blob: 526239a21332039b2c9703a146f7e1275df44f77 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <linux/string.h>
25#include <linux/kernel.h>
26#include <linux/types.h>
27#include <linux/ioport.h>
28#include <linux/interrupt.h>
29#include <linux/delay.h>
30#include <linux/slab.h>
31#include <linux/mm.h>
32#include <linux/proc_fs.h>
33#include <linux/init.h>
34#include <linux/blkdev.h>
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060035#include <linux/isa.h>
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060036#include <linux/eisa.h>
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040037#include <linux/pci.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <linux/spinlock.h>
39#include <linux/dma-mapping.h>
40
41#include <asm/io.h>
42#include <asm/system.h>
43#include <asm/dma.h>
44
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040045#include <scsi/scsi_cmnd.h>
46#include <scsi/scsi_device.h>
47#include <scsi/scsi_tcq.h>
48#include <scsi/scsi.h>
49#include <scsi/scsi_host.h>
50
Matthew Wilcox4bd6d7f2007-07-30 08:41:03 -060051/* FIXME:
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 *
Matthew Wilcox4bd6d7f2007-07-30 08:41:03 -060053 * 1. Although all of the necessary command mapping places have the
54 * appropriate dma_map.. APIs, the driver still processes its internal
55 * queue using bus_to_virt() and virt_to_bus() which are illegal under
56 * the API. The entire queue processing structure will need to be
57 * altered to fix this.
58 * 2. Need to add memory mapping workaround. Test the memory mapping.
59 * If it doesn't work revert to I/O port access. Can a test be done
60 * safely?
61 * 3. Handle an interrupt not working. Keep an interrupt counter in
62 * the interrupt handler. In the timeout function if the interrupt
63 * has not occurred then print a message and run in polled mode.
64 * 4. Need to add support for target mode commands, cf. CAM XPT.
65 * 5. check DMA mapping functions for failure
66 * 6. Remove internal queueing
67 * 7. Use scsi_transport_spi
68 * 8. advansys_info is not safe against multiple simultaneous callers
69 * 9. Kill boardp->id
70 * 10. Add module_param to override ISA/VLB ioport array
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 */
72#warning this driver is still not properly converted to the DMA API
73
Linus Torvalds1da177e2005-04-16 15:20:36 -070074/* Enable driver assertions. */
75#define ADVANSYS_ASSERT
76
77/* Enable driver /proc statistics. */
78#define ADVANSYS_STATS
79
80/* Enable driver tracing. */
81/* #define ADVANSYS_DEBUG */
82
Linus Torvalds1da177e2005-04-16 15:20:36 -070083/*
84 * --- Asc Library Constants and Macros
85 */
86
87#define ASC_LIB_VERSION_MAJOR 1
88#define ASC_LIB_VERSION_MINOR 24
89#define ASC_LIB_SERIAL_NUMBER 123
90
91/*
92 * Portable Data Types
93 *
94 * Any instance where a 32-bit long or pointer type is assumed
95 * for precision or HW defined structures, the following define
96 * types must be used. In Linux the char, short, and int types
97 * are all consistent at 8, 16, and 32 bits respectively. Pointers
98 * and long types are 64 bits on Alpha and UltraSPARC.
99 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400100#define ASC_PADDR __u32 /* Physical/Bus address data type. */
101#define ASC_VADDR __u32 /* Virtual address data type. */
102#define ASC_DCNT __u32 /* Unsigned Data count type. */
103#define ASC_SDCNT __s32 /* Signed Data count type. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
105/*
106 * These macros are used to convert a virtual address to a
107 * 32-bit value. This currently can be used on Linux Alpha
108 * which uses 64-bit virtual address but a 32-bit bus address.
109 * This is likely to break in the future, but doing this now
110 * will give us time to change the HW and FW to handle 64-bit
111 * addresses.
112 */
113#define ASC_VADDR_TO_U32 virt_to_bus
114#define ASC_U32_TO_VADDR bus_to_virt
115
116typedef unsigned char uchar;
117
118#ifndef TRUE
119#define TRUE (1)
120#endif
121#ifndef FALSE
122#define FALSE (0)
123#endif
124
125#define EOF (-1)
126#define ERR (-1)
127#define UW_ERR (uint)(0xFFFF)
128#define isodd_word(val) ((((uint)val) & (uint)0x0001) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
130#define ASC_DVCLIB_CALL_DONE (1)
131#define ASC_DVCLIB_CALL_FAILED (0)
132#define ASC_DVCLIB_CALL_ERROR (-1)
133
Dave Jones2672ea82006-08-02 17:11:49 -0400134#define PCI_VENDOR_ID_ASP 0x10cd
135#define PCI_DEVICE_ID_ASP_1200A 0x1100
136#define PCI_DEVICE_ID_ASP_ABP940 0x1200
137#define PCI_DEVICE_ID_ASP_ABP940U 0x1300
138#define PCI_DEVICE_ID_ASP_ABP940UW 0x2300
139#define PCI_DEVICE_ID_38C0800_REV1 0x2500
140#define PCI_DEVICE_ID_38C1600_REV1 0x2700
141
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142/*
143 * Enable CC_VERY_LONG_SG_LIST to support up to 64K element SG lists.
144 * The SRB structure will have to be changed and the ASC_SRB2SCSIQ()
145 * macro re-defined to be able to obtain a ASC_SCSI_Q pointer from the
146 * SRB structure.
147 */
148#define CC_VERY_LONG_SG_LIST 0
149#define ASC_SRB2SCSIQ(srb_ptr) (srb_ptr)
150
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400151#define PortAddr unsigned short /* port address size */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152#define inp(port) inb(port)
153#define outp(port, byte) outb((byte), (port))
154
155#define inpw(port) inw(port)
156#define outpw(port, word) outw((word), (port))
157
158#define ASC_MAX_SG_QUEUE 7
159#define ASC_MAX_SG_LIST 255
160
161#define ASC_CS_TYPE unsigned short
162
163#define ASC_IS_ISA (0x0001)
164#define ASC_IS_ISAPNP (0x0081)
165#define ASC_IS_EISA (0x0002)
166#define ASC_IS_PCI (0x0004)
167#define ASC_IS_PCI_ULTRA (0x0104)
168#define ASC_IS_PCMCIA (0x0008)
169#define ASC_IS_MCA (0x0020)
170#define ASC_IS_VL (0x0040)
171#define ASC_ISA_PNP_PORT_ADDR (0x279)
172#define ASC_ISA_PNP_PORT_WRITE (ASC_ISA_PNP_PORT_ADDR+0x800)
173#define ASC_IS_WIDESCSI_16 (0x0100)
174#define ASC_IS_WIDESCSI_32 (0x0200)
175#define ASC_IS_BIG_ENDIAN (0x8000)
176#define ASC_CHIP_MIN_VER_VL (0x01)
177#define ASC_CHIP_MAX_VER_VL (0x07)
178#define ASC_CHIP_MIN_VER_PCI (0x09)
179#define ASC_CHIP_MAX_VER_PCI (0x0F)
180#define ASC_CHIP_VER_PCI_BIT (0x08)
181#define ASC_CHIP_MIN_VER_ISA (0x11)
182#define ASC_CHIP_MIN_VER_ISA_PNP (0x21)
183#define ASC_CHIP_MAX_VER_ISA (0x27)
184#define ASC_CHIP_VER_ISA_BIT (0x30)
185#define ASC_CHIP_VER_ISAPNP_BIT (0x20)
186#define ASC_CHIP_VER_ASYN_BUG (0x21)
187#define ASC_CHIP_VER_PCI 0x08
188#define ASC_CHIP_VER_PCI_ULTRA_3150 (ASC_CHIP_VER_PCI | 0x02)
189#define ASC_CHIP_VER_PCI_ULTRA_3050 (ASC_CHIP_VER_PCI | 0x03)
190#define ASC_CHIP_MIN_VER_EISA (0x41)
191#define ASC_CHIP_MAX_VER_EISA (0x47)
192#define ASC_CHIP_VER_EISA_BIT (0x40)
193#define ASC_CHIP_LATEST_VER_EISA ((ASC_CHIP_MIN_VER_EISA - 1) + 3)
194#define ASC_MAX_LIB_SUPPORTED_ISA_CHIP_VER 0x21
195#define ASC_MAX_LIB_SUPPORTED_PCI_CHIP_VER 0x0A
196#define ASC_MAX_VL_DMA_ADDR (0x07FFFFFFL)
197#define ASC_MAX_VL_DMA_COUNT (0x07FFFFFFL)
198#define ASC_MAX_PCI_DMA_ADDR (0xFFFFFFFFL)
199#define ASC_MAX_PCI_DMA_COUNT (0xFFFFFFFFL)
200#define ASC_MAX_ISA_DMA_ADDR (0x00FFFFFFL)
201#define ASC_MAX_ISA_DMA_COUNT (0x00FFFFFFL)
202#define ASC_MAX_EISA_DMA_ADDR (0x07FFFFFFL)
203#define ASC_MAX_EISA_DMA_COUNT (0x07FFFFFFL)
204
205#define ASC_SCSI_ID_BITS 3
206#define ASC_SCSI_TIX_TYPE uchar
207#define ASC_ALL_DEVICE_BIT_SET 0xFF
208#define ASC_SCSI_BIT_ID_TYPE uchar
209#define ASC_MAX_TID 7
210#define ASC_MAX_LUN 7
211#define ASC_SCSI_WIDTH_BIT_SET 0xFF
212#define ASC_MAX_SENSE_LEN 32
213#define ASC_MIN_SENSE_LEN 14
214#define ASC_MAX_CDB_LEN 12
215#define ASC_SCSI_RESET_HOLD_TIME_US 60
216
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217/*
218 * Inquiry SPC-2 SPI Byte 1 EVPD (Enable Vital Product Data)
219 * and CmdDt (Command Support Data) field bit definitions.
220 */
221#define ADV_INQ_RTN_VPD_AND_CMDDT 0x3
222#define ADV_INQ_RTN_CMDDT_FOR_OP_CODE 0x2
223#define ADV_INQ_RTN_VPD_FOR_PG_CODE 0x1
224#define ADV_INQ_RTN_STD_INQUIRY_DATA 0x0
225
226#define ASC_SCSIDIR_NOCHK 0x00
227#define ASC_SCSIDIR_T2H 0x08
228#define ASC_SCSIDIR_H2T 0x10
229#define ASC_SCSIDIR_NODATA 0x18
230#define SCSI_ASC_NOMEDIA 0x3A
231#define ASC_SRB_HOST(x) ((uchar)((uchar)(x) >> 4))
232#define ASC_SRB_TID(x) ((uchar)((uchar)(x) & (uchar)0x0F))
233#define ASC_SRB_LUN(x) ((uchar)((uint)(x) >> 13))
234#define PUT_CDB1(x) ((uchar)((uint)(x) >> 8))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235#define MS_SDTR_LEN 0x03
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236#define MS_WDTR_LEN 0x02
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237
238#define ASC_SG_LIST_PER_Q 7
239#define QS_FREE 0x00
240#define QS_READY 0x01
241#define QS_DISC1 0x02
242#define QS_DISC2 0x04
243#define QS_BUSY 0x08
244#define QS_ABORTED 0x40
245#define QS_DONE 0x80
246#define QC_NO_CALLBACK 0x01
247#define QC_SG_SWAP_QUEUE 0x02
248#define QC_SG_HEAD 0x04
249#define QC_DATA_IN 0x08
250#define QC_DATA_OUT 0x10
251#define QC_URGENT 0x20
252#define QC_MSG_OUT 0x40
253#define QC_REQ_SENSE 0x80
254#define QCSG_SG_XFER_LIST 0x02
255#define QCSG_SG_XFER_MORE 0x04
256#define QCSG_SG_XFER_END 0x08
257#define QD_IN_PROGRESS 0x00
258#define QD_NO_ERROR 0x01
259#define QD_ABORTED_BY_HOST 0x02
260#define QD_WITH_ERROR 0x04
261#define QD_INVALID_REQUEST 0x80
262#define QD_INVALID_HOST_NUM 0x81
263#define QD_INVALID_DEVICE 0x82
264#define QD_ERR_INTERNAL 0xFF
265#define QHSTA_NO_ERROR 0x00
266#define QHSTA_M_SEL_TIMEOUT 0x11
267#define QHSTA_M_DATA_OVER_RUN 0x12
268#define QHSTA_M_DATA_UNDER_RUN 0x12
269#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
270#define QHSTA_M_BAD_BUS_PHASE_SEQ 0x14
271#define QHSTA_D_QDONE_SG_LIST_CORRUPTED 0x21
272#define QHSTA_D_ASC_DVC_ERROR_CODE_SET 0x22
273#define QHSTA_D_HOST_ABORT_FAILED 0x23
274#define QHSTA_D_EXE_SCSI_Q_FAILED 0x24
275#define QHSTA_D_EXE_SCSI_Q_BUSY_TIMEOUT 0x25
276#define QHSTA_D_ASPI_NO_BUF_POOL 0x26
277#define QHSTA_M_WTM_TIMEOUT 0x41
278#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42
279#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43
280#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
281#define QHSTA_M_TARGET_STATUS_BUSY 0x45
282#define QHSTA_M_BAD_TAG_CODE 0x46
283#define QHSTA_M_BAD_QUEUE_FULL_OR_BUSY 0x47
284#define QHSTA_M_HUNG_REQ_SCSI_BUS_RESET 0x48
285#define QHSTA_D_LRAM_CMP_ERROR 0x81
286#define QHSTA_M_MICRO_CODE_ERROR_HALT 0xA1
287#define ASC_FLAG_SCSIQ_REQ 0x01
288#define ASC_FLAG_BIOS_SCSIQ_REQ 0x02
289#define ASC_FLAG_BIOS_ASYNC_IO 0x04
290#define ASC_FLAG_SRB_LINEAR_ADDR 0x08
291#define ASC_FLAG_WIN16 0x10
292#define ASC_FLAG_WIN32 0x20
293#define ASC_FLAG_ISA_OVER_16MB 0x40
294#define ASC_FLAG_DOS_VM_CALLBACK 0x80
295#define ASC_TAG_FLAG_EXTRA_BYTES 0x10
296#define ASC_TAG_FLAG_DISABLE_DISCONNECT 0x04
297#define ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX 0x08
298#define ASC_TAG_FLAG_DISABLE_CHK_COND_INT_HOST 0x40
299#define ASC_SCSIQ_CPY_BEG 4
300#define ASC_SCSIQ_SGHD_CPY_BEG 2
301#define ASC_SCSIQ_B_FWD 0
302#define ASC_SCSIQ_B_BWD 1
303#define ASC_SCSIQ_B_STATUS 2
304#define ASC_SCSIQ_B_QNO 3
305#define ASC_SCSIQ_B_CNTL 4
306#define ASC_SCSIQ_B_SG_QUEUE_CNT 5
307#define ASC_SCSIQ_D_DATA_ADDR 8
308#define ASC_SCSIQ_D_DATA_CNT 12
309#define ASC_SCSIQ_B_SENSE_LEN 20
310#define ASC_SCSIQ_DONE_INFO_BEG 22
311#define ASC_SCSIQ_D_SRBPTR 22
312#define ASC_SCSIQ_B_TARGET_IX 26
313#define ASC_SCSIQ_B_CDB_LEN 28
314#define ASC_SCSIQ_B_TAG_CODE 29
315#define ASC_SCSIQ_W_VM_ID 30
316#define ASC_SCSIQ_DONE_STATUS 32
317#define ASC_SCSIQ_HOST_STATUS 33
318#define ASC_SCSIQ_SCSI_STATUS 34
319#define ASC_SCSIQ_CDB_BEG 36
320#define ASC_SCSIQ_DW_REMAIN_XFER_ADDR 56
321#define ASC_SCSIQ_DW_REMAIN_XFER_CNT 60
322#define ASC_SCSIQ_B_FIRST_SG_WK_QP 48
323#define ASC_SCSIQ_B_SG_WK_QP 49
324#define ASC_SCSIQ_B_SG_WK_IX 50
325#define ASC_SCSIQ_W_ALT_DC1 52
326#define ASC_SCSIQ_B_LIST_CNT 6
327#define ASC_SCSIQ_B_CUR_LIST_CNT 7
328#define ASC_SGQ_B_SG_CNTL 4
329#define ASC_SGQ_B_SG_HEAD_QP 5
330#define ASC_SGQ_B_SG_LIST_CNT 6
331#define ASC_SGQ_B_SG_CUR_LIST_CNT 7
332#define ASC_SGQ_LIST_BEG 8
333#define ASC_DEF_SCSI1_QNG 4
334#define ASC_MAX_SCSI1_QNG 4
335#define ASC_DEF_SCSI2_QNG 16
336#define ASC_MAX_SCSI2_QNG 32
337#define ASC_TAG_CODE_MASK 0x23
338#define ASC_STOP_REQ_RISC_STOP 0x01
339#define ASC_STOP_ACK_RISC_STOP 0x03
340#define ASC_STOP_CLEAN_UP_BUSY_Q 0x10
341#define ASC_STOP_CLEAN_UP_DISC_Q 0x20
342#define ASC_STOP_HOST_REQ_RISC_HALT 0x40
343#define ASC_TIDLUN_TO_IX(tid, lun) (ASC_SCSI_TIX_TYPE)((tid) + ((lun)<<ASC_SCSI_ID_BITS))
344#define ASC_TID_TO_TARGET_ID(tid) (ASC_SCSI_BIT_ID_TYPE)(0x01 << (tid))
345#define ASC_TIX_TO_TARGET_ID(tix) (0x01 << ((tix) & ASC_MAX_TID))
346#define ASC_TIX_TO_TID(tix) ((tix) & ASC_MAX_TID)
347#define ASC_TID_TO_TIX(tid) ((tid) & ASC_MAX_TID)
348#define ASC_TIX_TO_LUN(tix) (((tix) >> ASC_SCSI_ID_BITS) & ASC_MAX_LUN)
349#define ASC_QNO_TO_QADDR(q_no) ((ASC_QADR_BEG)+((int)(q_no) << 6))
350
351typedef struct asc_scsiq_1 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400352 uchar status;
353 uchar q_no;
354 uchar cntl;
355 uchar sg_queue_cnt;
356 uchar target_id;
357 uchar target_lun;
358 ASC_PADDR data_addr;
359 ASC_DCNT data_cnt;
360 ASC_PADDR sense_addr;
361 uchar sense_len;
362 uchar extra_bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363} ASC_SCSIQ_1;
364
365typedef struct asc_scsiq_2 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400366 ASC_VADDR srb_ptr;
367 uchar target_ix;
368 uchar flag;
369 uchar cdb_len;
370 uchar tag_code;
371 ushort vm_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372} ASC_SCSIQ_2;
373
374typedef struct asc_scsiq_3 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400375 uchar done_stat;
376 uchar host_stat;
377 uchar scsi_stat;
378 uchar scsi_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379} ASC_SCSIQ_3;
380
381typedef struct asc_scsiq_4 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400382 uchar cdb[ASC_MAX_CDB_LEN];
383 uchar y_first_sg_list_qp;
384 uchar y_working_sg_qp;
385 uchar y_working_sg_ix;
386 uchar y_res;
387 ushort x_req_count;
388 ushort x_reconnect_rtn;
389 ASC_PADDR x_saved_data_addr;
390 ASC_DCNT x_saved_data_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391} ASC_SCSIQ_4;
392
393typedef struct asc_q_done_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400394 ASC_SCSIQ_2 d2;
395 ASC_SCSIQ_3 d3;
396 uchar q_status;
397 uchar q_no;
398 uchar cntl;
399 uchar sense_len;
400 uchar extra_bytes;
401 uchar res;
402 ASC_DCNT remain_bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403} ASC_QDONE_INFO;
404
405typedef struct asc_sg_list {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400406 ASC_PADDR addr;
407 ASC_DCNT bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408} ASC_SG_LIST;
409
410typedef struct asc_sg_head {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400411 ushort entry_cnt;
412 ushort queue_cnt;
413 ushort entry_to_copy;
414 ushort res;
415 ASC_SG_LIST sg_list[ASC_MAX_SG_LIST];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416} ASC_SG_HEAD;
417
418#define ASC_MIN_SG_LIST 2
419
420typedef struct asc_min_sg_head {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400421 ushort entry_cnt;
422 ushort queue_cnt;
423 ushort entry_to_copy;
424 ushort res;
425 ASC_SG_LIST sg_list[ASC_MIN_SG_LIST];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426} ASC_MIN_SG_HEAD;
427
428#define QCX_SORT (0x0001)
429#define QCX_COALEASE (0x0002)
430
431typedef struct asc_scsi_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400432 ASC_SCSIQ_1 q1;
433 ASC_SCSIQ_2 q2;
434 uchar *cdbptr;
435 ASC_SG_HEAD *sg_head;
436 ushort remain_sg_entry_cnt;
437 ushort next_sg_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438} ASC_SCSI_Q;
439
440typedef struct asc_scsi_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400441 ASC_SCSIQ_1 r1;
442 ASC_SCSIQ_2 r2;
443 uchar *cdbptr;
444 ASC_SG_HEAD *sg_head;
445 uchar *sense_ptr;
446 ASC_SCSIQ_3 r3;
447 uchar cdb[ASC_MAX_CDB_LEN];
448 uchar sense[ASC_MIN_SENSE_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449} ASC_SCSI_REQ_Q;
450
451typedef struct asc_scsi_bios_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400452 ASC_SCSIQ_1 r1;
453 ASC_SCSIQ_2 r2;
454 uchar *cdbptr;
455 ASC_SG_HEAD *sg_head;
456 uchar *sense_ptr;
457 ASC_SCSIQ_3 r3;
458 uchar cdb[ASC_MAX_CDB_LEN];
459 uchar sense[ASC_MIN_SENSE_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460} ASC_SCSI_BIOS_REQ_Q;
461
462typedef struct asc_risc_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400463 uchar fwd;
464 uchar bwd;
465 ASC_SCSIQ_1 i1;
466 ASC_SCSIQ_2 i2;
467 ASC_SCSIQ_3 i3;
468 ASC_SCSIQ_4 i4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469} ASC_RISC_Q;
470
471typedef struct asc_sg_list_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400472 uchar seq_no;
473 uchar q_no;
474 uchar cntl;
475 uchar sg_head_qp;
476 uchar sg_list_cnt;
477 uchar sg_cur_list_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478} ASC_SG_LIST_Q;
479
480typedef struct asc_risc_sg_list_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400481 uchar fwd;
482 uchar bwd;
483 ASC_SG_LIST_Q sg;
484 ASC_SG_LIST sg_list[7];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485} ASC_RISC_SG_LIST_Q;
486
487#define ASC_EXE_SCSI_IO_MAX_IDLE_LOOP 0x1000000UL
488#define ASC_EXE_SCSI_IO_MAX_WAIT_LOOP 1024
489#define ASCQ_ERR_NO_ERROR 0
490#define ASCQ_ERR_IO_NOT_FOUND 1
491#define ASCQ_ERR_LOCAL_MEM 2
492#define ASCQ_ERR_CHKSUM 3
493#define ASCQ_ERR_START_CHIP 4
494#define ASCQ_ERR_INT_TARGET_ID 5
495#define ASCQ_ERR_INT_LOCAL_MEM 6
496#define ASCQ_ERR_HALT_RISC 7
497#define ASCQ_ERR_GET_ASPI_ENTRY 8
498#define ASCQ_ERR_CLOSE_ASPI 9
499#define ASCQ_ERR_HOST_INQUIRY 0x0A
500#define ASCQ_ERR_SAVED_SRB_BAD 0x0B
501#define ASCQ_ERR_QCNTL_SG_LIST 0x0C
502#define ASCQ_ERR_Q_STATUS 0x0D
503#define ASCQ_ERR_WR_SCSIQ 0x0E
504#define ASCQ_ERR_PC_ADDR 0x0F
505#define ASCQ_ERR_SYN_OFFSET 0x10
506#define ASCQ_ERR_SYN_XFER_TIME 0x11
507#define ASCQ_ERR_LOCK_DMA 0x12
508#define ASCQ_ERR_UNLOCK_DMA 0x13
509#define ASCQ_ERR_VDS_CHK_INSTALL 0x14
510#define ASCQ_ERR_MICRO_CODE_HALT 0x15
511#define ASCQ_ERR_SET_LRAM_ADDR 0x16
512#define ASCQ_ERR_CUR_QNG 0x17
513#define ASCQ_ERR_SG_Q_LINKS 0x18
514#define ASCQ_ERR_SCSIQ_PTR 0x19
515#define ASCQ_ERR_ISR_RE_ENTRY 0x1A
516#define ASCQ_ERR_CRITICAL_RE_ENTRY 0x1B
517#define ASCQ_ERR_ISR_ON_CRITICAL 0x1C
518#define ASCQ_ERR_SG_LIST_ODD_ADDRESS 0x1D
519#define ASCQ_ERR_XFER_ADDRESS_TOO_BIG 0x1E
520#define ASCQ_ERR_SCSIQ_NULL_PTR 0x1F
521#define ASCQ_ERR_SCSIQ_BAD_NEXT_PTR 0x20
522#define ASCQ_ERR_GET_NUM_OF_FREE_Q 0x21
523#define ASCQ_ERR_SEND_SCSI_Q 0x22
524#define ASCQ_ERR_HOST_REQ_RISC_HALT 0x23
525#define ASCQ_ERR_RESET_SDTR 0x24
526
527/*
528 * Warning code values are set in ASC_DVC_VAR 'warn_code'.
529 */
530#define ASC_WARN_NO_ERROR 0x0000
531#define ASC_WARN_IO_PORT_ROTATE 0x0001
532#define ASC_WARN_EEPROM_CHKSUM 0x0002
533#define ASC_WARN_IRQ_MODIFIED 0x0004
534#define ASC_WARN_AUTO_CONFIG 0x0008
535#define ASC_WARN_CMD_QNG_CONFLICT 0x0010
536#define ASC_WARN_EEPROM_RECOVER 0x0020
537#define ASC_WARN_CFG_MSW_RECOVER 0x0040
538#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080
539
540/*
541 * Error code values are set in ASC_DVC_VAR 'err_code'.
542 */
543#define ASC_IERR_WRITE_EEPROM 0x0001
544#define ASC_IERR_MCODE_CHKSUM 0x0002
545#define ASC_IERR_SET_PC_ADDR 0x0004
546#define ASC_IERR_START_STOP_CHIP 0x0008
547#define ASC_IERR_IRQ_NO 0x0010
548#define ASC_IERR_SET_IRQ_NO 0x0020
549#define ASC_IERR_CHIP_VERSION 0x0040
550#define ASC_IERR_SET_SCSI_ID 0x0080
551#define ASC_IERR_GET_PHY_ADDR 0x0100
552#define ASC_IERR_BAD_SIGNATURE 0x0200
553#define ASC_IERR_NO_BUS_TYPE 0x0400
554#define ASC_IERR_SCAM 0x0800
555#define ASC_IERR_SET_SDTR 0x1000
556#define ASC_IERR_RW_LRAM 0x8000
557
558#define ASC_DEF_IRQ_NO 10
559#define ASC_MAX_IRQ_NO 15
560#define ASC_MIN_IRQ_NO 10
561#define ASC_MIN_REMAIN_Q (0x02)
562#define ASC_DEF_MAX_TOTAL_QNG (0xF0)
563#define ASC_MIN_TAG_Q_PER_DVC (0x04)
564#define ASC_DEF_TAG_Q_PER_DVC (0x04)
565#define ASC_MIN_FREE_Q ASC_MIN_REMAIN_Q
566#define ASC_MIN_TOTAL_QNG ((ASC_MAX_SG_QUEUE)+(ASC_MIN_FREE_Q))
567#define ASC_MAX_TOTAL_QNG 240
568#define ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG 16
569#define ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG 8
570#define ASC_MAX_PCI_INRAM_TOTAL_QNG 20
571#define ASC_MAX_INRAM_TAG_QNG 16
572#define ASC_IOADR_TABLE_MAX_IX 11
573#define ASC_IOADR_GAP 0x10
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574#define ASC_LIB_SCSIQ_WK_SP 256
575#define ASC_MAX_SYN_XFER_NO 16
576#define ASC_SYN_MAX_OFFSET 0x0F
577#define ASC_DEF_SDTR_OFFSET 0x0F
578#define ASC_DEF_SDTR_INDEX 0x00
579#define ASC_SDTR_ULTRA_PCI_10MB_INDEX 0x02
580#define SYN_XFER_NS_0 25
581#define SYN_XFER_NS_1 30
582#define SYN_XFER_NS_2 35
583#define SYN_XFER_NS_3 40
584#define SYN_XFER_NS_4 50
585#define SYN_XFER_NS_5 60
586#define SYN_XFER_NS_6 70
587#define SYN_XFER_NS_7 85
588#define SYN_ULTRA_XFER_NS_0 12
589#define SYN_ULTRA_XFER_NS_1 19
590#define SYN_ULTRA_XFER_NS_2 25
591#define SYN_ULTRA_XFER_NS_3 32
592#define SYN_ULTRA_XFER_NS_4 38
593#define SYN_ULTRA_XFER_NS_5 44
594#define SYN_ULTRA_XFER_NS_6 50
595#define SYN_ULTRA_XFER_NS_7 57
596#define SYN_ULTRA_XFER_NS_8 63
597#define SYN_ULTRA_XFER_NS_9 69
598#define SYN_ULTRA_XFER_NS_10 75
599#define SYN_ULTRA_XFER_NS_11 82
600#define SYN_ULTRA_XFER_NS_12 88
601#define SYN_ULTRA_XFER_NS_13 94
602#define SYN_ULTRA_XFER_NS_14 100
603#define SYN_ULTRA_XFER_NS_15 107
604
605typedef struct ext_msg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400606 uchar msg_type;
607 uchar msg_len;
608 uchar msg_req;
609 union {
610 struct {
611 uchar sdtr_xfer_period;
612 uchar sdtr_req_ack_offset;
613 } sdtr;
614 struct {
615 uchar wdtr_width;
616 } wdtr;
617 struct {
618 uchar mdp_b3;
619 uchar mdp_b2;
620 uchar mdp_b1;
621 uchar mdp_b0;
622 } mdp;
623 } u_ext_msg;
624 uchar res;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625} EXT_MSG;
626
627#define xfer_period u_ext_msg.sdtr.sdtr_xfer_period
628#define req_ack_offset u_ext_msg.sdtr.sdtr_req_ack_offset
629#define wdtr_width u_ext_msg.wdtr.wdtr_width
630#define mdp_b3 u_ext_msg.mdp_b3
631#define mdp_b2 u_ext_msg.mdp_b2
632#define mdp_b1 u_ext_msg.mdp_b1
633#define mdp_b0 u_ext_msg.mdp_b0
634
635typedef struct asc_dvc_cfg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400636 ASC_SCSI_BIT_ID_TYPE can_tagged_qng;
637 ASC_SCSI_BIT_ID_TYPE cmd_qng_enabled;
638 ASC_SCSI_BIT_ID_TYPE disc_enable;
639 ASC_SCSI_BIT_ID_TYPE sdtr_enable;
640 uchar chip_scsi_id;
641 uchar isa_dma_speed;
642 uchar isa_dma_channel;
643 uchar chip_version;
644 ushort lib_serial_no;
645 ushort lib_version;
646 ushort mcode_date;
647 ushort mcode_version;
648 uchar max_tag_qng[ASC_MAX_TID + 1];
649 uchar *overrun_buf;
650 uchar sdtr_period_offset[ASC_MAX_TID + 1];
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400651 uchar adapter_info[6];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652} ASC_DVC_CFG;
653
654#define ASC_DEF_DVC_CNTL 0xFFFF
655#define ASC_DEF_CHIP_SCSI_ID 7
656#define ASC_DEF_ISA_DMA_SPEED 4
657#define ASC_INIT_STATE_NULL 0x0000
658#define ASC_INIT_STATE_BEG_GET_CFG 0x0001
659#define ASC_INIT_STATE_END_GET_CFG 0x0002
660#define ASC_INIT_STATE_BEG_SET_CFG 0x0004
661#define ASC_INIT_STATE_END_SET_CFG 0x0008
662#define ASC_INIT_STATE_BEG_LOAD_MC 0x0010
663#define ASC_INIT_STATE_END_LOAD_MC 0x0020
664#define ASC_INIT_STATE_BEG_INQUIRY 0x0040
665#define ASC_INIT_STATE_END_INQUIRY 0x0080
666#define ASC_INIT_RESET_SCSI_DONE 0x0100
667#define ASC_INIT_STATE_WITHOUT_EEP 0x8000
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668#define ASC_BUG_FIX_IF_NOT_DWB 0x0001
669#define ASC_BUG_FIX_ASYN_USE_SYN 0x0002
670#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41
671#define ASC_MIN_TAGGED_CMD 7
672#define ASC_MAX_SCSI_RESET_WAIT 30
673
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400674struct asc_dvc_var; /* Forward Declaration. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676typedef struct asc_dvc_var {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400677 PortAddr iop_base;
678 ushort err_code;
679 ushort dvc_cntl;
680 ushort bug_fix_cntl;
681 ushort bus_type;
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400682 ASC_SCSI_BIT_ID_TYPE init_sdtr;
683 ASC_SCSI_BIT_ID_TYPE sdtr_done;
684 ASC_SCSI_BIT_ID_TYPE use_tagged_qng;
685 ASC_SCSI_BIT_ID_TYPE unit_not_ready;
686 ASC_SCSI_BIT_ID_TYPE queue_full_or_busy;
687 ASC_SCSI_BIT_ID_TYPE start_motor;
688 uchar scsi_reset_wait;
689 uchar chip_no;
690 char is_in_int;
691 uchar max_total_qng;
692 uchar cur_total_qng;
693 uchar in_critical_cnt;
694 uchar irq_no;
695 uchar last_q_shortage;
696 ushort init_state;
697 uchar cur_dvc_qng[ASC_MAX_TID + 1];
698 uchar max_dvc_qng[ASC_MAX_TID + 1];
699 ASC_SCSI_Q *scsiq_busy_head[ASC_MAX_TID + 1];
700 ASC_SCSI_Q *scsiq_busy_tail[ASC_MAX_TID + 1];
701 uchar sdtr_period_tbl[ASC_MAX_SYN_XFER_NO];
702 ASC_DVC_CFG *cfg;
703 ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer_always;
704 char redo_scam;
705 ushort res2;
706 uchar dos_int13_table[ASC_MAX_TID + 1];
707 ASC_DCNT max_dma_count;
708 ASC_SCSI_BIT_ID_TYPE no_scam;
709 ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer;
710 uchar max_sdtr_index;
711 uchar host_init_sdtr_index;
712 struct asc_board *drv_ptr;
713 ASC_DCNT uc_break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714} ASC_DVC_VAR;
715
716typedef struct asc_dvc_inq_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400717 uchar type[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718} ASC_DVC_INQ_INFO;
719
720typedef struct asc_cap_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400721 ASC_DCNT lba;
722 ASC_DCNT blk_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723} ASC_CAP_INFO;
724
725typedef struct asc_cap_info_array {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400726 ASC_CAP_INFO cap_info[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727} ASC_CAP_INFO_ARRAY;
728
729#define ASC_MCNTL_NO_SEL_TIMEOUT (ushort)0x0001
730#define ASC_MCNTL_NULL_TARGET (ushort)0x0002
731#define ASC_CNTL_INITIATOR (ushort)0x0001
732#define ASC_CNTL_BIOS_GT_1GB (ushort)0x0002
733#define ASC_CNTL_BIOS_GT_2_DISK (ushort)0x0004
734#define ASC_CNTL_BIOS_REMOVABLE (ushort)0x0008
735#define ASC_CNTL_NO_SCAM (ushort)0x0010
736#define ASC_CNTL_INT_MULTI_Q (ushort)0x0080
737#define ASC_CNTL_NO_LUN_SUPPORT (ushort)0x0040
738#define ASC_CNTL_NO_VERIFY_COPY (ushort)0x0100
739#define ASC_CNTL_RESET_SCSI (ushort)0x0200
740#define ASC_CNTL_INIT_INQUIRY (ushort)0x0400
741#define ASC_CNTL_INIT_VERBOSE (ushort)0x0800
742#define ASC_CNTL_SCSI_PARITY (ushort)0x1000
743#define ASC_CNTL_BURST_MODE (ushort)0x2000
744#define ASC_CNTL_SDTR_ENABLE_ULTRA (ushort)0x4000
745#define ASC_EEP_DVC_CFG_BEG_VL 2
746#define ASC_EEP_MAX_DVC_ADDR_VL 15
747#define ASC_EEP_DVC_CFG_BEG 32
748#define ASC_EEP_MAX_DVC_ADDR 45
749#define ASC_EEP_DEFINED_WORDS 10
750#define ASC_EEP_MAX_ADDR 63
751#define ASC_EEP_RES_WORDS 0
752#define ASC_EEP_MAX_RETRY 20
753#define ASC_MAX_INIT_BUSY_RETRY 8
754#define ASC_EEP_ISA_PNP_WSIZE 16
755
756/*
757 * These macros keep the chip SCSI id and ISA DMA speed
758 * bitfields in board order. C bitfields aren't portable
759 * between big and little-endian platforms so they are
760 * not used.
761 */
762
763#define ASC_EEP_GET_CHIP_ID(cfg) ((cfg)->id_speed & 0x0f)
764#define ASC_EEP_GET_DMA_SPD(cfg) (((cfg)->id_speed & 0xf0) >> 4)
765#define ASC_EEP_SET_CHIP_ID(cfg, sid) \
766 ((cfg)->id_speed = ((cfg)->id_speed & 0xf0) | ((sid) & ASC_MAX_TID))
767#define ASC_EEP_SET_DMA_SPD(cfg, spd) \
768 ((cfg)->id_speed = ((cfg)->id_speed & 0x0f) | ((spd) & 0x0f) << 4)
769
770typedef struct asceep_config {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400771 ushort cfg_lsw;
772 ushort cfg_msw;
773 uchar init_sdtr;
774 uchar disc_enable;
775 uchar use_cmd_qng;
776 uchar start_motor;
777 uchar max_total_qng;
778 uchar max_tag_qng;
779 uchar bios_scan;
780 uchar power_up_wait;
781 uchar no_scam;
782 uchar id_speed; /* low order 4 bits is chip scsi id */
783 /* high order 4 bits is isa dma speed */
784 uchar dos_int13_table[ASC_MAX_TID + 1];
785 uchar adapter_info[6];
786 ushort cntl;
787 ushort chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788} ASCEEP_CONFIG;
789
790#define ASC_PCI_CFG_LSW_SCSI_PARITY 0x0800
791#define ASC_PCI_CFG_LSW_BURST_MODE 0x0080
792#define ASC_PCI_CFG_LSW_INTR_ABLE 0x0020
793
794#define ASC_EEP_CMD_READ 0x80
795#define ASC_EEP_CMD_WRITE 0x40
796#define ASC_EEP_CMD_WRITE_ABLE 0x30
797#define ASC_EEP_CMD_WRITE_DISABLE 0x00
798#define ASC_OVERRUN_BSIZE 0x00000048UL
799#define ASC_CTRL_BREAK_ONCE 0x0001
800#define ASC_CTRL_BREAK_STAY_IDLE 0x0002
801#define ASCV_MSGOUT_BEG 0x0000
802#define ASCV_MSGOUT_SDTR_PERIOD (ASCV_MSGOUT_BEG+3)
803#define ASCV_MSGOUT_SDTR_OFFSET (ASCV_MSGOUT_BEG+4)
804#define ASCV_BREAK_SAVED_CODE (ushort)0x0006
805#define ASCV_MSGIN_BEG (ASCV_MSGOUT_BEG+8)
806#define ASCV_MSGIN_SDTR_PERIOD (ASCV_MSGIN_BEG+3)
807#define ASCV_MSGIN_SDTR_OFFSET (ASCV_MSGIN_BEG+4)
808#define ASCV_SDTR_DATA_BEG (ASCV_MSGIN_BEG+8)
809#define ASCV_SDTR_DONE_BEG (ASCV_SDTR_DATA_BEG+8)
810#define ASCV_MAX_DVC_QNG_BEG (ushort)0x0020
811#define ASCV_BREAK_ADDR (ushort)0x0028
812#define ASCV_BREAK_NOTIFY_COUNT (ushort)0x002A
813#define ASCV_BREAK_CONTROL (ushort)0x002C
814#define ASCV_BREAK_HIT_COUNT (ushort)0x002E
815
816#define ASCV_ASCDVC_ERR_CODE_W (ushort)0x0030
817#define ASCV_MCODE_CHKSUM_W (ushort)0x0032
818#define ASCV_MCODE_SIZE_W (ushort)0x0034
819#define ASCV_STOP_CODE_B (ushort)0x0036
820#define ASCV_DVC_ERR_CODE_B (ushort)0x0037
821#define ASCV_OVERRUN_PADDR_D (ushort)0x0038
822#define ASCV_OVERRUN_BSIZE_D (ushort)0x003C
823#define ASCV_HALTCODE_W (ushort)0x0040
824#define ASCV_CHKSUM_W (ushort)0x0042
825#define ASCV_MC_DATE_W (ushort)0x0044
826#define ASCV_MC_VER_W (ushort)0x0046
827#define ASCV_NEXTRDY_B (ushort)0x0048
828#define ASCV_DONENEXT_B (ushort)0x0049
829#define ASCV_USE_TAGGED_QNG_B (ushort)0x004A
830#define ASCV_SCSIBUSY_B (ushort)0x004B
831#define ASCV_Q_DONE_IN_PROGRESS_B (ushort)0x004C
832#define ASCV_CURCDB_B (ushort)0x004D
833#define ASCV_RCLUN_B (ushort)0x004E
834#define ASCV_BUSY_QHEAD_B (ushort)0x004F
835#define ASCV_DISC1_QHEAD_B (ushort)0x0050
836#define ASCV_DISC_ENABLE_B (ushort)0x0052
837#define ASCV_CAN_TAGGED_QNG_B (ushort)0x0053
838#define ASCV_HOSTSCSI_ID_B (ushort)0x0055
839#define ASCV_MCODE_CNTL_B (ushort)0x0056
840#define ASCV_NULL_TARGET_B (ushort)0x0057
841#define ASCV_FREE_Q_HEAD_W (ushort)0x0058
842#define ASCV_DONE_Q_TAIL_W (ushort)0x005A
843#define ASCV_FREE_Q_HEAD_B (ushort)(ASCV_FREE_Q_HEAD_W+1)
844#define ASCV_DONE_Q_TAIL_B (ushort)(ASCV_DONE_Q_TAIL_W+1)
845#define ASCV_HOST_FLAG_B (ushort)0x005D
846#define ASCV_TOTAL_READY_Q_B (ushort)0x0064
847#define ASCV_VER_SERIAL_B (ushort)0x0065
848#define ASCV_HALTCODE_SAVED_W (ushort)0x0066
849#define ASCV_WTM_FLAG_B (ushort)0x0068
850#define ASCV_RISC_FLAG_B (ushort)0x006A
851#define ASCV_REQ_SG_LIST_QP (ushort)0x006B
852#define ASC_HOST_FLAG_IN_ISR 0x01
853#define ASC_HOST_FLAG_ACK_INT 0x02
854#define ASC_RISC_FLAG_GEN_INT 0x01
855#define ASC_RISC_FLAG_REQ_SG_LIST 0x02
856#define IOP_CTRL (0x0F)
857#define IOP_STATUS (0x0E)
858#define IOP_INT_ACK IOP_STATUS
859#define IOP_REG_IFC (0x0D)
860#define IOP_SYN_OFFSET (0x0B)
861#define IOP_EXTRA_CONTROL (0x0D)
862#define IOP_REG_PC (0x0C)
863#define IOP_RAM_ADDR (0x0A)
864#define IOP_RAM_DATA (0x08)
865#define IOP_EEP_DATA (0x06)
866#define IOP_EEP_CMD (0x07)
867#define IOP_VERSION (0x03)
868#define IOP_CONFIG_HIGH (0x04)
869#define IOP_CONFIG_LOW (0x02)
870#define IOP_SIG_BYTE (0x01)
871#define IOP_SIG_WORD (0x00)
872#define IOP_REG_DC1 (0x0E)
873#define IOP_REG_DC0 (0x0C)
874#define IOP_REG_SB (0x0B)
875#define IOP_REG_DA1 (0x0A)
876#define IOP_REG_DA0 (0x08)
877#define IOP_REG_SC (0x09)
878#define IOP_DMA_SPEED (0x07)
879#define IOP_REG_FLAG (0x07)
880#define IOP_FIFO_H (0x06)
881#define IOP_FIFO_L (0x04)
882#define IOP_REG_ID (0x05)
883#define IOP_REG_QP (0x03)
884#define IOP_REG_IH (0x02)
885#define IOP_REG_IX (0x01)
886#define IOP_REG_AX (0x00)
887#define IFC_REG_LOCK (0x00)
888#define IFC_REG_UNLOCK (0x09)
889#define IFC_WR_EN_FILTER (0x10)
890#define IFC_RD_NO_EEPROM (0x10)
891#define IFC_SLEW_RATE (0x20)
892#define IFC_ACT_NEG (0x40)
893#define IFC_INP_FILTER (0x80)
894#define IFC_INIT_DEFAULT (IFC_ACT_NEG | IFC_REG_UNLOCK)
895#define SC_SEL (uchar)(0x80)
896#define SC_BSY (uchar)(0x40)
897#define SC_ACK (uchar)(0x20)
898#define SC_REQ (uchar)(0x10)
899#define SC_ATN (uchar)(0x08)
900#define SC_IO (uchar)(0x04)
901#define SC_CD (uchar)(0x02)
902#define SC_MSG (uchar)(0x01)
903#define SEC_SCSI_CTL (uchar)(0x80)
904#define SEC_ACTIVE_NEGATE (uchar)(0x40)
905#define SEC_SLEW_RATE (uchar)(0x20)
906#define SEC_ENABLE_FILTER (uchar)(0x10)
907#define ASC_HALT_EXTMSG_IN (ushort)0x8000
908#define ASC_HALT_CHK_CONDITION (ushort)0x8100
909#define ASC_HALT_SS_QUEUE_FULL (ushort)0x8200
910#define ASC_HALT_DISABLE_ASYN_USE_SYN_FIX (ushort)0x8300
911#define ASC_HALT_ENABLE_ASYN_USE_SYN_FIX (ushort)0x8400
912#define ASC_HALT_SDTR_REJECTED (ushort)0x4000
913#define ASC_HALT_HOST_COPY_SG_LIST_TO_RISC ( ushort )0x2000
914#define ASC_MAX_QNO 0xF8
915#define ASC_DATA_SEC_BEG (ushort)0x0080
916#define ASC_DATA_SEC_END (ushort)0x0080
917#define ASC_CODE_SEC_BEG (ushort)0x0080
918#define ASC_CODE_SEC_END (ushort)0x0080
919#define ASC_QADR_BEG (0x4000)
920#define ASC_QADR_USED (ushort)(ASC_MAX_QNO * 64)
921#define ASC_QADR_END (ushort)0x7FFF
922#define ASC_QLAST_ADR (ushort)0x7FC0
923#define ASC_QBLK_SIZE 0x40
924#define ASC_BIOS_DATA_QBEG 0xF8
925#define ASC_MIN_ACTIVE_QNO 0x01
926#define ASC_QLINK_END 0xFF
927#define ASC_EEPROM_WORDS 0x10
928#define ASC_MAX_MGS_LEN 0x10
929#define ASC_BIOS_ADDR_DEF 0xDC00
930#define ASC_BIOS_SIZE 0x3800
931#define ASC_BIOS_RAM_OFF 0x3800
932#define ASC_BIOS_RAM_SIZE 0x800
933#define ASC_BIOS_MIN_ADDR 0xC000
934#define ASC_BIOS_MAX_ADDR 0xEC00
935#define ASC_BIOS_BANK_SIZE 0x0400
936#define ASC_MCODE_START_ADDR 0x0080
937#define ASC_CFG0_HOST_INT_ON 0x0020
938#define ASC_CFG0_BIOS_ON 0x0040
939#define ASC_CFG0_VERA_BURST_ON 0x0080
940#define ASC_CFG0_SCSI_PARITY_ON 0x0800
941#define ASC_CFG1_SCSI_TARGET_ON 0x0080
942#define ASC_CFG1_LRAM_8BITS_ON 0x0800
943#define ASC_CFG_MSW_CLR_MASK 0x3080
944#define CSW_TEST1 (ASC_CS_TYPE)0x8000
945#define CSW_AUTO_CONFIG (ASC_CS_TYPE)0x4000
946#define CSW_RESERVED1 (ASC_CS_TYPE)0x2000
947#define CSW_IRQ_WRITTEN (ASC_CS_TYPE)0x1000
948#define CSW_33MHZ_SELECTED (ASC_CS_TYPE)0x0800
949#define CSW_TEST2 (ASC_CS_TYPE)0x0400
950#define CSW_TEST3 (ASC_CS_TYPE)0x0200
951#define CSW_RESERVED2 (ASC_CS_TYPE)0x0100
952#define CSW_DMA_DONE (ASC_CS_TYPE)0x0080
953#define CSW_FIFO_RDY (ASC_CS_TYPE)0x0040
954#define CSW_EEP_READ_DONE (ASC_CS_TYPE)0x0020
955#define CSW_HALTED (ASC_CS_TYPE)0x0010
956#define CSW_SCSI_RESET_ACTIVE (ASC_CS_TYPE)0x0008
957#define CSW_PARITY_ERR (ASC_CS_TYPE)0x0004
958#define CSW_SCSI_RESET_LATCH (ASC_CS_TYPE)0x0002
959#define CSW_INT_PENDING (ASC_CS_TYPE)0x0001
960#define CIW_CLR_SCSI_RESET_INT (ASC_CS_TYPE)0x1000
961#define CIW_INT_ACK (ASC_CS_TYPE)0x0100
962#define CIW_TEST1 (ASC_CS_TYPE)0x0200
963#define CIW_TEST2 (ASC_CS_TYPE)0x0400
964#define CIW_SEL_33MHZ (ASC_CS_TYPE)0x0800
965#define CIW_IRQ_ACT (ASC_CS_TYPE)0x1000
966#define CC_CHIP_RESET (uchar)0x80
967#define CC_SCSI_RESET (uchar)0x40
968#define CC_HALT (uchar)0x20
969#define CC_SINGLE_STEP (uchar)0x10
970#define CC_DMA_ABLE (uchar)0x08
971#define CC_TEST (uchar)0x04
972#define CC_BANK_ONE (uchar)0x02
973#define CC_DIAG (uchar)0x01
974#define ASC_1000_ID0W 0x04C1
975#define ASC_1000_ID0W_FIX 0x00C1
976#define ASC_1000_ID1B 0x25
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977#define ASC_EISA_REV_IOP_MASK (0x0C83)
978#define ASC_EISA_PID_IOP_MASK (0x0C80)
979#define ASC_EISA_CFG_IOP_MASK (0x0C86)
980#define ASC_GET_EISA_SLOT(iop) (PortAddr)((iop) & 0xF000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981#define INS_HALTINT (ushort)0x6281
982#define INS_HALT (ushort)0x6280
983#define INS_SINT (ushort)0x6200
984#define INS_RFLAG_WTM (ushort)0x7380
985#define ASC_MC_SAVE_CODE_WSIZE 0x500
986#define ASC_MC_SAVE_DATA_WSIZE 0x40
987
988typedef struct asc_mc_saved {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400989 ushort data[ASC_MC_SAVE_DATA_WSIZE];
990 ushort code[ASC_MC_SAVE_CODE_WSIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991} ASC_MC_SAVED;
992
993#define AscGetQDoneInProgress(port) AscReadLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B)
994#define AscPutQDoneInProgress(port, val) AscWriteLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B, val)
995#define AscGetVarFreeQHead(port) AscReadLramWord((port), ASCV_FREE_Q_HEAD_W)
996#define AscGetVarDoneQTail(port) AscReadLramWord((port), ASCV_DONE_Q_TAIL_W)
997#define AscPutVarFreeQHead(port, val) AscWriteLramWord((port), ASCV_FREE_Q_HEAD_W, val)
998#define AscPutVarDoneQTail(port, val) AscWriteLramWord((port), ASCV_DONE_Q_TAIL_W, val)
999#define AscGetRiscVarFreeQHead(port) AscReadLramByte((port), ASCV_NEXTRDY_B)
1000#define AscGetRiscVarDoneQTail(port) AscReadLramByte((port), ASCV_DONENEXT_B)
1001#define AscPutRiscVarFreeQHead(port, val) AscWriteLramByte((port), ASCV_NEXTRDY_B, val)
1002#define AscPutRiscVarDoneQTail(port, val) AscWriteLramByte((port), ASCV_DONENEXT_B, val)
1003#define AscPutMCodeSDTRDoneAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id), (data));
1004#define AscGetMCodeSDTRDoneAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id));
1005#define AscPutMCodeInitSDTRAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id), data);
1006#define AscGetMCodeInitSDTRAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id));
1007#define AscSynIndexToPeriod(index) (uchar)(asc_dvc->sdtr_period_tbl[ (index) ])
1008#define AscGetChipSignatureByte(port) (uchar)inp((port)+IOP_SIG_BYTE)
1009#define AscGetChipSignatureWord(port) (ushort)inpw((port)+IOP_SIG_WORD)
1010#define AscGetChipVerNo(port) (uchar)inp((port)+IOP_VERSION)
1011#define AscGetChipCfgLsw(port) (ushort)inpw((port)+IOP_CONFIG_LOW)
1012#define AscGetChipCfgMsw(port) (ushort)inpw((port)+IOP_CONFIG_HIGH)
1013#define AscSetChipCfgLsw(port, data) outpw((port)+IOP_CONFIG_LOW, data)
1014#define AscSetChipCfgMsw(port, data) outpw((port)+IOP_CONFIG_HIGH, data)
1015#define AscGetChipEEPCmd(port) (uchar)inp((port)+IOP_EEP_CMD)
1016#define AscSetChipEEPCmd(port, data) outp((port)+IOP_EEP_CMD, data)
1017#define AscGetChipEEPData(port) (ushort)inpw((port)+IOP_EEP_DATA)
1018#define AscSetChipEEPData(port, data) outpw((port)+IOP_EEP_DATA, data)
1019#define AscGetChipLramAddr(port) (ushort)inpw((PortAddr)((port)+IOP_RAM_ADDR))
1020#define AscSetChipLramAddr(port, addr) outpw((PortAddr)((port)+IOP_RAM_ADDR), addr)
1021#define AscGetChipLramData(port) (ushort)inpw((port)+IOP_RAM_DATA)
1022#define AscSetChipLramData(port, data) outpw((port)+IOP_RAM_DATA, data)
1023#define AscGetChipIFC(port) (uchar)inp((port)+IOP_REG_IFC)
1024#define AscSetChipIFC(port, data) outp((port)+IOP_REG_IFC, data)
1025#define AscGetChipStatus(port) (ASC_CS_TYPE)inpw((port)+IOP_STATUS)
1026#define AscSetChipStatus(port, cs_val) outpw((port)+IOP_STATUS, cs_val)
1027#define AscGetChipControl(port) (uchar)inp((port)+IOP_CTRL)
1028#define AscSetChipControl(port, cc_val) outp((port)+IOP_CTRL, cc_val)
1029#define AscGetChipSyn(port) (uchar)inp((port)+IOP_SYN_OFFSET)
1030#define AscSetChipSyn(port, data) outp((port)+IOP_SYN_OFFSET, data)
1031#define AscSetPCAddr(port, data) outpw((port)+IOP_REG_PC, data)
1032#define AscGetPCAddr(port) (ushort)inpw((port)+IOP_REG_PC)
1033#define AscIsIntPending(port) (AscGetChipStatus(port) & (CSW_INT_PENDING | CSW_SCSI_RESET_LATCH))
1034#define AscGetChipScsiID(port) ((AscGetChipCfgLsw(port) >> 8) & ASC_MAX_TID)
1035#define AscGetExtraControl(port) (uchar)inp((port)+IOP_EXTRA_CONTROL)
1036#define AscSetExtraControl(port, data) outp((port)+IOP_EXTRA_CONTROL, data)
1037#define AscReadChipAX(port) (ushort)inpw((port)+IOP_REG_AX)
1038#define AscWriteChipAX(port, data) outpw((port)+IOP_REG_AX, data)
1039#define AscReadChipIX(port) (uchar)inp((port)+IOP_REG_IX)
1040#define AscWriteChipIX(port, data) outp((port)+IOP_REG_IX, data)
1041#define AscReadChipIH(port) (ushort)inpw((port)+IOP_REG_IH)
1042#define AscWriteChipIH(port, data) outpw((port)+IOP_REG_IH, data)
1043#define AscReadChipQP(port) (uchar)inp((port)+IOP_REG_QP)
1044#define AscWriteChipQP(port, data) outp((port)+IOP_REG_QP, data)
1045#define AscReadChipFIFO_L(port) (ushort)inpw((port)+IOP_REG_FIFO_L)
1046#define AscWriteChipFIFO_L(port, data) outpw((port)+IOP_REG_FIFO_L, data)
1047#define AscReadChipFIFO_H(port) (ushort)inpw((port)+IOP_REG_FIFO_H)
1048#define AscWriteChipFIFO_H(port, data) outpw((port)+IOP_REG_FIFO_H, data)
1049#define AscReadChipDmaSpeed(port) (uchar)inp((port)+IOP_DMA_SPEED)
1050#define AscWriteChipDmaSpeed(port, data) outp((port)+IOP_DMA_SPEED, data)
1051#define AscReadChipDA0(port) (ushort)inpw((port)+IOP_REG_DA0)
1052#define AscWriteChipDA0(port) outpw((port)+IOP_REG_DA0, data)
1053#define AscReadChipDA1(port) (ushort)inpw((port)+IOP_REG_DA1)
1054#define AscWriteChipDA1(port) outpw((port)+IOP_REG_DA1, data)
1055#define AscReadChipDC0(port) (ushort)inpw((port)+IOP_REG_DC0)
1056#define AscWriteChipDC0(port) outpw((port)+IOP_REG_DC0, data)
1057#define AscReadChipDC1(port) (ushort)inpw((port)+IOP_REG_DC1)
1058#define AscWriteChipDC1(port) outpw((port)+IOP_REG_DC1, data)
1059#define AscReadChipDvcID(port) (uchar)inp((port)+IOP_REG_ID)
1060#define AscWriteChipDvcID(port, data) outp((port)+IOP_REG_ID, data)
1061
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001062static int AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg);
1063static int AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg);
1064static void AscWaitEEPRead(void);
1065static void AscWaitEEPWrite(void);
1066static ushort AscReadEEPWord(PortAddr, uchar);
1067static ushort AscWriteEEPWord(PortAddr, uchar, ushort);
1068static ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
1069static int AscSetEEPConfigOnce(PortAddr, ASCEEP_CONFIG *, ushort);
1070static int AscSetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
1071static int AscStartChip(PortAddr);
1072static int AscStopChip(PortAddr);
1073static void AscSetChipIH(PortAddr, ushort);
1074static int AscIsChipHalted(PortAddr);
1075static void AscAckInterrupt(PortAddr);
1076static void AscDisableInterrupt(PortAddr);
1077static void AscEnableInterrupt(PortAddr);
1078static void AscSetBank(PortAddr, uchar);
1079static int AscResetChipAndScsiBus(ASC_DVC_VAR *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001081static uchar AscGetIsaDmaSpeed(PortAddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001083static uchar AscReadLramByte(PortAddr, ushort);
1084static ushort AscReadLramWord(PortAddr, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001086static ASC_DCNT AscReadLramDWord(PortAddr, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001088static void AscWriteLramWord(PortAddr, ushort, ushort);
1089static void AscWriteLramByte(PortAddr, ushort, uchar);
1090static ASC_DCNT AscMemSumLramWord(PortAddr, ushort, int);
1091static void AscMemWordSetLram(PortAddr, ushort, ushort, int);
1092static void AscMemWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
1093static void AscMemDWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
1094static void AscMemWordCopyPtrFromLram(PortAddr, ushort, uchar *, int);
1095static ushort AscInitAscDvcVar(ASC_DVC_VAR *);
1096static ushort AscInitFromEEP(ASC_DVC_VAR *);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001097static ushort AscInitMicroCodeVar(ASC_DVC_VAR *);
1098static int AscTestExternalLram(ASC_DVC_VAR *);
1099static uchar AscMsgOutSDTR(ASC_DVC_VAR *, uchar, uchar);
1100static uchar AscCalSDTRData(ASC_DVC_VAR *, uchar, uchar);
1101static void AscSetChipSDTR(PortAddr, uchar, uchar);
1102static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *, uchar);
1103static uchar AscAllocFreeQueue(PortAddr, uchar);
1104static uchar AscAllocMultipleFreeQueue(PortAddr, uchar, uchar);
1105static int AscHostReqRiscHalt(PortAddr);
1106static int AscStopQueueExe(PortAddr);
1107static int AscSendScsiQueue(ASC_DVC_VAR *,
1108 ASC_SCSI_Q *scsiq, uchar n_q_required);
1109static int AscPutReadyQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
1110static int AscPutReadySgListQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
1111static int AscSetChipSynRegAtID(PortAddr, uchar, uchar);
1112static int AscSetRunChipSynRegAtID(PortAddr, uchar, uchar);
1113static ushort AscInitLram(ASC_DVC_VAR *);
1114static ushort AscInitQLinkVar(ASC_DVC_VAR *);
1115static int AscSetLibErrorCode(ASC_DVC_VAR *, ushort);
1116static int AscIsrChipHalted(ASC_DVC_VAR *);
1117static uchar _AscCopyLramScsiDoneQ(PortAddr, ushort,
1118 ASC_QDONE_INFO *, ASC_DCNT);
1119static int AscIsrQDone(ASC_DVC_VAR *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001121static ushort AscGetEisaChipCfg(PortAddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001123static uchar AscGetChipScsiCtrl(PortAddr);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001124static uchar AscGetChipVersion(PortAddr, ushort);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001125static ASC_DCNT AscLoadMicroCode(PortAddr, ushort, uchar *, ushort);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001126static void AscToggleIRQAct(PortAddr);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001127static inline ulong DvcEnterCritical(void);
1128static inline void DvcLeaveCritical(ulong);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001129static void DvcSleepMilliSecond(ASC_DCNT);
1130static void DvcDelayNanoSecond(ASC_DVC_VAR *, ASC_DCNT);
1131static void DvcPutScsiQ(PortAddr, ushort, uchar *, int);
1132static void DvcGetQinfo(PortAddr, ushort, uchar *, int);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001133static ushort AscInitAsc1000Driver(ASC_DVC_VAR *);
Matthew Wilcox47d853c2007-07-26 11:41:33 -04001134static void AscAsyncFix(ASC_DVC_VAR *, struct scsi_device *);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001135static int AscExeScsiQueue(ASC_DVC_VAR *, ASC_SCSI_Q *);
1136static int AscISR(ASC_DVC_VAR *);
1137static uint AscGetNumOfFreeQueue(ASC_DVC_VAR *, uchar, uchar);
1138static int AscSgListToQueue(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001140static void AscEnableIsaDma(uchar);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001142static const char *advansys_info(struct Scsi_Host *shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143
1144/*
1145 * --- Adv Library Constants and Macros
1146 */
1147
1148#define ADV_LIB_VERSION_MAJOR 5
1149#define ADV_LIB_VERSION_MINOR 14
1150
1151/*
1152 * Define Adv Library required special types.
1153 */
1154
1155/*
1156 * Portable Data Types
1157 *
1158 * Any instance where a 32-bit long or pointer type is assumed
1159 * for precision or HW defined structures, the following define
1160 * types must be used. In Linux the char, short, and int types
1161 * are all consistent at 8, 16, and 32 bits respectively. Pointers
1162 * and long types are 64 bits on Alpha and UltraSPARC.
1163 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001164#define ADV_PADDR __u32 /* Physical address data type. */
1165#define ADV_VADDR __u32 /* Virtual address data type. */
1166#define ADV_DCNT __u32 /* Unsigned Data count type. */
1167#define ADV_SDCNT __s32 /* Signed Data count type. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168
1169/*
1170 * These macros are used to convert a virtual address to a
1171 * 32-bit value. This currently can be used on Linux Alpha
1172 * which uses 64-bit virtual address but a 32-bit bus address.
1173 * This is likely to break in the future, but doing this now
1174 * will give us time to change the HW and FW to handle 64-bit
1175 * addresses.
1176 */
1177#define ADV_VADDR_TO_U32 virt_to_bus
1178#define ADV_U32_TO_VADDR bus_to_virt
1179
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001180#define AdvPortAddr void __iomem * /* Virtual memory address size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181
1182/*
1183 * Define Adv Library required memory access macros.
1184 */
1185#define ADV_MEM_READB(addr) readb(addr)
1186#define ADV_MEM_READW(addr) readw(addr)
1187#define ADV_MEM_WRITEB(addr, byte) writeb(byte, addr)
1188#define ADV_MEM_WRITEW(addr, word) writew(word, addr)
1189#define ADV_MEM_WRITEDW(addr, dword) writel(dword, addr)
1190
1191#define ADV_CARRIER_COUNT (ASC_DEF_MAX_HOST_QNG + 15)
1192
1193/*
1194 * For wide boards a CDB length maximum of 16 bytes
1195 * is supported.
1196 */
1197#define ADV_MAX_CDB_LEN 16
1198
1199/*
1200 * Define total number of simultaneous maximum element scatter-gather
1201 * request blocks per wide adapter. ASC_DEF_MAX_HOST_QNG (253) is the
1202 * maximum number of outstanding commands per wide host adapter. Each
1203 * command uses one or more ADV_SG_BLOCK each with 15 scatter-gather
1204 * elements. Allow each command to have at least one ADV_SG_BLOCK structure.
1205 * This allows about 15 commands to have the maximum 17 ADV_SG_BLOCK
1206 * structures or 255 scatter-gather elements.
1207 *
1208 */
1209#define ADV_TOT_SG_BLOCK ASC_DEF_MAX_HOST_QNG
1210
1211/*
1212 * Define Adv Library required maximum number of scatter-gather
1213 * elements per request.
1214 */
1215#define ADV_MAX_SG_LIST 255
1216
1217/* Number of SG blocks needed. */
1218#define ADV_NUM_SG_BLOCK \
1219 ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)
1220
1221/* Total contiguous memory needed for SG blocks. */
1222#define ADV_SG_TOTAL_MEM_SIZE \
1223 (sizeof(ADV_SG_BLOCK) * ADV_NUM_SG_BLOCK)
1224
1225#define ADV_PAGE_SIZE PAGE_SIZE
1226
1227#define ADV_NUM_PAGE_CROSSING \
1228 ((ADV_SG_TOTAL_MEM_SIZE + (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
1229
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230#define ADV_EEP_DVC_CFG_BEGIN (0x00)
1231#define ADV_EEP_DVC_CFG_END (0x15)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001232#define ADV_EEP_DVC_CTL_BEGIN (0x16) /* location of OEM name */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233#define ADV_EEP_MAX_WORD_ADDR (0x1E)
1234
1235#define ADV_EEP_DELAY_MS 100
1236
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001237#define ADV_EEPROM_BIG_ENDIAN 0x8000 /* EEPROM Bit 15 */
1238#define ADV_EEPROM_BIOS_ENABLE 0x4000 /* EEPROM Bit 14 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239/*
1240 * For the ASC3550 Bit 13 is Termination Polarity control bit.
1241 * For later ICs Bit 13 controls whether the CIS (Card Information
1242 * Service Section) is loaded from EEPROM.
1243 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001244#define ADV_EEPROM_TERM_POL 0x2000 /* EEPROM Bit 13 */
1245#define ADV_EEPROM_CIS_LD 0x2000 /* EEPROM Bit 13 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246/*
1247 * ASC38C1600 Bit 11
1248 *
1249 * If EEPROM Bit 11 is 0 for Function 0, then Function 0 will specify
1250 * INT A in the PCI Configuration Space Int Pin field. If it is 1, then
1251 * Function 0 will specify INT B.
1252 *
1253 * If EEPROM Bit 11 is 0 for Function 1, then Function 1 will specify
1254 * INT B in the PCI Configuration Space Int Pin field. If it is 1, then
1255 * Function 1 will specify INT A.
1256 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001257#define ADV_EEPROM_INTAB 0x0800 /* EEPROM Bit 11 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001259typedef struct adveep_3550_config {
1260 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001262 ushort cfg_lsw; /* 00 power up initialization */
1263 /* bit 13 set - Term Polarity Control */
1264 /* bit 14 set - BIOS Enable */
1265 /* bit 15 set - Big Endian Mode */
1266 ushort cfg_msw; /* 01 unused */
1267 ushort disc_enable; /* 02 disconnect enable */
1268 ushort wdtr_able; /* 03 Wide DTR able */
1269 ushort sdtr_able; /* 04 Synchronous DTR able */
1270 ushort start_motor; /* 05 send start up motor */
1271 ushort tagqng_able; /* 06 tag queuing able */
1272 ushort bios_scan; /* 07 BIOS device control */
1273 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001275 uchar adapter_scsi_id; /* 09 Host Adapter ID */
1276 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001278 uchar scsi_reset_delay; /* 10 reset delay */
1279 uchar bios_id_lun; /* first boot device scsi id & lun */
1280 /* high nibble is lun */
1281 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001283 uchar termination; /* 11 0 - automatic */
1284 /* 1 - low off / high off */
1285 /* 2 - low off / high on */
1286 /* 3 - low on / high on */
1287 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001289 uchar reserved1; /* reserved byte (not used) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001291 ushort bios_ctrl; /* 12 BIOS control bits */
1292 /* bit 0 BIOS don't act as initiator. */
1293 /* bit 1 BIOS > 1 GB support */
1294 /* bit 2 BIOS > 2 Disk Support */
1295 /* bit 3 BIOS don't support removables */
1296 /* bit 4 BIOS support bootable CD */
1297 /* bit 5 BIOS scan enabled */
1298 /* bit 6 BIOS support multiple LUNs */
1299 /* bit 7 BIOS display of message */
1300 /* bit 8 SCAM disabled */
1301 /* bit 9 Reset SCSI bus during init. */
1302 /* bit 10 */
1303 /* bit 11 No verbose initialization. */
1304 /* bit 12 SCSI parity enabled */
1305 /* bit 13 */
1306 /* bit 14 */
1307 /* bit 15 */
1308 ushort ultra_able; /* 13 ULTRA speed able */
1309 ushort reserved2; /* 14 reserved */
1310 uchar max_host_qng; /* 15 maximum host queuing */
1311 uchar max_dvc_qng; /* maximum per device queuing */
1312 ushort dvc_cntl; /* 16 control bit for driver */
1313 ushort bug_fix; /* 17 control bit for bug fix */
1314 ushort serial_number_word1; /* 18 Board serial number word 1 */
1315 ushort serial_number_word2; /* 19 Board serial number word 2 */
1316 ushort serial_number_word3; /* 20 Board serial number word 3 */
1317 ushort check_sum; /* 21 EEP check sum */
1318 uchar oem_name[16]; /* 22 OEM name */
1319 ushort dvc_err_code; /* 30 last device driver error code */
1320 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
1321 ushort adv_err_addr; /* 32 last uc error address */
1322 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
1323 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
1324 ushort saved_adv_err_addr; /* 35 saved last uc error address */
1325 ushort num_of_err; /* 36 number of error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326} ADVEEP_3550_CONFIG;
1327
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001328typedef struct adveep_38C0800_config {
1329 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001331 ushort cfg_lsw; /* 00 power up initialization */
1332 /* bit 13 set - Load CIS */
1333 /* bit 14 set - BIOS Enable */
1334 /* bit 15 set - Big Endian Mode */
1335 ushort cfg_msw; /* 01 unused */
1336 ushort disc_enable; /* 02 disconnect enable */
1337 ushort wdtr_able; /* 03 Wide DTR able */
1338 ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
1339 ushort start_motor; /* 05 send start up motor */
1340 ushort tagqng_able; /* 06 tag queuing able */
1341 ushort bios_scan; /* 07 BIOS device control */
1342 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001344 uchar adapter_scsi_id; /* 09 Host Adapter ID */
1345 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001347 uchar scsi_reset_delay; /* 10 reset delay */
1348 uchar bios_id_lun; /* first boot device scsi id & lun */
1349 /* high nibble is lun */
1350 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001352 uchar termination_se; /* 11 0 - automatic */
1353 /* 1 - low off / high off */
1354 /* 2 - low off / high on */
1355 /* 3 - low on / high on */
1356 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001358 uchar termination_lvd; /* 11 0 - automatic */
1359 /* 1 - low off / high off */
1360 /* 2 - low off / high on */
1361 /* 3 - low on / high on */
1362 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001364 ushort bios_ctrl; /* 12 BIOS control bits */
1365 /* bit 0 BIOS don't act as initiator. */
1366 /* bit 1 BIOS > 1 GB support */
1367 /* bit 2 BIOS > 2 Disk Support */
1368 /* bit 3 BIOS don't support removables */
1369 /* bit 4 BIOS support bootable CD */
1370 /* bit 5 BIOS scan enabled */
1371 /* bit 6 BIOS support multiple LUNs */
1372 /* bit 7 BIOS display of message */
1373 /* bit 8 SCAM disabled */
1374 /* bit 9 Reset SCSI bus during init. */
1375 /* bit 10 */
1376 /* bit 11 No verbose initialization. */
1377 /* bit 12 SCSI parity enabled */
1378 /* bit 13 */
1379 /* bit 14 */
1380 /* bit 15 */
1381 ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
1382 ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
1383 uchar max_host_qng; /* 15 maximum host queueing */
1384 uchar max_dvc_qng; /* maximum per device queuing */
1385 ushort dvc_cntl; /* 16 control bit for driver */
1386 ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
1387 ushort serial_number_word1; /* 18 Board serial number word 1 */
1388 ushort serial_number_word2; /* 19 Board serial number word 2 */
1389 ushort serial_number_word3; /* 20 Board serial number word 3 */
1390 ushort check_sum; /* 21 EEP check sum */
1391 uchar oem_name[16]; /* 22 OEM name */
1392 ushort dvc_err_code; /* 30 last device driver error code */
1393 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
1394 ushort adv_err_addr; /* 32 last uc error address */
1395 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
1396 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
1397 ushort saved_adv_err_addr; /* 35 saved last uc error address */
1398 ushort reserved36; /* 36 reserved */
1399 ushort reserved37; /* 37 reserved */
1400 ushort reserved38; /* 38 reserved */
1401 ushort reserved39; /* 39 reserved */
1402 ushort reserved40; /* 40 reserved */
1403 ushort reserved41; /* 41 reserved */
1404 ushort reserved42; /* 42 reserved */
1405 ushort reserved43; /* 43 reserved */
1406 ushort reserved44; /* 44 reserved */
1407 ushort reserved45; /* 45 reserved */
1408 ushort reserved46; /* 46 reserved */
1409 ushort reserved47; /* 47 reserved */
1410 ushort reserved48; /* 48 reserved */
1411 ushort reserved49; /* 49 reserved */
1412 ushort reserved50; /* 50 reserved */
1413 ushort reserved51; /* 51 reserved */
1414 ushort reserved52; /* 52 reserved */
1415 ushort reserved53; /* 53 reserved */
1416 ushort reserved54; /* 54 reserved */
1417 ushort reserved55; /* 55 reserved */
1418 ushort cisptr_lsw; /* 56 CIS PTR LSW */
1419 ushort cisprt_msw; /* 57 CIS PTR MSW */
1420 ushort subsysvid; /* 58 SubSystem Vendor ID */
1421 ushort subsysid; /* 59 SubSystem ID */
1422 ushort reserved60; /* 60 reserved */
1423 ushort reserved61; /* 61 reserved */
1424 ushort reserved62; /* 62 reserved */
1425 ushort reserved63; /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426} ADVEEP_38C0800_CONFIG;
1427
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001428typedef struct adveep_38C1600_config {
1429 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001431 ushort cfg_lsw; /* 00 power up initialization */
1432 /* bit 11 set - Func. 0 INTB, Func. 1 INTA */
1433 /* clear - Func. 0 INTA, Func. 1 INTB */
1434 /* bit 13 set - Load CIS */
1435 /* bit 14 set - BIOS Enable */
1436 /* bit 15 set - Big Endian Mode */
1437 ushort cfg_msw; /* 01 unused */
1438 ushort disc_enable; /* 02 disconnect enable */
1439 ushort wdtr_able; /* 03 Wide DTR able */
1440 ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
1441 ushort start_motor; /* 05 send start up motor */
1442 ushort tagqng_able; /* 06 tag queuing able */
1443 ushort bios_scan; /* 07 BIOS device control */
1444 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001446 uchar adapter_scsi_id; /* 09 Host Adapter ID */
1447 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001449 uchar scsi_reset_delay; /* 10 reset delay */
1450 uchar bios_id_lun; /* first boot device scsi id & lun */
1451 /* high nibble is lun */
1452 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001454 uchar termination_se; /* 11 0 - automatic */
1455 /* 1 - low off / high off */
1456 /* 2 - low off / high on */
1457 /* 3 - low on / high on */
1458 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001460 uchar termination_lvd; /* 11 0 - automatic */
1461 /* 1 - low off / high off */
1462 /* 2 - low off / high on */
1463 /* 3 - low on / high on */
1464 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001466 ushort bios_ctrl; /* 12 BIOS control bits */
1467 /* bit 0 BIOS don't act as initiator. */
1468 /* bit 1 BIOS > 1 GB support */
1469 /* bit 2 BIOS > 2 Disk Support */
1470 /* bit 3 BIOS don't support removables */
1471 /* bit 4 BIOS support bootable CD */
1472 /* bit 5 BIOS scan enabled */
1473 /* bit 6 BIOS support multiple LUNs */
1474 /* bit 7 BIOS display of message */
1475 /* bit 8 SCAM disabled */
1476 /* bit 9 Reset SCSI bus during init. */
1477 /* bit 10 Basic Integrity Checking disabled */
1478 /* bit 11 No verbose initialization. */
1479 /* bit 12 SCSI parity enabled */
1480 /* bit 13 AIPP (Asyn. Info. Ph. Prot.) dis. */
1481 /* bit 14 */
1482 /* bit 15 */
1483 ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
1484 ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
1485 uchar max_host_qng; /* 15 maximum host queueing */
1486 uchar max_dvc_qng; /* maximum per device queuing */
1487 ushort dvc_cntl; /* 16 control bit for driver */
1488 ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
1489 ushort serial_number_word1; /* 18 Board serial number word 1 */
1490 ushort serial_number_word2; /* 19 Board serial number word 2 */
1491 ushort serial_number_word3; /* 20 Board serial number word 3 */
1492 ushort check_sum; /* 21 EEP check sum */
1493 uchar oem_name[16]; /* 22 OEM name */
1494 ushort dvc_err_code; /* 30 last device driver error code */
1495 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
1496 ushort adv_err_addr; /* 32 last uc error address */
1497 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
1498 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
1499 ushort saved_adv_err_addr; /* 35 saved last uc error address */
1500 ushort reserved36; /* 36 reserved */
1501 ushort reserved37; /* 37 reserved */
1502 ushort reserved38; /* 38 reserved */
1503 ushort reserved39; /* 39 reserved */
1504 ushort reserved40; /* 40 reserved */
1505 ushort reserved41; /* 41 reserved */
1506 ushort reserved42; /* 42 reserved */
1507 ushort reserved43; /* 43 reserved */
1508 ushort reserved44; /* 44 reserved */
1509 ushort reserved45; /* 45 reserved */
1510 ushort reserved46; /* 46 reserved */
1511 ushort reserved47; /* 47 reserved */
1512 ushort reserved48; /* 48 reserved */
1513 ushort reserved49; /* 49 reserved */
1514 ushort reserved50; /* 50 reserved */
1515 ushort reserved51; /* 51 reserved */
1516 ushort reserved52; /* 52 reserved */
1517 ushort reserved53; /* 53 reserved */
1518 ushort reserved54; /* 54 reserved */
1519 ushort reserved55; /* 55 reserved */
1520 ushort cisptr_lsw; /* 56 CIS PTR LSW */
1521 ushort cisprt_msw; /* 57 CIS PTR MSW */
1522 ushort subsysvid; /* 58 SubSystem Vendor ID */
1523 ushort subsysid; /* 59 SubSystem ID */
1524 ushort reserved60; /* 60 reserved */
1525 ushort reserved61; /* 61 reserved */
1526 ushort reserved62; /* 62 reserved */
1527 ushort reserved63; /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528} ADVEEP_38C1600_CONFIG;
1529
1530/*
1531 * EEPROM Commands
1532 */
1533#define ASC_EEP_CMD_DONE 0x0200
1534#define ASC_EEP_CMD_DONE_ERR 0x0001
1535
1536/* cfg_word */
1537#define EEP_CFG_WORD_BIG_ENDIAN 0x8000
1538
1539/* bios_ctrl */
1540#define BIOS_CTRL_BIOS 0x0001
1541#define BIOS_CTRL_EXTENDED_XLAT 0x0002
1542#define BIOS_CTRL_GT_2_DISK 0x0004
1543#define BIOS_CTRL_BIOS_REMOVABLE 0x0008
1544#define BIOS_CTRL_BOOTABLE_CD 0x0010
1545#define BIOS_CTRL_MULTIPLE_LUN 0x0040
1546#define BIOS_CTRL_DISPLAY_MSG 0x0080
1547#define BIOS_CTRL_NO_SCAM 0x0100
1548#define BIOS_CTRL_RESET_SCSI_BUS 0x0200
1549#define BIOS_CTRL_INIT_VERBOSE 0x0800
1550#define BIOS_CTRL_SCSI_PARITY 0x1000
1551#define BIOS_CTRL_AIPP_DIS 0x2000
1552
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001553#define ADV_3550_MEMSIZE 0x2000 /* 8 KB Internal Memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001555#define ADV_38C0800_MEMSIZE 0x4000 /* 16 KB Internal Memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556
1557/*
1558 * XXX - Since ASC38C1600 Rev.3 has a local RAM failure issue, there is
1559 * a special 16K Adv Library and Microcode version. After the issue is
1560 * resolved, should restore 32K support.
1561 *
1562 * #define ADV_38C1600_MEMSIZE 0x8000L * 32 KB Internal Memory *
1563 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001564#define ADV_38C1600_MEMSIZE 0x4000 /* 16 KB Internal Memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565
1566/*
1567 * Byte I/O register address from base of 'iop_base'.
1568 */
1569#define IOPB_INTR_STATUS_REG 0x00
1570#define IOPB_CHIP_ID_1 0x01
1571#define IOPB_INTR_ENABLES 0x02
1572#define IOPB_CHIP_TYPE_REV 0x03
1573#define IOPB_RES_ADDR_4 0x04
1574#define IOPB_RES_ADDR_5 0x05
1575#define IOPB_RAM_DATA 0x06
1576#define IOPB_RES_ADDR_7 0x07
1577#define IOPB_FLAG_REG 0x08
1578#define IOPB_RES_ADDR_9 0x09
1579#define IOPB_RISC_CSR 0x0A
1580#define IOPB_RES_ADDR_B 0x0B
1581#define IOPB_RES_ADDR_C 0x0C
1582#define IOPB_RES_ADDR_D 0x0D
1583#define IOPB_SOFT_OVER_WR 0x0E
1584#define IOPB_RES_ADDR_F 0x0F
1585#define IOPB_MEM_CFG 0x10
1586#define IOPB_RES_ADDR_11 0x11
1587#define IOPB_GPIO_DATA 0x12
1588#define IOPB_RES_ADDR_13 0x13
1589#define IOPB_FLASH_PAGE 0x14
1590#define IOPB_RES_ADDR_15 0x15
1591#define IOPB_GPIO_CNTL 0x16
1592#define IOPB_RES_ADDR_17 0x17
1593#define IOPB_FLASH_DATA 0x18
1594#define IOPB_RES_ADDR_19 0x19
1595#define IOPB_RES_ADDR_1A 0x1A
1596#define IOPB_RES_ADDR_1B 0x1B
1597#define IOPB_RES_ADDR_1C 0x1C
1598#define IOPB_RES_ADDR_1D 0x1D
1599#define IOPB_RES_ADDR_1E 0x1E
1600#define IOPB_RES_ADDR_1F 0x1F
1601#define IOPB_DMA_CFG0 0x20
1602#define IOPB_DMA_CFG1 0x21
1603#define IOPB_TICKLE 0x22
1604#define IOPB_DMA_REG_WR 0x23
1605#define IOPB_SDMA_STATUS 0x24
1606#define IOPB_SCSI_BYTE_CNT 0x25
1607#define IOPB_HOST_BYTE_CNT 0x26
1608#define IOPB_BYTE_LEFT_TO_XFER 0x27
1609#define IOPB_BYTE_TO_XFER_0 0x28
1610#define IOPB_BYTE_TO_XFER_1 0x29
1611#define IOPB_BYTE_TO_XFER_2 0x2A
1612#define IOPB_BYTE_TO_XFER_3 0x2B
1613#define IOPB_ACC_GRP 0x2C
1614#define IOPB_RES_ADDR_2D 0x2D
1615#define IOPB_DEV_ID 0x2E
1616#define IOPB_RES_ADDR_2F 0x2F
1617#define IOPB_SCSI_DATA 0x30
1618#define IOPB_RES_ADDR_31 0x31
1619#define IOPB_RES_ADDR_32 0x32
1620#define IOPB_SCSI_DATA_HSHK 0x33
1621#define IOPB_SCSI_CTRL 0x34
1622#define IOPB_RES_ADDR_35 0x35
1623#define IOPB_RES_ADDR_36 0x36
1624#define IOPB_RES_ADDR_37 0x37
1625#define IOPB_RAM_BIST 0x38
1626#define IOPB_PLL_TEST 0x39
1627#define IOPB_PCI_INT_CFG 0x3A
1628#define IOPB_RES_ADDR_3B 0x3B
1629#define IOPB_RFIFO_CNT 0x3C
1630#define IOPB_RES_ADDR_3D 0x3D
1631#define IOPB_RES_ADDR_3E 0x3E
1632#define IOPB_RES_ADDR_3F 0x3F
1633
1634/*
1635 * Word I/O register address from base of 'iop_base'.
1636 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001637#define IOPW_CHIP_ID_0 0x00 /* CID0 */
1638#define IOPW_CTRL_REG 0x02 /* CC */
1639#define IOPW_RAM_ADDR 0x04 /* LA */
1640#define IOPW_RAM_DATA 0x06 /* LD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641#define IOPW_RES_ADDR_08 0x08
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001642#define IOPW_RISC_CSR 0x0A /* CSR */
1643#define IOPW_SCSI_CFG0 0x0C /* CFG0 */
1644#define IOPW_SCSI_CFG1 0x0E /* CFG1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645#define IOPW_RES_ADDR_10 0x10
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001646#define IOPW_SEL_MASK 0x12 /* SM */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647#define IOPW_RES_ADDR_14 0x14
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001648#define IOPW_FLASH_ADDR 0x16 /* FA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649#define IOPW_RES_ADDR_18 0x18
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001650#define IOPW_EE_CMD 0x1A /* EC */
1651#define IOPW_EE_DATA 0x1C /* ED */
1652#define IOPW_SFIFO_CNT 0x1E /* SFC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653#define IOPW_RES_ADDR_20 0x20
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001654#define IOPW_Q_BASE 0x22 /* QB */
1655#define IOPW_QP 0x24 /* QP */
1656#define IOPW_IX 0x26 /* IX */
1657#define IOPW_SP 0x28 /* SP */
1658#define IOPW_PC 0x2A /* PC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659#define IOPW_RES_ADDR_2C 0x2C
1660#define IOPW_RES_ADDR_2E 0x2E
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001661#define IOPW_SCSI_DATA 0x30 /* SD */
1662#define IOPW_SCSI_DATA_HSHK 0x32 /* SDH */
1663#define IOPW_SCSI_CTRL 0x34 /* SC */
1664#define IOPW_HSHK_CFG 0x36 /* HCFG */
1665#define IOPW_SXFR_STATUS 0x36 /* SXS */
1666#define IOPW_SXFR_CNTL 0x38 /* SXL */
1667#define IOPW_SXFR_CNTH 0x3A /* SXH */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668#define IOPW_RES_ADDR_3C 0x3C
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001669#define IOPW_RFIFO_DATA 0x3E /* RFD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670
1671/*
1672 * Doubleword I/O register address from base of 'iop_base'.
1673 */
1674#define IOPDW_RES_ADDR_0 0x00
1675#define IOPDW_RAM_DATA 0x04
1676#define IOPDW_RES_ADDR_8 0x08
1677#define IOPDW_RES_ADDR_C 0x0C
1678#define IOPDW_RES_ADDR_10 0x10
1679#define IOPDW_COMMA 0x14
1680#define IOPDW_COMMB 0x18
1681#define IOPDW_RES_ADDR_1C 0x1C
1682#define IOPDW_SDMA_ADDR0 0x20
1683#define IOPDW_SDMA_ADDR1 0x24
1684#define IOPDW_SDMA_COUNT 0x28
1685#define IOPDW_SDMA_ERROR 0x2C
1686#define IOPDW_RDMA_ADDR0 0x30
1687#define IOPDW_RDMA_ADDR1 0x34
1688#define IOPDW_RDMA_COUNT 0x38
1689#define IOPDW_RDMA_ERROR 0x3C
1690
1691#define ADV_CHIP_ID_BYTE 0x25
1692#define ADV_CHIP_ID_WORD 0x04C1
1693
1694#define ADV_SC_SCSI_BUS_RESET 0x2000
1695
1696#define ADV_INTR_ENABLE_HOST_INTR 0x01
1697#define ADV_INTR_ENABLE_SEL_INTR 0x02
1698#define ADV_INTR_ENABLE_DPR_INTR 0x04
1699#define ADV_INTR_ENABLE_RTA_INTR 0x08
1700#define ADV_INTR_ENABLE_RMA_INTR 0x10
1701#define ADV_INTR_ENABLE_RST_INTR 0x20
1702#define ADV_INTR_ENABLE_DPE_INTR 0x40
1703#define ADV_INTR_ENABLE_GLOBAL_INTR 0x80
1704
1705#define ADV_INTR_STATUS_INTRA 0x01
1706#define ADV_INTR_STATUS_INTRB 0x02
1707#define ADV_INTR_STATUS_INTRC 0x04
1708
1709#define ADV_RISC_CSR_STOP (0x0000)
1710#define ADV_RISC_TEST_COND (0x2000)
1711#define ADV_RISC_CSR_RUN (0x4000)
1712#define ADV_RISC_CSR_SINGLE_STEP (0x8000)
1713
1714#define ADV_CTRL_REG_HOST_INTR 0x0100
1715#define ADV_CTRL_REG_SEL_INTR 0x0200
1716#define ADV_CTRL_REG_DPR_INTR 0x0400
1717#define ADV_CTRL_REG_RTA_INTR 0x0800
1718#define ADV_CTRL_REG_RMA_INTR 0x1000
1719#define ADV_CTRL_REG_RES_BIT14 0x2000
1720#define ADV_CTRL_REG_DPE_INTR 0x4000
1721#define ADV_CTRL_REG_POWER_DONE 0x8000
1722#define ADV_CTRL_REG_ANY_INTR 0xFF00
1723
1724#define ADV_CTRL_REG_CMD_RESET 0x00C6
1725#define ADV_CTRL_REG_CMD_WR_IO_REG 0x00C5
1726#define ADV_CTRL_REG_CMD_RD_IO_REG 0x00C4
1727#define ADV_CTRL_REG_CMD_WR_PCI_CFG_SPACE 0x00C3
1728#define ADV_CTRL_REG_CMD_RD_PCI_CFG_SPACE 0x00C2
1729
1730#define ADV_TICKLE_NOP 0x00
1731#define ADV_TICKLE_A 0x01
1732#define ADV_TICKLE_B 0x02
1733#define ADV_TICKLE_C 0x03
1734
1735#define ADV_SCSI_CTRL_RSTOUT 0x2000
1736
1737#define AdvIsIntPending(port) \
1738 (AdvReadWordRegister(port, IOPW_CTRL_REG) & ADV_CTRL_REG_HOST_INTR)
1739
1740/*
1741 * SCSI_CFG0 Register bit definitions
1742 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001743#define TIMER_MODEAB 0xC000 /* Watchdog, Second, and Select. Timer Ctrl. */
1744#define PARITY_EN 0x2000 /* Enable SCSI Parity Error detection */
1745#define EVEN_PARITY 0x1000 /* Select Even Parity */
1746#define WD_LONG 0x0800 /* Watchdog Interval, 1: 57 min, 0: 13 sec */
1747#define QUEUE_128 0x0400 /* Queue Size, 1: 128 byte, 0: 64 byte */
1748#define PRIM_MODE 0x0100 /* Primitive SCSI mode */
1749#define SCAM_EN 0x0080 /* Enable SCAM selection */
1750#define SEL_TMO_LONG 0x0040 /* Sel/Resel Timeout, 1: 400 ms, 0: 1.6 ms */
1751#define CFRM_ID 0x0020 /* SCAM id sel. confirm., 1: fast, 0: 6.4 ms */
1752#define OUR_ID_EN 0x0010 /* Enable OUR_ID bits */
1753#define OUR_ID 0x000F /* SCSI ID */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754
1755/*
1756 * SCSI_CFG1 Register bit definitions
1757 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001758#define BIG_ENDIAN 0x8000 /* Enable Big Endian Mode MIO:15, EEP:15 */
1759#define TERM_POL 0x2000 /* Terminator Polarity Ctrl. MIO:13, EEP:13 */
1760#define SLEW_RATE 0x1000 /* SCSI output buffer slew rate */
1761#define FILTER_SEL 0x0C00 /* Filter Period Selection */
1762#define FLTR_DISABLE 0x0000 /* Input Filtering Disabled */
1763#define FLTR_11_TO_20NS 0x0800 /* Input Filtering 11ns to 20ns */
1764#define FLTR_21_TO_39NS 0x0C00 /* Input Filtering 21ns to 39ns */
1765#define ACTIVE_DBL 0x0200 /* Disable Active Negation */
1766#define DIFF_MODE 0x0100 /* SCSI differential Mode (Read-Only) */
1767#define DIFF_SENSE 0x0080 /* 1: No SE cables, 0: SE cable (Read-Only) */
1768#define TERM_CTL_SEL 0x0040 /* Enable TERM_CTL_H and TERM_CTL_L */
1769#define TERM_CTL 0x0030 /* External SCSI Termination Bits */
1770#define TERM_CTL_H 0x0020 /* Enable External SCSI Upper Termination */
1771#define TERM_CTL_L 0x0010 /* Enable External SCSI Lower Termination */
1772#define CABLE_DETECT 0x000F /* External SCSI Cable Connection Status */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773
1774/*
1775 * Addendum for ASC-38C0800 Chip
1776 *
1777 * The ASC-38C1600 Chip uses the same definitions except that the
1778 * bus mode override bits [12:10] have been moved to byte register
1779 * offset 0xE (IOPB_SOFT_OVER_WR) bits [12:10]. The [12:10] bits in
1780 * SCSI_CFG1 are read-only and always available. Bit 14 (DIS_TERM_DRV)
1781 * is not needed. The [12:10] bits in IOPB_SOFT_OVER_WR are write-only.
1782 * Also each ASC-38C1600 function or channel uses only cable bits [5:4]
1783 * and [1:0]. Bits [14], [7:6], [3:2] are unused.
1784 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001785#define DIS_TERM_DRV 0x4000 /* 1: Read c_det[3:0], 0: cannot read */
1786#define HVD_LVD_SE 0x1C00 /* Device Detect Bits */
1787#define HVD 0x1000 /* HVD Device Detect */
1788#define LVD 0x0800 /* LVD Device Detect */
1789#define SE 0x0400 /* SE Device Detect */
1790#define TERM_LVD 0x00C0 /* LVD Termination Bits */
1791#define TERM_LVD_HI 0x0080 /* Enable LVD Upper Termination */
1792#define TERM_LVD_LO 0x0040 /* Enable LVD Lower Termination */
1793#define TERM_SE 0x0030 /* SE Termination Bits */
1794#define TERM_SE_HI 0x0020 /* Enable SE Upper Termination */
1795#define TERM_SE_LO 0x0010 /* Enable SE Lower Termination */
1796#define C_DET_LVD 0x000C /* LVD Cable Detect Bits */
1797#define C_DET3 0x0008 /* Cable Detect for LVD External Wide */
1798#define C_DET2 0x0004 /* Cable Detect for LVD Internal Wide */
1799#define C_DET_SE 0x0003 /* SE Cable Detect Bits */
1800#define C_DET1 0x0002 /* Cable Detect for SE Internal Wide */
1801#define C_DET0 0x0001 /* Cable Detect for SE Internal Narrow */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802
1803#define CABLE_ILLEGAL_A 0x7
1804 /* x 0 0 0 | on on | Illegal (all 3 connectors are used) */
1805
1806#define CABLE_ILLEGAL_B 0xB
1807 /* 0 x 0 0 | on on | Illegal (all 3 connectors are used) */
1808
1809/*
1810 * MEM_CFG Register bit definitions
1811 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001812#define BIOS_EN 0x40 /* BIOS Enable MIO:14,EEP:14 */
1813#define FAST_EE_CLK 0x20 /* Diagnostic Bit */
1814#define RAM_SZ 0x1C /* Specify size of RAM to RISC */
1815#define RAM_SZ_2KB 0x00 /* 2 KB */
1816#define RAM_SZ_4KB 0x04 /* 4 KB */
1817#define RAM_SZ_8KB 0x08 /* 8 KB */
1818#define RAM_SZ_16KB 0x0C /* 16 KB */
1819#define RAM_SZ_32KB 0x10 /* 32 KB */
1820#define RAM_SZ_64KB 0x14 /* 64 KB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821
1822/*
1823 * DMA_CFG0 Register bit definitions
1824 *
1825 * This register is only accessible to the host.
1826 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001827#define BC_THRESH_ENB 0x80 /* PCI DMA Start Conditions */
1828#define FIFO_THRESH 0x70 /* PCI DMA FIFO Threshold */
1829#define FIFO_THRESH_16B 0x00 /* 16 bytes */
1830#define FIFO_THRESH_32B 0x20 /* 32 bytes */
1831#define FIFO_THRESH_48B 0x30 /* 48 bytes */
1832#define FIFO_THRESH_64B 0x40 /* 64 bytes */
1833#define FIFO_THRESH_80B 0x50 /* 80 bytes (default) */
1834#define FIFO_THRESH_96B 0x60 /* 96 bytes */
1835#define FIFO_THRESH_112B 0x70 /* 112 bytes */
1836#define START_CTL 0x0C /* DMA start conditions */
1837#define START_CTL_TH 0x00 /* Wait threshold level (default) */
1838#define START_CTL_ID 0x04 /* Wait SDMA/SBUS idle */
1839#define START_CTL_THID 0x08 /* Wait threshold and SDMA/SBUS idle */
1840#define START_CTL_EMFU 0x0C /* Wait SDMA FIFO empty/full */
1841#define READ_CMD 0x03 /* Memory Read Method */
1842#define READ_CMD_MR 0x00 /* Memory Read */
1843#define READ_CMD_MRL 0x02 /* Memory Read Long */
1844#define READ_CMD_MRM 0x03 /* Memory Read Multiple (default) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845
1846/*
1847 * ASC-38C0800 RAM BIST Register bit definitions
1848 */
1849#define RAM_TEST_MODE 0x80
1850#define PRE_TEST_MODE 0x40
1851#define NORMAL_MODE 0x00
1852#define RAM_TEST_DONE 0x10
1853#define RAM_TEST_STATUS 0x0F
1854#define RAM_TEST_HOST_ERROR 0x08
1855#define RAM_TEST_INTRAM_ERROR 0x04
1856#define RAM_TEST_RISC_ERROR 0x02
1857#define RAM_TEST_SCSI_ERROR 0x01
1858#define RAM_TEST_SUCCESS 0x00
1859#define PRE_TEST_VALUE 0x05
1860#define NORMAL_VALUE 0x00
1861
1862/*
1863 * ASC38C1600 Definitions
1864 *
1865 * IOPB_PCI_INT_CFG Bit Field Definitions
1866 */
1867
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001868#define INTAB_LD 0x80 /* Value loaded from EEPROM Bit 11. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869
1870/*
1871 * Bit 1 can be set to change the interrupt for the Function to operate in
1872 * Totem Pole mode. By default Bit 1 is 0 and the interrupt operates in
1873 * Open Drain mode. Both functions of the ASC38C1600 must be set to the same
1874 * mode, otherwise the operating mode is undefined.
1875 */
1876#define TOTEMPOLE 0x02
1877
1878/*
1879 * Bit 0 can be used to change the Int Pin for the Function. The value is
1880 * 0 by default for both Functions with Function 0 using INT A and Function
1881 * B using INT B. For Function 0 if set, INT B is used. For Function 1 if set,
1882 * INT A is used.
1883 *
1884 * EEPROM Word 0 Bit 11 for each Function may change the initial Int Pin
1885 * value specified in the PCI Configuration Space.
1886 */
1887#define INTAB 0x01
1888
1889/* a_advlib.h */
1890
1891/*
1892 * Adv Library Status Definitions
1893 */
1894#define ADV_TRUE 1
1895#define ADV_FALSE 0
1896#define ADV_NOERROR 1
1897#define ADV_SUCCESS 1
1898#define ADV_BUSY 0
1899#define ADV_ERROR (-1)
1900
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901/*
1902 * ADV_DVC_VAR 'warn_code' values
1903 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001904#define ASC_WARN_BUSRESET_ERROR 0x0001 /* SCSI Bus Reset error */
1905#define ASC_WARN_EEPROM_CHKSUM 0x0002 /* EEP check sum error */
1906#define ASC_WARN_EEPROM_TERMINATION 0x0004 /* EEP termination bad field */
1907#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080 /* PCI config space set error */
1908#define ASC_WARN_ERROR 0xFFFF /* ADV_ERROR return */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001910#define ADV_MAX_TID 15 /* max. target identifier */
1911#define ADV_MAX_LUN 7 /* max. logical unit number */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912
1913/*
1914 * Error code values are set in ADV_DVC_VAR 'err_code'.
1915 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001916#define ASC_IERR_WRITE_EEPROM 0x0001 /* write EEPROM error */
1917#define ASC_IERR_MCODE_CHKSUM 0x0002 /* micro code check sum error */
1918#define ASC_IERR_NO_CARRIER 0x0004 /* No more carrier memory. */
1919#define ASC_IERR_START_STOP_CHIP 0x0008 /* start/stop chip failed */
1920#define ASC_IERR_CHIP_VERSION 0x0040 /* wrong chip version */
1921#define ASC_IERR_SET_SCSI_ID 0x0080 /* set SCSI ID failed */
1922#define ASC_IERR_HVD_DEVICE 0x0100 /* HVD attached to LVD connector. */
1923#define ASC_IERR_BAD_SIGNATURE 0x0200 /* signature not found */
1924#define ASC_IERR_ILLEGAL_CONNECTION 0x0400 /* Illegal cable connection */
1925#define ASC_IERR_SINGLE_END_DEVICE 0x0800 /* Single-end used w/differential */
1926#define ASC_IERR_REVERSED_CABLE 0x1000 /* Narrow flat cable reversed */
1927#define ASC_IERR_BIST_PRE_TEST 0x2000 /* BIST pre-test error */
1928#define ASC_IERR_BIST_RAM_TEST 0x4000 /* BIST RAM test error */
1929#define ASC_IERR_BAD_CHIPTYPE 0x8000 /* Invalid 'chip_type' setting. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930
1931/*
1932 * Fixed locations of microcode operating variables.
1933 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001934#define ASC_MC_CODE_BEGIN_ADDR 0x0028 /* microcode start address */
1935#define ASC_MC_CODE_END_ADDR 0x002A /* microcode end address */
1936#define ASC_MC_CODE_CHK_SUM 0x002C /* microcode code checksum */
1937#define ASC_MC_VERSION_DATE 0x0038 /* microcode version */
1938#define ASC_MC_VERSION_NUM 0x003A /* microcode number */
1939#define ASC_MC_BIOSMEM 0x0040 /* BIOS RISC Memory Start */
1940#define ASC_MC_BIOSLEN 0x0050 /* BIOS RISC Memory Length */
1941#define ASC_MC_BIOS_SIGNATURE 0x0058 /* BIOS Signature 0x55AA */
1942#define ASC_MC_BIOS_VERSION 0x005A /* BIOS Version (2 bytes) */
1943#define ASC_MC_SDTR_SPEED1 0x0090 /* SDTR Speed for TID 0-3 */
1944#define ASC_MC_SDTR_SPEED2 0x0092 /* SDTR Speed for TID 4-7 */
1945#define ASC_MC_SDTR_SPEED3 0x0094 /* SDTR Speed for TID 8-11 */
1946#define ASC_MC_SDTR_SPEED4 0x0096 /* SDTR Speed for TID 12-15 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947#define ASC_MC_CHIP_TYPE 0x009A
1948#define ASC_MC_INTRB_CODE 0x009B
1949#define ASC_MC_WDTR_ABLE 0x009C
1950#define ASC_MC_SDTR_ABLE 0x009E
1951#define ASC_MC_TAGQNG_ABLE 0x00A0
1952#define ASC_MC_DISC_ENABLE 0x00A2
1953#define ASC_MC_IDLE_CMD_STATUS 0x00A4
1954#define ASC_MC_IDLE_CMD 0x00A6
1955#define ASC_MC_IDLE_CMD_PARAMETER 0x00A8
1956#define ASC_MC_DEFAULT_SCSI_CFG0 0x00AC
1957#define ASC_MC_DEFAULT_SCSI_CFG1 0x00AE
1958#define ASC_MC_DEFAULT_MEM_CFG 0x00B0
1959#define ASC_MC_DEFAULT_SEL_MASK 0x00B2
1960#define ASC_MC_SDTR_DONE 0x00B6
1961#define ASC_MC_NUMBER_OF_QUEUED_CMD 0x00C0
1962#define ASC_MC_NUMBER_OF_MAX_CMD 0x00D0
1963#define ASC_MC_DEVICE_HSHK_CFG_TABLE 0x0100
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001964#define ASC_MC_CONTROL_FLAG 0x0122 /* Microcode control flag. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965#define ASC_MC_WDTR_DONE 0x0124
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001966#define ASC_MC_CAM_MODE_MASK 0x015E /* CAM mode TID bitmask. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967#define ASC_MC_ICQ 0x0160
1968#define ASC_MC_IRQ 0x0164
1969#define ASC_MC_PPR_ABLE 0x017A
1970
1971/*
1972 * BIOS LRAM variable absolute offsets.
1973 */
1974#define BIOS_CODESEG 0x54
1975#define BIOS_CODELEN 0x56
1976#define BIOS_SIGNATURE 0x58
1977#define BIOS_VERSION 0x5A
1978
1979/*
1980 * Microcode Control Flags
1981 *
1982 * Flags set by the Adv Library in RISC variable 'control_flag' (0x122)
1983 * and handled by the microcode.
1984 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001985#define CONTROL_FLAG_IGNORE_PERR 0x0001 /* Ignore DMA Parity Errors */
1986#define CONTROL_FLAG_ENABLE_AIPP 0x0002 /* Enabled AIPP checking. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987
1988/*
1989 * ASC_MC_DEVICE_HSHK_CFG_TABLE microcode table or HSHK_CFG register format
1990 */
1991#define HSHK_CFG_WIDE_XFR 0x8000
1992#define HSHK_CFG_RATE 0x0F00
1993#define HSHK_CFG_OFFSET 0x001F
1994
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001995#define ASC_DEF_MAX_HOST_QNG 0xFD /* Max. number of host commands (253) */
1996#define ASC_DEF_MIN_HOST_QNG 0x10 /* Min. number of host commands (16) */
1997#define ASC_DEF_MAX_DVC_QNG 0x3F /* Max. number commands per device (63) */
1998#define ASC_DEF_MIN_DVC_QNG 0x04 /* Min. number commands per device (4) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002000#define ASC_QC_DATA_CHECK 0x01 /* Require ASC_QC_DATA_OUT set or clear. */
2001#define ASC_QC_DATA_OUT 0x02 /* Data out DMA transfer. */
2002#define ASC_QC_START_MOTOR 0x04 /* Send auto-start motor before request. */
2003#define ASC_QC_NO_OVERRUN 0x08 /* Don't report overrun. */
2004#define ASC_QC_FREEZE_TIDQ 0x10 /* Freeze TID queue after request. XXX TBD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002006#define ASC_QSC_NO_DISC 0x01 /* Don't allow disconnect for request. */
2007#define ASC_QSC_NO_TAGMSG 0x02 /* Don't allow tag queuing for request. */
2008#define ASC_QSC_NO_SYNC 0x04 /* Don't use Synch. transfer on request. */
2009#define ASC_QSC_NO_WIDE 0x08 /* Don't use Wide transfer on request. */
2010#define ASC_QSC_REDO_DTR 0x10 /* Renegotiate WDTR/SDTR before request. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011/*
2012 * Note: If a Tag Message is to be sent and neither ASC_QSC_HEAD_TAG or
2013 * ASC_QSC_ORDERED_TAG is set, then a Simple Tag Message (0x20) is used.
2014 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002015#define ASC_QSC_HEAD_TAG 0x40 /* Use Head Tag Message (0x21). */
2016#define ASC_QSC_ORDERED_TAG 0x80 /* Use Ordered Tag Message (0x22). */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017
2018/*
2019 * All fields here are accessed by the board microcode and need to be
2020 * little-endian.
2021 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002022typedef struct adv_carr_t {
2023 ADV_VADDR carr_va; /* Carrier Virtual Address */
2024 ADV_PADDR carr_pa; /* Carrier Physical Address */
2025 ADV_VADDR areq_vpa; /* ASC_SCSI_REQ_Q Virtual or Physical Address */
2026 /*
2027 * next_vpa [31:4] Carrier Virtual or Physical Next Pointer
2028 *
2029 * next_vpa [3:1] Reserved Bits
2030 * next_vpa [0] Done Flag set in Response Queue.
2031 */
2032 ADV_VADDR next_vpa;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033} ADV_CARR_T;
2034
2035/*
2036 * Mask used to eliminate low 4 bits of carrier 'next_vpa' field.
2037 */
2038#define ASC_NEXT_VPA_MASK 0xFFFFFFF0
2039
2040#define ASC_RQ_DONE 0x00000001
2041#define ASC_RQ_GOOD 0x00000002
2042#define ASC_CQ_STOPPER 0x00000000
2043
2044#define ASC_GET_CARRP(carrp) ((carrp) & ASC_NEXT_VPA_MASK)
2045
2046#define ADV_CARRIER_NUM_PAGE_CROSSING \
2047 (((ADV_CARRIER_COUNT * sizeof(ADV_CARR_T)) + \
2048 (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
2049
2050#define ADV_CARRIER_BUFSIZE \
2051 ((ADV_CARRIER_COUNT + ADV_CARRIER_NUM_PAGE_CROSSING) * sizeof(ADV_CARR_T))
2052
2053/*
2054 * ASC_SCSI_REQ_Q 'a_flag' definitions
2055 *
2056 * The Adv Library should limit use to the lower nibble (4 bits) of
2057 * a_flag. Drivers are free to use the upper nibble (4 bits) of a_flag.
2058 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002059#define ADV_POLL_REQUEST 0x01 /* poll for request completion */
2060#define ADV_SCSIQ_DONE 0x02 /* request done */
2061#define ADV_DONT_RETRY 0x08 /* don't do retry */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002063#define ADV_CHIP_ASC3550 0x01 /* Ultra-Wide IC */
2064#define ADV_CHIP_ASC38C0800 0x02 /* Ultra2-Wide/LVD IC */
2065#define ADV_CHIP_ASC38C1600 0x03 /* Ultra3-Wide/LVD2 IC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066
2067/*
2068 * Adapter temporary configuration structure
2069 *
2070 * This structure can be discarded after initialization. Don't add
2071 * fields here needed after initialization.
2072 *
2073 * Field naming convention:
2074 *
2075 * *_enable indicates the field enables or disables a feature. The
2076 * value of the field is never reset.
2077 */
2078typedef struct adv_dvc_cfg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002079 ushort disc_enable; /* enable disconnection */
2080 uchar chip_version; /* chip version */
2081 uchar termination; /* Term. Ctrl. bits 6-5 of SCSI_CFG1 register */
2082 ushort lib_version; /* Adv Library version number */
2083 ushort control_flag; /* Microcode Control Flag */
2084 ushort mcode_date; /* Microcode date */
2085 ushort mcode_version; /* Microcode version */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002086 ushort serial1; /* EEPROM serial number word 1 */
2087 ushort serial2; /* EEPROM serial number word 2 */
2088 ushort serial3; /* EEPROM serial number word 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089} ADV_DVC_CFG;
2090
2091struct adv_dvc_var;
2092struct adv_scsi_req_q;
2093
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094/*
2095 * Adapter operation variable structure.
2096 *
2097 * One structure is required per host adapter.
2098 *
2099 * Field naming convention:
2100 *
2101 * *_able indicates both whether a feature should be enabled or disabled
2102 * and whether a device isi capable of the feature. At initialization
2103 * this field may be set, but later if a device is found to be incapable
2104 * of the feature, the field is cleared.
2105 */
2106typedef struct adv_dvc_var {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002107 AdvPortAddr iop_base; /* I/O port address */
2108 ushort err_code; /* fatal error code */
2109 ushort bios_ctrl; /* BIOS control word, EEPROM word 12 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002110 ushort wdtr_able; /* try WDTR for a device */
2111 ushort sdtr_able; /* try SDTR for a device */
2112 ushort ultra_able; /* try SDTR Ultra speed for a device */
2113 ushort sdtr_speed1; /* EEPROM SDTR Speed for TID 0-3 */
2114 ushort sdtr_speed2; /* EEPROM SDTR Speed for TID 4-7 */
2115 ushort sdtr_speed3; /* EEPROM SDTR Speed for TID 8-11 */
2116 ushort sdtr_speed4; /* EEPROM SDTR Speed for TID 12-15 */
2117 ushort tagqng_able; /* try tagged queuing with a device */
2118 ushort ppr_able; /* PPR message capable per TID bitmask. */
2119 uchar max_dvc_qng; /* maximum number of tagged commands per device */
2120 ushort start_motor; /* start motor command allowed */
2121 uchar scsi_reset_wait; /* delay in seconds after scsi bus reset */
2122 uchar chip_no; /* should be assigned by caller */
2123 uchar max_host_qng; /* maximum number of Q'ed command allowed */
2124 uchar irq_no; /* IRQ number */
2125 ushort no_scam; /* scam_tolerant of EEPROM */
2126 struct asc_board *drv_ptr; /* driver pointer to private structure */
2127 uchar chip_scsi_id; /* chip SCSI target ID */
2128 uchar chip_type;
2129 uchar bist_err_code;
2130 ADV_CARR_T *carrier_buf;
2131 ADV_CARR_T *carr_freelist; /* Carrier free list. */
2132 ADV_CARR_T *icq_sp; /* Initiator command queue stopper pointer. */
2133 ADV_CARR_T *irq_sp; /* Initiator response queue stopper pointer. */
2134 ushort carr_pending_cnt; /* Count of pending carriers. */
2135 /*
2136 * Note: The following fields will not be used after initialization. The
2137 * driver may discard the buffer after initialization is done.
2138 */
2139 ADV_DVC_CFG *cfg; /* temporary configuration structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140} ADV_DVC_VAR;
2141
2142#define NO_OF_SG_PER_BLOCK 15
2143
2144typedef struct asc_sg_block {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002145 uchar reserved1;
2146 uchar reserved2;
2147 uchar reserved3;
2148 uchar sg_cnt; /* Valid entries in block. */
2149 ADV_PADDR sg_ptr; /* Pointer to next sg block. */
2150 struct {
2151 ADV_PADDR sg_addr; /* SG element address. */
2152 ADV_DCNT sg_count; /* SG element count. */
2153 } sg_list[NO_OF_SG_PER_BLOCK];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154} ADV_SG_BLOCK;
2155
2156/*
2157 * ADV_SCSI_REQ_Q - microcode request structure
2158 *
2159 * All fields in this structure up to byte 60 are used by the microcode.
2160 * The microcode makes assumptions about the size and ordering of fields
2161 * in this structure. Do not change the structure definition here without
2162 * coordinating the change with the microcode.
2163 *
2164 * All fields accessed by microcode must be maintained in little_endian
2165 * order.
2166 */
2167typedef struct adv_scsi_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002168 uchar cntl; /* Ucode flags and state (ASC_MC_QC_*). */
2169 uchar target_cmd;
2170 uchar target_id; /* Device target identifier. */
2171 uchar target_lun; /* Device target logical unit number. */
2172 ADV_PADDR data_addr; /* Data buffer physical address. */
2173 ADV_DCNT data_cnt; /* Data count. Ucode sets to residual. */
2174 ADV_PADDR sense_addr;
2175 ADV_PADDR carr_pa;
2176 uchar mflag;
2177 uchar sense_len;
2178 uchar cdb_len; /* SCSI CDB length. Must <= 16 bytes. */
2179 uchar scsi_cntl;
2180 uchar done_status; /* Completion status. */
2181 uchar scsi_status; /* SCSI status byte. */
2182 uchar host_status; /* Ucode host status. */
2183 uchar sg_working_ix;
2184 uchar cdb[12]; /* SCSI CDB bytes 0-11. */
2185 ADV_PADDR sg_real_addr; /* SG list physical address. */
2186 ADV_PADDR scsiq_rptr;
2187 uchar cdb16[4]; /* SCSI CDB bytes 12-15. */
2188 ADV_VADDR scsiq_ptr;
2189 ADV_VADDR carr_va;
2190 /*
2191 * End of microcode structure - 60 bytes. The rest of the structure
2192 * is used by the Adv Library and ignored by the microcode.
2193 */
2194 ADV_VADDR srb_ptr;
2195 ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */
2196 char *vdata_addr; /* Data buffer virtual address. */
2197 uchar a_flag;
2198 uchar pad[2]; /* Pad out to a word boundary. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199} ADV_SCSI_REQ_Q;
2200
2201/*
2202 * Microcode idle loop commands
2203 */
2204#define IDLE_CMD_COMPLETED 0
2205#define IDLE_CMD_STOP_CHIP 0x0001
2206#define IDLE_CMD_STOP_CHIP_SEND_INT 0x0002
2207#define IDLE_CMD_SEND_INT 0x0004
2208#define IDLE_CMD_ABORT 0x0008
2209#define IDLE_CMD_DEVICE_RESET 0x0010
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002210#define IDLE_CMD_SCSI_RESET_START 0x0020 /* Assert SCSI Bus Reset */
2211#define IDLE_CMD_SCSI_RESET_END 0x0040 /* Deassert SCSI Bus Reset */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212#define IDLE_CMD_SCSIREQ 0x0080
2213
2214#define IDLE_CMD_STATUS_SUCCESS 0x0001
2215#define IDLE_CMD_STATUS_FAILURE 0x0002
2216
2217/*
2218 * AdvSendIdleCmd() flag definitions.
2219 */
2220#define ADV_NOWAIT 0x01
2221
2222/*
2223 * Wait loop time out values.
2224 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002225#define SCSI_WAIT_10_SEC 10UL /* 10 seconds */
2226#define SCSI_WAIT_100_MSEC 100UL /* 100 milliseconds */
2227#define SCSI_US_PER_MSEC 1000 /* microseconds per millisecond */
2228#define SCSI_MS_PER_SEC 1000UL /* milliseconds per second */
2229#define SCSI_MAX_RETRY 10 /* retry count */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002231#define ADV_ASYNC_RDMA_FAILURE 0x01 /* Fatal RDMA failure. */
2232#define ADV_ASYNC_SCSI_BUS_RESET_DET 0x02 /* Detected SCSI Bus Reset. */
2233#define ADV_ASYNC_CARRIER_READY_FAILURE 0x03 /* Carrier Ready failure. */
2234#define ADV_RDMA_IN_CARR_AND_Q_INVALID 0x04 /* RDMAed-in data invalid. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002236#define ADV_HOST_SCSI_BUS_RESET 0x80 /* Host Initiated SCSI Bus Reset. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237
2238/*
2239 * Device drivers must define the following functions.
2240 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002241static inline ulong DvcEnterCritical(void);
2242static inline void DvcLeaveCritical(ulong);
2243static void DvcSleepMilliSecond(ADV_DCNT);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002244static ADV_PADDR DvcGetPhyAddr(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *,
2245 uchar *, ASC_SDCNT *, int);
2246static void DvcDelayMicroSecond(ADV_DVC_VAR *, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247
2248/*
2249 * Adv Library functions available to drivers.
2250 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002251static int AdvExeScsiQueue(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
2252static int AdvISR(ADV_DVC_VAR *);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002253static int AdvInitAsc3550Driver(ADV_DVC_VAR *);
2254static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *);
2255static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *);
2256static int AdvResetChipAndSB(ADV_DVC_VAR *);
2257static int AdvResetSB(ADV_DVC_VAR *asc_dvc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258
2259/*
2260 * Internal Adv Library functions.
2261 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002262static int AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ADV_DCNT);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002263static int AdvInitFrom3550EEP(ADV_DVC_VAR *);
2264static int AdvInitFrom38C0800EEP(ADV_DVC_VAR *);
2265static int AdvInitFrom38C1600EEP(ADV_DVC_VAR *);
2266static ushort AdvGet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
2267static void AdvSet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
2268static ushort AdvGet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
2269static void AdvSet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
2270static ushort AdvGet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
2271static void AdvSet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
2272static void AdvWaitEEPCmd(AdvPortAddr);
2273static ushort AdvReadEEPWord(AdvPortAddr, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275/* Read byte from a register. */
2276#define AdvReadByteRegister(iop_base, reg_off) \
2277 (ADV_MEM_READB((iop_base) + (reg_off)))
2278
2279/* Write byte to a register. */
2280#define AdvWriteByteRegister(iop_base, reg_off, byte) \
2281 (ADV_MEM_WRITEB((iop_base) + (reg_off), (byte)))
2282
2283/* Read word (2 bytes) from a register. */
2284#define AdvReadWordRegister(iop_base, reg_off) \
2285 (ADV_MEM_READW((iop_base) + (reg_off)))
2286
2287/* Write word (2 bytes) to a register. */
2288#define AdvWriteWordRegister(iop_base, reg_off, word) \
2289 (ADV_MEM_WRITEW((iop_base) + (reg_off), (word)))
2290
2291/* Write dword (4 bytes) to a register. */
2292#define AdvWriteDWordRegister(iop_base, reg_off, dword) \
2293 (ADV_MEM_WRITEDW((iop_base) + (reg_off), (dword)))
2294
2295/* Read byte from LRAM. */
2296#define AdvReadByteLram(iop_base, addr, byte) \
2297do { \
2298 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
2299 (byte) = ADV_MEM_READB((iop_base) + IOPB_RAM_DATA); \
2300} while (0)
2301
2302/* Write byte to LRAM. */
2303#define AdvWriteByteLram(iop_base, addr, byte) \
2304 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
2305 ADV_MEM_WRITEB((iop_base) + IOPB_RAM_DATA, (byte)))
2306
2307/* Read word (2 bytes) from LRAM. */
2308#define AdvReadWordLram(iop_base, addr, word) \
2309do { \
2310 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
2311 (word) = (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA)); \
2312} while (0)
2313
2314/* Write word (2 bytes) to LRAM. */
2315#define AdvWriteWordLram(iop_base, addr, word) \
2316 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
2317 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
2318
2319/* Write little-endian double word (4 bytes) to LRAM */
2320/* Because of unspecified C language ordering don't use auto-increment. */
2321#define AdvWriteDWordLramNoSwap(iop_base, addr, dword) \
2322 ((ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
2323 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
2324 cpu_to_le16((ushort) ((dword) & 0xFFFF)))), \
2325 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr) + 2), \
2326 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
2327 cpu_to_le16((ushort) ((dword >> 16) & 0xFFFF)))))
2328
2329/* Read word (2 bytes) from LRAM assuming that the address is already set. */
2330#define AdvReadWordAutoIncLram(iop_base) \
2331 (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA))
2332
2333/* Write word (2 bytes) to LRAM assuming that the address is already set. */
2334#define AdvWriteWordAutoIncLram(iop_base, word) \
2335 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
2336
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337/*
2338 * Define macro to check for Condor signature.
2339 *
2340 * Evaluate to ADV_TRUE if a Condor chip is found the specified port
2341 * address 'iop_base'. Otherwise evalue to ADV_FALSE.
2342 */
2343#define AdvFindSignature(iop_base) \
2344 (((AdvReadByteRegister((iop_base), IOPB_CHIP_ID_1) == \
2345 ADV_CHIP_ID_BYTE) && \
2346 (AdvReadWordRegister((iop_base), IOPW_CHIP_ID_0) == \
2347 ADV_CHIP_ID_WORD)) ? ADV_TRUE : ADV_FALSE)
2348
2349/*
2350 * Define macro to Return the version number of the chip at 'iop_base'.
2351 *
2352 * The second parameter 'bus_type' is currently unused.
2353 */
2354#define AdvGetChipVersion(iop_base, bus_type) \
2355 AdvReadByteRegister((iop_base), IOPB_CHIP_TYPE_REV)
2356
2357/*
2358 * Abort an SRB in the chip's RISC Memory. The 'srb_ptr' argument must
2359 * match the ASC_SCSI_REQ_Q 'srb_ptr' field.
2360 *
2361 * If the request has not yet been sent to the device it will simply be
2362 * aborted from RISC memory. If the request is disconnected it will be
2363 * aborted on reselection by sending an Abort Message to the target ID.
2364 *
2365 * Return value:
2366 * ADV_TRUE(1) - Queue was successfully aborted.
2367 * ADV_FALSE(0) - Queue was not found on the active queue list.
2368 */
2369#define AdvAbortQueue(asc_dvc, scsiq) \
2370 AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_ABORT, \
2371 (ADV_DCNT) (scsiq))
2372
2373/*
2374 * Send a Bus Device Reset Message to the specified target ID.
2375 *
2376 * All outstanding commands will be purged if sending the
2377 * Bus Device Reset Message is successful.
2378 *
2379 * Return Value:
2380 * ADV_TRUE(1) - All requests on the target are purged.
2381 * ADV_FALSE(0) - Couldn't issue Bus Device Reset Message; Requests
2382 * are not purged.
2383 */
2384#define AdvResetDevice(asc_dvc, target_id) \
2385 AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_DEVICE_RESET, \
2386 (ADV_DCNT) (target_id))
2387
2388/*
2389 * SCSI Wide Type definition.
2390 */
2391#define ADV_SCSI_BIT_ID_TYPE ushort
2392
2393/*
2394 * AdvInitScsiTarget() 'cntl_flag' options.
2395 */
2396#define ADV_SCAN_LUN 0x01
2397#define ADV_CAPINFO_NOLUN 0x02
2398
2399/*
2400 * Convert target id to target id bit mask.
2401 */
2402#define ADV_TID_TO_TIDMASK(tid) (0x01 << ((tid) & ADV_MAX_TID))
2403
2404/*
2405 * ASC_SCSI_REQ_Q 'done_status' and 'host_status' return values.
2406 */
2407
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002408#define QD_NO_STATUS 0x00 /* Request not completed yet. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409#define QD_NO_ERROR 0x01
2410#define QD_ABORTED_BY_HOST 0x02
2411#define QD_WITH_ERROR 0x04
2412
2413#define QHSTA_NO_ERROR 0x00
2414#define QHSTA_M_SEL_TIMEOUT 0x11
2415#define QHSTA_M_DATA_OVER_RUN 0x12
2416#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
2417#define QHSTA_M_QUEUE_ABORTED 0x15
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002418#define QHSTA_M_SXFR_SDMA_ERR 0x16 /* SXFR_STATUS SCSI DMA Error */
2419#define QHSTA_M_SXFR_SXFR_PERR 0x17 /* SXFR_STATUS SCSI Bus Parity Error */
2420#define QHSTA_M_RDMA_PERR 0x18 /* RISC PCI DMA parity error */
2421#define QHSTA_M_SXFR_OFF_UFLW 0x19 /* SXFR_STATUS Offset Underflow */
2422#define QHSTA_M_SXFR_OFF_OFLW 0x20 /* SXFR_STATUS Offset Overflow */
2423#define QHSTA_M_SXFR_WD_TMO 0x21 /* SXFR_STATUS Watchdog Timeout */
2424#define QHSTA_M_SXFR_DESELECTED 0x22 /* SXFR_STATUS Deselected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425/* Note: QHSTA_M_SXFR_XFR_OFLW is identical to QHSTA_M_DATA_OVER_RUN. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002426#define QHSTA_M_SXFR_XFR_OFLW 0x12 /* SXFR_STATUS Transfer Overflow */
2427#define QHSTA_M_SXFR_XFR_PH_ERR 0x24 /* SXFR_STATUS Transfer Phase Error */
2428#define QHSTA_M_SXFR_UNKNOWN_ERROR 0x25 /* SXFR_STATUS Unknown Error */
2429#define QHSTA_M_SCSI_BUS_RESET 0x30 /* Request aborted from SBR */
2430#define QHSTA_M_SCSI_BUS_RESET_UNSOL 0x31 /* Request aborted from unsol. SBR */
2431#define QHSTA_M_BUS_DEVICE_RESET 0x32 /* Request aborted from BDR */
2432#define QHSTA_M_DIRECTION_ERR 0x35 /* Data Phase mismatch */
2433#define QHSTA_M_DIRECTION_ERR_HUNG 0x36 /* Data Phase mismatch and bus hang */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434#define QHSTA_M_WTM_TIMEOUT 0x41
2435#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42
2436#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43
2437#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002438#define QHSTA_M_INVALID_DEVICE 0x45 /* Bad target ID */
2439#define QHSTA_M_FROZEN_TIDQ 0x46 /* TID Queue frozen. */
2440#define QHSTA_M_SGBACKUP_ERROR 0x47 /* Scatter-Gather backup error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441
2442/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 * DvcGetPhyAddr() flag arguments
2444 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002445#define ADV_IS_SCSIQ_FLAG 0x01 /* 'addr' is ASC_SCSI_REQ_Q pointer */
2446#define ADV_ASCGETSGLIST_VADDR 0x02 /* 'addr' is AscGetSGList() virtual addr */
2447#define ADV_IS_SENSE_FLAG 0x04 /* 'addr' is sense virtual pointer */
2448#define ADV_IS_DATA_FLAG 0x08 /* 'addr' is data virtual pointer */
2449#define ADV_IS_SGLIST_FLAG 0x10 /* 'addr' is sglist virtual pointer */
2450#define ADV_IS_CARRIER_FLAG 0x20 /* 'addr' is ADV_CARR_T pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451
2452/* Return the address that is aligned at the next doubleword >= to 'addr'. */
2453#define ADV_8BALIGN(addr) (((ulong) (addr) + 0x7) & ~0x7)
2454#define ADV_16BALIGN(addr) (((ulong) (addr) + 0xF) & ~0xF)
2455#define ADV_32BALIGN(addr) (((ulong) (addr) + 0x1F) & ~0x1F)
2456
2457/*
2458 * Total contiguous memory needed for driver SG blocks.
2459 *
2460 * ADV_MAX_SG_LIST must be defined by a driver. It is the maximum
2461 * number of scatter-gather elements the driver supports in a
2462 * single request.
2463 */
2464
2465#define ADV_SG_LIST_MAX_BYTE_SIZE \
2466 (sizeof(ADV_SG_BLOCK) * \
2467 ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK))
2468
2469/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 * --- Driver Constants and Macros
2471 */
2472
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473/* Reference Scsi_Host hostdata */
2474#define ASC_BOARDP(host) ((asc_board_t *) &((host)->hostdata))
2475
2476/* asc_board_t flags */
2477#define ASC_HOST_IN_RESET 0x01
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002478#define ASC_IS_WIDE_BOARD 0x04 /* AdvanSys Wide Board */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479#define ASC_SELECT_QUEUE_DEPTHS 0x08
2480
2481#define ASC_NARROW_BOARD(boardp) (((boardp)->flags & ASC_IS_WIDE_BOARD) == 0)
2482#define ASC_WIDE_BOARD(boardp) ((boardp)->flags & ASC_IS_WIDE_BOARD)
2483
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002484#define NO_ISA_DMA 0xff /* No ISA DMA Channel Used */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002486#define ASC_INFO_SIZE 128 /* advansys_info() line size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487
2488#ifdef CONFIG_PROC_FS
2489/* /proc/scsi/advansys/[0...] related definitions */
2490#define ASC_PRTBUF_SIZE 2048
2491#define ASC_PRTLINE_SIZE 160
2492
2493#define ASC_PRT_NEXT() \
2494 if (cp) { \
2495 totlen += len; \
2496 leftlen -= len; \
2497 if (leftlen == 0) { \
2498 return totlen; \
2499 } \
2500 cp += len; \
2501 }
2502#endif /* CONFIG_PROC_FS */
2503
2504/* Asc Library return codes */
2505#define ASC_TRUE 1
2506#define ASC_FALSE 0
2507#define ASC_NOERROR 1
2508#define ASC_BUSY 0
2509#define ASC_ERROR (-1)
2510
2511/* struct scsi_cmnd function return codes */
2512#define STATUS_BYTE(byte) (byte)
2513#define MSG_BYTE(byte) ((byte) << 8)
2514#define HOST_BYTE(byte) ((byte) << 16)
2515#define DRIVER_BYTE(byte) ((byte) << 24)
2516
2517/*
2518 * The following definitions and macros are OS independent interfaces to
2519 * the queue functions:
2520 * REQ - SCSI request structure
2521 * REQP - pointer to SCSI request structure
2522 * REQPTID(reqp) - reqp's target id
2523 * REQPNEXT(reqp) - reqp's next pointer
2524 * REQPNEXTP(reqp) - pointer to reqp's next pointer
2525 * REQPTIME(reqp) - reqp's time stamp value
2526 * REQTIMESTAMP() - system time stamp value
2527 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002528typedef struct scsi_cmnd REQ, *REQP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529#define REQPNEXT(reqp) ((REQP) ((reqp)->host_scribble))
2530#define REQPNEXTP(reqp) ((REQP *) &((reqp)->host_scribble))
2531#define REQPTID(reqp) ((reqp)->device->id)
2532#define REQPTIME(reqp) ((reqp)->SCp.this_residual)
2533#define REQTIMESTAMP() (jiffies)
2534
2535#define REQTIMESTAT(function, ascq, reqp, tid) \
2536{ \
2537 /*
2538 * If the request time stamp is less than the system time stamp, then \
2539 * maybe the system time stamp wrapped. Set the request time to zero.\
2540 */ \
2541 if (REQPTIME(reqp) <= REQTIMESTAMP()) { \
2542 REQPTIME(reqp) = REQTIMESTAMP() - REQPTIME(reqp); \
2543 } else { \
2544 /* Indicate an error occurred with the assertion. */ \
2545 ASC_ASSERT(REQPTIME(reqp) <= REQTIMESTAMP()); \
2546 REQPTIME(reqp) = 0; \
2547 } \
2548 /* Handle first minimum time case without external initialization. */ \
2549 if (((ascq)->q_tot_cnt[tid] == 1) || \
2550 (REQPTIME(reqp) < (ascq)->q_min_tim[tid])) { \
2551 (ascq)->q_min_tim[tid] = REQPTIME(reqp); \
2552 ASC_DBG3(1, "%s: new q_min_tim[%d] %u\n", \
2553 (function), (tid), (ascq)->q_min_tim[tid]); \
2554 } \
2555 if (REQPTIME(reqp) > (ascq)->q_max_tim[tid]) { \
2556 (ascq)->q_max_tim[tid] = REQPTIME(reqp); \
2557 ASC_DBG3(1, "%s: new q_max_tim[%d] %u\n", \
2558 (function), tid, (ascq)->q_max_tim[tid]); \
2559 } \
2560 (ascq)->q_tot_tim[tid] += REQPTIME(reqp); \
2561 /* Reset the time stamp field. */ \
2562 REQPTIME(reqp) = 0; \
2563}
2564
2565/* asc_enqueue() flags */
2566#define ASC_FRONT 1
2567#define ASC_BACK 2
2568
2569/* asc_dequeue_list() argument */
2570#define ASC_TID_ALL (-1)
2571
2572/* Return non-zero, if the queue is empty. */
2573#define ASC_QUEUE_EMPTY(ascq) ((ascq)->q_tidmask == 0)
2574
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575#ifndef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002576#define ASC_STATS(shost, counter)
2577#define ASC_STATS_ADD(shost, counter, count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578#else /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002579#define ASC_STATS(shost, counter) \
2580 (ASC_BOARDP(shost)->asc_stats.counter++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002582#define ASC_STATS_ADD(shost, counter, count) \
2583 (ASC_BOARDP(shost)->asc_stats.counter += (count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584#endif /* ADVANSYS_STATS */
2585
2586#define ASC_CEILING(val, unit) (((val) + ((unit) - 1))/(unit))
2587
2588/* If the result wraps when calculating tenths, return 0. */
2589#define ASC_TENTHS(num, den) \
2590 (((10 * ((num)/(den))) > (((num) * 10)/(den))) ? \
2591 0 : ((((num) * 10)/(den)) - (10 * ((num)/(den)))))
2592
2593/*
2594 * Display a message to the console.
2595 */
2596#define ASC_PRINT(s) \
2597 { \
2598 printk("advansys: "); \
2599 printk(s); \
2600 }
2601
2602#define ASC_PRINT1(s, a1) \
2603 { \
2604 printk("advansys: "); \
2605 printk((s), (a1)); \
2606 }
2607
2608#define ASC_PRINT2(s, a1, a2) \
2609 { \
2610 printk("advansys: "); \
2611 printk((s), (a1), (a2)); \
2612 }
2613
2614#define ASC_PRINT3(s, a1, a2, a3) \
2615 { \
2616 printk("advansys: "); \
2617 printk((s), (a1), (a2), (a3)); \
2618 }
2619
2620#define ASC_PRINT4(s, a1, a2, a3, a4) \
2621 { \
2622 printk("advansys: "); \
2623 printk((s), (a1), (a2), (a3), (a4)); \
2624 }
2625
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626#ifndef ADVANSYS_DEBUG
2627
2628#define ASC_DBG(lvl, s)
2629#define ASC_DBG1(lvl, s, a1)
2630#define ASC_DBG2(lvl, s, a1, a2)
2631#define ASC_DBG3(lvl, s, a1, a2, a3)
2632#define ASC_DBG4(lvl, s, a1, a2, a3, a4)
2633#define ASC_DBG_PRT_SCSI_HOST(lvl, s)
2634#define ASC_DBG_PRT_SCSI_CMND(lvl, s)
2635#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp)
2636#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
2637#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone)
2638#define ADV_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
2639#define ASC_DBG_PRT_HEX(lvl, name, start, length)
2640#define ASC_DBG_PRT_CDB(lvl, cdb, len)
2641#define ASC_DBG_PRT_SENSE(lvl, sense, len)
2642#define ASC_DBG_PRT_INQUIRY(lvl, inq, len)
2643
2644#else /* ADVANSYS_DEBUG */
2645
2646/*
2647 * Debugging Message Levels:
2648 * 0: Errors Only
2649 * 1: High-Level Tracing
2650 * 2-N: Verbose Tracing
2651 */
2652
2653#define ASC_DBG(lvl, s) \
2654 { \
2655 if (asc_dbglvl >= (lvl)) { \
2656 printk(s); \
2657 } \
2658 }
2659
2660#define ASC_DBG1(lvl, s, a1) \
2661 { \
2662 if (asc_dbglvl >= (lvl)) { \
2663 printk((s), (a1)); \
2664 } \
2665 }
2666
2667#define ASC_DBG2(lvl, s, a1, a2) \
2668 { \
2669 if (asc_dbglvl >= (lvl)) { \
2670 printk((s), (a1), (a2)); \
2671 } \
2672 }
2673
2674#define ASC_DBG3(lvl, s, a1, a2, a3) \
2675 { \
2676 if (asc_dbglvl >= (lvl)) { \
2677 printk((s), (a1), (a2), (a3)); \
2678 } \
2679 }
2680
2681#define ASC_DBG4(lvl, s, a1, a2, a3, a4) \
2682 { \
2683 if (asc_dbglvl >= (lvl)) { \
2684 printk((s), (a1), (a2), (a3), (a4)); \
2685 } \
2686 }
2687
2688#define ASC_DBG_PRT_SCSI_HOST(lvl, s) \
2689 { \
2690 if (asc_dbglvl >= (lvl)) { \
2691 asc_prt_scsi_host(s); \
2692 } \
2693 }
2694
2695#define ASC_DBG_PRT_SCSI_CMND(lvl, s) \
2696 { \
2697 if (asc_dbglvl >= (lvl)) { \
2698 asc_prt_scsi_cmnd(s); \
2699 } \
2700 }
2701
2702#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp) \
2703 { \
2704 if (asc_dbglvl >= (lvl)) { \
2705 asc_prt_asc_scsi_q(scsiqp); \
2706 } \
2707 }
2708
2709#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone) \
2710 { \
2711 if (asc_dbglvl >= (lvl)) { \
2712 asc_prt_asc_qdone_info(qdone); \
2713 } \
2714 }
2715
2716#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp) \
2717 { \
2718 if (asc_dbglvl >= (lvl)) { \
2719 asc_prt_adv_scsi_req_q(scsiqp); \
2720 } \
2721 }
2722
2723#define ASC_DBG_PRT_HEX(lvl, name, start, length) \
2724 { \
2725 if (asc_dbglvl >= (lvl)) { \
2726 asc_prt_hex((name), (start), (length)); \
2727 } \
2728 }
2729
2730#define ASC_DBG_PRT_CDB(lvl, cdb, len) \
2731 ASC_DBG_PRT_HEX((lvl), "CDB", (uchar *) (cdb), (len));
2732
2733#define ASC_DBG_PRT_SENSE(lvl, sense, len) \
2734 ASC_DBG_PRT_HEX((lvl), "SENSE", (uchar *) (sense), (len));
2735
2736#define ASC_DBG_PRT_INQUIRY(lvl, inq, len) \
2737 ASC_DBG_PRT_HEX((lvl), "INQUIRY", (uchar *) (inq), (len));
2738#endif /* ADVANSYS_DEBUG */
2739
2740#ifndef ADVANSYS_ASSERT
2741#define ASC_ASSERT(a)
2742#else /* ADVANSYS_ASSERT */
2743
2744#define ASC_ASSERT(a) \
2745 { \
2746 if (!(a)) { \
2747 printk("ASC_ASSERT() Failure: file %s, line %d\n", \
2748 __FILE__, __LINE__); \
2749 } \
2750 }
2751
2752#endif /* ADVANSYS_ASSERT */
2753
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754/*
2755 * --- Driver Structures
2756 */
2757
2758#ifdef ADVANSYS_STATS
2759
2760/* Per board statistics structure */
2761struct asc_stats {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002762 /* Driver Entrypoint Statistics */
2763 ADV_DCNT queuecommand; /* # calls to advansys_queuecommand() */
2764 ADV_DCNT reset; /* # calls to advansys_eh_bus_reset() */
2765 ADV_DCNT biosparam; /* # calls to advansys_biosparam() */
2766 ADV_DCNT interrupt; /* # advansys_interrupt() calls */
2767 ADV_DCNT callback; /* # calls to asc/adv_isr_callback() */
2768 ADV_DCNT done; /* # calls to request's scsi_done function */
2769 ADV_DCNT build_error; /* # asc/adv_build_req() ASC_ERROR returns. */
2770 ADV_DCNT adv_build_noreq; /* # adv_build_req() adv_req_t alloc. fail. */
2771 ADV_DCNT adv_build_nosg; /* # adv_build_req() adv_sgblk_t alloc. fail. */
2772 /* AscExeScsiQueue()/AdvExeScsiQueue() Statistics */
2773 ADV_DCNT exe_noerror; /* # ASC_NOERROR returns. */
2774 ADV_DCNT exe_busy; /* # ASC_BUSY returns. */
2775 ADV_DCNT exe_error; /* # ASC_ERROR returns. */
2776 ADV_DCNT exe_unknown; /* # unknown returns. */
2777 /* Data Transfer Statistics */
2778 ADV_DCNT cont_cnt; /* # non-scatter-gather I/O requests received */
2779 ADV_DCNT cont_xfer; /* # contiguous transfer 512-bytes */
2780 ADV_DCNT sg_cnt; /* # scatter-gather I/O requests received */
2781 ADV_DCNT sg_elem; /* # scatter-gather elements */
2782 ADV_DCNT sg_xfer; /* # scatter-gather transfer 512-bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783};
2784#endif /* ADVANSYS_STATS */
2785
2786/*
2787 * Request queuing structure
2788 */
2789typedef struct asc_queue {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002790 ADV_SCSI_BIT_ID_TYPE q_tidmask; /* queue mask */
2791 REQP q_first[ADV_MAX_TID + 1]; /* first queued request */
2792 REQP q_last[ADV_MAX_TID + 1]; /* last queued request */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002794 short q_cur_cnt[ADV_MAX_TID + 1]; /* current queue count */
2795 short q_max_cnt[ADV_MAX_TID + 1]; /* maximum queue count */
2796 ADV_DCNT q_tot_cnt[ADV_MAX_TID + 1]; /* total enqueue count */
2797 ADV_DCNT q_tot_tim[ADV_MAX_TID + 1]; /* total time queued */
2798 ushort q_max_tim[ADV_MAX_TID + 1]; /* maximum time queued */
2799 ushort q_min_tim[ADV_MAX_TID + 1]; /* minimum time queued */
2800#endif /* ADVANSYS_STATS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801} asc_queue_t;
2802
2803/*
2804 * Adv Library Request Structures
2805 *
2806 * The following two structures are used to process Wide Board requests.
2807 *
2808 * The ADV_SCSI_REQ_Q structure in adv_req_t is passed to the Adv Library
2809 * and microcode with the ADV_SCSI_REQ_Q field 'srb_ptr' pointing to the
2810 * adv_req_t. The adv_req_t structure 'cmndp' field in turn points to the
2811 * Mid-Level SCSI request structure.
2812 *
2813 * Zero or more ADV_SG_BLOCK are used with each ADV_SCSI_REQ_Q. Each
2814 * ADV_SG_BLOCK structure holds 15 scatter-gather elements. Under Linux
2815 * up to 255 scatter-gather elements may be used per request or
2816 * ADV_SCSI_REQ_Q.
2817 *
2818 * Both structures must be 32 byte aligned.
2819 */
2820typedef struct adv_sgblk {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002821 ADV_SG_BLOCK sg_block; /* Sgblock structure. */
2822 uchar align[32]; /* Sgblock structure padding. */
2823 struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824} adv_sgblk_t;
2825
2826typedef struct adv_req {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002827 ADV_SCSI_REQ_Q scsi_req_q; /* Adv Library request structure. */
2828 uchar align[32]; /* Request structure padding. */
2829 struct scsi_cmnd *cmndp; /* Mid-Level SCSI command pointer. */
2830 adv_sgblk_t *sgblkp; /* Adv Library scatter-gather pointer. */
2831 struct adv_req *next_reqp; /* Next Request Structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832} adv_req_t;
2833
2834/*
2835 * Structure allocated for each board.
2836 *
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06002837 * This structure is allocated by scsi_host_alloc() at the end
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838 * of the 'Scsi_Host' structure starting at the 'hostdata'
2839 * field. It is guaranteed to be allocated from DMA-able memory.
2840 */
2841typedef struct asc_board {
Matthew Wilcox394dbf32007-07-26 11:56:40 -04002842 struct device *dev;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002843 int id; /* Board Id */
2844 uint flags; /* Board flags */
2845 union {
2846 ASC_DVC_VAR asc_dvc_var; /* Narrow board */
2847 ADV_DVC_VAR adv_dvc_var; /* Wide board */
2848 } dvc_var;
2849 union {
2850 ASC_DVC_CFG asc_dvc_cfg; /* Narrow board */
2851 ADV_DVC_CFG adv_dvc_cfg; /* Wide board */
2852 } dvc_cfg;
2853 ushort asc_n_io_port; /* Number I/O ports. */
2854 asc_queue_t active; /* Active command queue */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002855 asc_queue_t done; /* Done command queue */
2856 ADV_SCSI_BIT_ID_TYPE init_tidmask; /* Target init./valid mask */
2857 struct scsi_device *device[ADV_MAX_TID + 1]; /* Mid-Level Scsi Device */
2858 ushort reqcnt[ADV_MAX_TID + 1]; /* Starvation request count */
2859 ADV_SCSI_BIT_ID_TYPE queue_full; /* Queue full mask */
2860 ushort queue_full_cnt[ADV_MAX_TID + 1]; /* Queue full count */
2861 union {
2862 ASCEEP_CONFIG asc_eep; /* Narrow EEPROM config. */
2863 ADVEEP_3550_CONFIG adv_3550_eep; /* 3550 EEPROM config. */
2864 ADVEEP_38C0800_CONFIG adv_38C0800_eep; /* 38C0800 EEPROM config. */
2865 ADVEEP_38C1600_CONFIG adv_38C1600_eep; /* 38C1600 EEPROM config. */
2866 } eep_config;
2867 ulong last_reset; /* Saved last reset time */
2868 spinlock_t lock; /* Board spinlock */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002869 /* /proc/scsi/advansys/[0...] */
2870 char *prtbuf; /* /proc print buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002872 struct asc_stats asc_stats; /* Board statistics */
2873#endif /* ADVANSYS_STATS */
2874 /*
2875 * The following fields are used only for Narrow Boards.
2876 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002877 uchar sdtr_data[ASC_MAX_TID + 1]; /* SDTR information */
2878 /*
2879 * The following fields are used only for Wide Boards.
2880 */
2881 void __iomem *ioremap_addr; /* I/O Memory remap address. */
2882 ushort ioport; /* I/O Port address. */
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -06002883 ADV_CARR_T *carrp; /* ADV_CARR_T memory block. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002884 adv_req_t *orig_reqp; /* adv_req_t memory block. */
2885 adv_req_t *adv_reqp; /* Request structures. */
2886 adv_sgblk_t *adv_sgblkp; /* Scatter-gather structures. */
2887 ushort bios_signature; /* BIOS Signature. */
2888 ushort bios_version; /* BIOS Version. */
2889 ushort bios_codeseg; /* BIOS Code Segment. */
2890 ushort bios_codelen; /* BIOS Code Segment Length. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891} asc_board_t;
2892
Matthew Wilcox13ac2d92007-07-30 08:10:23 -06002893#define adv_dvc_to_board(adv_dvc) container_of(adv_dvc, struct asc_board, \
2894 dvc_var.adv_dvc_var)
2895#define adv_dvc_to_pdev(adv_dvc) to_pci_dev(adv_dvc_to_board(adv_dvc)->dev)
2896
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897/* Number of boards detected in system. */
Matthew Wilcox78e77d82007-07-29 21:46:15 -06002898static int asc_board_count;
2899
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900/* Overrun buffer used by all narrow boards. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002901static uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902
2903/*
2904 * Global structures required to issue a command.
2905 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002906static ASC_SCSI_Q asc_scsi_q = { {0} };
2907static ASC_SG_HEAD asc_sg_head = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002910static int asc_dbglvl = 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911#endif /* ADVANSYS_DEBUG */
2912
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913/*
2914 * --- Driver Function Prototypes
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915 */
2916
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002917static int advansys_slave_configure(struct scsi_device *);
2918static void asc_scsi_done_list(struct scsi_cmnd *);
2919static int asc_execute_scsi_cmnd(struct scsi_cmnd *);
2920static int asc_build_req(asc_board_t *, struct scsi_cmnd *);
2921static int adv_build_req(asc_board_t *, struct scsi_cmnd *, ADV_SCSI_REQ_Q **);
2922static int adv_get_sglist(asc_board_t *, adv_req_t *, struct scsi_cmnd *, int);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002923static void asc_enqueue(asc_queue_t *, REQP, int);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002924static REQP asc_dequeue_list(asc_queue_t *, REQP *, int);
2925static int asc_rmqueue(asc_queue_t *, REQP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002927static int asc_proc_copy(off_t, off_t, char *, int, char *, int);
2928static int asc_prt_board_devices(struct Scsi_Host *, char *, int);
2929static int asc_prt_adv_bios(struct Scsi_Host *, char *, int);
2930static int asc_get_eeprom_string(ushort *serialnum, uchar *cp);
2931static int asc_prt_asc_board_eeprom(struct Scsi_Host *, char *, int);
2932static int asc_prt_adv_board_eeprom(struct Scsi_Host *, char *, int);
2933static int asc_prt_driver_conf(struct Scsi_Host *, char *, int);
2934static int asc_prt_asc_board_info(struct Scsi_Host *, char *, int);
2935static int asc_prt_adv_board_info(struct Scsi_Host *, char *, int);
2936static int asc_prt_line(char *, int, char *fmt, ...);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937#endif /* CONFIG_PROC_FS */
2938
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939/* Statistics function prototypes. */
2940#ifdef ADVANSYS_STATS
2941#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002942static int asc_prt_board_stats(struct Scsi_Host *, char *, int);
2943static int asc_prt_target_stats(struct Scsi_Host *, int, char *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944#endif /* CONFIG_PROC_FS */
2945#endif /* ADVANSYS_STATS */
2946
2947/* Debug function prototypes. */
2948#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002949static void asc_prt_scsi_host(struct Scsi_Host *);
2950static void asc_prt_scsi_cmnd(struct scsi_cmnd *);
2951static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *);
2952static void asc_prt_asc_dvc_var(ASC_DVC_VAR *);
2953static void asc_prt_asc_scsi_q(ASC_SCSI_Q *);
2954static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *);
2955static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *);
2956static void asc_prt_adv_dvc_var(ADV_DVC_VAR *);
2957static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *);
2958static void asc_prt_adv_sgblock(int, ADV_SG_BLOCK *);
2959static void asc_prt_hex(char *f, uchar *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960#endif /* ADVANSYS_DEBUG */
2961
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962#ifdef CONFIG_PROC_FS
2963/*
Matthew Wilcoxc304ec92007-07-30 09:18:45 -06002964 * advansys_proc_info() - /proc/scsi/advansys/{0,1,2,3,...}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965 *
2966 * *buffer: I/O buffer
2967 * **start: if inout == FALSE pointer into buffer where user read should start
2968 * offset: current offset into a /proc/scsi/advansys/[0...] file
2969 * length: length of buffer
2970 * hostno: Scsi_Host host_no
2971 * inout: TRUE - user is writing; FALSE - user is reading
2972 *
2973 * Return the number of bytes read from or written to a
2974 * /proc/scsi/advansys/[0...] file.
2975 *
2976 * Note: This function uses the per board buffer 'prtbuf' which is
2977 * allocated when the board is initialized in advansys_detect(). The
2978 * buffer is ASC_PRTBUF_SIZE bytes. The function asc_proc_copy() is
2979 * used to write to the buffer. The way asc_proc_copy() is written
2980 * if 'prtbuf' is too small it will not be overwritten. Instead the
2981 * user just won't get all the available statistics.
2982 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07002983static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002985 off_t offset, int length, int inout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002987 asc_board_t *boardp;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002988 char *cp;
2989 int cplen;
2990 int cnt;
2991 int totcnt;
2992 int leftlen;
2993 char *curbuf;
2994 off_t advoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002996 int tgt_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997#endif /* ADVANSYS_STATS */
2998
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002999 ASC_DBG(1, "advansys_proc_info: begin\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003001 /*
3002 * User write not supported.
3003 */
3004 if (inout == TRUE) {
3005 return (-ENOSYS);
3006 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003008 /*
3009 * User read of /proc/scsi/advansys/[0...] file.
3010 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011
Matthew Wilcox2a437952007-07-26 11:00:51 -04003012 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003014 /* Copy read data starting at the beginning of the buffer. */
3015 *start = buffer;
3016 curbuf = buffer;
3017 advoffset = 0;
3018 totcnt = 0;
3019 leftlen = length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003021 /*
3022 * Get board configuration information.
3023 *
3024 * advansys_info() returns the board string from its own static buffer.
3025 */
Matthew Wilcox2a437952007-07-26 11:00:51 -04003026 cp = (char *)advansys_info(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003027 strcat(cp, "\n");
3028 cplen = strlen(cp);
3029 /* Copy board information. */
3030 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3031 totcnt += cnt;
3032 leftlen -= cnt;
3033 if (leftlen == 0) {
3034 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3035 return totcnt;
3036 }
3037 advoffset += cplen;
3038 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003040 /*
3041 * Display Wide Board BIOS Information.
3042 */
3043 if (ASC_WIDE_BOARD(boardp)) {
3044 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003045 cplen = asc_prt_adv_bios(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003046 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003047 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003048 cplen);
3049 totcnt += cnt;
3050 leftlen -= cnt;
3051 if (leftlen == 0) {
3052 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3053 return totcnt;
3054 }
3055 advoffset += cplen;
3056 curbuf += cnt;
3057 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003059 /*
3060 * Display driver information for each device attached to the board.
3061 */
3062 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003063 cplen = asc_prt_board_devices(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003064 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3065 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3066 totcnt += cnt;
3067 leftlen -= cnt;
3068 if (leftlen == 0) {
3069 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3070 return totcnt;
3071 }
3072 advoffset += cplen;
3073 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003074
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003075 /*
3076 * Display EEPROM configuration for the board.
3077 */
3078 cp = boardp->prtbuf;
3079 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003080 cplen = asc_prt_asc_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003081 } else {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003082 cplen = asc_prt_adv_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003083 }
3084 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3085 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3086 totcnt += cnt;
3087 leftlen -= cnt;
3088 if (leftlen == 0) {
3089 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3090 return totcnt;
3091 }
3092 advoffset += cplen;
3093 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003095 /*
3096 * Display driver configuration and information for the board.
3097 */
3098 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003099 cplen = asc_prt_driver_conf(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003100 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3101 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3102 totcnt += cnt;
3103 leftlen -= cnt;
3104 if (leftlen == 0) {
3105 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3106 return totcnt;
3107 }
3108 advoffset += cplen;
3109 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110
3111#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003112 /*
3113 * Display driver statistics for the board.
3114 */
3115 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003116 cplen = asc_prt_board_stats(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003117 ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
3118 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3119 totcnt += cnt;
3120 leftlen -= cnt;
3121 if (leftlen == 0) {
3122 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3123 return totcnt;
3124 }
3125 advoffset += cplen;
3126 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003128 /*
3129 * Display driver statistics for each target.
3130 */
3131 for (tgt_id = 0; tgt_id <= ADV_MAX_TID; tgt_id++) {
3132 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003133 cplen = asc_prt_target_stats(shost, tgt_id, cp,
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003134 ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003135 ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003136 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
3137 cplen);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003138 totcnt += cnt;
3139 leftlen -= cnt;
3140 if (leftlen == 0) {
3141 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3142 return totcnt;
3143 }
3144 advoffset += cplen;
3145 curbuf += cnt;
3146 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003147#endif /* ADVANSYS_STATS */
3148
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003149 /*
3150 * Display Asc Library dynamic configuration information
3151 * for the board.
3152 */
3153 cp = boardp->prtbuf;
3154 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003155 cplen = asc_prt_asc_board_info(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003156 } else {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003157 cplen = asc_prt_adv_board_info(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003158 }
3159 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3160 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3161 totcnt += cnt;
3162 leftlen -= cnt;
3163 if (leftlen == 0) {
3164 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3165 return totcnt;
3166 }
3167 advoffset += cplen;
3168 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003170 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003172 return totcnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173}
3174#endif /* CONFIG_PROC_FS */
3175
3176/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177 * advansys_info()
3178 *
3179 * Return suitable for printing on the console with the argument
3180 * adapter's configuration information.
3181 *
3182 * Note: The information line should not exceed ASC_INFO_SIZE bytes,
3183 * otherwise the static 'info' array will be overrun.
3184 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003185static const char *advansys_info(struct Scsi_Host *shost)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003187 static char info[ASC_INFO_SIZE];
3188 asc_board_t *boardp;
3189 ASC_DVC_VAR *asc_dvc_varp;
3190 ADV_DVC_VAR *adv_dvc_varp;
3191 char *busname;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003192 char *widename = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003194 boardp = ASC_BOARDP(shost);
3195 if (ASC_NARROW_BOARD(boardp)) {
3196 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
3197 ASC_DBG(1, "advansys_info: begin\n");
3198 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
3199 if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) ==
3200 ASC_IS_ISAPNP) {
3201 busname = "ISA PnP";
3202 } else {
3203 busname = "ISA";
3204 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003205 sprintf(info,
3206 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X",
3207 ASC_VERSION, busname,
3208 (ulong)shost->io_port,
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04003209 (ulong)shost->io_port + ASC_IOADR_GAP - 1,
3210 shost->irq, shost->dma_channel);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003211 } else {
3212 if (asc_dvc_varp->bus_type & ASC_IS_VL) {
3213 busname = "VL";
3214 } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
3215 busname = "EISA";
3216 } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
3217 if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
3218 == ASC_IS_PCI_ULTRA) {
3219 busname = "PCI Ultra";
3220 } else {
3221 busname = "PCI";
3222 }
3223 } else {
3224 busname = "?";
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003225 ASC_PRINT2("advansys_info: board %d: unknown "
3226 "bus type %d\n", boardp->id,
3227 asc_dvc_varp->bus_type);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003228 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003229 sprintf(info,
3230 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X",
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003231 ASC_VERSION, busname, (ulong)shost->io_port,
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04003232 (ulong)shost->io_port + ASC_IOADR_GAP - 1,
3233 shost->irq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003234 }
3235 } else {
3236 /*
3237 * Wide Adapter Information
3238 *
3239 * Memory-mapped I/O is used instead of I/O space to access
3240 * the adapter, but display the I/O Port range. The Memory
3241 * I/O address is displayed through the driver /proc file.
3242 */
3243 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
3244 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003245 widename = "Ultra-Wide";
3246 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003247 widename = "Ultra2-Wide";
3248 } else {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003249 widename = "Ultra3-Wide";
3250 }
3251 sprintf(info,
3252 "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X",
3253 ASC_VERSION, widename, (ulong)adv_dvc_varp->iop_base,
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04003254 (ulong)adv_dvc_varp->iop_base + boardp->asc_n_io_port - 1, shost->irq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003255 }
3256 ASC_ASSERT(strlen(info) < ASC_INFO_SIZE);
3257 ASC_DBG(1, "advansys_info: end\n");
3258 return info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003259}
3260
3261/*
3262 * advansys_queuecommand() - interrupt-driven I/O entrypoint.
3263 *
3264 * This function always returns 0. Command return status is saved
3265 * in the 'scp' result field.
3266 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07003267static int
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003268advansys_queuecommand(struct scsi_cmnd *scp, void (*done) (struct scsi_cmnd *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003270 struct Scsi_Host *shost;
3271 asc_board_t *boardp;
3272 ulong flags;
3273 struct scsi_cmnd *done_scp;
Matthew Wilcoxb6622922007-09-09 08:56:31 -06003274 int asc_res, result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003276 shost = scp->device->host;
3277 boardp = ASC_BOARDP(shost);
3278 ASC_STATS(shost, queuecommand);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003280 /* host_lock taken by mid-level prior to call but need to protect */
3281 /* against own ISR */
3282 spin_lock_irqsave(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003284 /*
3285 * Block new commands while handling a reset or abort request.
3286 */
3287 if (boardp->flags & ASC_HOST_IN_RESET) {
3288 ASC_DBG1(1,
3289 "advansys_queuecommand: scp 0x%lx blocked for reset request\n",
3290 (ulong)scp);
3291 scp->result = HOST_BYTE(DID_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003292
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003293 /*
3294 * Add blocked requests to the board's 'done' queue. The queued
3295 * requests will be completed at the end of the abort or reset
3296 * handling.
3297 */
3298 asc_enqueue(&boardp->done, scp, ASC_BACK);
3299 spin_unlock_irqrestore(&boardp->lock, flags);
3300 return 0;
3301 }
3302
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003303 scp->scsi_done = done;
Matthew Wilcoxb6622922007-09-09 08:56:31 -06003304 asc_res = asc_execute_scsi_cmnd(scp);
3305 switch (asc_res) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003306 case ASC_NOERROR:
3307 break;
3308 case ASC_BUSY:
Matthew Wilcoxb6622922007-09-09 08:56:31 -06003309 result = SCSI_MLQUEUE_HOST_BUSY;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003310 break;
3311 case ASC_ERROR:
3312 default:
3313 done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
3314 /* Interrupts could be enabled here. */
3315 asc_scsi_done_list(done_scp);
3316 break;
3317 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319
Matthew Wilcoxb6622922007-09-09 08:56:31 -06003320 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321}
3322
3323/*
3324 * advansys_reset()
3325 *
3326 * Reset the bus associated with the command 'scp'.
3327 *
3328 * This function runs its own thread. Interrupts must be blocked but
3329 * sleeping is allowed and no locking other than for host structures is
3330 * required. Returns SUCCESS or FAILED.
3331 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003332static int advansys_reset(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003334 struct Scsi_Host *shost;
3335 asc_board_t *boardp;
3336 ASC_DVC_VAR *asc_dvc_varp;
3337 ADV_DVC_VAR *adv_dvc_varp;
3338 ulong flags;
3339 struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
3340 struct scsi_cmnd *tscp, *new_last_scp;
3341 int status;
3342 int ret = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003344 ASC_DBG1(1, "advansys_reset: 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345
3346#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003347 if (scp->device->host != NULL) {
3348 ASC_STATS(scp->device->host, reset);
3349 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003350#endif /* ADVANSYS_STATS */
3351
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003352 if ((shost = scp->device->host) == NULL) {
3353 scp->result = HOST_BYTE(DID_ERROR);
3354 return FAILED;
3355 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003357 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003359 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset started...\n",
3360 boardp->id);
3361 /*
3362 * Check for re-entrancy.
3363 */
3364 spin_lock_irqsave(&boardp->lock, flags);
3365 if (boardp->flags & ASC_HOST_IN_RESET) {
3366 spin_unlock_irqrestore(&boardp->lock, flags);
3367 return FAILED;
3368 }
3369 boardp->flags |= ASC_HOST_IN_RESET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003372 if (ASC_NARROW_BOARD(boardp)) {
3373 /*
3374 * Narrow Board
3375 */
3376 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003378 /*
3379 * Reset the chip and SCSI bus.
3380 */
3381 ASC_DBG(1, "advansys_reset: before AscInitAsc1000Driver()\n");
3382 status = AscInitAsc1000Driver(asc_dvc_varp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003384 /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */
3385 if (asc_dvc_varp->err_code) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003386 ASC_PRINT2("advansys_reset: board %d: SCSI bus reset "
3387 "error: 0x%x\n", boardp->id,
3388 asc_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003389 ret = FAILED;
3390 } else if (status) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003391 ASC_PRINT2("advansys_reset: board %d: SCSI bus reset "
3392 "warning: 0x%x\n", boardp->id, status);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003393 } else {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003394 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset "
3395 "successful.\n", boardp->id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003396 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003398 ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
3399 spin_lock_irqsave(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003401 } else {
3402 /*
3403 * Wide Board
3404 *
3405 * If the suggest reset bus flags are set, then reset the bus.
3406 * Otherwise only reset the device.
3407 */
3408 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003409
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003410 /*
3411 * Reset the target's SCSI bus.
3412 */
3413 ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n");
3414 switch (AdvResetChipAndSB(adv_dvc_varp)) {
3415 case ASC_TRUE:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003416 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset "
3417 "successful.\n", boardp->id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003418 break;
3419 case ASC_FALSE:
3420 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003421 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset "
3422 "error.\n", boardp->id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003423 ret = FAILED;
3424 break;
3425 }
3426 spin_lock_irqsave(&boardp->lock, flags);
3427 (void)AdvISR(adv_dvc_varp);
3428 }
3429 /* Board lock is held. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003431 /*
3432 * Dequeue all board 'done' requests. A pointer to the last request
3433 * is returned in 'last_scp'.
3434 */
3435 done_scp = asc_dequeue_list(&boardp->done, &last_scp, ASC_TID_ALL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003437 /*
3438 * Dequeue all board 'active' requests for all devices and set
3439 * the request status to DID_RESET. A pointer to the last request
3440 * is returned in 'last_scp'.
3441 */
3442 if (done_scp == NULL) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003443 done_scp = asc_dequeue_list(&boardp->active, &last_scp,
3444 ASC_TID_ALL);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003445 for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
3446 tscp->result = HOST_BYTE(DID_RESET);
3447 }
3448 } else {
3449 /* Append to 'done_scp' at the end with 'last_scp'. */
3450 ASC_ASSERT(last_scp != NULL);
3451 last_scp->host_scribble =
3452 (unsigned char *)asc_dequeue_list(&boardp->active,
3453 &new_last_scp,
3454 ASC_TID_ALL);
3455 if (new_last_scp != NULL) {
3456 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
3457 for (tscp = REQPNEXT(last_scp); tscp;
3458 tscp = REQPNEXT(tscp)) {
3459 tscp->result = HOST_BYTE(DID_RESET);
3460 }
3461 last_scp = new_last_scp;
3462 }
3463 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003465 /* Save the time of the most recently completed reset. */
3466 boardp->last_reset = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003468 /* Clear reset flag. */
3469 boardp->flags &= ~ASC_HOST_IN_RESET;
3470 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003472 /*
3473 * Complete all the 'done_scp' requests.
3474 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003475 if (done_scp)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003476 asc_scsi_done_list(done_scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003478 ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003480 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481}
3482
3483/*
3484 * advansys_biosparam()
3485 *
3486 * Translate disk drive geometry if the "BIOS greater than 1 GB"
3487 * support is enabled for a drive.
3488 *
3489 * ip (information pointer) is an int array with the following definition:
3490 * ip[0]: heads
3491 * ip[1]: sectors
3492 * ip[2]: cylinders
3493 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07003494static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003496 sector_t capacity, int ip[])
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003498 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003500 ASC_DBG(1, "advansys_biosparam: begin\n");
3501 ASC_STATS(sdev->host, biosparam);
3502 boardp = ASC_BOARDP(sdev->host);
3503 if (ASC_NARROW_BOARD(boardp)) {
3504 if ((boardp->dvc_var.asc_dvc_var.dvc_cntl &
3505 ASC_CNTL_BIOS_GT_1GB) && capacity > 0x200000) {
3506 ip[0] = 255;
3507 ip[1] = 63;
3508 } else {
3509 ip[0] = 64;
3510 ip[1] = 32;
3511 }
3512 } else {
3513 if ((boardp->dvc_var.adv_dvc_var.bios_ctrl &
3514 BIOS_CTRL_EXTENDED_XLAT) && capacity > 0x200000) {
3515 ip[0] = 255;
3516 ip[1] = 63;
3517 } else {
3518 ip[0] = 64;
3519 ip[1] = 32;
3520 }
3521 }
3522 ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
3523 ASC_DBG(1, "advansys_biosparam: end\n");
3524 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525}
3526
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06003527static struct scsi_host_template advansys_template = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003528 .proc_name = "advansys",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003530 .proc_info = advansys_proc_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531#endif
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003532 .name = "advansys",
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003533 .info = advansys_info,
3534 .queuecommand = advansys_queuecommand,
3535 .eh_bus_reset_handler = advansys_reset,
3536 .bios_param = advansys_biosparam,
3537 .slave_configure = advansys_slave_configure,
3538 /*
3539 * Because the driver may control an ISA adapter 'unchecked_isa_dma'
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06003540 * must be set. The flag will be cleared in advansys_board_found
3541 * for non-ISA adapters.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003542 */
3543 .unchecked_isa_dma = 1,
3544 /*
3545 * All adapters controlled by this driver are capable of large
3546 * scatter-gather lists. According to the mid-level SCSI documentation
3547 * this obviates any performance gain provided by setting
3548 * 'use_clustering'. But empirically while CPU utilization is increased
3549 * by enabling clustering, I/O throughput increases as well.
3550 */
3551 .use_clustering = ENABLE_CLUSTERING,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554/*
3555 * --- Miscellaneous Driver Functions
3556 */
3557
3558/*
3559 * First-level interrupt handler.
3560 *
3561 * 'dev_id' is a pointer to the interrupting adapter's asc_board_t. Because
3562 * all boards are currently checked for interrupts on each interrupt, 'dev_id'
3563 * is not referenced. 'dev_id' could be used to identify an interrupt passed
3564 * to the AdvanSys driver which is for a device sharing an interrupt with
3565 * an AdvanSys adapter.
3566 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003567static irqreturn_t advansys_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568{
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003569 unsigned long flags;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003570 struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
3571 struct scsi_cmnd *new_last_scp;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003572 struct Scsi_Host *shost = dev_id;
3573 asc_board_t *boardp = ASC_BOARDP(shost);
3574 irqreturn_t result = IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003576 ASC_DBG1(2, "advansys_interrupt: boardp 0x%p\n", boardp);
3577 spin_lock_irqsave(&boardp->lock, flags);
3578 if (ASC_NARROW_BOARD(boardp)) {
3579 /*
3580 * Narrow Board
3581 */
3582 if (AscIsIntPending(shost->io_port)) {
3583 result = IRQ_HANDLED;
3584 ASC_STATS(shost, interrupt);
3585 ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
3586 AscISR(&boardp->dvc_var.asc_dvc_var);
3587 }
3588 } else {
3589 /*
3590 * Wide Board
3591 */
3592 ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
3593 if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
3594 result = IRQ_HANDLED;
3595 ASC_STATS(shost, interrupt);
3596 }
3597 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003599 /*
Matthew Wilcoxb6622922007-09-09 08:56:31 -06003600 * Create a list of completed requests.
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003601 *
3602 * If a reset request is being performed for the board, the reset
3603 * handler will complete pending requests after it has completed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003604 */
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003605 if ((boardp->flags & ASC_HOST_IN_RESET) == 0) {
3606 ASC_DBG2(1, "advansys_interrupt: done_scp 0x%p, "
3607 "last_scp 0x%p\n", done_scp, last_scp);
3608
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003609 /*
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003610 * Add to the list of requests that must be completed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003611 *
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003612 * 'done_scp' will always be NULL on the first iteration of
3613 * this loop. 'last_scp' is set at the same time as 'done_scp'.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003614 */
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003615 if (done_scp == NULL) {
3616 done_scp = asc_dequeue_list(&boardp->done,
3617 &last_scp, ASC_TID_ALL);
3618 } else {
3619 ASC_ASSERT(last_scp != NULL);
3620 last_scp->host_scribble =
3621 (unsigned char *)asc_dequeue_list(&boardp->
3622 done,
3623 &new_last_scp,
3624 ASC_TID_ALL);
3625 if (new_last_scp != NULL) {
3626 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
3627 last_scp = new_last_scp;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003628 }
3629 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003630 }
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003631 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003633 /*
3634 * If interrupts were enabled on entry, then they
3635 * are now enabled here.
3636 *
3637 * Complete all requests on the done list.
3638 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003639
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003640 asc_scsi_done_list(done_scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003642 ASC_DBG(1, "advansys_interrupt: end\n");
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003643 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003644}
3645
Matthew Wilcox47d853c2007-07-26 11:41:33 -04003646static void
3647advansys_narrow_slave_configure(struct scsi_device *sdev, ASC_DVC_VAR *asc_dvc)
3648{
3649 ASC_SCSI_BIT_ID_TYPE tid_bit = 1 << sdev->id;
3650 ASC_SCSI_BIT_ID_TYPE orig_use_tagged_qng = asc_dvc->use_tagged_qng;
3651
3652 if (sdev->lun == 0) {
3653 ASC_SCSI_BIT_ID_TYPE orig_init_sdtr = asc_dvc->init_sdtr;
3654 if ((asc_dvc->cfg->sdtr_enable & tid_bit) && sdev->sdtr) {
3655 asc_dvc->init_sdtr |= tid_bit;
3656 } else {
3657 asc_dvc->init_sdtr &= ~tid_bit;
3658 }
3659
3660 if (orig_init_sdtr != asc_dvc->init_sdtr)
3661 AscAsyncFix(asc_dvc, sdev);
3662 }
3663
3664 if (sdev->tagged_supported) {
3665 if (asc_dvc->cfg->cmd_qng_enabled & tid_bit) {
3666 if (sdev->lun == 0) {
3667 asc_dvc->cfg->can_tagged_qng |= tid_bit;
3668 asc_dvc->use_tagged_qng |= tid_bit;
3669 }
3670 scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
3671 asc_dvc->max_dvc_qng[sdev->id]);
3672 }
3673 } else {
3674 if (sdev->lun == 0) {
3675 asc_dvc->cfg->can_tagged_qng &= ~tid_bit;
3676 asc_dvc->use_tagged_qng &= ~tid_bit;
3677 }
3678 scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
3679 }
3680
3681 if ((sdev->lun == 0) &&
3682 (orig_use_tagged_qng != asc_dvc->use_tagged_qng)) {
3683 AscWriteLramByte(asc_dvc->iop_base, ASCV_DISC_ENABLE_B,
3684 asc_dvc->cfg->disc_enable);
3685 AscWriteLramByte(asc_dvc->iop_base, ASCV_USE_TAGGED_QNG_B,
3686 asc_dvc->use_tagged_qng);
3687 AscWriteLramByte(asc_dvc->iop_base, ASCV_CAN_TAGGED_QNG_B,
3688 asc_dvc->cfg->can_tagged_qng);
3689
3690 asc_dvc->max_dvc_qng[sdev->id] =
3691 asc_dvc->cfg->max_tag_qng[sdev->id];
3692 AscWriteLramByte(asc_dvc->iop_base,
3693 (ushort)(ASCV_MAX_DVC_QNG_BEG + sdev->id),
3694 asc_dvc->max_dvc_qng[sdev->id]);
3695 }
3696}
3697
3698/*
3699 * Wide Transfers
3700 *
3701 * If the EEPROM enabled WDTR for the device and the device supports wide
3702 * bus (16 bit) transfers, then turn on the device's 'wdtr_able' bit and
3703 * write the new value to the microcode.
3704 */
3705static void
3706advansys_wide_enable_wdtr(AdvPortAddr iop_base, unsigned short tidmask)
3707{
3708 unsigned short cfg_word;
3709 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
3710 if ((cfg_word & tidmask) != 0)
3711 return;
3712
3713 cfg_word |= tidmask;
3714 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
3715
3716 /*
3717 * Clear the microcode SDTR and WDTR negotiation done indicators for
3718 * the target to cause it to negotiate with the new setting set above.
3719 * WDTR when accepted causes the target to enter asynchronous mode, so
3720 * SDTR must be negotiated.
3721 */
3722 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
3723 cfg_word &= ~tidmask;
3724 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
3725 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
3726 cfg_word &= ~tidmask;
3727 AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
3728}
3729
3730/*
3731 * Synchronous Transfers
3732 *
3733 * If the EEPROM enabled SDTR for the device and the device
3734 * supports synchronous transfers, then turn on the device's
3735 * 'sdtr_able' bit. Write the new value to the microcode.
3736 */
3737static void
3738advansys_wide_enable_sdtr(AdvPortAddr iop_base, unsigned short tidmask)
3739{
3740 unsigned short cfg_word;
3741 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
3742 if ((cfg_word & tidmask) != 0)
3743 return;
3744
3745 cfg_word |= tidmask;
3746 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
3747
3748 /*
3749 * Clear the microcode "SDTR negotiation" done indicator for the
3750 * target to cause it to negotiate with the new setting set above.
3751 */
3752 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
3753 cfg_word &= ~tidmask;
3754 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
3755}
3756
3757/*
3758 * PPR (Parallel Protocol Request) Capable
3759 *
3760 * If the device supports DT mode, then it must be PPR capable.
3761 * The PPR message will be used in place of the SDTR and WDTR
3762 * messages to negotiate synchronous speed and offset, transfer
3763 * width, and protocol options.
3764 */
3765static void advansys_wide_enable_ppr(ADV_DVC_VAR *adv_dvc,
3766 AdvPortAddr iop_base, unsigned short tidmask)
3767{
3768 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able);
3769 adv_dvc->ppr_able |= tidmask;
3770 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able);
3771}
3772
3773static void
3774advansys_wide_slave_configure(struct scsi_device *sdev, ADV_DVC_VAR *adv_dvc)
3775{
3776 AdvPortAddr iop_base = adv_dvc->iop_base;
3777 unsigned short tidmask = 1 << sdev->id;
3778
3779 if (sdev->lun == 0) {
3780 /*
3781 * Handle WDTR, SDTR, and Tag Queuing. If the feature
3782 * is enabled in the EEPROM and the device supports the
3783 * feature, then enable it in the microcode.
3784 */
3785
3786 if ((adv_dvc->wdtr_able & tidmask) && sdev->wdtr)
3787 advansys_wide_enable_wdtr(iop_base, tidmask);
3788 if ((adv_dvc->sdtr_able & tidmask) && sdev->sdtr)
3789 advansys_wide_enable_sdtr(iop_base, tidmask);
3790 if (adv_dvc->chip_type == ADV_CHIP_ASC38C1600 && sdev->ppr)
3791 advansys_wide_enable_ppr(adv_dvc, iop_base, tidmask);
3792
3793 /*
3794 * Tag Queuing is disabled for the BIOS which runs in polled
3795 * mode and would see no benefit from Tag Queuing. Also by
3796 * disabling Tag Queuing in the BIOS devices with Tag Queuing
3797 * bugs will at least work with the BIOS.
3798 */
3799 if ((adv_dvc->tagqng_able & tidmask) &&
3800 sdev->tagged_supported) {
3801 unsigned short cfg_word;
3802 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
3803 cfg_word |= tidmask;
3804 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
3805 cfg_word);
3806 AdvWriteByteLram(iop_base,
3807 ASC_MC_NUMBER_OF_MAX_CMD + sdev->id,
3808 adv_dvc->max_dvc_qng);
3809 }
3810 }
3811
3812 if ((adv_dvc->tagqng_able & tidmask) && sdev->tagged_supported) {
3813 scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
3814 adv_dvc->max_dvc_qng);
3815 } else {
3816 scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
3817 }
3818}
3819
Linus Torvalds1da177e2005-04-16 15:20:36 -07003820/*
3821 * Set the number of commands to queue per device for the
3822 * specified host adapter.
3823 */
Matthew Wilcox47d853c2007-07-26 11:41:33 -04003824static int advansys_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003825{
Matthew Wilcox47d853c2007-07-26 11:41:33 -04003826 asc_board_t *boardp = ASC_BOARDP(sdev->host);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003827 boardp->flags |= ASC_SELECT_QUEUE_DEPTHS;
Matthew Wilcox47d853c2007-07-26 11:41:33 -04003828
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003829 /*
Matthew Wilcox47d853c2007-07-26 11:41:33 -04003830 * Save a pointer to the sdev and set its initial/maximum
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003831 * queue depth. Only save the pointer for a lun0 dev though.
3832 */
Matthew Wilcox47d853c2007-07-26 11:41:33 -04003833 if (sdev->lun == 0)
3834 boardp->device[sdev->id] = sdev;
3835
3836 if (ASC_NARROW_BOARD(boardp))
3837 advansys_narrow_slave_configure(sdev,
3838 &boardp->dvc_var.asc_dvc_var);
3839 else
3840 advansys_wide_slave_configure(sdev,
3841 &boardp->dvc_var.adv_dvc_var);
3842
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003843 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003844}
3845
3846/*
3847 * Complete all requests on the singly linked list pointed
3848 * to by 'scp'.
3849 *
3850 * Interrupts can be enabled on entry.
3851 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003852static void asc_scsi_done_list(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003853{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003854 struct scsi_cmnd *tscp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003855
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003856 ASC_DBG(2, "asc_scsi_done_list: begin\n");
3857 while (scp != NULL) {
3858 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003859
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003860 ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lx\n", (ulong)scp);
3861 tscp = REQPNEXT(scp);
3862 scp->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003863
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003864 boardp = ASC_BOARDP(scp->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003866 if (scp->use_sg)
Matthew Wilcox394dbf32007-07-26 11:56:40 -04003867 dma_unmap_sg(boardp->dev,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003868 (struct scatterlist *)scp->request_buffer,
3869 scp->use_sg, scp->sc_data_direction);
3870 else if (scp->request_bufflen)
Matthew Wilcox394dbf32007-07-26 11:56:40 -04003871 dma_unmap_single(boardp->dev, scp->SCp.dma_handle,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003872 scp->request_bufflen,
3873 scp->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003875 ASC_STATS(scp->device->host, done);
3876 ASC_ASSERT(scp->scsi_done != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003878 scp->scsi_done(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003880 scp = tscp;
3881 }
3882 ASC_DBG(2, "asc_scsi_done_list: done\n");
3883 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884}
3885
3886/*
3887 * Execute a single 'Scsi_Cmnd'.
3888 *
3889 * The function 'done' is called when the request has been completed.
3890 *
3891 * Scsi_Cmnd:
3892 *
3893 * host - board controlling device
3894 * device - device to send command
3895 * target - target of device
3896 * lun - lun of device
3897 * cmd_len - length of SCSI CDB
3898 * cmnd - buffer for SCSI 8, 10, or 12 byte CDB
3899 * use_sg - if non-zero indicates scatter-gather request with use_sg elements
3900 *
3901 * if (use_sg == 0) {
3902 * request_buffer - buffer address for request
3903 * request_bufflen - length of request buffer
3904 * } else {
3905 * request_buffer - pointer to scatterlist structure
3906 * }
3907 *
3908 * sense_buffer - sense command buffer
3909 *
3910 * result (4 bytes of an int):
3911 * Byte Meaning
3912 * 0 SCSI Status Byte Code
3913 * 1 SCSI One Byte Message Code
3914 * 2 Host Error Code
3915 * 3 Mid-Level Error Code
3916 *
3917 * host driver fields:
3918 * SCp - Scsi_Pointer used for command processing status
3919 * scsi_done - used to save caller's done function
3920 * host_scribble - used for pointer to another struct scsi_cmnd
3921 *
3922 * If this function returns ASC_NOERROR the request has been enqueued
3923 * on the board's 'active' queue and will be completed from the
3924 * interrupt handler.
3925 *
3926 * If this function returns ASC_NOERROR the request has been enqueued
3927 * on the board's 'done' queue and must be completed by the caller.
3928 *
Matthew Wilcoxb6622922007-09-09 08:56:31 -06003929 * If ASC_BUSY is returned the request will be returned to the midlayer
3930 * and re-tried later.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003931 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003932static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003933{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003934 asc_board_t *boardp;
3935 ASC_DVC_VAR *asc_dvc_varp;
3936 ADV_DVC_VAR *adv_dvc_varp;
3937 ADV_SCSI_REQ_Q *adv_scsiqp;
3938 struct scsi_device *device;
3939 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003940
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003941 ASC_DBG2(1, "asc_execute_scsi_cmnd: scp 0x%lx, done 0x%lx\n",
3942 (ulong)scp, (ulong)scp->scsi_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003943
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003944 boardp = ASC_BOARDP(scp->device->host);
3945 device = boardp->device[scp->device->id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003946
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003947 if (ASC_NARROW_BOARD(boardp)) {
3948 /*
3949 * Build and execute Narrow Board request.
3950 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003951
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003952 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003953
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003954 /*
3955 * Build Asc Library request structure using the
3956 * global structures 'asc_scsi_req' and 'asc_sg_head'.
3957 *
3958 * If an error is returned, then the request has been
3959 * queued on the board done queue. It will be completed
3960 * by the caller.
3961 *
3962 * asc_build_req() can not return ASC_BUSY.
3963 */
3964 if (asc_build_req(boardp, scp) == ASC_ERROR) {
3965 ASC_STATS(scp->device->host, build_error);
3966 return ASC_ERROR;
3967 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003968
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003969 /*
3970 * Execute the command. If there is no error, add the command
3971 * to the active queue.
3972 */
3973 switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
3974 case ASC_NOERROR:
3975 ASC_STATS(scp->device->host, exe_noerror);
3976 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003977 * Increment monotonically increasing per device
3978 * successful request counter. Wrapping doesn't matter.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003979 */
3980 boardp->reqcnt[scp->device->id]++;
3981 asc_enqueue(&boardp->active, scp, ASC_BACK);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003982 ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue(), "
3983 "ASC_NOERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003984 break;
3985 case ASC_BUSY:
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003986 ASC_STATS(scp->device->host, exe_busy);
3987 break;
3988 case ASC_ERROR:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003989 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
3990 "AscExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
3991 boardp->id, asc_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003992 ASC_STATS(scp->device->host, exe_error);
3993 scp->result = HOST_BYTE(DID_ERROR);
3994 asc_enqueue(&boardp->done, scp, ASC_BACK);
3995 break;
3996 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003997 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
3998 "AscExeScsiQueue() unknown, err_code 0x%x\n",
3999 boardp->id, asc_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004000 ASC_STATS(scp->device->host, exe_unknown);
4001 scp->result = HOST_BYTE(DID_ERROR);
4002 asc_enqueue(&boardp->done, scp, ASC_BACK);
4003 break;
4004 }
4005 } else {
4006 /*
4007 * Build and execute Wide Board request.
4008 */
4009 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004011 /*
4012 * Build and get a pointer to an Adv Library request structure.
4013 *
4014 * If the request is successfully built then send it below,
4015 * otherwise return with an error.
4016 */
4017 switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
4018 case ASC_NOERROR:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004019 ASC_DBG(3, "asc_execute_scsi_cmnd: adv_build_req "
4020 "ASC_NOERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004021 break;
4022 case ASC_BUSY:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004023 ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req "
4024 "ASC_BUSY\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004025 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004026 * The asc_stats fields 'adv_build_noreq' and
4027 * 'adv_build_nosg' count wide board busy conditions.
4028 * They are updated in adv_build_req and
4029 * adv_get_sglist, respectively.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004030 */
4031 return ASC_BUSY;
4032 case ASC_ERROR:
4033 /*
4034 * If an error is returned, then the request has been
4035 * queued on the board done queue. It will be completed
4036 * by the caller.
4037 */
4038 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004039 ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req "
4040 "ASC_ERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004041 ASC_STATS(scp->device->host, build_error);
4042 return ASC_ERROR;
4043 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004045 /*
4046 * Execute the command. If there is no error, add the command
4047 * to the active queue.
4048 */
4049 switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) {
4050 case ASC_NOERROR:
4051 ASC_STATS(scp->device->host, exe_noerror);
4052 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004053 * Increment monotonically increasing per device
4054 * successful request counter. Wrapping doesn't matter.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004055 */
4056 boardp->reqcnt[scp->device->id]++;
4057 asc_enqueue(&boardp->active, scp, ASC_BACK);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004058 ASC_DBG(1, "asc_execute_scsi_cmnd: AdvExeScsiQueue(), "
4059 "ASC_NOERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004060 break;
4061 case ASC_BUSY:
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004062 ASC_STATS(scp->device->host, exe_busy);
4063 break;
4064 case ASC_ERROR:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004065 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
4066 "AdvExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
4067 boardp->id, adv_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004068 ASC_STATS(scp->device->host, exe_error);
4069 scp->result = HOST_BYTE(DID_ERROR);
4070 asc_enqueue(&boardp->done, scp, ASC_BACK);
4071 break;
4072 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004073 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
4074 "AdvExeScsiQueue() unknown, err_code 0x%x\n",
4075 boardp->id, adv_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004076 ASC_STATS(scp->device->host, exe_unknown);
4077 scp->result = HOST_BYTE(DID_ERROR);
4078 asc_enqueue(&boardp->done, scp, ASC_BACK);
4079 break;
4080 }
4081 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004082
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004083 ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
4084 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004085}
4086
4087/*
4088 * Build a request structure for the Asc Library (Narrow Board).
4089 *
4090 * The global structures 'asc_scsi_q' and 'asc_sg_head' are
4091 * used to build the request.
4092 *
4093 * If an error occurs, then queue the request on the board done
4094 * queue and return ASC_ERROR.
4095 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004096static int asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004097{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004098 /*
4099 * Mutually exclusive access is required to 'asc_scsi_q' and
4100 * 'asc_sg_head' until after the request is started.
4101 */
4102 memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004103
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004104 /*
4105 * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'.
4106 */
4107 asc_scsi_q.q2.srb_ptr = ASC_VADDR_TO_U32(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004108
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004109 /*
4110 * Build the ASC_SCSI_Q request.
4111 *
4112 * For narrow boards a CDB length maximum of 12 bytes
4113 * is supported.
4114 */
4115 if (scp->cmd_len > ASC_MAX_CDB_LEN) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004116 ASC_PRINT3("asc_build_req: board %d: cmd_len %d > "
4117 "ASC_MAX_CDB_LEN %d\n", boardp->id, scp->cmd_len,
4118 ASC_MAX_CDB_LEN);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004119 scp->result = HOST_BYTE(DID_ERROR);
4120 asc_enqueue(&boardp->done, scp, ASC_BACK);
4121 return ASC_ERROR;
4122 }
4123 asc_scsi_q.cdbptr = &scp->cmnd[0];
4124 asc_scsi_q.q2.cdb_len = scp->cmd_len;
4125 asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id);
4126 asc_scsi_q.q1.target_lun = scp->device->lun;
4127 asc_scsi_q.q2.target_ix =
4128 ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
4129 asc_scsi_q.q1.sense_addr =
4130 cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
4131 asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004132
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004133 /*
4134 * If there are any outstanding requests for the current target,
4135 * then every 255th request send an ORDERED request. This heuristic
4136 * tries to retain the benefit of request sorting while preventing
4137 * request starvation. 255 is the max number of tags or pending commands
4138 * a device may have outstanding.
4139 *
4140 * The request count is incremented below for every successfully
4141 * started request.
4142 *
4143 */
4144 if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->device->id] > 0) &&
4145 (boardp->reqcnt[scp->device->id] % 255) == 0) {
4146 asc_scsi_q.q2.tag_code = MSG_ORDERED_TAG;
4147 } else {
4148 asc_scsi_q.q2.tag_code = MSG_SIMPLE_TAG;
4149 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004151 /*
4152 * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
4153 * buffer command.
4154 */
4155 if (scp->use_sg == 0) {
4156 /*
4157 * CDB request of single contiguous buffer.
4158 */
4159 ASC_STATS(scp->device->host, cont_cnt);
4160 scp->SCp.dma_handle = scp->request_bufflen ?
Matthew Wilcox394dbf32007-07-26 11:56:40 -04004161 dma_map_single(boardp->dev, scp->request_buffer,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004162 scp->request_bufflen,
4163 scp->sc_data_direction) : 0;
4164 asc_scsi_q.q1.data_addr = cpu_to_le32(scp->SCp.dma_handle);
4165 asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen);
4166 ASC_STATS_ADD(scp->device->host, cont_xfer,
4167 ASC_CEILING(scp->request_bufflen, 512));
4168 asc_scsi_q.q1.sg_queue_cnt = 0;
4169 asc_scsi_q.sg_head = NULL;
4170 } else {
4171 /*
4172 * CDB scatter-gather request list.
4173 */
4174 int sgcnt;
4175 int use_sg;
4176 struct scatterlist *slp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004178 slp = (struct scatterlist *)scp->request_buffer;
Matthew Wilcox394dbf32007-07-26 11:56:40 -04004179 use_sg = dma_map_sg(boardp->dev, slp, scp->use_sg,
4180 scp->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004182 if (use_sg > scp->device->host->sg_tablesize) {
Matthew Wilcox394dbf32007-07-26 11:56:40 -04004183 ASC_PRINT3("asc_build_req: board %d: use_sg %d > "
4184 "sg_tablesize %d\n", boardp->id, use_sg,
4185 scp->device->host->sg_tablesize);
4186 dma_unmap_sg(boardp->dev, slp, scp->use_sg,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004187 scp->sc_data_direction);
4188 scp->result = HOST_BYTE(DID_ERROR);
4189 asc_enqueue(&boardp->done, scp, ASC_BACK);
4190 return ASC_ERROR;
4191 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004193 ASC_STATS(scp->device->host, sg_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004195 /*
4196 * Use global ASC_SG_HEAD structure and set the ASC_SCSI_Q
4197 * structure to point to it.
4198 */
4199 memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004200
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004201 asc_scsi_q.q1.cntl |= QC_SG_HEAD;
4202 asc_scsi_q.sg_head = &asc_sg_head;
4203 asc_scsi_q.q1.data_cnt = 0;
4204 asc_scsi_q.q1.data_addr = 0;
4205 /* This is a byte value, otherwise it would need to be swapped. */
4206 asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = use_sg;
4207 ASC_STATS_ADD(scp->device->host, sg_elem,
4208 asc_sg_head.entry_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004210 /*
4211 * Convert scatter-gather list into ASC_SG_HEAD list.
4212 */
4213 for (sgcnt = 0; sgcnt < use_sg; sgcnt++, slp++) {
4214 asc_sg_head.sg_list[sgcnt].addr =
4215 cpu_to_le32(sg_dma_address(slp));
4216 asc_sg_head.sg_list[sgcnt].bytes =
4217 cpu_to_le32(sg_dma_len(slp));
4218 ASC_STATS_ADD(scp->device->host, sg_xfer,
4219 ASC_CEILING(sg_dma_len(slp), 512));
4220 }
4221 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004223 ASC_DBG_PRT_ASC_SCSI_Q(2, &asc_scsi_q);
4224 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004226 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227}
4228
4229/*
4230 * Build a request structure for the Adv Library (Wide Board).
4231 *
4232 * If an adv_req_t can not be allocated to issue the request,
4233 * then return ASC_BUSY. If an error occurs, then return ASC_ERROR.
4234 *
4235 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the
4236 * microcode for DMA addresses or math operations are byte swapped
4237 * to little-endian order.
4238 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004239static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240adv_build_req(asc_board_t *boardp, struct scsi_cmnd *scp,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004241 ADV_SCSI_REQ_Q **adv_scsiqpp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004242{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004243 adv_req_t *reqp;
4244 ADV_SCSI_REQ_Q *scsiqp;
4245 int i;
4246 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004247
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004248 /*
4249 * Allocate an adv_req_t structure from the board to execute
4250 * the command.
4251 */
4252 if (boardp->adv_reqp == NULL) {
4253 ASC_DBG(1, "adv_build_req: no free adv_req_t\n");
4254 ASC_STATS(scp->device->host, adv_build_noreq);
4255 return ASC_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004256 } else {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004257 reqp = boardp->adv_reqp;
4258 boardp->adv_reqp = reqp->next_reqp;
4259 reqp->next_reqp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004262 /*
4263 * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
4264 */
4265 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004266
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004267 /*
4268 * Initialize the structure.
4269 */
4270 scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004271
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004272 /*
4273 * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
4274 */
4275 scsiqp->srb_ptr = ASC_VADDR_TO_U32(reqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004276
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004277 /*
4278 * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure.
4279 */
4280 reqp->cmndp = scp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004282 /*
4283 * Build the ADV_SCSI_REQ_Q request.
4284 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004285
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004286 /*
4287 * Set CDB length and copy it to the request structure.
4288 * For wide boards a CDB length maximum of 16 bytes
4289 * is supported.
4290 */
4291 if (scp->cmd_len > ADV_MAX_CDB_LEN) {
4292 ASC_PRINT3
4293 ("adv_build_req: board %d: cmd_len %d > ADV_MAX_CDB_LEN %d\n",
4294 boardp->id, scp->cmd_len, ADV_MAX_CDB_LEN);
4295 scp->result = HOST_BYTE(DID_ERROR);
4296 asc_enqueue(&boardp->done, scp, ASC_BACK);
4297 return ASC_ERROR;
4298 }
4299 scsiqp->cdb_len = scp->cmd_len;
4300 /* Copy first 12 CDB bytes to cdb[]. */
4301 for (i = 0; i < scp->cmd_len && i < 12; i++) {
4302 scsiqp->cdb[i] = scp->cmnd[i];
4303 }
4304 /* Copy last 4 CDB bytes, if present, to cdb16[]. */
4305 for (; i < scp->cmd_len; i++) {
4306 scsiqp->cdb16[i - 12] = scp->cmnd[i];
4307 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004309 scsiqp->target_id = scp->device->id;
4310 scsiqp->target_lun = scp->device->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004312 scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
4313 scsiqp->sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004315 /*
4316 * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather
4317 * buffer command.
4318 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004320 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
4321 scsiqp->vdata_addr = scp->request_buffer;
4322 scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer));
4323
4324 if (scp->use_sg == 0) {
4325 /*
4326 * CDB request of single contiguous buffer.
4327 */
4328 reqp->sgblkp = NULL;
4329 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
4330 if (scp->request_bufflen) {
4331 scsiqp->vdata_addr = scp->request_buffer;
4332 scp->SCp.dma_handle =
Matthew Wilcox394dbf32007-07-26 11:56:40 -04004333 dma_map_single(boardp->dev, scp->request_buffer,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004334 scp->request_bufflen,
4335 scp->sc_data_direction);
4336 } else {
4337 scsiqp->vdata_addr = NULL;
4338 scp->SCp.dma_handle = 0;
4339 }
4340 scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle);
4341 scsiqp->sg_list_ptr = NULL;
4342 scsiqp->sg_real_addr = 0;
4343 ASC_STATS(scp->device->host, cont_cnt);
4344 ASC_STATS_ADD(scp->device->host, cont_xfer,
4345 ASC_CEILING(scp->request_bufflen, 512));
4346 } else {
4347 /*
4348 * CDB scatter-gather request list.
4349 */
4350 struct scatterlist *slp;
4351 int use_sg;
4352
4353 slp = (struct scatterlist *)scp->request_buffer;
Matthew Wilcox394dbf32007-07-26 11:56:40 -04004354 use_sg = dma_map_sg(boardp->dev, slp, scp->use_sg,
4355 scp->sc_data_direction);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004356
4357 if (use_sg > ADV_MAX_SG_LIST) {
Matthew Wilcox394dbf32007-07-26 11:56:40 -04004358 ASC_PRINT3("adv_build_req: board %d: use_sg %d > "
4359 "ADV_MAX_SG_LIST %d\n", boardp->id, use_sg,
4360 scp->device->host->sg_tablesize);
4361 dma_unmap_sg(boardp->dev, slp, scp->use_sg,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004362 scp->sc_data_direction);
4363 scp->result = HOST_BYTE(DID_ERROR);
4364 asc_enqueue(&boardp->done, scp, ASC_BACK);
4365
4366 /*
Matthew Wilcox394dbf32007-07-26 11:56:40 -04004367 * Free the 'adv_req_t' structure by adding it back
4368 * to the board free list.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004369 */
4370 reqp->next_reqp = boardp->adv_reqp;
4371 boardp->adv_reqp = reqp;
4372
4373 return ASC_ERROR;
4374 }
4375
Matthew Wilcox394dbf32007-07-26 11:56:40 -04004376 ret = adv_get_sglist(boardp, reqp, scp, use_sg);
4377 if (ret != ADV_SUCCESS) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004378 /*
Matthew Wilcox394dbf32007-07-26 11:56:40 -04004379 * Free the adv_req_t structure by adding it back to
4380 * the board free list.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004381 */
4382 reqp->next_reqp = boardp->adv_reqp;
4383 boardp->adv_reqp = reqp;
4384
4385 return ret;
4386 }
4387
4388 ASC_STATS(scp->device->host, sg_cnt);
4389 ASC_STATS_ADD(scp->device->host, sg_elem, use_sg);
4390 }
4391
4392 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
4393 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
4394
4395 *adv_scsiqpp = scsiqp;
4396
4397 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004398}
4399
4400/*
4401 * Build scatter-gather list for Adv Library (Wide Board).
4402 *
4403 * Additional ADV_SG_BLOCK structures will need to be allocated
4404 * if the total number of scatter-gather elements exceeds
4405 * NO_OF_SG_PER_BLOCK (15). The ADV_SG_BLOCK structures are
4406 * assumed to be physically contiguous.
4407 *
4408 * Return:
4409 * ADV_SUCCESS(1) - SG List successfully created
4410 * ADV_ERROR(-1) - SG List creation failed
4411 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004412static int
4413adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, struct scsi_cmnd *scp,
4414 int use_sg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004416 adv_sgblk_t *sgblkp;
4417 ADV_SCSI_REQ_Q *scsiqp;
4418 struct scatterlist *slp;
4419 int sg_elem_cnt;
4420 ADV_SG_BLOCK *sg_block, *prev_sg_block;
4421 ADV_PADDR sg_block_paddr;
4422 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004423
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004424 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
4425 slp = (struct scatterlist *)scp->request_buffer;
4426 sg_elem_cnt = use_sg;
4427 prev_sg_block = NULL;
4428 reqp->sgblkp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004430 do {
4431 /*
4432 * Allocate a 'adv_sgblk_t' structure from the board free
4433 * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK
4434 * (15) scatter-gather elements.
4435 */
4436 if ((sgblkp = boardp->adv_sgblkp) == NULL) {
4437 ASC_DBG(1, "adv_get_sglist: no free adv_sgblk_t\n");
4438 ASC_STATS(scp->device->host, adv_build_nosg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004439
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004440 /*
4441 * Allocation failed. Free 'adv_sgblk_t' structures already
4442 * allocated for the request.
4443 */
4444 while ((sgblkp = reqp->sgblkp) != NULL) {
4445 /* Remove 'sgblkp' from the request list. */
4446 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004448 /* Add 'sgblkp' to the board free list. */
4449 sgblkp->next_sgblkp = boardp->adv_sgblkp;
4450 boardp->adv_sgblkp = sgblkp;
4451 }
4452 return ASC_BUSY;
4453 } else {
4454 /* Complete 'adv_sgblk_t' board allocation. */
4455 boardp->adv_sgblkp = sgblkp->next_sgblkp;
4456 sgblkp->next_sgblkp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004457
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004458 /*
4459 * Get 8 byte aligned virtual and physical addresses for
4460 * the allocated ADV_SG_BLOCK structure.
4461 */
4462 sg_block =
4463 (ADV_SG_BLOCK *)ADV_8BALIGN(&sgblkp->sg_block);
4464 sg_block_paddr = virt_to_bus(sg_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004465
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004466 /*
4467 * Check if this is the first 'adv_sgblk_t' for the request.
4468 */
4469 if (reqp->sgblkp == NULL) {
4470 /* Request's first scatter-gather block. */
4471 reqp->sgblkp = sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004472
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004473 /*
4474 * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical
4475 * address pointers.
4476 */
4477 scsiqp->sg_list_ptr = sg_block;
4478 scsiqp->sg_real_addr =
4479 cpu_to_le32(sg_block_paddr);
4480 } else {
4481 /* Request's second or later scatter-gather block. */
4482 sgblkp->next_sgblkp = reqp->sgblkp;
4483 reqp->sgblkp = sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004485 /*
4486 * Point the previous ADV_SG_BLOCK structure to
4487 * the newly allocated ADV_SG_BLOCK structure.
4488 */
4489 ASC_ASSERT(prev_sg_block != NULL);
4490 prev_sg_block->sg_ptr =
4491 cpu_to_le32(sg_block_paddr);
4492 }
4493 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004495 for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) {
4496 sg_block->sg_list[i].sg_addr =
4497 cpu_to_le32(sg_dma_address(slp));
4498 sg_block->sg_list[i].sg_count =
4499 cpu_to_le32(sg_dma_len(slp));
4500 ASC_STATS_ADD(scp->device->host, sg_xfer,
4501 ASC_CEILING(sg_dma_len(slp), 512));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004503 if (--sg_elem_cnt == 0) { /* Last ADV_SG_BLOCK and scatter-gather entry. */
4504 sg_block->sg_cnt = i + 1;
4505 sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */
4506 return ADV_SUCCESS;
4507 }
4508 slp++;
4509 }
4510 sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
4511 prev_sg_block = sg_block;
4512 }
4513 while (1);
4514 /* NOTREACHED */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004515}
4516
4517/*
4518 * asc_isr_callback() - Second Level Interrupt Handler called by AscISR().
4519 *
4520 * Interrupt callback function for the Narrow SCSI Asc Library.
4521 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004522static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004523{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004524 asc_board_t *boardp;
4525 struct scsi_cmnd *scp;
4526 struct Scsi_Host *shost;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004528 ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp 0x%lx, qdonep 0x%lx\n",
4529 (ulong)asc_dvc_varp, (ulong)qdonep);
4530 ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004531
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004532 /*
4533 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
4534 * command that has been completed.
4535 */
4536 scp = (struct scsi_cmnd *)ASC_U32_TO_VADDR(qdonep->d2.srb_ptr);
4537 ASC_DBG1(1, "asc_isr_callback: scp 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004538
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004539 if (scp == NULL) {
4540 ASC_PRINT("asc_isr_callback: scp is NULL\n");
4541 return;
4542 }
4543 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004545 shost = scp->device->host;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004546 ASC_STATS(shost, callback);
4547 ASC_DBG1(1, "asc_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004548
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004549 /*
4550 * If the request isn't found on the active queue, it may
4551 * have been removed to handle a reset request.
4552 * Display a message and return.
4553 */
4554 boardp = ASC_BOARDP(shost);
4555 ASC_ASSERT(asc_dvc_varp == &boardp->dvc_var.asc_dvc_var);
4556 if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
4557 ASC_PRINT2
4558 ("asc_isr_callback: board %d: scp 0x%lx not on active queue\n",
4559 boardp->id, (ulong)scp);
4560 return;
4561 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004563 /*
4564 * 'qdonep' contains the command's ending status.
4565 */
4566 switch (qdonep->d3.done_stat) {
4567 case QD_NO_ERROR:
4568 ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n");
4569 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004571 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004572 * Check for an underrun condition.
4573 *
4574 * If there was no error and an underrun condition, then
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004575 * return the number of underrun bytes.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004576 */
4577 if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 &&
4578 qdonep->remain_bytes <= scp->request_bufflen) {
4579 ASC_DBG1(1,
4580 "asc_isr_callback: underrun condition %u bytes\n",
4581 (unsigned)qdonep->remain_bytes);
4582 scp->resid = qdonep->remain_bytes;
4583 }
4584 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004586 case QD_WITH_ERROR:
4587 ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n");
4588 switch (qdonep->d3.host_stat) {
4589 case QHSTA_NO_ERROR:
4590 if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
4591 ASC_DBG(2,
4592 "asc_isr_callback: SAM_STAT_CHECK_CONDITION\n");
4593 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
4594 sizeof(scp->sense_buffer));
4595 /*
4596 * Note: The 'status_byte()' macro used by target drivers
4597 * defined in scsi.h shifts the status byte returned by
4598 * host drivers right by 1 bit. This is why target drivers
4599 * also use right shifted status byte definitions. For
4600 * instance target drivers use CHECK_CONDITION, defined to
4601 * 0x1, instead of the SCSI defined check condition value
4602 * of 0x2. Host drivers are supposed to return the status
4603 * byte as it is defined by SCSI.
4604 */
4605 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
4606 STATUS_BYTE(qdonep->d3.scsi_stat);
4607 } else {
4608 scp->result = STATUS_BYTE(qdonep->d3.scsi_stat);
4609 }
4610 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004612 default:
4613 /* QHSTA error occurred */
4614 ASC_DBG1(1, "asc_isr_callback: host_stat 0x%x\n",
4615 qdonep->d3.host_stat);
4616 scp->result = HOST_BYTE(DID_BAD_TARGET);
4617 break;
4618 }
4619 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004621 case QD_ABORTED_BY_HOST:
4622 ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOST\n");
4623 scp->result =
4624 HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.
4625 scsi_msg) |
4626 STATUS_BYTE(qdonep->d3.scsi_stat);
4627 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004628
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004629 default:
4630 ASC_DBG1(1, "asc_isr_callback: done_stat 0x%x\n",
4631 qdonep->d3.done_stat);
4632 scp->result =
4633 HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.
4634 scsi_msg) |
4635 STATUS_BYTE(qdonep->d3.scsi_stat);
4636 break;
4637 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004639 /*
4640 * If the 'init_tidmask' bit isn't already set for the target and the
4641 * current request finished normally, then set the bit for the target
4642 * to indicate that a device is present.
4643 */
4644 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
4645 qdonep->d3.done_stat == QD_NO_ERROR &&
4646 qdonep->d3.host_stat == QHSTA_NO_ERROR) {
4647 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
4648 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004649
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004650 /*
4651 * Because interrupts may be enabled by the 'struct scsi_cmnd' done
4652 * function, add the command to the end of the board's done queue.
4653 * The done function for the command will be called from
4654 * advansys_interrupt().
4655 */
4656 asc_enqueue(&boardp->done, scp, ASC_BACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004658 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004659}
4660
4661/*
4662 * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR().
4663 *
4664 * Callback function for the Wide SCSI Adv Library.
4665 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004666static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004667{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004668 asc_board_t *boardp;
4669 adv_req_t *reqp;
4670 adv_sgblk_t *sgblkp;
4671 struct scsi_cmnd *scp;
4672 struct Scsi_Host *shost;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004673 ADV_DCNT resid_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004674
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004675 ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp 0x%lx, scsiqp 0x%lx\n",
4676 (ulong)adv_dvc_varp, (ulong)scsiqp);
4677 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004678
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004679 /*
4680 * Get the adv_req_t structure for the command that has been
4681 * completed. The adv_req_t structure actually contains the
4682 * completed ADV_SCSI_REQ_Q structure.
4683 */
4684 reqp = (adv_req_t *)ADV_U32_TO_VADDR(scsiqp->srb_ptr);
4685 ASC_DBG1(1, "adv_isr_callback: reqp 0x%lx\n", (ulong)reqp);
4686 if (reqp == NULL) {
4687 ASC_PRINT("adv_isr_callback: reqp is NULL\n");
4688 return;
4689 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004690
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004691 /*
4692 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
4693 * command that has been completed.
4694 *
4695 * Note: The adv_req_t request structure and adv_sgblk_t structure,
4696 * if any, are dropped, because a board structure pointer can not be
4697 * determined.
4698 */
4699 scp = reqp->cmndp;
4700 ASC_DBG1(1, "adv_isr_callback: scp 0x%lx\n", (ulong)scp);
4701 if (scp == NULL) {
4702 ASC_PRINT
4703 ("adv_isr_callback: scp is NULL; adv_req_t dropped.\n");
4704 return;
4705 }
4706 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004707
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004708 shost = scp->device->host;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004709 ASC_STATS(shost, callback);
4710 ASC_DBG1(1, "adv_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004711
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004712 /*
4713 * If the request isn't found on the active queue, it may have been
4714 * removed to handle a reset request. Display a message and return.
4715 *
4716 * Note: Because the structure may still be in use don't attempt
4717 * to free the adv_req_t and adv_sgblk_t, if any, structures.
4718 */
4719 boardp = ASC_BOARDP(shost);
4720 ASC_ASSERT(adv_dvc_varp == &boardp->dvc_var.adv_dvc_var);
4721 if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
4722 ASC_PRINT2
4723 ("adv_isr_callback: board %d: scp 0x%lx not on active queue\n",
4724 boardp->id, (ulong)scp);
4725 return;
4726 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004727
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004728 /*
4729 * 'done_status' contains the command's ending status.
4730 */
4731 switch (scsiqp->done_status) {
4732 case QD_NO_ERROR:
4733 ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n");
4734 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004735
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004736 /*
4737 * Check for an underrun condition.
4738 *
4739 * If there was no error and an underrun condition, then
4740 * then return the number of underrun bytes.
4741 */
4742 resid_cnt = le32_to_cpu(scsiqp->data_cnt);
4743 if (scp->request_bufflen != 0 && resid_cnt != 0 &&
4744 resid_cnt <= scp->request_bufflen) {
4745 ASC_DBG1(1,
4746 "adv_isr_callback: underrun condition %lu bytes\n",
4747 (ulong)resid_cnt);
4748 scp->resid = resid_cnt;
4749 }
4750 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004751
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004752 case QD_WITH_ERROR:
4753 ASC_DBG(2, "adv_isr_callback: QD_WITH_ERROR\n");
4754 switch (scsiqp->host_status) {
4755 case QHSTA_NO_ERROR:
4756 if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
4757 ASC_DBG(2,
4758 "adv_isr_callback: SAM_STAT_CHECK_CONDITION\n");
4759 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
4760 sizeof(scp->sense_buffer));
4761 /*
4762 * Note: The 'status_byte()' macro used by target drivers
4763 * defined in scsi.h shifts the status byte returned by
4764 * host drivers right by 1 bit. This is why target drivers
4765 * also use right shifted status byte definitions. For
4766 * instance target drivers use CHECK_CONDITION, defined to
4767 * 0x1, instead of the SCSI defined check condition value
4768 * of 0x2. Host drivers are supposed to return the status
4769 * byte as it is defined by SCSI.
4770 */
4771 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
4772 STATUS_BYTE(scsiqp->scsi_status);
4773 } else {
4774 scp->result = STATUS_BYTE(scsiqp->scsi_status);
4775 }
4776 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004777
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004778 default:
4779 /* Some other QHSTA error occurred. */
4780 ASC_DBG1(1, "adv_isr_callback: host_status 0x%x\n",
4781 scsiqp->host_status);
4782 scp->result = HOST_BYTE(DID_BAD_TARGET);
4783 break;
4784 }
4785 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004786
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004787 case QD_ABORTED_BY_HOST:
4788 ASC_DBG(1, "adv_isr_callback: QD_ABORTED_BY_HOST\n");
4789 scp->result =
4790 HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status);
4791 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004792
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004793 default:
4794 ASC_DBG1(1, "adv_isr_callback: done_status 0x%x\n",
4795 scsiqp->done_status);
4796 scp->result =
4797 HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status);
4798 break;
4799 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004801 /*
4802 * If the 'init_tidmask' bit isn't already set for the target and the
4803 * current request finished normally, then set the bit for the target
4804 * to indicate that a device is present.
4805 */
4806 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
4807 scsiqp->done_status == QD_NO_ERROR &&
4808 scsiqp->host_status == QHSTA_NO_ERROR) {
4809 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
4810 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004811
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004812 /*
4813 * Because interrupts may be enabled by the 'struct scsi_cmnd' done
4814 * function, add the command to the end of the board's done queue.
4815 * The done function for the command will be called from
4816 * advansys_interrupt().
4817 */
4818 asc_enqueue(&boardp->done, scp, ASC_BACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004819
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004820 /*
4821 * Free all 'adv_sgblk_t' structures allocated for the request.
4822 */
4823 while ((sgblkp = reqp->sgblkp) != NULL) {
4824 /* Remove 'sgblkp' from the request list. */
4825 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004826
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004827 /* Add 'sgblkp' to the board free list. */
4828 sgblkp->next_sgblkp = boardp->adv_sgblkp;
4829 boardp->adv_sgblkp = sgblkp;
4830 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004832 /*
4833 * Free the adv_req_t structure used with the command by adding
4834 * it back to the board free list.
4835 */
4836 reqp->next_reqp = boardp->adv_reqp;
4837 boardp->adv_reqp = reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004839 ASC_DBG(1, "adv_isr_callback: done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004841 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004842}
4843
4844/*
4845 * adv_async_callback() - Adv Library asynchronous event callback function.
4846 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004847static void adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004848{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004849 switch (code) {
4850 case ADV_ASYNC_SCSI_BUS_RESET_DET:
4851 /*
4852 * The firmware detected a SCSI Bus reset.
4853 */
4854 ASC_DBG(0,
4855 "adv_async_callback: ADV_ASYNC_SCSI_BUS_RESET_DET\n");
4856 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004857
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004858 case ADV_ASYNC_RDMA_FAILURE:
4859 /*
4860 * Handle RDMA failure by resetting the SCSI Bus and
4861 * possibly the chip if it is unresponsive. Log the error
4862 * with a unique code.
4863 */
4864 ASC_DBG(0, "adv_async_callback: ADV_ASYNC_RDMA_FAILURE\n");
4865 AdvResetChipAndSB(adv_dvc_varp);
4866 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004867
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004868 case ADV_HOST_SCSI_BUS_RESET:
4869 /*
4870 * Host generated SCSI bus reset occurred.
4871 */
4872 ASC_DBG(0, "adv_async_callback: ADV_HOST_SCSI_BUS_RESET\n");
4873 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004874
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004875 default:
4876 ASC_DBG1(0, "DvcAsyncCallBack: unknown code 0x%x\n", code);
4877 break;
4878 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879}
4880
4881/*
4882 * Add a 'REQP' to the end of specified queue. Set 'tidmask'
4883 * to indicate a command is queued for the device.
4884 *
4885 * 'flag' may be either ASC_FRONT or ASC_BACK.
4886 *
4887 * 'REQPNEXT(reqp)' returns reqp's next pointer.
4888 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004889static void asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004890{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004891 int tid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004892
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004893 ASC_DBG3(3, "asc_enqueue: ascq 0x%lx, reqp 0x%lx, flag %d\n",
4894 (ulong)ascq, (ulong)reqp, flag);
4895 ASC_ASSERT(reqp != NULL);
4896 ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
4897 tid = REQPTID(reqp);
4898 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
4899 if (flag == ASC_FRONT) {
4900 reqp->host_scribble = (unsigned char *)ascq->q_first[tid];
4901 ascq->q_first[tid] = reqp;
4902 /* If the queue was empty, set the last pointer. */
4903 if (ascq->q_last[tid] == NULL) {
4904 ascq->q_last[tid] = reqp;
4905 }
4906 } else { /* ASC_BACK */
4907 if (ascq->q_last[tid] != NULL) {
4908 ascq->q_last[tid]->host_scribble =
4909 (unsigned char *)reqp;
4910 }
4911 ascq->q_last[tid] = reqp;
4912 reqp->host_scribble = NULL;
4913 /* If the queue was empty, set the first pointer. */
4914 if (ascq->q_first[tid] == NULL) {
4915 ascq->q_first[tid] = reqp;
4916 }
4917 }
4918 /* The queue has at least one entry, set its bit. */
4919 ascq->q_tidmask |= ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004920#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004921 /* Maintain request queue statistics. */
4922 ascq->q_tot_cnt[tid]++;
4923 ascq->q_cur_cnt[tid]++;
4924 if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) {
4925 ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid];
4926 ASC_DBG2(2, "asc_enqueue: new q_max_cnt[%d] %d\n",
4927 tid, ascq->q_max_cnt[tid]);
4928 }
4929 REQPTIME(reqp) = REQTIMESTAMP();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004930#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004931 ASC_DBG1(3, "asc_enqueue: reqp 0x%lx\n", (ulong)reqp);
4932 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004933}
4934
4935/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004936 * Return a pointer to a singly linked list of all the requests queued
4937 * for 'tid' on the 'asc_queue_t' pointed to by 'ascq'.
4938 *
4939 * If 'lastpp' is not NULL, '*lastpp' will be set to point to the
4940 * the last request returned in the singly linked list.
4941 *
4942 * 'tid' should either be a valid target id or if it is ASC_TID_ALL,
4943 * then all queued requests are concatenated into one list and
4944 * returned.
4945 *
4946 * Note: If 'lastpp' is used to append a new list to the end of
4947 * an old list, only change the old list last pointer if '*lastpp'
4948 * (or the function return value) is not NULL, i.e. use a temporary
4949 * variable for 'lastpp' and check its value after the function return
4950 * before assigning it to the list last pointer.
4951 *
4952 * Unfortunately collecting queuing time statistics adds overhead to
4953 * the function that isn't inherent to the function's algorithm.
4954 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004955static REQP asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004956{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004957 REQP firstp, lastp;
4958 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004959
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004960 ASC_DBG2(3, "asc_dequeue_list: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
4961 ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004962
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004963 /*
4964 * If 'tid' is not ASC_TID_ALL, return requests only for
4965 * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all
4966 * requests for all tids.
4967 */
4968 if (tid != ASC_TID_ALL) {
4969 /* Return all requests for the specified 'tid'. */
4970 if ((ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)) == 0) {
4971 /* List is empty; Set first and last return pointers to NULL. */
4972 firstp = lastp = NULL;
4973 } else {
4974 firstp = ascq->q_first[tid];
4975 lastp = ascq->q_last[tid];
4976 ascq->q_first[tid] = ascq->q_last[tid] = NULL;
4977 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004978#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004979 {
4980 REQP reqp;
4981 ascq->q_cur_cnt[tid] = 0;
4982 for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
4983 REQTIMESTAT("asc_dequeue_list", ascq,
4984 reqp, tid);
4985 }
4986 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004987#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004988 }
4989 } else {
4990 /* Return all requests for all tids. */
4991 firstp = lastp = NULL;
4992 for (i = 0; i <= ADV_MAX_TID; i++) {
4993 if (ascq->q_tidmask & ADV_TID_TO_TIDMASK(i)) {
4994 if (firstp == NULL) {
4995 firstp = ascq->q_first[i];
4996 lastp = ascq->q_last[i];
4997 } else {
4998 ASC_ASSERT(lastp != NULL);
4999 lastp->host_scribble =
5000 (unsigned char *)ascq->q_first[i];
5001 lastp = ascq->q_last[i];
5002 }
5003 ascq->q_first[i] = ascq->q_last[i] = NULL;
5004 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005005#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005006 ascq->q_cur_cnt[i] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005007#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005008 }
5009 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005010#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005011 {
5012 REQP reqp;
5013 for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
5014 REQTIMESTAT("asc_dequeue_list", ascq, reqp,
5015 reqp->device->id);
5016 }
5017 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005018#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005019 }
5020 if (lastpp) {
5021 *lastpp = lastp;
5022 }
5023 ASC_DBG1(3, "asc_dequeue_list: firstp 0x%lx\n", (ulong)firstp);
5024 return firstp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005025}
5026
5027/*
5028 * Remove the specified 'REQP' from the specified queue for
5029 * the specified target device. Clear the 'tidmask' bit for the
5030 * device if no more commands are left queued for it.
5031 *
5032 * 'REQPNEXT(reqp)' returns reqp's the next pointer.
5033 *
5034 * Return ASC_TRUE if the command was found and removed,
5035 * otherwise return ASC_FALSE.
5036 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005037static int asc_rmqueue(asc_queue_t *ascq, REQP reqp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005038{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005039 REQP currp, prevp;
5040 int tid;
5041 int ret = ASC_FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005042
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005043 ASC_DBG2(3, "asc_rmqueue: ascq 0x%lx, reqp 0x%lx\n",
5044 (ulong)ascq, (ulong)reqp);
5045 ASC_ASSERT(reqp != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005046
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005047 tid = REQPTID(reqp);
5048 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005049
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005050 /*
5051 * Handle the common case of 'reqp' being the first
5052 * entry on the queue.
5053 */
5054 if (reqp == ascq->q_first[tid]) {
5055 ret = ASC_TRUE;
5056 ascq->q_first[tid] = REQPNEXT(reqp);
5057 /* If the queue is now empty, clear its bit and the last pointer. */
5058 if (ascq->q_first[tid] == NULL) {
5059 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
5060 ASC_ASSERT(ascq->q_last[tid] == reqp);
5061 ascq->q_last[tid] = NULL;
5062 }
5063 } else if (ascq->q_first[tid] != NULL) {
5064 ASC_ASSERT(ascq->q_last[tid] != NULL);
5065 /*
5066 * Because the case of 'reqp' being the first entry has been
5067 * handled above and it is known the queue is not empty, if
5068 * 'reqp' is found on the queue it is guaranteed the queue will
5069 * not become empty and that 'q_first[tid]' will not be changed.
5070 *
5071 * Set 'prevp' to the first entry, 'currp' to the second entry,
5072 * and search for 'reqp'.
5073 */
5074 for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp);
5075 currp; prevp = currp, currp = REQPNEXT(currp)) {
5076 if (currp == reqp) {
5077 ret = ASC_TRUE;
5078 prevp->host_scribble =
5079 (unsigned char *)REQPNEXT(currp);
5080 reqp->host_scribble = NULL;
5081 if (ascq->q_last[tid] == reqp) {
5082 ascq->q_last[tid] = prevp;
5083 }
5084 break;
5085 }
5086 }
5087 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005088#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005089 /* Maintain request queue statistics. */
5090 if (ret == ASC_TRUE) {
5091 ascq->q_cur_cnt[tid]--;
5092 REQTIMESTAT("asc_rmqueue", ascq, reqp, tid);
5093 }
5094 ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005095#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005096 ASC_DBG2(3, "asc_rmqueue: reqp 0x%lx, ret %d\n", (ulong)reqp, ret);
5097 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005098}
5099
Linus Torvalds1da177e2005-04-16 15:20:36 -07005100#ifdef CONFIG_PROC_FS
5101/*
5102 * asc_prt_board_devices()
5103 *
5104 * Print driver information for devices attached to the board.
5105 *
5106 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
5107 * cf. asc_prt_line().
5108 *
5109 * Return the number of characters copied into 'cp'. No more than
5110 * 'cplen' characters will be copied to 'cp'.
5111 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005112static int asc_prt_board_devices(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005113{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005114 asc_board_t *boardp;
5115 int leftlen;
5116 int totlen;
5117 int len;
5118 int chip_scsi_id;
5119 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005120
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005121 boardp = ASC_BOARDP(shost);
5122 leftlen = cplen;
5123 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005124
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005125 len = asc_prt_line(cp, leftlen,
5126 "\nDevice Information for AdvanSys SCSI Host %d:\n",
5127 shost->host_no);
5128 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005129
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005130 if (ASC_NARROW_BOARD(boardp)) {
5131 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
5132 } else {
5133 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
5134 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005135
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005136 len = asc_prt_line(cp, leftlen, "Target IDs Detected:");
5137 ASC_PRT_NEXT();
5138 for (i = 0; i <= ADV_MAX_TID; i++) {
5139 if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) {
5140 len = asc_prt_line(cp, leftlen, " %X,", i);
5141 ASC_PRT_NEXT();
5142 }
5143 }
5144 len = asc_prt_line(cp, leftlen, " (%X=Host Adapter)\n", chip_scsi_id);
5145 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005147 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005148}
5149
5150/*
5151 * Display Wide Board BIOS Information.
5152 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005153static int asc_prt_adv_bios(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005154{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005155 asc_board_t *boardp;
5156 int leftlen;
5157 int totlen;
5158 int len;
5159 ushort major, minor, letter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005160
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005161 boardp = ASC_BOARDP(shost);
5162 leftlen = cplen;
5163 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005164
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005165 len = asc_prt_line(cp, leftlen, "\nROM BIOS Version: ");
5166 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005167
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005168 /*
5169 * If the BIOS saved a valid signature, then fill in
5170 * the BIOS code segment base address.
5171 */
5172 if (boardp->bios_signature != 0x55AA) {
5173 len = asc_prt_line(cp, leftlen, "Disabled or Pre-3.1\n");
5174 ASC_PRT_NEXT();
5175 len = asc_prt_line(cp, leftlen,
5176 "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n");
5177 ASC_PRT_NEXT();
5178 len = asc_prt_line(cp, leftlen,
5179 "can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n");
5180 ASC_PRT_NEXT();
5181 } else {
5182 major = (boardp->bios_version >> 12) & 0xF;
5183 minor = (boardp->bios_version >> 8) & 0xF;
5184 letter = (boardp->bios_version & 0xFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005185
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005186 len = asc_prt_line(cp, leftlen, "%d.%d%c\n",
5187 major, minor,
5188 letter >= 26 ? '?' : letter + 'A');
5189 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005190
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005191 /*
5192 * Current available ROM BIOS release is 3.1I for UW
5193 * and 3.2I for U2W. This code doesn't differentiate
5194 * UW and U2W boards.
5195 */
5196 if (major < 3 || (major <= 3 && minor < 1) ||
5197 (major <= 3 && minor <= 1 && letter < ('I' - 'A'))) {
5198 len = asc_prt_line(cp, leftlen,
5199 "Newer version of ROM BIOS is available at the ConnectCom FTP site:\n");
5200 ASC_PRT_NEXT();
5201 len = asc_prt_line(cp, leftlen,
5202 "ftp://ftp.connectcom.net/pub\n");
5203 ASC_PRT_NEXT();
5204 }
5205 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005206
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005207 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005208}
5209
5210/*
5211 * Add serial number to information bar if signature AAh
5212 * is found in at bit 15-9 (7 bits) of word 1.
5213 *
5214 * Serial Number consists fo 12 alpha-numeric digits.
5215 *
5216 * 1 - Product type (A,B,C,D..) Word0: 15-13 (3 bits)
5217 * 2 - MFG Location (A,B,C,D..) Word0: 12-10 (3 bits)
5218 * 3-4 - Product ID (0-99) Word0: 9-0 (10 bits)
5219 * 5 - Product revision (A-J) Word0: " "
5220 *
5221 * Signature Word1: 15-9 (7 bits)
5222 * 6 - Year (0-9) Word1: 8-6 (3 bits) & Word2: 15 (1 bit)
5223 * 7-8 - Week of the year (1-52) Word1: 5-0 (6 bits)
5224 *
5225 * 9-12 - Serial Number (A001-Z999) Word2: 14-0 (15 bits)
5226 *
5227 * Note 1: Only production cards will have a serial number.
5228 *
5229 * Note 2: Signature is most significant 7 bits (0xFE).
5230 *
5231 * Returns ASC_TRUE if serial number found, otherwise returns ASC_FALSE.
5232 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005233static int asc_get_eeprom_string(ushort *serialnum, uchar *cp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005234{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005235 ushort w, num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005236
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005237 if ((serialnum[1] & 0xFE00) != ((ushort)0xAA << 8)) {
5238 return ASC_FALSE;
5239 } else {
5240 /*
5241 * First word - 6 digits.
5242 */
5243 w = serialnum[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07005244
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005245 /* Product type - 1st digit. */
5246 if ((*cp = 'A' + ((w & 0xE000) >> 13)) == 'H') {
5247 /* Product type is P=Prototype */
5248 *cp += 0x8;
5249 }
5250 cp++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005251
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005252 /* Manufacturing location - 2nd digit. */
5253 *cp++ = 'A' + ((w & 0x1C00) >> 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005254
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005255 /* Product ID - 3rd, 4th digits. */
5256 num = w & 0x3FF;
5257 *cp++ = '0' + (num / 100);
5258 num %= 100;
5259 *cp++ = '0' + (num / 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005260
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005261 /* Product revision - 5th digit. */
5262 *cp++ = 'A' + (num % 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005264 /*
5265 * Second word
5266 */
5267 w = serialnum[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07005268
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005269 /*
5270 * Year - 6th digit.
5271 *
5272 * If bit 15 of third word is set, then the
5273 * last digit of the year is greater than 7.
5274 */
5275 if (serialnum[2] & 0x8000) {
5276 *cp++ = '8' + ((w & 0x1C0) >> 6);
5277 } else {
5278 *cp++ = '0' + ((w & 0x1C0) >> 6);
5279 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005280
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005281 /* Week of year - 7th, 8th digits. */
5282 num = w & 0x003F;
5283 *cp++ = '0' + num / 10;
5284 num %= 10;
5285 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005286
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005287 /*
5288 * Third word
5289 */
5290 w = serialnum[2] & 0x7FFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005291
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005292 /* Serial number - 9th digit. */
5293 *cp++ = 'A' + (w / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005294
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005295 /* 10th, 11th, 12th digits. */
5296 num = w % 1000;
5297 *cp++ = '0' + num / 100;
5298 num %= 100;
5299 *cp++ = '0' + num / 10;
5300 num %= 10;
5301 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005302
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005303 *cp = '\0'; /* Null Terminate the string. */
5304 return ASC_TRUE;
5305 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005306}
5307
5308/*
5309 * asc_prt_asc_board_eeprom()
5310 *
5311 * Print board EEPROM configuration.
5312 *
5313 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
5314 * cf. asc_prt_line().
5315 *
5316 * Return the number of characters copied into 'cp'. No more than
5317 * 'cplen' characters will be copied to 'cp'.
5318 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005319static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005320{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005321 asc_board_t *boardp;
5322 ASC_DVC_VAR *asc_dvc_varp;
5323 int leftlen;
5324 int totlen;
5325 int len;
5326 ASCEEP_CONFIG *ep;
5327 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005328#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005329 int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07005330#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005331 uchar serialstr[13];
Linus Torvalds1da177e2005-04-16 15:20:36 -07005332
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005333 boardp = ASC_BOARDP(shost);
5334 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
5335 ep = &boardp->eep_config.asc_eep;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005336
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005337 leftlen = cplen;
5338 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005339
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005340 len = asc_prt_line(cp, leftlen,
5341 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
5342 shost->host_no);
5343 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005344
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005345 if (asc_get_eeprom_string((ushort *)&ep->adapter_info[0], serialstr)
5346 == ASC_TRUE) {
5347 len =
5348 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
5349 serialstr);
5350 ASC_PRT_NEXT();
5351 } else {
5352 if (ep->adapter_info[5] == 0xBB) {
5353 len = asc_prt_line(cp, leftlen,
5354 " Default Settings Used for EEPROM-less Adapter.\n");
5355 ASC_PRT_NEXT();
5356 } else {
5357 len = asc_prt_line(cp, leftlen,
5358 " Serial Number Signature Not Present.\n");
5359 ASC_PRT_NEXT();
5360 }
5361 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005362
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005363 len = asc_prt_line(cp, leftlen,
5364 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
5365 ASC_EEP_GET_CHIP_ID(ep), ep->max_total_qng,
5366 ep->max_tag_qng);
5367 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005368
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005369 len = asc_prt_line(cp, leftlen,
5370 " cntl 0x%x, no_scam 0x%x\n", ep->cntl, ep->no_scam);
5371 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005372
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005373 len = asc_prt_line(cp, leftlen, " Target ID: ");
5374 ASC_PRT_NEXT();
5375 for (i = 0; i <= ASC_MAX_TID; i++) {
5376 len = asc_prt_line(cp, leftlen, " %d", i);
5377 ASC_PRT_NEXT();
5378 }
5379 len = asc_prt_line(cp, leftlen, "\n");
5380 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005381
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005382 len = asc_prt_line(cp, leftlen, " Disconnects: ");
5383 ASC_PRT_NEXT();
5384 for (i = 0; i <= ASC_MAX_TID; i++) {
5385 len = asc_prt_line(cp, leftlen, " %c",
5386 (ep->
5387 disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
5388 'N');
5389 ASC_PRT_NEXT();
5390 }
5391 len = asc_prt_line(cp, leftlen, "\n");
5392 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005393
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005394 len = asc_prt_line(cp, leftlen, " Command Queuing: ");
5395 ASC_PRT_NEXT();
5396 for (i = 0; i <= ASC_MAX_TID; i++) {
5397 len = asc_prt_line(cp, leftlen, " %c",
5398 (ep->
5399 use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
5400 'N');
5401 ASC_PRT_NEXT();
5402 }
5403 len = asc_prt_line(cp, leftlen, "\n");
5404 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005405
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005406 len = asc_prt_line(cp, leftlen, " Start Motor: ");
5407 ASC_PRT_NEXT();
5408 for (i = 0; i <= ASC_MAX_TID; i++) {
5409 len = asc_prt_line(cp, leftlen, " %c",
5410 (ep->
5411 start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
5412 'N');
5413 ASC_PRT_NEXT();
5414 }
5415 len = asc_prt_line(cp, leftlen, "\n");
5416 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005417
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005418 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
5419 ASC_PRT_NEXT();
5420 for (i = 0; i <= ASC_MAX_TID; i++) {
5421 len = asc_prt_line(cp, leftlen, " %c",
5422 (ep->
5423 init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
5424 'N');
5425 ASC_PRT_NEXT();
5426 }
5427 len = asc_prt_line(cp, leftlen, "\n");
5428 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005429
5430#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005431 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
5432 len = asc_prt_line(cp, leftlen,
5433 " Host ISA DMA speed: %d MB/S\n",
5434 isa_dma_speed[ASC_EEP_GET_DMA_SPD(ep)]);
5435 ASC_PRT_NEXT();
5436 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005437#endif /* CONFIG_ISA */
5438
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005439 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005440}
5441
5442/*
5443 * asc_prt_adv_board_eeprom()
5444 *
5445 * Print board EEPROM configuration.
5446 *
5447 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
5448 * cf. asc_prt_line().
5449 *
5450 * Return the number of characters copied into 'cp'. No more than
5451 * 'cplen' characters will be copied to 'cp'.
5452 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005453static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005454{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005455 asc_board_t *boardp;
5456 ADV_DVC_VAR *adv_dvc_varp;
5457 int leftlen;
5458 int totlen;
5459 int len;
5460 int i;
5461 char *termstr;
5462 uchar serialstr[13];
5463 ADVEEP_3550_CONFIG *ep_3550 = NULL;
5464 ADVEEP_38C0800_CONFIG *ep_38C0800 = NULL;
5465 ADVEEP_38C1600_CONFIG *ep_38C1600 = NULL;
5466 ushort word;
5467 ushort *wordp;
5468 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005469
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005470 boardp = ASC_BOARDP(shost);
5471 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
5472 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
5473 ep_3550 = &boardp->eep_config.adv_3550_eep;
5474 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
5475 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
5476 } else {
5477 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
5478 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005480 leftlen = cplen;
5481 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005483 len = asc_prt_line(cp, leftlen,
5484 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
5485 shost->host_no);
5486 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005487
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005488 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
5489 wordp = &ep_3550->serial_number_word1;
5490 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
5491 wordp = &ep_38C0800->serial_number_word1;
5492 } else {
5493 wordp = &ep_38C1600->serial_number_word1;
5494 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005495
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005496 if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) {
5497 len =
5498 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
5499 serialstr);
5500 ASC_PRT_NEXT();
5501 } else {
5502 len = asc_prt_line(cp, leftlen,
5503 " Serial Number Signature Not Present.\n");
5504 ASC_PRT_NEXT();
5505 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005506
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005507 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
5508 len = asc_prt_line(cp, leftlen,
5509 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
5510 ep_3550->adapter_scsi_id,
5511 ep_3550->max_host_qng, ep_3550->max_dvc_qng);
5512 ASC_PRT_NEXT();
5513 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
5514 len = asc_prt_line(cp, leftlen,
5515 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
5516 ep_38C0800->adapter_scsi_id,
5517 ep_38C0800->max_host_qng,
5518 ep_38C0800->max_dvc_qng);
5519 ASC_PRT_NEXT();
5520 } else {
5521 len = asc_prt_line(cp, leftlen,
5522 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
5523 ep_38C1600->adapter_scsi_id,
5524 ep_38C1600->max_host_qng,
5525 ep_38C1600->max_dvc_qng);
5526 ASC_PRT_NEXT();
5527 }
5528 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
5529 word = ep_3550->termination;
5530 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
5531 word = ep_38C0800->termination_lvd;
5532 } else {
5533 word = ep_38C1600->termination_lvd;
5534 }
5535 switch (word) {
5536 case 1:
5537 termstr = "Low Off/High Off";
5538 break;
5539 case 2:
5540 termstr = "Low Off/High On";
5541 break;
5542 case 3:
5543 termstr = "Low On/High On";
5544 break;
5545 default:
5546 case 0:
5547 termstr = "Automatic";
5548 break;
5549 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005550
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005551 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
5552 len = asc_prt_line(cp, leftlen,
5553 " termination: %u (%s), bios_ctrl: 0x%x\n",
5554 ep_3550->termination, termstr,
5555 ep_3550->bios_ctrl);
5556 ASC_PRT_NEXT();
5557 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
5558 len = asc_prt_line(cp, leftlen,
5559 " termination: %u (%s), bios_ctrl: 0x%x\n",
5560 ep_38C0800->termination_lvd, termstr,
5561 ep_38C0800->bios_ctrl);
5562 ASC_PRT_NEXT();
5563 } else {
5564 len = asc_prt_line(cp, leftlen,
5565 " termination: %u (%s), bios_ctrl: 0x%x\n",
5566 ep_38C1600->termination_lvd, termstr,
5567 ep_38C1600->bios_ctrl);
5568 ASC_PRT_NEXT();
5569 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005570
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005571 len = asc_prt_line(cp, leftlen, " Target ID: ");
5572 ASC_PRT_NEXT();
5573 for (i = 0; i <= ADV_MAX_TID; i++) {
5574 len = asc_prt_line(cp, leftlen, " %X", i);
5575 ASC_PRT_NEXT();
5576 }
5577 len = asc_prt_line(cp, leftlen, "\n");
5578 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005579
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005580 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
5581 word = ep_3550->disc_enable;
5582 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
5583 word = ep_38C0800->disc_enable;
5584 } else {
5585 word = ep_38C1600->disc_enable;
5586 }
5587 len = asc_prt_line(cp, leftlen, " Disconnects: ");
5588 ASC_PRT_NEXT();
5589 for (i = 0; i <= ADV_MAX_TID; i++) {
5590 len = asc_prt_line(cp, leftlen, " %c",
5591 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
5592 ASC_PRT_NEXT();
5593 }
5594 len = asc_prt_line(cp, leftlen, "\n");
5595 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005596
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005597 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
5598 word = ep_3550->tagqng_able;
5599 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
5600 word = ep_38C0800->tagqng_able;
5601 } else {
5602 word = ep_38C1600->tagqng_able;
5603 }
5604 len = asc_prt_line(cp, leftlen, " Command Queuing: ");
5605 ASC_PRT_NEXT();
5606 for (i = 0; i <= ADV_MAX_TID; i++) {
5607 len = asc_prt_line(cp, leftlen, " %c",
5608 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
5609 ASC_PRT_NEXT();
5610 }
5611 len = asc_prt_line(cp, leftlen, "\n");
5612 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005613
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005614 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
5615 word = ep_3550->start_motor;
5616 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
5617 word = ep_38C0800->start_motor;
5618 } else {
5619 word = ep_38C1600->start_motor;
5620 }
5621 len = asc_prt_line(cp, leftlen, " Start Motor: ");
5622 ASC_PRT_NEXT();
5623 for (i = 0; i <= ADV_MAX_TID; i++) {
5624 len = asc_prt_line(cp, leftlen, " %c",
5625 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
5626 ASC_PRT_NEXT();
5627 }
5628 len = asc_prt_line(cp, leftlen, "\n");
5629 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005630
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005631 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
5632 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
5633 ASC_PRT_NEXT();
5634 for (i = 0; i <= ADV_MAX_TID; i++) {
5635 len = asc_prt_line(cp, leftlen, " %c",
5636 (ep_3550->
5637 sdtr_able & ADV_TID_TO_TIDMASK(i)) ?
5638 'Y' : 'N');
5639 ASC_PRT_NEXT();
5640 }
5641 len = asc_prt_line(cp, leftlen, "\n");
5642 ASC_PRT_NEXT();
5643 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005644
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005645 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
5646 len = asc_prt_line(cp, leftlen, " Ultra Transfer: ");
5647 ASC_PRT_NEXT();
5648 for (i = 0; i <= ADV_MAX_TID; i++) {
5649 len = asc_prt_line(cp, leftlen, " %c",
5650 (ep_3550->
5651 ultra_able & ADV_TID_TO_TIDMASK(i))
5652 ? 'Y' : 'N');
5653 ASC_PRT_NEXT();
5654 }
5655 len = asc_prt_line(cp, leftlen, "\n");
5656 ASC_PRT_NEXT();
5657 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005658
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005659 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
5660 word = ep_3550->wdtr_able;
5661 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
5662 word = ep_38C0800->wdtr_able;
5663 } else {
5664 word = ep_38C1600->wdtr_able;
5665 }
5666 len = asc_prt_line(cp, leftlen, " Wide Transfer: ");
5667 ASC_PRT_NEXT();
5668 for (i = 0; i <= ADV_MAX_TID; i++) {
5669 len = asc_prt_line(cp, leftlen, " %c",
5670 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
5671 ASC_PRT_NEXT();
5672 }
5673 len = asc_prt_line(cp, leftlen, "\n");
5674 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005675
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005676 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800 ||
5677 adv_dvc_varp->chip_type == ADV_CHIP_ASC38C1600) {
5678 len = asc_prt_line(cp, leftlen,
5679 " Synchronous Transfer Speed (Mhz):\n ");
5680 ASC_PRT_NEXT();
5681 for (i = 0; i <= ADV_MAX_TID; i++) {
5682 char *speed_str;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005683
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005684 if (i == 0) {
5685 sdtr_speed = adv_dvc_varp->sdtr_speed1;
5686 } else if (i == 4) {
5687 sdtr_speed = adv_dvc_varp->sdtr_speed2;
5688 } else if (i == 8) {
5689 sdtr_speed = adv_dvc_varp->sdtr_speed3;
5690 } else if (i == 12) {
5691 sdtr_speed = adv_dvc_varp->sdtr_speed4;
5692 }
5693 switch (sdtr_speed & ADV_MAX_TID) {
5694 case 0:
5695 speed_str = "Off";
5696 break;
5697 case 1:
5698 speed_str = " 5";
5699 break;
5700 case 2:
5701 speed_str = " 10";
5702 break;
5703 case 3:
5704 speed_str = " 20";
5705 break;
5706 case 4:
5707 speed_str = " 40";
5708 break;
5709 case 5:
5710 speed_str = " 80";
5711 break;
5712 default:
5713 speed_str = "Unk";
5714 break;
5715 }
5716 len = asc_prt_line(cp, leftlen, "%X:%s ", i, speed_str);
5717 ASC_PRT_NEXT();
5718 if (i == 7) {
5719 len = asc_prt_line(cp, leftlen, "\n ");
5720 ASC_PRT_NEXT();
5721 }
5722 sdtr_speed >>= 4;
5723 }
5724 len = asc_prt_line(cp, leftlen, "\n");
5725 ASC_PRT_NEXT();
5726 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005727
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005728 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005729}
5730
5731/*
5732 * asc_prt_driver_conf()
5733 *
5734 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
5735 * cf. asc_prt_line().
5736 *
5737 * Return the number of characters copied into 'cp'. No more than
5738 * 'cplen' characters will be copied to 'cp'.
5739 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005740static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005741{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005742 asc_board_t *boardp;
5743 int leftlen;
5744 int totlen;
5745 int len;
5746 int chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005747
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005748 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005749
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005750 leftlen = cplen;
5751 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005752
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005753 len = asc_prt_line(cp, leftlen,
5754 "\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n",
5755 shost->host_no);
5756 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005757
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005758 len = asc_prt_line(cp, leftlen,
5759 " host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n",
5760 shost->host_busy, shost->last_reset, shost->max_id,
5761 shost->max_lun, shost->max_channel);
5762 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005763
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005764 len = asc_prt_line(cp, leftlen,
5765 " unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
5766 shost->unique_id, shost->can_queue, shost->this_id,
5767 shost->sg_tablesize, shost->cmd_per_lun);
5768 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005769
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005770 len = asc_prt_line(cp, leftlen,
5771 " unchecked_isa_dma %d, use_clustering %d\n",
5772 shost->unchecked_isa_dma, shost->use_clustering);
5773 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005774
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005775 len = asc_prt_line(cp, leftlen,
5776 " flags 0x%x, last_reset 0x%x, jiffies 0x%x, asc_n_io_port 0x%x\n",
5777 boardp->flags, boardp->last_reset, jiffies,
5778 boardp->asc_n_io_port);
5779 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005780
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04005781 len = asc_prt_line(cp, leftlen, " io_port 0x%x\n", shost->io_port);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005782 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005783
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005784 if (ASC_NARROW_BOARD(boardp)) {
5785 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
5786 } else {
5787 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
5788 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005789
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005790 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005791}
5792
5793/*
5794 * asc_prt_asc_board_info()
5795 *
5796 * Print dynamic board configuration information.
5797 *
5798 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
5799 * cf. asc_prt_line().
5800 *
5801 * Return the number of characters copied into 'cp'. No more than
5802 * 'cplen' characters will be copied to 'cp'.
5803 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005804static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005805{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005806 asc_board_t *boardp;
5807 int chip_scsi_id;
5808 int leftlen;
5809 int totlen;
5810 int len;
5811 ASC_DVC_VAR *v;
5812 ASC_DVC_CFG *c;
5813 int i;
5814 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005815
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005816 boardp = ASC_BOARDP(shost);
5817 v = &boardp->dvc_var.asc_dvc_var;
5818 c = &boardp->dvc_cfg.asc_dvc_cfg;
5819 chip_scsi_id = c->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005820
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005821 leftlen = cplen;
5822 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005823
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005824 len = asc_prt_line(cp, leftlen,
5825 "\nAsc Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
5826 shost->host_no);
5827 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005828
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005829 len = asc_prt_line(cp, leftlen,
5830 " chip_version %u, lib_version 0x%x, lib_serial_no %u, mcode_date 0x%x\n",
5831 c->chip_version, c->lib_version, c->lib_serial_no,
5832 c->mcode_date);
5833 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005834
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005835 len = asc_prt_line(cp, leftlen,
5836 " mcode_version 0x%x, err_code %u\n",
5837 c->mcode_version, v->err_code);
5838 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005839
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005840 /* Current number of commands waiting for the host. */
5841 len = asc_prt_line(cp, leftlen,
5842 " Total Command Pending: %d\n", v->cur_total_qng);
5843 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005844
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005845 len = asc_prt_line(cp, leftlen, " Command Queuing:");
5846 ASC_PRT_NEXT();
5847 for (i = 0; i <= ASC_MAX_TID; i++) {
5848 if ((chip_scsi_id == i) ||
5849 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
5850 continue;
5851 }
5852 len = asc_prt_line(cp, leftlen, " %X:%c",
5853 i,
5854 (v->
5855 use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ?
5856 'Y' : 'N');
5857 ASC_PRT_NEXT();
5858 }
5859 len = asc_prt_line(cp, leftlen, "\n");
5860 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005861
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005862 /* Current number of commands waiting for a device. */
5863 len = asc_prt_line(cp, leftlen, " Command Queue Pending:");
5864 ASC_PRT_NEXT();
5865 for (i = 0; i <= ASC_MAX_TID; i++) {
5866 if ((chip_scsi_id == i) ||
5867 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
5868 continue;
5869 }
5870 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->cur_dvc_qng[i]);
5871 ASC_PRT_NEXT();
5872 }
5873 len = asc_prt_line(cp, leftlen, "\n");
5874 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005875
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005876 /* Current limit on number of commands that can be sent to a device. */
5877 len = asc_prt_line(cp, leftlen, " Command Queue Limit:");
5878 ASC_PRT_NEXT();
5879 for (i = 0; i <= ASC_MAX_TID; i++) {
5880 if ((chip_scsi_id == i) ||
5881 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
5882 continue;
5883 }
5884 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->max_dvc_qng[i]);
5885 ASC_PRT_NEXT();
5886 }
5887 len = asc_prt_line(cp, leftlen, "\n");
5888 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005889
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005890 /* Indicate whether the device has returned queue full status. */
5891 len = asc_prt_line(cp, leftlen, " Command Queue Full:");
5892 ASC_PRT_NEXT();
5893 for (i = 0; i <= ASC_MAX_TID; i++) {
5894 if ((chip_scsi_id == i) ||
5895 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
5896 continue;
5897 }
5898 if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) {
5899 len = asc_prt_line(cp, leftlen, " %X:Y-%d",
5900 i, boardp->queue_full_cnt[i]);
5901 } else {
5902 len = asc_prt_line(cp, leftlen, " %X:N", i);
5903 }
5904 ASC_PRT_NEXT();
5905 }
5906 len = asc_prt_line(cp, leftlen, "\n");
5907 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005908
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005909 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
5910 ASC_PRT_NEXT();
5911 for (i = 0; i <= ASC_MAX_TID; i++) {
5912 if ((chip_scsi_id == i) ||
5913 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
5914 continue;
5915 }
5916 len = asc_prt_line(cp, leftlen, " %X:%c",
5917 i,
5918 (v->
5919 sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
5920 'N');
5921 ASC_PRT_NEXT();
5922 }
5923 len = asc_prt_line(cp, leftlen, "\n");
5924 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005925
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005926 for (i = 0; i <= ASC_MAX_TID; i++) {
5927 uchar syn_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005928
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005929 if ((chip_scsi_id == i) ||
5930 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
5931 ((v->init_sdtr & ADV_TID_TO_TIDMASK(i)) == 0)) {
5932 continue;
5933 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005934
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005935 len = asc_prt_line(cp, leftlen, " %X:", i);
5936 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005937
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005938 if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0) {
5939 len = asc_prt_line(cp, leftlen, " Asynchronous");
5940 ASC_PRT_NEXT();
5941 } else {
5942 syn_period_ix =
5943 (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index -
5944 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005945
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005946 len = asc_prt_line(cp, leftlen,
5947 " Transfer Period Factor: %d (%d.%d Mhz),",
5948 v->sdtr_period_tbl[syn_period_ix],
5949 250 /
5950 v->sdtr_period_tbl[syn_period_ix],
5951 ASC_TENTHS(250,
5952 v->
5953 sdtr_period_tbl
5954 [syn_period_ix]));
5955 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005956
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005957 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
5958 boardp->
5959 sdtr_data[i] & ASC_SYN_MAX_OFFSET);
5960 ASC_PRT_NEXT();
5961 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005962
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005963 if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
5964 len = asc_prt_line(cp, leftlen, "*\n");
5965 renegotiate = 1;
5966 } else {
5967 len = asc_prt_line(cp, leftlen, "\n");
5968 }
5969 ASC_PRT_NEXT();
5970 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005971
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005972 if (renegotiate) {
5973 len = asc_prt_line(cp, leftlen,
5974 " * = Re-negotiation pending before next command.\n");
5975 ASC_PRT_NEXT();
5976 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005977
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005978 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005979}
5980
5981/*
5982 * asc_prt_adv_board_info()
5983 *
5984 * Print dynamic board configuration information.
5985 *
5986 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
5987 * cf. asc_prt_line().
5988 *
5989 * Return the number of characters copied into 'cp'. No more than
5990 * 'cplen' characters will be copied to 'cp'.
5991 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005992static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005993{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005994 asc_board_t *boardp;
5995 int leftlen;
5996 int totlen;
5997 int len;
5998 int i;
5999 ADV_DVC_VAR *v;
6000 ADV_DVC_CFG *c;
6001 AdvPortAddr iop_base;
6002 ushort chip_scsi_id;
6003 ushort lramword;
6004 uchar lrambyte;
6005 ushort tagqng_able;
6006 ushort sdtr_able, wdtr_able;
6007 ushort wdtr_done, sdtr_done;
6008 ushort period = 0;
6009 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006010
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006011 boardp = ASC_BOARDP(shost);
6012 v = &boardp->dvc_var.adv_dvc_var;
6013 c = &boardp->dvc_cfg.adv_dvc_cfg;
6014 iop_base = v->iop_base;
6015 chip_scsi_id = v->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006016
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006017 leftlen = cplen;
6018 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006019
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006020 len = asc_prt_line(cp, leftlen,
6021 "\nAdv Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
6022 shost->host_no);
6023 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006024
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006025 len = asc_prt_line(cp, leftlen,
6026 " iop_base 0x%lx, cable_detect: %X, err_code %u\n",
6027 v->iop_base,
6028 AdvReadWordRegister(iop_base,
6029 IOPW_SCSI_CFG1) & CABLE_DETECT,
6030 v->err_code);
6031 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006032
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006033 len = asc_prt_line(cp, leftlen,
6034 " chip_version %u, lib_version 0x%x, mcode_date 0x%x, mcode_version 0x%x\n",
6035 c->chip_version, c->lib_version, c->mcode_date,
6036 c->mcode_version);
6037 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006038
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006039 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
6040 len = asc_prt_line(cp, leftlen, " Queuing Enabled:");
6041 ASC_PRT_NEXT();
6042 for (i = 0; i <= ADV_MAX_TID; i++) {
6043 if ((chip_scsi_id == i) ||
6044 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6045 continue;
6046 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006047
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006048 len = asc_prt_line(cp, leftlen, " %X:%c",
6049 i,
6050 (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6051 'N');
6052 ASC_PRT_NEXT();
6053 }
6054 len = asc_prt_line(cp, leftlen, "\n");
6055 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006056
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006057 len = asc_prt_line(cp, leftlen, " Queue Limit:");
6058 ASC_PRT_NEXT();
6059 for (i = 0; i <= ADV_MAX_TID; i++) {
6060 if ((chip_scsi_id == i) ||
6061 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6062 continue;
6063 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006064
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006065 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + i,
6066 lrambyte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006067
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006068 len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
6069 ASC_PRT_NEXT();
6070 }
6071 len = asc_prt_line(cp, leftlen, "\n");
6072 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006073
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006074 len = asc_prt_line(cp, leftlen, " Command Pending:");
6075 ASC_PRT_NEXT();
6076 for (i = 0; i <= ADV_MAX_TID; i++) {
6077 if ((chip_scsi_id == i) ||
6078 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6079 continue;
6080 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006081
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006082 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_QUEUED_CMD + i,
6083 lrambyte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006084
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006085 len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
6086 ASC_PRT_NEXT();
6087 }
6088 len = asc_prt_line(cp, leftlen, "\n");
6089 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006090
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006091 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
6092 len = asc_prt_line(cp, leftlen, " Wide Enabled:");
6093 ASC_PRT_NEXT();
6094 for (i = 0; i <= ADV_MAX_TID; i++) {
6095 if ((chip_scsi_id == i) ||
6096 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6097 continue;
6098 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006099
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006100 len = asc_prt_line(cp, leftlen, " %X:%c",
6101 i,
6102 (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6103 'N');
6104 ASC_PRT_NEXT();
6105 }
6106 len = asc_prt_line(cp, leftlen, "\n");
6107 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006108
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006109 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done);
6110 len = asc_prt_line(cp, leftlen, " Transfer Bit Width:");
6111 ASC_PRT_NEXT();
6112 for (i = 0; i <= ADV_MAX_TID; i++) {
6113 if ((chip_scsi_id == i) ||
6114 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6115 continue;
6116 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006117
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006118 AdvReadWordLram(iop_base,
6119 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
6120 lramword);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006121
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006122 len = asc_prt_line(cp, leftlen, " %X:%d",
6123 i, (lramword & 0x8000) ? 16 : 8);
6124 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006125
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006126 if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) &&
6127 (wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
6128 len = asc_prt_line(cp, leftlen, "*");
6129 ASC_PRT_NEXT();
6130 renegotiate = 1;
6131 }
6132 }
6133 len = asc_prt_line(cp, leftlen, "\n");
6134 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006135
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006136 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
6137 len = asc_prt_line(cp, leftlen, " Synchronous Enabled:");
6138 ASC_PRT_NEXT();
6139 for (i = 0; i <= ADV_MAX_TID; i++) {
6140 if ((chip_scsi_id == i) ||
6141 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6142 continue;
6143 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006144
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006145 len = asc_prt_line(cp, leftlen, " %X:%c",
6146 i,
6147 (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6148 'N');
6149 ASC_PRT_NEXT();
6150 }
6151 len = asc_prt_line(cp, leftlen, "\n");
6152 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006153
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006154 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done);
6155 for (i = 0; i <= ADV_MAX_TID; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006156
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006157 AdvReadWordLram(iop_base,
6158 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
6159 lramword);
6160 lramword &= ~0x8000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006161
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006162 if ((chip_scsi_id == i) ||
6163 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
6164 ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0)) {
6165 continue;
6166 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006167
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006168 len = asc_prt_line(cp, leftlen, " %X:", i);
6169 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006170
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006171 if ((lramword & 0x1F) == 0) { /* Check for REQ/ACK Offset 0. */
6172 len = asc_prt_line(cp, leftlen, " Asynchronous");
6173 ASC_PRT_NEXT();
6174 } else {
6175 len =
6176 asc_prt_line(cp, leftlen,
6177 " Transfer Period Factor: ");
6178 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006179
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006180 if ((lramword & 0x1F00) == 0x1100) { /* 80 Mhz */
6181 len =
6182 asc_prt_line(cp, leftlen, "9 (80.0 Mhz),");
6183 ASC_PRT_NEXT();
6184 } else if ((lramword & 0x1F00) == 0x1000) { /* 40 Mhz */
6185 len =
6186 asc_prt_line(cp, leftlen, "10 (40.0 Mhz),");
6187 ASC_PRT_NEXT();
6188 } else { /* 20 Mhz or below. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006189
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006190 period = (((lramword >> 8) * 25) + 50) / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006191
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006192 if (period == 0) { /* Should never happen. */
6193 len =
6194 asc_prt_line(cp, leftlen,
6195 "%d (? Mhz), ");
6196 ASC_PRT_NEXT();
6197 } else {
6198 len = asc_prt_line(cp, leftlen,
6199 "%d (%d.%d Mhz),",
6200 period, 250 / period,
6201 ASC_TENTHS(250,
6202 period));
6203 ASC_PRT_NEXT();
6204 }
6205 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006206
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006207 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
6208 lramword & 0x1F);
6209 ASC_PRT_NEXT();
6210 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006211
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006212 if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
6213 len = asc_prt_line(cp, leftlen, "*\n");
6214 renegotiate = 1;
6215 } else {
6216 len = asc_prt_line(cp, leftlen, "\n");
6217 }
6218 ASC_PRT_NEXT();
6219 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006220
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006221 if (renegotiate) {
6222 len = asc_prt_line(cp, leftlen,
6223 " * = Re-negotiation pending before next command.\n");
6224 ASC_PRT_NEXT();
6225 }
6226
6227 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006228}
6229
6230/*
6231 * asc_proc_copy()
6232 *
6233 * Copy proc information to a read buffer taking into account the current
6234 * read offset in the file and the remaining space in the read buffer.
6235 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006236static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07006237asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006238 char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006239{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006240 int cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006241
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006242 ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n",
6243 (unsigned)offset, (unsigned)advoffset, cplen);
6244 if (offset <= advoffset) {
6245 /* Read offset below current offset, copy everything. */
6246 cnt = min(cplen, leftlen);
6247 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
6248 (ulong)curbuf, (ulong)cp, cnt);
6249 memcpy(curbuf, cp, cnt);
6250 } else if (offset < advoffset + cplen) {
6251 /* Read offset within current range, partial copy. */
6252 cnt = (advoffset + cplen) - offset;
6253 cp = (cp + cplen) - cnt;
6254 cnt = min(cnt, leftlen);
6255 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
6256 (ulong)curbuf, (ulong)cp, cnt);
6257 memcpy(curbuf, cp, cnt);
6258 }
6259 return cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006260}
6261
6262/*
6263 * asc_prt_line()
6264 *
6265 * If 'cp' is NULL print to the console, otherwise print to a buffer.
6266 *
6267 * Return 0 if printing to the console, otherwise return the number of
6268 * bytes written to the buffer.
6269 *
6270 * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack
6271 * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes.
6272 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006273static int asc_prt_line(char *buf, int buflen, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006274{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006275 va_list args;
6276 int ret;
6277 char s[ASC_PRTLINE_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006278
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006279 va_start(args, fmt);
6280 ret = vsprintf(s, fmt, args);
6281 ASC_ASSERT(ret < ASC_PRTLINE_SIZE);
6282 if (buf == NULL) {
6283 (void)printk(s);
6284 ret = 0;
6285 } else {
6286 ret = min(buflen, ret);
6287 memcpy(buf, s, ret);
6288 }
6289 va_end(args);
6290 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006291}
6292#endif /* CONFIG_PROC_FS */
6293
Linus Torvalds1da177e2005-04-16 15:20:36 -07006294/*
6295 * --- Functions Required by the Asc Library
6296 */
6297
6298/*
6299 * Delay for 'n' milliseconds. Don't use the 'jiffies'
6300 * global variable which is incremented once every 5 ms
6301 * from a timer interrupt, because this function may be
6302 * called when interrupts are disabled.
6303 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006304static void DvcSleepMilliSecond(ADV_DCNT n)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006305{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006306 ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", (ulong)n);
6307 mdelay(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006308}
6309
6310/*
6311 * Currently and inline noop but leave as a placeholder.
6312 * Leave DvcEnterCritical() as a noop placeholder.
6313 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006314static inline ulong DvcEnterCritical(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006315{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006316 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006317}
6318
6319/*
6320 * Critical sections are all protected by the board spinlock.
6321 * Leave DvcLeaveCritical() as a noop placeholder.
6322 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006323static inline void DvcLeaveCritical(ulong flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006324{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006325 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006326}
6327
6328/*
6329 * void
6330 * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
6331 *
6332 * Calling/Exit State:
6333 * none
6334 *
6335 * Description:
6336 * Output an ASC_SCSI_Q structure to the chip
6337 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006338static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07006339DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
6340{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006341 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006342
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006343 ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words);
6344 AscSetChipLramAddr(iop_base, s_addr);
6345 for (i = 0; i < 2 * words; i += 2) {
6346 if (i == 4 || i == 20) {
6347 continue;
6348 }
6349 outpw(iop_base + IOP_RAM_DATA,
6350 ((ushort)outbuf[i + 1] << 8) | outbuf[i]);
6351 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006352}
6353
6354/*
6355 * void
6356 * DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
6357 *
6358 * Calling/Exit State:
6359 * none
6360 *
6361 * Description:
6362 * Input an ASC_QDONE_INFO structure from the chip
6363 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006364static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07006365DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
6366{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006367 int i;
6368 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006369
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006370 AscSetChipLramAddr(iop_base, s_addr);
6371 for (i = 0; i < 2 * words; i += 2) {
6372 if (i == 10) {
6373 continue;
6374 }
6375 word = inpw(iop_base + IOP_RAM_DATA);
6376 inbuf[i] = word & 0xff;
6377 inbuf[i + 1] = (word >> 8) & 0xff;
6378 }
6379 ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006380}
6381
6382/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07006383 * Return the BIOS address of the adapter at the specified
6384 * I/O port and with the specified bus type.
6385 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006386static unsigned short __devinit
6387AscGetChipBiosAddress(PortAddr iop_base, unsigned short bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006388{
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006389 unsigned short cfg_lsw;
6390 unsigned short bios_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006391
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006392 /*
6393 * The PCI BIOS is re-located by the motherboard BIOS. Because
6394 * of this the driver can not determine where a PCI BIOS is
6395 * loaded and executes.
6396 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006397 if (bus_type & ASC_IS_PCI)
6398 return 0;
6399
Linus Torvalds1da177e2005-04-16 15:20:36 -07006400#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006401 if ((bus_type & ASC_IS_EISA) != 0) {
6402 cfg_lsw = AscGetEisaChipCfg(iop_base);
6403 cfg_lsw &= 0x000F;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006404 bios_addr = ASC_BIOS_MIN_ADDR + cfg_lsw * ASC_BIOS_BANK_SIZE;
6405 return bios_addr;
6406 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006407#endif /* CONFIG_ISA */
6408
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006409 cfg_lsw = AscGetChipCfgLsw(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006410
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006411 /*
6412 * ISA PnP uses the top bit as the 32K BIOS flag
6413 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006414 if (bus_type == ASC_IS_ISAPNP)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006415 cfg_lsw &= 0x7FFF;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006416 bios_addr = ASC_BIOS_MIN_ADDR + (cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE;
6417 return bios_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006418}
6419
Linus Torvalds1da177e2005-04-16 15:20:36 -07006420/*
6421 * --- Functions Required by the Adv Library
6422 */
6423
6424/*
6425 * DvcGetPhyAddr()
6426 *
6427 * Return the physical address of 'vaddr' and set '*lenp' to the
6428 * number of physically contiguous bytes that follow 'vaddr'.
6429 * 'flag' indicates the type of structure whose physical address
6430 * is being translated.
6431 *
6432 * Note: Because Linux currently doesn't page the kernel and all
6433 * kernel buffers are physically contiguous, leave '*lenp' unchanged.
6434 */
6435ADV_PADDR
6436DvcGetPhyAddr(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006437 uchar *vaddr, ADV_SDCNT *lenp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006438{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006439 ADV_PADDR paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006440
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006441 paddr = virt_to_bus(vaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006442
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006443 ASC_DBG4(4,
6444 "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n",
6445 (ulong)vaddr, (ulong)lenp, (ulong)*((ulong *)lenp),
6446 (ulong)paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006447
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006448 return paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006449}
6450
6451/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07006452 * --- Tracing and Debugging Functions
6453 */
6454
6455#ifdef ADVANSYS_STATS
6456#ifdef CONFIG_PROC_FS
6457/*
6458 * asc_prt_board_stats()
6459 *
6460 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6461 * cf. asc_prt_line().
6462 *
6463 * Return the number of characters copied into 'cp'. No more than
6464 * 'cplen' characters will be copied to 'cp'.
6465 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006466static int asc_prt_board_stats(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006467{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006468 int leftlen;
6469 int totlen;
6470 int len;
6471 struct asc_stats *s;
6472 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006473
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006474 leftlen = cplen;
6475 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006476
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006477 boardp = ASC_BOARDP(shost);
6478 s = &boardp->asc_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006479
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006480 len = asc_prt_line(cp, leftlen,
6481 "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n",
6482 shost->host_no);
6483 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006484
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006485 len = asc_prt_line(cp, leftlen,
6486 " queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n",
6487 s->queuecommand, s->reset, s->biosparam,
6488 s->interrupt);
6489 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006490
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006491 len = asc_prt_line(cp, leftlen,
6492 " callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n",
6493 s->callback, s->done, s->build_error,
6494 s->adv_build_noreq, s->adv_build_nosg);
6495 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006496
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006497 len = asc_prt_line(cp, leftlen,
6498 " exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n",
6499 s->exe_noerror, s->exe_busy, s->exe_error,
6500 s->exe_unknown);
6501 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006502
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006503 /*
6504 * Display data transfer statistics.
6505 */
6506 if (s->cont_cnt > 0) {
6507 len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt);
6508 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006509
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006510 len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ",
6511 s->cont_xfer / 2,
6512 ASC_TENTHS(s->cont_xfer, 2));
6513 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006514
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006515 /* Contiguous transfer average size */
6516 len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kb\n",
6517 (s->cont_xfer / 2) / s->cont_cnt,
6518 ASC_TENTHS((s->cont_xfer / 2), s->cont_cnt));
6519 ASC_PRT_NEXT();
6520 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006521
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006522 if (s->sg_cnt > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006523
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006524 len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ",
6525 s->sg_cnt, s->sg_elem);
6526 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006527
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006528 len = asc_prt_line(cp, leftlen, "sg_xfer %lu.%01lu kb\n",
6529 s->sg_xfer / 2, ASC_TENTHS(s->sg_xfer, 2));
6530 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006531
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006532 /* Scatter gather transfer statistics */
6533 len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ",
6534 s->sg_elem / s->sg_cnt,
6535 ASC_TENTHS(s->sg_elem, s->sg_cnt));
6536 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006537
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006538 len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ",
6539 (s->sg_xfer / 2) / s->sg_elem,
6540 ASC_TENTHS((s->sg_xfer / 2), s->sg_elem));
6541 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006542
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006543 len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n",
6544 (s->sg_xfer / 2) / s->sg_cnt,
6545 ASC_TENTHS((s->sg_xfer / 2), s->sg_cnt));
6546 ASC_PRT_NEXT();
6547 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006548
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006549 /*
6550 * Display request queuing statistics.
6551 */
6552 len = asc_prt_line(cp, leftlen,
6553 " Active and Waiting Request Queues (Time Unit: %d HZ):\n",
6554 HZ);
6555 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006556
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006557 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006558}
6559
6560/*
6561 * asc_prt_target_stats()
6562 *
6563 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6564 * cf. asc_prt_line().
6565 *
6566 * This is separated from asc_prt_board_stats because a full set
6567 * of targets will overflow ASC_PRTBUF_SIZE.
6568 *
6569 * Return the number of characters copied into 'cp'. No more than
6570 * 'cplen' characters will be copied to 'cp'.
6571 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006572static int
6573asc_prt_target_stats(struct Scsi_Host *shost, int tgt_id, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006574{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006575 int leftlen;
6576 int totlen;
6577 int len;
6578 struct asc_stats *s;
6579 ushort chip_scsi_id;
6580 asc_board_t *boardp;
6581 asc_queue_t *active;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006582
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006583 leftlen = cplen;
6584 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006585
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006586 boardp = ASC_BOARDP(shost);
6587 s = &boardp->asc_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006588
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006589 active = &ASC_BOARDP(shost)->active;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006590
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006591 if (ASC_NARROW_BOARD(boardp)) {
6592 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
6593 } else {
6594 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
6595 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006596
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006597 if ((chip_scsi_id == tgt_id) ||
6598 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(tgt_id)) == 0)) {
6599 return 0;
6600 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006601
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006602 do {
Matthew Wilcoxb6622922007-09-09 08:56:31 -06006603 if (active->q_tot_cnt[tgt_id] > 0) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006604 len = asc_prt_line(cp, leftlen, " target %d\n", tgt_id);
6605 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006606
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006607 len = asc_prt_line(cp, leftlen,
6608 " active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n",
6609 active->q_cur_cnt[tgt_id],
6610 active->q_max_cnt[tgt_id],
6611 active->q_tot_cnt[tgt_id],
6612 active->q_min_tim[tgt_id],
6613 active->q_max_tim[tgt_id],
6614 (active->q_tot_cnt[tgt_id] ==
6615 0) ? 0 : (active->
6616 q_tot_tim[tgt_id] /
6617 active->
6618 q_tot_cnt[tgt_id]),
6619 (active->q_tot_cnt[tgt_id] ==
6620 0) ? 0 : ASC_TENTHS(active->
6621 q_tot_tim
6622 [tgt_id],
6623 active->
6624 q_tot_cnt
6625 [tgt_id]));
6626 ASC_PRT_NEXT();
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006627 }
6628 } while (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006629
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006630 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006631}
6632#endif /* CONFIG_PROC_FS */
6633#endif /* ADVANSYS_STATS */
6634
6635#ifdef ADVANSYS_DEBUG
6636/*
6637 * asc_prt_scsi_host()
6638 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006639static void asc_prt_scsi_host(struct Scsi_Host *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006640{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006641 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006642
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006643 boardp = ASC_BOARDP(s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006644
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006645 printk("Scsi_Host at addr 0x%lx\n", (ulong)s);
6646 printk(" host_busy %u, host_no %d, last_reset %d,\n",
6647 s->host_busy, s->host_no, (unsigned)s->last_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006648
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04006649 printk(" base 0x%lx, io_port 0x%lx, irq 0x%x,\n",
6650 (ulong)s->base, (ulong)s->io_port, s->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006651
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006652 printk(" dma_channel %d, this_id %d, can_queue %d,\n",
6653 s->dma_channel, s->this_id, s->can_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006654
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006655 printk(" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
6656 s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006657
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006658 if (ASC_NARROW_BOARD(boardp)) {
6659 asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var);
6660 asc_prt_asc_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.asc_dvc_cfg);
6661 } else {
6662 asc_prt_adv_dvc_var(&ASC_BOARDP(s)->dvc_var.adv_dvc_var);
6663 asc_prt_adv_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.adv_dvc_cfg);
6664 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006665}
6666
6667/*
6668 * asc_prt_scsi_cmnd()
6669 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006670static void asc_prt_scsi_cmnd(struct scsi_cmnd *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006671{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006672 printk("struct scsi_cmnd at addr 0x%lx\n", (ulong)s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006673
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006674 printk(" host 0x%lx, device 0x%lx, target %u, lun %u, channel %u,\n",
6675 (ulong)s->device->host, (ulong)s->device, s->device->id,
6676 s->device->lun, s->device->channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006677
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006678 asc_prt_hex(" CDB", s->cmnd, s->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006679
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006680 printk("sc_data_direction %u, resid %d\n",
6681 s->sc_data_direction, s->resid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006682
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006683 printk(" use_sg %u, sglist_len %u\n", s->use_sg, s->sglist_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006684
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006685 printk(" serial_number 0x%x, retries %d, allowed %d\n",
6686 (unsigned)s->serial_number, s->retries, s->allowed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006687
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006688 printk(" timeout_per_command %d\n", s->timeout_per_command);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006689
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006690 printk(" scsi_done 0x%p, done 0x%p, host_scribble 0x%p, result 0x%x\n",
6691 s->scsi_done, s->done, s->host_scribble, s->result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006692
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006693 printk(" tag %u, pid %u\n", (unsigned)s->tag, (unsigned)s->pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006694}
6695
6696/*
6697 * asc_prt_asc_dvc_var()
6698 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006699static void asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006700{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006701 printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006702
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006703 printk(" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl "
6704 "%d,\n", h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006705
Matthew Wilcox895d6b42007-07-26 11:57:06 -04006706 printk(" bus_type %d, init_sdtr 0x%x,\n", h->bus_type,
6707 (unsigned)h->init_sdtr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006708
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006709 printk(" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, "
6710 "chip_no 0x%x,\n", (unsigned)h->sdtr_done,
6711 (unsigned)h->use_tagged_qng, (unsigned)h->unit_not_ready,
6712 (unsigned)h->chip_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006713
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006714 printk(" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait "
6715 "%u,\n", (unsigned)h->queue_full_or_busy,
6716 (unsigned)h->start_motor, (unsigned)h->scsi_reset_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006717
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006718 printk(" is_in_int %u, max_total_qng %u, cur_total_qng %u, "
6719 "in_critical_cnt %u,\n", (unsigned)h->is_in_int,
6720 (unsigned)h->max_total_qng, (unsigned)h->cur_total_qng,
6721 (unsigned)h->in_critical_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006722
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006723 printk(" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, "
6724 "pci_fix_asyn_xfer 0x%x,\n", (unsigned)h->last_q_shortage,
6725 (unsigned)h->init_state, (unsigned)h->no_scam,
6726 (unsigned)h->pci_fix_asyn_xfer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006727
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006728 printk(" cfg 0x%lx, irq_no 0x%x\n", (ulong)h->cfg, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006729}
6730
6731/*
6732 * asc_prt_asc_dvc_cfg()
6733 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006734static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006735{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006736 printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006737
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006738 printk(" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n",
6739 h->can_tagged_qng, h->cmd_qng_enabled);
6740 printk(" disc_enable 0x%x, sdtr_enable 0x%x,\n",
6741 h->disc_enable, h->sdtr_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006742
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006743 printk
6744 (" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n",
6745 h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel,
6746 h->chip_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006747
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006748 printk
6749 (" pci_device_id %d, lib_serial_no %u, lib_version %u, mcode_date 0x%x,\n",
6750 to_pci_dev(h->dev)->device, h->lib_serial_no, h->lib_version,
6751 h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006752
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006753 printk(" mcode_version %d, overrun_buf 0x%lx\n",
6754 h->mcode_version, (ulong)h->overrun_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006755}
6756
6757/*
6758 * asc_prt_asc_scsi_q()
6759 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006760static void asc_prt_asc_scsi_q(ASC_SCSI_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006761{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006762 ASC_SG_HEAD *sgp;
6763 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006764
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006765 printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006766
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006767 printk
6768 (" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n",
6769 q->q2.target_ix, q->q1.target_lun, (ulong)q->q2.srb_ptr,
6770 q->q2.tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006771
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006772 printk
6773 (" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
6774 (ulong)le32_to_cpu(q->q1.data_addr),
6775 (ulong)le32_to_cpu(q->q1.data_cnt),
6776 (ulong)le32_to_cpu(q->q1.sense_addr), q->q1.sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006777
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006778 printk(" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n",
6779 (ulong)q->cdbptr, q->q2.cdb_len,
6780 (ulong)q->sg_head, q->q1.sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006781
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006782 if (q->sg_head) {
6783 sgp = q->sg_head;
6784 printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong)sgp);
6785 printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt,
6786 sgp->queue_cnt);
6787 for (i = 0; i < sgp->entry_cnt; i++) {
6788 printk(" [%u]: addr 0x%lx, bytes %lu\n",
6789 i, (ulong)le32_to_cpu(sgp->sg_list[i].addr),
6790 (ulong)le32_to_cpu(sgp->sg_list[i].bytes));
6791 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006792
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006793 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006794}
6795
6796/*
6797 * asc_prt_asc_qdone_info()
6798 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006799static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006800{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006801 printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong)q);
6802 printk(" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n",
6803 (ulong)q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
6804 q->d2.tag_code);
6805 printk
6806 (" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n",
6807 q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006808}
6809
6810/*
6811 * asc_prt_adv_dvc_var()
6812 *
6813 * Display an ADV_DVC_VAR structure.
6814 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006815static void asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006816{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006817 printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006818
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006819 printk(" iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n",
6820 (ulong)h->iop_base, h->err_code, (unsigned)h->ultra_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006821
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006822 printk(" isr_callback 0x%lx, sdtr_able 0x%x, wdtr_able 0x%x\n",
6823 (ulong)h->isr_callback, (unsigned)h->sdtr_able,
6824 (unsigned)h->wdtr_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006825
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006826 printk(" start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n",
6827 (unsigned)h->start_motor,
6828 (unsigned)h->scsi_reset_wait, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006829
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006830 printk(" max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n",
6831 (unsigned)h->max_host_qng, (unsigned)h->max_dvc_qng,
6832 (ulong)h->carr_freelist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006833
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006834 printk(" icq_sp 0x%lx, irq_sp 0x%lx\n",
6835 (ulong)h->icq_sp, (ulong)h->irq_sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006836
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006837 printk(" no_scam 0x%x, tagqng_able 0x%x\n",
6838 (unsigned)h->no_scam, (unsigned)h->tagqng_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006839
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006840 printk(" chip_scsi_id 0x%x, cfg 0x%lx\n",
6841 (unsigned)h->chip_scsi_id, (ulong)h->cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006842}
6843
6844/*
6845 * asc_prt_adv_dvc_cfg()
6846 *
6847 * Display an ADV_DVC_CFG structure.
6848 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006849static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006850{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006851 printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006852
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006853 printk(" disc_enable 0x%x, termination 0x%x\n",
6854 h->disc_enable, h->termination);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006855
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006856 printk(" chip_version 0x%x, mcode_date 0x%x\n",
6857 h->chip_version, h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006858
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006859 printk(" mcode_version 0x%x, pci_device_id 0x%x, lib_version %u\n",
6860 h->mcode_version, to_pci_dev(h->dev)->device, h->lib_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006861
Matthew Wilcox13ac2d92007-07-30 08:10:23 -06006862 printk(" control_flag 0x%x\n", h->control_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006863}
6864
6865/*
6866 * asc_prt_adv_scsi_req_q()
6867 *
6868 * Display an ADV_SCSI_REQ_Q structure.
6869 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006870static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006871{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006872 int sg_blk_cnt;
6873 struct asc_sg_block *sg_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006874
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006875 printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006876
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006877 printk(" target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n",
6878 q->target_id, q->target_lun, (ulong)q->srb_ptr, q->a_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006879
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006880 printk(" cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
6881 q->cntl, (ulong)le32_to_cpu(q->data_addr), (ulong)q->vdata_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006882
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006883 printk(" data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
6884 (ulong)le32_to_cpu(q->data_cnt),
6885 (ulong)le32_to_cpu(q->sense_addr), q->sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006886
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006887 printk
6888 (" cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n",
6889 q->cdb_len, q->done_status, q->host_status, q->scsi_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006890
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006891 printk(" sg_working_ix 0x%x, target_cmd %u\n",
6892 q->sg_working_ix, q->target_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006893
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006894 printk(" scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n",
6895 (ulong)le32_to_cpu(q->scsiq_rptr),
6896 (ulong)le32_to_cpu(q->sg_real_addr), (ulong)q->sg_list_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006897
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006898 /* Display the request's ADV_SG_BLOCK structures. */
6899 if (q->sg_list_ptr != NULL) {
6900 sg_blk_cnt = 0;
6901 while (1) {
6902 /*
6903 * 'sg_ptr' is a physical address. Convert it to a virtual
6904 * address by indexing 'sg_blk_cnt' into the virtual address
6905 * array 'sg_list_ptr'.
6906 *
6907 * XXX - Assumes all SG physical blocks are virtually contiguous.
6908 */
6909 sg_ptr =
6910 &(((ADV_SG_BLOCK *)(q->sg_list_ptr))[sg_blk_cnt]);
6911 asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr);
6912 if (sg_ptr->sg_ptr == 0) {
6913 break;
6914 }
6915 sg_blk_cnt++;
6916 }
6917 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006918}
6919
6920/*
6921 * asc_prt_adv_sgblock()
6922 *
6923 * Display an ADV_SG_BLOCK structure.
6924 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006925static void asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006926{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006927 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006928
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006929 printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n",
6930 (ulong)b, sgblockno);
6931 printk(" sg_cnt %u, sg_ptr 0x%lx\n",
6932 b->sg_cnt, (ulong)le32_to_cpu(b->sg_ptr));
6933 ASC_ASSERT(b->sg_cnt <= NO_OF_SG_PER_BLOCK);
6934 if (b->sg_ptr != 0) {
6935 ASC_ASSERT(b->sg_cnt == NO_OF_SG_PER_BLOCK);
6936 }
6937 for (i = 0; i < b->sg_cnt; i++) {
6938 printk(" [%u]: sg_addr 0x%lx, sg_count 0x%lx\n",
6939 i, (ulong)b->sg_list[i].sg_addr,
6940 (ulong)b->sg_list[i].sg_count);
6941 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006942}
6943
6944/*
6945 * asc_prt_hex()
6946 *
6947 * Print hexadecimal output in 4 byte groupings 32 bytes
6948 * or 8 double-words per line.
6949 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006950static void asc_prt_hex(char *f, uchar *s, int l)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006951{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006952 int i;
6953 int j;
6954 int k;
6955 int m;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006956
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006957 printk("%s: (%d bytes)\n", f, l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006958
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006959 for (i = 0; i < l; i += 32) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006960
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006961 /* Display a maximum of 8 double-words per line. */
6962 if ((k = (l - i) / 4) >= 8) {
6963 k = 8;
6964 m = 0;
6965 } else {
6966 m = (l - i) % 4;
6967 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006968
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006969 for (j = 0; j < k; j++) {
6970 printk(" %2.2X%2.2X%2.2X%2.2X",
6971 (unsigned)s[i + (j * 4)],
6972 (unsigned)s[i + (j * 4) + 1],
6973 (unsigned)s[i + (j * 4) + 2],
6974 (unsigned)s[i + (j * 4) + 3]);
6975 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006976
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006977 switch (m) {
6978 case 0:
6979 default:
6980 break;
6981 case 1:
6982 printk(" %2.2X", (unsigned)s[i + (j * 4)]);
6983 break;
6984 case 2:
6985 printk(" %2.2X%2.2X",
6986 (unsigned)s[i + (j * 4)],
6987 (unsigned)s[i + (j * 4) + 1]);
6988 break;
6989 case 3:
6990 printk(" %2.2X%2.2X%2.2X",
6991 (unsigned)s[i + (j * 4) + 1],
6992 (unsigned)s[i + (j * 4) + 2],
6993 (unsigned)s[i + (j * 4) + 3]);
6994 break;
6995 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006996
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006997 printk("\n");
6998 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006999}
7000#endif /* ADVANSYS_DEBUG */
7001
7002/*
7003 * --- Asc Library Functions
7004 */
7005
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007006static ushort __devinit AscGetEisaChipCfg(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007007{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007008 PortAddr eisa_cfg_iop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007009
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007010 eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
7011 (PortAddr) (ASC_EISA_CFG_IOP_MASK);
7012 return (inpw(eisa_cfg_iop));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007013}
7014
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007015static uchar __devinit AscSetChipScsiID(PortAddr iop_base, uchar new_host_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007016{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007017 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007018
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007019 if (AscGetChipScsiID(iop_base) == new_host_id) {
7020 return (new_host_id);
7021 }
7022 cfg_lsw = AscGetChipCfgLsw(iop_base);
7023 cfg_lsw &= 0xF8FF;
7024 cfg_lsw |= (ushort)((new_host_id & ASC_MAX_TID) << 8);
7025 AscSetChipCfgLsw(iop_base, cfg_lsw);
7026 return (AscGetChipScsiID(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007027}
7028
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007029static unsigned char __devinit AscGetChipScsiCtrl(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007030{
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007031 unsigned char sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007032
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007033 AscSetBank(iop_base, 1);
7034 sc = inp(iop_base + IOP_REG_SC);
7035 AscSetBank(iop_base, 0);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007036 return sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007037}
7038
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007039static unsigned char __devinit
7040AscGetChipVersion(PortAddr iop_base, unsigned short bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007041{
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007042 if (bus_type & ASC_IS_EISA) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007043 PortAddr eisa_iop;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007044 unsigned char revision;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007045 eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
7046 (PortAddr) ASC_EISA_REV_IOP_MASK;
7047 revision = inp(eisa_iop);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007048 return ASC_CHIP_MIN_VER_EISA - 1 + revision;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007049 }
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007050 return AscGetChipVerNo(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007051}
7052
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007053static ASC_DCNT
7054AscLoadMicroCode(PortAddr iop_base,
7055 ushort s_addr, uchar *mcode_buf, ushort mcode_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007056{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007057 ASC_DCNT chksum;
7058 ushort mcode_word_size;
7059 ushort mcode_chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007060
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007061 /* Write the microcode buffer starting at LRAM address 0. */
7062 mcode_word_size = (ushort)(mcode_size >> 1);
7063 AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
7064 AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007065
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007066 chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size);
7067 ASC_DBG1(1, "AscLoadMicroCode: chksum 0x%lx\n", (ulong)chksum);
7068 mcode_chksum = (ushort)AscMemSumLramWord(iop_base,
7069 (ushort)ASC_CODE_SEC_BEG,
7070 (ushort)((mcode_size -
7071 s_addr - (ushort)
7072 ASC_CODE_SEC_BEG) /
7073 2));
7074 ASC_DBG1(1, "AscLoadMicroCode: mcode_chksum 0x%lx\n",
7075 (ulong)mcode_chksum);
7076 AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum);
7077 AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size);
7078 return (chksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007079}
7080
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007081static int AscFindSignature(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007082{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007083 ushort sig_word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007084
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007085 ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureByte(0x%x) 0x%x\n",
7086 iop_base, AscGetChipSignatureByte(iop_base));
7087 if (AscGetChipSignatureByte(iop_base) == (uchar)ASC_1000_ID1B) {
7088 ASC_DBG2(1,
7089 "AscFindSignature: AscGetChipSignatureWord(0x%x) 0x%x\n",
7090 iop_base, AscGetChipSignatureWord(iop_base));
7091 sig_word = AscGetChipSignatureWord(iop_base);
7092 if ((sig_word == (ushort)ASC_1000_ID0W) ||
7093 (sig_word == (ushort)ASC_1000_ID0W_FIX)) {
7094 return (1);
7095 }
7096 }
7097 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007098}
7099
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007100static void __devinit AscToggleIRQAct(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007101{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007102 AscSetChipStatus(iop_base, CIW_IRQ_ACT);
7103 AscSetChipStatus(iop_base, 0);
7104 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007105}
7106
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007107static uchar __devinit AscGetChipIRQ(PortAddr iop_base, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007108{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007109 ushort cfg_lsw;
7110 uchar chip_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007111
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007112 if ((bus_type & ASC_IS_EISA) != 0) {
7113 cfg_lsw = AscGetEisaChipCfg(iop_base);
7114 chip_irq = (uchar)(((cfg_lsw >> 8) & 0x07) + 10);
7115 if ((chip_irq == 13) || (chip_irq > 15)) {
7116 return (0);
7117 }
7118 return (chip_irq);
7119 }
7120 if ((bus_type & ASC_IS_VL) != 0) {
7121 cfg_lsw = AscGetChipCfgLsw(iop_base);
7122 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x07));
7123 if ((chip_irq == 0) || (chip_irq == 4) || (chip_irq == 7)) {
7124 return (0);
7125 }
7126 return ((uchar)(chip_irq + (ASC_MIN_IRQ_NO - 1)));
7127 }
7128 cfg_lsw = AscGetChipCfgLsw(iop_base);
7129 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x03));
7130 if (chip_irq == 3)
7131 chip_irq += (uchar)2;
7132 return ((uchar)(chip_irq + ASC_MIN_IRQ_NO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007133}
7134
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007135static uchar __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007136AscSetChipIRQ(PortAddr iop_base, uchar irq_no, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007137{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007138 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007139
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007140 if ((bus_type & ASC_IS_VL) != 0) {
7141 if (irq_no != 0) {
7142 if ((irq_no < ASC_MIN_IRQ_NO)
7143 || (irq_no > ASC_MAX_IRQ_NO)) {
7144 irq_no = 0;
7145 } else {
7146 irq_no -= (uchar)((ASC_MIN_IRQ_NO - 1));
7147 }
7148 }
7149 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE3);
7150 cfg_lsw |= (ushort)0x0010;
7151 AscSetChipCfgLsw(iop_base, cfg_lsw);
7152 AscToggleIRQAct(iop_base);
7153 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE0);
7154 cfg_lsw |= (ushort)((irq_no & 0x07) << 2);
7155 AscSetChipCfgLsw(iop_base, cfg_lsw);
7156 AscToggleIRQAct(iop_base);
7157 return (AscGetChipIRQ(iop_base, bus_type));
7158 }
7159 if ((bus_type & (ASC_IS_ISA)) != 0) {
7160 if (irq_no == 15)
7161 irq_no -= (uchar)2;
7162 irq_no -= (uchar)ASC_MIN_IRQ_NO;
7163 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFF3);
7164 cfg_lsw |= (ushort)((irq_no & 0x03) << 2);
7165 AscSetChipCfgLsw(iop_base, cfg_lsw);
7166 return (AscGetChipIRQ(iop_base, bus_type));
7167 }
7168 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007169}
7170
7171#ifdef CONFIG_ISA
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007172static void __devinit AscEnableIsaDma(uchar dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007173{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007174 if (dma_channel < 4) {
7175 outp(0x000B, (ushort)(0xC0 | dma_channel));
7176 outp(0x000A, dma_channel);
7177 } else if (dma_channel < 8) {
7178 outp(0x00D6, (ushort)(0xC0 | (dma_channel - 4)));
7179 outp(0x00D4, (ushort)(dma_channel - 4));
7180 }
7181 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007182}
7183#endif /* CONFIG_ISA */
7184
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007185static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007186{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007187 EXT_MSG ext_msg;
7188 EXT_MSG out_msg;
7189 ushort halt_q_addr;
7190 int sdtr_accept;
7191 ushort int_halt_code;
7192 ASC_SCSI_BIT_ID_TYPE scsi_busy;
7193 ASC_SCSI_BIT_ID_TYPE target_id;
7194 PortAddr iop_base;
7195 uchar tag_code;
7196 uchar q_status;
7197 uchar halt_qp;
7198 uchar sdtr_data;
7199 uchar target_ix;
7200 uchar q_cntl, tid_no;
7201 uchar cur_dvc_qng;
7202 uchar asyn_sdtr;
7203 uchar scsi_status;
7204 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007205
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007206 ASC_ASSERT(asc_dvc->drv_ptr != NULL);
7207 boardp = asc_dvc->drv_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007208
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007209 iop_base = asc_dvc->iop_base;
7210 int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007211
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007212 halt_qp = AscReadLramByte(iop_base, ASCV_CURCDB_B);
7213 halt_q_addr = ASC_QNO_TO_QADDR(halt_qp);
7214 target_ix = AscReadLramByte(iop_base,
7215 (ushort)(halt_q_addr +
7216 (ushort)ASC_SCSIQ_B_TARGET_IX));
7217 q_cntl =
7218 AscReadLramByte(iop_base,
7219 (ushort)(halt_q_addr + (ushort)ASC_SCSIQ_B_CNTL));
7220 tid_no = ASC_TIX_TO_TID(target_ix);
7221 target_id = (uchar)ASC_TID_TO_TARGET_ID(tid_no);
7222 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
7223 asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB;
7224 } else {
7225 asyn_sdtr = 0;
7226 }
7227 if (int_halt_code == ASC_HALT_DISABLE_ASYN_USE_SYN_FIX) {
7228 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
7229 AscSetChipSDTR(iop_base, 0, tid_no);
7230 boardp->sdtr_data[tid_no] = 0;
7231 }
7232 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
7233 return (0);
7234 } else if (int_halt_code == ASC_HALT_ENABLE_ASYN_USE_SYN_FIX) {
7235 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
7236 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
7237 boardp->sdtr_data[tid_no] = asyn_sdtr;
7238 }
7239 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
7240 return (0);
7241 } else if (int_halt_code == ASC_HALT_EXTMSG_IN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007242
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007243 AscMemWordCopyPtrFromLram(iop_base,
7244 ASCV_MSGIN_BEG,
7245 (uchar *)&ext_msg,
7246 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007247
Matthew Wilcox47d853c2007-07-26 11:41:33 -04007248 if (ext_msg.msg_type == EXTENDED_MESSAGE &&
7249 ext_msg.msg_req == EXTENDED_SDTR &&
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007250 ext_msg.msg_len == MS_SDTR_LEN) {
7251 sdtr_accept = TRUE;
7252 if ((ext_msg.req_ack_offset > ASC_SYN_MAX_OFFSET)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007253
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007254 sdtr_accept = FALSE;
7255 ext_msg.req_ack_offset = ASC_SYN_MAX_OFFSET;
7256 }
7257 if ((ext_msg.xfer_period <
7258 asc_dvc->sdtr_period_tbl[asc_dvc->
7259 host_init_sdtr_index])
7260 || (ext_msg.xfer_period >
7261 asc_dvc->sdtr_period_tbl[asc_dvc->
7262 max_sdtr_index])) {
7263 sdtr_accept = FALSE;
7264 ext_msg.xfer_period =
7265 asc_dvc->sdtr_period_tbl[asc_dvc->
7266 host_init_sdtr_index];
7267 }
7268 if (sdtr_accept) {
7269 sdtr_data =
7270 AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
7271 ext_msg.req_ack_offset);
7272 if ((sdtr_data == 0xFF)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007273
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007274 q_cntl |= QC_MSG_OUT;
7275 asc_dvc->init_sdtr &= ~target_id;
7276 asc_dvc->sdtr_done &= ~target_id;
7277 AscSetChipSDTR(iop_base, asyn_sdtr,
7278 tid_no);
7279 boardp->sdtr_data[tid_no] = asyn_sdtr;
7280 }
7281 }
7282 if (ext_msg.req_ack_offset == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007283
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007284 q_cntl &= ~QC_MSG_OUT;
7285 asc_dvc->init_sdtr &= ~target_id;
7286 asc_dvc->sdtr_done &= ~target_id;
7287 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
7288 } else {
7289 if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007290
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007291 q_cntl &= ~QC_MSG_OUT;
7292 asc_dvc->sdtr_done |= target_id;
7293 asc_dvc->init_sdtr |= target_id;
7294 asc_dvc->pci_fix_asyn_xfer &=
7295 ~target_id;
7296 sdtr_data =
7297 AscCalSDTRData(asc_dvc,
7298 ext_msg.xfer_period,
7299 ext_msg.
7300 req_ack_offset);
7301 AscSetChipSDTR(iop_base, sdtr_data,
7302 tid_no);
7303 boardp->sdtr_data[tid_no] = sdtr_data;
7304 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007305
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007306 q_cntl |= QC_MSG_OUT;
7307 AscMsgOutSDTR(asc_dvc,
7308 ext_msg.xfer_period,
7309 ext_msg.req_ack_offset);
7310 asc_dvc->pci_fix_asyn_xfer &=
7311 ~target_id;
7312 sdtr_data =
7313 AscCalSDTRData(asc_dvc,
7314 ext_msg.xfer_period,
7315 ext_msg.
7316 req_ack_offset);
7317 AscSetChipSDTR(iop_base, sdtr_data,
7318 tid_no);
7319 boardp->sdtr_data[tid_no] = sdtr_data;
7320 asc_dvc->sdtr_done |= target_id;
7321 asc_dvc->init_sdtr |= target_id;
7322 }
7323 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007324
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007325 AscWriteLramByte(iop_base,
7326 (ushort)(halt_q_addr +
7327 (ushort)ASC_SCSIQ_B_CNTL),
7328 q_cntl);
7329 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
7330 return (0);
Matthew Wilcox47d853c2007-07-26 11:41:33 -04007331 } else if (ext_msg.msg_type == EXTENDED_MESSAGE &&
7332 ext_msg.msg_req == EXTENDED_WDTR &&
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007333 ext_msg.msg_len == MS_WDTR_LEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007334
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007335 ext_msg.wdtr_width = 0;
7336 AscMemWordCopyPtrToLram(iop_base,
7337 ASCV_MSGOUT_BEG,
7338 (uchar *)&ext_msg,
7339 sizeof(EXT_MSG) >> 1);
7340 q_cntl |= QC_MSG_OUT;
7341 AscWriteLramByte(iop_base,
7342 (ushort)(halt_q_addr +
7343 (ushort)ASC_SCSIQ_B_CNTL),
7344 q_cntl);
7345 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
7346 return (0);
7347 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007348
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007349 ext_msg.msg_type = MESSAGE_REJECT;
7350 AscMemWordCopyPtrToLram(iop_base,
7351 ASCV_MSGOUT_BEG,
7352 (uchar *)&ext_msg,
7353 sizeof(EXT_MSG) >> 1);
7354 q_cntl |= QC_MSG_OUT;
7355 AscWriteLramByte(iop_base,
7356 (ushort)(halt_q_addr +
7357 (ushort)ASC_SCSIQ_B_CNTL),
7358 q_cntl);
7359 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
7360 return (0);
7361 }
7362 } else if (int_halt_code == ASC_HALT_CHK_CONDITION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007363
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007364 q_cntl |= QC_REQ_SENSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007365
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007366 if ((asc_dvc->init_sdtr & target_id) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007367
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007368 asc_dvc->sdtr_done &= ~target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007369
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007370 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
7371 q_cntl |= QC_MSG_OUT;
7372 AscMsgOutSDTR(asc_dvc,
7373 asc_dvc->
7374 sdtr_period_tbl[(sdtr_data >> 4) &
7375 (uchar)(asc_dvc->
7376 max_sdtr_index -
7377 1)],
7378 (uchar)(sdtr_data & (uchar)
7379 ASC_SYN_MAX_OFFSET));
7380 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007381
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007382 AscWriteLramByte(iop_base,
7383 (ushort)(halt_q_addr +
7384 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007385
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007386 tag_code = AscReadLramByte(iop_base,
7387 (ushort)(halt_q_addr + (ushort)
7388 ASC_SCSIQ_B_TAG_CODE));
7389 tag_code &= 0xDC;
7390 if ((asc_dvc->pci_fix_asyn_xfer & target_id)
7391 && !(asc_dvc->pci_fix_asyn_xfer_always & target_id)
7392 ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007393
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007394 tag_code |= (ASC_TAG_FLAG_DISABLE_DISCONNECT
7395 | ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007396
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007397 }
7398 AscWriteLramByte(iop_base,
7399 (ushort)(halt_q_addr +
7400 (ushort)ASC_SCSIQ_B_TAG_CODE),
7401 tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007402
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007403 q_status = AscReadLramByte(iop_base,
7404 (ushort)(halt_q_addr + (ushort)
7405 ASC_SCSIQ_B_STATUS));
7406 q_status |= (QS_READY | QS_BUSY);
7407 AscWriteLramByte(iop_base,
7408 (ushort)(halt_q_addr +
7409 (ushort)ASC_SCSIQ_B_STATUS),
7410 q_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007411
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007412 scsi_busy = AscReadLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B);
7413 scsi_busy &= ~target_id;
7414 AscWriteLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B, scsi_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007415
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007416 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
7417 return (0);
7418 } else if (int_halt_code == ASC_HALT_SDTR_REJECTED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007419
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007420 AscMemWordCopyPtrFromLram(iop_base,
7421 ASCV_MSGOUT_BEG,
7422 (uchar *)&out_msg,
7423 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007424
Matthew Wilcox47d853c2007-07-26 11:41:33 -04007425 if ((out_msg.msg_type == EXTENDED_MESSAGE) &&
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007426 (out_msg.msg_len == MS_SDTR_LEN) &&
Matthew Wilcox47d853c2007-07-26 11:41:33 -04007427 (out_msg.msg_req == EXTENDED_SDTR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007428
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007429 asc_dvc->init_sdtr &= ~target_id;
7430 asc_dvc->sdtr_done &= ~target_id;
7431 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
7432 boardp->sdtr_data[tid_no] = asyn_sdtr;
7433 }
7434 q_cntl &= ~QC_MSG_OUT;
7435 AscWriteLramByte(iop_base,
7436 (ushort)(halt_q_addr +
7437 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
7438 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
7439 return (0);
7440 } else if (int_halt_code == ASC_HALT_SS_QUEUE_FULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007441
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007442 scsi_status = AscReadLramByte(iop_base,
7443 (ushort)((ushort)halt_q_addr +
7444 (ushort)
7445 ASC_SCSIQ_SCSI_STATUS));
7446 cur_dvc_qng =
7447 AscReadLramByte(iop_base,
7448 (ushort)((ushort)ASC_QADR_BEG +
7449 (ushort)target_ix));
7450 if ((cur_dvc_qng > 0) && (asc_dvc->cur_dvc_qng[tid_no] > 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007451
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007452 scsi_busy = AscReadLramByte(iop_base,
7453 (ushort)ASCV_SCSIBUSY_B);
7454 scsi_busy |= target_id;
7455 AscWriteLramByte(iop_base,
7456 (ushort)ASCV_SCSIBUSY_B, scsi_busy);
7457 asc_dvc->queue_full_or_busy |= target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007458
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007459 if (scsi_status == SAM_STAT_TASK_SET_FULL) {
7460 if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) {
7461 cur_dvc_qng -= 1;
7462 asc_dvc->max_dvc_qng[tid_no] =
7463 cur_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007464
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007465 AscWriteLramByte(iop_base,
7466 (ushort)((ushort)
7467 ASCV_MAX_DVC_QNG_BEG
7468 + (ushort)
7469 tid_no),
7470 cur_dvc_qng);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007471
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007472 /*
7473 * Set the device queue depth to the number of
7474 * active requests when the QUEUE FULL condition
7475 * was encountered.
7476 */
7477 boardp->queue_full |= target_id;
7478 boardp->queue_full_cnt[tid_no] =
7479 cur_dvc_qng;
7480 }
7481 }
7482 }
7483 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
7484 return (0);
7485 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007486#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007487 else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC) {
7488 uchar q_no;
7489 ushort q_addr;
7490 uchar sg_wk_q_no;
7491 uchar first_sg_wk_q_no;
7492 ASC_SCSI_Q *scsiq; /* Ptr to driver request. */
7493 ASC_SG_HEAD *sg_head; /* Ptr to driver SG request. */
7494 ASC_SG_LIST_Q scsi_sg_q; /* Structure written to queue. */
7495 ushort sg_list_dwords;
7496 ushort sg_entry_cnt;
7497 uchar next_qp;
7498 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007499
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007500 q_no = AscReadLramByte(iop_base, (ushort)ASCV_REQ_SG_LIST_QP);
7501 if (q_no == ASC_QLINK_END) {
7502 return (0);
7503 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007504
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007505 q_addr = ASC_QNO_TO_QADDR(q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007506
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007507 /*
7508 * Convert the request's SRB pointer to a host ASC_SCSI_REQ
7509 * structure pointer using a macro provided by the driver.
7510 * The ASC_SCSI_REQ pointer provides a pointer to the
7511 * host ASC_SG_HEAD structure.
7512 */
7513 /* Read request's SRB pointer. */
7514 scsiq = (ASC_SCSI_Q *)
7515 ASC_SRB2SCSIQ(ASC_U32_TO_VADDR(AscReadLramDWord(iop_base,
7516 (ushort)
7517 (q_addr +
7518 ASC_SCSIQ_D_SRBPTR))));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007519
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007520 /*
7521 * Get request's first and working SG queue.
7522 */
7523 sg_wk_q_no = AscReadLramByte(iop_base,
7524 (ushort)(q_addr +
7525 ASC_SCSIQ_B_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007526
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007527 first_sg_wk_q_no = AscReadLramByte(iop_base,
7528 (ushort)(q_addr +
7529 ASC_SCSIQ_B_FIRST_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007530
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007531 /*
7532 * Reset request's working SG queue back to the
7533 * first SG queue.
7534 */
7535 AscWriteLramByte(iop_base,
7536 (ushort)(q_addr +
7537 (ushort)ASC_SCSIQ_B_SG_WK_QP),
7538 first_sg_wk_q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007539
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007540 sg_head = scsiq->sg_head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007541
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007542 /*
7543 * Set sg_entry_cnt to the number of SG elements
7544 * that will be completed on this interrupt.
7545 *
7546 * Note: The allocated SG queues contain ASC_MAX_SG_LIST - 1
7547 * SG elements. The data_cnt and data_addr fields which
7548 * add 1 to the SG element capacity are not used when
7549 * restarting SG handling after a halt.
7550 */
7551 if (scsiq->remain_sg_entry_cnt > (ASC_MAX_SG_LIST - 1)) {
7552 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007553
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007554 /*
7555 * Keep track of remaining number of SG elements that will
7556 * need to be handled on the next interrupt.
7557 */
7558 scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1);
7559 } else {
7560 sg_entry_cnt = scsiq->remain_sg_entry_cnt;
7561 scsiq->remain_sg_entry_cnt = 0;
7562 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007563
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007564 /*
7565 * Copy SG elements into the list of allocated SG queues.
7566 *
7567 * Last index completed is saved in scsiq->next_sg_index.
7568 */
7569 next_qp = first_sg_wk_q_no;
7570 q_addr = ASC_QNO_TO_QADDR(next_qp);
7571 scsi_sg_q.sg_head_qp = q_no;
7572 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
7573 for (i = 0; i < sg_head->queue_cnt; i++) {
7574 scsi_sg_q.seq_no = i + 1;
7575 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
7576 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
7577 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
7578 /*
7579 * After very first SG queue RISC FW uses next
7580 * SG queue first element then checks sg_list_cnt
7581 * against zero and then decrements, so set
7582 * sg_list_cnt 1 less than number of SG elements
7583 * in each SG queue.
7584 */
7585 scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
7586 scsi_sg_q.sg_cur_list_cnt =
7587 ASC_SG_LIST_PER_Q - 1;
7588 } else {
7589 /*
7590 * This is the last SG queue in the list of
7591 * allocated SG queues. If there are more
7592 * SG elements than will fit in the allocated
7593 * queues, then set the QCSG_SG_XFER_MORE flag.
7594 */
7595 if (scsiq->remain_sg_entry_cnt != 0) {
7596 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
7597 } else {
7598 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
7599 }
7600 /* equals sg_entry_cnt * 2 */
7601 sg_list_dwords = sg_entry_cnt << 1;
7602 scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
7603 scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
7604 sg_entry_cnt = 0;
7605 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007606
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007607 scsi_sg_q.q_no = next_qp;
7608 AscMemWordCopyPtrToLram(iop_base,
7609 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
7610 (uchar *)&scsi_sg_q,
7611 sizeof(ASC_SG_LIST_Q) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007612
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007613 AscMemDWordCopyPtrToLram(iop_base,
7614 q_addr + ASC_SGQ_LIST_BEG,
7615 (uchar *)&sg_head->
7616 sg_list[scsiq->next_sg_index],
7617 sg_list_dwords);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007618
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007619 scsiq->next_sg_index += ASC_SG_LIST_PER_Q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007620
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007621 /*
7622 * If the just completed SG queue contained the
7623 * last SG element, then no more SG queues need
7624 * to be written.
7625 */
7626 if (scsi_sg_q.cntl & QCSG_SG_XFER_END) {
7627 break;
7628 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007629
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007630 next_qp = AscReadLramByte(iop_base,
7631 (ushort)(q_addr +
7632 ASC_SCSIQ_B_FWD));
7633 q_addr = ASC_QNO_TO_QADDR(next_qp);
7634 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007635
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007636 /*
7637 * Clear the halt condition so the RISC will be restarted
7638 * after the return.
7639 */
7640 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
7641 return (0);
7642 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007643#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007644 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007645}
7646
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007647static uchar
7648_AscCopyLramScsiDoneQ(PortAddr iop_base,
7649 ushort q_addr,
7650 ASC_QDONE_INFO *scsiq, ASC_DCNT max_dma_count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007651{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007652 ushort _val;
7653 uchar sg_queue_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007654
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007655 DvcGetQinfo(iop_base,
7656 q_addr + ASC_SCSIQ_DONE_INFO_BEG,
7657 (uchar *)scsiq,
7658 (sizeof(ASC_SCSIQ_2) + sizeof(ASC_SCSIQ_3)) / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007659
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007660 _val = AscReadLramWord(iop_base,
7661 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS));
7662 scsiq->q_status = (uchar)_val;
7663 scsiq->q_no = (uchar)(_val >> 8);
7664 _val = AscReadLramWord(iop_base,
7665 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_CNTL));
7666 scsiq->cntl = (uchar)_val;
7667 sg_queue_cnt = (uchar)(_val >> 8);
7668 _val = AscReadLramWord(iop_base,
7669 (ushort)(q_addr +
7670 (ushort)ASC_SCSIQ_B_SENSE_LEN));
7671 scsiq->sense_len = (uchar)_val;
7672 scsiq->extra_bytes = (uchar)(_val >> 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007673
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007674 /*
7675 * Read high word of remain bytes from alternate location.
7676 */
7677 scsiq->remain_bytes = (((ADV_DCNT)AscReadLramWord(iop_base,
7678 (ushort)(q_addr +
7679 (ushort)
7680 ASC_SCSIQ_W_ALT_DC1)))
7681 << 16);
7682 /*
7683 * Read low word of remain bytes from original location.
7684 */
7685 scsiq->remain_bytes += AscReadLramWord(iop_base,
7686 (ushort)(q_addr + (ushort)
7687 ASC_SCSIQ_DW_REMAIN_XFER_CNT));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007688
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007689 scsiq->remain_bytes &= max_dma_count;
7690 return (sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007691}
7692
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007693static int AscIsrQDone(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007694{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007695 uchar next_qp;
7696 uchar n_q_used;
7697 uchar sg_list_qp;
7698 uchar sg_queue_cnt;
7699 uchar q_cnt;
7700 uchar done_q_tail;
7701 uchar tid_no;
7702 ASC_SCSI_BIT_ID_TYPE scsi_busy;
7703 ASC_SCSI_BIT_ID_TYPE target_id;
7704 PortAddr iop_base;
7705 ushort q_addr;
7706 ushort sg_q_addr;
7707 uchar cur_target_qng;
7708 ASC_QDONE_INFO scsiq_buf;
7709 ASC_QDONE_INFO *scsiq;
7710 int false_overrun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007711
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007712 iop_base = asc_dvc->iop_base;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007713 n_q_used = 1;
7714 scsiq = (ASC_QDONE_INFO *)&scsiq_buf;
7715 done_q_tail = (uchar)AscGetVarDoneQTail(iop_base);
7716 q_addr = ASC_QNO_TO_QADDR(done_q_tail);
7717 next_qp = AscReadLramByte(iop_base,
7718 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_FWD));
7719 if (next_qp != ASC_QLINK_END) {
7720 AscPutVarDoneQTail(iop_base, next_qp);
7721 q_addr = ASC_QNO_TO_QADDR(next_qp);
7722 sg_queue_cnt = _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq,
7723 asc_dvc->max_dma_count);
7724 AscWriteLramByte(iop_base,
7725 (ushort)(q_addr +
7726 (ushort)ASC_SCSIQ_B_STATUS),
7727 (uchar)(scsiq->
7728 q_status & (uchar)~(QS_READY |
7729 QS_ABORTED)));
7730 tid_no = ASC_TIX_TO_TID(scsiq->d2.target_ix);
7731 target_id = ASC_TIX_TO_TARGET_ID(scsiq->d2.target_ix);
7732 if ((scsiq->cntl & QC_SG_HEAD) != 0) {
7733 sg_q_addr = q_addr;
7734 sg_list_qp = next_qp;
7735 for (q_cnt = 0; q_cnt < sg_queue_cnt; q_cnt++) {
7736 sg_list_qp = AscReadLramByte(iop_base,
7737 (ushort)(sg_q_addr
7738 + (ushort)
7739 ASC_SCSIQ_B_FWD));
7740 sg_q_addr = ASC_QNO_TO_QADDR(sg_list_qp);
7741 if (sg_list_qp == ASC_QLINK_END) {
7742 AscSetLibErrorCode(asc_dvc,
7743 ASCQ_ERR_SG_Q_LINKS);
7744 scsiq->d3.done_stat = QD_WITH_ERROR;
7745 scsiq->d3.host_stat =
7746 QHSTA_D_QDONE_SG_LIST_CORRUPTED;
7747 goto FATAL_ERR_QDONE;
7748 }
7749 AscWriteLramByte(iop_base,
7750 (ushort)(sg_q_addr + (ushort)
7751 ASC_SCSIQ_B_STATUS),
7752 QS_FREE);
7753 }
7754 n_q_used = sg_queue_cnt + 1;
7755 AscPutVarDoneQTail(iop_base, sg_list_qp);
7756 }
7757 if (asc_dvc->queue_full_or_busy & target_id) {
7758 cur_target_qng = AscReadLramByte(iop_base,
7759 (ushort)((ushort)
7760 ASC_QADR_BEG
7761 + (ushort)
7762 scsiq->d2.
7763 target_ix));
7764 if (cur_target_qng < asc_dvc->max_dvc_qng[tid_no]) {
7765 scsi_busy = AscReadLramByte(iop_base, (ushort)
7766 ASCV_SCSIBUSY_B);
7767 scsi_busy &= ~target_id;
7768 AscWriteLramByte(iop_base,
7769 (ushort)ASCV_SCSIBUSY_B,
7770 scsi_busy);
7771 asc_dvc->queue_full_or_busy &= ~target_id;
7772 }
7773 }
7774 if (asc_dvc->cur_total_qng >= n_q_used) {
7775 asc_dvc->cur_total_qng -= n_q_used;
7776 if (asc_dvc->cur_dvc_qng[tid_no] != 0) {
7777 asc_dvc->cur_dvc_qng[tid_no]--;
7778 }
7779 } else {
7780 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CUR_QNG);
7781 scsiq->d3.done_stat = QD_WITH_ERROR;
7782 goto FATAL_ERR_QDONE;
7783 }
7784 if ((scsiq->d2.srb_ptr == 0UL) ||
7785 ((scsiq->q_status & QS_ABORTED) != 0)) {
7786 return (0x11);
7787 } else if (scsiq->q_status == QS_DONE) {
7788 false_overrun = FALSE;
7789 if (scsiq->extra_bytes != 0) {
7790 scsiq->remain_bytes +=
7791 (ADV_DCNT)scsiq->extra_bytes;
7792 }
7793 if (scsiq->d3.done_stat == QD_WITH_ERROR) {
7794 if (scsiq->d3.host_stat ==
7795 QHSTA_M_DATA_OVER_RUN) {
7796 if ((scsiq->
7797 cntl & (QC_DATA_IN | QC_DATA_OUT))
7798 == 0) {
7799 scsiq->d3.done_stat =
7800 QD_NO_ERROR;
7801 scsiq->d3.host_stat =
7802 QHSTA_NO_ERROR;
7803 } else if (false_overrun) {
7804 scsiq->d3.done_stat =
7805 QD_NO_ERROR;
7806 scsiq->d3.host_stat =
7807 QHSTA_NO_ERROR;
7808 }
7809 } else if (scsiq->d3.host_stat ==
7810 QHSTA_M_HUNG_REQ_SCSI_BUS_RESET) {
7811 AscStopChip(iop_base);
7812 AscSetChipControl(iop_base,
7813 (uchar)(CC_SCSI_RESET
7814 | CC_HALT));
7815 DvcDelayNanoSecond(asc_dvc, 60000);
7816 AscSetChipControl(iop_base, CC_HALT);
7817 AscSetChipStatus(iop_base,
7818 CIW_CLR_SCSI_RESET_INT);
7819 AscSetChipStatus(iop_base, 0);
7820 AscSetChipControl(iop_base, 0);
7821 }
7822 }
7823 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
Matthew Wilcox895d6b42007-07-26 11:57:06 -04007824 asc_isr_callback(asc_dvc, scsiq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007825 } else {
7826 if ((AscReadLramByte(iop_base,
7827 (ushort)(q_addr + (ushort)
7828 ASC_SCSIQ_CDB_BEG))
7829 == START_STOP)) {
7830 asc_dvc->unit_not_ready &= ~target_id;
7831 if (scsiq->d3.done_stat != QD_NO_ERROR) {
7832 asc_dvc->start_motor &=
7833 ~target_id;
7834 }
7835 }
7836 }
7837 return (1);
7838 } else {
7839 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS);
7840 FATAL_ERR_QDONE:
7841 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
Matthew Wilcox895d6b42007-07-26 11:57:06 -04007842 asc_isr_callback(asc_dvc, scsiq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007843 }
7844 return (0x80);
7845 }
7846 }
7847 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007848}
7849
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007850static int AscISR(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007851{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007852 ASC_CS_TYPE chipstat;
7853 PortAddr iop_base;
7854 ushort saved_ram_addr;
7855 uchar ctrl_reg;
7856 uchar saved_ctrl_reg;
7857 int int_pending;
7858 int status;
7859 uchar host_flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007860
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007861 iop_base = asc_dvc->iop_base;
7862 int_pending = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007863
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007864 if (AscIsIntPending(iop_base) == 0) {
7865 return int_pending;
7866 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007867
Matthew Wilcox895d6b42007-07-26 11:57:06 -04007868 if ((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007869 return (ERR);
7870 }
7871 if (asc_dvc->in_critical_cnt != 0) {
7872 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL);
7873 return (ERR);
7874 }
7875 if (asc_dvc->is_in_int) {
7876 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY);
7877 return (ERR);
7878 }
7879 asc_dvc->is_in_int = TRUE;
7880 ctrl_reg = AscGetChipControl(iop_base);
7881 saved_ctrl_reg = ctrl_reg & (~(CC_SCSI_RESET | CC_CHIP_RESET |
7882 CC_SINGLE_STEP | CC_DIAG | CC_TEST));
7883 chipstat = AscGetChipStatus(iop_base);
7884 if (chipstat & CSW_SCSI_RESET_LATCH) {
7885 if (!(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))) {
7886 int i = 10;
7887 int_pending = TRUE;
7888 asc_dvc->sdtr_done = 0;
7889 saved_ctrl_reg &= (uchar)(~CC_HALT);
7890 while ((AscGetChipStatus(iop_base) &
7891 CSW_SCSI_RESET_ACTIVE) && (i-- > 0)) {
7892 DvcSleepMilliSecond(100);
7893 }
7894 AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT));
7895 AscSetChipControl(iop_base, CC_HALT);
7896 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
7897 AscSetChipStatus(iop_base, 0);
7898 chipstat = AscGetChipStatus(iop_base);
7899 }
7900 }
7901 saved_ram_addr = AscGetChipLramAddr(iop_base);
7902 host_flag = AscReadLramByte(iop_base,
7903 ASCV_HOST_FLAG_B) &
7904 (uchar)(~ASC_HOST_FLAG_IN_ISR);
7905 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
7906 (uchar)(host_flag | (uchar)ASC_HOST_FLAG_IN_ISR));
7907 if ((chipstat & CSW_INT_PENDING)
7908 || (int_pending)
7909 ) {
7910 AscAckInterrupt(iop_base);
7911 int_pending = TRUE;
7912 if ((chipstat & CSW_HALTED) && (ctrl_reg & CC_SINGLE_STEP)) {
7913 if (AscIsrChipHalted(asc_dvc) == ERR) {
7914 goto ISR_REPORT_QDONE_FATAL_ERROR;
7915 } else {
7916 saved_ctrl_reg &= (uchar)(~CC_HALT);
7917 }
7918 } else {
7919 ISR_REPORT_QDONE_FATAL_ERROR:
7920 if ((asc_dvc->dvc_cntl & ASC_CNTL_INT_MULTI_Q) != 0) {
7921 while (((status =
7922 AscIsrQDone(asc_dvc)) & 0x01) != 0) {
7923 }
7924 } else {
7925 do {
7926 if ((status =
7927 AscIsrQDone(asc_dvc)) == 1) {
7928 break;
7929 }
7930 } while (status == 0x11);
7931 }
7932 if ((status & 0x80) != 0)
7933 int_pending = ERR;
7934 }
7935 }
7936 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
7937 AscSetChipLramAddr(iop_base, saved_ram_addr);
7938 AscSetChipControl(iop_base, saved_ctrl_reg);
7939 asc_dvc->is_in_int = FALSE;
7940 return (int_pending);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007941}
7942
7943/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007944static uchar _asc_mcode_buf[] = {
7945 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007946 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007947 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007948 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007949 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7950 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x12, 0x0D, 0x05,
7951 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7952 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007953 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007954 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
7955 0x00, 0x00, 0xE4, 0x88, 0x00, 0x00, 0x00, 0x00, 0x80, 0x73, 0x48, 0x04,
7956 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73, 0x03, 0x23, 0x36, 0x40,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007957 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007958 0xC2, 0x00, 0x92, 0x80, 0x1E, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x48, 0x98,
7959 0xDF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, 0x4F, 0x00, 0xF5, 0x00,
7960 0x48, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, 0x80, 0x62,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007961 0x92, 0x80, 0x00, 0x46, 0x15, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007962 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xD6, 0x00, 0xA6, 0x97, 0x7F, 0x23,
7963 0x04, 0x61, 0x84, 0x01, 0xE6, 0x84, 0xD2, 0xC1, 0x80, 0x73, 0xCD, 0x04,
7964 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x01, 0xA6, 0x97, 0xC6, 0x81, 0xC2, 0x88,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007965 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0xFE, 0x00, 0x4F, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007966 0x84, 0x97, 0x07, 0xA6, 0x08, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88,
7967 0x03, 0x03, 0x01, 0xDE, 0xC2, 0x88, 0xCE, 0x00, 0x69, 0x60, 0xCE, 0x00,
7968 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x78, 0x01, 0x80, 0x63, 0x07, 0xA6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007969 0x24, 0x01, 0x78, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007970 0x34, 0x01, 0x00, 0x33, 0x04, 0x00, 0xC2, 0x88, 0x03, 0x07, 0x02, 0x01,
7971 0x04, 0xCA, 0x0D, 0x23, 0x68, 0x98, 0x4D, 0x04, 0x04, 0x85, 0x05, 0xD8,
7972 0x0D, 0x23, 0x68, 0x98, 0xCD, 0x04, 0x15, 0x23, 0xF8, 0x88, 0xFB, 0x23,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007973 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x62, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007974 0x00, 0x33, 0x0A, 0x00, 0xC2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x6E, 0x01,
7975 0x00, 0x33, 0x0B, 0x00, 0xC2, 0x88, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33,
7976 0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x88, 0x81, 0x06, 0xAB, 0x82, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007977 0x88, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x92, 0x01, 0x50, 0x00, 0x00, 0xA3,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007978 0x3C, 0x01, 0x00, 0x05, 0x7C, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6,
7979 0x04, 0x23, 0xA0, 0x01, 0x15, 0x23, 0xA1, 0x01, 0xBE, 0x81, 0xFD, 0x23,
7980 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007981 0xB4, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007982 0xC2, 0x88, 0x06, 0x23, 0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01,
7983 0x00, 0xA2, 0xD4, 0x01, 0x57, 0x60, 0x00, 0xA0, 0xDA, 0x01, 0xE6, 0x84,
7984 0x80, 0x23, 0xA0, 0x01, 0xE6, 0x84, 0x80, 0x73, 0x4B, 0x00, 0x06, 0x61,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007985 0x00, 0xA2, 0x00, 0x02, 0x04, 0x01, 0x0C, 0xDE, 0x02, 0x01, 0x03, 0xCC,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007986 0x4F, 0x00, 0x84, 0x97, 0xFC, 0x81, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01,
7987 0x4F, 0x00, 0x62, 0x97, 0x48, 0x04, 0x84, 0x80, 0xF0, 0x97, 0x00, 0x46,
7988 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00, 0x81, 0x73, 0x06, 0x29,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007989 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x6B, 0xEB, 0x11, 0x23, 0xF8, 0x88,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007990 0x04, 0x98, 0xF0, 0x80, 0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x2A, 0x02,
7991 0x7C, 0x95, 0x06, 0xA6, 0x34, 0x02, 0x03, 0xA6, 0x4C, 0x04, 0x46, 0x82,
7992 0x04, 0x01, 0x03, 0xD8, 0xB4, 0x98, 0x6A, 0x96, 0x46, 0x82, 0xFE, 0x95,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007993 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x6C, 0x02,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007994 0x07, 0xA6, 0x5A, 0x02, 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x62, 0x02,
7995 0xC2, 0x88, 0x7C, 0x95, 0x48, 0x82, 0x60, 0x96, 0x48, 0x82, 0x04, 0x23,
7996 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84, 0x04, 0x01, 0x0C, 0xDC,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007997 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007998 0x6F, 0x00, 0xA5, 0x01, 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01,
7999 0x24, 0x2B, 0x1C, 0x01, 0x02, 0xA6, 0xAA, 0x02, 0x07, 0xA6, 0x5A, 0x02,
8000 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x20, 0x04, 0x01, 0xA6, 0xB4, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008001 0x00, 0xA6, 0xB4, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008002 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0x8C, 0x02, 0x4D, 0x04, 0x04, 0x01,
8003 0x0B, 0xDC, 0xE7, 0x23, 0x04, 0x61, 0x84, 0x01, 0x10, 0x31, 0x12, 0x35,
8004 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0xEA, 0x82,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008005 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0xA2, 0xC8,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008006 0x00, 0x33, 0x1F, 0x00, 0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39,
8007 0x0E, 0x3D, 0x7E, 0x98, 0xB6, 0x2D, 0x01, 0xA6, 0x14, 0x03, 0x00, 0xA6,
8008 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6, 0x10, 0x03, 0x03, 0xA6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008009 0x20, 0x04, 0x02, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008010 0x7C, 0x95, 0xEE, 0x82, 0x60, 0x96, 0xEE, 0x82, 0x82, 0x98, 0x80, 0x42,
8011 0x7E, 0x98, 0x64, 0xE4, 0x04, 0x01, 0x2D, 0xC8, 0x31, 0x05, 0x07, 0x01,
8012 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01, 0x05, 0x05, 0x86, 0x98,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008013 0x7E, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008014 0x3C, 0x04, 0x06, 0xA6, 0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33,
8015 0x25, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x32, 0x83, 0x60, 0x96, 0x32, 0x83,
8016 0x04, 0x01, 0x10, 0xCE, 0x07, 0xC8, 0x05, 0x05, 0xEB, 0x04, 0x00, 0x33,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008017 0x00, 0x20, 0xC0, 0x20, 0x81, 0x62, 0x72, 0x83, 0x00, 0x01, 0x05, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008018 0xFF, 0xA2, 0x7A, 0x03, 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83,
8019 0x05, 0x05, 0x15, 0x01, 0x00, 0xA2, 0x9A, 0x03, 0xEC, 0x00, 0x6E, 0x00,
8020 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0x01, 0xA6, 0x96, 0x03,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008021 0x00, 0xA6, 0x96, 0x03, 0x10, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008022 0xA4, 0x03, 0x00, 0xA6, 0xBC, 0x03, 0x10, 0x84, 0xA8, 0x98, 0x80, 0x42,
8023 0x01, 0xA6, 0xA4, 0x03, 0x07, 0xA6, 0xB2, 0x03, 0xD4, 0x83, 0x7C, 0x95,
8024 0xA8, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC2, 0x88, 0xA8, 0x98, 0x80, 0x42,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008025 0x00, 0xA6, 0xBC, 0x03, 0x07, 0xA6, 0xCA, 0x03, 0xD4, 0x83, 0x7C, 0x95,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008026 0xC0, 0x83, 0x00, 0x33, 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32,
8027 0x80, 0x36, 0x04, 0x23, 0xA0, 0x01, 0x12, 0x23, 0xA1, 0x01, 0x10, 0x84,
8028 0x07, 0xF0, 0x06, 0xA4, 0xF4, 0x03, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008029 0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x0E, 0x04, 0x07, 0xA6, 0x06, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008030 0x06, 0xA6, 0x0A, 0x04, 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x7C, 0x95,
8031 0xF4, 0x83, 0x60, 0x96, 0xF4, 0x83, 0x20, 0x84, 0x07, 0xF0, 0x06, 0xA4,
8032 0x20, 0x04, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23, 0x83, 0x03, 0x80, 0x63,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008033 0xB6, 0x2D, 0x03, 0xA6, 0x3C, 0x04, 0x07, 0xA6, 0x34, 0x04, 0x06, 0xA6,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008034 0x38, 0x04, 0x00, 0x33, 0x30, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x20, 0x84,
8035 0x60, 0x96, 0x20, 0x84, 0x1D, 0x01, 0x06, 0xCC, 0x00, 0x33, 0x00, 0x84,
8036 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62, 0xA2, 0x0D, 0x80, 0x63,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008037 0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008038 0x80, 0x63, 0xA3, 0x01, 0x07, 0xA4, 0x64, 0x04, 0x23, 0x01, 0x00, 0xA2,
8039 0x86, 0x04, 0x0A, 0xA0, 0x76, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1D, 0x00,
8040 0xC2, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1E, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008041 0xC2, 0x88, 0x42, 0x23, 0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008042 0x08, 0x23, 0x22, 0xA3, 0xA2, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xAE, 0x04,
8043 0x02, 0x23, 0x22, 0xA3, 0xC4, 0x04, 0x42, 0x23, 0xF8, 0x88, 0x4A, 0x00,
8044 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23, 0xF8, 0x88, 0x04, 0x98,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008045 0x00, 0xA2, 0xC0, 0x04, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008046 0x81, 0x62, 0xE8, 0x81, 0x47, 0x23, 0xF8, 0x88, 0x04, 0x01, 0x0B, 0xDE,
8047 0x04, 0x98, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x81, 0xC0, 0x20, 0x81, 0x62,
8048 0x14, 0x01, 0x00, 0xA0, 0x00, 0x02, 0x43, 0x23, 0xF8, 0x88, 0x04, 0x23,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008049 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008050 0xF4, 0x04, 0x00, 0x33, 0x27, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x04, 0xDC,
8051 0x02, 0x23, 0xA2, 0x01, 0x04, 0x23, 0xA0, 0x01, 0x04, 0x98, 0x26, 0x95,
8052 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00, 0x00, 0xA3, 0x22, 0x05,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008053 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x1C, 0x05, 0x0A, 0x85,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008054 0x46, 0x97, 0xCD, 0x04, 0x24, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01,
8055 0x03, 0xDA, 0x80, 0x23, 0x82, 0x01, 0x34, 0x85, 0x02, 0x23, 0xA0, 0x01,
8056 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x40, 0x05, 0x1D, 0x01, 0x04, 0xD6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008057 0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008058 0x49, 0x00, 0x81, 0x01, 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01,
8059 0xF7, 0x04, 0x03, 0x01, 0x49, 0x04, 0x80, 0x01, 0xC9, 0x00, 0x00, 0x05,
8060 0x00, 0x01, 0xFF, 0xA0, 0x60, 0x05, 0x77, 0x04, 0x01, 0x23, 0xEA, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008061 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008062 0x07, 0xA4, 0xF8, 0x05, 0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85,
8063 0x00, 0x33, 0x2D, 0x00, 0xC2, 0x88, 0x04, 0xA0, 0xB8, 0x05, 0x80, 0x63,
8064 0x00, 0x23, 0xDF, 0x00, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0xA4, 0x05,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008065 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008066 0x62, 0x97, 0x04, 0x85, 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0x04, 0x85,
8067 0x08, 0xA0, 0xBE, 0x05, 0xF4, 0x85, 0x03, 0xA0, 0xC4, 0x05, 0xF4, 0x85,
8068 0x01, 0xA0, 0xCE, 0x05, 0x88, 0x00, 0x80, 0x63, 0xCC, 0x86, 0x07, 0xA0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008069 0xEE, 0x05, 0x5F, 0x00, 0x00, 0x2B, 0xDF, 0x08, 0x00, 0xA2, 0xE6, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008070 0x80, 0x67, 0x80, 0x63, 0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23,
8071 0x68, 0x98, 0x48, 0x23, 0xF8, 0x88, 0x07, 0x23, 0x80, 0x00, 0x06, 0x87,
8072 0x80, 0x63, 0x7C, 0x85, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63, 0x4A, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008073 0x06, 0x61, 0x00, 0xA2, 0x36, 0x06, 0x1D, 0x01, 0x16, 0xD4, 0xC0, 0x23,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008074 0x07, 0x41, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33,
8075 0x37, 0x00, 0xC2, 0x88, 0x1D, 0x01, 0x01, 0xD6, 0x20, 0x23, 0x63, 0x60,
8076 0x83, 0x03, 0x80, 0x63, 0x02, 0x23, 0xDF, 0x00, 0x07, 0xA6, 0x7C, 0x05,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008077 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008078 0x52, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x4E, 0x06, 0x1D, 0x01, 0x03, 0xCA,
8079 0xC0, 0x23, 0x07, 0x41, 0x00, 0x63, 0x1D, 0x01, 0x04, 0xCC, 0x00, 0x33,
8080 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23, 0x07, 0x41, 0x00, 0x63,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008081 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x01, 0x23,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008082 0xDF, 0x00, 0x06, 0xA6, 0x84, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67,
8083 0x80, 0x63, 0x00, 0x33, 0x00, 0x40, 0xC0, 0x20, 0x81, 0x62, 0x00, 0x63,
8084 0x00, 0x00, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x94, 0x06,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008085 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x00, 0x01, 0xA0, 0x14, 0x07, 0x00, 0x2B,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008086 0x40, 0x0E, 0x80, 0x63, 0x01, 0x00, 0x06, 0xA6, 0xAA, 0x06, 0x07, 0xA6,
8087 0x7C, 0x05, 0x40, 0x0E, 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0xA2, 0x06,
8088 0x06, 0xA6, 0xBC, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x40, 0x0E,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008089 0x80, 0x63, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008090 0x07, 0xA6, 0xD6, 0x06, 0x00, 0x33, 0x2A, 0x00, 0xC2, 0x88, 0x03, 0x03,
8091 0x80, 0x63, 0x89, 0x00, 0x0A, 0x2B, 0x07, 0xA6, 0xE8, 0x06, 0x00, 0x33,
8092 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, 0x00, 0xA2, 0xF4, 0x06, 0xC0, 0x0E,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008093 0x80, 0x63, 0xDE, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008094 0x81, 0x62, 0x04, 0x01, 0x02, 0xDA, 0x80, 0x63, 0x7C, 0x85, 0x80, 0x7B,
8095 0x80, 0x63, 0x06, 0xA6, 0x8C, 0x06, 0x00, 0x33, 0x2C, 0x00, 0xC2, 0x88,
8096 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008097 0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008098 0x00, 0x00, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x44, 0x07,
8099 0x07, 0xA6, 0x7C, 0x05, 0xBF, 0x23, 0x04, 0x61, 0x84, 0x01, 0xE6, 0x84,
8100 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x00, 0x01, 0xF2, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008101 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008102 0x80, 0x05, 0x81, 0x05, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04,
8103 0x01, 0x01, 0xF1, 0x00, 0x70, 0x00, 0x81, 0x01, 0x70, 0x04, 0x71, 0x00,
8104 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04, 0x70, 0x00, 0x80, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008105 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008106 0xF1, 0x00, 0x70, 0x00, 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01,
8107 0x72, 0x00, 0x81, 0x01, 0x71, 0x04, 0x70, 0x00, 0x81, 0x01, 0x70, 0x04,
8108 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05, 0xA3, 0x01, 0xA2, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008109 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008110 0xC4, 0x07, 0x00, 0x33, 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05,
8111 0x04, 0x01, 0x11, 0xC8, 0x48, 0x00, 0xB0, 0x01, 0xB1, 0x01, 0x08, 0x23,
8112 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43, 0x00, 0xA2, 0xE4, 0x07,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008113 0x00, 0x05, 0xDA, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008114 0x05, 0x05, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04,
8115 0x00, 0x02, 0x80, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04, 0x00, 0x63,
8116 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x00, 0xA0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008117 0x14, 0x08, 0x16, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008118 0x00, 0x63, 0xF3, 0x04, 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43,
8119 0xF4, 0x00, 0xCF, 0x40, 0x00, 0xA2, 0x44, 0x08, 0x74, 0x04, 0x02, 0x01,
8120 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1, 0x24, 0x08, 0x04, 0x98,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008121 0x26, 0x95, 0x24, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008122 0x5A, 0x88, 0x02, 0x01, 0x04, 0xD8, 0x46, 0x97, 0x04, 0x98, 0x26, 0x95,
8123 0x4A, 0x88, 0x75, 0x00, 0x00, 0xA3, 0x64, 0x08, 0x00, 0x05, 0x4E, 0x88,
8124 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x76, 0x08,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008125 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008126 0x00, 0x63, 0x38, 0x2B, 0x9C, 0x88, 0x38, 0x2B, 0x92, 0x88, 0x32, 0x09,
8127 0x31, 0x05, 0x92, 0x98, 0x05, 0x05, 0xB2, 0x09, 0x00, 0x63, 0x00, 0x32,
8128 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63, 0x80, 0x32, 0x80, 0x36,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008129 0x80, 0x3A, 0x80, 0x3E, 0xB4, 0x3D, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008130 0x40, 0x36, 0x40, 0x3A, 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40,
8131 0x00, 0xA0, 0xB4, 0x08, 0x5D, 0x00, 0xFE, 0xC3, 0x00, 0x63, 0x80, 0x73,
8132 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73, 0xFF, 0xFD, 0x80, 0x73,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008133 0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008134 0xA1, 0x23, 0xA1, 0x01, 0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77,
8135 0x68, 0x00, 0x00, 0xA2, 0x80, 0x00, 0x03, 0xC2, 0xF1, 0xC7, 0x41, 0x23,
8136 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xE6, 0x84,
Linus Torvalds1da177e2005-04-16 15:20:36 -07008137};
8138
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008139static ushort _asc_mcode_size = sizeof(_asc_mcode_buf);
8140static ADV_DCNT _asc_mcode_chksum = 0x012C453FUL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008141
8142#define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008143static uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = {
8144 INQUIRY,
8145 REQUEST_SENSE,
8146 READ_CAPACITY,
8147 READ_TOC,
8148 MODE_SELECT,
8149 MODE_SENSE,
8150 MODE_SELECT_10,
8151 MODE_SENSE_10,
8152 0xFF,
8153 0xFF,
8154 0xFF,
8155 0xFF,
8156 0xFF,
8157 0xFF,
8158 0xFF,
8159 0xFF
Linus Torvalds1da177e2005-04-16 15:20:36 -07008160};
8161
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008162static int AscExeScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008163{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008164 PortAddr iop_base;
8165 ulong last_int_level;
8166 int sta;
8167 int n_q_required;
8168 int disable_syn_offset_one_fix;
8169 int i;
8170 ASC_PADDR addr;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008171 ushort sg_entry_cnt = 0;
8172 ushort sg_entry_cnt_minus_one = 0;
8173 uchar target_ix;
8174 uchar tid_no;
8175 uchar sdtr_data;
8176 uchar extra_bytes;
8177 uchar scsi_cmd;
8178 uchar disable_cmd;
8179 ASC_SG_HEAD *sg_head;
8180 ASC_DCNT data_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008181
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008182 iop_base = asc_dvc->iop_base;
8183 sg_head = scsiq->sg_head;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008184 if (asc_dvc->err_code != 0)
8185 return (ERR);
8186 if (scsiq == (ASC_SCSI_Q *)0L) {
8187 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_NULL_PTR);
8188 return (ERR);
8189 }
8190 scsiq->q1.q_no = 0;
8191 if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
8192 scsiq->q1.extra_bytes = 0;
8193 }
8194 sta = 0;
8195 target_ix = scsiq->q2.target_ix;
8196 tid_no = ASC_TIX_TO_TID(target_ix);
8197 n_q_required = 1;
8198 if (scsiq->cdbptr[0] == REQUEST_SENSE) {
8199 if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
8200 asc_dvc->sdtr_done &= ~scsiq->q1.target_id;
8201 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
8202 AscMsgOutSDTR(asc_dvc,
8203 asc_dvc->
8204 sdtr_period_tbl[(sdtr_data >> 4) &
8205 (uchar)(asc_dvc->
8206 max_sdtr_index -
8207 1)],
8208 (uchar)(sdtr_data & (uchar)
8209 ASC_SYN_MAX_OFFSET));
8210 scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
8211 }
8212 }
8213 last_int_level = DvcEnterCritical();
8214 if (asc_dvc->in_critical_cnt != 0) {
8215 DvcLeaveCritical(last_int_level);
8216 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY);
8217 return (ERR);
8218 }
8219 asc_dvc->in_critical_cnt++;
8220 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
8221 if ((sg_entry_cnt = sg_head->entry_cnt) == 0) {
8222 asc_dvc->in_critical_cnt--;
8223 DvcLeaveCritical(last_int_level);
8224 return (ERR);
8225 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008226#if !CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008227 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
8228 asc_dvc->in_critical_cnt--;
8229 DvcLeaveCritical(last_int_level);
8230 return (ERR);
8231 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008232#endif /* !CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008233 if (sg_entry_cnt == 1) {
8234 scsiq->q1.data_addr =
8235 (ADV_PADDR)sg_head->sg_list[0].addr;
8236 scsiq->q1.data_cnt =
8237 (ADV_DCNT)sg_head->sg_list[0].bytes;
8238 scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
8239 }
8240 sg_entry_cnt_minus_one = sg_entry_cnt - 1;
8241 }
8242 scsi_cmd = scsiq->cdbptr[0];
8243 disable_syn_offset_one_fix = FALSE;
8244 if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) &&
8245 !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) {
8246 if (scsiq->q1.cntl & QC_SG_HEAD) {
8247 data_cnt = 0;
8248 for (i = 0; i < sg_entry_cnt; i++) {
8249 data_cnt +=
8250 (ADV_DCNT)le32_to_cpu(sg_head->sg_list[i].
8251 bytes);
8252 }
8253 } else {
8254 data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
8255 }
8256 if (data_cnt != 0UL) {
8257 if (data_cnt < 512UL) {
8258 disable_syn_offset_one_fix = TRUE;
8259 } else {
8260 for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST;
8261 i++) {
8262 disable_cmd =
8263 _syn_offset_one_disable_cmd[i];
8264 if (disable_cmd == 0xFF) {
8265 break;
8266 }
8267 if (scsi_cmd == disable_cmd) {
8268 disable_syn_offset_one_fix =
8269 TRUE;
8270 break;
8271 }
8272 }
8273 }
8274 }
8275 }
8276 if (disable_syn_offset_one_fix) {
8277 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
8278 scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX |
8279 ASC_TAG_FLAG_DISABLE_DISCONNECT);
8280 } else {
8281 scsiq->q2.tag_code &= 0x27;
8282 }
8283 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
8284 if (asc_dvc->bug_fix_cntl) {
8285 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
8286 if ((scsi_cmd == READ_6) ||
8287 (scsi_cmd == READ_10)) {
8288 addr =
8289 (ADV_PADDR)le32_to_cpu(sg_head->
8290 sg_list
8291 [sg_entry_cnt_minus_one].
8292 addr) +
8293 (ADV_DCNT)le32_to_cpu(sg_head->
8294 sg_list
8295 [sg_entry_cnt_minus_one].
8296 bytes);
8297 extra_bytes =
8298 (uchar)((ushort)addr & 0x0003);
8299 if ((extra_bytes != 0)
8300 &&
8301 ((scsiq->q2.
8302 tag_code &
8303 ASC_TAG_FLAG_EXTRA_BYTES)
8304 == 0)) {
8305 scsiq->q2.tag_code |=
8306 ASC_TAG_FLAG_EXTRA_BYTES;
8307 scsiq->q1.extra_bytes =
8308 extra_bytes;
8309 data_cnt =
8310 le32_to_cpu(sg_head->
8311 sg_list
8312 [sg_entry_cnt_minus_one].
8313 bytes);
8314 data_cnt -=
8315 (ASC_DCNT) extra_bytes;
8316 sg_head->
8317 sg_list
8318 [sg_entry_cnt_minus_one].
8319 bytes =
8320 cpu_to_le32(data_cnt);
8321 }
8322 }
8323 }
8324 }
8325 sg_head->entry_to_copy = sg_head->entry_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008326#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008327 /*
8328 * Set the sg_entry_cnt to the maximum possible. The rest of
8329 * the SG elements will be copied when the RISC completes the
8330 * SG elements that fit and halts.
8331 */
8332 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
8333 sg_entry_cnt = ASC_MAX_SG_LIST;
8334 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008335#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008336 n_q_required = AscSgListToQueue(sg_entry_cnt);
8337 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
8338 (uint) n_q_required)
8339 || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
8340 if ((sta =
8341 AscSendScsiQueue(asc_dvc, scsiq,
8342 n_q_required)) == 1) {
8343 asc_dvc->in_critical_cnt--;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008344 DvcLeaveCritical(last_int_level);
8345 return (sta);
8346 }
8347 }
8348 } else {
8349 if (asc_dvc->bug_fix_cntl) {
8350 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
8351 if ((scsi_cmd == READ_6) ||
8352 (scsi_cmd == READ_10)) {
8353 addr =
8354 le32_to_cpu(scsiq->q1.data_addr) +
8355 le32_to_cpu(scsiq->q1.data_cnt);
8356 extra_bytes =
8357 (uchar)((ushort)addr & 0x0003);
8358 if ((extra_bytes != 0)
8359 &&
8360 ((scsiq->q2.
8361 tag_code &
8362 ASC_TAG_FLAG_EXTRA_BYTES)
8363 == 0)) {
8364 data_cnt =
8365 le32_to_cpu(scsiq->q1.
8366 data_cnt);
8367 if (((ushort)data_cnt & 0x01FF)
8368 == 0) {
8369 scsiq->q2.tag_code |=
8370 ASC_TAG_FLAG_EXTRA_BYTES;
8371 data_cnt -= (ASC_DCNT)
8372 extra_bytes;
8373 scsiq->q1.data_cnt =
8374 cpu_to_le32
8375 (data_cnt);
8376 scsiq->q1.extra_bytes =
8377 extra_bytes;
8378 }
8379 }
8380 }
8381 }
8382 }
8383 n_q_required = 1;
8384 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) ||
8385 ((scsiq->q1.cntl & QC_URGENT) != 0)) {
8386 if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
8387 n_q_required)) == 1) {
8388 asc_dvc->in_critical_cnt--;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008389 DvcLeaveCritical(last_int_level);
8390 return (sta);
8391 }
8392 }
8393 }
8394 asc_dvc->in_critical_cnt--;
8395 DvcLeaveCritical(last_int_level);
8396 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008397}
8398
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008399static int
8400AscSendScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar n_q_required)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008401{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008402 PortAddr iop_base;
8403 uchar free_q_head;
8404 uchar next_qp;
8405 uchar tid_no;
8406 uchar target_ix;
8407 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008408
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008409 iop_base = asc_dvc->iop_base;
8410 target_ix = scsiq->q2.target_ix;
8411 tid_no = ASC_TIX_TO_TID(target_ix);
8412 sta = 0;
8413 free_q_head = (uchar)AscGetVarFreeQHead(iop_base);
8414 if (n_q_required > 1) {
8415 if ((next_qp = AscAllocMultipleFreeQueue(iop_base,
8416 free_q_head, (uchar)
8417 (n_q_required)))
8418 != (uchar)ASC_QLINK_END) {
8419 asc_dvc->last_q_shortage = 0;
8420 scsiq->sg_head->queue_cnt = n_q_required - 1;
8421 scsiq->q1.q_no = free_q_head;
8422 if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq,
8423 free_q_head)) == 1) {
8424 AscPutVarFreeQHead(iop_base, next_qp);
8425 asc_dvc->cur_total_qng += (uchar)(n_q_required);
8426 asc_dvc->cur_dvc_qng[tid_no]++;
8427 }
8428 return (sta);
8429 }
8430 } else if (n_q_required == 1) {
8431 if ((next_qp = AscAllocFreeQueue(iop_base,
8432 free_q_head)) !=
8433 ASC_QLINK_END) {
8434 scsiq->q1.q_no = free_q_head;
8435 if ((sta = AscPutReadyQueue(asc_dvc, scsiq,
8436 free_q_head)) == 1) {
8437 AscPutVarFreeQHead(iop_base, next_qp);
8438 asc_dvc->cur_total_qng++;
8439 asc_dvc->cur_dvc_qng[tid_no]++;
8440 }
8441 return (sta);
8442 }
8443 }
8444 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008445}
8446
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008447static int AscSgListToQueue(int sg_list)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008448{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008449 int n_sg_list_qs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008450
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008451 n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q);
8452 if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0)
8453 n_sg_list_qs++;
8454 return (n_sg_list_qs + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008455}
8456
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008457static uint
8458AscGetNumOfFreeQueue(ASC_DVC_VAR *asc_dvc, uchar target_ix, uchar n_qs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008459{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008460 uint cur_used_qs;
8461 uint cur_free_qs;
8462 ASC_SCSI_BIT_ID_TYPE target_id;
8463 uchar tid_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008464
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008465 target_id = ASC_TIX_TO_TARGET_ID(target_ix);
8466 tid_no = ASC_TIX_TO_TID(target_ix);
8467 if ((asc_dvc->unit_not_ready & target_id) ||
8468 (asc_dvc->queue_full_or_busy & target_id)) {
8469 return (0);
8470 }
8471 if (n_qs == 1) {
8472 cur_used_qs = (uint) asc_dvc->cur_total_qng +
8473 (uint) asc_dvc->last_q_shortage + (uint) ASC_MIN_FREE_Q;
8474 } else {
8475 cur_used_qs = (uint) asc_dvc->cur_total_qng +
8476 (uint) ASC_MIN_FREE_Q;
8477 }
8478 if ((uint) (cur_used_qs + n_qs) <= (uint) asc_dvc->max_total_qng) {
8479 cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs;
8480 if (asc_dvc->cur_dvc_qng[tid_no] >=
8481 asc_dvc->max_dvc_qng[tid_no]) {
8482 return (0);
8483 }
8484 return (cur_free_qs);
8485 }
8486 if (n_qs > 1) {
8487 if ((n_qs > asc_dvc->last_q_shortage)
8488 && (n_qs <= (asc_dvc->max_total_qng - ASC_MIN_FREE_Q))) {
8489 asc_dvc->last_q_shortage = n_qs;
8490 }
8491 }
8492 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008493}
8494
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008495static int AscPutReadyQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008496{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008497 ushort q_addr;
8498 uchar tid_no;
8499 uchar sdtr_data;
8500 uchar syn_period_ix;
8501 uchar syn_offset;
8502 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008503
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008504 iop_base = asc_dvc->iop_base;
8505 if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) &&
8506 ((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) {
8507 tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix);
8508 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
8509 syn_period_ix =
8510 (sdtr_data >> 4) & (asc_dvc->max_sdtr_index - 1);
8511 syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET;
8512 AscMsgOutSDTR(asc_dvc,
8513 asc_dvc->sdtr_period_tbl[syn_period_ix],
8514 syn_offset);
8515 scsiq->q1.cntl |= QC_MSG_OUT;
8516 }
8517 q_addr = ASC_QNO_TO_QADDR(q_no);
8518 if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) {
8519 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
8520 }
8521 scsiq->q1.status = QS_FREE;
8522 AscMemWordCopyPtrToLram(iop_base,
8523 q_addr + ASC_SCSIQ_CDB_BEG,
8524 (uchar *)scsiq->cdbptr, scsiq->q2.cdb_len >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008525
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008526 DvcPutScsiQ(iop_base,
8527 q_addr + ASC_SCSIQ_CPY_BEG,
8528 (uchar *)&scsiq->q1.cntl,
8529 ((sizeof(ASC_SCSIQ_1) + sizeof(ASC_SCSIQ_2)) / 2) - 1);
8530 AscWriteLramWord(iop_base,
8531 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS),
8532 (ushort)(((ushort)scsiq->q1.
8533 q_no << 8) | (ushort)QS_READY));
8534 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008535}
8536
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008537static int
8538AscPutReadySgListQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008539{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008540 int sta;
8541 int i;
8542 ASC_SG_HEAD *sg_head;
8543 ASC_SG_LIST_Q scsi_sg_q;
8544 ASC_DCNT saved_data_addr;
8545 ASC_DCNT saved_data_cnt;
8546 PortAddr iop_base;
8547 ushort sg_list_dwords;
8548 ushort sg_index;
8549 ushort sg_entry_cnt;
8550 ushort q_addr;
8551 uchar next_qp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008552
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008553 iop_base = asc_dvc->iop_base;
8554 sg_head = scsiq->sg_head;
8555 saved_data_addr = scsiq->q1.data_addr;
8556 saved_data_cnt = scsiq->q1.data_cnt;
8557 scsiq->q1.data_addr = (ASC_PADDR) sg_head->sg_list[0].addr;
8558 scsiq->q1.data_cnt = (ASC_DCNT) sg_head->sg_list[0].bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008559#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008560 /*
8561 * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST
8562 * then not all SG elements will fit in the allocated queues.
8563 * The rest of the SG elements will be copied when the RISC
8564 * completes the SG elements that fit and halts.
8565 */
8566 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
8567 /*
8568 * Set sg_entry_cnt to be the number of SG elements that
8569 * will fit in the allocated SG queues. It is minus 1, because
8570 * the first SG element is handled above. ASC_MAX_SG_LIST is
8571 * already inflated by 1 to account for this. For example it
8572 * may be 50 which is 1 + 7 queues * 7 SG elements.
8573 */
8574 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008575
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008576 /*
8577 * Keep track of remaining number of SG elements that will
8578 * need to be handled from a_isr.c.
8579 */
8580 scsiq->remain_sg_entry_cnt =
8581 sg_head->entry_cnt - ASC_MAX_SG_LIST;
8582 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008583#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008584 /*
8585 * Set sg_entry_cnt to be the number of SG elements that
8586 * will fit in the allocated SG queues. It is minus 1, because
8587 * the first SG element is handled above.
8588 */
8589 sg_entry_cnt = sg_head->entry_cnt - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008590#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008591 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008592#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008593 if (sg_entry_cnt != 0) {
8594 scsiq->q1.cntl |= QC_SG_HEAD;
8595 q_addr = ASC_QNO_TO_QADDR(q_no);
8596 sg_index = 1;
8597 scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
8598 scsi_sg_q.sg_head_qp = q_no;
8599 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
8600 for (i = 0; i < sg_head->queue_cnt; i++) {
8601 scsi_sg_q.seq_no = i + 1;
8602 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
8603 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
8604 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
8605 if (i == 0) {
8606 scsi_sg_q.sg_list_cnt =
8607 ASC_SG_LIST_PER_Q;
8608 scsi_sg_q.sg_cur_list_cnt =
8609 ASC_SG_LIST_PER_Q;
8610 } else {
8611 scsi_sg_q.sg_list_cnt =
8612 ASC_SG_LIST_PER_Q - 1;
8613 scsi_sg_q.sg_cur_list_cnt =
8614 ASC_SG_LIST_PER_Q - 1;
8615 }
8616 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008617#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008618 /*
8619 * This is the last SG queue in the list of
8620 * allocated SG queues. If there are more
8621 * SG elements than will fit in the allocated
8622 * queues, then set the QCSG_SG_XFER_MORE flag.
8623 */
8624 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
8625 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
8626 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008627#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008628 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008629#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008630 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008631#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008632 sg_list_dwords = sg_entry_cnt << 1;
8633 if (i == 0) {
8634 scsi_sg_q.sg_list_cnt = sg_entry_cnt;
8635 scsi_sg_q.sg_cur_list_cnt =
8636 sg_entry_cnt;
8637 } else {
8638 scsi_sg_q.sg_list_cnt =
8639 sg_entry_cnt - 1;
8640 scsi_sg_q.sg_cur_list_cnt =
8641 sg_entry_cnt - 1;
8642 }
8643 sg_entry_cnt = 0;
8644 }
8645 next_qp = AscReadLramByte(iop_base,
8646 (ushort)(q_addr +
8647 ASC_SCSIQ_B_FWD));
8648 scsi_sg_q.q_no = next_qp;
8649 q_addr = ASC_QNO_TO_QADDR(next_qp);
8650 AscMemWordCopyPtrToLram(iop_base,
8651 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
8652 (uchar *)&scsi_sg_q,
8653 sizeof(ASC_SG_LIST_Q) >> 1);
8654 AscMemDWordCopyPtrToLram(iop_base,
8655 q_addr + ASC_SGQ_LIST_BEG,
8656 (uchar *)&sg_head->
8657 sg_list[sg_index],
8658 sg_list_dwords);
8659 sg_index += ASC_SG_LIST_PER_Q;
8660 scsiq->next_sg_index = sg_index;
8661 }
8662 } else {
8663 scsiq->q1.cntl &= ~QC_SG_HEAD;
8664 }
8665 sta = AscPutReadyQueue(asc_dvc, scsiq, q_no);
8666 scsiq->q1.data_addr = saved_data_addr;
8667 scsiq->q1.data_cnt = saved_data_cnt;
8668 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008669}
8670
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008671static int
8672AscSetRunChipSynRegAtID(PortAddr iop_base, uchar tid_no, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008673{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008674 int sta = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008675
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008676 if (AscHostReqRiscHalt(iop_base)) {
8677 sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
8678 AscStartChip(iop_base);
8679 return (sta);
8680 }
8681 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008682}
8683
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008684static int AscSetChipSynRegAtID(PortAddr iop_base, uchar id, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008685{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008686 ASC_SCSI_BIT_ID_TYPE org_id;
8687 int i;
8688 int sta = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008689
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008690 AscSetBank(iop_base, 1);
8691 org_id = AscReadChipDvcID(iop_base);
8692 for (i = 0; i <= ASC_MAX_TID; i++) {
8693 if (org_id == (0x01 << i))
8694 break;
8695 }
8696 org_id = (ASC_SCSI_BIT_ID_TYPE) i;
8697 AscWriteChipDvcID(iop_base, id);
8698 if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
8699 AscSetBank(iop_base, 0);
8700 AscSetChipSyn(iop_base, sdtr_data);
8701 if (AscGetChipSyn(iop_base) != sdtr_data) {
8702 sta = FALSE;
8703 }
8704 } else {
8705 sta = FALSE;
8706 }
8707 AscSetBank(iop_base, 1);
8708 AscWriteChipDvcID(iop_base, org_id);
8709 AscSetBank(iop_base, 0);
8710 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008711}
8712
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008713static ushort AscInitLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008714{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008715 uchar i;
8716 ushort s_addr;
8717 PortAddr iop_base;
8718 ushort warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008719
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008720 iop_base = asc_dvc->iop_base;
8721 warn_code = 0;
8722 AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0,
8723 (ushort)(((int)(asc_dvc->max_total_qng + 2 + 1) *
8724 64) >> 1)
8725 );
8726 i = ASC_MIN_ACTIVE_QNO;
8727 s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE;
8728 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
8729 (uchar)(i + 1));
8730 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
8731 (uchar)(asc_dvc->max_total_qng));
8732 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
8733 (uchar)i);
8734 i++;
8735 s_addr += ASC_QBLK_SIZE;
8736 for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) {
8737 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
8738 (uchar)(i + 1));
8739 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
8740 (uchar)(i - 1));
8741 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
8742 (uchar)i);
8743 }
8744 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
8745 (uchar)ASC_QLINK_END);
8746 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
8747 (uchar)(asc_dvc->max_total_qng - 1));
8748 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
8749 (uchar)asc_dvc->max_total_qng);
8750 i++;
8751 s_addr += ASC_QBLK_SIZE;
8752 for (; i <= (uchar)(asc_dvc->max_total_qng + 3);
8753 i++, s_addr += ASC_QBLK_SIZE) {
8754 AscWriteLramByte(iop_base,
8755 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_FWD), i);
8756 AscWriteLramByte(iop_base,
8757 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_BWD), i);
8758 AscWriteLramByte(iop_base,
8759 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_QNO), i);
8760 }
8761 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008762}
8763
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008764static ushort AscInitQLinkVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008765{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008766 PortAddr iop_base;
8767 int i;
8768 ushort lram_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008769
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008770 iop_base = asc_dvc->iop_base;
8771 AscPutRiscVarFreeQHead(iop_base, 1);
8772 AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng);
8773 AscPutVarFreeQHead(iop_base, 1);
8774 AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng);
8775 AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B,
8776 (uchar)((int)asc_dvc->max_total_qng + 1));
8777 AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B,
8778 (uchar)((int)asc_dvc->max_total_qng + 2));
8779 AscWriteLramByte(iop_base, (ushort)ASCV_TOTAL_READY_Q_B,
8780 asc_dvc->max_total_qng);
8781 AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0);
8782 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8783 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
8784 AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0);
8785 AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0);
8786 AscPutQDoneInProgress(iop_base, 0);
8787 lram_addr = ASC_QADR_BEG;
8788 for (i = 0; i < 32; i++, lram_addr += 2) {
8789 AscWriteLramWord(iop_base, lram_addr, 0);
8790 }
8791 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008792}
8793
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008794static int AscSetLibErrorCode(ASC_DVC_VAR *asc_dvc, ushort err_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008795{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008796 if (asc_dvc->err_code == 0) {
8797 asc_dvc->err_code = err_code;
8798 AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W,
8799 err_code);
8800 }
8801 return (err_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008802}
8803
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008804static uchar
8805AscMsgOutSDTR(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar sdtr_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008806{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008807 EXT_MSG sdtr_buf;
8808 uchar sdtr_period_index;
8809 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008810
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008811 iop_base = asc_dvc->iop_base;
Matthew Wilcox47d853c2007-07-26 11:41:33 -04008812 sdtr_buf.msg_type = EXTENDED_MESSAGE;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008813 sdtr_buf.msg_len = MS_SDTR_LEN;
Matthew Wilcox47d853c2007-07-26 11:41:33 -04008814 sdtr_buf.msg_req = EXTENDED_SDTR;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008815 sdtr_buf.xfer_period = sdtr_period;
8816 sdtr_offset &= ASC_SYN_MAX_OFFSET;
8817 sdtr_buf.req_ack_offset = sdtr_offset;
8818 if ((sdtr_period_index =
8819 AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <=
8820 asc_dvc->max_sdtr_index) {
8821 AscMemWordCopyPtrToLram(iop_base,
8822 ASCV_MSGOUT_BEG,
8823 (uchar *)&sdtr_buf,
8824 sizeof(EXT_MSG) >> 1);
8825 return ((sdtr_period_index << 4) | sdtr_offset);
8826 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008827
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008828 sdtr_buf.req_ack_offset = 0;
8829 AscMemWordCopyPtrToLram(iop_base,
8830 ASCV_MSGOUT_BEG,
8831 (uchar *)&sdtr_buf,
8832 sizeof(EXT_MSG) >> 1);
8833 return (0);
8834 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008835}
8836
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008837static uchar
8838AscCalSDTRData(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar syn_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008839{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008840 uchar byte;
8841 uchar sdtr_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008842
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008843 sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
8844 if ((sdtr_period_ix > asc_dvc->max_sdtr_index)
8845 ) {
8846 return (0xFF);
8847 }
8848 byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET);
8849 return (byte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008850}
8851
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008852static void AscSetChipSDTR(PortAddr iop_base, uchar sdtr_data, uchar tid_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008853{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008854 AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
8855 AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data);
8856 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008857}
8858
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008859static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *asc_dvc, uchar syn_time)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008860{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008861 uchar *period_table;
8862 int max_index;
8863 int min_index;
8864 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008865
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008866 period_table = asc_dvc->sdtr_period_tbl;
8867 max_index = (int)asc_dvc->max_sdtr_index;
8868 min_index = (int)asc_dvc->host_init_sdtr_index;
8869 if ((syn_time <= period_table[max_index])) {
8870 for (i = min_index; i < (max_index - 1); i++) {
8871 if (syn_time <= period_table[i]) {
8872 return ((uchar)i);
8873 }
8874 }
8875 return ((uchar)max_index);
8876 } else {
8877 return ((uchar)(max_index + 1));
8878 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008879}
8880
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008881static uchar AscAllocFreeQueue(PortAddr iop_base, uchar free_q_head)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008882{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008883 ushort q_addr;
8884 uchar next_qp;
8885 uchar q_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008886
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008887 q_addr = ASC_QNO_TO_QADDR(free_q_head);
8888 q_status = (uchar)AscReadLramByte(iop_base,
8889 (ushort)(q_addr +
8890 ASC_SCSIQ_B_STATUS));
8891 next_qp = AscReadLramByte(iop_base, (ushort)(q_addr + ASC_SCSIQ_B_FWD));
8892 if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END)) {
8893 return (next_qp);
8894 }
8895 return (ASC_QLINK_END);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008896}
8897
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008898static uchar
8899AscAllocMultipleFreeQueue(PortAddr iop_base, uchar free_q_head, uchar n_free_q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008900{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008901 uchar i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008902
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008903 for (i = 0; i < n_free_q; i++) {
8904 if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head))
8905 == ASC_QLINK_END) {
8906 return (ASC_QLINK_END);
8907 }
8908 }
8909 return (free_q_head);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008910}
8911
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008912static int AscHostReqRiscHalt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008913{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008914 int count = 0;
8915 int sta = 0;
8916 uchar saved_stop_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008917
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008918 if (AscIsChipHalted(iop_base))
8919 return (1);
8920 saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
8921 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
8922 ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP);
8923 do {
8924 if (AscIsChipHalted(iop_base)) {
8925 sta = 1;
8926 break;
8927 }
8928 DvcSleepMilliSecond(100);
8929 } while (count++ < 20);
8930 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code);
8931 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008932}
8933
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008934static int AscStopQueueExe(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008935{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008936 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008937
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008938 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) {
8939 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
8940 ASC_STOP_REQ_RISC_STOP);
8941 do {
8942 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) &
8943 ASC_STOP_ACK_RISC_STOP) {
8944 return (1);
8945 }
8946 DvcSleepMilliSecond(100);
8947 } while (count++ < 20);
8948 }
8949 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008950}
8951
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008952static void DvcDelayMicroSecond(ADV_DVC_VAR *asc_dvc, ushort micro_sec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008953{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008954 udelay(micro_sec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008955}
8956
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008957static void DvcDelayNanoSecond(ASC_DVC_VAR *asc_dvc, ASC_DCNT nano_sec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008958{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008959 udelay((nano_sec + 999) / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008960}
8961
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008962static int AscStartChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008963{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008964 AscSetChipControl(iop_base, 0);
8965 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
8966 return (0);
8967 }
8968 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008969}
8970
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008971static int AscStopChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008972{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008973 uchar cc_val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008974
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008975 cc_val =
8976 AscGetChipControl(iop_base) &
8977 (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG));
8978 AscSetChipControl(iop_base, (uchar)(cc_val | CC_HALT));
8979 AscSetChipIH(iop_base, INS_HALT);
8980 AscSetChipIH(iop_base, INS_RFLAG_WTM);
8981 if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) {
8982 return (0);
8983 }
8984 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008985}
8986
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008987static int AscIsChipHalted(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008988{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008989 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
8990 if ((AscGetChipControl(iop_base) & CC_HALT) != 0) {
8991 return (1);
8992 }
8993 }
8994 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008995}
8996
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008997static void AscSetChipIH(PortAddr iop_base, ushort ins_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008998{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008999 AscSetBank(iop_base, 1);
9000 AscWriteChipIH(iop_base, ins_code);
9001 AscSetBank(iop_base, 0);
9002 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009003}
9004
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009005static void AscAckInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009006{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009007 uchar host_flag;
9008 uchar risc_flag;
9009 ushort loop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009010
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009011 loop = 0;
9012 do {
9013 risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B);
9014 if (loop++ > 0x7FFF) {
9015 break;
9016 }
9017 } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0);
9018 host_flag =
9019 AscReadLramByte(iop_base,
9020 ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT);
9021 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
9022 (uchar)(host_flag | ASC_HOST_FLAG_ACK_INT));
9023 AscSetChipStatus(iop_base, CIW_INT_ACK);
9024 loop = 0;
9025 while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) {
9026 AscSetChipStatus(iop_base, CIW_INT_ACK);
9027 if (loop++ > 3) {
9028 break;
9029 }
9030 }
9031 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
9032 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009033}
9034
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009035static void AscDisableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009036{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009037 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009038
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009039 cfg = AscGetChipCfgLsw(iop_base);
9040 AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON));
9041 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009042}
9043
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009044static void AscEnableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009045{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009046 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009047
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009048 cfg = AscGetChipCfgLsw(iop_base);
9049 AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON);
9050 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009051}
9052
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009053static void AscSetBank(PortAddr iop_base, uchar bank)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009054{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009055 uchar val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009056
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009057 val = AscGetChipControl(iop_base) &
9058 (~
9059 (CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET |
9060 CC_CHIP_RESET));
9061 if (bank == 1) {
9062 val |= CC_BANK_ONE;
9063 } else if (bank == 2) {
9064 val |= CC_DIAG | CC_BANK_ONE;
9065 } else {
9066 val &= ~CC_BANK_ONE;
9067 }
9068 AscSetChipControl(iop_base, val);
9069 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009070}
9071
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009072static int AscResetChipAndScsiBus(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009073{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009074 PortAddr iop_base;
9075 int i = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009076
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009077 iop_base = asc_dvc->iop_base;
9078 while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE)
9079 && (i-- > 0)) {
9080 DvcSleepMilliSecond(100);
9081 }
9082 AscStopChip(iop_base);
9083 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
9084 DvcDelayNanoSecond(asc_dvc, 60000);
9085 AscSetChipIH(iop_base, INS_RFLAG_WTM);
9086 AscSetChipIH(iop_base, INS_HALT);
9087 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT);
9088 AscSetChipControl(iop_base, CC_HALT);
9089 DvcSleepMilliSecond(200);
9090 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
9091 AscSetChipStatus(iop_base, 0);
9092 return (AscIsChipHalted(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -07009093}
9094
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009095static ASC_DCNT __devinit AscGetMaxDmaCount(ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009096{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009097 if (bus_type & ASC_IS_ISA)
9098 return (ASC_MAX_ISA_DMA_COUNT);
9099 else if (bus_type & (ASC_IS_EISA | ASC_IS_VL))
9100 return (ASC_MAX_VL_DMA_COUNT);
9101 return (ASC_MAX_PCI_DMA_COUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009102}
9103
9104#ifdef CONFIG_ISA
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009105static ushort __devinit AscGetIsaDmaChannel(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009106{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009107 ushort channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009108
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009109 channel = AscGetChipCfgLsw(iop_base) & 0x0003;
9110 if (channel == 0x03)
9111 return (0);
9112 else if (channel == 0x00)
9113 return (7);
9114 return (channel + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009115}
9116
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009117static ushort __devinit AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009118{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009119 ushort cfg_lsw;
9120 uchar value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009121
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009122 if ((dma_channel >= 5) && (dma_channel <= 7)) {
9123 if (dma_channel == 7)
9124 value = 0x00;
9125 else
9126 value = dma_channel - 4;
9127 cfg_lsw = AscGetChipCfgLsw(iop_base) & 0xFFFC;
9128 cfg_lsw |= value;
9129 AscSetChipCfgLsw(iop_base, cfg_lsw);
9130 return (AscGetIsaDmaChannel(iop_base));
9131 }
9132 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009133}
9134
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009135static uchar __devinit AscSetIsaDmaSpeed(PortAddr iop_base, uchar speed_value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009136{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009137 speed_value &= 0x07;
9138 AscSetBank(iop_base, 1);
9139 AscWriteChipDmaSpeed(iop_base, speed_value);
9140 AscSetBank(iop_base, 0);
9141 return (AscGetIsaDmaSpeed(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -07009142}
9143
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009144static uchar __devinit AscGetIsaDmaSpeed(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009145{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009146 uchar speed_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009147
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009148 AscSetBank(iop_base, 1);
9149 speed_value = AscReadChipDmaSpeed(iop_base);
9150 speed_value &= 0x07;
9151 AscSetBank(iop_base, 0);
9152 return (speed_value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009153}
9154#endif /* CONFIG_ISA */
9155
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06009156static int __devinit AscInitGetConfig(asc_board_t *boardp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009157{
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06009158 ASC_DVC_VAR *asc_dvc = &boardp->dvc_var.asc_dvc_var;
Matthew Wilcox9649af32007-07-26 21:51:47 -06009159 unsigned short warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009160
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009161 asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG;
Matthew Wilcox9649af32007-07-26 21:51:47 -06009162 if (asc_dvc->err_code != 0)
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06009163 return asc_dvc->err_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009164
Matthew Wilcox9649af32007-07-26 21:51:47 -06009165 if (AscFindSignature(asc_dvc->iop_base)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009166 warn_code |= AscInitAscDvcVar(asc_dvc);
9167 warn_code |= AscInitFromEEP(asc_dvc);
9168 asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06009169 if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009170 asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009171 } else {
9172 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
9173 }
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06009174
9175 switch (warn_code) {
9176 case 0: /* No error */
9177 break;
9178 case ASC_WARN_IO_PORT_ROTATE:
9179 ASC_PRINT1("AscInitGetConfig: board %d: I/O port address "
9180 "modified\n", boardp->id);
9181 break;
9182 case ASC_WARN_AUTO_CONFIG:
9183 ASC_PRINT1("AscInitGetConfig: board %d: I/O port increment "
9184 "switch enabled\n", boardp->id);
9185 break;
9186 case ASC_WARN_EEPROM_CHKSUM:
9187 ASC_PRINT1("AscInitGetConfig: board %d: EEPROM checksum "
9188 "error\n", boardp->id);
9189 break;
9190 case ASC_WARN_IRQ_MODIFIED:
9191 ASC_PRINT1("AscInitGetConfig: board %d: IRQ modified\n",
9192 boardp->id);
9193 break;
9194 case ASC_WARN_CMD_QNG_CONFLICT:
9195 ASC_PRINT1("AscInitGetConfig: board %d: tag queuing enabled "
9196 "w/o disconnects\n", boardp->id);
9197 break;
9198 default:
9199 ASC_PRINT2("AscInitGetConfig: board %d: unknown warning: "
9200 "0x%x\n", boardp->id, warn_code);
9201 break;
9202 }
9203
9204 if (asc_dvc->err_code != 0) {
9205 ASC_PRINT3("AscInitGetConfig: board %d error: init_state 0x%x, "
9206 "err_code 0x%x\n", boardp->id, asc_dvc->init_state,
9207 asc_dvc->err_code);
9208 }
9209
9210 return asc_dvc->err_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009211}
9212
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06009213static int __devinit AscInitSetConfig(struct pci_dev *pdev, asc_board_t *boardp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009214{
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06009215 ASC_DVC_VAR *asc_dvc = &boardp->dvc_var.asc_dvc_var;
Matthew Wilcox394dbf32007-07-26 11:56:40 -04009216 PortAddr iop_base = asc_dvc->iop_base;
9217 unsigned short cfg_msw;
9218 unsigned short warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009219
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009220 asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG;
9221 if (asc_dvc->err_code != 0)
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06009222 return asc_dvc->err_code;
Matthew Wilcox394dbf32007-07-26 11:56:40 -04009223 if (!AscFindSignature(asc_dvc->iop_base)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009224 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06009225 return asc_dvc->err_code;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009226 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009227
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009228 cfg_msw = AscGetChipCfgMsw(iop_base);
9229 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06009230 cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009231 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
9232 AscSetChipCfgMsw(iop_base, cfg_msw);
9233 }
9234 if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) !=
9235 asc_dvc->cfg->cmd_qng_enabled) {
9236 asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled;
9237 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
9238 }
9239 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
9240 warn_code |= ASC_WARN_AUTO_CONFIG;
9241 }
9242 if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) {
9243 if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type)
9244 != asc_dvc->irq_no) {
9245 asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO;
9246 }
9247 }
Matthew Wilcox9649af32007-07-26 21:51:47 -06009248#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009249 if (asc_dvc->bus_type & ASC_IS_PCI) {
9250 cfg_msw &= 0xFFC0;
9251 AscSetChipCfgMsw(iop_base, cfg_msw);
9252 if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
9253 } else {
Matthew Wilcox9649af32007-07-26 21:51:47 -06009254 if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) ||
9255 (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009256 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
9257 asc_dvc->bug_fix_cntl |=
9258 ASC_BUG_FIX_ASYN_USE_SYN;
9259 }
9260 }
Matthew Wilcox9649af32007-07-26 21:51:47 -06009261 } else
9262#endif /* CONFIG_PCI */
9263 if (asc_dvc->bus_type == ASC_IS_ISAPNP) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009264 if (AscGetChipVersion(iop_base, asc_dvc->bus_type)
9265 == ASC_CHIP_VER_ASYN_BUG) {
9266 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
9267 }
9268 }
9269 if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) !=
9270 asc_dvc->cfg->chip_scsi_id) {
9271 asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID;
9272 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009273#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009274 if (asc_dvc->bus_type & ASC_IS_ISA) {
9275 AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel);
9276 AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed);
9277 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009278#endif /* CONFIG_ISA */
Matthew Wilcox394dbf32007-07-26 11:56:40 -04009279
9280 asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG;
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06009281
9282 switch (warn_code) {
9283 case 0: /* No error. */
9284 break;
9285 case ASC_WARN_IO_PORT_ROTATE:
9286 ASC_PRINT1("AscInitSetConfig: board %d: I/O port address "
9287 "modified\n", boardp->id);
9288 break;
9289 case ASC_WARN_AUTO_CONFIG:
9290 ASC_PRINT1("AscInitSetConfig: board %d: I/O port increment "
9291 "switch enabled\n", boardp->id);
9292 break;
9293 case ASC_WARN_EEPROM_CHKSUM:
9294 ASC_PRINT1("AscInitSetConfig: board %d: EEPROM checksum "
9295 "error\n", boardp->id);
9296 break;
9297 case ASC_WARN_IRQ_MODIFIED:
9298 ASC_PRINT1("AscInitSetConfig: board %d: IRQ modified\n",
9299 boardp->id);
9300 break;
9301 case ASC_WARN_CMD_QNG_CONFLICT:
9302 ASC_PRINT1("AscInitSetConfig: board %d: tag queuing w/o "
9303 "disconnects\n",
9304 boardp->id);
9305 break;
9306 default:
9307 ASC_PRINT2("AscInitSetConfig: board %d: unknown warning: "
9308 "0x%x\n", boardp->id, warn_code);
9309 break;
9310 }
9311
9312 if (asc_dvc->err_code != 0) {
9313 ASC_PRINT3("AscInitSetConfig: board %d error: init_state 0x%x, "
9314 "err_code 0x%x\n", boardp->id, asc_dvc->init_state,
9315 asc_dvc->err_code);
9316 }
9317
9318 return asc_dvc->err_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009319}
9320
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009321static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009322{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009323 ushort warn_code;
9324 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009325
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009326 iop_base = asc_dvc->iop_base;
9327 warn_code = 0;
9328 if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
9329 !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
9330 AscResetChipAndScsiBus(asc_dvc);
9331 DvcSleepMilliSecond((ASC_DCNT)
9332 ((ushort)asc_dvc->scsi_reset_wait * 1000));
9333 }
9334 asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
9335 if (asc_dvc->err_code != 0)
9336 return (UW_ERR);
9337 if (!AscFindSignature(asc_dvc->iop_base)) {
9338 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
9339 return (warn_code);
9340 }
9341 AscDisableInterrupt(iop_base);
9342 warn_code |= AscInitLram(asc_dvc);
9343 if (asc_dvc->err_code != 0)
9344 return (UW_ERR);
9345 ASC_DBG1(1, "AscInitAsc1000Driver: _asc_mcode_chksum 0x%lx\n",
9346 (ulong)_asc_mcode_chksum);
9347 if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf,
9348 _asc_mcode_size) != _asc_mcode_chksum) {
9349 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
9350 return (warn_code);
9351 }
9352 warn_code |= AscInitMicroCodeVar(asc_dvc);
9353 asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
9354 AscEnableInterrupt(iop_base);
9355 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009356}
9357
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009358static ushort __devinit AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009359{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009360 int i;
9361 PortAddr iop_base;
9362 ushort warn_code;
9363 uchar chip_version;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009364
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009365 iop_base = asc_dvc->iop_base;
9366 warn_code = 0;
9367 asc_dvc->err_code = 0;
9368 if ((asc_dvc->bus_type &
9369 (ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0) {
9370 asc_dvc->err_code |= ASC_IERR_NO_BUS_TYPE;
9371 }
9372 AscSetChipControl(iop_base, CC_HALT);
9373 AscSetChipStatus(iop_base, 0);
9374 asc_dvc->bug_fix_cntl = 0;
9375 asc_dvc->pci_fix_asyn_xfer = 0;
9376 asc_dvc->pci_fix_asyn_xfer_always = 0;
9377 /* asc_dvc->init_state initalized in AscInitGetConfig(). */
9378 asc_dvc->sdtr_done = 0;
9379 asc_dvc->cur_total_qng = 0;
9380 asc_dvc->is_in_int = 0;
9381 asc_dvc->in_critical_cnt = 0;
9382 asc_dvc->last_q_shortage = 0;
9383 asc_dvc->use_tagged_qng = 0;
9384 asc_dvc->no_scam = 0;
9385 asc_dvc->unit_not_ready = 0;
9386 asc_dvc->queue_full_or_busy = 0;
9387 asc_dvc->redo_scam = 0;
9388 asc_dvc->res2 = 0;
9389 asc_dvc->host_init_sdtr_index = 0;
9390 asc_dvc->cfg->can_tagged_qng = 0;
9391 asc_dvc->cfg->cmd_qng_enabled = 0;
9392 asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
9393 asc_dvc->init_sdtr = 0;
9394 asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG;
9395 asc_dvc->scsi_reset_wait = 3;
9396 asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET;
9397 asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
9398 asc_dvc->cfg->sdtr_enable = ASC_SCSI_WIDTH_BIT_SET;
9399 asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
9400 asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID;
9401 asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER;
9402 asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) |
9403 ASC_LIB_VERSION_MINOR;
9404 chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type);
9405 asc_dvc->cfg->chip_version = chip_version;
9406 asc_dvc->sdtr_period_tbl[0] = SYN_XFER_NS_0;
9407 asc_dvc->sdtr_period_tbl[1] = SYN_XFER_NS_1;
9408 asc_dvc->sdtr_period_tbl[2] = SYN_XFER_NS_2;
9409 asc_dvc->sdtr_period_tbl[3] = SYN_XFER_NS_3;
9410 asc_dvc->sdtr_period_tbl[4] = SYN_XFER_NS_4;
9411 asc_dvc->sdtr_period_tbl[5] = SYN_XFER_NS_5;
9412 asc_dvc->sdtr_period_tbl[6] = SYN_XFER_NS_6;
9413 asc_dvc->sdtr_period_tbl[7] = SYN_XFER_NS_7;
9414 asc_dvc->max_sdtr_index = 7;
9415 if ((asc_dvc->bus_type & ASC_IS_PCI) &&
9416 (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3150)) {
9417 asc_dvc->bus_type = ASC_IS_PCI_ULTRA;
9418 asc_dvc->sdtr_period_tbl[0] = SYN_ULTRA_XFER_NS_0;
9419 asc_dvc->sdtr_period_tbl[1] = SYN_ULTRA_XFER_NS_1;
9420 asc_dvc->sdtr_period_tbl[2] = SYN_ULTRA_XFER_NS_2;
9421 asc_dvc->sdtr_period_tbl[3] = SYN_ULTRA_XFER_NS_3;
9422 asc_dvc->sdtr_period_tbl[4] = SYN_ULTRA_XFER_NS_4;
9423 asc_dvc->sdtr_period_tbl[5] = SYN_ULTRA_XFER_NS_5;
9424 asc_dvc->sdtr_period_tbl[6] = SYN_ULTRA_XFER_NS_6;
9425 asc_dvc->sdtr_period_tbl[7] = SYN_ULTRA_XFER_NS_7;
9426 asc_dvc->sdtr_period_tbl[8] = SYN_ULTRA_XFER_NS_8;
9427 asc_dvc->sdtr_period_tbl[9] = SYN_ULTRA_XFER_NS_9;
9428 asc_dvc->sdtr_period_tbl[10] = SYN_ULTRA_XFER_NS_10;
9429 asc_dvc->sdtr_period_tbl[11] = SYN_ULTRA_XFER_NS_11;
9430 asc_dvc->sdtr_period_tbl[12] = SYN_ULTRA_XFER_NS_12;
9431 asc_dvc->sdtr_period_tbl[13] = SYN_ULTRA_XFER_NS_13;
9432 asc_dvc->sdtr_period_tbl[14] = SYN_ULTRA_XFER_NS_14;
9433 asc_dvc->sdtr_period_tbl[15] = SYN_ULTRA_XFER_NS_15;
9434 asc_dvc->max_sdtr_index = 15;
9435 if (chip_version == ASC_CHIP_VER_PCI_ULTRA_3150) {
9436 AscSetExtraControl(iop_base,
9437 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
9438 } else if (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3050) {
9439 AscSetExtraControl(iop_base,
9440 (SEC_ACTIVE_NEGATE |
9441 SEC_ENABLE_FILTER));
9442 }
9443 }
9444 if (asc_dvc->bus_type == ASC_IS_PCI) {
9445 AscSetExtraControl(iop_base,
9446 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
9447 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009448
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009449 asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009450#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009451 if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) {
Matthew Wilcox59fcf842007-07-26 11:54:15 -04009452 if (chip_version >= ASC_CHIP_MIN_VER_ISA_PNP) {
9453 AscSetChipIFC(iop_base, IFC_INIT_DEFAULT);
9454 asc_dvc->bus_type = ASC_IS_ISAPNP;
9455 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009456 asc_dvc->cfg->isa_dma_channel =
9457 (uchar)AscGetIsaDmaChannel(iop_base);
9458 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009459#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009460 for (i = 0; i <= ASC_MAX_TID; i++) {
9461 asc_dvc->cur_dvc_qng[i] = 0;
9462 asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG;
9463 asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q *)0L;
9464 asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q *)0L;
9465 asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG;
9466 }
9467 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009468}
9469
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009470static ushort __devinit AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009471{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009472 ASCEEP_CONFIG eep_config_buf;
9473 ASCEEP_CONFIG *eep_config;
9474 PortAddr iop_base;
9475 ushort chksum;
9476 ushort warn_code;
9477 ushort cfg_msw, cfg_lsw;
9478 int i;
9479 int write_eep = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009480
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009481 iop_base = asc_dvc->iop_base;
9482 warn_code = 0;
9483 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE);
9484 AscStopQueueExe(iop_base);
9485 if ((AscStopChip(iop_base) == FALSE) ||
9486 (AscGetChipScsiCtrl(iop_base) != 0)) {
9487 asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
9488 AscResetChipAndScsiBus(asc_dvc);
9489 DvcSleepMilliSecond((ASC_DCNT)
9490 ((ushort)asc_dvc->scsi_reset_wait * 1000));
9491 }
9492 if (AscIsChipHalted(iop_base) == FALSE) {
9493 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
9494 return (warn_code);
9495 }
9496 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
9497 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
9498 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
9499 return (warn_code);
9500 }
9501 eep_config = (ASCEEP_CONFIG *)&eep_config_buf;
9502 cfg_msw = AscGetChipCfgMsw(iop_base);
9503 cfg_lsw = AscGetChipCfgLsw(iop_base);
9504 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06009505 cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009506 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
9507 AscSetChipCfgMsw(iop_base, cfg_msw);
9508 }
9509 chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
9510 ASC_DBG1(1, "AscInitFromEEP: chksum 0x%x\n", chksum);
9511 if (chksum == 0) {
9512 chksum = 0xaa55;
9513 }
9514 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
9515 warn_code |= ASC_WARN_AUTO_CONFIG;
9516 if (asc_dvc->cfg->chip_version == 3) {
9517 if (eep_config->cfg_lsw != cfg_lsw) {
9518 warn_code |= ASC_WARN_EEPROM_RECOVER;
9519 eep_config->cfg_lsw =
9520 AscGetChipCfgLsw(iop_base);
9521 }
9522 if (eep_config->cfg_msw != cfg_msw) {
9523 warn_code |= ASC_WARN_EEPROM_RECOVER;
9524 eep_config->cfg_msw =
9525 AscGetChipCfgMsw(iop_base);
9526 }
9527 }
9528 }
9529 eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
9530 eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
9531 ASC_DBG1(1, "AscInitFromEEP: eep_config->chksum 0x%x\n",
9532 eep_config->chksum);
9533 if (chksum != eep_config->chksum) {
9534 if (AscGetChipVersion(iop_base, asc_dvc->bus_type) ==
9535 ASC_CHIP_VER_PCI_ULTRA_3050) {
9536 ASC_DBG(1,
9537 "AscInitFromEEP: chksum error ignored; EEPROM-less board\n");
9538 eep_config->init_sdtr = 0xFF;
9539 eep_config->disc_enable = 0xFF;
9540 eep_config->start_motor = 0xFF;
9541 eep_config->use_cmd_qng = 0;
9542 eep_config->max_total_qng = 0xF0;
9543 eep_config->max_tag_qng = 0x20;
9544 eep_config->cntl = 0xBFFF;
9545 ASC_EEP_SET_CHIP_ID(eep_config, 7);
9546 eep_config->no_scam = 0;
9547 eep_config->adapter_info[0] = 0;
9548 eep_config->adapter_info[1] = 0;
9549 eep_config->adapter_info[2] = 0;
9550 eep_config->adapter_info[3] = 0;
9551 eep_config->adapter_info[4] = 0;
9552 /* Indicate EEPROM-less board. */
9553 eep_config->adapter_info[5] = 0xBB;
9554 } else {
9555 ASC_PRINT
9556 ("AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n");
9557 write_eep = 1;
9558 warn_code |= ASC_WARN_EEPROM_CHKSUM;
9559 }
9560 }
9561 asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr;
9562 asc_dvc->cfg->disc_enable = eep_config->disc_enable;
9563 asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
9564 asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config);
9565 asc_dvc->start_motor = eep_config->start_motor;
9566 asc_dvc->dvc_cntl = eep_config->cntl;
9567 asc_dvc->no_scam = eep_config->no_scam;
9568 asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0];
9569 asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1];
9570 asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2];
9571 asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3];
9572 asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4];
9573 asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5];
9574 if (!AscTestExternalLram(asc_dvc)) {
9575 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) ==
9576 ASC_IS_PCI_ULTRA)) {
9577 eep_config->max_total_qng =
9578 ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
9579 eep_config->max_tag_qng =
9580 ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG;
9581 } else {
9582 eep_config->cfg_msw |= 0x0800;
9583 cfg_msw |= 0x0800;
9584 AscSetChipCfgMsw(iop_base, cfg_msw);
9585 eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
9586 eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG;
9587 }
9588 } else {
9589 }
9590 if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) {
9591 eep_config->max_total_qng = ASC_MIN_TOTAL_QNG;
9592 }
9593 if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) {
9594 eep_config->max_total_qng = ASC_MAX_TOTAL_QNG;
9595 }
9596 if (eep_config->max_tag_qng > eep_config->max_total_qng) {
9597 eep_config->max_tag_qng = eep_config->max_total_qng;
9598 }
9599 if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) {
9600 eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC;
9601 }
9602 asc_dvc->max_total_qng = eep_config->max_total_qng;
9603 if ((eep_config->use_cmd_qng & eep_config->disc_enable) !=
9604 eep_config->use_cmd_qng) {
9605 eep_config->disc_enable = eep_config->use_cmd_qng;
9606 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
9607 }
9608 if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
9609 asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
9610 }
9611 ASC_EEP_SET_CHIP_ID(eep_config,
9612 ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID);
9613 asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config);
9614 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) &&
9615 !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
9616 asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
9617 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009618
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009619 for (i = 0; i <= ASC_MAX_TID; i++) {
9620 asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
9621 asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
9622 asc_dvc->cfg->sdtr_period_offset[i] =
9623 (uchar)(ASC_DEF_SDTR_OFFSET |
9624 (asc_dvc->host_init_sdtr_index << 4));
9625 }
9626 eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
9627 if (write_eep) {
9628 if ((i =
9629 AscSetEEPConfig(iop_base, eep_config,
9630 asc_dvc->bus_type)) != 0) {
9631 ASC_PRINT1
9632 ("AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n",
9633 i);
9634 } else {
9635 ASC_PRINT
9636 ("AscInitFromEEP: Successfully re-wrote EEPROM.\n");
9637 }
9638 }
9639 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009640}
9641
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009642static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009643{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009644 int i;
9645 ushort warn_code;
9646 PortAddr iop_base;
9647 ASC_PADDR phy_addr;
9648 ASC_DCNT phy_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009649
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009650 iop_base = asc_dvc->iop_base;
9651 warn_code = 0;
9652 for (i = 0; i <= ASC_MAX_TID; i++) {
9653 AscPutMCodeInitSDTRAtID(iop_base, i,
9654 asc_dvc->cfg->sdtr_period_offset[i]
9655 );
9656 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009657
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009658 AscInitQLinkVar(asc_dvc);
9659 AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
9660 asc_dvc->cfg->disc_enable);
9661 AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
9662 ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07009663
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009664 /* Align overrun buffer on an 8 byte boundary. */
9665 phy_addr = virt_to_bus(asc_dvc->cfg->overrun_buf);
9666 phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7);
9667 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
9668 (uchar *)&phy_addr, 1);
9669 phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE - 8);
9670 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D,
9671 (uchar *)&phy_size, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009672
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009673 asc_dvc->cfg->mcode_date =
9674 AscReadLramWord(iop_base, (ushort)ASCV_MC_DATE_W);
9675 asc_dvc->cfg->mcode_version =
9676 AscReadLramWord(iop_base, (ushort)ASCV_MC_VER_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009677
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009678 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
9679 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
9680 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
9681 return (warn_code);
9682 }
9683 if (AscStartChip(iop_base) != 1) {
9684 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
9685 return (warn_code);
9686 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009687
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009688 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009689}
9690
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009691static int __devinit AscTestExternalLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009692{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009693 PortAddr iop_base;
9694 ushort q_addr;
9695 ushort saved_word;
9696 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009697
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009698 iop_base = asc_dvc->iop_base;
9699 sta = 0;
9700 q_addr = ASC_QNO_TO_QADDR(241);
9701 saved_word = AscReadLramWord(iop_base, q_addr);
9702 AscSetChipLramAddr(iop_base, q_addr);
9703 AscSetChipLramData(iop_base, 0x55AA);
9704 DvcSleepMilliSecond(10);
9705 AscSetChipLramAddr(iop_base, q_addr);
9706 if (AscGetChipLramData(iop_base) == 0x55AA) {
9707 sta = 1;
9708 AscWriteLramWord(iop_base, q_addr, saved_word);
9709 }
9710 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009711}
9712
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009713static int __devinit AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009714{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009715 uchar read_back;
9716 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009717
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009718 retry = 0;
9719 while (TRUE) {
9720 AscSetChipEEPCmd(iop_base, cmd_reg);
9721 DvcSleepMilliSecond(1);
9722 read_back = AscGetChipEEPCmd(iop_base);
9723 if (read_back == cmd_reg) {
9724 return (1);
9725 }
9726 if (retry++ > ASC_EEP_MAX_RETRY) {
9727 return (0);
9728 }
9729 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009730}
9731
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009732static int __devinit AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009733{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009734 ushort read_back;
9735 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009736
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009737 retry = 0;
9738 while (TRUE) {
9739 AscSetChipEEPData(iop_base, data_reg);
9740 DvcSleepMilliSecond(1);
9741 read_back = AscGetChipEEPData(iop_base);
9742 if (read_back == data_reg) {
9743 return (1);
9744 }
9745 if (retry++ > ASC_EEP_MAX_RETRY) {
9746 return (0);
9747 }
9748 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009749}
9750
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009751static void __devinit AscWaitEEPRead(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009752{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009753 DvcSleepMilliSecond(1);
9754 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009755}
9756
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009757static void __devinit AscWaitEEPWrite(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009758{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009759 DvcSleepMilliSecond(20);
9760 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009761}
9762
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009763static ushort __devinit AscReadEEPWord(PortAddr iop_base, uchar addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009764{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009765 ushort read_wval;
9766 uchar cmd_reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009767
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009768 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
9769 AscWaitEEPRead();
9770 cmd_reg = addr | ASC_EEP_CMD_READ;
9771 AscWriteEEPCmdReg(iop_base, cmd_reg);
9772 AscWaitEEPRead();
9773 read_wval = AscGetChipEEPData(iop_base);
9774 AscWaitEEPRead();
9775 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009776}
9777
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009778static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009779AscWriteEEPWord(PortAddr iop_base, uchar addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009780{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009781 ushort read_wval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009782
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009783 read_wval = AscReadEEPWord(iop_base, addr);
9784 if (read_wval != word_val) {
9785 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE);
9786 AscWaitEEPRead();
9787 AscWriteEEPDataReg(iop_base, word_val);
9788 AscWaitEEPRead();
9789 AscWriteEEPCmdReg(iop_base,
9790 (uchar)((uchar)ASC_EEP_CMD_WRITE | addr));
9791 AscWaitEEPWrite();
9792 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
9793 AscWaitEEPRead();
9794 return (AscReadEEPWord(iop_base, addr));
9795 }
9796 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009797}
9798
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009799static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009800AscGetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009801{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009802 ushort wval;
9803 ushort sum;
9804 ushort *wbuf;
9805 int cfg_beg;
9806 int cfg_end;
9807 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
9808 int s_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009809
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009810 wbuf = (ushort *)cfg_buf;
9811 sum = 0;
9812 /* Read two config words; Byte-swapping done by AscReadEEPWord(). */
9813 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
9814 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
9815 sum += *wbuf;
9816 }
9817 if (bus_type & ASC_IS_VL) {
9818 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
9819 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
9820 } else {
9821 cfg_beg = ASC_EEP_DVC_CFG_BEG;
9822 cfg_end = ASC_EEP_MAX_DVC_ADDR;
9823 }
9824 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
9825 wval = AscReadEEPWord(iop_base, (uchar)s_addr);
9826 if (s_addr <= uchar_end_in_config) {
9827 /*
9828 * Swap all char fields - must unswap bytes already swapped
9829 * by AscReadEEPWord().
9830 */
9831 *wbuf = le16_to_cpu(wval);
9832 } else {
9833 /* Don't swap word field at the end - cntl field. */
9834 *wbuf = wval;
9835 }
9836 sum += wval; /* Checksum treats all EEPROM data as words. */
9837 }
9838 /*
9839 * Read the checksum word which will be compared against 'sum'
9840 * by the caller. Word field already swapped.
9841 */
9842 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
9843 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009844}
9845
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009846static int __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009847AscSetEEPConfigOnce(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009848{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009849 int n_error;
9850 ushort *wbuf;
9851 ushort word;
9852 ushort sum;
9853 int s_addr;
9854 int cfg_beg;
9855 int cfg_end;
9856 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009857
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009858 wbuf = (ushort *)cfg_buf;
9859 n_error = 0;
9860 sum = 0;
9861 /* Write two config words; AscWriteEEPWord() will swap bytes. */
9862 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
9863 sum += *wbuf;
9864 if (*wbuf != AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
9865 n_error++;
9866 }
9867 }
9868 if (bus_type & ASC_IS_VL) {
9869 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
9870 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
9871 } else {
9872 cfg_beg = ASC_EEP_DVC_CFG_BEG;
9873 cfg_end = ASC_EEP_MAX_DVC_ADDR;
9874 }
9875 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
9876 if (s_addr <= uchar_end_in_config) {
9877 /*
9878 * This is a char field. Swap char fields before they are
9879 * swapped again by AscWriteEEPWord().
9880 */
9881 word = cpu_to_le16(*wbuf);
9882 if (word !=
9883 AscWriteEEPWord(iop_base, (uchar)s_addr, word)) {
9884 n_error++;
9885 }
9886 } else {
9887 /* Don't swap word field at the end - cntl field. */
9888 if (*wbuf !=
9889 AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
9890 n_error++;
9891 }
9892 }
9893 sum += *wbuf; /* Checksum calculated from word values. */
9894 }
9895 /* Write checksum word. It will be swapped by AscWriteEEPWord(). */
9896 *wbuf = sum;
9897 if (sum != AscWriteEEPWord(iop_base, (uchar)s_addr, sum)) {
9898 n_error++;
9899 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009900
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009901 /* Read EEPROM back again. */
9902 wbuf = (ushort *)cfg_buf;
9903 /*
9904 * Read two config words; Byte-swapping done by AscReadEEPWord().
9905 */
9906 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
9907 if (*wbuf != AscReadEEPWord(iop_base, (uchar)s_addr)) {
9908 n_error++;
9909 }
9910 }
9911 if (bus_type & ASC_IS_VL) {
9912 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
9913 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
9914 } else {
9915 cfg_beg = ASC_EEP_DVC_CFG_BEG;
9916 cfg_end = ASC_EEP_MAX_DVC_ADDR;
9917 }
9918 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
9919 if (s_addr <= uchar_end_in_config) {
9920 /*
9921 * Swap all char fields. Must unswap bytes already swapped
9922 * by AscReadEEPWord().
9923 */
9924 word =
9925 le16_to_cpu(AscReadEEPWord
9926 (iop_base, (uchar)s_addr));
9927 } else {
9928 /* Don't swap word field at the end - cntl field. */
9929 word = AscReadEEPWord(iop_base, (uchar)s_addr);
9930 }
9931 if (*wbuf != word) {
9932 n_error++;
9933 }
9934 }
9935 /* Read checksum; Byte swapping not needed. */
9936 if (AscReadEEPWord(iop_base, (uchar)s_addr) != sum) {
9937 n_error++;
9938 }
9939 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009940}
9941
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009942static int __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009943AscSetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009944{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009945 int retry;
9946 int n_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009947
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009948 retry = 0;
9949 while (TRUE) {
9950 if ((n_error = AscSetEEPConfigOnce(iop_base, cfg_buf,
9951 bus_type)) == 0) {
9952 break;
9953 }
9954 if (++retry > ASC_EEP_MAX_RETRY) {
9955 break;
9956 }
9957 }
9958 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009959}
9960
Matthew Wilcox47d853c2007-07-26 11:41:33 -04009961static void AscAsyncFix(ASC_DVC_VAR *asc_dvc, struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009962{
Matthew Wilcox47d853c2007-07-26 11:41:33 -04009963 char type = sdev->type;
9964 ASC_SCSI_BIT_ID_TYPE tid_bits = 1 << sdev->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009965
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009966 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) {
9967 if (!(asc_dvc->init_sdtr & tid_bits)) {
Matthew Wilcox47d853c2007-07-26 11:41:33 -04009968 if ((type == TYPE_ROM) &&
9969 (strncmp(sdev->vendor, "HP ", 3) == 0)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009970 asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
9971 }
9972 asc_dvc->pci_fix_asyn_xfer |= tid_bits;
Matthew Wilcox47d853c2007-07-26 11:41:33 -04009973 if ((type == TYPE_PROCESSOR) ||
9974 (type == TYPE_SCANNER) || (type == TYPE_ROM) ||
9975 (type == TYPE_TAPE)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009976 asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
9977 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009978
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009979 if (asc_dvc->pci_fix_asyn_xfer & tid_bits) {
9980 AscSetRunChipSynRegAtID(asc_dvc->iop_base,
Matthew Wilcox47d853c2007-07-26 11:41:33 -04009981 sdev->id,
9982 ASYN_SDTR_DATA_FIX_PCI_REV_AB);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009983 }
9984 }
9985 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009986}
9987
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009988static uchar AscReadLramByte(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009989{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009990 uchar byte_data;
9991 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009992
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009993 if (isodd_word(addr)) {
9994 AscSetChipLramAddr(iop_base, addr - 1);
9995 word_data = AscGetChipLramData(iop_base);
9996 byte_data = (uchar)((word_data >> 8) & 0xFF);
9997 } else {
9998 AscSetChipLramAddr(iop_base, addr);
9999 word_data = AscGetChipLramData(iop_base);
10000 byte_data = (uchar)(word_data & 0xFF);
10001 }
10002 return (byte_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010003}
Linus Torvalds1da177e2005-04-16 15:20:36 -070010004
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010005static ushort AscReadLramWord(PortAddr iop_base, ushort addr)
10006{
10007 ushort word_data;
10008
10009 AscSetChipLramAddr(iop_base, addr);
10010 word_data = AscGetChipLramData(iop_base);
10011 return (word_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010012}
10013
10014#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010015static ASC_DCNT AscReadLramDWord(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010016{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010017 ushort val_low, val_high;
10018 ASC_DCNT dword_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010019
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010020 AscSetChipLramAddr(iop_base, addr);
10021 val_low = AscGetChipLramData(iop_base);
10022 val_high = AscGetChipLramData(iop_base);
10023 dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low;
10024 return (dword_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010025}
10026#endif /* CC_VERY_LONG_SG_LIST */
10027
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010028static void AscWriteLramWord(PortAddr iop_base, ushort addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010029{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010030 AscSetChipLramAddr(iop_base, addr);
10031 AscSetChipLramData(iop_base, word_val);
10032 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010033}
10034
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010035static void AscWriteLramByte(PortAddr iop_base, ushort addr, uchar byte_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010036{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010037 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010038
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010039 if (isodd_word(addr)) {
10040 addr--;
10041 word_data = AscReadLramWord(iop_base, addr);
10042 word_data &= 0x00FF;
10043 word_data |= (((ushort)byte_val << 8) & 0xFF00);
10044 } else {
10045 word_data = AscReadLramWord(iop_base, addr);
10046 word_data &= 0xFF00;
10047 word_data |= ((ushort)byte_val & 0x00FF);
10048 }
10049 AscWriteLramWord(iop_base, addr, word_data);
10050 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010051}
10052
10053/*
10054 * Copy 2 bytes to LRAM.
10055 *
10056 * The source data is assumed to be in little-endian order in memory
10057 * and is maintained in little-endian order when written to LRAM.
10058 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010059static void
10060AscMemWordCopyPtrToLram(PortAddr iop_base,
10061 ushort s_addr, uchar *s_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010062{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010063 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010064
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010065 AscSetChipLramAddr(iop_base, s_addr);
10066 for (i = 0; i < 2 * words; i += 2) {
10067 /*
10068 * On a little-endian system the second argument below
10069 * produces a little-endian ushort which is written to
10070 * LRAM in little-endian order. On a big-endian system
10071 * the second argument produces a big-endian ushort which
10072 * is "transparently" byte-swapped by outpw() and written
10073 * in little-endian order to LRAM.
10074 */
10075 outpw(iop_base + IOP_RAM_DATA,
10076 ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]);
10077 }
10078 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010079}
10080
10081/*
10082 * Copy 4 bytes to LRAM.
10083 *
10084 * The source data is assumed to be in little-endian order in memory
10085 * and is maintained in little-endian order when writen to LRAM.
10086 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010087static void
10088AscMemDWordCopyPtrToLram(PortAddr iop_base,
10089 ushort s_addr, uchar *s_buffer, int dwords)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010090{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010091 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010092
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010093 AscSetChipLramAddr(iop_base, s_addr);
10094 for (i = 0; i < 4 * dwords; i += 4) {
10095 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]); /* LSW */
10096 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 3] << 8) | s_buffer[i + 2]); /* MSW */
10097 }
10098 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010099}
10100
10101/*
10102 * Copy 2 bytes from LRAM.
10103 *
10104 * The source data is assumed to be in little-endian order in LRAM
10105 * and is maintained in little-endian order when written to memory.
10106 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010107static void
10108AscMemWordCopyPtrFromLram(PortAddr iop_base,
10109 ushort s_addr, uchar *d_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010110{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010111 int i;
10112 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010113
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010114 AscSetChipLramAddr(iop_base, s_addr);
10115 for (i = 0; i < 2 * words; i += 2) {
10116 word = inpw(iop_base + IOP_RAM_DATA);
10117 d_buffer[i] = word & 0xff;
10118 d_buffer[i + 1] = (word >> 8) & 0xff;
10119 }
10120 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010121}
10122
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010123static ASC_DCNT AscMemSumLramWord(PortAddr iop_base, ushort s_addr, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010124{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010125 ASC_DCNT sum;
10126 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010127
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010128 sum = 0L;
10129 for (i = 0; i < words; i++, s_addr += 2) {
10130 sum += AscReadLramWord(iop_base, s_addr);
10131 }
10132 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010133}
10134
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010135static void
10136AscMemWordSetLram(PortAddr iop_base, ushort s_addr, ushort set_wval, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010137{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010138 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010139
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010140 AscSetChipLramAddr(iop_base, s_addr);
10141 for (i = 0; i < words; i++) {
10142 AscSetChipLramData(iop_base, set_wval);
10143 }
10144 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010145}
10146
Linus Torvalds1da177e2005-04-16 15:20:36 -070010147/*
10148 * --- Adv Library Functions
10149 */
10150
10151/* a_mcode.h */
10152
10153/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010154static unsigned char _adv_asc3550_buf[] = {
10155 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x18, 0xe4, 0x00, 0xfc,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010156 0x01, 0x00, 0x48, 0xe4, 0xbe, 0x18, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00,
10157 0x00, 0xfa, 0xff, 0xff, 0x28, 0x0e, 0x9e, 0xe7, 0xff, 0x00, 0x82, 0xe7,
10158 0x00, 0xea, 0x00, 0xf6, 0x01, 0xe6, 0x09, 0xe7, 0x55, 0xf0, 0x01, 0xf6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010159 0x01, 0xfa, 0x08, 0x00, 0x03, 0x00, 0x04, 0x00, 0x18, 0xf4, 0x10, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010160 0x00, 0xec, 0x85, 0xf0, 0xbc, 0x00, 0xd5, 0xf0, 0x8e, 0x0c, 0x38, 0x54,
10161 0x00, 0xe6, 0x1e, 0xf0, 0x86, 0xf0, 0xb4, 0x00, 0x98, 0x57, 0xd0, 0x01,
10162 0x0c, 0x1c, 0x3e, 0x1c, 0x0c, 0x00, 0xbb, 0x00, 0xaa, 0x18, 0x02, 0x80,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010163 0x32, 0xf0, 0x01, 0xfc, 0x88, 0x0c, 0xc6, 0x12, 0x02, 0x13, 0x18, 0x40,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010164 0x00, 0x57, 0x01, 0xea, 0x3c, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12,
10165 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00, 0xc0, 0x00, 0x01, 0x01,
10166 0x3e, 0x01, 0xda, 0x0f, 0x22, 0x10, 0x08, 0x12, 0x02, 0x4a, 0xb9, 0x54,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010167 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x20, 0x00, 0x32, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010168 0x3e, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01,
10169 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01, 0x78, 0x01, 0x62, 0x0a,
10170 0x92, 0x0c, 0x2c, 0x10, 0x2e, 0x10, 0x06, 0x13, 0x4c, 0x1c, 0xbb, 0x55,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010171 0x3c, 0x56, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0xb1, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010172 0x03, 0xf7, 0x06, 0xf7, 0x03, 0xfc, 0x0f, 0x00, 0x40, 0x00, 0xbe, 0x00,
10173 0x00, 0x01, 0xb0, 0x08, 0x30, 0x13, 0x64, 0x15, 0x32, 0x1c, 0x38, 0x1c,
10174 0x4e, 0x1c, 0x10, 0x44, 0x02, 0x48, 0x00, 0x4c, 0x04, 0xea, 0x5d, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010175 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010176 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x4e, 0x0b, 0x1e, 0x0e, 0x0c, 0x10,
10177 0x0a, 0x12, 0x04, 0x13, 0x40, 0x13, 0x30, 0x1c, 0x00, 0x4e, 0xbd, 0x56,
10178 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0, 0x59, 0xf0, 0xa7, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010179 0xb8, 0xf0, 0x0e, 0xf7, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010180 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00,
10181 0xde, 0x03, 0x56, 0x0a, 0x14, 0x0e, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10,
10182 0x36, 0x10, 0x0a, 0x13, 0x12, 0x13, 0x52, 0x13, 0x10, 0x15, 0x14, 0x15,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010183 0xac, 0x16, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010184 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x83, 0x55,
10185 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0, 0x0c, 0xf0,
10186 0x5c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010187 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x1c, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010188 0x9e, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01,
10189 0x26, 0x01, 0x79, 0x01, 0x7a, 0x01, 0xc0, 0x01, 0xc2, 0x01, 0x7c, 0x02,
10190 0x5a, 0x03, 0xea, 0x04, 0xe8, 0x07, 0x68, 0x08, 0x69, 0x08, 0xba, 0x08,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010191 0xe9, 0x09, 0x06, 0x0b, 0x3a, 0x0e, 0x00, 0x10, 0x1a, 0x10, 0xed, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010192 0xf1, 0x10, 0x06, 0x12, 0x0c, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x82, 0x13,
10193 0x42, 0x14, 0xd6, 0x14, 0x8a, 0x15, 0xc6, 0x17, 0xd2, 0x17, 0x6b, 0x18,
10194 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0x48, 0x47,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010195 0x41, 0x48, 0x89, 0x48, 0x80, 0x4c, 0x00, 0x54, 0x44, 0x55, 0xe5, 0x55,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010196 0x14, 0x56, 0x77, 0x57, 0xbf, 0x57, 0x40, 0x5c, 0x06, 0x80, 0x08, 0x90,
10197 0x03, 0xa1, 0xfe, 0x9c, 0xf0, 0x29, 0x02, 0xfe, 0xb8, 0x0c, 0xff, 0x10,
10198 0x00, 0x00, 0xd0, 0xfe, 0xcc, 0x18, 0x00, 0xcf, 0xfe, 0x80, 0x01, 0xff,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010199 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010200 0x00, 0xfe, 0x57, 0x24, 0x00, 0xfe, 0x48, 0x00, 0x4f, 0xff, 0x04, 0x00,
10201 0x00, 0x10, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x08,
10202 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x0f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010203 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010204 0xfe, 0x04, 0xf7, 0xcf, 0x2a, 0x67, 0x0b, 0x01, 0xfe, 0xce, 0x0e, 0xfe,
10205 0x04, 0xf7, 0xcf, 0x67, 0x0b, 0x3c, 0x2a, 0xfe, 0x3d, 0xf0, 0xfe, 0x02,
10206 0x02, 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x91, 0xf0, 0xfe, 0xf0, 0x01, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010207 0x90, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, 0x8f, 0xf0, 0x9c, 0x05, 0x51, 0x3b,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010208 0x02, 0xfe, 0xd4, 0x0c, 0x01, 0xfe, 0x44, 0x0d, 0xfe, 0xdd, 0x12, 0xfe,
10209 0xfc, 0x10, 0xfe, 0x28, 0x1c, 0x05, 0xfe, 0xa6, 0x00, 0xfe, 0xd3, 0x12,
10210 0x47, 0x18, 0xfe, 0xa6, 0x00, 0xb5, 0xfe, 0x48, 0xf0, 0xfe, 0x86, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010211 0xfe, 0x49, 0xf0, 0xfe, 0xa0, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xbe, 0x02,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010212 0xfe, 0x46, 0xf0, 0xfe, 0x50, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x56, 0x02,
10213 0xfe, 0x43, 0xf0, 0xfe, 0x44, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x48, 0x02,
10214 0xfe, 0x45, 0xf0, 0xfe, 0x4c, 0x02, 0x17, 0x0b, 0xa0, 0x17, 0x06, 0x18,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010215 0x96, 0x02, 0x29, 0xfe, 0x00, 0x1c, 0xde, 0xfe, 0x02, 0x1c, 0xdd, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010216 0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0xfe, 0x20, 0x17, 0xfe, 0xe7, 0x10,
10217 0xfe, 0x06, 0xfc, 0xc7, 0x0a, 0x6b, 0x01, 0x9e, 0x02, 0x29, 0x14, 0x4d,
10218 0x37, 0x97, 0x01, 0xfe, 0x64, 0x0f, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xbd,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010219 0x10, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010220 0x58, 0x1c, 0x17, 0x06, 0x18, 0x96, 0x2a, 0x25, 0x29, 0xfe, 0x3d, 0xf0,
10221 0xfe, 0x02, 0x02, 0x21, 0xfe, 0x94, 0x02, 0xfe, 0x5a, 0x1c, 0xea, 0xfe,
10222 0x14, 0x1c, 0x14, 0xfe, 0x30, 0x00, 0x37, 0x97, 0x01, 0xfe, 0x54, 0x0f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010223 0x17, 0x06, 0x18, 0x96, 0x02, 0xd0, 0x1e, 0x20, 0x07, 0x10, 0x34, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010224 0x69, 0x10, 0x17, 0x06, 0x18, 0x96, 0xfe, 0x04, 0xec, 0x20, 0x46, 0x3d,
10225 0x12, 0x20, 0xfe, 0x05, 0xf6, 0xc7, 0x01, 0xfe, 0x52, 0x16, 0x09, 0x4a,
10226 0x4c, 0x35, 0x11, 0x2d, 0x3c, 0x8a, 0x01, 0xe6, 0x02, 0x29, 0x0a, 0x40,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010227 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x01, 0x6f, 0xfe, 0x18, 0x10, 0xfe, 0x41,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010228 0x58, 0x0a, 0x99, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x64, 0xfe, 0x0c, 0x03,
10229 0x01, 0xe6, 0x02, 0x29, 0x2a, 0x46, 0xfe, 0x02, 0xe8, 0x27, 0xf8, 0xfe,
10230 0x9e, 0x43, 0xf7, 0xfe, 0x27, 0xf0, 0xfe, 0xdc, 0x01, 0xfe, 0x07, 0x4b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010231 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x40, 0x1c, 0x25, 0xd2, 0xfe, 0x26, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010232 0xfe, 0x56, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x44, 0x03, 0xfe, 0x11, 0xf0,
10233 0x9c, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x64, 0x03, 0xeb, 0x0f,
10234 0xfe, 0x11, 0x00, 0x02, 0x5a, 0x2a, 0xfe, 0x48, 0x1c, 0xeb, 0x09, 0x04,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010235 0x1d, 0xfe, 0x18, 0x13, 0x23, 0x1e, 0x98, 0xac, 0x12, 0x98, 0x0a, 0x40,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010236 0x01, 0x0e, 0xac, 0x75, 0x01, 0xfe, 0xbc, 0x15, 0x11, 0xca, 0x25, 0xd2,
10237 0xfe, 0x01, 0xf0, 0xd2, 0xfe, 0x82, 0xf0, 0xfe, 0x92, 0x03, 0xec, 0x11,
10238 0xfe, 0xe4, 0x00, 0x65, 0xfe, 0xa4, 0x03, 0x25, 0x32, 0x1f, 0xfe, 0xb4,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010239 0x03, 0x01, 0x43, 0xfe, 0x06, 0xf0, 0xfe, 0xc4, 0x03, 0x8d, 0x81, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010240 0x0a, 0xf0, 0xfe, 0x7a, 0x06, 0x02, 0x22, 0x05, 0x6b, 0x28, 0x16, 0xfe,
10241 0xf6, 0x04, 0x14, 0x2c, 0x01, 0x33, 0x8f, 0xfe, 0x66, 0x02, 0x02, 0xd1,
10242 0xeb, 0x2a, 0x67, 0x1a, 0xfe, 0x67, 0x1b, 0xf8, 0xf7, 0xfe, 0x48, 0x1c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010243 0x70, 0x01, 0x6e, 0x87, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x16, 0xd3,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010244 0x0a, 0xca, 0x01, 0x0e, 0x74, 0x60, 0x59, 0x76, 0x27, 0x05, 0x6b, 0x28,
10245 0xfe, 0x10, 0x12, 0x14, 0x2c, 0x01, 0x33, 0x8f, 0xfe, 0x66, 0x02, 0x02,
10246 0xd1, 0xbc, 0x7d, 0xbd, 0x7f, 0x25, 0x22, 0x65, 0xfe, 0x3c, 0x04, 0x1f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010247 0xfe, 0x38, 0x04, 0x68, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010248 0x12, 0x2b, 0xff, 0x02, 0x00, 0x10, 0x01, 0x08, 0x1f, 0xfe, 0xe0, 0x04,
10249 0x2b, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd5, 0xfe, 0x4c, 0x44, 0xfe,
10250 0x4c, 0x12, 0x60, 0xfe, 0x44, 0x48, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010251 0xd3, 0x46, 0x76, 0x27, 0xfa, 0xef, 0xfe, 0x62, 0x13, 0x09, 0x04, 0x1d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010252 0xfe, 0x2a, 0x13, 0x2f, 0x07, 0x7e, 0xa5, 0xfe, 0x20, 0x10, 0x13, 0x2c,
10253 0xfe, 0x4c, 0x54, 0x64, 0xd3, 0xfa, 0xef, 0x86, 0x09, 0x04, 0x1d, 0xfe,
10254 0x08, 0x13, 0x2f, 0x07, 0x7e, 0x6e, 0x09, 0x04, 0x1d, 0xfe, 0x1c, 0x12,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010255 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010256 0x70, 0x0c, 0x02, 0x22, 0x2b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90,
10257 0xf9, 0x03, 0x14, 0x92, 0x01, 0x33, 0x02, 0x29, 0xfe, 0x42, 0x5b, 0x67,
10258 0x1a, 0xfe, 0x46, 0x59, 0xf8, 0xf7, 0xfe, 0x87, 0x80, 0xfe, 0x31, 0xe4,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010259 0x4f, 0x09, 0x04, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x1a,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010260 0xfe, 0x70, 0x12, 0x49, 0x04, 0x06, 0xfe, 0x60, 0x13, 0x05, 0xfe, 0xa2,
10261 0x00, 0x28, 0x16, 0xfe, 0x80, 0x05, 0xfe, 0x31, 0xe4, 0x6a, 0x49, 0x04,
10262 0x0b, 0xfe, 0x4a, 0x13, 0x05, 0xfe, 0xa0, 0x00, 0x28, 0xfe, 0x42, 0x12,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010263 0x5e, 0x01, 0x08, 0x25, 0x32, 0xf1, 0x01, 0x08, 0x26, 0xfe, 0x98, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010264 0x11, 0xfe, 0xe3, 0x00, 0x23, 0x49, 0xfe, 0x4a, 0xf0, 0xfe, 0x6a, 0x05,
10265 0xfe, 0x49, 0xf0, 0xfe, 0x64, 0x05, 0x83, 0x24, 0xfe, 0x21, 0x00, 0xa1,
10266 0x24, 0xfe, 0x22, 0x00, 0xa0, 0x24, 0x4c, 0xfe, 0x09, 0x48, 0x01, 0x08,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010267 0x26, 0xfe, 0x98, 0x05, 0xfe, 0xe2, 0x08, 0x49, 0x04, 0xc5, 0x3b, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010268 0x86, 0x24, 0x06, 0x12, 0xcc, 0x37, 0xfe, 0x27, 0x01, 0x09, 0x04, 0x1d,
10269 0xfe, 0x22, 0x12, 0x47, 0x01, 0xa7, 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b,
10270 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c, 0x02, 0x22, 0x05, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010271 0x9c, 0x00, 0x28, 0xfe, 0x3e, 0x12, 0x05, 0x50, 0x28, 0xfe, 0x36, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010272 0x47, 0x01, 0xa7, 0x26, 0xfe, 0x08, 0x06, 0x0a, 0x06, 0x49, 0x04, 0x19,
10273 0xfe, 0x02, 0x12, 0x5f, 0x01, 0xfe, 0xaa, 0x14, 0x1f, 0xfe, 0xfe, 0x05,
10274 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x50, 0xb4, 0x0c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010275 0x50, 0x05, 0xc6, 0x28, 0xfe, 0x62, 0x12, 0x05, 0x3f, 0x28, 0xfe, 0x5a,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010276 0x13, 0x01, 0xfe, 0x14, 0x18, 0x01, 0xfe, 0x66, 0x18, 0xfe, 0x43, 0x48,
10277 0xb7, 0x19, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0x1c, 0x3d,
10278 0x85, 0xb7, 0x69, 0x47, 0x01, 0xa7, 0x26, 0xfe, 0x72, 0x06, 0x49, 0x04,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010279 0x1b, 0xdf, 0x89, 0x0a, 0x4d, 0x01, 0xfe, 0xd8, 0x14, 0x1f, 0xfe, 0x68,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010280 0x06, 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x3f, 0xb4,
10281 0x0c, 0x3f, 0x17, 0x06, 0x01, 0xa7, 0xec, 0x72, 0x70, 0x01, 0x6e, 0x87,
10282 0x11, 0xfe, 0xe2, 0x00, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010283 0xa6, 0x06, 0x8c, 0xfe, 0x5c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, 0x64, 0x07,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010284 0x8d, 0x81, 0x02, 0x22, 0x09, 0x04, 0x0b, 0xfe, 0x2e, 0x12, 0x15, 0x1a,
10285 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00,
10286 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x15, 0x00, 0x02, 0xfe, 0x32,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010287 0x08, 0x61, 0x04, 0x1b, 0xfe, 0x38, 0x12, 0x09, 0x04, 0x1b, 0x6e, 0x15,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010288 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01,
10289 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x06, 0x01, 0x08, 0x15, 0x00, 0x02,
10290 0xd9, 0x66, 0x4c, 0xfe, 0x3a, 0x55, 0x5f, 0xfe, 0x9a, 0x81, 0x4b, 0x1d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010291 0xba, 0xfe, 0x32, 0x07, 0x0a, 0x1d, 0xfe, 0x09, 0x6f, 0xaf, 0xfe, 0xca,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010292 0x45, 0xfe, 0x32, 0x12, 0x62, 0x2c, 0x85, 0x66, 0x7b, 0x01, 0x08, 0x25,
10293 0x32, 0xfe, 0x0a, 0xf0, 0xfe, 0x32, 0x07, 0x8d, 0x81, 0x8c, 0xfe, 0x5c,
10294 0x07, 0x02, 0x22, 0x01, 0x43, 0x02, 0xfe, 0x8a, 0x06, 0x15, 0x19, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010295 0xfe, 0x8a, 0x06, 0xfe, 0x9c, 0xf7, 0xd4, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010296 0x90, 0x77, 0xfe, 0xca, 0x07, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x4a, 0x6a,
10297 0x35, 0x1e, 0x20, 0x07, 0x10, 0xfe, 0x0e, 0x12, 0x74, 0xfe, 0x80, 0x80,
10298 0x37, 0x20, 0x63, 0x27, 0xfe, 0x06, 0x10, 0xfe, 0x83, 0xe7, 0xc4, 0xa1,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010299 0xfe, 0x03, 0x40, 0x09, 0x4a, 0x4f, 0x35, 0x01, 0xa8, 0xad, 0xfe, 0x1f,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010300 0x40, 0x12, 0x58, 0x01, 0xa5, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe,
10301 0x44, 0x51, 0xfe, 0xc6, 0x51, 0x83, 0xfb, 0xfe, 0x8a, 0x90, 0x0c, 0x52,
10302 0x18, 0x53, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010303 0xc2, 0x50, 0x0c, 0x39, 0x18, 0x3a, 0xfe, 0x4a, 0x10, 0x09, 0x04, 0x6a,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010304 0xfe, 0x2a, 0x12, 0xfe, 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x54, 0x18,
10305 0x55, 0x09, 0x04, 0x4f, 0x85, 0x01, 0xa8, 0xfe, 0x1f, 0x80, 0x12, 0x58,
10306 0xfe, 0x44, 0x90, 0xfe, 0xc6, 0x90, 0x0c, 0x56, 0x18, 0x57, 0xfb, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010307 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010308 0x0c, 0x39, 0x18, 0x3a, 0x0c, 0x38, 0x18, 0x4e, 0x09, 0x4a, 0x19, 0x35,
10309 0x2a, 0x13, 0xfe, 0x4e, 0x11, 0x65, 0xfe, 0x48, 0x08, 0xfe, 0x9e, 0xf0,
10310 0xfe, 0x5c, 0x08, 0xb1, 0x16, 0x32, 0x2a, 0x73, 0xdd, 0xb8, 0xfe, 0x80,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010311 0x08, 0xb9, 0xfe, 0x9e, 0x08, 0x8c, 0xfe, 0x74, 0x08, 0xfe, 0x06, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010312 0xfe, 0x7a, 0x08, 0x8d, 0x81, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xc9, 0x10,
10313 0x15, 0x19, 0xfe, 0xc9, 0x10, 0x61, 0x04, 0x06, 0xfe, 0x10, 0x12, 0x61,
10314 0x04, 0x0b, 0x45, 0x09, 0x04, 0x0b, 0xfe, 0x68, 0x12, 0xfe, 0x2e, 0x1c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010315 0x02, 0xfe, 0x24, 0x0a, 0x61, 0x04, 0x06, 0x45, 0x61, 0x04, 0x0b, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010316 0x52, 0x12, 0xfe, 0x2c, 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x1e, 0x09, 0xfe,
10317 0xac, 0xf0, 0xfe, 0xbe, 0x08, 0xfe, 0x8a, 0x10, 0xaa, 0xfe, 0xf3, 0x10,
10318 0xfe, 0xad, 0xf0, 0xfe, 0xca, 0x08, 0x02, 0xfe, 0x24, 0x0a, 0xab, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010319 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0x9d, 0xe9, 0x1c, 0xfe, 0x00, 0xfe, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010320 0x1c, 0x12, 0xb5, 0xfe, 0xd2, 0xf0, 0x9d, 0xfe, 0x76, 0x18, 0x1c, 0x1a,
10321 0x16, 0x9d, 0x05, 0xcb, 0x1c, 0x06, 0x16, 0x9d, 0xb8, 0x6d, 0xb9, 0x6d,
10322 0xaa, 0xab, 0xfe, 0xb1, 0x10, 0x70, 0x5e, 0x2b, 0x14, 0x92, 0x01, 0x33,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010323 0x0f, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x5a, 0x0f, 0x7c, 0x02, 0x5a,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010324 0xfe, 0x74, 0x18, 0x1c, 0xfe, 0x00, 0xf8, 0x16, 0x6d, 0x67, 0x1b, 0x01,
10325 0xfe, 0x44, 0x0d, 0x3b, 0x01, 0xe6, 0x1e, 0x27, 0x74, 0x67, 0x1a, 0x02,
10326 0x6d, 0x09, 0x04, 0x0b, 0x21, 0xfe, 0x06, 0x0a, 0x09, 0x04, 0x6a, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010327 0x82, 0x12, 0x09, 0x04, 0x19, 0xfe, 0x66, 0x13, 0x1e, 0x58, 0xac, 0xfc,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010328 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91,
10329 0xfe, 0x86, 0x91, 0x63, 0x27, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x77,
10330 0xd7, 0x05, 0x54, 0x31, 0x55, 0x0c, 0x7b, 0x18, 0x7c, 0xbe, 0x54, 0xbf,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010331 0x55, 0x01, 0xa8, 0xad, 0x63, 0x27, 0x12, 0x58, 0xc0, 0x38, 0xc1, 0x4e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010332 0x79, 0x56, 0x68, 0x57, 0xf4, 0xf5, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05,
10333 0xfa, 0x4e, 0x01, 0xa5, 0xa2, 0x23, 0x0c, 0x7b, 0x0c, 0x7c, 0x79, 0x56,
10334 0x68, 0x57, 0xfe, 0x12, 0x10, 0x09, 0x04, 0x19, 0x16, 0xd7, 0x79, 0x39,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010335 0x68, 0x3a, 0x09, 0x04, 0xfe, 0xf7, 0x00, 0x35, 0x05, 0x52, 0x31, 0x53,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010336 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59,
10337 0x02, 0x6d, 0x09, 0x04, 0x19, 0x16, 0xd7, 0x09, 0x04, 0xfe, 0xf7, 0x00,
10338 0x35, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x5f, 0xfe, 0x10, 0x90, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010339 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x2f, 0x07, 0x9b, 0x16, 0xfe, 0xc6, 0x08,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010340 0x11, 0x9b, 0x09, 0x04, 0x0b, 0xfe, 0x14, 0x13, 0x05, 0x39, 0x31, 0x3a,
10341 0x77, 0xfe, 0xc6, 0x08, 0xfe, 0x0c, 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x6d,
10342 0x23, 0x47, 0xfe, 0x19, 0x80, 0xde, 0x09, 0x04, 0x0b, 0xfe, 0x1a, 0x12,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010343 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xe9, 0xb5, 0xfe, 0xd1, 0xf0, 0xd9,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010344 0x14, 0x7a, 0x01, 0x33, 0x0f, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe,
10345 0x6c, 0x19, 0xbe, 0x39, 0xfe, 0xed, 0x19, 0xbf, 0x3a, 0xfe, 0x0c, 0x51,
10346 0xfe, 0x8e, 0x51, 0xe9, 0x1c, 0xfe, 0x00, 0xff, 0x34, 0xfe, 0x74, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010347 0xb5, 0xfe, 0xd2, 0xf0, 0xfe, 0xb2, 0x0a, 0xfe, 0x76, 0x18, 0x1c, 0x1a,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010348 0x84, 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0x08, 0x13, 0x0f, 0xfe, 0x16, 0x00,
10349 0x02, 0x5a, 0xfe, 0xd1, 0xf0, 0xfe, 0xc4, 0x0a, 0x14, 0x7a, 0x01, 0x33,
10350 0x0f, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe, 0xce, 0xf0, 0xfe, 0xca,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010351 0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x0f, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010352 0x22, 0x00, 0x02, 0x5a, 0xfe, 0xcb, 0xf0, 0xfe, 0xe2, 0x0a, 0x0f, 0xfe,
10353 0x24, 0x00, 0x02, 0x5a, 0xfe, 0xd0, 0xf0, 0xfe, 0xec, 0x0a, 0x0f, 0x93,
10354 0xdc, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x0f, 0x4c, 0xfe, 0x10, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010355 0xfe, 0xcc, 0xf0, 0xd9, 0x61, 0x04, 0x19, 0x3b, 0x0f, 0xfe, 0x12, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010356 0x2a, 0x13, 0xfe, 0x4e, 0x11, 0x65, 0xfe, 0x0c, 0x0b, 0xfe, 0x9e, 0xf0,
10357 0xfe, 0x20, 0x0b, 0xb1, 0x16, 0x32, 0x2a, 0x73, 0xdd, 0xb8, 0x22, 0xb9,
10358 0x22, 0x2a, 0xec, 0x65, 0xfe, 0x2c, 0x0b, 0x25, 0x32, 0x8c, 0xfe, 0x48,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010359 0x0b, 0x8d, 0x81, 0xb8, 0xd4, 0xb9, 0xd4, 0x02, 0x22, 0x01, 0x43, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010360 0xdb, 0x10, 0x11, 0xfe, 0xe8, 0x00, 0xaa, 0xab, 0x70, 0xbc, 0x7d, 0xbd,
10361 0x7f, 0xfe, 0x89, 0xf0, 0x22, 0x30, 0x2e, 0xd8, 0xbc, 0x7d, 0xbd, 0x7f,
10362 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd6, 0xb1, 0x45, 0x0f, 0xfe, 0x42,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010363 0x00, 0x02, 0x5a, 0x78, 0x06, 0xfe, 0x81, 0x49, 0x16, 0xfe, 0x38, 0x0c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010364 0x09, 0x04, 0x0b, 0xfe, 0x44, 0x13, 0x0f, 0x00, 0x4b, 0x0b, 0xfe, 0x54,
10365 0x12, 0x4b, 0xfe, 0x28, 0x00, 0x21, 0xfe, 0xa6, 0x0c, 0x0a, 0x40, 0x01,
10366 0x0e, 0x07, 0x00, 0x5d, 0x3e, 0xfe, 0x28, 0x00, 0xfe, 0xe2, 0x10, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010367 0xe7, 0x01, 0xe8, 0x0a, 0x99, 0x01, 0xfe, 0x32, 0x0e, 0x59, 0x11, 0x2d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010368 0x01, 0x6f, 0x02, 0x29, 0x0f, 0xfe, 0x44, 0x00, 0x4b, 0x0b, 0xdf, 0x3e,
10369 0x0b, 0xfe, 0xb4, 0x10, 0x01, 0x86, 0x3e, 0x0b, 0xfe, 0xaa, 0x10, 0x01,
10370 0x86, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xa3, 0x3e, 0x0b, 0x0f, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010371 0x43, 0x00, 0xfe, 0x96, 0x10, 0x09, 0x4a, 0x0b, 0x35, 0x01, 0xe7, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010372 0xe8, 0x59, 0x11, 0x2d, 0x01, 0x6f, 0x67, 0x0b, 0x59, 0x3c, 0x8a, 0x02,
10373 0xfe, 0x2a, 0x03, 0x09, 0x04, 0x0b, 0x84, 0x3e, 0x0b, 0x0f, 0x00, 0xfe,
10374 0x5c, 0x10, 0x61, 0x04, 0x1b, 0xfe, 0x58, 0x12, 0x09, 0x04, 0x1b, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010375 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x5c, 0x0c, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010376 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x62, 0x0c, 0x09, 0x4a, 0x1b, 0x35,
10377 0xfe, 0xa9, 0x10, 0x0f, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0b, 0x5f,
10378 0x5c, 0x0f, 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x0f, 0xfe, 0x47, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010379 0xa1, 0x0f, 0xfe, 0x41, 0x00, 0xa0, 0x0f, 0xfe, 0x24, 0x00, 0x87, 0xaa,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010380 0xab, 0x70, 0x05, 0x6b, 0x28, 0x21, 0xd1, 0x5f, 0xfe, 0x04, 0xe6, 0x1b,
10381 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x59, 0x01, 0xda, 0x02, 0x29, 0xea,
10382 0x14, 0x0b, 0x37, 0x95, 0xa9, 0x14, 0xfe, 0x31, 0x00, 0x37, 0x97, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010383 0xfe, 0x54, 0x0f, 0x02, 0xd0, 0x3c, 0xfe, 0x06, 0xec, 0xc9, 0xee, 0x3e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010384 0x1d, 0xfe, 0xce, 0x45, 0x34, 0x3c, 0xfe, 0x06, 0xea, 0xc9, 0xfe, 0x47,
10385 0x4b, 0x89, 0xfe, 0x75, 0x57, 0x05, 0x51, 0xfe, 0x98, 0x56, 0xfe, 0x38,
10386 0x12, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x44, 0x48, 0x46, 0x09, 0x04, 0x1d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010387 0xfe, 0x1a, 0x13, 0x0a, 0x40, 0x01, 0x0e, 0x47, 0xfe, 0x41, 0x58, 0x0a,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010388 0x99, 0x01, 0x0e, 0xfe, 0x49, 0x54, 0x8e, 0xfe, 0x2a, 0x0d, 0x02, 0xfe,
10389 0x2a, 0x03, 0x0a, 0x51, 0xfe, 0xee, 0x14, 0xee, 0x3e, 0x1d, 0xfe, 0xce,
10390 0x45, 0x34, 0x3c, 0xfe, 0xce, 0x47, 0xfe, 0xad, 0x13, 0x02, 0x29, 0x1e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010391 0x20, 0x07, 0x10, 0xfe, 0x9e, 0x12, 0x23, 0x12, 0x4d, 0x12, 0x94, 0x12,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010392 0xce, 0x1e, 0x2d, 0x47, 0x37, 0x2d, 0xb1, 0xe0, 0xfe, 0xbc, 0xf0, 0xfe,
10393 0xec, 0x0d, 0x13, 0x06, 0x12, 0x4d, 0x01, 0xfe, 0xe2, 0x15, 0x05, 0xfe,
10394 0x38, 0x01, 0x31, 0xfe, 0x3a, 0x01, 0x77, 0xfe, 0xf0, 0x0d, 0xfe, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010395 0xec, 0xce, 0x62, 0x00, 0x5d, 0xfe, 0x04, 0xec, 0x20, 0x46, 0xfe, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010396 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x52, 0x16, 0xfb, 0xfe, 0x48, 0xf4,
10397 0x0d, 0xfe, 0x18, 0x13, 0xaf, 0xfe, 0x02, 0xea, 0xce, 0x62, 0x7a, 0xfe,
10398 0xc5, 0x13, 0x14, 0x1b, 0x37, 0x95, 0xa9, 0x5c, 0x05, 0xfe, 0x38, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010399 0x1c, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x05, 0xfe, 0x3a, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010400 0x0c, 0xfe, 0x62, 0x01, 0x3d, 0x12, 0x20, 0x24, 0x06, 0x12, 0x2d, 0x11,
10401 0x2d, 0x8a, 0x13, 0x06, 0x03, 0x23, 0x03, 0x1e, 0x4d, 0xfe, 0xf7, 0x12,
10402 0x1e, 0x94, 0xac, 0x12, 0x94, 0x07, 0x7a, 0xfe, 0x71, 0x13, 0xfe, 0x24,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010403 0x1c, 0x14, 0x1a, 0x37, 0x95, 0xa9, 0xfe, 0xd9, 0x10, 0xb6, 0xfe, 0x03,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010404 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x03, 0xb6, 0xfe, 0x03, 0xdc,
10405 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x03, 0xfe, 0x03, 0x57, 0xb6, 0x23,
10406 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0xb6, 0x75, 0x03, 0x09, 0x04,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010407 0x4c, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010408 0xfe, 0x1e, 0x80, 0xe1, 0xfe, 0x1d, 0x80, 0xa4, 0xfe, 0x0c, 0x90, 0xfe,
10409 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xa3, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
10410 0x0b, 0xfe, 0x3c, 0x50, 0xa0, 0x01, 0xfe, 0x82, 0x16, 0x2f, 0x07, 0x2d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010411 0xe0, 0x01, 0xfe, 0xbc, 0x15, 0x09, 0x04, 0x1d, 0x45, 0x01, 0xe7, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010412 0xe8, 0x11, 0xfe, 0xe9, 0x00, 0x09, 0x04, 0x4c, 0xfe, 0x2c, 0x13, 0x01,
10413 0xfe, 0x14, 0x16, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90,
10414 0x0c, 0xfe, 0x64, 0x01, 0x18, 0xfe, 0x66, 0x01, 0x09, 0x04, 0x4f, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010415 0x12, 0x12, 0xfe, 0x03, 0x80, 0x74, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010416 0x40, 0x12, 0x20, 0x63, 0x27, 0x11, 0xc8, 0x59, 0x1e, 0x20, 0xed, 0x76,
10417 0x20, 0x03, 0xfe, 0x08, 0x1c, 0x05, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58,
10418 0x05, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x05, 0xfe, 0xb0, 0x00, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010419 0x08, 0x58, 0x05, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010420 0x24, 0x69, 0x12, 0xc9, 0x23, 0x0c, 0x50, 0x0c, 0x3f, 0x13, 0x40, 0x48,
10421 0x5f, 0x17, 0x1d, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x21, 0xfe, 0x08,
10422 0x0f, 0x3e, 0x10, 0x13, 0x42, 0x48, 0x17, 0x4c, 0xfe, 0x90, 0x4d, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010423 0x91, 0x54, 0x21, 0xfe, 0x1e, 0x0f, 0x24, 0x10, 0x12, 0x20, 0x78, 0x2c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010424 0x46, 0x1e, 0x20, 0xed, 0x76, 0x20, 0x11, 0xc8, 0xf6, 0xfe, 0xd6, 0xf0,
10425 0xfe, 0x32, 0x0f, 0xea, 0x70, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
10426 0x18, 0x1c, 0x03, 0x3c, 0xfe, 0x0c, 0x14, 0xee, 0xfe, 0x07, 0xe6, 0x1d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010427 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x86, 0x78, 0x2c, 0x46,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010428 0xfa, 0xef, 0xfe, 0x42, 0x13, 0x2f, 0x07, 0x2d, 0xfe, 0x34, 0x13, 0x0a,
10429 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x36, 0x12, 0xf0, 0xfe, 0x45, 0x48, 0x01,
10430 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010431 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x6f, 0xfe, 0x0e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010432 0x10, 0x07, 0x7e, 0x45, 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x6c, 0x0f, 0x03,
10433 0xfe, 0x44, 0x58, 0x74, 0xfe, 0x01, 0xec, 0x97, 0xfe, 0x9e, 0x40, 0xfe,
10434 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1b, 0x76, 0x27, 0x01, 0xda, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010435 0xdd, 0x10, 0x2a, 0xbc, 0x7d, 0xbd, 0x7f, 0x30, 0x2e, 0xd5, 0x07, 0x1b,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010436 0xfe, 0x48, 0x12, 0x07, 0x0b, 0xfe, 0x56, 0x12, 0x07, 0x1a, 0xfe, 0x30,
10437 0x12, 0x07, 0xc2, 0x16, 0xfe, 0x3e, 0x11, 0x07, 0xfe, 0x23, 0x00, 0x16,
10438 0xfe, 0x4a, 0x11, 0x07, 0x06, 0x16, 0xfe, 0xa8, 0x11, 0x07, 0x19, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010439 0x12, 0x12, 0x07, 0x00, 0x16, 0x22, 0x14, 0xc2, 0x01, 0x33, 0x9f, 0x2b,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010440 0x01, 0x08, 0x8c, 0x43, 0x03, 0x2b, 0xfe, 0x62, 0x08, 0x0a, 0xca, 0x01,
10441 0xfe, 0x32, 0x0e, 0x11, 0x7e, 0x02, 0x29, 0x2b, 0x2f, 0x07, 0x9b, 0xfe,
10442 0xd9, 0x13, 0x79, 0x39, 0x68, 0x3a, 0x77, 0xfe, 0xfc, 0x10, 0x09, 0x04,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010443 0x6a, 0xfe, 0x72, 0x12, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x8e, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010444 0xc6, 0x10, 0x1e, 0x58, 0xfe, 0x26, 0x13, 0x05, 0x7b, 0x31, 0x7c, 0x77,
10445 0xfe, 0x82, 0x0c, 0x0c, 0x54, 0x18, 0x55, 0x23, 0x0c, 0x7b, 0x0c, 0x7c,
10446 0x01, 0xa8, 0x24, 0x69, 0x73, 0x12, 0x58, 0x01, 0xa5, 0xc0, 0x38, 0xc1,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010447 0x4e, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x38, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010448 0x05, 0xfa, 0x4e, 0xfe, 0x91, 0x10, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x40,
10449 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x56, 0x18, 0x57, 0x83, 0xc0, 0x38, 0xc1,
10450 0x4e, 0xf4, 0xf5, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x00, 0x56, 0xfe, 0xa1,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010451 0x56, 0x0c, 0x52, 0x18, 0x53, 0x09, 0x04, 0x6a, 0xfe, 0x1e, 0x12, 0x1e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010452 0x58, 0xfe, 0x1f, 0x40, 0x05, 0x54, 0x31, 0x55, 0xfe, 0x2c, 0x50, 0xfe,
10453 0xae, 0x50, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x44, 0x50, 0xfe, 0xc6, 0x50,
10454 0x05, 0x52, 0x31, 0x53, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x05, 0x39,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010455 0x31, 0x3a, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x5c, 0x24, 0x06,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010456 0x12, 0xcd, 0x02, 0x5b, 0x2b, 0x01, 0x08, 0x1f, 0x44, 0x30, 0x2e, 0xd5,
10457 0x07, 0x06, 0x21, 0x44, 0x2f, 0x07, 0x9b, 0x21, 0x5b, 0x01, 0x6e, 0x1c,
10458 0x3d, 0x16, 0x44, 0x09, 0x04, 0x0b, 0xe2, 0x79, 0x39, 0x68, 0x3a, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010459 0x0a, 0x55, 0x34, 0xfe, 0x8b, 0x55, 0xbe, 0x39, 0xbf, 0x3a, 0xfe, 0x0c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010460 0x51, 0xfe, 0x8e, 0x51, 0x02, 0x5b, 0xfe, 0x19, 0x81, 0xaf, 0xfe, 0x19,
10461 0x41, 0x02, 0x5b, 0x2b, 0x01, 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e,
10462 0xd8, 0x4b, 0x1a, 0xfe, 0xa6, 0x12, 0x4b, 0x0b, 0x3b, 0x02, 0x44, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010463 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, 0xd6, 0x07, 0x1a, 0x21, 0x44,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010464 0x01, 0x08, 0x1f, 0xa2, 0x30, 0x2e, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49,
10465 0x60, 0x05, 0xfe, 0x9c, 0x00, 0x28, 0x84, 0x49, 0x04, 0x19, 0x34, 0x9f,
10466 0xfe, 0xbb, 0x45, 0x4b, 0x00, 0x45, 0x3e, 0x06, 0x78, 0x3d, 0xfe, 0xda,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010467 0x14, 0x01, 0x6e, 0x87, 0xfe, 0x4b, 0x45, 0xe2, 0x2f, 0x07, 0x9a, 0xe1,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010468 0x05, 0xc6, 0x28, 0x84, 0x05, 0x3f, 0x28, 0x34, 0x5e, 0x02, 0x5b, 0xfe,
10469 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17, 0x05, 0x50, 0xb4, 0x0c,
10470 0x50, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe, 0xaa, 0x14, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010471 0x5c, 0x01, 0x08, 0x25, 0x32, 0x1f, 0x44, 0x30, 0x2e, 0xd6, 0x07, 0x06,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010472 0x21, 0x44, 0x01, 0xfe, 0x8e, 0x13, 0xfe, 0x42, 0x58, 0xfe, 0x82, 0x14,
10473 0xfe, 0xa4, 0x14, 0x87, 0xfe, 0x4a, 0xf4, 0x0b, 0x16, 0x44, 0xfe, 0x4a,
10474 0xf4, 0x06, 0xfe, 0x0c, 0x12, 0x2f, 0x07, 0x9a, 0x85, 0x02, 0x5b, 0x05,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010475 0x3f, 0xb4, 0x0c, 0x3f, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010476 0xd8, 0x14, 0x02, 0x5c, 0x13, 0x06, 0x65, 0xfe, 0xca, 0x12, 0x26, 0xfe,
10477 0xe0, 0x12, 0x72, 0xf1, 0x01, 0x08, 0x23, 0x72, 0x03, 0x8f, 0xfe, 0xdc,
10478 0x12, 0x25, 0xfe, 0xdc, 0x12, 0x1f, 0xfe, 0xca, 0x12, 0x5e, 0x2b, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010479 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010480 0x1c, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13,
10481 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0x1c, 0x3d, 0xfe, 0x30, 0x56,
10482 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010483 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0xfe, 0x0b, 0x58,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010484 0x03, 0x0a, 0x50, 0x01, 0x82, 0x0a, 0x3f, 0x01, 0x82, 0x03, 0xfc, 0x1c,
10485 0x10, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x19, 0x48, 0xfe, 0x00,
10486 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x63, 0x27,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010487 0x0c, 0x52, 0x18, 0x53, 0xbe, 0x56, 0xbf, 0x57, 0x03, 0xfe, 0x62, 0x08,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010488 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x74, 0x03, 0x01,
10489 0xfe, 0x14, 0x18, 0xfe, 0x42, 0x48, 0x5f, 0x60, 0x89, 0x01, 0x08, 0x1f,
10490 0xfe, 0xa2, 0x14, 0x30, 0x2e, 0xd8, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010491 0x30, 0x2e, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x05, 0xc6, 0x28, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010492 0xcc, 0x12, 0x49, 0x04, 0x1b, 0xfe, 0xc4, 0x13, 0x23, 0x62, 0x1b, 0xe2,
10493 0x4b, 0xc3, 0x64, 0xfe, 0xe8, 0x13, 0x3b, 0x13, 0x06, 0x17, 0xc3, 0x78,
10494 0xdb, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xa1, 0xff, 0x02, 0x83,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010495 0x55, 0x62, 0x1a, 0xa4, 0xbb, 0xfe, 0x30, 0x00, 0x8e, 0xe4, 0x17, 0x2c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010496 0x13, 0x06, 0xfe, 0x56, 0x10, 0x62, 0x0b, 0xe1, 0xbb, 0xfe, 0x64, 0x00,
10497 0x8e, 0xe4, 0x0a, 0xfe, 0x64, 0x00, 0x17, 0x93, 0x13, 0x06, 0xfe, 0x28,
10498 0x10, 0x62, 0x06, 0xfe, 0x60, 0x13, 0xbb, 0xfe, 0xc8, 0x00, 0x8e, 0xe4,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010499 0x0a, 0xfe, 0xc8, 0x00, 0x17, 0x4d, 0x13, 0x06, 0x83, 0xbb, 0xfe, 0x90,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010500 0x01, 0xba, 0xfe, 0x4e, 0x14, 0x89, 0xfe, 0x12, 0x10, 0xfe, 0x43, 0xf4,
10501 0x94, 0xfe, 0x56, 0xf0, 0xfe, 0x60, 0x14, 0xfe, 0x04, 0xf4, 0x6c, 0xfe,
10502 0x43, 0xf4, 0x93, 0xfe, 0xf3, 0x10, 0xf9, 0x01, 0xfe, 0x22, 0x13, 0x1c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010503 0x3d, 0xfe, 0x10, 0x13, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x69, 0xba,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010504 0xfe, 0x9c, 0x14, 0xb7, 0x69, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe,
10505 0x4d, 0xe4, 0x19, 0xba, 0xfe, 0x9c, 0x14, 0xb7, 0x19, 0x83, 0x60, 0x23,
10506 0xfe, 0x4d, 0xf4, 0x00, 0xdf, 0x89, 0x13, 0x06, 0xfe, 0xb4, 0x56, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010507 0xc3, 0x58, 0x03, 0x60, 0x13, 0x0b, 0x03, 0x15, 0x06, 0x01, 0x08, 0x26,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010508 0xe5, 0x15, 0x0b, 0x01, 0x08, 0x26, 0xe5, 0x15, 0x1a, 0x01, 0x08, 0x26,
10509 0xe5, 0x72, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x03, 0x15, 0x06, 0x01, 0x08,
10510 0x26, 0xa6, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x06, 0x01, 0x08,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010511 0x26, 0xa6, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x26, 0xa6, 0x72, 0xfe, 0x89,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010512 0x4a, 0x01, 0x08, 0x03, 0x60, 0x03, 0x1e, 0xcc, 0x07, 0x06, 0xfe, 0x44,
10513 0x13, 0xad, 0x12, 0xcc, 0xfe, 0x49, 0xf4, 0x00, 0x3b, 0x72, 0x9f, 0x5e,
10514 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01, 0x08, 0x2f, 0x07, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010515 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0x5a, 0x15, 0x23, 0x12, 0xcd,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010516 0x01, 0x43, 0x1e, 0xcd, 0x07, 0x06, 0x45, 0x09, 0x4a, 0x06, 0x35, 0x03,
10517 0x0a, 0x42, 0x01, 0x0e, 0xed, 0x88, 0x07, 0x10, 0xa4, 0x0a, 0x80, 0x01,
10518 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x80, 0x01, 0x0e, 0x88,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010519 0xfe, 0x80, 0xe7, 0x10, 0x07, 0x10, 0x84, 0xfe, 0x45, 0x58, 0x01, 0xe3,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010520 0x88, 0x03, 0x0a, 0x42, 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03,
10521 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x80, 0x80, 0xf2, 0xfe, 0x49, 0xe4, 0x10,
10522 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x0a, 0x51, 0x01, 0x82, 0x03, 0x17,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010523 0x10, 0x71, 0x66, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010524 0xfe, 0x24, 0x1c, 0xfe, 0x1d, 0xf7, 0x1d, 0x90, 0xfe, 0xf6, 0x15, 0x01,
10525 0xfe, 0xfc, 0x16, 0xe0, 0x91, 0x1d, 0x66, 0xfe, 0x2c, 0x01, 0xfe, 0x2f,
10526 0x19, 0x03, 0xae, 0x21, 0xfe, 0xe6, 0x15, 0xfe, 0xda, 0x10, 0x17, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010527 0x71, 0x05, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010528 0x05, 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0x91, 0x19, 0xfe, 0x3c, 0x90,
10529 0xfe, 0x30, 0xf4, 0x06, 0xfe, 0x3c, 0x50, 0x66, 0xfe, 0x38, 0x00, 0xfe,
10530 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x90, 0xfe, 0x40, 0x16, 0xfe, 0xb6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010531 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x18, 0x16, 0xfe, 0x9c, 0x10, 0x17,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010532 0x10, 0x71, 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe,
10533 0x1d, 0xf7, 0x38, 0x90, 0xfe, 0x62, 0x16, 0xfe, 0x94, 0x14, 0xfe, 0x10,
10534 0x13, 0x91, 0x38, 0x66, 0x1b, 0xfe, 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010535 0x03, 0xae, 0x21, 0xfe, 0x56, 0x16, 0xfe, 0x6c, 0x10, 0x17, 0x10, 0x71,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010536 0xfe, 0x30, 0xbc, 0xfe, 0xb2, 0xbc, 0x91, 0xc5, 0x66, 0x1b, 0xfe, 0x0f,
10537 0x79, 0xfe, 0x1c, 0xf7, 0xc5, 0x90, 0xfe, 0x9a, 0x16, 0xfe, 0x5c, 0x14,
10538 0x34, 0x03, 0xae, 0x21, 0xfe, 0x86, 0x16, 0xfe, 0x42, 0x10, 0xfe, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010539 0xf6, 0x10, 0x71, 0xfe, 0x18, 0xfe, 0x54, 0xfe, 0x19, 0xfe, 0x55, 0xfc,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010540 0xfe, 0x1d, 0xf7, 0x4f, 0x90, 0xfe, 0xc0, 0x16, 0xfe, 0x36, 0x14, 0xfe,
10541 0x1c, 0x13, 0x91, 0x4f, 0x47, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe,
10542 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11, 0xfe, 0xdd, 0x00, 0x63,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010543 0x27, 0x03, 0x63, 0x27, 0xfe, 0x12, 0x45, 0x21, 0xfe, 0xb0, 0x16, 0x14,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010544 0x06, 0x37, 0x95, 0xa9, 0x02, 0x29, 0xfe, 0x39, 0xf0, 0xfe, 0x04, 0x17,
10545 0x23, 0x03, 0xfe, 0x7e, 0x18, 0x1c, 0x1a, 0x5d, 0x13, 0x0d, 0x03, 0x71,
10546 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x78, 0x2c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010547 0x46, 0x2f, 0x07, 0x2d, 0xfe, 0x3c, 0x13, 0xfe, 0x82, 0x14, 0xfe, 0x42,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010548 0x13, 0x3c, 0x8a, 0x0a, 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x3e, 0x12, 0xf0,
10549 0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13,
10550 0x3d, 0x75, 0x07, 0x10, 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x01, 0x6f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010551 0xfe, 0x16, 0x10, 0x07, 0x7e, 0x85, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010552 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x24, 0x17, 0x17, 0x0b, 0x03, 0xfe, 0x9c,
10553 0xe7, 0x0b, 0x0f, 0xfe, 0x15, 0x00, 0x59, 0x76, 0x27, 0x01, 0xda, 0x17,
10554 0x06, 0x03, 0x3c, 0x8a, 0x09, 0x4a, 0x1d, 0x35, 0x11, 0x2d, 0x01, 0x6f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010555 0x17, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x79, 0xc7, 0x68,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010556 0xc8, 0xfe, 0x48, 0x55, 0x34, 0xfe, 0xc9, 0x55, 0x03, 0x1e, 0x98, 0x73,
10557 0x12, 0x98, 0x03, 0x0a, 0x99, 0x01, 0x0e, 0xf0, 0x0a, 0x40, 0x01, 0x0e,
10558 0xfe, 0x49, 0x44, 0x16, 0xfe, 0xf0, 0x17, 0x73, 0x75, 0x03, 0x0a, 0x42,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010559 0x01, 0x0e, 0x07, 0x10, 0x45, 0x0a, 0x51, 0x01, 0x9e, 0x0a, 0x40, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010560 0x0e, 0x73, 0x75, 0x03, 0xfe, 0x4e, 0xe4, 0x1a, 0x64, 0xfe, 0x24, 0x18,
10561 0x05, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0x5b, 0xfe, 0x4e, 0xe4, 0xc2,
10562 0x64, 0xfe, 0x36, 0x18, 0x05, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010563 0xdc, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x64, 0xfe, 0x48, 0x18, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010564 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x19, 0xfe, 0x08, 0x10, 0x05, 0xfe,
10565 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x2c, 0xfe, 0x4e, 0x45, 0xfe, 0x0c, 0x12,
10566 0xaf, 0xff, 0x04, 0x68, 0x54, 0xde, 0x1c, 0x69, 0x03, 0x07, 0x7a, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010567 0x5a, 0xf0, 0xfe, 0x74, 0x18, 0x24, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010568 0x07, 0x1b, 0xfe, 0x5a, 0xf0, 0xfe, 0x82, 0x18, 0x24, 0xc3, 0xfe, 0x26,
10569 0x10, 0x07, 0x1a, 0x5d, 0x24, 0x2c, 0xdc, 0x07, 0x0b, 0x5d, 0x24, 0x93,
10570 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x5d, 0x24, 0x4d, 0x9f, 0xad, 0x03, 0x14,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010571 0xfe, 0x09, 0x00, 0x01, 0x33, 0xfe, 0x04, 0xfe, 0x7d, 0x05, 0x7f, 0xf9,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010572 0x03, 0x25, 0xfe, 0xca, 0x18, 0xfe, 0x14, 0xf0, 0x08, 0x65, 0xfe, 0xc6,
10573 0x18, 0x03, 0xff, 0x1a, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070010574};
10575
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010576static unsigned short _adv_asc3550_size = sizeof(_adv_asc3550_buf); /* 0x13AD */
10577static ADV_DCNT _adv_asc3550_chksum = 0x04D52DDDUL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070010578
10579/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010580static unsigned char _adv_asc38C0800_buf[] = {
10581 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x16, 0x18, 0xe4,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010582 0x01, 0x00, 0x48, 0xe4, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0xce, 0x19,
10583 0x00, 0xfa, 0xff, 0xff, 0x1c, 0x0f, 0x00, 0xf6, 0x9e, 0xe7, 0xff, 0x00,
10584 0x82, 0xe7, 0x00, 0xea, 0x01, 0xfa, 0x01, 0xe6, 0x09, 0xe7, 0x55, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010585 0x01, 0xf6, 0x03, 0x00, 0x04, 0x00, 0x10, 0x00, 0x1e, 0xf0, 0x85, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010586 0x18, 0xf4, 0x08, 0x00, 0xbc, 0x00, 0x38, 0x54, 0x00, 0xec, 0xd5, 0xf0,
10587 0x82, 0x0d, 0x00, 0xe6, 0x86, 0xf0, 0xb1, 0xf0, 0x98, 0x57, 0x01, 0xfc,
10588 0xb4, 0x00, 0xd4, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x3c, 0x00, 0xbb, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010589 0x00, 0x10, 0xba, 0x19, 0x02, 0x80, 0x32, 0xf0, 0x7c, 0x0d, 0x02, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010590 0xba, 0x13, 0x18, 0x40, 0x00, 0x57, 0x01, 0xea, 0x02, 0xfc, 0x03, 0xfc,
10591 0x3e, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x74, 0x01, 0x76, 0x01, 0xb9, 0x54,
10592 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00, 0xc0, 0x00, 0x01, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010593 0x3e, 0x01, 0x7a, 0x01, 0xca, 0x08, 0xce, 0x10, 0x16, 0x11, 0x04, 0x12,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010594 0x08, 0x12, 0x02, 0x4a, 0xbb, 0x55, 0x3c, 0x56, 0x03, 0x58, 0x1b, 0x80,
10595 0x30, 0xe4, 0x4b, 0xe4, 0x5d, 0xf0, 0x02, 0xfa, 0x20, 0x00, 0x32, 0x00,
10596 0x40, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010597 0x70, 0x01, 0x72, 0x01, 0x78, 0x01, 0x7c, 0x01, 0x62, 0x0a, 0x86, 0x0d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010598 0x06, 0x13, 0x4c, 0x1c, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0,
10599 0x03, 0xf7, 0x0c, 0x00, 0x0f, 0x00, 0x47, 0x00, 0xbe, 0x00, 0x00, 0x01,
10600 0x20, 0x11, 0x5c, 0x16, 0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010601 0x00, 0x4c, 0x04, 0xea, 0x5c, 0xf0, 0xa7, 0xf0, 0x04, 0xf6, 0x03, 0xfa,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010602 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01,
10603 0x4e, 0x01, 0x4a, 0x0b, 0x42, 0x0c, 0x12, 0x0f, 0x0c, 0x10, 0x22, 0x11,
10604 0x0a, 0x12, 0x04, 0x13, 0x30, 0x1c, 0x02, 0x48, 0x00, 0x4e, 0x42, 0x54,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010605 0x44, 0x55, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010606 0x59, 0xf0, 0xb8, 0xf0, 0x4b, 0xf4, 0x06, 0xf7, 0x0e, 0xf7, 0x04, 0xfc,
10607 0x05, 0xfc, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00, 0xa4, 0x00,
10608 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xe2, 0x03,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010609 0x08, 0x0f, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, 0x0a, 0x13, 0x0c, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010610 0x12, 0x13, 0x24, 0x14, 0x34, 0x14, 0x04, 0x16, 0x08, 0x16, 0xa4, 0x17,
10611 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44, 0x91, 0x44,
10612 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x3a, 0x55, 0x83, 0x55,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010613 0xe5, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010614 0x0c, 0xf0, 0x04, 0xf8, 0x05, 0xf8, 0x07, 0x00, 0x0a, 0x00, 0x1c, 0x00,
10615 0x1e, 0x00, 0x9e, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00,
10616 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7e, 0x01, 0xc4, 0x01, 0xc6, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010617 0x80, 0x02, 0x5e, 0x03, 0xee, 0x04, 0x9a, 0x06, 0xf8, 0x07, 0x62, 0x08,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010618 0x68, 0x08, 0x69, 0x08, 0xd6, 0x08, 0xe9, 0x09, 0xfa, 0x0b, 0x2e, 0x0f,
10619 0x12, 0x10, 0x1a, 0x10, 0xed, 0x10, 0xf1, 0x10, 0x2a, 0x11, 0x06, 0x12,
10620 0x0c, 0x12, 0x3e, 0x12, 0x10, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x46, 0x14,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010621 0x76, 0x14, 0x82, 0x14, 0x36, 0x15, 0xca, 0x15, 0x6b, 0x18, 0xbe, 0x18,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010622 0xca, 0x18, 0xe6, 0x19, 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40,
10623 0x0e, 0x47, 0xfe, 0x9c, 0xf0, 0x2b, 0x02, 0xfe, 0xac, 0x0d, 0xff, 0x10,
10624 0x00, 0x00, 0xd7, 0xfe, 0xe8, 0x19, 0x00, 0xd6, 0xfe, 0x84, 0x01, 0xff,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010625 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010626 0x00, 0xfe, 0x57, 0x24, 0x00, 0xfe, 0x4c, 0x00, 0x5b, 0xff, 0x04, 0x00,
10627 0x00, 0x11, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x08,
10628 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x11,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010629 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010630 0xfe, 0x04, 0xf7, 0xd6, 0x2c, 0x99, 0x0a, 0x01, 0xfe, 0xc2, 0x0f, 0xfe,
10631 0x04, 0xf7, 0xd6, 0x99, 0x0a, 0x42, 0x2c, 0xfe, 0x3d, 0xf0, 0xfe, 0x06,
10632 0x02, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x91, 0xf0, 0xfe, 0xf4, 0x01, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010633 0x90, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, 0x8f, 0xf0, 0xa7, 0x03, 0x5d, 0x4d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010634 0x02, 0xfe, 0xc8, 0x0d, 0x01, 0xfe, 0x38, 0x0e, 0xfe, 0xdd, 0x12, 0xfe,
10635 0xfc, 0x10, 0xfe, 0x28, 0x1c, 0x03, 0xfe, 0xa6, 0x00, 0xfe, 0xd3, 0x12,
10636 0x41, 0x14, 0xfe, 0xa6, 0x00, 0xc2, 0xfe, 0x48, 0xf0, 0xfe, 0x8a, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010637 0xfe, 0x49, 0xf0, 0xfe, 0xa4, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc2, 0x02,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010638 0xfe, 0x46, 0xf0, 0xfe, 0x54, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x5a, 0x02,
10639 0xfe, 0x43, 0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x4c, 0x02,
10640 0xfe, 0x45, 0xf0, 0xfe, 0x50, 0x02, 0x18, 0x0a, 0xaa, 0x18, 0x06, 0x14,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010641 0xa1, 0x02, 0x2b, 0xfe, 0x00, 0x1c, 0xe7, 0xfe, 0x02, 0x1c, 0xe6, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010642 0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0xfe, 0x18, 0x18, 0xfe, 0xe7, 0x10,
10643 0xfe, 0x06, 0xfc, 0xce, 0x09, 0x70, 0x01, 0xa8, 0x02, 0x2b, 0x15, 0x59,
10644 0x39, 0xa2, 0x01, 0xfe, 0x58, 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xbd,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010645 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010646 0x58, 0x1c, 0x18, 0x06, 0x14, 0xa1, 0x2c, 0x1c, 0x2b, 0xfe, 0x3d, 0xf0,
10647 0xfe, 0x06, 0x02, 0x23, 0xfe, 0x98, 0x02, 0xfe, 0x5a, 0x1c, 0xf8, 0xfe,
10648 0x14, 0x1c, 0x15, 0xfe, 0x30, 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010649 0x18, 0x06, 0x14, 0xa1, 0x02, 0xd7, 0x22, 0x20, 0x07, 0x11, 0x35, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010650 0x69, 0x10, 0x18, 0x06, 0x14, 0xa1, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0x43,
10651 0x13, 0x20, 0xfe, 0x05, 0xf6, 0xce, 0x01, 0xfe, 0x4a, 0x17, 0x08, 0x54,
10652 0x58, 0x37, 0x12, 0x2f, 0x42, 0x92, 0x01, 0xfe, 0x82, 0x16, 0x02, 0x2b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010653 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x01, 0x73, 0xfe, 0x18, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010654 0xfe, 0x41, 0x58, 0x09, 0xa4, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x6b, 0xfe,
10655 0x10, 0x03, 0x01, 0xfe, 0x82, 0x16, 0x02, 0x2b, 0x2c, 0x4f, 0xfe, 0x02,
10656 0xe8, 0x2a, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010657 0x27, 0xf0, 0xfe, 0xe0, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xa7,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010658 0xfe, 0x40, 0x1c, 0x1c, 0xd9, 0xfe, 0x26, 0xf0, 0xfe, 0x5a, 0x03, 0xfe,
10659 0xa0, 0xf0, 0xfe, 0x48, 0x03, 0xfe, 0x11, 0xf0, 0xa7, 0xfe, 0xef, 0x10,
10660 0xfe, 0x9f, 0xf0, 0xfe, 0x68, 0x03, 0xf9, 0x10, 0xfe, 0x11, 0x00, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010661 0x65, 0x2c, 0xfe, 0x48, 0x1c, 0xf9, 0x08, 0x05, 0x1b, 0xfe, 0x18, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010662 0x21, 0x22, 0xa3, 0xb7, 0x13, 0xa3, 0x09, 0x46, 0x01, 0x0e, 0xb7, 0x78,
10663 0x01, 0xfe, 0xb4, 0x16, 0x12, 0xd1, 0x1c, 0xd9, 0xfe, 0x01, 0xf0, 0xd9,
10664 0xfe, 0x82, 0xf0, 0xfe, 0x96, 0x03, 0xfa, 0x12, 0xfe, 0xe4, 0x00, 0x27,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010665 0xfe, 0xa8, 0x03, 0x1c, 0x34, 0x1d, 0xfe, 0xb8, 0x03, 0x01, 0x4b, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010666 0x06, 0xf0, 0xfe, 0xc8, 0x03, 0x95, 0x86, 0xfe, 0x0a, 0xf0, 0xfe, 0x8a,
10667 0x06, 0x02, 0x24, 0x03, 0x70, 0x28, 0x17, 0xfe, 0xfa, 0x04, 0x15, 0x6d,
10668 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, 0xd8, 0xf9, 0x2c, 0x99, 0x19,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010669 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010670 0x74, 0x01, 0xaf, 0x8c, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x17, 0xda,
10671 0x09, 0xd1, 0x01, 0x0e, 0x8d, 0x51, 0x64, 0x79, 0x2a, 0x03, 0x70, 0x28,
10672 0xfe, 0x10, 0x12, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010673 0xd8, 0xc7, 0x81, 0xc8, 0x83, 0x1c, 0x24, 0x27, 0xfe, 0x40, 0x04, 0x1d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010674 0xfe, 0x3c, 0x04, 0x3b, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e,
10675 0x12, 0x2d, 0xff, 0x02, 0x00, 0x10, 0x01, 0x0b, 0x1d, 0xfe, 0xe4, 0x04,
10676 0x2d, 0x01, 0x0b, 0x1d, 0x24, 0x33, 0x31, 0xde, 0xfe, 0x4c, 0x44, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010677 0x4c, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010678 0xda, 0x4f, 0x79, 0x2a, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x62,
10679 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x2a, 0x13, 0x32, 0x07, 0x82, 0xfe, 0x52,
10680 0x13, 0xfe, 0x20, 0x10, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b, 0xda, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010681 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x40, 0x13, 0x08, 0x05, 0x1b, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010682 0x08, 0x13, 0x32, 0x07, 0x82, 0xfe, 0x30, 0x13, 0x08, 0x05, 0x1b, 0xfe,
10683 0x1c, 0x12, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe, 0x0d, 0x00,
10684 0x01, 0x36, 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x2d, 0x12, 0xfe, 0xe6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010685 0x00, 0xfe, 0x1c, 0x90, 0xfe, 0x40, 0x5c, 0x04, 0x15, 0x9d, 0x01, 0x36,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010686 0x02, 0x2b, 0xfe, 0x42, 0x5b, 0x99, 0x19, 0xfe, 0x46, 0x59, 0xfe, 0xbf,
10687 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x87, 0x80, 0xfe, 0x31, 0xe4, 0x5b, 0x08,
10688 0x05, 0x0a, 0xfe, 0x84, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x19, 0xfe, 0x7c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010689 0x12, 0x53, 0x05, 0x06, 0xfe, 0x6c, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x28,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010690 0x17, 0xfe, 0x90, 0x05, 0xfe, 0x31, 0xe4, 0x5a, 0x53, 0x05, 0x0a, 0xfe,
10691 0x56, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x28, 0xfe, 0x4e, 0x12, 0x67, 0xff,
10692 0x02, 0x00, 0x10, 0x27, 0xfe, 0x48, 0x05, 0x1c, 0x34, 0xfe, 0x89, 0x48,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010693 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x56, 0x05, 0x26, 0xfe, 0xa8, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010694 0x12, 0xfe, 0xe3, 0x00, 0x21, 0x53, 0xfe, 0x4a, 0xf0, 0xfe, 0x76, 0x05,
10695 0xfe, 0x49, 0xf0, 0xfe, 0x70, 0x05, 0x88, 0x25, 0xfe, 0x21, 0x00, 0xab,
10696 0x25, 0xfe, 0x22, 0x00, 0xaa, 0x25, 0x58, 0xfe, 0x09, 0x48, 0xff, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010697 0x00, 0x10, 0x27, 0xfe, 0x86, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0xfe, 0xe2,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010698 0x08, 0x53, 0x05, 0xcb, 0x4d, 0x01, 0xb0, 0x25, 0x06, 0x13, 0xd3, 0x39,
10699 0xfe, 0x27, 0x01, 0x08, 0x05, 0x1b, 0xfe, 0x22, 0x12, 0x41, 0x01, 0xb2,
10700 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010701 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0xeb,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010702 0x03, 0x5c, 0x28, 0xfe, 0x36, 0x13, 0x41, 0x01, 0xb2, 0x26, 0xfe, 0x18,
10703 0x06, 0x09, 0x06, 0x53, 0x05, 0x1f, 0xfe, 0x02, 0x12, 0x50, 0x01, 0xfe,
10704 0x9e, 0x15, 0x1d, 0xfe, 0x0e, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010705 0xe5, 0x00, 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x03, 0xcd, 0x28, 0xfe, 0x62,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010706 0x12, 0x03, 0x45, 0x28, 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x0c, 0x19, 0x01,
10707 0xfe, 0x76, 0x19, 0xfe, 0x43, 0x48, 0xc4, 0xcc, 0x0f, 0x71, 0xff, 0x02,
10708 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0x8b, 0xc4, 0x6e, 0x41, 0x01, 0xb2,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010709 0x26, 0xfe, 0x82, 0x06, 0x53, 0x05, 0x1a, 0xe9, 0x91, 0x09, 0x59, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010710 0xfe, 0xcc, 0x15, 0x1d, 0xfe, 0x78, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12,
10711 0xfe, 0xe5, 0x00, 0x03, 0x45, 0xc1, 0x0c, 0x45, 0x18, 0x06, 0x01, 0xb2,
10712 0xfa, 0x76, 0x74, 0x01, 0xaf, 0x8c, 0x12, 0xfe, 0xe2, 0x00, 0x27, 0xdb,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010713 0x1c, 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0xb6, 0x06, 0x94, 0xfe, 0x6c, 0x07,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010714 0xfe, 0x06, 0xf0, 0xfe, 0x74, 0x07, 0x95, 0x86, 0x02, 0x24, 0x08, 0x05,
10715 0x0a, 0xfe, 0x2e, 0x12, 0x16, 0x19, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b,
10716 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0xfe, 0x99, 0xa4, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010717 0x0b, 0x16, 0x00, 0x02, 0xfe, 0x42, 0x08, 0x68, 0x05, 0x1a, 0xfe, 0x38,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010718 0x12, 0x08, 0x05, 0x1a, 0xfe, 0x30, 0x13, 0x16, 0xfe, 0x1b, 0x00, 0x01,
10719 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01,
10720 0x0b, 0x16, 0x06, 0x01, 0x0b, 0x16, 0x00, 0x02, 0xe2, 0x6c, 0x58, 0xbe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010721 0x50, 0xfe, 0x9a, 0x81, 0x55, 0x1b, 0x7a, 0xfe, 0x42, 0x07, 0x09, 0x1b,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010722 0xfe, 0x09, 0x6f, 0xba, 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x69, 0x6d,
10723 0x8b, 0x6c, 0x7f, 0x27, 0xfe, 0x54, 0x07, 0x1c, 0x34, 0xfe, 0x0a, 0xf0,
10724 0xfe, 0x42, 0x07, 0x95, 0x86, 0x94, 0xfe, 0x6c, 0x07, 0x02, 0x24, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010725 0x4b, 0x02, 0xdb, 0x16, 0x1f, 0x02, 0xdb, 0xfe, 0x9c, 0xf7, 0xdc, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010726 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x56, 0xfe, 0xda, 0x07, 0x0c, 0x60, 0x14,
10727 0x61, 0x08, 0x54, 0x5a, 0x37, 0x22, 0x20, 0x07, 0x11, 0xfe, 0x0e, 0x12,
10728 0x8d, 0xfe, 0x80, 0x80, 0x39, 0x20, 0x6a, 0x2a, 0xfe, 0x06, 0x10, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010729 0x83, 0xe7, 0xfe, 0x48, 0x00, 0xab, 0xfe, 0x03, 0x40, 0x08, 0x54, 0x5b,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010730 0x37, 0x01, 0xb3, 0xb8, 0xfe, 0x1f, 0x40, 0x13, 0x62, 0x01, 0xef, 0xfe,
10731 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0x88,
10732 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e, 0x14, 0x5f, 0xfe, 0x0c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010733 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x0c, 0x3d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010734 0x14, 0x3e, 0xfe, 0x4a, 0x10, 0x08, 0x05, 0x5a, 0xfe, 0x2a, 0x12, 0xfe,
10735 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x60, 0x14, 0x61, 0x08, 0x05, 0x5b,
10736 0x8b, 0x01, 0xb3, 0xfe, 0x1f, 0x80, 0x13, 0x62, 0xfe, 0x44, 0x90, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010737 0xc6, 0x90, 0x0c, 0x3f, 0x14, 0x40, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010738 0x0c, 0x5e, 0x14, 0x5f, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x3d,
10739 0x14, 0x3e, 0x0c, 0x2e, 0x14, 0x3c, 0x21, 0x0c, 0x49, 0x0c, 0x63, 0x08,
10740 0x54, 0x1f, 0x37, 0x2c, 0x0f, 0xfe, 0x4e, 0x11, 0x27, 0xdd, 0xfe, 0x9e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010741 0xf0, 0xfe, 0x76, 0x08, 0xbc, 0x17, 0x34, 0x2c, 0x77, 0xe6, 0xc5, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010742 0x9a, 0x08, 0xc6, 0xfe, 0xb8, 0x08, 0x94, 0xfe, 0x8e, 0x08, 0xfe, 0x06,
10743 0xf0, 0xfe, 0x94, 0x08, 0x95, 0x86, 0x02, 0x24, 0x01, 0x4b, 0xfe, 0xc9,
10744 0x10, 0x16, 0x1f, 0xfe, 0xc9, 0x10, 0x68, 0x05, 0x06, 0xfe, 0x10, 0x12,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010745 0x68, 0x05, 0x0a, 0x4e, 0x08, 0x05, 0x0a, 0xfe, 0x90, 0x12, 0xfe, 0x2e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010746 0x1c, 0x02, 0xfe, 0x18, 0x0b, 0x68, 0x05, 0x06, 0x4e, 0x68, 0x05, 0x0a,
10747 0xfe, 0x7a, 0x12, 0xfe, 0x2c, 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0xd2, 0x09,
10748 0xfe, 0xac, 0xf0, 0xfe, 0x00, 0x09, 0x02, 0xfe, 0xde, 0x09, 0xfe, 0xb7,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010749 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0x02, 0xf6, 0x1a, 0x50, 0xfe, 0x70, 0x18,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010750 0xfe, 0xf1, 0x18, 0xfe, 0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58,
10751 0xfe, 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x1c, 0x85, 0xfe,
10752 0x8c, 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0xac, 0xf0, 0xfe, 0xf0, 0x08, 0xb5,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010753 0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x0c, 0x09, 0x02, 0xfe, 0x18,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010754 0x0b, 0xb6, 0xfe, 0xbf, 0x10, 0xfe, 0x2b, 0xf0, 0x85, 0xf4, 0x1e, 0xfe,
10755 0x00, 0xfe, 0xfe, 0x1c, 0x12, 0xc2, 0xfe, 0xd2, 0xf0, 0x85, 0xfe, 0x76,
10756 0x18, 0x1e, 0x19, 0x17, 0x85, 0x03, 0xd2, 0x1e, 0x06, 0x17, 0x85, 0xc5,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010757 0x4a, 0xc6, 0x4a, 0xb5, 0xb6, 0xfe, 0x89, 0x10, 0x74, 0x67, 0x2d, 0x15,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010758 0x9d, 0x01, 0x36, 0x10, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x65, 0x10,
10759 0x80, 0x02, 0x65, 0xfe, 0x98, 0x80, 0xfe, 0x19, 0xe4, 0x0a, 0xfe, 0x1a,
10760 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18, 0xfe, 0x44, 0x54, 0xbe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010761 0xfe, 0x19, 0x81, 0xfe, 0x74, 0x18, 0x8f, 0x90, 0x17, 0xfe, 0xce, 0x08,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010762 0x02, 0x4a, 0x08, 0x05, 0x5a, 0xec, 0x03, 0x2e, 0x29, 0x3c, 0x0c, 0x3f,
10763 0x14, 0x40, 0x9b, 0x2e, 0x9c, 0x3c, 0xfe, 0x6c, 0x18, 0xfe, 0xed, 0x18,
10764 0xfe, 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x3a, 0x3f, 0x3b, 0x40, 0x03, 0x49,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010765 0x29, 0x63, 0x8f, 0xfe, 0xe3, 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010766 0x8f, 0xfe, 0xe3, 0x54, 0x90, 0xc0, 0x56, 0xfe, 0xce, 0x08, 0x02, 0x4a,
10767 0xfe, 0x37, 0xf0, 0xfe, 0xda, 0x09, 0xfe, 0x8b, 0xf0, 0xfe, 0x60, 0x09,
10768 0x02, 0x4a, 0x08, 0x05, 0x0a, 0x23, 0xfe, 0xfa, 0x0a, 0x3a, 0x49, 0x3b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010769 0x63, 0x56, 0xfe, 0x3e, 0x0a, 0x0f, 0xfe, 0xc0, 0x07, 0x41, 0x98, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010770 0xad, 0xfe, 0x01, 0x59, 0xfe, 0x52, 0xf0, 0xfe, 0x0c, 0x0a, 0x8f, 0x7a,
10771 0xfe, 0x24, 0x0a, 0x3a, 0x49, 0x8f, 0xfe, 0xe3, 0x54, 0x57, 0x49, 0x7d,
10772 0x63, 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02, 0x4a, 0x3a, 0x49, 0x3b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010773 0x63, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xbe, 0x57, 0x49, 0x57, 0x63,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010774 0x02, 0x4a, 0x08, 0x05, 0x5a, 0xfe, 0x82, 0x12, 0x08, 0x05, 0x1f, 0xfe,
10775 0x66, 0x13, 0x22, 0x62, 0xb7, 0xfe, 0x03, 0xa1, 0xfe, 0x83, 0x80, 0xfe,
10776 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x6a,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010777 0x2a, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x56, 0xe0, 0x03, 0x60, 0x29,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010778 0x61, 0x0c, 0x7f, 0x14, 0x80, 0x57, 0x60, 0x7d, 0x61, 0x01, 0xb3, 0xb8,
10779 0x6a, 0x2a, 0x13, 0x62, 0x9b, 0x2e, 0x9c, 0x3c, 0x3a, 0x3f, 0x3b, 0x40,
10780 0x90, 0xc0, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0x01, 0xef,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010781 0xfe, 0x36, 0x10, 0x21, 0x0c, 0x7f, 0x0c, 0x80, 0x3a, 0x3f, 0x3b, 0x40,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010782 0xe4, 0x08, 0x05, 0x1f, 0x17, 0xe0, 0x3a, 0x3d, 0x3b, 0x3e, 0x08, 0x05,
10783 0xfe, 0xf7, 0x00, 0x37, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x10, 0x58, 0xfe,
10784 0x91, 0x58, 0x57, 0x49, 0x7d, 0x63, 0x02, 0xfe, 0xf4, 0x09, 0x08, 0x05,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010785 0x1f, 0x17, 0xe0, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0xbe, 0xfe, 0x19,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010786 0x81, 0x50, 0xfe, 0x10, 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd3, 0x10, 0x32,
10787 0x07, 0xa6, 0x17, 0xfe, 0x08, 0x09, 0x12, 0xa6, 0x08, 0x05, 0x0a, 0xfe,
10788 0x14, 0x13, 0x03, 0x3d, 0x29, 0x3e, 0x56, 0xfe, 0x08, 0x09, 0xfe, 0x0c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010789 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x4a, 0x21, 0x41, 0xfe, 0x19, 0x80, 0xe7,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010790 0x08, 0x05, 0x0a, 0xfe, 0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41,
10791 0xf4, 0xc2, 0xfe, 0xd1, 0xf0, 0xe2, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe,
10792 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0x57, 0x3d, 0xfe, 0xed,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010793 0x19, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xf4, 0x1e, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010794 0x00, 0xff, 0x35, 0xfe, 0x74, 0x10, 0xc2, 0xfe, 0xd2, 0xf0, 0xfe, 0xa6,
10795 0x0b, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x8a, 0x03, 0xd2, 0x1e, 0x06, 0xfe,
10796 0x08, 0x13, 0x10, 0xfe, 0x16, 0x00, 0x02, 0x65, 0xfe, 0xd1, 0xf0, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010797 0xb8, 0x0b, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, 0x17, 0x00, 0xfe, 0x42,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010798 0x10, 0xfe, 0xce, 0xf0, 0xfe, 0xbe, 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd,
10799 0xf0, 0xfe, 0xca, 0x0b, 0x10, 0xfe, 0x22, 0x00, 0x02, 0x65, 0xfe, 0xcb,
10800 0xf0, 0xfe, 0xd6, 0x0b, 0x10, 0xfe, 0x24, 0x00, 0x02, 0x65, 0xfe, 0xd0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010801 0xf0, 0xfe, 0xe0, 0x0b, 0x10, 0x9e, 0xe5, 0xfe, 0xcf, 0xf0, 0xfe, 0xea,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010802 0x0b, 0x10, 0x58, 0xfe, 0x10, 0x10, 0xfe, 0xcc, 0xf0, 0xe2, 0x68, 0x05,
10803 0x1f, 0x4d, 0x10, 0xfe, 0x12, 0x00, 0x2c, 0x0f, 0xfe, 0x4e, 0x11, 0x27,
10804 0xfe, 0x00, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x14, 0x0c, 0xbc, 0x17, 0x34,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010805 0x2c, 0x77, 0xe6, 0xc5, 0x24, 0xc6, 0x24, 0x2c, 0xfa, 0x27, 0xfe, 0x20,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010806 0x0c, 0x1c, 0x34, 0x94, 0xfe, 0x3c, 0x0c, 0x95, 0x86, 0xc5, 0xdc, 0xc6,
10807 0xdc, 0x02, 0x24, 0x01, 0x4b, 0xfe, 0xdb, 0x10, 0x12, 0xfe, 0xe8, 0x00,
10808 0xb5, 0xb6, 0x74, 0xc7, 0x81, 0xc8, 0x83, 0xfe, 0x89, 0xf0, 0x24, 0x33,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010809 0x31, 0xe1, 0xc7, 0x81, 0xc8, 0x83, 0x27, 0xfe, 0x66, 0x0c, 0x1d, 0x24,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010810 0x33, 0x31, 0xdf, 0xbc, 0x4e, 0x10, 0xfe, 0x42, 0x00, 0x02, 0x65, 0x7c,
10811 0x06, 0xfe, 0x81, 0x49, 0x17, 0xfe, 0x2c, 0x0d, 0x08, 0x05, 0x0a, 0xfe,
10812 0x44, 0x13, 0x10, 0x00, 0x55, 0x0a, 0xfe, 0x54, 0x12, 0x55, 0xfe, 0x28,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010813 0x00, 0x23, 0xfe, 0x9a, 0x0d, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010814 0x44, 0xfe, 0x28, 0x00, 0xfe, 0xe2, 0x10, 0x01, 0xf5, 0x01, 0xf6, 0x09,
10815 0xa4, 0x01, 0xfe, 0x26, 0x0f, 0x64, 0x12, 0x2f, 0x01, 0x73, 0x02, 0x2b,
10816 0x10, 0xfe, 0x44, 0x00, 0x55, 0x0a, 0xe9, 0x44, 0x0a, 0xfe, 0xb4, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010817 0x01, 0xb0, 0x44, 0x0a, 0xfe, 0xaa, 0x10, 0x01, 0xb0, 0xfe, 0x19, 0x82,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010818 0xfe, 0x34, 0x46, 0xac, 0x44, 0x0a, 0x10, 0xfe, 0x43, 0x00, 0xfe, 0x96,
10819 0x10, 0x08, 0x54, 0x0a, 0x37, 0x01, 0xf5, 0x01, 0xf6, 0x64, 0x12, 0x2f,
10820 0x01, 0x73, 0x99, 0x0a, 0x64, 0x42, 0x92, 0x02, 0xfe, 0x2e, 0x03, 0x08,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010821 0x05, 0x0a, 0x8a, 0x44, 0x0a, 0x10, 0x00, 0xfe, 0x5c, 0x10, 0x68, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010822 0x1a, 0xfe, 0x58, 0x12, 0x08, 0x05, 0x1a, 0xfe, 0x50, 0x13, 0xfe, 0x1c,
10823 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x50, 0x0d, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d,
10824 0xf0, 0xfe, 0x56, 0x0d, 0x08, 0x54, 0x1a, 0x37, 0xfe, 0xa9, 0x10, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010825 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0a, 0x50, 0xfe, 0x2e, 0x10, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010826 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x10, 0x6f, 0xab, 0x10, 0xfe, 0x41,
10827 0x00, 0xaa, 0x10, 0xfe, 0x24, 0x00, 0x8c, 0xb5, 0xb6, 0x74, 0x03, 0x70,
10828 0x28, 0x23, 0xd8, 0x50, 0xfe, 0x04, 0xe6, 0x1a, 0xfe, 0x9d, 0x41, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010829 0x1c, 0x42, 0x64, 0x01, 0xe3, 0x02, 0x2b, 0xf8, 0x15, 0x0a, 0x39, 0xa0,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010830 0xb4, 0x15, 0xfe, 0x31, 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, 0x02,
10831 0xd7, 0x42, 0xfe, 0x06, 0xec, 0xd0, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45,
10832 0x35, 0x42, 0xfe, 0x06, 0xea, 0xd0, 0xfe, 0x47, 0x4b, 0x91, 0xfe, 0x75,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010833 0x57, 0x03, 0x5d, 0xfe, 0x98, 0x56, 0xfe, 0x38, 0x12, 0x09, 0x48, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010834 0x0e, 0xfe, 0x44, 0x48, 0x4f, 0x08, 0x05, 0x1b, 0xfe, 0x1a, 0x13, 0x09,
10835 0x46, 0x01, 0x0e, 0x41, 0xfe, 0x41, 0x58, 0x09, 0xa4, 0x01, 0x0e, 0xfe,
10836 0x49, 0x54, 0x96, 0xfe, 0x1e, 0x0e, 0x02, 0xfe, 0x2e, 0x03, 0x09, 0x5d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010837 0xfe, 0xee, 0x14, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010838 0xce, 0x47, 0xfe, 0xad, 0x13, 0x02, 0x2b, 0x22, 0x20, 0x07, 0x11, 0xfe,
10839 0x9e, 0x12, 0x21, 0x13, 0x59, 0x13, 0x9f, 0x13, 0xd5, 0x22, 0x2f, 0x41,
10840 0x39, 0x2f, 0xbc, 0xad, 0xfe, 0xbc, 0xf0, 0xfe, 0xe0, 0x0e, 0x0f, 0x06,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010841 0x13, 0x59, 0x01, 0xfe, 0xda, 0x16, 0x03, 0xfe, 0x38, 0x01, 0x29, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010842 0x3a, 0x01, 0x56, 0xfe, 0xe4, 0x0e, 0xfe, 0x02, 0xec, 0xd5, 0x69, 0x00,
10843 0x66, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01,
10844 0x01, 0xfe, 0x4a, 0x17, 0xfe, 0x08, 0x90, 0xfe, 0x48, 0xf4, 0x0d, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010845 0x18, 0x13, 0xba, 0xfe, 0x02, 0xea, 0xd5, 0x69, 0x7e, 0xfe, 0xc5, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010846 0x15, 0x1a, 0x39, 0xa0, 0xb4, 0xfe, 0x2e, 0x10, 0x03, 0xfe, 0x38, 0x01,
10847 0x1e, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x03, 0xfe, 0x3a, 0x01,
10848 0x0c, 0xfe, 0x62, 0x01, 0x43, 0x13, 0x20, 0x25, 0x06, 0x13, 0x2f, 0x12,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010849 0x2f, 0x92, 0x0f, 0x06, 0x04, 0x21, 0x04, 0x22, 0x59, 0xfe, 0xf7, 0x12,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010850 0x22, 0x9f, 0xb7, 0x13, 0x9f, 0x07, 0x7e, 0xfe, 0x71, 0x13, 0xfe, 0x24,
10851 0x1c, 0x15, 0x19, 0x39, 0xa0, 0xb4, 0xfe, 0xd9, 0x10, 0xc3, 0xfe, 0x03,
10852 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xc3, 0xfe, 0x03, 0xdc,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010853 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x21,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010854 0xfe, 0x00, 0xcc, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x78, 0x04, 0x08, 0x05,
10855 0x58, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13,
10856 0xfe, 0x1e, 0x80, 0xed, 0xfe, 0x1d, 0x80, 0xae, 0xfe, 0x0c, 0x90, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010857 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xac, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010858 0x0a, 0xfe, 0x3c, 0x50, 0xaa, 0x01, 0xfe, 0x7a, 0x17, 0x32, 0x07, 0x2f,
10859 0xad, 0x01, 0xfe, 0xb4, 0x16, 0x08, 0x05, 0x1b, 0x4e, 0x01, 0xf5, 0x01,
10860 0xf6, 0x12, 0xfe, 0xe9, 0x00, 0x08, 0x05, 0x58, 0xfe, 0x2c, 0x13, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010861 0xfe, 0x0c, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010862 0x0c, 0xfe, 0x64, 0x01, 0x14, 0xfe, 0x66, 0x01, 0x08, 0x05, 0x5b, 0xfe,
10863 0x12, 0x12, 0xfe, 0x03, 0x80, 0x8d, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80,
10864 0x40, 0x13, 0x20, 0x6a, 0x2a, 0x12, 0xcf, 0x64, 0x22, 0x20, 0xfb, 0x79,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010865 0x20, 0x04, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010866 0x03, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe,
10867 0x08, 0x58, 0x03, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
10868 0x25, 0x6e, 0x13, 0xd0, 0x21, 0x0c, 0x5c, 0x0c, 0x45, 0x0f, 0x46, 0x52,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010869 0x50, 0x18, 0x1b, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xfe, 0xfc,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010870 0x0f, 0x44, 0x11, 0x0f, 0x48, 0x52, 0x18, 0x58, 0xfe, 0x90, 0x4d, 0xfe,
10871 0x91, 0x54, 0x23, 0xe4, 0x25, 0x11, 0x13, 0x20, 0x7c, 0x6f, 0x4f, 0x22,
10872 0x20, 0xfb, 0x79, 0x20, 0x12, 0xcf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010873 0xfe, 0x26, 0x10, 0xf8, 0x74, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010874 0x18, 0x1c, 0x04, 0x42, 0xfe, 0x0c, 0x14, 0xfc, 0xfe, 0x07, 0xe6, 0x1b,
10875 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x04, 0x01, 0xb0, 0x7c, 0x6f, 0x4f,
10876 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0x32, 0x07, 0x2f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010877 0xfe, 0x34, 0x13, 0x09, 0x48, 0x01, 0x0e, 0xbb, 0xfe, 0x36, 0x12, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010878 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe,
10879 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, 0x84, 0x01, 0x0e, 0xfe,
10880 0x80, 0x5c, 0x01, 0x73, 0xfe, 0x0e, 0x10, 0x07, 0x82, 0x4e, 0xfe, 0x14,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010881 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x60, 0x10, 0x04, 0xfe, 0x44, 0x58, 0x8d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010882 0xfe, 0x01, 0xec, 0xa2, 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe,
10883 0x9c, 0xe7, 0x1a, 0x79, 0x2a, 0x01, 0xe3, 0xfe, 0xdd, 0x10, 0x2c, 0xc7,
10884 0x81, 0xc8, 0x83, 0x33, 0x31, 0xde, 0x07, 0x1a, 0xfe, 0x48, 0x12, 0x07,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010885 0x0a, 0xfe, 0x56, 0x12, 0x07, 0x19, 0xfe, 0x30, 0x12, 0x07, 0xc9, 0x17,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010886 0xfe, 0x32, 0x12, 0x07, 0xfe, 0x23, 0x00, 0x17, 0xeb, 0x07, 0x06, 0x17,
10887 0xfe, 0x9c, 0x12, 0x07, 0x1f, 0xfe, 0x12, 0x12, 0x07, 0x00, 0x17, 0x24,
10888 0x15, 0xc9, 0x01, 0x36, 0xa9, 0x2d, 0x01, 0x0b, 0x94, 0x4b, 0x04, 0x2d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010889 0xdd, 0x09, 0xd1, 0x01, 0xfe, 0x26, 0x0f, 0x12, 0x82, 0x02, 0x2b, 0x2d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010890 0x32, 0x07, 0xa6, 0xfe, 0xd9, 0x13, 0x3a, 0x3d, 0x3b, 0x3e, 0x56, 0xfe,
10891 0xf0, 0x11, 0x08, 0x05, 0x5a, 0xfe, 0x72, 0x12, 0x9b, 0x2e, 0x9c, 0x3c,
10892 0x90, 0xc0, 0x96, 0xfe, 0xba, 0x11, 0x22, 0x62, 0xfe, 0x26, 0x13, 0x03,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010893 0x7f, 0x29, 0x80, 0x56, 0xfe, 0x76, 0x0d, 0x0c, 0x60, 0x14, 0x61, 0x21,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010894 0x0c, 0x7f, 0x0c, 0x80, 0x01, 0xb3, 0x25, 0x6e, 0x77, 0x13, 0x62, 0x01,
10895 0xef, 0x9b, 0x2e, 0x9c, 0x3c, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe,
10896 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0xfe, 0x91, 0x10, 0x03, 0x3f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010897 0x29, 0x40, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x3f, 0x14, 0x40,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010898 0x88, 0x9b, 0x2e, 0x9c, 0x3c, 0x90, 0xc0, 0x03, 0x5e, 0x29, 0x5f, 0xfe,
10899 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x0c, 0x5e, 0x14, 0x5f, 0x08, 0x05, 0x5a,
10900 0xfe, 0x1e, 0x12, 0x22, 0x62, 0xfe, 0x1f, 0x40, 0x03, 0x60, 0x29, 0x61,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010901 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x03, 0x3f, 0x29, 0x40, 0xfe, 0x44,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010902 0x50, 0xfe, 0xc6, 0x50, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x08, 0x50, 0xfe,
10903 0x8a, 0x50, 0x03, 0x3d, 0x29, 0x3e, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50,
10904 0x02, 0x89, 0x25, 0x06, 0x13, 0xd4, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010905 0x4c, 0x33, 0x31, 0xde, 0x07, 0x06, 0x23, 0x4c, 0x32, 0x07, 0xa6, 0x23,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010906 0x72, 0x01, 0xaf, 0x1e, 0x43, 0x17, 0x4c, 0x08, 0x05, 0x0a, 0xee, 0x3a,
10907 0x3d, 0x3b, 0x3e, 0xfe, 0x0a, 0x55, 0x35, 0xfe, 0x8b, 0x55, 0x57, 0x3d,
10908 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x02, 0x72, 0xfe, 0x19,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010909 0x81, 0xba, 0xfe, 0x19, 0x41, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1c, 0x34,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010910 0x1d, 0xe8, 0x33, 0x31, 0xe1, 0x55, 0x19, 0xfe, 0xa6, 0x12, 0x55, 0x0a,
10911 0x4d, 0x02, 0x4c, 0x01, 0x0b, 0x1c, 0x34, 0x1d, 0xe8, 0x33, 0x31, 0xdf,
10912 0x07, 0x19, 0x23, 0x4c, 0x01, 0x0b, 0x1d, 0xe8, 0x33, 0x31, 0xfe, 0xe8,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010913 0x09, 0xfe, 0xc2, 0x49, 0x51, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0x8a, 0x53,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010914 0x05, 0x1f, 0x35, 0xa9, 0xfe, 0xbb, 0x45, 0x55, 0x00, 0x4e, 0x44, 0x06,
10915 0x7c, 0x43, 0xfe, 0xda, 0x14, 0x01, 0xaf, 0x8c, 0xfe, 0x4b, 0x45, 0xee,
10916 0x32, 0x07, 0xa5, 0xed, 0x03, 0xcd, 0x28, 0x8a, 0x03, 0x45, 0x28, 0x35,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010917 0x67, 0x02, 0x72, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010918 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01,
10919 0xfe, 0x9e, 0x15, 0x02, 0x89, 0x01, 0x0b, 0x1c, 0x34, 0x1d, 0x4c, 0x33,
10920 0x31, 0xdf, 0x07, 0x06, 0x23, 0x4c, 0x01, 0xf1, 0xfe, 0x42, 0x58, 0xf1,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010921 0xfe, 0xa4, 0x14, 0x8c, 0xfe, 0x4a, 0xf4, 0x0a, 0x17, 0x4c, 0xfe, 0x4a,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010922 0xf4, 0x06, 0xea, 0x32, 0x07, 0xa5, 0x8b, 0x02, 0x72, 0x03, 0x45, 0xc1,
10923 0x0c, 0x45, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, 0xfe, 0xcc, 0x15,
10924 0x02, 0x89, 0x0f, 0x06, 0x27, 0xfe, 0xbe, 0x13, 0x26, 0xfe, 0xd4, 0x13,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010925 0x76, 0xfe, 0x89, 0x48, 0x01, 0x0b, 0x21, 0x76, 0x04, 0x7b, 0xfe, 0xd0,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010926 0x13, 0x1c, 0xfe, 0xd0, 0x13, 0x1d, 0xfe, 0xbe, 0x13, 0x67, 0x2d, 0x01,
10927 0x0b, 0xfe, 0xd5, 0x10, 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93,
10928 0x1e, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x04, 0x0f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010929 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0xfe, 0x30, 0x56,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010930 0xfe, 0x00, 0x5c, 0x04, 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93,
10931 0x04, 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0xfe, 0x0b, 0x58,
10932 0x04, 0x09, 0x5c, 0x01, 0x87, 0x09, 0x45, 0x01, 0x87, 0x04, 0xfe, 0x03,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010933 0xa1, 0x1e, 0x11, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x1f, 0x52,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010934 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c,
10935 0x6a, 0x2a, 0x0c, 0x5e, 0x14, 0x5f, 0x57, 0x3f, 0x7d, 0x40, 0x04, 0xdd,
10936 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x8d, 0x04, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010937 0xfe, 0x0c, 0x19, 0xfe, 0x42, 0x48, 0x50, 0x51, 0x91, 0x01, 0x0b, 0x1d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010938 0xfe, 0x96, 0x15, 0x33, 0x31, 0xe1, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15,
10939 0x33, 0x31, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x03, 0xcd, 0x28, 0xfe,
10940 0xcc, 0x12, 0x53, 0x05, 0x1a, 0xfe, 0xc4, 0x13, 0x21, 0x69, 0x1a, 0xee,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010941 0x55, 0xca, 0x6b, 0xfe, 0xdc, 0x14, 0x4d, 0x0f, 0x06, 0x18, 0xca, 0x7c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010942 0x30, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xab, 0xff, 0x02, 0x83,
10943 0x55, 0x69, 0x19, 0xae, 0x98, 0xfe, 0x30, 0x00, 0x96, 0xf2, 0x18, 0x6d,
10944 0x0f, 0x06, 0xfe, 0x56, 0x10, 0x69, 0x0a, 0xed, 0x98, 0xfe, 0x64, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010945 0x96, 0xf2, 0x09, 0xfe, 0x64, 0x00, 0x18, 0x9e, 0x0f, 0x06, 0xfe, 0x28,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010946 0x10, 0x69, 0x06, 0xfe, 0x60, 0x13, 0x98, 0xfe, 0xc8, 0x00, 0x96, 0xf2,
10947 0x09, 0xfe, 0xc8, 0x00, 0x18, 0x59, 0x0f, 0x06, 0x88, 0x98, 0xfe, 0x90,
10948 0x01, 0x7a, 0xfe, 0x42, 0x15, 0x91, 0xe4, 0xfe, 0x43, 0xf4, 0x9f, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010949 0x56, 0xf0, 0xfe, 0x54, 0x15, 0xfe, 0x04, 0xf4, 0x71, 0xfe, 0x43, 0xf4,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010950 0x9e, 0xfe, 0xf3, 0x10, 0xfe, 0x40, 0x5c, 0x01, 0xfe, 0x16, 0x14, 0x1e,
10951 0x43, 0xec, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x6e, 0x7a, 0xfe, 0x90,
10952 0x15, 0xc4, 0x6e, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010953 0xcc, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0xcc, 0x88, 0x51, 0x21, 0xfe, 0x4d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010954 0xf4, 0x00, 0xe9, 0x91, 0x0f, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58,
10955 0x04, 0x51, 0x0f, 0x0a, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xf3, 0x16,
10956 0x0a, 0x01, 0x0b, 0x26, 0xf3, 0x16, 0x19, 0x01, 0x0b, 0x26, 0xf3, 0x76,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010957 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010958 0x16, 0x19, 0x01, 0x0b, 0x26, 0xb1, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1,
10959 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x26, 0xb1, 0x76, 0xfe, 0x89, 0x4a, 0x01,
10960 0x0b, 0x04, 0x51, 0x04, 0x22, 0xd3, 0x07, 0x06, 0xfe, 0x48, 0x13, 0xb8,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010961 0x13, 0xd3, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x76, 0xa9, 0x67, 0xfe, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010962 0xec, 0xfe, 0x27, 0x01, 0xfe, 0x89, 0x48, 0xff, 0x02, 0x00, 0x10, 0x27,
10963 0xfe, 0x2e, 0x16, 0x32, 0x07, 0xfe, 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1d,
10964 0xfe, 0x52, 0x16, 0x21, 0x13, 0xd4, 0x01, 0x4b, 0x22, 0xd4, 0x07, 0x06,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010965 0x4e, 0x08, 0x54, 0x06, 0x37, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfb, 0x8e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010966 0x07, 0x11, 0xae, 0x09, 0x84, 0x01, 0x0e, 0x8e, 0x09, 0x5d, 0x01, 0xa8,
10967 0x04, 0x09, 0x84, 0x01, 0x0e, 0x8e, 0xfe, 0x80, 0xe7, 0x11, 0x07, 0x11,
10968 0x8a, 0xfe, 0x45, 0x58, 0x01, 0xf0, 0x8e, 0x04, 0x09, 0x48, 0x01, 0x0e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010969 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x80,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010970 0x80, 0xfe, 0x80, 0x4c, 0xfe, 0x49, 0xe4, 0x11, 0xae, 0x09, 0x84, 0x01,
10971 0x0e, 0xfe, 0x80, 0x4c, 0x09, 0x5d, 0x01, 0x87, 0x04, 0x18, 0x11, 0x75,
10972 0x6c, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010973 0x1c, 0xfe, 0x1d, 0xf7, 0x1b, 0x97, 0xfe, 0xee, 0x16, 0x01, 0xfe, 0xf4,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010974 0x17, 0xad, 0x9a, 0x1b, 0x6c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x04,
10975 0xb9, 0x23, 0xfe, 0xde, 0x16, 0xfe, 0xda, 0x10, 0x18, 0x11, 0x75, 0x03,
10976 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1f, 0xfe, 0x18, 0x58, 0x03, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010977 0x66, 0x01, 0xfe, 0x19, 0x58, 0x9a, 0x1f, 0xfe, 0x3c, 0x90, 0xfe, 0x30,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010978 0xf4, 0x06, 0xfe, 0x3c, 0x50, 0x6c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79,
10979 0xfe, 0x1c, 0xf7, 0x1f, 0x97, 0xfe, 0x38, 0x17, 0xfe, 0xb6, 0x14, 0x35,
10980 0x04, 0xb9, 0x23, 0xfe, 0x10, 0x17, 0xfe, 0x9c, 0x10, 0x18, 0x11, 0x75,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010981 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010982 0x2e, 0x97, 0xfe, 0x5a, 0x17, 0xfe, 0x94, 0x14, 0xec, 0x9a, 0x2e, 0x6c,
10983 0x1a, 0xfe, 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00, 0x04, 0xb9, 0x23, 0xfe,
10984 0x4e, 0x17, 0xfe, 0x6c, 0x10, 0x18, 0x11, 0x75, 0xfe, 0x30, 0xbc, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010985 0xb2, 0xbc, 0x9a, 0xcb, 0x6c, 0x1a, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010986 0xcb, 0x97, 0xfe, 0x92, 0x17, 0xfe, 0x5c, 0x14, 0x35, 0x04, 0xb9, 0x23,
10987 0xfe, 0x7e, 0x17, 0xfe, 0x42, 0x10, 0xfe, 0x02, 0xf6, 0x11, 0x75, 0xfe,
10988 0x18, 0xfe, 0x60, 0xfe, 0x19, 0xfe, 0x61, 0xfe, 0x03, 0xa1, 0xfe, 0x1d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010989 0xf7, 0x5b, 0x97, 0xfe, 0xb8, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010990 0x9a, 0x5b, 0x41, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7,
10991 0x11, 0xfe, 0x81, 0xe7, 0x11, 0x12, 0xfe, 0xdd, 0x00, 0x6a, 0x2a, 0x04,
10992 0x6a, 0x2a, 0xfe, 0x12, 0x45, 0x23, 0xfe, 0xa8, 0x17, 0x15, 0x06, 0x39,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010993 0xa0, 0xb4, 0x02, 0x2b, 0xfe, 0x39, 0xf0, 0xfe, 0xfc, 0x17, 0x21, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010994 0xfe, 0x7e, 0x18, 0x1e, 0x19, 0x66, 0x0f, 0x0d, 0x04, 0x75, 0x03, 0xd2,
10995 0x1e, 0x06, 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x7c, 0x6f, 0x4f, 0x32,
10996 0x07, 0x2f, 0xfe, 0x3c, 0x13, 0xf1, 0xfe, 0x42, 0x13, 0x42, 0x92, 0x09,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010997 0x48, 0x01, 0x0e, 0xbb, 0xeb, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010998 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11,
10999 0xac, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c, 0x01, 0x73, 0xfe, 0x16,
11000 0x10, 0x07, 0x82, 0x8b, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12, 0xfe, 0x14,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011001 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x1c, 0x18, 0x18, 0x0a, 0x04, 0xfe, 0x9c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011002 0xe7, 0x0a, 0x10, 0xfe, 0x15, 0x00, 0x64, 0x79, 0x2a, 0x01, 0xe3, 0x18,
11003 0x06, 0x04, 0x42, 0x92, 0x08, 0x54, 0x1b, 0x37, 0x12, 0x2f, 0x01, 0x73,
11004 0x18, 0x06, 0x04, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x3a, 0xce, 0x3b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011005 0xcf, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x04, 0x22, 0xa3, 0x77,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011006 0x13, 0xa3, 0x04, 0x09, 0xa4, 0x01, 0x0e, 0xfe, 0x41, 0x48, 0x09, 0x46,
11007 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x17, 0xfe, 0xe8, 0x18, 0x77, 0x78, 0x04,
11008 0x09, 0x48, 0x01, 0x0e, 0x07, 0x11, 0x4e, 0x09, 0x5d, 0x01, 0xa8, 0x09,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011009 0x46, 0x01, 0x0e, 0x77, 0x78, 0x04, 0xfe, 0x4e, 0xe4, 0x19, 0x6b, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011010 0x1c, 0x19, 0x03, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10,
11011 0xfe, 0x4e, 0xe4, 0xc9, 0x6b, 0xfe, 0x2e, 0x19, 0x03, 0xfe, 0x92, 0x00,
11012 0xfe, 0x02, 0xe6, 0x1a, 0xe5, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x6b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011013 0xfe, 0x40, 0x19, 0x03, 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x1f, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011014 0x08, 0x10, 0x03, 0xfe, 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x6d, 0xfe, 0x4e,
11015 0x45, 0xea, 0xba, 0xff, 0x04, 0x68, 0x54, 0xe7, 0x1e, 0x6e, 0xfe, 0x08,
11016 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe, 0x1a, 0xf4, 0xfe, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011017 0x04, 0xea, 0xfe, 0x48, 0xf4, 0x19, 0x7a, 0xfe, 0x74, 0x19, 0x0f, 0x19,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011018 0x04, 0x07, 0x7e, 0xfe, 0x5a, 0xf0, 0xfe, 0x84, 0x19, 0x25, 0xfe, 0x09,
11019 0x00, 0xfe, 0x34, 0x10, 0x07, 0x1a, 0xfe, 0x5a, 0xf0, 0xfe, 0x92, 0x19,
11020 0x25, 0xca, 0xfe, 0x26, 0x10, 0x07, 0x19, 0x66, 0x25, 0x6d, 0xe5, 0x07,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011021 0x0a, 0x66, 0x25, 0x9e, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x66, 0x25, 0x59,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011022 0xa9, 0xb8, 0x04, 0x15, 0xfe, 0x09, 0x00, 0x01, 0x36, 0xfe, 0x04, 0xfe,
11023 0x81, 0x03, 0x83, 0xfe, 0x40, 0x5c, 0x04, 0x1c, 0xf7, 0xfe, 0x14, 0xf0,
11024 0x0b, 0x27, 0xfe, 0xd6, 0x19, 0x1c, 0xf7, 0x7b, 0xf7, 0xfe, 0x82, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011025 0xfe, 0xda, 0x19, 0x04, 0xff, 0xcc, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070011026};
11027
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011028static unsigned short _adv_asc38C0800_size = sizeof(_adv_asc38C0800_buf); /* 0x14E1 */
11029static ADV_DCNT _adv_asc38C0800_chksum = 0x050D3FD8UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011030
11031/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011032static unsigned char _adv_asc38C1600_buf[] = {
11033 0x00, 0x00, 0x00, 0xf2, 0x00, 0x16, 0x00, 0xfc, 0x00, 0x10, 0x00, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011034 0x18, 0xe4, 0x01, 0x00, 0x04, 0x1e, 0x48, 0xe4, 0x03, 0xf6, 0xf7, 0x13,
11035 0x2e, 0x1e, 0x02, 0x00, 0x07, 0x17, 0xc0, 0x5f, 0x00, 0xfa, 0xff, 0xff,
11036 0x04, 0x00, 0x00, 0xf6, 0x09, 0xe7, 0x82, 0xe7, 0x85, 0xf0, 0x86, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011037 0x4e, 0x10, 0x9e, 0xe7, 0xff, 0x00, 0x55, 0xf0, 0x01, 0xf6, 0x03, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011038 0x98, 0x57, 0x01, 0xe6, 0x00, 0xea, 0x00, 0xec, 0x01, 0xfa, 0x18, 0xf4,
11039 0x08, 0x00, 0xf0, 0x1d, 0x38, 0x54, 0x32, 0xf0, 0x10, 0x00, 0xc2, 0x0e,
11040 0x1e, 0xf0, 0xd5, 0xf0, 0xbc, 0x00, 0x4b, 0xe4, 0x00, 0xe6, 0xb1, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011041 0xb4, 0x00, 0x02, 0x13, 0x3e, 0x1c, 0xc8, 0x47, 0x3e, 0x00, 0xd8, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011042 0x06, 0x13, 0x0c, 0x1c, 0x5e, 0x1e, 0x00, 0x57, 0xc8, 0x57, 0x01, 0xfc,
11043 0xbc, 0x0e, 0xa2, 0x12, 0xb9, 0x54, 0x00, 0x80, 0x62, 0x0a, 0x5a, 0x12,
11044 0xc8, 0x15, 0x3e, 0x1e, 0x18, 0x40, 0xbd, 0x56, 0x03, 0xe6, 0x01, 0xea,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011045 0x5c, 0xf0, 0x0f, 0x00, 0x20, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011046 0x04, 0x13, 0xbb, 0x55, 0x3c, 0x56, 0x3e, 0x57, 0x03, 0x58, 0x4a, 0xe4,
11047 0x40, 0x00, 0xb6, 0x00, 0xbb, 0x00, 0xc0, 0x00, 0x00, 0x01, 0x01, 0x01,
11048 0x3e, 0x01, 0x58, 0x0a, 0x44, 0x10, 0x0a, 0x12, 0x4c, 0x1c, 0x4e, 0x1c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011049 0x02, 0x4a, 0x30, 0xe4, 0x05, 0xe6, 0x0c, 0x00, 0x3c, 0x00, 0x80, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011050 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01,
11051 0x74, 0x01, 0x76, 0x01, 0x78, 0x01, 0x7c, 0x01, 0xc6, 0x0e, 0x0c, 0x10,
11052 0xac, 0x12, 0xae, 0x12, 0x16, 0x1a, 0x32, 0x1c, 0x6e, 0x1e, 0x02, 0x48,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011053 0x3a, 0x55, 0xc9, 0x57, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x06, 0xf7,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011054 0x03, 0xfc, 0x06, 0x00, 0x1e, 0x00, 0xbe, 0x00, 0xe1, 0x00, 0x0c, 0x12,
11055 0x18, 0x1a, 0x70, 0x1a, 0x30, 0x1c, 0x38, 0x1c, 0x10, 0x44, 0x00, 0x4c,
11056 0xb0, 0x57, 0x40, 0x5c, 0x4d, 0xe4, 0x04, 0xea, 0x5d, 0xf0, 0xa7, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011057 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x09, 0x00, 0x19, 0x00, 0x32, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011058 0x33, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00, 0x9e, 0x00, 0xcc, 0x00,
11059 0x20, 0x01, 0x4e, 0x01, 0x79, 0x01, 0x3c, 0x09, 0x68, 0x0d, 0x02, 0x10,
11060 0x04, 0x10, 0x3a, 0x10, 0x08, 0x12, 0x0a, 0x13, 0x40, 0x16, 0x50, 0x16,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011061 0x00, 0x17, 0x4a, 0x19, 0x00, 0x4e, 0x00, 0x54, 0x01, 0x58, 0x00, 0xdc,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011062 0x05, 0xf0, 0x09, 0xf0, 0x59, 0xf0, 0xb8, 0xf0, 0x48, 0xf4, 0x0e, 0xf7,
11063 0x0a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00,
11064 0xd0, 0x00, 0xe7, 0x00, 0xf0, 0x03, 0x69, 0x08, 0xe9, 0x09, 0x5c, 0x0c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011065 0xb6, 0x12, 0xbc, 0x19, 0xd8, 0x1b, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011066 0x42, 0x1d, 0x08, 0x44, 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46,
11067 0x89, 0x48, 0x68, 0x54, 0x83, 0x55, 0x83, 0x59, 0x31, 0xe4, 0x02, 0xe6,
11068 0x07, 0xf0, 0x08, 0xf0, 0x0b, 0xf0, 0x0c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011069 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011070 0xa8, 0x00, 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0x22, 0x01,
11071 0x26, 0x01, 0x60, 0x01, 0x7a, 0x01, 0x82, 0x01, 0xc8, 0x01, 0xca, 0x01,
11072 0x86, 0x02, 0x6a, 0x03, 0x18, 0x05, 0xb2, 0x07, 0x68, 0x08, 0x10, 0x0d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011073 0x06, 0x10, 0x0a, 0x10, 0x0e, 0x10, 0x12, 0x10, 0x60, 0x10, 0xed, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011074 0xf3, 0x10, 0x06, 0x12, 0x10, 0x12, 0x1e, 0x12, 0x0c, 0x13, 0x0e, 0x13,
11075 0x10, 0x13, 0xfe, 0x9c, 0xf0, 0x35, 0x05, 0xfe, 0xec, 0x0e, 0xff, 0x10,
11076 0x00, 0x00, 0xe9, 0xfe, 0x34, 0x1f, 0x00, 0xe8, 0xfe, 0x88, 0x01, 0xff,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011077 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011078 0x00, 0xfe, 0x57, 0x24, 0x00, 0xfe, 0x4c, 0x00, 0x65, 0xff, 0x04, 0x00,
11079 0x00, 0x1a, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x08,
11080 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x13,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011081 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011082 0xfe, 0x04, 0xf7, 0xe8, 0x37, 0x7d, 0x0d, 0x01, 0xfe, 0x4a, 0x11, 0xfe,
11083 0x04, 0xf7, 0xe8, 0x7d, 0x0d, 0x51, 0x37, 0xfe, 0x3d, 0xf0, 0xfe, 0x0c,
11084 0x02, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x91, 0xf0, 0xfe, 0xf8, 0x01, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011085 0x90, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x8f, 0xf0, 0xbc, 0x03, 0x67, 0x4d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011086 0x05, 0xfe, 0x08, 0x0f, 0x01, 0xfe, 0x78, 0x0f, 0xfe, 0xdd, 0x12, 0x05,
11087 0xfe, 0x0e, 0x03, 0xfe, 0x28, 0x1c, 0x03, 0xfe, 0xa6, 0x00, 0xfe, 0xd1,
11088 0x12, 0x3e, 0x22, 0xfe, 0xa6, 0x00, 0xac, 0xfe, 0x48, 0xf0, 0xfe, 0x90,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011089 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0xaa, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc8,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011090 0x02, 0xfe, 0x46, 0xf0, 0xfe, 0x5a, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x60,
11091 0x02, 0xfe, 0x43, 0xf0, 0xfe, 0x4e, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x52,
11092 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x56, 0x02, 0x1c, 0x0d, 0xa2, 0x1c, 0x07,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011093 0x22, 0xb7, 0x05, 0x35, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011094 0x1c, 0xf5, 0xfe, 0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0x5f, 0xfe, 0xe7,
11095 0x10, 0xfe, 0x06, 0xfc, 0xde, 0x0a, 0x81, 0x01, 0xa3, 0x05, 0x35, 0x1f,
11096 0x95, 0x47, 0xb8, 0x01, 0xfe, 0xe4, 0x11, 0x0a, 0x81, 0x01, 0x5c, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011097 0xbd, 0x10, 0x0a, 0x81, 0x01, 0x5c, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011098 0xfe, 0x58, 0x1c, 0x1c, 0x07, 0x22, 0xb7, 0x37, 0x2a, 0x35, 0xfe, 0x3d,
11099 0xf0, 0xfe, 0x0c, 0x02, 0x2b, 0xfe, 0x9e, 0x02, 0xfe, 0x5a, 0x1c, 0xfe,
11100 0x12, 0x1c, 0xfe, 0x14, 0x1c, 0x1f, 0xfe, 0x30, 0x00, 0x47, 0xb8, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011101 0xfe, 0xd4, 0x11, 0x1c, 0x07, 0x22, 0xb7, 0x05, 0xe9, 0x21, 0x2c, 0x09,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011102 0x1a, 0x31, 0xfe, 0x69, 0x10, 0x1c, 0x07, 0x22, 0xb7, 0xfe, 0x04, 0xec,
11103 0x2c, 0x60, 0x01, 0xfe, 0x1e, 0x1e, 0x20, 0x2c, 0xfe, 0x05, 0xf6, 0xde,
11104 0x01, 0xfe, 0x62, 0x1b, 0x01, 0x0c, 0x61, 0x4a, 0x44, 0x15, 0x56, 0x51,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011105 0x01, 0xfe, 0x9e, 0x1e, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x0a, 0x57,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011106 0x01, 0x18, 0x09, 0x00, 0x36, 0x01, 0x85, 0xfe, 0x18, 0x10, 0xfe, 0x41,
11107 0x58, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0xc8, 0x54, 0x7b, 0xfe, 0x1c, 0x03,
11108 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x37, 0x60, 0xfe, 0x02, 0xe8, 0x30,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011109 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, 0x27, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011110 0xfe, 0xe4, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x40,
11111 0x1c, 0x2a, 0xeb, 0xfe, 0x26, 0xf0, 0xfe, 0x66, 0x03, 0xfe, 0xa0, 0xf0,
11112 0xfe, 0x54, 0x03, 0xfe, 0x11, 0xf0, 0xbc, 0xfe, 0xef, 0x10, 0xfe, 0x9f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011113 0xf0, 0xfe, 0x74, 0x03, 0xfe, 0x46, 0x1c, 0x19, 0xfe, 0x11, 0x00, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011114 0x70, 0x37, 0xfe, 0x48, 0x1c, 0xfe, 0x46, 0x1c, 0x01, 0x0c, 0x06, 0x28,
11115 0xfe, 0x18, 0x13, 0x26, 0x21, 0xb9, 0xc7, 0x20, 0xb9, 0x0a, 0x57, 0x01,
11116 0x18, 0xc7, 0x89, 0x01, 0xfe, 0xc8, 0x1a, 0x15, 0xe1, 0x2a, 0xeb, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011117 0x01, 0xf0, 0xeb, 0xfe, 0x82, 0xf0, 0xfe, 0xa4, 0x03, 0xfe, 0x9c, 0x32,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011118 0x15, 0xfe, 0xe4, 0x00, 0x2f, 0xfe, 0xb6, 0x03, 0x2a, 0x3c, 0x16, 0xfe,
11119 0xc6, 0x03, 0x01, 0x41, 0xfe, 0x06, 0xf0, 0xfe, 0xd6, 0x03, 0xaf, 0xa0,
11120 0xfe, 0x0a, 0xf0, 0xfe, 0xa2, 0x07, 0x05, 0x29, 0x03, 0x81, 0x1e, 0x1b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011121 0xfe, 0x24, 0x05, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011122 0xea, 0xfe, 0x46, 0x1c, 0x37, 0x7d, 0x1d, 0xfe, 0x67, 0x1b, 0xfe, 0xbf,
11123 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c, 0x75, 0x01, 0xa6, 0x86, 0x0a,
11124 0x57, 0x01, 0x18, 0x09, 0x00, 0x1b, 0xec, 0x0a, 0xe1, 0x01, 0x18, 0x77,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011125 0x50, 0x40, 0x8d, 0x30, 0x03, 0x81, 0x1e, 0xf8, 0x1f, 0x63, 0x01, 0x42,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011126 0x8f, 0xfe, 0x70, 0x02, 0x05, 0xea, 0xd7, 0x99, 0xd8, 0x9c, 0x2a, 0x29,
11127 0x2f, 0xfe, 0x4e, 0x04, 0x16, 0xfe, 0x4a, 0x04, 0x7e, 0xfe, 0xa0, 0x00,
11128 0xfe, 0x9b, 0x57, 0xfe, 0x54, 0x12, 0x32, 0xff, 0x02, 0x00, 0x10, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011129 0x08, 0x16, 0xfe, 0x02, 0x05, 0x32, 0x01, 0x08, 0x16, 0x29, 0x27, 0x25,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011130 0xee, 0xfe, 0x4c, 0x44, 0xfe, 0x58, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x13,
11131 0x34, 0xfe, 0x4c, 0x54, 0x7b, 0xec, 0x60, 0x8d, 0x30, 0x01, 0xfe, 0x4e,
11132 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x7c, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011133 0x32, 0x13, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x68, 0x13, 0xfe, 0x26, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011134 0x13, 0x34, 0xfe, 0x4c, 0x54, 0x7b, 0xec, 0x01, 0xfe, 0x4e, 0x1e, 0xfe,
11135 0x48, 0x47, 0xfe, 0x54, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xa5, 0x01, 0x43,
11136 0x09, 0x9b, 0xfe, 0x40, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xf9, 0x1f, 0x7f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011137 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, 0x8f,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011138 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x32, 0x15, 0xfe, 0xe6, 0x00, 0x0f, 0xfe,
11139 0x1c, 0x90, 0x04, 0xfe, 0x9c, 0x93, 0x3a, 0x0b, 0x0e, 0x8b, 0x02, 0x1f,
11140 0x7f, 0x01, 0x42, 0x05, 0x35, 0xfe, 0x42, 0x5b, 0x7d, 0x1d, 0xfe, 0x46,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011141 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0x0f, 0xfe, 0x87, 0x80, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011142 0xfe, 0x87, 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0xd0, 0x65, 0x01, 0x0c,
11143 0x06, 0x0d, 0xfe, 0x98, 0x13, 0x0f, 0xfe, 0x20, 0x80, 0x04, 0xfe, 0xa0,
11144 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x1d, 0xfe, 0x84, 0x12, 0x01, 0x38, 0x06,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011145 0x07, 0xfe, 0x70, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x1e, 0x1b, 0xfe, 0xda,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011146 0x05, 0xd0, 0x54, 0x01, 0x38, 0x06, 0x0d, 0xfe, 0x58, 0x13, 0x03, 0xfe,
11147 0xa0, 0x00, 0x1e, 0xfe, 0x50, 0x12, 0x5e, 0xff, 0x02, 0x00, 0x10, 0x2f,
11148 0xfe, 0x90, 0x05, 0x2a, 0x3c, 0xcc, 0xff, 0x02, 0x00, 0x10, 0x2f, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011149 0x9e, 0x05, 0x17, 0xfe, 0xf4, 0x05, 0x15, 0xfe, 0xe3, 0x00, 0x26, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011150 0x38, 0xfe, 0x4a, 0xf0, 0xfe, 0xc0, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0xba,
11151 0x05, 0x71, 0x2e, 0xfe, 0x21, 0x00, 0xf1, 0x2e, 0xfe, 0x22, 0x00, 0xa2,
11152 0x2e, 0x4a, 0xfe, 0x09, 0x48, 0xff, 0x02, 0x00, 0x10, 0x2f, 0xfe, 0xd0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011153 0x05, 0x17, 0xfe, 0xf4, 0x05, 0xfe, 0xe2, 0x08, 0x01, 0x38, 0x06, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011154 0x1c, 0x00, 0x4d, 0x01, 0xa7, 0x2e, 0x07, 0x20, 0xe4, 0x47, 0xfe, 0x27,
11155 0x01, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x24, 0x12, 0x3e, 0x01, 0x84, 0x1f,
11156 0x7f, 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011157 0x8f, 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x03, 0xe6, 0x1e, 0xfe, 0xca, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011158 0x03, 0xb6, 0x1e, 0xfe, 0x40, 0x12, 0x03, 0x66, 0x1e, 0xfe, 0x38, 0x13,
11159 0x3e, 0x01, 0x84, 0x17, 0xfe, 0x72, 0x06, 0x0a, 0x07, 0x01, 0x38, 0x06,
11160 0x24, 0xfe, 0x02, 0x12, 0x4f, 0x01, 0xfe, 0x56, 0x19, 0x16, 0xfe, 0x68,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011161 0x06, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x66, 0x8a, 0x10, 0x66,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011162 0x03, 0x9a, 0x1e, 0xfe, 0x70, 0x12, 0x03, 0x55, 0x1e, 0xfe, 0x68, 0x13,
11163 0x01, 0xc6, 0x09, 0x12, 0x48, 0xfe, 0x92, 0x06, 0x2e, 0x12, 0x01, 0xfe,
11164 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0x13, 0x58, 0xff, 0x02, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011165 0x57, 0x52, 0xad, 0x23, 0x3f, 0x4e, 0x62, 0x49, 0x3e, 0x01, 0x84, 0x17,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011166 0xfe, 0xea, 0x06, 0x01, 0x38, 0x06, 0x12, 0xf7, 0x45, 0x0a, 0x95, 0x01,
11167 0xfe, 0x84, 0x19, 0x16, 0xfe, 0xe0, 0x06, 0x15, 0x82, 0x01, 0x41, 0x15,
11168 0xe2, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x1c, 0x07, 0x01, 0x84, 0xfe, 0xae,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011169 0x10, 0x03, 0x6f, 0x1e, 0xfe, 0x9e, 0x13, 0x3e, 0x01, 0x84, 0x03, 0x9a,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011170 0x1e, 0xfe, 0x1a, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfc, 0x01, 0xc6, 0x01,
11171 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0xf0, 0x45, 0x0a, 0x95,
11172 0x03, 0xb6, 0x1e, 0xf8, 0x01, 0x38, 0x06, 0x24, 0x36, 0xfe, 0x02, 0xf6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011173 0x07, 0x71, 0x78, 0x8c, 0x00, 0x4d, 0x62, 0x49, 0x3e, 0x2d, 0x93, 0x4e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011174 0xd0, 0x0d, 0x17, 0xfe, 0x9a, 0x07, 0x01, 0xfe, 0xc0, 0x19, 0x16, 0xfe,
11175 0x90, 0x07, 0x26, 0x20, 0x9e, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x21,
11176 0x9e, 0x09, 0x07, 0xfb, 0x03, 0xe6, 0xfe, 0x58, 0x57, 0x10, 0xe6, 0x05,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011177 0xfe, 0x2a, 0x06, 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x1c, 0x07, 0x01, 0x84,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011178 0xfe, 0x9c, 0x32, 0x5f, 0x75, 0x01, 0xa6, 0x86, 0x15, 0xfe, 0xe2, 0x00,
11179 0x2f, 0xed, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe, 0xce, 0x07, 0xae, 0xfe,
11180 0x96, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x9e, 0x08, 0xaf, 0xa0, 0x05, 0x29,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011181 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x2e, 0x12, 0x14, 0x1d, 0x01, 0x08, 0x14,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011182 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0xfe,
11183 0x99, 0xa4, 0x01, 0x08, 0x14, 0x00, 0x05, 0xfe, 0xc6, 0x09, 0x01, 0x76,
11184 0x06, 0x12, 0xfe, 0x3a, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x30, 0x13,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011185 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011186 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x07, 0x01, 0x08, 0x14, 0x00,
11187 0x05, 0xef, 0x7c, 0x4a, 0x78, 0x4f, 0x0f, 0xfe, 0x9a, 0x81, 0x04, 0xfe,
11188 0x9a, 0x83, 0xfe, 0xcb, 0x47, 0x0b, 0x0e, 0x2d, 0x28, 0x48, 0xfe, 0x6c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011189 0x08, 0x0a, 0x28, 0xfe, 0x09, 0x6f, 0xca, 0xfe, 0xca, 0x45, 0xfe, 0x32,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011190 0x12, 0x53, 0x63, 0x4e, 0x7c, 0x97, 0x2f, 0xfe, 0x7e, 0x08, 0x2a, 0x3c,
11191 0xfe, 0x0a, 0xf0, 0xfe, 0x6c, 0x08, 0xaf, 0xa0, 0xae, 0xfe, 0x96, 0x08,
11192 0x05, 0x29, 0x01, 0x41, 0x05, 0xed, 0x14, 0x24, 0x05, 0xed, 0xfe, 0x9c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011193 0xf7, 0x9f, 0x01, 0xfe, 0xae, 0x1e, 0xfe, 0x18, 0x58, 0x01, 0xfe, 0xbe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011194 0x1e, 0xfe, 0x99, 0x58, 0xfe, 0x78, 0x18, 0xfe, 0xf9, 0x18, 0x8e, 0xfe,
11195 0x16, 0x09, 0x10, 0x6a, 0x22, 0x6b, 0x01, 0x0c, 0x61, 0x54, 0x44, 0x21,
11196 0x2c, 0x09, 0x1a, 0xf8, 0x77, 0x01, 0xfe, 0x7e, 0x1e, 0x47, 0x2c, 0x7a,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011197 0x30, 0xf0, 0xfe, 0x83, 0xe7, 0xfe, 0x3f, 0x00, 0x71, 0xfe, 0x03, 0x40,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011198 0x01, 0x0c, 0x61, 0x65, 0x44, 0x01, 0xc2, 0xc8, 0xfe, 0x1f, 0x40, 0x20,
11199 0x6e, 0x01, 0xfe, 0x6a, 0x16, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe,
11200 0x44, 0x51, 0xfe, 0xc6, 0x51, 0xfe, 0x10, 0x10, 0x01, 0xfe, 0xce, 0x1e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011201 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x01, 0xfe, 0xee, 0x1e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011202 0x01, 0xfe, 0xfe, 0x1e, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x10, 0x4b,
11203 0x22, 0x4c, 0xfe, 0x8a, 0x10, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0x50, 0x12,
11204 0x01, 0xfe, 0xae, 0x1e, 0x01, 0xfe, 0xbe, 0x1e, 0x10, 0x6a, 0x22, 0x6b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011205 0x01, 0x0c, 0x06, 0x65, 0x4e, 0x01, 0xc2, 0x0f, 0xfe, 0x1f, 0x80, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011206 0xfe, 0x9f, 0x83, 0x33, 0x0b, 0x0e, 0x20, 0x6e, 0x0f, 0xfe, 0x44, 0x90,
11207 0x04, 0xfe, 0xc4, 0x93, 0x3a, 0x0b, 0xfe, 0xc6, 0x90, 0x04, 0xfe, 0xc6,
11208 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x6c, 0x22, 0x6d, 0x01, 0xfe, 0xce, 0x1e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011209 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x0f, 0xfe, 0x40, 0x90,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011210 0x04, 0xfe, 0xc0, 0x93, 0x3a, 0x0b, 0xfe, 0xc2, 0x90, 0x04, 0xfe, 0xc2,
11211 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x4b, 0x22, 0x4c, 0x10, 0x64, 0x22, 0x34,
11212 0x01, 0x0c, 0x61, 0x24, 0x44, 0x37, 0x13, 0xfe, 0x4e, 0x11, 0x2f, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011213 0xde, 0x09, 0xfe, 0x9e, 0xf0, 0xfe, 0xf2, 0x09, 0xfe, 0x01, 0x48, 0x1b,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011214 0x3c, 0x37, 0x88, 0xf5, 0xd4, 0xfe, 0x1e, 0x0a, 0xd5, 0xfe, 0x42, 0x0a,
11215 0xd2, 0xfe, 0x1e, 0x0a, 0xd3, 0xfe, 0x42, 0x0a, 0xae, 0xfe, 0x12, 0x0a,
11216 0xfe, 0x06, 0xf0, 0xfe, 0x18, 0x0a, 0xaf, 0xa0, 0x05, 0x29, 0x01, 0x41,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011217 0xfe, 0xc1, 0x10, 0x14, 0x24, 0xfe, 0xc1, 0x10, 0x01, 0x76, 0x06, 0x07,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011218 0xfe, 0x14, 0x12, 0x01, 0x76, 0x06, 0x0d, 0x5d, 0x01, 0x0c, 0x06, 0x0d,
11219 0xfe, 0x74, 0x12, 0xfe, 0x2e, 0x1c, 0x05, 0xfe, 0x1a, 0x0c, 0x01, 0x76,
11220 0x06, 0x07, 0x5d, 0x01, 0x76, 0x06, 0x0d, 0x41, 0xfe, 0x2c, 0x1c, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011221 0xaa, 0xf0, 0xfe, 0xce, 0x0a, 0xfe, 0xac, 0xf0, 0xfe, 0x66, 0x0a, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011222 0x92, 0x10, 0xc4, 0xf6, 0xfe, 0xad, 0xf0, 0xfe, 0x72, 0x0a, 0x05, 0xfe,
11223 0x1a, 0x0c, 0xc5, 0xfe, 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0xbf, 0xfe, 0x6b,
11224 0x18, 0x23, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12, 0xac, 0xfe, 0xd2, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011225 0xbf, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x1b, 0xbf, 0x03, 0xe3, 0x23, 0x07,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011226 0x1b, 0xbf, 0xd4, 0x5b, 0xd5, 0x5b, 0xd2, 0x5b, 0xd3, 0x5b, 0xc4, 0xc5,
11227 0xfe, 0xa9, 0x10, 0x75, 0x5e, 0x32, 0x1f, 0x7f, 0x01, 0x42, 0x19, 0xfe,
11228 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x70, 0x19, 0x98, 0x05, 0x70, 0xfe, 0x74,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011229 0x18, 0x23, 0xfe, 0x00, 0xf8, 0x1b, 0x5b, 0x7d, 0x12, 0x01, 0xfe, 0x78,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011230 0x0f, 0x4d, 0x01, 0xfe, 0x96, 0x1a, 0x21, 0x30, 0x77, 0x7d, 0x1d, 0x05,
11231 0x5b, 0x01, 0x0c, 0x06, 0x0d, 0x2b, 0xfe, 0xe2, 0x0b, 0x01, 0x0c, 0x06,
11232 0x54, 0xfe, 0xa6, 0x12, 0x01, 0x0c, 0x06, 0x24, 0xfe, 0x88, 0x13, 0x21,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011233 0x6e, 0xc7, 0x01, 0xfe, 0x1e, 0x1f, 0x0f, 0xfe, 0x83, 0x80, 0x04, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011234 0x83, 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0xfe, 0xc8, 0x44, 0xfe, 0x42,
11235 0x13, 0x0f, 0xfe, 0x04, 0x91, 0x04, 0xfe, 0x84, 0x93, 0xfe, 0xca, 0x57,
11236 0x0b, 0xfe, 0x86, 0x91, 0x04, 0xfe, 0x86, 0x93, 0xfe, 0xcb, 0x57, 0x0b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011237 0x0e, 0x7a, 0x30, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x8e, 0x40, 0x03,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011238 0x6a, 0x3b, 0x6b, 0x10, 0x97, 0x22, 0x98, 0xd9, 0x6a, 0xda, 0x6b, 0x01,
11239 0xc2, 0xc8, 0x7a, 0x30, 0x20, 0x6e, 0xdb, 0x64, 0xdc, 0x34, 0x91, 0x6c,
11240 0x7e, 0x6d, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55, 0xfe, 0x04, 0xfa, 0x64,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011241 0xfe, 0x05, 0xfa, 0x34, 0x01, 0xfe, 0x6a, 0x16, 0xa3, 0x26, 0x10, 0x97,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011242 0x10, 0x98, 0x91, 0x6c, 0x7e, 0x6d, 0xfe, 0x14, 0x10, 0x01, 0x0c, 0x06,
11243 0x24, 0x1b, 0x40, 0x91, 0x4b, 0x7e, 0x4c, 0x01, 0x0c, 0x06, 0xfe, 0xf7,
11244 0x00, 0x44, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011245 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x24,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011246 0x1b, 0x40, 0x01, 0x0c, 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x78, 0x01, 0xfe,
11247 0x8e, 0x1e, 0x4f, 0x0f, 0xfe, 0x10, 0x90, 0x04, 0xfe, 0x90, 0x93, 0x3a,
11248 0x0b, 0xfe, 0x92, 0x90, 0x04, 0xfe, 0x92, 0x93, 0x79, 0x0b, 0x0e, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011249 0xbd, 0x10, 0x01, 0x43, 0x09, 0xbb, 0x1b, 0xfe, 0x6e, 0x0a, 0x15, 0xbb,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011250 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x14, 0x13, 0x03, 0x4b, 0x3b, 0x4c, 0x8e,
11251 0xfe, 0x6e, 0x0a, 0xfe, 0x0c, 0x58, 0xfe, 0x8d, 0x58, 0x05, 0x5b, 0x26,
11252 0x3e, 0x0f, 0xfe, 0x19, 0x80, 0x04, 0xfe, 0x99, 0x83, 0x33, 0x0b, 0x0e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011253 0xfe, 0xe5, 0x10, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1a, 0x12, 0xfe, 0x6c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011254 0x19, 0xfe, 0x19, 0x41, 0xfe, 0x6b, 0x18, 0xac, 0xfe, 0xd1, 0xf0, 0xef,
11255 0x1f, 0x92, 0x01, 0x42, 0x19, 0xfe, 0x44, 0x00, 0xfe, 0x90, 0x10, 0xfe,
11256 0x6c, 0x19, 0xd9, 0x4b, 0xfe, 0xed, 0x19, 0xda, 0x4c, 0xfe, 0x0c, 0x51,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011257 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xff, 0x31, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011258 0x76, 0x10, 0xac, 0xfe, 0xd2, 0xf0, 0xfe, 0xba, 0x0c, 0xfe, 0x76, 0x18,
11259 0x23, 0x1d, 0x5d, 0x03, 0xe3, 0x23, 0x07, 0xfe, 0x08, 0x13, 0x19, 0xfe,
11260 0x16, 0x00, 0x05, 0x70, 0xfe, 0xd1, 0xf0, 0xfe, 0xcc, 0x0c, 0x1f, 0x92,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011261 0x01, 0x42, 0x19, 0xfe, 0x17, 0x00, 0x5c, 0xfe, 0xce, 0xf0, 0xfe, 0xd2,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011262 0x0c, 0xfe, 0x3e, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xde, 0x0c, 0x19, 0xfe,
11263 0x22, 0x00, 0x05, 0x70, 0xfe, 0xcb, 0xf0, 0xfe, 0xea, 0x0c, 0x19, 0xfe,
11264 0x24, 0x00, 0x05, 0x70, 0xfe, 0xd0, 0xf0, 0xfe, 0xf4, 0x0c, 0x19, 0x94,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011265 0xfe, 0x1c, 0x10, 0xfe, 0xcf, 0xf0, 0xfe, 0xfe, 0x0c, 0x19, 0x4a, 0xf3,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011266 0xfe, 0xcc, 0xf0, 0xef, 0x01, 0x76, 0x06, 0x24, 0x4d, 0x19, 0xfe, 0x12,
11267 0x00, 0x37, 0x13, 0xfe, 0x4e, 0x11, 0x2f, 0xfe, 0x16, 0x0d, 0xfe, 0x9e,
11268 0xf0, 0xfe, 0x2a, 0x0d, 0xfe, 0x01, 0x48, 0x1b, 0x3c, 0x37, 0x88, 0xf5,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011269 0xd4, 0x29, 0xd5, 0x29, 0xd2, 0x29, 0xd3, 0x29, 0x37, 0xfe, 0x9c, 0x32,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011270 0x2f, 0xfe, 0x3e, 0x0d, 0x2a, 0x3c, 0xae, 0xfe, 0x62, 0x0d, 0xaf, 0xa0,
11271 0xd4, 0x9f, 0xd5, 0x9f, 0xd2, 0x9f, 0xd3, 0x9f, 0x05, 0x29, 0x01, 0x41,
11272 0xfe, 0xd3, 0x10, 0x15, 0xfe, 0xe8, 0x00, 0xc4, 0xc5, 0x75, 0xd7, 0x99,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011273 0xd8, 0x9c, 0xfe, 0x89, 0xf0, 0x29, 0x27, 0x25, 0xbe, 0xd7, 0x99, 0xd8,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011274 0x9c, 0x2f, 0xfe, 0x8c, 0x0d, 0x16, 0x29, 0x27, 0x25, 0xbd, 0xfe, 0x01,
11275 0x48, 0xa4, 0x19, 0xfe, 0x42, 0x00, 0x05, 0x70, 0x90, 0x07, 0xfe, 0x81,
11276 0x49, 0x1b, 0xfe, 0x64, 0x0e, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x44, 0x13,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011277 0x19, 0x00, 0x2d, 0x0d, 0xfe, 0x54, 0x12, 0x2d, 0xfe, 0x28, 0x00, 0x2b,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011278 0xfe, 0xda, 0x0e, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, 0x36, 0x46, 0xfe,
11279 0x28, 0x00, 0xfe, 0xfa, 0x10, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe, 0x00,
11280 0x1d, 0x0a, 0xba, 0x01, 0xfe, 0x58, 0x10, 0x40, 0x15, 0x56, 0x01, 0x85,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011281 0x05, 0x35, 0x19, 0xfe, 0x44, 0x00, 0x2d, 0x0d, 0xf7, 0x46, 0x0d, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011282 0xcc, 0x10, 0x01, 0xa7, 0x46, 0x0d, 0xfe, 0xc2, 0x10, 0x01, 0xa7, 0x0f,
11283 0xfe, 0x19, 0x82, 0x04, 0xfe, 0x99, 0x83, 0xfe, 0xcc, 0x47, 0x0b, 0x0e,
11284 0xfe, 0x34, 0x46, 0xa5, 0x46, 0x0d, 0x19, 0xfe, 0x43, 0x00, 0xfe, 0xa2,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011285 0x10, 0x01, 0x0c, 0x61, 0x0d, 0x44, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011286 0x00, 0x1d, 0x40, 0x15, 0x56, 0x01, 0x85, 0x7d, 0x0d, 0x40, 0x51, 0x01,
11287 0xfe, 0x9e, 0x1e, 0x05, 0xfe, 0x3a, 0x03, 0x01, 0x0c, 0x06, 0x0d, 0x5d,
11288 0x46, 0x0d, 0x19, 0x00, 0xfe, 0x62, 0x10, 0x01, 0x76, 0x06, 0x12, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011289 0x5c, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x52, 0x13, 0xfe, 0x1c, 0x1c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011290 0xfe, 0x9d, 0xf0, 0xfe, 0x8e, 0x0e, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0,
11291 0xfe, 0x94, 0x0e, 0x01, 0x0c, 0x61, 0x12, 0x44, 0xfe, 0x9f, 0x10, 0x19,
11292 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0d, 0x4f, 0xfe, 0x2e, 0x10, 0x19,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011293 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x19, 0xfe, 0x47, 0x00, 0xf1, 0x19,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011294 0xfe, 0x41, 0x00, 0xa2, 0x19, 0xfe, 0x24, 0x00, 0x86, 0xc4, 0xc5, 0x75,
11295 0x03, 0x81, 0x1e, 0x2b, 0xea, 0x4f, 0xfe, 0x04, 0xe6, 0x12, 0xfe, 0x9d,
11296 0x41, 0xfe, 0x1c, 0x42, 0x40, 0x01, 0xf4, 0x05, 0x35, 0xfe, 0x12, 0x1c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011297 0x1f, 0x0d, 0x47, 0xb5, 0xc3, 0x1f, 0xfe, 0x31, 0x00, 0x47, 0xb8, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011298 0xfe, 0xd4, 0x11, 0x05, 0xe9, 0x51, 0xfe, 0x06, 0xec, 0xe0, 0xfe, 0x0e,
11299 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0x06, 0xea, 0xe0,
11300 0xfe, 0x47, 0x4b, 0x45, 0xfe, 0x75, 0x57, 0x03, 0x67, 0xfe, 0x98, 0x56,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011301 0xfe, 0x38, 0x12, 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x44, 0x48, 0x60, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011302 0x0c, 0x06, 0x28, 0xfe, 0x18, 0x13, 0x0a, 0x57, 0x01, 0x18, 0x3e, 0xfe,
11303 0x41, 0x58, 0x0a, 0xba, 0xfe, 0xfa, 0x14, 0xfe, 0x49, 0x54, 0xb0, 0xfe,
11304 0x5e, 0x0f, 0x05, 0xfe, 0x3a, 0x03, 0x0a, 0x67, 0xfe, 0xe0, 0x14, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011305 0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0xce, 0x47,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011306 0xfe, 0xad, 0x13, 0x05, 0x35, 0x21, 0x2c, 0x09, 0x1a, 0xfe, 0x98, 0x12,
11307 0x26, 0x20, 0x96, 0x20, 0xe7, 0xfe, 0x08, 0x1c, 0xfe, 0x7c, 0x19, 0xfe,
11308 0xfd, 0x19, 0xfe, 0x0a, 0x1c, 0x03, 0xe5, 0xfe, 0x48, 0x55, 0xa5, 0x3b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011309 0xfe, 0x62, 0x01, 0xfe, 0xc9, 0x55, 0x31, 0xfe, 0x74, 0x10, 0x01, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011310 0xf0, 0x1a, 0x03, 0xfe, 0x38, 0x01, 0x3b, 0xfe, 0x3a, 0x01, 0x8e, 0xfe,
11311 0x1e, 0x10, 0xfe, 0x02, 0xec, 0xe7, 0x53, 0x00, 0x36, 0xfe, 0x04, 0xec,
11312 0x2c, 0x60, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x62, 0x1b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011313 0x01, 0xfe, 0xce, 0x1e, 0xb2, 0x11, 0xfe, 0x18, 0x13, 0xca, 0xfe, 0x02,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011314 0xea, 0xe7, 0x53, 0x92, 0xfe, 0xc3, 0x13, 0x1f, 0x12, 0x47, 0xb5, 0xc3,
11315 0xfe, 0x2a, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x23, 0xfe, 0xf0, 0xff, 0x10,
11316 0xe5, 0x03, 0xfe, 0x3a, 0x01, 0x10, 0xfe, 0x62, 0x01, 0x01, 0xfe, 0x1e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011317 0x1e, 0x20, 0x2c, 0x15, 0x56, 0x01, 0xfe, 0x9e, 0x1e, 0x13, 0x07, 0x02,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011318 0x26, 0x02, 0x21, 0x96, 0xc7, 0x20, 0x96, 0x09, 0x92, 0xfe, 0x79, 0x13,
11319 0x1f, 0x1d, 0x47, 0xb5, 0xc3, 0xfe, 0xe1, 0x10, 0xcf, 0xfe, 0x03, 0xdc,
11320 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xcf, 0xfe, 0x03, 0xdc, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011321 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x26, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011322 0x00, 0xcc, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x89, 0x02, 0x01, 0x0c, 0x06,
11323 0x4a, 0xfe, 0x4e, 0x13, 0x0f, 0xfe, 0x1c, 0x80, 0x04, 0xfe, 0x9c, 0x83,
11324 0x33, 0x0b, 0x0e, 0x09, 0x07, 0xfe, 0x3a, 0x13, 0x0f, 0xfe, 0x1e, 0x80,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011325 0x04, 0xfe, 0x9e, 0x83, 0x33, 0x0b, 0x0e, 0xfe, 0x2a, 0x13, 0x0f, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011326 0x1d, 0x80, 0x04, 0xfe, 0x9d, 0x83, 0xfe, 0xf9, 0x13, 0x0e, 0xfe, 0x1c,
11327 0x13, 0x01, 0xfe, 0xee, 0x1e, 0xac, 0xfe, 0x14, 0x13, 0x01, 0xfe, 0xfe,
11328 0x1e, 0xfe, 0x81, 0x58, 0xfa, 0x01, 0xfe, 0x0e, 0x1f, 0xfe, 0x30, 0xf4,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011329 0x0d, 0xfe, 0x3c, 0x50, 0xa2, 0x01, 0xfe, 0x92, 0x1b, 0x01, 0x43, 0x09,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011330 0x56, 0xfb, 0x01, 0xfe, 0xc8, 0x1a, 0x01, 0x0c, 0x06, 0x28, 0xa4, 0x01,
11331 0xfe, 0xf4, 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x15, 0xfe, 0xe9, 0x00, 0x01,
11332 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x01, 0xfe, 0x22, 0x1b, 0xfe, 0x1e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011333 0x1c, 0x0f, 0xfe, 0x14, 0x90, 0x04, 0xfe, 0x94, 0x93, 0x3a, 0x0b, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011334 0x96, 0x90, 0x04, 0xfe, 0x96, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0xfe, 0x64,
11335 0x01, 0x22, 0xfe, 0x66, 0x01, 0x01, 0x0c, 0x06, 0x65, 0xf9, 0x0f, 0xfe,
11336 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b, 0x0e, 0x77, 0xfe, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011337 0xec, 0x2c, 0xfe, 0x80, 0x40, 0x20, 0x2c, 0x7a, 0x30, 0x15, 0xdf, 0x40,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011338 0x21, 0x2c, 0xfe, 0x00, 0x40, 0x8d, 0x2c, 0x02, 0xfe, 0x08, 0x1c, 0x03,
11339 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58, 0x03, 0xfe, 0xae, 0x00, 0xfe, 0x07,
11340 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe, 0xb2, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011341 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x2e, 0x49, 0x20, 0xe0, 0x26, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011342 0x66, 0x10, 0x55, 0x10, 0x6f, 0x13, 0x57, 0x52, 0x4f, 0x1c, 0x28, 0xfe,
11343 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x2b, 0xfe, 0x88, 0x11, 0x46, 0x1a, 0x13,
11344 0x5a, 0x52, 0x1c, 0x4a, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x2b, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011345 0x9e, 0x11, 0x2e, 0x1a, 0x20, 0x2c, 0x90, 0x34, 0x60, 0x21, 0x2c, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011346 0x00, 0x40, 0x8d, 0x2c, 0x15, 0xdf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0,
11347 0xfe, 0xb2, 0x11, 0xfe, 0x12, 0x1c, 0x75, 0xfe, 0x14, 0x1c, 0xfe, 0x10,
11348 0x1c, 0xfe, 0x18, 0x1c, 0x02, 0x51, 0xfe, 0x0c, 0x14, 0xfe, 0x0e, 0x47,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011349 0xfe, 0x07, 0xe6, 0x28, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x02, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011350 0xa7, 0x90, 0x34, 0x60, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42,
11351 0x13, 0xfe, 0x02, 0x80, 0x09, 0x56, 0xfe, 0x34, 0x13, 0x0a, 0x5a, 0x01,
11352 0x18, 0xcb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011353 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, 0x89,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011354 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x5c, 0x01, 0x85,
11355 0xf2, 0x09, 0x9b, 0xa4, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xec,
11356 0x11, 0x02, 0xfe, 0x44, 0x58, 0x77, 0xfe, 0x01, 0xec, 0xb8, 0xfe, 0x9e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011357 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x12, 0x8d, 0x30, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011358 0xf4, 0xfe, 0xdd, 0x10, 0x37, 0xd7, 0x99, 0xd8, 0x9c, 0x27, 0x25, 0xee,
11359 0x09, 0x12, 0xfe, 0x48, 0x12, 0x09, 0x0d, 0xfe, 0x56, 0x12, 0x09, 0x1d,
11360 0xfe, 0x30, 0x12, 0x09, 0xdd, 0x1b, 0xfe, 0xc4, 0x13, 0x09, 0xfe, 0x23,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011361 0x00, 0x1b, 0xfe, 0xd0, 0x13, 0x09, 0x07, 0x1b, 0xfe, 0x34, 0x14, 0x09,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011362 0x24, 0xfe, 0x12, 0x12, 0x09, 0x00, 0x1b, 0x29, 0x1f, 0xdd, 0x01, 0x42,
11363 0xa1, 0x32, 0x01, 0x08, 0xae, 0x41, 0x02, 0x32, 0xfe, 0x62, 0x08, 0x0a,
11364 0xe1, 0x01, 0xfe, 0x58, 0x10, 0x15, 0x9b, 0x05, 0x35, 0x32, 0x01, 0x43,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011365 0x09, 0xbb, 0xfe, 0xd7, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0x8e, 0xfe, 0x80,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011366 0x13, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0x72, 0x12, 0xdb, 0x64, 0xdc, 0x34,
11367 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55, 0xb0, 0xfe, 0x4a, 0x13, 0x21, 0x6e,
11368 0xfe, 0x26, 0x13, 0x03, 0x97, 0x3b, 0x98, 0x8e, 0xfe, 0xb6, 0x0e, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011369 0x6a, 0x22, 0x6b, 0x26, 0x10, 0x97, 0x10, 0x98, 0x01, 0xc2, 0x2e, 0x49,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011370 0x88, 0x20, 0x6e, 0x01, 0xfe, 0x6a, 0x16, 0xdb, 0x64, 0xdc, 0x34, 0xfe,
11371 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x64, 0xfe, 0x05, 0xfa,
11372 0x34, 0xfe, 0x8f, 0x10, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x40, 0x56, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011373 0xe1, 0x56, 0x10, 0x6c, 0x22, 0x6d, 0x71, 0xdb, 0x64, 0xdc, 0x34, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011374 0x44, 0x55, 0xfe, 0xe5, 0x55, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x00, 0x56,
11375 0xfe, 0xa1, 0x56, 0x10, 0x68, 0x22, 0x69, 0x01, 0x0c, 0x06, 0x54, 0xf9,
11376 0x21, 0x6e, 0xfe, 0x1f, 0x40, 0x03, 0x6a, 0x3b, 0x6b, 0xfe, 0x2c, 0x50,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011377 0xfe, 0xae, 0x50, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x44, 0x50, 0xfe, 0xc6,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011378 0x50, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03,
11379 0x4b, 0x3b, 0x4c, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x05, 0x73, 0x2e,
11380 0x07, 0x20, 0x9e, 0x05, 0x72, 0x32, 0x01, 0x08, 0x16, 0x3d, 0x27, 0x25,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011381 0xee, 0x09, 0x07, 0x2b, 0x3d, 0x01, 0x43, 0x09, 0xbb, 0x2b, 0x72, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011382 0xa6, 0x23, 0x3f, 0x1b, 0x3d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1e, 0x13,
11383 0x91, 0x4b, 0x7e, 0x4c, 0xfe, 0x0a, 0x55, 0x31, 0xfe, 0x8b, 0x55, 0xd9,
11384 0x4b, 0xda, 0x4c, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x05, 0x72, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011385 0xfe, 0x8e, 0x1e, 0xca, 0xfe, 0x19, 0x41, 0x05, 0x72, 0x32, 0x01, 0x08,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011386 0x2a, 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbe, 0x2d, 0x1d, 0xc0, 0x2d, 0x0d,
11387 0x83, 0x2d, 0x7f, 0x1b, 0xfe, 0x66, 0x15, 0x05, 0x3d, 0x01, 0x08, 0x2a,
11388 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbd, 0x09, 0x1d, 0x2b, 0x3d, 0x01, 0x08,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011389 0x16, 0xc0, 0x27, 0x25, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x50, 0x03,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011390 0xb6, 0x1e, 0x83, 0x01, 0x38, 0x06, 0x24, 0x31, 0xa1, 0xfe, 0xbb, 0x45,
11391 0x2d, 0x00, 0xa4, 0x46, 0x07, 0x90, 0x3f, 0x01, 0xfe, 0xf8, 0x15, 0x01,
11392 0xa6, 0x86, 0xfe, 0x4b, 0x45, 0xfe, 0x20, 0x13, 0x01, 0x43, 0x09, 0x82,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011393 0xfe, 0x16, 0x13, 0x03, 0x9a, 0x1e, 0x5d, 0x03, 0x55, 0x1e, 0x31, 0x5e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011394 0x05, 0x72, 0xfe, 0xc0, 0x5d, 0x01, 0xa7, 0xfe, 0x03, 0x17, 0x03, 0x66,
11395 0x8a, 0x10, 0x66, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01, 0xfe, 0x56,
11396 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d, 0x27, 0x25, 0xbd,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011397 0x09, 0x07, 0x2b, 0x3d, 0x01, 0xfe, 0xbe, 0x16, 0xfe, 0x42, 0x58, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011398 0xe8, 0x14, 0x01, 0xa6, 0x86, 0xfe, 0x4a, 0xf4, 0x0d, 0x1b, 0x3d, 0xfe,
11399 0x4a, 0xf4, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09, 0x82, 0x4e, 0x05,
11400 0x72, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011401 0x01, 0xfe, 0x84, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011402 0x27, 0x25, 0xbd, 0x09, 0x12, 0x2b, 0x3d, 0x01, 0xfe, 0xe8, 0x17, 0x8b,
11403 0xfe, 0xaa, 0x14, 0xfe, 0xb6, 0x14, 0x86, 0xa8, 0xb2, 0x0d, 0x1b, 0x3d,
11404 0xb2, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09, 0x82, 0x4e, 0x05, 0x72,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011405 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011406 0xfe, 0xc0, 0x19, 0x05, 0x73, 0x13, 0x07, 0x2f, 0xfe, 0xcc, 0x15, 0x17,
11407 0xfe, 0xe2, 0x15, 0x5f, 0xcc, 0x01, 0x08, 0x26, 0x5f, 0x02, 0x8f, 0xfe,
11408 0xde, 0x15, 0x2a, 0xfe, 0xde, 0x15, 0x16, 0xfe, 0xcc, 0x15, 0x5e, 0x32,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011409 0x01, 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011410 0xad, 0x23, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02,
11411 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xad, 0x23, 0x3f, 0xfe, 0x30,
11412 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011413 0xad, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xfe, 0x00, 0x5e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011414 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xad, 0xfe, 0x0b, 0x58,
11415 0x02, 0x0a, 0x66, 0x01, 0x5c, 0x0a, 0x55, 0x01, 0x5c, 0x0a, 0x6f, 0x01,
11416 0x5c, 0x02, 0x01, 0xfe, 0x1e, 0x1f, 0x23, 0x1a, 0xff, 0x03, 0x00, 0x54,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011417 0xfe, 0x00, 0xf4, 0x24, 0x52, 0x0f, 0xfe, 0x00, 0x7c, 0x04, 0xfe, 0x07,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011418 0x7c, 0x3a, 0x0b, 0x0e, 0xfe, 0x00, 0x71, 0xfe, 0xf9, 0x18, 0xfe, 0x7a,
11419 0x19, 0xfe, 0xfb, 0x19, 0xfe, 0x1a, 0xf7, 0x00, 0xfe, 0x1b, 0xf7, 0x00,
11420 0x7a, 0x30, 0x10, 0x68, 0x22, 0x69, 0xd9, 0x6c, 0xda, 0x6d, 0x02, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011421 0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x77,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011422 0x02, 0x01, 0xc6, 0xfe, 0x42, 0x48, 0x4f, 0x50, 0x45, 0x01, 0x08, 0x16,
11423 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xbe, 0x01, 0x08, 0x16, 0xfe, 0xe0, 0x17,
11424 0x27, 0x25, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x03, 0x9a, 0x1e, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011425 0xda, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfe, 0xd0, 0x13, 0x26, 0x53, 0x12,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011426 0x48, 0xfe, 0x08, 0x17, 0xd1, 0x12, 0x53, 0x12, 0xfe, 0x1e, 0x13, 0x2d,
11427 0xb4, 0x7b, 0xfe, 0x26, 0x17, 0x4d, 0x13, 0x07, 0x1c, 0xb4, 0x90, 0x04,
11428 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xf1, 0xff, 0x02, 0x83, 0x55,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011429 0x53, 0x1d, 0xfe, 0x12, 0x13, 0xd6, 0xfe, 0x30, 0x00, 0xb0, 0xfe, 0x80,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011430 0x17, 0x1c, 0x63, 0x13, 0x07, 0xfe, 0x56, 0x10, 0x53, 0x0d, 0xfe, 0x16,
11431 0x13, 0xd6, 0xfe, 0x64, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0x64,
11432 0x00, 0x1c, 0x94, 0x13, 0x07, 0xfe, 0x28, 0x10, 0x53, 0x07, 0xfe, 0x60,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011433 0x13, 0xd6, 0xfe, 0xc8, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0xc8,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011434 0x00, 0x1c, 0x95, 0x13, 0x07, 0x71, 0xd6, 0xfe, 0x90, 0x01, 0x48, 0xfe,
11435 0x8c, 0x17, 0x45, 0xf3, 0xfe, 0x43, 0xf4, 0x96, 0xfe, 0x56, 0xf0, 0xfe,
11436 0x9e, 0x17, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x43, 0xf4, 0x94, 0xf6, 0x8b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011437 0x01, 0xfe, 0x24, 0x16, 0x23, 0x3f, 0xfc, 0xa8, 0x8c, 0x49, 0x48, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011438 0xda, 0x17, 0x62, 0x49, 0xfe, 0x1c, 0x10, 0xa8, 0x8c, 0x80, 0x48, 0xfe,
11439 0xda, 0x17, 0x62, 0x80, 0x71, 0x50, 0x26, 0xfe, 0x4d, 0xf4, 0x00, 0xf7,
11440 0x45, 0x13, 0x07, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x02, 0x50, 0x13,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011441 0x0d, 0x02, 0x50, 0x3e, 0x78, 0x4f, 0x45, 0x01, 0x08, 0x16, 0xa9, 0x27,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011442 0x25, 0xbe, 0xfe, 0x03, 0xea, 0xfe, 0x7e, 0x01, 0x01, 0x08, 0x16, 0xa9,
11443 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe,
11444 0xe9, 0x0a, 0xfe, 0x05, 0xea, 0xfe, 0x7f, 0x01, 0x01, 0x08, 0x16, 0xa9,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011445 0x27, 0x25, 0xfe, 0x69, 0x09, 0xfe, 0x02, 0xea, 0xfe, 0x80, 0x01, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011446 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, 0xe8, 0x08, 0x47, 0xfe, 0x81, 0x01,
11447 0x03, 0xb6, 0x1e, 0x83, 0x01, 0x38, 0x06, 0x24, 0x31, 0xa2, 0x78, 0xf2,
11448 0x53, 0x07, 0x36, 0xfe, 0x34, 0xf4, 0x3f, 0xa1, 0x78, 0x03, 0x9a, 0x1e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011449 0x83, 0x01, 0x38, 0x06, 0x12, 0x31, 0xf0, 0x4f, 0x45, 0xfe, 0x90, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011450 0xfe, 0x40, 0x5a, 0x23, 0x3f, 0xfb, 0x8c, 0x49, 0x48, 0xfe, 0xaa, 0x18,
11451 0x62, 0x49, 0x71, 0x8c, 0x80, 0x48, 0xfe, 0xaa, 0x18, 0x62, 0x80, 0xfe,
11452 0xb4, 0x56, 0xfe, 0x40, 0x5d, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011453 0x02, 0x17, 0xfe, 0xc8, 0x45, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0, 0x18, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011454 0x43, 0x48, 0x2d, 0x93, 0x36, 0xfe, 0x34, 0xf4, 0xfe, 0x00, 0x11, 0xfe,
11455 0x40, 0x10, 0x2d, 0xb4, 0x36, 0xfe, 0x34, 0xf4, 0x04, 0xfe, 0x34, 0x10,
11456 0x2d, 0xfe, 0x0b, 0x00, 0x36, 0x46, 0x63, 0xfe, 0x28, 0x10, 0xfe, 0xc0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011457 0x49, 0xff, 0x02, 0x00, 0x54, 0xb2, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0xfa,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011458 0x18, 0x45, 0xfe, 0x1c, 0xf4, 0x3f, 0xf3, 0xfe, 0x40, 0xf4, 0x96, 0xfe,
11459 0x56, 0xf0, 0xfe, 0x0c, 0x19, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x40, 0xf4,
11460 0x94, 0xf6, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d, 0x21, 0xfe, 0x7f, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011461 0xfe, 0xc8, 0x46, 0xfe, 0x24, 0x13, 0x8c, 0x00, 0x5d, 0x26, 0x21, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011462 0x7e, 0x01, 0xfe, 0xc8, 0x45, 0xfe, 0x14, 0x13, 0x21, 0xfe, 0x80, 0x01,
11463 0xfe, 0x48, 0x45, 0xfa, 0x21, 0xfe, 0x81, 0x01, 0xfe, 0xc8, 0x44, 0x4e,
11464 0x26, 0x02, 0x13, 0x07, 0x02, 0x78, 0x45, 0x50, 0x13, 0x0d, 0x02, 0x14,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011465 0x07, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, 0x0d, 0x01, 0x08, 0x17,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011466 0xfe, 0x82, 0x19, 0x14, 0x1d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x5f,
11467 0xfe, 0x89, 0x49, 0x01, 0x08, 0x02, 0x14, 0x07, 0x01, 0x08, 0x17, 0xc1,
11468 0x14, 0x1d, 0x01, 0x08, 0x17, 0xc1, 0x14, 0x07, 0x01, 0x08, 0x17, 0xc1,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011469 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0xc1, 0x5f, 0xfe, 0x89, 0x4a, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011470 0x08, 0x02, 0x50, 0x02, 0x14, 0x07, 0x01, 0x08, 0x17, 0x74, 0x14, 0x7f,
11471 0x01, 0x08, 0x17, 0x74, 0x14, 0x12, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x89,
11472 0x49, 0x01, 0x08, 0x17, 0x74, 0x14, 0x00, 0x01, 0x08, 0x17, 0x74, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011473 0x89, 0x4a, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x09, 0x49, 0x01, 0x08, 0x17,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011474 0x74, 0x5f, 0xcc, 0x01, 0x08, 0x02, 0x21, 0xe4, 0x09, 0x07, 0xfe, 0x4c,
11475 0x13, 0xc8, 0x20, 0xe4, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x5f, 0xa1, 0x5e,
11476 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xcc, 0xff, 0x02, 0x00, 0x10, 0x2f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011477 0xfe, 0x3e, 0x1a, 0x01, 0x43, 0x09, 0xfe, 0xe3, 0x00, 0xfe, 0x22, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011478 0x16, 0xfe, 0x64, 0x1a, 0x26, 0x20, 0x9e, 0x01, 0x41, 0x21, 0x9e, 0x09,
11479 0x07, 0x5d, 0x01, 0x0c, 0x61, 0x07, 0x44, 0x02, 0x0a, 0x5a, 0x01, 0x18,
11480 0xfe, 0x00, 0x40, 0xaa, 0x09, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011481 0x18, 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x9d, 0x01, 0x18, 0xaa,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011482 0xfe, 0x80, 0xe7, 0x1a, 0x09, 0x1a, 0x5d, 0xfe, 0x45, 0x58, 0x01, 0xfe,
11483 0xb2, 0x16, 0xaa, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0xaa, 0x0a, 0x67, 0x01,
11484 0xa3, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x01, 0xfe, 0x7e, 0x1e, 0xfe, 0x80,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011485 0x4c, 0xfe, 0x49, 0xe4, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, 0x18,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011486 0xfe, 0x80, 0x4c, 0x0a, 0x67, 0x01, 0x5c, 0x02, 0x1c, 0x1a, 0x87, 0x7c,
11487 0xe5, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24, 0x1c, 0xfe, 0x1d,
11488 0xf7, 0x28, 0xb1, 0xfe, 0x04, 0x1b, 0x01, 0xfe, 0x2a, 0x1c, 0xfa, 0xb3,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011489 0x28, 0x7c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x02, 0xc9, 0x2b, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011490 0xf4, 0x1a, 0xfe, 0xfa, 0x10, 0x1c, 0x1a, 0x87, 0x03, 0xfe, 0x64, 0x01,
11491 0xfe, 0x00, 0xf4, 0x24, 0xfe, 0x18, 0x58, 0x03, 0xfe, 0x66, 0x01, 0xfe,
11492 0x19, 0x58, 0xb3, 0x24, 0x01, 0xfe, 0x0e, 0x1f, 0xfe, 0x30, 0xf4, 0x07,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011493 0xfe, 0x3c, 0x50, 0x7c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011494 0xf7, 0x24, 0xb1, 0xfe, 0x50, 0x1b, 0xfe, 0xd4, 0x14, 0x31, 0x02, 0xc9,
11495 0x2b, 0xfe, 0x26, 0x1b, 0xfe, 0xba, 0x10, 0x1c, 0x1a, 0x87, 0xfe, 0x83,
11496 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x54, 0xb1,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011497 0xfe, 0x72, 0x1b, 0xfe, 0xb2, 0x14, 0xfc, 0xb3, 0x54, 0x7c, 0x12, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011498 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00, 0x02, 0xc9, 0x2b, 0xfe, 0x66, 0x1b,
11499 0xfe, 0x8a, 0x10, 0x1c, 0x1a, 0x87, 0x8b, 0x0f, 0xfe, 0x30, 0x90, 0x04,
11500 0xfe, 0xb0, 0x93, 0x3a, 0x0b, 0xfe, 0x18, 0x58, 0xfe, 0x32, 0x90, 0x04,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011501 0xfe, 0xb2, 0x93, 0x3a, 0x0b, 0xfe, 0x19, 0x58, 0x0e, 0xa8, 0xb3, 0x4a,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011502 0x7c, 0x12, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x4a, 0xb1, 0xfe, 0xc6,
11503 0x1b, 0xfe, 0x5e, 0x14, 0x31, 0x02, 0xc9, 0x2b, 0xfe, 0x96, 0x1b, 0x5c,
11504 0xfe, 0x02, 0xf6, 0x1a, 0x87, 0xfe, 0x18, 0xfe, 0x6a, 0xfe, 0x19, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011505 0x6b, 0x01, 0xfe, 0x1e, 0x1f, 0xfe, 0x1d, 0xf7, 0x65, 0xb1, 0xfe, 0xee,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011506 0x1b, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0xb3, 0x65, 0x3e, 0xfe, 0x83,
11507 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x1a, 0xfe, 0x81, 0xe7, 0x1a,
11508 0x15, 0xfe, 0xdd, 0x00, 0x7a, 0x30, 0x02, 0x7a, 0x30, 0xfe, 0x12, 0x45,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011509 0x2b, 0xfe, 0xdc, 0x1b, 0x1f, 0x07, 0x47, 0xb5, 0xc3, 0x05, 0x35, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011510 0x39, 0xf0, 0x75, 0x26, 0x02, 0xfe, 0x7e, 0x18, 0x23, 0x1d, 0x36, 0x13,
11511 0x11, 0x02, 0x87, 0x03, 0xe3, 0x23, 0x07, 0xfe, 0xef, 0x12, 0xfe, 0xe1,
11512 0x10, 0x90, 0x34, 0x60, 0xfe, 0x02, 0x80, 0x09, 0x56, 0xfe, 0x3c, 0x13,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011513 0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x51, 0xfe, 0x06, 0x83, 0x0a, 0x5a,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011514 0x01, 0x18, 0xcb, 0xfe, 0x3e, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48,
11515 0x01, 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f,
11516 0x89, 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x4c, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011517 0x85, 0xfe, 0x16, 0x10, 0x09, 0x9b, 0x4e, 0xfe, 0x40, 0x14, 0xfe, 0x24,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011518 0x12, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x52, 0x1c, 0x1c, 0x0d,
11519 0x02, 0xfe, 0x9c, 0xe7, 0x0d, 0x19, 0xfe, 0x15, 0x00, 0x40, 0x8d, 0x30,
11520 0x01, 0xf4, 0x1c, 0x07, 0x02, 0x51, 0xfe, 0x06, 0x83, 0xfe, 0x18, 0x80,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011521 0x61, 0x28, 0x44, 0x15, 0x56, 0x01, 0x85, 0x1c, 0x07, 0x02, 0xfe, 0x38,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011522 0x90, 0xfe, 0xba, 0x90, 0x91, 0xde, 0x7e, 0xdf, 0xfe, 0x48, 0x55, 0x31,
11523 0xfe, 0xc9, 0x55, 0x02, 0x21, 0xb9, 0x88, 0x20, 0xb9, 0x02, 0x0a, 0xba,
11524 0x01, 0x18, 0xfe, 0x41, 0x48, 0x0a, 0x57, 0x01, 0x18, 0xfe, 0x49, 0x44,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011525 0x1b, 0xfe, 0x1e, 0x1d, 0x88, 0x89, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x09,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011526 0x1a, 0xa4, 0x0a, 0x67, 0x01, 0xa3, 0x0a, 0x57, 0x01, 0x18, 0x88, 0x89,
11527 0x02, 0xfe, 0x4e, 0xe4, 0x1d, 0x7b, 0xfe, 0x52, 0x1d, 0x03, 0xfe, 0x90,
11528 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xdd, 0x7b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011529 0xfe, 0x64, 0x1d, 0x03, 0xfe, 0x92, 0x00, 0xd1, 0x12, 0xfe, 0x1a, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011530 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x7b, 0xfe, 0x76, 0x1d, 0x03, 0xfe,
11531 0x94, 0x00, 0xd1, 0x24, 0xfe, 0x08, 0x10, 0x03, 0xfe, 0x96, 0x00, 0xd1,
11532 0x63, 0xfe, 0x4e, 0x45, 0x83, 0xca, 0xff, 0x04, 0x68, 0x54, 0xfe, 0xf1,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011533 0x10, 0x23, 0x49, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011534 0xfe, 0x1a, 0xf4, 0xfe, 0x00, 0x04, 0x83, 0xb2, 0x1d, 0x48, 0xfe, 0xaa,
11535 0x1d, 0x13, 0x1d, 0x02, 0x09, 0x92, 0xfe, 0x5a, 0xf0, 0xfe, 0xba, 0x1d,
11536 0x2e, 0x93, 0xfe, 0x34, 0x10, 0x09, 0x12, 0xfe, 0x5a, 0xf0, 0xfe, 0xc8,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011537 0x1d, 0x2e, 0xb4, 0xfe, 0x26, 0x10, 0x09, 0x1d, 0x36, 0x2e, 0x63, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011538 0x1a, 0x10, 0x09, 0x0d, 0x36, 0x2e, 0x94, 0xf2, 0x09, 0x07, 0x36, 0x2e,
11539 0x95, 0xa1, 0xc8, 0x02, 0x1f, 0x93, 0x01, 0x42, 0xfe, 0x04, 0xfe, 0x99,
11540 0x03, 0x9c, 0x8b, 0x02, 0x2a, 0xfe, 0x1c, 0x1e, 0xfe, 0x14, 0xf0, 0x08,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011541 0x2f, 0xfe, 0x0c, 0x1e, 0x2a, 0xfe, 0x1c, 0x1e, 0x8f, 0xfe, 0x1c, 0x1e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011542 0xfe, 0x82, 0xf0, 0xfe, 0x10, 0x1e, 0x02, 0x0f, 0x3f, 0x04, 0xfe, 0x80,
11543 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x18, 0x80, 0x04, 0xfe, 0x98,
11544 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x02, 0x80, 0x04, 0xfe, 0x82,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011545 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x80, 0x04, 0xfe, 0x86,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011546 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x1b, 0x80, 0x04, 0xfe, 0x9b,
11547 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x04, 0x80, 0x04, 0xfe, 0x84,
11548 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x80, 0x80, 0x04, 0xfe, 0x80,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011549 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x19, 0x81, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011550 0xfe, 0x99, 0x83, 0xfe, 0xca, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06,
11551 0x83, 0x04, 0xfe, 0x86, 0x83, 0xfe, 0xce, 0x47, 0x0b, 0x0e, 0x02, 0x0f,
11552 0xfe, 0x2c, 0x90, 0x04, 0xfe, 0xac, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011553 0xfe, 0xae, 0x90, 0x04, 0xfe, 0xae, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011554 0xfe, 0x08, 0x90, 0x04, 0xfe, 0x88, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f,
11555 0xfe, 0x8a, 0x90, 0x04, 0xfe, 0x8a, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
11556 0xfe, 0x0c, 0x90, 0x04, 0xfe, 0x8c, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011557 0xfe, 0x8e, 0x90, 0x04, 0xfe, 0x8e, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011558 0xfe, 0x3c, 0x90, 0x04, 0xfe, 0xbc, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x8b,
11559 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b, 0x77, 0x0e,
11560 0xa8, 0x02, 0xff, 0x66, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070011561};
11562
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011563static unsigned short _adv_asc38C1600_size = sizeof(_adv_asc38C1600_buf); /* 0x1673 */
11564static ADV_DCNT _adv_asc38C1600_chksum = 0x0604EF77UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011565
Linus Torvalds1da177e2005-04-16 15:20:36 -070011566/*
11567 * EEPROM Configuration.
11568 *
11569 * All drivers should use this structure to set the default EEPROM
11570 * configuration. The BIOS now uses this structure when it is built.
11571 * Additional structure information can be found in a_condor.h where
11572 * the structure is defined.
11573 *
11574 * The *_Field_IsChar structs are needed to correct for endianness.
11575 * These values are read from the board 16 bits at a time directly
11576 * into the structs. Because some fields are char, the values will be
11577 * in the wrong order. The *_Field_IsChar tells when to flip the
11578 * bytes. Data read and written to PCI memory is automatically swapped
11579 * on big-endian platforms so char fields read as words are actually being
11580 * unswapped on big-endian platforms.
11581 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060011582static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011583 ADV_EEPROM_BIOS_ENABLE, /* cfg_lsw */
11584 0x0000, /* cfg_msw */
11585 0xFFFF, /* disc_enable */
11586 0xFFFF, /* wdtr_able */
11587 0xFFFF, /* sdtr_able */
11588 0xFFFF, /* start_motor */
11589 0xFFFF, /* tagqng_able */
11590 0xFFFF, /* bios_scan */
11591 0, /* scam_tolerant */
11592 7, /* adapter_scsi_id */
11593 0, /* bios_boot_delay */
11594 3, /* scsi_reset_delay */
11595 0, /* bios_id_lun */
11596 0, /* termination */
11597 0, /* reserved1 */
11598 0xFFE7, /* bios_ctrl */
11599 0xFFFF, /* ultra_able */
11600 0, /* reserved2 */
11601 ASC_DEF_MAX_HOST_QNG, /* max_host_qng */
11602 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
11603 0, /* dvc_cntl */
11604 0, /* bug_fix */
11605 0, /* serial_number_word1 */
11606 0, /* serial_number_word2 */
11607 0, /* serial_number_word3 */
11608 0, /* check_sum */
11609 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
11610 , /* oem_name[16] */
11611 0, /* dvc_err_code */
11612 0, /* adv_err_code */
11613 0, /* adv_err_addr */
11614 0, /* saved_dvc_err_code */
11615 0, /* saved_adv_err_code */
11616 0, /* saved_adv_err_addr */
11617 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011618};
11619
Matthew Wilcox78e77d82007-07-29 21:46:15 -060011620static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011621 0, /* cfg_lsw */
11622 0, /* cfg_msw */
11623 0, /* -disc_enable */
11624 0, /* wdtr_able */
11625 0, /* sdtr_able */
11626 0, /* start_motor */
11627 0, /* tagqng_able */
11628 0, /* bios_scan */
11629 0, /* scam_tolerant */
11630 1, /* adapter_scsi_id */
11631 1, /* bios_boot_delay */
11632 1, /* scsi_reset_delay */
11633 1, /* bios_id_lun */
11634 1, /* termination */
11635 1, /* reserved1 */
11636 0, /* bios_ctrl */
11637 0, /* ultra_able */
11638 0, /* reserved2 */
11639 1, /* max_host_qng */
11640 1, /* max_dvc_qng */
11641 0, /* dvc_cntl */
11642 0, /* bug_fix */
11643 0, /* serial_number_word1 */
11644 0, /* serial_number_word2 */
11645 0, /* serial_number_word3 */
11646 0, /* check_sum */
11647 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
11648 , /* oem_name[16] */
11649 0, /* dvc_err_code */
11650 0, /* adv_err_code */
11651 0, /* adv_err_addr */
11652 0, /* saved_dvc_err_code */
11653 0, /* saved_adv_err_code */
11654 0, /* saved_adv_err_addr */
11655 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011656};
11657
Matthew Wilcox78e77d82007-07-29 21:46:15 -060011658static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011659 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
11660 0x0000, /* 01 cfg_msw */
11661 0xFFFF, /* 02 disc_enable */
11662 0xFFFF, /* 03 wdtr_able */
11663 0x4444, /* 04 sdtr_speed1 */
11664 0xFFFF, /* 05 start_motor */
11665 0xFFFF, /* 06 tagqng_able */
11666 0xFFFF, /* 07 bios_scan */
11667 0, /* 08 scam_tolerant */
11668 7, /* 09 adapter_scsi_id */
11669 0, /* bios_boot_delay */
11670 3, /* 10 scsi_reset_delay */
11671 0, /* bios_id_lun */
11672 0, /* 11 termination_se */
11673 0, /* termination_lvd */
11674 0xFFE7, /* 12 bios_ctrl */
11675 0x4444, /* 13 sdtr_speed2 */
11676 0x4444, /* 14 sdtr_speed3 */
11677 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
11678 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
11679 0, /* 16 dvc_cntl */
11680 0x4444, /* 17 sdtr_speed4 */
11681 0, /* 18 serial_number_word1 */
11682 0, /* 19 serial_number_word2 */
11683 0, /* 20 serial_number_word3 */
11684 0, /* 21 check_sum */
11685 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
11686 , /* 22-29 oem_name[16] */
11687 0, /* 30 dvc_err_code */
11688 0, /* 31 adv_err_code */
11689 0, /* 32 adv_err_addr */
11690 0, /* 33 saved_dvc_err_code */
11691 0, /* 34 saved_adv_err_code */
11692 0, /* 35 saved_adv_err_addr */
11693 0, /* 36 reserved */
11694 0, /* 37 reserved */
11695 0, /* 38 reserved */
11696 0, /* 39 reserved */
11697 0, /* 40 reserved */
11698 0, /* 41 reserved */
11699 0, /* 42 reserved */
11700 0, /* 43 reserved */
11701 0, /* 44 reserved */
11702 0, /* 45 reserved */
11703 0, /* 46 reserved */
11704 0, /* 47 reserved */
11705 0, /* 48 reserved */
11706 0, /* 49 reserved */
11707 0, /* 50 reserved */
11708 0, /* 51 reserved */
11709 0, /* 52 reserved */
11710 0, /* 53 reserved */
11711 0, /* 54 reserved */
11712 0, /* 55 reserved */
11713 0, /* 56 cisptr_lsw */
11714 0, /* 57 cisprt_msw */
11715 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
11716 PCI_DEVICE_ID_38C0800_REV1, /* 59 subsysid */
11717 0, /* 60 reserved */
11718 0, /* 61 reserved */
11719 0, /* 62 reserved */
11720 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011721};
11722
Matthew Wilcox78e77d82007-07-29 21:46:15 -060011723static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011724 0, /* 00 cfg_lsw */
11725 0, /* 01 cfg_msw */
11726 0, /* 02 disc_enable */
11727 0, /* 03 wdtr_able */
11728 0, /* 04 sdtr_speed1 */
11729 0, /* 05 start_motor */
11730 0, /* 06 tagqng_able */
11731 0, /* 07 bios_scan */
11732 0, /* 08 scam_tolerant */
11733 1, /* 09 adapter_scsi_id */
11734 1, /* bios_boot_delay */
11735 1, /* 10 scsi_reset_delay */
11736 1, /* bios_id_lun */
11737 1, /* 11 termination_se */
11738 1, /* termination_lvd */
11739 0, /* 12 bios_ctrl */
11740 0, /* 13 sdtr_speed2 */
11741 0, /* 14 sdtr_speed3 */
11742 1, /* 15 max_host_qng */
11743 1, /* max_dvc_qng */
11744 0, /* 16 dvc_cntl */
11745 0, /* 17 sdtr_speed4 */
11746 0, /* 18 serial_number_word1 */
11747 0, /* 19 serial_number_word2 */
11748 0, /* 20 serial_number_word3 */
11749 0, /* 21 check_sum */
11750 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
11751 , /* 22-29 oem_name[16] */
11752 0, /* 30 dvc_err_code */
11753 0, /* 31 adv_err_code */
11754 0, /* 32 adv_err_addr */
11755 0, /* 33 saved_dvc_err_code */
11756 0, /* 34 saved_adv_err_code */
11757 0, /* 35 saved_adv_err_addr */
11758 0, /* 36 reserved */
11759 0, /* 37 reserved */
11760 0, /* 38 reserved */
11761 0, /* 39 reserved */
11762 0, /* 40 reserved */
11763 0, /* 41 reserved */
11764 0, /* 42 reserved */
11765 0, /* 43 reserved */
11766 0, /* 44 reserved */
11767 0, /* 45 reserved */
11768 0, /* 46 reserved */
11769 0, /* 47 reserved */
11770 0, /* 48 reserved */
11771 0, /* 49 reserved */
11772 0, /* 50 reserved */
11773 0, /* 51 reserved */
11774 0, /* 52 reserved */
11775 0, /* 53 reserved */
11776 0, /* 54 reserved */
11777 0, /* 55 reserved */
11778 0, /* 56 cisptr_lsw */
11779 0, /* 57 cisprt_msw */
11780 0, /* 58 subsysvid */
11781 0, /* 59 subsysid */
11782 0, /* 60 reserved */
11783 0, /* 61 reserved */
11784 0, /* 62 reserved */
11785 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011786};
11787
Matthew Wilcox78e77d82007-07-29 21:46:15 -060011788static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011789 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
11790 0x0000, /* 01 cfg_msw */
11791 0xFFFF, /* 02 disc_enable */
11792 0xFFFF, /* 03 wdtr_able */
11793 0x5555, /* 04 sdtr_speed1 */
11794 0xFFFF, /* 05 start_motor */
11795 0xFFFF, /* 06 tagqng_able */
11796 0xFFFF, /* 07 bios_scan */
11797 0, /* 08 scam_tolerant */
11798 7, /* 09 adapter_scsi_id */
11799 0, /* bios_boot_delay */
11800 3, /* 10 scsi_reset_delay */
11801 0, /* bios_id_lun */
11802 0, /* 11 termination_se */
11803 0, /* termination_lvd */
11804 0xFFE7, /* 12 bios_ctrl */
11805 0x5555, /* 13 sdtr_speed2 */
11806 0x5555, /* 14 sdtr_speed3 */
11807 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
11808 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
11809 0, /* 16 dvc_cntl */
11810 0x5555, /* 17 sdtr_speed4 */
11811 0, /* 18 serial_number_word1 */
11812 0, /* 19 serial_number_word2 */
11813 0, /* 20 serial_number_word3 */
11814 0, /* 21 check_sum */
11815 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
11816 , /* 22-29 oem_name[16] */
11817 0, /* 30 dvc_err_code */
11818 0, /* 31 adv_err_code */
11819 0, /* 32 adv_err_addr */
11820 0, /* 33 saved_dvc_err_code */
11821 0, /* 34 saved_adv_err_code */
11822 0, /* 35 saved_adv_err_addr */
11823 0, /* 36 reserved */
11824 0, /* 37 reserved */
11825 0, /* 38 reserved */
11826 0, /* 39 reserved */
11827 0, /* 40 reserved */
11828 0, /* 41 reserved */
11829 0, /* 42 reserved */
11830 0, /* 43 reserved */
11831 0, /* 44 reserved */
11832 0, /* 45 reserved */
11833 0, /* 46 reserved */
11834 0, /* 47 reserved */
11835 0, /* 48 reserved */
11836 0, /* 49 reserved */
11837 0, /* 50 reserved */
11838 0, /* 51 reserved */
11839 0, /* 52 reserved */
11840 0, /* 53 reserved */
11841 0, /* 54 reserved */
11842 0, /* 55 reserved */
11843 0, /* 56 cisptr_lsw */
11844 0, /* 57 cisprt_msw */
11845 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
11846 PCI_DEVICE_ID_38C1600_REV1, /* 59 subsysid */
11847 0, /* 60 reserved */
11848 0, /* 61 reserved */
11849 0, /* 62 reserved */
11850 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011851};
11852
Matthew Wilcox78e77d82007-07-29 21:46:15 -060011853static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011854 0, /* 00 cfg_lsw */
11855 0, /* 01 cfg_msw */
11856 0, /* 02 disc_enable */
11857 0, /* 03 wdtr_able */
11858 0, /* 04 sdtr_speed1 */
11859 0, /* 05 start_motor */
11860 0, /* 06 tagqng_able */
11861 0, /* 07 bios_scan */
11862 0, /* 08 scam_tolerant */
11863 1, /* 09 adapter_scsi_id */
11864 1, /* bios_boot_delay */
11865 1, /* 10 scsi_reset_delay */
11866 1, /* bios_id_lun */
11867 1, /* 11 termination_se */
11868 1, /* termination_lvd */
11869 0, /* 12 bios_ctrl */
11870 0, /* 13 sdtr_speed2 */
11871 0, /* 14 sdtr_speed3 */
11872 1, /* 15 max_host_qng */
11873 1, /* max_dvc_qng */
11874 0, /* 16 dvc_cntl */
11875 0, /* 17 sdtr_speed4 */
11876 0, /* 18 serial_number_word1 */
11877 0, /* 19 serial_number_word2 */
11878 0, /* 20 serial_number_word3 */
11879 0, /* 21 check_sum */
11880 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
11881 , /* 22-29 oem_name[16] */
11882 0, /* 30 dvc_err_code */
11883 0, /* 31 adv_err_code */
11884 0, /* 32 adv_err_addr */
11885 0, /* 33 saved_dvc_err_code */
11886 0, /* 34 saved_adv_err_code */
11887 0, /* 35 saved_adv_err_addr */
11888 0, /* 36 reserved */
11889 0, /* 37 reserved */
11890 0, /* 38 reserved */
11891 0, /* 39 reserved */
11892 0, /* 40 reserved */
11893 0, /* 41 reserved */
11894 0, /* 42 reserved */
11895 0, /* 43 reserved */
11896 0, /* 44 reserved */
11897 0, /* 45 reserved */
11898 0, /* 46 reserved */
11899 0, /* 47 reserved */
11900 0, /* 48 reserved */
11901 0, /* 49 reserved */
11902 0, /* 50 reserved */
11903 0, /* 51 reserved */
11904 0, /* 52 reserved */
11905 0, /* 53 reserved */
11906 0, /* 54 reserved */
11907 0, /* 55 reserved */
11908 0, /* 56 cisptr_lsw */
11909 0, /* 57 cisprt_msw */
11910 0, /* 58 subsysvid */
11911 0, /* 59 subsysid */
11912 0, /* 60 reserved */
11913 0, /* 61 reserved */
11914 0, /* 62 reserved */
11915 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011916};
11917
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060011918#ifdef CONFIG_PCI
Linus Torvalds1da177e2005-04-16 15:20:36 -070011919/*
11920 * Initialize the ADV_DVC_VAR structure.
11921 *
11922 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
11923 *
11924 * For a non-fatal error return a warning code. If there are no warnings
11925 * then 0 is returned.
11926 */
Matthew Wilcox394dbf32007-07-26 11:56:40 -040011927static int __devinit
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060011928AdvInitGetConfig(struct pci_dev *pdev, asc_board_t *boardp)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011929{
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060011930 ADV_DVC_VAR *asc_dvc = &boardp->dvc_var.adv_dvc_var;
Matthew Wilcox9649af32007-07-26 21:51:47 -060011931 unsigned short warn_code = 0;
11932 AdvPortAddr iop_base = asc_dvc->iop_base;
Matthew Wilcox9649af32007-07-26 21:51:47 -060011933 u16 cmd;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011934 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011935
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011936 asc_dvc->err_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011937
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011938 /*
11939 * Save the state of the PCI Configuration Command Register
11940 * "Parity Error Response Control" Bit. If the bit is clear (0),
11941 * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore
11942 * DMA parity errors.
11943 */
11944 asc_dvc->cfg->control_flag = 0;
Matthew Wilcox9649af32007-07-26 21:51:47 -060011945 pci_read_config_word(pdev, PCI_COMMAND, &cmd);
11946 if ((cmd & PCI_COMMAND_PARITY) == 0)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011947 asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011948
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011949 asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) |
11950 ADV_LIB_VERSION_MINOR;
11951 asc_dvc->cfg->chip_version =
11952 AdvGetChipVersion(iop_base, asc_dvc->bus_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011953
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011954 ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: 0x%x 0x%x\n",
11955 (ushort)AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
11956 (ushort)ADV_CHIP_ID_BYTE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011957
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011958 ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: 0x%x 0x%x\n",
11959 (ushort)AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
11960 (ushort)ADV_CHIP_ID_WORD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011961
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011962 /*
11963 * Reset the chip to start and allow register writes.
11964 */
11965 if (AdvFindSignature(iop_base) == 0) {
11966 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
11967 return ADV_ERROR;
11968 } else {
11969 /*
11970 * The caller must set 'chip_type' to a valid setting.
11971 */
11972 if (asc_dvc->chip_type != ADV_CHIP_ASC3550 &&
11973 asc_dvc->chip_type != ADV_CHIP_ASC38C0800 &&
11974 asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
11975 asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
11976 return ADV_ERROR;
11977 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011978
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011979 /*
11980 * Reset Chip.
11981 */
11982 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
11983 ADV_CTRL_REG_CMD_RESET);
11984 DvcSleepMilliSecond(100);
11985 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
11986 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011987
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011988 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
Matthew Wilcox9649af32007-07-26 21:51:47 -060011989 status = AdvInitFrom38C1600EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011990 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
Matthew Wilcox9649af32007-07-26 21:51:47 -060011991 status = AdvInitFrom38C0800EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011992 } else {
Matthew Wilcox9649af32007-07-26 21:51:47 -060011993 status = AdvInitFrom3550EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011994 }
11995 warn_code |= status;
11996 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011997
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060011998 if (warn_code != 0) {
11999 ASC_PRINT2("AdvInitGetConfig: board %d: warning: 0x%x\n",
12000 boardp->id, warn_code);
12001 }
12002
12003 if (asc_dvc->err_code) {
12004 ASC_PRINT2("AdvInitGetConfig: board %d error: err_code 0x%x\n",
12005 boardp->id, asc_dvc->err_code);
12006 }
12007
12008 return asc_dvc->err_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012009}
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060012010#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070012011
Matthew Wilcoxa9f4a592007-09-09 08:56:27 -060012012static void AdvBuildCarrierFreelist(struct adv_dvc_var *asc_dvc)
12013{
12014 ADV_CARR_T *carrp;
12015 ADV_SDCNT buf_size;
12016 ADV_PADDR carr_paddr;
12017
12018 BUG_ON(!asc_dvc->carrier_buf);
12019
12020 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
12021 asc_dvc->carr_freelist = NULL;
12022 if (carrp == asc_dvc->carrier_buf) {
12023 buf_size = ADV_CARRIER_BUFSIZE;
12024 } else {
12025 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
12026 }
12027
12028 do {
12029 /* Get physical address of the carrier 'carrp'. */
12030 ADV_DCNT contig_len = sizeof(ADV_CARR_T);
12031 carr_paddr = cpu_to_le32(DvcGetPhyAddr(asc_dvc, NULL,
12032 (uchar *)carrp,
12033 (ADV_SDCNT *)&contig_len,
12034 ADV_IS_CARRIER_FLAG));
12035
12036 buf_size -= sizeof(ADV_CARR_T);
12037
12038 /*
12039 * If the current carrier is not physically contiguous, then
12040 * maybe there was a page crossing. Try the next carrier
12041 * aligned start address.
12042 */
12043 if (contig_len < sizeof(ADV_CARR_T)) {
12044 carrp++;
12045 continue;
12046 }
12047
12048 carrp->carr_pa = carr_paddr;
12049 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
12050
12051 /*
12052 * Insert the carrier at the beginning of the freelist.
12053 */
12054 carrp->next_vpa =
12055 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
12056 asc_dvc->carr_freelist = carrp;
12057
12058 carrp++;
12059 } while (buf_size > 0);
12060}
12061
Linus Torvalds1da177e2005-04-16 15:20:36 -070012062/*
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012063 * Load the Microcode
12064 *
12065 * Write the microcode image to RISC memory starting at address 0.
12066 *
12067 * The microcode is stored compressed in the following format:
12068 *
12069 * 254 word (508 byte) table indexed by byte code followed
12070 * by the following byte codes:
12071 *
12072 * 1-Byte Code:
12073 * 00: Emit word 0 in table.
12074 * 01: Emit word 1 in table.
12075 * .
12076 * FD: Emit word 253 in table.
12077 *
12078 * Multi-Byte Code:
12079 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
12080 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
12081 *
12082 * Returns 0 or an error if the checksum doesn't match
12083 */
12084static int AdvLoadMicrocode(AdvPortAddr iop_base, unsigned char *buf, int size,
12085 int memsize, int chksum)
12086{
12087 int i, j, end, len = 0;
12088 ADV_DCNT sum;
12089
12090 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
12091
12092 for (i = 253 * 2; i < size; i++) {
12093 if (buf[i] == 0xff) {
12094 unsigned short word = (buf[i + 3] << 8) | buf[i + 2];
12095 for (j = 0; j < buf[i + 1]; j++) {
12096 AdvWriteWordAutoIncLram(iop_base, word);
12097 len += 2;
12098 }
12099 i += 3;
12100 } else if (buf[i] == 0xfe) {
12101 unsigned short word = (buf[i + 2] << 8) | buf[i + 1];
12102 AdvWriteWordAutoIncLram(iop_base, word);
12103 i += 2;
12104 len += 2;
12105 } else {
12106 unsigned char off = buf[i] * 2;
12107 unsigned short word = (buf[off + 1] << 8) | buf[off];
12108 AdvWriteWordAutoIncLram(iop_base, word);
12109 len += 2;
12110 }
12111 }
12112
12113 end = len;
12114
12115 while (len < memsize) {
12116 AdvWriteWordAutoIncLram(iop_base, 0);
12117 len += 2;
12118 }
12119
12120 /* Verify the microcode checksum. */
12121 sum = 0;
12122 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
12123
12124 for (len = 0; len < end; len += 2) {
12125 sum += AdvReadWordAutoIncLram(iop_base);
12126 }
12127
12128 if (sum != chksum)
12129 return ASC_IERR_MCODE_CHKSUM;
12130
12131 return 0;
12132}
12133
12134/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070012135 * Initialize the ASC-3550.
12136 *
12137 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
12138 *
12139 * For a non-fatal error return a warning code. If there are no warnings
12140 * then 0 is returned.
12141 *
12142 * Needed after initialization for error recovery.
12143 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012144static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070012145{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012146 AdvPortAddr iop_base;
12147 ushort warn_code;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012148 int begin_addr;
12149 int end_addr;
12150 ushort code_sum;
12151 int word;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012152 int i;
12153 ushort scsi_cfg1;
12154 uchar tid;
12155 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
12156 ushort wdtr_able = 0, sdtr_able, tagqng_able;
12157 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070012158
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012159 /* If there is already an error, don't continue. */
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012160 if (asc_dvc->err_code != 0)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012161 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012162
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012163 /*
12164 * The caller must set 'chip_type' to ADV_CHIP_ASC3550.
12165 */
12166 if (asc_dvc->chip_type != ADV_CHIP_ASC3550) {
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012167 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012168 return ADV_ERROR;
12169 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012170
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012171 warn_code = 0;
12172 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012173
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012174 /*
12175 * Save the RISC memory BIOS region before writing the microcode.
12176 * The BIOS may already be loaded and using its RISC LRAM region
12177 * so its region must be saved and restored.
12178 *
12179 * Note: This code makes the assumption, which is currently true,
12180 * that a chip reset does not clear RISC LRAM.
12181 */
12182 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
12183 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
12184 bios_mem[i]);
12185 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012186
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012187 /*
12188 * Save current per TID negotiated values.
12189 */
12190 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == 0x55AA) {
12191 ushort bios_version, major, minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012192
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012193 bios_version =
12194 bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM) / 2];
12195 major = (bios_version >> 12) & 0xF;
12196 minor = (bios_version >> 8) & 0xF;
12197 if (major < 3 || (major == 3 && minor == 1)) {
12198 /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
12199 AdvReadWordLram(iop_base, 0x120, wdtr_able);
12200 } else {
12201 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
12202 }
12203 }
12204 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
12205 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
12206 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
12207 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
12208 max_cmd[tid]);
12209 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012210
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012211 asc_dvc->err_code = AdvLoadMicrocode(iop_base, _adv_asc3550_buf,
12212 _adv_asc3550_size, ADV_3550_MEMSIZE,
12213 _adv_asc3550_chksum);
12214 if (asc_dvc->err_code)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012215 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012216
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012217 /*
12218 * Restore the RISC memory BIOS region.
12219 */
12220 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
12221 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
12222 bios_mem[i]);
12223 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012224
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012225 /*
12226 * Calculate and write the microcode code checksum to the microcode
12227 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
12228 */
12229 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
12230 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
12231 code_sum = 0;
12232 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
12233 for (word = begin_addr; word < end_addr; word += 2) {
12234 code_sum += AdvReadWordAutoIncLram(iop_base);
12235 }
12236 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012237
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012238 /*
12239 * Read and save microcode version and date.
12240 */
12241 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
12242 asc_dvc->cfg->mcode_date);
12243 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
12244 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012245
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012246 /*
12247 * Set the chip type to indicate the ASC3550.
12248 */
12249 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012250
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012251 /*
12252 * If the PCI Configuration Command Register "Parity Error Response
12253 * Control" Bit was clear (0), then set the microcode variable
12254 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
12255 * to ignore DMA parity errors.
12256 */
12257 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
12258 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
12259 word |= CONTROL_FLAG_IGNORE_PERR;
12260 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
12261 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012262
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012263 /*
12264 * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
12265 * threshold of 128 bytes. This register is only accessible to the host.
12266 */
12267 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
12268 START_CTL_EMFU | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012269
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012270 /*
12271 * Microcode operating variables for WDTR, SDTR, and command tag
Matthew Wilcox47d853c2007-07-26 11:41:33 -040012272 * queuing will be set in slave_configure() based on what a
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012273 * device reports it is capable of in Inquiry byte 7.
12274 *
12275 * If SCSI Bus Resets have been disabled, then directly set
12276 * SDTR and WDTR from the EEPROM configuration. This will allow
12277 * the BIOS and warm boot to work without a SCSI bus hang on
12278 * the Inquiry caused by host and target mismatched DTR values.
12279 * Without the SCSI Bus Reset, before an Inquiry a device can't
12280 * be assumed to be in Asynchronous, Narrow mode.
12281 */
12282 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
12283 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
12284 asc_dvc->wdtr_able);
12285 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
12286 asc_dvc->sdtr_able);
12287 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012288
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012289 /*
12290 * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
12291 * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
12292 * bitmask. These values determine the maximum SDTR speed negotiated
12293 * with a device.
12294 *
12295 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
12296 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
12297 * without determining here whether the device supports SDTR.
12298 *
12299 * 4-bit speed SDTR speed name
12300 * =========== ===============
12301 * 0000b (0x0) SDTR disabled
12302 * 0001b (0x1) 5 Mhz
12303 * 0010b (0x2) 10 Mhz
12304 * 0011b (0x3) 20 Mhz (Ultra)
12305 * 0100b (0x4) 40 Mhz (LVD/Ultra2)
12306 * 0101b (0x5) 80 Mhz (LVD2/Ultra3)
12307 * 0110b (0x6) Undefined
12308 * .
12309 * 1111b (0xF) Undefined
12310 */
12311 word = 0;
12312 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
12313 if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) {
12314 /* Set Ultra speed for TID 'tid'. */
12315 word |= (0x3 << (4 * (tid % 4)));
12316 } else {
12317 /* Set Fast speed for TID 'tid'. */
12318 word |= (0x2 << (4 * (tid % 4)));
12319 }
12320 if (tid == 3) { /* Check if done with sdtr_speed1. */
12321 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
12322 word = 0;
12323 } else if (tid == 7) { /* Check if done with sdtr_speed2. */
12324 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
12325 word = 0;
12326 } else if (tid == 11) { /* Check if done with sdtr_speed3. */
12327 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
12328 word = 0;
12329 } else if (tid == 15) { /* Check if done with sdtr_speed4. */
12330 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
12331 /* End of loop. */
12332 }
12333 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012334
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012335 /*
12336 * Set microcode operating variable for the disconnect per TID bitmask.
12337 */
12338 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
12339 asc_dvc->cfg->disc_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012340
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012341 /*
12342 * Set SCSI_CFG0 Microcode Default Value.
12343 *
12344 * The microcode will set the SCSI_CFG0 register using this value
12345 * after it is started below.
12346 */
12347 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
12348 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
12349 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012350
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012351 /*
12352 * Determine SCSI_CFG1 Microcode Default Value.
12353 *
12354 * The microcode will set the SCSI_CFG1 register using this value
12355 * after it is started below.
12356 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012357
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012358 /* Read current SCSI_CFG1 Register value. */
12359 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012360
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012361 /*
12362 * If all three connectors are in use, return an error.
12363 */
12364 if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
12365 (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) {
12366 asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
12367 return ADV_ERROR;
12368 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012369
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012370 /*
12371 * If the internal narrow cable is reversed all of the SCSI_CTRL
12372 * register signals will be set. Check for and return an error if
12373 * this condition is found.
12374 */
12375 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
12376 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
12377 return ADV_ERROR;
12378 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012379
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012380 /*
12381 * If this is a differential board and a single-ended device
12382 * is attached to one of the connectors, return an error.
12383 */
12384 if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) {
12385 asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE;
12386 return ADV_ERROR;
12387 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012388
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012389 /*
12390 * If automatic termination control is enabled, then set the
12391 * termination value based on a table listed in a_condor.h.
12392 *
12393 * If manual termination was specified with an EEPROM setting
12394 * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
12395 * is ready to be 'ored' into SCSI_CFG1.
12396 */
12397 if (asc_dvc->cfg->termination == 0) {
12398 /*
12399 * The software always controls termination by setting TERM_CTL_SEL.
12400 * If TERM_CTL_SEL were set to 0, the hardware would set termination.
12401 */
12402 asc_dvc->cfg->termination |= TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012403
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012404 switch (scsi_cfg1 & CABLE_DETECT) {
12405 /* TERM_CTL_H: on, TERM_CTL_L: on */
12406 case 0x3:
12407 case 0x7:
12408 case 0xB:
12409 case 0xD:
12410 case 0xE:
12411 case 0xF:
12412 asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L);
12413 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012414
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012415 /* TERM_CTL_H: on, TERM_CTL_L: off */
12416 case 0x1:
12417 case 0x5:
12418 case 0x9:
12419 case 0xA:
12420 case 0xC:
12421 asc_dvc->cfg->termination |= TERM_CTL_H;
12422 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012423
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012424 /* TERM_CTL_H: off, TERM_CTL_L: off */
12425 case 0x2:
12426 case 0x6:
12427 break;
12428 }
12429 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012430
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012431 /*
12432 * Clear any set TERM_CTL_H and TERM_CTL_L bits.
12433 */
12434 scsi_cfg1 &= ~TERM_CTL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012435
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012436 /*
12437 * Invert the TERM_CTL_H and TERM_CTL_L bits and then
12438 * set 'scsi_cfg1'. The TERM_POL bit does not need to be
12439 * referenced, because the hardware internally inverts
12440 * the Termination High and Low bits if TERM_POL is set.
12441 */
12442 scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012443
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012444 /*
12445 * Set SCSI_CFG1 Microcode Default Value
12446 *
12447 * Set filter value and possibly modified termination control
12448 * bits in the Microcode SCSI_CFG1 Register Value.
12449 *
12450 * The microcode will set the SCSI_CFG1 register using this value
12451 * after it is started below.
12452 */
12453 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
12454 FLTR_DISABLE | scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012455
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012456 /*
12457 * Set MEM_CFG Microcode Default Value
12458 *
12459 * The microcode will set the MEM_CFG register using this value
12460 * after it is started below.
12461 *
12462 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
12463 * are defined.
12464 *
12465 * ASC-3550 has 8KB internal memory.
12466 */
12467 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
12468 BIOS_EN | RAM_SZ_8KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012469
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012470 /*
12471 * Set SEL_MASK Microcode Default Value
12472 *
12473 * The microcode will set the SEL_MASK register using this value
12474 * after it is started below.
12475 */
12476 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
12477 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012478
Matthew Wilcoxa9f4a592007-09-09 08:56:27 -060012479 AdvBuildCarrierFreelist(asc_dvc);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012480
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012481 /*
12482 * Set-up the Host->RISC Initiator Command Queue (ICQ).
12483 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012484
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012485 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
12486 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
12487 return ADV_ERROR;
12488 }
12489 asc_dvc->carr_freelist = (ADV_CARR_T *)
12490 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012491
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012492 /*
12493 * The first command issued will be placed in the stopper carrier.
12494 */
12495 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012496
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012497 /*
12498 * Set RISC ICQ physical address start value.
12499 */
12500 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012501
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012502 /*
12503 * Set-up the RISC->Host Initiator Response Queue (IRQ).
12504 */
12505 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
12506 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
12507 return ADV_ERROR;
12508 }
12509 asc_dvc->carr_freelist = (ADV_CARR_T *)
12510 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012511
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012512 /*
12513 * The first command completed by the RISC will be placed in
12514 * the stopper.
12515 *
12516 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
12517 * completed the RISC will set the ASC_RQ_STOPPER bit.
12518 */
12519 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012520
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012521 /*
12522 * Set RISC IRQ physical address start value.
12523 */
12524 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
12525 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012526
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012527 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
12528 (ADV_INTR_ENABLE_HOST_INTR |
12529 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012530
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012531 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
12532 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012533
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012534 /* finally, finally, gentlemen, start your engine */
12535 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012536
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012537 /*
12538 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
12539 * Resets should be performed. The RISC has to be running
12540 * to issue a SCSI Bus Reset.
12541 */
12542 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
12543 /*
12544 * If the BIOS Signature is present in memory, restore the
12545 * BIOS Handshake Configuration Table and do not perform
12546 * a SCSI Bus Reset.
12547 */
12548 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
12549 0x55AA) {
12550 /*
12551 * Restore per TID negotiated values.
12552 */
12553 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
12554 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
12555 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
12556 tagqng_able);
12557 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
12558 AdvWriteByteLram(iop_base,
12559 ASC_MC_NUMBER_OF_MAX_CMD + tid,
12560 max_cmd[tid]);
12561 }
12562 } else {
12563 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
12564 warn_code = ASC_WARN_BUSRESET_ERROR;
12565 }
12566 }
12567 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012568
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012569 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012570}
12571
12572/*
12573 * Initialize the ASC-38C0800.
12574 *
12575 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
12576 *
12577 * For a non-fatal error return a warning code. If there are no warnings
12578 * then 0 is returned.
12579 *
12580 * Needed after initialization for error recovery.
12581 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012582static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070012583{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012584 AdvPortAddr iop_base;
12585 ushort warn_code;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012586 int begin_addr;
12587 int end_addr;
12588 ushort code_sum;
12589 int word;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012590 int i;
12591 ushort scsi_cfg1;
12592 uchar byte;
12593 uchar tid;
12594 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
12595 ushort wdtr_able, sdtr_able, tagqng_able;
12596 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070012597
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012598 /* If there is already an error, don't continue. */
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012599 if (asc_dvc->err_code != 0)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012600 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012601
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012602 /*
12603 * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
12604 */
12605 if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) {
12606 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
12607 return ADV_ERROR;
12608 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012609
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012610 warn_code = 0;
12611 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012612
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012613 /*
12614 * Save the RISC memory BIOS region before writing the microcode.
12615 * The BIOS may already be loaded and using its RISC LRAM region
12616 * so its region must be saved and restored.
12617 *
12618 * Note: This code makes the assumption, which is currently true,
12619 * that a chip reset does not clear RISC LRAM.
12620 */
12621 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
12622 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
12623 bios_mem[i]);
12624 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012625
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012626 /*
12627 * Save current per TID negotiated values.
12628 */
12629 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
12630 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
12631 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
12632 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
12633 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
12634 max_cmd[tid]);
12635 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012636
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012637 /*
12638 * RAM BIST (RAM Built-In Self Test)
12639 *
12640 * Address : I/O base + offset 0x38h register (byte).
12641 * Function: Bit 7-6(RW) : RAM mode
12642 * Normal Mode : 0x00
12643 * Pre-test Mode : 0x40
12644 * RAM Test Mode : 0x80
12645 * Bit 5 : unused
12646 * Bit 4(RO) : Done bit
12647 * Bit 3-0(RO) : Status
12648 * Host Error : 0x08
12649 * Int_RAM Error : 0x04
12650 * RISC Error : 0x02
12651 * SCSI Error : 0x01
12652 * No Error : 0x00
12653 *
12654 * Note: RAM BIST code should be put right here, before loading the
12655 * microcode and after saving the RISC memory BIOS region.
12656 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012657
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012658 /*
12659 * LRAM Pre-test
12660 *
12661 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
12662 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
12663 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
12664 * to NORMAL_MODE, return an error too.
12665 */
12666 for (i = 0; i < 2; i++) {
12667 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
12668 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
12669 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
12670 if ((byte & RAM_TEST_DONE) == 0
12671 || (byte & 0x0F) != PRE_TEST_VALUE) {
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012672 asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012673 return ADV_ERROR;
12674 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012675
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012676 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
12677 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
12678 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
12679 != NORMAL_VALUE) {
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012680 asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012681 return ADV_ERROR;
12682 }
12683 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012684
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012685 /*
12686 * LRAM Test - It takes about 1.5 ms to run through the test.
12687 *
12688 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
12689 * If Done bit not set or Status not 0, save register byte, set the
12690 * err_code, and return an error.
12691 */
12692 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
12693 DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012694
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012695 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
12696 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
12697 /* Get here if Done bit not set or Status not 0. */
12698 asc_dvc->bist_err_code = byte; /* for BIOS display message */
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012699 asc_dvc->err_code = ASC_IERR_BIST_RAM_TEST;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012700 return ADV_ERROR;
12701 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012702
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012703 /* We need to reset back to normal mode after LRAM test passes. */
12704 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012705
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012706 asc_dvc->err_code = AdvLoadMicrocode(iop_base, _adv_asc38C0800_buf,
12707 _adv_asc38C0800_size, ADV_38C0800_MEMSIZE,
12708 _adv_asc38C0800_chksum);
12709 if (asc_dvc->err_code)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012710 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012711
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012712 /*
12713 * Restore the RISC memory BIOS region.
12714 */
12715 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
12716 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
12717 bios_mem[i]);
12718 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012719
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012720 /*
12721 * Calculate and write the microcode code checksum to the microcode
12722 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
12723 */
12724 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
12725 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
12726 code_sum = 0;
12727 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
12728 for (word = begin_addr; word < end_addr; word += 2) {
12729 code_sum += AdvReadWordAutoIncLram(iop_base);
12730 }
12731 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012732
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012733 /*
12734 * Read microcode version and date.
12735 */
12736 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
12737 asc_dvc->cfg->mcode_date);
12738 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
12739 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012740
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012741 /*
12742 * Set the chip type to indicate the ASC38C0800.
12743 */
12744 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012745
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012746 /*
12747 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
12748 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
12749 * cable detection and then we are able to read C_DET[3:0].
12750 *
12751 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
12752 * Microcode Default Value' section below.
12753 */
12754 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
12755 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
12756 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012757
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012758 /*
12759 * If the PCI Configuration Command Register "Parity Error Response
12760 * Control" Bit was clear (0), then set the microcode variable
12761 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
12762 * to ignore DMA parity errors.
12763 */
12764 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
12765 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
12766 word |= CONTROL_FLAG_IGNORE_PERR;
12767 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
12768 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012769
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012770 /*
12771 * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
12772 * bits for the default FIFO threshold.
12773 *
12774 * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
12775 *
12776 * For DMA Errata #4 set the BC_THRESH_ENB bit.
12777 */
12778 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
12779 BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH |
12780 READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012781
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012782 /*
12783 * Microcode operating variables for WDTR, SDTR, and command tag
Matthew Wilcox47d853c2007-07-26 11:41:33 -040012784 * queuing will be set in slave_configure() based on what a
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012785 * device reports it is capable of in Inquiry byte 7.
12786 *
12787 * If SCSI Bus Resets have been disabled, then directly set
12788 * SDTR and WDTR from the EEPROM configuration. This will allow
12789 * the BIOS and warm boot to work without a SCSI bus hang on
12790 * the Inquiry caused by host and target mismatched DTR values.
12791 * Without the SCSI Bus Reset, before an Inquiry a device can't
12792 * be assumed to be in Asynchronous, Narrow mode.
12793 */
12794 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
12795 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
12796 asc_dvc->wdtr_able);
12797 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
12798 asc_dvc->sdtr_able);
12799 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012800
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012801 /*
12802 * Set microcode operating variables for DISC and SDTR_SPEED1,
12803 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
12804 * configuration values.
12805 *
12806 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
12807 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
12808 * without determining here whether the device supports SDTR.
12809 */
12810 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
12811 asc_dvc->cfg->disc_enable);
12812 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
12813 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
12814 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
12815 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012816
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012817 /*
12818 * Set SCSI_CFG0 Microcode Default Value.
12819 *
12820 * The microcode will set the SCSI_CFG0 register using this value
12821 * after it is started below.
12822 */
12823 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
12824 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
12825 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012826
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012827 /*
12828 * Determine SCSI_CFG1 Microcode Default Value.
12829 *
12830 * The microcode will set the SCSI_CFG1 register using this value
12831 * after it is started below.
12832 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012833
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012834 /* Read current SCSI_CFG1 Register value. */
12835 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012836
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012837 /*
12838 * If the internal narrow cable is reversed all of the SCSI_CTRL
12839 * register signals will be set. Check for and return an error if
12840 * this condition is found.
12841 */
12842 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
12843 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
12844 return ADV_ERROR;
12845 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012846
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012847 /*
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012848 * All kind of combinations of devices attached to one of four
12849 * connectors are acceptable except HVD device attached. For example,
12850 * LVD device can be attached to SE connector while SE device attached
12851 * to LVD connector. If LVD device attached to SE connector, it only
12852 * runs up to Ultra speed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012853 *
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012854 * If an HVD device is attached to one of LVD connectors, return an
12855 * error. However, there is no way to detect HVD device attached to
12856 * SE connectors.
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012857 */
12858 if (scsi_cfg1 & HVD) {
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012859 asc_dvc->err_code = ASC_IERR_HVD_DEVICE;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012860 return ADV_ERROR;
12861 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012862
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012863 /*
12864 * If either SE or LVD automatic termination control is enabled, then
12865 * set the termination value based on a table listed in a_condor.h.
12866 *
12867 * If manual termination was specified with an EEPROM setting then
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012868 * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready
12869 * to be 'ored' into SCSI_CFG1.
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012870 */
12871 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
12872 /* SE automatic termination control is enabled. */
12873 switch (scsi_cfg1 & C_DET_SE) {
12874 /* TERM_SE_HI: on, TERM_SE_LO: on */
12875 case 0x1:
12876 case 0x2:
12877 case 0x3:
12878 asc_dvc->cfg->termination |= TERM_SE;
12879 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012880
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012881 /* TERM_SE_HI: on, TERM_SE_LO: off */
12882 case 0x0:
12883 asc_dvc->cfg->termination |= TERM_SE_HI;
12884 break;
12885 }
12886 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012887
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012888 if ((asc_dvc->cfg->termination & TERM_LVD) == 0) {
12889 /* LVD automatic termination control is enabled. */
12890 switch (scsi_cfg1 & C_DET_LVD) {
12891 /* TERM_LVD_HI: on, TERM_LVD_LO: on */
12892 case 0x4:
12893 case 0x8:
12894 case 0xC:
12895 asc_dvc->cfg->termination |= TERM_LVD;
12896 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012897
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012898 /* TERM_LVD_HI: off, TERM_LVD_LO: off */
12899 case 0x0:
12900 break;
12901 }
12902 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012903
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012904 /*
12905 * Clear any set TERM_SE and TERM_LVD bits.
12906 */
12907 scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012908
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012909 /*
12910 * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
12911 */
12912 scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012913
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012914 /*
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012915 * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE
12916 * bits and set possibly modified termination control bits in the
12917 * Microcode SCSI_CFG1 Register Value.
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012918 */
12919 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012920
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012921 /*
12922 * Set SCSI_CFG1 Microcode Default Value
12923 *
12924 * Set possibly modified termination control and reset DIS_TERM_DRV
12925 * bits in the Microcode SCSI_CFG1 Register Value.
12926 *
12927 * The microcode will set the SCSI_CFG1 register using this value
12928 * after it is started below.
12929 */
12930 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012931
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012932 /*
12933 * Set MEM_CFG Microcode Default Value
12934 *
12935 * The microcode will set the MEM_CFG register using this value
12936 * after it is started below.
12937 *
12938 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
12939 * are defined.
12940 *
12941 * ASC-38C0800 has 16KB internal memory.
12942 */
12943 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
12944 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012945
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012946 /*
12947 * Set SEL_MASK Microcode Default Value
12948 *
12949 * The microcode will set the SEL_MASK register using this value
12950 * after it is started below.
12951 */
12952 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
12953 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012954
Matthew Wilcoxa9f4a592007-09-09 08:56:27 -060012955 AdvBuildCarrierFreelist(asc_dvc);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012956
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012957 /*
12958 * Set-up the Host->RISC Initiator Command Queue (ICQ).
12959 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012960
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012961 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
12962 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
12963 return ADV_ERROR;
12964 }
12965 asc_dvc->carr_freelist = (ADV_CARR_T *)
12966 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012967
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012968 /*
12969 * The first command issued will be placed in the stopper carrier.
12970 */
12971 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012972
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012973 /*
12974 * Set RISC ICQ physical address start value.
12975 * carr_pa is LE, must be native before write
12976 */
12977 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012978
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012979 /*
12980 * Set-up the RISC->Host Initiator Response Queue (IRQ).
12981 */
12982 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
12983 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
12984 return ADV_ERROR;
12985 }
12986 asc_dvc->carr_freelist = (ADV_CARR_T *)
12987 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012988
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012989 /*
12990 * The first command completed by the RISC will be placed in
12991 * the stopper.
12992 *
12993 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
12994 * completed the RISC will set the ASC_RQ_STOPPER bit.
12995 */
12996 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012997
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012998 /*
12999 * Set RISC IRQ physical address start value.
13000 *
13001 * carr_pa is LE, must be native before write *
13002 */
13003 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
13004 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013005
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013006 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
13007 (ADV_INTR_ENABLE_HOST_INTR |
13008 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013009
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013010 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
13011 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013012
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013013 /* finally, finally, gentlemen, start your engine */
13014 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013015
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013016 /*
13017 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
13018 * Resets should be performed. The RISC has to be running
13019 * to issue a SCSI Bus Reset.
13020 */
13021 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
13022 /*
13023 * If the BIOS Signature is present in memory, restore the
13024 * BIOS Handshake Configuration Table and do not perform
13025 * a SCSI Bus Reset.
13026 */
13027 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
13028 0x55AA) {
13029 /*
13030 * Restore per TID negotiated values.
13031 */
13032 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
13033 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
13034 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
13035 tagqng_able);
13036 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
13037 AdvWriteByteLram(iop_base,
13038 ASC_MC_NUMBER_OF_MAX_CMD + tid,
13039 max_cmd[tid]);
13040 }
13041 } else {
13042 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
13043 warn_code = ASC_WARN_BUSRESET_ERROR;
13044 }
13045 }
13046 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013047
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013048 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013049}
13050
13051/*
13052 * Initialize the ASC-38C1600.
13053 *
13054 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
13055 *
13056 * For a non-fatal error return a warning code. If there are no warnings
13057 * then 0 is returned.
13058 *
13059 * Needed after initialization for error recovery.
13060 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013061static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013062{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013063 AdvPortAddr iop_base;
13064 ushort warn_code;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013065 int begin_addr;
13066 int end_addr;
13067 ushort code_sum;
13068 long word;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013069 int i;
13070 ushort scsi_cfg1;
13071 uchar byte;
13072 uchar tid;
13073 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
13074 ushort wdtr_able, sdtr_able, ppr_able, tagqng_able;
13075 uchar max_cmd[ASC_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070013076
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013077 /* If there is already an error, don't continue. */
13078 if (asc_dvc->err_code != 0) {
13079 return ADV_ERROR;
13080 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013081
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013082 /*
13083 * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600.
13084 */
13085 if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
13086 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
13087 return ADV_ERROR;
13088 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013089
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013090 warn_code = 0;
13091 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013092
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013093 /*
13094 * Save the RISC memory BIOS region before writing the microcode.
13095 * The BIOS may already be loaded and using its RISC LRAM region
13096 * so its region must be saved and restored.
13097 *
13098 * Note: This code makes the assumption, which is currently true,
13099 * that a chip reset does not clear RISC LRAM.
13100 */
13101 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
13102 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
13103 bios_mem[i]);
13104 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013105
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013106 /*
13107 * Save current per TID negotiated values.
13108 */
13109 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
13110 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
13111 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
13112 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
13113 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
13114 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
13115 max_cmd[tid]);
13116 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013117
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013118 /*
13119 * RAM BIST (Built-In Self Test)
13120 *
13121 * Address : I/O base + offset 0x38h register (byte).
13122 * Function: Bit 7-6(RW) : RAM mode
13123 * Normal Mode : 0x00
13124 * Pre-test Mode : 0x40
13125 * RAM Test Mode : 0x80
13126 * Bit 5 : unused
13127 * Bit 4(RO) : Done bit
13128 * Bit 3-0(RO) : Status
13129 * Host Error : 0x08
13130 * Int_RAM Error : 0x04
13131 * RISC Error : 0x02
13132 * SCSI Error : 0x01
13133 * No Error : 0x00
13134 *
13135 * Note: RAM BIST code should be put right here, before loading the
13136 * microcode and after saving the RISC memory BIOS region.
13137 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013138
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013139 /*
13140 * LRAM Pre-test
13141 *
13142 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
13143 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
13144 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
13145 * to NORMAL_MODE, return an error too.
13146 */
13147 for (i = 0; i < 2; i++) {
13148 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
13149 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
13150 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
13151 if ((byte & RAM_TEST_DONE) == 0
13152 || (byte & 0x0F) != PRE_TEST_VALUE) {
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060013153 asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013154 return ADV_ERROR;
13155 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013156
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013157 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
13158 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
13159 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
13160 != NORMAL_VALUE) {
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060013161 asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013162 return ADV_ERROR;
13163 }
13164 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013165
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013166 /*
13167 * LRAM Test - It takes about 1.5 ms to run through the test.
13168 *
13169 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
13170 * If Done bit not set or Status not 0, save register byte, set the
13171 * err_code, and return an error.
13172 */
13173 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
13174 DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013175
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013176 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
13177 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
13178 /* Get here if Done bit not set or Status not 0. */
13179 asc_dvc->bist_err_code = byte; /* for BIOS display message */
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060013180 asc_dvc->err_code = ASC_IERR_BIST_RAM_TEST;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013181 return ADV_ERROR;
13182 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013183
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013184 /* We need to reset back to normal mode after LRAM test passes. */
13185 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013186
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060013187 asc_dvc->err_code = AdvLoadMicrocode(iop_base, _adv_asc38C1600_buf,
13188 _adv_asc38C1600_size, ADV_38C1600_MEMSIZE,
13189 _adv_asc38C1600_chksum);
13190 if (asc_dvc->err_code)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013191 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013192
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013193 /*
13194 * Restore the RISC memory BIOS region.
13195 */
13196 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
13197 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
13198 bios_mem[i]);
13199 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013200
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013201 /*
13202 * Calculate and write the microcode code checksum to the microcode
13203 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
13204 */
13205 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
13206 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
13207 code_sum = 0;
13208 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
13209 for (word = begin_addr; word < end_addr; word += 2) {
13210 code_sum += AdvReadWordAutoIncLram(iop_base);
13211 }
13212 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013213
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013214 /*
13215 * Read microcode version and date.
13216 */
13217 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
13218 asc_dvc->cfg->mcode_date);
13219 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
13220 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013221
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013222 /*
13223 * Set the chip type to indicate the ASC38C1600.
13224 */
13225 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013226
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013227 /*
13228 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
13229 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
13230 * cable detection and then we are able to read C_DET[3:0].
13231 *
13232 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
13233 * Microcode Default Value' section below.
13234 */
13235 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
13236 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
13237 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013238
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013239 /*
13240 * If the PCI Configuration Command Register "Parity Error Response
13241 * Control" Bit was clear (0), then set the microcode variable
13242 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
13243 * to ignore DMA parity errors.
13244 */
13245 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
13246 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
13247 word |= CONTROL_FLAG_IGNORE_PERR;
13248 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
13249 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013250
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013251 /*
13252 * If the BIOS control flag AIPP (Asynchronous Information
13253 * Phase Protection) disable bit is not set, then set the firmware
13254 * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable
13255 * AIPP checking and encoding.
13256 */
13257 if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) {
13258 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
13259 word |= CONTROL_FLAG_ENABLE_AIPP;
13260 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
13261 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013262
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013263 /*
13264 * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4],
13265 * and START_CTL_TH [3:2].
13266 */
13267 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
13268 FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013269
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013270 /*
13271 * Microcode operating variables for WDTR, SDTR, and command tag
Matthew Wilcox47d853c2007-07-26 11:41:33 -040013272 * queuing will be set in slave_configure() based on what a
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013273 * device reports it is capable of in Inquiry byte 7.
13274 *
13275 * If SCSI Bus Resets have been disabled, then directly set
13276 * SDTR and WDTR from the EEPROM configuration. This will allow
13277 * the BIOS and warm boot to work without a SCSI bus hang on
13278 * the Inquiry caused by host and target mismatched DTR values.
13279 * Without the SCSI Bus Reset, before an Inquiry a device can't
13280 * be assumed to be in Asynchronous, Narrow mode.
13281 */
13282 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
13283 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
13284 asc_dvc->wdtr_able);
13285 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
13286 asc_dvc->sdtr_able);
13287 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013288
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013289 /*
13290 * Set microcode operating variables for DISC and SDTR_SPEED1,
13291 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
13292 * configuration values.
13293 *
13294 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
13295 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
13296 * without determining here whether the device supports SDTR.
13297 */
13298 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
13299 asc_dvc->cfg->disc_enable);
13300 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
13301 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
13302 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
13303 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013304
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013305 /*
13306 * Set SCSI_CFG0 Microcode Default Value.
13307 *
13308 * The microcode will set the SCSI_CFG0 register using this value
13309 * after it is started below.
13310 */
13311 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
13312 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
13313 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013314
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013315 /*
13316 * Calculate SCSI_CFG1 Microcode Default Value.
13317 *
13318 * The microcode will set the SCSI_CFG1 register using this value
13319 * after it is started below.
13320 *
13321 * Each ASC-38C1600 function has only two cable detect bits.
13322 * The bus mode override bits are in IOPB_SOFT_OVER_WR.
13323 */
13324 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013325
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013326 /*
13327 * If the cable is reversed all of the SCSI_CTRL register signals
13328 * will be set. Check for and return an error if this condition is
13329 * found.
13330 */
13331 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
13332 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
13333 return ADV_ERROR;
13334 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013335
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013336 /*
13337 * Each ASC-38C1600 function has two connectors. Only an HVD device
13338 * can not be connected to either connector. An LVD device or SE device
13339 * may be connected to either connecor. If an SE device is connected,
13340 * then at most Ultra speed (20 Mhz) can be used on both connectors.
13341 *
13342 * If an HVD device is attached, return an error.
13343 */
13344 if (scsi_cfg1 & HVD) {
13345 asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
13346 return ADV_ERROR;
13347 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013348
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013349 /*
13350 * Each function in the ASC-38C1600 uses only the SE cable detect and
13351 * termination because there are two connectors for each function. Each
13352 * function may use either LVD or SE mode. Corresponding the SE automatic
13353 * termination control EEPROM bits are used for each function. Each
13354 * function has its own EEPROM. If SE automatic control is enabled for
13355 * the function, then set the termination value based on a table listed
13356 * in a_condor.h.
13357 *
13358 * If manual termination is specified in the EEPROM for the function,
13359 * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is
13360 * ready to be 'ored' into SCSI_CFG1.
13361 */
13362 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
Matthew Wilcox13ac2d92007-07-30 08:10:23 -060013363 struct pci_dev *pdev = adv_dvc_to_pdev(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013364 /* SE automatic termination control is enabled. */
13365 switch (scsi_cfg1 & C_DET_SE) {
13366 /* TERM_SE_HI: on, TERM_SE_LO: on */
13367 case 0x1:
13368 case 0x2:
13369 case 0x3:
13370 asc_dvc->cfg->termination |= TERM_SE;
13371 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013372
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013373 case 0x0:
Matthew Wilcox13ac2d92007-07-30 08:10:23 -060013374 if (PCI_FUNC(pdev->devfn) == 0) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013375 /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */
13376 } else {
13377 /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */
13378 asc_dvc->cfg->termination |= TERM_SE_HI;
13379 }
13380 break;
13381 }
13382 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013383
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013384 /*
13385 * Clear any set TERM_SE bits.
13386 */
13387 scsi_cfg1 &= ~TERM_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013388
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013389 /*
13390 * Invert the TERM_SE bits and then set 'scsi_cfg1'.
13391 */
13392 scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013393
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013394 /*
13395 * Clear Big Endian and Terminator Polarity bits and set possibly
13396 * modified termination control bits in the Microcode SCSI_CFG1
13397 * Register Value.
13398 *
13399 * Big Endian bit is not used even on big endian machines.
13400 */
13401 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013402
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013403 /*
13404 * Set SCSI_CFG1 Microcode Default Value
13405 *
13406 * Set possibly modified termination control bits in the Microcode
13407 * SCSI_CFG1 Register Value.
13408 *
13409 * The microcode will set the SCSI_CFG1 register using this value
13410 * after it is started below.
13411 */
13412 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013413
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013414 /*
13415 * Set MEM_CFG Microcode Default Value
13416 *
13417 * The microcode will set the MEM_CFG register using this value
13418 * after it is started below.
13419 *
13420 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
13421 * are defined.
13422 *
13423 * ASC-38C1600 has 32KB internal memory.
13424 *
13425 * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come
13426 * out a special 16K Adv Library and Microcode version. After the issue
13427 * resolved, we should turn back to the 32K support. Both a_condor.h and
13428 * mcode.sas files also need to be updated.
13429 *
13430 * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
13431 * BIOS_EN | RAM_SZ_32KB);
13432 */
13433 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
13434 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013435
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013436 /*
13437 * Set SEL_MASK Microcode Default Value
13438 *
13439 * The microcode will set the SEL_MASK register using this value
13440 * after it is started below.
13441 */
13442 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
13443 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013444
Matthew Wilcoxa9f4a592007-09-09 08:56:27 -060013445 AdvBuildCarrierFreelist(asc_dvc);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013446
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013447 /*
13448 * Set-up the Host->RISC Initiator Command Queue (ICQ).
13449 */
13450 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
13451 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
13452 return ADV_ERROR;
13453 }
13454 asc_dvc->carr_freelist = (ADV_CARR_T *)
13455 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013456
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013457 /*
13458 * The first command issued will be placed in the stopper carrier.
13459 */
13460 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013461
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013462 /*
13463 * Set RISC ICQ physical address start value. Initialize the
13464 * COMMA register to the same value otherwise the RISC will
13465 * prematurely detect a command is available.
13466 */
13467 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
13468 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
13469 le32_to_cpu(asc_dvc->icq_sp->carr_pa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013470
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013471 /*
13472 * Set-up the RISC->Host Initiator Response Queue (IRQ).
13473 */
13474 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
13475 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
13476 return ADV_ERROR;
13477 }
13478 asc_dvc->carr_freelist = (ADV_CARR_T *)
13479 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013480
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013481 /*
13482 * The first command completed by the RISC will be placed in
13483 * the stopper.
13484 *
13485 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
13486 * completed the RISC will set the ASC_RQ_STOPPER bit.
13487 */
13488 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013489
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013490 /*
13491 * Set RISC IRQ physical address start value.
13492 */
13493 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
13494 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013495
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013496 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
13497 (ADV_INTR_ENABLE_HOST_INTR |
13498 ADV_INTR_ENABLE_GLOBAL_INTR));
13499 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
13500 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013501
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013502 /* finally, finally, gentlemen, start your engine */
13503 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013504
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013505 /*
13506 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
13507 * Resets should be performed. The RISC has to be running
13508 * to issue a SCSI Bus Reset.
13509 */
13510 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
13511 /*
13512 * If the BIOS Signature is present in memory, restore the
13513 * per TID microcode operating variables.
13514 */
13515 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
13516 0x55AA) {
13517 /*
13518 * Restore per TID negotiated values.
13519 */
13520 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
13521 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
13522 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
13523 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
13524 tagqng_able);
13525 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
13526 AdvWriteByteLram(iop_base,
13527 ASC_MC_NUMBER_OF_MAX_CMD + tid,
13528 max_cmd[tid]);
13529 }
13530 } else {
13531 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
13532 warn_code = ASC_WARN_BUSRESET_ERROR;
13533 }
13534 }
13535 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013536
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013537 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013538}
13539
13540/*
13541 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
13542 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
13543 * all of this is done.
13544 *
13545 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
13546 *
13547 * For a non-fatal error return a warning code. If there are no warnings
13548 * then 0 is returned.
13549 *
13550 * Note: Chip is stopped on entry.
13551 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013552static int __devinit AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013553{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013554 AdvPortAddr iop_base;
13555 ushort warn_code;
13556 ADVEEP_3550_CONFIG eep_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013557
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013558 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013559
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013560 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013561
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013562 /*
13563 * Read the board's EEPROM configuration.
13564 *
13565 * Set default values if a bad checksum is found.
13566 */
13567 if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum) {
13568 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013569
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013570 /*
13571 * Set EEPROM default values.
13572 */
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040013573 memcpy(&eep_config, &Default_3550_EEPROM_Config,
13574 sizeof(ADVEEP_3550_CONFIG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013575
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013576 /*
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040013577 * Assume the 6 byte board serial number that was read from
13578 * EEPROM is correct even if the EEPROM checksum failed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013579 */
13580 eep_config.serial_number_word3 =
13581 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013582
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013583 eep_config.serial_number_word2 =
13584 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013585
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013586 eep_config.serial_number_word1 =
13587 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013588
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013589 AdvSet3550EEPConfig(iop_base, &eep_config);
13590 }
13591 /*
13592 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
13593 * EEPROM configuration that was read.
13594 *
13595 * This is the mapping of EEPROM fields to Adv Library fields.
13596 */
13597 asc_dvc->wdtr_able = eep_config.wdtr_able;
13598 asc_dvc->sdtr_able = eep_config.sdtr_able;
13599 asc_dvc->ultra_able = eep_config.ultra_able;
13600 asc_dvc->tagqng_able = eep_config.tagqng_able;
13601 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
13602 asc_dvc->max_host_qng = eep_config.max_host_qng;
13603 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
13604 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
13605 asc_dvc->start_motor = eep_config.start_motor;
13606 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
13607 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
13608 asc_dvc->no_scam = eep_config.scam_tolerant;
13609 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
13610 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
13611 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013612
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013613 /*
13614 * Set the host maximum queuing (max. 253, min. 16) and the per device
13615 * maximum queuing (max. 63, min. 4).
13616 */
13617 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
13618 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
13619 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
13620 /* If the value is zero, assume it is uninitialized. */
13621 if (eep_config.max_host_qng == 0) {
13622 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
13623 } else {
13624 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
13625 }
13626 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013627
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013628 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
13629 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
13630 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
13631 /* If the value is zero, assume it is uninitialized. */
13632 if (eep_config.max_dvc_qng == 0) {
13633 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
13634 } else {
13635 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
13636 }
13637 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013638
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013639 /*
13640 * If 'max_dvc_qng' is greater than 'max_host_qng', then
13641 * set 'max_dvc_qng' to 'max_host_qng'.
13642 */
13643 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
13644 eep_config.max_dvc_qng = eep_config.max_host_qng;
13645 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013646
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013647 /*
13648 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
13649 * values based on possibly adjusted EEPROM values.
13650 */
13651 asc_dvc->max_host_qng = eep_config.max_host_qng;
13652 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013653
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013654 /*
13655 * If the EEPROM 'termination' field is set to automatic (0), then set
13656 * the ADV_DVC_CFG 'termination' field to automatic also.
13657 *
13658 * If the termination is specified with a non-zero 'termination'
13659 * value check that a legal value is set and set the ADV_DVC_CFG
13660 * 'termination' field appropriately.
13661 */
13662 if (eep_config.termination == 0) {
13663 asc_dvc->cfg->termination = 0; /* auto termination */
13664 } else {
13665 /* Enable manual control with low off / high off. */
13666 if (eep_config.termination == 1) {
13667 asc_dvc->cfg->termination = TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013668
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013669 /* Enable manual control with low off / high on. */
13670 } else if (eep_config.termination == 2) {
13671 asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013672
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013673 /* Enable manual control with low on / high on. */
13674 } else if (eep_config.termination == 3) {
13675 asc_dvc->cfg->termination =
13676 TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L;
13677 } else {
13678 /*
13679 * The EEPROM 'termination' field contains a bad value. Use
13680 * automatic termination instead.
13681 */
13682 asc_dvc->cfg->termination = 0;
13683 warn_code |= ASC_WARN_EEPROM_TERMINATION;
13684 }
13685 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013686
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013687 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013688}
13689
13690/*
13691 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
13692 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
13693 * all of this is done.
13694 *
13695 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
13696 *
13697 * For a non-fatal error return a warning code. If there are no warnings
13698 * then 0 is returned.
13699 *
13700 * Note: Chip is stopped on entry.
13701 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013702static int __devinit AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013703{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013704 AdvPortAddr iop_base;
13705 ushort warn_code;
13706 ADVEEP_38C0800_CONFIG eep_config;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013707 uchar tid, termination;
13708 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013709
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013710 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013711
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013712 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013713
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013714 /*
13715 * Read the board's EEPROM configuration.
13716 *
13717 * Set default values if a bad checksum is found.
13718 */
13719 if (AdvGet38C0800EEPConfig(iop_base, &eep_config) !=
13720 eep_config.check_sum) {
13721 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013722
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013723 /*
13724 * Set EEPROM default values.
13725 */
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040013726 memcpy(&eep_config, &Default_38C0800_EEPROM_Config,
13727 sizeof(ADVEEP_38C0800_CONFIG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013728
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013729 /*
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040013730 * Assume the 6 byte board serial number that was read from
13731 * EEPROM is correct even if the EEPROM checksum failed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013732 */
13733 eep_config.serial_number_word3 =
13734 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013735
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013736 eep_config.serial_number_word2 =
13737 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013738
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013739 eep_config.serial_number_word1 =
13740 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013741
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013742 AdvSet38C0800EEPConfig(iop_base, &eep_config);
13743 }
13744 /*
13745 * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
13746 * EEPROM configuration that was read.
13747 *
13748 * This is the mapping of EEPROM fields to Adv Library fields.
13749 */
13750 asc_dvc->wdtr_able = eep_config.wdtr_able;
13751 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
13752 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
13753 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
13754 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
13755 asc_dvc->tagqng_able = eep_config.tagqng_able;
13756 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
13757 asc_dvc->max_host_qng = eep_config.max_host_qng;
13758 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
13759 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
13760 asc_dvc->start_motor = eep_config.start_motor;
13761 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
13762 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
13763 asc_dvc->no_scam = eep_config.scam_tolerant;
13764 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
13765 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
13766 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013767
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013768 /*
13769 * For every Target ID if any of its 'sdtr_speed[1234]' bits
13770 * are set, then set an 'sdtr_able' bit for it.
13771 */
13772 asc_dvc->sdtr_able = 0;
13773 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
13774 if (tid == 0) {
13775 sdtr_speed = asc_dvc->sdtr_speed1;
13776 } else if (tid == 4) {
13777 sdtr_speed = asc_dvc->sdtr_speed2;
13778 } else if (tid == 8) {
13779 sdtr_speed = asc_dvc->sdtr_speed3;
13780 } else if (tid == 12) {
13781 sdtr_speed = asc_dvc->sdtr_speed4;
13782 }
13783 if (sdtr_speed & ADV_MAX_TID) {
13784 asc_dvc->sdtr_able |= (1 << tid);
13785 }
13786 sdtr_speed >>= 4;
13787 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013788
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013789 /*
13790 * Set the host maximum queuing (max. 253, min. 16) and the per device
13791 * maximum queuing (max. 63, min. 4).
13792 */
13793 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
13794 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
13795 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
13796 /* If the value is zero, assume it is uninitialized. */
13797 if (eep_config.max_host_qng == 0) {
13798 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
13799 } else {
13800 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
13801 }
13802 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013803
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013804 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
13805 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
13806 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
13807 /* If the value is zero, assume it is uninitialized. */
13808 if (eep_config.max_dvc_qng == 0) {
13809 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
13810 } else {
13811 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
13812 }
13813 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013814
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013815 /*
13816 * If 'max_dvc_qng' is greater than 'max_host_qng', then
13817 * set 'max_dvc_qng' to 'max_host_qng'.
13818 */
13819 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
13820 eep_config.max_dvc_qng = eep_config.max_host_qng;
13821 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013822
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013823 /*
13824 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
13825 * values based on possibly adjusted EEPROM values.
13826 */
13827 asc_dvc->max_host_qng = eep_config.max_host_qng;
13828 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013829
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013830 /*
13831 * If the EEPROM 'termination' field is set to automatic (0), then set
13832 * the ADV_DVC_CFG 'termination' field to automatic also.
13833 *
13834 * If the termination is specified with a non-zero 'termination'
13835 * value check that a legal value is set and set the ADV_DVC_CFG
13836 * 'termination' field appropriately.
13837 */
13838 if (eep_config.termination_se == 0) {
13839 termination = 0; /* auto termination for SE */
13840 } else {
13841 /* Enable manual control with low off / high off. */
13842 if (eep_config.termination_se == 1) {
13843 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013844
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013845 /* Enable manual control with low off / high on. */
13846 } else if (eep_config.termination_se == 2) {
13847 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013848
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013849 /* Enable manual control with low on / high on. */
13850 } else if (eep_config.termination_se == 3) {
13851 termination = TERM_SE;
13852 } else {
13853 /*
13854 * The EEPROM 'termination_se' field contains a bad value.
13855 * Use automatic termination instead.
13856 */
13857 termination = 0;
13858 warn_code |= ASC_WARN_EEPROM_TERMINATION;
13859 }
13860 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013861
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013862 if (eep_config.termination_lvd == 0) {
13863 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
13864 } else {
13865 /* Enable manual control with low off / high off. */
13866 if (eep_config.termination_lvd == 1) {
13867 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013868
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013869 /* Enable manual control with low off / high on. */
13870 } else if (eep_config.termination_lvd == 2) {
13871 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013872
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013873 /* Enable manual control with low on / high on. */
13874 } else if (eep_config.termination_lvd == 3) {
13875 asc_dvc->cfg->termination = termination | TERM_LVD;
13876 } else {
13877 /*
13878 * The EEPROM 'termination_lvd' field contains a bad value.
13879 * Use automatic termination instead.
13880 */
13881 asc_dvc->cfg->termination = termination;
13882 warn_code |= ASC_WARN_EEPROM_TERMINATION;
13883 }
13884 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013885
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013886 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013887}
13888
13889/*
13890 * Read the board's EEPROM configuration. Set fields in ASC_DVC_VAR and
13891 * ASC_DVC_CFG based on the EEPROM settings. The chip is stopped while
13892 * all of this is done.
13893 *
13894 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
13895 *
13896 * For a non-fatal error return a warning code. If there are no warnings
13897 * then 0 is returned.
13898 *
13899 * Note: Chip is stopped on entry.
13900 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013901static int __devinit AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013902{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013903 AdvPortAddr iop_base;
13904 ushort warn_code;
13905 ADVEEP_38C1600_CONFIG eep_config;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013906 uchar tid, termination;
13907 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013908
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013909 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013910
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013911 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013912
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013913 /*
13914 * Read the board's EEPROM configuration.
13915 *
13916 * Set default values if a bad checksum is found.
13917 */
13918 if (AdvGet38C1600EEPConfig(iop_base, &eep_config) !=
13919 eep_config.check_sum) {
Matthew Wilcox13ac2d92007-07-30 08:10:23 -060013920 struct pci_dev *pdev = adv_dvc_to_pdev(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013921 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013922
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013923 /*
13924 * Set EEPROM default values.
13925 */
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040013926 memcpy(&eep_config, &Default_38C1600_EEPROM_Config,
13927 sizeof(ADVEEP_38C1600_CONFIG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013928
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040013929 if (PCI_FUNC(pdev->devfn) != 0) {
13930 u8 ints;
13931 /*
13932 * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60
13933 * and old Mac system booting problem. The Expansion
13934 * ROM must be disabled in Function 1 for these systems
13935 */
13936 eep_config.cfg_lsw &= ~ADV_EEPROM_BIOS_ENABLE;
13937 /*
13938 * Clear the INTAB (bit 11) if the GPIO 0 input
13939 * indicates the Function 1 interrupt line is wired
13940 * to INTB.
13941 *
13942 * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input:
13943 * 1 - Function 1 interrupt line wired to INT A.
13944 * 0 - Function 1 interrupt line wired to INT B.
13945 *
13946 * Note: Function 0 is always wired to INTA.
13947 * Put all 5 GPIO bits in input mode and then read
13948 * their input values.
13949 */
13950 AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL, 0);
13951 ints = AdvReadByteRegister(iop_base, IOPB_GPIO_DATA);
13952 if ((ints & 0x01) == 0)
13953 eep_config.cfg_lsw &= ~ADV_EEPROM_INTAB;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013954 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013955
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013956 /*
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040013957 * Assume the 6 byte board serial number that was read from
13958 * EEPROM is correct even if the EEPROM checksum failed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013959 */
13960 eep_config.serial_number_word3 =
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040013961 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013962 eep_config.serial_number_word2 =
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040013963 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013964 eep_config.serial_number_word1 =
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040013965 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013966
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013967 AdvSet38C1600EEPConfig(iop_base, &eep_config);
13968 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013969
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013970 /*
13971 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
13972 * EEPROM configuration that was read.
13973 *
13974 * This is the mapping of EEPROM fields to Adv Library fields.
13975 */
13976 asc_dvc->wdtr_able = eep_config.wdtr_able;
13977 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
13978 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
13979 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
13980 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
13981 asc_dvc->ppr_able = 0;
13982 asc_dvc->tagqng_able = eep_config.tagqng_able;
13983 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
13984 asc_dvc->max_host_qng = eep_config.max_host_qng;
13985 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
13986 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ASC_MAX_TID);
13987 asc_dvc->start_motor = eep_config.start_motor;
13988 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
13989 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
13990 asc_dvc->no_scam = eep_config.scam_tolerant;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013991
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013992 /*
13993 * For every Target ID if any of its 'sdtr_speed[1234]' bits
13994 * are set, then set an 'sdtr_able' bit for it.
13995 */
13996 asc_dvc->sdtr_able = 0;
13997 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
13998 if (tid == 0) {
13999 sdtr_speed = asc_dvc->sdtr_speed1;
14000 } else if (tid == 4) {
14001 sdtr_speed = asc_dvc->sdtr_speed2;
14002 } else if (tid == 8) {
14003 sdtr_speed = asc_dvc->sdtr_speed3;
14004 } else if (tid == 12) {
14005 sdtr_speed = asc_dvc->sdtr_speed4;
14006 }
14007 if (sdtr_speed & ASC_MAX_TID) {
14008 asc_dvc->sdtr_able |= (1 << tid);
14009 }
14010 sdtr_speed >>= 4;
14011 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014012
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014013 /*
14014 * Set the host maximum queuing (max. 253, min. 16) and the per device
14015 * maximum queuing (max. 63, min. 4).
14016 */
14017 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
14018 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
14019 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
14020 /* If the value is zero, assume it is uninitialized. */
14021 if (eep_config.max_host_qng == 0) {
14022 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
14023 } else {
14024 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
14025 }
14026 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014027
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014028 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
14029 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
14030 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
14031 /* If the value is zero, assume it is uninitialized. */
14032 if (eep_config.max_dvc_qng == 0) {
14033 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
14034 } else {
14035 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
14036 }
14037 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014038
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014039 /*
14040 * If 'max_dvc_qng' is greater than 'max_host_qng', then
14041 * set 'max_dvc_qng' to 'max_host_qng'.
14042 */
14043 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
14044 eep_config.max_dvc_qng = eep_config.max_host_qng;
14045 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014046
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014047 /*
14048 * Set ASC_DVC_VAR 'max_host_qng' and ASC_DVC_VAR 'max_dvc_qng'
14049 * values based on possibly adjusted EEPROM values.
14050 */
14051 asc_dvc->max_host_qng = eep_config.max_host_qng;
14052 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014053
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014054 /*
14055 * If the EEPROM 'termination' field is set to automatic (0), then set
14056 * the ASC_DVC_CFG 'termination' field to automatic also.
14057 *
14058 * If the termination is specified with a non-zero 'termination'
14059 * value check that a legal value is set and set the ASC_DVC_CFG
14060 * 'termination' field appropriately.
14061 */
14062 if (eep_config.termination_se == 0) {
14063 termination = 0; /* auto termination for SE */
14064 } else {
14065 /* Enable manual control with low off / high off. */
14066 if (eep_config.termination_se == 1) {
14067 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014068
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014069 /* Enable manual control with low off / high on. */
14070 } else if (eep_config.termination_se == 2) {
14071 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014072
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014073 /* Enable manual control with low on / high on. */
14074 } else if (eep_config.termination_se == 3) {
14075 termination = TERM_SE;
14076 } else {
14077 /*
14078 * The EEPROM 'termination_se' field contains a bad value.
14079 * Use automatic termination instead.
14080 */
14081 termination = 0;
14082 warn_code |= ASC_WARN_EEPROM_TERMINATION;
14083 }
14084 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014085
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014086 if (eep_config.termination_lvd == 0) {
14087 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
14088 } else {
14089 /* Enable manual control with low off / high off. */
14090 if (eep_config.termination_lvd == 1) {
14091 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014092
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014093 /* Enable manual control with low off / high on. */
14094 } else if (eep_config.termination_lvd == 2) {
14095 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014096
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014097 /* Enable manual control with low on / high on. */
14098 } else if (eep_config.termination_lvd == 3) {
14099 asc_dvc->cfg->termination = termination | TERM_LVD;
14100 } else {
14101 /*
14102 * The EEPROM 'termination_lvd' field contains a bad value.
14103 * Use automatic termination instead.
14104 */
14105 asc_dvc->cfg->termination = termination;
14106 warn_code |= ASC_WARN_EEPROM_TERMINATION;
14107 }
14108 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014109
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014110 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014111}
14112
14113/*
14114 * Read EEPROM configuration into the specified buffer.
14115 *
14116 * Return a checksum based on the EEPROM configuration read.
14117 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060014118static ushort __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -070014119AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
14120{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014121 ushort wval, chksum;
14122 ushort *wbuf;
14123 int eep_addr;
14124 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014125
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014126 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
14127 wbuf = (ushort *)cfg_buf;
14128 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014129
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014130 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
14131 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
14132 wval = AdvReadEEPWord(iop_base, eep_addr);
14133 chksum += wval; /* Checksum is calculated from word values. */
14134 if (*charfields++) {
14135 *wbuf = le16_to_cpu(wval);
14136 } else {
14137 *wbuf = wval;
14138 }
14139 }
14140 /* Read checksum word. */
14141 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
14142 wbuf++;
14143 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014144
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014145 /* Read rest of EEPROM not covered by the checksum. */
14146 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
14147 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
14148 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
14149 if (*charfields++) {
14150 *wbuf = le16_to_cpu(*wbuf);
14151 }
14152 }
14153 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014154}
14155
14156/*
14157 * Read EEPROM configuration into the specified buffer.
14158 *
14159 * Return a checksum based on the EEPROM configuration read.
14160 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060014161static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014162AdvGet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014163{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014164 ushort wval, chksum;
14165 ushort *wbuf;
14166 int eep_addr;
14167 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014168
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014169 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
14170 wbuf = (ushort *)cfg_buf;
14171 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014172
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014173 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
14174 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
14175 wval = AdvReadEEPWord(iop_base, eep_addr);
14176 chksum += wval; /* Checksum is calculated from word values. */
14177 if (*charfields++) {
14178 *wbuf = le16_to_cpu(wval);
14179 } else {
14180 *wbuf = wval;
14181 }
14182 }
14183 /* Read checksum word. */
14184 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
14185 wbuf++;
14186 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014187
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014188 /* Read rest of EEPROM not covered by the checksum. */
14189 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
14190 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
14191 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
14192 if (*charfields++) {
14193 *wbuf = le16_to_cpu(*wbuf);
14194 }
14195 }
14196 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014197}
14198
14199/*
14200 * Read EEPROM configuration into the specified buffer.
14201 *
14202 * Return a checksum based on the EEPROM configuration read.
14203 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060014204static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014205AdvGet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014206{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014207 ushort wval, chksum;
14208 ushort *wbuf;
14209 int eep_addr;
14210 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014211
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014212 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
14213 wbuf = (ushort *)cfg_buf;
14214 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014215
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014216 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
14217 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
14218 wval = AdvReadEEPWord(iop_base, eep_addr);
14219 chksum += wval; /* Checksum is calculated from word values. */
14220 if (*charfields++) {
14221 *wbuf = le16_to_cpu(wval);
14222 } else {
14223 *wbuf = wval;
14224 }
14225 }
14226 /* Read checksum word. */
14227 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
14228 wbuf++;
14229 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014230
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014231 /* Read rest of EEPROM not covered by the checksum. */
14232 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
14233 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
14234 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
14235 if (*charfields++) {
14236 *wbuf = le16_to_cpu(*wbuf);
14237 }
14238 }
14239 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014240}
14241
14242/*
14243 * Read the EEPROM from specified location
14244 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060014245static ushort __devinit AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014246{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014247 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
14248 ASC_EEP_CMD_READ | eep_word_addr);
14249 AdvWaitEEPCmd(iop_base);
14250 return AdvReadWordRegister(iop_base, IOPW_EE_DATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014251}
14252
14253/*
14254 * Wait for EEPROM command to complete
14255 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060014256static void __devinit AdvWaitEEPCmd(AdvPortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014257{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014258 int eep_delay_ms;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014259
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014260 for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++) {
14261 if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) &
14262 ASC_EEP_CMD_DONE) {
14263 break;
14264 }
14265 DvcSleepMilliSecond(1);
14266 }
14267 if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) ==
14268 0) {
14269 ASC_ASSERT(0);
14270 }
14271 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014272}
14273
14274/*
14275 * Write the EEPROM from 'cfg_buf'.
14276 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060014277void __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -070014278AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
14279{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014280 ushort *wbuf;
14281 ushort addr, chksum;
14282 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014283
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014284 wbuf = (ushort *)cfg_buf;
14285 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
14286 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014287
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014288 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
14289 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014290
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014291 /*
14292 * Write EEPROM from word 0 to word 20.
14293 */
14294 for (addr = ADV_EEP_DVC_CFG_BEGIN;
14295 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
14296 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014297
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014298 if (*charfields++) {
14299 word = cpu_to_le16(*wbuf);
14300 } else {
14301 word = *wbuf;
14302 }
14303 chksum += *wbuf; /* Checksum is calculated from word values. */
14304 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
14305 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
14306 ASC_EEP_CMD_WRITE | addr);
14307 AdvWaitEEPCmd(iop_base);
14308 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
14309 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014310
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014311 /*
14312 * Write EEPROM checksum at word 21.
14313 */
14314 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
14315 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
14316 AdvWaitEEPCmd(iop_base);
14317 wbuf++;
14318 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014319
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014320 /*
14321 * Write EEPROM OEM name at words 22 to 29.
14322 */
14323 for (addr = ADV_EEP_DVC_CTL_BEGIN;
14324 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
14325 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014326
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014327 if (*charfields++) {
14328 word = cpu_to_le16(*wbuf);
14329 } else {
14330 word = *wbuf;
14331 }
14332 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
14333 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
14334 ASC_EEP_CMD_WRITE | addr);
14335 AdvWaitEEPCmd(iop_base);
14336 }
14337 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
14338 AdvWaitEEPCmd(iop_base);
14339 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014340}
14341
14342/*
14343 * Write the EEPROM from 'cfg_buf'.
14344 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060014345void __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014346AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014347{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014348 ushort *wbuf;
14349 ushort *charfields;
14350 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014351
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014352 wbuf = (ushort *)cfg_buf;
14353 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
14354 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014355
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014356 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
14357 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014358
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014359 /*
14360 * Write EEPROM from word 0 to word 20.
14361 */
14362 for (addr = ADV_EEP_DVC_CFG_BEGIN;
14363 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
14364 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014365
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014366 if (*charfields++) {
14367 word = cpu_to_le16(*wbuf);
14368 } else {
14369 word = *wbuf;
14370 }
14371 chksum += *wbuf; /* Checksum is calculated from word values. */
14372 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
14373 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
14374 ASC_EEP_CMD_WRITE | addr);
14375 AdvWaitEEPCmd(iop_base);
14376 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
14377 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014378
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014379 /*
14380 * Write EEPROM checksum at word 21.
14381 */
14382 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
14383 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
14384 AdvWaitEEPCmd(iop_base);
14385 wbuf++;
14386 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014387
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014388 /*
14389 * Write EEPROM OEM name at words 22 to 29.
14390 */
14391 for (addr = ADV_EEP_DVC_CTL_BEGIN;
14392 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
14393 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014394
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014395 if (*charfields++) {
14396 word = cpu_to_le16(*wbuf);
14397 } else {
14398 word = *wbuf;
14399 }
14400 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
14401 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
14402 ASC_EEP_CMD_WRITE | addr);
14403 AdvWaitEEPCmd(iop_base);
14404 }
14405 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
14406 AdvWaitEEPCmd(iop_base);
14407 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014408}
14409
14410/*
14411 * Write the EEPROM from 'cfg_buf'.
14412 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060014413void __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014414AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014415{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014416 ushort *wbuf;
14417 ushort *charfields;
14418 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014419
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014420 wbuf = (ushort *)cfg_buf;
14421 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
14422 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014423
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014424 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
14425 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014426
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014427 /*
14428 * Write EEPROM from word 0 to word 20.
14429 */
14430 for (addr = ADV_EEP_DVC_CFG_BEGIN;
14431 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
14432 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014433
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014434 if (*charfields++) {
14435 word = cpu_to_le16(*wbuf);
14436 } else {
14437 word = *wbuf;
14438 }
14439 chksum += *wbuf; /* Checksum is calculated from word values. */
14440 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
14441 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
14442 ASC_EEP_CMD_WRITE | addr);
14443 AdvWaitEEPCmd(iop_base);
14444 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
14445 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014446
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014447 /*
14448 * Write EEPROM checksum at word 21.
14449 */
14450 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
14451 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
14452 AdvWaitEEPCmd(iop_base);
14453 wbuf++;
14454 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014455
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014456 /*
14457 * Write EEPROM OEM name at words 22 to 29.
14458 */
14459 for (addr = ADV_EEP_DVC_CTL_BEGIN;
14460 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
14461 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014462
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014463 if (*charfields++) {
14464 word = cpu_to_le16(*wbuf);
14465 } else {
14466 word = *wbuf;
14467 }
14468 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
14469 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
14470 ASC_EEP_CMD_WRITE | addr);
14471 AdvWaitEEPCmd(iop_base);
14472 }
14473 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
14474 AdvWaitEEPCmd(iop_base);
14475 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014476}
14477
14478/* a_advlib.c */
14479/*
14480 * AdvExeScsiQueue() - Send a request to the RISC microcode program.
14481 *
14482 * Allocate a carrier structure, point the carrier to the ADV_SCSI_REQ_Q,
14483 * add the carrier to the ICQ (Initiator Command Queue), and tickle the
14484 * RISC to notify it a new command is ready to be executed.
14485 *
14486 * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be
14487 * set to SCSI_MAX_RETRY.
14488 *
14489 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the microcode
14490 * for DMA addresses or math operations are byte swapped to little-endian
14491 * order.
14492 *
14493 * Return:
14494 * ADV_SUCCESS(1) - The request was successfully queued.
14495 * ADV_BUSY(0) - Resource unavailable; Retry again after pending
14496 * request completes.
14497 * ADV_ERROR(-1) - Invalid ADV_SCSI_REQ_Q request structure
14498 * host IC error.
14499 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014500static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014501{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014502 ulong last_int_level;
14503 AdvPortAddr iop_base;
14504 ADV_DCNT req_size;
14505 ADV_PADDR req_paddr;
14506 ADV_CARR_T *new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014507
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014508 ASC_ASSERT(scsiq != NULL); /* 'scsiq' should never be NULL. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014509
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014510 /*
14511 * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
14512 */
14513 if (scsiq->target_id > ADV_MAX_TID) {
14514 scsiq->host_status = QHSTA_M_INVALID_DEVICE;
14515 scsiq->done_status = QD_WITH_ERROR;
14516 return ADV_ERROR;
14517 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014518
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014519 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014520
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014521 last_int_level = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070014522
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014523 /*
14524 * Allocate a carrier ensuring at least one carrier always
14525 * remains on the freelist and initialize fields.
14526 */
14527 if ((new_carrp = asc_dvc->carr_freelist) == NULL) {
14528 DvcLeaveCritical(last_int_level);
14529 return ADV_BUSY;
14530 }
14531 asc_dvc->carr_freelist = (ADV_CARR_T *)
14532 ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa));
14533 asc_dvc->carr_pending_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014534
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014535 /*
14536 * Set the carrier to be a stopper by setting 'next_vpa'
14537 * to the stopper value. The current stopper will be changed
14538 * below to point to the new stopper.
14539 */
14540 new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014541
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014542 /*
14543 * Clear the ADV_SCSI_REQ_Q done flag.
14544 */
14545 scsiq->a_flag &= ~ADV_SCSIQ_DONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014546
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014547 req_size = sizeof(ADV_SCSI_REQ_Q);
14548 req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *)scsiq,
14549 (ADV_SDCNT *)&req_size, ADV_IS_SCSIQ_FLAG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014550
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014551 ASC_ASSERT(ADV_32BALIGN(req_paddr) == req_paddr);
14552 ASC_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014553
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014554 /* Wait for assertion before making little-endian */
14555 req_paddr = cpu_to_le32(req_paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014556
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014557 /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
14558 scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq));
14559 scsiq->scsiq_rptr = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014560
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014561 scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp));
14562 /*
14563 * Every ADV_CARR_T.carr_pa is byte swapped to little-endian
14564 * order during initialization.
14565 */
14566 scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014567
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014568 /*
14569 * Use the current stopper to send the ADV_SCSI_REQ_Q command to
14570 * the microcode. The newly allocated stopper will become the new
14571 * stopper.
14572 */
14573 asc_dvc->icq_sp->areq_vpa = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014574
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014575 /*
14576 * Set the 'next_vpa' pointer for the old stopper to be the
14577 * physical address of the new stopper. The RISC can only
14578 * follow physical addresses.
14579 */
14580 asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014581
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014582 /*
14583 * Set the host adapter stopper pointer to point to the new carrier.
14584 */
14585 asc_dvc->icq_sp = new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014586
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014587 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
14588 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
14589 /*
14590 * Tickle the RISC to tell it to read its Command Queue Head pointer.
14591 */
14592 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
14593 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
14594 /*
14595 * Clear the tickle value. In the ASC-3550 the RISC flag
14596 * command 'clr_tickle_a' does not work unless the host
14597 * value is cleared.
14598 */
14599 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
14600 ADV_TICKLE_NOP);
14601 }
14602 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
14603 /*
14604 * Notify the RISC a carrier is ready by writing the physical
14605 * address of the new carrier stopper to the COMMA register.
14606 */
14607 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
14608 le32_to_cpu(new_carrp->carr_pa));
14609 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014610
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014611 DvcLeaveCritical(last_int_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014612
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014613 return ADV_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014614}
14615
14616/*
14617 * Reset SCSI Bus and purge all outstanding requests.
14618 *
14619 * Return Value:
14620 * ADV_TRUE(1) - All requests are purged and SCSI Bus is reset.
14621 * ADV_FALSE(0) - Microcode command failed.
14622 * ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC
14623 * may be hung which requires driver recovery.
14624 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014625static int AdvResetSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014626{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014627 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014628
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014629 /*
14630 * Send the SCSI Bus Reset idle start idle command which asserts
14631 * the SCSI Bus Reset signal.
14632 */
14633 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_START, 0L);
14634 if (status != ADV_TRUE) {
14635 return status;
14636 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014637
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014638 /*
14639 * Delay for the specified SCSI Bus Reset hold time.
14640 *
14641 * The hold time delay is done on the host because the RISC has no
14642 * microsecond accurate timer.
14643 */
14644 DvcDelayMicroSecond(asc_dvc, (ushort)ASC_SCSI_RESET_HOLD_TIME_US);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014645
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014646 /*
14647 * Send the SCSI Bus Reset end idle command which de-asserts
14648 * the SCSI Bus Reset signal and purges any pending requests.
14649 */
14650 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_END, 0L);
14651 if (status != ADV_TRUE) {
14652 return status;
14653 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014654
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014655 DvcSleepMilliSecond((ADV_DCNT)asc_dvc->scsi_reset_wait * 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014656
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014657 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014658}
14659
14660/*
14661 * Reset chip and SCSI Bus.
14662 *
14663 * Return Value:
14664 * ADV_TRUE(1) - Chip re-initialization and SCSI Bus Reset successful.
14665 * ADV_FALSE(0) - Chip re-initialization and SCSI Bus Reset failure.
14666 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014667static int AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014668{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014669 int status;
14670 ushort wdtr_able, sdtr_able, tagqng_able;
14671 ushort ppr_able = 0;
14672 uchar tid, max_cmd[ADV_MAX_TID + 1];
14673 AdvPortAddr iop_base;
14674 ushort bios_sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014675
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014676 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014677
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014678 /*
14679 * Save current per TID negotiated values.
14680 */
14681 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14682 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14683 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
14684 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
14685 }
14686 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
14687 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14688 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
14689 max_cmd[tid]);
14690 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014691
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014692 /*
14693 * Force the AdvInitAsc3550/38C0800Driver() function to
14694 * perform a SCSI Bus Reset by clearing the BIOS signature word.
14695 * The initialization functions assumes a SCSI Bus Reset is not
14696 * needed if the BIOS signature word is present.
14697 */
14698 AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
14699 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014700
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014701 /*
14702 * Stop chip and reset it.
14703 */
14704 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP);
14705 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
14706 DvcSleepMilliSecond(100);
14707 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
14708 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014709
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014710 /*
14711 * Reset Adv Library error code, if any, and try
14712 * re-initializing the chip.
14713 */
14714 asc_dvc->err_code = 0;
14715 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
14716 status = AdvInitAsc38C1600Driver(asc_dvc);
14717 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
14718 status = AdvInitAsc38C0800Driver(asc_dvc);
14719 } else {
14720 status = AdvInitAsc3550Driver(asc_dvc);
14721 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014722
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014723 /* Translate initialization return value to status value. */
14724 if (status == 0) {
14725 status = ADV_TRUE;
14726 } else {
14727 status = ADV_FALSE;
14728 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014729
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014730 /*
14731 * Restore the BIOS signature word.
14732 */
14733 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014734
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014735 /*
14736 * Restore per TID negotiated values.
14737 */
14738 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14739 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14740 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
14741 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
14742 }
14743 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
14744 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14745 AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
14746 max_cmd[tid]);
14747 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014748
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014749 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014750}
14751
14752/*
14753 * Adv Library Interrupt Service Routine
14754 *
14755 * This function is called by a driver's interrupt service routine.
14756 * The function disables and re-enables interrupts.
14757 *
14758 * When a microcode idle command is completed, the ADV_DVC_VAR
14759 * 'idle_cmd_done' field is set to ADV_TRUE.
14760 *
14761 * Note: AdvISR() can be called when interrupts are disabled or even
14762 * when there is no hardware interrupt condition present. It will
14763 * always check for completed idle commands and microcode requests.
14764 * This is an important feature that shouldn't be changed because it
14765 * allows commands to be completed from polling mode loops.
14766 *
14767 * Return:
14768 * ADV_TRUE(1) - interrupt was pending
14769 * ADV_FALSE(0) - no interrupt was pending
14770 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014771static int AdvISR(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014772{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014773 AdvPortAddr iop_base;
14774 uchar int_stat;
14775 ushort target_bit;
14776 ADV_CARR_T *free_carrp;
14777 ADV_VADDR irq_next_vpa;
14778 int flags;
14779 ADV_SCSI_REQ_Q *scsiq;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014780
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014781 flags = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070014782
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014783 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014784
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014785 /* Reading the register clears the interrupt. */
14786 int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014787
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014788 if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB |
14789 ADV_INTR_STATUS_INTRC)) == 0) {
14790 DvcLeaveCritical(flags);
14791 return ADV_FALSE;
14792 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014793
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014794 /*
14795 * Notify the driver of an asynchronous microcode condition by
Matthew Wilcox895d6b42007-07-26 11:57:06 -040014796 * calling the adv_async_callback function. The function
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014797 * is passed the microcode ASC_MC_INTRB_CODE byte value.
14798 */
14799 if (int_stat & ADV_INTR_STATUS_INTRB) {
14800 uchar intrb_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014801
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014802 AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014803
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014804 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
14805 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
14806 if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
14807 asc_dvc->carr_pending_cnt != 0) {
14808 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
14809 ADV_TICKLE_A);
14810 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
14811 AdvWriteByteRegister(iop_base,
14812 IOPB_TICKLE,
14813 ADV_TICKLE_NOP);
14814 }
14815 }
14816 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014817
Matthew Wilcox895d6b42007-07-26 11:57:06 -040014818 adv_async_callback(asc_dvc, intrb_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014819 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014820
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014821 /*
14822 * Check if the IRQ stopper carrier contains a completed request.
14823 */
14824 while (((irq_next_vpa =
14825 le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0) {
14826 /*
14827 * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
14828 * The RISC will have set 'areq_vpa' to a virtual address.
14829 *
14830 * The firmware will have copied the ASC_SCSI_REQ_Q.scsiq_ptr
14831 * field to the carrier ADV_CARR_T.areq_vpa field. The conversion
14832 * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr'
14833 * in AdvExeScsiQueue().
14834 */
14835 scsiq = (ADV_SCSI_REQ_Q *)
14836 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014837
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014838 /*
14839 * Request finished with good status and the queue was not
14840 * DMAed to host memory by the firmware. Set all status fields
14841 * to indicate good status.
14842 */
14843 if ((irq_next_vpa & ASC_RQ_GOOD) != 0) {
14844 scsiq->done_status = QD_NO_ERROR;
14845 scsiq->host_status = scsiq->scsi_status = 0;
14846 scsiq->data_cnt = 0L;
14847 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014848
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014849 /*
14850 * Advance the stopper pointer to the next carrier
14851 * ignoring the lower four bits. Free the previous
14852 * stopper carrier.
14853 */
14854 free_carrp = asc_dvc->irq_sp;
14855 asc_dvc->irq_sp = (ADV_CARR_T *)
14856 ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014857
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014858 free_carrp->next_vpa =
14859 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
14860 asc_dvc->carr_freelist = free_carrp;
14861 asc_dvc->carr_pending_cnt--;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014862
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014863 ASC_ASSERT(scsiq != NULL);
14864 target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014865
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014866 /*
14867 * Clear request microcode control flag.
14868 */
14869 scsiq->cntl = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014870
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014871 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014872 * Notify the driver of the completed request by passing
14873 * the ADV_SCSI_REQ_Q pointer to its callback function.
14874 */
14875 scsiq->a_flag |= ADV_SCSIQ_DONE;
Matthew Wilcox895d6b42007-07-26 11:57:06 -040014876 adv_isr_callback(asc_dvc, scsiq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014877 /*
14878 * Note: After the driver callback function is called, 'scsiq'
14879 * can no longer be referenced.
14880 *
14881 * Fall through and continue processing other completed
14882 * requests...
14883 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014884
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014885 /*
14886 * Disable interrupts again in case the driver inadvertently
14887 * enabled interrupts in its callback function.
14888 *
14889 * The DvcEnterCritical() return value is ignored, because
14890 * the 'flags' saved when AdvISR() was first entered will be
14891 * used to restore the interrupt flag on exit.
14892 */
14893 (void)DvcEnterCritical();
14894 }
14895 DvcLeaveCritical(flags);
14896 return ADV_TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014897}
14898
14899/*
14900 * Send an idle command to the chip and wait for completion.
14901 *
14902 * Command completion is polled for once per microsecond.
14903 *
14904 * The function can be called from anywhere including an interrupt handler.
14905 * But the function is not re-entrant, so it uses the DvcEnter/LeaveCritical()
14906 * functions to prevent reentrancy.
14907 *
14908 * Return Values:
14909 * ADV_TRUE - command completed successfully
14910 * ADV_FALSE - command failed
14911 * ADV_ERROR - command timed out
14912 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014913static int
Linus Torvalds1da177e2005-04-16 15:20:36 -070014914AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014915 ushort idle_cmd, ADV_DCNT idle_cmd_parameter)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014916{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014917 ulong last_int_level;
14918 int result;
14919 ADV_DCNT i, j;
14920 AdvPortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014921
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014922 last_int_level = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070014923
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014924 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014925
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014926 /*
14927 * Clear the idle command status which is set by the microcode
14928 * to a non-zero value to indicate when the command is completed.
14929 * The non-zero result is one of the IDLE_CMD_STATUS_* values
14930 * defined in a_advlib.h.
14931 */
14932 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort)0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014933
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014934 /*
14935 * Write the idle command value after the idle command parameter
14936 * has been written to avoid a race condition. If the order is not
14937 * followed, the microcode may process the idle command before the
14938 * parameters have been written to LRAM.
14939 */
14940 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
14941 cpu_to_le32(idle_cmd_parameter));
14942 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014943
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014944 /*
14945 * Tickle the RISC to tell it to process the idle command.
14946 */
14947 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B);
14948 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
14949 /*
14950 * Clear the tickle value. In the ASC-3550 the RISC flag
14951 * command 'clr_tickle_b' does not work unless the host
14952 * value is cleared.
14953 */
14954 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
14955 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014956
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014957 /* Wait for up to 100 millisecond for the idle command to timeout. */
14958 for (i = 0; i < SCSI_WAIT_100_MSEC; i++) {
14959 /* Poll once each microsecond for command completion. */
14960 for (j = 0; j < SCSI_US_PER_MSEC; j++) {
14961 AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS,
14962 result);
14963 if (result != 0) {
14964 DvcLeaveCritical(last_int_level);
14965 return result;
14966 }
14967 DvcDelayMicroSecond(asc_dvc, (ushort)1);
14968 }
14969 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014970
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014971 ASC_ASSERT(0); /* The idle command should never timeout. */
14972 DvcLeaveCritical(last_int_level);
14973 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014974}
14975
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060014976static int __devinit
14977advansys_wide_init_chip(asc_board_t *boardp, ADV_DVC_VAR *adv_dvc_varp)
14978{
14979 int req_cnt = 0;
14980 adv_req_t *reqp = NULL;
14981 int sg_cnt = 0;
14982 adv_sgblk_t *sgp;
14983 int warn_code, err_code;
14984
14985 /*
14986 * Allocate buffer carrier structures. The total size
14987 * is about 4 KB, so allocate all at once.
14988 */
14989 boardp->carrp = kmalloc(ADV_CARRIER_BUFSIZE, GFP_KERNEL);
14990 ASC_DBG1(1, "advansys_wide_init_chip: carrp 0x%p\n", boardp->carrp);
14991
14992 if (!boardp->carrp)
14993 goto kmalloc_failed;
14994
14995 /*
14996 * Allocate up to 'max_host_qng' request structures for the Wide
14997 * board. The total size is about 16 KB, so allocate all at once.
14998 * If the allocation fails decrement and try again.
14999 */
15000 for (req_cnt = adv_dvc_varp->max_host_qng; req_cnt > 0; req_cnt--) {
15001 reqp = kmalloc(sizeof(adv_req_t) * req_cnt, GFP_KERNEL);
15002
15003 ASC_DBG3(1, "advansys_wide_init_chip: reqp 0x%p, req_cnt %d, "
15004 "bytes %lu\n", reqp, req_cnt,
15005 (ulong)sizeof(adv_req_t) * req_cnt);
15006
15007 if (reqp)
15008 break;
15009 }
15010
15011 if (!reqp)
15012 goto kmalloc_failed;
15013
15014 boardp->orig_reqp = reqp;
15015
15016 /*
15017 * Allocate up to ADV_TOT_SG_BLOCK request structures for
15018 * the Wide board. Each structure is about 136 bytes.
15019 */
15020 boardp->adv_sgblkp = NULL;
15021 for (sg_cnt = 0; sg_cnt < ADV_TOT_SG_BLOCK; sg_cnt++) {
15022 sgp = kmalloc(sizeof(adv_sgblk_t), GFP_KERNEL);
15023
15024 if (!sgp)
15025 break;
15026
15027 sgp->next_sgblkp = boardp->adv_sgblkp;
15028 boardp->adv_sgblkp = sgp;
15029
15030 }
15031
15032 ASC_DBG3(1, "advansys_wide_init_chip: sg_cnt %d * %u = %u bytes\n",
15033 sg_cnt, sizeof(adv_sgblk_t),
15034 (unsigned)(sizeof(adv_sgblk_t) * sg_cnt));
15035
15036 if (!boardp->adv_sgblkp)
15037 goto kmalloc_failed;
15038
15039 adv_dvc_varp->carrier_buf = boardp->carrp;
15040
15041 /*
15042 * Point 'adv_reqp' to the request structures and
15043 * link them together.
15044 */
15045 req_cnt--;
15046 reqp[req_cnt].next_reqp = NULL;
15047 for (; req_cnt > 0; req_cnt--) {
15048 reqp[req_cnt - 1].next_reqp = &reqp[req_cnt];
15049 }
15050 boardp->adv_reqp = &reqp[0];
15051
15052 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
15053 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc3550Driver()\n");
15054 warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
15055 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
15056 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc38C0800Driver()"
15057 "\n");
15058 warn_code = AdvInitAsc38C0800Driver(adv_dvc_varp);
15059 } else {
15060 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc38C1600Driver()"
15061 "\n");
15062 warn_code = AdvInitAsc38C1600Driver(adv_dvc_varp);
15063 }
15064 err_code = adv_dvc_varp->err_code;
15065
15066 if (warn_code || err_code) {
15067 ASC_PRINT3("advansys_wide_init_chip: board %d error: warn 0x%x,"
15068 " error 0x%x\n", boardp->id, warn_code, err_code);
15069 }
15070
15071 goto exit;
15072
15073 kmalloc_failed:
15074 ASC_PRINT1("advansys_wide_init_chip: board %d error: kmalloc() "
15075 "failed\n", boardp->id);
15076 err_code = ADV_ERROR;
15077 exit:
15078 return err_code;
15079}
15080
15081static void advansys_wide_free_mem(asc_board_t *boardp)
15082{
15083 kfree(boardp->carrp);
15084 boardp->carrp = NULL;
15085 kfree(boardp->orig_reqp);
15086 boardp->orig_reqp = boardp->adv_reqp = NULL;
15087 while (boardp->adv_sgblkp) {
15088 adv_sgblk_t *sgp = boardp->adv_sgblkp;
15089 boardp->adv_sgblkp = sgp->next_sgblkp;
15090 kfree(sgp);
15091 }
15092}
15093
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015094static struct Scsi_Host *__devinit
15095advansys_board_found(int iop, struct device *dev, int bus_type)
15096{
15097 struct Scsi_Host *shost;
15098 struct pci_dev *pdev = bus_type == ASC_IS_PCI ? to_pci_dev(dev) : NULL;
15099 asc_board_t *boardp;
15100 ASC_DVC_VAR *asc_dvc_varp = NULL;
15101 ADV_DVC_VAR *adv_dvc_varp = NULL;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060015102 int share_irq;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015103 int warn_code, err_code;
15104 int ret;
15105
15106 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015107 * Register the adapter, get its configuration, and
15108 * initialize it.
15109 */
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060015110 ASC_DBG(2, "advansys_board_found: scsi_host_alloc()\n");
15111 shost = scsi_host_alloc(&advansys_template, sizeof(asc_board_t));
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015112 if (!shost)
15113 return NULL;
15114
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015115 /* Initialize private per board data */
15116 boardp = ASC_BOARDP(shost);
15117 memset(boardp, 0, sizeof(asc_board_t));
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015118 boardp->id = asc_board_count++;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015119 spin_lock_init(&boardp->lock);
Matthew Wilcox394dbf32007-07-26 11:56:40 -040015120 boardp->dev = dev;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015121
15122 /*
15123 * Handle both narrow and wide boards.
15124 *
15125 * If a Wide board was detected, set the board structure
15126 * wide board flag. Set-up the board structure based on
15127 * the board type.
15128 */
15129#ifdef CONFIG_PCI
15130 if (bus_type == ASC_IS_PCI &&
15131 (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW ||
15132 pdev->device == PCI_DEVICE_ID_38C0800_REV1 ||
15133 pdev->device == PCI_DEVICE_ID_38C1600_REV1)) {
15134 boardp->flags |= ASC_IS_WIDE_BOARD;
15135 }
15136#endif /* CONFIG_PCI */
15137
15138 if (ASC_NARROW_BOARD(boardp)) {
15139 ASC_DBG(1, "advansys_board_found: narrow board\n");
15140 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
15141 asc_dvc_varp->bus_type = bus_type;
15142 asc_dvc_varp->drv_ptr = boardp;
15143 asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg;
15144 asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
15145 asc_dvc_varp->iop_base = iop;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015146 } else {
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040015147#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015148 ASC_DBG(1, "advansys_board_found: wide board\n");
15149 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
15150 adv_dvc_varp->drv_ptr = boardp;
15151 adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015152 if (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW) {
15153 ASC_DBG(1, "advansys_board_found: ASC-3550\n");
15154 adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
15155 } else if (pdev->device == PCI_DEVICE_ID_38C0800_REV1) {
15156 ASC_DBG(1, "advansys_board_found: ASC-38C0800\n");
15157 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
15158 } else {
15159 ASC_DBG(1, "advansys_board_found: ASC-38C1600\n");
15160 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C1600;
15161 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015162
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040015163 boardp->asc_n_io_port = pci_resource_len(pdev, 1);
15164 boardp->ioremap_addr = ioremap(pci_resource_start(pdev, 1),
15165 boardp->asc_n_io_port);
15166 if (!boardp->ioremap_addr) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015167 ASC_PRINT3
15168 ("advansys_board_found: board %d: ioremap(%x, %d) returned NULL\n",
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040015169 boardp->id, pci_resource_start(pdev, 1),
15170 boardp->asc_n_io_port);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060015171 goto err_shost;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015172 }
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040015173 adv_dvc_varp->iop_base = (AdvPortAddr)boardp->ioremap_addr
Matthew Wilcox71f36112007-07-30 08:04:53 -060015174 ASC_DBG1(1, "advansys_board_found: iop_base: 0x%lx\n",
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015175 adv_dvc_varp->iop_base);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015176
15177 /*
15178 * Even though it isn't used to access wide boards, other
15179 * than for the debug line below, save I/O Port address so
15180 * that it can be reported.
15181 */
15182 boardp->ioport = iop;
15183
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040015184 ASC_DBG2(1, "advansys_board_found: iopb_chip_id_1 0x%x, "
15185 "iopw_chip_id_0 0x%x\n", (ushort)inp(iop + 1),
15186 (ushort)inpw(iop));
15187#endif /* CONFIG_PCI */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015188 }
15189
15190#ifdef CONFIG_PROC_FS
15191 /*
15192 * Allocate buffer for printing information from
15193 * /proc/scsi/advansys/[0...].
15194 */
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060015195 boardp->prtbuf = kmalloc(ASC_PRTBUF_SIZE, GFP_KERNEL);
15196 if (!boardp->prtbuf) {
15197 ASC_PRINT2("advansys_board_found: board %d: kmalloc(%d) "
15198 "returned NULL\n", boardp->id, ASC_PRTBUF_SIZE);
15199 goto err_unmap;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015200 }
15201#endif /* CONFIG_PROC_FS */
15202
15203 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015204 /*
15205 * Set the board bus type and PCI IRQ before
15206 * calling AscInitGetConfig().
15207 */
15208 switch (asc_dvc_varp->bus_type) {
15209#ifdef CONFIG_ISA
15210 case ASC_IS_ISA:
15211 shost->unchecked_isa_dma = TRUE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060015212 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015213 break;
15214 case ASC_IS_VL:
15215 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060015216 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015217 break;
15218 case ASC_IS_EISA:
15219 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060015220 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015221 break;
15222#endif /* CONFIG_ISA */
15223#ifdef CONFIG_PCI
15224 case ASC_IS_PCI:
15225 shost->irq = asc_dvc_varp->irq_no = pdev->irq;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015226 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060015227 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015228 break;
15229#endif /* CONFIG_PCI */
15230 default:
15231 ASC_PRINT2
15232 ("advansys_board_found: board %d: unknown adapter type: %d\n",
15233 boardp->id, asc_dvc_varp->bus_type);
15234 shost->unchecked_isa_dma = TRUE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060015235 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015236 break;
15237 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015238
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015239 /*
15240 * NOTE: AscInitGetConfig() may change the board's
15241 * bus_type value. The bus_type value should no
15242 * longer be used. If the bus_type field must be
15243 * referenced only use the bit-wise AND operator "&".
15244 */
15245 ASC_DBG(2, "advansys_board_found: AscInitGetConfig()\n");
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060015246 err_code = AscInitGetConfig(boardp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015247 } else {
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060015248#ifdef CONFIG_PCI
15249 /*
15250 * For Wide boards set PCI information before calling
15251 * AdvInitGetConfig().
15252 */
15253 shost->irq = adv_dvc_varp->irq_no = pdev->irq;
15254 shost->unchecked_isa_dma = FALSE;
15255 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015256 ASC_DBG(2, "advansys_board_found: AdvInitGetConfig()\n");
Matthew Wilcox394dbf32007-07-26 11:56:40 -040015257
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060015258 err_code = AdvInitGetConfig(pdev, boardp);
15259#endif /* CONFIG_PCI */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015260 }
15261
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060015262 if (err_code != 0)
15263 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015264
15265 /*
15266 * Save the EEPROM configuration so that it can be displayed
15267 * from /proc/scsi/advansys/[0...].
15268 */
15269 if (ASC_NARROW_BOARD(boardp)) {
15270
15271 ASCEEP_CONFIG *ep;
15272
15273 /*
15274 * Set the adapter's target id bit in the 'init_tidmask' field.
15275 */
15276 boardp->init_tidmask |=
15277 ADV_TID_TO_TIDMASK(asc_dvc_varp->cfg->chip_scsi_id);
15278
15279 /*
15280 * Save EEPROM settings for the board.
15281 */
15282 ep = &boardp->eep_config.asc_eep;
15283
15284 ep->init_sdtr = asc_dvc_varp->cfg->sdtr_enable;
15285 ep->disc_enable = asc_dvc_varp->cfg->disc_enable;
15286 ep->use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled;
15287 ASC_EEP_SET_DMA_SPD(ep, asc_dvc_varp->cfg->isa_dma_speed);
15288 ep->start_motor = asc_dvc_varp->start_motor;
15289 ep->cntl = asc_dvc_varp->dvc_cntl;
15290 ep->no_scam = asc_dvc_varp->no_scam;
15291 ep->max_total_qng = asc_dvc_varp->max_total_qng;
15292 ASC_EEP_SET_CHIP_ID(ep, asc_dvc_varp->cfg->chip_scsi_id);
15293 /* 'max_tag_qng' is set to the same value for every device. */
15294 ep->max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0];
15295 ep->adapter_info[0] = asc_dvc_varp->cfg->adapter_info[0];
15296 ep->adapter_info[1] = asc_dvc_varp->cfg->adapter_info[1];
15297 ep->adapter_info[2] = asc_dvc_varp->cfg->adapter_info[2];
15298 ep->adapter_info[3] = asc_dvc_varp->cfg->adapter_info[3];
15299 ep->adapter_info[4] = asc_dvc_varp->cfg->adapter_info[4];
15300 ep->adapter_info[5] = asc_dvc_varp->cfg->adapter_info[5];
15301
15302 /*
15303 * Modify board configuration.
15304 */
15305 ASC_DBG(2, "advansys_board_found: AscInitSetConfig()\n");
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060015306 err_code = AscInitSetConfig(pdev, boardp);
15307 if (err_code)
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060015308 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015309
15310 /*
15311 * Finish initializing the 'Scsi_Host' structure.
15312 */
15313 /* AscInitSetConfig() will set the IRQ for non-PCI boards. */
15314 if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
15315 shost->irq = asc_dvc_varp->irq_no;
15316 }
15317 } else {
15318 ADVEEP_3550_CONFIG *ep_3550;
15319 ADVEEP_38C0800_CONFIG *ep_38C0800;
15320 ADVEEP_38C1600_CONFIG *ep_38C1600;
15321
15322 /*
15323 * Save Wide EEP Configuration Information.
15324 */
15325 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
15326 ep_3550 = &boardp->eep_config.adv_3550_eep;
15327
15328 ep_3550->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
15329 ep_3550->max_host_qng = adv_dvc_varp->max_host_qng;
15330 ep_3550->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
15331 ep_3550->termination = adv_dvc_varp->cfg->termination;
15332 ep_3550->disc_enable = adv_dvc_varp->cfg->disc_enable;
15333 ep_3550->bios_ctrl = adv_dvc_varp->bios_ctrl;
15334 ep_3550->wdtr_able = adv_dvc_varp->wdtr_able;
15335 ep_3550->sdtr_able = adv_dvc_varp->sdtr_able;
15336 ep_3550->ultra_able = adv_dvc_varp->ultra_able;
15337 ep_3550->tagqng_able = adv_dvc_varp->tagqng_able;
15338 ep_3550->start_motor = adv_dvc_varp->start_motor;
15339 ep_3550->scsi_reset_delay =
15340 adv_dvc_varp->scsi_reset_wait;
15341 ep_3550->serial_number_word1 =
15342 adv_dvc_varp->cfg->serial1;
15343 ep_3550->serial_number_word2 =
15344 adv_dvc_varp->cfg->serial2;
15345 ep_3550->serial_number_word3 =
15346 adv_dvc_varp->cfg->serial3;
15347 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
15348 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
15349
15350 ep_38C0800->adapter_scsi_id =
15351 adv_dvc_varp->chip_scsi_id;
15352 ep_38C0800->max_host_qng = adv_dvc_varp->max_host_qng;
15353 ep_38C0800->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
15354 ep_38C0800->termination_lvd =
15355 adv_dvc_varp->cfg->termination;
15356 ep_38C0800->disc_enable =
15357 adv_dvc_varp->cfg->disc_enable;
15358 ep_38C0800->bios_ctrl = adv_dvc_varp->bios_ctrl;
15359 ep_38C0800->wdtr_able = adv_dvc_varp->wdtr_able;
15360 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
15361 ep_38C0800->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
15362 ep_38C0800->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
15363 ep_38C0800->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
15364 ep_38C0800->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
15365 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
15366 ep_38C0800->start_motor = adv_dvc_varp->start_motor;
15367 ep_38C0800->scsi_reset_delay =
15368 adv_dvc_varp->scsi_reset_wait;
15369 ep_38C0800->serial_number_word1 =
15370 adv_dvc_varp->cfg->serial1;
15371 ep_38C0800->serial_number_word2 =
15372 adv_dvc_varp->cfg->serial2;
15373 ep_38C0800->serial_number_word3 =
15374 adv_dvc_varp->cfg->serial3;
15375 } else {
15376 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
15377
15378 ep_38C1600->adapter_scsi_id =
15379 adv_dvc_varp->chip_scsi_id;
15380 ep_38C1600->max_host_qng = adv_dvc_varp->max_host_qng;
15381 ep_38C1600->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
15382 ep_38C1600->termination_lvd =
15383 adv_dvc_varp->cfg->termination;
15384 ep_38C1600->disc_enable =
15385 adv_dvc_varp->cfg->disc_enable;
15386 ep_38C1600->bios_ctrl = adv_dvc_varp->bios_ctrl;
15387 ep_38C1600->wdtr_able = adv_dvc_varp->wdtr_able;
15388 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
15389 ep_38C1600->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
15390 ep_38C1600->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
15391 ep_38C1600->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
15392 ep_38C1600->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
15393 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
15394 ep_38C1600->start_motor = adv_dvc_varp->start_motor;
15395 ep_38C1600->scsi_reset_delay =
15396 adv_dvc_varp->scsi_reset_wait;
15397 ep_38C1600->serial_number_word1 =
15398 adv_dvc_varp->cfg->serial1;
15399 ep_38C1600->serial_number_word2 =
15400 adv_dvc_varp->cfg->serial2;
15401 ep_38C1600->serial_number_word3 =
15402 adv_dvc_varp->cfg->serial3;
15403 }
15404
15405 /*
15406 * Set the adapter's target id bit in the 'init_tidmask' field.
15407 */
15408 boardp->init_tidmask |=
15409 ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015410 }
15411
15412 /*
15413 * Channels are numbered beginning with 0. For AdvanSys one host
15414 * structure supports one channel. Multi-channel boards have a
15415 * separate host structure for each channel.
15416 */
15417 shost->max_channel = 0;
15418 if (ASC_NARROW_BOARD(boardp)) {
15419 shost->max_id = ASC_MAX_TID + 1;
15420 shost->max_lun = ASC_MAX_LUN + 1;
15421
15422 shost->io_port = asc_dvc_varp->iop_base;
15423 boardp->asc_n_io_port = ASC_IOADR_GAP;
15424 shost->this_id = asc_dvc_varp->cfg->chip_scsi_id;
15425
15426 /* Set maximum number of queues the adapter can handle. */
15427 shost->can_queue = asc_dvc_varp->max_total_qng;
15428 } else {
15429 shost->max_id = ADV_MAX_TID + 1;
15430 shost->max_lun = ADV_MAX_LUN + 1;
15431
15432 /*
15433 * Save the I/O Port address and length even though
15434 * I/O ports are not used to access Wide boards.
15435 * Instead the Wide boards are accessed with
15436 * PCI Memory Mapped I/O.
15437 */
15438 shost->io_port = iop;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015439
15440 shost->this_id = adv_dvc_varp->chip_scsi_id;
15441
15442 /* Set maximum number of queues the adapter can handle. */
15443 shost->can_queue = adv_dvc_varp->max_host_qng;
15444 }
15445
15446 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015447 * Following v1.3.89, 'cmd_per_lun' is no longer needed
15448 * and should be set to zero.
15449 *
15450 * But because of a bug introduced in v1.3.89 if the driver is
15451 * compiled as a module and 'cmd_per_lun' is zero, the Mid-Level
15452 * SCSI function 'allocate_device' will panic. To allow the driver
15453 * to work as a module in these kernels set 'cmd_per_lun' to 1.
15454 *
15455 * Note: This is wrong. cmd_per_lun should be set to the depth
15456 * you want on untagged devices always.
15457 #ifdef MODULE
15458 */
15459 shost->cmd_per_lun = 1;
15460/* #else
15461 shost->cmd_per_lun = 0;
15462#endif */
15463
15464 /*
15465 * Set the maximum number of scatter-gather elements the
15466 * adapter can handle.
15467 */
15468 if (ASC_NARROW_BOARD(boardp)) {
15469 /*
15470 * Allow two commands with 'sg_tablesize' scatter-gather
15471 * elements to be executed simultaneously. This value is
15472 * the theoretical hardware limit. It may be decreased
15473 * below.
15474 */
15475 shost->sg_tablesize =
15476 (((asc_dvc_varp->max_total_qng - 2) / 2) *
15477 ASC_SG_LIST_PER_Q) + 1;
15478 } else {
15479 shost->sg_tablesize = ADV_MAX_SG_LIST;
15480 }
15481
15482 /*
15483 * The value of 'sg_tablesize' can not exceed the SCSI
15484 * mid-level driver definition of SG_ALL. SG_ALL also
15485 * must not be exceeded, because it is used to define the
15486 * size of the scatter-gather table in 'struct asc_sg_head'.
15487 */
15488 if (shost->sg_tablesize > SG_ALL) {
15489 shost->sg_tablesize = SG_ALL;
15490 }
15491
15492 ASC_DBG1(1, "advansys_board_found: sg_tablesize: %d\n", shost->sg_tablesize);
15493
15494 /* BIOS start address. */
15495 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060015496 shost->base = AscGetChipBiosAddress(asc_dvc_varp->iop_base,
15497 asc_dvc_varp->bus_type);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015498 } else {
15499 /*
15500 * Fill-in BIOS board variables. The Wide BIOS saves
15501 * information in LRAM that is used by the driver.
15502 */
15503 AdvReadWordLram(adv_dvc_varp->iop_base,
15504 BIOS_SIGNATURE, boardp->bios_signature);
15505 AdvReadWordLram(adv_dvc_varp->iop_base,
15506 BIOS_VERSION, boardp->bios_version);
15507 AdvReadWordLram(adv_dvc_varp->iop_base,
15508 BIOS_CODESEG, boardp->bios_codeseg);
15509 AdvReadWordLram(adv_dvc_varp->iop_base,
15510 BIOS_CODELEN, boardp->bios_codelen);
15511
15512 ASC_DBG2(1,
15513 "advansys_board_found: bios_signature 0x%x, bios_version 0x%x\n",
15514 boardp->bios_signature, boardp->bios_version);
15515
15516 ASC_DBG2(1,
15517 "advansys_board_found: bios_codeseg 0x%x, bios_codelen 0x%x\n",
15518 boardp->bios_codeseg, boardp->bios_codelen);
15519
15520 /*
15521 * If the BIOS saved a valid signature, then fill in
15522 * the BIOS code segment base address.
15523 */
15524 if (boardp->bios_signature == 0x55AA) {
15525 /*
15526 * Convert x86 realmode code segment to a linear
15527 * address by shifting left 4.
15528 */
15529 shost->base = ((ulong)boardp->bios_codeseg << 4);
15530 } else {
15531 shost->base = 0;
15532 }
15533 }
15534
15535 /*
15536 * Register Board Resources - I/O Port, DMA, IRQ
15537 */
15538
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015539 /* Register DMA Channel for Narrow boards. */
15540 shost->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */
15541#ifdef CONFIG_ISA
15542 if (ASC_NARROW_BOARD(boardp)) {
15543 /* Register DMA channel for ISA bus. */
15544 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
15545 shost->dma_channel = asc_dvc_varp->cfg->isa_dma_channel;
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060015546 ret = request_dma(shost->dma_channel, "advansys");
15547 if (ret) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015548 ASC_PRINT3
15549 ("advansys_board_found: board %d: request_dma() %d failed %d\n",
15550 boardp->id, shost->dma_channel, ret);
Matthew Wilcox71f36112007-07-30 08:04:53 -060015551 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015552 }
15553 AscEnableIsaDma(shost->dma_channel);
15554 }
15555 }
15556#endif /* CONFIG_ISA */
15557
15558 /* Register IRQ Number. */
15559 ASC_DBG1(2, "advansys_board_found: request_irq() %d\n", shost->irq);
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060015560
15561 ret = request_irq(shost->irq, advansys_interrupt, share_irq,
15562 "advansys", shost);
15563
15564 if (ret) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015565 if (ret == -EBUSY) {
15566 ASC_PRINT2
15567 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x already in use.\n",
15568 boardp->id, shost->irq);
15569 } else if (ret == -EINVAL) {
15570 ASC_PRINT2
15571 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x not valid.\n",
15572 boardp->id, shost->irq);
15573 } else {
15574 ASC_PRINT3
15575 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x failed with %d\n",
15576 boardp->id, shost->irq, ret);
15577 }
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060015578 goto err_free_dma;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015579 }
15580
15581 /*
15582 * Initialize board RISC chip and enable interrupts.
15583 */
15584 if (ASC_NARROW_BOARD(boardp)) {
15585 ASC_DBG(2, "advansys_board_found: AscInitAsc1000Driver()\n");
15586 warn_code = AscInitAsc1000Driver(asc_dvc_varp);
15587 err_code = asc_dvc_varp->err_code;
15588
15589 if (warn_code || err_code) {
15590 ASC_PRINT4
15591 ("advansys_board_found: board %d error: init_state 0x%x, warn 0x%x, error 0x%x\n",
15592 boardp->id,
15593 asc_dvc_varp->init_state, warn_code, err_code);
15594 }
15595 } else {
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060015596 err_code = advansys_wide_init_chip(boardp, adv_dvc_varp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015597 }
15598
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060015599 if (err_code != 0)
15600 goto err_free_wide_mem;
15601
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015602 ASC_DBG_PRT_SCSI_HOST(2, shost);
15603
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060015604 ret = scsi_add_host(shost, dev);
15605 if (ret)
15606 goto err_free_wide_mem;
15607
15608 scsi_scan_host(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015609 return shost;
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060015610
15611 err_free_wide_mem:
15612 advansys_wide_free_mem(boardp);
15613 free_irq(shost->irq, shost);
15614 err_free_dma:
15615 if (shost->dma_channel != NO_ISA_DMA)
15616 free_dma(shost->dma_channel);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060015617 err_free_proc:
15618 kfree(boardp->prtbuf);
15619 err_unmap:
15620 if (boardp->ioremap_addr)
15621 iounmap(boardp->ioremap_addr);
15622 err_shost:
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060015623 scsi_host_put(shost);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060015624 return NULL;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015625}
15626
15627/*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015628 * advansys_release()
15629 *
15630 * Release resources allocated for a single AdvanSys adapter.
15631 */
15632static int advansys_release(struct Scsi_Host *shost)
15633{
15634 asc_board_t *boardp;
15635
15636 ASC_DBG(1, "advansys_release: begin\n");
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060015637 scsi_remove_host(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015638 boardp = ASC_BOARDP(shost);
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060015639 free_irq(shost->irq, shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015640 if (shost->dma_channel != NO_ISA_DMA) {
15641 ASC_DBG(1, "advansys_release: free_dma()\n");
15642 free_dma(shost->dma_channel);
15643 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015644 if (ASC_WIDE_BOARD(boardp)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015645 iounmap(boardp->ioremap_addr);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060015646 advansys_wide_free_mem(boardp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015647 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015648 kfree(boardp->prtbuf);
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060015649 scsi_host_put(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015650 ASC_DBG(1, "advansys_release: end\n");
15651 return 0;
15652}
15653
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015654static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __devinitdata = {
15655 0x100, 0x0110, 0x120, 0x0130, 0x140, 0x0150, 0x0190,
15656 0x0210, 0x0230, 0x0250, 0x0330
15657};
15658
15659static int __devinit advansys_isa_probe(struct device *dev, unsigned int id)
15660{
15661 PortAddr iop_base = _asc_def_iop_base[id];
15662 struct Scsi_Host *shost;
15663
15664 if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060015665 ASC_DBG1(1, "advansys_isa_match: I/O port 0x%x busy\n",
15666 iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015667 return -ENODEV;
15668 }
15669 ASC_DBG1(1, "advansys_isa_match: probing I/O port 0x%x\n", iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015670 if (!AscFindSignature(iop_base))
15671 goto nodev;
15672 if (!(AscGetChipVersion(iop_base, ASC_IS_ISA) & ASC_CHIP_VER_ISA_BIT))
15673 goto nodev;
15674
15675 shost = advansys_board_found(iop_base, dev, ASC_IS_ISA);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015676 if (!shost)
15677 goto nodev;
15678
15679 dev_set_drvdata(dev, shost);
15680 return 0;
15681
15682 nodev:
Matthew Wilcox71f36112007-07-30 08:04:53 -060015683 release_region(iop_base, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015684 return -ENODEV;
15685}
15686
15687static int __devexit advansys_isa_remove(struct device *dev, unsigned int id)
15688{
Matthew Wilcox71f36112007-07-30 08:04:53 -060015689 int ioport = _asc_def_iop_base[id];
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015690 advansys_release(dev_get_drvdata(dev));
Matthew Wilcox71f36112007-07-30 08:04:53 -060015691 release_region(ioport, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015692 return 0;
15693}
15694
15695static struct isa_driver advansys_isa_driver = {
15696 .probe = advansys_isa_probe,
15697 .remove = __devexit_p(advansys_isa_remove),
15698 .driver = {
15699 .owner = THIS_MODULE,
15700 .name = "advansys",
15701 },
15702};
15703
15704static int __devinit advansys_vlb_probe(struct device *dev, unsigned int id)
15705{
15706 PortAddr iop_base = _asc_def_iop_base[id];
15707 struct Scsi_Host *shost;
15708
15709 if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060015710 ASC_DBG1(1, "advansys_vlb_match: I/O port 0x%x busy\n",
15711 iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015712 return -ENODEV;
15713 }
15714 ASC_DBG1(1, "advansys_vlb_match: probing I/O port 0x%x\n", iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015715 if (!AscFindSignature(iop_base))
15716 goto nodev;
15717 /*
15718 * I don't think this condition can actually happen, but the old
15719 * driver did it, and the chances of finding a VLB setup in 2007
15720 * to do testing with is slight to none.
15721 */
15722 if (AscGetChipVersion(iop_base, ASC_IS_VL) > ASC_CHIP_MAX_VER_VL)
15723 goto nodev;
15724
15725 shost = advansys_board_found(iop_base, dev, ASC_IS_VL);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015726 if (!shost)
15727 goto nodev;
15728
15729 dev_set_drvdata(dev, shost);
15730 return 0;
15731
15732 nodev:
Matthew Wilcox71f36112007-07-30 08:04:53 -060015733 release_region(iop_base, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015734 return -ENODEV;
15735}
15736
15737static struct isa_driver advansys_vlb_driver = {
15738 .probe = advansys_vlb_probe,
15739 .remove = __devexit_p(advansys_isa_remove),
15740 .driver = {
15741 .owner = THIS_MODULE,
Matthew Wilcoxb8e5152b2007-09-09 08:56:26 -060015742 .name = "advansys_vlb",
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015743 },
15744};
15745
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060015746static struct eisa_device_id advansys_eisa_table[] __devinitdata = {
15747 { "ABP7401" },
15748 { "ABP7501" },
15749 { "" }
15750};
15751
15752MODULE_DEVICE_TABLE(eisa, advansys_eisa_table);
15753
15754/*
15755 * EISA is a little more tricky than PCI; each EISA device may have two
15756 * channels, and this driver is written to make each channel its own Scsi_Host
15757 */
15758struct eisa_scsi_data {
15759 struct Scsi_Host *host[2];
15760};
15761
15762static int __devinit advansys_eisa_probe(struct device *dev)
15763{
15764 int i, ioport;
15765 int err;
15766 struct eisa_device *edev = to_eisa_device(dev);
15767 struct eisa_scsi_data *data;
15768
15769 err = -ENOMEM;
15770 data = kzalloc(sizeof(*data), GFP_KERNEL);
15771 if (!data)
15772 goto fail;
15773 ioport = edev->base_addr + 0xc30;
15774
15775 err = -ENODEV;
15776 for (i = 0; i < 2; i++, ioport += 0x20) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060015777 if (!request_region(ioport, ASC_IOADR_GAP, "advansys")) {
15778 printk(KERN_WARNING "Region %x-%x busy\n", ioport,
15779 ioport + ASC_IOADR_GAP - 1);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060015780 continue;
Matthew Wilcox71f36112007-07-30 08:04:53 -060015781 }
15782 if (!AscFindSignature(ioport)) {
15783 release_region(ioport, ASC_IOADR_GAP);
15784 continue;
15785 }
15786
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060015787 /*
15788 * I don't know why we need to do this for EISA chips, but
15789 * not for any others. It looks to be equivalent to
15790 * AscGetChipCfgMsw, but I may have overlooked something,
15791 * so I'm not converting it until I get an EISA board to
15792 * test with.
15793 */
15794 inw(ioport + 4);
15795 data->host[i] = advansys_board_found(ioport, dev, ASC_IS_EISA);
Matthew Wilcox71f36112007-07-30 08:04:53 -060015796 if (data->host[i]) {
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060015797 err = 0;
Matthew Wilcox71f36112007-07-30 08:04:53 -060015798 } else {
15799 release_region(ioport, ASC_IOADR_GAP);
15800 }
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060015801 }
15802
15803 if (err) {
15804 kfree(data);
15805 } else {
15806 dev_set_drvdata(dev, data);
15807 }
15808
15809 fail:
15810 return err;
15811}
15812
15813static __devexit int advansys_eisa_remove(struct device *dev)
15814{
15815 int i;
15816 struct eisa_scsi_data *data = dev_get_drvdata(dev);
15817
15818 for (i = 0; i < 2; i++) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060015819 int ioport;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060015820 struct Scsi_Host *shost = data->host[i];
15821 if (!shost)
15822 continue;
Matthew Wilcox71f36112007-07-30 08:04:53 -060015823 ioport = shost->io_port;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060015824 advansys_release(shost);
Matthew Wilcox71f36112007-07-30 08:04:53 -060015825 release_region(ioport, ASC_IOADR_GAP);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060015826 }
15827
15828 kfree(data);
15829 return 0;
15830}
15831
15832static struct eisa_driver advansys_eisa_driver = {
15833 .id_table = advansys_eisa_table,
15834 .driver = {
15835 .name = "advansys",
15836 .probe = advansys_eisa_probe,
15837 .remove = __devexit_p(advansys_eisa_remove),
15838 }
15839};
15840
Dave Jones2672ea82006-08-02 17:11:49 -040015841/* PCI Devices supported by this driver */
15842static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015843 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A,
15844 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
15845 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940,
15846 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
15847 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940U,
15848 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
15849 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940UW,
15850 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
15851 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C0800_REV1,
15852 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
15853 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C1600_REV1,
15854 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
15855 {}
Dave Jones2672ea82006-08-02 17:11:49 -040015856};
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015857
Dave Jones2672ea82006-08-02 17:11:49 -040015858MODULE_DEVICE_TABLE(pci, advansys_pci_tbl);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015859
Matthew Wilcox9649af32007-07-26 21:51:47 -060015860static void __devinit advansys_set_latency(struct pci_dev *pdev)
15861{
15862 if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) ||
15863 (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) {
15864 pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0);
15865 } else {
15866 u8 latency;
15867 pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency);
15868 if (latency < 0x20)
15869 pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x20);
15870 }
15871}
15872
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015873static int __devinit
15874advansys_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
15875{
15876 int err, ioport;
15877 struct Scsi_Host *shost;
15878
15879 err = pci_enable_device(pdev);
15880 if (err)
15881 goto fail;
Matthew Wilcox71f36112007-07-30 08:04:53 -060015882 err = pci_request_regions(pdev, "advansys");
15883 if (err)
15884 goto disable_device;
Matthew Wilcox9649af32007-07-26 21:51:47 -060015885 pci_set_master(pdev);
15886 advansys_set_latency(pdev);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015887
15888 if (pci_resource_len(pdev, 0) == 0)
15889 goto nodev;
15890
15891 ioport = pci_resource_start(pdev, 0);
15892 shost = advansys_board_found(ioport, &pdev->dev, ASC_IS_PCI);
15893
15894 if (!shost)
15895 goto nodev;
15896
15897 pci_set_drvdata(pdev, shost);
15898 return 0;
15899
15900 nodev:
15901 err = -ENODEV;
Matthew Wilcox71f36112007-07-30 08:04:53 -060015902 pci_release_regions(pdev);
15903 disable_device:
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015904 pci_disable_device(pdev);
15905 fail:
15906 return err;
15907}
15908
15909static void __devexit advansys_pci_remove(struct pci_dev *pdev)
15910{
15911 advansys_release(pci_get_drvdata(pdev));
Matthew Wilcox71f36112007-07-30 08:04:53 -060015912 pci_release_regions(pdev);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015913 pci_disable_device(pdev);
15914}
15915
15916static struct pci_driver advansys_pci_driver = {
15917 .name = "advansys",
15918 .id_table = advansys_pci_tbl,
15919 .probe = advansys_pci_probe,
15920 .remove = __devexit_p(advansys_pci_remove),
15921};
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040015922
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060015923static int __init advansys_init(void)
15924{
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015925 int error;
15926
15927 error = isa_register_driver(&advansys_isa_driver,
15928 ASC_IOADR_TABLE_MAX_IX);
15929 if (error)
15930 goto fail;
15931
15932 error = isa_register_driver(&advansys_vlb_driver,
15933 ASC_IOADR_TABLE_MAX_IX);
15934 if (error)
15935 goto unregister_isa;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060015936
15937 error = eisa_driver_register(&advansys_eisa_driver);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015938 if (error)
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015939 goto unregister_vlb;
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060015940
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060015941 error = pci_register_driver(&advansys_pci_driver);
15942 if (error)
15943 goto unregister_eisa;
15944
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060015945 return 0;
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015946
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060015947 unregister_eisa:
15948 eisa_driver_unregister(&advansys_eisa_driver);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015949 unregister_vlb:
15950 isa_unregister_driver(&advansys_vlb_driver);
15951 unregister_isa:
15952 isa_unregister_driver(&advansys_isa_driver);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015953 fail:
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015954 return error;
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060015955}
15956
15957static void __exit advansys_exit(void)
15958{
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015959 pci_unregister_driver(&advansys_pci_driver);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060015960 eisa_driver_unregister(&advansys_eisa_driver);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015961 isa_unregister_driver(&advansys_vlb_driver);
15962 isa_unregister_driver(&advansys_isa_driver);
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060015963}
15964
15965module_init(advansys_init);
15966module_exit(advansys_exit);
15967
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040015968MODULE_LICENSE("GPL");