blob: dc9dca37c25838a198bec0c0a278f8e0ab4ab1da [file] [log] [blame]
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -04001#define ASC_VERSION "3.4" /* AdvanSys Driver Version */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002
3/*
4 * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
5 *
6 * Copyright (c) 1995-2000 Advanced System Products, Inc.
7 * Copyright (c) 2000-2001 ConnectCom Solutions, Inc.
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -04008 * Copyright (c) 2007 Matthew Wilcox <matthew@wil.cx>
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * All Rights Reserved.
10 *
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040011 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 */
16
17/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070018 * As of March 8, 2000 Advanced System Products, Inc. (AdvanSys)
19 * changed its name to ConnectCom Solutions, Inc.
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040020 * On June 18, 2001 Initio Corp. acquired ConnectCom's SCSI assets
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 */
22
23/*
24
25 Documentation for the AdvanSys Driver
26
27 A. Linux Kernels Supported by this Driver
28 B. Adapters Supported by this Driver
29 C. Linux source files modified by AdvanSys Driver
30 D. Source Comments
31 E. Driver Compile Time Options and Debugging
32 F. Driver LILO Option
33 G. Tests to run before releasing new driver
34 H. Release History
35 I. Known Problems/Fix List
36 J. Credits (Chronological Order)
37
38 A. Linux Kernels Supported by this Driver
39
40 This driver has been tested in the following Linux kernels: v2.2.18
41 v2.4.0. The driver is supported on v2.2 and v2.4 kernels and on x86,
42 alpha, and PowerPC platforms.
43
44 B. Adapters Supported by this Driver
45
46 AdvanSys (Advanced System Products, Inc.) manufactures the following
47 RISC-based, Bus-Mastering, Fast (10 Mhz) and Ultra (20 Mhz) Narrow
48 (8-bit transfer) SCSI Host Adapters for the ISA, EISA, VL, and PCI
49 buses and RISC-based, Bus-Mastering, Ultra (20 Mhz) Wide (16-bit
50 transfer) SCSI Host Adapters for the PCI bus.
51
52 The CDB counts below indicate the number of SCSI CDB (Command
53 Descriptor Block) requests that can be stored in the RISC chip
54 cache and board LRAM. A CDB is a single SCSI command. The driver
55 detect routine will display the number of CDBs available for each
56 adapter detected. The number of CDBs used by the driver can be
57 lowered in the BIOS by changing the 'Host Queue Size' adapter setting.
58
59 Laptop Products:
60 ABP-480 - Bus-Master CardBus (16 CDB) (2.4 kernel and greater)
61
62 Connectivity Products:
63 ABP510/5150 - Bus-Master ISA (240 CDB)
64 ABP5140 - Bus-Master ISA PnP (16 CDB)
65 ABP5142 - Bus-Master ISA PnP with floppy (16 CDB)
66 ABP902/3902 - Bus-Master PCI (16 CDB)
67 ABP3905 - Bus-Master PCI (16 CDB)
68 ABP915 - Bus-Master PCI (16 CDB)
69 ABP920 - Bus-Master PCI (16 CDB)
70 ABP3922 - Bus-Master PCI (16 CDB)
71 ABP3925 - Bus-Master PCI (16 CDB)
72 ABP930 - Bus-Master PCI (16 CDB)
73 ABP930U - Bus-Master PCI Ultra (16 CDB)
74 ABP930UA - Bus-Master PCI Ultra (16 CDB)
75 ABP960 - Bus-Master PCI MAC/PC (16 CDB)
76 ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB)
77
78 Single Channel Products:
79 ABP542 - Bus-Master ISA with floppy (240 CDB)
80 ABP742 - Bus-Master EISA (240 CDB)
81 ABP842 - Bus-Master VL (240 CDB)
82 ABP940 - Bus-Master PCI (240 CDB)
83 ABP940U - Bus-Master PCI Ultra (240 CDB)
84 ABP940UA/3940UA - Bus-Master PCI Ultra (240 CDB)
85 ABP970 - Bus-Master PCI MAC/PC (240 CDB)
86 ABP970U - Bus-Master PCI MAC/PC Ultra (240 CDB)
87 ABP3960UA - Bus-Master PCI MAC/PC Ultra (240 CDB)
88 ABP940UW/3940UW - Bus-Master PCI Ultra-Wide (253 CDB)
89 ABP970UW - Bus-Master PCI MAC/PC Ultra-Wide (253 CDB)
90 ABP3940U2W - Bus-Master PCI LVD/Ultra2-Wide (253 CDB)
91
92 Multi-Channel Products:
93 ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel)
94 ABP852 - Dual Channel Bus-Master VL (240 CDB Per Channel)
95 ABP950 - Dual Channel Bus-Master PCI (240 CDB Per Channel)
96 ABP950UW - Dual Channel Bus-Master PCI Ultra-Wide (253 CDB Per Channel)
97 ABP980 - Four Channel Bus-Master PCI (240 CDB Per Channel)
98 ABP980U - Four Channel Bus-Master PCI Ultra (240 CDB Per Channel)
99 ABP980UA/3980UA - Four Channel Bus-Master PCI Ultra (16 CDB Per Chan.)
100 ABP3950U2W - Bus-Master PCI LVD/Ultra2-Wide and Ultra-Wide (253 CDB)
101 ABP3950U3W - Bus-Master PCI Dual LVD2/Ultra3-Wide (253 CDB)
102
103 C. Linux source files modified by AdvanSys Driver
104
105 This section for historical purposes documents the changes
106 originally made to the Linux kernel source to add the advansys
107 driver. As Linux has changed some of these files have also
108 been modified.
109
110 1. linux/arch/i386/config.in:
111
112 bool 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS y
113
114 2. linux/drivers/scsi/hosts.c:
115
116 #ifdef CONFIG_SCSI_ADVANSYS
117 #include "advansys.h"
118 #endif
119
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +0100120 and after "static struct scsi_host_template builtin_scsi_hosts[] =":
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121
122 #ifdef CONFIG_SCSI_ADVANSYS
123 ADVANSYS,
124 #endif
125
126 3. linux/drivers/scsi/Makefile:
127
128 ifdef CONFIG_SCSI_ADVANSYS
129 SCSI_SRCS := $(SCSI_SRCS) advansys.c
130 SCSI_OBJS := $(SCSI_OBJS) advansys.o
131 else
132 SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) advansys.o
133 endif
134
135 4. linux/init/main.c:
136
137 extern void advansys_setup(char *str, int *ints);
138
139 and add the following lines to the bootsetups[] array.
140
141 #ifdef CONFIG_SCSI_ADVANSYS
142 { "advansys=", advansys_setup },
143 #endif
144
145 D. Source Comments
146
147 1. Use tab stops set to 4 for the source files. For vi use 'se tabstops=4'.
148
149 2. This driver should be maintained in multiple files. But to make
150 it easier to include with Linux and to follow Linux conventions,
151 the whole driver is maintained in the source files advansys.h and
152 advansys.c. In this file logical sections of the driver begin with
153 a comment that contains '---'. The following are the logical sections
154 of the driver below.
155
156 --- Linux Version
157 --- Linux Include File
158 --- Driver Options
159 --- Debugging Header
160 --- Asc Library Constants and Macros
161 --- Adv Library Constants and Macros
162 --- Driver Constants and Macros
163 --- Driver Structures
164 --- Driver Data
165 --- Driver Function Prototypes
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +0100166 --- Linux 'struct scsi_host_template' and advansys_setup() Functions
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 --- Loadable Driver Support
168 --- Miscellaneous Driver Functions
169 --- Functions Required by the Asc Library
170 --- Functions Required by the Adv Library
171 --- Tracing and Debugging Functions
172 --- Asc Library Functions
173 --- Adv Library Functions
174
175 3. The string 'XXX' is used to flag code that needs to be re-written
176 or that contains a problem that needs to be addressed.
177
178 4. I have stripped comments from and reformatted the source for the
179 Asc Library and Adv Library to reduce the size of this file. This
180 source can be found under the following headings. The Asc Library
181 is used to support Narrow Boards. The Adv Library is used to
182 support Wide Boards.
183
184 --- Asc Library Constants and Macros
185 --- Adv Library Constants and Macros
186 --- Asc Library Functions
187 --- Adv Library Functions
188
189 E. Driver Compile Time Options and Debugging
190
191 In this source file the following constants can be defined. They are
192 defined in the source below. Both of these options are enabled by
193 default.
194
195 1. ADVANSYS_ASSERT - Enable driver assertions (Def: Enabled)
196
197 Enabling this option adds assertion logic statements to the
198 driver. If an assertion fails a message will be displayed to
199 the console, but the system will continue to operate. Any
200 assertions encountered should be reported to the person
201 responsible for the driver. Assertion statements may proactively
202 detect problems with the driver and facilitate fixing these
203 problems. Enabling assertions will add a small overhead to the
204 execution of the driver.
205
206 2. ADVANSYS_DEBUG - Enable driver debugging (Def: Disabled)
207
208 Enabling this option adds tracing functions to the driver and
209 the ability to set a driver tracing level at boot time. This
210 option will also export symbols not required outside the driver to
211 the kernel name space. This option is very useful for debugging
212 the driver, but it will add to the size of the driver execution
213 image and add overhead to the execution of the driver.
214
215 The amount of debugging output can be controlled with the global
216 variable 'asc_dbglvl'. The higher the number the more output. By
217 default the debug level is 0.
218
219 If the driver is loaded at boot time and the LILO Driver Option
220 is included in the system, the debug level can be changed by
221 specifying a 5th (ASC_NUM_IOPORT_PROBE + 1) I/O Port. The
222 first three hex digits of the pseudo I/O Port must be set to
223 'deb' and the fourth hex digit specifies the debug level: 0 - F.
224 The following command line will look for an adapter at 0x330
225 and set the debug level to 2.
226
227 linux advansys=0x330,0,0,0,0xdeb2
228
229 If the driver is built as a loadable module this variable can be
230 defined when the driver is loaded. The following insmod command
231 will set the debug level to one.
232
233 insmod advansys.o asc_dbglvl=1
234
235 Debugging Message Levels:
236 0: Errors Only
237 1: High-Level Tracing
238 2-N: Verbose Tracing
239
240 To enable debug output to console, please make sure that:
241
242 a. System and kernel logging is enabled (syslogd, klogd running).
243 b. Kernel messages are routed to console output. Check
244 /etc/syslog.conf for an entry similar to this:
245
246 kern.* /dev/console
247
248 c. klogd is started with the appropriate -c parameter
249 (e.g. klogd -c 8)
250
251 This will cause printk() messages to be be displayed on the
252 current console. Refer to the klogd(8) and syslogd(8) man pages
253 for details.
254
255 Alternatively you can enable printk() to console with this
256 program. However, this is not the 'official' way to do this.
257 Debug output is logged in /var/log/messages.
258
259 main()
260 {
261 syscall(103, 7, 0, 0);
262 }
263
264 Increasing LOG_BUF_LEN in kernel/printk.c to something like
265 40960 allows more debug messages to be buffered in the kernel
266 and written to the console or log file.
267
268 3. ADVANSYS_STATS - Enable statistics (Def: Enabled >= v1.3.0)
269
270 Enabling this option adds statistics collection and display
271 through /proc to the driver. The information is useful for
272 monitoring driver and device performance. It will add to the
273 size of the driver execution image and add minor overhead to
274 the execution of the driver.
275
276 Statistics are maintained on a per adapter basis. Driver entry
277 point call counts and transfer size counts are maintained.
278 Statistics are only available for kernels greater than or equal
279 to v1.3.0 with the CONFIG_PROC_FS (/proc) file system configured.
280
281 AdvanSys SCSI adapter files have the following path name format:
282
Matthew Wilcoxc304ec92007-07-30 09:18:45 -0600283 /proc/scsi/advansys/{0,1,2,3,...}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284
285 This information can be displayed with cat. For example:
286
287 cat /proc/scsi/advansys/0
288
289 When ADVANSYS_STATS is not defined the AdvanSys /proc files only
290 contain adapter and device configuration information.
291
292 F. Driver LILO Option
293
294 If init/main.c is modified as described in the 'Directions for Adding
295 the AdvanSys Driver to Linux' section (B.4.) above, the driver will
296 recognize the 'advansys' LILO command line and /etc/lilo.conf option.
297 This option can be used to either disable I/O port scanning or to limit
298 scanning to 1 - 4 I/O ports. Regardless of the option setting EISA and
299 PCI boards will still be searched for and detected. This option only
300 affects searching for ISA and VL boards.
301
302 Examples:
303 1. Eliminate I/O port scanning:
304 boot: linux advansys=
305 or
306 boot: linux advansys=0x0
307 2. Limit I/O port scanning to one I/O port:
308 boot: linux advansys=0x110
309 3. Limit I/O port scanning to four I/O ports:
310 boot: linux advansys=0x110,0x210,0x230,0x330
311
312 For a loadable module the same effect can be achieved by setting
313 the 'asc_iopflag' variable and 'asc_ioport' array when loading
314 the driver, e.g.
315
316 insmod advansys.o asc_iopflag=1 asc_ioport=0x110,0x330
317
318 If ADVANSYS_DEBUG is defined a 5th (ASC_NUM_IOPORT_PROBE + 1)
319 I/O Port may be added to specify the driver debug level. Refer to
320 the 'Driver Compile Time Options and Debugging' section above for
321 more information.
322
323 G. Tests to run before releasing new driver
324
325 1. In the supported kernels verify there are no warning or compile
326 errors when the kernel is built as both a driver and as a module
327 and with the following options:
328
329 ADVANSYS_DEBUG - enabled and disabled
330 CONFIG_SMP - enabled and disabled
331 CONFIG_PROC_FS - enabled and disabled
332
333 2. Run tests on an x86, alpha, and PowerPC with at least one narrow
334 card and one wide card attached to a hard disk and CD-ROM drive:
335 fdisk, mkfs, fsck, bonnie, copy/compare test from the
336 CD-ROM to the hard drive.
337
338 H. Release History
339
340 BETA-1.0 (12/23/95):
341 First Release
342
343 BETA-1.1 (12/28/95):
344 1. Prevent advansys_detect() from being called twice.
345 2. Add LILO 0xdeb[0-f] option to set 'asc_dbglvl'.
346
347 1.2 (1/12/96):
348 1. Prevent re-entrancy in the interrupt handler which
349 resulted in the driver hanging Linux.
350 2. Fix problem that prevented ABP-940 cards from being
351 recognized on some PCI motherboards.
352 3. Add support for the ABP-5140 PnP ISA card.
353 4. Fix check condition return status.
354 5. Add conditionally compiled code for Linux v1.3.X.
355
356 1.3 (2/23/96):
357 1. Fix problem in advansys_biosparam() that resulted in the
358 wrong drive geometry being returned for drives > 1GB with
359 extended translation enabled.
360 2. Add additional tracing during device initialization.
361 3. Change code that only applies to ISA PnP adapter.
362 4. Eliminate 'make dep' warning.
363 5. Try to fix problem with handling resets by increasing their
364 timeout value.
365
366 1.4 (5/8/96):
367 1. Change definitions to eliminate conflicts with other subsystems.
368 2. Add versioning code for the shared interrupt changes.
369 3. Eliminate problem in asc_rmqueue() with iterating after removing
370 a request.
371 4. Remove reset request loop problem from the "Known Problems or
372 Issues" section. This problem was isolated and fixed in the
373 mid-level SCSI driver.
374
375 1.5 (8/8/96):
376 1. Add support for ABP-940U (PCI Ultra) adapter.
Thomas Gleixner1d6f3592006-07-01 19:29:42 -0700377 2. Add support for IRQ sharing by setting the IRQF_SHARED flag for
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 request_irq and supplying a dev_id pointer to both request_irq()
379 and free_irq().
380 3. In AscSearchIOPortAddr11() restore a call to check_region() which
381 should be used before I/O port probing.
382 4. Fix bug in asc_prt_hex() which resulted in the displaying
383 the wrong data.
384 5. Incorporate miscellaneous Asc Library bug fixes and new microcode.
385 6. Change driver versioning to be specific to each Linux sub-level.
386 7. Change statistics gathering to be per adapter instead of global
387 to the driver.
388 8. Add more information and statistics to the adapter /proc file:
389 /proc/scsi/advansys[0...].
390 9. Remove 'cmd_per_lun' from the "Known Problems or Issues" list.
391 This problem has been addressed with the SCSI mid-level changes
392 made in v1.3.89. The advansys_select_queue_depths() function
393 was added for the v1.3.89 changes.
394
395 1.6 (9/10/96):
396 1. Incorporate miscellaneous Asc Library bug fixes and new microcode.
397
398 1.7 (9/25/96):
399 1. Enable clustering and optimize the setting of the maximum number
400 of scatter gather elements for any particular board. Clustering
401 increases CPU utilization, but results in a relatively larger
402 increase in I/O throughput.
403 2. Improve the performance of the request queuing functions by
404 adding a last pointer to the queue structure.
405 3. Correct problems with reset and abort request handling that
406 could have hung or crashed Linux.
407 4. Add more information to the adapter /proc file:
408 /proc/scsi/advansys[0...].
409 5. Remove the request timeout issue form the driver issues list.
410 6. Miscellaneous documentation additions and changes.
411
412 1.8 (10/4/96):
413 1. Make changes to handle the new v2.1.0 kernel memory mapping
414 in which a kernel virtual address may not be equivalent to its
415 bus or DMA memory address.
416 2. Change abort and reset request handling to make it yet even
417 more robust.
418 3. Try to mitigate request starvation by sending ordered requests
419 to heavily loaded, tag queuing enabled devices.
420 4. Maintain statistics on request response time.
421 5. Add request response time statistics and other information to
422 the adapter /proc file: /proc/scsi/advansys[0...].
423
424 1.9 (10/21/96):
425 1. Add conditionally compiled code (ASC_QUEUE_FLOW_CONTROL) to
426 make use of mid-level SCSI driver device queue depth flow
427 control mechanism. This will eliminate aborts caused by a
428 device being unable to keep up with requests and eliminate
429 repeat busy or QUEUE FULL status returned by a device.
430 2. Incorporate miscellaneous Asc Library bug fixes.
431 3. To allow the driver to work in kernels with broken module
432 support set 'cmd_per_lun' if the driver is compiled as a
433 module. This change affects kernels v1.3.89 to present.
434 4. Remove PCI BIOS address from the driver banner. The PCI BIOS
435 is relocated by the motherboard BIOS and its new address can
436 not be determined by the driver.
437 5. Add mid-level SCSI queue depth information to the adapter
438 /proc file: /proc/scsi/advansys[0...].
439
440 2.0 (11/14/96):
441 1. Change allocation of global structures used for device
442 initialization to guarantee they are in DMA-able memory.
443 Previously when the driver was loaded as a module these
444 structures might not have been in DMA-able memory, causing
445 device initialization to fail.
446
447 2.1 (12/30/96):
448 1. In advansys_reset(), if the request is a synchronous reset
449 request, even if the request serial number has changed, then
450 complete the request.
451 2. Add Asc Library bug fixes including new microcode.
452 3. Clear inquiry buffer before using it.
453 4. Correct ifdef typo.
454
455 2.2 (1/15/97):
456 1. Add Asc Library bug fixes including new microcode.
457 2. Add synchronous data transfer rate information to the
458 adapter /proc file: /proc/scsi/advansys[0...].
459 3. Change ADVANSYS_DEBUG to be disabled by default. This
460 will reduce the size of the driver image, eliminate execution
461 overhead, and remove unneeded symbols from the kernel symbol
462 space that were previously added by the driver.
463 4. Add new compile-time option ADVANSYS_ASSERT for assertion
464 code that used to be defined within ADVANSYS_DEBUG. This
465 option is enabled by default.
466
467 2.8 (5/26/97):
468 1. Change version number to 2.8 to synchronize the Linux driver
469 version numbering with other AdvanSys drivers.
470 2. Reformat source files without tabs to present the same view
471 of the file to everyone regardless of the editor tab setting
472 being used.
473 3. Add Asc Library bug fixes.
474
475 3.1A (1/8/98):
476 1. Change version number to 3.1 to indicate that support for
477 Ultra-Wide adapters (ABP-940UW) is included in this release.
478 2. Add Asc Library (Narrow Board) bug fixes.
479 3. Report an underrun condition with the host status byte set
480 to DID_UNDERRUN. Currently DID_UNDERRUN is defined to 0 which
481 causes the underrun condition to be ignored. When Linux defines
482 its own DID_UNDERRUN the constant defined in this file can be
483 removed.
484 4. Add patch to AscWaitTixISRDone().
485 5. Add support for up to 16 different AdvanSys host adapter SCSI
486 channels in one system. This allows four cards with four channels
487 to be used in one system.
488
489 3.1B (1/9/98):
490 1. Handle that PCI register base addresses are not always page
491 aligned even though ioremap() requires that the address argument
492 be page aligned.
493
494 3.1C (1/10/98):
495 1. Update latest BIOS version checked for from the /proc file.
496 2. Don't set microcode SDTR variable at initialization. Instead
497 wait until device capabilities have been detected from an Inquiry
498 command.
499
500 3.1D (1/21/98):
501 1. Improve performance when the driver is compiled as module by
502 allowing up to 64 scatter-gather elements instead of 8.
503
504 3.1E (5/1/98):
505 1. Set time delay in AscWaitTixISRDone() to 1000 ms.
506 2. Include SMP locking changes.
507 3. For v2.1.93 and newer kernels use CONFIG_PCI and new PCI BIOS
508 access functions.
509 4. Update board serial number printing.
Thomas Gleixner1d6f3592006-07-01 19:29:42 -0700510 5. Try allocating an IRQ both with and without the IRQF_DISABLED
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 flag set to allow IRQ sharing with drivers that do not set
Thomas Gleixner1d6f3592006-07-01 19:29:42 -0700512 the IRQF_DISABLED flag. Also display a more descriptive error
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 message if request_irq() fails.
514 6. Update to latest Asc and Adv Libraries.
515
516 3.2A (7/22/99):
517 1. Update Adv Library to 4.16 which includes support for
518 the ASC38C0800 (Ultra2/LVD) IC.
519
520 3.2B (8/23/99):
521 1. Correct PCI compile time option for v2.1.93 and greater
522 kernels, advansys_info() string, and debug compile time
523 option.
524 2. Correct DvcSleepMilliSecond() for v2.1.0 and greater
525 kernels. This caused an LVD detection/BIST problem problem
526 among other things.
527 3. Sort PCI cards by PCI Bus, Slot, Function ascending order
528 to be consistent with the BIOS.
529 4. Update to Asc Library S121 and Adv Library 5.2.
530
531 3.2C (8/24/99):
532 1. Correct PCI card detection bug introduced in 3.2B that
533 prevented PCI cards from being detected in kernels older
534 than v2.1.93.
535
536 3.2D (8/26/99):
537 1. Correct /proc device synchronous speed information display.
538 Also when re-negotiation is pending for a target device
539 note this condition with an * and footnote.
540 2. Correct initialization problem with Ultra-Wide cards that
541 have a pre-3.2 BIOS. A microcode variable changed locations
542 in 3.2 and greater BIOSes which caused WDTR to be attempted
543 erroneously with drives that don't support WDTR.
544
545 3.2E (8/30/99):
546 1. Fix compile error caused by v2.3.13 PCI structure change.
547 2. Remove field from ASCEEP_CONFIG that resulted in an EEPROM
548 checksum error for ISA cards.
549 3. Remove ASC_QUEUE_FLOW_CONTROL conditional code. The mid-level
550 SCSI changes that it depended on were never included in Linux.
551
552 3.2F (9/3/99):
553 1. Handle new initial function code added in v2.3.16 for all
554 driver versions.
555
556 3.2G (9/8/99):
557 1. Fix PCI board detection in v2.3.13 and greater kernels.
558 2. Fix comiple errors in v2.3.X with debugging enabled.
559
560 3.2H (9/13/99):
561 1. Add 64-bit address, long support for Alpha and UltraSPARC.
562 The driver has been verified to work on an Alpha system.
563 2. Add partial byte order handling support for Power PC and
564 other big-endian platforms. This support has not yet been
565 completed or verified.
566 3. For wide boards replace block zeroing of request and
567 scatter-gather structures with individual field initialization
568 to improve performance.
569 4. Correct and clarify ROM BIOS version detection.
570
571 3.2I (10/8/99):
572 1. Update to Adv Library 5.4.
573 2. Add v2.3.19 underrun reporting to asc_isr_callback() and
574 adv_isr_callback(). Remove DID_UNDERRUN constant and other
575 no longer needed code that previously documented the lack
576 of underrun handling.
577
578 3.2J (10/14/99):
579 1. Eliminate compile errors for v2.0 and earlier kernels.
580
581 3.2K (11/15/99):
582 1. Correct debug compile error in asc_prt_adv_scsi_req_q().
583 2. Update Adv Library to 5.5.
584 3. Add ifdef handling for /proc changes added in v2.3.28.
585 4. Increase Wide board scatter-gather list maximum length to
586 255 when the driver is compiled into the kernel.
587
588 3.2L (11/18/99):
589 1. Fix bug in adv_get_sglist() that caused an assertion failure
590 at line 7475. The reqp->sgblkp pointer must be initialized
591 to NULL in adv_get_sglist().
592
593 3.2M (11/29/99):
594 1. Really fix bug in adv_get_sglist().
595 2. Incorporate v2.3.29 changes into driver.
596
597 3.2N (4/1/00):
598 1. Add CONFIG_ISA ifdef code.
599 2. Include advansys_interrupts_enabled name change patch.
600 3. For >= v2.3.28 use new SCSI error handling with new function
601 advansys_eh_bus_reset(). Don't include an abort function
602 because of base library limitations.
603 4. For >= v2.3.28 use per board lock instead of io_request_lock.
604 5. For >= v2.3.28 eliminate advansys_command() and
605 advansys_command_done().
606 6. Add some changes for PowerPC (Big Endian) support, but it isn't
607 working yet.
608 7. Fix "nonexistent resource free" problem that occurred on a module
609 unload for boards with an I/O space >= 255. The 'n_io_port' field
610 is only one byte and can not be used to hold an ioport length more
611 than 255.
612
613 3.3A (4/4/00):
614 1. Update to Adv Library 5.8.
615 2. For wide cards add support for CDBs up to 16 bytes.
616 3. Eliminate warnings when CONFIG_PROC_FS is not defined.
617
618 3.3B (5/1/00):
619 1. Support for PowerPC (Big Endian) wide cards. Narrow cards
620 still need work.
621 2. Change bitfields to shift and mask access for endian
622 portability.
623
624 3.3C (10/13/00):
625 1. Update for latest 2.4 kernel.
626 2. Test ABP-480 CardBus support in 2.4 kernel - works!
627 3. Update to Asc Library S123.
628 4. Update to Adv Library 5.12.
629
630 3.3D (11/22/00):
631 1. Update for latest 2.4 kernel.
632 2. Create patches for 2.2 and 2.4 kernels.
633
634 3.3E (1/9/01):
635 1. Now that 2.4 is released remove ifdef code for kernel versions
636 less than 2.2. The driver is now only supported in kernels 2.2,
637 2.4, and greater.
638 2. Add code to release and acquire the io_request_lock in
639 the driver entrypoint functions: advansys_detect and
640 advansys_queuecommand. In kernel 2.4 the SCSI mid-level driver
641 still holds the io_request_lock on entry to SCSI low-level drivers.
642 This was supposed to be removed before 2.4 was released but never
643 happened. When the mid-level SCSI driver is changed all references
644 to the io_request_lock should be removed from the driver.
645 3. Simplify error handling by removing advansys_abort(),
646 AscAbortSRB(), AscResetDevice(). SCSI bus reset requests are
647 now handled by resetting the SCSI bus and fully re-initializing
648 the chip. This simple method of error recovery has proven to work
649 most reliably after attempts at different methods. Also now only
650 support the "new" error handling method and remove the obsolete
651 error handling interface.
652 4. Fix debug build errors.
653
654 3.3F (1/24/01):
655 1. Merge with ConnectCom version from Andy Kellner which
656 updates Adv Library to 5.14.
657 2. Make PowerPC (Big Endian) work for narrow cards and
658 fix problems writing EEPROM for wide cards.
659 3. Remove interrupts_enabled assertion function.
660
661 3.3G (2/16/01):
662 1. Return an error from narrow boards if passed a 16 byte
663 CDB. The wide board can already handle 16 byte CDBs.
664
665 3.3GJ (4/15/02):
666 1. hacks for lk 2.5 series (D. Gilbert)
667
668 3.3GJD (10/14/02):
669 1. change select_queue_depths to slave_configure
670 2. make cmd_per_lun be sane again
671
672 3.3K [2004/06/24]:
673 1. continuing cleanup for lk 2.6 series
674 2. Fix problem in lk 2.6.7-bk2 that broke PCI wide cards
675 3. Fix problem that oopsed ISA cards
676
677 I. Known Problems/Fix List (XXX)
678
679 1. Need to add memory mapping workaround. Test the memory mapping.
680 If it doesn't work revert to I/O port access. Can a test be done
681 safely?
682 2. Handle an interrupt not working. Keep an interrupt counter in
683 the interrupt handler. In the timeout function if the interrupt
684 has not occurred then print a message and run in polled mode.
685 3. Allow bus type scanning order to be changed.
686 4. Need to add support for target mode commands, cf. CAM XPT.
687
688 J. Credits (Chronological Order)
689
690 Bob Frey <bfrey@turbolinux.com.cn> wrote the AdvanSys SCSI driver
691 and maintained it up to 3.3F. He continues to answer questions
692 and help maintain the driver.
693
694 Nathan Hartwell <mage@cdc3.cdc.net> provided the directions and
695 basis for the Linux v1.3.X changes which were included in the
696 1.2 release.
697
698 Thomas E Zerucha <zerucha@shell.portal.com> pointed out a bug
699 in advansys_biosparam() which was fixed in the 1.3 release.
700
701 Erik Ratcliffe <erik@caldera.com> has done testing of the
702 AdvanSys driver in the Caldera releases.
703
704 Rik van Riel <H.H.vanRiel@fys.ruu.nl> provided a patch to
705 AscWaitTixISRDone() which he found necessary to make the
706 driver work with a SCSI-1 disk.
707
708 Mark Moran <mmoran@mmoran.com> has helped test Ultra-Wide
709 support in the 3.1A driver.
710
711 Doug Gilbert <dgilbert@interlog.com> has made changes and
712 suggestions to improve the driver and done a lot of testing.
713
714 Ken Mort <ken@mort.net> reported a DEBUG compile bug fixed
715 in 3.2K.
716
717 Tom Rini <trini@kernel.crashing.org> provided the CONFIG_ISA
718 patch and helped with PowerPC wide and narrow board support.
719
720 Philip Blundell <philb@gnu.org> provided an
721 advansys_interrupts_enabled patch.
722
723 Dave Jones <dave@denial.force9.co.uk> reported the compiler
724 warnings generated when CONFIG_PROC_FS was not defined in
725 the 3.2M driver.
726
727 Jerry Quinn <jlquinn@us.ibm.com> fixed PowerPC support (endian
728 problems) for wide cards.
729
730 Bryan Henderson <bryanh@giraffe-data.com> helped debug narrow
731 card error handling.
732
733 Manuel Veloso <veloso@pobox.com> worked hard on PowerPC narrow
734 board support and fixed a bug in AscGetEEPConfig().
735
736 Arnaldo Carvalho de Melo <acme@conectiva.com.br> made
737 save_flags/restore_flags changes.
738
739 Andy Kellner <AKellner@connectcom.net> continues the Advansys SCSI
740 driver development for ConnectCom (Version > 3.3F).
741
742 K. ConnectCom (AdvanSys) Contact Information
743
744 Mail: ConnectCom Solutions, Inc.
745 1150 Ringwood Court
746 San Jose, CA 95131
747 Operator/Sales: 1-408-383-9400
748 FAX: 1-408-383-9612
749 Tech Support: 1-408-467-2930
750 Tech Support E-Mail: linux@connectcom.net
751 FTP Site: ftp.connectcom.net (login: anonymous)
752 Web Site: http://www.connectcom.net
753
754*/
755
756/*
757 * --- Linux Include Files
758 */
759
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761#include <linux/string.h>
762#include <linux/kernel.h>
763#include <linux/types.h>
764#include <linux/ioport.h>
765#include <linux/interrupt.h>
766#include <linux/delay.h>
767#include <linux/slab.h>
768#include <linux/mm.h>
769#include <linux/proc_fs.h>
770#include <linux/init.h>
771#include <linux/blkdev.h>
Matthew Wilcoxc304ec92007-07-30 09:18:45 -0600772#include <linux/isa.h>
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -0600773#include <linux/eisa.h>
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -0400774#include <linux/pci.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775#include <linux/spinlock.h>
776#include <linux/dma-mapping.h>
777
778#include <asm/io.h>
779#include <asm/system.h>
780#include <asm/dma.h>
781
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -0400782#include <scsi/scsi_cmnd.h>
783#include <scsi/scsi_device.h>
784#include <scsi/scsi_tcq.h>
785#include <scsi/scsi.h>
786#include <scsi/scsi_host.h>
787
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -0600788/* FIXME: (by jejb@steeleye.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 *
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -0600790 * Although all of the necessary command mapping places have the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 * appropriate dma_map.. APIs, the driver still processes its internal
792 * queue using bus_to_virt() and virt_to_bus() which are illegal under
793 * the API. The entire queue processing structure will need to be
794 * altered to fix this.
795 */
796#warning this driver is still not properly converted to the DMA API
797
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798/*
799 * --- Driver Options
800 */
801
802/* Enable driver assertions. */
803#define ADVANSYS_ASSERT
804
805/* Enable driver /proc statistics. */
806#define ADVANSYS_STATS
807
808/* Enable driver tracing. */
809/* #define ADVANSYS_DEBUG */
810
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811/*
812 * --- Asc Library Constants and Macros
813 */
814
815#define ASC_LIB_VERSION_MAJOR 1
816#define ASC_LIB_VERSION_MINOR 24
817#define ASC_LIB_SERIAL_NUMBER 123
818
819/*
820 * Portable Data Types
821 *
822 * Any instance where a 32-bit long or pointer type is assumed
823 * for precision or HW defined structures, the following define
824 * types must be used. In Linux the char, short, and int types
825 * are all consistent at 8, 16, and 32 bits respectively. Pointers
826 * and long types are 64 bits on Alpha and UltraSPARC.
827 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400828#define ASC_PADDR __u32 /* Physical/Bus address data type. */
829#define ASC_VADDR __u32 /* Virtual address data type. */
830#define ASC_DCNT __u32 /* Unsigned Data count type. */
831#define ASC_SDCNT __s32 /* Signed Data count type. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
833/*
834 * These macros are used to convert a virtual address to a
835 * 32-bit value. This currently can be used on Linux Alpha
836 * which uses 64-bit virtual address but a 32-bit bus address.
837 * This is likely to break in the future, but doing this now
838 * will give us time to change the HW and FW to handle 64-bit
839 * addresses.
840 */
841#define ASC_VADDR_TO_U32 virt_to_bus
842#define ASC_U32_TO_VADDR bus_to_virt
843
844typedef unsigned char uchar;
845
846#ifndef TRUE
847#define TRUE (1)
848#endif
849#ifndef FALSE
850#define FALSE (0)
851#endif
852
853#define EOF (-1)
854#define ERR (-1)
855#define UW_ERR (uint)(0xFFFF)
856#define isodd_word(val) ((((uint)val) & (uint)0x0001) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857#define ASC_PCI_ID2FUNC(id) (((id) >> 8) & 0x7)
858#define ASC_PCI_MKID(bus, dev, func) ((((dev) & 0x1F) << 11) | (((func) & 0x7) << 8) | ((bus) & 0xFF))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859
860#define ASC_DVCLIB_CALL_DONE (1)
861#define ASC_DVCLIB_CALL_FAILED (0)
862#define ASC_DVCLIB_CALL_ERROR (-1)
863
Dave Jones2672ea82006-08-02 17:11:49 -0400864#define PCI_VENDOR_ID_ASP 0x10cd
865#define PCI_DEVICE_ID_ASP_1200A 0x1100
866#define PCI_DEVICE_ID_ASP_ABP940 0x1200
867#define PCI_DEVICE_ID_ASP_ABP940U 0x1300
868#define PCI_DEVICE_ID_ASP_ABP940UW 0x2300
869#define PCI_DEVICE_ID_38C0800_REV1 0x2500
870#define PCI_DEVICE_ID_38C1600_REV1 0x2700
871
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872/*
873 * Enable CC_VERY_LONG_SG_LIST to support up to 64K element SG lists.
874 * The SRB structure will have to be changed and the ASC_SRB2SCSIQ()
875 * macro re-defined to be able to obtain a ASC_SCSI_Q pointer from the
876 * SRB structure.
877 */
878#define CC_VERY_LONG_SG_LIST 0
879#define ASC_SRB2SCSIQ(srb_ptr) (srb_ptr)
880
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400881#define PortAddr unsigned short /* port address size */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882#define inp(port) inb(port)
883#define outp(port, byte) outb((byte), (port))
884
885#define inpw(port) inw(port)
886#define outpw(port, word) outw((word), (port))
887
888#define ASC_MAX_SG_QUEUE 7
889#define ASC_MAX_SG_LIST 255
890
891#define ASC_CS_TYPE unsigned short
892
893#define ASC_IS_ISA (0x0001)
894#define ASC_IS_ISAPNP (0x0081)
895#define ASC_IS_EISA (0x0002)
896#define ASC_IS_PCI (0x0004)
897#define ASC_IS_PCI_ULTRA (0x0104)
898#define ASC_IS_PCMCIA (0x0008)
899#define ASC_IS_MCA (0x0020)
900#define ASC_IS_VL (0x0040)
901#define ASC_ISA_PNP_PORT_ADDR (0x279)
902#define ASC_ISA_PNP_PORT_WRITE (ASC_ISA_PNP_PORT_ADDR+0x800)
903#define ASC_IS_WIDESCSI_16 (0x0100)
904#define ASC_IS_WIDESCSI_32 (0x0200)
905#define ASC_IS_BIG_ENDIAN (0x8000)
906#define ASC_CHIP_MIN_VER_VL (0x01)
907#define ASC_CHIP_MAX_VER_VL (0x07)
908#define ASC_CHIP_MIN_VER_PCI (0x09)
909#define ASC_CHIP_MAX_VER_PCI (0x0F)
910#define ASC_CHIP_VER_PCI_BIT (0x08)
911#define ASC_CHIP_MIN_VER_ISA (0x11)
912#define ASC_CHIP_MIN_VER_ISA_PNP (0x21)
913#define ASC_CHIP_MAX_VER_ISA (0x27)
914#define ASC_CHIP_VER_ISA_BIT (0x30)
915#define ASC_CHIP_VER_ISAPNP_BIT (0x20)
916#define ASC_CHIP_VER_ASYN_BUG (0x21)
917#define ASC_CHIP_VER_PCI 0x08
918#define ASC_CHIP_VER_PCI_ULTRA_3150 (ASC_CHIP_VER_PCI | 0x02)
919#define ASC_CHIP_VER_PCI_ULTRA_3050 (ASC_CHIP_VER_PCI | 0x03)
920#define ASC_CHIP_MIN_VER_EISA (0x41)
921#define ASC_CHIP_MAX_VER_EISA (0x47)
922#define ASC_CHIP_VER_EISA_BIT (0x40)
923#define ASC_CHIP_LATEST_VER_EISA ((ASC_CHIP_MIN_VER_EISA - 1) + 3)
924#define ASC_MAX_LIB_SUPPORTED_ISA_CHIP_VER 0x21
925#define ASC_MAX_LIB_SUPPORTED_PCI_CHIP_VER 0x0A
926#define ASC_MAX_VL_DMA_ADDR (0x07FFFFFFL)
927#define ASC_MAX_VL_DMA_COUNT (0x07FFFFFFL)
928#define ASC_MAX_PCI_DMA_ADDR (0xFFFFFFFFL)
929#define ASC_MAX_PCI_DMA_COUNT (0xFFFFFFFFL)
930#define ASC_MAX_ISA_DMA_ADDR (0x00FFFFFFL)
931#define ASC_MAX_ISA_DMA_COUNT (0x00FFFFFFL)
932#define ASC_MAX_EISA_DMA_ADDR (0x07FFFFFFL)
933#define ASC_MAX_EISA_DMA_COUNT (0x07FFFFFFL)
934
935#define ASC_SCSI_ID_BITS 3
936#define ASC_SCSI_TIX_TYPE uchar
937#define ASC_ALL_DEVICE_BIT_SET 0xFF
938#define ASC_SCSI_BIT_ID_TYPE uchar
939#define ASC_MAX_TID 7
940#define ASC_MAX_LUN 7
941#define ASC_SCSI_WIDTH_BIT_SET 0xFF
942#define ASC_MAX_SENSE_LEN 32
943#define ASC_MIN_SENSE_LEN 14
944#define ASC_MAX_CDB_LEN 12
945#define ASC_SCSI_RESET_HOLD_TIME_US 60
946
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947/*
948 * Inquiry SPC-2 SPI Byte 1 EVPD (Enable Vital Product Data)
949 * and CmdDt (Command Support Data) field bit definitions.
950 */
951#define ADV_INQ_RTN_VPD_AND_CMDDT 0x3
952#define ADV_INQ_RTN_CMDDT_FOR_OP_CODE 0x2
953#define ADV_INQ_RTN_VPD_FOR_PG_CODE 0x1
954#define ADV_INQ_RTN_STD_INQUIRY_DATA 0x0
955
956#define ASC_SCSIDIR_NOCHK 0x00
957#define ASC_SCSIDIR_T2H 0x08
958#define ASC_SCSIDIR_H2T 0x10
959#define ASC_SCSIDIR_NODATA 0x18
960#define SCSI_ASC_NOMEDIA 0x3A
961#define ASC_SRB_HOST(x) ((uchar)((uchar)(x) >> 4))
962#define ASC_SRB_TID(x) ((uchar)((uchar)(x) & (uchar)0x0F))
963#define ASC_SRB_LUN(x) ((uchar)((uint)(x) >> 13))
964#define PUT_CDB1(x) ((uchar)((uint)(x) >> 8))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965#define MS_SDTR_LEN 0x03
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966#define MS_WDTR_LEN 0x02
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967
968#define ASC_SG_LIST_PER_Q 7
969#define QS_FREE 0x00
970#define QS_READY 0x01
971#define QS_DISC1 0x02
972#define QS_DISC2 0x04
973#define QS_BUSY 0x08
974#define QS_ABORTED 0x40
975#define QS_DONE 0x80
976#define QC_NO_CALLBACK 0x01
977#define QC_SG_SWAP_QUEUE 0x02
978#define QC_SG_HEAD 0x04
979#define QC_DATA_IN 0x08
980#define QC_DATA_OUT 0x10
981#define QC_URGENT 0x20
982#define QC_MSG_OUT 0x40
983#define QC_REQ_SENSE 0x80
984#define QCSG_SG_XFER_LIST 0x02
985#define QCSG_SG_XFER_MORE 0x04
986#define QCSG_SG_XFER_END 0x08
987#define QD_IN_PROGRESS 0x00
988#define QD_NO_ERROR 0x01
989#define QD_ABORTED_BY_HOST 0x02
990#define QD_WITH_ERROR 0x04
991#define QD_INVALID_REQUEST 0x80
992#define QD_INVALID_HOST_NUM 0x81
993#define QD_INVALID_DEVICE 0x82
994#define QD_ERR_INTERNAL 0xFF
995#define QHSTA_NO_ERROR 0x00
996#define QHSTA_M_SEL_TIMEOUT 0x11
997#define QHSTA_M_DATA_OVER_RUN 0x12
998#define QHSTA_M_DATA_UNDER_RUN 0x12
999#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
1000#define QHSTA_M_BAD_BUS_PHASE_SEQ 0x14
1001#define QHSTA_D_QDONE_SG_LIST_CORRUPTED 0x21
1002#define QHSTA_D_ASC_DVC_ERROR_CODE_SET 0x22
1003#define QHSTA_D_HOST_ABORT_FAILED 0x23
1004#define QHSTA_D_EXE_SCSI_Q_FAILED 0x24
1005#define QHSTA_D_EXE_SCSI_Q_BUSY_TIMEOUT 0x25
1006#define QHSTA_D_ASPI_NO_BUF_POOL 0x26
1007#define QHSTA_M_WTM_TIMEOUT 0x41
1008#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42
1009#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43
1010#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
1011#define QHSTA_M_TARGET_STATUS_BUSY 0x45
1012#define QHSTA_M_BAD_TAG_CODE 0x46
1013#define QHSTA_M_BAD_QUEUE_FULL_OR_BUSY 0x47
1014#define QHSTA_M_HUNG_REQ_SCSI_BUS_RESET 0x48
1015#define QHSTA_D_LRAM_CMP_ERROR 0x81
1016#define QHSTA_M_MICRO_CODE_ERROR_HALT 0xA1
1017#define ASC_FLAG_SCSIQ_REQ 0x01
1018#define ASC_FLAG_BIOS_SCSIQ_REQ 0x02
1019#define ASC_FLAG_BIOS_ASYNC_IO 0x04
1020#define ASC_FLAG_SRB_LINEAR_ADDR 0x08
1021#define ASC_FLAG_WIN16 0x10
1022#define ASC_FLAG_WIN32 0x20
1023#define ASC_FLAG_ISA_OVER_16MB 0x40
1024#define ASC_FLAG_DOS_VM_CALLBACK 0x80
1025#define ASC_TAG_FLAG_EXTRA_BYTES 0x10
1026#define ASC_TAG_FLAG_DISABLE_DISCONNECT 0x04
1027#define ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX 0x08
1028#define ASC_TAG_FLAG_DISABLE_CHK_COND_INT_HOST 0x40
1029#define ASC_SCSIQ_CPY_BEG 4
1030#define ASC_SCSIQ_SGHD_CPY_BEG 2
1031#define ASC_SCSIQ_B_FWD 0
1032#define ASC_SCSIQ_B_BWD 1
1033#define ASC_SCSIQ_B_STATUS 2
1034#define ASC_SCSIQ_B_QNO 3
1035#define ASC_SCSIQ_B_CNTL 4
1036#define ASC_SCSIQ_B_SG_QUEUE_CNT 5
1037#define ASC_SCSIQ_D_DATA_ADDR 8
1038#define ASC_SCSIQ_D_DATA_CNT 12
1039#define ASC_SCSIQ_B_SENSE_LEN 20
1040#define ASC_SCSIQ_DONE_INFO_BEG 22
1041#define ASC_SCSIQ_D_SRBPTR 22
1042#define ASC_SCSIQ_B_TARGET_IX 26
1043#define ASC_SCSIQ_B_CDB_LEN 28
1044#define ASC_SCSIQ_B_TAG_CODE 29
1045#define ASC_SCSIQ_W_VM_ID 30
1046#define ASC_SCSIQ_DONE_STATUS 32
1047#define ASC_SCSIQ_HOST_STATUS 33
1048#define ASC_SCSIQ_SCSI_STATUS 34
1049#define ASC_SCSIQ_CDB_BEG 36
1050#define ASC_SCSIQ_DW_REMAIN_XFER_ADDR 56
1051#define ASC_SCSIQ_DW_REMAIN_XFER_CNT 60
1052#define ASC_SCSIQ_B_FIRST_SG_WK_QP 48
1053#define ASC_SCSIQ_B_SG_WK_QP 49
1054#define ASC_SCSIQ_B_SG_WK_IX 50
1055#define ASC_SCSIQ_W_ALT_DC1 52
1056#define ASC_SCSIQ_B_LIST_CNT 6
1057#define ASC_SCSIQ_B_CUR_LIST_CNT 7
1058#define ASC_SGQ_B_SG_CNTL 4
1059#define ASC_SGQ_B_SG_HEAD_QP 5
1060#define ASC_SGQ_B_SG_LIST_CNT 6
1061#define ASC_SGQ_B_SG_CUR_LIST_CNT 7
1062#define ASC_SGQ_LIST_BEG 8
1063#define ASC_DEF_SCSI1_QNG 4
1064#define ASC_MAX_SCSI1_QNG 4
1065#define ASC_DEF_SCSI2_QNG 16
1066#define ASC_MAX_SCSI2_QNG 32
1067#define ASC_TAG_CODE_MASK 0x23
1068#define ASC_STOP_REQ_RISC_STOP 0x01
1069#define ASC_STOP_ACK_RISC_STOP 0x03
1070#define ASC_STOP_CLEAN_UP_BUSY_Q 0x10
1071#define ASC_STOP_CLEAN_UP_DISC_Q 0x20
1072#define ASC_STOP_HOST_REQ_RISC_HALT 0x40
1073#define ASC_TIDLUN_TO_IX(tid, lun) (ASC_SCSI_TIX_TYPE)((tid) + ((lun)<<ASC_SCSI_ID_BITS))
1074#define ASC_TID_TO_TARGET_ID(tid) (ASC_SCSI_BIT_ID_TYPE)(0x01 << (tid))
1075#define ASC_TIX_TO_TARGET_ID(tix) (0x01 << ((tix) & ASC_MAX_TID))
1076#define ASC_TIX_TO_TID(tix) ((tix) & ASC_MAX_TID)
1077#define ASC_TID_TO_TIX(tid) ((tid) & ASC_MAX_TID)
1078#define ASC_TIX_TO_LUN(tix) (((tix) >> ASC_SCSI_ID_BITS) & ASC_MAX_LUN)
1079#define ASC_QNO_TO_QADDR(q_no) ((ASC_QADR_BEG)+((int)(q_no) << 6))
1080
1081typedef struct asc_scsiq_1 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001082 uchar status;
1083 uchar q_no;
1084 uchar cntl;
1085 uchar sg_queue_cnt;
1086 uchar target_id;
1087 uchar target_lun;
1088 ASC_PADDR data_addr;
1089 ASC_DCNT data_cnt;
1090 ASC_PADDR sense_addr;
1091 uchar sense_len;
1092 uchar extra_bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093} ASC_SCSIQ_1;
1094
1095typedef struct asc_scsiq_2 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001096 ASC_VADDR srb_ptr;
1097 uchar target_ix;
1098 uchar flag;
1099 uchar cdb_len;
1100 uchar tag_code;
1101 ushort vm_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102} ASC_SCSIQ_2;
1103
1104typedef struct asc_scsiq_3 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001105 uchar done_stat;
1106 uchar host_stat;
1107 uchar scsi_stat;
1108 uchar scsi_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109} ASC_SCSIQ_3;
1110
1111typedef struct asc_scsiq_4 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001112 uchar cdb[ASC_MAX_CDB_LEN];
1113 uchar y_first_sg_list_qp;
1114 uchar y_working_sg_qp;
1115 uchar y_working_sg_ix;
1116 uchar y_res;
1117 ushort x_req_count;
1118 ushort x_reconnect_rtn;
1119 ASC_PADDR x_saved_data_addr;
1120 ASC_DCNT x_saved_data_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121} ASC_SCSIQ_4;
1122
1123typedef struct asc_q_done_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001124 ASC_SCSIQ_2 d2;
1125 ASC_SCSIQ_3 d3;
1126 uchar q_status;
1127 uchar q_no;
1128 uchar cntl;
1129 uchar sense_len;
1130 uchar extra_bytes;
1131 uchar res;
1132 ASC_DCNT remain_bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133} ASC_QDONE_INFO;
1134
1135typedef struct asc_sg_list {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001136 ASC_PADDR addr;
1137 ASC_DCNT bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138} ASC_SG_LIST;
1139
1140typedef struct asc_sg_head {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001141 ushort entry_cnt;
1142 ushort queue_cnt;
1143 ushort entry_to_copy;
1144 ushort res;
1145 ASC_SG_LIST sg_list[ASC_MAX_SG_LIST];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146} ASC_SG_HEAD;
1147
1148#define ASC_MIN_SG_LIST 2
1149
1150typedef struct asc_min_sg_head {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001151 ushort entry_cnt;
1152 ushort queue_cnt;
1153 ushort entry_to_copy;
1154 ushort res;
1155 ASC_SG_LIST sg_list[ASC_MIN_SG_LIST];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156} ASC_MIN_SG_HEAD;
1157
1158#define QCX_SORT (0x0001)
1159#define QCX_COALEASE (0x0002)
1160
1161typedef struct asc_scsi_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001162 ASC_SCSIQ_1 q1;
1163 ASC_SCSIQ_2 q2;
1164 uchar *cdbptr;
1165 ASC_SG_HEAD *sg_head;
1166 ushort remain_sg_entry_cnt;
1167 ushort next_sg_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168} ASC_SCSI_Q;
1169
1170typedef struct asc_scsi_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001171 ASC_SCSIQ_1 r1;
1172 ASC_SCSIQ_2 r2;
1173 uchar *cdbptr;
1174 ASC_SG_HEAD *sg_head;
1175 uchar *sense_ptr;
1176 ASC_SCSIQ_3 r3;
1177 uchar cdb[ASC_MAX_CDB_LEN];
1178 uchar sense[ASC_MIN_SENSE_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179} ASC_SCSI_REQ_Q;
1180
1181typedef struct asc_scsi_bios_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001182 ASC_SCSIQ_1 r1;
1183 ASC_SCSIQ_2 r2;
1184 uchar *cdbptr;
1185 ASC_SG_HEAD *sg_head;
1186 uchar *sense_ptr;
1187 ASC_SCSIQ_3 r3;
1188 uchar cdb[ASC_MAX_CDB_LEN];
1189 uchar sense[ASC_MIN_SENSE_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190} ASC_SCSI_BIOS_REQ_Q;
1191
1192typedef struct asc_risc_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001193 uchar fwd;
1194 uchar bwd;
1195 ASC_SCSIQ_1 i1;
1196 ASC_SCSIQ_2 i2;
1197 ASC_SCSIQ_3 i3;
1198 ASC_SCSIQ_4 i4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199} ASC_RISC_Q;
1200
1201typedef struct asc_sg_list_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001202 uchar seq_no;
1203 uchar q_no;
1204 uchar cntl;
1205 uchar sg_head_qp;
1206 uchar sg_list_cnt;
1207 uchar sg_cur_list_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208} ASC_SG_LIST_Q;
1209
1210typedef struct asc_risc_sg_list_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001211 uchar fwd;
1212 uchar bwd;
1213 ASC_SG_LIST_Q sg;
1214 ASC_SG_LIST sg_list[7];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215} ASC_RISC_SG_LIST_Q;
1216
1217#define ASC_EXE_SCSI_IO_MAX_IDLE_LOOP 0x1000000UL
1218#define ASC_EXE_SCSI_IO_MAX_WAIT_LOOP 1024
1219#define ASCQ_ERR_NO_ERROR 0
1220#define ASCQ_ERR_IO_NOT_FOUND 1
1221#define ASCQ_ERR_LOCAL_MEM 2
1222#define ASCQ_ERR_CHKSUM 3
1223#define ASCQ_ERR_START_CHIP 4
1224#define ASCQ_ERR_INT_TARGET_ID 5
1225#define ASCQ_ERR_INT_LOCAL_MEM 6
1226#define ASCQ_ERR_HALT_RISC 7
1227#define ASCQ_ERR_GET_ASPI_ENTRY 8
1228#define ASCQ_ERR_CLOSE_ASPI 9
1229#define ASCQ_ERR_HOST_INQUIRY 0x0A
1230#define ASCQ_ERR_SAVED_SRB_BAD 0x0B
1231#define ASCQ_ERR_QCNTL_SG_LIST 0x0C
1232#define ASCQ_ERR_Q_STATUS 0x0D
1233#define ASCQ_ERR_WR_SCSIQ 0x0E
1234#define ASCQ_ERR_PC_ADDR 0x0F
1235#define ASCQ_ERR_SYN_OFFSET 0x10
1236#define ASCQ_ERR_SYN_XFER_TIME 0x11
1237#define ASCQ_ERR_LOCK_DMA 0x12
1238#define ASCQ_ERR_UNLOCK_DMA 0x13
1239#define ASCQ_ERR_VDS_CHK_INSTALL 0x14
1240#define ASCQ_ERR_MICRO_CODE_HALT 0x15
1241#define ASCQ_ERR_SET_LRAM_ADDR 0x16
1242#define ASCQ_ERR_CUR_QNG 0x17
1243#define ASCQ_ERR_SG_Q_LINKS 0x18
1244#define ASCQ_ERR_SCSIQ_PTR 0x19
1245#define ASCQ_ERR_ISR_RE_ENTRY 0x1A
1246#define ASCQ_ERR_CRITICAL_RE_ENTRY 0x1B
1247#define ASCQ_ERR_ISR_ON_CRITICAL 0x1C
1248#define ASCQ_ERR_SG_LIST_ODD_ADDRESS 0x1D
1249#define ASCQ_ERR_XFER_ADDRESS_TOO_BIG 0x1E
1250#define ASCQ_ERR_SCSIQ_NULL_PTR 0x1F
1251#define ASCQ_ERR_SCSIQ_BAD_NEXT_PTR 0x20
1252#define ASCQ_ERR_GET_NUM_OF_FREE_Q 0x21
1253#define ASCQ_ERR_SEND_SCSI_Q 0x22
1254#define ASCQ_ERR_HOST_REQ_RISC_HALT 0x23
1255#define ASCQ_ERR_RESET_SDTR 0x24
1256
1257/*
1258 * Warning code values are set in ASC_DVC_VAR 'warn_code'.
1259 */
1260#define ASC_WARN_NO_ERROR 0x0000
1261#define ASC_WARN_IO_PORT_ROTATE 0x0001
1262#define ASC_WARN_EEPROM_CHKSUM 0x0002
1263#define ASC_WARN_IRQ_MODIFIED 0x0004
1264#define ASC_WARN_AUTO_CONFIG 0x0008
1265#define ASC_WARN_CMD_QNG_CONFLICT 0x0010
1266#define ASC_WARN_EEPROM_RECOVER 0x0020
1267#define ASC_WARN_CFG_MSW_RECOVER 0x0040
1268#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080
1269
1270/*
1271 * Error code values are set in ASC_DVC_VAR 'err_code'.
1272 */
1273#define ASC_IERR_WRITE_EEPROM 0x0001
1274#define ASC_IERR_MCODE_CHKSUM 0x0002
1275#define ASC_IERR_SET_PC_ADDR 0x0004
1276#define ASC_IERR_START_STOP_CHIP 0x0008
1277#define ASC_IERR_IRQ_NO 0x0010
1278#define ASC_IERR_SET_IRQ_NO 0x0020
1279#define ASC_IERR_CHIP_VERSION 0x0040
1280#define ASC_IERR_SET_SCSI_ID 0x0080
1281#define ASC_IERR_GET_PHY_ADDR 0x0100
1282#define ASC_IERR_BAD_SIGNATURE 0x0200
1283#define ASC_IERR_NO_BUS_TYPE 0x0400
1284#define ASC_IERR_SCAM 0x0800
1285#define ASC_IERR_SET_SDTR 0x1000
1286#define ASC_IERR_RW_LRAM 0x8000
1287
1288#define ASC_DEF_IRQ_NO 10
1289#define ASC_MAX_IRQ_NO 15
1290#define ASC_MIN_IRQ_NO 10
1291#define ASC_MIN_REMAIN_Q (0x02)
1292#define ASC_DEF_MAX_TOTAL_QNG (0xF0)
1293#define ASC_MIN_TAG_Q_PER_DVC (0x04)
1294#define ASC_DEF_TAG_Q_PER_DVC (0x04)
1295#define ASC_MIN_FREE_Q ASC_MIN_REMAIN_Q
1296#define ASC_MIN_TOTAL_QNG ((ASC_MAX_SG_QUEUE)+(ASC_MIN_FREE_Q))
1297#define ASC_MAX_TOTAL_QNG 240
1298#define ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG 16
1299#define ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG 8
1300#define ASC_MAX_PCI_INRAM_TOTAL_QNG 20
1301#define ASC_MAX_INRAM_TAG_QNG 16
1302#define ASC_IOADR_TABLE_MAX_IX 11
1303#define ASC_IOADR_GAP 0x10
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304#define ASC_LIB_SCSIQ_WK_SP 256
1305#define ASC_MAX_SYN_XFER_NO 16
1306#define ASC_SYN_MAX_OFFSET 0x0F
1307#define ASC_DEF_SDTR_OFFSET 0x0F
1308#define ASC_DEF_SDTR_INDEX 0x00
1309#define ASC_SDTR_ULTRA_PCI_10MB_INDEX 0x02
1310#define SYN_XFER_NS_0 25
1311#define SYN_XFER_NS_1 30
1312#define SYN_XFER_NS_2 35
1313#define SYN_XFER_NS_3 40
1314#define SYN_XFER_NS_4 50
1315#define SYN_XFER_NS_5 60
1316#define SYN_XFER_NS_6 70
1317#define SYN_XFER_NS_7 85
1318#define SYN_ULTRA_XFER_NS_0 12
1319#define SYN_ULTRA_XFER_NS_1 19
1320#define SYN_ULTRA_XFER_NS_2 25
1321#define SYN_ULTRA_XFER_NS_3 32
1322#define SYN_ULTRA_XFER_NS_4 38
1323#define SYN_ULTRA_XFER_NS_5 44
1324#define SYN_ULTRA_XFER_NS_6 50
1325#define SYN_ULTRA_XFER_NS_7 57
1326#define SYN_ULTRA_XFER_NS_8 63
1327#define SYN_ULTRA_XFER_NS_9 69
1328#define SYN_ULTRA_XFER_NS_10 75
1329#define SYN_ULTRA_XFER_NS_11 82
1330#define SYN_ULTRA_XFER_NS_12 88
1331#define SYN_ULTRA_XFER_NS_13 94
1332#define SYN_ULTRA_XFER_NS_14 100
1333#define SYN_ULTRA_XFER_NS_15 107
1334
1335typedef struct ext_msg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001336 uchar msg_type;
1337 uchar msg_len;
1338 uchar msg_req;
1339 union {
1340 struct {
1341 uchar sdtr_xfer_period;
1342 uchar sdtr_req_ack_offset;
1343 } sdtr;
1344 struct {
1345 uchar wdtr_width;
1346 } wdtr;
1347 struct {
1348 uchar mdp_b3;
1349 uchar mdp_b2;
1350 uchar mdp_b1;
1351 uchar mdp_b0;
1352 } mdp;
1353 } u_ext_msg;
1354 uchar res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355} EXT_MSG;
1356
1357#define xfer_period u_ext_msg.sdtr.sdtr_xfer_period
1358#define req_ack_offset u_ext_msg.sdtr.sdtr_req_ack_offset
1359#define wdtr_width u_ext_msg.wdtr.wdtr_width
1360#define mdp_b3 u_ext_msg.mdp_b3
1361#define mdp_b2 u_ext_msg.mdp_b2
1362#define mdp_b1 u_ext_msg.mdp_b1
1363#define mdp_b0 u_ext_msg.mdp_b0
1364
1365typedef struct asc_dvc_cfg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001366 ASC_SCSI_BIT_ID_TYPE can_tagged_qng;
1367 ASC_SCSI_BIT_ID_TYPE cmd_qng_enabled;
1368 ASC_SCSI_BIT_ID_TYPE disc_enable;
1369 ASC_SCSI_BIT_ID_TYPE sdtr_enable;
1370 uchar chip_scsi_id;
1371 uchar isa_dma_speed;
1372 uchar isa_dma_channel;
1373 uchar chip_version;
1374 ushort lib_serial_no;
1375 ushort lib_version;
1376 ushort mcode_date;
1377 ushort mcode_version;
1378 uchar max_tag_qng[ASC_MAX_TID + 1];
1379 uchar *overrun_buf;
1380 uchar sdtr_period_offset[ASC_MAX_TID + 1];
1381 ushort pci_slot_info;
1382 uchar adapter_info[6];
1383 struct device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384} ASC_DVC_CFG;
1385
1386#define ASC_DEF_DVC_CNTL 0xFFFF
1387#define ASC_DEF_CHIP_SCSI_ID 7
1388#define ASC_DEF_ISA_DMA_SPEED 4
1389#define ASC_INIT_STATE_NULL 0x0000
1390#define ASC_INIT_STATE_BEG_GET_CFG 0x0001
1391#define ASC_INIT_STATE_END_GET_CFG 0x0002
1392#define ASC_INIT_STATE_BEG_SET_CFG 0x0004
1393#define ASC_INIT_STATE_END_SET_CFG 0x0008
1394#define ASC_INIT_STATE_BEG_LOAD_MC 0x0010
1395#define ASC_INIT_STATE_END_LOAD_MC 0x0020
1396#define ASC_INIT_STATE_BEG_INQUIRY 0x0040
1397#define ASC_INIT_STATE_END_INQUIRY 0x0080
1398#define ASC_INIT_RESET_SCSI_DONE 0x0100
1399#define ASC_INIT_STATE_WITHOUT_EEP 0x8000
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400#define ASC_BUG_FIX_IF_NOT_DWB 0x0001
1401#define ASC_BUG_FIX_ASYN_USE_SYN 0x0002
1402#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41
1403#define ASC_MIN_TAGGED_CMD 7
1404#define ASC_MAX_SCSI_RESET_WAIT 30
1405
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001406struct asc_dvc_var; /* Forward Declaration. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001408typedef void (*ASC_ISR_CALLBACK) (struct asc_dvc_var *, ASC_QDONE_INFO *);
1409typedef int (*ASC_EXE_CALLBACK) (struct asc_dvc_var *, ASC_SCSI_Q *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410
1411typedef struct asc_dvc_var {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001412 PortAddr iop_base;
1413 ushort err_code;
1414 ushort dvc_cntl;
1415 ushort bug_fix_cntl;
1416 ushort bus_type;
1417 ASC_ISR_CALLBACK isr_callback;
1418 ASC_EXE_CALLBACK exe_callback;
1419 ASC_SCSI_BIT_ID_TYPE init_sdtr;
1420 ASC_SCSI_BIT_ID_TYPE sdtr_done;
1421 ASC_SCSI_BIT_ID_TYPE use_tagged_qng;
1422 ASC_SCSI_BIT_ID_TYPE unit_not_ready;
1423 ASC_SCSI_BIT_ID_TYPE queue_full_or_busy;
1424 ASC_SCSI_BIT_ID_TYPE start_motor;
1425 uchar scsi_reset_wait;
1426 uchar chip_no;
1427 char is_in_int;
1428 uchar max_total_qng;
1429 uchar cur_total_qng;
1430 uchar in_critical_cnt;
1431 uchar irq_no;
1432 uchar last_q_shortage;
1433 ushort init_state;
1434 uchar cur_dvc_qng[ASC_MAX_TID + 1];
1435 uchar max_dvc_qng[ASC_MAX_TID + 1];
1436 ASC_SCSI_Q *scsiq_busy_head[ASC_MAX_TID + 1];
1437 ASC_SCSI_Q *scsiq_busy_tail[ASC_MAX_TID + 1];
1438 uchar sdtr_period_tbl[ASC_MAX_SYN_XFER_NO];
1439 ASC_DVC_CFG *cfg;
1440 ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer_always;
1441 char redo_scam;
1442 ushort res2;
1443 uchar dos_int13_table[ASC_MAX_TID + 1];
1444 ASC_DCNT max_dma_count;
1445 ASC_SCSI_BIT_ID_TYPE no_scam;
1446 ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer;
1447 uchar max_sdtr_index;
1448 uchar host_init_sdtr_index;
1449 struct asc_board *drv_ptr;
1450 ASC_DCNT uc_break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451} ASC_DVC_VAR;
1452
1453typedef struct asc_dvc_inq_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001454 uchar type[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455} ASC_DVC_INQ_INFO;
1456
1457typedef struct asc_cap_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001458 ASC_DCNT lba;
1459 ASC_DCNT blk_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460} ASC_CAP_INFO;
1461
1462typedef struct asc_cap_info_array {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001463 ASC_CAP_INFO cap_info[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464} ASC_CAP_INFO_ARRAY;
1465
1466#define ASC_MCNTL_NO_SEL_TIMEOUT (ushort)0x0001
1467#define ASC_MCNTL_NULL_TARGET (ushort)0x0002
1468#define ASC_CNTL_INITIATOR (ushort)0x0001
1469#define ASC_CNTL_BIOS_GT_1GB (ushort)0x0002
1470#define ASC_CNTL_BIOS_GT_2_DISK (ushort)0x0004
1471#define ASC_CNTL_BIOS_REMOVABLE (ushort)0x0008
1472#define ASC_CNTL_NO_SCAM (ushort)0x0010
1473#define ASC_CNTL_INT_MULTI_Q (ushort)0x0080
1474#define ASC_CNTL_NO_LUN_SUPPORT (ushort)0x0040
1475#define ASC_CNTL_NO_VERIFY_COPY (ushort)0x0100
1476#define ASC_CNTL_RESET_SCSI (ushort)0x0200
1477#define ASC_CNTL_INIT_INQUIRY (ushort)0x0400
1478#define ASC_CNTL_INIT_VERBOSE (ushort)0x0800
1479#define ASC_CNTL_SCSI_PARITY (ushort)0x1000
1480#define ASC_CNTL_BURST_MODE (ushort)0x2000
1481#define ASC_CNTL_SDTR_ENABLE_ULTRA (ushort)0x4000
1482#define ASC_EEP_DVC_CFG_BEG_VL 2
1483#define ASC_EEP_MAX_DVC_ADDR_VL 15
1484#define ASC_EEP_DVC_CFG_BEG 32
1485#define ASC_EEP_MAX_DVC_ADDR 45
1486#define ASC_EEP_DEFINED_WORDS 10
1487#define ASC_EEP_MAX_ADDR 63
1488#define ASC_EEP_RES_WORDS 0
1489#define ASC_EEP_MAX_RETRY 20
1490#define ASC_MAX_INIT_BUSY_RETRY 8
1491#define ASC_EEP_ISA_PNP_WSIZE 16
1492
1493/*
1494 * These macros keep the chip SCSI id and ISA DMA speed
1495 * bitfields in board order. C bitfields aren't portable
1496 * between big and little-endian platforms so they are
1497 * not used.
1498 */
1499
1500#define ASC_EEP_GET_CHIP_ID(cfg) ((cfg)->id_speed & 0x0f)
1501#define ASC_EEP_GET_DMA_SPD(cfg) (((cfg)->id_speed & 0xf0) >> 4)
1502#define ASC_EEP_SET_CHIP_ID(cfg, sid) \
1503 ((cfg)->id_speed = ((cfg)->id_speed & 0xf0) | ((sid) & ASC_MAX_TID))
1504#define ASC_EEP_SET_DMA_SPD(cfg, spd) \
1505 ((cfg)->id_speed = ((cfg)->id_speed & 0x0f) | ((spd) & 0x0f) << 4)
1506
1507typedef struct asceep_config {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001508 ushort cfg_lsw;
1509 ushort cfg_msw;
1510 uchar init_sdtr;
1511 uchar disc_enable;
1512 uchar use_cmd_qng;
1513 uchar start_motor;
1514 uchar max_total_qng;
1515 uchar max_tag_qng;
1516 uchar bios_scan;
1517 uchar power_up_wait;
1518 uchar no_scam;
1519 uchar id_speed; /* low order 4 bits is chip scsi id */
1520 /* high order 4 bits is isa dma speed */
1521 uchar dos_int13_table[ASC_MAX_TID + 1];
1522 uchar adapter_info[6];
1523 ushort cntl;
1524 ushort chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525} ASCEEP_CONFIG;
1526
1527#define ASC_PCI_CFG_LSW_SCSI_PARITY 0x0800
1528#define ASC_PCI_CFG_LSW_BURST_MODE 0x0080
1529#define ASC_PCI_CFG_LSW_INTR_ABLE 0x0020
1530
1531#define ASC_EEP_CMD_READ 0x80
1532#define ASC_EEP_CMD_WRITE 0x40
1533#define ASC_EEP_CMD_WRITE_ABLE 0x30
1534#define ASC_EEP_CMD_WRITE_DISABLE 0x00
1535#define ASC_OVERRUN_BSIZE 0x00000048UL
1536#define ASC_CTRL_BREAK_ONCE 0x0001
1537#define ASC_CTRL_BREAK_STAY_IDLE 0x0002
1538#define ASCV_MSGOUT_BEG 0x0000
1539#define ASCV_MSGOUT_SDTR_PERIOD (ASCV_MSGOUT_BEG+3)
1540#define ASCV_MSGOUT_SDTR_OFFSET (ASCV_MSGOUT_BEG+4)
1541#define ASCV_BREAK_SAVED_CODE (ushort)0x0006
1542#define ASCV_MSGIN_BEG (ASCV_MSGOUT_BEG+8)
1543#define ASCV_MSGIN_SDTR_PERIOD (ASCV_MSGIN_BEG+3)
1544#define ASCV_MSGIN_SDTR_OFFSET (ASCV_MSGIN_BEG+4)
1545#define ASCV_SDTR_DATA_BEG (ASCV_MSGIN_BEG+8)
1546#define ASCV_SDTR_DONE_BEG (ASCV_SDTR_DATA_BEG+8)
1547#define ASCV_MAX_DVC_QNG_BEG (ushort)0x0020
1548#define ASCV_BREAK_ADDR (ushort)0x0028
1549#define ASCV_BREAK_NOTIFY_COUNT (ushort)0x002A
1550#define ASCV_BREAK_CONTROL (ushort)0x002C
1551#define ASCV_BREAK_HIT_COUNT (ushort)0x002E
1552
1553#define ASCV_ASCDVC_ERR_CODE_W (ushort)0x0030
1554#define ASCV_MCODE_CHKSUM_W (ushort)0x0032
1555#define ASCV_MCODE_SIZE_W (ushort)0x0034
1556#define ASCV_STOP_CODE_B (ushort)0x0036
1557#define ASCV_DVC_ERR_CODE_B (ushort)0x0037
1558#define ASCV_OVERRUN_PADDR_D (ushort)0x0038
1559#define ASCV_OVERRUN_BSIZE_D (ushort)0x003C
1560#define ASCV_HALTCODE_W (ushort)0x0040
1561#define ASCV_CHKSUM_W (ushort)0x0042
1562#define ASCV_MC_DATE_W (ushort)0x0044
1563#define ASCV_MC_VER_W (ushort)0x0046
1564#define ASCV_NEXTRDY_B (ushort)0x0048
1565#define ASCV_DONENEXT_B (ushort)0x0049
1566#define ASCV_USE_TAGGED_QNG_B (ushort)0x004A
1567#define ASCV_SCSIBUSY_B (ushort)0x004B
1568#define ASCV_Q_DONE_IN_PROGRESS_B (ushort)0x004C
1569#define ASCV_CURCDB_B (ushort)0x004D
1570#define ASCV_RCLUN_B (ushort)0x004E
1571#define ASCV_BUSY_QHEAD_B (ushort)0x004F
1572#define ASCV_DISC1_QHEAD_B (ushort)0x0050
1573#define ASCV_DISC_ENABLE_B (ushort)0x0052
1574#define ASCV_CAN_TAGGED_QNG_B (ushort)0x0053
1575#define ASCV_HOSTSCSI_ID_B (ushort)0x0055
1576#define ASCV_MCODE_CNTL_B (ushort)0x0056
1577#define ASCV_NULL_TARGET_B (ushort)0x0057
1578#define ASCV_FREE_Q_HEAD_W (ushort)0x0058
1579#define ASCV_DONE_Q_TAIL_W (ushort)0x005A
1580#define ASCV_FREE_Q_HEAD_B (ushort)(ASCV_FREE_Q_HEAD_W+1)
1581#define ASCV_DONE_Q_TAIL_B (ushort)(ASCV_DONE_Q_TAIL_W+1)
1582#define ASCV_HOST_FLAG_B (ushort)0x005D
1583#define ASCV_TOTAL_READY_Q_B (ushort)0x0064
1584#define ASCV_VER_SERIAL_B (ushort)0x0065
1585#define ASCV_HALTCODE_SAVED_W (ushort)0x0066
1586#define ASCV_WTM_FLAG_B (ushort)0x0068
1587#define ASCV_RISC_FLAG_B (ushort)0x006A
1588#define ASCV_REQ_SG_LIST_QP (ushort)0x006B
1589#define ASC_HOST_FLAG_IN_ISR 0x01
1590#define ASC_HOST_FLAG_ACK_INT 0x02
1591#define ASC_RISC_FLAG_GEN_INT 0x01
1592#define ASC_RISC_FLAG_REQ_SG_LIST 0x02
1593#define IOP_CTRL (0x0F)
1594#define IOP_STATUS (0x0E)
1595#define IOP_INT_ACK IOP_STATUS
1596#define IOP_REG_IFC (0x0D)
1597#define IOP_SYN_OFFSET (0x0B)
1598#define IOP_EXTRA_CONTROL (0x0D)
1599#define IOP_REG_PC (0x0C)
1600#define IOP_RAM_ADDR (0x0A)
1601#define IOP_RAM_DATA (0x08)
1602#define IOP_EEP_DATA (0x06)
1603#define IOP_EEP_CMD (0x07)
1604#define IOP_VERSION (0x03)
1605#define IOP_CONFIG_HIGH (0x04)
1606#define IOP_CONFIG_LOW (0x02)
1607#define IOP_SIG_BYTE (0x01)
1608#define IOP_SIG_WORD (0x00)
1609#define IOP_REG_DC1 (0x0E)
1610#define IOP_REG_DC0 (0x0C)
1611#define IOP_REG_SB (0x0B)
1612#define IOP_REG_DA1 (0x0A)
1613#define IOP_REG_DA0 (0x08)
1614#define IOP_REG_SC (0x09)
1615#define IOP_DMA_SPEED (0x07)
1616#define IOP_REG_FLAG (0x07)
1617#define IOP_FIFO_H (0x06)
1618#define IOP_FIFO_L (0x04)
1619#define IOP_REG_ID (0x05)
1620#define IOP_REG_QP (0x03)
1621#define IOP_REG_IH (0x02)
1622#define IOP_REG_IX (0x01)
1623#define IOP_REG_AX (0x00)
1624#define IFC_REG_LOCK (0x00)
1625#define IFC_REG_UNLOCK (0x09)
1626#define IFC_WR_EN_FILTER (0x10)
1627#define IFC_RD_NO_EEPROM (0x10)
1628#define IFC_SLEW_RATE (0x20)
1629#define IFC_ACT_NEG (0x40)
1630#define IFC_INP_FILTER (0x80)
1631#define IFC_INIT_DEFAULT (IFC_ACT_NEG | IFC_REG_UNLOCK)
1632#define SC_SEL (uchar)(0x80)
1633#define SC_BSY (uchar)(0x40)
1634#define SC_ACK (uchar)(0x20)
1635#define SC_REQ (uchar)(0x10)
1636#define SC_ATN (uchar)(0x08)
1637#define SC_IO (uchar)(0x04)
1638#define SC_CD (uchar)(0x02)
1639#define SC_MSG (uchar)(0x01)
1640#define SEC_SCSI_CTL (uchar)(0x80)
1641#define SEC_ACTIVE_NEGATE (uchar)(0x40)
1642#define SEC_SLEW_RATE (uchar)(0x20)
1643#define SEC_ENABLE_FILTER (uchar)(0x10)
1644#define ASC_HALT_EXTMSG_IN (ushort)0x8000
1645#define ASC_HALT_CHK_CONDITION (ushort)0x8100
1646#define ASC_HALT_SS_QUEUE_FULL (ushort)0x8200
1647#define ASC_HALT_DISABLE_ASYN_USE_SYN_FIX (ushort)0x8300
1648#define ASC_HALT_ENABLE_ASYN_USE_SYN_FIX (ushort)0x8400
1649#define ASC_HALT_SDTR_REJECTED (ushort)0x4000
1650#define ASC_HALT_HOST_COPY_SG_LIST_TO_RISC ( ushort )0x2000
1651#define ASC_MAX_QNO 0xF8
1652#define ASC_DATA_SEC_BEG (ushort)0x0080
1653#define ASC_DATA_SEC_END (ushort)0x0080
1654#define ASC_CODE_SEC_BEG (ushort)0x0080
1655#define ASC_CODE_SEC_END (ushort)0x0080
1656#define ASC_QADR_BEG (0x4000)
1657#define ASC_QADR_USED (ushort)(ASC_MAX_QNO * 64)
1658#define ASC_QADR_END (ushort)0x7FFF
1659#define ASC_QLAST_ADR (ushort)0x7FC0
1660#define ASC_QBLK_SIZE 0x40
1661#define ASC_BIOS_DATA_QBEG 0xF8
1662#define ASC_MIN_ACTIVE_QNO 0x01
1663#define ASC_QLINK_END 0xFF
1664#define ASC_EEPROM_WORDS 0x10
1665#define ASC_MAX_MGS_LEN 0x10
1666#define ASC_BIOS_ADDR_DEF 0xDC00
1667#define ASC_BIOS_SIZE 0x3800
1668#define ASC_BIOS_RAM_OFF 0x3800
1669#define ASC_BIOS_RAM_SIZE 0x800
1670#define ASC_BIOS_MIN_ADDR 0xC000
1671#define ASC_BIOS_MAX_ADDR 0xEC00
1672#define ASC_BIOS_BANK_SIZE 0x0400
1673#define ASC_MCODE_START_ADDR 0x0080
1674#define ASC_CFG0_HOST_INT_ON 0x0020
1675#define ASC_CFG0_BIOS_ON 0x0040
1676#define ASC_CFG0_VERA_BURST_ON 0x0080
1677#define ASC_CFG0_SCSI_PARITY_ON 0x0800
1678#define ASC_CFG1_SCSI_TARGET_ON 0x0080
1679#define ASC_CFG1_LRAM_8BITS_ON 0x0800
1680#define ASC_CFG_MSW_CLR_MASK 0x3080
1681#define CSW_TEST1 (ASC_CS_TYPE)0x8000
1682#define CSW_AUTO_CONFIG (ASC_CS_TYPE)0x4000
1683#define CSW_RESERVED1 (ASC_CS_TYPE)0x2000
1684#define CSW_IRQ_WRITTEN (ASC_CS_TYPE)0x1000
1685#define CSW_33MHZ_SELECTED (ASC_CS_TYPE)0x0800
1686#define CSW_TEST2 (ASC_CS_TYPE)0x0400
1687#define CSW_TEST3 (ASC_CS_TYPE)0x0200
1688#define CSW_RESERVED2 (ASC_CS_TYPE)0x0100
1689#define CSW_DMA_DONE (ASC_CS_TYPE)0x0080
1690#define CSW_FIFO_RDY (ASC_CS_TYPE)0x0040
1691#define CSW_EEP_READ_DONE (ASC_CS_TYPE)0x0020
1692#define CSW_HALTED (ASC_CS_TYPE)0x0010
1693#define CSW_SCSI_RESET_ACTIVE (ASC_CS_TYPE)0x0008
1694#define CSW_PARITY_ERR (ASC_CS_TYPE)0x0004
1695#define CSW_SCSI_RESET_LATCH (ASC_CS_TYPE)0x0002
1696#define CSW_INT_PENDING (ASC_CS_TYPE)0x0001
1697#define CIW_CLR_SCSI_RESET_INT (ASC_CS_TYPE)0x1000
1698#define CIW_INT_ACK (ASC_CS_TYPE)0x0100
1699#define CIW_TEST1 (ASC_CS_TYPE)0x0200
1700#define CIW_TEST2 (ASC_CS_TYPE)0x0400
1701#define CIW_SEL_33MHZ (ASC_CS_TYPE)0x0800
1702#define CIW_IRQ_ACT (ASC_CS_TYPE)0x1000
1703#define CC_CHIP_RESET (uchar)0x80
1704#define CC_SCSI_RESET (uchar)0x40
1705#define CC_HALT (uchar)0x20
1706#define CC_SINGLE_STEP (uchar)0x10
1707#define CC_DMA_ABLE (uchar)0x08
1708#define CC_TEST (uchar)0x04
1709#define CC_BANK_ONE (uchar)0x02
1710#define CC_DIAG (uchar)0x01
1711#define ASC_1000_ID0W 0x04C1
1712#define ASC_1000_ID0W_FIX 0x00C1
1713#define ASC_1000_ID1B 0x25
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714#define ASC_EISA_REV_IOP_MASK (0x0C83)
1715#define ASC_EISA_PID_IOP_MASK (0x0C80)
1716#define ASC_EISA_CFG_IOP_MASK (0x0C86)
1717#define ASC_GET_EISA_SLOT(iop) (PortAddr)((iop) & 0xF000)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718#define INS_HALTINT (ushort)0x6281
1719#define INS_HALT (ushort)0x6280
1720#define INS_SINT (ushort)0x6200
1721#define INS_RFLAG_WTM (ushort)0x7380
1722#define ASC_MC_SAVE_CODE_WSIZE 0x500
1723#define ASC_MC_SAVE_DATA_WSIZE 0x40
1724
1725typedef struct asc_mc_saved {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001726 ushort data[ASC_MC_SAVE_DATA_WSIZE];
1727 ushort code[ASC_MC_SAVE_CODE_WSIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728} ASC_MC_SAVED;
1729
1730#define AscGetQDoneInProgress(port) AscReadLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B)
1731#define AscPutQDoneInProgress(port, val) AscWriteLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B, val)
1732#define AscGetVarFreeQHead(port) AscReadLramWord((port), ASCV_FREE_Q_HEAD_W)
1733#define AscGetVarDoneQTail(port) AscReadLramWord((port), ASCV_DONE_Q_TAIL_W)
1734#define AscPutVarFreeQHead(port, val) AscWriteLramWord((port), ASCV_FREE_Q_HEAD_W, val)
1735#define AscPutVarDoneQTail(port, val) AscWriteLramWord((port), ASCV_DONE_Q_TAIL_W, val)
1736#define AscGetRiscVarFreeQHead(port) AscReadLramByte((port), ASCV_NEXTRDY_B)
1737#define AscGetRiscVarDoneQTail(port) AscReadLramByte((port), ASCV_DONENEXT_B)
1738#define AscPutRiscVarFreeQHead(port, val) AscWriteLramByte((port), ASCV_NEXTRDY_B, val)
1739#define AscPutRiscVarDoneQTail(port, val) AscWriteLramByte((port), ASCV_DONENEXT_B, val)
1740#define AscPutMCodeSDTRDoneAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id), (data));
1741#define AscGetMCodeSDTRDoneAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id));
1742#define AscPutMCodeInitSDTRAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id), data);
1743#define AscGetMCodeInitSDTRAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id));
1744#define AscSynIndexToPeriod(index) (uchar)(asc_dvc->sdtr_period_tbl[ (index) ])
1745#define AscGetChipSignatureByte(port) (uchar)inp((port)+IOP_SIG_BYTE)
1746#define AscGetChipSignatureWord(port) (ushort)inpw((port)+IOP_SIG_WORD)
1747#define AscGetChipVerNo(port) (uchar)inp((port)+IOP_VERSION)
1748#define AscGetChipCfgLsw(port) (ushort)inpw((port)+IOP_CONFIG_LOW)
1749#define AscGetChipCfgMsw(port) (ushort)inpw((port)+IOP_CONFIG_HIGH)
1750#define AscSetChipCfgLsw(port, data) outpw((port)+IOP_CONFIG_LOW, data)
1751#define AscSetChipCfgMsw(port, data) outpw((port)+IOP_CONFIG_HIGH, data)
1752#define AscGetChipEEPCmd(port) (uchar)inp((port)+IOP_EEP_CMD)
1753#define AscSetChipEEPCmd(port, data) outp((port)+IOP_EEP_CMD, data)
1754#define AscGetChipEEPData(port) (ushort)inpw((port)+IOP_EEP_DATA)
1755#define AscSetChipEEPData(port, data) outpw((port)+IOP_EEP_DATA, data)
1756#define AscGetChipLramAddr(port) (ushort)inpw((PortAddr)((port)+IOP_RAM_ADDR))
1757#define AscSetChipLramAddr(port, addr) outpw((PortAddr)((port)+IOP_RAM_ADDR), addr)
1758#define AscGetChipLramData(port) (ushort)inpw((port)+IOP_RAM_DATA)
1759#define AscSetChipLramData(port, data) outpw((port)+IOP_RAM_DATA, data)
1760#define AscGetChipIFC(port) (uchar)inp((port)+IOP_REG_IFC)
1761#define AscSetChipIFC(port, data) outp((port)+IOP_REG_IFC, data)
1762#define AscGetChipStatus(port) (ASC_CS_TYPE)inpw((port)+IOP_STATUS)
1763#define AscSetChipStatus(port, cs_val) outpw((port)+IOP_STATUS, cs_val)
1764#define AscGetChipControl(port) (uchar)inp((port)+IOP_CTRL)
1765#define AscSetChipControl(port, cc_val) outp((port)+IOP_CTRL, cc_val)
1766#define AscGetChipSyn(port) (uchar)inp((port)+IOP_SYN_OFFSET)
1767#define AscSetChipSyn(port, data) outp((port)+IOP_SYN_OFFSET, data)
1768#define AscSetPCAddr(port, data) outpw((port)+IOP_REG_PC, data)
1769#define AscGetPCAddr(port) (ushort)inpw((port)+IOP_REG_PC)
1770#define AscIsIntPending(port) (AscGetChipStatus(port) & (CSW_INT_PENDING | CSW_SCSI_RESET_LATCH))
1771#define AscGetChipScsiID(port) ((AscGetChipCfgLsw(port) >> 8) & ASC_MAX_TID)
1772#define AscGetExtraControl(port) (uchar)inp((port)+IOP_EXTRA_CONTROL)
1773#define AscSetExtraControl(port, data) outp((port)+IOP_EXTRA_CONTROL, data)
1774#define AscReadChipAX(port) (ushort)inpw((port)+IOP_REG_AX)
1775#define AscWriteChipAX(port, data) outpw((port)+IOP_REG_AX, data)
1776#define AscReadChipIX(port) (uchar)inp((port)+IOP_REG_IX)
1777#define AscWriteChipIX(port, data) outp((port)+IOP_REG_IX, data)
1778#define AscReadChipIH(port) (ushort)inpw((port)+IOP_REG_IH)
1779#define AscWriteChipIH(port, data) outpw((port)+IOP_REG_IH, data)
1780#define AscReadChipQP(port) (uchar)inp((port)+IOP_REG_QP)
1781#define AscWriteChipQP(port, data) outp((port)+IOP_REG_QP, data)
1782#define AscReadChipFIFO_L(port) (ushort)inpw((port)+IOP_REG_FIFO_L)
1783#define AscWriteChipFIFO_L(port, data) outpw((port)+IOP_REG_FIFO_L, data)
1784#define AscReadChipFIFO_H(port) (ushort)inpw((port)+IOP_REG_FIFO_H)
1785#define AscWriteChipFIFO_H(port, data) outpw((port)+IOP_REG_FIFO_H, data)
1786#define AscReadChipDmaSpeed(port) (uchar)inp((port)+IOP_DMA_SPEED)
1787#define AscWriteChipDmaSpeed(port, data) outp((port)+IOP_DMA_SPEED, data)
1788#define AscReadChipDA0(port) (ushort)inpw((port)+IOP_REG_DA0)
1789#define AscWriteChipDA0(port) outpw((port)+IOP_REG_DA0, data)
1790#define AscReadChipDA1(port) (ushort)inpw((port)+IOP_REG_DA1)
1791#define AscWriteChipDA1(port) outpw((port)+IOP_REG_DA1, data)
1792#define AscReadChipDC0(port) (ushort)inpw((port)+IOP_REG_DC0)
1793#define AscWriteChipDC0(port) outpw((port)+IOP_REG_DC0, data)
1794#define AscReadChipDC1(port) (ushort)inpw((port)+IOP_REG_DC1)
1795#define AscWriteChipDC1(port) outpw((port)+IOP_REG_DC1, data)
1796#define AscReadChipDvcID(port) (uchar)inp((port)+IOP_REG_ID)
1797#define AscWriteChipDvcID(port, data) outp((port)+IOP_REG_ID, data)
1798
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001799static int AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg);
1800static int AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg);
1801static void AscWaitEEPRead(void);
1802static void AscWaitEEPWrite(void);
1803static ushort AscReadEEPWord(PortAddr, uchar);
1804static ushort AscWriteEEPWord(PortAddr, uchar, ushort);
1805static ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
1806static int AscSetEEPConfigOnce(PortAddr, ASCEEP_CONFIG *, ushort);
1807static int AscSetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
1808static int AscStartChip(PortAddr);
1809static int AscStopChip(PortAddr);
1810static void AscSetChipIH(PortAddr, ushort);
1811static int AscIsChipHalted(PortAddr);
1812static void AscAckInterrupt(PortAddr);
1813static void AscDisableInterrupt(PortAddr);
1814static void AscEnableInterrupt(PortAddr);
1815static void AscSetBank(PortAddr, uchar);
1816static int AscResetChipAndScsiBus(ASC_DVC_VAR *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001818static uchar AscGetIsaDmaSpeed(PortAddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001820static uchar AscReadLramByte(PortAddr, ushort);
1821static ushort AscReadLramWord(PortAddr, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001823static ASC_DCNT AscReadLramDWord(PortAddr, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001825static void AscWriteLramWord(PortAddr, ushort, ushort);
1826static void AscWriteLramByte(PortAddr, ushort, uchar);
1827static ASC_DCNT AscMemSumLramWord(PortAddr, ushort, int);
1828static void AscMemWordSetLram(PortAddr, ushort, ushort, int);
1829static void AscMemWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
1830static void AscMemDWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
1831static void AscMemWordCopyPtrFromLram(PortAddr, ushort, uchar *, int);
1832static ushort AscInitAscDvcVar(ASC_DVC_VAR *);
1833static ushort AscInitFromEEP(ASC_DVC_VAR *);
1834static ushort AscInitFromAscDvcVar(ASC_DVC_VAR *);
1835static ushort AscInitMicroCodeVar(ASC_DVC_VAR *);
1836static int AscTestExternalLram(ASC_DVC_VAR *);
1837static uchar AscMsgOutSDTR(ASC_DVC_VAR *, uchar, uchar);
1838static uchar AscCalSDTRData(ASC_DVC_VAR *, uchar, uchar);
1839static void AscSetChipSDTR(PortAddr, uchar, uchar);
1840static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *, uchar);
1841static uchar AscAllocFreeQueue(PortAddr, uchar);
1842static uchar AscAllocMultipleFreeQueue(PortAddr, uchar, uchar);
1843static int AscHostReqRiscHalt(PortAddr);
1844static int AscStopQueueExe(PortAddr);
1845static int AscSendScsiQueue(ASC_DVC_VAR *,
1846 ASC_SCSI_Q *scsiq, uchar n_q_required);
1847static int AscPutReadyQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
1848static int AscPutReadySgListQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
1849static int AscSetChipSynRegAtID(PortAddr, uchar, uchar);
1850static int AscSetRunChipSynRegAtID(PortAddr, uchar, uchar);
1851static ushort AscInitLram(ASC_DVC_VAR *);
1852static ushort AscInitQLinkVar(ASC_DVC_VAR *);
1853static int AscSetLibErrorCode(ASC_DVC_VAR *, ushort);
1854static int AscIsrChipHalted(ASC_DVC_VAR *);
1855static uchar _AscCopyLramScsiDoneQ(PortAddr, ushort,
1856 ASC_QDONE_INFO *, ASC_DCNT);
1857static int AscIsrQDone(ASC_DVC_VAR *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001859static ushort AscGetEisaChipCfg(PortAddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001861static uchar AscGetChipScsiCtrl(PortAddr);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001862static uchar AscGetChipVersion(PortAddr, ushort);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001863static ASC_DCNT AscLoadMicroCode(PortAddr, ushort, uchar *, ushort);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001864static void AscToggleIRQAct(PortAddr);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001865static inline ulong DvcEnterCritical(void);
1866static inline void DvcLeaveCritical(ulong);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001867static void DvcSleepMilliSecond(ASC_DCNT);
1868static void DvcDelayNanoSecond(ASC_DVC_VAR *, ASC_DCNT);
1869static void DvcPutScsiQ(PortAddr, ushort, uchar *, int);
1870static void DvcGetQinfo(PortAddr, ushort, uchar *, int);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001871static ushort AscInitAsc1000Driver(ASC_DVC_VAR *);
Matthew Wilcox47d853c2007-07-26 11:41:33 -04001872static void AscAsyncFix(ASC_DVC_VAR *, struct scsi_device *);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001873static int AscExeScsiQueue(ASC_DVC_VAR *, ASC_SCSI_Q *);
1874static int AscISR(ASC_DVC_VAR *);
1875static uint AscGetNumOfFreeQueue(ASC_DVC_VAR *, uchar, uchar);
1876static int AscSgListToQueue(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001878static void AscEnableIsaDma(uchar);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001880static const char *advansys_info(struct Scsi_Host *shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881
1882/*
1883 * --- Adv Library Constants and Macros
1884 */
1885
1886#define ADV_LIB_VERSION_MAJOR 5
1887#define ADV_LIB_VERSION_MINOR 14
1888
1889/*
1890 * Define Adv Library required special types.
1891 */
1892
1893/*
1894 * Portable Data Types
1895 *
1896 * Any instance where a 32-bit long or pointer type is assumed
1897 * for precision or HW defined structures, the following define
1898 * types must be used. In Linux the char, short, and int types
1899 * are all consistent at 8, 16, and 32 bits respectively. Pointers
1900 * and long types are 64 bits on Alpha and UltraSPARC.
1901 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001902#define ADV_PADDR __u32 /* Physical address data type. */
1903#define ADV_VADDR __u32 /* Virtual address data type. */
1904#define ADV_DCNT __u32 /* Unsigned Data count type. */
1905#define ADV_SDCNT __s32 /* Signed Data count type. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906
1907/*
1908 * These macros are used to convert a virtual address to a
1909 * 32-bit value. This currently can be used on Linux Alpha
1910 * which uses 64-bit virtual address but a 32-bit bus address.
1911 * This is likely to break in the future, but doing this now
1912 * will give us time to change the HW and FW to handle 64-bit
1913 * addresses.
1914 */
1915#define ADV_VADDR_TO_U32 virt_to_bus
1916#define ADV_U32_TO_VADDR bus_to_virt
1917
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001918#define AdvPortAddr void __iomem * /* Virtual memory address size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919
1920/*
1921 * Define Adv Library required memory access macros.
1922 */
1923#define ADV_MEM_READB(addr) readb(addr)
1924#define ADV_MEM_READW(addr) readw(addr)
1925#define ADV_MEM_WRITEB(addr, byte) writeb(byte, addr)
1926#define ADV_MEM_WRITEW(addr, word) writew(word, addr)
1927#define ADV_MEM_WRITEDW(addr, dword) writel(dword, addr)
1928
1929#define ADV_CARRIER_COUNT (ASC_DEF_MAX_HOST_QNG + 15)
1930
1931/*
1932 * For wide boards a CDB length maximum of 16 bytes
1933 * is supported.
1934 */
1935#define ADV_MAX_CDB_LEN 16
1936
1937/*
1938 * Define total number of simultaneous maximum element scatter-gather
1939 * request blocks per wide adapter. ASC_DEF_MAX_HOST_QNG (253) is the
1940 * maximum number of outstanding commands per wide host adapter. Each
1941 * command uses one or more ADV_SG_BLOCK each with 15 scatter-gather
1942 * elements. Allow each command to have at least one ADV_SG_BLOCK structure.
1943 * This allows about 15 commands to have the maximum 17 ADV_SG_BLOCK
1944 * structures or 255 scatter-gather elements.
1945 *
1946 */
1947#define ADV_TOT_SG_BLOCK ASC_DEF_MAX_HOST_QNG
1948
1949/*
1950 * Define Adv Library required maximum number of scatter-gather
1951 * elements per request.
1952 */
1953#define ADV_MAX_SG_LIST 255
1954
1955/* Number of SG blocks needed. */
1956#define ADV_NUM_SG_BLOCK \
1957 ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)
1958
1959/* Total contiguous memory needed for SG blocks. */
1960#define ADV_SG_TOTAL_MEM_SIZE \
1961 (sizeof(ADV_SG_BLOCK) * ADV_NUM_SG_BLOCK)
1962
1963#define ADV_PAGE_SIZE PAGE_SIZE
1964
1965#define ADV_NUM_PAGE_CROSSING \
1966 ((ADV_SG_TOTAL_MEM_SIZE + (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
1967
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968#define ADV_EEP_DVC_CFG_BEGIN (0x00)
1969#define ADV_EEP_DVC_CFG_END (0x15)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001970#define ADV_EEP_DVC_CTL_BEGIN (0x16) /* location of OEM name */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971#define ADV_EEP_MAX_WORD_ADDR (0x1E)
1972
1973#define ADV_EEP_DELAY_MS 100
1974
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001975#define ADV_EEPROM_BIG_ENDIAN 0x8000 /* EEPROM Bit 15 */
1976#define ADV_EEPROM_BIOS_ENABLE 0x4000 /* EEPROM Bit 14 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977/*
1978 * For the ASC3550 Bit 13 is Termination Polarity control bit.
1979 * For later ICs Bit 13 controls whether the CIS (Card Information
1980 * Service Section) is loaded from EEPROM.
1981 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001982#define ADV_EEPROM_TERM_POL 0x2000 /* EEPROM Bit 13 */
1983#define ADV_EEPROM_CIS_LD 0x2000 /* EEPROM Bit 13 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984/*
1985 * ASC38C1600 Bit 11
1986 *
1987 * If EEPROM Bit 11 is 0 for Function 0, then Function 0 will specify
1988 * INT A in the PCI Configuration Space Int Pin field. If it is 1, then
1989 * Function 0 will specify INT B.
1990 *
1991 * If EEPROM Bit 11 is 0 for Function 1, then Function 1 will specify
1992 * INT B in the PCI Configuration Space Int Pin field. If it is 1, then
1993 * Function 1 will specify INT A.
1994 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001995#define ADV_EEPROM_INTAB 0x0800 /* EEPROM Bit 11 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001997typedef struct adveep_3550_config {
1998 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002000 ushort cfg_lsw; /* 00 power up initialization */
2001 /* bit 13 set - Term Polarity Control */
2002 /* bit 14 set - BIOS Enable */
2003 /* bit 15 set - Big Endian Mode */
2004 ushort cfg_msw; /* 01 unused */
2005 ushort disc_enable; /* 02 disconnect enable */
2006 ushort wdtr_able; /* 03 Wide DTR able */
2007 ushort sdtr_able; /* 04 Synchronous DTR able */
2008 ushort start_motor; /* 05 send start up motor */
2009 ushort tagqng_able; /* 06 tag queuing able */
2010 ushort bios_scan; /* 07 BIOS device control */
2011 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002013 uchar adapter_scsi_id; /* 09 Host Adapter ID */
2014 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002016 uchar scsi_reset_delay; /* 10 reset delay */
2017 uchar bios_id_lun; /* first boot device scsi id & lun */
2018 /* high nibble is lun */
2019 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002021 uchar termination; /* 11 0 - automatic */
2022 /* 1 - low off / high off */
2023 /* 2 - low off / high on */
2024 /* 3 - low on / high on */
2025 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002027 uchar reserved1; /* reserved byte (not used) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002029 ushort bios_ctrl; /* 12 BIOS control bits */
2030 /* bit 0 BIOS don't act as initiator. */
2031 /* bit 1 BIOS > 1 GB support */
2032 /* bit 2 BIOS > 2 Disk Support */
2033 /* bit 3 BIOS don't support removables */
2034 /* bit 4 BIOS support bootable CD */
2035 /* bit 5 BIOS scan enabled */
2036 /* bit 6 BIOS support multiple LUNs */
2037 /* bit 7 BIOS display of message */
2038 /* bit 8 SCAM disabled */
2039 /* bit 9 Reset SCSI bus during init. */
2040 /* bit 10 */
2041 /* bit 11 No verbose initialization. */
2042 /* bit 12 SCSI parity enabled */
2043 /* bit 13 */
2044 /* bit 14 */
2045 /* bit 15 */
2046 ushort ultra_able; /* 13 ULTRA speed able */
2047 ushort reserved2; /* 14 reserved */
2048 uchar max_host_qng; /* 15 maximum host queuing */
2049 uchar max_dvc_qng; /* maximum per device queuing */
2050 ushort dvc_cntl; /* 16 control bit for driver */
2051 ushort bug_fix; /* 17 control bit for bug fix */
2052 ushort serial_number_word1; /* 18 Board serial number word 1 */
2053 ushort serial_number_word2; /* 19 Board serial number word 2 */
2054 ushort serial_number_word3; /* 20 Board serial number word 3 */
2055 ushort check_sum; /* 21 EEP check sum */
2056 uchar oem_name[16]; /* 22 OEM name */
2057 ushort dvc_err_code; /* 30 last device driver error code */
2058 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
2059 ushort adv_err_addr; /* 32 last uc error address */
2060 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
2061 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
2062 ushort saved_adv_err_addr; /* 35 saved last uc error address */
2063 ushort num_of_err; /* 36 number of error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064} ADVEEP_3550_CONFIG;
2065
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002066typedef struct adveep_38C0800_config {
2067 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002069 ushort cfg_lsw; /* 00 power up initialization */
2070 /* bit 13 set - Load CIS */
2071 /* bit 14 set - BIOS Enable */
2072 /* bit 15 set - Big Endian Mode */
2073 ushort cfg_msw; /* 01 unused */
2074 ushort disc_enable; /* 02 disconnect enable */
2075 ushort wdtr_able; /* 03 Wide DTR able */
2076 ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
2077 ushort start_motor; /* 05 send start up motor */
2078 ushort tagqng_able; /* 06 tag queuing able */
2079 ushort bios_scan; /* 07 BIOS device control */
2080 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002082 uchar adapter_scsi_id; /* 09 Host Adapter ID */
2083 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002085 uchar scsi_reset_delay; /* 10 reset delay */
2086 uchar bios_id_lun; /* first boot device scsi id & lun */
2087 /* high nibble is lun */
2088 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002090 uchar termination_se; /* 11 0 - automatic */
2091 /* 1 - low off / high off */
2092 /* 2 - low off / high on */
2093 /* 3 - low on / high on */
2094 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002096 uchar termination_lvd; /* 11 0 - automatic */
2097 /* 1 - low off / high off */
2098 /* 2 - low off / high on */
2099 /* 3 - low on / high on */
2100 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002102 ushort bios_ctrl; /* 12 BIOS control bits */
2103 /* bit 0 BIOS don't act as initiator. */
2104 /* bit 1 BIOS > 1 GB support */
2105 /* bit 2 BIOS > 2 Disk Support */
2106 /* bit 3 BIOS don't support removables */
2107 /* bit 4 BIOS support bootable CD */
2108 /* bit 5 BIOS scan enabled */
2109 /* bit 6 BIOS support multiple LUNs */
2110 /* bit 7 BIOS display of message */
2111 /* bit 8 SCAM disabled */
2112 /* bit 9 Reset SCSI bus during init. */
2113 /* bit 10 */
2114 /* bit 11 No verbose initialization. */
2115 /* bit 12 SCSI parity enabled */
2116 /* bit 13 */
2117 /* bit 14 */
2118 /* bit 15 */
2119 ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
2120 ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
2121 uchar max_host_qng; /* 15 maximum host queueing */
2122 uchar max_dvc_qng; /* maximum per device queuing */
2123 ushort dvc_cntl; /* 16 control bit for driver */
2124 ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
2125 ushort serial_number_word1; /* 18 Board serial number word 1 */
2126 ushort serial_number_word2; /* 19 Board serial number word 2 */
2127 ushort serial_number_word3; /* 20 Board serial number word 3 */
2128 ushort check_sum; /* 21 EEP check sum */
2129 uchar oem_name[16]; /* 22 OEM name */
2130 ushort dvc_err_code; /* 30 last device driver error code */
2131 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
2132 ushort adv_err_addr; /* 32 last uc error address */
2133 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
2134 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
2135 ushort saved_adv_err_addr; /* 35 saved last uc error address */
2136 ushort reserved36; /* 36 reserved */
2137 ushort reserved37; /* 37 reserved */
2138 ushort reserved38; /* 38 reserved */
2139 ushort reserved39; /* 39 reserved */
2140 ushort reserved40; /* 40 reserved */
2141 ushort reserved41; /* 41 reserved */
2142 ushort reserved42; /* 42 reserved */
2143 ushort reserved43; /* 43 reserved */
2144 ushort reserved44; /* 44 reserved */
2145 ushort reserved45; /* 45 reserved */
2146 ushort reserved46; /* 46 reserved */
2147 ushort reserved47; /* 47 reserved */
2148 ushort reserved48; /* 48 reserved */
2149 ushort reserved49; /* 49 reserved */
2150 ushort reserved50; /* 50 reserved */
2151 ushort reserved51; /* 51 reserved */
2152 ushort reserved52; /* 52 reserved */
2153 ushort reserved53; /* 53 reserved */
2154 ushort reserved54; /* 54 reserved */
2155 ushort reserved55; /* 55 reserved */
2156 ushort cisptr_lsw; /* 56 CIS PTR LSW */
2157 ushort cisprt_msw; /* 57 CIS PTR MSW */
2158 ushort subsysvid; /* 58 SubSystem Vendor ID */
2159 ushort subsysid; /* 59 SubSystem ID */
2160 ushort reserved60; /* 60 reserved */
2161 ushort reserved61; /* 61 reserved */
2162 ushort reserved62; /* 62 reserved */
2163 ushort reserved63; /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164} ADVEEP_38C0800_CONFIG;
2165
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002166typedef struct adveep_38C1600_config {
2167 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002169 ushort cfg_lsw; /* 00 power up initialization */
2170 /* bit 11 set - Func. 0 INTB, Func. 1 INTA */
2171 /* clear - Func. 0 INTA, Func. 1 INTB */
2172 /* bit 13 set - Load CIS */
2173 /* bit 14 set - BIOS Enable */
2174 /* bit 15 set - Big Endian Mode */
2175 ushort cfg_msw; /* 01 unused */
2176 ushort disc_enable; /* 02 disconnect enable */
2177 ushort wdtr_able; /* 03 Wide DTR able */
2178 ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
2179 ushort start_motor; /* 05 send start up motor */
2180 ushort tagqng_able; /* 06 tag queuing able */
2181 ushort bios_scan; /* 07 BIOS device control */
2182 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002184 uchar adapter_scsi_id; /* 09 Host Adapter ID */
2185 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002187 uchar scsi_reset_delay; /* 10 reset delay */
2188 uchar bios_id_lun; /* first boot device scsi id & lun */
2189 /* high nibble is lun */
2190 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002192 uchar termination_se; /* 11 0 - automatic */
2193 /* 1 - low off / high off */
2194 /* 2 - low off / high on */
2195 /* 3 - low on / high on */
2196 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002198 uchar termination_lvd; /* 11 0 - automatic */
2199 /* 1 - low off / high off */
2200 /* 2 - low off / high on */
2201 /* 3 - low on / high on */
2202 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002204 ushort bios_ctrl; /* 12 BIOS control bits */
2205 /* bit 0 BIOS don't act as initiator. */
2206 /* bit 1 BIOS > 1 GB support */
2207 /* bit 2 BIOS > 2 Disk Support */
2208 /* bit 3 BIOS don't support removables */
2209 /* bit 4 BIOS support bootable CD */
2210 /* bit 5 BIOS scan enabled */
2211 /* bit 6 BIOS support multiple LUNs */
2212 /* bit 7 BIOS display of message */
2213 /* bit 8 SCAM disabled */
2214 /* bit 9 Reset SCSI bus during init. */
2215 /* bit 10 Basic Integrity Checking disabled */
2216 /* bit 11 No verbose initialization. */
2217 /* bit 12 SCSI parity enabled */
2218 /* bit 13 AIPP (Asyn. Info. Ph. Prot.) dis. */
2219 /* bit 14 */
2220 /* bit 15 */
2221 ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
2222 ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
2223 uchar max_host_qng; /* 15 maximum host queueing */
2224 uchar max_dvc_qng; /* maximum per device queuing */
2225 ushort dvc_cntl; /* 16 control bit for driver */
2226 ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
2227 ushort serial_number_word1; /* 18 Board serial number word 1 */
2228 ushort serial_number_word2; /* 19 Board serial number word 2 */
2229 ushort serial_number_word3; /* 20 Board serial number word 3 */
2230 ushort check_sum; /* 21 EEP check sum */
2231 uchar oem_name[16]; /* 22 OEM name */
2232 ushort dvc_err_code; /* 30 last device driver error code */
2233 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
2234 ushort adv_err_addr; /* 32 last uc error address */
2235 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
2236 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
2237 ushort saved_adv_err_addr; /* 35 saved last uc error address */
2238 ushort reserved36; /* 36 reserved */
2239 ushort reserved37; /* 37 reserved */
2240 ushort reserved38; /* 38 reserved */
2241 ushort reserved39; /* 39 reserved */
2242 ushort reserved40; /* 40 reserved */
2243 ushort reserved41; /* 41 reserved */
2244 ushort reserved42; /* 42 reserved */
2245 ushort reserved43; /* 43 reserved */
2246 ushort reserved44; /* 44 reserved */
2247 ushort reserved45; /* 45 reserved */
2248 ushort reserved46; /* 46 reserved */
2249 ushort reserved47; /* 47 reserved */
2250 ushort reserved48; /* 48 reserved */
2251 ushort reserved49; /* 49 reserved */
2252 ushort reserved50; /* 50 reserved */
2253 ushort reserved51; /* 51 reserved */
2254 ushort reserved52; /* 52 reserved */
2255 ushort reserved53; /* 53 reserved */
2256 ushort reserved54; /* 54 reserved */
2257 ushort reserved55; /* 55 reserved */
2258 ushort cisptr_lsw; /* 56 CIS PTR LSW */
2259 ushort cisprt_msw; /* 57 CIS PTR MSW */
2260 ushort subsysvid; /* 58 SubSystem Vendor ID */
2261 ushort subsysid; /* 59 SubSystem ID */
2262 ushort reserved60; /* 60 reserved */
2263 ushort reserved61; /* 61 reserved */
2264 ushort reserved62; /* 62 reserved */
2265 ushort reserved63; /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266} ADVEEP_38C1600_CONFIG;
2267
2268/*
2269 * EEPROM Commands
2270 */
2271#define ASC_EEP_CMD_DONE 0x0200
2272#define ASC_EEP_CMD_DONE_ERR 0x0001
2273
2274/* cfg_word */
2275#define EEP_CFG_WORD_BIG_ENDIAN 0x8000
2276
2277/* bios_ctrl */
2278#define BIOS_CTRL_BIOS 0x0001
2279#define BIOS_CTRL_EXTENDED_XLAT 0x0002
2280#define BIOS_CTRL_GT_2_DISK 0x0004
2281#define BIOS_CTRL_BIOS_REMOVABLE 0x0008
2282#define BIOS_CTRL_BOOTABLE_CD 0x0010
2283#define BIOS_CTRL_MULTIPLE_LUN 0x0040
2284#define BIOS_CTRL_DISPLAY_MSG 0x0080
2285#define BIOS_CTRL_NO_SCAM 0x0100
2286#define BIOS_CTRL_RESET_SCSI_BUS 0x0200
2287#define BIOS_CTRL_INIT_VERBOSE 0x0800
2288#define BIOS_CTRL_SCSI_PARITY 0x1000
2289#define BIOS_CTRL_AIPP_DIS 0x2000
2290
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002291#define ADV_3550_MEMSIZE 0x2000 /* 8 KB Internal Memory */
2292#define ADV_3550_IOLEN 0x40 /* I/O Port Range in bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002294#define ADV_38C0800_MEMSIZE 0x4000 /* 16 KB Internal Memory */
2295#define ADV_38C0800_IOLEN 0x100 /* I/O Port Range in bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296
2297/*
2298 * XXX - Since ASC38C1600 Rev.3 has a local RAM failure issue, there is
2299 * a special 16K Adv Library and Microcode version. After the issue is
2300 * resolved, should restore 32K support.
2301 *
2302 * #define ADV_38C1600_MEMSIZE 0x8000L * 32 KB Internal Memory *
2303 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002304#define ADV_38C1600_MEMSIZE 0x4000 /* 16 KB Internal Memory */
2305#define ADV_38C1600_IOLEN 0x100 /* I/O Port Range 256 bytes */
2306#define ADV_38C1600_MEMLEN 0x1000 /* Memory Range 4KB bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307
2308/*
2309 * Byte I/O register address from base of 'iop_base'.
2310 */
2311#define IOPB_INTR_STATUS_REG 0x00
2312#define IOPB_CHIP_ID_1 0x01
2313#define IOPB_INTR_ENABLES 0x02
2314#define IOPB_CHIP_TYPE_REV 0x03
2315#define IOPB_RES_ADDR_4 0x04
2316#define IOPB_RES_ADDR_5 0x05
2317#define IOPB_RAM_DATA 0x06
2318#define IOPB_RES_ADDR_7 0x07
2319#define IOPB_FLAG_REG 0x08
2320#define IOPB_RES_ADDR_9 0x09
2321#define IOPB_RISC_CSR 0x0A
2322#define IOPB_RES_ADDR_B 0x0B
2323#define IOPB_RES_ADDR_C 0x0C
2324#define IOPB_RES_ADDR_D 0x0D
2325#define IOPB_SOFT_OVER_WR 0x0E
2326#define IOPB_RES_ADDR_F 0x0F
2327#define IOPB_MEM_CFG 0x10
2328#define IOPB_RES_ADDR_11 0x11
2329#define IOPB_GPIO_DATA 0x12
2330#define IOPB_RES_ADDR_13 0x13
2331#define IOPB_FLASH_PAGE 0x14
2332#define IOPB_RES_ADDR_15 0x15
2333#define IOPB_GPIO_CNTL 0x16
2334#define IOPB_RES_ADDR_17 0x17
2335#define IOPB_FLASH_DATA 0x18
2336#define IOPB_RES_ADDR_19 0x19
2337#define IOPB_RES_ADDR_1A 0x1A
2338#define IOPB_RES_ADDR_1B 0x1B
2339#define IOPB_RES_ADDR_1C 0x1C
2340#define IOPB_RES_ADDR_1D 0x1D
2341#define IOPB_RES_ADDR_1E 0x1E
2342#define IOPB_RES_ADDR_1F 0x1F
2343#define IOPB_DMA_CFG0 0x20
2344#define IOPB_DMA_CFG1 0x21
2345#define IOPB_TICKLE 0x22
2346#define IOPB_DMA_REG_WR 0x23
2347#define IOPB_SDMA_STATUS 0x24
2348#define IOPB_SCSI_BYTE_CNT 0x25
2349#define IOPB_HOST_BYTE_CNT 0x26
2350#define IOPB_BYTE_LEFT_TO_XFER 0x27
2351#define IOPB_BYTE_TO_XFER_0 0x28
2352#define IOPB_BYTE_TO_XFER_1 0x29
2353#define IOPB_BYTE_TO_XFER_2 0x2A
2354#define IOPB_BYTE_TO_XFER_3 0x2B
2355#define IOPB_ACC_GRP 0x2C
2356#define IOPB_RES_ADDR_2D 0x2D
2357#define IOPB_DEV_ID 0x2E
2358#define IOPB_RES_ADDR_2F 0x2F
2359#define IOPB_SCSI_DATA 0x30
2360#define IOPB_RES_ADDR_31 0x31
2361#define IOPB_RES_ADDR_32 0x32
2362#define IOPB_SCSI_DATA_HSHK 0x33
2363#define IOPB_SCSI_CTRL 0x34
2364#define IOPB_RES_ADDR_35 0x35
2365#define IOPB_RES_ADDR_36 0x36
2366#define IOPB_RES_ADDR_37 0x37
2367#define IOPB_RAM_BIST 0x38
2368#define IOPB_PLL_TEST 0x39
2369#define IOPB_PCI_INT_CFG 0x3A
2370#define IOPB_RES_ADDR_3B 0x3B
2371#define IOPB_RFIFO_CNT 0x3C
2372#define IOPB_RES_ADDR_3D 0x3D
2373#define IOPB_RES_ADDR_3E 0x3E
2374#define IOPB_RES_ADDR_3F 0x3F
2375
2376/*
2377 * Word I/O register address from base of 'iop_base'.
2378 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002379#define IOPW_CHIP_ID_0 0x00 /* CID0 */
2380#define IOPW_CTRL_REG 0x02 /* CC */
2381#define IOPW_RAM_ADDR 0x04 /* LA */
2382#define IOPW_RAM_DATA 0x06 /* LD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383#define IOPW_RES_ADDR_08 0x08
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002384#define IOPW_RISC_CSR 0x0A /* CSR */
2385#define IOPW_SCSI_CFG0 0x0C /* CFG0 */
2386#define IOPW_SCSI_CFG1 0x0E /* CFG1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387#define IOPW_RES_ADDR_10 0x10
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002388#define IOPW_SEL_MASK 0x12 /* SM */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389#define IOPW_RES_ADDR_14 0x14
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002390#define IOPW_FLASH_ADDR 0x16 /* FA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391#define IOPW_RES_ADDR_18 0x18
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002392#define IOPW_EE_CMD 0x1A /* EC */
2393#define IOPW_EE_DATA 0x1C /* ED */
2394#define IOPW_SFIFO_CNT 0x1E /* SFC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395#define IOPW_RES_ADDR_20 0x20
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002396#define IOPW_Q_BASE 0x22 /* QB */
2397#define IOPW_QP 0x24 /* QP */
2398#define IOPW_IX 0x26 /* IX */
2399#define IOPW_SP 0x28 /* SP */
2400#define IOPW_PC 0x2A /* PC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401#define IOPW_RES_ADDR_2C 0x2C
2402#define IOPW_RES_ADDR_2E 0x2E
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002403#define IOPW_SCSI_DATA 0x30 /* SD */
2404#define IOPW_SCSI_DATA_HSHK 0x32 /* SDH */
2405#define IOPW_SCSI_CTRL 0x34 /* SC */
2406#define IOPW_HSHK_CFG 0x36 /* HCFG */
2407#define IOPW_SXFR_STATUS 0x36 /* SXS */
2408#define IOPW_SXFR_CNTL 0x38 /* SXL */
2409#define IOPW_SXFR_CNTH 0x3A /* SXH */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410#define IOPW_RES_ADDR_3C 0x3C
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002411#define IOPW_RFIFO_DATA 0x3E /* RFD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412
2413/*
2414 * Doubleword I/O register address from base of 'iop_base'.
2415 */
2416#define IOPDW_RES_ADDR_0 0x00
2417#define IOPDW_RAM_DATA 0x04
2418#define IOPDW_RES_ADDR_8 0x08
2419#define IOPDW_RES_ADDR_C 0x0C
2420#define IOPDW_RES_ADDR_10 0x10
2421#define IOPDW_COMMA 0x14
2422#define IOPDW_COMMB 0x18
2423#define IOPDW_RES_ADDR_1C 0x1C
2424#define IOPDW_SDMA_ADDR0 0x20
2425#define IOPDW_SDMA_ADDR1 0x24
2426#define IOPDW_SDMA_COUNT 0x28
2427#define IOPDW_SDMA_ERROR 0x2C
2428#define IOPDW_RDMA_ADDR0 0x30
2429#define IOPDW_RDMA_ADDR1 0x34
2430#define IOPDW_RDMA_COUNT 0x38
2431#define IOPDW_RDMA_ERROR 0x3C
2432
2433#define ADV_CHIP_ID_BYTE 0x25
2434#define ADV_CHIP_ID_WORD 0x04C1
2435
2436#define ADV_SC_SCSI_BUS_RESET 0x2000
2437
2438#define ADV_INTR_ENABLE_HOST_INTR 0x01
2439#define ADV_INTR_ENABLE_SEL_INTR 0x02
2440#define ADV_INTR_ENABLE_DPR_INTR 0x04
2441#define ADV_INTR_ENABLE_RTA_INTR 0x08
2442#define ADV_INTR_ENABLE_RMA_INTR 0x10
2443#define ADV_INTR_ENABLE_RST_INTR 0x20
2444#define ADV_INTR_ENABLE_DPE_INTR 0x40
2445#define ADV_INTR_ENABLE_GLOBAL_INTR 0x80
2446
2447#define ADV_INTR_STATUS_INTRA 0x01
2448#define ADV_INTR_STATUS_INTRB 0x02
2449#define ADV_INTR_STATUS_INTRC 0x04
2450
2451#define ADV_RISC_CSR_STOP (0x0000)
2452#define ADV_RISC_TEST_COND (0x2000)
2453#define ADV_RISC_CSR_RUN (0x4000)
2454#define ADV_RISC_CSR_SINGLE_STEP (0x8000)
2455
2456#define ADV_CTRL_REG_HOST_INTR 0x0100
2457#define ADV_CTRL_REG_SEL_INTR 0x0200
2458#define ADV_CTRL_REG_DPR_INTR 0x0400
2459#define ADV_CTRL_REG_RTA_INTR 0x0800
2460#define ADV_CTRL_REG_RMA_INTR 0x1000
2461#define ADV_CTRL_REG_RES_BIT14 0x2000
2462#define ADV_CTRL_REG_DPE_INTR 0x4000
2463#define ADV_CTRL_REG_POWER_DONE 0x8000
2464#define ADV_CTRL_REG_ANY_INTR 0xFF00
2465
2466#define ADV_CTRL_REG_CMD_RESET 0x00C6
2467#define ADV_CTRL_REG_CMD_WR_IO_REG 0x00C5
2468#define ADV_CTRL_REG_CMD_RD_IO_REG 0x00C4
2469#define ADV_CTRL_REG_CMD_WR_PCI_CFG_SPACE 0x00C3
2470#define ADV_CTRL_REG_CMD_RD_PCI_CFG_SPACE 0x00C2
2471
2472#define ADV_TICKLE_NOP 0x00
2473#define ADV_TICKLE_A 0x01
2474#define ADV_TICKLE_B 0x02
2475#define ADV_TICKLE_C 0x03
2476
2477#define ADV_SCSI_CTRL_RSTOUT 0x2000
2478
2479#define AdvIsIntPending(port) \
2480 (AdvReadWordRegister(port, IOPW_CTRL_REG) & ADV_CTRL_REG_HOST_INTR)
2481
2482/*
2483 * SCSI_CFG0 Register bit definitions
2484 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002485#define TIMER_MODEAB 0xC000 /* Watchdog, Second, and Select. Timer Ctrl. */
2486#define PARITY_EN 0x2000 /* Enable SCSI Parity Error detection */
2487#define EVEN_PARITY 0x1000 /* Select Even Parity */
2488#define WD_LONG 0x0800 /* Watchdog Interval, 1: 57 min, 0: 13 sec */
2489#define QUEUE_128 0x0400 /* Queue Size, 1: 128 byte, 0: 64 byte */
2490#define PRIM_MODE 0x0100 /* Primitive SCSI mode */
2491#define SCAM_EN 0x0080 /* Enable SCAM selection */
2492#define SEL_TMO_LONG 0x0040 /* Sel/Resel Timeout, 1: 400 ms, 0: 1.6 ms */
2493#define CFRM_ID 0x0020 /* SCAM id sel. confirm., 1: fast, 0: 6.4 ms */
2494#define OUR_ID_EN 0x0010 /* Enable OUR_ID bits */
2495#define OUR_ID 0x000F /* SCSI ID */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496
2497/*
2498 * SCSI_CFG1 Register bit definitions
2499 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002500#define BIG_ENDIAN 0x8000 /* Enable Big Endian Mode MIO:15, EEP:15 */
2501#define TERM_POL 0x2000 /* Terminator Polarity Ctrl. MIO:13, EEP:13 */
2502#define SLEW_RATE 0x1000 /* SCSI output buffer slew rate */
2503#define FILTER_SEL 0x0C00 /* Filter Period Selection */
2504#define FLTR_DISABLE 0x0000 /* Input Filtering Disabled */
2505#define FLTR_11_TO_20NS 0x0800 /* Input Filtering 11ns to 20ns */
2506#define FLTR_21_TO_39NS 0x0C00 /* Input Filtering 21ns to 39ns */
2507#define ACTIVE_DBL 0x0200 /* Disable Active Negation */
2508#define DIFF_MODE 0x0100 /* SCSI differential Mode (Read-Only) */
2509#define DIFF_SENSE 0x0080 /* 1: No SE cables, 0: SE cable (Read-Only) */
2510#define TERM_CTL_SEL 0x0040 /* Enable TERM_CTL_H and TERM_CTL_L */
2511#define TERM_CTL 0x0030 /* External SCSI Termination Bits */
2512#define TERM_CTL_H 0x0020 /* Enable External SCSI Upper Termination */
2513#define TERM_CTL_L 0x0010 /* Enable External SCSI Lower Termination */
2514#define CABLE_DETECT 0x000F /* External SCSI Cable Connection Status */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515
2516/*
2517 * Addendum for ASC-38C0800 Chip
2518 *
2519 * The ASC-38C1600 Chip uses the same definitions except that the
2520 * bus mode override bits [12:10] have been moved to byte register
2521 * offset 0xE (IOPB_SOFT_OVER_WR) bits [12:10]. The [12:10] bits in
2522 * SCSI_CFG1 are read-only and always available. Bit 14 (DIS_TERM_DRV)
2523 * is not needed. The [12:10] bits in IOPB_SOFT_OVER_WR are write-only.
2524 * Also each ASC-38C1600 function or channel uses only cable bits [5:4]
2525 * and [1:0]. Bits [14], [7:6], [3:2] are unused.
2526 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002527#define DIS_TERM_DRV 0x4000 /* 1: Read c_det[3:0], 0: cannot read */
2528#define HVD_LVD_SE 0x1C00 /* Device Detect Bits */
2529#define HVD 0x1000 /* HVD Device Detect */
2530#define LVD 0x0800 /* LVD Device Detect */
2531#define SE 0x0400 /* SE Device Detect */
2532#define TERM_LVD 0x00C0 /* LVD Termination Bits */
2533#define TERM_LVD_HI 0x0080 /* Enable LVD Upper Termination */
2534#define TERM_LVD_LO 0x0040 /* Enable LVD Lower Termination */
2535#define TERM_SE 0x0030 /* SE Termination Bits */
2536#define TERM_SE_HI 0x0020 /* Enable SE Upper Termination */
2537#define TERM_SE_LO 0x0010 /* Enable SE Lower Termination */
2538#define C_DET_LVD 0x000C /* LVD Cable Detect Bits */
2539#define C_DET3 0x0008 /* Cable Detect for LVD External Wide */
2540#define C_DET2 0x0004 /* Cable Detect for LVD Internal Wide */
2541#define C_DET_SE 0x0003 /* SE Cable Detect Bits */
2542#define C_DET1 0x0002 /* Cable Detect for SE Internal Wide */
2543#define C_DET0 0x0001 /* Cable Detect for SE Internal Narrow */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544
2545#define CABLE_ILLEGAL_A 0x7
2546 /* x 0 0 0 | on on | Illegal (all 3 connectors are used) */
2547
2548#define CABLE_ILLEGAL_B 0xB
2549 /* 0 x 0 0 | on on | Illegal (all 3 connectors are used) */
2550
2551/*
2552 * MEM_CFG Register bit definitions
2553 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002554#define BIOS_EN 0x40 /* BIOS Enable MIO:14,EEP:14 */
2555#define FAST_EE_CLK 0x20 /* Diagnostic Bit */
2556#define RAM_SZ 0x1C /* Specify size of RAM to RISC */
2557#define RAM_SZ_2KB 0x00 /* 2 KB */
2558#define RAM_SZ_4KB 0x04 /* 4 KB */
2559#define RAM_SZ_8KB 0x08 /* 8 KB */
2560#define RAM_SZ_16KB 0x0C /* 16 KB */
2561#define RAM_SZ_32KB 0x10 /* 32 KB */
2562#define RAM_SZ_64KB 0x14 /* 64 KB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563
2564/*
2565 * DMA_CFG0 Register bit definitions
2566 *
2567 * This register is only accessible to the host.
2568 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002569#define BC_THRESH_ENB 0x80 /* PCI DMA Start Conditions */
2570#define FIFO_THRESH 0x70 /* PCI DMA FIFO Threshold */
2571#define FIFO_THRESH_16B 0x00 /* 16 bytes */
2572#define FIFO_THRESH_32B 0x20 /* 32 bytes */
2573#define FIFO_THRESH_48B 0x30 /* 48 bytes */
2574#define FIFO_THRESH_64B 0x40 /* 64 bytes */
2575#define FIFO_THRESH_80B 0x50 /* 80 bytes (default) */
2576#define FIFO_THRESH_96B 0x60 /* 96 bytes */
2577#define FIFO_THRESH_112B 0x70 /* 112 bytes */
2578#define START_CTL 0x0C /* DMA start conditions */
2579#define START_CTL_TH 0x00 /* Wait threshold level (default) */
2580#define START_CTL_ID 0x04 /* Wait SDMA/SBUS idle */
2581#define START_CTL_THID 0x08 /* Wait threshold and SDMA/SBUS idle */
2582#define START_CTL_EMFU 0x0C /* Wait SDMA FIFO empty/full */
2583#define READ_CMD 0x03 /* Memory Read Method */
2584#define READ_CMD_MR 0x00 /* Memory Read */
2585#define READ_CMD_MRL 0x02 /* Memory Read Long */
2586#define READ_CMD_MRM 0x03 /* Memory Read Multiple (default) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587
2588/*
2589 * ASC-38C0800 RAM BIST Register bit definitions
2590 */
2591#define RAM_TEST_MODE 0x80
2592#define PRE_TEST_MODE 0x40
2593#define NORMAL_MODE 0x00
2594#define RAM_TEST_DONE 0x10
2595#define RAM_TEST_STATUS 0x0F
2596#define RAM_TEST_HOST_ERROR 0x08
2597#define RAM_TEST_INTRAM_ERROR 0x04
2598#define RAM_TEST_RISC_ERROR 0x02
2599#define RAM_TEST_SCSI_ERROR 0x01
2600#define RAM_TEST_SUCCESS 0x00
2601#define PRE_TEST_VALUE 0x05
2602#define NORMAL_VALUE 0x00
2603
2604/*
2605 * ASC38C1600 Definitions
2606 *
2607 * IOPB_PCI_INT_CFG Bit Field Definitions
2608 */
2609
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002610#define INTAB_LD 0x80 /* Value loaded from EEPROM Bit 11. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611
2612/*
2613 * Bit 1 can be set to change the interrupt for the Function to operate in
2614 * Totem Pole mode. By default Bit 1 is 0 and the interrupt operates in
2615 * Open Drain mode. Both functions of the ASC38C1600 must be set to the same
2616 * mode, otherwise the operating mode is undefined.
2617 */
2618#define TOTEMPOLE 0x02
2619
2620/*
2621 * Bit 0 can be used to change the Int Pin for the Function. The value is
2622 * 0 by default for both Functions with Function 0 using INT A and Function
2623 * B using INT B. For Function 0 if set, INT B is used. For Function 1 if set,
2624 * INT A is used.
2625 *
2626 * EEPROM Word 0 Bit 11 for each Function may change the initial Int Pin
2627 * value specified in the PCI Configuration Space.
2628 */
2629#define INTAB 0x01
2630
2631/* a_advlib.h */
2632
2633/*
2634 * Adv Library Status Definitions
2635 */
2636#define ADV_TRUE 1
2637#define ADV_FALSE 0
2638#define ADV_NOERROR 1
2639#define ADV_SUCCESS 1
2640#define ADV_BUSY 0
2641#define ADV_ERROR (-1)
2642
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643/*
2644 * ADV_DVC_VAR 'warn_code' values
2645 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002646#define ASC_WARN_BUSRESET_ERROR 0x0001 /* SCSI Bus Reset error */
2647#define ASC_WARN_EEPROM_CHKSUM 0x0002 /* EEP check sum error */
2648#define ASC_WARN_EEPROM_TERMINATION 0x0004 /* EEP termination bad field */
2649#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080 /* PCI config space set error */
2650#define ASC_WARN_ERROR 0xFFFF /* ADV_ERROR return */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002652#define ADV_MAX_TID 15 /* max. target identifier */
2653#define ADV_MAX_LUN 7 /* max. logical unit number */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654
2655/*
2656 * Error code values are set in ADV_DVC_VAR 'err_code'.
2657 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002658#define ASC_IERR_WRITE_EEPROM 0x0001 /* write EEPROM error */
2659#define ASC_IERR_MCODE_CHKSUM 0x0002 /* micro code check sum error */
2660#define ASC_IERR_NO_CARRIER 0x0004 /* No more carrier memory. */
2661#define ASC_IERR_START_STOP_CHIP 0x0008 /* start/stop chip failed */
2662#define ASC_IERR_CHIP_VERSION 0x0040 /* wrong chip version */
2663#define ASC_IERR_SET_SCSI_ID 0x0080 /* set SCSI ID failed */
2664#define ASC_IERR_HVD_DEVICE 0x0100 /* HVD attached to LVD connector. */
2665#define ASC_IERR_BAD_SIGNATURE 0x0200 /* signature not found */
2666#define ASC_IERR_ILLEGAL_CONNECTION 0x0400 /* Illegal cable connection */
2667#define ASC_IERR_SINGLE_END_DEVICE 0x0800 /* Single-end used w/differential */
2668#define ASC_IERR_REVERSED_CABLE 0x1000 /* Narrow flat cable reversed */
2669#define ASC_IERR_BIST_PRE_TEST 0x2000 /* BIST pre-test error */
2670#define ASC_IERR_BIST_RAM_TEST 0x4000 /* BIST RAM test error */
2671#define ASC_IERR_BAD_CHIPTYPE 0x8000 /* Invalid 'chip_type' setting. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672
2673/*
2674 * Fixed locations of microcode operating variables.
2675 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002676#define ASC_MC_CODE_BEGIN_ADDR 0x0028 /* microcode start address */
2677#define ASC_MC_CODE_END_ADDR 0x002A /* microcode end address */
2678#define ASC_MC_CODE_CHK_SUM 0x002C /* microcode code checksum */
2679#define ASC_MC_VERSION_DATE 0x0038 /* microcode version */
2680#define ASC_MC_VERSION_NUM 0x003A /* microcode number */
2681#define ASC_MC_BIOSMEM 0x0040 /* BIOS RISC Memory Start */
2682#define ASC_MC_BIOSLEN 0x0050 /* BIOS RISC Memory Length */
2683#define ASC_MC_BIOS_SIGNATURE 0x0058 /* BIOS Signature 0x55AA */
2684#define ASC_MC_BIOS_VERSION 0x005A /* BIOS Version (2 bytes) */
2685#define ASC_MC_SDTR_SPEED1 0x0090 /* SDTR Speed for TID 0-3 */
2686#define ASC_MC_SDTR_SPEED2 0x0092 /* SDTR Speed for TID 4-7 */
2687#define ASC_MC_SDTR_SPEED3 0x0094 /* SDTR Speed for TID 8-11 */
2688#define ASC_MC_SDTR_SPEED4 0x0096 /* SDTR Speed for TID 12-15 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689#define ASC_MC_CHIP_TYPE 0x009A
2690#define ASC_MC_INTRB_CODE 0x009B
2691#define ASC_MC_WDTR_ABLE 0x009C
2692#define ASC_MC_SDTR_ABLE 0x009E
2693#define ASC_MC_TAGQNG_ABLE 0x00A0
2694#define ASC_MC_DISC_ENABLE 0x00A2
2695#define ASC_MC_IDLE_CMD_STATUS 0x00A4
2696#define ASC_MC_IDLE_CMD 0x00A6
2697#define ASC_MC_IDLE_CMD_PARAMETER 0x00A8
2698#define ASC_MC_DEFAULT_SCSI_CFG0 0x00AC
2699#define ASC_MC_DEFAULT_SCSI_CFG1 0x00AE
2700#define ASC_MC_DEFAULT_MEM_CFG 0x00B0
2701#define ASC_MC_DEFAULT_SEL_MASK 0x00B2
2702#define ASC_MC_SDTR_DONE 0x00B6
2703#define ASC_MC_NUMBER_OF_QUEUED_CMD 0x00C0
2704#define ASC_MC_NUMBER_OF_MAX_CMD 0x00D0
2705#define ASC_MC_DEVICE_HSHK_CFG_TABLE 0x0100
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002706#define ASC_MC_CONTROL_FLAG 0x0122 /* Microcode control flag. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707#define ASC_MC_WDTR_DONE 0x0124
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002708#define ASC_MC_CAM_MODE_MASK 0x015E /* CAM mode TID bitmask. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709#define ASC_MC_ICQ 0x0160
2710#define ASC_MC_IRQ 0x0164
2711#define ASC_MC_PPR_ABLE 0x017A
2712
2713/*
2714 * BIOS LRAM variable absolute offsets.
2715 */
2716#define BIOS_CODESEG 0x54
2717#define BIOS_CODELEN 0x56
2718#define BIOS_SIGNATURE 0x58
2719#define BIOS_VERSION 0x5A
2720
2721/*
2722 * Microcode Control Flags
2723 *
2724 * Flags set by the Adv Library in RISC variable 'control_flag' (0x122)
2725 * and handled by the microcode.
2726 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002727#define CONTROL_FLAG_IGNORE_PERR 0x0001 /* Ignore DMA Parity Errors */
2728#define CONTROL_FLAG_ENABLE_AIPP 0x0002 /* Enabled AIPP checking. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729
2730/*
2731 * ASC_MC_DEVICE_HSHK_CFG_TABLE microcode table or HSHK_CFG register format
2732 */
2733#define HSHK_CFG_WIDE_XFR 0x8000
2734#define HSHK_CFG_RATE 0x0F00
2735#define HSHK_CFG_OFFSET 0x001F
2736
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002737#define ASC_DEF_MAX_HOST_QNG 0xFD /* Max. number of host commands (253) */
2738#define ASC_DEF_MIN_HOST_QNG 0x10 /* Min. number of host commands (16) */
2739#define ASC_DEF_MAX_DVC_QNG 0x3F /* Max. number commands per device (63) */
2740#define ASC_DEF_MIN_DVC_QNG 0x04 /* Min. number commands per device (4) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002742#define ASC_QC_DATA_CHECK 0x01 /* Require ASC_QC_DATA_OUT set or clear. */
2743#define ASC_QC_DATA_OUT 0x02 /* Data out DMA transfer. */
2744#define ASC_QC_START_MOTOR 0x04 /* Send auto-start motor before request. */
2745#define ASC_QC_NO_OVERRUN 0x08 /* Don't report overrun. */
2746#define ASC_QC_FREEZE_TIDQ 0x10 /* Freeze TID queue after request. XXX TBD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002748#define ASC_QSC_NO_DISC 0x01 /* Don't allow disconnect for request. */
2749#define ASC_QSC_NO_TAGMSG 0x02 /* Don't allow tag queuing for request. */
2750#define ASC_QSC_NO_SYNC 0x04 /* Don't use Synch. transfer on request. */
2751#define ASC_QSC_NO_WIDE 0x08 /* Don't use Wide transfer on request. */
2752#define ASC_QSC_REDO_DTR 0x10 /* Renegotiate WDTR/SDTR before request. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753/*
2754 * Note: If a Tag Message is to be sent and neither ASC_QSC_HEAD_TAG or
2755 * ASC_QSC_ORDERED_TAG is set, then a Simple Tag Message (0x20) is used.
2756 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002757#define ASC_QSC_HEAD_TAG 0x40 /* Use Head Tag Message (0x21). */
2758#define ASC_QSC_ORDERED_TAG 0x80 /* Use Ordered Tag Message (0x22). */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759
2760/*
2761 * All fields here are accessed by the board microcode and need to be
2762 * little-endian.
2763 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002764typedef struct adv_carr_t {
2765 ADV_VADDR carr_va; /* Carrier Virtual Address */
2766 ADV_PADDR carr_pa; /* Carrier Physical Address */
2767 ADV_VADDR areq_vpa; /* ASC_SCSI_REQ_Q Virtual or Physical Address */
2768 /*
2769 * next_vpa [31:4] Carrier Virtual or Physical Next Pointer
2770 *
2771 * next_vpa [3:1] Reserved Bits
2772 * next_vpa [0] Done Flag set in Response Queue.
2773 */
2774 ADV_VADDR next_vpa;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775} ADV_CARR_T;
2776
2777/*
2778 * Mask used to eliminate low 4 bits of carrier 'next_vpa' field.
2779 */
2780#define ASC_NEXT_VPA_MASK 0xFFFFFFF0
2781
2782#define ASC_RQ_DONE 0x00000001
2783#define ASC_RQ_GOOD 0x00000002
2784#define ASC_CQ_STOPPER 0x00000000
2785
2786#define ASC_GET_CARRP(carrp) ((carrp) & ASC_NEXT_VPA_MASK)
2787
2788#define ADV_CARRIER_NUM_PAGE_CROSSING \
2789 (((ADV_CARRIER_COUNT * sizeof(ADV_CARR_T)) + \
2790 (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
2791
2792#define ADV_CARRIER_BUFSIZE \
2793 ((ADV_CARRIER_COUNT + ADV_CARRIER_NUM_PAGE_CROSSING) * sizeof(ADV_CARR_T))
2794
2795/*
2796 * ASC_SCSI_REQ_Q 'a_flag' definitions
2797 *
2798 * The Adv Library should limit use to the lower nibble (4 bits) of
2799 * a_flag. Drivers are free to use the upper nibble (4 bits) of a_flag.
2800 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002801#define ADV_POLL_REQUEST 0x01 /* poll for request completion */
2802#define ADV_SCSIQ_DONE 0x02 /* request done */
2803#define ADV_DONT_RETRY 0x08 /* don't do retry */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002805#define ADV_CHIP_ASC3550 0x01 /* Ultra-Wide IC */
2806#define ADV_CHIP_ASC38C0800 0x02 /* Ultra2-Wide/LVD IC */
2807#define ADV_CHIP_ASC38C1600 0x03 /* Ultra3-Wide/LVD2 IC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808
2809/*
2810 * Adapter temporary configuration structure
2811 *
2812 * This structure can be discarded after initialization. Don't add
2813 * fields here needed after initialization.
2814 *
2815 * Field naming convention:
2816 *
2817 * *_enable indicates the field enables or disables a feature. The
2818 * value of the field is never reset.
2819 */
2820typedef struct adv_dvc_cfg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002821 ushort disc_enable; /* enable disconnection */
2822 uchar chip_version; /* chip version */
2823 uchar termination; /* Term. Ctrl. bits 6-5 of SCSI_CFG1 register */
2824 ushort lib_version; /* Adv Library version number */
2825 ushort control_flag; /* Microcode Control Flag */
2826 ushort mcode_date; /* Microcode date */
2827 ushort mcode_version; /* Microcode version */
2828 ushort pci_slot_info; /* high byte device/function number */
2829 /* bits 7-3 device num., bits 2-0 function num. */
2830 /* low byte bus num. */
2831 ushort serial1; /* EEPROM serial number word 1 */
2832 ushort serial2; /* EEPROM serial number word 2 */
2833 ushort serial3; /* EEPROM serial number word 3 */
2834 struct device *dev; /* pointer to the pci dev structure for this board */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835} ADV_DVC_CFG;
2836
2837struct adv_dvc_var;
2838struct adv_scsi_req_q;
2839
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002840typedef void (*ADV_ISR_CALLBACK)
2841 (struct adv_dvc_var *, struct adv_scsi_req_q *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002843typedef void (*ADV_ASYNC_CALLBACK)
2844 (struct adv_dvc_var *, uchar);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845
2846/*
2847 * Adapter operation variable structure.
2848 *
2849 * One structure is required per host adapter.
2850 *
2851 * Field naming convention:
2852 *
2853 * *_able indicates both whether a feature should be enabled or disabled
2854 * and whether a device isi capable of the feature. At initialization
2855 * this field may be set, but later if a device is found to be incapable
2856 * of the feature, the field is cleared.
2857 */
2858typedef struct adv_dvc_var {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002859 AdvPortAddr iop_base; /* I/O port address */
2860 ushort err_code; /* fatal error code */
2861 ushort bios_ctrl; /* BIOS control word, EEPROM word 12 */
2862 ADV_ISR_CALLBACK isr_callback;
2863 ADV_ASYNC_CALLBACK async_callback;
2864 ushort wdtr_able; /* try WDTR for a device */
2865 ushort sdtr_able; /* try SDTR for a device */
2866 ushort ultra_able; /* try SDTR Ultra speed for a device */
2867 ushort sdtr_speed1; /* EEPROM SDTR Speed for TID 0-3 */
2868 ushort sdtr_speed2; /* EEPROM SDTR Speed for TID 4-7 */
2869 ushort sdtr_speed3; /* EEPROM SDTR Speed for TID 8-11 */
2870 ushort sdtr_speed4; /* EEPROM SDTR Speed for TID 12-15 */
2871 ushort tagqng_able; /* try tagged queuing with a device */
2872 ushort ppr_able; /* PPR message capable per TID bitmask. */
2873 uchar max_dvc_qng; /* maximum number of tagged commands per device */
2874 ushort start_motor; /* start motor command allowed */
2875 uchar scsi_reset_wait; /* delay in seconds after scsi bus reset */
2876 uchar chip_no; /* should be assigned by caller */
2877 uchar max_host_qng; /* maximum number of Q'ed command allowed */
2878 uchar irq_no; /* IRQ number */
2879 ushort no_scam; /* scam_tolerant of EEPROM */
2880 struct asc_board *drv_ptr; /* driver pointer to private structure */
2881 uchar chip_scsi_id; /* chip SCSI target ID */
2882 uchar chip_type;
2883 uchar bist_err_code;
2884 ADV_CARR_T *carrier_buf;
2885 ADV_CARR_T *carr_freelist; /* Carrier free list. */
2886 ADV_CARR_T *icq_sp; /* Initiator command queue stopper pointer. */
2887 ADV_CARR_T *irq_sp; /* Initiator response queue stopper pointer. */
2888 ushort carr_pending_cnt; /* Count of pending carriers. */
2889 /*
2890 * Note: The following fields will not be used after initialization. The
2891 * driver may discard the buffer after initialization is done.
2892 */
2893 ADV_DVC_CFG *cfg; /* temporary configuration structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894} ADV_DVC_VAR;
2895
2896#define NO_OF_SG_PER_BLOCK 15
2897
2898typedef struct asc_sg_block {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002899 uchar reserved1;
2900 uchar reserved2;
2901 uchar reserved3;
2902 uchar sg_cnt; /* Valid entries in block. */
2903 ADV_PADDR sg_ptr; /* Pointer to next sg block. */
2904 struct {
2905 ADV_PADDR sg_addr; /* SG element address. */
2906 ADV_DCNT sg_count; /* SG element count. */
2907 } sg_list[NO_OF_SG_PER_BLOCK];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908} ADV_SG_BLOCK;
2909
2910/*
2911 * ADV_SCSI_REQ_Q - microcode request structure
2912 *
2913 * All fields in this structure up to byte 60 are used by the microcode.
2914 * The microcode makes assumptions about the size and ordering of fields
2915 * in this structure. Do not change the structure definition here without
2916 * coordinating the change with the microcode.
2917 *
2918 * All fields accessed by microcode must be maintained in little_endian
2919 * order.
2920 */
2921typedef struct adv_scsi_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002922 uchar cntl; /* Ucode flags and state (ASC_MC_QC_*). */
2923 uchar target_cmd;
2924 uchar target_id; /* Device target identifier. */
2925 uchar target_lun; /* Device target logical unit number. */
2926 ADV_PADDR data_addr; /* Data buffer physical address. */
2927 ADV_DCNT data_cnt; /* Data count. Ucode sets to residual. */
2928 ADV_PADDR sense_addr;
2929 ADV_PADDR carr_pa;
2930 uchar mflag;
2931 uchar sense_len;
2932 uchar cdb_len; /* SCSI CDB length. Must <= 16 bytes. */
2933 uchar scsi_cntl;
2934 uchar done_status; /* Completion status. */
2935 uchar scsi_status; /* SCSI status byte. */
2936 uchar host_status; /* Ucode host status. */
2937 uchar sg_working_ix;
2938 uchar cdb[12]; /* SCSI CDB bytes 0-11. */
2939 ADV_PADDR sg_real_addr; /* SG list physical address. */
2940 ADV_PADDR scsiq_rptr;
2941 uchar cdb16[4]; /* SCSI CDB bytes 12-15. */
2942 ADV_VADDR scsiq_ptr;
2943 ADV_VADDR carr_va;
2944 /*
2945 * End of microcode structure - 60 bytes. The rest of the structure
2946 * is used by the Adv Library and ignored by the microcode.
2947 */
2948 ADV_VADDR srb_ptr;
2949 ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */
2950 char *vdata_addr; /* Data buffer virtual address. */
2951 uchar a_flag;
2952 uchar pad[2]; /* Pad out to a word boundary. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953} ADV_SCSI_REQ_Q;
2954
2955/*
2956 * Microcode idle loop commands
2957 */
2958#define IDLE_CMD_COMPLETED 0
2959#define IDLE_CMD_STOP_CHIP 0x0001
2960#define IDLE_CMD_STOP_CHIP_SEND_INT 0x0002
2961#define IDLE_CMD_SEND_INT 0x0004
2962#define IDLE_CMD_ABORT 0x0008
2963#define IDLE_CMD_DEVICE_RESET 0x0010
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002964#define IDLE_CMD_SCSI_RESET_START 0x0020 /* Assert SCSI Bus Reset */
2965#define IDLE_CMD_SCSI_RESET_END 0x0040 /* Deassert SCSI Bus Reset */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966#define IDLE_CMD_SCSIREQ 0x0080
2967
2968#define IDLE_CMD_STATUS_SUCCESS 0x0001
2969#define IDLE_CMD_STATUS_FAILURE 0x0002
2970
2971/*
2972 * AdvSendIdleCmd() flag definitions.
2973 */
2974#define ADV_NOWAIT 0x01
2975
2976/*
2977 * Wait loop time out values.
2978 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002979#define SCSI_WAIT_10_SEC 10UL /* 10 seconds */
2980#define SCSI_WAIT_100_MSEC 100UL /* 100 milliseconds */
2981#define SCSI_US_PER_MSEC 1000 /* microseconds per millisecond */
2982#define SCSI_MS_PER_SEC 1000UL /* milliseconds per second */
2983#define SCSI_MAX_RETRY 10 /* retry count */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002985#define ADV_ASYNC_RDMA_FAILURE 0x01 /* Fatal RDMA failure. */
2986#define ADV_ASYNC_SCSI_BUS_RESET_DET 0x02 /* Detected SCSI Bus Reset. */
2987#define ADV_ASYNC_CARRIER_READY_FAILURE 0x03 /* Carrier Ready failure. */
2988#define ADV_RDMA_IN_CARR_AND_Q_INVALID 0x04 /* RDMAed-in data invalid. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002990#define ADV_HOST_SCSI_BUS_RESET 0x80 /* Host Initiated SCSI Bus Reset. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991
2992/*
2993 * Device drivers must define the following functions.
2994 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002995static inline ulong DvcEnterCritical(void);
2996static inline void DvcLeaveCritical(ulong);
2997static void DvcSleepMilliSecond(ADV_DCNT);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002998static ADV_PADDR DvcGetPhyAddr(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *,
2999 uchar *, ASC_SDCNT *, int);
3000static void DvcDelayMicroSecond(ADV_DVC_VAR *, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001
3002/*
3003 * Adv Library functions available to drivers.
3004 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003005static int AdvExeScsiQueue(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
3006static int AdvISR(ADV_DVC_VAR *);
3007static int AdvInitGetConfig(ADV_DVC_VAR *);
3008static int AdvInitAsc3550Driver(ADV_DVC_VAR *);
3009static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *);
3010static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *);
3011static int AdvResetChipAndSB(ADV_DVC_VAR *);
3012static int AdvResetSB(ADV_DVC_VAR *asc_dvc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013
3014/*
3015 * Internal Adv Library functions.
3016 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003017static int AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ADV_DCNT);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003018static int AdvInitFrom3550EEP(ADV_DVC_VAR *);
3019static int AdvInitFrom38C0800EEP(ADV_DVC_VAR *);
3020static int AdvInitFrom38C1600EEP(ADV_DVC_VAR *);
3021static ushort AdvGet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
3022static void AdvSet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
3023static ushort AdvGet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
3024static void AdvSet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
3025static ushort AdvGet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
3026static void AdvSet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
3027static void AdvWaitEEPCmd(AdvPortAddr);
3028static ushort AdvReadEEPWord(AdvPortAddr, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030/* Read byte from a register. */
3031#define AdvReadByteRegister(iop_base, reg_off) \
3032 (ADV_MEM_READB((iop_base) + (reg_off)))
3033
3034/* Write byte to a register. */
3035#define AdvWriteByteRegister(iop_base, reg_off, byte) \
3036 (ADV_MEM_WRITEB((iop_base) + (reg_off), (byte)))
3037
3038/* Read word (2 bytes) from a register. */
3039#define AdvReadWordRegister(iop_base, reg_off) \
3040 (ADV_MEM_READW((iop_base) + (reg_off)))
3041
3042/* Write word (2 bytes) to a register. */
3043#define AdvWriteWordRegister(iop_base, reg_off, word) \
3044 (ADV_MEM_WRITEW((iop_base) + (reg_off), (word)))
3045
3046/* Write dword (4 bytes) to a register. */
3047#define AdvWriteDWordRegister(iop_base, reg_off, dword) \
3048 (ADV_MEM_WRITEDW((iop_base) + (reg_off), (dword)))
3049
3050/* Read byte from LRAM. */
3051#define AdvReadByteLram(iop_base, addr, byte) \
3052do { \
3053 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
3054 (byte) = ADV_MEM_READB((iop_base) + IOPB_RAM_DATA); \
3055} while (0)
3056
3057/* Write byte to LRAM. */
3058#define AdvWriteByteLram(iop_base, addr, byte) \
3059 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
3060 ADV_MEM_WRITEB((iop_base) + IOPB_RAM_DATA, (byte)))
3061
3062/* Read word (2 bytes) from LRAM. */
3063#define AdvReadWordLram(iop_base, addr, word) \
3064do { \
3065 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
3066 (word) = (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA)); \
3067} while (0)
3068
3069/* Write word (2 bytes) to LRAM. */
3070#define AdvWriteWordLram(iop_base, addr, word) \
3071 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
3072 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
3073
3074/* Write little-endian double word (4 bytes) to LRAM */
3075/* Because of unspecified C language ordering don't use auto-increment. */
3076#define AdvWriteDWordLramNoSwap(iop_base, addr, dword) \
3077 ((ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
3078 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
3079 cpu_to_le16((ushort) ((dword) & 0xFFFF)))), \
3080 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr) + 2), \
3081 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
3082 cpu_to_le16((ushort) ((dword >> 16) & 0xFFFF)))))
3083
3084/* Read word (2 bytes) from LRAM assuming that the address is already set. */
3085#define AdvReadWordAutoIncLram(iop_base) \
3086 (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA))
3087
3088/* Write word (2 bytes) to LRAM assuming that the address is already set. */
3089#define AdvWriteWordAutoIncLram(iop_base, word) \
3090 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
3091
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092/*
3093 * Define macro to check for Condor signature.
3094 *
3095 * Evaluate to ADV_TRUE if a Condor chip is found the specified port
3096 * address 'iop_base'. Otherwise evalue to ADV_FALSE.
3097 */
3098#define AdvFindSignature(iop_base) \
3099 (((AdvReadByteRegister((iop_base), IOPB_CHIP_ID_1) == \
3100 ADV_CHIP_ID_BYTE) && \
3101 (AdvReadWordRegister((iop_base), IOPW_CHIP_ID_0) == \
3102 ADV_CHIP_ID_WORD)) ? ADV_TRUE : ADV_FALSE)
3103
3104/*
3105 * Define macro to Return the version number of the chip at 'iop_base'.
3106 *
3107 * The second parameter 'bus_type' is currently unused.
3108 */
3109#define AdvGetChipVersion(iop_base, bus_type) \
3110 AdvReadByteRegister((iop_base), IOPB_CHIP_TYPE_REV)
3111
3112/*
3113 * Abort an SRB in the chip's RISC Memory. The 'srb_ptr' argument must
3114 * match the ASC_SCSI_REQ_Q 'srb_ptr' field.
3115 *
3116 * If the request has not yet been sent to the device it will simply be
3117 * aborted from RISC memory. If the request is disconnected it will be
3118 * aborted on reselection by sending an Abort Message to the target ID.
3119 *
3120 * Return value:
3121 * ADV_TRUE(1) - Queue was successfully aborted.
3122 * ADV_FALSE(0) - Queue was not found on the active queue list.
3123 */
3124#define AdvAbortQueue(asc_dvc, scsiq) \
3125 AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_ABORT, \
3126 (ADV_DCNT) (scsiq))
3127
3128/*
3129 * Send a Bus Device Reset Message to the specified target ID.
3130 *
3131 * All outstanding commands will be purged if sending the
3132 * Bus Device Reset Message is successful.
3133 *
3134 * Return Value:
3135 * ADV_TRUE(1) - All requests on the target are purged.
3136 * ADV_FALSE(0) - Couldn't issue Bus Device Reset Message; Requests
3137 * are not purged.
3138 */
3139#define AdvResetDevice(asc_dvc, target_id) \
3140 AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_DEVICE_RESET, \
3141 (ADV_DCNT) (target_id))
3142
3143/*
3144 * SCSI Wide Type definition.
3145 */
3146#define ADV_SCSI_BIT_ID_TYPE ushort
3147
3148/*
3149 * AdvInitScsiTarget() 'cntl_flag' options.
3150 */
3151#define ADV_SCAN_LUN 0x01
3152#define ADV_CAPINFO_NOLUN 0x02
3153
3154/*
3155 * Convert target id to target id bit mask.
3156 */
3157#define ADV_TID_TO_TIDMASK(tid) (0x01 << ((tid) & ADV_MAX_TID))
3158
3159/*
3160 * ASC_SCSI_REQ_Q 'done_status' and 'host_status' return values.
3161 */
3162
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003163#define QD_NO_STATUS 0x00 /* Request not completed yet. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164#define QD_NO_ERROR 0x01
3165#define QD_ABORTED_BY_HOST 0x02
3166#define QD_WITH_ERROR 0x04
3167
3168#define QHSTA_NO_ERROR 0x00
3169#define QHSTA_M_SEL_TIMEOUT 0x11
3170#define QHSTA_M_DATA_OVER_RUN 0x12
3171#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
3172#define QHSTA_M_QUEUE_ABORTED 0x15
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003173#define QHSTA_M_SXFR_SDMA_ERR 0x16 /* SXFR_STATUS SCSI DMA Error */
3174#define QHSTA_M_SXFR_SXFR_PERR 0x17 /* SXFR_STATUS SCSI Bus Parity Error */
3175#define QHSTA_M_RDMA_PERR 0x18 /* RISC PCI DMA parity error */
3176#define QHSTA_M_SXFR_OFF_UFLW 0x19 /* SXFR_STATUS Offset Underflow */
3177#define QHSTA_M_SXFR_OFF_OFLW 0x20 /* SXFR_STATUS Offset Overflow */
3178#define QHSTA_M_SXFR_WD_TMO 0x21 /* SXFR_STATUS Watchdog Timeout */
3179#define QHSTA_M_SXFR_DESELECTED 0x22 /* SXFR_STATUS Deselected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180/* Note: QHSTA_M_SXFR_XFR_OFLW is identical to QHSTA_M_DATA_OVER_RUN. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003181#define QHSTA_M_SXFR_XFR_OFLW 0x12 /* SXFR_STATUS Transfer Overflow */
3182#define QHSTA_M_SXFR_XFR_PH_ERR 0x24 /* SXFR_STATUS Transfer Phase Error */
3183#define QHSTA_M_SXFR_UNKNOWN_ERROR 0x25 /* SXFR_STATUS Unknown Error */
3184#define QHSTA_M_SCSI_BUS_RESET 0x30 /* Request aborted from SBR */
3185#define QHSTA_M_SCSI_BUS_RESET_UNSOL 0x31 /* Request aborted from unsol. SBR */
3186#define QHSTA_M_BUS_DEVICE_RESET 0x32 /* Request aborted from BDR */
3187#define QHSTA_M_DIRECTION_ERR 0x35 /* Data Phase mismatch */
3188#define QHSTA_M_DIRECTION_ERR_HUNG 0x36 /* Data Phase mismatch and bus hang */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189#define QHSTA_M_WTM_TIMEOUT 0x41
3190#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42
3191#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43
3192#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003193#define QHSTA_M_INVALID_DEVICE 0x45 /* Bad target ID */
3194#define QHSTA_M_FROZEN_TIDQ 0x46 /* TID Queue frozen. */
3195#define QHSTA_M_SGBACKUP_ERROR 0x47 /* Scatter-Gather backup error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196
3197/*
3198 * Default EEPROM Configuration structure defined in a_init.c.
3199 */
3200static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config;
3201static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config;
3202static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config;
3203
3204/*
3205 * DvcGetPhyAddr() flag arguments
3206 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003207#define ADV_IS_SCSIQ_FLAG 0x01 /* 'addr' is ASC_SCSI_REQ_Q pointer */
3208#define ADV_ASCGETSGLIST_VADDR 0x02 /* 'addr' is AscGetSGList() virtual addr */
3209#define ADV_IS_SENSE_FLAG 0x04 /* 'addr' is sense virtual pointer */
3210#define ADV_IS_DATA_FLAG 0x08 /* 'addr' is data virtual pointer */
3211#define ADV_IS_SGLIST_FLAG 0x10 /* 'addr' is sglist virtual pointer */
3212#define ADV_IS_CARRIER_FLAG 0x20 /* 'addr' is ADV_CARR_T pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213
3214/* Return the address that is aligned at the next doubleword >= to 'addr'. */
3215#define ADV_8BALIGN(addr) (((ulong) (addr) + 0x7) & ~0x7)
3216#define ADV_16BALIGN(addr) (((ulong) (addr) + 0xF) & ~0xF)
3217#define ADV_32BALIGN(addr) (((ulong) (addr) + 0x1F) & ~0x1F)
3218
3219/*
3220 * Total contiguous memory needed for driver SG blocks.
3221 *
3222 * ADV_MAX_SG_LIST must be defined by a driver. It is the maximum
3223 * number of scatter-gather elements the driver supports in a
3224 * single request.
3225 */
3226
3227#define ADV_SG_LIST_MAX_BYTE_SIZE \
3228 (sizeof(ADV_SG_BLOCK) * \
3229 ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK))
3230
3231/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232 * --- Driver Constants and Macros
3233 */
3234
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235/* Reference Scsi_Host hostdata */
3236#define ASC_BOARDP(host) ((asc_board_t *) &((host)->hostdata))
3237
3238/* asc_board_t flags */
3239#define ASC_HOST_IN_RESET 0x01
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003240#define ASC_IS_WIDE_BOARD 0x04 /* AdvanSys Wide Board */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241#define ASC_SELECT_QUEUE_DEPTHS 0x08
3242
3243#define ASC_NARROW_BOARD(boardp) (((boardp)->flags & ASC_IS_WIDE_BOARD) == 0)
3244#define ASC_WIDE_BOARD(boardp) ((boardp)->flags & ASC_IS_WIDE_BOARD)
3245
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003246#define NO_ISA_DMA 0xff /* No ISA DMA Channel Used */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003248#define ASC_INFO_SIZE 128 /* advansys_info() line size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003249
3250#ifdef CONFIG_PROC_FS
3251/* /proc/scsi/advansys/[0...] related definitions */
3252#define ASC_PRTBUF_SIZE 2048
3253#define ASC_PRTLINE_SIZE 160
3254
3255#define ASC_PRT_NEXT() \
3256 if (cp) { \
3257 totlen += len; \
3258 leftlen -= len; \
3259 if (leftlen == 0) { \
3260 return totlen; \
3261 } \
3262 cp += len; \
3263 }
3264#endif /* CONFIG_PROC_FS */
3265
3266/* Asc Library return codes */
3267#define ASC_TRUE 1
3268#define ASC_FALSE 0
3269#define ASC_NOERROR 1
3270#define ASC_BUSY 0
3271#define ASC_ERROR (-1)
3272
3273/* struct scsi_cmnd function return codes */
3274#define STATUS_BYTE(byte) (byte)
3275#define MSG_BYTE(byte) ((byte) << 8)
3276#define HOST_BYTE(byte) ((byte) << 16)
3277#define DRIVER_BYTE(byte) ((byte) << 24)
3278
3279/*
3280 * The following definitions and macros are OS independent interfaces to
3281 * the queue functions:
3282 * REQ - SCSI request structure
3283 * REQP - pointer to SCSI request structure
3284 * REQPTID(reqp) - reqp's target id
3285 * REQPNEXT(reqp) - reqp's next pointer
3286 * REQPNEXTP(reqp) - pointer to reqp's next pointer
3287 * REQPTIME(reqp) - reqp's time stamp value
3288 * REQTIMESTAMP() - system time stamp value
3289 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003290typedef struct scsi_cmnd REQ, *REQP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003291#define REQPNEXT(reqp) ((REQP) ((reqp)->host_scribble))
3292#define REQPNEXTP(reqp) ((REQP *) &((reqp)->host_scribble))
3293#define REQPTID(reqp) ((reqp)->device->id)
3294#define REQPTIME(reqp) ((reqp)->SCp.this_residual)
3295#define REQTIMESTAMP() (jiffies)
3296
3297#define REQTIMESTAT(function, ascq, reqp, tid) \
3298{ \
3299 /*
3300 * If the request time stamp is less than the system time stamp, then \
3301 * maybe the system time stamp wrapped. Set the request time to zero.\
3302 */ \
3303 if (REQPTIME(reqp) <= REQTIMESTAMP()) { \
3304 REQPTIME(reqp) = REQTIMESTAMP() - REQPTIME(reqp); \
3305 } else { \
3306 /* Indicate an error occurred with the assertion. */ \
3307 ASC_ASSERT(REQPTIME(reqp) <= REQTIMESTAMP()); \
3308 REQPTIME(reqp) = 0; \
3309 } \
3310 /* Handle first minimum time case without external initialization. */ \
3311 if (((ascq)->q_tot_cnt[tid] == 1) || \
3312 (REQPTIME(reqp) < (ascq)->q_min_tim[tid])) { \
3313 (ascq)->q_min_tim[tid] = REQPTIME(reqp); \
3314 ASC_DBG3(1, "%s: new q_min_tim[%d] %u\n", \
3315 (function), (tid), (ascq)->q_min_tim[tid]); \
3316 } \
3317 if (REQPTIME(reqp) > (ascq)->q_max_tim[tid]) { \
3318 (ascq)->q_max_tim[tid] = REQPTIME(reqp); \
3319 ASC_DBG3(1, "%s: new q_max_tim[%d] %u\n", \
3320 (function), tid, (ascq)->q_max_tim[tid]); \
3321 } \
3322 (ascq)->q_tot_tim[tid] += REQPTIME(reqp); \
3323 /* Reset the time stamp field. */ \
3324 REQPTIME(reqp) = 0; \
3325}
3326
3327/* asc_enqueue() flags */
3328#define ASC_FRONT 1
3329#define ASC_BACK 2
3330
3331/* asc_dequeue_list() argument */
3332#define ASC_TID_ALL (-1)
3333
3334/* Return non-zero, if the queue is empty. */
3335#define ASC_QUEUE_EMPTY(ascq) ((ascq)->q_tidmask == 0)
3336
Linus Torvalds1da177e2005-04-16 15:20:36 -07003337#ifndef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003338#define ASC_STATS(shost, counter)
3339#define ASC_STATS_ADD(shost, counter, count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340#else /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003341#define ASC_STATS(shost, counter) \
3342 (ASC_BOARDP(shost)->asc_stats.counter++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003344#define ASC_STATS_ADD(shost, counter, count) \
3345 (ASC_BOARDP(shost)->asc_stats.counter += (count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346#endif /* ADVANSYS_STATS */
3347
3348#define ASC_CEILING(val, unit) (((val) + ((unit) - 1))/(unit))
3349
3350/* If the result wraps when calculating tenths, return 0. */
3351#define ASC_TENTHS(num, den) \
3352 (((10 * ((num)/(den))) > (((num) * 10)/(den))) ? \
3353 0 : ((((num) * 10)/(den)) - (10 * ((num)/(den)))))
3354
3355/*
3356 * Display a message to the console.
3357 */
3358#define ASC_PRINT(s) \
3359 { \
3360 printk("advansys: "); \
3361 printk(s); \
3362 }
3363
3364#define ASC_PRINT1(s, a1) \
3365 { \
3366 printk("advansys: "); \
3367 printk((s), (a1)); \
3368 }
3369
3370#define ASC_PRINT2(s, a1, a2) \
3371 { \
3372 printk("advansys: "); \
3373 printk((s), (a1), (a2)); \
3374 }
3375
3376#define ASC_PRINT3(s, a1, a2, a3) \
3377 { \
3378 printk("advansys: "); \
3379 printk((s), (a1), (a2), (a3)); \
3380 }
3381
3382#define ASC_PRINT4(s, a1, a2, a3, a4) \
3383 { \
3384 printk("advansys: "); \
3385 printk((s), (a1), (a2), (a3), (a4)); \
3386 }
3387
Linus Torvalds1da177e2005-04-16 15:20:36 -07003388#ifndef ADVANSYS_DEBUG
3389
3390#define ASC_DBG(lvl, s)
3391#define ASC_DBG1(lvl, s, a1)
3392#define ASC_DBG2(lvl, s, a1, a2)
3393#define ASC_DBG3(lvl, s, a1, a2, a3)
3394#define ASC_DBG4(lvl, s, a1, a2, a3, a4)
3395#define ASC_DBG_PRT_SCSI_HOST(lvl, s)
3396#define ASC_DBG_PRT_SCSI_CMND(lvl, s)
3397#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp)
3398#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
3399#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone)
3400#define ADV_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
3401#define ASC_DBG_PRT_HEX(lvl, name, start, length)
3402#define ASC_DBG_PRT_CDB(lvl, cdb, len)
3403#define ASC_DBG_PRT_SENSE(lvl, sense, len)
3404#define ASC_DBG_PRT_INQUIRY(lvl, inq, len)
3405
3406#else /* ADVANSYS_DEBUG */
3407
3408/*
3409 * Debugging Message Levels:
3410 * 0: Errors Only
3411 * 1: High-Level Tracing
3412 * 2-N: Verbose Tracing
3413 */
3414
3415#define ASC_DBG(lvl, s) \
3416 { \
3417 if (asc_dbglvl >= (lvl)) { \
3418 printk(s); \
3419 } \
3420 }
3421
3422#define ASC_DBG1(lvl, s, a1) \
3423 { \
3424 if (asc_dbglvl >= (lvl)) { \
3425 printk((s), (a1)); \
3426 } \
3427 }
3428
3429#define ASC_DBG2(lvl, s, a1, a2) \
3430 { \
3431 if (asc_dbglvl >= (lvl)) { \
3432 printk((s), (a1), (a2)); \
3433 } \
3434 }
3435
3436#define ASC_DBG3(lvl, s, a1, a2, a3) \
3437 { \
3438 if (asc_dbglvl >= (lvl)) { \
3439 printk((s), (a1), (a2), (a3)); \
3440 } \
3441 }
3442
3443#define ASC_DBG4(lvl, s, a1, a2, a3, a4) \
3444 { \
3445 if (asc_dbglvl >= (lvl)) { \
3446 printk((s), (a1), (a2), (a3), (a4)); \
3447 } \
3448 }
3449
3450#define ASC_DBG_PRT_SCSI_HOST(lvl, s) \
3451 { \
3452 if (asc_dbglvl >= (lvl)) { \
3453 asc_prt_scsi_host(s); \
3454 } \
3455 }
3456
3457#define ASC_DBG_PRT_SCSI_CMND(lvl, s) \
3458 { \
3459 if (asc_dbglvl >= (lvl)) { \
3460 asc_prt_scsi_cmnd(s); \
3461 } \
3462 }
3463
3464#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp) \
3465 { \
3466 if (asc_dbglvl >= (lvl)) { \
3467 asc_prt_asc_scsi_q(scsiqp); \
3468 } \
3469 }
3470
3471#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone) \
3472 { \
3473 if (asc_dbglvl >= (lvl)) { \
3474 asc_prt_asc_qdone_info(qdone); \
3475 } \
3476 }
3477
3478#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp) \
3479 { \
3480 if (asc_dbglvl >= (lvl)) { \
3481 asc_prt_adv_scsi_req_q(scsiqp); \
3482 } \
3483 }
3484
3485#define ASC_DBG_PRT_HEX(lvl, name, start, length) \
3486 { \
3487 if (asc_dbglvl >= (lvl)) { \
3488 asc_prt_hex((name), (start), (length)); \
3489 } \
3490 }
3491
3492#define ASC_DBG_PRT_CDB(lvl, cdb, len) \
3493 ASC_DBG_PRT_HEX((lvl), "CDB", (uchar *) (cdb), (len));
3494
3495#define ASC_DBG_PRT_SENSE(lvl, sense, len) \
3496 ASC_DBG_PRT_HEX((lvl), "SENSE", (uchar *) (sense), (len));
3497
3498#define ASC_DBG_PRT_INQUIRY(lvl, inq, len) \
3499 ASC_DBG_PRT_HEX((lvl), "INQUIRY", (uchar *) (inq), (len));
3500#endif /* ADVANSYS_DEBUG */
3501
3502#ifndef ADVANSYS_ASSERT
3503#define ASC_ASSERT(a)
3504#else /* ADVANSYS_ASSERT */
3505
3506#define ASC_ASSERT(a) \
3507 { \
3508 if (!(a)) { \
3509 printk("ASC_ASSERT() Failure: file %s, line %d\n", \
3510 __FILE__, __LINE__); \
3511 } \
3512 }
3513
3514#endif /* ADVANSYS_ASSERT */
3515
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516/*
3517 * --- Driver Structures
3518 */
3519
3520#ifdef ADVANSYS_STATS
3521
3522/* Per board statistics structure */
3523struct asc_stats {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003524 /* Driver Entrypoint Statistics */
3525 ADV_DCNT queuecommand; /* # calls to advansys_queuecommand() */
3526 ADV_DCNT reset; /* # calls to advansys_eh_bus_reset() */
3527 ADV_DCNT biosparam; /* # calls to advansys_biosparam() */
3528 ADV_DCNT interrupt; /* # advansys_interrupt() calls */
3529 ADV_DCNT callback; /* # calls to asc/adv_isr_callback() */
3530 ADV_DCNT done; /* # calls to request's scsi_done function */
3531 ADV_DCNT build_error; /* # asc/adv_build_req() ASC_ERROR returns. */
3532 ADV_DCNT adv_build_noreq; /* # adv_build_req() adv_req_t alloc. fail. */
3533 ADV_DCNT adv_build_nosg; /* # adv_build_req() adv_sgblk_t alloc. fail. */
3534 /* AscExeScsiQueue()/AdvExeScsiQueue() Statistics */
3535 ADV_DCNT exe_noerror; /* # ASC_NOERROR returns. */
3536 ADV_DCNT exe_busy; /* # ASC_BUSY returns. */
3537 ADV_DCNT exe_error; /* # ASC_ERROR returns. */
3538 ADV_DCNT exe_unknown; /* # unknown returns. */
3539 /* Data Transfer Statistics */
3540 ADV_DCNT cont_cnt; /* # non-scatter-gather I/O requests received */
3541 ADV_DCNT cont_xfer; /* # contiguous transfer 512-bytes */
3542 ADV_DCNT sg_cnt; /* # scatter-gather I/O requests received */
3543 ADV_DCNT sg_elem; /* # scatter-gather elements */
3544 ADV_DCNT sg_xfer; /* # scatter-gather transfer 512-bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003545};
3546#endif /* ADVANSYS_STATS */
3547
3548/*
3549 * Request queuing structure
3550 */
3551typedef struct asc_queue {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003552 ADV_SCSI_BIT_ID_TYPE q_tidmask; /* queue mask */
3553 REQP q_first[ADV_MAX_TID + 1]; /* first queued request */
3554 REQP q_last[ADV_MAX_TID + 1]; /* last queued request */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003556 short q_cur_cnt[ADV_MAX_TID + 1]; /* current queue count */
3557 short q_max_cnt[ADV_MAX_TID + 1]; /* maximum queue count */
3558 ADV_DCNT q_tot_cnt[ADV_MAX_TID + 1]; /* total enqueue count */
3559 ADV_DCNT q_tot_tim[ADV_MAX_TID + 1]; /* total time queued */
3560 ushort q_max_tim[ADV_MAX_TID + 1]; /* maximum time queued */
3561 ushort q_min_tim[ADV_MAX_TID + 1]; /* minimum time queued */
3562#endif /* ADVANSYS_STATS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563} asc_queue_t;
3564
3565/*
3566 * Adv Library Request Structures
3567 *
3568 * The following two structures are used to process Wide Board requests.
3569 *
3570 * The ADV_SCSI_REQ_Q structure in adv_req_t is passed to the Adv Library
3571 * and microcode with the ADV_SCSI_REQ_Q field 'srb_ptr' pointing to the
3572 * adv_req_t. The adv_req_t structure 'cmndp' field in turn points to the
3573 * Mid-Level SCSI request structure.
3574 *
3575 * Zero or more ADV_SG_BLOCK are used with each ADV_SCSI_REQ_Q. Each
3576 * ADV_SG_BLOCK structure holds 15 scatter-gather elements. Under Linux
3577 * up to 255 scatter-gather elements may be used per request or
3578 * ADV_SCSI_REQ_Q.
3579 *
3580 * Both structures must be 32 byte aligned.
3581 */
3582typedef struct adv_sgblk {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003583 ADV_SG_BLOCK sg_block; /* Sgblock structure. */
3584 uchar align[32]; /* Sgblock structure padding. */
3585 struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003586} adv_sgblk_t;
3587
3588typedef struct adv_req {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003589 ADV_SCSI_REQ_Q scsi_req_q; /* Adv Library request structure. */
3590 uchar align[32]; /* Request structure padding. */
3591 struct scsi_cmnd *cmndp; /* Mid-Level SCSI command pointer. */
3592 adv_sgblk_t *sgblkp; /* Adv Library scatter-gather pointer. */
3593 struct adv_req *next_reqp; /* Next Request Structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594} adv_req_t;
3595
3596/*
3597 * Structure allocated for each board.
3598 *
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06003599 * This structure is allocated by scsi_host_alloc() at the end
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600 * of the 'Scsi_Host' structure starting at the 'hostdata'
3601 * field. It is guaranteed to be allocated from DMA-able memory.
3602 */
3603typedef struct asc_board {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003604 int id; /* Board Id */
3605 uint flags; /* Board flags */
3606 union {
3607 ASC_DVC_VAR asc_dvc_var; /* Narrow board */
3608 ADV_DVC_VAR adv_dvc_var; /* Wide board */
3609 } dvc_var;
3610 union {
3611 ASC_DVC_CFG asc_dvc_cfg; /* Narrow board */
3612 ADV_DVC_CFG adv_dvc_cfg; /* Wide board */
3613 } dvc_cfg;
3614 ushort asc_n_io_port; /* Number I/O ports. */
3615 asc_queue_t active; /* Active command queue */
3616 asc_queue_t waiting; /* Waiting command queue */
3617 asc_queue_t done; /* Done command queue */
3618 ADV_SCSI_BIT_ID_TYPE init_tidmask; /* Target init./valid mask */
3619 struct scsi_device *device[ADV_MAX_TID + 1]; /* Mid-Level Scsi Device */
3620 ushort reqcnt[ADV_MAX_TID + 1]; /* Starvation request count */
3621 ADV_SCSI_BIT_ID_TYPE queue_full; /* Queue full mask */
3622 ushort queue_full_cnt[ADV_MAX_TID + 1]; /* Queue full count */
3623 union {
3624 ASCEEP_CONFIG asc_eep; /* Narrow EEPROM config. */
3625 ADVEEP_3550_CONFIG adv_3550_eep; /* 3550 EEPROM config. */
3626 ADVEEP_38C0800_CONFIG adv_38C0800_eep; /* 38C0800 EEPROM config. */
3627 ADVEEP_38C1600_CONFIG adv_38C1600_eep; /* 38C1600 EEPROM config. */
3628 } eep_config;
3629 ulong last_reset; /* Saved last reset time */
3630 spinlock_t lock; /* Board spinlock */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003631 /* /proc/scsi/advansys/[0...] */
3632 char *prtbuf; /* /proc print buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003634 struct asc_stats asc_stats; /* Board statistics */
3635#endif /* ADVANSYS_STATS */
3636 /*
3637 * The following fields are used only for Narrow Boards.
3638 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003639 uchar sdtr_data[ASC_MAX_TID + 1]; /* SDTR information */
3640 /*
3641 * The following fields are used only for Wide Boards.
3642 */
3643 void __iomem *ioremap_addr; /* I/O Memory remap address. */
3644 ushort ioport; /* I/O Port address. */
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -06003645 ADV_CARR_T *carrp; /* ADV_CARR_T memory block. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003646 adv_req_t *orig_reqp; /* adv_req_t memory block. */
3647 adv_req_t *adv_reqp; /* Request structures. */
3648 adv_sgblk_t *adv_sgblkp; /* Scatter-gather structures. */
3649 ushort bios_signature; /* BIOS Signature. */
3650 ushort bios_version; /* BIOS Version. */
3651 ushort bios_codeseg; /* BIOS Code Segment. */
3652 ushort bios_codelen; /* BIOS Code Segment Length. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653} asc_board_t;
3654
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655/* Number of boards detected in system. */
Matthew Wilcox78e77d82007-07-29 21:46:15 -06003656static int asc_board_count;
3657
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658/* Overrun buffer used by all narrow boards. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003659static uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003660
3661/*
3662 * Global structures required to issue a command.
3663 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003664static ASC_SCSI_Q asc_scsi_q = { {0} };
3665static ASC_SG_HEAD asc_sg_head = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003668static int asc_dbglvl = 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669#endif /* ADVANSYS_DEBUG */
3670
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671/*
3672 * --- Driver Function Prototypes
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673 */
3674
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003675static int advansys_slave_configure(struct scsi_device *);
3676static void asc_scsi_done_list(struct scsi_cmnd *);
3677static int asc_execute_scsi_cmnd(struct scsi_cmnd *);
3678static int asc_build_req(asc_board_t *, struct scsi_cmnd *);
3679static int adv_build_req(asc_board_t *, struct scsi_cmnd *, ADV_SCSI_REQ_Q **);
3680static int adv_get_sglist(asc_board_t *, adv_req_t *, struct scsi_cmnd *, int);
3681static void asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
3682static void adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
3683static void adv_async_callback(ADV_DVC_VAR *, uchar);
3684static void asc_enqueue(asc_queue_t *, REQP, int);
3685static REQP asc_dequeue(asc_queue_t *, int);
3686static REQP asc_dequeue_list(asc_queue_t *, REQP *, int);
3687static int asc_rmqueue(asc_queue_t *, REQP);
3688static void asc_execute_queue(asc_queue_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003690static int asc_proc_copy(off_t, off_t, char *, int, char *, int);
3691static int asc_prt_board_devices(struct Scsi_Host *, char *, int);
3692static int asc_prt_adv_bios(struct Scsi_Host *, char *, int);
3693static int asc_get_eeprom_string(ushort *serialnum, uchar *cp);
3694static int asc_prt_asc_board_eeprom(struct Scsi_Host *, char *, int);
3695static int asc_prt_adv_board_eeprom(struct Scsi_Host *, char *, int);
3696static int asc_prt_driver_conf(struct Scsi_Host *, char *, int);
3697static int asc_prt_asc_board_info(struct Scsi_Host *, char *, int);
3698static int asc_prt_adv_board_info(struct Scsi_Host *, char *, int);
3699static int asc_prt_line(char *, int, char *fmt, ...);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700#endif /* CONFIG_PROC_FS */
3701
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702/* Statistics function prototypes. */
3703#ifdef ADVANSYS_STATS
3704#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003705static int asc_prt_board_stats(struct Scsi_Host *, char *, int);
3706static int asc_prt_target_stats(struct Scsi_Host *, int, char *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707#endif /* CONFIG_PROC_FS */
3708#endif /* ADVANSYS_STATS */
3709
3710/* Debug function prototypes. */
3711#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003712static void asc_prt_scsi_host(struct Scsi_Host *);
3713static void asc_prt_scsi_cmnd(struct scsi_cmnd *);
3714static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *);
3715static void asc_prt_asc_dvc_var(ASC_DVC_VAR *);
3716static void asc_prt_asc_scsi_q(ASC_SCSI_Q *);
3717static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *);
3718static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *);
3719static void asc_prt_adv_dvc_var(ADV_DVC_VAR *);
3720static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *);
3721static void asc_prt_adv_sgblock(int, ADV_SG_BLOCK *);
3722static void asc_prt_hex(char *f, uchar *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723#endif /* ADVANSYS_DEBUG */
3724
Linus Torvalds1da177e2005-04-16 15:20:36 -07003725#ifdef CONFIG_PROC_FS
3726/*
Matthew Wilcoxc304ec92007-07-30 09:18:45 -06003727 * advansys_proc_info() - /proc/scsi/advansys/{0,1,2,3,...}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728 *
3729 * *buffer: I/O buffer
3730 * **start: if inout == FALSE pointer into buffer where user read should start
3731 * offset: current offset into a /proc/scsi/advansys/[0...] file
3732 * length: length of buffer
3733 * hostno: Scsi_Host host_no
3734 * inout: TRUE - user is writing; FALSE - user is reading
3735 *
3736 * Return the number of bytes read from or written to a
3737 * /proc/scsi/advansys/[0...] file.
3738 *
3739 * Note: This function uses the per board buffer 'prtbuf' which is
3740 * allocated when the board is initialized in advansys_detect(). The
3741 * buffer is ASC_PRTBUF_SIZE bytes. The function asc_proc_copy() is
3742 * used to write to the buffer. The way asc_proc_copy() is written
3743 * if 'prtbuf' is too small it will not be overwritten. Instead the
3744 * user just won't get all the available statistics.
3745 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07003746static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003747advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003748 off_t offset, int length, int inout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003749{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003750 asc_board_t *boardp;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003751 char *cp;
3752 int cplen;
3753 int cnt;
3754 int totcnt;
3755 int leftlen;
3756 char *curbuf;
3757 off_t advoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003759 int tgt_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003760#endif /* ADVANSYS_STATS */
3761
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003762 ASC_DBG(1, "advansys_proc_info: begin\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003763
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003764 /*
3765 * User write not supported.
3766 */
3767 if (inout == TRUE) {
3768 return (-ENOSYS);
3769 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003770
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003771 /*
3772 * User read of /proc/scsi/advansys/[0...] file.
3773 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003774
Matthew Wilcox2a437952007-07-26 11:00:51 -04003775 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003776
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003777 /* Copy read data starting at the beginning of the buffer. */
3778 *start = buffer;
3779 curbuf = buffer;
3780 advoffset = 0;
3781 totcnt = 0;
3782 leftlen = length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003784 /*
3785 * Get board configuration information.
3786 *
3787 * advansys_info() returns the board string from its own static buffer.
3788 */
Matthew Wilcox2a437952007-07-26 11:00:51 -04003789 cp = (char *)advansys_info(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003790 strcat(cp, "\n");
3791 cplen = strlen(cp);
3792 /* Copy board information. */
3793 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3794 totcnt += cnt;
3795 leftlen -= cnt;
3796 if (leftlen == 0) {
3797 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3798 return totcnt;
3799 }
3800 advoffset += cplen;
3801 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003802
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003803 /*
3804 * Display Wide Board BIOS Information.
3805 */
3806 if (ASC_WIDE_BOARD(boardp)) {
3807 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003808 cplen = asc_prt_adv_bios(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003809 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003810 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003811 cplen);
3812 totcnt += cnt;
3813 leftlen -= cnt;
3814 if (leftlen == 0) {
3815 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3816 return totcnt;
3817 }
3818 advoffset += cplen;
3819 curbuf += cnt;
3820 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003822 /*
3823 * Display driver information for each device attached to the board.
3824 */
3825 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003826 cplen = asc_prt_board_devices(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003827 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3828 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3829 totcnt += cnt;
3830 leftlen -= cnt;
3831 if (leftlen == 0) {
3832 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3833 return totcnt;
3834 }
3835 advoffset += cplen;
3836 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003837
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003838 /*
3839 * Display EEPROM configuration for the board.
3840 */
3841 cp = boardp->prtbuf;
3842 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003843 cplen = asc_prt_asc_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003844 } else {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003845 cplen = asc_prt_adv_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003846 }
3847 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3848 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3849 totcnt += cnt;
3850 leftlen -= cnt;
3851 if (leftlen == 0) {
3852 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3853 return totcnt;
3854 }
3855 advoffset += cplen;
3856 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003858 /*
3859 * Display driver configuration and information for the board.
3860 */
3861 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003862 cplen = asc_prt_driver_conf(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003863 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3864 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3865 totcnt += cnt;
3866 leftlen -= cnt;
3867 if (leftlen == 0) {
3868 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3869 return totcnt;
3870 }
3871 advoffset += cplen;
3872 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873
3874#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003875 /*
3876 * Display driver statistics for the board.
3877 */
3878 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003879 cplen = asc_prt_board_stats(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003880 ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
3881 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3882 totcnt += cnt;
3883 leftlen -= cnt;
3884 if (leftlen == 0) {
3885 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3886 return totcnt;
3887 }
3888 advoffset += cplen;
3889 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003890
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003891 /*
3892 * Display driver statistics for each target.
3893 */
3894 for (tgt_id = 0; tgt_id <= ADV_MAX_TID; tgt_id++) {
3895 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003896 cplen = asc_prt_target_stats(shost, tgt_id, cp,
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003897 ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003898 ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003899 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
3900 cplen);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003901 totcnt += cnt;
3902 leftlen -= cnt;
3903 if (leftlen == 0) {
3904 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3905 return totcnt;
3906 }
3907 advoffset += cplen;
3908 curbuf += cnt;
3909 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910#endif /* ADVANSYS_STATS */
3911
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003912 /*
3913 * Display Asc Library dynamic configuration information
3914 * for the board.
3915 */
3916 cp = boardp->prtbuf;
3917 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003918 cplen = asc_prt_asc_board_info(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003919 } else {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003920 cplen = asc_prt_adv_board_info(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003921 }
3922 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3923 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3924 totcnt += cnt;
3925 leftlen -= cnt;
3926 if (leftlen == 0) {
3927 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3928 return totcnt;
3929 }
3930 advoffset += cplen;
3931 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003932
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003933 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003934
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003935 return totcnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003936}
3937#endif /* CONFIG_PROC_FS */
3938
3939/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003940 * advansys_info()
3941 *
3942 * Return suitable for printing on the console with the argument
3943 * adapter's configuration information.
3944 *
3945 * Note: The information line should not exceed ASC_INFO_SIZE bytes,
3946 * otherwise the static 'info' array will be overrun.
3947 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003948static const char *advansys_info(struct Scsi_Host *shost)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003950 static char info[ASC_INFO_SIZE];
3951 asc_board_t *boardp;
3952 ASC_DVC_VAR *asc_dvc_varp;
3953 ADV_DVC_VAR *adv_dvc_varp;
3954 char *busname;
3955 int iolen;
3956 char *widename = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003957
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003958 boardp = ASC_BOARDP(shost);
3959 if (ASC_NARROW_BOARD(boardp)) {
3960 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
3961 ASC_DBG(1, "advansys_info: begin\n");
3962 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
3963 if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) ==
3964 ASC_IS_ISAPNP) {
3965 busname = "ISA PnP";
3966 } else {
3967 busname = "ISA";
3968 }
3969 /* Don't reference 'shost->n_io_port'; It may be truncated. */
3970 sprintf(info,
3971 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X",
3972 ASC_VERSION, busname,
3973 (ulong)shost->io_port,
3974 (ulong)shost->io_port + boardp->asc_n_io_port -
3975 1, shost->irq, shost->dma_channel);
3976 } else {
3977 if (asc_dvc_varp->bus_type & ASC_IS_VL) {
3978 busname = "VL";
3979 } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
3980 busname = "EISA";
3981 } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
3982 if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
3983 == ASC_IS_PCI_ULTRA) {
3984 busname = "PCI Ultra";
3985 } else {
3986 busname = "PCI";
3987 }
3988 } else {
3989 busname = "?";
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003990 ASC_PRINT2("advansys_info: board %d: unknown "
3991 "bus type %d\n", boardp->id,
3992 asc_dvc_varp->bus_type);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003993 }
3994 /* Don't reference 'shost->n_io_port'; It may be truncated. */
3995 sprintf(info,
3996 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X",
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003997 ASC_VERSION, busname, (ulong)shost->io_port,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003998 (ulong)shost->io_port + boardp->asc_n_io_port -
3999 1, shost->irq);
4000 }
4001 } else {
4002 /*
4003 * Wide Adapter Information
4004 *
4005 * Memory-mapped I/O is used instead of I/O space to access
4006 * the adapter, but display the I/O Port range. The Memory
4007 * I/O address is displayed through the driver /proc file.
4008 */
4009 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
4010 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
4011 iolen = ADV_3550_IOLEN;
4012 widename = "Ultra-Wide";
4013 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
4014 iolen = ADV_38C0800_IOLEN;
4015 widename = "Ultra2-Wide";
4016 } else {
4017 iolen = ADV_38C1600_IOLEN;
4018 widename = "Ultra3-Wide";
4019 }
4020 sprintf(info,
4021 "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X",
4022 ASC_VERSION, widename, (ulong)adv_dvc_varp->iop_base,
4023 (ulong)adv_dvc_varp->iop_base + iolen - 1, shost->irq);
4024 }
4025 ASC_ASSERT(strlen(info) < ASC_INFO_SIZE);
4026 ASC_DBG(1, "advansys_info: end\n");
4027 return info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028}
4029
4030/*
4031 * advansys_queuecommand() - interrupt-driven I/O entrypoint.
4032 *
4033 * This function always returns 0. Command return status is saved
4034 * in the 'scp' result field.
4035 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07004036static int
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004037advansys_queuecommand(struct scsi_cmnd *scp, void (*done) (struct scsi_cmnd *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004038{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004039 struct Scsi_Host *shost;
4040 asc_board_t *boardp;
4041 ulong flags;
4042 struct scsi_cmnd *done_scp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004044 shost = scp->device->host;
4045 boardp = ASC_BOARDP(shost);
4046 ASC_STATS(shost, queuecommand);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004047
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004048 /* host_lock taken by mid-level prior to call but need to protect */
4049 /* against own ISR */
4050 spin_lock_irqsave(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004052 /*
4053 * Block new commands while handling a reset or abort request.
4054 */
4055 if (boardp->flags & ASC_HOST_IN_RESET) {
4056 ASC_DBG1(1,
4057 "advansys_queuecommand: scp 0x%lx blocked for reset request\n",
4058 (ulong)scp);
4059 scp->result = HOST_BYTE(DID_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004061 /*
4062 * Add blocked requests to the board's 'done' queue. The queued
4063 * requests will be completed at the end of the abort or reset
4064 * handling.
4065 */
4066 asc_enqueue(&boardp->done, scp, ASC_BACK);
4067 spin_unlock_irqrestore(&boardp->lock, flags);
4068 return 0;
4069 }
4070
4071 /*
4072 * Attempt to execute any waiting commands for the board.
4073 */
4074 if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
4075 ASC_DBG(1,
4076 "advansys_queuecommand: before asc_execute_queue() waiting\n");
4077 asc_execute_queue(&boardp->waiting);
4078 }
4079
4080 /*
4081 * Save the function pointer to Linux mid-level 'done' function
4082 * and attempt to execute the command.
4083 *
4084 * If ASC_NOERROR is returned the request has been added to the
4085 * board's 'active' queue and will be completed by the interrupt
4086 * handler.
4087 *
4088 * If ASC_BUSY is returned add the request to the board's per
4089 * target waiting list. This is the first time the request has
4090 * been tried. Add it to the back of the waiting list. It will be
4091 * retried later.
4092 *
4093 * If an error occurred, the request will have been placed on the
4094 * board's 'done' queue and must be completed before returning.
4095 */
4096 scp->scsi_done = done;
4097 switch (asc_execute_scsi_cmnd(scp)) {
4098 case ASC_NOERROR:
4099 break;
4100 case ASC_BUSY:
4101 asc_enqueue(&boardp->waiting, scp, ASC_BACK);
4102 break;
4103 case ASC_ERROR:
4104 default:
4105 done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
4106 /* Interrupts could be enabled here. */
4107 asc_scsi_done_list(done_scp);
4108 break;
4109 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004110 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004112 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004113}
4114
4115/*
4116 * advansys_reset()
4117 *
4118 * Reset the bus associated with the command 'scp'.
4119 *
4120 * This function runs its own thread. Interrupts must be blocked but
4121 * sleeping is allowed and no locking other than for host structures is
4122 * required. Returns SUCCESS or FAILED.
4123 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004124static int advansys_reset(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004125{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004126 struct Scsi_Host *shost;
4127 asc_board_t *boardp;
4128 ASC_DVC_VAR *asc_dvc_varp;
4129 ADV_DVC_VAR *adv_dvc_varp;
4130 ulong flags;
4131 struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
4132 struct scsi_cmnd *tscp, *new_last_scp;
4133 int status;
4134 int ret = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004136 ASC_DBG1(1, "advansys_reset: 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137
4138#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004139 if (scp->device->host != NULL) {
4140 ASC_STATS(scp->device->host, reset);
4141 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142#endif /* ADVANSYS_STATS */
4143
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004144 if ((shost = scp->device->host) == NULL) {
4145 scp->result = HOST_BYTE(DID_ERROR);
4146 return FAILED;
4147 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004148
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004149 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004151 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset started...\n",
4152 boardp->id);
4153 /*
4154 * Check for re-entrancy.
4155 */
4156 spin_lock_irqsave(&boardp->lock, flags);
4157 if (boardp->flags & ASC_HOST_IN_RESET) {
4158 spin_unlock_irqrestore(&boardp->lock, flags);
4159 return FAILED;
4160 }
4161 boardp->flags |= ASC_HOST_IN_RESET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004164 if (ASC_NARROW_BOARD(boardp)) {
4165 /*
4166 * Narrow Board
4167 */
4168 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004170 /*
4171 * Reset the chip and SCSI bus.
4172 */
4173 ASC_DBG(1, "advansys_reset: before AscInitAsc1000Driver()\n");
4174 status = AscInitAsc1000Driver(asc_dvc_varp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004176 /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */
4177 if (asc_dvc_varp->err_code) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004178 ASC_PRINT2("advansys_reset: board %d: SCSI bus reset "
4179 "error: 0x%x\n", boardp->id,
4180 asc_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004181 ret = FAILED;
4182 } else if (status) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004183 ASC_PRINT2("advansys_reset: board %d: SCSI bus reset "
4184 "warning: 0x%x\n", boardp->id, status);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004185 } else {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004186 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset "
4187 "successful.\n", boardp->id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004188 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004190 ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
4191 spin_lock_irqsave(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004193 } else {
4194 /*
4195 * Wide Board
4196 *
4197 * If the suggest reset bus flags are set, then reset the bus.
4198 * Otherwise only reset the device.
4199 */
4200 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004201
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004202 /*
4203 * Reset the target's SCSI bus.
4204 */
4205 ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n");
4206 switch (AdvResetChipAndSB(adv_dvc_varp)) {
4207 case ASC_TRUE:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004208 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset "
4209 "successful.\n", boardp->id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004210 break;
4211 case ASC_FALSE:
4212 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004213 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset "
4214 "error.\n", boardp->id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004215 ret = FAILED;
4216 break;
4217 }
4218 spin_lock_irqsave(&boardp->lock, flags);
4219 (void)AdvISR(adv_dvc_varp);
4220 }
4221 /* Board lock is held. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004223 /*
4224 * Dequeue all board 'done' requests. A pointer to the last request
4225 * is returned in 'last_scp'.
4226 */
4227 done_scp = asc_dequeue_list(&boardp->done, &last_scp, ASC_TID_ALL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004229 /*
4230 * Dequeue all board 'active' requests for all devices and set
4231 * the request status to DID_RESET. A pointer to the last request
4232 * is returned in 'last_scp'.
4233 */
4234 if (done_scp == NULL) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004235 done_scp = asc_dequeue_list(&boardp->active, &last_scp,
4236 ASC_TID_ALL);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004237 for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
4238 tscp->result = HOST_BYTE(DID_RESET);
4239 }
4240 } else {
4241 /* Append to 'done_scp' at the end with 'last_scp'. */
4242 ASC_ASSERT(last_scp != NULL);
4243 last_scp->host_scribble =
4244 (unsigned char *)asc_dequeue_list(&boardp->active,
4245 &new_last_scp,
4246 ASC_TID_ALL);
4247 if (new_last_scp != NULL) {
4248 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4249 for (tscp = REQPNEXT(last_scp); tscp;
4250 tscp = REQPNEXT(tscp)) {
4251 tscp->result = HOST_BYTE(DID_RESET);
4252 }
4253 last_scp = new_last_scp;
4254 }
4255 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004256
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004257 /*
4258 * Dequeue all 'waiting' requests and set the request status
4259 * to DID_RESET.
4260 */
4261 if (done_scp == NULL) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004262 done_scp = asc_dequeue_list(&boardp->waiting, &last_scp,
4263 ASC_TID_ALL);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004264 for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
4265 tscp->result = HOST_BYTE(DID_RESET);
4266 }
4267 } else {
4268 /* Append to 'done_scp' at the end with 'last_scp'. */
4269 ASC_ASSERT(last_scp != NULL);
4270 last_scp->host_scribble =
4271 (unsigned char *)asc_dequeue_list(&boardp->waiting,
4272 &new_last_scp,
4273 ASC_TID_ALL);
4274 if (new_last_scp != NULL) {
4275 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4276 for (tscp = REQPNEXT(last_scp); tscp;
4277 tscp = REQPNEXT(tscp)) {
4278 tscp->result = HOST_BYTE(DID_RESET);
4279 }
4280 last_scp = new_last_scp;
4281 }
4282 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004284 /* Save the time of the most recently completed reset. */
4285 boardp->last_reset = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004286
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004287 /* Clear reset flag. */
4288 boardp->flags &= ~ASC_HOST_IN_RESET;
4289 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004291 /*
4292 * Complete all the 'done_scp' requests.
4293 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004294 if (done_scp)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004295 asc_scsi_done_list(done_scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004297 ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004299 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300}
4301
4302/*
4303 * advansys_biosparam()
4304 *
4305 * Translate disk drive geometry if the "BIOS greater than 1 GB"
4306 * support is enabled for a drive.
4307 *
4308 * ip (information pointer) is an int array with the following definition:
4309 * ip[0]: heads
4310 * ip[1]: sectors
4311 * ip[2]: cylinders
4312 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07004313static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004315 sector_t capacity, int ip[])
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004317 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004318
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004319 ASC_DBG(1, "advansys_biosparam: begin\n");
4320 ASC_STATS(sdev->host, biosparam);
4321 boardp = ASC_BOARDP(sdev->host);
4322 if (ASC_NARROW_BOARD(boardp)) {
4323 if ((boardp->dvc_var.asc_dvc_var.dvc_cntl &
4324 ASC_CNTL_BIOS_GT_1GB) && capacity > 0x200000) {
4325 ip[0] = 255;
4326 ip[1] = 63;
4327 } else {
4328 ip[0] = 64;
4329 ip[1] = 32;
4330 }
4331 } else {
4332 if ((boardp->dvc_var.adv_dvc_var.bios_ctrl &
4333 BIOS_CTRL_EXTENDED_XLAT) && capacity > 0x200000) {
4334 ip[0] = 255;
4335 ip[1] = 63;
4336 } else {
4337 ip[0] = 64;
4338 ip[1] = 32;
4339 }
4340 }
4341 ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
4342 ASC_DBG(1, "advansys_biosparam: end\n");
4343 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344}
4345
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06004346static struct scsi_host_template advansys_template = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004347 .proc_name = "advansys",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004349 .proc_info = advansys_proc_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004350#endif
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004351 .name = "advansys",
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004352 .info = advansys_info,
4353 .queuecommand = advansys_queuecommand,
4354 .eh_bus_reset_handler = advansys_reset,
4355 .bios_param = advansys_biosparam,
4356 .slave_configure = advansys_slave_configure,
4357 /*
4358 * Because the driver may control an ISA adapter 'unchecked_isa_dma'
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06004359 * must be set. The flag will be cleared in advansys_board_found
4360 * for non-ISA adapters.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004361 */
4362 .unchecked_isa_dma = 1,
4363 /*
4364 * All adapters controlled by this driver are capable of large
4365 * scatter-gather lists. According to the mid-level SCSI documentation
4366 * this obviates any performance gain provided by setting
4367 * 'use_clustering'. But empirically while CPU utilization is increased
4368 * by enabling clustering, I/O throughput increases as well.
4369 */
4370 .use_clustering = ENABLE_CLUSTERING,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372
Linus Torvalds1da177e2005-04-16 15:20:36 -07004373/*
4374 * --- Miscellaneous Driver Functions
4375 */
4376
4377/*
4378 * First-level interrupt handler.
4379 *
4380 * 'dev_id' is a pointer to the interrupting adapter's asc_board_t. Because
4381 * all boards are currently checked for interrupts on each interrupt, 'dev_id'
4382 * is not referenced. 'dev_id' could be used to identify an interrupt passed
4383 * to the AdvanSys driver which is for a device sharing an interrupt with
4384 * an AdvanSys adapter.
4385 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004386static irqreturn_t advansys_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387{
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004388 unsigned long flags;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004389 struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
4390 struct scsi_cmnd *new_last_scp;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004391 struct Scsi_Host *shost = dev_id;
4392 asc_board_t *boardp = ASC_BOARDP(shost);
4393 irqreturn_t result = IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004394
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004395 ASC_DBG1(2, "advansys_interrupt: boardp 0x%p\n", boardp);
4396 spin_lock_irqsave(&boardp->lock, flags);
4397 if (ASC_NARROW_BOARD(boardp)) {
4398 /*
4399 * Narrow Board
4400 */
4401 if (AscIsIntPending(shost->io_port)) {
4402 result = IRQ_HANDLED;
4403 ASC_STATS(shost, interrupt);
4404 ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
4405 AscISR(&boardp->dvc_var.asc_dvc_var);
4406 }
4407 } else {
4408 /*
4409 * Wide Board
4410 */
4411 ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
4412 if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
4413 result = IRQ_HANDLED;
4414 ASC_STATS(shost, interrupt);
4415 }
4416 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004418 /*
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004419 * Start waiting requests and create a list of completed requests.
4420 *
4421 * If a reset request is being performed for the board, the reset
4422 * handler will complete pending requests after it has completed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004423 */
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004424 if ((boardp->flags & ASC_HOST_IN_RESET) == 0) {
4425 ASC_DBG2(1, "advansys_interrupt: done_scp 0x%p, "
4426 "last_scp 0x%p\n", done_scp, last_scp);
4427
4428 /* Start any waiting commands for the board. */
4429 if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
4430 ASC_DBG(1, "advansys_interrupt: before "
4431 "asc_execute_queue()\n");
4432 asc_execute_queue(&boardp->waiting);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004433 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004435 /*
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004436 * Add to the list of requests that must be completed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004437 *
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004438 * 'done_scp' will always be NULL on the first iteration of
4439 * this loop. 'last_scp' is set at the same time as 'done_scp'.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004440 */
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004441 if (done_scp == NULL) {
4442 done_scp = asc_dequeue_list(&boardp->done,
4443 &last_scp, ASC_TID_ALL);
4444 } else {
4445 ASC_ASSERT(last_scp != NULL);
4446 last_scp->host_scribble =
4447 (unsigned char *)asc_dequeue_list(&boardp->
4448 done,
4449 &new_last_scp,
4450 ASC_TID_ALL);
4451 if (new_last_scp != NULL) {
4452 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4453 last_scp = new_last_scp;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004454 }
4455 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004456 }
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004457 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004459 /*
4460 * If interrupts were enabled on entry, then they
4461 * are now enabled here.
4462 *
4463 * Complete all requests on the done list.
4464 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004465
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004466 asc_scsi_done_list(done_scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004467
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004468 ASC_DBG(1, "advansys_interrupt: end\n");
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004469 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470}
4471
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004472static void
4473advansys_narrow_slave_configure(struct scsi_device *sdev, ASC_DVC_VAR *asc_dvc)
4474{
4475 ASC_SCSI_BIT_ID_TYPE tid_bit = 1 << sdev->id;
4476 ASC_SCSI_BIT_ID_TYPE orig_use_tagged_qng = asc_dvc->use_tagged_qng;
4477
4478 if (sdev->lun == 0) {
4479 ASC_SCSI_BIT_ID_TYPE orig_init_sdtr = asc_dvc->init_sdtr;
4480 if ((asc_dvc->cfg->sdtr_enable & tid_bit) && sdev->sdtr) {
4481 asc_dvc->init_sdtr |= tid_bit;
4482 } else {
4483 asc_dvc->init_sdtr &= ~tid_bit;
4484 }
4485
4486 if (orig_init_sdtr != asc_dvc->init_sdtr)
4487 AscAsyncFix(asc_dvc, sdev);
4488 }
4489
4490 if (sdev->tagged_supported) {
4491 if (asc_dvc->cfg->cmd_qng_enabled & tid_bit) {
4492 if (sdev->lun == 0) {
4493 asc_dvc->cfg->can_tagged_qng |= tid_bit;
4494 asc_dvc->use_tagged_qng |= tid_bit;
4495 }
4496 scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
4497 asc_dvc->max_dvc_qng[sdev->id]);
4498 }
4499 } else {
4500 if (sdev->lun == 0) {
4501 asc_dvc->cfg->can_tagged_qng &= ~tid_bit;
4502 asc_dvc->use_tagged_qng &= ~tid_bit;
4503 }
4504 scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
4505 }
4506
4507 if ((sdev->lun == 0) &&
4508 (orig_use_tagged_qng != asc_dvc->use_tagged_qng)) {
4509 AscWriteLramByte(asc_dvc->iop_base, ASCV_DISC_ENABLE_B,
4510 asc_dvc->cfg->disc_enable);
4511 AscWriteLramByte(asc_dvc->iop_base, ASCV_USE_TAGGED_QNG_B,
4512 asc_dvc->use_tagged_qng);
4513 AscWriteLramByte(asc_dvc->iop_base, ASCV_CAN_TAGGED_QNG_B,
4514 asc_dvc->cfg->can_tagged_qng);
4515
4516 asc_dvc->max_dvc_qng[sdev->id] =
4517 asc_dvc->cfg->max_tag_qng[sdev->id];
4518 AscWriteLramByte(asc_dvc->iop_base,
4519 (ushort)(ASCV_MAX_DVC_QNG_BEG + sdev->id),
4520 asc_dvc->max_dvc_qng[sdev->id]);
4521 }
4522}
4523
4524/*
4525 * Wide Transfers
4526 *
4527 * If the EEPROM enabled WDTR for the device and the device supports wide
4528 * bus (16 bit) transfers, then turn on the device's 'wdtr_able' bit and
4529 * write the new value to the microcode.
4530 */
4531static void
4532advansys_wide_enable_wdtr(AdvPortAddr iop_base, unsigned short tidmask)
4533{
4534 unsigned short cfg_word;
4535 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
4536 if ((cfg_word & tidmask) != 0)
4537 return;
4538
4539 cfg_word |= tidmask;
4540 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
4541
4542 /*
4543 * Clear the microcode SDTR and WDTR negotiation done indicators for
4544 * the target to cause it to negotiate with the new setting set above.
4545 * WDTR when accepted causes the target to enter asynchronous mode, so
4546 * SDTR must be negotiated.
4547 */
4548 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
4549 cfg_word &= ~tidmask;
4550 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
4551 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
4552 cfg_word &= ~tidmask;
4553 AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
4554}
4555
4556/*
4557 * Synchronous Transfers
4558 *
4559 * If the EEPROM enabled SDTR for the device and the device
4560 * supports synchronous transfers, then turn on the device's
4561 * 'sdtr_able' bit. Write the new value to the microcode.
4562 */
4563static void
4564advansys_wide_enable_sdtr(AdvPortAddr iop_base, unsigned short tidmask)
4565{
4566 unsigned short cfg_word;
4567 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
4568 if ((cfg_word & tidmask) != 0)
4569 return;
4570
4571 cfg_word |= tidmask;
4572 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
4573
4574 /*
4575 * Clear the microcode "SDTR negotiation" done indicator for the
4576 * target to cause it to negotiate with the new setting set above.
4577 */
4578 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
4579 cfg_word &= ~tidmask;
4580 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
4581}
4582
4583/*
4584 * PPR (Parallel Protocol Request) Capable
4585 *
4586 * If the device supports DT mode, then it must be PPR capable.
4587 * The PPR message will be used in place of the SDTR and WDTR
4588 * messages to negotiate synchronous speed and offset, transfer
4589 * width, and protocol options.
4590 */
4591static void advansys_wide_enable_ppr(ADV_DVC_VAR *adv_dvc,
4592 AdvPortAddr iop_base, unsigned short tidmask)
4593{
4594 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able);
4595 adv_dvc->ppr_able |= tidmask;
4596 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able);
4597}
4598
4599static void
4600advansys_wide_slave_configure(struct scsi_device *sdev, ADV_DVC_VAR *adv_dvc)
4601{
4602 AdvPortAddr iop_base = adv_dvc->iop_base;
4603 unsigned short tidmask = 1 << sdev->id;
4604
4605 if (sdev->lun == 0) {
4606 /*
4607 * Handle WDTR, SDTR, and Tag Queuing. If the feature
4608 * is enabled in the EEPROM and the device supports the
4609 * feature, then enable it in the microcode.
4610 */
4611
4612 if ((adv_dvc->wdtr_able & tidmask) && sdev->wdtr)
4613 advansys_wide_enable_wdtr(iop_base, tidmask);
4614 if ((adv_dvc->sdtr_able & tidmask) && sdev->sdtr)
4615 advansys_wide_enable_sdtr(iop_base, tidmask);
4616 if (adv_dvc->chip_type == ADV_CHIP_ASC38C1600 && sdev->ppr)
4617 advansys_wide_enable_ppr(adv_dvc, iop_base, tidmask);
4618
4619 /*
4620 * Tag Queuing is disabled for the BIOS which runs in polled
4621 * mode and would see no benefit from Tag Queuing. Also by
4622 * disabling Tag Queuing in the BIOS devices with Tag Queuing
4623 * bugs will at least work with the BIOS.
4624 */
4625 if ((adv_dvc->tagqng_able & tidmask) &&
4626 sdev->tagged_supported) {
4627 unsigned short cfg_word;
4628 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
4629 cfg_word |= tidmask;
4630 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
4631 cfg_word);
4632 AdvWriteByteLram(iop_base,
4633 ASC_MC_NUMBER_OF_MAX_CMD + sdev->id,
4634 adv_dvc->max_dvc_qng);
4635 }
4636 }
4637
4638 if ((adv_dvc->tagqng_able & tidmask) && sdev->tagged_supported) {
4639 scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
4640 adv_dvc->max_dvc_qng);
4641 } else {
4642 scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
4643 }
4644}
4645
Linus Torvalds1da177e2005-04-16 15:20:36 -07004646/*
4647 * Set the number of commands to queue per device for the
4648 * specified host adapter.
4649 */
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004650static int advansys_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004651{
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004652 asc_board_t *boardp = ASC_BOARDP(sdev->host);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004653 boardp->flags |= ASC_SELECT_QUEUE_DEPTHS;
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004654
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004655 /*
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004656 * Save a pointer to the sdev and set its initial/maximum
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004657 * queue depth. Only save the pointer for a lun0 dev though.
4658 */
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004659 if (sdev->lun == 0)
4660 boardp->device[sdev->id] = sdev;
4661
4662 if (ASC_NARROW_BOARD(boardp))
4663 advansys_narrow_slave_configure(sdev,
4664 &boardp->dvc_var.asc_dvc_var);
4665 else
4666 advansys_wide_slave_configure(sdev,
4667 &boardp->dvc_var.adv_dvc_var);
4668
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004669 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004670}
4671
4672/*
4673 * Complete all requests on the singly linked list pointed
4674 * to by 'scp'.
4675 *
4676 * Interrupts can be enabled on entry.
4677 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004678static void asc_scsi_done_list(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004679{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004680 struct scsi_cmnd *tscp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004681
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004682 ASC_DBG(2, "asc_scsi_done_list: begin\n");
4683 while (scp != NULL) {
4684 asc_board_t *boardp;
4685 struct device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004686
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004687 ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lx\n", (ulong)scp);
4688 tscp = REQPNEXT(scp);
4689 scp->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004690
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004691 boardp = ASC_BOARDP(scp->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004692
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004693 if (ASC_NARROW_BOARD(boardp))
4694 dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
4695 else
4696 dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004697
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004698 if (scp->use_sg)
4699 dma_unmap_sg(dev,
4700 (struct scatterlist *)scp->request_buffer,
4701 scp->use_sg, scp->sc_data_direction);
4702 else if (scp->request_bufflen)
4703 dma_unmap_single(dev, scp->SCp.dma_handle,
4704 scp->request_bufflen,
4705 scp->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004707 ASC_STATS(scp->device->host, done);
4708 ASC_ASSERT(scp->scsi_done != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004709
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004710 scp->scsi_done(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004711
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004712 scp = tscp;
4713 }
4714 ASC_DBG(2, "asc_scsi_done_list: done\n");
4715 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004716}
4717
4718/*
4719 * Execute a single 'Scsi_Cmnd'.
4720 *
4721 * The function 'done' is called when the request has been completed.
4722 *
4723 * Scsi_Cmnd:
4724 *
4725 * host - board controlling device
4726 * device - device to send command
4727 * target - target of device
4728 * lun - lun of device
4729 * cmd_len - length of SCSI CDB
4730 * cmnd - buffer for SCSI 8, 10, or 12 byte CDB
4731 * use_sg - if non-zero indicates scatter-gather request with use_sg elements
4732 *
4733 * if (use_sg == 0) {
4734 * request_buffer - buffer address for request
4735 * request_bufflen - length of request buffer
4736 * } else {
4737 * request_buffer - pointer to scatterlist structure
4738 * }
4739 *
4740 * sense_buffer - sense command buffer
4741 *
4742 * result (4 bytes of an int):
4743 * Byte Meaning
4744 * 0 SCSI Status Byte Code
4745 * 1 SCSI One Byte Message Code
4746 * 2 Host Error Code
4747 * 3 Mid-Level Error Code
4748 *
4749 * host driver fields:
4750 * SCp - Scsi_Pointer used for command processing status
4751 * scsi_done - used to save caller's done function
4752 * host_scribble - used for pointer to another struct scsi_cmnd
4753 *
4754 * If this function returns ASC_NOERROR the request has been enqueued
4755 * on the board's 'active' queue and will be completed from the
4756 * interrupt handler.
4757 *
4758 * If this function returns ASC_NOERROR the request has been enqueued
4759 * on the board's 'done' queue and must be completed by the caller.
4760 *
4761 * If ASC_BUSY is returned the request will be enqueued by the
4762 * caller on the target's waiting queue and re-tried later.
4763 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004764static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004766 asc_board_t *boardp;
4767 ASC_DVC_VAR *asc_dvc_varp;
4768 ADV_DVC_VAR *adv_dvc_varp;
4769 ADV_SCSI_REQ_Q *adv_scsiqp;
4770 struct scsi_device *device;
4771 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004773 ASC_DBG2(1, "asc_execute_scsi_cmnd: scp 0x%lx, done 0x%lx\n",
4774 (ulong)scp, (ulong)scp->scsi_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004776 boardp = ASC_BOARDP(scp->device->host);
4777 device = boardp->device[scp->device->id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004779 if (ASC_NARROW_BOARD(boardp)) {
4780 /*
4781 * Build and execute Narrow Board request.
4782 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004783
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004784 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004785
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004786 /*
4787 * Build Asc Library request structure using the
4788 * global structures 'asc_scsi_req' and 'asc_sg_head'.
4789 *
4790 * If an error is returned, then the request has been
4791 * queued on the board done queue. It will be completed
4792 * by the caller.
4793 *
4794 * asc_build_req() can not return ASC_BUSY.
4795 */
4796 if (asc_build_req(boardp, scp) == ASC_ERROR) {
4797 ASC_STATS(scp->device->host, build_error);
4798 return ASC_ERROR;
4799 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004801 /*
4802 * Execute the command. If there is no error, add the command
4803 * to the active queue.
4804 */
4805 switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
4806 case ASC_NOERROR:
4807 ASC_STATS(scp->device->host, exe_noerror);
4808 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004809 * Increment monotonically increasing per device
4810 * successful request counter. Wrapping doesn't matter.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004811 */
4812 boardp->reqcnt[scp->device->id]++;
4813 asc_enqueue(&boardp->active, scp, ASC_BACK);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004814 ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue(), "
4815 "ASC_NOERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004816 break;
4817 case ASC_BUSY:
4818 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004819 * Caller will enqueue request on the target's waiting
4820 * queue and retry later.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004821 */
4822 ASC_STATS(scp->device->host, exe_busy);
4823 break;
4824 case ASC_ERROR:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004825 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
4826 "AscExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
4827 boardp->id, asc_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004828 ASC_STATS(scp->device->host, exe_error);
4829 scp->result = HOST_BYTE(DID_ERROR);
4830 asc_enqueue(&boardp->done, scp, ASC_BACK);
4831 break;
4832 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004833 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
4834 "AscExeScsiQueue() unknown, err_code 0x%x\n",
4835 boardp->id, asc_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004836 ASC_STATS(scp->device->host, exe_unknown);
4837 scp->result = HOST_BYTE(DID_ERROR);
4838 asc_enqueue(&boardp->done, scp, ASC_BACK);
4839 break;
4840 }
4841 } else {
4842 /*
4843 * Build and execute Wide Board request.
4844 */
4845 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004846
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004847 /*
4848 * Build and get a pointer to an Adv Library request structure.
4849 *
4850 * If the request is successfully built then send it below,
4851 * otherwise return with an error.
4852 */
4853 switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
4854 case ASC_NOERROR:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004855 ASC_DBG(3, "asc_execute_scsi_cmnd: adv_build_req "
4856 "ASC_NOERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004857 break;
4858 case ASC_BUSY:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004859 ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req "
4860 "ASC_BUSY\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004861 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004862 * If busy is returned the request has not been
4863 * enqueued. It will be enqueued by the caller on the
4864 * target's waiting queue and retried later.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004865 *
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004866 * The asc_stats fields 'adv_build_noreq' and
4867 * 'adv_build_nosg' count wide board busy conditions.
4868 * They are updated in adv_build_req and
4869 * adv_get_sglist, respectively.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004870 */
4871 return ASC_BUSY;
4872 case ASC_ERROR:
4873 /*
4874 * If an error is returned, then the request has been
4875 * queued on the board done queue. It will be completed
4876 * by the caller.
4877 */
4878 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004879 ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req "
4880 "ASC_ERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004881 ASC_STATS(scp->device->host, build_error);
4882 return ASC_ERROR;
4883 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004884
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004885 /*
4886 * Execute the command. If there is no error, add the command
4887 * to the active queue.
4888 */
4889 switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) {
4890 case ASC_NOERROR:
4891 ASC_STATS(scp->device->host, exe_noerror);
4892 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004893 * Increment monotonically increasing per device
4894 * successful request counter. Wrapping doesn't matter.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004895 */
4896 boardp->reqcnt[scp->device->id]++;
4897 asc_enqueue(&boardp->active, scp, ASC_BACK);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004898 ASC_DBG(1, "asc_execute_scsi_cmnd: AdvExeScsiQueue(), "
4899 "ASC_NOERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004900 break;
4901 case ASC_BUSY:
4902 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004903 * Caller will enqueue request on the target's waiting
4904 * queue and retry later.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004905 */
4906 ASC_STATS(scp->device->host, exe_busy);
4907 break;
4908 case ASC_ERROR:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004909 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
4910 "AdvExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
4911 boardp->id, adv_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004912 ASC_STATS(scp->device->host, exe_error);
4913 scp->result = HOST_BYTE(DID_ERROR);
4914 asc_enqueue(&boardp->done, scp, ASC_BACK);
4915 break;
4916 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004917 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
4918 "AdvExeScsiQueue() unknown, err_code 0x%x\n",
4919 boardp->id, adv_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004920 ASC_STATS(scp->device->host, exe_unknown);
4921 scp->result = HOST_BYTE(DID_ERROR);
4922 asc_enqueue(&boardp->done, scp, ASC_BACK);
4923 break;
4924 }
4925 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004926
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004927 ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
4928 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004929}
4930
4931/*
4932 * Build a request structure for the Asc Library (Narrow Board).
4933 *
4934 * The global structures 'asc_scsi_q' and 'asc_sg_head' are
4935 * used to build the request.
4936 *
4937 * If an error occurs, then queue the request on the board done
4938 * queue and return ASC_ERROR.
4939 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004940static int asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004941{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004942 struct device *dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004943
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004944 /*
4945 * Mutually exclusive access is required to 'asc_scsi_q' and
4946 * 'asc_sg_head' until after the request is started.
4947 */
4948 memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004949
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004950 /*
4951 * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'.
4952 */
4953 asc_scsi_q.q2.srb_ptr = ASC_VADDR_TO_U32(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004954
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004955 /*
4956 * Build the ASC_SCSI_Q request.
4957 *
4958 * For narrow boards a CDB length maximum of 12 bytes
4959 * is supported.
4960 */
4961 if (scp->cmd_len > ASC_MAX_CDB_LEN) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004962 ASC_PRINT3("asc_build_req: board %d: cmd_len %d > "
4963 "ASC_MAX_CDB_LEN %d\n", boardp->id, scp->cmd_len,
4964 ASC_MAX_CDB_LEN);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004965 scp->result = HOST_BYTE(DID_ERROR);
4966 asc_enqueue(&boardp->done, scp, ASC_BACK);
4967 return ASC_ERROR;
4968 }
4969 asc_scsi_q.cdbptr = &scp->cmnd[0];
4970 asc_scsi_q.q2.cdb_len = scp->cmd_len;
4971 asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id);
4972 asc_scsi_q.q1.target_lun = scp->device->lun;
4973 asc_scsi_q.q2.target_ix =
4974 ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
4975 asc_scsi_q.q1.sense_addr =
4976 cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
4977 asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004978
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004979 /*
4980 * If there are any outstanding requests for the current target,
4981 * then every 255th request send an ORDERED request. This heuristic
4982 * tries to retain the benefit of request sorting while preventing
4983 * request starvation. 255 is the max number of tags or pending commands
4984 * a device may have outstanding.
4985 *
4986 * The request count is incremented below for every successfully
4987 * started request.
4988 *
4989 */
4990 if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->device->id] > 0) &&
4991 (boardp->reqcnt[scp->device->id] % 255) == 0) {
4992 asc_scsi_q.q2.tag_code = MSG_ORDERED_TAG;
4993 } else {
4994 asc_scsi_q.q2.tag_code = MSG_SIMPLE_TAG;
4995 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004996
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004997 /*
4998 * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
4999 * buffer command.
5000 */
5001 if (scp->use_sg == 0) {
5002 /*
5003 * CDB request of single contiguous buffer.
5004 */
5005 ASC_STATS(scp->device->host, cont_cnt);
5006 scp->SCp.dma_handle = scp->request_bufflen ?
5007 dma_map_single(dev, scp->request_buffer,
5008 scp->request_bufflen,
5009 scp->sc_data_direction) : 0;
5010 asc_scsi_q.q1.data_addr = cpu_to_le32(scp->SCp.dma_handle);
5011 asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen);
5012 ASC_STATS_ADD(scp->device->host, cont_xfer,
5013 ASC_CEILING(scp->request_bufflen, 512));
5014 asc_scsi_q.q1.sg_queue_cnt = 0;
5015 asc_scsi_q.sg_head = NULL;
5016 } else {
5017 /*
5018 * CDB scatter-gather request list.
5019 */
5020 int sgcnt;
5021 int use_sg;
5022 struct scatterlist *slp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005023
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005024 slp = (struct scatterlist *)scp->request_buffer;
5025 use_sg =
5026 dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005027
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005028 if (use_sg > scp->device->host->sg_tablesize) {
5029 ASC_PRINT3
5030 ("asc_build_req: board %d: use_sg %d > sg_tablesize %d\n",
5031 boardp->id, use_sg,
5032 scp->device->host->sg_tablesize);
5033 dma_unmap_sg(dev, slp, scp->use_sg,
5034 scp->sc_data_direction);
5035 scp->result = HOST_BYTE(DID_ERROR);
5036 asc_enqueue(&boardp->done, scp, ASC_BACK);
5037 return ASC_ERROR;
5038 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005039
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005040 ASC_STATS(scp->device->host, sg_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005041
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005042 /*
5043 * Use global ASC_SG_HEAD structure and set the ASC_SCSI_Q
5044 * structure to point to it.
5045 */
5046 memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005047
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005048 asc_scsi_q.q1.cntl |= QC_SG_HEAD;
5049 asc_scsi_q.sg_head = &asc_sg_head;
5050 asc_scsi_q.q1.data_cnt = 0;
5051 asc_scsi_q.q1.data_addr = 0;
5052 /* This is a byte value, otherwise it would need to be swapped. */
5053 asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = use_sg;
5054 ASC_STATS_ADD(scp->device->host, sg_elem,
5055 asc_sg_head.entry_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005057 /*
5058 * Convert scatter-gather list into ASC_SG_HEAD list.
5059 */
5060 for (sgcnt = 0; sgcnt < use_sg; sgcnt++, slp++) {
5061 asc_sg_head.sg_list[sgcnt].addr =
5062 cpu_to_le32(sg_dma_address(slp));
5063 asc_sg_head.sg_list[sgcnt].bytes =
5064 cpu_to_le32(sg_dma_len(slp));
5065 ASC_STATS_ADD(scp->device->host, sg_xfer,
5066 ASC_CEILING(sg_dma_len(slp), 512));
5067 }
5068 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005069
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005070 ASC_DBG_PRT_ASC_SCSI_Q(2, &asc_scsi_q);
5071 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005072
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005073 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005074}
5075
5076/*
5077 * Build a request structure for the Adv Library (Wide Board).
5078 *
5079 * If an adv_req_t can not be allocated to issue the request,
5080 * then return ASC_BUSY. If an error occurs, then return ASC_ERROR.
5081 *
5082 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the
5083 * microcode for DMA addresses or math operations are byte swapped
5084 * to little-endian order.
5085 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005086static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005087adv_build_req(asc_board_t *boardp, struct scsi_cmnd *scp,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005088 ADV_SCSI_REQ_Q **adv_scsiqpp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005089{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005090 adv_req_t *reqp;
5091 ADV_SCSI_REQ_Q *scsiqp;
5092 int i;
5093 int ret;
5094 struct device *dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005095
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005096 /*
5097 * Allocate an adv_req_t structure from the board to execute
5098 * the command.
5099 */
5100 if (boardp->adv_reqp == NULL) {
5101 ASC_DBG(1, "adv_build_req: no free adv_req_t\n");
5102 ASC_STATS(scp->device->host, adv_build_noreq);
5103 return ASC_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005104 } else {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005105 reqp = boardp->adv_reqp;
5106 boardp->adv_reqp = reqp->next_reqp;
5107 reqp->next_reqp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005108 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005109
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005110 /*
5111 * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
5112 */
5113 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005114
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005115 /*
5116 * Initialize the structure.
5117 */
5118 scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005119
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005120 /*
5121 * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
5122 */
5123 scsiqp->srb_ptr = ASC_VADDR_TO_U32(reqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005124
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005125 /*
5126 * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure.
5127 */
5128 reqp->cmndp = scp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005129
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005130 /*
5131 * Build the ADV_SCSI_REQ_Q request.
5132 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005133
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005134 /*
5135 * Set CDB length and copy it to the request structure.
5136 * For wide boards a CDB length maximum of 16 bytes
5137 * is supported.
5138 */
5139 if (scp->cmd_len > ADV_MAX_CDB_LEN) {
5140 ASC_PRINT3
5141 ("adv_build_req: board %d: cmd_len %d > ADV_MAX_CDB_LEN %d\n",
5142 boardp->id, scp->cmd_len, ADV_MAX_CDB_LEN);
5143 scp->result = HOST_BYTE(DID_ERROR);
5144 asc_enqueue(&boardp->done, scp, ASC_BACK);
5145 return ASC_ERROR;
5146 }
5147 scsiqp->cdb_len = scp->cmd_len;
5148 /* Copy first 12 CDB bytes to cdb[]. */
5149 for (i = 0; i < scp->cmd_len && i < 12; i++) {
5150 scsiqp->cdb[i] = scp->cmnd[i];
5151 }
5152 /* Copy last 4 CDB bytes, if present, to cdb16[]. */
5153 for (; i < scp->cmd_len; i++) {
5154 scsiqp->cdb16[i - 12] = scp->cmnd[i];
5155 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005156
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005157 scsiqp->target_id = scp->device->id;
5158 scsiqp->target_lun = scp->device->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005159
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005160 scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
5161 scsiqp->sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005162
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005163 /*
5164 * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather
5165 * buffer command.
5166 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005167
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005168 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
5169 scsiqp->vdata_addr = scp->request_buffer;
5170 scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer));
5171
5172 if (scp->use_sg == 0) {
5173 /*
5174 * CDB request of single contiguous buffer.
5175 */
5176 reqp->sgblkp = NULL;
5177 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
5178 if (scp->request_bufflen) {
5179 scsiqp->vdata_addr = scp->request_buffer;
5180 scp->SCp.dma_handle =
5181 dma_map_single(dev, scp->request_buffer,
5182 scp->request_bufflen,
5183 scp->sc_data_direction);
5184 } else {
5185 scsiqp->vdata_addr = NULL;
5186 scp->SCp.dma_handle = 0;
5187 }
5188 scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle);
5189 scsiqp->sg_list_ptr = NULL;
5190 scsiqp->sg_real_addr = 0;
5191 ASC_STATS(scp->device->host, cont_cnt);
5192 ASC_STATS_ADD(scp->device->host, cont_xfer,
5193 ASC_CEILING(scp->request_bufflen, 512));
5194 } else {
5195 /*
5196 * CDB scatter-gather request list.
5197 */
5198 struct scatterlist *slp;
5199 int use_sg;
5200
5201 slp = (struct scatterlist *)scp->request_buffer;
5202 use_sg =
5203 dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
5204
5205 if (use_sg > ADV_MAX_SG_LIST) {
5206 ASC_PRINT3
5207 ("adv_build_req: board %d: use_sg %d > ADV_MAX_SG_LIST %d\n",
5208 boardp->id, use_sg,
5209 scp->device->host->sg_tablesize);
5210 dma_unmap_sg(dev, slp, scp->use_sg,
5211 scp->sc_data_direction);
5212 scp->result = HOST_BYTE(DID_ERROR);
5213 asc_enqueue(&boardp->done, scp, ASC_BACK);
5214
5215 /*
5216 * Free the 'adv_req_t' structure by adding it back to the
5217 * board free list.
5218 */
5219 reqp->next_reqp = boardp->adv_reqp;
5220 boardp->adv_reqp = reqp;
5221
5222 return ASC_ERROR;
5223 }
5224
5225 if ((ret =
5226 adv_get_sglist(boardp, reqp, scp,
5227 use_sg)) != ADV_SUCCESS) {
5228 /*
5229 * Free the adv_req_t structure by adding it back to the
5230 * board free list.
5231 */
5232 reqp->next_reqp = boardp->adv_reqp;
5233 boardp->adv_reqp = reqp;
5234
5235 return ret;
5236 }
5237
5238 ASC_STATS(scp->device->host, sg_cnt);
5239 ASC_STATS_ADD(scp->device->host, sg_elem, use_sg);
5240 }
5241
5242 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
5243 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
5244
5245 *adv_scsiqpp = scsiqp;
5246
5247 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248}
5249
5250/*
5251 * Build scatter-gather list for Adv Library (Wide Board).
5252 *
5253 * Additional ADV_SG_BLOCK structures will need to be allocated
5254 * if the total number of scatter-gather elements exceeds
5255 * NO_OF_SG_PER_BLOCK (15). The ADV_SG_BLOCK structures are
5256 * assumed to be physically contiguous.
5257 *
5258 * Return:
5259 * ADV_SUCCESS(1) - SG List successfully created
5260 * ADV_ERROR(-1) - SG List creation failed
5261 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005262static int
5263adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, struct scsi_cmnd *scp,
5264 int use_sg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005265{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005266 adv_sgblk_t *sgblkp;
5267 ADV_SCSI_REQ_Q *scsiqp;
5268 struct scatterlist *slp;
5269 int sg_elem_cnt;
5270 ADV_SG_BLOCK *sg_block, *prev_sg_block;
5271 ADV_PADDR sg_block_paddr;
5272 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005273
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005274 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
5275 slp = (struct scatterlist *)scp->request_buffer;
5276 sg_elem_cnt = use_sg;
5277 prev_sg_block = NULL;
5278 reqp->sgblkp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005279
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005280 do {
5281 /*
5282 * Allocate a 'adv_sgblk_t' structure from the board free
5283 * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK
5284 * (15) scatter-gather elements.
5285 */
5286 if ((sgblkp = boardp->adv_sgblkp) == NULL) {
5287 ASC_DBG(1, "adv_get_sglist: no free adv_sgblk_t\n");
5288 ASC_STATS(scp->device->host, adv_build_nosg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005289
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005290 /*
5291 * Allocation failed. Free 'adv_sgblk_t' structures already
5292 * allocated for the request.
5293 */
5294 while ((sgblkp = reqp->sgblkp) != NULL) {
5295 /* Remove 'sgblkp' from the request list. */
5296 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005297
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005298 /* Add 'sgblkp' to the board free list. */
5299 sgblkp->next_sgblkp = boardp->adv_sgblkp;
5300 boardp->adv_sgblkp = sgblkp;
5301 }
5302 return ASC_BUSY;
5303 } else {
5304 /* Complete 'adv_sgblk_t' board allocation. */
5305 boardp->adv_sgblkp = sgblkp->next_sgblkp;
5306 sgblkp->next_sgblkp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005307
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005308 /*
5309 * Get 8 byte aligned virtual and physical addresses for
5310 * the allocated ADV_SG_BLOCK structure.
5311 */
5312 sg_block =
5313 (ADV_SG_BLOCK *)ADV_8BALIGN(&sgblkp->sg_block);
5314 sg_block_paddr = virt_to_bus(sg_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005315
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005316 /*
5317 * Check if this is the first 'adv_sgblk_t' for the request.
5318 */
5319 if (reqp->sgblkp == NULL) {
5320 /* Request's first scatter-gather block. */
5321 reqp->sgblkp = sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005322
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005323 /*
5324 * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical
5325 * address pointers.
5326 */
5327 scsiqp->sg_list_ptr = sg_block;
5328 scsiqp->sg_real_addr =
5329 cpu_to_le32(sg_block_paddr);
5330 } else {
5331 /* Request's second or later scatter-gather block. */
5332 sgblkp->next_sgblkp = reqp->sgblkp;
5333 reqp->sgblkp = sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005334
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005335 /*
5336 * Point the previous ADV_SG_BLOCK structure to
5337 * the newly allocated ADV_SG_BLOCK structure.
5338 */
5339 ASC_ASSERT(prev_sg_block != NULL);
5340 prev_sg_block->sg_ptr =
5341 cpu_to_le32(sg_block_paddr);
5342 }
5343 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005344
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005345 for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) {
5346 sg_block->sg_list[i].sg_addr =
5347 cpu_to_le32(sg_dma_address(slp));
5348 sg_block->sg_list[i].sg_count =
5349 cpu_to_le32(sg_dma_len(slp));
5350 ASC_STATS_ADD(scp->device->host, sg_xfer,
5351 ASC_CEILING(sg_dma_len(slp), 512));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005352
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005353 if (--sg_elem_cnt == 0) { /* Last ADV_SG_BLOCK and scatter-gather entry. */
5354 sg_block->sg_cnt = i + 1;
5355 sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */
5356 return ADV_SUCCESS;
5357 }
5358 slp++;
5359 }
5360 sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
5361 prev_sg_block = sg_block;
5362 }
5363 while (1);
5364 /* NOTREACHED */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005365}
5366
5367/*
5368 * asc_isr_callback() - Second Level Interrupt Handler called by AscISR().
5369 *
5370 * Interrupt callback function for the Narrow SCSI Asc Library.
5371 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005372static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005373{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005374 asc_board_t *boardp;
5375 struct scsi_cmnd *scp;
5376 struct Scsi_Host *shost;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005377
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005378 ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp 0x%lx, qdonep 0x%lx\n",
5379 (ulong)asc_dvc_varp, (ulong)qdonep);
5380 ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005381
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005382 /*
5383 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
5384 * command that has been completed.
5385 */
5386 scp = (struct scsi_cmnd *)ASC_U32_TO_VADDR(qdonep->d2.srb_ptr);
5387 ASC_DBG1(1, "asc_isr_callback: scp 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005388
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005389 if (scp == NULL) {
5390 ASC_PRINT("asc_isr_callback: scp is NULL\n");
5391 return;
5392 }
5393 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005394
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005395 shost = scp->device->host;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005396 ASC_STATS(shost, callback);
5397 ASC_DBG1(1, "asc_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005398
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005399 /*
5400 * If the request isn't found on the active queue, it may
5401 * have been removed to handle a reset request.
5402 * Display a message and return.
5403 */
5404 boardp = ASC_BOARDP(shost);
5405 ASC_ASSERT(asc_dvc_varp == &boardp->dvc_var.asc_dvc_var);
5406 if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
5407 ASC_PRINT2
5408 ("asc_isr_callback: board %d: scp 0x%lx not on active queue\n",
5409 boardp->id, (ulong)scp);
5410 return;
5411 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005412
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005413 /*
5414 * 'qdonep' contains the command's ending status.
5415 */
5416 switch (qdonep->d3.done_stat) {
5417 case QD_NO_ERROR:
5418 ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n");
5419 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005420
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005421 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005422 * Check for an underrun condition.
5423 *
5424 * If there was no error and an underrun condition, then
Matthew Wilcox47d853c2007-07-26 11:41:33 -04005425 * return the number of underrun bytes.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005426 */
5427 if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 &&
5428 qdonep->remain_bytes <= scp->request_bufflen) {
5429 ASC_DBG1(1,
5430 "asc_isr_callback: underrun condition %u bytes\n",
5431 (unsigned)qdonep->remain_bytes);
5432 scp->resid = qdonep->remain_bytes;
5433 }
5434 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005435
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005436 case QD_WITH_ERROR:
5437 ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n");
5438 switch (qdonep->d3.host_stat) {
5439 case QHSTA_NO_ERROR:
5440 if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
5441 ASC_DBG(2,
5442 "asc_isr_callback: SAM_STAT_CHECK_CONDITION\n");
5443 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
5444 sizeof(scp->sense_buffer));
5445 /*
5446 * Note: The 'status_byte()' macro used by target drivers
5447 * defined in scsi.h shifts the status byte returned by
5448 * host drivers right by 1 bit. This is why target drivers
5449 * also use right shifted status byte definitions. For
5450 * instance target drivers use CHECK_CONDITION, defined to
5451 * 0x1, instead of the SCSI defined check condition value
5452 * of 0x2. Host drivers are supposed to return the status
5453 * byte as it is defined by SCSI.
5454 */
5455 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
5456 STATUS_BYTE(qdonep->d3.scsi_stat);
5457 } else {
5458 scp->result = STATUS_BYTE(qdonep->d3.scsi_stat);
5459 }
5460 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005461
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005462 default:
5463 /* QHSTA error occurred */
5464 ASC_DBG1(1, "asc_isr_callback: host_stat 0x%x\n",
5465 qdonep->d3.host_stat);
5466 scp->result = HOST_BYTE(DID_BAD_TARGET);
5467 break;
5468 }
5469 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005470
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005471 case QD_ABORTED_BY_HOST:
5472 ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOST\n");
5473 scp->result =
5474 HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.
5475 scsi_msg) |
5476 STATUS_BYTE(qdonep->d3.scsi_stat);
5477 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005478
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005479 default:
5480 ASC_DBG1(1, "asc_isr_callback: done_stat 0x%x\n",
5481 qdonep->d3.done_stat);
5482 scp->result =
5483 HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.
5484 scsi_msg) |
5485 STATUS_BYTE(qdonep->d3.scsi_stat);
5486 break;
5487 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005488
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005489 /*
5490 * If the 'init_tidmask' bit isn't already set for the target and the
5491 * current request finished normally, then set the bit for the target
5492 * to indicate that a device is present.
5493 */
5494 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
5495 qdonep->d3.done_stat == QD_NO_ERROR &&
5496 qdonep->d3.host_stat == QHSTA_NO_ERROR) {
5497 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
5498 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005499
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005500 /*
5501 * Because interrupts may be enabled by the 'struct scsi_cmnd' done
5502 * function, add the command to the end of the board's done queue.
5503 * The done function for the command will be called from
5504 * advansys_interrupt().
5505 */
5506 asc_enqueue(&boardp->done, scp, ASC_BACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005507
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005508 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509}
5510
5511/*
5512 * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR().
5513 *
5514 * Callback function for the Wide SCSI Adv Library.
5515 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005516static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005517{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005518 asc_board_t *boardp;
5519 adv_req_t *reqp;
5520 adv_sgblk_t *sgblkp;
5521 struct scsi_cmnd *scp;
5522 struct Scsi_Host *shost;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005523 ADV_DCNT resid_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005524
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005525 ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp 0x%lx, scsiqp 0x%lx\n",
5526 (ulong)adv_dvc_varp, (ulong)scsiqp);
5527 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005528
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005529 /*
5530 * Get the adv_req_t structure for the command that has been
5531 * completed. The adv_req_t structure actually contains the
5532 * completed ADV_SCSI_REQ_Q structure.
5533 */
5534 reqp = (adv_req_t *)ADV_U32_TO_VADDR(scsiqp->srb_ptr);
5535 ASC_DBG1(1, "adv_isr_callback: reqp 0x%lx\n", (ulong)reqp);
5536 if (reqp == NULL) {
5537 ASC_PRINT("adv_isr_callback: reqp is NULL\n");
5538 return;
5539 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005540
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005541 /*
5542 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
5543 * command that has been completed.
5544 *
5545 * Note: The adv_req_t request structure and adv_sgblk_t structure,
5546 * if any, are dropped, because a board structure pointer can not be
5547 * determined.
5548 */
5549 scp = reqp->cmndp;
5550 ASC_DBG1(1, "adv_isr_callback: scp 0x%lx\n", (ulong)scp);
5551 if (scp == NULL) {
5552 ASC_PRINT
5553 ("adv_isr_callback: scp is NULL; adv_req_t dropped.\n");
5554 return;
5555 }
5556 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005557
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005558 shost = scp->device->host;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005559 ASC_STATS(shost, callback);
5560 ASC_DBG1(1, "adv_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005561
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005562 /*
5563 * If the request isn't found on the active queue, it may have been
5564 * removed to handle a reset request. Display a message and return.
5565 *
5566 * Note: Because the structure may still be in use don't attempt
5567 * to free the adv_req_t and adv_sgblk_t, if any, structures.
5568 */
5569 boardp = ASC_BOARDP(shost);
5570 ASC_ASSERT(adv_dvc_varp == &boardp->dvc_var.adv_dvc_var);
5571 if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
5572 ASC_PRINT2
5573 ("adv_isr_callback: board %d: scp 0x%lx not on active queue\n",
5574 boardp->id, (ulong)scp);
5575 return;
5576 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005577
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005578 /*
5579 * 'done_status' contains the command's ending status.
5580 */
5581 switch (scsiqp->done_status) {
5582 case QD_NO_ERROR:
5583 ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n");
5584 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005585
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005586 /*
5587 * Check for an underrun condition.
5588 *
5589 * If there was no error and an underrun condition, then
5590 * then return the number of underrun bytes.
5591 */
5592 resid_cnt = le32_to_cpu(scsiqp->data_cnt);
5593 if (scp->request_bufflen != 0 && resid_cnt != 0 &&
5594 resid_cnt <= scp->request_bufflen) {
5595 ASC_DBG1(1,
5596 "adv_isr_callback: underrun condition %lu bytes\n",
5597 (ulong)resid_cnt);
5598 scp->resid = resid_cnt;
5599 }
5600 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005601
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005602 case QD_WITH_ERROR:
5603 ASC_DBG(2, "adv_isr_callback: QD_WITH_ERROR\n");
5604 switch (scsiqp->host_status) {
5605 case QHSTA_NO_ERROR:
5606 if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
5607 ASC_DBG(2,
5608 "adv_isr_callback: SAM_STAT_CHECK_CONDITION\n");
5609 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
5610 sizeof(scp->sense_buffer));
5611 /*
5612 * Note: The 'status_byte()' macro used by target drivers
5613 * defined in scsi.h shifts the status byte returned by
5614 * host drivers right by 1 bit. This is why target drivers
5615 * also use right shifted status byte definitions. For
5616 * instance target drivers use CHECK_CONDITION, defined to
5617 * 0x1, instead of the SCSI defined check condition value
5618 * of 0x2. Host drivers are supposed to return the status
5619 * byte as it is defined by SCSI.
5620 */
5621 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
5622 STATUS_BYTE(scsiqp->scsi_status);
5623 } else {
5624 scp->result = STATUS_BYTE(scsiqp->scsi_status);
5625 }
5626 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005627
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005628 default:
5629 /* Some other QHSTA error occurred. */
5630 ASC_DBG1(1, "adv_isr_callback: host_status 0x%x\n",
5631 scsiqp->host_status);
5632 scp->result = HOST_BYTE(DID_BAD_TARGET);
5633 break;
5634 }
5635 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005636
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005637 case QD_ABORTED_BY_HOST:
5638 ASC_DBG(1, "adv_isr_callback: QD_ABORTED_BY_HOST\n");
5639 scp->result =
5640 HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status);
5641 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005642
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005643 default:
5644 ASC_DBG1(1, "adv_isr_callback: done_status 0x%x\n",
5645 scsiqp->done_status);
5646 scp->result =
5647 HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status);
5648 break;
5649 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005650
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005651 /*
5652 * If the 'init_tidmask' bit isn't already set for the target and the
5653 * current request finished normally, then set the bit for the target
5654 * to indicate that a device is present.
5655 */
5656 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
5657 scsiqp->done_status == QD_NO_ERROR &&
5658 scsiqp->host_status == QHSTA_NO_ERROR) {
5659 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
5660 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005661
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005662 /*
5663 * Because interrupts may be enabled by the 'struct scsi_cmnd' done
5664 * function, add the command to the end of the board's done queue.
5665 * The done function for the command will be called from
5666 * advansys_interrupt().
5667 */
5668 asc_enqueue(&boardp->done, scp, ASC_BACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005669
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005670 /*
5671 * Free all 'adv_sgblk_t' structures allocated for the request.
5672 */
5673 while ((sgblkp = reqp->sgblkp) != NULL) {
5674 /* Remove 'sgblkp' from the request list. */
5675 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005676
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005677 /* Add 'sgblkp' to the board free list. */
5678 sgblkp->next_sgblkp = boardp->adv_sgblkp;
5679 boardp->adv_sgblkp = sgblkp;
5680 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005681
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005682 /*
5683 * Free the adv_req_t structure used with the command by adding
5684 * it back to the board free list.
5685 */
5686 reqp->next_reqp = boardp->adv_reqp;
5687 boardp->adv_reqp = reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005688
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005689 ASC_DBG(1, "adv_isr_callback: done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005690
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005691 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005692}
5693
5694/*
5695 * adv_async_callback() - Adv Library asynchronous event callback function.
5696 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005697static void adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005698{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005699 switch (code) {
5700 case ADV_ASYNC_SCSI_BUS_RESET_DET:
5701 /*
5702 * The firmware detected a SCSI Bus reset.
5703 */
5704 ASC_DBG(0,
5705 "adv_async_callback: ADV_ASYNC_SCSI_BUS_RESET_DET\n");
5706 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005707
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005708 case ADV_ASYNC_RDMA_FAILURE:
5709 /*
5710 * Handle RDMA failure by resetting the SCSI Bus and
5711 * possibly the chip if it is unresponsive. Log the error
5712 * with a unique code.
5713 */
5714 ASC_DBG(0, "adv_async_callback: ADV_ASYNC_RDMA_FAILURE\n");
5715 AdvResetChipAndSB(adv_dvc_varp);
5716 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005717
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005718 case ADV_HOST_SCSI_BUS_RESET:
5719 /*
5720 * Host generated SCSI bus reset occurred.
5721 */
5722 ASC_DBG(0, "adv_async_callback: ADV_HOST_SCSI_BUS_RESET\n");
5723 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005724
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005725 default:
5726 ASC_DBG1(0, "DvcAsyncCallBack: unknown code 0x%x\n", code);
5727 break;
5728 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005729}
5730
5731/*
5732 * Add a 'REQP' to the end of specified queue. Set 'tidmask'
5733 * to indicate a command is queued for the device.
5734 *
5735 * 'flag' may be either ASC_FRONT or ASC_BACK.
5736 *
5737 * 'REQPNEXT(reqp)' returns reqp's next pointer.
5738 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005739static void asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005740{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005741 int tid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005742
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005743 ASC_DBG3(3, "asc_enqueue: ascq 0x%lx, reqp 0x%lx, flag %d\n",
5744 (ulong)ascq, (ulong)reqp, flag);
5745 ASC_ASSERT(reqp != NULL);
5746 ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
5747 tid = REQPTID(reqp);
5748 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
5749 if (flag == ASC_FRONT) {
5750 reqp->host_scribble = (unsigned char *)ascq->q_first[tid];
5751 ascq->q_first[tid] = reqp;
5752 /* If the queue was empty, set the last pointer. */
5753 if (ascq->q_last[tid] == NULL) {
5754 ascq->q_last[tid] = reqp;
5755 }
5756 } else { /* ASC_BACK */
5757 if (ascq->q_last[tid] != NULL) {
5758 ascq->q_last[tid]->host_scribble =
5759 (unsigned char *)reqp;
5760 }
5761 ascq->q_last[tid] = reqp;
5762 reqp->host_scribble = NULL;
5763 /* If the queue was empty, set the first pointer. */
5764 if (ascq->q_first[tid] == NULL) {
5765 ascq->q_first[tid] = reqp;
5766 }
5767 }
5768 /* The queue has at least one entry, set its bit. */
5769 ascq->q_tidmask |= ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005770#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005771 /* Maintain request queue statistics. */
5772 ascq->q_tot_cnt[tid]++;
5773 ascq->q_cur_cnt[tid]++;
5774 if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) {
5775 ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid];
5776 ASC_DBG2(2, "asc_enqueue: new q_max_cnt[%d] %d\n",
5777 tid, ascq->q_max_cnt[tid]);
5778 }
5779 REQPTIME(reqp) = REQTIMESTAMP();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005780#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005781 ASC_DBG1(3, "asc_enqueue: reqp 0x%lx\n", (ulong)reqp);
5782 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005783}
5784
5785/*
5786 * Return first queued 'REQP' on the specified queue for
5787 * the specified target device. Clear the 'tidmask' bit for
5788 * the device if no more commands are left queued for it.
5789 *
5790 * 'REQPNEXT(reqp)' returns reqp's next pointer.
5791 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005792static REQP asc_dequeue(asc_queue_t *ascq, int tid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005793{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005794 REQP reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005795
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005796 ASC_DBG2(3, "asc_dequeue: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
5797 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
5798 if ((reqp = ascq->q_first[tid]) != NULL) {
5799 ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid));
5800 ascq->q_first[tid] = REQPNEXT(reqp);
5801 /* If the queue is empty, clear its bit and the last pointer. */
5802 if (ascq->q_first[tid] == NULL) {
5803 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
5804 ASC_ASSERT(ascq->q_last[tid] == reqp);
5805 ascq->q_last[tid] = NULL;
5806 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005807#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005808 /* Maintain request queue statistics. */
5809 ascq->q_cur_cnt[tid]--;
5810 ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
5811 REQTIMESTAT("asc_dequeue", ascq, reqp, tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005812#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005813 }
5814 ASC_DBG1(3, "asc_dequeue: reqp 0x%lx\n", (ulong)reqp);
5815 return reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005816}
5817
5818/*
5819 * Return a pointer to a singly linked list of all the requests queued
5820 * for 'tid' on the 'asc_queue_t' pointed to by 'ascq'.
5821 *
5822 * If 'lastpp' is not NULL, '*lastpp' will be set to point to the
5823 * the last request returned in the singly linked list.
5824 *
5825 * 'tid' should either be a valid target id or if it is ASC_TID_ALL,
5826 * then all queued requests are concatenated into one list and
5827 * returned.
5828 *
5829 * Note: If 'lastpp' is used to append a new list to the end of
5830 * an old list, only change the old list last pointer if '*lastpp'
5831 * (or the function return value) is not NULL, i.e. use a temporary
5832 * variable for 'lastpp' and check its value after the function return
5833 * before assigning it to the list last pointer.
5834 *
5835 * Unfortunately collecting queuing time statistics adds overhead to
5836 * the function that isn't inherent to the function's algorithm.
5837 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005838static REQP asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005839{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005840 REQP firstp, lastp;
5841 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005842
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005843 ASC_DBG2(3, "asc_dequeue_list: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
5844 ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005845
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005846 /*
5847 * If 'tid' is not ASC_TID_ALL, return requests only for
5848 * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all
5849 * requests for all tids.
5850 */
5851 if (tid != ASC_TID_ALL) {
5852 /* Return all requests for the specified 'tid'. */
5853 if ((ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)) == 0) {
5854 /* List is empty; Set first and last return pointers to NULL. */
5855 firstp = lastp = NULL;
5856 } else {
5857 firstp = ascq->q_first[tid];
5858 lastp = ascq->q_last[tid];
5859 ascq->q_first[tid] = ascq->q_last[tid] = NULL;
5860 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005861#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005862 {
5863 REQP reqp;
5864 ascq->q_cur_cnt[tid] = 0;
5865 for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
5866 REQTIMESTAT("asc_dequeue_list", ascq,
5867 reqp, tid);
5868 }
5869 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005870#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005871 }
5872 } else {
5873 /* Return all requests for all tids. */
5874 firstp = lastp = NULL;
5875 for (i = 0; i <= ADV_MAX_TID; i++) {
5876 if (ascq->q_tidmask & ADV_TID_TO_TIDMASK(i)) {
5877 if (firstp == NULL) {
5878 firstp = ascq->q_first[i];
5879 lastp = ascq->q_last[i];
5880 } else {
5881 ASC_ASSERT(lastp != NULL);
5882 lastp->host_scribble =
5883 (unsigned char *)ascq->q_first[i];
5884 lastp = ascq->q_last[i];
5885 }
5886 ascq->q_first[i] = ascq->q_last[i] = NULL;
5887 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005888#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005889 ascq->q_cur_cnt[i] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005890#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005891 }
5892 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005893#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005894 {
5895 REQP reqp;
5896 for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
5897 REQTIMESTAT("asc_dequeue_list", ascq, reqp,
5898 reqp->device->id);
5899 }
5900 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005901#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005902 }
5903 if (lastpp) {
5904 *lastpp = lastp;
5905 }
5906 ASC_DBG1(3, "asc_dequeue_list: firstp 0x%lx\n", (ulong)firstp);
5907 return firstp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005908}
5909
5910/*
5911 * Remove the specified 'REQP' from the specified queue for
5912 * the specified target device. Clear the 'tidmask' bit for the
5913 * device if no more commands are left queued for it.
5914 *
5915 * 'REQPNEXT(reqp)' returns reqp's the next pointer.
5916 *
5917 * Return ASC_TRUE if the command was found and removed,
5918 * otherwise return ASC_FALSE.
5919 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005920static int asc_rmqueue(asc_queue_t *ascq, REQP reqp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005921{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005922 REQP currp, prevp;
5923 int tid;
5924 int ret = ASC_FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005925
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005926 ASC_DBG2(3, "asc_rmqueue: ascq 0x%lx, reqp 0x%lx\n",
5927 (ulong)ascq, (ulong)reqp);
5928 ASC_ASSERT(reqp != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005929
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005930 tid = REQPTID(reqp);
5931 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005932
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005933 /*
5934 * Handle the common case of 'reqp' being the first
5935 * entry on the queue.
5936 */
5937 if (reqp == ascq->q_first[tid]) {
5938 ret = ASC_TRUE;
5939 ascq->q_first[tid] = REQPNEXT(reqp);
5940 /* If the queue is now empty, clear its bit and the last pointer. */
5941 if (ascq->q_first[tid] == NULL) {
5942 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
5943 ASC_ASSERT(ascq->q_last[tid] == reqp);
5944 ascq->q_last[tid] = NULL;
5945 }
5946 } else if (ascq->q_first[tid] != NULL) {
5947 ASC_ASSERT(ascq->q_last[tid] != NULL);
5948 /*
5949 * Because the case of 'reqp' being the first entry has been
5950 * handled above and it is known the queue is not empty, if
5951 * 'reqp' is found on the queue it is guaranteed the queue will
5952 * not become empty and that 'q_first[tid]' will not be changed.
5953 *
5954 * Set 'prevp' to the first entry, 'currp' to the second entry,
5955 * and search for 'reqp'.
5956 */
5957 for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp);
5958 currp; prevp = currp, currp = REQPNEXT(currp)) {
5959 if (currp == reqp) {
5960 ret = ASC_TRUE;
5961 prevp->host_scribble =
5962 (unsigned char *)REQPNEXT(currp);
5963 reqp->host_scribble = NULL;
5964 if (ascq->q_last[tid] == reqp) {
5965 ascq->q_last[tid] = prevp;
5966 }
5967 break;
5968 }
5969 }
5970 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005971#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005972 /* Maintain request queue statistics. */
5973 if (ret == ASC_TRUE) {
5974 ascq->q_cur_cnt[tid]--;
5975 REQTIMESTAT("asc_rmqueue", ascq, reqp, tid);
5976 }
5977 ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005978#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005979 ASC_DBG2(3, "asc_rmqueue: reqp 0x%lx, ret %d\n", (ulong)reqp, ret);
5980 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005981}
5982
5983/*
5984 * Execute as many queued requests as possible for the specified queue.
5985 *
5986 * Calls asc_execute_scsi_cmnd() to execute a REQP/struct scsi_cmnd.
5987 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005988static void asc_execute_queue(asc_queue_t *ascq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005989{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005990 ADV_SCSI_BIT_ID_TYPE scan_tidmask;
5991 REQP reqp;
5992 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005993
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005994 ASC_DBG1(1, "asc_execute_queue: ascq 0x%lx\n", (ulong)ascq);
5995 /*
5996 * Execute queued commands for devices attached to
5997 * the current board in round-robin fashion.
5998 */
5999 scan_tidmask = ascq->q_tidmask;
6000 do {
6001 for (i = 0; i <= ADV_MAX_TID; i++) {
6002 if (scan_tidmask & ADV_TID_TO_TIDMASK(i)) {
6003 if ((reqp = asc_dequeue(ascq, i)) == NULL) {
6004 scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
6005 } else
6006 if (asc_execute_scsi_cmnd
6007 ((struct scsi_cmnd *)reqp)
6008 == ASC_BUSY) {
6009 scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
6010 /*
6011 * The request returned ASC_BUSY. Enqueue at the front of
6012 * target's waiting list to maintain correct ordering.
6013 */
6014 asc_enqueue(ascq, reqp, ASC_FRONT);
6015 }
6016 }
6017 }
6018 } while (scan_tidmask);
6019 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006020}
6021
6022#ifdef CONFIG_PROC_FS
6023/*
6024 * asc_prt_board_devices()
6025 *
6026 * Print driver information for devices attached to the board.
6027 *
6028 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6029 * cf. asc_prt_line().
6030 *
6031 * Return the number of characters copied into 'cp'. No more than
6032 * 'cplen' characters will be copied to 'cp'.
6033 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006034static int asc_prt_board_devices(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006035{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006036 asc_board_t *boardp;
6037 int leftlen;
6038 int totlen;
6039 int len;
6040 int chip_scsi_id;
6041 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006042
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006043 boardp = ASC_BOARDP(shost);
6044 leftlen = cplen;
6045 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006046
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006047 len = asc_prt_line(cp, leftlen,
6048 "\nDevice Information for AdvanSys SCSI Host %d:\n",
6049 shost->host_no);
6050 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006051
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006052 if (ASC_NARROW_BOARD(boardp)) {
6053 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
6054 } else {
6055 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
6056 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006057
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006058 len = asc_prt_line(cp, leftlen, "Target IDs Detected:");
6059 ASC_PRT_NEXT();
6060 for (i = 0; i <= ADV_MAX_TID; i++) {
6061 if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) {
6062 len = asc_prt_line(cp, leftlen, " %X,", i);
6063 ASC_PRT_NEXT();
6064 }
6065 }
6066 len = asc_prt_line(cp, leftlen, " (%X=Host Adapter)\n", chip_scsi_id);
6067 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006068
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006069 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006070}
6071
6072/*
6073 * Display Wide Board BIOS Information.
6074 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006075static int asc_prt_adv_bios(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006076{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006077 asc_board_t *boardp;
6078 int leftlen;
6079 int totlen;
6080 int len;
6081 ushort major, minor, letter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006082
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006083 boardp = ASC_BOARDP(shost);
6084 leftlen = cplen;
6085 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006086
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006087 len = asc_prt_line(cp, leftlen, "\nROM BIOS Version: ");
6088 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006089
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006090 /*
6091 * If the BIOS saved a valid signature, then fill in
6092 * the BIOS code segment base address.
6093 */
6094 if (boardp->bios_signature != 0x55AA) {
6095 len = asc_prt_line(cp, leftlen, "Disabled or Pre-3.1\n");
6096 ASC_PRT_NEXT();
6097 len = asc_prt_line(cp, leftlen,
6098 "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n");
6099 ASC_PRT_NEXT();
6100 len = asc_prt_line(cp, leftlen,
6101 "can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n");
6102 ASC_PRT_NEXT();
6103 } else {
6104 major = (boardp->bios_version >> 12) & 0xF;
6105 minor = (boardp->bios_version >> 8) & 0xF;
6106 letter = (boardp->bios_version & 0xFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006107
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006108 len = asc_prt_line(cp, leftlen, "%d.%d%c\n",
6109 major, minor,
6110 letter >= 26 ? '?' : letter + 'A');
6111 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006112
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006113 /*
6114 * Current available ROM BIOS release is 3.1I for UW
6115 * and 3.2I for U2W. This code doesn't differentiate
6116 * UW and U2W boards.
6117 */
6118 if (major < 3 || (major <= 3 && minor < 1) ||
6119 (major <= 3 && minor <= 1 && letter < ('I' - 'A'))) {
6120 len = asc_prt_line(cp, leftlen,
6121 "Newer version of ROM BIOS is available at the ConnectCom FTP site:\n");
6122 ASC_PRT_NEXT();
6123 len = asc_prt_line(cp, leftlen,
6124 "ftp://ftp.connectcom.net/pub\n");
6125 ASC_PRT_NEXT();
6126 }
6127 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006128
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006129 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006130}
6131
6132/*
6133 * Add serial number to information bar if signature AAh
6134 * is found in at bit 15-9 (7 bits) of word 1.
6135 *
6136 * Serial Number consists fo 12 alpha-numeric digits.
6137 *
6138 * 1 - Product type (A,B,C,D..) Word0: 15-13 (3 bits)
6139 * 2 - MFG Location (A,B,C,D..) Word0: 12-10 (3 bits)
6140 * 3-4 - Product ID (0-99) Word0: 9-0 (10 bits)
6141 * 5 - Product revision (A-J) Word0: " "
6142 *
6143 * Signature Word1: 15-9 (7 bits)
6144 * 6 - Year (0-9) Word1: 8-6 (3 bits) & Word2: 15 (1 bit)
6145 * 7-8 - Week of the year (1-52) Word1: 5-0 (6 bits)
6146 *
6147 * 9-12 - Serial Number (A001-Z999) Word2: 14-0 (15 bits)
6148 *
6149 * Note 1: Only production cards will have a serial number.
6150 *
6151 * Note 2: Signature is most significant 7 bits (0xFE).
6152 *
6153 * Returns ASC_TRUE if serial number found, otherwise returns ASC_FALSE.
6154 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006155static int asc_get_eeprom_string(ushort *serialnum, uchar *cp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006156{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006157 ushort w, num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006158
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006159 if ((serialnum[1] & 0xFE00) != ((ushort)0xAA << 8)) {
6160 return ASC_FALSE;
6161 } else {
6162 /*
6163 * First word - 6 digits.
6164 */
6165 w = serialnum[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006166
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006167 /* Product type - 1st digit. */
6168 if ((*cp = 'A' + ((w & 0xE000) >> 13)) == 'H') {
6169 /* Product type is P=Prototype */
6170 *cp += 0x8;
6171 }
6172 cp++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006173
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006174 /* Manufacturing location - 2nd digit. */
6175 *cp++ = 'A' + ((w & 0x1C00) >> 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006176
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006177 /* Product ID - 3rd, 4th digits. */
6178 num = w & 0x3FF;
6179 *cp++ = '0' + (num / 100);
6180 num %= 100;
6181 *cp++ = '0' + (num / 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006182
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006183 /* Product revision - 5th digit. */
6184 *cp++ = 'A' + (num % 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006185
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006186 /*
6187 * Second word
6188 */
6189 w = serialnum[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006190
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006191 /*
6192 * Year - 6th digit.
6193 *
6194 * If bit 15 of third word is set, then the
6195 * last digit of the year is greater than 7.
6196 */
6197 if (serialnum[2] & 0x8000) {
6198 *cp++ = '8' + ((w & 0x1C0) >> 6);
6199 } else {
6200 *cp++ = '0' + ((w & 0x1C0) >> 6);
6201 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006202
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006203 /* Week of year - 7th, 8th digits. */
6204 num = w & 0x003F;
6205 *cp++ = '0' + num / 10;
6206 num %= 10;
6207 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006208
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006209 /*
6210 * Third word
6211 */
6212 w = serialnum[2] & 0x7FFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006213
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006214 /* Serial number - 9th digit. */
6215 *cp++ = 'A' + (w / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006216
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006217 /* 10th, 11th, 12th digits. */
6218 num = w % 1000;
6219 *cp++ = '0' + num / 100;
6220 num %= 100;
6221 *cp++ = '0' + num / 10;
6222 num %= 10;
6223 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006224
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006225 *cp = '\0'; /* Null Terminate the string. */
6226 return ASC_TRUE;
6227 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006228}
6229
6230/*
6231 * asc_prt_asc_board_eeprom()
6232 *
6233 * Print board EEPROM configuration.
6234 *
6235 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6236 * cf. asc_prt_line().
6237 *
6238 * Return the number of characters copied into 'cp'. No more than
6239 * 'cplen' characters will be copied to 'cp'.
6240 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006241static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006242{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006243 asc_board_t *boardp;
6244 ASC_DVC_VAR *asc_dvc_varp;
6245 int leftlen;
6246 int totlen;
6247 int len;
6248 ASCEEP_CONFIG *ep;
6249 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006250#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006251 int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07006252#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006253 uchar serialstr[13];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006254
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006255 boardp = ASC_BOARDP(shost);
6256 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
6257 ep = &boardp->eep_config.asc_eep;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006258
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006259 leftlen = cplen;
6260 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006261
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006262 len = asc_prt_line(cp, leftlen,
6263 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
6264 shost->host_no);
6265 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006266
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006267 if (asc_get_eeprom_string((ushort *)&ep->adapter_info[0], serialstr)
6268 == ASC_TRUE) {
6269 len =
6270 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
6271 serialstr);
6272 ASC_PRT_NEXT();
6273 } else {
6274 if (ep->adapter_info[5] == 0xBB) {
6275 len = asc_prt_line(cp, leftlen,
6276 " Default Settings Used for EEPROM-less Adapter.\n");
6277 ASC_PRT_NEXT();
6278 } else {
6279 len = asc_prt_line(cp, leftlen,
6280 " Serial Number Signature Not Present.\n");
6281 ASC_PRT_NEXT();
6282 }
6283 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006284
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006285 len = asc_prt_line(cp, leftlen,
6286 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6287 ASC_EEP_GET_CHIP_ID(ep), ep->max_total_qng,
6288 ep->max_tag_qng);
6289 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006290
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006291 len = asc_prt_line(cp, leftlen,
6292 " cntl 0x%x, no_scam 0x%x\n", ep->cntl, ep->no_scam);
6293 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006294
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006295 len = asc_prt_line(cp, leftlen, " Target ID: ");
6296 ASC_PRT_NEXT();
6297 for (i = 0; i <= ASC_MAX_TID; i++) {
6298 len = asc_prt_line(cp, leftlen, " %d", i);
6299 ASC_PRT_NEXT();
6300 }
6301 len = asc_prt_line(cp, leftlen, "\n");
6302 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006303
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006304 len = asc_prt_line(cp, leftlen, " Disconnects: ");
6305 ASC_PRT_NEXT();
6306 for (i = 0; i <= ASC_MAX_TID; i++) {
6307 len = asc_prt_line(cp, leftlen, " %c",
6308 (ep->
6309 disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6310 'N');
6311 ASC_PRT_NEXT();
6312 }
6313 len = asc_prt_line(cp, leftlen, "\n");
6314 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006315
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006316 len = asc_prt_line(cp, leftlen, " Command Queuing: ");
6317 ASC_PRT_NEXT();
6318 for (i = 0; i <= ASC_MAX_TID; i++) {
6319 len = asc_prt_line(cp, leftlen, " %c",
6320 (ep->
6321 use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6322 'N');
6323 ASC_PRT_NEXT();
6324 }
6325 len = asc_prt_line(cp, leftlen, "\n");
6326 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006327
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006328 len = asc_prt_line(cp, leftlen, " Start Motor: ");
6329 ASC_PRT_NEXT();
6330 for (i = 0; i <= ASC_MAX_TID; i++) {
6331 len = asc_prt_line(cp, leftlen, " %c",
6332 (ep->
6333 start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6334 'N');
6335 ASC_PRT_NEXT();
6336 }
6337 len = asc_prt_line(cp, leftlen, "\n");
6338 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006339
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006340 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6341 ASC_PRT_NEXT();
6342 for (i = 0; i <= ASC_MAX_TID; i++) {
6343 len = asc_prt_line(cp, leftlen, " %c",
6344 (ep->
6345 init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6346 'N');
6347 ASC_PRT_NEXT();
6348 }
6349 len = asc_prt_line(cp, leftlen, "\n");
6350 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006351
6352#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006353 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
6354 len = asc_prt_line(cp, leftlen,
6355 " Host ISA DMA speed: %d MB/S\n",
6356 isa_dma_speed[ASC_EEP_GET_DMA_SPD(ep)]);
6357 ASC_PRT_NEXT();
6358 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006359#endif /* CONFIG_ISA */
6360
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006361 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006362}
6363
6364/*
6365 * asc_prt_adv_board_eeprom()
6366 *
6367 * Print board EEPROM configuration.
6368 *
6369 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6370 * cf. asc_prt_line().
6371 *
6372 * Return the number of characters copied into 'cp'. No more than
6373 * 'cplen' characters will be copied to 'cp'.
6374 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006375static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006376{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006377 asc_board_t *boardp;
6378 ADV_DVC_VAR *adv_dvc_varp;
6379 int leftlen;
6380 int totlen;
6381 int len;
6382 int i;
6383 char *termstr;
6384 uchar serialstr[13];
6385 ADVEEP_3550_CONFIG *ep_3550 = NULL;
6386 ADVEEP_38C0800_CONFIG *ep_38C0800 = NULL;
6387 ADVEEP_38C1600_CONFIG *ep_38C1600 = NULL;
6388 ushort word;
6389 ushort *wordp;
6390 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006391
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006392 boardp = ASC_BOARDP(shost);
6393 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
6394 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6395 ep_3550 = &boardp->eep_config.adv_3550_eep;
6396 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6397 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
6398 } else {
6399 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
6400 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006401
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006402 leftlen = cplen;
6403 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006404
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006405 len = asc_prt_line(cp, leftlen,
6406 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
6407 shost->host_no);
6408 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006409
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006410 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6411 wordp = &ep_3550->serial_number_word1;
6412 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6413 wordp = &ep_38C0800->serial_number_word1;
6414 } else {
6415 wordp = &ep_38C1600->serial_number_word1;
6416 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006417
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006418 if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) {
6419 len =
6420 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
6421 serialstr);
6422 ASC_PRT_NEXT();
6423 } else {
6424 len = asc_prt_line(cp, leftlen,
6425 " Serial Number Signature Not Present.\n");
6426 ASC_PRT_NEXT();
6427 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006428
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006429 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6430 len = asc_prt_line(cp, leftlen,
6431 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6432 ep_3550->adapter_scsi_id,
6433 ep_3550->max_host_qng, ep_3550->max_dvc_qng);
6434 ASC_PRT_NEXT();
6435 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6436 len = asc_prt_line(cp, leftlen,
6437 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6438 ep_38C0800->adapter_scsi_id,
6439 ep_38C0800->max_host_qng,
6440 ep_38C0800->max_dvc_qng);
6441 ASC_PRT_NEXT();
6442 } else {
6443 len = asc_prt_line(cp, leftlen,
6444 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6445 ep_38C1600->adapter_scsi_id,
6446 ep_38C1600->max_host_qng,
6447 ep_38C1600->max_dvc_qng);
6448 ASC_PRT_NEXT();
6449 }
6450 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6451 word = ep_3550->termination;
6452 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6453 word = ep_38C0800->termination_lvd;
6454 } else {
6455 word = ep_38C1600->termination_lvd;
6456 }
6457 switch (word) {
6458 case 1:
6459 termstr = "Low Off/High Off";
6460 break;
6461 case 2:
6462 termstr = "Low Off/High On";
6463 break;
6464 case 3:
6465 termstr = "Low On/High On";
6466 break;
6467 default:
6468 case 0:
6469 termstr = "Automatic";
6470 break;
6471 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006472
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006473 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6474 len = asc_prt_line(cp, leftlen,
6475 " termination: %u (%s), bios_ctrl: 0x%x\n",
6476 ep_3550->termination, termstr,
6477 ep_3550->bios_ctrl);
6478 ASC_PRT_NEXT();
6479 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6480 len = asc_prt_line(cp, leftlen,
6481 " termination: %u (%s), bios_ctrl: 0x%x\n",
6482 ep_38C0800->termination_lvd, termstr,
6483 ep_38C0800->bios_ctrl);
6484 ASC_PRT_NEXT();
6485 } else {
6486 len = asc_prt_line(cp, leftlen,
6487 " termination: %u (%s), bios_ctrl: 0x%x\n",
6488 ep_38C1600->termination_lvd, termstr,
6489 ep_38C1600->bios_ctrl);
6490 ASC_PRT_NEXT();
6491 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006492
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006493 len = asc_prt_line(cp, leftlen, " Target ID: ");
6494 ASC_PRT_NEXT();
6495 for (i = 0; i <= ADV_MAX_TID; i++) {
6496 len = asc_prt_line(cp, leftlen, " %X", i);
6497 ASC_PRT_NEXT();
6498 }
6499 len = asc_prt_line(cp, leftlen, "\n");
6500 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006501
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006502 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6503 word = ep_3550->disc_enable;
6504 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6505 word = ep_38C0800->disc_enable;
6506 } else {
6507 word = ep_38C1600->disc_enable;
6508 }
6509 len = asc_prt_line(cp, leftlen, " Disconnects: ");
6510 ASC_PRT_NEXT();
6511 for (i = 0; i <= ADV_MAX_TID; i++) {
6512 len = asc_prt_line(cp, leftlen, " %c",
6513 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6514 ASC_PRT_NEXT();
6515 }
6516 len = asc_prt_line(cp, leftlen, "\n");
6517 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006518
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006519 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6520 word = ep_3550->tagqng_able;
6521 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6522 word = ep_38C0800->tagqng_able;
6523 } else {
6524 word = ep_38C1600->tagqng_able;
6525 }
6526 len = asc_prt_line(cp, leftlen, " Command Queuing: ");
6527 ASC_PRT_NEXT();
6528 for (i = 0; i <= ADV_MAX_TID; i++) {
6529 len = asc_prt_line(cp, leftlen, " %c",
6530 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6531 ASC_PRT_NEXT();
6532 }
6533 len = asc_prt_line(cp, leftlen, "\n");
6534 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006535
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006536 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6537 word = ep_3550->start_motor;
6538 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6539 word = ep_38C0800->start_motor;
6540 } else {
6541 word = ep_38C1600->start_motor;
6542 }
6543 len = asc_prt_line(cp, leftlen, " Start Motor: ");
6544 ASC_PRT_NEXT();
6545 for (i = 0; i <= ADV_MAX_TID; i++) {
6546 len = asc_prt_line(cp, leftlen, " %c",
6547 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6548 ASC_PRT_NEXT();
6549 }
6550 len = asc_prt_line(cp, leftlen, "\n");
6551 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006552
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006553 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6554 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6555 ASC_PRT_NEXT();
6556 for (i = 0; i <= ADV_MAX_TID; i++) {
6557 len = asc_prt_line(cp, leftlen, " %c",
6558 (ep_3550->
6559 sdtr_able & ADV_TID_TO_TIDMASK(i)) ?
6560 'Y' : 'N');
6561 ASC_PRT_NEXT();
6562 }
6563 len = asc_prt_line(cp, leftlen, "\n");
6564 ASC_PRT_NEXT();
6565 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006566
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006567 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6568 len = asc_prt_line(cp, leftlen, " Ultra Transfer: ");
6569 ASC_PRT_NEXT();
6570 for (i = 0; i <= ADV_MAX_TID; i++) {
6571 len = asc_prt_line(cp, leftlen, " %c",
6572 (ep_3550->
6573 ultra_able & ADV_TID_TO_TIDMASK(i))
6574 ? 'Y' : 'N');
6575 ASC_PRT_NEXT();
6576 }
6577 len = asc_prt_line(cp, leftlen, "\n");
6578 ASC_PRT_NEXT();
6579 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006580
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006581 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6582 word = ep_3550->wdtr_able;
6583 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6584 word = ep_38C0800->wdtr_able;
6585 } else {
6586 word = ep_38C1600->wdtr_able;
6587 }
6588 len = asc_prt_line(cp, leftlen, " Wide Transfer: ");
6589 ASC_PRT_NEXT();
6590 for (i = 0; i <= ADV_MAX_TID; i++) {
6591 len = asc_prt_line(cp, leftlen, " %c",
6592 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6593 ASC_PRT_NEXT();
6594 }
6595 len = asc_prt_line(cp, leftlen, "\n");
6596 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006597
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006598 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800 ||
6599 adv_dvc_varp->chip_type == ADV_CHIP_ASC38C1600) {
6600 len = asc_prt_line(cp, leftlen,
6601 " Synchronous Transfer Speed (Mhz):\n ");
6602 ASC_PRT_NEXT();
6603 for (i = 0; i <= ADV_MAX_TID; i++) {
6604 char *speed_str;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006605
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006606 if (i == 0) {
6607 sdtr_speed = adv_dvc_varp->sdtr_speed1;
6608 } else if (i == 4) {
6609 sdtr_speed = adv_dvc_varp->sdtr_speed2;
6610 } else if (i == 8) {
6611 sdtr_speed = adv_dvc_varp->sdtr_speed3;
6612 } else if (i == 12) {
6613 sdtr_speed = adv_dvc_varp->sdtr_speed4;
6614 }
6615 switch (sdtr_speed & ADV_MAX_TID) {
6616 case 0:
6617 speed_str = "Off";
6618 break;
6619 case 1:
6620 speed_str = " 5";
6621 break;
6622 case 2:
6623 speed_str = " 10";
6624 break;
6625 case 3:
6626 speed_str = " 20";
6627 break;
6628 case 4:
6629 speed_str = " 40";
6630 break;
6631 case 5:
6632 speed_str = " 80";
6633 break;
6634 default:
6635 speed_str = "Unk";
6636 break;
6637 }
6638 len = asc_prt_line(cp, leftlen, "%X:%s ", i, speed_str);
6639 ASC_PRT_NEXT();
6640 if (i == 7) {
6641 len = asc_prt_line(cp, leftlen, "\n ");
6642 ASC_PRT_NEXT();
6643 }
6644 sdtr_speed >>= 4;
6645 }
6646 len = asc_prt_line(cp, leftlen, "\n");
6647 ASC_PRT_NEXT();
6648 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006649
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006650 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006651}
6652
6653/*
6654 * asc_prt_driver_conf()
6655 *
6656 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6657 * cf. asc_prt_line().
6658 *
6659 * Return the number of characters copied into 'cp'. No more than
6660 * 'cplen' characters will be copied to 'cp'.
6661 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006662static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006663{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006664 asc_board_t *boardp;
6665 int leftlen;
6666 int totlen;
6667 int len;
6668 int chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006669
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006670 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006671
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006672 leftlen = cplen;
6673 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006674
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006675 len = asc_prt_line(cp, leftlen,
6676 "\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n",
6677 shost->host_no);
6678 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006679
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006680 len = asc_prt_line(cp, leftlen,
6681 " host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n",
6682 shost->host_busy, shost->last_reset, shost->max_id,
6683 shost->max_lun, shost->max_channel);
6684 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006685
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006686 len = asc_prt_line(cp, leftlen,
6687 " unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
6688 shost->unique_id, shost->can_queue, shost->this_id,
6689 shost->sg_tablesize, shost->cmd_per_lun);
6690 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006691
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006692 len = asc_prt_line(cp, leftlen,
6693 " unchecked_isa_dma %d, use_clustering %d\n",
6694 shost->unchecked_isa_dma, shost->use_clustering);
6695 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006696
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006697 len = asc_prt_line(cp, leftlen,
6698 " flags 0x%x, last_reset 0x%x, jiffies 0x%x, asc_n_io_port 0x%x\n",
6699 boardp->flags, boardp->last_reset, jiffies,
6700 boardp->asc_n_io_port);
6701 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006702
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006703 /* 'shost->n_io_port' may be truncated because it is only one byte. */
6704 len = asc_prt_line(cp, leftlen,
6705 " io_port 0x%x, n_io_port 0x%x\n",
6706 shost->io_port, shost->n_io_port);
6707 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006708
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006709 if (ASC_NARROW_BOARD(boardp)) {
6710 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
6711 } else {
6712 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
6713 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006714
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006715 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006716}
6717
6718/*
6719 * asc_prt_asc_board_info()
6720 *
6721 * Print dynamic board configuration information.
6722 *
6723 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6724 * cf. asc_prt_line().
6725 *
6726 * Return the number of characters copied into 'cp'. No more than
6727 * 'cplen' characters will be copied to 'cp'.
6728 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006729static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006730{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006731 asc_board_t *boardp;
6732 int chip_scsi_id;
6733 int leftlen;
6734 int totlen;
6735 int len;
6736 ASC_DVC_VAR *v;
6737 ASC_DVC_CFG *c;
6738 int i;
6739 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006740
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006741 boardp = ASC_BOARDP(shost);
6742 v = &boardp->dvc_var.asc_dvc_var;
6743 c = &boardp->dvc_cfg.asc_dvc_cfg;
6744 chip_scsi_id = c->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006745
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006746 leftlen = cplen;
6747 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006748
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006749 len = asc_prt_line(cp, leftlen,
6750 "\nAsc Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
6751 shost->host_no);
6752 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006753
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006754 len = asc_prt_line(cp, leftlen,
6755 " chip_version %u, lib_version 0x%x, lib_serial_no %u, mcode_date 0x%x\n",
6756 c->chip_version, c->lib_version, c->lib_serial_no,
6757 c->mcode_date);
6758 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006759
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006760 len = asc_prt_line(cp, leftlen,
6761 " mcode_version 0x%x, err_code %u\n",
6762 c->mcode_version, v->err_code);
6763 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006764
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006765 /* Current number of commands waiting for the host. */
6766 len = asc_prt_line(cp, leftlen,
6767 " Total Command Pending: %d\n", v->cur_total_qng);
6768 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006769
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006770 len = asc_prt_line(cp, leftlen, " Command Queuing:");
6771 ASC_PRT_NEXT();
6772 for (i = 0; i <= ASC_MAX_TID; i++) {
6773 if ((chip_scsi_id == i) ||
6774 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6775 continue;
6776 }
6777 len = asc_prt_line(cp, leftlen, " %X:%c",
6778 i,
6779 (v->
6780 use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ?
6781 'Y' : 'N');
6782 ASC_PRT_NEXT();
6783 }
6784 len = asc_prt_line(cp, leftlen, "\n");
6785 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006786
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006787 /* Current number of commands waiting for a device. */
6788 len = asc_prt_line(cp, leftlen, " Command Queue Pending:");
6789 ASC_PRT_NEXT();
6790 for (i = 0; i <= ASC_MAX_TID; i++) {
6791 if ((chip_scsi_id == i) ||
6792 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6793 continue;
6794 }
6795 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->cur_dvc_qng[i]);
6796 ASC_PRT_NEXT();
6797 }
6798 len = asc_prt_line(cp, leftlen, "\n");
6799 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006800
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006801 /* Current limit on number of commands that can be sent to a device. */
6802 len = asc_prt_line(cp, leftlen, " Command Queue Limit:");
6803 ASC_PRT_NEXT();
6804 for (i = 0; i <= ASC_MAX_TID; i++) {
6805 if ((chip_scsi_id == i) ||
6806 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6807 continue;
6808 }
6809 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->max_dvc_qng[i]);
6810 ASC_PRT_NEXT();
6811 }
6812 len = asc_prt_line(cp, leftlen, "\n");
6813 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006814
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006815 /* Indicate whether the device has returned queue full status. */
6816 len = asc_prt_line(cp, leftlen, " Command Queue Full:");
6817 ASC_PRT_NEXT();
6818 for (i = 0; i <= ASC_MAX_TID; i++) {
6819 if ((chip_scsi_id == i) ||
6820 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6821 continue;
6822 }
6823 if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) {
6824 len = asc_prt_line(cp, leftlen, " %X:Y-%d",
6825 i, boardp->queue_full_cnt[i]);
6826 } else {
6827 len = asc_prt_line(cp, leftlen, " %X:N", i);
6828 }
6829 ASC_PRT_NEXT();
6830 }
6831 len = asc_prt_line(cp, leftlen, "\n");
6832 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006833
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006834 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6835 ASC_PRT_NEXT();
6836 for (i = 0; i <= ASC_MAX_TID; i++) {
6837 if ((chip_scsi_id == i) ||
6838 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6839 continue;
6840 }
6841 len = asc_prt_line(cp, leftlen, " %X:%c",
6842 i,
6843 (v->
6844 sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6845 'N');
6846 ASC_PRT_NEXT();
6847 }
6848 len = asc_prt_line(cp, leftlen, "\n");
6849 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006850
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006851 for (i = 0; i <= ASC_MAX_TID; i++) {
6852 uchar syn_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006853
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006854 if ((chip_scsi_id == i) ||
6855 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
6856 ((v->init_sdtr & ADV_TID_TO_TIDMASK(i)) == 0)) {
6857 continue;
6858 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006859
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006860 len = asc_prt_line(cp, leftlen, " %X:", i);
6861 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006862
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006863 if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0) {
6864 len = asc_prt_line(cp, leftlen, " Asynchronous");
6865 ASC_PRT_NEXT();
6866 } else {
6867 syn_period_ix =
6868 (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index -
6869 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006870
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006871 len = asc_prt_line(cp, leftlen,
6872 " Transfer Period Factor: %d (%d.%d Mhz),",
6873 v->sdtr_period_tbl[syn_period_ix],
6874 250 /
6875 v->sdtr_period_tbl[syn_period_ix],
6876 ASC_TENTHS(250,
6877 v->
6878 sdtr_period_tbl
6879 [syn_period_ix]));
6880 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006881
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006882 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
6883 boardp->
6884 sdtr_data[i] & ASC_SYN_MAX_OFFSET);
6885 ASC_PRT_NEXT();
6886 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006887
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006888 if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
6889 len = asc_prt_line(cp, leftlen, "*\n");
6890 renegotiate = 1;
6891 } else {
6892 len = asc_prt_line(cp, leftlen, "\n");
6893 }
6894 ASC_PRT_NEXT();
6895 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006896
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006897 if (renegotiate) {
6898 len = asc_prt_line(cp, leftlen,
6899 " * = Re-negotiation pending before next command.\n");
6900 ASC_PRT_NEXT();
6901 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006902
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006903 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006904}
6905
6906/*
6907 * asc_prt_adv_board_info()
6908 *
6909 * Print dynamic board configuration information.
6910 *
6911 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6912 * cf. asc_prt_line().
6913 *
6914 * Return the number of characters copied into 'cp'. No more than
6915 * 'cplen' characters will be copied to 'cp'.
6916 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006917static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006918{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006919 asc_board_t *boardp;
6920 int leftlen;
6921 int totlen;
6922 int len;
6923 int i;
6924 ADV_DVC_VAR *v;
6925 ADV_DVC_CFG *c;
6926 AdvPortAddr iop_base;
6927 ushort chip_scsi_id;
6928 ushort lramword;
6929 uchar lrambyte;
6930 ushort tagqng_able;
6931 ushort sdtr_able, wdtr_able;
6932 ushort wdtr_done, sdtr_done;
6933 ushort period = 0;
6934 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006935
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006936 boardp = ASC_BOARDP(shost);
6937 v = &boardp->dvc_var.adv_dvc_var;
6938 c = &boardp->dvc_cfg.adv_dvc_cfg;
6939 iop_base = v->iop_base;
6940 chip_scsi_id = v->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006941
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006942 leftlen = cplen;
6943 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006944
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006945 len = asc_prt_line(cp, leftlen,
6946 "\nAdv Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
6947 shost->host_no);
6948 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006949
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006950 len = asc_prt_line(cp, leftlen,
6951 " iop_base 0x%lx, cable_detect: %X, err_code %u\n",
6952 v->iop_base,
6953 AdvReadWordRegister(iop_base,
6954 IOPW_SCSI_CFG1) & CABLE_DETECT,
6955 v->err_code);
6956 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006957
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006958 len = asc_prt_line(cp, leftlen,
6959 " chip_version %u, lib_version 0x%x, mcode_date 0x%x, mcode_version 0x%x\n",
6960 c->chip_version, c->lib_version, c->mcode_date,
6961 c->mcode_version);
6962 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006963
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006964 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
6965 len = asc_prt_line(cp, leftlen, " Queuing Enabled:");
6966 ASC_PRT_NEXT();
6967 for (i = 0; i <= ADV_MAX_TID; i++) {
6968 if ((chip_scsi_id == i) ||
6969 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6970 continue;
6971 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006972
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006973 len = asc_prt_line(cp, leftlen, " %X:%c",
6974 i,
6975 (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6976 'N');
6977 ASC_PRT_NEXT();
6978 }
6979 len = asc_prt_line(cp, leftlen, "\n");
6980 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006981
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006982 len = asc_prt_line(cp, leftlen, " Queue Limit:");
6983 ASC_PRT_NEXT();
6984 for (i = 0; i <= ADV_MAX_TID; i++) {
6985 if ((chip_scsi_id == i) ||
6986 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6987 continue;
6988 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006989
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006990 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + i,
6991 lrambyte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006992
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006993 len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
6994 ASC_PRT_NEXT();
6995 }
6996 len = asc_prt_line(cp, leftlen, "\n");
6997 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006998
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006999 len = asc_prt_line(cp, leftlen, " Command Pending:");
7000 ASC_PRT_NEXT();
7001 for (i = 0; i <= ADV_MAX_TID; i++) {
7002 if ((chip_scsi_id == i) ||
7003 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7004 continue;
7005 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007006
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007007 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_QUEUED_CMD + i,
7008 lrambyte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007009
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007010 len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
7011 ASC_PRT_NEXT();
7012 }
7013 len = asc_prt_line(cp, leftlen, "\n");
7014 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007015
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007016 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
7017 len = asc_prt_line(cp, leftlen, " Wide Enabled:");
7018 ASC_PRT_NEXT();
7019 for (i = 0; i <= ADV_MAX_TID; i++) {
7020 if ((chip_scsi_id == i) ||
7021 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7022 continue;
7023 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007024
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007025 len = asc_prt_line(cp, leftlen, " %X:%c",
7026 i,
7027 (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
7028 'N');
7029 ASC_PRT_NEXT();
7030 }
7031 len = asc_prt_line(cp, leftlen, "\n");
7032 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007033
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007034 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done);
7035 len = asc_prt_line(cp, leftlen, " Transfer Bit Width:");
7036 ASC_PRT_NEXT();
7037 for (i = 0; i <= ADV_MAX_TID; i++) {
7038 if ((chip_scsi_id == i) ||
7039 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7040 continue;
7041 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007042
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007043 AdvReadWordLram(iop_base,
7044 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
7045 lramword);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007046
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007047 len = asc_prt_line(cp, leftlen, " %X:%d",
7048 i, (lramword & 0x8000) ? 16 : 8);
7049 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007050
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007051 if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) &&
7052 (wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
7053 len = asc_prt_line(cp, leftlen, "*");
7054 ASC_PRT_NEXT();
7055 renegotiate = 1;
7056 }
7057 }
7058 len = asc_prt_line(cp, leftlen, "\n");
7059 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007060
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007061 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
7062 len = asc_prt_line(cp, leftlen, " Synchronous Enabled:");
7063 ASC_PRT_NEXT();
7064 for (i = 0; i <= ADV_MAX_TID; i++) {
7065 if ((chip_scsi_id == i) ||
7066 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7067 continue;
7068 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007069
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007070 len = asc_prt_line(cp, leftlen, " %X:%c",
7071 i,
7072 (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
7073 'N');
7074 ASC_PRT_NEXT();
7075 }
7076 len = asc_prt_line(cp, leftlen, "\n");
7077 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007078
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007079 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done);
7080 for (i = 0; i <= ADV_MAX_TID; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007081
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007082 AdvReadWordLram(iop_base,
7083 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
7084 lramword);
7085 lramword &= ~0x8000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007086
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007087 if ((chip_scsi_id == i) ||
7088 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
7089 ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0)) {
7090 continue;
7091 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007092
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007093 len = asc_prt_line(cp, leftlen, " %X:", i);
7094 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007095
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007096 if ((lramword & 0x1F) == 0) { /* Check for REQ/ACK Offset 0. */
7097 len = asc_prt_line(cp, leftlen, " Asynchronous");
7098 ASC_PRT_NEXT();
7099 } else {
7100 len =
7101 asc_prt_line(cp, leftlen,
7102 " Transfer Period Factor: ");
7103 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007104
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007105 if ((lramword & 0x1F00) == 0x1100) { /* 80 Mhz */
7106 len =
7107 asc_prt_line(cp, leftlen, "9 (80.0 Mhz),");
7108 ASC_PRT_NEXT();
7109 } else if ((lramword & 0x1F00) == 0x1000) { /* 40 Mhz */
7110 len =
7111 asc_prt_line(cp, leftlen, "10 (40.0 Mhz),");
7112 ASC_PRT_NEXT();
7113 } else { /* 20 Mhz or below. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007114
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007115 period = (((lramword >> 8) * 25) + 50) / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007116
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007117 if (period == 0) { /* Should never happen. */
7118 len =
7119 asc_prt_line(cp, leftlen,
7120 "%d (? Mhz), ");
7121 ASC_PRT_NEXT();
7122 } else {
7123 len = asc_prt_line(cp, leftlen,
7124 "%d (%d.%d Mhz),",
7125 period, 250 / period,
7126 ASC_TENTHS(250,
7127 period));
7128 ASC_PRT_NEXT();
7129 }
7130 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007131
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007132 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
7133 lramword & 0x1F);
7134 ASC_PRT_NEXT();
7135 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007136
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007137 if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
7138 len = asc_prt_line(cp, leftlen, "*\n");
7139 renegotiate = 1;
7140 } else {
7141 len = asc_prt_line(cp, leftlen, "\n");
7142 }
7143 ASC_PRT_NEXT();
7144 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007145
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007146 if (renegotiate) {
7147 len = asc_prt_line(cp, leftlen,
7148 " * = Re-negotiation pending before next command.\n");
7149 ASC_PRT_NEXT();
7150 }
7151
7152 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007153}
7154
7155/*
7156 * asc_proc_copy()
7157 *
7158 * Copy proc information to a read buffer taking into account the current
7159 * read offset in the file and the remaining space in the read buffer.
7160 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007161static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07007162asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007163 char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007164{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007165 int cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007166
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007167 ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n",
7168 (unsigned)offset, (unsigned)advoffset, cplen);
7169 if (offset <= advoffset) {
7170 /* Read offset below current offset, copy everything. */
7171 cnt = min(cplen, leftlen);
7172 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
7173 (ulong)curbuf, (ulong)cp, cnt);
7174 memcpy(curbuf, cp, cnt);
7175 } else if (offset < advoffset + cplen) {
7176 /* Read offset within current range, partial copy. */
7177 cnt = (advoffset + cplen) - offset;
7178 cp = (cp + cplen) - cnt;
7179 cnt = min(cnt, leftlen);
7180 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
7181 (ulong)curbuf, (ulong)cp, cnt);
7182 memcpy(curbuf, cp, cnt);
7183 }
7184 return cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007185}
7186
7187/*
7188 * asc_prt_line()
7189 *
7190 * If 'cp' is NULL print to the console, otherwise print to a buffer.
7191 *
7192 * Return 0 if printing to the console, otherwise return the number of
7193 * bytes written to the buffer.
7194 *
7195 * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack
7196 * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes.
7197 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007198static int asc_prt_line(char *buf, int buflen, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007199{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007200 va_list args;
7201 int ret;
7202 char s[ASC_PRTLINE_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07007203
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007204 va_start(args, fmt);
7205 ret = vsprintf(s, fmt, args);
7206 ASC_ASSERT(ret < ASC_PRTLINE_SIZE);
7207 if (buf == NULL) {
7208 (void)printk(s);
7209 ret = 0;
7210 } else {
7211 ret = min(buflen, ret);
7212 memcpy(buf, s, ret);
7213 }
7214 va_end(args);
7215 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007216}
7217#endif /* CONFIG_PROC_FS */
7218
Linus Torvalds1da177e2005-04-16 15:20:36 -07007219/*
7220 * --- Functions Required by the Asc Library
7221 */
7222
7223/*
7224 * Delay for 'n' milliseconds. Don't use the 'jiffies'
7225 * global variable which is incremented once every 5 ms
7226 * from a timer interrupt, because this function may be
7227 * called when interrupts are disabled.
7228 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007229static void DvcSleepMilliSecond(ADV_DCNT n)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007230{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007231 ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", (ulong)n);
7232 mdelay(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007233}
7234
7235/*
7236 * Currently and inline noop but leave as a placeholder.
7237 * Leave DvcEnterCritical() as a noop placeholder.
7238 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007239static inline ulong DvcEnterCritical(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007240{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007241 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007242}
7243
7244/*
7245 * Critical sections are all protected by the board spinlock.
7246 * Leave DvcLeaveCritical() as a noop placeholder.
7247 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007248static inline void DvcLeaveCritical(ulong flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007249{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007250 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007251}
7252
7253/*
7254 * void
7255 * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
7256 *
7257 * Calling/Exit State:
7258 * none
7259 *
7260 * Description:
7261 * Output an ASC_SCSI_Q structure to the chip
7262 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007263static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07007264DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
7265{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007266 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007267
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007268 ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words);
7269 AscSetChipLramAddr(iop_base, s_addr);
7270 for (i = 0; i < 2 * words; i += 2) {
7271 if (i == 4 || i == 20) {
7272 continue;
7273 }
7274 outpw(iop_base + IOP_RAM_DATA,
7275 ((ushort)outbuf[i + 1] << 8) | outbuf[i]);
7276 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007277}
7278
7279/*
7280 * void
7281 * DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
7282 *
7283 * Calling/Exit State:
7284 * none
7285 *
7286 * Description:
7287 * Input an ASC_QDONE_INFO structure from the chip
7288 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007289static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07007290DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
7291{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007292 int i;
7293 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007294
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007295 AscSetChipLramAddr(iop_base, s_addr);
7296 for (i = 0; i < 2 * words; i += 2) {
7297 if (i == 10) {
7298 continue;
7299 }
7300 word = inpw(iop_base + IOP_RAM_DATA);
7301 inbuf[i] = word & 0xff;
7302 inbuf[i + 1] = (word >> 8) & 0xff;
7303 }
7304 ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007305}
7306
7307/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07007308 * Return the BIOS address of the adapter at the specified
7309 * I/O port and with the specified bus type.
7310 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007311static unsigned short __devinit
7312AscGetChipBiosAddress(PortAddr iop_base, unsigned short bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007313{
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007314 unsigned short cfg_lsw;
7315 unsigned short bios_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007316
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007317 /*
7318 * The PCI BIOS is re-located by the motherboard BIOS. Because
7319 * of this the driver can not determine where a PCI BIOS is
7320 * loaded and executes.
7321 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007322 if (bus_type & ASC_IS_PCI)
7323 return 0;
7324
Linus Torvalds1da177e2005-04-16 15:20:36 -07007325#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007326 if ((bus_type & ASC_IS_EISA) != 0) {
7327 cfg_lsw = AscGetEisaChipCfg(iop_base);
7328 cfg_lsw &= 0x000F;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007329 bios_addr = ASC_BIOS_MIN_ADDR + cfg_lsw * ASC_BIOS_BANK_SIZE;
7330 return bios_addr;
7331 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007332#endif /* CONFIG_ISA */
7333
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007334 cfg_lsw = AscGetChipCfgLsw(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007335
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007336 /*
7337 * ISA PnP uses the top bit as the 32K BIOS flag
7338 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007339 if (bus_type == ASC_IS_ISAPNP)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007340 cfg_lsw &= 0x7FFF;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007341 bios_addr = ASC_BIOS_MIN_ADDR + (cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE;
7342 return bios_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007343}
7344
Linus Torvalds1da177e2005-04-16 15:20:36 -07007345/*
7346 * --- Functions Required by the Adv Library
7347 */
7348
7349/*
7350 * DvcGetPhyAddr()
7351 *
7352 * Return the physical address of 'vaddr' and set '*lenp' to the
7353 * number of physically contiguous bytes that follow 'vaddr'.
7354 * 'flag' indicates the type of structure whose physical address
7355 * is being translated.
7356 *
7357 * Note: Because Linux currently doesn't page the kernel and all
7358 * kernel buffers are physically contiguous, leave '*lenp' unchanged.
7359 */
7360ADV_PADDR
7361DvcGetPhyAddr(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007362 uchar *vaddr, ADV_SDCNT *lenp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007363{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007364 ADV_PADDR paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007365
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007366 paddr = virt_to_bus(vaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007367
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007368 ASC_DBG4(4,
7369 "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n",
7370 (ulong)vaddr, (ulong)lenp, (ulong)*((ulong *)lenp),
7371 (ulong)paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007372
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007373 return paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007374}
7375
7376/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07007377 * --- Tracing and Debugging Functions
7378 */
7379
7380#ifdef ADVANSYS_STATS
7381#ifdef CONFIG_PROC_FS
7382/*
7383 * asc_prt_board_stats()
7384 *
7385 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
7386 * cf. asc_prt_line().
7387 *
7388 * Return the number of characters copied into 'cp'. No more than
7389 * 'cplen' characters will be copied to 'cp'.
7390 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007391static int asc_prt_board_stats(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007392{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007393 int leftlen;
7394 int totlen;
7395 int len;
7396 struct asc_stats *s;
7397 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007398
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007399 leftlen = cplen;
7400 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007401
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007402 boardp = ASC_BOARDP(shost);
7403 s = &boardp->asc_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007404
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007405 len = asc_prt_line(cp, leftlen,
7406 "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n",
7407 shost->host_no);
7408 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007409
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007410 len = asc_prt_line(cp, leftlen,
7411 " queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n",
7412 s->queuecommand, s->reset, s->biosparam,
7413 s->interrupt);
7414 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007415
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007416 len = asc_prt_line(cp, leftlen,
7417 " callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n",
7418 s->callback, s->done, s->build_error,
7419 s->adv_build_noreq, s->adv_build_nosg);
7420 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007421
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007422 len = asc_prt_line(cp, leftlen,
7423 " exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n",
7424 s->exe_noerror, s->exe_busy, s->exe_error,
7425 s->exe_unknown);
7426 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007427
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007428 /*
7429 * Display data transfer statistics.
7430 */
7431 if (s->cont_cnt > 0) {
7432 len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt);
7433 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007434
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007435 len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ",
7436 s->cont_xfer / 2,
7437 ASC_TENTHS(s->cont_xfer, 2));
7438 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007439
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007440 /* Contiguous transfer average size */
7441 len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kb\n",
7442 (s->cont_xfer / 2) / s->cont_cnt,
7443 ASC_TENTHS((s->cont_xfer / 2), s->cont_cnt));
7444 ASC_PRT_NEXT();
7445 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007446
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007447 if (s->sg_cnt > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007448
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007449 len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ",
7450 s->sg_cnt, s->sg_elem);
7451 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007452
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007453 len = asc_prt_line(cp, leftlen, "sg_xfer %lu.%01lu kb\n",
7454 s->sg_xfer / 2, ASC_TENTHS(s->sg_xfer, 2));
7455 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007456
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007457 /* Scatter gather transfer statistics */
7458 len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ",
7459 s->sg_elem / s->sg_cnt,
7460 ASC_TENTHS(s->sg_elem, s->sg_cnt));
7461 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007462
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007463 len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ",
7464 (s->sg_xfer / 2) / s->sg_elem,
7465 ASC_TENTHS((s->sg_xfer / 2), s->sg_elem));
7466 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007467
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007468 len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n",
7469 (s->sg_xfer / 2) / s->sg_cnt,
7470 ASC_TENTHS((s->sg_xfer / 2), s->sg_cnt));
7471 ASC_PRT_NEXT();
7472 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007473
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007474 /*
7475 * Display request queuing statistics.
7476 */
7477 len = asc_prt_line(cp, leftlen,
7478 " Active and Waiting Request Queues (Time Unit: %d HZ):\n",
7479 HZ);
7480 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007481
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007482 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007483}
7484
7485/*
7486 * asc_prt_target_stats()
7487 *
7488 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
7489 * cf. asc_prt_line().
7490 *
7491 * This is separated from asc_prt_board_stats because a full set
7492 * of targets will overflow ASC_PRTBUF_SIZE.
7493 *
7494 * Return the number of characters copied into 'cp'. No more than
7495 * 'cplen' characters will be copied to 'cp'.
7496 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007497static int
7498asc_prt_target_stats(struct Scsi_Host *shost, int tgt_id, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007499{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007500 int leftlen;
7501 int totlen;
7502 int len;
7503 struct asc_stats *s;
7504 ushort chip_scsi_id;
7505 asc_board_t *boardp;
7506 asc_queue_t *active;
7507 asc_queue_t *waiting;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007508
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007509 leftlen = cplen;
7510 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007511
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007512 boardp = ASC_BOARDP(shost);
7513 s = &boardp->asc_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007514
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007515 active = &ASC_BOARDP(shost)->active;
7516 waiting = &ASC_BOARDP(shost)->waiting;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007517
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007518 if (ASC_NARROW_BOARD(boardp)) {
7519 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
7520 } else {
7521 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
7522 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007523
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007524 if ((chip_scsi_id == tgt_id) ||
7525 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(tgt_id)) == 0)) {
7526 return 0;
7527 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007528
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007529 do {
7530 if (active->q_tot_cnt[tgt_id] > 0
7531 || waiting->q_tot_cnt[tgt_id] > 0) {
7532 len = asc_prt_line(cp, leftlen, " target %d\n", tgt_id);
7533 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007534
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007535 len = asc_prt_line(cp, leftlen,
7536 " active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n",
7537 active->q_cur_cnt[tgt_id],
7538 active->q_max_cnt[tgt_id],
7539 active->q_tot_cnt[tgt_id],
7540 active->q_min_tim[tgt_id],
7541 active->q_max_tim[tgt_id],
7542 (active->q_tot_cnt[tgt_id] ==
7543 0) ? 0 : (active->
7544 q_tot_tim[tgt_id] /
7545 active->
7546 q_tot_cnt[tgt_id]),
7547 (active->q_tot_cnt[tgt_id] ==
7548 0) ? 0 : ASC_TENTHS(active->
7549 q_tot_tim
7550 [tgt_id],
7551 active->
7552 q_tot_cnt
7553 [tgt_id]));
7554 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007555
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007556 len = asc_prt_line(cp, leftlen,
7557 " waiting: cnt [cur %d, max %d, tot %u], time [min %u, max %u, avg %lu.%01lu]\n",
7558 waiting->q_cur_cnt[tgt_id],
7559 waiting->q_max_cnt[tgt_id],
7560 waiting->q_tot_cnt[tgt_id],
7561 waiting->q_min_tim[tgt_id],
7562 waiting->q_max_tim[tgt_id],
7563 (waiting->q_tot_cnt[tgt_id] ==
7564 0) ? 0 : (waiting->
7565 q_tot_tim[tgt_id] /
7566 waiting->
7567 q_tot_cnt[tgt_id]),
7568 (waiting->q_tot_cnt[tgt_id] ==
7569 0) ? 0 : ASC_TENTHS(waiting->
7570 q_tot_tim
7571 [tgt_id],
7572 waiting->
7573 q_tot_cnt
7574 [tgt_id]));
7575 ASC_PRT_NEXT();
7576 }
7577 } while (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007578
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007579 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007580}
7581#endif /* CONFIG_PROC_FS */
7582#endif /* ADVANSYS_STATS */
7583
7584#ifdef ADVANSYS_DEBUG
7585/*
7586 * asc_prt_scsi_host()
7587 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007588static void asc_prt_scsi_host(struct Scsi_Host *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007589{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007590 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007591
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007592 boardp = ASC_BOARDP(s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007593
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007594 printk("Scsi_Host at addr 0x%lx\n", (ulong)s);
7595 printk(" host_busy %u, host_no %d, last_reset %d,\n",
7596 s->host_busy, s->host_no, (unsigned)s->last_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007597
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007598 printk(" base 0x%lx, io_port 0x%lx, n_io_port %u, irq 0x%x,\n",
7599 (ulong)s->base, (ulong)s->io_port, s->n_io_port, s->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007600
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007601 printk(" dma_channel %d, this_id %d, can_queue %d,\n",
7602 s->dma_channel, s->this_id, s->can_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007603
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007604 printk(" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
7605 s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007606
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007607 if (ASC_NARROW_BOARD(boardp)) {
7608 asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var);
7609 asc_prt_asc_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.asc_dvc_cfg);
7610 } else {
7611 asc_prt_adv_dvc_var(&ASC_BOARDP(s)->dvc_var.adv_dvc_var);
7612 asc_prt_adv_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.adv_dvc_cfg);
7613 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007614}
7615
7616/*
7617 * asc_prt_scsi_cmnd()
7618 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007619static void asc_prt_scsi_cmnd(struct scsi_cmnd *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007620{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007621 printk("struct scsi_cmnd at addr 0x%lx\n", (ulong)s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007622
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007623 printk(" host 0x%lx, device 0x%lx, target %u, lun %u, channel %u,\n",
7624 (ulong)s->device->host, (ulong)s->device, s->device->id,
7625 s->device->lun, s->device->channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007626
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007627 asc_prt_hex(" CDB", s->cmnd, s->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007628
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007629 printk("sc_data_direction %u, resid %d\n",
7630 s->sc_data_direction, s->resid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007631
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007632 printk(" use_sg %u, sglist_len %u\n", s->use_sg, s->sglist_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007633
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007634 printk(" serial_number 0x%x, retries %d, allowed %d\n",
7635 (unsigned)s->serial_number, s->retries, s->allowed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007636
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007637 printk(" timeout_per_command %d\n", s->timeout_per_command);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007638
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007639 printk(" scsi_done 0x%p, done 0x%p, host_scribble 0x%p, result 0x%x\n",
7640 s->scsi_done, s->done, s->host_scribble, s->result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007641
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007642 printk(" tag %u, pid %u\n", (unsigned)s->tag, (unsigned)s->pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007643}
7644
7645/*
7646 * asc_prt_asc_dvc_var()
7647 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007648static void asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007649{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007650 printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007651
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007652 printk(" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl "
7653 "%d,\n", h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007654
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007655 printk(" bus_type %d, isr_callback 0x%p, exe_callback 0x%p, "
7656 "init_sdtr 0x%x,\n", h->bus_type, h->isr_callback,
7657 h->exe_callback, (unsigned)h->init_sdtr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007658
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007659 printk(" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, "
7660 "chip_no 0x%x,\n", (unsigned)h->sdtr_done,
7661 (unsigned)h->use_tagged_qng, (unsigned)h->unit_not_ready,
7662 (unsigned)h->chip_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007663
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007664 printk(" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait "
7665 "%u,\n", (unsigned)h->queue_full_or_busy,
7666 (unsigned)h->start_motor, (unsigned)h->scsi_reset_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007667
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007668 printk(" is_in_int %u, max_total_qng %u, cur_total_qng %u, "
7669 "in_critical_cnt %u,\n", (unsigned)h->is_in_int,
7670 (unsigned)h->max_total_qng, (unsigned)h->cur_total_qng,
7671 (unsigned)h->in_critical_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007672
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007673 printk(" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, "
7674 "pci_fix_asyn_xfer 0x%x,\n", (unsigned)h->last_q_shortage,
7675 (unsigned)h->init_state, (unsigned)h->no_scam,
7676 (unsigned)h->pci_fix_asyn_xfer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007677
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007678 printk(" cfg 0x%lx, irq_no 0x%x\n", (ulong)h->cfg, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007679}
7680
7681/*
7682 * asc_prt_asc_dvc_cfg()
7683 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007684static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007685{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007686 printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007687
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007688 printk(" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n",
7689 h->can_tagged_qng, h->cmd_qng_enabled);
7690 printk(" disc_enable 0x%x, sdtr_enable 0x%x,\n",
7691 h->disc_enable, h->sdtr_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007692
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007693 printk
7694 (" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n",
7695 h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel,
7696 h->chip_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007697
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007698 printk
7699 (" pci_device_id %d, lib_serial_no %u, lib_version %u, mcode_date 0x%x,\n",
7700 to_pci_dev(h->dev)->device, h->lib_serial_no, h->lib_version,
7701 h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007702
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007703 printk(" mcode_version %d, overrun_buf 0x%lx\n",
7704 h->mcode_version, (ulong)h->overrun_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007705}
7706
7707/*
7708 * asc_prt_asc_scsi_q()
7709 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007710static void asc_prt_asc_scsi_q(ASC_SCSI_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007711{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007712 ASC_SG_HEAD *sgp;
7713 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007714
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007715 printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007716
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007717 printk
7718 (" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n",
7719 q->q2.target_ix, q->q1.target_lun, (ulong)q->q2.srb_ptr,
7720 q->q2.tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007721
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007722 printk
7723 (" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
7724 (ulong)le32_to_cpu(q->q1.data_addr),
7725 (ulong)le32_to_cpu(q->q1.data_cnt),
7726 (ulong)le32_to_cpu(q->q1.sense_addr), q->q1.sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007727
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007728 printk(" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n",
7729 (ulong)q->cdbptr, q->q2.cdb_len,
7730 (ulong)q->sg_head, q->q1.sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007731
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007732 if (q->sg_head) {
7733 sgp = q->sg_head;
7734 printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong)sgp);
7735 printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt,
7736 sgp->queue_cnt);
7737 for (i = 0; i < sgp->entry_cnt; i++) {
7738 printk(" [%u]: addr 0x%lx, bytes %lu\n",
7739 i, (ulong)le32_to_cpu(sgp->sg_list[i].addr),
7740 (ulong)le32_to_cpu(sgp->sg_list[i].bytes));
7741 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007742
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007743 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007744}
7745
7746/*
7747 * asc_prt_asc_qdone_info()
7748 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007749static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007750{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007751 printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong)q);
7752 printk(" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n",
7753 (ulong)q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
7754 q->d2.tag_code);
7755 printk
7756 (" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n",
7757 q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007758}
7759
7760/*
7761 * asc_prt_adv_dvc_var()
7762 *
7763 * Display an ADV_DVC_VAR structure.
7764 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007765static void asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007766{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007767 printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007768
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007769 printk(" iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n",
7770 (ulong)h->iop_base, h->err_code, (unsigned)h->ultra_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007771
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007772 printk(" isr_callback 0x%lx, sdtr_able 0x%x, wdtr_able 0x%x\n",
7773 (ulong)h->isr_callback, (unsigned)h->sdtr_able,
7774 (unsigned)h->wdtr_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007775
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007776 printk(" start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n",
7777 (unsigned)h->start_motor,
7778 (unsigned)h->scsi_reset_wait, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007779
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007780 printk(" max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n",
7781 (unsigned)h->max_host_qng, (unsigned)h->max_dvc_qng,
7782 (ulong)h->carr_freelist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007783
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007784 printk(" icq_sp 0x%lx, irq_sp 0x%lx\n",
7785 (ulong)h->icq_sp, (ulong)h->irq_sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007786
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007787 printk(" no_scam 0x%x, tagqng_able 0x%x\n",
7788 (unsigned)h->no_scam, (unsigned)h->tagqng_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007789
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007790 printk(" chip_scsi_id 0x%x, cfg 0x%lx\n",
7791 (unsigned)h->chip_scsi_id, (ulong)h->cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007792}
7793
7794/*
7795 * asc_prt_adv_dvc_cfg()
7796 *
7797 * Display an ADV_DVC_CFG structure.
7798 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007799static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007800{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007801 printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007802
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007803 printk(" disc_enable 0x%x, termination 0x%x\n",
7804 h->disc_enable, h->termination);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007805
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007806 printk(" chip_version 0x%x, mcode_date 0x%x\n",
7807 h->chip_version, h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007808
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007809 printk(" mcode_version 0x%x, pci_device_id 0x%x, lib_version %u\n",
7810 h->mcode_version, to_pci_dev(h->dev)->device, h->lib_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007811
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007812 printk(" control_flag 0x%x, pci_slot_info 0x%x\n",
7813 h->control_flag, h->pci_slot_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007814}
7815
7816/*
7817 * asc_prt_adv_scsi_req_q()
7818 *
7819 * Display an ADV_SCSI_REQ_Q structure.
7820 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007821static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007822{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007823 int sg_blk_cnt;
7824 struct asc_sg_block *sg_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007825
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007826 printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007827
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007828 printk(" target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n",
7829 q->target_id, q->target_lun, (ulong)q->srb_ptr, q->a_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007830
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007831 printk(" cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
7832 q->cntl, (ulong)le32_to_cpu(q->data_addr), (ulong)q->vdata_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007833
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007834 printk(" data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
7835 (ulong)le32_to_cpu(q->data_cnt),
7836 (ulong)le32_to_cpu(q->sense_addr), q->sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007837
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007838 printk
7839 (" cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n",
7840 q->cdb_len, q->done_status, q->host_status, q->scsi_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007841
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007842 printk(" sg_working_ix 0x%x, target_cmd %u\n",
7843 q->sg_working_ix, q->target_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007844
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007845 printk(" scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n",
7846 (ulong)le32_to_cpu(q->scsiq_rptr),
7847 (ulong)le32_to_cpu(q->sg_real_addr), (ulong)q->sg_list_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007848
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007849 /* Display the request's ADV_SG_BLOCK structures. */
7850 if (q->sg_list_ptr != NULL) {
7851 sg_blk_cnt = 0;
7852 while (1) {
7853 /*
7854 * 'sg_ptr' is a physical address. Convert it to a virtual
7855 * address by indexing 'sg_blk_cnt' into the virtual address
7856 * array 'sg_list_ptr'.
7857 *
7858 * XXX - Assumes all SG physical blocks are virtually contiguous.
7859 */
7860 sg_ptr =
7861 &(((ADV_SG_BLOCK *)(q->sg_list_ptr))[sg_blk_cnt]);
7862 asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr);
7863 if (sg_ptr->sg_ptr == 0) {
7864 break;
7865 }
7866 sg_blk_cnt++;
7867 }
7868 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007869}
7870
7871/*
7872 * asc_prt_adv_sgblock()
7873 *
7874 * Display an ADV_SG_BLOCK structure.
7875 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007876static void asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007877{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007878 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007879
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007880 printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n",
7881 (ulong)b, sgblockno);
7882 printk(" sg_cnt %u, sg_ptr 0x%lx\n",
7883 b->sg_cnt, (ulong)le32_to_cpu(b->sg_ptr));
7884 ASC_ASSERT(b->sg_cnt <= NO_OF_SG_PER_BLOCK);
7885 if (b->sg_ptr != 0) {
7886 ASC_ASSERT(b->sg_cnt == NO_OF_SG_PER_BLOCK);
7887 }
7888 for (i = 0; i < b->sg_cnt; i++) {
7889 printk(" [%u]: sg_addr 0x%lx, sg_count 0x%lx\n",
7890 i, (ulong)b->sg_list[i].sg_addr,
7891 (ulong)b->sg_list[i].sg_count);
7892 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007893}
7894
7895/*
7896 * asc_prt_hex()
7897 *
7898 * Print hexadecimal output in 4 byte groupings 32 bytes
7899 * or 8 double-words per line.
7900 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007901static void asc_prt_hex(char *f, uchar *s, int l)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007902{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007903 int i;
7904 int j;
7905 int k;
7906 int m;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007907
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007908 printk("%s: (%d bytes)\n", f, l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007909
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007910 for (i = 0; i < l; i += 32) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007911
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007912 /* Display a maximum of 8 double-words per line. */
7913 if ((k = (l - i) / 4) >= 8) {
7914 k = 8;
7915 m = 0;
7916 } else {
7917 m = (l - i) % 4;
7918 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007919
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007920 for (j = 0; j < k; j++) {
7921 printk(" %2.2X%2.2X%2.2X%2.2X",
7922 (unsigned)s[i + (j * 4)],
7923 (unsigned)s[i + (j * 4) + 1],
7924 (unsigned)s[i + (j * 4) + 2],
7925 (unsigned)s[i + (j * 4) + 3]);
7926 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007927
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007928 switch (m) {
7929 case 0:
7930 default:
7931 break;
7932 case 1:
7933 printk(" %2.2X", (unsigned)s[i + (j * 4)]);
7934 break;
7935 case 2:
7936 printk(" %2.2X%2.2X",
7937 (unsigned)s[i + (j * 4)],
7938 (unsigned)s[i + (j * 4) + 1]);
7939 break;
7940 case 3:
7941 printk(" %2.2X%2.2X%2.2X",
7942 (unsigned)s[i + (j * 4) + 1],
7943 (unsigned)s[i + (j * 4) + 2],
7944 (unsigned)s[i + (j * 4) + 3]);
7945 break;
7946 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007947
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007948 printk("\n");
7949 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007950}
7951#endif /* ADVANSYS_DEBUG */
7952
7953/*
7954 * --- Asc Library Functions
7955 */
7956
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007957static ushort __devinit AscGetEisaChipCfg(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007958{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007959 PortAddr eisa_cfg_iop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007960
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007961 eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
7962 (PortAddr) (ASC_EISA_CFG_IOP_MASK);
7963 return (inpw(eisa_cfg_iop));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007964}
7965
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007966static uchar __devinit AscSetChipScsiID(PortAddr iop_base, uchar new_host_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007967{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007968 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007969
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007970 if (AscGetChipScsiID(iop_base) == new_host_id) {
7971 return (new_host_id);
7972 }
7973 cfg_lsw = AscGetChipCfgLsw(iop_base);
7974 cfg_lsw &= 0xF8FF;
7975 cfg_lsw |= (ushort)((new_host_id & ASC_MAX_TID) << 8);
7976 AscSetChipCfgLsw(iop_base, cfg_lsw);
7977 return (AscGetChipScsiID(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007978}
7979
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007980static unsigned char __devinit AscGetChipScsiCtrl(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007981{
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007982 unsigned char sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007983
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007984 AscSetBank(iop_base, 1);
7985 sc = inp(iop_base + IOP_REG_SC);
7986 AscSetBank(iop_base, 0);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007987 return sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007988}
7989
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007990static unsigned char __devinit
7991AscGetChipVersion(PortAddr iop_base, unsigned short bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007992{
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007993 if (bus_type & ASC_IS_EISA) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007994 PortAddr eisa_iop;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007995 unsigned char revision;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007996 eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
7997 (PortAddr) ASC_EISA_REV_IOP_MASK;
7998 revision = inp(eisa_iop);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007999 return ASC_CHIP_MIN_VER_EISA - 1 + revision;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008000 }
Matthew Wilcoxecec1942007-07-30 08:08:22 -06008001 return AscGetChipVerNo(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008002}
8003
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008004static ushort __devinit AscGetChipBusType(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008005{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008006 ushort chip_ver;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008007
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008008 chip_ver = AscGetChipVerNo(iop_base);
8009 if ((chip_ver >= ASC_CHIP_MIN_VER_VL)
8010 && (chip_ver <= ASC_CHIP_MAX_VER_VL)
8011 ) {
8012 if (((iop_base & 0x0C30) == 0x0C30)
8013 || ((iop_base & 0x0C50) == 0x0C50)
8014 ) {
8015 return (ASC_IS_EISA);
8016 }
8017 return (ASC_IS_VL);
8018 }
8019 if ((chip_ver >= ASC_CHIP_MIN_VER_ISA) &&
8020 (chip_ver <= ASC_CHIP_MAX_VER_ISA)) {
8021 if (chip_ver >= ASC_CHIP_MIN_VER_ISA_PNP) {
8022 return (ASC_IS_ISAPNP);
8023 }
8024 return (ASC_IS_ISA);
8025 } else if ((chip_ver >= ASC_CHIP_MIN_VER_PCI) &&
8026 (chip_ver <= ASC_CHIP_MAX_VER_PCI)) {
8027 return (ASC_IS_PCI);
8028 }
8029 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008030}
8031
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008032static ASC_DCNT
8033AscLoadMicroCode(PortAddr iop_base,
8034 ushort s_addr, uchar *mcode_buf, ushort mcode_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008035{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008036 ASC_DCNT chksum;
8037 ushort mcode_word_size;
8038 ushort mcode_chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008039
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008040 /* Write the microcode buffer starting at LRAM address 0. */
8041 mcode_word_size = (ushort)(mcode_size >> 1);
8042 AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
8043 AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008044
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008045 chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size);
8046 ASC_DBG1(1, "AscLoadMicroCode: chksum 0x%lx\n", (ulong)chksum);
8047 mcode_chksum = (ushort)AscMemSumLramWord(iop_base,
8048 (ushort)ASC_CODE_SEC_BEG,
8049 (ushort)((mcode_size -
8050 s_addr - (ushort)
8051 ASC_CODE_SEC_BEG) /
8052 2));
8053 ASC_DBG1(1, "AscLoadMicroCode: mcode_chksum 0x%lx\n",
8054 (ulong)mcode_chksum);
8055 AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum);
8056 AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size);
8057 return (chksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008058}
8059
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008060static int AscFindSignature(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008061{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008062 ushort sig_word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008063
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008064 ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureByte(0x%x) 0x%x\n",
8065 iop_base, AscGetChipSignatureByte(iop_base));
8066 if (AscGetChipSignatureByte(iop_base) == (uchar)ASC_1000_ID1B) {
8067 ASC_DBG2(1,
8068 "AscFindSignature: AscGetChipSignatureWord(0x%x) 0x%x\n",
8069 iop_base, AscGetChipSignatureWord(iop_base));
8070 sig_word = AscGetChipSignatureWord(iop_base);
8071 if ((sig_word == (ushort)ASC_1000_ID0W) ||
8072 (sig_word == (ushort)ASC_1000_ID0W_FIX)) {
8073 return (1);
8074 }
8075 }
8076 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008077}
8078
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008079static void __devinit AscToggleIRQAct(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008080{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008081 AscSetChipStatus(iop_base, CIW_IRQ_ACT);
8082 AscSetChipStatus(iop_base, 0);
8083 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008084}
8085
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008086static uchar __devinit AscGetChipIRQ(PortAddr iop_base, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008087{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008088 ushort cfg_lsw;
8089 uchar chip_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008090
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008091 if ((bus_type & ASC_IS_EISA) != 0) {
8092 cfg_lsw = AscGetEisaChipCfg(iop_base);
8093 chip_irq = (uchar)(((cfg_lsw >> 8) & 0x07) + 10);
8094 if ((chip_irq == 13) || (chip_irq > 15)) {
8095 return (0);
8096 }
8097 return (chip_irq);
8098 }
8099 if ((bus_type & ASC_IS_VL) != 0) {
8100 cfg_lsw = AscGetChipCfgLsw(iop_base);
8101 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x07));
8102 if ((chip_irq == 0) || (chip_irq == 4) || (chip_irq == 7)) {
8103 return (0);
8104 }
8105 return ((uchar)(chip_irq + (ASC_MIN_IRQ_NO - 1)));
8106 }
8107 cfg_lsw = AscGetChipCfgLsw(iop_base);
8108 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x03));
8109 if (chip_irq == 3)
8110 chip_irq += (uchar)2;
8111 return ((uchar)(chip_irq + ASC_MIN_IRQ_NO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008112}
8113
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008114static uchar __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008115AscSetChipIRQ(PortAddr iop_base, uchar irq_no, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008116{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008117 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008118
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008119 if ((bus_type & ASC_IS_VL) != 0) {
8120 if (irq_no != 0) {
8121 if ((irq_no < ASC_MIN_IRQ_NO)
8122 || (irq_no > ASC_MAX_IRQ_NO)) {
8123 irq_no = 0;
8124 } else {
8125 irq_no -= (uchar)((ASC_MIN_IRQ_NO - 1));
8126 }
8127 }
8128 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE3);
8129 cfg_lsw |= (ushort)0x0010;
8130 AscSetChipCfgLsw(iop_base, cfg_lsw);
8131 AscToggleIRQAct(iop_base);
8132 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE0);
8133 cfg_lsw |= (ushort)((irq_no & 0x07) << 2);
8134 AscSetChipCfgLsw(iop_base, cfg_lsw);
8135 AscToggleIRQAct(iop_base);
8136 return (AscGetChipIRQ(iop_base, bus_type));
8137 }
8138 if ((bus_type & (ASC_IS_ISA)) != 0) {
8139 if (irq_no == 15)
8140 irq_no -= (uchar)2;
8141 irq_no -= (uchar)ASC_MIN_IRQ_NO;
8142 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFF3);
8143 cfg_lsw |= (ushort)((irq_no & 0x03) << 2);
8144 AscSetChipCfgLsw(iop_base, cfg_lsw);
8145 return (AscGetChipIRQ(iop_base, bus_type));
8146 }
8147 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008148}
8149
8150#ifdef CONFIG_ISA
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008151static void __devinit AscEnableIsaDma(uchar dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008152{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008153 if (dma_channel < 4) {
8154 outp(0x000B, (ushort)(0xC0 | dma_channel));
8155 outp(0x000A, dma_channel);
8156 } else if (dma_channel < 8) {
8157 outp(0x00D6, (ushort)(0xC0 | (dma_channel - 4)));
8158 outp(0x00D4, (ushort)(dma_channel - 4));
8159 }
8160 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008161}
8162#endif /* CONFIG_ISA */
8163
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008164static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008165{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008166 EXT_MSG ext_msg;
8167 EXT_MSG out_msg;
8168 ushort halt_q_addr;
8169 int sdtr_accept;
8170 ushort int_halt_code;
8171 ASC_SCSI_BIT_ID_TYPE scsi_busy;
8172 ASC_SCSI_BIT_ID_TYPE target_id;
8173 PortAddr iop_base;
8174 uchar tag_code;
8175 uchar q_status;
8176 uchar halt_qp;
8177 uchar sdtr_data;
8178 uchar target_ix;
8179 uchar q_cntl, tid_no;
8180 uchar cur_dvc_qng;
8181 uchar asyn_sdtr;
8182 uchar scsi_status;
8183 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008184
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008185 ASC_ASSERT(asc_dvc->drv_ptr != NULL);
8186 boardp = asc_dvc->drv_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008187
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008188 iop_base = asc_dvc->iop_base;
8189 int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008190
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008191 halt_qp = AscReadLramByte(iop_base, ASCV_CURCDB_B);
8192 halt_q_addr = ASC_QNO_TO_QADDR(halt_qp);
8193 target_ix = AscReadLramByte(iop_base,
8194 (ushort)(halt_q_addr +
8195 (ushort)ASC_SCSIQ_B_TARGET_IX));
8196 q_cntl =
8197 AscReadLramByte(iop_base,
8198 (ushort)(halt_q_addr + (ushort)ASC_SCSIQ_B_CNTL));
8199 tid_no = ASC_TIX_TO_TID(target_ix);
8200 target_id = (uchar)ASC_TID_TO_TARGET_ID(tid_no);
8201 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8202 asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB;
8203 } else {
8204 asyn_sdtr = 0;
8205 }
8206 if (int_halt_code == ASC_HALT_DISABLE_ASYN_USE_SYN_FIX) {
8207 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8208 AscSetChipSDTR(iop_base, 0, tid_no);
8209 boardp->sdtr_data[tid_no] = 0;
8210 }
8211 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8212 return (0);
8213 } else if (int_halt_code == ASC_HALT_ENABLE_ASYN_USE_SYN_FIX) {
8214 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8215 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8216 boardp->sdtr_data[tid_no] = asyn_sdtr;
8217 }
8218 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8219 return (0);
8220 } else if (int_halt_code == ASC_HALT_EXTMSG_IN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008221
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008222 AscMemWordCopyPtrFromLram(iop_base,
8223 ASCV_MSGIN_BEG,
8224 (uchar *)&ext_msg,
8225 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008226
Matthew Wilcox47d853c2007-07-26 11:41:33 -04008227 if (ext_msg.msg_type == EXTENDED_MESSAGE &&
8228 ext_msg.msg_req == EXTENDED_SDTR &&
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008229 ext_msg.msg_len == MS_SDTR_LEN) {
8230 sdtr_accept = TRUE;
8231 if ((ext_msg.req_ack_offset > ASC_SYN_MAX_OFFSET)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008232
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008233 sdtr_accept = FALSE;
8234 ext_msg.req_ack_offset = ASC_SYN_MAX_OFFSET;
8235 }
8236 if ((ext_msg.xfer_period <
8237 asc_dvc->sdtr_period_tbl[asc_dvc->
8238 host_init_sdtr_index])
8239 || (ext_msg.xfer_period >
8240 asc_dvc->sdtr_period_tbl[asc_dvc->
8241 max_sdtr_index])) {
8242 sdtr_accept = FALSE;
8243 ext_msg.xfer_period =
8244 asc_dvc->sdtr_period_tbl[asc_dvc->
8245 host_init_sdtr_index];
8246 }
8247 if (sdtr_accept) {
8248 sdtr_data =
8249 AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
8250 ext_msg.req_ack_offset);
8251 if ((sdtr_data == 0xFF)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008252
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008253 q_cntl |= QC_MSG_OUT;
8254 asc_dvc->init_sdtr &= ~target_id;
8255 asc_dvc->sdtr_done &= ~target_id;
8256 AscSetChipSDTR(iop_base, asyn_sdtr,
8257 tid_no);
8258 boardp->sdtr_data[tid_no] = asyn_sdtr;
8259 }
8260 }
8261 if (ext_msg.req_ack_offset == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008262
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008263 q_cntl &= ~QC_MSG_OUT;
8264 asc_dvc->init_sdtr &= ~target_id;
8265 asc_dvc->sdtr_done &= ~target_id;
8266 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8267 } else {
8268 if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008269
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008270 q_cntl &= ~QC_MSG_OUT;
8271 asc_dvc->sdtr_done |= target_id;
8272 asc_dvc->init_sdtr |= target_id;
8273 asc_dvc->pci_fix_asyn_xfer &=
8274 ~target_id;
8275 sdtr_data =
8276 AscCalSDTRData(asc_dvc,
8277 ext_msg.xfer_period,
8278 ext_msg.
8279 req_ack_offset);
8280 AscSetChipSDTR(iop_base, sdtr_data,
8281 tid_no);
8282 boardp->sdtr_data[tid_no] = sdtr_data;
8283 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008284
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008285 q_cntl |= QC_MSG_OUT;
8286 AscMsgOutSDTR(asc_dvc,
8287 ext_msg.xfer_period,
8288 ext_msg.req_ack_offset);
8289 asc_dvc->pci_fix_asyn_xfer &=
8290 ~target_id;
8291 sdtr_data =
8292 AscCalSDTRData(asc_dvc,
8293 ext_msg.xfer_period,
8294 ext_msg.
8295 req_ack_offset);
8296 AscSetChipSDTR(iop_base, sdtr_data,
8297 tid_no);
8298 boardp->sdtr_data[tid_no] = sdtr_data;
8299 asc_dvc->sdtr_done |= target_id;
8300 asc_dvc->init_sdtr |= target_id;
8301 }
8302 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008303
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008304 AscWriteLramByte(iop_base,
8305 (ushort)(halt_q_addr +
8306 (ushort)ASC_SCSIQ_B_CNTL),
8307 q_cntl);
8308 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8309 return (0);
Matthew Wilcox47d853c2007-07-26 11:41:33 -04008310 } else if (ext_msg.msg_type == EXTENDED_MESSAGE &&
8311 ext_msg.msg_req == EXTENDED_WDTR &&
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008312 ext_msg.msg_len == MS_WDTR_LEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008313
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008314 ext_msg.wdtr_width = 0;
8315 AscMemWordCopyPtrToLram(iop_base,
8316 ASCV_MSGOUT_BEG,
8317 (uchar *)&ext_msg,
8318 sizeof(EXT_MSG) >> 1);
8319 q_cntl |= QC_MSG_OUT;
8320 AscWriteLramByte(iop_base,
8321 (ushort)(halt_q_addr +
8322 (ushort)ASC_SCSIQ_B_CNTL),
8323 q_cntl);
8324 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8325 return (0);
8326 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008327
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008328 ext_msg.msg_type = MESSAGE_REJECT;
8329 AscMemWordCopyPtrToLram(iop_base,
8330 ASCV_MSGOUT_BEG,
8331 (uchar *)&ext_msg,
8332 sizeof(EXT_MSG) >> 1);
8333 q_cntl |= QC_MSG_OUT;
8334 AscWriteLramByte(iop_base,
8335 (ushort)(halt_q_addr +
8336 (ushort)ASC_SCSIQ_B_CNTL),
8337 q_cntl);
8338 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8339 return (0);
8340 }
8341 } else if (int_halt_code == ASC_HALT_CHK_CONDITION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008342
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008343 q_cntl |= QC_REQ_SENSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008344
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008345 if ((asc_dvc->init_sdtr & target_id) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008346
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008347 asc_dvc->sdtr_done &= ~target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008348
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008349 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
8350 q_cntl |= QC_MSG_OUT;
8351 AscMsgOutSDTR(asc_dvc,
8352 asc_dvc->
8353 sdtr_period_tbl[(sdtr_data >> 4) &
8354 (uchar)(asc_dvc->
8355 max_sdtr_index -
8356 1)],
8357 (uchar)(sdtr_data & (uchar)
8358 ASC_SYN_MAX_OFFSET));
8359 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008360
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008361 AscWriteLramByte(iop_base,
8362 (ushort)(halt_q_addr +
8363 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008364
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008365 tag_code = AscReadLramByte(iop_base,
8366 (ushort)(halt_q_addr + (ushort)
8367 ASC_SCSIQ_B_TAG_CODE));
8368 tag_code &= 0xDC;
8369 if ((asc_dvc->pci_fix_asyn_xfer & target_id)
8370 && !(asc_dvc->pci_fix_asyn_xfer_always & target_id)
8371 ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008372
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008373 tag_code |= (ASC_TAG_FLAG_DISABLE_DISCONNECT
8374 | ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008375
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008376 }
8377 AscWriteLramByte(iop_base,
8378 (ushort)(halt_q_addr +
8379 (ushort)ASC_SCSIQ_B_TAG_CODE),
8380 tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008381
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008382 q_status = AscReadLramByte(iop_base,
8383 (ushort)(halt_q_addr + (ushort)
8384 ASC_SCSIQ_B_STATUS));
8385 q_status |= (QS_READY | QS_BUSY);
8386 AscWriteLramByte(iop_base,
8387 (ushort)(halt_q_addr +
8388 (ushort)ASC_SCSIQ_B_STATUS),
8389 q_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008390
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008391 scsi_busy = AscReadLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B);
8392 scsi_busy &= ~target_id;
8393 AscWriteLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B, scsi_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008394
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008395 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8396 return (0);
8397 } else if (int_halt_code == ASC_HALT_SDTR_REJECTED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008398
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008399 AscMemWordCopyPtrFromLram(iop_base,
8400 ASCV_MSGOUT_BEG,
8401 (uchar *)&out_msg,
8402 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008403
Matthew Wilcox47d853c2007-07-26 11:41:33 -04008404 if ((out_msg.msg_type == EXTENDED_MESSAGE) &&
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008405 (out_msg.msg_len == MS_SDTR_LEN) &&
Matthew Wilcox47d853c2007-07-26 11:41:33 -04008406 (out_msg.msg_req == EXTENDED_SDTR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008407
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008408 asc_dvc->init_sdtr &= ~target_id;
8409 asc_dvc->sdtr_done &= ~target_id;
8410 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8411 boardp->sdtr_data[tid_no] = asyn_sdtr;
8412 }
8413 q_cntl &= ~QC_MSG_OUT;
8414 AscWriteLramByte(iop_base,
8415 (ushort)(halt_q_addr +
8416 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
8417 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8418 return (0);
8419 } else if (int_halt_code == ASC_HALT_SS_QUEUE_FULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008420
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008421 scsi_status = AscReadLramByte(iop_base,
8422 (ushort)((ushort)halt_q_addr +
8423 (ushort)
8424 ASC_SCSIQ_SCSI_STATUS));
8425 cur_dvc_qng =
8426 AscReadLramByte(iop_base,
8427 (ushort)((ushort)ASC_QADR_BEG +
8428 (ushort)target_ix));
8429 if ((cur_dvc_qng > 0) && (asc_dvc->cur_dvc_qng[tid_no] > 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008430
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008431 scsi_busy = AscReadLramByte(iop_base,
8432 (ushort)ASCV_SCSIBUSY_B);
8433 scsi_busy |= target_id;
8434 AscWriteLramByte(iop_base,
8435 (ushort)ASCV_SCSIBUSY_B, scsi_busy);
8436 asc_dvc->queue_full_or_busy |= target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008437
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008438 if (scsi_status == SAM_STAT_TASK_SET_FULL) {
8439 if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) {
8440 cur_dvc_qng -= 1;
8441 asc_dvc->max_dvc_qng[tid_no] =
8442 cur_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008443
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008444 AscWriteLramByte(iop_base,
8445 (ushort)((ushort)
8446 ASCV_MAX_DVC_QNG_BEG
8447 + (ushort)
8448 tid_no),
8449 cur_dvc_qng);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008450
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008451 /*
8452 * Set the device queue depth to the number of
8453 * active requests when the QUEUE FULL condition
8454 * was encountered.
8455 */
8456 boardp->queue_full |= target_id;
8457 boardp->queue_full_cnt[tid_no] =
8458 cur_dvc_qng;
8459 }
8460 }
8461 }
8462 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8463 return (0);
8464 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008465#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008466 else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC) {
8467 uchar q_no;
8468 ushort q_addr;
8469 uchar sg_wk_q_no;
8470 uchar first_sg_wk_q_no;
8471 ASC_SCSI_Q *scsiq; /* Ptr to driver request. */
8472 ASC_SG_HEAD *sg_head; /* Ptr to driver SG request. */
8473 ASC_SG_LIST_Q scsi_sg_q; /* Structure written to queue. */
8474 ushort sg_list_dwords;
8475 ushort sg_entry_cnt;
8476 uchar next_qp;
8477 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008478
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008479 q_no = AscReadLramByte(iop_base, (ushort)ASCV_REQ_SG_LIST_QP);
8480 if (q_no == ASC_QLINK_END) {
8481 return (0);
8482 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008483
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008484 q_addr = ASC_QNO_TO_QADDR(q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008485
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008486 /*
8487 * Convert the request's SRB pointer to a host ASC_SCSI_REQ
8488 * structure pointer using a macro provided by the driver.
8489 * The ASC_SCSI_REQ pointer provides a pointer to the
8490 * host ASC_SG_HEAD structure.
8491 */
8492 /* Read request's SRB pointer. */
8493 scsiq = (ASC_SCSI_Q *)
8494 ASC_SRB2SCSIQ(ASC_U32_TO_VADDR(AscReadLramDWord(iop_base,
8495 (ushort)
8496 (q_addr +
8497 ASC_SCSIQ_D_SRBPTR))));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008498
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008499 /*
8500 * Get request's first and working SG queue.
8501 */
8502 sg_wk_q_no = AscReadLramByte(iop_base,
8503 (ushort)(q_addr +
8504 ASC_SCSIQ_B_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008505
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008506 first_sg_wk_q_no = AscReadLramByte(iop_base,
8507 (ushort)(q_addr +
8508 ASC_SCSIQ_B_FIRST_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008509
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008510 /*
8511 * Reset request's working SG queue back to the
8512 * first SG queue.
8513 */
8514 AscWriteLramByte(iop_base,
8515 (ushort)(q_addr +
8516 (ushort)ASC_SCSIQ_B_SG_WK_QP),
8517 first_sg_wk_q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008518
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008519 sg_head = scsiq->sg_head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008520
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008521 /*
8522 * Set sg_entry_cnt to the number of SG elements
8523 * that will be completed on this interrupt.
8524 *
8525 * Note: The allocated SG queues contain ASC_MAX_SG_LIST - 1
8526 * SG elements. The data_cnt and data_addr fields which
8527 * add 1 to the SG element capacity are not used when
8528 * restarting SG handling after a halt.
8529 */
8530 if (scsiq->remain_sg_entry_cnt > (ASC_MAX_SG_LIST - 1)) {
8531 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008532
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008533 /*
8534 * Keep track of remaining number of SG elements that will
8535 * need to be handled on the next interrupt.
8536 */
8537 scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1);
8538 } else {
8539 sg_entry_cnt = scsiq->remain_sg_entry_cnt;
8540 scsiq->remain_sg_entry_cnt = 0;
8541 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008542
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008543 /*
8544 * Copy SG elements into the list of allocated SG queues.
8545 *
8546 * Last index completed is saved in scsiq->next_sg_index.
8547 */
8548 next_qp = first_sg_wk_q_no;
8549 q_addr = ASC_QNO_TO_QADDR(next_qp);
8550 scsi_sg_q.sg_head_qp = q_no;
8551 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
8552 for (i = 0; i < sg_head->queue_cnt; i++) {
8553 scsi_sg_q.seq_no = i + 1;
8554 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
8555 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
8556 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
8557 /*
8558 * After very first SG queue RISC FW uses next
8559 * SG queue first element then checks sg_list_cnt
8560 * against zero and then decrements, so set
8561 * sg_list_cnt 1 less than number of SG elements
8562 * in each SG queue.
8563 */
8564 scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
8565 scsi_sg_q.sg_cur_list_cnt =
8566 ASC_SG_LIST_PER_Q - 1;
8567 } else {
8568 /*
8569 * This is the last SG queue in the list of
8570 * allocated SG queues. If there are more
8571 * SG elements than will fit in the allocated
8572 * queues, then set the QCSG_SG_XFER_MORE flag.
8573 */
8574 if (scsiq->remain_sg_entry_cnt != 0) {
8575 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
8576 } else {
8577 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
8578 }
8579 /* equals sg_entry_cnt * 2 */
8580 sg_list_dwords = sg_entry_cnt << 1;
8581 scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
8582 scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
8583 sg_entry_cnt = 0;
8584 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008585
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008586 scsi_sg_q.q_no = next_qp;
8587 AscMemWordCopyPtrToLram(iop_base,
8588 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
8589 (uchar *)&scsi_sg_q,
8590 sizeof(ASC_SG_LIST_Q) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008591
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008592 AscMemDWordCopyPtrToLram(iop_base,
8593 q_addr + ASC_SGQ_LIST_BEG,
8594 (uchar *)&sg_head->
8595 sg_list[scsiq->next_sg_index],
8596 sg_list_dwords);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008597
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008598 scsiq->next_sg_index += ASC_SG_LIST_PER_Q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008599
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008600 /*
8601 * If the just completed SG queue contained the
8602 * last SG element, then no more SG queues need
8603 * to be written.
8604 */
8605 if (scsi_sg_q.cntl & QCSG_SG_XFER_END) {
8606 break;
8607 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008608
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008609 next_qp = AscReadLramByte(iop_base,
8610 (ushort)(q_addr +
8611 ASC_SCSIQ_B_FWD));
8612 q_addr = ASC_QNO_TO_QADDR(next_qp);
8613 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008614
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008615 /*
8616 * Clear the halt condition so the RISC will be restarted
8617 * after the return.
8618 */
8619 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8620 return (0);
8621 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008622#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008623 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008624}
8625
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008626static uchar
8627_AscCopyLramScsiDoneQ(PortAddr iop_base,
8628 ushort q_addr,
8629 ASC_QDONE_INFO *scsiq, ASC_DCNT max_dma_count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008630{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008631 ushort _val;
8632 uchar sg_queue_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008633
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008634 DvcGetQinfo(iop_base,
8635 q_addr + ASC_SCSIQ_DONE_INFO_BEG,
8636 (uchar *)scsiq,
8637 (sizeof(ASC_SCSIQ_2) + sizeof(ASC_SCSIQ_3)) / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008638
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008639 _val = AscReadLramWord(iop_base,
8640 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS));
8641 scsiq->q_status = (uchar)_val;
8642 scsiq->q_no = (uchar)(_val >> 8);
8643 _val = AscReadLramWord(iop_base,
8644 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_CNTL));
8645 scsiq->cntl = (uchar)_val;
8646 sg_queue_cnt = (uchar)(_val >> 8);
8647 _val = AscReadLramWord(iop_base,
8648 (ushort)(q_addr +
8649 (ushort)ASC_SCSIQ_B_SENSE_LEN));
8650 scsiq->sense_len = (uchar)_val;
8651 scsiq->extra_bytes = (uchar)(_val >> 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008652
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008653 /*
8654 * Read high word of remain bytes from alternate location.
8655 */
8656 scsiq->remain_bytes = (((ADV_DCNT)AscReadLramWord(iop_base,
8657 (ushort)(q_addr +
8658 (ushort)
8659 ASC_SCSIQ_W_ALT_DC1)))
8660 << 16);
8661 /*
8662 * Read low word of remain bytes from original location.
8663 */
8664 scsiq->remain_bytes += AscReadLramWord(iop_base,
8665 (ushort)(q_addr + (ushort)
8666 ASC_SCSIQ_DW_REMAIN_XFER_CNT));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008667
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008668 scsiq->remain_bytes &= max_dma_count;
8669 return (sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008670}
8671
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008672static int AscIsrQDone(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008673{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008674 uchar next_qp;
8675 uchar n_q_used;
8676 uchar sg_list_qp;
8677 uchar sg_queue_cnt;
8678 uchar q_cnt;
8679 uchar done_q_tail;
8680 uchar tid_no;
8681 ASC_SCSI_BIT_ID_TYPE scsi_busy;
8682 ASC_SCSI_BIT_ID_TYPE target_id;
8683 PortAddr iop_base;
8684 ushort q_addr;
8685 ushort sg_q_addr;
8686 uchar cur_target_qng;
8687 ASC_QDONE_INFO scsiq_buf;
8688 ASC_QDONE_INFO *scsiq;
8689 int false_overrun;
8690 ASC_ISR_CALLBACK asc_isr_callback;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008691
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008692 iop_base = asc_dvc->iop_base;
8693 asc_isr_callback = asc_dvc->isr_callback;
8694 n_q_used = 1;
8695 scsiq = (ASC_QDONE_INFO *)&scsiq_buf;
8696 done_q_tail = (uchar)AscGetVarDoneQTail(iop_base);
8697 q_addr = ASC_QNO_TO_QADDR(done_q_tail);
8698 next_qp = AscReadLramByte(iop_base,
8699 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_FWD));
8700 if (next_qp != ASC_QLINK_END) {
8701 AscPutVarDoneQTail(iop_base, next_qp);
8702 q_addr = ASC_QNO_TO_QADDR(next_qp);
8703 sg_queue_cnt = _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq,
8704 asc_dvc->max_dma_count);
8705 AscWriteLramByte(iop_base,
8706 (ushort)(q_addr +
8707 (ushort)ASC_SCSIQ_B_STATUS),
8708 (uchar)(scsiq->
8709 q_status & (uchar)~(QS_READY |
8710 QS_ABORTED)));
8711 tid_no = ASC_TIX_TO_TID(scsiq->d2.target_ix);
8712 target_id = ASC_TIX_TO_TARGET_ID(scsiq->d2.target_ix);
8713 if ((scsiq->cntl & QC_SG_HEAD) != 0) {
8714 sg_q_addr = q_addr;
8715 sg_list_qp = next_qp;
8716 for (q_cnt = 0; q_cnt < sg_queue_cnt; q_cnt++) {
8717 sg_list_qp = AscReadLramByte(iop_base,
8718 (ushort)(sg_q_addr
8719 + (ushort)
8720 ASC_SCSIQ_B_FWD));
8721 sg_q_addr = ASC_QNO_TO_QADDR(sg_list_qp);
8722 if (sg_list_qp == ASC_QLINK_END) {
8723 AscSetLibErrorCode(asc_dvc,
8724 ASCQ_ERR_SG_Q_LINKS);
8725 scsiq->d3.done_stat = QD_WITH_ERROR;
8726 scsiq->d3.host_stat =
8727 QHSTA_D_QDONE_SG_LIST_CORRUPTED;
8728 goto FATAL_ERR_QDONE;
8729 }
8730 AscWriteLramByte(iop_base,
8731 (ushort)(sg_q_addr + (ushort)
8732 ASC_SCSIQ_B_STATUS),
8733 QS_FREE);
8734 }
8735 n_q_used = sg_queue_cnt + 1;
8736 AscPutVarDoneQTail(iop_base, sg_list_qp);
8737 }
8738 if (asc_dvc->queue_full_or_busy & target_id) {
8739 cur_target_qng = AscReadLramByte(iop_base,
8740 (ushort)((ushort)
8741 ASC_QADR_BEG
8742 + (ushort)
8743 scsiq->d2.
8744 target_ix));
8745 if (cur_target_qng < asc_dvc->max_dvc_qng[tid_no]) {
8746 scsi_busy = AscReadLramByte(iop_base, (ushort)
8747 ASCV_SCSIBUSY_B);
8748 scsi_busy &= ~target_id;
8749 AscWriteLramByte(iop_base,
8750 (ushort)ASCV_SCSIBUSY_B,
8751 scsi_busy);
8752 asc_dvc->queue_full_or_busy &= ~target_id;
8753 }
8754 }
8755 if (asc_dvc->cur_total_qng >= n_q_used) {
8756 asc_dvc->cur_total_qng -= n_q_used;
8757 if (asc_dvc->cur_dvc_qng[tid_no] != 0) {
8758 asc_dvc->cur_dvc_qng[tid_no]--;
8759 }
8760 } else {
8761 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CUR_QNG);
8762 scsiq->d3.done_stat = QD_WITH_ERROR;
8763 goto FATAL_ERR_QDONE;
8764 }
8765 if ((scsiq->d2.srb_ptr == 0UL) ||
8766 ((scsiq->q_status & QS_ABORTED) != 0)) {
8767 return (0x11);
8768 } else if (scsiq->q_status == QS_DONE) {
8769 false_overrun = FALSE;
8770 if (scsiq->extra_bytes != 0) {
8771 scsiq->remain_bytes +=
8772 (ADV_DCNT)scsiq->extra_bytes;
8773 }
8774 if (scsiq->d3.done_stat == QD_WITH_ERROR) {
8775 if (scsiq->d3.host_stat ==
8776 QHSTA_M_DATA_OVER_RUN) {
8777 if ((scsiq->
8778 cntl & (QC_DATA_IN | QC_DATA_OUT))
8779 == 0) {
8780 scsiq->d3.done_stat =
8781 QD_NO_ERROR;
8782 scsiq->d3.host_stat =
8783 QHSTA_NO_ERROR;
8784 } else if (false_overrun) {
8785 scsiq->d3.done_stat =
8786 QD_NO_ERROR;
8787 scsiq->d3.host_stat =
8788 QHSTA_NO_ERROR;
8789 }
8790 } else if (scsiq->d3.host_stat ==
8791 QHSTA_M_HUNG_REQ_SCSI_BUS_RESET) {
8792 AscStopChip(iop_base);
8793 AscSetChipControl(iop_base,
8794 (uchar)(CC_SCSI_RESET
8795 | CC_HALT));
8796 DvcDelayNanoSecond(asc_dvc, 60000);
8797 AscSetChipControl(iop_base, CC_HALT);
8798 AscSetChipStatus(iop_base,
8799 CIW_CLR_SCSI_RESET_INT);
8800 AscSetChipStatus(iop_base, 0);
8801 AscSetChipControl(iop_base, 0);
8802 }
8803 }
8804 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
8805 (*asc_isr_callback) (asc_dvc, scsiq);
8806 } else {
8807 if ((AscReadLramByte(iop_base,
8808 (ushort)(q_addr + (ushort)
8809 ASC_SCSIQ_CDB_BEG))
8810 == START_STOP)) {
8811 asc_dvc->unit_not_ready &= ~target_id;
8812 if (scsiq->d3.done_stat != QD_NO_ERROR) {
8813 asc_dvc->start_motor &=
8814 ~target_id;
8815 }
8816 }
8817 }
8818 return (1);
8819 } else {
8820 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS);
8821 FATAL_ERR_QDONE:
8822 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
8823 (*asc_isr_callback) (asc_dvc, scsiq);
8824 }
8825 return (0x80);
8826 }
8827 }
8828 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008829}
8830
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008831static int AscISR(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008832{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008833 ASC_CS_TYPE chipstat;
8834 PortAddr iop_base;
8835 ushort saved_ram_addr;
8836 uchar ctrl_reg;
8837 uchar saved_ctrl_reg;
8838 int int_pending;
8839 int status;
8840 uchar host_flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008841
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008842 iop_base = asc_dvc->iop_base;
8843 int_pending = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008844
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008845 if (AscIsIntPending(iop_base) == 0) {
8846 return int_pending;
8847 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008848
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008849 if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0)
8850 || (asc_dvc->isr_callback == 0)
8851 ) {
8852 return (ERR);
8853 }
8854 if (asc_dvc->in_critical_cnt != 0) {
8855 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL);
8856 return (ERR);
8857 }
8858 if (asc_dvc->is_in_int) {
8859 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY);
8860 return (ERR);
8861 }
8862 asc_dvc->is_in_int = TRUE;
8863 ctrl_reg = AscGetChipControl(iop_base);
8864 saved_ctrl_reg = ctrl_reg & (~(CC_SCSI_RESET | CC_CHIP_RESET |
8865 CC_SINGLE_STEP | CC_DIAG | CC_TEST));
8866 chipstat = AscGetChipStatus(iop_base);
8867 if (chipstat & CSW_SCSI_RESET_LATCH) {
8868 if (!(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))) {
8869 int i = 10;
8870 int_pending = TRUE;
8871 asc_dvc->sdtr_done = 0;
8872 saved_ctrl_reg &= (uchar)(~CC_HALT);
8873 while ((AscGetChipStatus(iop_base) &
8874 CSW_SCSI_RESET_ACTIVE) && (i-- > 0)) {
8875 DvcSleepMilliSecond(100);
8876 }
8877 AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT));
8878 AscSetChipControl(iop_base, CC_HALT);
8879 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
8880 AscSetChipStatus(iop_base, 0);
8881 chipstat = AscGetChipStatus(iop_base);
8882 }
8883 }
8884 saved_ram_addr = AscGetChipLramAddr(iop_base);
8885 host_flag = AscReadLramByte(iop_base,
8886 ASCV_HOST_FLAG_B) &
8887 (uchar)(~ASC_HOST_FLAG_IN_ISR);
8888 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
8889 (uchar)(host_flag | (uchar)ASC_HOST_FLAG_IN_ISR));
8890 if ((chipstat & CSW_INT_PENDING)
8891 || (int_pending)
8892 ) {
8893 AscAckInterrupt(iop_base);
8894 int_pending = TRUE;
8895 if ((chipstat & CSW_HALTED) && (ctrl_reg & CC_SINGLE_STEP)) {
8896 if (AscIsrChipHalted(asc_dvc) == ERR) {
8897 goto ISR_REPORT_QDONE_FATAL_ERROR;
8898 } else {
8899 saved_ctrl_reg &= (uchar)(~CC_HALT);
8900 }
8901 } else {
8902 ISR_REPORT_QDONE_FATAL_ERROR:
8903 if ((asc_dvc->dvc_cntl & ASC_CNTL_INT_MULTI_Q) != 0) {
8904 while (((status =
8905 AscIsrQDone(asc_dvc)) & 0x01) != 0) {
8906 }
8907 } else {
8908 do {
8909 if ((status =
8910 AscIsrQDone(asc_dvc)) == 1) {
8911 break;
8912 }
8913 } while (status == 0x11);
8914 }
8915 if ((status & 0x80) != 0)
8916 int_pending = ERR;
8917 }
8918 }
8919 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
8920 AscSetChipLramAddr(iop_base, saved_ram_addr);
8921 AscSetChipControl(iop_base, saved_ctrl_reg);
8922 asc_dvc->is_in_int = FALSE;
8923 return (int_pending);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008924}
8925
8926/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008927static uchar _asc_mcode_buf[] = {
8928 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8929 0x00, 0x00, 0x00, 0x00,
8930 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00,
8931 0x00, 0x00, 0x00, 0x00,
8932 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8933 0x00, 0x00, 0x00, 0x00,
8934 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8935 0x00, 0x00, 0x00, 0x00,
8936 0x00, 0x00, 0x00, 0x00, 0xC3, 0x12, 0x0D, 0x05, 0x01, 0x00, 0x00, 0x00,
8937 0x00, 0xFF, 0x00, 0x00,
8938 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00,
8939 0x00, 0x00, 0x00, 0x00,
8940 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF,
8941 0x00, 0x00, 0x00, 0x00,
8942 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x88,
8943 0x00, 0x00, 0x00, 0x00,
8944 0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73,
8945 0x03, 0x23, 0x36, 0x40,
8946 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2,
8947 0xC2, 0x00, 0x92, 0x80,
8948 0x1E, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xDF, 0x23, 0x36, 0x60,
8949 0xB6, 0x00, 0x92, 0x80,
8950 0x4F, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00,
8951 0x92, 0x80, 0x80, 0x62,
8952 0x92, 0x80, 0x00, 0x46, 0x15, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8,
8953 0xCD, 0x04, 0x4D, 0x00,
8954 0x00, 0xA3, 0xD6, 0x00, 0xA6, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01,
8955 0xE6, 0x84, 0xD2, 0xC1,
8956 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x01, 0xA6, 0x97,
8957 0xC6, 0x81, 0xC2, 0x88,
8958 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0xFE, 0x00, 0x4F, 0x00,
8959 0x84, 0x97, 0x07, 0xA6,
8960 0x08, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x01, 0xDE,
8961 0xC2, 0x88, 0xCE, 0x00,
8962 0x69, 0x60, 0xCE, 0x00, 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x78, 0x01,
8963 0x80, 0x63, 0x07, 0xA6,
8964 0x24, 0x01, 0x78, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6,
8965 0x34, 0x01, 0x00, 0x33,
8966 0x04, 0x00, 0xC2, 0x88, 0x03, 0x07, 0x02, 0x01, 0x04, 0xCA, 0x0D, 0x23,
8967 0x68, 0x98, 0x4D, 0x04,
8968 0x04, 0x85, 0x05, 0xD8, 0x0D, 0x23, 0x68, 0x98, 0xCD, 0x04, 0x15, 0x23,
8969 0xF8, 0x88, 0xFB, 0x23,
8970 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x62, 0x01,
8971 0x00, 0x33, 0x0A, 0x00,
8972 0xC2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x6E, 0x01, 0x00, 0x33, 0x0B, 0x00,
8973 0xC2, 0x88, 0xCD, 0x04,
8974 0x36, 0x2D, 0x00, 0x33, 0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x88, 0x81,
8975 0x06, 0xAB, 0x82, 0x01,
8976 0x88, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x92, 0x01, 0x50, 0x00, 0x00, 0xA3,
8977 0x3C, 0x01, 0x00, 0x05,
8978 0x7C, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6, 0x04, 0x23, 0xA0, 0x01,
8979 0x15, 0x23, 0xA1, 0x01,
8980 0xBE, 0x81, 0xFD, 0x23, 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00,
8981 0x06, 0x61, 0x00, 0xA0,
8982 0xB4, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00,
8983 0xC2, 0x88, 0x06, 0x23,
8984 0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01, 0x00, 0xA2, 0xD4, 0x01,
8985 0x57, 0x60, 0x00, 0xA0,
8986 0xDA, 0x01, 0xE6, 0x84, 0x80, 0x23, 0xA0, 0x01, 0xE6, 0x84, 0x80, 0x73,
8987 0x4B, 0x00, 0x06, 0x61,
8988 0x00, 0xA2, 0x00, 0x02, 0x04, 0x01, 0x0C, 0xDE, 0x02, 0x01, 0x03, 0xCC,
8989 0x4F, 0x00, 0x84, 0x97,
8990 0xFC, 0x81, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, 0x4F, 0x00, 0x62, 0x97,
8991 0x48, 0x04, 0x84, 0x80,
8992 0xF0, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00,
8993 0x81, 0x73, 0x06, 0x29,
8994 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x6B, 0xEB, 0x11, 0x23, 0xF8, 0x88,
8995 0x04, 0x98, 0xF0, 0x80,
8996 0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x2A, 0x02, 0x7C, 0x95, 0x06, 0xA6,
8997 0x34, 0x02, 0x03, 0xA6,
8998 0x4C, 0x04, 0x46, 0x82, 0x04, 0x01, 0x03, 0xD8, 0xB4, 0x98, 0x6A, 0x96,
8999 0x46, 0x82, 0xFE, 0x95,
9000 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x6C, 0x02,
9001 0x07, 0xA6, 0x5A, 0x02,
9002 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x62, 0x02, 0xC2, 0x88, 0x7C, 0x95,
9003 0x48, 0x82, 0x60, 0x96,
9004 0x48, 0x82, 0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84,
9005 0x04, 0x01, 0x0C, 0xDC,
9006 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01,
9007 0x6F, 0x00, 0xA5, 0x01,
9008 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, 0x1C, 0x01,
9009 0x02, 0xA6, 0xAA, 0x02,
9010 0x07, 0xA6, 0x5A, 0x02, 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x20, 0x04,
9011 0x01, 0xA6, 0xB4, 0x02,
9012 0x00, 0xA6, 0xB4, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E,
9013 0x80, 0x63, 0x00, 0x43,
9014 0x00, 0xA0, 0x8C, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, 0xE7, 0x23,
9015 0x04, 0x61, 0x84, 0x01,
9016 0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F,
9017 0x00, 0x00, 0xEA, 0x82,
9018 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0xA2, 0xC8,
9019 0x00, 0x33, 0x1F, 0x00,
9020 0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x7E, 0x98,
9021 0xB6, 0x2D, 0x01, 0xA6,
9022 0x14, 0x03, 0x00, 0xA6, 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6,
9023 0x10, 0x03, 0x03, 0xA6,
9024 0x20, 0x04, 0x02, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88,
9025 0x7C, 0x95, 0xEE, 0x82,
9026 0x60, 0x96, 0xEE, 0x82, 0x82, 0x98, 0x80, 0x42, 0x7E, 0x98, 0x64, 0xE4,
9027 0x04, 0x01, 0x2D, 0xC8,
9028 0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01,
9029 0x05, 0x05, 0x86, 0x98,
9030 0x7E, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6,
9031 0x3C, 0x04, 0x06, 0xA6,
9032 0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33, 0x25, 0x00, 0xC2, 0x88,
9033 0x7C, 0x95, 0x32, 0x83,
9034 0x60, 0x96, 0x32, 0x83, 0x04, 0x01, 0x10, 0xCE, 0x07, 0xC8, 0x05, 0x05,
9035 0xEB, 0x04, 0x00, 0x33,
9036 0x00, 0x20, 0xC0, 0x20, 0x81, 0x62, 0x72, 0x83, 0x00, 0x01, 0x05, 0x05,
9037 0xFF, 0xA2, 0x7A, 0x03,
9038 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83, 0x05, 0x05, 0x15, 0x01,
9039 0x00, 0xA2, 0x9A, 0x03,
9040 0xEC, 0x00, 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00,
9041 0x01, 0xA6, 0x96, 0x03,
9042 0x00, 0xA6, 0x96, 0x03, 0x10, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6,
9043 0xA4, 0x03, 0x00, 0xA6,
9044 0xBC, 0x03, 0x10, 0x84, 0xA8, 0x98, 0x80, 0x42, 0x01, 0xA6, 0xA4, 0x03,
9045 0x07, 0xA6, 0xB2, 0x03,
9046 0xD4, 0x83, 0x7C, 0x95, 0xA8, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC2, 0x88,
9047 0xA8, 0x98, 0x80, 0x42,
9048 0x00, 0xA6, 0xBC, 0x03, 0x07, 0xA6, 0xCA, 0x03, 0xD4, 0x83, 0x7C, 0x95,
9049 0xC0, 0x83, 0x00, 0x33,
9050 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, 0x04, 0x23,
9051 0xA0, 0x01, 0x12, 0x23,
9052 0xA1, 0x01, 0x10, 0x84, 0x07, 0xF0, 0x06, 0xA4, 0xF4, 0x03, 0x80, 0x6B,
9053 0x80, 0x67, 0x05, 0x23,
9054 0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x0E, 0x04, 0x07, 0xA6, 0x06, 0x04,
9055 0x06, 0xA6, 0x0A, 0x04,
9056 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0xF4, 0x83, 0x60, 0x96,
9057 0xF4, 0x83, 0x20, 0x84,
9058 0x07, 0xF0, 0x06, 0xA4, 0x20, 0x04, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23,
9059 0x83, 0x03, 0x80, 0x63,
9060 0xB6, 0x2D, 0x03, 0xA6, 0x3C, 0x04, 0x07, 0xA6, 0x34, 0x04, 0x06, 0xA6,
9061 0x38, 0x04, 0x00, 0x33,
9062 0x30, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x20, 0x84, 0x60, 0x96, 0x20, 0x84,
9063 0x1D, 0x01, 0x06, 0xCC,
9064 0x00, 0x33, 0x00, 0x84, 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62,
9065 0xA2, 0x0D, 0x80, 0x63,
9066 0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03,
9067 0x80, 0x63, 0xA3, 0x01,
9068 0x07, 0xA4, 0x64, 0x04, 0x23, 0x01, 0x00, 0xA2, 0x86, 0x04, 0x0A, 0xA0,
9069 0x76, 0x04, 0xE0, 0x00,
9070 0x00, 0x33, 0x1D, 0x00, 0xC2, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00,
9071 0x00, 0x33, 0x1E, 0x00,
9072 0xC2, 0x88, 0x42, 0x23, 0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04,
9073 0x08, 0x23, 0x22, 0xA3,
9074 0xA2, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xAE, 0x04, 0x02, 0x23, 0x22, 0xA3,
9075 0xC4, 0x04, 0x42, 0x23,
9076 0xF8, 0x88, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23,
9077 0xF8, 0x88, 0x04, 0x98,
9078 0x00, 0xA2, 0xC0, 0x04, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20,
9079 0x81, 0x62, 0xE8, 0x81,
9080 0x47, 0x23, 0xF8, 0x88, 0x04, 0x01, 0x0B, 0xDE, 0x04, 0x98, 0xB4, 0x98,
9081 0x00, 0x33, 0x00, 0x81,
9082 0xC0, 0x20, 0x81, 0x62, 0x14, 0x01, 0x00, 0xA0, 0x00, 0x02, 0x43, 0x23,
9083 0xF8, 0x88, 0x04, 0x23,
9084 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3,
9085 0xF4, 0x04, 0x00, 0x33,
9086 0x27, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01,
9087 0x04, 0x23, 0xA0, 0x01,
9088 0x04, 0x98, 0x26, 0x95, 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00,
9089 0x00, 0xA3, 0x22, 0x05,
9090 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x1C, 0x05, 0x0A, 0x85,
9091 0x46, 0x97, 0xCD, 0x04,
9092 0x24, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23,
9093 0x82, 0x01, 0x34, 0x85,
9094 0x02, 0x23, 0xA0, 0x01, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x40, 0x05,
9095 0x1D, 0x01, 0x04, 0xD6,
9096 0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01,
9097 0x49, 0x00, 0x81, 0x01,
9098 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01, 0xF7, 0x04, 0x03, 0x01,
9099 0x49, 0x04, 0x80, 0x01,
9100 0xC9, 0x00, 0x00, 0x05, 0x00, 0x01, 0xFF, 0xA0, 0x60, 0x05, 0x77, 0x04,
9101 0x01, 0x23, 0xEA, 0x00,
9102 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63,
9103 0x07, 0xA4, 0xF8, 0x05,
9104 0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85, 0x00, 0x33, 0x2D, 0x00,
9105 0xC2, 0x88, 0x04, 0xA0,
9106 0xB8, 0x05, 0x80, 0x63, 0x00, 0x23, 0xDF, 0x00, 0x4A, 0x00, 0x06, 0x61,
9107 0x00, 0xA2, 0xA4, 0x05,
9108 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00,
9109 0x62, 0x97, 0x04, 0x85,
9110 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0x04, 0x85, 0x08, 0xA0, 0xBE, 0x05,
9111 0xF4, 0x85, 0x03, 0xA0,
9112 0xC4, 0x05, 0xF4, 0x85, 0x01, 0xA0, 0xCE, 0x05, 0x88, 0x00, 0x80, 0x63,
9113 0xCC, 0x86, 0x07, 0xA0,
9114 0xEE, 0x05, 0x5F, 0x00, 0x00, 0x2B, 0xDF, 0x08, 0x00, 0xA2, 0xE6, 0x05,
9115 0x80, 0x67, 0x80, 0x63,
9116 0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23, 0x68, 0x98, 0x48, 0x23,
9117 0xF8, 0x88, 0x07, 0x23,
9118 0x80, 0x00, 0x06, 0x87, 0x80, 0x63, 0x7C, 0x85, 0x00, 0x23, 0xDF, 0x00,
9119 0x00, 0x63, 0x4A, 0x00,
9120 0x06, 0x61, 0x00, 0xA2, 0x36, 0x06, 0x1D, 0x01, 0x16, 0xD4, 0xC0, 0x23,
9121 0x07, 0x41, 0x83, 0x03,
9122 0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33, 0x37, 0x00, 0xC2, 0x88,
9123 0x1D, 0x01, 0x01, 0xD6,
9124 0x20, 0x23, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x02, 0x23, 0xDF, 0x00,
9125 0x07, 0xA6, 0x7C, 0x05,
9126 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00,
9127 0x52, 0x00, 0x06, 0x61,
9128 0x00, 0xA2, 0x4E, 0x06, 0x1D, 0x01, 0x03, 0xCA, 0xC0, 0x23, 0x07, 0x41,
9129 0x00, 0x63, 0x1D, 0x01,
9130 0x04, 0xCC, 0x00, 0x33, 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23,
9131 0x07, 0x41, 0x00, 0x63,
9132 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x01, 0x23,
9133 0xDF, 0x00, 0x06, 0xA6,
9134 0x84, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x80, 0x63, 0x00, 0x33,
9135 0x00, 0x40, 0xC0, 0x20,
9136 0x81, 0x62, 0x00, 0x63, 0x00, 0x00, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63,
9137 0x06, 0xA6, 0x94, 0x06,
9138 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x00, 0x01, 0xA0, 0x14, 0x07, 0x00, 0x2B,
9139 0x40, 0x0E, 0x80, 0x63,
9140 0x01, 0x00, 0x06, 0xA6, 0xAA, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x40, 0x0E,
9141 0x80, 0x63, 0x00, 0x43,
9142 0x00, 0xA0, 0xA2, 0x06, 0x06, 0xA6, 0xBC, 0x06, 0x07, 0xA6, 0x7C, 0x05,
9143 0x80, 0x67, 0x40, 0x0E,
9144 0x80, 0x63, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63,
9145 0x07, 0xA6, 0xD6, 0x06,
9146 0x00, 0x33, 0x2A, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x80, 0x63, 0x89, 0x00,
9147 0x0A, 0x2B, 0x07, 0xA6,
9148 0xE8, 0x06, 0x00, 0x33, 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, 0x00, 0xA2,
9149 0xF4, 0x06, 0xC0, 0x0E,
9150 0x80, 0x63, 0xDE, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20,
9151 0x81, 0x62, 0x04, 0x01,
9152 0x02, 0xDA, 0x80, 0x63, 0x7C, 0x85, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6,
9153 0x8C, 0x06, 0x00, 0x33,
9154 0x2C, 0x00, 0xC2, 0x88, 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03,
9155 0x80, 0x63, 0x06, 0xA6,
9156 0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88,
9157 0x00, 0x00, 0x80, 0x67,
9158 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x44, 0x07, 0x07, 0xA6, 0x7C, 0x05,
9159 0xBF, 0x23, 0x04, 0x61,
9160 0x84, 0x01, 0xE6, 0x84, 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00,
9161 0x00, 0x01, 0xF2, 0x00,
9162 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04,
9163 0x80, 0x05, 0x81, 0x05,
9164 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x01, 0x01, 0xF1, 0x00,
9165 0x70, 0x00, 0x81, 0x01,
9166 0x70, 0x04, 0x71, 0x00, 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04,
9167 0x70, 0x00, 0x80, 0x01,
9168 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01,
9169 0xF1, 0x00, 0x70, 0x00,
9170 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01, 0x72, 0x00, 0x81, 0x01,
9171 0x71, 0x04, 0x70, 0x00,
9172 0x81, 0x01, 0x70, 0x04, 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05,
9173 0xA3, 0x01, 0xA2, 0x01,
9174 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1,
9175 0xC4, 0x07, 0x00, 0x33,
9176 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8,
9177 0x48, 0x00, 0xB0, 0x01,
9178 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43,
9179 0x00, 0xA2, 0xE4, 0x07,
9180 0x00, 0x05, 0xDA, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01,
9181 0x05, 0x05, 0x00, 0x63,
9182 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x80, 0x43,
9183 0x76, 0x08, 0x80, 0x02,
9184 0x77, 0x04, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04,
9185 0x00, 0x02, 0x00, 0xA0,
9186 0x14, 0x08, 0x16, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04,
9187 0x00, 0x63, 0xF3, 0x04,
9188 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43, 0xF4, 0x00, 0xCF, 0x40,
9189 0x00, 0xA2, 0x44, 0x08,
9190 0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1,
9191 0x24, 0x08, 0x04, 0x98,
9192 0x26, 0x95, 0x24, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04,
9193 0x5A, 0x88, 0x02, 0x01,
9194 0x04, 0xD8, 0x46, 0x97, 0x04, 0x98, 0x26, 0x95, 0x4A, 0x88, 0x75, 0x00,
9195 0x00, 0xA3, 0x64, 0x08,
9196 0x00, 0x05, 0x4E, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63,
9197 0x06, 0xA6, 0x76, 0x08,
9198 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63,
9199 0x00, 0x63, 0x38, 0x2B,
9200 0x9C, 0x88, 0x38, 0x2B, 0x92, 0x88, 0x32, 0x09, 0x31, 0x05, 0x92, 0x98,
9201 0x05, 0x05, 0xB2, 0x09,
9202 0x00, 0x63, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63,
9203 0x80, 0x32, 0x80, 0x36,
9204 0x80, 0x3A, 0x80, 0x3E, 0xB4, 0x3D, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32,
9205 0x40, 0x36, 0x40, 0x3A,
9206 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0xB4, 0x08,
9207 0x5D, 0x00, 0xFE, 0xC3,
9208 0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73,
9209 0xFF, 0xFD, 0x80, 0x73,
9210 0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01,
9211 0xA1, 0x23, 0xA1, 0x01,
9212 0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2,
9213 0x80, 0x00, 0x03, 0xC2,
9214 0xF1, 0xC7, 0x41, 0x23, 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23,
9215 0xA0, 0x01, 0xE6, 0x84,
Linus Torvalds1da177e2005-04-16 15:20:36 -07009216};
9217
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009218static ushort _asc_mcode_size = sizeof(_asc_mcode_buf);
9219static ADV_DCNT _asc_mcode_chksum = 0x012C453FUL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009220
9221#define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009222static uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = {
9223 INQUIRY,
9224 REQUEST_SENSE,
9225 READ_CAPACITY,
9226 READ_TOC,
9227 MODE_SELECT,
9228 MODE_SENSE,
9229 MODE_SELECT_10,
9230 MODE_SENSE_10,
9231 0xFF,
9232 0xFF,
9233 0xFF,
9234 0xFF,
9235 0xFF,
9236 0xFF,
9237 0xFF,
9238 0xFF
Linus Torvalds1da177e2005-04-16 15:20:36 -07009239};
9240
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009241static int AscExeScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009242{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009243 PortAddr iop_base;
9244 ulong last_int_level;
9245 int sta;
9246 int n_q_required;
9247 int disable_syn_offset_one_fix;
9248 int i;
9249 ASC_PADDR addr;
9250 ASC_EXE_CALLBACK asc_exe_callback;
9251 ushort sg_entry_cnt = 0;
9252 ushort sg_entry_cnt_minus_one = 0;
9253 uchar target_ix;
9254 uchar tid_no;
9255 uchar sdtr_data;
9256 uchar extra_bytes;
9257 uchar scsi_cmd;
9258 uchar disable_cmd;
9259 ASC_SG_HEAD *sg_head;
9260 ASC_DCNT data_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009261
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009262 iop_base = asc_dvc->iop_base;
9263 sg_head = scsiq->sg_head;
9264 asc_exe_callback = asc_dvc->exe_callback;
9265 if (asc_dvc->err_code != 0)
9266 return (ERR);
9267 if (scsiq == (ASC_SCSI_Q *)0L) {
9268 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_NULL_PTR);
9269 return (ERR);
9270 }
9271 scsiq->q1.q_no = 0;
9272 if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
9273 scsiq->q1.extra_bytes = 0;
9274 }
9275 sta = 0;
9276 target_ix = scsiq->q2.target_ix;
9277 tid_no = ASC_TIX_TO_TID(target_ix);
9278 n_q_required = 1;
9279 if (scsiq->cdbptr[0] == REQUEST_SENSE) {
9280 if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
9281 asc_dvc->sdtr_done &= ~scsiq->q1.target_id;
9282 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
9283 AscMsgOutSDTR(asc_dvc,
9284 asc_dvc->
9285 sdtr_period_tbl[(sdtr_data >> 4) &
9286 (uchar)(asc_dvc->
9287 max_sdtr_index -
9288 1)],
9289 (uchar)(sdtr_data & (uchar)
9290 ASC_SYN_MAX_OFFSET));
9291 scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
9292 }
9293 }
9294 last_int_level = DvcEnterCritical();
9295 if (asc_dvc->in_critical_cnt != 0) {
9296 DvcLeaveCritical(last_int_level);
9297 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY);
9298 return (ERR);
9299 }
9300 asc_dvc->in_critical_cnt++;
9301 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
9302 if ((sg_entry_cnt = sg_head->entry_cnt) == 0) {
9303 asc_dvc->in_critical_cnt--;
9304 DvcLeaveCritical(last_int_level);
9305 return (ERR);
9306 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009307#if !CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009308 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
9309 asc_dvc->in_critical_cnt--;
9310 DvcLeaveCritical(last_int_level);
9311 return (ERR);
9312 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009313#endif /* !CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009314 if (sg_entry_cnt == 1) {
9315 scsiq->q1.data_addr =
9316 (ADV_PADDR)sg_head->sg_list[0].addr;
9317 scsiq->q1.data_cnt =
9318 (ADV_DCNT)sg_head->sg_list[0].bytes;
9319 scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
9320 }
9321 sg_entry_cnt_minus_one = sg_entry_cnt - 1;
9322 }
9323 scsi_cmd = scsiq->cdbptr[0];
9324 disable_syn_offset_one_fix = FALSE;
9325 if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) &&
9326 !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) {
9327 if (scsiq->q1.cntl & QC_SG_HEAD) {
9328 data_cnt = 0;
9329 for (i = 0; i < sg_entry_cnt; i++) {
9330 data_cnt +=
9331 (ADV_DCNT)le32_to_cpu(sg_head->sg_list[i].
9332 bytes);
9333 }
9334 } else {
9335 data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
9336 }
9337 if (data_cnt != 0UL) {
9338 if (data_cnt < 512UL) {
9339 disable_syn_offset_one_fix = TRUE;
9340 } else {
9341 for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST;
9342 i++) {
9343 disable_cmd =
9344 _syn_offset_one_disable_cmd[i];
9345 if (disable_cmd == 0xFF) {
9346 break;
9347 }
9348 if (scsi_cmd == disable_cmd) {
9349 disable_syn_offset_one_fix =
9350 TRUE;
9351 break;
9352 }
9353 }
9354 }
9355 }
9356 }
9357 if (disable_syn_offset_one_fix) {
9358 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
9359 scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX |
9360 ASC_TAG_FLAG_DISABLE_DISCONNECT);
9361 } else {
9362 scsiq->q2.tag_code &= 0x27;
9363 }
9364 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
9365 if (asc_dvc->bug_fix_cntl) {
9366 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
9367 if ((scsi_cmd == READ_6) ||
9368 (scsi_cmd == READ_10)) {
9369 addr =
9370 (ADV_PADDR)le32_to_cpu(sg_head->
9371 sg_list
9372 [sg_entry_cnt_minus_one].
9373 addr) +
9374 (ADV_DCNT)le32_to_cpu(sg_head->
9375 sg_list
9376 [sg_entry_cnt_minus_one].
9377 bytes);
9378 extra_bytes =
9379 (uchar)((ushort)addr & 0x0003);
9380 if ((extra_bytes != 0)
9381 &&
9382 ((scsiq->q2.
9383 tag_code &
9384 ASC_TAG_FLAG_EXTRA_BYTES)
9385 == 0)) {
9386 scsiq->q2.tag_code |=
9387 ASC_TAG_FLAG_EXTRA_BYTES;
9388 scsiq->q1.extra_bytes =
9389 extra_bytes;
9390 data_cnt =
9391 le32_to_cpu(sg_head->
9392 sg_list
9393 [sg_entry_cnt_minus_one].
9394 bytes);
9395 data_cnt -=
9396 (ASC_DCNT) extra_bytes;
9397 sg_head->
9398 sg_list
9399 [sg_entry_cnt_minus_one].
9400 bytes =
9401 cpu_to_le32(data_cnt);
9402 }
9403 }
9404 }
9405 }
9406 sg_head->entry_to_copy = sg_head->entry_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009407#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009408 /*
9409 * Set the sg_entry_cnt to the maximum possible. The rest of
9410 * the SG elements will be copied when the RISC completes the
9411 * SG elements that fit and halts.
9412 */
9413 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
9414 sg_entry_cnt = ASC_MAX_SG_LIST;
9415 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009416#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009417 n_q_required = AscSgListToQueue(sg_entry_cnt);
9418 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
9419 (uint) n_q_required)
9420 || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
9421 if ((sta =
9422 AscSendScsiQueue(asc_dvc, scsiq,
9423 n_q_required)) == 1) {
9424 asc_dvc->in_critical_cnt--;
9425 if (asc_exe_callback != 0) {
9426 (*asc_exe_callback) (asc_dvc, scsiq);
9427 }
9428 DvcLeaveCritical(last_int_level);
9429 return (sta);
9430 }
9431 }
9432 } else {
9433 if (asc_dvc->bug_fix_cntl) {
9434 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
9435 if ((scsi_cmd == READ_6) ||
9436 (scsi_cmd == READ_10)) {
9437 addr =
9438 le32_to_cpu(scsiq->q1.data_addr) +
9439 le32_to_cpu(scsiq->q1.data_cnt);
9440 extra_bytes =
9441 (uchar)((ushort)addr & 0x0003);
9442 if ((extra_bytes != 0)
9443 &&
9444 ((scsiq->q2.
9445 tag_code &
9446 ASC_TAG_FLAG_EXTRA_BYTES)
9447 == 0)) {
9448 data_cnt =
9449 le32_to_cpu(scsiq->q1.
9450 data_cnt);
9451 if (((ushort)data_cnt & 0x01FF)
9452 == 0) {
9453 scsiq->q2.tag_code |=
9454 ASC_TAG_FLAG_EXTRA_BYTES;
9455 data_cnt -= (ASC_DCNT)
9456 extra_bytes;
9457 scsiq->q1.data_cnt =
9458 cpu_to_le32
9459 (data_cnt);
9460 scsiq->q1.extra_bytes =
9461 extra_bytes;
9462 }
9463 }
9464 }
9465 }
9466 }
9467 n_q_required = 1;
9468 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) ||
9469 ((scsiq->q1.cntl & QC_URGENT) != 0)) {
9470 if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
9471 n_q_required)) == 1) {
9472 asc_dvc->in_critical_cnt--;
9473 if (asc_exe_callback != 0) {
9474 (*asc_exe_callback) (asc_dvc, scsiq);
9475 }
9476 DvcLeaveCritical(last_int_level);
9477 return (sta);
9478 }
9479 }
9480 }
9481 asc_dvc->in_critical_cnt--;
9482 DvcLeaveCritical(last_int_level);
9483 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009484}
9485
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009486static int
9487AscSendScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar n_q_required)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009488{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009489 PortAddr iop_base;
9490 uchar free_q_head;
9491 uchar next_qp;
9492 uchar tid_no;
9493 uchar target_ix;
9494 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009495
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009496 iop_base = asc_dvc->iop_base;
9497 target_ix = scsiq->q2.target_ix;
9498 tid_no = ASC_TIX_TO_TID(target_ix);
9499 sta = 0;
9500 free_q_head = (uchar)AscGetVarFreeQHead(iop_base);
9501 if (n_q_required > 1) {
9502 if ((next_qp = AscAllocMultipleFreeQueue(iop_base,
9503 free_q_head, (uchar)
9504 (n_q_required)))
9505 != (uchar)ASC_QLINK_END) {
9506 asc_dvc->last_q_shortage = 0;
9507 scsiq->sg_head->queue_cnt = n_q_required - 1;
9508 scsiq->q1.q_no = free_q_head;
9509 if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq,
9510 free_q_head)) == 1) {
9511 AscPutVarFreeQHead(iop_base, next_qp);
9512 asc_dvc->cur_total_qng += (uchar)(n_q_required);
9513 asc_dvc->cur_dvc_qng[tid_no]++;
9514 }
9515 return (sta);
9516 }
9517 } else if (n_q_required == 1) {
9518 if ((next_qp = AscAllocFreeQueue(iop_base,
9519 free_q_head)) !=
9520 ASC_QLINK_END) {
9521 scsiq->q1.q_no = free_q_head;
9522 if ((sta = AscPutReadyQueue(asc_dvc, scsiq,
9523 free_q_head)) == 1) {
9524 AscPutVarFreeQHead(iop_base, next_qp);
9525 asc_dvc->cur_total_qng++;
9526 asc_dvc->cur_dvc_qng[tid_no]++;
9527 }
9528 return (sta);
9529 }
9530 }
9531 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009532}
9533
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009534static int AscSgListToQueue(int sg_list)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009535{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009536 int n_sg_list_qs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009537
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009538 n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q);
9539 if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0)
9540 n_sg_list_qs++;
9541 return (n_sg_list_qs + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009542}
9543
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009544static uint
9545AscGetNumOfFreeQueue(ASC_DVC_VAR *asc_dvc, uchar target_ix, uchar n_qs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009546{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009547 uint cur_used_qs;
9548 uint cur_free_qs;
9549 ASC_SCSI_BIT_ID_TYPE target_id;
9550 uchar tid_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009551
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009552 target_id = ASC_TIX_TO_TARGET_ID(target_ix);
9553 tid_no = ASC_TIX_TO_TID(target_ix);
9554 if ((asc_dvc->unit_not_ready & target_id) ||
9555 (asc_dvc->queue_full_or_busy & target_id)) {
9556 return (0);
9557 }
9558 if (n_qs == 1) {
9559 cur_used_qs = (uint) asc_dvc->cur_total_qng +
9560 (uint) asc_dvc->last_q_shortage + (uint) ASC_MIN_FREE_Q;
9561 } else {
9562 cur_used_qs = (uint) asc_dvc->cur_total_qng +
9563 (uint) ASC_MIN_FREE_Q;
9564 }
9565 if ((uint) (cur_used_qs + n_qs) <= (uint) asc_dvc->max_total_qng) {
9566 cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs;
9567 if (asc_dvc->cur_dvc_qng[tid_no] >=
9568 asc_dvc->max_dvc_qng[tid_no]) {
9569 return (0);
9570 }
9571 return (cur_free_qs);
9572 }
9573 if (n_qs > 1) {
9574 if ((n_qs > asc_dvc->last_q_shortage)
9575 && (n_qs <= (asc_dvc->max_total_qng - ASC_MIN_FREE_Q))) {
9576 asc_dvc->last_q_shortage = n_qs;
9577 }
9578 }
9579 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009580}
9581
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009582static int AscPutReadyQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009583{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009584 ushort q_addr;
9585 uchar tid_no;
9586 uchar sdtr_data;
9587 uchar syn_period_ix;
9588 uchar syn_offset;
9589 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009590
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009591 iop_base = asc_dvc->iop_base;
9592 if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) &&
9593 ((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) {
9594 tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix);
9595 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
9596 syn_period_ix =
9597 (sdtr_data >> 4) & (asc_dvc->max_sdtr_index - 1);
9598 syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET;
9599 AscMsgOutSDTR(asc_dvc,
9600 asc_dvc->sdtr_period_tbl[syn_period_ix],
9601 syn_offset);
9602 scsiq->q1.cntl |= QC_MSG_OUT;
9603 }
9604 q_addr = ASC_QNO_TO_QADDR(q_no);
9605 if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) {
9606 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
9607 }
9608 scsiq->q1.status = QS_FREE;
9609 AscMemWordCopyPtrToLram(iop_base,
9610 q_addr + ASC_SCSIQ_CDB_BEG,
9611 (uchar *)scsiq->cdbptr, scsiq->q2.cdb_len >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009612
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009613 DvcPutScsiQ(iop_base,
9614 q_addr + ASC_SCSIQ_CPY_BEG,
9615 (uchar *)&scsiq->q1.cntl,
9616 ((sizeof(ASC_SCSIQ_1) + sizeof(ASC_SCSIQ_2)) / 2) - 1);
9617 AscWriteLramWord(iop_base,
9618 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS),
9619 (ushort)(((ushort)scsiq->q1.
9620 q_no << 8) | (ushort)QS_READY));
9621 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009622}
9623
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009624static int
9625AscPutReadySgListQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009626{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009627 int sta;
9628 int i;
9629 ASC_SG_HEAD *sg_head;
9630 ASC_SG_LIST_Q scsi_sg_q;
9631 ASC_DCNT saved_data_addr;
9632 ASC_DCNT saved_data_cnt;
9633 PortAddr iop_base;
9634 ushort sg_list_dwords;
9635 ushort sg_index;
9636 ushort sg_entry_cnt;
9637 ushort q_addr;
9638 uchar next_qp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009639
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009640 iop_base = asc_dvc->iop_base;
9641 sg_head = scsiq->sg_head;
9642 saved_data_addr = scsiq->q1.data_addr;
9643 saved_data_cnt = scsiq->q1.data_cnt;
9644 scsiq->q1.data_addr = (ASC_PADDR) sg_head->sg_list[0].addr;
9645 scsiq->q1.data_cnt = (ASC_DCNT) sg_head->sg_list[0].bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009646#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009647 /*
9648 * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST
9649 * then not all SG elements will fit in the allocated queues.
9650 * The rest of the SG elements will be copied when the RISC
9651 * completes the SG elements that fit and halts.
9652 */
9653 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
9654 /*
9655 * Set sg_entry_cnt to be the number of SG elements that
9656 * will fit in the allocated SG queues. It is minus 1, because
9657 * the first SG element is handled above. ASC_MAX_SG_LIST is
9658 * already inflated by 1 to account for this. For example it
9659 * may be 50 which is 1 + 7 queues * 7 SG elements.
9660 */
9661 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009662
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009663 /*
9664 * Keep track of remaining number of SG elements that will
9665 * need to be handled from a_isr.c.
9666 */
9667 scsiq->remain_sg_entry_cnt =
9668 sg_head->entry_cnt - ASC_MAX_SG_LIST;
9669 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009670#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009671 /*
9672 * Set sg_entry_cnt to be the number of SG elements that
9673 * will fit in the allocated SG queues. It is minus 1, because
9674 * the first SG element is handled above.
9675 */
9676 sg_entry_cnt = sg_head->entry_cnt - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009677#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009678 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009679#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009680 if (sg_entry_cnt != 0) {
9681 scsiq->q1.cntl |= QC_SG_HEAD;
9682 q_addr = ASC_QNO_TO_QADDR(q_no);
9683 sg_index = 1;
9684 scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
9685 scsi_sg_q.sg_head_qp = q_no;
9686 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
9687 for (i = 0; i < sg_head->queue_cnt; i++) {
9688 scsi_sg_q.seq_no = i + 1;
9689 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
9690 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
9691 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
9692 if (i == 0) {
9693 scsi_sg_q.sg_list_cnt =
9694 ASC_SG_LIST_PER_Q;
9695 scsi_sg_q.sg_cur_list_cnt =
9696 ASC_SG_LIST_PER_Q;
9697 } else {
9698 scsi_sg_q.sg_list_cnt =
9699 ASC_SG_LIST_PER_Q - 1;
9700 scsi_sg_q.sg_cur_list_cnt =
9701 ASC_SG_LIST_PER_Q - 1;
9702 }
9703 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009704#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009705 /*
9706 * This is the last SG queue in the list of
9707 * allocated SG queues. If there are more
9708 * SG elements than will fit in the allocated
9709 * queues, then set the QCSG_SG_XFER_MORE flag.
9710 */
9711 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
9712 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
9713 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009714#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009715 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009716#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009717 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009718#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009719 sg_list_dwords = sg_entry_cnt << 1;
9720 if (i == 0) {
9721 scsi_sg_q.sg_list_cnt = sg_entry_cnt;
9722 scsi_sg_q.sg_cur_list_cnt =
9723 sg_entry_cnt;
9724 } else {
9725 scsi_sg_q.sg_list_cnt =
9726 sg_entry_cnt - 1;
9727 scsi_sg_q.sg_cur_list_cnt =
9728 sg_entry_cnt - 1;
9729 }
9730 sg_entry_cnt = 0;
9731 }
9732 next_qp = AscReadLramByte(iop_base,
9733 (ushort)(q_addr +
9734 ASC_SCSIQ_B_FWD));
9735 scsi_sg_q.q_no = next_qp;
9736 q_addr = ASC_QNO_TO_QADDR(next_qp);
9737 AscMemWordCopyPtrToLram(iop_base,
9738 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
9739 (uchar *)&scsi_sg_q,
9740 sizeof(ASC_SG_LIST_Q) >> 1);
9741 AscMemDWordCopyPtrToLram(iop_base,
9742 q_addr + ASC_SGQ_LIST_BEG,
9743 (uchar *)&sg_head->
9744 sg_list[sg_index],
9745 sg_list_dwords);
9746 sg_index += ASC_SG_LIST_PER_Q;
9747 scsiq->next_sg_index = sg_index;
9748 }
9749 } else {
9750 scsiq->q1.cntl &= ~QC_SG_HEAD;
9751 }
9752 sta = AscPutReadyQueue(asc_dvc, scsiq, q_no);
9753 scsiq->q1.data_addr = saved_data_addr;
9754 scsiq->q1.data_cnt = saved_data_cnt;
9755 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009756}
9757
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009758static int
9759AscSetRunChipSynRegAtID(PortAddr iop_base, uchar tid_no, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009760{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009761 int sta = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009762
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009763 if (AscHostReqRiscHalt(iop_base)) {
9764 sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
9765 AscStartChip(iop_base);
9766 return (sta);
9767 }
9768 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009769}
9770
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009771static int AscSetChipSynRegAtID(PortAddr iop_base, uchar id, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009772{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009773 ASC_SCSI_BIT_ID_TYPE org_id;
9774 int i;
9775 int sta = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009776
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009777 AscSetBank(iop_base, 1);
9778 org_id = AscReadChipDvcID(iop_base);
9779 for (i = 0; i <= ASC_MAX_TID; i++) {
9780 if (org_id == (0x01 << i))
9781 break;
9782 }
9783 org_id = (ASC_SCSI_BIT_ID_TYPE) i;
9784 AscWriteChipDvcID(iop_base, id);
9785 if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
9786 AscSetBank(iop_base, 0);
9787 AscSetChipSyn(iop_base, sdtr_data);
9788 if (AscGetChipSyn(iop_base) != sdtr_data) {
9789 sta = FALSE;
9790 }
9791 } else {
9792 sta = FALSE;
9793 }
9794 AscSetBank(iop_base, 1);
9795 AscWriteChipDvcID(iop_base, org_id);
9796 AscSetBank(iop_base, 0);
9797 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009798}
9799
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009800static ushort AscInitLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009801{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009802 uchar i;
9803 ushort s_addr;
9804 PortAddr iop_base;
9805 ushort warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009806
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009807 iop_base = asc_dvc->iop_base;
9808 warn_code = 0;
9809 AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0,
9810 (ushort)(((int)(asc_dvc->max_total_qng + 2 + 1) *
9811 64) >> 1)
9812 );
9813 i = ASC_MIN_ACTIVE_QNO;
9814 s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE;
9815 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
9816 (uchar)(i + 1));
9817 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
9818 (uchar)(asc_dvc->max_total_qng));
9819 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
9820 (uchar)i);
9821 i++;
9822 s_addr += ASC_QBLK_SIZE;
9823 for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) {
9824 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
9825 (uchar)(i + 1));
9826 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
9827 (uchar)(i - 1));
9828 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
9829 (uchar)i);
9830 }
9831 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
9832 (uchar)ASC_QLINK_END);
9833 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
9834 (uchar)(asc_dvc->max_total_qng - 1));
9835 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
9836 (uchar)asc_dvc->max_total_qng);
9837 i++;
9838 s_addr += ASC_QBLK_SIZE;
9839 for (; i <= (uchar)(asc_dvc->max_total_qng + 3);
9840 i++, s_addr += ASC_QBLK_SIZE) {
9841 AscWriteLramByte(iop_base,
9842 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_FWD), i);
9843 AscWriteLramByte(iop_base,
9844 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_BWD), i);
9845 AscWriteLramByte(iop_base,
9846 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_QNO), i);
9847 }
9848 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009849}
9850
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009851static ushort AscInitQLinkVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009852{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009853 PortAddr iop_base;
9854 int i;
9855 ushort lram_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009856
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009857 iop_base = asc_dvc->iop_base;
9858 AscPutRiscVarFreeQHead(iop_base, 1);
9859 AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng);
9860 AscPutVarFreeQHead(iop_base, 1);
9861 AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng);
9862 AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B,
9863 (uchar)((int)asc_dvc->max_total_qng + 1));
9864 AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B,
9865 (uchar)((int)asc_dvc->max_total_qng + 2));
9866 AscWriteLramByte(iop_base, (ushort)ASCV_TOTAL_READY_Q_B,
9867 asc_dvc->max_total_qng);
9868 AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0);
9869 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
9870 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
9871 AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0);
9872 AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0);
9873 AscPutQDoneInProgress(iop_base, 0);
9874 lram_addr = ASC_QADR_BEG;
9875 for (i = 0; i < 32; i++, lram_addr += 2) {
9876 AscWriteLramWord(iop_base, lram_addr, 0);
9877 }
9878 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009879}
9880
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009881static int AscSetLibErrorCode(ASC_DVC_VAR *asc_dvc, ushort err_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009882{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009883 if (asc_dvc->err_code == 0) {
9884 asc_dvc->err_code = err_code;
9885 AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W,
9886 err_code);
9887 }
9888 return (err_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009889}
9890
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009891static uchar
9892AscMsgOutSDTR(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar sdtr_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009893{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009894 EXT_MSG sdtr_buf;
9895 uchar sdtr_period_index;
9896 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009897
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009898 iop_base = asc_dvc->iop_base;
Matthew Wilcox47d853c2007-07-26 11:41:33 -04009899 sdtr_buf.msg_type = EXTENDED_MESSAGE;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009900 sdtr_buf.msg_len = MS_SDTR_LEN;
Matthew Wilcox47d853c2007-07-26 11:41:33 -04009901 sdtr_buf.msg_req = EXTENDED_SDTR;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009902 sdtr_buf.xfer_period = sdtr_period;
9903 sdtr_offset &= ASC_SYN_MAX_OFFSET;
9904 sdtr_buf.req_ack_offset = sdtr_offset;
9905 if ((sdtr_period_index =
9906 AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <=
9907 asc_dvc->max_sdtr_index) {
9908 AscMemWordCopyPtrToLram(iop_base,
9909 ASCV_MSGOUT_BEG,
9910 (uchar *)&sdtr_buf,
9911 sizeof(EXT_MSG) >> 1);
9912 return ((sdtr_period_index << 4) | sdtr_offset);
9913 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009914
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009915 sdtr_buf.req_ack_offset = 0;
9916 AscMemWordCopyPtrToLram(iop_base,
9917 ASCV_MSGOUT_BEG,
9918 (uchar *)&sdtr_buf,
9919 sizeof(EXT_MSG) >> 1);
9920 return (0);
9921 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009922}
9923
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009924static uchar
9925AscCalSDTRData(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar syn_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009926{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009927 uchar byte;
9928 uchar sdtr_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009929
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009930 sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
9931 if ((sdtr_period_ix > asc_dvc->max_sdtr_index)
9932 ) {
9933 return (0xFF);
9934 }
9935 byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET);
9936 return (byte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009937}
9938
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009939static void AscSetChipSDTR(PortAddr iop_base, uchar sdtr_data, uchar tid_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009940{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009941 AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
9942 AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data);
9943 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009944}
9945
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009946static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *asc_dvc, uchar syn_time)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009947{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009948 uchar *period_table;
9949 int max_index;
9950 int min_index;
9951 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009952
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009953 period_table = asc_dvc->sdtr_period_tbl;
9954 max_index = (int)asc_dvc->max_sdtr_index;
9955 min_index = (int)asc_dvc->host_init_sdtr_index;
9956 if ((syn_time <= period_table[max_index])) {
9957 for (i = min_index; i < (max_index - 1); i++) {
9958 if (syn_time <= period_table[i]) {
9959 return ((uchar)i);
9960 }
9961 }
9962 return ((uchar)max_index);
9963 } else {
9964 return ((uchar)(max_index + 1));
9965 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009966}
9967
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009968static uchar AscAllocFreeQueue(PortAddr iop_base, uchar free_q_head)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009969{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009970 ushort q_addr;
9971 uchar next_qp;
9972 uchar q_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009973
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009974 q_addr = ASC_QNO_TO_QADDR(free_q_head);
9975 q_status = (uchar)AscReadLramByte(iop_base,
9976 (ushort)(q_addr +
9977 ASC_SCSIQ_B_STATUS));
9978 next_qp = AscReadLramByte(iop_base, (ushort)(q_addr + ASC_SCSIQ_B_FWD));
9979 if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END)) {
9980 return (next_qp);
9981 }
9982 return (ASC_QLINK_END);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009983}
9984
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009985static uchar
9986AscAllocMultipleFreeQueue(PortAddr iop_base, uchar free_q_head, uchar n_free_q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009987{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009988 uchar i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009989
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009990 for (i = 0; i < n_free_q; i++) {
9991 if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head))
9992 == ASC_QLINK_END) {
9993 return (ASC_QLINK_END);
9994 }
9995 }
9996 return (free_q_head);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009997}
9998
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009999static int AscHostReqRiscHalt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010000{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010001 int count = 0;
10002 int sta = 0;
10003 uchar saved_stop_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010004
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010005 if (AscIsChipHalted(iop_base))
10006 return (1);
10007 saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
10008 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
10009 ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP);
10010 do {
10011 if (AscIsChipHalted(iop_base)) {
10012 sta = 1;
10013 break;
10014 }
10015 DvcSleepMilliSecond(100);
10016 } while (count++ < 20);
10017 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code);
10018 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010019}
10020
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010021static int AscStopQueueExe(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010022{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010023 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010024
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010025 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) {
10026 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
10027 ASC_STOP_REQ_RISC_STOP);
10028 do {
10029 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) &
10030 ASC_STOP_ACK_RISC_STOP) {
10031 return (1);
10032 }
10033 DvcSleepMilliSecond(100);
10034 } while (count++ < 20);
10035 }
10036 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010037}
10038
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010039static void DvcDelayMicroSecond(ADV_DVC_VAR *asc_dvc, ushort micro_sec)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010040{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010041 udelay(micro_sec);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010042}
10043
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010044static void DvcDelayNanoSecond(ASC_DVC_VAR *asc_dvc, ASC_DCNT nano_sec)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010045{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010046 udelay((nano_sec + 999) / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010047}
10048
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010049static int AscStartChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010050{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010051 AscSetChipControl(iop_base, 0);
10052 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
10053 return (0);
10054 }
10055 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010056}
10057
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010058static int AscStopChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010059{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010060 uchar cc_val;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010061
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010062 cc_val =
10063 AscGetChipControl(iop_base) &
10064 (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG));
10065 AscSetChipControl(iop_base, (uchar)(cc_val | CC_HALT));
10066 AscSetChipIH(iop_base, INS_HALT);
10067 AscSetChipIH(iop_base, INS_RFLAG_WTM);
10068 if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) {
10069 return (0);
10070 }
10071 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010072}
10073
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010074static int AscIsChipHalted(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010075{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010076 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
10077 if ((AscGetChipControl(iop_base) & CC_HALT) != 0) {
10078 return (1);
10079 }
10080 }
10081 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010082}
10083
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010084static void AscSetChipIH(PortAddr iop_base, ushort ins_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010085{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010086 AscSetBank(iop_base, 1);
10087 AscWriteChipIH(iop_base, ins_code);
10088 AscSetBank(iop_base, 0);
10089 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010090}
10091
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010092static void AscAckInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010093{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010094 uchar host_flag;
10095 uchar risc_flag;
10096 ushort loop;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010097
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010098 loop = 0;
10099 do {
10100 risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B);
10101 if (loop++ > 0x7FFF) {
10102 break;
10103 }
10104 } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0);
10105 host_flag =
10106 AscReadLramByte(iop_base,
10107 ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT);
10108 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
10109 (uchar)(host_flag | ASC_HOST_FLAG_ACK_INT));
10110 AscSetChipStatus(iop_base, CIW_INT_ACK);
10111 loop = 0;
10112 while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) {
10113 AscSetChipStatus(iop_base, CIW_INT_ACK);
10114 if (loop++ > 3) {
10115 break;
10116 }
10117 }
10118 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
10119 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010120}
10121
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010122static void AscDisableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010123{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010124 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010125
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010126 cfg = AscGetChipCfgLsw(iop_base);
10127 AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON));
10128 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010129}
10130
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010131static void AscEnableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010132{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010133 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010134
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010135 cfg = AscGetChipCfgLsw(iop_base);
10136 AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON);
10137 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010138}
10139
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010140static void AscSetBank(PortAddr iop_base, uchar bank)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010141{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010142 uchar val;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010143
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010144 val = AscGetChipControl(iop_base) &
10145 (~
10146 (CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET |
10147 CC_CHIP_RESET));
10148 if (bank == 1) {
10149 val |= CC_BANK_ONE;
10150 } else if (bank == 2) {
10151 val |= CC_DIAG | CC_BANK_ONE;
10152 } else {
10153 val &= ~CC_BANK_ONE;
10154 }
10155 AscSetChipControl(iop_base, val);
10156 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010157}
10158
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010159static int AscResetChipAndScsiBus(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010160{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010161 PortAddr iop_base;
10162 int i = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010163
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010164 iop_base = asc_dvc->iop_base;
10165 while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE)
10166 && (i-- > 0)) {
10167 DvcSleepMilliSecond(100);
10168 }
10169 AscStopChip(iop_base);
10170 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
10171 DvcDelayNanoSecond(asc_dvc, 60000);
10172 AscSetChipIH(iop_base, INS_RFLAG_WTM);
10173 AscSetChipIH(iop_base, INS_HALT);
10174 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT);
10175 AscSetChipControl(iop_base, CC_HALT);
10176 DvcSleepMilliSecond(200);
10177 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
10178 AscSetChipStatus(iop_base, 0);
10179 return (AscIsChipHalted(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010180}
10181
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010182static ASC_DCNT __devinit AscGetMaxDmaCount(ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010183{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010184 if (bus_type & ASC_IS_ISA)
10185 return (ASC_MAX_ISA_DMA_COUNT);
10186 else if (bus_type & (ASC_IS_EISA | ASC_IS_VL))
10187 return (ASC_MAX_VL_DMA_COUNT);
10188 return (ASC_MAX_PCI_DMA_COUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010189}
10190
10191#ifdef CONFIG_ISA
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010192static ushort __devinit AscGetIsaDmaChannel(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010193{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010194 ushort channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010195
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010196 channel = AscGetChipCfgLsw(iop_base) & 0x0003;
10197 if (channel == 0x03)
10198 return (0);
10199 else if (channel == 0x00)
10200 return (7);
10201 return (channel + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010202}
10203
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010204static ushort __devinit AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010205{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010206 ushort cfg_lsw;
10207 uchar value;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010208
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010209 if ((dma_channel >= 5) && (dma_channel <= 7)) {
10210 if (dma_channel == 7)
10211 value = 0x00;
10212 else
10213 value = dma_channel - 4;
10214 cfg_lsw = AscGetChipCfgLsw(iop_base) & 0xFFFC;
10215 cfg_lsw |= value;
10216 AscSetChipCfgLsw(iop_base, cfg_lsw);
10217 return (AscGetIsaDmaChannel(iop_base));
10218 }
10219 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010220}
10221
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010222static uchar __devinit AscSetIsaDmaSpeed(PortAddr iop_base, uchar speed_value)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010223{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010224 speed_value &= 0x07;
10225 AscSetBank(iop_base, 1);
10226 AscWriteChipDmaSpeed(iop_base, speed_value);
10227 AscSetBank(iop_base, 0);
10228 return (AscGetIsaDmaSpeed(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010229}
10230
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010231static uchar __devinit AscGetIsaDmaSpeed(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010232{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010233 uchar speed_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010234
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010235 AscSetBank(iop_base, 1);
10236 speed_value = AscReadChipDmaSpeed(iop_base);
10237 speed_value &= 0x07;
10238 AscSetBank(iop_base, 0);
10239 return (speed_value);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010240}
10241#endif /* CONFIG_ISA */
10242
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010243static ushort __devinit AscInitGetConfig(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010244{
Matthew Wilcox9649af32007-07-26 21:51:47 -060010245 unsigned short warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010246
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010247 asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG;
Matthew Wilcox9649af32007-07-26 21:51:47 -060010248 if (asc_dvc->err_code != 0)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010249 return (UW_ERR);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010250
Matthew Wilcox9649af32007-07-26 21:51:47 -060010251 if (AscFindSignature(asc_dvc->iop_base)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010252 warn_code |= AscInitAscDvcVar(asc_dvc);
10253 warn_code |= AscInitFromEEP(asc_dvc);
10254 asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG;
Matthew Wilcoxecec1942007-07-30 08:08:22 -060010255 if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010256 asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010257 } else {
10258 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10259 }
Matthew Wilcoxecec1942007-07-30 08:08:22 -060010260 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010261}
10262
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010263static ushort __devinit AscInitSetConfig(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010264{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010265 ushort warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010266
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010267 asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG;
10268 if (asc_dvc->err_code != 0)
10269 return (UW_ERR);
10270 if (AscFindSignature(asc_dvc->iop_base)) {
10271 warn_code |= AscInitFromAscDvcVar(asc_dvc);
10272 asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG;
10273 } else {
10274 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10275 }
10276 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010277}
10278
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010279static ushort __devinit AscInitFromAscDvcVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010280{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010281 PortAddr iop_base;
10282 ushort cfg_msw;
10283 ushort warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010284
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010285 iop_base = asc_dvc->iop_base;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010286 warn_code = 0;
10287 cfg_msw = AscGetChipCfgMsw(iop_base);
10288 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
10289 cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
10290 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
10291 AscSetChipCfgMsw(iop_base, cfg_msw);
10292 }
10293 if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) !=
10294 asc_dvc->cfg->cmd_qng_enabled) {
10295 asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled;
10296 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
10297 }
10298 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
10299 warn_code |= ASC_WARN_AUTO_CONFIG;
10300 }
10301 if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) {
10302 if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type)
10303 != asc_dvc->irq_no) {
10304 asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO;
10305 }
10306 }
Matthew Wilcox9649af32007-07-26 21:51:47 -060010307#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010308 if (asc_dvc->bus_type & ASC_IS_PCI) {
Matthew Wilcox9649af32007-07-26 21:51:47 -060010309 struct pci_dev *pdev = to_pci_dev(asc_dvc->cfg->dev);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010310 cfg_msw &= 0xFFC0;
10311 AscSetChipCfgMsw(iop_base, cfg_msw);
10312 if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
10313 } else {
Matthew Wilcox9649af32007-07-26 21:51:47 -060010314 if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) ||
10315 (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010316 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
10317 asc_dvc->bug_fix_cntl |=
10318 ASC_BUG_FIX_ASYN_USE_SYN;
10319 }
10320 }
Matthew Wilcox9649af32007-07-26 21:51:47 -060010321 } else
10322#endif /* CONFIG_PCI */
10323 if (asc_dvc->bus_type == ASC_IS_ISAPNP) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010324 if (AscGetChipVersion(iop_base, asc_dvc->bus_type)
10325 == ASC_CHIP_VER_ASYN_BUG) {
10326 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
10327 }
10328 }
10329 if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) !=
10330 asc_dvc->cfg->chip_scsi_id) {
10331 asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID;
10332 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010333#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010334 if (asc_dvc->bus_type & ASC_IS_ISA) {
10335 AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel);
10336 AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed);
10337 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010338#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010339 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010340}
10341
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010342static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010343{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010344 ushort warn_code;
10345 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010346
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010347 iop_base = asc_dvc->iop_base;
10348 warn_code = 0;
10349 if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
10350 !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
10351 AscResetChipAndScsiBus(asc_dvc);
10352 DvcSleepMilliSecond((ASC_DCNT)
10353 ((ushort)asc_dvc->scsi_reset_wait * 1000));
10354 }
10355 asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
10356 if (asc_dvc->err_code != 0)
10357 return (UW_ERR);
10358 if (!AscFindSignature(asc_dvc->iop_base)) {
10359 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10360 return (warn_code);
10361 }
10362 AscDisableInterrupt(iop_base);
10363 warn_code |= AscInitLram(asc_dvc);
10364 if (asc_dvc->err_code != 0)
10365 return (UW_ERR);
10366 ASC_DBG1(1, "AscInitAsc1000Driver: _asc_mcode_chksum 0x%lx\n",
10367 (ulong)_asc_mcode_chksum);
10368 if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf,
10369 _asc_mcode_size) != _asc_mcode_chksum) {
10370 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
10371 return (warn_code);
10372 }
10373 warn_code |= AscInitMicroCodeVar(asc_dvc);
10374 asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
10375 AscEnableInterrupt(iop_base);
10376 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010377}
10378
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010379static ushort __devinit AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010380{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010381 int i;
10382 PortAddr iop_base;
10383 ushort warn_code;
10384 uchar chip_version;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010385
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010386 iop_base = asc_dvc->iop_base;
10387 warn_code = 0;
10388 asc_dvc->err_code = 0;
10389 if ((asc_dvc->bus_type &
10390 (ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0) {
10391 asc_dvc->err_code |= ASC_IERR_NO_BUS_TYPE;
10392 }
10393 AscSetChipControl(iop_base, CC_HALT);
10394 AscSetChipStatus(iop_base, 0);
10395 asc_dvc->bug_fix_cntl = 0;
10396 asc_dvc->pci_fix_asyn_xfer = 0;
10397 asc_dvc->pci_fix_asyn_xfer_always = 0;
10398 /* asc_dvc->init_state initalized in AscInitGetConfig(). */
10399 asc_dvc->sdtr_done = 0;
10400 asc_dvc->cur_total_qng = 0;
10401 asc_dvc->is_in_int = 0;
10402 asc_dvc->in_critical_cnt = 0;
10403 asc_dvc->last_q_shortage = 0;
10404 asc_dvc->use_tagged_qng = 0;
10405 asc_dvc->no_scam = 0;
10406 asc_dvc->unit_not_ready = 0;
10407 asc_dvc->queue_full_or_busy = 0;
10408 asc_dvc->redo_scam = 0;
10409 asc_dvc->res2 = 0;
10410 asc_dvc->host_init_sdtr_index = 0;
10411 asc_dvc->cfg->can_tagged_qng = 0;
10412 asc_dvc->cfg->cmd_qng_enabled = 0;
10413 asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
10414 asc_dvc->init_sdtr = 0;
10415 asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG;
10416 asc_dvc->scsi_reset_wait = 3;
10417 asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET;
10418 asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
10419 asc_dvc->cfg->sdtr_enable = ASC_SCSI_WIDTH_BIT_SET;
10420 asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
10421 asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID;
10422 asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER;
10423 asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) |
10424 ASC_LIB_VERSION_MINOR;
10425 chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type);
10426 asc_dvc->cfg->chip_version = chip_version;
10427 asc_dvc->sdtr_period_tbl[0] = SYN_XFER_NS_0;
10428 asc_dvc->sdtr_period_tbl[1] = SYN_XFER_NS_1;
10429 asc_dvc->sdtr_period_tbl[2] = SYN_XFER_NS_2;
10430 asc_dvc->sdtr_period_tbl[3] = SYN_XFER_NS_3;
10431 asc_dvc->sdtr_period_tbl[4] = SYN_XFER_NS_4;
10432 asc_dvc->sdtr_period_tbl[5] = SYN_XFER_NS_5;
10433 asc_dvc->sdtr_period_tbl[6] = SYN_XFER_NS_6;
10434 asc_dvc->sdtr_period_tbl[7] = SYN_XFER_NS_7;
10435 asc_dvc->max_sdtr_index = 7;
10436 if ((asc_dvc->bus_type & ASC_IS_PCI) &&
10437 (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3150)) {
10438 asc_dvc->bus_type = ASC_IS_PCI_ULTRA;
10439 asc_dvc->sdtr_period_tbl[0] = SYN_ULTRA_XFER_NS_0;
10440 asc_dvc->sdtr_period_tbl[1] = SYN_ULTRA_XFER_NS_1;
10441 asc_dvc->sdtr_period_tbl[2] = SYN_ULTRA_XFER_NS_2;
10442 asc_dvc->sdtr_period_tbl[3] = SYN_ULTRA_XFER_NS_3;
10443 asc_dvc->sdtr_period_tbl[4] = SYN_ULTRA_XFER_NS_4;
10444 asc_dvc->sdtr_period_tbl[5] = SYN_ULTRA_XFER_NS_5;
10445 asc_dvc->sdtr_period_tbl[6] = SYN_ULTRA_XFER_NS_6;
10446 asc_dvc->sdtr_period_tbl[7] = SYN_ULTRA_XFER_NS_7;
10447 asc_dvc->sdtr_period_tbl[8] = SYN_ULTRA_XFER_NS_8;
10448 asc_dvc->sdtr_period_tbl[9] = SYN_ULTRA_XFER_NS_9;
10449 asc_dvc->sdtr_period_tbl[10] = SYN_ULTRA_XFER_NS_10;
10450 asc_dvc->sdtr_period_tbl[11] = SYN_ULTRA_XFER_NS_11;
10451 asc_dvc->sdtr_period_tbl[12] = SYN_ULTRA_XFER_NS_12;
10452 asc_dvc->sdtr_period_tbl[13] = SYN_ULTRA_XFER_NS_13;
10453 asc_dvc->sdtr_period_tbl[14] = SYN_ULTRA_XFER_NS_14;
10454 asc_dvc->sdtr_period_tbl[15] = SYN_ULTRA_XFER_NS_15;
10455 asc_dvc->max_sdtr_index = 15;
10456 if (chip_version == ASC_CHIP_VER_PCI_ULTRA_3150) {
10457 AscSetExtraControl(iop_base,
10458 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
10459 } else if (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3050) {
10460 AscSetExtraControl(iop_base,
10461 (SEC_ACTIVE_NEGATE |
10462 SEC_ENABLE_FILTER));
10463 }
10464 }
10465 if (asc_dvc->bus_type == ASC_IS_PCI) {
10466 AscSetExtraControl(iop_base,
10467 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
10468 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010469
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010470 asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED;
10471 if (AscGetChipBusType(iop_base) == ASC_IS_ISAPNP) {
10472 AscSetChipIFC(iop_base, IFC_INIT_DEFAULT);
10473 asc_dvc->bus_type = ASC_IS_ISAPNP;
10474 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010475#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010476 if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) {
10477 asc_dvc->cfg->isa_dma_channel =
10478 (uchar)AscGetIsaDmaChannel(iop_base);
10479 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010480#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010481 for (i = 0; i <= ASC_MAX_TID; i++) {
10482 asc_dvc->cur_dvc_qng[i] = 0;
10483 asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG;
10484 asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q *)0L;
10485 asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q *)0L;
10486 asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG;
10487 }
10488 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010489}
10490
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010491static ushort __devinit AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010492{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010493 ASCEEP_CONFIG eep_config_buf;
10494 ASCEEP_CONFIG *eep_config;
10495 PortAddr iop_base;
10496 ushort chksum;
10497 ushort warn_code;
10498 ushort cfg_msw, cfg_lsw;
10499 int i;
10500 int write_eep = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010501
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010502 iop_base = asc_dvc->iop_base;
10503 warn_code = 0;
10504 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE);
10505 AscStopQueueExe(iop_base);
10506 if ((AscStopChip(iop_base) == FALSE) ||
10507 (AscGetChipScsiCtrl(iop_base) != 0)) {
10508 asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
10509 AscResetChipAndScsiBus(asc_dvc);
10510 DvcSleepMilliSecond((ASC_DCNT)
10511 ((ushort)asc_dvc->scsi_reset_wait * 1000));
10512 }
10513 if (AscIsChipHalted(iop_base) == FALSE) {
10514 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
10515 return (warn_code);
10516 }
10517 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
10518 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
10519 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
10520 return (warn_code);
10521 }
10522 eep_config = (ASCEEP_CONFIG *)&eep_config_buf;
10523 cfg_msw = AscGetChipCfgMsw(iop_base);
10524 cfg_lsw = AscGetChipCfgLsw(iop_base);
10525 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
10526 cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
10527 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
10528 AscSetChipCfgMsw(iop_base, cfg_msw);
10529 }
10530 chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
10531 ASC_DBG1(1, "AscInitFromEEP: chksum 0x%x\n", chksum);
10532 if (chksum == 0) {
10533 chksum = 0xaa55;
10534 }
10535 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
10536 warn_code |= ASC_WARN_AUTO_CONFIG;
10537 if (asc_dvc->cfg->chip_version == 3) {
10538 if (eep_config->cfg_lsw != cfg_lsw) {
10539 warn_code |= ASC_WARN_EEPROM_RECOVER;
10540 eep_config->cfg_lsw =
10541 AscGetChipCfgLsw(iop_base);
10542 }
10543 if (eep_config->cfg_msw != cfg_msw) {
10544 warn_code |= ASC_WARN_EEPROM_RECOVER;
10545 eep_config->cfg_msw =
10546 AscGetChipCfgMsw(iop_base);
10547 }
10548 }
10549 }
10550 eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
10551 eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
10552 ASC_DBG1(1, "AscInitFromEEP: eep_config->chksum 0x%x\n",
10553 eep_config->chksum);
10554 if (chksum != eep_config->chksum) {
10555 if (AscGetChipVersion(iop_base, asc_dvc->bus_type) ==
10556 ASC_CHIP_VER_PCI_ULTRA_3050) {
10557 ASC_DBG(1,
10558 "AscInitFromEEP: chksum error ignored; EEPROM-less board\n");
10559 eep_config->init_sdtr = 0xFF;
10560 eep_config->disc_enable = 0xFF;
10561 eep_config->start_motor = 0xFF;
10562 eep_config->use_cmd_qng = 0;
10563 eep_config->max_total_qng = 0xF0;
10564 eep_config->max_tag_qng = 0x20;
10565 eep_config->cntl = 0xBFFF;
10566 ASC_EEP_SET_CHIP_ID(eep_config, 7);
10567 eep_config->no_scam = 0;
10568 eep_config->adapter_info[0] = 0;
10569 eep_config->adapter_info[1] = 0;
10570 eep_config->adapter_info[2] = 0;
10571 eep_config->adapter_info[3] = 0;
10572 eep_config->adapter_info[4] = 0;
10573 /* Indicate EEPROM-less board. */
10574 eep_config->adapter_info[5] = 0xBB;
10575 } else {
10576 ASC_PRINT
10577 ("AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n");
10578 write_eep = 1;
10579 warn_code |= ASC_WARN_EEPROM_CHKSUM;
10580 }
10581 }
10582 asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr;
10583 asc_dvc->cfg->disc_enable = eep_config->disc_enable;
10584 asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
10585 asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config);
10586 asc_dvc->start_motor = eep_config->start_motor;
10587 asc_dvc->dvc_cntl = eep_config->cntl;
10588 asc_dvc->no_scam = eep_config->no_scam;
10589 asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0];
10590 asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1];
10591 asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2];
10592 asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3];
10593 asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4];
10594 asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5];
10595 if (!AscTestExternalLram(asc_dvc)) {
10596 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) ==
10597 ASC_IS_PCI_ULTRA)) {
10598 eep_config->max_total_qng =
10599 ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
10600 eep_config->max_tag_qng =
10601 ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG;
10602 } else {
10603 eep_config->cfg_msw |= 0x0800;
10604 cfg_msw |= 0x0800;
10605 AscSetChipCfgMsw(iop_base, cfg_msw);
10606 eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
10607 eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG;
10608 }
10609 } else {
10610 }
10611 if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) {
10612 eep_config->max_total_qng = ASC_MIN_TOTAL_QNG;
10613 }
10614 if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) {
10615 eep_config->max_total_qng = ASC_MAX_TOTAL_QNG;
10616 }
10617 if (eep_config->max_tag_qng > eep_config->max_total_qng) {
10618 eep_config->max_tag_qng = eep_config->max_total_qng;
10619 }
10620 if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) {
10621 eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC;
10622 }
10623 asc_dvc->max_total_qng = eep_config->max_total_qng;
10624 if ((eep_config->use_cmd_qng & eep_config->disc_enable) !=
10625 eep_config->use_cmd_qng) {
10626 eep_config->disc_enable = eep_config->use_cmd_qng;
10627 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
10628 }
10629 if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
10630 asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
10631 }
10632 ASC_EEP_SET_CHIP_ID(eep_config,
10633 ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID);
10634 asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config);
10635 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) &&
10636 !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
10637 asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
10638 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010639
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010640 for (i = 0; i <= ASC_MAX_TID; i++) {
10641 asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
10642 asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
10643 asc_dvc->cfg->sdtr_period_offset[i] =
10644 (uchar)(ASC_DEF_SDTR_OFFSET |
10645 (asc_dvc->host_init_sdtr_index << 4));
10646 }
10647 eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
10648 if (write_eep) {
10649 if ((i =
10650 AscSetEEPConfig(iop_base, eep_config,
10651 asc_dvc->bus_type)) != 0) {
10652 ASC_PRINT1
10653 ("AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n",
10654 i);
10655 } else {
10656 ASC_PRINT
10657 ("AscInitFromEEP: Successfully re-wrote EEPROM.\n");
10658 }
10659 }
10660 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010661}
10662
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010663static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010664{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010665 int i;
10666 ushort warn_code;
10667 PortAddr iop_base;
10668 ASC_PADDR phy_addr;
10669 ASC_DCNT phy_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010670
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010671 iop_base = asc_dvc->iop_base;
10672 warn_code = 0;
10673 for (i = 0; i <= ASC_MAX_TID; i++) {
10674 AscPutMCodeInitSDTRAtID(iop_base, i,
10675 asc_dvc->cfg->sdtr_period_offset[i]
10676 );
10677 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010678
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010679 AscInitQLinkVar(asc_dvc);
10680 AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
10681 asc_dvc->cfg->disc_enable);
10682 AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
10683 ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010684
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010685 /* Align overrun buffer on an 8 byte boundary. */
10686 phy_addr = virt_to_bus(asc_dvc->cfg->overrun_buf);
10687 phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7);
10688 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
10689 (uchar *)&phy_addr, 1);
10690 phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE - 8);
10691 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D,
10692 (uchar *)&phy_size, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010693
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010694 asc_dvc->cfg->mcode_date =
10695 AscReadLramWord(iop_base, (ushort)ASCV_MC_DATE_W);
10696 asc_dvc->cfg->mcode_version =
10697 AscReadLramWord(iop_base, (ushort)ASCV_MC_VER_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010698
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010699 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
10700 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
10701 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
10702 return (warn_code);
10703 }
10704 if (AscStartChip(iop_base) != 1) {
10705 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
10706 return (warn_code);
10707 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010708
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010709 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010710}
10711
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010712static int __devinit AscTestExternalLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010713{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010714 PortAddr iop_base;
10715 ushort q_addr;
10716 ushort saved_word;
10717 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010718
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010719 iop_base = asc_dvc->iop_base;
10720 sta = 0;
10721 q_addr = ASC_QNO_TO_QADDR(241);
10722 saved_word = AscReadLramWord(iop_base, q_addr);
10723 AscSetChipLramAddr(iop_base, q_addr);
10724 AscSetChipLramData(iop_base, 0x55AA);
10725 DvcSleepMilliSecond(10);
10726 AscSetChipLramAddr(iop_base, q_addr);
10727 if (AscGetChipLramData(iop_base) == 0x55AA) {
10728 sta = 1;
10729 AscWriteLramWord(iop_base, q_addr, saved_word);
10730 }
10731 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010732}
10733
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010734static int __devinit AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010735{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010736 uchar read_back;
10737 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010738
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010739 retry = 0;
10740 while (TRUE) {
10741 AscSetChipEEPCmd(iop_base, cmd_reg);
10742 DvcSleepMilliSecond(1);
10743 read_back = AscGetChipEEPCmd(iop_base);
10744 if (read_back == cmd_reg) {
10745 return (1);
10746 }
10747 if (retry++ > ASC_EEP_MAX_RETRY) {
10748 return (0);
10749 }
10750 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010751}
10752
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010753static int __devinit AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010754{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010755 ushort read_back;
10756 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010757
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010758 retry = 0;
10759 while (TRUE) {
10760 AscSetChipEEPData(iop_base, data_reg);
10761 DvcSleepMilliSecond(1);
10762 read_back = AscGetChipEEPData(iop_base);
10763 if (read_back == data_reg) {
10764 return (1);
10765 }
10766 if (retry++ > ASC_EEP_MAX_RETRY) {
10767 return (0);
10768 }
10769 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010770}
10771
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010772static void __devinit AscWaitEEPRead(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010773{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010774 DvcSleepMilliSecond(1);
10775 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010776}
10777
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010778static void __devinit AscWaitEEPWrite(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010779{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010780 DvcSleepMilliSecond(20);
10781 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010782}
10783
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010784static ushort __devinit AscReadEEPWord(PortAddr iop_base, uchar addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010785{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010786 ushort read_wval;
10787 uchar cmd_reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010788
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010789 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
10790 AscWaitEEPRead();
10791 cmd_reg = addr | ASC_EEP_CMD_READ;
10792 AscWriteEEPCmdReg(iop_base, cmd_reg);
10793 AscWaitEEPRead();
10794 read_wval = AscGetChipEEPData(iop_base);
10795 AscWaitEEPRead();
10796 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010797}
10798
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010799static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010800AscWriteEEPWord(PortAddr iop_base, uchar addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010801{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010802 ushort read_wval;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010803
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010804 read_wval = AscReadEEPWord(iop_base, addr);
10805 if (read_wval != word_val) {
10806 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE);
10807 AscWaitEEPRead();
10808 AscWriteEEPDataReg(iop_base, word_val);
10809 AscWaitEEPRead();
10810 AscWriteEEPCmdReg(iop_base,
10811 (uchar)((uchar)ASC_EEP_CMD_WRITE | addr));
10812 AscWaitEEPWrite();
10813 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
10814 AscWaitEEPRead();
10815 return (AscReadEEPWord(iop_base, addr));
10816 }
10817 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010818}
10819
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010820static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010821AscGetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010822{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010823 ushort wval;
10824 ushort sum;
10825 ushort *wbuf;
10826 int cfg_beg;
10827 int cfg_end;
10828 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
10829 int s_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010830
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010831 wbuf = (ushort *)cfg_buf;
10832 sum = 0;
10833 /* Read two config words; Byte-swapping done by AscReadEEPWord(). */
10834 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
10835 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
10836 sum += *wbuf;
10837 }
10838 if (bus_type & ASC_IS_VL) {
10839 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
10840 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
10841 } else {
10842 cfg_beg = ASC_EEP_DVC_CFG_BEG;
10843 cfg_end = ASC_EEP_MAX_DVC_ADDR;
10844 }
10845 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
10846 wval = AscReadEEPWord(iop_base, (uchar)s_addr);
10847 if (s_addr <= uchar_end_in_config) {
10848 /*
10849 * Swap all char fields - must unswap bytes already swapped
10850 * by AscReadEEPWord().
10851 */
10852 *wbuf = le16_to_cpu(wval);
10853 } else {
10854 /* Don't swap word field at the end - cntl field. */
10855 *wbuf = wval;
10856 }
10857 sum += wval; /* Checksum treats all EEPROM data as words. */
10858 }
10859 /*
10860 * Read the checksum word which will be compared against 'sum'
10861 * by the caller. Word field already swapped.
10862 */
10863 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
10864 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010865}
10866
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010867static int __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010868AscSetEEPConfigOnce(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010869{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010870 int n_error;
10871 ushort *wbuf;
10872 ushort word;
10873 ushort sum;
10874 int s_addr;
10875 int cfg_beg;
10876 int cfg_end;
10877 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010878
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010879 wbuf = (ushort *)cfg_buf;
10880 n_error = 0;
10881 sum = 0;
10882 /* Write two config words; AscWriteEEPWord() will swap bytes. */
10883 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
10884 sum += *wbuf;
10885 if (*wbuf != AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
10886 n_error++;
10887 }
10888 }
10889 if (bus_type & ASC_IS_VL) {
10890 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
10891 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
10892 } else {
10893 cfg_beg = ASC_EEP_DVC_CFG_BEG;
10894 cfg_end = ASC_EEP_MAX_DVC_ADDR;
10895 }
10896 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
10897 if (s_addr <= uchar_end_in_config) {
10898 /*
10899 * This is a char field. Swap char fields before they are
10900 * swapped again by AscWriteEEPWord().
10901 */
10902 word = cpu_to_le16(*wbuf);
10903 if (word !=
10904 AscWriteEEPWord(iop_base, (uchar)s_addr, word)) {
10905 n_error++;
10906 }
10907 } else {
10908 /* Don't swap word field at the end - cntl field. */
10909 if (*wbuf !=
10910 AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
10911 n_error++;
10912 }
10913 }
10914 sum += *wbuf; /* Checksum calculated from word values. */
10915 }
10916 /* Write checksum word. It will be swapped by AscWriteEEPWord(). */
10917 *wbuf = sum;
10918 if (sum != AscWriteEEPWord(iop_base, (uchar)s_addr, sum)) {
10919 n_error++;
10920 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010921
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010922 /* Read EEPROM back again. */
10923 wbuf = (ushort *)cfg_buf;
10924 /*
10925 * Read two config words; Byte-swapping done by AscReadEEPWord().
10926 */
10927 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
10928 if (*wbuf != AscReadEEPWord(iop_base, (uchar)s_addr)) {
10929 n_error++;
10930 }
10931 }
10932 if (bus_type & ASC_IS_VL) {
10933 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
10934 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
10935 } else {
10936 cfg_beg = ASC_EEP_DVC_CFG_BEG;
10937 cfg_end = ASC_EEP_MAX_DVC_ADDR;
10938 }
10939 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
10940 if (s_addr <= uchar_end_in_config) {
10941 /*
10942 * Swap all char fields. Must unswap bytes already swapped
10943 * by AscReadEEPWord().
10944 */
10945 word =
10946 le16_to_cpu(AscReadEEPWord
10947 (iop_base, (uchar)s_addr));
10948 } else {
10949 /* Don't swap word field at the end - cntl field. */
10950 word = AscReadEEPWord(iop_base, (uchar)s_addr);
10951 }
10952 if (*wbuf != word) {
10953 n_error++;
10954 }
10955 }
10956 /* Read checksum; Byte swapping not needed. */
10957 if (AscReadEEPWord(iop_base, (uchar)s_addr) != sum) {
10958 n_error++;
10959 }
10960 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010961}
10962
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010963static int __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010964AscSetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010965{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010966 int retry;
10967 int n_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010968
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010969 retry = 0;
10970 while (TRUE) {
10971 if ((n_error = AscSetEEPConfigOnce(iop_base, cfg_buf,
10972 bus_type)) == 0) {
10973 break;
10974 }
10975 if (++retry > ASC_EEP_MAX_RETRY) {
10976 break;
10977 }
10978 }
10979 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010980}
10981
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010982static void AscAsyncFix(ASC_DVC_VAR *asc_dvc, struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010983{
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010984 char type = sdev->type;
10985 ASC_SCSI_BIT_ID_TYPE tid_bits = 1 << sdev->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010986
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010987 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) {
10988 if (!(asc_dvc->init_sdtr & tid_bits)) {
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010989 if ((type == TYPE_ROM) &&
10990 (strncmp(sdev->vendor, "HP ", 3) == 0)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010991 asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
10992 }
10993 asc_dvc->pci_fix_asyn_xfer |= tid_bits;
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010994 if ((type == TYPE_PROCESSOR) ||
10995 (type == TYPE_SCANNER) || (type == TYPE_ROM) ||
10996 (type == TYPE_TAPE)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010997 asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
10998 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010999
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011000 if (asc_dvc->pci_fix_asyn_xfer & tid_bits) {
11001 AscSetRunChipSynRegAtID(asc_dvc->iop_base,
Matthew Wilcox47d853c2007-07-26 11:41:33 -040011002 sdev->id,
11003 ASYN_SDTR_DATA_FIX_PCI_REV_AB);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011004 }
11005 }
11006 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011007}
11008
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011009static uchar AscReadLramByte(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011010{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011011 uchar byte_data;
11012 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011013
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011014 if (isodd_word(addr)) {
11015 AscSetChipLramAddr(iop_base, addr - 1);
11016 word_data = AscGetChipLramData(iop_base);
11017 byte_data = (uchar)((word_data >> 8) & 0xFF);
11018 } else {
11019 AscSetChipLramAddr(iop_base, addr);
11020 word_data = AscGetChipLramData(iop_base);
11021 byte_data = (uchar)(word_data & 0xFF);
11022 }
11023 return (byte_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011024}
Linus Torvalds1da177e2005-04-16 15:20:36 -070011025
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011026static ushort AscReadLramWord(PortAddr iop_base, ushort addr)
11027{
11028 ushort word_data;
11029
11030 AscSetChipLramAddr(iop_base, addr);
11031 word_data = AscGetChipLramData(iop_base);
11032 return (word_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011033}
11034
11035#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011036static ASC_DCNT AscReadLramDWord(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011037{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011038 ushort val_low, val_high;
11039 ASC_DCNT dword_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011040
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011041 AscSetChipLramAddr(iop_base, addr);
11042 val_low = AscGetChipLramData(iop_base);
11043 val_high = AscGetChipLramData(iop_base);
11044 dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low;
11045 return (dword_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011046}
11047#endif /* CC_VERY_LONG_SG_LIST */
11048
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011049static void AscWriteLramWord(PortAddr iop_base, ushort addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011050{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011051 AscSetChipLramAddr(iop_base, addr);
11052 AscSetChipLramData(iop_base, word_val);
11053 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011054}
11055
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011056static void AscWriteLramByte(PortAddr iop_base, ushort addr, uchar byte_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011057{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011058 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011059
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011060 if (isodd_word(addr)) {
11061 addr--;
11062 word_data = AscReadLramWord(iop_base, addr);
11063 word_data &= 0x00FF;
11064 word_data |= (((ushort)byte_val << 8) & 0xFF00);
11065 } else {
11066 word_data = AscReadLramWord(iop_base, addr);
11067 word_data &= 0xFF00;
11068 word_data |= ((ushort)byte_val & 0x00FF);
11069 }
11070 AscWriteLramWord(iop_base, addr, word_data);
11071 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011072}
11073
11074/*
11075 * Copy 2 bytes to LRAM.
11076 *
11077 * The source data is assumed to be in little-endian order in memory
11078 * and is maintained in little-endian order when written to LRAM.
11079 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011080static void
11081AscMemWordCopyPtrToLram(PortAddr iop_base,
11082 ushort s_addr, uchar *s_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011083{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011084 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011085
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011086 AscSetChipLramAddr(iop_base, s_addr);
11087 for (i = 0; i < 2 * words; i += 2) {
11088 /*
11089 * On a little-endian system the second argument below
11090 * produces a little-endian ushort which is written to
11091 * LRAM in little-endian order. On a big-endian system
11092 * the second argument produces a big-endian ushort which
11093 * is "transparently" byte-swapped by outpw() and written
11094 * in little-endian order to LRAM.
11095 */
11096 outpw(iop_base + IOP_RAM_DATA,
11097 ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]);
11098 }
11099 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011100}
11101
11102/*
11103 * Copy 4 bytes to LRAM.
11104 *
11105 * The source data is assumed to be in little-endian order in memory
11106 * and is maintained in little-endian order when writen to LRAM.
11107 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011108static void
11109AscMemDWordCopyPtrToLram(PortAddr iop_base,
11110 ushort s_addr, uchar *s_buffer, int dwords)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011111{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011112 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011113
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011114 AscSetChipLramAddr(iop_base, s_addr);
11115 for (i = 0; i < 4 * dwords; i += 4) {
11116 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]); /* LSW */
11117 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 3] << 8) | s_buffer[i + 2]); /* MSW */
11118 }
11119 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011120}
11121
11122/*
11123 * Copy 2 bytes from LRAM.
11124 *
11125 * The source data is assumed to be in little-endian order in LRAM
11126 * and is maintained in little-endian order when written to memory.
11127 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011128static void
11129AscMemWordCopyPtrFromLram(PortAddr iop_base,
11130 ushort s_addr, uchar *d_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011131{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011132 int i;
11133 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011134
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011135 AscSetChipLramAddr(iop_base, s_addr);
11136 for (i = 0; i < 2 * words; i += 2) {
11137 word = inpw(iop_base + IOP_RAM_DATA);
11138 d_buffer[i] = word & 0xff;
11139 d_buffer[i + 1] = (word >> 8) & 0xff;
11140 }
11141 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011142}
11143
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011144static ASC_DCNT AscMemSumLramWord(PortAddr iop_base, ushort s_addr, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011145{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011146 ASC_DCNT sum;
11147 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011148
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011149 sum = 0L;
11150 for (i = 0; i < words; i++, s_addr += 2) {
11151 sum += AscReadLramWord(iop_base, s_addr);
11152 }
11153 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011154}
11155
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011156static void
11157AscMemWordSetLram(PortAddr iop_base, ushort s_addr, ushort set_wval, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011158{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011159 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011160
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011161 AscSetChipLramAddr(iop_base, s_addr);
11162 for (i = 0; i < words; i++) {
11163 AscSetChipLramData(iop_base, set_wval);
11164 }
11165 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011166}
11167
Linus Torvalds1da177e2005-04-16 15:20:36 -070011168/*
11169 * --- Adv Library Functions
11170 */
11171
11172/* a_mcode.h */
11173
11174/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011175static unsigned char _adv_asc3550_buf[] = {
11176 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x18, 0xe4, 0x00, 0xfc,
11177 0x01, 0x00, 0x48, 0xe4,
11178 0xbe, 0x18, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0x00, 0xfa, 0xff, 0xff,
11179 0x28, 0x0e, 0x9e, 0xe7,
11180 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x00, 0xf6, 0x01, 0xe6, 0x09, 0xe7,
11181 0x55, 0xf0, 0x01, 0xf6,
11182 0x01, 0xfa, 0x08, 0x00, 0x03, 0x00, 0x04, 0x00, 0x18, 0xf4, 0x10, 0x00,
11183 0x00, 0xec, 0x85, 0xf0,
11184 0xbc, 0x00, 0xd5, 0xf0, 0x8e, 0x0c, 0x38, 0x54, 0x00, 0xe6, 0x1e, 0xf0,
11185 0x86, 0xf0, 0xb4, 0x00,
11186 0x98, 0x57, 0xd0, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x0c, 0x00, 0xbb, 0x00,
11187 0xaa, 0x18, 0x02, 0x80,
11188 0x32, 0xf0, 0x01, 0xfc, 0x88, 0x0c, 0xc6, 0x12, 0x02, 0x13, 0x18, 0x40,
11189 0x00, 0x57, 0x01, 0xea,
11190 0x3c, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12, 0x3e, 0x57, 0x00, 0x80,
11191 0x03, 0xe6, 0xb6, 0x00,
11192 0xc0, 0x00, 0x01, 0x01, 0x3e, 0x01, 0xda, 0x0f, 0x22, 0x10, 0x08, 0x12,
11193 0x02, 0x4a, 0xb9, 0x54,
11194 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x20, 0x00, 0x32, 0x00,
11195 0x3e, 0x00, 0x80, 0x00,
11196 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01,
11197 0x74, 0x01, 0x76, 0x01,
11198 0x78, 0x01, 0x62, 0x0a, 0x92, 0x0c, 0x2c, 0x10, 0x2e, 0x10, 0x06, 0x13,
11199 0x4c, 0x1c, 0xbb, 0x55,
11200 0x3c, 0x56, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0xb1, 0xf0,
11201 0x03, 0xf7, 0x06, 0xf7,
11202 0x03, 0xfc, 0x0f, 0x00, 0x40, 0x00, 0xbe, 0x00, 0x00, 0x01, 0xb0, 0x08,
11203 0x30, 0x13, 0x64, 0x15,
11204 0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44, 0x02, 0x48, 0x00, 0x4c,
11205 0x04, 0xea, 0x5d, 0xf0,
11206 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00,
11207 0xcc, 0x00, 0x20, 0x01,
11208 0x4e, 0x01, 0x4e, 0x0b, 0x1e, 0x0e, 0x0c, 0x10, 0x0a, 0x12, 0x04, 0x13,
11209 0x40, 0x13, 0x30, 0x1c,
11210 0x00, 0x4e, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
11211 0x59, 0xf0, 0xa7, 0xf0,
11212 0xb8, 0xf0, 0x0e, 0xf7, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00,
11213 0xa4, 0x00, 0xb5, 0x00,
11214 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xde, 0x03, 0x56, 0x0a,
11215 0x14, 0x0e, 0x02, 0x10,
11216 0x04, 0x10, 0x0a, 0x10, 0x36, 0x10, 0x0a, 0x13, 0x12, 0x13, 0x52, 0x13,
11217 0x10, 0x15, 0x14, 0x15,
11218 0xac, 0x16, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44,
11219 0x91, 0x44, 0x0a, 0x45,
11220 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x83, 0x55, 0xb0, 0x57, 0x01, 0x58,
11221 0x83, 0x59, 0x05, 0xe6,
11222 0x0b, 0xf0, 0x0c, 0xf0, 0x5c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, 0x05, 0xf8,
11223 0x02, 0xfa, 0x03, 0xfa,
11224 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x1c, 0x00,
11225 0x9e, 0x00, 0xa8, 0x00,
11226 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01,
11227 0x7a, 0x01, 0xc0, 0x01,
11228 0xc2, 0x01, 0x7c, 0x02, 0x5a, 0x03, 0xea, 0x04, 0xe8, 0x07, 0x68, 0x08,
11229 0x69, 0x08, 0xba, 0x08,
11230 0xe9, 0x09, 0x06, 0x0b, 0x3a, 0x0e, 0x00, 0x10, 0x1a, 0x10, 0xed, 0x10,
11231 0xf1, 0x10, 0x06, 0x12,
11232 0x0c, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x82, 0x13, 0x42, 0x14, 0xd6, 0x14,
11233 0x8a, 0x15, 0xc6, 0x17,
11234 0xd2, 0x17, 0x6b, 0x18, 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40,
11235 0x0e, 0x47, 0x48, 0x47,
11236 0x41, 0x48, 0x89, 0x48, 0x80, 0x4c, 0x00, 0x54, 0x44, 0x55, 0xe5, 0x55,
11237 0x14, 0x56, 0x77, 0x57,
11238 0xbf, 0x57, 0x40, 0x5c, 0x06, 0x80, 0x08, 0x90, 0x03, 0xa1, 0xfe, 0x9c,
11239 0xf0, 0x29, 0x02, 0xfe,
11240 0xb8, 0x0c, 0xff, 0x10, 0x00, 0x00, 0xd0, 0xfe, 0xcc, 0x18, 0x00, 0xcf,
11241 0xfe, 0x80, 0x01, 0xff,
11242 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
11243 0x00, 0xfe, 0x57, 0x24,
11244 0x00, 0xfe, 0x48, 0x00, 0x4f, 0xff, 0x04, 0x00, 0x00, 0x10, 0xff, 0x09,
11245 0x00, 0x00, 0xff, 0x08,
11246 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
11247 0xff, 0xff, 0xff, 0x0f,
11248 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
11249 0xfe, 0x04, 0xf7, 0xcf,
11250 0x2a, 0x67, 0x0b, 0x01, 0xfe, 0xce, 0x0e, 0xfe, 0x04, 0xf7, 0xcf, 0x67,
11251 0x0b, 0x3c, 0x2a, 0xfe,
11252 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x91, 0xf0,
11253 0xfe, 0xf0, 0x01, 0xfe,
11254 0x90, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, 0x8f, 0xf0, 0x9c, 0x05, 0x51, 0x3b,
11255 0x02, 0xfe, 0xd4, 0x0c,
11256 0x01, 0xfe, 0x44, 0x0d, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
11257 0x1c, 0x05, 0xfe, 0xa6,
11258 0x00, 0xfe, 0xd3, 0x12, 0x47, 0x18, 0xfe, 0xa6, 0x00, 0xb5, 0xfe, 0x48,
11259 0xf0, 0xfe, 0x86, 0x02,
11260 0xfe, 0x49, 0xf0, 0xfe, 0xa0, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xbe, 0x02,
11261 0xfe, 0x46, 0xf0, 0xfe,
11262 0x50, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x56, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
11263 0x44, 0x02, 0xfe, 0x44,
11264 0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x4c, 0x02, 0x17, 0x0b,
11265 0xa0, 0x17, 0x06, 0x18,
11266 0x96, 0x02, 0x29, 0xfe, 0x00, 0x1c, 0xde, 0xfe, 0x02, 0x1c, 0xdd, 0xfe,
11267 0x1e, 0x1c, 0xfe, 0xe9,
11268 0x10, 0x01, 0xfe, 0x20, 0x17, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xc7,
11269 0x0a, 0x6b, 0x01, 0x9e,
11270 0x02, 0x29, 0x14, 0x4d, 0x37, 0x97, 0x01, 0xfe, 0x64, 0x0f, 0x0a, 0x6b,
11271 0x01, 0x82, 0xfe, 0xbd,
11272 0x10, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
11273 0x58, 0x1c, 0x17, 0x06,
11274 0x18, 0x96, 0x2a, 0x25, 0x29, 0xfe, 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0x21,
11275 0xfe, 0x94, 0x02, 0xfe,
11276 0x5a, 0x1c, 0xea, 0xfe, 0x14, 0x1c, 0x14, 0xfe, 0x30, 0x00, 0x37, 0x97,
11277 0x01, 0xfe, 0x54, 0x0f,
11278 0x17, 0x06, 0x18, 0x96, 0x02, 0xd0, 0x1e, 0x20, 0x07, 0x10, 0x34, 0xfe,
11279 0x69, 0x10, 0x17, 0x06,
11280 0x18, 0x96, 0xfe, 0x04, 0xec, 0x20, 0x46, 0x3d, 0x12, 0x20, 0xfe, 0x05,
11281 0xf6, 0xc7, 0x01, 0xfe,
11282 0x52, 0x16, 0x09, 0x4a, 0x4c, 0x35, 0x11, 0x2d, 0x3c, 0x8a, 0x01, 0xe6,
11283 0x02, 0x29, 0x0a, 0x40,
11284 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x01, 0x6f, 0xfe, 0x18, 0x10, 0xfe, 0x41,
11285 0x58, 0x0a, 0x99, 0x01,
11286 0x0e, 0xfe, 0xc8, 0x54, 0x64, 0xfe, 0x0c, 0x03, 0x01, 0xe6, 0x02, 0x29,
11287 0x2a, 0x46, 0xfe, 0x02,
11288 0xe8, 0x27, 0xf8, 0xfe, 0x9e, 0x43, 0xf7, 0xfe, 0x27, 0xf0, 0xfe, 0xdc,
11289 0x01, 0xfe, 0x07, 0x4b,
11290 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x40, 0x1c, 0x25, 0xd2, 0xfe, 0x26, 0xf0,
11291 0xfe, 0x56, 0x03, 0xfe,
11292 0xa0, 0xf0, 0xfe, 0x44, 0x03, 0xfe, 0x11, 0xf0, 0x9c, 0xfe, 0xef, 0x10,
11293 0xfe, 0x9f, 0xf0, 0xfe,
11294 0x64, 0x03, 0xeb, 0x0f, 0xfe, 0x11, 0x00, 0x02, 0x5a, 0x2a, 0xfe, 0x48,
11295 0x1c, 0xeb, 0x09, 0x04,
11296 0x1d, 0xfe, 0x18, 0x13, 0x23, 0x1e, 0x98, 0xac, 0x12, 0x98, 0x0a, 0x40,
11297 0x01, 0x0e, 0xac, 0x75,
11298 0x01, 0xfe, 0xbc, 0x15, 0x11, 0xca, 0x25, 0xd2, 0xfe, 0x01, 0xf0, 0xd2,
11299 0xfe, 0x82, 0xf0, 0xfe,
11300 0x92, 0x03, 0xec, 0x11, 0xfe, 0xe4, 0x00, 0x65, 0xfe, 0xa4, 0x03, 0x25,
11301 0x32, 0x1f, 0xfe, 0xb4,
11302 0x03, 0x01, 0x43, 0xfe, 0x06, 0xf0, 0xfe, 0xc4, 0x03, 0x8d, 0x81, 0xfe,
11303 0x0a, 0xf0, 0xfe, 0x7a,
11304 0x06, 0x02, 0x22, 0x05, 0x6b, 0x28, 0x16, 0xfe, 0xf6, 0x04, 0x14, 0x2c,
11305 0x01, 0x33, 0x8f, 0xfe,
11306 0x66, 0x02, 0x02, 0xd1, 0xeb, 0x2a, 0x67, 0x1a, 0xfe, 0x67, 0x1b, 0xf8,
11307 0xf7, 0xfe, 0x48, 0x1c,
11308 0x70, 0x01, 0x6e, 0x87, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x16, 0xd3,
11309 0x0a, 0xca, 0x01, 0x0e,
11310 0x74, 0x60, 0x59, 0x76, 0x27, 0x05, 0x6b, 0x28, 0xfe, 0x10, 0x12, 0x14,
11311 0x2c, 0x01, 0x33, 0x8f,
11312 0xfe, 0x66, 0x02, 0x02, 0xd1, 0xbc, 0x7d, 0xbd, 0x7f, 0x25, 0x22, 0x65,
11313 0xfe, 0x3c, 0x04, 0x1f,
11314 0xfe, 0x38, 0x04, 0x68, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e,
11315 0x12, 0x2b, 0xff, 0x02,
11316 0x00, 0x10, 0x01, 0x08, 0x1f, 0xfe, 0xe0, 0x04, 0x2b, 0x01, 0x08, 0x1f,
11317 0x22, 0x30, 0x2e, 0xd5,
11318 0xfe, 0x4c, 0x44, 0xfe, 0x4c, 0x12, 0x60, 0xfe, 0x44, 0x48, 0x13, 0x2c,
11319 0xfe, 0x4c, 0x54, 0x64,
11320 0xd3, 0x46, 0x76, 0x27, 0xfa, 0xef, 0xfe, 0x62, 0x13, 0x09, 0x04, 0x1d,
11321 0xfe, 0x2a, 0x13, 0x2f,
11322 0x07, 0x7e, 0xa5, 0xfe, 0x20, 0x10, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64,
11323 0xd3, 0xfa, 0xef, 0x86,
11324 0x09, 0x04, 0x1d, 0xfe, 0x08, 0x13, 0x2f, 0x07, 0x7e, 0x6e, 0x09, 0x04,
11325 0x1d, 0xfe, 0x1c, 0x12,
11326 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe,
11327 0x70, 0x0c, 0x02, 0x22,
11328 0x2b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90, 0xf9, 0x03, 0x14, 0x92,
11329 0x01, 0x33, 0x02, 0x29,
11330 0xfe, 0x42, 0x5b, 0x67, 0x1a, 0xfe, 0x46, 0x59, 0xf8, 0xf7, 0xfe, 0x87,
11331 0x80, 0xfe, 0x31, 0xe4,
11332 0x4f, 0x09, 0x04, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x1a,
11333 0xfe, 0x70, 0x12, 0x49,
11334 0x04, 0x06, 0xfe, 0x60, 0x13, 0x05, 0xfe, 0xa2, 0x00, 0x28, 0x16, 0xfe,
11335 0x80, 0x05, 0xfe, 0x31,
11336 0xe4, 0x6a, 0x49, 0x04, 0x0b, 0xfe, 0x4a, 0x13, 0x05, 0xfe, 0xa0, 0x00,
11337 0x28, 0xfe, 0x42, 0x12,
11338 0x5e, 0x01, 0x08, 0x25, 0x32, 0xf1, 0x01, 0x08, 0x26, 0xfe, 0x98, 0x05,
11339 0x11, 0xfe, 0xe3, 0x00,
11340 0x23, 0x49, 0xfe, 0x4a, 0xf0, 0xfe, 0x6a, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
11341 0x64, 0x05, 0x83, 0x24,
11342 0xfe, 0x21, 0x00, 0xa1, 0x24, 0xfe, 0x22, 0x00, 0xa0, 0x24, 0x4c, 0xfe,
11343 0x09, 0x48, 0x01, 0x08,
11344 0x26, 0xfe, 0x98, 0x05, 0xfe, 0xe2, 0x08, 0x49, 0x04, 0xc5, 0x3b, 0x01,
11345 0x86, 0x24, 0x06, 0x12,
11346 0xcc, 0x37, 0xfe, 0x27, 0x01, 0x09, 0x04, 0x1d, 0xfe, 0x22, 0x12, 0x47,
11347 0x01, 0xa7, 0x14, 0x92,
11348 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c,
11349 0x02, 0x22, 0x05, 0xfe,
11350 0x9c, 0x00, 0x28, 0xfe, 0x3e, 0x12, 0x05, 0x50, 0x28, 0xfe, 0x36, 0x13,
11351 0x47, 0x01, 0xa7, 0x26,
11352 0xfe, 0x08, 0x06, 0x0a, 0x06, 0x49, 0x04, 0x19, 0xfe, 0x02, 0x12, 0x5f,
11353 0x01, 0xfe, 0xaa, 0x14,
11354 0x1f, 0xfe, 0xfe, 0x05, 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00,
11355 0x05, 0x50, 0xb4, 0x0c,
11356 0x50, 0x05, 0xc6, 0x28, 0xfe, 0x62, 0x12, 0x05, 0x3f, 0x28, 0xfe, 0x5a,
11357 0x13, 0x01, 0xfe, 0x14,
11358 0x18, 0x01, 0xfe, 0x66, 0x18, 0xfe, 0x43, 0x48, 0xb7, 0x19, 0x13, 0x6c,
11359 0xff, 0x02, 0x00, 0x57,
11360 0x48, 0x8b, 0x1c, 0x3d, 0x85, 0xb7, 0x69, 0x47, 0x01, 0xa7, 0x26, 0xfe,
11361 0x72, 0x06, 0x49, 0x04,
11362 0x1b, 0xdf, 0x89, 0x0a, 0x4d, 0x01, 0xfe, 0xd8, 0x14, 0x1f, 0xfe, 0x68,
11363 0x06, 0x11, 0x9a, 0x01,
11364 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x3f, 0xb4, 0x0c, 0x3f, 0x17, 0x06,
11365 0x01, 0xa7, 0xec, 0x72,
11366 0x70, 0x01, 0x6e, 0x87, 0x11, 0xfe, 0xe2, 0x00, 0x01, 0x08, 0x25, 0x32,
11367 0xfe, 0x0a, 0xf0, 0xfe,
11368 0xa6, 0x06, 0x8c, 0xfe, 0x5c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, 0x64, 0x07,
11369 0x8d, 0x81, 0x02, 0x22,
11370 0x09, 0x04, 0x0b, 0xfe, 0x2e, 0x12, 0x15, 0x1a, 0x01, 0x08, 0x15, 0x00,
11371 0x01, 0x08, 0x15, 0x00,
11372 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x15,
11373 0x00, 0x02, 0xfe, 0x32,
11374 0x08, 0x61, 0x04, 0x1b, 0xfe, 0x38, 0x12, 0x09, 0x04, 0x1b, 0x6e, 0x15,
11375 0xfe, 0x1b, 0x00, 0x01,
11376 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01,
11377 0x08, 0x15, 0x06, 0x01,
11378 0x08, 0x15, 0x00, 0x02, 0xd9, 0x66, 0x4c, 0xfe, 0x3a, 0x55, 0x5f, 0xfe,
11379 0x9a, 0x81, 0x4b, 0x1d,
11380 0xba, 0xfe, 0x32, 0x07, 0x0a, 0x1d, 0xfe, 0x09, 0x6f, 0xaf, 0xfe, 0xca,
11381 0x45, 0xfe, 0x32, 0x12,
11382 0x62, 0x2c, 0x85, 0x66, 0x7b, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0,
11383 0xfe, 0x32, 0x07, 0x8d,
11384 0x81, 0x8c, 0xfe, 0x5c, 0x07, 0x02, 0x22, 0x01, 0x43, 0x02, 0xfe, 0x8a,
11385 0x06, 0x15, 0x19, 0x02,
11386 0xfe, 0x8a, 0x06, 0xfe, 0x9c, 0xf7, 0xd4, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
11387 0x90, 0x77, 0xfe, 0xca,
11388 0x07, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x4a, 0x6a, 0x35, 0x1e, 0x20, 0x07,
11389 0x10, 0xfe, 0x0e, 0x12,
11390 0x74, 0xfe, 0x80, 0x80, 0x37, 0x20, 0x63, 0x27, 0xfe, 0x06, 0x10, 0xfe,
11391 0x83, 0xe7, 0xc4, 0xa1,
11392 0xfe, 0x03, 0x40, 0x09, 0x4a, 0x4f, 0x35, 0x01, 0xa8, 0xad, 0xfe, 0x1f,
11393 0x40, 0x12, 0x58, 0x01,
11394 0xa5, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6,
11395 0x51, 0x83, 0xfb, 0xfe,
11396 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90,
11397 0xfe, 0x40, 0x50, 0xfe,
11398 0xc2, 0x50, 0x0c, 0x39, 0x18, 0x3a, 0xfe, 0x4a, 0x10, 0x09, 0x04, 0x6a,
11399 0xfe, 0x2a, 0x12, 0xfe,
11400 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x04, 0x4f,
11401 0x85, 0x01, 0xa8, 0xfe,
11402 0x1f, 0x80, 0x12, 0x58, 0xfe, 0x44, 0x90, 0xfe, 0xc6, 0x90, 0x0c, 0x56,
11403 0x18, 0x57, 0xfb, 0xfe,
11404 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90,
11405 0x0c, 0x39, 0x18, 0x3a,
11406 0x0c, 0x38, 0x18, 0x4e, 0x09, 0x4a, 0x19, 0x35, 0x2a, 0x13, 0xfe, 0x4e,
11407 0x11, 0x65, 0xfe, 0x48,
11408 0x08, 0xfe, 0x9e, 0xf0, 0xfe, 0x5c, 0x08, 0xb1, 0x16, 0x32, 0x2a, 0x73,
11409 0xdd, 0xb8, 0xfe, 0x80,
11410 0x08, 0xb9, 0xfe, 0x9e, 0x08, 0x8c, 0xfe, 0x74, 0x08, 0xfe, 0x06, 0xf0,
11411 0xfe, 0x7a, 0x08, 0x8d,
11412 0x81, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xc9, 0x10, 0x15, 0x19, 0xfe, 0xc9,
11413 0x10, 0x61, 0x04, 0x06,
11414 0xfe, 0x10, 0x12, 0x61, 0x04, 0x0b, 0x45, 0x09, 0x04, 0x0b, 0xfe, 0x68,
11415 0x12, 0xfe, 0x2e, 0x1c,
11416 0x02, 0xfe, 0x24, 0x0a, 0x61, 0x04, 0x06, 0x45, 0x61, 0x04, 0x0b, 0xfe,
11417 0x52, 0x12, 0xfe, 0x2c,
11418 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x1e, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0xbe,
11419 0x08, 0xfe, 0x8a, 0x10,
11420 0xaa, 0xfe, 0xf3, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0xca, 0x08, 0x02, 0xfe,
11421 0x24, 0x0a, 0xab, 0xfe,
11422 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0x9d, 0xe9, 0x1c, 0xfe, 0x00, 0xfe, 0xfe,
11423 0x1c, 0x12, 0xb5, 0xfe,
11424 0xd2, 0xf0, 0x9d, 0xfe, 0x76, 0x18, 0x1c, 0x1a, 0x16, 0x9d, 0x05, 0xcb,
11425 0x1c, 0x06, 0x16, 0x9d,
11426 0xb8, 0x6d, 0xb9, 0x6d, 0xaa, 0xab, 0xfe, 0xb1, 0x10, 0x70, 0x5e, 0x2b,
11427 0x14, 0x92, 0x01, 0x33,
11428 0x0f, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x5a, 0x0f, 0x7c, 0x02, 0x5a,
11429 0xfe, 0x74, 0x18, 0x1c,
11430 0xfe, 0x00, 0xf8, 0x16, 0x6d, 0x67, 0x1b, 0x01, 0xfe, 0x44, 0x0d, 0x3b,
11431 0x01, 0xe6, 0x1e, 0x27,
11432 0x74, 0x67, 0x1a, 0x02, 0x6d, 0x09, 0x04, 0x0b, 0x21, 0xfe, 0x06, 0x0a,
11433 0x09, 0x04, 0x6a, 0xfe,
11434 0x82, 0x12, 0x09, 0x04, 0x19, 0xfe, 0x66, 0x13, 0x1e, 0x58, 0xac, 0xfc,
11435 0xfe, 0x83, 0x80, 0xfe,
11436 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x63,
11437 0x27, 0xfe, 0x40, 0x59,
11438 0xfe, 0xc1, 0x59, 0x77, 0xd7, 0x05, 0x54, 0x31, 0x55, 0x0c, 0x7b, 0x18,
11439 0x7c, 0xbe, 0x54, 0xbf,
11440 0x55, 0x01, 0xa8, 0xad, 0x63, 0x27, 0x12, 0x58, 0xc0, 0x38, 0xc1, 0x4e,
11441 0x79, 0x56, 0x68, 0x57,
11442 0xf4, 0xf5, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05, 0xfa, 0x4e, 0x01, 0xa5,
11443 0xa2, 0x23, 0x0c, 0x7b,
11444 0x0c, 0x7c, 0x79, 0x56, 0x68, 0x57, 0xfe, 0x12, 0x10, 0x09, 0x04, 0x19,
11445 0x16, 0xd7, 0x79, 0x39,
11446 0x68, 0x3a, 0x09, 0x04, 0xfe, 0xf7, 0x00, 0x35, 0x05, 0x52, 0x31, 0x53,
11447 0xfe, 0x10, 0x58, 0xfe,
11448 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x02, 0x6d, 0x09, 0x04,
11449 0x19, 0x16, 0xd7, 0x09,
11450 0x04, 0xfe, 0xf7, 0x00, 0x35, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x5f,
11451 0xfe, 0x10, 0x90, 0xfe,
11452 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x2f, 0x07, 0x9b, 0x16, 0xfe, 0xc6, 0x08,
11453 0x11, 0x9b, 0x09, 0x04,
11454 0x0b, 0xfe, 0x14, 0x13, 0x05, 0x39, 0x31, 0x3a, 0x77, 0xfe, 0xc6, 0x08,
11455 0xfe, 0x0c, 0x58, 0xfe,
11456 0x8d, 0x58, 0x02, 0x6d, 0x23, 0x47, 0xfe, 0x19, 0x80, 0xde, 0x09, 0x04,
11457 0x0b, 0xfe, 0x1a, 0x12,
11458 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xe9, 0xb5, 0xfe, 0xd1, 0xf0, 0xd9,
11459 0x14, 0x7a, 0x01, 0x33,
11460 0x0f, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0xbe, 0x39,
11461 0xfe, 0xed, 0x19, 0xbf,
11462 0x3a, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xe9, 0x1c, 0xfe, 0x00, 0xff,
11463 0x34, 0xfe, 0x74, 0x10,
11464 0xb5, 0xfe, 0xd2, 0xf0, 0xfe, 0xb2, 0x0a, 0xfe, 0x76, 0x18, 0x1c, 0x1a,
11465 0x84, 0x05, 0xcb, 0x1c,
11466 0x06, 0xfe, 0x08, 0x13, 0x0f, 0xfe, 0x16, 0x00, 0x02, 0x5a, 0xfe, 0xd1,
11467 0xf0, 0xfe, 0xc4, 0x0a,
11468 0x14, 0x7a, 0x01, 0x33, 0x0f, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe,
11469 0xce, 0xf0, 0xfe, 0xca,
11470 0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x0f, 0xfe,
11471 0x22, 0x00, 0x02, 0x5a,
11472 0xfe, 0xcb, 0xf0, 0xfe, 0xe2, 0x0a, 0x0f, 0xfe, 0x24, 0x00, 0x02, 0x5a,
11473 0xfe, 0xd0, 0xf0, 0xfe,
11474 0xec, 0x0a, 0x0f, 0x93, 0xdc, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x0f,
11475 0x4c, 0xfe, 0x10, 0x10,
11476 0xfe, 0xcc, 0xf0, 0xd9, 0x61, 0x04, 0x19, 0x3b, 0x0f, 0xfe, 0x12, 0x00,
11477 0x2a, 0x13, 0xfe, 0x4e,
11478 0x11, 0x65, 0xfe, 0x0c, 0x0b, 0xfe, 0x9e, 0xf0, 0xfe, 0x20, 0x0b, 0xb1,
11479 0x16, 0x32, 0x2a, 0x73,
11480 0xdd, 0xb8, 0x22, 0xb9, 0x22, 0x2a, 0xec, 0x65, 0xfe, 0x2c, 0x0b, 0x25,
11481 0x32, 0x8c, 0xfe, 0x48,
11482 0x0b, 0x8d, 0x81, 0xb8, 0xd4, 0xb9, 0xd4, 0x02, 0x22, 0x01, 0x43, 0xfe,
11483 0xdb, 0x10, 0x11, 0xfe,
11484 0xe8, 0x00, 0xaa, 0xab, 0x70, 0xbc, 0x7d, 0xbd, 0x7f, 0xfe, 0x89, 0xf0,
11485 0x22, 0x30, 0x2e, 0xd8,
11486 0xbc, 0x7d, 0xbd, 0x7f, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd6, 0xb1,
11487 0x45, 0x0f, 0xfe, 0x42,
11488 0x00, 0x02, 0x5a, 0x78, 0x06, 0xfe, 0x81, 0x49, 0x16, 0xfe, 0x38, 0x0c,
11489 0x09, 0x04, 0x0b, 0xfe,
11490 0x44, 0x13, 0x0f, 0x00, 0x4b, 0x0b, 0xfe, 0x54, 0x12, 0x4b, 0xfe, 0x28,
11491 0x00, 0x21, 0xfe, 0xa6,
11492 0x0c, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x3e, 0xfe, 0x28, 0x00,
11493 0xfe, 0xe2, 0x10, 0x01,
11494 0xe7, 0x01, 0xe8, 0x0a, 0x99, 0x01, 0xfe, 0x32, 0x0e, 0x59, 0x11, 0x2d,
11495 0x01, 0x6f, 0x02, 0x29,
11496 0x0f, 0xfe, 0x44, 0x00, 0x4b, 0x0b, 0xdf, 0x3e, 0x0b, 0xfe, 0xb4, 0x10,
11497 0x01, 0x86, 0x3e, 0x0b,
11498 0xfe, 0xaa, 0x10, 0x01, 0x86, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xa3,
11499 0x3e, 0x0b, 0x0f, 0xfe,
11500 0x43, 0x00, 0xfe, 0x96, 0x10, 0x09, 0x4a, 0x0b, 0x35, 0x01, 0xe7, 0x01,
11501 0xe8, 0x59, 0x11, 0x2d,
11502 0x01, 0x6f, 0x67, 0x0b, 0x59, 0x3c, 0x8a, 0x02, 0xfe, 0x2a, 0x03, 0x09,
11503 0x04, 0x0b, 0x84, 0x3e,
11504 0x0b, 0x0f, 0x00, 0xfe, 0x5c, 0x10, 0x61, 0x04, 0x1b, 0xfe, 0x58, 0x12,
11505 0x09, 0x04, 0x1b, 0xfe,
11506 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x5c, 0x0c, 0xfe,
11507 0x1c, 0x1c, 0xfe, 0x9d,
11508 0xf0, 0xfe, 0x62, 0x0c, 0x09, 0x4a, 0x1b, 0x35, 0xfe, 0xa9, 0x10, 0x0f,
11509 0xfe, 0x15, 0x00, 0xfe,
11510 0x04, 0xe6, 0x0b, 0x5f, 0x5c, 0x0f, 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10,
11511 0x0f, 0xfe, 0x47, 0x00,
11512 0xa1, 0x0f, 0xfe, 0x41, 0x00, 0xa0, 0x0f, 0xfe, 0x24, 0x00, 0x87, 0xaa,
11513 0xab, 0x70, 0x05, 0x6b,
11514 0x28, 0x21, 0xd1, 0x5f, 0xfe, 0x04, 0xe6, 0x1b, 0xfe, 0x9d, 0x41, 0xfe,
11515 0x1c, 0x42, 0x59, 0x01,
11516 0xda, 0x02, 0x29, 0xea, 0x14, 0x0b, 0x37, 0x95, 0xa9, 0x14, 0xfe, 0x31,
11517 0x00, 0x37, 0x97, 0x01,
11518 0xfe, 0x54, 0x0f, 0x02, 0xd0, 0x3c, 0xfe, 0x06, 0xec, 0xc9, 0xee, 0x3e,
11519 0x1d, 0xfe, 0xce, 0x45,
11520 0x34, 0x3c, 0xfe, 0x06, 0xea, 0xc9, 0xfe, 0x47, 0x4b, 0x89, 0xfe, 0x75,
11521 0x57, 0x05, 0x51, 0xfe,
11522 0x98, 0x56, 0xfe, 0x38, 0x12, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x44, 0x48,
11523 0x46, 0x09, 0x04, 0x1d,
11524 0xfe, 0x1a, 0x13, 0x0a, 0x40, 0x01, 0x0e, 0x47, 0xfe, 0x41, 0x58, 0x0a,
11525 0x99, 0x01, 0x0e, 0xfe,
11526 0x49, 0x54, 0x8e, 0xfe, 0x2a, 0x0d, 0x02, 0xfe, 0x2a, 0x03, 0x0a, 0x51,
11527 0xfe, 0xee, 0x14, 0xee,
11528 0x3e, 0x1d, 0xfe, 0xce, 0x45, 0x34, 0x3c, 0xfe, 0xce, 0x47, 0xfe, 0xad,
11529 0x13, 0x02, 0x29, 0x1e,
11530 0x20, 0x07, 0x10, 0xfe, 0x9e, 0x12, 0x23, 0x12, 0x4d, 0x12, 0x94, 0x12,
11531 0xce, 0x1e, 0x2d, 0x47,
11532 0x37, 0x2d, 0xb1, 0xe0, 0xfe, 0xbc, 0xf0, 0xfe, 0xec, 0x0d, 0x13, 0x06,
11533 0x12, 0x4d, 0x01, 0xfe,
11534 0xe2, 0x15, 0x05, 0xfe, 0x38, 0x01, 0x31, 0xfe, 0x3a, 0x01, 0x77, 0xfe,
11535 0xf0, 0x0d, 0xfe, 0x02,
11536 0xec, 0xce, 0x62, 0x00, 0x5d, 0xfe, 0x04, 0xec, 0x20, 0x46, 0xfe, 0x05,
11537 0xf6, 0xfe, 0x34, 0x01,
11538 0x01, 0xfe, 0x52, 0x16, 0xfb, 0xfe, 0x48, 0xf4, 0x0d, 0xfe, 0x18, 0x13,
11539 0xaf, 0xfe, 0x02, 0xea,
11540 0xce, 0x62, 0x7a, 0xfe, 0xc5, 0x13, 0x14, 0x1b, 0x37, 0x95, 0xa9, 0x5c,
11541 0x05, 0xfe, 0x38, 0x01,
11542 0x1c, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x05, 0xfe, 0x3a, 0x01,
11543 0x0c, 0xfe, 0x62, 0x01,
11544 0x3d, 0x12, 0x20, 0x24, 0x06, 0x12, 0x2d, 0x11, 0x2d, 0x8a, 0x13, 0x06,
11545 0x03, 0x23, 0x03, 0x1e,
11546 0x4d, 0xfe, 0xf7, 0x12, 0x1e, 0x94, 0xac, 0x12, 0x94, 0x07, 0x7a, 0xfe,
11547 0x71, 0x13, 0xfe, 0x24,
11548 0x1c, 0x14, 0x1a, 0x37, 0x95, 0xa9, 0xfe, 0xd9, 0x10, 0xb6, 0xfe, 0x03,
11549 0xdc, 0xfe, 0x73, 0x57,
11550 0xfe, 0x80, 0x5d, 0x03, 0xb6, 0xfe, 0x03, 0xdc, 0xfe, 0x5b, 0x57, 0xfe,
11551 0x80, 0x5d, 0x03, 0xfe,
11552 0x03, 0x57, 0xb6, 0x23, 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0xb6,
11553 0x75, 0x03, 0x09, 0x04,
11554 0x4c, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13,
11555 0xfe, 0x1e, 0x80, 0xe1,
11556 0xfe, 0x1d, 0x80, 0xa4, 0xfe, 0x0c, 0x90, 0xfe, 0x0e, 0x13, 0xfe, 0x0e,
11557 0x90, 0xa3, 0xfe, 0x3c,
11558 0x90, 0xfe, 0x30, 0xf4, 0x0b, 0xfe, 0x3c, 0x50, 0xa0, 0x01, 0xfe, 0x82,
11559 0x16, 0x2f, 0x07, 0x2d,
11560 0xe0, 0x01, 0xfe, 0xbc, 0x15, 0x09, 0x04, 0x1d, 0x45, 0x01, 0xe7, 0x01,
11561 0xe8, 0x11, 0xfe, 0xe9,
11562 0x00, 0x09, 0x04, 0x4c, 0xfe, 0x2c, 0x13, 0x01, 0xfe, 0x14, 0x16, 0xfe,
11563 0x1e, 0x1c, 0xfe, 0x14,
11564 0x90, 0xfe, 0x96, 0x90, 0x0c, 0xfe, 0x64, 0x01, 0x18, 0xfe, 0x66, 0x01,
11565 0x09, 0x04, 0x4f, 0xfe,
11566 0x12, 0x12, 0xfe, 0x03, 0x80, 0x74, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80,
11567 0x40, 0x12, 0x20, 0x63,
11568 0x27, 0x11, 0xc8, 0x59, 0x1e, 0x20, 0xed, 0x76, 0x20, 0x03, 0xfe, 0x08,
11569 0x1c, 0x05, 0xfe, 0xac,
11570 0x00, 0xfe, 0x06, 0x58, 0x05, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x05,
11571 0xfe, 0xb0, 0x00, 0xfe,
11572 0x08, 0x58, 0x05, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
11573 0x24, 0x69, 0x12, 0xc9,
11574 0x23, 0x0c, 0x50, 0x0c, 0x3f, 0x13, 0x40, 0x48, 0x5f, 0x17, 0x1d, 0xfe,
11575 0x90, 0x4d, 0xfe, 0x91,
11576 0x54, 0x21, 0xfe, 0x08, 0x0f, 0x3e, 0x10, 0x13, 0x42, 0x48, 0x17, 0x4c,
11577 0xfe, 0x90, 0x4d, 0xfe,
11578 0x91, 0x54, 0x21, 0xfe, 0x1e, 0x0f, 0x24, 0x10, 0x12, 0x20, 0x78, 0x2c,
11579 0x46, 0x1e, 0x20, 0xed,
11580 0x76, 0x20, 0x11, 0xc8, 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x32, 0x0f, 0xea,
11581 0x70, 0xfe, 0x14, 0x1c,
11582 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x03, 0x3c, 0xfe, 0x0c, 0x14, 0xee,
11583 0xfe, 0x07, 0xe6, 0x1d,
11584 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x86, 0x78, 0x2c, 0x46,
11585 0xfa, 0xef, 0xfe, 0x42,
11586 0x13, 0x2f, 0x07, 0x2d, 0xfe, 0x34, 0x13, 0x0a, 0x42, 0x01, 0x0e, 0xb0,
11587 0xfe, 0x36, 0x12, 0xf0,
11588 0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13,
11589 0x3d, 0x75, 0x07, 0x10,
11590 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x6f, 0xfe, 0x0e,
11591 0x10, 0x07, 0x7e, 0x45,
11592 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x6c, 0x0f, 0x03, 0xfe, 0x44, 0x58, 0x74,
11593 0xfe, 0x01, 0xec, 0x97,
11594 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1b, 0x76,
11595 0x27, 0x01, 0xda, 0xfe,
11596 0xdd, 0x10, 0x2a, 0xbc, 0x7d, 0xbd, 0x7f, 0x30, 0x2e, 0xd5, 0x07, 0x1b,
11597 0xfe, 0x48, 0x12, 0x07,
11598 0x0b, 0xfe, 0x56, 0x12, 0x07, 0x1a, 0xfe, 0x30, 0x12, 0x07, 0xc2, 0x16,
11599 0xfe, 0x3e, 0x11, 0x07,
11600 0xfe, 0x23, 0x00, 0x16, 0xfe, 0x4a, 0x11, 0x07, 0x06, 0x16, 0xfe, 0xa8,
11601 0x11, 0x07, 0x19, 0xfe,
11602 0x12, 0x12, 0x07, 0x00, 0x16, 0x22, 0x14, 0xc2, 0x01, 0x33, 0x9f, 0x2b,
11603 0x01, 0x08, 0x8c, 0x43,
11604 0x03, 0x2b, 0xfe, 0x62, 0x08, 0x0a, 0xca, 0x01, 0xfe, 0x32, 0x0e, 0x11,
11605 0x7e, 0x02, 0x29, 0x2b,
11606 0x2f, 0x07, 0x9b, 0xfe, 0xd9, 0x13, 0x79, 0x39, 0x68, 0x3a, 0x77, 0xfe,
11607 0xfc, 0x10, 0x09, 0x04,
11608 0x6a, 0xfe, 0x72, 0x12, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x8e, 0xfe,
11609 0xc6, 0x10, 0x1e, 0x58,
11610 0xfe, 0x26, 0x13, 0x05, 0x7b, 0x31, 0x7c, 0x77, 0xfe, 0x82, 0x0c, 0x0c,
11611 0x54, 0x18, 0x55, 0x23,
11612 0x0c, 0x7b, 0x0c, 0x7c, 0x01, 0xa8, 0x24, 0x69, 0x73, 0x12, 0x58, 0x01,
11613 0xa5, 0xc0, 0x38, 0xc1,
11614 0x4e, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x38, 0xfe,
11615 0x05, 0xfa, 0x4e, 0xfe,
11616 0x91, 0x10, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56,
11617 0x0c, 0x56, 0x18, 0x57,
11618 0x83, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x05, 0x52, 0x31, 0x53, 0xfe,
11619 0x00, 0x56, 0xfe, 0xa1,
11620 0x56, 0x0c, 0x52, 0x18, 0x53, 0x09, 0x04, 0x6a, 0xfe, 0x1e, 0x12, 0x1e,
11621 0x58, 0xfe, 0x1f, 0x40,
11622 0x05, 0x54, 0x31, 0x55, 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x05, 0x56,
11623 0x31, 0x57, 0xfe, 0x44,
11624 0x50, 0xfe, 0xc6, 0x50, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x08, 0x50, 0xfe,
11625 0x8a, 0x50, 0x05, 0x39,
11626 0x31, 0x3a, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x5c, 0x24, 0x06,
11627 0x12, 0xcd, 0x02, 0x5b,
11628 0x2b, 0x01, 0x08, 0x1f, 0x44, 0x30, 0x2e, 0xd5, 0x07, 0x06, 0x21, 0x44,
11629 0x2f, 0x07, 0x9b, 0x21,
11630 0x5b, 0x01, 0x6e, 0x1c, 0x3d, 0x16, 0x44, 0x09, 0x04, 0x0b, 0xe2, 0x79,
11631 0x39, 0x68, 0x3a, 0xfe,
11632 0x0a, 0x55, 0x34, 0xfe, 0x8b, 0x55, 0xbe, 0x39, 0xbf, 0x3a, 0xfe, 0x0c,
11633 0x51, 0xfe, 0x8e, 0x51,
11634 0x02, 0x5b, 0xfe, 0x19, 0x81, 0xaf, 0xfe, 0x19, 0x41, 0x02, 0x5b, 0x2b,
11635 0x01, 0x08, 0x25, 0x32,
11636 0x1f, 0xa2, 0x30, 0x2e, 0xd8, 0x4b, 0x1a, 0xfe, 0xa6, 0x12, 0x4b, 0x0b,
11637 0x3b, 0x02, 0x44, 0x01,
11638 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, 0xd6, 0x07, 0x1a, 0x21, 0x44,
11639 0x01, 0x08, 0x1f, 0xa2,
11640 0x30, 0x2e, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x60, 0x05, 0xfe, 0x9c,
11641 0x00, 0x28, 0x84, 0x49,
11642 0x04, 0x19, 0x34, 0x9f, 0xfe, 0xbb, 0x45, 0x4b, 0x00, 0x45, 0x3e, 0x06,
11643 0x78, 0x3d, 0xfe, 0xda,
11644 0x14, 0x01, 0x6e, 0x87, 0xfe, 0x4b, 0x45, 0xe2, 0x2f, 0x07, 0x9a, 0xe1,
11645 0x05, 0xc6, 0x28, 0x84,
11646 0x05, 0x3f, 0x28, 0x34, 0x5e, 0x02, 0x5b, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8,
11647 0x14, 0xfe, 0x03, 0x17,
11648 0x05, 0x50, 0xb4, 0x0c, 0x50, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01,
11649 0xfe, 0xaa, 0x14, 0x02,
11650 0x5c, 0x01, 0x08, 0x25, 0x32, 0x1f, 0x44, 0x30, 0x2e, 0xd6, 0x07, 0x06,
11651 0x21, 0x44, 0x01, 0xfe,
11652 0x8e, 0x13, 0xfe, 0x42, 0x58, 0xfe, 0x82, 0x14, 0xfe, 0xa4, 0x14, 0x87,
11653 0xfe, 0x4a, 0xf4, 0x0b,
11654 0x16, 0x44, 0xfe, 0x4a, 0xf4, 0x06, 0xfe, 0x0c, 0x12, 0x2f, 0x07, 0x9a,
11655 0x85, 0x02, 0x5b, 0x05,
11656 0x3f, 0xb4, 0x0c, 0x3f, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe,
11657 0xd8, 0x14, 0x02, 0x5c,
11658 0x13, 0x06, 0x65, 0xfe, 0xca, 0x12, 0x26, 0xfe, 0xe0, 0x12, 0x72, 0xf1,
11659 0x01, 0x08, 0x23, 0x72,
11660 0x03, 0x8f, 0xfe, 0xdc, 0x12, 0x25, 0xfe, 0xdc, 0x12, 0x1f, 0xfe, 0xca,
11661 0x12, 0x5e, 0x2b, 0x01,
11662 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
11663 0x1c, 0xfe, 0xff, 0x7f,
11664 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00,
11665 0x57, 0x48, 0x8b, 0x1c,
11666 0x3d, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02,
11667 0x00, 0x57, 0x48, 0x8b,
11668 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0xfe, 0x0b, 0x58,
11669 0x03, 0x0a, 0x50, 0x01,
11670 0x82, 0x0a, 0x3f, 0x01, 0x82, 0x03, 0xfc, 0x1c, 0x10, 0xff, 0x03, 0x00,
11671 0x54, 0xfe, 0x00, 0xf4,
11672 0x19, 0x48, 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe,
11673 0x03, 0x7c, 0x63, 0x27,
11674 0x0c, 0x52, 0x18, 0x53, 0xbe, 0x56, 0xbf, 0x57, 0x03, 0xfe, 0x62, 0x08,
11675 0xfe, 0x82, 0x4a, 0xfe,
11676 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x74, 0x03, 0x01, 0xfe, 0x14, 0x18, 0xfe,
11677 0x42, 0x48, 0x5f, 0x60,
11678 0x89, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14, 0x30, 0x2e, 0xd8, 0x01, 0x08,
11679 0x1f, 0xfe, 0xa2, 0x14,
11680 0x30, 0x2e, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x05, 0xc6, 0x28, 0xfe,
11681 0xcc, 0x12, 0x49, 0x04,
11682 0x1b, 0xfe, 0xc4, 0x13, 0x23, 0x62, 0x1b, 0xe2, 0x4b, 0xc3, 0x64, 0xfe,
11683 0xe8, 0x13, 0x3b, 0x13,
11684 0x06, 0x17, 0xc3, 0x78, 0xdb, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55,
11685 0xa1, 0xff, 0x02, 0x83,
11686 0x55, 0x62, 0x1a, 0xa4, 0xbb, 0xfe, 0x30, 0x00, 0x8e, 0xe4, 0x17, 0x2c,
11687 0x13, 0x06, 0xfe, 0x56,
11688 0x10, 0x62, 0x0b, 0xe1, 0xbb, 0xfe, 0x64, 0x00, 0x8e, 0xe4, 0x0a, 0xfe,
11689 0x64, 0x00, 0x17, 0x93,
11690 0x13, 0x06, 0xfe, 0x28, 0x10, 0x62, 0x06, 0xfe, 0x60, 0x13, 0xbb, 0xfe,
11691 0xc8, 0x00, 0x8e, 0xe4,
11692 0x0a, 0xfe, 0xc8, 0x00, 0x17, 0x4d, 0x13, 0x06, 0x83, 0xbb, 0xfe, 0x90,
11693 0x01, 0xba, 0xfe, 0x4e,
11694 0x14, 0x89, 0xfe, 0x12, 0x10, 0xfe, 0x43, 0xf4, 0x94, 0xfe, 0x56, 0xf0,
11695 0xfe, 0x60, 0x14, 0xfe,
11696 0x04, 0xf4, 0x6c, 0xfe, 0x43, 0xf4, 0x93, 0xfe, 0xf3, 0x10, 0xf9, 0x01,
11697 0xfe, 0x22, 0x13, 0x1c,
11698 0x3d, 0xfe, 0x10, 0x13, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x69, 0xba,
11699 0xfe, 0x9c, 0x14, 0xb7,
11700 0x69, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x19, 0xba,
11701 0xfe, 0x9c, 0x14, 0xb7,
11702 0x19, 0x83, 0x60, 0x23, 0xfe, 0x4d, 0xf4, 0x00, 0xdf, 0x89, 0x13, 0x06,
11703 0xfe, 0xb4, 0x56, 0xfe,
11704 0xc3, 0x58, 0x03, 0x60, 0x13, 0x0b, 0x03, 0x15, 0x06, 0x01, 0x08, 0x26,
11705 0xe5, 0x15, 0x0b, 0x01,
11706 0x08, 0x26, 0xe5, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xe5, 0x72, 0xfe, 0x89,
11707 0x49, 0x01, 0x08, 0x03,
11708 0x15, 0x06, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xa6,
11709 0x15, 0x06, 0x01, 0x08,
11710 0x26, 0xa6, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x26, 0xa6, 0x72, 0xfe, 0x89,
11711 0x4a, 0x01, 0x08, 0x03,
11712 0x60, 0x03, 0x1e, 0xcc, 0x07, 0x06, 0xfe, 0x44, 0x13, 0xad, 0x12, 0xcc,
11713 0xfe, 0x49, 0xf4, 0x00,
11714 0x3b, 0x72, 0x9f, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01,
11715 0x08, 0x2f, 0x07, 0xfe,
11716 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0x5a, 0x15, 0x23, 0x12, 0xcd,
11717 0x01, 0x43, 0x1e, 0xcd,
11718 0x07, 0x06, 0x45, 0x09, 0x4a, 0x06, 0x35, 0x03, 0x0a, 0x42, 0x01, 0x0e,
11719 0xed, 0x88, 0x07, 0x10,
11720 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a,
11721 0x80, 0x01, 0x0e, 0x88,
11722 0xfe, 0x80, 0xe7, 0x10, 0x07, 0x10, 0x84, 0xfe, 0x45, 0x58, 0x01, 0xe3,
11723 0x88, 0x03, 0x0a, 0x42,
11724 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x42, 0x01, 0x0e,
11725 0xfe, 0x80, 0x80, 0xf2,
11726 0xfe, 0x49, 0xe4, 0x10, 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x0a, 0x51,
11727 0x01, 0x82, 0x03, 0x17,
11728 0x10, 0x71, 0x66, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde,
11729 0xfe, 0x24, 0x1c, 0xfe,
11730 0x1d, 0xf7, 0x1d, 0x90, 0xfe, 0xf6, 0x15, 0x01, 0xfe, 0xfc, 0x16, 0xe0,
11731 0x91, 0x1d, 0x66, 0xfe,
11732 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x03, 0xae, 0x21, 0xfe, 0xe6, 0x15, 0xfe,
11733 0xda, 0x10, 0x17, 0x10,
11734 0x71, 0x05, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58,
11735 0x05, 0xfe, 0x66, 0x01,
11736 0xfe, 0x19, 0x58, 0x91, 0x19, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x06,
11737 0xfe, 0x3c, 0x50, 0x66,
11738 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x90, 0xfe,
11739 0x40, 0x16, 0xfe, 0xb6,
11740 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x18, 0x16, 0xfe, 0x9c, 0x10, 0x17,
11741 0x10, 0x71, 0xfe, 0x83,
11742 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x38, 0x90,
11743 0xfe, 0x62, 0x16, 0xfe,
11744 0x94, 0x14, 0xfe, 0x10, 0x13, 0x91, 0x38, 0x66, 0x1b, 0xfe, 0xaf, 0x19,
11745 0xfe, 0x98, 0xe7, 0x00,
11746 0x03, 0xae, 0x21, 0xfe, 0x56, 0x16, 0xfe, 0x6c, 0x10, 0x17, 0x10, 0x71,
11747 0xfe, 0x30, 0xbc, 0xfe,
11748 0xb2, 0xbc, 0x91, 0xc5, 0x66, 0x1b, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
11749 0xc5, 0x90, 0xfe, 0x9a,
11750 0x16, 0xfe, 0x5c, 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x86, 0x16, 0xfe,
11751 0x42, 0x10, 0xfe, 0x02,
11752 0xf6, 0x10, 0x71, 0xfe, 0x18, 0xfe, 0x54, 0xfe, 0x19, 0xfe, 0x55, 0xfc,
11753 0xfe, 0x1d, 0xf7, 0x4f,
11754 0x90, 0xfe, 0xc0, 0x16, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0x91, 0x4f,
11755 0x47, 0xfe, 0x83, 0x58,
11756 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11,
11757 0xfe, 0xdd, 0x00, 0x63,
11758 0x27, 0x03, 0x63, 0x27, 0xfe, 0x12, 0x45, 0x21, 0xfe, 0xb0, 0x16, 0x14,
11759 0x06, 0x37, 0x95, 0xa9,
11760 0x02, 0x29, 0xfe, 0x39, 0xf0, 0xfe, 0x04, 0x17, 0x23, 0x03, 0xfe, 0x7e,
11761 0x18, 0x1c, 0x1a, 0x5d,
11762 0x13, 0x0d, 0x03, 0x71, 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0xef, 0x12, 0xfe,
11763 0xe1, 0x10, 0x78, 0x2c,
11764 0x46, 0x2f, 0x07, 0x2d, 0xfe, 0x3c, 0x13, 0xfe, 0x82, 0x14, 0xfe, 0x42,
11765 0x13, 0x3c, 0x8a, 0x0a,
11766 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x3e, 0x12, 0xf0, 0xfe, 0x45, 0x48, 0x01,
11767 0xe3, 0xfe, 0x00, 0xcc,
11768 0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10, 0xa3, 0x0a, 0x80, 0x01,
11769 0x0e, 0xf2, 0x01, 0x6f,
11770 0xfe, 0x16, 0x10, 0x07, 0x7e, 0x85, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12,
11771 0xf6, 0xfe, 0xd6, 0xf0,
11772 0xfe, 0x24, 0x17, 0x17, 0x0b, 0x03, 0xfe, 0x9c, 0xe7, 0x0b, 0x0f, 0xfe,
11773 0x15, 0x00, 0x59, 0x76,
11774 0x27, 0x01, 0xda, 0x17, 0x06, 0x03, 0x3c, 0x8a, 0x09, 0x4a, 0x1d, 0x35,
11775 0x11, 0x2d, 0x01, 0x6f,
11776 0x17, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x79, 0xc7, 0x68,
11777 0xc8, 0xfe, 0x48, 0x55,
11778 0x34, 0xfe, 0xc9, 0x55, 0x03, 0x1e, 0x98, 0x73, 0x12, 0x98, 0x03, 0x0a,
11779 0x99, 0x01, 0x0e, 0xf0,
11780 0x0a, 0x40, 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x16, 0xfe, 0xf0, 0x17, 0x73,
11781 0x75, 0x03, 0x0a, 0x42,
11782 0x01, 0x0e, 0x07, 0x10, 0x45, 0x0a, 0x51, 0x01, 0x9e, 0x0a, 0x40, 0x01,
11783 0x0e, 0x73, 0x75, 0x03,
11784 0xfe, 0x4e, 0xe4, 0x1a, 0x64, 0xfe, 0x24, 0x18, 0x05, 0xfe, 0x90, 0x00,
11785 0xfe, 0x3a, 0x45, 0x5b,
11786 0xfe, 0x4e, 0xe4, 0xc2, 0x64, 0xfe, 0x36, 0x18, 0x05, 0xfe, 0x92, 0x00,
11787 0xfe, 0x02, 0xe6, 0x1b,
11788 0xdc, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x64, 0xfe, 0x48, 0x18, 0x05,
11789 0xfe, 0x94, 0x00, 0xfe,
11790 0x02, 0xe6, 0x19, 0xfe, 0x08, 0x10, 0x05, 0xfe, 0x96, 0x00, 0xfe, 0x02,
11791 0xe6, 0x2c, 0xfe, 0x4e,
11792 0x45, 0xfe, 0x0c, 0x12, 0xaf, 0xff, 0x04, 0x68, 0x54, 0xde, 0x1c, 0x69,
11793 0x03, 0x07, 0x7a, 0xfe,
11794 0x5a, 0xf0, 0xfe, 0x74, 0x18, 0x24, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
11795 0x07, 0x1b, 0xfe, 0x5a,
11796 0xf0, 0xfe, 0x82, 0x18, 0x24, 0xc3, 0xfe, 0x26, 0x10, 0x07, 0x1a, 0x5d,
11797 0x24, 0x2c, 0xdc, 0x07,
11798 0x0b, 0x5d, 0x24, 0x93, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x5d, 0x24, 0x4d,
11799 0x9f, 0xad, 0x03, 0x14,
11800 0xfe, 0x09, 0x00, 0x01, 0x33, 0xfe, 0x04, 0xfe, 0x7d, 0x05, 0x7f, 0xf9,
11801 0x03, 0x25, 0xfe, 0xca,
11802 0x18, 0xfe, 0x14, 0xf0, 0x08, 0x65, 0xfe, 0xc6, 0x18, 0x03, 0xff, 0x1a,
11803 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070011804};
11805
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011806static unsigned short _adv_asc3550_size = sizeof(_adv_asc3550_buf); /* 0x13AD */
11807static ADV_DCNT _adv_asc3550_chksum = 0x04D52DDDUL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011808
11809/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011810static unsigned char _adv_asc38C0800_buf[] = {
11811 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x16, 0x18, 0xe4,
11812 0x01, 0x00, 0x48, 0xe4,
11813 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0xce, 0x19, 0x00, 0xfa, 0xff, 0xff,
11814 0x1c, 0x0f, 0x00, 0xf6,
11815 0x9e, 0xe7, 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x01, 0xfa, 0x01, 0xe6,
11816 0x09, 0xe7, 0x55, 0xf0,
11817 0x01, 0xf6, 0x03, 0x00, 0x04, 0x00, 0x10, 0x00, 0x1e, 0xf0, 0x85, 0xf0,
11818 0x18, 0xf4, 0x08, 0x00,
11819 0xbc, 0x00, 0x38, 0x54, 0x00, 0xec, 0xd5, 0xf0, 0x82, 0x0d, 0x00, 0xe6,
11820 0x86, 0xf0, 0xb1, 0xf0,
11821 0x98, 0x57, 0x01, 0xfc, 0xb4, 0x00, 0xd4, 0x01, 0x0c, 0x1c, 0x3e, 0x1c,
11822 0x3c, 0x00, 0xbb, 0x00,
11823 0x00, 0x10, 0xba, 0x19, 0x02, 0x80, 0x32, 0xf0, 0x7c, 0x0d, 0x02, 0x13,
11824 0xba, 0x13, 0x18, 0x40,
11825 0x00, 0x57, 0x01, 0xea, 0x02, 0xfc, 0x03, 0xfc, 0x3e, 0x00, 0x6c, 0x01,
11826 0x6e, 0x01, 0x74, 0x01,
11827 0x76, 0x01, 0xb9, 0x54, 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00,
11828 0xc0, 0x00, 0x01, 0x01,
11829 0x3e, 0x01, 0x7a, 0x01, 0xca, 0x08, 0xce, 0x10, 0x16, 0x11, 0x04, 0x12,
11830 0x08, 0x12, 0x02, 0x4a,
11831 0xbb, 0x55, 0x3c, 0x56, 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4,
11832 0x5d, 0xf0, 0x02, 0xfa,
11833 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01,
11834 0x68, 0x01, 0x6a, 0x01,
11835 0x70, 0x01, 0x72, 0x01, 0x78, 0x01, 0x7c, 0x01, 0x62, 0x0a, 0x86, 0x0d,
11836 0x06, 0x13, 0x4c, 0x1c,
11837 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x0c, 0x00,
11838 0x0f, 0x00, 0x47, 0x00,
11839 0xbe, 0x00, 0x00, 0x01, 0x20, 0x11, 0x5c, 0x16, 0x32, 0x1c, 0x38, 0x1c,
11840 0x4e, 0x1c, 0x10, 0x44,
11841 0x00, 0x4c, 0x04, 0xea, 0x5c, 0xf0, 0xa7, 0xf0, 0x04, 0xf6, 0x03, 0xfa,
11842 0x05, 0x00, 0x34, 0x00,
11843 0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x4a, 0x0b,
11844 0x42, 0x0c, 0x12, 0x0f,
11845 0x0c, 0x10, 0x22, 0x11, 0x0a, 0x12, 0x04, 0x13, 0x30, 0x1c, 0x02, 0x48,
11846 0x00, 0x4e, 0x42, 0x54,
11847 0x44, 0x55, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
11848 0x59, 0xf0, 0xb8, 0xf0,
11849 0x4b, 0xf4, 0x06, 0xf7, 0x0e, 0xf7, 0x04, 0xfc, 0x05, 0xfc, 0x06, 0x00,
11850 0x19, 0x00, 0x33, 0x00,
11851 0x9b, 0x00, 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00,
11852 0xe7, 0x00, 0xe2, 0x03,
11853 0x08, 0x0f, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, 0x0a, 0x13, 0x0c, 0x13,
11854 0x12, 0x13, 0x24, 0x14,
11855 0x34, 0x14, 0x04, 0x16, 0x08, 0x16, 0xa4, 0x17, 0x20, 0x1c, 0x34, 0x1c,
11856 0x36, 0x1c, 0x08, 0x44,
11857 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54,
11858 0x3a, 0x55, 0x83, 0x55,
11859 0xe5, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0,
11860 0x0c, 0xf0, 0x04, 0xf8,
11861 0x05, 0xf8, 0x07, 0x00, 0x0a, 0x00, 0x1c, 0x00, 0x1e, 0x00, 0x9e, 0x00,
11862 0xa8, 0x00, 0xaa, 0x00,
11863 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7e, 0x01,
11864 0xc4, 0x01, 0xc6, 0x01,
11865 0x80, 0x02, 0x5e, 0x03, 0xee, 0x04, 0x9a, 0x06, 0xf8, 0x07, 0x62, 0x08,
11866 0x68, 0x08, 0x69, 0x08,
11867 0xd6, 0x08, 0xe9, 0x09, 0xfa, 0x0b, 0x2e, 0x0f, 0x12, 0x10, 0x1a, 0x10,
11868 0xed, 0x10, 0xf1, 0x10,
11869 0x2a, 0x11, 0x06, 0x12, 0x0c, 0x12, 0x3e, 0x12, 0x10, 0x13, 0x16, 0x13,
11870 0x1e, 0x13, 0x46, 0x14,
11871 0x76, 0x14, 0x82, 0x14, 0x36, 0x15, 0xca, 0x15, 0x6b, 0x18, 0xbe, 0x18,
11872 0xca, 0x18, 0xe6, 0x19,
11873 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0xfe, 0x9c,
11874 0xf0, 0x2b, 0x02, 0xfe,
11875 0xac, 0x0d, 0xff, 0x10, 0x00, 0x00, 0xd7, 0xfe, 0xe8, 0x19, 0x00, 0xd6,
11876 0xfe, 0x84, 0x01, 0xff,
11877 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
11878 0x00, 0xfe, 0x57, 0x24,
11879 0x00, 0xfe, 0x4c, 0x00, 0x5b, 0xff, 0x04, 0x00, 0x00, 0x11, 0xff, 0x09,
11880 0x00, 0x00, 0xff, 0x08,
11881 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
11882 0xff, 0xff, 0xff, 0x11,
11883 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
11884 0xfe, 0x04, 0xf7, 0xd6,
11885 0x2c, 0x99, 0x0a, 0x01, 0xfe, 0xc2, 0x0f, 0xfe, 0x04, 0xf7, 0xd6, 0x99,
11886 0x0a, 0x42, 0x2c, 0xfe,
11887 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x91, 0xf0,
11888 0xfe, 0xf4, 0x01, 0xfe,
11889 0x90, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, 0x8f, 0xf0, 0xa7, 0x03, 0x5d, 0x4d,
11890 0x02, 0xfe, 0xc8, 0x0d,
11891 0x01, 0xfe, 0x38, 0x0e, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
11892 0x1c, 0x03, 0xfe, 0xa6,
11893 0x00, 0xfe, 0xd3, 0x12, 0x41, 0x14, 0xfe, 0xa6, 0x00, 0xc2, 0xfe, 0x48,
11894 0xf0, 0xfe, 0x8a, 0x02,
11895 0xfe, 0x49, 0xf0, 0xfe, 0xa4, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc2, 0x02,
11896 0xfe, 0x46, 0xf0, 0xfe,
11897 0x54, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x5a, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
11898 0x48, 0x02, 0xfe, 0x44,
11899 0xf0, 0xfe, 0x4c, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x50, 0x02, 0x18, 0x0a,
11900 0xaa, 0x18, 0x06, 0x14,
11901 0xa1, 0x02, 0x2b, 0xfe, 0x00, 0x1c, 0xe7, 0xfe, 0x02, 0x1c, 0xe6, 0xfe,
11902 0x1e, 0x1c, 0xfe, 0xe9,
11903 0x10, 0x01, 0xfe, 0x18, 0x18, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xce,
11904 0x09, 0x70, 0x01, 0xa8,
11905 0x02, 0x2b, 0x15, 0x59, 0x39, 0xa2, 0x01, 0xfe, 0x58, 0x10, 0x09, 0x70,
11906 0x01, 0x87, 0xfe, 0xbd,
11907 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
11908 0x58, 0x1c, 0x18, 0x06,
11909 0x14, 0xa1, 0x2c, 0x1c, 0x2b, 0xfe, 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0x23,
11910 0xfe, 0x98, 0x02, 0xfe,
11911 0x5a, 0x1c, 0xf8, 0xfe, 0x14, 0x1c, 0x15, 0xfe, 0x30, 0x00, 0x39, 0xa2,
11912 0x01, 0xfe, 0x48, 0x10,
11913 0x18, 0x06, 0x14, 0xa1, 0x02, 0xd7, 0x22, 0x20, 0x07, 0x11, 0x35, 0xfe,
11914 0x69, 0x10, 0x18, 0x06,
11915 0x14, 0xa1, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0x43, 0x13, 0x20, 0xfe, 0x05,
11916 0xf6, 0xce, 0x01, 0xfe,
11917 0x4a, 0x17, 0x08, 0x54, 0x58, 0x37, 0x12, 0x2f, 0x42, 0x92, 0x01, 0xfe,
11918 0x82, 0x16, 0x02, 0x2b,
11919 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x01, 0x73, 0xfe, 0x18, 0x10,
11920 0xfe, 0x41, 0x58, 0x09,
11921 0xa4, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x6b, 0xfe, 0x10, 0x03, 0x01, 0xfe,
11922 0x82, 0x16, 0x02, 0x2b,
11923 0x2c, 0x4f, 0xfe, 0x02, 0xe8, 0x2a, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43,
11924 0xfe, 0x77, 0x57, 0xfe,
11925 0x27, 0xf0, 0xfe, 0xe0, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xa7,
11926 0xfe, 0x40, 0x1c, 0x1c,
11927 0xd9, 0xfe, 0x26, 0xf0, 0xfe, 0x5a, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x48,
11928 0x03, 0xfe, 0x11, 0xf0,
11929 0xa7, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x68, 0x03, 0xf9, 0x10,
11930 0xfe, 0x11, 0x00, 0x02,
11931 0x65, 0x2c, 0xfe, 0x48, 0x1c, 0xf9, 0x08, 0x05, 0x1b, 0xfe, 0x18, 0x13,
11932 0x21, 0x22, 0xa3, 0xb7,
11933 0x13, 0xa3, 0x09, 0x46, 0x01, 0x0e, 0xb7, 0x78, 0x01, 0xfe, 0xb4, 0x16,
11934 0x12, 0xd1, 0x1c, 0xd9,
11935 0xfe, 0x01, 0xf0, 0xd9, 0xfe, 0x82, 0xf0, 0xfe, 0x96, 0x03, 0xfa, 0x12,
11936 0xfe, 0xe4, 0x00, 0x27,
11937 0xfe, 0xa8, 0x03, 0x1c, 0x34, 0x1d, 0xfe, 0xb8, 0x03, 0x01, 0x4b, 0xfe,
11938 0x06, 0xf0, 0xfe, 0xc8,
11939 0x03, 0x95, 0x86, 0xfe, 0x0a, 0xf0, 0xfe, 0x8a, 0x06, 0x02, 0x24, 0x03,
11940 0x70, 0x28, 0x17, 0xfe,
11941 0xfa, 0x04, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, 0xd8,
11942 0xf9, 0x2c, 0x99, 0x19,
11943 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c,
11944 0x74, 0x01, 0xaf, 0x8c,
11945 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x17, 0xda, 0x09, 0xd1, 0x01, 0x0e,
11946 0x8d, 0x51, 0x64, 0x79,
11947 0x2a, 0x03, 0x70, 0x28, 0xfe, 0x10, 0x12, 0x15, 0x6d, 0x01, 0x36, 0x7b,
11948 0xfe, 0x6a, 0x02, 0x02,
11949 0xd8, 0xc7, 0x81, 0xc8, 0x83, 0x1c, 0x24, 0x27, 0xfe, 0x40, 0x04, 0x1d,
11950 0xfe, 0x3c, 0x04, 0x3b,
11951 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e, 0x12, 0x2d, 0xff, 0x02,
11952 0x00, 0x10, 0x01, 0x0b,
11953 0x1d, 0xfe, 0xe4, 0x04, 0x2d, 0x01, 0x0b, 0x1d, 0x24, 0x33, 0x31, 0xde,
11954 0xfe, 0x4c, 0x44, 0xfe,
11955 0x4c, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b,
11956 0xda, 0x4f, 0x79, 0x2a,
11957 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x62, 0x13, 0x08, 0x05, 0x1b,
11958 0xfe, 0x2a, 0x13, 0x32,
11959 0x07, 0x82, 0xfe, 0x52, 0x13, 0xfe, 0x20, 0x10, 0x0f, 0x6f, 0xfe, 0x4c,
11960 0x54, 0x6b, 0xda, 0xfe,
11961 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x40, 0x13, 0x08, 0x05, 0x1b, 0xfe,
11962 0x08, 0x13, 0x32, 0x07,
11963 0x82, 0xfe, 0x30, 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x1c, 0x12, 0x15, 0x9d,
11964 0x08, 0x05, 0x06, 0x4d,
11965 0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36, 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24,
11966 0x2d, 0x12, 0xfe, 0xe6,
11967 0x00, 0xfe, 0x1c, 0x90, 0xfe, 0x40, 0x5c, 0x04, 0x15, 0x9d, 0x01, 0x36,
11968 0x02, 0x2b, 0xfe, 0x42,
11969 0x5b, 0x99, 0x19, 0xfe, 0x46, 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
11970 0xfe, 0x87, 0x80, 0xfe,
11971 0x31, 0xe4, 0x5b, 0x08, 0x05, 0x0a, 0xfe, 0x84, 0x13, 0xfe, 0x20, 0x80,
11972 0x07, 0x19, 0xfe, 0x7c,
11973 0x12, 0x53, 0x05, 0x06, 0xfe, 0x6c, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x28,
11974 0x17, 0xfe, 0x90, 0x05,
11975 0xfe, 0x31, 0xe4, 0x5a, 0x53, 0x05, 0x0a, 0xfe, 0x56, 0x13, 0x03, 0xfe,
11976 0xa0, 0x00, 0x28, 0xfe,
11977 0x4e, 0x12, 0x67, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x48, 0x05, 0x1c,
11978 0x34, 0xfe, 0x89, 0x48,
11979 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x56, 0x05, 0x26, 0xfe, 0xa8, 0x05,
11980 0x12, 0xfe, 0xe3, 0x00,
11981 0x21, 0x53, 0xfe, 0x4a, 0xf0, 0xfe, 0x76, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
11982 0x70, 0x05, 0x88, 0x25,
11983 0xfe, 0x21, 0x00, 0xab, 0x25, 0xfe, 0x22, 0x00, 0xaa, 0x25, 0x58, 0xfe,
11984 0x09, 0x48, 0xff, 0x02,
11985 0x00, 0x10, 0x27, 0xfe, 0x86, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0xfe, 0xe2,
11986 0x08, 0x53, 0x05, 0xcb,
11987 0x4d, 0x01, 0xb0, 0x25, 0x06, 0x13, 0xd3, 0x39, 0xfe, 0x27, 0x01, 0x08,
11988 0x05, 0x1b, 0xfe, 0x22,
11989 0x12, 0x41, 0x01, 0xb2, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe,
11990 0x0d, 0x00, 0x01, 0x36,
11991 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0xeb,
11992 0x03, 0x5c, 0x28, 0xfe,
11993 0x36, 0x13, 0x41, 0x01, 0xb2, 0x26, 0xfe, 0x18, 0x06, 0x09, 0x06, 0x53,
11994 0x05, 0x1f, 0xfe, 0x02,
11995 0x12, 0x50, 0x01, 0xfe, 0x9e, 0x15, 0x1d, 0xfe, 0x0e, 0x06, 0x12, 0xa5,
11996 0x01, 0x4b, 0x12, 0xfe,
11997 0xe5, 0x00, 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x03, 0xcd, 0x28, 0xfe, 0x62,
11998 0x12, 0x03, 0x45, 0x28,
11999 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x0c, 0x19, 0x01, 0xfe, 0x76, 0x19, 0xfe,
12000 0x43, 0x48, 0xc4, 0xcc,
12001 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0x8b, 0xc4,
12002 0x6e, 0x41, 0x01, 0xb2,
12003 0x26, 0xfe, 0x82, 0x06, 0x53, 0x05, 0x1a, 0xe9, 0x91, 0x09, 0x59, 0x01,
12004 0xfe, 0xcc, 0x15, 0x1d,
12005 0xfe, 0x78, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe, 0xe5, 0x00, 0x03,
12006 0x45, 0xc1, 0x0c, 0x45,
12007 0x18, 0x06, 0x01, 0xb2, 0xfa, 0x76, 0x74, 0x01, 0xaf, 0x8c, 0x12, 0xfe,
12008 0xe2, 0x00, 0x27, 0xdb,
12009 0x1c, 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0xb6, 0x06, 0x94, 0xfe, 0x6c, 0x07,
12010 0xfe, 0x06, 0xf0, 0xfe,
12011 0x74, 0x07, 0x95, 0x86, 0x02, 0x24, 0x08, 0x05, 0x0a, 0xfe, 0x2e, 0x12,
12012 0x16, 0x19, 0x01, 0x0b,
12013 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b,
12014 0xfe, 0x99, 0xa4, 0x01,
12015 0x0b, 0x16, 0x00, 0x02, 0xfe, 0x42, 0x08, 0x68, 0x05, 0x1a, 0xfe, 0x38,
12016 0x12, 0x08, 0x05, 0x1a,
12017 0xfe, 0x30, 0x13, 0x16, 0xfe, 0x1b, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01,
12018 0x0b, 0x16, 0x00, 0x01,
12019 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x06, 0x01, 0x0b, 0x16, 0x00, 0x02,
12020 0xe2, 0x6c, 0x58, 0xbe,
12021 0x50, 0xfe, 0x9a, 0x81, 0x55, 0x1b, 0x7a, 0xfe, 0x42, 0x07, 0x09, 0x1b,
12022 0xfe, 0x09, 0x6f, 0xba,
12023 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x69, 0x6d, 0x8b, 0x6c, 0x7f, 0x27,
12024 0xfe, 0x54, 0x07, 0x1c,
12025 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0x42, 0x07, 0x95, 0x86, 0x94, 0xfe, 0x6c,
12026 0x07, 0x02, 0x24, 0x01,
12027 0x4b, 0x02, 0xdb, 0x16, 0x1f, 0x02, 0xdb, 0xfe, 0x9c, 0xf7, 0xdc, 0xfe,
12028 0x2c, 0x90, 0xfe, 0xae,
12029 0x90, 0x56, 0xfe, 0xda, 0x07, 0x0c, 0x60, 0x14, 0x61, 0x08, 0x54, 0x5a,
12030 0x37, 0x22, 0x20, 0x07,
12031 0x11, 0xfe, 0x0e, 0x12, 0x8d, 0xfe, 0x80, 0x80, 0x39, 0x20, 0x6a, 0x2a,
12032 0xfe, 0x06, 0x10, 0xfe,
12033 0x83, 0xe7, 0xfe, 0x48, 0x00, 0xab, 0xfe, 0x03, 0x40, 0x08, 0x54, 0x5b,
12034 0x37, 0x01, 0xb3, 0xb8,
12035 0xfe, 0x1f, 0x40, 0x13, 0x62, 0x01, 0xef, 0xfe, 0x08, 0x50, 0xfe, 0x8a,
12036 0x50, 0xfe, 0x44, 0x51,
12037 0xfe, 0xc6, 0x51, 0x88, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e,
12038 0x14, 0x5f, 0xfe, 0x0c,
12039 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x0c, 0x3d,
12040 0x14, 0x3e, 0xfe, 0x4a,
12041 0x10, 0x08, 0x05, 0x5a, 0xfe, 0x2a, 0x12, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
12042 0x90, 0x0c, 0x60, 0x14,
12043 0x61, 0x08, 0x05, 0x5b, 0x8b, 0x01, 0xb3, 0xfe, 0x1f, 0x80, 0x13, 0x62,
12044 0xfe, 0x44, 0x90, 0xfe,
12045 0xc6, 0x90, 0x0c, 0x3f, 0x14, 0x40, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90,
12046 0x0c, 0x5e, 0x14, 0x5f,
12047 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x3d, 0x14, 0x3e, 0x0c, 0x2e,
12048 0x14, 0x3c, 0x21, 0x0c,
12049 0x49, 0x0c, 0x63, 0x08, 0x54, 0x1f, 0x37, 0x2c, 0x0f, 0xfe, 0x4e, 0x11,
12050 0x27, 0xdd, 0xfe, 0x9e,
12051 0xf0, 0xfe, 0x76, 0x08, 0xbc, 0x17, 0x34, 0x2c, 0x77, 0xe6, 0xc5, 0xfe,
12052 0x9a, 0x08, 0xc6, 0xfe,
12053 0xb8, 0x08, 0x94, 0xfe, 0x8e, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x94, 0x08,
12054 0x95, 0x86, 0x02, 0x24,
12055 0x01, 0x4b, 0xfe, 0xc9, 0x10, 0x16, 0x1f, 0xfe, 0xc9, 0x10, 0x68, 0x05,
12056 0x06, 0xfe, 0x10, 0x12,
12057 0x68, 0x05, 0x0a, 0x4e, 0x08, 0x05, 0x0a, 0xfe, 0x90, 0x12, 0xfe, 0x2e,
12058 0x1c, 0x02, 0xfe, 0x18,
12059 0x0b, 0x68, 0x05, 0x06, 0x4e, 0x68, 0x05, 0x0a, 0xfe, 0x7a, 0x12, 0xfe,
12060 0x2c, 0x1c, 0xfe, 0xaa,
12061 0xf0, 0xfe, 0xd2, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0x00, 0x09, 0x02, 0xfe,
12062 0xde, 0x09, 0xfe, 0xb7,
12063 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0x02, 0xf6, 0x1a, 0x50, 0xfe, 0x70, 0x18,
12064 0xfe, 0xf1, 0x18, 0xfe,
12065 0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe,
12066 0x14, 0x59, 0xfe, 0x95,
12067 0x59, 0x1c, 0x85, 0xfe, 0x8c, 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0xac, 0xf0,
12068 0xfe, 0xf0, 0x08, 0xb5,
12069 0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x0c, 0x09, 0x02, 0xfe, 0x18,
12070 0x0b, 0xb6, 0xfe, 0xbf,
12071 0x10, 0xfe, 0x2b, 0xf0, 0x85, 0xf4, 0x1e, 0xfe, 0x00, 0xfe, 0xfe, 0x1c,
12072 0x12, 0xc2, 0xfe, 0xd2,
12073 0xf0, 0x85, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x17, 0x85, 0x03, 0xd2, 0x1e,
12074 0x06, 0x17, 0x85, 0xc5,
12075 0x4a, 0xc6, 0x4a, 0xb5, 0xb6, 0xfe, 0x89, 0x10, 0x74, 0x67, 0x2d, 0x15,
12076 0x9d, 0x01, 0x36, 0x10,
12077 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x65, 0x10, 0x80, 0x02, 0x65, 0xfe,
12078 0x98, 0x80, 0xfe, 0x19,
12079 0xe4, 0x0a, 0xfe, 0x1a, 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18,
12080 0xfe, 0x44, 0x54, 0xbe,
12081 0xfe, 0x19, 0x81, 0xfe, 0x74, 0x18, 0x8f, 0x90, 0x17, 0xfe, 0xce, 0x08,
12082 0x02, 0x4a, 0x08, 0x05,
12083 0x5a, 0xec, 0x03, 0x2e, 0x29, 0x3c, 0x0c, 0x3f, 0x14, 0x40, 0x9b, 0x2e,
12084 0x9c, 0x3c, 0xfe, 0x6c,
12085 0x18, 0xfe, 0xed, 0x18, 0xfe, 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x3a, 0x3f,
12086 0x3b, 0x40, 0x03, 0x49,
12087 0x29, 0x63, 0x8f, 0xfe, 0xe3, 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18,
12088 0x8f, 0xfe, 0xe3, 0x54,
12089 0x90, 0xc0, 0x56, 0xfe, 0xce, 0x08, 0x02, 0x4a, 0xfe, 0x37, 0xf0, 0xfe,
12090 0xda, 0x09, 0xfe, 0x8b,
12091 0xf0, 0xfe, 0x60, 0x09, 0x02, 0x4a, 0x08, 0x05, 0x0a, 0x23, 0xfe, 0xfa,
12092 0x0a, 0x3a, 0x49, 0x3b,
12093 0x63, 0x56, 0xfe, 0x3e, 0x0a, 0x0f, 0xfe, 0xc0, 0x07, 0x41, 0x98, 0x00,
12094 0xad, 0xfe, 0x01, 0x59,
12095 0xfe, 0x52, 0xf0, 0xfe, 0x0c, 0x0a, 0x8f, 0x7a, 0xfe, 0x24, 0x0a, 0x3a,
12096 0x49, 0x8f, 0xfe, 0xe3,
12097 0x54, 0x57, 0x49, 0x7d, 0x63, 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02,
12098 0x4a, 0x3a, 0x49, 0x3b,
12099 0x63, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xbe, 0x57, 0x49, 0x57, 0x63,
12100 0x02, 0x4a, 0x08, 0x05,
12101 0x5a, 0xfe, 0x82, 0x12, 0x08, 0x05, 0x1f, 0xfe, 0x66, 0x13, 0x22, 0x62,
12102 0xb7, 0xfe, 0x03, 0xa1,
12103 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91,
12104 0xfe, 0x86, 0x91, 0x6a,
12105 0x2a, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x56, 0xe0, 0x03, 0x60, 0x29,
12106 0x61, 0x0c, 0x7f, 0x14,
12107 0x80, 0x57, 0x60, 0x7d, 0x61, 0x01, 0xb3, 0xb8, 0x6a, 0x2a, 0x13, 0x62,
12108 0x9b, 0x2e, 0x9c, 0x3c,
12109 0x3a, 0x3f, 0x3b, 0x40, 0x90, 0xc0, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05,
12110 0xfa, 0x3c, 0x01, 0xef,
12111 0xfe, 0x36, 0x10, 0x21, 0x0c, 0x7f, 0x0c, 0x80, 0x3a, 0x3f, 0x3b, 0x40,
12112 0xe4, 0x08, 0x05, 0x1f,
12113 0x17, 0xe0, 0x3a, 0x3d, 0x3b, 0x3e, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37,
12114 0x03, 0x5e, 0x29, 0x5f,
12115 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0x57, 0x49, 0x7d, 0x63, 0x02, 0xfe,
12116 0xf4, 0x09, 0x08, 0x05,
12117 0x1f, 0x17, 0xe0, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0xbe, 0xfe, 0x19,
12118 0x81, 0x50, 0xfe, 0x10,
12119 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd3, 0x10, 0x32, 0x07, 0xa6, 0x17, 0xfe,
12120 0x08, 0x09, 0x12, 0xa6,
12121 0x08, 0x05, 0x0a, 0xfe, 0x14, 0x13, 0x03, 0x3d, 0x29, 0x3e, 0x56, 0xfe,
12122 0x08, 0x09, 0xfe, 0x0c,
12123 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x4a, 0x21, 0x41, 0xfe, 0x19, 0x80, 0xe7,
12124 0x08, 0x05, 0x0a, 0xfe,
12125 0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xf4, 0xc2, 0xfe, 0xd1,
12126 0xf0, 0xe2, 0x15, 0x7e,
12127 0x01, 0x36, 0x10, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19,
12128 0x57, 0x3d, 0xfe, 0xed,
12129 0x19, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xf4, 0x1e, 0xfe,
12130 0x00, 0xff, 0x35, 0xfe,
12131 0x74, 0x10, 0xc2, 0xfe, 0xd2, 0xf0, 0xfe, 0xa6, 0x0b, 0xfe, 0x76, 0x18,
12132 0x1e, 0x19, 0x8a, 0x03,
12133 0xd2, 0x1e, 0x06, 0xfe, 0x08, 0x13, 0x10, 0xfe, 0x16, 0x00, 0x02, 0x65,
12134 0xfe, 0xd1, 0xf0, 0xfe,
12135 0xb8, 0x0b, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, 0x17, 0x00, 0xfe, 0x42,
12136 0x10, 0xfe, 0xce, 0xf0,
12137 0xfe, 0xbe, 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xca, 0x0b,
12138 0x10, 0xfe, 0x22, 0x00,
12139 0x02, 0x65, 0xfe, 0xcb, 0xf0, 0xfe, 0xd6, 0x0b, 0x10, 0xfe, 0x24, 0x00,
12140 0x02, 0x65, 0xfe, 0xd0,
12141 0xf0, 0xfe, 0xe0, 0x0b, 0x10, 0x9e, 0xe5, 0xfe, 0xcf, 0xf0, 0xfe, 0xea,
12142 0x0b, 0x10, 0x58, 0xfe,
12143 0x10, 0x10, 0xfe, 0xcc, 0xf0, 0xe2, 0x68, 0x05, 0x1f, 0x4d, 0x10, 0xfe,
12144 0x12, 0x00, 0x2c, 0x0f,
12145 0xfe, 0x4e, 0x11, 0x27, 0xfe, 0x00, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x14,
12146 0x0c, 0xbc, 0x17, 0x34,
12147 0x2c, 0x77, 0xe6, 0xc5, 0x24, 0xc6, 0x24, 0x2c, 0xfa, 0x27, 0xfe, 0x20,
12148 0x0c, 0x1c, 0x34, 0x94,
12149 0xfe, 0x3c, 0x0c, 0x95, 0x86, 0xc5, 0xdc, 0xc6, 0xdc, 0x02, 0x24, 0x01,
12150 0x4b, 0xfe, 0xdb, 0x10,
12151 0x12, 0xfe, 0xe8, 0x00, 0xb5, 0xb6, 0x74, 0xc7, 0x81, 0xc8, 0x83, 0xfe,
12152 0x89, 0xf0, 0x24, 0x33,
12153 0x31, 0xe1, 0xc7, 0x81, 0xc8, 0x83, 0x27, 0xfe, 0x66, 0x0c, 0x1d, 0x24,
12154 0x33, 0x31, 0xdf, 0xbc,
12155 0x4e, 0x10, 0xfe, 0x42, 0x00, 0x02, 0x65, 0x7c, 0x06, 0xfe, 0x81, 0x49,
12156 0x17, 0xfe, 0x2c, 0x0d,
12157 0x08, 0x05, 0x0a, 0xfe, 0x44, 0x13, 0x10, 0x00, 0x55, 0x0a, 0xfe, 0x54,
12158 0x12, 0x55, 0xfe, 0x28,
12159 0x00, 0x23, 0xfe, 0x9a, 0x0d, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66,
12160 0x44, 0xfe, 0x28, 0x00,
12161 0xfe, 0xe2, 0x10, 0x01, 0xf5, 0x01, 0xf6, 0x09, 0xa4, 0x01, 0xfe, 0x26,
12162 0x0f, 0x64, 0x12, 0x2f,
12163 0x01, 0x73, 0x02, 0x2b, 0x10, 0xfe, 0x44, 0x00, 0x55, 0x0a, 0xe9, 0x44,
12164 0x0a, 0xfe, 0xb4, 0x10,
12165 0x01, 0xb0, 0x44, 0x0a, 0xfe, 0xaa, 0x10, 0x01, 0xb0, 0xfe, 0x19, 0x82,
12166 0xfe, 0x34, 0x46, 0xac,
12167 0x44, 0x0a, 0x10, 0xfe, 0x43, 0x00, 0xfe, 0x96, 0x10, 0x08, 0x54, 0x0a,
12168 0x37, 0x01, 0xf5, 0x01,
12169 0xf6, 0x64, 0x12, 0x2f, 0x01, 0x73, 0x99, 0x0a, 0x64, 0x42, 0x92, 0x02,
12170 0xfe, 0x2e, 0x03, 0x08,
12171 0x05, 0x0a, 0x8a, 0x44, 0x0a, 0x10, 0x00, 0xfe, 0x5c, 0x10, 0x68, 0x05,
12172 0x1a, 0xfe, 0x58, 0x12,
12173 0x08, 0x05, 0x1a, 0xfe, 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0,
12174 0xfe, 0x50, 0x0d, 0xfe,
12175 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x56, 0x0d, 0x08, 0x54, 0x1a, 0x37,
12176 0xfe, 0xa9, 0x10, 0x10,
12177 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0a, 0x50, 0xfe, 0x2e, 0x10, 0x10,
12178 0xfe, 0x13, 0x00, 0xfe,
12179 0x10, 0x10, 0x10, 0x6f, 0xab, 0x10, 0xfe, 0x41, 0x00, 0xaa, 0x10, 0xfe,
12180 0x24, 0x00, 0x8c, 0xb5,
12181 0xb6, 0x74, 0x03, 0x70, 0x28, 0x23, 0xd8, 0x50, 0xfe, 0x04, 0xe6, 0x1a,
12182 0xfe, 0x9d, 0x41, 0xfe,
12183 0x1c, 0x42, 0x64, 0x01, 0xe3, 0x02, 0x2b, 0xf8, 0x15, 0x0a, 0x39, 0xa0,
12184 0xb4, 0x15, 0xfe, 0x31,
12185 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, 0x02, 0xd7, 0x42, 0xfe, 0x06,
12186 0xec, 0xd0, 0xfc, 0x44,
12187 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe, 0x06, 0xea, 0xd0, 0xfe, 0x47,
12188 0x4b, 0x91, 0xfe, 0x75,
12189 0x57, 0x03, 0x5d, 0xfe, 0x98, 0x56, 0xfe, 0x38, 0x12, 0x09, 0x48, 0x01,
12190 0x0e, 0xfe, 0x44, 0x48,
12191 0x4f, 0x08, 0x05, 0x1b, 0xfe, 0x1a, 0x13, 0x09, 0x46, 0x01, 0x0e, 0x41,
12192 0xfe, 0x41, 0x58, 0x09,
12193 0xa4, 0x01, 0x0e, 0xfe, 0x49, 0x54, 0x96, 0xfe, 0x1e, 0x0e, 0x02, 0xfe,
12194 0x2e, 0x03, 0x09, 0x5d,
12195 0xfe, 0xee, 0x14, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe,
12196 0xce, 0x47, 0xfe, 0xad,
12197 0x13, 0x02, 0x2b, 0x22, 0x20, 0x07, 0x11, 0xfe, 0x9e, 0x12, 0x21, 0x13,
12198 0x59, 0x13, 0x9f, 0x13,
12199 0xd5, 0x22, 0x2f, 0x41, 0x39, 0x2f, 0xbc, 0xad, 0xfe, 0xbc, 0xf0, 0xfe,
12200 0xe0, 0x0e, 0x0f, 0x06,
12201 0x13, 0x59, 0x01, 0xfe, 0xda, 0x16, 0x03, 0xfe, 0x38, 0x01, 0x29, 0xfe,
12202 0x3a, 0x01, 0x56, 0xfe,
12203 0xe4, 0x0e, 0xfe, 0x02, 0xec, 0xd5, 0x69, 0x00, 0x66, 0xfe, 0x04, 0xec,
12204 0x20, 0x4f, 0xfe, 0x05,
12205 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x4a, 0x17, 0xfe, 0x08, 0x90, 0xfe,
12206 0x48, 0xf4, 0x0d, 0xfe,
12207 0x18, 0x13, 0xba, 0xfe, 0x02, 0xea, 0xd5, 0x69, 0x7e, 0xfe, 0xc5, 0x13,
12208 0x15, 0x1a, 0x39, 0xa0,
12209 0xb4, 0xfe, 0x2e, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x1e, 0xfe, 0xf0, 0xff,
12210 0x0c, 0xfe, 0x60, 0x01,
12211 0x03, 0xfe, 0x3a, 0x01, 0x0c, 0xfe, 0x62, 0x01, 0x43, 0x13, 0x20, 0x25,
12212 0x06, 0x13, 0x2f, 0x12,
12213 0x2f, 0x92, 0x0f, 0x06, 0x04, 0x21, 0x04, 0x22, 0x59, 0xfe, 0xf7, 0x12,
12214 0x22, 0x9f, 0xb7, 0x13,
12215 0x9f, 0x07, 0x7e, 0xfe, 0x71, 0x13, 0xfe, 0x24, 0x1c, 0x15, 0x19, 0x39,
12216 0xa0, 0xb4, 0xfe, 0xd9,
12217 0x10, 0xc3, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x04,
12218 0xc3, 0xfe, 0x03, 0xdc,
12219 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x21,
12220 0xfe, 0x00, 0xcc, 0x04,
12221 0xfe, 0x03, 0x57, 0xc3, 0x78, 0x04, 0x08, 0x05, 0x58, 0xfe, 0x22, 0x13,
12222 0xfe, 0x1c, 0x80, 0x07,
12223 0x06, 0xfe, 0x1a, 0x13, 0xfe, 0x1e, 0x80, 0xed, 0xfe, 0x1d, 0x80, 0xae,
12224 0xfe, 0x0c, 0x90, 0xfe,
12225 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xac, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
12226 0x0a, 0xfe, 0x3c, 0x50,
12227 0xaa, 0x01, 0xfe, 0x7a, 0x17, 0x32, 0x07, 0x2f, 0xad, 0x01, 0xfe, 0xb4,
12228 0x16, 0x08, 0x05, 0x1b,
12229 0x4e, 0x01, 0xf5, 0x01, 0xf6, 0x12, 0xfe, 0xe9, 0x00, 0x08, 0x05, 0x58,
12230 0xfe, 0x2c, 0x13, 0x01,
12231 0xfe, 0x0c, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90,
12232 0x0c, 0xfe, 0x64, 0x01,
12233 0x14, 0xfe, 0x66, 0x01, 0x08, 0x05, 0x5b, 0xfe, 0x12, 0x12, 0xfe, 0x03,
12234 0x80, 0x8d, 0xfe, 0x01,
12235 0xec, 0x20, 0xfe, 0x80, 0x40, 0x13, 0x20, 0x6a, 0x2a, 0x12, 0xcf, 0x64,
12236 0x22, 0x20, 0xfb, 0x79,
12237 0x20, 0x04, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58,
12238 0x03, 0xfe, 0xae, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070012239
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012240 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe,
12241 0xb2, 0x00, 0xfe, 0x09,
12242 0x58, 0xfe, 0x0a, 0x1c, 0x25, 0x6e, 0x13, 0xd0, 0x21, 0x0c, 0x5c, 0x0c,
12243 0x45, 0x0f, 0x46, 0x52,
12244 0x50, 0x18, 0x1b, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xfe, 0xfc,
12245 0x0f, 0x44, 0x11, 0x0f,
12246 0x48, 0x52, 0x18, 0x58, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xe4,
12247 0x25, 0x11, 0x13, 0x20,
12248 0x7c, 0x6f, 0x4f, 0x22, 0x20, 0xfb, 0x79, 0x20, 0x12, 0xcf, 0xfe, 0x14,
12249 0x56, 0xfe, 0xd6, 0xf0,
12250 0xfe, 0x26, 0x10, 0xf8, 0x74, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
12251 0x18, 0x1c, 0x04, 0x42,
12252 0xfe, 0x0c, 0x14, 0xfc, 0xfe, 0x07, 0xe6, 0x1b, 0xfe, 0xce, 0x47, 0xfe,
12253 0xf5, 0x13, 0x04, 0x01,
12254 0xb0, 0x7c, 0x6f, 0x4f, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42,
12255 0x13, 0x32, 0x07, 0x2f,
12256 0xfe, 0x34, 0x13, 0x09, 0x48, 0x01, 0x0e, 0xbb, 0xfe, 0x36, 0x12, 0xfe,
12257 0x41, 0x48, 0xfe, 0x45,
12258 0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78,
12259 0x07, 0x11, 0xac, 0x09,
12260 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x73, 0xfe, 0x0e, 0x10, 0x07,
12261 0x82, 0x4e, 0xfe, 0x14,
12262 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x60, 0x10, 0x04, 0xfe, 0x44, 0x58, 0x8d,
12263 0xfe, 0x01, 0xec, 0xa2,
12264 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1a, 0x79,
12265 0x2a, 0x01, 0xe3, 0xfe,
12266 0xdd, 0x10, 0x2c, 0xc7, 0x81, 0xc8, 0x83, 0x33, 0x31, 0xde, 0x07, 0x1a,
12267 0xfe, 0x48, 0x12, 0x07,
12268 0x0a, 0xfe, 0x56, 0x12, 0x07, 0x19, 0xfe, 0x30, 0x12, 0x07, 0xc9, 0x17,
12269 0xfe, 0x32, 0x12, 0x07,
12270 0xfe, 0x23, 0x00, 0x17, 0xeb, 0x07, 0x06, 0x17, 0xfe, 0x9c, 0x12, 0x07,
12271 0x1f, 0xfe, 0x12, 0x12,
12272 0x07, 0x00, 0x17, 0x24, 0x15, 0xc9, 0x01, 0x36, 0xa9, 0x2d, 0x01, 0x0b,
12273 0x94, 0x4b, 0x04, 0x2d,
12274 0xdd, 0x09, 0xd1, 0x01, 0xfe, 0x26, 0x0f, 0x12, 0x82, 0x02, 0x2b, 0x2d,
12275 0x32, 0x07, 0xa6, 0xfe,
12276 0xd9, 0x13, 0x3a, 0x3d, 0x3b, 0x3e, 0x56, 0xfe, 0xf0, 0x11, 0x08, 0x05,
12277 0x5a, 0xfe, 0x72, 0x12,
12278 0x9b, 0x2e, 0x9c, 0x3c, 0x90, 0xc0, 0x96, 0xfe, 0xba, 0x11, 0x22, 0x62,
12279 0xfe, 0x26, 0x13, 0x03,
12280 0x7f, 0x29, 0x80, 0x56, 0xfe, 0x76, 0x0d, 0x0c, 0x60, 0x14, 0x61, 0x21,
12281 0x0c, 0x7f, 0x0c, 0x80,
12282 0x01, 0xb3, 0x25, 0x6e, 0x77, 0x13, 0x62, 0x01, 0xef, 0x9b, 0x2e, 0x9c,
12283 0x3c, 0xfe, 0x04, 0x55,
12284 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0xfe,
12285 0x91, 0x10, 0x03, 0x3f,
12286 0x29, 0x40, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x3f, 0x14, 0x40,
12287 0x88, 0x9b, 0x2e, 0x9c,
12288 0x3c, 0x90, 0xc0, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x00, 0x56, 0xfe, 0xa1,
12289 0x56, 0x0c, 0x5e, 0x14,
12290 0x5f, 0x08, 0x05, 0x5a, 0xfe, 0x1e, 0x12, 0x22, 0x62, 0xfe, 0x1f, 0x40,
12291 0x03, 0x60, 0x29, 0x61,
12292 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x03, 0x3f, 0x29, 0x40, 0xfe, 0x44,
12293 0x50, 0xfe, 0xc6, 0x50,
12294 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x3d,
12295 0x29, 0x3e, 0xfe, 0x40,
12296 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x89, 0x25, 0x06, 0x13, 0xd4, 0x02, 0x72,
12297 0x2d, 0x01, 0x0b, 0x1d,
12298 0x4c, 0x33, 0x31, 0xde, 0x07, 0x06, 0x23, 0x4c, 0x32, 0x07, 0xa6, 0x23,
12299 0x72, 0x01, 0xaf, 0x1e,
12300 0x43, 0x17, 0x4c, 0x08, 0x05, 0x0a, 0xee, 0x3a, 0x3d, 0x3b, 0x3e, 0xfe,
12301 0x0a, 0x55, 0x35, 0xfe,
12302 0x8b, 0x55, 0x57, 0x3d, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51,
12303 0x02, 0x72, 0xfe, 0x19,
12304 0x81, 0xba, 0xfe, 0x19, 0x41, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1c, 0x34,
12305 0x1d, 0xe8, 0x33, 0x31,
12306 0xe1, 0x55, 0x19, 0xfe, 0xa6, 0x12, 0x55, 0x0a, 0x4d, 0x02, 0x4c, 0x01,
12307 0x0b, 0x1c, 0x34, 0x1d,
12308 0xe8, 0x33, 0x31, 0xdf, 0x07, 0x19, 0x23, 0x4c, 0x01, 0x0b, 0x1d, 0xe8,
12309 0x33, 0x31, 0xfe, 0xe8,
12310 0x09, 0xfe, 0xc2, 0x49, 0x51, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0x8a, 0x53,
12311 0x05, 0x1f, 0x35, 0xa9,
12312 0xfe, 0xbb, 0x45, 0x55, 0x00, 0x4e, 0x44, 0x06, 0x7c, 0x43, 0xfe, 0xda,
12313 0x14, 0x01, 0xaf, 0x8c,
12314 0xfe, 0x4b, 0x45, 0xee, 0x32, 0x07, 0xa5, 0xed, 0x03, 0xcd, 0x28, 0x8a,
12315 0x03, 0x45, 0x28, 0x35,
12316 0x67, 0x02, 0x72, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17,
12317 0x03, 0x5c, 0xc1, 0x0c,
12318 0x5c, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, 0xfe, 0x9e, 0x15, 0x02,
12319 0x89, 0x01, 0x0b, 0x1c,
12320 0x34, 0x1d, 0x4c, 0x33, 0x31, 0xdf, 0x07, 0x06, 0x23, 0x4c, 0x01, 0xf1,
12321 0xfe, 0x42, 0x58, 0xf1,
12322 0xfe, 0xa4, 0x14, 0x8c, 0xfe, 0x4a, 0xf4, 0x0a, 0x17, 0x4c, 0xfe, 0x4a,
12323 0xf4, 0x06, 0xea, 0x32,
12324 0x07, 0xa5, 0x8b, 0x02, 0x72, 0x03, 0x45, 0xc1, 0x0c, 0x45, 0x67, 0x2d,
12325 0x01, 0x0b, 0x26, 0x89,
12326 0x01, 0xfe, 0xcc, 0x15, 0x02, 0x89, 0x0f, 0x06, 0x27, 0xfe, 0xbe, 0x13,
12327 0x26, 0xfe, 0xd4, 0x13,
12328 0x76, 0xfe, 0x89, 0x48, 0x01, 0x0b, 0x21, 0x76, 0x04, 0x7b, 0xfe, 0xd0,
12329 0x13, 0x1c, 0xfe, 0xd0,
12330 0x13, 0x1d, 0xfe, 0xbe, 0x13, 0x67, 0x2d, 0x01, 0x0b, 0xfe, 0xd5, 0x10,
12331 0x0f, 0x71, 0xff, 0x02,
12332 0x00, 0x57, 0x52, 0x93, 0x1e, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe,
12333 0x00, 0x5c, 0x04, 0x0f,
12334 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0xfe, 0x30, 0x56,
12335 0xfe, 0x00, 0x5c, 0x04,
12336 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x04, 0x0f, 0x71, 0xff,
12337 0x02, 0x00, 0x57, 0x52,
12338 0x93, 0xfe, 0x0b, 0x58, 0x04, 0x09, 0x5c, 0x01, 0x87, 0x09, 0x45, 0x01,
12339 0x87, 0x04, 0xfe, 0x03,
12340 0xa1, 0x1e, 0x11, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x1f, 0x52,
12341 0xfe, 0x00, 0x7d, 0xfe,
12342 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x6a, 0x2a, 0x0c, 0x5e,
12343 0x14, 0x5f, 0x57, 0x3f,
12344 0x7d, 0x40, 0x04, 0xdd, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83,
12345 0x5a, 0x8d, 0x04, 0x01,
12346 0xfe, 0x0c, 0x19, 0xfe, 0x42, 0x48, 0x50, 0x51, 0x91, 0x01, 0x0b, 0x1d,
12347 0xfe, 0x96, 0x15, 0x33,
12348 0x31, 0xe1, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15, 0x33, 0x31, 0xfe, 0xe8,
12349 0x0a, 0xfe, 0xc1, 0x59,
12350 0x03, 0xcd, 0x28, 0xfe, 0xcc, 0x12, 0x53, 0x05, 0x1a, 0xfe, 0xc4, 0x13,
12351 0x21, 0x69, 0x1a, 0xee,
12352 0x55, 0xca, 0x6b, 0xfe, 0xdc, 0x14, 0x4d, 0x0f, 0x06, 0x18, 0xca, 0x7c,
12353 0x30, 0xfe, 0x78, 0x10,
12354 0xff, 0x02, 0x83, 0x55, 0xab, 0xff, 0x02, 0x83, 0x55, 0x69, 0x19, 0xae,
12355 0x98, 0xfe, 0x30, 0x00,
12356 0x96, 0xf2, 0x18, 0x6d, 0x0f, 0x06, 0xfe, 0x56, 0x10, 0x69, 0x0a, 0xed,
12357 0x98, 0xfe, 0x64, 0x00,
12358 0x96, 0xf2, 0x09, 0xfe, 0x64, 0x00, 0x18, 0x9e, 0x0f, 0x06, 0xfe, 0x28,
12359 0x10, 0x69, 0x06, 0xfe,
12360 0x60, 0x13, 0x98, 0xfe, 0xc8, 0x00, 0x96, 0xf2, 0x09, 0xfe, 0xc8, 0x00,
12361 0x18, 0x59, 0x0f, 0x06,
12362 0x88, 0x98, 0xfe, 0x90, 0x01, 0x7a, 0xfe, 0x42, 0x15, 0x91, 0xe4, 0xfe,
12363 0x43, 0xf4, 0x9f, 0xfe,
12364 0x56, 0xf0, 0xfe, 0x54, 0x15, 0xfe, 0x04, 0xf4, 0x71, 0xfe, 0x43, 0xf4,
12365 0x9e, 0xfe, 0xf3, 0x10,
12366 0xfe, 0x40, 0x5c, 0x01, 0xfe, 0x16, 0x14, 0x1e, 0x43, 0xec, 0xfe, 0x00,
12367 0x17, 0xfe, 0x4d, 0xe4,
12368 0x6e, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0x6e, 0xfe, 0x1c, 0x10, 0xfe, 0x00,
12369 0x17, 0xfe, 0x4d, 0xe4,
12370 0xcc, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0xcc, 0x88, 0x51, 0x21, 0xfe, 0x4d,
12371 0xf4, 0x00, 0xe9, 0x91,
12372 0x0f, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x04, 0x51, 0x0f, 0x0a,
12373 0x04, 0x16, 0x06, 0x01,
12374 0x0b, 0x26, 0xf3, 0x16, 0x0a, 0x01, 0x0b, 0x26, 0xf3, 0x16, 0x19, 0x01,
12375 0x0b, 0x26, 0xf3, 0x76,
12376 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1,
12377 0x16, 0x19, 0x01, 0x0b,
12378 0x26, 0xb1, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1, 0xfe, 0x89, 0x49, 0x01,
12379 0x0b, 0x26, 0xb1, 0x76,
12380 0xfe, 0x89, 0x4a, 0x01, 0x0b, 0x04, 0x51, 0x04, 0x22, 0xd3, 0x07, 0x06,
12381 0xfe, 0x48, 0x13, 0xb8,
12382 0x13, 0xd3, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x76, 0xa9, 0x67, 0xfe, 0x01,
12383 0xec, 0xfe, 0x27, 0x01,
12384 0xfe, 0x89, 0x48, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x2e, 0x16, 0x32,
12385 0x07, 0xfe, 0xe3, 0x00,
12386 0xfe, 0x20, 0x13, 0x1d, 0xfe, 0x52, 0x16, 0x21, 0x13, 0xd4, 0x01, 0x4b,
12387 0x22, 0xd4, 0x07, 0x06,
12388 0x4e, 0x08, 0x54, 0x06, 0x37, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfb, 0x8e,
12389 0x07, 0x11, 0xae, 0x09,
12390 0x84, 0x01, 0x0e, 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x84, 0x01,
12391 0x0e, 0x8e, 0xfe, 0x80,
12392 0xe7, 0x11, 0x07, 0x11, 0x8a, 0xfe, 0x45, 0x58, 0x01, 0xf0, 0x8e, 0x04,
12393 0x09, 0x48, 0x01, 0x0e,
12394 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x80,
12395 0x80, 0xfe, 0x80, 0x4c,
12396 0xfe, 0x49, 0xe4, 0x11, 0xae, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c,
12397 0x09, 0x5d, 0x01, 0x87,
12398 0x04, 0x18, 0x11, 0x75, 0x6c, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe,
12399 0x19, 0xde, 0xfe, 0x24,
12400 0x1c, 0xfe, 0x1d, 0xf7, 0x1b, 0x97, 0xfe, 0xee, 0x16, 0x01, 0xfe, 0xf4,
12401 0x17, 0xad, 0x9a, 0x1b,
12402 0x6c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x04, 0xb9, 0x23, 0xfe, 0xde,
12403 0x16, 0xfe, 0xda, 0x10,
12404 0x18, 0x11, 0x75, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1f, 0xfe,
12405 0x18, 0x58, 0x03, 0xfe,
12406 0x66, 0x01, 0xfe, 0x19, 0x58, 0x9a, 0x1f, 0xfe, 0x3c, 0x90, 0xfe, 0x30,
12407 0xf4, 0x06, 0xfe, 0x3c,
12408 0x50, 0x6c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x1f,
12409 0x97, 0xfe, 0x38, 0x17,
12410 0xfe, 0xb6, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x10, 0x17, 0xfe, 0x9c,
12411 0x10, 0x18, 0x11, 0x75,
12412 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7,
12413 0x2e, 0x97, 0xfe, 0x5a,
12414 0x17, 0xfe, 0x94, 0x14, 0xec, 0x9a, 0x2e, 0x6c, 0x1a, 0xfe, 0xaf, 0x19,
12415 0xfe, 0x98, 0xe7, 0x00,
12416 0x04, 0xb9, 0x23, 0xfe, 0x4e, 0x17, 0xfe, 0x6c, 0x10, 0x18, 0x11, 0x75,
12417 0xfe, 0x30, 0xbc, 0xfe,
12418 0xb2, 0xbc, 0x9a, 0xcb, 0x6c, 0x1a, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
12419 0xcb, 0x97, 0xfe, 0x92,
12420 0x17, 0xfe, 0x5c, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x7e, 0x17, 0xfe,
12421 0x42, 0x10, 0xfe, 0x02,
12422 0xf6, 0x11, 0x75, 0xfe, 0x18, 0xfe, 0x60, 0xfe, 0x19, 0xfe, 0x61, 0xfe,
12423 0x03, 0xa1, 0xfe, 0x1d,
12424 0xf7, 0x5b, 0x97, 0xfe, 0xb8, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13,
12425 0x9a, 0x5b, 0x41, 0xfe,
12426 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x11, 0xfe, 0x81, 0xe7,
12427 0x11, 0x12, 0xfe, 0xdd,
12428 0x00, 0x6a, 0x2a, 0x04, 0x6a, 0x2a, 0xfe, 0x12, 0x45, 0x23, 0xfe, 0xa8,
12429 0x17, 0x15, 0x06, 0x39,
12430 0xa0, 0xb4, 0x02, 0x2b, 0xfe, 0x39, 0xf0, 0xfe, 0xfc, 0x17, 0x21, 0x04,
12431 0xfe, 0x7e, 0x18, 0x1e,
12432 0x19, 0x66, 0x0f, 0x0d, 0x04, 0x75, 0x03, 0xd2, 0x1e, 0x06, 0xfe, 0xef,
12433 0x12, 0xfe, 0xe1, 0x10,
12434 0x7c, 0x6f, 0x4f, 0x32, 0x07, 0x2f, 0xfe, 0x3c, 0x13, 0xf1, 0xfe, 0x42,
12435 0x13, 0x42, 0x92, 0x09,
12436 0x48, 0x01, 0x0e, 0xbb, 0xeb, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
12437 0xf0, 0xfe, 0x00, 0xcc,
12438 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, 0x84, 0x01,
12439 0x0e, 0xfe, 0x80, 0x4c,
12440 0x01, 0x73, 0xfe, 0x16, 0x10, 0x07, 0x82, 0x8b, 0xfe, 0x40, 0x14, 0xfe,
12441 0x24, 0x12, 0xfe, 0x14,
12442 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x1c, 0x18, 0x18, 0x0a, 0x04, 0xfe, 0x9c,
12443 0xe7, 0x0a, 0x10, 0xfe,
12444 0x15, 0x00, 0x64, 0x79, 0x2a, 0x01, 0xe3, 0x18, 0x06, 0x04, 0x42, 0x92,
12445 0x08, 0x54, 0x1b, 0x37,
12446 0x12, 0x2f, 0x01, 0x73, 0x18, 0x06, 0x04, 0xfe, 0x38, 0x90, 0xfe, 0xba,
12447 0x90, 0x3a, 0xce, 0x3b,
12448 0xcf, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x04, 0x22, 0xa3, 0x77,
12449 0x13, 0xa3, 0x04, 0x09,
12450 0xa4, 0x01, 0x0e, 0xfe, 0x41, 0x48, 0x09, 0x46, 0x01, 0x0e, 0xfe, 0x49,
12451 0x44, 0x17, 0xfe, 0xe8,
12452 0x18, 0x77, 0x78, 0x04, 0x09, 0x48, 0x01, 0x0e, 0x07, 0x11, 0x4e, 0x09,
12453 0x5d, 0x01, 0xa8, 0x09,
12454 0x46, 0x01, 0x0e, 0x77, 0x78, 0x04, 0xfe, 0x4e, 0xe4, 0x19, 0x6b, 0xfe,
12455 0x1c, 0x19, 0x03, 0xfe,
12456 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xc9,
12457 0x6b, 0xfe, 0x2e, 0x19,
12458 0x03, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1a, 0xe5, 0xfe, 0x4e, 0xe4,
12459 0xfe, 0x0b, 0x00, 0x6b,
12460 0xfe, 0x40, 0x19, 0x03, 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x1f, 0xfe,
12461 0x08, 0x10, 0x03, 0xfe,
12462 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x6d, 0xfe, 0x4e, 0x45, 0xea, 0xba, 0xff,
12463 0x04, 0x68, 0x54, 0xe7,
12464 0x1e, 0x6e, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe,
12465 0x1a, 0xf4, 0xfe, 0x00,
12466 0x04, 0xea, 0xfe, 0x48, 0xf4, 0x19, 0x7a, 0xfe, 0x74, 0x19, 0x0f, 0x19,
12467 0x04, 0x07, 0x7e, 0xfe,
12468 0x5a, 0xf0, 0xfe, 0x84, 0x19, 0x25, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
12469 0x07, 0x1a, 0xfe, 0x5a,
12470 0xf0, 0xfe, 0x92, 0x19, 0x25, 0xca, 0xfe, 0x26, 0x10, 0x07, 0x19, 0x66,
12471 0x25, 0x6d, 0xe5, 0x07,
12472 0x0a, 0x66, 0x25, 0x9e, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x66, 0x25, 0x59,
12473 0xa9, 0xb8, 0x04, 0x15,
12474 0xfe, 0x09, 0x00, 0x01, 0x36, 0xfe, 0x04, 0xfe, 0x81, 0x03, 0x83, 0xfe,
12475 0x40, 0x5c, 0x04, 0x1c,
12476 0xf7, 0xfe, 0x14, 0xf0, 0x0b, 0x27, 0xfe, 0xd6, 0x19, 0x1c, 0xf7, 0x7b,
12477 0xf7, 0xfe, 0x82, 0xf0,
12478 0xfe, 0xda, 0x19, 0x04, 0xff, 0xcc, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070012479};
12480
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012481static unsigned short _adv_asc38C0800_size = sizeof(_adv_asc38C0800_buf); /* 0x14E1 */
12482static ADV_DCNT _adv_asc38C0800_chksum = 0x050D3FD8UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012483
12484/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012485static unsigned char _adv_asc38C1600_buf[] = {
12486 0x00, 0x00, 0x00, 0xf2, 0x00, 0x16, 0x00, 0xfc, 0x00, 0x10, 0x00, 0xf0,
12487 0x18, 0xe4, 0x01, 0x00,
12488 0x04, 0x1e, 0x48, 0xe4, 0x03, 0xf6, 0xf7, 0x13, 0x2e, 0x1e, 0x02, 0x00,
12489 0x07, 0x17, 0xc0, 0x5f,
12490 0x00, 0xfa, 0xff, 0xff, 0x04, 0x00, 0x00, 0xf6, 0x09, 0xe7, 0x82, 0xe7,
12491 0x85, 0xf0, 0x86, 0xf0,
12492 0x4e, 0x10, 0x9e, 0xe7, 0xff, 0x00, 0x55, 0xf0, 0x01, 0xf6, 0x03, 0x00,
12493 0x98, 0x57, 0x01, 0xe6,
12494 0x00, 0xea, 0x00, 0xec, 0x01, 0xfa, 0x18, 0xf4, 0x08, 0x00, 0xf0, 0x1d,
12495 0x38, 0x54, 0x32, 0xf0,
12496 0x10, 0x00, 0xc2, 0x0e, 0x1e, 0xf0, 0xd5, 0xf0, 0xbc, 0x00, 0x4b, 0xe4,
12497 0x00, 0xe6, 0xb1, 0xf0,
12498 0xb4, 0x00, 0x02, 0x13, 0x3e, 0x1c, 0xc8, 0x47, 0x3e, 0x00, 0xd8, 0x01,
12499 0x06, 0x13, 0x0c, 0x1c,
12500 0x5e, 0x1e, 0x00, 0x57, 0xc8, 0x57, 0x01, 0xfc, 0xbc, 0x0e, 0xa2, 0x12,
12501 0xb9, 0x54, 0x00, 0x80,
12502 0x62, 0x0a, 0x5a, 0x12, 0xc8, 0x15, 0x3e, 0x1e, 0x18, 0x40, 0xbd, 0x56,
12503 0x03, 0xe6, 0x01, 0xea,
12504 0x5c, 0xf0, 0x0f, 0x00, 0x20, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12,
12505 0x04, 0x13, 0xbb, 0x55,
12506 0x3c, 0x56, 0x3e, 0x57, 0x03, 0x58, 0x4a, 0xe4, 0x40, 0x00, 0xb6, 0x00,
12507 0xbb, 0x00, 0xc0, 0x00,
12508 0x00, 0x01, 0x01, 0x01, 0x3e, 0x01, 0x58, 0x0a, 0x44, 0x10, 0x0a, 0x12,
12509 0x4c, 0x1c, 0x4e, 0x1c,
12510 0x02, 0x4a, 0x30, 0xe4, 0x05, 0xe6, 0x0c, 0x00, 0x3c, 0x00, 0x80, 0x00,
12511 0x24, 0x01, 0x3c, 0x01,
12512 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01,
12513 0x78, 0x01, 0x7c, 0x01,
12514 0xc6, 0x0e, 0x0c, 0x10, 0xac, 0x12, 0xae, 0x12, 0x16, 0x1a, 0x32, 0x1c,
12515 0x6e, 0x1e, 0x02, 0x48,
12516 0x3a, 0x55, 0xc9, 0x57, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x06, 0xf7,
12517 0x03, 0xfc, 0x06, 0x00,
12518 0x1e, 0x00, 0xbe, 0x00, 0xe1, 0x00, 0x0c, 0x12, 0x18, 0x1a, 0x70, 0x1a,
12519 0x30, 0x1c, 0x38, 0x1c,
12520 0x10, 0x44, 0x00, 0x4c, 0xb0, 0x57, 0x40, 0x5c, 0x4d, 0xe4, 0x04, 0xea,
12521 0x5d, 0xf0, 0xa7, 0xf0,
12522 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x09, 0x00, 0x19, 0x00, 0x32, 0x00,
12523 0x33, 0x00, 0x34, 0x00,
12524 0x36, 0x00, 0x98, 0x00, 0x9e, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01,
12525 0x79, 0x01, 0x3c, 0x09,
12526 0x68, 0x0d, 0x02, 0x10, 0x04, 0x10, 0x3a, 0x10, 0x08, 0x12, 0x0a, 0x13,
12527 0x40, 0x16, 0x50, 0x16,
12528 0x00, 0x17, 0x4a, 0x19, 0x00, 0x4e, 0x00, 0x54, 0x01, 0x58, 0x00, 0xdc,
12529 0x05, 0xf0, 0x09, 0xf0,
12530 0x59, 0xf0, 0xb8, 0xf0, 0x48, 0xf4, 0x0e, 0xf7, 0x0a, 0x00, 0x9b, 0x00,
12531 0x9c, 0x00, 0xa4, 0x00,
12532 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe7, 0x00, 0xf0, 0x03, 0x69, 0x08,
12533 0xe9, 0x09, 0x5c, 0x0c,
12534 0xb6, 0x12, 0xbc, 0x19, 0xd8, 0x1b, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c,
12535 0x42, 0x1d, 0x08, 0x44,
12536 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x89, 0x48, 0x68, 0x54,
12537 0x83, 0x55, 0x83, 0x59,
12538 0x31, 0xe4, 0x02, 0xe6, 0x07, 0xf0, 0x08, 0xf0, 0x0b, 0xf0, 0x0c, 0xf0,
12539 0x4b, 0xf4, 0x04, 0xf8,
12540 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00,
12541 0xa8, 0x00, 0xaa, 0x00,
12542 0xb9, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0x22, 0x01, 0x26, 0x01, 0x60, 0x01,
12543 0x7a, 0x01, 0x82, 0x01,
12544 0xc8, 0x01, 0xca, 0x01, 0x86, 0x02, 0x6a, 0x03, 0x18, 0x05, 0xb2, 0x07,
12545 0x68, 0x08, 0x10, 0x0d,
12546 0x06, 0x10, 0x0a, 0x10, 0x0e, 0x10, 0x12, 0x10, 0x60, 0x10, 0xed, 0x10,
12547 0xf3, 0x10, 0x06, 0x12,
12548 0x10, 0x12, 0x1e, 0x12, 0x0c, 0x13, 0x0e, 0x13, 0x10, 0x13, 0xfe, 0x9c,
12549 0xf0, 0x35, 0x05, 0xfe,
12550 0xec, 0x0e, 0xff, 0x10, 0x00, 0x00, 0xe9, 0xfe, 0x34, 0x1f, 0x00, 0xe8,
12551 0xfe, 0x88, 0x01, 0xff,
12552 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
12553 0x00, 0xfe, 0x57, 0x24,
12554 0x00, 0xfe, 0x4c, 0x00, 0x65, 0xff, 0x04, 0x00, 0x00, 0x1a, 0xff, 0x09,
12555 0x00, 0x00, 0xff, 0x08,
12556 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
12557 0xff, 0xff, 0xff, 0x13,
12558 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
12559 0xfe, 0x04, 0xf7, 0xe8,
12560 0x37, 0x7d, 0x0d, 0x01, 0xfe, 0x4a, 0x11, 0xfe, 0x04, 0xf7, 0xe8, 0x7d,
12561 0x0d, 0x51, 0x37, 0xfe,
12562 0x3d, 0xf0, 0xfe, 0x0c, 0x02, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x91, 0xf0,
12563 0xfe, 0xf8, 0x01, 0xfe,
12564 0x90, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x8f, 0xf0, 0xbc, 0x03, 0x67, 0x4d,
12565 0x05, 0xfe, 0x08, 0x0f,
12566 0x01, 0xfe, 0x78, 0x0f, 0xfe, 0xdd, 0x12, 0x05, 0xfe, 0x0e, 0x03, 0xfe,
12567 0x28, 0x1c, 0x03, 0xfe,
12568 0xa6, 0x00, 0xfe, 0xd1, 0x12, 0x3e, 0x22, 0xfe, 0xa6, 0x00, 0xac, 0xfe,
12569 0x48, 0xf0, 0xfe, 0x90,
12570 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0xaa, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc8,
12571 0x02, 0xfe, 0x46, 0xf0,
12572 0xfe, 0x5a, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x60, 0x02, 0xfe, 0x43, 0xf0,
12573 0xfe, 0x4e, 0x02, 0xfe,
12574 0x44, 0xf0, 0xfe, 0x52, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x56, 0x02, 0x1c,
12575 0x0d, 0xa2, 0x1c, 0x07,
12576 0x22, 0xb7, 0x05, 0x35, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02,
12577 0x1c, 0xf5, 0xfe, 0x1e,
12578 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0x5f, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc,
12579 0xde, 0x0a, 0x81, 0x01,
12580 0xa3, 0x05, 0x35, 0x1f, 0x95, 0x47, 0xb8, 0x01, 0xfe, 0xe4, 0x11, 0x0a,
12581 0x81, 0x01, 0x5c, 0xfe,
12582 0xbd, 0x10, 0x0a, 0x81, 0x01, 0x5c, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c,
12583 0xfe, 0x58, 0x1c, 0x1c,
12584 0x07, 0x22, 0xb7, 0x37, 0x2a, 0x35, 0xfe, 0x3d, 0xf0, 0xfe, 0x0c, 0x02,
12585 0x2b, 0xfe, 0x9e, 0x02,
12586 0xfe, 0x5a, 0x1c, 0xfe, 0x12, 0x1c, 0xfe, 0x14, 0x1c, 0x1f, 0xfe, 0x30,
12587 0x00, 0x47, 0xb8, 0x01,
12588 0xfe, 0xd4, 0x11, 0x1c, 0x07, 0x22, 0xb7, 0x05, 0xe9, 0x21, 0x2c, 0x09,
12589 0x1a, 0x31, 0xfe, 0x69,
12590 0x10, 0x1c, 0x07, 0x22, 0xb7, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0x01, 0xfe,
12591 0x1e, 0x1e, 0x20, 0x2c,
12592 0xfe, 0x05, 0xf6, 0xde, 0x01, 0xfe, 0x62, 0x1b, 0x01, 0x0c, 0x61, 0x4a,
12593 0x44, 0x15, 0x56, 0x51,
12594 0x01, 0xfe, 0x9e, 0x1e, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x0a, 0x57,
12595 0x01, 0x18, 0x09, 0x00,
12596 0x36, 0x01, 0x85, 0xfe, 0x18, 0x10, 0xfe, 0x41, 0x58, 0x0a, 0xba, 0x01,
12597 0x18, 0xfe, 0xc8, 0x54,
12598 0x7b, 0xfe, 0x1c, 0x03, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x37, 0x60,
12599 0xfe, 0x02, 0xe8, 0x30,
12600 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, 0x27, 0xf0,
12601 0xfe, 0xe4, 0x01, 0xfe,
12602 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x40, 0x1c, 0x2a, 0xeb, 0xfe,
12603 0x26, 0xf0, 0xfe, 0x66,
12604 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x54, 0x03, 0xfe, 0x11, 0xf0, 0xbc, 0xfe,
12605 0xef, 0x10, 0xfe, 0x9f,
12606 0xf0, 0xfe, 0x74, 0x03, 0xfe, 0x46, 0x1c, 0x19, 0xfe, 0x11, 0x00, 0x05,
12607 0x70, 0x37, 0xfe, 0x48,
12608 0x1c, 0xfe, 0x46, 0x1c, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x18, 0x13, 0x26,
12609 0x21, 0xb9, 0xc7, 0x20,
12610 0xb9, 0x0a, 0x57, 0x01, 0x18, 0xc7, 0x89, 0x01, 0xfe, 0xc8, 0x1a, 0x15,
12611 0xe1, 0x2a, 0xeb, 0xfe,
12612 0x01, 0xf0, 0xeb, 0xfe, 0x82, 0xf0, 0xfe, 0xa4, 0x03, 0xfe, 0x9c, 0x32,
12613 0x15, 0xfe, 0xe4, 0x00,
12614 0x2f, 0xfe, 0xb6, 0x03, 0x2a, 0x3c, 0x16, 0xfe, 0xc6, 0x03, 0x01, 0x41,
12615 0xfe, 0x06, 0xf0, 0xfe,
12616 0xd6, 0x03, 0xaf, 0xa0, 0xfe, 0x0a, 0xf0, 0xfe, 0xa2, 0x07, 0x05, 0x29,
12617 0x03, 0x81, 0x1e, 0x1b,
12618 0xfe, 0x24, 0x05, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, 0x05,
12619 0xea, 0xfe, 0x46, 0x1c,
12620 0x37, 0x7d, 0x1d, 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
12621 0xfe, 0x48, 0x1c, 0x75,
12622 0x01, 0xa6, 0x86, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, 0x1b, 0xec, 0x0a,
12623 0xe1, 0x01, 0x18, 0x77,
12624 0x50, 0x40, 0x8d, 0x30, 0x03, 0x81, 0x1e, 0xf8, 0x1f, 0x63, 0x01, 0x42,
12625 0x8f, 0xfe, 0x70, 0x02,
12626 0x05, 0xea, 0xd7, 0x99, 0xd8, 0x9c, 0x2a, 0x29, 0x2f, 0xfe, 0x4e, 0x04,
12627 0x16, 0xfe, 0x4a, 0x04,
12628 0x7e, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x54, 0x12, 0x32, 0xff,
12629 0x02, 0x00, 0x10, 0x01,
12630 0x08, 0x16, 0xfe, 0x02, 0x05, 0x32, 0x01, 0x08, 0x16, 0x29, 0x27, 0x25,
12631 0xee, 0xfe, 0x4c, 0x44,
12632 0xfe, 0x58, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x13, 0x34, 0xfe, 0x4c, 0x54,
12633 0x7b, 0xec, 0x60, 0x8d,
12634 0x30, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x7c, 0x13, 0x01,
12635 0x0c, 0x06, 0x28, 0xfe,
12636 0x32, 0x13, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x68, 0x13, 0xfe, 0x26, 0x10,
12637 0x13, 0x34, 0xfe, 0x4c,
12638 0x54, 0x7b, 0xec, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x54,
12639 0x13, 0x01, 0x0c, 0x06,
12640 0x28, 0xa5, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x40, 0x13, 0x01, 0x0c, 0x06,
12641 0x28, 0xf9, 0x1f, 0x7f,
12642 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, 0x8f,
12643 0xfe, 0xa4, 0x0e, 0x05,
12644 0x29, 0x32, 0x15, 0xfe, 0xe6, 0x00, 0x0f, 0xfe, 0x1c, 0x90, 0x04, 0xfe,
12645 0x9c, 0x93, 0x3a, 0x0b,
12646 0x0e, 0x8b, 0x02, 0x1f, 0x7f, 0x01, 0x42, 0x05, 0x35, 0xfe, 0x42, 0x5b,
12647 0x7d, 0x1d, 0xfe, 0x46,
12648 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0x0f, 0xfe, 0x87, 0x80, 0x04,
12649 0xfe, 0x87, 0x83, 0xfe,
12650 0xc9, 0x47, 0x0b, 0x0e, 0xd0, 0x65, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x98,
12651 0x13, 0x0f, 0xfe, 0x20,
12652 0x80, 0x04, 0xfe, 0xa0, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x1d, 0xfe, 0x84,
12653 0x12, 0x01, 0x38, 0x06,
12654 0x07, 0xfe, 0x70, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x1e, 0x1b, 0xfe, 0xda,
12655 0x05, 0xd0, 0x54, 0x01,
12656 0x38, 0x06, 0x0d, 0xfe, 0x58, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x1e, 0xfe,
12657 0x50, 0x12, 0x5e, 0xff,
12658 0x02, 0x00, 0x10, 0x2f, 0xfe, 0x90, 0x05, 0x2a, 0x3c, 0xcc, 0xff, 0x02,
12659 0x00, 0x10, 0x2f, 0xfe,
12660 0x9e, 0x05, 0x17, 0xfe, 0xf4, 0x05, 0x15, 0xfe, 0xe3, 0x00, 0x26, 0x01,
12661 0x38, 0xfe, 0x4a, 0xf0,
12662 0xfe, 0xc0, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0xba, 0x05, 0x71, 0x2e, 0xfe,
12663 0x21, 0x00, 0xf1, 0x2e,
12664 0xfe, 0x22, 0x00, 0xa2, 0x2e, 0x4a, 0xfe, 0x09, 0x48, 0xff, 0x02, 0x00,
12665 0x10, 0x2f, 0xfe, 0xd0,
12666 0x05, 0x17, 0xfe, 0xf4, 0x05, 0xfe, 0xe2, 0x08, 0x01, 0x38, 0x06, 0xfe,
12667 0x1c, 0x00, 0x4d, 0x01,
12668 0xa7, 0x2e, 0x07, 0x20, 0xe4, 0x47, 0xfe, 0x27, 0x01, 0x01, 0x0c, 0x06,
12669 0x28, 0xfe, 0x24, 0x12,
12670 0x3e, 0x01, 0x84, 0x1f, 0x7f, 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe,
12671 0x0d, 0x00, 0x01, 0x42,
12672 0x8f, 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x03, 0xe6, 0x1e, 0xfe, 0xca, 0x13,
12673 0x03, 0xb6, 0x1e, 0xfe,
12674 0x40, 0x12, 0x03, 0x66, 0x1e, 0xfe, 0x38, 0x13, 0x3e, 0x01, 0x84, 0x17,
12675 0xfe, 0x72, 0x06, 0x0a,
12676 0x07, 0x01, 0x38, 0x06, 0x24, 0xfe, 0x02, 0x12, 0x4f, 0x01, 0xfe, 0x56,
12677 0x19, 0x16, 0xfe, 0x68,
12678 0x06, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x66, 0x8a, 0x10, 0x66,
12679 0x03, 0x9a, 0x1e, 0xfe,
12680 0x70, 0x12, 0x03, 0x55, 0x1e, 0xfe, 0x68, 0x13, 0x01, 0xc6, 0x09, 0x12,
12681 0x48, 0xfe, 0x92, 0x06,
12682 0x2e, 0x12, 0x01, 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0x13,
12683 0x58, 0xff, 0x02, 0x00,
12684 0x57, 0x52, 0xad, 0x23, 0x3f, 0x4e, 0x62, 0x49, 0x3e, 0x01, 0x84, 0x17,
12685 0xfe, 0xea, 0x06, 0x01,
12686 0x38, 0x06, 0x12, 0xf7, 0x45, 0x0a, 0x95, 0x01, 0xfe, 0x84, 0x19, 0x16,
12687 0xfe, 0xe0, 0x06, 0x15,
12688 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x1c, 0x07,
12689 0x01, 0x84, 0xfe, 0xae,
12690 0x10, 0x03, 0x6f, 0x1e, 0xfe, 0x9e, 0x13, 0x3e, 0x01, 0x84, 0x03, 0x9a,
12691 0x1e, 0xfe, 0x1a, 0x12,
12692 0x01, 0x38, 0x06, 0x12, 0xfc, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe,
12693 0x43, 0x48, 0x62, 0x80,
12694 0xf0, 0x45, 0x0a, 0x95, 0x03, 0xb6, 0x1e, 0xf8, 0x01, 0x38, 0x06, 0x24,
12695 0x36, 0xfe, 0x02, 0xf6,
12696 0x07, 0x71, 0x78, 0x8c, 0x00, 0x4d, 0x62, 0x49, 0x3e, 0x2d, 0x93, 0x4e,
12697 0xd0, 0x0d, 0x17, 0xfe,
12698 0x9a, 0x07, 0x01, 0xfe, 0xc0, 0x19, 0x16, 0xfe, 0x90, 0x07, 0x26, 0x20,
12699 0x9e, 0x15, 0x82, 0x01,
12700 0x41, 0x15, 0xe2, 0x21, 0x9e, 0x09, 0x07, 0xfb, 0x03, 0xe6, 0xfe, 0x58,
12701 0x57, 0x10, 0xe6, 0x05,
12702 0xfe, 0x2a, 0x06, 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x1c, 0x07, 0x01, 0x84,
12703 0xfe, 0x9c, 0x32, 0x5f,
12704 0x75, 0x01, 0xa6, 0x86, 0x15, 0xfe, 0xe2, 0x00, 0x2f, 0xed, 0x2a, 0x3c,
12705 0xfe, 0x0a, 0xf0, 0xfe,
12706 0xce, 0x07, 0xae, 0xfe, 0x96, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x9e, 0x08,
12707 0xaf, 0xa0, 0x05, 0x29,
12708 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x2e, 0x12, 0x14, 0x1d, 0x01, 0x08, 0x14,
12709 0x00, 0x01, 0x08, 0x14,
12710 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08,
12711 0x14, 0x00, 0x05, 0xfe,
12712 0xc6, 0x09, 0x01, 0x76, 0x06, 0x12, 0xfe, 0x3a, 0x12, 0x01, 0x0c, 0x06,
12713 0x12, 0xfe, 0x30, 0x13,
12714 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00,
12715 0x01, 0x08, 0x14, 0x00,
12716 0x01, 0x08, 0x14, 0x07, 0x01, 0x08, 0x14, 0x00, 0x05, 0xef, 0x7c, 0x4a,
12717 0x78, 0x4f, 0x0f, 0xfe,
12718 0x9a, 0x81, 0x04, 0xfe, 0x9a, 0x83, 0xfe, 0xcb, 0x47, 0x0b, 0x0e, 0x2d,
12719 0x28, 0x48, 0xfe, 0x6c,
12720 0x08, 0x0a, 0x28, 0xfe, 0x09, 0x6f, 0xca, 0xfe, 0xca, 0x45, 0xfe, 0x32,
12721 0x12, 0x53, 0x63, 0x4e,
12722 0x7c, 0x97, 0x2f, 0xfe, 0x7e, 0x08, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe,
12723 0x6c, 0x08, 0xaf, 0xa0,
12724 0xae, 0xfe, 0x96, 0x08, 0x05, 0x29, 0x01, 0x41, 0x05, 0xed, 0x14, 0x24,
12725 0x05, 0xed, 0xfe, 0x9c,
12726 0xf7, 0x9f, 0x01, 0xfe, 0xae, 0x1e, 0xfe, 0x18, 0x58, 0x01, 0xfe, 0xbe,
12727 0x1e, 0xfe, 0x99, 0x58,
12728 0xfe, 0x78, 0x18, 0xfe, 0xf9, 0x18, 0x8e, 0xfe, 0x16, 0x09, 0x10, 0x6a,
12729 0x22, 0x6b, 0x01, 0x0c,
12730 0x61, 0x54, 0x44, 0x21, 0x2c, 0x09, 0x1a, 0xf8, 0x77, 0x01, 0xfe, 0x7e,
12731 0x1e, 0x47, 0x2c, 0x7a,
12732 0x30, 0xf0, 0xfe, 0x83, 0xe7, 0xfe, 0x3f, 0x00, 0x71, 0xfe, 0x03, 0x40,
12733 0x01, 0x0c, 0x61, 0x65,
12734 0x44, 0x01, 0xc2, 0xc8, 0xfe, 0x1f, 0x40, 0x20, 0x6e, 0x01, 0xfe, 0x6a,
12735 0x16, 0xfe, 0x08, 0x50,
12736 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0xfe, 0x10, 0x10,
12737 0x01, 0xfe, 0xce, 0x1e,
12738 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x01, 0xfe, 0xee, 0x1e,
12739 0x01, 0xfe, 0xfe, 0x1e,
12740 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x10, 0x4b, 0x22, 0x4c, 0xfe, 0x8a,
12741 0x10, 0x01, 0x0c, 0x06,
12742 0x54, 0xfe, 0x50, 0x12, 0x01, 0xfe, 0xae, 0x1e, 0x01, 0xfe, 0xbe, 0x1e,
12743 0x10, 0x6a, 0x22, 0x6b,
12744 0x01, 0x0c, 0x06, 0x65, 0x4e, 0x01, 0xc2, 0x0f, 0xfe, 0x1f, 0x80, 0x04,
12745 0xfe, 0x9f, 0x83, 0x33,
12746 0x0b, 0x0e, 0x20, 0x6e, 0x0f, 0xfe, 0x44, 0x90, 0x04, 0xfe, 0xc4, 0x93,
12747 0x3a, 0x0b, 0xfe, 0xc6,
12748 0x90, 0x04, 0xfe, 0xc6, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x6c, 0x22, 0x6d,
12749 0x01, 0xfe, 0xce, 0x1e,
12750 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x0f, 0xfe, 0x40, 0x90,
12751 0x04, 0xfe, 0xc0, 0x93,
12752 0x3a, 0x0b, 0xfe, 0xc2, 0x90, 0x04, 0xfe, 0xc2, 0x93, 0x79, 0x0b, 0x0e,
12753 0x10, 0x4b, 0x22, 0x4c,
12754 0x10, 0x64, 0x22, 0x34, 0x01, 0x0c, 0x61, 0x24, 0x44, 0x37, 0x13, 0xfe,
12755 0x4e, 0x11, 0x2f, 0xfe,
12756 0xde, 0x09, 0xfe, 0x9e, 0xf0, 0xfe, 0xf2, 0x09, 0xfe, 0x01, 0x48, 0x1b,
12757 0x3c, 0x37, 0x88, 0xf5,
12758 0xd4, 0xfe, 0x1e, 0x0a, 0xd5, 0xfe, 0x42, 0x0a, 0xd2, 0xfe, 0x1e, 0x0a,
12759 0xd3, 0xfe, 0x42, 0x0a,
12760 0xae, 0xfe, 0x12, 0x0a, 0xfe, 0x06, 0xf0, 0xfe, 0x18, 0x0a, 0xaf, 0xa0,
12761 0x05, 0x29, 0x01, 0x41,
12762 0xfe, 0xc1, 0x10, 0x14, 0x24, 0xfe, 0xc1, 0x10, 0x01, 0x76, 0x06, 0x07,
12763 0xfe, 0x14, 0x12, 0x01,
12764 0x76, 0x06, 0x0d, 0x5d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x74, 0x12, 0xfe,
12765 0x2e, 0x1c, 0x05, 0xfe,
12766 0x1a, 0x0c, 0x01, 0x76, 0x06, 0x07, 0x5d, 0x01, 0x76, 0x06, 0x0d, 0x41,
12767 0xfe, 0x2c, 0x1c, 0xfe,
12768 0xaa, 0xf0, 0xfe, 0xce, 0x0a, 0xfe, 0xac, 0xf0, 0xfe, 0x66, 0x0a, 0xfe,
12769 0x92, 0x10, 0xc4, 0xf6,
12770 0xfe, 0xad, 0xf0, 0xfe, 0x72, 0x0a, 0x05, 0xfe, 0x1a, 0x0c, 0xc5, 0xfe,
12771 0xe7, 0x10, 0xfe, 0x2b,
12772 0xf0, 0xbf, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12,
12773 0xac, 0xfe, 0xd2, 0xf0,
12774 0xbf, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x1b, 0xbf, 0x03, 0xe3, 0x23, 0x07,
12775 0x1b, 0xbf, 0xd4, 0x5b,
12776 0xd5, 0x5b, 0xd2, 0x5b, 0xd3, 0x5b, 0xc4, 0xc5, 0xfe, 0xa9, 0x10, 0x75,
12777 0x5e, 0x32, 0x1f, 0x7f,
12778 0x01, 0x42, 0x19, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x70, 0x19, 0x98,
12779 0x05, 0x70, 0xfe, 0x74,
12780 0x18, 0x23, 0xfe, 0x00, 0xf8, 0x1b, 0x5b, 0x7d, 0x12, 0x01, 0xfe, 0x78,
12781 0x0f, 0x4d, 0x01, 0xfe,
12782 0x96, 0x1a, 0x21, 0x30, 0x77, 0x7d, 0x1d, 0x05, 0x5b, 0x01, 0x0c, 0x06,
12783 0x0d, 0x2b, 0xfe, 0xe2,
12784 0x0b, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0xa6, 0x12, 0x01, 0x0c, 0x06, 0x24,
12785 0xfe, 0x88, 0x13, 0x21,
12786 0x6e, 0xc7, 0x01, 0xfe, 0x1e, 0x1f, 0x0f, 0xfe, 0x83, 0x80, 0x04, 0xfe,
12787 0x83, 0x83, 0xfe, 0xc9,
12788 0x47, 0x0b, 0x0e, 0xfe, 0xc8, 0x44, 0xfe, 0x42, 0x13, 0x0f, 0xfe, 0x04,
12789 0x91, 0x04, 0xfe, 0x84,
12790 0x93, 0xfe, 0xca, 0x57, 0x0b, 0xfe, 0x86, 0x91, 0x04, 0xfe, 0x86, 0x93,
12791 0xfe, 0xcb, 0x57, 0x0b,
12792 0x0e, 0x7a, 0x30, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x8e, 0x40, 0x03,
12793 0x6a, 0x3b, 0x6b, 0x10,
12794 0x97, 0x22, 0x98, 0xd9, 0x6a, 0xda, 0x6b, 0x01, 0xc2, 0xc8, 0x7a, 0x30,
12795 0x20, 0x6e, 0xdb, 0x64,
12796 0xdc, 0x34, 0x91, 0x6c, 0x7e, 0x6d, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55,
12797 0xfe, 0x04, 0xfa, 0x64,
12798 0xfe, 0x05, 0xfa, 0x34, 0x01, 0xfe, 0x6a, 0x16, 0xa3, 0x26, 0x10, 0x97,
12799 0x10, 0x98, 0x91, 0x6c,
12800 0x7e, 0x6d, 0xfe, 0x14, 0x10, 0x01, 0x0c, 0x06, 0x24, 0x1b, 0x40, 0x91,
12801 0x4b, 0x7e, 0x4c, 0x01,
12802 0x0c, 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x10,
12803 0x58, 0xfe, 0x91, 0x58,
12804 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x24,
12805 0x1b, 0x40, 0x01, 0x0c,
12806 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x78, 0x01, 0xfe, 0x8e, 0x1e, 0x4f, 0x0f,
12807 0xfe, 0x10, 0x90, 0x04,
12808 0xfe, 0x90, 0x93, 0x3a, 0x0b, 0xfe, 0x92, 0x90, 0x04, 0xfe, 0x92, 0x93,
12809 0x79, 0x0b, 0x0e, 0xfe,
12810 0xbd, 0x10, 0x01, 0x43, 0x09, 0xbb, 0x1b, 0xfe, 0x6e, 0x0a, 0x15, 0xbb,
12811 0x01, 0x0c, 0x06, 0x0d,
12812 0xfe, 0x14, 0x13, 0x03, 0x4b, 0x3b, 0x4c, 0x8e, 0xfe, 0x6e, 0x0a, 0xfe,
12813 0x0c, 0x58, 0xfe, 0x8d,
12814 0x58, 0x05, 0x5b, 0x26, 0x3e, 0x0f, 0xfe, 0x19, 0x80, 0x04, 0xfe, 0x99,
12815 0x83, 0x33, 0x0b, 0x0e,
12816 0xfe, 0xe5, 0x10, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1a, 0x12, 0xfe, 0x6c,
12817 0x19, 0xfe, 0x19, 0x41,
12818 0xfe, 0x6b, 0x18, 0xac, 0xfe, 0xd1, 0xf0, 0xef, 0x1f, 0x92, 0x01, 0x42,
12819 0x19, 0xfe, 0x44, 0x00,
12820 0xfe, 0x90, 0x10, 0xfe, 0x6c, 0x19, 0xd9, 0x4b, 0xfe, 0xed, 0x19, 0xda,
12821 0x4c, 0xfe, 0x0c, 0x51,
12822 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xff, 0x31, 0xfe,
12823 0x76, 0x10, 0xac, 0xfe,
12824 0xd2, 0xf0, 0xfe, 0xba, 0x0c, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x5d, 0x03,
12825 0xe3, 0x23, 0x07, 0xfe,
12826 0x08, 0x13, 0x19, 0xfe, 0x16, 0x00, 0x05, 0x70, 0xfe, 0xd1, 0xf0, 0xfe,
12827 0xcc, 0x0c, 0x1f, 0x92,
12828 0x01, 0x42, 0x19, 0xfe, 0x17, 0x00, 0x5c, 0xfe, 0xce, 0xf0, 0xfe, 0xd2,
12829 0x0c, 0xfe, 0x3e, 0x10,
12830 0xfe, 0xcd, 0xf0, 0xfe, 0xde, 0x0c, 0x19, 0xfe, 0x22, 0x00, 0x05, 0x70,
12831 0xfe, 0xcb, 0xf0, 0xfe,
12832 0xea, 0x0c, 0x19, 0xfe, 0x24, 0x00, 0x05, 0x70, 0xfe, 0xd0, 0xf0, 0xfe,
12833 0xf4, 0x0c, 0x19, 0x94,
12834 0xfe, 0x1c, 0x10, 0xfe, 0xcf, 0xf0, 0xfe, 0xfe, 0x0c, 0x19, 0x4a, 0xf3,
12835 0xfe, 0xcc, 0xf0, 0xef,
12836 0x01, 0x76, 0x06, 0x24, 0x4d, 0x19, 0xfe, 0x12, 0x00, 0x37, 0x13, 0xfe,
12837 0x4e, 0x11, 0x2f, 0xfe,
12838 0x16, 0x0d, 0xfe, 0x9e, 0xf0, 0xfe, 0x2a, 0x0d, 0xfe, 0x01, 0x48, 0x1b,
12839 0x3c, 0x37, 0x88, 0xf5,
12840 0xd4, 0x29, 0xd5, 0x29, 0xd2, 0x29, 0xd3, 0x29, 0x37, 0xfe, 0x9c, 0x32,
12841 0x2f, 0xfe, 0x3e, 0x0d,
12842 0x2a, 0x3c, 0xae, 0xfe, 0x62, 0x0d, 0xaf, 0xa0, 0xd4, 0x9f, 0xd5, 0x9f,
12843 0xd2, 0x9f, 0xd3, 0x9f,
12844 0x05, 0x29, 0x01, 0x41, 0xfe, 0xd3, 0x10, 0x15, 0xfe, 0xe8, 0x00, 0xc4,
12845 0xc5, 0x75, 0xd7, 0x99,
12846 0xd8, 0x9c, 0xfe, 0x89, 0xf0, 0x29, 0x27, 0x25, 0xbe, 0xd7, 0x99, 0xd8,
12847 0x9c, 0x2f, 0xfe, 0x8c,
12848 0x0d, 0x16, 0x29, 0x27, 0x25, 0xbd, 0xfe, 0x01, 0x48, 0xa4, 0x19, 0xfe,
12849 0x42, 0x00, 0x05, 0x70,
12850 0x90, 0x07, 0xfe, 0x81, 0x49, 0x1b, 0xfe, 0x64, 0x0e, 0x01, 0x0c, 0x06,
12851 0x0d, 0xfe, 0x44, 0x13,
12852 0x19, 0x00, 0x2d, 0x0d, 0xfe, 0x54, 0x12, 0x2d, 0xfe, 0x28, 0x00, 0x2b,
12853 0xfe, 0xda, 0x0e, 0x0a,
12854 0x57, 0x01, 0x18, 0x09, 0x00, 0x36, 0x46, 0xfe, 0x28, 0x00, 0xfe, 0xfa,
12855 0x10, 0x01, 0xfe, 0xf4,
12856 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x0a, 0xba, 0x01, 0xfe, 0x58, 0x10, 0x40,
12857 0x15, 0x56, 0x01, 0x85,
12858 0x05, 0x35, 0x19, 0xfe, 0x44, 0x00, 0x2d, 0x0d, 0xf7, 0x46, 0x0d, 0xfe,
12859 0xcc, 0x10, 0x01, 0xa7,
12860 0x46, 0x0d, 0xfe, 0xc2, 0x10, 0x01, 0xa7, 0x0f, 0xfe, 0x19, 0x82, 0x04,
12861 0xfe, 0x99, 0x83, 0xfe,
12862 0xcc, 0x47, 0x0b, 0x0e, 0xfe, 0x34, 0x46, 0xa5, 0x46, 0x0d, 0x19, 0xfe,
12863 0x43, 0x00, 0xfe, 0xa2,
12864 0x10, 0x01, 0x0c, 0x61, 0x0d, 0x44, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe,
12865 0x00, 0x1d, 0x40, 0x15,
12866 0x56, 0x01, 0x85, 0x7d, 0x0d, 0x40, 0x51, 0x01, 0xfe, 0x9e, 0x1e, 0x05,
12867 0xfe, 0x3a, 0x03, 0x01,
12868 0x0c, 0x06, 0x0d, 0x5d, 0x46, 0x0d, 0x19, 0x00, 0xfe, 0x62, 0x10, 0x01,
12869 0x76, 0x06, 0x12, 0xfe,
12870 0x5c, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x52, 0x13, 0xfe, 0x1c, 0x1c,
12871 0xfe, 0x9d, 0xf0, 0xfe,
12872 0x8e, 0x0e, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x94, 0x0e, 0x01,
12873 0x0c, 0x61, 0x12, 0x44,
12874 0xfe, 0x9f, 0x10, 0x19, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0d, 0x4f,
12875 0xfe, 0x2e, 0x10, 0x19,
12876 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x19, 0xfe, 0x47, 0x00, 0xf1, 0x19,
12877 0xfe, 0x41, 0x00, 0xa2,
12878 0x19, 0xfe, 0x24, 0x00, 0x86, 0xc4, 0xc5, 0x75, 0x03, 0x81, 0x1e, 0x2b,
12879 0xea, 0x4f, 0xfe, 0x04,
12880 0xe6, 0x12, 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x40, 0x01, 0xf4, 0x05,
12881 0x35, 0xfe, 0x12, 0x1c,
12882 0x1f, 0x0d, 0x47, 0xb5, 0xc3, 0x1f, 0xfe, 0x31, 0x00, 0x47, 0xb8, 0x01,
12883 0xfe, 0xd4, 0x11, 0x05,
12884 0xe9, 0x51, 0xfe, 0x06, 0xec, 0xe0, 0xfe, 0x0e, 0x47, 0x46, 0x28, 0xfe,
12885 0xce, 0x45, 0x31, 0x51,
12886 0xfe, 0x06, 0xea, 0xe0, 0xfe, 0x47, 0x4b, 0x45, 0xfe, 0x75, 0x57, 0x03,
12887 0x67, 0xfe, 0x98, 0x56,
12888 0xfe, 0x38, 0x12, 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x44, 0x48, 0x60, 0x01,
12889 0x0c, 0x06, 0x28, 0xfe,
12890 0x18, 0x13, 0x0a, 0x57, 0x01, 0x18, 0x3e, 0xfe, 0x41, 0x58, 0x0a, 0xba,
12891 0xfe, 0xfa, 0x14, 0xfe,
12892 0x49, 0x54, 0xb0, 0xfe, 0x5e, 0x0f, 0x05, 0xfe, 0x3a, 0x03, 0x0a, 0x67,
12893 0xfe, 0xe0, 0x14, 0xfe,
12894 0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0xce, 0x47,
12895 0xfe, 0xad, 0x13, 0x05,
12896 0x35, 0x21, 0x2c, 0x09, 0x1a, 0xfe, 0x98, 0x12, 0x26, 0x20, 0x96, 0x20,
12897 0xe7, 0xfe, 0x08, 0x1c,
12898 0xfe, 0x7c, 0x19, 0xfe, 0xfd, 0x19, 0xfe, 0x0a, 0x1c, 0x03, 0xe5, 0xfe,
12899 0x48, 0x55, 0xa5, 0x3b,
12900 0xfe, 0x62, 0x01, 0xfe, 0xc9, 0x55, 0x31, 0xfe, 0x74, 0x10, 0x01, 0xfe,
12901 0xf0, 0x1a, 0x03, 0xfe,
12902 0x38, 0x01, 0x3b, 0xfe, 0x3a, 0x01, 0x8e, 0xfe, 0x1e, 0x10, 0xfe, 0x02,
12903 0xec, 0xe7, 0x53, 0x00,
12904 0x36, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01,
12905 0x01, 0xfe, 0x62, 0x1b,
12906 0x01, 0xfe, 0xce, 0x1e, 0xb2, 0x11, 0xfe, 0x18, 0x13, 0xca, 0xfe, 0x02,
12907 0xea, 0xe7, 0x53, 0x92,
12908 0xfe, 0xc3, 0x13, 0x1f, 0x12, 0x47, 0xb5, 0xc3, 0xfe, 0x2a, 0x10, 0x03,
12909 0xfe, 0x38, 0x01, 0x23,
12910 0xfe, 0xf0, 0xff, 0x10, 0xe5, 0x03, 0xfe, 0x3a, 0x01, 0x10, 0xfe, 0x62,
12911 0x01, 0x01, 0xfe, 0x1e,
12912 0x1e, 0x20, 0x2c, 0x15, 0x56, 0x01, 0xfe, 0x9e, 0x1e, 0x13, 0x07, 0x02,
12913 0x26, 0x02, 0x21, 0x96,
12914 0xc7, 0x20, 0x96, 0x09, 0x92, 0xfe, 0x79, 0x13, 0x1f, 0x1d, 0x47, 0xb5,
12915 0xc3, 0xfe, 0xe1, 0x10,
12916 0xcf, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xcf,
12917 0xfe, 0x03, 0xdc, 0xfe,
12918 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x26, 0xfe,
12919 0x00, 0xcc, 0x02, 0xfe,
12920 0x03, 0x57, 0xcf, 0x89, 0x02, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13,
12921 0x0f, 0xfe, 0x1c, 0x80,
12922 0x04, 0xfe, 0x9c, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x07, 0xfe, 0x3a, 0x13,
12923 0x0f, 0xfe, 0x1e, 0x80,
12924 0x04, 0xfe, 0x9e, 0x83, 0x33, 0x0b, 0x0e, 0xfe, 0x2a, 0x13, 0x0f, 0xfe,
12925 0x1d, 0x80, 0x04, 0xfe,
12926 0x9d, 0x83, 0xfe, 0xf9, 0x13, 0x0e, 0xfe, 0x1c, 0x13, 0x01, 0xfe, 0xee,
12927 0x1e, 0xac, 0xfe, 0x14,
12928 0x13, 0x01, 0xfe, 0xfe, 0x1e, 0xfe, 0x81, 0x58, 0xfa, 0x01, 0xfe, 0x0e,
12929 0x1f, 0xfe, 0x30, 0xf4,
12930 0x0d, 0xfe, 0x3c, 0x50, 0xa2, 0x01, 0xfe, 0x92, 0x1b, 0x01, 0x43, 0x09,
12931 0x56, 0xfb, 0x01, 0xfe,
12932 0xc8, 0x1a, 0x01, 0x0c, 0x06, 0x28, 0xa4, 0x01, 0xfe, 0xf4, 0x1c, 0x01,
12933 0xfe, 0x00, 0x1d, 0x15,
12934 0xfe, 0xe9, 0x00, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x01, 0xfe,
12935 0x22, 0x1b, 0xfe, 0x1e,
12936 0x1c, 0x0f, 0xfe, 0x14, 0x90, 0x04, 0xfe, 0x94, 0x93, 0x3a, 0x0b, 0xfe,
12937 0x96, 0x90, 0x04, 0xfe,
12938 0x96, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0xfe, 0x64, 0x01, 0x22, 0xfe, 0x66,
12939 0x01, 0x01, 0x0c, 0x06,
12940 0x65, 0xf9, 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b,
12941 0x0e, 0x77, 0xfe, 0x01,
12942 0xec, 0x2c, 0xfe, 0x80, 0x40, 0x20, 0x2c, 0x7a, 0x30, 0x15, 0xdf, 0x40,
12943 0x21, 0x2c, 0xfe, 0x00,
12944 0x40, 0x8d, 0x2c, 0x02, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe,
12945 0x06, 0x58, 0x03, 0xfe,
12946 0xae, 0x00, 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58,
12947 0x03, 0xfe, 0xb2, 0x00,
12948 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x2e, 0x49, 0x20, 0xe0, 0x26, 0x10,
12949 0x66, 0x10, 0x55, 0x10,
12950 0x6f, 0x13, 0x57, 0x52, 0x4f, 0x1c, 0x28, 0xfe, 0x90, 0x4d, 0xfe, 0x91,
12951 0x54, 0x2b, 0xfe, 0x88,
12952 0x11, 0x46, 0x1a, 0x13, 0x5a, 0x52, 0x1c, 0x4a, 0xfe, 0x90, 0x4d, 0xfe,
12953 0x91, 0x54, 0x2b, 0xfe,
12954 0x9e, 0x11, 0x2e, 0x1a, 0x20, 0x2c, 0x90, 0x34, 0x60, 0x21, 0x2c, 0xfe,
12955 0x00, 0x40, 0x8d, 0x2c,
12956 0x15, 0xdf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xb2, 0x11, 0xfe,
12957 0x12, 0x1c, 0x75, 0xfe,
12958 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x02, 0x51, 0xfe, 0x0c,
12959 0x14, 0xfe, 0x0e, 0x47,
12960 0xfe, 0x07, 0xe6, 0x28, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x02, 0x01,
12961 0xa7, 0x90, 0x34, 0x60,
12962 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0xfe, 0x02, 0x80,
12963 0x09, 0x56, 0xfe, 0x34,
12964 0x13, 0x0a, 0x5a, 0x01, 0x18, 0xcb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48,
12965 0xfe, 0x45, 0x48, 0x01,
12966 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, 0x89,
12967 0x09, 0x1a, 0xa5, 0x0a,
12968 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x5c, 0x01, 0x85, 0xf2, 0x09, 0x9b, 0xa4,
12969 0xfe, 0x14, 0x56, 0xfe,
12970 0xd6, 0xf0, 0xfe, 0xec, 0x11, 0x02, 0xfe, 0x44, 0x58, 0x77, 0xfe, 0x01,
12971 0xec, 0xb8, 0xfe, 0x9e,
12972 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x12, 0x8d, 0x30, 0x01,
12973 0xf4, 0xfe, 0xdd, 0x10,
12974 0x37, 0xd7, 0x99, 0xd8, 0x9c, 0x27, 0x25, 0xee, 0x09, 0x12, 0xfe, 0x48,
12975 0x12, 0x09, 0x0d, 0xfe,
12976 0x56, 0x12, 0x09, 0x1d, 0xfe, 0x30, 0x12, 0x09, 0xdd, 0x1b, 0xfe, 0xc4,
12977 0x13, 0x09, 0xfe, 0x23,
12978 0x00, 0x1b, 0xfe, 0xd0, 0x13, 0x09, 0x07, 0x1b, 0xfe, 0x34, 0x14, 0x09,
12979 0x24, 0xfe, 0x12, 0x12,
12980 0x09, 0x00, 0x1b, 0x29, 0x1f, 0xdd, 0x01, 0x42, 0xa1, 0x32, 0x01, 0x08,
12981 0xae, 0x41, 0x02, 0x32,
12982 0xfe, 0x62, 0x08, 0x0a, 0xe1, 0x01, 0xfe, 0x58, 0x10, 0x15, 0x9b, 0x05,
12983 0x35, 0x32, 0x01, 0x43,
12984 0x09, 0xbb, 0xfe, 0xd7, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0x8e, 0xfe, 0x80,
12985 0x13, 0x01, 0x0c, 0x06,
12986 0x54, 0xfe, 0x72, 0x12, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x44, 0x55, 0xfe,
12987 0xe5, 0x55, 0xb0, 0xfe,
12988 0x4a, 0x13, 0x21, 0x6e, 0xfe, 0x26, 0x13, 0x03, 0x97, 0x3b, 0x98, 0x8e,
12989 0xfe, 0xb6, 0x0e, 0x10,
12990 0x6a, 0x22, 0x6b, 0x26, 0x10, 0x97, 0x10, 0x98, 0x01, 0xc2, 0x2e, 0x49,
12991 0x88, 0x20, 0x6e, 0x01,
12992 0xfe, 0x6a, 0x16, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x04, 0x55, 0xfe, 0xa5,
12993 0x55, 0xfe, 0x04, 0xfa,
12994 0x64, 0xfe, 0x05, 0xfa, 0x34, 0xfe, 0x8f, 0x10, 0x03, 0x6c, 0x3b, 0x6d,
12995 0xfe, 0x40, 0x56, 0xfe,
12996 0xe1, 0x56, 0x10, 0x6c, 0x22, 0x6d, 0x71, 0xdb, 0x64, 0xdc, 0x34, 0xfe,
12997 0x44, 0x55, 0xfe, 0xe5,
12998 0x55, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x10,
12999 0x68, 0x22, 0x69, 0x01,
13000 0x0c, 0x06, 0x54, 0xf9, 0x21, 0x6e, 0xfe, 0x1f, 0x40, 0x03, 0x6a, 0x3b,
13001 0x6b, 0xfe, 0x2c, 0x50,
13002 0xfe, 0xae, 0x50, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x44, 0x50, 0xfe, 0xc6,
13003 0x50, 0x03, 0x68, 0x3b,
13004 0x69, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x4b, 0x3b, 0x4c, 0xfe,
13005 0x40, 0x50, 0xfe, 0xc2,
13006 0x50, 0x05, 0x73, 0x2e, 0x07, 0x20, 0x9e, 0x05, 0x72, 0x32, 0x01, 0x08,
13007 0x16, 0x3d, 0x27, 0x25,
13008 0xee, 0x09, 0x07, 0x2b, 0x3d, 0x01, 0x43, 0x09, 0xbb, 0x2b, 0x72, 0x01,
13009 0xa6, 0x23, 0x3f, 0x1b,
13010 0x3d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1e, 0x13, 0x91, 0x4b, 0x7e, 0x4c,
13011 0xfe, 0x0a, 0x55, 0x31,
13012 0xfe, 0x8b, 0x55, 0xd9, 0x4b, 0xda, 0x4c, 0xfe, 0x0c, 0x51, 0xfe, 0x8e,
13013 0x51, 0x05, 0x72, 0x01,
13014 0xfe, 0x8e, 0x1e, 0xca, 0xfe, 0x19, 0x41, 0x05, 0x72, 0x32, 0x01, 0x08,
13015 0x2a, 0x3c, 0x16, 0xc0,
13016 0x27, 0x25, 0xbe, 0x2d, 0x1d, 0xc0, 0x2d, 0x0d, 0x83, 0x2d, 0x7f, 0x1b,
13017 0xfe, 0x66, 0x15, 0x05,
13018 0x3d, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbd, 0x09, 0x1d,
13019 0x2b, 0x3d, 0x01, 0x08,
13020 0x16, 0xc0, 0x27, 0x25, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x50, 0x03,
13021 0xb6, 0x1e, 0x83, 0x01,
13022 0x38, 0x06, 0x24, 0x31, 0xa1, 0xfe, 0xbb, 0x45, 0x2d, 0x00, 0xa4, 0x46,
13023 0x07, 0x90, 0x3f, 0x01,
13024 0xfe, 0xf8, 0x15, 0x01, 0xa6, 0x86, 0xfe, 0x4b, 0x45, 0xfe, 0x20, 0x13,
13025 0x01, 0x43, 0x09, 0x82,
13026 0xfe, 0x16, 0x13, 0x03, 0x9a, 0x1e, 0x5d, 0x03, 0x55, 0x1e, 0x31, 0x5e,
13027 0x05, 0x72, 0xfe, 0xc0,
13028 0x5d, 0x01, 0xa7, 0xfe, 0x03, 0x17, 0x03, 0x66, 0x8a, 0x10, 0x66, 0x5e,
13029 0x32, 0x01, 0x08, 0x17,
13030 0x73, 0x01, 0xfe, 0x56, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16,
13031 0x3d, 0x27, 0x25, 0xbd,
13032 0x09, 0x07, 0x2b, 0x3d, 0x01, 0xfe, 0xbe, 0x16, 0xfe, 0x42, 0x58, 0xfe,
13033 0xe8, 0x14, 0x01, 0xa6,
13034 0x86, 0xfe, 0x4a, 0xf4, 0x0d, 0x1b, 0x3d, 0xfe, 0x4a, 0xf4, 0x07, 0xfe,
13035 0x0e, 0x12, 0x01, 0x43,
13036 0x09, 0x82, 0x4e, 0x05, 0x72, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x5e, 0x32,
13037 0x01, 0x08, 0x17, 0x73,
13038 0x01, 0xfe, 0x84, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d,
13039 0x27, 0x25, 0xbd, 0x09,
13040 0x12, 0x2b, 0x3d, 0x01, 0xfe, 0xe8, 0x17, 0x8b, 0xfe, 0xaa, 0x14, 0xfe,
13041 0xb6, 0x14, 0x86, 0xa8,
13042 0xb2, 0x0d, 0x1b, 0x3d, 0xb2, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09,
13043 0x82, 0x4e, 0x05, 0x72,
13044 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01,
13045 0xfe, 0xc0, 0x19, 0x05,
13046 0x73, 0x13, 0x07, 0x2f, 0xfe, 0xcc, 0x15, 0x17, 0xfe, 0xe2, 0x15, 0x5f,
13047 0xcc, 0x01, 0x08, 0x26,
13048 0x5f, 0x02, 0x8f, 0xfe, 0xde, 0x15, 0x2a, 0xfe, 0xde, 0x15, 0x16, 0xfe,
13049 0xcc, 0x15, 0x5e, 0x32,
13050 0x01, 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
13051 0xad, 0x23, 0xfe, 0xff,
13052 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02,
13053 0x00, 0x57, 0x52, 0xad,
13054 0x23, 0x3f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff,
13055 0x02, 0x00, 0x57, 0x52,
13056 0xad, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xfe, 0x00, 0x5e,
13057 0x02, 0x13, 0x58, 0xff,
13058 0x02, 0x00, 0x57, 0x52, 0xad, 0xfe, 0x0b, 0x58, 0x02, 0x0a, 0x66, 0x01,
13059 0x5c, 0x0a, 0x55, 0x01,
13060 0x5c, 0x0a, 0x6f, 0x01, 0x5c, 0x02, 0x01, 0xfe, 0x1e, 0x1f, 0x23, 0x1a,
13061 0xff, 0x03, 0x00, 0x54,
13062 0xfe, 0x00, 0xf4, 0x24, 0x52, 0x0f, 0xfe, 0x00, 0x7c, 0x04, 0xfe, 0x07,
13063 0x7c, 0x3a, 0x0b, 0x0e,
13064 0xfe, 0x00, 0x71, 0xfe, 0xf9, 0x18, 0xfe, 0x7a, 0x19, 0xfe, 0xfb, 0x19,
13065 0xfe, 0x1a, 0xf7, 0x00,
13066 0xfe, 0x1b, 0xf7, 0x00, 0x7a, 0x30, 0x10, 0x68, 0x22, 0x69, 0xd9, 0x6c,
13067 0xda, 0x6d, 0x02, 0xfe,
13068 0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x77,
13069 0x02, 0x01, 0xc6, 0xfe,
13070 0x42, 0x48, 0x4f, 0x50, 0x45, 0x01, 0x08, 0x16, 0xfe, 0xe0, 0x17, 0x27,
13071 0x25, 0xbe, 0x01, 0x08,
13072 0x16, 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59,
13073 0x03, 0x9a, 0x1e, 0xfe,
13074 0xda, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfe, 0xd0, 0x13, 0x26, 0x53, 0x12,
13075 0x48, 0xfe, 0x08, 0x17,
13076 0xd1, 0x12, 0x53, 0x12, 0xfe, 0x1e, 0x13, 0x2d, 0xb4, 0x7b, 0xfe, 0x26,
13077 0x17, 0x4d, 0x13, 0x07,
13078 0x1c, 0xb4, 0x90, 0x04, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xf1,
13079 0xff, 0x02, 0x83, 0x55,
13080 0x53, 0x1d, 0xfe, 0x12, 0x13, 0xd6, 0xfe, 0x30, 0x00, 0xb0, 0xfe, 0x80,
13081 0x17, 0x1c, 0x63, 0x13,
13082 0x07, 0xfe, 0x56, 0x10, 0x53, 0x0d, 0xfe, 0x16, 0x13, 0xd6, 0xfe, 0x64,
13083 0x00, 0xb0, 0xfe, 0x80,
13084 0x17, 0x0a, 0xfe, 0x64, 0x00, 0x1c, 0x94, 0x13, 0x07, 0xfe, 0x28, 0x10,
13085 0x53, 0x07, 0xfe, 0x60,
13086 0x13, 0xd6, 0xfe, 0xc8, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0xc8,
13087 0x00, 0x1c, 0x95, 0x13,
13088 0x07, 0x71, 0xd6, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0x8c, 0x17, 0x45, 0xf3,
13089 0xfe, 0x43, 0xf4, 0x96,
13090 0xfe, 0x56, 0xf0, 0xfe, 0x9e, 0x17, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x43,
13091 0xf4, 0x94, 0xf6, 0x8b,
13092 0x01, 0xfe, 0x24, 0x16, 0x23, 0x3f, 0xfc, 0xa8, 0x8c, 0x49, 0x48, 0xfe,
13093 0xda, 0x17, 0x62, 0x49,
13094 0xfe, 0x1c, 0x10, 0xa8, 0x8c, 0x80, 0x48, 0xfe, 0xda, 0x17, 0x62, 0x80,
13095 0x71, 0x50, 0x26, 0xfe,
13096 0x4d, 0xf4, 0x00, 0xf7, 0x45, 0x13, 0x07, 0xfe, 0xb4, 0x56, 0xfe, 0xc3,
13097 0x58, 0x02, 0x50, 0x13,
13098 0x0d, 0x02, 0x50, 0x3e, 0x78, 0x4f, 0x45, 0x01, 0x08, 0x16, 0xa9, 0x27,
13099 0x25, 0xbe, 0xfe, 0x03,
13100 0xea, 0xfe, 0x7e, 0x01, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, 0xe9,
13101 0x0a, 0x01, 0x08, 0x16,
13102 0xa9, 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0xfe, 0x05, 0xea, 0xfe, 0x7f, 0x01,
13103 0x01, 0x08, 0x16, 0xa9,
13104 0x27, 0x25, 0xfe, 0x69, 0x09, 0xfe, 0x02, 0xea, 0xfe, 0x80, 0x01, 0x01,
13105 0x08, 0x16, 0xa9, 0x27,
13106 0x25, 0xfe, 0xe8, 0x08, 0x47, 0xfe, 0x81, 0x01, 0x03, 0xb6, 0x1e, 0x83,
13107 0x01, 0x38, 0x06, 0x24,
13108 0x31, 0xa2, 0x78, 0xf2, 0x53, 0x07, 0x36, 0xfe, 0x34, 0xf4, 0x3f, 0xa1,
13109 0x78, 0x03, 0x9a, 0x1e,
13110 0x83, 0x01, 0x38, 0x06, 0x12, 0x31, 0xf0, 0x4f, 0x45, 0xfe, 0x90, 0x10,
13111 0xfe, 0x40, 0x5a, 0x23,
13112 0x3f, 0xfb, 0x8c, 0x49, 0x48, 0xfe, 0xaa, 0x18, 0x62, 0x49, 0x71, 0x8c,
13113 0x80, 0x48, 0xfe, 0xaa,
13114 0x18, 0x62, 0x80, 0xfe, 0xb4, 0x56, 0xfe, 0x40, 0x5d, 0x01, 0xc6, 0x01,
13115 0xfe, 0xac, 0x1d, 0xfe,
13116 0x02, 0x17, 0xfe, 0xc8, 0x45, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0, 0x18, 0xfe,
13117 0x43, 0x48, 0x2d, 0x93,
13118 0x36, 0xfe, 0x34, 0xf4, 0xfe, 0x00, 0x11, 0xfe, 0x40, 0x10, 0x2d, 0xb4,
13119 0x36, 0xfe, 0x34, 0xf4,
13120 0x04, 0xfe, 0x34, 0x10, 0x2d, 0xfe, 0x0b, 0x00, 0x36, 0x46, 0x63, 0xfe,
13121 0x28, 0x10, 0xfe, 0xc0,
13122 0x49, 0xff, 0x02, 0x00, 0x54, 0xb2, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0xfa,
13123 0x18, 0x45, 0xfe, 0x1c,
13124 0xf4, 0x3f, 0xf3, 0xfe, 0x40, 0xf4, 0x96, 0xfe, 0x56, 0xf0, 0xfe, 0x0c,
13125 0x19, 0xfe, 0x04, 0xf4,
13126 0x58, 0xfe, 0x40, 0xf4, 0x94, 0xf6, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d,
13127 0x21, 0xfe, 0x7f, 0x01,
13128 0xfe, 0xc8, 0x46, 0xfe, 0x24, 0x13, 0x8c, 0x00, 0x5d, 0x26, 0x21, 0xfe,
13129 0x7e, 0x01, 0xfe, 0xc8,
13130 0x45, 0xfe, 0x14, 0x13, 0x21, 0xfe, 0x80, 0x01, 0xfe, 0x48, 0x45, 0xfa,
13131 0x21, 0xfe, 0x81, 0x01,
13132 0xfe, 0xc8, 0x44, 0x4e, 0x26, 0x02, 0x13, 0x07, 0x02, 0x78, 0x45, 0x50,
13133 0x13, 0x0d, 0x02, 0x14,
13134 0x07, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, 0x0d, 0x01, 0x08, 0x17,
13135 0xfe, 0x82, 0x19, 0x14,
13136 0x1d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x5f, 0xfe, 0x89, 0x49, 0x01,
13137 0x08, 0x02, 0x14, 0x07,
13138 0x01, 0x08, 0x17, 0xc1, 0x14, 0x1d, 0x01, 0x08, 0x17, 0xc1, 0x14, 0x07,
13139 0x01, 0x08, 0x17, 0xc1,
13140 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0xc1, 0x5f, 0xfe, 0x89, 0x4a, 0x01,
13141 0x08, 0x02, 0x50, 0x02,
13142 0x14, 0x07, 0x01, 0x08, 0x17, 0x74, 0x14, 0x7f, 0x01, 0x08, 0x17, 0x74,
13143 0x14, 0x12, 0x01, 0x08,
13144 0x17, 0x74, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0x74, 0x14, 0x00, 0x01,
13145 0x08, 0x17, 0x74, 0xfe,
13146 0x89, 0x4a, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x09, 0x49, 0x01, 0x08, 0x17,
13147 0x74, 0x5f, 0xcc, 0x01,
13148 0x08, 0x02, 0x21, 0xe4, 0x09, 0x07, 0xfe, 0x4c, 0x13, 0xc8, 0x20, 0xe4,
13149 0xfe, 0x49, 0xf4, 0x00,
13150 0x4d, 0x5f, 0xa1, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xcc, 0xff,
13151 0x02, 0x00, 0x10, 0x2f,
13152 0xfe, 0x3e, 0x1a, 0x01, 0x43, 0x09, 0xfe, 0xe3, 0x00, 0xfe, 0x22, 0x13,
13153 0x16, 0xfe, 0x64, 0x1a,
13154 0x26, 0x20, 0x9e, 0x01, 0x41, 0x21, 0x9e, 0x09, 0x07, 0x5d, 0x01, 0x0c,
13155 0x61, 0x07, 0x44, 0x02,
13156 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x00, 0x40, 0xaa, 0x09, 0x1a, 0xfe, 0x12,
13157 0x13, 0x0a, 0x9d, 0x01,
13158 0x18, 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x9d, 0x01, 0x18, 0xaa,
13159 0xfe, 0x80, 0xe7, 0x1a,
13160 0x09, 0x1a, 0x5d, 0xfe, 0x45, 0x58, 0x01, 0xfe, 0xb2, 0x16, 0xaa, 0x02,
13161 0x0a, 0x5a, 0x01, 0x18,
13162 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x01, 0xfe,
13163 0x7e, 0x1e, 0xfe, 0x80,
13164 0x4c, 0xfe, 0x49, 0xe4, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, 0x18,
13165 0xfe, 0x80, 0x4c, 0x0a,
13166 0x67, 0x01, 0x5c, 0x02, 0x1c, 0x1a, 0x87, 0x7c, 0xe5, 0xfe, 0x18, 0xdf,
13167 0xfe, 0x19, 0xde, 0xfe,
13168 0x24, 0x1c, 0xfe, 0x1d, 0xf7, 0x28, 0xb1, 0xfe, 0x04, 0x1b, 0x01, 0xfe,
13169 0x2a, 0x1c, 0xfa, 0xb3,
13170 0x28, 0x7c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x02, 0xc9, 0x2b, 0xfe,
13171 0xf4, 0x1a, 0xfe, 0xfa,
13172 0x10, 0x1c, 0x1a, 0x87, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x24,
13173 0xfe, 0x18, 0x58, 0x03,
13174 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0xb3, 0x24, 0x01, 0xfe, 0x0e, 0x1f,
13175 0xfe, 0x30, 0xf4, 0x07,
13176 0xfe, 0x3c, 0x50, 0x7c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c,
13177 0xf7, 0x24, 0xb1, 0xfe,
13178 0x50, 0x1b, 0xfe, 0xd4, 0x14, 0x31, 0x02, 0xc9, 0x2b, 0xfe, 0x26, 0x1b,
13179 0xfe, 0xba, 0x10, 0x1c,
13180 0x1a, 0x87, 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe,
13181 0x1d, 0xf7, 0x54, 0xb1,
13182 0xfe, 0x72, 0x1b, 0xfe, 0xb2, 0x14, 0xfc, 0xb3, 0x54, 0x7c, 0x12, 0xfe,
13183 0xaf, 0x19, 0xfe, 0x98,
13184 0xe7, 0x00, 0x02, 0xc9, 0x2b, 0xfe, 0x66, 0x1b, 0xfe, 0x8a, 0x10, 0x1c,
13185 0x1a, 0x87, 0x8b, 0x0f,
13186 0xfe, 0x30, 0x90, 0x04, 0xfe, 0xb0, 0x93, 0x3a, 0x0b, 0xfe, 0x18, 0x58,
13187 0xfe, 0x32, 0x90, 0x04,
13188 0xfe, 0xb2, 0x93, 0x3a, 0x0b, 0xfe, 0x19, 0x58, 0x0e, 0xa8, 0xb3, 0x4a,
13189 0x7c, 0x12, 0xfe, 0x0f,
13190 0x79, 0xfe, 0x1c, 0xf7, 0x4a, 0xb1, 0xfe, 0xc6, 0x1b, 0xfe, 0x5e, 0x14,
13191 0x31, 0x02, 0xc9, 0x2b,
13192 0xfe, 0x96, 0x1b, 0x5c, 0xfe, 0x02, 0xf6, 0x1a, 0x87, 0xfe, 0x18, 0xfe,
13193 0x6a, 0xfe, 0x19, 0xfe,
13194 0x6b, 0x01, 0xfe, 0x1e, 0x1f, 0xfe, 0x1d, 0xf7, 0x65, 0xb1, 0xfe, 0xee,
13195 0x1b, 0xfe, 0x36, 0x14,
13196 0xfe, 0x1c, 0x13, 0xb3, 0x65, 0x3e, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19,
13197 0xfe, 0x80, 0xe7, 0x1a,
13198 0xfe, 0x81, 0xe7, 0x1a, 0x15, 0xfe, 0xdd, 0x00, 0x7a, 0x30, 0x02, 0x7a,
13199 0x30, 0xfe, 0x12, 0x45,
13200 0x2b, 0xfe, 0xdc, 0x1b, 0x1f, 0x07, 0x47, 0xb5, 0xc3, 0x05, 0x35, 0xfe,
13201 0x39, 0xf0, 0x75, 0x26,
13202 0x02, 0xfe, 0x7e, 0x18, 0x23, 0x1d, 0x36, 0x13, 0x11, 0x02, 0x87, 0x03,
13203 0xe3, 0x23, 0x07, 0xfe,
13204 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x90, 0x34, 0x60, 0xfe, 0x02, 0x80, 0x09,
13205 0x56, 0xfe, 0x3c, 0x13,
13206 0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x51, 0xfe, 0x06, 0x83, 0x0a, 0x5a,
13207 0x01, 0x18, 0xcb, 0xfe,
13208 0x3e, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xfe, 0xb2, 0x16,
13209 0xfe, 0x00, 0xcc, 0xcb,
13210 0xfe, 0xf3, 0x13, 0x3f, 0x89, 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18,
13211 0xfe, 0x80, 0x4c, 0x01,
13212 0x85, 0xfe, 0x16, 0x10, 0x09, 0x9b, 0x4e, 0xfe, 0x40, 0x14, 0xfe, 0x24,
13213 0x12, 0xfe, 0x14, 0x56,
13214 0xfe, 0xd6, 0xf0, 0xfe, 0x52, 0x1c, 0x1c, 0x0d, 0x02, 0xfe, 0x9c, 0xe7,
13215 0x0d, 0x19, 0xfe, 0x15,
13216 0x00, 0x40, 0x8d, 0x30, 0x01, 0xf4, 0x1c, 0x07, 0x02, 0x51, 0xfe, 0x06,
13217 0x83, 0xfe, 0x18, 0x80,
13218 0x61, 0x28, 0x44, 0x15, 0x56, 0x01, 0x85, 0x1c, 0x07, 0x02, 0xfe, 0x38,
13219 0x90, 0xfe, 0xba, 0x90,
13220 0x91, 0xde, 0x7e, 0xdf, 0xfe, 0x48, 0x55, 0x31, 0xfe, 0xc9, 0x55, 0x02,
13221 0x21, 0xb9, 0x88, 0x20,
13222 0xb9, 0x02, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0x41, 0x48, 0x0a, 0x57, 0x01,
13223 0x18, 0xfe, 0x49, 0x44,
13224 0x1b, 0xfe, 0x1e, 0x1d, 0x88, 0x89, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x09,
13225 0x1a, 0xa4, 0x0a, 0x67,
13226 0x01, 0xa3, 0x0a, 0x57, 0x01, 0x18, 0x88, 0x89, 0x02, 0xfe, 0x4e, 0xe4,
13227 0x1d, 0x7b, 0xfe, 0x52,
13228 0x1d, 0x03, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe,
13229 0x4e, 0xe4, 0xdd, 0x7b,
13230 0xfe, 0x64, 0x1d, 0x03, 0xfe, 0x92, 0x00, 0xd1, 0x12, 0xfe, 0x1a, 0x10,
13231 0xfe, 0x4e, 0xe4, 0xfe,
13232 0x0b, 0x00, 0x7b, 0xfe, 0x76, 0x1d, 0x03, 0xfe, 0x94, 0x00, 0xd1, 0x24,
13233 0xfe, 0x08, 0x10, 0x03,
13234 0xfe, 0x96, 0x00, 0xd1, 0x63, 0xfe, 0x4e, 0x45, 0x83, 0xca, 0xff, 0x04,
13235 0x68, 0x54, 0xfe, 0xf1,
13236 0x10, 0x23, 0x49, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c,
13237 0xfe, 0x1a, 0xf4, 0xfe,
13238 0x00, 0x04, 0x83, 0xb2, 0x1d, 0x48, 0xfe, 0xaa, 0x1d, 0x13, 0x1d, 0x02,
13239 0x09, 0x92, 0xfe, 0x5a,
13240 0xf0, 0xfe, 0xba, 0x1d, 0x2e, 0x93, 0xfe, 0x34, 0x10, 0x09, 0x12, 0xfe,
13241 0x5a, 0xf0, 0xfe, 0xc8,
13242 0x1d, 0x2e, 0xb4, 0xfe, 0x26, 0x10, 0x09, 0x1d, 0x36, 0x2e, 0x63, 0xfe,
13243 0x1a, 0x10, 0x09, 0x0d,
13244 0x36, 0x2e, 0x94, 0xf2, 0x09, 0x07, 0x36, 0x2e, 0x95, 0xa1, 0xc8, 0x02,
13245 0x1f, 0x93, 0x01, 0x42,
13246 0xfe, 0x04, 0xfe, 0x99, 0x03, 0x9c, 0x8b, 0x02, 0x2a, 0xfe, 0x1c, 0x1e,
13247 0xfe, 0x14, 0xf0, 0x08,
13248 0x2f, 0xfe, 0x0c, 0x1e, 0x2a, 0xfe, 0x1c, 0x1e, 0x8f, 0xfe, 0x1c, 0x1e,
13249 0xfe, 0x82, 0xf0, 0xfe,
13250 0x10, 0x1e, 0x02, 0x0f, 0x3f, 0x04, 0xfe, 0x80, 0x83, 0x33, 0x0b, 0x0e,
13251 0x02, 0x0f, 0xfe, 0x18,
13252 0x80, 0x04, 0xfe, 0x98, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x02,
13253 0x80, 0x04, 0xfe, 0x82,
13254 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x80, 0x04, 0xfe, 0x86,
13255 0x83, 0x33, 0x0b, 0x0e,
13256 0x02, 0x0f, 0xfe, 0x1b, 0x80, 0x04, 0xfe, 0x9b, 0x83, 0x33, 0x0b, 0x0e,
13257 0x02, 0x0f, 0xfe, 0x04,
13258 0x80, 0x04, 0xfe, 0x84, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x80,
13259 0x80, 0x04, 0xfe, 0x80,
13260 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x19, 0x81, 0x04,
13261 0xfe, 0x99, 0x83, 0xfe,
13262 0xca, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x83, 0x04, 0xfe, 0x86,
13263 0x83, 0xfe, 0xce, 0x47,
13264 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x2c, 0x90, 0x04, 0xfe, 0xac, 0x93, 0x3a,
13265 0x0b, 0x0e, 0x02, 0x0f,
13266 0xfe, 0xae, 0x90, 0x04, 0xfe, 0xae, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
13267 0xfe, 0x08, 0x90, 0x04,
13268 0xfe, 0x88, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x8a, 0x90, 0x04,
13269 0xfe, 0x8a, 0x93, 0x79,
13270 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x0c, 0x90, 0x04, 0xfe, 0x8c, 0x93, 0x3a,
13271 0x0b, 0x0e, 0x02, 0x0f,
13272 0xfe, 0x8e, 0x90, 0x04, 0xfe, 0x8e, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
13273 0xfe, 0x3c, 0x90, 0x04,
13274 0xfe, 0xbc, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x8b, 0x0f, 0xfe, 0x03, 0x80,
13275 0x04, 0xfe, 0x83, 0x83,
13276 0x33, 0x0b, 0x77, 0x0e, 0xa8, 0x02, 0xff, 0x66, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070013277};
13278
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013279static unsigned short _adv_asc38C1600_size = sizeof(_adv_asc38C1600_buf); /* 0x1673 */
13280static ADV_DCNT _adv_asc38C1600_chksum = 0x0604EF77UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013281
13282/* a_init.c */
13283/*
13284 * EEPROM Configuration.
13285 *
13286 * All drivers should use this structure to set the default EEPROM
13287 * configuration. The BIOS now uses this structure when it is built.
13288 * Additional structure information can be found in a_condor.h where
13289 * the structure is defined.
13290 *
13291 * The *_Field_IsChar structs are needed to correct for endianness.
13292 * These values are read from the board 16 bits at a time directly
13293 * into the structs. Because some fields are char, the values will be
13294 * in the wrong order. The *_Field_IsChar tells when to flip the
13295 * bytes. Data read and written to PCI memory is automatically swapped
13296 * on big-endian platforms so char fields read as words are actually being
13297 * unswapped on big-endian platforms.
13298 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013299static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013300 ADV_EEPROM_BIOS_ENABLE, /* cfg_lsw */
13301 0x0000, /* cfg_msw */
13302 0xFFFF, /* disc_enable */
13303 0xFFFF, /* wdtr_able */
13304 0xFFFF, /* sdtr_able */
13305 0xFFFF, /* start_motor */
13306 0xFFFF, /* tagqng_able */
13307 0xFFFF, /* bios_scan */
13308 0, /* scam_tolerant */
13309 7, /* adapter_scsi_id */
13310 0, /* bios_boot_delay */
13311 3, /* scsi_reset_delay */
13312 0, /* bios_id_lun */
13313 0, /* termination */
13314 0, /* reserved1 */
13315 0xFFE7, /* bios_ctrl */
13316 0xFFFF, /* ultra_able */
13317 0, /* reserved2 */
13318 ASC_DEF_MAX_HOST_QNG, /* max_host_qng */
13319 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13320 0, /* dvc_cntl */
13321 0, /* bug_fix */
13322 0, /* serial_number_word1 */
13323 0, /* serial_number_word2 */
13324 0, /* serial_number_word3 */
13325 0, /* check_sum */
13326 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13327 , /* oem_name[16] */
13328 0, /* dvc_err_code */
13329 0, /* adv_err_code */
13330 0, /* adv_err_addr */
13331 0, /* saved_dvc_err_code */
13332 0, /* saved_adv_err_code */
13333 0, /* saved_adv_err_addr */
13334 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013335};
13336
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013337static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013338 0, /* cfg_lsw */
13339 0, /* cfg_msw */
13340 0, /* -disc_enable */
13341 0, /* wdtr_able */
13342 0, /* sdtr_able */
13343 0, /* start_motor */
13344 0, /* tagqng_able */
13345 0, /* bios_scan */
13346 0, /* scam_tolerant */
13347 1, /* adapter_scsi_id */
13348 1, /* bios_boot_delay */
13349 1, /* scsi_reset_delay */
13350 1, /* bios_id_lun */
13351 1, /* termination */
13352 1, /* reserved1 */
13353 0, /* bios_ctrl */
13354 0, /* ultra_able */
13355 0, /* reserved2 */
13356 1, /* max_host_qng */
13357 1, /* max_dvc_qng */
13358 0, /* dvc_cntl */
13359 0, /* bug_fix */
13360 0, /* serial_number_word1 */
13361 0, /* serial_number_word2 */
13362 0, /* serial_number_word3 */
13363 0, /* check_sum */
13364 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
13365 , /* oem_name[16] */
13366 0, /* dvc_err_code */
13367 0, /* adv_err_code */
13368 0, /* adv_err_addr */
13369 0, /* saved_dvc_err_code */
13370 0, /* saved_adv_err_code */
13371 0, /* saved_adv_err_addr */
13372 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013373};
13374
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013375static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013376 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
13377 0x0000, /* 01 cfg_msw */
13378 0xFFFF, /* 02 disc_enable */
13379 0xFFFF, /* 03 wdtr_able */
13380 0x4444, /* 04 sdtr_speed1 */
13381 0xFFFF, /* 05 start_motor */
13382 0xFFFF, /* 06 tagqng_able */
13383 0xFFFF, /* 07 bios_scan */
13384 0, /* 08 scam_tolerant */
13385 7, /* 09 adapter_scsi_id */
13386 0, /* bios_boot_delay */
13387 3, /* 10 scsi_reset_delay */
13388 0, /* bios_id_lun */
13389 0, /* 11 termination_se */
13390 0, /* termination_lvd */
13391 0xFFE7, /* 12 bios_ctrl */
13392 0x4444, /* 13 sdtr_speed2 */
13393 0x4444, /* 14 sdtr_speed3 */
13394 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
13395 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13396 0, /* 16 dvc_cntl */
13397 0x4444, /* 17 sdtr_speed4 */
13398 0, /* 18 serial_number_word1 */
13399 0, /* 19 serial_number_word2 */
13400 0, /* 20 serial_number_word3 */
13401 0, /* 21 check_sum */
13402 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13403 , /* 22-29 oem_name[16] */
13404 0, /* 30 dvc_err_code */
13405 0, /* 31 adv_err_code */
13406 0, /* 32 adv_err_addr */
13407 0, /* 33 saved_dvc_err_code */
13408 0, /* 34 saved_adv_err_code */
13409 0, /* 35 saved_adv_err_addr */
13410 0, /* 36 reserved */
13411 0, /* 37 reserved */
13412 0, /* 38 reserved */
13413 0, /* 39 reserved */
13414 0, /* 40 reserved */
13415 0, /* 41 reserved */
13416 0, /* 42 reserved */
13417 0, /* 43 reserved */
13418 0, /* 44 reserved */
13419 0, /* 45 reserved */
13420 0, /* 46 reserved */
13421 0, /* 47 reserved */
13422 0, /* 48 reserved */
13423 0, /* 49 reserved */
13424 0, /* 50 reserved */
13425 0, /* 51 reserved */
13426 0, /* 52 reserved */
13427 0, /* 53 reserved */
13428 0, /* 54 reserved */
13429 0, /* 55 reserved */
13430 0, /* 56 cisptr_lsw */
13431 0, /* 57 cisprt_msw */
13432 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
13433 PCI_DEVICE_ID_38C0800_REV1, /* 59 subsysid */
13434 0, /* 60 reserved */
13435 0, /* 61 reserved */
13436 0, /* 62 reserved */
13437 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013438};
13439
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013440static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013441 0, /* 00 cfg_lsw */
13442 0, /* 01 cfg_msw */
13443 0, /* 02 disc_enable */
13444 0, /* 03 wdtr_able */
13445 0, /* 04 sdtr_speed1 */
13446 0, /* 05 start_motor */
13447 0, /* 06 tagqng_able */
13448 0, /* 07 bios_scan */
13449 0, /* 08 scam_tolerant */
13450 1, /* 09 adapter_scsi_id */
13451 1, /* bios_boot_delay */
13452 1, /* 10 scsi_reset_delay */
13453 1, /* bios_id_lun */
13454 1, /* 11 termination_se */
13455 1, /* termination_lvd */
13456 0, /* 12 bios_ctrl */
13457 0, /* 13 sdtr_speed2 */
13458 0, /* 14 sdtr_speed3 */
13459 1, /* 15 max_host_qng */
13460 1, /* max_dvc_qng */
13461 0, /* 16 dvc_cntl */
13462 0, /* 17 sdtr_speed4 */
13463 0, /* 18 serial_number_word1 */
13464 0, /* 19 serial_number_word2 */
13465 0, /* 20 serial_number_word3 */
13466 0, /* 21 check_sum */
13467 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
13468 , /* 22-29 oem_name[16] */
13469 0, /* 30 dvc_err_code */
13470 0, /* 31 adv_err_code */
13471 0, /* 32 adv_err_addr */
13472 0, /* 33 saved_dvc_err_code */
13473 0, /* 34 saved_adv_err_code */
13474 0, /* 35 saved_adv_err_addr */
13475 0, /* 36 reserved */
13476 0, /* 37 reserved */
13477 0, /* 38 reserved */
13478 0, /* 39 reserved */
13479 0, /* 40 reserved */
13480 0, /* 41 reserved */
13481 0, /* 42 reserved */
13482 0, /* 43 reserved */
13483 0, /* 44 reserved */
13484 0, /* 45 reserved */
13485 0, /* 46 reserved */
13486 0, /* 47 reserved */
13487 0, /* 48 reserved */
13488 0, /* 49 reserved */
13489 0, /* 50 reserved */
13490 0, /* 51 reserved */
13491 0, /* 52 reserved */
13492 0, /* 53 reserved */
13493 0, /* 54 reserved */
13494 0, /* 55 reserved */
13495 0, /* 56 cisptr_lsw */
13496 0, /* 57 cisprt_msw */
13497 0, /* 58 subsysvid */
13498 0, /* 59 subsysid */
13499 0, /* 60 reserved */
13500 0, /* 61 reserved */
13501 0, /* 62 reserved */
13502 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013503};
13504
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013505static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013506 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
13507 0x0000, /* 01 cfg_msw */
13508 0xFFFF, /* 02 disc_enable */
13509 0xFFFF, /* 03 wdtr_able */
13510 0x5555, /* 04 sdtr_speed1 */
13511 0xFFFF, /* 05 start_motor */
13512 0xFFFF, /* 06 tagqng_able */
13513 0xFFFF, /* 07 bios_scan */
13514 0, /* 08 scam_tolerant */
13515 7, /* 09 adapter_scsi_id */
13516 0, /* bios_boot_delay */
13517 3, /* 10 scsi_reset_delay */
13518 0, /* bios_id_lun */
13519 0, /* 11 termination_se */
13520 0, /* termination_lvd */
13521 0xFFE7, /* 12 bios_ctrl */
13522 0x5555, /* 13 sdtr_speed2 */
13523 0x5555, /* 14 sdtr_speed3 */
13524 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
13525 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13526 0, /* 16 dvc_cntl */
13527 0x5555, /* 17 sdtr_speed4 */
13528 0, /* 18 serial_number_word1 */
13529 0, /* 19 serial_number_word2 */
13530 0, /* 20 serial_number_word3 */
13531 0, /* 21 check_sum */
13532 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13533 , /* 22-29 oem_name[16] */
13534 0, /* 30 dvc_err_code */
13535 0, /* 31 adv_err_code */
13536 0, /* 32 adv_err_addr */
13537 0, /* 33 saved_dvc_err_code */
13538 0, /* 34 saved_adv_err_code */
13539 0, /* 35 saved_adv_err_addr */
13540 0, /* 36 reserved */
13541 0, /* 37 reserved */
13542 0, /* 38 reserved */
13543 0, /* 39 reserved */
13544 0, /* 40 reserved */
13545 0, /* 41 reserved */
13546 0, /* 42 reserved */
13547 0, /* 43 reserved */
13548 0, /* 44 reserved */
13549 0, /* 45 reserved */
13550 0, /* 46 reserved */
13551 0, /* 47 reserved */
13552 0, /* 48 reserved */
13553 0, /* 49 reserved */
13554 0, /* 50 reserved */
13555 0, /* 51 reserved */
13556 0, /* 52 reserved */
13557 0, /* 53 reserved */
13558 0, /* 54 reserved */
13559 0, /* 55 reserved */
13560 0, /* 56 cisptr_lsw */
13561 0, /* 57 cisprt_msw */
13562 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
13563 PCI_DEVICE_ID_38C1600_REV1, /* 59 subsysid */
13564 0, /* 60 reserved */
13565 0, /* 61 reserved */
13566 0, /* 62 reserved */
13567 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013568};
13569
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013570static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013571 0, /* 00 cfg_lsw */
13572 0, /* 01 cfg_msw */
13573 0, /* 02 disc_enable */
13574 0, /* 03 wdtr_able */
13575 0, /* 04 sdtr_speed1 */
13576 0, /* 05 start_motor */
13577 0, /* 06 tagqng_able */
13578 0, /* 07 bios_scan */
13579 0, /* 08 scam_tolerant */
13580 1, /* 09 adapter_scsi_id */
13581 1, /* bios_boot_delay */
13582 1, /* 10 scsi_reset_delay */
13583 1, /* bios_id_lun */
13584 1, /* 11 termination_se */
13585 1, /* termination_lvd */
13586 0, /* 12 bios_ctrl */
13587 0, /* 13 sdtr_speed2 */
13588 0, /* 14 sdtr_speed3 */
13589 1, /* 15 max_host_qng */
13590 1, /* max_dvc_qng */
13591 0, /* 16 dvc_cntl */
13592 0, /* 17 sdtr_speed4 */
13593 0, /* 18 serial_number_word1 */
13594 0, /* 19 serial_number_word2 */
13595 0, /* 20 serial_number_word3 */
13596 0, /* 21 check_sum */
13597 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
13598 , /* 22-29 oem_name[16] */
13599 0, /* 30 dvc_err_code */
13600 0, /* 31 adv_err_code */
13601 0, /* 32 adv_err_addr */
13602 0, /* 33 saved_dvc_err_code */
13603 0, /* 34 saved_adv_err_code */
13604 0, /* 35 saved_adv_err_addr */
13605 0, /* 36 reserved */
13606 0, /* 37 reserved */
13607 0, /* 38 reserved */
13608 0, /* 39 reserved */
13609 0, /* 40 reserved */
13610 0, /* 41 reserved */
13611 0, /* 42 reserved */
13612 0, /* 43 reserved */
13613 0, /* 44 reserved */
13614 0, /* 45 reserved */
13615 0, /* 46 reserved */
13616 0, /* 47 reserved */
13617 0, /* 48 reserved */
13618 0, /* 49 reserved */
13619 0, /* 50 reserved */
13620 0, /* 51 reserved */
13621 0, /* 52 reserved */
13622 0, /* 53 reserved */
13623 0, /* 54 reserved */
13624 0, /* 55 reserved */
13625 0, /* 56 cisptr_lsw */
13626 0, /* 57 cisprt_msw */
13627 0, /* 58 subsysvid */
13628 0, /* 59 subsysid */
13629 0, /* 60 reserved */
13630 0, /* 61 reserved */
13631 0, /* 62 reserved */
13632 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013633};
13634
13635/*
13636 * Initialize the ADV_DVC_VAR structure.
13637 *
13638 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
13639 *
13640 * For a non-fatal error return a warning code. If there are no warnings
13641 * then 0 is returned.
13642 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013643static int __devinit AdvInitGetConfig(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013644{
Matthew Wilcox9649af32007-07-26 21:51:47 -060013645 unsigned short warn_code = 0;
13646 AdvPortAddr iop_base = asc_dvc->iop_base;
13647 struct pci_dev *pdev = to_pci_dev(asc_dvc->cfg->dev);
13648 u16 cmd;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013649 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013650
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013651 asc_dvc->err_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013652
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013653 /*
13654 * Save the state of the PCI Configuration Command Register
13655 * "Parity Error Response Control" Bit. If the bit is clear (0),
13656 * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore
13657 * DMA parity errors.
13658 */
13659 asc_dvc->cfg->control_flag = 0;
Matthew Wilcox9649af32007-07-26 21:51:47 -060013660 pci_read_config_word(pdev, PCI_COMMAND, &cmd);
13661 if ((cmd & PCI_COMMAND_PARITY) == 0)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013662 asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013663
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013664 asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) |
13665 ADV_LIB_VERSION_MINOR;
13666 asc_dvc->cfg->chip_version =
13667 AdvGetChipVersion(iop_base, asc_dvc->bus_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013668
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013669 ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: 0x%x 0x%x\n",
13670 (ushort)AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
13671 (ushort)ADV_CHIP_ID_BYTE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013672
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013673 ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: 0x%x 0x%x\n",
13674 (ushort)AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
13675 (ushort)ADV_CHIP_ID_WORD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013676
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013677 /*
13678 * Reset the chip to start and allow register writes.
13679 */
13680 if (AdvFindSignature(iop_base) == 0) {
13681 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
13682 return ADV_ERROR;
13683 } else {
13684 /*
13685 * The caller must set 'chip_type' to a valid setting.
13686 */
13687 if (asc_dvc->chip_type != ADV_CHIP_ASC3550 &&
13688 asc_dvc->chip_type != ADV_CHIP_ASC38C0800 &&
13689 asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
13690 asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
13691 return ADV_ERROR;
13692 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013693
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013694 /*
13695 * Reset Chip.
13696 */
13697 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
13698 ADV_CTRL_REG_CMD_RESET);
13699 DvcSleepMilliSecond(100);
13700 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
13701 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013702
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013703 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
Matthew Wilcox9649af32007-07-26 21:51:47 -060013704 status = AdvInitFrom38C1600EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013705 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
Matthew Wilcox9649af32007-07-26 21:51:47 -060013706 status = AdvInitFrom38C0800EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013707 } else {
Matthew Wilcox9649af32007-07-26 21:51:47 -060013708 status = AdvInitFrom3550EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013709 }
13710 warn_code |= status;
13711 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013712
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013713 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013714}
13715
13716/*
13717 * Initialize the ASC-3550.
13718 *
13719 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
13720 *
13721 * For a non-fatal error return a warning code. If there are no warnings
13722 * then 0 is returned.
13723 *
13724 * Needed after initialization for error recovery.
13725 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013726static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013727{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013728 AdvPortAddr iop_base;
13729 ushort warn_code;
13730 ADV_DCNT sum;
13731 int begin_addr;
13732 int end_addr;
13733 ushort code_sum;
13734 int word;
13735 int j;
13736 int adv_asc3550_expanded_size;
13737 ADV_CARR_T *carrp;
13738 ADV_DCNT contig_len;
13739 ADV_SDCNT buf_size;
13740 ADV_PADDR carr_paddr;
13741 int i;
13742 ushort scsi_cfg1;
13743 uchar tid;
13744 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
13745 ushort wdtr_able = 0, sdtr_able, tagqng_able;
13746 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070013747
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013748 /* If there is already an error, don't continue. */
13749 if (asc_dvc->err_code != 0) {
13750 return ADV_ERROR;
13751 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013752
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013753 /*
13754 * The caller must set 'chip_type' to ADV_CHIP_ASC3550.
13755 */
13756 if (asc_dvc->chip_type != ADV_CHIP_ASC3550) {
13757 asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
13758 return ADV_ERROR;
13759 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013760
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013761 warn_code = 0;
13762 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013763
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013764 /*
13765 * Save the RISC memory BIOS region before writing the microcode.
13766 * The BIOS may already be loaded and using its RISC LRAM region
13767 * so its region must be saved and restored.
13768 *
13769 * Note: This code makes the assumption, which is currently true,
13770 * that a chip reset does not clear RISC LRAM.
13771 */
13772 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
13773 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
13774 bios_mem[i]);
13775 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013776
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013777 /*
13778 * Save current per TID negotiated values.
13779 */
13780 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == 0x55AA) {
13781 ushort bios_version, major, minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013782
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013783 bios_version =
13784 bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM) / 2];
13785 major = (bios_version >> 12) & 0xF;
13786 minor = (bios_version >> 8) & 0xF;
13787 if (major < 3 || (major == 3 && minor == 1)) {
13788 /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
13789 AdvReadWordLram(iop_base, 0x120, wdtr_able);
13790 } else {
13791 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
13792 }
13793 }
13794 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
13795 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
13796 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
13797 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
13798 max_cmd[tid]);
13799 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013800
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013801 /*
13802 * Load the Microcode
13803 *
13804 * Write the microcode image to RISC memory starting at address 0.
13805 */
13806 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
13807 /* Assume the following compressed format of the microcode buffer:
13808 *
13809 * 254 word (508 byte) table indexed by byte code followed
13810 * by the following byte codes:
13811 *
13812 * 1-Byte Code:
13813 * 00: Emit word 0 in table.
13814 * 01: Emit word 1 in table.
13815 * .
13816 * FD: Emit word 253 in table.
13817 *
13818 * Multi-Byte Code:
13819 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
13820 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
13821 */
13822 word = 0;
13823 for (i = 253 * 2; i < _adv_asc3550_size; i++) {
13824 if (_adv_asc3550_buf[i] == 0xff) {
13825 for (j = 0; j < _adv_asc3550_buf[i + 1]; j++) {
13826 AdvWriteWordAutoIncLram(iop_base, (((ushort)
13827 _adv_asc3550_buf
13828 [i +
13829 3] << 8) |
13830 _adv_asc3550_buf
13831 [i + 2]));
13832 word++;
13833 }
13834 i += 3;
13835 } else if (_adv_asc3550_buf[i] == 0xfe) {
13836 AdvWriteWordAutoIncLram(iop_base, (((ushort)
13837 _adv_asc3550_buf[i +
13838 2]
13839 << 8) |
13840 _adv_asc3550_buf[i +
13841 1]));
13842 i += 2;
13843 word++;
13844 } else {
13845 AdvWriteWordAutoIncLram(iop_base, (((ushort)
13846 _adv_asc3550_buf[(_adv_asc3550_buf[i] * 2) + 1] << 8) | _adv_asc3550_buf[_adv_asc3550_buf[i] * 2]));
13847 word++;
13848 }
13849 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013850
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013851 /*
13852 * Set 'word' for later use to clear the rest of memory and save
13853 * the expanded mcode size.
13854 */
13855 word *= 2;
13856 adv_asc3550_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013857
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013858 /*
13859 * Clear the rest of ASC-3550 Internal RAM (8KB).
13860 */
13861 for (; word < ADV_3550_MEMSIZE; word += 2) {
13862 AdvWriteWordAutoIncLram(iop_base, 0);
13863 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013864
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013865 /*
13866 * Verify the microcode checksum.
13867 */
13868 sum = 0;
13869 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013870
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013871 for (word = 0; word < adv_asc3550_expanded_size; word += 2) {
13872 sum += AdvReadWordAutoIncLram(iop_base);
13873 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013874
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013875 if (sum != _adv_asc3550_chksum) {
13876 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
13877 return ADV_ERROR;
13878 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013879
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013880 /*
13881 * Restore the RISC memory BIOS region.
13882 */
13883 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
13884 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
13885 bios_mem[i]);
13886 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013887
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013888 /*
13889 * Calculate and write the microcode code checksum to the microcode
13890 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
13891 */
13892 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
13893 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
13894 code_sum = 0;
13895 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
13896 for (word = begin_addr; word < end_addr; word += 2) {
13897 code_sum += AdvReadWordAutoIncLram(iop_base);
13898 }
13899 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013900
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013901 /*
13902 * Read and save microcode version and date.
13903 */
13904 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
13905 asc_dvc->cfg->mcode_date);
13906 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
13907 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013908
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013909 /*
13910 * Set the chip type to indicate the ASC3550.
13911 */
13912 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013913
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013914 /*
13915 * If the PCI Configuration Command Register "Parity Error Response
13916 * Control" Bit was clear (0), then set the microcode variable
13917 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
13918 * to ignore DMA parity errors.
13919 */
13920 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
13921 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
13922 word |= CONTROL_FLAG_IGNORE_PERR;
13923 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
13924 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013925
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013926 /*
13927 * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
13928 * threshold of 128 bytes. This register is only accessible to the host.
13929 */
13930 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
13931 START_CTL_EMFU | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013932
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013933 /*
13934 * Microcode operating variables for WDTR, SDTR, and command tag
Matthew Wilcox47d853c2007-07-26 11:41:33 -040013935 * queuing will be set in slave_configure() based on what a
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013936 * device reports it is capable of in Inquiry byte 7.
13937 *
13938 * If SCSI Bus Resets have been disabled, then directly set
13939 * SDTR and WDTR from the EEPROM configuration. This will allow
13940 * the BIOS and warm boot to work without a SCSI bus hang on
13941 * the Inquiry caused by host and target mismatched DTR values.
13942 * Without the SCSI Bus Reset, before an Inquiry a device can't
13943 * be assumed to be in Asynchronous, Narrow mode.
13944 */
13945 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
13946 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
13947 asc_dvc->wdtr_able);
13948 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
13949 asc_dvc->sdtr_able);
13950 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013951
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013952 /*
13953 * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
13954 * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
13955 * bitmask. These values determine the maximum SDTR speed negotiated
13956 * with a device.
13957 *
13958 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
13959 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
13960 * without determining here whether the device supports SDTR.
13961 *
13962 * 4-bit speed SDTR speed name
13963 * =========== ===============
13964 * 0000b (0x0) SDTR disabled
13965 * 0001b (0x1) 5 Mhz
13966 * 0010b (0x2) 10 Mhz
13967 * 0011b (0x3) 20 Mhz (Ultra)
13968 * 0100b (0x4) 40 Mhz (LVD/Ultra2)
13969 * 0101b (0x5) 80 Mhz (LVD2/Ultra3)
13970 * 0110b (0x6) Undefined
13971 * .
13972 * 1111b (0xF) Undefined
13973 */
13974 word = 0;
13975 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
13976 if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) {
13977 /* Set Ultra speed for TID 'tid'. */
13978 word |= (0x3 << (4 * (tid % 4)));
13979 } else {
13980 /* Set Fast speed for TID 'tid'. */
13981 word |= (0x2 << (4 * (tid % 4)));
13982 }
13983 if (tid == 3) { /* Check if done with sdtr_speed1. */
13984 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
13985 word = 0;
13986 } else if (tid == 7) { /* Check if done with sdtr_speed2. */
13987 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
13988 word = 0;
13989 } else if (tid == 11) { /* Check if done with sdtr_speed3. */
13990 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
13991 word = 0;
13992 } else if (tid == 15) { /* Check if done with sdtr_speed4. */
13993 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
13994 /* End of loop. */
13995 }
13996 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013997
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013998 /*
13999 * Set microcode operating variable for the disconnect per TID bitmask.
14000 */
14001 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
14002 asc_dvc->cfg->disc_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014003
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014004 /*
14005 * Set SCSI_CFG0 Microcode Default Value.
14006 *
14007 * The microcode will set the SCSI_CFG0 register using this value
14008 * after it is started below.
14009 */
14010 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
14011 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
14012 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014013
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014014 /*
14015 * Determine SCSI_CFG1 Microcode Default Value.
14016 *
14017 * The microcode will set the SCSI_CFG1 register using this value
14018 * after it is started below.
14019 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014020
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014021 /* Read current SCSI_CFG1 Register value. */
14022 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014023
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014024 /*
14025 * If all three connectors are in use, return an error.
14026 */
14027 if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
14028 (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) {
14029 asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
14030 return ADV_ERROR;
14031 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014032
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014033 /*
14034 * If the internal narrow cable is reversed all of the SCSI_CTRL
14035 * register signals will be set. Check for and return an error if
14036 * this condition is found.
14037 */
14038 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
14039 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
14040 return ADV_ERROR;
14041 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014042
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014043 /*
14044 * If this is a differential board and a single-ended device
14045 * is attached to one of the connectors, return an error.
14046 */
14047 if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) {
14048 asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE;
14049 return ADV_ERROR;
14050 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014051
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014052 /*
14053 * If automatic termination control is enabled, then set the
14054 * termination value based on a table listed in a_condor.h.
14055 *
14056 * If manual termination was specified with an EEPROM setting
14057 * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
14058 * is ready to be 'ored' into SCSI_CFG1.
14059 */
14060 if (asc_dvc->cfg->termination == 0) {
14061 /*
14062 * The software always controls termination by setting TERM_CTL_SEL.
14063 * If TERM_CTL_SEL were set to 0, the hardware would set termination.
14064 */
14065 asc_dvc->cfg->termination |= TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014066
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014067 switch (scsi_cfg1 & CABLE_DETECT) {
14068 /* TERM_CTL_H: on, TERM_CTL_L: on */
14069 case 0x3:
14070 case 0x7:
14071 case 0xB:
14072 case 0xD:
14073 case 0xE:
14074 case 0xF:
14075 asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L);
14076 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014077
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014078 /* TERM_CTL_H: on, TERM_CTL_L: off */
14079 case 0x1:
14080 case 0x5:
14081 case 0x9:
14082 case 0xA:
14083 case 0xC:
14084 asc_dvc->cfg->termination |= TERM_CTL_H;
14085 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014086
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014087 /* TERM_CTL_H: off, TERM_CTL_L: off */
14088 case 0x2:
14089 case 0x6:
14090 break;
14091 }
14092 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014093
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014094 /*
14095 * Clear any set TERM_CTL_H and TERM_CTL_L bits.
14096 */
14097 scsi_cfg1 &= ~TERM_CTL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014098
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014099 /*
14100 * Invert the TERM_CTL_H and TERM_CTL_L bits and then
14101 * set 'scsi_cfg1'. The TERM_POL bit does not need to be
14102 * referenced, because the hardware internally inverts
14103 * the Termination High and Low bits if TERM_POL is set.
14104 */
14105 scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014106
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014107 /*
14108 * Set SCSI_CFG1 Microcode Default Value
14109 *
14110 * Set filter value and possibly modified termination control
14111 * bits in the Microcode SCSI_CFG1 Register Value.
14112 *
14113 * The microcode will set the SCSI_CFG1 register using this value
14114 * after it is started below.
14115 */
14116 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
14117 FLTR_DISABLE | scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014118
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014119 /*
14120 * Set MEM_CFG Microcode Default Value
14121 *
14122 * The microcode will set the MEM_CFG register using this value
14123 * after it is started below.
14124 *
14125 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
14126 * are defined.
14127 *
14128 * ASC-3550 has 8KB internal memory.
14129 */
14130 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
14131 BIOS_EN | RAM_SZ_8KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014132
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014133 /*
14134 * Set SEL_MASK Microcode Default Value
14135 *
14136 * The microcode will set the SEL_MASK register using this value
14137 * after it is started below.
14138 */
14139 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
14140 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014141
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014142 /*
14143 * Build carrier freelist.
14144 *
14145 * Driver must have already allocated memory and set 'carrier_buf'.
14146 */
14147 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014148
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014149 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
14150 asc_dvc->carr_freelist = NULL;
14151 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
14152 buf_size = ADV_CARRIER_BUFSIZE;
14153 } else {
14154 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
14155 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014156
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014157 do {
14158 /*
14159 * Get physical address of the carrier 'carrp'.
14160 */
14161 contig_len = sizeof(ADV_CARR_T);
14162 carr_paddr =
14163 cpu_to_le32(DvcGetPhyAddr
14164 (asc_dvc, NULL, (uchar *)carrp,
14165 (ADV_SDCNT *)&contig_len,
14166 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014167
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014168 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014169
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014170 /*
14171 * If the current carrier is not physically contiguous, then
14172 * maybe there was a page crossing. Try the next carrier aligned
14173 * start address.
14174 */
14175 if (contig_len < sizeof(ADV_CARR_T)) {
14176 carrp++;
14177 continue;
14178 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014179
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014180 carrp->carr_pa = carr_paddr;
14181 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014182
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014183 /*
14184 * Insert the carrier at the beginning of the freelist.
14185 */
14186 carrp->next_vpa =
14187 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
14188 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014189
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014190 carrp++;
14191 }
14192 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014193
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014194 /*
14195 * Set-up the Host->RISC Initiator Command Queue (ICQ).
14196 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014197
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014198 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
14199 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14200 return ADV_ERROR;
14201 }
14202 asc_dvc->carr_freelist = (ADV_CARR_T *)
14203 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014204
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014205 /*
14206 * The first command issued will be placed in the stopper carrier.
14207 */
14208 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014209
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014210 /*
14211 * Set RISC ICQ physical address start value.
14212 */
14213 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014214
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014215 /*
14216 * Set-up the RISC->Host Initiator Response Queue (IRQ).
14217 */
14218 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
14219 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14220 return ADV_ERROR;
14221 }
14222 asc_dvc->carr_freelist = (ADV_CARR_T *)
14223 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014224
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014225 /*
14226 * The first command completed by the RISC will be placed in
14227 * the stopper.
14228 *
14229 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
14230 * completed the RISC will set the ASC_RQ_STOPPER bit.
14231 */
14232 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014233
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014234 /*
14235 * Set RISC IRQ physical address start value.
14236 */
14237 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
14238 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014239
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014240 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
14241 (ADV_INTR_ENABLE_HOST_INTR |
14242 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014243
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014244 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
14245 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014246
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014247 /* finally, finally, gentlemen, start your engine */
14248 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014249
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014250 /*
14251 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
14252 * Resets should be performed. The RISC has to be running
14253 * to issue a SCSI Bus Reset.
14254 */
14255 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
14256 /*
14257 * If the BIOS Signature is present in memory, restore the
14258 * BIOS Handshake Configuration Table and do not perform
14259 * a SCSI Bus Reset.
14260 */
14261 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
14262 0x55AA) {
14263 /*
14264 * Restore per TID negotiated values.
14265 */
14266 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14267 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14268 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
14269 tagqng_able);
14270 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14271 AdvWriteByteLram(iop_base,
14272 ASC_MC_NUMBER_OF_MAX_CMD + tid,
14273 max_cmd[tid]);
14274 }
14275 } else {
14276 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
14277 warn_code = ASC_WARN_BUSRESET_ERROR;
14278 }
14279 }
14280 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014281
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014282 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014283}
14284
14285/*
14286 * Initialize the ASC-38C0800.
14287 *
14288 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
14289 *
14290 * For a non-fatal error return a warning code. If there are no warnings
14291 * then 0 is returned.
14292 *
14293 * Needed after initialization for error recovery.
14294 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014295static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014296{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014297 AdvPortAddr iop_base;
14298 ushort warn_code;
14299 ADV_DCNT sum;
14300 int begin_addr;
14301 int end_addr;
14302 ushort code_sum;
14303 int word;
14304 int j;
14305 int adv_asc38C0800_expanded_size;
14306 ADV_CARR_T *carrp;
14307 ADV_DCNT contig_len;
14308 ADV_SDCNT buf_size;
14309 ADV_PADDR carr_paddr;
14310 int i;
14311 ushort scsi_cfg1;
14312 uchar byte;
14313 uchar tid;
14314 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
14315 ushort wdtr_able, sdtr_able, tagqng_able;
14316 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070014317
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014318 /* If there is already an error, don't continue. */
14319 if (asc_dvc->err_code != 0) {
14320 return ADV_ERROR;
14321 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014322
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014323 /*
14324 * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
14325 */
14326 if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) {
14327 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
14328 return ADV_ERROR;
14329 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014330
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014331 warn_code = 0;
14332 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014333
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014334 /*
14335 * Save the RISC memory BIOS region before writing the microcode.
14336 * The BIOS may already be loaded and using its RISC LRAM region
14337 * so its region must be saved and restored.
14338 *
14339 * Note: This code makes the assumption, which is currently true,
14340 * that a chip reset does not clear RISC LRAM.
14341 */
14342 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14343 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14344 bios_mem[i]);
14345 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014346
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014347 /*
14348 * Save current per TID negotiated values.
14349 */
14350 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14351 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14352 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
14353 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14354 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
14355 max_cmd[tid]);
14356 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014357
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014358 /*
14359 * RAM BIST (RAM Built-In Self Test)
14360 *
14361 * Address : I/O base + offset 0x38h register (byte).
14362 * Function: Bit 7-6(RW) : RAM mode
14363 * Normal Mode : 0x00
14364 * Pre-test Mode : 0x40
14365 * RAM Test Mode : 0x80
14366 * Bit 5 : unused
14367 * Bit 4(RO) : Done bit
14368 * Bit 3-0(RO) : Status
14369 * Host Error : 0x08
14370 * Int_RAM Error : 0x04
14371 * RISC Error : 0x02
14372 * SCSI Error : 0x01
14373 * No Error : 0x00
14374 *
14375 * Note: RAM BIST code should be put right here, before loading the
14376 * microcode and after saving the RISC memory BIOS region.
14377 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014378
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014379 /*
14380 * LRAM Pre-test
14381 *
14382 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
14383 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
14384 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
14385 * to NORMAL_MODE, return an error too.
14386 */
14387 for (i = 0; i < 2; i++) {
14388 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
14389 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14390 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
14391 if ((byte & RAM_TEST_DONE) == 0
14392 || (byte & 0x0F) != PRE_TEST_VALUE) {
14393 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14394 return ADV_ERROR;
14395 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014396
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014397 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
14398 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14399 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
14400 != NORMAL_VALUE) {
14401 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14402 return ADV_ERROR;
14403 }
14404 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014405
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014406 /*
14407 * LRAM Test - It takes about 1.5 ms to run through the test.
14408 *
14409 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
14410 * If Done bit not set or Status not 0, save register byte, set the
14411 * err_code, and return an error.
14412 */
14413 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
14414 DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014415
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014416 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
14417 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
14418 /* Get here if Done bit not set or Status not 0. */
14419 asc_dvc->bist_err_code = byte; /* for BIOS display message */
14420 asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
14421 return ADV_ERROR;
14422 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014423
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014424 /* We need to reset back to normal mode after LRAM test passes. */
14425 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014426
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014427 /*
14428 * Load the Microcode
14429 *
14430 * Write the microcode image to RISC memory starting at address 0.
14431 *
14432 */
14433 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014434
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014435 /* Assume the following compressed format of the microcode buffer:
14436 *
14437 * 254 word (508 byte) table indexed by byte code followed
14438 * by the following byte codes:
14439 *
14440 * 1-Byte Code:
14441 * 00: Emit word 0 in table.
14442 * 01: Emit word 1 in table.
14443 * .
14444 * FD: Emit word 253 in table.
14445 *
14446 * Multi-Byte Code:
14447 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
14448 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
14449 */
14450 word = 0;
14451 for (i = 253 * 2; i < _adv_asc38C0800_size; i++) {
14452 if (_adv_asc38C0800_buf[i] == 0xff) {
14453 for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++) {
14454 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14455 _adv_asc38C0800_buf
14456 [i +
14457 3] << 8) |
14458 _adv_asc38C0800_buf
14459 [i + 2]));
14460 word++;
14461 }
14462 i += 3;
14463 } else if (_adv_asc38C0800_buf[i] == 0xfe) {
14464 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14465 _adv_asc38C0800_buf
14466 [i +
14467 2] << 8) |
14468 _adv_asc38C0800_buf[i
14469 +
14470 1]));
14471 i += 2;
14472 word++;
14473 } else {
14474 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14475 _adv_asc38C0800_buf[(_adv_asc38C0800_buf[i] * 2) + 1] << 8) | _adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2]));
14476 word++;
14477 }
14478 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014479
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014480 /*
14481 * Set 'word' for later use to clear the rest of memory and save
14482 * the expanded mcode size.
14483 */
14484 word *= 2;
14485 adv_asc38C0800_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014486
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014487 /*
14488 * Clear the rest of ASC-38C0800 Internal RAM (16KB).
14489 */
14490 for (; word < ADV_38C0800_MEMSIZE; word += 2) {
14491 AdvWriteWordAutoIncLram(iop_base, 0);
14492 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014493
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014494 /*
14495 * Verify the microcode checksum.
14496 */
14497 sum = 0;
14498 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014499
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014500 for (word = 0; word < adv_asc38C0800_expanded_size; word += 2) {
14501 sum += AdvReadWordAutoIncLram(iop_base);
14502 }
14503 ASC_DBG2(1, "AdvInitAsc38C0800Driver: word %d, i %d\n", word, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014504
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014505 ASC_DBG2(1,
14506 "AdvInitAsc38C0800Driver: sum 0x%lx, _adv_asc38C0800_chksum 0x%lx\n",
14507 (ulong)sum, (ulong)_adv_asc38C0800_chksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014508
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014509 if (sum != _adv_asc38C0800_chksum) {
14510 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
14511 return ADV_ERROR;
14512 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014513
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014514 /*
14515 * Restore the RISC memory BIOS region.
14516 */
14517 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14518 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14519 bios_mem[i]);
14520 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014521
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014522 /*
14523 * Calculate and write the microcode code checksum to the microcode
14524 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
14525 */
14526 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
14527 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
14528 code_sum = 0;
14529 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
14530 for (word = begin_addr; word < end_addr; word += 2) {
14531 code_sum += AdvReadWordAutoIncLram(iop_base);
14532 }
14533 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014534
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014535 /*
14536 * Read microcode version and date.
14537 */
14538 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
14539 asc_dvc->cfg->mcode_date);
14540 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
14541 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014542
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014543 /*
14544 * Set the chip type to indicate the ASC38C0800.
14545 */
14546 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014547
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014548 /*
14549 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
14550 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
14551 * cable detection and then we are able to read C_DET[3:0].
14552 *
14553 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
14554 * Microcode Default Value' section below.
14555 */
14556 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
14557 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
14558 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014559
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014560 /*
14561 * If the PCI Configuration Command Register "Parity Error Response
14562 * Control" Bit was clear (0), then set the microcode variable
14563 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
14564 * to ignore DMA parity errors.
14565 */
14566 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
14567 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
14568 word |= CONTROL_FLAG_IGNORE_PERR;
14569 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
14570 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014571
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014572 /*
14573 * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
14574 * bits for the default FIFO threshold.
14575 *
14576 * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
14577 *
14578 * For DMA Errata #4 set the BC_THRESH_ENB bit.
14579 */
14580 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
14581 BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH |
14582 READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014583
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014584 /*
14585 * Microcode operating variables for WDTR, SDTR, and command tag
Matthew Wilcox47d853c2007-07-26 11:41:33 -040014586 * queuing will be set in slave_configure() based on what a
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014587 * device reports it is capable of in Inquiry byte 7.
14588 *
14589 * If SCSI Bus Resets have been disabled, then directly set
14590 * SDTR and WDTR from the EEPROM configuration. This will allow
14591 * the BIOS and warm boot to work without a SCSI bus hang on
14592 * the Inquiry caused by host and target mismatched DTR values.
14593 * Without the SCSI Bus Reset, before an Inquiry a device can't
14594 * be assumed to be in Asynchronous, Narrow mode.
14595 */
14596 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
14597 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
14598 asc_dvc->wdtr_able);
14599 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
14600 asc_dvc->sdtr_able);
14601 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014602
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014603 /*
14604 * Set microcode operating variables for DISC and SDTR_SPEED1,
14605 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
14606 * configuration values.
14607 *
14608 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
14609 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
14610 * without determining here whether the device supports SDTR.
14611 */
14612 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
14613 asc_dvc->cfg->disc_enable);
14614 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
14615 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
14616 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
14617 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014618
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014619 /*
14620 * Set SCSI_CFG0 Microcode Default Value.
14621 *
14622 * The microcode will set the SCSI_CFG0 register using this value
14623 * after it is started below.
14624 */
14625 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
14626 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
14627 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014628
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014629 /*
14630 * Determine SCSI_CFG1 Microcode Default Value.
14631 *
14632 * The microcode will set the SCSI_CFG1 register using this value
14633 * after it is started below.
14634 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014635
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014636 /* Read current SCSI_CFG1 Register value. */
14637 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014638
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014639 /*
14640 * If the internal narrow cable is reversed all of the SCSI_CTRL
14641 * register signals will be set. Check for and return an error if
14642 * this condition is found.
14643 */
14644 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
14645 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
14646 return ADV_ERROR;
14647 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014648
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014649 /*
14650 * All kind of combinations of devices attached to one of four connectors
14651 * are acceptable except HVD device attached. For example, LVD device can
14652 * be attached to SE connector while SE device attached to LVD connector.
14653 * If LVD device attached to SE connector, it only runs up to Ultra speed.
14654 *
14655 * If an HVD device is attached to one of LVD connectors, return an error.
14656 * However, there is no way to detect HVD device attached to SE connectors.
14657 */
14658 if (scsi_cfg1 & HVD) {
14659 asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
14660 return ADV_ERROR;
14661 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014662
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014663 /*
14664 * If either SE or LVD automatic termination control is enabled, then
14665 * set the termination value based on a table listed in a_condor.h.
14666 *
14667 * If manual termination was specified with an EEPROM setting then
14668 * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready to
14669 * be 'ored' into SCSI_CFG1.
14670 */
14671 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
14672 /* SE automatic termination control is enabled. */
14673 switch (scsi_cfg1 & C_DET_SE) {
14674 /* TERM_SE_HI: on, TERM_SE_LO: on */
14675 case 0x1:
14676 case 0x2:
14677 case 0x3:
14678 asc_dvc->cfg->termination |= TERM_SE;
14679 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014680
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014681 /* TERM_SE_HI: on, TERM_SE_LO: off */
14682 case 0x0:
14683 asc_dvc->cfg->termination |= TERM_SE_HI;
14684 break;
14685 }
14686 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014687
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014688 if ((asc_dvc->cfg->termination & TERM_LVD) == 0) {
14689 /* LVD automatic termination control is enabled. */
14690 switch (scsi_cfg1 & C_DET_LVD) {
14691 /* TERM_LVD_HI: on, TERM_LVD_LO: on */
14692 case 0x4:
14693 case 0x8:
14694 case 0xC:
14695 asc_dvc->cfg->termination |= TERM_LVD;
14696 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014697
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014698 /* TERM_LVD_HI: off, TERM_LVD_LO: off */
14699 case 0x0:
14700 break;
14701 }
14702 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014703
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014704 /*
14705 * Clear any set TERM_SE and TERM_LVD bits.
14706 */
14707 scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014708
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014709 /*
14710 * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
14711 */
14712 scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014713
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014714 /*
14715 * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE bits
14716 * and set possibly modified termination control bits in the Microcode
14717 * SCSI_CFG1 Register Value.
14718 */
14719 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014720
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014721 /*
14722 * Set SCSI_CFG1 Microcode Default Value
14723 *
14724 * Set possibly modified termination control and reset DIS_TERM_DRV
14725 * bits in the Microcode SCSI_CFG1 Register Value.
14726 *
14727 * The microcode will set the SCSI_CFG1 register using this value
14728 * after it is started below.
14729 */
14730 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014731
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014732 /*
14733 * Set MEM_CFG Microcode Default Value
14734 *
14735 * The microcode will set the MEM_CFG register using this value
14736 * after it is started below.
14737 *
14738 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
14739 * are defined.
14740 *
14741 * ASC-38C0800 has 16KB internal memory.
14742 */
14743 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
14744 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014745
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014746 /*
14747 * Set SEL_MASK Microcode Default Value
14748 *
14749 * The microcode will set the SEL_MASK register using this value
14750 * after it is started below.
14751 */
14752 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
14753 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014754
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014755 /*
14756 * Build the carrier freelist.
14757 *
14758 * Driver must have already allocated memory and set 'carrier_buf'.
14759 */
14760 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014761
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014762 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
14763 asc_dvc->carr_freelist = NULL;
14764 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
14765 buf_size = ADV_CARRIER_BUFSIZE;
14766 } else {
14767 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
14768 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014769
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014770 do {
14771 /*
14772 * Get physical address for the carrier 'carrp'.
14773 */
14774 contig_len = sizeof(ADV_CARR_T);
14775 carr_paddr =
14776 cpu_to_le32(DvcGetPhyAddr
14777 (asc_dvc, NULL, (uchar *)carrp,
14778 (ADV_SDCNT *)&contig_len,
14779 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014780
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014781 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014782
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014783 /*
14784 * If the current carrier is not physically contiguous, then
14785 * maybe there was a page crossing. Try the next carrier aligned
14786 * start address.
14787 */
14788 if (contig_len < sizeof(ADV_CARR_T)) {
14789 carrp++;
14790 continue;
14791 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014792
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014793 carrp->carr_pa = carr_paddr;
14794 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014795
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014796 /*
14797 * Insert the carrier at the beginning of the freelist.
14798 */
14799 carrp->next_vpa =
14800 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
14801 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014802
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014803 carrp++;
14804 }
14805 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014806
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014807 /*
14808 * Set-up the Host->RISC Initiator Command Queue (ICQ).
14809 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014810
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014811 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
14812 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14813 return ADV_ERROR;
14814 }
14815 asc_dvc->carr_freelist = (ADV_CARR_T *)
14816 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014817
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014818 /*
14819 * The first command issued will be placed in the stopper carrier.
14820 */
14821 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014822
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014823 /*
14824 * Set RISC ICQ physical address start value.
14825 * carr_pa is LE, must be native before write
14826 */
14827 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014828
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014829 /*
14830 * Set-up the RISC->Host Initiator Response Queue (IRQ).
14831 */
14832 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
14833 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14834 return ADV_ERROR;
14835 }
14836 asc_dvc->carr_freelist = (ADV_CARR_T *)
14837 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014838
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014839 /*
14840 * The first command completed by the RISC will be placed in
14841 * the stopper.
14842 *
14843 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
14844 * completed the RISC will set the ASC_RQ_STOPPER bit.
14845 */
14846 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014847
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014848 /*
14849 * Set RISC IRQ physical address start value.
14850 *
14851 * carr_pa is LE, must be native before write *
14852 */
14853 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
14854 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014855
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014856 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
14857 (ADV_INTR_ENABLE_HOST_INTR |
14858 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014859
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014860 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
14861 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014862
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014863 /* finally, finally, gentlemen, start your engine */
14864 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014865
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014866 /*
14867 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
14868 * Resets should be performed. The RISC has to be running
14869 * to issue a SCSI Bus Reset.
14870 */
14871 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
14872 /*
14873 * If the BIOS Signature is present in memory, restore the
14874 * BIOS Handshake Configuration Table and do not perform
14875 * a SCSI Bus Reset.
14876 */
14877 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
14878 0x55AA) {
14879 /*
14880 * Restore per TID negotiated values.
14881 */
14882 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14883 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14884 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
14885 tagqng_able);
14886 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14887 AdvWriteByteLram(iop_base,
14888 ASC_MC_NUMBER_OF_MAX_CMD + tid,
14889 max_cmd[tid]);
14890 }
14891 } else {
14892 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
14893 warn_code = ASC_WARN_BUSRESET_ERROR;
14894 }
14895 }
14896 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014897
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014898 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014899}
14900
14901/*
14902 * Initialize the ASC-38C1600.
14903 *
14904 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
14905 *
14906 * For a non-fatal error return a warning code. If there are no warnings
14907 * then 0 is returned.
14908 *
14909 * Needed after initialization for error recovery.
14910 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014911static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014912{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014913 AdvPortAddr iop_base;
14914 ushort warn_code;
14915 ADV_DCNT sum;
14916 int begin_addr;
14917 int end_addr;
14918 ushort code_sum;
14919 long word;
14920 int j;
14921 int adv_asc38C1600_expanded_size;
14922 ADV_CARR_T *carrp;
14923 ADV_DCNT contig_len;
14924 ADV_SDCNT buf_size;
14925 ADV_PADDR carr_paddr;
14926 int i;
14927 ushort scsi_cfg1;
14928 uchar byte;
14929 uchar tid;
14930 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
14931 ushort wdtr_able, sdtr_able, ppr_able, tagqng_able;
14932 uchar max_cmd[ASC_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070014933
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014934 /* If there is already an error, don't continue. */
14935 if (asc_dvc->err_code != 0) {
14936 return ADV_ERROR;
14937 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014938
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014939 /*
14940 * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600.
14941 */
14942 if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
14943 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
14944 return ADV_ERROR;
14945 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014946
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014947 warn_code = 0;
14948 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014949
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014950 /*
14951 * Save the RISC memory BIOS region before writing the microcode.
14952 * The BIOS may already be loaded and using its RISC LRAM region
14953 * so its region must be saved and restored.
14954 *
14955 * Note: This code makes the assumption, which is currently true,
14956 * that a chip reset does not clear RISC LRAM.
14957 */
14958 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14959 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14960 bios_mem[i]);
14961 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014962
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014963 /*
14964 * Save current per TID negotiated values.
14965 */
14966 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14967 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14968 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
14969 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
14970 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
14971 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
14972 max_cmd[tid]);
14973 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014974
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014975 /*
14976 * RAM BIST (Built-In Self Test)
14977 *
14978 * Address : I/O base + offset 0x38h register (byte).
14979 * Function: Bit 7-6(RW) : RAM mode
14980 * Normal Mode : 0x00
14981 * Pre-test Mode : 0x40
14982 * RAM Test Mode : 0x80
14983 * Bit 5 : unused
14984 * Bit 4(RO) : Done bit
14985 * Bit 3-0(RO) : Status
14986 * Host Error : 0x08
14987 * Int_RAM Error : 0x04
14988 * RISC Error : 0x02
14989 * SCSI Error : 0x01
14990 * No Error : 0x00
14991 *
14992 * Note: RAM BIST code should be put right here, before loading the
14993 * microcode and after saving the RISC memory BIOS region.
14994 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014995
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014996 /*
14997 * LRAM Pre-test
14998 *
14999 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
15000 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
15001 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
15002 * to NORMAL_MODE, return an error too.
15003 */
15004 for (i = 0; i < 2; i++) {
15005 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
15006 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
15007 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
15008 if ((byte & RAM_TEST_DONE) == 0
15009 || (byte & 0x0F) != PRE_TEST_VALUE) {
15010 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
15011 return ADV_ERROR;
15012 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015013
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015014 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
15015 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
15016 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
15017 != NORMAL_VALUE) {
15018 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
15019 return ADV_ERROR;
15020 }
15021 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015022
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015023 /*
15024 * LRAM Test - It takes about 1.5 ms to run through the test.
15025 *
15026 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
15027 * If Done bit not set or Status not 0, save register byte, set the
15028 * err_code, and return an error.
15029 */
15030 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
15031 DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015032
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015033 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
15034 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
15035 /* Get here if Done bit not set or Status not 0. */
15036 asc_dvc->bist_err_code = byte; /* for BIOS display message */
15037 asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
15038 return ADV_ERROR;
15039 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015040
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015041 /* We need to reset back to normal mode after LRAM test passes. */
15042 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015043
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015044 /*
15045 * Load the Microcode
15046 *
15047 * Write the microcode image to RISC memory starting at address 0.
15048 *
15049 */
15050 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015051
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015052 /*
15053 * Assume the following compressed format of the microcode buffer:
15054 *
15055 * 254 word (508 byte) table indexed by byte code followed
15056 * by the following byte codes:
15057 *
15058 * 1-Byte Code:
15059 * 00: Emit word 0 in table.
15060 * 01: Emit word 1 in table.
15061 * .
15062 * FD: Emit word 253 in table.
15063 *
15064 * Multi-Byte Code:
15065 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
15066 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
15067 */
15068 word = 0;
15069 for (i = 253 * 2; i < _adv_asc38C1600_size; i++) {
15070 if (_adv_asc38C1600_buf[i] == 0xff) {
15071 for (j = 0; j < _adv_asc38C1600_buf[i + 1]; j++) {
15072 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15073 _adv_asc38C1600_buf
15074 [i +
15075 3] << 8) |
15076 _adv_asc38C1600_buf
15077 [i + 2]));
15078 word++;
15079 }
15080 i += 3;
15081 } else if (_adv_asc38C1600_buf[i] == 0xfe) {
15082 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15083 _adv_asc38C1600_buf
15084 [i +
15085 2] << 8) |
15086 _adv_asc38C1600_buf[i
15087 +
15088 1]));
15089 i += 2;
15090 word++;
15091 } else {
15092 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15093 _adv_asc38C1600_buf[(_adv_asc38C1600_buf[i] * 2) + 1] << 8) | _adv_asc38C1600_buf[_adv_asc38C1600_buf[i] * 2]));
15094 word++;
15095 }
15096 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015097
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015098 /*
15099 * Set 'word' for later use to clear the rest of memory and save
15100 * the expanded mcode size.
15101 */
15102 word *= 2;
15103 adv_asc38C1600_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015104
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015105 /*
15106 * Clear the rest of ASC-38C1600 Internal RAM (32KB).
15107 */
15108 for (; word < ADV_38C1600_MEMSIZE; word += 2) {
15109 AdvWriteWordAutoIncLram(iop_base, 0);
15110 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015111
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015112 /*
15113 * Verify the microcode checksum.
15114 */
15115 sum = 0;
15116 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015117
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015118 for (word = 0; word < adv_asc38C1600_expanded_size; word += 2) {
15119 sum += AdvReadWordAutoIncLram(iop_base);
15120 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015121
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015122 if (sum != _adv_asc38C1600_chksum) {
15123 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
15124 return ADV_ERROR;
15125 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015126
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015127 /*
15128 * Restore the RISC memory BIOS region.
15129 */
15130 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
15131 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
15132 bios_mem[i]);
15133 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015134
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015135 /*
15136 * Calculate and write the microcode code checksum to the microcode
15137 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
15138 */
15139 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
15140 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
15141 code_sum = 0;
15142 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
15143 for (word = begin_addr; word < end_addr; word += 2) {
15144 code_sum += AdvReadWordAutoIncLram(iop_base);
15145 }
15146 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015147
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015148 /*
15149 * Read microcode version and date.
15150 */
15151 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
15152 asc_dvc->cfg->mcode_date);
15153 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
15154 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015155
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015156 /*
15157 * Set the chip type to indicate the ASC38C1600.
15158 */
15159 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015160
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015161 /*
15162 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
15163 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
15164 * cable detection and then we are able to read C_DET[3:0].
15165 *
15166 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
15167 * Microcode Default Value' section below.
15168 */
15169 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
15170 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
15171 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015172
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015173 /*
15174 * If the PCI Configuration Command Register "Parity Error Response
15175 * Control" Bit was clear (0), then set the microcode variable
15176 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
15177 * to ignore DMA parity errors.
15178 */
15179 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
15180 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15181 word |= CONTROL_FLAG_IGNORE_PERR;
15182 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15183 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015184
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015185 /*
15186 * If the BIOS control flag AIPP (Asynchronous Information
15187 * Phase Protection) disable bit is not set, then set the firmware
15188 * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable
15189 * AIPP checking and encoding.
15190 */
15191 if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) {
15192 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15193 word |= CONTROL_FLAG_ENABLE_AIPP;
15194 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15195 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015196
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015197 /*
15198 * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4],
15199 * and START_CTL_TH [3:2].
15200 */
15201 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
15202 FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015203
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015204 /*
15205 * Microcode operating variables for WDTR, SDTR, and command tag
Matthew Wilcox47d853c2007-07-26 11:41:33 -040015206 * queuing will be set in slave_configure() based on what a
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015207 * device reports it is capable of in Inquiry byte 7.
15208 *
15209 * If SCSI Bus Resets have been disabled, then directly set
15210 * SDTR and WDTR from the EEPROM configuration. This will allow
15211 * the BIOS and warm boot to work without a SCSI bus hang on
15212 * the Inquiry caused by host and target mismatched DTR values.
15213 * Without the SCSI Bus Reset, before an Inquiry a device can't
15214 * be assumed to be in Asynchronous, Narrow mode.
15215 */
15216 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
15217 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
15218 asc_dvc->wdtr_able);
15219 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
15220 asc_dvc->sdtr_able);
15221 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015222
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015223 /*
15224 * Set microcode operating variables for DISC and SDTR_SPEED1,
15225 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
15226 * configuration values.
15227 *
15228 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
15229 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
15230 * without determining here whether the device supports SDTR.
15231 */
15232 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
15233 asc_dvc->cfg->disc_enable);
15234 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
15235 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
15236 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
15237 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015238
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015239 /*
15240 * Set SCSI_CFG0 Microcode Default Value.
15241 *
15242 * The microcode will set the SCSI_CFG0 register using this value
15243 * after it is started below.
15244 */
15245 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
15246 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
15247 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015248
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015249 /*
15250 * Calculate SCSI_CFG1 Microcode Default Value.
15251 *
15252 * The microcode will set the SCSI_CFG1 register using this value
15253 * after it is started below.
15254 *
15255 * Each ASC-38C1600 function has only two cable detect bits.
15256 * The bus mode override bits are in IOPB_SOFT_OVER_WR.
15257 */
15258 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015259
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015260 /*
15261 * If the cable is reversed all of the SCSI_CTRL register signals
15262 * will be set. Check for and return an error if this condition is
15263 * found.
15264 */
15265 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
15266 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
15267 return ADV_ERROR;
15268 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015269
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015270 /*
15271 * Each ASC-38C1600 function has two connectors. Only an HVD device
15272 * can not be connected to either connector. An LVD device or SE device
15273 * may be connected to either connecor. If an SE device is connected,
15274 * then at most Ultra speed (20 Mhz) can be used on both connectors.
15275 *
15276 * If an HVD device is attached, return an error.
15277 */
15278 if (scsi_cfg1 & HVD) {
15279 asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
15280 return ADV_ERROR;
15281 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015282
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015283 /*
15284 * Each function in the ASC-38C1600 uses only the SE cable detect and
15285 * termination because there are two connectors for each function. Each
15286 * function may use either LVD or SE mode. Corresponding the SE automatic
15287 * termination control EEPROM bits are used for each function. Each
15288 * function has its own EEPROM. If SE automatic control is enabled for
15289 * the function, then set the termination value based on a table listed
15290 * in a_condor.h.
15291 *
15292 * If manual termination is specified in the EEPROM for the function,
15293 * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is
15294 * ready to be 'ored' into SCSI_CFG1.
15295 */
15296 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
15297 /* SE automatic termination control is enabled. */
15298 switch (scsi_cfg1 & C_DET_SE) {
15299 /* TERM_SE_HI: on, TERM_SE_LO: on */
15300 case 0x1:
15301 case 0x2:
15302 case 0x3:
15303 asc_dvc->cfg->termination |= TERM_SE;
15304 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015305
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015306 case 0x0:
15307 if (ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) == 0) {
15308 /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */
15309 } else {
15310 /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */
15311 asc_dvc->cfg->termination |= TERM_SE_HI;
15312 }
15313 break;
15314 }
15315 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015316
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015317 /*
15318 * Clear any set TERM_SE bits.
15319 */
15320 scsi_cfg1 &= ~TERM_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015321
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015322 /*
15323 * Invert the TERM_SE bits and then set 'scsi_cfg1'.
15324 */
15325 scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015326
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015327 /*
15328 * Clear Big Endian and Terminator Polarity bits and set possibly
15329 * modified termination control bits in the Microcode SCSI_CFG1
15330 * Register Value.
15331 *
15332 * Big Endian bit is not used even on big endian machines.
15333 */
15334 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015335
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015336 /*
15337 * Set SCSI_CFG1 Microcode Default Value
15338 *
15339 * Set possibly modified termination control bits in the Microcode
15340 * SCSI_CFG1 Register Value.
15341 *
15342 * The microcode will set the SCSI_CFG1 register using this value
15343 * after it is started below.
15344 */
15345 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015346
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015347 /*
15348 * Set MEM_CFG Microcode Default Value
15349 *
15350 * The microcode will set the MEM_CFG register using this value
15351 * after it is started below.
15352 *
15353 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
15354 * are defined.
15355 *
15356 * ASC-38C1600 has 32KB internal memory.
15357 *
15358 * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come
15359 * out a special 16K Adv Library and Microcode version. After the issue
15360 * resolved, we should turn back to the 32K support. Both a_condor.h and
15361 * mcode.sas files also need to be updated.
15362 *
15363 * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
15364 * BIOS_EN | RAM_SZ_32KB);
15365 */
15366 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
15367 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015368
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015369 /*
15370 * Set SEL_MASK Microcode Default Value
15371 *
15372 * The microcode will set the SEL_MASK register using this value
15373 * after it is started below.
15374 */
15375 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
15376 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015377
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015378 /*
15379 * Build the carrier freelist.
15380 *
15381 * Driver must have already allocated memory and set 'carrier_buf'.
15382 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015383
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015384 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015385
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015386 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
15387 asc_dvc->carr_freelist = NULL;
15388 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
15389 buf_size = ADV_CARRIER_BUFSIZE;
15390 } else {
15391 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
15392 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015393
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015394 do {
15395 /*
15396 * Get physical address for the carrier 'carrp'.
15397 */
15398 contig_len = sizeof(ADV_CARR_T);
15399 carr_paddr =
15400 cpu_to_le32(DvcGetPhyAddr
15401 (asc_dvc, NULL, (uchar *)carrp,
15402 (ADV_SDCNT *)&contig_len,
15403 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015404
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015405 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015406
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015407 /*
15408 * If the current carrier is not physically contiguous, then
15409 * maybe there was a page crossing. Try the next carrier aligned
15410 * start address.
15411 */
15412 if (contig_len < sizeof(ADV_CARR_T)) {
15413 carrp++;
15414 continue;
15415 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015416
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015417 carrp->carr_pa = carr_paddr;
15418 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015419
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015420 /*
15421 * Insert the carrier at the beginning of the freelist.
15422 */
15423 carrp->next_vpa =
15424 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
15425 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015426
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015427 carrp++;
15428 }
15429 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015430
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015431 /*
15432 * Set-up the Host->RISC Initiator Command Queue (ICQ).
15433 */
15434 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
15435 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
15436 return ADV_ERROR;
15437 }
15438 asc_dvc->carr_freelist = (ADV_CARR_T *)
15439 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015440
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015441 /*
15442 * The first command issued will be placed in the stopper carrier.
15443 */
15444 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015445
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015446 /*
15447 * Set RISC ICQ physical address start value. Initialize the
15448 * COMMA register to the same value otherwise the RISC will
15449 * prematurely detect a command is available.
15450 */
15451 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
15452 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
15453 le32_to_cpu(asc_dvc->icq_sp->carr_pa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015454
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015455 /*
15456 * Set-up the RISC->Host Initiator Response Queue (IRQ).
15457 */
15458 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
15459 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
15460 return ADV_ERROR;
15461 }
15462 asc_dvc->carr_freelist = (ADV_CARR_T *)
15463 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015464
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015465 /*
15466 * The first command completed by the RISC will be placed in
15467 * the stopper.
15468 *
15469 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
15470 * completed the RISC will set the ASC_RQ_STOPPER bit.
15471 */
15472 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015473
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015474 /*
15475 * Set RISC IRQ physical address start value.
15476 */
15477 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
15478 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015479
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015480 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
15481 (ADV_INTR_ENABLE_HOST_INTR |
15482 ADV_INTR_ENABLE_GLOBAL_INTR));
15483 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
15484 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015485
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015486 /* finally, finally, gentlemen, start your engine */
15487 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015488
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015489 /*
15490 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
15491 * Resets should be performed. The RISC has to be running
15492 * to issue a SCSI Bus Reset.
15493 */
15494 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
15495 /*
15496 * If the BIOS Signature is present in memory, restore the
15497 * per TID microcode operating variables.
15498 */
15499 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
15500 0x55AA) {
15501 /*
15502 * Restore per TID negotiated values.
15503 */
15504 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
15505 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
15506 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
15507 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
15508 tagqng_able);
15509 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
15510 AdvWriteByteLram(iop_base,
15511 ASC_MC_NUMBER_OF_MAX_CMD + tid,
15512 max_cmd[tid]);
15513 }
15514 } else {
15515 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
15516 warn_code = ASC_WARN_BUSRESET_ERROR;
15517 }
15518 }
15519 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015520
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015521 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015522}
15523
15524/*
15525 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
15526 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
15527 * all of this is done.
15528 *
15529 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
15530 *
15531 * For a non-fatal error return a warning code. If there are no warnings
15532 * then 0 is returned.
15533 *
15534 * Note: Chip is stopped on entry.
15535 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015536static int __devinit AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070015537{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015538 AdvPortAddr iop_base;
15539 ushort warn_code;
15540 ADVEEP_3550_CONFIG eep_config;
15541 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015542
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015543 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015544
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015545 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015546
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015547 /*
15548 * Read the board's EEPROM configuration.
15549 *
15550 * Set default values if a bad checksum is found.
15551 */
15552 if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum) {
15553 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015554
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015555 /*
15556 * Set EEPROM default values.
15557 */
15558 for (i = 0; i < sizeof(ADVEEP_3550_CONFIG); i++) {
15559 *((uchar *)&eep_config + i) =
15560 *((uchar *)&Default_3550_EEPROM_Config + i);
15561 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015562
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015563 /*
15564 * Assume the 6 byte board serial number that was read
15565 * from EEPROM is correct even if the EEPROM checksum
15566 * failed.
15567 */
15568 eep_config.serial_number_word3 =
15569 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015570
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015571 eep_config.serial_number_word2 =
15572 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015573
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015574 eep_config.serial_number_word1 =
15575 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015576
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015577 AdvSet3550EEPConfig(iop_base, &eep_config);
15578 }
15579 /*
15580 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
15581 * EEPROM configuration that was read.
15582 *
15583 * This is the mapping of EEPROM fields to Adv Library fields.
15584 */
15585 asc_dvc->wdtr_able = eep_config.wdtr_able;
15586 asc_dvc->sdtr_able = eep_config.sdtr_able;
15587 asc_dvc->ultra_able = eep_config.ultra_able;
15588 asc_dvc->tagqng_able = eep_config.tagqng_able;
15589 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
15590 asc_dvc->max_host_qng = eep_config.max_host_qng;
15591 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
15592 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
15593 asc_dvc->start_motor = eep_config.start_motor;
15594 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
15595 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
15596 asc_dvc->no_scam = eep_config.scam_tolerant;
15597 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
15598 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
15599 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015600
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015601 /*
15602 * Set the host maximum queuing (max. 253, min. 16) and the per device
15603 * maximum queuing (max. 63, min. 4).
15604 */
15605 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
15606 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15607 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
15608 /* If the value is zero, assume it is uninitialized. */
15609 if (eep_config.max_host_qng == 0) {
15610 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15611 } else {
15612 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
15613 }
15614 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015615
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015616 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
15617 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15618 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
15619 /* If the value is zero, assume it is uninitialized. */
15620 if (eep_config.max_dvc_qng == 0) {
15621 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15622 } else {
15623 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
15624 }
15625 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015626
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015627 /*
15628 * If 'max_dvc_qng' is greater than 'max_host_qng', then
15629 * set 'max_dvc_qng' to 'max_host_qng'.
15630 */
15631 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
15632 eep_config.max_dvc_qng = eep_config.max_host_qng;
15633 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015634
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015635 /*
15636 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
15637 * values based on possibly adjusted EEPROM values.
15638 */
15639 asc_dvc->max_host_qng = eep_config.max_host_qng;
15640 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015641
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015642 /*
15643 * If the EEPROM 'termination' field is set to automatic (0), then set
15644 * the ADV_DVC_CFG 'termination' field to automatic also.
15645 *
15646 * If the termination is specified with a non-zero 'termination'
15647 * value check that a legal value is set and set the ADV_DVC_CFG
15648 * 'termination' field appropriately.
15649 */
15650 if (eep_config.termination == 0) {
15651 asc_dvc->cfg->termination = 0; /* auto termination */
15652 } else {
15653 /* Enable manual control with low off / high off. */
15654 if (eep_config.termination == 1) {
15655 asc_dvc->cfg->termination = TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015656
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015657 /* Enable manual control with low off / high on. */
15658 } else if (eep_config.termination == 2) {
15659 asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015660
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015661 /* Enable manual control with low on / high on. */
15662 } else if (eep_config.termination == 3) {
15663 asc_dvc->cfg->termination =
15664 TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L;
15665 } else {
15666 /*
15667 * The EEPROM 'termination' field contains a bad value. Use
15668 * automatic termination instead.
15669 */
15670 asc_dvc->cfg->termination = 0;
15671 warn_code |= ASC_WARN_EEPROM_TERMINATION;
15672 }
15673 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015674
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015675 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015676}
15677
15678/*
15679 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
15680 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
15681 * all of this is done.
15682 *
15683 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
15684 *
15685 * For a non-fatal error return a warning code. If there are no warnings
15686 * then 0 is returned.
15687 *
15688 * Note: Chip is stopped on entry.
15689 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015690static int __devinit AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070015691{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015692 AdvPortAddr iop_base;
15693 ushort warn_code;
15694 ADVEEP_38C0800_CONFIG eep_config;
15695 int i;
15696 uchar tid, termination;
15697 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015698
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015699 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015700
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015701 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015702
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015703 /*
15704 * Read the board's EEPROM configuration.
15705 *
15706 * Set default values if a bad checksum is found.
15707 */
15708 if (AdvGet38C0800EEPConfig(iop_base, &eep_config) !=
15709 eep_config.check_sum) {
15710 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015711
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015712 /*
15713 * Set EEPROM default values.
15714 */
15715 for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++) {
15716 *((uchar *)&eep_config + i) =
15717 *((uchar *)&Default_38C0800_EEPROM_Config + i);
15718 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015719
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015720 /*
15721 * Assume the 6 byte board serial number that was read
15722 * from EEPROM is correct even if the EEPROM checksum
15723 * failed.
15724 */
15725 eep_config.serial_number_word3 =
15726 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015727
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015728 eep_config.serial_number_word2 =
15729 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015730
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015731 eep_config.serial_number_word1 =
15732 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015733
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015734 AdvSet38C0800EEPConfig(iop_base, &eep_config);
15735 }
15736 /*
15737 * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
15738 * EEPROM configuration that was read.
15739 *
15740 * This is the mapping of EEPROM fields to Adv Library fields.
15741 */
15742 asc_dvc->wdtr_able = eep_config.wdtr_able;
15743 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
15744 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
15745 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
15746 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
15747 asc_dvc->tagqng_able = eep_config.tagqng_able;
15748 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
15749 asc_dvc->max_host_qng = eep_config.max_host_qng;
15750 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
15751 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
15752 asc_dvc->start_motor = eep_config.start_motor;
15753 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
15754 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
15755 asc_dvc->no_scam = eep_config.scam_tolerant;
15756 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
15757 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
15758 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015759
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015760 /*
15761 * For every Target ID if any of its 'sdtr_speed[1234]' bits
15762 * are set, then set an 'sdtr_able' bit for it.
15763 */
15764 asc_dvc->sdtr_able = 0;
15765 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
15766 if (tid == 0) {
15767 sdtr_speed = asc_dvc->sdtr_speed1;
15768 } else if (tid == 4) {
15769 sdtr_speed = asc_dvc->sdtr_speed2;
15770 } else if (tid == 8) {
15771 sdtr_speed = asc_dvc->sdtr_speed3;
15772 } else if (tid == 12) {
15773 sdtr_speed = asc_dvc->sdtr_speed4;
15774 }
15775 if (sdtr_speed & ADV_MAX_TID) {
15776 asc_dvc->sdtr_able |= (1 << tid);
15777 }
15778 sdtr_speed >>= 4;
15779 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015780
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015781 /*
15782 * Set the host maximum queuing (max. 253, min. 16) and the per device
15783 * maximum queuing (max. 63, min. 4).
15784 */
15785 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
15786 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15787 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
15788 /* If the value is zero, assume it is uninitialized. */
15789 if (eep_config.max_host_qng == 0) {
15790 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15791 } else {
15792 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
15793 }
15794 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015795
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015796 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
15797 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15798 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
15799 /* If the value is zero, assume it is uninitialized. */
15800 if (eep_config.max_dvc_qng == 0) {
15801 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15802 } else {
15803 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
15804 }
15805 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015806
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015807 /*
15808 * If 'max_dvc_qng' is greater than 'max_host_qng', then
15809 * set 'max_dvc_qng' to 'max_host_qng'.
15810 */
15811 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
15812 eep_config.max_dvc_qng = eep_config.max_host_qng;
15813 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015814
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015815 /*
15816 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
15817 * values based on possibly adjusted EEPROM values.
15818 */
15819 asc_dvc->max_host_qng = eep_config.max_host_qng;
15820 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015821
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015822 /*
15823 * If the EEPROM 'termination' field is set to automatic (0), then set
15824 * the ADV_DVC_CFG 'termination' field to automatic also.
15825 *
15826 * If the termination is specified with a non-zero 'termination'
15827 * value check that a legal value is set and set the ADV_DVC_CFG
15828 * 'termination' field appropriately.
15829 */
15830 if (eep_config.termination_se == 0) {
15831 termination = 0; /* auto termination for SE */
15832 } else {
15833 /* Enable manual control with low off / high off. */
15834 if (eep_config.termination_se == 1) {
15835 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015836
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015837 /* Enable manual control with low off / high on. */
15838 } else if (eep_config.termination_se == 2) {
15839 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015840
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015841 /* Enable manual control with low on / high on. */
15842 } else if (eep_config.termination_se == 3) {
15843 termination = TERM_SE;
15844 } else {
15845 /*
15846 * The EEPROM 'termination_se' field contains a bad value.
15847 * Use automatic termination instead.
15848 */
15849 termination = 0;
15850 warn_code |= ASC_WARN_EEPROM_TERMINATION;
15851 }
15852 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015853
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015854 if (eep_config.termination_lvd == 0) {
15855 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
15856 } else {
15857 /* Enable manual control with low off / high off. */
15858 if (eep_config.termination_lvd == 1) {
15859 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015860
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015861 /* Enable manual control with low off / high on. */
15862 } else if (eep_config.termination_lvd == 2) {
15863 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015864
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015865 /* Enable manual control with low on / high on. */
15866 } else if (eep_config.termination_lvd == 3) {
15867 asc_dvc->cfg->termination = termination | TERM_LVD;
15868 } else {
15869 /*
15870 * The EEPROM 'termination_lvd' field contains a bad value.
15871 * Use automatic termination instead.
15872 */
15873 asc_dvc->cfg->termination = termination;
15874 warn_code |= ASC_WARN_EEPROM_TERMINATION;
15875 }
15876 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015877
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015878 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015879}
15880
15881/*
15882 * Read the board's EEPROM configuration. Set fields in ASC_DVC_VAR and
15883 * ASC_DVC_CFG based on the EEPROM settings. The chip is stopped while
15884 * all of this is done.
15885 *
15886 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
15887 *
15888 * For a non-fatal error return a warning code. If there are no warnings
15889 * then 0 is returned.
15890 *
15891 * Note: Chip is stopped on entry.
15892 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015893static int __devinit AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070015894{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015895 AdvPortAddr iop_base;
15896 ushort warn_code;
15897 ADVEEP_38C1600_CONFIG eep_config;
15898 int i;
15899 uchar tid, termination;
15900 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015901
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015902 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015903
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015904 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015905
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015906 /*
15907 * Read the board's EEPROM configuration.
15908 *
15909 * Set default values if a bad checksum is found.
15910 */
15911 if (AdvGet38C1600EEPConfig(iop_base, &eep_config) !=
15912 eep_config.check_sum) {
15913 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015914
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015915 /*
15916 * Set EEPROM default values.
15917 */
15918 for (i = 0; i < sizeof(ADVEEP_38C1600_CONFIG); i++) {
15919 if (i == 1
15920 && ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) !=
15921 0) {
15922 /*
15923 * Set Function 1 EEPROM Word 0 MSB
15924 *
15925 * Clear the BIOS_ENABLE (bit 14) and INTAB (bit 11)
15926 * EEPROM bits.
15927 *
15928 * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60 and
15929 * old Mac system booting problem. The Expansion ROM must
15930 * be disabled in Function 1 for these systems.
15931 *
15932 */
15933 *((uchar *)&eep_config + i) =
15934 ((*
15935 ((uchar *)&Default_38C1600_EEPROM_Config
15936 +
15937 i)) &
15938 (~
15939 (((ADV_EEPROM_BIOS_ENABLE |
15940 ADV_EEPROM_INTAB) >> 8) & 0xFF)));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015941
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015942 /*
15943 * Set the INTAB (bit 11) if the GPIO 0 input indicates
15944 * the Function 1 interrupt line is wired to INTA.
15945 *
15946 * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input:
15947 * 1 - Function 1 interrupt line wired to INT A.
15948 * 0 - Function 1 interrupt line wired to INT B.
15949 *
15950 * Note: Adapter boards always have Function 0 wired to INTA.
15951 * Put all 5 GPIO bits in input mode and then read
15952 * their input values.
15953 */
15954 AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL,
15955 0);
15956 if (AdvReadByteRegister
15957 (iop_base, IOPB_GPIO_DATA) & 0x01) {
15958 /* Function 1 interrupt wired to INTA; Set EEPROM bit. */
15959 *((uchar *)&eep_config + i) |=
15960 ((ADV_EEPROM_INTAB >> 8) & 0xFF);
15961 }
15962 } else {
15963 *((uchar *)&eep_config + i) =
15964 *((uchar *)&Default_38C1600_EEPROM_Config
15965 + i);
15966 }
15967 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015968
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015969 /*
15970 * Assume the 6 byte board serial number that was read
15971 * from EEPROM is correct even if the EEPROM checksum
15972 * failed.
15973 */
15974 eep_config.serial_number_word3 =
15975 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015976
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015977 eep_config.serial_number_word2 =
15978 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015979
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015980 eep_config.serial_number_word1 =
15981 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015982
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015983 AdvSet38C1600EEPConfig(iop_base, &eep_config);
15984 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015985
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015986 /*
15987 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
15988 * EEPROM configuration that was read.
15989 *
15990 * This is the mapping of EEPROM fields to Adv Library fields.
15991 */
15992 asc_dvc->wdtr_able = eep_config.wdtr_able;
15993 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
15994 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
15995 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
15996 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
15997 asc_dvc->ppr_able = 0;
15998 asc_dvc->tagqng_able = eep_config.tagqng_able;
15999 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
16000 asc_dvc->max_host_qng = eep_config.max_host_qng;
16001 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
16002 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ASC_MAX_TID);
16003 asc_dvc->start_motor = eep_config.start_motor;
16004 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
16005 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
16006 asc_dvc->no_scam = eep_config.scam_tolerant;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016007
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016008 /*
16009 * For every Target ID if any of its 'sdtr_speed[1234]' bits
16010 * are set, then set an 'sdtr_able' bit for it.
16011 */
16012 asc_dvc->sdtr_able = 0;
16013 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
16014 if (tid == 0) {
16015 sdtr_speed = asc_dvc->sdtr_speed1;
16016 } else if (tid == 4) {
16017 sdtr_speed = asc_dvc->sdtr_speed2;
16018 } else if (tid == 8) {
16019 sdtr_speed = asc_dvc->sdtr_speed3;
16020 } else if (tid == 12) {
16021 sdtr_speed = asc_dvc->sdtr_speed4;
16022 }
16023 if (sdtr_speed & ASC_MAX_TID) {
16024 asc_dvc->sdtr_able |= (1 << tid);
16025 }
16026 sdtr_speed >>= 4;
16027 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016028
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016029 /*
16030 * Set the host maximum queuing (max. 253, min. 16) and the per device
16031 * maximum queuing (max. 63, min. 4).
16032 */
16033 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
16034 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16035 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
16036 /* If the value is zero, assume it is uninitialized. */
16037 if (eep_config.max_host_qng == 0) {
16038 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16039 } else {
16040 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
16041 }
16042 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016043
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016044 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
16045 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16046 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
16047 /* If the value is zero, assume it is uninitialized. */
16048 if (eep_config.max_dvc_qng == 0) {
16049 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16050 } else {
16051 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
16052 }
16053 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016054
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016055 /*
16056 * If 'max_dvc_qng' is greater than 'max_host_qng', then
16057 * set 'max_dvc_qng' to 'max_host_qng'.
16058 */
16059 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
16060 eep_config.max_dvc_qng = eep_config.max_host_qng;
16061 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016062
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016063 /*
16064 * Set ASC_DVC_VAR 'max_host_qng' and ASC_DVC_VAR 'max_dvc_qng'
16065 * values based on possibly adjusted EEPROM values.
16066 */
16067 asc_dvc->max_host_qng = eep_config.max_host_qng;
16068 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016069
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016070 /*
16071 * If the EEPROM 'termination' field is set to automatic (0), then set
16072 * the ASC_DVC_CFG 'termination' field to automatic also.
16073 *
16074 * If the termination is specified with a non-zero 'termination'
16075 * value check that a legal value is set and set the ASC_DVC_CFG
16076 * 'termination' field appropriately.
16077 */
16078 if (eep_config.termination_se == 0) {
16079 termination = 0; /* auto termination for SE */
16080 } else {
16081 /* Enable manual control with low off / high off. */
16082 if (eep_config.termination_se == 1) {
16083 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016084
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016085 /* Enable manual control with low off / high on. */
16086 } else if (eep_config.termination_se == 2) {
16087 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016088
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016089 /* Enable manual control with low on / high on. */
16090 } else if (eep_config.termination_se == 3) {
16091 termination = TERM_SE;
16092 } else {
16093 /*
16094 * The EEPROM 'termination_se' field contains a bad value.
16095 * Use automatic termination instead.
16096 */
16097 termination = 0;
16098 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16099 }
16100 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016101
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016102 if (eep_config.termination_lvd == 0) {
16103 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
16104 } else {
16105 /* Enable manual control with low off / high off. */
16106 if (eep_config.termination_lvd == 1) {
16107 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016108
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016109 /* Enable manual control with low off / high on. */
16110 } else if (eep_config.termination_lvd == 2) {
16111 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016112
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016113 /* Enable manual control with low on / high on. */
16114 } else if (eep_config.termination_lvd == 3) {
16115 asc_dvc->cfg->termination = termination | TERM_LVD;
16116 } else {
16117 /*
16118 * The EEPROM 'termination_lvd' field contains a bad value.
16119 * Use automatic termination instead.
16120 */
16121 asc_dvc->cfg->termination = termination;
16122 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16123 }
16124 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016125
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016126 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016127}
16128
16129/*
16130 * Read EEPROM configuration into the specified buffer.
16131 *
16132 * Return a checksum based on the EEPROM configuration read.
16133 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016134static ushort __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -070016135AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
16136{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016137 ushort wval, chksum;
16138 ushort *wbuf;
16139 int eep_addr;
16140 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016141
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016142 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
16143 wbuf = (ushort *)cfg_buf;
16144 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016145
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016146 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16147 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16148 wval = AdvReadEEPWord(iop_base, eep_addr);
16149 chksum += wval; /* Checksum is calculated from word values. */
16150 if (*charfields++) {
16151 *wbuf = le16_to_cpu(wval);
16152 } else {
16153 *wbuf = wval;
16154 }
16155 }
16156 /* Read checksum word. */
16157 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16158 wbuf++;
16159 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016160
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016161 /* Read rest of EEPROM not covered by the checksum. */
16162 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16163 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16164 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16165 if (*charfields++) {
16166 *wbuf = le16_to_cpu(*wbuf);
16167 }
16168 }
16169 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016170}
16171
16172/*
16173 * Read EEPROM configuration into the specified buffer.
16174 *
16175 * Return a checksum based on the EEPROM configuration read.
16176 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016177static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016178AdvGet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016179{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016180 ushort wval, chksum;
16181 ushort *wbuf;
16182 int eep_addr;
16183 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016184
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016185 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
16186 wbuf = (ushort *)cfg_buf;
16187 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016188
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016189 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16190 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16191 wval = AdvReadEEPWord(iop_base, eep_addr);
16192 chksum += wval; /* Checksum is calculated from word values. */
16193 if (*charfields++) {
16194 *wbuf = le16_to_cpu(wval);
16195 } else {
16196 *wbuf = wval;
16197 }
16198 }
16199 /* Read checksum word. */
16200 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16201 wbuf++;
16202 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016203
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016204 /* Read rest of EEPROM not covered by the checksum. */
16205 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16206 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16207 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16208 if (*charfields++) {
16209 *wbuf = le16_to_cpu(*wbuf);
16210 }
16211 }
16212 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016213}
16214
16215/*
16216 * Read EEPROM configuration into the specified buffer.
16217 *
16218 * Return a checksum based on the EEPROM configuration read.
16219 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016220static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016221AdvGet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016222{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016223 ushort wval, chksum;
16224 ushort *wbuf;
16225 int eep_addr;
16226 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016227
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016228 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
16229 wbuf = (ushort *)cfg_buf;
16230 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016231
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016232 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16233 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16234 wval = AdvReadEEPWord(iop_base, eep_addr);
16235 chksum += wval; /* Checksum is calculated from word values. */
16236 if (*charfields++) {
16237 *wbuf = le16_to_cpu(wval);
16238 } else {
16239 *wbuf = wval;
16240 }
16241 }
16242 /* Read checksum word. */
16243 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16244 wbuf++;
16245 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016246
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016247 /* Read rest of EEPROM not covered by the checksum. */
16248 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16249 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16250 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16251 if (*charfields++) {
16252 *wbuf = le16_to_cpu(*wbuf);
16253 }
16254 }
16255 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016256}
16257
16258/*
16259 * Read the EEPROM from specified location
16260 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016261static ushort __devinit AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016262{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016263 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16264 ASC_EEP_CMD_READ | eep_word_addr);
16265 AdvWaitEEPCmd(iop_base);
16266 return AdvReadWordRegister(iop_base, IOPW_EE_DATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016267}
16268
16269/*
16270 * Wait for EEPROM command to complete
16271 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016272static void __devinit AdvWaitEEPCmd(AdvPortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016273{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016274 int eep_delay_ms;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016275
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016276 for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++) {
16277 if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) &
16278 ASC_EEP_CMD_DONE) {
16279 break;
16280 }
16281 DvcSleepMilliSecond(1);
16282 }
16283 if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) ==
16284 0) {
16285 ASC_ASSERT(0);
16286 }
16287 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016288}
16289
16290/*
16291 * Write the EEPROM from 'cfg_buf'.
16292 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016293void __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -070016294AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
16295{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016296 ushort *wbuf;
16297 ushort addr, chksum;
16298 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016299
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016300 wbuf = (ushort *)cfg_buf;
16301 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
16302 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016303
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016304 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16305 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016306
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016307 /*
16308 * Write EEPROM from word 0 to word 20.
16309 */
16310 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16311 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16312 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016313
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016314 if (*charfields++) {
16315 word = cpu_to_le16(*wbuf);
16316 } else {
16317 word = *wbuf;
16318 }
16319 chksum += *wbuf; /* Checksum is calculated from word values. */
16320 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16321 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16322 ASC_EEP_CMD_WRITE | addr);
16323 AdvWaitEEPCmd(iop_base);
16324 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16325 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016326
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016327 /*
16328 * Write EEPROM checksum at word 21.
16329 */
16330 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16331 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16332 AdvWaitEEPCmd(iop_base);
16333 wbuf++;
16334 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016335
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016336 /*
16337 * Write EEPROM OEM name at words 22 to 29.
16338 */
16339 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16340 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
16341 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016342
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016343 if (*charfields++) {
16344 word = cpu_to_le16(*wbuf);
16345 } else {
16346 word = *wbuf;
16347 }
16348 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16349 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16350 ASC_EEP_CMD_WRITE | addr);
16351 AdvWaitEEPCmd(iop_base);
16352 }
16353 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
16354 AdvWaitEEPCmd(iop_base);
16355 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016356}
16357
16358/*
16359 * Write the EEPROM from 'cfg_buf'.
16360 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016361void __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016362AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016363{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016364 ushort *wbuf;
16365 ushort *charfields;
16366 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016367
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016368 wbuf = (ushort *)cfg_buf;
16369 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
16370 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016371
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016372 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16373 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016374
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016375 /*
16376 * Write EEPROM from word 0 to word 20.
16377 */
16378 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16379 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16380 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016381
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016382 if (*charfields++) {
16383 word = cpu_to_le16(*wbuf);
16384 } else {
16385 word = *wbuf;
16386 }
16387 chksum += *wbuf; /* Checksum is calculated from word values. */
16388 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16389 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16390 ASC_EEP_CMD_WRITE | addr);
16391 AdvWaitEEPCmd(iop_base);
16392 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16393 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016394
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016395 /*
16396 * Write EEPROM checksum at word 21.
16397 */
16398 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16399 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16400 AdvWaitEEPCmd(iop_base);
16401 wbuf++;
16402 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016403
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016404 /*
16405 * Write EEPROM OEM name at words 22 to 29.
16406 */
16407 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16408 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
16409 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016410
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016411 if (*charfields++) {
16412 word = cpu_to_le16(*wbuf);
16413 } else {
16414 word = *wbuf;
16415 }
16416 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16417 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16418 ASC_EEP_CMD_WRITE | addr);
16419 AdvWaitEEPCmd(iop_base);
16420 }
16421 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
16422 AdvWaitEEPCmd(iop_base);
16423 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016424}
16425
16426/*
16427 * Write the EEPROM from 'cfg_buf'.
16428 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016429void __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016430AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016431{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016432 ushort *wbuf;
16433 ushort *charfields;
16434 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016435
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016436 wbuf = (ushort *)cfg_buf;
16437 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
16438 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016439
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016440 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16441 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016442
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016443 /*
16444 * Write EEPROM from word 0 to word 20.
16445 */
16446 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16447 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16448 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016449
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016450 if (*charfields++) {
16451 word = cpu_to_le16(*wbuf);
16452 } else {
16453 word = *wbuf;
16454 }
16455 chksum += *wbuf; /* Checksum is calculated from word values. */
16456 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16457 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16458 ASC_EEP_CMD_WRITE | addr);
16459 AdvWaitEEPCmd(iop_base);
16460 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16461 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016462
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016463 /*
16464 * Write EEPROM checksum at word 21.
16465 */
16466 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16467 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16468 AdvWaitEEPCmd(iop_base);
16469 wbuf++;
16470 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016471
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016472 /*
16473 * Write EEPROM OEM name at words 22 to 29.
16474 */
16475 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16476 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
16477 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016478
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016479 if (*charfields++) {
16480 word = cpu_to_le16(*wbuf);
16481 } else {
16482 word = *wbuf;
16483 }
16484 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16485 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16486 ASC_EEP_CMD_WRITE | addr);
16487 AdvWaitEEPCmd(iop_base);
16488 }
16489 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
16490 AdvWaitEEPCmd(iop_base);
16491 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016492}
16493
16494/* a_advlib.c */
16495/*
16496 * AdvExeScsiQueue() - Send a request to the RISC microcode program.
16497 *
16498 * Allocate a carrier structure, point the carrier to the ADV_SCSI_REQ_Q,
16499 * add the carrier to the ICQ (Initiator Command Queue), and tickle the
16500 * RISC to notify it a new command is ready to be executed.
16501 *
16502 * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be
16503 * set to SCSI_MAX_RETRY.
16504 *
16505 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the microcode
16506 * for DMA addresses or math operations are byte swapped to little-endian
16507 * order.
16508 *
16509 * Return:
16510 * ADV_SUCCESS(1) - The request was successfully queued.
16511 * ADV_BUSY(0) - Resource unavailable; Retry again after pending
16512 * request completes.
16513 * ADV_ERROR(-1) - Invalid ADV_SCSI_REQ_Q request structure
16514 * host IC error.
16515 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016516static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016517{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016518 ulong last_int_level;
16519 AdvPortAddr iop_base;
16520 ADV_DCNT req_size;
16521 ADV_PADDR req_paddr;
16522 ADV_CARR_T *new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016523
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016524 ASC_ASSERT(scsiq != NULL); /* 'scsiq' should never be NULL. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070016525
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016526 /*
16527 * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
16528 */
16529 if (scsiq->target_id > ADV_MAX_TID) {
16530 scsiq->host_status = QHSTA_M_INVALID_DEVICE;
16531 scsiq->done_status = QD_WITH_ERROR;
16532 return ADV_ERROR;
16533 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016534
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016535 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016536
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016537 last_int_level = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070016538
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016539 /*
16540 * Allocate a carrier ensuring at least one carrier always
16541 * remains on the freelist and initialize fields.
16542 */
16543 if ((new_carrp = asc_dvc->carr_freelist) == NULL) {
16544 DvcLeaveCritical(last_int_level);
16545 return ADV_BUSY;
16546 }
16547 asc_dvc->carr_freelist = (ADV_CARR_T *)
16548 ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa));
16549 asc_dvc->carr_pending_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016550
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016551 /*
16552 * Set the carrier to be a stopper by setting 'next_vpa'
16553 * to the stopper value. The current stopper will be changed
16554 * below to point to the new stopper.
16555 */
16556 new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016557
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016558 /*
16559 * Clear the ADV_SCSI_REQ_Q done flag.
16560 */
16561 scsiq->a_flag &= ~ADV_SCSIQ_DONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016562
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016563 req_size = sizeof(ADV_SCSI_REQ_Q);
16564 req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *)scsiq,
16565 (ADV_SDCNT *)&req_size, ADV_IS_SCSIQ_FLAG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016566
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016567 ASC_ASSERT(ADV_32BALIGN(req_paddr) == req_paddr);
16568 ASC_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016569
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016570 /* Wait for assertion before making little-endian */
16571 req_paddr = cpu_to_le32(req_paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016572
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016573 /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
16574 scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq));
16575 scsiq->scsiq_rptr = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016576
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016577 scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp));
16578 /*
16579 * Every ADV_CARR_T.carr_pa is byte swapped to little-endian
16580 * order during initialization.
16581 */
16582 scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016583
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016584 /*
16585 * Use the current stopper to send the ADV_SCSI_REQ_Q command to
16586 * the microcode. The newly allocated stopper will become the new
16587 * stopper.
16588 */
16589 asc_dvc->icq_sp->areq_vpa = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016590
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016591 /*
16592 * Set the 'next_vpa' pointer for the old stopper to be the
16593 * physical address of the new stopper. The RISC can only
16594 * follow physical addresses.
16595 */
16596 asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016597
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016598 /*
16599 * Set the host adapter stopper pointer to point to the new carrier.
16600 */
16601 asc_dvc->icq_sp = new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016602
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016603 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
16604 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
16605 /*
16606 * Tickle the RISC to tell it to read its Command Queue Head pointer.
16607 */
16608 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
16609 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
16610 /*
16611 * Clear the tickle value. In the ASC-3550 the RISC flag
16612 * command 'clr_tickle_a' does not work unless the host
16613 * value is cleared.
16614 */
16615 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
16616 ADV_TICKLE_NOP);
16617 }
16618 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16619 /*
16620 * Notify the RISC a carrier is ready by writing the physical
16621 * address of the new carrier stopper to the COMMA register.
16622 */
16623 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
16624 le32_to_cpu(new_carrp->carr_pa));
16625 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016626
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016627 DvcLeaveCritical(last_int_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016628
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016629 return ADV_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016630}
16631
16632/*
16633 * Reset SCSI Bus and purge all outstanding requests.
16634 *
16635 * Return Value:
16636 * ADV_TRUE(1) - All requests are purged and SCSI Bus is reset.
16637 * ADV_FALSE(0) - Microcode command failed.
16638 * ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC
16639 * may be hung which requires driver recovery.
16640 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016641static int AdvResetSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016642{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016643 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016644
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016645 /*
16646 * Send the SCSI Bus Reset idle start idle command which asserts
16647 * the SCSI Bus Reset signal.
16648 */
16649 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_START, 0L);
16650 if (status != ADV_TRUE) {
16651 return status;
16652 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016653
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016654 /*
16655 * Delay for the specified SCSI Bus Reset hold time.
16656 *
16657 * The hold time delay is done on the host because the RISC has no
16658 * microsecond accurate timer.
16659 */
16660 DvcDelayMicroSecond(asc_dvc, (ushort)ASC_SCSI_RESET_HOLD_TIME_US);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016661
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016662 /*
16663 * Send the SCSI Bus Reset end idle command which de-asserts
16664 * the SCSI Bus Reset signal and purges any pending requests.
16665 */
16666 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_END, 0L);
16667 if (status != ADV_TRUE) {
16668 return status;
16669 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016670
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016671 DvcSleepMilliSecond((ADV_DCNT)asc_dvc->scsi_reset_wait * 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016672
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016673 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016674}
16675
16676/*
16677 * Reset chip and SCSI Bus.
16678 *
16679 * Return Value:
16680 * ADV_TRUE(1) - Chip re-initialization and SCSI Bus Reset successful.
16681 * ADV_FALSE(0) - Chip re-initialization and SCSI Bus Reset failure.
16682 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016683static int AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016684{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016685 int status;
16686 ushort wdtr_able, sdtr_able, tagqng_able;
16687 ushort ppr_able = 0;
16688 uchar tid, max_cmd[ADV_MAX_TID + 1];
16689 AdvPortAddr iop_base;
16690 ushort bios_sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016691
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016692 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016693
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016694 /*
16695 * Save current per TID negotiated values.
16696 */
16697 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
16698 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
16699 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16700 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
16701 }
16702 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
16703 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
16704 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
16705 max_cmd[tid]);
16706 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016707
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016708 /*
16709 * Force the AdvInitAsc3550/38C0800Driver() function to
16710 * perform a SCSI Bus Reset by clearing the BIOS signature word.
16711 * The initialization functions assumes a SCSI Bus Reset is not
16712 * needed if the BIOS signature word is present.
16713 */
16714 AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
16715 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016716
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016717 /*
16718 * Stop chip and reset it.
16719 */
16720 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP);
16721 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
16722 DvcSleepMilliSecond(100);
16723 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
16724 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016725
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016726 /*
16727 * Reset Adv Library error code, if any, and try
16728 * re-initializing the chip.
16729 */
16730 asc_dvc->err_code = 0;
16731 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16732 status = AdvInitAsc38C1600Driver(asc_dvc);
16733 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
16734 status = AdvInitAsc38C0800Driver(asc_dvc);
16735 } else {
16736 status = AdvInitAsc3550Driver(asc_dvc);
16737 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016738
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016739 /* Translate initialization return value to status value. */
16740 if (status == 0) {
16741 status = ADV_TRUE;
16742 } else {
16743 status = ADV_FALSE;
16744 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016745
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016746 /*
16747 * Restore the BIOS signature word.
16748 */
16749 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016750
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016751 /*
16752 * Restore per TID negotiated values.
16753 */
16754 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
16755 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
16756 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16757 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
16758 }
16759 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
16760 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
16761 AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
16762 max_cmd[tid]);
16763 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016764
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016765 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016766}
16767
16768/*
16769 * Adv Library Interrupt Service Routine
16770 *
16771 * This function is called by a driver's interrupt service routine.
16772 * The function disables and re-enables interrupts.
16773 *
16774 * When a microcode idle command is completed, the ADV_DVC_VAR
16775 * 'idle_cmd_done' field is set to ADV_TRUE.
16776 *
16777 * Note: AdvISR() can be called when interrupts are disabled or even
16778 * when there is no hardware interrupt condition present. It will
16779 * always check for completed idle commands and microcode requests.
16780 * This is an important feature that shouldn't be changed because it
16781 * allows commands to be completed from polling mode loops.
16782 *
16783 * Return:
16784 * ADV_TRUE(1) - interrupt was pending
16785 * ADV_FALSE(0) - no interrupt was pending
16786 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016787static int AdvISR(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016788{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016789 AdvPortAddr iop_base;
16790 uchar int_stat;
16791 ushort target_bit;
16792 ADV_CARR_T *free_carrp;
16793 ADV_VADDR irq_next_vpa;
16794 int flags;
16795 ADV_SCSI_REQ_Q *scsiq;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016796
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016797 flags = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070016798
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016799 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016800
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016801 /* Reading the register clears the interrupt. */
16802 int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016803
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016804 if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB |
16805 ADV_INTR_STATUS_INTRC)) == 0) {
16806 DvcLeaveCritical(flags);
16807 return ADV_FALSE;
16808 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016809
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016810 /*
16811 * Notify the driver of an asynchronous microcode condition by
16812 * calling the ADV_DVC_VAR.async_callback function. The function
16813 * is passed the microcode ASC_MC_INTRB_CODE byte value.
16814 */
16815 if (int_stat & ADV_INTR_STATUS_INTRB) {
16816 uchar intrb_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016817
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016818 AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016819
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016820 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
16821 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
16822 if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
16823 asc_dvc->carr_pending_cnt != 0) {
16824 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
16825 ADV_TICKLE_A);
16826 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
16827 AdvWriteByteRegister(iop_base,
16828 IOPB_TICKLE,
16829 ADV_TICKLE_NOP);
16830 }
16831 }
16832 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016833
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016834 if (asc_dvc->async_callback != 0) {
16835 (*asc_dvc->async_callback) (asc_dvc, intrb_code);
16836 }
16837 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016838
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016839 /*
16840 * Check if the IRQ stopper carrier contains a completed request.
16841 */
16842 while (((irq_next_vpa =
16843 le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0) {
16844 /*
16845 * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
16846 * The RISC will have set 'areq_vpa' to a virtual address.
16847 *
16848 * The firmware will have copied the ASC_SCSI_REQ_Q.scsiq_ptr
16849 * field to the carrier ADV_CARR_T.areq_vpa field. The conversion
16850 * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr'
16851 * in AdvExeScsiQueue().
16852 */
16853 scsiq = (ADV_SCSI_REQ_Q *)
16854 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016855
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016856 /*
16857 * Request finished with good status and the queue was not
16858 * DMAed to host memory by the firmware. Set all status fields
16859 * to indicate good status.
16860 */
16861 if ((irq_next_vpa & ASC_RQ_GOOD) != 0) {
16862 scsiq->done_status = QD_NO_ERROR;
16863 scsiq->host_status = scsiq->scsi_status = 0;
16864 scsiq->data_cnt = 0L;
16865 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016866
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016867 /*
16868 * Advance the stopper pointer to the next carrier
16869 * ignoring the lower four bits. Free the previous
16870 * stopper carrier.
16871 */
16872 free_carrp = asc_dvc->irq_sp;
16873 asc_dvc->irq_sp = (ADV_CARR_T *)
16874 ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016875
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016876 free_carrp->next_vpa =
16877 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
16878 asc_dvc->carr_freelist = free_carrp;
16879 asc_dvc->carr_pending_cnt--;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016880
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016881 ASC_ASSERT(scsiq != NULL);
16882 target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016883
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016884 /*
16885 * Clear request microcode control flag.
16886 */
16887 scsiq->cntl = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016888
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016889 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016890 * Notify the driver of the completed request by passing
16891 * the ADV_SCSI_REQ_Q pointer to its callback function.
16892 */
16893 scsiq->a_flag |= ADV_SCSIQ_DONE;
16894 (*asc_dvc->isr_callback) (asc_dvc, scsiq);
16895 /*
16896 * Note: After the driver callback function is called, 'scsiq'
16897 * can no longer be referenced.
16898 *
16899 * Fall through and continue processing other completed
16900 * requests...
16901 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070016902
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016903 /*
16904 * Disable interrupts again in case the driver inadvertently
16905 * enabled interrupts in its callback function.
16906 *
16907 * The DvcEnterCritical() return value is ignored, because
16908 * the 'flags' saved when AdvISR() was first entered will be
16909 * used to restore the interrupt flag on exit.
16910 */
16911 (void)DvcEnterCritical();
16912 }
16913 DvcLeaveCritical(flags);
16914 return ADV_TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016915}
16916
16917/*
16918 * Send an idle command to the chip and wait for completion.
16919 *
16920 * Command completion is polled for once per microsecond.
16921 *
16922 * The function can be called from anywhere including an interrupt handler.
16923 * But the function is not re-entrant, so it uses the DvcEnter/LeaveCritical()
16924 * functions to prevent reentrancy.
16925 *
16926 * Return Values:
16927 * ADV_TRUE - command completed successfully
16928 * ADV_FALSE - command failed
16929 * ADV_ERROR - command timed out
16930 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016931static int
Linus Torvalds1da177e2005-04-16 15:20:36 -070016932AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016933 ushort idle_cmd, ADV_DCNT idle_cmd_parameter)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016934{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016935 ulong last_int_level;
16936 int result;
16937 ADV_DCNT i, j;
16938 AdvPortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016939
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016940 last_int_level = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070016941
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016942 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016943
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016944 /*
16945 * Clear the idle command status which is set by the microcode
16946 * to a non-zero value to indicate when the command is completed.
16947 * The non-zero result is one of the IDLE_CMD_STATUS_* values
16948 * defined in a_advlib.h.
16949 */
16950 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort)0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016951
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016952 /*
16953 * Write the idle command value after the idle command parameter
16954 * has been written to avoid a race condition. If the order is not
16955 * followed, the microcode may process the idle command before the
16956 * parameters have been written to LRAM.
16957 */
16958 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
16959 cpu_to_le32(idle_cmd_parameter));
16960 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016961
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016962 /*
16963 * Tickle the RISC to tell it to process the idle command.
16964 */
16965 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B);
16966 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
16967 /*
16968 * Clear the tickle value. In the ASC-3550 the RISC flag
16969 * command 'clr_tickle_b' does not work unless the host
16970 * value is cleared.
16971 */
16972 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
16973 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016974
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016975 /* Wait for up to 100 millisecond for the idle command to timeout. */
16976 for (i = 0; i < SCSI_WAIT_100_MSEC; i++) {
16977 /* Poll once each microsecond for command completion. */
16978 for (j = 0; j < SCSI_US_PER_MSEC; j++) {
16979 AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS,
16980 result);
16981 if (result != 0) {
16982 DvcLeaveCritical(last_int_level);
16983 return result;
16984 }
16985 DvcDelayMicroSecond(asc_dvc, (ushort)1);
16986 }
16987 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016988
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016989 ASC_ASSERT(0); /* The idle command should never timeout. */
16990 DvcLeaveCritical(last_int_level);
16991 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016992}
16993
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060016994static int __devinit
16995advansys_wide_init_chip(asc_board_t *boardp, ADV_DVC_VAR *adv_dvc_varp)
16996{
16997 int req_cnt = 0;
16998 adv_req_t *reqp = NULL;
16999 int sg_cnt = 0;
17000 adv_sgblk_t *sgp;
17001 int warn_code, err_code;
17002
17003 /*
17004 * Allocate buffer carrier structures. The total size
17005 * is about 4 KB, so allocate all at once.
17006 */
17007 boardp->carrp = kmalloc(ADV_CARRIER_BUFSIZE, GFP_KERNEL);
17008 ASC_DBG1(1, "advansys_wide_init_chip: carrp 0x%p\n", boardp->carrp);
17009
17010 if (!boardp->carrp)
17011 goto kmalloc_failed;
17012
17013 /*
17014 * Allocate up to 'max_host_qng' request structures for the Wide
17015 * board. The total size is about 16 KB, so allocate all at once.
17016 * If the allocation fails decrement and try again.
17017 */
17018 for (req_cnt = adv_dvc_varp->max_host_qng; req_cnt > 0; req_cnt--) {
17019 reqp = kmalloc(sizeof(adv_req_t) * req_cnt, GFP_KERNEL);
17020
17021 ASC_DBG3(1, "advansys_wide_init_chip: reqp 0x%p, req_cnt %d, "
17022 "bytes %lu\n", reqp, req_cnt,
17023 (ulong)sizeof(adv_req_t) * req_cnt);
17024
17025 if (reqp)
17026 break;
17027 }
17028
17029 if (!reqp)
17030 goto kmalloc_failed;
17031
17032 boardp->orig_reqp = reqp;
17033
17034 /*
17035 * Allocate up to ADV_TOT_SG_BLOCK request structures for
17036 * the Wide board. Each structure is about 136 bytes.
17037 */
17038 boardp->adv_sgblkp = NULL;
17039 for (sg_cnt = 0; sg_cnt < ADV_TOT_SG_BLOCK; sg_cnt++) {
17040 sgp = kmalloc(sizeof(adv_sgblk_t), GFP_KERNEL);
17041
17042 if (!sgp)
17043 break;
17044
17045 sgp->next_sgblkp = boardp->adv_sgblkp;
17046 boardp->adv_sgblkp = sgp;
17047
17048 }
17049
17050 ASC_DBG3(1, "advansys_wide_init_chip: sg_cnt %d * %u = %u bytes\n",
17051 sg_cnt, sizeof(adv_sgblk_t),
17052 (unsigned)(sizeof(adv_sgblk_t) * sg_cnt));
17053
17054 if (!boardp->adv_sgblkp)
17055 goto kmalloc_failed;
17056
17057 adv_dvc_varp->carrier_buf = boardp->carrp;
17058
17059 /*
17060 * Point 'adv_reqp' to the request structures and
17061 * link them together.
17062 */
17063 req_cnt--;
17064 reqp[req_cnt].next_reqp = NULL;
17065 for (; req_cnt > 0; req_cnt--) {
17066 reqp[req_cnt - 1].next_reqp = &reqp[req_cnt];
17067 }
17068 boardp->adv_reqp = &reqp[0];
17069
17070 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
17071 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc3550Driver()\n");
17072 warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
17073 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
17074 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc38C0800Driver()"
17075 "\n");
17076 warn_code = AdvInitAsc38C0800Driver(adv_dvc_varp);
17077 } else {
17078 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc38C1600Driver()"
17079 "\n");
17080 warn_code = AdvInitAsc38C1600Driver(adv_dvc_varp);
17081 }
17082 err_code = adv_dvc_varp->err_code;
17083
17084 if (warn_code || err_code) {
17085 ASC_PRINT3("advansys_wide_init_chip: board %d error: warn 0x%x,"
17086 " error 0x%x\n", boardp->id, warn_code, err_code);
17087 }
17088
17089 goto exit;
17090
17091 kmalloc_failed:
17092 ASC_PRINT1("advansys_wide_init_chip: board %d error: kmalloc() "
17093 "failed\n", boardp->id);
17094 err_code = ADV_ERROR;
17095 exit:
17096 return err_code;
17097}
17098
17099static void advansys_wide_free_mem(asc_board_t *boardp)
17100{
17101 kfree(boardp->carrp);
17102 boardp->carrp = NULL;
17103 kfree(boardp->orig_reqp);
17104 boardp->orig_reqp = boardp->adv_reqp = NULL;
17105 while (boardp->adv_sgblkp) {
17106 adv_sgblk_t *sgp = boardp->adv_sgblkp;
17107 boardp->adv_sgblkp = sgp->next_sgblkp;
17108 kfree(sgp);
17109 }
17110}
17111
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017112static struct Scsi_Host *__devinit
17113advansys_board_found(int iop, struct device *dev, int bus_type)
17114{
17115 struct Scsi_Host *shost;
17116 struct pci_dev *pdev = bus_type == ASC_IS_PCI ? to_pci_dev(dev) : NULL;
17117 asc_board_t *boardp;
17118 ASC_DVC_VAR *asc_dvc_varp = NULL;
17119 ADV_DVC_VAR *adv_dvc_varp = NULL;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017120 int share_irq;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017121 int iolen = 0;
17122 ADV_PADDR pci_memory_address;
17123 int warn_code, err_code;
17124 int ret;
17125
17126 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017127 * Register the adapter, get its configuration, and
17128 * initialize it.
17129 */
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017130 ASC_DBG(2, "advansys_board_found: scsi_host_alloc()\n");
17131 shost = scsi_host_alloc(&advansys_template, sizeof(asc_board_t));
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017132 if (!shost)
17133 return NULL;
17134
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017135 /* Initialize private per board data */
17136 boardp = ASC_BOARDP(shost);
17137 memset(boardp, 0, sizeof(asc_board_t));
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017138 boardp->id = asc_board_count++;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017139 spin_lock_init(&boardp->lock);
17140
17141 /*
17142 * Handle both narrow and wide boards.
17143 *
17144 * If a Wide board was detected, set the board structure
17145 * wide board flag. Set-up the board structure based on
17146 * the board type.
17147 */
17148#ifdef CONFIG_PCI
17149 if (bus_type == ASC_IS_PCI &&
17150 (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW ||
17151 pdev->device == PCI_DEVICE_ID_38C0800_REV1 ||
17152 pdev->device == PCI_DEVICE_ID_38C1600_REV1)) {
17153 boardp->flags |= ASC_IS_WIDE_BOARD;
17154 }
17155#endif /* CONFIG_PCI */
17156
17157 if (ASC_NARROW_BOARD(boardp)) {
17158 ASC_DBG(1, "advansys_board_found: narrow board\n");
17159 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
17160 asc_dvc_varp->bus_type = bus_type;
17161 asc_dvc_varp->drv_ptr = boardp;
17162 asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg;
17163 asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
17164 asc_dvc_varp->iop_base = iop;
17165 asc_dvc_varp->isr_callback = asc_isr_callback;
17166 } else {
17167 ASC_DBG(1, "advansys_board_found: wide board\n");
17168 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
17169 adv_dvc_varp->drv_ptr = boardp;
17170 adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
17171 adv_dvc_varp->isr_callback = adv_isr_callback;
17172 adv_dvc_varp->async_callback = adv_async_callback;
17173#ifdef CONFIG_PCI
17174 if (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW) {
17175 ASC_DBG(1, "advansys_board_found: ASC-3550\n");
17176 adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
17177 } else if (pdev->device == PCI_DEVICE_ID_38C0800_REV1) {
17178 ASC_DBG(1, "advansys_board_found: ASC-38C0800\n");
17179 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
17180 } else {
17181 ASC_DBG(1, "advansys_board_found: ASC-38C1600\n");
17182 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C1600;
17183 }
17184#endif /* CONFIG_PCI */
17185
17186 /*
17187 * Map the board's registers into virtual memory for
17188 * PCI slave access. Only memory accesses are used to
17189 * access the board's registers.
17190 *
17191 * Note: The PCI register base address is not always
17192 * page aligned, but the address passed to ioremap()
17193 * must be page aligned. It is guaranteed that the
17194 * PCI register base address will not cross a page
17195 * boundary.
17196 */
17197 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
17198 iolen = ADV_3550_IOLEN;
17199 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
17200 iolen = ADV_38C0800_IOLEN;
17201 } else {
17202 iolen = ADV_38C1600_IOLEN;
17203 }
17204#ifdef CONFIG_PCI
17205 pci_memory_address = pci_resource_start(pdev, 1);
17206 ASC_DBG1(1,
17207 "advansys_board_found: pci_memory_address: 0x%lx\n",
17208 (ulong)pci_memory_address);
17209 if ((boardp->ioremap_addr =
17210 ioremap(pci_memory_address & PAGE_MASK, PAGE_SIZE)) == 0) {
17211 ASC_PRINT3
17212 ("advansys_board_found: board %d: ioremap(%x, %d) returned NULL\n",
17213 boardp->id, pci_memory_address, iolen);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017214 goto err_shost;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017215 }
Matthew Wilcox71f36112007-07-30 08:04:53 -060017216 ASC_DBG1(1, "advansys_board_found: ioremap_addr: 0x%lx\n",
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017217 (ulong)boardp->ioremap_addr);
17218 adv_dvc_varp->iop_base = (AdvPortAddr)
17219 (boardp->ioremap_addr +
17220 (pci_memory_address - (pci_memory_address & PAGE_MASK)));
Matthew Wilcox71f36112007-07-30 08:04:53 -060017221 ASC_DBG1(1, "advansys_board_found: iop_base: 0x%lx\n",
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017222 adv_dvc_varp->iop_base);
17223#endif /* CONFIG_PCI */
17224
17225 /*
17226 * Even though it isn't used to access wide boards, other
17227 * than for the debug line below, save I/O Port address so
17228 * that it can be reported.
17229 */
17230 boardp->ioport = iop;
17231
17232 ASC_DBG2(1,
17233 "advansys_board_found: iopb_chip_id_1 0x%x, iopw_chip_id_0 0x%x\n",
17234 (ushort)inp(iop + 1), (ushort)inpw(iop));
17235 }
17236
17237#ifdef CONFIG_PROC_FS
17238 /*
17239 * Allocate buffer for printing information from
17240 * /proc/scsi/advansys/[0...].
17241 */
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017242 boardp->prtbuf = kmalloc(ASC_PRTBUF_SIZE, GFP_KERNEL);
17243 if (!boardp->prtbuf) {
17244 ASC_PRINT2("advansys_board_found: board %d: kmalloc(%d) "
17245 "returned NULL\n", boardp->id, ASC_PRTBUF_SIZE);
17246 goto err_unmap;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017247 }
17248#endif /* CONFIG_PROC_FS */
17249
17250 if (ASC_NARROW_BOARD(boardp)) {
17251 asc_dvc_varp->cfg->dev = dev;
17252 /*
17253 * Set the board bus type and PCI IRQ before
17254 * calling AscInitGetConfig().
17255 */
17256 switch (asc_dvc_varp->bus_type) {
17257#ifdef CONFIG_ISA
17258 case ASC_IS_ISA:
17259 shost->unchecked_isa_dma = TRUE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017260 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017261 break;
17262 case ASC_IS_VL:
17263 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017264 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017265 break;
17266 case ASC_IS_EISA:
17267 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017268 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017269 break;
17270#endif /* CONFIG_ISA */
17271#ifdef CONFIG_PCI
17272 case ASC_IS_PCI:
17273 shost->irq = asc_dvc_varp->irq_no = pdev->irq;
17274 asc_dvc_varp->cfg->pci_slot_info =
17275 ASC_PCI_MKID(pdev->bus->number,
17276 PCI_SLOT(pdev->devfn),
17277 PCI_FUNC(pdev->devfn));
17278 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017279 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017280 break;
17281#endif /* CONFIG_PCI */
17282 default:
17283 ASC_PRINT2
17284 ("advansys_board_found: board %d: unknown adapter type: %d\n",
17285 boardp->id, asc_dvc_varp->bus_type);
17286 shost->unchecked_isa_dma = TRUE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017287 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017288 break;
17289 }
17290 } else {
17291 adv_dvc_varp->cfg->dev = dev;
17292 /*
17293 * For Wide boards set PCI information before calling
17294 * AdvInitGetConfig().
17295 */
17296#ifdef CONFIG_PCI
17297 shost->irq = adv_dvc_varp->irq_no = pdev->irq;
17298 adv_dvc_varp->cfg->pci_slot_info =
17299 ASC_PCI_MKID(pdev->bus->number,
17300 PCI_SLOT(pdev->devfn),
17301 PCI_FUNC(pdev->devfn));
17302 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017303 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017304#endif /* CONFIG_PCI */
17305 }
17306
17307 /*
17308 * Read the board configuration.
17309 */
17310 if (ASC_NARROW_BOARD(boardp)) {
17311 /*
17312 * NOTE: AscInitGetConfig() may change the board's
17313 * bus_type value. The bus_type value should no
17314 * longer be used. If the bus_type field must be
17315 * referenced only use the bit-wise AND operator "&".
17316 */
17317 ASC_DBG(2, "advansys_board_found: AscInitGetConfig()\n");
17318 switch (ret = AscInitGetConfig(asc_dvc_varp)) {
17319 case 0: /* No error */
17320 break;
17321 case ASC_WARN_IO_PORT_ROTATE:
17322 ASC_PRINT1
17323 ("AscInitGetConfig: board %d: I/O port address modified\n",
17324 boardp->id);
17325 break;
17326 case ASC_WARN_AUTO_CONFIG:
17327 ASC_PRINT1
17328 ("AscInitGetConfig: board %d: I/O port increment switch enabled\n",
17329 boardp->id);
17330 break;
17331 case ASC_WARN_EEPROM_CHKSUM:
17332 ASC_PRINT1
17333 ("AscInitGetConfig: board %d: EEPROM checksum error\n",
17334 boardp->id);
17335 break;
17336 case ASC_WARN_IRQ_MODIFIED:
17337 ASC_PRINT1
17338 ("AscInitGetConfig: board %d: IRQ modified\n",
17339 boardp->id);
17340 break;
17341 case ASC_WARN_CMD_QNG_CONFLICT:
17342 ASC_PRINT1
17343 ("AscInitGetConfig: board %d: tag queuing enabled w/o disconnects\n",
17344 boardp->id);
17345 break;
17346 default:
17347 ASC_PRINT2
17348 ("AscInitGetConfig: board %d: unknown warning: 0x%x\n",
17349 boardp->id, ret);
17350 break;
17351 }
17352 if ((err_code = asc_dvc_varp->err_code) != 0) {
17353 ASC_PRINT3
17354 ("AscInitGetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
17355 boardp->id,
17356 asc_dvc_varp->init_state, asc_dvc_varp->err_code);
17357 }
17358 } else {
17359 ASC_DBG(2, "advansys_board_found: AdvInitGetConfig()\n");
17360 if ((ret = AdvInitGetConfig(adv_dvc_varp)) != 0) {
17361 ASC_PRINT2
17362 ("AdvInitGetConfig: board %d: warning: 0x%x\n",
17363 boardp->id, ret);
17364 }
17365 if ((err_code = adv_dvc_varp->err_code) != 0) {
17366 ASC_PRINT2
17367 ("AdvInitGetConfig: board %d error: err_code 0x%x\n",
17368 boardp->id, adv_dvc_varp->err_code);
17369 }
17370 }
17371
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017372 if (err_code != 0)
17373 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017374
17375 /*
17376 * Save the EEPROM configuration so that it can be displayed
17377 * from /proc/scsi/advansys/[0...].
17378 */
17379 if (ASC_NARROW_BOARD(boardp)) {
17380
17381 ASCEEP_CONFIG *ep;
17382
17383 /*
17384 * Set the adapter's target id bit in the 'init_tidmask' field.
17385 */
17386 boardp->init_tidmask |=
17387 ADV_TID_TO_TIDMASK(asc_dvc_varp->cfg->chip_scsi_id);
17388
17389 /*
17390 * Save EEPROM settings for the board.
17391 */
17392 ep = &boardp->eep_config.asc_eep;
17393
17394 ep->init_sdtr = asc_dvc_varp->cfg->sdtr_enable;
17395 ep->disc_enable = asc_dvc_varp->cfg->disc_enable;
17396 ep->use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled;
17397 ASC_EEP_SET_DMA_SPD(ep, asc_dvc_varp->cfg->isa_dma_speed);
17398 ep->start_motor = asc_dvc_varp->start_motor;
17399 ep->cntl = asc_dvc_varp->dvc_cntl;
17400 ep->no_scam = asc_dvc_varp->no_scam;
17401 ep->max_total_qng = asc_dvc_varp->max_total_qng;
17402 ASC_EEP_SET_CHIP_ID(ep, asc_dvc_varp->cfg->chip_scsi_id);
17403 /* 'max_tag_qng' is set to the same value for every device. */
17404 ep->max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0];
17405 ep->adapter_info[0] = asc_dvc_varp->cfg->adapter_info[0];
17406 ep->adapter_info[1] = asc_dvc_varp->cfg->adapter_info[1];
17407 ep->adapter_info[2] = asc_dvc_varp->cfg->adapter_info[2];
17408 ep->adapter_info[3] = asc_dvc_varp->cfg->adapter_info[3];
17409 ep->adapter_info[4] = asc_dvc_varp->cfg->adapter_info[4];
17410 ep->adapter_info[5] = asc_dvc_varp->cfg->adapter_info[5];
17411
17412 /*
17413 * Modify board configuration.
17414 */
17415 ASC_DBG(2, "advansys_board_found: AscInitSetConfig()\n");
17416 switch (ret = AscInitSetConfig(asc_dvc_varp)) {
17417 case 0: /* No error. */
17418 break;
17419 case ASC_WARN_IO_PORT_ROTATE:
17420 ASC_PRINT1
17421 ("AscInitSetConfig: board %d: I/O port address modified\n",
17422 boardp->id);
17423 break;
17424 case ASC_WARN_AUTO_CONFIG:
17425 ASC_PRINT1
17426 ("AscInitSetConfig: board %d: I/O port increment switch enabled\n",
17427 boardp->id);
17428 break;
17429 case ASC_WARN_EEPROM_CHKSUM:
17430 ASC_PRINT1
17431 ("AscInitSetConfig: board %d: EEPROM checksum error\n",
17432 boardp->id);
17433 break;
17434 case ASC_WARN_IRQ_MODIFIED:
17435 ASC_PRINT1
17436 ("AscInitSetConfig: board %d: IRQ modified\n",
17437 boardp->id);
17438 break;
17439 case ASC_WARN_CMD_QNG_CONFLICT:
17440 ASC_PRINT1
17441 ("AscInitSetConfig: board %d: tag queuing w/o disconnects\n",
17442 boardp->id);
17443 break;
17444 default:
17445 ASC_PRINT2
17446 ("AscInitSetConfig: board %d: unknown warning: 0x%x\n",
17447 boardp->id, ret);
17448 break;
17449 }
17450 if (asc_dvc_varp->err_code != 0) {
17451 ASC_PRINT3
17452 ("AscInitSetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
17453 boardp->id,
17454 asc_dvc_varp->init_state, asc_dvc_varp->err_code);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017455 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017456 }
17457
17458 /*
17459 * Finish initializing the 'Scsi_Host' structure.
17460 */
17461 /* AscInitSetConfig() will set the IRQ for non-PCI boards. */
17462 if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
17463 shost->irq = asc_dvc_varp->irq_no;
17464 }
17465 } else {
17466 ADVEEP_3550_CONFIG *ep_3550;
17467 ADVEEP_38C0800_CONFIG *ep_38C0800;
17468 ADVEEP_38C1600_CONFIG *ep_38C1600;
17469
17470 /*
17471 * Save Wide EEP Configuration Information.
17472 */
17473 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
17474 ep_3550 = &boardp->eep_config.adv_3550_eep;
17475
17476 ep_3550->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
17477 ep_3550->max_host_qng = adv_dvc_varp->max_host_qng;
17478 ep_3550->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
17479 ep_3550->termination = adv_dvc_varp->cfg->termination;
17480 ep_3550->disc_enable = adv_dvc_varp->cfg->disc_enable;
17481 ep_3550->bios_ctrl = adv_dvc_varp->bios_ctrl;
17482 ep_3550->wdtr_able = adv_dvc_varp->wdtr_able;
17483 ep_3550->sdtr_able = adv_dvc_varp->sdtr_able;
17484 ep_3550->ultra_able = adv_dvc_varp->ultra_able;
17485 ep_3550->tagqng_able = adv_dvc_varp->tagqng_able;
17486 ep_3550->start_motor = adv_dvc_varp->start_motor;
17487 ep_3550->scsi_reset_delay =
17488 adv_dvc_varp->scsi_reset_wait;
17489 ep_3550->serial_number_word1 =
17490 adv_dvc_varp->cfg->serial1;
17491 ep_3550->serial_number_word2 =
17492 adv_dvc_varp->cfg->serial2;
17493 ep_3550->serial_number_word3 =
17494 adv_dvc_varp->cfg->serial3;
17495 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
17496 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
17497
17498 ep_38C0800->adapter_scsi_id =
17499 adv_dvc_varp->chip_scsi_id;
17500 ep_38C0800->max_host_qng = adv_dvc_varp->max_host_qng;
17501 ep_38C0800->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
17502 ep_38C0800->termination_lvd =
17503 adv_dvc_varp->cfg->termination;
17504 ep_38C0800->disc_enable =
17505 adv_dvc_varp->cfg->disc_enable;
17506 ep_38C0800->bios_ctrl = adv_dvc_varp->bios_ctrl;
17507 ep_38C0800->wdtr_able = adv_dvc_varp->wdtr_able;
17508 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
17509 ep_38C0800->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
17510 ep_38C0800->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
17511 ep_38C0800->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
17512 ep_38C0800->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
17513 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
17514 ep_38C0800->start_motor = adv_dvc_varp->start_motor;
17515 ep_38C0800->scsi_reset_delay =
17516 adv_dvc_varp->scsi_reset_wait;
17517 ep_38C0800->serial_number_word1 =
17518 adv_dvc_varp->cfg->serial1;
17519 ep_38C0800->serial_number_word2 =
17520 adv_dvc_varp->cfg->serial2;
17521 ep_38C0800->serial_number_word3 =
17522 adv_dvc_varp->cfg->serial3;
17523 } else {
17524 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
17525
17526 ep_38C1600->adapter_scsi_id =
17527 adv_dvc_varp->chip_scsi_id;
17528 ep_38C1600->max_host_qng = adv_dvc_varp->max_host_qng;
17529 ep_38C1600->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
17530 ep_38C1600->termination_lvd =
17531 adv_dvc_varp->cfg->termination;
17532 ep_38C1600->disc_enable =
17533 adv_dvc_varp->cfg->disc_enable;
17534 ep_38C1600->bios_ctrl = adv_dvc_varp->bios_ctrl;
17535 ep_38C1600->wdtr_able = adv_dvc_varp->wdtr_able;
17536 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
17537 ep_38C1600->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
17538 ep_38C1600->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
17539 ep_38C1600->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
17540 ep_38C1600->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
17541 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
17542 ep_38C1600->start_motor = adv_dvc_varp->start_motor;
17543 ep_38C1600->scsi_reset_delay =
17544 adv_dvc_varp->scsi_reset_wait;
17545 ep_38C1600->serial_number_word1 =
17546 adv_dvc_varp->cfg->serial1;
17547 ep_38C1600->serial_number_word2 =
17548 adv_dvc_varp->cfg->serial2;
17549 ep_38C1600->serial_number_word3 =
17550 adv_dvc_varp->cfg->serial3;
17551 }
17552
17553 /*
17554 * Set the adapter's target id bit in the 'init_tidmask' field.
17555 */
17556 boardp->init_tidmask |=
17557 ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017558 }
17559
17560 /*
17561 * Channels are numbered beginning with 0. For AdvanSys one host
17562 * structure supports one channel. Multi-channel boards have a
17563 * separate host structure for each channel.
17564 */
17565 shost->max_channel = 0;
17566 if (ASC_NARROW_BOARD(boardp)) {
17567 shost->max_id = ASC_MAX_TID + 1;
17568 shost->max_lun = ASC_MAX_LUN + 1;
17569
17570 shost->io_port = asc_dvc_varp->iop_base;
17571 boardp->asc_n_io_port = ASC_IOADR_GAP;
17572 shost->this_id = asc_dvc_varp->cfg->chip_scsi_id;
17573
17574 /* Set maximum number of queues the adapter can handle. */
17575 shost->can_queue = asc_dvc_varp->max_total_qng;
17576 } else {
17577 shost->max_id = ADV_MAX_TID + 1;
17578 shost->max_lun = ADV_MAX_LUN + 1;
17579
17580 /*
17581 * Save the I/O Port address and length even though
17582 * I/O ports are not used to access Wide boards.
17583 * Instead the Wide boards are accessed with
17584 * PCI Memory Mapped I/O.
17585 */
17586 shost->io_port = iop;
17587 boardp->asc_n_io_port = iolen;
17588
17589 shost->this_id = adv_dvc_varp->chip_scsi_id;
17590
17591 /* Set maximum number of queues the adapter can handle. */
17592 shost->can_queue = adv_dvc_varp->max_host_qng;
17593 }
17594
17595 /*
17596 * 'n_io_port' currently is one byte.
17597 *
17598 * Set a value to 'n_io_port', but never referenced it because
17599 * it may be truncated.
17600 */
17601 shost->n_io_port = boardp->asc_n_io_port <= 255 ?
17602 boardp->asc_n_io_port : 255;
17603
17604 /*
17605 * Following v1.3.89, 'cmd_per_lun' is no longer needed
17606 * and should be set to zero.
17607 *
17608 * But because of a bug introduced in v1.3.89 if the driver is
17609 * compiled as a module and 'cmd_per_lun' is zero, the Mid-Level
17610 * SCSI function 'allocate_device' will panic. To allow the driver
17611 * to work as a module in these kernels set 'cmd_per_lun' to 1.
17612 *
17613 * Note: This is wrong. cmd_per_lun should be set to the depth
17614 * you want on untagged devices always.
17615 #ifdef MODULE
17616 */
17617 shost->cmd_per_lun = 1;
17618/* #else
17619 shost->cmd_per_lun = 0;
17620#endif */
17621
17622 /*
17623 * Set the maximum number of scatter-gather elements the
17624 * adapter can handle.
17625 */
17626 if (ASC_NARROW_BOARD(boardp)) {
17627 /*
17628 * Allow two commands with 'sg_tablesize' scatter-gather
17629 * elements to be executed simultaneously. This value is
17630 * the theoretical hardware limit. It may be decreased
17631 * below.
17632 */
17633 shost->sg_tablesize =
17634 (((asc_dvc_varp->max_total_qng - 2) / 2) *
17635 ASC_SG_LIST_PER_Q) + 1;
17636 } else {
17637 shost->sg_tablesize = ADV_MAX_SG_LIST;
17638 }
17639
17640 /*
17641 * The value of 'sg_tablesize' can not exceed the SCSI
17642 * mid-level driver definition of SG_ALL. SG_ALL also
17643 * must not be exceeded, because it is used to define the
17644 * size of the scatter-gather table in 'struct asc_sg_head'.
17645 */
17646 if (shost->sg_tablesize > SG_ALL) {
17647 shost->sg_tablesize = SG_ALL;
17648 }
17649
17650 ASC_DBG1(1, "advansys_board_found: sg_tablesize: %d\n", shost->sg_tablesize);
17651
17652 /* BIOS start address. */
17653 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017654 shost->base = AscGetChipBiosAddress(asc_dvc_varp->iop_base,
17655 asc_dvc_varp->bus_type);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017656 } else {
17657 /*
17658 * Fill-in BIOS board variables. The Wide BIOS saves
17659 * information in LRAM that is used by the driver.
17660 */
17661 AdvReadWordLram(adv_dvc_varp->iop_base,
17662 BIOS_SIGNATURE, boardp->bios_signature);
17663 AdvReadWordLram(adv_dvc_varp->iop_base,
17664 BIOS_VERSION, boardp->bios_version);
17665 AdvReadWordLram(adv_dvc_varp->iop_base,
17666 BIOS_CODESEG, boardp->bios_codeseg);
17667 AdvReadWordLram(adv_dvc_varp->iop_base,
17668 BIOS_CODELEN, boardp->bios_codelen);
17669
17670 ASC_DBG2(1,
17671 "advansys_board_found: bios_signature 0x%x, bios_version 0x%x\n",
17672 boardp->bios_signature, boardp->bios_version);
17673
17674 ASC_DBG2(1,
17675 "advansys_board_found: bios_codeseg 0x%x, bios_codelen 0x%x\n",
17676 boardp->bios_codeseg, boardp->bios_codelen);
17677
17678 /*
17679 * If the BIOS saved a valid signature, then fill in
17680 * the BIOS code segment base address.
17681 */
17682 if (boardp->bios_signature == 0x55AA) {
17683 /*
17684 * Convert x86 realmode code segment to a linear
17685 * address by shifting left 4.
17686 */
17687 shost->base = ((ulong)boardp->bios_codeseg << 4);
17688 } else {
17689 shost->base = 0;
17690 }
17691 }
17692
17693 /*
17694 * Register Board Resources - I/O Port, DMA, IRQ
17695 */
17696
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017697 /* Register DMA Channel for Narrow boards. */
17698 shost->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */
17699#ifdef CONFIG_ISA
17700 if (ASC_NARROW_BOARD(boardp)) {
17701 /* Register DMA channel for ISA bus. */
17702 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
17703 shost->dma_channel = asc_dvc_varp->cfg->isa_dma_channel;
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017704 ret = request_dma(shost->dma_channel, "advansys");
17705 if (ret) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017706 ASC_PRINT3
17707 ("advansys_board_found: board %d: request_dma() %d failed %d\n",
17708 boardp->id, shost->dma_channel, ret);
Matthew Wilcox71f36112007-07-30 08:04:53 -060017709 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017710 }
17711 AscEnableIsaDma(shost->dma_channel);
17712 }
17713 }
17714#endif /* CONFIG_ISA */
17715
17716 /* Register IRQ Number. */
17717 ASC_DBG1(2, "advansys_board_found: request_irq() %d\n", shost->irq);
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017718
17719 ret = request_irq(shost->irq, advansys_interrupt, share_irq,
17720 "advansys", shost);
17721
17722 if (ret) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017723 if (ret == -EBUSY) {
17724 ASC_PRINT2
17725 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x already in use.\n",
17726 boardp->id, shost->irq);
17727 } else if (ret == -EINVAL) {
17728 ASC_PRINT2
17729 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x not valid.\n",
17730 boardp->id, shost->irq);
17731 } else {
17732 ASC_PRINT3
17733 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x failed with %d\n",
17734 boardp->id, shost->irq, ret);
17735 }
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017736 goto err_free_dma;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017737 }
17738
17739 /*
17740 * Initialize board RISC chip and enable interrupts.
17741 */
17742 if (ASC_NARROW_BOARD(boardp)) {
17743 ASC_DBG(2, "advansys_board_found: AscInitAsc1000Driver()\n");
17744 warn_code = AscInitAsc1000Driver(asc_dvc_varp);
17745 err_code = asc_dvc_varp->err_code;
17746
17747 if (warn_code || err_code) {
17748 ASC_PRINT4
17749 ("advansys_board_found: board %d error: init_state 0x%x, warn 0x%x, error 0x%x\n",
17750 boardp->id,
17751 asc_dvc_varp->init_state, warn_code, err_code);
17752 }
17753 } else {
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017754 err_code = advansys_wide_init_chip(boardp, adv_dvc_varp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017755 }
17756
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017757 if (err_code != 0)
17758 goto err_free_wide_mem;
17759
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017760 ASC_DBG_PRT_SCSI_HOST(2, shost);
17761
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017762 ret = scsi_add_host(shost, dev);
17763 if (ret)
17764 goto err_free_wide_mem;
17765
17766 scsi_scan_host(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017767 return shost;
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017768
17769 err_free_wide_mem:
17770 advansys_wide_free_mem(boardp);
17771 free_irq(shost->irq, shost);
17772 err_free_dma:
17773 if (shost->dma_channel != NO_ISA_DMA)
17774 free_dma(shost->dma_channel);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017775 err_free_proc:
17776 kfree(boardp->prtbuf);
17777 err_unmap:
17778 if (boardp->ioremap_addr)
17779 iounmap(boardp->ioremap_addr);
17780 err_shost:
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017781 scsi_host_put(shost);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017782 return NULL;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017783}
17784
17785/*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017786 * advansys_release()
17787 *
17788 * Release resources allocated for a single AdvanSys adapter.
17789 */
17790static int advansys_release(struct Scsi_Host *shost)
17791{
17792 asc_board_t *boardp;
17793
17794 ASC_DBG(1, "advansys_release: begin\n");
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017795 scsi_remove_host(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017796 boardp = ASC_BOARDP(shost);
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017797 free_irq(shost->irq, shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017798 if (shost->dma_channel != NO_ISA_DMA) {
17799 ASC_DBG(1, "advansys_release: free_dma()\n");
17800 free_dma(shost->dma_channel);
17801 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017802 if (ASC_WIDE_BOARD(boardp)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017803 iounmap(boardp->ioremap_addr);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017804 advansys_wide_free_mem(boardp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017805 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017806 kfree(boardp->prtbuf);
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017807 scsi_host_put(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017808 ASC_DBG(1, "advansys_release: end\n");
17809 return 0;
17810}
17811
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017812static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __devinitdata = {
17813 0x100, 0x0110, 0x120, 0x0130, 0x140, 0x0150, 0x0190,
17814 0x0210, 0x0230, 0x0250, 0x0330
17815};
17816
17817static int __devinit advansys_isa_probe(struct device *dev, unsigned int id)
17818{
17819 PortAddr iop_base = _asc_def_iop_base[id];
17820 struct Scsi_Host *shost;
17821
17822 if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060017823 ASC_DBG1(1, "advansys_isa_match: I/O port 0x%x busy\n",
17824 iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017825 return -ENODEV;
17826 }
17827 ASC_DBG1(1, "advansys_isa_match: probing I/O port 0x%x\n", iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017828 if (!AscFindSignature(iop_base))
17829 goto nodev;
17830 if (!(AscGetChipVersion(iop_base, ASC_IS_ISA) & ASC_CHIP_VER_ISA_BIT))
17831 goto nodev;
17832
17833 shost = advansys_board_found(iop_base, dev, ASC_IS_ISA);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017834 if (!shost)
17835 goto nodev;
17836
17837 dev_set_drvdata(dev, shost);
17838 return 0;
17839
17840 nodev:
Matthew Wilcox71f36112007-07-30 08:04:53 -060017841 release_region(iop_base, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017842 return -ENODEV;
17843}
17844
17845static int __devexit advansys_isa_remove(struct device *dev, unsigned int id)
17846{
Matthew Wilcox71f36112007-07-30 08:04:53 -060017847 int ioport = _asc_def_iop_base[id];
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017848 advansys_release(dev_get_drvdata(dev));
Matthew Wilcox71f36112007-07-30 08:04:53 -060017849 release_region(ioport, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017850 return 0;
17851}
17852
17853static struct isa_driver advansys_isa_driver = {
17854 .probe = advansys_isa_probe,
17855 .remove = __devexit_p(advansys_isa_remove),
17856 .driver = {
17857 .owner = THIS_MODULE,
17858 .name = "advansys",
17859 },
17860};
17861
17862static int __devinit advansys_vlb_probe(struct device *dev, unsigned int id)
17863{
17864 PortAddr iop_base = _asc_def_iop_base[id];
17865 struct Scsi_Host *shost;
17866
17867 if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060017868 ASC_DBG1(1, "advansys_vlb_match: I/O port 0x%x busy\n",
17869 iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017870 return -ENODEV;
17871 }
17872 ASC_DBG1(1, "advansys_vlb_match: probing I/O port 0x%x\n", iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017873 if (!AscFindSignature(iop_base))
17874 goto nodev;
17875 /*
17876 * I don't think this condition can actually happen, but the old
17877 * driver did it, and the chances of finding a VLB setup in 2007
17878 * to do testing with is slight to none.
17879 */
17880 if (AscGetChipVersion(iop_base, ASC_IS_VL) > ASC_CHIP_MAX_VER_VL)
17881 goto nodev;
17882
17883 shost = advansys_board_found(iop_base, dev, ASC_IS_VL);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017884 if (!shost)
17885 goto nodev;
17886
17887 dev_set_drvdata(dev, shost);
17888 return 0;
17889
17890 nodev:
Matthew Wilcox71f36112007-07-30 08:04:53 -060017891 release_region(iop_base, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017892 return -ENODEV;
17893}
17894
17895static struct isa_driver advansys_vlb_driver = {
17896 .probe = advansys_vlb_probe,
17897 .remove = __devexit_p(advansys_isa_remove),
17898 .driver = {
17899 .owner = THIS_MODULE,
17900 .name = "advansys",
17901 },
17902};
17903
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017904static struct eisa_device_id advansys_eisa_table[] __devinitdata = {
17905 { "ABP7401" },
17906 { "ABP7501" },
17907 { "" }
17908};
17909
17910MODULE_DEVICE_TABLE(eisa, advansys_eisa_table);
17911
17912/*
17913 * EISA is a little more tricky than PCI; each EISA device may have two
17914 * channels, and this driver is written to make each channel its own Scsi_Host
17915 */
17916struct eisa_scsi_data {
17917 struct Scsi_Host *host[2];
17918};
17919
17920static int __devinit advansys_eisa_probe(struct device *dev)
17921{
17922 int i, ioport;
17923 int err;
17924 struct eisa_device *edev = to_eisa_device(dev);
17925 struct eisa_scsi_data *data;
17926
17927 err = -ENOMEM;
17928 data = kzalloc(sizeof(*data), GFP_KERNEL);
17929 if (!data)
17930 goto fail;
17931 ioport = edev->base_addr + 0xc30;
17932
17933 err = -ENODEV;
17934 for (i = 0; i < 2; i++, ioport += 0x20) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060017935 if (!request_region(ioport, ASC_IOADR_GAP, "advansys")) {
17936 printk(KERN_WARNING "Region %x-%x busy\n", ioport,
17937 ioport + ASC_IOADR_GAP - 1);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017938 continue;
Matthew Wilcox71f36112007-07-30 08:04:53 -060017939 }
17940 if (!AscFindSignature(ioport)) {
17941 release_region(ioport, ASC_IOADR_GAP);
17942 continue;
17943 }
17944
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017945 /*
17946 * I don't know why we need to do this for EISA chips, but
17947 * not for any others. It looks to be equivalent to
17948 * AscGetChipCfgMsw, but I may have overlooked something,
17949 * so I'm not converting it until I get an EISA board to
17950 * test with.
17951 */
17952 inw(ioport + 4);
17953 data->host[i] = advansys_board_found(ioport, dev, ASC_IS_EISA);
Matthew Wilcox71f36112007-07-30 08:04:53 -060017954 if (data->host[i]) {
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017955 err = 0;
Matthew Wilcox71f36112007-07-30 08:04:53 -060017956 } else {
17957 release_region(ioport, ASC_IOADR_GAP);
17958 }
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017959 }
17960
17961 if (err) {
17962 kfree(data);
17963 } else {
17964 dev_set_drvdata(dev, data);
17965 }
17966
17967 fail:
17968 return err;
17969}
17970
17971static __devexit int advansys_eisa_remove(struct device *dev)
17972{
17973 int i;
17974 struct eisa_scsi_data *data = dev_get_drvdata(dev);
17975
17976 for (i = 0; i < 2; i++) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060017977 int ioport;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017978 struct Scsi_Host *shost = data->host[i];
17979 if (!shost)
17980 continue;
Matthew Wilcox71f36112007-07-30 08:04:53 -060017981 ioport = shost->io_port;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017982 advansys_release(shost);
Matthew Wilcox71f36112007-07-30 08:04:53 -060017983 release_region(ioport, ASC_IOADR_GAP);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017984 }
17985
17986 kfree(data);
17987 return 0;
17988}
17989
17990static struct eisa_driver advansys_eisa_driver = {
17991 .id_table = advansys_eisa_table,
17992 .driver = {
17993 .name = "advansys",
17994 .probe = advansys_eisa_probe,
17995 .remove = __devexit_p(advansys_eisa_remove),
17996 }
17997};
17998
Dave Jones2672ea82006-08-02 17:11:49 -040017999/* PCI Devices supported by this driver */
18000static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018001 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A,
18002 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
18003 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940,
18004 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
18005 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940U,
18006 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
18007 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940UW,
18008 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
18009 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C0800_REV1,
18010 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
18011 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C1600_REV1,
18012 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
18013 {}
Dave Jones2672ea82006-08-02 17:11:49 -040018014};
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018015
Dave Jones2672ea82006-08-02 17:11:49 -040018016MODULE_DEVICE_TABLE(pci, advansys_pci_tbl);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018017
Matthew Wilcox9649af32007-07-26 21:51:47 -060018018static void __devinit advansys_set_latency(struct pci_dev *pdev)
18019{
18020 if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) ||
18021 (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) {
18022 pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0);
18023 } else {
18024 u8 latency;
18025 pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency);
18026 if (latency < 0x20)
18027 pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x20);
18028 }
18029}
18030
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018031static int __devinit
18032advansys_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
18033{
18034 int err, ioport;
18035 struct Scsi_Host *shost;
18036
18037 err = pci_enable_device(pdev);
18038 if (err)
18039 goto fail;
Matthew Wilcox71f36112007-07-30 08:04:53 -060018040 err = pci_request_regions(pdev, "advansys");
18041 if (err)
18042 goto disable_device;
Matthew Wilcox9649af32007-07-26 21:51:47 -060018043 pci_set_master(pdev);
18044 advansys_set_latency(pdev);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018045
18046 if (pci_resource_len(pdev, 0) == 0)
18047 goto nodev;
18048
18049 ioport = pci_resource_start(pdev, 0);
18050 shost = advansys_board_found(ioport, &pdev->dev, ASC_IS_PCI);
18051
18052 if (!shost)
18053 goto nodev;
18054
18055 pci_set_drvdata(pdev, shost);
18056 return 0;
18057
18058 nodev:
18059 err = -ENODEV;
Matthew Wilcox71f36112007-07-30 08:04:53 -060018060 pci_release_regions(pdev);
18061 disable_device:
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018062 pci_disable_device(pdev);
18063 fail:
18064 return err;
18065}
18066
18067static void __devexit advansys_pci_remove(struct pci_dev *pdev)
18068{
18069 advansys_release(pci_get_drvdata(pdev));
Matthew Wilcox71f36112007-07-30 08:04:53 -060018070 pci_release_regions(pdev);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018071 pci_disable_device(pdev);
18072}
18073
18074static struct pci_driver advansys_pci_driver = {
18075 .name = "advansys",
18076 .id_table = advansys_pci_tbl,
18077 .probe = advansys_pci_probe,
18078 .remove = __devexit_p(advansys_pci_remove),
18079};
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040018080
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018081static int __init advansys_init(void)
18082{
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018083 int error;
18084
18085 error = isa_register_driver(&advansys_isa_driver,
18086 ASC_IOADR_TABLE_MAX_IX);
18087 if (error)
18088 goto fail;
18089
18090 error = isa_register_driver(&advansys_vlb_driver,
18091 ASC_IOADR_TABLE_MAX_IX);
18092 if (error)
18093 goto unregister_isa;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018094
18095 error = eisa_driver_register(&advansys_eisa_driver);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018096 if (error)
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018097 goto unregister_vlb;
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018098
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018099 error = pci_register_driver(&advansys_pci_driver);
18100 if (error)
18101 goto unregister_eisa;
18102
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018103 return 0;
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018104
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018105 unregister_eisa:
18106 eisa_driver_unregister(&advansys_eisa_driver);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018107 unregister_vlb:
18108 isa_unregister_driver(&advansys_vlb_driver);
18109 unregister_isa:
18110 isa_unregister_driver(&advansys_isa_driver);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018111 fail:
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018112 return error;
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018113}
18114
18115static void __exit advansys_exit(void)
18116{
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018117 pci_unregister_driver(&advansys_pci_driver);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018118 eisa_driver_unregister(&advansys_eisa_driver);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018119 isa_unregister_driver(&advansys_vlb_driver);
18120 isa_unregister_driver(&advansys_isa_driver);
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018121}
18122
18123module_init(advansys_init);
18124module_exit(advansys_exit);
18125
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040018126MODULE_LICENSE("GPL");