blob: 73d974a15fcae7c9102ed4c79b91687fd374c5d7 [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];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383} ASC_DVC_CFG;
1384
1385#define ASC_DEF_DVC_CNTL 0xFFFF
1386#define ASC_DEF_CHIP_SCSI_ID 7
1387#define ASC_DEF_ISA_DMA_SPEED 4
1388#define ASC_INIT_STATE_NULL 0x0000
1389#define ASC_INIT_STATE_BEG_GET_CFG 0x0001
1390#define ASC_INIT_STATE_END_GET_CFG 0x0002
1391#define ASC_INIT_STATE_BEG_SET_CFG 0x0004
1392#define ASC_INIT_STATE_END_SET_CFG 0x0008
1393#define ASC_INIT_STATE_BEG_LOAD_MC 0x0010
1394#define ASC_INIT_STATE_END_LOAD_MC 0x0020
1395#define ASC_INIT_STATE_BEG_INQUIRY 0x0040
1396#define ASC_INIT_STATE_END_INQUIRY 0x0080
1397#define ASC_INIT_RESET_SCSI_DONE 0x0100
1398#define ASC_INIT_STATE_WITHOUT_EEP 0x8000
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399#define ASC_BUG_FIX_IF_NOT_DWB 0x0001
1400#define ASC_BUG_FIX_ASYN_USE_SYN 0x0002
1401#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41
1402#define ASC_MIN_TAGGED_CMD 7
1403#define ASC_MAX_SCSI_RESET_WAIT 30
1404
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001405struct asc_dvc_var; /* Forward Declaration. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001407typedef void (*ASC_ISR_CALLBACK) (struct asc_dvc_var *, ASC_QDONE_INFO *);
1408typedef int (*ASC_EXE_CALLBACK) (struct asc_dvc_var *, ASC_SCSI_Q *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409
1410typedef struct asc_dvc_var {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001411 PortAddr iop_base;
1412 ushort err_code;
1413 ushort dvc_cntl;
1414 ushort bug_fix_cntl;
1415 ushort bus_type;
1416 ASC_ISR_CALLBACK isr_callback;
1417 ASC_EXE_CALLBACK exe_callback;
1418 ASC_SCSI_BIT_ID_TYPE init_sdtr;
1419 ASC_SCSI_BIT_ID_TYPE sdtr_done;
1420 ASC_SCSI_BIT_ID_TYPE use_tagged_qng;
1421 ASC_SCSI_BIT_ID_TYPE unit_not_ready;
1422 ASC_SCSI_BIT_ID_TYPE queue_full_or_busy;
1423 ASC_SCSI_BIT_ID_TYPE start_motor;
1424 uchar scsi_reset_wait;
1425 uchar chip_no;
1426 char is_in_int;
1427 uchar max_total_qng;
1428 uchar cur_total_qng;
1429 uchar in_critical_cnt;
1430 uchar irq_no;
1431 uchar last_q_shortage;
1432 ushort init_state;
1433 uchar cur_dvc_qng[ASC_MAX_TID + 1];
1434 uchar max_dvc_qng[ASC_MAX_TID + 1];
1435 ASC_SCSI_Q *scsiq_busy_head[ASC_MAX_TID + 1];
1436 ASC_SCSI_Q *scsiq_busy_tail[ASC_MAX_TID + 1];
1437 uchar sdtr_period_tbl[ASC_MAX_SYN_XFER_NO];
1438 ASC_DVC_CFG *cfg;
1439 ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer_always;
1440 char redo_scam;
1441 ushort res2;
1442 uchar dos_int13_table[ASC_MAX_TID + 1];
1443 ASC_DCNT max_dma_count;
1444 ASC_SCSI_BIT_ID_TYPE no_scam;
1445 ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer;
1446 uchar max_sdtr_index;
1447 uchar host_init_sdtr_index;
1448 struct asc_board *drv_ptr;
1449 ASC_DCNT uc_break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450} ASC_DVC_VAR;
1451
1452typedef struct asc_dvc_inq_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001453 uchar type[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454} ASC_DVC_INQ_INFO;
1455
1456typedef struct asc_cap_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001457 ASC_DCNT lba;
1458 ASC_DCNT blk_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459} ASC_CAP_INFO;
1460
1461typedef struct asc_cap_info_array {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001462 ASC_CAP_INFO cap_info[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463} ASC_CAP_INFO_ARRAY;
1464
1465#define ASC_MCNTL_NO_SEL_TIMEOUT (ushort)0x0001
1466#define ASC_MCNTL_NULL_TARGET (ushort)0x0002
1467#define ASC_CNTL_INITIATOR (ushort)0x0001
1468#define ASC_CNTL_BIOS_GT_1GB (ushort)0x0002
1469#define ASC_CNTL_BIOS_GT_2_DISK (ushort)0x0004
1470#define ASC_CNTL_BIOS_REMOVABLE (ushort)0x0008
1471#define ASC_CNTL_NO_SCAM (ushort)0x0010
1472#define ASC_CNTL_INT_MULTI_Q (ushort)0x0080
1473#define ASC_CNTL_NO_LUN_SUPPORT (ushort)0x0040
1474#define ASC_CNTL_NO_VERIFY_COPY (ushort)0x0100
1475#define ASC_CNTL_RESET_SCSI (ushort)0x0200
1476#define ASC_CNTL_INIT_INQUIRY (ushort)0x0400
1477#define ASC_CNTL_INIT_VERBOSE (ushort)0x0800
1478#define ASC_CNTL_SCSI_PARITY (ushort)0x1000
1479#define ASC_CNTL_BURST_MODE (ushort)0x2000
1480#define ASC_CNTL_SDTR_ENABLE_ULTRA (ushort)0x4000
1481#define ASC_EEP_DVC_CFG_BEG_VL 2
1482#define ASC_EEP_MAX_DVC_ADDR_VL 15
1483#define ASC_EEP_DVC_CFG_BEG 32
1484#define ASC_EEP_MAX_DVC_ADDR 45
1485#define ASC_EEP_DEFINED_WORDS 10
1486#define ASC_EEP_MAX_ADDR 63
1487#define ASC_EEP_RES_WORDS 0
1488#define ASC_EEP_MAX_RETRY 20
1489#define ASC_MAX_INIT_BUSY_RETRY 8
1490#define ASC_EEP_ISA_PNP_WSIZE 16
1491
1492/*
1493 * These macros keep the chip SCSI id and ISA DMA speed
1494 * bitfields in board order. C bitfields aren't portable
1495 * between big and little-endian platforms so they are
1496 * not used.
1497 */
1498
1499#define ASC_EEP_GET_CHIP_ID(cfg) ((cfg)->id_speed & 0x0f)
1500#define ASC_EEP_GET_DMA_SPD(cfg) (((cfg)->id_speed & 0xf0) >> 4)
1501#define ASC_EEP_SET_CHIP_ID(cfg, sid) \
1502 ((cfg)->id_speed = ((cfg)->id_speed & 0xf0) | ((sid) & ASC_MAX_TID))
1503#define ASC_EEP_SET_DMA_SPD(cfg, spd) \
1504 ((cfg)->id_speed = ((cfg)->id_speed & 0x0f) | ((spd) & 0x0f) << 4)
1505
1506typedef struct asceep_config {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001507 ushort cfg_lsw;
1508 ushort cfg_msw;
1509 uchar init_sdtr;
1510 uchar disc_enable;
1511 uchar use_cmd_qng;
1512 uchar start_motor;
1513 uchar max_total_qng;
1514 uchar max_tag_qng;
1515 uchar bios_scan;
1516 uchar power_up_wait;
1517 uchar no_scam;
1518 uchar id_speed; /* low order 4 bits is chip scsi id */
1519 /* high order 4 bits is isa dma speed */
1520 uchar dos_int13_table[ASC_MAX_TID + 1];
1521 uchar adapter_info[6];
1522 ushort cntl;
1523 ushort chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524} ASCEEP_CONFIG;
1525
1526#define ASC_PCI_CFG_LSW_SCSI_PARITY 0x0800
1527#define ASC_PCI_CFG_LSW_BURST_MODE 0x0080
1528#define ASC_PCI_CFG_LSW_INTR_ABLE 0x0020
1529
1530#define ASC_EEP_CMD_READ 0x80
1531#define ASC_EEP_CMD_WRITE 0x40
1532#define ASC_EEP_CMD_WRITE_ABLE 0x30
1533#define ASC_EEP_CMD_WRITE_DISABLE 0x00
1534#define ASC_OVERRUN_BSIZE 0x00000048UL
1535#define ASC_CTRL_BREAK_ONCE 0x0001
1536#define ASC_CTRL_BREAK_STAY_IDLE 0x0002
1537#define ASCV_MSGOUT_BEG 0x0000
1538#define ASCV_MSGOUT_SDTR_PERIOD (ASCV_MSGOUT_BEG+3)
1539#define ASCV_MSGOUT_SDTR_OFFSET (ASCV_MSGOUT_BEG+4)
1540#define ASCV_BREAK_SAVED_CODE (ushort)0x0006
1541#define ASCV_MSGIN_BEG (ASCV_MSGOUT_BEG+8)
1542#define ASCV_MSGIN_SDTR_PERIOD (ASCV_MSGIN_BEG+3)
1543#define ASCV_MSGIN_SDTR_OFFSET (ASCV_MSGIN_BEG+4)
1544#define ASCV_SDTR_DATA_BEG (ASCV_MSGIN_BEG+8)
1545#define ASCV_SDTR_DONE_BEG (ASCV_SDTR_DATA_BEG+8)
1546#define ASCV_MAX_DVC_QNG_BEG (ushort)0x0020
1547#define ASCV_BREAK_ADDR (ushort)0x0028
1548#define ASCV_BREAK_NOTIFY_COUNT (ushort)0x002A
1549#define ASCV_BREAK_CONTROL (ushort)0x002C
1550#define ASCV_BREAK_HIT_COUNT (ushort)0x002E
1551
1552#define ASCV_ASCDVC_ERR_CODE_W (ushort)0x0030
1553#define ASCV_MCODE_CHKSUM_W (ushort)0x0032
1554#define ASCV_MCODE_SIZE_W (ushort)0x0034
1555#define ASCV_STOP_CODE_B (ushort)0x0036
1556#define ASCV_DVC_ERR_CODE_B (ushort)0x0037
1557#define ASCV_OVERRUN_PADDR_D (ushort)0x0038
1558#define ASCV_OVERRUN_BSIZE_D (ushort)0x003C
1559#define ASCV_HALTCODE_W (ushort)0x0040
1560#define ASCV_CHKSUM_W (ushort)0x0042
1561#define ASCV_MC_DATE_W (ushort)0x0044
1562#define ASCV_MC_VER_W (ushort)0x0046
1563#define ASCV_NEXTRDY_B (ushort)0x0048
1564#define ASCV_DONENEXT_B (ushort)0x0049
1565#define ASCV_USE_TAGGED_QNG_B (ushort)0x004A
1566#define ASCV_SCSIBUSY_B (ushort)0x004B
1567#define ASCV_Q_DONE_IN_PROGRESS_B (ushort)0x004C
1568#define ASCV_CURCDB_B (ushort)0x004D
1569#define ASCV_RCLUN_B (ushort)0x004E
1570#define ASCV_BUSY_QHEAD_B (ushort)0x004F
1571#define ASCV_DISC1_QHEAD_B (ushort)0x0050
1572#define ASCV_DISC_ENABLE_B (ushort)0x0052
1573#define ASCV_CAN_TAGGED_QNG_B (ushort)0x0053
1574#define ASCV_HOSTSCSI_ID_B (ushort)0x0055
1575#define ASCV_MCODE_CNTL_B (ushort)0x0056
1576#define ASCV_NULL_TARGET_B (ushort)0x0057
1577#define ASCV_FREE_Q_HEAD_W (ushort)0x0058
1578#define ASCV_DONE_Q_TAIL_W (ushort)0x005A
1579#define ASCV_FREE_Q_HEAD_B (ushort)(ASCV_FREE_Q_HEAD_W+1)
1580#define ASCV_DONE_Q_TAIL_B (ushort)(ASCV_DONE_Q_TAIL_W+1)
1581#define ASCV_HOST_FLAG_B (ushort)0x005D
1582#define ASCV_TOTAL_READY_Q_B (ushort)0x0064
1583#define ASCV_VER_SERIAL_B (ushort)0x0065
1584#define ASCV_HALTCODE_SAVED_W (ushort)0x0066
1585#define ASCV_WTM_FLAG_B (ushort)0x0068
1586#define ASCV_RISC_FLAG_B (ushort)0x006A
1587#define ASCV_REQ_SG_LIST_QP (ushort)0x006B
1588#define ASC_HOST_FLAG_IN_ISR 0x01
1589#define ASC_HOST_FLAG_ACK_INT 0x02
1590#define ASC_RISC_FLAG_GEN_INT 0x01
1591#define ASC_RISC_FLAG_REQ_SG_LIST 0x02
1592#define IOP_CTRL (0x0F)
1593#define IOP_STATUS (0x0E)
1594#define IOP_INT_ACK IOP_STATUS
1595#define IOP_REG_IFC (0x0D)
1596#define IOP_SYN_OFFSET (0x0B)
1597#define IOP_EXTRA_CONTROL (0x0D)
1598#define IOP_REG_PC (0x0C)
1599#define IOP_RAM_ADDR (0x0A)
1600#define IOP_RAM_DATA (0x08)
1601#define IOP_EEP_DATA (0x06)
1602#define IOP_EEP_CMD (0x07)
1603#define IOP_VERSION (0x03)
1604#define IOP_CONFIG_HIGH (0x04)
1605#define IOP_CONFIG_LOW (0x02)
1606#define IOP_SIG_BYTE (0x01)
1607#define IOP_SIG_WORD (0x00)
1608#define IOP_REG_DC1 (0x0E)
1609#define IOP_REG_DC0 (0x0C)
1610#define IOP_REG_SB (0x0B)
1611#define IOP_REG_DA1 (0x0A)
1612#define IOP_REG_DA0 (0x08)
1613#define IOP_REG_SC (0x09)
1614#define IOP_DMA_SPEED (0x07)
1615#define IOP_REG_FLAG (0x07)
1616#define IOP_FIFO_H (0x06)
1617#define IOP_FIFO_L (0x04)
1618#define IOP_REG_ID (0x05)
1619#define IOP_REG_QP (0x03)
1620#define IOP_REG_IH (0x02)
1621#define IOP_REG_IX (0x01)
1622#define IOP_REG_AX (0x00)
1623#define IFC_REG_LOCK (0x00)
1624#define IFC_REG_UNLOCK (0x09)
1625#define IFC_WR_EN_FILTER (0x10)
1626#define IFC_RD_NO_EEPROM (0x10)
1627#define IFC_SLEW_RATE (0x20)
1628#define IFC_ACT_NEG (0x40)
1629#define IFC_INP_FILTER (0x80)
1630#define IFC_INIT_DEFAULT (IFC_ACT_NEG | IFC_REG_UNLOCK)
1631#define SC_SEL (uchar)(0x80)
1632#define SC_BSY (uchar)(0x40)
1633#define SC_ACK (uchar)(0x20)
1634#define SC_REQ (uchar)(0x10)
1635#define SC_ATN (uchar)(0x08)
1636#define SC_IO (uchar)(0x04)
1637#define SC_CD (uchar)(0x02)
1638#define SC_MSG (uchar)(0x01)
1639#define SEC_SCSI_CTL (uchar)(0x80)
1640#define SEC_ACTIVE_NEGATE (uchar)(0x40)
1641#define SEC_SLEW_RATE (uchar)(0x20)
1642#define SEC_ENABLE_FILTER (uchar)(0x10)
1643#define ASC_HALT_EXTMSG_IN (ushort)0x8000
1644#define ASC_HALT_CHK_CONDITION (ushort)0x8100
1645#define ASC_HALT_SS_QUEUE_FULL (ushort)0x8200
1646#define ASC_HALT_DISABLE_ASYN_USE_SYN_FIX (ushort)0x8300
1647#define ASC_HALT_ENABLE_ASYN_USE_SYN_FIX (ushort)0x8400
1648#define ASC_HALT_SDTR_REJECTED (ushort)0x4000
1649#define ASC_HALT_HOST_COPY_SG_LIST_TO_RISC ( ushort )0x2000
1650#define ASC_MAX_QNO 0xF8
1651#define ASC_DATA_SEC_BEG (ushort)0x0080
1652#define ASC_DATA_SEC_END (ushort)0x0080
1653#define ASC_CODE_SEC_BEG (ushort)0x0080
1654#define ASC_CODE_SEC_END (ushort)0x0080
1655#define ASC_QADR_BEG (0x4000)
1656#define ASC_QADR_USED (ushort)(ASC_MAX_QNO * 64)
1657#define ASC_QADR_END (ushort)0x7FFF
1658#define ASC_QLAST_ADR (ushort)0x7FC0
1659#define ASC_QBLK_SIZE 0x40
1660#define ASC_BIOS_DATA_QBEG 0xF8
1661#define ASC_MIN_ACTIVE_QNO 0x01
1662#define ASC_QLINK_END 0xFF
1663#define ASC_EEPROM_WORDS 0x10
1664#define ASC_MAX_MGS_LEN 0x10
1665#define ASC_BIOS_ADDR_DEF 0xDC00
1666#define ASC_BIOS_SIZE 0x3800
1667#define ASC_BIOS_RAM_OFF 0x3800
1668#define ASC_BIOS_RAM_SIZE 0x800
1669#define ASC_BIOS_MIN_ADDR 0xC000
1670#define ASC_BIOS_MAX_ADDR 0xEC00
1671#define ASC_BIOS_BANK_SIZE 0x0400
1672#define ASC_MCODE_START_ADDR 0x0080
1673#define ASC_CFG0_HOST_INT_ON 0x0020
1674#define ASC_CFG0_BIOS_ON 0x0040
1675#define ASC_CFG0_VERA_BURST_ON 0x0080
1676#define ASC_CFG0_SCSI_PARITY_ON 0x0800
1677#define ASC_CFG1_SCSI_TARGET_ON 0x0080
1678#define ASC_CFG1_LRAM_8BITS_ON 0x0800
1679#define ASC_CFG_MSW_CLR_MASK 0x3080
1680#define CSW_TEST1 (ASC_CS_TYPE)0x8000
1681#define CSW_AUTO_CONFIG (ASC_CS_TYPE)0x4000
1682#define CSW_RESERVED1 (ASC_CS_TYPE)0x2000
1683#define CSW_IRQ_WRITTEN (ASC_CS_TYPE)0x1000
1684#define CSW_33MHZ_SELECTED (ASC_CS_TYPE)0x0800
1685#define CSW_TEST2 (ASC_CS_TYPE)0x0400
1686#define CSW_TEST3 (ASC_CS_TYPE)0x0200
1687#define CSW_RESERVED2 (ASC_CS_TYPE)0x0100
1688#define CSW_DMA_DONE (ASC_CS_TYPE)0x0080
1689#define CSW_FIFO_RDY (ASC_CS_TYPE)0x0040
1690#define CSW_EEP_READ_DONE (ASC_CS_TYPE)0x0020
1691#define CSW_HALTED (ASC_CS_TYPE)0x0010
1692#define CSW_SCSI_RESET_ACTIVE (ASC_CS_TYPE)0x0008
1693#define CSW_PARITY_ERR (ASC_CS_TYPE)0x0004
1694#define CSW_SCSI_RESET_LATCH (ASC_CS_TYPE)0x0002
1695#define CSW_INT_PENDING (ASC_CS_TYPE)0x0001
1696#define CIW_CLR_SCSI_RESET_INT (ASC_CS_TYPE)0x1000
1697#define CIW_INT_ACK (ASC_CS_TYPE)0x0100
1698#define CIW_TEST1 (ASC_CS_TYPE)0x0200
1699#define CIW_TEST2 (ASC_CS_TYPE)0x0400
1700#define CIW_SEL_33MHZ (ASC_CS_TYPE)0x0800
1701#define CIW_IRQ_ACT (ASC_CS_TYPE)0x1000
1702#define CC_CHIP_RESET (uchar)0x80
1703#define CC_SCSI_RESET (uchar)0x40
1704#define CC_HALT (uchar)0x20
1705#define CC_SINGLE_STEP (uchar)0x10
1706#define CC_DMA_ABLE (uchar)0x08
1707#define CC_TEST (uchar)0x04
1708#define CC_BANK_ONE (uchar)0x02
1709#define CC_DIAG (uchar)0x01
1710#define ASC_1000_ID0W 0x04C1
1711#define ASC_1000_ID0W_FIX 0x00C1
1712#define ASC_1000_ID1B 0x25
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713#define ASC_EISA_REV_IOP_MASK (0x0C83)
1714#define ASC_EISA_PID_IOP_MASK (0x0C80)
1715#define ASC_EISA_CFG_IOP_MASK (0x0C86)
1716#define ASC_GET_EISA_SLOT(iop) (PortAddr)((iop) & 0xF000)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717#define INS_HALTINT (ushort)0x6281
1718#define INS_HALT (ushort)0x6280
1719#define INS_SINT (ushort)0x6200
1720#define INS_RFLAG_WTM (ushort)0x7380
1721#define ASC_MC_SAVE_CODE_WSIZE 0x500
1722#define ASC_MC_SAVE_DATA_WSIZE 0x40
1723
1724typedef struct asc_mc_saved {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001725 ushort data[ASC_MC_SAVE_DATA_WSIZE];
1726 ushort code[ASC_MC_SAVE_CODE_WSIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727} ASC_MC_SAVED;
1728
1729#define AscGetQDoneInProgress(port) AscReadLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B)
1730#define AscPutQDoneInProgress(port, val) AscWriteLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B, val)
1731#define AscGetVarFreeQHead(port) AscReadLramWord((port), ASCV_FREE_Q_HEAD_W)
1732#define AscGetVarDoneQTail(port) AscReadLramWord((port), ASCV_DONE_Q_TAIL_W)
1733#define AscPutVarFreeQHead(port, val) AscWriteLramWord((port), ASCV_FREE_Q_HEAD_W, val)
1734#define AscPutVarDoneQTail(port, val) AscWriteLramWord((port), ASCV_DONE_Q_TAIL_W, val)
1735#define AscGetRiscVarFreeQHead(port) AscReadLramByte((port), ASCV_NEXTRDY_B)
1736#define AscGetRiscVarDoneQTail(port) AscReadLramByte((port), ASCV_DONENEXT_B)
1737#define AscPutRiscVarFreeQHead(port, val) AscWriteLramByte((port), ASCV_NEXTRDY_B, val)
1738#define AscPutRiscVarDoneQTail(port, val) AscWriteLramByte((port), ASCV_DONENEXT_B, val)
1739#define AscPutMCodeSDTRDoneAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id), (data));
1740#define AscGetMCodeSDTRDoneAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id));
1741#define AscPutMCodeInitSDTRAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id), data);
1742#define AscGetMCodeInitSDTRAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id));
1743#define AscSynIndexToPeriod(index) (uchar)(asc_dvc->sdtr_period_tbl[ (index) ])
1744#define AscGetChipSignatureByte(port) (uchar)inp((port)+IOP_SIG_BYTE)
1745#define AscGetChipSignatureWord(port) (ushort)inpw((port)+IOP_SIG_WORD)
1746#define AscGetChipVerNo(port) (uchar)inp((port)+IOP_VERSION)
1747#define AscGetChipCfgLsw(port) (ushort)inpw((port)+IOP_CONFIG_LOW)
1748#define AscGetChipCfgMsw(port) (ushort)inpw((port)+IOP_CONFIG_HIGH)
1749#define AscSetChipCfgLsw(port, data) outpw((port)+IOP_CONFIG_LOW, data)
1750#define AscSetChipCfgMsw(port, data) outpw((port)+IOP_CONFIG_HIGH, data)
1751#define AscGetChipEEPCmd(port) (uchar)inp((port)+IOP_EEP_CMD)
1752#define AscSetChipEEPCmd(port, data) outp((port)+IOP_EEP_CMD, data)
1753#define AscGetChipEEPData(port) (ushort)inpw((port)+IOP_EEP_DATA)
1754#define AscSetChipEEPData(port, data) outpw((port)+IOP_EEP_DATA, data)
1755#define AscGetChipLramAddr(port) (ushort)inpw((PortAddr)((port)+IOP_RAM_ADDR))
1756#define AscSetChipLramAddr(port, addr) outpw((PortAddr)((port)+IOP_RAM_ADDR), addr)
1757#define AscGetChipLramData(port) (ushort)inpw((port)+IOP_RAM_DATA)
1758#define AscSetChipLramData(port, data) outpw((port)+IOP_RAM_DATA, data)
1759#define AscGetChipIFC(port) (uchar)inp((port)+IOP_REG_IFC)
1760#define AscSetChipIFC(port, data) outp((port)+IOP_REG_IFC, data)
1761#define AscGetChipStatus(port) (ASC_CS_TYPE)inpw((port)+IOP_STATUS)
1762#define AscSetChipStatus(port, cs_val) outpw((port)+IOP_STATUS, cs_val)
1763#define AscGetChipControl(port) (uchar)inp((port)+IOP_CTRL)
1764#define AscSetChipControl(port, cc_val) outp((port)+IOP_CTRL, cc_val)
1765#define AscGetChipSyn(port) (uchar)inp((port)+IOP_SYN_OFFSET)
1766#define AscSetChipSyn(port, data) outp((port)+IOP_SYN_OFFSET, data)
1767#define AscSetPCAddr(port, data) outpw((port)+IOP_REG_PC, data)
1768#define AscGetPCAddr(port) (ushort)inpw((port)+IOP_REG_PC)
1769#define AscIsIntPending(port) (AscGetChipStatus(port) & (CSW_INT_PENDING | CSW_SCSI_RESET_LATCH))
1770#define AscGetChipScsiID(port) ((AscGetChipCfgLsw(port) >> 8) & ASC_MAX_TID)
1771#define AscGetExtraControl(port) (uchar)inp((port)+IOP_EXTRA_CONTROL)
1772#define AscSetExtraControl(port, data) outp((port)+IOP_EXTRA_CONTROL, data)
1773#define AscReadChipAX(port) (ushort)inpw((port)+IOP_REG_AX)
1774#define AscWriteChipAX(port, data) outpw((port)+IOP_REG_AX, data)
1775#define AscReadChipIX(port) (uchar)inp((port)+IOP_REG_IX)
1776#define AscWriteChipIX(port, data) outp((port)+IOP_REG_IX, data)
1777#define AscReadChipIH(port) (ushort)inpw((port)+IOP_REG_IH)
1778#define AscWriteChipIH(port, data) outpw((port)+IOP_REG_IH, data)
1779#define AscReadChipQP(port) (uchar)inp((port)+IOP_REG_QP)
1780#define AscWriteChipQP(port, data) outp((port)+IOP_REG_QP, data)
1781#define AscReadChipFIFO_L(port) (ushort)inpw((port)+IOP_REG_FIFO_L)
1782#define AscWriteChipFIFO_L(port, data) outpw((port)+IOP_REG_FIFO_L, data)
1783#define AscReadChipFIFO_H(port) (ushort)inpw((port)+IOP_REG_FIFO_H)
1784#define AscWriteChipFIFO_H(port, data) outpw((port)+IOP_REG_FIFO_H, data)
1785#define AscReadChipDmaSpeed(port) (uchar)inp((port)+IOP_DMA_SPEED)
1786#define AscWriteChipDmaSpeed(port, data) outp((port)+IOP_DMA_SPEED, data)
1787#define AscReadChipDA0(port) (ushort)inpw((port)+IOP_REG_DA0)
1788#define AscWriteChipDA0(port) outpw((port)+IOP_REG_DA0, data)
1789#define AscReadChipDA1(port) (ushort)inpw((port)+IOP_REG_DA1)
1790#define AscWriteChipDA1(port) outpw((port)+IOP_REG_DA1, data)
1791#define AscReadChipDC0(port) (ushort)inpw((port)+IOP_REG_DC0)
1792#define AscWriteChipDC0(port) outpw((port)+IOP_REG_DC0, data)
1793#define AscReadChipDC1(port) (ushort)inpw((port)+IOP_REG_DC1)
1794#define AscWriteChipDC1(port) outpw((port)+IOP_REG_DC1, data)
1795#define AscReadChipDvcID(port) (uchar)inp((port)+IOP_REG_ID)
1796#define AscWriteChipDvcID(port, data) outp((port)+IOP_REG_ID, data)
1797
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001798static int AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg);
1799static int AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg);
1800static void AscWaitEEPRead(void);
1801static void AscWaitEEPWrite(void);
1802static ushort AscReadEEPWord(PortAddr, uchar);
1803static ushort AscWriteEEPWord(PortAddr, uchar, ushort);
1804static ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
1805static int AscSetEEPConfigOnce(PortAddr, ASCEEP_CONFIG *, ushort);
1806static int AscSetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
1807static int AscStartChip(PortAddr);
1808static int AscStopChip(PortAddr);
1809static void AscSetChipIH(PortAddr, ushort);
1810static int AscIsChipHalted(PortAddr);
1811static void AscAckInterrupt(PortAddr);
1812static void AscDisableInterrupt(PortAddr);
1813static void AscEnableInterrupt(PortAddr);
1814static void AscSetBank(PortAddr, uchar);
1815static int AscResetChipAndScsiBus(ASC_DVC_VAR *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001817static uchar AscGetIsaDmaSpeed(PortAddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001819static uchar AscReadLramByte(PortAddr, ushort);
1820static ushort AscReadLramWord(PortAddr, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001822static ASC_DCNT AscReadLramDWord(PortAddr, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001824static void AscWriteLramWord(PortAddr, ushort, ushort);
1825static void AscWriteLramByte(PortAddr, ushort, uchar);
1826static ASC_DCNT AscMemSumLramWord(PortAddr, ushort, int);
1827static void AscMemWordSetLram(PortAddr, ushort, ushort, int);
1828static void AscMemWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
1829static void AscMemDWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
1830static void AscMemWordCopyPtrFromLram(PortAddr, ushort, uchar *, int);
1831static ushort AscInitAscDvcVar(ASC_DVC_VAR *);
1832static ushort AscInitFromEEP(ASC_DVC_VAR *);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001833static ushort AscInitMicroCodeVar(ASC_DVC_VAR *);
1834static int AscTestExternalLram(ASC_DVC_VAR *);
1835static uchar AscMsgOutSDTR(ASC_DVC_VAR *, uchar, uchar);
1836static uchar AscCalSDTRData(ASC_DVC_VAR *, uchar, uchar);
1837static void AscSetChipSDTR(PortAddr, uchar, uchar);
1838static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *, uchar);
1839static uchar AscAllocFreeQueue(PortAddr, uchar);
1840static uchar AscAllocMultipleFreeQueue(PortAddr, uchar, uchar);
1841static int AscHostReqRiscHalt(PortAddr);
1842static int AscStopQueueExe(PortAddr);
1843static int AscSendScsiQueue(ASC_DVC_VAR *,
1844 ASC_SCSI_Q *scsiq, uchar n_q_required);
1845static int AscPutReadyQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
1846static int AscPutReadySgListQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
1847static int AscSetChipSynRegAtID(PortAddr, uchar, uchar);
1848static int AscSetRunChipSynRegAtID(PortAddr, uchar, uchar);
1849static ushort AscInitLram(ASC_DVC_VAR *);
1850static ushort AscInitQLinkVar(ASC_DVC_VAR *);
1851static int AscSetLibErrorCode(ASC_DVC_VAR *, ushort);
1852static int AscIsrChipHalted(ASC_DVC_VAR *);
1853static uchar _AscCopyLramScsiDoneQ(PortAddr, ushort,
1854 ASC_QDONE_INFO *, ASC_DCNT);
1855static int AscIsrQDone(ASC_DVC_VAR *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001857static ushort AscGetEisaChipCfg(PortAddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001859static uchar AscGetChipScsiCtrl(PortAddr);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001860static uchar AscGetChipVersion(PortAddr, ushort);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001861static ASC_DCNT AscLoadMicroCode(PortAddr, ushort, uchar *, ushort);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001862static void AscToggleIRQAct(PortAddr);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001863static inline ulong DvcEnterCritical(void);
1864static inline void DvcLeaveCritical(ulong);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001865static void DvcSleepMilliSecond(ASC_DCNT);
1866static void DvcDelayNanoSecond(ASC_DVC_VAR *, ASC_DCNT);
1867static void DvcPutScsiQ(PortAddr, ushort, uchar *, int);
1868static void DvcGetQinfo(PortAddr, ushort, uchar *, int);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001869static ushort AscInitAsc1000Driver(ASC_DVC_VAR *);
Matthew Wilcox47d853c2007-07-26 11:41:33 -04001870static void AscAsyncFix(ASC_DVC_VAR *, struct scsi_device *);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001871static int AscExeScsiQueue(ASC_DVC_VAR *, ASC_SCSI_Q *);
1872static int AscISR(ASC_DVC_VAR *);
1873static uint AscGetNumOfFreeQueue(ASC_DVC_VAR *, uchar, uchar);
1874static int AscSgListToQueue(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001876static void AscEnableIsaDma(uchar);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001878static const char *advansys_info(struct Scsi_Host *shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879
1880/*
1881 * --- Adv Library Constants and Macros
1882 */
1883
1884#define ADV_LIB_VERSION_MAJOR 5
1885#define ADV_LIB_VERSION_MINOR 14
1886
1887/*
1888 * Define Adv Library required special types.
1889 */
1890
1891/*
1892 * Portable Data Types
1893 *
1894 * Any instance where a 32-bit long or pointer type is assumed
1895 * for precision or HW defined structures, the following define
1896 * types must be used. In Linux the char, short, and int types
1897 * are all consistent at 8, 16, and 32 bits respectively. Pointers
1898 * and long types are 64 bits on Alpha and UltraSPARC.
1899 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001900#define ADV_PADDR __u32 /* Physical address data type. */
1901#define ADV_VADDR __u32 /* Virtual address data type. */
1902#define ADV_DCNT __u32 /* Unsigned Data count type. */
1903#define ADV_SDCNT __s32 /* Signed Data count type. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904
1905/*
1906 * These macros are used to convert a virtual address to a
1907 * 32-bit value. This currently can be used on Linux Alpha
1908 * which uses 64-bit virtual address but a 32-bit bus address.
1909 * This is likely to break in the future, but doing this now
1910 * will give us time to change the HW and FW to handle 64-bit
1911 * addresses.
1912 */
1913#define ADV_VADDR_TO_U32 virt_to_bus
1914#define ADV_U32_TO_VADDR bus_to_virt
1915
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001916#define AdvPortAddr void __iomem * /* Virtual memory address size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917
1918/*
1919 * Define Adv Library required memory access macros.
1920 */
1921#define ADV_MEM_READB(addr) readb(addr)
1922#define ADV_MEM_READW(addr) readw(addr)
1923#define ADV_MEM_WRITEB(addr, byte) writeb(byte, addr)
1924#define ADV_MEM_WRITEW(addr, word) writew(word, addr)
1925#define ADV_MEM_WRITEDW(addr, dword) writel(dword, addr)
1926
1927#define ADV_CARRIER_COUNT (ASC_DEF_MAX_HOST_QNG + 15)
1928
1929/*
1930 * For wide boards a CDB length maximum of 16 bytes
1931 * is supported.
1932 */
1933#define ADV_MAX_CDB_LEN 16
1934
1935/*
1936 * Define total number of simultaneous maximum element scatter-gather
1937 * request blocks per wide adapter. ASC_DEF_MAX_HOST_QNG (253) is the
1938 * maximum number of outstanding commands per wide host adapter. Each
1939 * command uses one or more ADV_SG_BLOCK each with 15 scatter-gather
1940 * elements. Allow each command to have at least one ADV_SG_BLOCK structure.
1941 * This allows about 15 commands to have the maximum 17 ADV_SG_BLOCK
1942 * structures or 255 scatter-gather elements.
1943 *
1944 */
1945#define ADV_TOT_SG_BLOCK ASC_DEF_MAX_HOST_QNG
1946
1947/*
1948 * Define Adv Library required maximum number of scatter-gather
1949 * elements per request.
1950 */
1951#define ADV_MAX_SG_LIST 255
1952
1953/* Number of SG blocks needed. */
1954#define ADV_NUM_SG_BLOCK \
1955 ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)
1956
1957/* Total contiguous memory needed for SG blocks. */
1958#define ADV_SG_TOTAL_MEM_SIZE \
1959 (sizeof(ADV_SG_BLOCK) * ADV_NUM_SG_BLOCK)
1960
1961#define ADV_PAGE_SIZE PAGE_SIZE
1962
1963#define ADV_NUM_PAGE_CROSSING \
1964 ((ADV_SG_TOTAL_MEM_SIZE + (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
1965
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966#define ADV_EEP_DVC_CFG_BEGIN (0x00)
1967#define ADV_EEP_DVC_CFG_END (0x15)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001968#define ADV_EEP_DVC_CTL_BEGIN (0x16) /* location of OEM name */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969#define ADV_EEP_MAX_WORD_ADDR (0x1E)
1970
1971#define ADV_EEP_DELAY_MS 100
1972
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001973#define ADV_EEPROM_BIG_ENDIAN 0x8000 /* EEPROM Bit 15 */
1974#define ADV_EEPROM_BIOS_ENABLE 0x4000 /* EEPROM Bit 14 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975/*
1976 * For the ASC3550 Bit 13 is Termination Polarity control bit.
1977 * For later ICs Bit 13 controls whether the CIS (Card Information
1978 * Service Section) is loaded from EEPROM.
1979 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001980#define ADV_EEPROM_TERM_POL 0x2000 /* EEPROM Bit 13 */
1981#define ADV_EEPROM_CIS_LD 0x2000 /* EEPROM Bit 13 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982/*
1983 * ASC38C1600 Bit 11
1984 *
1985 * If EEPROM Bit 11 is 0 for Function 0, then Function 0 will specify
1986 * INT A in the PCI Configuration Space Int Pin field. If it is 1, then
1987 * Function 0 will specify INT B.
1988 *
1989 * If EEPROM Bit 11 is 0 for Function 1, then Function 1 will specify
1990 * INT B in the PCI Configuration Space Int Pin field. If it is 1, then
1991 * Function 1 will specify INT A.
1992 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001993#define ADV_EEPROM_INTAB 0x0800 /* EEPROM Bit 11 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001995typedef struct adveep_3550_config {
1996 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001998 ushort cfg_lsw; /* 00 power up initialization */
1999 /* bit 13 set - Term Polarity Control */
2000 /* bit 14 set - BIOS Enable */
2001 /* bit 15 set - Big Endian Mode */
2002 ushort cfg_msw; /* 01 unused */
2003 ushort disc_enable; /* 02 disconnect enable */
2004 ushort wdtr_able; /* 03 Wide DTR able */
2005 ushort sdtr_able; /* 04 Synchronous DTR able */
2006 ushort start_motor; /* 05 send start up motor */
2007 ushort tagqng_able; /* 06 tag queuing able */
2008 ushort bios_scan; /* 07 BIOS device control */
2009 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002011 uchar adapter_scsi_id; /* 09 Host Adapter ID */
2012 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002014 uchar scsi_reset_delay; /* 10 reset delay */
2015 uchar bios_id_lun; /* first boot device scsi id & lun */
2016 /* high nibble is lun */
2017 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002019 uchar termination; /* 11 0 - automatic */
2020 /* 1 - low off / high off */
2021 /* 2 - low off / high on */
2022 /* 3 - low on / high on */
2023 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002025 uchar reserved1; /* reserved byte (not used) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002027 ushort bios_ctrl; /* 12 BIOS control bits */
2028 /* bit 0 BIOS don't act as initiator. */
2029 /* bit 1 BIOS > 1 GB support */
2030 /* bit 2 BIOS > 2 Disk Support */
2031 /* bit 3 BIOS don't support removables */
2032 /* bit 4 BIOS support bootable CD */
2033 /* bit 5 BIOS scan enabled */
2034 /* bit 6 BIOS support multiple LUNs */
2035 /* bit 7 BIOS display of message */
2036 /* bit 8 SCAM disabled */
2037 /* bit 9 Reset SCSI bus during init. */
2038 /* bit 10 */
2039 /* bit 11 No verbose initialization. */
2040 /* bit 12 SCSI parity enabled */
2041 /* bit 13 */
2042 /* bit 14 */
2043 /* bit 15 */
2044 ushort ultra_able; /* 13 ULTRA speed able */
2045 ushort reserved2; /* 14 reserved */
2046 uchar max_host_qng; /* 15 maximum host queuing */
2047 uchar max_dvc_qng; /* maximum per device queuing */
2048 ushort dvc_cntl; /* 16 control bit for driver */
2049 ushort bug_fix; /* 17 control bit for bug fix */
2050 ushort serial_number_word1; /* 18 Board serial number word 1 */
2051 ushort serial_number_word2; /* 19 Board serial number word 2 */
2052 ushort serial_number_word3; /* 20 Board serial number word 3 */
2053 ushort check_sum; /* 21 EEP check sum */
2054 uchar oem_name[16]; /* 22 OEM name */
2055 ushort dvc_err_code; /* 30 last device driver error code */
2056 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
2057 ushort adv_err_addr; /* 32 last uc error address */
2058 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
2059 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
2060 ushort saved_adv_err_addr; /* 35 saved last uc error address */
2061 ushort num_of_err; /* 36 number of error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062} ADVEEP_3550_CONFIG;
2063
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002064typedef struct adveep_38C0800_config {
2065 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002067 ushort cfg_lsw; /* 00 power up initialization */
2068 /* bit 13 set - Load CIS */
2069 /* bit 14 set - BIOS Enable */
2070 /* bit 15 set - Big Endian Mode */
2071 ushort cfg_msw; /* 01 unused */
2072 ushort disc_enable; /* 02 disconnect enable */
2073 ushort wdtr_able; /* 03 Wide DTR able */
2074 ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
2075 ushort start_motor; /* 05 send start up motor */
2076 ushort tagqng_able; /* 06 tag queuing able */
2077 ushort bios_scan; /* 07 BIOS device control */
2078 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002080 uchar adapter_scsi_id; /* 09 Host Adapter ID */
2081 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002083 uchar scsi_reset_delay; /* 10 reset delay */
2084 uchar bios_id_lun; /* first boot device scsi id & lun */
2085 /* high nibble is lun */
2086 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002088 uchar termination_se; /* 11 0 - automatic */
2089 /* 1 - low off / high off */
2090 /* 2 - low off / high on */
2091 /* 3 - low on / high on */
2092 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002094 uchar termination_lvd; /* 11 0 - automatic */
2095 /* 1 - low off / high off */
2096 /* 2 - low off / high on */
2097 /* 3 - low on / high on */
2098 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002100 ushort bios_ctrl; /* 12 BIOS control bits */
2101 /* bit 0 BIOS don't act as initiator. */
2102 /* bit 1 BIOS > 1 GB support */
2103 /* bit 2 BIOS > 2 Disk Support */
2104 /* bit 3 BIOS don't support removables */
2105 /* bit 4 BIOS support bootable CD */
2106 /* bit 5 BIOS scan enabled */
2107 /* bit 6 BIOS support multiple LUNs */
2108 /* bit 7 BIOS display of message */
2109 /* bit 8 SCAM disabled */
2110 /* bit 9 Reset SCSI bus during init. */
2111 /* bit 10 */
2112 /* bit 11 No verbose initialization. */
2113 /* bit 12 SCSI parity enabled */
2114 /* bit 13 */
2115 /* bit 14 */
2116 /* bit 15 */
2117 ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
2118 ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
2119 uchar max_host_qng; /* 15 maximum host queueing */
2120 uchar max_dvc_qng; /* maximum per device queuing */
2121 ushort dvc_cntl; /* 16 control bit for driver */
2122 ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
2123 ushort serial_number_word1; /* 18 Board serial number word 1 */
2124 ushort serial_number_word2; /* 19 Board serial number word 2 */
2125 ushort serial_number_word3; /* 20 Board serial number word 3 */
2126 ushort check_sum; /* 21 EEP check sum */
2127 uchar oem_name[16]; /* 22 OEM name */
2128 ushort dvc_err_code; /* 30 last device driver error code */
2129 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
2130 ushort adv_err_addr; /* 32 last uc error address */
2131 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
2132 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
2133 ushort saved_adv_err_addr; /* 35 saved last uc error address */
2134 ushort reserved36; /* 36 reserved */
2135 ushort reserved37; /* 37 reserved */
2136 ushort reserved38; /* 38 reserved */
2137 ushort reserved39; /* 39 reserved */
2138 ushort reserved40; /* 40 reserved */
2139 ushort reserved41; /* 41 reserved */
2140 ushort reserved42; /* 42 reserved */
2141 ushort reserved43; /* 43 reserved */
2142 ushort reserved44; /* 44 reserved */
2143 ushort reserved45; /* 45 reserved */
2144 ushort reserved46; /* 46 reserved */
2145 ushort reserved47; /* 47 reserved */
2146 ushort reserved48; /* 48 reserved */
2147 ushort reserved49; /* 49 reserved */
2148 ushort reserved50; /* 50 reserved */
2149 ushort reserved51; /* 51 reserved */
2150 ushort reserved52; /* 52 reserved */
2151 ushort reserved53; /* 53 reserved */
2152 ushort reserved54; /* 54 reserved */
2153 ushort reserved55; /* 55 reserved */
2154 ushort cisptr_lsw; /* 56 CIS PTR LSW */
2155 ushort cisprt_msw; /* 57 CIS PTR MSW */
2156 ushort subsysvid; /* 58 SubSystem Vendor ID */
2157 ushort subsysid; /* 59 SubSystem ID */
2158 ushort reserved60; /* 60 reserved */
2159 ushort reserved61; /* 61 reserved */
2160 ushort reserved62; /* 62 reserved */
2161 ushort reserved63; /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162} ADVEEP_38C0800_CONFIG;
2163
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002164typedef struct adveep_38C1600_config {
2165 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002167 ushort cfg_lsw; /* 00 power up initialization */
2168 /* bit 11 set - Func. 0 INTB, Func. 1 INTA */
2169 /* clear - Func. 0 INTA, Func. 1 INTB */
2170 /* bit 13 set - Load CIS */
2171 /* bit 14 set - BIOS Enable */
2172 /* bit 15 set - Big Endian Mode */
2173 ushort cfg_msw; /* 01 unused */
2174 ushort disc_enable; /* 02 disconnect enable */
2175 ushort wdtr_able; /* 03 Wide DTR able */
2176 ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
2177 ushort start_motor; /* 05 send start up motor */
2178 ushort tagqng_able; /* 06 tag queuing able */
2179 ushort bios_scan; /* 07 BIOS device control */
2180 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002182 uchar adapter_scsi_id; /* 09 Host Adapter ID */
2183 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002185 uchar scsi_reset_delay; /* 10 reset delay */
2186 uchar bios_id_lun; /* first boot device scsi id & lun */
2187 /* high nibble is lun */
2188 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002190 uchar termination_se; /* 11 0 - automatic */
2191 /* 1 - low off / high off */
2192 /* 2 - low off / high on */
2193 /* 3 - low on / high on */
2194 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002196 uchar termination_lvd; /* 11 0 - automatic */
2197 /* 1 - low off / high off */
2198 /* 2 - low off / high on */
2199 /* 3 - low on / high on */
2200 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002202 ushort bios_ctrl; /* 12 BIOS control bits */
2203 /* bit 0 BIOS don't act as initiator. */
2204 /* bit 1 BIOS > 1 GB support */
2205 /* bit 2 BIOS > 2 Disk Support */
2206 /* bit 3 BIOS don't support removables */
2207 /* bit 4 BIOS support bootable CD */
2208 /* bit 5 BIOS scan enabled */
2209 /* bit 6 BIOS support multiple LUNs */
2210 /* bit 7 BIOS display of message */
2211 /* bit 8 SCAM disabled */
2212 /* bit 9 Reset SCSI bus during init. */
2213 /* bit 10 Basic Integrity Checking disabled */
2214 /* bit 11 No verbose initialization. */
2215 /* bit 12 SCSI parity enabled */
2216 /* bit 13 AIPP (Asyn. Info. Ph. Prot.) dis. */
2217 /* bit 14 */
2218 /* bit 15 */
2219 ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
2220 ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
2221 uchar max_host_qng; /* 15 maximum host queueing */
2222 uchar max_dvc_qng; /* maximum per device queuing */
2223 ushort dvc_cntl; /* 16 control bit for driver */
2224 ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
2225 ushort serial_number_word1; /* 18 Board serial number word 1 */
2226 ushort serial_number_word2; /* 19 Board serial number word 2 */
2227 ushort serial_number_word3; /* 20 Board serial number word 3 */
2228 ushort check_sum; /* 21 EEP check sum */
2229 uchar oem_name[16]; /* 22 OEM name */
2230 ushort dvc_err_code; /* 30 last device driver error code */
2231 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
2232 ushort adv_err_addr; /* 32 last uc error address */
2233 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
2234 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
2235 ushort saved_adv_err_addr; /* 35 saved last uc error address */
2236 ushort reserved36; /* 36 reserved */
2237 ushort reserved37; /* 37 reserved */
2238 ushort reserved38; /* 38 reserved */
2239 ushort reserved39; /* 39 reserved */
2240 ushort reserved40; /* 40 reserved */
2241 ushort reserved41; /* 41 reserved */
2242 ushort reserved42; /* 42 reserved */
2243 ushort reserved43; /* 43 reserved */
2244 ushort reserved44; /* 44 reserved */
2245 ushort reserved45; /* 45 reserved */
2246 ushort reserved46; /* 46 reserved */
2247 ushort reserved47; /* 47 reserved */
2248 ushort reserved48; /* 48 reserved */
2249 ushort reserved49; /* 49 reserved */
2250 ushort reserved50; /* 50 reserved */
2251 ushort reserved51; /* 51 reserved */
2252 ushort reserved52; /* 52 reserved */
2253 ushort reserved53; /* 53 reserved */
2254 ushort reserved54; /* 54 reserved */
2255 ushort reserved55; /* 55 reserved */
2256 ushort cisptr_lsw; /* 56 CIS PTR LSW */
2257 ushort cisprt_msw; /* 57 CIS PTR MSW */
2258 ushort subsysvid; /* 58 SubSystem Vendor ID */
2259 ushort subsysid; /* 59 SubSystem ID */
2260 ushort reserved60; /* 60 reserved */
2261 ushort reserved61; /* 61 reserved */
2262 ushort reserved62; /* 62 reserved */
2263 ushort reserved63; /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264} ADVEEP_38C1600_CONFIG;
2265
2266/*
2267 * EEPROM Commands
2268 */
2269#define ASC_EEP_CMD_DONE 0x0200
2270#define ASC_EEP_CMD_DONE_ERR 0x0001
2271
2272/* cfg_word */
2273#define EEP_CFG_WORD_BIG_ENDIAN 0x8000
2274
2275/* bios_ctrl */
2276#define BIOS_CTRL_BIOS 0x0001
2277#define BIOS_CTRL_EXTENDED_XLAT 0x0002
2278#define BIOS_CTRL_GT_2_DISK 0x0004
2279#define BIOS_CTRL_BIOS_REMOVABLE 0x0008
2280#define BIOS_CTRL_BOOTABLE_CD 0x0010
2281#define BIOS_CTRL_MULTIPLE_LUN 0x0040
2282#define BIOS_CTRL_DISPLAY_MSG 0x0080
2283#define BIOS_CTRL_NO_SCAM 0x0100
2284#define BIOS_CTRL_RESET_SCSI_BUS 0x0200
2285#define BIOS_CTRL_INIT_VERBOSE 0x0800
2286#define BIOS_CTRL_SCSI_PARITY 0x1000
2287#define BIOS_CTRL_AIPP_DIS 0x2000
2288
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002289#define ADV_3550_MEMSIZE 0x2000 /* 8 KB Internal Memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002291#define ADV_38C0800_MEMSIZE 0x4000 /* 16 KB Internal Memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292
2293/*
2294 * XXX - Since ASC38C1600 Rev.3 has a local RAM failure issue, there is
2295 * a special 16K Adv Library and Microcode version. After the issue is
2296 * resolved, should restore 32K support.
2297 *
2298 * #define ADV_38C1600_MEMSIZE 0x8000L * 32 KB Internal Memory *
2299 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002300#define ADV_38C1600_MEMSIZE 0x4000 /* 16 KB Internal Memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301
2302/*
2303 * Byte I/O register address from base of 'iop_base'.
2304 */
2305#define IOPB_INTR_STATUS_REG 0x00
2306#define IOPB_CHIP_ID_1 0x01
2307#define IOPB_INTR_ENABLES 0x02
2308#define IOPB_CHIP_TYPE_REV 0x03
2309#define IOPB_RES_ADDR_4 0x04
2310#define IOPB_RES_ADDR_5 0x05
2311#define IOPB_RAM_DATA 0x06
2312#define IOPB_RES_ADDR_7 0x07
2313#define IOPB_FLAG_REG 0x08
2314#define IOPB_RES_ADDR_9 0x09
2315#define IOPB_RISC_CSR 0x0A
2316#define IOPB_RES_ADDR_B 0x0B
2317#define IOPB_RES_ADDR_C 0x0C
2318#define IOPB_RES_ADDR_D 0x0D
2319#define IOPB_SOFT_OVER_WR 0x0E
2320#define IOPB_RES_ADDR_F 0x0F
2321#define IOPB_MEM_CFG 0x10
2322#define IOPB_RES_ADDR_11 0x11
2323#define IOPB_GPIO_DATA 0x12
2324#define IOPB_RES_ADDR_13 0x13
2325#define IOPB_FLASH_PAGE 0x14
2326#define IOPB_RES_ADDR_15 0x15
2327#define IOPB_GPIO_CNTL 0x16
2328#define IOPB_RES_ADDR_17 0x17
2329#define IOPB_FLASH_DATA 0x18
2330#define IOPB_RES_ADDR_19 0x19
2331#define IOPB_RES_ADDR_1A 0x1A
2332#define IOPB_RES_ADDR_1B 0x1B
2333#define IOPB_RES_ADDR_1C 0x1C
2334#define IOPB_RES_ADDR_1D 0x1D
2335#define IOPB_RES_ADDR_1E 0x1E
2336#define IOPB_RES_ADDR_1F 0x1F
2337#define IOPB_DMA_CFG0 0x20
2338#define IOPB_DMA_CFG1 0x21
2339#define IOPB_TICKLE 0x22
2340#define IOPB_DMA_REG_WR 0x23
2341#define IOPB_SDMA_STATUS 0x24
2342#define IOPB_SCSI_BYTE_CNT 0x25
2343#define IOPB_HOST_BYTE_CNT 0x26
2344#define IOPB_BYTE_LEFT_TO_XFER 0x27
2345#define IOPB_BYTE_TO_XFER_0 0x28
2346#define IOPB_BYTE_TO_XFER_1 0x29
2347#define IOPB_BYTE_TO_XFER_2 0x2A
2348#define IOPB_BYTE_TO_XFER_3 0x2B
2349#define IOPB_ACC_GRP 0x2C
2350#define IOPB_RES_ADDR_2D 0x2D
2351#define IOPB_DEV_ID 0x2E
2352#define IOPB_RES_ADDR_2F 0x2F
2353#define IOPB_SCSI_DATA 0x30
2354#define IOPB_RES_ADDR_31 0x31
2355#define IOPB_RES_ADDR_32 0x32
2356#define IOPB_SCSI_DATA_HSHK 0x33
2357#define IOPB_SCSI_CTRL 0x34
2358#define IOPB_RES_ADDR_35 0x35
2359#define IOPB_RES_ADDR_36 0x36
2360#define IOPB_RES_ADDR_37 0x37
2361#define IOPB_RAM_BIST 0x38
2362#define IOPB_PLL_TEST 0x39
2363#define IOPB_PCI_INT_CFG 0x3A
2364#define IOPB_RES_ADDR_3B 0x3B
2365#define IOPB_RFIFO_CNT 0x3C
2366#define IOPB_RES_ADDR_3D 0x3D
2367#define IOPB_RES_ADDR_3E 0x3E
2368#define IOPB_RES_ADDR_3F 0x3F
2369
2370/*
2371 * Word I/O register address from base of 'iop_base'.
2372 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002373#define IOPW_CHIP_ID_0 0x00 /* CID0 */
2374#define IOPW_CTRL_REG 0x02 /* CC */
2375#define IOPW_RAM_ADDR 0x04 /* LA */
2376#define IOPW_RAM_DATA 0x06 /* LD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377#define IOPW_RES_ADDR_08 0x08
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002378#define IOPW_RISC_CSR 0x0A /* CSR */
2379#define IOPW_SCSI_CFG0 0x0C /* CFG0 */
2380#define IOPW_SCSI_CFG1 0x0E /* CFG1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381#define IOPW_RES_ADDR_10 0x10
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002382#define IOPW_SEL_MASK 0x12 /* SM */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383#define IOPW_RES_ADDR_14 0x14
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002384#define IOPW_FLASH_ADDR 0x16 /* FA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385#define IOPW_RES_ADDR_18 0x18
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002386#define IOPW_EE_CMD 0x1A /* EC */
2387#define IOPW_EE_DATA 0x1C /* ED */
2388#define IOPW_SFIFO_CNT 0x1E /* SFC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389#define IOPW_RES_ADDR_20 0x20
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002390#define IOPW_Q_BASE 0x22 /* QB */
2391#define IOPW_QP 0x24 /* QP */
2392#define IOPW_IX 0x26 /* IX */
2393#define IOPW_SP 0x28 /* SP */
2394#define IOPW_PC 0x2A /* PC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395#define IOPW_RES_ADDR_2C 0x2C
2396#define IOPW_RES_ADDR_2E 0x2E
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002397#define IOPW_SCSI_DATA 0x30 /* SD */
2398#define IOPW_SCSI_DATA_HSHK 0x32 /* SDH */
2399#define IOPW_SCSI_CTRL 0x34 /* SC */
2400#define IOPW_HSHK_CFG 0x36 /* HCFG */
2401#define IOPW_SXFR_STATUS 0x36 /* SXS */
2402#define IOPW_SXFR_CNTL 0x38 /* SXL */
2403#define IOPW_SXFR_CNTH 0x3A /* SXH */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404#define IOPW_RES_ADDR_3C 0x3C
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002405#define IOPW_RFIFO_DATA 0x3E /* RFD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406
2407/*
2408 * Doubleword I/O register address from base of 'iop_base'.
2409 */
2410#define IOPDW_RES_ADDR_0 0x00
2411#define IOPDW_RAM_DATA 0x04
2412#define IOPDW_RES_ADDR_8 0x08
2413#define IOPDW_RES_ADDR_C 0x0C
2414#define IOPDW_RES_ADDR_10 0x10
2415#define IOPDW_COMMA 0x14
2416#define IOPDW_COMMB 0x18
2417#define IOPDW_RES_ADDR_1C 0x1C
2418#define IOPDW_SDMA_ADDR0 0x20
2419#define IOPDW_SDMA_ADDR1 0x24
2420#define IOPDW_SDMA_COUNT 0x28
2421#define IOPDW_SDMA_ERROR 0x2C
2422#define IOPDW_RDMA_ADDR0 0x30
2423#define IOPDW_RDMA_ADDR1 0x34
2424#define IOPDW_RDMA_COUNT 0x38
2425#define IOPDW_RDMA_ERROR 0x3C
2426
2427#define ADV_CHIP_ID_BYTE 0x25
2428#define ADV_CHIP_ID_WORD 0x04C1
2429
2430#define ADV_SC_SCSI_BUS_RESET 0x2000
2431
2432#define ADV_INTR_ENABLE_HOST_INTR 0x01
2433#define ADV_INTR_ENABLE_SEL_INTR 0x02
2434#define ADV_INTR_ENABLE_DPR_INTR 0x04
2435#define ADV_INTR_ENABLE_RTA_INTR 0x08
2436#define ADV_INTR_ENABLE_RMA_INTR 0x10
2437#define ADV_INTR_ENABLE_RST_INTR 0x20
2438#define ADV_INTR_ENABLE_DPE_INTR 0x40
2439#define ADV_INTR_ENABLE_GLOBAL_INTR 0x80
2440
2441#define ADV_INTR_STATUS_INTRA 0x01
2442#define ADV_INTR_STATUS_INTRB 0x02
2443#define ADV_INTR_STATUS_INTRC 0x04
2444
2445#define ADV_RISC_CSR_STOP (0x0000)
2446#define ADV_RISC_TEST_COND (0x2000)
2447#define ADV_RISC_CSR_RUN (0x4000)
2448#define ADV_RISC_CSR_SINGLE_STEP (0x8000)
2449
2450#define ADV_CTRL_REG_HOST_INTR 0x0100
2451#define ADV_CTRL_REG_SEL_INTR 0x0200
2452#define ADV_CTRL_REG_DPR_INTR 0x0400
2453#define ADV_CTRL_REG_RTA_INTR 0x0800
2454#define ADV_CTRL_REG_RMA_INTR 0x1000
2455#define ADV_CTRL_REG_RES_BIT14 0x2000
2456#define ADV_CTRL_REG_DPE_INTR 0x4000
2457#define ADV_CTRL_REG_POWER_DONE 0x8000
2458#define ADV_CTRL_REG_ANY_INTR 0xFF00
2459
2460#define ADV_CTRL_REG_CMD_RESET 0x00C6
2461#define ADV_CTRL_REG_CMD_WR_IO_REG 0x00C5
2462#define ADV_CTRL_REG_CMD_RD_IO_REG 0x00C4
2463#define ADV_CTRL_REG_CMD_WR_PCI_CFG_SPACE 0x00C3
2464#define ADV_CTRL_REG_CMD_RD_PCI_CFG_SPACE 0x00C2
2465
2466#define ADV_TICKLE_NOP 0x00
2467#define ADV_TICKLE_A 0x01
2468#define ADV_TICKLE_B 0x02
2469#define ADV_TICKLE_C 0x03
2470
2471#define ADV_SCSI_CTRL_RSTOUT 0x2000
2472
2473#define AdvIsIntPending(port) \
2474 (AdvReadWordRegister(port, IOPW_CTRL_REG) & ADV_CTRL_REG_HOST_INTR)
2475
2476/*
2477 * SCSI_CFG0 Register bit definitions
2478 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002479#define TIMER_MODEAB 0xC000 /* Watchdog, Second, and Select. Timer Ctrl. */
2480#define PARITY_EN 0x2000 /* Enable SCSI Parity Error detection */
2481#define EVEN_PARITY 0x1000 /* Select Even Parity */
2482#define WD_LONG 0x0800 /* Watchdog Interval, 1: 57 min, 0: 13 sec */
2483#define QUEUE_128 0x0400 /* Queue Size, 1: 128 byte, 0: 64 byte */
2484#define PRIM_MODE 0x0100 /* Primitive SCSI mode */
2485#define SCAM_EN 0x0080 /* Enable SCAM selection */
2486#define SEL_TMO_LONG 0x0040 /* Sel/Resel Timeout, 1: 400 ms, 0: 1.6 ms */
2487#define CFRM_ID 0x0020 /* SCAM id sel. confirm., 1: fast, 0: 6.4 ms */
2488#define OUR_ID_EN 0x0010 /* Enable OUR_ID bits */
2489#define OUR_ID 0x000F /* SCSI ID */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490
2491/*
2492 * SCSI_CFG1 Register bit definitions
2493 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002494#define BIG_ENDIAN 0x8000 /* Enable Big Endian Mode MIO:15, EEP:15 */
2495#define TERM_POL 0x2000 /* Terminator Polarity Ctrl. MIO:13, EEP:13 */
2496#define SLEW_RATE 0x1000 /* SCSI output buffer slew rate */
2497#define FILTER_SEL 0x0C00 /* Filter Period Selection */
2498#define FLTR_DISABLE 0x0000 /* Input Filtering Disabled */
2499#define FLTR_11_TO_20NS 0x0800 /* Input Filtering 11ns to 20ns */
2500#define FLTR_21_TO_39NS 0x0C00 /* Input Filtering 21ns to 39ns */
2501#define ACTIVE_DBL 0x0200 /* Disable Active Negation */
2502#define DIFF_MODE 0x0100 /* SCSI differential Mode (Read-Only) */
2503#define DIFF_SENSE 0x0080 /* 1: No SE cables, 0: SE cable (Read-Only) */
2504#define TERM_CTL_SEL 0x0040 /* Enable TERM_CTL_H and TERM_CTL_L */
2505#define TERM_CTL 0x0030 /* External SCSI Termination Bits */
2506#define TERM_CTL_H 0x0020 /* Enable External SCSI Upper Termination */
2507#define TERM_CTL_L 0x0010 /* Enable External SCSI Lower Termination */
2508#define CABLE_DETECT 0x000F /* External SCSI Cable Connection Status */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509
2510/*
2511 * Addendum for ASC-38C0800 Chip
2512 *
2513 * The ASC-38C1600 Chip uses the same definitions except that the
2514 * bus mode override bits [12:10] have been moved to byte register
2515 * offset 0xE (IOPB_SOFT_OVER_WR) bits [12:10]. The [12:10] bits in
2516 * SCSI_CFG1 are read-only and always available. Bit 14 (DIS_TERM_DRV)
2517 * is not needed. The [12:10] bits in IOPB_SOFT_OVER_WR are write-only.
2518 * Also each ASC-38C1600 function or channel uses only cable bits [5:4]
2519 * and [1:0]. Bits [14], [7:6], [3:2] are unused.
2520 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002521#define DIS_TERM_DRV 0x4000 /* 1: Read c_det[3:0], 0: cannot read */
2522#define HVD_LVD_SE 0x1C00 /* Device Detect Bits */
2523#define HVD 0x1000 /* HVD Device Detect */
2524#define LVD 0x0800 /* LVD Device Detect */
2525#define SE 0x0400 /* SE Device Detect */
2526#define TERM_LVD 0x00C0 /* LVD Termination Bits */
2527#define TERM_LVD_HI 0x0080 /* Enable LVD Upper Termination */
2528#define TERM_LVD_LO 0x0040 /* Enable LVD Lower Termination */
2529#define TERM_SE 0x0030 /* SE Termination Bits */
2530#define TERM_SE_HI 0x0020 /* Enable SE Upper Termination */
2531#define TERM_SE_LO 0x0010 /* Enable SE Lower Termination */
2532#define C_DET_LVD 0x000C /* LVD Cable Detect Bits */
2533#define C_DET3 0x0008 /* Cable Detect for LVD External Wide */
2534#define C_DET2 0x0004 /* Cable Detect for LVD Internal Wide */
2535#define C_DET_SE 0x0003 /* SE Cable Detect Bits */
2536#define C_DET1 0x0002 /* Cable Detect for SE Internal Wide */
2537#define C_DET0 0x0001 /* Cable Detect for SE Internal Narrow */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538
2539#define CABLE_ILLEGAL_A 0x7
2540 /* x 0 0 0 | on on | Illegal (all 3 connectors are used) */
2541
2542#define CABLE_ILLEGAL_B 0xB
2543 /* 0 x 0 0 | on on | Illegal (all 3 connectors are used) */
2544
2545/*
2546 * MEM_CFG Register bit definitions
2547 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002548#define BIOS_EN 0x40 /* BIOS Enable MIO:14,EEP:14 */
2549#define FAST_EE_CLK 0x20 /* Diagnostic Bit */
2550#define RAM_SZ 0x1C /* Specify size of RAM to RISC */
2551#define RAM_SZ_2KB 0x00 /* 2 KB */
2552#define RAM_SZ_4KB 0x04 /* 4 KB */
2553#define RAM_SZ_8KB 0x08 /* 8 KB */
2554#define RAM_SZ_16KB 0x0C /* 16 KB */
2555#define RAM_SZ_32KB 0x10 /* 32 KB */
2556#define RAM_SZ_64KB 0x14 /* 64 KB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557
2558/*
2559 * DMA_CFG0 Register bit definitions
2560 *
2561 * This register is only accessible to the host.
2562 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002563#define BC_THRESH_ENB 0x80 /* PCI DMA Start Conditions */
2564#define FIFO_THRESH 0x70 /* PCI DMA FIFO Threshold */
2565#define FIFO_THRESH_16B 0x00 /* 16 bytes */
2566#define FIFO_THRESH_32B 0x20 /* 32 bytes */
2567#define FIFO_THRESH_48B 0x30 /* 48 bytes */
2568#define FIFO_THRESH_64B 0x40 /* 64 bytes */
2569#define FIFO_THRESH_80B 0x50 /* 80 bytes (default) */
2570#define FIFO_THRESH_96B 0x60 /* 96 bytes */
2571#define FIFO_THRESH_112B 0x70 /* 112 bytes */
2572#define START_CTL 0x0C /* DMA start conditions */
2573#define START_CTL_TH 0x00 /* Wait threshold level (default) */
2574#define START_CTL_ID 0x04 /* Wait SDMA/SBUS idle */
2575#define START_CTL_THID 0x08 /* Wait threshold and SDMA/SBUS idle */
2576#define START_CTL_EMFU 0x0C /* Wait SDMA FIFO empty/full */
2577#define READ_CMD 0x03 /* Memory Read Method */
2578#define READ_CMD_MR 0x00 /* Memory Read */
2579#define READ_CMD_MRL 0x02 /* Memory Read Long */
2580#define READ_CMD_MRM 0x03 /* Memory Read Multiple (default) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581
2582/*
2583 * ASC-38C0800 RAM BIST Register bit definitions
2584 */
2585#define RAM_TEST_MODE 0x80
2586#define PRE_TEST_MODE 0x40
2587#define NORMAL_MODE 0x00
2588#define RAM_TEST_DONE 0x10
2589#define RAM_TEST_STATUS 0x0F
2590#define RAM_TEST_HOST_ERROR 0x08
2591#define RAM_TEST_INTRAM_ERROR 0x04
2592#define RAM_TEST_RISC_ERROR 0x02
2593#define RAM_TEST_SCSI_ERROR 0x01
2594#define RAM_TEST_SUCCESS 0x00
2595#define PRE_TEST_VALUE 0x05
2596#define NORMAL_VALUE 0x00
2597
2598/*
2599 * ASC38C1600 Definitions
2600 *
2601 * IOPB_PCI_INT_CFG Bit Field Definitions
2602 */
2603
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002604#define INTAB_LD 0x80 /* Value loaded from EEPROM Bit 11. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605
2606/*
2607 * Bit 1 can be set to change the interrupt for the Function to operate in
2608 * Totem Pole mode. By default Bit 1 is 0 and the interrupt operates in
2609 * Open Drain mode. Both functions of the ASC38C1600 must be set to the same
2610 * mode, otherwise the operating mode is undefined.
2611 */
2612#define TOTEMPOLE 0x02
2613
2614/*
2615 * Bit 0 can be used to change the Int Pin for the Function. The value is
2616 * 0 by default for both Functions with Function 0 using INT A and Function
2617 * B using INT B. For Function 0 if set, INT B is used. For Function 1 if set,
2618 * INT A is used.
2619 *
2620 * EEPROM Word 0 Bit 11 for each Function may change the initial Int Pin
2621 * value specified in the PCI Configuration Space.
2622 */
2623#define INTAB 0x01
2624
2625/* a_advlib.h */
2626
2627/*
2628 * Adv Library Status Definitions
2629 */
2630#define ADV_TRUE 1
2631#define ADV_FALSE 0
2632#define ADV_NOERROR 1
2633#define ADV_SUCCESS 1
2634#define ADV_BUSY 0
2635#define ADV_ERROR (-1)
2636
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637/*
2638 * ADV_DVC_VAR 'warn_code' values
2639 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002640#define ASC_WARN_BUSRESET_ERROR 0x0001 /* SCSI Bus Reset error */
2641#define ASC_WARN_EEPROM_CHKSUM 0x0002 /* EEP check sum error */
2642#define ASC_WARN_EEPROM_TERMINATION 0x0004 /* EEP termination bad field */
2643#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080 /* PCI config space set error */
2644#define ASC_WARN_ERROR 0xFFFF /* ADV_ERROR return */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002646#define ADV_MAX_TID 15 /* max. target identifier */
2647#define ADV_MAX_LUN 7 /* max. logical unit number */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648
2649/*
2650 * Error code values are set in ADV_DVC_VAR 'err_code'.
2651 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002652#define ASC_IERR_WRITE_EEPROM 0x0001 /* write EEPROM error */
2653#define ASC_IERR_MCODE_CHKSUM 0x0002 /* micro code check sum error */
2654#define ASC_IERR_NO_CARRIER 0x0004 /* No more carrier memory. */
2655#define ASC_IERR_START_STOP_CHIP 0x0008 /* start/stop chip failed */
2656#define ASC_IERR_CHIP_VERSION 0x0040 /* wrong chip version */
2657#define ASC_IERR_SET_SCSI_ID 0x0080 /* set SCSI ID failed */
2658#define ASC_IERR_HVD_DEVICE 0x0100 /* HVD attached to LVD connector. */
2659#define ASC_IERR_BAD_SIGNATURE 0x0200 /* signature not found */
2660#define ASC_IERR_ILLEGAL_CONNECTION 0x0400 /* Illegal cable connection */
2661#define ASC_IERR_SINGLE_END_DEVICE 0x0800 /* Single-end used w/differential */
2662#define ASC_IERR_REVERSED_CABLE 0x1000 /* Narrow flat cable reversed */
2663#define ASC_IERR_BIST_PRE_TEST 0x2000 /* BIST pre-test error */
2664#define ASC_IERR_BIST_RAM_TEST 0x4000 /* BIST RAM test error */
2665#define ASC_IERR_BAD_CHIPTYPE 0x8000 /* Invalid 'chip_type' setting. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666
2667/*
2668 * Fixed locations of microcode operating variables.
2669 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002670#define ASC_MC_CODE_BEGIN_ADDR 0x0028 /* microcode start address */
2671#define ASC_MC_CODE_END_ADDR 0x002A /* microcode end address */
2672#define ASC_MC_CODE_CHK_SUM 0x002C /* microcode code checksum */
2673#define ASC_MC_VERSION_DATE 0x0038 /* microcode version */
2674#define ASC_MC_VERSION_NUM 0x003A /* microcode number */
2675#define ASC_MC_BIOSMEM 0x0040 /* BIOS RISC Memory Start */
2676#define ASC_MC_BIOSLEN 0x0050 /* BIOS RISC Memory Length */
2677#define ASC_MC_BIOS_SIGNATURE 0x0058 /* BIOS Signature 0x55AA */
2678#define ASC_MC_BIOS_VERSION 0x005A /* BIOS Version (2 bytes) */
2679#define ASC_MC_SDTR_SPEED1 0x0090 /* SDTR Speed for TID 0-3 */
2680#define ASC_MC_SDTR_SPEED2 0x0092 /* SDTR Speed for TID 4-7 */
2681#define ASC_MC_SDTR_SPEED3 0x0094 /* SDTR Speed for TID 8-11 */
2682#define ASC_MC_SDTR_SPEED4 0x0096 /* SDTR Speed for TID 12-15 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683#define ASC_MC_CHIP_TYPE 0x009A
2684#define ASC_MC_INTRB_CODE 0x009B
2685#define ASC_MC_WDTR_ABLE 0x009C
2686#define ASC_MC_SDTR_ABLE 0x009E
2687#define ASC_MC_TAGQNG_ABLE 0x00A0
2688#define ASC_MC_DISC_ENABLE 0x00A2
2689#define ASC_MC_IDLE_CMD_STATUS 0x00A4
2690#define ASC_MC_IDLE_CMD 0x00A6
2691#define ASC_MC_IDLE_CMD_PARAMETER 0x00A8
2692#define ASC_MC_DEFAULT_SCSI_CFG0 0x00AC
2693#define ASC_MC_DEFAULT_SCSI_CFG1 0x00AE
2694#define ASC_MC_DEFAULT_MEM_CFG 0x00B0
2695#define ASC_MC_DEFAULT_SEL_MASK 0x00B2
2696#define ASC_MC_SDTR_DONE 0x00B6
2697#define ASC_MC_NUMBER_OF_QUEUED_CMD 0x00C0
2698#define ASC_MC_NUMBER_OF_MAX_CMD 0x00D0
2699#define ASC_MC_DEVICE_HSHK_CFG_TABLE 0x0100
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002700#define ASC_MC_CONTROL_FLAG 0x0122 /* Microcode control flag. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701#define ASC_MC_WDTR_DONE 0x0124
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002702#define ASC_MC_CAM_MODE_MASK 0x015E /* CAM mode TID bitmask. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703#define ASC_MC_ICQ 0x0160
2704#define ASC_MC_IRQ 0x0164
2705#define ASC_MC_PPR_ABLE 0x017A
2706
2707/*
2708 * BIOS LRAM variable absolute offsets.
2709 */
2710#define BIOS_CODESEG 0x54
2711#define BIOS_CODELEN 0x56
2712#define BIOS_SIGNATURE 0x58
2713#define BIOS_VERSION 0x5A
2714
2715/*
2716 * Microcode Control Flags
2717 *
2718 * Flags set by the Adv Library in RISC variable 'control_flag' (0x122)
2719 * and handled by the microcode.
2720 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002721#define CONTROL_FLAG_IGNORE_PERR 0x0001 /* Ignore DMA Parity Errors */
2722#define CONTROL_FLAG_ENABLE_AIPP 0x0002 /* Enabled AIPP checking. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723
2724/*
2725 * ASC_MC_DEVICE_HSHK_CFG_TABLE microcode table or HSHK_CFG register format
2726 */
2727#define HSHK_CFG_WIDE_XFR 0x8000
2728#define HSHK_CFG_RATE 0x0F00
2729#define HSHK_CFG_OFFSET 0x001F
2730
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002731#define ASC_DEF_MAX_HOST_QNG 0xFD /* Max. number of host commands (253) */
2732#define ASC_DEF_MIN_HOST_QNG 0x10 /* Min. number of host commands (16) */
2733#define ASC_DEF_MAX_DVC_QNG 0x3F /* Max. number commands per device (63) */
2734#define ASC_DEF_MIN_DVC_QNG 0x04 /* Min. number commands per device (4) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002736#define ASC_QC_DATA_CHECK 0x01 /* Require ASC_QC_DATA_OUT set or clear. */
2737#define ASC_QC_DATA_OUT 0x02 /* Data out DMA transfer. */
2738#define ASC_QC_START_MOTOR 0x04 /* Send auto-start motor before request. */
2739#define ASC_QC_NO_OVERRUN 0x08 /* Don't report overrun. */
2740#define ASC_QC_FREEZE_TIDQ 0x10 /* Freeze TID queue after request. XXX TBD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002742#define ASC_QSC_NO_DISC 0x01 /* Don't allow disconnect for request. */
2743#define ASC_QSC_NO_TAGMSG 0x02 /* Don't allow tag queuing for request. */
2744#define ASC_QSC_NO_SYNC 0x04 /* Don't use Synch. transfer on request. */
2745#define ASC_QSC_NO_WIDE 0x08 /* Don't use Wide transfer on request. */
2746#define ASC_QSC_REDO_DTR 0x10 /* Renegotiate WDTR/SDTR before request. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747/*
2748 * Note: If a Tag Message is to be sent and neither ASC_QSC_HEAD_TAG or
2749 * ASC_QSC_ORDERED_TAG is set, then a Simple Tag Message (0x20) is used.
2750 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002751#define ASC_QSC_HEAD_TAG 0x40 /* Use Head Tag Message (0x21). */
2752#define ASC_QSC_ORDERED_TAG 0x80 /* Use Ordered Tag Message (0x22). */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753
2754/*
2755 * All fields here are accessed by the board microcode and need to be
2756 * little-endian.
2757 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002758typedef struct adv_carr_t {
2759 ADV_VADDR carr_va; /* Carrier Virtual Address */
2760 ADV_PADDR carr_pa; /* Carrier Physical Address */
2761 ADV_VADDR areq_vpa; /* ASC_SCSI_REQ_Q Virtual or Physical Address */
2762 /*
2763 * next_vpa [31:4] Carrier Virtual or Physical Next Pointer
2764 *
2765 * next_vpa [3:1] Reserved Bits
2766 * next_vpa [0] Done Flag set in Response Queue.
2767 */
2768 ADV_VADDR next_vpa;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769} ADV_CARR_T;
2770
2771/*
2772 * Mask used to eliminate low 4 bits of carrier 'next_vpa' field.
2773 */
2774#define ASC_NEXT_VPA_MASK 0xFFFFFFF0
2775
2776#define ASC_RQ_DONE 0x00000001
2777#define ASC_RQ_GOOD 0x00000002
2778#define ASC_CQ_STOPPER 0x00000000
2779
2780#define ASC_GET_CARRP(carrp) ((carrp) & ASC_NEXT_VPA_MASK)
2781
2782#define ADV_CARRIER_NUM_PAGE_CROSSING \
2783 (((ADV_CARRIER_COUNT * sizeof(ADV_CARR_T)) + \
2784 (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
2785
2786#define ADV_CARRIER_BUFSIZE \
2787 ((ADV_CARRIER_COUNT + ADV_CARRIER_NUM_PAGE_CROSSING) * sizeof(ADV_CARR_T))
2788
2789/*
2790 * ASC_SCSI_REQ_Q 'a_flag' definitions
2791 *
2792 * The Adv Library should limit use to the lower nibble (4 bits) of
2793 * a_flag. Drivers are free to use the upper nibble (4 bits) of a_flag.
2794 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002795#define ADV_POLL_REQUEST 0x01 /* poll for request completion */
2796#define ADV_SCSIQ_DONE 0x02 /* request done */
2797#define ADV_DONT_RETRY 0x08 /* don't do retry */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002799#define ADV_CHIP_ASC3550 0x01 /* Ultra-Wide IC */
2800#define ADV_CHIP_ASC38C0800 0x02 /* Ultra2-Wide/LVD IC */
2801#define ADV_CHIP_ASC38C1600 0x03 /* Ultra3-Wide/LVD2 IC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802
2803/*
2804 * Adapter temporary configuration structure
2805 *
2806 * This structure can be discarded after initialization. Don't add
2807 * fields here needed after initialization.
2808 *
2809 * Field naming convention:
2810 *
2811 * *_enable indicates the field enables or disables a feature. The
2812 * value of the field is never reset.
2813 */
2814typedef struct adv_dvc_cfg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002815 ushort disc_enable; /* enable disconnection */
2816 uchar chip_version; /* chip version */
2817 uchar termination; /* Term. Ctrl. bits 6-5 of SCSI_CFG1 register */
2818 ushort lib_version; /* Adv Library version number */
2819 ushort control_flag; /* Microcode Control Flag */
2820 ushort mcode_date; /* Microcode date */
2821 ushort mcode_version; /* Microcode version */
2822 ushort pci_slot_info; /* high byte device/function number */
2823 /* bits 7-3 device num., bits 2-0 function num. */
2824 /* low byte bus num. */
2825 ushort serial1; /* EEPROM serial number word 1 */
2826 ushort serial2; /* EEPROM serial number word 2 */
2827 ushort serial3; /* EEPROM serial number word 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828} ADV_DVC_CFG;
2829
2830struct adv_dvc_var;
2831struct adv_scsi_req_q;
2832
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002833typedef void (*ADV_ISR_CALLBACK)
2834 (struct adv_dvc_var *, struct adv_scsi_req_q *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002836typedef void (*ADV_ASYNC_CALLBACK)
2837 (struct adv_dvc_var *, uchar);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838
2839/*
2840 * Adapter operation variable structure.
2841 *
2842 * One structure is required per host adapter.
2843 *
2844 * Field naming convention:
2845 *
2846 * *_able indicates both whether a feature should be enabled or disabled
2847 * and whether a device isi capable of the feature. At initialization
2848 * this field may be set, but later if a device is found to be incapable
2849 * of the feature, the field is cleared.
2850 */
2851typedef struct adv_dvc_var {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002852 AdvPortAddr iop_base; /* I/O port address */
2853 ushort err_code; /* fatal error code */
2854 ushort bios_ctrl; /* BIOS control word, EEPROM word 12 */
2855 ADV_ISR_CALLBACK isr_callback;
2856 ADV_ASYNC_CALLBACK async_callback;
2857 ushort wdtr_able; /* try WDTR for a device */
2858 ushort sdtr_able; /* try SDTR for a device */
2859 ushort ultra_able; /* try SDTR Ultra speed for a device */
2860 ushort sdtr_speed1; /* EEPROM SDTR Speed for TID 0-3 */
2861 ushort sdtr_speed2; /* EEPROM SDTR Speed for TID 4-7 */
2862 ushort sdtr_speed3; /* EEPROM SDTR Speed for TID 8-11 */
2863 ushort sdtr_speed4; /* EEPROM SDTR Speed for TID 12-15 */
2864 ushort tagqng_able; /* try tagged queuing with a device */
2865 ushort ppr_able; /* PPR message capable per TID bitmask. */
2866 uchar max_dvc_qng; /* maximum number of tagged commands per device */
2867 ushort start_motor; /* start motor command allowed */
2868 uchar scsi_reset_wait; /* delay in seconds after scsi bus reset */
2869 uchar chip_no; /* should be assigned by caller */
2870 uchar max_host_qng; /* maximum number of Q'ed command allowed */
2871 uchar irq_no; /* IRQ number */
2872 ushort no_scam; /* scam_tolerant of EEPROM */
2873 struct asc_board *drv_ptr; /* driver pointer to private structure */
2874 uchar chip_scsi_id; /* chip SCSI target ID */
2875 uchar chip_type;
2876 uchar bist_err_code;
2877 ADV_CARR_T *carrier_buf;
2878 ADV_CARR_T *carr_freelist; /* Carrier free list. */
2879 ADV_CARR_T *icq_sp; /* Initiator command queue stopper pointer. */
2880 ADV_CARR_T *irq_sp; /* Initiator response queue stopper pointer. */
2881 ushort carr_pending_cnt; /* Count of pending carriers. */
2882 /*
2883 * Note: The following fields will not be used after initialization. The
2884 * driver may discard the buffer after initialization is done.
2885 */
2886 ADV_DVC_CFG *cfg; /* temporary configuration structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887} ADV_DVC_VAR;
2888
2889#define NO_OF_SG_PER_BLOCK 15
2890
2891typedef struct asc_sg_block {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002892 uchar reserved1;
2893 uchar reserved2;
2894 uchar reserved3;
2895 uchar sg_cnt; /* Valid entries in block. */
2896 ADV_PADDR sg_ptr; /* Pointer to next sg block. */
2897 struct {
2898 ADV_PADDR sg_addr; /* SG element address. */
2899 ADV_DCNT sg_count; /* SG element count. */
2900 } sg_list[NO_OF_SG_PER_BLOCK];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901} ADV_SG_BLOCK;
2902
2903/*
2904 * ADV_SCSI_REQ_Q - microcode request structure
2905 *
2906 * All fields in this structure up to byte 60 are used by the microcode.
2907 * The microcode makes assumptions about the size and ordering of fields
2908 * in this structure. Do not change the structure definition here without
2909 * coordinating the change with the microcode.
2910 *
2911 * All fields accessed by microcode must be maintained in little_endian
2912 * order.
2913 */
2914typedef struct adv_scsi_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002915 uchar cntl; /* Ucode flags and state (ASC_MC_QC_*). */
2916 uchar target_cmd;
2917 uchar target_id; /* Device target identifier. */
2918 uchar target_lun; /* Device target logical unit number. */
2919 ADV_PADDR data_addr; /* Data buffer physical address. */
2920 ADV_DCNT data_cnt; /* Data count. Ucode sets to residual. */
2921 ADV_PADDR sense_addr;
2922 ADV_PADDR carr_pa;
2923 uchar mflag;
2924 uchar sense_len;
2925 uchar cdb_len; /* SCSI CDB length. Must <= 16 bytes. */
2926 uchar scsi_cntl;
2927 uchar done_status; /* Completion status. */
2928 uchar scsi_status; /* SCSI status byte. */
2929 uchar host_status; /* Ucode host status. */
2930 uchar sg_working_ix;
2931 uchar cdb[12]; /* SCSI CDB bytes 0-11. */
2932 ADV_PADDR sg_real_addr; /* SG list physical address. */
2933 ADV_PADDR scsiq_rptr;
2934 uchar cdb16[4]; /* SCSI CDB bytes 12-15. */
2935 ADV_VADDR scsiq_ptr;
2936 ADV_VADDR carr_va;
2937 /*
2938 * End of microcode structure - 60 bytes. The rest of the structure
2939 * is used by the Adv Library and ignored by the microcode.
2940 */
2941 ADV_VADDR srb_ptr;
2942 ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */
2943 char *vdata_addr; /* Data buffer virtual address. */
2944 uchar a_flag;
2945 uchar pad[2]; /* Pad out to a word boundary. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946} ADV_SCSI_REQ_Q;
2947
2948/*
2949 * Microcode idle loop commands
2950 */
2951#define IDLE_CMD_COMPLETED 0
2952#define IDLE_CMD_STOP_CHIP 0x0001
2953#define IDLE_CMD_STOP_CHIP_SEND_INT 0x0002
2954#define IDLE_CMD_SEND_INT 0x0004
2955#define IDLE_CMD_ABORT 0x0008
2956#define IDLE_CMD_DEVICE_RESET 0x0010
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002957#define IDLE_CMD_SCSI_RESET_START 0x0020 /* Assert SCSI Bus Reset */
2958#define IDLE_CMD_SCSI_RESET_END 0x0040 /* Deassert SCSI Bus Reset */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959#define IDLE_CMD_SCSIREQ 0x0080
2960
2961#define IDLE_CMD_STATUS_SUCCESS 0x0001
2962#define IDLE_CMD_STATUS_FAILURE 0x0002
2963
2964/*
2965 * AdvSendIdleCmd() flag definitions.
2966 */
2967#define ADV_NOWAIT 0x01
2968
2969/*
2970 * Wait loop time out values.
2971 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002972#define SCSI_WAIT_10_SEC 10UL /* 10 seconds */
2973#define SCSI_WAIT_100_MSEC 100UL /* 100 milliseconds */
2974#define SCSI_US_PER_MSEC 1000 /* microseconds per millisecond */
2975#define SCSI_MS_PER_SEC 1000UL /* milliseconds per second */
2976#define SCSI_MAX_RETRY 10 /* retry count */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002978#define ADV_ASYNC_RDMA_FAILURE 0x01 /* Fatal RDMA failure. */
2979#define ADV_ASYNC_SCSI_BUS_RESET_DET 0x02 /* Detected SCSI Bus Reset. */
2980#define ADV_ASYNC_CARRIER_READY_FAILURE 0x03 /* Carrier Ready failure. */
2981#define ADV_RDMA_IN_CARR_AND_Q_INVALID 0x04 /* RDMAed-in data invalid. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002983#define ADV_HOST_SCSI_BUS_RESET 0x80 /* Host Initiated SCSI Bus Reset. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984
2985/*
2986 * Device drivers must define the following functions.
2987 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002988static inline ulong DvcEnterCritical(void);
2989static inline void DvcLeaveCritical(ulong);
2990static void DvcSleepMilliSecond(ADV_DCNT);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002991static ADV_PADDR DvcGetPhyAddr(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *,
2992 uchar *, ASC_SDCNT *, int);
2993static void DvcDelayMicroSecond(ADV_DVC_VAR *, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994
2995/*
2996 * Adv Library functions available to drivers.
2997 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002998static int AdvExeScsiQueue(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
2999static int AdvISR(ADV_DVC_VAR *);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003000static int AdvInitAsc3550Driver(ADV_DVC_VAR *);
3001static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *);
3002static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *);
3003static int AdvResetChipAndSB(ADV_DVC_VAR *);
3004static int AdvResetSB(ADV_DVC_VAR *asc_dvc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005
3006/*
3007 * Internal Adv Library functions.
3008 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003009static int AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ADV_DCNT);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003010static int AdvInitFrom3550EEP(ADV_DVC_VAR *);
3011static int AdvInitFrom38C0800EEP(ADV_DVC_VAR *);
3012static int AdvInitFrom38C1600EEP(ADV_DVC_VAR *);
3013static ushort AdvGet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
3014static void AdvSet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
3015static ushort AdvGet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
3016static void AdvSet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
3017static ushort AdvGet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
3018static void AdvSet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
3019static void AdvWaitEEPCmd(AdvPortAddr);
3020static ushort AdvReadEEPWord(AdvPortAddr, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022/* Read byte from a register. */
3023#define AdvReadByteRegister(iop_base, reg_off) \
3024 (ADV_MEM_READB((iop_base) + (reg_off)))
3025
3026/* Write byte to a register. */
3027#define AdvWriteByteRegister(iop_base, reg_off, byte) \
3028 (ADV_MEM_WRITEB((iop_base) + (reg_off), (byte)))
3029
3030/* Read word (2 bytes) from a register. */
3031#define AdvReadWordRegister(iop_base, reg_off) \
3032 (ADV_MEM_READW((iop_base) + (reg_off)))
3033
3034/* Write word (2 bytes) to a register. */
3035#define AdvWriteWordRegister(iop_base, reg_off, word) \
3036 (ADV_MEM_WRITEW((iop_base) + (reg_off), (word)))
3037
3038/* Write dword (4 bytes) to a register. */
3039#define AdvWriteDWordRegister(iop_base, reg_off, dword) \
3040 (ADV_MEM_WRITEDW((iop_base) + (reg_off), (dword)))
3041
3042/* Read byte from LRAM. */
3043#define AdvReadByteLram(iop_base, addr, byte) \
3044do { \
3045 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
3046 (byte) = ADV_MEM_READB((iop_base) + IOPB_RAM_DATA); \
3047} while (0)
3048
3049/* Write byte to LRAM. */
3050#define AdvWriteByteLram(iop_base, addr, byte) \
3051 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
3052 ADV_MEM_WRITEB((iop_base) + IOPB_RAM_DATA, (byte)))
3053
3054/* Read word (2 bytes) from LRAM. */
3055#define AdvReadWordLram(iop_base, addr, word) \
3056do { \
3057 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
3058 (word) = (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA)); \
3059} while (0)
3060
3061/* Write word (2 bytes) to LRAM. */
3062#define AdvWriteWordLram(iop_base, addr, word) \
3063 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
3064 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
3065
3066/* Write little-endian double word (4 bytes) to LRAM */
3067/* Because of unspecified C language ordering don't use auto-increment. */
3068#define AdvWriteDWordLramNoSwap(iop_base, addr, dword) \
3069 ((ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
3070 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
3071 cpu_to_le16((ushort) ((dword) & 0xFFFF)))), \
3072 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr) + 2), \
3073 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
3074 cpu_to_le16((ushort) ((dword >> 16) & 0xFFFF)))))
3075
3076/* Read word (2 bytes) from LRAM assuming that the address is already set. */
3077#define AdvReadWordAutoIncLram(iop_base) \
3078 (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA))
3079
3080/* Write word (2 bytes) to LRAM assuming that the address is already set. */
3081#define AdvWriteWordAutoIncLram(iop_base, word) \
3082 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
3083
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084/*
3085 * Define macro to check for Condor signature.
3086 *
3087 * Evaluate to ADV_TRUE if a Condor chip is found the specified port
3088 * address 'iop_base'. Otherwise evalue to ADV_FALSE.
3089 */
3090#define AdvFindSignature(iop_base) \
3091 (((AdvReadByteRegister((iop_base), IOPB_CHIP_ID_1) == \
3092 ADV_CHIP_ID_BYTE) && \
3093 (AdvReadWordRegister((iop_base), IOPW_CHIP_ID_0) == \
3094 ADV_CHIP_ID_WORD)) ? ADV_TRUE : ADV_FALSE)
3095
3096/*
3097 * Define macro to Return the version number of the chip at 'iop_base'.
3098 *
3099 * The second parameter 'bus_type' is currently unused.
3100 */
3101#define AdvGetChipVersion(iop_base, bus_type) \
3102 AdvReadByteRegister((iop_base), IOPB_CHIP_TYPE_REV)
3103
3104/*
3105 * Abort an SRB in the chip's RISC Memory. The 'srb_ptr' argument must
3106 * match the ASC_SCSI_REQ_Q 'srb_ptr' field.
3107 *
3108 * If the request has not yet been sent to the device it will simply be
3109 * aborted from RISC memory. If the request is disconnected it will be
3110 * aborted on reselection by sending an Abort Message to the target ID.
3111 *
3112 * Return value:
3113 * ADV_TRUE(1) - Queue was successfully aborted.
3114 * ADV_FALSE(0) - Queue was not found on the active queue list.
3115 */
3116#define AdvAbortQueue(asc_dvc, scsiq) \
3117 AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_ABORT, \
3118 (ADV_DCNT) (scsiq))
3119
3120/*
3121 * Send a Bus Device Reset Message to the specified target ID.
3122 *
3123 * All outstanding commands will be purged if sending the
3124 * Bus Device Reset Message is successful.
3125 *
3126 * Return Value:
3127 * ADV_TRUE(1) - All requests on the target are purged.
3128 * ADV_FALSE(0) - Couldn't issue Bus Device Reset Message; Requests
3129 * are not purged.
3130 */
3131#define AdvResetDevice(asc_dvc, target_id) \
3132 AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_DEVICE_RESET, \
3133 (ADV_DCNT) (target_id))
3134
3135/*
3136 * SCSI Wide Type definition.
3137 */
3138#define ADV_SCSI_BIT_ID_TYPE ushort
3139
3140/*
3141 * AdvInitScsiTarget() 'cntl_flag' options.
3142 */
3143#define ADV_SCAN_LUN 0x01
3144#define ADV_CAPINFO_NOLUN 0x02
3145
3146/*
3147 * Convert target id to target id bit mask.
3148 */
3149#define ADV_TID_TO_TIDMASK(tid) (0x01 << ((tid) & ADV_MAX_TID))
3150
3151/*
3152 * ASC_SCSI_REQ_Q 'done_status' and 'host_status' return values.
3153 */
3154
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003155#define QD_NO_STATUS 0x00 /* Request not completed yet. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156#define QD_NO_ERROR 0x01
3157#define QD_ABORTED_BY_HOST 0x02
3158#define QD_WITH_ERROR 0x04
3159
3160#define QHSTA_NO_ERROR 0x00
3161#define QHSTA_M_SEL_TIMEOUT 0x11
3162#define QHSTA_M_DATA_OVER_RUN 0x12
3163#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
3164#define QHSTA_M_QUEUE_ABORTED 0x15
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003165#define QHSTA_M_SXFR_SDMA_ERR 0x16 /* SXFR_STATUS SCSI DMA Error */
3166#define QHSTA_M_SXFR_SXFR_PERR 0x17 /* SXFR_STATUS SCSI Bus Parity Error */
3167#define QHSTA_M_RDMA_PERR 0x18 /* RISC PCI DMA parity error */
3168#define QHSTA_M_SXFR_OFF_UFLW 0x19 /* SXFR_STATUS Offset Underflow */
3169#define QHSTA_M_SXFR_OFF_OFLW 0x20 /* SXFR_STATUS Offset Overflow */
3170#define QHSTA_M_SXFR_WD_TMO 0x21 /* SXFR_STATUS Watchdog Timeout */
3171#define QHSTA_M_SXFR_DESELECTED 0x22 /* SXFR_STATUS Deselected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172/* Note: QHSTA_M_SXFR_XFR_OFLW is identical to QHSTA_M_DATA_OVER_RUN. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003173#define QHSTA_M_SXFR_XFR_OFLW 0x12 /* SXFR_STATUS Transfer Overflow */
3174#define QHSTA_M_SXFR_XFR_PH_ERR 0x24 /* SXFR_STATUS Transfer Phase Error */
3175#define QHSTA_M_SXFR_UNKNOWN_ERROR 0x25 /* SXFR_STATUS Unknown Error */
3176#define QHSTA_M_SCSI_BUS_RESET 0x30 /* Request aborted from SBR */
3177#define QHSTA_M_SCSI_BUS_RESET_UNSOL 0x31 /* Request aborted from unsol. SBR */
3178#define QHSTA_M_BUS_DEVICE_RESET 0x32 /* Request aborted from BDR */
3179#define QHSTA_M_DIRECTION_ERR 0x35 /* Data Phase mismatch */
3180#define QHSTA_M_DIRECTION_ERR_HUNG 0x36 /* Data Phase mismatch and bus hang */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181#define QHSTA_M_WTM_TIMEOUT 0x41
3182#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42
3183#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43
3184#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003185#define QHSTA_M_INVALID_DEVICE 0x45 /* Bad target ID */
3186#define QHSTA_M_FROZEN_TIDQ 0x46 /* TID Queue frozen. */
3187#define QHSTA_M_SGBACKUP_ERROR 0x47 /* Scatter-Gather backup error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188
3189/*
3190 * Default EEPROM Configuration structure defined in a_init.c.
3191 */
3192static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config;
3193static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config;
3194static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config;
3195
3196/*
3197 * DvcGetPhyAddr() flag arguments
3198 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003199#define ADV_IS_SCSIQ_FLAG 0x01 /* 'addr' is ASC_SCSI_REQ_Q pointer */
3200#define ADV_ASCGETSGLIST_VADDR 0x02 /* 'addr' is AscGetSGList() virtual addr */
3201#define ADV_IS_SENSE_FLAG 0x04 /* 'addr' is sense virtual pointer */
3202#define ADV_IS_DATA_FLAG 0x08 /* 'addr' is data virtual pointer */
3203#define ADV_IS_SGLIST_FLAG 0x10 /* 'addr' is sglist virtual pointer */
3204#define ADV_IS_CARRIER_FLAG 0x20 /* 'addr' is ADV_CARR_T pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205
3206/* Return the address that is aligned at the next doubleword >= to 'addr'. */
3207#define ADV_8BALIGN(addr) (((ulong) (addr) + 0x7) & ~0x7)
3208#define ADV_16BALIGN(addr) (((ulong) (addr) + 0xF) & ~0xF)
3209#define ADV_32BALIGN(addr) (((ulong) (addr) + 0x1F) & ~0x1F)
3210
3211/*
3212 * Total contiguous memory needed for driver SG blocks.
3213 *
3214 * ADV_MAX_SG_LIST must be defined by a driver. It is the maximum
3215 * number of scatter-gather elements the driver supports in a
3216 * single request.
3217 */
3218
3219#define ADV_SG_LIST_MAX_BYTE_SIZE \
3220 (sizeof(ADV_SG_BLOCK) * \
3221 ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK))
3222
3223/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224 * --- Driver Constants and Macros
3225 */
3226
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227/* Reference Scsi_Host hostdata */
3228#define ASC_BOARDP(host) ((asc_board_t *) &((host)->hostdata))
3229
3230/* asc_board_t flags */
3231#define ASC_HOST_IN_RESET 0x01
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003232#define ASC_IS_WIDE_BOARD 0x04 /* AdvanSys Wide Board */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233#define ASC_SELECT_QUEUE_DEPTHS 0x08
3234
3235#define ASC_NARROW_BOARD(boardp) (((boardp)->flags & ASC_IS_WIDE_BOARD) == 0)
3236#define ASC_WIDE_BOARD(boardp) ((boardp)->flags & ASC_IS_WIDE_BOARD)
3237
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003238#define NO_ISA_DMA 0xff /* No ISA DMA Channel Used */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003239
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003240#define ASC_INFO_SIZE 128 /* advansys_info() line size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241
3242#ifdef CONFIG_PROC_FS
3243/* /proc/scsi/advansys/[0...] related definitions */
3244#define ASC_PRTBUF_SIZE 2048
3245#define ASC_PRTLINE_SIZE 160
3246
3247#define ASC_PRT_NEXT() \
3248 if (cp) { \
3249 totlen += len; \
3250 leftlen -= len; \
3251 if (leftlen == 0) { \
3252 return totlen; \
3253 } \
3254 cp += len; \
3255 }
3256#endif /* CONFIG_PROC_FS */
3257
3258/* Asc Library return codes */
3259#define ASC_TRUE 1
3260#define ASC_FALSE 0
3261#define ASC_NOERROR 1
3262#define ASC_BUSY 0
3263#define ASC_ERROR (-1)
3264
3265/* struct scsi_cmnd function return codes */
3266#define STATUS_BYTE(byte) (byte)
3267#define MSG_BYTE(byte) ((byte) << 8)
3268#define HOST_BYTE(byte) ((byte) << 16)
3269#define DRIVER_BYTE(byte) ((byte) << 24)
3270
3271/*
3272 * The following definitions and macros are OS independent interfaces to
3273 * the queue functions:
3274 * REQ - SCSI request structure
3275 * REQP - pointer to SCSI request structure
3276 * REQPTID(reqp) - reqp's target id
3277 * REQPNEXT(reqp) - reqp's next pointer
3278 * REQPNEXTP(reqp) - pointer to reqp's next pointer
3279 * REQPTIME(reqp) - reqp's time stamp value
3280 * REQTIMESTAMP() - system time stamp value
3281 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003282typedef struct scsi_cmnd REQ, *REQP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283#define REQPNEXT(reqp) ((REQP) ((reqp)->host_scribble))
3284#define REQPNEXTP(reqp) ((REQP *) &((reqp)->host_scribble))
3285#define REQPTID(reqp) ((reqp)->device->id)
3286#define REQPTIME(reqp) ((reqp)->SCp.this_residual)
3287#define REQTIMESTAMP() (jiffies)
3288
3289#define REQTIMESTAT(function, ascq, reqp, tid) \
3290{ \
3291 /*
3292 * If the request time stamp is less than the system time stamp, then \
3293 * maybe the system time stamp wrapped. Set the request time to zero.\
3294 */ \
3295 if (REQPTIME(reqp) <= REQTIMESTAMP()) { \
3296 REQPTIME(reqp) = REQTIMESTAMP() - REQPTIME(reqp); \
3297 } else { \
3298 /* Indicate an error occurred with the assertion. */ \
3299 ASC_ASSERT(REQPTIME(reqp) <= REQTIMESTAMP()); \
3300 REQPTIME(reqp) = 0; \
3301 } \
3302 /* Handle first minimum time case without external initialization. */ \
3303 if (((ascq)->q_tot_cnt[tid] == 1) || \
3304 (REQPTIME(reqp) < (ascq)->q_min_tim[tid])) { \
3305 (ascq)->q_min_tim[tid] = REQPTIME(reqp); \
3306 ASC_DBG3(1, "%s: new q_min_tim[%d] %u\n", \
3307 (function), (tid), (ascq)->q_min_tim[tid]); \
3308 } \
3309 if (REQPTIME(reqp) > (ascq)->q_max_tim[tid]) { \
3310 (ascq)->q_max_tim[tid] = REQPTIME(reqp); \
3311 ASC_DBG3(1, "%s: new q_max_tim[%d] %u\n", \
3312 (function), tid, (ascq)->q_max_tim[tid]); \
3313 } \
3314 (ascq)->q_tot_tim[tid] += REQPTIME(reqp); \
3315 /* Reset the time stamp field. */ \
3316 REQPTIME(reqp) = 0; \
3317}
3318
3319/* asc_enqueue() flags */
3320#define ASC_FRONT 1
3321#define ASC_BACK 2
3322
3323/* asc_dequeue_list() argument */
3324#define ASC_TID_ALL (-1)
3325
3326/* Return non-zero, if the queue is empty. */
3327#define ASC_QUEUE_EMPTY(ascq) ((ascq)->q_tidmask == 0)
3328
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329#ifndef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003330#define ASC_STATS(shost, counter)
3331#define ASC_STATS_ADD(shost, counter, count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332#else /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003333#define ASC_STATS(shost, counter) \
3334 (ASC_BOARDP(shost)->asc_stats.counter++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003335
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003336#define ASC_STATS_ADD(shost, counter, count) \
3337 (ASC_BOARDP(shost)->asc_stats.counter += (count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338#endif /* ADVANSYS_STATS */
3339
3340#define ASC_CEILING(val, unit) (((val) + ((unit) - 1))/(unit))
3341
3342/* If the result wraps when calculating tenths, return 0. */
3343#define ASC_TENTHS(num, den) \
3344 (((10 * ((num)/(den))) > (((num) * 10)/(den))) ? \
3345 0 : ((((num) * 10)/(den)) - (10 * ((num)/(den)))))
3346
3347/*
3348 * Display a message to the console.
3349 */
3350#define ASC_PRINT(s) \
3351 { \
3352 printk("advansys: "); \
3353 printk(s); \
3354 }
3355
3356#define ASC_PRINT1(s, a1) \
3357 { \
3358 printk("advansys: "); \
3359 printk((s), (a1)); \
3360 }
3361
3362#define ASC_PRINT2(s, a1, a2) \
3363 { \
3364 printk("advansys: "); \
3365 printk((s), (a1), (a2)); \
3366 }
3367
3368#define ASC_PRINT3(s, a1, a2, a3) \
3369 { \
3370 printk("advansys: "); \
3371 printk((s), (a1), (a2), (a3)); \
3372 }
3373
3374#define ASC_PRINT4(s, a1, a2, a3, a4) \
3375 { \
3376 printk("advansys: "); \
3377 printk((s), (a1), (a2), (a3), (a4)); \
3378 }
3379
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380#ifndef ADVANSYS_DEBUG
3381
3382#define ASC_DBG(lvl, s)
3383#define ASC_DBG1(lvl, s, a1)
3384#define ASC_DBG2(lvl, s, a1, a2)
3385#define ASC_DBG3(lvl, s, a1, a2, a3)
3386#define ASC_DBG4(lvl, s, a1, a2, a3, a4)
3387#define ASC_DBG_PRT_SCSI_HOST(lvl, s)
3388#define ASC_DBG_PRT_SCSI_CMND(lvl, s)
3389#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp)
3390#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
3391#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone)
3392#define ADV_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
3393#define ASC_DBG_PRT_HEX(lvl, name, start, length)
3394#define ASC_DBG_PRT_CDB(lvl, cdb, len)
3395#define ASC_DBG_PRT_SENSE(lvl, sense, len)
3396#define ASC_DBG_PRT_INQUIRY(lvl, inq, len)
3397
3398#else /* ADVANSYS_DEBUG */
3399
3400/*
3401 * Debugging Message Levels:
3402 * 0: Errors Only
3403 * 1: High-Level Tracing
3404 * 2-N: Verbose Tracing
3405 */
3406
3407#define ASC_DBG(lvl, s) \
3408 { \
3409 if (asc_dbglvl >= (lvl)) { \
3410 printk(s); \
3411 } \
3412 }
3413
3414#define ASC_DBG1(lvl, s, a1) \
3415 { \
3416 if (asc_dbglvl >= (lvl)) { \
3417 printk((s), (a1)); \
3418 } \
3419 }
3420
3421#define ASC_DBG2(lvl, s, a1, a2) \
3422 { \
3423 if (asc_dbglvl >= (lvl)) { \
3424 printk((s), (a1), (a2)); \
3425 } \
3426 }
3427
3428#define ASC_DBG3(lvl, s, a1, a2, a3) \
3429 { \
3430 if (asc_dbglvl >= (lvl)) { \
3431 printk((s), (a1), (a2), (a3)); \
3432 } \
3433 }
3434
3435#define ASC_DBG4(lvl, s, a1, a2, a3, a4) \
3436 { \
3437 if (asc_dbglvl >= (lvl)) { \
3438 printk((s), (a1), (a2), (a3), (a4)); \
3439 } \
3440 }
3441
3442#define ASC_DBG_PRT_SCSI_HOST(lvl, s) \
3443 { \
3444 if (asc_dbglvl >= (lvl)) { \
3445 asc_prt_scsi_host(s); \
3446 } \
3447 }
3448
3449#define ASC_DBG_PRT_SCSI_CMND(lvl, s) \
3450 { \
3451 if (asc_dbglvl >= (lvl)) { \
3452 asc_prt_scsi_cmnd(s); \
3453 } \
3454 }
3455
3456#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp) \
3457 { \
3458 if (asc_dbglvl >= (lvl)) { \
3459 asc_prt_asc_scsi_q(scsiqp); \
3460 } \
3461 }
3462
3463#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone) \
3464 { \
3465 if (asc_dbglvl >= (lvl)) { \
3466 asc_prt_asc_qdone_info(qdone); \
3467 } \
3468 }
3469
3470#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp) \
3471 { \
3472 if (asc_dbglvl >= (lvl)) { \
3473 asc_prt_adv_scsi_req_q(scsiqp); \
3474 } \
3475 }
3476
3477#define ASC_DBG_PRT_HEX(lvl, name, start, length) \
3478 { \
3479 if (asc_dbglvl >= (lvl)) { \
3480 asc_prt_hex((name), (start), (length)); \
3481 } \
3482 }
3483
3484#define ASC_DBG_PRT_CDB(lvl, cdb, len) \
3485 ASC_DBG_PRT_HEX((lvl), "CDB", (uchar *) (cdb), (len));
3486
3487#define ASC_DBG_PRT_SENSE(lvl, sense, len) \
3488 ASC_DBG_PRT_HEX((lvl), "SENSE", (uchar *) (sense), (len));
3489
3490#define ASC_DBG_PRT_INQUIRY(lvl, inq, len) \
3491 ASC_DBG_PRT_HEX((lvl), "INQUIRY", (uchar *) (inq), (len));
3492#endif /* ADVANSYS_DEBUG */
3493
3494#ifndef ADVANSYS_ASSERT
3495#define ASC_ASSERT(a)
3496#else /* ADVANSYS_ASSERT */
3497
3498#define ASC_ASSERT(a) \
3499 { \
3500 if (!(a)) { \
3501 printk("ASC_ASSERT() Failure: file %s, line %d\n", \
3502 __FILE__, __LINE__); \
3503 } \
3504 }
3505
3506#endif /* ADVANSYS_ASSERT */
3507
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508/*
3509 * --- Driver Structures
3510 */
3511
3512#ifdef ADVANSYS_STATS
3513
3514/* Per board statistics structure */
3515struct asc_stats {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003516 /* Driver Entrypoint Statistics */
3517 ADV_DCNT queuecommand; /* # calls to advansys_queuecommand() */
3518 ADV_DCNT reset; /* # calls to advansys_eh_bus_reset() */
3519 ADV_DCNT biosparam; /* # calls to advansys_biosparam() */
3520 ADV_DCNT interrupt; /* # advansys_interrupt() calls */
3521 ADV_DCNT callback; /* # calls to asc/adv_isr_callback() */
3522 ADV_DCNT done; /* # calls to request's scsi_done function */
3523 ADV_DCNT build_error; /* # asc/adv_build_req() ASC_ERROR returns. */
3524 ADV_DCNT adv_build_noreq; /* # adv_build_req() adv_req_t alloc. fail. */
3525 ADV_DCNT adv_build_nosg; /* # adv_build_req() adv_sgblk_t alloc. fail. */
3526 /* AscExeScsiQueue()/AdvExeScsiQueue() Statistics */
3527 ADV_DCNT exe_noerror; /* # ASC_NOERROR returns. */
3528 ADV_DCNT exe_busy; /* # ASC_BUSY returns. */
3529 ADV_DCNT exe_error; /* # ASC_ERROR returns. */
3530 ADV_DCNT exe_unknown; /* # unknown returns. */
3531 /* Data Transfer Statistics */
3532 ADV_DCNT cont_cnt; /* # non-scatter-gather I/O requests received */
3533 ADV_DCNT cont_xfer; /* # contiguous transfer 512-bytes */
3534 ADV_DCNT sg_cnt; /* # scatter-gather I/O requests received */
3535 ADV_DCNT sg_elem; /* # scatter-gather elements */
3536 ADV_DCNT sg_xfer; /* # scatter-gather transfer 512-bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537};
3538#endif /* ADVANSYS_STATS */
3539
3540/*
3541 * Request queuing structure
3542 */
3543typedef struct asc_queue {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003544 ADV_SCSI_BIT_ID_TYPE q_tidmask; /* queue mask */
3545 REQP q_first[ADV_MAX_TID + 1]; /* first queued request */
3546 REQP q_last[ADV_MAX_TID + 1]; /* last queued request */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003548 short q_cur_cnt[ADV_MAX_TID + 1]; /* current queue count */
3549 short q_max_cnt[ADV_MAX_TID + 1]; /* maximum queue count */
3550 ADV_DCNT q_tot_cnt[ADV_MAX_TID + 1]; /* total enqueue count */
3551 ADV_DCNT q_tot_tim[ADV_MAX_TID + 1]; /* total time queued */
3552 ushort q_max_tim[ADV_MAX_TID + 1]; /* maximum time queued */
3553 ushort q_min_tim[ADV_MAX_TID + 1]; /* minimum time queued */
3554#endif /* ADVANSYS_STATS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555} asc_queue_t;
3556
3557/*
3558 * Adv Library Request Structures
3559 *
3560 * The following two structures are used to process Wide Board requests.
3561 *
3562 * The ADV_SCSI_REQ_Q structure in adv_req_t is passed to the Adv Library
3563 * and microcode with the ADV_SCSI_REQ_Q field 'srb_ptr' pointing to the
3564 * adv_req_t. The adv_req_t structure 'cmndp' field in turn points to the
3565 * Mid-Level SCSI request structure.
3566 *
3567 * Zero or more ADV_SG_BLOCK are used with each ADV_SCSI_REQ_Q. Each
3568 * ADV_SG_BLOCK structure holds 15 scatter-gather elements. Under Linux
3569 * up to 255 scatter-gather elements may be used per request or
3570 * ADV_SCSI_REQ_Q.
3571 *
3572 * Both structures must be 32 byte aligned.
3573 */
3574typedef struct adv_sgblk {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003575 ADV_SG_BLOCK sg_block; /* Sgblock structure. */
3576 uchar align[32]; /* Sgblock structure padding. */
3577 struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578} adv_sgblk_t;
3579
3580typedef struct adv_req {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003581 ADV_SCSI_REQ_Q scsi_req_q; /* Adv Library request structure. */
3582 uchar align[32]; /* Request structure padding. */
3583 struct scsi_cmnd *cmndp; /* Mid-Level SCSI command pointer. */
3584 adv_sgblk_t *sgblkp; /* Adv Library scatter-gather pointer. */
3585 struct adv_req *next_reqp; /* Next Request Structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003586} adv_req_t;
3587
3588/*
3589 * Structure allocated for each board.
3590 *
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06003591 * This structure is allocated by scsi_host_alloc() at the end
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592 * of the 'Scsi_Host' structure starting at the 'hostdata'
3593 * field. It is guaranteed to be allocated from DMA-able memory.
3594 */
3595typedef struct asc_board {
Matthew Wilcox394dbf32007-07-26 11:56:40 -04003596 struct device *dev;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003597 int id; /* Board Id */
3598 uint flags; /* Board flags */
3599 union {
3600 ASC_DVC_VAR asc_dvc_var; /* Narrow board */
3601 ADV_DVC_VAR adv_dvc_var; /* Wide board */
3602 } dvc_var;
3603 union {
3604 ASC_DVC_CFG asc_dvc_cfg; /* Narrow board */
3605 ADV_DVC_CFG adv_dvc_cfg; /* Wide board */
3606 } dvc_cfg;
3607 ushort asc_n_io_port; /* Number I/O ports. */
3608 asc_queue_t active; /* Active command queue */
3609 asc_queue_t waiting; /* Waiting command queue */
3610 asc_queue_t done; /* Done command queue */
3611 ADV_SCSI_BIT_ID_TYPE init_tidmask; /* Target init./valid mask */
3612 struct scsi_device *device[ADV_MAX_TID + 1]; /* Mid-Level Scsi Device */
3613 ushort reqcnt[ADV_MAX_TID + 1]; /* Starvation request count */
3614 ADV_SCSI_BIT_ID_TYPE queue_full; /* Queue full mask */
3615 ushort queue_full_cnt[ADV_MAX_TID + 1]; /* Queue full count */
3616 union {
3617 ASCEEP_CONFIG asc_eep; /* Narrow EEPROM config. */
3618 ADVEEP_3550_CONFIG adv_3550_eep; /* 3550 EEPROM config. */
3619 ADVEEP_38C0800_CONFIG adv_38C0800_eep; /* 38C0800 EEPROM config. */
3620 ADVEEP_38C1600_CONFIG adv_38C1600_eep; /* 38C1600 EEPROM config. */
3621 } eep_config;
3622 ulong last_reset; /* Saved last reset time */
3623 spinlock_t lock; /* Board spinlock */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003624 /* /proc/scsi/advansys/[0...] */
3625 char *prtbuf; /* /proc print buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003627 struct asc_stats asc_stats; /* Board statistics */
3628#endif /* ADVANSYS_STATS */
3629 /*
3630 * The following fields are used only for Narrow Boards.
3631 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003632 uchar sdtr_data[ASC_MAX_TID + 1]; /* SDTR information */
3633 /*
3634 * The following fields are used only for Wide Boards.
3635 */
3636 void __iomem *ioremap_addr; /* I/O Memory remap address. */
3637 ushort ioport; /* I/O Port address. */
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -06003638 ADV_CARR_T *carrp; /* ADV_CARR_T memory block. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003639 adv_req_t *orig_reqp; /* adv_req_t memory block. */
3640 adv_req_t *adv_reqp; /* Request structures. */
3641 adv_sgblk_t *adv_sgblkp; /* Scatter-gather structures. */
3642 ushort bios_signature; /* BIOS Signature. */
3643 ushort bios_version; /* BIOS Version. */
3644 ushort bios_codeseg; /* BIOS Code Segment. */
3645 ushort bios_codelen; /* BIOS Code Segment Length. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646} asc_board_t;
3647
Linus Torvalds1da177e2005-04-16 15:20:36 -07003648/* Number of boards detected in system. */
Matthew Wilcox78e77d82007-07-29 21:46:15 -06003649static int asc_board_count;
3650
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651/* Overrun buffer used by all narrow boards. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003652static uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653
3654/*
3655 * Global structures required to issue a command.
3656 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003657static ASC_SCSI_Q asc_scsi_q = { {0} };
3658static ASC_SG_HEAD asc_sg_head = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659
Linus Torvalds1da177e2005-04-16 15:20:36 -07003660#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003661static int asc_dbglvl = 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662#endif /* ADVANSYS_DEBUG */
3663
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664/*
3665 * --- Driver Function Prototypes
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666 */
3667
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003668static int advansys_slave_configure(struct scsi_device *);
3669static void asc_scsi_done_list(struct scsi_cmnd *);
3670static int asc_execute_scsi_cmnd(struct scsi_cmnd *);
3671static int asc_build_req(asc_board_t *, struct scsi_cmnd *);
3672static int adv_build_req(asc_board_t *, struct scsi_cmnd *, ADV_SCSI_REQ_Q **);
3673static int adv_get_sglist(asc_board_t *, adv_req_t *, struct scsi_cmnd *, int);
3674static void asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
3675static void adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
3676static void adv_async_callback(ADV_DVC_VAR *, uchar);
3677static void asc_enqueue(asc_queue_t *, REQP, int);
3678static REQP asc_dequeue(asc_queue_t *, int);
3679static REQP asc_dequeue_list(asc_queue_t *, REQP *, int);
3680static int asc_rmqueue(asc_queue_t *, REQP);
3681static void asc_execute_queue(asc_queue_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003682#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003683static int asc_proc_copy(off_t, off_t, char *, int, char *, int);
3684static int asc_prt_board_devices(struct Scsi_Host *, char *, int);
3685static int asc_prt_adv_bios(struct Scsi_Host *, char *, int);
3686static int asc_get_eeprom_string(ushort *serialnum, uchar *cp);
3687static int asc_prt_asc_board_eeprom(struct Scsi_Host *, char *, int);
3688static int asc_prt_adv_board_eeprom(struct Scsi_Host *, char *, int);
3689static int asc_prt_driver_conf(struct Scsi_Host *, char *, int);
3690static int asc_prt_asc_board_info(struct Scsi_Host *, char *, int);
3691static int asc_prt_adv_board_info(struct Scsi_Host *, char *, int);
3692static int asc_prt_line(char *, int, char *fmt, ...);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693#endif /* CONFIG_PROC_FS */
3694
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695/* Statistics function prototypes. */
3696#ifdef ADVANSYS_STATS
3697#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003698static int asc_prt_board_stats(struct Scsi_Host *, char *, int);
3699static int asc_prt_target_stats(struct Scsi_Host *, int, char *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700#endif /* CONFIG_PROC_FS */
3701#endif /* ADVANSYS_STATS */
3702
3703/* Debug function prototypes. */
3704#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003705static void asc_prt_scsi_host(struct Scsi_Host *);
3706static void asc_prt_scsi_cmnd(struct scsi_cmnd *);
3707static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *);
3708static void asc_prt_asc_dvc_var(ASC_DVC_VAR *);
3709static void asc_prt_asc_scsi_q(ASC_SCSI_Q *);
3710static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *);
3711static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *);
3712static void asc_prt_adv_dvc_var(ADV_DVC_VAR *);
3713static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *);
3714static void asc_prt_adv_sgblock(int, ADV_SG_BLOCK *);
3715static void asc_prt_hex(char *f, uchar *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716#endif /* ADVANSYS_DEBUG */
3717
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718#ifdef CONFIG_PROC_FS
3719/*
Matthew Wilcoxc304ec92007-07-30 09:18:45 -06003720 * advansys_proc_info() - /proc/scsi/advansys/{0,1,2,3,...}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003721 *
3722 * *buffer: I/O buffer
3723 * **start: if inout == FALSE pointer into buffer where user read should start
3724 * offset: current offset into a /proc/scsi/advansys/[0...] file
3725 * length: length of buffer
3726 * hostno: Scsi_Host host_no
3727 * inout: TRUE - user is writing; FALSE - user is reading
3728 *
3729 * Return the number of bytes read from or written to a
3730 * /proc/scsi/advansys/[0...] file.
3731 *
3732 * Note: This function uses the per board buffer 'prtbuf' which is
3733 * allocated when the board is initialized in advansys_detect(). The
3734 * buffer is ASC_PRTBUF_SIZE bytes. The function asc_proc_copy() is
3735 * used to write to the buffer. The way asc_proc_copy() is written
3736 * if 'prtbuf' is too small it will not be overwritten. Instead the
3737 * user just won't get all the available statistics.
3738 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07003739static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003740advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003741 off_t offset, int length, int inout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003742{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003743 asc_board_t *boardp;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003744 char *cp;
3745 int cplen;
3746 int cnt;
3747 int totcnt;
3748 int leftlen;
3749 char *curbuf;
3750 off_t advoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003752 int tgt_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003753#endif /* ADVANSYS_STATS */
3754
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003755 ASC_DBG(1, "advansys_proc_info: begin\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003757 /*
3758 * User write not supported.
3759 */
3760 if (inout == TRUE) {
3761 return (-ENOSYS);
3762 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003763
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003764 /*
3765 * User read of /proc/scsi/advansys/[0...] file.
3766 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003767
Matthew Wilcox2a437952007-07-26 11:00:51 -04003768 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003769
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003770 /* Copy read data starting at the beginning of the buffer. */
3771 *start = buffer;
3772 curbuf = buffer;
3773 advoffset = 0;
3774 totcnt = 0;
3775 leftlen = length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003776
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003777 /*
3778 * Get board configuration information.
3779 *
3780 * advansys_info() returns the board string from its own static buffer.
3781 */
Matthew Wilcox2a437952007-07-26 11:00:51 -04003782 cp = (char *)advansys_info(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003783 strcat(cp, "\n");
3784 cplen = strlen(cp);
3785 /* Copy board information. */
3786 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3787 totcnt += cnt;
3788 leftlen -= cnt;
3789 if (leftlen == 0) {
3790 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3791 return totcnt;
3792 }
3793 advoffset += cplen;
3794 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003795
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003796 /*
3797 * Display Wide Board BIOS Information.
3798 */
3799 if (ASC_WIDE_BOARD(boardp)) {
3800 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003801 cplen = asc_prt_adv_bios(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003802 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003803 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003804 cplen);
3805 totcnt += cnt;
3806 leftlen -= cnt;
3807 if (leftlen == 0) {
3808 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3809 return totcnt;
3810 }
3811 advoffset += cplen;
3812 curbuf += cnt;
3813 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003815 /*
3816 * Display driver information for each device attached to the board.
3817 */
3818 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003819 cplen = asc_prt_board_devices(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003820 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3821 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3822 totcnt += cnt;
3823 leftlen -= cnt;
3824 if (leftlen == 0) {
3825 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3826 return totcnt;
3827 }
3828 advoffset += cplen;
3829 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003830
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003831 /*
3832 * Display EEPROM configuration for the board.
3833 */
3834 cp = boardp->prtbuf;
3835 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003836 cplen = asc_prt_asc_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003837 } else {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003838 cplen = asc_prt_adv_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003839 }
3840 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3841 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3842 totcnt += cnt;
3843 leftlen -= cnt;
3844 if (leftlen == 0) {
3845 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3846 return totcnt;
3847 }
3848 advoffset += cplen;
3849 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003850
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003851 /*
3852 * Display driver configuration and information for the board.
3853 */
3854 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003855 cplen = asc_prt_driver_conf(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003856 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3857 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3858 totcnt += cnt;
3859 leftlen -= cnt;
3860 if (leftlen == 0) {
3861 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3862 return totcnt;
3863 }
3864 advoffset += cplen;
3865 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866
3867#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003868 /*
3869 * Display driver statistics for the board.
3870 */
3871 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003872 cplen = asc_prt_board_stats(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003873 ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
3874 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3875 totcnt += cnt;
3876 leftlen -= cnt;
3877 if (leftlen == 0) {
3878 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3879 return totcnt;
3880 }
3881 advoffset += cplen;
3882 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003883
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003884 /*
3885 * Display driver statistics for each target.
3886 */
3887 for (tgt_id = 0; tgt_id <= ADV_MAX_TID; tgt_id++) {
3888 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003889 cplen = asc_prt_target_stats(shost, tgt_id, cp,
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003890 ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003891 ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003892 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
3893 cplen);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003894 totcnt += cnt;
3895 leftlen -= cnt;
3896 if (leftlen == 0) {
3897 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3898 return totcnt;
3899 }
3900 advoffset += cplen;
3901 curbuf += cnt;
3902 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903#endif /* ADVANSYS_STATS */
3904
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003905 /*
3906 * Display Asc Library dynamic configuration information
3907 * for the board.
3908 */
3909 cp = boardp->prtbuf;
3910 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003911 cplen = asc_prt_asc_board_info(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003912 } else {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003913 cplen = asc_prt_adv_board_info(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003914 }
3915 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3916 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3917 totcnt += cnt;
3918 leftlen -= cnt;
3919 if (leftlen == 0) {
3920 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3921 return totcnt;
3922 }
3923 advoffset += cplen;
3924 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003925
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003926 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003927
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003928 return totcnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003929}
3930#endif /* CONFIG_PROC_FS */
3931
3932/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003933 * advansys_info()
3934 *
3935 * Return suitable for printing on the console with the argument
3936 * adapter's configuration information.
3937 *
3938 * Note: The information line should not exceed ASC_INFO_SIZE bytes,
3939 * otherwise the static 'info' array will be overrun.
3940 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003941static const char *advansys_info(struct Scsi_Host *shost)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003942{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003943 static char info[ASC_INFO_SIZE];
3944 asc_board_t *boardp;
3945 ASC_DVC_VAR *asc_dvc_varp;
3946 ADV_DVC_VAR *adv_dvc_varp;
3947 char *busname;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003948 char *widename = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003950 boardp = ASC_BOARDP(shost);
3951 if (ASC_NARROW_BOARD(boardp)) {
3952 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
3953 ASC_DBG(1, "advansys_info: begin\n");
3954 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
3955 if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) ==
3956 ASC_IS_ISAPNP) {
3957 busname = "ISA PnP";
3958 } else {
3959 busname = "ISA";
3960 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003961 sprintf(info,
3962 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X",
3963 ASC_VERSION, busname,
3964 (ulong)shost->io_port,
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04003965 (ulong)shost->io_port + ASC_IOADR_GAP - 1,
3966 shost->irq, shost->dma_channel);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003967 } else {
3968 if (asc_dvc_varp->bus_type & ASC_IS_VL) {
3969 busname = "VL";
3970 } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
3971 busname = "EISA";
3972 } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
3973 if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
3974 == ASC_IS_PCI_ULTRA) {
3975 busname = "PCI Ultra";
3976 } else {
3977 busname = "PCI";
3978 }
3979 } else {
3980 busname = "?";
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003981 ASC_PRINT2("advansys_info: board %d: unknown "
3982 "bus type %d\n", boardp->id,
3983 asc_dvc_varp->bus_type);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003984 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003985 sprintf(info,
3986 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X",
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003987 ASC_VERSION, busname, (ulong)shost->io_port,
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04003988 (ulong)shost->io_port + ASC_IOADR_GAP - 1,
3989 shost->irq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003990 }
3991 } else {
3992 /*
3993 * Wide Adapter Information
3994 *
3995 * Memory-mapped I/O is used instead of I/O space to access
3996 * the adapter, but display the I/O Port range. The Memory
3997 * I/O address is displayed through the driver /proc file.
3998 */
3999 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
4000 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004001 widename = "Ultra-Wide";
4002 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004003 widename = "Ultra2-Wide";
4004 } else {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004005 widename = "Ultra3-Wide";
4006 }
4007 sprintf(info,
4008 "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X",
4009 ASC_VERSION, widename, (ulong)adv_dvc_varp->iop_base,
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04004010 (ulong)adv_dvc_varp->iop_base + boardp->asc_n_io_port - 1, shost->irq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004011 }
4012 ASC_ASSERT(strlen(info) < ASC_INFO_SIZE);
4013 ASC_DBG(1, "advansys_info: end\n");
4014 return info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004015}
4016
4017/*
4018 * advansys_queuecommand() - interrupt-driven I/O entrypoint.
4019 *
4020 * This function always returns 0. Command return status is saved
4021 * in the 'scp' result field.
4022 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07004023static int
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004024advansys_queuecommand(struct scsi_cmnd *scp, void (*done) (struct scsi_cmnd *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004025{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004026 struct Scsi_Host *shost;
4027 asc_board_t *boardp;
4028 ulong flags;
4029 struct scsi_cmnd *done_scp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004030
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004031 shost = scp->device->host;
4032 boardp = ASC_BOARDP(shost);
4033 ASC_STATS(shost, queuecommand);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004035 /* host_lock taken by mid-level prior to call but need to protect */
4036 /* against own ISR */
4037 spin_lock_irqsave(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004038
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004039 /*
4040 * Block new commands while handling a reset or abort request.
4041 */
4042 if (boardp->flags & ASC_HOST_IN_RESET) {
4043 ASC_DBG1(1,
4044 "advansys_queuecommand: scp 0x%lx blocked for reset request\n",
4045 (ulong)scp);
4046 scp->result = HOST_BYTE(DID_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004047
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004048 /*
4049 * Add blocked requests to the board's 'done' queue. The queued
4050 * requests will be completed at the end of the abort or reset
4051 * handling.
4052 */
4053 asc_enqueue(&boardp->done, scp, ASC_BACK);
4054 spin_unlock_irqrestore(&boardp->lock, flags);
4055 return 0;
4056 }
4057
4058 /*
4059 * Attempt to execute any waiting commands for the board.
4060 */
4061 if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
4062 ASC_DBG(1,
4063 "advansys_queuecommand: before asc_execute_queue() waiting\n");
4064 asc_execute_queue(&boardp->waiting);
4065 }
4066
4067 /*
4068 * Save the function pointer to Linux mid-level 'done' function
4069 * and attempt to execute the command.
4070 *
4071 * If ASC_NOERROR is returned the request has been added to the
4072 * board's 'active' queue and will be completed by the interrupt
4073 * handler.
4074 *
4075 * If ASC_BUSY is returned add the request to the board's per
4076 * target waiting list. This is the first time the request has
4077 * been tried. Add it to the back of the waiting list. It will be
4078 * retried later.
4079 *
4080 * If an error occurred, the request will have been placed on the
4081 * board's 'done' queue and must be completed before returning.
4082 */
4083 scp->scsi_done = done;
4084 switch (asc_execute_scsi_cmnd(scp)) {
4085 case ASC_NOERROR:
4086 break;
4087 case ASC_BUSY:
4088 asc_enqueue(&boardp->waiting, scp, ASC_BACK);
4089 break;
4090 case ASC_ERROR:
4091 default:
4092 done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
4093 /* Interrupts could be enabled here. */
4094 asc_scsi_done_list(done_scp);
4095 break;
4096 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004097 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004098
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004099 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004100}
4101
4102/*
4103 * advansys_reset()
4104 *
4105 * Reset the bus associated with the command 'scp'.
4106 *
4107 * This function runs its own thread. Interrupts must be blocked but
4108 * sleeping is allowed and no locking other than for host structures is
4109 * required. Returns SUCCESS or FAILED.
4110 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004111static int advansys_reset(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004112{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004113 struct Scsi_Host *shost;
4114 asc_board_t *boardp;
4115 ASC_DVC_VAR *asc_dvc_varp;
4116 ADV_DVC_VAR *adv_dvc_varp;
4117 ulong flags;
4118 struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
4119 struct scsi_cmnd *tscp, *new_last_scp;
4120 int status;
4121 int ret = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004122
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004123 ASC_DBG1(1, "advansys_reset: 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004124
4125#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004126 if (scp->device->host != NULL) {
4127 ASC_STATS(scp->device->host, reset);
4128 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004129#endif /* ADVANSYS_STATS */
4130
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004131 if ((shost = scp->device->host) == NULL) {
4132 scp->result = HOST_BYTE(DID_ERROR);
4133 return FAILED;
4134 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004136 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004138 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset started...\n",
4139 boardp->id);
4140 /*
4141 * Check for re-entrancy.
4142 */
4143 spin_lock_irqsave(&boardp->lock, flags);
4144 if (boardp->flags & ASC_HOST_IN_RESET) {
4145 spin_unlock_irqrestore(&boardp->lock, flags);
4146 return FAILED;
4147 }
4148 boardp->flags |= ASC_HOST_IN_RESET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004149 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004151 if (ASC_NARROW_BOARD(boardp)) {
4152 /*
4153 * Narrow Board
4154 */
4155 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004157 /*
4158 * Reset the chip and SCSI bus.
4159 */
4160 ASC_DBG(1, "advansys_reset: before AscInitAsc1000Driver()\n");
4161 status = AscInitAsc1000Driver(asc_dvc_varp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004163 /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */
4164 if (asc_dvc_varp->err_code) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004165 ASC_PRINT2("advansys_reset: board %d: SCSI bus reset "
4166 "error: 0x%x\n", boardp->id,
4167 asc_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004168 ret = FAILED;
4169 } else if (status) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004170 ASC_PRINT2("advansys_reset: board %d: SCSI bus reset "
4171 "warning: 0x%x\n", boardp->id, status);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004172 } else {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004173 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset "
4174 "successful.\n", boardp->id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004175 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004177 ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
4178 spin_lock_irqsave(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004179
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004180 } else {
4181 /*
4182 * Wide Board
4183 *
4184 * If the suggest reset bus flags are set, then reset the bus.
4185 * Otherwise only reset the device.
4186 */
4187 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004189 /*
4190 * Reset the target's SCSI bus.
4191 */
4192 ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n");
4193 switch (AdvResetChipAndSB(adv_dvc_varp)) {
4194 case ASC_TRUE:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004195 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset "
4196 "successful.\n", boardp->id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004197 break;
4198 case ASC_FALSE:
4199 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004200 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset "
4201 "error.\n", boardp->id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004202 ret = FAILED;
4203 break;
4204 }
4205 spin_lock_irqsave(&boardp->lock, flags);
4206 (void)AdvISR(adv_dvc_varp);
4207 }
4208 /* Board lock is held. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004210 /*
4211 * Dequeue all board 'done' requests. A pointer to the last request
4212 * is returned in 'last_scp'.
4213 */
4214 done_scp = asc_dequeue_list(&boardp->done, &last_scp, ASC_TID_ALL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004216 /*
4217 * Dequeue all board 'active' requests for all devices and set
4218 * the request status to DID_RESET. A pointer to the last request
4219 * is returned in 'last_scp'.
4220 */
4221 if (done_scp == NULL) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004222 done_scp = asc_dequeue_list(&boardp->active, &last_scp,
4223 ASC_TID_ALL);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004224 for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
4225 tscp->result = HOST_BYTE(DID_RESET);
4226 }
4227 } else {
4228 /* Append to 'done_scp' at the end with 'last_scp'. */
4229 ASC_ASSERT(last_scp != NULL);
4230 last_scp->host_scribble =
4231 (unsigned char *)asc_dequeue_list(&boardp->active,
4232 &new_last_scp,
4233 ASC_TID_ALL);
4234 if (new_last_scp != NULL) {
4235 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4236 for (tscp = REQPNEXT(last_scp); tscp;
4237 tscp = REQPNEXT(tscp)) {
4238 tscp->result = HOST_BYTE(DID_RESET);
4239 }
4240 last_scp = new_last_scp;
4241 }
4242 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004243
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004244 /*
4245 * Dequeue all 'waiting' requests and set the request status
4246 * to DID_RESET.
4247 */
4248 if (done_scp == NULL) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004249 done_scp = asc_dequeue_list(&boardp->waiting, &last_scp,
4250 ASC_TID_ALL);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004251 for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
4252 tscp->result = HOST_BYTE(DID_RESET);
4253 }
4254 } else {
4255 /* Append to 'done_scp' at the end with 'last_scp'. */
4256 ASC_ASSERT(last_scp != NULL);
4257 last_scp->host_scribble =
4258 (unsigned char *)asc_dequeue_list(&boardp->waiting,
4259 &new_last_scp,
4260 ASC_TID_ALL);
4261 if (new_last_scp != NULL) {
4262 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4263 for (tscp = REQPNEXT(last_scp); tscp;
4264 tscp = REQPNEXT(tscp)) {
4265 tscp->result = HOST_BYTE(DID_RESET);
4266 }
4267 last_scp = new_last_scp;
4268 }
4269 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004271 /* Save the time of the most recently completed reset. */
4272 boardp->last_reset = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004274 /* Clear reset flag. */
4275 boardp->flags &= ~ASC_HOST_IN_RESET;
4276 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004277
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004278 /*
4279 * Complete all the 'done_scp' requests.
4280 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004281 if (done_scp)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004282 asc_scsi_done_list(done_scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004284 ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004285
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004286 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287}
4288
4289/*
4290 * advansys_biosparam()
4291 *
4292 * Translate disk drive geometry if the "BIOS greater than 1 GB"
4293 * support is enabled for a drive.
4294 *
4295 * ip (information pointer) is an int array with the following definition:
4296 * ip[0]: heads
4297 * ip[1]: sectors
4298 * ip[2]: cylinders
4299 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07004300static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004302 sector_t capacity, int ip[])
Linus Torvalds1da177e2005-04-16 15:20:36 -07004303{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004304 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004306 ASC_DBG(1, "advansys_biosparam: begin\n");
4307 ASC_STATS(sdev->host, biosparam);
4308 boardp = ASC_BOARDP(sdev->host);
4309 if (ASC_NARROW_BOARD(boardp)) {
4310 if ((boardp->dvc_var.asc_dvc_var.dvc_cntl &
4311 ASC_CNTL_BIOS_GT_1GB) && capacity > 0x200000) {
4312 ip[0] = 255;
4313 ip[1] = 63;
4314 } else {
4315 ip[0] = 64;
4316 ip[1] = 32;
4317 }
4318 } else {
4319 if ((boardp->dvc_var.adv_dvc_var.bios_ctrl &
4320 BIOS_CTRL_EXTENDED_XLAT) && capacity > 0x200000) {
4321 ip[0] = 255;
4322 ip[1] = 63;
4323 } else {
4324 ip[0] = 64;
4325 ip[1] = 32;
4326 }
4327 }
4328 ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
4329 ASC_DBG(1, "advansys_biosparam: end\n");
4330 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004331}
4332
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06004333static struct scsi_host_template advansys_template = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004334 .proc_name = "advansys",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004336 .proc_info = advansys_proc_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004337#endif
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004338 .name = "advansys",
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004339 .info = advansys_info,
4340 .queuecommand = advansys_queuecommand,
4341 .eh_bus_reset_handler = advansys_reset,
4342 .bios_param = advansys_biosparam,
4343 .slave_configure = advansys_slave_configure,
4344 /*
4345 * Because the driver may control an ISA adapter 'unchecked_isa_dma'
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06004346 * must be set. The flag will be cleared in advansys_board_found
4347 * for non-ISA adapters.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004348 */
4349 .unchecked_isa_dma = 1,
4350 /*
4351 * All adapters controlled by this driver are capable of large
4352 * scatter-gather lists. According to the mid-level SCSI documentation
4353 * this obviates any performance gain provided by setting
4354 * 'use_clustering'. But empirically while CPU utilization is increased
4355 * by enabling clustering, I/O throughput increases as well.
4356 */
4357 .use_clustering = ENABLE_CLUSTERING,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004359
Linus Torvalds1da177e2005-04-16 15:20:36 -07004360/*
4361 * --- Miscellaneous Driver Functions
4362 */
4363
4364/*
4365 * First-level interrupt handler.
4366 *
4367 * 'dev_id' is a pointer to the interrupting adapter's asc_board_t. Because
4368 * all boards are currently checked for interrupts on each interrupt, 'dev_id'
4369 * is not referenced. 'dev_id' could be used to identify an interrupt passed
4370 * to the AdvanSys driver which is for a device sharing an interrupt with
4371 * an AdvanSys adapter.
4372 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004373static irqreturn_t advansys_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374{
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004375 unsigned long flags;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004376 struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
4377 struct scsi_cmnd *new_last_scp;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004378 struct Scsi_Host *shost = dev_id;
4379 asc_board_t *boardp = ASC_BOARDP(shost);
4380 irqreturn_t result = IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004382 ASC_DBG1(2, "advansys_interrupt: boardp 0x%p\n", boardp);
4383 spin_lock_irqsave(&boardp->lock, flags);
4384 if (ASC_NARROW_BOARD(boardp)) {
4385 /*
4386 * Narrow Board
4387 */
4388 if (AscIsIntPending(shost->io_port)) {
4389 result = IRQ_HANDLED;
4390 ASC_STATS(shost, interrupt);
4391 ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
4392 AscISR(&boardp->dvc_var.asc_dvc_var);
4393 }
4394 } else {
4395 /*
4396 * Wide Board
4397 */
4398 ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
4399 if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
4400 result = IRQ_HANDLED;
4401 ASC_STATS(shost, interrupt);
4402 }
4403 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004404
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004405 /*
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004406 * Start waiting requests and create a list of completed requests.
4407 *
4408 * If a reset request is being performed for the board, the reset
4409 * handler will complete pending requests after it has completed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004410 */
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004411 if ((boardp->flags & ASC_HOST_IN_RESET) == 0) {
4412 ASC_DBG2(1, "advansys_interrupt: done_scp 0x%p, "
4413 "last_scp 0x%p\n", done_scp, last_scp);
4414
4415 /* Start any waiting commands for the board. */
4416 if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
4417 ASC_DBG(1, "advansys_interrupt: before "
4418 "asc_execute_queue()\n");
4419 asc_execute_queue(&boardp->waiting);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004420 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004422 /*
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004423 * Add to the list of requests that must be completed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004424 *
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004425 * 'done_scp' will always be NULL on the first iteration of
4426 * this loop. 'last_scp' is set at the same time as 'done_scp'.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004427 */
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004428 if (done_scp == NULL) {
4429 done_scp = asc_dequeue_list(&boardp->done,
4430 &last_scp, ASC_TID_ALL);
4431 } else {
4432 ASC_ASSERT(last_scp != NULL);
4433 last_scp->host_scribble =
4434 (unsigned char *)asc_dequeue_list(&boardp->
4435 done,
4436 &new_last_scp,
4437 ASC_TID_ALL);
4438 if (new_last_scp != NULL) {
4439 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4440 last_scp = new_last_scp;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004441 }
4442 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004443 }
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004444 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004445
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004446 /*
4447 * If interrupts were enabled on entry, then they
4448 * are now enabled here.
4449 *
4450 * Complete all requests on the done list.
4451 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004453 asc_scsi_done_list(done_scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004455 ASC_DBG(1, "advansys_interrupt: end\n");
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004456 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004457}
4458
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004459static void
4460advansys_narrow_slave_configure(struct scsi_device *sdev, ASC_DVC_VAR *asc_dvc)
4461{
4462 ASC_SCSI_BIT_ID_TYPE tid_bit = 1 << sdev->id;
4463 ASC_SCSI_BIT_ID_TYPE orig_use_tagged_qng = asc_dvc->use_tagged_qng;
4464
4465 if (sdev->lun == 0) {
4466 ASC_SCSI_BIT_ID_TYPE orig_init_sdtr = asc_dvc->init_sdtr;
4467 if ((asc_dvc->cfg->sdtr_enable & tid_bit) && sdev->sdtr) {
4468 asc_dvc->init_sdtr |= tid_bit;
4469 } else {
4470 asc_dvc->init_sdtr &= ~tid_bit;
4471 }
4472
4473 if (orig_init_sdtr != asc_dvc->init_sdtr)
4474 AscAsyncFix(asc_dvc, sdev);
4475 }
4476
4477 if (sdev->tagged_supported) {
4478 if (asc_dvc->cfg->cmd_qng_enabled & tid_bit) {
4479 if (sdev->lun == 0) {
4480 asc_dvc->cfg->can_tagged_qng |= tid_bit;
4481 asc_dvc->use_tagged_qng |= tid_bit;
4482 }
4483 scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
4484 asc_dvc->max_dvc_qng[sdev->id]);
4485 }
4486 } else {
4487 if (sdev->lun == 0) {
4488 asc_dvc->cfg->can_tagged_qng &= ~tid_bit;
4489 asc_dvc->use_tagged_qng &= ~tid_bit;
4490 }
4491 scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
4492 }
4493
4494 if ((sdev->lun == 0) &&
4495 (orig_use_tagged_qng != asc_dvc->use_tagged_qng)) {
4496 AscWriteLramByte(asc_dvc->iop_base, ASCV_DISC_ENABLE_B,
4497 asc_dvc->cfg->disc_enable);
4498 AscWriteLramByte(asc_dvc->iop_base, ASCV_USE_TAGGED_QNG_B,
4499 asc_dvc->use_tagged_qng);
4500 AscWriteLramByte(asc_dvc->iop_base, ASCV_CAN_TAGGED_QNG_B,
4501 asc_dvc->cfg->can_tagged_qng);
4502
4503 asc_dvc->max_dvc_qng[sdev->id] =
4504 asc_dvc->cfg->max_tag_qng[sdev->id];
4505 AscWriteLramByte(asc_dvc->iop_base,
4506 (ushort)(ASCV_MAX_DVC_QNG_BEG + sdev->id),
4507 asc_dvc->max_dvc_qng[sdev->id]);
4508 }
4509}
4510
4511/*
4512 * Wide Transfers
4513 *
4514 * If the EEPROM enabled WDTR for the device and the device supports wide
4515 * bus (16 bit) transfers, then turn on the device's 'wdtr_able' bit and
4516 * write the new value to the microcode.
4517 */
4518static void
4519advansys_wide_enable_wdtr(AdvPortAddr iop_base, unsigned short tidmask)
4520{
4521 unsigned short cfg_word;
4522 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
4523 if ((cfg_word & tidmask) != 0)
4524 return;
4525
4526 cfg_word |= tidmask;
4527 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
4528
4529 /*
4530 * Clear the microcode SDTR and WDTR negotiation done indicators for
4531 * the target to cause it to negotiate with the new setting set above.
4532 * WDTR when accepted causes the target to enter asynchronous mode, so
4533 * SDTR must be negotiated.
4534 */
4535 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
4536 cfg_word &= ~tidmask;
4537 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
4538 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
4539 cfg_word &= ~tidmask;
4540 AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
4541}
4542
4543/*
4544 * Synchronous Transfers
4545 *
4546 * If the EEPROM enabled SDTR for the device and the device
4547 * supports synchronous transfers, then turn on the device's
4548 * 'sdtr_able' bit. Write the new value to the microcode.
4549 */
4550static void
4551advansys_wide_enable_sdtr(AdvPortAddr iop_base, unsigned short tidmask)
4552{
4553 unsigned short cfg_word;
4554 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
4555 if ((cfg_word & tidmask) != 0)
4556 return;
4557
4558 cfg_word |= tidmask;
4559 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
4560
4561 /*
4562 * Clear the microcode "SDTR negotiation" done indicator for the
4563 * target to cause it to negotiate with the new setting set above.
4564 */
4565 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
4566 cfg_word &= ~tidmask;
4567 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
4568}
4569
4570/*
4571 * PPR (Parallel Protocol Request) Capable
4572 *
4573 * If the device supports DT mode, then it must be PPR capable.
4574 * The PPR message will be used in place of the SDTR and WDTR
4575 * messages to negotiate synchronous speed and offset, transfer
4576 * width, and protocol options.
4577 */
4578static void advansys_wide_enable_ppr(ADV_DVC_VAR *adv_dvc,
4579 AdvPortAddr iop_base, unsigned short tidmask)
4580{
4581 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able);
4582 adv_dvc->ppr_able |= tidmask;
4583 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able);
4584}
4585
4586static void
4587advansys_wide_slave_configure(struct scsi_device *sdev, ADV_DVC_VAR *adv_dvc)
4588{
4589 AdvPortAddr iop_base = adv_dvc->iop_base;
4590 unsigned short tidmask = 1 << sdev->id;
4591
4592 if (sdev->lun == 0) {
4593 /*
4594 * Handle WDTR, SDTR, and Tag Queuing. If the feature
4595 * is enabled in the EEPROM and the device supports the
4596 * feature, then enable it in the microcode.
4597 */
4598
4599 if ((adv_dvc->wdtr_able & tidmask) && sdev->wdtr)
4600 advansys_wide_enable_wdtr(iop_base, tidmask);
4601 if ((adv_dvc->sdtr_able & tidmask) && sdev->sdtr)
4602 advansys_wide_enable_sdtr(iop_base, tidmask);
4603 if (adv_dvc->chip_type == ADV_CHIP_ASC38C1600 && sdev->ppr)
4604 advansys_wide_enable_ppr(adv_dvc, iop_base, tidmask);
4605
4606 /*
4607 * Tag Queuing is disabled for the BIOS which runs in polled
4608 * mode and would see no benefit from Tag Queuing. Also by
4609 * disabling Tag Queuing in the BIOS devices with Tag Queuing
4610 * bugs will at least work with the BIOS.
4611 */
4612 if ((adv_dvc->tagqng_able & tidmask) &&
4613 sdev->tagged_supported) {
4614 unsigned short cfg_word;
4615 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
4616 cfg_word |= tidmask;
4617 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
4618 cfg_word);
4619 AdvWriteByteLram(iop_base,
4620 ASC_MC_NUMBER_OF_MAX_CMD + sdev->id,
4621 adv_dvc->max_dvc_qng);
4622 }
4623 }
4624
4625 if ((adv_dvc->tagqng_able & tidmask) && sdev->tagged_supported) {
4626 scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
4627 adv_dvc->max_dvc_qng);
4628 } else {
4629 scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
4630 }
4631}
4632
Linus Torvalds1da177e2005-04-16 15:20:36 -07004633/*
4634 * Set the number of commands to queue per device for the
4635 * specified host adapter.
4636 */
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004637static int advansys_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638{
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004639 asc_board_t *boardp = ASC_BOARDP(sdev->host);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004640 boardp->flags |= ASC_SELECT_QUEUE_DEPTHS;
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004641
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004642 /*
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004643 * Save a pointer to the sdev and set its initial/maximum
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004644 * queue depth. Only save the pointer for a lun0 dev though.
4645 */
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004646 if (sdev->lun == 0)
4647 boardp->device[sdev->id] = sdev;
4648
4649 if (ASC_NARROW_BOARD(boardp))
4650 advansys_narrow_slave_configure(sdev,
4651 &boardp->dvc_var.asc_dvc_var);
4652 else
4653 advansys_wide_slave_configure(sdev,
4654 &boardp->dvc_var.adv_dvc_var);
4655
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004656 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657}
4658
4659/*
4660 * Complete all requests on the singly linked list pointed
4661 * to by 'scp'.
4662 *
4663 * Interrupts can be enabled on entry.
4664 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004665static void asc_scsi_done_list(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004667 struct scsi_cmnd *tscp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004668
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004669 ASC_DBG(2, "asc_scsi_done_list: begin\n");
4670 while (scp != NULL) {
4671 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004672
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004673 ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lx\n", (ulong)scp);
4674 tscp = REQPNEXT(scp);
4675 scp->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004676
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004677 boardp = ASC_BOARDP(scp->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004678
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004679 if (scp->use_sg)
Matthew Wilcox394dbf32007-07-26 11:56:40 -04004680 dma_unmap_sg(boardp->dev,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004681 (struct scatterlist *)scp->request_buffer,
4682 scp->use_sg, scp->sc_data_direction);
4683 else if (scp->request_bufflen)
Matthew Wilcox394dbf32007-07-26 11:56:40 -04004684 dma_unmap_single(boardp->dev, scp->SCp.dma_handle,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004685 scp->request_bufflen,
4686 scp->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004687
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004688 ASC_STATS(scp->device->host, done);
4689 ASC_ASSERT(scp->scsi_done != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004690
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004691 scp->scsi_done(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004692
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004693 scp = tscp;
4694 }
4695 ASC_DBG(2, "asc_scsi_done_list: done\n");
4696 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004697}
4698
4699/*
4700 * Execute a single 'Scsi_Cmnd'.
4701 *
4702 * The function 'done' is called when the request has been completed.
4703 *
4704 * Scsi_Cmnd:
4705 *
4706 * host - board controlling device
4707 * device - device to send command
4708 * target - target of device
4709 * lun - lun of device
4710 * cmd_len - length of SCSI CDB
4711 * cmnd - buffer for SCSI 8, 10, or 12 byte CDB
4712 * use_sg - if non-zero indicates scatter-gather request with use_sg elements
4713 *
4714 * if (use_sg == 0) {
4715 * request_buffer - buffer address for request
4716 * request_bufflen - length of request buffer
4717 * } else {
4718 * request_buffer - pointer to scatterlist structure
4719 * }
4720 *
4721 * sense_buffer - sense command buffer
4722 *
4723 * result (4 bytes of an int):
4724 * Byte Meaning
4725 * 0 SCSI Status Byte Code
4726 * 1 SCSI One Byte Message Code
4727 * 2 Host Error Code
4728 * 3 Mid-Level Error Code
4729 *
4730 * host driver fields:
4731 * SCp - Scsi_Pointer used for command processing status
4732 * scsi_done - used to save caller's done function
4733 * host_scribble - used for pointer to another struct scsi_cmnd
4734 *
4735 * If this function returns ASC_NOERROR the request has been enqueued
4736 * on the board's 'active' queue and will be completed from the
4737 * interrupt handler.
4738 *
4739 * If this function returns ASC_NOERROR the request has been enqueued
4740 * on the board's 'done' queue and must be completed by the caller.
4741 *
4742 * If ASC_BUSY is returned the request will be enqueued by the
4743 * caller on the target's waiting queue and re-tried later.
4744 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004745static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004746{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004747 asc_board_t *boardp;
4748 ASC_DVC_VAR *asc_dvc_varp;
4749 ADV_DVC_VAR *adv_dvc_varp;
4750 ADV_SCSI_REQ_Q *adv_scsiqp;
4751 struct scsi_device *device;
4752 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004753
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004754 ASC_DBG2(1, "asc_execute_scsi_cmnd: scp 0x%lx, done 0x%lx\n",
4755 (ulong)scp, (ulong)scp->scsi_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004756
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004757 boardp = ASC_BOARDP(scp->device->host);
4758 device = boardp->device[scp->device->id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004760 if (ASC_NARROW_BOARD(boardp)) {
4761 /*
4762 * Build and execute Narrow Board request.
4763 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004764
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004765 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004766
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004767 /*
4768 * Build Asc Library request structure using the
4769 * global structures 'asc_scsi_req' and 'asc_sg_head'.
4770 *
4771 * If an error is returned, then the request has been
4772 * queued on the board done queue. It will be completed
4773 * by the caller.
4774 *
4775 * asc_build_req() can not return ASC_BUSY.
4776 */
4777 if (asc_build_req(boardp, scp) == ASC_ERROR) {
4778 ASC_STATS(scp->device->host, build_error);
4779 return ASC_ERROR;
4780 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004782 /*
4783 * Execute the command. If there is no error, add the command
4784 * to the active queue.
4785 */
4786 switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
4787 case ASC_NOERROR:
4788 ASC_STATS(scp->device->host, exe_noerror);
4789 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004790 * Increment monotonically increasing per device
4791 * successful request counter. Wrapping doesn't matter.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004792 */
4793 boardp->reqcnt[scp->device->id]++;
4794 asc_enqueue(&boardp->active, scp, ASC_BACK);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004795 ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue(), "
4796 "ASC_NOERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004797 break;
4798 case ASC_BUSY:
4799 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004800 * Caller will enqueue request on the target's waiting
4801 * queue and retry later.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004802 */
4803 ASC_STATS(scp->device->host, exe_busy);
4804 break;
4805 case ASC_ERROR:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004806 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
4807 "AscExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
4808 boardp->id, asc_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004809 ASC_STATS(scp->device->host, exe_error);
4810 scp->result = HOST_BYTE(DID_ERROR);
4811 asc_enqueue(&boardp->done, scp, ASC_BACK);
4812 break;
4813 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004814 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
4815 "AscExeScsiQueue() unknown, err_code 0x%x\n",
4816 boardp->id, asc_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004817 ASC_STATS(scp->device->host, exe_unknown);
4818 scp->result = HOST_BYTE(DID_ERROR);
4819 asc_enqueue(&boardp->done, scp, ASC_BACK);
4820 break;
4821 }
4822 } else {
4823 /*
4824 * Build and execute Wide Board request.
4825 */
4826 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004828 /*
4829 * Build and get a pointer to an Adv Library request structure.
4830 *
4831 * If the request is successfully built then send it below,
4832 * otherwise return with an error.
4833 */
4834 switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
4835 case ASC_NOERROR:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004836 ASC_DBG(3, "asc_execute_scsi_cmnd: adv_build_req "
4837 "ASC_NOERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004838 break;
4839 case ASC_BUSY:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004840 ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req "
4841 "ASC_BUSY\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004842 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004843 * If busy is returned the request has not been
4844 * enqueued. It will be enqueued by the caller on the
4845 * target's waiting queue and retried later.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004846 *
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004847 * The asc_stats fields 'adv_build_noreq' and
4848 * 'adv_build_nosg' count wide board busy conditions.
4849 * They are updated in adv_build_req and
4850 * adv_get_sglist, respectively.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004851 */
4852 return ASC_BUSY;
4853 case ASC_ERROR:
4854 /*
4855 * If an error is returned, then the request has been
4856 * queued on the board done queue. It will be completed
4857 * by the caller.
4858 */
4859 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004860 ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req "
4861 "ASC_ERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004862 ASC_STATS(scp->device->host, build_error);
4863 return ASC_ERROR;
4864 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004866 /*
4867 * Execute the command. If there is no error, add the command
4868 * to the active queue.
4869 */
4870 switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) {
4871 case ASC_NOERROR:
4872 ASC_STATS(scp->device->host, exe_noerror);
4873 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004874 * Increment monotonically increasing per device
4875 * successful request counter. Wrapping doesn't matter.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004876 */
4877 boardp->reqcnt[scp->device->id]++;
4878 asc_enqueue(&boardp->active, scp, ASC_BACK);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004879 ASC_DBG(1, "asc_execute_scsi_cmnd: AdvExeScsiQueue(), "
4880 "ASC_NOERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004881 break;
4882 case ASC_BUSY:
4883 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004884 * Caller will enqueue request on the target's waiting
4885 * queue and retry later.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004886 */
4887 ASC_STATS(scp->device->host, exe_busy);
4888 break;
4889 case ASC_ERROR:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004890 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
4891 "AdvExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
4892 boardp->id, adv_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004893 ASC_STATS(scp->device->host, exe_error);
4894 scp->result = HOST_BYTE(DID_ERROR);
4895 asc_enqueue(&boardp->done, scp, ASC_BACK);
4896 break;
4897 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004898 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
4899 "AdvExeScsiQueue() unknown, err_code 0x%x\n",
4900 boardp->id, adv_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004901 ASC_STATS(scp->device->host, exe_unknown);
4902 scp->result = HOST_BYTE(DID_ERROR);
4903 asc_enqueue(&boardp->done, scp, ASC_BACK);
4904 break;
4905 }
4906 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004907
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004908 ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
4909 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910}
4911
4912/*
4913 * Build a request structure for the Asc Library (Narrow Board).
4914 *
4915 * The global structures 'asc_scsi_q' and 'asc_sg_head' are
4916 * used to build the request.
4917 *
4918 * If an error occurs, then queue the request on the board done
4919 * queue and return ASC_ERROR.
4920 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004921static int asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004922{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004923 /*
4924 * Mutually exclusive access is required to 'asc_scsi_q' and
4925 * 'asc_sg_head' until after the request is started.
4926 */
4927 memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004928
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004929 /*
4930 * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'.
4931 */
4932 asc_scsi_q.q2.srb_ptr = ASC_VADDR_TO_U32(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004933
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004934 /*
4935 * Build the ASC_SCSI_Q request.
4936 *
4937 * For narrow boards a CDB length maximum of 12 bytes
4938 * is supported.
4939 */
4940 if (scp->cmd_len > ASC_MAX_CDB_LEN) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004941 ASC_PRINT3("asc_build_req: board %d: cmd_len %d > "
4942 "ASC_MAX_CDB_LEN %d\n", boardp->id, scp->cmd_len,
4943 ASC_MAX_CDB_LEN);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004944 scp->result = HOST_BYTE(DID_ERROR);
4945 asc_enqueue(&boardp->done, scp, ASC_BACK);
4946 return ASC_ERROR;
4947 }
4948 asc_scsi_q.cdbptr = &scp->cmnd[0];
4949 asc_scsi_q.q2.cdb_len = scp->cmd_len;
4950 asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id);
4951 asc_scsi_q.q1.target_lun = scp->device->lun;
4952 asc_scsi_q.q2.target_ix =
4953 ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
4954 asc_scsi_q.q1.sense_addr =
4955 cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
4956 asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004957
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004958 /*
4959 * If there are any outstanding requests for the current target,
4960 * then every 255th request send an ORDERED request. This heuristic
4961 * tries to retain the benefit of request sorting while preventing
4962 * request starvation. 255 is the max number of tags or pending commands
4963 * a device may have outstanding.
4964 *
4965 * The request count is incremented below for every successfully
4966 * started request.
4967 *
4968 */
4969 if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->device->id] > 0) &&
4970 (boardp->reqcnt[scp->device->id] % 255) == 0) {
4971 asc_scsi_q.q2.tag_code = MSG_ORDERED_TAG;
4972 } else {
4973 asc_scsi_q.q2.tag_code = MSG_SIMPLE_TAG;
4974 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004975
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004976 /*
4977 * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
4978 * buffer command.
4979 */
4980 if (scp->use_sg == 0) {
4981 /*
4982 * CDB request of single contiguous buffer.
4983 */
4984 ASC_STATS(scp->device->host, cont_cnt);
4985 scp->SCp.dma_handle = scp->request_bufflen ?
Matthew Wilcox394dbf32007-07-26 11:56:40 -04004986 dma_map_single(boardp->dev, scp->request_buffer,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004987 scp->request_bufflen,
4988 scp->sc_data_direction) : 0;
4989 asc_scsi_q.q1.data_addr = cpu_to_le32(scp->SCp.dma_handle);
4990 asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen);
4991 ASC_STATS_ADD(scp->device->host, cont_xfer,
4992 ASC_CEILING(scp->request_bufflen, 512));
4993 asc_scsi_q.q1.sg_queue_cnt = 0;
4994 asc_scsi_q.sg_head = NULL;
4995 } else {
4996 /*
4997 * CDB scatter-gather request list.
4998 */
4999 int sgcnt;
5000 int use_sg;
5001 struct scatterlist *slp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005002
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005003 slp = (struct scatterlist *)scp->request_buffer;
Matthew Wilcox394dbf32007-07-26 11:56:40 -04005004 use_sg = dma_map_sg(boardp->dev, slp, scp->use_sg,
5005 scp->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005006
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005007 if (use_sg > scp->device->host->sg_tablesize) {
Matthew Wilcox394dbf32007-07-26 11:56:40 -04005008 ASC_PRINT3("asc_build_req: board %d: use_sg %d > "
5009 "sg_tablesize %d\n", boardp->id, use_sg,
5010 scp->device->host->sg_tablesize);
5011 dma_unmap_sg(boardp->dev, slp, scp->use_sg,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005012 scp->sc_data_direction);
5013 scp->result = HOST_BYTE(DID_ERROR);
5014 asc_enqueue(&boardp->done, scp, ASC_BACK);
5015 return ASC_ERROR;
5016 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005017
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005018 ASC_STATS(scp->device->host, sg_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005019
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005020 /*
5021 * Use global ASC_SG_HEAD structure and set the ASC_SCSI_Q
5022 * structure to point to it.
5023 */
5024 memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005025
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005026 asc_scsi_q.q1.cntl |= QC_SG_HEAD;
5027 asc_scsi_q.sg_head = &asc_sg_head;
5028 asc_scsi_q.q1.data_cnt = 0;
5029 asc_scsi_q.q1.data_addr = 0;
5030 /* This is a byte value, otherwise it would need to be swapped. */
5031 asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = use_sg;
5032 ASC_STATS_ADD(scp->device->host, sg_elem,
5033 asc_sg_head.entry_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005034
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005035 /*
5036 * Convert scatter-gather list into ASC_SG_HEAD list.
5037 */
5038 for (sgcnt = 0; sgcnt < use_sg; sgcnt++, slp++) {
5039 asc_sg_head.sg_list[sgcnt].addr =
5040 cpu_to_le32(sg_dma_address(slp));
5041 asc_sg_head.sg_list[sgcnt].bytes =
5042 cpu_to_le32(sg_dma_len(slp));
5043 ASC_STATS_ADD(scp->device->host, sg_xfer,
5044 ASC_CEILING(sg_dma_len(slp), 512));
5045 }
5046 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005047
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005048 ASC_DBG_PRT_ASC_SCSI_Q(2, &asc_scsi_q);
5049 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005050
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005051 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005052}
5053
5054/*
5055 * Build a request structure for the Adv Library (Wide Board).
5056 *
5057 * If an adv_req_t can not be allocated to issue the request,
5058 * then return ASC_BUSY. If an error occurs, then return ASC_ERROR.
5059 *
5060 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the
5061 * microcode for DMA addresses or math operations are byte swapped
5062 * to little-endian order.
5063 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005064static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005065adv_build_req(asc_board_t *boardp, struct scsi_cmnd *scp,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005066 ADV_SCSI_REQ_Q **adv_scsiqpp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005067{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005068 adv_req_t *reqp;
5069 ADV_SCSI_REQ_Q *scsiqp;
5070 int i;
5071 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005072
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005073 /*
5074 * Allocate an adv_req_t structure from the board to execute
5075 * the command.
5076 */
5077 if (boardp->adv_reqp == NULL) {
5078 ASC_DBG(1, "adv_build_req: no free adv_req_t\n");
5079 ASC_STATS(scp->device->host, adv_build_noreq);
5080 return ASC_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005081 } else {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005082 reqp = boardp->adv_reqp;
5083 boardp->adv_reqp = reqp->next_reqp;
5084 reqp->next_reqp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005085 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005086
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005087 /*
5088 * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
5089 */
5090 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005091
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005092 /*
5093 * Initialize the structure.
5094 */
5095 scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005096
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005097 /*
5098 * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
5099 */
5100 scsiqp->srb_ptr = ASC_VADDR_TO_U32(reqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005101
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005102 /*
5103 * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure.
5104 */
5105 reqp->cmndp = scp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005106
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005107 /*
5108 * Build the ADV_SCSI_REQ_Q request.
5109 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005110
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005111 /*
5112 * Set CDB length and copy it to the request structure.
5113 * For wide boards a CDB length maximum of 16 bytes
5114 * is supported.
5115 */
5116 if (scp->cmd_len > ADV_MAX_CDB_LEN) {
5117 ASC_PRINT3
5118 ("adv_build_req: board %d: cmd_len %d > ADV_MAX_CDB_LEN %d\n",
5119 boardp->id, scp->cmd_len, ADV_MAX_CDB_LEN);
5120 scp->result = HOST_BYTE(DID_ERROR);
5121 asc_enqueue(&boardp->done, scp, ASC_BACK);
5122 return ASC_ERROR;
5123 }
5124 scsiqp->cdb_len = scp->cmd_len;
5125 /* Copy first 12 CDB bytes to cdb[]. */
5126 for (i = 0; i < scp->cmd_len && i < 12; i++) {
5127 scsiqp->cdb[i] = scp->cmnd[i];
5128 }
5129 /* Copy last 4 CDB bytes, if present, to cdb16[]. */
5130 for (; i < scp->cmd_len; i++) {
5131 scsiqp->cdb16[i - 12] = scp->cmnd[i];
5132 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005133
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005134 scsiqp->target_id = scp->device->id;
5135 scsiqp->target_lun = scp->device->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005136
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005137 scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
5138 scsiqp->sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005139
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005140 /*
5141 * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather
5142 * buffer command.
5143 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005144
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005145 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
5146 scsiqp->vdata_addr = scp->request_buffer;
5147 scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer));
5148
5149 if (scp->use_sg == 0) {
5150 /*
5151 * CDB request of single contiguous buffer.
5152 */
5153 reqp->sgblkp = NULL;
5154 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
5155 if (scp->request_bufflen) {
5156 scsiqp->vdata_addr = scp->request_buffer;
5157 scp->SCp.dma_handle =
Matthew Wilcox394dbf32007-07-26 11:56:40 -04005158 dma_map_single(boardp->dev, scp->request_buffer,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005159 scp->request_bufflen,
5160 scp->sc_data_direction);
5161 } else {
5162 scsiqp->vdata_addr = NULL;
5163 scp->SCp.dma_handle = 0;
5164 }
5165 scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle);
5166 scsiqp->sg_list_ptr = NULL;
5167 scsiqp->sg_real_addr = 0;
5168 ASC_STATS(scp->device->host, cont_cnt);
5169 ASC_STATS_ADD(scp->device->host, cont_xfer,
5170 ASC_CEILING(scp->request_bufflen, 512));
5171 } else {
5172 /*
5173 * CDB scatter-gather request list.
5174 */
5175 struct scatterlist *slp;
5176 int use_sg;
5177
5178 slp = (struct scatterlist *)scp->request_buffer;
Matthew Wilcox394dbf32007-07-26 11:56:40 -04005179 use_sg = dma_map_sg(boardp->dev, slp, scp->use_sg,
5180 scp->sc_data_direction);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005181
5182 if (use_sg > ADV_MAX_SG_LIST) {
Matthew Wilcox394dbf32007-07-26 11:56:40 -04005183 ASC_PRINT3("adv_build_req: board %d: use_sg %d > "
5184 "ADV_MAX_SG_LIST %d\n", boardp->id, use_sg,
5185 scp->device->host->sg_tablesize);
5186 dma_unmap_sg(boardp->dev, slp, scp->use_sg,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005187 scp->sc_data_direction);
5188 scp->result = HOST_BYTE(DID_ERROR);
5189 asc_enqueue(&boardp->done, scp, ASC_BACK);
5190
5191 /*
Matthew Wilcox394dbf32007-07-26 11:56:40 -04005192 * Free the 'adv_req_t' structure by adding it back
5193 * to the board free list.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005194 */
5195 reqp->next_reqp = boardp->adv_reqp;
5196 boardp->adv_reqp = reqp;
5197
5198 return ASC_ERROR;
5199 }
5200
Matthew Wilcox394dbf32007-07-26 11:56:40 -04005201 ret = adv_get_sglist(boardp, reqp, scp, use_sg);
5202 if (ret != ADV_SUCCESS) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005203 /*
Matthew Wilcox394dbf32007-07-26 11:56:40 -04005204 * Free the adv_req_t structure by adding it back to
5205 * the board free list.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005206 */
5207 reqp->next_reqp = boardp->adv_reqp;
5208 boardp->adv_reqp = reqp;
5209
5210 return ret;
5211 }
5212
5213 ASC_STATS(scp->device->host, sg_cnt);
5214 ASC_STATS_ADD(scp->device->host, sg_elem, use_sg);
5215 }
5216
5217 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
5218 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
5219
5220 *adv_scsiqpp = scsiqp;
5221
5222 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005223}
5224
5225/*
5226 * Build scatter-gather list for Adv Library (Wide Board).
5227 *
5228 * Additional ADV_SG_BLOCK structures will need to be allocated
5229 * if the total number of scatter-gather elements exceeds
5230 * NO_OF_SG_PER_BLOCK (15). The ADV_SG_BLOCK structures are
5231 * assumed to be physically contiguous.
5232 *
5233 * Return:
5234 * ADV_SUCCESS(1) - SG List successfully created
5235 * ADV_ERROR(-1) - SG List creation failed
5236 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005237static int
5238adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, struct scsi_cmnd *scp,
5239 int use_sg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005240{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005241 adv_sgblk_t *sgblkp;
5242 ADV_SCSI_REQ_Q *scsiqp;
5243 struct scatterlist *slp;
5244 int sg_elem_cnt;
5245 ADV_SG_BLOCK *sg_block, *prev_sg_block;
5246 ADV_PADDR sg_block_paddr;
5247 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005249 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
5250 slp = (struct scatterlist *)scp->request_buffer;
5251 sg_elem_cnt = use_sg;
5252 prev_sg_block = NULL;
5253 reqp->sgblkp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005254
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005255 do {
5256 /*
5257 * Allocate a 'adv_sgblk_t' structure from the board free
5258 * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK
5259 * (15) scatter-gather elements.
5260 */
5261 if ((sgblkp = boardp->adv_sgblkp) == NULL) {
5262 ASC_DBG(1, "adv_get_sglist: no free adv_sgblk_t\n");
5263 ASC_STATS(scp->device->host, adv_build_nosg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005264
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005265 /*
5266 * Allocation failed. Free 'adv_sgblk_t' structures already
5267 * allocated for the request.
5268 */
5269 while ((sgblkp = reqp->sgblkp) != NULL) {
5270 /* Remove 'sgblkp' from the request list. */
5271 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005272
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005273 /* Add 'sgblkp' to the board free list. */
5274 sgblkp->next_sgblkp = boardp->adv_sgblkp;
5275 boardp->adv_sgblkp = sgblkp;
5276 }
5277 return ASC_BUSY;
5278 } else {
5279 /* Complete 'adv_sgblk_t' board allocation. */
5280 boardp->adv_sgblkp = sgblkp->next_sgblkp;
5281 sgblkp->next_sgblkp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005282
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005283 /*
5284 * Get 8 byte aligned virtual and physical addresses for
5285 * the allocated ADV_SG_BLOCK structure.
5286 */
5287 sg_block =
5288 (ADV_SG_BLOCK *)ADV_8BALIGN(&sgblkp->sg_block);
5289 sg_block_paddr = virt_to_bus(sg_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005290
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005291 /*
5292 * Check if this is the first 'adv_sgblk_t' for the request.
5293 */
5294 if (reqp->sgblkp == NULL) {
5295 /* Request's first scatter-gather block. */
5296 reqp->sgblkp = sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005297
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005298 /*
5299 * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical
5300 * address pointers.
5301 */
5302 scsiqp->sg_list_ptr = sg_block;
5303 scsiqp->sg_real_addr =
5304 cpu_to_le32(sg_block_paddr);
5305 } else {
5306 /* Request's second or later scatter-gather block. */
5307 sgblkp->next_sgblkp = reqp->sgblkp;
5308 reqp->sgblkp = sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005309
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005310 /*
5311 * Point the previous ADV_SG_BLOCK structure to
5312 * the newly allocated ADV_SG_BLOCK structure.
5313 */
5314 ASC_ASSERT(prev_sg_block != NULL);
5315 prev_sg_block->sg_ptr =
5316 cpu_to_le32(sg_block_paddr);
5317 }
5318 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005319
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005320 for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) {
5321 sg_block->sg_list[i].sg_addr =
5322 cpu_to_le32(sg_dma_address(slp));
5323 sg_block->sg_list[i].sg_count =
5324 cpu_to_le32(sg_dma_len(slp));
5325 ASC_STATS_ADD(scp->device->host, sg_xfer,
5326 ASC_CEILING(sg_dma_len(slp), 512));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005327
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005328 if (--sg_elem_cnt == 0) { /* Last ADV_SG_BLOCK and scatter-gather entry. */
5329 sg_block->sg_cnt = i + 1;
5330 sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */
5331 return ADV_SUCCESS;
5332 }
5333 slp++;
5334 }
5335 sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
5336 prev_sg_block = sg_block;
5337 }
5338 while (1);
5339 /* NOTREACHED */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005340}
5341
5342/*
5343 * asc_isr_callback() - Second Level Interrupt Handler called by AscISR().
5344 *
5345 * Interrupt callback function for the Narrow SCSI Asc Library.
5346 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005347static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005348{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005349 asc_board_t *boardp;
5350 struct scsi_cmnd *scp;
5351 struct Scsi_Host *shost;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005352
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005353 ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp 0x%lx, qdonep 0x%lx\n",
5354 (ulong)asc_dvc_varp, (ulong)qdonep);
5355 ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005356
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005357 /*
5358 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
5359 * command that has been completed.
5360 */
5361 scp = (struct scsi_cmnd *)ASC_U32_TO_VADDR(qdonep->d2.srb_ptr);
5362 ASC_DBG1(1, "asc_isr_callback: scp 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005363
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005364 if (scp == NULL) {
5365 ASC_PRINT("asc_isr_callback: scp is NULL\n");
5366 return;
5367 }
5368 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005369
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005370 shost = scp->device->host;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005371 ASC_STATS(shost, callback);
5372 ASC_DBG1(1, "asc_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005373
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005374 /*
5375 * If the request isn't found on the active queue, it may
5376 * have been removed to handle a reset request.
5377 * Display a message and return.
5378 */
5379 boardp = ASC_BOARDP(shost);
5380 ASC_ASSERT(asc_dvc_varp == &boardp->dvc_var.asc_dvc_var);
5381 if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
5382 ASC_PRINT2
5383 ("asc_isr_callback: board %d: scp 0x%lx not on active queue\n",
5384 boardp->id, (ulong)scp);
5385 return;
5386 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005387
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005388 /*
5389 * 'qdonep' contains the command's ending status.
5390 */
5391 switch (qdonep->d3.done_stat) {
5392 case QD_NO_ERROR:
5393 ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n");
5394 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005395
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005396 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005397 * Check for an underrun condition.
5398 *
5399 * If there was no error and an underrun condition, then
Matthew Wilcox47d853c2007-07-26 11:41:33 -04005400 * return the number of underrun bytes.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005401 */
5402 if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 &&
5403 qdonep->remain_bytes <= scp->request_bufflen) {
5404 ASC_DBG1(1,
5405 "asc_isr_callback: underrun condition %u bytes\n",
5406 (unsigned)qdonep->remain_bytes);
5407 scp->resid = qdonep->remain_bytes;
5408 }
5409 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005410
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005411 case QD_WITH_ERROR:
5412 ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n");
5413 switch (qdonep->d3.host_stat) {
5414 case QHSTA_NO_ERROR:
5415 if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
5416 ASC_DBG(2,
5417 "asc_isr_callback: SAM_STAT_CHECK_CONDITION\n");
5418 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
5419 sizeof(scp->sense_buffer));
5420 /*
5421 * Note: The 'status_byte()' macro used by target drivers
5422 * defined in scsi.h shifts the status byte returned by
5423 * host drivers right by 1 bit. This is why target drivers
5424 * also use right shifted status byte definitions. For
5425 * instance target drivers use CHECK_CONDITION, defined to
5426 * 0x1, instead of the SCSI defined check condition value
5427 * of 0x2. Host drivers are supposed to return the status
5428 * byte as it is defined by SCSI.
5429 */
5430 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
5431 STATUS_BYTE(qdonep->d3.scsi_stat);
5432 } else {
5433 scp->result = STATUS_BYTE(qdonep->d3.scsi_stat);
5434 }
5435 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005436
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005437 default:
5438 /* QHSTA error occurred */
5439 ASC_DBG1(1, "asc_isr_callback: host_stat 0x%x\n",
5440 qdonep->d3.host_stat);
5441 scp->result = HOST_BYTE(DID_BAD_TARGET);
5442 break;
5443 }
5444 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005445
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005446 case QD_ABORTED_BY_HOST:
5447 ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOST\n");
5448 scp->result =
5449 HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.
5450 scsi_msg) |
5451 STATUS_BYTE(qdonep->d3.scsi_stat);
5452 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005453
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005454 default:
5455 ASC_DBG1(1, "asc_isr_callback: done_stat 0x%x\n",
5456 qdonep->d3.done_stat);
5457 scp->result =
5458 HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.
5459 scsi_msg) |
5460 STATUS_BYTE(qdonep->d3.scsi_stat);
5461 break;
5462 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005463
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005464 /*
5465 * If the 'init_tidmask' bit isn't already set for the target and the
5466 * current request finished normally, then set the bit for the target
5467 * to indicate that a device is present.
5468 */
5469 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
5470 qdonep->d3.done_stat == QD_NO_ERROR &&
5471 qdonep->d3.host_stat == QHSTA_NO_ERROR) {
5472 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
5473 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005474
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005475 /*
5476 * Because interrupts may be enabled by the 'struct scsi_cmnd' done
5477 * function, add the command to the end of the board's done queue.
5478 * The done function for the command will be called from
5479 * advansys_interrupt().
5480 */
5481 asc_enqueue(&boardp->done, scp, ASC_BACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005483 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005484}
5485
5486/*
5487 * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR().
5488 *
5489 * Callback function for the Wide SCSI Adv Library.
5490 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005491static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005492{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005493 asc_board_t *boardp;
5494 adv_req_t *reqp;
5495 adv_sgblk_t *sgblkp;
5496 struct scsi_cmnd *scp;
5497 struct Scsi_Host *shost;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005498 ADV_DCNT resid_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005499
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005500 ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp 0x%lx, scsiqp 0x%lx\n",
5501 (ulong)adv_dvc_varp, (ulong)scsiqp);
5502 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005503
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005504 /*
5505 * Get the adv_req_t structure for the command that has been
5506 * completed. The adv_req_t structure actually contains the
5507 * completed ADV_SCSI_REQ_Q structure.
5508 */
5509 reqp = (adv_req_t *)ADV_U32_TO_VADDR(scsiqp->srb_ptr);
5510 ASC_DBG1(1, "adv_isr_callback: reqp 0x%lx\n", (ulong)reqp);
5511 if (reqp == NULL) {
5512 ASC_PRINT("adv_isr_callback: reqp is NULL\n");
5513 return;
5514 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005515
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005516 /*
5517 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
5518 * command that has been completed.
5519 *
5520 * Note: The adv_req_t request structure and adv_sgblk_t structure,
5521 * if any, are dropped, because a board structure pointer can not be
5522 * determined.
5523 */
5524 scp = reqp->cmndp;
5525 ASC_DBG1(1, "adv_isr_callback: scp 0x%lx\n", (ulong)scp);
5526 if (scp == NULL) {
5527 ASC_PRINT
5528 ("adv_isr_callback: scp is NULL; adv_req_t dropped.\n");
5529 return;
5530 }
5531 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005532
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005533 shost = scp->device->host;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005534 ASC_STATS(shost, callback);
5535 ASC_DBG1(1, "adv_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005536
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005537 /*
5538 * If the request isn't found on the active queue, it may have been
5539 * removed to handle a reset request. Display a message and return.
5540 *
5541 * Note: Because the structure may still be in use don't attempt
5542 * to free the adv_req_t and adv_sgblk_t, if any, structures.
5543 */
5544 boardp = ASC_BOARDP(shost);
5545 ASC_ASSERT(adv_dvc_varp == &boardp->dvc_var.adv_dvc_var);
5546 if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
5547 ASC_PRINT2
5548 ("adv_isr_callback: board %d: scp 0x%lx not on active queue\n",
5549 boardp->id, (ulong)scp);
5550 return;
5551 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005552
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005553 /*
5554 * 'done_status' contains the command's ending status.
5555 */
5556 switch (scsiqp->done_status) {
5557 case QD_NO_ERROR:
5558 ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n");
5559 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005560
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005561 /*
5562 * Check for an underrun condition.
5563 *
5564 * If there was no error and an underrun condition, then
5565 * then return the number of underrun bytes.
5566 */
5567 resid_cnt = le32_to_cpu(scsiqp->data_cnt);
5568 if (scp->request_bufflen != 0 && resid_cnt != 0 &&
5569 resid_cnt <= scp->request_bufflen) {
5570 ASC_DBG1(1,
5571 "adv_isr_callback: underrun condition %lu bytes\n",
5572 (ulong)resid_cnt);
5573 scp->resid = resid_cnt;
5574 }
5575 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005576
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005577 case QD_WITH_ERROR:
5578 ASC_DBG(2, "adv_isr_callback: QD_WITH_ERROR\n");
5579 switch (scsiqp->host_status) {
5580 case QHSTA_NO_ERROR:
5581 if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
5582 ASC_DBG(2,
5583 "adv_isr_callback: SAM_STAT_CHECK_CONDITION\n");
5584 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
5585 sizeof(scp->sense_buffer));
5586 /*
5587 * Note: The 'status_byte()' macro used by target drivers
5588 * defined in scsi.h shifts the status byte returned by
5589 * host drivers right by 1 bit. This is why target drivers
5590 * also use right shifted status byte definitions. For
5591 * instance target drivers use CHECK_CONDITION, defined to
5592 * 0x1, instead of the SCSI defined check condition value
5593 * of 0x2. Host drivers are supposed to return the status
5594 * byte as it is defined by SCSI.
5595 */
5596 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
5597 STATUS_BYTE(scsiqp->scsi_status);
5598 } else {
5599 scp->result = STATUS_BYTE(scsiqp->scsi_status);
5600 }
5601 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005602
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005603 default:
5604 /* Some other QHSTA error occurred. */
5605 ASC_DBG1(1, "adv_isr_callback: host_status 0x%x\n",
5606 scsiqp->host_status);
5607 scp->result = HOST_BYTE(DID_BAD_TARGET);
5608 break;
5609 }
5610 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005611
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005612 case QD_ABORTED_BY_HOST:
5613 ASC_DBG(1, "adv_isr_callback: QD_ABORTED_BY_HOST\n");
5614 scp->result =
5615 HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status);
5616 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005617
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005618 default:
5619 ASC_DBG1(1, "adv_isr_callback: done_status 0x%x\n",
5620 scsiqp->done_status);
5621 scp->result =
5622 HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status);
5623 break;
5624 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005625
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005626 /*
5627 * If the 'init_tidmask' bit isn't already set for the target and the
5628 * current request finished normally, then set the bit for the target
5629 * to indicate that a device is present.
5630 */
5631 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
5632 scsiqp->done_status == QD_NO_ERROR &&
5633 scsiqp->host_status == QHSTA_NO_ERROR) {
5634 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
5635 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005636
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005637 /*
5638 * Because interrupts may be enabled by the 'struct scsi_cmnd' done
5639 * function, add the command to the end of the board's done queue.
5640 * The done function for the command will be called from
5641 * advansys_interrupt().
5642 */
5643 asc_enqueue(&boardp->done, scp, ASC_BACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005644
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005645 /*
5646 * Free all 'adv_sgblk_t' structures allocated for the request.
5647 */
5648 while ((sgblkp = reqp->sgblkp) != NULL) {
5649 /* Remove 'sgblkp' from the request list. */
5650 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005652 /* Add 'sgblkp' to the board free list. */
5653 sgblkp->next_sgblkp = boardp->adv_sgblkp;
5654 boardp->adv_sgblkp = sgblkp;
5655 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005656
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005657 /*
5658 * Free the adv_req_t structure used with the command by adding
5659 * it back to the board free list.
5660 */
5661 reqp->next_reqp = boardp->adv_reqp;
5662 boardp->adv_reqp = reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005663
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005664 ASC_DBG(1, "adv_isr_callback: done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005665
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005666 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005667}
5668
5669/*
5670 * adv_async_callback() - Adv Library asynchronous event callback function.
5671 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005672static void adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005673{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005674 switch (code) {
5675 case ADV_ASYNC_SCSI_BUS_RESET_DET:
5676 /*
5677 * The firmware detected a SCSI Bus reset.
5678 */
5679 ASC_DBG(0,
5680 "adv_async_callback: ADV_ASYNC_SCSI_BUS_RESET_DET\n");
5681 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005682
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005683 case ADV_ASYNC_RDMA_FAILURE:
5684 /*
5685 * Handle RDMA failure by resetting the SCSI Bus and
5686 * possibly the chip if it is unresponsive. Log the error
5687 * with a unique code.
5688 */
5689 ASC_DBG(0, "adv_async_callback: ADV_ASYNC_RDMA_FAILURE\n");
5690 AdvResetChipAndSB(adv_dvc_varp);
5691 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005692
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005693 case ADV_HOST_SCSI_BUS_RESET:
5694 /*
5695 * Host generated SCSI bus reset occurred.
5696 */
5697 ASC_DBG(0, "adv_async_callback: ADV_HOST_SCSI_BUS_RESET\n");
5698 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005699
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005700 default:
5701 ASC_DBG1(0, "DvcAsyncCallBack: unknown code 0x%x\n", code);
5702 break;
5703 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005704}
5705
5706/*
5707 * Add a 'REQP' to the end of specified queue. Set 'tidmask'
5708 * to indicate a command is queued for the device.
5709 *
5710 * 'flag' may be either ASC_FRONT or ASC_BACK.
5711 *
5712 * 'REQPNEXT(reqp)' returns reqp's next pointer.
5713 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005714static void asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005715{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005716 int tid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005717
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005718 ASC_DBG3(3, "asc_enqueue: ascq 0x%lx, reqp 0x%lx, flag %d\n",
5719 (ulong)ascq, (ulong)reqp, flag);
5720 ASC_ASSERT(reqp != NULL);
5721 ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
5722 tid = REQPTID(reqp);
5723 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
5724 if (flag == ASC_FRONT) {
5725 reqp->host_scribble = (unsigned char *)ascq->q_first[tid];
5726 ascq->q_first[tid] = reqp;
5727 /* If the queue was empty, set the last pointer. */
5728 if (ascq->q_last[tid] == NULL) {
5729 ascq->q_last[tid] = reqp;
5730 }
5731 } else { /* ASC_BACK */
5732 if (ascq->q_last[tid] != NULL) {
5733 ascq->q_last[tid]->host_scribble =
5734 (unsigned char *)reqp;
5735 }
5736 ascq->q_last[tid] = reqp;
5737 reqp->host_scribble = NULL;
5738 /* If the queue was empty, set the first pointer. */
5739 if (ascq->q_first[tid] == NULL) {
5740 ascq->q_first[tid] = reqp;
5741 }
5742 }
5743 /* The queue has at least one entry, set its bit. */
5744 ascq->q_tidmask |= ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005745#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005746 /* Maintain request queue statistics. */
5747 ascq->q_tot_cnt[tid]++;
5748 ascq->q_cur_cnt[tid]++;
5749 if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) {
5750 ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid];
5751 ASC_DBG2(2, "asc_enqueue: new q_max_cnt[%d] %d\n",
5752 tid, ascq->q_max_cnt[tid]);
5753 }
5754 REQPTIME(reqp) = REQTIMESTAMP();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005755#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005756 ASC_DBG1(3, "asc_enqueue: reqp 0x%lx\n", (ulong)reqp);
5757 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005758}
5759
5760/*
5761 * Return first queued 'REQP' on the specified queue for
5762 * the specified target device. Clear the 'tidmask' bit for
5763 * the device if no more commands are left queued for it.
5764 *
5765 * 'REQPNEXT(reqp)' returns reqp's next pointer.
5766 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005767static REQP asc_dequeue(asc_queue_t *ascq, int tid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005768{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005769 REQP reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005770
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005771 ASC_DBG2(3, "asc_dequeue: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
5772 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
5773 if ((reqp = ascq->q_first[tid]) != NULL) {
5774 ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid));
5775 ascq->q_first[tid] = REQPNEXT(reqp);
5776 /* If the queue is empty, clear its bit and the last pointer. */
5777 if (ascq->q_first[tid] == NULL) {
5778 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
5779 ASC_ASSERT(ascq->q_last[tid] == reqp);
5780 ascq->q_last[tid] = NULL;
5781 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005782#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005783 /* Maintain request queue statistics. */
5784 ascq->q_cur_cnt[tid]--;
5785 ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
5786 REQTIMESTAT("asc_dequeue", ascq, reqp, tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005787#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005788 }
5789 ASC_DBG1(3, "asc_dequeue: reqp 0x%lx\n", (ulong)reqp);
5790 return reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005791}
5792
5793/*
5794 * Return a pointer to a singly linked list of all the requests queued
5795 * for 'tid' on the 'asc_queue_t' pointed to by 'ascq'.
5796 *
5797 * If 'lastpp' is not NULL, '*lastpp' will be set to point to the
5798 * the last request returned in the singly linked list.
5799 *
5800 * 'tid' should either be a valid target id or if it is ASC_TID_ALL,
5801 * then all queued requests are concatenated into one list and
5802 * returned.
5803 *
5804 * Note: If 'lastpp' is used to append a new list to the end of
5805 * an old list, only change the old list last pointer if '*lastpp'
5806 * (or the function return value) is not NULL, i.e. use a temporary
5807 * variable for 'lastpp' and check its value after the function return
5808 * before assigning it to the list last pointer.
5809 *
5810 * Unfortunately collecting queuing time statistics adds overhead to
5811 * the function that isn't inherent to the function's algorithm.
5812 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005813static REQP asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005814{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005815 REQP firstp, lastp;
5816 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005817
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005818 ASC_DBG2(3, "asc_dequeue_list: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
5819 ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005820
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005821 /*
5822 * If 'tid' is not ASC_TID_ALL, return requests only for
5823 * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all
5824 * requests for all tids.
5825 */
5826 if (tid != ASC_TID_ALL) {
5827 /* Return all requests for the specified 'tid'. */
5828 if ((ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)) == 0) {
5829 /* List is empty; Set first and last return pointers to NULL. */
5830 firstp = lastp = NULL;
5831 } else {
5832 firstp = ascq->q_first[tid];
5833 lastp = ascq->q_last[tid];
5834 ascq->q_first[tid] = ascq->q_last[tid] = NULL;
5835 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005836#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005837 {
5838 REQP reqp;
5839 ascq->q_cur_cnt[tid] = 0;
5840 for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
5841 REQTIMESTAT("asc_dequeue_list", ascq,
5842 reqp, tid);
5843 }
5844 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005845#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005846 }
5847 } else {
5848 /* Return all requests for all tids. */
5849 firstp = lastp = NULL;
5850 for (i = 0; i <= ADV_MAX_TID; i++) {
5851 if (ascq->q_tidmask & ADV_TID_TO_TIDMASK(i)) {
5852 if (firstp == NULL) {
5853 firstp = ascq->q_first[i];
5854 lastp = ascq->q_last[i];
5855 } else {
5856 ASC_ASSERT(lastp != NULL);
5857 lastp->host_scribble =
5858 (unsigned char *)ascq->q_first[i];
5859 lastp = ascq->q_last[i];
5860 }
5861 ascq->q_first[i] = ascq->q_last[i] = NULL;
5862 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005863#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005864 ascq->q_cur_cnt[i] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005865#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005866 }
5867 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005868#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005869 {
5870 REQP reqp;
5871 for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
5872 REQTIMESTAT("asc_dequeue_list", ascq, reqp,
5873 reqp->device->id);
5874 }
5875 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005876#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005877 }
5878 if (lastpp) {
5879 *lastpp = lastp;
5880 }
5881 ASC_DBG1(3, "asc_dequeue_list: firstp 0x%lx\n", (ulong)firstp);
5882 return firstp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005883}
5884
5885/*
5886 * Remove the specified 'REQP' from the specified queue for
5887 * the specified target device. Clear the 'tidmask' bit for the
5888 * device if no more commands are left queued for it.
5889 *
5890 * 'REQPNEXT(reqp)' returns reqp's the next pointer.
5891 *
5892 * Return ASC_TRUE if the command was found and removed,
5893 * otherwise return ASC_FALSE.
5894 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005895static int asc_rmqueue(asc_queue_t *ascq, REQP reqp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005896{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005897 REQP currp, prevp;
5898 int tid;
5899 int ret = ASC_FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005900
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005901 ASC_DBG2(3, "asc_rmqueue: ascq 0x%lx, reqp 0x%lx\n",
5902 (ulong)ascq, (ulong)reqp);
5903 ASC_ASSERT(reqp != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005904
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005905 tid = REQPTID(reqp);
5906 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005907
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005908 /*
5909 * Handle the common case of 'reqp' being the first
5910 * entry on the queue.
5911 */
5912 if (reqp == ascq->q_first[tid]) {
5913 ret = ASC_TRUE;
5914 ascq->q_first[tid] = REQPNEXT(reqp);
5915 /* If the queue is now empty, clear its bit and the last pointer. */
5916 if (ascq->q_first[tid] == NULL) {
5917 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
5918 ASC_ASSERT(ascq->q_last[tid] == reqp);
5919 ascq->q_last[tid] = NULL;
5920 }
5921 } else if (ascq->q_first[tid] != NULL) {
5922 ASC_ASSERT(ascq->q_last[tid] != NULL);
5923 /*
5924 * Because the case of 'reqp' being the first entry has been
5925 * handled above and it is known the queue is not empty, if
5926 * 'reqp' is found on the queue it is guaranteed the queue will
5927 * not become empty and that 'q_first[tid]' will not be changed.
5928 *
5929 * Set 'prevp' to the first entry, 'currp' to the second entry,
5930 * and search for 'reqp'.
5931 */
5932 for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp);
5933 currp; prevp = currp, currp = REQPNEXT(currp)) {
5934 if (currp == reqp) {
5935 ret = ASC_TRUE;
5936 prevp->host_scribble =
5937 (unsigned char *)REQPNEXT(currp);
5938 reqp->host_scribble = NULL;
5939 if (ascq->q_last[tid] == reqp) {
5940 ascq->q_last[tid] = prevp;
5941 }
5942 break;
5943 }
5944 }
5945 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005946#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005947 /* Maintain request queue statistics. */
5948 if (ret == ASC_TRUE) {
5949 ascq->q_cur_cnt[tid]--;
5950 REQTIMESTAT("asc_rmqueue", ascq, reqp, tid);
5951 }
5952 ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005953#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005954 ASC_DBG2(3, "asc_rmqueue: reqp 0x%lx, ret %d\n", (ulong)reqp, ret);
5955 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005956}
5957
5958/*
5959 * Execute as many queued requests as possible for the specified queue.
5960 *
5961 * Calls asc_execute_scsi_cmnd() to execute a REQP/struct scsi_cmnd.
5962 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005963static void asc_execute_queue(asc_queue_t *ascq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005964{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005965 ADV_SCSI_BIT_ID_TYPE scan_tidmask;
5966 REQP reqp;
5967 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005968
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005969 ASC_DBG1(1, "asc_execute_queue: ascq 0x%lx\n", (ulong)ascq);
5970 /*
5971 * Execute queued commands for devices attached to
5972 * the current board in round-robin fashion.
5973 */
5974 scan_tidmask = ascq->q_tidmask;
5975 do {
5976 for (i = 0; i <= ADV_MAX_TID; i++) {
5977 if (scan_tidmask & ADV_TID_TO_TIDMASK(i)) {
5978 if ((reqp = asc_dequeue(ascq, i)) == NULL) {
5979 scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
5980 } else
5981 if (asc_execute_scsi_cmnd
5982 ((struct scsi_cmnd *)reqp)
5983 == ASC_BUSY) {
5984 scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
5985 /*
5986 * The request returned ASC_BUSY. Enqueue at the front of
5987 * target's waiting list to maintain correct ordering.
5988 */
5989 asc_enqueue(ascq, reqp, ASC_FRONT);
5990 }
5991 }
5992 }
5993 } while (scan_tidmask);
5994 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005995}
5996
5997#ifdef CONFIG_PROC_FS
5998/*
5999 * asc_prt_board_devices()
6000 *
6001 * Print driver information for devices attached to the board.
6002 *
6003 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6004 * cf. asc_prt_line().
6005 *
6006 * Return the number of characters copied into 'cp'. No more than
6007 * 'cplen' characters will be copied to 'cp'.
6008 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006009static int asc_prt_board_devices(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006010{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006011 asc_board_t *boardp;
6012 int leftlen;
6013 int totlen;
6014 int len;
6015 int chip_scsi_id;
6016 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006017
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006018 boardp = ASC_BOARDP(shost);
6019 leftlen = cplen;
6020 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006021
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006022 len = asc_prt_line(cp, leftlen,
6023 "\nDevice Information for AdvanSys SCSI Host %d:\n",
6024 shost->host_no);
6025 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006026
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006027 if (ASC_NARROW_BOARD(boardp)) {
6028 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
6029 } else {
6030 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
6031 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006032
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006033 len = asc_prt_line(cp, leftlen, "Target IDs Detected:");
6034 ASC_PRT_NEXT();
6035 for (i = 0; i <= ADV_MAX_TID; i++) {
6036 if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) {
6037 len = asc_prt_line(cp, leftlen, " %X,", i);
6038 ASC_PRT_NEXT();
6039 }
6040 }
6041 len = asc_prt_line(cp, leftlen, " (%X=Host Adapter)\n", chip_scsi_id);
6042 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006043
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006044 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006045}
6046
6047/*
6048 * Display Wide Board BIOS Information.
6049 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006050static int asc_prt_adv_bios(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006051{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006052 asc_board_t *boardp;
6053 int leftlen;
6054 int totlen;
6055 int len;
6056 ushort major, minor, letter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006057
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006058 boardp = ASC_BOARDP(shost);
6059 leftlen = cplen;
6060 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006061
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006062 len = asc_prt_line(cp, leftlen, "\nROM BIOS Version: ");
6063 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006064
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006065 /*
6066 * If the BIOS saved a valid signature, then fill in
6067 * the BIOS code segment base address.
6068 */
6069 if (boardp->bios_signature != 0x55AA) {
6070 len = asc_prt_line(cp, leftlen, "Disabled or Pre-3.1\n");
6071 ASC_PRT_NEXT();
6072 len = asc_prt_line(cp, leftlen,
6073 "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n");
6074 ASC_PRT_NEXT();
6075 len = asc_prt_line(cp, leftlen,
6076 "can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n");
6077 ASC_PRT_NEXT();
6078 } else {
6079 major = (boardp->bios_version >> 12) & 0xF;
6080 minor = (boardp->bios_version >> 8) & 0xF;
6081 letter = (boardp->bios_version & 0xFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006082
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006083 len = asc_prt_line(cp, leftlen, "%d.%d%c\n",
6084 major, minor,
6085 letter >= 26 ? '?' : letter + 'A');
6086 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006087
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006088 /*
6089 * Current available ROM BIOS release is 3.1I for UW
6090 * and 3.2I for U2W. This code doesn't differentiate
6091 * UW and U2W boards.
6092 */
6093 if (major < 3 || (major <= 3 && minor < 1) ||
6094 (major <= 3 && minor <= 1 && letter < ('I' - 'A'))) {
6095 len = asc_prt_line(cp, leftlen,
6096 "Newer version of ROM BIOS is available at the ConnectCom FTP site:\n");
6097 ASC_PRT_NEXT();
6098 len = asc_prt_line(cp, leftlen,
6099 "ftp://ftp.connectcom.net/pub\n");
6100 ASC_PRT_NEXT();
6101 }
6102 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006103
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006104 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006105}
6106
6107/*
6108 * Add serial number to information bar if signature AAh
6109 * is found in at bit 15-9 (7 bits) of word 1.
6110 *
6111 * Serial Number consists fo 12 alpha-numeric digits.
6112 *
6113 * 1 - Product type (A,B,C,D..) Word0: 15-13 (3 bits)
6114 * 2 - MFG Location (A,B,C,D..) Word0: 12-10 (3 bits)
6115 * 3-4 - Product ID (0-99) Word0: 9-0 (10 bits)
6116 * 5 - Product revision (A-J) Word0: " "
6117 *
6118 * Signature Word1: 15-9 (7 bits)
6119 * 6 - Year (0-9) Word1: 8-6 (3 bits) & Word2: 15 (1 bit)
6120 * 7-8 - Week of the year (1-52) Word1: 5-0 (6 bits)
6121 *
6122 * 9-12 - Serial Number (A001-Z999) Word2: 14-0 (15 bits)
6123 *
6124 * Note 1: Only production cards will have a serial number.
6125 *
6126 * Note 2: Signature is most significant 7 bits (0xFE).
6127 *
6128 * Returns ASC_TRUE if serial number found, otherwise returns ASC_FALSE.
6129 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006130static int asc_get_eeprom_string(ushort *serialnum, uchar *cp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006131{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006132 ushort w, num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006133
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006134 if ((serialnum[1] & 0xFE00) != ((ushort)0xAA << 8)) {
6135 return ASC_FALSE;
6136 } else {
6137 /*
6138 * First word - 6 digits.
6139 */
6140 w = serialnum[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006141
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006142 /* Product type - 1st digit. */
6143 if ((*cp = 'A' + ((w & 0xE000) >> 13)) == 'H') {
6144 /* Product type is P=Prototype */
6145 *cp += 0x8;
6146 }
6147 cp++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006148
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006149 /* Manufacturing location - 2nd digit. */
6150 *cp++ = 'A' + ((w & 0x1C00) >> 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006151
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006152 /* Product ID - 3rd, 4th digits. */
6153 num = w & 0x3FF;
6154 *cp++ = '0' + (num / 100);
6155 num %= 100;
6156 *cp++ = '0' + (num / 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006157
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006158 /* Product revision - 5th digit. */
6159 *cp++ = 'A' + (num % 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006160
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006161 /*
6162 * Second word
6163 */
6164 w = serialnum[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006165
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006166 /*
6167 * Year - 6th digit.
6168 *
6169 * If bit 15 of third word is set, then the
6170 * last digit of the year is greater than 7.
6171 */
6172 if (serialnum[2] & 0x8000) {
6173 *cp++ = '8' + ((w & 0x1C0) >> 6);
6174 } else {
6175 *cp++ = '0' + ((w & 0x1C0) >> 6);
6176 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006177
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006178 /* Week of year - 7th, 8th digits. */
6179 num = w & 0x003F;
6180 *cp++ = '0' + num / 10;
6181 num %= 10;
6182 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006183
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006184 /*
6185 * Third word
6186 */
6187 w = serialnum[2] & 0x7FFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006188
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006189 /* Serial number - 9th digit. */
6190 *cp++ = 'A' + (w / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006191
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006192 /* 10th, 11th, 12th digits. */
6193 num = w % 1000;
6194 *cp++ = '0' + num / 100;
6195 num %= 100;
6196 *cp++ = '0' + num / 10;
6197 num %= 10;
6198 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006199
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006200 *cp = '\0'; /* Null Terminate the string. */
6201 return ASC_TRUE;
6202 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006203}
6204
6205/*
6206 * asc_prt_asc_board_eeprom()
6207 *
6208 * Print board EEPROM configuration.
6209 *
6210 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6211 * cf. asc_prt_line().
6212 *
6213 * Return the number of characters copied into 'cp'. No more than
6214 * 'cplen' characters will be copied to 'cp'.
6215 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006216static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006217{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006218 asc_board_t *boardp;
6219 ASC_DVC_VAR *asc_dvc_varp;
6220 int leftlen;
6221 int totlen;
6222 int len;
6223 ASCEEP_CONFIG *ep;
6224 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006225#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006226 int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07006227#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006228 uchar serialstr[13];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006229
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006230 boardp = ASC_BOARDP(shost);
6231 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
6232 ep = &boardp->eep_config.asc_eep;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006233
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006234 leftlen = cplen;
6235 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006236
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006237 len = asc_prt_line(cp, leftlen,
6238 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
6239 shost->host_no);
6240 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006241
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006242 if (asc_get_eeprom_string((ushort *)&ep->adapter_info[0], serialstr)
6243 == ASC_TRUE) {
6244 len =
6245 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
6246 serialstr);
6247 ASC_PRT_NEXT();
6248 } else {
6249 if (ep->adapter_info[5] == 0xBB) {
6250 len = asc_prt_line(cp, leftlen,
6251 " Default Settings Used for EEPROM-less Adapter.\n");
6252 ASC_PRT_NEXT();
6253 } else {
6254 len = asc_prt_line(cp, leftlen,
6255 " Serial Number Signature Not Present.\n");
6256 ASC_PRT_NEXT();
6257 }
6258 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006259
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006260 len = asc_prt_line(cp, leftlen,
6261 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6262 ASC_EEP_GET_CHIP_ID(ep), ep->max_total_qng,
6263 ep->max_tag_qng);
6264 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006265
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006266 len = asc_prt_line(cp, leftlen,
6267 " cntl 0x%x, no_scam 0x%x\n", ep->cntl, ep->no_scam);
6268 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006269
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006270 len = asc_prt_line(cp, leftlen, " Target ID: ");
6271 ASC_PRT_NEXT();
6272 for (i = 0; i <= ASC_MAX_TID; i++) {
6273 len = asc_prt_line(cp, leftlen, " %d", i);
6274 ASC_PRT_NEXT();
6275 }
6276 len = asc_prt_line(cp, leftlen, "\n");
6277 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006278
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006279 len = asc_prt_line(cp, leftlen, " Disconnects: ");
6280 ASC_PRT_NEXT();
6281 for (i = 0; i <= ASC_MAX_TID; i++) {
6282 len = asc_prt_line(cp, leftlen, " %c",
6283 (ep->
6284 disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6285 'N');
6286 ASC_PRT_NEXT();
6287 }
6288 len = asc_prt_line(cp, leftlen, "\n");
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, " Command Queuing: ");
6292 ASC_PRT_NEXT();
6293 for (i = 0; i <= ASC_MAX_TID; i++) {
6294 len = asc_prt_line(cp, leftlen, " %c",
6295 (ep->
6296 use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6297 'N');
6298 ASC_PRT_NEXT();
6299 }
6300 len = asc_prt_line(cp, leftlen, "\n");
6301 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006302
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006303 len = asc_prt_line(cp, leftlen, " Start Motor: ");
6304 ASC_PRT_NEXT();
6305 for (i = 0; i <= ASC_MAX_TID; i++) {
6306 len = asc_prt_line(cp, leftlen, " %c",
6307 (ep->
6308 start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6309 'N');
6310 ASC_PRT_NEXT();
6311 }
6312 len = asc_prt_line(cp, leftlen, "\n");
6313 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006314
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006315 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6316 ASC_PRT_NEXT();
6317 for (i = 0; i <= ASC_MAX_TID; i++) {
6318 len = asc_prt_line(cp, leftlen, " %c",
6319 (ep->
6320 init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6321 'N');
6322 ASC_PRT_NEXT();
6323 }
6324 len = asc_prt_line(cp, leftlen, "\n");
6325 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006326
6327#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006328 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
6329 len = asc_prt_line(cp, leftlen,
6330 " Host ISA DMA speed: %d MB/S\n",
6331 isa_dma_speed[ASC_EEP_GET_DMA_SPD(ep)]);
6332 ASC_PRT_NEXT();
6333 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006334#endif /* CONFIG_ISA */
6335
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006336 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006337}
6338
6339/*
6340 * asc_prt_adv_board_eeprom()
6341 *
6342 * Print board EEPROM configuration.
6343 *
6344 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6345 * cf. asc_prt_line().
6346 *
6347 * Return the number of characters copied into 'cp'. No more than
6348 * 'cplen' characters will be copied to 'cp'.
6349 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006350static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006351{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006352 asc_board_t *boardp;
6353 ADV_DVC_VAR *adv_dvc_varp;
6354 int leftlen;
6355 int totlen;
6356 int len;
6357 int i;
6358 char *termstr;
6359 uchar serialstr[13];
6360 ADVEEP_3550_CONFIG *ep_3550 = NULL;
6361 ADVEEP_38C0800_CONFIG *ep_38C0800 = NULL;
6362 ADVEEP_38C1600_CONFIG *ep_38C1600 = NULL;
6363 ushort word;
6364 ushort *wordp;
6365 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006366
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006367 boardp = ASC_BOARDP(shost);
6368 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
6369 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6370 ep_3550 = &boardp->eep_config.adv_3550_eep;
6371 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6372 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
6373 } else {
6374 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
6375 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006376
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006377 leftlen = cplen;
6378 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006379
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006380 len = asc_prt_line(cp, leftlen,
6381 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
6382 shost->host_no);
6383 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006384
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006385 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6386 wordp = &ep_3550->serial_number_word1;
6387 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6388 wordp = &ep_38C0800->serial_number_word1;
6389 } else {
6390 wordp = &ep_38C1600->serial_number_word1;
6391 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006392
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006393 if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) {
6394 len =
6395 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
6396 serialstr);
6397 ASC_PRT_NEXT();
6398 } else {
6399 len = asc_prt_line(cp, leftlen,
6400 " Serial Number Signature Not Present.\n");
6401 ASC_PRT_NEXT();
6402 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006403
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006404 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6405 len = asc_prt_line(cp, leftlen,
6406 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6407 ep_3550->adapter_scsi_id,
6408 ep_3550->max_host_qng, ep_3550->max_dvc_qng);
6409 ASC_PRT_NEXT();
6410 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6411 len = asc_prt_line(cp, leftlen,
6412 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6413 ep_38C0800->adapter_scsi_id,
6414 ep_38C0800->max_host_qng,
6415 ep_38C0800->max_dvc_qng);
6416 ASC_PRT_NEXT();
6417 } else {
6418 len = asc_prt_line(cp, leftlen,
6419 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6420 ep_38C1600->adapter_scsi_id,
6421 ep_38C1600->max_host_qng,
6422 ep_38C1600->max_dvc_qng);
6423 ASC_PRT_NEXT();
6424 }
6425 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6426 word = ep_3550->termination;
6427 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6428 word = ep_38C0800->termination_lvd;
6429 } else {
6430 word = ep_38C1600->termination_lvd;
6431 }
6432 switch (word) {
6433 case 1:
6434 termstr = "Low Off/High Off";
6435 break;
6436 case 2:
6437 termstr = "Low Off/High On";
6438 break;
6439 case 3:
6440 termstr = "Low On/High On";
6441 break;
6442 default:
6443 case 0:
6444 termstr = "Automatic";
6445 break;
6446 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006447
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006448 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6449 len = asc_prt_line(cp, leftlen,
6450 " termination: %u (%s), bios_ctrl: 0x%x\n",
6451 ep_3550->termination, termstr,
6452 ep_3550->bios_ctrl);
6453 ASC_PRT_NEXT();
6454 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6455 len = asc_prt_line(cp, leftlen,
6456 " termination: %u (%s), bios_ctrl: 0x%x\n",
6457 ep_38C0800->termination_lvd, termstr,
6458 ep_38C0800->bios_ctrl);
6459 ASC_PRT_NEXT();
6460 } else {
6461 len = asc_prt_line(cp, leftlen,
6462 " termination: %u (%s), bios_ctrl: 0x%x\n",
6463 ep_38C1600->termination_lvd, termstr,
6464 ep_38C1600->bios_ctrl);
6465 ASC_PRT_NEXT();
6466 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006467
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006468 len = asc_prt_line(cp, leftlen, " Target ID: ");
6469 ASC_PRT_NEXT();
6470 for (i = 0; i <= ADV_MAX_TID; i++) {
6471 len = asc_prt_line(cp, leftlen, " %X", i);
6472 ASC_PRT_NEXT();
6473 }
6474 len = asc_prt_line(cp, leftlen, "\n");
6475 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006476
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006477 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6478 word = ep_3550->disc_enable;
6479 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6480 word = ep_38C0800->disc_enable;
6481 } else {
6482 word = ep_38C1600->disc_enable;
6483 }
6484 len = asc_prt_line(cp, leftlen, " Disconnects: ");
6485 ASC_PRT_NEXT();
6486 for (i = 0; i <= ADV_MAX_TID; i++) {
6487 len = asc_prt_line(cp, leftlen, " %c",
6488 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6489 ASC_PRT_NEXT();
6490 }
6491 len = asc_prt_line(cp, leftlen, "\n");
6492 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006493
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006494 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6495 word = ep_3550->tagqng_able;
6496 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6497 word = ep_38C0800->tagqng_able;
6498 } else {
6499 word = ep_38C1600->tagqng_able;
6500 }
6501 len = asc_prt_line(cp, leftlen, " Command Queuing: ");
6502 ASC_PRT_NEXT();
6503 for (i = 0; i <= ADV_MAX_TID; i++) {
6504 len = asc_prt_line(cp, leftlen, " %c",
6505 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6506 ASC_PRT_NEXT();
6507 }
6508 len = asc_prt_line(cp, leftlen, "\n");
6509 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006510
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006511 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6512 word = ep_3550->start_motor;
6513 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6514 word = ep_38C0800->start_motor;
6515 } else {
6516 word = ep_38C1600->start_motor;
6517 }
6518 len = asc_prt_line(cp, leftlen, " Start Motor: ");
6519 ASC_PRT_NEXT();
6520 for (i = 0; i <= ADV_MAX_TID; i++) {
6521 len = asc_prt_line(cp, leftlen, " %c",
6522 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6523 ASC_PRT_NEXT();
6524 }
6525 len = asc_prt_line(cp, leftlen, "\n");
6526 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006527
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006528 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6529 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6530 ASC_PRT_NEXT();
6531 for (i = 0; i <= ADV_MAX_TID; i++) {
6532 len = asc_prt_line(cp, leftlen, " %c",
6533 (ep_3550->
6534 sdtr_able & ADV_TID_TO_TIDMASK(i)) ?
6535 'Y' : 'N');
6536 ASC_PRT_NEXT();
6537 }
6538 len = asc_prt_line(cp, leftlen, "\n");
6539 ASC_PRT_NEXT();
6540 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006541
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006542 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6543 len = asc_prt_line(cp, leftlen, " Ultra Transfer: ");
6544 ASC_PRT_NEXT();
6545 for (i = 0; i <= ADV_MAX_TID; i++) {
6546 len = asc_prt_line(cp, leftlen, " %c",
6547 (ep_3550->
6548 ultra_able & ADV_TID_TO_TIDMASK(i))
6549 ? 'Y' : 'N');
6550 ASC_PRT_NEXT();
6551 }
6552 len = asc_prt_line(cp, leftlen, "\n");
6553 ASC_PRT_NEXT();
6554 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006555
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006556 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6557 word = ep_3550->wdtr_able;
6558 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6559 word = ep_38C0800->wdtr_able;
6560 } else {
6561 word = ep_38C1600->wdtr_able;
6562 }
6563 len = asc_prt_line(cp, leftlen, " Wide Transfer: ");
6564 ASC_PRT_NEXT();
6565 for (i = 0; i <= ADV_MAX_TID; i++) {
6566 len = asc_prt_line(cp, leftlen, " %c",
6567 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6568 ASC_PRT_NEXT();
6569 }
6570 len = asc_prt_line(cp, leftlen, "\n");
6571 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006572
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006573 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800 ||
6574 adv_dvc_varp->chip_type == ADV_CHIP_ASC38C1600) {
6575 len = asc_prt_line(cp, leftlen,
6576 " Synchronous Transfer Speed (Mhz):\n ");
6577 ASC_PRT_NEXT();
6578 for (i = 0; i <= ADV_MAX_TID; i++) {
6579 char *speed_str;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006580
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006581 if (i == 0) {
6582 sdtr_speed = adv_dvc_varp->sdtr_speed1;
6583 } else if (i == 4) {
6584 sdtr_speed = adv_dvc_varp->sdtr_speed2;
6585 } else if (i == 8) {
6586 sdtr_speed = adv_dvc_varp->sdtr_speed3;
6587 } else if (i == 12) {
6588 sdtr_speed = adv_dvc_varp->sdtr_speed4;
6589 }
6590 switch (sdtr_speed & ADV_MAX_TID) {
6591 case 0:
6592 speed_str = "Off";
6593 break;
6594 case 1:
6595 speed_str = " 5";
6596 break;
6597 case 2:
6598 speed_str = " 10";
6599 break;
6600 case 3:
6601 speed_str = " 20";
6602 break;
6603 case 4:
6604 speed_str = " 40";
6605 break;
6606 case 5:
6607 speed_str = " 80";
6608 break;
6609 default:
6610 speed_str = "Unk";
6611 break;
6612 }
6613 len = asc_prt_line(cp, leftlen, "%X:%s ", i, speed_str);
6614 ASC_PRT_NEXT();
6615 if (i == 7) {
6616 len = asc_prt_line(cp, leftlen, "\n ");
6617 ASC_PRT_NEXT();
6618 }
6619 sdtr_speed >>= 4;
6620 }
6621 len = asc_prt_line(cp, leftlen, "\n");
6622 ASC_PRT_NEXT();
6623 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006624
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006625 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006626}
6627
6628/*
6629 * asc_prt_driver_conf()
6630 *
6631 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6632 * cf. asc_prt_line().
6633 *
6634 * Return the number of characters copied into 'cp'. No more than
6635 * 'cplen' characters will be copied to 'cp'.
6636 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006637static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006638{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006639 asc_board_t *boardp;
6640 int leftlen;
6641 int totlen;
6642 int len;
6643 int chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006644
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006645 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006646
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006647 leftlen = cplen;
6648 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006649
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006650 len = asc_prt_line(cp, leftlen,
6651 "\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n",
6652 shost->host_no);
6653 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006654
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006655 len = asc_prt_line(cp, leftlen,
6656 " host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n",
6657 shost->host_busy, shost->last_reset, shost->max_id,
6658 shost->max_lun, shost->max_channel);
6659 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006660
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006661 len = asc_prt_line(cp, leftlen,
6662 " unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
6663 shost->unique_id, shost->can_queue, shost->this_id,
6664 shost->sg_tablesize, shost->cmd_per_lun);
6665 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006666
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006667 len = asc_prt_line(cp, leftlen,
6668 " unchecked_isa_dma %d, use_clustering %d\n",
6669 shost->unchecked_isa_dma, shost->use_clustering);
6670 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006671
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006672 len = asc_prt_line(cp, leftlen,
6673 " flags 0x%x, last_reset 0x%x, jiffies 0x%x, asc_n_io_port 0x%x\n",
6674 boardp->flags, boardp->last_reset, jiffies,
6675 boardp->asc_n_io_port);
6676 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006677
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04006678 len = asc_prt_line(cp, leftlen, " io_port 0x%x\n", shost->io_port);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006679 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006680
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006681 if (ASC_NARROW_BOARD(boardp)) {
6682 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
6683 } else {
6684 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
6685 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006686
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006687 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006688}
6689
6690/*
6691 * asc_prt_asc_board_info()
6692 *
6693 * Print dynamic board configuration information.
6694 *
6695 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6696 * cf. asc_prt_line().
6697 *
6698 * Return the number of characters copied into 'cp'. No more than
6699 * 'cplen' characters will be copied to 'cp'.
6700 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006701static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006702{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006703 asc_board_t *boardp;
6704 int chip_scsi_id;
6705 int leftlen;
6706 int totlen;
6707 int len;
6708 ASC_DVC_VAR *v;
6709 ASC_DVC_CFG *c;
6710 int i;
6711 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006712
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006713 boardp = ASC_BOARDP(shost);
6714 v = &boardp->dvc_var.asc_dvc_var;
6715 c = &boardp->dvc_cfg.asc_dvc_cfg;
6716 chip_scsi_id = c->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006717
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006718 leftlen = cplen;
6719 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006720
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006721 len = asc_prt_line(cp, leftlen,
6722 "\nAsc Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
6723 shost->host_no);
6724 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006725
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006726 len = asc_prt_line(cp, leftlen,
6727 " chip_version %u, lib_version 0x%x, lib_serial_no %u, mcode_date 0x%x\n",
6728 c->chip_version, c->lib_version, c->lib_serial_no,
6729 c->mcode_date);
6730 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006731
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006732 len = asc_prt_line(cp, leftlen,
6733 " mcode_version 0x%x, err_code %u\n",
6734 c->mcode_version, v->err_code);
6735 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006736
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006737 /* Current number of commands waiting for the host. */
6738 len = asc_prt_line(cp, leftlen,
6739 " Total Command Pending: %d\n", v->cur_total_qng);
6740 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006741
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006742 len = asc_prt_line(cp, leftlen, " Command Queuing:");
6743 ASC_PRT_NEXT();
6744 for (i = 0; i <= ASC_MAX_TID; i++) {
6745 if ((chip_scsi_id == i) ||
6746 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6747 continue;
6748 }
6749 len = asc_prt_line(cp, leftlen, " %X:%c",
6750 i,
6751 (v->
6752 use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ?
6753 'Y' : 'N');
6754 ASC_PRT_NEXT();
6755 }
6756 len = asc_prt_line(cp, leftlen, "\n");
6757 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006758
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006759 /* Current number of commands waiting for a device. */
6760 len = asc_prt_line(cp, leftlen, " Command Queue Pending:");
6761 ASC_PRT_NEXT();
6762 for (i = 0; i <= ASC_MAX_TID; i++) {
6763 if ((chip_scsi_id == i) ||
6764 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6765 continue;
6766 }
6767 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->cur_dvc_qng[i]);
6768 ASC_PRT_NEXT();
6769 }
6770 len = asc_prt_line(cp, leftlen, "\n");
6771 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006772
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006773 /* Current limit on number of commands that can be sent to a device. */
6774 len = asc_prt_line(cp, leftlen, " Command Queue Limit:");
6775 ASC_PRT_NEXT();
6776 for (i = 0; i <= ASC_MAX_TID; i++) {
6777 if ((chip_scsi_id == i) ||
6778 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6779 continue;
6780 }
6781 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->max_dvc_qng[i]);
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 /* Indicate whether the device has returned queue full status. */
6788 len = asc_prt_line(cp, leftlen, " Command Queue Full:");
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 if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) {
6796 len = asc_prt_line(cp, leftlen, " %X:Y-%d",
6797 i, boardp->queue_full_cnt[i]);
6798 } else {
6799 len = asc_prt_line(cp, leftlen, " %X:N", i);
6800 }
6801 ASC_PRT_NEXT();
6802 }
6803 len = asc_prt_line(cp, leftlen, "\n");
6804 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006805
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006806 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6807 ASC_PRT_NEXT();
6808 for (i = 0; i <= ASC_MAX_TID; i++) {
6809 if ((chip_scsi_id == i) ||
6810 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6811 continue;
6812 }
6813 len = asc_prt_line(cp, leftlen, " %X:%c",
6814 i,
6815 (v->
6816 sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6817 'N');
6818 ASC_PRT_NEXT();
6819 }
6820 len = asc_prt_line(cp, leftlen, "\n");
6821 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006822
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006823 for (i = 0; i <= ASC_MAX_TID; i++) {
6824 uchar syn_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006825
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006826 if ((chip_scsi_id == i) ||
6827 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
6828 ((v->init_sdtr & ADV_TID_TO_TIDMASK(i)) == 0)) {
6829 continue;
6830 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006831
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006832 len = asc_prt_line(cp, leftlen, " %X:", i);
6833 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006834
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006835 if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0) {
6836 len = asc_prt_line(cp, leftlen, " Asynchronous");
6837 ASC_PRT_NEXT();
6838 } else {
6839 syn_period_ix =
6840 (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index -
6841 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006842
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006843 len = asc_prt_line(cp, leftlen,
6844 " Transfer Period Factor: %d (%d.%d Mhz),",
6845 v->sdtr_period_tbl[syn_period_ix],
6846 250 /
6847 v->sdtr_period_tbl[syn_period_ix],
6848 ASC_TENTHS(250,
6849 v->
6850 sdtr_period_tbl
6851 [syn_period_ix]));
6852 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006853
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006854 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
6855 boardp->
6856 sdtr_data[i] & ASC_SYN_MAX_OFFSET);
6857 ASC_PRT_NEXT();
6858 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006859
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006860 if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
6861 len = asc_prt_line(cp, leftlen, "*\n");
6862 renegotiate = 1;
6863 } else {
6864 len = asc_prt_line(cp, leftlen, "\n");
6865 }
6866 ASC_PRT_NEXT();
6867 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006868
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006869 if (renegotiate) {
6870 len = asc_prt_line(cp, leftlen,
6871 " * = Re-negotiation pending before next command.\n");
6872 ASC_PRT_NEXT();
6873 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006874
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006875 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006876}
6877
6878/*
6879 * asc_prt_adv_board_info()
6880 *
6881 * Print dynamic board configuration information.
6882 *
6883 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6884 * cf. asc_prt_line().
6885 *
6886 * Return the number of characters copied into 'cp'. No more than
6887 * 'cplen' characters will be copied to 'cp'.
6888 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006889static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006890{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006891 asc_board_t *boardp;
6892 int leftlen;
6893 int totlen;
6894 int len;
6895 int i;
6896 ADV_DVC_VAR *v;
6897 ADV_DVC_CFG *c;
6898 AdvPortAddr iop_base;
6899 ushort chip_scsi_id;
6900 ushort lramword;
6901 uchar lrambyte;
6902 ushort tagqng_able;
6903 ushort sdtr_able, wdtr_able;
6904 ushort wdtr_done, sdtr_done;
6905 ushort period = 0;
6906 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006907
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006908 boardp = ASC_BOARDP(shost);
6909 v = &boardp->dvc_var.adv_dvc_var;
6910 c = &boardp->dvc_cfg.adv_dvc_cfg;
6911 iop_base = v->iop_base;
6912 chip_scsi_id = v->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006913
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006914 leftlen = cplen;
6915 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006916
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006917 len = asc_prt_line(cp, leftlen,
6918 "\nAdv Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
6919 shost->host_no);
6920 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006921
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006922 len = asc_prt_line(cp, leftlen,
6923 " iop_base 0x%lx, cable_detect: %X, err_code %u\n",
6924 v->iop_base,
6925 AdvReadWordRegister(iop_base,
6926 IOPW_SCSI_CFG1) & CABLE_DETECT,
6927 v->err_code);
6928 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006929
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006930 len = asc_prt_line(cp, leftlen,
6931 " chip_version %u, lib_version 0x%x, mcode_date 0x%x, mcode_version 0x%x\n",
6932 c->chip_version, c->lib_version, c->mcode_date,
6933 c->mcode_version);
6934 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006935
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006936 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
6937 len = asc_prt_line(cp, leftlen, " Queuing Enabled:");
6938 ASC_PRT_NEXT();
6939 for (i = 0; i <= ADV_MAX_TID; i++) {
6940 if ((chip_scsi_id == i) ||
6941 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6942 continue;
6943 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006944
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006945 len = asc_prt_line(cp, leftlen, " %X:%c",
6946 i,
6947 (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6948 'N');
6949 ASC_PRT_NEXT();
6950 }
6951 len = asc_prt_line(cp, leftlen, "\n");
6952 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006953
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006954 len = asc_prt_line(cp, leftlen, " Queue Limit:");
6955 ASC_PRT_NEXT();
6956 for (i = 0; i <= ADV_MAX_TID; i++) {
6957 if ((chip_scsi_id == i) ||
6958 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6959 continue;
6960 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006961
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006962 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + i,
6963 lrambyte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006964
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006965 len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
6966 ASC_PRT_NEXT();
6967 }
6968 len = asc_prt_line(cp, leftlen, "\n");
6969 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006970
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006971 len = asc_prt_line(cp, leftlen, " Command Pending:");
6972 ASC_PRT_NEXT();
6973 for (i = 0; i <= ADV_MAX_TID; i++) {
6974 if ((chip_scsi_id == i) ||
6975 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6976 continue;
6977 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006978
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006979 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_QUEUED_CMD + i,
6980 lrambyte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006981
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006982 len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
6983 ASC_PRT_NEXT();
6984 }
6985 len = asc_prt_line(cp, leftlen, "\n");
6986 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006987
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006988 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
6989 len = asc_prt_line(cp, leftlen, " Wide Enabled:");
6990 ASC_PRT_NEXT();
6991 for (i = 0; i <= ADV_MAX_TID; i++) {
6992 if ((chip_scsi_id == i) ||
6993 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6994 continue;
6995 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006996
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006997 len = asc_prt_line(cp, leftlen, " %X:%c",
6998 i,
6999 (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
7000 'N');
7001 ASC_PRT_NEXT();
7002 }
7003 len = asc_prt_line(cp, leftlen, "\n");
7004 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007005
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007006 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done);
7007 len = asc_prt_line(cp, leftlen, " Transfer Bit Width:");
7008 ASC_PRT_NEXT();
7009 for (i = 0; i <= ADV_MAX_TID; i++) {
7010 if ((chip_scsi_id == i) ||
7011 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7012 continue;
7013 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007014
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007015 AdvReadWordLram(iop_base,
7016 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
7017 lramword);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007018
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007019 len = asc_prt_line(cp, leftlen, " %X:%d",
7020 i, (lramword & 0x8000) ? 16 : 8);
7021 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007022
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007023 if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) &&
7024 (wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
7025 len = asc_prt_line(cp, leftlen, "*");
7026 ASC_PRT_NEXT();
7027 renegotiate = 1;
7028 }
7029 }
7030 len = asc_prt_line(cp, leftlen, "\n");
7031 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007032
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007033 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
7034 len = asc_prt_line(cp, leftlen, " Synchronous Enabled:");
7035 ASC_PRT_NEXT();
7036 for (i = 0; i <= ADV_MAX_TID; i++) {
7037 if ((chip_scsi_id == i) ||
7038 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7039 continue;
7040 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007041
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007042 len = asc_prt_line(cp, leftlen, " %X:%c",
7043 i,
7044 (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
7045 'N');
7046 ASC_PRT_NEXT();
7047 }
7048 len = asc_prt_line(cp, leftlen, "\n");
7049 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007050
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007051 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done);
7052 for (i = 0; i <= ADV_MAX_TID; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007053
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007054 AdvReadWordLram(iop_base,
7055 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
7056 lramword);
7057 lramword &= ~0x8000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007058
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007059 if ((chip_scsi_id == i) ||
7060 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
7061 ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0)) {
7062 continue;
7063 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007064
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007065 len = asc_prt_line(cp, leftlen, " %X:", i);
7066 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007067
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007068 if ((lramword & 0x1F) == 0) { /* Check for REQ/ACK Offset 0. */
7069 len = asc_prt_line(cp, leftlen, " Asynchronous");
7070 ASC_PRT_NEXT();
7071 } else {
7072 len =
7073 asc_prt_line(cp, leftlen,
7074 " Transfer Period Factor: ");
7075 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007076
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007077 if ((lramword & 0x1F00) == 0x1100) { /* 80 Mhz */
7078 len =
7079 asc_prt_line(cp, leftlen, "9 (80.0 Mhz),");
7080 ASC_PRT_NEXT();
7081 } else if ((lramword & 0x1F00) == 0x1000) { /* 40 Mhz */
7082 len =
7083 asc_prt_line(cp, leftlen, "10 (40.0 Mhz),");
7084 ASC_PRT_NEXT();
7085 } else { /* 20 Mhz or below. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007086
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007087 period = (((lramword >> 8) * 25) + 50) / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007088
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007089 if (period == 0) { /* Should never happen. */
7090 len =
7091 asc_prt_line(cp, leftlen,
7092 "%d (? Mhz), ");
7093 ASC_PRT_NEXT();
7094 } else {
7095 len = asc_prt_line(cp, leftlen,
7096 "%d (%d.%d Mhz),",
7097 period, 250 / period,
7098 ASC_TENTHS(250,
7099 period));
7100 ASC_PRT_NEXT();
7101 }
7102 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007103
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007104 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
7105 lramword & 0x1F);
7106 ASC_PRT_NEXT();
7107 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007108
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007109 if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
7110 len = asc_prt_line(cp, leftlen, "*\n");
7111 renegotiate = 1;
7112 } else {
7113 len = asc_prt_line(cp, leftlen, "\n");
7114 }
7115 ASC_PRT_NEXT();
7116 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007117
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007118 if (renegotiate) {
7119 len = asc_prt_line(cp, leftlen,
7120 " * = Re-negotiation pending before next command.\n");
7121 ASC_PRT_NEXT();
7122 }
7123
7124 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007125}
7126
7127/*
7128 * asc_proc_copy()
7129 *
7130 * Copy proc information to a read buffer taking into account the current
7131 * read offset in the file and the remaining space in the read buffer.
7132 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007133static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07007134asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007135 char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007136{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007137 int cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007138
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007139 ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n",
7140 (unsigned)offset, (unsigned)advoffset, cplen);
7141 if (offset <= advoffset) {
7142 /* Read offset below current offset, copy everything. */
7143 cnt = min(cplen, leftlen);
7144 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
7145 (ulong)curbuf, (ulong)cp, cnt);
7146 memcpy(curbuf, cp, cnt);
7147 } else if (offset < advoffset + cplen) {
7148 /* Read offset within current range, partial copy. */
7149 cnt = (advoffset + cplen) - offset;
7150 cp = (cp + cplen) - cnt;
7151 cnt = min(cnt, leftlen);
7152 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
7153 (ulong)curbuf, (ulong)cp, cnt);
7154 memcpy(curbuf, cp, cnt);
7155 }
7156 return cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007157}
7158
7159/*
7160 * asc_prt_line()
7161 *
7162 * If 'cp' is NULL print to the console, otherwise print to a buffer.
7163 *
7164 * Return 0 if printing to the console, otherwise return the number of
7165 * bytes written to the buffer.
7166 *
7167 * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack
7168 * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes.
7169 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007170static int asc_prt_line(char *buf, int buflen, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007171{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007172 va_list args;
7173 int ret;
7174 char s[ASC_PRTLINE_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07007175
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007176 va_start(args, fmt);
7177 ret = vsprintf(s, fmt, args);
7178 ASC_ASSERT(ret < ASC_PRTLINE_SIZE);
7179 if (buf == NULL) {
7180 (void)printk(s);
7181 ret = 0;
7182 } else {
7183 ret = min(buflen, ret);
7184 memcpy(buf, s, ret);
7185 }
7186 va_end(args);
7187 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007188}
7189#endif /* CONFIG_PROC_FS */
7190
Linus Torvalds1da177e2005-04-16 15:20:36 -07007191/*
7192 * --- Functions Required by the Asc Library
7193 */
7194
7195/*
7196 * Delay for 'n' milliseconds. Don't use the 'jiffies'
7197 * global variable which is incremented once every 5 ms
7198 * from a timer interrupt, because this function may be
7199 * called when interrupts are disabled.
7200 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007201static void DvcSleepMilliSecond(ADV_DCNT n)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007202{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007203 ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", (ulong)n);
7204 mdelay(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007205}
7206
7207/*
7208 * Currently and inline noop but leave as a placeholder.
7209 * Leave DvcEnterCritical() as a noop placeholder.
7210 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007211static inline ulong DvcEnterCritical(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007212{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007213 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007214}
7215
7216/*
7217 * Critical sections are all protected by the board spinlock.
7218 * Leave DvcLeaveCritical() as a noop placeholder.
7219 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007220static inline void DvcLeaveCritical(ulong flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007221{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007222 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007223}
7224
7225/*
7226 * void
7227 * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
7228 *
7229 * Calling/Exit State:
7230 * none
7231 *
7232 * Description:
7233 * Output an ASC_SCSI_Q structure to the chip
7234 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007235static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07007236DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
7237{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007238 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007239
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007240 ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words);
7241 AscSetChipLramAddr(iop_base, s_addr);
7242 for (i = 0; i < 2 * words; i += 2) {
7243 if (i == 4 || i == 20) {
7244 continue;
7245 }
7246 outpw(iop_base + IOP_RAM_DATA,
7247 ((ushort)outbuf[i + 1] << 8) | outbuf[i]);
7248 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007249}
7250
7251/*
7252 * void
7253 * DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
7254 *
7255 * Calling/Exit State:
7256 * none
7257 *
7258 * Description:
7259 * Input an ASC_QDONE_INFO structure from the chip
7260 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007261static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07007262DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
7263{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007264 int i;
7265 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007266
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007267 AscSetChipLramAddr(iop_base, s_addr);
7268 for (i = 0; i < 2 * words; i += 2) {
7269 if (i == 10) {
7270 continue;
7271 }
7272 word = inpw(iop_base + IOP_RAM_DATA);
7273 inbuf[i] = word & 0xff;
7274 inbuf[i + 1] = (word >> 8) & 0xff;
7275 }
7276 ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007277}
7278
7279/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07007280 * Return the BIOS address of the adapter at the specified
7281 * I/O port and with the specified bus type.
7282 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007283static unsigned short __devinit
7284AscGetChipBiosAddress(PortAddr iop_base, unsigned short bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007285{
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007286 unsigned short cfg_lsw;
7287 unsigned short bios_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007288
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007289 /*
7290 * The PCI BIOS is re-located by the motherboard BIOS. Because
7291 * of this the driver can not determine where a PCI BIOS is
7292 * loaded and executes.
7293 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007294 if (bus_type & ASC_IS_PCI)
7295 return 0;
7296
Linus Torvalds1da177e2005-04-16 15:20:36 -07007297#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007298 if ((bus_type & ASC_IS_EISA) != 0) {
7299 cfg_lsw = AscGetEisaChipCfg(iop_base);
7300 cfg_lsw &= 0x000F;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007301 bios_addr = ASC_BIOS_MIN_ADDR + cfg_lsw * ASC_BIOS_BANK_SIZE;
7302 return bios_addr;
7303 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007304#endif /* CONFIG_ISA */
7305
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007306 cfg_lsw = AscGetChipCfgLsw(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007307
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007308 /*
7309 * ISA PnP uses the top bit as the 32K BIOS flag
7310 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007311 if (bus_type == ASC_IS_ISAPNP)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007312 cfg_lsw &= 0x7FFF;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007313 bios_addr = ASC_BIOS_MIN_ADDR + (cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE;
7314 return bios_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007315}
7316
Linus Torvalds1da177e2005-04-16 15:20:36 -07007317/*
7318 * --- Functions Required by the Adv Library
7319 */
7320
7321/*
7322 * DvcGetPhyAddr()
7323 *
7324 * Return the physical address of 'vaddr' and set '*lenp' to the
7325 * number of physically contiguous bytes that follow 'vaddr'.
7326 * 'flag' indicates the type of structure whose physical address
7327 * is being translated.
7328 *
7329 * Note: Because Linux currently doesn't page the kernel and all
7330 * kernel buffers are physically contiguous, leave '*lenp' unchanged.
7331 */
7332ADV_PADDR
7333DvcGetPhyAddr(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007334 uchar *vaddr, ADV_SDCNT *lenp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007335{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007336 ADV_PADDR paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007337
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007338 paddr = virt_to_bus(vaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007339
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007340 ASC_DBG4(4,
7341 "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n",
7342 (ulong)vaddr, (ulong)lenp, (ulong)*((ulong *)lenp),
7343 (ulong)paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007344
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007345 return paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007346}
7347
7348/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07007349 * --- Tracing and Debugging Functions
7350 */
7351
7352#ifdef ADVANSYS_STATS
7353#ifdef CONFIG_PROC_FS
7354/*
7355 * asc_prt_board_stats()
7356 *
7357 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
7358 * cf. asc_prt_line().
7359 *
7360 * Return the number of characters copied into 'cp'. No more than
7361 * 'cplen' characters will be copied to 'cp'.
7362 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007363static int asc_prt_board_stats(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007364{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007365 int leftlen;
7366 int totlen;
7367 int len;
7368 struct asc_stats *s;
7369 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007370
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007371 leftlen = cplen;
7372 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007373
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007374 boardp = ASC_BOARDP(shost);
7375 s = &boardp->asc_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007376
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007377 len = asc_prt_line(cp, leftlen,
7378 "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n",
7379 shost->host_no);
7380 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007381
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007382 len = asc_prt_line(cp, leftlen,
7383 " queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n",
7384 s->queuecommand, s->reset, s->biosparam,
7385 s->interrupt);
7386 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007387
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007388 len = asc_prt_line(cp, leftlen,
7389 " callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n",
7390 s->callback, s->done, s->build_error,
7391 s->adv_build_noreq, s->adv_build_nosg);
7392 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007393
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007394 len = asc_prt_line(cp, leftlen,
7395 " exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n",
7396 s->exe_noerror, s->exe_busy, s->exe_error,
7397 s->exe_unknown);
7398 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007399
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007400 /*
7401 * Display data transfer statistics.
7402 */
7403 if (s->cont_cnt > 0) {
7404 len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt);
7405 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007406
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007407 len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ",
7408 s->cont_xfer / 2,
7409 ASC_TENTHS(s->cont_xfer, 2));
7410 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007411
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007412 /* Contiguous transfer average size */
7413 len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kb\n",
7414 (s->cont_xfer / 2) / s->cont_cnt,
7415 ASC_TENTHS((s->cont_xfer / 2), s->cont_cnt));
7416 ASC_PRT_NEXT();
7417 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007418
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007419 if (s->sg_cnt > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007420
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007421 len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ",
7422 s->sg_cnt, s->sg_elem);
7423 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007424
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007425 len = asc_prt_line(cp, leftlen, "sg_xfer %lu.%01lu kb\n",
7426 s->sg_xfer / 2, ASC_TENTHS(s->sg_xfer, 2));
7427 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007428
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007429 /* Scatter gather transfer statistics */
7430 len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ",
7431 s->sg_elem / s->sg_cnt,
7432 ASC_TENTHS(s->sg_elem, s->sg_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, "avg_elem_size %lu.%01lu kb, ",
7436 (s->sg_xfer / 2) / s->sg_elem,
7437 ASC_TENTHS((s->sg_xfer / 2), s->sg_elem));
7438 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007439
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007440 len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n",
7441 (s->sg_xfer / 2) / s->sg_cnt,
7442 ASC_TENTHS((s->sg_xfer / 2), s->sg_cnt));
7443 ASC_PRT_NEXT();
7444 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007445
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007446 /*
7447 * Display request queuing statistics.
7448 */
7449 len = asc_prt_line(cp, leftlen,
7450 " Active and Waiting Request Queues (Time Unit: %d HZ):\n",
7451 HZ);
7452 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007453
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007454 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007455}
7456
7457/*
7458 * asc_prt_target_stats()
7459 *
7460 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
7461 * cf. asc_prt_line().
7462 *
7463 * This is separated from asc_prt_board_stats because a full set
7464 * of targets will overflow ASC_PRTBUF_SIZE.
7465 *
7466 * Return the number of characters copied into 'cp'. No more than
7467 * 'cplen' characters will be copied to 'cp'.
7468 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007469static int
7470asc_prt_target_stats(struct Scsi_Host *shost, int tgt_id, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007471{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007472 int leftlen;
7473 int totlen;
7474 int len;
7475 struct asc_stats *s;
7476 ushort chip_scsi_id;
7477 asc_board_t *boardp;
7478 asc_queue_t *active;
7479 asc_queue_t *waiting;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007480
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007481 leftlen = cplen;
7482 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007483
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007484 boardp = ASC_BOARDP(shost);
7485 s = &boardp->asc_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007486
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007487 active = &ASC_BOARDP(shost)->active;
7488 waiting = &ASC_BOARDP(shost)->waiting;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007489
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007490 if (ASC_NARROW_BOARD(boardp)) {
7491 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
7492 } else {
7493 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
7494 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007495
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007496 if ((chip_scsi_id == tgt_id) ||
7497 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(tgt_id)) == 0)) {
7498 return 0;
7499 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007500
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007501 do {
7502 if (active->q_tot_cnt[tgt_id] > 0
7503 || waiting->q_tot_cnt[tgt_id] > 0) {
7504 len = asc_prt_line(cp, leftlen, " target %d\n", tgt_id);
7505 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007506
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007507 len = asc_prt_line(cp, leftlen,
7508 " active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n",
7509 active->q_cur_cnt[tgt_id],
7510 active->q_max_cnt[tgt_id],
7511 active->q_tot_cnt[tgt_id],
7512 active->q_min_tim[tgt_id],
7513 active->q_max_tim[tgt_id],
7514 (active->q_tot_cnt[tgt_id] ==
7515 0) ? 0 : (active->
7516 q_tot_tim[tgt_id] /
7517 active->
7518 q_tot_cnt[tgt_id]),
7519 (active->q_tot_cnt[tgt_id] ==
7520 0) ? 0 : ASC_TENTHS(active->
7521 q_tot_tim
7522 [tgt_id],
7523 active->
7524 q_tot_cnt
7525 [tgt_id]));
7526 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007527
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007528 len = asc_prt_line(cp, leftlen,
7529 " waiting: cnt [cur %d, max %d, tot %u], time [min %u, max %u, avg %lu.%01lu]\n",
7530 waiting->q_cur_cnt[tgt_id],
7531 waiting->q_max_cnt[tgt_id],
7532 waiting->q_tot_cnt[tgt_id],
7533 waiting->q_min_tim[tgt_id],
7534 waiting->q_max_tim[tgt_id],
7535 (waiting->q_tot_cnt[tgt_id] ==
7536 0) ? 0 : (waiting->
7537 q_tot_tim[tgt_id] /
7538 waiting->
7539 q_tot_cnt[tgt_id]),
7540 (waiting->q_tot_cnt[tgt_id] ==
7541 0) ? 0 : ASC_TENTHS(waiting->
7542 q_tot_tim
7543 [tgt_id],
7544 waiting->
7545 q_tot_cnt
7546 [tgt_id]));
7547 ASC_PRT_NEXT();
7548 }
7549 } while (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007550
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007551 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007552}
7553#endif /* CONFIG_PROC_FS */
7554#endif /* ADVANSYS_STATS */
7555
7556#ifdef ADVANSYS_DEBUG
7557/*
7558 * asc_prt_scsi_host()
7559 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007560static void asc_prt_scsi_host(struct Scsi_Host *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007561{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007562 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007563
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007564 boardp = ASC_BOARDP(s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007565
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007566 printk("Scsi_Host at addr 0x%lx\n", (ulong)s);
7567 printk(" host_busy %u, host_no %d, last_reset %d,\n",
7568 s->host_busy, s->host_no, (unsigned)s->last_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007569
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04007570 printk(" base 0x%lx, io_port 0x%lx, irq 0x%x,\n",
7571 (ulong)s->base, (ulong)s->io_port, s->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007572
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007573 printk(" dma_channel %d, this_id %d, can_queue %d,\n",
7574 s->dma_channel, s->this_id, s->can_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007575
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007576 printk(" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
7577 s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007578
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007579 if (ASC_NARROW_BOARD(boardp)) {
7580 asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var);
7581 asc_prt_asc_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.asc_dvc_cfg);
7582 } else {
7583 asc_prt_adv_dvc_var(&ASC_BOARDP(s)->dvc_var.adv_dvc_var);
7584 asc_prt_adv_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.adv_dvc_cfg);
7585 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007586}
7587
7588/*
7589 * asc_prt_scsi_cmnd()
7590 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007591static void asc_prt_scsi_cmnd(struct scsi_cmnd *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007592{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007593 printk("struct scsi_cmnd at addr 0x%lx\n", (ulong)s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007594
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007595 printk(" host 0x%lx, device 0x%lx, target %u, lun %u, channel %u,\n",
7596 (ulong)s->device->host, (ulong)s->device, s->device->id,
7597 s->device->lun, s->device->channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007598
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007599 asc_prt_hex(" CDB", s->cmnd, s->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007600
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007601 printk("sc_data_direction %u, resid %d\n",
7602 s->sc_data_direction, s->resid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007603
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007604 printk(" use_sg %u, sglist_len %u\n", s->use_sg, s->sglist_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007605
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007606 printk(" serial_number 0x%x, retries %d, allowed %d\n",
7607 (unsigned)s->serial_number, s->retries, s->allowed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007608
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007609 printk(" timeout_per_command %d\n", s->timeout_per_command);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007610
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007611 printk(" scsi_done 0x%p, done 0x%p, host_scribble 0x%p, result 0x%x\n",
7612 s->scsi_done, s->done, s->host_scribble, s->result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007613
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007614 printk(" tag %u, pid %u\n", (unsigned)s->tag, (unsigned)s->pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007615}
7616
7617/*
7618 * asc_prt_asc_dvc_var()
7619 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007620static void asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007621{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007622 printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007623
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007624 printk(" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl "
7625 "%d,\n", h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007626
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007627 printk(" bus_type %d, isr_callback 0x%p, exe_callback 0x%p, "
7628 "init_sdtr 0x%x,\n", h->bus_type, h->isr_callback,
7629 h->exe_callback, (unsigned)h->init_sdtr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007630
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007631 printk(" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, "
7632 "chip_no 0x%x,\n", (unsigned)h->sdtr_done,
7633 (unsigned)h->use_tagged_qng, (unsigned)h->unit_not_ready,
7634 (unsigned)h->chip_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007635
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007636 printk(" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait "
7637 "%u,\n", (unsigned)h->queue_full_or_busy,
7638 (unsigned)h->start_motor, (unsigned)h->scsi_reset_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007639
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007640 printk(" is_in_int %u, max_total_qng %u, cur_total_qng %u, "
7641 "in_critical_cnt %u,\n", (unsigned)h->is_in_int,
7642 (unsigned)h->max_total_qng, (unsigned)h->cur_total_qng,
7643 (unsigned)h->in_critical_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007644
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007645 printk(" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, "
7646 "pci_fix_asyn_xfer 0x%x,\n", (unsigned)h->last_q_shortage,
7647 (unsigned)h->init_state, (unsigned)h->no_scam,
7648 (unsigned)h->pci_fix_asyn_xfer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007649
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007650 printk(" cfg 0x%lx, irq_no 0x%x\n", (ulong)h->cfg, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007651}
7652
7653/*
7654 * asc_prt_asc_dvc_cfg()
7655 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007656static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007657{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007658 printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007659
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007660 printk(" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n",
7661 h->can_tagged_qng, h->cmd_qng_enabled);
7662 printk(" disc_enable 0x%x, sdtr_enable 0x%x,\n",
7663 h->disc_enable, h->sdtr_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007664
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007665 printk
7666 (" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n",
7667 h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel,
7668 h->chip_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007669
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007670 printk
7671 (" pci_device_id %d, lib_serial_no %u, lib_version %u, mcode_date 0x%x,\n",
7672 to_pci_dev(h->dev)->device, h->lib_serial_no, h->lib_version,
7673 h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007674
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007675 printk(" mcode_version %d, overrun_buf 0x%lx\n",
7676 h->mcode_version, (ulong)h->overrun_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007677}
7678
7679/*
7680 * asc_prt_asc_scsi_q()
7681 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007682static void asc_prt_asc_scsi_q(ASC_SCSI_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007683{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007684 ASC_SG_HEAD *sgp;
7685 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007686
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007687 printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007688
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007689 printk
7690 (" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n",
7691 q->q2.target_ix, q->q1.target_lun, (ulong)q->q2.srb_ptr,
7692 q->q2.tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007693
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007694 printk
7695 (" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
7696 (ulong)le32_to_cpu(q->q1.data_addr),
7697 (ulong)le32_to_cpu(q->q1.data_cnt),
7698 (ulong)le32_to_cpu(q->q1.sense_addr), q->q1.sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007699
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007700 printk(" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n",
7701 (ulong)q->cdbptr, q->q2.cdb_len,
7702 (ulong)q->sg_head, q->q1.sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007703
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007704 if (q->sg_head) {
7705 sgp = q->sg_head;
7706 printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong)sgp);
7707 printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt,
7708 sgp->queue_cnt);
7709 for (i = 0; i < sgp->entry_cnt; i++) {
7710 printk(" [%u]: addr 0x%lx, bytes %lu\n",
7711 i, (ulong)le32_to_cpu(sgp->sg_list[i].addr),
7712 (ulong)le32_to_cpu(sgp->sg_list[i].bytes));
7713 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007714
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007715 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007716}
7717
7718/*
7719 * asc_prt_asc_qdone_info()
7720 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007721static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007722{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007723 printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong)q);
7724 printk(" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n",
7725 (ulong)q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
7726 q->d2.tag_code);
7727 printk
7728 (" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n",
7729 q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007730}
7731
7732/*
7733 * asc_prt_adv_dvc_var()
7734 *
7735 * Display an ADV_DVC_VAR structure.
7736 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007737static void asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007738{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007739 printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007740
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007741 printk(" iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n",
7742 (ulong)h->iop_base, h->err_code, (unsigned)h->ultra_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007743
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007744 printk(" isr_callback 0x%lx, sdtr_able 0x%x, wdtr_able 0x%x\n",
7745 (ulong)h->isr_callback, (unsigned)h->sdtr_able,
7746 (unsigned)h->wdtr_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007747
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007748 printk(" start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n",
7749 (unsigned)h->start_motor,
7750 (unsigned)h->scsi_reset_wait, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007751
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007752 printk(" max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n",
7753 (unsigned)h->max_host_qng, (unsigned)h->max_dvc_qng,
7754 (ulong)h->carr_freelist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007755
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007756 printk(" icq_sp 0x%lx, irq_sp 0x%lx\n",
7757 (ulong)h->icq_sp, (ulong)h->irq_sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007758
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007759 printk(" no_scam 0x%x, tagqng_able 0x%x\n",
7760 (unsigned)h->no_scam, (unsigned)h->tagqng_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007761
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007762 printk(" chip_scsi_id 0x%x, cfg 0x%lx\n",
7763 (unsigned)h->chip_scsi_id, (ulong)h->cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007764}
7765
7766/*
7767 * asc_prt_adv_dvc_cfg()
7768 *
7769 * Display an ADV_DVC_CFG structure.
7770 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007771static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007772{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007773 printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007774
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007775 printk(" disc_enable 0x%x, termination 0x%x\n",
7776 h->disc_enable, h->termination);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007777
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007778 printk(" chip_version 0x%x, mcode_date 0x%x\n",
7779 h->chip_version, h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007780
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007781 printk(" mcode_version 0x%x, pci_device_id 0x%x, lib_version %u\n",
7782 h->mcode_version, to_pci_dev(h->dev)->device, h->lib_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007783
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007784 printk(" control_flag 0x%x, pci_slot_info 0x%x\n",
7785 h->control_flag, h->pci_slot_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007786}
7787
7788/*
7789 * asc_prt_adv_scsi_req_q()
7790 *
7791 * Display an ADV_SCSI_REQ_Q structure.
7792 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007793static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007794{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007795 int sg_blk_cnt;
7796 struct asc_sg_block *sg_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007797
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007798 printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007799
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007800 printk(" target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n",
7801 q->target_id, q->target_lun, (ulong)q->srb_ptr, q->a_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007802
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007803 printk(" cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
7804 q->cntl, (ulong)le32_to_cpu(q->data_addr), (ulong)q->vdata_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007805
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007806 printk(" data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
7807 (ulong)le32_to_cpu(q->data_cnt),
7808 (ulong)le32_to_cpu(q->sense_addr), q->sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007809
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007810 printk
7811 (" cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n",
7812 q->cdb_len, q->done_status, q->host_status, q->scsi_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007813
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007814 printk(" sg_working_ix 0x%x, target_cmd %u\n",
7815 q->sg_working_ix, q->target_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007816
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007817 printk(" scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n",
7818 (ulong)le32_to_cpu(q->scsiq_rptr),
7819 (ulong)le32_to_cpu(q->sg_real_addr), (ulong)q->sg_list_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007820
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007821 /* Display the request's ADV_SG_BLOCK structures. */
7822 if (q->sg_list_ptr != NULL) {
7823 sg_blk_cnt = 0;
7824 while (1) {
7825 /*
7826 * 'sg_ptr' is a physical address. Convert it to a virtual
7827 * address by indexing 'sg_blk_cnt' into the virtual address
7828 * array 'sg_list_ptr'.
7829 *
7830 * XXX - Assumes all SG physical blocks are virtually contiguous.
7831 */
7832 sg_ptr =
7833 &(((ADV_SG_BLOCK *)(q->sg_list_ptr))[sg_blk_cnt]);
7834 asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr);
7835 if (sg_ptr->sg_ptr == 0) {
7836 break;
7837 }
7838 sg_blk_cnt++;
7839 }
7840 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007841}
7842
7843/*
7844 * asc_prt_adv_sgblock()
7845 *
7846 * Display an ADV_SG_BLOCK structure.
7847 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007848static void asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007849{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007850 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007851
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007852 printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n",
7853 (ulong)b, sgblockno);
7854 printk(" sg_cnt %u, sg_ptr 0x%lx\n",
7855 b->sg_cnt, (ulong)le32_to_cpu(b->sg_ptr));
7856 ASC_ASSERT(b->sg_cnt <= NO_OF_SG_PER_BLOCK);
7857 if (b->sg_ptr != 0) {
7858 ASC_ASSERT(b->sg_cnt == NO_OF_SG_PER_BLOCK);
7859 }
7860 for (i = 0; i < b->sg_cnt; i++) {
7861 printk(" [%u]: sg_addr 0x%lx, sg_count 0x%lx\n",
7862 i, (ulong)b->sg_list[i].sg_addr,
7863 (ulong)b->sg_list[i].sg_count);
7864 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007865}
7866
7867/*
7868 * asc_prt_hex()
7869 *
7870 * Print hexadecimal output in 4 byte groupings 32 bytes
7871 * or 8 double-words per line.
7872 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007873static void asc_prt_hex(char *f, uchar *s, int l)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007874{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007875 int i;
7876 int j;
7877 int k;
7878 int m;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007879
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007880 printk("%s: (%d bytes)\n", f, l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007881
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007882 for (i = 0; i < l; i += 32) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007883
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007884 /* Display a maximum of 8 double-words per line. */
7885 if ((k = (l - i) / 4) >= 8) {
7886 k = 8;
7887 m = 0;
7888 } else {
7889 m = (l - i) % 4;
7890 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007891
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007892 for (j = 0; j < k; j++) {
7893 printk(" %2.2X%2.2X%2.2X%2.2X",
7894 (unsigned)s[i + (j * 4)],
7895 (unsigned)s[i + (j * 4) + 1],
7896 (unsigned)s[i + (j * 4) + 2],
7897 (unsigned)s[i + (j * 4) + 3]);
7898 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007899
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007900 switch (m) {
7901 case 0:
7902 default:
7903 break;
7904 case 1:
7905 printk(" %2.2X", (unsigned)s[i + (j * 4)]);
7906 break;
7907 case 2:
7908 printk(" %2.2X%2.2X",
7909 (unsigned)s[i + (j * 4)],
7910 (unsigned)s[i + (j * 4) + 1]);
7911 break;
7912 case 3:
7913 printk(" %2.2X%2.2X%2.2X",
7914 (unsigned)s[i + (j * 4) + 1],
7915 (unsigned)s[i + (j * 4) + 2],
7916 (unsigned)s[i + (j * 4) + 3]);
7917 break;
7918 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007919
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007920 printk("\n");
7921 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007922}
7923#endif /* ADVANSYS_DEBUG */
7924
7925/*
7926 * --- Asc Library Functions
7927 */
7928
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007929static ushort __devinit AscGetEisaChipCfg(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007930{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007931 PortAddr eisa_cfg_iop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007932
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007933 eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
7934 (PortAddr) (ASC_EISA_CFG_IOP_MASK);
7935 return (inpw(eisa_cfg_iop));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007936}
7937
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007938static uchar __devinit AscSetChipScsiID(PortAddr iop_base, uchar new_host_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007939{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007940 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007941
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007942 if (AscGetChipScsiID(iop_base) == new_host_id) {
7943 return (new_host_id);
7944 }
7945 cfg_lsw = AscGetChipCfgLsw(iop_base);
7946 cfg_lsw &= 0xF8FF;
7947 cfg_lsw |= (ushort)((new_host_id & ASC_MAX_TID) << 8);
7948 AscSetChipCfgLsw(iop_base, cfg_lsw);
7949 return (AscGetChipScsiID(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007950}
7951
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007952static unsigned char __devinit AscGetChipScsiCtrl(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007953{
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007954 unsigned char sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007955
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007956 AscSetBank(iop_base, 1);
7957 sc = inp(iop_base + IOP_REG_SC);
7958 AscSetBank(iop_base, 0);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007959 return sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007960}
7961
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007962static unsigned char __devinit
7963AscGetChipVersion(PortAddr iop_base, unsigned short bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007964{
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007965 if (bus_type & ASC_IS_EISA) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007966 PortAddr eisa_iop;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007967 unsigned char revision;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007968 eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
7969 (PortAddr) ASC_EISA_REV_IOP_MASK;
7970 revision = inp(eisa_iop);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007971 return ASC_CHIP_MIN_VER_EISA - 1 + revision;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007972 }
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007973 return AscGetChipVerNo(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007974}
7975
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007976static ASC_DCNT
7977AscLoadMicroCode(PortAddr iop_base,
7978 ushort s_addr, uchar *mcode_buf, ushort mcode_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007979{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007980 ASC_DCNT chksum;
7981 ushort mcode_word_size;
7982 ushort mcode_chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007983
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007984 /* Write the microcode buffer starting at LRAM address 0. */
7985 mcode_word_size = (ushort)(mcode_size >> 1);
7986 AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
7987 AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007988
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007989 chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size);
7990 ASC_DBG1(1, "AscLoadMicroCode: chksum 0x%lx\n", (ulong)chksum);
7991 mcode_chksum = (ushort)AscMemSumLramWord(iop_base,
7992 (ushort)ASC_CODE_SEC_BEG,
7993 (ushort)((mcode_size -
7994 s_addr - (ushort)
7995 ASC_CODE_SEC_BEG) /
7996 2));
7997 ASC_DBG1(1, "AscLoadMicroCode: mcode_chksum 0x%lx\n",
7998 (ulong)mcode_chksum);
7999 AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum);
8000 AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size);
8001 return (chksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008002}
8003
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008004static int AscFindSignature(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008005{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008006 ushort sig_word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008007
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008008 ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureByte(0x%x) 0x%x\n",
8009 iop_base, AscGetChipSignatureByte(iop_base));
8010 if (AscGetChipSignatureByte(iop_base) == (uchar)ASC_1000_ID1B) {
8011 ASC_DBG2(1,
8012 "AscFindSignature: AscGetChipSignatureWord(0x%x) 0x%x\n",
8013 iop_base, AscGetChipSignatureWord(iop_base));
8014 sig_word = AscGetChipSignatureWord(iop_base);
8015 if ((sig_word == (ushort)ASC_1000_ID0W) ||
8016 (sig_word == (ushort)ASC_1000_ID0W_FIX)) {
8017 return (1);
8018 }
8019 }
8020 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008021}
8022
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008023static void __devinit AscToggleIRQAct(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008024{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008025 AscSetChipStatus(iop_base, CIW_IRQ_ACT);
8026 AscSetChipStatus(iop_base, 0);
8027 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008028}
8029
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008030static uchar __devinit AscGetChipIRQ(PortAddr iop_base, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008031{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008032 ushort cfg_lsw;
8033 uchar chip_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008034
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008035 if ((bus_type & ASC_IS_EISA) != 0) {
8036 cfg_lsw = AscGetEisaChipCfg(iop_base);
8037 chip_irq = (uchar)(((cfg_lsw >> 8) & 0x07) + 10);
8038 if ((chip_irq == 13) || (chip_irq > 15)) {
8039 return (0);
8040 }
8041 return (chip_irq);
8042 }
8043 if ((bus_type & ASC_IS_VL) != 0) {
8044 cfg_lsw = AscGetChipCfgLsw(iop_base);
8045 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x07));
8046 if ((chip_irq == 0) || (chip_irq == 4) || (chip_irq == 7)) {
8047 return (0);
8048 }
8049 return ((uchar)(chip_irq + (ASC_MIN_IRQ_NO - 1)));
8050 }
8051 cfg_lsw = AscGetChipCfgLsw(iop_base);
8052 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x03));
8053 if (chip_irq == 3)
8054 chip_irq += (uchar)2;
8055 return ((uchar)(chip_irq + ASC_MIN_IRQ_NO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008056}
8057
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008058static uchar __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008059AscSetChipIRQ(PortAddr iop_base, uchar irq_no, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008060{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008061 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008062
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008063 if ((bus_type & ASC_IS_VL) != 0) {
8064 if (irq_no != 0) {
8065 if ((irq_no < ASC_MIN_IRQ_NO)
8066 || (irq_no > ASC_MAX_IRQ_NO)) {
8067 irq_no = 0;
8068 } else {
8069 irq_no -= (uchar)((ASC_MIN_IRQ_NO - 1));
8070 }
8071 }
8072 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE3);
8073 cfg_lsw |= (ushort)0x0010;
8074 AscSetChipCfgLsw(iop_base, cfg_lsw);
8075 AscToggleIRQAct(iop_base);
8076 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE0);
8077 cfg_lsw |= (ushort)((irq_no & 0x07) << 2);
8078 AscSetChipCfgLsw(iop_base, cfg_lsw);
8079 AscToggleIRQAct(iop_base);
8080 return (AscGetChipIRQ(iop_base, bus_type));
8081 }
8082 if ((bus_type & (ASC_IS_ISA)) != 0) {
8083 if (irq_no == 15)
8084 irq_no -= (uchar)2;
8085 irq_no -= (uchar)ASC_MIN_IRQ_NO;
8086 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFF3);
8087 cfg_lsw |= (ushort)((irq_no & 0x03) << 2);
8088 AscSetChipCfgLsw(iop_base, cfg_lsw);
8089 return (AscGetChipIRQ(iop_base, bus_type));
8090 }
8091 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008092}
8093
8094#ifdef CONFIG_ISA
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008095static void __devinit AscEnableIsaDma(uchar dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008096{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008097 if (dma_channel < 4) {
8098 outp(0x000B, (ushort)(0xC0 | dma_channel));
8099 outp(0x000A, dma_channel);
8100 } else if (dma_channel < 8) {
8101 outp(0x00D6, (ushort)(0xC0 | (dma_channel - 4)));
8102 outp(0x00D4, (ushort)(dma_channel - 4));
8103 }
8104 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008105}
8106#endif /* CONFIG_ISA */
8107
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008108static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008109{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008110 EXT_MSG ext_msg;
8111 EXT_MSG out_msg;
8112 ushort halt_q_addr;
8113 int sdtr_accept;
8114 ushort int_halt_code;
8115 ASC_SCSI_BIT_ID_TYPE scsi_busy;
8116 ASC_SCSI_BIT_ID_TYPE target_id;
8117 PortAddr iop_base;
8118 uchar tag_code;
8119 uchar q_status;
8120 uchar halt_qp;
8121 uchar sdtr_data;
8122 uchar target_ix;
8123 uchar q_cntl, tid_no;
8124 uchar cur_dvc_qng;
8125 uchar asyn_sdtr;
8126 uchar scsi_status;
8127 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008128
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008129 ASC_ASSERT(asc_dvc->drv_ptr != NULL);
8130 boardp = asc_dvc->drv_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008131
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008132 iop_base = asc_dvc->iop_base;
8133 int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008134
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008135 halt_qp = AscReadLramByte(iop_base, ASCV_CURCDB_B);
8136 halt_q_addr = ASC_QNO_TO_QADDR(halt_qp);
8137 target_ix = AscReadLramByte(iop_base,
8138 (ushort)(halt_q_addr +
8139 (ushort)ASC_SCSIQ_B_TARGET_IX));
8140 q_cntl =
8141 AscReadLramByte(iop_base,
8142 (ushort)(halt_q_addr + (ushort)ASC_SCSIQ_B_CNTL));
8143 tid_no = ASC_TIX_TO_TID(target_ix);
8144 target_id = (uchar)ASC_TID_TO_TARGET_ID(tid_no);
8145 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8146 asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB;
8147 } else {
8148 asyn_sdtr = 0;
8149 }
8150 if (int_halt_code == ASC_HALT_DISABLE_ASYN_USE_SYN_FIX) {
8151 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8152 AscSetChipSDTR(iop_base, 0, tid_no);
8153 boardp->sdtr_data[tid_no] = 0;
8154 }
8155 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8156 return (0);
8157 } else if (int_halt_code == ASC_HALT_ENABLE_ASYN_USE_SYN_FIX) {
8158 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8159 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8160 boardp->sdtr_data[tid_no] = asyn_sdtr;
8161 }
8162 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8163 return (0);
8164 } else if (int_halt_code == ASC_HALT_EXTMSG_IN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008165
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008166 AscMemWordCopyPtrFromLram(iop_base,
8167 ASCV_MSGIN_BEG,
8168 (uchar *)&ext_msg,
8169 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008170
Matthew Wilcox47d853c2007-07-26 11:41:33 -04008171 if (ext_msg.msg_type == EXTENDED_MESSAGE &&
8172 ext_msg.msg_req == EXTENDED_SDTR &&
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008173 ext_msg.msg_len == MS_SDTR_LEN) {
8174 sdtr_accept = TRUE;
8175 if ((ext_msg.req_ack_offset > ASC_SYN_MAX_OFFSET)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008176
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008177 sdtr_accept = FALSE;
8178 ext_msg.req_ack_offset = ASC_SYN_MAX_OFFSET;
8179 }
8180 if ((ext_msg.xfer_period <
8181 asc_dvc->sdtr_period_tbl[asc_dvc->
8182 host_init_sdtr_index])
8183 || (ext_msg.xfer_period >
8184 asc_dvc->sdtr_period_tbl[asc_dvc->
8185 max_sdtr_index])) {
8186 sdtr_accept = FALSE;
8187 ext_msg.xfer_period =
8188 asc_dvc->sdtr_period_tbl[asc_dvc->
8189 host_init_sdtr_index];
8190 }
8191 if (sdtr_accept) {
8192 sdtr_data =
8193 AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
8194 ext_msg.req_ack_offset);
8195 if ((sdtr_data == 0xFF)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008196
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008197 q_cntl |= QC_MSG_OUT;
8198 asc_dvc->init_sdtr &= ~target_id;
8199 asc_dvc->sdtr_done &= ~target_id;
8200 AscSetChipSDTR(iop_base, asyn_sdtr,
8201 tid_no);
8202 boardp->sdtr_data[tid_no] = asyn_sdtr;
8203 }
8204 }
8205 if (ext_msg.req_ack_offset == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008206
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008207 q_cntl &= ~QC_MSG_OUT;
8208 asc_dvc->init_sdtr &= ~target_id;
8209 asc_dvc->sdtr_done &= ~target_id;
8210 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8211 } else {
8212 if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008213
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008214 q_cntl &= ~QC_MSG_OUT;
8215 asc_dvc->sdtr_done |= target_id;
8216 asc_dvc->init_sdtr |= target_id;
8217 asc_dvc->pci_fix_asyn_xfer &=
8218 ~target_id;
8219 sdtr_data =
8220 AscCalSDTRData(asc_dvc,
8221 ext_msg.xfer_period,
8222 ext_msg.
8223 req_ack_offset);
8224 AscSetChipSDTR(iop_base, sdtr_data,
8225 tid_no);
8226 boardp->sdtr_data[tid_no] = sdtr_data;
8227 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008228
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008229 q_cntl |= QC_MSG_OUT;
8230 AscMsgOutSDTR(asc_dvc,
8231 ext_msg.xfer_period,
8232 ext_msg.req_ack_offset);
8233 asc_dvc->pci_fix_asyn_xfer &=
8234 ~target_id;
8235 sdtr_data =
8236 AscCalSDTRData(asc_dvc,
8237 ext_msg.xfer_period,
8238 ext_msg.
8239 req_ack_offset);
8240 AscSetChipSDTR(iop_base, sdtr_data,
8241 tid_no);
8242 boardp->sdtr_data[tid_no] = sdtr_data;
8243 asc_dvc->sdtr_done |= target_id;
8244 asc_dvc->init_sdtr |= target_id;
8245 }
8246 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008247
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008248 AscWriteLramByte(iop_base,
8249 (ushort)(halt_q_addr +
8250 (ushort)ASC_SCSIQ_B_CNTL),
8251 q_cntl);
8252 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8253 return (0);
Matthew Wilcox47d853c2007-07-26 11:41:33 -04008254 } else if (ext_msg.msg_type == EXTENDED_MESSAGE &&
8255 ext_msg.msg_req == EXTENDED_WDTR &&
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008256 ext_msg.msg_len == MS_WDTR_LEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008257
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008258 ext_msg.wdtr_width = 0;
8259 AscMemWordCopyPtrToLram(iop_base,
8260 ASCV_MSGOUT_BEG,
8261 (uchar *)&ext_msg,
8262 sizeof(EXT_MSG) >> 1);
8263 q_cntl |= QC_MSG_OUT;
8264 AscWriteLramByte(iop_base,
8265 (ushort)(halt_q_addr +
8266 (ushort)ASC_SCSIQ_B_CNTL),
8267 q_cntl);
8268 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8269 return (0);
8270 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008271
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008272 ext_msg.msg_type = MESSAGE_REJECT;
8273 AscMemWordCopyPtrToLram(iop_base,
8274 ASCV_MSGOUT_BEG,
8275 (uchar *)&ext_msg,
8276 sizeof(EXT_MSG) >> 1);
8277 q_cntl |= QC_MSG_OUT;
8278 AscWriteLramByte(iop_base,
8279 (ushort)(halt_q_addr +
8280 (ushort)ASC_SCSIQ_B_CNTL),
8281 q_cntl);
8282 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8283 return (0);
8284 }
8285 } else if (int_halt_code == ASC_HALT_CHK_CONDITION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008286
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008287 q_cntl |= QC_REQ_SENSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008288
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008289 if ((asc_dvc->init_sdtr & target_id) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008290
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008291 asc_dvc->sdtr_done &= ~target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008292
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008293 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
8294 q_cntl |= QC_MSG_OUT;
8295 AscMsgOutSDTR(asc_dvc,
8296 asc_dvc->
8297 sdtr_period_tbl[(sdtr_data >> 4) &
8298 (uchar)(asc_dvc->
8299 max_sdtr_index -
8300 1)],
8301 (uchar)(sdtr_data & (uchar)
8302 ASC_SYN_MAX_OFFSET));
8303 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008304
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008305 AscWriteLramByte(iop_base,
8306 (ushort)(halt_q_addr +
8307 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008308
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008309 tag_code = AscReadLramByte(iop_base,
8310 (ushort)(halt_q_addr + (ushort)
8311 ASC_SCSIQ_B_TAG_CODE));
8312 tag_code &= 0xDC;
8313 if ((asc_dvc->pci_fix_asyn_xfer & target_id)
8314 && !(asc_dvc->pci_fix_asyn_xfer_always & target_id)
8315 ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008316
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008317 tag_code |= (ASC_TAG_FLAG_DISABLE_DISCONNECT
8318 | ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008319
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008320 }
8321 AscWriteLramByte(iop_base,
8322 (ushort)(halt_q_addr +
8323 (ushort)ASC_SCSIQ_B_TAG_CODE),
8324 tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008325
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008326 q_status = AscReadLramByte(iop_base,
8327 (ushort)(halt_q_addr + (ushort)
8328 ASC_SCSIQ_B_STATUS));
8329 q_status |= (QS_READY | QS_BUSY);
8330 AscWriteLramByte(iop_base,
8331 (ushort)(halt_q_addr +
8332 (ushort)ASC_SCSIQ_B_STATUS),
8333 q_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008334
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008335 scsi_busy = AscReadLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B);
8336 scsi_busy &= ~target_id;
8337 AscWriteLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B, scsi_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008338
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008339 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8340 return (0);
8341 } else if (int_halt_code == ASC_HALT_SDTR_REJECTED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008342
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008343 AscMemWordCopyPtrFromLram(iop_base,
8344 ASCV_MSGOUT_BEG,
8345 (uchar *)&out_msg,
8346 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008347
Matthew Wilcox47d853c2007-07-26 11:41:33 -04008348 if ((out_msg.msg_type == EXTENDED_MESSAGE) &&
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008349 (out_msg.msg_len == MS_SDTR_LEN) &&
Matthew Wilcox47d853c2007-07-26 11:41:33 -04008350 (out_msg.msg_req == EXTENDED_SDTR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008351
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008352 asc_dvc->init_sdtr &= ~target_id;
8353 asc_dvc->sdtr_done &= ~target_id;
8354 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8355 boardp->sdtr_data[tid_no] = asyn_sdtr;
8356 }
8357 q_cntl &= ~QC_MSG_OUT;
8358 AscWriteLramByte(iop_base,
8359 (ushort)(halt_q_addr +
8360 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
8361 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8362 return (0);
8363 } else if (int_halt_code == ASC_HALT_SS_QUEUE_FULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008364
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008365 scsi_status = AscReadLramByte(iop_base,
8366 (ushort)((ushort)halt_q_addr +
8367 (ushort)
8368 ASC_SCSIQ_SCSI_STATUS));
8369 cur_dvc_qng =
8370 AscReadLramByte(iop_base,
8371 (ushort)((ushort)ASC_QADR_BEG +
8372 (ushort)target_ix));
8373 if ((cur_dvc_qng > 0) && (asc_dvc->cur_dvc_qng[tid_no] > 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008374
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008375 scsi_busy = AscReadLramByte(iop_base,
8376 (ushort)ASCV_SCSIBUSY_B);
8377 scsi_busy |= target_id;
8378 AscWriteLramByte(iop_base,
8379 (ushort)ASCV_SCSIBUSY_B, scsi_busy);
8380 asc_dvc->queue_full_or_busy |= target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008381
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008382 if (scsi_status == SAM_STAT_TASK_SET_FULL) {
8383 if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) {
8384 cur_dvc_qng -= 1;
8385 asc_dvc->max_dvc_qng[tid_no] =
8386 cur_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008387
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008388 AscWriteLramByte(iop_base,
8389 (ushort)((ushort)
8390 ASCV_MAX_DVC_QNG_BEG
8391 + (ushort)
8392 tid_no),
8393 cur_dvc_qng);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008394
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008395 /*
8396 * Set the device queue depth to the number of
8397 * active requests when the QUEUE FULL condition
8398 * was encountered.
8399 */
8400 boardp->queue_full |= target_id;
8401 boardp->queue_full_cnt[tid_no] =
8402 cur_dvc_qng;
8403 }
8404 }
8405 }
8406 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8407 return (0);
8408 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008409#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008410 else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC) {
8411 uchar q_no;
8412 ushort q_addr;
8413 uchar sg_wk_q_no;
8414 uchar first_sg_wk_q_no;
8415 ASC_SCSI_Q *scsiq; /* Ptr to driver request. */
8416 ASC_SG_HEAD *sg_head; /* Ptr to driver SG request. */
8417 ASC_SG_LIST_Q scsi_sg_q; /* Structure written to queue. */
8418 ushort sg_list_dwords;
8419 ushort sg_entry_cnt;
8420 uchar next_qp;
8421 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008422
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008423 q_no = AscReadLramByte(iop_base, (ushort)ASCV_REQ_SG_LIST_QP);
8424 if (q_no == ASC_QLINK_END) {
8425 return (0);
8426 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008427
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008428 q_addr = ASC_QNO_TO_QADDR(q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008429
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008430 /*
8431 * Convert the request's SRB pointer to a host ASC_SCSI_REQ
8432 * structure pointer using a macro provided by the driver.
8433 * The ASC_SCSI_REQ pointer provides a pointer to the
8434 * host ASC_SG_HEAD structure.
8435 */
8436 /* Read request's SRB pointer. */
8437 scsiq = (ASC_SCSI_Q *)
8438 ASC_SRB2SCSIQ(ASC_U32_TO_VADDR(AscReadLramDWord(iop_base,
8439 (ushort)
8440 (q_addr +
8441 ASC_SCSIQ_D_SRBPTR))));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008442
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008443 /*
8444 * Get request's first and working SG queue.
8445 */
8446 sg_wk_q_no = AscReadLramByte(iop_base,
8447 (ushort)(q_addr +
8448 ASC_SCSIQ_B_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008449
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008450 first_sg_wk_q_no = AscReadLramByte(iop_base,
8451 (ushort)(q_addr +
8452 ASC_SCSIQ_B_FIRST_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008453
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008454 /*
8455 * Reset request's working SG queue back to the
8456 * first SG queue.
8457 */
8458 AscWriteLramByte(iop_base,
8459 (ushort)(q_addr +
8460 (ushort)ASC_SCSIQ_B_SG_WK_QP),
8461 first_sg_wk_q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008462
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008463 sg_head = scsiq->sg_head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008464
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008465 /*
8466 * Set sg_entry_cnt to the number of SG elements
8467 * that will be completed on this interrupt.
8468 *
8469 * Note: The allocated SG queues contain ASC_MAX_SG_LIST - 1
8470 * SG elements. The data_cnt and data_addr fields which
8471 * add 1 to the SG element capacity are not used when
8472 * restarting SG handling after a halt.
8473 */
8474 if (scsiq->remain_sg_entry_cnt > (ASC_MAX_SG_LIST - 1)) {
8475 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008476
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008477 /*
8478 * Keep track of remaining number of SG elements that will
8479 * need to be handled on the next interrupt.
8480 */
8481 scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1);
8482 } else {
8483 sg_entry_cnt = scsiq->remain_sg_entry_cnt;
8484 scsiq->remain_sg_entry_cnt = 0;
8485 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008486
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008487 /*
8488 * Copy SG elements into the list of allocated SG queues.
8489 *
8490 * Last index completed is saved in scsiq->next_sg_index.
8491 */
8492 next_qp = first_sg_wk_q_no;
8493 q_addr = ASC_QNO_TO_QADDR(next_qp);
8494 scsi_sg_q.sg_head_qp = q_no;
8495 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
8496 for (i = 0; i < sg_head->queue_cnt; i++) {
8497 scsi_sg_q.seq_no = i + 1;
8498 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
8499 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
8500 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
8501 /*
8502 * After very first SG queue RISC FW uses next
8503 * SG queue first element then checks sg_list_cnt
8504 * against zero and then decrements, so set
8505 * sg_list_cnt 1 less than number of SG elements
8506 * in each SG queue.
8507 */
8508 scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
8509 scsi_sg_q.sg_cur_list_cnt =
8510 ASC_SG_LIST_PER_Q - 1;
8511 } else {
8512 /*
8513 * This is the last SG queue in the list of
8514 * allocated SG queues. If there are more
8515 * SG elements than will fit in the allocated
8516 * queues, then set the QCSG_SG_XFER_MORE flag.
8517 */
8518 if (scsiq->remain_sg_entry_cnt != 0) {
8519 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
8520 } else {
8521 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
8522 }
8523 /* equals sg_entry_cnt * 2 */
8524 sg_list_dwords = sg_entry_cnt << 1;
8525 scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
8526 scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
8527 sg_entry_cnt = 0;
8528 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008529
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008530 scsi_sg_q.q_no = next_qp;
8531 AscMemWordCopyPtrToLram(iop_base,
8532 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
8533 (uchar *)&scsi_sg_q,
8534 sizeof(ASC_SG_LIST_Q) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008535
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008536 AscMemDWordCopyPtrToLram(iop_base,
8537 q_addr + ASC_SGQ_LIST_BEG,
8538 (uchar *)&sg_head->
8539 sg_list[scsiq->next_sg_index],
8540 sg_list_dwords);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008541
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008542 scsiq->next_sg_index += ASC_SG_LIST_PER_Q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008543
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008544 /*
8545 * If the just completed SG queue contained the
8546 * last SG element, then no more SG queues need
8547 * to be written.
8548 */
8549 if (scsi_sg_q.cntl & QCSG_SG_XFER_END) {
8550 break;
8551 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008552
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008553 next_qp = AscReadLramByte(iop_base,
8554 (ushort)(q_addr +
8555 ASC_SCSIQ_B_FWD));
8556 q_addr = ASC_QNO_TO_QADDR(next_qp);
8557 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008558
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008559 /*
8560 * Clear the halt condition so the RISC will be restarted
8561 * after the return.
8562 */
8563 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8564 return (0);
8565 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008566#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008567 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008568}
8569
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008570static uchar
8571_AscCopyLramScsiDoneQ(PortAddr iop_base,
8572 ushort q_addr,
8573 ASC_QDONE_INFO *scsiq, ASC_DCNT max_dma_count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008574{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008575 ushort _val;
8576 uchar sg_queue_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008577
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008578 DvcGetQinfo(iop_base,
8579 q_addr + ASC_SCSIQ_DONE_INFO_BEG,
8580 (uchar *)scsiq,
8581 (sizeof(ASC_SCSIQ_2) + sizeof(ASC_SCSIQ_3)) / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008582
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008583 _val = AscReadLramWord(iop_base,
8584 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS));
8585 scsiq->q_status = (uchar)_val;
8586 scsiq->q_no = (uchar)(_val >> 8);
8587 _val = AscReadLramWord(iop_base,
8588 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_CNTL));
8589 scsiq->cntl = (uchar)_val;
8590 sg_queue_cnt = (uchar)(_val >> 8);
8591 _val = AscReadLramWord(iop_base,
8592 (ushort)(q_addr +
8593 (ushort)ASC_SCSIQ_B_SENSE_LEN));
8594 scsiq->sense_len = (uchar)_val;
8595 scsiq->extra_bytes = (uchar)(_val >> 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008596
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008597 /*
8598 * Read high word of remain bytes from alternate location.
8599 */
8600 scsiq->remain_bytes = (((ADV_DCNT)AscReadLramWord(iop_base,
8601 (ushort)(q_addr +
8602 (ushort)
8603 ASC_SCSIQ_W_ALT_DC1)))
8604 << 16);
8605 /*
8606 * Read low word of remain bytes from original location.
8607 */
8608 scsiq->remain_bytes += AscReadLramWord(iop_base,
8609 (ushort)(q_addr + (ushort)
8610 ASC_SCSIQ_DW_REMAIN_XFER_CNT));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008611
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008612 scsiq->remain_bytes &= max_dma_count;
8613 return (sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008614}
8615
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008616static int AscIsrQDone(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008617{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008618 uchar next_qp;
8619 uchar n_q_used;
8620 uchar sg_list_qp;
8621 uchar sg_queue_cnt;
8622 uchar q_cnt;
8623 uchar done_q_tail;
8624 uchar tid_no;
8625 ASC_SCSI_BIT_ID_TYPE scsi_busy;
8626 ASC_SCSI_BIT_ID_TYPE target_id;
8627 PortAddr iop_base;
8628 ushort q_addr;
8629 ushort sg_q_addr;
8630 uchar cur_target_qng;
8631 ASC_QDONE_INFO scsiq_buf;
8632 ASC_QDONE_INFO *scsiq;
8633 int false_overrun;
8634 ASC_ISR_CALLBACK asc_isr_callback;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008635
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008636 iop_base = asc_dvc->iop_base;
8637 asc_isr_callback = asc_dvc->isr_callback;
8638 n_q_used = 1;
8639 scsiq = (ASC_QDONE_INFO *)&scsiq_buf;
8640 done_q_tail = (uchar)AscGetVarDoneQTail(iop_base);
8641 q_addr = ASC_QNO_TO_QADDR(done_q_tail);
8642 next_qp = AscReadLramByte(iop_base,
8643 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_FWD));
8644 if (next_qp != ASC_QLINK_END) {
8645 AscPutVarDoneQTail(iop_base, next_qp);
8646 q_addr = ASC_QNO_TO_QADDR(next_qp);
8647 sg_queue_cnt = _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq,
8648 asc_dvc->max_dma_count);
8649 AscWriteLramByte(iop_base,
8650 (ushort)(q_addr +
8651 (ushort)ASC_SCSIQ_B_STATUS),
8652 (uchar)(scsiq->
8653 q_status & (uchar)~(QS_READY |
8654 QS_ABORTED)));
8655 tid_no = ASC_TIX_TO_TID(scsiq->d2.target_ix);
8656 target_id = ASC_TIX_TO_TARGET_ID(scsiq->d2.target_ix);
8657 if ((scsiq->cntl & QC_SG_HEAD) != 0) {
8658 sg_q_addr = q_addr;
8659 sg_list_qp = next_qp;
8660 for (q_cnt = 0; q_cnt < sg_queue_cnt; q_cnt++) {
8661 sg_list_qp = AscReadLramByte(iop_base,
8662 (ushort)(sg_q_addr
8663 + (ushort)
8664 ASC_SCSIQ_B_FWD));
8665 sg_q_addr = ASC_QNO_TO_QADDR(sg_list_qp);
8666 if (sg_list_qp == ASC_QLINK_END) {
8667 AscSetLibErrorCode(asc_dvc,
8668 ASCQ_ERR_SG_Q_LINKS);
8669 scsiq->d3.done_stat = QD_WITH_ERROR;
8670 scsiq->d3.host_stat =
8671 QHSTA_D_QDONE_SG_LIST_CORRUPTED;
8672 goto FATAL_ERR_QDONE;
8673 }
8674 AscWriteLramByte(iop_base,
8675 (ushort)(sg_q_addr + (ushort)
8676 ASC_SCSIQ_B_STATUS),
8677 QS_FREE);
8678 }
8679 n_q_used = sg_queue_cnt + 1;
8680 AscPutVarDoneQTail(iop_base, sg_list_qp);
8681 }
8682 if (asc_dvc->queue_full_or_busy & target_id) {
8683 cur_target_qng = AscReadLramByte(iop_base,
8684 (ushort)((ushort)
8685 ASC_QADR_BEG
8686 + (ushort)
8687 scsiq->d2.
8688 target_ix));
8689 if (cur_target_qng < asc_dvc->max_dvc_qng[tid_no]) {
8690 scsi_busy = AscReadLramByte(iop_base, (ushort)
8691 ASCV_SCSIBUSY_B);
8692 scsi_busy &= ~target_id;
8693 AscWriteLramByte(iop_base,
8694 (ushort)ASCV_SCSIBUSY_B,
8695 scsi_busy);
8696 asc_dvc->queue_full_or_busy &= ~target_id;
8697 }
8698 }
8699 if (asc_dvc->cur_total_qng >= n_q_used) {
8700 asc_dvc->cur_total_qng -= n_q_used;
8701 if (asc_dvc->cur_dvc_qng[tid_no] != 0) {
8702 asc_dvc->cur_dvc_qng[tid_no]--;
8703 }
8704 } else {
8705 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CUR_QNG);
8706 scsiq->d3.done_stat = QD_WITH_ERROR;
8707 goto FATAL_ERR_QDONE;
8708 }
8709 if ((scsiq->d2.srb_ptr == 0UL) ||
8710 ((scsiq->q_status & QS_ABORTED) != 0)) {
8711 return (0x11);
8712 } else if (scsiq->q_status == QS_DONE) {
8713 false_overrun = FALSE;
8714 if (scsiq->extra_bytes != 0) {
8715 scsiq->remain_bytes +=
8716 (ADV_DCNT)scsiq->extra_bytes;
8717 }
8718 if (scsiq->d3.done_stat == QD_WITH_ERROR) {
8719 if (scsiq->d3.host_stat ==
8720 QHSTA_M_DATA_OVER_RUN) {
8721 if ((scsiq->
8722 cntl & (QC_DATA_IN | QC_DATA_OUT))
8723 == 0) {
8724 scsiq->d3.done_stat =
8725 QD_NO_ERROR;
8726 scsiq->d3.host_stat =
8727 QHSTA_NO_ERROR;
8728 } else if (false_overrun) {
8729 scsiq->d3.done_stat =
8730 QD_NO_ERROR;
8731 scsiq->d3.host_stat =
8732 QHSTA_NO_ERROR;
8733 }
8734 } else if (scsiq->d3.host_stat ==
8735 QHSTA_M_HUNG_REQ_SCSI_BUS_RESET) {
8736 AscStopChip(iop_base);
8737 AscSetChipControl(iop_base,
8738 (uchar)(CC_SCSI_RESET
8739 | CC_HALT));
8740 DvcDelayNanoSecond(asc_dvc, 60000);
8741 AscSetChipControl(iop_base, CC_HALT);
8742 AscSetChipStatus(iop_base,
8743 CIW_CLR_SCSI_RESET_INT);
8744 AscSetChipStatus(iop_base, 0);
8745 AscSetChipControl(iop_base, 0);
8746 }
8747 }
8748 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
8749 (*asc_isr_callback) (asc_dvc, scsiq);
8750 } else {
8751 if ((AscReadLramByte(iop_base,
8752 (ushort)(q_addr + (ushort)
8753 ASC_SCSIQ_CDB_BEG))
8754 == START_STOP)) {
8755 asc_dvc->unit_not_ready &= ~target_id;
8756 if (scsiq->d3.done_stat != QD_NO_ERROR) {
8757 asc_dvc->start_motor &=
8758 ~target_id;
8759 }
8760 }
8761 }
8762 return (1);
8763 } else {
8764 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS);
8765 FATAL_ERR_QDONE:
8766 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
8767 (*asc_isr_callback) (asc_dvc, scsiq);
8768 }
8769 return (0x80);
8770 }
8771 }
8772 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008773}
8774
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008775static int AscISR(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008776{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008777 ASC_CS_TYPE chipstat;
8778 PortAddr iop_base;
8779 ushort saved_ram_addr;
8780 uchar ctrl_reg;
8781 uchar saved_ctrl_reg;
8782 int int_pending;
8783 int status;
8784 uchar host_flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008785
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008786 iop_base = asc_dvc->iop_base;
8787 int_pending = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008788
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008789 if (AscIsIntPending(iop_base) == 0) {
8790 return int_pending;
8791 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008792
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008793 if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0)
8794 || (asc_dvc->isr_callback == 0)
8795 ) {
8796 return (ERR);
8797 }
8798 if (asc_dvc->in_critical_cnt != 0) {
8799 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL);
8800 return (ERR);
8801 }
8802 if (asc_dvc->is_in_int) {
8803 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY);
8804 return (ERR);
8805 }
8806 asc_dvc->is_in_int = TRUE;
8807 ctrl_reg = AscGetChipControl(iop_base);
8808 saved_ctrl_reg = ctrl_reg & (~(CC_SCSI_RESET | CC_CHIP_RESET |
8809 CC_SINGLE_STEP | CC_DIAG | CC_TEST));
8810 chipstat = AscGetChipStatus(iop_base);
8811 if (chipstat & CSW_SCSI_RESET_LATCH) {
8812 if (!(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))) {
8813 int i = 10;
8814 int_pending = TRUE;
8815 asc_dvc->sdtr_done = 0;
8816 saved_ctrl_reg &= (uchar)(~CC_HALT);
8817 while ((AscGetChipStatus(iop_base) &
8818 CSW_SCSI_RESET_ACTIVE) && (i-- > 0)) {
8819 DvcSleepMilliSecond(100);
8820 }
8821 AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT));
8822 AscSetChipControl(iop_base, CC_HALT);
8823 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
8824 AscSetChipStatus(iop_base, 0);
8825 chipstat = AscGetChipStatus(iop_base);
8826 }
8827 }
8828 saved_ram_addr = AscGetChipLramAddr(iop_base);
8829 host_flag = AscReadLramByte(iop_base,
8830 ASCV_HOST_FLAG_B) &
8831 (uchar)(~ASC_HOST_FLAG_IN_ISR);
8832 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
8833 (uchar)(host_flag | (uchar)ASC_HOST_FLAG_IN_ISR));
8834 if ((chipstat & CSW_INT_PENDING)
8835 || (int_pending)
8836 ) {
8837 AscAckInterrupt(iop_base);
8838 int_pending = TRUE;
8839 if ((chipstat & CSW_HALTED) && (ctrl_reg & CC_SINGLE_STEP)) {
8840 if (AscIsrChipHalted(asc_dvc) == ERR) {
8841 goto ISR_REPORT_QDONE_FATAL_ERROR;
8842 } else {
8843 saved_ctrl_reg &= (uchar)(~CC_HALT);
8844 }
8845 } else {
8846 ISR_REPORT_QDONE_FATAL_ERROR:
8847 if ((asc_dvc->dvc_cntl & ASC_CNTL_INT_MULTI_Q) != 0) {
8848 while (((status =
8849 AscIsrQDone(asc_dvc)) & 0x01) != 0) {
8850 }
8851 } else {
8852 do {
8853 if ((status =
8854 AscIsrQDone(asc_dvc)) == 1) {
8855 break;
8856 }
8857 } while (status == 0x11);
8858 }
8859 if ((status & 0x80) != 0)
8860 int_pending = ERR;
8861 }
8862 }
8863 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
8864 AscSetChipLramAddr(iop_base, saved_ram_addr);
8865 AscSetChipControl(iop_base, saved_ctrl_reg);
8866 asc_dvc->is_in_int = FALSE;
8867 return (int_pending);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008868}
8869
8870/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008871static uchar _asc_mcode_buf[] = {
8872 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8873 0x00, 0x00, 0x00, 0x00,
8874 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00,
8875 0x00, 0x00, 0x00, 0x00,
8876 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8877 0x00, 0x00, 0x00, 0x00,
8878 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8879 0x00, 0x00, 0x00, 0x00,
8880 0x00, 0x00, 0x00, 0x00, 0xC3, 0x12, 0x0D, 0x05, 0x01, 0x00, 0x00, 0x00,
8881 0x00, 0xFF, 0x00, 0x00,
8882 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00,
8883 0x00, 0x00, 0x00, 0x00,
8884 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF,
8885 0x00, 0x00, 0x00, 0x00,
8886 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x88,
8887 0x00, 0x00, 0x00, 0x00,
8888 0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73,
8889 0x03, 0x23, 0x36, 0x40,
8890 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2,
8891 0xC2, 0x00, 0x92, 0x80,
8892 0x1E, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xDF, 0x23, 0x36, 0x60,
8893 0xB6, 0x00, 0x92, 0x80,
8894 0x4F, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00,
8895 0x92, 0x80, 0x80, 0x62,
8896 0x92, 0x80, 0x00, 0x46, 0x15, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8,
8897 0xCD, 0x04, 0x4D, 0x00,
8898 0x00, 0xA3, 0xD6, 0x00, 0xA6, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01,
8899 0xE6, 0x84, 0xD2, 0xC1,
8900 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x01, 0xA6, 0x97,
8901 0xC6, 0x81, 0xC2, 0x88,
8902 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0xFE, 0x00, 0x4F, 0x00,
8903 0x84, 0x97, 0x07, 0xA6,
8904 0x08, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x01, 0xDE,
8905 0xC2, 0x88, 0xCE, 0x00,
8906 0x69, 0x60, 0xCE, 0x00, 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x78, 0x01,
8907 0x80, 0x63, 0x07, 0xA6,
8908 0x24, 0x01, 0x78, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6,
8909 0x34, 0x01, 0x00, 0x33,
8910 0x04, 0x00, 0xC2, 0x88, 0x03, 0x07, 0x02, 0x01, 0x04, 0xCA, 0x0D, 0x23,
8911 0x68, 0x98, 0x4D, 0x04,
8912 0x04, 0x85, 0x05, 0xD8, 0x0D, 0x23, 0x68, 0x98, 0xCD, 0x04, 0x15, 0x23,
8913 0xF8, 0x88, 0xFB, 0x23,
8914 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x62, 0x01,
8915 0x00, 0x33, 0x0A, 0x00,
8916 0xC2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x6E, 0x01, 0x00, 0x33, 0x0B, 0x00,
8917 0xC2, 0x88, 0xCD, 0x04,
8918 0x36, 0x2D, 0x00, 0x33, 0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x88, 0x81,
8919 0x06, 0xAB, 0x82, 0x01,
8920 0x88, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x92, 0x01, 0x50, 0x00, 0x00, 0xA3,
8921 0x3C, 0x01, 0x00, 0x05,
8922 0x7C, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6, 0x04, 0x23, 0xA0, 0x01,
8923 0x15, 0x23, 0xA1, 0x01,
8924 0xBE, 0x81, 0xFD, 0x23, 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00,
8925 0x06, 0x61, 0x00, 0xA0,
8926 0xB4, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00,
8927 0xC2, 0x88, 0x06, 0x23,
8928 0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01, 0x00, 0xA2, 0xD4, 0x01,
8929 0x57, 0x60, 0x00, 0xA0,
8930 0xDA, 0x01, 0xE6, 0x84, 0x80, 0x23, 0xA0, 0x01, 0xE6, 0x84, 0x80, 0x73,
8931 0x4B, 0x00, 0x06, 0x61,
8932 0x00, 0xA2, 0x00, 0x02, 0x04, 0x01, 0x0C, 0xDE, 0x02, 0x01, 0x03, 0xCC,
8933 0x4F, 0x00, 0x84, 0x97,
8934 0xFC, 0x81, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, 0x4F, 0x00, 0x62, 0x97,
8935 0x48, 0x04, 0x84, 0x80,
8936 0xF0, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00,
8937 0x81, 0x73, 0x06, 0x29,
8938 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x6B, 0xEB, 0x11, 0x23, 0xF8, 0x88,
8939 0x04, 0x98, 0xF0, 0x80,
8940 0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x2A, 0x02, 0x7C, 0x95, 0x06, 0xA6,
8941 0x34, 0x02, 0x03, 0xA6,
8942 0x4C, 0x04, 0x46, 0x82, 0x04, 0x01, 0x03, 0xD8, 0xB4, 0x98, 0x6A, 0x96,
8943 0x46, 0x82, 0xFE, 0x95,
8944 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x6C, 0x02,
8945 0x07, 0xA6, 0x5A, 0x02,
8946 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x62, 0x02, 0xC2, 0x88, 0x7C, 0x95,
8947 0x48, 0x82, 0x60, 0x96,
8948 0x48, 0x82, 0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84,
8949 0x04, 0x01, 0x0C, 0xDC,
8950 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01,
8951 0x6F, 0x00, 0xA5, 0x01,
8952 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, 0x1C, 0x01,
8953 0x02, 0xA6, 0xAA, 0x02,
8954 0x07, 0xA6, 0x5A, 0x02, 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x20, 0x04,
8955 0x01, 0xA6, 0xB4, 0x02,
8956 0x00, 0xA6, 0xB4, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E,
8957 0x80, 0x63, 0x00, 0x43,
8958 0x00, 0xA0, 0x8C, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, 0xE7, 0x23,
8959 0x04, 0x61, 0x84, 0x01,
8960 0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F,
8961 0x00, 0x00, 0xEA, 0x82,
8962 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0xA2, 0xC8,
8963 0x00, 0x33, 0x1F, 0x00,
8964 0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x7E, 0x98,
8965 0xB6, 0x2D, 0x01, 0xA6,
8966 0x14, 0x03, 0x00, 0xA6, 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6,
8967 0x10, 0x03, 0x03, 0xA6,
8968 0x20, 0x04, 0x02, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88,
8969 0x7C, 0x95, 0xEE, 0x82,
8970 0x60, 0x96, 0xEE, 0x82, 0x82, 0x98, 0x80, 0x42, 0x7E, 0x98, 0x64, 0xE4,
8971 0x04, 0x01, 0x2D, 0xC8,
8972 0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01,
8973 0x05, 0x05, 0x86, 0x98,
8974 0x7E, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6,
8975 0x3C, 0x04, 0x06, 0xA6,
8976 0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33, 0x25, 0x00, 0xC2, 0x88,
8977 0x7C, 0x95, 0x32, 0x83,
8978 0x60, 0x96, 0x32, 0x83, 0x04, 0x01, 0x10, 0xCE, 0x07, 0xC8, 0x05, 0x05,
8979 0xEB, 0x04, 0x00, 0x33,
8980 0x00, 0x20, 0xC0, 0x20, 0x81, 0x62, 0x72, 0x83, 0x00, 0x01, 0x05, 0x05,
8981 0xFF, 0xA2, 0x7A, 0x03,
8982 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83, 0x05, 0x05, 0x15, 0x01,
8983 0x00, 0xA2, 0x9A, 0x03,
8984 0xEC, 0x00, 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00,
8985 0x01, 0xA6, 0x96, 0x03,
8986 0x00, 0xA6, 0x96, 0x03, 0x10, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6,
8987 0xA4, 0x03, 0x00, 0xA6,
8988 0xBC, 0x03, 0x10, 0x84, 0xA8, 0x98, 0x80, 0x42, 0x01, 0xA6, 0xA4, 0x03,
8989 0x07, 0xA6, 0xB2, 0x03,
8990 0xD4, 0x83, 0x7C, 0x95, 0xA8, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC2, 0x88,
8991 0xA8, 0x98, 0x80, 0x42,
8992 0x00, 0xA6, 0xBC, 0x03, 0x07, 0xA6, 0xCA, 0x03, 0xD4, 0x83, 0x7C, 0x95,
8993 0xC0, 0x83, 0x00, 0x33,
8994 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, 0x04, 0x23,
8995 0xA0, 0x01, 0x12, 0x23,
8996 0xA1, 0x01, 0x10, 0x84, 0x07, 0xF0, 0x06, 0xA4, 0xF4, 0x03, 0x80, 0x6B,
8997 0x80, 0x67, 0x05, 0x23,
8998 0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x0E, 0x04, 0x07, 0xA6, 0x06, 0x04,
8999 0x06, 0xA6, 0x0A, 0x04,
9000 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0xF4, 0x83, 0x60, 0x96,
9001 0xF4, 0x83, 0x20, 0x84,
9002 0x07, 0xF0, 0x06, 0xA4, 0x20, 0x04, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23,
9003 0x83, 0x03, 0x80, 0x63,
9004 0xB6, 0x2D, 0x03, 0xA6, 0x3C, 0x04, 0x07, 0xA6, 0x34, 0x04, 0x06, 0xA6,
9005 0x38, 0x04, 0x00, 0x33,
9006 0x30, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x20, 0x84, 0x60, 0x96, 0x20, 0x84,
9007 0x1D, 0x01, 0x06, 0xCC,
9008 0x00, 0x33, 0x00, 0x84, 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62,
9009 0xA2, 0x0D, 0x80, 0x63,
9010 0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03,
9011 0x80, 0x63, 0xA3, 0x01,
9012 0x07, 0xA4, 0x64, 0x04, 0x23, 0x01, 0x00, 0xA2, 0x86, 0x04, 0x0A, 0xA0,
9013 0x76, 0x04, 0xE0, 0x00,
9014 0x00, 0x33, 0x1D, 0x00, 0xC2, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00,
9015 0x00, 0x33, 0x1E, 0x00,
9016 0xC2, 0x88, 0x42, 0x23, 0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04,
9017 0x08, 0x23, 0x22, 0xA3,
9018 0xA2, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xAE, 0x04, 0x02, 0x23, 0x22, 0xA3,
9019 0xC4, 0x04, 0x42, 0x23,
9020 0xF8, 0x88, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23,
9021 0xF8, 0x88, 0x04, 0x98,
9022 0x00, 0xA2, 0xC0, 0x04, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20,
9023 0x81, 0x62, 0xE8, 0x81,
9024 0x47, 0x23, 0xF8, 0x88, 0x04, 0x01, 0x0B, 0xDE, 0x04, 0x98, 0xB4, 0x98,
9025 0x00, 0x33, 0x00, 0x81,
9026 0xC0, 0x20, 0x81, 0x62, 0x14, 0x01, 0x00, 0xA0, 0x00, 0x02, 0x43, 0x23,
9027 0xF8, 0x88, 0x04, 0x23,
9028 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3,
9029 0xF4, 0x04, 0x00, 0x33,
9030 0x27, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01,
9031 0x04, 0x23, 0xA0, 0x01,
9032 0x04, 0x98, 0x26, 0x95, 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00,
9033 0x00, 0xA3, 0x22, 0x05,
9034 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x1C, 0x05, 0x0A, 0x85,
9035 0x46, 0x97, 0xCD, 0x04,
9036 0x24, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23,
9037 0x82, 0x01, 0x34, 0x85,
9038 0x02, 0x23, 0xA0, 0x01, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x40, 0x05,
9039 0x1D, 0x01, 0x04, 0xD6,
9040 0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01,
9041 0x49, 0x00, 0x81, 0x01,
9042 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01, 0xF7, 0x04, 0x03, 0x01,
9043 0x49, 0x04, 0x80, 0x01,
9044 0xC9, 0x00, 0x00, 0x05, 0x00, 0x01, 0xFF, 0xA0, 0x60, 0x05, 0x77, 0x04,
9045 0x01, 0x23, 0xEA, 0x00,
9046 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63,
9047 0x07, 0xA4, 0xF8, 0x05,
9048 0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85, 0x00, 0x33, 0x2D, 0x00,
9049 0xC2, 0x88, 0x04, 0xA0,
9050 0xB8, 0x05, 0x80, 0x63, 0x00, 0x23, 0xDF, 0x00, 0x4A, 0x00, 0x06, 0x61,
9051 0x00, 0xA2, 0xA4, 0x05,
9052 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00,
9053 0x62, 0x97, 0x04, 0x85,
9054 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0x04, 0x85, 0x08, 0xA0, 0xBE, 0x05,
9055 0xF4, 0x85, 0x03, 0xA0,
9056 0xC4, 0x05, 0xF4, 0x85, 0x01, 0xA0, 0xCE, 0x05, 0x88, 0x00, 0x80, 0x63,
9057 0xCC, 0x86, 0x07, 0xA0,
9058 0xEE, 0x05, 0x5F, 0x00, 0x00, 0x2B, 0xDF, 0x08, 0x00, 0xA2, 0xE6, 0x05,
9059 0x80, 0x67, 0x80, 0x63,
9060 0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23, 0x68, 0x98, 0x48, 0x23,
9061 0xF8, 0x88, 0x07, 0x23,
9062 0x80, 0x00, 0x06, 0x87, 0x80, 0x63, 0x7C, 0x85, 0x00, 0x23, 0xDF, 0x00,
9063 0x00, 0x63, 0x4A, 0x00,
9064 0x06, 0x61, 0x00, 0xA2, 0x36, 0x06, 0x1D, 0x01, 0x16, 0xD4, 0xC0, 0x23,
9065 0x07, 0x41, 0x83, 0x03,
9066 0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33, 0x37, 0x00, 0xC2, 0x88,
9067 0x1D, 0x01, 0x01, 0xD6,
9068 0x20, 0x23, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x02, 0x23, 0xDF, 0x00,
9069 0x07, 0xA6, 0x7C, 0x05,
9070 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00,
9071 0x52, 0x00, 0x06, 0x61,
9072 0x00, 0xA2, 0x4E, 0x06, 0x1D, 0x01, 0x03, 0xCA, 0xC0, 0x23, 0x07, 0x41,
9073 0x00, 0x63, 0x1D, 0x01,
9074 0x04, 0xCC, 0x00, 0x33, 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23,
9075 0x07, 0x41, 0x00, 0x63,
9076 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x01, 0x23,
9077 0xDF, 0x00, 0x06, 0xA6,
9078 0x84, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x80, 0x63, 0x00, 0x33,
9079 0x00, 0x40, 0xC0, 0x20,
9080 0x81, 0x62, 0x00, 0x63, 0x00, 0x00, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63,
9081 0x06, 0xA6, 0x94, 0x06,
9082 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x00, 0x01, 0xA0, 0x14, 0x07, 0x00, 0x2B,
9083 0x40, 0x0E, 0x80, 0x63,
9084 0x01, 0x00, 0x06, 0xA6, 0xAA, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x40, 0x0E,
9085 0x80, 0x63, 0x00, 0x43,
9086 0x00, 0xA0, 0xA2, 0x06, 0x06, 0xA6, 0xBC, 0x06, 0x07, 0xA6, 0x7C, 0x05,
9087 0x80, 0x67, 0x40, 0x0E,
9088 0x80, 0x63, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63,
9089 0x07, 0xA6, 0xD6, 0x06,
9090 0x00, 0x33, 0x2A, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x80, 0x63, 0x89, 0x00,
9091 0x0A, 0x2B, 0x07, 0xA6,
9092 0xE8, 0x06, 0x00, 0x33, 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, 0x00, 0xA2,
9093 0xF4, 0x06, 0xC0, 0x0E,
9094 0x80, 0x63, 0xDE, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20,
9095 0x81, 0x62, 0x04, 0x01,
9096 0x02, 0xDA, 0x80, 0x63, 0x7C, 0x85, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6,
9097 0x8C, 0x06, 0x00, 0x33,
9098 0x2C, 0x00, 0xC2, 0x88, 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03,
9099 0x80, 0x63, 0x06, 0xA6,
9100 0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88,
9101 0x00, 0x00, 0x80, 0x67,
9102 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x44, 0x07, 0x07, 0xA6, 0x7C, 0x05,
9103 0xBF, 0x23, 0x04, 0x61,
9104 0x84, 0x01, 0xE6, 0x84, 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00,
9105 0x00, 0x01, 0xF2, 0x00,
9106 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04,
9107 0x80, 0x05, 0x81, 0x05,
9108 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x01, 0x01, 0xF1, 0x00,
9109 0x70, 0x00, 0x81, 0x01,
9110 0x70, 0x04, 0x71, 0x00, 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04,
9111 0x70, 0x00, 0x80, 0x01,
9112 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01,
9113 0xF1, 0x00, 0x70, 0x00,
9114 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01, 0x72, 0x00, 0x81, 0x01,
9115 0x71, 0x04, 0x70, 0x00,
9116 0x81, 0x01, 0x70, 0x04, 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05,
9117 0xA3, 0x01, 0xA2, 0x01,
9118 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1,
9119 0xC4, 0x07, 0x00, 0x33,
9120 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8,
9121 0x48, 0x00, 0xB0, 0x01,
9122 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43,
9123 0x00, 0xA2, 0xE4, 0x07,
9124 0x00, 0x05, 0xDA, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01,
9125 0x05, 0x05, 0x00, 0x63,
9126 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x80, 0x43,
9127 0x76, 0x08, 0x80, 0x02,
9128 0x77, 0x04, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04,
9129 0x00, 0x02, 0x00, 0xA0,
9130 0x14, 0x08, 0x16, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04,
9131 0x00, 0x63, 0xF3, 0x04,
9132 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43, 0xF4, 0x00, 0xCF, 0x40,
9133 0x00, 0xA2, 0x44, 0x08,
9134 0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1,
9135 0x24, 0x08, 0x04, 0x98,
9136 0x26, 0x95, 0x24, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04,
9137 0x5A, 0x88, 0x02, 0x01,
9138 0x04, 0xD8, 0x46, 0x97, 0x04, 0x98, 0x26, 0x95, 0x4A, 0x88, 0x75, 0x00,
9139 0x00, 0xA3, 0x64, 0x08,
9140 0x00, 0x05, 0x4E, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63,
9141 0x06, 0xA6, 0x76, 0x08,
9142 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63,
9143 0x00, 0x63, 0x38, 0x2B,
9144 0x9C, 0x88, 0x38, 0x2B, 0x92, 0x88, 0x32, 0x09, 0x31, 0x05, 0x92, 0x98,
9145 0x05, 0x05, 0xB2, 0x09,
9146 0x00, 0x63, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63,
9147 0x80, 0x32, 0x80, 0x36,
9148 0x80, 0x3A, 0x80, 0x3E, 0xB4, 0x3D, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32,
9149 0x40, 0x36, 0x40, 0x3A,
9150 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0xB4, 0x08,
9151 0x5D, 0x00, 0xFE, 0xC3,
9152 0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73,
9153 0xFF, 0xFD, 0x80, 0x73,
9154 0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01,
9155 0xA1, 0x23, 0xA1, 0x01,
9156 0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2,
9157 0x80, 0x00, 0x03, 0xC2,
9158 0xF1, 0xC7, 0x41, 0x23, 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23,
9159 0xA0, 0x01, 0xE6, 0x84,
Linus Torvalds1da177e2005-04-16 15:20:36 -07009160};
9161
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009162static ushort _asc_mcode_size = sizeof(_asc_mcode_buf);
9163static ADV_DCNT _asc_mcode_chksum = 0x012C453FUL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009164
9165#define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009166static uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = {
9167 INQUIRY,
9168 REQUEST_SENSE,
9169 READ_CAPACITY,
9170 READ_TOC,
9171 MODE_SELECT,
9172 MODE_SENSE,
9173 MODE_SELECT_10,
9174 MODE_SENSE_10,
9175 0xFF,
9176 0xFF,
9177 0xFF,
9178 0xFF,
9179 0xFF,
9180 0xFF,
9181 0xFF,
9182 0xFF
Linus Torvalds1da177e2005-04-16 15:20:36 -07009183};
9184
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009185static int AscExeScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009186{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009187 PortAddr iop_base;
9188 ulong last_int_level;
9189 int sta;
9190 int n_q_required;
9191 int disable_syn_offset_one_fix;
9192 int i;
9193 ASC_PADDR addr;
9194 ASC_EXE_CALLBACK asc_exe_callback;
9195 ushort sg_entry_cnt = 0;
9196 ushort sg_entry_cnt_minus_one = 0;
9197 uchar target_ix;
9198 uchar tid_no;
9199 uchar sdtr_data;
9200 uchar extra_bytes;
9201 uchar scsi_cmd;
9202 uchar disable_cmd;
9203 ASC_SG_HEAD *sg_head;
9204 ASC_DCNT data_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009205
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009206 iop_base = asc_dvc->iop_base;
9207 sg_head = scsiq->sg_head;
9208 asc_exe_callback = asc_dvc->exe_callback;
9209 if (asc_dvc->err_code != 0)
9210 return (ERR);
9211 if (scsiq == (ASC_SCSI_Q *)0L) {
9212 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_NULL_PTR);
9213 return (ERR);
9214 }
9215 scsiq->q1.q_no = 0;
9216 if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
9217 scsiq->q1.extra_bytes = 0;
9218 }
9219 sta = 0;
9220 target_ix = scsiq->q2.target_ix;
9221 tid_no = ASC_TIX_TO_TID(target_ix);
9222 n_q_required = 1;
9223 if (scsiq->cdbptr[0] == REQUEST_SENSE) {
9224 if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
9225 asc_dvc->sdtr_done &= ~scsiq->q1.target_id;
9226 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
9227 AscMsgOutSDTR(asc_dvc,
9228 asc_dvc->
9229 sdtr_period_tbl[(sdtr_data >> 4) &
9230 (uchar)(asc_dvc->
9231 max_sdtr_index -
9232 1)],
9233 (uchar)(sdtr_data & (uchar)
9234 ASC_SYN_MAX_OFFSET));
9235 scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
9236 }
9237 }
9238 last_int_level = DvcEnterCritical();
9239 if (asc_dvc->in_critical_cnt != 0) {
9240 DvcLeaveCritical(last_int_level);
9241 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY);
9242 return (ERR);
9243 }
9244 asc_dvc->in_critical_cnt++;
9245 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
9246 if ((sg_entry_cnt = sg_head->entry_cnt) == 0) {
9247 asc_dvc->in_critical_cnt--;
9248 DvcLeaveCritical(last_int_level);
9249 return (ERR);
9250 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009251#if !CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009252 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
9253 asc_dvc->in_critical_cnt--;
9254 DvcLeaveCritical(last_int_level);
9255 return (ERR);
9256 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009257#endif /* !CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009258 if (sg_entry_cnt == 1) {
9259 scsiq->q1.data_addr =
9260 (ADV_PADDR)sg_head->sg_list[0].addr;
9261 scsiq->q1.data_cnt =
9262 (ADV_DCNT)sg_head->sg_list[0].bytes;
9263 scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
9264 }
9265 sg_entry_cnt_minus_one = sg_entry_cnt - 1;
9266 }
9267 scsi_cmd = scsiq->cdbptr[0];
9268 disable_syn_offset_one_fix = FALSE;
9269 if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) &&
9270 !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) {
9271 if (scsiq->q1.cntl & QC_SG_HEAD) {
9272 data_cnt = 0;
9273 for (i = 0; i < sg_entry_cnt; i++) {
9274 data_cnt +=
9275 (ADV_DCNT)le32_to_cpu(sg_head->sg_list[i].
9276 bytes);
9277 }
9278 } else {
9279 data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
9280 }
9281 if (data_cnt != 0UL) {
9282 if (data_cnt < 512UL) {
9283 disable_syn_offset_one_fix = TRUE;
9284 } else {
9285 for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST;
9286 i++) {
9287 disable_cmd =
9288 _syn_offset_one_disable_cmd[i];
9289 if (disable_cmd == 0xFF) {
9290 break;
9291 }
9292 if (scsi_cmd == disable_cmd) {
9293 disable_syn_offset_one_fix =
9294 TRUE;
9295 break;
9296 }
9297 }
9298 }
9299 }
9300 }
9301 if (disable_syn_offset_one_fix) {
9302 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
9303 scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX |
9304 ASC_TAG_FLAG_DISABLE_DISCONNECT);
9305 } else {
9306 scsiq->q2.tag_code &= 0x27;
9307 }
9308 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
9309 if (asc_dvc->bug_fix_cntl) {
9310 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
9311 if ((scsi_cmd == READ_6) ||
9312 (scsi_cmd == READ_10)) {
9313 addr =
9314 (ADV_PADDR)le32_to_cpu(sg_head->
9315 sg_list
9316 [sg_entry_cnt_minus_one].
9317 addr) +
9318 (ADV_DCNT)le32_to_cpu(sg_head->
9319 sg_list
9320 [sg_entry_cnt_minus_one].
9321 bytes);
9322 extra_bytes =
9323 (uchar)((ushort)addr & 0x0003);
9324 if ((extra_bytes != 0)
9325 &&
9326 ((scsiq->q2.
9327 tag_code &
9328 ASC_TAG_FLAG_EXTRA_BYTES)
9329 == 0)) {
9330 scsiq->q2.tag_code |=
9331 ASC_TAG_FLAG_EXTRA_BYTES;
9332 scsiq->q1.extra_bytes =
9333 extra_bytes;
9334 data_cnt =
9335 le32_to_cpu(sg_head->
9336 sg_list
9337 [sg_entry_cnt_minus_one].
9338 bytes);
9339 data_cnt -=
9340 (ASC_DCNT) extra_bytes;
9341 sg_head->
9342 sg_list
9343 [sg_entry_cnt_minus_one].
9344 bytes =
9345 cpu_to_le32(data_cnt);
9346 }
9347 }
9348 }
9349 }
9350 sg_head->entry_to_copy = sg_head->entry_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009351#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009352 /*
9353 * Set the sg_entry_cnt to the maximum possible. The rest of
9354 * the SG elements will be copied when the RISC completes the
9355 * SG elements that fit and halts.
9356 */
9357 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
9358 sg_entry_cnt = ASC_MAX_SG_LIST;
9359 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009360#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009361 n_q_required = AscSgListToQueue(sg_entry_cnt);
9362 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
9363 (uint) n_q_required)
9364 || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
9365 if ((sta =
9366 AscSendScsiQueue(asc_dvc, scsiq,
9367 n_q_required)) == 1) {
9368 asc_dvc->in_critical_cnt--;
9369 if (asc_exe_callback != 0) {
9370 (*asc_exe_callback) (asc_dvc, scsiq);
9371 }
9372 DvcLeaveCritical(last_int_level);
9373 return (sta);
9374 }
9375 }
9376 } else {
9377 if (asc_dvc->bug_fix_cntl) {
9378 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
9379 if ((scsi_cmd == READ_6) ||
9380 (scsi_cmd == READ_10)) {
9381 addr =
9382 le32_to_cpu(scsiq->q1.data_addr) +
9383 le32_to_cpu(scsiq->q1.data_cnt);
9384 extra_bytes =
9385 (uchar)((ushort)addr & 0x0003);
9386 if ((extra_bytes != 0)
9387 &&
9388 ((scsiq->q2.
9389 tag_code &
9390 ASC_TAG_FLAG_EXTRA_BYTES)
9391 == 0)) {
9392 data_cnt =
9393 le32_to_cpu(scsiq->q1.
9394 data_cnt);
9395 if (((ushort)data_cnt & 0x01FF)
9396 == 0) {
9397 scsiq->q2.tag_code |=
9398 ASC_TAG_FLAG_EXTRA_BYTES;
9399 data_cnt -= (ASC_DCNT)
9400 extra_bytes;
9401 scsiq->q1.data_cnt =
9402 cpu_to_le32
9403 (data_cnt);
9404 scsiq->q1.extra_bytes =
9405 extra_bytes;
9406 }
9407 }
9408 }
9409 }
9410 }
9411 n_q_required = 1;
9412 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) ||
9413 ((scsiq->q1.cntl & QC_URGENT) != 0)) {
9414 if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
9415 n_q_required)) == 1) {
9416 asc_dvc->in_critical_cnt--;
9417 if (asc_exe_callback != 0) {
9418 (*asc_exe_callback) (asc_dvc, scsiq);
9419 }
9420 DvcLeaveCritical(last_int_level);
9421 return (sta);
9422 }
9423 }
9424 }
9425 asc_dvc->in_critical_cnt--;
9426 DvcLeaveCritical(last_int_level);
9427 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009428}
9429
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009430static int
9431AscSendScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar n_q_required)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009432{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009433 PortAddr iop_base;
9434 uchar free_q_head;
9435 uchar next_qp;
9436 uchar tid_no;
9437 uchar target_ix;
9438 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009439
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009440 iop_base = asc_dvc->iop_base;
9441 target_ix = scsiq->q2.target_ix;
9442 tid_no = ASC_TIX_TO_TID(target_ix);
9443 sta = 0;
9444 free_q_head = (uchar)AscGetVarFreeQHead(iop_base);
9445 if (n_q_required > 1) {
9446 if ((next_qp = AscAllocMultipleFreeQueue(iop_base,
9447 free_q_head, (uchar)
9448 (n_q_required)))
9449 != (uchar)ASC_QLINK_END) {
9450 asc_dvc->last_q_shortage = 0;
9451 scsiq->sg_head->queue_cnt = n_q_required - 1;
9452 scsiq->q1.q_no = free_q_head;
9453 if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq,
9454 free_q_head)) == 1) {
9455 AscPutVarFreeQHead(iop_base, next_qp);
9456 asc_dvc->cur_total_qng += (uchar)(n_q_required);
9457 asc_dvc->cur_dvc_qng[tid_no]++;
9458 }
9459 return (sta);
9460 }
9461 } else if (n_q_required == 1) {
9462 if ((next_qp = AscAllocFreeQueue(iop_base,
9463 free_q_head)) !=
9464 ASC_QLINK_END) {
9465 scsiq->q1.q_no = free_q_head;
9466 if ((sta = AscPutReadyQueue(asc_dvc, scsiq,
9467 free_q_head)) == 1) {
9468 AscPutVarFreeQHead(iop_base, next_qp);
9469 asc_dvc->cur_total_qng++;
9470 asc_dvc->cur_dvc_qng[tid_no]++;
9471 }
9472 return (sta);
9473 }
9474 }
9475 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009476}
9477
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009478static int AscSgListToQueue(int sg_list)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009479{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009480 int n_sg_list_qs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009481
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009482 n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q);
9483 if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0)
9484 n_sg_list_qs++;
9485 return (n_sg_list_qs + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009486}
9487
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009488static uint
9489AscGetNumOfFreeQueue(ASC_DVC_VAR *asc_dvc, uchar target_ix, uchar n_qs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009490{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009491 uint cur_used_qs;
9492 uint cur_free_qs;
9493 ASC_SCSI_BIT_ID_TYPE target_id;
9494 uchar tid_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009495
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009496 target_id = ASC_TIX_TO_TARGET_ID(target_ix);
9497 tid_no = ASC_TIX_TO_TID(target_ix);
9498 if ((asc_dvc->unit_not_ready & target_id) ||
9499 (asc_dvc->queue_full_or_busy & target_id)) {
9500 return (0);
9501 }
9502 if (n_qs == 1) {
9503 cur_used_qs = (uint) asc_dvc->cur_total_qng +
9504 (uint) asc_dvc->last_q_shortage + (uint) ASC_MIN_FREE_Q;
9505 } else {
9506 cur_used_qs = (uint) asc_dvc->cur_total_qng +
9507 (uint) ASC_MIN_FREE_Q;
9508 }
9509 if ((uint) (cur_used_qs + n_qs) <= (uint) asc_dvc->max_total_qng) {
9510 cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs;
9511 if (asc_dvc->cur_dvc_qng[tid_no] >=
9512 asc_dvc->max_dvc_qng[tid_no]) {
9513 return (0);
9514 }
9515 return (cur_free_qs);
9516 }
9517 if (n_qs > 1) {
9518 if ((n_qs > asc_dvc->last_q_shortage)
9519 && (n_qs <= (asc_dvc->max_total_qng - ASC_MIN_FREE_Q))) {
9520 asc_dvc->last_q_shortage = n_qs;
9521 }
9522 }
9523 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009524}
9525
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009526static int AscPutReadyQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009527{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009528 ushort q_addr;
9529 uchar tid_no;
9530 uchar sdtr_data;
9531 uchar syn_period_ix;
9532 uchar syn_offset;
9533 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009534
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009535 iop_base = asc_dvc->iop_base;
9536 if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) &&
9537 ((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) {
9538 tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix);
9539 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
9540 syn_period_ix =
9541 (sdtr_data >> 4) & (asc_dvc->max_sdtr_index - 1);
9542 syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET;
9543 AscMsgOutSDTR(asc_dvc,
9544 asc_dvc->sdtr_period_tbl[syn_period_ix],
9545 syn_offset);
9546 scsiq->q1.cntl |= QC_MSG_OUT;
9547 }
9548 q_addr = ASC_QNO_TO_QADDR(q_no);
9549 if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) {
9550 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
9551 }
9552 scsiq->q1.status = QS_FREE;
9553 AscMemWordCopyPtrToLram(iop_base,
9554 q_addr + ASC_SCSIQ_CDB_BEG,
9555 (uchar *)scsiq->cdbptr, scsiq->q2.cdb_len >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009556
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009557 DvcPutScsiQ(iop_base,
9558 q_addr + ASC_SCSIQ_CPY_BEG,
9559 (uchar *)&scsiq->q1.cntl,
9560 ((sizeof(ASC_SCSIQ_1) + sizeof(ASC_SCSIQ_2)) / 2) - 1);
9561 AscWriteLramWord(iop_base,
9562 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS),
9563 (ushort)(((ushort)scsiq->q1.
9564 q_no << 8) | (ushort)QS_READY));
9565 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009566}
9567
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009568static int
9569AscPutReadySgListQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009570{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009571 int sta;
9572 int i;
9573 ASC_SG_HEAD *sg_head;
9574 ASC_SG_LIST_Q scsi_sg_q;
9575 ASC_DCNT saved_data_addr;
9576 ASC_DCNT saved_data_cnt;
9577 PortAddr iop_base;
9578 ushort sg_list_dwords;
9579 ushort sg_index;
9580 ushort sg_entry_cnt;
9581 ushort q_addr;
9582 uchar next_qp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009583
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009584 iop_base = asc_dvc->iop_base;
9585 sg_head = scsiq->sg_head;
9586 saved_data_addr = scsiq->q1.data_addr;
9587 saved_data_cnt = scsiq->q1.data_cnt;
9588 scsiq->q1.data_addr = (ASC_PADDR) sg_head->sg_list[0].addr;
9589 scsiq->q1.data_cnt = (ASC_DCNT) sg_head->sg_list[0].bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009590#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009591 /*
9592 * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST
9593 * then not all SG elements will fit in the allocated queues.
9594 * The rest of the SG elements will be copied when the RISC
9595 * completes the SG elements that fit and halts.
9596 */
9597 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
9598 /*
9599 * Set sg_entry_cnt to be the number of SG elements that
9600 * will fit in the allocated SG queues. It is minus 1, because
9601 * the first SG element is handled above. ASC_MAX_SG_LIST is
9602 * already inflated by 1 to account for this. For example it
9603 * may be 50 which is 1 + 7 queues * 7 SG elements.
9604 */
9605 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009606
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009607 /*
9608 * Keep track of remaining number of SG elements that will
9609 * need to be handled from a_isr.c.
9610 */
9611 scsiq->remain_sg_entry_cnt =
9612 sg_head->entry_cnt - ASC_MAX_SG_LIST;
9613 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009614#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009615 /*
9616 * Set sg_entry_cnt to be the number of SG elements that
9617 * will fit in the allocated SG queues. It is minus 1, because
9618 * the first SG element is handled above.
9619 */
9620 sg_entry_cnt = sg_head->entry_cnt - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009621#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009622 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009623#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009624 if (sg_entry_cnt != 0) {
9625 scsiq->q1.cntl |= QC_SG_HEAD;
9626 q_addr = ASC_QNO_TO_QADDR(q_no);
9627 sg_index = 1;
9628 scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
9629 scsi_sg_q.sg_head_qp = q_no;
9630 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
9631 for (i = 0; i < sg_head->queue_cnt; i++) {
9632 scsi_sg_q.seq_no = i + 1;
9633 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
9634 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
9635 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
9636 if (i == 0) {
9637 scsi_sg_q.sg_list_cnt =
9638 ASC_SG_LIST_PER_Q;
9639 scsi_sg_q.sg_cur_list_cnt =
9640 ASC_SG_LIST_PER_Q;
9641 } else {
9642 scsi_sg_q.sg_list_cnt =
9643 ASC_SG_LIST_PER_Q - 1;
9644 scsi_sg_q.sg_cur_list_cnt =
9645 ASC_SG_LIST_PER_Q - 1;
9646 }
9647 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009648#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009649 /*
9650 * This is the last SG queue in the list of
9651 * allocated SG queues. If there are more
9652 * SG elements than will fit in the allocated
9653 * queues, then set the QCSG_SG_XFER_MORE flag.
9654 */
9655 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
9656 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
9657 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009658#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009659 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009660#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009661 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009662#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009663 sg_list_dwords = sg_entry_cnt << 1;
9664 if (i == 0) {
9665 scsi_sg_q.sg_list_cnt = sg_entry_cnt;
9666 scsi_sg_q.sg_cur_list_cnt =
9667 sg_entry_cnt;
9668 } else {
9669 scsi_sg_q.sg_list_cnt =
9670 sg_entry_cnt - 1;
9671 scsi_sg_q.sg_cur_list_cnt =
9672 sg_entry_cnt - 1;
9673 }
9674 sg_entry_cnt = 0;
9675 }
9676 next_qp = AscReadLramByte(iop_base,
9677 (ushort)(q_addr +
9678 ASC_SCSIQ_B_FWD));
9679 scsi_sg_q.q_no = next_qp;
9680 q_addr = ASC_QNO_TO_QADDR(next_qp);
9681 AscMemWordCopyPtrToLram(iop_base,
9682 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
9683 (uchar *)&scsi_sg_q,
9684 sizeof(ASC_SG_LIST_Q) >> 1);
9685 AscMemDWordCopyPtrToLram(iop_base,
9686 q_addr + ASC_SGQ_LIST_BEG,
9687 (uchar *)&sg_head->
9688 sg_list[sg_index],
9689 sg_list_dwords);
9690 sg_index += ASC_SG_LIST_PER_Q;
9691 scsiq->next_sg_index = sg_index;
9692 }
9693 } else {
9694 scsiq->q1.cntl &= ~QC_SG_HEAD;
9695 }
9696 sta = AscPutReadyQueue(asc_dvc, scsiq, q_no);
9697 scsiq->q1.data_addr = saved_data_addr;
9698 scsiq->q1.data_cnt = saved_data_cnt;
9699 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009700}
9701
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009702static int
9703AscSetRunChipSynRegAtID(PortAddr iop_base, uchar tid_no, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009704{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009705 int sta = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009706
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009707 if (AscHostReqRiscHalt(iop_base)) {
9708 sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
9709 AscStartChip(iop_base);
9710 return (sta);
9711 }
9712 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009713}
9714
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009715static int AscSetChipSynRegAtID(PortAddr iop_base, uchar id, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009716{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009717 ASC_SCSI_BIT_ID_TYPE org_id;
9718 int i;
9719 int sta = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009720
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009721 AscSetBank(iop_base, 1);
9722 org_id = AscReadChipDvcID(iop_base);
9723 for (i = 0; i <= ASC_MAX_TID; i++) {
9724 if (org_id == (0x01 << i))
9725 break;
9726 }
9727 org_id = (ASC_SCSI_BIT_ID_TYPE) i;
9728 AscWriteChipDvcID(iop_base, id);
9729 if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
9730 AscSetBank(iop_base, 0);
9731 AscSetChipSyn(iop_base, sdtr_data);
9732 if (AscGetChipSyn(iop_base) != sdtr_data) {
9733 sta = FALSE;
9734 }
9735 } else {
9736 sta = FALSE;
9737 }
9738 AscSetBank(iop_base, 1);
9739 AscWriteChipDvcID(iop_base, org_id);
9740 AscSetBank(iop_base, 0);
9741 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009742}
9743
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009744static ushort AscInitLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009745{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009746 uchar i;
9747 ushort s_addr;
9748 PortAddr iop_base;
9749 ushort warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009750
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009751 iop_base = asc_dvc->iop_base;
9752 warn_code = 0;
9753 AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0,
9754 (ushort)(((int)(asc_dvc->max_total_qng + 2 + 1) *
9755 64) >> 1)
9756 );
9757 i = ASC_MIN_ACTIVE_QNO;
9758 s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE;
9759 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
9760 (uchar)(i + 1));
9761 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
9762 (uchar)(asc_dvc->max_total_qng));
9763 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
9764 (uchar)i);
9765 i++;
9766 s_addr += ASC_QBLK_SIZE;
9767 for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) {
9768 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
9769 (uchar)(i + 1));
9770 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
9771 (uchar)(i - 1));
9772 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
9773 (uchar)i);
9774 }
9775 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
9776 (uchar)ASC_QLINK_END);
9777 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
9778 (uchar)(asc_dvc->max_total_qng - 1));
9779 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
9780 (uchar)asc_dvc->max_total_qng);
9781 i++;
9782 s_addr += ASC_QBLK_SIZE;
9783 for (; i <= (uchar)(asc_dvc->max_total_qng + 3);
9784 i++, s_addr += ASC_QBLK_SIZE) {
9785 AscWriteLramByte(iop_base,
9786 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_FWD), i);
9787 AscWriteLramByte(iop_base,
9788 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_BWD), i);
9789 AscWriteLramByte(iop_base,
9790 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_QNO), i);
9791 }
9792 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009793}
9794
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009795static ushort AscInitQLinkVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009796{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009797 PortAddr iop_base;
9798 int i;
9799 ushort lram_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009800
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009801 iop_base = asc_dvc->iop_base;
9802 AscPutRiscVarFreeQHead(iop_base, 1);
9803 AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng);
9804 AscPutVarFreeQHead(iop_base, 1);
9805 AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng);
9806 AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B,
9807 (uchar)((int)asc_dvc->max_total_qng + 1));
9808 AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B,
9809 (uchar)((int)asc_dvc->max_total_qng + 2));
9810 AscWriteLramByte(iop_base, (ushort)ASCV_TOTAL_READY_Q_B,
9811 asc_dvc->max_total_qng);
9812 AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0);
9813 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
9814 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
9815 AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0);
9816 AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0);
9817 AscPutQDoneInProgress(iop_base, 0);
9818 lram_addr = ASC_QADR_BEG;
9819 for (i = 0; i < 32; i++, lram_addr += 2) {
9820 AscWriteLramWord(iop_base, lram_addr, 0);
9821 }
9822 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009823}
9824
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009825static int AscSetLibErrorCode(ASC_DVC_VAR *asc_dvc, ushort err_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009826{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009827 if (asc_dvc->err_code == 0) {
9828 asc_dvc->err_code = err_code;
9829 AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W,
9830 err_code);
9831 }
9832 return (err_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009833}
9834
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009835static uchar
9836AscMsgOutSDTR(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar sdtr_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009837{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009838 EXT_MSG sdtr_buf;
9839 uchar sdtr_period_index;
9840 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009841
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009842 iop_base = asc_dvc->iop_base;
Matthew Wilcox47d853c2007-07-26 11:41:33 -04009843 sdtr_buf.msg_type = EXTENDED_MESSAGE;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009844 sdtr_buf.msg_len = MS_SDTR_LEN;
Matthew Wilcox47d853c2007-07-26 11:41:33 -04009845 sdtr_buf.msg_req = EXTENDED_SDTR;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009846 sdtr_buf.xfer_period = sdtr_period;
9847 sdtr_offset &= ASC_SYN_MAX_OFFSET;
9848 sdtr_buf.req_ack_offset = sdtr_offset;
9849 if ((sdtr_period_index =
9850 AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <=
9851 asc_dvc->max_sdtr_index) {
9852 AscMemWordCopyPtrToLram(iop_base,
9853 ASCV_MSGOUT_BEG,
9854 (uchar *)&sdtr_buf,
9855 sizeof(EXT_MSG) >> 1);
9856 return ((sdtr_period_index << 4) | sdtr_offset);
9857 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009858
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009859 sdtr_buf.req_ack_offset = 0;
9860 AscMemWordCopyPtrToLram(iop_base,
9861 ASCV_MSGOUT_BEG,
9862 (uchar *)&sdtr_buf,
9863 sizeof(EXT_MSG) >> 1);
9864 return (0);
9865 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009866}
9867
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009868static uchar
9869AscCalSDTRData(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar syn_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009870{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009871 uchar byte;
9872 uchar sdtr_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009873
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009874 sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
9875 if ((sdtr_period_ix > asc_dvc->max_sdtr_index)
9876 ) {
9877 return (0xFF);
9878 }
9879 byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET);
9880 return (byte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009881}
9882
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009883static void AscSetChipSDTR(PortAddr iop_base, uchar sdtr_data, uchar tid_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009884{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009885 AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
9886 AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data);
9887 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009888}
9889
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009890static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *asc_dvc, uchar syn_time)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009891{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009892 uchar *period_table;
9893 int max_index;
9894 int min_index;
9895 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009896
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009897 period_table = asc_dvc->sdtr_period_tbl;
9898 max_index = (int)asc_dvc->max_sdtr_index;
9899 min_index = (int)asc_dvc->host_init_sdtr_index;
9900 if ((syn_time <= period_table[max_index])) {
9901 for (i = min_index; i < (max_index - 1); i++) {
9902 if (syn_time <= period_table[i]) {
9903 return ((uchar)i);
9904 }
9905 }
9906 return ((uchar)max_index);
9907 } else {
9908 return ((uchar)(max_index + 1));
9909 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009910}
9911
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009912static uchar AscAllocFreeQueue(PortAddr iop_base, uchar free_q_head)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009913{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009914 ushort q_addr;
9915 uchar next_qp;
9916 uchar q_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009917
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009918 q_addr = ASC_QNO_TO_QADDR(free_q_head);
9919 q_status = (uchar)AscReadLramByte(iop_base,
9920 (ushort)(q_addr +
9921 ASC_SCSIQ_B_STATUS));
9922 next_qp = AscReadLramByte(iop_base, (ushort)(q_addr + ASC_SCSIQ_B_FWD));
9923 if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END)) {
9924 return (next_qp);
9925 }
9926 return (ASC_QLINK_END);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009927}
9928
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009929static uchar
9930AscAllocMultipleFreeQueue(PortAddr iop_base, uchar free_q_head, uchar n_free_q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009931{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009932 uchar i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009933
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009934 for (i = 0; i < n_free_q; i++) {
9935 if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head))
9936 == ASC_QLINK_END) {
9937 return (ASC_QLINK_END);
9938 }
9939 }
9940 return (free_q_head);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009941}
9942
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009943static int AscHostReqRiscHalt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009944{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009945 int count = 0;
9946 int sta = 0;
9947 uchar saved_stop_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009948
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009949 if (AscIsChipHalted(iop_base))
9950 return (1);
9951 saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
9952 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
9953 ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP);
9954 do {
9955 if (AscIsChipHalted(iop_base)) {
9956 sta = 1;
9957 break;
9958 }
9959 DvcSleepMilliSecond(100);
9960 } while (count++ < 20);
9961 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code);
9962 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009963}
9964
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009965static int AscStopQueueExe(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009966{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009967 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009968
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009969 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) {
9970 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
9971 ASC_STOP_REQ_RISC_STOP);
9972 do {
9973 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) &
9974 ASC_STOP_ACK_RISC_STOP) {
9975 return (1);
9976 }
9977 DvcSleepMilliSecond(100);
9978 } while (count++ < 20);
9979 }
9980 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009981}
9982
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009983static void DvcDelayMicroSecond(ADV_DVC_VAR *asc_dvc, ushort micro_sec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009984{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009985 udelay(micro_sec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009986}
9987
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009988static void DvcDelayNanoSecond(ASC_DVC_VAR *asc_dvc, ASC_DCNT nano_sec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009989{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009990 udelay((nano_sec + 999) / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009991}
9992
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009993static int AscStartChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009994{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009995 AscSetChipControl(iop_base, 0);
9996 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
9997 return (0);
9998 }
9999 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010000}
10001
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010002static int AscStopChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010003{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010004 uchar cc_val;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010005
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010006 cc_val =
10007 AscGetChipControl(iop_base) &
10008 (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG));
10009 AscSetChipControl(iop_base, (uchar)(cc_val | CC_HALT));
10010 AscSetChipIH(iop_base, INS_HALT);
10011 AscSetChipIH(iop_base, INS_RFLAG_WTM);
10012 if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) {
10013 return (0);
10014 }
10015 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010016}
10017
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010018static int AscIsChipHalted(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010019{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010020 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
10021 if ((AscGetChipControl(iop_base) & CC_HALT) != 0) {
10022 return (1);
10023 }
10024 }
10025 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010026}
10027
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010028static void AscSetChipIH(PortAddr iop_base, ushort ins_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010029{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010030 AscSetBank(iop_base, 1);
10031 AscWriteChipIH(iop_base, ins_code);
10032 AscSetBank(iop_base, 0);
10033 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010034}
10035
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010036static void AscAckInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010037{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010038 uchar host_flag;
10039 uchar risc_flag;
10040 ushort loop;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010041
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010042 loop = 0;
10043 do {
10044 risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B);
10045 if (loop++ > 0x7FFF) {
10046 break;
10047 }
10048 } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0);
10049 host_flag =
10050 AscReadLramByte(iop_base,
10051 ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT);
10052 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
10053 (uchar)(host_flag | ASC_HOST_FLAG_ACK_INT));
10054 AscSetChipStatus(iop_base, CIW_INT_ACK);
10055 loop = 0;
10056 while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) {
10057 AscSetChipStatus(iop_base, CIW_INT_ACK);
10058 if (loop++ > 3) {
10059 break;
10060 }
10061 }
10062 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
10063 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010064}
10065
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010066static void AscDisableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010067{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010068 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010069
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010070 cfg = AscGetChipCfgLsw(iop_base);
10071 AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON));
10072 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010073}
10074
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010075static void AscEnableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010076{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010077 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010078
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010079 cfg = AscGetChipCfgLsw(iop_base);
10080 AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON);
10081 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010082}
10083
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010084static void AscSetBank(PortAddr iop_base, uchar bank)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010085{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010086 uchar val;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010087
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010088 val = AscGetChipControl(iop_base) &
10089 (~
10090 (CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET |
10091 CC_CHIP_RESET));
10092 if (bank == 1) {
10093 val |= CC_BANK_ONE;
10094 } else if (bank == 2) {
10095 val |= CC_DIAG | CC_BANK_ONE;
10096 } else {
10097 val &= ~CC_BANK_ONE;
10098 }
10099 AscSetChipControl(iop_base, val);
10100 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010101}
10102
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010103static int AscResetChipAndScsiBus(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010104{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010105 PortAddr iop_base;
10106 int i = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010107
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010108 iop_base = asc_dvc->iop_base;
10109 while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE)
10110 && (i-- > 0)) {
10111 DvcSleepMilliSecond(100);
10112 }
10113 AscStopChip(iop_base);
10114 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
10115 DvcDelayNanoSecond(asc_dvc, 60000);
10116 AscSetChipIH(iop_base, INS_RFLAG_WTM);
10117 AscSetChipIH(iop_base, INS_HALT);
10118 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT);
10119 AscSetChipControl(iop_base, CC_HALT);
10120 DvcSleepMilliSecond(200);
10121 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
10122 AscSetChipStatus(iop_base, 0);
10123 return (AscIsChipHalted(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010124}
10125
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010126static ASC_DCNT __devinit AscGetMaxDmaCount(ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010127{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010128 if (bus_type & ASC_IS_ISA)
10129 return (ASC_MAX_ISA_DMA_COUNT);
10130 else if (bus_type & (ASC_IS_EISA | ASC_IS_VL))
10131 return (ASC_MAX_VL_DMA_COUNT);
10132 return (ASC_MAX_PCI_DMA_COUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010133}
10134
10135#ifdef CONFIG_ISA
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010136static ushort __devinit AscGetIsaDmaChannel(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010137{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010138 ushort channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010139
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010140 channel = AscGetChipCfgLsw(iop_base) & 0x0003;
10141 if (channel == 0x03)
10142 return (0);
10143 else if (channel == 0x00)
10144 return (7);
10145 return (channel + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010146}
10147
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010148static ushort __devinit AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010149{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010150 ushort cfg_lsw;
10151 uchar value;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010152
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010153 if ((dma_channel >= 5) && (dma_channel <= 7)) {
10154 if (dma_channel == 7)
10155 value = 0x00;
10156 else
10157 value = dma_channel - 4;
10158 cfg_lsw = AscGetChipCfgLsw(iop_base) & 0xFFFC;
10159 cfg_lsw |= value;
10160 AscSetChipCfgLsw(iop_base, cfg_lsw);
10161 return (AscGetIsaDmaChannel(iop_base));
10162 }
10163 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010164}
10165
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010166static uchar __devinit AscSetIsaDmaSpeed(PortAddr iop_base, uchar speed_value)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010167{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010168 speed_value &= 0x07;
10169 AscSetBank(iop_base, 1);
10170 AscWriteChipDmaSpeed(iop_base, speed_value);
10171 AscSetBank(iop_base, 0);
10172 return (AscGetIsaDmaSpeed(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010173}
10174
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010175static uchar __devinit AscGetIsaDmaSpeed(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010176{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010177 uchar speed_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010178
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010179 AscSetBank(iop_base, 1);
10180 speed_value = AscReadChipDmaSpeed(iop_base);
10181 speed_value &= 0x07;
10182 AscSetBank(iop_base, 0);
10183 return (speed_value);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010184}
10185#endif /* CONFIG_ISA */
10186
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010187static ushort __devinit AscInitGetConfig(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010188{
Matthew Wilcox9649af32007-07-26 21:51:47 -060010189 unsigned short warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010190
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010191 asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG;
Matthew Wilcox9649af32007-07-26 21:51:47 -060010192 if (asc_dvc->err_code != 0)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010193 return (UW_ERR);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010194
Matthew Wilcox9649af32007-07-26 21:51:47 -060010195 if (AscFindSignature(asc_dvc->iop_base)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010196 warn_code |= AscInitAscDvcVar(asc_dvc);
10197 warn_code |= AscInitFromEEP(asc_dvc);
10198 asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG;
Matthew Wilcoxecec1942007-07-30 08:08:22 -060010199 if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010200 asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010201 } else {
10202 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10203 }
Matthew Wilcoxecec1942007-07-30 08:08:22 -060010204 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010205}
10206
Matthew Wilcox394dbf32007-07-26 11:56:40 -040010207static unsigned short __devinit
10208AscInitSetConfig(struct pci_dev *pdev, ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010209{
Matthew Wilcox394dbf32007-07-26 11:56:40 -040010210 PortAddr iop_base = asc_dvc->iop_base;
10211 unsigned short cfg_msw;
10212 unsigned short warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010213
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010214 asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG;
10215 if (asc_dvc->err_code != 0)
Matthew Wilcox394dbf32007-07-26 11:56:40 -040010216 return UW_ERR;
10217 if (!AscFindSignature(asc_dvc->iop_base)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010218 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
Matthew Wilcox394dbf32007-07-26 11:56:40 -040010219 return 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010220 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010221
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010222 cfg_msw = AscGetChipCfgMsw(iop_base);
10223 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
10224 cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
10225 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
10226 AscSetChipCfgMsw(iop_base, cfg_msw);
10227 }
10228 if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) !=
10229 asc_dvc->cfg->cmd_qng_enabled) {
10230 asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled;
10231 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
10232 }
10233 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
10234 warn_code |= ASC_WARN_AUTO_CONFIG;
10235 }
10236 if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) {
10237 if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type)
10238 != asc_dvc->irq_no) {
10239 asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO;
10240 }
10241 }
Matthew Wilcox9649af32007-07-26 21:51:47 -060010242#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010243 if (asc_dvc->bus_type & ASC_IS_PCI) {
10244 cfg_msw &= 0xFFC0;
10245 AscSetChipCfgMsw(iop_base, cfg_msw);
10246 if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
10247 } else {
Matthew Wilcox9649af32007-07-26 21:51:47 -060010248 if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) ||
10249 (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010250 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
10251 asc_dvc->bug_fix_cntl |=
10252 ASC_BUG_FIX_ASYN_USE_SYN;
10253 }
10254 }
Matthew Wilcox9649af32007-07-26 21:51:47 -060010255 } else
10256#endif /* CONFIG_PCI */
10257 if (asc_dvc->bus_type == ASC_IS_ISAPNP) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010258 if (AscGetChipVersion(iop_base, asc_dvc->bus_type)
10259 == ASC_CHIP_VER_ASYN_BUG) {
10260 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
10261 }
10262 }
10263 if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) !=
10264 asc_dvc->cfg->chip_scsi_id) {
10265 asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID;
10266 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010267#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010268 if (asc_dvc->bus_type & ASC_IS_ISA) {
10269 AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel);
10270 AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed);
10271 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010272#endif /* CONFIG_ISA */
Matthew Wilcox394dbf32007-07-26 11:56:40 -040010273
10274 asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG;
10275 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010276}
10277
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010278static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010279{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010280 ushort warn_code;
10281 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010282
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010283 iop_base = asc_dvc->iop_base;
10284 warn_code = 0;
10285 if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
10286 !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
10287 AscResetChipAndScsiBus(asc_dvc);
10288 DvcSleepMilliSecond((ASC_DCNT)
10289 ((ushort)asc_dvc->scsi_reset_wait * 1000));
10290 }
10291 asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
10292 if (asc_dvc->err_code != 0)
10293 return (UW_ERR);
10294 if (!AscFindSignature(asc_dvc->iop_base)) {
10295 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10296 return (warn_code);
10297 }
10298 AscDisableInterrupt(iop_base);
10299 warn_code |= AscInitLram(asc_dvc);
10300 if (asc_dvc->err_code != 0)
10301 return (UW_ERR);
10302 ASC_DBG1(1, "AscInitAsc1000Driver: _asc_mcode_chksum 0x%lx\n",
10303 (ulong)_asc_mcode_chksum);
10304 if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf,
10305 _asc_mcode_size) != _asc_mcode_chksum) {
10306 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
10307 return (warn_code);
10308 }
10309 warn_code |= AscInitMicroCodeVar(asc_dvc);
10310 asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
10311 AscEnableInterrupt(iop_base);
10312 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010313}
10314
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010315static ushort __devinit AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010316{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010317 int i;
10318 PortAddr iop_base;
10319 ushort warn_code;
10320 uchar chip_version;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010321
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010322 iop_base = asc_dvc->iop_base;
10323 warn_code = 0;
10324 asc_dvc->err_code = 0;
10325 if ((asc_dvc->bus_type &
10326 (ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0) {
10327 asc_dvc->err_code |= ASC_IERR_NO_BUS_TYPE;
10328 }
10329 AscSetChipControl(iop_base, CC_HALT);
10330 AscSetChipStatus(iop_base, 0);
10331 asc_dvc->bug_fix_cntl = 0;
10332 asc_dvc->pci_fix_asyn_xfer = 0;
10333 asc_dvc->pci_fix_asyn_xfer_always = 0;
10334 /* asc_dvc->init_state initalized in AscInitGetConfig(). */
10335 asc_dvc->sdtr_done = 0;
10336 asc_dvc->cur_total_qng = 0;
10337 asc_dvc->is_in_int = 0;
10338 asc_dvc->in_critical_cnt = 0;
10339 asc_dvc->last_q_shortage = 0;
10340 asc_dvc->use_tagged_qng = 0;
10341 asc_dvc->no_scam = 0;
10342 asc_dvc->unit_not_ready = 0;
10343 asc_dvc->queue_full_or_busy = 0;
10344 asc_dvc->redo_scam = 0;
10345 asc_dvc->res2 = 0;
10346 asc_dvc->host_init_sdtr_index = 0;
10347 asc_dvc->cfg->can_tagged_qng = 0;
10348 asc_dvc->cfg->cmd_qng_enabled = 0;
10349 asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
10350 asc_dvc->init_sdtr = 0;
10351 asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG;
10352 asc_dvc->scsi_reset_wait = 3;
10353 asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET;
10354 asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
10355 asc_dvc->cfg->sdtr_enable = ASC_SCSI_WIDTH_BIT_SET;
10356 asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
10357 asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID;
10358 asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER;
10359 asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) |
10360 ASC_LIB_VERSION_MINOR;
10361 chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type);
10362 asc_dvc->cfg->chip_version = chip_version;
10363 asc_dvc->sdtr_period_tbl[0] = SYN_XFER_NS_0;
10364 asc_dvc->sdtr_period_tbl[1] = SYN_XFER_NS_1;
10365 asc_dvc->sdtr_period_tbl[2] = SYN_XFER_NS_2;
10366 asc_dvc->sdtr_period_tbl[3] = SYN_XFER_NS_3;
10367 asc_dvc->sdtr_period_tbl[4] = SYN_XFER_NS_4;
10368 asc_dvc->sdtr_period_tbl[5] = SYN_XFER_NS_5;
10369 asc_dvc->sdtr_period_tbl[6] = SYN_XFER_NS_6;
10370 asc_dvc->sdtr_period_tbl[7] = SYN_XFER_NS_7;
10371 asc_dvc->max_sdtr_index = 7;
10372 if ((asc_dvc->bus_type & ASC_IS_PCI) &&
10373 (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3150)) {
10374 asc_dvc->bus_type = ASC_IS_PCI_ULTRA;
10375 asc_dvc->sdtr_period_tbl[0] = SYN_ULTRA_XFER_NS_0;
10376 asc_dvc->sdtr_period_tbl[1] = SYN_ULTRA_XFER_NS_1;
10377 asc_dvc->sdtr_period_tbl[2] = SYN_ULTRA_XFER_NS_2;
10378 asc_dvc->sdtr_period_tbl[3] = SYN_ULTRA_XFER_NS_3;
10379 asc_dvc->sdtr_period_tbl[4] = SYN_ULTRA_XFER_NS_4;
10380 asc_dvc->sdtr_period_tbl[5] = SYN_ULTRA_XFER_NS_5;
10381 asc_dvc->sdtr_period_tbl[6] = SYN_ULTRA_XFER_NS_6;
10382 asc_dvc->sdtr_period_tbl[7] = SYN_ULTRA_XFER_NS_7;
10383 asc_dvc->sdtr_period_tbl[8] = SYN_ULTRA_XFER_NS_8;
10384 asc_dvc->sdtr_period_tbl[9] = SYN_ULTRA_XFER_NS_9;
10385 asc_dvc->sdtr_period_tbl[10] = SYN_ULTRA_XFER_NS_10;
10386 asc_dvc->sdtr_period_tbl[11] = SYN_ULTRA_XFER_NS_11;
10387 asc_dvc->sdtr_period_tbl[12] = SYN_ULTRA_XFER_NS_12;
10388 asc_dvc->sdtr_period_tbl[13] = SYN_ULTRA_XFER_NS_13;
10389 asc_dvc->sdtr_period_tbl[14] = SYN_ULTRA_XFER_NS_14;
10390 asc_dvc->sdtr_period_tbl[15] = SYN_ULTRA_XFER_NS_15;
10391 asc_dvc->max_sdtr_index = 15;
10392 if (chip_version == ASC_CHIP_VER_PCI_ULTRA_3150) {
10393 AscSetExtraControl(iop_base,
10394 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
10395 } else if (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3050) {
10396 AscSetExtraControl(iop_base,
10397 (SEC_ACTIVE_NEGATE |
10398 SEC_ENABLE_FILTER));
10399 }
10400 }
10401 if (asc_dvc->bus_type == ASC_IS_PCI) {
10402 AscSetExtraControl(iop_base,
10403 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
10404 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010405
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010406 asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010407#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010408 if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) {
Matthew Wilcox59fcf842007-07-26 11:54:15 -040010409 if (chip_version >= ASC_CHIP_MIN_VER_ISA_PNP) {
10410 AscSetChipIFC(iop_base, IFC_INIT_DEFAULT);
10411 asc_dvc->bus_type = ASC_IS_ISAPNP;
10412 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010413 asc_dvc->cfg->isa_dma_channel =
10414 (uchar)AscGetIsaDmaChannel(iop_base);
10415 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010416#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010417 for (i = 0; i <= ASC_MAX_TID; i++) {
10418 asc_dvc->cur_dvc_qng[i] = 0;
10419 asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG;
10420 asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q *)0L;
10421 asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q *)0L;
10422 asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG;
10423 }
10424 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010425}
10426
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010427static ushort __devinit AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010428{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010429 ASCEEP_CONFIG eep_config_buf;
10430 ASCEEP_CONFIG *eep_config;
10431 PortAddr iop_base;
10432 ushort chksum;
10433 ushort warn_code;
10434 ushort cfg_msw, cfg_lsw;
10435 int i;
10436 int write_eep = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010437
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010438 iop_base = asc_dvc->iop_base;
10439 warn_code = 0;
10440 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE);
10441 AscStopQueueExe(iop_base);
10442 if ((AscStopChip(iop_base) == FALSE) ||
10443 (AscGetChipScsiCtrl(iop_base) != 0)) {
10444 asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
10445 AscResetChipAndScsiBus(asc_dvc);
10446 DvcSleepMilliSecond((ASC_DCNT)
10447 ((ushort)asc_dvc->scsi_reset_wait * 1000));
10448 }
10449 if (AscIsChipHalted(iop_base) == FALSE) {
10450 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
10451 return (warn_code);
10452 }
10453 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
10454 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
10455 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
10456 return (warn_code);
10457 }
10458 eep_config = (ASCEEP_CONFIG *)&eep_config_buf;
10459 cfg_msw = AscGetChipCfgMsw(iop_base);
10460 cfg_lsw = AscGetChipCfgLsw(iop_base);
10461 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
10462 cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
10463 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
10464 AscSetChipCfgMsw(iop_base, cfg_msw);
10465 }
10466 chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
10467 ASC_DBG1(1, "AscInitFromEEP: chksum 0x%x\n", chksum);
10468 if (chksum == 0) {
10469 chksum = 0xaa55;
10470 }
10471 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
10472 warn_code |= ASC_WARN_AUTO_CONFIG;
10473 if (asc_dvc->cfg->chip_version == 3) {
10474 if (eep_config->cfg_lsw != cfg_lsw) {
10475 warn_code |= ASC_WARN_EEPROM_RECOVER;
10476 eep_config->cfg_lsw =
10477 AscGetChipCfgLsw(iop_base);
10478 }
10479 if (eep_config->cfg_msw != cfg_msw) {
10480 warn_code |= ASC_WARN_EEPROM_RECOVER;
10481 eep_config->cfg_msw =
10482 AscGetChipCfgMsw(iop_base);
10483 }
10484 }
10485 }
10486 eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
10487 eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
10488 ASC_DBG1(1, "AscInitFromEEP: eep_config->chksum 0x%x\n",
10489 eep_config->chksum);
10490 if (chksum != eep_config->chksum) {
10491 if (AscGetChipVersion(iop_base, asc_dvc->bus_type) ==
10492 ASC_CHIP_VER_PCI_ULTRA_3050) {
10493 ASC_DBG(1,
10494 "AscInitFromEEP: chksum error ignored; EEPROM-less board\n");
10495 eep_config->init_sdtr = 0xFF;
10496 eep_config->disc_enable = 0xFF;
10497 eep_config->start_motor = 0xFF;
10498 eep_config->use_cmd_qng = 0;
10499 eep_config->max_total_qng = 0xF0;
10500 eep_config->max_tag_qng = 0x20;
10501 eep_config->cntl = 0xBFFF;
10502 ASC_EEP_SET_CHIP_ID(eep_config, 7);
10503 eep_config->no_scam = 0;
10504 eep_config->adapter_info[0] = 0;
10505 eep_config->adapter_info[1] = 0;
10506 eep_config->adapter_info[2] = 0;
10507 eep_config->adapter_info[3] = 0;
10508 eep_config->adapter_info[4] = 0;
10509 /* Indicate EEPROM-less board. */
10510 eep_config->adapter_info[5] = 0xBB;
10511 } else {
10512 ASC_PRINT
10513 ("AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n");
10514 write_eep = 1;
10515 warn_code |= ASC_WARN_EEPROM_CHKSUM;
10516 }
10517 }
10518 asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr;
10519 asc_dvc->cfg->disc_enable = eep_config->disc_enable;
10520 asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
10521 asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config);
10522 asc_dvc->start_motor = eep_config->start_motor;
10523 asc_dvc->dvc_cntl = eep_config->cntl;
10524 asc_dvc->no_scam = eep_config->no_scam;
10525 asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0];
10526 asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1];
10527 asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2];
10528 asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3];
10529 asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4];
10530 asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5];
10531 if (!AscTestExternalLram(asc_dvc)) {
10532 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) ==
10533 ASC_IS_PCI_ULTRA)) {
10534 eep_config->max_total_qng =
10535 ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
10536 eep_config->max_tag_qng =
10537 ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG;
10538 } else {
10539 eep_config->cfg_msw |= 0x0800;
10540 cfg_msw |= 0x0800;
10541 AscSetChipCfgMsw(iop_base, cfg_msw);
10542 eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
10543 eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG;
10544 }
10545 } else {
10546 }
10547 if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) {
10548 eep_config->max_total_qng = ASC_MIN_TOTAL_QNG;
10549 }
10550 if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) {
10551 eep_config->max_total_qng = ASC_MAX_TOTAL_QNG;
10552 }
10553 if (eep_config->max_tag_qng > eep_config->max_total_qng) {
10554 eep_config->max_tag_qng = eep_config->max_total_qng;
10555 }
10556 if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) {
10557 eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC;
10558 }
10559 asc_dvc->max_total_qng = eep_config->max_total_qng;
10560 if ((eep_config->use_cmd_qng & eep_config->disc_enable) !=
10561 eep_config->use_cmd_qng) {
10562 eep_config->disc_enable = eep_config->use_cmd_qng;
10563 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
10564 }
10565 if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
10566 asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
10567 }
10568 ASC_EEP_SET_CHIP_ID(eep_config,
10569 ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID);
10570 asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config);
10571 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) &&
10572 !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
10573 asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
10574 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010575
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010576 for (i = 0; i <= ASC_MAX_TID; i++) {
10577 asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
10578 asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
10579 asc_dvc->cfg->sdtr_period_offset[i] =
10580 (uchar)(ASC_DEF_SDTR_OFFSET |
10581 (asc_dvc->host_init_sdtr_index << 4));
10582 }
10583 eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
10584 if (write_eep) {
10585 if ((i =
10586 AscSetEEPConfig(iop_base, eep_config,
10587 asc_dvc->bus_type)) != 0) {
10588 ASC_PRINT1
10589 ("AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n",
10590 i);
10591 } else {
10592 ASC_PRINT
10593 ("AscInitFromEEP: Successfully re-wrote EEPROM.\n");
10594 }
10595 }
10596 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010597}
10598
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010599static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010600{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010601 int i;
10602 ushort warn_code;
10603 PortAddr iop_base;
10604 ASC_PADDR phy_addr;
10605 ASC_DCNT phy_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010606
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010607 iop_base = asc_dvc->iop_base;
10608 warn_code = 0;
10609 for (i = 0; i <= ASC_MAX_TID; i++) {
10610 AscPutMCodeInitSDTRAtID(iop_base, i,
10611 asc_dvc->cfg->sdtr_period_offset[i]
10612 );
10613 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010614
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010615 AscInitQLinkVar(asc_dvc);
10616 AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
10617 asc_dvc->cfg->disc_enable);
10618 AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
10619 ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010620
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010621 /* Align overrun buffer on an 8 byte boundary. */
10622 phy_addr = virt_to_bus(asc_dvc->cfg->overrun_buf);
10623 phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7);
10624 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
10625 (uchar *)&phy_addr, 1);
10626 phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE - 8);
10627 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D,
10628 (uchar *)&phy_size, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010629
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010630 asc_dvc->cfg->mcode_date =
10631 AscReadLramWord(iop_base, (ushort)ASCV_MC_DATE_W);
10632 asc_dvc->cfg->mcode_version =
10633 AscReadLramWord(iop_base, (ushort)ASCV_MC_VER_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010634
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010635 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
10636 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
10637 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
10638 return (warn_code);
10639 }
10640 if (AscStartChip(iop_base) != 1) {
10641 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
10642 return (warn_code);
10643 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010644
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010645 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010646}
10647
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010648static int __devinit AscTestExternalLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010649{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010650 PortAddr iop_base;
10651 ushort q_addr;
10652 ushort saved_word;
10653 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010654
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010655 iop_base = asc_dvc->iop_base;
10656 sta = 0;
10657 q_addr = ASC_QNO_TO_QADDR(241);
10658 saved_word = AscReadLramWord(iop_base, q_addr);
10659 AscSetChipLramAddr(iop_base, q_addr);
10660 AscSetChipLramData(iop_base, 0x55AA);
10661 DvcSleepMilliSecond(10);
10662 AscSetChipLramAddr(iop_base, q_addr);
10663 if (AscGetChipLramData(iop_base) == 0x55AA) {
10664 sta = 1;
10665 AscWriteLramWord(iop_base, q_addr, saved_word);
10666 }
10667 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010668}
10669
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010670static int __devinit AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010671{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010672 uchar read_back;
10673 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010674
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010675 retry = 0;
10676 while (TRUE) {
10677 AscSetChipEEPCmd(iop_base, cmd_reg);
10678 DvcSleepMilliSecond(1);
10679 read_back = AscGetChipEEPCmd(iop_base);
10680 if (read_back == cmd_reg) {
10681 return (1);
10682 }
10683 if (retry++ > ASC_EEP_MAX_RETRY) {
10684 return (0);
10685 }
10686 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010687}
10688
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010689static int __devinit AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010690{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010691 ushort read_back;
10692 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010693
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010694 retry = 0;
10695 while (TRUE) {
10696 AscSetChipEEPData(iop_base, data_reg);
10697 DvcSleepMilliSecond(1);
10698 read_back = AscGetChipEEPData(iop_base);
10699 if (read_back == data_reg) {
10700 return (1);
10701 }
10702 if (retry++ > ASC_EEP_MAX_RETRY) {
10703 return (0);
10704 }
10705 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010706}
10707
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010708static void __devinit AscWaitEEPRead(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010709{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010710 DvcSleepMilliSecond(1);
10711 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010712}
10713
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010714static void __devinit AscWaitEEPWrite(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010715{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010716 DvcSleepMilliSecond(20);
10717 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010718}
10719
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010720static ushort __devinit AscReadEEPWord(PortAddr iop_base, uchar addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010721{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010722 ushort read_wval;
10723 uchar cmd_reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010724
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010725 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
10726 AscWaitEEPRead();
10727 cmd_reg = addr | ASC_EEP_CMD_READ;
10728 AscWriteEEPCmdReg(iop_base, cmd_reg);
10729 AscWaitEEPRead();
10730 read_wval = AscGetChipEEPData(iop_base);
10731 AscWaitEEPRead();
10732 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010733}
10734
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010735static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010736AscWriteEEPWord(PortAddr iop_base, uchar addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010737{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010738 ushort read_wval;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010739
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010740 read_wval = AscReadEEPWord(iop_base, addr);
10741 if (read_wval != word_val) {
10742 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE);
10743 AscWaitEEPRead();
10744 AscWriteEEPDataReg(iop_base, word_val);
10745 AscWaitEEPRead();
10746 AscWriteEEPCmdReg(iop_base,
10747 (uchar)((uchar)ASC_EEP_CMD_WRITE | addr));
10748 AscWaitEEPWrite();
10749 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
10750 AscWaitEEPRead();
10751 return (AscReadEEPWord(iop_base, addr));
10752 }
10753 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010754}
10755
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010756static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010757AscGetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010758{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010759 ushort wval;
10760 ushort sum;
10761 ushort *wbuf;
10762 int cfg_beg;
10763 int cfg_end;
10764 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
10765 int s_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010766
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010767 wbuf = (ushort *)cfg_buf;
10768 sum = 0;
10769 /* Read two config words; Byte-swapping done by AscReadEEPWord(). */
10770 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
10771 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
10772 sum += *wbuf;
10773 }
10774 if (bus_type & ASC_IS_VL) {
10775 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
10776 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
10777 } else {
10778 cfg_beg = ASC_EEP_DVC_CFG_BEG;
10779 cfg_end = ASC_EEP_MAX_DVC_ADDR;
10780 }
10781 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
10782 wval = AscReadEEPWord(iop_base, (uchar)s_addr);
10783 if (s_addr <= uchar_end_in_config) {
10784 /*
10785 * Swap all char fields - must unswap bytes already swapped
10786 * by AscReadEEPWord().
10787 */
10788 *wbuf = le16_to_cpu(wval);
10789 } else {
10790 /* Don't swap word field at the end - cntl field. */
10791 *wbuf = wval;
10792 }
10793 sum += wval; /* Checksum treats all EEPROM data as words. */
10794 }
10795 /*
10796 * Read the checksum word which will be compared against 'sum'
10797 * by the caller. Word field already swapped.
10798 */
10799 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
10800 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010801}
10802
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010803static int __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010804AscSetEEPConfigOnce(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010805{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010806 int n_error;
10807 ushort *wbuf;
10808 ushort word;
10809 ushort sum;
10810 int s_addr;
10811 int cfg_beg;
10812 int cfg_end;
10813 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010814
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010815 wbuf = (ushort *)cfg_buf;
10816 n_error = 0;
10817 sum = 0;
10818 /* Write two config words; AscWriteEEPWord() will swap bytes. */
10819 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
10820 sum += *wbuf;
10821 if (*wbuf != AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
10822 n_error++;
10823 }
10824 }
10825 if (bus_type & ASC_IS_VL) {
10826 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
10827 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
10828 } else {
10829 cfg_beg = ASC_EEP_DVC_CFG_BEG;
10830 cfg_end = ASC_EEP_MAX_DVC_ADDR;
10831 }
10832 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
10833 if (s_addr <= uchar_end_in_config) {
10834 /*
10835 * This is a char field. Swap char fields before they are
10836 * swapped again by AscWriteEEPWord().
10837 */
10838 word = cpu_to_le16(*wbuf);
10839 if (word !=
10840 AscWriteEEPWord(iop_base, (uchar)s_addr, word)) {
10841 n_error++;
10842 }
10843 } else {
10844 /* Don't swap word field at the end - cntl field. */
10845 if (*wbuf !=
10846 AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
10847 n_error++;
10848 }
10849 }
10850 sum += *wbuf; /* Checksum calculated from word values. */
10851 }
10852 /* Write checksum word. It will be swapped by AscWriteEEPWord(). */
10853 *wbuf = sum;
10854 if (sum != AscWriteEEPWord(iop_base, (uchar)s_addr, sum)) {
10855 n_error++;
10856 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010857
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010858 /* Read EEPROM back again. */
10859 wbuf = (ushort *)cfg_buf;
10860 /*
10861 * Read two config words; Byte-swapping done by AscReadEEPWord().
10862 */
10863 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
10864 if (*wbuf != AscReadEEPWord(iop_base, (uchar)s_addr)) {
10865 n_error++;
10866 }
10867 }
10868 if (bus_type & ASC_IS_VL) {
10869 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
10870 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
10871 } else {
10872 cfg_beg = ASC_EEP_DVC_CFG_BEG;
10873 cfg_end = ASC_EEP_MAX_DVC_ADDR;
10874 }
10875 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
10876 if (s_addr <= uchar_end_in_config) {
10877 /*
10878 * Swap all char fields. Must unswap bytes already swapped
10879 * by AscReadEEPWord().
10880 */
10881 word =
10882 le16_to_cpu(AscReadEEPWord
10883 (iop_base, (uchar)s_addr));
10884 } else {
10885 /* Don't swap word field at the end - cntl field. */
10886 word = AscReadEEPWord(iop_base, (uchar)s_addr);
10887 }
10888 if (*wbuf != word) {
10889 n_error++;
10890 }
10891 }
10892 /* Read checksum; Byte swapping not needed. */
10893 if (AscReadEEPWord(iop_base, (uchar)s_addr) != sum) {
10894 n_error++;
10895 }
10896 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010897}
10898
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010899static int __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010900AscSetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010901{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010902 int retry;
10903 int n_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010904
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010905 retry = 0;
10906 while (TRUE) {
10907 if ((n_error = AscSetEEPConfigOnce(iop_base, cfg_buf,
10908 bus_type)) == 0) {
10909 break;
10910 }
10911 if (++retry > ASC_EEP_MAX_RETRY) {
10912 break;
10913 }
10914 }
10915 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010916}
10917
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010918static void AscAsyncFix(ASC_DVC_VAR *asc_dvc, struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010919{
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010920 char type = sdev->type;
10921 ASC_SCSI_BIT_ID_TYPE tid_bits = 1 << sdev->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010922
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010923 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) {
10924 if (!(asc_dvc->init_sdtr & tid_bits)) {
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010925 if ((type == TYPE_ROM) &&
10926 (strncmp(sdev->vendor, "HP ", 3) == 0)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010927 asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
10928 }
10929 asc_dvc->pci_fix_asyn_xfer |= tid_bits;
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010930 if ((type == TYPE_PROCESSOR) ||
10931 (type == TYPE_SCANNER) || (type == TYPE_ROM) ||
10932 (type == TYPE_TAPE)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010933 asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
10934 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010935
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010936 if (asc_dvc->pci_fix_asyn_xfer & tid_bits) {
10937 AscSetRunChipSynRegAtID(asc_dvc->iop_base,
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010938 sdev->id,
10939 ASYN_SDTR_DATA_FIX_PCI_REV_AB);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010940 }
10941 }
10942 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010943}
10944
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010945static uchar AscReadLramByte(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010946{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010947 uchar byte_data;
10948 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010949
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010950 if (isodd_word(addr)) {
10951 AscSetChipLramAddr(iop_base, addr - 1);
10952 word_data = AscGetChipLramData(iop_base);
10953 byte_data = (uchar)((word_data >> 8) & 0xFF);
10954 } else {
10955 AscSetChipLramAddr(iop_base, addr);
10956 word_data = AscGetChipLramData(iop_base);
10957 byte_data = (uchar)(word_data & 0xFF);
10958 }
10959 return (byte_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010960}
Linus Torvalds1da177e2005-04-16 15:20:36 -070010961
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010962static ushort AscReadLramWord(PortAddr iop_base, ushort addr)
10963{
10964 ushort word_data;
10965
10966 AscSetChipLramAddr(iop_base, addr);
10967 word_data = AscGetChipLramData(iop_base);
10968 return (word_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010969}
10970
10971#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010972static ASC_DCNT AscReadLramDWord(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010973{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010974 ushort val_low, val_high;
10975 ASC_DCNT dword_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010976
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010977 AscSetChipLramAddr(iop_base, addr);
10978 val_low = AscGetChipLramData(iop_base);
10979 val_high = AscGetChipLramData(iop_base);
10980 dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low;
10981 return (dword_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010982}
10983#endif /* CC_VERY_LONG_SG_LIST */
10984
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010985static void AscWriteLramWord(PortAddr iop_base, ushort addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010986{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010987 AscSetChipLramAddr(iop_base, addr);
10988 AscSetChipLramData(iop_base, word_val);
10989 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010990}
10991
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010992static void AscWriteLramByte(PortAddr iop_base, ushort addr, uchar byte_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010993{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010994 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010995
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010996 if (isodd_word(addr)) {
10997 addr--;
10998 word_data = AscReadLramWord(iop_base, addr);
10999 word_data &= 0x00FF;
11000 word_data |= (((ushort)byte_val << 8) & 0xFF00);
11001 } else {
11002 word_data = AscReadLramWord(iop_base, addr);
11003 word_data &= 0xFF00;
11004 word_data |= ((ushort)byte_val & 0x00FF);
11005 }
11006 AscWriteLramWord(iop_base, addr, word_data);
11007 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011008}
11009
11010/*
11011 * Copy 2 bytes to LRAM.
11012 *
11013 * The source data is assumed to be in little-endian order in memory
11014 * and is maintained in little-endian order when written to LRAM.
11015 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011016static void
11017AscMemWordCopyPtrToLram(PortAddr iop_base,
11018 ushort s_addr, uchar *s_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011019{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011020 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011021
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011022 AscSetChipLramAddr(iop_base, s_addr);
11023 for (i = 0; i < 2 * words; i += 2) {
11024 /*
11025 * On a little-endian system the second argument below
11026 * produces a little-endian ushort which is written to
11027 * LRAM in little-endian order. On a big-endian system
11028 * the second argument produces a big-endian ushort which
11029 * is "transparently" byte-swapped by outpw() and written
11030 * in little-endian order to LRAM.
11031 */
11032 outpw(iop_base + IOP_RAM_DATA,
11033 ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]);
11034 }
11035 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011036}
11037
11038/*
11039 * Copy 4 bytes to LRAM.
11040 *
11041 * The source data is assumed to be in little-endian order in memory
11042 * and is maintained in little-endian order when writen to LRAM.
11043 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011044static void
11045AscMemDWordCopyPtrToLram(PortAddr iop_base,
11046 ushort s_addr, uchar *s_buffer, int dwords)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011047{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011048 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011049
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011050 AscSetChipLramAddr(iop_base, s_addr);
11051 for (i = 0; i < 4 * dwords; i += 4) {
11052 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]); /* LSW */
11053 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 3] << 8) | s_buffer[i + 2]); /* MSW */
11054 }
11055 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011056}
11057
11058/*
11059 * Copy 2 bytes from LRAM.
11060 *
11061 * The source data is assumed to be in little-endian order in LRAM
11062 * and is maintained in little-endian order when written to memory.
11063 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011064static void
11065AscMemWordCopyPtrFromLram(PortAddr iop_base,
11066 ushort s_addr, uchar *d_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011067{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011068 int i;
11069 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011070
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011071 AscSetChipLramAddr(iop_base, s_addr);
11072 for (i = 0; i < 2 * words; i += 2) {
11073 word = inpw(iop_base + IOP_RAM_DATA);
11074 d_buffer[i] = word & 0xff;
11075 d_buffer[i + 1] = (word >> 8) & 0xff;
11076 }
11077 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011078}
11079
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011080static ASC_DCNT AscMemSumLramWord(PortAddr iop_base, ushort s_addr, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011081{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011082 ASC_DCNT sum;
11083 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011084
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011085 sum = 0L;
11086 for (i = 0; i < words; i++, s_addr += 2) {
11087 sum += AscReadLramWord(iop_base, s_addr);
11088 }
11089 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011090}
11091
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011092static void
11093AscMemWordSetLram(PortAddr iop_base, ushort s_addr, ushort set_wval, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011094{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011095 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011096
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011097 AscSetChipLramAddr(iop_base, s_addr);
11098 for (i = 0; i < words; i++) {
11099 AscSetChipLramData(iop_base, set_wval);
11100 }
11101 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011102}
11103
Linus Torvalds1da177e2005-04-16 15:20:36 -070011104/*
11105 * --- Adv Library Functions
11106 */
11107
11108/* a_mcode.h */
11109
11110/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011111static unsigned char _adv_asc3550_buf[] = {
11112 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x18, 0xe4, 0x00, 0xfc,
11113 0x01, 0x00, 0x48, 0xe4,
11114 0xbe, 0x18, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0x00, 0xfa, 0xff, 0xff,
11115 0x28, 0x0e, 0x9e, 0xe7,
11116 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x00, 0xf6, 0x01, 0xe6, 0x09, 0xe7,
11117 0x55, 0xf0, 0x01, 0xf6,
11118 0x01, 0xfa, 0x08, 0x00, 0x03, 0x00, 0x04, 0x00, 0x18, 0xf4, 0x10, 0x00,
11119 0x00, 0xec, 0x85, 0xf0,
11120 0xbc, 0x00, 0xd5, 0xf0, 0x8e, 0x0c, 0x38, 0x54, 0x00, 0xe6, 0x1e, 0xf0,
11121 0x86, 0xf0, 0xb4, 0x00,
11122 0x98, 0x57, 0xd0, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x0c, 0x00, 0xbb, 0x00,
11123 0xaa, 0x18, 0x02, 0x80,
11124 0x32, 0xf0, 0x01, 0xfc, 0x88, 0x0c, 0xc6, 0x12, 0x02, 0x13, 0x18, 0x40,
11125 0x00, 0x57, 0x01, 0xea,
11126 0x3c, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12, 0x3e, 0x57, 0x00, 0x80,
11127 0x03, 0xe6, 0xb6, 0x00,
11128 0xc0, 0x00, 0x01, 0x01, 0x3e, 0x01, 0xda, 0x0f, 0x22, 0x10, 0x08, 0x12,
11129 0x02, 0x4a, 0xb9, 0x54,
11130 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x20, 0x00, 0x32, 0x00,
11131 0x3e, 0x00, 0x80, 0x00,
11132 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01,
11133 0x74, 0x01, 0x76, 0x01,
11134 0x78, 0x01, 0x62, 0x0a, 0x92, 0x0c, 0x2c, 0x10, 0x2e, 0x10, 0x06, 0x13,
11135 0x4c, 0x1c, 0xbb, 0x55,
11136 0x3c, 0x56, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0xb1, 0xf0,
11137 0x03, 0xf7, 0x06, 0xf7,
11138 0x03, 0xfc, 0x0f, 0x00, 0x40, 0x00, 0xbe, 0x00, 0x00, 0x01, 0xb0, 0x08,
11139 0x30, 0x13, 0x64, 0x15,
11140 0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44, 0x02, 0x48, 0x00, 0x4c,
11141 0x04, 0xea, 0x5d, 0xf0,
11142 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00,
11143 0xcc, 0x00, 0x20, 0x01,
11144 0x4e, 0x01, 0x4e, 0x0b, 0x1e, 0x0e, 0x0c, 0x10, 0x0a, 0x12, 0x04, 0x13,
11145 0x40, 0x13, 0x30, 0x1c,
11146 0x00, 0x4e, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
11147 0x59, 0xf0, 0xa7, 0xf0,
11148 0xb8, 0xf0, 0x0e, 0xf7, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00,
11149 0xa4, 0x00, 0xb5, 0x00,
11150 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xde, 0x03, 0x56, 0x0a,
11151 0x14, 0x0e, 0x02, 0x10,
11152 0x04, 0x10, 0x0a, 0x10, 0x36, 0x10, 0x0a, 0x13, 0x12, 0x13, 0x52, 0x13,
11153 0x10, 0x15, 0x14, 0x15,
11154 0xac, 0x16, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44,
11155 0x91, 0x44, 0x0a, 0x45,
11156 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x83, 0x55, 0xb0, 0x57, 0x01, 0x58,
11157 0x83, 0x59, 0x05, 0xe6,
11158 0x0b, 0xf0, 0x0c, 0xf0, 0x5c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, 0x05, 0xf8,
11159 0x02, 0xfa, 0x03, 0xfa,
11160 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x1c, 0x00,
11161 0x9e, 0x00, 0xa8, 0x00,
11162 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01,
11163 0x7a, 0x01, 0xc0, 0x01,
11164 0xc2, 0x01, 0x7c, 0x02, 0x5a, 0x03, 0xea, 0x04, 0xe8, 0x07, 0x68, 0x08,
11165 0x69, 0x08, 0xba, 0x08,
11166 0xe9, 0x09, 0x06, 0x0b, 0x3a, 0x0e, 0x00, 0x10, 0x1a, 0x10, 0xed, 0x10,
11167 0xf1, 0x10, 0x06, 0x12,
11168 0x0c, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x82, 0x13, 0x42, 0x14, 0xd6, 0x14,
11169 0x8a, 0x15, 0xc6, 0x17,
11170 0xd2, 0x17, 0x6b, 0x18, 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40,
11171 0x0e, 0x47, 0x48, 0x47,
11172 0x41, 0x48, 0x89, 0x48, 0x80, 0x4c, 0x00, 0x54, 0x44, 0x55, 0xe5, 0x55,
11173 0x14, 0x56, 0x77, 0x57,
11174 0xbf, 0x57, 0x40, 0x5c, 0x06, 0x80, 0x08, 0x90, 0x03, 0xa1, 0xfe, 0x9c,
11175 0xf0, 0x29, 0x02, 0xfe,
11176 0xb8, 0x0c, 0xff, 0x10, 0x00, 0x00, 0xd0, 0xfe, 0xcc, 0x18, 0x00, 0xcf,
11177 0xfe, 0x80, 0x01, 0xff,
11178 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
11179 0x00, 0xfe, 0x57, 0x24,
11180 0x00, 0xfe, 0x48, 0x00, 0x4f, 0xff, 0x04, 0x00, 0x00, 0x10, 0xff, 0x09,
11181 0x00, 0x00, 0xff, 0x08,
11182 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
11183 0xff, 0xff, 0xff, 0x0f,
11184 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
11185 0xfe, 0x04, 0xf7, 0xcf,
11186 0x2a, 0x67, 0x0b, 0x01, 0xfe, 0xce, 0x0e, 0xfe, 0x04, 0xf7, 0xcf, 0x67,
11187 0x0b, 0x3c, 0x2a, 0xfe,
11188 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x91, 0xf0,
11189 0xfe, 0xf0, 0x01, 0xfe,
11190 0x90, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, 0x8f, 0xf0, 0x9c, 0x05, 0x51, 0x3b,
11191 0x02, 0xfe, 0xd4, 0x0c,
11192 0x01, 0xfe, 0x44, 0x0d, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
11193 0x1c, 0x05, 0xfe, 0xa6,
11194 0x00, 0xfe, 0xd3, 0x12, 0x47, 0x18, 0xfe, 0xa6, 0x00, 0xb5, 0xfe, 0x48,
11195 0xf0, 0xfe, 0x86, 0x02,
11196 0xfe, 0x49, 0xf0, 0xfe, 0xa0, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xbe, 0x02,
11197 0xfe, 0x46, 0xf0, 0xfe,
11198 0x50, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x56, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
11199 0x44, 0x02, 0xfe, 0x44,
11200 0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x4c, 0x02, 0x17, 0x0b,
11201 0xa0, 0x17, 0x06, 0x18,
11202 0x96, 0x02, 0x29, 0xfe, 0x00, 0x1c, 0xde, 0xfe, 0x02, 0x1c, 0xdd, 0xfe,
11203 0x1e, 0x1c, 0xfe, 0xe9,
11204 0x10, 0x01, 0xfe, 0x20, 0x17, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xc7,
11205 0x0a, 0x6b, 0x01, 0x9e,
11206 0x02, 0x29, 0x14, 0x4d, 0x37, 0x97, 0x01, 0xfe, 0x64, 0x0f, 0x0a, 0x6b,
11207 0x01, 0x82, 0xfe, 0xbd,
11208 0x10, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
11209 0x58, 0x1c, 0x17, 0x06,
11210 0x18, 0x96, 0x2a, 0x25, 0x29, 0xfe, 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0x21,
11211 0xfe, 0x94, 0x02, 0xfe,
11212 0x5a, 0x1c, 0xea, 0xfe, 0x14, 0x1c, 0x14, 0xfe, 0x30, 0x00, 0x37, 0x97,
11213 0x01, 0xfe, 0x54, 0x0f,
11214 0x17, 0x06, 0x18, 0x96, 0x02, 0xd0, 0x1e, 0x20, 0x07, 0x10, 0x34, 0xfe,
11215 0x69, 0x10, 0x17, 0x06,
11216 0x18, 0x96, 0xfe, 0x04, 0xec, 0x20, 0x46, 0x3d, 0x12, 0x20, 0xfe, 0x05,
11217 0xf6, 0xc7, 0x01, 0xfe,
11218 0x52, 0x16, 0x09, 0x4a, 0x4c, 0x35, 0x11, 0x2d, 0x3c, 0x8a, 0x01, 0xe6,
11219 0x02, 0x29, 0x0a, 0x40,
11220 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x01, 0x6f, 0xfe, 0x18, 0x10, 0xfe, 0x41,
11221 0x58, 0x0a, 0x99, 0x01,
11222 0x0e, 0xfe, 0xc8, 0x54, 0x64, 0xfe, 0x0c, 0x03, 0x01, 0xe6, 0x02, 0x29,
11223 0x2a, 0x46, 0xfe, 0x02,
11224 0xe8, 0x27, 0xf8, 0xfe, 0x9e, 0x43, 0xf7, 0xfe, 0x27, 0xf0, 0xfe, 0xdc,
11225 0x01, 0xfe, 0x07, 0x4b,
11226 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x40, 0x1c, 0x25, 0xd2, 0xfe, 0x26, 0xf0,
11227 0xfe, 0x56, 0x03, 0xfe,
11228 0xa0, 0xf0, 0xfe, 0x44, 0x03, 0xfe, 0x11, 0xf0, 0x9c, 0xfe, 0xef, 0x10,
11229 0xfe, 0x9f, 0xf0, 0xfe,
11230 0x64, 0x03, 0xeb, 0x0f, 0xfe, 0x11, 0x00, 0x02, 0x5a, 0x2a, 0xfe, 0x48,
11231 0x1c, 0xeb, 0x09, 0x04,
11232 0x1d, 0xfe, 0x18, 0x13, 0x23, 0x1e, 0x98, 0xac, 0x12, 0x98, 0x0a, 0x40,
11233 0x01, 0x0e, 0xac, 0x75,
11234 0x01, 0xfe, 0xbc, 0x15, 0x11, 0xca, 0x25, 0xd2, 0xfe, 0x01, 0xf0, 0xd2,
11235 0xfe, 0x82, 0xf0, 0xfe,
11236 0x92, 0x03, 0xec, 0x11, 0xfe, 0xe4, 0x00, 0x65, 0xfe, 0xa4, 0x03, 0x25,
11237 0x32, 0x1f, 0xfe, 0xb4,
11238 0x03, 0x01, 0x43, 0xfe, 0x06, 0xf0, 0xfe, 0xc4, 0x03, 0x8d, 0x81, 0xfe,
11239 0x0a, 0xf0, 0xfe, 0x7a,
11240 0x06, 0x02, 0x22, 0x05, 0x6b, 0x28, 0x16, 0xfe, 0xf6, 0x04, 0x14, 0x2c,
11241 0x01, 0x33, 0x8f, 0xfe,
11242 0x66, 0x02, 0x02, 0xd1, 0xeb, 0x2a, 0x67, 0x1a, 0xfe, 0x67, 0x1b, 0xf8,
11243 0xf7, 0xfe, 0x48, 0x1c,
11244 0x70, 0x01, 0x6e, 0x87, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x16, 0xd3,
11245 0x0a, 0xca, 0x01, 0x0e,
11246 0x74, 0x60, 0x59, 0x76, 0x27, 0x05, 0x6b, 0x28, 0xfe, 0x10, 0x12, 0x14,
11247 0x2c, 0x01, 0x33, 0x8f,
11248 0xfe, 0x66, 0x02, 0x02, 0xd1, 0xbc, 0x7d, 0xbd, 0x7f, 0x25, 0x22, 0x65,
11249 0xfe, 0x3c, 0x04, 0x1f,
11250 0xfe, 0x38, 0x04, 0x68, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e,
11251 0x12, 0x2b, 0xff, 0x02,
11252 0x00, 0x10, 0x01, 0x08, 0x1f, 0xfe, 0xe0, 0x04, 0x2b, 0x01, 0x08, 0x1f,
11253 0x22, 0x30, 0x2e, 0xd5,
11254 0xfe, 0x4c, 0x44, 0xfe, 0x4c, 0x12, 0x60, 0xfe, 0x44, 0x48, 0x13, 0x2c,
11255 0xfe, 0x4c, 0x54, 0x64,
11256 0xd3, 0x46, 0x76, 0x27, 0xfa, 0xef, 0xfe, 0x62, 0x13, 0x09, 0x04, 0x1d,
11257 0xfe, 0x2a, 0x13, 0x2f,
11258 0x07, 0x7e, 0xa5, 0xfe, 0x20, 0x10, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64,
11259 0xd3, 0xfa, 0xef, 0x86,
11260 0x09, 0x04, 0x1d, 0xfe, 0x08, 0x13, 0x2f, 0x07, 0x7e, 0x6e, 0x09, 0x04,
11261 0x1d, 0xfe, 0x1c, 0x12,
11262 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe,
11263 0x70, 0x0c, 0x02, 0x22,
11264 0x2b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90, 0xf9, 0x03, 0x14, 0x92,
11265 0x01, 0x33, 0x02, 0x29,
11266 0xfe, 0x42, 0x5b, 0x67, 0x1a, 0xfe, 0x46, 0x59, 0xf8, 0xf7, 0xfe, 0x87,
11267 0x80, 0xfe, 0x31, 0xe4,
11268 0x4f, 0x09, 0x04, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x1a,
11269 0xfe, 0x70, 0x12, 0x49,
11270 0x04, 0x06, 0xfe, 0x60, 0x13, 0x05, 0xfe, 0xa2, 0x00, 0x28, 0x16, 0xfe,
11271 0x80, 0x05, 0xfe, 0x31,
11272 0xe4, 0x6a, 0x49, 0x04, 0x0b, 0xfe, 0x4a, 0x13, 0x05, 0xfe, 0xa0, 0x00,
11273 0x28, 0xfe, 0x42, 0x12,
11274 0x5e, 0x01, 0x08, 0x25, 0x32, 0xf1, 0x01, 0x08, 0x26, 0xfe, 0x98, 0x05,
11275 0x11, 0xfe, 0xe3, 0x00,
11276 0x23, 0x49, 0xfe, 0x4a, 0xf0, 0xfe, 0x6a, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
11277 0x64, 0x05, 0x83, 0x24,
11278 0xfe, 0x21, 0x00, 0xa1, 0x24, 0xfe, 0x22, 0x00, 0xa0, 0x24, 0x4c, 0xfe,
11279 0x09, 0x48, 0x01, 0x08,
11280 0x26, 0xfe, 0x98, 0x05, 0xfe, 0xe2, 0x08, 0x49, 0x04, 0xc5, 0x3b, 0x01,
11281 0x86, 0x24, 0x06, 0x12,
11282 0xcc, 0x37, 0xfe, 0x27, 0x01, 0x09, 0x04, 0x1d, 0xfe, 0x22, 0x12, 0x47,
11283 0x01, 0xa7, 0x14, 0x92,
11284 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c,
11285 0x02, 0x22, 0x05, 0xfe,
11286 0x9c, 0x00, 0x28, 0xfe, 0x3e, 0x12, 0x05, 0x50, 0x28, 0xfe, 0x36, 0x13,
11287 0x47, 0x01, 0xa7, 0x26,
11288 0xfe, 0x08, 0x06, 0x0a, 0x06, 0x49, 0x04, 0x19, 0xfe, 0x02, 0x12, 0x5f,
11289 0x01, 0xfe, 0xaa, 0x14,
11290 0x1f, 0xfe, 0xfe, 0x05, 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00,
11291 0x05, 0x50, 0xb4, 0x0c,
11292 0x50, 0x05, 0xc6, 0x28, 0xfe, 0x62, 0x12, 0x05, 0x3f, 0x28, 0xfe, 0x5a,
11293 0x13, 0x01, 0xfe, 0x14,
11294 0x18, 0x01, 0xfe, 0x66, 0x18, 0xfe, 0x43, 0x48, 0xb7, 0x19, 0x13, 0x6c,
11295 0xff, 0x02, 0x00, 0x57,
11296 0x48, 0x8b, 0x1c, 0x3d, 0x85, 0xb7, 0x69, 0x47, 0x01, 0xa7, 0x26, 0xfe,
11297 0x72, 0x06, 0x49, 0x04,
11298 0x1b, 0xdf, 0x89, 0x0a, 0x4d, 0x01, 0xfe, 0xd8, 0x14, 0x1f, 0xfe, 0x68,
11299 0x06, 0x11, 0x9a, 0x01,
11300 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x3f, 0xb4, 0x0c, 0x3f, 0x17, 0x06,
11301 0x01, 0xa7, 0xec, 0x72,
11302 0x70, 0x01, 0x6e, 0x87, 0x11, 0xfe, 0xe2, 0x00, 0x01, 0x08, 0x25, 0x32,
11303 0xfe, 0x0a, 0xf0, 0xfe,
11304 0xa6, 0x06, 0x8c, 0xfe, 0x5c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, 0x64, 0x07,
11305 0x8d, 0x81, 0x02, 0x22,
11306 0x09, 0x04, 0x0b, 0xfe, 0x2e, 0x12, 0x15, 0x1a, 0x01, 0x08, 0x15, 0x00,
11307 0x01, 0x08, 0x15, 0x00,
11308 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x15,
11309 0x00, 0x02, 0xfe, 0x32,
11310 0x08, 0x61, 0x04, 0x1b, 0xfe, 0x38, 0x12, 0x09, 0x04, 0x1b, 0x6e, 0x15,
11311 0xfe, 0x1b, 0x00, 0x01,
11312 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01,
11313 0x08, 0x15, 0x06, 0x01,
11314 0x08, 0x15, 0x00, 0x02, 0xd9, 0x66, 0x4c, 0xfe, 0x3a, 0x55, 0x5f, 0xfe,
11315 0x9a, 0x81, 0x4b, 0x1d,
11316 0xba, 0xfe, 0x32, 0x07, 0x0a, 0x1d, 0xfe, 0x09, 0x6f, 0xaf, 0xfe, 0xca,
11317 0x45, 0xfe, 0x32, 0x12,
11318 0x62, 0x2c, 0x85, 0x66, 0x7b, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0,
11319 0xfe, 0x32, 0x07, 0x8d,
11320 0x81, 0x8c, 0xfe, 0x5c, 0x07, 0x02, 0x22, 0x01, 0x43, 0x02, 0xfe, 0x8a,
11321 0x06, 0x15, 0x19, 0x02,
11322 0xfe, 0x8a, 0x06, 0xfe, 0x9c, 0xf7, 0xd4, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
11323 0x90, 0x77, 0xfe, 0xca,
11324 0x07, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x4a, 0x6a, 0x35, 0x1e, 0x20, 0x07,
11325 0x10, 0xfe, 0x0e, 0x12,
11326 0x74, 0xfe, 0x80, 0x80, 0x37, 0x20, 0x63, 0x27, 0xfe, 0x06, 0x10, 0xfe,
11327 0x83, 0xe7, 0xc4, 0xa1,
11328 0xfe, 0x03, 0x40, 0x09, 0x4a, 0x4f, 0x35, 0x01, 0xa8, 0xad, 0xfe, 0x1f,
11329 0x40, 0x12, 0x58, 0x01,
11330 0xa5, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6,
11331 0x51, 0x83, 0xfb, 0xfe,
11332 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90,
11333 0xfe, 0x40, 0x50, 0xfe,
11334 0xc2, 0x50, 0x0c, 0x39, 0x18, 0x3a, 0xfe, 0x4a, 0x10, 0x09, 0x04, 0x6a,
11335 0xfe, 0x2a, 0x12, 0xfe,
11336 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x04, 0x4f,
11337 0x85, 0x01, 0xa8, 0xfe,
11338 0x1f, 0x80, 0x12, 0x58, 0xfe, 0x44, 0x90, 0xfe, 0xc6, 0x90, 0x0c, 0x56,
11339 0x18, 0x57, 0xfb, 0xfe,
11340 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90,
11341 0x0c, 0x39, 0x18, 0x3a,
11342 0x0c, 0x38, 0x18, 0x4e, 0x09, 0x4a, 0x19, 0x35, 0x2a, 0x13, 0xfe, 0x4e,
11343 0x11, 0x65, 0xfe, 0x48,
11344 0x08, 0xfe, 0x9e, 0xf0, 0xfe, 0x5c, 0x08, 0xb1, 0x16, 0x32, 0x2a, 0x73,
11345 0xdd, 0xb8, 0xfe, 0x80,
11346 0x08, 0xb9, 0xfe, 0x9e, 0x08, 0x8c, 0xfe, 0x74, 0x08, 0xfe, 0x06, 0xf0,
11347 0xfe, 0x7a, 0x08, 0x8d,
11348 0x81, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xc9, 0x10, 0x15, 0x19, 0xfe, 0xc9,
11349 0x10, 0x61, 0x04, 0x06,
11350 0xfe, 0x10, 0x12, 0x61, 0x04, 0x0b, 0x45, 0x09, 0x04, 0x0b, 0xfe, 0x68,
11351 0x12, 0xfe, 0x2e, 0x1c,
11352 0x02, 0xfe, 0x24, 0x0a, 0x61, 0x04, 0x06, 0x45, 0x61, 0x04, 0x0b, 0xfe,
11353 0x52, 0x12, 0xfe, 0x2c,
11354 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x1e, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0xbe,
11355 0x08, 0xfe, 0x8a, 0x10,
11356 0xaa, 0xfe, 0xf3, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0xca, 0x08, 0x02, 0xfe,
11357 0x24, 0x0a, 0xab, 0xfe,
11358 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0x9d, 0xe9, 0x1c, 0xfe, 0x00, 0xfe, 0xfe,
11359 0x1c, 0x12, 0xb5, 0xfe,
11360 0xd2, 0xf0, 0x9d, 0xfe, 0x76, 0x18, 0x1c, 0x1a, 0x16, 0x9d, 0x05, 0xcb,
11361 0x1c, 0x06, 0x16, 0x9d,
11362 0xb8, 0x6d, 0xb9, 0x6d, 0xaa, 0xab, 0xfe, 0xb1, 0x10, 0x70, 0x5e, 0x2b,
11363 0x14, 0x92, 0x01, 0x33,
11364 0x0f, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x5a, 0x0f, 0x7c, 0x02, 0x5a,
11365 0xfe, 0x74, 0x18, 0x1c,
11366 0xfe, 0x00, 0xf8, 0x16, 0x6d, 0x67, 0x1b, 0x01, 0xfe, 0x44, 0x0d, 0x3b,
11367 0x01, 0xe6, 0x1e, 0x27,
11368 0x74, 0x67, 0x1a, 0x02, 0x6d, 0x09, 0x04, 0x0b, 0x21, 0xfe, 0x06, 0x0a,
11369 0x09, 0x04, 0x6a, 0xfe,
11370 0x82, 0x12, 0x09, 0x04, 0x19, 0xfe, 0x66, 0x13, 0x1e, 0x58, 0xac, 0xfc,
11371 0xfe, 0x83, 0x80, 0xfe,
11372 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x63,
11373 0x27, 0xfe, 0x40, 0x59,
11374 0xfe, 0xc1, 0x59, 0x77, 0xd7, 0x05, 0x54, 0x31, 0x55, 0x0c, 0x7b, 0x18,
11375 0x7c, 0xbe, 0x54, 0xbf,
11376 0x55, 0x01, 0xa8, 0xad, 0x63, 0x27, 0x12, 0x58, 0xc0, 0x38, 0xc1, 0x4e,
11377 0x79, 0x56, 0x68, 0x57,
11378 0xf4, 0xf5, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05, 0xfa, 0x4e, 0x01, 0xa5,
11379 0xa2, 0x23, 0x0c, 0x7b,
11380 0x0c, 0x7c, 0x79, 0x56, 0x68, 0x57, 0xfe, 0x12, 0x10, 0x09, 0x04, 0x19,
11381 0x16, 0xd7, 0x79, 0x39,
11382 0x68, 0x3a, 0x09, 0x04, 0xfe, 0xf7, 0x00, 0x35, 0x05, 0x52, 0x31, 0x53,
11383 0xfe, 0x10, 0x58, 0xfe,
11384 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x02, 0x6d, 0x09, 0x04,
11385 0x19, 0x16, 0xd7, 0x09,
11386 0x04, 0xfe, 0xf7, 0x00, 0x35, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x5f,
11387 0xfe, 0x10, 0x90, 0xfe,
11388 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x2f, 0x07, 0x9b, 0x16, 0xfe, 0xc6, 0x08,
11389 0x11, 0x9b, 0x09, 0x04,
11390 0x0b, 0xfe, 0x14, 0x13, 0x05, 0x39, 0x31, 0x3a, 0x77, 0xfe, 0xc6, 0x08,
11391 0xfe, 0x0c, 0x58, 0xfe,
11392 0x8d, 0x58, 0x02, 0x6d, 0x23, 0x47, 0xfe, 0x19, 0x80, 0xde, 0x09, 0x04,
11393 0x0b, 0xfe, 0x1a, 0x12,
11394 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xe9, 0xb5, 0xfe, 0xd1, 0xf0, 0xd9,
11395 0x14, 0x7a, 0x01, 0x33,
11396 0x0f, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0xbe, 0x39,
11397 0xfe, 0xed, 0x19, 0xbf,
11398 0x3a, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xe9, 0x1c, 0xfe, 0x00, 0xff,
11399 0x34, 0xfe, 0x74, 0x10,
11400 0xb5, 0xfe, 0xd2, 0xf0, 0xfe, 0xb2, 0x0a, 0xfe, 0x76, 0x18, 0x1c, 0x1a,
11401 0x84, 0x05, 0xcb, 0x1c,
11402 0x06, 0xfe, 0x08, 0x13, 0x0f, 0xfe, 0x16, 0x00, 0x02, 0x5a, 0xfe, 0xd1,
11403 0xf0, 0xfe, 0xc4, 0x0a,
11404 0x14, 0x7a, 0x01, 0x33, 0x0f, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe,
11405 0xce, 0xf0, 0xfe, 0xca,
11406 0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x0f, 0xfe,
11407 0x22, 0x00, 0x02, 0x5a,
11408 0xfe, 0xcb, 0xf0, 0xfe, 0xe2, 0x0a, 0x0f, 0xfe, 0x24, 0x00, 0x02, 0x5a,
11409 0xfe, 0xd0, 0xf0, 0xfe,
11410 0xec, 0x0a, 0x0f, 0x93, 0xdc, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x0f,
11411 0x4c, 0xfe, 0x10, 0x10,
11412 0xfe, 0xcc, 0xf0, 0xd9, 0x61, 0x04, 0x19, 0x3b, 0x0f, 0xfe, 0x12, 0x00,
11413 0x2a, 0x13, 0xfe, 0x4e,
11414 0x11, 0x65, 0xfe, 0x0c, 0x0b, 0xfe, 0x9e, 0xf0, 0xfe, 0x20, 0x0b, 0xb1,
11415 0x16, 0x32, 0x2a, 0x73,
11416 0xdd, 0xb8, 0x22, 0xb9, 0x22, 0x2a, 0xec, 0x65, 0xfe, 0x2c, 0x0b, 0x25,
11417 0x32, 0x8c, 0xfe, 0x48,
11418 0x0b, 0x8d, 0x81, 0xb8, 0xd4, 0xb9, 0xd4, 0x02, 0x22, 0x01, 0x43, 0xfe,
11419 0xdb, 0x10, 0x11, 0xfe,
11420 0xe8, 0x00, 0xaa, 0xab, 0x70, 0xbc, 0x7d, 0xbd, 0x7f, 0xfe, 0x89, 0xf0,
11421 0x22, 0x30, 0x2e, 0xd8,
11422 0xbc, 0x7d, 0xbd, 0x7f, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd6, 0xb1,
11423 0x45, 0x0f, 0xfe, 0x42,
11424 0x00, 0x02, 0x5a, 0x78, 0x06, 0xfe, 0x81, 0x49, 0x16, 0xfe, 0x38, 0x0c,
11425 0x09, 0x04, 0x0b, 0xfe,
11426 0x44, 0x13, 0x0f, 0x00, 0x4b, 0x0b, 0xfe, 0x54, 0x12, 0x4b, 0xfe, 0x28,
11427 0x00, 0x21, 0xfe, 0xa6,
11428 0x0c, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x3e, 0xfe, 0x28, 0x00,
11429 0xfe, 0xe2, 0x10, 0x01,
11430 0xe7, 0x01, 0xe8, 0x0a, 0x99, 0x01, 0xfe, 0x32, 0x0e, 0x59, 0x11, 0x2d,
11431 0x01, 0x6f, 0x02, 0x29,
11432 0x0f, 0xfe, 0x44, 0x00, 0x4b, 0x0b, 0xdf, 0x3e, 0x0b, 0xfe, 0xb4, 0x10,
11433 0x01, 0x86, 0x3e, 0x0b,
11434 0xfe, 0xaa, 0x10, 0x01, 0x86, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xa3,
11435 0x3e, 0x0b, 0x0f, 0xfe,
11436 0x43, 0x00, 0xfe, 0x96, 0x10, 0x09, 0x4a, 0x0b, 0x35, 0x01, 0xe7, 0x01,
11437 0xe8, 0x59, 0x11, 0x2d,
11438 0x01, 0x6f, 0x67, 0x0b, 0x59, 0x3c, 0x8a, 0x02, 0xfe, 0x2a, 0x03, 0x09,
11439 0x04, 0x0b, 0x84, 0x3e,
11440 0x0b, 0x0f, 0x00, 0xfe, 0x5c, 0x10, 0x61, 0x04, 0x1b, 0xfe, 0x58, 0x12,
11441 0x09, 0x04, 0x1b, 0xfe,
11442 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x5c, 0x0c, 0xfe,
11443 0x1c, 0x1c, 0xfe, 0x9d,
11444 0xf0, 0xfe, 0x62, 0x0c, 0x09, 0x4a, 0x1b, 0x35, 0xfe, 0xa9, 0x10, 0x0f,
11445 0xfe, 0x15, 0x00, 0xfe,
11446 0x04, 0xe6, 0x0b, 0x5f, 0x5c, 0x0f, 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10,
11447 0x0f, 0xfe, 0x47, 0x00,
11448 0xa1, 0x0f, 0xfe, 0x41, 0x00, 0xa0, 0x0f, 0xfe, 0x24, 0x00, 0x87, 0xaa,
11449 0xab, 0x70, 0x05, 0x6b,
11450 0x28, 0x21, 0xd1, 0x5f, 0xfe, 0x04, 0xe6, 0x1b, 0xfe, 0x9d, 0x41, 0xfe,
11451 0x1c, 0x42, 0x59, 0x01,
11452 0xda, 0x02, 0x29, 0xea, 0x14, 0x0b, 0x37, 0x95, 0xa9, 0x14, 0xfe, 0x31,
11453 0x00, 0x37, 0x97, 0x01,
11454 0xfe, 0x54, 0x0f, 0x02, 0xd0, 0x3c, 0xfe, 0x06, 0xec, 0xc9, 0xee, 0x3e,
11455 0x1d, 0xfe, 0xce, 0x45,
11456 0x34, 0x3c, 0xfe, 0x06, 0xea, 0xc9, 0xfe, 0x47, 0x4b, 0x89, 0xfe, 0x75,
11457 0x57, 0x05, 0x51, 0xfe,
11458 0x98, 0x56, 0xfe, 0x38, 0x12, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x44, 0x48,
11459 0x46, 0x09, 0x04, 0x1d,
11460 0xfe, 0x1a, 0x13, 0x0a, 0x40, 0x01, 0x0e, 0x47, 0xfe, 0x41, 0x58, 0x0a,
11461 0x99, 0x01, 0x0e, 0xfe,
11462 0x49, 0x54, 0x8e, 0xfe, 0x2a, 0x0d, 0x02, 0xfe, 0x2a, 0x03, 0x0a, 0x51,
11463 0xfe, 0xee, 0x14, 0xee,
11464 0x3e, 0x1d, 0xfe, 0xce, 0x45, 0x34, 0x3c, 0xfe, 0xce, 0x47, 0xfe, 0xad,
11465 0x13, 0x02, 0x29, 0x1e,
11466 0x20, 0x07, 0x10, 0xfe, 0x9e, 0x12, 0x23, 0x12, 0x4d, 0x12, 0x94, 0x12,
11467 0xce, 0x1e, 0x2d, 0x47,
11468 0x37, 0x2d, 0xb1, 0xe0, 0xfe, 0xbc, 0xf0, 0xfe, 0xec, 0x0d, 0x13, 0x06,
11469 0x12, 0x4d, 0x01, 0xfe,
11470 0xe2, 0x15, 0x05, 0xfe, 0x38, 0x01, 0x31, 0xfe, 0x3a, 0x01, 0x77, 0xfe,
11471 0xf0, 0x0d, 0xfe, 0x02,
11472 0xec, 0xce, 0x62, 0x00, 0x5d, 0xfe, 0x04, 0xec, 0x20, 0x46, 0xfe, 0x05,
11473 0xf6, 0xfe, 0x34, 0x01,
11474 0x01, 0xfe, 0x52, 0x16, 0xfb, 0xfe, 0x48, 0xf4, 0x0d, 0xfe, 0x18, 0x13,
11475 0xaf, 0xfe, 0x02, 0xea,
11476 0xce, 0x62, 0x7a, 0xfe, 0xc5, 0x13, 0x14, 0x1b, 0x37, 0x95, 0xa9, 0x5c,
11477 0x05, 0xfe, 0x38, 0x01,
11478 0x1c, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x05, 0xfe, 0x3a, 0x01,
11479 0x0c, 0xfe, 0x62, 0x01,
11480 0x3d, 0x12, 0x20, 0x24, 0x06, 0x12, 0x2d, 0x11, 0x2d, 0x8a, 0x13, 0x06,
11481 0x03, 0x23, 0x03, 0x1e,
11482 0x4d, 0xfe, 0xf7, 0x12, 0x1e, 0x94, 0xac, 0x12, 0x94, 0x07, 0x7a, 0xfe,
11483 0x71, 0x13, 0xfe, 0x24,
11484 0x1c, 0x14, 0x1a, 0x37, 0x95, 0xa9, 0xfe, 0xd9, 0x10, 0xb6, 0xfe, 0x03,
11485 0xdc, 0xfe, 0x73, 0x57,
11486 0xfe, 0x80, 0x5d, 0x03, 0xb6, 0xfe, 0x03, 0xdc, 0xfe, 0x5b, 0x57, 0xfe,
11487 0x80, 0x5d, 0x03, 0xfe,
11488 0x03, 0x57, 0xb6, 0x23, 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0xb6,
11489 0x75, 0x03, 0x09, 0x04,
11490 0x4c, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13,
11491 0xfe, 0x1e, 0x80, 0xe1,
11492 0xfe, 0x1d, 0x80, 0xa4, 0xfe, 0x0c, 0x90, 0xfe, 0x0e, 0x13, 0xfe, 0x0e,
11493 0x90, 0xa3, 0xfe, 0x3c,
11494 0x90, 0xfe, 0x30, 0xf4, 0x0b, 0xfe, 0x3c, 0x50, 0xa0, 0x01, 0xfe, 0x82,
11495 0x16, 0x2f, 0x07, 0x2d,
11496 0xe0, 0x01, 0xfe, 0xbc, 0x15, 0x09, 0x04, 0x1d, 0x45, 0x01, 0xe7, 0x01,
11497 0xe8, 0x11, 0xfe, 0xe9,
11498 0x00, 0x09, 0x04, 0x4c, 0xfe, 0x2c, 0x13, 0x01, 0xfe, 0x14, 0x16, 0xfe,
11499 0x1e, 0x1c, 0xfe, 0x14,
11500 0x90, 0xfe, 0x96, 0x90, 0x0c, 0xfe, 0x64, 0x01, 0x18, 0xfe, 0x66, 0x01,
11501 0x09, 0x04, 0x4f, 0xfe,
11502 0x12, 0x12, 0xfe, 0x03, 0x80, 0x74, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80,
11503 0x40, 0x12, 0x20, 0x63,
11504 0x27, 0x11, 0xc8, 0x59, 0x1e, 0x20, 0xed, 0x76, 0x20, 0x03, 0xfe, 0x08,
11505 0x1c, 0x05, 0xfe, 0xac,
11506 0x00, 0xfe, 0x06, 0x58, 0x05, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x05,
11507 0xfe, 0xb0, 0x00, 0xfe,
11508 0x08, 0x58, 0x05, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
11509 0x24, 0x69, 0x12, 0xc9,
11510 0x23, 0x0c, 0x50, 0x0c, 0x3f, 0x13, 0x40, 0x48, 0x5f, 0x17, 0x1d, 0xfe,
11511 0x90, 0x4d, 0xfe, 0x91,
11512 0x54, 0x21, 0xfe, 0x08, 0x0f, 0x3e, 0x10, 0x13, 0x42, 0x48, 0x17, 0x4c,
11513 0xfe, 0x90, 0x4d, 0xfe,
11514 0x91, 0x54, 0x21, 0xfe, 0x1e, 0x0f, 0x24, 0x10, 0x12, 0x20, 0x78, 0x2c,
11515 0x46, 0x1e, 0x20, 0xed,
11516 0x76, 0x20, 0x11, 0xc8, 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x32, 0x0f, 0xea,
11517 0x70, 0xfe, 0x14, 0x1c,
11518 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x03, 0x3c, 0xfe, 0x0c, 0x14, 0xee,
11519 0xfe, 0x07, 0xe6, 0x1d,
11520 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x86, 0x78, 0x2c, 0x46,
11521 0xfa, 0xef, 0xfe, 0x42,
11522 0x13, 0x2f, 0x07, 0x2d, 0xfe, 0x34, 0x13, 0x0a, 0x42, 0x01, 0x0e, 0xb0,
11523 0xfe, 0x36, 0x12, 0xf0,
11524 0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13,
11525 0x3d, 0x75, 0x07, 0x10,
11526 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x6f, 0xfe, 0x0e,
11527 0x10, 0x07, 0x7e, 0x45,
11528 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x6c, 0x0f, 0x03, 0xfe, 0x44, 0x58, 0x74,
11529 0xfe, 0x01, 0xec, 0x97,
11530 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1b, 0x76,
11531 0x27, 0x01, 0xda, 0xfe,
11532 0xdd, 0x10, 0x2a, 0xbc, 0x7d, 0xbd, 0x7f, 0x30, 0x2e, 0xd5, 0x07, 0x1b,
11533 0xfe, 0x48, 0x12, 0x07,
11534 0x0b, 0xfe, 0x56, 0x12, 0x07, 0x1a, 0xfe, 0x30, 0x12, 0x07, 0xc2, 0x16,
11535 0xfe, 0x3e, 0x11, 0x07,
11536 0xfe, 0x23, 0x00, 0x16, 0xfe, 0x4a, 0x11, 0x07, 0x06, 0x16, 0xfe, 0xa8,
11537 0x11, 0x07, 0x19, 0xfe,
11538 0x12, 0x12, 0x07, 0x00, 0x16, 0x22, 0x14, 0xc2, 0x01, 0x33, 0x9f, 0x2b,
11539 0x01, 0x08, 0x8c, 0x43,
11540 0x03, 0x2b, 0xfe, 0x62, 0x08, 0x0a, 0xca, 0x01, 0xfe, 0x32, 0x0e, 0x11,
11541 0x7e, 0x02, 0x29, 0x2b,
11542 0x2f, 0x07, 0x9b, 0xfe, 0xd9, 0x13, 0x79, 0x39, 0x68, 0x3a, 0x77, 0xfe,
11543 0xfc, 0x10, 0x09, 0x04,
11544 0x6a, 0xfe, 0x72, 0x12, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x8e, 0xfe,
11545 0xc6, 0x10, 0x1e, 0x58,
11546 0xfe, 0x26, 0x13, 0x05, 0x7b, 0x31, 0x7c, 0x77, 0xfe, 0x82, 0x0c, 0x0c,
11547 0x54, 0x18, 0x55, 0x23,
11548 0x0c, 0x7b, 0x0c, 0x7c, 0x01, 0xa8, 0x24, 0x69, 0x73, 0x12, 0x58, 0x01,
11549 0xa5, 0xc0, 0x38, 0xc1,
11550 0x4e, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x38, 0xfe,
11551 0x05, 0xfa, 0x4e, 0xfe,
11552 0x91, 0x10, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56,
11553 0x0c, 0x56, 0x18, 0x57,
11554 0x83, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x05, 0x52, 0x31, 0x53, 0xfe,
11555 0x00, 0x56, 0xfe, 0xa1,
11556 0x56, 0x0c, 0x52, 0x18, 0x53, 0x09, 0x04, 0x6a, 0xfe, 0x1e, 0x12, 0x1e,
11557 0x58, 0xfe, 0x1f, 0x40,
11558 0x05, 0x54, 0x31, 0x55, 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x05, 0x56,
11559 0x31, 0x57, 0xfe, 0x44,
11560 0x50, 0xfe, 0xc6, 0x50, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x08, 0x50, 0xfe,
11561 0x8a, 0x50, 0x05, 0x39,
11562 0x31, 0x3a, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x5c, 0x24, 0x06,
11563 0x12, 0xcd, 0x02, 0x5b,
11564 0x2b, 0x01, 0x08, 0x1f, 0x44, 0x30, 0x2e, 0xd5, 0x07, 0x06, 0x21, 0x44,
11565 0x2f, 0x07, 0x9b, 0x21,
11566 0x5b, 0x01, 0x6e, 0x1c, 0x3d, 0x16, 0x44, 0x09, 0x04, 0x0b, 0xe2, 0x79,
11567 0x39, 0x68, 0x3a, 0xfe,
11568 0x0a, 0x55, 0x34, 0xfe, 0x8b, 0x55, 0xbe, 0x39, 0xbf, 0x3a, 0xfe, 0x0c,
11569 0x51, 0xfe, 0x8e, 0x51,
11570 0x02, 0x5b, 0xfe, 0x19, 0x81, 0xaf, 0xfe, 0x19, 0x41, 0x02, 0x5b, 0x2b,
11571 0x01, 0x08, 0x25, 0x32,
11572 0x1f, 0xa2, 0x30, 0x2e, 0xd8, 0x4b, 0x1a, 0xfe, 0xa6, 0x12, 0x4b, 0x0b,
11573 0x3b, 0x02, 0x44, 0x01,
11574 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, 0xd6, 0x07, 0x1a, 0x21, 0x44,
11575 0x01, 0x08, 0x1f, 0xa2,
11576 0x30, 0x2e, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x60, 0x05, 0xfe, 0x9c,
11577 0x00, 0x28, 0x84, 0x49,
11578 0x04, 0x19, 0x34, 0x9f, 0xfe, 0xbb, 0x45, 0x4b, 0x00, 0x45, 0x3e, 0x06,
11579 0x78, 0x3d, 0xfe, 0xda,
11580 0x14, 0x01, 0x6e, 0x87, 0xfe, 0x4b, 0x45, 0xe2, 0x2f, 0x07, 0x9a, 0xe1,
11581 0x05, 0xc6, 0x28, 0x84,
11582 0x05, 0x3f, 0x28, 0x34, 0x5e, 0x02, 0x5b, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8,
11583 0x14, 0xfe, 0x03, 0x17,
11584 0x05, 0x50, 0xb4, 0x0c, 0x50, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01,
11585 0xfe, 0xaa, 0x14, 0x02,
11586 0x5c, 0x01, 0x08, 0x25, 0x32, 0x1f, 0x44, 0x30, 0x2e, 0xd6, 0x07, 0x06,
11587 0x21, 0x44, 0x01, 0xfe,
11588 0x8e, 0x13, 0xfe, 0x42, 0x58, 0xfe, 0x82, 0x14, 0xfe, 0xa4, 0x14, 0x87,
11589 0xfe, 0x4a, 0xf4, 0x0b,
11590 0x16, 0x44, 0xfe, 0x4a, 0xf4, 0x06, 0xfe, 0x0c, 0x12, 0x2f, 0x07, 0x9a,
11591 0x85, 0x02, 0x5b, 0x05,
11592 0x3f, 0xb4, 0x0c, 0x3f, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe,
11593 0xd8, 0x14, 0x02, 0x5c,
11594 0x13, 0x06, 0x65, 0xfe, 0xca, 0x12, 0x26, 0xfe, 0xe0, 0x12, 0x72, 0xf1,
11595 0x01, 0x08, 0x23, 0x72,
11596 0x03, 0x8f, 0xfe, 0xdc, 0x12, 0x25, 0xfe, 0xdc, 0x12, 0x1f, 0xfe, 0xca,
11597 0x12, 0x5e, 0x2b, 0x01,
11598 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
11599 0x1c, 0xfe, 0xff, 0x7f,
11600 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00,
11601 0x57, 0x48, 0x8b, 0x1c,
11602 0x3d, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02,
11603 0x00, 0x57, 0x48, 0x8b,
11604 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0xfe, 0x0b, 0x58,
11605 0x03, 0x0a, 0x50, 0x01,
11606 0x82, 0x0a, 0x3f, 0x01, 0x82, 0x03, 0xfc, 0x1c, 0x10, 0xff, 0x03, 0x00,
11607 0x54, 0xfe, 0x00, 0xf4,
11608 0x19, 0x48, 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe,
11609 0x03, 0x7c, 0x63, 0x27,
11610 0x0c, 0x52, 0x18, 0x53, 0xbe, 0x56, 0xbf, 0x57, 0x03, 0xfe, 0x62, 0x08,
11611 0xfe, 0x82, 0x4a, 0xfe,
11612 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x74, 0x03, 0x01, 0xfe, 0x14, 0x18, 0xfe,
11613 0x42, 0x48, 0x5f, 0x60,
11614 0x89, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14, 0x30, 0x2e, 0xd8, 0x01, 0x08,
11615 0x1f, 0xfe, 0xa2, 0x14,
11616 0x30, 0x2e, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x05, 0xc6, 0x28, 0xfe,
11617 0xcc, 0x12, 0x49, 0x04,
11618 0x1b, 0xfe, 0xc4, 0x13, 0x23, 0x62, 0x1b, 0xe2, 0x4b, 0xc3, 0x64, 0xfe,
11619 0xe8, 0x13, 0x3b, 0x13,
11620 0x06, 0x17, 0xc3, 0x78, 0xdb, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55,
11621 0xa1, 0xff, 0x02, 0x83,
11622 0x55, 0x62, 0x1a, 0xa4, 0xbb, 0xfe, 0x30, 0x00, 0x8e, 0xe4, 0x17, 0x2c,
11623 0x13, 0x06, 0xfe, 0x56,
11624 0x10, 0x62, 0x0b, 0xe1, 0xbb, 0xfe, 0x64, 0x00, 0x8e, 0xe4, 0x0a, 0xfe,
11625 0x64, 0x00, 0x17, 0x93,
11626 0x13, 0x06, 0xfe, 0x28, 0x10, 0x62, 0x06, 0xfe, 0x60, 0x13, 0xbb, 0xfe,
11627 0xc8, 0x00, 0x8e, 0xe4,
11628 0x0a, 0xfe, 0xc8, 0x00, 0x17, 0x4d, 0x13, 0x06, 0x83, 0xbb, 0xfe, 0x90,
11629 0x01, 0xba, 0xfe, 0x4e,
11630 0x14, 0x89, 0xfe, 0x12, 0x10, 0xfe, 0x43, 0xf4, 0x94, 0xfe, 0x56, 0xf0,
11631 0xfe, 0x60, 0x14, 0xfe,
11632 0x04, 0xf4, 0x6c, 0xfe, 0x43, 0xf4, 0x93, 0xfe, 0xf3, 0x10, 0xf9, 0x01,
11633 0xfe, 0x22, 0x13, 0x1c,
11634 0x3d, 0xfe, 0x10, 0x13, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x69, 0xba,
11635 0xfe, 0x9c, 0x14, 0xb7,
11636 0x69, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x19, 0xba,
11637 0xfe, 0x9c, 0x14, 0xb7,
11638 0x19, 0x83, 0x60, 0x23, 0xfe, 0x4d, 0xf4, 0x00, 0xdf, 0x89, 0x13, 0x06,
11639 0xfe, 0xb4, 0x56, 0xfe,
11640 0xc3, 0x58, 0x03, 0x60, 0x13, 0x0b, 0x03, 0x15, 0x06, 0x01, 0x08, 0x26,
11641 0xe5, 0x15, 0x0b, 0x01,
11642 0x08, 0x26, 0xe5, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xe5, 0x72, 0xfe, 0x89,
11643 0x49, 0x01, 0x08, 0x03,
11644 0x15, 0x06, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xa6,
11645 0x15, 0x06, 0x01, 0x08,
11646 0x26, 0xa6, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x26, 0xa6, 0x72, 0xfe, 0x89,
11647 0x4a, 0x01, 0x08, 0x03,
11648 0x60, 0x03, 0x1e, 0xcc, 0x07, 0x06, 0xfe, 0x44, 0x13, 0xad, 0x12, 0xcc,
11649 0xfe, 0x49, 0xf4, 0x00,
11650 0x3b, 0x72, 0x9f, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01,
11651 0x08, 0x2f, 0x07, 0xfe,
11652 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0x5a, 0x15, 0x23, 0x12, 0xcd,
11653 0x01, 0x43, 0x1e, 0xcd,
11654 0x07, 0x06, 0x45, 0x09, 0x4a, 0x06, 0x35, 0x03, 0x0a, 0x42, 0x01, 0x0e,
11655 0xed, 0x88, 0x07, 0x10,
11656 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a,
11657 0x80, 0x01, 0x0e, 0x88,
11658 0xfe, 0x80, 0xe7, 0x10, 0x07, 0x10, 0x84, 0xfe, 0x45, 0x58, 0x01, 0xe3,
11659 0x88, 0x03, 0x0a, 0x42,
11660 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x42, 0x01, 0x0e,
11661 0xfe, 0x80, 0x80, 0xf2,
11662 0xfe, 0x49, 0xe4, 0x10, 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x0a, 0x51,
11663 0x01, 0x82, 0x03, 0x17,
11664 0x10, 0x71, 0x66, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde,
11665 0xfe, 0x24, 0x1c, 0xfe,
11666 0x1d, 0xf7, 0x1d, 0x90, 0xfe, 0xf6, 0x15, 0x01, 0xfe, 0xfc, 0x16, 0xe0,
11667 0x91, 0x1d, 0x66, 0xfe,
11668 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x03, 0xae, 0x21, 0xfe, 0xe6, 0x15, 0xfe,
11669 0xda, 0x10, 0x17, 0x10,
11670 0x71, 0x05, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58,
11671 0x05, 0xfe, 0x66, 0x01,
11672 0xfe, 0x19, 0x58, 0x91, 0x19, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x06,
11673 0xfe, 0x3c, 0x50, 0x66,
11674 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x90, 0xfe,
11675 0x40, 0x16, 0xfe, 0xb6,
11676 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x18, 0x16, 0xfe, 0x9c, 0x10, 0x17,
11677 0x10, 0x71, 0xfe, 0x83,
11678 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x38, 0x90,
11679 0xfe, 0x62, 0x16, 0xfe,
11680 0x94, 0x14, 0xfe, 0x10, 0x13, 0x91, 0x38, 0x66, 0x1b, 0xfe, 0xaf, 0x19,
11681 0xfe, 0x98, 0xe7, 0x00,
11682 0x03, 0xae, 0x21, 0xfe, 0x56, 0x16, 0xfe, 0x6c, 0x10, 0x17, 0x10, 0x71,
11683 0xfe, 0x30, 0xbc, 0xfe,
11684 0xb2, 0xbc, 0x91, 0xc5, 0x66, 0x1b, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
11685 0xc5, 0x90, 0xfe, 0x9a,
11686 0x16, 0xfe, 0x5c, 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x86, 0x16, 0xfe,
11687 0x42, 0x10, 0xfe, 0x02,
11688 0xf6, 0x10, 0x71, 0xfe, 0x18, 0xfe, 0x54, 0xfe, 0x19, 0xfe, 0x55, 0xfc,
11689 0xfe, 0x1d, 0xf7, 0x4f,
11690 0x90, 0xfe, 0xc0, 0x16, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0x91, 0x4f,
11691 0x47, 0xfe, 0x83, 0x58,
11692 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11,
11693 0xfe, 0xdd, 0x00, 0x63,
11694 0x27, 0x03, 0x63, 0x27, 0xfe, 0x12, 0x45, 0x21, 0xfe, 0xb0, 0x16, 0x14,
11695 0x06, 0x37, 0x95, 0xa9,
11696 0x02, 0x29, 0xfe, 0x39, 0xf0, 0xfe, 0x04, 0x17, 0x23, 0x03, 0xfe, 0x7e,
11697 0x18, 0x1c, 0x1a, 0x5d,
11698 0x13, 0x0d, 0x03, 0x71, 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0xef, 0x12, 0xfe,
11699 0xe1, 0x10, 0x78, 0x2c,
11700 0x46, 0x2f, 0x07, 0x2d, 0xfe, 0x3c, 0x13, 0xfe, 0x82, 0x14, 0xfe, 0x42,
11701 0x13, 0x3c, 0x8a, 0x0a,
11702 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x3e, 0x12, 0xf0, 0xfe, 0x45, 0x48, 0x01,
11703 0xe3, 0xfe, 0x00, 0xcc,
11704 0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10, 0xa3, 0x0a, 0x80, 0x01,
11705 0x0e, 0xf2, 0x01, 0x6f,
11706 0xfe, 0x16, 0x10, 0x07, 0x7e, 0x85, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12,
11707 0xf6, 0xfe, 0xd6, 0xf0,
11708 0xfe, 0x24, 0x17, 0x17, 0x0b, 0x03, 0xfe, 0x9c, 0xe7, 0x0b, 0x0f, 0xfe,
11709 0x15, 0x00, 0x59, 0x76,
11710 0x27, 0x01, 0xda, 0x17, 0x06, 0x03, 0x3c, 0x8a, 0x09, 0x4a, 0x1d, 0x35,
11711 0x11, 0x2d, 0x01, 0x6f,
11712 0x17, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x79, 0xc7, 0x68,
11713 0xc8, 0xfe, 0x48, 0x55,
11714 0x34, 0xfe, 0xc9, 0x55, 0x03, 0x1e, 0x98, 0x73, 0x12, 0x98, 0x03, 0x0a,
11715 0x99, 0x01, 0x0e, 0xf0,
11716 0x0a, 0x40, 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x16, 0xfe, 0xf0, 0x17, 0x73,
11717 0x75, 0x03, 0x0a, 0x42,
11718 0x01, 0x0e, 0x07, 0x10, 0x45, 0x0a, 0x51, 0x01, 0x9e, 0x0a, 0x40, 0x01,
11719 0x0e, 0x73, 0x75, 0x03,
11720 0xfe, 0x4e, 0xe4, 0x1a, 0x64, 0xfe, 0x24, 0x18, 0x05, 0xfe, 0x90, 0x00,
11721 0xfe, 0x3a, 0x45, 0x5b,
11722 0xfe, 0x4e, 0xe4, 0xc2, 0x64, 0xfe, 0x36, 0x18, 0x05, 0xfe, 0x92, 0x00,
11723 0xfe, 0x02, 0xe6, 0x1b,
11724 0xdc, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x64, 0xfe, 0x48, 0x18, 0x05,
11725 0xfe, 0x94, 0x00, 0xfe,
11726 0x02, 0xe6, 0x19, 0xfe, 0x08, 0x10, 0x05, 0xfe, 0x96, 0x00, 0xfe, 0x02,
11727 0xe6, 0x2c, 0xfe, 0x4e,
11728 0x45, 0xfe, 0x0c, 0x12, 0xaf, 0xff, 0x04, 0x68, 0x54, 0xde, 0x1c, 0x69,
11729 0x03, 0x07, 0x7a, 0xfe,
11730 0x5a, 0xf0, 0xfe, 0x74, 0x18, 0x24, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
11731 0x07, 0x1b, 0xfe, 0x5a,
11732 0xf0, 0xfe, 0x82, 0x18, 0x24, 0xc3, 0xfe, 0x26, 0x10, 0x07, 0x1a, 0x5d,
11733 0x24, 0x2c, 0xdc, 0x07,
11734 0x0b, 0x5d, 0x24, 0x93, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x5d, 0x24, 0x4d,
11735 0x9f, 0xad, 0x03, 0x14,
11736 0xfe, 0x09, 0x00, 0x01, 0x33, 0xfe, 0x04, 0xfe, 0x7d, 0x05, 0x7f, 0xf9,
11737 0x03, 0x25, 0xfe, 0xca,
11738 0x18, 0xfe, 0x14, 0xf0, 0x08, 0x65, 0xfe, 0xc6, 0x18, 0x03, 0xff, 0x1a,
11739 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070011740};
11741
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011742static unsigned short _adv_asc3550_size = sizeof(_adv_asc3550_buf); /* 0x13AD */
11743static ADV_DCNT _adv_asc3550_chksum = 0x04D52DDDUL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011744
11745/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011746static unsigned char _adv_asc38C0800_buf[] = {
11747 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x16, 0x18, 0xe4,
11748 0x01, 0x00, 0x48, 0xe4,
11749 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0xce, 0x19, 0x00, 0xfa, 0xff, 0xff,
11750 0x1c, 0x0f, 0x00, 0xf6,
11751 0x9e, 0xe7, 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x01, 0xfa, 0x01, 0xe6,
11752 0x09, 0xe7, 0x55, 0xf0,
11753 0x01, 0xf6, 0x03, 0x00, 0x04, 0x00, 0x10, 0x00, 0x1e, 0xf0, 0x85, 0xf0,
11754 0x18, 0xf4, 0x08, 0x00,
11755 0xbc, 0x00, 0x38, 0x54, 0x00, 0xec, 0xd5, 0xf0, 0x82, 0x0d, 0x00, 0xe6,
11756 0x86, 0xf0, 0xb1, 0xf0,
11757 0x98, 0x57, 0x01, 0xfc, 0xb4, 0x00, 0xd4, 0x01, 0x0c, 0x1c, 0x3e, 0x1c,
11758 0x3c, 0x00, 0xbb, 0x00,
11759 0x00, 0x10, 0xba, 0x19, 0x02, 0x80, 0x32, 0xf0, 0x7c, 0x0d, 0x02, 0x13,
11760 0xba, 0x13, 0x18, 0x40,
11761 0x00, 0x57, 0x01, 0xea, 0x02, 0xfc, 0x03, 0xfc, 0x3e, 0x00, 0x6c, 0x01,
11762 0x6e, 0x01, 0x74, 0x01,
11763 0x76, 0x01, 0xb9, 0x54, 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00,
11764 0xc0, 0x00, 0x01, 0x01,
11765 0x3e, 0x01, 0x7a, 0x01, 0xca, 0x08, 0xce, 0x10, 0x16, 0x11, 0x04, 0x12,
11766 0x08, 0x12, 0x02, 0x4a,
11767 0xbb, 0x55, 0x3c, 0x56, 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4,
11768 0x5d, 0xf0, 0x02, 0xfa,
11769 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01,
11770 0x68, 0x01, 0x6a, 0x01,
11771 0x70, 0x01, 0x72, 0x01, 0x78, 0x01, 0x7c, 0x01, 0x62, 0x0a, 0x86, 0x0d,
11772 0x06, 0x13, 0x4c, 0x1c,
11773 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x0c, 0x00,
11774 0x0f, 0x00, 0x47, 0x00,
11775 0xbe, 0x00, 0x00, 0x01, 0x20, 0x11, 0x5c, 0x16, 0x32, 0x1c, 0x38, 0x1c,
11776 0x4e, 0x1c, 0x10, 0x44,
11777 0x00, 0x4c, 0x04, 0xea, 0x5c, 0xf0, 0xa7, 0xf0, 0x04, 0xf6, 0x03, 0xfa,
11778 0x05, 0x00, 0x34, 0x00,
11779 0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x4a, 0x0b,
11780 0x42, 0x0c, 0x12, 0x0f,
11781 0x0c, 0x10, 0x22, 0x11, 0x0a, 0x12, 0x04, 0x13, 0x30, 0x1c, 0x02, 0x48,
11782 0x00, 0x4e, 0x42, 0x54,
11783 0x44, 0x55, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
11784 0x59, 0xf0, 0xb8, 0xf0,
11785 0x4b, 0xf4, 0x06, 0xf7, 0x0e, 0xf7, 0x04, 0xfc, 0x05, 0xfc, 0x06, 0x00,
11786 0x19, 0x00, 0x33, 0x00,
11787 0x9b, 0x00, 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00,
11788 0xe7, 0x00, 0xe2, 0x03,
11789 0x08, 0x0f, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, 0x0a, 0x13, 0x0c, 0x13,
11790 0x12, 0x13, 0x24, 0x14,
11791 0x34, 0x14, 0x04, 0x16, 0x08, 0x16, 0xa4, 0x17, 0x20, 0x1c, 0x34, 0x1c,
11792 0x36, 0x1c, 0x08, 0x44,
11793 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54,
11794 0x3a, 0x55, 0x83, 0x55,
11795 0xe5, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0,
11796 0x0c, 0xf0, 0x04, 0xf8,
11797 0x05, 0xf8, 0x07, 0x00, 0x0a, 0x00, 0x1c, 0x00, 0x1e, 0x00, 0x9e, 0x00,
11798 0xa8, 0x00, 0xaa, 0x00,
11799 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7e, 0x01,
11800 0xc4, 0x01, 0xc6, 0x01,
11801 0x80, 0x02, 0x5e, 0x03, 0xee, 0x04, 0x9a, 0x06, 0xf8, 0x07, 0x62, 0x08,
11802 0x68, 0x08, 0x69, 0x08,
11803 0xd6, 0x08, 0xe9, 0x09, 0xfa, 0x0b, 0x2e, 0x0f, 0x12, 0x10, 0x1a, 0x10,
11804 0xed, 0x10, 0xf1, 0x10,
11805 0x2a, 0x11, 0x06, 0x12, 0x0c, 0x12, 0x3e, 0x12, 0x10, 0x13, 0x16, 0x13,
11806 0x1e, 0x13, 0x46, 0x14,
11807 0x76, 0x14, 0x82, 0x14, 0x36, 0x15, 0xca, 0x15, 0x6b, 0x18, 0xbe, 0x18,
11808 0xca, 0x18, 0xe6, 0x19,
11809 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0xfe, 0x9c,
11810 0xf0, 0x2b, 0x02, 0xfe,
11811 0xac, 0x0d, 0xff, 0x10, 0x00, 0x00, 0xd7, 0xfe, 0xe8, 0x19, 0x00, 0xd6,
11812 0xfe, 0x84, 0x01, 0xff,
11813 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
11814 0x00, 0xfe, 0x57, 0x24,
11815 0x00, 0xfe, 0x4c, 0x00, 0x5b, 0xff, 0x04, 0x00, 0x00, 0x11, 0xff, 0x09,
11816 0x00, 0x00, 0xff, 0x08,
11817 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
11818 0xff, 0xff, 0xff, 0x11,
11819 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
11820 0xfe, 0x04, 0xf7, 0xd6,
11821 0x2c, 0x99, 0x0a, 0x01, 0xfe, 0xc2, 0x0f, 0xfe, 0x04, 0xf7, 0xd6, 0x99,
11822 0x0a, 0x42, 0x2c, 0xfe,
11823 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x91, 0xf0,
11824 0xfe, 0xf4, 0x01, 0xfe,
11825 0x90, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, 0x8f, 0xf0, 0xa7, 0x03, 0x5d, 0x4d,
11826 0x02, 0xfe, 0xc8, 0x0d,
11827 0x01, 0xfe, 0x38, 0x0e, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
11828 0x1c, 0x03, 0xfe, 0xa6,
11829 0x00, 0xfe, 0xd3, 0x12, 0x41, 0x14, 0xfe, 0xa6, 0x00, 0xc2, 0xfe, 0x48,
11830 0xf0, 0xfe, 0x8a, 0x02,
11831 0xfe, 0x49, 0xf0, 0xfe, 0xa4, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc2, 0x02,
11832 0xfe, 0x46, 0xf0, 0xfe,
11833 0x54, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x5a, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
11834 0x48, 0x02, 0xfe, 0x44,
11835 0xf0, 0xfe, 0x4c, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x50, 0x02, 0x18, 0x0a,
11836 0xaa, 0x18, 0x06, 0x14,
11837 0xa1, 0x02, 0x2b, 0xfe, 0x00, 0x1c, 0xe7, 0xfe, 0x02, 0x1c, 0xe6, 0xfe,
11838 0x1e, 0x1c, 0xfe, 0xe9,
11839 0x10, 0x01, 0xfe, 0x18, 0x18, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xce,
11840 0x09, 0x70, 0x01, 0xa8,
11841 0x02, 0x2b, 0x15, 0x59, 0x39, 0xa2, 0x01, 0xfe, 0x58, 0x10, 0x09, 0x70,
11842 0x01, 0x87, 0xfe, 0xbd,
11843 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
11844 0x58, 0x1c, 0x18, 0x06,
11845 0x14, 0xa1, 0x2c, 0x1c, 0x2b, 0xfe, 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0x23,
11846 0xfe, 0x98, 0x02, 0xfe,
11847 0x5a, 0x1c, 0xf8, 0xfe, 0x14, 0x1c, 0x15, 0xfe, 0x30, 0x00, 0x39, 0xa2,
11848 0x01, 0xfe, 0x48, 0x10,
11849 0x18, 0x06, 0x14, 0xa1, 0x02, 0xd7, 0x22, 0x20, 0x07, 0x11, 0x35, 0xfe,
11850 0x69, 0x10, 0x18, 0x06,
11851 0x14, 0xa1, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0x43, 0x13, 0x20, 0xfe, 0x05,
11852 0xf6, 0xce, 0x01, 0xfe,
11853 0x4a, 0x17, 0x08, 0x54, 0x58, 0x37, 0x12, 0x2f, 0x42, 0x92, 0x01, 0xfe,
11854 0x82, 0x16, 0x02, 0x2b,
11855 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x01, 0x73, 0xfe, 0x18, 0x10,
11856 0xfe, 0x41, 0x58, 0x09,
11857 0xa4, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x6b, 0xfe, 0x10, 0x03, 0x01, 0xfe,
11858 0x82, 0x16, 0x02, 0x2b,
11859 0x2c, 0x4f, 0xfe, 0x02, 0xe8, 0x2a, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43,
11860 0xfe, 0x77, 0x57, 0xfe,
11861 0x27, 0xf0, 0xfe, 0xe0, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xa7,
11862 0xfe, 0x40, 0x1c, 0x1c,
11863 0xd9, 0xfe, 0x26, 0xf0, 0xfe, 0x5a, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x48,
11864 0x03, 0xfe, 0x11, 0xf0,
11865 0xa7, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x68, 0x03, 0xf9, 0x10,
11866 0xfe, 0x11, 0x00, 0x02,
11867 0x65, 0x2c, 0xfe, 0x48, 0x1c, 0xf9, 0x08, 0x05, 0x1b, 0xfe, 0x18, 0x13,
11868 0x21, 0x22, 0xa3, 0xb7,
11869 0x13, 0xa3, 0x09, 0x46, 0x01, 0x0e, 0xb7, 0x78, 0x01, 0xfe, 0xb4, 0x16,
11870 0x12, 0xd1, 0x1c, 0xd9,
11871 0xfe, 0x01, 0xf0, 0xd9, 0xfe, 0x82, 0xf0, 0xfe, 0x96, 0x03, 0xfa, 0x12,
11872 0xfe, 0xe4, 0x00, 0x27,
11873 0xfe, 0xa8, 0x03, 0x1c, 0x34, 0x1d, 0xfe, 0xb8, 0x03, 0x01, 0x4b, 0xfe,
11874 0x06, 0xf0, 0xfe, 0xc8,
11875 0x03, 0x95, 0x86, 0xfe, 0x0a, 0xf0, 0xfe, 0x8a, 0x06, 0x02, 0x24, 0x03,
11876 0x70, 0x28, 0x17, 0xfe,
11877 0xfa, 0x04, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, 0xd8,
11878 0xf9, 0x2c, 0x99, 0x19,
11879 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c,
11880 0x74, 0x01, 0xaf, 0x8c,
11881 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x17, 0xda, 0x09, 0xd1, 0x01, 0x0e,
11882 0x8d, 0x51, 0x64, 0x79,
11883 0x2a, 0x03, 0x70, 0x28, 0xfe, 0x10, 0x12, 0x15, 0x6d, 0x01, 0x36, 0x7b,
11884 0xfe, 0x6a, 0x02, 0x02,
11885 0xd8, 0xc7, 0x81, 0xc8, 0x83, 0x1c, 0x24, 0x27, 0xfe, 0x40, 0x04, 0x1d,
11886 0xfe, 0x3c, 0x04, 0x3b,
11887 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e, 0x12, 0x2d, 0xff, 0x02,
11888 0x00, 0x10, 0x01, 0x0b,
11889 0x1d, 0xfe, 0xe4, 0x04, 0x2d, 0x01, 0x0b, 0x1d, 0x24, 0x33, 0x31, 0xde,
11890 0xfe, 0x4c, 0x44, 0xfe,
11891 0x4c, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b,
11892 0xda, 0x4f, 0x79, 0x2a,
11893 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x62, 0x13, 0x08, 0x05, 0x1b,
11894 0xfe, 0x2a, 0x13, 0x32,
11895 0x07, 0x82, 0xfe, 0x52, 0x13, 0xfe, 0x20, 0x10, 0x0f, 0x6f, 0xfe, 0x4c,
11896 0x54, 0x6b, 0xda, 0xfe,
11897 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x40, 0x13, 0x08, 0x05, 0x1b, 0xfe,
11898 0x08, 0x13, 0x32, 0x07,
11899 0x82, 0xfe, 0x30, 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x1c, 0x12, 0x15, 0x9d,
11900 0x08, 0x05, 0x06, 0x4d,
11901 0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36, 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24,
11902 0x2d, 0x12, 0xfe, 0xe6,
11903 0x00, 0xfe, 0x1c, 0x90, 0xfe, 0x40, 0x5c, 0x04, 0x15, 0x9d, 0x01, 0x36,
11904 0x02, 0x2b, 0xfe, 0x42,
11905 0x5b, 0x99, 0x19, 0xfe, 0x46, 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
11906 0xfe, 0x87, 0x80, 0xfe,
11907 0x31, 0xe4, 0x5b, 0x08, 0x05, 0x0a, 0xfe, 0x84, 0x13, 0xfe, 0x20, 0x80,
11908 0x07, 0x19, 0xfe, 0x7c,
11909 0x12, 0x53, 0x05, 0x06, 0xfe, 0x6c, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x28,
11910 0x17, 0xfe, 0x90, 0x05,
11911 0xfe, 0x31, 0xe4, 0x5a, 0x53, 0x05, 0x0a, 0xfe, 0x56, 0x13, 0x03, 0xfe,
11912 0xa0, 0x00, 0x28, 0xfe,
11913 0x4e, 0x12, 0x67, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x48, 0x05, 0x1c,
11914 0x34, 0xfe, 0x89, 0x48,
11915 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x56, 0x05, 0x26, 0xfe, 0xa8, 0x05,
11916 0x12, 0xfe, 0xe3, 0x00,
11917 0x21, 0x53, 0xfe, 0x4a, 0xf0, 0xfe, 0x76, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
11918 0x70, 0x05, 0x88, 0x25,
11919 0xfe, 0x21, 0x00, 0xab, 0x25, 0xfe, 0x22, 0x00, 0xaa, 0x25, 0x58, 0xfe,
11920 0x09, 0x48, 0xff, 0x02,
11921 0x00, 0x10, 0x27, 0xfe, 0x86, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0xfe, 0xe2,
11922 0x08, 0x53, 0x05, 0xcb,
11923 0x4d, 0x01, 0xb0, 0x25, 0x06, 0x13, 0xd3, 0x39, 0xfe, 0x27, 0x01, 0x08,
11924 0x05, 0x1b, 0xfe, 0x22,
11925 0x12, 0x41, 0x01, 0xb2, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe,
11926 0x0d, 0x00, 0x01, 0x36,
11927 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0xeb,
11928 0x03, 0x5c, 0x28, 0xfe,
11929 0x36, 0x13, 0x41, 0x01, 0xb2, 0x26, 0xfe, 0x18, 0x06, 0x09, 0x06, 0x53,
11930 0x05, 0x1f, 0xfe, 0x02,
11931 0x12, 0x50, 0x01, 0xfe, 0x9e, 0x15, 0x1d, 0xfe, 0x0e, 0x06, 0x12, 0xa5,
11932 0x01, 0x4b, 0x12, 0xfe,
11933 0xe5, 0x00, 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x03, 0xcd, 0x28, 0xfe, 0x62,
11934 0x12, 0x03, 0x45, 0x28,
11935 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x0c, 0x19, 0x01, 0xfe, 0x76, 0x19, 0xfe,
11936 0x43, 0x48, 0xc4, 0xcc,
11937 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0x8b, 0xc4,
11938 0x6e, 0x41, 0x01, 0xb2,
11939 0x26, 0xfe, 0x82, 0x06, 0x53, 0x05, 0x1a, 0xe9, 0x91, 0x09, 0x59, 0x01,
11940 0xfe, 0xcc, 0x15, 0x1d,
11941 0xfe, 0x78, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe, 0xe5, 0x00, 0x03,
11942 0x45, 0xc1, 0x0c, 0x45,
11943 0x18, 0x06, 0x01, 0xb2, 0xfa, 0x76, 0x74, 0x01, 0xaf, 0x8c, 0x12, 0xfe,
11944 0xe2, 0x00, 0x27, 0xdb,
11945 0x1c, 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0xb6, 0x06, 0x94, 0xfe, 0x6c, 0x07,
11946 0xfe, 0x06, 0xf0, 0xfe,
11947 0x74, 0x07, 0x95, 0x86, 0x02, 0x24, 0x08, 0x05, 0x0a, 0xfe, 0x2e, 0x12,
11948 0x16, 0x19, 0x01, 0x0b,
11949 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b,
11950 0xfe, 0x99, 0xa4, 0x01,
11951 0x0b, 0x16, 0x00, 0x02, 0xfe, 0x42, 0x08, 0x68, 0x05, 0x1a, 0xfe, 0x38,
11952 0x12, 0x08, 0x05, 0x1a,
11953 0xfe, 0x30, 0x13, 0x16, 0xfe, 0x1b, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01,
11954 0x0b, 0x16, 0x00, 0x01,
11955 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x06, 0x01, 0x0b, 0x16, 0x00, 0x02,
11956 0xe2, 0x6c, 0x58, 0xbe,
11957 0x50, 0xfe, 0x9a, 0x81, 0x55, 0x1b, 0x7a, 0xfe, 0x42, 0x07, 0x09, 0x1b,
11958 0xfe, 0x09, 0x6f, 0xba,
11959 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x69, 0x6d, 0x8b, 0x6c, 0x7f, 0x27,
11960 0xfe, 0x54, 0x07, 0x1c,
11961 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0x42, 0x07, 0x95, 0x86, 0x94, 0xfe, 0x6c,
11962 0x07, 0x02, 0x24, 0x01,
11963 0x4b, 0x02, 0xdb, 0x16, 0x1f, 0x02, 0xdb, 0xfe, 0x9c, 0xf7, 0xdc, 0xfe,
11964 0x2c, 0x90, 0xfe, 0xae,
11965 0x90, 0x56, 0xfe, 0xda, 0x07, 0x0c, 0x60, 0x14, 0x61, 0x08, 0x54, 0x5a,
11966 0x37, 0x22, 0x20, 0x07,
11967 0x11, 0xfe, 0x0e, 0x12, 0x8d, 0xfe, 0x80, 0x80, 0x39, 0x20, 0x6a, 0x2a,
11968 0xfe, 0x06, 0x10, 0xfe,
11969 0x83, 0xe7, 0xfe, 0x48, 0x00, 0xab, 0xfe, 0x03, 0x40, 0x08, 0x54, 0x5b,
11970 0x37, 0x01, 0xb3, 0xb8,
11971 0xfe, 0x1f, 0x40, 0x13, 0x62, 0x01, 0xef, 0xfe, 0x08, 0x50, 0xfe, 0x8a,
11972 0x50, 0xfe, 0x44, 0x51,
11973 0xfe, 0xc6, 0x51, 0x88, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e,
11974 0x14, 0x5f, 0xfe, 0x0c,
11975 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x0c, 0x3d,
11976 0x14, 0x3e, 0xfe, 0x4a,
11977 0x10, 0x08, 0x05, 0x5a, 0xfe, 0x2a, 0x12, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
11978 0x90, 0x0c, 0x60, 0x14,
11979 0x61, 0x08, 0x05, 0x5b, 0x8b, 0x01, 0xb3, 0xfe, 0x1f, 0x80, 0x13, 0x62,
11980 0xfe, 0x44, 0x90, 0xfe,
11981 0xc6, 0x90, 0x0c, 0x3f, 0x14, 0x40, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90,
11982 0x0c, 0x5e, 0x14, 0x5f,
11983 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x3d, 0x14, 0x3e, 0x0c, 0x2e,
11984 0x14, 0x3c, 0x21, 0x0c,
11985 0x49, 0x0c, 0x63, 0x08, 0x54, 0x1f, 0x37, 0x2c, 0x0f, 0xfe, 0x4e, 0x11,
11986 0x27, 0xdd, 0xfe, 0x9e,
11987 0xf0, 0xfe, 0x76, 0x08, 0xbc, 0x17, 0x34, 0x2c, 0x77, 0xe6, 0xc5, 0xfe,
11988 0x9a, 0x08, 0xc6, 0xfe,
11989 0xb8, 0x08, 0x94, 0xfe, 0x8e, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x94, 0x08,
11990 0x95, 0x86, 0x02, 0x24,
11991 0x01, 0x4b, 0xfe, 0xc9, 0x10, 0x16, 0x1f, 0xfe, 0xc9, 0x10, 0x68, 0x05,
11992 0x06, 0xfe, 0x10, 0x12,
11993 0x68, 0x05, 0x0a, 0x4e, 0x08, 0x05, 0x0a, 0xfe, 0x90, 0x12, 0xfe, 0x2e,
11994 0x1c, 0x02, 0xfe, 0x18,
11995 0x0b, 0x68, 0x05, 0x06, 0x4e, 0x68, 0x05, 0x0a, 0xfe, 0x7a, 0x12, 0xfe,
11996 0x2c, 0x1c, 0xfe, 0xaa,
11997 0xf0, 0xfe, 0xd2, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0x00, 0x09, 0x02, 0xfe,
11998 0xde, 0x09, 0xfe, 0xb7,
11999 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0x02, 0xf6, 0x1a, 0x50, 0xfe, 0x70, 0x18,
12000 0xfe, 0xf1, 0x18, 0xfe,
12001 0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe,
12002 0x14, 0x59, 0xfe, 0x95,
12003 0x59, 0x1c, 0x85, 0xfe, 0x8c, 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0xac, 0xf0,
12004 0xfe, 0xf0, 0x08, 0xb5,
12005 0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x0c, 0x09, 0x02, 0xfe, 0x18,
12006 0x0b, 0xb6, 0xfe, 0xbf,
12007 0x10, 0xfe, 0x2b, 0xf0, 0x85, 0xf4, 0x1e, 0xfe, 0x00, 0xfe, 0xfe, 0x1c,
12008 0x12, 0xc2, 0xfe, 0xd2,
12009 0xf0, 0x85, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x17, 0x85, 0x03, 0xd2, 0x1e,
12010 0x06, 0x17, 0x85, 0xc5,
12011 0x4a, 0xc6, 0x4a, 0xb5, 0xb6, 0xfe, 0x89, 0x10, 0x74, 0x67, 0x2d, 0x15,
12012 0x9d, 0x01, 0x36, 0x10,
12013 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x65, 0x10, 0x80, 0x02, 0x65, 0xfe,
12014 0x98, 0x80, 0xfe, 0x19,
12015 0xe4, 0x0a, 0xfe, 0x1a, 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18,
12016 0xfe, 0x44, 0x54, 0xbe,
12017 0xfe, 0x19, 0x81, 0xfe, 0x74, 0x18, 0x8f, 0x90, 0x17, 0xfe, 0xce, 0x08,
12018 0x02, 0x4a, 0x08, 0x05,
12019 0x5a, 0xec, 0x03, 0x2e, 0x29, 0x3c, 0x0c, 0x3f, 0x14, 0x40, 0x9b, 0x2e,
12020 0x9c, 0x3c, 0xfe, 0x6c,
12021 0x18, 0xfe, 0xed, 0x18, 0xfe, 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x3a, 0x3f,
12022 0x3b, 0x40, 0x03, 0x49,
12023 0x29, 0x63, 0x8f, 0xfe, 0xe3, 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18,
12024 0x8f, 0xfe, 0xe3, 0x54,
12025 0x90, 0xc0, 0x56, 0xfe, 0xce, 0x08, 0x02, 0x4a, 0xfe, 0x37, 0xf0, 0xfe,
12026 0xda, 0x09, 0xfe, 0x8b,
12027 0xf0, 0xfe, 0x60, 0x09, 0x02, 0x4a, 0x08, 0x05, 0x0a, 0x23, 0xfe, 0xfa,
12028 0x0a, 0x3a, 0x49, 0x3b,
12029 0x63, 0x56, 0xfe, 0x3e, 0x0a, 0x0f, 0xfe, 0xc0, 0x07, 0x41, 0x98, 0x00,
12030 0xad, 0xfe, 0x01, 0x59,
12031 0xfe, 0x52, 0xf0, 0xfe, 0x0c, 0x0a, 0x8f, 0x7a, 0xfe, 0x24, 0x0a, 0x3a,
12032 0x49, 0x8f, 0xfe, 0xe3,
12033 0x54, 0x57, 0x49, 0x7d, 0x63, 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02,
12034 0x4a, 0x3a, 0x49, 0x3b,
12035 0x63, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xbe, 0x57, 0x49, 0x57, 0x63,
12036 0x02, 0x4a, 0x08, 0x05,
12037 0x5a, 0xfe, 0x82, 0x12, 0x08, 0x05, 0x1f, 0xfe, 0x66, 0x13, 0x22, 0x62,
12038 0xb7, 0xfe, 0x03, 0xa1,
12039 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91,
12040 0xfe, 0x86, 0x91, 0x6a,
12041 0x2a, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x56, 0xe0, 0x03, 0x60, 0x29,
12042 0x61, 0x0c, 0x7f, 0x14,
12043 0x80, 0x57, 0x60, 0x7d, 0x61, 0x01, 0xb3, 0xb8, 0x6a, 0x2a, 0x13, 0x62,
12044 0x9b, 0x2e, 0x9c, 0x3c,
12045 0x3a, 0x3f, 0x3b, 0x40, 0x90, 0xc0, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05,
12046 0xfa, 0x3c, 0x01, 0xef,
12047 0xfe, 0x36, 0x10, 0x21, 0x0c, 0x7f, 0x0c, 0x80, 0x3a, 0x3f, 0x3b, 0x40,
12048 0xe4, 0x08, 0x05, 0x1f,
12049 0x17, 0xe0, 0x3a, 0x3d, 0x3b, 0x3e, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37,
12050 0x03, 0x5e, 0x29, 0x5f,
12051 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0x57, 0x49, 0x7d, 0x63, 0x02, 0xfe,
12052 0xf4, 0x09, 0x08, 0x05,
12053 0x1f, 0x17, 0xe0, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0xbe, 0xfe, 0x19,
12054 0x81, 0x50, 0xfe, 0x10,
12055 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd3, 0x10, 0x32, 0x07, 0xa6, 0x17, 0xfe,
12056 0x08, 0x09, 0x12, 0xa6,
12057 0x08, 0x05, 0x0a, 0xfe, 0x14, 0x13, 0x03, 0x3d, 0x29, 0x3e, 0x56, 0xfe,
12058 0x08, 0x09, 0xfe, 0x0c,
12059 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x4a, 0x21, 0x41, 0xfe, 0x19, 0x80, 0xe7,
12060 0x08, 0x05, 0x0a, 0xfe,
12061 0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xf4, 0xc2, 0xfe, 0xd1,
12062 0xf0, 0xe2, 0x15, 0x7e,
12063 0x01, 0x36, 0x10, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19,
12064 0x57, 0x3d, 0xfe, 0xed,
12065 0x19, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xf4, 0x1e, 0xfe,
12066 0x00, 0xff, 0x35, 0xfe,
12067 0x74, 0x10, 0xc2, 0xfe, 0xd2, 0xf0, 0xfe, 0xa6, 0x0b, 0xfe, 0x76, 0x18,
12068 0x1e, 0x19, 0x8a, 0x03,
12069 0xd2, 0x1e, 0x06, 0xfe, 0x08, 0x13, 0x10, 0xfe, 0x16, 0x00, 0x02, 0x65,
12070 0xfe, 0xd1, 0xf0, 0xfe,
12071 0xb8, 0x0b, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, 0x17, 0x00, 0xfe, 0x42,
12072 0x10, 0xfe, 0xce, 0xf0,
12073 0xfe, 0xbe, 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xca, 0x0b,
12074 0x10, 0xfe, 0x22, 0x00,
12075 0x02, 0x65, 0xfe, 0xcb, 0xf0, 0xfe, 0xd6, 0x0b, 0x10, 0xfe, 0x24, 0x00,
12076 0x02, 0x65, 0xfe, 0xd0,
12077 0xf0, 0xfe, 0xe0, 0x0b, 0x10, 0x9e, 0xe5, 0xfe, 0xcf, 0xf0, 0xfe, 0xea,
12078 0x0b, 0x10, 0x58, 0xfe,
12079 0x10, 0x10, 0xfe, 0xcc, 0xf0, 0xe2, 0x68, 0x05, 0x1f, 0x4d, 0x10, 0xfe,
12080 0x12, 0x00, 0x2c, 0x0f,
12081 0xfe, 0x4e, 0x11, 0x27, 0xfe, 0x00, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x14,
12082 0x0c, 0xbc, 0x17, 0x34,
12083 0x2c, 0x77, 0xe6, 0xc5, 0x24, 0xc6, 0x24, 0x2c, 0xfa, 0x27, 0xfe, 0x20,
12084 0x0c, 0x1c, 0x34, 0x94,
12085 0xfe, 0x3c, 0x0c, 0x95, 0x86, 0xc5, 0xdc, 0xc6, 0xdc, 0x02, 0x24, 0x01,
12086 0x4b, 0xfe, 0xdb, 0x10,
12087 0x12, 0xfe, 0xe8, 0x00, 0xb5, 0xb6, 0x74, 0xc7, 0x81, 0xc8, 0x83, 0xfe,
12088 0x89, 0xf0, 0x24, 0x33,
12089 0x31, 0xe1, 0xc7, 0x81, 0xc8, 0x83, 0x27, 0xfe, 0x66, 0x0c, 0x1d, 0x24,
12090 0x33, 0x31, 0xdf, 0xbc,
12091 0x4e, 0x10, 0xfe, 0x42, 0x00, 0x02, 0x65, 0x7c, 0x06, 0xfe, 0x81, 0x49,
12092 0x17, 0xfe, 0x2c, 0x0d,
12093 0x08, 0x05, 0x0a, 0xfe, 0x44, 0x13, 0x10, 0x00, 0x55, 0x0a, 0xfe, 0x54,
12094 0x12, 0x55, 0xfe, 0x28,
12095 0x00, 0x23, 0xfe, 0x9a, 0x0d, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66,
12096 0x44, 0xfe, 0x28, 0x00,
12097 0xfe, 0xe2, 0x10, 0x01, 0xf5, 0x01, 0xf6, 0x09, 0xa4, 0x01, 0xfe, 0x26,
12098 0x0f, 0x64, 0x12, 0x2f,
12099 0x01, 0x73, 0x02, 0x2b, 0x10, 0xfe, 0x44, 0x00, 0x55, 0x0a, 0xe9, 0x44,
12100 0x0a, 0xfe, 0xb4, 0x10,
12101 0x01, 0xb0, 0x44, 0x0a, 0xfe, 0xaa, 0x10, 0x01, 0xb0, 0xfe, 0x19, 0x82,
12102 0xfe, 0x34, 0x46, 0xac,
12103 0x44, 0x0a, 0x10, 0xfe, 0x43, 0x00, 0xfe, 0x96, 0x10, 0x08, 0x54, 0x0a,
12104 0x37, 0x01, 0xf5, 0x01,
12105 0xf6, 0x64, 0x12, 0x2f, 0x01, 0x73, 0x99, 0x0a, 0x64, 0x42, 0x92, 0x02,
12106 0xfe, 0x2e, 0x03, 0x08,
12107 0x05, 0x0a, 0x8a, 0x44, 0x0a, 0x10, 0x00, 0xfe, 0x5c, 0x10, 0x68, 0x05,
12108 0x1a, 0xfe, 0x58, 0x12,
12109 0x08, 0x05, 0x1a, 0xfe, 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0,
12110 0xfe, 0x50, 0x0d, 0xfe,
12111 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x56, 0x0d, 0x08, 0x54, 0x1a, 0x37,
12112 0xfe, 0xa9, 0x10, 0x10,
12113 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0a, 0x50, 0xfe, 0x2e, 0x10, 0x10,
12114 0xfe, 0x13, 0x00, 0xfe,
12115 0x10, 0x10, 0x10, 0x6f, 0xab, 0x10, 0xfe, 0x41, 0x00, 0xaa, 0x10, 0xfe,
12116 0x24, 0x00, 0x8c, 0xb5,
12117 0xb6, 0x74, 0x03, 0x70, 0x28, 0x23, 0xd8, 0x50, 0xfe, 0x04, 0xe6, 0x1a,
12118 0xfe, 0x9d, 0x41, 0xfe,
12119 0x1c, 0x42, 0x64, 0x01, 0xe3, 0x02, 0x2b, 0xf8, 0x15, 0x0a, 0x39, 0xa0,
12120 0xb4, 0x15, 0xfe, 0x31,
12121 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, 0x02, 0xd7, 0x42, 0xfe, 0x06,
12122 0xec, 0xd0, 0xfc, 0x44,
12123 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe, 0x06, 0xea, 0xd0, 0xfe, 0x47,
12124 0x4b, 0x91, 0xfe, 0x75,
12125 0x57, 0x03, 0x5d, 0xfe, 0x98, 0x56, 0xfe, 0x38, 0x12, 0x09, 0x48, 0x01,
12126 0x0e, 0xfe, 0x44, 0x48,
12127 0x4f, 0x08, 0x05, 0x1b, 0xfe, 0x1a, 0x13, 0x09, 0x46, 0x01, 0x0e, 0x41,
12128 0xfe, 0x41, 0x58, 0x09,
12129 0xa4, 0x01, 0x0e, 0xfe, 0x49, 0x54, 0x96, 0xfe, 0x1e, 0x0e, 0x02, 0xfe,
12130 0x2e, 0x03, 0x09, 0x5d,
12131 0xfe, 0xee, 0x14, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe,
12132 0xce, 0x47, 0xfe, 0xad,
12133 0x13, 0x02, 0x2b, 0x22, 0x20, 0x07, 0x11, 0xfe, 0x9e, 0x12, 0x21, 0x13,
12134 0x59, 0x13, 0x9f, 0x13,
12135 0xd5, 0x22, 0x2f, 0x41, 0x39, 0x2f, 0xbc, 0xad, 0xfe, 0xbc, 0xf0, 0xfe,
12136 0xe0, 0x0e, 0x0f, 0x06,
12137 0x13, 0x59, 0x01, 0xfe, 0xda, 0x16, 0x03, 0xfe, 0x38, 0x01, 0x29, 0xfe,
12138 0x3a, 0x01, 0x56, 0xfe,
12139 0xe4, 0x0e, 0xfe, 0x02, 0xec, 0xd5, 0x69, 0x00, 0x66, 0xfe, 0x04, 0xec,
12140 0x20, 0x4f, 0xfe, 0x05,
12141 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x4a, 0x17, 0xfe, 0x08, 0x90, 0xfe,
12142 0x48, 0xf4, 0x0d, 0xfe,
12143 0x18, 0x13, 0xba, 0xfe, 0x02, 0xea, 0xd5, 0x69, 0x7e, 0xfe, 0xc5, 0x13,
12144 0x15, 0x1a, 0x39, 0xa0,
12145 0xb4, 0xfe, 0x2e, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x1e, 0xfe, 0xf0, 0xff,
12146 0x0c, 0xfe, 0x60, 0x01,
12147 0x03, 0xfe, 0x3a, 0x01, 0x0c, 0xfe, 0x62, 0x01, 0x43, 0x13, 0x20, 0x25,
12148 0x06, 0x13, 0x2f, 0x12,
12149 0x2f, 0x92, 0x0f, 0x06, 0x04, 0x21, 0x04, 0x22, 0x59, 0xfe, 0xf7, 0x12,
12150 0x22, 0x9f, 0xb7, 0x13,
12151 0x9f, 0x07, 0x7e, 0xfe, 0x71, 0x13, 0xfe, 0x24, 0x1c, 0x15, 0x19, 0x39,
12152 0xa0, 0xb4, 0xfe, 0xd9,
12153 0x10, 0xc3, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x04,
12154 0xc3, 0xfe, 0x03, 0xdc,
12155 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x21,
12156 0xfe, 0x00, 0xcc, 0x04,
12157 0xfe, 0x03, 0x57, 0xc3, 0x78, 0x04, 0x08, 0x05, 0x58, 0xfe, 0x22, 0x13,
12158 0xfe, 0x1c, 0x80, 0x07,
12159 0x06, 0xfe, 0x1a, 0x13, 0xfe, 0x1e, 0x80, 0xed, 0xfe, 0x1d, 0x80, 0xae,
12160 0xfe, 0x0c, 0x90, 0xfe,
12161 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xac, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
12162 0x0a, 0xfe, 0x3c, 0x50,
12163 0xaa, 0x01, 0xfe, 0x7a, 0x17, 0x32, 0x07, 0x2f, 0xad, 0x01, 0xfe, 0xb4,
12164 0x16, 0x08, 0x05, 0x1b,
12165 0x4e, 0x01, 0xf5, 0x01, 0xf6, 0x12, 0xfe, 0xe9, 0x00, 0x08, 0x05, 0x58,
12166 0xfe, 0x2c, 0x13, 0x01,
12167 0xfe, 0x0c, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90,
12168 0x0c, 0xfe, 0x64, 0x01,
12169 0x14, 0xfe, 0x66, 0x01, 0x08, 0x05, 0x5b, 0xfe, 0x12, 0x12, 0xfe, 0x03,
12170 0x80, 0x8d, 0xfe, 0x01,
12171 0xec, 0x20, 0xfe, 0x80, 0x40, 0x13, 0x20, 0x6a, 0x2a, 0x12, 0xcf, 0x64,
12172 0x22, 0x20, 0xfb, 0x79,
12173 0x20, 0x04, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58,
12174 0x03, 0xfe, 0xae, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070012175
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012176 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe,
12177 0xb2, 0x00, 0xfe, 0x09,
12178 0x58, 0xfe, 0x0a, 0x1c, 0x25, 0x6e, 0x13, 0xd0, 0x21, 0x0c, 0x5c, 0x0c,
12179 0x45, 0x0f, 0x46, 0x52,
12180 0x50, 0x18, 0x1b, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xfe, 0xfc,
12181 0x0f, 0x44, 0x11, 0x0f,
12182 0x48, 0x52, 0x18, 0x58, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xe4,
12183 0x25, 0x11, 0x13, 0x20,
12184 0x7c, 0x6f, 0x4f, 0x22, 0x20, 0xfb, 0x79, 0x20, 0x12, 0xcf, 0xfe, 0x14,
12185 0x56, 0xfe, 0xd6, 0xf0,
12186 0xfe, 0x26, 0x10, 0xf8, 0x74, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
12187 0x18, 0x1c, 0x04, 0x42,
12188 0xfe, 0x0c, 0x14, 0xfc, 0xfe, 0x07, 0xe6, 0x1b, 0xfe, 0xce, 0x47, 0xfe,
12189 0xf5, 0x13, 0x04, 0x01,
12190 0xb0, 0x7c, 0x6f, 0x4f, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42,
12191 0x13, 0x32, 0x07, 0x2f,
12192 0xfe, 0x34, 0x13, 0x09, 0x48, 0x01, 0x0e, 0xbb, 0xfe, 0x36, 0x12, 0xfe,
12193 0x41, 0x48, 0xfe, 0x45,
12194 0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78,
12195 0x07, 0x11, 0xac, 0x09,
12196 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x73, 0xfe, 0x0e, 0x10, 0x07,
12197 0x82, 0x4e, 0xfe, 0x14,
12198 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x60, 0x10, 0x04, 0xfe, 0x44, 0x58, 0x8d,
12199 0xfe, 0x01, 0xec, 0xa2,
12200 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1a, 0x79,
12201 0x2a, 0x01, 0xe3, 0xfe,
12202 0xdd, 0x10, 0x2c, 0xc7, 0x81, 0xc8, 0x83, 0x33, 0x31, 0xde, 0x07, 0x1a,
12203 0xfe, 0x48, 0x12, 0x07,
12204 0x0a, 0xfe, 0x56, 0x12, 0x07, 0x19, 0xfe, 0x30, 0x12, 0x07, 0xc9, 0x17,
12205 0xfe, 0x32, 0x12, 0x07,
12206 0xfe, 0x23, 0x00, 0x17, 0xeb, 0x07, 0x06, 0x17, 0xfe, 0x9c, 0x12, 0x07,
12207 0x1f, 0xfe, 0x12, 0x12,
12208 0x07, 0x00, 0x17, 0x24, 0x15, 0xc9, 0x01, 0x36, 0xa9, 0x2d, 0x01, 0x0b,
12209 0x94, 0x4b, 0x04, 0x2d,
12210 0xdd, 0x09, 0xd1, 0x01, 0xfe, 0x26, 0x0f, 0x12, 0x82, 0x02, 0x2b, 0x2d,
12211 0x32, 0x07, 0xa6, 0xfe,
12212 0xd9, 0x13, 0x3a, 0x3d, 0x3b, 0x3e, 0x56, 0xfe, 0xf0, 0x11, 0x08, 0x05,
12213 0x5a, 0xfe, 0x72, 0x12,
12214 0x9b, 0x2e, 0x9c, 0x3c, 0x90, 0xc0, 0x96, 0xfe, 0xba, 0x11, 0x22, 0x62,
12215 0xfe, 0x26, 0x13, 0x03,
12216 0x7f, 0x29, 0x80, 0x56, 0xfe, 0x76, 0x0d, 0x0c, 0x60, 0x14, 0x61, 0x21,
12217 0x0c, 0x7f, 0x0c, 0x80,
12218 0x01, 0xb3, 0x25, 0x6e, 0x77, 0x13, 0x62, 0x01, 0xef, 0x9b, 0x2e, 0x9c,
12219 0x3c, 0xfe, 0x04, 0x55,
12220 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0xfe,
12221 0x91, 0x10, 0x03, 0x3f,
12222 0x29, 0x40, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x3f, 0x14, 0x40,
12223 0x88, 0x9b, 0x2e, 0x9c,
12224 0x3c, 0x90, 0xc0, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x00, 0x56, 0xfe, 0xa1,
12225 0x56, 0x0c, 0x5e, 0x14,
12226 0x5f, 0x08, 0x05, 0x5a, 0xfe, 0x1e, 0x12, 0x22, 0x62, 0xfe, 0x1f, 0x40,
12227 0x03, 0x60, 0x29, 0x61,
12228 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x03, 0x3f, 0x29, 0x40, 0xfe, 0x44,
12229 0x50, 0xfe, 0xc6, 0x50,
12230 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x3d,
12231 0x29, 0x3e, 0xfe, 0x40,
12232 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x89, 0x25, 0x06, 0x13, 0xd4, 0x02, 0x72,
12233 0x2d, 0x01, 0x0b, 0x1d,
12234 0x4c, 0x33, 0x31, 0xde, 0x07, 0x06, 0x23, 0x4c, 0x32, 0x07, 0xa6, 0x23,
12235 0x72, 0x01, 0xaf, 0x1e,
12236 0x43, 0x17, 0x4c, 0x08, 0x05, 0x0a, 0xee, 0x3a, 0x3d, 0x3b, 0x3e, 0xfe,
12237 0x0a, 0x55, 0x35, 0xfe,
12238 0x8b, 0x55, 0x57, 0x3d, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51,
12239 0x02, 0x72, 0xfe, 0x19,
12240 0x81, 0xba, 0xfe, 0x19, 0x41, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1c, 0x34,
12241 0x1d, 0xe8, 0x33, 0x31,
12242 0xe1, 0x55, 0x19, 0xfe, 0xa6, 0x12, 0x55, 0x0a, 0x4d, 0x02, 0x4c, 0x01,
12243 0x0b, 0x1c, 0x34, 0x1d,
12244 0xe8, 0x33, 0x31, 0xdf, 0x07, 0x19, 0x23, 0x4c, 0x01, 0x0b, 0x1d, 0xe8,
12245 0x33, 0x31, 0xfe, 0xe8,
12246 0x09, 0xfe, 0xc2, 0x49, 0x51, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0x8a, 0x53,
12247 0x05, 0x1f, 0x35, 0xa9,
12248 0xfe, 0xbb, 0x45, 0x55, 0x00, 0x4e, 0x44, 0x06, 0x7c, 0x43, 0xfe, 0xda,
12249 0x14, 0x01, 0xaf, 0x8c,
12250 0xfe, 0x4b, 0x45, 0xee, 0x32, 0x07, 0xa5, 0xed, 0x03, 0xcd, 0x28, 0x8a,
12251 0x03, 0x45, 0x28, 0x35,
12252 0x67, 0x02, 0x72, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17,
12253 0x03, 0x5c, 0xc1, 0x0c,
12254 0x5c, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, 0xfe, 0x9e, 0x15, 0x02,
12255 0x89, 0x01, 0x0b, 0x1c,
12256 0x34, 0x1d, 0x4c, 0x33, 0x31, 0xdf, 0x07, 0x06, 0x23, 0x4c, 0x01, 0xf1,
12257 0xfe, 0x42, 0x58, 0xf1,
12258 0xfe, 0xa4, 0x14, 0x8c, 0xfe, 0x4a, 0xf4, 0x0a, 0x17, 0x4c, 0xfe, 0x4a,
12259 0xf4, 0x06, 0xea, 0x32,
12260 0x07, 0xa5, 0x8b, 0x02, 0x72, 0x03, 0x45, 0xc1, 0x0c, 0x45, 0x67, 0x2d,
12261 0x01, 0x0b, 0x26, 0x89,
12262 0x01, 0xfe, 0xcc, 0x15, 0x02, 0x89, 0x0f, 0x06, 0x27, 0xfe, 0xbe, 0x13,
12263 0x26, 0xfe, 0xd4, 0x13,
12264 0x76, 0xfe, 0x89, 0x48, 0x01, 0x0b, 0x21, 0x76, 0x04, 0x7b, 0xfe, 0xd0,
12265 0x13, 0x1c, 0xfe, 0xd0,
12266 0x13, 0x1d, 0xfe, 0xbe, 0x13, 0x67, 0x2d, 0x01, 0x0b, 0xfe, 0xd5, 0x10,
12267 0x0f, 0x71, 0xff, 0x02,
12268 0x00, 0x57, 0x52, 0x93, 0x1e, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe,
12269 0x00, 0x5c, 0x04, 0x0f,
12270 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0xfe, 0x30, 0x56,
12271 0xfe, 0x00, 0x5c, 0x04,
12272 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x04, 0x0f, 0x71, 0xff,
12273 0x02, 0x00, 0x57, 0x52,
12274 0x93, 0xfe, 0x0b, 0x58, 0x04, 0x09, 0x5c, 0x01, 0x87, 0x09, 0x45, 0x01,
12275 0x87, 0x04, 0xfe, 0x03,
12276 0xa1, 0x1e, 0x11, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x1f, 0x52,
12277 0xfe, 0x00, 0x7d, 0xfe,
12278 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x6a, 0x2a, 0x0c, 0x5e,
12279 0x14, 0x5f, 0x57, 0x3f,
12280 0x7d, 0x40, 0x04, 0xdd, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83,
12281 0x5a, 0x8d, 0x04, 0x01,
12282 0xfe, 0x0c, 0x19, 0xfe, 0x42, 0x48, 0x50, 0x51, 0x91, 0x01, 0x0b, 0x1d,
12283 0xfe, 0x96, 0x15, 0x33,
12284 0x31, 0xe1, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15, 0x33, 0x31, 0xfe, 0xe8,
12285 0x0a, 0xfe, 0xc1, 0x59,
12286 0x03, 0xcd, 0x28, 0xfe, 0xcc, 0x12, 0x53, 0x05, 0x1a, 0xfe, 0xc4, 0x13,
12287 0x21, 0x69, 0x1a, 0xee,
12288 0x55, 0xca, 0x6b, 0xfe, 0xdc, 0x14, 0x4d, 0x0f, 0x06, 0x18, 0xca, 0x7c,
12289 0x30, 0xfe, 0x78, 0x10,
12290 0xff, 0x02, 0x83, 0x55, 0xab, 0xff, 0x02, 0x83, 0x55, 0x69, 0x19, 0xae,
12291 0x98, 0xfe, 0x30, 0x00,
12292 0x96, 0xf2, 0x18, 0x6d, 0x0f, 0x06, 0xfe, 0x56, 0x10, 0x69, 0x0a, 0xed,
12293 0x98, 0xfe, 0x64, 0x00,
12294 0x96, 0xf2, 0x09, 0xfe, 0x64, 0x00, 0x18, 0x9e, 0x0f, 0x06, 0xfe, 0x28,
12295 0x10, 0x69, 0x06, 0xfe,
12296 0x60, 0x13, 0x98, 0xfe, 0xc8, 0x00, 0x96, 0xf2, 0x09, 0xfe, 0xc8, 0x00,
12297 0x18, 0x59, 0x0f, 0x06,
12298 0x88, 0x98, 0xfe, 0x90, 0x01, 0x7a, 0xfe, 0x42, 0x15, 0x91, 0xe4, 0xfe,
12299 0x43, 0xf4, 0x9f, 0xfe,
12300 0x56, 0xf0, 0xfe, 0x54, 0x15, 0xfe, 0x04, 0xf4, 0x71, 0xfe, 0x43, 0xf4,
12301 0x9e, 0xfe, 0xf3, 0x10,
12302 0xfe, 0x40, 0x5c, 0x01, 0xfe, 0x16, 0x14, 0x1e, 0x43, 0xec, 0xfe, 0x00,
12303 0x17, 0xfe, 0x4d, 0xe4,
12304 0x6e, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0x6e, 0xfe, 0x1c, 0x10, 0xfe, 0x00,
12305 0x17, 0xfe, 0x4d, 0xe4,
12306 0xcc, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0xcc, 0x88, 0x51, 0x21, 0xfe, 0x4d,
12307 0xf4, 0x00, 0xe9, 0x91,
12308 0x0f, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x04, 0x51, 0x0f, 0x0a,
12309 0x04, 0x16, 0x06, 0x01,
12310 0x0b, 0x26, 0xf3, 0x16, 0x0a, 0x01, 0x0b, 0x26, 0xf3, 0x16, 0x19, 0x01,
12311 0x0b, 0x26, 0xf3, 0x76,
12312 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1,
12313 0x16, 0x19, 0x01, 0x0b,
12314 0x26, 0xb1, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1, 0xfe, 0x89, 0x49, 0x01,
12315 0x0b, 0x26, 0xb1, 0x76,
12316 0xfe, 0x89, 0x4a, 0x01, 0x0b, 0x04, 0x51, 0x04, 0x22, 0xd3, 0x07, 0x06,
12317 0xfe, 0x48, 0x13, 0xb8,
12318 0x13, 0xd3, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x76, 0xa9, 0x67, 0xfe, 0x01,
12319 0xec, 0xfe, 0x27, 0x01,
12320 0xfe, 0x89, 0x48, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x2e, 0x16, 0x32,
12321 0x07, 0xfe, 0xe3, 0x00,
12322 0xfe, 0x20, 0x13, 0x1d, 0xfe, 0x52, 0x16, 0x21, 0x13, 0xd4, 0x01, 0x4b,
12323 0x22, 0xd4, 0x07, 0x06,
12324 0x4e, 0x08, 0x54, 0x06, 0x37, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfb, 0x8e,
12325 0x07, 0x11, 0xae, 0x09,
12326 0x84, 0x01, 0x0e, 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x84, 0x01,
12327 0x0e, 0x8e, 0xfe, 0x80,
12328 0xe7, 0x11, 0x07, 0x11, 0x8a, 0xfe, 0x45, 0x58, 0x01, 0xf0, 0x8e, 0x04,
12329 0x09, 0x48, 0x01, 0x0e,
12330 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x80,
12331 0x80, 0xfe, 0x80, 0x4c,
12332 0xfe, 0x49, 0xe4, 0x11, 0xae, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c,
12333 0x09, 0x5d, 0x01, 0x87,
12334 0x04, 0x18, 0x11, 0x75, 0x6c, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe,
12335 0x19, 0xde, 0xfe, 0x24,
12336 0x1c, 0xfe, 0x1d, 0xf7, 0x1b, 0x97, 0xfe, 0xee, 0x16, 0x01, 0xfe, 0xf4,
12337 0x17, 0xad, 0x9a, 0x1b,
12338 0x6c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x04, 0xb9, 0x23, 0xfe, 0xde,
12339 0x16, 0xfe, 0xda, 0x10,
12340 0x18, 0x11, 0x75, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1f, 0xfe,
12341 0x18, 0x58, 0x03, 0xfe,
12342 0x66, 0x01, 0xfe, 0x19, 0x58, 0x9a, 0x1f, 0xfe, 0x3c, 0x90, 0xfe, 0x30,
12343 0xf4, 0x06, 0xfe, 0x3c,
12344 0x50, 0x6c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x1f,
12345 0x97, 0xfe, 0x38, 0x17,
12346 0xfe, 0xb6, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x10, 0x17, 0xfe, 0x9c,
12347 0x10, 0x18, 0x11, 0x75,
12348 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7,
12349 0x2e, 0x97, 0xfe, 0x5a,
12350 0x17, 0xfe, 0x94, 0x14, 0xec, 0x9a, 0x2e, 0x6c, 0x1a, 0xfe, 0xaf, 0x19,
12351 0xfe, 0x98, 0xe7, 0x00,
12352 0x04, 0xb9, 0x23, 0xfe, 0x4e, 0x17, 0xfe, 0x6c, 0x10, 0x18, 0x11, 0x75,
12353 0xfe, 0x30, 0xbc, 0xfe,
12354 0xb2, 0xbc, 0x9a, 0xcb, 0x6c, 0x1a, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
12355 0xcb, 0x97, 0xfe, 0x92,
12356 0x17, 0xfe, 0x5c, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x7e, 0x17, 0xfe,
12357 0x42, 0x10, 0xfe, 0x02,
12358 0xf6, 0x11, 0x75, 0xfe, 0x18, 0xfe, 0x60, 0xfe, 0x19, 0xfe, 0x61, 0xfe,
12359 0x03, 0xa1, 0xfe, 0x1d,
12360 0xf7, 0x5b, 0x97, 0xfe, 0xb8, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13,
12361 0x9a, 0x5b, 0x41, 0xfe,
12362 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x11, 0xfe, 0x81, 0xe7,
12363 0x11, 0x12, 0xfe, 0xdd,
12364 0x00, 0x6a, 0x2a, 0x04, 0x6a, 0x2a, 0xfe, 0x12, 0x45, 0x23, 0xfe, 0xa8,
12365 0x17, 0x15, 0x06, 0x39,
12366 0xa0, 0xb4, 0x02, 0x2b, 0xfe, 0x39, 0xf0, 0xfe, 0xfc, 0x17, 0x21, 0x04,
12367 0xfe, 0x7e, 0x18, 0x1e,
12368 0x19, 0x66, 0x0f, 0x0d, 0x04, 0x75, 0x03, 0xd2, 0x1e, 0x06, 0xfe, 0xef,
12369 0x12, 0xfe, 0xe1, 0x10,
12370 0x7c, 0x6f, 0x4f, 0x32, 0x07, 0x2f, 0xfe, 0x3c, 0x13, 0xf1, 0xfe, 0x42,
12371 0x13, 0x42, 0x92, 0x09,
12372 0x48, 0x01, 0x0e, 0xbb, 0xeb, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
12373 0xf0, 0xfe, 0x00, 0xcc,
12374 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, 0x84, 0x01,
12375 0x0e, 0xfe, 0x80, 0x4c,
12376 0x01, 0x73, 0xfe, 0x16, 0x10, 0x07, 0x82, 0x8b, 0xfe, 0x40, 0x14, 0xfe,
12377 0x24, 0x12, 0xfe, 0x14,
12378 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x1c, 0x18, 0x18, 0x0a, 0x04, 0xfe, 0x9c,
12379 0xe7, 0x0a, 0x10, 0xfe,
12380 0x15, 0x00, 0x64, 0x79, 0x2a, 0x01, 0xe3, 0x18, 0x06, 0x04, 0x42, 0x92,
12381 0x08, 0x54, 0x1b, 0x37,
12382 0x12, 0x2f, 0x01, 0x73, 0x18, 0x06, 0x04, 0xfe, 0x38, 0x90, 0xfe, 0xba,
12383 0x90, 0x3a, 0xce, 0x3b,
12384 0xcf, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x04, 0x22, 0xa3, 0x77,
12385 0x13, 0xa3, 0x04, 0x09,
12386 0xa4, 0x01, 0x0e, 0xfe, 0x41, 0x48, 0x09, 0x46, 0x01, 0x0e, 0xfe, 0x49,
12387 0x44, 0x17, 0xfe, 0xe8,
12388 0x18, 0x77, 0x78, 0x04, 0x09, 0x48, 0x01, 0x0e, 0x07, 0x11, 0x4e, 0x09,
12389 0x5d, 0x01, 0xa8, 0x09,
12390 0x46, 0x01, 0x0e, 0x77, 0x78, 0x04, 0xfe, 0x4e, 0xe4, 0x19, 0x6b, 0xfe,
12391 0x1c, 0x19, 0x03, 0xfe,
12392 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xc9,
12393 0x6b, 0xfe, 0x2e, 0x19,
12394 0x03, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1a, 0xe5, 0xfe, 0x4e, 0xe4,
12395 0xfe, 0x0b, 0x00, 0x6b,
12396 0xfe, 0x40, 0x19, 0x03, 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x1f, 0xfe,
12397 0x08, 0x10, 0x03, 0xfe,
12398 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x6d, 0xfe, 0x4e, 0x45, 0xea, 0xba, 0xff,
12399 0x04, 0x68, 0x54, 0xe7,
12400 0x1e, 0x6e, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe,
12401 0x1a, 0xf4, 0xfe, 0x00,
12402 0x04, 0xea, 0xfe, 0x48, 0xf4, 0x19, 0x7a, 0xfe, 0x74, 0x19, 0x0f, 0x19,
12403 0x04, 0x07, 0x7e, 0xfe,
12404 0x5a, 0xf0, 0xfe, 0x84, 0x19, 0x25, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
12405 0x07, 0x1a, 0xfe, 0x5a,
12406 0xf0, 0xfe, 0x92, 0x19, 0x25, 0xca, 0xfe, 0x26, 0x10, 0x07, 0x19, 0x66,
12407 0x25, 0x6d, 0xe5, 0x07,
12408 0x0a, 0x66, 0x25, 0x9e, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x66, 0x25, 0x59,
12409 0xa9, 0xb8, 0x04, 0x15,
12410 0xfe, 0x09, 0x00, 0x01, 0x36, 0xfe, 0x04, 0xfe, 0x81, 0x03, 0x83, 0xfe,
12411 0x40, 0x5c, 0x04, 0x1c,
12412 0xf7, 0xfe, 0x14, 0xf0, 0x0b, 0x27, 0xfe, 0xd6, 0x19, 0x1c, 0xf7, 0x7b,
12413 0xf7, 0xfe, 0x82, 0xf0,
12414 0xfe, 0xda, 0x19, 0x04, 0xff, 0xcc, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070012415};
12416
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012417static unsigned short _adv_asc38C0800_size = sizeof(_adv_asc38C0800_buf); /* 0x14E1 */
12418static ADV_DCNT _adv_asc38C0800_chksum = 0x050D3FD8UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012419
12420/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012421static unsigned char _adv_asc38C1600_buf[] = {
12422 0x00, 0x00, 0x00, 0xf2, 0x00, 0x16, 0x00, 0xfc, 0x00, 0x10, 0x00, 0xf0,
12423 0x18, 0xe4, 0x01, 0x00,
12424 0x04, 0x1e, 0x48, 0xe4, 0x03, 0xf6, 0xf7, 0x13, 0x2e, 0x1e, 0x02, 0x00,
12425 0x07, 0x17, 0xc0, 0x5f,
12426 0x00, 0xfa, 0xff, 0xff, 0x04, 0x00, 0x00, 0xf6, 0x09, 0xe7, 0x82, 0xe7,
12427 0x85, 0xf0, 0x86, 0xf0,
12428 0x4e, 0x10, 0x9e, 0xe7, 0xff, 0x00, 0x55, 0xf0, 0x01, 0xf6, 0x03, 0x00,
12429 0x98, 0x57, 0x01, 0xe6,
12430 0x00, 0xea, 0x00, 0xec, 0x01, 0xfa, 0x18, 0xf4, 0x08, 0x00, 0xf0, 0x1d,
12431 0x38, 0x54, 0x32, 0xf0,
12432 0x10, 0x00, 0xc2, 0x0e, 0x1e, 0xf0, 0xd5, 0xf0, 0xbc, 0x00, 0x4b, 0xe4,
12433 0x00, 0xe6, 0xb1, 0xf0,
12434 0xb4, 0x00, 0x02, 0x13, 0x3e, 0x1c, 0xc8, 0x47, 0x3e, 0x00, 0xd8, 0x01,
12435 0x06, 0x13, 0x0c, 0x1c,
12436 0x5e, 0x1e, 0x00, 0x57, 0xc8, 0x57, 0x01, 0xfc, 0xbc, 0x0e, 0xa2, 0x12,
12437 0xb9, 0x54, 0x00, 0x80,
12438 0x62, 0x0a, 0x5a, 0x12, 0xc8, 0x15, 0x3e, 0x1e, 0x18, 0x40, 0xbd, 0x56,
12439 0x03, 0xe6, 0x01, 0xea,
12440 0x5c, 0xf0, 0x0f, 0x00, 0x20, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12,
12441 0x04, 0x13, 0xbb, 0x55,
12442 0x3c, 0x56, 0x3e, 0x57, 0x03, 0x58, 0x4a, 0xe4, 0x40, 0x00, 0xb6, 0x00,
12443 0xbb, 0x00, 0xc0, 0x00,
12444 0x00, 0x01, 0x01, 0x01, 0x3e, 0x01, 0x58, 0x0a, 0x44, 0x10, 0x0a, 0x12,
12445 0x4c, 0x1c, 0x4e, 0x1c,
12446 0x02, 0x4a, 0x30, 0xe4, 0x05, 0xe6, 0x0c, 0x00, 0x3c, 0x00, 0x80, 0x00,
12447 0x24, 0x01, 0x3c, 0x01,
12448 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01,
12449 0x78, 0x01, 0x7c, 0x01,
12450 0xc6, 0x0e, 0x0c, 0x10, 0xac, 0x12, 0xae, 0x12, 0x16, 0x1a, 0x32, 0x1c,
12451 0x6e, 0x1e, 0x02, 0x48,
12452 0x3a, 0x55, 0xc9, 0x57, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x06, 0xf7,
12453 0x03, 0xfc, 0x06, 0x00,
12454 0x1e, 0x00, 0xbe, 0x00, 0xe1, 0x00, 0x0c, 0x12, 0x18, 0x1a, 0x70, 0x1a,
12455 0x30, 0x1c, 0x38, 0x1c,
12456 0x10, 0x44, 0x00, 0x4c, 0xb0, 0x57, 0x40, 0x5c, 0x4d, 0xe4, 0x04, 0xea,
12457 0x5d, 0xf0, 0xa7, 0xf0,
12458 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x09, 0x00, 0x19, 0x00, 0x32, 0x00,
12459 0x33, 0x00, 0x34, 0x00,
12460 0x36, 0x00, 0x98, 0x00, 0x9e, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01,
12461 0x79, 0x01, 0x3c, 0x09,
12462 0x68, 0x0d, 0x02, 0x10, 0x04, 0x10, 0x3a, 0x10, 0x08, 0x12, 0x0a, 0x13,
12463 0x40, 0x16, 0x50, 0x16,
12464 0x00, 0x17, 0x4a, 0x19, 0x00, 0x4e, 0x00, 0x54, 0x01, 0x58, 0x00, 0xdc,
12465 0x05, 0xf0, 0x09, 0xf0,
12466 0x59, 0xf0, 0xb8, 0xf0, 0x48, 0xf4, 0x0e, 0xf7, 0x0a, 0x00, 0x9b, 0x00,
12467 0x9c, 0x00, 0xa4, 0x00,
12468 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe7, 0x00, 0xf0, 0x03, 0x69, 0x08,
12469 0xe9, 0x09, 0x5c, 0x0c,
12470 0xb6, 0x12, 0xbc, 0x19, 0xd8, 0x1b, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c,
12471 0x42, 0x1d, 0x08, 0x44,
12472 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x89, 0x48, 0x68, 0x54,
12473 0x83, 0x55, 0x83, 0x59,
12474 0x31, 0xe4, 0x02, 0xe6, 0x07, 0xf0, 0x08, 0xf0, 0x0b, 0xf0, 0x0c, 0xf0,
12475 0x4b, 0xf4, 0x04, 0xf8,
12476 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00,
12477 0xa8, 0x00, 0xaa, 0x00,
12478 0xb9, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0x22, 0x01, 0x26, 0x01, 0x60, 0x01,
12479 0x7a, 0x01, 0x82, 0x01,
12480 0xc8, 0x01, 0xca, 0x01, 0x86, 0x02, 0x6a, 0x03, 0x18, 0x05, 0xb2, 0x07,
12481 0x68, 0x08, 0x10, 0x0d,
12482 0x06, 0x10, 0x0a, 0x10, 0x0e, 0x10, 0x12, 0x10, 0x60, 0x10, 0xed, 0x10,
12483 0xf3, 0x10, 0x06, 0x12,
12484 0x10, 0x12, 0x1e, 0x12, 0x0c, 0x13, 0x0e, 0x13, 0x10, 0x13, 0xfe, 0x9c,
12485 0xf0, 0x35, 0x05, 0xfe,
12486 0xec, 0x0e, 0xff, 0x10, 0x00, 0x00, 0xe9, 0xfe, 0x34, 0x1f, 0x00, 0xe8,
12487 0xfe, 0x88, 0x01, 0xff,
12488 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
12489 0x00, 0xfe, 0x57, 0x24,
12490 0x00, 0xfe, 0x4c, 0x00, 0x65, 0xff, 0x04, 0x00, 0x00, 0x1a, 0xff, 0x09,
12491 0x00, 0x00, 0xff, 0x08,
12492 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
12493 0xff, 0xff, 0xff, 0x13,
12494 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
12495 0xfe, 0x04, 0xf7, 0xe8,
12496 0x37, 0x7d, 0x0d, 0x01, 0xfe, 0x4a, 0x11, 0xfe, 0x04, 0xf7, 0xe8, 0x7d,
12497 0x0d, 0x51, 0x37, 0xfe,
12498 0x3d, 0xf0, 0xfe, 0x0c, 0x02, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x91, 0xf0,
12499 0xfe, 0xf8, 0x01, 0xfe,
12500 0x90, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x8f, 0xf0, 0xbc, 0x03, 0x67, 0x4d,
12501 0x05, 0xfe, 0x08, 0x0f,
12502 0x01, 0xfe, 0x78, 0x0f, 0xfe, 0xdd, 0x12, 0x05, 0xfe, 0x0e, 0x03, 0xfe,
12503 0x28, 0x1c, 0x03, 0xfe,
12504 0xa6, 0x00, 0xfe, 0xd1, 0x12, 0x3e, 0x22, 0xfe, 0xa6, 0x00, 0xac, 0xfe,
12505 0x48, 0xf0, 0xfe, 0x90,
12506 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0xaa, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc8,
12507 0x02, 0xfe, 0x46, 0xf0,
12508 0xfe, 0x5a, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x60, 0x02, 0xfe, 0x43, 0xf0,
12509 0xfe, 0x4e, 0x02, 0xfe,
12510 0x44, 0xf0, 0xfe, 0x52, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x56, 0x02, 0x1c,
12511 0x0d, 0xa2, 0x1c, 0x07,
12512 0x22, 0xb7, 0x05, 0x35, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02,
12513 0x1c, 0xf5, 0xfe, 0x1e,
12514 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0x5f, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc,
12515 0xde, 0x0a, 0x81, 0x01,
12516 0xa3, 0x05, 0x35, 0x1f, 0x95, 0x47, 0xb8, 0x01, 0xfe, 0xe4, 0x11, 0x0a,
12517 0x81, 0x01, 0x5c, 0xfe,
12518 0xbd, 0x10, 0x0a, 0x81, 0x01, 0x5c, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c,
12519 0xfe, 0x58, 0x1c, 0x1c,
12520 0x07, 0x22, 0xb7, 0x37, 0x2a, 0x35, 0xfe, 0x3d, 0xf0, 0xfe, 0x0c, 0x02,
12521 0x2b, 0xfe, 0x9e, 0x02,
12522 0xfe, 0x5a, 0x1c, 0xfe, 0x12, 0x1c, 0xfe, 0x14, 0x1c, 0x1f, 0xfe, 0x30,
12523 0x00, 0x47, 0xb8, 0x01,
12524 0xfe, 0xd4, 0x11, 0x1c, 0x07, 0x22, 0xb7, 0x05, 0xe9, 0x21, 0x2c, 0x09,
12525 0x1a, 0x31, 0xfe, 0x69,
12526 0x10, 0x1c, 0x07, 0x22, 0xb7, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0x01, 0xfe,
12527 0x1e, 0x1e, 0x20, 0x2c,
12528 0xfe, 0x05, 0xf6, 0xde, 0x01, 0xfe, 0x62, 0x1b, 0x01, 0x0c, 0x61, 0x4a,
12529 0x44, 0x15, 0x56, 0x51,
12530 0x01, 0xfe, 0x9e, 0x1e, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x0a, 0x57,
12531 0x01, 0x18, 0x09, 0x00,
12532 0x36, 0x01, 0x85, 0xfe, 0x18, 0x10, 0xfe, 0x41, 0x58, 0x0a, 0xba, 0x01,
12533 0x18, 0xfe, 0xc8, 0x54,
12534 0x7b, 0xfe, 0x1c, 0x03, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x37, 0x60,
12535 0xfe, 0x02, 0xe8, 0x30,
12536 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, 0x27, 0xf0,
12537 0xfe, 0xe4, 0x01, 0xfe,
12538 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x40, 0x1c, 0x2a, 0xeb, 0xfe,
12539 0x26, 0xf0, 0xfe, 0x66,
12540 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x54, 0x03, 0xfe, 0x11, 0xf0, 0xbc, 0xfe,
12541 0xef, 0x10, 0xfe, 0x9f,
12542 0xf0, 0xfe, 0x74, 0x03, 0xfe, 0x46, 0x1c, 0x19, 0xfe, 0x11, 0x00, 0x05,
12543 0x70, 0x37, 0xfe, 0x48,
12544 0x1c, 0xfe, 0x46, 0x1c, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x18, 0x13, 0x26,
12545 0x21, 0xb9, 0xc7, 0x20,
12546 0xb9, 0x0a, 0x57, 0x01, 0x18, 0xc7, 0x89, 0x01, 0xfe, 0xc8, 0x1a, 0x15,
12547 0xe1, 0x2a, 0xeb, 0xfe,
12548 0x01, 0xf0, 0xeb, 0xfe, 0x82, 0xf0, 0xfe, 0xa4, 0x03, 0xfe, 0x9c, 0x32,
12549 0x15, 0xfe, 0xe4, 0x00,
12550 0x2f, 0xfe, 0xb6, 0x03, 0x2a, 0x3c, 0x16, 0xfe, 0xc6, 0x03, 0x01, 0x41,
12551 0xfe, 0x06, 0xf0, 0xfe,
12552 0xd6, 0x03, 0xaf, 0xa0, 0xfe, 0x0a, 0xf0, 0xfe, 0xa2, 0x07, 0x05, 0x29,
12553 0x03, 0x81, 0x1e, 0x1b,
12554 0xfe, 0x24, 0x05, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, 0x05,
12555 0xea, 0xfe, 0x46, 0x1c,
12556 0x37, 0x7d, 0x1d, 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
12557 0xfe, 0x48, 0x1c, 0x75,
12558 0x01, 0xa6, 0x86, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, 0x1b, 0xec, 0x0a,
12559 0xe1, 0x01, 0x18, 0x77,
12560 0x50, 0x40, 0x8d, 0x30, 0x03, 0x81, 0x1e, 0xf8, 0x1f, 0x63, 0x01, 0x42,
12561 0x8f, 0xfe, 0x70, 0x02,
12562 0x05, 0xea, 0xd7, 0x99, 0xd8, 0x9c, 0x2a, 0x29, 0x2f, 0xfe, 0x4e, 0x04,
12563 0x16, 0xfe, 0x4a, 0x04,
12564 0x7e, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x54, 0x12, 0x32, 0xff,
12565 0x02, 0x00, 0x10, 0x01,
12566 0x08, 0x16, 0xfe, 0x02, 0x05, 0x32, 0x01, 0x08, 0x16, 0x29, 0x27, 0x25,
12567 0xee, 0xfe, 0x4c, 0x44,
12568 0xfe, 0x58, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x13, 0x34, 0xfe, 0x4c, 0x54,
12569 0x7b, 0xec, 0x60, 0x8d,
12570 0x30, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x7c, 0x13, 0x01,
12571 0x0c, 0x06, 0x28, 0xfe,
12572 0x32, 0x13, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x68, 0x13, 0xfe, 0x26, 0x10,
12573 0x13, 0x34, 0xfe, 0x4c,
12574 0x54, 0x7b, 0xec, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x54,
12575 0x13, 0x01, 0x0c, 0x06,
12576 0x28, 0xa5, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x40, 0x13, 0x01, 0x0c, 0x06,
12577 0x28, 0xf9, 0x1f, 0x7f,
12578 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, 0x8f,
12579 0xfe, 0xa4, 0x0e, 0x05,
12580 0x29, 0x32, 0x15, 0xfe, 0xe6, 0x00, 0x0f, 0xfe, 0x1c, 0x90, 0x04, 0xfe,
12581 0x9c, 0x93, 0x3a, 0x0b,
12582 0x0e, 0x8b, 0x02, 0x1f, 0x7f, 0x01, 0x42, 0x05, 0x35, 0xfe, 0x42, 0x5b,
12583 0x7d, 0x1d, 0xfe, 0x46,
12584 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0x0f, 0xfe, 0x87, 0x80, 0x04,
12585 0xfe, 0x87, 0x83, 0xfe,
12586 0xc9, 0x47, 0x0b, 0x0e, 0xd0, 0x65, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x98,
12587 0x13, 0x0f, 0xfe, 0x20,
12588 0x80, 0x04, 0xfe, 0xa0, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x1d, 0xfe, 0x84,
12589 0x12, 0x01, 0x38, 0x06,
12590 0x07, 0xfe, 0x70, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x1e, 0x1b, 0xfe, 0xda,
12591 0x05, 0xd0, 0x54, 0x01,
12592 0x38, 0x06, 0x0d, 0xfe, 0x58, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x1e, 0xfe,
12593 0x50, 0x12, 0x5e, 0xff,
12594 0x02, 0x00, 0x10, 0x2f, 0xfe, 0x90, 0x05, 0x2a, 0x3c, 0xcc, 0xff, 0x02,
12595 0x00, 0x10, 0x2f, 0xfe,
12596 0x9e, 0x05, 0x17, 0xfe, 0xf4, 0x05, 0x15, 0xfe, 0xe3, 0x00, 0x26, 0x01,
12597 0x38, 0xfe, 0x4a, 0xf0,
12598 0xfe, 0xc0, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0xba, 0x05, 0x71, 0x2e, 0xfe,
12599 0x21, 0x00, 0xf1, 0x2e,
12600 0xfe, 0x22, 0x00, 0xa2, 0x2e, 0x4a, 0xfe, 0x09, 0x48, 0xff, 0x02, 0x00,
12601 0x10, 0x2f, 0xfe, 0xd0,
12602 0x05, 0x17, 0xfe, 0xf4, 0x05, 0xfe, 0xe2, 0x08, 0x01, 0x38, 0x06, 0xfe,
12603 0x1c, 0x00, 0x4d, 0x01,
12604 0xa7, 0x2e, 0x07, 0x20, 0xe4, 0x47, 0xfe, 0x27, 0x01, 0x01, 0x0c, 0x06,
12605 0x28, 0xfe, 0x24, 0x12,
12606 0x3e, 0x01, 0x84, 0x1f, 0x7f, 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe,
12607 0x0d, 0x00, 0x01, 0x42,
12608 0x8f, 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x03, 0xe6, 0x1e, 0xfe, 0xca, 0x13,
12609 0x03, 0xb6, 0x1e, 0xfe,
12610 0x40, 0x12, 0x03, 0x66, 0x1e, 0xfe, 0x38, 0x13, 0x3e, 0x01, 0x84, 0x17,
12611 0xfe, 0x72, 0x06, 0x0a,
12612 0x07, 0x01, 0x38, 0x06, 0x24, 0xfe, 0x02, 0x12, 0x4f, 0x01, 0xfe, 0x56,
12613 0x19, 0x16, 0xfe, 0x68,
12614 0x06, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x66, 0x8a, 0x10, 0x66,
12615 0x03, 0x9a, 0x1e, 0xfe,
12616 0x70, 0x12, 0x03, 0x55, 0x1e, 0xfe, 0x68, 0x13, 0x01, 0xc6, 0x09, 0x12,
12617 0x48, 0xfe, 0x92, 0x06,
12618 0x2e, 0x12, 0x01, 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0x13,
12619 0x58, 0xff, 0x02, 0x00,
12620 0x57, 0x52, 0xad, 0x23, 0x3f, 0x4e, 0x62, 0x49, 0x3e, 0x01, 0x84, 0x17,
12621 0xfe, 0xea, 0x06, 0x01,
12622 0x38, 0x06, 0x12, 0xf7, 0x45, 0x0a, 0x95, 0x01, 0xfe, 0x84, 0x19, 0x16,
12623 0xfe, 0xe0, 0x06, 0x15,
12624 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x1c, 0x07,
12625 0x01, 0x84, 0xfe, 0xae,
12626 0x10, 0x03, 0x6f, 0x1e, 0xfe, 0x9e, 0x13, 0x3e, 0x01, 0x84, 0x03, 0x9a,
12627 0x1e, 0xfe, 0x1a, 0x12,
12628 0x01, 0x38, 0x06, 0x12, 0xfc, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe,
12629 0x43, 0x48, 0x62, 0x80,
12630 0xf0, 0x45, 0x0a, 0x95, 0x03, 0xb6, 0x1e, 0xf8, 0x01, 0x38, 0x06, 0x24,
12631 0x36, 0xfe, 0x02, 0xf6,
12632 0x07, 0x71, 0x78, 0x8c, 0x00, 0x4d, 0x62, 0x49, 0x3e, 0x2d, 0x93, 0x4e,
12633 0xd0, 0x0d, 0x17, 0xfe,
12634 0x9a, 0x07, 0x01, 0xfe, 0xc0, 0x19, 0x16, 0xfe, 0x90, 0x07, 0x26, 0x20,
12635 0x9e, 0x15, 0x82, 0x01,
12636 0x41, 0x15, 0xe2, 0x21, 0x9e, 0x09, 0x07, 0xfb, 0x03, 0xe6, 0xfe, 0x58,
12637 0x57, 0x10, 0xe6, 0x05,
12638 0xfe, 0x2a, 0x06, 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x1c, 0x07, 0x01, 0x84,
12639 0xfe, 0x9c, 0x32, 0x5f,
12640 0x75, 0x01, 0xa6, 0x86, 0x15, 0xfe, 0xe2, 0x00, 0x2f, 0xed, 0x2a, 0x3c,
12641 0xfe, 0x0a, 0xf0, 0xfe,
12642 0xce, 0x07, 0xae, 0xfe, 0x96, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x9e, 0x08,
12643 0xaf, 0xa0, 0x05, 0x29,
12644 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x2e, 0x12, 0x14, 0x1d, 0x01, 0x08, 0x14,
12645 0x00, 0x01, 0x08, 0x14,
12646 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08,
12647 0x14, 0x00, 0x05, 0xfe,
12648 0xc6, 0x09, 0x01, 0x76, 0x06, 0x12, 0xfe, 0x3a, 0x12, 0x01, 0x0c, 0x06,
12649 0x12, 0xfe, 0x30, 0x13,
12650 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00,
12651 0x01, 0x08, 0x14, 0x00,
12652 0x01, 0x08, 0x14, 0x07, 0x01, 0x08, 0x14, 0x00, 0x05, 0xef, 0x7c, 0x4a,
12653 0x78, 0x4f, 0x0f, 0xfe,
12654 0x9a, 0x81, 0x04, 0xfe, 0x9a, 0x83, 0xfe, 0xcb, 0x47, 0x0b, 0x0e, 0x2d,
12655 0x28, 0x48, 0xfe, 0x6c,
12656 0x08, 0x0a, 0x28, 0xfe, 0x09, 0x6f, 0xca, 0xfe, 0xca, 0x45, 0xfe, 0x32,
12657 0x12, 0x53, 0x63, 0x4e,
12658 0x7c, 0x97, 0x2f, 0xfe, 0x7e, 0x08, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe,
12659 0x6c, 0x08, 0xaf, 0xa0,
12660 0xae, 0xfe, 0x96, 0x08, 0x05, 0x29, 0x01, 0x41, 0x05, 0xed, 0x14, 0x24,
12661 0x05, 0xed, 0xfe, 0x9c,
12662 0xf7, 0x9f, 0x01, 0xfe, 0xae, 0x1e, 0xfe, 0x18, 0x58, 0x01, 0xfe, 0xbe,
12663 0x1e, 0xfe, 0x99, 0x58,
12664 0xfe, 0x78, 0x18, 0xfe, 0xf9, 0x18, 0x8e, 0xfe, 0x16, 0x09, 0x10, 0x6a,
12665 0x22, 0x6b, 0x01, 0x0c,
12666 0x61, 0x54, 0x44, 0x21, 0x2c, 0x09, 0x1a, 0xf8, 0x77, 0x01, 0xfe, 0x7e,
12667 0x1e, 0x47, 0x2c, 0x7a,
12668 0x30, 0xf0, 0xfe, 0x83, 0xe7, 0xfe, 0x3f, 0x00, 0x71, 0xfe, 0x03, 0x40,
12669 0x01, 0x0c, 0x61, 0x65,
12670 0x44, 0x01, 0xc2, 0xc8, 0xfe, 0x1f, 0x40, 0x20, 0x6e, 0x01, 0xfe, 0x6a,
12671 0x16, 0xfe, 0x08, 0x50,
12672 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0xfe, 0x10, 0x10,
12673 0x01, 0xfe, 0xce, 0x1e,
12674 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x01, 0xfe, 0xee, 0x1e,
12675 0x01, 0xfe, 0xfe, 0x1e,
12676 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x10, 0x4b, 0x22, 0x4c, 0xfe, 0x8a,
12677 0x10, 0x01, 0x0c, 0x06,
12678 0x54, 0xfe, 0x50, 0x12, 0x01, 0xfe, 0xae, 0x1e, 0x01, 0xfe, 0xbe, 0x1e,
12679 0x10, 0x6a, 0x22, 0x6b,
12680 0x01, 0x0c, 0x06, 0x65, 0x4e, 0x01, 0xc2, 0x0f, 0xfe, 0x1f, 0x80, 0x04,
12681 0xfe, 0x9f, 0x83, 0x33,
12682 0x0b, 0x0e, 0x20, 0x6e, 0x0f, 0xfe, 0x44, 0x90, 0x04, 0xfe, 0xc4, 0x93,
12683 0x3a, 0x0b, 0xfe, 0xc6,
12684 0x90, 0x04, 0xfe, 0xc6, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x6c, 0x22, 0x6d,
12685 0x01, 0xfe, 0xce, 0x1e,
12686 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x0f, 0xfe, 0x40, 0x90,
12687 0x04, 0xfe, 0xc0, 0x93,
12688 0x3a, 0x0b, 0xfe, 0xc2, 0x90, 0x04, 0xfe, 0xc2, 0x93, 0x79, 0x0b, 0x0e,
12689 0x10, 0x4b, 0x22, 0x4c,
12690 0x10, 0x64, 0x22, 0x34, 0x01, 0x0c, 0x61, 0x24, 0x44, 0x37, 0x13, 0xfe,
12691 0x4e, 0x11, 0x2f, 0xfe,
12692 0xde, 0x09, 0xfe, 0x9e, 0xf0, 0xfe, 0xf2, 0x09, 0xfe, 0x01, 0x48, 0x1b,
12693 0x3c, 0x37, 0x88, 0xf5,
12694 0xd4, 0xfe, 0x1e, 0x0a, 0xd5, 0xfe, 0x42, 0x0a, 0xd2, 0xfe, 0x1e, 0x0a,
12695 0xd3, 0xfe, 0x42, 0x0a,
12696 0xae, 0xfe, 0x12, 0x0a, 0xfe, 0x06, 0xf0, 0xfe, 0x18, 0x0a, 0xaf, 0xa0,
12697 0x05, 0x29, 0x01, 0x41,
12698 0xfe, 0xc1, 0x10, 0x14, 0x24, 0xfe, 0xc1, 0x10, 0x01, 0x76, 0x06, 0x07,
12699 0xfe, 0x14, 0x12, 0x01,
12700 0x76, 0x06, 0x0d, 0x5d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x74, 0x12, 0xfe,
12701 0x2e, 0x1c, 0x05, 0xfe,
12702 0x1a, 0x0c, 0x01, 0x76, 0x06, 0x07, 0x5d, 0x01, 0x76, 0x06, 0x0d, 0x41,
12703 0xfe, 0x2c, 0x1c, 0xfe,
12704 0xaa, 0xf0, 0xfe, 0xce, 0x0a, 0xfe, 0xac, 0xf0, 0xfe, 0x66, 0x0a, 0xfe,
12705 0x92, 0x10, 0xc4, 0xf6,
12706 0xfe, 0xad, 0xf0, 0xfe, 0x72, 0x0a, 0x05, 0xfe, 0x1a, 0x0c, 0xc5, 0xfe,
12707 0xe7, 0x10, 0xfe, 0x2b,
12708 0xf0, 0xbf, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12,
12709 0xac, 0xfe, 0xd2, 0xf0,
12710 0xbf, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x1b, 0xbf, 0x03, 0xe3, 0x23, 0x07,
12711 0x1b, 0xbf, 0xd4, 0x5b,
12712 0xd5, 0x5b, 0xd2, 0x5b, 0xd3, 0x5b, 0xc4, 0xc5, 0xfe, 0xa9, 0x10, 0x75,
12713 0x5e, 0x32, 0x1f, 0x7f,
12714 0x01, 0x42, 0x19, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x70, 0x19, 0x98,
12715 0x05, 0x70, 0xfe, 0x74,
12716 0x18, 0x23, 0xfe, 0x00, 0xf8, 0x1b, 0x5b, 0x7d, 0x12, 0x01, 0xfe, 0x78,
12717 0x0f, 0x4d, 0x01, 0xfe,
12718 0x96, 0x1a, 0x21, 0x30, 0x77, 0x7d, 0x1d, 0x05, 0x5b, 0x01, 0x0c, 0x06,
12719 0x0d, 0x2b, 0xfe, 0xe2,
12720 0x0b, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0xa6, 0x12, 0x01, 0x0c, 0x06, 0x24,
12721 0xfe, 0x88, 0x13, 0x21,
12722 0x6e, 0xc7, 0x01, 0xfe, 0x1e, 0x1f, 0x0f, 0xfe, 0x83, 0x80, 0x04, 0xfe,
12723 0x83, 0x83, 0xfe, 0xc9,
12724 0x47, 0x0b, 0x0e, 0xfe, 0xc8, 0x44, 0xfe, 0x42, 0x13, 0x0f, 0xfe, 0x04,
12725 0x91, 0x04, 0xfe, 0x84,
12726 0x93, 0xfe, 0xca, 0x57, 0x0b, 0xfe, 0x86, 0x91, 0x04, 0xfe, 0x86, 0x93,
12727 0xfe, 0xcb, 0x57, 0x0b,
12728 0x0e, 0x7a, 0x30, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x8e, 0x40, 0x03,
12729 0x6a, 0x3b, 0x6b, 0x10,
12730 0x97, 0x22, 0x98, 0xd9, 0x6a, 0xda, 0x6b, 0x01, 0xc2, 0xc8, 0x7a, 0x30,
12731 0x20, 0x6e, 0xdb, 0x64,
12732 0xdc, 0x34, 0x91, 0x6c, 0x7e, 0x6d, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55,
12733 0xfe, 0x04, 0xfa, 0x64,
12734 0xfe, 0x05, 0xfa, 0x34, 0x01, 0xfe, 0x6a, 0x16, 0xa3, 0x26, 0x10, 0x97,
12735 0x10, 0x98, 0x91, 0x6c,
12736 0x7e, 0x6d, 0xfe, 0x14, 0x10, 0x01, 0x0c, 0x06, 0x24, 0x1b, 0x40, 0x91,
12737 0x4b, 0x7e, 0x4c, 0x01,
12738 0x0c, 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x10,
12739 0x58, 0xfe, 0x91, 0x58,
12740 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x24,
12741 0x1b, 0x40, 0x01, 0x0c,
12742 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x78, 0x01, 0xfe, 0x8e, 0x1e, 0x4f, 0x0f,
12743 0xfe, 0x10, 0x90, 0x04,
12744 0xfe, 0x90, 0x93, 0x3a, 0x0b, 0xfe, 0x92, 0x90, 0x04, 0xfe, 0x92, 0x93,
12745 0x79, 0x0b, 0x0e, 0xfe,
12746 0xbd, 0x10, 0x01, 0x43, 0x09, 0xbb, 0x1b, 0xfe, 0x6e, 0x0a, 0x15, 0xbb,
12747 0x01, 0x0c, 0x06, 0x0d,
12748 0xfe, 0x14, 0x13, 0x03, 0x4b, 0x3b, 0x4c, 0x8e, 0xfe, 0x6e, 0x0a, 0xfe,
12749 0x0c, 0x58, 0xfe, 0x8d,
12750 0x58, 0x05, 0x5b, 0x26, 0x3e, 0x0f, 0xfe, 0x19, 0x80, 0x04, 0xfe, 0x99,
12751 0x83, 0x33, 0x0b, 0x0e,
12752 0xfe, 0xe5, 0x10, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1a, 0x12, 0xfe, 0x6c,
12753 0x19, 0xfe, 0x19, 0x41,
12754 0xfe, 0x6b, 0x18, 0xac, 0xfe, 0xd1, 0xf0, 0xef, 0x1f, 0x92, 0x01, 0x42,
12755 0x19, 0xfe, 0x44, 0x00,
12756 0xfe, 0x90, 0x10, 0xfe, 0x6c, 0x19, 0xd9, 0x4b, 0xfe, 0xed, 0x19, 0xda,
12757 0x4c, 0xfe, 0x0c, 0x51,
12758 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xff, 0x31, 0xfe,
12759 0x76, 0x10, 0xac, 0xfe,
12760 0xd2, 0xf0, 0xfe, 0xba, 0x0c, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x5d, 0x03,
12761 0xe3, 0x23, 0x07, 0xfe,
12762 0x08, 0x13, 0x19, 0xfe, 0x16, 0x00, 0x05, 0x70, 0xfe, 0xd1, 0xf0, 0xfe,
12763 0xcc, 0x0c, 0x1f, 0x92,
12764 0x01, 0x42, 0x19, 0xfe, 0x17, 0x00, 0x5c, 0xfe, 0xce, 0xf0, 0xfe, 0xd2,
12765 0x0c, 0xfe, 0x3e, 0x10,
12766 0xfe, 0xcd, 0xf0, 0xfe, 0xde, 0x0c, 0x19, 0xfe, 0x22, 0x00, 0x05, 0x70,
12767 0xfe, 0xcb, 0xf0, 0xfe,
12768 0xea, 0x0c, 0x19, 0xfe, 0x24, 0x00, 0x05, 0x70, 0xfe, 0xd0, 0xf0, 0xfe,
12769 0xf4, 0x0c, 0x19, 0x94,
12770 0xfe, 0x1c, 0x10, 0xfe, 0xcf, 0xf0, 0xfe, 0xfe, 0x0c, 0x19, 0x4a, 0xf3,
12771 0xfe, 0xcc, 0xf0, 0xef,
12772 0x01, 0x76, 0x06, 0x24, 0x4d, 0x19, 0xfe, 0x12, 0x00, 0x37, 0x13, 0xfe,
12773 0x4e, 0x11, 0x2f, 0xfe,
12774 0x16, 0x0d, 0xfe, 0x9e, 0xf0, 0xfe, 0x2a, 0x0d, 0xfe, 0x01, 0x48, 0x1b,
12775 0x3c, 0x37, 0x88, 0xf5,
12776 0xd4, 0x29, 0xd5, 0x29, 0xd2, 0x29, 0xd3, 0x29, 0x37, 0xfe, 0x9c, 0x32,
12777 0x2f, 0xfe, 0x3e, 0x0d,
12778 0x2a, 0x3c, 0xae, 0xfe, 0x62, 0x0d, 0xaf, 0xa0, 0xd4, 0x9f, 0xd5, 0x9f,
12779 0xd2, 0x9f, 0xd3, 0x9f,
12780 0x05, 0x29, 0x01, 0x41, 0xfe, 0xd3, 0x10, 0x15, 0xfe, 0xe8, 0x00, 0xc4,
12781 0xc5, 0x75, 0xd7, 0x99,
12782 0xd8, 0x9c, 0xfe, 0x89, 0xf0, 0x29, 0x27, 0x25, 0xbe, 0xd7, 0x99, 0xd8,
12783 0x9c, 0x2f, 0xfe, 0x8c,
12784 0x0d, 0x16, 0x29, 0x27, 0x25, 0xbd, 0xfe, 0x01, 0x48, 0xa4, 0x19, 0xfe,
12785 0x42, 0x00, 0x05, 0x70,
12786 0x90, 0x07, 0xfe, 0x81, 0x49, 0x1b, 0xfe, 0x64, 0x0e, 0x01, 0x0c, 0x06,
12787 0x0d, 0xfe, 0x44, 0x13,
12788 0x19, 0x00, 0x2d, 0x0d, 0xfe, 0x54, 0x12, 0x2d, 0xfe, 0x28, 0x00, 0x2b,
12789 0xfe, 0xda, 0x0e, 0x0a,
12790 0x57, 0x01, 0x18, 0x09, 0x00, 0x36, 0x46, 0xfe, 0x28, 0x00, 0xfe, 0xfa,
12791 0x10, 0x01, 0xfe, 0xf4,
12792 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x0a, 0xba, 0x01, 0xfe, 0x58, 0x10, 0x40,
12793 0x15, 0x56, 0x01, 0x85,
12794 0x05, 0x35, 0x19, 0xfe, 0x44, 0x00, 0x2d, 0x0d, 0xf7, 0x46, 0x0d, 0xfe,
12795 0xcc, 0x10, 0x01, 0xa7,
12796 0x46, 0x0d, 0xfe, 0xc2, 0x10, 0x01, 0xa7, 0x0f, 0xfe, 0x19, 0x82, 0x04,
12797 0xfe, 0x99, 0x83, 0xfe,
12798 0xcc, 0x47, 0x0b, 0x0e, 0xfe, 0x34, 0x46, 0xa5, 0x46, 0x0d, 0x19, 0xfe,
12799 0x43, 0x00, 0xfe, 0xa2,
12800 0x10, 0x01, 0x0c, 0x61, 0x0d, 0x44, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe,
12801 0x00, 0x1d, 0x40, 0x15,
12802 0x56, 0x01, 0x85, 0x7d, 0x0d, 0x40, 0x51, 0x01, 0xfe, 0x9e, 0x1e, 0x05,
12803 0xfe, 0x3a, 0x03, 0x01,
12804 0x0c, 0x06, 0x0d, 0x5d, 0x46, 0x0d, 0x19, 0x00, 0xfe, 0x62, 0x10, 0x01,
12805 0x76, 0x06, 0x12, 0xfe,
12806 0x5c, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x52, 0x13, 0xfe, 0x1c, 0x1c,
12807 0xfe, 0x9d, 0xf0, 0xfe,
12808 0x8e, 0x0e, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x94, 0x0e, 0x01,
12809 0x0c, 0x61, 0x12, 0x44,
12810 0xfe, 0x9f, 0x10, 0x19, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0d, 0x4f,
12811 0xfe, 0x2e, 0x10, 0x19,
12812 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x19, 0xfe, 0x47, 0x00, 0xf1, 0x19,
12813 0xfe, 0x41, 0x00, 0xa2,
12814 0x19, 0xfe, 0x24, 0x00, 0x86, 0xc4, 0xc5, 0x75, 0x03, 0x81, 0x1e, 0x2b,
12815 0xea, 0x4f, 0xfe, 0x04,
12816 0xe6, 0x12, 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x40, 0x01, 0xf4, 0x05,
12817 0x35, 0xfe, 0x12, 0x1c,
12818 0x1f, 0x0d, 0x47, 0xb5, 0xc3, 0x1f, 0xfe, 0x31, 0x00, 0x47, 0xb8, 0x01,
12819 0xfe, 0xd4, 0x11, 0x05,
12820 0xe9, 0x51, 0xfe, 0x06, 0xec, 0xe0, 0xfe, 0x0e, 0x47, 0x46, 0x28, 0xfe,
12821 0xce, 0x45, 0x31, 0x51,
12822 0xfe, 0x06, 0xea, 0xe0, 0xfe, 0x47, 0x4b, 0x45, 0xfe, 0x75, 0x57, 0x03,
12823 0x67, 0xfe, 0x98, 0x56,
12824 0xfe, 0x38, 0x12, 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x44, 0x48, 0x60, 0x01,
12825 0x0c, 0x06, 0x28, 0xfe,
12826 0x18, 0x13, 0x0a, 0x57, 0x01, 0x18, 0x3e, 0xfe, 0x41, 0x58, 0x0a, 0xba,
12827 0xfe, 0xfa, 0x14, 0xfe,
12828 0x49, 0x54, 0xb0, 0xfe, 0x5e, 0x0f, 0x05, 0xfe, 0x3a, 0x03, 0x0a, 0x67,
12829 0xfe, 0xe0, 0x14, 0xfe,
12830 0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0xce, 0x47,
12831 0xfe, 0xad, 0x13, 0x05,
12832 0x35, 0x21, 0x2c, 0x09, 0x1a, 0xfe, 0x98, 0x12, 0x26, 0x20, 0x96, 0x20,
12833 0xe7, 0xfe, 0x08, 0x1c,
12834 0xfe, 0x7c, 0x19, 0xfe, 0xfd, 0x19, 0xfe, 0x0a, 0x1c, 0x03, 0xe5, 0xfe,
12835 0x48, 0x55, 0xa5, 0x3b,
12836 0xfe, 0x62, 0x01, 0xfe, 0xc9, 0x55, 0x31, 0xfe, 0x74, 0x10, 0x01, 0xfe,
12837 0xf0, 0x1a, 0x03, 0xfe,
12838 0x38, 0x01, 0x3b, 0xfe, 0x3a, 0x01, 0x8e, 0xfe, 0x1e, 0x10, 0xfe, 0x02,
12839 0xec, 0xe7, 0x53, 0x00,
12840 0x36, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01,
12841 0x01, 0xfe, 0x62, 0x1b,
12842 0x01, 0xfe, 0xce, 0x1e, 0xb2, 0x11, 0xfe, 0x18, 0x13, 0xca, 0xfe, 0x02,
12843 0xea, 0xe7, 0x53, 0x92,
12844 0xfe, 0xc3, 0x13, 0x1f, 0x12, 0x47, 0xb5, 0xc3, 0xfe, 0x2a, 0x10, 0x03,
12845 0xfe, 0x38, 0x01, 0x23,
12846 0xfe, 0xf0, 0xff, 0x10, 0xe5, 0x03, 0xfe, 0x3a, 0x01, 0x10, 0xfe, 0x62,
12847 0x01, 0x01, 0xfe, 0x1e,
12848 0x1e, 0x20, 0x2c, 0x15, 0x56, 0x01, 0xfe, 0x9e, 0x1e, 0x13, 0x07, 0x02,
12849 0x26, 0x02, 0x21, 0x96,
12850 0xc7, 0x20, 0x96, 0x09, 0x92, 0xfe, 0x79, 0x13, 0x1f, 0x1d, 0x47, 0xb5,
12851 0xc3, 0xfe, 0xe1, 0x10,
12852 0xcf, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xcf,
12853 0xfe, 0x03, 0xdc, 0xfe,
12854 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x26, 0xfe,
12855 0x00, 0xcc, 0x02, 0xfe,
12856 0x03, 0x57, 0xcf, 0x89, 0x02, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13,
12857 0x0f, 0xfe, 0x1c, 0x80,
12858 0x04, 0xfe, 0x9c, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x07, 0xfe, 0x3a, 0x13,
12859 0x0f, 0xfe, 0x1e, 0x80,
12860 0x04, 0xfe, 0x9e, 0x83, 0x33, 0x0b, 0x0e, 0xfe, 0x2a, 0x13, 0x0f, 0xfe,
12861 0x1d, 0x80, 0x04, 0xfe,
12862 0x9d, 0x83, 0xfe, 0xf9, 0x13, 0x0e, 0xfe, 0x1c, 0x13, 0x01, 0xfe, 0xee,
12863 0x1e, 0xac, 0xfe, 0x14,
12864 0x13, 0x01, 0xfe, 0xfe, 0x1e, 0xfe, 0x81, 0x58, 0xfa, 0x01, 0xfe, 0x0e,
12865 0x1f, 0xfe, 0x30, 0xf4,
12866 0x0d, 0xfe, 0x3c, 0x50, 0xa2, 0x01, 0xfe, 0x92, 0x1b, 0x01, 0x43, 0x09,
12867 0x56, 0xfb, 0x01, 0xfe,
12868 0xc8, 0x1a, 0x01, 0x0c, 0x06, 0x28, 0xa4, 0x01, 0xfe, 0xf4, 0x1c, 0x01,
12869 0xfe, 0x00, 0x1d, 0x15,
12870 0xfe, 0xe9, 0x00, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x01, 0xfe,
12871 0x22, 0x1b, 0xfe, 0x1e,
12872 0x1c, 0x0f, 0xfe, 0x14, 0x90, 0x04, 0xfe, 0x94, 0x93, 0x3a, 0x0b, 0xfe,
12873 0x96, 0x90, 0x04, 0xfe,
12874 0x96, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0xfe, 0x64, 0x01, 0x22, 0xfe, 0x66,
12875 0x01, 0x01, 0x0c, 0x06,
12876 0x65, 0xf9, 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b,
12877 0x0e, 0x77, 0xfe, 0x01,
12878 0xec, 0x2c, 0xfe, 0x80, 0x40, 0x20, 0x2c, 0x7a, 0x30, 0x15, 0xdf, 0x40,
12879 0x21, 0x2c, 0xfe, 0x00,
12880 0x40, 0x8d, 0x2c, 0x02, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe,
12881 0x06, 0x58, 0x03, 0xfe,
12882 0xae, 0x00, 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58,
12883 0x03, 0xfe, 0xb2, 0x00,
12884 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x2e, 0x49, 0x20, 0xe0, 0x26, 0x10,
12885 0x66, 0x10, 0x55, 0x10,
12886 0x6f, 0x13, 0x57, 0x52, 0x4f, 0x1c, 0x28, 0xfe, 0x90, 0x4d, 0xfe, 0x91,
12887 0x54, 0x2b, 0xfe, 0x88,
12888 0x11, 0x46, 0x1a, 0x13, 0x5a, 0x52, 0x1c, 0x4a, 0xfe, 0x90, 0x4d, 0xfe,
12889 0x91, 0x54, 0x2b, 0xfe,
12890 0x9e, 0x11, 0x2e, 0x1a, 0x20, 0x2c, 0x90, 0x34, 0x60, 0x21, 0x2c, 0xfe,
12891 0x00, 0x40, 0x8d, 0x2c,
12892 0x15, 0xdf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xb2, 0x11, 0xfe,
12893 0x12, 0x1c, 0x75, 0xfe,
12894 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x02, 0x51, 0xfe, 0x0c,
12895 0x14, 0xfe, 0x0e, 0x47,
12896 0xfe, 0x07, 0xe6, 0x28, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x02, 0x01,
12897 0xa7, 0x90, 0x34, 0x60,
12898 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0xfe, 0x02, 0x80,
12899 0x09, 0x56, 0xfe, 0x34,
12900 0x13, 0x0a, 0x5a, 0x01, 0x18, 0xcb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48,
12901 0xfe, 0x45, 0x48, 0x01,
12902 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, 0x89,
12903 0x09, 0x1a, 0xa5, 0x0a,
12904 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x5c, 0x01, 0x85, 0xf2, 0x09, 0x9b, 0xa4,
12905 0xfe, 0x14, 0x56, 0xfe,
12906 0xd6, 0xf0, 0xfe, 0xec, 0x11, 0x02, 0xfe, 0x44, 0x58, 0x77, 0xfe, 0x01,
12907 0xec, 0xb8, 0xfe, 0x9e,
12908 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x12, 0x8d, 0x30, 0x01,
12909 0xf4, 0xfe, 0xdd, 0x10,
12910 0x37, 0xd7, 0x99, 0xd8, 0x9c, 0x27, 0x25, 0xee, 0x09, 0x12, 0xfe, 0x48,
12911 0x12, 0x09, 0x0d, 0xfe,
12912 0x56, 0x12, 0x09, 0x1d, 0xfe, 0x30, 0x12, 0x09, 0xdd, 0x1b, 0xfe, 0xc4,
12913 0x13, 0x09, 0xfe, 0x23,
12914 0x00, 0x1b, 0xfe, 0xd0, 0x13, 0x09, 0x07, 0x1b, 0xfe, 0x34, 0x14, 0x09,
12915 0x24, 0xfe, 0x12, 0x12,
12916 0x09, 0x00, 0x1b, 0x29, 0x1f, 0xdd, 0x01, 0x42, 0xa1, 0x32, 0x01, 0x08,
12917 0xae, 0x41, 0x02, 0x32,
12918 0xfe, 0x62, 0x08, 0x0a, 0xe1, 0x01, 0xfe, 0x58, 0x10, 0x15, 0x9b, 0x05,
12919 0x35, 0x32, 0x01, 0x43,
12920 0x09, 0xbb, 0xfe, 0xd7, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0x8e, 0xfe, 0x80,
12921 0x13, 0x01, 0x0c, 0x06,
12922 0x54, 0xfe, 0x72, 0x12, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x44, 0x55, 0xfe,
12923 0xe5, 0x55, 0xb0, 0xfe,
12924 0x4a, 0x13, 0x21, 0x6e, 0xfe, 0x26, 0x13, 0x03, 0x97, 0x3b, 0x98, 0x8e,
12925 0xfe, 0xb6, 0x0e, 0x10,
12926 0x6a, 0x22, 0x6b, 0x26, 0x10, 0x97, 0x10, 0x98, 0x01, 0xc2, 0x2e, 0x49,
12927 0x88, 0x20, 0x6e, 0x01,
12928 0xfe, 0x6a, 0x16, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x04, 0x55, 0xfe, 0xa5,
12929 0x55, 0xfe, 0x04, 0xfa,
12930 0x64, 0xfe, 0x05, 0xfa, 0x34, 0xfe, 0x8f, 0x10, 0x03, 0x6c, 0x3b, 0x6d,
12931 0xfe, 0x40, 0x56, 0xfe,
12932 0xe1, 0x56, 0x10, 0x6c, 0x22, 0x6d, 0x71, 0xdb, 0x64, 0xdc, 0x34, 0xfe,
12933 0x44, 0x55, 0xfe, 0xe5,
12934 0x55, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x10,
12935 0x68, 0x22, 0x69, 0x01,
12936 0x0c, 0x06, 0x54, 0xf9, 0x21, 0x6e, 0xfe, 0x1f, 0x40, 0x03, 0x6a, 0x3b,
12937 0x6b, 0xfe, 0x2c, 0x50,
12938 0xfe, 0xae, 0x50, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x44, 0x50, 0xfe, 0xc6,
12939 0x50, 0x03, 0x68, 0x3b,
12940 0x69, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x4b, 0x3b, 0x4c, 0xfe,
12941 0x40, 0x50, 0xfe, 0xc2,
12942 0x50, 0x05, 0x73, 0x2e, 0x07, 0x20, 0x9e, 0x05, 0x72, 0x32, 0x01, 0x08,
12943 0x16, 0x3d, 0x27, 0x25,
12944 0xee, 0x09, 0x07, 0x2b, 0x3d, 0x01, 0x43, 0x09, 0xbb, 0x2b, 0x72, 0x01,
12945 0xa6, 0x23, 0x3f, 0x1b,
12946 0x3d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1e, 0x13, 0x91, 0x4b, 0x7e, 0x4c,
12947 0xfe, 0x0a, 0x55, 0x31,
12948 0xfe, 0x8b, 0x55, 0xd9, 0x4b, 0xda, 0x4c, 0xfe, 0x0c, 0x51, 0xfe, 0x8e,
12949 0x51, 0x05, 0x72, 0x01,
12950 0xfe, 0x8e, 0x1e, 0xca, 0xfe, 0x19, 0x41, 0x05, 0x72, 0x32, 0x01, 0x08,
12951 0x2a, 0x3c, 0x16, 0xc0,
12952 0x27, 0x25, 0xbe, 0x2d, 0x1d, 0xc0, 0x2d, 0x0d, 0x83, 0x2d, 0x7f, 0x1b,
12953 0xfe, 0x66, 0x15, 0x05,
12954 0x3d, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbd, 0x09, 0x1d,
12955 0x2b, 0x3d, 0x01, 0x08,
12956 0x16, 0xc0, 0x27, 0x25, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x50, 0x03,
12957 0xb6, 0x1e, 0x83, 0x01,
12958 0x38, 0x06, 0x24, 0x31, 0xa1, 0xfe, 0xbb, 0x45, 0x2d, 0x00, 0xa4, 0x46,
12959 0x07, 0x90, 0x3f, 0x01,
12960 0xfe, 0xf8, 0x15, 0x01, 0xa6, 0x86, 0xfe, 0x4b, 0x45, 0xfe, 0x20, 0x13,
12961 0x01, 0x43, 0x09, 0x82,
12962 0xfe, 0x16, 0x13, 0x03, 0x9a, 0x1e, 0x5d, 0x03, 0x55, 0x1e, 0x31, 0x5e,
12963 0x05, 0x72, 0xfe, 0xc0,
12964 0x5d, 0x01, 0xa7, 0xfe, 0x03, 0x17, 0x03, 0x66, 0x8a, 0x10, 0x66, 0x5e,
12965 0x32, 0x01, 0x08, 0x17,
12966 0x73, 0x01, 0xfe, 0x56, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16,
12967 0x3d, 0x27, 0x25, 0xbd,
12968 0x09, 0x07, 0x2b, 0x3d, 0x01, 0xfe, 0xbe, 0x16, 0xfe, 0x42, 0x58, 0xfe,
12969 0xe8, 0x14, 0x01, 0xa6,
12970 0x86, 0xfe, 0x4a, 0xf4, 0x0d, 0x1b, 0x3d, 0xfe, 0x4a, 0xf4, 0x07, 0xfe,
12971 0x0e, 0x12, 0x01, 0x43,
12972 0x09, 0x82, 0x4e, 0x05, 0x72, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x5e, 0x32,
12973 0x01, 0x08, 0x17, 0x73,
12974 0x01, 0xfe, 0x84, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d,
12975 0x27, 0x25, 0xbd, 0x09,
12976 0x12, 0x2b, 0x3d, 0x01, 0xfe, 0xe8, 0x17, 0x8b, 0xfe, 0xaa, 0x14, 0xfe,
12977 0xb6, 0x14, 0x86, 0xa8,
12978 0xb2, 0x0d, 0x1b, 0x3d, 0xb2, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09,
12979 0x82, 0x4e, 0x05, 0x72,
12980 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01,
12981 0xfe, 0xc0, 0x19, 0x05,
12982 0x73, 0x13, 0x07, 0x2f, 0xfe, 0xcc, 0x15, 0x17, 0xfe, 0xe2, 0x15, 0x5f,
12983 0xcc, 0x01, 0x08, 0x26,
12984 0x5f, 0x02, 0x8f, 0xfe, 0xde, 0x15, 0x2a, 0xfe, 0xde, 0x15, 0x16, 0xfe,
12985 0xcc, 0x15, 0x5e, 0x32,
12986 0x01, 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
12987 0xad, 0x23, 0xfe, 0xff,
12988 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02,
12989 0x00, 0x57, 0x52, 0xad,
12990 0x23, 0x3f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff,
12991 0x02, 0x00, 0x57, 0x52,
12992 0xad, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xfe, 0x00, 0x5e,
12993 0x02, 0x13, 0x58, 0xff,
12994 0x02, 0x00, 0x57, 0x52, 0xad, 0xfe, 0x0b, 0x58, 0x02, 0x0a, 0x66, 0x01,
12995 0x5c, 0x0a, 0x55, 0x01,
12996 0x5c, 0x0a, 0x6f, 0x01, 0x5c, 0x02, 0x01, 0xfe, 0x1e, 0x1f, 0x23, 0x1a,
12997 0xff, 0x03, 0x00, 0x54,
12998 0xfe, 0x00, 0xf4, 0x24, 0x52, 0x0f, 0xfe, 0x00, 0x7c, 0x04, 0xfe, 0x07,
12999 0x7c, 0x3a, 0x0b, 0x0e,
13000 0xfe, 0x00, 0x71, 0xfe, 0xf9, 0x18, 0xfe, 0x7a, 0x19, 0xfe, 0xfb, 0x19,
13001 0xfe, 0x1a, 0xf7, 0x00,
13002 0xfe, 0x1b, 0xf7, 0x00, 0x7a, 0x30, 0x10, 0x68, 0x22, 0x69, 0xd9, 0x6c,
13003 0xda, 0x6d, 0x02, 0xfe,
13004 0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x77,
13005 0x02, 0x01, 0xc6, 0xfe,
13006 0x42, 0x48, 0x4f, 0x50, 0x45, 0x01, 0x08, 0x16, 0xfe, 0xe0, 0x17, 0x27,
13007 0x25, 0xbe, 0x01, 0x08,
13008 0x16, 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59,
13009 0x03, 0x9a, 0x1e, 0xfe,
13010 0xda, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfe, 0xd0, 0x13, 0x26, 0x53, 0x12,
13011 0x48, 0xfe, 0x08, 0x17,
13012 0xd1, 0x12, 0x53, 0x12, 0xfe, 0x1e, 0x13, 0x2d, 0xb4, 0x7b, 0xfe, 0x26,
13013 0x17, 0x4d, 0x13, 0x07,
13014 0x1c, 0xb4, 0x90, 0x04, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xf1,
13015 0xff, 0x02, 0x83, 0x55,
13016 0x53, 0x1d, 0xfe, 0x12, 0x13, 0xd6, 0xfe, 0x30, 0x00, 0xb0, 0xfe, 0x80,
13017 0x17, 0x1c, 0x63, 0x13,
13018 0x07, 0xfe, 0x56, 0x10, 0x53, 0x0d, 0xfe, 0x16, 0x13, 0xd6, 0xfe, 0x64,
13019 0x00, 0xb0, 0xfe, 0x80,
13020 0x17, 0x0a, 0xfe, 0x64, 0x00, 0x1c, 0x94, 0x13, 0x07, 0xfe, 0x28, 0x10,
13021 0x53, 0x07, 0xfe, 0x60,
13022 0x13, 0xd6, 0xfe, 0xc8, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0xc8,
13023 0x00, 0x1c, 0x95, 0x13,
13024 0x07, 0x71, 0xd6, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0x8c, 0x17, 0x45, 0xf3,
13025 0xfe, 0x43, 0xf4, 0x96,
13026 0xfe, 0x56, 0xf0, 0xfe, 0x9e, 0x17, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x43,
13027 0xf4, 0x94, 0xf6, 0x8b,
13028 0x01, 0xfe, 0x24, 0x16, 0x23, 0x3f, 0xfc, 0xa8, 0x8c, 0x49, 0x48, 0xfe,
13029 0xda, 0x17, 0x62, 0x49,
13030 0xfe, 0x1c, 0x10, 0xa8, 0x8c, 0x80, 0x48, 0xfe, 0xda, 0x17, 0x62, 0x80,
13031 0x71, 0x50, 0x26, 0xfe,
13032 0x4d, 0xf4, 0x00, 0xf7, 0x45, 0x13, 0x07, 0xfe, 0xb4, 0x56, 0xfe, 0xc3,
13033 0x58, 0x02, 0x50, 0x13,
13034 0x0d, 0x02, 0x50, 0x3e, 0x78, 0x4f, 0x45, 0x01, 0x08, 0x16, 0xa9, 0x27,
13035 0x25, 0xbe, 0xfe, 0x03,
13036 0xea, 0xfe, 0x7e, 0x01, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, 0xe9,
13037 0x0a, 0x01, 0x08, 0x16,
13038 0xa9, 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0xfe, 0x05, 0xea, 0xfe, 0x7f, 0x01,
13039 0x01, 0x08, 0x16, 0xa9,
13040 0x27, 0x25, 0xfe, 0x69, 0x09, 0xfe, 0x02, 0xea, 0xfe, 0x80, 0x01, 0x01,
13041 0x08, 0x16, 0xa9, 0x27,
13042 0x25, 0xfe, 0xe8, 0x08, 0x47, 0xfe, 0x81, 0x01, 0x03, 0xb6, 0x1e, 0x83,
13043 0x01, 0x38, 0x06, 0x24,
13044 0x31, 0xa2, 0x78, 0xf2, 0x53, 0x07, 0x36, 0xfe, 0x34, 0xf4, 0x3f, 0xa1,
13045 0x78, 0x03, 0x9a, 0x1e,
13046 0x83, 0x01, 0x38, 0x06, 0x12, 0x31, 0xf0, 0x4f, 0x45, 0xfe, 0x90, 0x10,
13047 0xfe, 0x40, 0x5a, 0x23,
13048 0x3f, 0xfb, 0x8c, 0x49, 0x48, 0xfe, 0xaa, 0x18, 0x62, 0x49, 0x71, 0x8c,
13049 0x80, 0x48, 0xfe, 0xaa,
13050 0x18, 0x62, 0x80, 0xfe, 0xb4, 0x56, 0xfe, 0x40, 0x5d, 0x01, 0xc6, 0x01,
13051 0xfe, 0xac, 0x1d, 0xfe,
13052 0x02, 0x17, 0xfe, 0xc8, 0x45, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0, 0x18, 0xfe,
13053 0x43, 0x48, 0x2d, 0x93,
13054 0x36, 0xfe, 0x34, 0xf4, 0xfe, 0x00, 0x11, 0xfe, 0x40, 0x10, 0x2d, 0xb4,
13055 0x36, 0xfe, 0x34, 0xf4,
13056 0x04, 0xfe, 0x34, 0x10, 0x2d, 0xfe, 0x0b, 0x00, 0x36, 0x46, 0x63, 0xfe,
13057 0x28, 0x10, 0xfe, 0xc0,
13058 0x49, 0xff, 0x02, 0x00, 0x54, 0xb2, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0xfa,
13059 0x18, 0x45, 0xfe, 0x1c,
13060 0xf4, 0x3f, 0xf3, 0xfe, 0x40, 0xf4, 0x96, 0xfe, 0x56, 0xf0, 0xfe, 0x0c,
13061 0x19, 0xfe, 0x04, 0xf4,
13062 0x58, 0xfe, 0x40, 0xf4, 0x94, 0xf6, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d,
13063 0x21, 0xfe, 0x7f, 0x01,
13064 0xfe, 0xc8, 0x46, 0xfe, 0x24, 0x13, 0x8c, 0x00, 0x5d, 0x26, 0x21, 0xfe,
13065 0x7e, 0x01, 0xfe, 0xc8,
13066 0x45, 0xfe, 0x14, 0x13, 0x21, 0xfe, 0x80, 0x01, 0xfe, 0x48, 0x45, 0xfa,
13067 0x21, 0xfe, 0x81, 0x01,
13068 0xfe, 0xc8, 0x44, 0x4e, 0x26, 0x02, 0x13, 0x07, 0x02, 0x78, 0x45, 0x50,
13069 0x13, 0x0d, 0x02, 0x14,
13070 0x07, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, 0x0d, 0x01, 0x08, 0x17,
13071 0xfe, 0x82, 0x19, 0x14,
13072 0x1d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x5f, 0xfe, 0x89, 0x49, 0x01,
13073 0x08, 0x02, 0x14, 0x07,
13074 0x01, 0x08, 0x17, 0xc1, 0x14, 0x1d, 0x01, 0x08, 0x17, 0xc1, 0x14, 0x07,
13075 0x01, 0x08, 0x17, 0xc1,
13076 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0xc1, 0x5f, 0xfe, 0x89, 0x4a, 0x01,
13077 0x08, 0x02, 0x50, 0x02,
13078 0x14, 0x07, 0x01, 0x08, 0x17, 0x74, 0x14, 0x7f, 0x01, 0x08, 0x17, 0x74,
13079 0x14, 0x12, 0x01, 0x08,
13080 0x17, 0x74, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0x74, 0x14, 0x00, 0x01,
13081 0x08, 0x17, 0x74, 0xfe,
13082 0x89, 0x4a, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x09, 0x49, 0x01, 0x08, 0x17,
13083 0x74, 0x5f, 0xcc, 0x01,
13084 0x08, 0x02, 0x21, 0xe4, 0x09, 0x07, 0xfe, 0x4c, 0x13, 0xc8, 0x20, 0xe4,
13085 0xfe, 0x49, 0xf4, 0x00,
13086 0x4d, 0x5f, 0xa1, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xcc, 0xff,
13087 0x02, 0x00, 0x10, 0x2f,
13088 0xfe, 0x3e, 0x1a, 0x01, 0x43, 0x09, 0xfe, 0xe3, 0x00, 0xfe, 0x22, 0x13,
13089 0x16, 0xfe, 0x64, 0x1a,
13090 0x26, 0x20, 0x9e, 0x01, 0x41, 0x21, 0x9e, 0x09, 0x07, 0x5d, 0x01, 0x0c,
13091 0x61, 0x07, 0x44, 0x02,
13092 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x00, 0x40, 0xaa, 0x09, 0x1a, 0xfe, 0x12,
13093 0x13, 0x0a, 0x9d, 0x01,
13094 0x18, 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x9d, 0x01, 0x18, 0xaa,
13095 0xfe, 0x80, 0xe7, 0x1a,
13096 0x09, 0x1a, 0x5d, 0xfe, 0x45, 0x58, 0x01, 0xfe, 0xb2, 0x16, 0xaa, 0x02,
13097 0x0a, 0x5a, 0x01, 0x18,
13098 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x01, 0xfe,
13099 0x7e, 0x1e, 0xfe, 0x80,
13100 0x4c, 0xfe, 0x49, 0xe4, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, 0x18,
13101 0xfe, 0x80, 0x4c, 0x0a,
13102 0x67, 0x01, 0x5c, 0x02, 0x1c, 0x1a, 0x87, 0x7c, 0xe5, 0xfe, 0x18, 0xdf,
13103 0xfe, 0x19, 0xde, 0xfe,
13104 0x24, 0x1c, 0xfe, 0x1d, 0xf7, 0x28, 0xb1, 0xfe, 0x04, 0x1b, 0x01, 0xfe,
13105 0x2a, 0x1c, 0xfa, 0xb3,
13106 0x28, 0x7c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x02, 0xc9, 0x2b, 0xfe,
13107 0xf4, 0x1a, 0xfe, 0xfa,
13108 0x10, 0x1c, 0x1a, 0x87, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x24,
13109 0xfe, 0x18, 0x58, 0x03,
13110 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0xb3, 0x24, 0x01, 0xfe, 0x0e, 0x1f,
13111 0xfe, 0x30, 0xf4, 0x07,
13112 0xfe, 0x3c, 0x50, 0x7c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c,
13113 0xf7, 0x24, 0xb1, 0xfe,
13114 0x50, 0x1b, 0xfe, 0xd4, 0x14, 0x31, 0x02, 0xc9, 0x2b, 0xfe, 0x26, 0x1b,
13115 0xfe, 0xba, 0x10, 0x1c,
13116 0x1a, 0x87, 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe,
13117 0x1d, 0xf7, 0x54, 0xb1,
13118 0xfe, 0x72, 0x1b, 0xfe, 0xb2, 0x14, 0xfc, 0xb3, 0x54, 0x7c, 0x12, 0xfe,
13119 0xaf, 0x19, 0xfe, 0x98,
13120 0xe7, 0x00, 0x02, 0xc9, 0x2b, 0xfe, 0x66, 0x1b, 0xfe, 0x8a, 0x10, 0x1c,
13121 0x1a, 0x87, 0x8b, 0x0f,
13122 0xfe, 0x30, 0x90, 0x04, 0xfe, 0xb0, 0x93, 0x3a, 0x0b, 0xfe, 0x18, 0x58,
13123 0xfe, 0x32, 0x90, 0x04,
13124 0xfe, 0xb2, 0x93, 0x3a, 0x0b, 0xfe, 0x19, 0x58, 0x0e, 0xa8, 0xb3, 0x4a,
13125 0x7c, 0x12, 0xfe, 0x0f,
13126 0x79, 0xfe, 0x1c, 0xf7, 0x4a, 0xb1, 0xfe, 0xc6, 0x1b, 0xfe, 0x5e, 0x14,
13127 0x31, 0x02, 0xc9, 0x2b,
13128 0xfe, 0x96, 0x1b, 0x5c, 0xfe, 0x02, 0xf6, 0x1a, 0x87, 0xfe, 0x18, 0xfe,
13129 0x6a, 0xfe, 0x19, 0xfe,
13130 0x6b, 0x01, 0xfe, 0x1e, 0x1f, 0xfe, 0x1d, 0xf7, 0x65, 0xb1, 0xfe, 0xee,
13131 0x1b, 0xfe, 0x36, 0x14,
13132 0xfe, 0x1c, 0x13, 0xb3, 0x65, 0x3e, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19,
13133 0xfe, 0x80, 0xe7, 0x1a,
13134 0xfe, 0x81, 0xe7, 0x1a, 0x15, 0xfe, 0xdd, 0x00, 0x7a, 0x30, 0x02, 0x7a,
13135 0x30, 0xfe, 0x12, 0x45,
13136 0x2b, 0xfe, 0xdc, 0x1b, 0x1f, 0x07, 0x47, 0xb5, 0xc3, 0x05, 0x35, 0xfe,
13137 0x39, 0xf0, 0x75, 0x26,
13138 0x02, 0xfe, 0x7e, 0x18, 0x23, 0x1d, 0x36, 0x13, 0x11, 0x02, 0x87, 0x03,
13139 0xe3, 0x23, 0x07, 0xfe,
13140 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x90, 0x34, 0x60, 0xfe, 0x02, 0x80, 0x09,
13141 0x56, 0xfe, 0x3c, 0x13,
13142 0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x51, 0xfe, 0x06, 0x83, 0x0a, 0x5a,
13143 0x01, 0x18, 0xcb, 0xfe,
13144 0x3e, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xfe, 0xb2, 0x16,
13145 0xfe, 0x00, 0xcc, 0xcb,
13146 0xfe, 0xf3, 0x13, 0x3f, 0x89, 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18,
13147 0xfe, 0x80, 0x4c, 0x01,
13148 0x85, 0xfe, 0x16, 0x10, 0x09, 0x9b, 0x4e, 0xfe, 0x40, 0x14, 0xfe, 0x24,
13149 0x12, 0xfe, 0x14, 0x56,
13150 0xfe, 0xd6, 0xf0, 0xfe, 0x52, 0x1c, 0x1c, 0x0d, 0x02, 0xfe, 0x9c, 0xe7,
13151 0x0d, 0x19, 0xfe, 0x15,
13152 0x00, 0x40, 0x8d, 0x30, 0x01, 0xf4, 0x1c, 0x07, 0x02, 0x51, 0xfe, 0x06,
13153 0x83, 0xfe, 0x18, 0x80,
13154 0x61, 0x28, 0x44, 0x15, 0x56, 0x01, 0x85, 0x1c, 0x07, 0x02, 0xfe, 0x38,
13155 0x90, 0xfe, 0xba, 0x90,
13156 0x91, 0xde, 0x7e, 0xdf, 0xfe, 0x48, 0x55, 0x31, 0xfe, 0xc9, 0x55, 0x02,
13157 0x21, 0xb9, 0x88, 0x20,
13158 0xb9, 0x02, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0x41, 0x48, 0x0a, 0x57, 0x01,
13159 0x18, 0xfe, 0x49, 0x44,
13160 0x1b, 0xfe, 0x1e, 0x1d, 0x88, 0x89, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x09,
13161 0x1a, 0xa4, 0x0a, 0x67,
13162 0x01, 0xa3, 0x0a, 0x57, 0x01, 0x18, 0x88, 0x89, 0x02, 0xfe, 0x4e, 0xe4,
13163 0x1d, 0x7b, 0xfe, 0x52,
13164 0x1d, 0x03, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe,
13165 0x4e, 0xe4, 0xdd, 0x7b,
13166 0xfe, 0x64, 0x1d, 0x03, 0xfe, 0x92, 0x00, 0xd1, 0x12, 0xfe, 0x1a, 0x10,
13167 0xfe, 0x4e, 0xe4, 0xfe,
13168 0x0b, 0x00, 0x7b, 0xfe, 0x76, 0x1d, 0x03, 0xfe, 0x94, 0x00, 0xd1, 0x24,
13169 0xfe, 0x08, 0x10, 0x03,
13170 0xfe, 0x96, 0x00, 0xd1, 0x63, 0xfe, 0x4e, 0x45, 0x83, 0xca, 0xff, 0x04,
13171 0x68, 0x54, 0xfe, 0xf1,
13172 0x10, 0x23, 0x49, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c,
13173 0xfe, 0x1a, 0xf4, 0xfe,
13174 0x00, 0x04, 0x83, 0xb2, 0x1d, 0x48, 0xfe, 0xaa, 0x1d, 0x13, 0x1d, 0x02,
13175 0x09, 0x92, 0xfe, 0x5a,
13176 0xf0, 0xfe, 0xba, 0x1d, 0x2e, 0x93, 0xfe, 0x34, 0x10, 0x09, 0x12, 0xfe,
13177 0x5a, 0xf0, 0xfe, 0xc8,
13178 0x1d, 0x2e, 0xb4, 0xfe, 0x26, 0x10, 0x09, 0x1d, 0x36, 0x2e, 0x63, 0xfe,
13179 0x1a, 0x10, 0x09, 0x0d,
13180 0x36, 0x2e, 0x94, 0xf2, 0x09, 0x07, 0x36, 0x2e, 0x95, 0xa1, 0xc8, 0x02,
13181 0x1f, 0x93, 0x01, 0x42,
13182 0xfe, 0x04, 0xfe, 0x99, 0x03, 0x9c, 0x8b, 0x02, 0x2a, 0xfe, 0x1c, 0x1e,
13183 0xfe, 0x14, 0xf0, 0x08,
13184 0x2f, 0xfe, 0x0c, 0x1e, 0x2a, 0xfe, 0x1c, 0x1e, 0x8f, 0xfe, 0x1c, 0x1e,
13185 0xfe, 0x82, 0xf0, 0xfe,
13186 0x10, 0x1e, 0x02, 0x0f, 0x3f, 0x04, 0xfe, 0x80, 0x83, 0x33, 0x0b, 0x0e,
13187 0x02, 0x0f, 0xfe, 0x18,
13188 0x80, 0x04, 0xfe, 0x98, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x02,
13189 0x80, 0x04, 0xfe, 0x82,
13190 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x80, 0x04, 0xfe, 0x86,
13191 0x83, 0x33, 0x0b, 0x0e,
13192 0x02, 0x0f, 0xfe, 0x1b, 0x80, 0x04, 0xfe, 0x9b, 0x83, 0x33, 0x0b, 0x0e,
13193 0x02, 0x0f, 0xfe, 0x04,
13194 0x80, 0x04, 0xfe, 0x84, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x80,
13195 0x80, 0x04, 0xfe, 0x80,
13196 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x19, 0x81, 0x04,
13197 0xfe, 0x99, 0x83, 0xfe,
13198 0xca, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x83, 0x04, 0xfe, 0x86,
13199 0x83, 0xfe, 0xce, 0x47,
13200 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x2c, 0x90, 0x04, 0xfe, 0xac, 0x93, 0x3a,
13201 0x0b, 0x0e, 0x02, 0x0f,
13202 0xfe, 0xae, 0x90, 0x04, 0xfe, 0xae, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
13203 0xfe, 0x08, 0x90, 0x04,
13204 0xfe, 0x88, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x8a, 0x90, 0x04,
13205 0xfe, 0x8a, 0x93, 0x79,
13206 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x0c, 0x90, 0x04, 0xfe, 0x8c, 0x93, 0x3a,
13207 0x0b, 0x0e, 0x02, 0x0f,
13208 0xfe, 0x8e, 0x90, 0x04, 0xfe, 0x8e, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
13209 0xfe, 0x3c, 0x90, 0x04,
13210 0xfe, 0xbc, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x8b, 0x0f, 0xfe, 0x03, 0x80,
13211 0x04, 0xfe, 0x83, 0x83,
13212 0x33, 0x0b, 0x77, 0x0e, 0xa8, 0x02, 0xff, 0x66, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070013213};
13214
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013215static unsigned short _adv_asc38C1600_size = sizeof(_adv_asc38C1600_buf); /* 0x1673 */
13216static ADV_DCNT _adv_asc38C1600_chksum = 0x0604EF77UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013217
13218/* a_init.c */
13219/*
13220 * EEPROM Configuration.
13221 *
13222 * All drivers should use this structure to set the default EEPROM
13223 * configuration. The BIOS now uses this structure when it is built.
13224 * Additional structure information can be found in a_condor.h where
13225 * the structure is defined.
13226 *
13227 * The *_Field_IsChar structs are needed to correct for endianness.
13228 * These values are read from the board 16 bits at a time directly
13229 * into the structs. Because some fields are char, the values will be
13230 * in the wrong order. The *_Field_IsChar tells when to flip the
13231 * bytes. Data read and written to PCI memory is automatically swapped
13232 * on big-endian platforms so char fields read as words are actually being
13233 * unswapped on big-endian platforms.
13234 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013235static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013236 ADV_EEPROM_BIOS_ENABLE, /* cfg_lsw */
13237 0x0000, /* cfg_msw */
13238 0xFFFF, /* disc_enable */
13239 0xFFFF, /* wdtr_able */
13240 0xFFFF, /* sdtr_able */
13241 0xFFFF, /* start_motor */
13242 0xFFFF, /* tagqng_able */
13243 0xFFFF, /* bios_scan */
13244 0, /* scam_tolerant */
13245 7, /* adapter_scsi_id */
13246 0, /* bios_boot_delay */
13247 3, /* scsi_reset_delay */
13248 0, /* bios_id_lun */
13249 0, /* termination */
13250 0, /* reserved1 */
13251 0xFFE7, /* bios_ctrl */
13252 0xFFFF, /* ultra_able */
13253 0, /* reserved2 */
13254 ASC_DEF_MAX_HOST_QNG, /* max_host_qng */
13255 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13256 0, /* dvc_cntl */
13257 0, /* bug_fix */
13258 0, /* serial_number_word1 */
13259 0, /* serial_number_word2 */
13260 0, /* serial_number_word3 */
13261 0, /* check_sum */
13262 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13263 , /* oem_name[16] */
13264 0, /* dvc_err_code */
13265 0, /* adv_err_code */
13266 0, /* adv_err_addr */
13267 0, /* saved_dvc_err_code */
13268 0, /* saved_adv_err_code */
13269 0, /* saved_adv_err_addr */
13270 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013271};
13272
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013273static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013274 0, /* cfg_lsw */
13275 0, /* cfg_msw */
13276 0, /* -disc_enable */
13277 0, /* wdtr_able */
13278 0, /* sdtr_able */
13279 0, /* start_motor */
13280 0, /* tagqng_able */
13281 0, /* bios_scan */
13282 0, /* scam_tolerant */
13283 1, /* adapter_scsi_id */
13284 1, /* bios_boot_delay */
13285 1, /* scsi_reset_delay */
13286 1, /* bios_id_lun */
13287 1, /* termination */
13288 1, /* reserved1 */
13289 0, /* bios_ctrl */
13290 0, /* ultra_able */
13291 0, /* reserved2 */
13292 1, /* max_host_qng */
13293 1, /* max_dvc_qng */
13294 0, /* dvc_cntl */
13295 0, /* bug_fix */
13296 0, /* serial_number_word1 */
13297 0, /* serial_number_word2 */
13298 0, /* serial_number_word3 */
13299 0, /* check_sum */
13300 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
13301 , /* oem_name[16] */
13302 0, /* dvc_err_code */
13303 0, /* adv_err_code */
13304 0, /* adv_err_addr */
13305 0, /* saved_dvc_err_code */
13306 0, /* saved_adv_err_code */
13307 0, /* saved_adv_err_addr */
13308 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013309};
13310
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013311static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013312 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
13313 0x0000, /* 01 cfg_msw */
13314 0xFFFF, /* 02 disc_enable */
13315 0xFFFF, /* 03 wdtr_able */
13316 0x4444, /* 04 sdtr_speed1 */
13317 0xFFFF, /* 05 start_motor */
13318 0xFFFF, /* 06 tagqng_able */
13319 0xFFFF, /* 07 bios_scan */
13320 0, /* 08 scam_tolerant */
13321 7, /* 09 adapter_scsi_id */
13322 0, /* bios_boot_delay */
13323 3, /* 10 scsi_reset_delay */
13324 0, /* bios_id_lun */
13325 0, /* 11 termination_se */
13326 0, /* termination_lvd */
13327 0xFFE7, /* 12 bios_ctrl */
13328 0x4444, /* 13 sdtr_speed2 */
13329 0x4444, /* 14 sdtr_speed3 */
13330 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
13331 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13332 0, /* 16 dvc_cntl */
13333 0x4444, /* 17 sdtr_speed4 */
13334 0, /* 18 serial_number_word1 */
13335 0, /* 19 serial_number_word2 */
13336 0, /* 20 serial_number_word3 */
13337 0, /* 21 check_sum */
13338 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13339 , /* 22-29 oem_name[16] */
13340 0, /* 30 dvc_err_code */
13341 0, /* 31 adv_err_code */
13342 0, /* 32 adv_err_addr */
13343 0, /* 33 saved_dvc_err_code */
13344 0, /* 34 saved_adv_err_code */
13345 0, /* 35 saved_adv_err_addr */
13346 0, /* 36 reserved */
13347 0, /* 37 reserved */
13348 0, /* 38 reserved */
13349 0, /* 39 reserved */
13350 0, /* 40 reserved */
13351 0, /* 41 reserved */
13352 0, /* 42 reserved */
13353 0, /* 43 reserved */
13354 0, /* 44 reserved */
13355 0, /* 45 reserved */
13356 0, /* 46 reserved */
13357 0, /* 47 reserved */
13358 0, /* 48 reserved */
13359 0, /* 49 reserved */
13360 0, /* 50 reserved */
13361 0, /* 51 reserved */
13362 0, /* 52 reserved */
13363 0, /* 53 reserved */
13364 0, /* 54 reserved */
13365 0, /* 55 reserved */
13366 0, /* 56 cisptr_lsw */
13367 0, /* 57 cisprt_msw */
13368 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
13369 PCI_DEVICE_ID_38C0800_REV1, /* 59 subsysid */
13370 0, /* 60 reserved */
13371 0, /* 61 reserved */
13372 0, /* 62 reserved */
13373 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013374};
13375
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013376static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013377 0, /* 00 cfg_lsw */
13378 0, /* 01 cfg_msw */
13379 0, /* 02 disc_enable */
13380 0, /* 03 wdtr_able */
13381 0, /* 04 sdtr_speed1 */
13382 0, /* 05 start_motor */
13383 0, /* 06 tagqng_able */
13384 0, /* 07 bios_scan */
13385 0, /* 08 scam_tolerant */
13386 1, /* 09 adapter_scsi_id */
13387 1, /* bios_boot_delay */
13388 1, /* 10 scsi_reset_delay */
13389 1, /* bios_id_lun */
13390 1, /* 11 termination_se */
13391 1, /* termination_lvd */
13392 0, /* 12 bios_ctrl */
13393 0, /* 13 sdtr_speed2 */
13394 0, /* 14 sdtr_speed3 */
13395 1, /* 15 max_host_qng */
13396 1, /* max_dvc_qng */
13397 0, /* 16 dvc_cntl */
13398 0, /* 17 sdtr_speed4 */
13399 0, /* 18 serial_number_word1 */
13400 0, /* 19 serial_number_word2 */
13401 0, /* 20 serial_number_word3 */
13402 0, /* 21 check_sum */
13403 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
13404 , /* 22-29 oem_name[16] */
13405 0, /* 30 dvc_err_code */
13406 0, /* 31 adv_err_code */
13407 0, /* 32 adv_err_addr */
13408 0, /* 33 saved_dvc_err_code */
13409 0, /* 34 saved_adv_err_code */
13410 0, /* 35 saved_adv_err_addr */
13411 0, /* 36 reserved */
13412 0, /* 37 reserved */
13413 0, /* 38 reserved */
13414 0, /* 39 reserved */
13415 0, /* 40 reserved */
13416 0, /* 41 reserved */
13417 0, /* 42 reserved */
13418 0, /* 43 reserved */
13419 0, /* 44 reserved */
13420 0, /* 45 reserved */
13421 0, /* 46 reserved */
13422 0, /* 47 reserved */
13423 0, /* 48 reserved */
13424 0, /* 49 reserved */
13425 0, /* 50 reserved */
13426 0, /* 51 reserved */
13427 0, /* 52 reserved */
13428 0, /* 53 reserved */
13429 0, /* 54 reserved */
13430 0, /* 55 reserved */
13431 0, /* 56 cisptr_lsw */
13432 0, /* 57 cisprt_msw */
13433 0, /* 58 subsysvid */
13434 0, /* 59 subsysid */
13435 0, /* 60 reserved */
13436 0, /* 61 reserved */
13437 0, /* 62 reserved */
13438 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013439};
13440
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013441static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013442 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
13443 0x0000, /* 01 cfg_msw */
13444 0xFFFF, /* 02 disc_enable */
13445 0xFFFF, /* 03 wdtr_able */
13446 0x5555, /* 04 sdtr_speed1 */
13447 0xFFFF, /* 05 start_motor */
13448 0xFFFF, /* 06 tagqng_able */
13449 0xFFFF, /* 07 bios_scan */
13450 0, /* 08 scam_tolerant */
13451 7, /* 09 adapter_scsi_id */
13452 0, /* bios_boot_delay */
13453 3, /* 10 scsi_reset_delay */
13454 0, /* bios_id_lun */
13455 0, /* 11 termination_se */
13456 0, /* termination_lvd */
13457 0xFFE7, /* 12 bios_ctrl */
13458 0x5555, /* 13 sdtr_speed2 */
13459 0x5555, /* 14 sdtr_speed3 */
13460 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
13461 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13462 0, /* 16 dvc_cntl */
13463 0x5555, /* 17 sdtr_speed4 */
13464 0, /* 18 serial_number_word1 */
13465 0, /* 19 serial_number_word2 */
13466 0, /* 20 serial_number_word3 */
13467 0, /* 21 check_sum */
13468 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13469 , /* 22-29 oem_name[16] */
13470 0, /* 30 dvc_err_code */
13471 0, /* 31 adv_err_code */
13472 0, /* 32 adv_err_addr */
13473 0, /* 33 saved_dvc_err_code */
13474 0, /* 34 saved_adv_err_code */
13475 0, /* 35 saved_adv_err_addr */
13476 0, /* 36 reserved */
13477 0, /* 37 reserved */
13478 0, /* 38 reserved */
13479 0, /* 39 reserved */
13480 0, /* 40 reserved */
13481 0, /* 41 reserved */
13482 0, /* 42 reserved */
13483 0, /* 43 reserved */
13484 0, /* 44 reserved */
13485 0, /* 45 reserved */
13486 0, /* 46 reserved */
13487 0, /* 47 reserved */
13488 0, /* 48 reserved */
13489 0, /* 49 reserved */
13490 0, /* 50 reserved */
13491 0, /* 51 reserved */
13492 0, /* 52 reserved */
13493 0, /* 53 reserved */
13494 0, /* 54 reserved */
13495 0, /* 55 reserved */
13496 0, /* 56 cisptr_lsw */
13497 0, /* 57 cisprt_msw */
13498 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
13499 PCI_DEVICE_ID_38C1600_REV1, /* 59 subsysid */
13500 0, /* 60 reserved */
13501 0, /* 61 reserved */
13502 0, /* 62 reserved */
13503 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013504};
13505
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013506static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013507 0, /* 00 cfg_lsw */
13508 0, /* 01 cfg_msw */
13509 0, /* 02 disc_enable */
13510 0, /* 03 wdtr_able */
13511 0, /* 04 sdtr_speed1 */
13512 0, /* 05 start_motor */
13513 0, /* 06 tagqng_able */
13514 0, /* 07 bios_scan */
13515 0, /* 08 scam_tolerant */
13516 1, /* 09 adapter_scsi_id */
13517 1, /* bios_boot_delay */
13518 1, /* 10 scsi_reset_delay */
13519 1, /* bios_id_lun */
13520 1, /* 11 termination_se */
13521 1, /* termination_lvd */
13522 0, /* 12 bios_ctrl */
13523 0, /* 13 sdtr_speed2 */
13524 0, /* 14 sdtr_speed3 */
13525 1, /* 15 max_host_qng */
13526 1, /* max_dvc_qng */
13527 0, /* 16 dvc_cntl */
13528 0, /* 17 sdtr_speed4 */
13529 0, /* 18 serial_number_word1 */
13530 0, /* 19 serial_number_word2 */
13531 0, /* 20 serial_number_word3 */
13532 0, /* 21 check_sum */
13533 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
13534 , /* 22-29 oem_name[16] */
13535 0, /* 30 dvc_err_code */
13536 0, /* 31 adv_err_code */
13537 0, /* 32 adv_err_addr */
13538 0, /* 33 saved_dvc_err_code */
13539 0, /* 34 saved_adv_err_code */
13540 0, /* 35 saved_adv_err_addr */
13541 0, /* 36 reserved */
13542 0, /* 37 reserved */
13543 0, /* 38 reserved */
13544 0, /* 39 reserved */
13545 0, /* 40 reserved */
13546 0, /* 41 reserved */
13547 0, /* 42 reserved */
13548 0, /* 43 reserved */
13549 0, /* 44 reserved */
13550 0, /* 45 reserved */
13551 0, /* 46 reserved */
13552 0, /* 47 reserved */
13553 0, /* 48 reserved */
13554 0, /* 49 reserved */
13555 0, /* 50 reserved */
13556 0, /* 51 reserved */
13557 0, /* 52 reserved */
13558 0, /* 53 reserved */
13559 0, /* 54 reserved */
13560 0, /* 55 reserved */
13561 0, /* 56 cisptr_lsw */
13562 0, /* 57 cisprt_msw */
13563 0, /* 58 subsysvid */
13564 0, /* 59 subsysid */
13565 0, /* 60 reserved */
13566 0, /* 61 reserved */
13567 0, /* 62 reserved */
13568 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013569};
13570
13571/*
13572 * Initialize the ADV_DVC_VAR structure.
13573 *
13574 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
13575 *
13576 * For a non-fatal error return a warning code. If there are no warnings
13577 * then 0 is returned.
13578 */
Matthew Wilcox394dbf32007-07-26 11:56:40 -040013579static int __devinit
13580AdvInitGetConfig(struct pci_dev *pdev, ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013581{
Matthew Wilcox9649af32007-07-26 21:51:47 -060013582 unsigned short warn_code = 0;
13583 AdvPortAddr iop_base = asc_dvc->iop_base;
Matthew Wilcox9649af32007-07-26 21:51:47 -060013584 u16 cmd;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013585 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013586
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013587 asc_dvc->err_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013588
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013589 /*
13590 * Save the state of the PCI Configuration Command Register
13591 * "Parity Error Response Control" Bit. If the bit is clear (0),
13592 * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore
13593 * DMA parity errors.
13594 */
13595 asc_dvc->cfg->control_flag = 0;
Matthew Wilcox9649af32007-07-26 21:51:47 -060013596 pci_read_config_word(pdev, PCI_COMMAND, &cmd);
13597 if ((cmd & PCI_COMMAND_PARITY) == 0)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013598 asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013599
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013600 asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) |
13601 ADV_LIB_VERSION_MINOR;
13602 asc_dvc->cfg->chip_version =
13603 AdvGetChipVersion(iop_base, asc_dvc->bus_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013604
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013605 ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: 0x%x 0x%x\n",
13606 (ushort)AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
13607 (ushort)ADV_CHIP_ID_BYTE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013608
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013609 ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: 0x%x 0x%x\n",
13610 (ushort)AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
13611 (ushort)ADV_CHIP_ID_WORD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013612
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013613 /*
13614 * Reset the chip to start and allow register writes.
13615 */
13616 if (AdvFindSignature(iop_base) == 0) {
13617 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
13618 return ADV_ERROR;
13619 } else {
13620 /*
13621 * The caller must set 'chip_type' to a valid setting.
13622 */
13623 if (asc_dvc->chip_type != ADV_CHIP_ASC3550 &&
13624 asc_dvc->chip_type != ADV_CHIP_ASC38C0800 &&
13625 asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
13626 asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
13627 return ADV_ERROR;
13628 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013629
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013630 /*
13631 * Reset Chip.
13632 */
13633 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
13634 ADV_CTRL_REG_CMD_RESET);
13635 DvcSleepMilliSecond(100);
13636 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
13637 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013638
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013639 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
Matthew Wilcox9649af32007-07-26 21:51:47 -060013640 status = AdvInitFrom38C1600EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013641 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
Matthew Wilcox9649af32007-07-26 21:51:47 -060013642 status = AdvInitFrom38C0800EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013643 } else {
Matthew Wilcox9649af32007-07-26 21:51:47 -060013644 status = AdvInitFrom3550EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013645 }
13646 warn_code |= status;
13647 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013648
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013649 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013650}
13651
13652/*
13653 * Initialize the ASC-3550.
13654 *
13655 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
13656 *
13657 * For a non-fatal error return a warning code. If there are no warnings
13658 * then 0 is returned.
13659 *
13660 * Needed after initialization for error recovery.
13661 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013662static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013663{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013664 AdvPortAddr iop_base;
13665 ushort warn_code;
13666 ADV_DCNT sum;
13667 int begin_addr;
13668 int end_addr;
13669 ushort code_sum;
13670 int word;
13671 int j;
13672 int adv_asc3550_expanded_size;
13673 ADV_CARR_T *carrp;
13674 ADV_DCNT contig_len;
13675 ADV_SDCNT buf_size;
13676 ADV_PADDR carr_paddr;
13677 int i;
13678 ushort scsi_cfg1;
13679 uchar tid;
13680 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
13681 ushort wdtr_able = 0, sdtr_able, tagqng_able;
13682 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070013683
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013684 /* If there is already an error, don't continue. */
13685 if (asc_dvc->err_code != 0) {
13686 return ADV_ERROR;
13687 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013688
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013689 /*
13690 * The caller must set 'chip_type' to ADV_CHIP_ASC3550.
13691 */
13692 if (asc_dvc->chip_type != ADV_CHIP_ASC3550) {
13693 asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
13694 return ADV_ERROR;
13695 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013696
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013697 warn_code = 0;
13698 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013699
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013700 /*
13701 * Save the RISC memory BIOS region before writing the microcode.
13702 * The BIOS may already be loaded and using its RISC LRAM region
13703 * so its region must be saved and restored.
13704 *
13705 * Note: This code makes the assumption, which is currently true,
13706 * that a chip reset does not clear RISC LRAM.
13707 */
13708 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
13709 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
13710 bios_mem[i]);
13711 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013712
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013713 /*
13714 * Save current per TID negotiated values.
13715 */
13716 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == 0x55AA) {
13717 ushort bios_version, major, minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013718
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013719 bios_version =
13720 bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM) / 2];
13721 major = (bios_version >> 12) & 0xF;
13722 minor = (bios_version >> 8) & 0xF;
13723 if (major < 3 || (major == 3 && minor == 1)) {
13724 /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
13725 AdvReadWordLram(iop_base, 0x120, wdtr_able);
13726 } else {
13727 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
13728 }
13729 }
13730 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
13731 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
13732 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
13733 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
13734 max_cmd[tid]);
13735 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013736
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013737 /*
13738 * Load the Microcode
13739 *
13740 * Write the microcode image to RISC memory starting at address 0.
13741 */
13742 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
13743 /* Assume the following compressed format of the microcode buffer:
13744 *
13745 * 254 word (508 byte) table indexed by byte code followed
13746 * by the following byte codes:
13747 *
13748 * 1-Byte Code:
13749 * 00: Emit word 0 in table.
13750 * 01: Emit word 1 in table.
13751 * .
13752 * FD: Emit word 253 in table.
13753 *
13754 * Multi-Byte Code:
13755 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
13756 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
13757 */
13758 word = 0;
13759 for (i = 253 * 2; i < _adv_asc3550_size; i++) {
13760 if (_adv_asc3550_buf[i] == 0xff) {
13761 for (j = 0; j < _adv_asc3550_buf[i + 1]; j++) {
13762 AdvWriteWordAutoIncLram(iop_base, (((ushort)
13763 _adv_asc3550_buf
13764 [i +
13765 3] << 8) |
13766 _adv_asc3550_buf
13767 [i + 2]));
13768 word++;
13769 }
13770 i += 3;
13771 } else if (_adv_asc3550_buf[i] == 0xfe) {
13772 AdvWriteWordAutoIncLram(iop_base, (((ushort)
13773 _adv_asc3550_buf[i +
13774 2]
13775 << 8) |
13776 _adv_asc3550_buf[i +
13777 1]));
13778 i += 2;
13779 word++;
13780 } else {
13781 AdvWriteWordAutoIncLram(iop_base, (((ushort)
13782 _adv_asc3550_buf[(_adv_asc3550_buf[i] * 2) + 1] << 8) | _adv_asc3550_buf[_adv_asc3550_buf[i] * 2]));
13783 word++;
13784 }
13785 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013786
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013787 /*
13788 * Set 'word' for later use to clear the rest of memory and save
13789 * the expanded mcode size.
13790 */
13791 word *= 2;
13792 adv_asc3550_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013793
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013794 /*
13795 * Clear the rest of ASC-3550 Internal RAM (8KB).
13796 */
13797 for (; word < ADV_3550_MEMSIZE; word += 2) {
13798 AdvWriteWordAutoIncLram(iop_base, 0);
13799 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013800
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013801 /*
13802 * Verify the microcode checksum.
13803 */
13804 sum = 0;
13805 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013806
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013807 for (word = 0; word < adv_asc3550_expanded_size; word += 2) {
13808 sum += AdvReadWordAutoIncLram(iop_base);
13809 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013810
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013811 if (sum != _adv_asc3550_chksum) {
13812 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
13813 return ADV_ERROR;
13814 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013815
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013816 /*
13817 * Restore the RISC memory BIOS region.
13818 */
13819 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
13820 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
13821 bios_mem[i]);
13822 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013823
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013824 /*
13825 * Calculate and write the microcode code checksum to the microcode
13826 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
13827 */
13828 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
13829 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
13830 code_sum = 0;
13831 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
13832 for (word = begin_addr; word < end_addr; word += 2) {
13833 code_sum += AdvReadWordAutoIncLram(iop_base);
13834 }
13835 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013836
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013837 /*
13838 * Read and save microcode version and date.
13839 */
13840 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
13841 asc_dvc->cfg->mcode_date);
13842 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
13843 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013844
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013845 /*
13846 * Set the chip type to indicate the ASC3550.
13847 */
13848 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013849
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013850 /*
13851 * If the PCI Configuration Command Register "Parity Error Response
13852 * Control" Bit was clear (0), then set the microcode variable
13853 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
13854 * to ignore DMA parity errors.
13855 */
13856 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
13857 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
13858 word |= CONTROL_FLAG_IGNORE_PERR;
13859 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
13860 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013861
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013862 /*
13863 * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
13864 * threshold of 128 bytes. This register is only accessible to the host.
13865 */
13866 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
13867 START_CTL_EMFU | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013868
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013869 /*
13870 * Microcode operating variables for WDTR, SDTR, and command tag
Matthew Wilcox47d853c2007-07-26 11:41:33 -040013871 * queuing will be set in slave_configure() based on what a
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013872 * device reports it is capable of in Inquiry byte 7.
13873 *
13874 * If SCSI Bus Resets have been disabled, then directly set
13875 * SDTR and WDTR from the EEPROM configuration. This will allow
13876 * the BIOS and warm boot to work without a SCSI bus hang on
13877 * the Inquiry caused by host and target mismatched DTR values.
13878 * Without the SCSI Bus Reset, before an Inquiry a device can't
13879 * be assumed to be in Asynchronous, Narrow mode.
13880 */
13881 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
13882 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
13883 asc_dvc->wdtr_able);
13884 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
13885 asc_dvc->sdtr_able);
13886 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013887
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013888 /*
13889 * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
13890 * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
13891 * bitmask. These values determine the maximum SDTR speed negotiated
13892 * with a device.
13893 *
13894 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
13895 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
13896 * without determining here whether the device supports SDTR.
13897 *
13898 * 4-bit speed SDTR speed name
13899 * =========== ===============
13900 * 0000b (0x0) SDTR disabled
13901 * 0001b (0x1) 5 Mhz
13902 * 0010b (0x2) 10 Mhz
13903 * 0011b (0x3) 20 Mhz (Ultra)
13904 * 0100b (0x4) 40 Mhz (LVD/Ultra2)
13905 * 0101b (0x5) 80 Mhz (LVD2/Ultra3)
13906 * 0110b (0x6) Undefined
13907 * .
13908 * 1111b (0xF) Undefined
13909 */
13910 word = 0;
13911 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
13912 if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) {
13913 /* Set Ultra speed for TID 'tid'. */
13914 word |= (0x3 << (4 * (tid % 4)));
13915 } else {
13916 /* Set Fast speed for TID 'tid'. */
13917 word |= (0x2 << (4 * (tid % 4)));
13918 }
13919 if (tid == 3) { /* Check if done with sdtr_speed1. */
13920 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
13921 word = 0;
13922 } else if (tid == 7) { /* Check if done with sdtr_speed2. */
13923 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
13924 word = 0;
13925 } else if (tid == 11) { /* Check if done with sdtr_speed3. */
13926 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
13927 word = 0;
13928 } else if (tid == 15) { /* Check if done with sdtr_speed4. */
13929 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
13930 /* End of loop. */
13931 }
13932 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013933
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013934 /*
13935 * Set microcode operating variable for the disconnect per TID bitmask.
13936 */
13937 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
13938 asc_dvc->cfg->disc_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013939
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013940 /*
13941 * Set SCSI_CFG0 Microcode Default Value.
13942 *
13943 * The microcode will set the SCSI_CFG0 register using this value
13944 * after it is started below.
13945 */
13946 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
13947 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
13948 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013949
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013950 /*
13951 * Determine SCSI_CFG1 Microcode Default Value.
13952 *
13953 * The microcode will set the SCSI_CFG1 register using this value
13954 * after it is started below.
13955 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013956
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013957 /* Read current SCSI_CFG1 Register value. */
13958 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013959
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013960 /*
13961 * If all three connectors are in use, return an error.
13962 */
13963 if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
13964 (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) {
13965 asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
13966 return ADV_ERROR;
13967 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013968
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013969 /*
13970 * If the internal narrow cable is reversed all of the SCSI_CTRL
13971 * register signals will be set. Check for and return an error if
13972 * this condition is found.
13973 */
13974 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
13975 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
13976 return ADV_ERROR;
13977 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013978
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013979 /*
13980 * If this is a differential board and a single-ended device
13981 * is attached to one of the connectors, return an error.
13982 */
13983 if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) {
13984 asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE;
13985 return ADV_ERROR;
13986 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013987
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013988 /*
13989 * If automatic termination control is enabled, then set the
13990 * termination value based on a table listed in a_condor.h.
13991 *
13992 * If manual termination was specified with an EEPROM setting
13993 * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
13994 * is ready to be 'ored' into SCSI_CFG1.
13995 */
13996 if (asc_dvc->cfg->termination == 0) {
13997 /*
13998 * The software always controls termination by setting TERM_CTL_SEL.
13999 * If TERM_CTL_SEL were set to 0, the hardware would set termination.
14000 */
14001 asc_dvc->cfg->termination |= TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014002
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014003 switch (scsi_cfg1 & CABLE_DETECT) {
14004 /* TERM_CTL_H: on, TERM_CTL_L: on */
14005 case 0x3:
14006 case 0x7:
14007 case 0xB:
14008 case 0xD:
14009 case 0xE:
14010 case 0xF:
14011 asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L);
14012 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014013
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014014 /* TERM_CTL_H: on, TERM_CTL_L: off */
14015 case 0x1:
14016 case 0x5:
14017 case 0x9:
14018 case 0xA:
14019 case 0xC:
14020 asc_dvc->cfg->termination |= TERM_CTL_H;
14021 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014022
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014023 /* TERM_CTL_H: off, TERM_CTL_L: off */
14024 case 0x2:
14025 case 0x6:
14026 break;
14027 }
14028 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014029
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014030 /*
14031 * Clear any set TERM_CTL_H and TERM_CTL_L bits.
14032 */
14033 scsi_cfg1 &= ~TERM_CTL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014034
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014035 /*
14036 * Invert the TERM_CTL_H and TERM_CTL_L bits and then
14037 * set 'scsi_cfg1'. The TERM_POL bit does not need to be
14038 * referenced, because the hardware internally inverts
14039 * the Termination High and Low bits if TERM_POL is set.
14040 */
14041 scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014042
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014043 /*
14044 * Set SCSI_CFG1 Microcode Default Value
14045 *
14046 * Set filter value and possibly modified termination control
14047 * bits in the Microcode SCSI_CFG1 Register Value.
14048 *
14049 * The microcode will set the SCSI_CFG1 register using this value
14050 * after it is started below.
14051 */
14052 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
14053 FLTR_DISABLE | scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014054
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014055 /*
14056 * Set MEM_CFG Microcode Default Value
14057 *
14058 * The microcode will set the MEM_CFG register using this value
14059 * after it is started below.
14060 *
14061 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
14062 * are defined.
14063 *
14064 * ASC-3550 has 8KB internal memory.
14065 */
14066 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
14067 BIOS_EN | RAM_SZ_8KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014068
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014069 /*
14070 * Set SEL_MASK Microcode Default Value
14071 *
14072 * The microcode will set the SEL_MASK register using this value
14073 * after it is started below.
14074 */
14075 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
14076 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014077
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014078 /*
14079 * Build carrier freelist.
14080 *
14081 * Driver must have already allocated memory and set 'carrier_buf'.
14082 */
14083 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014084
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014085 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
14086 asc_dvc->carr_freelist = NULL;
14087 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
14088 buf_size = ADV_CARRIER_BUFSIZE;
14089 } else {
14090 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
14091 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014092
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014093 do {
14094 /*
14095 * Get physical address of the carrier 'carrp'.
14096 */
14097 contig_len = sizeof(ADV_CARR_T);
14098 carr_paddr =
14099 cpu_to_le32(DvcGetPhyAddr
14100 (asc_dvc, NULL, (uchar *)carrp,
14101 (ADV_SDCNT *)&contig_len,
14102 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014103
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014104 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014105
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014106 /*
14107 * If the current carrier is not physically contiguous, then
14108 * maybe there was a page crossing. Try the next carrier aligned
14109 * start address.
14110 */
14111 if (contig_len < sizeof(ADV_CARR_T)) {
14112 carrp++;
14113 continue;
14114 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014115
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014116 carrp->carr_pa = carr_paddr;
14117 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014118
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014119 /*
14120 * Insert the carrier at the beginning of the freelist.
14121 */
14122 carrp->next_vpa =
14123 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
14124 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014125
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014126 carrp++;
14127 }
14128 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014129
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014130 /*
14131 * Set-up the Host->RISC Initiator Command Queue (ICQ).
14132 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014133
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014134 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
14135 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14136 return ADV_ERROR;
14137 }
14138 asc_dvc->carr_freelist = (ADV_CARR_T *)
14139 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014140
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014141 /*
14142 * The first command issued will be placed in the stopper carrier.
14143 */
14144 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014145
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014146 /*
14147 * Set RISC ICQ physical address start value.
14148 */
14149 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014150
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014151 /*
14152 * Set-up the RISC->Host Initiator Response Queue (IRQ).
14153 */
14154 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
14155 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14156 return ADV_ERROR;
14157 }
14158 asc_dvc->carr_freelist = (ADV_CARR_T *)
14159 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014160
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014161 /*
14162 * The first command completed by the RISC will be placed in
14163 * the stopper.
14164 *
14165 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
14166 * completed the RISC will set the ASC_RQ_STOPPER bit.
14167 */
14168 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014169
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014170 /*
14171 * Set RISC IRQ physical address start value.
14172 */
14173 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
14174 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014175
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014176 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
14177 (ADV_INTR_ENABLE_HOST_INTR |
14178 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014179
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014180 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
14181 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014182
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014183 /* finally, finally, gentlemen, start your engine */
14184 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014185
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014186 /*
14187 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
14188 * Resets should be performed. The RISC has to be running
14189 * to issue a SCSI Bus Reset.
14190 */
14191 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
14192 /*
14193 * If the BIOS Signature is present in memory, restore the
14194 * BIOS Handshake Configuration Table and do not perform
14195 * a SCSI Bus Reset.
14196 */
14197 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
14198 0x55AA) {
14199 /*
14200 * Restore per TID negotiated values.
14201 */
14202 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14203 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14204 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
14205 tagqng_able);
14206 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14207 AdvWriteByteLram(iop_base,
14208 ASC_MC_NUMBER_OF_MAX_CMD + tid,
14209 max_cmd[tid]);
14210 }
14211 } else {
14212 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
14213 warn_code = ASC_WARN_BUSRESET_ERROR;
14214 }
14215 }
14216 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014217
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014218 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014219}
14220
14221/*
14222 * Initialize the ASC-38C0800.
14223 *
14224 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
14225 *
14226 * For a non-fatal error return a warning code. If there are no warnings
14227 * then 0 is returned.
14228 *
14229 * Needed after initialization for error recovery.
14230 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014231static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014232{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014233 AdvPortAddr iop_base;
14234 ushort warn_code;
14235 ADV_DCNT sum;
14236 int begin_addr;
14237 int end_addr;
14238 ushort code_sum;
14239 int word;
14240 int j;
14241 int adv_asc38C0800_expanded_size;
14242 ADV_CARR_T *carrp;
14243 ADV_DCNT contig_len;
14244 ADV_SDCNT buf_size;
14245 ADV_PADDR carr_paddr;
14246 int i;
14247 ushort scsi_cfg1;
14248 uchar byte;
14249 uchar tid;
14250 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
14251 ushort wdtr_able, sdtr_able, tagqng_able;
14252 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070014253
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014254 /* If there is already an error, don't continue. */
14255 if (asc_dvc->err_code != 0) {
14256 return ADV_ERROR;
14257 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014258
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014259 /*
14260 * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
14261 */
14262 if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) {
14263 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
14264 return ADV_ERROR;
14265 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014266
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014267 warn_code = 0;
14268 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014269
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014270 /*
14271 * Save the RISC memory BIOS region before writing the microcode.
14272 * The BIOS may already be loaded and using its RISC LRAM region
14273 * so its region must be saved and restored.
14274 *
14275 * Note: This code makes the assumption, which is currently true,
14276 * that a chip reset does not clear RISC LRAM.
14277 */
14278 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14279 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14280 bios_mem[i]);
14281 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014282
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014283 /*
14284 * Save current per TID negotiated values.
14285 */
14286 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14287 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14288 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
14289 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14290 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
14291 max_cmd[tid]);
14292 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014293
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014294 /*
14295 * RAM BIST (RAM Built-In Self Test)
14296 *
14297 * Address : I/O base + offset 0x38h register (byte).
14298 * Function: Bit 7-6(RW) : RAM mode
14299 * Normal Mode : 0x00
14300 * Pre-test Mode : 0x40
14301 * RAM Test Mode : 0x80
14302 * Bit 5 : unused
14303 * Bit 4(RO) : Done bit
14304 * Bit 3-0(RO) : Status
14305 * Host Error : 0x08
14306 * Int_RAM Error : 0x04
14307 * RISC Error : 0x02
14308 * SCSI Error : 0x01
14309 * No Error : 0x00
14310 *
14311 * Note: RAM BIST code should be put right here, before loading the
14312 * microcode and after saving the RISC memory BIOS region.
14313 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014314
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014315 /*
14316 * LRAM Pre-test
14317 *
14318 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
14319 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
14320 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
14321 * to NORMAL_MODE, return an error too.
14322 */
14323 for (i = 0; i < 2; i++) {
14324 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
14325 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14326 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
14327 if ((byte & RAM_TEST_DONE) == 0
14328 || (byte & 0x0F) != PRE_TEST_VALUE) {
14329 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14330 return ADV_ERROR;
14331 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014332
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014333 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
14334 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14335 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
14336 != NORMAL_VALUE) {
14337 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14338 return ADV_ERROR;
14339 }
14340 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014341
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014342 /*
14343 * LRAM Test - It takes about 1.5 ms to run through the test.
14344 *
14345 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
14346 * If Done bit not set or Status not 0, save register byte, set the
14347 * err_code, and return an error.
14348 */
14349 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
14350 DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014351
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014352 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
14353 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
14354 /* Get here if Done bit not set or Status not 0. */
14355 asc_dvc->bist_err_code = byte; /* for BIOS display message */
14356 asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
14357 return ADV_ERROR;
14358 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014359
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014360 /* We need to reset back to normal mode after LRAM test passes. */
14361 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014362
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014363 /*
14364 * Load the Microcode
14365 *
14366 * Write the microcode image to RISC memory starting at address 0.
14367 *
14368 */
14369 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014370
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014371 /* Assume the following compressed format of the microcode buffer:
14372 *
14373 * 254 word (508 byte) table indexed by byte code followed
14374 * by the following byte codes:
14375 *
14376 * 1-Byte Code:
14377 * 00: Emit word 0 in table.
14378 * 01: Emit word 1 in table.
14379 * .
14380 * FD: Emit word 253 in table.
14381 *
14382 * Multi-Byte Code:
14383 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
14384 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
14385 */
14386 word = 0;
14387 for (i = 253 * 2; i < _adv_asc38C0800_size; i++) {
14388 if (_adv_asc38C0800_buf[i] == 0xff) {
14389 for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++) {
14390 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14391 _adv_asc38C0800_buf
14392 [i +
14393 3] << 8) |
14394 _adv_asc38C0800_buf
14395 [i + 2]));
14396 word++;
14397 }
14398 i += 3;
14399 } else if (_adv_asc38C0800_buf[i] == 0xfe) {
14400 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14401 _adv_asc38C0800_buf
14402 [i +
14403 2] << 8) |
14404 _adv_asc38C0800_buf[i
14405 +
14406 1]));
14407 i += 2;
14408 word++;
14409 } else {
14410 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14411 _adv_asc38C0800_buf[(_adv_asc38C0800_buf[i] * 2) + 1] << 8) | _adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2]));
14412 word++;
14413 }
14414 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014415
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014416 /*
14417 * Set 'word' for later use to clear the rest of memory and save
14418 * the expanded mcode size.
14419 */
14420 word *= 2;
14421 adv_asc38C0800_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014422
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014423 /*
14424 * Clear the rest of ASC-38C0800 Internal RAM (16KB).
14425 */
14426 for (; word < ADV_38C0800_MEMSIZE; word += 2) {
14427 AdvWriteWordAutoIncLram(iop_base, 0);
14428 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014429
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014430 /*
14431 * Verify the microcode checksum.
14432 */
14433 sum = 0;
14434 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014435
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014436 for (word = 0; word < adv_asc38C0800_expanded_size; word += 2) {
14437 sum += AdvReadWordAutoIncLram(iop_base);
14438 }
14439 ASC_DBG2(1, "AdvInitAsc38C0800Driver: word %d, i %d\n", word, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014440
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014441 ASC_DBG2(1,
14442 "AdvInitAsc38C0800Driver: sum 0x%lx, _adv_asc38C0800_chksum 0x%lx\n",
14443 (ulong)sum, (ulong)_adv_asc38C0800_chksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014444
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014445 if (sum != _adv_asc38C0800_chksum) {
14446 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
14447 return ADV_ERROR;
14448 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014449
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014450 /*
14451 * Restore the RISC memory BIOS region.
14452 */
14453 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14454 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14455 bios_mem[i]);
14456 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014457
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014458 /*
14459 * Calculate and write the microcode code checksum to the microcode
14460 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
14461 */
14462 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
14463 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
14464 code_sum = 0;
14465 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
14466 for (word = begin_addr; word < end_addr; word += 2) {
14467 code_sum += AdvReadWordAutoIncLram(iop_base);
14468 }
14469 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014470
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014471 /*
14472 * Read microcode version and date.
14473 */
14474 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
14475 asc_dvc->cfg->mcode_date);
14476 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
14477 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014478
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014479 /*
14480 * Set the chip type to indicate the ASC38C0800.
14481 */
14482 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014483
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014484 /*
14485 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
14486 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
14487 * cable detection and then we are able to read C_DET[3:0].
14488 *
14489 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
14490 * Microcode Default Value' section below.
14491 */
14492 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
14493 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
14494 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014495
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014496 /*
14497 * If the PCI Configuration Command Register "Parity Error Response
14498 * Control" Bit was clear (0), then set the microcode variable
14499 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
14500 * to ignore DMA parity errors.
14501 */
14502 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
14503 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
14504 word |= CONTROL_FLAG_IGNORE_PERR;
14505 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
14506 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014507
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014508 /*
14509 * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
14510 * bits for the default FIFO threshold.
14511 *
14512 * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
14513 *
14514 * For DMA Errata #4 set the BC_THRESH_ENB bit.
14515 */
14516 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
14517 BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH |
14518 READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014519
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014520 /*
14521 * Microcode operating variables for WDTR, SDTR, and command tag
Matthew Wilcox47d853c2007-07-26 11:41:33 -040014522 * queuing will be set in slave_configure() based on what a
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014523 * device reports it is capable of in Inquiry byte 7.
14524 *
14525 * If SCSI Bus Resets have been disabled, then directly set
14526 * SDTR and WDTR from the EEPROM configuration. This will allow
14527 * the BIOS and warm boot to work without a SCSI bus hang on
14528 * the Inquiry caused by host and target mismatched DTR values.
14529 * Without the SCSI Bus Reset, before an Inquiry a device can't
14530 * be assumed to be in Asynchronous, Narrow mode.
14531 */
14532 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
14533 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
14534 asc_dvc->wdtr_able);
14535 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
14536 asc_dvc->sdtr_able);
14537 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014538
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014539 /*
14540 * Set microcode operating variables for DISC and SDTR_SPEED1,
14541 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
14542 * configuration values.
14543 *
14544 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
14545 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
14546 * without determining here whether the device supports SDTR.
14547 */
14548 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
14549 asc_dvc->cfg->disc_enable);
14550 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
14551 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
14552 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
14553 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014554
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014555 /*
14556 * Set SCSI_CFG0 Microcode Default Value.
14557 *
14558 * The microcode will set the SCSI_CFG0 register using this value
14559 * after it is started below.
14560 */
14561 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
14562 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
14563 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014564
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014565 /*
14566 * Determine SCSI_CFG1 Microcode Default Value.
14567 *
14568 * The microcode will set the SCSI_CFG1 register using this value
14569 * after it is started below.
14570 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014571
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014572 /* Read current SCSI_CFG1 Register value. */
14573 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014574
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014575 /*
14576 * If the internal narrow cable is reversed all of the SCSI_CTRL
14577 * register signals will be set. Check for and return an error if
14578 * this condition is found.
14579 */
14580 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
14581 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
14582 return ADV_ERROR;
14583 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014584
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014585 /*
14586 * All kind of combinations of devices attached to one of four connectors
14587 * are acceptable except HVD device attached. For example, LVD device can
14588 * be attached to SE connector while SE device attached to LVD connector.
14589 * If LVD device attached to SE connector, it only runs up to Ultra speed.
14590 *
14591 * If an HVD device is attached to one of LVD connectors, return an error.
14592 * However, there is no way to detect HVD device attached to SE connectors.
14593 */
14594 if (scsi_cfg1 & HVD) {
14595 asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
14596 return ADV_ERROR;
14597 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014598
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014599 /*
14600 * If either SE or LVD automatic termination control is enabled, then
14601 * set the termination value based on a table listed in a_condor.h.
14602 *
14603 * If manual termination was specified with an EEPROM setting then
14604 * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready to
14605 * be 'ored' into SCSI_CFG1.
14606 */
14607 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
14608 /* SE automatic termination control is enabled. */
14609 switch (scsi_cfg1 & C_DET_SE) {
14610 /* TERM_SE_HI: on, TERM_SE_LO: on */
14611 case 0x1:
14612 case 0x2:
14613 case 0x3:
14614 asc_dvc->cfg->termination |= TERM_SE;
14615 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014616
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014617 /* TERM_SE_HI: on, TERM_SE_LO: off */
14618 case 0x0:
14619 asc_dvc->cfg->termination |= TERM_SE_HI;
14620 break;
14621 }
14622 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014623
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014624 if ((asc_dvc->cfg->termination & TERM_LVD) == 0) {
14625 /* LVD automatic termination control is enabled. */
14626 switch (scsi_cfg1 & C_DET_LVD) {
14627 /* TERM_LVD_HI: on, TERM_LVD_LO: on */
14628 case 0x4:
14629 case 0x8:
14630 case 0xC:
14631 asc_dvc->cfg->termination |= TERM_LVD;
14632 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014633
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014634 /* TERM_LVD_HI: off, TERM_LVD_LO: off */
14635 case 0x0:
14636 break;
14637 }
14638 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014639
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014640 /*
14641 * Clear any set TERM_SE and TERM_LVD bits.
14642 */
14643 scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014644
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014645 /*
14646 * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
14647 */
14648 scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014649
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014650 /*
14651 * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE bits
14652 * and set possibly modified termination control bits in the Microcode
14653 * SCSI_CFG1 Register Value.
14654 */
14655 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014656
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014657 /*
14658 * Set SCSI_CFG1 Microcode Default Value
14659 *
14660 * Set possibly modified termination control and reset DIS_TERM_DRV
14661 * bits in the Microcode SCSI_CFG1 Register Value.
14662 *
14663 * The microcode will set the SCSI_CFG1 register using this value
14664 * after it is started below.
14665 */
14666 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014667
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014668 /*
14669 * Set MEM_CFG Microcode Default Value
14670 *
14671 * The microcode will set the MEM_CFG register using this value
14672 * after it is started below.
14673 *
14674 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
14675 * are defined.
14676 *
14677 * ASC-38C0800 has 16KB internal memory.
14678 */
14679 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
14680 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014681
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014682 /*
14683 * Set SEL_MASK Microcode Default Value
14684 *
14685 * The microcode will set the SEL_MASK register using this value
14686 * after it is started below.
14687 */
14688 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
14689 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014690
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014691 /*
14692 * Build the carrier freelist.
14693 *
14694 * Driver must have already allocated memory and set 'carrier_buf'.
14695 */
14696 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014697
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014698 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
14699 asc_dvc->carr_freelist = NULL;
14700 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
14701 buf_size = ADV_CARRIER_BUFSIZE;
14702 } else {
14703 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
14704 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014705
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014706 do {
14707 /*
14708 * Get physical address for the carrier 'carrp'.
14709 */
14710 contig_len = sizeof(ADV_CARR_T);
14711 carr_paddr =
14712 cpu_to_le32(DvcGetPhyAddr
14713 (asc_dvc, NULL, (uchar *)carrp,
14714 (ADV_SDCNT *)&contig_len,
14715 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014716
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014717 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014718
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014719 /*
14720 * If the current carrier is not physically contiguous, then
14721 * maybe there was a page crossing. Try the next carrier aligned
14722 * start address.
14723 */
14724 if (contig_len < sizeof(ADV_CARR_T)) {
14725 carrp++;
14726 continue;
14727 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014728
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014729 carrp->carr_pa = carr_paddr;
14730 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014731
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014732 /*
14733 * Insert the carrier at the beginning of the freelist.
14734 */
14735 carrp->next_vpa =
14736 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
14737 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014738
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014739 carrp++;
14740 }
14741 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014742
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014743 /*
14744 * Set-up the Host->RISC Initiator Command Queue (ICQ).
14745 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014746
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014747 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
14748 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14749 return ADV_ERROR;
14750 }
14751 asc_dvc->carr_freelist = (ADV_CARR_T *)
14752 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014753
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014754 /*
14755 * The first command issued will be placed in the stopper carrier.
14756 */
14757 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014758
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014759 /*
14760 * Set RISC ICQ physical address start value.
14761 * carr_pa is LE, must be native before write
14762 */
14763 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014764
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014765 /*
14766 * Set-up the RISC->Host Initiator Response Queue (IRQ).
14767 */
14768 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
14769 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14770 return ADV_ERROR;
14771 }
14772 asc_dvc->carr_freelist = (ADV_CARR_T *)
14773 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014774
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014775 /*
14776 * The first command completed by the RISC will be placed in
14777 * the stopper.
14778 *
14779 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
14780 * completed the RISC will set the ASC_RQ_STOPPER bit.
14781 */
14782 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014783
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014784 /*
14785 * Set RISC IRQ physical address start value.
14786 *
14787 * carr_pa is LE, must be native before write *
14788 */
14789 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
14790 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014791
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014792 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
14793 (ADV_INTR_ENABLE_HOST_INTR |
14794 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014795
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014796 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
14797 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014798
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014799 /* finally, finally, gentlemen, start your engine */
14800 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014801
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014802 /*
14803 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
14804 * Resets should be performed. The RISC has to be running
14805 * to issue a SCSI Bus Reset.
14806 */
14807 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
14808 /*
14809 * If the BIOS Signature is present in memory, restore the
14810 * BIOS Handshake Configuration Table and do not perform
14811 * a SCSI Bus Reset.
14812 */
14813 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
14814 0x55AA) {
14815 /*
14816 * Restore per TID negotiated values.
14817 */
14818 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14819 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14820 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
14821 tagqng_able);
14822 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14823 AdvWriteByteLram(iop_base,
14824 ASC_MC_NUMBER_OF_MAX_CMD + tid,
14825 max_cmd[tid]);
14826 }
14827 } else {
14828 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
14829 warn_code = ASC_WARN_BUSRESET_ERROR;
14830 }
14831 }
14832 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014833
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014834 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014835}
14836
14837/*
14838 * Initialize the ASC-38C1600.
14839 *
14840 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
14841 *
14842 * For a non-fatal error return a warning code. If there are no warnings
14843 * then 0 is returned.
14844 *
14845 * Needed after initialization for error recovery.
14846 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014847static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014848{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014849 AdvPortAddr iop_base;
14850 ushort warn_code;
14851 ADV_DCNT sum;
14852 int begin_addr;
14853 int end_addr;
14854 ushort code_sum;
14855 long word;
14856 int j;
14857 int adv_asc38C1600_expanded_size;
14858 ADV_CARR_T *carrp;
14859 ADV_DCNT contig_len;
14860 ADV_SDCNT buf_size;
14861 ADV_PADDR carr_paddr;
14862 int i;
14863 ushort scsi_cfg1;
14864 uchar byte;
14865 uchar tid;
14866 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
14867 ushort wdtr_able, sdtr_able, ppr_able, tagqng_able;
14868 uchar max_cmd[ASC_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070014869
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014870 /* If there is already an error, don't continue. */
14871 if (asc_dvc->err_code != 0) {
14872 return ADV_ERROR;
14873 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014874
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014875 /*
14876 * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600.
14877 */
14878 if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
14879 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
14880 return ADV_ERROR;
14881 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014882
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014883 warn_code = 0;
14884 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014885
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014886 /*
14887 * Save the RISC memory BIOS region before writing the microcode.
14888 * The BIOS may already be loaded and using its RISC LRAM region
14889 * so its region must be saved and restored.
14890 *
14891 * Note: This code makes the assumption, which is currently true,
14892 * that a chip reset does not clear RISC LRAM.
14893 */
14894 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14895 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14896 bios_mem[i]);
14897 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014898
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014899 /*
14900 * Save current per TID negotiated values.
14901 */
14902 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14903 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14904 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
14905 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
14906 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
14907 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
14908 max_cmd[tid]);
14909 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014910
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014911 /*
14912 * RAM BIST (Built-In Self Test)
14913 *
14914 * Address : I/O base + offset 0x38h register (byte).
14915 * Function: Bit 7-6(RW) : RAM mode
14916 * Normal Mode : 0x00
14917 * Pre-test Mode : 0x40
14918 * RAM Test Mode : 0x80
14919 * Bit 5 : unused
14920 * Bit 4(RO) : Done bit
14921 * Bit 3-0(RO) : Status
14922 * Host Error : 0x08
14923 * Int_RAM Error : 0x04
14924 * RISC Error : 0x02
14925 * SCSI Error : 0x01
14926 * No Error : 0x00
14927 *
14928 * Note: RAM BIST code should be put right here, before loading the
14929 * microcode and after saving the RISC memory BIOS region.
14930 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014931
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014932 /*
14933 * LRAM Pre-test
14934 *
14935 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
14936 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
14937 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
14938 * to NORMAL_MODE, return an error too.
14939 */
14940 for (i = 0; i < 2; i++) {
14941 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
14942 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14943 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
14944 if ((byte & RAM_TEST_DONE) == 0
14945 || (byte & 0x0F) != PRE_TEST_VALUE) {
14946 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14947 return ADV_ERROR;
14948 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014949
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014950 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
14951 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14952 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
14953 != NORMAL_VALUE) {
14954 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14955 return ADV_ERROR;
14956 }
14957 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014958
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014959 /*
14960 * LRAM Test - It takes about 1.5 ms to run through the test.
14961 *
14962 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
14963 * If Done bit not set or Status not 0, save register byte, set the
14964 * err_code, and return an error.
14965 */
14966 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
14967 DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014968
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014969 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
14970 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
14971 /* Get here if Done bit not set or Status not 0. */
14972 asc_dvc->bist_err_code = byte; /* for BIOS display message */
14973 asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
14974 return ADV_ERROR;
14975 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014976
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014977 /* We need to reset back to normal mode after LRAM test passes. */
14978 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014979
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014980 /*
14981 * Load the Microcode
14982 *
14983 * Write the microcode image to RISC memory starting at address 0.
14984 *
14985 */
14986 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014987
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014988 /*
14989 * Assume the following compressed format of the microcode buffer:
14990 *
14991 * 254 word (508 byte) table indexed by byte code followed
14992 * by the following byte codes:
14993 *
14994 * 1-Byte Code:
14995 * 00: Emit word 0 in table.
14996 * 01: Emit word 1 in table.
14997 * .
14998 * FD: Emit word 253 in table.
14999 *
15000 * Multi-Byte Code:
15001 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
15002 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
15003 */
15004 word = 0;
15005 for (i = 253 * 2; i < _adv_asc38C1600_size; i++) {
15006 if (_adv_asc38C1600_buf[i] == 0xff) {
15007 for (j = 0; j < _adv_asc38C1600_buf[i + 1]; j++) {
15008 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15009 _adv_asc38C1600_buf
15010 [i +
15011 3] << 8) |
15012 _adv_asc38C1600_buf
15013 [i + 2]));
15014 word++;
15015 }
15016 i += 3;
15017 } else if (_adv_asc38C1600_buf[i] == 0xfe) {
15018 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15019 _adv_asc38C1600_buf
15020 [i +
15021 2] << 8) |
15022 _adv_asc38C1600_buf[i
15023 +
15024 1]));
15025 i += 2;
15026 word++;
15027 } else {
15028 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15029 _adv_asc38C1600_buf[(_adv_asc38C1600_buf[i] * 2) + 1] << 8) | _adv_asc38C1600_buf[_adv_asc38C1600_buf[i] * 2]));
15030 word++;
15031 }
15032 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015033
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015034 /*
15035 * Set 'word' for later use to clear the rest of memory and save
15036 * the expanded mcode size.
15037 */
15038 word *= 2;
15039 adv_asc38C1600_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015040
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015041 /*
15042 * Clear the rest of ASC-38C1600 Internal RAM (32KB).
15043 */
15044 for (; word < ADV_38C1600_MEMSIZE; word += 2) {
15045 AdvWriteWordAutoIncLram(iop_base, 0);
15046 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015047
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015048 /*
15049 * Verify the microcode checksum.
15050 */
15051 sum = 0;
15052 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015053
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015054 for (word = 0; word < adv_asc38C1600_expanded_size; word += 2) {
15055 sum += AdvReadWordAutoIncLram(iop_base);
15056 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015057
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015058 if (sum != _adv_asc38C1600_chksum) {
15059 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
15060 return ADV_ERROR;
15061 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015062
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015063 /*
15064 * Restore the RISC memory BIOS region.
15065 */
15066 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
15067 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
15068 bios_mem[i]);
15069 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015070
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015071 /*
15072 * Calculate and write the microcode code checksum to the microcode
15073 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
15074 */
15075 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
15076 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
15077 code_sum = 0;
15078 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
15079 for (word = begin_addr; word < end_addr; word += 2) {
15080 code_sum += AdvReadWordAutoIncLram(iop_base);
15081 }
15082 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015083
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015084 /*
15085 * Read microcode version and date.
15086 */
15087 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
15088 asc_dvc->cfg->mcode_date);
15089 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
15090 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015091
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015092 /*
15093 * Set the chip type to indicate the ASC38C1600.
15094 */
15095 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015096
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015097 /*
15098 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
15099 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
15100 * cable detection and then we are able to read C_DET[3:0].
15101 *
15102 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
15103 * Microcode Default Value' section below.
15104 */
15105 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
15106 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
15107 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015108
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015109 /*
15110 * If the PCI Configuration Command Register "Parity Error Response
15111 * Control" Bit was clear (0), then set the microcode variable
15112 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
15113 * to ignore DMA parity errors.
15114 */
15115 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
15116 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15117 word |= CONTROL_FLAG_IGNORE_PERR;
15118 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15119 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015120
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015121 /*
15122 * If the BIOS control flag AIPP (Asynchronous Information
15123 * Phase Protection) disable bit is not set, then set the firmware
15124 * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable
15125 * AIPP checking and encoding.
15126 */
15127 if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) {
15128 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15129 word |= CONTROL_FLAG_ENABLE_AIPP;
15130 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15131 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015132
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015133 /*
15134 * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4],
15135 * and START_CTL_TH [3:2].
15136 */
15137 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
15138 FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015139
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015140 /*
15141 * Microcode operating variables for WDTR, SDTR, and command tag
Matthew Wilcox47d853c2007-07-26 11:41:33 -040015142 * queuing will be set in slave_configure() based on what a
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015143 * device reports it is capable of in Inquiry byte 7.
15144 *
15145 * If SCSI Bus Resets have been disabled, then directly set
15146 * SDTR and WDTR from the EEPROM configuration. This will allow
15147 * the BIOS and warm boot to work without a SCSI bus hang on
15148 * the Inquiry caused by host and target mismatched DTR values.
15149 * Without the SCSI Bus Reset, before an Inquiry a device can't
15150 * be assumed to be in Asynchronous, Narrow mode.
15151 */
15152 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
15153 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
15154 asc_dvc->wdtr_able);
15155 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
15156 asc_dvc->sdtr_able);
15157 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015158
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015159 /*
15160 * Set microcode operating variables for DISC and SDTR_SPEED1,
15161 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
15162 * configuration values.
15163 *
15164 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
15165 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
15166 * without determining here whether the device supports SDTR.
15167 */
15168 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
15169 asc_dvc->cfg->disc_enable);
15170 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
15171 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
15172 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
15173 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015174
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015175 /*
15176 * Set SCSI_CFG0 Microcode Default Value.
15177 *
15178 * The microcode will set the SCSI_CFG0 register using this value
15179 * after it is started below.
15180 */
15181 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
15182 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
15183 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015184
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015185 /*
15186 * Calculate SCSI_CFG1 Microcode Default Value.
15187 *
15188 * The microcode will set the SCSI_CFG1 register using this value
15189 * after it is started below.
15190 *
15191 * Each ASC-38C1600 function has only two cable detect bits.
15192 * The bus mode override bits are in IOPB_SOFT_OVER_WR.
15193 */
15194 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015195
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015196 /*
15197 * If the cable is reversed all of the SCSI_CTRL register signals
15198 * will be set. Check for and return an error if this condition is
15199 * found.
15200 */
15201 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
15202 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
15203 return ADV_ERROR;
15204 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015205
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015206 /*
15207 * Each ASC-38C1600 function has two connectors. Only an HVD device
15208 * can not be connected to either connector. An LVD device or SE device
15209 * may be connected to either connecor. If an SE device is connected,
15210 * then at most Ultra speed (20 Mhz) can be used on both connectors.
15211 *
15212 * If an HVD device is attached, return an error.
15213 */
15214 if (scsi_cfg1 & HVD) {
15215 asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
15216 return ADV_ERROR;
15217 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015218
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015219 /*
15220 * Each function in the ASC-38C1600 uses only the SE cable detect and
15221 * termination because there are two connectors for each function. Each
15222 * function may use either LVD or SE mode. Corresponding the SE automatic
15223 * termination control EEPROM bits are used for each function. Each
15224 * function has its own EEPROM. If SE automatic control is enabled for
15225 * the function, then set the termination value based on a table listed
15226 * in a_condor.h.
15227 *
15228 * If manual termination is specified in the EEPROM for the function,
15229 * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is
15230 * ready to be 'ored' into SCSI_CFG1.
15231 */
15232 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
15233 /* SE automatic termination control is enabled. */
15234 switch (scsi_cfg1 & C_DET_SE) {
15235 /* TERM_SE_HI: on, TERM_SE_LO: on */
15236 case 0x1:
15237 case 0x2:
15238 case 0x3:
15239 asc_dvc->cfg->termination |= TERM_SE;
15240 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015241
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015242 case 0x0:
15243 if (ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) == 0) {
15244 /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */
15245 } else {
15246 /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */
15247 asc_dvc->cfg->termination |= TERM_SE_HI;
15248 }
15249 break;
15250 }
15251 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015252
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015253 /*
15254 * Clear any set TERM_SE bits.
15255 */
15256 scsi_cfg1 &= ~TERM_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015257
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015258 /*
15259 * Invert the TERM_SE bits and then set 'scsi_cfg1'.
15260 */
15261 scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015262
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015263 /*
15264 * Clear Big Endian and Terminator Polarity bits and set possibly
15265 * modified termination control bits in the Microcode SCSI_CFG1
15266 * Register Value.
15267 *
15268 * Big Endian bit is not used even on big endian machines.
15269 */
15270 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015271
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015272 /*
15273 * Set SCSI_CFG1 Microcode Default Value
15274 *
15275 * Set possibly modified termination control bits in the Microcode
15276 * SCSI_CFG1 Register Value.
15277 *
15278 * The microcode will set the SCSI_CFG1 register using this value
15279 * after it is started below.
15280 */
15281 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015282
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015283 /*
15284 * Set MEM_CFG Microcode Default Value
15285 *
15286 * The microcode will set the MEM_CFG register using this value
15287 * after it is started below.
15288 *
15289 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
15290 * are defined.
15291 *
15292 * ASC-38C1600 has 32KB internal memory.
15293 *
15294 * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come
15295 * out a special 16K Adv Library and Microcode version. After the issue
15296 * resolved, we should turn back to the 32K support. Both a_condor.h and
15297 * mcode.sas files also need to be updated.
15298 *
15299 * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
15300 * BIOS_EN | RAM_SZ_32KB);
15301 */
15302 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
15303 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015304
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015305 /*
15306 * Set SEL_MASK Microcode Default Value
15307 *
15308 * The microcode will set the SEL_MASK register using this value
15309 * after it is started below.
15310 */
15311 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
15312 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015313
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015314 /*
15315 * Build the carrier freelist.
15316 *
15317 * Driver must have already allocated memory and set 'carrier_buf'.
15318 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015319
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015320 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015321
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015322 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
15323 asc_dvc->carr_freelist = NULL;
15324 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
15325 buf_size = ADV_CARRIER_BUFSIZE;
15326 } else {
15327 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
15328 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015329
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015330 do {
15331 /*
15332 * Get physical address for the carrier 'carrp'.
15333 */
15334 contig_len = sizeof(ADV_CARR_T);
15335 carr_paddr =
15336 cpu_to_le32(DvcGetPhyAddr
15337 (asc_dvc, NULL, (uchar *)carrp,
15338 (ADV_SDCNT *)&contig_len,
15339 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015340
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015341 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015342
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015343 /*
15344 * If the current carrier is not physically contiguous, then
15345 * maybe there was a page crossing. Try the next carrier aligned
15346 * start address.
15347 */
15348 if (contig_len < sizeof(ADV_CARR_T)) {
15349 carrp++;
15350 continue;
15351 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015352
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015353 carrp->carr_pa = carr_paddr;
15354 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015355
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015356 /*
15357 * Insert the carrier at the beginning of the freelist.
15358 */
15359 carrp->next_vpa =
15360 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
15361 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015362
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015363 carrp++;
15364 }
15365 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015366
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015367 /*
15368 * Set-up the Host->RISC Initiator Command Queue (ICQ).
15369 */
15370 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
15371 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
15372 return ADV_ERROR;
15373 }
15374 asc_dvc->carr_freelist = (ADV_CARR_T *)
15375 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015376
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015377 /*
15378 * The first command issued will be placed in the stopper carrier.
15379 */
15380 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015381
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015382 /*
15383 * Set RISC ICQ physical address start value. Initialize the
15384 * COMMA register to the same value otherwise the RISC will
15385 * prematurely detect a command is available.
15386 */
15387 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
15388 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
15389 le32_to_cpu(asc_dvc->icq_sp->carr_pa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015390
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015391 /*
15392 * Set-up the RISC->Host Initiator Response Queue (IRQ).
15393 */
15394 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
15395 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
15396 return ADV_ERROR;
15397 }
15398 asc_dvc->carr_freelist = (ADV_CARR_T *)
15399 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015400
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015401 /*
15402 * The first command completed by the RISC will be placed in
15403 * the stopper.
15404 *
15405 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
15406 * completed the RISC will set the ASC_RQ_STOPPER bit.
15407 */
15408 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015409
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015410 /*
15411 * Set RISC IRQ physical address start value.
15412 */
15413 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
15414 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015415
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015416 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
15417 (ADV_INTR_ENABLE_HOST_INTR |
15418 ADV_INTR_ENABLE_GLOBAL_INTR));
15419 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
15420 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015421
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015422 /* finally, finally, gentlemen, start your engine */
15423 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015424
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015425 /*
15426 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
15427 * Resets should be performed. The RISC has to be running
15428 * to issue a SCSI Bus Reset.
15429 */
15430 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
15431 /*
15432 * If the BIOS Signature is present in memory, restore the
15433 * per TID microcode operating variables.
15434 */
15435 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
15436 0x55AA) {
15437 /*
15438 * Restore per TID negotiated values.
15439 */
15440 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
15441 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
15442 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
15443 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
15444 tagqng_able);
15445 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
15446 AdvWriteByteLram(iop_base,
15447 ASC_MC_NUMBER_OF_MAX_CMD + tid,
15448 max_cmd[tid]);
15449 }
15450 } else {
15451 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
15452 warn_code = ASC_WARN_BUSRESET_ERROR;
15453 }
15454 }
15455 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015456
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015457 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015458}
15459
15460/*
15461 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
15462 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
15463 * all of this is done.
15464 *
15465 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
15466 *
15467 * For a non-fatal error return a warning code. If there are no warnings
15468 * then 0 is returned.
15469 *
15470 * Note: Chip is stopped on entry.
15471 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015472static int __devinit AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070015473{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015474 AdvPortAddr iop_base;
15475 ushort warn_code;
15476 ADVEEP_3550_CONFIG eep_config;
15477 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015478
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015479 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015480
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015481 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015482
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015483 /*
15484 * Read the board's EEPROM configuration.
15485 *
15486 * Set default values if a bad checksum is found.
15487 */
15488 if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum) {
15489 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015490
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015491 /*
15492 * Set EEPROM default values.
15493 */
15494 for (i = 0; i < sizeof(ADVEEP_3550_CONFIG); i++) {
15495 *((uchar *)&eep_config + i) =
15496 *((uchar *)&Default_3550_EEPROM_Config + i);
15497 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015498
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015499 /*
15500 * Assume the 6 byte board serial number that was read
15501 * from EEPROM is correct even if the EEPROM checksum
15502 * failed.
15503 */
15504 eep_config.serial_number_word3 =
15505 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015506
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015507 eep_config.serial_number_word2 =
15508 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015509
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015510 eep_config.serial_number_word1 =
15511 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015512
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015513 AdvSet3550EEPConfig(iop_base, &eep_config);
15514 }
15515 /*
15516 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
15517 * EEPROM configuration that was read.
15518 *
15519 * This is the mapping of EEPROM fields to Adv Library fields.
15520 */
15521 asc_dvc->wdtr_able = eep_config.wdtr_able;
15522 asc_dvc->sdtr_able = eep_config.sdtr_able;
15523 asc_dvc->ultra_able = eep_config.ultra_able;
15524 asc_dvc->tagqng_able = eep_config.tagqng_able;
15525 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
15526 asc_dvc->max_host_qng = eep_config.max_host_qng;
15527 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
15528 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
15529 asc_dvc->start_motor = eep_config.start_motor;
15530 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
15531 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
15532 asc_dvc->no_scam = eep_config.scam_tolerant;
15533 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
15534 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
15535 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015536
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015537 /*
15538 * Set the host maximum queuing (max. 253, min. 16) and the per device
15539 * maximum queuing (max. 63, min. 4).
15540 */
15541 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
15542 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15543 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
15544 /* If the value is zero, assume it is uninitialized. */
15545 if (eep_config.max_host_qng == 0) {
15546 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15547 } else {
15548 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
15549 }
15550 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015551
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015552 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
15553 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15554 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
15555 /* If the value is zero, assume it is uninitialized. */
15556 if (eep_config.max_dvc_qng == 0) {
15557 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15558 } else {
15559 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
15560 }
15561 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015562
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015563 /*
15564 * If 'max_dvc_qng' is greater than 'max_host_qng', then
15565 * set 'max_dvc_qng' to 'max_host_qng'.
15566 */
15567 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
15568 eep_config.max_dvc_qng = eep_config.max_host_qng;
15569 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015570
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015571 /*
15572 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
15573 * values based on possibly adjusted EEPROM values.
15574 */
15575 asc_dvc->max_host_qng = eep_config.max_host_qng;
15576 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015577
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015578 /*
15579 * If the EEPROM 'termination' field is set to automatic (0), then set
15580 * the ADV_DVC_CFG 'termination' field to automatic also.
15581 *
15582 * If the termination is specified with a non-zero 'termination'
15583 * value check that a legal value is set and set the ADV_DVC_CFG
15584 * 'termination' field appropriately.
15585 */
15586 if (eep_config.termination == 0) {
15587 asc_dvc->cfg->termination = 0; /* auto termination */
15588 } else {
15589 /* Enable manual control with low off / high off. */
15590 if (eep_config.termination == 1) {
15591 asc_dvc->cfg->termination = TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015592
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015593 /* Enable manual control with low off / high on. */
15594 } else if (eep_config.termination == 2) {
15595 asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015596
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015597 /* Enable manual control with low on / high on. */
15598 } else if (eep_config.termination == 3) {
15599 asc_dvc->cfg->termination =
15600 TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L;
15601 } else {
15602 /*
15603 * The EEPROM 'termination' field contains a bad value. Use
15604 * automatic termination instead.
15605 */
15606 asc_dvc->cfg->termination = 0;
15607 warn_code |= ASC_WARN_EEPROM_TERMINATION;
15608 }
15609 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015610
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015611 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015612}
15613
15614/*
15615 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
15616 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
15617 * all of this is done.
15618 *
15619 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
15620 *
15621 * For a non-fatal error return a warning code. If there are no warnings
15622 * then 0 is returned.
15623 *
15624 * Note: Chip is stopped on entry.
15625 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015626static int __devinit AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070015627{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015628 AdvPortAddr iop_base;
15629 ushort warn_code;
15630 ADVEEP_38C0800_CONFIG eep_config;
15631 int i;
15632 uchar tid, termination;
15633 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015634
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015635 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015636
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015637 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015638
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015639 /*
15640 * Read the board's EEPROM configuration.
15641 *
15642 * Set default values if a bad checksum is found.
15643 */
15644 if (AdvGet38C0800EEPConfig(iop_base, &eep_config) !=
15645 eep_config.check_sum) {
15646 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015647
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015648 /*
15649 * Set EEPROM default values.
15650 */
15651 for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++) {
15652 *((uchar *)&eep_config + i) =
15653 *((uchar *)&Default_38C0800_EEPROM_Config + i);
15654 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015655
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015656 /*
15657 * Assume the 6 byte board serial number that was read
15658 * from EEPROM is correct even if the EEPROM checksum
15659 * failed.
15660 */
15661 eep_config.serial_number_word3 =
15662 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015663
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015664 eep_config.serial_number_word2 =
15665 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015666
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015667 eep_config.serial_number_word1 =
15668 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015669
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015670 AdvSet38C0800EEPConfig(iop_base, &eep_config);
15671 }
15672 /*
15673 * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
15674 * EEPROM configuration that was read.
15675 *
15676 * This is the mapping of EEPROM fields to Adv Library fields.
15677 */
15678 asc_dvc->wdtr_able = eep_config.wdtr_able;
15679 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
15680 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
15681 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
15682 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
15683 asc_dvc->tagqng_able = eep_config.tagqng_able;
15684 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
15685 asc_dvc->max_host_qng = eep_config.max_host_qng;
15686 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
15687 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
15688 asc_dvc->start_motor = eep_config.start_motor;
15689 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
15690 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
15691 asc_dvc->no_scam = eep_config.scam_tolerant;
15692 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
15693 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
15694 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015695
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015696 /*
15697 * For every Target ID if any of its 'sdtr_speed[1234]' bits
15698 * are set, then set an 'sdtr_able' bit for it.
15699 */
15700 asc_dvc->sdtr_able = 0;
15701 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
15702 if (tid == 0) {
15703 sdtr_speed = asc_dvc->sdtr_speed1;
15704 } else if (tid == 4) {
15705 sdtr_speed = asc_dvc->sdtr_speed2;
15706 } else if (tid == 8) {
15707 sdtr_speed = asc_dvc->sdtr_speed3;
15708 } else if (tid == 12) {
15709 sdtr_speed = asc_dvc->sdtr_speed4;
15710 }
15711 if (sdtr_speed & ADV_MAX_TID) {
15712 asc_dvc->sdtr_able |= (1 << tid);
15713 }
15714 sdtr_speed >>= 4;
15715 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015716
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015717 /*
15718 * Set the host maximum queuing (max. 253, min. 16) and the per device
15719 * maximum queuing (max. 63, min. 4).
15720 */
15721 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
15722 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15723 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
15724 /* If the value is zero, assume it is uninitialized. */
15725 if (eep_config.max_host_qng == 0) {
15726 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15727 } else {
15728 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
15729 }
15730 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015731
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015732 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
15733 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15734 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
15735 /* If the value is zero, assume it is uninitialized. */
15736 if (eep_config.max_dvc_qng == 0) {
15737 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15738 } else {
15739 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
15740 }
15741 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015742
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015743 /*
15744 * If 'max_dvc_qng' is greater than 'max_host_qng', then
15745 * set 'max_dvc_qng' to 'max_host_qng'.
15746 */
15747 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
15748 eep_config.max_dvc_qng = eep_config.max_host_qng;
15749 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015750
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015751 /*
15752 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
15753 * values based on possibly adjusted EEPROM values.
15754 */
15755 asc_dvc->max_host_qng = eep_config.max_host_qng;
15756 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015757
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015758 /*
15759 * If the EEPROM 'termination' field is set to automatic (0), then set
15760 * the ADV_DVC_CFG 'termination' field to automatic also.
15761 *
15762 * If the termination is specified with a non-zero 'termination'
15763 * value check that a legal value is set and set the ADV_DVC_CFG
15764 * 'termination' field appropriately.
15765 */
15766 if (eep_config.termination_se == 0) {
15767 termination = 0; /* auto termination for SE */
15768 } else {
15769 /* Enable manual control with low off / high off. */
15770 if (eep_config.termination_se == 1) {
15771 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015772
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015773 /* Enable manual control with low off / high on. */
15774 } else if (eep_config.termination_se == 2) {
15775 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015776
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015777 /* Enable manual control with low on / high on. */
15778 } else if (eep_config.termination_se == 3) {
15779 termination = TERM_SE;
15780 } else {
15781 /*
15782 * The EEPROM 'termination_se' field contains a bad value.
15783 * Use automatic termination instead.
15784 */
15785 termination = 0;
15786 warn_code |= ASC_WARN_EEPROM_TERMINATION;
15787 }
15788 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015789
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015790 if (eep_config.termination_lvd == 0) {
15791 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
15792 } else {
15793 /* Enable manual control with low off / high off. */
15794 if (eep_config.termination_lvd == 1) {
15795 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015796
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015797 /* Enable manual control with low off / high on. */
15798 } else if (eep_config.termination_lvd == 2) {
15799 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015800
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015801 /* Enable manual control with low on / high on. */
15802 } else if (eep_config.termination_lvd == 3) {
15803 asc_dvc->cfg->termination = termination | TERM_LVD;
15804 } else {
15805 /*
15806 * The EEPROM 'termination_lvd' field contains a bad value.
15807 * Use automatic termination instead.
15808 */
15809 asc_dvc->cfg->termination = termination;
15810 warn_code |= ASC_WARN_EEPROM_TERMINATION;
15811 }
15812 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015813
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015814 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015815}
15816
15817/*
15818 * Read the board's EEPROM configuration. Set fields in ASC_DVC_VAR and
15819 * ASC_DVC_CFG based on the EEPROM settings. The chip is stopped while
15820 * all of this is done.
15821 *
15822 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
15823 *
15824 * For a non-fatal error return a warning code. If there are no warnings
15825 * then 0 is returned.
15826 *
15827 * Note: Chip is stopped on entry.
15828 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015829static int __devinit AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070015830{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015831 AdvPortAddr iop_base;
15832 ushort warn_code;
15833 ADVEEP_38C1600_CONFIG eep_config;
15834 int i;
15835 uchar tid, termination;
15836 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015837
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015838 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015839
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015840 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015841
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015842 /*
15843 * Read the board's EEPROM configuration.
15844 *
15845 * Set default values if a bad checksum is found.
15846 */
15847 if (AdvGet38C1600EEPConfig(iop_base, &eep_config) !=
15848 eep_config.check_sum) {
15849 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015850
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015851 /*
15852 * Set EEPROM default values.
15853 */
15854 for (i = 0; i < sizeof(ADVEEP_38C1600_CONFIG); i++) {
15855 if (i == 1
15856 && ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) !=
15857 0) {
15858 /*
15859 * Set Function 1 EEPROM Word 0 MSB
15860 *
15861 * Clear the BIOS_ENABLE (bit 14) and INTAB (bit 11)
15862 * EEPROM bits.
15863 *
15864 * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60 and
15865 * old Mac system booting problem. The Expansion ROM must
15866 * be disabled in Function 1 for these systems.
15867 *
15868 */
15869 *((uchar *)&eep_config + i) =
15870 ((*
15871 ((uchar *)&Default_38C1600_EEPROM_Config
15872 +
15873 i)) &
15874 (~
15875 (((ADV_EEPROM_BIOS_ENABLE |
15876 ADV_EEPROM_INTAB) >> 8) & 0xFF)));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015877
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015878 /*
15879 * Set the INTAB (bit 11) if the GPIO 0 input indicates
15880 * the Function 1 interrupt line is wired to INTA.
15881 *
15882 * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input:
15883 * 1 - Function 1 interrupt line wired to INT A.
15884 * 0 - Function 1 interrupt line wired to INT B.
15885 *
15886 * Note: Adapter boards always have Function 0 wired to INTA.
15887 * Put all 5 GPIO bits in input mode and then read
15888 * their input values.
15889 */
15890 AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL,
15891 0);
15892 if (AdvReadByteRegister
15893 (iop_base, IOPB_GPIO_DATA) & 0x01) {
15894 /* Function 1 interrupt wired to INTA; Set EEPROM bit. */
15895 *((uchar *)&eep_config + i) |=
15896 ((ADV_EEPROM_INTAB >> 8) & 0xFF);
15897 }
15898 } else {
15899 *((uchar *)&eep_config + i) =
15900 *((uchar *)&Default_38C1600_EEPROM_Config
15901 + i);
15902 }
15903 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015904
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015905 /*
15906 * Assume the 6 byte board serial number that was read
15907 * from EEPROM is correct even if the EEPROM checksum
15908 * failed.
15909 */
15910 eep_config.serial_number_word3 =
15911 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015912
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015913 eep_config.serial_number_word2 =
15914 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015915
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015916 eep_config.serial_number_word1 =
15917 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015918
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015919 AdvSet38C1600EEPConfig(iop_base, &eep_config);
15920 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015921
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015922 /*
15923 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
15924 * EEPROM configuration that was read.
15925 *
15926 * This is the mapping of EEPROM fields to Adv Library fields.
15927 */
15928 asc_dvc->wdtr_able = eep_config.wdtr_able;
15929 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
15930 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
15931 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
15932 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
15933 asc_dvc->ppr_able = 0;
15934 asc_dvc->tagqng_able = eep_config.tagqng_able;
15935 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
15936 asc_dvc->max_host_qng = eep_config.max_host_qng;
15937 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
15938 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ASC_MAX_TID);
15939 asc_dvc->start_motor = eep_config.start_motor;
15940 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
15941 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
15942 asc_dvc->no_scam = eep_config.scam_tolerant;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015943
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015944 /*
15945 * For every Target ID if any of its 'sdtr_speed[1234]' bits
15946 * are set, then set an 'sdtr_able' bit for it.
15947 */
15948 asc_dvc->sdtr_able = 0;
15949 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
15950 if (tid == 0) {
15951 sdtr_speed = asc_dvc->sdtr_speed1;
15952 } else if (tid == 4) {
15953 sdtr_speed = asc_dvc->sdtr_speed2;
15954 } else if (tid == 8) {
15955 sdtr_speed = asc_dvc->sdtr_speed3;
15956 } else if (tid == 12) {
15957 sdtr_speed = asc_dvc->sdtr_speed4;
15958 }
15959 if (sdtr_speed & ASC_MAX_TID) {
15960 asc_dvc->sdtr_able |= (1 << tid);
15961 }
15962 sdtr_speed >>= 4;
15963 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015964
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015965 /*
15966 * Set the host maximum queuing (max. 253, min. 16) and the per device
15967 * maximum queuing (max. 63, min. 4).
15968 */
15969 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
15970 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15971 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
15972 /* If the value is zero, assume it is uninitialized. */
15973 if (eep_config.max_host_qng == 0) {
15974 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15975 } else {
15976 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
15977 }
15978 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015979
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015980 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
15981 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15982 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
15983 /* If the value is zero, assume it is uninitialized. */
15984 if (eep_config.max_dvc_qng == 0) {
15985 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15986 } else {
15987 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
15988 }
15989 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015990
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015991 /*
15992 * If 'max_dvc_qng' is greater than 'max_host_qng', then
15993 * set 'max_dvc_qng' to 'max_host_qng'.
15994 */
15995 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
15996 eep_config.max_dvc_qng = eep_config.max_host_qng;
15997 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015998
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015999 /*
16000 * Set ASC_DVC_VAR 'max_host_qng' and ASC_DVC_VAR 'max_dvc_qng'
16001 * values based on possibly adjusted EEPROM values.
16002 */
16003 asc_dvc->max_host_qng = eep_config.max_host_qng;
16004 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016005
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016006 /*
16007 * If the EEPROM 'termination' field is set to automatic (0), then set
16008 * the ASC_DVC_CFG 'termination' field to automatic also.
16009 *
16010 * If the termination is specified with a non-zero 'termination'
16011 * value check that a legal value is set and set the ASC_DVC_CFG
16012 * 'termination' field appropriately.
16013 */
16014 if (eep_config.termination_se == 0) {
16015 termination = 0; /* auto termination for SE */
16016 } else {
16017 /* Enable manual control with low off / high off. */
16018 if (eep_config.termination_se == 1) {
16019 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016020
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016021 /* Enable manual control with low off / high on. */
16022 } else if (eep_config.termination_se == 2) {
16023 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016024
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016025 /* Enable manual control with low on / high on. */
16026 } else if (eep_config.termination_se == 3) {
16027 termination = TERM_SE;
16028 } else {
16029 /*
16030 * The EEPROM 'termination_se' field contains a bad value.
16031 * Use automatic termination instead.
16032 */
16033 termination = 0;
16034 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16035 }
16036 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016037
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016038 if (eep_config.termination_lvd == 0) {
16039 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
16040 } else {
16041 /* Enable manual control with low off / high off. */
16042 if (eep_config.termination_lvd == 1) {
16043 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016044
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016045 /* Enable manual control with low off / high on. */
16046 } else if (eep_config.termination_lvd == 2) {
16047 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016048
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016049 /* Enable manual control with low on / high on. */
16050 } else if (eep_config.termination_lvd == 3) {
16051 asc_dvc->cfg->termination = termination | TERM_LVD;
16052 } else {
16053 /*
16054 * The EEPROM 'termination_lvd' field contains a bad value.
16055 * Use automatic termination instead.
16056 */
16057 asc_dvc->cfg->termination = termination;
16058 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16059 }
16060 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016061
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016062 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016063}
16064
16065/*
16066 * Read EEPROM configuration into the specified buffer.
16067 *
16068 * Return a checksum based on the EEPROM configuration read.
16069 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016070static ushort __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -070016071AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
16072{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016073 ushort wval, chksum;
16074 ushort *wbuf;
16075 int eep_addr;
16076 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016077
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016078 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
16079 wbuf = (ushort *)cfg_buf;
16080 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016081
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016082 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16083 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16084 wval = AdvReadEEPWord(iop_base, eep_addr);
16085 chksum += wval; /* Checksum is calculated from word values. */
16086 if (*charfields++) {
16087 *wbuf = le16_to_cpu(wval);
16088 } else {
16089 *wbuf = wval;
16090 }
16091 }
16092 /* Read checksum word. */
16093 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16094 wbuf++;
16095 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016096
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016097 /* Read rest of EEPROM not covered by the checksum. */
16098 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16099 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16100 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16101 if (*charfields++) {
16102 *wbuf = le16_to_cpu(*wbuf);
16103 }
16104 }
16105 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016106}
16107
16108/*
16109 * Read EEPROM configuration into the specified buffer.
16110 *
16111 * Return a checksum based on the EEPROM configuration read.
16112 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016113static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016114AdvGet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016115{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016116 ushort wval, chksum;
16117 ushort *wbuf;
16118 int eep_addr;
16119 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016120
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016121 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
16122 wbuf = (ushort *)cfg_buf;
16123 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016124
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016125 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16126 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16127 wval = AdvReadEEPWord(iop_base, eep_addr);
16128 chksum += wval; /* Checksum is calculated from word values. */
16129 if (*charfields++) {
16130 *wbuf = le16_to_cpu(wval);
16131 } else {
16132 *wbuf = wval;
16133 }
16134 }
16135 /* Read checksum word. */
16136 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16137 wbuf++;
16138 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016139
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016140 /* Read rest of EEPROM not covered by the checksum. */
16141 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16142 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16143 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16144 if (*charfields++) {
16145 *wbuf = le16_to_cpu(*wbuf);
16146 }
16147 }
16148 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016149}
16150
16151/*
16152 * Read EEPROM configuration into the specified buffer.
16153 *
16154 * Return a checksum based on the EEPROM configuration read.
16155 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016156static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016157AdvGet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016158{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016159 ushort wval, chksum;
16160 ushort *wbuf;
16161 int eep_addr;
16162 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016163
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016164 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
16165 wbuf = (ushort *)cfg_buf;
16166 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016167
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016168 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16169 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16170 wval = AdvReadEEPWord(iop_base, eep_addr);
16171 chksum += wval; /* Checksum is calculated from word values. */
16172 if (*charfields++) {
16173 *wbuf = le16_to_cpu(wval);
16174 } else {
16175 *wbuf = wval;
16176 }
16177 }
16178 /* Read checksum word. */
16179 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16180 wbuf++;
16181 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016182
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016183 /* Read rest of EEPROM not covered by the checksum. */
16184 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16185 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16186 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16187 if (*charfields++) {
16188 *wbuf = le16_to_cpu(*wbuf);
16189 }
16190 }
16191 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016192}
16193
16194/*
16195 * Read the EEPROM from specified location
16196 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016197static ushort __devinit AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016198{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016199 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16200 ASC_EEP_CMD_READ | eep_word_addr);
16201 AdvWaitEEPCmd(iop_base);
16202 return AdvReadWordRegister(iop_base, IOPW_EE_DATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016203}
16204
16205/*
16206 * Wait for EEPROM command to complete
16207 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016208static void __devinit AdvWaitEEPCmd(AdvPortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016209{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016210 int eep_delay_ms;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016211
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016212 for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++) {
16213 if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) &
16214 ASC_EEP_CMD_DONE) {
16215 break;
16216 }
16217 DvcSleepMilliSecond(1);
16218 }
16219 if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) ==
16220 0) {
16221 ASC_ASSERT(0);
16222 }
16223 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016224}
16225
16226/*
16227 * Write the EEPROM from 'cfg_buf'.
16228 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016229void __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -070016230AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
16231{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016232 ushort *wbuf;
16233 ushort addr, chksum;
16234 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016235
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016236 wbuf = (ushort *)cfg_buf;
16237 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
16238 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016239
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016240 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16241 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016242
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016243 /*
16244 * Write EEPROM from word 0 to word 20.
16245 */
16246 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16247 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16248 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016249
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016250 if (*charfields++) {
16251 word = cpu_to_le16(*wbuf);
16252 } else {
16253 word = *wbuf;
16254 }
16255 chksum += *wbuf; /* Checksum is calculated from word values. */
16256 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16257 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16258 ASC_EEP_CMD_WRITE | addr);
16259 AdvWaitEEPCmd(iop_base);
16260 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16261 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016262
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016263 /*
16264 * Write EEPROM checksum at word 21.
16265 */
16266 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16267 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16268 AdvWaitEEPCmd(iop_base);
16269 wbuf++;
16270 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016271
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016272 /*
16273 * Write EEPROM OEM name at words 22 to 29.
16274 */
16275 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16276 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
16277 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016278
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016279 if (*charfields++) {
16280 word = cpu_to_le16(*wbuf);
16281 } else {
16282 word = *wbuf;
16283 }
16284 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16285 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16286 ASC_EEP_CMD_WRITE | addr);
16287 AdvWaitEEPCmd(iop_base);
16288 }
16289 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
16290 AdvWaitEEPCmd(iop_base);
16291 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016292}
16293
16294/*
16295 * Write the EEPROM from 'cfg_buf'.
16296 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016297void __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016298AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016299{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016300 ushort *wbuf;
16301 ushort *charfields;
16302 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016303
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016304 wbuf = (ushort *)cfg_buf;
16305 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
16306 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016307
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016308 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16309 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016310
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016311 /*
16312 * Write EEPROM from word 0 to word 20.
16313 */
16314 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16315 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16316 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016317
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016318 if (*charfields++) {
16319 word = cpu_to_le16(*wbuf);
16320 } else {
16321 word = *wbuf;
16322 }
16323 chksum += *wbuf; /* Checksum is calculated from word values. */
16324 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16325 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16326 ASC_EEP_CMD_WRITE | addr);
16327 AdvWaitEEPCmd(iop_base);
16328 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16329 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016330
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016331 /*
16332 * Write EEPROM checksum at word 21.
16333 */
16334 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16335 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16336 AdvWaitEEPCmd(iop_base);
16337 wbuf++;
16338 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016339
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016340 /*
16341 * Write EEPROM OEM name at words 22 to 29.
16342 */
16343 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16344 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
16345 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016346
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016347 if (*charfields++) {
16348 word = cpu_to_le16(*wbuf);
16349 } else {
16350 word = *wbuf;
16351 }
16352 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16353 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16354 ASC_EEP_CMD_WRITE | addr);
16355 AdvWaitEEPCmd(iop_base);
16356 }
16357 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
16358 AdvWaitEEPCmd(iop_base);
16359 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016360}
16361
16362/*
16363 * Write the EEPROM from 'cfg_buf'.
16364 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016365void __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016366AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016367{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016368 ushort *wbuf;
16369 ushort *charfields;
16370 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016371
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016372 wbuf = (ushort *)cfg_buf;
16373 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
16374 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016375
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016376 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16377 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016378
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016379 /*
16380 * Write EEPROM from word 0 to word 20.
16381 */
16382 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16383 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16384 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016385
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016386 if (*charfields++) {
16387 word = cpu_to_le16(*wbuf);
16388 } else {
16389 word = *wbuf;
16390 }
16391 chksum += *wbuf; /* Checksum is calculated from word values. */
16392 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16393 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16394 ASC_EEP_CMD_WRITE | addr);
16395 AdvWaitEEPCmd(iop_base);
16396 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16397 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016398
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016399 /*
16400 * Write EEPROM checksum at word 21.
16401 */
16402 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16403 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16404 AdvWaitEEPCmd(iop_base);
16405 wbuf++;
16406 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016407
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016408 /*
16409 * Write EEPROM OEM name at words 22 to 29.
16410 */
16411 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16412 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
16413 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016414
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016415 if (*charfields++) {
16416 word = cpu_to_le16(*wbuf);
16417 } else {
16418 word = *wbuf;
16419 }
16420 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16421 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16422 ASC_EEP_CMD_WRITE | addr);
16423 AdvWaitEEPCmd(iop_base);
16424 }
16425 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
16426 AdvWaitEEPCmd(iop_base);
16427 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016428}
16429
16430/* a_advlib.c */
16431/*
16432 * AdvExeScsiQueue() - Send a request to the RISC microcode program.
16433 *
16434 * Allocate a carrier structure, point the carrier to the ADV_SCSI_REQ_Q,
16435 * add the carrier to the ICQ (Initiator Command Queue), and tickle the
16436 * RISC to notify it a new command is ready to be executed.
16437 *
16438 * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be
16439 * set to SCSI_MAX_RETRY.
16440 *
16441 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the microcode
16442 * for DMA addresses or math operations are byte swapped to little-endian
16443 * order.
16444 *
16445 * Return:
16446 * ADV_SUCCESS(1) - The request was successfully queued.
16447 * ADV_BUSY(0) - Resource unavailable; Retry again after pending
16448 * request completes.
16449 * ADV_ERROR(-1) - Invalid ADV_SCSI_REQ_Q request structure
16450 * host IC error.
16451 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016452static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016453{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016454 ulong last_int_level;
16455 AdvPortAddr iop_base;
16456 ADV_DCNT req_size;
16457 ADV_PADDR req_paddr;
16458 ADV_CARR_T *new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016459
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016460 ASC_ASSERT(scsiq != NULL); /* 'scsiq' should never be NULL. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070016461
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016462 /*
16463 * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
16464 */
16465 if (scsiq->target_id > ADV_MAX_TID) {
16466 scsiq->host_status = QHSTA_M_INVALID_DEVICE;
16467 scsiq->done_status = QD_WITH_ERROR;
16468 return ADV_ERROR;
16469 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016470
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016471 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016472
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016473 last_int_level = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070016474
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016475 /*
16476 * Allocate a carrier ensuring at least one carrier always
16477 * remains on the freelist and initialize fields.
16478 */
16479 if ((new_carrp = asc_dvc->carr_freelist) == NULL) {
16480 DvcLeaveCritical(last_int_level);
16481 return ADV_BUSY;
16482 }
16483 asc_dvc->carr_freelist = (ADV_CARR_T *)
16484 ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa));
16485 asc_dvc->carr_pending_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016486
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016487 /*
16488 * Set the carrier to be a stopper by setting 'next_vpa'
16489 * to the stopper value. The current stopper will be changed
16490 * below to point to the new stopper.
16491 */
16492 new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016493
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016494 /*
16495 * Clear the ADV_SCSI_REQ_Q done flag.
16496 */
16497 scsiq->a_flag &= ~ADV_SCSIQ_DONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016498
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016499 req_size = sizeof(ADV_SCSI_REQ_Q);
16500 req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *)scsiq,
16501 (ADV_SDCNT *)&req_size, ADV_IS_SCSIQ_FLAG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016502
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016503 ASC_ASSERT(ADV_32BALIGN(req_paddr) == req_paddr);
16504 ASC_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016505
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016506 /* Wait for assertion before making little-endian */
16507 req_paddr = cpu_to_le32(req_paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016508
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016509 /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
16510 scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq));
16511 scsiq->scsiq_rptr = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016512
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016513 scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp));
16514 /*
16515 * Every ADV_CARR_T.carr_pa is byte swapped to little-endian
16516 * order during initialization.
16517 */
16518 scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016519
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016520 /*
16521 * Use the current stopper to send the ADV_SCSI_REQ_Q command to
16522 * the microcode. The newly allocated stopper will become the new
16523 * stopper.
16524 */
16525 asc_dvc->icq_sp->areq_vpa = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016526
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016527 /*
16528 * Set the 'next_vpa' pointer for the old stopper to be the
16529 * physical address of the new stopper. The RISC can only
16530 * follow physical addresses.
16531 */
16532 asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016533
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016534 /*
16535 * Set the host adapter stopper pointer to point to the new carrier.
16536 */
16537 asc_dvc->icq_sp = new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016538
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016539 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
16540 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
16541 /*
16542 * Tickle the RISC to tell it to read its Command Queue Head pointer.
16543 */
16544 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
16545 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
16546 /*
16547 * Clear the tickle value. In the ASC-3550 the RISC flag
16548 * command 'clr_tickle_a' does not work unless the host
16549 * value is cleared.
16550 */
16551 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
16552 ADV_TICKLE_NOP);
16553 }
16554 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16555 /*
16556 * Notify the RISC a carrier is ready by writing the physical
16557 * address of the new carrier stopper to the COMMA register.
16558 */
16559 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
16560 le32_to_cpu(new_carrp->carr_pa));
16561 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016562
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016563 DvcLeaveCritical(last_int_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016564
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016565 return ADV_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016566}
16567
16568/*
16569 * Reset SCSI Bus and purge all outstanding requests.
16570 *
16571 * Return Value:
16572 * ADV_TRUE(1) - All requests are purged and SCSI Bus is reset.
16573 * ADV_FALSE(0) - Microcode command failed.
16574 * ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC
16575 * may be hung which requires driver recovery.
16576 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016577static int AdvResetSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016578{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016579 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016580
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016581 /*
16582 * Send the SCSI Bus Reset idle start idle command which asserts
16583 * the SCSI Bus Reset signal.
16584 */
16585 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_START, 0L);
16586 if (status != ADV_TRUE) {
16587 return status;
16588 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016589
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016590 /*
16591 * Delay for the specified SCSI Bus Reset hold time.
16592 *
16593 * The hold time delay is done on the host because the RISC has no
16594 * microsecond accurate timer.
16595 */
16596 DvcDelayMicroSecond(asc_dvc, (ushort)ASC_SCSI_RESET_HOLD_TIME_US);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016597
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016598 /*
16599 * Send the SCSI Bus Reset end idle command which de-asserts
16600 * the SCSI Bus Reset signal and purges any pending requests.
16601 */
16602 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_END, 0L);
16603 if (status != ADV_TRUE) {
16604 return status;
16605 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016606
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016607 DvcSleepMilliSecond((ADV_DCNT)asc_dvc->scsi_reset_wait * 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016608
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016609 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016610}
16611
16612/*
16613 * Reset chip and SCSI Bus.
16614 *
16615 * Return Value:
16616 * ADV_TRUE(1) - Chip re-initialization and SCSI Bus Reset successful.
16617 * ADV_FALSE(0) - Chip re-initialization and SCSI Bus Reset failure.
16618 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016619static int AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016620{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016621 int status;
16622 ushort wdtr_able, sdtr_able, tagqng_able;
16623 ushort ppr_able = 0;
16624 uchar tid, max_cmd[ADV_MAX_TID + 1];
16625 AdvPortAddr iop_base;
16626 ushort bios_sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016627
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016628 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016629
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016630 /*
16631 * Save current per TID negotiated values.
16632 */
16633 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
16634 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
16635 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16636 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
16637 }
16638 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
16639 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
16640 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
16641 max_cmd[tid]);
16642 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016643
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016644 /*
16645 * Force the AdvInitAsc3550/38C0800Driver() function to
16646 * perform a SCSI Bus Reset by clearing the BIOS signature word.
16647 * The initialization functions assumes a SCSI Bus Reset is not
16648 * needed if the BIOS signature word is present.
16649 */
16650 AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
16651 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016652
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016653 /*
16654 * Stop chip and reset it.
16655 */
16656 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP);
16657 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
16658 DvcSleepMilliSecond(100);
16659 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
16660 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016661
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016662 /*
16663 * Reset Adv Library error code, if any, and try
16664 * re-initializing the chip.
16665 */
16666 asc_dvc->err_code = 0;
16667 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16668 status = AdvInitAsc38C1600Driver(asc_dvc);
16669 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
16670 status = AdvInitAsc38C0800Driver(asc_dvc);
16671 } else {
16672 status = AdvInitAsc3550Driver(asc_dvc);
16673 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016674
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016675 /* Translate initialization return value to status value. */
16676 if (status == 0) {
16677 status = ADV_TRUE;
16678 } else {
16679 status = ADV_FALSE;
16680 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016681
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016682 /*
16683 * Restore the BIOS signature word.
16684 */
16685 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016686
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016687 /*
16688 * Restore per TID negotiated values.
16689 */
16690 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
16691 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
16692 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16693 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
16694 }
16695 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
16696 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
16697 AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
16698 max_cmd[tid]);
16699 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016700
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016701 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016702}
16703
16704/*
16705 * Adv Library Interrupt Service Routine
16706 *
16707 * This function is called by a driver's interrupt service routine.
16708 * The function disables and re-enables interrupts.
16709 *
16710 * When a microcode idle command is completed, the ADV_DVC_VAR
16711 * 'idle_cmd_done' field is set to ADV_TRUE.
16712 *
16713 * Note: AdvISR() can be called when interrupts are disabled or even
16714 * when there is no hardware interrupt condition present. It will
16715 * always check for completed idle commands and microcode requests.
16716 * This is an important feature that shouldn't be changed because it
16717 * allows commands to be completed from polling mode loops.
16718 *
16719 * Return:
16720 * ADV_TRUE(1) - interrupt was pending
16721 * ADV_FALSE(0) - no interrupt was pending
16722 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016723static int AdvISR(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016724{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016725 AdvPortAddr iop_base;
16726 uchar int_stat;
16727 ushort target_bit;
16728 ADV_CARR_T *free_carrp;
16729 ADV_VADDR irq_next_vpa;
16730 int flags;
16731 ADV_SCSI_REQ_Q *scsiq;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016732
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016733 flags = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070016734
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016735 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016736
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016737 /* Reading the register clears the interrupt. */
16738 int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016739
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016740 if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB |
16741 ADV_INTR_STATUS_INTRC)) == 0) {
16742 DvcLeaveCritical(flags);
16743 return ADV_FALSE;
16744 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016745
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016746 /*
16747 * Notify the driver of an asynchronous microcode condition by
16748 * calling the ADV_DVC_VAR.async_callback function. The function
16749 * is passed the microcode ASC_MC_INTRB_CODE byte value.
16750 */
16751 if (int_stat & ADV_INTR_STATUS_INTRB) {
16752 uchar intrb_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016753
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016754 AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016755
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016756 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
16757 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
16758 if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
16759 asc_dvc->carr_pending_cnt != 0) {
16760 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
16761 ADV_TICKLE_A);
16762 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
16763 AdvWriteByteRegister(iop_base,
16764 IOPB_TICKLE,
16765 ADV_TICKLE_NOP);
16766 }
16767 }
16768 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016769
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016770 if (asc_dvc->async_callback != 0) {
16771 (*asc_dvc->async_callback) (asc_dvc, intrb_code);
16772 }
16773 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016774
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016775 /*
16776 * Check if the IRQ stopper carrier contains a completed request.
16777 */
16778 while (((irq_next_vpa =
16779 le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0) {
16780 /*
16781 * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
16782 * The RISC will have set 'areq_vpa' to a virtual address.
16783 *
16784 * The firmware will have copied the ASC_SCSI_REQ_Q.scsiq_ptr
16785 * field to the carrier ADV_CARR_T.areq_vpa field. The conversion
16786 * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr'
16787 * in AdvExeScsiQueue().
16788 */
16789 scsiq = (ADV_SCSI_REQ_Q *)
16790 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016791
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016792 /*
16793 * Request finished with good status and the queue was not
16794 * DMAed to host memory by the firmware. Set all status fields
16795 * to indicate good status.
16796 */
16797 if ((irq_next_vpa & ASC_RQ_GOOD) != 0) {
16798 scsiq->done_status = QD_NO_ERROR;
16799 scsiq->host_status = scsiq->scsi_status = 0;
16800 scsiq->data_cnt = 0L;
16801 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016802
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016803 /*
16804 * Advance the stopper pointer to the next carrier
16805 * ignoring the lower four bits. Free the previous
16806 * stopper carrier.
16807 */
16808 free_carrp = asc_dvc->irq_sp;
16809 asc_dvc->irq_sp = (ADV_CARR_T *)
16810 ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016811
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016812 free_carrp->next_vpa =
16813 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
16814 asc_dvc->carr_freelist = free_carrp;
16815 asc_dvc->carr_pending_cnt--;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016816
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016817 ASC_ASSERT(scsiq != NULL);
16818 target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016819
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016820 /*
16821 * Clear request microcode control flag.
16822 */
16823 scsiq->cntl = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016824
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016825 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016826 * Notify the driver of the completed request by passing
16827 * the ADV_SCSI_REQ_Q pointer to its callback function.
16828 */
16829 scsiq->a_flag |= ADV_SCSIQ_DONE;
16830 (*asc_dvc->isr_callback) (asc_dvc, scsiq);
16831 /*
16832 * Note: After the driver callback function is called, 'scsiq'
16833 * can no longer be referenced.
16834 *
16835 * Fall through and continue processing other completed
16836 * requests...
16837 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070016838
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016839 /*
16840 * Disable interrupts again in case the driver inadvertently
16841 * enabled interrupts in its callback function.
16842 *
16843 * The DvcEnterCritical() return value is ignored, because
16844 * the 'flags' saved when AdvISR() was first entered will be
16845 * used to restore the interrupt flag on exit.
16846 */
16847 (void)DvcEnterCritical();
16848 }
16849 DvcLeaveCritical(flags);
16850 return ADV_TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016851}
16852
16853/*
16854 * Send an idle command to the chip and wait for completion.
16855 *
16856 * Command completion is polled for once per microsecond.
16857 *
16858 * The function can be called from anywhere including an interrupt handler.
16859 * But the function is not re-entrant, so it uses the DvcEnter/LeaveCritical()
16860 * functions to prevent reentrancy.
16861 *
16862 * Return Values:
16863 * ADV_TRUE - command completed successfully
16864 * ADV_FALSE - command failed
16865 * ADV_ERROR - command timed out
16866 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016867static int
Linus Torvalds1da177e2005-04-16 15:20:36 -070016868AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016869 ushort idle_cmd, ADV_DCNT idle_cmd_parameter)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016870{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016871 ulong last_int_level;
16872 int result;
16873 ADV_DCNT i, j;
16874 AdvPortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016875
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016876 last_int_level = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070016877
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016878 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016879
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016880 /*
16881 * Clear the idle command status which is set by the microcode
16882 * to a non-zero value to indicate when the command is completed.
16883 * The non-zero result is one of the IDLE_CMD_STATUS_* values
16884 * defined in a_advlib.h.
16885 */
16886 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort)0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016887
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016888 /*
16889 * Write the idle command value after the idle command parameter
16890 * has been written to avoid a race condition. If the order is not
16891 * followed, the microcode may process the idle command before the
16892 * parameters have been written to LRAM.
16893 */
16894 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
16895 cpu_to_le32(idle_cmd_parameter));
16896 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016897
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016898 /*
16899 * Tickle the RISC to tell it to process the idle command.
16900 */
16901 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B);
16902 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
16903 /*
16904 * Clear the tickle value. In the ASC-3550 the RISC flag
16905 * command 'clr_tickle_b' does not work unless the host
16906 * value is cleared.
16907 */
16908 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
16909 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016910
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016911 /* Wait for up to 100 millisecond for the idle command to timeout. */
16912 for (i = 0; i < SCSI_WAIT_100_MSEC; i++) {
16913 /* Poll once each microsecond for command completion. */
16914 for (j = 0; j < SCSI_US_PER_MSEC; j++) {
16915 AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS,
16916 result);
16917 if (result != 0) {
16918 DvcLeaveCritical(last_int_level);
16919 return result;
16920 }
16921 DvcDelayMicroSecond(asc_dvc, (ushort)1);
16922 }
16923 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016924
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016925 ASC_ASSERT(0); /* The idle command should never timeout. */
16926 DvcLeaveCritical(last_int_level);
16927 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016928}
16929
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060016930static int __devinit
16931advansys_wide_init_chip(asc_board_t *boardp, ADV_DVC_VAR *adv_dvc_varp)
16932{
16933 int req_cnt = 0;
16934 adv_req_t *reqp = NULL;
16935 int sg_cnt = 0;
16936 adv_sgblk_t *sgp;
16937 int warn_code, err_code;
16938
16939 /*
16940 * Allocate buffer carrier structures. The total size
16941 * is about 4 KB, so allocate all at once.
16942 */
16943 boardp->carrp = kmalloc(ADV_CARRIER_BUFSIZE, GFP_KERNEL);
16944 ASC_DBG1(1, "advansys_wide_init_chip: carrp 0x%p\n", boardp->carrp);
16945
16946 if (!boardp->carrp)
16947 goto kmalloc_failed;
16948
16949 /*
16950 * Allocate up to 'max_host_qng' request structures for the Wide
16951 * board. The total size is about 16 KB, so allocate all at once.
16952 * If the allocation fails decrement and try again.
16953 */
16954 for (req_cnt = adv_dvc_varp->max_host_qng; req_cnt > 0; req_cnt--) {
16955 reqp = kmalloc(sizeof(adv_req_t) * req_cnt, GFP_KERNEL);
16956
16957 ASC_DBG3(1, "advansys_wide_init_chip: reqp 0x%p, req_cnt %d, "
16958 "bytes %lu\n", reqp, req_cnt,
16959 (ulong)sizeof(adv_req_t) * req_cnt);
16960
16961 if (reqp)
16962 break;
16963 }
16964
16965 if (!reqp)
16966 goto kmalloc_failed;
16967
16968 boardp->orig_reqp = reqp;
16969
16970 /*
16971 * Allocate up to ADV_TOT_SG_BLOCK request structures for
16972 * the Wide board. Each structure is about 136 bytes.
16973 */
16974 boardp->adv_sgblkp = NULL;
16975 for (sg_cnt = 0; sg_cnt < ADV_TOT_SG_BLOCK; sg_cnt++) {
16976 sgp = kmalloc(sizeof(adv_sgblk_t), GFP_KERNEL);
16977
16978 if (!sgp)
16979 break;
16980
16981 sgp->next_sgblkp = boardp->adv_sgblkp;
16982 boardp->adv_sgblkp = sgp;
16983
16984 }
16985
16986 ASC_DBG3(1, "advansys_wide_init_chip: sg_cnt %d * %u = %u bytes\n",
16987 sg_cnt, sizeof(adv_sgblk_t),
16988 (unsigned)(sizeof(adv_sgblk_t) * sg_cnt));
16989
16990 if (!boardp->adv_sgblkp)
16991 goto kmalloc_failed;
16992
16993 adv_dvc_varp->carrier_buf = boardp->carrp;
16994
16995 /*
16996 * Point 'adv_reqp' to the request structures and
16997 * link them together.
16998 */
16999 req_cnt--;
17000 reqp[req_cnt].next_reqp = NULL;
17001 for (; req_cnt > 0; req_cnt--) {
17002 reqp[req_cnt - 1].next_reqp = &reqp[req_cnt];
17003 }
17004 boardp->adv_reqp = &reqp[0];
17005
17006 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
17007 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc3550Driver()\n");
17008 warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
17009 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
17010 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc38C0800Driver()"
17011 "\n");
17012 warn_code = AdvInitAsc38C0800Driver(adv_dvc_varp);
17013 } else {
17014 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc38C1600Driver()"
17015 "\n");
17016 warn_code = AdvInitAsc38C1600Driver(adv_dvc_varp);
17017 }
17018 err_code = adv_dvc_varp->err_code;
17019
17020 if (warn_code || err_code) {
17021 ASC_PRINT3("advansys_wide_init_chip: board %d error: warn 0x%x,"
17022 " error 0x%x\n", boardp->id, warn_code, err_code);
17023 }
17024
17025 goto exit;
17026
17027 kmalloc_failed:
17028 ASC_PRINT1("advansys_wide_init_chip: board %d error: kmalloc() "
17029 "failed\n", boardp->id);
17030 err_code = ADV_ERROR;
17031 exit:
17032 return err_code;
17033}
17034
17035static void advansys_wide_free_mem(asc_board_t *boardp)
17036{
17037 kfree(boardp->carrp);
17038 boardp->carrp = NULL;
17039 kfree(boardp->orig_reqp);
17040 boardp->orig_reqp = boardp->adv_reqp = NULL;
17041 while (boardp->adv_sgblkp) {
17042 adv_sgblk_t *sgp = boardp->adv_sgblkp;
17043 boardp->adv_sgblkp = sgp->next_sgblkp;
17044 kfree(sgp);
17045 }
17046}
17047
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017048static struct Scsi_Host *__devinit
17049advansys_board_found(int iop, struct device *dev, int bus_type)
17050{
17051 struct Scsi_Host *shost;
17052 struct pci_dev *pdev = bus_type == ASC_IS_PCI ? to_pci_dev(dev) : NULL;
17053 asc_board_t *boardp;
17054 ASC_DVC_VAR *asc_dvc_varp = NULL;
17055 ADV_DVC_VAR *adv_dvc_varp = NULL;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017056 int share_irq;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017057 int warn_code, err_code;
17058 int ret;
17059
17060 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017061 * Register the adapter, get its configuration, and
17062 * initialize it.
17063 */
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017064 ASC_DBG(2, "advansys_board_found: scsi_host_alloc()\n");
17065 shost = scsi_host_alloc(&advansys_template, sizeof(asc_board_t));
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017066 if (!shost)
17067 return NULL;
17068
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017069 /* Initialize private per board data */
17070 boardp = ASC_BOARDP(shost);
17071 memset(boardp, 0, sizeof(asc_board_t));
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017072 boardp->id = asc_board_count++;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017073 spin_lock_init(&boardp->lock);
Matthew Wilcox394dbf32007-07-26 11:56:40 -040017074 boardp->dev = dev;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017075
17076 /*
17077 * Handle both narrow and wide boards.
17078 *
17079 * If a Wide board was detected, set the board structure
17080 * wide board flag. Set-up the board structure based on
17081 * the board type.
17082 */
17083#ifdef CONFIG_PCI
17084 if (bus_type == ASC_IS_PCI &&
17085 (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW ||
17086 pdev->device == PCI_DEVICE_ID_38C0800_REV1 ||
17087 pdev->device == PCI_DEVICE_ID_38C1600_REV1)) {
17088 boardp->flags |= ASC_IS_WIDE_BOARD;
17089 }
17090#endif /* CONFIG_PCI */
17091
17092 if (ASC_NARROW_BOARD(boardp)) {
17093 ASC_DBG(1, "advansys_board_found: narrow board\n");
17094 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
17095 asc_dvc_varp->bus_type = bus_type;
17096 asc_dvc_varp->drv_ptr = boardp;
17097 asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg;
17098 asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
17099 asc_dvc_varp->iop_base = iop;
17100 asc_dvc_varp->isr_callback = asc_isr_callback;
17101 } else {
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040017102#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017103 ASC_DBG(1, "advansys_board_found: wide board\n");
17104 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
17105 adv_dvc_varp->drv_ptr = boardp;
17106 adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
17107 adv_dvc_varp->isr_callback = adv_isr_callback;
17108 adv_dvc_varp->async_callback = adv_async_callback;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017109 if (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW) {
17110 ASC_DBG(1, "advansys_board_found: ASC-3550\n");
17111 adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
17112 } else if (pdev->device == PCI_DEVICE_ID_38C0800_REV1) {
17113 ASC_DBG(1, "advansys_board_found: ASC-38C0800\n");
17114 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
17115 } else {
17116 ASC_DBG(1, "advansys_board_found: ASC-38C1600\n");
17117 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C1600;
17118 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017119
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040017120 boardp->asc_n_io_port = pci_resource_len(pdev, 1);
17121 boardp->ioremap_addr = ioremap(pci_resource_start(pdev, 1),
17122 boardp->asc_n_io_port);
17123 if (!boardp->ioremap_addr) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017124 ASC_PRINT3
17125 ("advansys_board_found: board %d: ioremap(%x, %d) returned NULL\n",
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040017126 boardp->id, pci_resource_start(pdev, 1),
17127 boardp->asc_n_io_port);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017128 goto err_shost;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017129 }
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040017130 adv_dvc_varp->iop_base = (AdvPortAddr)boardp->ioremap_addr
Matthew Wilcox71f36112007-07-30 08:04:53 -060017131 ASC_DBG1(1, "advansys_board_found: iop_base: 0x%lx\n",
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017132 adv_dvc_varp->iop_base);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017133
17134 /*
17135 * Even though it isn't used to access wide boards, other
17136 * than for the debug line below, save I/O Port address so
17137 * that it can be reported.
17138 */
17139 boardp->ioport = iop;
17140
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040017141 ASC_DBG2(1, "advansys_board_found: iopb_chip_id_1 0x%x, "
17142 "iopw_chip_id_0 0x%x\n", (ushort)inp(iop + 1),
17143 (ushort)inpw(iop));
17144#endif /* CONFIG_PCI */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017145 }
17146
17147#ifdef CONFIG_PROC_FS
17148 /*
17149 * Allocate buffer for printing information from
17150 * /proc/scsi/advansys/[0...].
17151 */
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017152 boardp->prtbuf = kmalloc(ASC_PRTBUF_SIZE, GFP_KERNEL);
17153 if (!boardp->prtbuf) {
17154 ASC_PRINT2("advansys_board_found: board %d: kmalloc(%d) "
17155 "returned NULL\n", boardp->id, ASC_PRTBUF_SIZE);
17156 goto err_unmap;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017157 }
17158#endif /* CONFIG_PROC_FS */
17159
17160 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017161 /*
17162 * Set the board bus type and PCI IRQ before
17163 * calling AscInitGetConfig().
17164 */
17165 switch (asc_dvc_varp->bus_type) {
17166#ifdef CONFIG_ISA
17167 case ASC_IS_ISA:
17168 shost->unchecked_isa_dma = TRUE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017169 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017170 break;
17171 case ASC_IS_VL:
17172 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017173 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017174 break;
17175 case ASC_IS_EISA:
17176 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017177 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017178 break;
17179#endif /* CONFIG_ISA */
17180#ifdef CONFIG_PCI
17181 case ASC_IS_PCI:
17182 shost->irq = asc_dvc_varp->irq_no = pdev->irq;
17183 asc_dvc_varp->cfg->pci_slot_info =
17184 ASC_PCI_MKID(pdev->bus->number,
17185 PCI_SLOT(pdev->devfn),
17186 PCI_FUNC(pdev->devfn));
17187 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017188 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017189 break;
17190#endif /* CONFIG_PCI */
17191 default:
17192 ASC_PRINT2
17193 ("advansys_board_found: board %d: unknown adapter type: %d\n",
17194 boardp->id, asc_dvc_varp->bus_type);
17195 shost->unchecked_isa_dma = TRUE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017196 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017197 break;
17198 }
17199 } else {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017200 /*
17201 * For Wide boards set PCI information before calling
17202 * AdvInitGetConfig().
17203 */
17204#ifdef CONFIG_PCI
17205 shost->irq = adv_dvc_varp->irq_no = pdev->irq;
17206 adv_dvc_varp->cfg->pci_slot_info =
17207 ASC_PCI_MKID(pdev->bus->number,
17208 PCI_SLOT(pdev->devfn),
17209 PCI_FUNC(pdev->devfn));
17210 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017211 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017212#endif /* CONFIG_PCI */
17213 }
17214
17215 /*
17216 * Read the board configuration.
17217 */
17218 if (ASC_NARROW_BOARD(boardp)) {
17219 /*
17220 * NOTE: AscInitGetConfig() may change the board's
17221 * bus_type value. The bus_type value should no
17222 * longer be used. If the bus_type field must be
17223 * referenced only use the bit-wise AND operator "&".
17224 */
17225 ASC_DBG(2, "advansys_board_found: AscInitGetConfig()\n");
17226 switch (ret = AscInitGetConfig(asc_dvc_varp)) {
17227 case 0: /* No error */
17228 break;
17229 case ASC_WARN_IO_PORT_ROTATE:
17230 ASC_PRINT1
17231 ("AscInitGetConfig: board %d: I/O port address modified\n",
17232 boardp->id);
17233 break;
17234 case ASC_WARN_AUTO_CONFIG:
17235 ASC_PRINT1
17236 ("AscInitGetConfig: board %d: I/O port increment switch enabled\n",
17237 boardp->id);
17238 break;
17239 case ASC_WARN_EEPROM_CHKSUM:
17240 ASC_PRINT1
17241 ("AscInitGetConfig: board %d: EEPROM checksum error\n",
17242 boardp->id);
17243 break;
17244 case ASC_WARN_IRQ_MODIFIED:
17245 ASC_PRINT1
17246 ("AscInitGetConfig: board %d: IRQ modified\n",
17247 boardp->id);
17248 break;
17249 case ASC_WARN_CMD_QNG_CONFLICT:
17250 ASC_PRINT1
17251 ("AscInitGetConfig: board %d: tag queuing enabled w/o disconnects\n",
17252 boardp->id);
17253 break;
17254 default:
17255 ASC_PRINT2
17256 ("AscInitGetConfig: board %d: unknown warning: 0x%x\n",
17257 boardp->id, ret);
17258 break;
17259 }
17260 if ((err_code = asc_dvc_varp->err_code) != 0) {
17261 ASC_PRINT3
17262 ("AscInitGetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
17263 boardp->id,
17264 asc_dvc_varp->init_state, asc_dvc_varp->err_code);
17265 }
17266 } else {
17267 ASC_DBG(2, "advansys_board_found: AdvInitGetConfig()\n");
Matthew Wilcox394dbf32007-07-26 11:56:40 -040017268
17269 ret = AdvInitGetConfig(pdev, adv_dvc_varp);
17270 if (ret != 0) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017271 ASC_PRINT2
17272 ("AdvInitGetConfig: board %d: warning: 0x%x\n",
17273 boardp->id, ret);
17274 }
17275 if ((err_code = adv_dvc_varp->err_code) != 0) {
17276 ASC_PRINT2
17277 ("AdvInitGetConfig: board %d error: err_code 0x%x\n",
17278 boardp->id, adv_dvc_varp->err_code);
17279 }
17280 }
17281
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017282 if (err_code != 0)
17283 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017284
17285 /*
17286 * Save the EEPROM configuration so that it can be displayed
17287 * from /proc/scsi/advansys/[0...].
17288 */
17289 if (ASC_NARROW_BOARD(boardp)) {
17290
17291 ASCEEP_CONFIG *ep;
17292
17293 /*
17294 * Set the adapter's target id bit in the 'init_tidmask' field.
17295 */
17296 boardp->init_tidmask |=
17297 ADV_TID_TO_TIDMASK(asc_dvc_varp->cfg->chip_scsi_id);
17298
17299 /*
17300 * Save EEPROM settings for the board.
17301 */
17302 ep = &boardp->eep_config.asc_eep;
17303
17304 ep->init_sdtr = asc_dvc_varp->cfg->sdtr_enable;
17305 ep->disc_enable = asc_dvc_varp->cfg->disc_enable;
17306 ep->use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled;
17307 ASC_EEP_SET_DMA_SPD(ep, asc_dvc_varp->cfg->isa_dma_speed);
17308 ep->start_motor = asc_dvc_varp->start_motor;
17309 ep->cntl = asc_dvc_varp->dvc_cntl;
17310 ep->no_scam = asc_dvc_varp->no_scam;
17311 ep->max_total_qng = asc_dvc_varp->max_total_qng;
17312 ASC_EEP_SET_CHIP_ID(ep, asc_dvc_varp->cfg->chip_scsi_id);
17313 /* 'max_tag_qng' is set to the same value for every device. */
17314 ep->max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0];
17315 ep->adapter_info[0] = asc_dvc_varp->cfg->adapter_info[0];
17316 ep->adapter_info[1] = asc_dvc_varp->cfg->adapter_info[1];
17317 ep->adapter_info[2] = asc_dvc_varp->cfg->adapter_info[2];
17318 ep->adapter_info[3] = asc_dvc_varp->cfg->adapter_info[3];
17319 ep->adapter_info[4] = asc_dvc_varp->cfg->adapter_info[4];
17320 ep->adapter_info[5] = asc_dvc_varp->cfg->adapter_info[5];
17321
17322 /*
17323 * Modify board configuration.
17324 */
17325 ASC_DBG(2, "advansys_board_found: AscInitSetConfig()\n");
Matthew Wilcox394dbf32007-07-26 11:56:40 -040017326 switch (ret = AscInitSetConfig(pdev, asc_dvc_varp)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017327 case 0: /* No error. */
17328 break;
17329 case ASC_WARN_IO_PORT_ROTATE:
17330 ASC_PRINT1
17331 ("AscInitSetConfig: board %d: I/O port address modified\n",
17332 boardp->id);
17333 break;
17334 case ASC_WARN_AUTO_CONFIG:
17335 ASC_PRINT1
17336 ("AscInitSetConfig: board %d: I/O port increment switch enabled\n",
17337 boardp->id);
17338 break;
17339 case ASC_WARN_EEPROM_CHKSUM:
17340 ASC_PRINT1
17341 ("AscInitSetConfig: board %d: EEPROM checksum error\n",
17342 boardp->id);
17343 break;
17344 case ASC_WARN_IRQ_MODIFIED:
17345 ASC_PRINT1
17346 ("AscInitSetConfig: board %d: IRQ modified\n",
17347 boardp->id);
17348 break;
17349 case ASC_WARN_CMD_QNG_CONFLICT:
17350 ASC_PRINT1
17351 ("AscInitSetConfig: board %d: tag queuing w/o disconnects\n",
17352 boardp->id);
17353 break;
17354 default:
17355 ASC_PRINT2
17356 ("AscInitSetConfig: board %d: unknown warning: 0x%x\n",
17357 boardp->id, ret);
17358 break;
17359 }
17360 if (asc_dvc_varp->err_code != 0) {
17361 ASC_PRINT3
17362 ("AscInitSetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
17363 boardp->id,
17364 asc_dvc_varp->init_state, asc_dvc_varp->err_code);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017365 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017366 }
17367
17368 /*
17369 * Finish initializing the 'Scsi_Host' structure.
17370 */
17371 /* AscInitSetConfig() will set the IRQ for non-PCI boards. */
17372 if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
17373 shost->irq = asc_dvc_varp->irq_no;
17374 }
17375 } else {
17376 ADVEEP_3550_CONFIG *ep_3550;
17377 ADVEEP_38C0800_CONFIG *ep_38C0800;
17378 ADVEEP_38C1600_CONFIG *ep_38C1600;
17379
17380 /*
17381 * Save Wide EEP Configuration Information.
17382 */
17383 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
17384 ep_3550 = &boardp->eep_config.adv_3550_eep;
17385
17386 ep_3550->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
17387 ep_3550->max_host_qng = adv_dvc_varp->max_host_qng;
17388 ep_3550->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
17389 ep_3550->termination = adv_dvc_varp->cfg->termination;
17390 ep_3550->disc_enable = adv_dvc_varp->cfg->disc_enable;
17391 ep_3550->bios_ctrl = adv_dvc_varp->bios_ctrl;
17392 ep_3550->wdtr_able = adv_dvc_varp->wdtr_able;
17393 ep_3550->sdtr_able = adv_dvc_varp->sdtr_able;
17394 ep_3550->ultra_able = adv_dvc_varp->ultra_able;
17395 ep_3550->tagqng_able = adv_dvc_varp->tagqng_able;
17396 ep_3550->start_motor = adv_dvc_varp->start_motor;
17397 ep_3550->scsi_reset_delay =
17398 adv_dvc_varp->scsi_reset_wait;
17399 ep_3550->serial_number_word1 =
17400 adv_dvc_varp->cfg->serial1;
17401 ep_3550->serial_number_word2 =
17402 adv_dvc_varp->cfg->serial2;
17403 ep_3550->serial_number_word3 =
17404 adv_dvc_varp->cfg->serial3;
17405 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
17406 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
17407
17408 ep_38C0800->adapter_scsi_id =
17409 adv_dvc_varp->chip_scsi_id;
17410 ep_38C0800->max_host_qng = adv_dvc_varp->max_host_qng;
17411 ep_38C0800->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
17412 ep_38C0800->termination_lvd =
17413 adv_dvc_varp->cfg->termination;
17414 ep_38C0800->disc_enable =
17415 adv_dvc_varp->cfg->disc_enable;
17416 ep_38C0800->bios_ctrl = adv_dvc_varp->bios_ctrl;
17417 ep_38C0800->wdtr_able = adv_dvc_varp->wdtr_able;
17418 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
17419 ep_38C0800->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
17420 ep_38C0800->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
17421 ep_38C0800->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
17422 ep_38C0800->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
17423 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
17424 ep_38C0800->start_motor = adv_dvc_varp->start_motor;
17425 ep_38C0800->scsi_reset_delay =
17426 adv_dvc_varp->scsi_reset_wait;
17427 ep_38C0800->serial_number_word1 =
17428 adv_dvc_varp->cfg->serial1;
17429 ep_38C0800->serial_number_word2 =
17430 adv_dvc_varp->cfg->serial2;
17431 ep_38C0800->serial_number_word3 =
17432 adv_dvc_varp->cfg->serial3;
17433 } else {
17434 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
17435
17436 ep_38C1600->adapter_scsi_id =
17437 adv_dvc_varp->chip_scsi_id;
17438 ep_38C1600->max_host_qng = adv_dvc_varp->max_host_qng;
17439 ep_38C1600->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
17440 ep_38C1600->termination_lvd =
17441 adv_dvc_varp->cfg->termination;
17442 ep_38C1600->disc_enable =
17443 adv_dvc_varp->cfg->disc_enable;
17444 ep_38C1600->bios_ctrl = adv_dvc_varp->bios_ctrl;
17445 ep_38C1600->wdtr_able = adv_dvc_varp->wdtr_able;
17446 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
17447 ep_38C1600->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
17448 ep_38C1600->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
17449 ep_38C1600->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
17450 ep_38C1600->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
17451 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
17452 ep_38C1600->start_motor = adv_dvc_varp->start_motor;
17453 ep_38C1600->scsi_reset_delay =
17454 adv_dvc_varp->scsi_reset_wait;
17455 ep_38C1600->serial_number_word1 =
17456 adv_dvc_varp->cfg->serial1;
17457 ep_38C1600->serial_number_word2 =
17458 adv_dvc_varp->cfg->serial2;
17459 ep_38C1600->serial_number_word3 =
17460 adv_dvc_varp->cfg->serial3;
17461 }
17462
17463 /*
17464 * Set the adapter's target id bit in the 'init_tidmask' field.
17465 */
17466 boardp->init_tidmask |=
17467 ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017468 }
17469
17470 /*
17471 * Channels are numbered beginning with 0. For AdvanSys one host
17472 * structure supports one channel. Multi-channel boards have a
17473 * separate host structure for each channel.
17474 */
17475 shost->max_channel = 0;
17476 if (ASC_NARROW_BOARD(boardp)) {
17477 shost->max_id = ASC_MAX_TID + 1;
17478 shost->max_lun = ASC_MAX_LUN + 1;
17479
17480 shost->io_port = asc_dvc_varp->iop_base;
17481 boardp->asc_n_io_port = ASC_IOADR_GAP;
17482 shost->this_id = asc_dvc_varp->cfg->chip_scsi_id;
17483
17484 /* Set maximum number of queues the adapter can handle. */
17485 shost->can_queue = asc_dvc_varp->max_total_qng;
17486 } else {
17487 shost->max_id = ADV_MAX_TID + 1;
17488 shost->max_lun = ADV_MAX_LUN + 1;
17489
17490 /*
17491 * Save the I/O Port address and length even though
17492 * I/O ports are not used to access Wide boards.
17493 * Instead the Wide boards are accessed with
17494 * PCI Memory Mapped I/O.
17495 */
17496 shost->io_port = iop;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017497
17498 shost->this_id = adv_dvc_varp->chip_scsi_id;
17499
17500 /* Set maximum number of queues the adapter can handle. */
17501 shost->can_queue = adv_dvc_varp->max_host_qng;
17502 }
17503
17504 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017505 * Following v1.3.89, 'cmd_per_lun' is no longer needed
17506 * and should be set to zero.
17507 *
17508 * But because of a bug introduced in v1.3.89 if the driver is
17509 * compiled as a module and 'cmd_per_lun' is zero, the Mid-Level
17510 * SCSI function 'allocate_device' will panic. To allow the driver
17511 * to work as a module in these kernels set 'cmd_per_lun' to 1.
17512 *
17513 * Note: This is wrong. cmd_per_lun should be set to the depth
17514 * you want on untagged devices always.
17515 #ifdef MODULE
17516 */
17517 shost->cmd_per_lun = 1;
17518/* #else
17519 shost->cmd_per_lun = 0;
17520#endif */
17521
17522 /*
17523 * Set the maximum number of scatter-gather elements the
17524 * adapter can handle.
17525 */
17526 if (ASC_NARROW_BOARD(boardp)) {
17527 /*
17528 * Allow two commands with 'sg_tablesize' scatter-gather
17529 * elements to be executed simultaneously. This value is
17530 * the theoretical hardware limit. It may be decreased
17531 * below.
17532 */
17533 shost->sg_tablesize =
17534 (((asc_dvc_varp->max_total_qng - 2) / 2) *
17535 ASC_SG_LIST_PER_Q) + 1;
17536 } else {
17537 shost->sg_tablesize = ADV_MAX_SG_LIST;
17538 }
17539
17540 /*
17541 * The value of 'sg_tablesize' can not exceed the SCSI
17542 * mid-level driver definition of SG_ALL. SG_ALL also
17543 * must not be exceeded, because it is used to define the
17544 * size of the scatter-gather table in 'struct asc_sg_head'.
17545 */
17546 if (shost->sg_tablesize > SG_ALL) {
17547 shost->sg_tablesize = SG_ALL;
17548 }
17549
17550 ASC_DBG1(1, "advansys_board_found: sg_tablesize: %d\n", shost->sg_tablesize);
17551
17552 /* BIOS start address. */
17553 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017554 shost->base = AscGetChipBiosAddress(asc_dvc_varp->iop_base,
17555 asc_dvc_varp->bus_type);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017556 } else {
17557 /*
17558 * Fill-in BIOS board variables. The Wide BIOS saves
17559 * information in LRAM that is used by the driver.
17560 */
17561 AdvReadWordLram(adv_dvc_varp->iop_base,
17562 BIOS_SIGNATURE, boardp->bios_signature);
17563 AdvReadWordLram(adv_dvc_varp->iop_base,
17564 BIOS_VERSION, boardp->bios_version);
17565 AdvReadWordLram(adv_dvc_varp->iop_base,
17566 BIOS_CODESEG, boardp->bios_codeseg);
17567 AdvReadWordLram(adv_dvc_varp->iop_base,
17568 BIOS_CODELEN, boardp->bios_codelen);
17569
17570 ASC_DBG2(1,
17571 "advansys_board_found: bios_signature 0x%x, bios_version 0x%x\n",
17572 boardp->bios_signature, boardp->bios_version);
17573
17574 ASC_DBG2(1,
17575 "advansys_board_found: bios_codeseg 0x%x, bios_codelen 0x%x\n",
17576 boardp->bios_codeseg, boardp->bios_codelen);
17577
17578 /*
17579 * If the BIOS saved a valid signature, then fill in
17580 * the BIOS code segment base address.
17581 */
17582 if (boardp->bios_signature == 0x55AA) {
17583 /*
17584 * Convert x86 realmode code segment to a linear
17585 * address by shifting left 4.
17586 */
17587 shost->base = ((ulong)boardp->bios_codeseg << 4);
17588 } else {
17589 shost->base = 0;
17590 }
17591 }
17592
17593 /*
17594 * Register Board Resources - I/O Port, DMA, IRQ
17595 */
17596
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017597 /* Register DMA Channel for Narrow boards. */
17598 shost->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */
17599#ifdef CONFIG_ISA
17600 if (ASC_NARROW_BOARD(boardp)) {
17601 /* Register DMA channel for ISA bus. */
17602 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
17603 shost->dma_channel = asc_dvc_varp->cfg->isa_dma_channel;
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017604 ret = request_dma(shost->dma_channel, "advansys");
17605 if (ret) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017606 ASC_PRINT3
17607 ("advansys_board_found: board %d: request_dma() %d failed %d\n",
17608 boardp->id, shost->dma_channel, ret);
Matthew Wilcox71f36112007-07-30 08:04:53 -060017609 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017610 }
17611 AscEnableIsaDma(shost->dma_channel);
17612 }
17613 }
17614#endif /* CONFIG_ISA */
17615
17616 /* Register IRQ Number. */
17617 ASC_DBG1(2, "advansys_board_found: request_irq() %d\n", shost->irq);
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017618
17619 ret = request_irq(shost->irq, advansys_interrupt, share_irq,
17620 "advansys", shost);
17621
17622 if (ret) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017623 if (ret == -EBUSY) {
17624 ASC_PRINT2
17625 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x already in use.\n",
17626 boardp->id, shost->irq);
17627 } else if (ret == -EINVAL) {
17628 ASC_PRINT2
17629 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x not valid.\n",
17630 boardp->id, shost->irq);
17631 } else {
17632 ASC_PRINT3
17633 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x failed with %d\n",
17634 boardp->id, shost->irq, ret);
17635 }
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017636 goto err_free_dma;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017637 }
17638
17639 /*
17640 * Initialize board RISC chip and enable interrupts.
17641 */
17642 if (ASC_NARROW_BOARD(boardp)) {
17643 ASC_DBG(2, "advansys_board_found: AscInitAsc1000Driver()\n");
17644 warn_code = AscInitAsc1000Driver(asc_dvc_varp);
17645 err_code = asc_dvc_varp->err_code;
17646
17647 if (warn_code || err_code) {
17648 ASC_PRINT4
17649 ("advansys_board_found: board %d error: init_state 0x%x, warn 0x%x, error 0x%x\n",
17650 boardp->id,
17651 asc_dvc_varp->init_state, warn_code, err_code);
17652 }
17653 } else {
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017654 err_code = advansys_wide_init_chip(boardp, adv_dvc_varp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017655 }
17656
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017657 if (err_code != 0)
17658 goto err_free_wide_mem;
17659
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017660 ASC_DBG_PRT_SCSI_HOST(2, shost);
17661
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017662 ret = scsi_add_host(shost, dev);
17663 if (ret)
17664 goto err_free_wide_mem;
17665
17666 scsi_scan_host(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017667 return shost;
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017668
17669 err_free_wide_mem:
17670 advansys_wide_free_mem(boardp);
17671 free_irq(shost->irq, shost);
17672 err_free_dma:
17673 if (shost->dma_channel != NO_ISA_DMA)
17674 free_dma(shost->dma_channel);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017675 err_free_proc:
17676 kfree(boardp->prtbuf);
17677 err_unmap:
17678 if (boardp->ioremap_addr)
17679 iounmap(boardp->ioremap_addr);
17680 err_shost:
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017681 scsi_host_put(shost);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017682 return NULL;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017683}
17684
17685/*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017686 * advansys_release()
17687 *
17688 * Release resources allocated for a single AdvanSys adapter.
17689 */
17690static int advansys_release(struct Scsi_Host *shost)
17691{
17692 asc_board_t *boardp;
17693
17694 ASC_DBG(1, "advansys_release: begin\n");
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017695 scsi_remove_host(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017696 boardp = ASC_BOARDP(shost);
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017697 free_irq(shost->irq, shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017698 if (shost->dma_channel != NO_ISA_DMA) {
17699 ASC_DBG(1, "advansys_release: free_dma()\n");
17700 free_dma(shost->dma_channel);
17701 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017702 if (ASC_WIDE_BOARD(boardp)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017703 iounmap(boardp->ioremap_addr);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017704 advansys_wide_free_mem(boardp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017705 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017706 kfree(boardp->prtbuf);
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017707 scsi_host_put(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017708 ASC_DBG(1, "advansys_release: end\n");
17709 return 0;
17710}
17711
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017712static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __devinitdata = {
17713 0x100, 0x0110, 0x120, 0x0130, 0x140, 0x0150, 0x0190,
17714 0x0210, 0x0230, 0x0250, 0x0330
17715};
17716
17717static int __devinit advansys_isa_probe(struct device *dev, unsigned int id)
17718{
17719 PortAddr iop_base = _asc_def_iop_base[id];
17720 struct Scsi_Host *shost;
17721
17722 if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060017723 ASC_DBG1(1, "advansys_isa_match: I/O port 0x%x busy\n",
17724 iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017725 return -ENODEV;
17726 }
17727 ASC_DBG1(1, "advansys_isa_match: probing I/O port 0x%x\n", iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017728 if (!AscFindSignature(iop_base))
17729 goto nodev;
17730 if (!(AscGetChipVersion(iop_base, ASC_IS_ISA) & ASC_CHIP_VER_ISA_BIT))
17731 goto nodev;
17732
17733 shost = advansys_board_found(iop_base, dev, ASC_IS_ISA);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017734 if (!shost)
17735 goto nodev;
17736
17737 dev_set_drvdata(dev, shost);
17738 return 0;
17739
17740 nodev:
Matthew Wilcox71f36112007-07-30 08:04:53 -060017741 release_region(iop_base, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017742 return -ENODEV;
17743}
17744
17745static int __devexit advansys_isa_remove(struct device *dev, unsigned int id)
17746{
Matthew Wilcox71f36112007-07-30 08:04:53 -060017747 int ioport = _asc_def_iop_base[id];
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017748 advansys_release(dev_get_drvdata(dev));
Matthew Wilcox71f36112007-07-30 08:04:53 -060017749 release_region(ioport, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017750 return 0;
17751}
17752
17753static struct isa_driver advansys_isa_driver = {
17754 .probe = advansys_isa_probe,
17755 .remove = __devexit_p(advansys_isa_remove),
17756 .driver = {
17757 .owner = THIS_MODULE,
17758 .name = "advansys",
17759 },
17760};
17761
17762static int __devinit advansys_vlb_probe(struct device *dev, unsigned int id)
17763{
17764 PortAddr iop_base = _asc_def_iop_base[id];
17765 struct Scsi_Host *shost;
17766
17767 if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060017768 ASC_DBG1(1, "advansys_vlb_match: I/O port 0x%x busy\n",
17769 iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017770 return -ENODEV;
17771 }
17772 ASC_DBG1(1, "advansys_vlb_match: probing I/O port 0x%x\n", iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017773 if (!AscFindSignature(iop_base))
17774 goto nodev;
17775 /*
17776 * I don't think this condition can actually happen, but the old
17777 * driver did it, and the chances of finding a VLB setup in 2007
17778 * to do testing with is slight to none.
17779 */
17780 if (AscGetChipVersion(iop_base, ASC_IS_VL) > ASC_CHIP_MAX_VER_VL)
17781 goto nodev;
17782
17783 shost = advansys_board_found(iop_base, dev, ASC_IS_VL);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017784 if (!shost)
17785 goto nodev;
17786
17787 dev_set_drvdata(dev, shost);
17788 return 0;
17789
17790 nodev:
Matthew Wilcox71f36112007-07-30 08:04:53 -060017791 release_region(iop_base, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017792 return -ENODEV;
17793}
17794
17795static struct isa_driver advansys_vlb_driver = {
17796 .probe = advansys_vlb_probe,
17797 .remove = __devexit_p(advansys_isa_remove),
17798 .driver = {
17799 .owner = THIS_MODULE,
17800 .name = "advansys",
17801 },
17802};
17803
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017804static struct eisa_device_id advansys_eisa_table[] __devinitdata = {
17805 { "ABP7401" },
17806 { "ABP7501" },
17807 { "" }
17808};
17809
17810MODULE_DEVICE_TABLE(eisa, advansys_eisa_table);
17811
17812/*
17813 * EISA is a little more tricky than PCI; each EISA device may have two
17814 * channels, and this driver is written to make each channel its own Scsi_Host
17815 */
17816struct eisa_scsi_data {
17817 struct Scsi_Host *host[2];
17818};
17819
17820static int __devinit advansys_eisa_probe(struct device *dev)
17821{
17822 int i, ioport;
17823 int err;
17824 struct eisa_device *edev = to_eisa_device(dev);
17825 struct eisa_scsi_data *data;
17826
17827 err = -ENOMEM;
17828 data = kzalloc(sizeof(*data), GFP_KERNEL);
17829 if (!data)
17830 goto fail;
17831 ioport = edev->base_addr + 0xc30;
17832
17833 err = -ENODEV;
17834 for (i = 0; i < 2; i++, ioport += 0x20) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060017835 if (!request_region(ioport, ASC_IOADR_GAP, "advansys")) {
17836 printk(KERN_WARNING "Region %x-%x busy\n", ioport,
17837 ioport + ASC_IOADR_GAP - 1);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017838 continue;
Matthew Wilcox71f36112007-07-30 08:04:53 -060017839 }
17840 if (!AscFindSignature(ioport)) {
17841 release_region(ioport, ASC_IOADR_GAP);
17842 continue;
17843 }
17844
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017845 /*
17846 * I don't know why we need to do this for EISA chips, but
17847 * not for any others. It looks to be equivalent to
17848 * AscGetChipCfgMsw, but I may have overlooked something,
17849 * so I'm not converting it until I get an EISA board to
17850 * test with.
17851 */
17852 inw(ioport + 4);
17853 data->host[i] = advansys_board_found(ioport, dev, ASC_IS_EISA);
Matthew Wilcox71f36112007-07-30 08:04:53 -060017854 if (data->host[i]) {
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017855 err = 0;
Matthew Wilcox71f36112007-07-30 08:04:53 -060017856 } else {
17857 release_region(ioport, ASC_IOADR_GAP);
17858 }
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017859 }
17860
17861 if (err) {
17862 kfree(data);
17863 } else {
17864 dev_set_drvdata(dev, data);
17865 }
17866
17867 fail:
17868 return err;
17869}
17870
17871static __devexit int advansys_eisa_remove(struct device *dev)
17872{
17873 int i;
17874 struct eisa_scsi_data *data = dev_get_drvdata(dev);
17875
17876 for (i = 0; i < 2; i++) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060017877 int ioport;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017878 struct Scsi_Host *shost = data->host[i];
17879 if (!shost)
17880 continue;
Matthew Wilcox71f36112007-07-30 08:04:53 -060017881 ioport = shost->io_port;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017882 advansys_release(shost);
Matthew Wilcox71f36112007-07-30 08:04:53 -060017883 release_region(ioport, ASC_IOADR_GAP);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017884 }
17885
17886 kfree(data);
17887 return 0;
17888}
17889
17890static struct eisa_driver advansys_eisa_driver = {
17891 .id_table = advansys_eisa_table,
17892 .driver = {
17893 .name = "advansys",
17894 .probe = advansys_eisa_probe,
17895 .remove = __devexit_p(advansys_eisa_remove),
17896 }
17897};
17898
Dave Jones2672ea82006-08-02 17:11:49 -040017899/* PCI Devices supported by this driver */
17900static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017901 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A,
17902 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
17903 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940,
17904 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
17905 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940U,
17906 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
17907 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940UW,
17908 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
17909 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C0800_REV1,
17910 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
17911 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C1600_REV1,
17912 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
17913 {}
Dave Jones2672ea82006-08-02 17:11:49 -040017914};
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017915
Dave Jones2672ea82006-08-02 17:11:49 -040017916MODULE_DEVICE_TABLE(pci, advansys_pci_tbl);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017917
Matthew Wilcox9649af32007-07-26 21:51:47 -060017918static void __devinit advansys_set_latency(struct pci_dev *pdev)
17919{
17920 if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) ||
17921 (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) {
17922 pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0);
17923 } else {
17924 u8 latency;
17925 pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency);
17926 if (latency < 0x20)
17927 pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x20);
17928 }
17929}
17930
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017931static int __devinit
17932advansys_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
17933{
17934 int err, ioport;
17935 struct Scsi_Host *shost;
17936
17937 err = pci_enable_device(pdev);
17938 if (err)
17939 goto fail;
Matthew Wilcox71f36112007-07-30 08:04:53 -060017940 err = pci_request_regions(pdev, "advansys");
17941 if (err)
17942 goto disable_device;
Matthew Wilcox9649af32007-07-26 21:51:47 -060017943 pci_set_master(pdev);
17944 advansys_set_latency(pdev);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017945
17946 if (pci_resource_len(pdev, 0) == 0)
17947 goto nodev;
17948
17949 ioport = pci_resource_start(pdev, 0);
17950 shost = advansys_board_found(ioport, &pdev->dev, ASC_IS_PCI);
17951
17952 if (!shost)
17953 goto nodev;
17954
17955 pci_set_drvdata(pdev, shost);
17956 return 0;
17957
17958 nodev:
17959 err = -ENODEV;
Matthew Wilcox71f36112007-07-30 08:04:53 -060017960 pci_release_regions(pdev);
17961 disable_device:
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017962 pci_disable_device(pdev);
17963 fail:
17964 return err;
17965}
17966
17967static void __devexit advansys_pci_remove(struct pci_dev *pdev)
17968{
17969 advansys_release(pci_get_drvdata(pdev));
Matthew Wilcox71f36112007-07-30 08:04:53 -060017970 pci_release_regions(pdev);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017971 pci_disable_device(pdev);
17972}
17973
17974static struct pci_driver advansys_pci_driver = {
17975 .name = "advansys",
17976 .id_table = advansys_pci_tbl,
17977 .probe = advansys_pci_probe,
17978 .remove = __devexit_p(advansys_pci_remove),
17979};
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040017980
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017981static int __init advansys_init(void)
17982{
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017983 int error;
17984
17985 error = isa_register_driver(&advansys_isa_driver,
17986 ASC_IOADR_TABLE_MAX_IX);
17987 if (error)
17988 goto fail;
17989
17990 error = isa_register_driver(&advansys_vlb_driver,
17991 ASC_IOADR_TABLE_MAX_IX);
17992 if (error)
17993 goto unregister_isa;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017994
17995 error = eisa_driver_register(&advansys_eisa_driver);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017996 if (error)
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017997 goto unregister_vlb;
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017998
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017999 error = pci_register_driver(&advansys_pci_driver);
18000 if (error)
18001 goto unregister_eisa;
18002
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018003 return 0;
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018004
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018005 unregister_eisa:
18006 eisa_driver_unregister(&advansys_eisa_driver);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018007 unregister_vlb:
18008 isa_unregister_driver(&advansys_vlb_driver);
18009 unregister_isa:
18010 isa_unregister_driver(&advansys_isa_driver);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018011 fail:
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018012 return error;
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018013}
18014
18015static void __exit advansys_exit(void)
18016{
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018017 pci_unregister_driver(&advansys_pci_driver);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018018 eisa_driver_unregister(&advansys_eisa_driver);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018019 isa_unregister_driver(&advansys_vlb_driver);
18020 isa_unregister_driver(&advansys_isa_driver);
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018021}
18022
18023module_init(advansys_init);
18024module_exit(advansys_exit);
18025
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040018026MODULE_LICENSE("GPL");