blob: 0303fc7dacd35238c6c04ebe879620f3e58d1bf5 [file] [log] [blame]
Matthew Wilcox01fbfe02007-09-09 08:56:40 -06001#define DRV_NAME "advansys"
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -04002#define ASC_VERSION "3.4" /* AdvanSys Driver Version */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003
4/*
5 * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
6 *
7 * Copyright (c) 1995-2000 Advanced System Products, Inc.
8 * Copyright (c) 2000-2001 ConnectCom Solutions, Inc.
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -04009 * Copyright (c) 2007 Matthew Wilcox <matthew@wil.cx>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 * All Rights Reserved.
11 *
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040012 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 */
17
18/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070019 * As of March 8, 2000 Advanced System Products, Inc. (AdvanSys)
20 * changed its name to ConnectCom Solutions, Inc.
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040021 * On June 18, 2001 Initio Corp. acquired ConnectCom's SCSI assets
Linus Torvalds1da177e2005-04-16 15:20:36 -070022 */
23
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025#include <linux/string.h>
26#include <linux/kernel.h>
27#include <linux/types.h>
28#include <linux/ioport.h>
29#include <linux/interrupt.h>
30#include <linux/delay.h>
31#include <linux/slab.h>
32#include <linux/mm.h>
33#include <linux/proc_fs.h>
34#include <linux/init.h>
35#include <linux/blkdev.h>
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060036#include <linux/isa.h>
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060037#include <linux/eisa.h>
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040038#include <linux/pci.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <linux/spinlock.h>
40#include <linux/dma-mapping.h>
41
42#include <asm/io.h>
43#include <asm/system.h>
44#include <asm/dma.h>
45
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040046#include <scsi/scsi_cmnd.h>
47#include <scsi/scsi_device.h>
48#include <scsi/scsi_tcq.h>
49#include <scsi/scsi.h>
50#include <scsi/scsi_host.h>
51
Matthew Wilcox4bd6d7f2007-07-30 08:41:03 -060052/* FIXME:
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 *
Matthew Wilcox4bd6d7f2007-07-30 08:41:03 -060054 * 1. Although all of the necessary command mapping places have the
55 * appropriate dma_map.. APIs, the driver still processes its internal
56 * queue using bus_to_virt() and virt_to_bus() which are illegal under
57 * the API. The entire queue processing structure will need to be
58 * altered to fix this.
59 * 2. Need to add memory mapping workaround. Test the memory mapping.
60 * If it doesn't work revert to I/O port access. Can a test be done
61 * safely?
62 * 3. Handle an interrupt not working. Keep an interrupt counter in
63 * the interrupt handler. In the timeout function if the interrupt
64 * has not occurred then print a message and run in polled mode.
65 * 4. Need to add support for target mode commands, cf. CAM XPT.
66 * 5. check DMA mapping functions for failure
Matthew Wilcox349d2c42007-09-09 08:56:34 -060067 * 6. Use scsi_transport_spi
68 * 7. advansys_info is not safe against multiple simultaneous callers
69 * 8. Kill boardp->id
70 * 9. 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 /proc statistics. */
75#define ADVANSYS_STATS
76
77/* Enable driver tracing. */
78/* #define ADVANSYS_DEBUG */
79
Linus Torvalds1da177e2005-04-16 15:20:36 -070080#define ASC_LIB_VERSION_MAJOR 1
81#define ASC_LIB_VERSION_MINOR 24
82#define ASC_LIB_SERIAL_NUMBER 123
83
84/*
85 * Portable Data Types
86 *
87 * Any instance where a 32-bit long or pointer type is assumed
88 * for precision or HW defined structures, the following define
89 * types must be used. In Linux the char, short, and int types
90 * are all consistent at 8, 16, and 32 bits respectively. Pointers
91 * and long types are 64 bits on Alpha and UltraSPARC.
92 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040093#define ASC_PADDR __u32 /* Physical/Bus address data type. */
94#define ASC_VADDR __u32 /* Virtual address data type. */
95#define ASC_DCNT __u32 /* Unsigned Data count type. */
96#define ASC_SDCNT __s32 /* Signed Data count type. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
98/*
99 * These macros are used to convert a virtual address to a
100 * 32-bit value. This currently can be used on Linux Alpha
101 * which uses 64-bit virtual address but a 32-bit bus address.
102 * This is likely to break in the future, but doing this now
103 * will give us time to change the HW and FW to handle 64-bit
104 * addresses.
105 */
106#define ASC_VADDR_TO_U32 virt_to_bus
107#define ASC_U32_TO_VADDR bus_to_virt
108
109typedef unsigned char uchar;
110
111#ifndef TRUE
112#define TRUE (1)
113#endif
114#ifndef FALSE
115#define FALSE (0)
116#endif
117
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118#define ERR (-1)
119#define UW_ERR (uint)(0xFFFF)
120#define isodd_word(val) ((((uint)val) & (uint)0x0001) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121
Dave Jones2672ea82006-08-02 17:11:49 -0400122#define PCI_VENDOR_ID_ASP 0x10cd
123#define PCI_DEVICE_ID_ASP_1200A 0x1100
124#define PCI_DEVICE_ID_ASP_ABP940 0x1200
125#define PCI_DEVICE_ID_ASP_ABP940U 0x1300
126#define PCI_DEVICE_ID_ASP_ABP940UW 0x2300
127#define PCI_DEVICE_ID_38C0800_REV1 0x2500
128#define PCI_DEVICE_ID_38C1600_REV1 0x2700
129
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130/*
131 * Enable CC_VERY_LONG_SG_LIST to support up to 64K element SG lists.
132 * The SRB structure will have to be changed and the ASC_SRB2SCSIQ()
133 * macro re-defined to be able to obtain a ASC_SCSI_Q pointer from the
134 * SRB structure.
135 */
136#define CC_VERY_LONG_SG_LIST 0
137#define ASC_SRB2SCSIQ(srb_ptr) (srb_ptr)
138
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400139#define PortAddr unsigned short /* port address size */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140#define inp(port) inb(port)
141#define outp(port, byte) outb((byte), (port))
142
143#define inpw(port) inw(port)
144#define outpw(port, word) outw((word), (port))
145
146#define ASC_MAX_SG_QUEUE 7
147#define ASC_MAX_SG_LIST 255
148
149#define ASC_CS_TYPE unsigned short
150
151#define ASC_IS_ISA (0x0001)
152#define ASC_IS_ISAPNP (0x0081)
153#define ASC_IS_EISA (0x0002)
154#define ASC_IS_PCI (0x0004)
155#define ASC_IS_PCI_ULTRA (0x0104)
156#define ASC_IS_PCMCIA (0x0008)
157#define ASC_IS_MCA (0x0020)
158#define ASC_IS_VL (0x0040)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159#define ASC_IS_WIDESCSI_16 (0x0100)
160#define ASC_IS_WIDESCSI_32 (0x0200)
161#define ASC_IS_BIG_ENDIAN (0x8000)
Matthew Wilcox95c9f162007-09-09 08:56:39 -0600162
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163#define ASC_CHIP_MIN_VER_VL (0x01)
164#define ASC_CHIP_MAX_VER_VL (0x07)
165#define ASC_CHIP_MIN_VER_PCI (0x09)
166#define ASC_CHIP_MAX_VER_PCI (0x0F)
167#define ASC_CHIP_VER_PCI_BIT (0x08)
168#define ASC_CHIP_MIN_VER_ISA (0x11)
169#define ASC_CHIP_MIN_VER_ISA_PNP (0x21)
170#define ASC_CHIP_MAX_VER_ISA (0x27)
171#define ASC_CHIP_VER_ISA_BIT (0x30)
172#define ASC_CHIP_VER_ISAPNP_BIT (0x20)
173#define ASC_CHIP_VER_ASYN_BUG (0x21)
174#define ASC_CHIP_VER_PCI 0x08
175#define ASC_CHIP_VER_PCI_ULTRA_3150 (ASC_CHIP_VER_PCI | 0x02)
176#define ASC_CHIP_VER_PCI_ULTRA_3050 (ASC_CHIP_VER_PCI | 0x03)
177#define ASC_CHIP_MIN_VER_EISA (0x41)
178#define ASC_CHIP_MAX_VER_EISA (0x47)
179#define ASC_CHIP_VER_EISA_BIT (0x40)
180#define ASC_CHIP_LATEST_VER_EISA ((ASC_CHIP_MIN_VER_EISA - 1) + 3)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181#define ASC_MAX_VL_DMA_COUNT (0x07FFFFFFL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182#define ASC_MAX_PCI_DMA_COUNT (0xFFFFFFFFL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183#define ASC_MAX_ISA_DMA_COUNT (0x00FFFFFFL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184
185#define ASC_SCSI_ID_BITS 3
186#define ASC_SCSI_TIX_TYPE uchar
187#define ASC_ALL_DEVICE_BIT_SET 0xFF
188#define ASC_SCSI_BIT_ID_TYPE uchar
189#define ASC_MAX_TID 7
190#define ASC_MAX_LUN 7
191#define ASC_SCSI_WIDTH_BIT_SET 0xFF
192#define ASC_MAX_SENSE_LEN 32
193#define ASC_MIN_SENSE_LEN 14
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194#define ASC_SCSI_RESET_HOLD_TIME_US 60
195
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196/*
Matthew Wilcoxf05ec592007-09-09 08:56:36 -0600197 * Narrow boards only support 12-byte commands, while wide boards
198 * extend to 16-byte commands.
199 */
200#define ASC_MAX_CDB_LEN 12
201#define ADV_MAX_CDB_LEN 16
202
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203#define MS_SDTR_LEN 0x03
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204#define MS_WDTR_LEN 0x02
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
206#define ASC_SG_LIST_PER_Q 7
207#define QS_FREE 0x00
208#define QS_READY 0x01
209#define QS_DISC1 0x02
210#define QS_DISC2 0x04
211#define QS_BUSY 0x08
212#define QS_ABORTED 0x40
213#define QS_DONE 0x80
214#define QC_NO_CALLBACK 0x01
215#define QC_SG_SWAP_QUEUE 0x02
216#define QC_SG_HEAD 0x04
217#define QC_DATA_IN 0x08
218#define QC_DATA_OUT 0x10
219#define QC_URGENT 0x20
220#define QC_MSG_OUT 0x40
221#define QC_REQ_SENSE 0x80
222#define QCSG_SG_XFER_LIST 0x02
223#define QCSG_SG_XFER_MORE 0x04
224#define QCSG_SG_XFER_END 0x08
225#define QD_IN_PROGRESS 0x00
226#define QD_NO_ERROR 0x01
227#define QD_ABORTED_BY_HOST 0x02
228#define QD_WITH_ERROR 0x04
229#define QD_INVALID_REQUEST 0x80
230#define QD_INVALID_HOST_NUM 0x81
231#define QD_INVALID_DEVICE 0x82
232#define QD_ERR_INTERNAL 0xFF
233#define QHSTA_NO_ERROR 0x00
234#define QHSTA_M_SEL_TIMEOUT 0x11
235#define QHSTA_M_DATA_OVER_RUN 0x12
236#define QHSTA_M_DATA_UNDER_RUN 0x12
237#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
238#define QHSTA_M_BAD_BUS_PHASE_SEQ 0x14
239#define QHSTA_D_QDONE_SG_LIST_CORRUPTED 0x21
240#define QHSTA_D_ASC_DVC_ERROR_CODE_SET 0x22
241#define QHSTA_D_HOST_ABORT_FAILED 0x23
242#define QHSTA_D_EXE_SCSI_Q_FAILED 0x24
243#define QHSTA_D_EXE_SCSI_Q_BUSY_TIMEOUT 0x25
244#define QHSTA_D_ASPI_NO_BUF_POOL 0x26
245#define QHSTA_M_WTM_TIMEOUT 0x41
246#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42
247#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43
248#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
249#define QHSTA_M_TARGET_STATUS_BUSY 0x45
250#define QHSTA_M_BAD_TAG_CODE 0x46
251#define QHSTA_M_BAD_QUEUE_FULL_OR_BUSY 0x47
252#define QHSTA_M_HUNG_REQ_SCSI_BUS_RESET 0x48
253#define QHSTA_D_LRAM_CMP_ERROR 0x81
254#define QHSTA_M_MICRO_CODE_ERROR_HALT 0xA1
255#define ASC_FLAG_SCSIQ_REQ 0x01
256#define ASC_FLAG_BIOS_SCSIQ_REQ 0x02
257#define ASC_FLAG_BIOS_ASYNC_IO 0x04
258#define ASC_FLAG_SRB_LINEAR_ADDR 0x08
259#define ASC_FLAG_WIN16 0x10
260#define ASC_FLAG_WIN32 0x20
261#define ASC_FLAG_ISA_OVER_16MB 0x40
262#define ASC_FLAG_DOS_VM_CALLBACK 0x80
263#define ASC_TAG_FLAG_EXTRA_BYTES 0x10
264#define ASC_TAG_FLAG_DISABLE_DISCONNECT 0x04
265#define ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX 0x08
266#define ASC_TAG_FLAG_DISABLE_CHK_COND_INT_HOST 0x40
267#define ASC_SCSIQ_CPY_BEG 4
268#define ASC_SCSIQ_SGHD_CPY_BEG 2
269#define ASC_SCSIQ_B_FWD 0
270#define ASC_SCSIQ_B_BWD 1
271#define ASC_SCSIQ_B_STATUS 2
272#define ASC_SCSIQ_B_QNO 3
273#define ASC_SCSIQ_B_CNTL 4
274#define ASC_SCSIQ_B_SG_QUEUE_CNT 5
275#define ASC_SCSIQ_D_DATA_ADDR 8
276#define ASC_SCSIQ_D_DATA_CNT 12
277#define ASC_SCSIQ_B_SENSE_LEN 20
278#define ASC_SCSIQ_DONE_INFO_BEG 22
279#define ASC_SCSIQ_D_SRBPTR 22
280#define ASC_SCSIQ_B_TARGET_IX 26
281#define ASC_SCSIQ_B_CDB_LEN 28
282#define ASC_SCSIQ_B_TAG_CODE 29
283#define ASC_SCSIQ_W_VM_ID 30
284#define ASC_SCSIQ_DONE_STATUS 32
285#define ASC_SCSIQ_HOST_STATUS 33
286#define ASC_SCSIQ_SCSI_STATUS 34
287#define ASC_SCSIQ_CDB_BEG 36
288#define ASC_SCSIQ_DW_REMAIN_XFER_ADDR 56
289#define ASC_SCSIQ_DW_REMAIN_XFER_CNT 60
290#define ASC_SCSIQ_B_FIRST_SG_WK_QP 48
291#define ASC_SCSIQ_B_SG_WK_QP 49
292#define ASC_SCSIQ_B_SG_WK_IX 50
293#define ASC_SCSIQ_W_ALT_DC1 52
294#define ASC_SCSIQ_B_LIST_CNT 6
295#define ASC_SCSIQ_B_CUR_LIST_CNT 7
296#define ASC_SGQ_B_SG_CNTL 4
297#define ASC_SGQ_B_SG_HEAD_QP 5
298#define ASC_SGQ_B_SG_LIST_CNT 6
299#define ASC_SGQ_B_SG_CUR_LIST_CNT 7
300#define ASC_SGQ_LIST_BEG 8
301#define ASC_DEF_SCSI1_QNG 4
302#define ASC_MAX_SCSI1_QNG 4
303#define ASC_DEF_SCSI2_QNG 16
304#define ASC_MAX_SCSI2_QNG 32
305#define ASC_TAG_CODE_MASK 0x23
306#define ASC_STOP_REQ_RISC_STOP 0x01
307#define ASC_STOP_ACK_RISC_STOP 0x03
308#define ASC_STOP_CLEAN_UP_BUSY_Q 0x10
309#define ASC_STOP_CLEAN_UP_DISC_Q 0x20
310#define ASC_STOP_HOST_REQ_RISC_HALT 0x40
311#define ASC_TIDLUN_TO_IX(tid, lun) (ASC_SCSI_TIX_TYPE)((tid) + ((lun)<<ASC_SCSI_ID_BITS))
312#define ASC_TID_TO_TARGET_ID(tid) (ASC_SCSI_BIT_ID_TYPE)(0x01 << (tid))
313#define ASC_TIX_TO_TARGET_ID(tix) (0x01 << ((tix) & ASC_MAX_TID))
314#define ASC_TIX_TO_TID(tix) ((tix) & ASC_MAX_TID)
315#define ASC_TID_TO_TIX(tid) ((tid) & ASC_MAX_TID)
316#define ASC_TIX_TO_LUN(tix) (((tix) >> ASC_SCSI_ID_BITS) & ASC_MAX_LUN)
317#define ASC_QNO_TO_QADDR(q_no) ((ASC_QADR_BEG)+((int)(q_no) << 6))
318
319typedef struct asc_scsiq_1 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400320 uchar status;
321 uchar q_no;
322 uchar cntl;
323 uchar sg_queue_cnt;
324 uchar target_id;
325 uchar target_lun;
326 ASC_PADDR data_addr;
327 ASC_DCNT data_cnt;
328 ASC_PADDR sense_addr;
329 uchar sense_len;
330 uchar extra_bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331} ASC_SCSIQ_1;
332
333typedef struct asc_scsiq_2 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400334 ASC_VADDR srb_ptr;
335 uchar target_ix;
336 uchar flag;
337 uchar cdb_len;
338 uchar tag_code;
339 ushort vm_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340} ASC_SCSIQ_2;
341
342typedef struct asc_scsiq_3 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400343 uchar done_stat;
344 uchar host_stat;
345 uchar scsi_stat;
346 uchar scsi_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347} ASC_SCSIQ_3;
348
349typedef struct asc_scsiq_4 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400350 uchar cdb[ASC_MAX_CDB_LEN];
351 uchar y_first_sg_list_qp;
352 uchar y_working_sg_qp;
353 uchar y_working_sg_ix;
354 uchar y_res;
355 ushort x_req_count;
356 ushort x_reconnect_rtn;
357 ASC_PADDR x_saved_data_addr;
358 ASC_DCNT x_saved_data_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359} ASC_SCSIQ_4;
360
361typedef struct asc_q_done_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400362 ASC_SCSIQ_2 d2;
363 ASC_SCSIQ_3 d3;
364 uchar q_status;
365 uchar q_no;
366 uchar cntl;
367 uchar sense_len;
368 uchar extra_bytes;
369 uchar res;
370 ASC_DCNT remain_bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371} ASC_QDONE_INFO;
372
373typedef struct asc_sg_list {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400374 ASC_PADDR addr;
375 ASC_DCNT bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376} ASC_SG_LIST;
377
378typedef struct asc_sg_head {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400379 ushort entry_cnt;
380 ushort queue_cnt;
381 ushort entry_to_copy;
382 ushort res;
383 ASC_SG_LIST sg_list[ASC_MAX_SG_LIST];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384} ASC_SG_HEAD;
385
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386typedef struct asc_scsi_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400387 ASC_SCSIQ_1 q1;
388 ASC_SCSIQ_2 q2;
389 uchar *cdbptr;
390 ASC_SG_HEAD *sg_head;
391 ushort remain_sg_entry_cnt;
392 ushort next_sg_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393} ASC_SCSI_Q;
394
395typedef struct asc_scsi_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400396 ASC_SCSIQ_1 r1;
397 ASC_SCSIQ_2 r2;
398 uchar *cdbptr;
399 ASC_SG_HEAD *sg_head;
400 uchar *sense_ptr;
401 ASC_SCSIQ_3 r3;
402 uchar cdb[ASC_MAX_CDB_LEN];
403 uchar sense[ASC_MIN_SENSE_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404} ASC_SCSI_REQ_Q;
405
406typedef struct asc_scsi_bios_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400407 ASC_SCSIQ_1 r1;
408 ASC_SCSIQ_2 r2;
409 uchar *cdbptr;
410 ASC_SG_HEAD *sg_head;
411 uchar *sense_ptr;
412 ASC_SCSIQ_3 r3;
413 uchar cdb[ASC_MAX_CDB_LEN];
414 uchar sense[ASC_MIN_SENSE_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415} ASC_SCSI_BIOS_REQ_Q;
416
417typedef struct asc_risc_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400418 uchar fwd;
419 uchar bwd;
420 ASC_SCSIQ_1 i1;
421 ASC_SCSIQ_2 i2;
422 ASC_SCSIQ_3 i3;
423 ASC_SCSIQ_4 i4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424} ASC_RISC_Q;
425
426typedef struct asc_sg_list_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400427 uchar seq_no;
428 uchar q_no;
429 uchar cntl;
430 uchar sg_head_qp;
431 uchar sg_list_cnt;
432 uchar sg_cur_list_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433} ASC_SG_LIST_Q;
434
435typedef struct asc_risc_sg_list_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400436 uchar fwd;
437 uchar bwd;
438 ASC_SG_LIST_Q sg;
439 ASC_SG_LIST sg_list[7];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440} ASC_RISC_SG_LIST_Q;
441
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442#define ASCQ_ERR_Q_STATUS 0x0D
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443#define ASCQ_ERR_CUR_QNG 0x17
444#define ASCQ_ERR_SG_Q_LINKS 0x18
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445#define ASCQ_ERR_ISR_RE_ENTRY 0x1A
446#define ASCQ_ERR_CRITICAL_RE_ENTRY 0x1B
447#define ASCQ_ERR_ISR_ON_CRITICAL 0x1C
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448
449/*
450 * Warning code values are set in ASC_DVC_VAR 'warn_code'.
451 */
452#define ASC_WARN_NO_ERROR 0x0000
453#define ASC_WARN_IO_PORT_ROTATE 0x0001
454#define ASC_WARN_EEPROM_CHKSUM 0x0002
455#define ASC_WARN_IRQ_MODIFIED 0x0004
456#define ASC_WARN_AUTO_CONFIG 0x0008
457#define ASC_WARN_CMD_QNG_CONFLICT 0x0010
458#define ASC_WARN_EEPROM_RECOVER 0x0020
459#define ASC_WARN_CFG_MSW_RECOVER 0x0040
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460
461/*
462 * Error code values are set in ASC_DVC_VAR 'err_code'.
463 */
464#define ASC_IERR_WRITE_EEPROM 0x0001
465#define ASC_IERR_MCODE_CHKSUM 0x0002
466#define ASC_IERR_SET_PC_ADDR 0x0004
467#define ASC_IERR_START_STOP_CHIP 0x0008
468#define ASC_IERR_IRQ_NO 0x0010
469#define ASC_IERR_SET_IRQ_NO 0x0020
470#define ASC_IERR_CHIP_VERSION 0x0040
471#define ASC_IERR_SET_SCSI_ID 0x0080
472#define ASC_IERR_GET_PHY_ADDR 0x0100
473#define ASC_IERR_BAD_SIGNATURE 0x0200
474#define ASC_IERR_NO_BUS_TYPE 0x0400
475#define ASC_IERR_SCAM 0x0800
476#define ASC_IERR_SET_SDTR 0x1000
477#define ASC_IERR_RW_LRAM 0x8000
478
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479#define ASC_MAX_IRQ_NO 15
480#define ASC_MIN_IRQ_NO 10
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481#define ASC_DEF_MAX_TOTAL_QNG (0xF0)
482#define ASC_MIN_TAG_Q_PER_DVC (0x04)
Matthew Wilcox95c9f162007-09-09 08:56:39 -0600483#define ASC_MIN_FREE_Q (0x02)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484#define ASC_MIN_TOTAL_QNG ((ASC_MAX_SG_QUEUE)+(ASC_MIN_FREE_Q))
485#define ASC_MAX_TOTAL_QNG 240
486#define ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG 16
487#define ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG 8
488#define ASC_MAX_PCI_INRAM_TOTAL_QNG 20
489#define ASC_MAX_INRAM_TAG_QNG 16
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490#define ASC_IOADR_GAP 0x10
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491#define ASC_MAX_SYN_XFER_NO 16
492#define ASC_SYN_MAX_OFFSET 0x0F
493#define ASC_DEF_SDTR_OFFSET 0x0F
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494#define ASC_SDTR_ULTRA_PCI_10MB_INDEX 0x02
495#define SYN_XFER_NS_0 25
496#define SYN_XFER_NS_1 30
497#define SYN_XFER_NS_2 35
498#define SYN_XFER_NS_3 40
499#define SYN_XFER_NS_4 50
500#define SYN_XFER_NS_5 60
501#define SYN_XFER_NS_6 70
502#define SYN_XFER_NS_7 85
503#define SYN_ULTRA_XFER_NS_0 12
504#define SYN_ULTRA_XFER_NS_1 19
505#define SYN_ULTRA_XFER_NS_2 25
506#define SYN_ULTRA_XFER_NS_3 32
507#define SYN_ULTRA_XFER_NS_4 38
508#define SYN_ULTRA_XFER_NS_5 44
509#define SYN_ULTRA_XFER_NS_6 50
510#define SYN_ULTRA_XFER_NS_7 57
511#define SYN_ULTRA_XFER_NS_8 63
512#define SYN_ULTRA_XFER_NS_9 69
513#define SYN_ULTRA_XFER_NS_10 75
514#define SYN_ULTRA_XFER_NS_11 82
515#define SYN_ULTRA_XFER_NS_12 88
516#define SYN_ULTRA_XFER_NS_13 94
517#define SYN_ULTRA_XFER_NS_14 100
518#define SYN_ULTRA_XFER_NS_15 107
519
520typedef struct ext_msg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400521 uchar msg_type;
522 uchar msg_len;
523 uchar msg_req;
524 union {
525 struct {
526 uchar sdtr_xfer_period;
527 uchar sdtr_req_ack_offset;
528 } sdtr;
529 struct {
530 uchar wdtr_width;
531 } wdtr;
532 struct {
533 uchar mdp_b3;
534 uchar mdp_b2;
535 uchar mdp_b1;
536 uchar mdp_b0;
537 } mdp;
538 } u_ext_msg;
539 uchar res;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540} EXT_MSG;
541
542#define xfer_period u_ext_msg.sdtr.sdtr_xfer_period
543#define req_ack_offset u_ext_msg.sdtr.sdtr_req_ack_offset
544#define wdtr_width u_ext_msg.wdtr.wdtr_width
545#define mdp_b3 u_ext_msg.mdp_b3
546#define mdp_b2 u_ext_msg.mdp_b2
547#define mdp_b1 u_ext_msg.mdp_b1
548#define mdp_b0 u_ext_msg.mdp_b0
549
550typedef struct asc_dvc_cfg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400551 ASC_SCSI_BIT_ID_TYPE can_tagged_qng;
552 ASC_SCSI_BIT_ID_TYPE cmd_qng_enabled;
553 ASC_SCSI_BIT_ID_TYPE disc_enable;
554 ASC_SCSI_BIT_ID_TYPE sdtr_enable;
555 uchar chip_scsi_id;
556 uchar isa_dma_speed;
557 uchar isa_dma_channel;
558 uchar chip_version;
559 ushort lib_serial_no;
560 ushort lib_version;
561 ushort mcode_date;
562 ushort mcode_version;
563 uchar max_tag_qng[ASC_MAX_TID + 1];
564 uchar *overrun_buf;
565 uchar sdtr_period_offset[ASC_MAX_TID + 1];
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400566 uchar adapter_info[6];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567} ASC_DVC_CFG;
568
569#define ASC_DEF_DVC_CNTL 0xFFFF
570#define ASC_DEF_CHIP_SCSI_ID 7
571#define ASC_DEF_ISA_DMA_SPEED 4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572#define ASC_INIT_STATE_BEG_GET_CFG 0x0001
573#define ASC_INIT_STATE_END_GET_CFG 0x0002
574#define ASC_INIT_STATE_BEG_SET_CFG 0x0004
575#define ASC_INIT_STATE_END_SET_CFG 0x0008
576#define ASC_INIT_STATE_BEG_LOAD_MC 0x0010
577#define ASC_INIT_STATE_END_LOAD_MC 0x0020
578#define ASC_INIT_STATE_BEG_INQUIRY 0x0040
579#define ASC_INIT_STATE_END_INQUIRY 0x0080
580#define ASC_INIT_RESET_SCSI_DONE 0x0100
581#define ASC_INIT_STATE_WITHOUT_EEP 0x8000
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582#define ASC_BUG_FIX_IF_NOT_DWB 0x0001
583#define ASC_BUG_FIX_ASYN_USE_SYN 0x0002
584#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41
585#define ASC_MIN_TAGGED_CMD 7
586#define ASC_MAX_SCSI_RESET_WAIT 30
587
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400588struct asc_dvc_var; /* Forward Declaration. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590typedef struct asc_dvc_var {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400591 PortAddr iop_base;
592 ushort err_code;
593 ushort dvc_cntl;
594 ushort bug_fix_cntl;
595 ushort bus_type;
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400596 ASC_SCSI_BIT_ID_TYPE init_sdtr;
597 ASC_SCSI_BIT_ID_TYPE sdtr_done;
598 ASC_SCSI_BIT_ID_TYPE use_tagged_qng;
599 ASC_SCSI_BIT_ID_TYPE unit_not_ready;
600 ASC_SCSI_BIT_ID_TYPE queue_full_or_busy;
601 ASC_SCSI_BIT_ID_TYPE start_motor;
602 uchar scsi_reset_wait;
603 uchar chip_no;
604 char is_in_int;
605 uchar max_total_qng;
606 uchar cur_total_qng;
607 uchar in_critical_cnt;
608 uchar irq_no;
609 uchar last_q_shortage;
610 ushort init_state;
611 uchar cur_dvc_qng[ASC_MAX_TID + 1];
612 uchar max_dvc_qng[ASC_MAX_TID + 1];
613 ASC_SCSI_Q *scsiq_busy_head[ASC_MAX_TID + 1];
614 ASC_SCSI_Q *scsiq_busy_tail[ASC_MAX_TID + 1];
615 uchar sdtr_period_tbl[ASC_MAX_SYN_XFER_NO];
616 ASC_DVC_CFG *cfg;
617 ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer_always;
618 char redo_scam;
619 ushort res2;
620 uchar dos_int13_table[ASC_MAX_TID + 1];
621 ASC_DCNT max_dma_count;
622 ASC_SCSI_BIT_ID_TYPE no_scam;
623 ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer;
624 uchar max_sdtr_index;
625 uchar host_init_sdtr_index;
626 struct asc_board *drv_ptr;
627 ASC_DCNT uc_break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628} ASC_DVC_VAR;
629
630typedef struct asc_dvc_inq_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400631 uchar type[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632} ASC_DVC_INQ_INFO;
633
634typedef struct asc_cap_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400635 ASC_DCNT lba;
636 ASC_DCNT blk_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637} ASC_CAP_INFO;
638
639typedef struct asc_cap_info_array {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400640 ASC_CAP_INFO cap_info[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641} ASC_CAP_INFO_ARRAY;
642
643#define ASC_MCNTL_NO_SEL_TIMEOUT (ushort)0x0001
644#define ASC_MCNTL_NULL_TARGET (ushort)0x0002
645#define ASC_CNTL_INITIATOR (ushort)0x0001
646#define ASC_CNTL_BIOS_GT_1GB (ushort)0x0002
647#define ASC_CNTL_BIOS_GT_2_DISK (ushort)0x0004
648#define ASC_CNTL_BIOS_REMOVABLE (ushort)0x0008
649#define ASC_CNTL_NO_SCAM (ushort)0x0010
650#define ASC_CNTL_INT_MULTI_Q (ushort)0x0080
651#define ASC_CNTL_NO_LUN_SUPPORT (ushort)0x0040
652#define ASC_CNTL_NO_VERIFY_COPY (ushort)0x0100
653#define ASC_CNTL_RESET_SCSI (ushort)0x0200
654#define ASC_CNTL_INIT_INQUIRY (ushort)0x0400
655#define ASC_CNTL_INIT_VERBOSE (ushort)0x0800
656#define ASC_CNTL_SCSI_PARITY (ushort)0x1000
657#define ASC_CNTL_BURST_MODE (ushort)0x2000
658#define ASC_CNTL_SDTR_ENABLE_ULTRA (ushort)0x4000
659#define ASC_EEP_DVC_CFG_BEG_VL 2
660#define ASC_EEP_MAX_DVC_ADDR_VL 15
661#define ASC_EEP_DVC_CFG_BEG 32
662#define ASC_EEP_MAX_DVC_ADDR 45
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663#define ASC_EEP_MAX_RETRY 20
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664
665/*
666 * These macros keep the chip SCSI id and ISA DMA speed
667 * bitfields in board order. C bitfields aren't portable
668 * between big and little-endian platforms so they are
669 * not used.
670 */
671
672#define ASC_EEP_GET_CHIP_ID(cfg) ((cfg)->id_speed & 0x0f)
673#define ASC_EEP_GET_DMA_SPD(cfg) (((cfg)->id_speed & 0xf0) >> 4)
674#define ASC_EEP_SET_CHIP_ID(cfg, sid) \
675 ((cfg)->id_speed = ((cfg)->id_speed & 0xf0) | ((sid) & ASC_MAX_TID))
676#define ASC_EEP_SET_DMA_SPD(cfg, spd) \
677 ((cfg)->id_speed = ((cfg)->id_speed & 0x0f) | ((spd) & 0x0f) << 4)
678
679typedef struct asceep_config {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400680 ushort cfg_lsw;
681 ushort cfg_msw;
682 uchar init_sdtr;
683 uchar disc_enable;
684 uchar use_cmd_qng;
685 uchar start_motor;
686 uchar max_total_qng;
687 uchar max_tag_qng;
688 uchar bios_scan;
689 uchar power_up_wait;
690 uchar no_scam;
691 uchar id_speed; /* low order 4 bits is chip scsi id */
692 /* high order 4 bits is isa dma speed */
693 uchar dos_int13_table[ASC_MAX_TID + 1];
694 uchar adapter_info[6];
695 ushort cntl;
696 ushort chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697} ASCEEP_CONFIG;
698
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699#define ASC_EEP_CMD_READ 0x80
700#define ASC_EEP_CMD_WRITE 0x40
701#define ASC_EEP_CMD_WRITE_ABLE 0x30
702#define ASC_EEP_CMD_WRITE_DISABLE 0x00
703#define ASC_OVERRUN_BSIZE 0x00000048UL
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704#define ASCV_MSGOUT_BEG 0x0000
705#define ASCV_MSGOUT_SDTR_PERIOD (ASCV_MSGOUT_BEG+3)
706#define ASCV_MSGOUT_SDTR_OFFSET (ASCV_MSGOUT_BEG+4)
707#define ASCV_BREAK_SAVED_CODE (ushort)0x0006
708#define ASCV_MSGIN_BEG (ASCV_MSGOUT_BEG+8)
709#define ASCV_MSGIN_SDTR_PERIOD (ASCV_MSGIN_BEG+3)
710#define ASCV_MSGIN_SDTR_OFFSET (ASCV_MSGIN_BEG+4)
711#define ASCV_SDTR_DATA_BEG (ASCV_MSGIN_BEG+8)
712#define ASCV_SDTR_DONE_BEG (ASCV_SDTR_DATA_BEG+8)
713#define ASCV_MAX_DVC_QNG_BEG (ushort)0x0020
714#define ASCV_BREAK_ADDR (ushort)0x0028
715#define ASCV_BREAK_NOTIFY_COUNT (ushort)0x002A
716#define ASCV_BREAK_CONTROL (ushort)0x002C
717#define ASCV_BREAK_HIT_COUNT (ushort)0x002E
718
719#define ASCV_ASCDVC_ERR_CODE_W (ushort)0x0030
720#define ASCV_MCODE_CHKSUM_W (ushort)0x0032
721#define ASCV_MCODE_SIZE_W (ushort)0x0034
722#define ASCV_STOP_CODE_B (ushort)0x0036
723#define ASCV_DVC_ERR_CODE_B (ushort)0x0037
724#define ASCV_OVERRUN_PADDR_D (ushort)0x0038
725#define ASCV_OVERRUN_BSIZE_D (ushort)0x003C
726#define ASCV_HALTCODE_W (ushort)0x0040
727#define ASCV_CHKSUM_W (ushort)0x0042
728#define ASCV_MC_DATE_W (ushort)0x0044
729#define ASCV_MC_VER_W (ushort)0x0046
730#define ASCV_NEXTRDY_B (ushort)0x0048
731#define ASCV_DONENEXT_B (ushort)0x0049
732#define ASCV_USE_TAGGED_QNG_B (ushort)0x004A
733#define ASCV_SCSIBUSY_B (ushort)0x004B
734#define ASCV_Q_DONE_IN_PROGRESS_B (ushort)0x004C
735#define ASCV_CURCDB_B (ushort)0x004D
736#define ASCV_RCLUN_B (ushort)0x004E
737#define ASCV_BUSY_QHEAD_B (ushort)0x004F
738#define ASCV_DISC1_QHEAD_B (ushort)0x0050
739#define ASCV_DISC_ENABLE_B (ushort)0x0052
740#define ASCV_CAN_TAGGED_QNG_B (ushort)0x0053
741#define ASCV_HOSTSCSI_ID_B (ushort)0x0055
742#define ASCV_MCODE_CNTL_B (ushort)0x0056
743#define ASCV_NULL_TARGET_B (ushort)0x0057
744#define ASCV_FREE_Q_HEAD_W (ushort)0x0058
745#define ASCV_DONE_Q_TAIL_W (ushort)0x005A
746#define ASCV_FREE_Q_HEAD_B (ushort)(ASCV_FREE_Q_HEAD_W+1)
747#define ASCV_DONE_Q_TAIL_B (ushort)(ASCV_DONE_Q_TAIL_W+1)
748#define ASCV_HOST_FLAG_B (ushort)0x005D
749#define ASCV_TOTAL_READY_Q_B (ushort)0x0064
750#define ASCV_VER_SERIAL_B (ushort)0x0065
751#define ASCV_HALTCODE_SAVED_W (ushort)0x0066
752#define ASCV_WTM_FLAG_B (ushort)0x0068
753#define ASCV_RISC_FLAG_B (ushort)0x006A
754#define ASCV_REQ_SG_LIST_QP (ushort)0x006B
755#define ASC_HOST_FLAG_IN_ISR 0x01
756#define ASC_HOST_FLAG_ACK_INT 0x02
757#define ASC_RISC_FLAG_GEN_INT 0x01
758#define ASC_RISC_FLAG_REQ_SG_LIST 0x02
759#define IOP_CTRL (0x0F)
760#define IOP_STATUS (0x0E)
761#define IOP_INT_ACK IOP_STATUS
762#define IOP_REG_IFC (0x0D)
763#define IOP_SYN_OFFSET (0x0B)
764#define IOP_EXTRA_CONTROL (0x0D)
765#define IOP_REG_PC (0x0C)
766#define IOP_RAM_ADDR (0x0A)
767#define IOP_RAM_DATA (0x08)
768#define IOP_EEP_DATA (0x06)
769#define IOP_EEP_CMD (0x07)
770#define IOP_VERSION (0x03)
771#define IOP_CONFIG_HIGH (0x04)
772#define IOP_CONFIG_LOW (0x02)
773#define IOP_SIG_BYTE (0x01)
774#define IOP_SIG_WORD (0x00)
775#define IOP_REG_DC1 (0x0E)
776#define IOP_REG_DC0 (0x0C)
777#define IOP_REG_SB (0x0B)
778#define IOP_REG_DA1 (0x0A)
779#define IOP_REG_DA0 (0x08)
780#define IOP_REG_SC (0x09)
781#define IOP_DMA_SPEED (0x07)
782#define IOP_REG_FLAG (0x07)
783#define IOP_FIFO_H (0x06)
784#define IOP_FIFO_L (0x04)
785#define IOP_REG_ID (0x05)
786#define IOP_REG_QP (0x03)
787#define IOP_REG_IH (0x02)
788#define IOP_REG_IX (0x01)
789#define IOP_REG_AX (0x00)
790#define IFC_REG_LOCK (0x00)
791#define IFC_REG_UNLOCK (0x09)
792#define IFC_WR_EN_FILTER (0x10)
793#define IFC_RD_NO_EEPROM (0x10)
794#define IFC_SLEW_RATE (0x20)
795#define IFC_ACT_NEG (0x40)
796#define IFC_INP_FILTER (0x80)
797#define IFC_INIT_DEFAULT (IFC_ACT_NEG | IFC_REG_UNLOCK)
798#define SC_SEL (uchar)(0x80)
799#define SC_BSY (uchar)(0x40)
800#define SC_ACK (uchar)(0x20)
801#define SC_REQ (uchar)(0x10)
802#define SC_ATN (uchar)(0x08)
803#define SC_IO (uchar)(0x04)
804#define SC_CD (uchar)(0x02)
805#define SC_MSG (uchar)(0x01)
806#define SEC_SCSI_CTL (uchar)(0x80)
807#define SEC_ACTIVE_NEGATE (uchar)(0x40)
808#define SEC_SLEW_RATE (uchar)(0x20)
809#define SEC_ENABLE_FILTER (uchar)(0x10)
810#define ASC_HALT_EXTMSG_IN (ushort)0x8000
811#define ASC_HALT_CHK_CONDITION (ushort)0x8100
812#define ASC_HALT_SS_QUEUE_FULL (ushort)0x8200
813#define ASC_HALT_DISABLE_ASYN_USE_SYN_FIX (ushort)0x8300
814#define ASC_HALT_ENABLE_ASYN_USE_SYN_FIX (ushort)0x8400
815#define ASC_HALT_SDTR_REJECTED (ushort)0x4000
816#define ASC_HALT_HOST_COPY_SG_LIST_TO_RISC ( ushort )0x2000
817#define ASC_MAX_QNO 0xF8
818#define ASC_DATA_SEC_BEG (ushort)0x0080
819#define ASC_DATA_SEC_END (ushort)0x0080
820#define ASC_CODE_SEC_BEG (ushort)0x0080
821#define ASC_CODE_SEC_END (ushort)0x0080
822#define ASC_QADR_BEG (0x4000)
823#define ASC_QADR_USED (ushort)(ASC_MAX_QNO * 64)
824#define ASC_QADR_END (ushort)0x7FFF
825#define ASC_QLAST_ADR (ushort)0x7FC0
826#define ASC_QBLK_SIZE 0x40
827#define ASC_BIOS_DATA_QBEG 0xF8
828#define ASC_MIN_ACTIVE_QNO 0x01
829#define ASC_QLINK_END 0xFF
830#define ASC_EEPROM_WORDS 0x10
831#define ASC_MAX_MGS_LEN 0x10
832#define ASC_BIOS_ADDR_DEF 0xDC00
833#define ASC_BIOS_SIZE 0x3800
834#define ASC_BIOS_RAM_OFF 0x3800
835#define ASC_BIOS_RAM_SIZE 0x800
836#define ASC_BIOS_MIN_ADDR 0xC000
837#define ASC_BIOS_MAX_ADDR 0xEC00
838#define ASC_BIOS_BANK_SIZE 0x0400
839#define ASC_MCODE_START_ADDR 0x0080
840#define ASC_CFG0_HOST_INT_ON 0x0020
841#define ASC_CFG0_BIOS_ON 0x0040
842#define ASC_CFG0_VERA_BURST_ON 0x0080
843#define ASC_CFG0_SCSI_PARITY_ON 0x0800
844#define ASC_CFG1_SCSI_TARGET_ON 0x0080
845#define ASC_CFG1_LRAM_8BITS_ON 0x0800
846#define ASC_CFG_MSW_CLR_MASK 0x3080
847#define CSW_TEST1 (ASC_CS_TYPE)0x8000
848#define CSW_AUTO_CONFIG (ASC_CS_TYPE)0x4000
849#define CSW_RESERVED1 (ASC_CS_TYPE)0x2000
850#define CSW_IRQ_WRITTEN (ASC_CS_TYPE)0x1000
851#define CSW_33MHZ_SELECTED (ASC_CS_TYPE)0x0800
852#define CSW_TEST2 (ASC_CS_TYPE)0x0400
853#define CSW_TEST3 (ASC_CS_TYPE)0x0200
854#define CSW_RESERVED2 (ASC_CS_TYPE)0x0100
855#define CSW_DMA_DONE (ASC_CS_TYPE)0x0080
856#define CSW_FIFO_RDY (ASC_CS_TYPE)0x0040
857#define CSW_EEP_READ_DONE (ASC_CS_TYPE)0x0020
858#define CSW_HALTED (ASC_CS_TYPE)0x0010
859#define CSW_SCSI_RESET_ACTIVE (ASC_CS_TYPE)0x0008
860#define CSW_PARITY_ERR (ASC_CS_TYPE)0x0004
861#define CSW_SCSI_RESET_LATCH (ASC_CS_TYPE)0x0002
862#define CSW_INT_PENDING (ASC_CS_TYPE)0x0001
863#define CIW_CLR_SCSI_RESET_INT (ASC_CS_TYPE)0x1000
864#define CIW_INT_ACK (ASC_CS_TYPE)0x0100
865#define CIW_TEST1 (ASC_CS_TYPE)0x0200
866#define CIW_TEST2 (ASC_CS_TYPE)0x0400
867#define CIW_SEL_33MHZ (ASC_CS_TYPE)0x0800
868#define CIW_IRQ_ACT (ASC_CS_TYPE)0x1000
869#define CC_CHIP_RESET (uchar)0x80
870#define CC_SCSI_RESET (uchar)0x40
871#define CC_HALT (uchar)0x20
872#define CC_SINGLE_STEP (uchar)0x10
873#define CC_DMA_ABLE (uchar)0x08
874#define CC_TEST (uchar)0x04
875#define CC_BANK_ONE (uchar)0x02
876#define CC_DIAG (uchar)0x01
877#define ASC_1000_ID0W 0x04C1
878#define ASC_1000_ID0W_FIX 0x00C1
879#define ASC_1000_ID1B 0x25
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880#define ASC_EISA_REV_IOP_MASK (0x0C83)
881#define ASC_EISA_PID_IOP_MASK (0x0C80)
882#define ASC_EISA_CFG_IOP_MASK (0x0C86)
883#define ASC_GET_EISA_SLOT(iop) (PortAddr)((iop) & 0xF000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884#define INS_HALTINT (ushort)0x6281
885#define INS_HALT (ushort)0x6280
886#define INS_SINT (ushort)0x6200
887#define INS_RFLAG_WTM (ushort)0x7380
888#define ASC_MC_SAVE_CODE_WSIZE 0x500
889#define ASC_MC_SAVE_DATA_WSIZE 0x40
890
891typedef struct asc_mc_saved {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400892 ushort data[ASC_MC_SAVE_DATA_WSIZE];
893 ushort code[ASC_MC_SAVE_CODE_WSIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894} ASC_MC_SAVED;
895
896#define AscGetQDoneInProgress(port) AscReadLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B)
897#define AscPutQDoneInProgress(port, val) AscWriteLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B, val)
898#define AscGetVarFreeQHead(port) AscReadLramWord((port), ASCV_FREE_Q_HEAD_W)
899#define AscGetVarDoneQTail(port) AscReadLramWord((port), ASCV_DONE_Q_TAIL_W)
900#define AscPutVarFreeQHead(port, val) AscWriteLramWord((port), ASCV_FREE_Q_HEAD_W, val)
901#define AscPutVarDoneQTail(port, val) AscWriteLramWord((port), ASCV_DONE_Q_TAIL_W, val)
902#define AscGetRiscVarFreeQHead(port) AscReadLramByte((port), ASCV_NEXTRDY_B)
903#define AscGetRiscVarDoneQTail(port) AscReadLramByte((port), ASCV_DONENEXT_B)
904#define AscPutRiscVarFreeQHead(port, val) AscWriteLramByte((port), ASCV_NEXTRDY_B, val)
905#define AscPutRiscVarDoneQTail(port, val) AscWriteLramByte((port), ASCV_DONENEXT_B, val)
906#define AscPutMCodeSDTRDoneAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id), (data));
907#define AscGetMCodeSDTRDoneAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id));
908#define AscPutMCodeInitSDTRAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id), data);
909#define AscGetMCodeInitSDTRAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id));
910#define AscSynIndexToPeriod(index) (uchar)(asc_dvc->sdtr_period_tbl[ (index) ])
911#define AscGetChipSignatureByte(port) (uchar)inp((port)+IOP_SIG_BYTE)
912#define AscGetChipSignatureWord(port) (ushort)inpw((port)+IOP_SIG_WORD)
913#define AscGetChipVerNo(port) (uchar)inp((port)+IOP_VERSION)
914#define AscGetChipCfgLsw(port) (ushort)inpw((port)+IOP_CONFIG_LOW)
915#define AscGetChipCfgMsw(port) (ushort)inpw((port)+IOP_CONFIG_HIGH)
916#define AscSetChipCfgLsw(port, data) outpw((port)+IOP_CONFIG_LOW, data)
917#define AscSetChipCfgMsw(port, data) outpw((port)+IOP_CONFIG_HIGH, data)
918#define AscGetChipEEPCmd(port) (uchar)inp((port)+IOP_EEP_CMD)
919#define AscSetChipEEPCmd(port, data) outp((port)+IOP_EEP_CMD, data)
920#define AscGetChipEEPData(port) (ushort)inpw((port)+IOP_EEP_DATA)
921#define AscSetChipEEPData(port, data) outpw((port)+IOP_EEP_DATA, data)
922#define AscGetChipLramAddr(port) (ushort)inpw((PortAddr)((port)+IOP_RAM_ADDR))
923#define AscSetChipLramAddr(port, addr) outpw((PortAddr)((port)+IOP_RAM_ADDR), addr)
924#define AscGetChipLramData(port) (ushort)inpw((port)+IOP_RAM_DATA)
925#define AscSetChipLramData(port, data) outpw((port)+IOP_RAM_DATA, data)
926#define AscGetChipIFC(port) (uchar)inp((port)+IOP_REG_IFC)
927#define AscSetChipIFC(port, data) outp((port)+IOP_REG_IFC, data)
928#define AscGetChipStatus(port) (ASC_CS_TYPE)inpw((port)+IOP_STATUS)
929#define AscSetChipStatus(port, cs_val) outpw((port)+IOP_STATUS, cs_val)
930#define AscGetChipControl(port) (uchar)inp((port)+IOP_CTRL)
931#define AscSetChipControl(port, cc_val) outp((port)+IOP_CTRL, cc_val)
932#define AscGetChipSyn(port) (uchar)inp((port)+IOP_SYN_OFFSET)
933#define AscSetChipSyn(port, data) outp((port)+IOP_SYN_OFFSET, data)
934#define AscSetPCAddr(port, data) outpw((port)+IOP_REG_PC, data)
935#define AscGetPCAddr(port) (ushort)inpw((port)+IOP_REG_PC)
936#define AscIsIntPending(port) (AscGetChipStatus(port) & (CSW_INT_PENDING | CSW_SCSI_RESET_LATCH))
937#define AscGetChipScsiID(port) ((AscGetChipCfgLsw(port) >> 8) & ASC_MAX_TID)
938#define AscGetExtraControl(port) (uchar)inp((port)+IOP_EXTRA_CONTROL)
939#define AscSetExtraControl(port, data) outp((port)+IOP_EXTRA_CONTROL, data)
940#define AscReadChipAX(port) (ushort)inpw((port)+IOP_REG_AX)
941#define AscWriteChipAX(port, data) outpw((port)+IOP_REG_AX, data)
942#define AscReadChipIX(port) (uchar)inp((port)+IOP_REG_IX)
943#define AscWriteChipIX(port, data) outp((port)+IOP_REG_IX, data)
944#define AscReadChipIH(port) (ushort)inpw((port)+IOP_REG_IH)
945#define AscWriteChipIH(port, data) outpw((port)+IOP_REG_IH, data)
946#define AscReadChipQP(port) (uchar)inp((port)+IOP_REG_QP)
947#define AscWriteChipQP(port, data) outp((port)+IOP_REG_QP, data)
948#define AscReadChipFIFO_L(port) (ushort)inpw((port)+IOP_REG_FIFO_L)
949#define AscWriteChipFIFO_L(port, data) outpw((port)+IOP_REG_FIFO_L, data)
950#define AscReadChipFIFO_H(port) (ushort)inpw((port)+IOP_REG_FIFO_H)
951#define AscWriteChipFIFO_H(port, data) outpw((port)+IOP_REG_FIFO_H, data)
952#define AscReadChipDmaSpeed(port) (uchar)inp((port)+IOP_DMA_SPEED)
953#define AscWriteChipDmaSpeed(port, data) outp((port)+IOP_DMA_SPEED, data)
954#define AscReadChipDA0(port) (ushort)inpw((port)+IOP_REG_DA0)
955#define AscWriteChipDA0(port) outpw((port)+IOP_REG_DA0, data)
956#define AscReadChipDA1(port) (ushort)inpw((port)+IOP_REG_DA1)
957#define AscWriteChipDA1(port) outpw((port)+IOP_REG_DA1, data)
958#define AscReadChipDC0(port) (ushort)inpw((port)+IOP_REG_DC0)
959#define AscWriteChipDC0(port) outpw((port)+IOP_REG_DC0, data)
960#define AscReadChipDC1(port) (ushort)inpw((port)+IOP_REG_DC1)
961#define AscWriteChipDC1(port) outpw((port)+IOP_REG_DC1, data)
962#define AscReadChipDvcID(port) (uchar)inp((port)+IOP_REG_ID)
963#define AscWriteChipDvcID(port, data) outp((port)+IOP_REG_ID, data)
964
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400965static int AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg);
966static int AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg);
967static void AscWaitEEPRead(void);
968static void AscWaitEEPWrite(void);
969static ushort AscReadEEPWord(PortAddr, uchar);
970static ushort AscWriteEEPWord(PortAddr, uchar, ushort);
971static ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
972static int AscSetEEPConfigOnce(PortAddr, ASCEEP_CONFIG *, ushort);
973static int AscSetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
974static int AscStartChip(PortAddr);
975static int AscStopChip(PortAddr);
976static void AscSetChipIH(PortAddr, ushort);
977static int AscIsChipHalted(PortAddr);
978static void AscAckInterrupt(PortAddr);
979static void AscDisableInterrupt(PortAddr);
980static void AscEnableInterrupt(PortAddr);
981static void AscSetBank(PortAddr, uchar);
982static int AscResetChipAndScsiBus(ASC_DVC_VAR *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400984static uchar AscGetIsaDmaSpeed(PortAddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400986static uchar AscReadLramByte(PortAddr, ushort);
987static ushort AscReadLramWord(PortAddr, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400989static ASC_DCNT AscReadLramDWord(PortAddr, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400991static void AscWriteLramWord(PortAddr, ushort, ushort);
992static void AscWriteLramByte(PortAddr, ushort, uchar);
993static ASC_DCNT AscMemSumLramWord(PortAddr, ushort, int);
994static void AscMemWordSetLram(PortAddr, ushort, ushort, int);
995static void AscMemWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
996static void AscMemDWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
997static void AscMemWordCopyPtrFromLram(PortAddr, ushort, uchar *, int);
998static ushort AscInitAscDvcVar(ASC_DVC_VAR *);
999static ushort AscInitFromEEP(ASC_DVC_VAR *);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001000static ushort AscInitMicroCodeVar(ASC_DVC_VAR *);
1001static int AscTestExternalLram(ASC_DVC_VAR *);
1002static uchar AscMsgOutSDTR(ASC_DVC_VAR *, uchar, uchar);
1003static uchar AscCalSDTRData(ASC_DVC_VAR *, uchar, uchar);
1004static void AscSetChipSDTR(PortAddr, uchar, uchar);
1005static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *, uchar);
1006static uchar AscAllocFreeQueue(PortAddr, uchar);
1007static uchar AscAllocMultipleFreeQueue(PortAddr, uchar, uchar);
1008static int AscHostReqRiscHalt(PortAddr);
1009static int AscStopQueueExe(PortAddr);
1010static int AscSendScsiQueue(ASC_DVC_VAR *,
1011 ASC_SCSI_Q *scsiq, uchar n_q_required);
1012static int AscPutReadyQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
1013static int AscPutReadySgListQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
1014static int AscSetChipSynRegAtID(PortAddr, uchar, uchar);
1015static int AscSetRunChipSynRegAtID(PortAddr, uchar, uchar);
1016static ushort AscInitLram(ASC_DVC_VAR *);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001017static int AscSetLibErrorCode(ASC_DVC_VAR *, ushort);
1018static int AscIsrChipHalted(ASC_DVC_VAR *);
1019static uchar _AscCopyLramScsiDoneQ(PortAddr, ushort,
1020 ASC_QDONE_INFO *, ASC_DCNT);
1021static int AscIsrQDone(ASC_DVC_VAR *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001023static ushort AscGetEisaChipCfg(PortAddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001025static uchar AscGetChipScsiCtrl(PortAddr);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001026static uchar AscGetChipVersion(PortAddr, ushort);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001027static ASC_DCNT AscLoadMicroCode(PortAddr, ushort, uchar *, ushort);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001028static void AscToggleIRQAct(PortAddr);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001029static void DvcPutScsiQ(PortAddr, ushort, uchar *, int);
1030static void DvcGetQinfo(PortAddr, ushort, uchar *, int);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001031static ushort AscInitAsc1000Driver(ASC_DVC_VAR *);
Matthew Wilcox47d853c2007-07-26 11:41:33 -04001032static void AscAsyncFix(ASC_DVC_VAR *, struct scsi_device *);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001033static int AscExeScsiQueue(ASC_DVC_VAR *, ASC_SCSI_Q *);
1034static int AscISR(ASC_DVC_VAR *);
1035static uint AscGetNumOfFreeQueue(ASC_DVC_VAR *, uchar, uchar);
1036static int AscSgListToQueue(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001038static void AscEnableIsaDma(uchar);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001040static const char *advansys_info(struct Scsi_Host *shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042#define ADV_LIB_VERSION_MAJOR 5
1043#define ADV_LIB_VERSION_MINOR 14
1044
1045/*
1046 * Define Adv Library required special types.
1047 */
1048
1049/*
1050 * Portable Data Types
1051 *
1052 * Any instance where a 32-bit long or pointer type is assumed
1053 * for precision or HW defined structures, the following define
1054 * types must be used. In Linux the char, short, and int types
1055 * are all consistent at 8, 16, and 32 bits respectively. Pointers
1056 * and long types are 64 bits on Alpha and UltraSPARC.
1057 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001058#define ADV_PADDR __u32 /* Physical address data type. */
1059#define ADV_VADDR __u32 /* Virtual address data type. */
1060#define ADV_DCNT __u32 /* Unsigned Data count type. */
1061#define ADV_SDCNT __s32 /* Signed Data count type. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062
1063/*
1064 * These macros are used to convert a virtual address to a
1065 * 32-bit value. This currently can be used on Linux Alpha
1066 * which uses 64-bit virtual address but a 32-bit bus address.
1067 * This is likely to break in the future, but doing this now
1068 * will give us time to change the HW and FW to handle 64-bit
1069 * addresses.
1070 */
1071#define ADV_VADDR_TO_U32 virt_to_bus
1072#define ADV_U32_TO_VADDR bus_to_virt
1073
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001074#define AdvPortAddr void __iomem * /* Virtual memory address size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075
1076/*
1077 * Define Adv Library required memory access macros.
1078 */
1079#define ADV_MEM_READB(addr) readb(addr)
1080#define ADV_MEM_READW(addr) readw(addr)
1081#define ADV_MEM_WRITEB(addr, byte) writeb(byte, addr)
1082#define ADV_MEM_WRITEW(addr, word) writew(word, addr)
1083#define ADV_MEM_WRITEDW(addr, dword) writel(dword, addr)
1084
1085#define ADV_CARRIER_COUNT (ASC_DEF_MAX_HOST_QNG + 15)
1086
1087/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 * Define total number of simultaneous maximum element scatter-gather
1089 * request blocks per wide adapter. ASC_DEF_MAX_HOST_QNG (253) is the
1090 * maximum number of outstanding commands per wide host adapter. Each
1091 * command uses one or more ADV_SG_BLOCK each with 15 scatter-gather
1092 * elements. Allow each command to have at least one ADV_SG_BLOCK structure.
1093 * This allows about 15 commands to have the maximum 17 ADV_SG_BLOCK
1094 * structures or 255 scatter-gather elements.
1095 *
1096 */
1097#define ADV_TOT_SG_BLOCK ASC_DEF_MAX_HOST_QNG
1098
1099/*
1100 * Define Adv Library required maximum number of scatter-gather
1101 * elements per request.
1102 */
1103#define ADV_MAX_SG_LIST 255
1104
1105/* Number of SG blocks needed. */
1106#define ADV_NUM_SG_BLOCK \
1107 ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)
1108
1109/* Total contiguous memory needed for SG blocks. */
1110#define ADV_SG_TOTAL_MEM_SIZE \
1111 (sizeof(ADV_SG_BLOCK) * ADV_NUM_SG_BLOCK)
1112
1113#define ADV_PAGE_SIZE PAGE_SIZE
1114
1115#define ADV_NUM_PAGE_CROSSING \
1116 ((ADV_SG_TOTAL_MEM_SIZE + (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
1117
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118#define ADV_EEP_DVC_CFG_BEGIN (0x00)
1119#define ADV_EEP_DVC_CFG_END (0x15)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001120#define ADV_EEP_DVC_CTL_BEGIN (0x16) /* location of OEM name */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121#define ADV_EEP_MAX_WORD_ADDR (0x1E)
1122
1123#define ADV_EEP_DELAY_MS 100
1124
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001125#define ADV_EEPROM_BIG_ENDIAN 0x8000 /* EEPROM Bit 15 */
1126#define ADV_EEPROM_BIOS_ENABLE 0x4000 /* EEPROM Bit 14 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127/*
1128 * For the ASC3550 Bit 13 is Termination Polarity control bit.
1129 * For later ICs Bit 13 controls whether the CIS (Card Information
1130 * Service Section) is loaded from EEPROM.
1131 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001132#define ADV_EEPROM_TERM_POL 0x2000 /* EEPROM Bit 13 */
1133#define ADV_EEPROM_CIS_LD 0x2000 /* EEPROM Bit 13 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134/*
1135 * ASC38C1600 Bit 11
1136 *
1137 * If EEPROM Bit 11 is 0 for Function 0, then Function 0 will specify
1138 * INT A in the PCI Configuration Space Int Pin field. If it is 1, then
1139 * Function 0 will specify INT B.
1140 *
1141 * If EEPROM Bit 11 is 0 for Function 1, then Function 1 will specify
1142 * INT B in the PCI Configuration Space Int Pin field. If it is 1, then
1143 * Function 1 will specify INT A.
1144 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001145#define ADV_EEPROM_INTAB 0x0800 /* EEPROM Bit 11 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001147typedef struct adveep_3550_config {
1148 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001150 ushort cfg_lsw; /* 00 power up initialization */
1151 /* bit 13 set - Term Polarity Control */
1152 /* bit 14 set - BIOS Enable */
1153 /* bit 15 set - Big Endian Mode */
1154 ushort cfg_msw; /* 01 unused */
1155 ushort disc_enable; /* 02 disconnect enable */
1156 ushort wdtr_able; /* 03 Wide DTR able */
1157 ushort sdtr_able; /* 04 Synchronous DTR able */
1158 ushort start_motor; /* 05 send start up motor */
1159 ushort tagqng_able; /* 06 tag queuing able */
1160 ushort bios_scan; /* 07 BIOS device control */
1161 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001163 uchar adapter_scsi_id; /* 09 Host Adapter ID */
1164 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001166 uchar scsi_reset_delay; /* 10 reset delay */
1167 uchar bios_id_lun; /* first boot device scsi id & lun */
1168 /* high nibble is lun */
1169 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001171 uchar termination; /* 11 0 - automatic */
1172 /* 1 - low off / high off */
1173 /* 2 - low off / high on */
1174 /* 3 - low on / high on */
1175 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001177 uchar reserved1; /* reserved byte (not used) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001179 ushort bios_ctrl; /* 12 BIOS control bits */
1180 /* bit 0 BIOS don't act as initiator. */
1181 /* bit 1 BIOS > 1 GB support */
1182 /* bit 2 BIOS > 2 Disk Support */
1183 /* bit 3 BIOS don't support removables */
1184 /* bit 4 BIOS support bootable CD */
1185 /* bit 5 BIOS scan enabled */
1186 /* bit 6 BIOS support multiple LUNs */
1187 /* bit 7 BIOS display of message */
1188 /* bit 8 SCAM disabled */
1189 /* bit 9 Reset SCSI bus during init. */
1190 /* bit 10 */
1191 /* bit 11 No verbose initialization. */
1192 /* bit 12 SCSI parity enabled */
1193 /* bit 13 */
1194 /* bit 14 */
1195 /* bit 15 */
1196 ushort ultra_able; /* 13 ULTRA speed able */
1197 ushort reserved2; /* 14 reserved */
1198 uchar max_host_qng; /* 15 maximum host queuing */
1199 uchar max_dvc_qng; /* maximum per device queuing */
1200 ushort dvc_cntl; /* 16 control bit for driver */
1201 ushort bug_fix; /* 17 control bit for bug fix */
1202 ushort serial_number_word1; /* 18 Board serial number word 1 */
1203 ushort serial_number_word2; /* 19 Board serial number word 2 */
1204 ushort serial_number_word3; /* 20 Board serial number word 3 */
1205 ushort check_sum; /* 21 EEP check sum */
1206 uchar oem_name[16]; /* 22 OEM name */
1207 ushort dvc_err_code; /* 30 last device driver error code */
1208 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
1209 ushort adv_err_addr; /* 32 last uc error address */
1210 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
1211 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
1212 ushort saved_adv_err_addr; /* 35 saved last uc error address */
1213 ushort num_of_err; /* 36 number of error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214} ADVEEP_3550_CONFIG;
1215
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001216typedef struct adveep_38C0800_config {
1217 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001219 ushort cfg_lsw; /* 00 power up initialization */
1220 /* bit 13 set - Load CIS */
1221 /* bit 14 set - BIOS Enable */
1222 /* bit 15 set - Big Endian Mode */
1223 ushort cfg_msw; /* 01 unused */
1224 ushort disc_enable; /* 02 disconnect enable */
1225 ushort wdtr_able; /* 03 Wide DTR able */
1226 ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
1227 ushort start_motor; /* 05 send start up motor */
1228 ushort tagqng_able; /* 06 tag queuing able */
1229 ushort bios_scan; /* 07 BIOS device control */
1230 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001232 uchar adapter_scsi_id; /* 09 Host Adapter ID */
1233 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001235 uchar scsi_reset_delay; /* 10 reset delay */
1236 uchar bios_id_lun; /* first boot device scsi id & lun */
1237 /* high nibble is lun */
1238 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001240 uchar termination_se; /* 11 0 - automatic */
1241 /* 1 - low off / high off */
1242 /* 2 - low off / high on */
1243 /* 3 - low on / high on */
1244 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001246 uchar termination_lvd; /* 11 0 - automatic */
1247 /* 1 - low off / high off */
1248 /* 2 - low off / high on */
1249 /* 3 - low on / high on */
1250 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001252 ushort bios_ctrl; /* 12 BIOS control bits */
1253 /* bit 0 BIOS don't act as initiator. */
1254 /* bit 1 BIOS > 1 GB support */
1255 /* bit 2 BIOS > 2 Disk Support */
1256 /* bit 3 BIOS don't support removables */
1257 /* bit 4 BIOS support bootable CD */
1258 /* bit 5 BIOS scan enabled */
1259 /* bit 6 BIOS support multiple LUNs */
1260 /* bit 7 BIOS display of message */
1261 /* bit 8 SCAM disabled */
1262 /* bit 9 Reset SCSI bus during init. */
1263 /* bit 10 */
1264 /* bit 11 No verbose initialization. */
1265 /* bit 12 SCSI parity enabled */
1266 /* bit 13 */
1267 /* bit 14 */
1268 /* bit 15 */
1269 ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
1270 ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
1271 uchar max_host_qng; /* 15 maximum host queueing */
1272 uchar max_dvc_qng; /* maximum per device queuing */
1273 ushort dvc_cntl; /* 16 control bit for driver */
1274 ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
1275 ushort serial_number_word1; /* 18 Board serial number word 1 */
1276 ushort serial_number_word2; /* 19 Board serial number word 2 */
1277 ushort serial_number_word3; /* 20 Board serial number word 3 */
1278 ushort check_sum; /* 21 EEP check sum */
1279 uchar oem_name[16]; /* 22 OEM name */
1280 ushort dvc_err_code; /* 30 last device driver error code */
1281 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
1282 ushort adv_err_addr; /* 32 last uc error address */
1283 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
1284 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
1285 ushort saved_adv_err_addr; /* 35 saved last uc error address */
1286 ushort reserved36; /* 36 reserved */
1287 ushort reserved37; /* 37 reserved */
1288 ushort reserved38; /* 38 reserved */
1289 ushort reserved39; /* 39 reserved */
1290 ushort reserved40; /* 40 reserved */
1291 ushort reserved41; /* 41 reserved */
1292 ushort reserved42; /* 42 reserved */
1293 ushort reserved43; /* 43 reserved */
1294 ushort reserved44; /* 44 reserved */
1295 ushort reserved45; /* 45 reserved */
1296 ushort reserved46; /* 46 reserved */
1297 ushort reserved47; /* 47 reserved */
1298 ushort reserved48; /* 48 reserved */
1299 ushort reserved49; /* 49 reserved */
1300 ushort reserved50; /* 50 reserved */
1301 ushort reserved51; /* 51 reserved */
1302 ushort reserved52; /* 52 reserved */
1303 ushort reserved53; /* 53 reserved */
1304 ushort reserved54; /* 54 reserved */
1305 ushort reserved55; /* 55 reserved */
1306 ushort cisptr_lsw; /* 56 CIS PTR LSW */
1307 ushort cisprt_msw; /* 57 CIS PTR MSW */
1308 ushort subsysvid; /* 58 SubSystem Vendor ID */
1309 ushort subsysid; /* 59 SubSystem ID */
1310 ushort reserved60; /* 60 reserved */
1311 ushort reserved61; /* 61 reserved */
1312 ushort reserved62; /* 62 reserved */
1313 ushort reserved63; /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314} ADVEEP_38C0800_CONFIG;
1315
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001316typedef struct adveep_38C1600_config {
1317 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001319 ushort cfg_lsw; /* 00 power up initialization */
1320 /* bit 11 set - Func. 0 INTB, Func. 1 INTA */
1321 /* clear - Func. 0 INTA, Func. 1 INTB */
1322 /* bit 13 set - Load CIS */
1323 /* bit 14 set - BIOS Enable */
1324 /* bit 15 set - Big Endian Mode */
1325 ushort cfg_msw; /* 01 unused */
1326 ushort disc_enable; /* 02 disconnect enable */
1327 ushort wdtr_able; /* 03 Wide DTR able */
1328 ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
1329 ushort start_motor; /* 05 send start up motor */
1330 ushort tagqng_able; /* 06 tag queuing able */
1331 ushort bios_scan; /* 07 BIOS device control */
1332 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001334 uchar adapter_scsi_id; /* 09 Host Adapter ID */
1335 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001337 uchar scsi_reset_delay; /* 10 reset delay */
1338 uchar bios_id_lun; /* first boot device scsi id & lun */
1339 /* high nibble is lun */
1340 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001342 uchar termination_se; /* 11 0 - automatic */
1343 /* 1 - low off / high off */
1344 /* 2 - low off / high on */
1345 /* 3 - low on / high on */
1346 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001348 uchar termination_lvd; /* 11 0 - automatic */
1349 /* 1 - low off / high off */
1350 /* 2 - low off / high on */
1351 /* 3 - low on / high on */
1352 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001354 ushort bios_ctrl; /* 12 BIOS control bits */
1355 /* bit 0 BIOS don't act as initiator. */
1356 /* bit 1 BIOS > 1 GB support */
1357 /* bit 2 BIOS > 2 Disk Support */
1358 /* bit 3 BIOS don't support removables */
1359 /* bit 4 BIOS support bootable CD */
1360 /* bit 5 BIOS scan enabled */
1361 /* bit 6 BIOS support multiple LUNs */
1362 /* bit 7 BIOS display of message */
1363 /* bit 8 SCAM disabled */
1364 /* bit 9 Reset SCSI bus during init. */
1365 /* bit 10 Basic Integrity Checking disabled */
1366 /* bit 11 No verbose initialization. */
1367 /* bit 12 SCSI parity enabled */
1368 /* bit 13 AIPP (Asyn. Info. Ph. Prot.) dis. */
1369 /* bit 14 */
1370 /* bit 15 */
1371 ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
1372 ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
1373 uchar max_host_qng; /* 15 maximum host queueing */
1374 uchar max_dvc_qng; /* maximum per device queuing */
1375 ushort dvc_cntl; /* 16 control bit for driver */
1376 ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
1377 ushort serial_number_word1; /* 18 Board serial number word 1 */
1378 ushort serial_number_word2; /* 19 Board serial number word 2 */
1379 ushort serial_number_word3; /* 20 Board serial number word 3 */
1380 ushort check_sum; /* 21 EEP check sum */
1381 uchar oem_name[16]; /* 22 OEM name */
1382 ushort dvc_err_code; /* 30 last device driver error code */
1383 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
1384 ushort adv_err_addr; /* 32 last uc error address */
1385 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
1386 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
1387 ushort saved_adv_err_addr; /* 35 saved last uc error address */
1388 ushort reserved36; /* 36 reserved */
1389 ushort reserved37; /* 37 reserved */
1390 ushort reserved38; /* 38 reserved */
1391 ushort reserved39; /* 39 reserved */
1392 ushort reserved40; /* 40 reserved */
1393 ushort reserved41; /* 41 reserved */
1394 ushort reserved42; /* 42 reserved */
1395 ushort reserved43; /* 43 reserved */
1396 ushort reserved44; /* 44 reserved */
1397 ushort reserved45; /* 45 reserved */
1398 ushort reserved46; /* 46 reserved */
1399 ushort reserved47; /* 47 reserved */
1400 ushort reserved48; /* 48 reserved */
1401 ushort reserved49; /* 49 reserved */
1402 ushort reserved50; /* 50 reserved */
1403 ushort reserved51; /* 51 reserved */
1404 ushort reserved52; /* 52 reserved */
1405 ushort reserved53; /* 53 reserved */
1406 ushort reserved54; /* 54 reserved */
1407 ushort reserved55; /* 55 reserved */
1408 ushort cisptr_lsw; /* 56 CIS PTR LSW */
1409 ushort cisprt_msw; /* 57 CIS PTR MSW */
1410 ushort subsysvid; /* 58 SubSystem Vendor ID */
1411 ushort subsysid; /* 59 SubSystem ID */
1412 ushort reserved60; /* 60 reserved */
1413 ushort reserved61; /* 61 reserved */
1414 ushort reserved62; /* 62 reserved */
1415 ushort reserved63; /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416} ADVEEP_38C1600_CONFIG;
1417
1418/*
1419 * EEPROM Commands
1420 */
1421#define ASC_EEP_CMD_DONE 0x0200
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422
1423/* bios_ctrl */
1424#define BIOS_CTRL_BIOS 0x0001
1425#define BIOS_CTRL_EXTENDED_XLAT 0x0002
1426#define BIOS_CTRL_GT_2_DISK 0x0004
1427#define BIOS_CTRL_BIOS_REMOVABLE 0x0008
1428#define BIOS_CTRL_BOOTABLE_CD 0x0010
1429#define BIOS_CTRL_MULTIPLE_LUN 0x0040
1430#define BIOS_CTRL_DISPLAY_MSG 0x0080
1431#define BIOS_CTRL_NO_SCAM 0x0100
1432#define BIOS_CTRL_RESET_SCSI_BUS 0x0200
1433#define BIOS_CTRL_INIT_VERBOSE 0x0800
1434#define BIOS_CTRL_SCSI_PARITY 0x1000
1435#define BIOS_CTRL_AIPP_DIS 0x2000
1436
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001437#define ADV_3550_MEMSIZE 0x2000 /* 8 KB Internal Memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001439#define ADV_38C0800_MEMSIZE 0x4000 /* 16 KB Internal Memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440
1441/*
1442 * XXX - Since ASC38C1600 Rev.3 has a local RAM failure issue, there is
1443 * a special 16K Adv Library and Microcode version. After the issue is
1444 * resolved, should restore 32K support.
1445 *
1446 * #define ADV_38C1600_MEMSIZE 0x8000L * 32 KB Internal Memory *
1447 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001448#define ADV_38C1600_MEMSIZE 0x4000 /* 16 KB Internal Memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449
1450/*
1451 * Byte I/O register address from base of 'iop_base'.
1452 */
1453#define IOPB_INTR_STATUS_REG 0x00
1454#define IOPB_CHIP_ID_1 0x01
1455#define IOPB_INTR_ENABLES 0x02
1456#define IOPB_CHIP_TYPE_REV 0x03
1457#define IOPB_RES_ADDR_4 0x04
1458#define IOPB_RES_ADDR_5 0x05
1459#define IOPB_RAM_DATA 0x06
1460#define IOPB_RES_ADDR_7 0x07
1461#define IOPB_FLAG_REG 0x08
1462#define IOPB_RES_ADDR_9 0x09
1463#define IOPB_RISC_CSR 0x0A
1464#define IOPB_RES_ADDR_B 0x0B
1465#define IOPB_RES_ADDR_C 0x0C
1466#define IOPB_RES_ADDR_D 0x0D
1467#define IOPB_SOFT_OVER_WR 0x0E
1468#define IOPB_RES_ADDR_F 0x0F
1469#define IOPB_MEM_CFG 0x10
1470#define IOPB_RES_ADDR_11 0x11
1471#define IOPB_GPIO_DATA 0x12
1472#define IOPB_RES_ADDR_13 0x13
1473#define IOPB_FLASH_PAGE 0x14
1474#define IOPB_RES_ADDR_15 0x15
1475#define IOPB_GPIO_CNTL 0x16
1476#define IOPB_RES_ADDR_17 0x17
1477#define IOPB_FLASH_DATA 0x18
1478#define IOPB_RES_ADDR_19 0x19
1479#define IOPB_RES_ADDR_1A 0x1A
1480#define IOPB_RES_ADDR_1B 0x1B
1481#define IOPB_RES_ADDR_1C 0x1C
1482#define IOPB_RES_ADDR_1D 0x1D
1483#define IOPB_RES_ADDR_1E 0x1E
1484#define IOPB_RES_ADDR_1F 0x1F
1485#define IOPB_DMA_CFG0 0x20
1486#define IOPB_DMA_CFG1 0x21
1487#define IOPB_TICKLE 0x22
1488#define IOPB_DMA_REG_WR 0x23
1489#define IOPB_SDMA_STATUS 0x24
1490#define IOPB_SCSI_BYTE_CNT 0x25
1491#define IOPB_HOST_BYTE_CNT 0x26
1492#define IOPB_BYTE_LEFT_TO_XFER 0x27
1493#define IOPB_BYTE_TO_XFER_0 0x28
1494#define IOPB_BYTE_TO_XFER_1 0x29
1495#define IOPB_BYTE_TO_XFER_2 0x2A
1496#define IOPB_BYTE_TO_XFER_3 0x2B
1497#define IOPB_ACC_GRP 0x2C
1498#define IOPB_RES_ADDR_2D 0x2D
1499#define IOPB_DEV_ID 0x2E
1500#define IOPB_RES_ADDR_2F 0x2F
1501#define IOPB_SCSI_DATA 0x30
1502#define IOPB_RES_ADDR_31 0x31
1503#define IOPB_RES_ADDR_32 0x32
1504#define IOPB_SCSI_DATA_HSHK 0x33
1505#define IOPB_SCSI_CTRL 0x34
1506#define IOPB_RES_ADDR_35 0x35
1507#define IOPB_RES_ADDR_36 0x36
1508#define IOPB_RES_ADDR_37 0x37
1509#define IOPB_RAM_BIST 0x38
1510#define IOPB_PLL_TEST 0x39
1511#define IOPB_PCI_INT_CFG 0x3A
1512#define IOPB_RES_ADDR_3B 0x3B
1513#define IOPB_RFIFO_CNT 0x3C
1514#define IOPB_RES_ADDR_3D 0x3D
1515#define IOPB_RES_ADDR_3E 0x3E
1516#define IOPB_RES_ADDR_3F 0x3F
1517
1518/*
1519 * Word I/O register address from base of 'iop_base'.
1520 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001521#define IOPW_CHIP_ID_0 0x00 /* CID0 */
1522#define IOPW_CTRL_REG 0x02 /* CC */
1523#define IOPW_RAM_ADDR 0x04 /* LA */
1524#define IOPW_RAM_DATA 0x06 /* LD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525#define IOPW_RES_ADDR_08 0x08
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001526#define IOPW_RISC_CSR 0x0A /* CSR */
1527#define IOPW_SCSI_CFG0 0x0C /* CFG0 */
1528#define IOPW_SCSI_CFG1 0x0E /* CFG1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529#define IOPW_RES_ADDR_10 0x10
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001530#define IOPW_SEL_MASK 0x12 /* SM */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531#define IOPW_RES_ADDR_14 0x14
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001532#define IOPW_FLASH_ADDR 0x16 /* FA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533#define IOPW_RES_ADDR_18 0x18
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001534#define IOPW_EE_CMD 0x1A /* EC */
1535#define IOPW_EE_DATA 0x1C /* ED */
1536#define IOPW_SFIFO_CNT 0x1E /* SFC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537#define IOPW_RES_ADDR_20 0x20
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001538#define IOPW_Q_BASE 0x22 /* QB */
1539#define IOPW_QP 0x24 /* QP */
1540#define IOPW_IX 0x26 /* IX */
1541#define IOPW_SP 0x28 /* SP */
1542#define IOPW_PC 0x2A /* PC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543#define IOPW_RES_ADDR_2C 0x2C
1544#define IOPW_RES_ADDR_2E 0x2E
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001545#define IOPW_SCSI_DATA 0x30 /* SD */
1546#define IOPW_SCSI_DATA_HSHK 0x32 /* SDH */
1547#define IOPW_SCSI_CTRL 0x34 /* SC */
1548#define IOPW_HSHK_CFG 0x36 /* HCFG */
1549#define IOPW_SXFR_STATUS 0x36 /* SXS */
1550#define IOPW_SXFR_CNTL 0x38 /* SXL */
1551#define IOPW_SXFR_CNTH 0x3A /* SXH */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552#define IOPW_RES_ADDR_3C 0x3C
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001553#define IOPW_RFIFO_DATA 0x3E /* RFD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554
1555/*
1556 * Doubleword I/O register address from base of 'iop_base'.
1557 */
1558#define IOPDW_RES_ADDR_0 0x00
1559#define IOPDW_RAM_DATA 0x04
1560#define IOPDW_RES_ADDR_8 0x08
1561#define IOPDW_RES_ADDR_C 0x0C
1562#define IOPDW_RES_ADDR_10 0x10
1563#define IOPDW_COMMA 0x14
1564#define IOPDW_COMMB 0x18
1565#define IOPDW_RES_ADDR_1C 0x1C
1566#define IOPDW_SDMA_ADDR0 0x20
1567#define IOPDW_SDMA_ADDR1 0x24
1568#define IOPDW_SDMA_COUNT 0x28
1569#define IOPDW_SDMA_ERROR 0x2C
1570#define IOPDW_RDMA_ADDR0 0x30
1571#define IOPDW_RDMA_ADDR1 0x34
1572#define IOPDW_RDMA_COUNT 0x38
1573#define IOPDW_RDMA_ERROR 0x3C
1574
1575#define ADV_CHIP_ID_BYTE 0x25
1576#define ADV_CHIP_ID_WORD 0x04C1
1577
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578#define ADV_INTR_ENABLE_HOST_INTR 0x01
1579#define ADV_INTR_ENABLE_SEL_INTR 0x02
1580#define ADV_INTR_ENABLE_DPR_INTR 0x04
1581#define ADV_INTR_ENABLE_RTA_INTR 0x08
1582#define ADV_INTR_ENABLE_RMA_INTR 0x10
1583#define ADV_INTR_ENABLE_RST_INTR 0x20
1584#define ADV_INTR_ENABLE_DPE_INTR 0x40
1585#define ADV_INTR_ENABLE_GLOBAL_INTR 0x80
1586
1587#define ADV_INTR_STATUS_INTRA 0x01
1588#define ADV_INTR_STATUS_INTRB 0x02
1589#define ADV_INTR_STATUS_INTRC 0x04
1590
1591#define ADV_RISC_CSR_STOP (0x0000)
1592#define ADV_RISC_TEST_COND (0x2000)
1593#define ADV_RISC_CSR_RUN (0x4000)
1594#define ADV_RISC_CSR_SINGLE_STEP (0x8000)
1595
1596#define ADV_CTRL_REG_HOST_INTR 0x0100
1597#define ADV_CTRL_REG_SEL_INTR 0x0200
1598#define ADV_CTRL_REG_DPR_INTR 0x0400
1599#define ADV_CTRL_REG_RTA_INTR 0x0800
1600#define ADV_CTRL_REG_RMA_INTR 0x1000
1601#define ADV_CTRL_REG_RES_BIT14 0x2000
1602#define ADV_CTRL_REG_DPE_INTR 0x4000
1603#define ADV_CTRL_REG_POWER_DONE 0x8000
1604#define ADV_CTRL_REG_ANY_INTR 0xFF00
1605
1606#define ADV_CTRL_REG_CMD_RESET 0x00C6
1607#define ADV_CTRL_REG_CMD_WR_IO_REG 0x00C5
1608#define ADV_CTRL_REG_CMD_RD_IO_REG 0x00C4
1609#define ADV_CTRL_REG_CMD_WR_PCI_CFG_SPACE 0x00C3
1610#define ADV_CTRL_REG_CMD_RD_PCI_CFG_SPACE 0x00C2
1611
1612#define ADV_TICKLE_NOP 0x00
1613#define ADV_TICKLE_A 0x01
1614#define ADV_TICKLE_B 0x02
1615#define ADV_TICKLE_C 0x03
1616
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617#define AdvIsIntPending(port) \
1618 (AdvReadWordRegister(port, IOPW_CTRL_REG) & ADV_CTRL_REG_HOST_INTR)
1619
1620/*
1621 * SCSI_CFG0 Register bit definitions
1622 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001623#define TIMER_MODEAB 0xC000 /* Watchdog, Second, and Select. Timer Ctrl. */
1624#define PARITY_EN 0x2000 /* Enable SCSI Parity Error detection */
1625#define EVEN_PARITY 0x1000 /* Select Even Parity */
1626#define WD_LONG 0x0800 /* Watchdog Interval, 1: 57 min, 0: 13 sec */
1627#define QUEUE_128 0x0400 /* Queue Size, 1: 128 byte, 0: 64 byte */
1628#define PRIM_MODE 0x0100 /* Primitive SCSI mode */
1629#define SCAM_EN 0x0080 /* Enable SCAM selection */
1630#define SEL_TMO_LONG 0x0040 /* Sel/Resel Timeout, 1: 400 ms, 0: 1.6 ms */
1631#define CFRM_ID 0x0020 /* SCAM id sel. confirm., 1: fast, 0: 6.4 ms */
1632#define OUR_ID_EN 0x0010 /* Enable OUR_ID bits */
1633#define OUR_ID 0x000F /* SCSI ID */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634
1635/*
1636 * SCSI_CFG1 Register bit definitions
1637 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001638#define BIG_ENDIAN 0x8000 /* Enable Big Endian Mode MIO:15, EEP:15 */
1639#define TERM_POL 0x2000 /* Terminator Polarity Ctrl. MIO:13, EEP:13 */
1640#define SLEW_RATE 0x1000 /* SCSI output buffer slew rate */
1641#define FILTER_SEL 0x0C00 /* Filter Period Selection */
1642#define FLTR_DISABLE 0x0000 /* Input Filtering Disabled */
1643#define FLTR_11_TO_20NS 0x0800 /* Input Filtering 11ns to 20ns */
1644#define FLTR_21_TO_39NS 0x0C00 /* Input Filtering 21ns to 39ns */
1645#define ACTIVE_DBL 0x0200 /* Disable Active Negation */
1646#define DIFF_MODE 0x0100 /* SCSI differential Mode (Read-Only) */
1647#define DIFF_SENSE 0x0080 /* 1: No SE cables, 0: SE cable (Read-Only) */
1648#define TERM_CTL_SEL 0x0040 /* Enable TERM_CTL_H and TERM_CTL_L */
1649#define TERM_CTL 0x0030 /* External SCSI Termination Bits */
1650#define TERM_CTL_H 0x0020 /* Enable External SCSI Upper Termination */
1651#define TERM_CTL_L 0x0010 /* Enable External SCSI Lower Termination */
1652#define CABLE_DETECT 0x000F /* External SCSI Cable Connection Status */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653
1654/*
1655 * Addendum for ASC-38C0800 Chip
1656 *
1657 * The ASC-38C1600 Chip uses the same definitions except that the
1658 * bus mode override bits [12:10] have been moved to byte register
1659 * offset 0xE (IOPB_SOFT_OVER_WR) bits [12:10]. The [12:10] bits in
1660 * SCSI_CFG1 are read-only and always available. Bit 14 (DIS_TERM_DRV)
1661 * is not needed. The [12:10] bits in IOPB_SOFT_OVER_WR are write-only.
1662 * Also each ASC-38C1600 function or channel uses only cable bits [5:4]
1663 * and [1:0]. Bits [14], [7:6], [3:2] are unused.
1664 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001665#define DIS_TERM_DRV 0x4000 /* 1: Read c_det[3:0], 0: cannot read */
1666#define HVD_LVD_SE 0x1C00 /* Device Detect Bits */
1667#define HVD 0x1000 /* HVD Device Detect */
1668#define LVD 0x0800 /* LVD Device Detect */
1669#define SE 0x0400 /* SE Device Detect */
1670#define TERM_LVD 0x00C0 /* LVD Termination Bits */
1671#define TERM_LVD_HI 0x0080 /* Enable LVD Upper Termination */
1672#define TERM_LVD_LO 0x0040 /* Enable LVD Lower Termination */
1673#define TERM_SE 0x0030 /* SE Termination Bits */
1674#define TERM_SE_HI 0x0020 /* Enable SE Upper Termination */
1675#define TERM_SE_LO 0x0010 /* Enable SE Lower Termination */
1676#define C_DET_LVD 0x000C /* LVD Cable Detect Bits */
1677#define C_DET3 0x0008 /* Cable Detect for LVD External Wide */
1678#define C_DET2 0x0004 /* Cable Detect for LVD Internal Wide */
1679#define C_DET_SE 0x0003 /* SE Cable Detect Bits */
1680#define C_DET1 0x0002 /* Cable Detect for SE Internal Wide */
1681#define C_DET0 0x0001 /* Cable Detect for SE Internal Narrow */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682
1683#define CABLE_ILLEGAL_A 0x7
1684 /* x 0 0 0 | on on | Illegal (all 3 connectors are used) */
1685
1686#define CABLE_ILLEGAL_B 0xB
1687 /* 0 x 0 0 | on on | Illegal (all 3 connectors are used) */
1688
1689/*
1690 * MEM_CFG Register bit definitions
1691 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001692#define BIOS_EN 0x40 /* BIOS Enable MIO:14,EEP:14 */
1693#define FAST_EE_CLK 0x20 /* Diagnostic Bit */
1694#define RAM_SZ 0x1C /* Specify size of RAM to RISC */
1695#define RAM_SZ_2KB 0x00 /* 2 KB */
1696#define RAM_SZ_4KB 0x04 /* 4 KB */
1697#define RAM_SZ_8KB 0x08 /* 8 KB */
1698#define RAM_SZ_16KB 0x0C /* 16 KB */
1699#define RAM_SZ_32KB 0x10 /* 32 KB */
1700#define RAM_SZ_64KB 0x14 /* 64 KB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701
1702/*
1703 * DMA_CFG0 Register bit definitions
1704 *
1705 * This register is only accessible to the host.
1706 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001707#define BC_THRESH_ENB 0x80 /* PCI DMA Start Conditions */
1708#define FIFO_THRESH 0x70 /* PCI DMA FIFO Threshold */
1709#define FIFO_THRESH_16B 0x00 /* 16 bytes */
1710#define FIFO_THRESH_32B 0x20 /* 32 bytes */
1711#define FIFO_THRESH_48B 0x30 /* 48 bytes */
1712#define FIFO_THRESH_64B 0x40 /* 64 bytes */
1713#define FIFO_THRESH_80B 0x50 /* 80 bytes (default) */
1714#define FIFO_THRESH_96B 0x60 /* 96 bytes */
1715#define FIFO_THRESH_112B 0x70 /* 112 bytes */
1716#define START_CTL 0x0C /* DMA start conditions */
1717#define START_CTL_TH 0x00 /* Wait threshold level (default) */
1718#define START_CTL_ID 0x04 /* Wait SDMA/SBUS idle */
1719#define START_CTL_THID 0x08 /* Wait threshold and SDMA/SBUS idle */
1720#define START_CTL_EMFU 0x0C /* Wait SDMA FIFO empty/full */
1721#define READ_CMD 0x03 /* Memory Read Method */
1722#define READ_CMD_MR 0x00 /* Memory Read */
1723#define READ_CMD_MRL 0x02 /* Memory Read Long */
1724#define READ_CMD_MRM 0x03 /* Memory Read Multiple (default) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725
1726/*
1727 * ASC-38C0800 RAM BIST Register bit definitions
1728 */
1729#define RAM_TEST_MODE 0x80
1730#define PRE_TEST_MODE 0x40
1731#define NORMAL_MODE 0x00
1732#define RAM_TEST_DONE 0x10
1733#define RAM_TEST_STATUS 0x0F
1734#define RAM_TEST_HOST_ERROR 0x08
1735#define RAM_TEST_INTRAM_ERROR 0x04
1736#define RAM_TEST_RISC_ERROR 0x02
1737#define RAM_TEST_SCSI_ERROR 0x01
1738#define RAM_TEST_SUCCESS 0x00
1739#define PRE_TEST_VALUE 0x05
1740#define NORMAL_VALUE 0x00
1741
1742/*
1743 * ASC38C1600 Definitions
1744 *
1745 * IOPB_PCI_INT_CFG Bit Field Definitions
1746 */
1747
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001748#define INTAB_LD 0x80 /* Value loaded from EEPROM Bit 11. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749
1750/*
1751 * Bit 1 can be set to change the interrupt for the Function to operate in
1752 * Totem Pole mode. By default Bit 1 is 0 and the interrupt operates in
1753 * Open Drain mode. Both functions of the ASC38C1600 must be set to the same
1754 * mode, otherwise the operating mode is undefined.
1755 */
1756#define TOTEMPOLE 0x02
1757
1758/*
1759 * Bit 0 can be used to change the Int Pin for the Function. The value is
1760 * 0 by default for both Functions with Function 0 using INT A and Function
1761 * B using INT B. For Function 0 if set, INT B is used. For Function 1 if set,
1762 * INT A is used.
1763 *
1764 * EEPROM Word 0 Bit 11 for each Function may change the initial Int Pin
1765 * value specified in the PCI Configuration Space.
1766 */
1767#define INTAB 0x01
1768
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769/*
1770 * Adv Library Status Definitions
1771 */
1772#define ADV_TRUE 1
1773#define ADV_FALSE 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774#define ADV_SUCCESS 1
1775#define ADV_BUSY 0
1776#define ADV_ERROR (-1)
1777
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778/*
1779 * ADV_DVC_VAR 'warn_code' values
1780 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001781#define ASC_WARN_BUSRESET_ERROR 0x0001 /* SCSI Bus Reset error */
1782#define ASC_WARN_EEPROM_CHKSUM 0x0002 /* EEP check sum error */
1783#define ASC_WARN_EEPROM_TERMINATION 0x0004 /* EEP termination bad field */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001784#define ASC_WARN_ERROR 0xFFFF /* ADV_ERROR return */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001786#define ADV_MAX_TID 15 /* max. target identifier */
1787#define ADV_MAX_LUN 7 /* max. logical unit number */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788
1789/*
1790 * Error code values are set in ADV_DVC_VAR 'err_code'.
1791 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001792#define ASC_IERR_WRITE_EEPROM 0x0001 /* write EEPROM error */
1793#define ASC_IERR_MCODE_CHKSUM 0x0002 /* micro code check sum error */
1794#define ASC_IERR_NO_CARRIER 0x0004 /* No more carrier memory. */
1795#define ASC_IERR_START_STOP_CHIP 0x0008 /* start/stop chip failed */
1796#define ASC_IERR_CHIP_VERSION 0x0040 /* wrong chip version */
1797#define ASC_IERR_SET_SCSI_ID 0x0080 /* set SCSI ID failed */
1798#define ASC_IERR_HVD_DEVICE 0x0100 /* HVD attached to LVD connector. */
1799#define ASC_IERR_BAD_SIGNATURE 0x0200 /* signature not found */
1800#define ASC_IERR_ILLEGAL_CONNECTION 0x0400 /* Illegal cable connection */
1801#define ASC_IERR_SINGLE_END_DEVICE 0x0800 /* Single-end used w/differential */
1802#define ASC_IERR_REVERSED_CABLE 0x1000 /* Narrow flat cable reversed */
1803#define ASC_IERR_BIST_PRE_TEST 0x2000 /* BIST pre-test error */
1804#define ASC_IERR_BIST_RAM_TEST 0x4000 /* BIST RAM test error */
1805#define ASC_IERR_BAD_CHIPTYPE 0x8000 /* Invalid 'chip_type' setting. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806
1807/*
1808 * Fixed locations of microcode operating variables.
1809 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001810#define ASC_MC_CODE_BEGIN_ADDR 0x0028 /* microcode start address */
1811#define ASC_MC_CODE_END_ADDR 0x002A /* microcode end address */
1812#define ASC_MC_CODE_CHK_SUM 0x002C /* microcode code checksum */
1813#define ASC_MC_VERSION_DATE 0x0038 /* microcode version */
1814#define ASC_MC_VERSION_NUM 0x003A /* microcode number */
1815#define ASC_MC_BIOSMEM 0x0040 /* BIOS RISC Memory Start */
1816#define ASC_MC_BIOSLEN 0x0050 /* BIOS RISC Memory Length */
1817#define ASC_MC_BIOS_SIGNATURE 0x0058 /* BIOS Signature 0x55AA */
1818#define ASC_MC_BIOS_VERSION 0x005A /* BIOS Version (2 bytes) */
1819#define ASC_MC_SDTR_SPEED1 0x0090 /* SDTR Speed for TID 0-3 */
1820#define ASC_MC_SDTR_SPEED2 0x0092 /* SDTR Speed for TID 4-7 */
1821#define ASC_MC_SDTR_SPEED3 0x0094 /* SDTR Speed for TID 8-11 */
1822#define ASC_MC_SDTR_SPEED4 0x0096 /* SDTR Speed for TID 12-15 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823#define ASC_MC_CHIP_TYPE 0x009A
1824#define ASC_MC_INTRB_CODE 0x009B
1825#define ASC_MC_WDTR_ABLE 0x009C
1826#define ASC_MC_SDTR_ABLE 0x009E
1827#define ASC_MC_TAGQNG_ABLE 0x00A0
1828#define ASC_MC_DISC_ENABLE 0x00A2
1829#define ASC_MC_IDLE_CMD_STATUS 0x00A4
1830#define ASC_MC_IDLE_CMD 0x00A6
1831#define ASC_MC_IDLE_CMD_PARAMETER 0x00A8
1832#define ASC_MC_DEFAULT_SCSI_CFG0 0x00AC
1833#define ASC_MC_DEFAULT_SCSI_CFG1 0x00AE
1834#define ASC_MC_DEFAULT_MEM_CFG 0x00B0
1835#define ASC_MC_DEFAULT_SEL_MASK 0x00B2
1836#define ASC_MC_SDTR_DONE 0x00B6
1837#define ASC_MC_NUMBER_OF_QUEUED_CMD 0x00C0
1838#define ASC_MC_NUMBER_OF_MAX_CMD 0x00D0
1839#define ASC_MC_DEVICE_HSHK_CFG_TABLE 0x0100
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001840#define ASC_MC_CONTROL_FLAG 0x0122 /* Microcode control flag. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841#define ASC_MC_WDTR_DONE 0x0124
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001842#define ASC_MC_CAM_MODE_MASK 0x015E /* CAM mode TID bitmask. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843#define ASC_MC_ICQ 0x0160
1844#define ASC_MC_IRQ 0x0164
1845#define ASC_MC_PPR_ABLE 0x017A
1846
1847/*
1848 * BIOS LRAM variable absolute offsets.
1849 */
1850#define BIOS_CODESEG 0x54
1851#define BIOS_CODELEN 0x56
1852#define BIOS_SIGNATURE 0x58
1853#define BIOS_VERSION 0x5A
1854
1855/*
1856 * Microcode Control Flags
1857 *
1858 * Flags set by the Adv Library in RISC variable 'control_flag' (0x122)
1859 * and handled by the microcode.
1860 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001861#define CONTROL_FLAG_IGNORE_PERR 0x0001 /* Ignore DMA Parity Errors */
1862#define CONTROL_FLAG_ENABLE_AIPP 0x0002 /* Enabled AIPP checking. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863
1864/*
1865 * ASC_MC_DEVICE_HSHK_CFG_TABLE microcode table or HSHK_CFG register format
1866 */
1867#define HSHK_CFG_WIDE_XFR 0x8000
1868#define HSHK_CFG_RATE 0x0F00
1869#define HSHK_CFG_OFFSET 0x001F
1870
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001871#define ASC_DEF_MAX_HOST_QNG 0xFD /* Max. number of host commands (253) */
1872#define ASC_DEF_MIN_HOST_QNG 0x10 /* Min. number of host commands (16) */
1873#define ASC_DEF_MAX_DVC_QNG 0x3F /* Max. number commands per device (63) */
1874#define ASC_DEF_MIN_DVC_QNG 0x04 /* Min. number commands per device (4) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001876#define ASC_QC_DATA_CHECK 0x01 /* Require ASC_QC_DATA_OUT set or clear. */
1877#define ASC_QC_DATA_OUT 0x02 /* Data out DMA transfer. */
1878#define ASC_QC_START_MOTOR 0x04 /* Send auto-start motor before request. */
1879#define ASC_QC_NO_OVERRUN 0x08 /* Don't report overrun. */
1880#define ASC_QC_FREEZE_TIDQ 0x10 /* Freeze TID queue after request. XXX TBD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001882#define ASC_QSC_NO_DISC 0x01 /* Don't allow disconnect for request. */
1883#define ASC_QSC_NO_TAGMSG 0x02 /* Don't allow tag queuing for request. */
1884#define ASC_QSC_NO_SYNC 0x04 /* Don't use Synch. transfer on request. */
1885#define ASC_QSC_NO_WIDE 0x08 /* Don't use Wide transfer on request. */
1886#define ASC_QSC_REDO_DTR 0x10 /* Renegotiate WDTR/SDTR before request. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887/*
1888 * Note: If a Tag Message is to be sent and neither ASC_QSC_HEAD_TAG or
1889 * ASC_QSC_ORDERED_TAG is set, then a Simple Tag Message (0x20) is used.
1890 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001891#define ASC_QSC_HEAD_TAG 0x40 /* Use Head Tag Message (0x21). */
1892#define ASC_QSC_ORDERED_TAG 0x80 /* Use Ordered Tag Message (0x22). */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893
1894/*
1895 * All fields here are accessed by the board microcode and need to be
1896 * little-endian.
1897 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001898typedef struct adv_carr_t {
1899 ADV_VADDR carr_va; /* Carrier Virtual Address */
1900 ADV_PADDR carr_pa; /* Carrier Physical Address */
1901 ADV_VADDR areq_vpa; /* ASC_SCSI_REQ_Q Virtual or Physical Address */
1902 /*
1903 * next_vpa [31:4] Carrier Virtual or Physical Next Pointer
1904 *
1905 * next_vpa [3:1] Reserved Bits
1906 * next_vpa [0] Done Flag set in Response Queue.
1907 */
1908 ADV_VADDR next_vpa;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909} ADV_CARR_T;
1910
1911/*
1912 * Mask used to eliminate low 4 bits of carrier 'next_vpa' field.
1913 */
1914#define ASC_NEXT_VPA_MASK 0xFFFFFFF0
1915
1916#define ASC_RQ_DONE 0x00000001
1917#define ASC_RQ_GOOD 0x00000002
1918#define ASC_CQ_STOPPER 0x00000000
1919
1920#define ASC_GET_CARRP(carrp) ((carrp) & ASC_NEXT_VPA_MASK)
1921
1922#define ADV_CARRIER_NUM_PAGE_CROSSING \
1923 (((ADV_CARRIER_COUNT * sizeof(ADV_CARR_T)) + \
1924 (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
1925
1926#define ADV_CARRIER_BUFSIZE \
1927 ((ADV_CARRIER_COUNT + ADV_CARRIER_NUM_PAGE_CROSSING) * sizeof(ADV_CARR_T))
1928
1929/*
1930 * ASC_SCSI_REQ_Q 'a_flag' definitions
1931 *
1932 * The Adv Library should limit use to the lower nibble (4 bits) of
1933 * a_flag. Drivers are free to use the upper nibble (4 bits) of a_flag.
1934 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001935#define ADV_POLL_REQUEST 0x01 /* poll for request completion */
1936#define ADV_SCSIQ_DONE 0x02 /* request done */
1937#define ADV_DONT_RETRY 0x08 /* don't do retry */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001939#define ADV_CHIP_ASC3550 0x01 /* Ultra-Wide IC */
1940#define ADV_CHIP_ASC38C0800 0x02 /* Ultra2-Wide/LVD IC */
1941#define ADV_CHIP_ASC38C1600 0x03 /* Ultra3-Wide/LVD2 IC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942
1943/*
1944 * Adapter temporary configuration structure
1945 *
1946 * This structure can be discarded after initialization. Don't add
1947 * fields here needed after initialization.
1948 *
1949 * Field naming convention:
1950 *
1951 * *_enable indicates the field enables or disables a feature. The
1952 * value of the field is never reset.
1953 */
1954typedef struct adv_dvc_cfg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001955 ushort disc_enable; /* enable disconnection */
1956 uchar chip_version; /* chip version */
1957 uchar termination; /* Term. Ctrl. bits 6-5 of SCSI_CFG1 register */
1958 ushort lib_version; /* Adv Library version number */
1959 ushort control_flag; /* Microcode Control Flag */
1960 ushort mcode_date; /* Microcode date */
1961 ushort mcode_version; /* Microcode version */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001962 ushort serial1; /* EEPROM serial number word 1 */
1963 ushort serial2; /* EEPROM serial number word 2 */
1964 ushort serial3; /* EEPROM serial number word 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965} ADV_DVC_CFG;
1966
1967struct adv_dvc_var;
1968struct adv_scsi_req_q;
1969
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970/*
1971 * Adapter operation variable structure.
1972 *
1973 * One structure is required per host adapter.
1974 *
1975 * Field naming convention:
1976 *
1977 * *_able indicates both whether a feature should be enabled or disabled
1978 * and whether a device isi capable of the feature. At initialization
1979 * this field may be set, but later if a device is found to be incapable
1980 * of the feature, the field is cleared.
1981 */
1982typedef struct adv_dvc_var {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001983 AdvPortAddr iop_base; /* I/O port address */
1984 ushort err_code; /* fatal error code */
1985 ushort bios_ctrl; /* BIOS control word, EEPROM word 12 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001986 ushort wdtr_able; /* try WDTR for a device */
1987 ushort sdtr_able; /* try SDTR for a device */
1988 ushort ultra_able; /* try SDTR Ultra speed for a device */
1989 ushort sdtr_speed1; /* EEPROM SDTR Speed for TID 0-3 */
1990 ushort sdtr_speed2; /* EEPROM SDTR Speed for TID 4-7 */
1991 ushort sdtr_speed3; /* EEPROM SDTR Speed for TID 8-11 */
1992 ushort sdtr_speed4; /* EEPROM SDTR Speed for TID 12-15 */
1993 ushort tagqng_able; /* try tagged queuing with a device */
1994 ushort ppr_able; /* PPR message capable per TID bitmask. */
1995 uchar max_dvc_qng; /* maximum number of tagged commands per device */
1996 ushort start_motor; /* start motor command allowed */
1997 uchar scsi_reset_wait; /* delay in seconds after scsi bus reset */
1998 uchar chip_no; /* should be assigned by caller */
1999 uchar max_host_qng; /* maximum number of Q'ed command allowed */
2000 uchar irq_no; /* IRQ number */
2001 ushort no_scam; /* scam_tolerant of EEPROM */
2002 struct asc_board *drv_ptr; /* driver pointer to private structure */
2003 uchar chip_scsi_id; /* chip SCSI target ID */
2004 uchar chip_type;
2005 uchar bist_err_code;
2006 ADV_CARR_T *carrier_buf;
2007 ADV_CARR_T *carr_freelist; /* Carrier free list. */
2008 ADV_CARR_T *icq_sp; /* Initiator command queue stopper pointer. */
2009 ADV_CARR_T *irq_sp; /* Initiator response queue stopper pointer. */
2010 ushort carr_pending_cnt; /* Count of pending carriers. */
2011 /*
2012 * Note: The following fields will not be used after initialization. The
2013 * driver may discard the buffer after initialization is done.
2014 */
2015 ADV_DVC_CFG *cfg; /* temporary configuration structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016} ADV_DVC_VAR;
2017
2018#define NO_OF_SG_PER_BLOCK 15
2019
2020typedef struct asc_sg_block {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002021 uchar reserved1;
2022 uchar reserved2;
2023 uchar reserved3;
2024 uchar sg_cnt; /* Valid entries in block. */
2025 ADV_PADDR sg_ptr; /* Pointer to next sg block. */
2026 struct {
2027 ADV_PADDR sg_addr; /* SG element address. */
2028 ADV_DCNT sg_count; /* SG element count. */
2029 } sg_list[NO_OF_SG_PER_BLOCK];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030} ADV_SG_BLOCK;
2031
2032/*
2033 * ADV_SCSI_REQ_Q - microcode request structure
2034 *
2035 * All fields in this structure up to byte 60 are used by the microcode.
2036 * The microcode makes assumptions about the size and ordering of fields
2037 * in this structure. Do not change the structure definition here without
2038 * coordinating the change with the microcode.
2039 *
2040 * All fields accessed by microcode must be maintained in little_endian
2041 * order.
2042 */
2043typedef struct adv_scsi_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002044 uchar cntl; /* Ucode flags and state (ASC_MC_QC_*). */
2045 uchar target_cmd;
2046 uchar target_id; /* Device target identifier. */
2047 uchar target_lun; /* Device target logical unit number. */
2048 ADV_PADDR data_addr; /* Data buffer physical address. */
2049 ADV_DCNT data_cnt; /* Data count. Ucode sets to residual. */
2050 ADV_PADDR sense_addr;
2051 ADV_PADDR carr_pa;
2052 uchar mflag;
2053 uchar sense_len;
2054 uchar cdb_len; /* SCSI CDB length. Must <= 16 bytes. */
2055 uchar scsi_cntl;
2056 uchar done_status; /* Completion status. */
2057 uchar scsi_status; /* SCSI status byte. */
2058 uchar host_status; /* Ucode host status. */
2059 uchar sg_working_ix;
2060 uchar cdb[12]; /* SCSI CDB bytes 0-11. */
2061 ADV_PADDR sg_real_addr; /* SG list physical address. */
2062 ADV_PADDR scsiq_rptr;
2063 uchar cdb16[4]; /* SCSI CDB bytes 12-15. */
2064 ADV_VADDR scsiq_ptr;
2065 ADV_VADDR carr_va;
2066 /*
2067 * End of microcode structure - 60 bytes. The rest of the structure
2068 * is used by the Adv Library and ignored by the microcode.
2069 */
2070 ADV_VADDR srb_ptr;
2071 ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */
2072 char *vdata_addr; /* Data buffer virtual address. */
2073 uchar a_flag;
2074 uchar pad[2]; /* Pad out to a word boundary. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075} ADV_SCSI_REQ_Q;
2076
2077/*
2078 * Microcode idle loop commands
2079 */
2080#define IDLE_CMD_COMPLETED 0
2081#define IDLE_CMD_STOP_CHIP 0x0001
2082#define IDLE_CMD_STOP_CHIP_SEND_INT 0x0002
2083#define IDLE_CMD_SEND_INT 0x0004
2084#define IDLE_CMD_ABORT 0x0008
2085#define IDLE_CMD_DEVICE_RESET 0x0010
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002086#define IDLE_CMD_SCSI_RESET_START 0x0020 /* Assert SCSI Bus Reset */
2087#define IDLE_CMD_SCSI_RESET_END 0x0040 /* Deassert SCSI Bus Reset */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088#define IDLE_CMD_SCSIREQ 0x0080
2089
2090#define IDLE_CMD_STATUS_SUCCESS 0x0001
2091#define IDLE_CMD_STATUS_FAILURE 0x0002
2092
2093/*
2094 * AdvSendIdleCmd() flag definitions.
2095 */
2096#define ADV_NOWAIT 0x01
2097
2098/*
2099 * Wait loop time out values.
2100 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002101#define SCSI_WAIT_100_MSEC 100UL /* 100 milliseconds */
2102#define SCSI_US_PER_MSEC 1000 /* microseconds per millisecond */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002103#define SCSI_MAX_RETRY 10 /* retry count */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002105#define ADV_ASYNC_RDMA_FAILURE 0x01 /* Fatal RDMA failure. */
2106#define ADV_ASYNC_SCSI_BUS_RESET_DET 0x02 /* Detected SCSI Bus Reset. */
2107#define ADV_ASYNC_CARRIER_READY_FAILURE 0x03 /* Carrier Ready failure. */
2108#define ADV_RDMA_IN_CARR_AND_Q_INVALID 0x04 /* RDMAed-in data invalid. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002110#define ADV_HOST_SCSI_BUS_RESET 0x80 /* Host Initiated SCSI Bus Reset. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002112static ADV_PADDR DvcGetPhyAddr(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *,
2113 uchar *, ASC_SDCNT *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114
2115/*
2116 * Adv Library functions available to drivers.
2117 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002118static int AdvExeScsiQueue(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
2119static int AdvISR(ADV_DVC_VAR *);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002120static int AdvInitAsc3550Driver(ADV_DVC_VAR *);
2121static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *);
2122static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *);
2123static int AdvResetChipAndSB(ADV_DVC_VAR *);
2124static int AdvResetSB(ADV_DVC_VAR *asc_dvc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125
2126/*
2127 * Internal Adv Library functions.
2128 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002129static int AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ADV_DCNT);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002130static int AdvInitFrom3550EEP(ADV_DVC_VAR *);
2131static int AdvInitFrom38C0800EEP(ADV_DVC_VAR *);
2132static int AdvInitFrom38C1600EEP(ADV_DVC_VAR *);
2133static ushort AdvGet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
2134static void AdvSet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
2135static ushort AdvGet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
2136static void AdvSet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
2137static ushort AdvGet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
2138static void AdvSet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
2139static void AdvWaitEEPCmd(AdvPortAddr);
2140static ushort AdvReadEEPWord(AdvPortAddr, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142/* Read byte from a register. */
2143#define AdvReadByteRegister(iop_base, reg_off) \
2144 (ADV_MEM_READB((iop_base) + (reg_off)))
2145
2146/* Write byte to a register. */
2147#define AdvWriteByteRegister(iop_base, reg_off, byte) \
2148 (ADV_MEM_WRITEB((iop_base) + (reg_off), (byte)))
2149
2150/* Read word (2 bytes) from a register. */
2151#define AdvReadWordRegister(iop_base, reg_off) \
2152 (ADV_MEM_READW((iop_base) + (reg_off)))
2153
2154/* Write word (2 bytes) to a register. */
2155#define AdvWriteWordRegister(iop_base, reg_off, word) \
2156 (ADV_MEM_WRITEW((iop_base) + (reg_off), (word)))
2157
2158/* Write dword (4 bytes) to a register. */
2159#define AdvWriteDWordRegister(iop_base, reg_off, dword) \
2160 (ADV_MEM_WRITEDW((iop_base) + (reg_off), (dword)))
2161
2162/* Read byte from LRAM. */
2163#define AdvReadByteLram(iop_base, addr, byte) \
2164do { \
2165 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
2166 (byte) = ADV_MEM_READB((iop_base) + IOPB_RAM_DATA); \
2167} while (0)
2168
2169/* Write byte to LRAM. */
2170#define AdvWriteByteLram(iop_base, addr, byte) \
2171 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
2172 ADV_MEM_WRITEB((iop_base) + IOPB_RAM_DATA, (byte)))
2173
2174/* Read word (2 bytes) from LRAM. */
2175#define AdvReadWordLram(iop_base, addr, word) \
2176do { \
2177 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
2178 (word) = (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA)); \
2179} while (0)
2180
2181/* Write word (2 bytes) to LRAM. */
2182#define AdvWriteWordLram(iop_base, addr, word) \
2183 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
2184 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
2185
2186/* Write little-endian double word (4 bytes) to LRAM */
2187/* Because of unspecified C language ordering don't use auto-increment. */
2188#define AdvWriteDWordLramNoSwap(iop_base, addr, dword) \
2189 ((ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
2190 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
2191 cpu_to_le16((ushort) ((dword) & 0xFFFF)))), \
2192 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr) + 2), \
2193 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
2194 cpu_to_le16((ushort) ((dword >> 16) & 0xFFFF)))))
2195
2196/* Read word (2 bytes) from LRAM assuming that the address is already set. */
2197#define AdvReadWordAutoIncLram(iop_base) \
2198 (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA))
2199
2200/* Write word (2 bytes) to LRAM assuming that the address is already set. */
2201#define AdvWriteWordAutoIncLram(iop_base, word) \
2202 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
2203
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204/*
2205 * Define macro to check for Condor signature.
2206 *
2207 * Evaluate to ADV_TRUE if a Condor chip is found the specified port
2208 * address 'iop_base'. Otherwise evalue to ADV_FALSE.
2209 */
2210#define AdvFindSignature(iop_base) \
2211 (((AdvReadByteRegister((iop_base), IOPB_CHIP_ID_1) == \
2212 ADV_CHIP_ID_BYTE) && \
2213 (AdvReadWordRegister((iop_base), IOPW_CHIP_ID_0) == \
2214 ADV_CHIP_ID_WORD)) ? ADV_TRUE : ADV_FALSE)
2215
2216/*
2217 * Define macro to Return the version number of the chip at 'iop_base'.
2218 *
2219 * The second parameter 'bus_type' is currently unused.
2220 */
2221#define AdvGetChipVersion(iop_base, bus_type) \
2222 AdvReadByteRegister((iop_base), IOPB_CHIP_TYPE_REV)
2223
2224/*
2225 * Abort an SRB in the chip's RISC Memory. The 'srb_ptr' argument must
2226 * match the ASC_SCSI_REQ_Q 'srb_ptr' field.
2227 *
2228 * If the request has not yet been sent to the device it will simply be
2229 * aborted from RISC memory. If the request is disconnected it will be
2230 * aborted on reselection by sending an Abort Message to the target ID.
2231 *
2232 * Return value:
2233 * ADV_TRUE(1) - Queue was successfully aborted.
2234 * ADV_FALSE(0) - Queue was not found on the active queue list.
2235 */
2236#define AdvAbortQueue(asc_dvc, scsiq) \
2237 AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_ABORT, \
2238 (ADV_DCNT) (scsiq))
2239
2240/*
2241 * Send a Bus Device Reset Message to the specified target ID.
2242 *
2243 * All outstanding commands will be purged if sending the
2244 * Bus Device Reset Message is successful.
2245 *
2246 * Return Value:
2247 * ADV_TRUE(1) - All requests on the target are purged.
2248 * ADV_FALSE(0) - Couldn't issue Bus Device Reset Message; Requests
2249 * are not purged.
2250 */
2251#define AdvResetDevice(asc_dvc, target_id) \
2252 AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_DEVICE_RESET, \
2253 (ADV_DCNT) (target_id))
2254
2255/*
2256 * SCSI Wide Type definition.
2257 */
2258#define ADV_SCSI_BIT_ID_TYPE ushort
2259
2260/*
2261 * AdvInitScsiTarget() 'cntl_flag' options.
2262 */
2263#define ADV_SCAN_LUN 0x01
2264#define ADV_CAPINFO_NOLUN 0x02
2265
2266/*
2267 * Convert target id to target id bit mask.
2268 */
2269#define ADV_TID_TO_TIDMASK(tid) (0x01 << ((tid) & ADV_MAX_TID))
2270
2271/*
2272 * ASC_SCSI_REQ_Q 'done_status' and 'host_status' return values.
2273 */
2274
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002275#define QD_NO_STATUS 0x00 /* Request not completed yet. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276#define QD_NO_ERROR 0x01
2277#define QD_ABORTED_BY_HOST 0x02
2278#define QD_WITH_ERROR 0x04
2279
2280#define QHSTA_NO_ERROR 0x00
2281#define QHSTA_M_SEL_TIMEOUT 0x11
2282#define QHSTA_M_DATA_OVER_RUN 0x12
2283#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
2284#define QHSTA_M_QUEUE_ABORTED 0x15
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002285#define QHSTA_M_SXFR_SDMA_ERR 0x16 /* SXFR_STATUS SCSI DMA Error */
2286#define QHSTA_M_SXFR_SXFR_PERR 0x17 /* SXFR_STATUS SCSI Bus Parity Error */
2287#define QHSTA_M_RDMA_PERR 0x18 /* RISC PCI DMA parity error */
2288#define QHSTA_M_SXFR_OFF_UFLW 0x19 /* SXFR_STATUS Offset Underflow */
2289#define QHSTA_M_SXFR_OFF_OFLW 0x20 /* SXFR_STATUS Offset Overflow */
2290#define QHSTA_M_SXFR_WD_TMO 0x21 /* SXFR_STATUS Watchdog Timeout */
2291#define QHSTA_M_SXFR_DESELECTED 0x22 /* SXFR_STATUS Deselected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292/* Note: QHSTA_M_SXFR_XFR_OFLW is identical to QHSTA_M_DATA_OVER_RUN. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002293#define QHSTA_M_SXFR_XFR_OFLW 0x12 /* SXFR_STATUS Transfer Overflow */
2294#define QHSTA_M_SXFR_XFR_PH_ERR 0x24 /* SXFR_STATUS Transfer Phase Error */
2295#define QHSTA_M_SXFR_UNKNOWN_ERROR 0x25 /* SXFR_STATUS Unknown Error */
2296#define QHSTA_M_SCSI_BUS_RESET 0x30 /* Request aborted from SBR */
2297#define QHSTA_M_SCSI_BUS_RESET_UNSOL 0x31 /* Request aborted from unsol. SBR */
2298#define QHSTA_M_BUS_DEVICE_RESET 0x32 /* Request aborted from BDR */
2299#define QHSTA_M_DIRECTION_ERR 0x35 /* Data Phase mismatch */
2300#define QHSTA_M_DIRECTION_ERR_HUNG 0x36 /* Data Phase mismatch and bus hang */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301#define QHSTA_M_WTM_TIMEOUT 0x41
2302#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42
2303#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43
2304#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002305#define QHSTA_M_INVALID_DEVICE 0x45 /* Bad target ID */
2306#define QHSTA_M_FROZEN_TIDQ 0x46 /* TID Queue frozen. */
2307#define QHSTA_M_SGBACKUP_ERROR 0x47 /* Scatter-Gather backup error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308
2309/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 * DvcGetPhyAddr() flag arguments
2311 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002312#define ADV_IS_SCSIQ_FLAG 0x01 /* 'addr' is ASC_SCSI_REQ_Q pointer */
2313#define ADV_ASCGETSGLIST_VADDR 0x02 /* 'addr' is AscGetSGList() virtual addr */
2314#define ADV_IS_SENSE_FLAG 0x04 /* 'addr' is sense virtual pointer */
2315#define ADV_IS_DATA_FLAG 0x08 /* 'addr' is data virtual pointer */
2316#define ADV_IS_SGLIST_FLAG 0x10 /* 'addr' is sglist virtual pointer */
2317#define ADV_IS_CARRIER_FLAG 0x20 /* 'addr' is ADV_CARR_T pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318
2319/* Return the address that is aligned at the next doubleword >= to 'addr'. */
2320#define ADV_8BALIGN(addr) (((ulong) (addr) + 0x7) & ~0x7)
2321#define ADV_16BALIGN(addr) (((ulong) (addr) + 0xF) & ~0xF)
2322#define ADV_32BALIGN(addr) (((ulong) (addr) + 0x1F) & ~0x1F)
2323
2324/*
2325 * Total contiguous memory needed for driver SG blocks.
2326 *
2327 * ADV_MAX_SG_LIST must be defined by a driver. It is the maximum
2328 * number of scatter-gather elements the driver supports in a
2329 * single request.
2330 */
2331
2332#define ADV_SG_LIST_MAX_BYTE_SIZE \
2333 (sizeof(ADV_SG_BLOCK) * \
2334 ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK))
2335
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336/* Reference Scsi_Host hostdata */
2337#define ASC_BOARDP(host) ((asc_board_t *) &((host)->hostdata))
2338
2339/* asc_board_t flags */
2340#define ASC_HOST_IN_RESET 0x01
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002341#define ASC_IS_WIDE_BOARD 0x04 /* AdvanSys Wide Board */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342#define ASC_SELECT_QUEUE_DEPTHS 0x08
2343
2344#define ASC_NARROW_BOARD(boardp) (((boardp)->flags & ASC_IS_WIDE_BOARD) == 0)
2345#define ASC_WIDE_BOARD(boardp) ((boardp)->flags & ASC_IS_WIDE_BOARD)
2346
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002347#define NO_ISA_DMA 0xff /* No ISA DMA Channel Used */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002349#define ASC_INFO_SIZE 128 /* advansys_info() line size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350
2351#ifdef CONFIG_PROC_FS
2352/* /proc/scsi/advansys/[0...] related definitions */
2353#define ASC_PRTBUF_SIZE 2048
2354#define ASC_PRTLINE_SIZE 160
2355
2356#define ASC_PRT_NEXT() \
2357 if (cp) { \
2358 totlen += len; \
2359 leftlen -= len; \
2360 if (leftlen == 0) { \
2361 return totlen; \
2362 } \
2363 cp += len; \
2364 }
2365#endif /* CONFIG_PROC_FS */
2366
2367/* Asc Library return codes */
2368#define ASC_TRUE 1
2369#define ASC_FALSE 0
2370#define ASC_NOERROR 1
2371#define ASC_BUSY 0
2372#define ASC_ERROR (-1)
2373
2374/* struct scsi_cmnd function return codes */
2375#define STATUS_BYTE(byte) (byte)
2376#define MSG_BYTE(byte) ((byte) << 8)
2377#define HOST_BYTE(byte) ((byte) << 16)
2378#define DRIVER_BYTE(byte) ((byte) << 24)
2379
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380#ifndef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002381#define ASC_STATS(shost, counter)
2382#define ASC_STATS_ADD(shost, counter, count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383#else /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002384#define ASC_STATS(shost, counter) \
2385 (ASC_BOARDP(shost)->asc_stats.counter++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002387#define ASC_STATS_ADD(shost, counter, count) \
2388 (ASC_BOARDP(shost)->asc_stats.counter += (count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389#endif /* ADVANSYS_STATS */
2390
2391#define ASC_CEILING(val, unit) (((val) + ((unit) - 1))/(unit))
2392
2393/* If the result wraps when calculating tenths, return 0. */
2394#define ASC_TENTHS(num, den) \
2395 (((10 * ((num)/(den))) > (((num) * 10)/(den))) ? \
2396 0 : ((((num) * 10)/(den)) - (10 * ((num)/(den)))))
2397
2398/*
2399 * Display a message to the console.
2400 */
2401#define ASC_PRINT(s) \
2402 { \
2403 printk("advansys: "); \
2404 printk(s); \
2405 }
2406
2407#define ASC_PRINT1(s, a1) \
2408 { \
2409 printk("advansys: "); \
2410 printk((s), (a1)); \
2411 }
2412
2413#define ASC_PRINT2(s, a1, a2) \
2414 { \
2415 printk("advansys: "); \
2416 printk((s), (a1), (a2)); \
2417 }
2418
2419#define ASC_PRINT3(s, a1, a2, a3) \
2420 { \
2421 printk("advansys: "); \
2422 printk((s), (a1), (a2), (a3)); \
2423 }
2424
2425#define ASC_PRINT4(s, a1, a2, a3, a4) \
2426 { \
2427 printk("advansys: "); \
2428 printk((s), (a1), (a2), (a3), (a4)); \
2429 }
2430
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431#ifndef ADVANSYS_DEBUG
2432
2433#define ASC_DBG(lvl, s)
2434#define ASC_DBG1(lvl, s, a1)
2435#define ASC_DBG2(lvl, s, a1, a2)
2436#define ASC_DBG3(lvl, s, a1, a2, a3)
2437#define ASC_DBG4(lvl, s, a1, a2, a3, a4)
2438#define ASC_DBG_PRT_SCSI_HOST(lvl, s)
2439#define ASC_DBG_PRT_SCSI_CMND(lvl, s)
2440#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp)
2441#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
2442#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone)
2443#define ADV_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
2444#define ASC_DBG_PRT_HEX(lvl, name, start, length)
2445#define ASC_DBG_PRT_CDB(lvl, cdb, len)
2446#define ASC_DBG_PRT_SENSE(lvl, sense, len)
2447#define ASC_DBG_PRT_INQUIRY(lvl, inq, len)
2448
2449#else /* ADVANSYS_DEBUG */
2450
2451/*
2452 * Debugging Message Levels:
2453 * 0: Errors Only
2454 * 1: High-Level Tracing
2455 * 2-N: Verbose Tracing
2456 */
2457
2458#define ASC_DBG(lvl, s) \
2459 { \
2460 if (asc_dbglvl >= (lvl)) { \
2461 printk(s); \
2462 } \
2463 }
2464
2465#define ASC_DBG1(lvl, s, a1) \
2466 { \
2467 if (asc_dbglvl >= (lvl)) { \
2468 printk((s), (a1)); \
2469 } \
2470 }
2471
2472#define ASC_DBG2(lvl, s, a1, a2) \
2473 { \
2474 if (asc_dbglvl >= (lvl)) { \
2475 printk((s), (a1), (a2)); \
2476 } \
2477 }
2478
2479#define ASC_DBG3(lvl, s, a1, a2, a3) \
2480 { \
2481 if (asc_dbglvl >= (lvl)) { \
2482 printk((s), (a1), (a2), (a3)); \
2483 } \
2484 }
2485
2486#define ASC_DBG4(lvl, s, a1, a2, a3, a4) \
2487 { \
2488 if (asc_dbglvl >= (lvl)) { \
2489 printk((s), (a1), (a2), (a3), (a4)); \
2490 } \
2491 }
2492
2493#define ASC_DBG_PRT_SCSI_HOST(lvl, s) \
2494 { \
2495 if (asc_dbglvl >= (lvl)) { \
2496 asc_prt_scsi_host(s); \
2497 } \
2498 }
2499
2500#define ASC_DBG_PRT_SCSI_CMND(lvl, s) \
2501 { \
2502 if (asc_dbglvl >= (lvl)) { \
2503 asc_prt_scsi_cmnd(s); \
2504 } \
2505 }
2506
2507#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp) \
2508 { \
2509 if (asc_dbglvl >= (lvl)) { \
2510 asc_prt_asc_scsi_q(scsiqp); \
2511 } \
2512 }
2513
2514#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone) \
2515 { \
2516 if (asc_dbglvl >= (lvl)) { \
2517 asc_prt_asc_qdone_info(qdone); \
2518 } \
2519 }
2520
2521#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp) \
2522 { \
2523 if (asc_dbglvl >= (lvl)) { \
2524 asc_prt_adv_scsi_req_q(scsiqp); \
2525 } \
2526 }
2527
2528#define ASC_DBG_PRT_HEX(lvl, name, start, length) \
2529 { \
2530 if (asc_dbglvl >= (lvl)) { \
2531 asc_prt_hex((name), (start), (length)); \
2532 } \
2533 }
2534
2535#define ASC_DBG_PRT_CDB(lvl, cdb, len) \
2536 ASC_DBG_PRT_HEX((lvl), "CDB", (uchar *) (cdb), (len));
2537
2538#define ASC_DBG_PRT_SENSE(lvl, sense, len) \
2539 ASC_DBG_PRT_HEX((lvl), "SENSE", (uchar *) (sense), (len));
2540
2541#define ASC_DBG_PRT_INQUIRY(lvl, inq, len) \
2542 ASC_DBG_PRT_HEX((lvl), "INQUIRY", (uchar *) (inq), (len));
2543#endif /* ADVANSYS_DEBUG */
2544
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545#ifdef ADVANSYS_STATS
2546
2547/* Per board statistics structure */
2548struct asc_stats {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002549 /* Driver Entrypoint Statistics */
2550 ADV_DCNT queuecommand; /* # calls to advansys_queuecommand() */
2551 ADV_DCNT reset; /* # calls to advansys_eh_bus_reset() */
2552 ADV_DCNT biosparam; /* # calls to advansys_biosparam() */
2553 ADV_DCNT interrupt; /* # advansys_interrupt() calls */
2554 ADV_DCNT callback; /* # calls to asc/adv_isr_callback() */
2555 ADV_DCNT done; /* # calls to request's scsi_done function */
2556 ADV_DCNT build_error; /* # asc/adv_build_req() ASC_ERROR returns. */
2557 ADV_DCNT adv_build_noreq; /* # adv_build_req() adv_req_t alloc. fail. */
2558 ADV_DCNT adv_build_nosg; /* # adv_build_req() adv_sgblk_t alloc. fail. */
2559 /* AscExeScsiQueue()/AdvExeScsiQueue() Statistics */
2560 ADV_DCNT exe_noerror; /* # ASC_NOERROR returns. */
2561 ADV_DCNT exe_busy; /* # ASC_BUSY returns. */
2562 ADV_DCNT exe_error; /* # ASC_ERROR returns. */
2563 ADV_DCNT exe_unknown; /* # unknown returns. */
2564 /* Data Transfer Statistics */
2565 ADV_DCNT cont_cnt; /* # non-scatter-gather I/O requests received */
2566 ADV_DCNT cont_xfer; /* # contiguous transfer 512-bytes */
2567 ADV_DCNT sg_cnt; /* # scatter-gather I/O requests received */
2568 ADV_DCNT sg_elem; /* # scatter-gather elements */
2569 ADV_DCNT sg_xfer; /* # scatter-gather transfer 512-bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570};
2571#endif /* ADVANSYS_STATS */
2572
2573/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 * Adv Library Request Structures
2575 *
2576 * The following two structures are used to process Wide Board requests.
2577 *
2578 * The ADV_SCSI_REQ_Q structure in adv_req_t is passed to the Adv Library
2579 * and microcode with the ADV_SCSI_REQ_Q field 'srb_ptr' pointing to the
2580 * adv_req_t. The adv_req_t structure 'cmndp' field in turn points to the
2581 * Mid-Level SCSI request structure.
2582 *
2583 * Zero or more ADV_SG_BLOCK are used with each ADV_SCSI_REQ_Q. Each
2584 * ADV_SG_BLOCK structure holds 15 scatter-gather elements. Under Linux
2585 * up to 255 scatter-gather elements may be used per request or
2586 * ADV_SCSI_REQ_Q.
2587 *
2588 * Both structures must be 32 byte aligned.
2589 */
2590typedef struct adv_sgblk {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002591 ADV_SG_BLOCK sg_block; /* Sgblock structure. */
2592 uchar align[32]; /* Sgblock structure padding. */
2593 struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594} adv_sgblk_t;
2595
2596typedef struct adv_req {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002597 ADV_SCSI_REQ_Q scsi_req_q; /* Adv Library request structure. */
2598 uchar align[32]; /* Request structure padding. */
2599 struct scsi_cmnd *cmndp; /* Mid-Level SCSI command pointer. */
2600 adv_sgblk_t *sgblkp; /* Adv Library scatter-gather pointer. */
2601 struct adv_req *next_reqp; /* Next Request Structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602} adv_req_t;
2603
2604/*
2605 * Structure allocated for each board.
2606 *
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06002607 * This structure is allocated by scsi_host_alloc() at the end
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 * of the 'Scsi_Host' structure starting at the 'hostdata'
2609 * field. It is guaranteed to be allocated from DMA-able memory.
2610 */
2611typedef struct asc_board {
Matthew Wilcox394dbf32007-07-26 11:56:40 -04002612 struct device *dev;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002613 int id; /* Board Id */
2614 uint flags; /* Board flags */
2615 union {
2616 ASC_DVC_VAR asc_dvc_var; /* Narrow board */
2617 ADV_DVC_VAR adv_dvc_var; /* Wide board */
2618 } dvc_var;
2619 union {
2620 ASC_DVC_CFG asc_dvc_cfg; /* Narrow board */
2621 ADV_DVC_CFG adv_dvc_cfg; /* Wide board */
2622 } dvc_cfg;
2623 ushort asc_n_io_port; /* Number I/O ports. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002624 ADV_SCSI_BIT_ID_TYPE init_tidmask; /* Target init./valid mask */
2625 struct scsi_device *device[ADV_MAX_TID + 1]; /* Mid-Level Scsi Device */
2626 ushort reqcnt[ADV_MAX_TID + 1]; /* Starvation request count */
2627 ADV_SCSI_BIT_ID_TYPE queue_full; /* Queue full mask */
2628 ushort queue_full_cnt[ADV_MAX_TID + 1]; /* Queue full count */
2629 union {
2630 ASCEEP_CONFIG asc_eep; /* Narrow EEPROM config. */
2631 ADVEEP_3550_CONFIG adv_3550_eep; /* 3550 EEPROM config. */
2632 ADVEEP_38C0800_CONFIG adv_38C0800_eep; /* 38C0800 EEPROM config. */
2633 ADVEEP_38C1600_CONFIG adv_38C1600_eep; /* 38C1600 EEPROM config. */
2634 } eep_config;
2635 ulong last_reset; /* Saved last reset time */
2636 spinlock_t lock; /* Board spinlock */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002637 /* /proc/scsi/advansys/[0...] */
2638 char *prtbuf; /* /proc print buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002640 struct asc_stats asc_stats; /* Board statistics */
2641#endif /* ADVANSYS_STATS */
2642 /*
2643 * The following fields are used only for Narrow Boards.
2644 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002645 uchar sdtr_data[ASC_MAX_TID + 1]; /* SDTR information */
2646 /*
2647 * The following fields are used only for Wide Boards.
2648 */
2649 void __iomem *ioremap_addr; /* I/O Memory remap address. */
2650 ushort ioport; /* I/O Port address. */
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -06002651 ADV_CARR_T *carrp; /* ADV_CARR_T memory block. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002652 adv_req_t *orig_reqp; /* adv_req_t memory block. */
2653 adv_req_t *adv_reqp; /* Request structures. */
2654 adv_sgblk_t *adv_sgblkp; /* Scatter-gather structures. */
2655 ushort bios_signature; /* BIOS Signature. */
2656 ushort bios_version; /* BIOS Version. */
2657 ushort bios_codeseg; /* BIOS Code Segment. */
2658 ushort bios_codelen; /* BIOS Code Segment Length. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659} asc_board_t;
2660
Matthew Wilcox13ac2d92007-07-30 08:10:23 -06002661#define adv_dvc_to_board(adv_dvc) container_of(adv_dvc, struct asc_board, \
2662 dvc_var.adv_dvc_var)
2663#define adv_dvc_to_pdev(adv_dvc) to_pci_dev(adv_dvc_to_board(adv_dvc)->dev)
2664
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665/* Number of boards detected in system. */
Matthew Wilcox78e77d82007-07-29 21:46:15 -06002666static int asc_board_count;
2667
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668/* Overrun buffer used by all narrow boards. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002669static uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670
2671/*
2672 * Global structures required to issue a command.
2673 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002674static ASC_SCSI_Q asc_scsi_q = { {0} };
2675static ASC_SG_HEAD asc_sg_head = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002678static int asc_dbglvl = 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679#endif /* ADVANSYS_DEBUG */
2680
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002681static int advansys_slave_configure(struct scsi_device *);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002682static int asc_execute_scsi_cmnd(struct scsi_cmnd *);
2683static int asc_build_req(asc_board_t *, struct scsi_cmnd *);
2684static int adv_build_req(asc_board_t *, struct scsi_cmnd *, ADV_SCSI_REQ_Q **);
2685static int adv_get_sglist(asc_board_t *, adv_req_t *, struct scsi_cmnd *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002687static int asc_proc_copy(off_t, off_t, char *, int, char *, int);
2688static int asc_prt_board_devices(struct Scsi_Host *, char *, int);
2689static int asc_prt_adv_bios(struct Scsi_Host *, char *, int);
2690static int asc_get_eeprom_string(ushort *serialnum, uchar *cp);
2691static int asc_prt_asc_board_eeprom(struct Scsi_Host *, char *, int);
2692static int asc_prt_adv_board_eeprom(struct Scsi_Host *, char *, int);
2693static int asc_prt_driver_conf(struct Scsi_Host *, char *, int);
2694static int asc_prt_asc_board_info(struct Scsi_Host *, char *, int);
2695static int asc_prt_adv_board_info(struct Scsi_Host *, char *, int);
2696static int asc_prt_line(char *, int, char *fmt, ...);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697#endif /* CONFIG_PROC_FS */
2698
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699/* Statistics function prototypes. */
2700#ifdef ADVANSYS_STATS
2701#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002702static int asc_prt_board_stats(struct Scsi_Host *, char *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703#endif /* CONFIG_PROC_FS */
2704#endif /* ADVANSYS_STATS */
2705
2706/* Debug function prototypes. */
2707#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002708static void asc_prt_scsi_host(struct Scsi_Host *);
2709static void asc_prt_scsi_cmnd(struct scsi_cmnd *);
2710static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *);
2711static void asc_prt_asc_dvc_var(ASC_DVC_VAR *);
2712static void asc_prt_asc_scsi_q(ASC_SCSI_Q *);
2713static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *);
2714static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *);
2715static void asc_prt_adv_dvc_var(ADV_DVC_VAR *);
2716static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *);
2717static void asc_prt_adv_sgblock(int, ADV_SG_BLOCK *);
2718static void asc_prt_hex(char *f, uchar *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719#endif /* ADVANSYS_DEBUG */
2720
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721#ifdef CONFIG_PROC_FS
2722/*
Matthew Wilcoxc304ec92007-07-30 09:18:45 -06002723 * advansys_proc_info() - /proc/scsi/advansys/{0,1,2,3,...}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 *
2725 * *buffer: I/O buffer
2726 * **start: if inout == FALSE pointer into buffer where user read should start
2727 * offset: current offset into a /proc/scsi/advansys/[0...] file
2728 * length: length of buffer
2729 * hostno: Scsi_Host host_no
2730 * inout: TRUE - user is writing; FALSE - user is reading
2731 *
2732 * Return the number of bytes read from or written to a
2733 * /proc/scsi/advansys/[0...] file.
2734 *
2735 * Note: This function uses the per board buffer 'prtbuf' which is
2736 * allocated when the board is initialized in advansys_detect(). The
2737 * buffer is ASC_PRTBUF_SIZE bytes. The function asc_proc_copy() is
2738 * used to write to the buffer. The way asc_proc_copy() is written
2739 * if 'prtbuf' is too small it will not be overwritten. Instead the
2740 * user just won't get all the available statistics.
2741 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07002742static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002744 off_t offset, int length, int inout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002746 asc_board_t *boardp;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002747 char *cp;
2748 int cplen;
2749 int cnt;
2750 int totcnt;
2751 int leftlen;
2752 char *curbuf;
2753 off_t advoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002755 ASC_DBG(1, "advansys_proc_info: begin\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002757 /*
2758 * User write not supported.
2759 */
2760 if (inout == TRUE) {
2761 return (-ENOSYS);
2762 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002764 /*
2765 * User read of /proc/scsi/advansys/[0...] file.
2766 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767
Matthew Wilcox2a437952007-07-26 11:00:51 -04002768 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002770 /* Copy read data starting at the beginning of the buffer. */
2771 *start = buffer;
2772 curbuf = buffer;
2773 advoffset = 0;
2774 totcnt = 0;
2775 leftlen = length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002777 /*
2778 * Get board configuration information.
2779 *
2780 * advansys_info() returns the board string from its own static buffer.
2781 */
Matthew Wilcox2a437952007-07-26 11:00:51 -04002782 cp = (char *)advansys_info(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002783 strcat(cp, "\n");
2784 cplen = strlen(cp);
2785 /* Copy board information. */
2786 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
2787 totcnt += cnt;
2788 leftlen -= cnt;
2789 if (leftlen == 0) {
2790 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
2791 return totcnt;
2792 }
2793 advoffset += cplen;
2794 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002796 /*
2797 * Display Wide Board BIOS Information.
2798 */
2799 if (ASC_WIDE_BOARD(boardp)) {
2800 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04002801 cplen = asc_prt_adv_bios(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06002802 BUG_ON(cplen >= ASC_PRTBUF_SIZE);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06002803 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002804 cplen);
2805 totcnt += cnt;
2806 leftlen -= cnt;
2807 if (leftlen == 0) {
2808 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
2809 return totcnt;
2810 }
2811 advoffset += cplen;
2812 curbuf += cnt;
2813 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002815 /*
2816 * Display driver information for each device attached to the board.
2817 */
2818 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04002819 cplen = asc_prt_board_devices(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06002820 BUG_ON(cplen >= ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002821 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
2822 totcnt += cnt;
2823 leftlen -= cnt;
2824 if (leftlen == 0) {
2825 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
2826 return totcnt;
2827 }
2828 advoffset += cplen;
2829 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002831 /*
2832 * Display EEPROM configuration for the board.
2833 */
2834 cp = boardp->prtbuf;
2835 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox2a437952007-07-26 11:00:51 -04002836 cplen = asc_prt_asc_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002837 } else {
Matthew Wilcox2a437952007-07-26 11:00:51 -04002838 cplen = asc_prt_adv_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002839 }
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06002840 BUG_ON(cplen >= ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002841 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
2842 totcnt += cnt;
2843 leftlen -= cnt;
2844 if (leftlen == 0) {
2845 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
2846 return totcnt;
2847 }
2848 advoffset += cplen;
2849 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002851 /*
2852 * Display driver configuration and information for the board.
2853 */
2854 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04002855 cplen = asc_prt_driver_conf(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06002856 BUG_ON(cplen >= ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002857 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
2858 totcnt += cnt;
2859 leftlen -= cnt;
2860 if (leftlen == 0) {
2861 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
2862 return totcnt;
2863 }
2864 advoffset += cplen;
2865 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866
2867#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002868 /*
2869 * Display driver statistics for the board.
2870 */
2871 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04002872 cplen = asc_prt_board_stats(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06002873 BUG_ON(cplen >= ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002874 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
2875 totcnt += cnt;
2876 leftlen -= cnt;
2877 if (leftlen == 0) {
2878 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
2879 return totcnt;
2880 }
2881 advoffset += cplen;
2882 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883#endif /* ADVANSYS_STATS */
2884
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002885 /*
2886 * Display Asc Library dynamic configuration information
2887 * for the board.
2888 */
2889 cp = boardp->prtbuf;
2890 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox2a437952007-07-26 11:00:51 -04002891 cplen = asc_prt_asc_board_info(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002892 } else {
Matthew Wilcox2a437952007-07-26 11:00:51 -04002893 cplen = asc_prt_adv_board_info(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002894 }
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06002895 BUG_ON(cplen >= ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002896 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
2897 totcnt += cnt;
2898 leftlen -= cnt;
2899 if (leftlen == 0) {
2900 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
2901 return totcnt;
2902 }
2903 advoffset += cplen;
2904 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002906 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002908 return totcnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909}
2910#endif /* CONFIG_PROC_FS */
2911
2912/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 * advansys_info()
2914 *
2915 * Return suitable for printing on the console with the argument
2916 * adapter's configuration information.
2917 *
2918 * Note: The information line should not exceed ASC_INFO_SIZE bytes,
2919 * otherwise the static 'info' array will be overrun.
2920 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002921static const char *advansys_info(struct Scsi_Host *shost)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002923 static char info[ASC_INFO_SIZE];
2924 asc_board_t *boardp;
2925 ASC_DVC_VAR *asc_dvc_varp;
2926 ADV_DVC_VAR *adv_dvc_varp;
2927 char *busname;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002928 char *widename = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002930 boardp = ASC_BOARDP(shost);
2931 if (ASC_NARROW_BOARD(boardp)) {
2932 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
2933 ASC_DBG(1, "advansys_info: begin\n");
2934 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
2935 if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) ==
2936 ASC_IS_ISAPNP) {
2937 busname = "ISA PnP";
2938 } else {
2939 busname = "ISA";
2940 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002941 sprintf(info,
2942 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X",
2943 ASC_VERSION, busname,
2944 (ulong)shost->io_port,
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04002945 (ulong)shost->io_port + ASC_IOADR_GAP - 1,
2946 shost->irq, shost->dma_channel);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002947 } else {
2948 if (asc_dvc_varp->bus_type & ASC_IS_VL) {
2949 busname = "VL";
2950 } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
2951 busname = "EISA";
2952 } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
2953 if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
2954 == ASC_IS_PCI_ULTRA) {
2955 busname = "PCI Ultra";
2956 } else {
2957 busname = "PCI";
2958 }
2959 } else {
2960 busname = "?";
Matthew Wilcoxecec1942007-07-30 08:08:22 -06002961 ASC_PRINT2("advansys_info: board %d: unknown "
2962 "bus type %d\n", boardp->id,
2963 asc_dvc_varp->bus_type);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002964 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002965 sprintf(info,
2966 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X",
Matthew Wilcoxecec1942007-07-30 08:08:22 -06002967 ASC_VERSION, busname, (ulong)shost->io_port,
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04002968 (ulong)shost->io_port + ASC_IOADR_GAP - 1,
2969 shost->irq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002970 }
2971 } else {
2972 /*
2973 * Wide Adapter Information
2974 *
2975 * Memory-mapped I/O is used instead of I/O space to access
2976 * the adapter, but display the I/O Port range. The Memory
2977 * I/O address is displayed through the driver /proc file.
2978 */
2979 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
2980 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002981 widename = "Ultra-Wide";
2982 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002983 widename = "Ultra2-Wide";
2984 } else {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002985 widename = "Ultra3-Wide";
2986 }
2987 sprintf(info,
2988 "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X",
2989 ASC_VERSION, widename, (ulong)adv_dvc_varp->iop_base,
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04002990 (ulong)adv_dvc_varp->iop_base + boardp->asc_n_io_port - 1, shost->irq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002991 }
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06002992 BUG_ON(strlen(info) >= ASC_INFO_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002993 ASC_DBG(1, "advansys_info: end\n");
2994 return info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995}
2996
Matthew Wilcox6ed1ef02007-09-09 08:56:33 -06002997static void asc_scsi_done(struct scsi_cmnd *scp)
2998{
2999 struct asc_board *boardp = ASC_BOARDP(scp->device->host);
3000
3001 if (scp->use_sg)
3002 dma_unmap_sg(boardp->dev,
3003 (struct scatterlist *)scp->request_buffer,
3004 scp->use_sg, scp->sc_data_direction);
3005 else if (scp->request_bufflen)
3006 dma_unmap_single(boardp->dev, scp->SCp.dma_handle,
3007 scp->request_bufflen, scp->sc_data_direction);
3008
3009 ASC_STATS(scp->device->host, done);
3010
3011 scp->scsi_done(scp);
3012}
3013
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014/*
3015 * advansys_queuecommand() - interrupt-driven I/O entrypoint.
3016 *
3017 * This function always returns 0. Command return status is saved
3018 * in the 'scp' result field.
3019 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07003020static int
Matthew Wilcoxb2a7a4b2007-09-09 08:56:35 -06003021advansys_queuecommand(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022{
Matthew Wilcoxb2a7a4b2007-09-09 08:56:35 -06003023 struct Scsi_Host *shost = scp->device->host;
3024 asc_board_t *boardp = ASC_BOARDP(shost);
3025 unsigned long flags;
Matthew Wilcoxb6622922007-09-09 08:56:31 -06003026 int asc_res, result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003028 ASC_STATS(shost, queuecommand);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003029 scp->scsi_done = done;
Matthew Wilcoxb2a7a4b2007-09-09 08:56:35 -06003030
3031 /*
3032 * host_lock taken by mid-level prior to call, but need
3033 * to protect against own ISR
3034 */
3035 spin_lock_irqsave(&boardp->lock, flags);
Matthew Wilcoxb6622922007-09-09 08:56:31 -06003036 asc_res = asc_execute_scsi_cmnd(scp);
Matthew Wilcoxb2a7a4b2007-09-09 08:56:35 -06003037 spin_unlock_irqrestore(&boardp->lock, flags);
3038
Matthew Wilcoxb6622922007-09-09 08:56:31 -06003039 switch (asc_res) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003040 case ASC_NOERROR:
3041 break;
3042 case ASC_BUSY:
Matthew Wilcoxb6622922007-09-09 08:56:31 -06003043 result = SCSI_MLQUEUE_HOST_BUSY;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003044 break;
3045 case ASC_ERROR:
3046 default:
Matthew Wilcox6ed1ef02007-09-09 08:56:33 -06003047 asc_scsi_done(scp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003048 break;
3049 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050
Matthew Wilcoxb6622922007-09-09 08:56:31 -06003051 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052}
3053
3054/*
3055 * advansys_reset()
3056 *
3057 * Reset the bus associated with the command 'scp'.
3058 *
3059 * This function runs its own thread. Interrupts must be blocked but
3060 * sleeping is allowed and no locking other than for host structures is
3061 * required. Returns SUCCESS or FAILED.
3062 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003063static int advansys_reset(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003065 struct Scsi_Host *shost;
3066 asc_board_t *boardp;
3067 ASC_DVC_VAR *asc_dvc_varp;
3068 ADV_DVC_VAR *adv_dvc_varp;
3069 ulong flags;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003070 int status;
3071 int ret = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003073 ASC_DBG1(1, "advansys_reset: 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003074
3075#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003076 if (scp->device->host != NULL) {
3077 ASC_STATS(scp->device->host, reset);
3078 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079#endif /* ADVANSYS_STATS */
3080
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003081 if ((shost = scp->device->host) == NULL) {
3082 scp->result = HOST_BYTE(DID_ERROR);
3083 return FAILED;
3084 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003086 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003088 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset started...\n",
3089 boardp->id);
3090 /*
3091 * Check for re-entrancy.
3092 */
3093 spin_lock_irqsave(&boardp->lock, flags);
3094 if (boardp->flags & ASC_HOST_IN_RESET) {
3095 spin_unlock_irqrestore(&boardp->lock, flags);
3096 return FAILED;
3097 }
3098 boardp->flags |= ASC_HOST_IN_RESET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003101 if (ASC_NARROW_BOARD(boardp)) {
3102 /*
3103 * Narrow Board
3104 */
3105 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003106
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003107 /*
3108 * Reset the chip and SCSI bus.
3109 */
3110 ASC_DBG(1, "advansys_reset: before AscInitAsc1000Driver()\n");
3111 status = AscInitAsc1000Driver(asc_dvc_varp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003113 /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */
3114 if (asc_dvc_varp->err_code) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003115 ASC_PRINT2("advansys_reset: board %d: SCSI bus reset "
3116 "error: 0x%x\n", boardp->id,
3117 asc_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003118 ret = FAILED;
3119 } else if (status) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003120 ASC_PRINT2("advansys_reset: board %d: SCSI bus reset "
3121 "warning: 0x%x\n", boardp->id, status);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003122 } else {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003123 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset "
3124 "successful.\n", boardp->id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003125 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003127 ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
3128 spin_lock_irqsave(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003130 } else {
3131 /*
3132 * Wide Board
3133 *
3134 * If the suggest reset bus flags are set, then reset the bus.
3135 * Otherwise only reset the device.
3136 */
3137 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003139 /*
3140 * Reset the target's SCSI bus.
3141 */
3142 ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n");
3143 switch (AdvResetChipAndSB(adv_dvc_varp)) {
3144 case ASC_TRUE:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003145 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset "
3146 "successful.\n", boardp->id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003147 break;
3148 case ASC_FALSE:
3149 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003150 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset "
3151 "error.\n", boardp->id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003152 ret = FAILED;
3153 break;
3154 }
3155 spin_lock_irqsave(&boardp->lock, flags);
3156 (void)AdvISR(adv_dvc_varp);
3157 }
3158 /* Board lock is held. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003160 /* Save the time of the most recently completed reset. */
3161 boardp->last_reset = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003163 /* Clear reset flag. */
3164 boardp->flags &= ~ASC_HOST_IN_RESET;
3165 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003167 ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003169 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170}
3171
3172/*
3173 * advansys_biosparam()
3174 *
3175 * Translate disk drive geometry if the "BIOS greater than 1 GB"
3176 * support is enabled for a drive.
3177 *
3178 * ip (information pointer) is an int array with the following definition:
3179 * ip[0]: heads
3180 * ip[1]: sectors
3181 * ip[2]: cylinders
3182 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07003183static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003185 sector_t capacity, int ip[])
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003187 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003189 ASC_DBG(1, "advansys_biosparam: begin\n");
3190 ASC_STATS(sdev->host, biosparam);
3191 boardp = ASC_BOARDP(sdev->host);
3192 if (ASC_NARROW_BOARD(boardp)) {
3193 if ((boardp->dvc_var.asc_dvc_var.dvc_cntl &
3194 ASC_CNTL_BIOS_GT_1GB) && capacity > 0x200000) {
3195 ip[0] = 255;
3196 ip[1] = 63;
3197 } else {
3198 ip[0] = 64;
3199 ip[1] = 32;
3200 }
3201 } else {
3202 if ((boardp->dvc_var.adv_dvc_var.bios_ctrl &
3203 BIOS_CTRL_EXTENDED_XLAT) && capacity > 0x200000) {
3204 ip[0] = 255;
3205 ip[1] = 63;
3206 } else {
3207 ip[0] = 64;
3208 ip[1] = 32;
3209 }
3210 }
3211 ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
3212 ASC_DBG(1, "advansys_biosparam: end\n");
3213 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214}
3215
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06003216static struct scsi_host_template advansys_template = {
Matthew Wilcox01fbfe02007-09-09 08:56:40 -06003217 .proc_name = DRV_NAME,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003219 .proc_info = advansys_proc_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220#endif
Matthew Wilcox01fbfe02007-09-09 08:56:40 -06003221 .name = DRV_NAME,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003222 .info = advansys_info,
3223 .queuecommand = advansys_queuecommand,
3224 .eh_bus_reset_handler = advansys_reset,
3225 .bios_param = advansys_biosparam,
3226 .slave_configure = advansys_slave_configure,
3227 /*
3228 * Because the driver may control an ISA adapter 'unchecked_isa_dma'
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06003229 * must be set. The flag will be cleared in advansys_board_found
3230 * for non-ISA adapters.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003231 */
3232 .unchecked_isa_dma = 1,
3233 /*
3234 * All adapters controlled by this driver are capable of large
3235 * scatter-gather lists. According to the mid-level SCSI documentation
3236 * this obviates any performance gain provided by setting
3237 * 'use_clustering'. But empirically while CPU utilization is increased
3238 * by enabling clustering, I/O throughput increases as well.
3239 */
3240 .use_clustering = ENABLE_CLUSTERING,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244 * First-level interrupt handler.
3245 *
Matthew Wilcox95c9f162007-09-09 08:56:39 -06003246 * 'dev_id' is a pointer to the interrupting adapter's Scsi_Host.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003248static irqreturn_t advansys_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003249{
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003250 unsigned long flags;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003251 struct Scsi_Host *shost = dev_id;
3252 asc_board_t *boardp = ASC_BOARDP(shost);
3253 irqreturn_t result = IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003255 ASC_DBG1(2, "advansys_interrupt: boardp 0x%p\n", boardp);
3256 spin_lock_irqsave(&boardp->lock, flags);
3257 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003258 if (AscIsIntPending(shost->io_port)) {
3259 result = IRQ_HANDLED;
3260 ASC_STATS(shost, interrupt);
3261 ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
3262 AscISR(&boardp->dvc_var.asc_dvc_var);
3263 }
3264 } else {
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003265 ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
3266 if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
3267 result = IRQ_HANDLED;
3268 ASC_STATS(shost, interrupt);
3269 }
3270 }
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003271 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003273 ASC_DBG(1, "advansys_interrupt: end\n");
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003274 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275}
3276
Matthew Wilcox47d853c2007-07-26 11:41:33 -04003277static void
3278advansys_narrow_slave_configure(struct scsi_device *sdev, ASC_DVC_VAR *asc_dvc)
3279{
3280 ASC_SCSI_BIT_ID_TYPE tid_bit = 1 << sdev->id;
3281 ASC_SCSI_BIT_ID_TYPE orig_use_tagged_qng = asc_dvc->use_tagged_qng;
3282
3283 if (sdev->lun == 0) {
3284 ASC_SCSI_BIT_ID_TYPE orig_init_sdtr = asc_dvc->init_sdtr;
3285 if ((asc_dvc->cfg->sdtr_enable & tid_bit) && sdev->sdtr) {
3286 asc_dvc->init_sdtr |= tid_bit;
3287 } else {
3288 asc_dvc->init_sdtr &= ~tid_bit;
3289 }
3290
3291 if (orig_init_sdtr != asc_dvc->init_sdtr)
3292 AscAsyncFix(asc_dvc, sdev);
3293 }
3294
3295 if (sdev->tagged_supported) {
3296 if (asc_dvc->cfg->cmd_qng_enabled & tid_bit) {
3297 if (sdev->lun == 0) {
3298 asc_dvc->cfg->can_tagged_qng |= tid_bit;
3299 asc_dvc->use_tagged_qng |= tid_bit;
3300 }
3301 scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
3302 asc_dvc->max_dvc_qng[sdev->id]);
3303 }
3304 } else {
3305 if (sdev->lun == 0) {
3306 asc_dvc->cfg->can_tagged_qng &= ~tid_bit;
3307 asc_dvc->use_tagged_qng &= ~tid_bit;
3308 }
3309 scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
3310 }
3311
3312 if ((sdev->lun == 0) &&
3313 (orig_use_tagged_qng != asc_dvc->use_tagged_qng)) {
3314 AscWriteLramByte(asc_dvc->iop_base, ASCV_DISC_ENABLE_B,
3315 asc_dvc->cfg->disc_enable);
3316 AscWriteLramByte(asc_dvc->iop_base, ASCV_USE_TAGGED_QNG_B,
3317 asc_dvc->use_tagged_qng);
3318 AscWriteLramByte(asc_dvc->iop_base, ASCV_CAN_TAGGED_QNG_B,
3319 asc_dvc->cfg->can_tagged_qng);
3320
3321 asc_dvc->max_dvc_qng[sdev->id] =
3322 asc_dvc->cfg->max_tag_qng[sdev->id];
3323 AscWriteLramByte(asc_dvc->iop_base,
3324 (ushort)(ASCV_MAX_DVC_QNG_BEG + sdev->id),
3325 asc_dvc->max_dvc_qng[sdev->id]);
3326 }
3327}
3328
3329/*
3330 * Wide Transfers
3331 *
3332 * If the EEPROM enabled WDTR for the device and the device supports wide
3333 * bus (16 bit) transfers, then turn on the device's 'wdtr_able' bit and
3334 * write the new value to the microcode.
3335 */
3336static void
3337advansys_wide_enable_wdtr(AdvPortAddr iop_base, unsigned short tidmask)
3338{
3339 unsigned short cfg_word;
3340 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
3341 if ((cfg_word & tidmask) != 0)
3342 return;
3343
3344 cfg_word |= tidmask;
3345 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
3346
3347 /*
3348 * Clear the microcode SDTR and WDTR negotiation done indicators for
3349 * the target to cause it to negotiate with the new setting set above.
3350 * WDTR when accepted causes the target to enter asynchronous mode, so
3351 * SDTR must be negotiated.
3352 */
3353 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
3354 cfg_word &= ~tidmask;
3355 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
3356 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
3357 cfg_word &= ~tidmask;
3358 AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
3359}
3360
3361/*
3362 * Synchronous Transfers
3363 *
3364 * If the EEPROM enabled SDTR for the device and the device
3365 * supports synchronous transfers, then turn on the device's
3366 * 'sdtr_able' bit. Write the new value to the microcode.
3367 */
3368static void
3369advansys_wide_enable_sdtr(AdvPortAddr iop_base, unsigned short tidmask)
3370{
3371 unsigned short cfg_word;
3372 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
3373 if ((cfg_word & tidmask) != 0)
3374 return;
3375
3376 cfg_word |= tidmask;
3377 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
3378
3379 /*
3380 * Clear the microcode "SDTR negotiation" done indicator for the
3381 * target to cause it to negotiate with the new setting set above.
3382 */
3383 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
3384 cfg_word &= ~tidmask;
3385 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
3386}
3387
3388/*
3389 * PPR (Parallel Protocol Request) Capable
3390 *
3391 * If the device supports DT mode, then it must be PPR capable.
3392 * The PPR message will be used in place of the SDTR and WDTR
3393 * messages to negotiate synchronous speed and offset, transfer
3394 * width, and protocol options.
3395 */
3396static void advansys_wide_enable_ppr(ADV_DVC_VAR *adv_dvc,
3397 AdvPortAddr iop_base, unsigned short tidmask)
3398{
3399 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able);
3400 adv_dvc->ppr_able |= tidmask;
3401 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able);
3402}
3403
3404static void
3405advansys_wide_slave_configure(struct scsi_device *sdev, ADV_DVC_VAR *adv_dvc)
3406{
3407 AdvPortAddr iop_base = adv_dvc->iop_base;
3408 unsigned short tidmask = 1 << sdev->id;
3409
3410 if (sdev->lun == 0) {
3411 /*
3412 * Handle WDTR, SDTR, and Tag Queuing. If the feature
3413 * is enabled in the EEPROM and the device supports the
3414 * feature, then enable it in the microcode.
3415 */
3416
3417 if ((adv_dvc->wdtr_able & tidmask) && sdev->wdtr)
3418 advansys_wide_enable_wdtr(iop_base, tidmask);
3419 if ((adv_dvc->sdtr_able & tidmask) && sdev->sdtr)
3420 advansys_wide_enable_sdtr(iop_base, tidmask);
3421 if (adv_dvc->chip_type == ADV_CHIP_ASC38C1600 && sdev->ppr)
3422 advansys_wide_enable_ppr(adv_dvc, iop_base, tidmask);
3423
3424 /*
3425 * Tag Queuing is disabled for the BIOS which runs in polled
3426 * mode and would see no benefit from Tag Queuing. Also by
3427 * disabling Tag Queuing in the BIOS devices with Tag Queuing
3428 * bugs will at least work with the BIOS.
3429 */
3430 if ((adv_dvc->tagqng_able & tidmask) &&
3431 sdev->tagged_supported) {
3432 unsigned short cfg_word;
3433 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
3434 cfg_word |= tidmask;
3435 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
3436 cfg_word);
3437 AdvWriteByteLram(iop_base,
3438 ASC_MC_NUMBER_OF_MAX_CMD + sdev->id,
3439 adv_dvc->max_dvc_qng);
3440 }
3441 }
3442
3443 if ((adv_dvc->tagqng_able & tidmask) && sdev->tagged_supported) {
3444 scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
3445 adv_dvc->max_dvc_qng);
3446 } else {
3447 scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
3448 }
3449}
3450
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451/*
3452 * Set the number of commands to queue per device for the
3453 * specified host adapter.
3454 */
Matthew Wilcox47d853c2007-07-26 11:41:33 -04003455static int advansys_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456{
Matthew Wilcox47d853c2007-07-26 11:41:33 -04003457 asc_board_t *boardp = ASC_BOARDP(sdev->host);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003458 boardp->flags |= ASC_SELECT_QUEUE_DEPTHS;
Matthew Wilcox47d853c2007-07-26 11:41:33 -04003459
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003460 /*
Matthew Wilcox47d853c2007-07-26 11:41:33 -04003461 * Save a pointer to the sdev and set its initial/maximum
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003462 * queue depth. Only save the pointer for a lun0 dev though.
3463 */
Matthew Wilcox47d853c2007-07-26 11:41:33 -04003464 if (sdev->lun == 0)
3465 boardp->device[sdev->id] = sdev;
3466
3467 if (ASC_NARROW_BOARD(boardp))
3468 advansys_narrow_slave_configure(sdev,
3469 &boardp->dvc_var.asc_dvc_var);
3470 else
3471 advansys_wide_slave_configure(sdev,
3472 &boardp->dvc_var.adv_dvc_var);
3473
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003474 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475}
3476
3477/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478 * Execute a single 'Scsi_Cmnd'.
3479 *
3480 * The function 'done' is called when the request has been completed.
3481 *
3482 * Scsi_Cmnd:
3483 *
3484 * host - board controlling device
3485 * device - device to send command
3486 * target - target of device
3487 * lun - lun of device
3488 * cmd_len - length of SCSI CDB
3489 * cmnd - buffer for SCSI 8, 10, or 12 byte CDB
3490 * use_sg - if non-zero indicates scatter-gather request with use_sg elements
3491 *
3492 * if (use_sg == 0) {
3493 * request_buffer - buffer address for request
3494 * request_bufflen - length of request buffer
3495 * } else {
3496 * request_buffer - pointer to scatterlist structure
3497 * }
3498 *
3499 * sense_buffer - sense command buffer
3500 *
3501 * result (4 bytes of an int):
3502 * Byte Meaning
3503 * 0 SCSI Status Byte Code
3504 * 1 SCSI One Byte Message Code
3505 * 2 Host Error Code
3506 * 3 Mid-Level Error Code
3507 *
3508 * host driver fields:
3509 * SCp - Scsi_Pointer used for command processing status
3510 * scsi_done - used to save caller's done function
3511 * host_scribble - used for pointer to another struct scsi_cmnd
3512 *
Matthew Wilcox349d2c42007-09-09 08:56:34 -06003513 * If this function returns ASC_NOERROR the request will be completed
3514 * from the interrupt handler.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515 *
Matthew Wilcox6ed1ef02007-09-09 08:56:33 -06003516 * If this function returns ASC_ERROR the host error code has been set,
3517 * and the called must call asc_scsi_done.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518 *
Matthew Wilcoxb6622922007-09-09 08:56:31 -06003519 * If ASC_BUSY is returned the request will be returned to the midlayer
3520 * and re-tried later.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003522static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003524 asc_board_t *boardp;
3525 ASC_DVC_VAR *asc_dvc_varp;
3526 ADV_DVC_VAR *adv_dvc_varp;
3527 ADV_SCSI_REQ_Q *adv_scsiqp;
3528 struct scsi_device *device;
3529 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003531 ASC_DBG2(1, "asc_execute_scsi_cmnd: scp 0x%lx, done 0x%lx\n",
3532 (ulong)scp, (ulong)scp->scsi_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003534 boardp = ASC_BOARDP(scp->device->host);
3535 device = boardp->device[scp->device->id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003537 if (ASC_NARROW_BOARD(boardp)) {
3538 /*
3539 * Build and execute Narrow Board request.
3540 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003542 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003544 /*
3545 * Build Asc Library request structure using the
3546 * global structures 'asc_scsi_req' and 'asc_sg_head'.
3547 *
3548 * If an error is returned, then the request has been
3549 * queued on the board done queue. It will be completed
3550 * by the caller.
3551 *
3552 * asc_build_req() can not return ASC_BUSY.
3553 */
3554 if (asc_build_req(boardp, scp) == ASC_ERROR) {
3555 ASC_STATS(scp->device->host, build_error);
3556 return ASC_ERROR;
3557 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003559 switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
3560 case ASC_NOERROR:
3561 ASC_STATS(scp->device->host, exe_noerror);
3562 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003563 * Increment monotonically increasing per device
3564 * successful request counter. Wrapping doesn't matter.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003565 */
3566 boardp->reqcnt[scp->device->id]++;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003567 ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue(), "
3568 "ASC_NOERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003569 break;
3570 case ASC_BUSY:
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003571 ASC_STATS(scp->device->host, exe_busy);
3572 break;
3573 case ASC_ERROR:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003574 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
3575 "AscExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
3576 boardp->id, asc_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003577 ASC_STATS(scp->device->host, exe_error);
3578 scp->result = HOST_BYTE(DID_ERROR);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003579 break;
3580 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003581 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
3582 "AscExeScsiQueue() unknown, err_code 0x%x\n",
3583 boardp->id, asc_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003584 ASC_STATS(scp->device->host, exe_unknown);
3585 scp->result = HOST_BYTE(DID_ERROR);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003586 break;
3587 }
3588 } else {
3589 /*
3590 * Build and execute Wide Board request.
3591 */
3592 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003594 /*
3595 * Build and get a pointer to an Adv Library request structure.
3596 *
3597 * If the request is successfully built then send it below,
3598 * otherwise return with an error.
3599 */
3600 switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
3601 case ASC_NOERROR:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003602 ASC_DBG(3, "asc_execute_scsi_cmnd: adv_build_req "
3603 "ASC_NOERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003604 break;
3605 case ASC_BUSY:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003606 ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req "
3607 "ASC_BUSY\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003608 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003609 * The asc_stats fields 'adv_build_noreq' and
3610 * 'adv_build_nosg' count wide board busy conditions.
3611 * They are updated in adv_build_req and
3612 * adv_get_sglist, respectively.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003613 */
3614 return ASC_BUSY;
3615 case ASC_ERROR:
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003616 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003617 ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req "
3618 "ASC_ERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003619 ASC_STATS(scp->device->host, build_error);
3620 return ASC_ERROR;
3621 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003622
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003623 switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) {
3624 case ASC_NOERROR:
3625 ASC_STATS(scp->device->host, exe_noerror);
3626 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003627 * Increment monotonically increasing per device
3628 * successful request counter. Wrapping doesn't matter.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003629 */
3630 boardp->reqcnt[scp->device->id]++;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003631 ASC_DBG(1, "asc_execute_scsi_cmnd: AdvExeScsiQueue(), "
3632 "ASC_NOERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003633 break;
3634 case ASC_BUSY:
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003635 ASC_STATS(scp->device->host, exe_busy);
3636 break;
3637 case ASC_ERROR:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003638 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
3639 "AdvExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
3640 boardp->id, adv_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003641 ASC_STATS(scp->device->host, exe_error);
3642 scp->result = HOST_BYTE(DID_ERROR);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003643 break;
3644 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003645 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
3646 "AdvExeScsiQueue() unknown, err_code 0x%x\n",
3647 boardp->id, adv_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003648 ASC_STATS(scp->device->host, exe_unknown);
3649 scp->result = HOST_BYTE(DID_ERROR);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003650 break;
3651 }
3652 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003654 ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
3655 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003656}
3657
3658/*
3659 * Build a request structure for the Asc Library (Narrow Board).
3660 *
3661 * The global structures 'asc_scsi_q' and 'asc_sg_head' are
3662 * used to build the request.
3663 *
Matthew Wilcox6ed1ef02007-09-09 08:56:33 -06003664 * If an error occurs, then return ASC_ERROR.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003666static int asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003668 /*
3669 * Mutually exclusive access is required to 'asc_scsi_q' and
3670 * 'asc_sg_head' until after the request is started.
3671 */
3672 memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003674 /*
3675 * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'.
3676 */
3677 asc_scsi_q.q2.srb_ptr = ASC_VADDR_TO_U32(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003679 /*
3680 * Build the ASC_SCSI_Q request.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003681 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003682 asc_scsi_q.cdbptr = &scp->cmnd[0];
3683 asc_scsi_q.q2.cdb_len = scp->cmd_len;
3684 asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id);
3685 asc_scsi_q.q1.target_lun = scp->device->lun;
3686 asc_scsi_q.q2.target_ix =
3687 ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
3688 asc_scsi_q.q1.sense_addr =
3689 cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
3690 asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003692 /*
3693 * If there are any outstanding requests for the current target,
3694 * then every 255th request send an ORDERED request. This heuristic
3695 * tries to retain the benefit of request sorting while preventing
3696 * request starvation. 255 is the max number of tags or pending commands
3697 * a device may have outstanding.
3698 *
3699 * The request count is incremented below for every successfully
3700 * started request.
3701 *
3702 */
3703 if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->device->id] > 0) &&
3704 (boardp->reqcnt[scp->device->id] % 255) == 0) {
3705 asc_scsi_q.q2.tag_code = MSG_ORDERED_TAG;
3706 } else {
3707 asc_scsi_q.q2.tag_code = MSG_SIMPLE_TAG;
3708 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003710 /*
3711 * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
3712 * buffer command.
3713 */
3714 if (scp->use_sg == 0) {
3715 /*
3716 * CDB request of single contiguous buffer.
3717 */
3718 ASC_STATS(scp->device->host, cont_cnt);
3719 scp->SCp.dma_handle = scp->request_bufflen ?
Matthew Wilcox394dbf32007-07-26 11:56:40 -04003720 dma_map_single(boardp->dev, scp->request_buffer,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003721 scp->request_bufflen,
3722 scp->sc_data_direction) : 0;
3723 asc_scsi_q.q1.data_addr = cpu_to_le32(scp->SCp.dma_handle);
3724 asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen);
3725 ASC_STATS_ADD(scp->device->host, cont_xfer,
3726 ASC_CEILING(scp->request_bufflen, 512));
3727 asc_scsi_q.q1.sg_queue_cnt = 0;
3728 asc_scsi_q.sg_head = NULL;
3729 } else {
3730 /*
3731 * CDB scatter-gather request list.
3732 */
3733 int sgcnt;
3734 int use_sg;
3735 struct scatterlist *slp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003737 slp = (struct scatterlist *)scp->request_buffer;
Matthew Wilcox394dbf32007-07-26 11:56:40 -04003738 use_sg = dma_map_sg(boardp->dev, slp, scp->use_sg,
3739 scp->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003740
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003741 if (use_sg > scp->device->host->sg_tablesize) {
Matthew Wilcox394dbf32007-07-26 11:56:40 -04003742 ASC_PRINT3("asc_build_req: board %d: use_sg %d > "
3743 "sg_tablesize %d\n", boardp->id, use_sg,
3744 scp->device->host->sg_tablesize);
3745 dma_unmap_sg(boardp->dev, slp, scp->use_sg,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003746 scp->sc_data_direction);
3747 scp->result = HOST_BYTE(DID_ERROR);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003748 return ASC_ERROR;
3749 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003751 ASC_STATS(scp->device->host, sg_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003752
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003753 /*
3754 * Use global ASC_SG_HEAD structure and set the ASC_SCSI_Q
3755 * structure to point to it.
3756 */
3757 memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003759 asc_scsi_q.q1.cntl |= QC_SG_HEAD;
3760 asc_scsi_q.sg_head = &asc_sg_head;
3761 asc_scsi_q.q1.data_cnt = 0;
3762 asc_scsi_q.q1.data_addr = 0;
3763 /* This is a byte value, otherwise it would need to be swapped. */
3764 asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = use_sg;
3765 ASC_STATS_ADD(scp->device->host, sg_elem,
3766 asc_sg_head.entry_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003767
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003768 /*
3769 * Convert scatter-gather list into ASC_SG_HEAD list.
3770 */
3771 for (sgcnt = 0; sgcnt < use_sg; sgcnt++, slp++) {
3772 asc_sg_head.sg_list[sgcnt].addr =
3773 cpu_to_le32(sg_dma_address(slp));
3774 asc_sg_head.sg_list[sgcnt].bytes =
3775 cpu_to_le32(sg_dma_len(slp));
3776 ASC_STATS_ADD(scp->device->host, sg_xfer,
3777 ASC_CEILING(sg_dma_len(slp), 512));
3778 }
3779 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003781 ASC_DBG_PRT_ASC_SCSI_Q(2, &asc_scsi_q);
3782 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003784 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785}
3786
3787/*
3788 * Build a request structure for the Adv Library (Wide Board).
3789 *
3790 * If an adv_req_t can not be allocated to issue the request,
3791 * then return ASC_BUSY. If an error occurs, then return ASC_ERROR.
3792 *
3793 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the
3794 * microcode for DMA addresses or math operations are byte swapped
3795 * to little-endian order.
3796 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003797static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798adv_build_req(asc_board_t *boardp, struct scsi_cmnd *scp,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003799 ADV_SCSI_REQ_Q **adv_scsiqpp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003801 adv_req_t *reqp;
3802 ADV_SCSI_REQ_Q *scsiqp;
3803 int i;
3804 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003805
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003806 /*
3807 * Allocate an adv_req_t structure from the board to execute
3808 * the command.
3809 */
3810 if (boardp->adv_reqp == NULL) {
3811 ASC_DBG(1, "adv_build_req: no free adv_req_t\n");
3812 ASC_STATS(scp->device->host, adv_build_noreq);
3813 return ASC_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814 } else {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003815 reqp = boardp->adv_reqp;
3816 boardp->adv_reqp = reqp->next_reqp;
3817 reqp->next_reqp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003818 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003820 /*
3821 * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
3822 */
3823 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003825 /*
3826 * Initialize the structure.
3827 */
3828 scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003830 /*
3831 * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
3832 */
3833 scsiqp->srb_ptr = ASC_VADDR_TO_U32(reqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003835 /*
3836 * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure.
3837 */
3838 reqp->cmndp = scp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003839
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003840 /*
3841 * Build the ADV_SCSI_REQ_Q request.
3842 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003843
Matthew Wilcoxf05ec592007-09-09 08:56:36 -06003844 /* Set CDB length and copy it to the request structure. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003845 scsiqp->cdb_len = scp->cmd_len;
3846 /* Copy first 12 CDB bytes to cdb[]. */
3847 for (i = 0; i < scp->cmd_len && i < 12; i++) {
3848 scsiqp->cdb[i] = scp->cmnd[i];
3849 }
3850 /* Copy last 4 CDB bytes, if present, to cdb16[]. */
3851 for (; i < scp->cmd_len; i++) {
3852 scsiqp->cdb16[i - 12] = scp->cmnd[i];
3853 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003854
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003855 scsiqp->target_id = scp->device->id;
3856 scsiqp->target_lun = scp->device->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003858 scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
3859 scsiqp->sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003860
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003861 /*
3862 * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather
3863 * buffer command.
3864 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003866 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
3867 scsiqp->vdata_addr = scp->request_buffer;
3868 scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer));
3869
3870 if (scp->use_sg == 0) {
3871 /*
3872 * CDB request of single contiguous buffer.
3873 */
3874 reqp->sgblkp = NULL;
3875 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
3876 if (scp->request_bufflen) {
3877 scsiqp->vdata_addr = scp->request_buffer;
3878 scp->SCp.dma_handle =
Matthew Wilcox394dbf32007-07-26 11:56:40 -04003879 dma_map_single(boardp->dev, scp->request_buffer,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003880 scp->request_bufflen,
3881 scp->sc_data_direction);
3882 } else {
3883 scsiqp->vdata_addr = NULL;
3884 scp->SCp.dma_handle = 0;
3885 }
3886 scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle);
3887 scsiqp->sg_list_ptr = NULL;
3888 scsiqp->sg_real_addr = 0;
3889 ASC_STATS(scp->device->host, cont_cnt);
3890 ASC_STATS_ADD(scp->device->host, cont_xfer,
3891 ASC_CEILING(scp->request_bufflen, 512));
3892 } else {
3893 /*
3894 * CDB scatter-gather request list.
3895 */
3896 struct scatterlist *slp;
3897 int use_sg;
3898
3899 slp = (struct scatterlist *)scp->request_buffer;
Matthew Wilcox394dbf32007-07-26 11:56:40 -04003900 use_sg = dma_map_sg(boardp->dev, slp, scp->use_sg,
3901 scp->sc_data_direction);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003902
3903 if (use_sg > ADV_MAX_SG_LIST) {
Matthew Wilcox394dbf32007-07-26 11:56:40 -04003904 ASC_PRINT3("adv_build_req: board %d: use_sg %d > "
3905 "ADV_MAX_SG_LIST %d\n", boardp->id, use_sg,
3906 scp->device->host->sg_tablesize);
3907 dma_unmap_sg(boardp->dev, slp, scp->use_sg,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003908 scp->sc_data_direction);
3909 scp->result = HOST_BYTE(DID_ERROR);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003910
3911 /*
Matthew Wilcox394dbf32007-07-26 11:56:40 -04003912 * Free the 'adv_req_t' structure by adding it back
3913 * to the board free list.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003914 */
3915 reqp->next_reqp = boardp->adv_reqp;
3916 boardp->adv_reqp = reqp;
3917
3918 return ASC_ERROR;
3919 }
3920
Matthew Wilcox394dbf32007-07-26 11:56:40 -04003921 ret = adv_get_sglist(boardp, reqp, scp, use_sg);
3922 if (ret != ADV_SUCCESS) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003923 /*
Matthew Wilcox394dbf32007-07-26 11:56:40 -04003924 * Free the adv_req_t structure by adding it back to
3925 * the board free list.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003926 */
3927 reqp->next_reqp = boardp->adv_reqp;
3928 boardp->adv_reqp = reqp;
3929
3930 return ret;
3931 }
3932
3933 ASC_STATS(scp->device->host, sg_cnt);
3934 ASC_STATS_ADD(scp->device->host, sg_elem, use_sg);
3935 }
3936
3937 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
3938 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
3939
3940 *adv_scsiqpp = scsiqp;
3941
3942 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003943}
3944
3945/*
3946 * Build scatter-gather list for Adv Library (Wide Board).
3947 *
3948 * Additional ADV_SG_BLOCK structures will need to be allocated
3949 * if the total number of scatter-gather elements exceeds
3950 * NO_OF_SG_PER_BLOCK (15). The ADV_SG_BLOCK structures are
3951 * assumed to be physically contiguous.
3952 *
3953 * Return:
3954 * ADV_SUCCESS(1) - SG List successfully created
3955 * ADV_ERROR(-1) - SG List creation failed
3956 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003957static int
3958adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, struct scsi_cmnd *scp,
3959 int use_sg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003961 adv_sgblk_t *sgblkp;
3962 ADV_SCSI_REQ_Q *scsiqp;
3963 struct scatterlist *slp;
3964 int sg_elem_cnt;
3965 ADV_SG_BLOCK *sg_block, *prev_sg_block;
3966 ADV_PADDR sg_block_paddr;
3967 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003968
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003969 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
3970 slp = (struct scatterlist *)scp->request_buffer;
3971 sg_elem_cnt = use_sg;
3972 prev_sg_block = NULL;
3973 reqp->sgblkp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003974
Matthew Wilcox95c9f162007-09-09 08:56:39 -06003975 for (;;) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003976 /*
3977 * Allocate a 'adv_sgblk_t' structure from the board free
3978 * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK
3979 * (15) scatter-gather elements.
3980 */
3981 if ((sgblkp = boardp->adv_sgblkp) == NULL) {
3982 ASC_DBG(1, "adv_get_sglist: no free adv_sgblk_t\n");
3983 ASC_STATS(scp->device->host, adv_build_nosg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003985 /*
Matthew Wilcox95c9f162007-09-09 08:56:39 -06003986 * Allocation failed. Free 'adv_sgblk_t' structures
3987 * already allocated for the request.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003988 */
3989 while ((sgblkp = reqp->sgblkp) != NULL) {
3990 /* Remove 'sgblkp' from the request list. */
3991 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003992
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003993 /* Add 'sgblkp' to the board free list. */
3994 sgblkp->next_sgblkp = boardp->adv_sgblkp;
3995 boardp->adv_sgblkp = sgblkp;
3996 }
3997 return ASC_BUSY;
Matthew Wilcox95c9f162007-09-09 08:56:39 -06003998 }
3999
4000 /* Complete 'adv_sgblk_t' board allocation. */
4001 boardp->adv_sgblkp = sgblkp->next_sgblkp;
4002 sgblkp->next_sgblkp = NULL;
4003
4004 /*
4005 * Get 8 byte aligned virtual and physical addresses
4006 * for the allocated ADV_SG_BLOCK structure.
4007 */
4008 sg_block = (ADV_SG_BLOCK *)ADV_8BALIGN(&sgblkp->sg_block);
4009 sg_block_paddr = virt_to_bus(sg_block);
4010
4011 /*
4012 * Check if this is the first 'adv_sgblk_t' for the
4013 * request.
4014 */
4015 if (reqp->sgblkp == NULL) {
4016 /* Request's first scatter-gather block. */
4017 reqp->sgblkp = sgblkp;
4018
4019 /*
4020 * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical
4021 * address pointers.
4022 */
4023 scsiqp->sg_list_ptr = sg_block;
4024 scsiqp->sg_real_addr = cpu_to_le32(sg_block_paddr);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004025 } else {
Matthew Wilcox95c9f162007-09-09 08:56:39 -06004026 /* Request's second or later scatter-gather block. */
4027 sgblkp->next_sgblkp = reqp->sgblkp;
4028 reqp->sgblkp = sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004029
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004030 /*
Matthew Wilcox95c9f162007-09-09 08:56:39 -06004031 * Point the previous ADV_SG_BLOCK structure to
4032 * the newly allocated ADV_SG_BLOCK structure.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004033 */
Matthew Wilcox95c9f162007-09-09 08:56:39 -06004034 prev_sg_block->sg_ptr = cpu_to_le32(sg_block_paddr);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004035 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004037 for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) {
4038 sg_block->sg_list[i].sg_addr =
Matthew Wilcox95c9f162007-09-09 08:56:39 -06004039 cpu_to_le32(sg_dma_address(slp));
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004040 sg_block->sg_list[i].sg_count =
Matthew Wilcox95c9f162007-09-09 08:56:39 -06004041 cpu_to_le32(sg_dma_len(slp));
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004042 ASC_STATS_ADD(scp->device->host, sg_xfer,
4043 ASC_CEILING(sg_dma_len(slp), 512));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004045 if (--sg_elem_cnt == 0) { /* Last ADV_SG_BLOCK and scatter-gather entry. */
4046 sg_block->sg_cnt = i + 1;
4047 sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */
4048 return ADV_SUCCESS;
4049 }
4050 slp++;
4051 }
4052 sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
4053 prev_sg_block = sg_block;
4054 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004055}
4056
4057/*
4058 * asc_isr_callback() - Second Level Interrupt Handler called by AscISR().
4059 *
4060 * Interrupt callback function for the Narrow SCSI Asc Library.
4061 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004062static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004064 asc_board_t *boardp;
4065 struct scsi_cmnd *scp;
4066 struct Scsi_Host *shost;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004067
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004068 ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp 0x%lx, qdonep 0x%lx\n",
4069 (ulong)asc_dvc_varp, (ulong)qdonep);
4070 ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004071
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004072 /*
4073 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
4074 * command that has been completed.
4075 */
4076 scp = (struct scsi_cmnd *)ASC_U32_TO_VADDR(qdonep->d2.srb_ptr);
4077 ASC_DBG1(1, "asc_isr_callback: scp 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004078
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004079 if (scp == NULL) {
4080 ASC_PRINT("asc_isr_callback: scp is NULL\n");
4081 return;
4082 }
4083 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004084
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004085 shost = scp->device->host;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004086 ASC_STATS(shost, callback);
4087 ASC_DBG1(1, "asc_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004088
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004089 boardp = ASC_BOARDP(shost);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06004090 BUG_ON(asc_dvc_varp != &boardp->dvc_var.asc_dvc_var);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004091
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004092 /*
4093 * 'qdonep' contains the command's ending status.
4094 */
4095 switch (qdonep->d3.done_stat) {
4096 case QD_NO_ERROR:
4097 ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n");
4098 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004099
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004100 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004101 * Check for an underrun condition.
4102 *
4103 * If there was no error and an underrun condition, then
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004104 * return the number of underrun bytes.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004105 */
4106 if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 &&
4107 qdonep->remain_bytes <= scp->request_bufflen) {
4108 ASC_DBG1(1,
4109 "asc_isr_callback: underrun condition %u bytes\n",
4110 (unsigned)qdonep->remain_bytes);
4111 scp->resid = qdonep->remain_bytes;
4112 }
4113 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004114
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004115 case QD_WITH_ERROR:
4116 ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n");
4117 switch (qdonep->d3.host_stat) {
4118 case QHSTA_NO_ERROR:
4119 if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
4120 ASC_DBG(2,
4121 "asc_isr_callback: SAM_STAT_CHECK_CONDITION\n");
4122 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
4123 sizeof(scp->sense_buffer));
4124 /*
Matthew Wilcox95c9f162007-09-09 08:56:39 -06004125 * Note: The 'status_byte()' macro used by
4126 * target drivers defined in scsi.h shifts the
4127 * status byte returned by host drivers right
4128 * by 1 bit. This is why target drivers also
4129 * use right shifted status byte definitions.
4130 * For instance target drivers use
4131 * CHECK_CONDITION, defined to 0x1, instead of
4132 * the SCSI defined check condition value of
4133 * 0x2. Host drivers are supposed to return
4134 * the status byte as it is defined by SCSI.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004135 */
4136 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
4137 STATUS_BYTE(qdonep->d3.scsi_stat);
4138 } else {
4139 scp->result = STATUS_BYTE(qdonep->d3.scsi_stat);
4140 }
4141 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004143 default:
4144 /* QHSTA error occurred */
4145 ASC_DBG1(1, "asc_isr_callback: host_stat 0x%x\n",
4146 qdonep->d3.host_stat);
4147 scp->result = HOST_BYTE(DID_BAD_TARGET);
4148 break;
4149 }
4150 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004151
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004152 case QD_ABORTED_BY_HOST:
4153 ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOST\n");
4154 scp->result =
4155 HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.
4156 scsi_msg) |
4157 STATUS_BYTE(qdonep->d3.scsi_stat);
4158 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004160 default:
4161 ASC_DBG1(1, "asc_isr_callback: done_stat 0x%x\n",
4162 qdonep->d3.done_stat);
4163 scp->result =
4164 HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.
4165 scsi_msg) |
4166 STATUS_BYTE(qdonep->d3.scsi_stat);
4167 break;
4168 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004170 /*
4171 * If the 'init_tidmask' bit isn't already set for the target and the
4172 * current request finished normally, then set the bit for the target
4173 * to indicate that a device is present.
4174 */
4175 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
4176 qdonep->d3.done_stat == QD_NO_ERROR &&
4177 qdonep->d3.host_stat == QHSTA_NO_ERROR) {
4178 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
4179 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180
Matthew Wilcox6ed1ef02007-09-09 08:56:33 -06004181 asc_scsi_done(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004183 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184}
4185
4186/*
4187 * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR().
4188 *
4189 * Callback function for the Wide SCSI Adv Library.
4190 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004191static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004193 asc_board_t *boardp;
4194 adv_req_t *reqp;
4195 adv_sgblk_t *sgblkp;
4196 struct scsi_cmnd *scp;
4197 struct Scsi_Host *shost;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004198 ADV_DCNT resid_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004200 ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp 0x%lx, scsiqp 0x%lx\n",
4201 (ulong)adv_dvc_varp, (ulong)scsiqp);
4202 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004203
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004204 /*
4205 * Get the adv_req_t structure for the command that has been
4206 * completed. The adv_req_t structure actually contains the
4207 * completed ADV_SCSI_REQ_Q structure.
4208 */
4209 reqp = (adv_req_t *)ADV_U32_TO_VADDR(scsiqp->srb_ptr);
4210 ASC_DBG1(1, "adv_isr_callback: reqp 0x%lx\n", (ulong)reqp);
4211 if (reqp == NULL) {
4212 ASC_PRINT("adv_isr_callback: reqp is NULL\n");
4213 return;
4214 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004216 /*
4217 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
4218 * command that has been completed.
4219 *
4220 * Note: The adv_req_t request structure and adv_sgblk_t structure,
4221 * if any, are dropped, because a board structure pointer can not be
4222 * determined.
4223 */
4224 scp = reqp->cmndp;
4225 ASC_DBG1(1, "adv_isr_callback: scp 0x%lx\n", (ulong)scp);
4226 if (scp == NULL) {
4227 ASC_PRINT
4228 ("adv_isr_callback: scp is NULL; adv_req_t dropped.\n");
4229 return;
4230 }
4231 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004233 shost = scp->device->host;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004234 ASC_STATS(shost, callback);
4235 ASC_DBG1(1, "adv_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004236
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004237 boardp = ASC_BOARDP(shost);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06004238 BUG_ON(adv_dvc_varp != &boardp->dvc_var.adv_dvc_var);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004239
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004240 /*
4241 * 'done_status' contains the command's ending status.
4242 */
4243 switch (scsiqp->done_status) {
4244 case QD_NO_ERROR:
4245 ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n");
4246 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004247
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004248 /*
4249 * Check for an underrun condition.
4250 *
4251 * If there was no error and an underrun condition, then
4252 * then return the number of underrun bytes.
4253 */
4254 resid_cnt = le32_to_cpu(scsiqp->data_cnt);
4255 if (scp->request_bufflen != 0 && resid_cnt != 0 &&
4256 resid_cnt <= scp->request_bufflen) {
4257 ASC_DBG1(1,
4258 "adv_isr_callback: underrun condition %lu bytes\n",
4259 (ulong)resid_cnt);
4260 scp->resid = resid_cnt;
4261 }
4262 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004264 case QD_WITH_ERROR:
4265 ASC_DBG(2, "adv_isr_callback: QD_WITH_ERROR\n");
4266 switch (scsiqp->host_status) {
4267 case QHSTA_NO_ERROR:
4268 if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
4269 ASC_DBG(2,
4270 "adv_isr_callback: SAM_STAT_CHECK_CONDITION\n");
4271 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
4272 sizeof(scp->sense_buffer));
4273 /*
Matthew Wilcox95c9f162007-09-09 08:56:39 -06004274 * Note: The 'status_byte()' macro used by
4275 * target drivers defined in scsi.h shifts the
4276 * status byte returned by host drivers right
4277 * by 1 bit. This is why target drivers also
4278 * use right shifted status byte definitions.
4279 * For instance target drivers use
4280 * CHECK_CONDITION, defined to 0x1, instead of
4281 * the SCSI defined check condition value of
4282 * 0x2. Host drivers are supposed to return
4283 * the status byte as it is defined by SCSI.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004284 */
4285 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
4286 STATUS_BYTE(scsiqp->scsi_status);
4287 } else {
4288 scp->result = STATUS_BYTE(scsiqp->scsi_status);
4289 }
4290 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004291
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004292 default:
4293 /* Some other QHSTA error occurred. */
4294 ASC_DBG1(1, "adv_isr_callback: host_status 0x%x\n",
4295 scsiqp->host_status);
4296 scp->result = HOST_BYTE(DID_BAD_TARGET);
4297 break;
4298 }
4299 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004301 case QD_ABORTED_BY_HOST:
4302 ASC_DBG(1, "adv_isr_callback: QD_ABORTED_BY_HOST\n");
4303 scp->result =
4304 HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status);
4305 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004307 default:
4308 ASC_DBG1(1, "adv_isr_callback: done_status 0x%x\n",
4309 scsiqp->done_status);
4310 scp->result =
4311 HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status);
4312 break;
4313 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004315 /*
4316 * If the 'init_tidmask' bit isn't already set for the target and the
4317 * current request finished normally, then set the bit for the target
4318 * to indicate that a device is present.
4319 */
4320 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
4321 scsiqp->done_status == QD_NO_ERROR &&
4322 scsiqp->host_status == QHSTA_NO_ERROR) {
4323 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
4324 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004325
Matthew Wilcox6ed1ef02007-09-09 08:56:33 -06004326 asc_scsi_done(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004327
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004328 /*
4329 * Free all 'adv_sgblk_t' structures allocated for the request.
4330 */
4331 while ((sgblkp = reqp->sgblkp) != NULL) {
4332 /* Remove 'sgblkp' from the request list. */
4333 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004335 /* Add 'sgblkp' to the board free list. */
4336 sgblkp->next_sgblkp = boardp->adv_sgblkp;
4337 boardp->adv_sgblkp = sgblkp;
4338 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004339
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004340 /*
4341 * Free the adv_req_t structure used with the command by adding
4342 * it back to the board free list.
4343 */
4344 reqp->next_reqp = boardp->adv_reqp;
4345 boardp->adv_reqp = reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004346
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004347 ASC_DBG(1, "adv_isr_callback: done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004349 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004350}
4351
4352/*
4353 * adv_async_callback() - Adv Library asynchronous event callback function.
4354 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004355static void adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004356{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004357 switch (code) {
4358 case ADV_ASYNC_SCSI_BUS_RESET_DET:
4359 /*
4360 * The firmware detected a SCSI Bus reset.
4361 */
4362 ASC_DBG(0,
4363 "adv_async_callback: ADV_ASYNC_SCSI_BUS_RESET_DET\n");
4364 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004366 case ADV_ASYNC_RDMA_FAILURE:
4367 /*
4368 * Handle RDMA failure by resetting the SCSI Bus and
4369 * possibly the chip if it is unresponsive. Log the error
4370 * with a unique code.
4371 */
4372 ASC_DBG(0, "adv_async_callback: ADV_ASYNC_RDMA_FAILURE\n");
4373 AdvResetChipAndSB(adv_dvc_varp);
4374 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004376 case ADV_HOST_SCSI_BUS_RESET:
4377 /*
4378 * Host generated SCSI bus reset occurred.
4379 */
4380 ASC_DBG(0, "adv_async_callback: ADV_HOST_SCSI_BUS_RESET\n");
4381 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004382
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004383 default:
4384 ASC_DBG1(0, "DvcAsyncCallBack: unknown code 0x%x\n", code);
4385 break;
4386 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387}
4388
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389#ifdef CONFIG_PROC_FS
4390/*
4391 * asc_prt_board_devices()
4392 *
4393 * Print driver information for devices attached to the board.
4394 *
4395 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
4396 * cf. asc_prt_line().
4397 *
4398 * Return the number of characters copied into 'cp'. No more than
4399 * 'cplen' characters will be copied to 'cp'.
4400 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004401static int asc_prt_board_devices(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004402{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004403 asc_board_t *boardp;
4404 int leftlen;
4405 int totlen;
4406 int len;
4407 int chip_scsi_id;
4408 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004410 boardp = ASC_BOARDP(shost);
4411 leftlen = cplen;
4412 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004413
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004414 len = asc_prt_line(cp, leftlen,
4415 "\nDevice Information for AdvanSys SCSI Host %d:\n",
4416 shost->host_no);
4417 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004419 if (ASC_NARROW_BOARD(boardp)) {
4420 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
4421 } else {
4422 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
4423 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004425 len = asc_prt_line(cp, leftlen, "Target IDs Detected:");
4426 ASC_PRT_NEXT();
4427 for (i = 0; i <= ADV_MAX_TID; i++) {
4428 if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) {
4429 len = asc_prt_line(cp, leftlen, " %X,", i);
4430 ASC_PRT_NEXT();
4431 }
4432 }
4433 len = asc_prt_line(cp, leftlen, " (%X=Host Adapter)\n", chip_scsi_id);
4434 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004435
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004436 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437}
4438
4439/*
4440 * Display Wide Board BIOS Information.
4441 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004442static int asc_prt_adv_bios(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004444 asc_board_t *boardp;
4445 int leftlen;
4446 int totlen;
4447 int len;
4448 ushort major, minor, letter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004450 boardp = ASC_BOARDP(shost);
4451 leftlen = cplen;
4452 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004454 len = asc_prt_line(cp, leftlen, "\nROM BIOS Version: ");
4455 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004457 /*
4458 * If the BIOS saved a valid signature, then fill in
4459 * the BIOS code segment base address.
4460 */
4461 if (boardp->bios_signature != 0x55AA) {
4462 len = asc_prt_line(cp, leftlen, "Disabled or Pre-3.1\n");
4463 ASC_PRT_NEXT();
4464 len = asc_prt_line(cp, leftlen,
4465 "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n");
4466 ASC_PRT_NEXT();
4467 len = asc_prt_line(cp, leftlen,
4468 "can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n");
4469 ASC_PRT_NEXT();
4470 } else {
4471 major = (boardp->bios_version >> 12) & 0xF;
4472 minor = (boardp->bios_version >> 8) & 0xF;
4473 letter = (boardp->bios_version & 0xFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004474
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004475 len = asc_prt_line(cp, leftlen, "%d.%d%c\n",
4476 major, minor,
4477 letter >= 26 ? '?' : letter + 'A');
4478 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004479
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004480 /*
4481 * Current available ROM BIOS release is 3.1I for UW
4482 * and 3.2I for U2W. This code doesn't differentiate
4483 * UW and U2W boards.
4484 */
4485 if (major < 3 || (major <= 3 && minor < 1) ||
4486 (major <= 3 && minor <= 1 && letter < ('I' - 'A'))) {
4487 len = asc_prt_line(cp, leftlen,
4488 "Newer version of ROM BIOS is available at the ConnectCom FTP site:\n");
4489 ASC_PRT_NEXT();
4490 len = asc_prt_line(cp, leftlen,
4491 "ftp://ftp.connectcom.net/pub\n");
4492 ASC_PRT_NEXT();
4493 }
4494 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004496 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004497}
4498
4499/*
4500 * Add serial number to information bar if signature AAh
4501 * is found in at bit 15-9 (7 bits) of word 1.
4502 *
4503 * Serial Number consists fo 12 alpha-numeric digits.
4504 *
4505 * 1 - Product type (A,B,C,D..) Word0: 15-13 (3 bits)
4506 * 2 - MFG Location (A,B,C,D..) Word0: 12-10 (3 bits)
4507 * 3-4 - Product ID (0-99) Word0: 9-0 (10 bits)
4508 * 5 - Product revision (A-J) Word0: " "
4509 *
4510 * Signature Word1: 15-9 (7 bits)
4511 * 6 - Year (0-9) Word1: 8-6 (3 bits) & Word2: 15 (1 bit)
4512 * 7-8 - Week of the year (1-52) Word1: 5-0 (6 bits)
4513 *
4514 * 9-12 - Serial Number (A001-Z999) Word2: 14-0 (15 bits)
4515 *
4516 * Note 1: Only production cards will have a serial number.
4517 *
4518 * Note 2: Signature is most significant 7 bits (0xFE).
4519 *
4520 * Returns ASC_TRUE if serial number found, otherwise returns ASC_FALSE.
4521 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004522static int asc_get_eeprom_string(ushort *serialnum, uchar *cp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004523{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004524 ushort w, num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004525
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004526 if ((serialnum[1] & 0xFE00) != ((ushort)0xAA << 8)) {
4527 return ASC_FALSE;
4528 } else {
4529 /*
4530 * First word - 6 digits.
4531 */
4532 w = serialnum[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004534 /* Product type - 1st digit. */
4535 if ((*cp = 'A' + ((w & 0xE000) >> 13)) == 'H') {
4536 /* Product type is P=Prototype */
4537 *cp += 0x8;
4538 }
4539 cp++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004540
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004541 /* Manufacturing location - 2nd digit. */
4542 *cp++ = 'A' + ((w & 0x1C00) >> 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004544 /* Product ID - 3rd, 4th digits. */
4545 num = w & 0x3FF;
4546 *cp++ = '0' + (num / 100);
4547 num %= 100;
4548 *cp++ = '0' + (num / 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004549
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004550 /* Product revision - 5th digit. */
4551 *cp++ = 'A' + (num % 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004552
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004553 /*
4554 * Second word
4555 */
4556 w = serialnum[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004557
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004558 /*
4559 * Year - 6th digit.
4560 *
4561 * If bit 15 of third word is set, then the
4562 * last digit of the year is greater than 7.
4563 */
4564 if (serialnum[2] & 0x8000) {
4565 *cp++ = '8' + ((w & 0x1C0) >> 6);
4566 } else {
4567 *cp++ = '0' + ((w & 0x1C0) >> 6);
4568 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004570 /* Week of year - 7th, 8th digits. */
4571 num = w & 0x003F;
4572 *cp++ = '0' + num / 10;
4573 num %= 10;
4574 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004576 /*
4577 * Third word
4578 */
4579 w = serialnum[2] & 0x7FFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004580
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004581 /* Serial number - 9th digit. */
4582 *cp++ = 'A' + (w / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004583
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004584 /* 10th, 11th, 12th digits. */
4585 num = w % 1000;
4586 *cp++ = '0' + num / 100;
4587 num %= 100;
4588 *cp++ = '0' + num / 10;
4589 num %= 10;
4590 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004592 *cp = '\0'; /* Null Terminate the string. */
4593 return ASC_TRUE;
4594 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004595}
4596
4597/*
4598 * asc_prt_asc_board_eeprom()
4599 *
4600 * Print board EEPROM configuration.
4601 *
4602 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
4603 * cf. asc_prt_line().
4604 *
4605 * Return the number of characters copied into 'cp'. No more than
4606 * 'cplen' characters will be copied to 'cp'.
4607 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004608static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004610 asc_board_t *boardp;
4611 ASC_DVC_VAR *asc_dvc_varp;
4612 int leftlen;
4613 int totlen;
4614 int len;
4615 ASCEEP_CONFIG *ep;
4616 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004617#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004618 int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07004619#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004620 uchar serialstr[13];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004621
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004622 boardp = ASC_BOARDP(shost);
4623 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
4624 ep = &boardp->eep_config.asc_eep;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004625
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004626 leftlen = cplen;
4627 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004628
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004629 len = asc_prt_line(cp, leftlen,
4630 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
4631 shost->host_no);
4632 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004633
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004634 if (asc_get_eeprom_string((ushort *)&ep->adapter_info[0], serialstr)
4635 == ASC_TRUE) {
4636 len =
4637 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
4638 serialstr);
4639 ASC_PRT_NEXT();
4640 } else {
4641 if (ep->adapter_info[5] == 0xBB) {
4642 len = asc_prt_line(cp, leftlen,
4643 " Default Settings Used for EEPROM-less Adapter.\n");
4644 ASC_PRT_NEXT();
4645 } else {
4646 len = asc_prt_line(cp, leftlen,
4647 " Serial Number Signature Not Present.\n");
4648 ASC_PRT_NEXT();
4649 }
4650 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004651
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004652 len = asc_prt_line(cp, leftlen,
4653 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
4654 ASC_EEP_GET_CHIP_ID(ep), ep->max_total_qng,
4655 ep->max_tag_qng);
4656 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004658 len = asc_prt_line(cp, leftlen,
4659 " cntl 0x%x, no_scam 0x%x\n", ep->cntl, ep->no_scam);
4660 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004661
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004662 len = asc_prt_line(cp, leftlen, " Target ID: ");
4663 ASC_PRT_NEXT();
4664 for (i = 0; i <= ASC_MAX_TID; i++) {
4665 len = asc_prt_line(cp, leftlen, " %d", i);
4666 ASC_PRT_NEXT();
4667 }
4668 len = asc_prt_line(cp, leftlen, "\n");
4669 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004670
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004671 len = asc_prt_line(cp, leftlen, " Disconnects: ");
4672 ASC_PRT_NEXT();
4673 for (i = 0; i <= ASC_MAX_TID; i++) {
4674 len = asc_prt_line(cp, leftlen, " %c",
4675 (ep->
4676 disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
4677 'N');
4678 ASC_PRT_NEXT();
4679 }
4680 len = asc_prt_line(cp, leftlen, "\n");
4681 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004682
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004683 len = asc_prt_line(cp, leftlen, " Command Queuing: ");
4684 ASC_PRT_NEXT();
4685 for (i = 0; i <= ASC_MAX_TID; i++) {
4686 len = asc_prt_line(cp, leftlen, " %c",
4687 (ep->
4688 use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
4689 'N');
4690 ASC_PRT_NEXT();
4691 }
4692 len = asc_prt_line(cp, leftlen, "\n");
4693 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004694
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004695 len = asc_prt_line(cp, leftlen, " Start Motor: ");
4696 ASC_PRT_NEXT();
4697 for (i = 0; i <= ASC_MAX_TID; i++) {
4698 len = asc_prt_line(cp, leftlen, " %c",
4699 (ep->
4700 start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
4701 'N');
4702 ASC_PRT_NEXT();
4703 }
4704 len = asc_prt_line(cp, leftlen, "\n");
4705 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004707 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
4708 ASC_PRT_NEXT();
4709 for (i = 0; i <= ASC_MAX_TID; i++) {
4710 len = asc_prt_line(cp, leftlen, " %c",
4711 (ep->
4712 init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
4713 'N');
4714 ASC_PRT_NEXT();
4715 }
4716 len = asc_prt_line(cp, leftlen, "\n");
4717 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004718
4719#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004720 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
4721 len = asc_prt_line(cp, leftlen,
4722 " Host ISA DMA speed: %d MB/S\n",
4723 isa_dma_speed[ASC_EEP_GET_DMA_SPD(ep)]);
4724 ASC_PRT_NEXT();
4725 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726#endif /* CONFIG_ISA */
4727
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004728 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004729}
4730
4731/*
4732 * asc_prt_adv_board_eeprom()
4733 *
4734 * Print board EEPROM configuration.
4735 *
4736 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
4737 * cf. asc_prt_line().
4738 *
4739 * Return the number of characters copied into 'cp'. No more than
4740 * 'cplen' characters will be copied to 'cp'.
4741 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004742static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004743{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004744 asc_board_t *boardp;
4745 ADV_DVC_VAR *adv_dvc_varp;
4746 int leftlen;
4747 int totlen;
4748 int len;
4749 int i;
4750 char *termstr;
4751 uchar serialstr[13];
4752 ADVEEP_3550_CONFIG *ep_3550 = NULL;
4753 ADVEEP_38C0800_CONFIG *ep_38C0800 = NULL;
4754 ADVEEP_38C1600_CONFIG *ep_38C1600 = NULL;
4755 ushort word;
4756 ushort *wordp;
4757 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004759 boardp = ASC_BOARDP(shost);
4760 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
4761 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
4762 ep_3550 = &boardp->eep_config.adv_3550_eep;
4763 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
4764 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
4765 } else {
4766 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
4767 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004769 leftlen = cplen;
4770 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004772 len = asc_prt_line(cp, leftlen,
4773 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
4774 shost->host_no);
4775 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004777 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
4778 wordp = &ep_3550->serial_number_word1;
4779 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
4780 wordp = &ep_38C0800->serial_number_word1;
4781 } else {
4782 wordp = &ep_38C1600->serial_number_word1;
4783 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004784
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004785 if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) {
4786 len =
4787 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
4788 serialstr);
4789 ASC_PRT_NEXT();
4790 } else {
4791 len = asc_prt_line(cp, leftlen,
4792 " Serial Number Signature Not Present.\n");
4793 ASC_PRT_NEXT();
4794 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004795
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004796 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
4797 len = asc_prt_line(cp, leftlen,
4798 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
4799 ep_3550->adapter_scsi_id,
4800 ep_3550->max_host_qng, ep_3550->max_dvc_qng);
4801 ASC_PRT_NEXT();
4802 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
4803 len = asc_prt_line(cp, leftlen,
4804 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
4805 ep_38C0800->adapter_scsi_id,
4806 ep_38C0800->max_host_qng,
4807 ep_38C0800->max_dvc_qng);
4808 ASC_PRT_NEXT();
4809 } else {
4810 len = asc_prt_line(cp, leftlen,
4811 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
4812 ep_38C1600->adapter_scsi_id,
4813 ep_38C1600->max_host_qng,
4814 ep_38C1600->max_dvc_qng);
4815 ASC_PRT_NEXT();
4816 }
4817 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
4818 word = ep_3550->termination;
4819 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
4820 word = ep_38C0800->termination_lvd;
4821 } else {
4822 word = ep_38C1600->termination_lvd;
4823 }
4824 switch (word) {
4825 case 1:
4826 termstr = "Low Off/High Off";
4827 break;
4828 case 2:
4829 termstr = "Low Off/High On";
4830 break;
4831 case 3:
4832 termstr = "Low On/High On";
4833 break;
4834 default:
4835 case 0:
4836 termstr = "Automatic";
4837 break;
4838 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004840 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
4841 len = asc_prt_line(cp, leftlen,
4842 " termination: %u (%s), bios_ctrl: 0x%x\n",
4843 ep_3550->termination, termstr,
4844 ep_3550->bios_ctrl);
4845 ASC_PRT_NEXT();
4846 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
4847 len = asc_prt_line(cp, leftlen,
4848 " termination: %u (%s), bios_ctrl: 0x%x\n",
4849 ep_38C0800->termination_lvd, termstr,
4850 ep_38C0800->bios_ctrl);
4851 ASC_PRT_NEXT();
4852 } else {
4853 len = asc_prt_line(cp, leftlen,
4854 " termination: %u (%s), bios_ctrl: 0x%x\n",
4855 ep_38C1600->termination_lvd, termstr,
4856 ep_38C1600->bios_ctrl);
4857 ASC_PRT_NEXT();
4858 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004859
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004860 len = asc_prt_line(cp, leftlen, " Target ID: ");
4861 ASC_PRT_NEXT();
4862 for (i = 0; i <= ADV_MAX_TID; i++) {
4863 len = asc_prt_line(cp, leftlen, " %X", i);
4864 ASC_PRT_NEXT();
4865 }
4866 len = asc_prt_line(cp, leftlen, "\n");
4867 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004868
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004869 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
4870 word = ep_3550->disc_enable;
4871 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
4872 word = ep_38C0800->disc_enable;
4873 } else {
4874 word = ep_38C1600->disc_enable;
4875 }
4876 len = asc_prt_line(cp, leftlen, " Disconnects: ");
4877 ASC_PRT_NEXT();
4878 for (i = 0; i <= ADV_MAX_TID; i++) {
4879 len = asc_prt_line(cp, leftlen, " %c",
4880 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
4881 ASC_PRT_NEXT();
4882 }
4883 len = asc_prt_line(cp, leftlen, "\n");
4884 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004885
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004886 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
4887 word = ep_3550->tagqng_able;
4888 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
4889 word = ep_38C0800->tagqng_able;
4890 } else {
4891 word = ep_38C1600->tagqng_able;
4892 }
4893 len = asc_prt_line(cp, leftlen, " Command Queuing: ");
4894 ASC_PRT_NEXT();
4895 for (i = 0; i <= ADV_MAX_TID; i++) {
4896 len = asc_prt_line(cp, leftlen, " %c",
4897 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
4898 ASC_PRT_NEXT();
4899 }
4900 len = asc_prt_line(cp, leftlen, "\n");
4901 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004902
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004903 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
4904 word = ep_3550->start_motor;
4905 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
4906 word = ep_38C0800->start_motor;
4907 } else {
4908 word = ep_38C1600->start_motor;
4909 }
4910 len = asc_prt_line(cp, leftlen, " Start Motor: ");
4911 ASC_PRT_NEXT();
4912 for (i = 0; i <= ADV_MAX_TID; i++) {
4913 len = asc_prt_line(cp, leftlen, " %c",
4914 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
4915 ASC_PRT_NEXT();
4916 }
4917 len = asc_prt_line(cp, leftlen, "\n");
4918 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004919
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004920 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
4921 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
4922 ASC_PRT_NEXT();
4923 for (i = 0; i <= ADV_MAX_TID; i++) {
4924 len = asc_prt_line(cp, leftlen, " %c",
4925 (ep_3550->
4926 sdtr_able & ADV_TID_TO_TIDMASK(i)) ?
4927 'Y' : 'N');
4928 ASC_PRT_NEXT();
4929 }
4930 len = asc_prt_line(cp, leftlen, "\n");
4931 ASC_PRT_NEXT();
4932 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004933
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004934 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
4935 len = asc_prt_line(cp, leftlen, " Ultra Transfer: ");
4936 ASC_PRT_NEXT();
4937 for (i = 0; i <= ADV_MAX_TID; i++) {
4938 len = asc_prt_line(cp, leftlen, " %c",
4939 (ep_3550->
4940 ultra_able & ADV_TID_TO_TIDMASK(i))
4941 ? 'Y' : 'N');
4942 ASC_PRT_NEXT();
4943 }
4944 len = asc_prt_line(cp, leftlen, "\n");
4945 ASC_PRT_NEXT();
4946 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004947
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004948 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
4949 word = ep_3550->wdtr_able;
4950 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
4951 word = ep_38C0800->wdtr_able;
4952 } else {
4953 word = ep_38C1600->wdtr_able;
4954 }
4955 len = asc_prt_line(cp, leftlen, " Wide Transfer: ");
4956 ASC_PRT_NEXT();
4957 for (i = 0; i <= ADV_MAX_TID; i++) {
4958 len = asc_prt_line(cp, leftlen, " %c",
4959 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
4960 ASC_PRT_NEXT();
4961 }
4962 len = asc_prt_line(cp, leftlen, "\n");
4963 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004964
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004965 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800 ||
4966 adv_dvc_varp->chip_type == ADV_CHIP_ASC38C1600) {
4967 len = asc_prt_line(cp, leftlen,
4968 " Synchronous Transfer Speed (Mhz):\n ");
4969 ASC_PRT_NEXT();
4970 for (i = 0; i <= ADV_MAX_TID; i++) {
4971 char *speed_str;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004972
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004973 if (i == 0) {
4974 sdtr_speed = adv_dvc_varp->sdtr_speed1;
4975 } else if (i == 4) {
4976 sdtr_speed = adv_dvc_varp->sdtr_speed2;
4977 } else if (i == 8) {
4978 sdtr_speed = adv_dvc_varp->sdtr_speed3;
4979 } else if (i == 12) {
4980 sdtr_speed = adv_dvc_varp->sdtr_speed4;
4981 }
4982 switch (sdtr_speed & ADV_MAX_TID) {
4983 case 0:
4984 speed_str = "Off";
4985 break;
4986 case 1:
4987 speed_str = " 5";
4988 break;
4989 case 2:
4990 speed_str = " 10";
4991 break;
4992 case 3:
4993 speed_str = " 20";
4994 break;
4995 case 4:
4996 speed_str = " 40";
4997 break;
4998 case 5:
4999 speed_str = " 80";
5000 break;
5001 default:
5002 speed_str = "Unk";
5003 break;
5004 }
5005 len = asc_prt_line(cp, leftlen, "%X:%s ", i, speed_str);
5006 ASC_PRT_NEXT();
5007 if (i == 7) {
5008 len = asc_prt_line(cp, leftlen, "\n ");
5009 ASC_PRT_NEXT();
5010 }
5011 sdtr_speed >>= 4;
5012 }
5013 len = asc_prt_line(cp, leftlen, "\n");
5014 ASC_PRT_NEXT();
5015 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005016
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005017 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005018}
5019
5020/*
5021 * asc_prt_driver_conf()
5022 *
5023 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
5024 * cf. asc_prt_line().
5025 *
5026 * Return the number of characters copied into 'cp'. No more than
5027 * 'cplen' characters will be copied to 'cp'.
5028 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005029static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005030{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005031 asc_board_t *boardp;
5032 int leftlen;
5033 int totlen;
5034 int len;
5035 int chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005036
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005037 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005038
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005039 leftlen = cplen;
5040 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005041
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005042 len = asc_prt_line(cp, leftlen,
5043 "\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n",
5044 shost->host_no);
5045 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005046
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005047 len = asc_prt_line(cp, leftlen,
5048 " host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n",
5049 shost->host_busy, shost->last_reset, shost->max_id,
5050 shost->max_lun, shost->max_channel);
5051 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005052
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005053 len = asc_prt_line(cp, leftlen,
5054 " unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
5055 shost->unique_id, shost->can_queue, shost->this_id,
5056 shost->sg_tablesize, shost->cmd_per_lun);
5057 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005058
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005059 len = asc_prt_line(cp, leftlen,
5060 " unchecked_isa_dma %d, use_clustering %d\n",
5061 shost->unchecked_isa_dma, shost->use_clustering);
5062 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005063
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005064 len = asc_prt_line(cp, leftlen,
5065 " flags 0x%x, last_reset 0x%x, jiffies 0x%x, asc_n_io_port 0x%x\n",
5066 boardp->flags, boardp->last_reset, jiffies,
5067 boardp->asc_n_io_port);
5068 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005069
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04005070 len = asc_prt_line(cp, leftlen, " io_port 0x%x\n", shost->io_port);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005071 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005072
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005073 if (ASC_NARROW_BOARD(boardp)) {
5074 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
5075 } else {
5076 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
5077 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005078
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005079 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005080}
5081
5082/*
5083 * asc_prt_asc_board_info()
5084 *
5085 * Print dynamic board configuration information.
5086 *
5087 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
5088 * cf. asc_prt_line().
5089 *
5090 * Return the number of characters copied into 'cp'. No more than
5091 * 'cplen' characters will be copied to 'cp'.
5092 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005093static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005094{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005095 asc_board_t *boardp;
5096 int chip_scsi_id;
5097 int leftlen;
5098 int totlen;
5099 int len;
5100 ASC_DVC_VAR *v;
5101 ASC_DVC_CFG *c;
5102 int i;
5103 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005104
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005105 boardp = ASC_BOARDP(shost);
5106 v = &boardp->dvc_var.asc_dvc_var;
5107 c = &boardp->dvc_cfg.asc_dvc_cfg;
5108 chip_scsi_id = c->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005109
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005110 leftlen = cplen;
5111 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005112
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005113 len = asc_prt_line(cp, leftlen,
5114 "\nAsc Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
5115 shost->host_no);
5116 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005117
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005118 len = asc_prt_line(cp, leftlen,
5119 " chip_version %u, lib_version 0x%x, lib_serial_no %u, mcode_date 0x%x\n",
5120 c->chip_version, c->lib_version, c->lib_serial_no,
5121 c->mcode_date);
5122 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005123
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005124 len = asc_prt_line(cp, leftlen,
5125 " mcode_version 0x%x, err_code %u\n",
5126 c->mcode_version, v->err_code);
5127 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005128
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005129 /* Current number of commands waiting for the host. */
5130 len = asc_prt_line(cp, leftlen,
5131 " Total Command Pending: %d\n", v->cur_total_qng);
5132 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005133
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005134 len = asc_prt_line(cp, leftlen, " Command Queuing:");
5135 ASC_PRT_NEXT();
5136 for (i = 0; i <= ASC_MAX_TID; i++) {
5137 if ((chip_scsi_id == i) ||
5138 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
5139 continue;
5140 }
5141 len = asc_prt_line(cp, leftlen, " %X:%c",
5142 i,
5143 (v->
5144 use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ?
5145 'Y' : 'N');
5146 ASC_PRT_NEXT();
5147 }
5148 len = asc_prt_line(cp, leftlen, "\n");
5149 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005151 /* Current number of commands waiting for a device. */
5152 len = asc_prt_line(cp, leftlen, " Command Queue Pending:");
5153 ASC_PRT_NEXT();
5154 for (i = 0; i <= ASC_MAX_TID; i++) {
5155 if ((chip_scsi_id == i) ||
5156 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
5157 continue;
5158 }
5159 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->cur_dvc_qng[i]);
5160 ASC_PRT_NEXT();
5161 }
5162 len = asc_prt_line(cp, leftlen, "\n");
5163 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005164
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005165 /* Current limit on number of commands that can be sent to a device. */
5166 len = asc_prt_line(cp, leftlen, " Command Queue Limit:");
5167 ASC_PRT_NEXT();
5168 for (i = 0; i <= ASC_MAX_TID; i++) {
5169 if ((chip_scsi_id == i) ||
5170 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
5171 continue;
5172 }
5173 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->max_dvc_qng[i]);
5174 ASC_PRT_NEXT();
5175 }
5176 len = asc_prt_line(cp, leftlen, "\n");
5177 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005178
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005179 /* Indicate whether the device has returned queue full status. */
5180 len = asc_prt_line(cp, leftlen, " Command Queue Full:");
5181 ASC_PRT_NEXT();
5182 for (i = 0; i <= ASC_MAX_TID; i++) {
5183 if ((chip_scsi_id == i) ||
5184 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
5185 continue;
5186 }
5187 if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) {
5188 len = asc_prt_line(cp, leftlen, " %X:Y-%d",
5189 i, boardp->queue_full_cnt[i]);
5190 } else {
5191 len = asc_prt_line(cp, leftlen, " %X:N", i);
5192 }
5193 ASC_PRT_NEXT();
5194 }
5195 len = asc_prt_line(cp, leftlen, "\n");
5196 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005198 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
5199 ASC_PRT_NEXT();
5200 for (i = 0; i <= ASC_MAX_TID; i++) {
5201 if ((chip_scsi_id == i) ||
5202 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
5203 continue;
5204 }
5205 len = asc_prt_line(cp, leftlen, " %X:%c",
5206 i,
5207 (v->
5208 sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
5209 'N');
5210 ASC_PRT_NEXT();
5211 }
5212 len = asc_prt_line(cp, leftlen, "\n");
5213 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005214
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005215 for (i = 0; i <= ASC_MAX_TID; i++) {
5216 uchar syn_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005217
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005218 if ((chip_scsi_id == i) ||
5219 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
5220 ((v->init_sdtr & ADV_TID_TO_TIDMASK(i)) == 0)) {
5221 continue;
5222 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005223
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005224 len = asc_prt_line(cp, leftlen, " %X:", i);
5225 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005227 if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0) {
5228 len = asc_prt_line(cp, leftlen, " Asynchronous");
5229 ASC_PRT_NEXT();
5230 } else {
5231 syn_period_ix =
5232 (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index -
5233 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005234
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005235 len = asc_prt_line(cp, leftlen,
5236 " Transfer Period Factor: %d (%d.%d Mhz),",
5237 v->sdtr_period_tbl[syn_period_ix],
5238 250 /
5239 v->sdtr_period_tbl[syn_period_ix],
5240 ASC_TENTHS(250,
5241 v->
5242 sdtr_period_tbl
5243 [syn_period_ix]));
5244 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005245
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005246 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
5247 boardp->
5248 sdtr_data[i] & ASC_SYN_MAX_OFFSET);
5249 ASC_PRT_NEXT();
5250 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005251
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005252 if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
5253 len = asc_prt_line(cp, leftlen, "*\n");
5254 renegotiate = 1;
5255 } else {
5256 len = asc_prt_line(cp, leftlen, "\n");
5257 }
5258 ASC_PRT_NEXT();
5259 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005260
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005261 if (renegotiate) {
5262 len = asc_prt_line(cp, leftlen,
5263 " * = Re-negotiation pending before next command.\n");
5264 ASC_PRT_NEXT();
5265 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005266
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005267 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005268}
5269
5270/*
5271 * asc_prt_adv_board_info()
5272 *
5273 * Print dynamic board configuration information.
5274 *
5275 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
5276 * cf. asc_prt_line().
5277 *
5278 * Return the number of characters copied into 'cp'. No more than
5279 * 'cplen' characters will be copied to 'cp'.
5280 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005281static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005282{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005283 asc_board_t *boardp;
5284 int leftlen;
5285 int totlen;
5286 int len;
5287 int i;
5288 ADV_DVC_VAR *v;
5289 ADV_DVC_CFG *c;
5290 AdvPortAddr iop_base;
5291 ushort chip_scsi_id;
5292 ushort lramword;
5293 uchar lrambyte;
5294 ushort tagqng_able;
5295 ushort sdtr_able, wdtr_able;
5296 ushort wdtr_done, sdtr_done;
5297 ushort period = 0;
5298 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005299
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005300 boardp = ASC_BOARDP(shost);
5301 v = &boardp->dvc_var.adv_dvc_var;
5302 c = &boardp->dvc_cfg.adv_dvc_cfg;
5303 iop_base = v->iop_base;
5304 chip_scsi_id = v->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005305
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005306 leftlen = cplen;
5307 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005308
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005309 len = asc_prt_line(cp, leftlen,
5310 "\nAdv Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
5311 shost->host_no);
5312 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005313
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005314 len = asc_prt_line(cp, leftlen,
5315 " iop_base 0x%lx, cable_detect: %X, err_code %u\n",
5316 v->iop_base,
5317 AdvReadWordRegister(iop_base,
5318 IOPW_SCSI_CFG1) & CABLE_DETECT,
5319 v->err_code);
5320 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005321
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005322 len = asc_prt_line(cp, leftlen,
5323 " chip_version %u, lib_version 0x%x, mcode_date 0x%x, mcode_version 0x%x\n",
5324 c->chip_version, c->lib_version, c->mcode_date,
5325 c->mcode_version);
5326 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005327
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005328 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
5329 len = asc_prt_line(cp, leftlen, " Queuing Enabled:");
5330 ASC_PRT_NEXT();
5331 for (i = 0; i <= ADV_MAX_TID; i++) {
5332 if ((chip_scsi_id == i) ||
5333 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
5334 continue;
5335 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005336
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005337 len = asc_prt_line(cp, leftlen, " %X:%c",
5338 i,
5339 (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
5340 'N');
5341 ASC_PRT_NEXT();
5342 }
5343 len = asc_prt_line(cp, leftlen, "\n");
5344 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005345
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005346 len = asc_prt_line(cp, leftlen, " Queue Limit:");
5347 ASC_PRT_NEXT();
5348 for (i = 0; i <= ADV_MAX_TID; i++) {
5349 if ((chip_scsi_id == i) ||
5350 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
5351 continue;
5352 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005353
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005354 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + i,
5355 lrambyte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005356
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005357 len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
5358 ASC_PRT_NEXT();
5359 }
5360 len = asc_prt_line(cp, leftlen, "\n");
5361 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005362
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005363 len = asc_prt_line(cp, leftlen, " Command Pending:");
5364 ASC_PRT_NEXT();
5365 for (i = 0; i <= ADV_MAX_TID; i++) {
5366 if ((chip_scsi_id == i) ||
5367 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
5368 continue;
5369 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005370
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005371 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_QUEUED_CMD + i,
5372 lrambyte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005373
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005374 len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
5375 ASC_PRT_NEXT();
5376 }
5377 len = asc_prt_line(cp, leftlen, "\n");
5378 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005379
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005380 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
5381 len = asc_prt_line(cp, leftlen, " Wide Enabled:");
5382 ASC_PRT_NEXT();
5383 for (i = 0; i <= ADV_MAX_TID; i++) {
5384 if ((chip_scsi_id == i) ||
5385 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
5386 continue;
5387 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005388
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005389 len = asc_prt_line(cp, leftlen, " %X:%c",
5390 i,
5391 (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
5392 'N');
5393 ASC_PRT_NEXT();
5394 }
5395 len = asc_prt_line(cp, leftlen, "\n");
5396 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005397
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005398 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done);
5399 len = asc_prt_line(cp, leftlen, " Transfer Bit Width:");
5400 ASC_PRT_NEXT();
5401 for (i = 0; i <= ADV_MAX_TID; i++) {
5402 if ((chip_scsi_id == i) ||
5403 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
5404 continue;
5405 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005406
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005407 AdvReadWordLram(iop_base,
5408 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
5409 lramword);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005410
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005411 len = asc_prt_line(cp, leftlen, " %X:%d",
5412 i, (lramword & 0x8000) ? 16 : 8);
5413 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005414
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005415 if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) &&
5416 (wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
5417 len = asc_prt_line(cp, leftlen, "*");
5418 ASC_PRT_NEXT();
5419 renegotiate = 1;
5420 }
5421 }
5422 len = asc_prt_line(cp, leftlen, "\n");
5423 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005425 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
5426 len = asc_prt_line(cp, leftlen, " Synchronous Enabled:");
5427 ASC_PRT_NEXT();
5428 for (i = 0; i <= ADV_MAX_TID; i++) {
5429 if ((chip_scsi_id == i) ||
5430 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
5431 continue;
5432 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005433
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005434 len = asc_prt_line(cp, leftlen, " %X:%c",
5435 i,
5436 (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
5437 'N');
5438 ASC_PRT_NEXT();
5439 }
5440 len = asc_prt_line(cp, leftlen, "\n");
5441 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005442
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005443 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done);
5444 for (i = 0; i <= ADV_MAX_TID; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005445
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005446 AdvReadWordLram(iop_base,
5447 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
5448 lramword);
5449 lramword &= ~0x8000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005450
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005451 if ((chip_scsi_id == i) ||
5452 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
5453 ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0)) {
5454 continue;
5455 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005456
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005457 len = asc_prt_line(cp, leftlen, " %X:", i);
5458 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005459
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005460 if ((lramword & 0x1F) == 0) { /* Check for REQ/ACK Offset 0. */
5461 len = asc_prt_line(cp, leftlen, " Asynchronous");
5462 ASC_PRT_NEXT();
5463 } else {
5464 len =
5465 asc_prt_line(cp, leftlen,
5466 " Transfer Period Factor: ");
5467 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005468
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005469 if ((lramword & 0x1F00) == 0x1100) { /* 80 Mhz */
5470 len =
5471 asc_prt_line(cp, leftlen, "9 (80.0 Mhz),");
5472 ASC_PRT_NEXT();
5473 } else if ((lramword & 0x1F00) == 0x1000) { /* 40 Mhz */
5474 len =
5475 asc_prt_line(cp, leftlen, "10 (40.0 Mhz),");
5476 ASC_PRT_NEXT();
5477 } else { /* 20 Mhz or below. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005478
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005479 period = (((lramword >> 8) * 25) + 50) / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005480
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005481 if (period == 0) { /* Should never happen. */
5482 len =
5483 asc_prt_line(cp, leftlen,
5484 "%d (? Mhz), ");
5485 ASC_PRT_NEXT();
5486 } else {
5487 len = asc_prt_line(cp, leftlen,
5488 "%d (%d.%d Mhz),",
5489 period, 250 / period,
5490 ASC_TENTHS(250,
5491 period));
5492 ASC_PRT_NEXT();
5493 }
5494 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005495
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005496 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
5497 lramword & 0x1F);
5498 ASC_PRT_NEXT();
5499 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005500
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005501 if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
5502 len = asc_prt_line(cp, leftlen, "*\n");
5503 renegotiate = 1;
5504 } else {
5505 len = asc_prt_line(cp, leftlen, "\n");
5506 }
5507 ASC_PRT_NEXT();
5508 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005510 if (renegotiate) {
5511 len = asc_prt_line(cp, leftlen,
5512 " * = Re-negotiation pending before next command.\n");
5513 ASC_PRT_NEXT();
5514 }
5515
5516 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005517}
5518
5519/*
5520 * asc_proc_copy()
5521 *
5522 * Copy proc information to a read buffer taking into account the current
5523 * read offset in the file and the remaining space in the read buffer.
5524 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005525static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005526asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005527 char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005528{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005529 int cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005530
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005531 ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n",
5532 (unsigned)offset, (unsigned)advoffset, cplen);
5533 if (offset <= advoffset) {
5534 /* Read offset below current offset, copy everything. */
5535 cnt = min(cplen, leftlen);
5536 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
5537 (ulong)curbuf, (ulong)cp, cnt);
5538 memcpy(curbuf, cp, cnt);
5539 } else if (offset < advoffset + cplen) {
5540 /* Read offset within current range, partial copy. */
5541 cnt = (advoffset + cplen) - offset;
5542 cp = (cp + cplen) - cnt;
5543 cnt = min(cnt, leftlen);
5544 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
5545 (ulong)curbuf, (ulong)cp, cnt);
5546 memcpy(curbuf, cp, cnt);
5547 }
5548 return cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549}
5550
5551/*
5552 * asc_prt_line()
5553 *
5554 * If 'cp' is NULL print to the console, otherwise print to a buffer.
5555 *
5556 * Return 0 if printing to the console, otherwise return the number of
5557 * bytes written to the buffer.
5558 *
5559 * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack
5560 * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes.
5561 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005562static int asc_prt_line(char *buf, int buflen, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005563{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005564 va_list args;
5565 int ret;
5566 char s[ASC_PRTLINE_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07005567
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005568 va_start(args, fmt);
5569 ret = vsprintf(s, fmt, args);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06005570 BUG_ON(ret >= ASC_PRTLINE_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005571 if (buf == NULL) {
5572 (void)printk(s);
5573 ret = 0;
5574 } else {
5575 ret = min(buflen, ret);
5576 memcpy(buf, s, ret);
5577 }
5578 va_end(args);
5579 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005580}
5581#endif /* CONFIG_PROC_FS */
5582
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07005584 * void
5585 * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
5586 *
5587 * Calling/Exit State:
5588 * none
5589 *
5590 * Description:
5591 * Output an ASC_SCSI_Q structure to the chip
5592 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005593static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07005594DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
5595{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005596 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005597
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005598 ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words);
5599 AscSetChipLramAddr(iop_base, s_addr);
5600 for (i = 0; i < 2 * words; i += 2) {
5601 if (i == 4 || i == 20) {
5602 continue;
5603 }
5604 outpw(iop_base + IOP_RAM_DATA,
5605 ((ushort)outbuf[i + 1] << 8) | outbuf[i]);
5606 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005607}
5608
5609/*
5610 * void
5611 * DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
5612 *
5613 * Calling/Exit State:
5614 * none
5615 *
5616 * Description:
5617 * Input an ASC_QDONE_INFO structure from the chip
5618 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005619static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07005620DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
5621{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005622 int i;
5623 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005624
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005625 AscSetChipLramAddr(iop_base, s_addr);
5626 for (i = 0; i < 2 * words; i += 2) {
5627 if (i == 10) {
5628 continue;
5629 }
5630 word = inpw(iop_base + IOP_RAM_DATA);
5631 inbuf[i] = word & 0xff;
5632 inbuf[i + 1] = (word >> 8) & 0xff;
5633 }
5634 ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005635}
5636
5637/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07005638 * Return the BIOS address of the adapter at the specified
5639 * I/O port and with the specified bus type.
5640 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06005641static unsigned short __devinit
5642AscGetChipBiosAddress(PortAddr iop_base, unsigned short bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005643{
Matthew Wilcoxecec1942007-07-30 08:08:22 -06005644 unsigned short cfg_lsw;
5645 unsigned short bios_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005646
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005647 /*
5648 * The PCI BIOS is re-located by the motherboard BIOS. Because
5649 * of this the driver can not determine where a PCI BIOS is
5650 * loaded and executes.
5651 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06005652 if (bus_type & ASC_IS_PCI)
5653 return 0;
5654
Linus Torvalds1da177e2005-04-16 15:20:36 -07005655#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005656 if ((bus_type & ASC_IS_EISA) != 0) {
5657 cfg_lsw = AscGetEisaChipCfg(iop_base);
5658 cfg_lsw &= 0x000F;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06005659 bios_addr = ASC_BIOS_MIN_ADDR + cfg_lsw * ASC_BIOS_BANK_SIZE;
5660 return bios_addr;
5661 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005662#endif /* CONFIG_ISA */
5663
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005664 cfg_lsw = AscGetChipCfgLsw(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005665
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005666 /*
5667 * ISA PnP uses the top bit as the 32K BIOS flag
5668 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06005669 if (bus_type == ASC_IS_ISAPNP)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005670 cfg_lsw &= 0x7FFF;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06005671 bios_addr = ASC_BIOS_MIN_ADDR + (cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE;
5672 return bios_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005673}
5674
Linus Torvalds1da177e2005-04-16 15:20:36 -07005675/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07005676 * DvcGetPhyAddr()
5677 *
5678 * Return the physical address of 'vaddr' and set '*lenp' to the
5679 * number of physically contiguous bytes that follow 'vaddr'.
5680 * 'flag' indicates the type of structure whose physical address
5681 * is being translated.
5682 *
5683 * Note: Because Linux currently doesn't page the kernel and all
5684 * kernel buffers are physically contiguous, leave '*lenp' unchanged.
5685 */
5686ADV_PADDR
5687DvcGetPhyAddr(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005688 uchar *vaddr, ADV_SDCNT *lenp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005689{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005690 ADV_PADDR paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005691
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005692 paddr = virt_to_bus(vaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005693
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005694 ASC_DBG4(4,
5695 "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n",
5696 (ulong)vaddr, (ulong)lenp, (ulong)*((ulong *)lenp),
5697 (ulong)paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005698
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005699 return paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005700}
5701
Linus Torvalds1da177e2005-04-16 15:20:36 -07005702#ifdef ADVANSYS_STATS
5703#ifdef CONFIG_PROC_FS
5704/*
5705 * asc_prt_board_stats()
5706 *
5707 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
5708 * cf. asc_prt_line().
5709 *
5710 * Return the number of characters copied into 'cp'. No more than
5711 * 'cplen' characters will be copied to 'cp'.
5712 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005713static int asc_prt_board_stats(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005714{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005715 int leftlen;
5716 int totlen;
5717 int len;
5718 struct asc_stats *s;
5719 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005720
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005721 leftlen = cplen;
5722 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005723
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005724 boardp = ASC_BOARDP(shost);
5725 s = &boardp->asc_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005726
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005727 len = asc_prt_line(cp, leftlen,
5728 "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n",
5729 shost->host_no);
5730 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005731
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005732 len = asc_prt_line(cp, leftlen,
5733 " queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n",
5734 s->queuecommand, s->reset, s->biosparam,
5735 s->interrupt);
5736 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005737
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005738 len = asc_prt_line(cp, leftlen,
5739 " callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n",
5740 s->callback, s->done, s->build_error,
5741 s->adv_build_noreq, s->adv_build_nosg);
5742 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005743
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005744 len = asc_prt_line(cp, leftlen,
5745 " exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n",
5746 s->exe_noerror, s->exe_busy, s->exe_error,
5747 s->exe_unknown);
5748 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005749
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005750 /*
5751 * Display data transfer statistics.
5752 */
5753 if (s->cont_cnt > 0) {
5754 len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt);
5755 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005756
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005757 len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ",
5758 s->cont_xfer / 2,
5759 ASC_TENTHS(s->cont_xfer, 2));
5760 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005761
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005762 /* Contiguous transfer average size */
5763 len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kb\n",
5764 (s->cont_xfer / 2) / s->cont_cnt,
5765 ASC_TENTHS((s->cont_xfer / 2), s->cont_cnt));
5766 ASC_PRT_NEXT();
5767 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005768
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005769 if (s->sg_cnt > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005770
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005771 len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ",
5772 s->sg_cnt, s->sg_elem);
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, "sg_xfer %lu.%01lu kb\n",
5776 s->sg_xfer / 2, ASC_TENTHS(s->sg_xfer, 2));
5777 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005778
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005779 /* Scatter gather transfer statistics */
5780 len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ",
5781 s->sg_elem / s->sg_cnt,
5782 ASC_TENTHS(s->sg_elem, s->sg_cnt));
5783 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005784
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005785 len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ",
5786 (s->sg_xfer / 2) / s->sg_elem,
5787 ASC_TENTHS((s->sg_xfer / 2), s->sg_elem));
5788 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005789
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005790 len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n",
5791 (s->sg_xfer / 2) / s->sg_cnt,
5792 ASC_TENTHS((s->sg_xfer / 2), s->sg_cnt));
5793 ASC_PRT_NEXT();
5794 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005795
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005796 /*
5797 * Display request queuing statistics.
5798 */
5799 len = asc_prt_line(cp, leftlen,
5800 " Active and Waiting Request Queues (Time Unit: %d HZ):\n",
5801 HZ);
5802 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005803
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005804 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005805}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005806#endif /* CONFIG_PROC_FS */
5807#endif /* ADVANSYS_STATS */
5808
5809#ifdef ADVANSYS_DEBUG
5810/*
5811 * asc_prt_scsi_host()
5812 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005813static void asc_prt_scsi_host(struct Scsi_Host *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005814{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005815 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005816
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005817 boardp = ASC_BOARDP(s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005818
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005819 printk("Scsi_Host at addr 0x%lx\n", (ulong)s);
5820 printk(" host_busy %u, host_no %d, last_reset %d,\n",
5821 s->host_busy, s->host_no, (unsigned)s->last_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005822
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04005823 printk(" base 0x%lx, io_port 0x%lx, irq 0x%x,\n",
5824 (ulong)s->base, (ulong)s->io_port, s->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005825
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005826 printk(" dma_channel %d, this_id %d, can_queue %d,\n",
5827 s->dma_channel, s->this_id, s->can_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005828
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005829 printk(" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
5830 s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005831
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005832 if (ASC_NARROW_BOARD(boardp)) {
5833 asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var);
5834 asc_prt_asc_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.asc_dvc_cfg);
5835 } else {
5836 asc_prt_adv_dvc_var(&ASC_BOARDP(s)->dvc_var.adv_dvc_var);
5837 asc_prt_adv_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.adv_dvc_cfg);
5838 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005839}
5840
5841/*
5842 * asc_prt_scsi_cmnd()
5843 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005844static void asc_prt_scsi_cmnd(struct scsi_cmnd *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005845{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005846 printk("struct scsi_cmnd at addr 0x%lx\n", (ulong)s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005847
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005848 printk(" host 0x%lx, device 0x%lx, target %u, lun %u, channel %u,\n",
5849 (ulong)s->device->host, (ulong)s->device, s->device->id,
5850 s->device->lun, s->device->channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005851
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005852 asc_prt_hex(" CDB", s->cmnd, s->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005853
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005854 printk("sc_data_direction %u, resid %d\n",
5855 s->sc_data_direction, s->resid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005856
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005857 printk(" use_sg %u, sglist_len %u\n", s->use_sg, s->sglist_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005858
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005859 printk(" serial_number 0x%x, retries %d, allowed %d\n",
5860 (unsigned)s->serial_number, s->retries, s->allowed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005861
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005862 printk(" timeout_per_command %d\n", s->timeout_per_command);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005863
Matthew Wilcoxecec1942007-07-30 08:08:22 -06005864 printk(" scsi_done 0x%p, done 0x%p, host_scribble 0x%p, result 0x%x\n",
5865 s->scsi_done, s->done, s->host_scribble, s->result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005866
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005867 printk(" tag %u, pid %u\n", (unsigned)s->tag, (unsigned)s->pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005868}
5869
5870/*
5871 * asc_prt_asc_dvc_var()
5872 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005873static void asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005874{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005875 printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005876
Matthew Wilcoxecec1942007-07-30 08:08:22 -06005877 printk(" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl "
5878 "%d,\n", h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005879
Matthew Wilcox895d6b42007-07-26 11:57:06 -04005880 printk(" bus_type %d, init_sdtr 0x%x,\n", h->bus_type,
5881 (unsigned)h->init_sdtr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005882
Matthew Wilcoxecec1942007-07-30 08:08:22 -06005883 printk(" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, "
5884 "chip_no 0x%x,\n", (unsigned)h->sdtr_done,
5885 (unsigned)h->use_tagged_qng, (unsigned)h->unit_not_ready,
5886 (unsigned)h->chip_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005887
Matthew Wilcoxecec1942007-07-30 08:08:22 -06005888 printk(" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait "
5889 "%u,\n", (unsigned)h->queue_full_or_busy,
5890 (unsigned)h->start_motor, (unsigned)h->scsi_reset_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005891
Matthew Wilcoxecec1942007-07-30 08:08:22 -06005892 printk(" is_in_int %u, max_total_qng %u, cur_total_qng %u, "
5893 "in_critical_cnt %u,\n", (unsigned)h->is_in_int,
5894 (unsigned)h->max_total_qng, (unsigned)h->cur_total_qng,
5895 (unsigned)h->in_critical_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005896
Matthew Wilcoxecec1942007-07-30 08:08:22 -06005897 printk(" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, "
5898 "pci_fix_asyn_xfer 0x%x,\n", (unsigned)h->last_q_shortage,
5899 (unsigned)h->init_state, (unsigned)h->no_scam,
5900 (unsigned)h->pci_fix_asyn_xfer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005901
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005902 printk(" cfg 0x%lx, irq_no 0x%x\n", (ulong)h->cfg, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005903}
5904
5905/*
5906 * asc_prt_asc_dvc_cfg()
5907 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005908static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005909{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005910 printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005911
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005912 printk(" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n",
5913 h->can_tagged_qng, h->cmd_qng_enabled);
5914 printk(" disc_enable 0x%x, sdtr_enable 0x%x,\n",
5915 h->disc_enable, h->sdtr_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005916
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005917 printk
5918 (" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n",
5919 h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel,
5920 h->chip_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005921
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005922 printk
5923 (" pci_device_id %d, lib_serial_no %u, lib_version %u, mcode_date 0x%x,\n",
5924 to_pci_dev(h->dev)->device, h->lib_serial_no, h->lib_version,
5925 h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005926
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005927 printk(" mcode_version %d, overrun_buf 0x%lx\n",
5928 h->mcode_version, (ulong)h->overrun_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005929}
5930
5931/*
5932 * asc_prt_asc_scsi_q()
5933 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005934static void asc_prt_asc_scsi_q(ASC_SCSI_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005935{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005936 ASC_SG_HEAD *sgp;
5937 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005938
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005939 printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005940
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005941 printk
5942 (" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n",
5943 q->q2.target_ix, q->q1.target_lun, (ulong)q->q2.srb_ptr,
5944 q->q2.tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005945
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005946 printk
5947 (" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
5948 (ulong)le32_to_cpu(q->q1.data_addr),
5949 (ulong)le32_to_cpu(q->q1.data_cnt),
5950 (ulong)le32_to_cpu(q->q1.sense_addr), q->q1.sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005951
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005952 printk(" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n",
5953 (ulong)q->cdbptr, q->q2.cdb_len,
5954 (ulong)q->sg_head, q->q1.sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005955
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005956 if (q->sg_head) {
5957 sgp = q->sg_head;
5958 printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong)sgp);
5959 printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt,
5960 sgp->queue_cnt);
5961 for (i = 0; i < sgp->entry_cnt; i++) {
5962 printk(" [%u]: addr 0x%lx, bytes %lu\n",
5963 i, (ulong)le32_to_cpu(sgp->sg_list[i].addr),
5964 (ulong)le32_to_cpu(sgp->sg_list[i].bytes));
5965 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005966
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005967 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005968}
5969
5970/*
5971 * asc_prt_asc_qdone_info()
5972 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005973static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005974{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005975 printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong)q);
5976 printk(" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n",
5977 (ulong)q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
5978 q->d2.tag_code);
5979 printk
5980 (" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n",
5981 q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005982}
5983
5984/*
5985 * asc_prt_adv_dvc_var()
5986 *
5987 * Display an ADV_DVC_VAR structure.
5988 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005989static void asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005990{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005991 printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005992
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005993 printk(" iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n",
5994 (ulong)h->iop_base, h->err_code, (unsigned)h->ultra_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005995
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005996 printk(" isr_callback 0x%lx, sdtr_able 0x%x, wdtr_able 0x%x\n",
5997 (ulong)h->isr_callback, (unsigned)h->sdtr_able,
5998 (unsigned)h->wdtr_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005999
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006000 printk(" start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n",
6001 (unsigned)h->start_motor,
6002 (unsigned)h->scsi_reset_wait, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006003
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006004 printk(" max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n",
6005 (unsigned)h->max_host_qng, (unsigned)h->max_dvc_qng,
6006 (ulong)h->carr_freelist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006007
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006008 printk(" icq_sp 0x%lx, irq_sp 0x%lx\n",
6009 (ulong)h->icq_sp, (ulong)h->irq_sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006010
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006011 printk(" no_scam 0x%x, tagqng_able 0x%x\n",
6012 (unsigned)h->no_scam, (unsigned)h->tagqng_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006013
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006014 printk(" chip_scsi_id 0x%x, cfg 0x%lx\n",
6015 (unsigned)h->chip_scsi_id, (ulong)h->cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006016}
6017
6018/*
6019 * asc_prt_adv_dvc_cfg()
6020 *
6021 * Display an ADV_DVC_CFG structure.
6022 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006023static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006024{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006025 printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006026
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006027 printk(" disc_enable 0x%x, termination 0x%x\n",
6028 h->disc_enable, h->termination);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006029
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006030 printk(" chip_version 0x%x, mcode_date 0x%x\n",
6031 h->chip_version, h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006032
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006033 printk(" mcode_version 0x%x, pci_device_id 0x%x, lib_version %u\n",
6034 h->mcode_version, to_pci_dev(h->dev)->device, h->lib_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006035
Matthew Wilcox13ac2d92007-07-30 08:10:23 -06006036 printk(" control_flag 0x%x\n", h->control_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006037}
6038
6039/*
6040 * asc_prt_adv_scsi_req_q()
6041 *
6042 * Display an ADV_SCSI_REQ_Q structure.
6043 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006044static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006045{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006046 int sg_blk_cnt;
6047 struct asc_sg_block *sg_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006048
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006049 printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006050
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006051 printk(" target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n",
6052 q->target_id, q->target_lun, (ulong)q->srb_ptr, q->a_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006053
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006054 printk(" cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
6055 q->cntl, (ulong)le32_to_cpu(q->data_addr), (ulong)q->vdata_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006056
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006057 printk(" data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
6058 (ulong)le32_to_cpu(q->data_cnt),
6059 (ulong)le32_to_cpu(q->sense_addr), q->sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006060
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006061 printk
6062 (" cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n",
6063 q->cdb_len, q->done_status, q->host_status, q->scsi_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006064
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006065 printk(" sg_working_ix 0x%x, target_cmd %u\n",
6066 q->sg_working_ix, q->target_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006067
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006068 printk(" scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n",
6069 (ulong)le32_to_cpu(q->scsiq_rptr),
6070 (ulong)le32_to_cpu(q->sg_real_addr), (ulong)q->sg_list_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006071
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006072 /* Display the request's ADV_SG_BLOCK structures. */
6073 if (q->sg_list_ptr != NULL) {
6074 sg_blk_cnt = 0;
6075 while (1) {
6076 /*
6077 * 'sg_ptr' is a physical address. Convert it to a virtual
6078 * address by indexing 'sg_blk_cnt' into the virtual address
6079 * array 'sg_list_ptr'.
6080 *
6081 * XXX - Assumes all SG physical blocks are virtually contiguous.
6082 */
6083 sg_ptr =
6084 &(((ADV_SG_BLOCK *)(q->sg_list_ptr))[sg_blk_cnt]);
6085 asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr);
6086 if (sg_ptr->sg_ptr == 0) {
6087 break;
6088 }
6089 sg_blk_cnt++;
6090 }
6091 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006092}
6093
6094/*
6095 * asc_prt_adv_sgblock()
6096 *
6097 * Display an ADV_SG_BLOCK structure.
6098 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006099static void asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006100{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006101 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006102
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006103 printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n",
6104 (ulong)b, sgblockno);
6105 printk(" sg_cnt %u, sg_ptr 0x%lx\n",
6106 b->sg_cnt, (ulong)le32_to_cpu(b->sg_ptr));
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06006107 BUG_ON(b->sg_cnt > NO_OF_SG_PER_BLOCK);
6108 if (b->sg_ptr != 0)
6109 BUG_ON(b->sg_cnt != NO_OF_SG_PER_BLOCK);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006110 for (i = 0; i < b->sg_cnt; i++) {
6111 printk(" [%u]: sg_addr 0x%lx, sg_count 0x%lx\n",
6112 i, (ulong)b->sg_list[i].sg_addr,
6113 (ulong)b->sg_list[i].sg_count);
6114 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006115}
6116
6117/*
6118 * asc_prt_hex()
6119 *
6120 * Print hexadecimal output in 4 byte groupings 32 bytes
6121 * or 8 double-words per line.
6122 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006123static void asc_prt_hex(char *f, uchar *s, int l)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006124{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006125 int i;
6126 int j;
6127 int k;
6128 int m;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006129
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006130 printk("%s: (%d bytes)\n", f, l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006131
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006132 for (i = 0; i < l; i += 32) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006133
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006134 /* Display a maximum of 8 double-words per line. */
6135 if ((k = (l - i) / 4) >= 8) {
6136 k = 8;
6137 m = 0;
6138 } else {
6139 m = (l - i) % 4;
6140 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006141
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006142 for (j = 0; j < k; j++) {
6143 printk(" %2.2X%2.2X%2.2X%2.2X",
6144 (unsigned)s[i + (j * 4)],
6145 (unsigned)s[i + (j * 4) + 1],
6146 (unsigned)s[i + (j * 4) + 2],
6147 (unsigned)s[i + (j * 4) + 3]);
6148 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006149
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006150 switch (m) {
6151 case 0:
6152 default:
6153 break;
6154 case 1:
6155 printk(" %2.2X", (unsigned)s[i + (j * 4)]);
6156 break;
6157 case 2:
6158 printk(" %2.2X%2.2X",
6159 (unsigned)s[i + (j * 4)],
6160 (unsigned)s[i + (j * 4) + 1]);
6161 break;
6162 case 3:
6163 printk(" %2.2X%2.2X%2.2X",
6164 (unsigned)s[i + (j * 4) + 1],
6165 (unsigned)s[i + (j * 4) + 2],
6166 (unsigned)s[i + (j * 4) + 3]);
6167 break;
6168 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006169
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006170 printk("\n");
6171 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006172}
6173#endif /* ADVANSYS_DEBUG */
6174
Matthew Wilcox78e77d82007-07-29 21:46:15 -06006175static ushort __devinit AscGetEisaChipCfg(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006176{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006177 PortAddr eisa_cfg_iop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006178
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006179 eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
6180 (PortAddr) (ASC_EISA_CFG_IOP_MASK);
6181 return (inpw(eisa_cfg_iop));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006182}
6183
Matthew Wilcox78e77d82007-07-29 21:46:15 -06006184static uchar __devinit AscSetChipScsiID(PortAddr iop_base, uchar new_host_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006185{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006186 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006187
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006188 if (AscGetChipScsiID(iop_base) == new_host_id) {
6189 return (new_host_id);
6190 }
6191 cfg_lsw = AscGetChipCfgLsw(iop_base);
6192 cfg_lsw &= 0xF8FF;
6193 cfg_lsw |= (ushort)((new_host_id & ASC_MAX_TID) << 8);
6194 AscSetChipCfgLsw(iop_base, cfg_lsw);
6195 return (AscGetChipScsiID(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006196}
6197
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006198static unsigned char __devinit AscGetChipScsiCtrl(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006199{
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006200 unsigned char sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006201
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006202 AscSetBank(iop_base, 1);
6203 sc = inp(iop_base + IOP_REG_SC);
6204 AscSetBank(iop_base, 0);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006205 return sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006206}
6207
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006208static unsigned char __devinit
6209AscGetChipVersion(PortAddr iop_base, unsigned short bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006210{
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006211 if (bus_type & ASC_IS_EISA) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006212 PortAddr eisa_iop;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006213 unsigned char revision;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006214 eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
6215 (PortAddr) ASC_EISA_REV_IOP_MASK;
6216 revision = inp(eisa_iop);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006217 return ASC_CHIP_MIN_VER_EISA - 1 + revision;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006218 }
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006219 return AscGetChipVerNo(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006220}
6221
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006222static ASC_DCNT
6223AscLoadMicroCode(PortAddr iop_base,
6224 ushort s_addr, uchar *mcode_buf, ushort mcode_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006225{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006226 ASC_DCNT chksum;
6227 ushort mcode_word_size;
6228 ushort mcode_chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006229
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006230 /* Write the microcode buffer starting at LRAM address 0. */
6231 mcode_word_size = (ushort)(mcode_size >> 1);
6232 AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
6233 AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006234
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006235 chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size);
6236 ASC_DBG1(1, "AscLoadMicroCode: chksum 0x%lx\n", (ulong)chksum);
6237 mcode_chksum = (ushort)AscMemSumLramWord(iop_base,
6238 (ushort)ASC_CODE_SEC_BEG,
6239 (ushort)((mcode_size -
6240 s_addr - (ushort)
6241 ASC_CODE_SEC_BEG) /
6242 2));
6243 ASC_DBG1(1, "AscLoadMicroCode: mcode_chksum 0x%lx\n",
6244 (ulong)mcode_chksum);
6245 AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum);
6246 AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size);
6247 return (chksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006248}
6249
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006250static int AscFindSignature(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006251{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006252 ushort sig_word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006253
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006254 ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureByte(0x%x) 0x%x\n",
6255 iop_base, AscGetChipSignatureByte(iop_base));
6256 if (AscGetChipSignatureByte(iop_base) == (uchar)ASC_1000_ID1B) {
6257 ASC_DBG2(1,
6258 "AscFindSignature: AscGetChipSignatureWord(0x%x) 0x%x\n",
6259 iop_base, AscGetChipSignatureWord(iop_base));
6260 sig_word = AscGetChipSignatureWord(iop_base);
6261 if ((sig_word == (ushort)ASC_1000_ID0W) ||
6262 (sig_word == (ushort)ASC_1000_ID0W_FIX)) {
6263 return (1);
6264 }
6265 }
6266 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006267}
6268
Matthew Wilcox78e77d82007-07-29 21:46:15 -06006269static void __devinit AscToggleIRQAct(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006270{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006271 AscSetChipStatus(iop_base, CIW_IRQ_ACT);
6272 AscSetChipStatus(iop_base, 0);
6273 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006274}
6275
Matthew Wilcox78e77d82007-07-29 21:46:15 -06006276static uchar __devinit AscGetChipIRQ(PortAddr iop_base, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006277{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006278 ushort cfg_lsw;
6279 uchar chip_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006280
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006281 if ((bus_type & ASC_IS_EISA) != 0) {
6282 cfg_lsw = AscGetEisaChipCfg(iop_base);
6283 chip_irq = (uchar)(((cfg_lsw >> 8) & 0x07) + 10);
6284 if ((chip_irq == 13) || (chip_irq > 15)) {
6285 return (0);
6286 }
6287 return (chip_irq);
6288 }
6289 if ((bus_type & ASC_IS_VL) != 0) {
6290 cfg_lsw = AscGetChipCfgLsw(iop_base);
6291 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x07));
6292 if ((chip_irq == 0) || (chip_irq == 4) || (chip_irq == 7)) {
6293 return (0);
6294 }
6295 return ((uchar)(chip_irq + (ASC_MIN_IRQ_NO - 1)));
6296 }
6297 cfg_lsw = AscGetChipCfgLsw(iop_base);
6298 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x03));
6299 if (chip_irq == 3)
6300 chip_irq += (uchar)2;
6301 return ((uchar)(chip_irq + ASC_MIN_IRQ_NO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006302}
6303
Matthew Wilcox78e77d82007-07-29 21:46:15 -06006304static uchar __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006305AscSetChipIRQ(PortAddr iop_base, uchar irq_no, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006306{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006307 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006308
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006309 if ((bus_type & ASC_IS_VL) != 0) {
6310 if (irq_no != 0) {
6311 if ((irq_no < ASC_MIN_IRQ_NO)
6312 || (irq_no > ASC_MAX_IRQ_NO)) {
6313 irq_no = 0;
6314 } else {
6315 irq_no -= (uchar)((ASC_MIN_IRQ_NO - 1));
6316 }
6317 }
6318 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE3);
6319 cfg_lsw |= (ushort)0x0010;
6320 AscSetChipCfgLsw(iop_base, cfg_lsw);
6321 AscToggleIRQAct(iop_base);
6322 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE0);
6323 cfg_lsw |= (ushort)((irq_no & 0x07) << 2);
6324 AscSetChipCfgLsw(iop_base, cfg_lsw);
6325 AscToggleIRQAct(iop_base);
6326 return (AscGetChipIRQ(iop_base, bus_type));
6327 }
6328 if ((bus_type & (ASC_IS_ISA)) != 0) {
6329 if (irq_no == 15)
6330 irq_no -= (uchar)2;
6331 irq_no -= (uchar)ASC_MIN_IRQ_NO;
6332 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFF3);
6333 cfg_lsw |= (ushort)((irq_no & 0x03) << 2);
6334 AscSetChipCfgLsw(iop_base, cfg_lsw);
6335 return (AscGetChipIRQ(iop_base, bus_type));
6336 }
6337 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006338}
6339
6340#ifdef CONFIG_ISA
Matthew Wilcox78e77d82007-07-29 21:46:15 -06006341static void __devinit AscEnableIsaDma(uchar dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006342{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006343 if (dma_channel < 4) {
6344 outp(0x000B, (ushort)(0xC0 | dma_channel));
6345 outp(0x000A, dma_channel);
6346 } else if (dma_channel < 8) {
6347 outp(0x00D6, (ushort)(0xC0 | (dma_channel - 4)));
6348 outp(0x00D4, (ushort)(dma_channel - 4));
6349 }
6350 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006351}
6352#endif /* CONFIG_ISA */
6353
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006354static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006355{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006356 EXT_MSG ext_msg;
6357 EXT_MSG out_msg;
6358 ushort halt_q_addr;
6359 int sdtr_accept;
6360 ushort int_halt_code;
6361 ASC_SCSI_BIT_ID_TYPE scsi_busy;
6362 ASC_SCSI_BIT_ID_TYPE target_id;
6363 PortAddr iop_base;
6364 uchar tag_code;
6365 uchar q_status;
6366 uchar halt_qp;
6367 uchar sdtr_data;
6368 uchar target_ix;
6369 uchar q_cntl, tid_no;
6370 uchar cur_dvc_qng;
6371 uchar asyn_sdtr;
6372 uchar scsi_status;
6373 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006374
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06006375 BUG_ON(!asc_dvc->drv_ptr);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006376 boardp = asc_dvc->drv_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006377
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006378 iop_base = asc_dvc->iop_base;
6379 int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006380
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006381 halt_qp = AscReadLramByte(iop_base, ASCV_CURCDB_B);
6382 halt_q_addr = ASC_QNO_TO_QADDR(halt_qp);
6383 target_ix = AscReadLramByte(iop_base,
6384 (ushort)(halt_q_addr +
6385 (ushort)ASC_SCSIQ_B_TARGET_IX));
Matthew Wilcox95c9f162007-09-09 08:56:39 -06006386 q_cntl = AscReadLramByte(iop_base,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006387 (ushort)(halt_q_addr + (ushort)ASC_SCSIQ_B_CNTL));
6388 tid_no = ASC_TIX_TO_TID(target_ix);
6389 target_id = (uchar)ASC_TID_TO_TARGET_ID(tid_no);
6390 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
6391 asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB;
6392 } else {
6393 asyn_sdtr = 0;
6394 }
6395 if (int_halt_code == ASC_HALT_DISABLE_ASYN_USE_SYN_FIX) {
6396 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
6397 AscSetChipSDTR(iop_base, 0, tid_no);
6398 boardp->sdtr_data[tid_no] = 0;
6399 }
6400 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
6401 return (0);
6402 } else if (int_halt_code == ASC_HALT_ENABLE_ASYN_USE_SYN_FIX) {
6403 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
6404 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
6405 boardp->sdtr_data[tid_no] = asyn_sdtr;
6406 }
6407 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
6408 return (0);
6409 } else if (int_halt_code == ASC_HALT_EXTMSG_IN) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006410 AscMemWordCopyPtrFromLram(iop_base,
6411 ASCV_MSGIN_BEG,
6412 (uchar *)&ext_msg,
6413 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006414
Matthew Wilcox47d853c2007-07-26 11:41:33 -04006415 if (ext_msg.msg_type == EXTENDED_MESSAGE &&
6416 ext_msg.msg_req == EXTENDED_SDTR &&
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006417 ext_msg.msg_len == MS_SDTR_LEN) {
6418 sdtr_accept = TRUE;
6419 if ((ext_msg.req_ack_offset > ASC_SYN_MAX_OFFSET)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006420
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006421 sdtr_accept = FALSE;
6422 ext_msg.req_ack_offset = ASC_SYN_MAX_OFFSET;
6423 }
6424 if ((ext_msg.xfer_period <
6425 asc_dvc->sdtr_period_tbl[asc_dvc->
6426 host_init_sdtr_index])
6427 || (ext_msg.xfer_period >
6428 asc_dvc->sdtr_period_tbl[asc_dvc->
6429 max_sdtr_index])) {
6430 sdtr_accept = FALSE;
6431 ext_msg.xfer_period =
6432 asc_dvc->sdtr_period_tbl[asc_dvc->
6433 host_init_sdtr_index];
6434 }
6435 if (sdtr_accept) {
6436 sdtr_data =
6437 AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
6438 ext_msg.req_ack_offset);
6439 if ((sdtr_data == 0xFF)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006440
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006441 q_cntl |= QC_MSG_OUT;
6442 asc_dvc->init_sdtr &= ~target_id;
6443 asc_dvc->sdtr_done &= ~target_id;
6444 AscSetChipSDTR(iop_base, asyn_sdtr,
6445 tid_no);
6446 boardp->sdtr_data[tid_no] = asyn_sdtr;
6447 }
6448 }
6449 if (ext_msg.req_ack_offset == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006450
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006451 q_cntl &= ~QC_MSG_OUT;
6452 asc_dvc->init_sdtr &= ~target_id;
6453 asc_dvc->sdtr_done &= ~target_id;
6454 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
6455 } else {
6456 if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006457
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006458 q_cntl &= ~QC_MSG_OUT;
6459 asc_dvc->sdtr_done |= target_id;
6460 asc_dvc->init_sdtr |= target_id;
6461 asc_dvc->pci_fix_asyn_xfer &=
6462 ~target_id;
6463 sdtr_data =
6464 AscCalSDTRData(asc_dvc,
6465 ext_msg.xfer_period,
6466 ext_msg.
6467 req_ack_offset);
6468 AscSetChipSDTR(iop_base, sdtr_data,
6469 tid_no);
6470 boardp->sdtr_data[tid_no] = sdtr_data;
6471 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006472
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006473 q_cntl |= QC_MSG_OUT;
6474 AscMsgOutSDTR(asc_dvc,
6475 ext_msg.xfer_period,
6476 ext_msg.req_ack_offset);
6477 asc_dvc->pci_fix_asyn_xfer &=
6478 ~target_id;
6479 sdtr_data =
6480 AscCalSDTRData(asc_dvc,
6481 ext_msg.xfer_period,
6482 ext_msg.
6483 req_ack_offset);
6484 AscSetChipSDTR(iop_base, sdtr_data,
6485 tid_no);
6486 boardp->sdtr_data[tid_no] = sdtr_data;
6487 asc_dvc->sdtr_done |= target_id;
6488 asc_dvc->init_sdtr |= target_id;
6489 }
6490 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006491
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006492 AscWriteLramByte(iop_base,
6493 (ushort)(halt_q_addr +
6494 (ushort)ASC_SCSIQ_B_CNTL),
6495 q_cntl);
6496 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
6497 return (0);
Matthew Wilcox47d853c2007-07-26 11:41:33 -04006498 } else if (ext_msg.msg_type == EXTENDED_MESSAGE &&
6499 ext_msg.msg_req == EXTENDED_WDTR &&
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006500 ext_msg.msg_len == MS_WDTR_LEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006501
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006502 ext_msg.wdtr_width = 0;
6503 AscMemWordCopyPtrToLram(iop_base,
6504 ASCV_MSGOUT_BEG,
6505 (uchar *)&ext_msg,
6506 sizeof(EXT_MSG) >> 1);
6507 q_cntl |= QC_MSG_OUT;
6508 AscWriteLramByte(iop_base,
6509 (ushort)(halt_q_addr +
6510 (ushort)ASC_SCSIQ_B_CNTL),
6511 q_cntl);
6512 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
6513 return (0);
6514 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006515
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006516 ext_msg.msg_type = MESSAGE_REJECT;
6517 AscMemWordCopyPtrToLram(iop_base,
6518 ASCV_MSGOUT_BEG,
6519 (uchar *)&ext_msg,
6520 sizeof(EXT_MSG) >> 1);
6521 q_cntl |= QC_MSG_OUT;
6522 AscWriteLramByte(iop_base,
6523 (ushort)(halt_q_addr +
6524 (ushort)ASC_SCSIQ_B_CNTL),
6525 q_cntl);
6526 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
6527 return (0);
6528 }
6529 } else if (int_halt_code == ASC_HALT_CHK_CONDITION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006530
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006531 q_cntl |= QC_REQ_SENSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006532
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006533 if ((asc_dvc->init_sdtr & target_id) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006534
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006535 asc_dvc->sdtr_done &= ~target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006536
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006537 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
6538 q_cntl |= QC_MSG_OUT;
6539 AscMsgOutSDTR(asc_dvc,
6540 asc_dvc->
6541 sdtr_period_tbl[(sdtr_data >> 4) &
6542 (uchar)(asc_dvc->
6543 max_sdtr_index -
6544 1)],
6545 (uchar)(sdtr_data & (uchar)
6546 ASC_SYN_MAX_OFFSET));
6547 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006548
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006549 AscWriteLramByte(iop_base,
6550 (ushort)(halt_q_addr +
6551 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006552
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006553 tag_code = AscReadLramByte(iop_base,
6554 (ushort)(halt_q_addr + (ushort)
6555 ASC_SCSIQ_B_TAG_CODE));
6556 tag_code &= 0xDC;
6557 if ((asc_dvc->pci_fix_asyn_xfer & target_id)
6558 && !(asc_dvc->pci_fix_asyn_xfer_always & target_id)
6559 ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006560
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006561 tag_code |= (ASC_TAG_FLAG_DISABLE_DISCONNECT
6562 | ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006563
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006564 }
6565 AscWriteLramByte(iop_base,
6566 (ushort)(halt_q_addr +
6567 (ushort)ASC_SCSIQ_B_TAG_CODE),
6568 tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006569
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006570 q_status = AscReadLramByte(iop_base,
6571 (ushort)(halt_q_addr + (ushort)
6572 ASC_SCSIQ_B_STATUS));
6573 q_status |= (QS_READY | QS_BUSY);
6574 AscWriteLramByte(iop_base,
6575 (ushort)(halt_q_addr +
6576 (ushort)ASC_SCSIQ_B_STATUS),
6577 q_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006578
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006579 scsi_busy = AscReadLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B);
6580 scsi_busy &= ~target_id;
6581 AscWriteLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B, scsi_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006582
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006583 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
6584 return (0);
6585 } else if (int_halt_code == ASC_HALT_SDTR_REJECTED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006586
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006587 AscMemWordCopyPtrFromLram(iop_base,
6588 ASCV_MSGOUT_BEG,
6589 (uchar *)&out_msg,
6590 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006591
Matthew Wilcox47d853c2007-07-26 11:41:33 -04006592 if ((out_msg.msg_type == EXTENDED_MESSAGE) &&
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006593 (out_msg.msg_len == MS_SDTR_LEN) &&
Matthew Wilcox47d853c2007-07-26 11:41:33 -04006594 (out_msg.msg_req == EXTENDED_SDTR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006595
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006596 asc_dvc->init_sdtr &= ~target_id;
6597 asc_dvc->sdtr_done &= ~target_id;
6598 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
6599 boardp->sdtr_data[tid_no] = asyn_sdtr;
6600 }
6601 q_cntl &= ~QC_MSG_OUT;
6602 AscWriteLramByte(iop_base,
6603 (ushort)(halt_q_addr +
6604 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
6605 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
6606 return (0);
6607 } else if (int_halt_code == ASC_HALT_SS_QUEUE_FULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006608
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006609 scsi_status = AscReadLramByte(iop_base,
6610 (ushort)((ushort)halt_q_addr +
6611 (ushort)
6612 ASC_SCSIQ_SCSI_STATUS));
6613 cur_dvc_qng =
6614 AscReadLramByte(iop_base,
6615 (ushort)((ushort)ASC_QADR_BEG +
6616 (ushort)target_ix));
6617 if ((cur_dvc_qng > 0) && (asc_dvc->cur_dvc_qng[tid_no] > 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006618
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006619 scsi_busy = AscReadLramByte(iop_base,
6620 (ushort)ASCV_SCSIBUSY_B);
6621 scsi_busy |= target_id;
6622 AscWriteLramByte(iop_base,
6623 (ushort)ASCV_SCSIBUSY_B, scsi_busy);
6624 asc_dvc->queue_full_or_busy |= target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006625
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006626 if (scsi_status == SAM_STAT_TASK_SET_FULL) {
6627 if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) {
6628 cur_dvc_qng -= 1;
6629 asc_dvc->max_dvc_qng[tid_no] =
6630 cur_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006631
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006632 AscWriteLramByte(iop_base,
6633 (ushort)((ushort)
6634 ASCV_MAX_DVC_QNG_BEG
6635 + (ushort)
6636 tid_no),
6637 cur_dvc_qng);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006638
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006639 /*
Matthew Wilcox95c9f162007-09-09 08:56:39 -06006640 * Set the device queue depth to the
6641 * number of active requests when the
6642 * QUEUE FULL condition was encountered.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006643 */
6644 boardp->queue_full |= target_id;
6645 boardp->queue_full_cnt[tid_no] =
6646 cur_dvc_qng;
6647 }
6648 }
6649 }
6650 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
6651 return (0);
6652 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006653#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006654 else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC) {
6655 uchar q_no;
6656 ushort q_addr;
6657 uchar sg_wk_q_no;
6658 uchar first_sg_wk_q_no;
6659 ASC_SCSI_Q *scsiq; /* Ptr to driver request. */
6660 ASC_SG_HEAD *sg_head; /* Ptr to driver SG request. */
6661 ASC_SG_LIST_Q scsi_sg_q; /* Structure written to queue. */
6662 ushort sg_list_dwords;
6663 ushort sg_entry_cnt;
6664 uchar next_qp;
6665 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006666
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006667 q_no = AscReadLramByte(iop_base, (ushort)ASCV_REQ_SG_LIST_QP);
Matthew Wilcox95c9f162007-09-09 08:56:39 -06006668 if (q_no == ASC_QLINK_END)
6669 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006670
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006671 q_addr = ASC_QNO_TO_QADDR(q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006672
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006673 /*
6674 * Convert the request's SRB pointer to a host ASC_SCSI_REQ
6675 * structure pointer using a macro provided by the driver.
6676 * The ASC_SCSI_REQ pointer provides a pointer to the
6677 * host ASC_SG_HEAD structure.
6678 */
6679 /* Read request's SRB pointer. */
6680 scsiq = (ASC_SCSI_Q *)
6681 ASC_SRB2SCSIQ(ASC_U32_TO_VADDR(AscReadLramDWord(iop_base,
6682 (ushort)
6683 (q_addr +
6684 ASC_SCSIQ_D_SRBPTR))));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006685
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006686 /*
6687 * Get request's first and working SG queue.
6688 */
6689 sg_wk_q_no = AscReadLramByte(iop_base,
6690 (ushort)(q_addr +
6691 ASC_SCSIQ_B_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006692
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006693 first_sg_wk_q_no = AscReadLramByte(iop_base,
6694 (ushort)(q_addr +
6695 ASC_SCSIQ_B_FIRST_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006696
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006697 /*
6698 * Reset request's working SG queue back to the
6699 * first SG queue.
6700 */
6701 AscWriteLramByte(iop_base,
6702 (ushort)(q_addr +
6703 (ushort)ASC_SCSIQ_B_SG_WK_QP),
6704 first_sg_wk_q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006705
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006706 sg_head = scsiq->sg_head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006707
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006708 /*
6709 * Set sg_entry_cnt to the number of SG elements
6710 * that will be completed on this interrupt.
6711 *
6712 * Note: The allocated SG queues contain ASC_MAX_SG_LIST - 1
6713 * SG elements. The data_cnt and data_addr fields which
6714 * add 1 to the SG element capacity are not used when
6715 * restarting SG handling after a halt.
6716 */
6717 if (scsiq->remain_sg_entry_cnt > (ASC_MAX_SG_LIST - 1)) {
6718 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006719
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006720 /*
Matthew Wilcox95c9f162007-09-09 08:56:39 -06006721 * Keep track of remaining number of SG elements that
6722 * will need to be handled on the next interrupt.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006723 */
6724 scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1);
6725 } else {
6726 sg_entry_cnt = scsiq->remain_sg_entry_cnt;
6727 scsiq->remain_sg_entry_cnt = 0;
6728 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006729
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006730 /*
6731 * Copy SG elements into the list of allocated SG queues.
6732 *
6733 * Last index completed is saved in scsiq->next_sg_index.
6734 */
6735 next_qp = first_sg_wk_q_no;
6736 q_addr = ASC_QNO_TO_QADDR(next_qp);
6737 scsi_sg_q.sg_head_qp = q_no;
6738 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
6739 for (i = 0; i < sg_head->queue_cnt; i++) {
6740 scsi_sg_q.seq_no = i + 1;
6741 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
6742 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
6743 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
6744 /*
6745 * After very first SG queue RISC FW uses next
6746 * SG queue first element then checks sg_list_cnt
6747 * against zero and then decrements, so set
6748 * sg_list_cnt 1 less than number of SG elements
6749 * in each SG queue.
6750 */
6751 scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
6752 scsi_sg_q.sg_cur_list_cnt =
6753 ASC_SG_LIST_PER_Q - 1;
6754 } else {
6755 /*
6756 * This is the last SG queue in the list of
6757 * allocated SG queues. If there are more
6758 * SG elements than will fit in the allocated
6759 * queues, then set the QCSG_SG_XFER_MORE flag.
6760 */
6761 if (scsiq->remain_sg_entry_cnt != 0) {
6762 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
6763 } else {
6764 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
6765 }
6766 /* equals sg_entry_cnt * 2 */
6767 sg_list_dwords = sg_entry_cnt << 1;
6768 scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
6769 scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
6770 sg_entry_cnt = 0;
6771 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006772
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006773 scsi_sg_q.q_no = next_qp;
6774 AscMemWordCopyPtrToLram(iop_base,
6775 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
6776 (uchar *)&scsi_sg_q,
6777 sizeof(ASC_SG_LIST_Q) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006778
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006779 AscMemDWordCopyPtrToLram(iop_base,
6780 q_addr + ASC_SGQ_LIST_BEG,
6781 (uchar *)&sg_head->
6782 sg_list[scsiq->next_sg_index],
6783 sg_list_dwords);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006784
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006785 scsiq->next_sg_index += ASC_SG_LIST_PER_Q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006786
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006787 /*
6788 * If the just completed SG queue contained the
6789 * last SG element, then no more SG queues need
6790 * to be written.
6791 */
6792 if (scsi_sg_q.cntl & QCSG_SG_XFER_END) {
6793 break;
6794 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006795
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006796 next_qp = AscReadLramByte(iop_base,
6797 (ushort)(q_addr +
6798 ASC_SCSIQ_B_FWD));
6799 q_addr = ASC_QNO_TO_QADDR(next_qp);
6800 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006801
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006802 /*
6803 * Clear the halt condition so the RISC will be restarted
6804 * after the return.
6805 */
6806 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
6807 return (0);
6808 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006809#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006810 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006811}
6812
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006813static uchar
6814_AscCopyLramScsiDoneQ(PortAddr iop_base,
6815 ushort q_addr,
6816 ASC_QDONE_INFO *scsiq, ASC_DCNT max_dma_count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006817{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006818 ushort _val;
6819 uchar sg_queue_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006820
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006821 DvcGetQinfo(iop_base,
6822 q_addr + ASC_SCSIQ_DONE_INFO_BEG,
6823 (uchar *)scsiq,
6824 (sizeof(ASC_SCSIQ_2) + sizeof(ASC_SCSIQ_3)) / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006825
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006826 _val = AscReadLramWord(iop_base,
6827 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS));
6828 scsiq->q_status = (uchar)_val;
6829 scsiq->q_no = (uchar)(_val >> 8);
6830 _val = AscReadLramWord(iop_base,
6831 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_CNTL));
6832 scsiq->cntl = (uchar)_val;
6833 sg_queue_cnt = (uchar)(_val >> 8);
6834 _val = AscReadLramWord(iop_base,
6835 (ushort)(q_addr +
6836 (ushort)ASC_SCSIQ_B_SENSE_LEN));
6837 scsiq->sense_len = (uchar)_val;
6838 scsiq->extra_bytes = (uchar)(_val >> 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006839
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006840 /*
6841 * Read high word of remain bytes from alternate location.
6842 */
6843 scsiq->remain_bytes = (((ADV_DCNT)AscReadLramWord(iop_base,
6844 (ushort)(q_addr +
6845 (ushort)
6846 ASC_SCSIQ_W_ALT_DC1)))
6847 << 16);
6848 /*
6849 * Read low word of remain bytes from original location.
6850 */
6851 scsiq->remain_bytes += AscReadLramWord(iop_base,
6852 (ushort)(q_addr + (ushort)
6853 ASC_SCSIQ_DW_REMAIN_XFER_CNT));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006854
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006855 scsiq->remain_bytes &= max_dma_count;
6856 return (sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006857}
6858
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006859static int AscIsrQDone(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006860{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006861 uchar next_qp;
6862 uchar n_q_used;
6863 uchar sg_list_qp;
6864 uchar sg_queue_cnt;
6865 uchar q_cnt;
6866 uchar done_q_tail;
6867 uchar tid_no;
6868 ASC_SCSI_BIT_ID_TYPE scsi_busy;
6869 ASC_SCSI_BIT_ID_TYPE target_id;
6870 PortAddr iop_base;
6871 ushort q_addr;
6872 ushort sg_q_addr;
6873 uchar cur_target_qng;
6874 ASC_QDONE_INFO scsiq_buf;
6875 ASC_QDONE_INFO *scsiq;
6876 int false_overrun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006877
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006878 iop_base = asc_dvc->iop_base;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006879 n_q_used = 1;
6880 scsiq = (ASC_QDONE_INFO *)&scsiq_buf;
6881 done_q_tail = (uchar)AscGetVarDoneQTail(iop_base);
6882 q_addr = ASC_QNO_TO_QADDR(done_q_tail);
6883 next_qp = AscReadLramByte(iop_base,
6884 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_FWD));
6885 if (next_qp != ASC_QLINK_END) {
6886 AscPutVarDoneQTail(iop_base, next_qp);
6887 q_addr = ASC_QNO_TO_QADDR(next_qp);
6888 sg_queue_cnt = _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq,
6889 asc_dvc->max_dma_count);
6890 AscWriteLramByte(iop_base,
6891 (ushort)(q_addr +
6892 (ushort)ASC_SCSIQ_B_STATUS),
6893 (uchar)(scsiq->
6894 q_status & (uchar)~(QS_READY |
6895 QS_ABORTED)));
6896 tid_no = ASC_TIX_TO_TID(scsiq->d2.target_ix);
6897 target_id = ASC_TIX_TO_TARGET_ID(scsiq->d2.target_ix);
6898 if ((scsiq->cntl & QC_SG_HEAD) != 0) {
6899 sg_q_addr = q_addr;
6900 sg_list_qp = next_qp;
6901 for (q_cnt = 0; q_cnt < sg_queue_cnt; q_cnt++) {
6902 sg_list_qp = AscReadLramByte(iop_base,
6903 (ushort)(sg_q_addr
6904 + (ushort)
6905 ASC_SCSIQ_B_FWD));
6906 sg_q_addr = ASC_QNO_TO_QADDR(sg_list_qp);
6907 if (sg_list_qp == ASC_QLINK_END) {
6908 AscSetLibErrorCode(asc_dvc,
6909 ASCQ_ERR_SG_Q_LINKS);
6910 scsiq->d3.done_stat = QD_WITH_ERROR;
6911 scsiq->d3.host_stat =
6912 QHSTA_D_QDONE_SG_LIST_CORRUPTED;
6913 goto FATAL_ERR_QDONE;
6914 }
6915 AscWriteLramByte(iop_base,
6916 (ushort)(sg_q_addr + (ushort)
6917 ASC_SCSIQ_B_STATUS),
6918 QS_FREE);
6919 }
6920 n_q_used = sg_queue_cnt + 1;
6921 AscPutVarDoneQTail(iop_base, sg_list_qp);
6922 }
6923 if (asc_dvc->queue_full_or_busy & target_id) {
6924 cur_target_qng = AscReadLramByte(iop_base,
6925 (ushort)((ushort)
6926 ASC_QADR_BEG
6927 + (ushort)
6928 scsiq->d2.
6929 target_ix));
6930 if (cur_target_qng < asc_dvc->max_dvc_qng[tid_no]) {
6931 scsi_busy = AscReadLramByte(iop_base, (ushort)
6932 ASCV_SCSIBUSY_B);
6933 scsi_busy &= ~target_id;
6934 AscWriteLramByte(iop_base,
6935 (ushort)ASCV_SCSIBUSY_B,
6936 scsi_busy);
6937 asc_dvc->queue_full_or_busy &= ~target_id;
6938 }
6939 }
6940 if (asc_dvc->cur_total_qng >= n_q_used) {
6941 asc_dvc->cur_total_qng -= n_q_used;
6942 if (asc_dvc->cur_dvc_qng[tid_no] != 0) {
6943 asc_dvc->cur_dvc_qng[tid_no]--;
6944 }
6945 } else {
6946 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CUR_QNG);
6947 scsiq->d3.done_stat = QD_WITH_ERROR;
6948 goto FATAL_ERR_QDONE;
6949 }
6950 if ((scsiq->d2.srb_ptr == 0UL) ||
6951 ((scsiq->q_status & QS_ABORTED) != 0)) {
6952 return (0x11);
6953 } else if (scsiq->q_status == QS_DONE) {
6954 false_overrun = FALSE;
6955 if (scsiq->extra_bytes != 0) {
6956 scsiq->remain_bytes +=
6957 (ADV_DCNT)scsiq->extra_bytes;
6958 }
6959 if (scsiq->d3.done_stat == QD_WITH_ERROR) {
6960 if (scsiq->d3.host_stat ==
6961 QHSTA_M_DATA_OVER_RUN) {
6962 if ((scsiq->
6963 cntl & (QC_DATA_IN | QC_DATA_OUT))
6964 == 0) {
6965 scsiq->d3.done_stat =
6966 QD_NO_ERROR;
6967 scsiq->d3.host_stat =
6968 QHSTA_NO_ERROR;
6969 } else if (false_overrun) {
6970 scsiq->d3.done_stat =
6971 QD_NO_ERROR;
6972 scsiq->d3.host_stat =
6973 QHSTA_NO_ERROR;
6974 }
6975 } else if (scsiq->d3.host_stat ==
6976 QHSTA_M_HUNG_REQ_SCSI_BUS_RESET) {
6977 AscStopChip(iop_base);
6978 AscSetChipControl(iop_base,
6979 (uchar)(CC_SCSI_RESET
6980 | CC_HALT));
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06006981 udelay(60);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006982 AscSetChipControl(iop_base, CC_HALT);
6983 AscSetChipStatus(iop_base,
6984 CIW_CLR_SCSI_RESET_INT);
6985 AscSetChipStatus(iop_base, 0);
6986 AscSetChipControl(iop_base, 0);
6987 }
6988 }
6989 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
Matthew Wilcox895d6b42007-07-26 11:57:06 -04006990 asc_isr_callback(asc_dvc, scsiq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006991 } else {
6992 if ((AscReadLramByte(iop_base,
6993 (ushort)(q_addr + (ushort)
6994 ASC_SCSIQ_CDB_BEG))
6995 == START_STOP)) {
6996 asc_dvc->unit_not_ready &= ~target_id;
6997 if (scsiq->d3.done_stat != QD_NO_ERROR) {
6998 asc_dvc->start_motor &=
6999 ~target_id;
7000 }
7001 }
7002 }
7003 return (1);
7004 } else {
7005 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS);
7006 FATAL_ERR_QDONE:
7007 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
Matthew Wilcox895d6b42007-07-26 11:57:06 -04007008 asc_isr_callback(asc_dvc, scsiq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007009 }
7010 return (0x80);
7011 }
7012 }
7013 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007014}
7015
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007016static int AscISR(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007017{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007018 ASC_CS_TYPE chipstat;
7019 PortAddr iop_base;
7020 ushort saved_ram_addr;
7021 uchar ctrl_reg;
7022 uchar saved_ctrl_reg;
7023 int int_pending;
7024 int status;
7025 uchar host_flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007026
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007027 iop_base = asc_dvc->iop_base;
7028 int_pending = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007029
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007030 if (AscIsIntPending(iop_base) == 0) {
7031 return int_pending;
7032 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007033
Matthew Wilcox895d6b42007-07-26 11:57:06 -04007034 if ((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007035 return (ERR);
7036 }
7037 if (asc_dvc->in_critical_cnt != 0) {
7038 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL);
7039 return (ERR);
7040 }
7041 if (asc_dvc->is_in_int) {
7042 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY);
7043 return (ERR);
7044 }
7045 asc_dvc->is_in_int = TRUE;
7046 ctrl_reg = AscGetChipControl(iop_base);
7047 saved_ctrl_reg = ctrl_reg & (~(CC_SCSI_RESET | CC_CHIP_RESET |
7048 CC_SINGLE_STEP | CC_DIAG | CC_TEST));
7049 chipstat = AscGetChipStatus(iop_base);
7050 if (chipstat & CSW_SCSI_RESET_LATCH) {
7051 if (!(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))) {
7052 int i = 10;
7053 int_pending = TRUE;
7054 asc_dvc->sdtr_done = 0;
7055 saved_ctrl_reg &= (uchar)(~CC_HALT);
7056 while ((AscGetChipStatus(iop_base) &
7057 CSW_SCSI_RESET_ACTIVE) && (i-- > 0)) {
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06007058 mdelay(100);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007059 }
7060 AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT));
7061 AscSetChipControl(iop_base, CC_HALT);
7062 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
7063 AscSetChipStatus(iop_base, 0);
7064 chipstat = AscGetChipStatus(iop_base);
7065 }
7066 }
7067 saved_ram_addr = AscGetChipLramAddr(iop_base);
7068 host_flag = AscReadLramByte(iop_base,
7069 ASCV_HOST_FLAG_B) &
7070 (uchar)(~ASC_HOST_FLAG_IN_ISR);
7071 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
7072 (uchar)(host_flag | (uchar)ASC_HOST_FLAG_IN_ISR));
7073 if ((chipstat & CSW_INT_PENDING)
7074 || (int_pending)
7075 ) {
7076 AscAckInterrupt(iop_base);
7077 int_pending = TRUE;
7078 if ((chipstat & CSW_HALTED) && (ctrl_reg & CC_SINGLE_STEP)) {
7079 if (AscIsrChipHalted(asc_dvc) == ERR) {
7080 goto ISR_REPORT_QDONE_FATAL_ERROR;
7081 } else {
7082 saved_ctrl_reg &= (uchar)(~CC_HALT);
7083 }
7084 } else {
7085 ISR_REPORT_QDONE_FATAL_ERROR:
7086 if ((asc_dvc->dvc_cntl & ASC_CNTL_INT_MULTI_Q) != 0) {
7087 while (((status =
7088 AscIsrQDone(asc_dvc)) & 0x01) != 0) {
7089 }
7090 } else {
7091 do {
7092 if ((status =
7093 AscIsrQDone(asc_dvc)) == 1) {
7094 break;
7095 }
7096 } while (status == 0x11);
7097 }
7098 if ((status & 0x80) != 0)
7099 int_pending = ERR;
7100 }
7101 }
7102 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
7103 AscSetChipLramAddr(iop_base, saved_ram_addr);
7104 AscSetChipControl(iop_base, saved_ctrl_reg);
7105 asc_dvc->is_in_int = FALSE;
7106 return (int_pending);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007107}
7108
7109/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007110static uchar _asc_mcode_buf[] = {
7111 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007112 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007113 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007114 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007115 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7116 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x12, 0x0D, 0x05,
7117 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7118 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007119 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007120 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
7121 0x00, 0x00, 0xE4, 0x88, 0x00, 0x00, 0x00, 0x00, 0x80, 0x73, 0x48, 0x04,
7122 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73, 0x03, 0x23, 0x36, 0x40,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007123 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007124 0xC2, 0x00, 0x92, 0x80, 0x1E, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x48, 0x98,
7125 0xDF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, 0x4F, 0x00, 0xF5, 0x00,
7126 0x48, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, 0x80, 0x62,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007127 0x92, 0x80, 0x00, 0x46, 0x15, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007128 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xD6, 0x00, 0xA6, 0x97, 0x7F, 0x23,
7129 0x04, 0x61, 0x84, 0x01, 0xE6, 0x84, 0xD2, 0xC1, 0x80, 0x73, 0xCD, 0x04,
7130 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x01, 0xA6, 0x97, 0xC6, 0x81, 0xC2, 0x88,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007131 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0xFE, 0x00, 0x4F, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007132 0x84, 0x97, 0x07, 0xA6, 0x08, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88,
7133 0x03, 0x03, 0x01, 0xDE, 0xC2, 0x88, 0xCE, 0x00, 0x69, 0x60, 0xCE, 0x00,
7134 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x78, 0x01, 0x80, 0x63, 0x07, 0xA6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007135 0x24, 0x01, 0x78, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007136 0x34, 0x01, 0x00, 0x33, 0x04, 0x00, 0xC2, 0x88, 0x03, 0x07, 0x02, 0x01,
7137 0x04, 0xCA, 0x0D, 0x23, 0x68, 0x98, 0x4D, 0x04, 0x04, 0x85, 0x05, 0xD8,
7138 0x0D, 0x23, 0x68, 0x98, 0xCD, 0x04, 0x15, 0x23, 0xF8, 0x88, 0xFB, 0x23,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007139 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x62, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007140 0x00, 0x33, 0x0A, 0x00, 0xC2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x6E, 0x01,
7141 0x00, 0x33, 0x0B, 0x00, 0xC2, 0x88, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33,
7142 0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x88, 0x81, 0x06, 0xAB, 0x82, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007143 0x88, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x92, 0x01, 0x50, 0x00, 0x00, 0xA3,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007144 0x3C, 0x01, 0x00, 0x05, 0x7C, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6,
7145 0x04, 0x23, 0xA0, 0x01, 0x15, 0x23, 0xA1, 0x01, 0xBE, 0x81, 0xFD, 0x23,
7146 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007147 0xB4, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007148 0xC2, 0x88, 0x06, 0x23, 0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01,
7149 0x00, 0xA2, 0xD4, 0x01, 0x57, 0x60, 0x00, 0xA0, 0xDA, 0x01, 0xE6, 0x84,
7150 0x80, 0x23, 0xA0, 0x01, 0xE6, 0x84, 0x80, 0x73, 0x4B, 0x00, 0x06, 0x61,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007151 0x00, 0xA2, 0x00, 0x02, 0x04, 0x01, 0x0C, 0xDE, 0x02, 0x01, 0x03, 0xCC,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007152 0x4F, 0x00, 0x84, 0x97, 0xFC, 0x81, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01,
7153 0x4F, 0x00, 0x62, 0x97, 0x48, 0x04, 0x84, 0x80, 0xF0, 0x97, 0x00, 0x46,
7154 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00, 0x81, 0x73, 0x06, 0x29,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007155 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x6B, 0xEB, 0x11, 0x23, 0xF8, 0x88,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007156 0x04, 0x98, 0xF0, 0x80, 0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x2A, 0x02,
7157 0x7C, 0x95, 0x06, 0xA6, 0x34, 0x02, 0x03, 0xA6, 0x4C, 0x04, 0x46, 0x82,
7158 0x04, 0x01, 0x03, 0xD8, 0xB4, 0x98, 0x6A, 0x96, 0x46, 0x82, 0xFE, 0x95,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007159 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x6C, 0x02,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007160 0x07, 0xA6, 0x5A, 0x02, 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x62, 0x02,
7161 0xC2, 0x88, 0x7C, 0x95, 0x48, 0x82, 0x60, 0x96, 0x48, 0x82, 0x04, 0x23,
7162 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84, 0x04, 0x01, 0x0C, 0xDC,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007163 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007164 0x6F, 0x00, 0xA5, 0x01, 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01,
7165 0x24, 0x2B, 0x1C, 0x01, 0x02, 0xA6, 0xAA, 0x02, 0x07, 0xA6, 0x5A, 0x02,
7166 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x20, 0x04, 0x01, 0xA6, 0xB4, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007167 0x00, 0xA6, 0xB4, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007168 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0x8C, 0x02, 0x4D, 0x04, 0x04, 0x01,
7169 0x0B, 0xDC, 0xE7, 0x23, 0x04, 0x61, 0x84, 0x01, 0x10, 0x31, 0x12, 0x35,
7170 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0xEA, 0x82,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007171 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0xA2, 0xC8,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007172 0x00, 0x33, 0x1F, 0x00, 0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39,
7173 0x0E, 0x3D, 0x7E, 0x98, 0xB6, 0x2D, 0x01, 0xA6, 0x14, 0x03, 0x00, 0xA6,
7174 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6, 0x10, 0x03, 0x03, 0xA6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007175 0x20, 0x04, 0x02, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007176 0x7C, 0x95, 0xEE, 0x82, 0x60, 0x96, 0xEE, 0x82, 0x82, 0x98, 0x80, 0x42,
7177 0x7E, 0x98, 0x64, 0xE4, 0x04, 0x01, 0x2D, 0xC8, 0x31, 0x05, 0x07, 0x01,
7178 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01, 0x05, 0x05, 0x86, 0x98,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007179 0x7E, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007180 0x3C, 0x04, 0x06, 0xA6, 0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33,
7181 0x25, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x32, 0x83, 0x60, 0x96, 0x32, 0x83,
7182 0x04, 0x01, 0x10, 0xCE, 0x07, 0xC8, 0x05, 0x05, 0xEB, 0x04, 0x00, 0x33,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007183 0x00, 0x20, 0xC0, 0x20, 0x81, 0x62, 0x72, 0x83, 0x00, 0x01, 0x05, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007184 0xFF, 0xA2, 0x7A, 0x03, 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83,
7185 0x05, 0x05, 0x15, 0x01, 0x00, 0xA2, 0x9A, 0x03, 0xEC, 0x00, 0x6E, 0x00,
7186 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0x01, 0xA6, 0x96, 0x03,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007187 0x00, 0xA6, 0x96, 0x03, 0x10, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007188 0xA4, 0x03, 0x00, 0xA6, 0xBC, 0x03, 0x10, 0x84, 0xA8, 0x98, 0x80, 0x42,
7189 0x01, 0xA6, 0xA4, 0x03, 0x07, 0xA6, 0xB2, 0x03, 0xD4, 0x83, 0x7C, 0x95,
7190 0xA8, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC2, 0x88, 0xA8, 0x98, 0x80, 0x42,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007191 0x00, 0xA6, 0xBC, 0x03, 0x07, 0xA6, 0xCA, 0x03, 0xD4, 0x83, 0x7C, 0x95,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007192 0xC0, 0x83, 0x00, 0x33, 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32,
7193 0x80, 0x36, 0x04, 0x23, 0xA0, 0x01, 0x12, 0x23, 0xA1, 0x01, 0x10, 0x84,
7194 0x07, 0xF0, 0x06, 0xA4, 0xF4, 0x03, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007195 0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x0E, 0x04, 0x07, 0xA6, 0x06, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007196 0x06, 0xA6, 0x0A, 0x04, 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x7C, 0x95,
7197 0xF4, 0x83, 0x60, 0x96, 0xF4, 0x83, 0x20, 0x84, 0x07, 0xF0, 0x06, 0xA4,
7198 0x20, 0x04, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23, 0x83, 0x03, 0x80, 0x63,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007199 0xB6, 0x2D, 0x03, 0xA6, 0x3C, 0x04, 0x07, 0xA6, 0x34, 0x04, 0x06, 0xA6,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007200 0x38, 0x04, 0x00, 0x33, 0x30, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x20, 0x84,
7201 0x60, 0x96, 0x20, 0x84, 0x1D, 0x01, 0x06, 0xCC, 0x00, 0x33, 0x00, 0x84,
7202 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62, 0xA2, 0x0D, 0x80, 0x63,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007203 0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007204 0x80, 0x63, 0xA3, 0x01, 0x07, 0xA4, 0x64, 0x04, 0x23, 0x01, 0x00, 0xA2,
7205 0x86, 0x04, 0x0A, 0xA0, 0x76, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1D, 0x00,
7206 0xC2, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1E, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007207 0xC2, 0x88, 0x42, 0x23, 0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007208 0x08, 0x23, 0x22, 0xA3, 0xA2, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xAE, 0x04,
7209 0x02, 0x23, 0x22, 0xA3, 0xC4, 0x04, 0x42, 0x23, 0xF8, 0x88, 0x4A, 0x00,
7210 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23, 0xF8, 0x88, 0x04, 0x98,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007211 0x00, 0xA2, 0xC0, 0x04, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007212 0x81, 0x62, 0xE8, 0x81, 0x47, 0x23, 0xF8, 0x88, 0x04, 0x01, 0x0B, 0xDE,
7213 0x04, 0x98, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x81, 0xC0, 0x20, 0x81, 0x62,
7214 0x14, 0x01, 0x00, 0xA0, 0x00, 0x02, 0x43, 0x23, 0xF8, 0x88, 0x04, 0x23,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007215 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007216 0xF4, 0x04, 0x00, 0x33, 0x27, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x04, 0xDC,
7217 0x02, 0x23, 0xA2, 0x01, 0x04, 0x23, 0xA0, 0x01, 0x04, 0x98, 0x26, 0x95,
7218 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00, 0x00, 0xA3, 0x22, 0x05,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007219 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x1C, 0x05, 0x0A, 0x85,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007220 0x46, 0x97, 0xCD, 0x04, 0x24, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01,
7221 0x03, 0xDA, 0x80, 0x23, 0x82, 0x01, 0x34, 0x85, 0x02, 0x23, 0xA0, 0x01,
7222 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x40, 0x05, 0x1D, 0x01, 0x04, 0xD6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007223 0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007224 0x49, 0x00, 0x81, 0x01, 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01,
7225 0xF7, 0x04, 0x03, 0x01, 0x49, 0x04, 0x80, 0x01, 0xC9, 0x00, 0x00, 0x05,
7226 0x00, 0x01, 0xFF, 0xA0, 0x60, 0x05, 0x77, 0x04, 0x01, 0x23, 0xEA, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007227 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007228 0x07, 0xA4, 0xF8, 0x05, 0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85,
7229 0x00, 0x33, 0x2D, 0x00, 0xC2, 0x88, 0x04, 0xA0, 0xB8, 0x05, 0x80, 0x63,
7230 0x00, 0x23, 0xDF, 0x00, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0xA4, 0x05,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007231 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007232 0x62, 0x97, 0x04, 0x85, 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0x04, 0x85,
7233 0x08, 0xA0, 0xBE, 0x05, 0xF4, 0x85, 0x03, 0xA0, 0xC4, 0x05, 0xF4, 0x85,
7234 0x01, 0xA0, 0xCE, 0x05, 0x88, 0x00, 0x80, 0x63, 0xCC, 0x86, 0x07, 0xA0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007235 0xEE, 0x05, 0x5F, 0x00, 0x00, 0x2B, 0xDF, 0x08, 0x00, 0xA2, 0xE6, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007236 0x80, 0x67, 0x80, 0x63, 0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23,
7237 0x68, 0x98, 0x48, 0x23, 0xF8, 0x88, 0x07, 0x23, 0x80, 0x00, 0x06, 0x87,
7238 0x80, 0x63, 0x7C, 0x85, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63, 0x4A, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007239 0x06, 0x61, 0x00, 0xA2, 0x36, 0x06, 0x1D, 0x01, 0x16, 0xD4, 0xC0, 0x23,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007240 0x07, 0x41, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33,
7241 0x37, 0x00, 0xC2, 0x88, 0x1D, 0x01, 0x01, 0xD6, 0x20, 0x23, 0x63, 0x60,
7242 0x83, 0x03, 0x80, 0x63, 0x02, 0x23, 0xDF, 0x00, 0x07, 0xA6, 0x7C, 0x05,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007243 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007244 0x52, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x4E, 0x06, 0x1D, 0x01, 0x03, 0xCA,
7245 0xC0, 0x23, 0x07, 0x41, 0x00, 0x63, 0x1D, 0x01, 0x04, 0xCC, 0x00, 0x33,
7246 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23, 0x07, 0x41, 0x00, 0x63,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007247 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x01, 0x23,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007248 0xDF, 0x00, 0x06, 0xA6, 0x84, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67,
7249 0x80, 0x63, 0x00, 0x33, 0x00, 0x40, 0xC0, 0x20, 0x81, 0x62, 0x00, 0x63,
7250 0x00, 0x00, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x94, 0x06,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007251 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x00, 0x01, 0xA0, 0x14, 0x07, 0x00, 0x2B,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007252 0x40, 0x0E, 0x80, 0x63, 0x01, 0x00, 0x06, 0xA6, 0xAA, 0x06, 0x07, 0xA6,
7253 0x7C, 0x05, 0x40, 0x0E, 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0xA2, 0x06,
7254 0x06, 0xA6, 0xBC, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x40, 0x0E,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007255 0x80, 0x63, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007256 0x07, 0xA6, 0xD6, 0x06, 0x00, 0x33, 0x2A, 0x00, 0xC2, 0x88, 0x03, 0x03,
7257 0x80, 0x63, 0x89, 0x00, 0x0A, 0x2B, 0x07, 0xA6, 0xE8, 0x06, 0x00, 0x33,
7258 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, 0x00, 0xA2, 0xF4, 0x06, 0xC0, 0x0E,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007259 0x80, 0x63, 0xDE, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007260 0x81, 0x62, 0x04, 0x01, 0x02, 0xDA, 0x80, 0x63, 0x7C, 0x85, 0x80, 0x7B,
7261 0x80, 0x63, 0x06, 0xA6, 0x8C, 0x06, 0x00, 0x33, 0x2C, 0x00, 0xC2, 0x88,
7262 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007263 0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007264 0x00, 0x00, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x44, 0x07,
7265 0x07, 0xA6, 0x7C, 0x05, 0xBF, 0x23, 0x04, 0x61, 0x84, 0x01, 0xE6, 0x84,
7266 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x00, 0x01, 0xF2, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007267 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007268 0x80, 0x05, 0x81, 0x05, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04,
7269 0x01, 0x01, 0xF1, 0x00, 0x70, 0x00, 0x81, 0x01, 0x70, 0x04, 0x71, 0x00,
7270 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04, 0x70, 0x00, 0x80, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007271 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007272 0xF1, 0x00, 0x70, 0x00, 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01,
7273 0x72, 0x00, 0x81, 0x01, 0x71, 0x04, 0x70, 0x00, 0x81, 0x01, 0x70, 0x04,
7274 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05, 0xA3, 0x01, 0xA2, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007275 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007276 0xC4, 0x07, 0x00, 0x33, 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05,
7277 0x04, 0x01, 0x11, 0xC8, 0x48, 0x00, 0xB0, 0x01, 0xB1, 0x01, 0x08, 0x23,
7278 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43, 0x00, 0xA2, 0xE4, 0x07,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007279 0x00, 0x05, 0xDA, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007280 0x05, 0x05, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04,
7281 0x00, 0x02, 0x80, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04, 0x00, 0x63,
7282 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x00, 0xA0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007283 0x14, 0x08, 0x16, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007284 0x00, 0x63, 0xF3, 0x04, 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43,
7285 0xF4, 0x00, 0xCF, 0x40, 0x00, 0xA2, 0x44, 0x08, 0x74, 0x04, 0x02, 0x01,
7286 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1, 0x24, 0x08, 0x04, 0x98,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007287 0x26, 0x95, 0x24, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007288 0x5A, 0x88, 0x02, 0x01, 0x04, 0xD8, 0x46, 0x97, 0x04, 0x98, 0x26, 0x95,
7289 0x4A, 0x88, 0x75, 0x00, 0x00, 0xA3, 0x64, 0x08, 0x00, 0x05, 0x4E, 0x88,
7290 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x76, 0x08,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007291 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007292 0x00, 0x63, 0x38, 0x2B, 0x9C, 0x88, 0x38, 0x2B, 0x92, 0x88, 0x32, 0x09,
7293 0x31, 0x05, 0x92, 0x98, 0x05, 0x05, 0xB2, 0x09, 0x00, 0x63, 0x00, 0x32,
7294 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63, 0x80, 0x32, 0x80, 0x36,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007295 0x80, 0x3A, 0x80, 0x3E, 0xB4, 0x3D, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007296 0x40, 0x36, 0x40, 0x3A, 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40,
7297 0x00, 0xA0, 0xB4, 0x08, 0x5D, 0x00, 0xFE, 0xC3, 0x00, 0x63, 0x80, 0x73,
7298 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73, 0xFF, 0xFD, 0x80, 0x73,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007299 0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007300 0xA1, 0x23, 0xA1, 0x01, 0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77,
7301 0x68, 0x00, 0x00, 0xA2, 0x80, 0x00, 0x03, 0xC2, 0xF1, 0xC7, 0x41, 0x23,
7302 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xE6, 0x84,
Linus Torvalds1da177e2005-04-16 15:20:36 -07007303};
7304
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007305static ushort _asc_mcode_size = sizeof(_asc_mcode_buf);
7306static ADV_DCNT _asc_mcode_chksum = 0x012C453FUL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007307
7308#define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007309static uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = {
7310 INQUIRY,
7311 REQUEST_SENSE,
7312 READ_CAPACITY,
7313 READ_TOC,
7314 MODE_SELECT,
7315 MODE_SENSE,
7316 MODE_SELECT_10,
7317 MODE_SENSE_10,
7318 0xFF,
7319 0xFF,
7320 0xFF,
7321 0xFF,
7322 0xFF,
7323 0xFF,
7324 0xFF,
7325 0xFF
Linus Torvalds1da177e2005-04-16 15:20:36 -07007326};
7327
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007328static int AscExeScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007329{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007330 PortAddr iop_base;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007331 int sta;
7332 int n_q_required;
7333 int disable_syn_offset_one_fix;
7334 int i;
7335 ASC_PADDR addr;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007336 ushort sg_entry_cnt = 0;
7337 ushort sg_entry_cnt_minus_one = 0;
7338 uchar target_ix;
7339 uchar tid_no;
7340 uchar sdtr_data;
7341 uchar extra_bytes;
7342 uchar scsi_cmd;
7343 uchar disable_cmd;
7344 ASC_SG_HEAD *sg_head;
7345 ASC_DCNT data_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007346
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007347 iop_base = asc_dvc->iop_base;
7348 sg_head = scsiq->sg_head;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007349 if (asc_dvc->err_code != 0)
7350 return (ERR);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007351 scsiq->q1.q_no = 0;
7352 if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
7353 scsiq->q1.extra_bytes = 0;
7354 }
7355 sta = 0;
7356 target_ix = scsiq->q2.target_ix;
7357 tid_no = ASC_TIX_TO_TID(target_ix);
7358 n_q_required = 1;
7359 if (scsiq->cdbptr[0] == REQUEST_SENSE) {
7360 if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
7361 asc_dvc->sdtr_done &= ~scsiq->q1.target_id;
7362 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
7363 AscMsgOutSDTR(asc_dvc,
7364 asc_dvc->
7365 sdtr_period_tbl[(sdtr_data >> 4) &
7366 (uchar)(asc_dvc->
7367 max_sdtr_index -
7368 1)],
7369 (uchar)(sdtr_data & (uchar)
7370 ASC_SYN_MAX_OFFSET));
7371 scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
7372 }
7373 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007374 if (asc_dvc->in_critical_cnt != 0) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007375 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY);
7376 return (ERR);
7377 }
7378 asc_dvc->in_critical_cnt++;
7379 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
7380 if ((sg_entry_cnt = sg_head->entry_cnt) == 0) {
7381 asc_dvc->in_critical_cnt--;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007382 return (ERR);
7383 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007384#if !CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007385 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
7386 asc_dvc->in_critical_cnt--;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007387 return (ERR);
7388 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007389#endif /* !CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007390 if (sg_entry_cnt == 1) {
7391 scsiq->q1.data_addr =
7392 (ADV_PADDR)sg_head->sg_list[0].addr;
7393 scsiq->q1.data_cnt =
7394 (ADV_DCNT)sg_head->sg_list[0].bytes;
7395 scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
7396 }
7397 sg_entry_cnt_minus_one = sg_entry_cnt - 1;
7398 }
7399 scsi_cmd = scsiq->cdbptr[0];
7400 disable_syn_offset_one_fix = FALSE;
7401 if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) &&
7402 !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) {
7403 if (scsiq->q1.cntl & QC_SG_HEAD) {
7404 data_cnt = 0;
7405 for (i = 0; i < sg_entry_cnt; i++) {
7406 data_cnt +=
7407 (ADV_DCNT)le32_to_cpu(sg_head->sg_list[i].
7408 bytes);
7409 }
7410 } else {
7411 data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
7412 }
7413 if (data_cnt != 0UL) {
7414 if (data_cnt < 512UL) {
7415 disable_syn_offset_one_fix = TRUE;
7416 } else {
7417 for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST;
7418 i++) {
7419 disable_cmd =
7420 _syn_offset_one_disable_cmd[i];
7421 if (disable_cmd == 0xFF) {
7422 break;
7423 }
7424 if (scsi_cmd == disable_cmd) {
7425 disable_syn_offset_one_fix =
7426 TRUE;
7427 break;
7428 }
7429 }
7430 }
7431 }
7432 }
7433 if (disable_syn_offset_one_fix) {
7434 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
7435 scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX |
7436 ASC_TAG_FLAG_DISABLE_DISCONNECT);
7437 } else {
7438 scsiq->q2.tag_code &= 0x27;
7439 }
7440 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
7441 if (asc_dvc->bug_fix_cntl) {
7442 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
7443 if ((scsi_cmd == READ_6) ||
7444 (scsi_cmd == READ_10)) {
7445 addr =
7446 (ADV_PADDR)le32_to_cpu(sg_head->
7447 sg_list
7448 [sg_entry_cnt_minus_one].
7449 addr) +
7450 (ADV_DCNT)le32_to_cpu(sg_head->
7451 sg_list
7452 [sg_entry_cnt_minus_one].
7453 bytes);
7454 extra_bytes =
7455 (uchar)((ushort)addr & 0x0003);
7456 if ((extra_bytes != 0)
7457 &&
7458 ((scsiq->q2.
7459 tag_code &
7460 ASC_TAG_FLAG_EXTRA_BYTES)
7461 == 0)) {
7462 scsiq->q2.tag_code |=
7463 ASC_TAG_FLAG_EXTRA_BYTES;
7464 scsiq->q1.extra_bytes =
7465 extra_bytes;
7466 data_cnt =
7467 le32_to_cpu(sg_head->
7468 sg_list
7469 [sg_entry_cnt_minus_one].
7470 bytes);
7471 data_cnt -=
7472 (ASC_DCNT) extra_bytes;
7473 sg_head->
7474 sg_list
7475 [sg_entry_cnt_minus_one].
7476 bytes =
7477 cpu_to_le32(data_cnt);
7478 }
7479 }
7480 }
7481 }
7482 sg_head->entry_to_copy = sg_head->entry_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007483#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007484 /*
7485 * Set the sg_entry_cnt to the maximum possible. The rest of
7486 * the SG elements will be copied when the RISC completes the
7487 * SG elements that fit and halts.
7488 */
7489 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
7490 sg_entry_cnt = ASC_MAX_SG_LIST;
7491 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007492#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007493 n_q_required = AscSgListToQueue(sg_entry_cnt);
7494 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
7495 (uint) n_q_required)
7496 || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
7497 if ((sta =
7498 AscSendScsiQueue(asc_dvc, scsiq,
7499 n_q_required)) == 1) {
7500 asc_dvc->in_critical_cnt--;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007501 return (sta);
7502 }
7503 }
7504 } else {
7505 if (asc_dvc->bug_fix_cntl) {
7506 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
7507 if ((scsi_cmd == READ_6) ||
7508 (scsi_cmd == READ_10)) {
7509 addr =
7510 le32_to_cpu(scsiq->q1.data_addr) +
7511 le32_to_cpu(scsiq->q1.data_cnt);
7512 extra_bytes =
7513 (uchar)((ushort)addr & 0x0003);
7514 if ((extra_bytes != 0)
7515 &&
7516 ((scsiq->q2.
7517 tag_code &
7518 ASC_TAG_FLAG_EXTRA_BYTES)
7519 == 0)) {
7520 data_cnt =
7521 le32_to_cpu(scsiq->q1.
7522 data_cnt);
7523 if (((ushort)data_cnt & 0x01FF)
7524 == 0) {
7525 scsiq->q2.tag_code |=
7526 ASC_TAG_FLAG_EXTRA_BYTES;
7527 data_cnt -= (ASC_DCNT)
7528 extra_bytes;
7529 scsiq->q1.data_cnt =
7530 cpu_to_le32
7531 (data_cnt);
7532 scsiq->q1.extra_bytes =
7533 extra_bytes;
7534 }
7535 }
7536 }
7537 }
7538 }
7539 n_q_required = 1;
7540 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) ||
7541 ((scsiq->q1.cntl & QC_URGENT) != 0)) {
7542 if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
7543 n_q_required)) == 1) {
7544 asc_dvc->in_critical_cnt--;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007545 return (sta);
7546 }
7547 }
7548 }
7549 asc_dvc->in_critical_cnt--;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007550 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007551}
7552
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007553static int
7554AscSendScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar n_q_required)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007555{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007556 PortAddr iop_base;
7557 uchar free_q_head;
7558 uchar next_qp;
7559 uchar tid_no;
7560 uchar target_ix;
7561 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007562
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007563 iop_base = asc_dvc->iop_base;
7564 target_ix = scsiq->q2.target_ix;
7565 tid_no = ASC_TIX_TO_TID(target_ix);
7566 sta = 0;
7567 free_q_head = (uchar)AscGetVarFreeQHead(iop_base);
7568 if (n_q_required > 1) {
Matthew Wilcox95c9f162007-09-09 08:56:39 -06007569 next_qp = AscAllocMultipleFreeQueue(iop_base, free_q_head,
7570 (uchar)n_q_required);
7571 if (next_qp != ASC_QLINK_END) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007572 asc_dvc->last_q_shortage = 0;
7573 scsiq->sg_head->queue_cnt = n_q_required - 1;
7574 scsiq->q1.q_no = free_q_head;
Matthew Wilcox95c9f162007-09-09 08:56:39 -06007575 sta = AscPutReadySgListQueue(asc_dvc, scsiq,
7576 free_q_head);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007577 }
7578 } else if (n_q_required == 1) {
Matthew Wilcox95c9f162007-09-09 08:56:39 -06007579 next_qp = AscAllocFreeQueue(iop_base, free_q_head);
7580 if (next_qp != ASC_QLINK_END) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007581 scsiq->q1.q_no = free_q_head;
Matthew Wilcox95c9f162007-09-09 08:56:39 -06007582 sta = AscPutReadyQueue(asc_dvc, scsiq, free_q_head);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007583 }
7584 }
Matthew Wilcox95c9f162007-09-09 08:56:39 -06007585 if (sta == 1) {
7586 AscPutVarFreeQHead(iop_base, next_qp);
7587 asc_dvc->cur_total_qng += (uchar)(n_q_required);
7588 asc_dvc->cur_dvc_qng[tid_no]++;
7589 }
7590 return sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007591}
7592
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007593static int AscSgListToQueue(int sg_list)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007594{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007595 int n_sg_list_qs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007596
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007597 n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q);
7598 if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0)
7599 n_sg_list_qs++;
7600 return (n_sg_list_qs + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007601}
7602
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007603static uint
7604AscGetNumOfFreeQueue(ASC_DVC_VAR *asc_dvc, uchar target_ix, uchar n_qs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007605{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007606 uint cur_used_qs;
7607 uint cur_free_qs;
7608 ASC_SCSI_BIT_ID_TYPE target_id;
7609 uchar tid_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007610
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007611 target_id = ASC_TIX_TO_TARGET_ID(target_ix);
7612 tid_no = ASC_TIX_TO_TID(target_ix);
7613 if ((asc_dvc->unit_not_ready & target_id) ||
7614 (asc_dvc->queue_full_or_busy & target_id)) {
7615 return (0);
7616 }
7617 if (n_qs == 1) {
7618 cur_used_qs = (uint) asc_dvc->cur_total_qng +
7619 (uint) asc_dvc->last_q_shortage + (uint) ASC_MIN_FREE_Q;
7620 } else {
7621 cur_used_qs = (uint) asc_dvc->cur_total_qng +
7622 (uint) ASC_MIN_FREE_Q;
7623 }
7624 if ((uint) (cur_used_qs + n_qs) <= (uint) asc_dvc->max_total_qng) {
7625 cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs;
7626 if (asc_dvc->cur_dvc_qng[tid_no] >=
7627 asc_dvc->max_dvc_qng[tid_no]) {
7628 return (0);
7629 }
7630 return (cur_free_qs);
7631 }
7632 if (n_qs > 1) {
7633 if ((n_qs > asc_dvc->last_q_shortage)
7634 && (n_qs <= (asc_dvc->max_total_qng - ASC_MIN_FREE_Q))) {
7635 asc_dvc->last_q_shortage = n_qs;
7636 }
7637 }
7638 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007639}
7640
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007641static int AscPutReadyQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007642{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007643 ushort q_addr;
7644 uchar tid_no;
7645 uchar sdtr_data;
7646 uchar syn_period_ix;
7647 uchar syn_offset;
7648 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007649
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007650 iop_base = asc_dvc->iop_base;
7651 if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) &&
7652 ((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) {
7653 tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix);
7654 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
7655 syn_period_ix =
7656 (sdtr_data >> 4) & (asc_dvc->max_sdtr_index - 1);
7657 syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET;
7658 AscMsgOutSDTR(asc_dvc,
7659 asc_dvc->sdtr_period_tbl[syn_period_ix],
7660 syn_offset);
7661 scsiq->q1.cntl |= QC_MSG_OUT;
7662 }
7663 q_addr = ASC_QNO_TO_QADDR(q_no);
7664 if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) {
7665 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
7666 }
7667 scsiq->q1.status = QS_FREE;
7668 AscMemWordCopyPtrToLram(iop_base,
7669 q_addr + ASC_SCSIQ_CDB_BEG,
7670 (uchar *)scsiq->cdbptr, scsiq->q2.cdb_len >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007671
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007672 DvcPutScsiQ(iop_base,
7673 q_addr + ASC_SCSIQ_CPY_BEG,
7674 (uchar *)&scsiq->q1.cntl,
7675 ((sizeof(ASC_SCSIQ_1) + sizeof(ASC_SCSIQ_2)) / 2) - 1);
7676 AscWriteLramWord(iop_base,
7677 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS),
7678 (ushort)(((ushort)scsiq->q1.
7679 q_no << 8) | (ushort)QS_READY));
7680 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007681}
7682
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007683static int
7684AscPutReadySgListQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007685{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007686 int sta;
7687 int i;
7688 ASC_SG_HEAD *sg_head;
7689 ASC_SG_LIST_Q scsi_sg_q;
7690 ASC_DCNT saved_data_addr;
7691 ASC_DCNT saved_data_cnt;
7692 PortAddr iop_base;
7693 ushort sg_list_dwords;
7694 ushort sg_index;
7695 ushort sg_entry_cnt;
7696 ushort q_addr;
7697 uchar next_qp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007698
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007699 iop_base = asc_dvc->iop_base;
7700 sg_head = scsiq->sg_head;
7701 saved_data_addr = scsiq->q1.data_addr;
7702 saved_data_cnt = scsiq->q1.data_cnt;
7703 scsiq->q1.data_addr = (ASC_PADDR) sg_head->sg_list[0].addr;
7704 scsiq->q1.data_cnt = (ASC_DCNT) sg_head->sg_list[0].bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007705#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007706 /*
7707 * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST
7708 * then not all SG elements will fit in the allocated queues.
7709 * The rest of the SG elements will be copied when the RISC
7710 * completes the SG elements that fit and halts.
7711 */
7712 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
7713 /*
7714 * Set sg_entry_cnt to be the number of SG elements that
7715 * will fit in the allocated SG queues. It is minus 1, because
7716 * the first SG element is handled above. ASC_MAX_SG_LIST is
7717 * already inflated by 1 to account for this. For example it
7718 * may be 50 which is 1 + 7 queues * 7 SG elements.
7719 */
7720 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007721
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007722 /*
7723 * Keep track of remaining number of SG elements that will
7724 * need to be handled from a_isr.c.
7725 */
7726 scsiq->remain_sg_entry_cnt =
7727 sg_head->entry_cnt - ASC_MAX_SG_LIST;
7728 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007729#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007730 /*
7731 * Set sg_entry_cnt to be the number of SG elements that
7732 * will fit in the allocated SG queues. It is minus 1, because
7733 * the first SG element is handled above.
7734 */
7735 sg_entry_cnt = sg_head->entry_cnt - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007736#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007737 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007738#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007739 if (sg_entry_cnt != 0) {
7740 scsiq->q1.cntl |= QC_SG_HEAD;
7741 q_addr = ASC_QNO_TO_QADDR(q_no);
7742 sg_index = 1;
7743 scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
7744 scsi_sg_q.sg_head_qp = q_no;
7745 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
7746 for (i = 0; i < sg_head->queue_cnt; i++) {
7747 scsi_sg_q.seq_no = i + 1;
7748 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
7749 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
7750 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
7751 if (i == 0) {
7752 scsi_sg_q.sg_list_cnt =
7753 ASC_SG_LIST_PER_Q;
7754 scsi_sg_q.sg_cur_list_cnt =
7755 ASC_SG_LIST_PER_Q;
7756 } else {
7757 scsi_sg_q.sg_list_cnt =
7758 ASC_SG_LIST_PER_Q - 1;
7759 scsi_sg_q.sg_cur_list_cnt =
7760 ASC_SG_LIST_PER_Q - 1;
7761 }
7762 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007763#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007764 /*
7765 * This is the last SG queue in the list of
7766 * allocated SG queues. If there are more
7767 * SG elements than will fit in the allocated
7768 * queues, then set the QCSG_SG_XFER_MORE flag.
7769 */
7770 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
7771 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
7772 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007773#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007774 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007775#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007776 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007777#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007778 sg_list_dwords = sg_entry_cnt << 1;
7779 if (i == 0) {
7780 scsi_sg_q.sg_list_cnt = sg_entry_cnt;
7781 scsi_sg_q.sg_cur_list_cnt =
7782 sg_entry_cnt;
7783 } else {
7784 scsi_sg_q.sg_list_cnt =
7785 sg_entry_cnt - 1;
7786 scsi_sg_q.sg_cur_list_cnt =
7787 sg_entry_cnt - 1;
7788 }
7789 sg_entry_cnt = 0;
7790 }
7791 next_qp = AscReadLramByte(iop_base,
7792 (ushort)(q_addr +
7793 ASC_SCSIQ_B_FWD));
7794 scsi_sg_q.q_no = next_qp;
7795 q_addr = ASC_QNO_TO_QADDR(next_qp);
7796 AscMemWordCopyPtrToLram(iop_base,
7797 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
7798 (uchar *)&scsi_sg_q,
7799 sizeof(ASC_SG_LIST_Q) >> 1);
7800 AscMemDWordCopyPtrToLram(iop_base,
7801 q_addr + ASC_SGQ_LIST_BEG,
7802 (uchar *)&sg_head->
7803 sg_list[sg_index],
7804 sg_list_dwords);
7805 sg_index += ASC_SG_LIST_PER_Q;
7806 scsiq->next_sg_index = sg_index;
7807 }
7808 } else {
7809 scsiq->q1.cntl &= ~QC_SG_HEAD;
7810 }
7811 sta = AscPutReadyQueue(asc_dvc, scsiq, q_no);
7812 scsiq->q1.data_addr = saved_data_addr;
7813 scsiq->q1.data_cnt = saved_data_cnt;
7814 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007815}
7816
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007817static int
7818AscSetRunChipSynRegAtID(PortAddr iop_base, uchar tid_no, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007819{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007820 int sta = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007821
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007822 if (AscHostReqRiscHalt(iop_base)) {
7823 sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
7824 AscStartChip(iop_base);
7825 return (sta);
7826 }
7827 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007828}
7829
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007830static int AscSetChipSynRegAtID(PortAddr iop_base, uchar id, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007831{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007832 ASC_SCSI_BIT_ID_TYPE org_id;
7833 int i;
7834 int sta = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007835
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007836 AscSetBank(iop_base, 1);
7837 org_id = AscReadChipDvcID(iop_base);
7838 for (i = 0; i <= ASC_MAX_TID; i++) {
7839 if (org_id == (0x01 << i))
7840 break;
7841 }
7842 org_id = (ASC_SCSI_BIT_ID_TYPE) i;
7843 AscWriteChipDvcID(iop_base, id);
7844 if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
7845 AscSetBank(iop_base, 0);
7846 AscSetChipSyn(iop_base, sdtr_data);
7847 if (AscGetChipSyn(iop_base) != sdtr_data) {
7848 sta = FALSE;
7849 }
7850 } else {
7851 sta = FALSE;
7852 }
7853 AscSetBank(iop_base, 1);
7854 AscWriteChipDvcID(iop_base, org_id);
7855 AscSetBank(iop_base, 0);
7856 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007857}
7858
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007859static ushort AscInitLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007860{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007861 uchar i;
7862 ushort s_addr;
7863 PortAddr iop_base;
7864 ushort warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007865
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007866 iop_base = asc_dvc->iop_base;
7867 warn_code = 0;
7868 AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0,
7869 (ushort)(((int)(asc_dvc->max_total_qng + 2 + 1) *
7870 64) >> 1)
7871 );
7872 i = ASC_MIN_ACTIVE_QNO;
7873 s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE;
7874 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
7875 (uchar)(i + 1));
7876 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
7877 (uchar)(asc_dvc->max_total_qng));
7878 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
7879 (uchar)i);
7880 i++;
7881 s_addr += ASC_QBLK_SIZE;
7882 for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) {
7883 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
7884 (uchar)(i + 1));
7885 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
7886 (uchar)(i - 1));
7887 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
7888 (uchar)i);
7889 }
7890 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
7891 (uchar)ASC_QLINK_END);
7892 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
7893 (uchar)(asc_dvc->max_total_qng - 1));
7894 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
7895 (uchar)asc_dvc->max_total_qng);
7896 i++;
7897 s_addr += ASC_QBLK_SIZE;
7898 for (; i <= (uchar)(asc_dvc->max_total_qng + 3);
7899 i++, s_addr += ASC_QBLK_SIZE) {
7900 AscWriteLramByte(iop_base,
7901 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_FWD), i);
7902 AscWriteLramByte(iop_base,
7903 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_BWD), i);
7904 AscWriteLramByte(iop_base,
7905 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_QNO), i);
7906 }
7907 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007908}
7909
Matthew Wilcox95c9f162007-09-09 08:56:39 -06007910static void AscInitQLinkVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007911{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007912 PortAddr iop_base;
7913 int i;
7914 ushort lram_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007915
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007916 iop_base = asc_dvc->iop_base;
7917 AscPutRiscVarFreeQHead(iop_base, 1);
7918 AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng);
7919 AscPutVarFreeQHead(iop_base, 1);
7920 AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng);
7921 AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B,
7922 (uchar)((int)asc_dvc->max_total_qng + 1));
7923 AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B,
7924 (uchar)((int)asc_dvc->max_total_qng + 2));
7925 AscWriteLramByte(iop_base, (ushort)ASCV_TOTAL_READY_Q_B,
7926 asc_dvc->max_total_qng);
7927 AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0);
7928 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
7929 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
7930 AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0);
7931 AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0);
7932 AscPutQDoneInProgress(iop_base, 0);
7933 lram_addr = ASC_QADR_BEG;
7934 for (i = 0; i < 32; i++, lram_addr += 2) {
7935 AscWriteLramWord(iop_base, lram_addr, 0);
7936 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007937}
7938
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007939static int AscSetLibErrorCode(ASC_DVC_VAR *asc_dvc, ushort err_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007940{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007941 if (asc_dvc->err_code == 0) {
7942 asc_dvc->err_code = err_code;
7943 AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W,
7944 err_code);
7945 }
7946 return (err_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007947}
7948
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007949static uchar
7950AscMsgOutSDTR(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar sdtr_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007951{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007952 EXT_MSG sdtr_buf;
7953 uchar sdtr_period_index;
7954 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007955
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007956 iop_base = asc_dvc->iop_base;
Matthew Wilcox47d853c2007-07-26 11:41:33 -04007957 sdtr_buf.msg_type = EXTENDED_MESSAGE;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007958 sdtr_buf.msg_len = MS_SDTR_LEN;
Matthew Wilcox47d853c2007-07-26 11:41:33 -04007959 sdtr_buf.msg_req = EXTENDED_SDTR;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007960 sdtr_buf.xfer_period = sdtr_period;
7961 sdtr_offset &= ASC_SYN_MAX_OFFSET;
7962 sdtr_buf.req_ack_offset = sdtr_offset;
7963 if ((sdtr_period_index =
7964 AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <=
7965 asc_dvc->max_sdtr_index) {
7966 AscMemWordCopyPtrToLram(iop_base,
7967 ASCV_MSGOUT_BEG,
7968 (uchar *)&sdtr_buf,
7969 sizeof(EXT_MSG) >> 1);
7970 return ((sdtr_period_index << 4) | sdtr_offset);
7971 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007972
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007973 sdtr_buf.req_ack_offset = 0;
7974 AscMemWordCopyPtrToLram(iop_base,
7975 ASCV_MSGOUT_BEG,
7976 (uchar *)&sdtr_buf,
7977 sizeof(EXT_MSG) >> 1);
7978 return (0);
7979 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007980}
7981
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007982static uchar
7983AscCalSDTRData(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar syn_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007984{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007985 uchar byte;
7986 uchar sdtr_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007987
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007988 sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
7989 if ((sdtr_period_ix > asc_dvc->max_sdtr_index)
7990 ) {
7991 return (0xFF);
7992 }
7993 byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET);
7994 return (byte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007995}
7996
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007997static void AscSetChipSDTR(PortAddr iop_base, uchar sdtr_data, uchar tid_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007998{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007999 AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
8000 AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data);
8001 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008002}
8003
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008004static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *asc_dvc, uchar syn_time)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008005{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008006 uchar *period_table;
8007 int max_index;
8008 int min_index;
8009 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008010
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008011 period_table = asc_dvc->sdtr_period_tbl;
8012 max_index = (int)asc_dvc->max_sdtr_index;
8013 min_index = (int)asc_dvc->host_init_sdtr_index;
8014 if ((syn_time <= period_table[max_index])) {
8015 for (i = min_index; i < (max_index - 1); i++) {
8016 if (syn_time <= period_table[i]) {
8017 return ((uchar)i);
8018 }
8019 }
8020 return ((uchar)max_index);
8021 } else {
8022 return ((uchar)(max_index + 1));
8023 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008024}
8025
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008026static uchar AscAllocFreeQueue(PortAddr iop_base, uchar free_q_head)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008027{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008028 ushort q_addr;
8029 uchar next_qp;
8030 uchar q_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008031
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008032 q_addr = ASC_QNO_TO_QADDR(free_q_head);
8033 q_status = (uchar)AscReadLramByte(iop_base,
8034 (ushort)(q_addr +
8035 ASC_SCSIQ_B_STATUS));
8036 next_qp = AscReadLramByte(iop_base, (ushort)(q_addr + ASC_SCSIQ_B_FWD));
8037 if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END)) {
8038 return (next_qp);
8039 }
8040 return (ASC_QLINK_END);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008041}
8042
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008043static uchar
8044AscAllocMultipleFreeQueue(PortAddr iop_base, uchar free_q_head, uchar n_free_q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008045{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008046 uchar i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008047
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008048 for (i = 0; i < n_free_q; i++) {
8049 if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head))
8050 == ASC_QLINK_END) {
8051 return (ASC_QLINK_END);
8052 }
8053 }
8054 return (free_q_head);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008055}
8056
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008057static int AscHostReqRiscHalt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008058{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008059 int count = 0;
8060 int sta = 0;
8061 uchar saved_stop_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008062
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008063 if (AscIsChipHalted(iop_base))
8064 return (1);
8065 saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
8066 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
8067 ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP);
8068 do {
8069 if (AscIsChipHalted(iop_base)) {
8070 sta = 1;
8071 break;
8072 }
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06008073 mdelay(100);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008074 } while (count++ < 20);
8075 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code);
8076 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008077}
8078
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008079static int AscStopQueueExe(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008080{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008081 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008082
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008083 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) {
8084 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
8085 ASC_STOP_REQ_RISC_STOP);
8086 do {
8087 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) &
8088 ASC_STOP_ACK_RISC_STOP) {
8089 return (1);
8090 }
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06008091 mdelay(100);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008092 } while (count++ < 20);
8093 }
8094 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008095}
8096
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008097static int AscStartChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008098{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008099 AscSetChipControl(iop_base, 0);
8100 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
8101 return (0);
8102 }
8103 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008104}
8105
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008106static int AscStopChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008107{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008108 uchar cc_val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008109
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008110 cc_val =
8111 AscGetChipControl(iop_base) &
8112 (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG));
8113 AscSetChipControl(iop_base, (uchar)(cc_val | CC_HALT));
8114 AscSetChipIH(iop_base, INS_HALT);
8115 AscSetChipIH(iop_base, INS_RFLAG_WTM);
8116 if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) {
8117 return (0);
8118 }
8119 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008120}
8121
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008122static int AscIsChipHalted(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008123{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008124 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
8125 if ((AscGetChipControl(iop_base) & CC_HALT) != 0) {
8126 return (1);
8127 }
8128 }
8129 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008130}
8131
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008132static void AscSetChipIH(PortAddr iop_base, ushort ins_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008133{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008134 AscSetBank(iop_base, 1);
8135 AscWriteChipIH(iop_base, ins_code);
8136 AscSetBank(iop_base, 0);
8137 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008138}
8139
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008140static void AscAckInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008141{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008142 uchar host_flag;
8143 uchar risc_flag;
8144 ushort loop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008145
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008146 loop = 0;
8147 do {
8148 risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B);
8149 if (loop++ > 0x7FFF) {
8150 break;
8151 }
8152 } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0);
8153 host_flag =
8154 AscReadLramByte(iop_base,
8155 ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT);
8156 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
8157 (uchar)(host_flag | ASC_HOST_FLAG_ACK_INT));
8158 AscSetChipStatus(iop_base, CIW_INT_ACK);
8159 loop = 0;
8160 while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) {
8161 AscSetChipStatus(iop_base, CIW_INT_ACK);
8162 if (loop++ > 3) {
8163 break;
8164 }
8165 }
8166 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
8167 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008168}
8169
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008170static void AscDisableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008171{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008172 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008173
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008174 cfg = AscGetChipCfgLsw(iop_base);
8175 AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON));
8176 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008177}
8178
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008179static void AscEnableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008180{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008181 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008182
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008183 cfg = AscGetChipCfgLsw(iop_base);
8184 AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON);
8185 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008186}
8187
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008188static void AscSetBank(PortAddr iop_base, uchar bank)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008189{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008190 uchar val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008191
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008192 val = AscGetChipControl(iop_base) &
8193 (~
8194 (CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET |
8195 CC_CHIP_RESET));
8196 if (bank == 1) {
8197 val |= CC_BANK_ONE;
8198 } else if (bank == 2) {
8199 val |= CC_DIAG | CC_BANK_ONE;
8200 } else {
8201 val &= ~CC_BANK_ONE;
8202 }
8203 AscSetChipControl(iop_base, val);
8204 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008205}
8206
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008207static int AscResetChipAndScsiBus(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008208{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008209 PortAddr iop_base;
8210 int i = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008211
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008212 iop_base = asc_dvc->iop_base;
8213 while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE)
8214 && (i-- > 0)) {
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06008215 mdelay(100);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008216 }
8217 AscStopChip(iop_base);
8218 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06008219 udelay(60);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008220 AscSetChipIH(iop_base, INS_RFLAG_WTM);
8221 AscSetChipIH(iop_base, INS_HALT);
8222 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT);
8223 AscSetChipControl(iop_base, CC_HALT);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06008224 mdelay(200);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008225 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
8226 AscSetChipStatus(iop_base, 0);
8227 return (AscIsChipHalted(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008228}
8229
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008230static ASC_DCNT __devinit AscGetMaxDmaCount(ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008231{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008232 if (bus_type & ASC_IS_ISA)
Matthew Wilcox95c9f162007-09-09 08:56:39 -06008233 return ASC_MAX_ISA_DMA_COUNT;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008234 else if (bus_type & (ASC_IS_EISA | ASC_IS_VL))
Matthew Wilcox95c9f162007-09-09 08:56:39 -06008235 return ASC_MAX_VL_DMA_COUNT;
8236 return ASC_MAX_PCI_DMA_COUNT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008237}
8238
8239#ifdef CONFIG_ISA
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008240static ushort __devinit AscGetIsaDmaChannel(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008241{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008242 ushort channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008243
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008244 channel = AscGetChipCfgLsw(iop_base) & 0x0003;
8245 if (channel == 0x03)
8246 return (0);
8247 else if (channel == 0x00)
8248 return (7);
8249 return (channel + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008250}
8251
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008252static ushort __devinit AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008253{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008254 ushort cfg_lsw;
8255 uchar value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008256
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008257 if ((dma_channel >= 5) && (dma_channel <= 7)) {
8258 if (dma_channel == 7)
8259 value = 0x00;
8260 else
8261 value = dma_channel - 4;
8262 cfg_lsw = AscGetChipCfgLsw(iop_base) & 0xFFFC;
8263 cfg_lsw |= value;
8264 AscSetChipCfgLsw(iop_base, cfg_lsw);
8265 return (AscGetIsaDmaChannel(iop_base));
8266 }
8267 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008268}
8269
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008270static uchar __devinit AscSetIsaDmaSpeed(PortAddr iop_base, uchar speed_value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008271{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008272 speed_value &= 0x07;
8273 AscSetBank(iop_base, 1);
8274 AscWriteChipDmaSpeed(iop_base, speed_value);
8275 AscSetBank(iop_base, 0);
8276 return (AscGetIsaDmaSpeed(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008277}
8278
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008279static uchar __devinit AscGetIsaDmaSpeed(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008280{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008281 uchar speed_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008282
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008283 AscSetBank(iop_base, 1);
8284 speed_value = AscReadChipDmaSpeed(iop_base);
8285 speed_value &= 0x07;
8286 AscSetBank(iop_base, 0);
8287 return (speed_value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008288}
8289#endif /* CONFIG_ISA */
8290
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06008291static int __devinit AscInitGetConfig(asc_board_t *boardp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008292{
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06008293 ASC_DVC_VAR *asc_dvc = &boardp->dvc_var.asc_dvc_var;
Matthew Wilcox9649af32007-07-26 21:51:47 -06008294 unsigned short warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008295
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008296 asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG;
Matthew Wilcox9649af32007-07-26 21:51:47 -06008297 if (asc_dvc->err_code != 0)
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06008298 return asc_dvc->err_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008299
Matthew Wilcox9649af32007-07-26 21:51:47 -06008300 if (AscFindSignature(asc_dvc->iop_base)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008301 warn_code |= AscInitAscDvcVar(asc_dvc);
8302 warn_code |= AscInitFromEEP(asc_dvc);
8303 asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06008304 if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008305 asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008306 } else {
8307 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
8308 }
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06008309
8310 switch (warn_code) {
8311 case 0: /* No error */
8312 break;
8313 case ASC_WARN_IO_PORT_ROTATE:
8314 ASC_PRINT1("AscInitGetConfig: board %d: I/O port address "
8315 "modified\n", boardp->id);
8316 break;
8317 case ASC_WARN_AUTO_CONFIG:
8318 ASC_PRINT1("AscInitGetConfig: board %d: I/O port increment "
8319 "switch enabled\n", boardp->id);
8320 break;
8321 case ASC_WARN_EEPROM_CHKSUM:
8322 ASC_PRINT1("AscInitGetConfig: board %d: EEPROM checksum "
8323 "error\n", boardp->id);
8324 break;
8325 case ASC_WARN_IRQ_MODIFIED:
8326 ASC_PRINT1("AscInitGetConfig: board %d: IRQ modified\n",
8327 boardp->id);
8328 break;
8329 case ASC_WARN_CMD_QNG_CONFLICT:
8330 ASC_PRINT1("AscInitGetConfig: board %d: tag queuing enabled "
8331 "w/o disconnects\n", boardp->id);
8332 break;
8333 default:
8334 ASC_PRINT2("AscInitGetConfig: board %d: unknown warning: "
8335 "0x%x\n", boardp->id, warn_code);
8336 break;
8337 }
8338
8339 if (asc_dvc->err_code != 0) {
8340 ASC_PRINT3("AscInitGetConfig: board %d error: init_state 0x%x, "
8341 "err_code 0x%x\n", boardp->id, asc_dvc->init_state,
8342 asc_dvc->err_code);
8343 }
8344
8345 return asc_dvc->err_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008346}
8347
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06008348static int __devinit AscInitSetConfig(struct pci_dev *pdev, asc_board_t *boardp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008349{
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06008350 ASC_DVC_VAR *asc_dvc = &boardp->dvc_var.asc_dvc_var;
Matthew Wilcox394dbf32007-07-26 11:56:40 -04008351 PortAddr iop_base = asc_dvc->iop_base;
8352 unsigned short cfg_msw;
8353 unsigned short warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008354
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008355 asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG;
8356 if (asc_dvc->err_code != 0)
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06008357 return asc_dvc->err_code;
Matthew Wilcox394dbf32007-07-26 11:56:40 -04008358 if (!AscFindSignature(asc_dvc->iop_base)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008359 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06008360 return asc_dvc->err_code;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008361 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008362
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008363 cfg_msw = AscGetChipCfgMsw(iop_base);
8364 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06008365 cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008366 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
8367 AscSetChipCfgMsw(iop_base, cfg_msw);
8368 }
8369 if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) !=
8370 asc_dvc->cfg->cmd_qng_enabled) {
8371 asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled;
8372 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
8373 }
8374 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
8375 warn_code |= ASC_WARN_AUTO_CONFIG;
8376 }
8377 if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) {
8378 if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type)
8379 != asc_dvc->irq_no) {
8380 asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO;
8381 }
8382 }
Matthew Wilcox9649af32007-07-26 21:51:47 -06008383#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008384 if (asc_dvc->bus_type & ASC_IS_PCI) {
8385 cfg_msw &= 0xFFC0;
8386 AscSetChipCfgMsw(iop_base, cfg_msw);
8387 if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
8388 } else {
Matthew Wilcox9649af32007-07-26 21:51:47 -06008389 if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) ||
8390 (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008391 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
8392 asc_dvc->bug_fix_cntl |=
8393 ASC_BUG_FIX_ASYN_USE_SYN;
8394 }
8395 }
Matthew Wilcox9649af32007-07-26 21:51:47 -06008396 } else
8397#endif /* CONFIG_PCI */
8398 if (asc_dvc->bus_type == ASC_IS_ISAPNP) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008399 if (AscGetChipVersion(iop_base, asc_dvc->bus_type)
8400 == ASC_CHIP_VER_ASYN_BUG) {
8401 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
8402 }
8403 }
8404 if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) !=
8405 asc_dvc->cfg->chip_scsi_id) {
8406 asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID;
8407 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008408#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008409 if (asc_dvc->bus_type & ASC_IS_ISA) {
8410 AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel);
8411 AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed);
8412 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008413#endif /* CONFIG_ISA */
Matthew Wilcox394dbf32007-07-26 11:56:40 -04008414
8415 asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG;
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06008416
8417 switch (warn_code) {
8418 case 0: /* No error. */
8419 break;
8420 case ASC_WARN_IO_PORT_ROTATE:
8421 ASC_PRINT1("AscInitSetConfig: board %d: I/O port address "
8422 "modified\n", boardp->id);
8423 break;
8424 case ASC_WARN_AUTO_CONFIG:
8425 ASC_PRINT1("AscInitSetConfig: board %d: I/O port increment "
8426 "switch enabled\n", boardp->id);
8427 break;
8428 case ASC_WARN_EEPROM_CHKSUM:
8429 ASC_PRINT1("AscInitSetConfig: board %d: EEPROM checksum "
8430 "error\n", boardp->id);
8431 break;
8432 case ASC_WARN_IRQ_MODIFIED:
8433 ASC_PRINT1("AscInitSetConfig: board %d: IRQ modified\n",
8434 boardp->id);
8435 break;
8436 case ASC_WARN_CMD_QNG_CONFLICT:
8437 ASC_PRINT1("AscInitSetConfig: board %d: tag queuing w/o "
8438 "disconnects\n",
8439 boardp->id);
8440 break;
8441 default:
8442 ASC_PRINT2("AscInitSetConfig: board %d: unknown warning: "
8443 "0x%x\n", boardp->id, warn_code);
8444 break;
8445 }
8446
8447 if (asc_dvc->err_code != 0) {
8448 ASC_PRINT3("AscInitSetConfig: board %d error: init_state 0x%x, "
8449 "err_code 0x%x\n", boardp->id, asc_dvc->init_state,
8450 asc_dvc->err_code);
8451 }
8452
8453 return asc_dvc->err_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008454}
8455
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008456static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008457{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008458 ushort warn_code;
8459 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008460
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008461 iop_base = asc_dvc->iop_base;
8462 warn_code = 0;
8463 if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
8464 !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
8465 AscResetChipAndScsiBus(asc_dvc);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06008466 mdelay(asc_dvc->scsi_reset_wait * 1000); /* XXX: msleep? */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008467 }
8468 asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
8469 if (asc_dvc->err_code != 0)
8470 return (UW_ERR);
8471 if (!AscFindSignature(asc_dvc->iop_base)) {
8472 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
8473 return (warn_code);
8474 }
8475 AscDisableInterrupt(iop_base);
8476 warn_code |= AscInitLram(asc_dvc);
8477 if (asc_dvc->err_code != 0)
8478 return (UW_ERR);
8479 ASC_DBG1(1, "AscInitAsc1000Driver: _asc_mcode_chksum 0x%lx\n",
8480 (ulong)_asc_mcode_chksum);
8481 if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf,
8482 _asc_mcode_size) != _asc_mcode_chksum) {
8483 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
8484 return (warn_code);
8485 }
8486 warn_code |= AscInitMicroCodeVar(asc_dvc);
8487 asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
8488 AscEnableInterrupt(iop_base);
8489 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008490}
8491
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008492static ushort __devinit AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008493{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008494 int i;
8495 PortAddr iop_base;
8496 ushort warn_code;
8497 uchar chip_version;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008498
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008499 iop_base = asc_dvc->iop_base;
8500 warn_code = 0;
8501 asc_dvc->err_code = 0;
8502 if ((asc_dvc->bus_type &
8503 (ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0) {
8504 asc_dvc->err_code |= ASC_IERR_NO_BUS_TYPE;
8505 }
8506 AscSetChipControl(iop_base, CC_HALT);
8507 AscSetChipStatus(iop_base, 0);
8508 asc_dvc->bug_fix_cntl = 0;
8509 asc_dvc->pci_fix_asyn_xfer = 0;
8510 asc_dvc->pci_fix_asyn_xfer_always = 0;
8511 /* asc_dvc->init_state initalized in AscInitGetConfig(). */
8512 asc_dvc->sdtr_done = 0;
8513 asc_dvc->cur_total_qng = 0;
8514 asc_dvc->is_in_int = 0;
8515 asc_dvc->in_critical_cnt = 0;
8516 asc_dvc->last_q_shortage = 0;
8517 asc_dvc->use_tagged_qng = 0;
8518 asc_dvc->no_scam = 0;
8519 asc_dvc->unit_not_ready = 0;
8520 asc_dvc->queue_full_or_busy = 0;
8521 asc_dvc->redo_scam = 0;
8522 asc_dvc->res2 = 0;
8523 asc_dvc->host_init_sdtr_index = 0;
8524 asc_dvc->cfg->can_tagged_qng = 0;
8525 asc_dvc->cfg->cmd_qng_enabled = 0;
8526 asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
8527 asc_dvc->init_sdtr = 0;
8528 asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG;
8529 asc_dvc->scsi_reset_wait = 3;
8530 asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET;
8531 asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
8532 asc_dvc->cfg->sdtr_enable = ASC_SCSI_WIDTH_BIT_SET;
8533 asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
8534 asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID;
8535 asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER;
8536 asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) |
8537 ASC_LIB_VERSION_MINOR;
8538 chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type);
8539 asc_dvc->cfg->chip_version = chip_version;
8540 asc_dvc->sdtr_period_tbl[0] = SYN_XFER_NS_0;
8541 asc_dvc->sdtr_period_tbl[1] = SYN_XFER_NS_1;
8542 asc_dvc->sdtr_period_tbl[2] = SYN_XFER_NS_2;
8543 asc_dvc->sdtr_period_tbl[3] = SYN_XFER_NS_3;
8544 asc_dvc->sdtr_period_tbl[4] = SYN_XFER_NS_4;
8545 asc_dvc->sdtr_period_tbl[5] = SYN_XFER_NS_5;
8546 asc_dvc->sdtr_period_tbl[6] = SYN_XFER_NS_6;
8547 asc_dvc->sdtr_period_tbl[7] = SYN_XFER_NS_7;
8548 asc_dvc->max_sdtr_index = 7;
8549 if ((asc_dvc->bus_type & ASC_IS_PCI) &&
8550 (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3150)) {
8551 asc_dvc->bus_type = ASC_IS_PCI_ULTRA;
8552 asc_dvc->sdtr_period_tbl[0] = SYN_ULTRA_XFER_NS_0;
8553 asc_dvc->sdtr_period_tbl[1] = SYN_ULTRA_XFER_NS_1;
8554 asc_dvc->sdtr_period_tbl[2] = SYN_ULTRA_XFER_NS_2;
8555 asc_dvc->sdtr_period_tbl[3] = SYN_ULTRA_XFER_NS_3;
8556 asc_dvc->sdtr_period_tbl[4] = SYN_ULTRA_XFER_NS_4;
8557 asc_dvc->sdtr_period_tbl[5] = SYN_ULTRA_XFER_NS_5;
8558 asc_dvc->sdtr_period_tbl[6] = SYN_ULTRA_XFER_NS_6;
8559 asc_dvc->sdtr_period_tbl[7] = SYN_ULTRA_XFER_NS_7;
8560 asc_dvc->sdtr_period_tbl[8] = SYN_ULTRA_XFER_NS_8;
8561 asc_dvc->sdtr_period_tbl[9] = SYN_ULTRA_XFER_NS_9;
8562 asc_dvc->sdtr_period_tbl[10] = SYN_ULTRA_XFER_NS_10;
8563 asc_dvc->sdtr_period_tbl[11] = SYN_ULTRA_XFER_NS_11;
8564 asc_dvc->sdtr_period_tbl[12] = SYN_ULTRA_XFER_NS_12;
8565 asc_dvc->sdtr_period_tbl[13] = SYN_ULTRA_XFER_NS_13;
8566 asc_dvc->sdtr_period_tbl[14] = SYN_ULTRA_XFER_NS_14;
8567 asc_dvc->sdtr_period_tbl[15] = SYN_ULTRA_XFER_NS_15;
8568 asc_dvc->max_sdtr_index = 15;
8569 if (chip_version == ASC_CHIP_VER_PCI_ULTRA_3150) {
8570 AscSetExtraControl(iop_base,
8571 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
8572 } else if (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3050) {
8573 AscSetExtraControl(iop_base,
8574 (SEC_ACTIVE_NEGATE |
8575 SEC_ENABLE_FILTER));
8576 }
8577 }
8578 if (asc_dvc->bus_type == ASC_IS_PCI) {
8579 AscSetExtraControl(iop_base,
8580 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
8581 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008582
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008583 asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008584#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008585 if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) {
Matthew Wilcox59fcf842007-07-26 11:54:15 -04008586 if (chip_version >= ASC_CHIP_MIN_VER_ISA_PNP) {
8587 AscSetChipIFC(iop_base, IFC_INIT_DEFAULT);
8588 asc_dvc->bus_type = ASC_IS_ISAPNP;
8589 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008590 asc_dvc->cfg->isa_dma_channel =
8591 (uchar)AscGetIsaDmaChannel(iop_base);
8592 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008593#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008594 for (i = 0; i <= ASC_MAX_TID; i++) {
8595 asc_dvc->cur_dvc_qng[i] = 0;
8596 asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG;
8597 asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q *)0L;
8598 asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q *)0L;
8599 asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG;
8600 }
8601 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008602}
8603
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008604static ushort __devinit AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008605{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008606 ASCEEP_CONFIG eep_config_buf;
8607 ASCEEP_CONFIG *eep_config;
8608 PortAddr iop_base;
8609 ushort chksum;
8610 ushort warn_code;
8611 ushort cfg_msw, cfg_lsw;
8612 int i;
8613 int write_eep = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008614
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008615 iop_base = asc_dvc->iop_base;
8616 warn_code = 0;
8617 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE);
8618 AscStopQueueExe(iop_base);
8619 if ((AscStopChip(iop_base) == FALSE) ||
8620 (AscGetChipScsiCtrl(iop_base) != 0)) {
8621 asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
8622 AscResetChipAndScsiBus(asc_dvc);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06008623 mdelay(asc_dvc->scsi_reset_wait * 1000); /* XXX: msleep? */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008624 }
8625 if (AscIsChipHalted(iop_base) == FALSE) {
8626 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
8627 return (warn_code);
8628 }
8629 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
8630 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
8631 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
8632 return (warn_code);
8633 }
8634 eep_config = (ASCEEP_CONFIG *)&eep_config_buf;
8635 cfg_msw = AscGetChipCfgMsw(iop_base);
8636 cfg_lsw = AscGetChipCfgLsw(iop_base);
8637 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06008638 cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008639 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
8640 AscSetChipCfgMsw(iop_base, cfg_msw);
8641 }
8642 chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
8643 ASC_DBG1(1, "AscInitFromEEP: chksum 0x%x\n", chksum);
8644 if (chksum == 0) {
8645 chksum = 0xaa55;
8646 }
8647 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
8648 warn_code |= ASC_WARN_AUTO_CONFIG;
8649 if (asc_dvc->cfg->chip_version == 3) {
8650 if (eep_config->cfg_lsw != cfg_lsw) {
8651 warn_code |= ASC_WARN_EEPROM_RECOVER;
8652 eep_config->cfg_lsw =
8653 AscGetChipCfgLsw(iop_base);
8654 }
8655 if (eep_config->cfg_msw != cfg_msw) {
8656 warn_code |= ASC_WARN_EEPROM_RECOVER;
8657 eep_config->cfg_msw =
8658 AscGetChipCfgMsw(iop_base);
8659 }
8660 }
8661 }
8662 eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
8663 eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
8664 ASC_DBG1(1, "AscInitFromEEP: eep_config->chksum 0x%x\n",
8665 eep_config->chksum);
8666 if (chksum != eep_config->chksum) {
8667 if (AscGetChipVersion(iop_base, asc_dvc->bus_type) ==
8668 ASC_CHIP_VER_PCI_ULTRA_3050) {
8669 ASC_DBG(1,
8670 "AscInitFromEEP: chksum error ignored; EEPROM-less board\n");
8671 eep_config->init_sdtr = 0xFF;
8672 eep_config->disc_enable = 0xFF;
8673 eep_config->start_motor = 0xFF;
8674 eep_config->use_cmd_qng = 0;
8675 eep_config->max_total_qng = 0xF0;
8676 eep_config->max_tag_qng = 0x20;
8677 eep_config->cntl = 0xBFFF;
8678 ASC_EEP_SET_CHIP_ID(eep_config, 7);
8679 eep_config->no_scam = 0;
8680 eep_config->adapter_info[0] = 0;
8681 eep_config->adapter_info[1] = 0;
8682 eep_config->adapter_info[2] = 0;
8683 eep_config->adapter_info[3] = 0;
8684 eep_config->adapter_info[4] = 0;
8685 /* Indicate EEPROM-less board. */
8686 eep_config->adapter_info[5] = 0xBB;
8687 } else {
8688 ASC_PRINT
8689 ("AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n");
8690 write_eep = 1;
8691 warn_code |= ASC_WARN_EEPROM_CHKSUM;
8692 }
8693 }
8694 asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr;
8695 asc_dvc->cfg->disc_enable = eep_config->disc_enable;
8696 asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
8697 asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config);
8698 asc_dvc->start_motor = eep_config->start_motor;
8699 asc_dvc->dvc_cntl = eep_config->cntl;
8700 asc_dvc->no_scam = eep_config->no_scam;
8701 asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0];
8702 asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1];
8703 asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2];
8704 asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3];
8705 asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4];
8706 asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5];
8707 if (!AscTestExternalLram(asc_dvc)) {
8708 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) ==
8709 ASC_IS_PCI_ULTRA)) {
8710 eep_config->max_total_qng =
8711 ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
8712 eep_config->max_tag_qng =
8713 ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG;
8714 } else {
8715 eep_config->cfg_msw |= 0x0800;
8716 cfg_msw |= 0x0800;
8717 AscSetChipCfgMsw(iop_base, cfg_msw);
8718 eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
8719 eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG;
8720 }
8721 } else {
8722 }
8723 if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) {
8724 eep_config->max_total_qng = ASC_MIN_TOTAL_QNG;
8725 }
8726 if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) {
8727 eep_config->max_total_qng = ASC_MAX_TOTAL_QNG;
8728 }
8729 if (eep_config->max_tag_qng > eep_config->max_total_qng) {
8730 eep_config->max_tag_qng = eep_config->max_total_qng;
8731 }
8732 if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) {
8733 eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC;
8734 }
8735 asc_dvc->max_total_qng = eep_config->max_total_qng;
8736 if ((eep_config->use_cmd_qng & eep_config->disc_enable) !=
8737 eep_config->use_cmd_qng) {
8738 eep_config->disc_enable = eep_config->use_cmd_qng;
8739 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
8740 }
8741 if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
8742 asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
8743 }
8744 ASC_EEP_SET_CHIP_ID(eep_config,
8745 ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID);
8746 asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config);
8747 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) &&
8748 !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
8749 asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
8750 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008751
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008752 for (i = 0; i <= ASC_MAX_TID; i++) {
8753 asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
8754 asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
8755 asc_dvc->cfg->sdtr_period_offset[i] =
8756 (uchar)(ASC_DEF_SDTR_OFFSET |
8757 (asc_dvc->host_init_sdtr_index << 4));
8758 }
8759 eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
8760 if (write_eep) {
8761 if ((i =
8762 AscSetEEPConfig(iop_base, eep_config,
8763 asc_dvc->bus_type)) != 0) {
8764 ASC_PRINT1
8765 ("AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n",
8766 i);
8767 } else {
8768 ASC_PRINT
8769 ("AscInitFromEEP: Successfully re-wrote EEPROM.\n");
8770 }
8771 }
8772 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008773}
8774
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008775static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008776{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008777 int i;
8778 ushort warn_code;
8779 PortAddr iop_base;
8780 ASC_PADDR phy_addr;
8781 ASC_DCNT phy_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008782
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008783 iop_base = asc_dvc->iop_base;
8784 warn_code = 0;
8785 for (i = 0; i <= ASC_MAX_TID; i++) {
8786 AscPutMCodeInitSDTRAtID(iop_base, i,
8787 asc_dvc->cfg->sdtr_period_offset[i]
8788 );
8789 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008790
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008791 AscInitQLinkVar(asc_dvc);
8792 AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
8793 asc_dvc->cfg->disc_enable);
8794 AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
8795 ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008796
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008797 /* Align overrun buffer on an 8 byte boundary. */
8798 phy_addr = virt_to_bus(asc_dvc->cfg->overrun_buf);
8799 phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7);
8800 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
8801 (uchar *)&phy_addr, 1);
8802 phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE - 8);
8803 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D,
8804 (uchar *)&phy_size, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008805
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008806 asc_dvc->cfg->mcode_date =
8807 AscReadLramWord(iop_base, (ushort)ASCV_MC_DATE_W);
8808 asc_dvc->cfg->mcode_version =
8809 AscReadLramWord(iop_base, (ushort)ASCV_MC_VER_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008810
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008811 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
8812 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
8813 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
8814 return (warn_code);
8815 }
8816 if (AscStartChip(iop_base) != 1) {
8817 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
8818 return (warn_code);
8819 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008820
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008821 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008822}
8823
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008824static int __devinit AscTestExternalLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008825{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008826 PortAddr iop_base;
8827 ushort q_addr;
8828 ushort saved_word;
8829 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008830
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008831 iop_base = asc_dvc->iop_base;
8832 sta = 0;
8833 q_addr = ASC_QNO_TO_QADDR(241);
8834 saved_word = AscReadLramWord(iop_base, q_addr);
8835 AscSetChipLramAddr(iop_base, q_addr);
8836 AscSetChipLramData(iop_base, 0x55AA);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06008837 mdelay(10);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008838 AscSetChipLramAddr(iop_base, q_addr);
8839 if (AscGetChipLramData(iop_base) == 0x55AA) {
8840 sta = 1;
8841 AscWriteLramWord(iop_base, q_addr, saved_word);
8842 }
8843 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008844}
8845
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008846static int __devinit AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008847{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008848 uchar read_back;
8849 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008850
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008851 retry = 0;
8852 while (TRUE) {
8853 AscSetChipEEPCmd(iop_base, cmd_reg);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06008854 mdelay(1);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008855 read_back = AscGetChipEEPCmd(iop_base);
8856 if (read_back == cmd_reg) {
8857 return (1);
8858 }
8859 if (retry++ > ASC_EEP_MAX_RETRY) {
8860 return (0);
8861 }
8862 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008863}
8864
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008865static int __devinit AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008866{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008867 ushort read_back;
8868 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008869
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008870 retry = 0;
8871 while (TRUE) {
8872 AscSetChipEEPData(iop_base, data_reg);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06008873 mdelay(1);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008874 read_back = AscGetChipEEPData(iop_base);
8875 if (read_back == data_reg) {
8876 return (1);
8877 }
8878 if (retry++ > ASC_EEP_MAX_RETRY) {
8879 return (0);
8880 }
8881 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008882}
8883
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008884static void __devinit AscWaitEEPRead(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008885{
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06008886 mdelay(1);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008887 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008888}
8889
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008890static void __devinit AscWaitEEPWrite(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008891{
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06008892 mdelay(20);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008893 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008894}
8895
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008896static ushort __devinit AscReadEEPWord(PortAddr iop_base, uchar addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008897{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008898 ushort read_wval;
8899 uchar cmd_reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008900
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008901 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
8902 AscWaitEEPRead();
8903 cmd_reg = addr | ASC_EEP_CMD_READ;
8904 AscWriteEEPCmdReg(iop_base, cmd_reg);
8905 AscWaitEEPRead();
8906 read_wval = AscGetChipEEPData(iop_base);
8907 AscWaitEEPRead();
8908 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008909}
8910
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008911static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008912AscWriteEEPWord(PortAddr iop_base, uchar addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008913{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008914 ushort read_wval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008915
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008916 read_wval = AscReadEEPWord(iop_base, addr);
8917 if (read_wval != word_val) {
8918 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE);
8919 AscWaitEEPRead();
8920 AscWriteEEPDataReg(iop_base, word_val);
8921 AscWaitEEPRead();
8922 AscWriteEEPCmdReg(iop_base,
8923 (uchar)((uchar)ASC_EEP_CMD_WRITE | addr));
8924 AscWaitEEPWrite();
8925 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
8926 AscWaitEEPRead();
8927 return (AscReadEEPWord(iop_base, addr));
8928 }
8929 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008930}
8931
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008932static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008933AscGetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008934{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008935 ushort wval;
8936 ushort sum;
8937 ushort *wbuf;
8938 int cfg_beg;
8939 int cfg_end;
8940 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
8941 int s_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008942
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008943 wbuf = (ushort *)cfg_buf;
8944 sum = 0;
8945 /* Read two config words; Byte-swapping done by AscReadEEPWord(). */
8946 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
8947 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
8948 sum += *wbuf;
8949 }
8950 if (bus_type & ASC_IS_VL) {
8951 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
8952 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
8953 } else {
8954 cfg_beg = ASC_EEP_DVC_CFG_BEG;
8955 cfg_end = ASC_EEP_MAX_DVC_ADDR;
8956 }
8957 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
8958 wval = AscReadEEPWord(iop_base, (uchar)s_addr);
8959 if (s_addr <= uchar_end_in_config) {
8960 /*
8961 * Swap all char fields - must unswap bytes already swapped
8962 * by AscReadEEPWord().
8963 */
8964 *wbuf = le16_to_cpu(wval);
8965 } else {
8966 /* Don't swap word field at the end - cntl field. */
8967 *wbuf = wval;
8968 }
8969 sum += wval; /* Checksum treats all EEPROM data as words. */
8970 }
8971 /*
8972 * Read the checksum word which will be compared against 'sum'
8973 * by the caller. Word field already swapped.
8974 */
8975 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
8976 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008977}
8978
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008979static int __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008980AscSetEEPConfigOnce(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008981{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008982 int n_error;
8983 ushort *wbuf;
8984 ushort word;
8985 ushort sum;
8986 int s_addr;
8987 int cfg_beg;
8988 int cfg_end;
8989 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008990
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008991 wbuf = (ushort *)cfg_buf;
8992 n_error = 0;
8993 sum = 0;
8994 /* Write two config words; AscWriteEEPWord() will swap bytes. */
8995 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
8996 sum += *wbuf;
8997 if (*wbuf != AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
8998 n_error++;
8999 }
9000 }
9001 if (bus_type & ASC_IS_VL) {
9002 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
9003 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
9004 } else {
9005 cfg_beg = ASC_EEP_DVC_CFG_BEG;
9006 cfg_end = ASC_EEP_MAX_DVC_ADDR;
9007 }
9008 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
9009 if (s_addr <= uchar_end_in_config) {
9010 /*
9011 * This is a char field. Swap char fields before they are
9012 * swapped again by AscWriteEEPWord().
9013 */
9014 word = cpu_to_le16(*wbuf);
9015 if (word !=
9016 AscWriteEEPWord(iop_base, (uchar)s_addr, word)) {
9017 n_error++;
9018 }
9019 } else {
9020 /* Don't swap word field at the end - cntl field. */
9021 if (*wbuf !=
9022 AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
9023 n_error++;
9024 }
9025 }
9026 sum += *wbuf; /* Checksum calculated from word values. */
9027 }
9028 /* Write checksum word. It will be swapped by AscWriteEEPWord(). */
9029 *wbuf = sum;
9030 if (sum != AscWriteEEPWord(iop_base, (uchar)s_addr, sum)) {
9031 n_error++;
9032 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009033
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009034 /* Read EEPROM back again. */
9035 wbuf = (ushort *)cfg_buf;
9036 /*
9037 * Read two config words; Byte-swapping done by AscReadEEPWord().
9038 */
9039 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
9040 if (*wbuf != AscReadEEPWord(iop_base, (uchar)s_addr)) {
9041 n_error++;
9042 }
9043 }
9044 if (bus_type & ASC_IS_VL) {
9045 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
9046 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
9047 } else {
9048 cfg_beg = ASC_EEP_DVC_CFG_BEG;
9049 cfg_end = ASC_EEP_MAX_DVC_ADDR;
9050 }
9051 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
9052 if (s_addr <= uchar_end_in_config) {
9053 /*
9054 * Swap all char fields. Must unswap bytes already swapped
9055 * by AscReadEEPWord().
9056 */
9057 word =
9058 le16_to_cpu(AscReadEEPWord
9059 (iop_base, (uchar)s_addr));
9060 } else {
9061 /* Don't swap word field at the end - cntl field. */
9062 word = AscReadEEPWord(iop_base, (uchar)s_addr);
9063 }
9064 if (*wbuf != word) {
9065 n_error++;
9066 }
9067 }
9068 /* Read checksum; Byte swapping not needed. */
9069 if (AscReadEEPWord(iop_base, (uchar)s_addr) != sum) {
9070 n_error++;
9071 }
9072 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009073}
9074
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009075static int __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009076AscSetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009077{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009078 int retry;
9079 int n_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009080
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009081 retry = 0;
9082 while (TRUE) {
9083 if ((n_error = AscSetEEPConfigOnce(iop_base, cfg_buf,
9084 bus_type)) == 0) {
9085 break;
9086 }
9087 if (++retry > ASC_EEP_MAX_RETRY) {
9088 break;
9089 }
9090 }
9091 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009092}
9093
Matthew Wilcox47d853c2007-07-26 11:41:33 -04009094static void AscAsyncFix(ASC_DVC_VAR *asc_dvc, struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009095{
Matthew Wilcox47d853c2007-07-26 11:41:33 -04009096 char type = sdev->type;
9097 ASC_SCSI_BIT_ID_TYPE tid_bits = 1 << sdev->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009098
Matthew Wilcox95c9f162007-09-09 08:56:39 -06009099 if (!(asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN))
9100 return;
9101 if (asc_dvc->init_sdtr & tid_bits)
9102 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009103
Matthew Wilcox95c9f162007-09-09 08:56:39 -06009104 if ((type == TYPE_ROM) && (strncmp(sdev->vendor, "HP ", 3) == 0))
9105 asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
9106
9107 asc_dvc->pci_fix_asyn_xfer |= tid_bits;
9108 if ((type == TYPE_PROCESSOR) || (type == TYPE_SCANNER) ||
9109 (type == TYPE_ROM) || (type == TYPE_TAPE))
9110 asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
9111
9112 if (asc_dvc->pci_fix_asyn_xfer & tid_bits)
9113 AscSetRunChipSynRegAtID(asc_dvc->iop_base, sdev->id,
Matthew Wilcox47d853c2007-07-26 11:41:33 -04009114 ASYN_SDTR_DATA_FIX_PCI_REV_AB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009115}
9116
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009117static uchar AscReadLramByte(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009118{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009119 uchar byte_data;
9120 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009121
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009122 if (isodd_word(addr)) {
9123 AscSetChipLramAddr(iop_base, addr - 1);
9124 word_data = AscGetChipLramData(iop_base);
9125 byte_data = (uchar)((word_data >> 8) & 0xFF);
9126 } else {
9127 AscSetChipLramAddr(iop_base, addr);
9128 word_data = AscGetChipLramData(iop_base);
9129 byte_data = (uchar)(word_data & 0xFF);
9130 }
9131 return (byte_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009132}
Linus Torvalds1da177e2005-04-16 15:20:36 -07009133
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009134static ushort AscReadLramWord(PortAddr iop_base, ushort addr)
9135{
9136 ushort word_data;
9137
9138 AscSetChipLramAddr(iop_base, addr);
9139 word_data = AscGetChipLramData(iop_base);
9140 return (word_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009141}
9142
9143#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009144static ASC_DCNT AscReadLramDWord(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009145{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009146 ushort val_low, val_high;
9147 ASC_DCNT dword_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009148
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009149 AscSetChipLramAddr(iop_base, addr);
9150 val_low = AscGetChipLramData(iop_base);
9151 val_high = AscGetChipLramData(iop_base);
9152 dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low;
9153 return (dword_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009154}
9155#endif /* CC_VERY_LONG_SG_LIST */
9156
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009157static void AscWriteLramWord(PortAddr iop_base, ushort addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009158{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009159 AscSetChipLramAddr(iop_base, addr);
9160 AscSetChipLramData(iop_base, word_val);
9161 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009162}
9163
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009164static void AscWriteLramByte(PortAddr iop_base, ushort addr, uchar byte_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009165{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009166 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009167
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009168 if (isodd_word(addr)) {
9169 addr--;
9170 word_data = AscReadLramWord(iop_base, addr);
9171 word_data &= 0x00FF;
9172 word_data |= (((ushort)byte_val << 8) & 0xFF00);
9173 } else {
9174 word_data = AscReadLramWord(iop_base, addr);
9175 word_data &= 0xFF00;
9176 word_data |= ((ushort)byte_val & 0x00FF);
9177 }
9178 AscWriteLramWord(iop_base, addr, word_data);
9179 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009180}
9181
9182/*
9183 * Copy 2 bytes to LRAM.
9184 *
9185 * The source data is assumed to be in little-endian order in memory
9186 * and is maintained in little-endian order when written to LRAM.
9187 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009188static void
9189AscMemWordCopyPtrToLram(PortAddr iop_base,
9190 ushort s_addr, uchar *s_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009191{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009192 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009193
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009194 AscSetChipLramAddr(iop_base, s_addr);
9195 for (i = 0; i < 2 * words; i += 2) {
9196 /*
9197 * On a little-endian system the second argument below
9198 * produces a little-endian ushort which is written to
9199 * LRAM in little-endian order. On a big-endian system
9200 * the second argument produces a big-endian ushort which
9201 * is "transparently" byte-swapped by outpw() and written
9202 * in little-endian order to LRAM.
9203 */
9204 outpw(iop_base + IOP_RAM_DATA,
9205 ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]);
9206 }
9207 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009208}
9209
9210/*
9211 * Copy 4 bytes to LRAM.
9212 *
9213 * The source data is assumed to be in little-endian order in memory
9214 * and is maintained in little-endian order when writen to LRAM.
9215 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009216static void
9217AscMemDWordCopyPtrToLram(PortAddr iop_base,
9218 ushort s_addr, uchar *s_buffer, int dwords)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009219{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009220 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009221
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009222 AscSetChipLramAddr(iop_base, s_addr);
9223 for (i = 0; i < 4 * dwords; i += 4) {
9224 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]); /* LSW */
9225 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 3] << 8) | s_buffer[i + 2]); /* MSW */
9226 }
9227 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009228}
9229
9230/*
9231 * Copy 2 bytes from LRAM.
9232 *
9233 * The source data is assumed to be in little-endian order in LRAM
9234 * and is maintained in little-endian order when written to memory.
9235 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009236static void
9237AscMemWordCopyPtrFromLram(PortAddr iop_base,
9238 ushort s_addr, uchar *d_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009239{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009240 int i;
9241 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009242
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009243 AscSetChipLramAddr(iop_base, s_addr);
9244 for (i = 0; i < 2 * words; i += 2) {
9245 word = inpw(iop_base + IOP_RAM_DATA);
9246 d_buffer[i] = word & 0xff;
9247 d_buffer[i + 1] = (word >> 8) & 0xff;
9248 }
9249 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009250}
9251
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009252static ASC_DCNT AscMemSumLramWord(PortAddr iop_base, ushort s_addr, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009253{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009254 ASC_DCNT sum;
9255 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009256
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009257 sum = 0L;
9258 for (i = 0; i < words; i++, s_addr += 2) {
9259 sum += AscReadLramWord(iop_base, s_addr);
9260 }
9261 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009262}
9263
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009264static void
9265AscMemWordSetLram(PortAddr iop_base, ushort s_addr, ushort set_wval, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009266{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009267 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009268
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009269 AscSetChipLramAddr(iop_base, s_addr);
9270 for (i = 0; i < words; i++) {
9271 AscSetChipLramData(iop_base, set_wval);
9272 }
9273 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009274}
9275
Linus Torvalds1da177e2005-04-16 15:20:36 -07009276/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009277static unsigned char _adv_asc3550_buf[] = {
9278 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x18, 0xe4, 0x00, 0xfc,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009279 0x01, 0x00, 0x48, 0xe4, 0xbe, 0x18, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00,
9280 0x00, 0xfa, 0xff, 0xff, 0x28, 0x0e, 0x9e, 0xe7, 0xff, 0x00, 0x82, 0xe7,
9281 0x00, 0xea, 0x00, 0xf6, 0x01, 0xe6, 0x09, 0xe7, 0x55, 0xf0, 0x01, 0xf6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009282 0x01, 0xfa, 0x08, 0x00, 0x03, 0x00, 0x04, 0x00, 0x18, 0xf4, 0x10, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009283 0x00, 0xec, 0x85, 0xf0, 0xbc, 0x00, 0xd5, 0xf0, 0x8e, 0x0c, 0x38, 0x54,
9284 0x00, 0xe6, 0x1e, 0xf0, 0x86, 0xf0, 0xb4, 0x00, 0x98, 0x57, 0xd0, 0x01,
9285 0x0c, 0x1c, 0x3e, 0x1c, 0x0c, 0x00, 0xbb, 0x00, 0xaa, 0x18, 0x02, 0x80,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009286 0x32, 0xf0, 0x01, 0xfc, 0x88, 0x0c, 0xc6, 0x12, 0x02, 0x13, 0x18, 0x40,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009287 0x00, 0x57, 0x01, 0xea, 0x3c, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12,
9288 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00, 0xc0, 0x00, 0x01, 0x01,
9289 0x3e, 0x01, 0xda, 0x0f, 0x22, 0x10, 0x08, 0x12, 0x02, 0x4a, 0xb9, 0x54,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009290 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x20, 0x00, 0x32, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009291 0x3e, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01,
9292 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01, 0x78, 0x01, 0x62, 0x0a,
9293 0x92, 0x0c, 0x2c, 0x10, 0x2e, 0x10, 0x06, 0x13, 0x4c, 0x1c, 0xbb, 0x55,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009294 0x3c, 0x56, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0xb1, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009295 0x03, 0xf7, 0x06, 0xf7, 0x03, 0xfc, 0x0f, 0x00, 0x40, 0x00, 0xbe, 0x00,
9296 0x00, 0x01, 0xb0, 0x08, 0x30, 0x13, 0x64, 0x15, 0x32, 0x1c, 0x38, 0x1c,
9297 0x4e, 0x1c, 0x10, 0x44, 0x02, 0x48, 0x00, 0x4c, 0x04, 0xea, 0x5d, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009298 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009299 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x4e, 0x0b, 0x1e, 0x0e, 0x0c, 0x10,
9300 0x0a, 0x12, 0x04, 0x13, 0x40, 0x13, 0x30, 0x1c, 0x00, 0x4e, 0xbd, 0x56,
9301 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0, 0x59, 0xf0, 0xa7, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009302 0xb8, 0xf0, 0x0e, 0xf7, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009303 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00,
9304 0xde, 0x03, 0x56, 0x0a, 0x14, 0x0e, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10,
9305 0x36, 0x10, 0x0a, 0x13, 0x12, 0x13, 0x52, 0x13, 0x10, 0x15, 0x14, 0x15,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009306 0xac, 0x16, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009307 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x83, 0x55,
9308 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0, 0x0c, 0xf0,
9309 0x5c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009310 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x1c, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009311 0x9e, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01,
9312 0x26, 0x01, 0x79, 0x01, 0x7a, 0x01, 0xc0, 0x01, 0xc2, 0x01, 0x7c, 0x02,
9313 0x5a, 0x03, 0xea, 0x04, 0xe8, 0x07, 0x68, 0x08, 0x69, 0x08, 0xba, 0x08,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009314 0xe9, 0x09, 0x06, 0x0b, 0x3a, 0x0e, 0x00, 0x10, 0x1a, 0x10, 0xed, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009315 0xf1, 0x10, 0x06, 0x12, 0x0c, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x82, 0x13,
9316 0x42, 0x14, 0xd6, 0x14, 0x8a, 0x15, 0xc6, 0x17, 0xd2, 0x17, 0x6b, 0x18,
9317 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0x48, 0x47,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009318 0x41, 0x48, 0x89, 0x48, 0x80, 0x4c, 0x00, 0x54, 0x44, 0x55, 0xe5, 0x55,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009319 0x14, 0x56, 0x77, 0x57, 0xbf, 0x57, 0x40, 0x5c, 0x06, 0x80, 0x08, 0x90,
9320 0x03, 0xa1, 0xfe, 0x9c, 0xf0, 0x29, 0x02, 0xfe, 0xb8, 0x0c, 0xff, 0x10,
9321 0x00, 0x00, 0xd0, 0xfe, 0xcc, 0x18, 0x00, 0xcf, 0xfe, 0x80, 0x01, 0xff,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009322 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009323 0x00, 0xfe, 0x57, 0x24, 0x00, 0xfe, 0x48, 0x00, 0x4f, 0xff, 0x04, 0x00,
9324 0x00, 0x10, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x08,
9325 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x0f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009326 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009327 0xfe, 0x04, 0xf7, 0xcf, 0x2a, 0x67, 0x0b, 0x01, 0xfe, 0xce, 0x0e, 0xfe,
9328 0x04, 0xf7, 0xcf, 0x67, 0x0b, 0x3c, 0x2a, 0xfe, 0x3d, 0xf0, 0xfe, 0x02,
9329 0x02, 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x91, 0xf0, 0xfe, 0xf0, 0x01, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009330 0x90, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, 0x8f, 0xf0, 0x9c, 0x05, 0x51, 0x3b,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009331 0x02, 0xfe, 0xd4, 0x0c, 0x01, 0xfe, 0x44, 0x0d, 0xfe, 0xdd, 0x12, 0xfe,
9332 0xfc, 0x10, 0xfe, 0x28, 0x1c, 0x05, 0xfe, 0xa6, 0x00, 0xfe, 0xd3, 0x12,
9333 0x47, 0x18, 0xfe, 0xa6, 0x00, 0xb5, 0xfe, 0x48, 0xf0, 0xfe, 0x86, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009334 0xfe, 0x49, 0xf0, 0xfe, 0xa0, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xbe, 0x02,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009335 0xfe, 0x46, 0xf0, 0xfe, 0x50, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x56, 0x02,
9336 0xfe, 0x43, 0xf0, 0xfe, 0x44, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x48, 0x02,
9337 0xfe, 0x45, 0xf0, 0xfe, 0x4c, 0x02, 0x17, 0x0b, 0xa0, 0x17, 0x06, 0x18,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009338 0x96, 0x02, 0x29, 0xfe, 0x00, 0x1c, 0xde, 0xfe, 0x02, 0x1c, 0xdd, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009339 0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0xfe, 0x20, 0x17, 0xfe, 0xe7, 0x10,
9340 0xfe, 0x06, 0xfc, 0xc7, 0x0a, 0x6b, 0x01, 0x9e, 0x02, 0x29, 0x14, 0x4d,
9341 0x37, 0x97, 0x01, 0xfe, 0x64, 0x0f, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xbd,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009342 0x10, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009343 0x58, 0x1c, 0x17, 0x06, 0x18, 0x96, 0x2a, 0x25, 0x29, 0xfe, 0x3d, 0xf0,
9344 0xfe, 0x02, 0x02, 0x21, 0xfe, 0x94, 0x02, 0xfe, 0x5a, 0x1c, 0xea, 0xfe,
9345 0x14, 0x1c, 0x14, 0xfe, 0x30, 0x00, 0x37, 0x97, 0x01, 0xfe, 0x54, 0x0f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009346 0x17, 0x06, 0x18, 0x96, 0x02, 0xd0, 0x1e, 0x20, 0x07, 0x10, 0x34, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009347 0x69, 0x10, 0x17, 0x06, 0x18, 0x96, 0xfe, 0x04, 0xec, 0x20, 0x46, 0x3d,
9348 0x12, 0x20, 0xfe, 0x05, 0xf6, 0xc7, 0x01, 0xfe, 0x52, 0x16, 0x09, 0x4a,
9349 0x4c, 0x35, 0x11, 0x2d, 0x3c, 0x8a, 0x01, 0xe6, 0x02, 0x29, 0x0a, 0x40,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009350 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x01, 0x6f, 0xfe, 0x18, 0x10, 0xfe, 0x41,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009351 0x58, 0x0a, 0x99, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x64, 0xfe, 0x0c, 0x03,
9352 0x01, 0xe6, 0x02, 0x29, 0x2a, 0x46, 0xfe, 0x02, 0xe8, 0x27, 0xf8, 0xfe,
9353 0x9e, 0x43, 0xf7, 0xfe, 0x27, 0xf0, 0xfe, 0xdc, 0x01, 0xfe, 0x07, 0x4b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009354 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x40, 0x1c, 0x25, 0xd2, 0xfe, 0x26, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009355 0xfe, 0x56, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x44, 0x03, 0xfe, 0x11, 0xf0,
9356 0x9c, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x64, 0x03, 0xeb, 0x0f,
9357 0xfe, 0x11, 0x00, 0x02, 0x5a, 0x2a, 0xfe, 0x48, 0x1c, 0xeb, 0x09, 0x04,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009358 0x1d, 0xfe, 0x18, 0x13, 0x23, 0x1e, 0x98, 0xac, 0x12, 0x98, 0x0a, 0x40,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009359 0x01, 0x0e, 0xac, 0x75, 0x01, 0xfe, 0xbc, 0x15, 0x11, 0xca, 0x25, 0xd2,
9360 0xfe, 0x01, 0xf0, 0xd2, 0xfe, 0x82, 0xf0, 0xfe, 0x92, 0x03, 0xec, 0x11,
9361 0xfe, 0xe4, 0x00, 0x65, 0xfe, 0xa4, 0x03, 0x25, 0x32, 0x1f, 0xfe, 0xb4,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009362 0x03, 0x01, 0x43, 0xfe, 0x06, 0xf0, 0xfe, 0xc4, 0x03, 0x8d, 0x81, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009363 0x0a, 0xf0, 0xfe, 0x7a, 0x06, 0x02, 0x22, 0x05, 0x6b, 0x28, 0x16, 0xfe,
9364 0xf6, 0x04, 0x14, 0x2c, 0x01, 0x33, 0x8f, 0xfe, 0x66, 0x02, 0x02, 0xd1,
9365 0xeb, 0x2a, 0x67, 0x1a, 0xfe, 0x67, 0x1b, 0xf8, 0xf7, 0xfe, 0x48, 0x1c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009366 0x70, 0x01, 0x6e, 0x87, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x16, 0xd3,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009367 0x0a, 0xca, 0x01, 0x0e, 0x74, 0x60, 0x59, 0x76, 0x27, 0x05, 0x6b, 0x28,
9368 0xfe, 0x10, 0x12, 0x14, 0x2c, 0x01, 0x33, 0x8f, 0xfe, 0x66, 0x02, 0x02,
9369 0xd1, 0xbc, 0x7d, 0xbd, 0x7f, 0x25, 0x22, 0x65, 0xfe, 0x3c, 0x04, 0x1f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009370 0xfe, 0x38, 0x04, 0x68, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009371 0x12, 0x2b, 0xff, 0x02, 0x00, 0x10, 0x01, 0x08, 0x1f, 0xfe, 0xe0, 0x04,
9372 0x2b, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd5, 0xfe, 0x4c, 0x44, 0xfe,
9373 0x4c, 0x12, 0x60, 0xfe, 0x44, 0x48, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009374 0xd3, 0x46, 0x76, 0x27, 0xfa, 0xef, 0xfe, 0x62, 0x13, 0x09, 0x04, 0x1d,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009375 0xfe, 0x2a, 0x13, 0x2f, 0x07, 0x7e, 0xa5, 0xfe, 0x20, 0x10, 0x13, 0x2c,
9376 0xfe, 0x4c, 0x54, 0x64, 0xd3, 0xfa, 0xef, 0x86, 0x09, 0x04, 0x1d, 0xfe,
9377 0x08, 0x13, 0x2f, 0x07, 0x7e, 0x6e, 0x09, 0x04, 0x1d, 0xfe, 0x1c, 0x12,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009378 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009379 0x70, 0x0c, 0x02, 0x22, 0x2b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90,
9380 0xf9, 0x03, 0x14, 0x92, 0x01, 0x33, 0x02, 0x29, 0xfe, 0x42, 0x5b, 0x67,
9381 0x1a, 0xfe, 0x46, 0x59, 0xf8, 0xf7, 0xfe, 0x87, 0x80, 0xfe, 0x31, 0xe4,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009382 0x4f, 0x09, 0x04, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x1a,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009383 0xfe, 0x70, 0x12, 0x49, 0x04, 0x06, 0xfe, 0x60, 0x13, 0x05, 0xfe, 0xa2,
9384 0x00, 0x28, 0x16, 0xfe, 0x80, 0x05, 0xfe, 0x31, 0xe4, 0x6a, 0x49, 0x04,
9385 0x0b, 0xfe, 0x4a, 0x13, 0x05, 0xfe, 0xa0, 0x00, 0x28, 0xfe, 0x42, 0x12,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009386 0x5e, 0x01, 0x08, 0x25, 0x32, 0xf1, 0x01, 0x08, 0x26, 0xfe, 0x98, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009387 0x11, 0xfe, 0xe3, 0x00, 0x23, 0x49, 0xfe, 0x4a, 0xf0, 0xfe, 0x6a, 0x05,
9388 0xfe, 0x49, 0xf0, 0xfe, 0x64, 0x05, 0x83, 0x24, 0xfe, 0x21, 0x00, 0xa1,
9389 0x24, 0xfe, 0x22, 0x00, 0xa0, 0x24, 0x4c, 0xfe, 0x09, 0x48, 0x01, 0x08,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009390 0x26, 0xfe, 0x98, 0x05, 0xfe, 0xe2, 0x08, 0x49, 0x04, 0xc5, 0x3b, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009391 0x86, 0x24, 0x06, 0x12, 0xcc, 0x37, 0xfe, 0x27, 0x01, 0x09, 0x04, 0x1d,
9392 0xfe, 0x22, 0x12, 0x47, 0x01, 0xa7, 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b,
9393 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c, 0x02, 0x22, 0x05, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009394 0x9c, 0x00, 0x28, 0xfe, 0x3e, 0x12, 0x05, 0x50, 0x28, 0xfe, 0x36, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009395 0x47, 0x01, 0xa7, 0x26, 0xfe, 0x08, 0x06, 0x0a, 0x06, 0x49, 0x04, 0x19,
9396 0xfe, 0x02, 0x12, 0x5f, 0x01, 0xfe, 0xaa, 0x14, 0x1f, 0xfe, 0xfe, 0x05,
9397 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x50, 0xb4, 0x0c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009398 0x50, 0x05, 0xc6, 0x28, 0xfe, 0x62, 0x12, 0x05, 0x3f, 0x28, 0xfe, 0x5a,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009399 0x13, 0x01, 0xfe, 0x14, 0x18, 0x01, 0xfe, 0x66, 0x18, 0xfe, 0x43, 0x48,
9400 0xb7, 0x19, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0x1c, 0x3d,
9401 0x85, 0xb7, 0x69, 0x47, 0x01, 0xa7, 0x26, 0xfe, 0x72, 0x06, 0x49, 0x04,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009402 0x1b, 0xdf, 0x89, 0x0a, 0x4d, 0x01, 0xfe, 0xd8, 0x14, 0x1f, 0xfe, 0x68,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009403 0x06, 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x3f, 0xb4,
9404 0x0c, 0x3f, 0x17, 0x06, 0x01, 0xa7, 0xec, 0x72, 0x70, 0x01, 0x6e, 0x87,
9405 0x11, 0xfe, 0xe2, 0x00, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009406 0xa6, 0x06, 0x8c, 0xfe, 0x5c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, 0x64, 0x07,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009407 0x8d, 0x81, 0x02, 0x22, 0x09, 0x04, 0x0b, 0xfe, 0x2e, 0x12, 0x15, 0x1a,
9408 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00,
9409 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x15, 0x00, 0x02, 0xfe, 0x32,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009410 0x08, 0x61, 0x04, 0x1b, 0xfe, 0x38, 0x12, 0x09, 0x04, 0x1b, 0x6e, 0x15,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009411 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01,
9412 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x06, 0x01, 0x08, 0x15, 0x00, 0x02,
9413 0xd9, 0x66, 0x4c, 0xfe, 0x3a, 0x55, 0x5f, 0xfe, 0x9a, 0x81, 0x4b, 0x1d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009414 0xba, 0xfe, 0x32, 0x07, 0x0a, 0x1d, 0xfe, 0x09, 0x6f, 0xaf, 0xfe, 0xca,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009415 0x45, 0xfe, 0x32, 0x12, 0x62, 0x2c, 0x85, 0x66, 0x7b, 0x01, 0x08, 0x25,
9416 0x32, 0xfe, 0x0a, 0xf0, 0xfe, 0x32, 0x07, 0x8d, 0x81, 0x8c, 0xfe, 0x5c,
9417 0x07, 0x02, 0x22, 0x01, 0x43, 0x02, 0xfe, 0x8a, 0x06, 0x15, 0x19, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009418 0xfe, 0x8a, 0x06, 0xfe, 0x9c, 0xf7, 0xd4, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009419 0x90, 0x77, 0xfe, 0xca, 0x07, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x4a, 0x6a,
9420 0x35, 0x1e, 0x20, 0x07, 0x10, 0xfe, 0x0e, 0x12, 0x74, 0xfe, 0x80, 0x80,
9421 0x37, 0x20, 0x63, 0x27, 0xfe, 0x06, 0x10, 0xfe, 0x83, 0xe7, 0xc4, 0xa1,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009422 0xfe, 0x03, 0x40, 0x09, 0x4a, 0x4f, 0x35, 0x01, 0xa8, 0xad, 0xfe, 0x1f,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009423 0x40, 0x12, 0x58, 0x01, 0xa5, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe,
9424 0x44, 0x51, 0xfe, 0xc6, 0x51, 0x83, 0xfb, 0xfe, 0x8a, 0x90, 0x0c, 0x52,
9425 0x18, 0x53, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009426 0xc2, 0x50, 0x0c, 0x39, 0x18, 0x3a, 0xfe, 0x4a, 0x10, 0x09, 0x04, 0x6a,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009427 0xfe, 0x2a, 0x12, 0xfe, 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x54, 0x18,
9428 0x55, 0x09, 0x04, 0x4f, 0x85, 0x01, 0xa8, 0xfe, 0x1f, 0x80, 0x12, 0x58,
9429 0xfe, 0x44, 0x90, 0xfe, 0xc6, 0x90, 0x0c, 0x56, 0x18, 0x57, 0xfb, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009430 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009431 0x0c, 0x39, 0x18, 0x3a, 0x0c, 0x38, 0x18, 0x4e, 0x09, 0x4a, 0x19, 0x35,
9432 0x2a, 0x13, 0xfe, 0x4e, 0x11, 0x65, 0xfe, 0x48, 0x08, 0xfe, 0x9e, 0xf0,
9433 0xfe, 0x5c, 0x08, 0xb1, 0x16, 0x32, 0x2a, 0x73, 0xdd, 0xb8, 0xfe, 0x80,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009434 0x08, 0xb9, 0xfe, 0x9e, 0x08, 0x8c, 0xfe, 0x74, 0x08, 0xfe, 0x06, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009435 0xfe, 0x7a, 0x08, 0x8d, 0x81, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xc9, 0x10,
9436 0x15, 0x19, 0xfe, 0xc9, 0x10, 0x61, 0x04, 0x06, 0xfe, 0x10, 0x12, 0x61,
9437 0x04, 0x0b, 0x45, 0x09, 0x04, 0x0b, 0xfe, 0x68, 0x12, 0xfe, 0x2e, 0x1c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009438 0x02, 0xfe, 0x24, 0x0a, 0x61, 0x04, 0x06, 0x45, 0x61, 0x04, 0x0b, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009439 0x52, 0x12, 0xfe, 0x2c, 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x1e, 0x09, 0xfe,
9440 0xac, 0xf0, 0xfe, 0xbe, 0x08, 0xfe, 0x8a, 0x10, 0xaa, 0xfe, 0xf3, 0x10,
9441 0xfe, 0xad, 0xf0, 0xfe, 0xca, 0x08, 0x02, 0xfe, 0x24, 0x0a, 0xab, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009442 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0x9d, 0xe9, 0x1c, 0xfe, 0x00, 0xfe, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009443 0x1c, 0x12, 0xb5, 0xfe, 0xd2, 0xf0, 0x9d, 0xfe, 0x76, 0x18, 0x1c, 0x1a,
9444 0x16, 0x9d, 0x05, 0xcb, 0x1c, 0x06, 0x16, 0x9d, 0xb8, 0x6d, 0xb9, 0x6d,
9445 0xaa, 0xab, 0xfe, 0xb1, 0x10, 0x70, 0x5e, 0x2b, 0x14, 0x92, 0x01, 0x33,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009446 0x0f, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x5a, 0x0f, 0x7c, 0x02, 0x5a,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009447 0xfe, 0x74, 0x18, 0x1c, 0xfe, 0x00, 0xf8, 0x16, 0x6d, 0x67, 0x1b, 0x01,
9448 0xfe, 0x44, 0x0d, 0x3b, 0x01, 0xe6, 0x1e, 0x27, 0x74, 0x67, 0x1a, 0x02,
9449 0x6d, 0x09, 0x04, 0x0b, 0x21, 0xfe, 0x06, 0x0a, 0x09, 0x04, 0x6a, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009450 0x82, 0x12, 0x09, 0x04, 0x19, 0xfe, 0x66, 0x13, 0x1e, 0x58, 0xac, 0xfc,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009451 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91,
9452 0xfe, 0x86, 0x91, 0x63, 0x27, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x77,
9453 0xd7, 0x05, 0x54, 0x31, 0x55, 0x0c, 0x7b, 0x18, 0x7c, 0xbe, 0x54, 0xbf,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009454 0x55, 0x01, 0xa8, 0xad, 0x63, 0x27, 0x12, 0x58, 0xc0, 0x38, 0xc1, 0x4e,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009455 0x79, 0x56, 0x68, 0x57, 0xf4, 0xf5, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05,
9456 0xfa, 0x4e, 0x01, 0xa5, 0xa2, 0x23, 0x0c, 0x7b, 0x0c, 0x7c, 0x79, 0x56,
9457 0x68, 0x57, 0xfe, 0x12, 0x10, 0x09, 0x04, 0x19, 0x16, 0xd7, 0x79, 0x39,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009458 0x68, 0x3a, 0x09, 0x04, 0xfe, 0xf7, 0x00, 0x35, 0x05, 0x52, 0x31, 0x53,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009459 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59,
9460 0x02, 0x6d, 0x09, 0x04, 0x19, 0x16, 0xd7, 0x09, 0x04, 0xfe, 0xf7, 0x00,
9461 0x35, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x5f, 0xfe, 0x10, 0x90, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009462 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x2f, 0x07, 0x9b, 0x16, 0xfe, 0xc6, 0x08,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009463 0x11, 0x9b, 0x09, 0x04, 0x0b, 0xfe, 0x14, 0x13, 0x05, 0x39, 0x31, 0x3a,
9464 0x77, 0xfe, 0xc6, 0x08, 0xfe, 0x0c, 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x6d,
9465 0x23, 0x47, 0xfe, 0x19, 0x80, 0xde, 0x09, 0x04, 0x0b, 0xfe, 0x1a, 0x12,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009466 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xe9, 0xb5, 0xfe, 0xd1, 0xf0, 0xd9,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009467 0x14, 0x7a, 0x01, 0x33, 0x0f, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe,
9468 0x6c, 0x19, 0xbe, 0x39, 0xfe, 0xed, 0x19, 0xbf, 0x3a, 0xfe, 0x0c, 0x51,
9469 0xfe, 0x8e, 0x51, 0xe9, 0x1c, 0xfe, 0x00, 0xff, 0x34, 0xfe, 0x74, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009470 0xb5, 0xfe, 0xd2, 0xf0, 0xfe, 0xb2, 0x0a, 0xfe, 0x76, 0x18, 0x1c, 0x1a,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009471 0x84, 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0x08, 0x13, 0x0f, 0xfe, 0x16, 0x00,
9472 0x02, 0x5a, 0xfe, 0xd1, 0xf0, 0xfe, 0xc4, 0x0a, 0x14, 0x7a, 0x01, 0x33,
9473 0x0f, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe, 0xce, 0xf0, 0xfe, 0xca,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009474 0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x0f, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009475 0x22, 0x00, 0x02, 0x5a, 0xfe, 0xcb, 0xf0, 0xfe, 0xe2, 0x0a, 0x0f, 0xfe,
9476 0x24, 0x00, 0x02, 0x5a, 0xfe, 0xd0, 0xf0, 0xfe, 0xec, 0x0a, 0x0f, 0x93,
9477 0xdc, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x0f, 0x4c, 0xfe, 0x10, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009478 0xfe, 0xcc, 0xf0, 0xd9, 0x61, 0x04, 0x19, 0x3b, 0x0f, 0xfe, 0x12, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009479 0x2a, 0x13, 0xfe, 0x4e, 0x11, 0x65, 0xfe, 0x0c, 0x0b, 0xfe, 0x9e, 0xf0,
9480 0xfe, 0x20, 0x0b, 0xb1, 0x16, 0x32, 0x2a, 0x73, 0xdd, 0xb8, 0x22, 0xb9,
9481 0x22, 0x2a, 0xec, 0x65, 0xfe, 0x2c, 0x0b, 0x25, 0x32, 0x8c, 0xfe, 0x48,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009482 0x0b, 0x8d, 0x81, 0xb8, 0xd4, 0xb9, 0xd4, 0x02, 0x22, 0x01, 0x43, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009483 0xdb, 0x10, 0x11, 0xfe, 0xe8, 0x00, 0xaa, 0xab, 0x70, 0xbc, 0x7d, 0xbd,
9484 0x7f, 0xfe, 0x89, 0xf0, 0x22, 0x30, 0x2e, 0xd8, 0xbc, 0x7d, 0xbd, 0x7f,
9485 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd6, 0xb1, 0x45, 0x0f, 0xfe, 0x42,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009486 0x00, 0x02, 0x5a, 0x78, 0x06, 0xfe, 0x81, 0x49, 0x16, 0xfe, 0x38, 0x0c,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009487 0x09, 0x04, 0x0b, 0xfe, 0x44, 0x13, 0x0f, 0x00, 0x4b, 0x0b, 0xfe, 0x54,
9488 0x12, 0x4b, 0xfe, 0x28, 0x00, 0x21, 0xfe, 0xa6, 0x0c, 0x0a, 0x40, 0x01,
9489 0x0e, 0x07, 0x00, 0x5d, 0x3e, 0xfe, 0x28, 0x00, 0xfe, 0xe2, 0x10, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009490 0xe7, 0x01, 0xe8, 0x0a, 0x99, 0x01, 0xfe, 0x32, 0x0e, 0x59, 0x11, 0x2d,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009491 0x01, 0x6f, 0x02, 0x29, 0x0f, 0xfe, 0x44, 0x00, 0x4b, 0x0b, 0xdf, 0x3e,
9492 0x0b, 0xfe, 0xb4, 0x10, 0x01, 0x86, 0x3e, 0x0b, 0xfe, 0xaa, 0x10, 0x01,
9493 0x86, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xa3, 0x3e, 0x0b, 0x0f, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009494 0x43, 0x00, 0xfe, 0x96, 0x10, 0x09, 0x4a, 0x0b, 0x35, 0x01, 0xe7, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009495 0xe8, 0x59, 0x11, 0x2d, 0x01, 0x6f, 0x67, 0x0b, 0x59, 0x3c, 0x8a, 0x02,
9496 0xfe, 0x2a, 0x03, 0x09, 0x04, 0x0b, 0x84, 0x3e, 0x0b, 0x0f, 0x00, 0xfe,
9497 0x5c, 0x10, 0x61, 0x04, 0x1b, 0xfe, 0x58, 0x12, 0x09, 0x04, 0x1b, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009498 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x5c, 0x0c, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009499 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x62, 0x0c, 0x09, 0x4a, 0x1b, 0x35,
9500 0xfe, 0xa9, 0x10, 0x0f, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0b, 0x5f,
9501 0x5c, 0x0f, 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x0f, 0xfe, 0x47, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009502 0xa1, 0x0f, 0xfe, 0x41, 0x00, 0xa0, 0x0f, 0xfe, 0x24, 0x00, 0x87, 0xaa,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009503 0xab, 0x70, 0x05, 0x6b, 0x28, 0x21, 0xd1, 0x5f, 0xfe, 0x04, 0xe6, 0x1b,
9504 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x59, 0x01, 0xda, 0x02, 0x29, 0xea,
9505 0x14, 0x0b, 0x37, 0x95, 0xa9, 0x14, 0xfe, 0x31, 0x00, 0x37, 0x97, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009506 0xfe, 0x54, 0x0f, 0x02, 0xd0, 0x3c, 0xfe, 0x06, 0xec, 0xc9, 0xee, 0x3e,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009507 0x1d, 0xfe, 0xce, 0x45, 0x34, 0x3c, 0xfe, 0x06, 0xea, 0xc9, 0xfe, 0x47,
9508 0x4b, 0x89, 0xfe, 0x75, 0x57, 0x05, 0x51, 0xfe, 0x98, 0x56, 0xfe, 0x38,
9509 0x12, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x44, 0x48, 0x46, 0x09, 0x04, 0x1d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009510 0xfe, 0x1a, 0x13, 0x0a, 0x40, 0x01, 0x0e, 0x47, 0xfe, 0x41, 0x58, 0x0a,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009511 0x99, 0x01, 0x0e, 0xfe, 0x49, 0x54, 0x8e, 0xfe, 0x2a, 0x0d, 0x02, 0xfe,
9512 0x2a, 0x03, 0x0a, 0x51, 0xfe, 0xee, 0x14, 0xee, 0x3e, 0x1d, 0xfe, 0xce,
9513 0x45, 0x34, 0x3c, 0xfe, 0xce, 0x47, 0xfe, 0xad, 0x13, 0x02, 0x29, 0x1e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009514 0x20, 0x07, 0x10, 0xfe, 0x9e, 0x12, 0x23, 0x12, 0x4d, 0x12, 0x94, 0x12,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009515 0xce, 0x1e, 0x2d, 0x47, 0x37, 0x2d, 0xb1, 0xe0, 0xfe, 0xbc, 0xf0, 0xfe,
9516 0xec, 0x0d, 0x13, 0x06, 0x12, 0x4d, 0x01, 0xfe, 0xe2, 0x15, 0x05, 0xfe,
9517 0x38, 0x01, 0x31, 0xfe, 0x3a, 0x01, 0x77, 0xfe, 0xf0, 0x0d, 0xfe, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009518 0xec, 0xce, 0x62, 0x00, 0x5d, 0xfe, 0x04, 0xec, 0x20, 0x46, 0xfe, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009519 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x52, 0x16, 0xfb, 0xfe, 0x48, 0xf4,
9520 0x0d, 0xfe, 0x18, 0x13, 0xaf, 0xfe, 0x02, 0xea, 0xce, 0x62, 0x7a, 0xfe,
9521 0xc5, 0x13, 0x14, 0x1b, 0x37, 0x95, 0xa9, 0x5c, 0x05, 0xfe, 0x38, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009522 0x1c, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x05, 0xfe, 0x3a, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009523 0x0c, 0xfe, 0x62, 0x01, 0x3d, 0x12, 0x20, 0x24, 0x06, 0x12, 0x2d, 0x11,
9524 0x2d, 0x8a, 0x13, 0x06, 0x03, 0x23, 0x03, 0x1e, 0x4d, 0xfe, 0xf7, 0x12,
9525 0x1e, 0x94, 0xac, 0x12, 0x94, 0x07, 0x7a, 0xfe, 0x71, 0x13, 0xfe, 0x24,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009526 0x1c, 0x14, 0x1a, 0x37, 0x95, 0xa9, 0xfe, 0xd9, 0x10, 0xb6, 0xfe, 0x03,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009527 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x03, 0xb6, 0xfe, 0x03, 0xdc,
9528 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x03, 0xfe, 0x03, 0x57, 0xb6, 0x23,
9529 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0xb6, 0x75, 0x03, 0x09, 0x04,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009530 0x4c, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009531 0xfe, 0x1e, 0x80, 0xe1, 0xfe, 0x1d, 0x80, 0xa4, 0xfe, 0x0c, 0x90, 0xfe,
9532 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xa3, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
9533 0x0b, 0xfe, 0x3c, 0x50, 0xa0, 0x01, 0xfe, 0x82, 0x16, 0x2f, 0x07, 0x2d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009534 0xe0, 0x01, 0xfe, 0xbc, 0x15, 0x09, 0x04, 0x1d, 0x45, 0x01, 0xe7, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009535 0xe8, 0x11, 0xfe, 0xe9, 0x00, 0x09, 0x04, 0x4c, 0xfe, 0x2c, 0x13, 0x01,
9536 0xfe, 0x14, 0x16, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90,
9537 0x0c, 0xfe, 0x64, 0x01, 0x18, 0xfe, 0x66, 0x01, 0x09, 0x04, 0x4f, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009538 0x12, 0x12, 0xfe, 0x03, 0x80, 0x74, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009539 0x40, 0x12, 0x20, 0x63, 0x27, 0x11, 0xc8, 0x59, 0x1e, 0x20, 0xed, 0x76,
9540 0x20, 0x03, 0xfe, 0x08, 0x1c, 0x05, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58,
9541 0x05, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x05, 0xfe, 0xb0, 0x00, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009542 0x08, 0x58, 0x05, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009543 0x24, 0x69, 0x12, 0xc9, 0x23, 0x0c, 0x50, 0x0c, 0x3f, 0x13, 0x40, 0x48,
9544 0x5f, 0x17, 0x1d, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x21, 0xfe, 0x08,
9545 0x0f, 0x3e, 0x10, 0x13, 0x42, 0x48, 0x17, 0x4c, 0xfe, 0x90, 0x4d, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009546 0x91, 0x54, 0x21, 0xfe, 0x1e, 0x0f, 0x24, 0x10, 0x12, 0x20, 0x78, 0x2c,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009547 0x46, 0x1e, 0x20, 0xed, 0x76, 0x20, 0x11, 0xc8, 0xf6, 0xfe, 0xd6, 0xf0,
9548 0xfe, 0x32, 0x0f, 0xea, 0x70, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
9549 0x18, 0x1c, 0x03, 0x3c, 0xfe, 0x0c, 0x14, 0xee, 0xfe, 0x07, 0xe6, 0x1d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009550 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x86, 0x78, 0x2c, 0x46,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009551 0xfa, 0xef, 0xfe, 0x42, 0x13, 0x2f, 0x07, 0x2d, 0xfe, 0x34, 0x13, 0x0a,
9552 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x36, 0x12, 0xf0, 0xfe, 0x45, 0x48, 0x01,
9553 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009554 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x6f, 0xfe, 0x0e,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009555 0x10, 0x07, 0x7e, 0x45, 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x6c, 0x0f, 0x03,
9556 0xfe, 0x44, 0x58, 0x74, 0xfe, 0x01, 0xec, 0x97, 0xfe, 0x9e, 0x40, 0xfe,
9557 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1b, 0x76, 0x27, 0x01, 0xda, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009558 0xdd, 0x10, 0x2a, 0xbc, 0x7d, 0xbd, 0x7f, 0x30, 0x2e, 0xd5, 0x07, 0x1b,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009559 0xfe, 0x48, 0x12, 0x07, 0x0b, 0xfe, 0x56, 0x12, 0x07, 0x1a, 0xfe, 0x30,
9560 0x12, 0x07, 0xc2, 0x16, 0xfe, 0x3e, 0x11, 0x07, 0xfe, 0x23, 0x00, 0x16,
9561 0xfe, 0x4a, 0x11, 0x07, 0x06, 0x16, 0xfe, 0xa8, 0x11, 0x07, 0x19, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009562 0x12, 0x12, 0x07, 0x00, 0x16, 0x22, 0x14, 0xc2, 0x01, 0x33, 0x9f, 0x2b,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009563 0x01, 0x08, 0x8c, 0x43, 0x03, 0x2b, 0xfe, 0x62, 0x08, 0x0a, 0xca, 0x01,
9564 0xfe, 0x32, 0x0e, 0x11, 0x7e, 0x02, 0x29, 0x2b, 0x2f, 0x07, 0x9b, 0xfe,
9565 0xd9, 0x13, 0x79, 0x39, 0x68, 0x3a, 0x77, 0xfe, 0xfc, 0x10, 0x09, 0x04,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009566 0x6a, 0xfe, 0x72, 0x12, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x8e, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009567 0xc6, 0x10, 0x1e, 0x58, 0xfe, 0x26, 0x13, 0x05, 0x7b, 0x31, 0x7c, 0x77,
9568 0xfe, 0x82, 0x0c, 0x0c, 0x54, 0x18, 0x55, 0x23, 0x0c, 0x7b, 0x0c, 0x7c,
9569 0x01, 0xa8, 0x24, 0x69, 0x73, 0x12, 0x58, 0x01, 0xa5, 0xc0, 0x38, 0xc1,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009570 0x4e, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x38, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009571 0x05, 0xfa, 0x4e, 0xfe, 0x91, 0x10, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x40,
9572 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x56, 0x18, 0x57, 0x83, 0xc0, 0x38, 0xc1,
9573 0x4e, 0xf4, 0xf5, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x00, 0x56, 0xfe, 0xa1,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009574 0x56, 0x0c, 0x52, 0x18, 0x53, 0x09, 0x04, 0x6a, 0xfe, 0x1e, 0x12, 0x1e,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009575 0x58, 0xfe, 0x1f, 0x40, 0x05, 0x54, 0x31, 0x55, 0xfe, 0x2c, 0x50, 0xfe,
9576 0xae, 0x50, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x44, 0x50, 0xfe, 0xc6, 0x50,
9577 0x05, 0x52, 0x31, 0x53, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x05, 0x39,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009578 0x31, 0x3a, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x5c, 0x24, 0x06,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009579 0x12, 0xcd, 0x02, 0x5b, 0x2b, 0x01, 0x08, 0x1f, 0x44, 0x30, 0x2e, 0xd5,
9580 0x07, 0x06, 0x21, 0x44, 0x2f, 0x07, 0x9b, 0x21, 0x5b, 0x01, 0x6e, 0x1c,
9581 0x3d, 0x16, 0x44, 0x09, 0x04, 0x0b, 0xe2, 0x79, 0x39, 0x68, 0x3a, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009582 0x0a, 0x55, 0x34, 0xfe, 0x8b, 0x55, 0xbe, 0x39, 0xbf, 0x3a, 0xfe, 0x0c,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009583 0x51, 0xfe, 0x8e, 0x51, 0x02, 0x5b, 0xfe, 0x19, 0x81, 0xaf, 0xfe, 0x19,
9584 0x41, 0x02, 0x5b, 0x2b, 0x01, 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e,
9585 0xd8, 0x4b, 0x1a, 0xfe, 0xa6, 0x12, 0x4b, 0x0b, 0x3b, 0x02, 0x44, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009586 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, 0xd6, 0x07, 0x1a, 0x21, 0x44,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009587 0x01, 0x08, 0x1f, 0xa2, 0x30, 0x2e, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49,
9588 0x60, 0x05, 0xfe, 0x9c, 0x00, 0x28, 0x84, 0x49, 0x04, 0x19, 0x34, 0x9f,
9589 0xfe, 0xbb, 0x45, 0x4b, 0x00, 0x45, 0x3e, 0x06, 0x78, 0x3d, 0xfe, 0xda,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009590 0x14, 0x01, 0x6e, 0x87, 0xfe, 0x4b, 0x45, 0xe2, 0x2f, 0x07, 0x9a, 0xe1,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009591 0x05, 0xc6, 0x28, 0x84, 0x05, 0x3f, 0x28, 0x34, 0x5e, 0x02, 0x5b, 0xfe,
9592 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17, 0x05, 0x50, 0xb4, 0x0c,
9593 0x50, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe, 0xaa, 0x14, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009594 0x5c, 0x01, 0x08, 0x25, 0x32, 0x1f, 0x44, 0x30, 0x2e, 0xd6, 0x07, 0x06,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009595 0x21, 0x44, 0x01, 0xfe, 0x8e, 0x13, 0xfe, 0x42, 0x58, 0xfe, 0x82, 0x14,
9596 0xfe, 0xa4, 0x14, 0x87, 0xfe, 0x4a, 0xf4, 0x0b, 0x16, 0x44, 0xfe, 0x4a,
9597 0xf4, 0x06, 0xfe, 0x0c, 0x12, 0x2f, 0x07, 0x9a, 0x85, 0x02, 0x5b, 0x05,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009598 0x3f, 0xb4, 0x0c, 0x3f, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009599 0xd8, 0x14, 0x02, 0x5c, 0x13, 0x06, 0x65, 0xfe, 0xca, 0x12, 0x26, 0xfe,
9600 0xe0, 0x12, 0x72, 0xf1, 0x01, 0x08, 0x23, 0x72, 0x03, 0x8f, 0xfe, 0xdc,
9601 0x12, 0x25, 0xfe, 0xdc, 0x12, 0x1f, 0xfe, 0xca, 0x12, 0x5e, 0x2b, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009602 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009603 0x1c, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13,
9604 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0x1c, 0x3d, 0xfe, 0x30, 0x56,
9605 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009606 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0xfe, 0x0b, 0x58,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009607 0x03, 0x0a, 0x50, 0x01, 0x82, 0x0a, 0x3f, 0x01, 0x82, 0x03, 0xfc, 0x1c,
9608 0x10, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x19, 0x48, 0xfe, 0x00,
9609 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x63, 0x27,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009610 0x0c, 0x52, 0x18, 0x53, 0xbe, 0x56, 0xbf, 0x57, 0x03, 0xfe, 0x62, 0x08,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009611 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x74, 0x03, 0x01,
9612 0xfe, 0x14, 0x18, 0xfe, 0x42, 0x48, 0x5f, 0x60, 0x89, 0x01, 0x08, 0x1f,
9613 0xfe, 0xa2, 0x14, 0x30, 0x2e, 0xd8, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009614 0x30, 0x2e, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x05, 0xc6, 0x28, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009615 0xcc, 0x12, 0x49, 0x04, 0x1b, 0xfe, 0xc4, 0x13, 0x23, 0x62, 0x1b, 0xe2,
9616 0x4b, 0xc3, 0x64, 0xfe, 0xe8, 0x13, 0x3b, 0x13, 0x06, 0x17, 0xc3, 0x78,
9617 0xdb, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xa1, 0xff, 0x02, 0x83,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009618 0x55, 0x62, 0x1a, 0xa4, 0xbb, 0xfe, 0x30, 0x00, 0x8e, 0xe4, 0x17, 0x2c,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009619 0x13, 0x06, 0xfe, 0x56, 0x10, 0x62, 0x0b, 0xe1, 0xbb, 0xfe, 0x64, 0x00,
9620 0x8e, 0xe4, 0x0a, 0xfe, 0x64, 0x00, 0x17, 0x93, 0x13, 0x06, 0xfe, 0x28,
9621 0x10, 0x62, 0x06, 0xfe, 0x60, 0x13, 0xbb, 0xfe, 0xc8, 0x00, 0x8e, 0xe4,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009622 0x0a, 0xfe, 0xc8, 0x00, 0x17, 0x4d, 0x13, 0x06, 0x83, 0xbb, 0xfe, 0x90,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009623 0x01, 0xba, 0xfe, 0x4e, 0x14, 0x89, 0xfe, 0x12, 0x10, 0xfe, 0x43, 0xf4,
9624 0x94, 0xfe, 0x56, 0xf0, 0xfe, 0x60, 0x14, 0xfe, 0x04, 0xf4, 0x6c, 0xfe,
9625 0x43, 0xf4, 0x93, 0xfe, 0xf3, 0x10, 0xf9, 0x01, 0xfe, 0x22, 0x13, 0x1c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009626 0x3d, 0xfe, 0x10, 0x13, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x69, 0xba,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009627 0xfe, 0x9c, 0x14, 0xb7, 0x69, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe,
9628 0x4d, 0xe4, 0x19, 0xba, 0xfe, 0x9c, 0x14, 0xb7, 0x19, 0x83, 0x60, 0x23,
9629 0xfe, 0x4d, 0xf4, 0x00, 0xdf, 0x89, 0x13, 0x06, 0xfe, 0xb4, 0x56, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009630 0xc3, 0x58, 0x03, 0x60, 0x13, 0x0b, 0x03, 0x15, 0x06, 0x01, 0x08, 0x26,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009631 0xe5, 0x15, 0x0b, 0x01, 0x08, 0x26, 0xe5, 0x15, 0x1a, 0x01, 0x08, 0x26,
9632 0xe5, 0x72, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x03, 0x15, 0x06, 0x01, 0x08,
9633 0x26, 0xa6, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x06, 0x01, 0x08,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009634 0x26, 0xa6, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x26, 0xa6, 0x72, 0xfe, 0x89,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009635 0x4a, 0x01, 0x08, 0x03, 0x60, 0x03, 0x1e, 0xcc, 0x07, 0x06, 0xfe, 0x44,
9636 0x13, 0xad, 0x12, 0xcc, 0xfe, 0x49, 0xf4, 0x00, 0x3b, 0x72, 0x9f, 0x5e,
9637 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01, 0x08, 0x2f, 0x07, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009638 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0x5a, 0x15, 0x23, 0x12, 0xcd,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009639 0x01, 0x43, 0x1e, 0xcd, 0x07, 0x06, 0x45, 0x09, 0x4a, 0x06, 0x35, 0x03,
9640 0x0a, 0x42, 0x01, 0x0e, 0xed, 0x88, 0x07, 0x10, 0xa4, 0x0a, 0x80, 0x01,
9641 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x80, 0x01, 0x0e, 0x88,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009642 0xfe, 0x80, 0xe7, 0x10, 0x07, 0x10, 0x84, 0xfe, 0x45, 0x58, 0x01, 0xe3,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009643 0x88, 0x03, 0x0a, 0x42, 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03,
9644 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x80, 0x80, 0xf2, 0xfe, 0x49, 0xe4, 0x10,
9645 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x0a, 0x51, 0x01, 0x82, 0x03, 0x17,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009646 0x10, 0x71, 0x66, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009647 0xfe, 0x24, 0x1c, 0xfe, 0x1d, 0xf7, 0x1d, 0x90, 0xfe, 0xf6, 0x15, 0x01,
9648 0xfe, 0xfc, 0x16, 0xe0, 0x91, 0x1d, 0x66, 0xfe, 0x2c, 0x01, 0xfe, 0x2f,
9649 0x19, 0x03, 0xae, 0x21, 0xfe, 0xe6, 0x15, 0xfe, 0xda, 0x10, 0x17, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009650 0x71, 0x05, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009651 0x05, 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0x91, 0x19, 0xfe, 0x3c, 0x90,
9652 0xfe, 0x30, 0xf4, 0x06, 0xfe, 0x3c, 0x50, 0x66, 0xfe, 0x38, 0x00, 0xfe,
9653 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x90, 0xfe, 0x40, 0x16, 0xfe, 0xb6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009654 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x18, 0x16, 0xfe, 0x9c, 0x10, 0x17,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009655 0x10, 0x71, 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe,
9656 0x1d, 0xf7, 0x38, 0x90, 0xfe, 0x62, 0x16, 0xfe, 0x94, 0x14, 0xfe, 0x10,
9657 0x13, 0x91, 0x38, 0x66, 0x1b, 0xfe, 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009658 0x03, 0xae, 0x21, 0xfe, 0x56, 0x16, 0xfe, 0x6c, 0x10, 0x17, 0x10, 0x71,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009659 0xfe, 0x30, 0xbc, 0xfe, 0xb2, 0xbc, 0x91, 0xc5, 0x66, 0x1b, 0xfe, 0x0f,
9660 0x79, 0xfe, 0x1c, 0xf7, 0xc5, 0x90, 0xfe, 0x9a, 0x16, 0xfe, 0x5c, 0x14,
9661 0x34, 0x03, 0xae, 0x21, 0xfe, 0x86, 0x16, 0xfe, 0x42, 0x10, 0xfe, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009662 0xf6, 0x10, 0x71, 0xfe, 0x18, 0xfe, 0x54, 0xfe, 0x19, 0xfe, 0x55, 0xfc,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009663 0xfe, 0x1d, 0xf7, 0x4f, 0x90, 0xfe, 0xc0, 0x16, 0xfe, 0x36, 0x14, 0xfe,
9664 0x1c, 0x13, 0x91, 0x4f, 0x47, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe,
9665 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11, 0xfe, 0xdd, 0x00, 0x63,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009666 0x27, 0x03, 0x63, 0x27, 0xfe, 0x12, 0x45, 0x21, 0xfe, 0xb0, 0x16, 0x14,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009667 0x06, 0x37, 0x95, 0xa9, 0x02, 0x29, 0xfe, 0x39, 0xf0, 0xfe, 0x04, 0x17,
9668 0x23, 0x03, 0xfe, 0x7e, 0x18, 0x1c, 0x1a, 0x5d, 0x13, 0x0d, 0x03, 0x71,
9669 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x78, 0x2c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009670 0x46, 0x2f, 0x07, 0x2d, 0xfe, 0x3c, 0x13, 0xfe, 0x82, 0x14, 0xfe, 0x42,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009671 0x13, 0x3c, 0x8a, 0x0a, 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x3e, 0x12, 0xf0,
9672 0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13,
9673 0x3d, 0x75, 0x07, 0x10, 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x01, 0x6f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009674 0xfe, 0x16, 0x10, 0x07, 0x7e, 0x85, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009675 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x24, 0x17, 0x17, 0x0b, 0x03, 0xfe, 0x9c,
9676 0xe7, 0x0b, 0x0f, 0xfe, 0x15, 0x00, 0x59, 0x76, 0x27, 0x01, 0xda, 0x17,
9677 0x06, 0x03, 0x3c, 0x8a, 0x09, 0x4a, 0x1d, 0x35, 0x11, 0x2d, 0x01, 0x6f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009678 0x17, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x79, 0xc7, 0x68,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009679 0xc8, 0xfe, 0x48, 0x55, 0x34, 0xfe, 0xc9, 0x55, 0x03, 0x1e, 0x98, 0x73,
9680 0x12, 0x98, 0x03, 0x0a, 0x99, 0x01, 0x0e, 0xf0, 0x0a, 0x40, 0x01, 0x0e,
9681 0xfe, 0x49, 0x44, 0x16, 0xfe, 0xf0, 0x17, 0x73, 0x75, 0x03, 0x0a, 0x42,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009682 0x01, 0x0e, 0x07, 0x10, 0x45, 0x0a, 0x51, 0x01, 0x9e, 0x0a, 0x40, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009683 0x0e, 0x73, 0x75, 0x03, 0xfe, 0x4e, 0xe4, 0x1a, 0x64, 0xfe, 0x24, 0x18,
9684 0x05, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0x5b, 0xfe, 0x4e, 0xe4, 0xc2,
9685 0x64, 0xfe, 0x36, 0x18, 0x05, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009686 0xdc, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x64, 0xfe, 0x48, 0x18, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009687 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x19, 0xfe, 0x08, 0x10, 0x05, 0xfe,
9688 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x2c, 0xfe, 0x4e, 0x45, 0xfe, 0x0c, 0x12,
9689 0xaf, 0xff, 0x04, 0x68, 0x54, 0xde, 0x1c, 0x69, 0x03, 0x07, 0x7a, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009690 0x5a, 0xf0, 0xfe, 0x74, 0x18, 0x24, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009691 0x07, 0x1b, 0xfe, 0x5a, 0xf0, 0xfe, 0x82, 0x18, 0x24, 0xc3, 0xfe, 0x26,
9692 0x10, 0x07, 0x1a, 0x5d, 0x24, 0x2c, 0xdc, 0x07, 0x0b, 0x5d, 0x24, 0x93,
9693 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x5d, 0x24, 0x4d, 0x9f, 0xad, 0x03, 0x14,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009694 0xfe, 0x09, 0x00, 0x01, 0x33, 0xfe, 0x04, 0xfe, 0x7d, 0x05, 0x7f, 0xf9,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009695 0x03, 0x25, 0xfe, 0xca, 0x18, 0xfe, 0x14, 0xf0, 0x08, 0x65, 0xfe, 0xc6,
9696 0x18, 0x03, 0xff, 0x1a, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -07009697};
9698
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009699static unsigned short _adv_asc3550_size = sizeof(_adv_asc3550_buf); /* 0x13AD */
9700static ADV_DCNT _adv_asc3550_chksum = 0x04D52DDDUL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07009701
9702/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009703static unsigned char _adv_asc38C0800_buf[] = {
9704 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x16, 0x18, 0xe4,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009705 0x01, 0x00, 0x48, 0xe4, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0xce, 0x19,
9706 0x00, 0xfa, 0xff, 0xff, 0x1c, 0x0f, 0x00, 0xf6, 0x9e, 0xe7, 0xff, 0x00,
9707 0x82, 0xe7, 0x00, 0xea, 0x01, 0xfa, 0x01, 0xe6, 0x09, 0xe7, 0x55, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009708 0x01, 0xf6, 0x03, 0x00, 0x04, 0x00, 0x10, 0x00, 0x1e, 0xf0, 0x85, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009709 0x18, 0xf4, 0x08, 0x00, 0xbc, 0x00, 0x38, 0x54, 0x00, 0xec, 0xd5, 0xf0,
9710 0x82, 0x0d, 0x00, 0xe6, 0x86, 0xf0, 0xb1, 0xf0, 0x98, 0x57, 0x01, 0xfc,
9711 0xb4, 0x00, 0xd4, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x3c, 0x00, 0xbb, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009712 0x00, 0x10, 0xba, 0x19, 0x02, 0x80, 0x32, 0xf0, 0x7c, 0x0d, 0x02, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009713 0xba, 0x13, 0x18, 0x40, 0x00, 0x57, 0x01, 0xea, 0x02, 0xfc, 0x03, 0xfc,
9714 0x3e, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x74, 0x01, 0x76, 0x01, 0xb9, 0x54,
9715 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00, 0xc0, 0x00, 0x01, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009716 0x3e, 0x01, 0x7a, 0x01, 0xca, 0x08, 0xce, 0x10, 0x16, 0x11, 0x04, 0x12,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009717 0x08, 0x12, 0x02, 0x4a, 0xbb, 0x55, 0x3c, 0x56, 0x03, 0x58, 0x1b, 0x80,
9718 0x30, 0xe4, 0x4b, 0xe4, 0x5d, 0xf0, 0x02, 0xfa, 0x20, 0x00, 0x32, 0x00,
9719 0x40, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009720 0x70, 0x01, 0x72, 0x01, 0x78, 0x01, 0x7c, 0x01, 0x62, 0x0a, 0x86, 0x0d,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009721 0x06, 0x13, 0x4c, 0x1c, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0,
9722 0x03, 0xf7, 0x0c, 0x00, 0x0f, 0x00, 0x47, 0x00, 0xbe, 0x00, 0x00, 0x01,
9723 0x20, 0x11, 0x5c, 0x16, 0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009724 0x00, 0x4c, 0x04, 0xea, 0x5c, 0xf0, 0xa7, 0xf0, 0x04, 0xf6, 0x03, 0xfa,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009725 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01,
9726 0x4e, 0x01, 0x4a, 0x0b, 0x42, 0x0c, 0x12, 0x0f, 0x0c, 0x10, 0x22, 0x11,
9727 0x0a, 0x12, 0x04, 0x13, 0x30, 0x1c, 0x02, 0x48, 0x00, 0x4e, 0x42, 0x54,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009728 0x44, 0x55, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009729 0x59, 0xf0, 0xb8, 0xf0, 0x4b, 0xf4, 0x06, 0xf7, 0x0e, 0xf7, 0x04, 0xfc,
9730 0x05, 0xfc, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00, 0xa4, 0x00,
9731 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xe2, 0x03,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009732 0x08, 0x0f, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, 0x0a, 0x13, 0x0c, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009733 0x12, 0x13, 0x24, 0x14, 0x34, 0x14, 0x04, 0x16, 0x08, 0x16, 0xa4, 0x17,
9734 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44, 0x91, 0x44,
9735 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x3a, 0x55, 0x83, 0x55,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009736 0xe5, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009737 0x0c, 0xf0, 0x04, 0xf8, 0x05, 0xf8, 0x07, 0x00, 0x0a, 0x00, 0x1c, 0x00,
9738 0x1e, 0x00, 0x9e, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00,
9739 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7e, 0x01, 0xc4, 0x01, 0xc6, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009740 0x80, 0x02, 0x5e, 0x03, 0xee, 0x04, 0x9a, 0x06, 0xf8, 0x07, 0x62, 0x08,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009741 0x68, 0x08, 0x69, 0x08, 0xd6, 0x08, 0xe9, 0x09, 0xfa, 0x0b, 0x2e, 0x0f,
9742 0x12, 0x10, 0x1a, 0x10, 0xed, 0x10, 0xf1, 0x10, 0x2a, 0x11, 0x06, 0x12,
9743 0x0c, 0x12, 0x3e, 0x12, 0x10, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x46, 0x14,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009744 0x76, 0x14, 0x82, 0x14, 0x36, 0x15, 0xca, 0x15, 0x6b, 0x18, 0xbe, 0x18,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009745 0xca, 0x18, 0xe6, 0x19, 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40,
9746 0x0e, 0x47, 0xfe, 0x9c, 0xf0, 0x2b, 0x02, 0xfe, 0xac, 0x0d, 0xff, 0x10,
9747 0x00, 0x00, 0xd7, 0xfe, 0xe8, 0x19, 0x00, 0xd6, 0xfe, 0x84, 0x01, 0xff,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009748 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009749 0x00, 0xfe, 0x57, 0x24, 0x00, 0xfe, 0x4c, 0x00, 0x5b, 0xff, 0x04, 0x00,
9750 0x00, 0x11, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x08,
9751 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x11,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009752 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009753 0xfe, 0x04, 0xf7, 0xd6, 0x2c, 0x99, 0x0a, 0x01, 0xfe, 0xc2, 0x0f, 0xfe,
9754 0x04, 0xf7, 0xd6, 0x99, 0x0a, 0x42, 0x2c, 0xfe, 0x3d, 0xf0, 0xfe, 0x06,
9755 0x02, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x91, 0xf0, 0xfe, 0xf4, 0x01, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009756 0x90, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, 0x8f, 0xf0, 0xa7, 0x03, 0x5d, 0x4d,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009757 0x02, 0xfe, 0xc8, 0x0d, 0x01, 0xfe, 0x38, 0x0e, 0xfe, 0xdd, 0x12, 0xfe,
9758 0xfc, 0x10, 0xfe, 0x28, 0x1c, 0x03, 0xfe, 0xa6, 0x00, 0xfe, 0xd3, 0x12,
9759 0x41, 0x14, 0xfe, 0xa6, 0x00, 0xc2, 0xfe, 0x48, 0xf0, 0xfe, 0x8a, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009760 0xfe, 0x49, 0xf0, 0xfe, 0xa4, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc2, 0x02,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009761 0xfe, 0x46, 0xf0, 0xfe, 0x54, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x5a, 0x02,
9762 0xfe, 0x43, 0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x4c, 0x02,
9763 0xfe, 0x45, 0xf0, 0xfe, 0x50, 0x02, 0x18, 0x0a, 0xaa, 0x18, 0x06, 0x14,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009764 0xa1, 0x02, 0x2b, 0xfe, 0x00, 0x1c, 0xe7, 0xfe, 0x02, 0x1c, 0xe6, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009765 0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0xfe, 0x18, 0x18, 0xfe, 0xe7, 0x10,
9766 0xfe, 0x06, 0xfc, 0xce, 0x09, 0x70, 0x01, 0xa8, 0x02, 0x2b, 0x15, 0x59,
9767 0x39, 0xa2, 0x01, 0xfe, 0x58, 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xbd,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009768 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009769 0x58, 0x1c, 0x18, 0x06, 0x14, 0xa1, 0x2c, 0x1c, 0x2b, 0xfe, 0x3d, 0xf0,
9770 0xfe, 0x06, 0x02, 0x23, 0xfe, 0x98, 0x02, 0xfe, 0x5a, 0x1c, 0xf8, 0xfe,
9771 0x14, 0x1c, 0x15, 0xfe, 0x30, 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009772 0x18, 0x06, 0x14, 0xa1, 0x02, 0xd7, 0x22, 0x20, 0x07, 0x11, 0x35, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009773 0x69, 0x10, 0x18, 0x06, 0x14, 0xa1, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0x43,
9774 0x13, 0x20, 0xfe, 0x05, 0xf6, 0xce, 0x01, 0xfe, 0x4a, 0x17, 0x08, 0x54,
9775 0x58, 0x37, 0x12, 0x2f, 0x42, 0x92, 0x01, 0xfe, 0x82, 0x16, 0x02, 0x2b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009776 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x01, 0x73, 0xfe, 0x18, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009777 0xfe, 0x41, 0x58, 0x09, 0xa4, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x6b, 0xfe,
9778 0x10, 0x03, 0x01, 0xfe, 0x82, 0x16, 0x02, 0x2b, 0x2c, 0x4f, 0xfe, 0x02,
9779 0xe8, 0x2a, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009780 0x27, 0xf0, 0xfe, 0xe0, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xa7,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009781 0xfe, 0x40, 0x1c, 0x1c, 0xd9, 0xfe, 0x26, 0xf0, 0xfe, 0x5a, 0x03, 0xfe,
9782 0xa0, 0xf0, 0xfe, 0x48, 0x03, 0xfe, 0x11, 0xf0, 0xa7, 0xfe, 0xef, 0x10,
9783 0xfe, 0x9f, 0xf0, 0xfe, 0x68, 0x03, 0xf9, 0x10, 0xfe, 0x11, 0x00, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009784 0x65, 0x2c, 0xfe, 0x48, 0x1c, 0xf9, 0x08, 0x05, 0x1b, 0xfe, 0x18, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009785 0x21, 0x22, 0xa3, 0xb7, 0x13, 0xa3, 0x09, 0x46, 0x01, 0x0e, 0xb7, 0x78,
9786 0x01, 0xfe, 0xb4, 0x16, 0x12, 0xd1, 0x1c, 0xd9, 0xfe, 0x01, 0xf0, 0xd9,
9787 0xfe, 0x82, 0xf0, 0xfe, 0x96, 0x03, 0xfa, 0x12, 0xfe, 0xe4, 0x00, 0x27,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009788 0xfe, 0xa8, 0x03, 0x1c, 0x34, 0x1d, 0xfe, 0xb8, 0x03, 0x01, 0x4b, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009789 0x06, 0xf0, 0xfe, 0xc8, 0x03, 0x95, 0x86, 0xfe, 0x0a, 0xf0, 0xfe, 0x8a,
9790 0x06, 0x02, 0x24, 0x03, 0x70, 0x28, 0x17, 0xfe, 0xfa, 0x04, 0x15, 0x6d,
9791 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, 0xd8, 0xf9, 0x2c, 0x99, 0x19,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009792 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009793 0x74, 0x01, 0xaf, 0x8c, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x17, 0xda,
9794 0x09, 0xd1, 0x01, 0x0e, 0x8d, 0x51, 0x64, 0x79, 0x2a, 0x03, 0x70, 0x28,
9795 0xfe, 0x10, 0x12, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009796 0xd8, 0xc7, 0x81, 0xc8, 0x83, 0x1c, 0x24, 0x27, 0xfe, 0x40, 0x04, 0x1d,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009797 0xfe, 0x3c, 0x04, 0x3b, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e,
9798 0x12, 0x2d, 0xff, 0x02, 0x00, 0x10, 0x01, 0x0b, 0x1d, 0xfe, 0xe4, 0x04,
9799 0x2d, 0x01, 0x0b, 0x1d, 0x24, 0x33, 0x31, 0xde, 0xfe, 0x4c, 0x44, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009800 0x4c, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009801 0xda, 0x4f, 0x79, 0x2a, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x62,
9802 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x2a, 0x13, 0x32, 0x07, 0x82, 0xfe, 0x52,
9803 0x13, 0xfe, 0x20, 0x10, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b, 0xda, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009804 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x40, 0x13, 0x08, 0x05, 0x1b, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009805 0x08, 0x13, 0x32, 0x07, 0x82, 0xfe, 0x30, 0x13, 0x08, 0x05, 0x1b, 0xfe,
9806 0x1c, 0x12, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe, 0x0d, 0x00,
9807 0x01, 0x36, 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x2d, 0x12, 0xfe, 0xe6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009808 0x00, 0xfe, 0x1c, 0x90, 0xfe, 0x40, 0x5c, 0x04, 0x15, 0x9d, 0x01, 0x36,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009809 0x02, 0x2b, 0xfe, 0x42, 0x5b, 0x99, 0x19, 0xfe, 0x46, 0x59, 0xfe, 0xbf,
9810 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x87, 0x80, 0xfe, 0x31, 0xe4, 0x5b, 0x08,
9811 0x05, 0x0a, 0xfe, 0x84, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x19, 0xfe, 0x7c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009812 0x12, 0x53, 0x05, 0x06, 0xfe, 0x6c, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x28,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009813 0x17, 0xfe, 0x90, 0x05, 0xfe, 0x31, 0xe4, 0x5a, 0x53, 0x05, 0x0a, 0xfe,
9814 0x56, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x28, 0xfe, 0x4e, 0x12, 0x67, 0xff,
9815 0x02, 0x00, 0x10, 0x27, 0xfe, 0x48, 0x05, 0x1c, 0x34, 0xfe, 0x89, 0x48,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009816 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x56, 0x05, 0x26, 0xfe, 0xa8, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009817 0x12, 0xfe, 0xe3, 0x00, 0x21, 0x53, 0xfe, 0x4a, 0xf0, 0xfe, 0x76, 0x05,
9818 0xfe, 0x49, 0xf0, 0xfe, 0x70, 0x05, 0x88, 0x25, 0xfe, 0x21, 0x00, 0xab,
9819 0x25, 0xfe, 0x22, 0x00, 0xaa, 0x25, 0x58, 0xfe, 0x09, 0x48, 0xff, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009820 0x00, 0x10, 0x27, 0xfe, 0x86, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0xfe, 0xe2,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009821 0x08, 0x53, 0x05, 0xcb, 0x4d, 0x01, 0xb0, 0x25, 0x06, 0x13, 0xd3, 0x39,
9822 0xfe, 0x27, 0x01, 0x08, 0x05, 0x1b, 0xfe, 0x22, 0x12, 0x41, 0x01, 0xb2,
9823 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009824 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0xeb,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009825 0x03, 0x5c, 0x28, 0xfe, 0x36, 0x13, 0x41, 0x01, 0xb2, 0x26, 0xfe, 0x18,
9826 0x06, 0x09, 0x06, 0x53, 0x05, 0x1f, 0xfe, 0x02, 0x12, 0x50, 0x01, 0xfe,
9827 0x9e, 0x15, 0x1d, 0xfe, 0x0e, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009828 0xe5, 0x00, 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x03, 0xcd, 0x28, 0xfe, 0x62,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009829 0x12, 0x03, 0x45, 0x28, 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x0c, 0x19, 0x01,
9830 0xfe, 0x76, 0x19, 0xfe, 0x43, 0x48, 0xc4, 0xcc, 0x0f, 0x71, 0xff, 0x02,
9831 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0x8b, 0xc4, 0x6e, 0x41, 0x01, 0xb2,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009832 0x26, 0xfe, 0x82, 0x06, 0x53, 0x05, 0x1a, 0xe9, 0x91, 0x09, 0x59, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009833 0xfe, 0xcc, 0x15, 0x1d, 0xfe, 0x78, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12,
9834 0xfe, 0xe5, 0x00, 0x03, 0x45, 0xc1, 0x0c, 0x45, 0x18, 0x06, 0x01, 0xb2,
9835 0xfa, 0x76, 0x74, 0x01, 0xaf, 0x8c, 0x12, 0xfe, 0xe2, 0x00, 0x27, 0xdb,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009836 0x1c, 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0xb6, 0x06, 0x94, 0xfe, 0x6c, 0x07,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009837 0xfe, 0x06, 0xf0, 0xfe, 0x74, 0x07, 0x95, 0x86, 0x02, 0x24, 0x08, 0x05,
9838 0x0a, 0xfe, 0x2e, 0x12, 0x16, 0x19, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b,
9839 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0xfe, 0x99, 0xa4, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009840 0x0b, 0x16, 0x00, 0x02, 0xfe, 0x42, 0x08, 0x68, 0x05, 0x1a, 0xfe, 0x38,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009841 0x12, 0x08, 0x05, 0x1a, 0xfe, 0x30, 0x13, 0x16, 0xfe, 0x1b, 0x00, 0x01,
9842 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01,
9843 0x0b, 0x16, 0x06, 0x01, 0x0b, 0x16, 0x00, 0x02, 0xe2, 0x6c, 0x58, 0xbe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009844 0x50, 0xfe, 0x9a, 0x81, 0x55, 0x1b, 0x7a, 0xfe, 0x42, 0x07, 0x09, 0x1b,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009845 0xfe, 0x09, 0x6f, 0xba, 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x69, 0x6d,
9846 0x8b, 0x6c, 0x7f, 0x27, 0xfe, 0x54, 0x07, 0x1c, 0x34, 0xfe, 0x0a, 0xf0,
9847 0xfe, 0x42, 0x07, 0x95, 0x86, 0x94, 0xfe, 0x6c, 0x07, 0x02, 0x24, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009848 0x4b, 0x02, 0xdb, 0x16, 0x1f, 0x02, 0xdb, 0xfe, 0x9c, 0xf7, 0xdc, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009849 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x56, 0xfe, 0xda, 0x07, 0x0c, 0x60, 0x14,
9850 0x61, 0x08, 0x54, 0x5a, 0x37, 0x22, 0x20, 0x07, 0x11, 0xfe, 0x0e, 0x12,
9851 0x8d, 0xfe, 0x80, 0x80, 0x39, 0x20, 0x6a, 0x2a, 0xfe, 0x06, 0x10, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009852 0x83, 0xe7, 0xfe, 0x48, 0x00, 0xab, 0xfe, 0x03, 0x40, 0x08, 0x54, 0x5b,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009853 0x37, 0x01, 0xb3, 0xb8, 0xfe, 0x1f, 0x40, 0x13, 0x62, 0x01, 0xef, 0xfe,
9854 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0x88,
9855 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e, 0x14, 0x5f, 0xfe, 0x0c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009856 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x0c, 0x3d,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009857 0x14, 0x3e, 0xfe, 0x4a, 0x10, 0x08, 0x05, 0x5a, 0xfe, 0x2a, 0x12, 0xfe,
9858 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x60, 0x14, 0x61, 0x08, 0x05, 0x5b,
9859 0x8b, 0x01, 0xb3, 0xfe, 0x1f, 0x80, 0x13, 0x62, 0xfe, 0x44, 0x90, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009860 0xc6, 0x90, 0x0c, 0x3f, 0x14, 0x40, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009861 0x0c, 0x5e, 0x14, 0x5f, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x3d,
9862 0x14, 0x3e, 0x0c, 0x2e, 0x14, 0x3c, 0x21, 0x0c, 0x49, 0x0c, 0x63, 0x08,
9863 0x54, 0x1f, 0x37, 0x2c, 0x0f, 0xfe, 0x4e, 0x11, 0x27, 0xdd, 0xfe, 0x9e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009864 0xf0, 0xfe, 0x76, 0x08, 0xbc, 0x17, 0x34, 0x2c, 0x77, 0xe6, 0xc5, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009865 0x9a, 0x08, 0xc6, 0xfe, 0xb8, 0x08, 0x94, 0xfe, 0x8e, 0x08, 0xfe, 0x06,
9866 0xf0, 0xfe, 0x94, 0x08, 0x95, 0x86, 0x02, 0x24, 0x01, 0x4b, 0xfe, 0xc9,
9867 0x10, 0x16, 0x1f, 0xfe, 0xc9, 0x10, 0x68, 0x05, 0x06, 0xfe, 0x10, 0x12,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009868 0x68, 0x05, 0x0a, 0x4e, 0x08, 0x05, 0x0a, 0xfe, 0x90, 0x12, 0xfe, 0x2e,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009869 0x1c, 0x02, 0xfe, 0x18, 0x0b, 0x68, 0x05, 0x06, 0x4e, 0x68, 0x05, 0x0a,
9870 0xfe, 0x7a, 0x12, 0xfe, 0x2c, 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0xd2, 0x09,
9871 0xfe, 0xac, 0xf0, 0xfe, 0x00, 0x09, 0x02, 0xfe, 0xde, 0x09, 0xfe, 0xb7,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009872 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0x02, 0xf6, 0x1a, 0x50, 0xfe, 0x70, 0x18,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009873 0xfe, 0xf1, 0x18, 0xfe, 0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58,
9874 0xfe, 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x1c, 0x85, 0xfe,
9875 0x8c, 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0xac, 0xf0, 0xfe, 0xf0, 0x08, 0xb5,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009876 0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x0c, 0x09, 0x02, 0xfe, 0x18,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009877 0x0b, 0xb6, 0xfe, 0xbf, 0x10, 0xfe, 0x2b, 0xf0, 0x85, 0xf4, 0x1e, 0xfe,
9878 0x00, 0xfe, 0xfe, 0x1c, 0x12, 0xc2, 0xfe, 0xd2, 0xf0, 0x85, 0xfe, 0x76,
9879 0x18, 0x1e, 0x19, 0x17, 0x85, 0x03, 0xd2, 0x1e, 0x06, 0x17, 0x85, 0xc5,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009880 0x4a, 0xc6, 0x4a, 0xb5, 0xb6, 0xfe, 0x89, 0x10, 0x74, 0x67, 0x2d, 0x15,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009881 0x9d, 0x01, 0x36, 0x10, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x65, 0x10,
9882 0x80, 0x02, 0x65, 0xfe, 0x98, 0x80, 0xfe, 0x19, 0xe4, 0x0a, 0xfe, 0x1a,
9883 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18, 0xfe, 0x44, 0x54, 0xbe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009884 0xfe, 0x19, 0x81, 0xfe, 0x74, 0x18, 0x8f, 0x90, 0x17, 0xfe, 0xce, 0x08,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009885 0x02, 0x4a, 0x08, 0x05, 0x5a, 0xec, 0x03, 0x2e, 0x29, 0x3c, 0x0c, 0x3f,
9886 0x14, 0x40, 0x9b, 0x2e, 0x9c, 0x3c, 0xfe, 0x6c, 0x18, 0xfe, 0xed, 0x18,
9887 0xfe, 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x3a, 0x3f, 0x3b, 0x40, 0x03, 0x49,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009888 0x29, 0x63, 0x8f, 0xfe, 0xe3, 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009889 0x8f, 0xfe, 0xe3, 0x54, 0x90, 0xc0, 0x56, 0xfe, 0xce, 0x08, 0x02, 0x4a,
9890 0xfe, 0x37, 0xf0, 0xfe, 0xda, 0x09, 0xfe, 0x8b, 0xf0, 0xfe, 0x60, 0x09,
9891 0x02, 0x4a, 0x08, 0x05, 0x0a, 0x23, 0xfe, 0xfa, 0x0a, 0x3a, 0x49, 0x3b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009892 0x63, 0x56, 0xfe, 0x3e, 0x0a, 0x0f, 0xfe, 0xc0, 0x07, 0x41, 0x98, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009893 0xad, 0xfe, 0x01, 0x59, 0xfe, 0x52, 0xf0, 0xfe, 0x0c, 0x0a, 0x8f, 0x7a,
9894 0xfe, 0x24, 0x0a, 0x3a, 0x49, 0x8f, 0xfe, 0xe3, 0x54, 0x57, 0x49, 0x7d,
9895 0x63, 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02, 0x4a, 0x3a, 0x49, 0x3b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009896 0x63, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xbe, 0x57, 0x49, 0x57, 0x63,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009897 0x02, 0x4a, 0x08, 0x05, 0x5a, 0xfe, 0x82, 0x12, 0x08, 0x05, 0x1f, 0xfe,
9898 0x66, 0x13, 0x22, 0x62, 0xb7, 0xfe, 0x03, 0xa1, 0xfe, 0x83, 0x80, 0xfe,
9899 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x6a,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009900 0x2a, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x56, 0xe0, 0x03, 0x60, 0x29,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009901 0x61, 0x0c, 0x7f, 0x14, 0x80, 0x57, 0x60, 0x7d, 0x61, 0x01, 0xb3, 0xb8,
9902 0x6a, 0x2a, 0x13, 0x62, 0x9b, 0x2e, 0x9c, 0x3c, 0x3a, 0x3f, 0x3b, 0x40,
9903 0x90, 0xc0, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0x01, 0xef,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009904 0xfe, 0x36, 0x10, 0x21, 0x0c, 0x7f, 0x0c, 0x80, 0x3a, 0x3f, 0x3b, 0x40,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009905 0xe4, 0x08, 0x05, 0x1f, 0x17, 0xe0, 0x3a, 0x3d, 0x3b, 0x3e, 0x08, 0x05,
9906 0xfe, 0xf7, 0x00, 0x37, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x10, 0x58, 0xfe,
9907 0x91, 0x58, 0x57, 0x49, 0x7d, 0x63, 0x02, 0xfe, 0xf4, 0x09, 0x08, 0x05,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009908 0x1f, 0x17, 0xe0, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0xbe, 0xfe, 0x19,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009909 0x81, 0x50, 0xfe, 0x10, 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd3, 0x10, 0x32,
9910 0x07, 0xa6, 0x17, 0xfe, 0x08, 0x09, 0x12, 0xa6, 0x08, 0x05, 0x0a, 0xfe,
9911 0x14, 0x13, 0x03, 0x3d, 0x29, 0x3e, 0x56, 0xfe, 0x08, 0x09, 0xfe, 0x0c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009912 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x4a, 0x21, 0x41, 0xfe, 0x19, 0x80, 0xe7,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009913 0x08, 0x05, 0x0a, 0xfe, 0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41,
9914 0xf4, 0xc2, 0xfe, 0xd1, 0xf0, 0xe2, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe,
9915 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0x57, 0x3d, 0xfe, 0xed,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009916 0x19, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xf4, 0x1e, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009917 0x00, 0xff, 0x35, 0xfe, 0x74, 0x10, 0xc2, 0xfe, 0xd2, 0xf0, 0xfe, 0xa6,
9918 0x0b, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x8a, 0x03, 0xd2, 0x1e, 0x06, 0xfe,
9919 0x08, 0x13, 0x10, 0xfe, 0x16, 0x00, 0x02, 0x65, 0xfe, 0xd1, 0xf0, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009920 0xb8, 0x0b, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, 0x17, 0x00, 0xfe, 0x42,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009921 0x10, 0xfe, 0xce, 0xf0, 0xfe, 0xbe, 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd,
9922 0xf0, 0xfe, 0xca, 0x0b, 0x10, 0xfe, 0x22, 0x00, 0x02, 0x65, 0xfe, 0xcb,
9923 0xf0, 0xfe, 0xd6, 0x0b, 0x10, 0xfe, 0x24, 0x00, 0x02, 0x65, 0xfe, 0xd0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009924 0xf0, 0xfe, 0xe0, 0x0b, 0x10, 0x9e, 0xe5, 0xfe, 0xcf, 0xf0, 0xfe, 0xea,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009925 0x0b, 0x10, 0x58, 0xfe, 0x10, 0x10, 0xfe, 0xcc, 0xf0, 0xe2, 0x68, 0x05,
9926 0x1f, 0x4d, 0x10, 0xfe, 0x12, 0x00, 0x2c, 0x0f, 0xfe, 0x4e, 0x11, 0x27,
9927 0xfe, 0x00, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x14, 0x0c, 0xbc, 0x17, 0x34,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009928 0x2c, 0x77, 0xe6, 0xc5, 0x24, 0xc6, 0x24, 0x2c, 0xfa, 0x27, 0xfe, 0x20,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009929 0x0c, 0x1c, 0x34, 0x94, 0xfe, 0x3c, 0x0c, 0x95, 0x86, 0xc5, 0xdc, 0xc6,
9930 0xdc, 0x02, 0x24, 0x01, 0x4b, 0xfe, 0xdb, 0x10, 0x12, 0xfe, 0xe8, 0x00,
9931 0xb5, 0xb6, 0x74, 0xc7, 0x81, 0xc8, 0x83, 0xfe, 0x89, 0xf0, 0x24, 0x33,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009932 0x31, 0xe1, 0xc7, 0x81, 0xc8, 0x83, 0x27, 0xfe, 0x66, 0x0c, 0x1d, 0x24,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009933 0x33, 0x31, 0xdf, 0xbc, 0x4e, 0x10, 0xfe, 0x42, 0x00, 0x02, 0x65, 0x7c,
9934 0x06, 0xfe, 0x81, 0x49, 0x17, 0xfe, 0x2c, 0x0d, 0x08, 0x05, 0x0a, 0xfe,
9935 0x44, 0x13, 0x10, 0x00, 0x55, 0x0a, 0xfe, 0x54, 0x12, 0x55, 0xfe, 0x28,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009936 0x00, 0x23, 0xfe, 0x9a, 0x0d, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009937 0x44, 0xfe, 0x28, 0x00, 0xfe, 0xe2, 0x10, 0x01, 0xf5, 0x01, 0xf6, 0x09,
9938 0xa4, 0x01, 0xfe, 0x26, 0x0f, 0x64, 0x12, 0x2f, 0x01, 0x73, 0x02, 0x2b,
9939 0x10, 0xfe, 0x44, 0x00, 0x55, 0x0a, 0xe9, 0x44, 0x0a, 0xfe, 0xb4, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009940 0x01, 0xb0, 0x44, 0x0a, 0xfe, 0xaa, 0x10, 0x01, 0xb0, 0xfe, 0x19, 0x82,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009941 0xfe, 0x34, 0x46, 0xac, 0x44, 0x0a, 0x10, 0xfe, 0x43, 0x00, 0xfe, 0x96,
9942 0x10, 0x08, 0x54, 0x0a, 0x37, 0x01, 0xf5, 0x01, 0xf6, 0x64, 0x12, 0x2f,
9943 0x01, 0x73, 0x99, 0x0a, 0x64, 0x42, 0x92, 0x02, 0xfe, 0x2e, 0x03, 0x08,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009944 0x05, 0x0a, 0x8a, 0x44, 0x0a, 0x10, 0x00, 0xfe, 0x5c, 0x10, 0x68, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009945 0x1a, 0xfe, 0x58, 0x12, 0x08, 0x05, 0x1a, 0xfe, 0x50, 0x13, 0xfe, 0x1c,
9946 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x50, 0x0d, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d,
9947 0xf0, 0xfe, 0x56, 0x0d, 0x08, 0x54, 0x1a, 0x37, 0xfe, 0xa9, 0x10, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009948 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0a, 0x50, 0xfe, 0x2e, 0x10, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009949 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x10, 0x6f, 0xab, 0x10, 0xfe, 0x41,
9950 0x00, 0xaa, 0x10, 0xfe, 0x24, 0x00, 0x8c, 0xb5, 0xb6, 0x74, 0x03, 0x70,
9951 0x28, 0x23, 0xd8, 0x50, 0xfe, 0x04, 0xe6, 0x1a, 0xfe, 0x9d, 0x41, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009952 0x1c, 0x42, 0x64, 0x01, 0xe3, 0x02, 0x2b, 0xf8, 0x15, 0x0a, 0x39, 0xa0,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009953 0xb4, 0x15, 0xfe, 0x31, 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, 0x02,
9954 0xd7, 0x42, 0xfe, 0x06, 0xec, 0xd0, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45,
9955 0x35, 0x42, 0xfe, 0x06, 0xea, 0xd0, 0xfe, 0x47, 0x4b, 0x91, 0xfe, 0x75,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009956 0x57, 0x03, 0x5d, 0xfe, 0x98, 0x56, 0xfe, 0x38, 0x12, 0x09, 0x48, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009957 0x0e, 0xfe, 0x44, 0x48, 0x4f, 0x08, 0x05, 0x1b, 0xfe, 0x1a, 0x13, 0x09,
9958 0x46, 0x01, 0x0e, 0x41, 0xfe, 0x41, 0x58, 0x09, 0xa4, 0x01, 0x0e, 0xfe,
9959 0x49, 0x54, 0x96, 0xfe, 0x1e, 0x0e, 0x02, 0xfe, 0x2e, 0x03, 0x09, 0x5d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009960 0xfe, 0xee, 0x14, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009961 0xce, 0x47, 0xfe, 0xad, 0x13, 0x02, 0x2b, 0x22, 0x20, 0x07, 0x11, 0xfe,
9962 0x9e, 0x12, 0x21, 0x13, 0x59, 0x13, 0x9f, 0x13, 0xd5, 0x22, 0x2f, 0x41,
9963 0x39, 0x2f, 0xbc, 0xad, 0xfe, 0xbc, 0xf0, 0xfe, 0xe0, 0x0e, 0x0f, 0x06,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009964 0x13, 0x59, 0x01, 0xfe, 0xda, 0x16, 0x03, 0xfe, 0x38, 0x01, 0x29, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009965 0x3a, 0x01, 0x56, 0xfe, 0xe4, 0x0e, 0xfe, 0x02, 0xec, 0xd5, 0x69, 0x00,
9966 0x66, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01,
9967 0x01, 0xfe, 0x4a, 0x17, 0xfe, 0x08, 0x90, 0xfe, 0x48, 0xf4, 0x0d, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009968 0x18, 0x13, 0xba, 0xfe, 0x02, 0xea, 0xd5, 0x69, 0x7e, 0xfe, 0xc5, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009969 0x15, 0x1a, 0x39, 0xa0, 0xb4, 0xfe, 0x2e, 0x10, 0x03, 0xfe, 0x38, 0x01,
9970 0x1e, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x03, 0xfe, 0x3a, 0x01,
9971 0x0c, 0xfe, 0x62, 0x01, 0x43, 0x13, 0x20, 0x25, 0x06, 0x13, 0x2f, 0x12,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009972 0x2f, 0x92, 0x0f, 0x06, 0x04, 0x21, 0x04, 0x22, 0x59, 0xfe, 0xf7, 0x12,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009973 0x22, 0x9f, 0xb7, 0x13, 0x9f, 0x07, 0x7e, 0xfe, 0x71, 0x13, 0xfe, 0x24,
9974 0x1c, 0x15, 0x19, 0x39, 0xa0, 0xb4, 0xfe, 0xd9, 0x10, 0xc3, 0xfe, 0x03,
9975 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xc3, 0xfe, 0x03, 0xdc,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009976 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x21,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009977 0xfe, 0x00, 0xcc, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x78, 0x04, 0x08, 0x05,
9978 0x58, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13,
9979 0xfe, 0x1e, 0x80, 0xed, 0xfe, 0x1d, 0x80, 0xae, 0xfe, 0x0c, 0x90, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009980 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xac, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009981 0x0a, 0xfe, 0x3c, 0x50, 0xaa, 0x01, 0xfe, 0x7a, 0x17, 0x32, 0x07, 0x2f,
9982 0xad, 0x01, 0xfe, 0xb4, 0x16, 0x08, 0x05, 0x1b, 0x4e, 0x01, 0xf5, 0x01,
9983 0xf6, 0x12, 0xfe, 0xe9, 0x00, 0x08, 0x05, 0x58, 0xfe, 0x2c, 0x13, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009984 0xfe, 0x0c, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009985 0x0c, 0xfe, 0x64, 0x01, 0x14, 0xfe, 0x66, 0x01, 0x08, 0x05, 0x5b, 0xfe,
9986 0x12, 0x12, 0xfe, 0x03, 0x80, 0x8d, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80,
9987 0x40, 0x13, 0x20, 0x6a, 0x2a, 0x12, 0xcf, 0x64, 0x22, 0x20, 0xfb, 0x79,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009988 0x20, 0x04, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009989 0x03, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe,
9990 0x08, 0x58, 0x03, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
9991 0x25, 0x6e, 0x13, 0xd0, 0x21, 0x0c, 0x5c, 0x0c, 0x45, 0x0f, 0x46, 0x52,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009992 0x50, 0x18, 0x1b, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xfe, 0xfc,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009993 0x0f, 0x44, 0x11, 0x0f, 0x48, 0x52, 0x18, 0x58, 0xfe, 0x90, 0x4d, 0xfe,
9994 0x91, 0x54, 0x23, 0xe4, 0x25, 0x11, 0x13, 0x20, 0x7c, 0x6f, 0x4f, 0x22,
9995 0x20, 0xfb, 0x79, 0x20, 0x12, 0xcf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009996 0xfe, 0x26, 0x10, 0xf8, 0x74, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009997 0x18, 0x1c, 0x04, 0x42, 0xfe, 0x0c, 0x14, 0xfc, 0xfe, 0x07, 0xe6, 0x1b,
9998 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x04, 0x01, 0xb0, 0x7c, 0x6f, 0x4f,
9999 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0x32, 0x07, 0x2f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010000 0xfe, 0x34, 0x13, 0x09, 0x48, 0x01, 0x0e, 0xbb, 0xfe, 0x36, 0x12, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010001 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe,
10002 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, 0x84, 0x01, 0x0e, 0xfe,
10003 0x80, 0x5c, 0x01, 0x73, 0xfe, 0x0e, 0x10, 0x07, 0x82, 0x4e, 0xfe, 0x14,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010004 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x60, 0x10, 0x04, 0xfe, 0x44, 0x58, 0x8d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010005 0xfe, 0x01, 0xec, 0xa2, 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe,
10006 0x9c, 0xe7, 0x1a, 0x79, 0x2a, 0x01, 0xe3, 0xfe, 0xdd, 0x10, 0x2c, 0xc7,
10007 0x81, 0xc8, 0x83, 0x33, 0x31, 0xde, 0x07, 0x1a, 0xfe, 0x48, 0x12, 0x07,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010008 0x0a, 0xfe, 0x56, 0x12, 0x07, 0x19, 0xfe, 0x30, 0x12, 0x07, 0xc9, 0x17,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010009 0xfe, 0x32, 0x12, 0x07, 0xfe, 0x23, 0x00, 0x17, 0xeb, 0x07, 0x06, 0x17,
10010 0xfe, 0x9c, 0x12, 0x07, 0x1f, 0xfe, 0x12, 0x12, 0x07, 0x00, 0x17, 0x24,
10011 0x15, 0xc9, 0x01, 0x36, 0xa9, 0x2d, 0x01, 0x0b, 0x94, 0x4b, 0x04, 0x2d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010012 0xdd, 0x09, 0xd1, 0x01, 0xfe, 0x26, 0x0f, 0x12, 0x82, 0x02, 0x2b, 0x2d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010013 0x32, 0x07, 0xa6, 0xfe, 0xd9, 0x13, 0x3a, 0x3d, 0x3b, 0x3e, 0x56, 0xfe,
10014 0xf0, 0x11, 0x08, 0x05, 0x5a, 0xfe, 0x72, 0x12, 0x9b, 0x2e, 0x9c, 0x3c,
10015 0x90, 0xc0, 0x96, 0xfe, 0xba, 0x11, 0x22, 0x62, 0xfe, 0x26, 0x13, 0x03,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010016 0x7f, 0x29, 0x80, 0x56, 0xfe, 0x76, 0x0d, 0x0c, 0x60, 0x14, 0x61, 0x21,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010017 0x0c, 0x7f, 0x0c, 0x80, 0x01, 0xb3, 0x25, 0x6e, 0x77, 0x13, 0x62, 0x01,
10018 0xef, 0x9b, 0x2e, 0x9c, 0x3c, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe,
10019 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0xfe, 0x91, 0x10, 0x03, 0x3f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010020 0x29, 0x40, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x3f, 0x14, 0x40,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010021 0x88, 0x9b, 0x2e, 0x9c, 0x3c, 0x90, 0xc0, 0x03, 0x5e, 0x29, 0x5f, 0xfe,
10022 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x0c, 0x5e, 0x14, 0x5f, 0x08, 0x05, 0x5a,
10023 0xfe, 0x1e, 0x12, 0x22, 0x62, 0xfe, 0x1f, 0x40, 0x03, 0x60, 0x29, 0x61,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010024 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x03, 0x3f, 0x29, 0x40, 0xfe, 0x44,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010025 0x50, 0xfe, 0xc6, 0x50, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x08, 0x50, 0xfe,
10026 0x8a, 0x50, 0x03, 0x3d, 0x29, 0x3e, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50,
10027 0x02, 0x89, 0x25, 0x06, 0x13, 0xd4, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010028 0x4c, 0x33, 0x31, 0xde, 0x07, 0x06, 0x23, 0x4c, 0x32, 0x07, 0xa6, 0x23,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010029 0x72, 0x01, 0xaf, 0x1e, 0x43, 0x17, 0x4c, 0x08, 0x05, 0x0a, 0xee, 0x3a,
10030 0x3d, 0x3b, 0x3e, 0xfe, 0x0a, 0x55, 0x35, 0xfe, 0x8b, 0x55, 0x57, 0x3d,
10031 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x02, 0x72, 0xfe, 0x19,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010032 0x81, 0xba, 0xfe, 0x19, 0x41, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1c, 0x34,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010033 0x1d, 0xe8, 0x33, 0x31, 0xe1, 0x55, 0x19, 0xfe, 0xa6, 0x12, 0x55, 0x0a,
10034 0x4d, 0x02, 0x4c, 0x01, 0x0b, 0x1c, 0x34, 0x1d, 0xe8, 0x33, 0x31, 0xdf,
10035 0x07, 0x19, 0x23, 0x4c, 0x01, 0x0b, 0x1d, 0xe8, 0x33, 0x31, 0xfe, 0xe8,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010036 0x09, 0xfe, 0xc2, 0x49, 0x51, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0x8a, 0x53,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010037 0x05, 0x1f, 0x35, 0xa9, 0xfe, 0xbb, 0x45, 0x55, 0x00, 0x4e, 0x44, 0x06,
10038 0x7c, 0x43, 0xfe, 0xda, 0x14, 0x01, 0xaf, 0x8c, 0xfe, 0x4b, 0x45, 0xee,
10039 0x32, 0x07, 0xa5, 0xed, 0x03, 0xcd, 0x28, 0x8a, 0x03, 0x45, 0x28, 0x35,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010040 0x67, 0x02, 0x72, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010041 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01,
10042 0xfe, 0x9e, 0x15, 0x02, 0x89, 0x01, 0x0b, 0x1c, 0x34, 0x1d, 0x4c, 0x33,
10043 0x31, 0xdf, 0x07, 0x06, 0x23, 0x4c, 0x01, 0xf1, 0xfe, 0x42, 0x58, 0xf1,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010044 0xfe, 0xa4, 0x14, 0x8c, 0xfe, 0x4a, 0xf4, 0x0a, 0x17, 0x4c, 0xfe, 0x4a,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010045 0xf4, 0x06, 0xea, 0x32, 0x07, 0xa5, 0x8b, 0x02, 0x72, 0x03, 0x45, 0xc1,
10046 0x0c, 0x45, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, 0xfe, 0xcc, 0x15,
10047 0x02, 0x89, 0x0f, 0x06, 0x27, 0xfe, 0xbe, 0x13, 0x26, 0xfe, 0xd4, 0x13,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010048 0x76, 0xfe, 0x89, 0x48, 0x01, 0x0b, 0x21, 0x76, 0x04, 0x7b, 0xfe, 0xd0,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010049 0x13, 0x1c, 0xfe, 0xd0, 0x13, 0x1d, 0xfe, 0xbe, 0x13, 0x67, 0x2d, 0x01,
10050 0x0b, 0xfe, 0xd5, 0x10, 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93,
10051 0x1e, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x04, 0x0f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010052 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0xfe, 0x30, 0x56,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010053 0xfe, 0x00, 0x5c, 0x04, 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93,
10054 0x04, 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0xfe, 0x0b, 0x58,
10055 0x04, 0x09, 0x5c, 0x01, 0x87, 0x09, 0x45, 0x01, 0x87, 0x04, 0xfe, 0x03,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010056 0xa1, 0x1e, 0x11, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x1f, 0x52,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010057 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c,
10058 0x6a, 0x2a, 0x0c, 0x5e, 0x14, 0x5f, 0x57, 0x3f, 0x7d, 0x40, 0x04, 0xdd,
10059 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x8d, 0x04, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010060 0xfe, 0x0c, 0x19, 0xfe, 0x42, 0x48, 0x50, 0x51, 0x91, 0x01, 0x0b, 0x1d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010061 0xfe, 0x96, 0x15, 0x33, 0x31, 0xe1, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15,
10062 0x33, 0x31, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x03, 0xcd, 0x28, 0xfe,
10063 0xcc, 0x12, 0x53, 0x05, 0x1a, 0xfe, 0xc4, 0x13, 0x21, 0x69, 0x1a, 0xee,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010064 0x55, 0xca, 0x6b, 0xfe, 0xdc, 0x14, 0x4d, 0x0f, 0x06, 0x18, 0xca, 0x7c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010065 0x30, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xab, 0xff, 0x02, 0x83,
10066 0x55, 0x69, 0x19, 0xae, 0x98, 0xfe, 0x30, 0x00, 0x96, 0xf2, 0x18, 0x6d,
10067 0x0f, 0x06, 0xfe, 0x56, 0x10, 0x69, 0x0a, 0xed, 0x98, 0xfe, 0x64, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010068 0x96, 0xf2, 0x09, 0xfe, 0x64, 0x00, 0x18, 0x9e, 0x0f, 0x06, 0xfe, 0x28,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010069 0x10, 0x69, 0x06, 0xfe, 0x60, 0x13, 0x98, 0xfe, 0xc8, 0x00, 0x96, 0xf2,
10070 0x09, 0xfe, 0xc8, 0x00, 0x18, 0x59, 0x0f, 0x06, 0x88, 0x98, 0xfe, 0x90,
10071 0x01, 0x7a, 0xfe, 0x42, 0x15, 0x91, 0xe4, 0xfe, 0x43, 0xf4, 0x9f, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010072 0x56, 0xf0, 0xfe, 0x54, 0x15, 0xfe, 0x04, 0xf4, 0x71, 0xfe, 0x43, 0xf4,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010073 0x9e, 0xfe, 0xf3, 0x10, 0xfe, 0x40, 0x5c, 0x01, 0xfe, 0x16, 0x14, 0x1e,
10074 0x43, 0xec, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x6e, 0x7a, 0xfe, 0x90,
10075 0x15, 0xc4, 0x6e, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010076 0xcc, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0xcc, 0x88, 0x51, 0x21, 0xfe, 0x4d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010077 0xf4, 0x00, 0xe9, 0x91, 0x0f, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58,
10078 0x04, 0x51, 0x0f, 0x0a, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xf3, 0x16,
10079 0x0a, 0x01, 0x0b, 0x26, 0xf3, 0x16, 0x19, 0x01, 0x0b, 0x26, 0xf3, 0x76,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010080 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010081 0x16, 0x19, 0x01, 0x0b, 0x26, 0xb1, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1,
10082 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x26, 0xb1, 0x76, 0xfe, 0x89, 0x4a, 0x01,
10083 0x0b, 0x04, 0x51, 0x04, 0x22, 0xd3, 0x07, 0x06, 0xfe, 0x48, 0x13, 0xb8,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010084 0x13, 0xd3, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x76, 0xa9, 0x67, 0xfe, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010085 0xec, 0xfe, 0x27, 0x01, 0xfe, 0x89, 0x48, 0xff, 0x02, 0x00, 0x10, 0x27,
10086 0xfe, 0x2e, 0x16, 0x32, 0x07, 0xfe, 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1d,
10087 0xfe, 0x52, 0x16, 0x21, 0x13, 0xd4, 0x01, 0x4b, 0x22, 0xd4, 0x07, 0x06,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010088 0x4e, 0x08, 0x54, 0x06, 0x37, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfb, 0x8e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010089 0x07, 0x11, 0xae, 0x09, 0x84, 0x01, 0x0e, 0x8e, 0x09, 0x5d, 0x01, 0xa8,
10090 0x04, 0x09, 0x84, 0x01, 0x0e, 0x8e, 0xfe, 0x80, 0xe7, 0x11, 0x07, 0x11,
10091 0x8a, 0xfe, 0x45, 0x58, 0x01, 0xf0, 0x8e, 0x04, 0x09, 0x48, 0x01, 0x0e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010092 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x80,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010093 0x80, 0xfe, 0x80, 0x4c, 0xfe, 0x49, 0xe4, 0x11, 0xae, 0x09, 0x84, 0x01,
10094 0x0e, 0xfe, 0x80, 0x4c, 0x09, 0x5d, 0x01, 0x87, 0x04, 0x18, 0x11, 0x75,
10095 0x6c, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010096 0x1c, 0xfe, 0x1d, 0xf7, 0x1b, 0x97, 0xfe, 0xee, 0x16, 0x01, 0xfe, 0xf4,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010097 0x17, 0xad, 0x9a, 0x1b, 0x6c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x04,
10098 0xb9, 0x23, 0xfe, 0xde, 0x16, 0xfe, 0xda, 0x10, 0x18, 0x11, 0x75, 0x03,
10099 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1f, 0xfe, 0x18, 0x58, 0x03, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010100 0x66, 0x01, 0xfe, 0x19, 0x58, 0x9a, 0x1f, 0xfe, 0x3c, 0x90, 0xfe, 0x30,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010101 0xf4, 0x06, 0xfe, 0x3c, 0x50, 0x6c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79,
10102 0xfe, 0x1c, 0xf7, 0x1f, 0x97, 0xfe, 0x38, 0x17, 0xfe, 0xb6, 0x14, 0x35,
10103 0x04, 0xb9, 0x23, 0xfe, 0x10, 0x17, 0xfe, 0x9c, 0x10, 0x18, 0x11, 0x75,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010104 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010105 0x2e, 0x97, 0xfe, 0x5a, 0x17, 0xfe, 0x94, 0x14, 0xec, 0x9a, 0x2e, 0x6c,
10106 0x1a, 0xfe, 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00, 0x04, 0xb9, 0x23, 0xfe,
10107 0x4e, 0x17, 0xfe, 0x6c, 0x10, 0x18, 0x11, 0x75, 0xfe, 0x30, 0xbc, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010108 0xb2, 0xbc, 0x9a, 0xcb, 0x6c, 0x1a, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010109 0xcb, 0x97, 0xfe, 0x92, 0x17, 0xfe, 0x5c, 0x14, 0x35, 0x04, 0xb9, 0x23,
10110 0xfe, 0x7e, 0x17, 0xfe, 0x42, 0x10, 0xfe, 0x02, 0xf6, 0x11, 0x75, 0xfe,
10111 0x18, 0xfe, 0x60, 0xfe, 0x19, 0xfe, 0x61, 0xfe, 0x03, 0xa1, 0xfe, 0x1d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010112 0xf7, 0x5b, 0x97, 0xfe, 0xb8, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010113 0x9a, 0x5b, 0x41, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7,
10114 0x11, 0xfe, 0x81, 0xe7, 0x11, 0x12, 0xfe, 0xdd, 0x00, 0x6a, 0x2a, 0x04,
10115 0x6a, 0x2a, 0xfe, 0x12, 0x45, 0x23, 0xfe, 0xa8, 0x17, 0x15, 0x06, 0x39,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010116 0xa0, 0xb4, 0x02, 0x2b, 0xfe, 0x39, 0xf0, 0xfe, 0xfc, 0x17, 0x21, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010117 0xfe, 0x7e, 0x18, 0x1e, 0x19, 0x66, 0x0f, 0x0d, 0x04, 0x75, 0x03, 0xd2,
10118 0x1e, 0x06, 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x7c, 0x6f, 0x4f, 0x32,
10119 0x07, 0x2f, 0xfe, 0x3c, 0x13, 0xf1, 0xfe, 0x42, 0x13, 0x42, 0x92, 0x09,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010120 0x48, 0x01, 0x0e, 0xbb, 0xeb, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010121 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11,
10122 0xac, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c, 0x01, 0x73, 0xfe, 0x16,
10123 0x10, 0x07, 0x82, 0x8b, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12, 0xfe, 0x14,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010124 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x1c, 0x18, 0x18, 0x0a, 0x04, 0xfe, 0x9c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010125 0xe7, 0x0a, 0x10, 0xfe, 0x15, 0x00, 0x64, 0x79, 0x2a, 0x01, 0xe3, 0x18,
10126 0x06, 0x04, 0x42, 0x92, 0x08, 0x54, 0x1b, 0x37, 0x12, 0x2f, 0x01, 0x73,
10127 0x18, 0x06, 0x04, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x3a, 0xce, 0x3b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010128 0xcf, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x04, 0x22, 0xa3, 0x77,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010129 0x13, 0xa3, 0x04, 0x09, 0xa4, 0x01, 0x0e, 0xfe, 0x41, 0x48, 0x09, 0x46,
10130 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x17, 0xfe, 0xe8, 0x18, 0x77, 0x78, 0x04,
10131 0x09, 0x48, 0x01, 0x0e, 0x07, 0x11, 0x4e, 0x09, 0x5d, 0x01, 0xa8, 0x09,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010132 0x46, 0x01, 0x0e, 0x77, 0x78, 0x04, 0xfe, 0x4e, 0xe4, 0x19, 0x6b, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010133 0x1c, 0x19, 0x03, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10,
10134 0xfe, 0x4e, 0xe4, 0xc9, 0x6b, 0xfe, 0x2e, 0x19, 0x03, 0xfe, 0x92, 0x00,
10135 0xfe, 0x02, 0xe6, 0x1a, 0xe5, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x6b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010136 0xfe, 0x40, 0x19, 0x03, 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x1f, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010137 0x08, 0x10, 0x03, 0xfe, 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x6d, 0xfe, 0x4e,
10138 0x45, 0xea, 0xba, 0xff, 0x04, 0x68, 0x54, 0xe7, 0x1e, 0x6e, 0xfe, 0x08,
10139 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe, 0x1a, 0xf4, 0xfe, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010140 0x04, 0xea, 0xfe, 0x48, 0xf4, 0x19, 0x7a, 0xfe, 0x74, 0x19, 0x0f, 0x19,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010141 0x04, 0x07, 0x7e, 0xfe, 0x5a, 0xf0, 0xfe, 0x84, 0x19, 0x25, 0xfe, 0x09,
10142 0x00, 0xfe, 0x34, 0x10, 0x07, 0x1a, 0xfe, 0x5a, 0xf0, 0xfe, 0x92, 0x19,
10143 0x25, 0xca, 0xfe, 0x26, 0x10, 0x07, 0x19, 0x66, 0x25, 0x6d, 0xe5, 0x07,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010144 0x0a, 0x66, 0x25, 0x9e, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x66, 0x25, 0x59,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010145 0xa9, 0xb8, 0x04, 0x15, 0xfe, 0x09, 0x00, 0x01, 0x36, 0xfe, 0x04, 0xfe,
10146 0x81, 0x03, 0x83, 0xfe, 0x40, 0x5c, 0x04, 0x1c, 0xf7, 0xfe, 0x14, 0xf0,
10147 0x0b, 0x27, 0xfe, 0xd6, 0x19, 0x1c, 0xf7, 0x7b, 0xf7, 0xfe, 0x82, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010148 0xfe, 0xda, 0x19, 0x04, 0xff, 0xcc, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070010149};
10150
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010151static unsigned short _adv_asc38C0800_size = sizeof(_adv_asc38C0800_buf); /* 0x14E1 */
10152static ADV_DCNT _adv_asc38C0800_chksum = 0x050D3FD8UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070010153
10154/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010155static unsigned char _adv_asc38C1600_buf[] = {
10156 0x00, 0x00, 0x00, 0xf2, 0x00, 0x16, 0x00, 0xfc, 0x00, 0x10, 0x00, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010157 0x18, 0xe4, 0x01, 0x00, 0x04, 0x1e, 0x48, 0xe4, 0x03, 0xf6, 0xf7, 0x13,
10158 0x2e, 0x1e, 0x02, 0x00, 0x07, 0x17, 0xc0, 0x5f, 0x00, 0xfa, 0xff, 0xff,
10159 0x04, 0x00, 0x00, 0xf6, 0x09, 0xe7, 0x82, 0xe7, 0x85, 0xf0, 0x86, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010160 0x4e, 0x10, 0x9e, 0xe7, 0xff, 0x00, 0x55, 0xf0, 0x01, 0xf6, 0x03, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010161 0x98, 0x57, 0x01, 0xe6, 0x00, 0xea, 0x00, 0xec, 0x01, 0xfa, 0x18, 0xf4,
10162 0x08, 0x00, 0xf0, 0x1d, 0x38, 0x54, 0x32, 0xf0, 0x10, 0x00, 0xc2, 0x0e,
10163 0x1e, 0xf0, 0xd5, 0xf0, 0xbc, 0x00, 0x4b, 0xe4, 0x00, 0xe6, 0xb1, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010164 0xb4, 0x00, 0x02, 0x13, 0x3e, 0x1c, 0xc8, 0x47, 0x3e, 0x00, 0xd8, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010165 0x06, 0x13, 0x0c, 0x1c, 0x5e, 0x1e, 0x00, 0x57, 0xc8, 0x57, 0x01, 0xfc,
10166 0xbc, 0x0e, 0xa2, 0x12, 0xb9, 0x54, 0x00, 0x80, 0x62, 0x0a, 0x5a, 0x12,
10167 0xc8, 0x15, 0x3e, 0x1e, 0x18, 0x40, 0xbd, 0x56, 0x03, 0xe6, 0x01, 0xea,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010168 0x5c, 0xf0, 0x0f, 0x00, 0x20, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010169 0x04, 0x13, 0xbb, 0x55, 0x3c, 0x56, 0x3e, 0x57, 0x03, 0x58, 0x4a, 0xe4,
10170 0x40, 0x00, 0xb6, 0x00, 0xbb, 0x00, 0xc0, 0x00, 0x00, 0x01, 0x01, 0x01,
10171 0x3e, 0x01, 0x58, 0x0a, 0x44, 0x10, 0x0a, 0x12, 0x4c, 0x1c, 0x4e, 0x1c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010172 0x02, 0x4a, 0x30, 0xe4, 0x05, 0xe6, 0x0c, 0x00, 0x3c, 0x00, 0x80, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010173 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01,
10174 0x74, 0x01, 0x76, 0x01, 0x78, 0x01, 0x7c, 0x01, 0xc6, 0x0e, 0x0c, 0x10,
10175 0xac, 0x12, 0xae, 0x12, 0x16, 0x1a, 0x32, 0x1c, 0x6e, 0x1e, 0x02, 0x48,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010176 0x3a, 0x55, 0xc9, 0x57, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x06, 0xf7,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010177 0x03, 0xfc, 0x06, 0x00, 0x1e, 0x00, 0xbe, 0x00, 0xe1, 0x00, 0x0c, 0x12,
10178 0x18, 0x1a, 0x70, 0x1a, 0x30, 0x1c, 0x38, 0x1c, 0x10, 0x44, 0x00, 0x4c,
10179 0xb0, 0x57, 0x40, 0x5c, 0x4d, 0xe4, 0x04, 0xea, 0x5d, 0xf0, 0xa7, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010180 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x09, 0x00, 0x19, 0x00, 0x32, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010181 0x33, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00, 0x9e, 0x00, 0xcc, 0x00,
10182 0x20, 0x01, 0x4e, 0x01, 0x79, 0x01, 0x3c, 0x09, 0x68, 0x0d, 0x02, 0x10,
10183 0x04, 0x10, 0x3a, 0x10, 0x08, 0x12, 0x0a, 0x13, 0x40, 0x16, 0x50, 0x16,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010184 0x00, 0x17, 0x4a, 0x19, 0x00, 0x4e, 0x00, 0x54, 0x01, 0x58, 0x00, 0xdc,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010185 0x05, 0xf0, 0x09, 0xf0, 0x59, 0xf0, 0xb8, 0xf0, 0x48, 0xf4, 0x0e, 0xf7,
10186 0x0a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00,
10187 0xd0, 0x00, 0xe7, 0x00, 0xf0, 0x03, 0x69, 0x08, 0xe9, 0x09, 0x5c, 0x0c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010188 0xb6, 0x12, 0xbc, 0x19, 0xd8, 0x1b, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010189 0x42, 0x1d, 0x08, 0x44, 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46,
10190 0x89, 0x48, 0x68, 0x54, 0x83, 0x55, 0x83, 0x59, 0x31, 0xe4, 0x02, 0xe6,
10191 0x07, 0xf0, 0x08, 0xf0, 0x0b, 0xf0, 0x0c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010192 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010193 0xa8, 0x00, 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0x22, 0x01,
10194 0x26, 0x01, 0x60, 0x01, 0x7a, 0x01, 0x82, 0x01, 0xc8, 0x01, 0xca, 0x01,
10195 0x86, 0x02, 0x6a, 0x03, 0x18, 0x05, 0xb2, 0x07, 0x68, 0x08, 0x10, 0x0d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010196 0x06, 0x10, 0x0a, 0x10, 0x0e, 0x10, 0x12, 0x10, 0x60, 0x10, 0xed, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010197 0xf3, 0x10, 0x06, 0x12, 0x10, 0x12, 0x1e, 0x12, 0x0c, 0x13, 0x0e, 0x13,
10198 0x10, 0x13, 0xfe, 0x9c, 0xf0, 0x35, 0x05, 0xfe, 0xec, 0x0e, 0xff, 0x10,
10199 0x00, 0x00, 0xe9, 0xfe, 0x34, 0x1f, 0x00, 0xe8, 0xfe, 0x88, 0x01, 0xff,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010200 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010201 0x00, 0xfe, 0x57, 0x24, 0x00, 0xfe, 0x4c, 0x00, 0x65, 0xff, 0x04, 0x00,
10202 0x00, 0x1a, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x08,
10203 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x13,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010204 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010205 0xfe, 0x04, 0xf7, 0xe8, 0x37, 0x7d, 0x0d, 0x01, 0xfe, 0x4a, 0x11, 0xfe,
10206 0x04, 0xf7, 0xe8, 0x7d, 0x0d, 0x51, 0x37, 0xfe, 0x3d, 0xf0, 0xfe, 0x0c,
10207 0x02, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x91, 0xf0, 0xfe, 0xf8, 0x01, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010208 0x90, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x8f, 0xf0, 0xbc, 0x03, 0x67, 0x4d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010209 0x05, 0xfe, 0x08, 0x0f, 0x01, 0xfe, 0x78, 0x0f, 0xfe, 0xdd, 0x12, 0x05,
10210 0xfe, 0x0e, 0x03, 0xfe, 0x28, 0x1c, 0x03, 0xfe, 0xa6, 0x00, 0xfe, 0xd1,
10211 0x12, 0x3e, 0x22, 0xfe, 0xa6, 0x00, 0xac, 0xfe, 0x48, 0xf0, 0xfe, 0x90,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010212 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0xaa, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc8,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010213 0x02, 0xfe, 0x46, 0xf0, 0xfe, 0x5a, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x60,
10214 0x02, 0xfe, 0x43, 0xf0, 0xfe, 0x4e, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x52,
10215 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x56, 0x02, 0x1c, 0x0d, 0xa2, 0x1c, 0x07,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010216 0x22, 0xb7, 0x05, 0x35, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010217 0x1c, 0xf5, 0xfe, 0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0x5f, 0xfe, 0xe7,
10218 0x10, 0xfe, 0x06, 0xfc, 0xde, 0x0a, 0x81, 0x01, 0xa3, 0x05, 0x35, 0x1f,
10219 0x95, 0x47, 0xb8, 0x01, 0xfe, 0xe4, 0x11, 0x0a, 0x81, 0x01, 0x5c, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010220 0xbd, 0x10, 0x0a, 0x81, 0x01, 0x5c, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010221 0xfe, 0x58, 0x1c, 0x1c, 0x07, 0x22, 0xb7, 0x37, 0x2a, 0x35, 0xfe, 0x3d,
10222 0xf0, 0xfe, 0x0c, 0x02, 0x2b, 0xfe, 0x9e, 0x02, 0xfe, 0x5a, 0x1c, 0xfe,
10223 0x12, 0x1c, 0xfe, 0x14, 0x1c, 0x1f, 0xfe, 0x30, 0x00, 0x47, 0xb8, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010224 0xfe, 0xd4, 0x11, 0x1c, 0x07, 0x22, 0xb7, 0x05, 0xe9, 0x21, 0x2c, 0x09,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010225 0x1a, 0x31, 0xfe, 0x69, 0x10, 0x1c, 0x07, 0x22, 0xb7, 0xfe, 0x04, 0xec,
10226 0x2c, 0x60, 0x01, 0xfe, 0x1e, 0x1e, 0x20, 0x2c, 0xfe, 0x05, 0xf6, 0xde,
10227 0x01, 0xfe, 0x62, 0x1b, 0x01, 0x0c, 0x61, 0x4a, 0x44, 0x15, 0x56, 0x51,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010228 0x01, 0xfe, 0x9e, 0x1e, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x0a, 0x57,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010229 0x01, 0x18, 0x09, 0x00, 0x36, 0x01, 0x85, 0xfe, 0x18, 0x10, 0xfe, 0x41,
10230 0x58, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0xc8, 0x54, 0x7b, 0xfe, 0x1c, 0x03,
10231 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x37, 0x60, 0xfe, 0x02, 0xe8, 0x30,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010232 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, 0x27, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010233 0xfe, 0xe4, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x40,
10234 0x1c, 0x2a, 0xeb, 0xfe, 0x26, 0xf0, 0xfe, 0x66, 0x03, 0xfe, 0xa0, 0xf0,
10235 0xfe, 0x54, 0x03, 0xfe, 0x11, 0xf0, 0xbc, 0xfe, 0xef, 0x10, 0xfe, 0x9f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010236 0xf0, 0xfe, 0x74, 0x03, 0xfe, 0x46, 0x1c, 0x19, 0xfe, 0x11, 0x00, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010237 0x70, 0x37, 0xfe, 0x48, 0x1c, 0xfe, 0x46, 0x1c, 0x01, 0x0c, 0x06, 0x28,
10238 0xfe, 0x18, 0x13, 0x26, 0x21, 0xb9, 0xc7, 0x20, 0xb9, 0x0a, 0x57, 0x01,
10239 0x18, 0xc7, 0x89, 0x01, 0xfe, 0xc8, 0x1a, 0x15, 0xe1, 0x2a, 0xeb, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010240 0x01, 0xf0, 0xeb, 0xfe, 0x82, 0xf0, 0xfe, 0xa4, 0x03, 0xfe, 0x9c, 0x32,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010241 0x15, 0xfe, 0xe4, 0x00, 0x2f, 0xfe, 0xb6, 0x03, 0x2a, 0x3c, 0x16, 0xfe,
10242 0xc6, 0x03, 0x01, 0x41, 0xfe, 0x06, 0xf0, 0xfe, 0xd6, 0x03, 0xaf, 0xa0,
10243 0xfe, 0x0a, 0xf0, 0xfe, 0xa2, 0x07, 0x05, 0x29, 0x03, 0x81, 0x1e, 0x1b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010244 0xfe, 0x24, 0x05, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010245 0xea, 0xfe, 0x46, 0x1c, 0x37, 0x7d, 0x1d, 0xfe, 0x67, 0x1b, 0xfe, 0xbf,
10246 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c, 0x75, 0x01, 0xa6, 0x86, 0x0a,
10247 0x57, 0x01, 0x18, 0x09, 0x00, 0x1b, 0xec, 0x0a, 0xe1, 0x01, 0x18, 0x77,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010248 0x50, 0x40, 0x8d, 0x30, 0x03, 0x81, 0x1e, 0xf8, 0x1f, 0x63, 0x01, 0x42,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010249 0x8f, 0xfe, 0x70, 0x02, 0x05, 0xea, 0xd7, 0x99, 0xd8, 0x9c, 0x2a, 0x29,
10250 0x2f, 0xfe, 0x4e, 0x04, 0x16, 0xfe, 0x4a, 0x04, 0x7e, 0xfe, 0xa0, 0x00,
10251 0xfe, 0x9b, 0x57, 0xfe, 0x54, 0x12, 0x32, 0xff, 0x02, 0x00, 0x10, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010252 0x08, 0x16, 0xfe, 0x02, 0x05, 0x32, 0x01, 0x08, 0x16, 0x29, 0x27, 0x25,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010253 0xee, 0xfe, 0x4c, 0x44, 0xfe, 0x58, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x13,
10254 0x34, 0xfe, 0x4c, 0x54, 0x7b, 0xec, 0x60, 0x8d, 0x30, 0x01, 0xfe, 0x4e,
10255 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x7c, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010256 0x32, 0x13, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x68, 0x13, 0xfe, 0x26, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010257 0x13, 0x34, 0xfe, 0x4c, 0x54, 0x7b, 0xec, 0x01, 0xfe, 0x4e, 0x1e, 0xfe,
10258 0x48, 0x47, 0xfe, 0x54, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xa5, 0x01, 0x43,
10259 0x09, 0x9b, 0xfe, 0x40, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xf9, 0x1f, 0x7f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010260 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, 0x8f,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010261 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x32, 0x15, 0xfe, 0xe6, 0x00, 0x0f, 0xfe,
10262 0x1c, 0x90, 0x04, 0xfe, 0x9c, 0x93, 0x3a, 0x0b, 0x0e, 0x8b, 0x02, 0x1f,
10263 0x7f, 0x01, 0x42, 0x05, 0x35, 0xfe, 0x42, 0x5b, 0x7d, 0x1d, 0xfe, 0x46,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010264 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0x0f, 0xfe, 0x87, 0x80, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010265 0xfe, 0x87, 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0xd0, 0x65, 0x01, 0x0c,
10266 0x06, 0x0d, 0xfe, 0x98, 0x13, 0x0f, 0xfe, 0x20, 0x80, 0x04, 0xfe, 0xa0,
10267 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x1d, 0xfe, 0x84, 0x12, 0x01, 0x38, 0x06,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010268 0x07, 0xfe, 0x70, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x1e, 0x1b, 0xfe, 0xda,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010269 0x05, 0xd0, 0x54, 0x01, 0x38, 0x06, 0x0d, 0xfe, 0x58, 0x13, 0x03, 0xfe,
10270 0xa0, 0x00, 0x1e, 0xfe, 0x50, 0x12, 0x5e, 0xff, 0x02, 0x00, 0x10, 0x2f,
10271 0xfe, 0x90, 0x05, 0x2a, 0x3c, 0xcc, 0xff, 0x02, 0x00, 0x10, 0x2f, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010272 0x9e, 0x05, 0x17, 0xfe, 0xf4, 0x05, 0x15, 0xfe, 0xe3, 0x00, 0x26, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010273 0x38, 0xfe, 0x4a, 0xf0, 0xfe, 0xc0, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0xba,
10274 0x05, 0x71, 0x2e, 0xfe, 0x21, 0x00, 0xf1, 0x2e, 0xfe, 0x22, 0x00, 0xa2,
10275 0x2e, 0x4a, 0xfe, 0x09, 0x48, 0xff, 0x02, 0x00, 0x10, 0x2f, 0xfe, 0xd0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010276 0x05, 0x17, 0xfe, 0xf4, 0x05, 0xfe, 0xe2, 0x08, 0x01, 0x38, 0x06, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010277 0x1c, 0x00, 0x4d, 0x01, 0xa7, 0x2e, 0x07, 0x20, 0xe4, 0x47, 0xfe, 0x27,
10278 0x01, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x24, 0x12, 0x3e, 0x01, 0x84, 0x1f,
10279 0x7f, 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010280 0x8f, 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x03, 0xe6, 0x1e, 0xfe, 0xca, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010281 0x03, 0xb6, 0x1e, 0xfe, 0x40, 0x12, 0x03, 0x66, 0x1e, 0xfe, 0x38, 0x13,
10282 0x3e, 0x01, 0x84, 0x17, 0xfe, 0x72, 0x06, 0x0a, 0x07, 0x01, 0x38, 0x06,
10283 0x24, 0xfe, 0x02, 0x12, 0x4f, 0x01, 0xfe, 0x56, 0x19, 0x16, 0xfe, 0x68,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010284 0x06, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x66, 0x8a, 0x10, 0x66,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010285 0x03, 0x9a, 0x1e, 0xfe, 0x70, 0x12, 0x03, 0x55, 0x1e, 0xfe, 0x68, 0x13,
10286 0x01, 0xc6, 0x09, 0x12, 0x48, 0xfe, 0x92, 0x06, 0x2e, 0x12, 0x01, 0xfe,
10287 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0x13, 0x58, 0xff, 0x02, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010288 0x57, 0x52, 0xad, 0x23, 0x3f, 0x4e, 0x62, 0x49, 0x3e, 0x01, 0x84, 0x17,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010289 0xfe, 0xea, 0x06, 0x01, 0x38, 0x06, 0x12, 0xf7, 0x45, 0x0a, 0x95, 0x01,
10290 0xfe, 0x84, 0x19, 0x16, 0xfe, 0xe0, 0x06, 0x15, 0x82, 0x01, 0x41, 0x15,
10291 0xe2, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x1c, 0x07, 0x01, 0x84, 0xfe, 0xae,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010292 0x10, 0x03, 0x6f, 0x1e, 0xfe, 0x9e, 0x13, 0x3e, 0x01, 0x84, 0x03, 0x9a,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010293 0x1e, 0xfe, 0x1a, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfc, 0x01, 0xc6, 0x01,
10294 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0xf0, 0x45, 0x0a, 0x95,
10295 0x03, 0xb6, 0x1e, 0xf8, 0x01, 0x38, 0x06, 0x24, 0x36, 0xfe, 0x02, 0xf6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010296 0x07, 0x71, 0x78, 0x8c, 0x00, 0x4d, 0x62, 0x49, 0x3e, 0x2d, 0x93, 0x4e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010297 0xd0, 0x0d, 0x17, 0xfe, 0x9a, 0x07, 0x01, 0xfe, 0xc0, 0x19, 0x16, 0xfe,
10298 0x90, 0x07, 0x26, 0x20, 0x9e, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x21,
10299 0x9e, 0x09, 0x07, 0xfb, 0x03, 0xe6, 0xfe, 0x58, 0x57, 0x10, 0xe6, 0x05,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010300 0xfe, 0x2a, 0x06, 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x1c, 0x07, 0x01, 0x84,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010301 0xfe, 0x9c, 0x32, 0x5f, 0x75, 0x01, 0xa6, 0x86, 0x15, 0xfe, 0xe2, 0x00,
10302 0x2f, 0xed, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe, 0xce, 0x07, 0xae, 0xfe,
10303 0x96, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x9e, 0x08, 0xaf, 0xa0, 0x05, 0x29,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010304 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x2e, 0x12, 0x14, 0x1d, 0x01, 0x08, 0x14,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010305 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0xfe,
10306 0x99, 0xa4, 0x01, 0x08, 0x14, 0x00, 0x05, 0xfe, 0xc6, 0x09, 0x01, 0x76,
10307 0x06, 0x12, 0xfe, 0x3a, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x30, 0x13,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010308 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010309 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x07, 0x01, 0x08, 0x14, 0x00,
10310 0x05, 0xef, 0x7c, 0x4a, 0x78, 0x4f, 0x0f, 0xfe, 0x9a, 0x81, 0x04, 0xfe,
10311 0x9a, 0x83, 0xfe, 0xcb, 0x47, 0x0b, 0x0e, 0x2d, 0x28, 0x48, 0xfe, 0x6c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010312 0x08, 0x0a, 0x28, 0xfe, 0x09, 0x6f, 0xca, 0xfe, 0xca, 0x45, 0xfe, 0x32,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010313 0x12, 0x53, 0x63, 0x4e, 0x7c, 0x97, 0x2f, 0xfe, 0x7e, 0x08, 0x2a, 0x3c,
10314 0xfe, 0x0a, 0xf0, 0xfe, 0x6c, 0x08, 0xaf, 0xa0, 0xae, 0xfe, 0x96, 0x08,
10315 0x05, 0x29, 0x01, 0x41, 0x05, 0xed, 0x14, 0x24, 0x05, 0xed, 0xfe, 0x9c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010316 0xf7, 0x9f, 0x01, 0xfe, 0xae, 0x1e, 0xfe, 0x18, 0x58, 0x01, 0xfe, 0xbe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010317 0x1e, 0xfe, 0x99, 0x58, 0xfe, 0x78, 0x18, 0xfe, 0xf9, 0x18, 0x8e, 0xfe,
10318 0x16, 0x09, 0x10, 0x6a, 0x22, 0x6b, 0x01, 0x0c, 0x61, 0x54, 0x44, 0x21,
10319 0x2c, 0x09, 0x1a, 0xf8, 0x77, 0x01, 0xfe, 0x7e, 0x1e, 0x47, 0x2c, 0x7a,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010320 0x30, 0xf0, 0xfe, 0x83, 0xe7, 0xfe, 0x3f, 0x00, 0x71, 0xfe, 0x03, 0x40,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010321 0x01, 0x0c, 0x61, 0x65, 0x44, 0x01, 0xc2, 0xc8, 0xfe, 0x1f, 0x40, 0x20,
10322 0x6e, 0x01, 0xfe, 0x6a, 0x16, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe,
10323 0x44, 0x51, 0xfe, 0xc6, 0x51, 0xfe, 0x10, 0x10, 0x01, 0xfe, 0xce, 0x1e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010324 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x01, 0xfe, 0xee, 0x1e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010325 0x01, 0xfe, 0xfe, 0x1e, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x10, 0x4b,
10326 0x22, 0x4c, 0xfe, 0x8a, 0x10, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0x50, 0x12,
10327 0x01, 0xfe, 0xae, 0x1e, 0x01, 0xfe, 0xbe, 0x1e, 0x10, 0x6a, 0x22, 0x6b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010328 0x01, 0x0c, 0x06, 0x65, 0x4e, 0x01, 0xc2, 0x0f, 0xfe, 0x1f, 0x80, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010329 0xfe, 0x9f, 0x83, 0x33, 0x0b, 0x0e, 0x20, 0x6e, 0x0f, 0xfe, 0x44, 0x90,
10330 0x04, 0xfe, 0xc4, 0x93, 0x3a, 0x0b, 0xfe, 0xc6, 0x90, 0x04, 0xfe, 0xc6,
10331 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x6c, 0x22, 0x6d, 0x01, 0xfe, 0xce, 0x1e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010332 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x0f, 0xfe, 0x40, 0x90,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010333 0x04, 0xfe, 0xc0, 0x93, 0x3a, 0x0b, 0xfe, 0xc2, 0x90, 0x04, 0xfe, 0xc2,
10334 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x4b, 0x22, 0x4c, 0x10, 0x64, 0x22, 0x34,
10335 0x01, 0x0c, 0x61, 0x24, 0x44, 0x37, 0x13, 0xfe, 0x4e, 0x11, 0x2f, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010336 0xde, 0x09, 0xfe, 0x9e, 0xf0, 0xfe, 0xf2, 0x09, 0xfe, 0x01, 0x48, 0x1b,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010337 0x3c, 0x37, 0x88, 0xf5, 0xd4, 0xfe, 0x1e, 0x0a, 0xd5, 0xfe, 0x42, 0x0a,
10338 0xd2, 0xfe, 0x1e, 0x0a, 0xd3, 0xfe, 0x42, 0x0a, 0xae, 0xfe, 0x12, 0x0a,
10339 0xfe, 0x06, 0xf0, 0xfe, 0x18, 0x0a, 0xaf, 0xa0, 0x05, 0x29, 0x01, 0x41,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010340 0xfe, 0xc1, 0x10, 0x14, 0x24, 0xfe, 0xc1, 0x10, 0x01, 0x76, 0x06, 0x07,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010341 0xfe, 0x14, 0x12, 0x01, 0x76, 0x06, 0x0d, 0x5d, 0x01, 0x0c, 0x06, 0x0d,
10342 0xfe, 0x74, 0x12, 0xfe, 0x2e, 0x1c, 0x05, 0xfe, 0x1a, 0x0c, 0x01, 0x76,
10343 0x06, 0x07, 0x5d, 0x01, 0x76, 0x06, 0x0d, 0x41, 0xfe, 0x2c, 0x1c, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010344 0xaa, 0xf0, 0xfe, 0xce, 0x0a, 0xfe, 0xac, 0xf0, 0xfe, 0x66, 0x0a, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010345 0x92, 0x10, 0xc4, 0xf6, 0xfe, 0xad, 0xf0, 0xfe, 0x72, 0x0a, 0x05, 0xfe,
10346 0x1a, 0x0c, 0xc5, 0xfe, 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0xbf, 0xfe, 0x6b,
10347 0x18, 0x23, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12, 0xac, 0xfe, 0xd2, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010348 0xbf, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x1b, 0xbf, 0x03, 0xe3, 0x23, 0x07,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010349 0x1b, 0xbf, 0xd4, 0x5b, 0xd5, 0x5b, 0xd2, 0x5b, 0xd3, 0x5b, 0xc4, 0xc5,
10350 0xfe, 0xa9, 0x10, 0x75, 0x5e, 0x32, 0x1f, 0x7f, 0x01, 0x42, 0x19, 0xfe,
10351 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x70, 0x19, 0x98, 0x05, 0x70, 0xfe, 0x74,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010352 0x18, 0x23, 0xfe, 0x00, 0xf8, 0x1b, 0x5b, 0x7d, 0x12, 0x01, 0xfe, 0x78,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010353 0x0f, 0x4d, 0x01, 0xfe, 0x96, 0x1a, 0x21, 0x30, 0x77, 0x7d, 0x1d, 0x05,
10354 0x5b, 0x01, 0x0c, 0x06, 0x0d, 0x2b, 0xfe, 0xe2, 0x0b, 0x01, 0x0c, 0x06,
10355 0x54, 0xfe, 0xa6, 0x12, 0x01, 0x0c, 0x06, 0x24, 0xfe, 0x88, 0x13, 0x21,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010356 0x6e, 0xc7, 0x01, 0xfe, 0x1e, 0x1f, 0x0f, 0xfe, 0x83, 0x80, 0x04, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010357 0x83, 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0xfe, 0xc8, 0x44, 0xfe, 0x42,
10358 0x13, 0x0f, 0xfe, 0x04, 0x91, 0x04, 0xfe, 0x84, 0x93, 0xfe, 0xca, 0x57,
10359 0x0b, 0xfe, 0x86, 0x91, 0x04, 0xfe, 0x86, 0x93, 0xfe, 0xcb, 0x57, 0x0b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010360 0x0e, 0x7a, 0x30, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x8e, 0x40, 0x03,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010361 0x6a, 0x3b, 0x6b, 0x10, 0x97, 0x22, 0x98, 0xd9, 0x6a, 0xda, 0x6b, 0x01,
10362 0xc2, 0xc8, 0x7a, 0x30, 0x20, 0x6e, 0xdb, 0x64, 0xdc, 0x34, 0x91, 0x6c,
10363 0x7e, 0x6d, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55, 0xfe, 0x04, 0xfa, 0x64,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010364 0xfe, 0x05, 0xfa, 0x34, 0x01, 0xfe, 0x6a, 0x16, 0xa3, 0x26, 0x10, 0x97,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010365 0x10, 0x98, 0x91, 0x6c, 0x7e, 0x6d, 0xfe, 0x14, 0x10, 0x01, 0x0c, 0x06,
10366 0x24, 0x1b, 0x40, 0x91, 0x4b, 0x7e, 0x4c, 0x01, 0x0c, 0x06, 0xfe, 0xf7,
10367 0x00, 0x44, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010368 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x24,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010369 0x1b, 0x40, 0x01, 0x0c, 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x78, 0x01, 0xfe,
10370 0x8e, 0x1e, 0x4f, 0x0f, 0xfe, 0x10, 0x90, 0x04, 0xfe, 0x90, 0x93, 0x3a,
10371 0x0b, 0xfe, 0x92, 0x90, 0x04, 0xfe, 0x92, 0x93, 0x79, 0x0b, 0x0e, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010372 0xbd, 0x10, 0x01, 0x43, 0x09, 0xbb, 0x1b, 0xfe, 0x6e, 0x0a, 0x15, 0xbb,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010373 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x14, 0x13, 0x03, 0x4b, 0x3b, 0x4c, 0x8e,
10374 0xfe, 0x6e, 0x0a, 0xfe, 0x0c, 0x58, 0xfe, 0x8d, 0x58, 0x05, 0x5b, 0x26,
10375 0x3e, 0x0f, 0xfe, 0x19, 0x80, 0x04, 0xfe, 0x99, 0x83, 0x33, 0x0b, 0x0e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010376 0xfe, 0xe5, 0x10, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1a, 0x12, 0xfe, 0x6c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010377 0x19, 0xfe, 0x19, 0x41, 0xfe, 0x6b, 0x18, 0xac, 0xfe, 0xd1, 0xf0, 0xef,
10378 0x1f, 0x92, 0x01, 0x42, 0x19, 0xfe, 0x44, 0x00, 0xfe, 0x90, 0x10, 0xfe,
10379 0x6c, 0x19, 0xd9, 0x4b, 0xfe, 0xed, 0x19, 0xda, 0x4c, 0xfe, 0x0c, 0x51,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010380 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xff, 0x31, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010381 0x76, 0x10, 0xac, 0xfe, 0xd2, 0xf0, 0xfe, 0xba, 0x0c, 0xfe, 0x76, 0x18,
10382 0x23, 0x1d, 0x5d, 0x03, 0xe3, 0x23, 0x07, 0xfe, 0x08, 0x13, 0x19, 0xfe,
10383 0x16, 0x00, 0x05, 0x70, 0xfe, 0xd1, 0xf0, 0xfe, 0xcc, 0x0c, 0x1f, 0x92,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010384 0x01, 0x42, 0x19, 0xfe, 0x17, 0x00, 0x5c, 0xfe, 0xce, 0xf0, 0xfe, 0xd2,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010385 0x0c, 0xfe, 0x3e, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xde, 0x0c, 0x19, 0xfe,
10386 0x22, 0x00, 0x05, 0x70, 0xfe, 0xcb, 0xf0, 0xfe, 0xea, 0x0c, 0x19, 0xfe,
10387 0x24, 0x00, 0x05, 0x70, 0xfe, 0xd0, 0xf0, 0xfe, 0xf4, 0x0c, 0x19, 0x94,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010388 0xfe, 0x1c, 0x10, 0xfe, 0xcf, 0xf0, 0xfe, 0xfe, 0x0c, 0x19, 0x4a, 0xf3,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010389 0xfe, 0xcc, 0xf0, 0xef, 0x01, 0x76, 0x06, 0x24, 0x4d, 0x19, 0xfe, 0x12,
10390 0x00, 0x37, 0x13, 0xfe, 0x4e, 0x11, 0x2f, 0xfe, 0x16, 0x0d, 0xfe, 0x9e,
10391 0xf0, 0xfe, 0x2a, 0x0d, 0xfe, 0x01, 0x48, 0x1b, 0x3c, 0x37, 0x88, 0xf5,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010392 0xd4, 0x29, 0xd5, 0x29, 0xd2, 0x29, 0xd3, 0x29, 0x37, 0xfe, 0x9c, 0x32,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010393 0x2f, 0xfe, 0x3e, 0x0d, 0x2a, 0x3c, 0xae, 0xfe, 0x62, 0x0d, 0xaf, 0xa0,
10394 0xd4, 0x9f, 0xd5, 0x9f, 0xd2, 0x9f, 0xd3, 0x9f, 0x05, 0x29, 0x01, 0x41,
10395 0xfe, 0xd3, 0x10, 0x15, 0xfe, 0xe8, 0x00, 0xc4, 0xc5, 0x75, 0xd7, 0x99,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010396 0xd8, 0x9c, 0xfe, 0x89, 0xf0, 0x29, 0x27, 0x25, 0xbe, 0xd7, 0x99, 0xd8,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010397 0x9c, 0x2f, 0xfe, 0x8c, 0x0d, 0x16, 0x29, 0x27, 0x25, 0xbd, 0xfe, 0x01,
10398 0x48, 0xa4, 0x19, 0xfe, 0x42, 0x00, 0x05, 0x70, 0x90, 0x07, 0xfe, 0x81,
10399 0x49, 0x1b, 0xfe, 0x64, 0x0e, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x44, 0x13,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010400 0x19, 0x00, 0x2d, 0x0d, 0xfe, 0x54, 0x12, 0x2d, 0xfe, 0x28, 0x00, 0x2b,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010401 0xfe, 0xda, 0x0e, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, 0x36, 0x46, 0xfe,
10402 0x28, 0x00, 0xfe, 0xfa, 0x10, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe, 0x00,
10403 0x1d, 0x0a, 0xba, 0x01, 0xfe, 0x58, 0x10, 0x40, 0x15, 0x56, 0x01, 0x85,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010404 0x05, 0x35, 0x19, 0xfe, 0x44, 0x00, 0x2d, 0x0d, 0xf7, 0x46, 0x0d, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010405 0xcc, 0x10, 0x01, 0xa7, 0x46, 0x0d, 0xfe, 0xc2, 0x10, 0x01, 0xa7, 0x0f,
10406 0xfe, 0x19, 0x82, 0x04, 0xfe, 0x99, 0x83, 0xfe, 0xcc, 0x47, 0x0b, 0x0e,
10407 0xfe, 0x34, 0x46, 0xa5, 0x46, 0x0d, 0x19, 0xfe, 0x43, 0x00, 0xfe, 0xa2,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010408 0x10, 0x01, 0x0c, 0x61, 0x0d, 0x44, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010409 0x00, 0x1d, 0x40, 0x15, 0x56, 0x01, 0x85, 0x7d, 0x0d, 0x40, 0x51, 0x01,
10410 0xfe, 0x9e, 0x1e, 0x05, 0xfe, 0x3a, 0x03, 0x01, 0x0c, 0x06, 0x0d, 0x5d,
10411 0x46, 0x0d, 0x19, 0x00, 0xfe, 0x62, 0x10, 0x01, 0x76, 0x06, 0x12, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010412 0x5c, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x52, 0x13, 0xfe, 0x1c, 0x1c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010413 0xfe, 0x9d, 0xf0, 0xfe, 0x8e, 0x0e, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0,
10414 0xfe, 0x94, 0x0e, 0x01, 0x0c, 0x61, 0x12, 0x44, 0xfe, 0x9f, 0x10, 0x19,
10415 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0d, 0x4f, 0xfe, 0x2e, 0x10, 0x19,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010416 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x19, 0xfe, 0x47, 0x00, 0xf1, 0x19,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010417 0xfe, 0x41, 0x00, 0xa2, 0x19, 0xfe, 0x24, 0x00, 0x86, 0xc4, 0xc5, 0x75,
10418 0x03, 0x81, 0x1e, 0x2b, 0xea, 0x4f, 0xfe, 0x04, 0xe6, 0x12, 0xfe, 0x9d,
10419 0x41, 0xfe, 0x1c, 0x42, 0x40, 0x01, 0xf4, 0x05, 0x35, 0xfe, 0x12, 0x1c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010420 0x1f, 0x0d, 0x47, 0xb5, 0xc3, 0x1f, 0xfe, 0x31, 0x00, 0x47, 0xb8, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010421 0xfe, 0xd4, 0x11, 0x05, 0xe9, 0x51, 0xfe, 0x06, 0xec, 0xe0, 0xfe, 0x0e,
10422 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0x06, 0xea, 0xe0,
10423 0xfe, 0x47, 0x4b, 0x45, 0xfe, 0x75, 0x57, 0x03, 0x67, 0xfe, 0x98, 0x56,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010424 0xfe, 0x38, 0x12, 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x44, 0x48, 0x60, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010425 0x0c, 0x06, 0x28, 0xfe, 0x18, 0x13, 0x0a, 0x57, 0x01, 0x18, 0x3e, 0xfe,
10426 0x41, 0x58, 0x0a, 0xba, 0xfe, 0xfa, 0x14, 0xfe, 0x49, 0x54, 0xb0, 0xfe,
10427 0x5e, 0x0f, 0x05, 0xfe, 0x3a, 0x03, 0x0a, 0x67, 0xfe, 0xe0, 0x14, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010428 0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0xce, 0x47,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010429 0xfe, 0xad, 0x13, 0x05, 0x35, 0x21, 0x2c, 0x09, 0x1a, 0xfe, 0x98, 0x12,
10430 0x26, 0x20, 0x96, 0x20, 0xe7, 0xfe, 0x08, 0x1c, 0xfe, 0x7c, 0x19, 0xfe,
10431 0xfd, 0x19, 0xfe, 0x0a, 0x1c, 0x03, 0xe5, 0xfe, 0x48, 0x55, 0xa5, 0x3b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010432 0xfe, 0x62, 0x01, 0xfe, 0xc9, 0x55, 0x31, 0xfe, 0x74, 0x10, 0x01, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010433 0xf0, 0x1a, 0x03, 0xfe, 0x38, 0x01, 0x3b, 0xfe, 0x3a, 0x01, 0x8e, 0xfe,
10434 0x1e, 0x10, 0xfe, 0x02, 0xec, 0xe7, 0x53, 0x00, 0x36, 0xfe, 0x04, 0xec,
10435 0x2c, 0x60, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x62, 0x1b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010436 0x01, 0xfe, 0xce, 0x1e, 0xb2, 0x11, 0xfe, 0x18, 0x13, 0xca, 0xfe, 0x02,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010437 0xea, 0xe7, 0x53, 0x92, 0xfe, 0xc3, 0x13, 0x1f, 0x12, 0x47, 0xb5, 0xc3,
10438 0xfe, 0x2a, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x23, 0xfe, 0xf0, 0xff, 0x10,
10439 0xe5, 0x03, 0xfe, 0x3a, 0x01, 0x10, 0xfe, 0x62, 0x01, 0x01, 0xfe, 0x1e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010440 0x1e, 0x20, 0x2c, 0x15, 0x56, 0x01, 0xfe, 0x9e, 0x1e, 0x13, 0x07, 0x02,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010441 0x26, 0x02, 0x21, 0x96, 0xc7, 0x20, 0x96, 0x09, 0x92, 0xfe, 0x79, 0x13,
10442 0x1f, 0x1d, 0x47, 0xb5, 0xc3, 0xfe, 0xe1, 0x10, 0xcf, 0xfe, 0x03, 0xdc,
10443 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xcf, 0xfe, 0x03, 0xdc, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010444 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x26, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010445 0x00, 0xcc, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x89, 0x02, 0x01, 0x0c, 0x06,
10446 0x4a, 0xfe, 0x4e, 0x13, 0x0f, 0xfe, 0x1c, 0x80, 0x04, 0xfe, 0x9c, 0x83,
10447 0x33, 0x0b, 0x0e, 0x09, 0x07, 0xfe, 0x3a, 0x13, 0x0f, 0xfe, 0x1e, 0x80,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010448 0x04, 0xfe, 0x9e, 0x83, 0x33, 0x0b, 0x0e, 0xfe, 0x2a, 0x13, 0x0f, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010449 0x1d, 0x80, 0x04, 0xfe, 0x9d, 0x83, 0xfe, 0xf9, 0x13, 0x0e, 0xfe, 0x1c,
10450 0x13, 0x01, 0xfe, 0xee, 0x1e, 0xac, 0xfe, 0x14, 0x13, 0x01, 0xfe, 0xfe,
10451 0x1e, 0xfe, 0x81, 0x58, 0xfa, 0x01, 0xfe, 0x0e, 0x1f, 0xfe, 0x30, 0xf4,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010452 0x0d, 0xfe, 0x3c, 0x50, 0xa2, 0x01, 0xfe, 0x92, 0x1b, 0x01, 0x43, 0x09,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010453 0x56, 0xfb, 0x01, 0xfe, 0xc8, 0x1a, 0x01, 0x0c, 0x06, 0x28, 0xa4, 0x01,
10454 0xfe, 0xf4, 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x15, 0xfe, 0xe9, 0x00, 0x01,
10455 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x01, 0xfe, 0x22, 0x1b, 0xfe, 0x1e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010456 0x1c, 0x0f, 0xfe, 0x14, 0x90, 0x04, 0xfe, 0x94, 0x93, 0x3a, 0x0b, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010457 0x96, 0x90, 0x04, 0xfe, 0x96, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0xfe, 0x64,
10458 0x01, 0x22, 0xfe, 0x66, 0x01, 0x01, 0x0c, 0x06, 0x65, 0xf9, 0x0f, 0xfe,
10459 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b, 0x0e, 0x77, 0xfe, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010460 0xec, 0x2c, 0xfe, 0x80, 0x40, 0x20, 0x2c, 0x7a, 0x30, 0x15, 0xdf, 0x40,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010461 0x21, 0x2c, 0xfe, 0x00, 0x40, 0x8d, 0x2c, 0x02, 0xfe, 0x08, 0x1c, 0x03,
10462 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58, 0x03, 0xfe, 0xae, 0x00, 0xfe, 0x07,
10463 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe, 0xb2, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010464 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x2e, 0x49, 0x20, 0xe0, 0x26, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010465 0x66, 0x10, 0x55, 0x10, 0x6f, 0x13, 0x57, 0x52, 0x4f, 0x1c, 0x28, 0xfe,
10466 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x2b, 0xfe, 0x88, 0x11, 0x46, 0x1a, 0x13,
10467 0x5a, 0x52, 0x1c, 0x4a, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x2b, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010468 0x9e, 0x11, 0x2e, 0x1a, 0x20, 0x2c, 0x90, 0x34, 0x60, 0x21, 0x2c, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010469 0x00, 0x40, 0x8d, 0x2c, 0x15, 0xdf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0,
10470 0xfe, 0xb2, 0x11, 0xfe, 0x12, 0x1c, 0x75, 0xfe, 0x14, 0x1c, 0xfe, 0x10,
10471 0x1c, 0xfe, 0x18, 0x1c, 0x02, 0x51, 0xfe, 0x0c, 0x14, 0xfe, 0x0e, 0x47,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010472 0xfe, 0x07, 0xe6, 0x28, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x02, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010473 0xa7, 0x90, 0x34, 0x60, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42,
10474 0x13, 0xfe, 0x02, 0x80, 0x09, 0x56, 0xfe, 0x34, 0x13, 0x0a, 0x5a, 0x01,
10475 0x18, 0xcb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010476 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, 0x89,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010477 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x5c, 0x01, 0x85,
10478 0xf2, 0x09, 0x9b, 0xa4, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xec,
10479 0x11, 0x02, 0xfe, 0x44, 0x58, 0x77, 0xfe, 0x01, 0xec, 0xb8, 0xfe, 0x9e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010480 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x12, 0x8d, 0x30, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010481 0xf4, 0xfe, 0xdd, 0x10, 0x37, 0xd7, 0x99, 0xd8, 0x9c, 0x27, 0x25, 0xee,
10482 0x09, 0x12, 0xfe, 0x48, 0x12, 0x09, 0x0d, 0xfe, 0x56, 0x12, 0x09, 0x1d,
10483 0xfe, 0x30, 0x12, 0x09, 0xdd, 0x1b, 0xfe, 0xc4, 0x13, 0x09, 0xfe, 0x23,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010484 0x00, 0x1b, 0xfe, 0xd0, 0x13, 0x09, 0x07, 0x1b, 0xfe, 0x34, 0x14, 0x09,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010485 0x24, 0xfe, 0x12, 0x12, 0x09, 0x00, 0x1b, 0x29, 0x1f, 0xdd, 0x01, 0x42,
10486 0xa1, 0x32, 0x01, 0x08, 0xae, 0x41, 0x02, 0x32, 0xfe, 0x62, 0x08, 0x0a,
10487 0xe1, 0x01, 0xfe, 0x58, 0x10, 0x15, 0x9b, 0x05, 0x35, 0x32, 0x01, 0x43,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010488 0x09, 0xbb, 0xfe, 0xd7, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0x8e, 0xfe, 0x80,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010489 0x13, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0x72, 0x12, 0xdb, 0x64, 0xdc, 0x34,
10490 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55, 0xb0, 0xfe, 0x4a, 0x13, 0x21, 0x6e,
10491 0xfe, 0x26, 0x13, 0x03, 0x97, 0x3b, 0x98, 0x8e, 0xfe, 0xb6, 0x0e, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010492 0x6a, 0x22, 0x6b, 0x26, 0x10, 0x97, 0x10, 0x98, 0x01, 0xc2, 0x2e, 0x49,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010493 0x88, 0x20, 0x6e, 0x01, 0xfe, 0x6a, 0x16, 0xdb, 0x64, 0xdc, 0x34, 0xfe,
10494 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x64, 0xfe, 0x05, 0xfa,
10495 0x34, 0xfe, 0x8f, 0x10, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x40, 0x56, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010496 0xe1, 0x56, 0x10, 0x6c, 0x22, 0x6d, 0x71, 0xdb, 0x64, 0xdc, 0x34, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010497 0x44, 0x55, 0xfe, 0xe5, 0x55, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x00, 0x56,
10498 0xfe, 0xa1, 0x56, 0x10, 0x68, 0x22, 0x69, 0x01, 0x0c, 0x06, 0x54, 0xf9,
10499 0x21, 0x6e, 0xfe, 0x1f, 0x40, 0x03, 0x6a, 0x3b, 0x6b, 0xfe, 0x2c, 0x50,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010500 0xfe, 0xae, 0x50, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x44, 0x50, 0xfe, 0xc6,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010501 0x50, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03,
10502 0x4b, 0x3b, 0x4c, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x05, 0x73, 0x2e,
10503 0x07, 0x20, 0x9e, 0x05, 0x72, 0x32, 0x01, 0x08, 0x16, 0x3d, 0x27, 0x25,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010504 0xee, 0x09, 0x07, 0x2b, 0x3d, 0x01, 0x43, 0x09, 0xbb, 0x2b, 0x72, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010505 0xa6, 0x23, 0x3f, 0x1b, 0x3d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1e, 0x13,
10506 0x91, 0x4b, 0x7e, 0x4c, 0xfe, 0x0a, 0x55, 0x31, 0xfe, 0x8b, 0x55, 0xd9,
10507 0x4b, 0xda, 0x4c, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x05, 0x72, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010508 0xfe, 0x8e, 0x1e, 0xca, 0xfe, 0x19, 0x41, 0x05, 0x72, 0x32, 0x01, 0x08,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010509 0x2a, 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbe, 0x2d, 0x1d, 0xc0, 0x2d, 0x0d,
10510 0x83, 0x2d, 0x7f, 0x1b, 0xfe, 0x66, 0x15, 0x05, 0x3d, 0x01, 0x08, 0x2a,
10511 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbd, 0x09, 0x1d, 0x2b, 0x3d, 0x01, 0x08,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010512 0x16, 0xc0, 0x27, 0x25, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x50, 0x03,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010513 0xb6, 0x1e, 0x83, 0x01, 0x38, 0x06, 0x24, 0x31, 0xa1, 0xfe, 0xbb, 0x45,
10514 0x2d, 0x00, 0xa4, 0x46, 0x07, 0x90, 0x3f, 0x01, 0xfe, 0xf8, 0x15, 0x01,
10515 0xa6, 0x86, 0xfe, 0x4b, 0x45, 0xfe, 0x20, 0x13, 0x01, 0x43, 0x09, 0x82,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010516 0xfe, 0x16, 0x13, 0x03, 0x9a, 0x1e, 0x5d, 0x03, 0x55, 0x1e, 0x31, 0x5e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010517 0x05, 0x72, 0xfe, 0xc0, 0x5d, 0x01, 0xa7, 0xfe, 0x03, 0x17, 0x03, 0x66,
10518 0x8a, 0x10, 0x66, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01, 0xfe, 0x56,
10519 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d, 0x27, 0x25, 0xbd,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010520 0x09, 0x07, 0x2b, 0x3d, 0x01, 0xfe, 0xbe, 0x16, 0xfe, 0x42, 0x58, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010521 0xe8, 0x14, 0x01, 0xa6, 0x86, 0xfe, 0x4a, 0xf4, 0x0d, 0x1b, 0x3d, 0xfe,
10522 0x4a, 0xf4, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09, 0x82, 0x4e, 0x05,
10523 0x72, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010524 0x01, 0xfe, 0x84, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010525 0x27, 0x25, 0xbd, 0x09, 0x12, 0x2b, 0x3d, 0x01, 0xfe, 0xe8, 0x17, 0x8b,
10526 0xfe, 0xaa, 0x14, 0xfe, 0xb6, 0x14, 0x86, 0xa8, 0xb2, 0x0d, 0x1b, 0x3d,
10527 0xb2, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09, 0x82, 0x4e, 0x05, 0x72,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010528 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010529 0xfe, 0xc0, 0x19, 0x05, 0x73, 0x13, 0x07, 0x2f, 0xfe, 0xcc, 0x15, 0x17,
10530 0xfe, 0xe2, 0x15, 0x5f, 0xcc, 0x01, 0x08, 0x26, 0x5f, 0x02, 0x8f, 0xfe,
10531 0xde, 0x15, 0x2a, 0xfe, 0xde, 0x15, 0x16, 0xfe, 0xcc, 0x15, 0x5e, 0x32,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010532 0x01, 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010533 0xad, 0x23, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02,
10534 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xad, 0x23, 0x3f, 0xfe, 0x30,
10535 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010536 0xad, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xfe, 0x00, 0x5e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010537 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xad, 0xfe, 0x0b, 0x58,
10538 0x02, 0x0a, 0x66, 0x01, 0x5c, 0x0a, 0x55, 0x01, 0x5c, 0x0a, 0x6f, 0x01,
10539 0x5c, 0x02, 0x01, 0xfe, 0x1e, 0x1f, 0x23, 0x1a, 0xff, 0x03, 0x00, 0x54,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010540 0xfe, 0x00, 0xf4, 0x24, 0x52, 0x0f, 0xfe, 0x00, 0x7c, 0x04, 0xfe, 0x07,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010541 0x7c, 0x3a, 0x0b, 0x0e, 0xfe, 0x00, 0x71, 0xfe, 0xf9, 0x18, 0xfe, 0x7a,
10542 0x19, 0xfe, 0xfb, 0x19, 0xfe, 0x1a, 0xf7, 0x00, 0xfe, 0x1b, 0xf7, 0x00,
10543 0x7a, 0x30, 0x10, 0x68, 0x22, 0x69, 0xd9, 0x6c, 0xda, 0x6d, 0x02, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010544 0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x77,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010545 0x02, 0x01, 0xc6, 0xfe, 0x42, 0x48, 0x4f, 0x50, 0x45, 0x01, 0x08, 0x16,
10546 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xbe, 0x01, 0x08, 0x16, 0xfe, 0xe0, 0x17,
10547 0x27, 0x25, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x03, 0x9a, 0x1e, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010548 0xda, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfe, 0xd0, 0x13, 0x26, 0x53, 0x12,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010549 0x48, 0xfe, 0x08, 0x17, 0xd1, 0x12, 0x53, 0x12, 0xfe, 0x1e, 0x13, 0x2d,
10550 0xb4, 0x7b, 0xfe, 0x26, 0x17, 0x4d, 0x13, 0x07, 0x1c, 0xb4, 0x90, 0x04,
10551 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xf1, 0xff, 0x02, 0x83, 0x55,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010552 0x53, 0x1d, 0xfe, 0x12, 0x13, 0xd6, 0xfe, 0x30, 0x00, 0xb0, 0xfe, 0x80,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010553 0x17, 0x1c, 0x63, 0x13, 0x07, 0xfe, 0x56, 0x10, 0x53, 0x0d, 0xfe, 0x16,
10554 0x13, 0xd6, 0xfe, 0x64, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0x64,
10555 0x00, 0x1c, 0x94, 0x13, 0x07, 0xfe, 0x28, 0x10, 0x53, 0x07, 0xfe, 0x60,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010556 0x13, 0xd6, 0xfe, 0xc8, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0xc8,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010557 0x00, 0x1c, 0x95, 0x13, 0x07, 0x71, 0xd6, 0xfe, 0x90, 0x01, 0x48, 0xfe,
10558 0x8c, 0x17, 0x45, 0xf3, 0xfe, 0x43, 0xf4, 0x96, 0xfe, 0x56, 0xf0, 0xfe,
10559 0x9e, 0x17, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x43, 0xf4, 0x94, 0xf6, 0x8b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010560 0x01, 0xfe, 0x24, 0x16, 0x23, 0x3f, 0xfc, 0xa8, 0x8c, 0x49, 0x48, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010561 0xda, 0x17, 0x62, 0x49, 0xfe, 0x1c, 0x10, 0xa8, 0x8c, 0x80, 0x48, 0xfe,
10562 0xda, 0x17, 0x62, 0x80, 0x71, 0x50, 0x26, 0xfe, 0x4d, 0xf4, 0x00, 0xf7,
10563 0x45, 0x13, 0x07, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x02, 0x50, 0x13,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010564 0x0d, 0x02, 0x50, 0x3e, 0x78, 0x4f, 0x45, 0x01, 0x08, 0x16, 0xa9, 0x27,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010565 0x25, 0xbe, 0xfe, 0x03, 0xea, 0xfe, 0x7e, 0x01, 0x01, 0x08, 0x16, 0xa9,
10566 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe,
10567 0xe9, 0x0a, 0xfe, 0x05, 0xea, 0xfe, 0x7f, 0x01, 0x01, 0x08, 0x16, 0xa9,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010568 0x27, 0x25, 0xfe, 0x69, 0x09, 0xfe, 0x02, 0xea, 0xfe, 0x80, 0x01, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010569 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, 0xe8, 0x08, 0x47, 0xfe, 0x81, 0x01,
10570 0x03, 0xb6, 0x1e, 0x83, 0x01, 0x38, 0x06, 0x24, 0x31, 0xa2, 0x78, 0xf2,
10571 0x53, 0x07, 0x36, 0xfe, 0x34, 0xf4, 0x3f, 0xa1, 0x78, 0x03, 0x9a, 0x1e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010572 0x83, 0x01, 0x38, 0x06, 0x12, 0x31, 0xf0, 0x4f, 0x45, 0xfe, 0x90, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010573 0xfe, 0x40, 0x5a, 0x23, 0x3f, 0xfb, 0x8c, 0x49, 0x48, 0xfe, 0xaa, 0x18,
10574 0x62, 0x49, 0x71, 0x8c, 0x80, 0x48, 0xfe, 0xaa, 0x18, 0x62, 0x80, 0xfe,
10575 0xb4, 0x56, 0xfe, 0x40, 0x5d, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010576 0x02, 0x17, 0xfe, 0xc8, 0x45, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0, 0x18, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010577 0x43, 0x48, 0x2d, 0x93, 0x36, 0xfe, 0x34, 0xf4, 0xfe, 0x00, 0x11, 0xfe,
10578 0x40, 0x10, 0x2d, 0xb4, 0x36, 0xfe, 0x34, 0xf4, 0x04, 0xfe, 0x34, 0x10,
10579 0x2d, 0xfe, 0x0b, 0x00, 0x36, 0x46, 0x63, 0xfe, 0x28, 0x10, 0xfe, 0xc0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010580 0x49, 0xff, 0x02, 0x00, 0x54, 0xb2, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0xfa,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010581 0x18, 0x45, 0xfe, 0x1c, 0xf4, 0x3f, 0xf3, 0xfe, 0x40, 0xf4, 0x96, 0xfe,
10582 0x56, 0xf0, 0xfe, 0x0c, 0x19, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x40, 0xf4,
10583 0x94, 0xf6, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d, 0x21, 0xfe, 0x7f, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010584 0xfe, 0xc8, 0x46, 0xfe, 0x24, 0x13, 0x8c, 0x00, 0x5d, 0x26, 0x21, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010585 0x7e, 0x01, 0xfe, 0xc8, 0x45, 0xfe, 0x14, 0x13, 0x21, 0xfe, 0x80, 0x01,
10586 0xfe, 0x48, 0x45, 0xfa, 0x21, 0xfe, 0x81, 0x01, 0xfe, 0xc8, 0x44, 0x4e,
10587 0x26, 0x02, 0x13, 0x07, 0x02, 0x78, 0x45, 0x50, 0x13, 0x0d, 0x02, 0x14,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010588 0x07, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, 0x0d, 0x01, 0x08, 0x17,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010589 0xfe, 0x82, 0x19, 0x14, 0x1d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x5f,
10590 0xfe, 0x89, 0x49, 0x01, 0x08, 0x02, 0x14, 0x07, 0x01, 0x08, 0x17, 0xc1,
10591 0x14, 0x1d, 0x01, 0x08, 0x17, 0xc1, 0x14, 0x07, 0x01, 0x08, 0x17, 0xc1,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010592 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0xc1, 0x5f, 0xfe, 0x89, 0x4a, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010593 0x08, 0x02, 0x50, 0x02, 0x14, 0x07, 0x01, 0x08, 0x17, 0x74, 0x14, 0x7f,
10594 0x01, 0x08, 0x17, 0x74, 0x14, 0x12, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x89,
10595 0x49, 0x01, 0x08, 0x17, 0x74, 0x14, 0x00, 0x01, 0x08, 0x17, 0x74, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010596 0x89, 0x4a, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x09, 0x49, 0x01, 0x08, 0x17,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010597 0x74, 0x5f, 0xcc, 0x01, 0x08, 0x02, 0x21, 0xe4, 0x09, 0x07, 0xfe, 0x4c,
10598 0x13, 0xc8, 0x20, 0xe4, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x5f, 0xa1, 0x5e,
10599 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xcc, 0xff, 0x02, 0x00, 0x10, 0x2f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010600 0xfe, 0x3e, 0x1a, 0x01, 0x43, 0x09, 0xfe, 0xe3, 0x00, 0xfe, 0x22, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010601 0x16, 0xfe, 0x64, 0x1a, 0x26, 0x20, 0x9e, 0x01, 0x41, 0x21, 0x9e, 0x09,
10602 0x07, 0x5d, 0x01, 0x0c, 0x61, 0x07, 0x44, 0x02, 0x0a, 0x5a, 0x01, 0x18,
10603 0xfe, 0x00, 0x40, 0xaa, 0x09, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010604 0x18, 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x9d, 0x01, 0x18, 0xaa,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010605 0xfe, 0x80, 0xe7, 0x1a, 0x09, 0x1a, 0x5d, 0xfe, 0x45, 0x58, 0x01, 0xfe,
10606 0xb2, 0x16, 0xaa, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0xaa, 0x0a, 0x67, 0x01,
10607 0xa3, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x01, 0xfe, 0x7e, 0x1e, 0xfe, 0x80,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010608 0x4c, 0xfe, 0x49, 0xe4, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, 0x18,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010609 0xfe, 0x80, 0x4c, 0x0a, 0x67, 0x01, 0x5c, 0x02, 0x1c, 0x1a, 0x87, 0x7c,
10610 0xe5, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24, 0x1c, 0xfe, 0x1d,
10611 0xf7, 0x28, 0xb1, 0xfe, 0x04, 0x1b, 0x01, 0xfe, 0x2a, 0x1c, 0xfa, 0xb3,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010612 0x28, 0x7c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x02, 0xc9, 0x2b, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010613 0xf4, 0x1a, 0xfe, 0xfa, 0x10, 0x1c, 0x1a, 0x87, 0x03, 0xfe, 0x64, 0x01,
10614 0xfe, 0x00, 0xf4, 0x24, 0xfe, 0x18, 0x58, 0x03, 0xfe, 0x66, 0x01, 0xfe,
10615 0x19, 0x58, 0xb3, 0x24, 0x01, 0xfe, 0x0e, 0x1f, 0xfe, 0x30, 0xf4, 0x07,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010616 0xfe, 0x3c, 0x50, 0x7c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010617 0xf7, 0x24, 0xb1, 0xfe, 0x50, 0x1b, 0xfe, 0xd4, 0x14, 0x31, 0x02, 0xc9,
10618 0x2b, 0xfe, 0x26, 0x1b, 0xfe, 0xba, 0x10, 0x1c, 0x1a, 0x87, 0xfe, 0x83,
10619 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x54, 0xb1,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010620 0xfe, 0x72, 0x1b, 0xfe, 0xb2, 0x14, 0xfc, 0xb3, 0x54, 0x7c, 0x12, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010621 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00, 0x02, 0xc9, 0x2b, 0xfe, 0x66, 0x1b,
10622 0xfe, 0x8a, 0x10, 0x1c, 0x1a, 0x87, 0x8b, 0x0f, 0xfe, 0x30, 0x90, 0x04,
10623 0xfe, 0xb0, 0x93, 0x3a, 0x0b, 0xfe, 0x18, 0x58, 0xfe, 0x32, 0x90, 0x04,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010624 0xfe, 0xb2, 0x93, 0x3a, 0x0b, 0xfe, 0x19, 0x58, 0x0e, 0xa8, 0xb3, 0x4a,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010625 0x7c, 0x12, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x4a, 0xb1, 0xfe, 0xc6,
10626 0x1b, 0xfe, 0x5e, 0x14, 0x31, 0x02, 0xc9, 0x2b, 0xfe, 0x96, 0x1b, 0x5c,
10627 0xfe, 0x02, 0xf6, 0x1a, 0x87, 0xfe, 0x18, 0xfe, 0x6a, 0xfe, 0x19, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010628 0x6b, 0x01, 0xfe, 0x1e, 0x1f, 0xfe, 0x1d, 0xf7, 0x65, 0xb1, 0xfe, 0xee,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010629 0x1b, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0xb3, 0x65, 0x3e, 0xfe, 0x83,
10630 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x1a, 0xfe, 0x81, 0xe7, 0x1a,
10631 0x15, 0xfe, 0xdd, 0x00, 0x7a, 0x30, 0x02, 0x7a, 0x30, 0xfe, 0x12, 0x45,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010632 0x2b, 0xfe, 0xdc, 0x1b, 0x1f, 0x07, 0x47, 0xb5, 0xc3, 0x05, 0x35, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010633 0x39, 0xf0, 0x75, 0x26, 0x02, 0xfe, 0x7e, 0x18, 0x23, 0x1d, 0x36, 0x13,
10634 0x11, 0x02, 0x87, 0x03, 0xe3, 0x23, 0x07, 0xfe, 0xef, 0x12, 0xfe, 0xe1,
10635 0x10, 0x90, 0x34, 0x60, 0xfe, 0x02, 0x80, 0x09, 0x56, 0xfe, 0x3c, 0x13,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010636 0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x51, 0xfe, 0x06, 0x83, 0x0a, 0x5a,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010637 0x01, 0x18, 0xcb, 0xfe, 0x3e, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48,
10638 0x01, 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f,
10639 0x89, 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x4c, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010640 0x85, 0xfe, 0x16, 0x10, 0x09, 0x9b, 0x4e, 0xfe, 0x40, 0x14, 0xfe, 0x24,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010641 0x12, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x52, 0x1c, 0x1c, 0x0d,
10642 0x02, 0xfe, 0x9c, 0xe7, 0x0d, 0x19, 0xfe, 0x15, 0x00, 0x40, 0x8d, 0x30,
10643 0x01, 0xf4, 0x1c, 0x07, 0x02, 0x51, 0xfe, 0x06, 0x83, 0xfe, 0x18, 0x80,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010644 0x61, 0x28, 0x44, 0x15, 0x56, 0x01, 0x85, 0x1c, 0x07, 0x02, 0xfe, 0x38,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010645 0x90, 0xfe, 0xba, 0x90, 0x91, 0xde, 0x7e, 0xdf, 0xfe, 0x48, 0x55, 0x31,
10646 0xfe, 0xc9, 0x55, 0x02, 0x21, 0xb9, 0x88, 0x20, 0xb9, 0x02, 0x0a, 0xba,
10647 0x01, 0x18, 0xfe, 0x41, 0x48, 0x0a, 0x57, 0x01, 0x18, 0xfe, 0x49, 0x44,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010648 0x1b, 0xfe, 0x1e, 0x1d, 0x88, 0x89, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x09,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010649 0x1a, 0xa4, 0x0a, 0x67, 0x01, 0xa3, 0x0a, 0x57, 0x01, 0x18, 0x88, 0x89,
10650 0x02, 0xfe, 0x4e, 0xe4, 0x1d, 0x7b, 0xfe, 0x52, 0x1d, 0x03, 0xfe, 0x90,
10651 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xdd, 0x7b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010652 0xfe, 0x64, 0x1d, 0x03, 0xfe, 0x92, 0x00, 0xd1, 0x12, 0xfe, 0x1a, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010653 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x7b, 0xfe, 0x76, 0x1d, 0x03, 0xfe,
10654 0x94, 0x00, 0xd1, 0x24, 0xfe, 0x08, 0x10, 0x03, 0xfe, 0x96, 0x00, 0xd1,
10655 0x63, 0xfe, 0x4e, 0x45, 0x83, 0xca, 0xff, 0x04, 0x68, 0x54, 0xfe, 0xf1,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010656 0x10, 0x23, 0x49, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010657 0xfe, 0x1a, 0xf4, 0xfe, 0x00, 0x04, 0x83, 0xb2, 0x1d, 0x48, 0xfe, 0xaa,
10658 0x1d, 0x13, 0x1d, 0x02, 0x09, 0x92, 0xfe, 0x5a, 0xf0, 0xfe, 0xba, 0x1d,
10659 0x2e, 0x93, 0xfe, 0x34, 0x10, 0x09, 0x12, 0xfe, 0x5a, 0xf0, 0xfe, 0xc8,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010660 0x1d, 0x2e, 0xb4, 0xfe, 0x26, 0x10, 0x09, 0x1d, 0x36, 0x2e, 0x63, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010661 0x1a, 0x10, 0x09, 0x0d, 0x36, 0x2e, 0x94, 0xf2, 0x09, 0x07, 0x36, 0x2e,
10662 0x95, 0xa1, 0xc8, 0x02, 0x1f, 0x93, 0x01, 0x42, 0xfe, 0x04, 0xfe, 0x99,
10663 0x03, 0x9c, 0x8b, 0x02, 0x2a, 0xfe, 0x1c, 0x1e, 0xfe, 0x14, 0xf0, 0x08,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010664 0x2f, 0xfe, 0x0c, 0x1e, 0x2a, 0xfe, 0x1c, 0x1e, 0x8f, 0xfe, 0x1c, 0x1e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010665 0xfe, 0x82, 0xf0, 0xfe, 0x10, 0x1e, 0x02, 0x0f, 0x3f, 0x04, 0xfe, 0x80,
10666 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x18, 0x80, 0x04, 0xfe, 0x98,
10667 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x02, 0x80, 0x04, 0xfe, 0x82,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010668 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x80, 0x04, 0xfe, 0x86,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010669 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x1b, 0x80, 0x04, 0xfe, 0x9b,
10670 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x04, 0x80, 0x04, 0xfe, 0x84,
10671 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x80, 0x80, 0x04, 0xfe, 0x80,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010672 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x19, 0x81, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010673 0xfe, 0x99, 0x83, 0xfe, 0xca, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06,
10674 0x83, 0x04, 0xfe, 0x86, 0x83, 0xfe, 0xce, 0x47, 0x0b, 0x0e, 0x02, 0x0f,
10675 0xfe, 0x2c, 0x90, 0x04, 0xfe, 0xac, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010676 0xfe, 0xae, 0x90, 0x04, 0xfe, 0xae, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010677 0xfe, 0x08, 0x90, 0x04, 0xfe, 0x88, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f,
10678 0xfe, 0x8a, 0x90, 0x04, 0xfe, 0x8a, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
10679 0xfe, 0x0c, 0x90, 0x04, 0xfe, 0x8c, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010680 0xfe, 0x8e, 0x90, 0x04, 0xfe, 0x8e, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010681 0xfe, 0x3c, 0x90, 0x04, 0xfe, 0xbc, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x8b,
10682 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b, 0x77, 0x0e,
10683 0xa8, 0x02, 0xff, 0x66, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070010684};
10685
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010686static unsigned short _adv_asc38C1600_size = sizeof(_adv_asc38C1600_buf); /* 0x1673 */
10687static ADV_DCNT _adv_asc38C1600_chksum = 0x0604EF77UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070010688
Linus Torvalds1da177e2005-04-16 15:20:36 -070010689/*
10690 * EEPROM Configuration.
10691 *
10692 * All drivers should use this structure to set the default EEPROM
10693 * configuration. The BIOS now uses this structure when it is built.
10694 * Additional structure information can be found in a_condor.h where
10695 * the structure is defined.
10696 *
10697 * The *_Field_IsChar structs are needed to correct for endianness.
10698 * These values are read from the board 16 bits at a time directly
10699 * into the structs. Because some fields are char, the values will be
10700 * in the wrong order. The *_Field_IsChar tells when to flip the
10701 * bytes. Data read and written to PCI memory is automatically swapped
10702 * on big-endian platforms so char fields read as words are actually being
10703 * unswapped on big-endian platforms.
10704 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010705static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010706 ADV_EEPROM_BIOS_ENABLE, /* cfg_lsw */
10707 0x0000, /* cfg_msw */
10708 0xFFFF, /* disc_enable */
10709 0xFFFF, /* wdtr_able */
10710 0xFFFF, /* sdtr_able */
10711 0xFFFF, /* start_motor */
10712 0xFFFF, /* tagqng_able */
10713 0xFFFF, /* bios_scan */
10714 0, /* scam_tolerant */
10715 7, /* adapter_scsi_id */
10716 0, /* bios_boot_delay */
10717 3, /* scsi_reset_delay */
10718 0, /* bios_id_lun */
10719 0, /* termination */
10720 0, /* reserved1 */
10721 0xFFE7, /* bios_ctrl */
10722 0xFFFF, /* ultra_able */
10723 0, /* reserved2 */
10724 ASC_DEF_MAX_HOST_QNG, /* max_host_qng */
10725 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
10726 0, /* dvc_cntl */
10727 0, /* bug_fix */
10728 0, /* serial_number_word1 */
10729 0, /* serial_number_word2 */
10730 0, /* serial_number_word3 */
10731 0, /* check_sum */
10732 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
10733 , /* oem_name[16] */
10734 0, /* dvc_err_code */
10735 0, /* adv_err_code */
10736 0, /* adv_err_addr */
10737 0, /* saved_dvc_err_code */
10738 0, /* saved_adv_err_code */
10739 0, /* saved_adv_err_addr */
10740 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070010741};
10742
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010743static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010744 0, /* cfg_lsw */
10745 0, /* cfg_msw */
10746 0, /* -disc_enable */
10747 0, /* wdtr_able */
10748 0, /* sdtr_able */
10749 0, /* start_motor */
10750 0, /* tagqng_able */
10751 0, /* bios_scan */
10752 0, /* scam_tolerant */
10753 1, /* adapter_scsi_id */
10754 1, /* bios_boot_delay */
10755 1, /* scsi_reset_delay */
10756 1, /* bios_id_lun */
10757 1, /* termination */
10758 1, /* reserved1 */
10759 0, /* bios_ctrl */
10760 0, /* ultra_able */
10761 0, /* reserved2 */
10762 1, /* max_host_qng */
10763 1, /* max_dvc_qng */
10764 0, /* dvc_cntl */
10765 0, /* bug_fix */
10766 0, /* serial_number_word1 */
10767 0, /* serial_number_word2 */
10768 0, /* serial_number_word3 */
10769 0, /* check_sum */
10770 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
10771 , /* oem_name[16] */
10772 0, /* dvc_err_code */
10773 0, /* adv_err_code */
10774 0, /* adv_err_addr */
10775 0, /* saved_dvc_err_code */
10776 0, /* saved_adv_err_code */
10777 0, /* saved_adv_err_addr */
10778 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070010779};
10780
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010781static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010782 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
10783 0x0000, /* 01 cfg_msw */
10784 0xFFFF, /* 02 disc_enable */
10785 0xFFFF, /* 03 wdtr_able */
10786 0x4444, /* 04 sdtr_speed1 */
10787 0xFFFF, /* 05 start_motor */
10788 0xFFFF, /* 06 tagqng_able */
10789 0xFFFF, /* 07 bios_scan */
10790 0, /* 08 scam_tolerant */
10791 7, /* 09 adapter_scsi_id */
10792 0, /* bios_boot_delay */
10793 3, /* 10 scsi_reset_delay */
10794 0, /* bios_id_lun */
10795 0, /* 11 termination_se */
10796 0, /* termination_lvd */
10797 0xFFE7, /* 12 bios_ctrl */
10798 0x4444, /* 13 sdtr_speed2 */
10799 0x4444, /* 14 sdtr_speed3 */
10800 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
10801 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
10802 0, /* 16 dvc_cntl */
10803 0x4444, /* 17 sdtr_speed4 */
10804 0, /* 18 serial_number_word1 */
10805 0, /* 19 serial_number_word2 */
10806 0, /* 20 serial_number_word3 */
10807 0, /* 21 check_sum */
10808 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
10809 , /* 22-29 oem_name[16] */
10810 0, /* 30 dvc_err_code */
10811 0, /* 31 adv_err_code */
10812 0, /* 32 adv_err_addr */
10813 0, /* 33 saved_dvc_err_code */
10814 0, /* 34 saved_adv_err_code */
10815 0, /* 35 saved_adv_err_addr */
10816 0, /* 36 reserved */
10817 0, /* 37 reserved */
10818 0, /* 38 reserved */
10819 0, /* 39 reserved */
10820 0, /* 40 reserved */
10821 0, /* 41 reserved */
10822 0, /* 42 reserved */
10823 0, /* 43 reserved */
10824 0, /* 44 reserved */
10825 0, /* 45 reserved */
10826 0, /* 46 reserved */
10827 0, /* 47 reserved */
10828 0, /* 48 reserved */
10829 0, /* 49 reserved */
10830 0, /* 50 reserved */
10831 0, /* 51 reserved */
10832 0, /* 52 reserved */
10833 0, /* 53 reserved */
10834 0, /* 54 reserved */
10835 0, /* 55 reserved */
10836 0, /* 56 cisptr_lsw */
10837 0, /* 57 cisprt_msw */
10838 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
10839 PCI_DEVICE_ID_38C0800_REV1, /* 59 subsysid */
10840 0, /* 60 reserved */
10841 0, /* 61 reserved */
10842 0, /* 62 reserved */
10843 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070010844};
10845
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010846static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010847 0, /* 00 cfg_lsw */
10848 0, /* 01 cfg_msw */
10849 0, /* 02 disc_enable */
10850 0, /* 03 wdtr_able */
10851 0, /* 04 sdtr_speed1 */
10852 0, /* 05 start_motor */
10853 0, /* 06 tagqng_able */
10854 0, /* 07 bios_scan */
10855 0, /* 08 scam_tolerant */
10856 1, /* 09 adapter_scsi_id */
10857 1, /* bios_boot_delay */
10858 1, /* 10 scsi_reset_delay */
10859 1, /* bios_id_lun */
10860 1, /* 11 termination_se */
10861 1, /* termination_lvd */
10862 0, /* 12 bios_ctrl */
10863 0, /* 13 sdtr_speed2 */
10864 0, /* 14 sdtr_speed3 */
10865 1, /* 15 max_host_qng */
10866 1, /* max_dvc_qng */
10867 0, /* 16 dvc_cntl */
10868 0, /* 17 sdtr_speed4 */
10869 0, /* 18 serial_number_word1 */
10870 0, /* 19 serial_number_word2 */
10871 0, /* 20 serial_number_word3 */
10872 0, /* 21 check_sum */
10873 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
10874 , /* 22-29 oem_name[16] */
10875 0, /* 30 dvc_err_code */
10876 0, /* 31 adv_err_code */
10877 0, /* 32 adv_err_addr */
10878 0, /* 33 saved_dvc_err_code */
10879 0, /* 34 saved_adv_err_code */
10880 0, /* 35 saved_adv_err_addr */
10881 0, /* 36 reserved */
10882 0, /* 37 reserved */
10883 0, /* 38 reserved */
10884 0, /* 39 reserved */
10885 0, /* 40 reserved */
10886 0, /* 41 reserved */
10887 0, /* 42 reserved */
10888 0, /* 43 reserved */
10889 0, /* 44 reserved */
10890 0, /* 45 reserved */
10891 0, /* 46 reserved */
10892 0, /* 47 reserved */
10893 0, /* 48 reserved */
10894 0, /* 49 reserved */
10895 0, /* 50 reserved */
10896 0, /* 51 reserved */
10897 0, /* 52 reserved */
10898 0, /* 53 reserved */
10899 0, /* 54 reserved */
10900 0, /* 55 reserved */
10901 0, /* 56 cisptr_lsw */
10902 0, /* 57 cisprt_msw */
10903 0, /* 58 subsysvid */
10904 0, /* 59 subsysid */
10905 0, /* 60 reserved */
10906 0, /* 61 reserved */
10907 0, /* 62 reserved */
10908 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070010909};
10910
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010911static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010912 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
10913 0x0000, /* 01 cfg_msw */
10914 0xFFFF, /* 02 disc_enable */
10915 0xFFFF, /* 03 wdtr_able */
10916 0x5555, /* 04 sdtr_speed1 */
10917 0xFFFF, /* 05 start_motor */
10918 0xFFFF, /* 06 tagqng_able */
10919 0xFFFF, /* 07 bios_scan */
10920 0, /* 08 scam_tolerant */
10921 7, /* 09 adapter_scsi_id */
10922 0, /* bios_boot_delay */
10923 3, /* 10 scsi_reset_delay */
10924 0, /* bios_id_lun */
10925 0, /* 11 termination_se */
10926 0, /* termination_lvd */
10927 0xFFE7, /* 12 bios_ctrl */
10928 0x5555, /* 13 sdtr_speed2 */
10929 0x5555, /* 14 sdtr_speed3 */
10930 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
10931 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
10932 0, /* 16 dvc_cntl */
10933 0x5555, /* 17 sdtr_speed4 */
10934 0, /* 18 serial_number_word1 */
10935 0, /* 19 serial_number_word2 */
10936 0, /* 20 serial_number_word3 */
10937 0, /* 21 check_sum */
10938 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
10939 , /* 22-29 oem_name[16] */
10940 0, /* 30 dvc_err_code */
10941 0, /* 31 adv_err_code */
10942 0, /* 32 adv_err_addr */
10943 0, /* 33 saved_dvc_err_code */
10944 0, /* 34 saved_adv_err_code */
10945 0, /* 35 saved_adv_err_addr */
10946 0, /* 36 reserved */
10947 0, /* 37 reserved */
10948 0, /* 38 reserved */
10949 0, /* 39 reserved */
10950 0, /* 40 reserved */
10951 0, /* 41 reserved */
10952 0, /* 42 reserved */
10953 0, /* 43 reserved */
10954 0, /* 44 reserved */
10955 0, /* 45 reserved */
10956 0, /* 46 reserved */
10957 0, /* 47 reserved */
10958 0, /* 48 reserved */
10959 0, /* 49 reserved */
10960 0, /* 50 reserved */
10961 0, /* 51 reserved */
10962 0, /* 52 reserved */
10963 0, /* 53 reserved */
10964 0, /* 54 reserved */
10965 0, /* 55 reserved */
10966 0, /* 56 cisptr_lsw */
10967 0, /* 57 cisprt_msw */
10968 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
10969 PCI_DEVICE_ID_38C1600_REV1, /* 59 subsysid */
10970 0, /* 60 reserved */
10971 0, /* 61 reserved */
10972 0, /* 62 reserved */
10973 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070010974};
10975
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010976static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010977 0, /* 00 cfg_lsw */
10978 0, /* 01 cfg_msw */
10979 0, /* 02 disc_enable */
10980 0, /* 03 wdtr_able */
10981 0, /* 04 sdtr_speed1 */
10982 0, /* 05 start_motor */
10983 0, /* 06 tagqng_able */
10984 0, /* 07 bios_scan */
10985 0, /* 08 scam_tolerant */
10986 1, /* 09 adapter_scsi_id */
10987 1, /* bios_boot_delay */
10988 1, /* 10 scsi_reset_delay */
10989 1, /* bios_id_lun */
10990 1, /* 11 termination_se */
10991 1, /* termination_lvd */
10992 0, /* 12 bios_ctrl */
10993 0, /* 13 sdtr_speed2 */
10994 0, /* 14 sdtr_speed3 */
10995 1, /* 15 max_host_qng */
10996 1, /* max_dvc_qng */
10997 0, /* 16 dvc_cntl */
10998 0, /* 17 sdtr_speed4 */
10999 0, /* 18 serial_number_word1 */
11000 0, /* 19 serial_number_word2 */
11001 0, /* 20 serial_number_word3 */
11002 0, /* 21 check_sum */
11003 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
11004 , /* 22-29 oem_name[16] */
11005 0, /* 30 dvc_err_code */
11006 0, /* 31 adv_err_code */
11007 0, /* 32 adv_err_addr */
11008 0, /* 33 saved_dvc_err_code */
11009 0, /* 34 saved_adv_err_code */
11010 0, /* 35 saved_adv_err_addr */
11011 0, /* 36 reserved */
11012 0, /* 37 reserved */
11013 0, /* 38 reserved */
11014 0, /* 39 reserved */
11015 0, /* 40 reserved */
11016 0, /* 41 reserved */
11017 0, /* 42 reserved */
11018 0, /* 43 reserved */
11019 0, /* 44 reserved */
11020 0, /* 45 reserved */
11021 0, /* 46 reserved */
11022 0, /* 47 reserved */
11023 0, /* 48 reserved */
11024 0, /* 49 reserved */
11025 0, /* 50 reserved */
11026 0, /* 51 reserved */
11027 0, /* 52 reserved */
11028 0, /* 53 reserved */
11029 0, /* 54 reserved */
11030 0, /* 55 reserved */
11031 0, /* 56 cisptr_lsw */
11032 0, /* 57 cisprt_msw */
11033 0, /* 58 subsysvid */
11034 0, /* 59 subsysid */
11035 0, /* 60 reserved */
11036 0, /* 61 reserved */
11037 0, /* 62 reserved */
11038 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011039};
11040
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060011041#ifdef CONFIG_PCI
Linus Torvalds1da177e2005-04-16 15:20:36 -070011042/*
11043 * Initialize the ADV_DVC_VAR structure.
11044 *
11045 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
11046 *
11047 * For a non-fatal error return a warning code. If there are no warnings
11048 * then 0 is returned.
11049 */
Matthew Wilcox394dbf32007-07-26 11:56:40 -040011050static int __devinit
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060011051AdvInitGetConfig(struct pci_dev *pdev, asc_board_t *boardp)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011052{
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060011053 ADV_DVC_VAR *asc_dvc = &boardp->dvc_var.adv_dvc_var;
Matthew Wilcox9649af32007-07-26 21:51:47 -060011054 unsigned short warn_code = 0;
11055 AdvPortAddr iop_base = asc_dvc->iop_base;
Matthew Wilcox9649af32007-07-26 21:51:47 -060011056 u16 cmd;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011057 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011058
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011059 asc_dvc->err_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011060
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011061 /*
11062 * Save the state of the PCI Configuration Command Register
11063 * "Parity Error Response Control" Bit. If the bit is clear (0),
11064 * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore
11065 * DMA parity errors.
11066 */
11067 asc_dvc->cfg->control_flag = 0;
Matthew Wilcox9649af32007-07-26 21:51:47 -060011068 pci_read_config_word(pdev, PCI_COMMAND, &cmd);
11069 if ((cmd & PCI_COMMAND_PARITY) == 0)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011070 asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011071
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011072 asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) |
11073 ADV_LIB_VERSION_MINOR;
11074 asc_dvc->cfg->chip_version =
11075 AdvGetChipVersion(iop_base, asc_dvc->bus_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011076
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011077 ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: 0x%x 0x%x\n",
11078 (ushort)AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
11079 (ushort)ADV_CHIP_ID_BYTE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011080
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011081 ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: 0x%x 0x%x\n",
11082 (ushort)AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
11083 (ushort)ADV_CHIP_ID_WORD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011084
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011085 /*
11086 * Reset the chip to start and allow register writes.
11087 */
11088 if (AdvFindSignature(iop_base) == 0) {
11089 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
11090 return ADV_ERROR;
11091 } else {
11092 /*
11093 * The caller must set 'chip_type' to a valid setting.
11094 */
11095 if (asc_dvc->chip_type != ADV_CHIP_ASC3550 &&
11096 asc_dvc->chip_type != ADV_CHIP_ASC38C0800 &&
11097 asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
11098 asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
11099 return ADV_ERROR;
11100 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011101
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011102 /*
11103 * Reset Chip.
11104 */
11105 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
11106 ADV_CTRL_REG_CMD_RESET);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060011107 mdelay(100);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011108 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
11109 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011110
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011111 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
Matthew Wilcox9649af32007-07-26 21:51:47 -060011112 status = AdvInitFrom38C1600EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011113 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
Matthew Wilcox9649af32007-07-26 21:51:47 -060011114 status = AdvInitFrom38C0800EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011115 } else {
Matthew Wilcox9649af32007-07-26 21:51:47 -060011116 status = AdvInitFrom3550EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011117 }
11118 warn_code |= status;
11119 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011120
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060011121 if (warn_code != 0) {
11122 ASC_PRINT2("AdvInitGetConfig: board %d: warning: 0x%x\n",
11123 boardp->id, warn_code);
11124 }
11125
11126 if (asc_dvc->err_code) {
11127 ASC_PRINT2("AdvInitGetConfig: board %d error: err_code 0x%x\n",
11128 boardp->id, asc_dvc->err_code);
11129 }
11130
11131 return asc_dvc->err_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011132}
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060011133#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070011134
Matthew Wilcoxa9f4a592007-09-09 08:56:27 -060011135static void AdvBuildCarrierFreelist(struct adv_dvc_var *asc_dvc)
11136{
11137 ADV_CARR_T *carrp;
11138 ADV_SDCNT buf_size;
11139 ADV_PADDR carr_paddr;
11140
11141 BUG_ON(!asc_dvc->carrier_buf);
11142
11143 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
11144 asc_dvc->carr_freelist = NULL;
11145 if (carrp == asc_dvc->carrier_buf) {
11146 buf_size = ADV_CARRIER_BUFSIZE;
11147 } else {
11148 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
11149 }
11150
11151 do {
11152 /* Get physical address of the carrier 'carrp'. */
11153 ADV_DCNT contig_len = sizeof(ADV_CARR_T);
11154 carr_paddr = cpu_to_le32(DvcGetPhyAddr(asc_dvc, NULL,
11155 (uchar *)carrp,
11156 (ADV_SDCNT *)&contig_len,
11157 ADV_IS_CARRIER_FLAG));
11158
11159 buf_size -= sizeof(ADV_CARR_T);
11160
11161 /*
11162 * If the current carrier is not physically contiguous, then
11163 * maybe there was a page crossing. Try the next carrier
11164 * aligned start address.
11165 */
11166 if (contig_len < sizeof(ADV_CARR_T)) {
11167 carrp++;
11168 continue;
11169 }
11170
11171 carrp->carr_pa = carr_paddr;
11172 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
11173
11174 /*
11175 * Insert the carrier at the beginning of the freelist.
11176 */
11177 carrp->next_vpa =
11178 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
11179 asc_dvc->carr_freelist = carrp;
11180
11181 carrp++;
11182 } while (buf_size > 0);
11183}
11184
Linus Torvalds1da177e2005-04-16 15:20:36 -070011185/*
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060011186 * Load the Microcode
11187 *
11188 * Write the microcode image to RISC memory starting at address 0.
11189 *
11190 * The microcode is stored compressed in the following format:
11191 *
11192 * 254 word (508 byte) table indexed by byte code followed
11193 * by the following byte codes:
11194 *
11195 * 1-Byte Code:
11196 * 00: Emit word 0 in table.
11197 * 01: Emit word 1 in table.
11198 * .
11199 * FD: Emit word 253 in table.
11200 *
11201 * Multi-Byte Code:
11202 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
11203 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
11204 *
11205 * Returns 0 or an error if the checksum doesn't match
11206 */
11207static int AdvLoadMicrocode(AdvPortAddr iop_base, unsigned char *buf, int size,
11208 int memsize, int chksum)
11209{
11210 int i, j, end, len = 0;
11211 ADV_DCNT sum;
11212
11213 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
11214
11215 for (i = 253 * 2; i < size; i++) {
11216 if (buf[i] == 0xff) {
11217 unsigned short word = (buf[i + 3] << 8) | buf[i + 2];
11218 for (j = 0; j < buf[i + 1]; j++) {
11219 AdvWriteWordAutoIncLram(iop_base, word);
11220 len += 2;
11221 }
11222 i += 3;
11223 } else if (buf[i] == 0xfe) {
11224 unsigned short word = (buf[i + 2] << 8) | buf[i + 1];
11225 AdvWriteWordAutoIncLram(iop_base, word);
11226 i += 2;
11227 len += 2;
11228 } else {
11229 unsigned char off = buf[i] * 2;
11230 unsigned short word = (buf[off + 1] << 8) | buf[off];
11231 AdvWriteWordAutoIncLram(iop_base, word);
11232 len += 2;
11233 }
11234 }
11235
11236 end = len;
11237
11238 while (len < memsize) {
11239 AdvWriteWordAutoIncLram(iop_base, 0);
11240 len += 2;
11241 }
11242
11243 /* Verify the microcode checksum. */
11244 sum = 0;
11245 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
11246
11247 for (len = 0; len < end; len += 2) {
11248 sum += AdvReadWordAutoIncLram(iop_base);
11249 }
11250
11251 if (sum != chksum)
11252 return ASC_IERR_MCODE_CHKSUM;
11253
11254 return 0;
11255}
11256
11257/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070011258 * Initialize the ASC-3550.
11259 *
11260 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
11261 *
11262 * For a non-fatal error return a warning code. If there are no warnings
11263 * then 0 is returned.
11264 *
11265 * Needed after initialization for error recovery.
11266 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011267static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011268{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011269 AdvPortAddr iop_base;
11270 ushort warn_code;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011271 int begin_addr;
11272 int end_addr;
11273 ushort code_sum;
11274 int word;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011275 int i;
11276 ushort scsi_cfg1;
11277 uchar tid;
11278 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
11279 ushort wdtr_able = 0, sdtr_able, tagqng_able;
11280 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070011281
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011282 /* If there is already an error, don't continue. */
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060011283 if (asc_dvc->err_code != 0)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011284 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011285
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011286 /*
11287 * The caller must set 'chip_type' to ADV_CHIP_ASC3550.
11288 */
11289 if (asc_dvc->chip_type != ADV_CHIP_ASC3550) {
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060011290 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011291 return ADV_ERROR;
11292 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011293
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011294 warn_code = 0;
11295 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011296
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011297 /*
11298 * Save the RISC memory BIOS region before writing the microcode.
11299 * The BIOS may already be loaded and using its RISC LRAM region
11300 * so its region must be saved and restored.
11301 *
11302 * Note: This code makes the assumption, which is currently true,
11303 * that a chip reset does not clear RISC LRAM.
11304 */
11305 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
11306 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
11307 bios_mem[i]);
11308 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011309
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011310 /*
11311 * Save current per TID negotiated values.
11312 */
11313 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == 0x55AA) {
11314 ushort bios_version, major, minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011315
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011316 bios_version =
11317 bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM) / 2];
11318 major = (bios_version >> 12) & 0xF;
11319 minor = (bios_version >> 8) & 0xF;
11320 if (major < 3 || (major == 3 && minor == 1)) {
11321 /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
11322 AdvReadWordLram(iop_base, 0x120, wdtr_able);
11323 } else {
11324 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
11325 }
11326 }
11327 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
11328 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
11329 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
11330 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
11331 max_cmd[tid]);
11332 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011333
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060011334 asc_dvc->err_code = AdvLoadMicrocode(iop_base, _adv_asc3550_buf,
11335 _adv_asc3550_size, ADV_3550_MEMSIZE,
11336 _adv_asc3550_chksum);
11337 if (asc_dvc->err_code)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011338 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011339
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011340 /*
11341 * Restore the RISC memory BIOS region.
11342 */
11343 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
11344 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
11345 bios_mem[i]);
11346 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011347
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011348 /*
11349 * Calculate and write the microcode code checksum to the microcode
11350 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
11351 */
11352 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
11353 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
11354 code_sum = 0;
11355 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
11356 for (word = begin_addr; word < end_addr; word += 2) {
11357 code_sum += AdvReadWordAutoIncLram(iop_base);
11358 }
11359 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011360
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011361 /*
11362 * Read and save microcode version and date.
11363 */
11364 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
11365 asc_dvc->cfg->mcode_date);
11366 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
11367 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011368
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011369 /*
11370 * Set the chip type to indicate the ASC3550.
11371 */
11372 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011373
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011374 /*
11375 * If the PCI Configuration Command Register "Parity Error Response
11376 * Control" Bit was clear (0), then set the microcode variable
11377 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
11378 * to ignore DMA parity errors.
11379 */
11380 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
11381 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
11382 word |= CONTROL_FLAG_IGNORE_PERR;
11383 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
11384 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011385
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011386 /*
11387 * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
11388 * threshold of 128 bytes. This register is only accessible to the host.
11389 */
11390 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
11391 START_CTL_EMFU | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011392
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011393 /*
11394 * Microcode operating variables for WDTR, SDTR, and command tag
Matthew Wilcox47d853c2007-07-26 11:41:33 -040011395 * queuing will be set in slave_configure() based on what a
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011396 * device reports it is capable of in Inquiry byte 7.
11397 *
11398 * If SCSI Bus Resets have been disabled, then directly set
11399 * SDTR and WDTR from the EEPROM configuration. This will allow
11400 * the BIOS and warm boot to work without a SCSI bus hang on
11401 * the Inquiry caused by host and target mismatched DTR values.
11402 * Without the SCSI Bus Reset, before an Inquiry a device can't
11403 * be assumed to be in Asynchronous, Narrow mode.
11404 */
11405 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
11406 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
11407 asc_dvc->wdtr_able);
11408 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
11409 asc_dvc->sdtr_able);
11410 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011411
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011412 /*
11413 * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
11414 * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
11415 * bitmask. These values determine the maximum SDTR speed negotiated
11416 * with a device.
11417 *
11418 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
11419 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
11420 * without determining here whether the device supports SDTR.
11421 *
11422 * 4-bit speed SDTR speed name
11423 * =========== ===============
11424 * 0000b (0x0) SDTR disabled
11425 * 0001b (0x1) 5 Mhz
11426 * 0010b (0x2) 10 Mhz
11427 * 0011b (0x3) 20 Mhz (Ultra)
11428 * 0100b (0x4) 40 Mhz (LVD/Ultra2)
11429 * 0101b (0x5) 80 Mhz (LVD2/Ultra3)
11430 * 0110b (0x6) Undefined
11431 * .
11432 * 1111b (0xF) Undefined
11433 */
11434 word = 0;
11435 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
11436 if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) {
11437 /* Set Ultra speed for TID 'tid'. */
11438 word |= (0x3 << (4 * (tid % 4)));
11439 } else {
11440 /* Set Fast speed for TID 'tid'. */
11441 word |= (0x2 << (4 * (tid % 4)));
11442 }
11443 if (tid == 3) { /* Check if done with sdtr_speed1. */
11444 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
11445 word = 0;
11446 } else if (tid == 7) { /* Check if done with sdtr_speed2. */
11447 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
11448 word = 0;
11449 } else if (tid == 11) { /* Check if done with sdtr_speed3. */
11450 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
11451 word = 0;
11452 } else if (tid == 15) { /* Check if done with sdtr_speed4. */
11453 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
11454 /* End of loop. */
11455 }
11456 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011457
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011458 /*
11459 * Set microcode operating variable for the disconnect per TID bitmask.
11460 */
11461 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
11462 asc_dvc->cfg->disc_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011463
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011464 /*
11465 * Set SCSI_CFG0 Microcode Default Value.
11466 *
11467 * The microcode will set the SCSI_CFG0 register using this value
11468 * after it is started below.
11469 */
11470 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
11471 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
11472 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011473
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011474 /*
11475 * Determine SCSI_CFG1 Microcode Default Value.
11476 *
11477 * The microcode will set the SCSI_CFG1 register using this value
11478 * after it is started below.
11479 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011480
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011481 /* Read current SCSI_CFG1 Register value. */
11482 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011483
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011484 /*
11485 * If all three connectors are in use, return an error.
11486 */
11487 if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
11488 (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) {
11489 asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
11490 return ADV_ERROR;
11491 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011492
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011493 /*
11494 * If the internal narrow cable is reversed all of the SCSI_CTRL
11495 * register signals will be set. Check for and return an error if
11496 * this condition is found.
11497 */
11498 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
11499 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
11500 return ADV_ERROR;
11501 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011502
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011503 /*
11504 * If this is a differential board and a single-ended device
11505 * is attached to one of the connectors, return an error.
11506 */
11507 if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) {
11508 asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE;
11509 return ADV_ERROR;
11510 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011511
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011512 /*
11513 * If automatic termination control is enabled, then set the
11514 * termination value based on a table listed in a_condor.h.
11515 *
11516 * If manual termination was specified with an EEPROM setting
11517 * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
11518 * is ready to be 'ored' into SCSI_CFG1.
11519 */
11520 if (asc_dvc->cfg->termination == 0) {
11521 /*
11522 * The software always controls termination by setting TERM_CTL_SEL.
11523 * If TERM_CTL_SEL were set to 0, the hardware would set termination.
11524 */
11525 asc_dvc->cfg->termination |= TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011526
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011527 switch (scsi_cfg1 & CABLE_DETECT) {
11528 /* TERM_CTL_H: on, TERM_CTL_L: on */
11529 case 0x3:
11530 case 0x7:
11531 case 0xB:
11532 case 0xD:
11533 case 0xE:
11534 case 0xF:
11535 asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L);
11536 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011537
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011538 /* TERM_CTL_H: on, TERM_CTL_L: off */
11539 case 0x1:
11540 case 0x5:
11541 case 0x9:
11542 case 0xA:
11543 case 0xC:
11544 asc_dvc->cfg->termination |= TERM_CTL_H;
11545 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011546
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011547 /* TERM_CTL_H: off, TERM_CTL_L: off */
11548 case 0x2:
11549 case 0x6:
11550 break;
11551 }
11552 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011553
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011554 /*
11555 * Clear any set TERM_CTL_H and TERM_CTL_L bits.
11556 */
11557 scsi_cfg1 &= ~TERM_CTL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011558
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011559 /*
11560 * Invert the TERM_CTL_H and TERM_CTL_L bits and then
11561 * set 'scsi_cfg1'. The TERM_POL bit does not need to be
11562 * referenced, because the hardware internally inverts
11563 * the Termination High and Low bits if TERM_POL is set.
11564 */
11565 scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
Linus Torvalds1da177e2005-04-16 15:20:36 -070011566
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011567 /*
11568 * Set SCSI_CFG1 Microcode Default Value
11569 *
11570 * Set filter value and possibly modified termination control
11571 * bits in the Microcode SCSI_CFG1 Register Value.
11572 *
11573 * The microcode will set the SCSI_CFG1 register using this value
11574 * after it is started below.
11575 */
11576 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
11577 FLTR_DISABLE | scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011578
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011579 /*
11580 * Set MEM_CFG Microcode Default Value
11581 *
11582 * The microcode will set the MEM_CFG register using this value
11583 * after it is started below.
11584 *
11585 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
11586 * are defined.
11587 *
11588 * ASC-3550 has 8KB internal memory.
11589 */
11590 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
11591 BIOS_EN | RAM_SZ_8KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011592
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011593 /*
11594 * Set SEL_MASK Microcode Default Value
11595 *
11596 * The microcode will set the SEL_MASK register using this value
11597 * after it is started below.
11598 */
11599 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
11600 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070011601
Matthew Wilcoxa9f4a592007-09-09 08:56:27 -060011602 AdvBuildCarrierFreelist(asc_dvc);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011603
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011604 /*
11605 * Set-up the Host->RISC Initiator Command Queue (ICQ).
11606 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011607
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011608 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
11609 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
11610 return ADV_ERROR;
11611 }
11612 asc_dvc->carr_freelist = (ADV_CARR_T *)
11613 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070011614
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011615 /*
11616 * The first command issued will be placed in the stopper carrier.
11617 */
11618 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011619
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011620 /*
11621 * Set RISC ICQ physical address start value.
11622 */
11623 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011624
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011625 /*
11626 * Set-up the RISC->Host Initiator Response Queue (IRQ).
11627 */
11628 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
11629 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
11630 return ADV_ERROR;
11631 }
11632 asc_dvc->carr_freelist = (ADV_CARR_T *)
11633 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070011634
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011635 /*
11636 * The first command completed by the RISC will be placed in
11637 * the stopper.
11638 *
11639 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
11640 * completed the RISC will set the ASC_RQ_STOPPER bit.
11641 */
11642 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011643
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011644 /*
11645 * Set RISC IRQ physical address start value.
11646 */
11647 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
11648 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011649
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011650 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
11651 (ADV_INTR_ENABLE_HOST_INTR |
11652 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070011653
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011654 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
11655 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011656
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011657 /* finally, finally, gentlemen, start your engine */
11658 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011659
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011660 /*
11661 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
11662 * Resets should be performed. The RISC has to be running
11663 * to issue a SCSI Bus Reset.
11664 */
11665 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
11666 /*
11667 * If the BIOS Signature is present in memory, restore the
11668 * BIOS Handshake Configuration Table and do not perform
11669 * a SCSI Bus Reset.
11670 */
11671 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
11672 0x55AA) {
11673 /*
11674 * Restore per TID negotiated values.
11675 */
11676 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
11677 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
11678 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
11679 tagqng_able);
11680 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
11681 AdvWriteByteLram(iop_base,
11682 ASC_MC_NUMBER_OF_MAX_CMD + tid,
11683 max_cmd[tid]);
11684 }
11685 } else {
11686 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
11687 warn_code = ASC_WARN_BUSRESET_ERROR;
11688 }
11689 }
11690 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011691
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011692 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011693}
11694
11695/*
11696 * Initialize the ASC-38C0800.
11697 *
11698 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
11699 *
11700 * For a non-fatal error return a warning code. If there are no warnings
11701 * then 0 is returned.
11702 *
11703 * Needed after initialization for error recovery.
11704 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011705static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011706{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011707 AdvPortAddr iop_base;
11708 ushort warn_code;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011709 int begin_addr;
11710 int end_addr;
11711 ushort code_sum;
11712 int word;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011713 int i;
11714 ushort scsi_cfg1;
11715 uchar byte;
11716 uchar tid;
11717 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
11718 ushort wdtr_able, sdtr_able, tagqng_able;
11719 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070011720
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011721 /* If there is already an error, don't continue. */
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060011722 if (asc_dvc->err_code != 0)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011723 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011724
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011725 /*
11726 * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
11727 */
11728 if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) {
11729 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
11730 return ADV_ERROR;
11731 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011732
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011733 warn_code = 0;
11734 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011735
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011736 /*
11737 * Save the RISC memory BIOS region before writing the microcode.
11738 * The BIOS may already be loaded and using its RISC LRAM region
11739 * so its region must be saved and restored.
11740 *
11741 * Note: This code makes the assumption, which is currently true,
11742 * that a chip reset does not clear RISC LRAM.
11743 */
11744 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
11745 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
11746 bios_mem[i]);
11747 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011748
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011749 /*
11750 * Save current per TID negotiated values.
11751 */
11752 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
11753 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
11754 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
11755 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
11756 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
11757 max_cmd[tid]);
11758 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011759
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011760 /*
11761 * RAM BIST (RAM Built-In Self Test)
11762 *
11763 * Address : I/O base + offset 0x38h register (byte).
11764 * Function: Bit 7-6(RW) : RAM mode
11765 * Normal Mode : 0x00
11766 * Pre-test Mode : 0x40
11767 * RAM Test Mode : 0x80
11768 * Bit 5 : unused
11769 * Bit 4(RO) : Done bit
11770 * Bit 3-0(RO) : Status
11771 * Host Error : 0x08
11772 * Int_RAM Error : 0x04
11773 * RISC Error : 0x02
11774 * SCSI Error : 0x01
11775 * No Error : 0x00
11776 *
11777 * Note: RAM BIST code should be put right here, before loading the
11778 * microcode and after saving the RISC memory BIOS region.
11779 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011780
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011781 /*
11782 * LRAM Pre-test
11783 *
11784 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
11785 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
11786 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
11787 * to NORMAL_MODE, return an error too.
11788 */
11789 for (i = 0; i < 2; i++) {
11790 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060011791 mdelay(10); /* Wait for 10ms before reading back. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011792 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
11793 if ((byte & RAM_TEST_DONE) == 0
11794 || (byte & 0x0F) != PRE_TEST_VALUE) {
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060011795 asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011796 return ADV_ERROR;
11797 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011798
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011799 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060011800 mdelay(10); /* Wait for 10ms before reading back. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011801 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
11802 != NORMAL_VALUE) {
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060011803 asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011804 return ADV_ERROR;
11805 }
11806 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011807
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011808 /*
11809 * LRAM Test - It takes about 1.5 ms to run through the test.
11810 *
11811 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
11812 * If Done bit not set or Status not 0, save register byte, set the
11813 * err_code, and return an error.
11814 */
11815 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060011816 mdelay(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011817
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011818 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
11819 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
11820 /* Get here if Done bit not set or Status not 0. */
11821 asc_dvc->bist_err_code = byte; /* for BIOS display message */
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060011822 asc_dvc->err_code = ASC_IERR_BIST_RAM_TEST;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011823 return ADV_ERROR;
11824 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011825
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011826 /* We need to reset back to normal mode after LRAM test passes. */
11827 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011828
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060011829 asc_dvc->err_code = AdvLoadMicrocode(iop_base, _adv_asc38C0800_buf,
11830 _adv_asc38C0800_size, ADV_38C0800_MEMSIZE,
11831 _adv_asc38C0800_chksum);
11832 if (asc_dvc->err_code)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011833 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011834
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011835 /*
11836 * Restore the RISC memory BIOS region.
11837 */
11838 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
11839 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
11840 bios_mem[i]);
11841 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011842
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011843 /*
11844 * Calculate and write the microcode code checksum to the microcode
11845 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
11846 */
11847 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
11848 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
11849 code_sum = 0;
11850 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
11851 for (word = begin_addr; word < end_addr; word += 2) {
11852 code_sum += AdvReadWordAutoIncLram(iop_base);
11853 }
11854 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011855
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011856 /*
11857 * Read microcode version and date.
11858 */
11859 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
11860 asc_dvc->cfg->mcode_date);
11861 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
11862 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011863
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011864 /*
11865 * Set the chip type to indicate the ASC38C0800.
11866 */
11867 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011868
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011869 /*
11870 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
11871 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
11872 * cable detection and then we are able to read C_DET[3:0].
11873 *
11874 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
11875 * Microcode Default Value' section below.
11876 */
11877 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
11878 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
11879 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011880
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011881 /*
11882 * If the PCI Configuration Command Register "Parity Error Response
11883 * Control" Bit was clear (0), then set the microcode variable
11884 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
11885 * to ignore DMA parity errors.
11886 */
11887 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
11888 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
11889 word |= CONTROL_FLAG_IGNORE_PERR;
11890 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
11891 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011892
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011893 /*
11894 * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
11895 * bits for the default FIFO threshold.
11896 *
11897 * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
11898 *
11899 * For DMA Errata #4 set the BC_THRESH_ENB bit.
11900 */
11901 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
11902 BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH |
11903 READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011904
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011905 /*
11906 * Microcode operating variables for WDTR, SDTR, and command tag
Matthew Wilcox47d853c2007-07-26 11:41:33 -040011907 * queuing will be set in slave_configure() based on what a
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011908 * device reports it is capable of in Inquiry byte 7.
11909 *
11910 * If SCSI Bus Resets have been disabled, then directly set
11911 * SDTR and WDTR from the EEPROM configuration. This will allow
11912 * the BIOS and warm boot to work without a SCSI bus hang on
11913 * the Inquiry caused by host and target mismatched DTR values.
11914 * Without the SCSI Bus Reset, before an Inquiry a device can't
11915 * be assumed to be in Asynchronous, Narrow mode.
11916 */
11917 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
11918 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
11919 asc_dvc->wdtr_able);
11920 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
11921 asc_dvc->sdtr_able);
11922 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011923
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011924 /*
11925 * Set microcode operating variables for DISC and SDTR_SPEED1,
11926 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
11927 * configuration values.
11928 *
11929 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
11930 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
11931 * without determining here whether the device supports SDTR.
11932 */
11933 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
11934 asc_dvc->cfg->disc_enable);
11935 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
11936 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
11937 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
11938 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011939
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011940 /*
11941 * Set SCSI_CFG0 Microcode Default Value.
11942 *
11943 * The microcode will set the SCSI_CFG0 register using this value
11944 * after it is started below.
11945 */
11946 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
11947 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
11948 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011949
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011950 /*
11951 * Determine SCSI_CFG1 Microcode Default Value.
11952 *
11953 * The microcode will set the SCSI_CFG1 register using this value
11954 * after it is started below.
11955 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011956
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011957 /* Read current SCSI_CFG1 Register value. */
11958 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011959
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011960 /*
11961 * If the internal narrow cable is reversed all of the SCSI_CTRL
11962 * register signals will be set. Check for and return an error if
11963 * this condition is found.
11964 */
11965 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
11966 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
11967 return ADV_ERROR;
11968 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011969
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011970 /*
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060011971 * All kind of combinations of devices attached to one of four
11972 * connectors are acceptable except HVD device attached. For example,
11973 * LVD device can be attached to SE connector while SE device attached
11974 * to LVD connector. If LVD device attached to SE connector, it only
11975 * runs up to Ultra speed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011976 *
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060011977 * If an HVD device is attached to one of LVD connectors, return an
11978 * error. However, there is no way to detect HVD device attached to
11979 * SE connectors.
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011980 */
11981 if (scsi_cfg1 & HVD) {
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060011982 asc_dvc->err_code = ASC_IERR_HVD_DEVICE;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011983 return ADV_ERROR;
11984 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011985
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011986 /*
11987 * If either SE or LVD automatic termination control is enabled, then
11988 * set the termination value based on a table listed in a_condor.h.
11989 *
11990 * If manual termination was specified with an EEPROM setting then
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060011991 * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready
11992 * to be 'ored' into SCSI_CFG1.
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011993 */
11994 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
11995 /* SE automatic termination control is enabled. */
11996 switch (scsi_cfg1 & C_DET_SE) {
11997 /* TERM_SE_HI: on, TERM_SE_LO: on */
11998 case 0x1:
11999 case 0x2:
12000 case 0x3:
12001 asc_dvc->cfg->termination |= TERM_SE;
12002 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012003
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012004 /* TERM_SE_HI: on, TERM_SE_LO: off */
12005 case 0x0:
12006 asc_dvc->cfg->termination |= TERM_SE_HI;
12007 break;
12008 }
12009 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012010
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012011 if ((asc_dvc->cfg->termination & TERM_LVD) == 0) {
12012 /* LVD automatic termination control is enabled. */
12013 switch (scsi_cfg1 & C_DET_LVD) {
12014 /* TERM_LVD_HI: on, TERM_LVD_LO: on */
12015 case 0x4:
12016 case 0x8:
12017 case 0xC:
12018 asc_dvc->cfg->termination |= TERM_LVD;
12019 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012020
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012021 /* TERM_LVD_HI: off, TERM_LVD_LO: off */
12022 case 0x0:
12023 break;
12024 }
12025 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012026
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012027 /*
12028 * Clear any set TERM_SE and TERM_LVD bits.
12029 */
12030 scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012031
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012032 /*
12033 * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
12034 */
12035 scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012036
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012037 /*
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012038 * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE
12039 * bits and set possibly modified termination control bits in the
12040 * Microcode SCSI_CFG1 Register Value.
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012041 */
12042 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012043
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012044 /*
12045 * Set SCSI_CFG1 Microcode Default Value
12046 *
12047 * Set possibly modified termination control and reset DIS_TERM_DRV
12048 * bits in the Microcode SCSI_CFG1 Register Value.
12049 *
12050 * The microcode will set the SCSI_CFG1 register using this value
12051 * after it is started below.
12052 */
12053 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012054
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012055 /*
12056 * Set MEM_CFG Microcode Default Value
12057 *
12058 * The microcode will set the MEM_CFG register using this value
12059 * after it is started below.
12060 *
12061 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
12062 * are defined.
12063 *
12064 * ASC-38C0800 has 16KB internal memory.
12065 */
12066 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
12067 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012068
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012069 /*
12070 * Set SEL_MASK Microcode Default Value
12071 *
12072 * The microcode will set the SEL_MASK register using this value
12073 * after it is started below.
12074 */
12075 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
12076 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012077
Matthew Wilcoxa9f4a592007-09-09 08:56:27 -060012078 AdvBuildCarrierFreelist(asc_dvc);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012079
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012080 /*
12081 * Set-up the Host->RISC Initiator Command Queue (ICQ).
12082 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012083
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012084 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
12085 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
12086 return ADV_ERROR;
12087 }
12088 asc_dvc->carr_freelist = (ADV_CARR_T *)
12089 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012090
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012091 /*
12092 * The first command issued will be placed in the stopper carrier.
12093 */
12094 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012095
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012096 /*
12097 * Set RISC ICQ physical address start value.
12098 * carr_pa is LE, must be native before write
12099 */
12100 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012101
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012102 /*
12103 * Set-up the RISC->Host Initiator Response Queue (IRQ).
12104 */
12105 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
12106 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
12107 return ADV_ERROR;
12108 }
12109 asc_dvc->carr_freelist = (ADV_CARR_T *)
12110 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012111
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012112 /*
12113 * The first command completed by the RISC will be placed in
12114 * the stopper.
12115 *
12116 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
12117 * completed the RISC will set the ASC_RQ_STOPPER bit.
12118 */
12119 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012120
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012121 /*
12122 * Set RISC IRQ physical address start value.
12123 *
12124 * carr_pa is LE, must be native before write *
12125 */
12126 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
12127 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012128
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012129 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
12130 (ADV_INTR_ENABLE_HOST_INTR |
12131 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012132
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012133 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
12134 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012135
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012136 /* finally, finally, gentlemen, start your engine */
12137 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012138
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012139 /*
12140 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
12141 * Resets should be performed. The RISC has to be running
12142 * to issue a SCSI Bus Reset.
12143 */
12144 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
12145 /*
12146 * If the BIOS Signature is present in memory, restore the
12147 * BIOS Handshake Configuration Table and do not perform
12148 * a SCSI Bus Reset.
12149 */
12150 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
12151 0x55AA) {
12152 /*
12153 * Restore per TID negotiated values.
12154 */
12155 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
12156 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
12157 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
12158 tagqng_able);
12159 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
12160 AdvWriteByteLram(iop_base,
12161 ASC_MC_NUMBER_OF_MAX_CMD + tid,
12162 max_cmd[tid]);
12163 }
12164 } else {
12165 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
12166 warn_code = ASC_WARN_BUSRESET_ERROR;
12167 }
12168 }
12169 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012170
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012171 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012172}
12173
12174/*
12175 * Initialize the ASC-38C1600.
12176 *
12177 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
12178 *
12179 * For a non-fatal error return a warning code. If there are no warnings
12180 * then 0 is returned.
12181 *
12182 * Needed after initialization for error recovery.
12183 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012184static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070012185{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012186 AdvPortAddr iop_base;
12187 ushort warn_code;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012188 int begin_addr;
12189 int end_addr;
12190 ushort code_sum;
12191 long word;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012192 int i;
12193 ushort scsi_cfg1;
12194 uchar byte;
12195 uchar tid;
12196 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
12197 ushort wdtr_able, sdtr_able, ppr_able, tagqng_able;
12198 uchar max_cmd[ASC_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070012199
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012200 /* If there is already an error, don't continue. */
12201 if (asc_dvc->err_code != 0) {
12202 return ADV_ERROR;
12203 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012204
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012205 /*
12206 * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600.
12207 */
12208 if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
12209 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
12210 return ADV_ERROR;
12211 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012212
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012213 warn_code = 0;
12214 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012215
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012216 /*
12217 * Save the RISC memory BIOS region before writing the microcode.
12218 * The BIOS may already be loaded and using its RISC LRAM region
12219 * so its region must be saved and restored.
12220 *
12221 * Note: This code makes the assumption, which is currently true,
12222 * that a chip reset does not clear RISC LRAM.
12223 */
12224 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
12225 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
12226 bios_mem[i]);
12227 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012228
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012229 /*
12230 * Save current per TID negotiated values.
12231 */
12232 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
12233 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
12234 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
12235 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
12236 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
12237 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
12238 max_cmd[tid]);
12239 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012240
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012241 /*
12242 * RAM BIST (Built-In Self Test)
12243 *
12244 * Address : I/O base + offset 0x38h register (byte).
12245 * Function: Bit 7-6(RW) : RAM mode
12246 * Normal Mode : 0x00
12247 * Pre-test Mode : 0x40
12248 * RAM Test Mode : 0x80
12249 * Bit 5 : unused
12250 * Bit 4(RO) : Done bit
12251 * Bit 3-0(RO) : Status
12252 * Host Error : 0x08
12253 * Int_RAM Error : 0x04
12254 * RISC Error : 0x02
12255 * SCSI Error : 0x01
12256 * No Error : 0x00
12257 *
12258 * Note: RAM BIST code should be put right here, before loading the
12259 * microcode and after saving the RISC memory BIOS region.
12260 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012261
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012262 /*
12263 * LRAM Pre-test
12264 *
12265 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
12266 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
12267 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
12268 * to NORMAL_MODE, return an error too.
12269 */
12270 for (i = 0; i < 2; i++) {
12271 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060012272 mdelay(10); /* Wait for 10ms before reading back. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012273 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
12274 if ((byte & RAM_TEST_DONE) == 0
12275 || (byte & 0x0F) != PRE_TEST_VALUE) {
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012276 asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012277 return ADV_ERROR;
12278 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012279
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012280 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060012281 mdelay(10); /* Wait for 10ms before reading back. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012282 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
12283 != NORMAL_VALUE) {
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012284 asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012285 return ADV_ERROR;
12286 }
12287 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012288
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012289 /*
12290 * LRAM Test - It takes about 1.5 ms to run through the test.
12291 *
12292 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
12293 * If Done bit not set or Status not 0, save register byte, set the
12294 * err_code, and return an error.
12295 */
12296 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060012297 mdelay(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012298
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012299 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
12300 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
12301 /* Get here if Done bit not set or Status not 0. */
12302 asc_dvc->bist_err_code = byte; /* for BIOS display message */
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012303 asc_dvc->err_code = ASC_IERR_BIST_RAM_TEST;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012304 return ADV_ERROR;
12305 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012306
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012307 /* We need to reset back to normal mode after LRAM test passes. */
12308 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012309
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012310 asc_dvc->err_code = AdvLoadMicrocode(iop_base, _adv_asc38C1600_buf,
12311 _adv_asc38C1600_size, ADV_38C1600_MEMSIZE,
12312 _adv_asc38C1600_chksum);
12313 if (asc_dvc->err_code)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012314 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012315
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012316 /*
12317 * Restore the RISC memory BIOS region.
12318 */
12319 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
12320 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
12321 bios_mem[i]);
12322 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012323
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012324 /*
12325 * Calculate and write the microcode code checksum to the microcode
12326 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
12327 */
12328 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
12329 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
12330 code_sum = 0;
12331 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
12332 for (word = begin_addr; word < end_addr; word += 2) {
12333 code_sum += AdvReadWordAutoIncLram(iop_base);
12334 }
12335 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012336
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012337 /*
12338 * Read microcode version and date.
12339 */
12340 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
12341 asc_dvc->cfg->mcode_date);
12342 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
12343 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012344
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012345 /*
12346 * Set the chip type to indicate the ASC38C1600.
12347 */
12348 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012349
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012350 /*
12351 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
12352 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
12353 * cable detection and then we are able to read C_DET[3:0].
12354 *
12355 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
12356 * Microcode Default Value' section below.
12357 */
12358 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
12359 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
12360 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012361
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012362 /*
12363 * If the PCI Configuration Command Register "Parity Error Response
12364 * Control" Bit was clear (0), then set the microcode variable
12365 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
12366 * to ignore DMA parity errors.
12367 */
12368 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
12369 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
12370 word |= CONTROL_FLAG_IGNORE_PERR;
12371 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
12372 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012373
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012374 /*
12375 * If the BIOS control flag AIPP (Asynchronous Information
12376 * Phase Protection) disable bit is not set, then set the firmware
12377 * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable
12378 * AIPP checking and encoding.
12379 */
12380 if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) {
12381 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
12382 word |= CONTROL_FLAG_ENABLE_AIPP;
12383 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
12384 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012385
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012386 /*
12387 * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4],
12388 * and START_CTL_TH [3:2].
12389 */
12390 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
12391 FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012392
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012393 /*
12394 * Microcode operating variables for WDTR, SDTR, and command tag
Matthew Wilcox47d853c2007-07-26 11:41:33 -040012395 * queuing will be set in slave_configure() based on what a
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012396 * device reports it is capable of in Inquiry byte 7.
12397 *
12398 * If SCSI Bus Resets have been disabled, then directly set
12399 * SDTR and WDTR from the EEPROM configuration. This will allow
12400 * the BIOS and warm boot to work without a SCSI bus hang on
12401 * the Inquiry caused by host and target mismatched DTR values.
12402 * Without the SCSI Bus Reset, before an Inquiry a device can't
12403 * be assumed to be in Asynchronous, Narrow mode.
12404 */
12405 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
12406 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
12407 asc_dvc->wdtr_able);
12408 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
12409 asc_dvc->sdtr_able);
12410 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012411
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012412 /*
12413 * Set microcode operating variables for DISC and SDTR_SPEED1,
12414 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
12415 * configuration values.
12416 *
12417 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
12418 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
12419 * without determining here whether the device supports SDTR.
12420 */
12421 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
12422 asc_dvc->cfg->disc_enable);
12423 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
12424 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
12425 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
12426 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012427
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012428 /*
12429 * Set SCSI_CFG0 Microcode Default Value.
12430 *
12431 * The microcode will set the SCSI_CFG0 register using this value
12432 * after it is started below.
12433 */
12434 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
12435 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
12436 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012437
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012438 /*
12439 * Calculate SCSI_CFG1 Microcode Default Value.
12440 *
12441 * The microcode will set the SCSI_CFG1 register using this value
12442 * after it is started below.
12443 *
12444 * Each ASC-38C1600 function has only two cable detect bits.
12445 * The bus mode override bits are in IOPB_SOFT_OVER_WR.
12446 */
12447 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012448
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012449 /*
12450 * If the cable is reversed all of the SCSI_CTRL register signals
12451 * will be set. Check for and return an error if this condition is
12452 * found.
12453 */
12454 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
12455 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
12456 return ADV_ERROR;
12457 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012458
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012459 /*
12460 * Each ASC-38C1600 function has two connectors. Only an HVD device
12461 * can not be connected to either connector. An LVD device or SE device
12462 * may be connected to either connecor. If an SE device is connected,
12463 * then at most Ultra speed (20 Mhz) can be used on both connectors.
12464 *
12465 * If an HVD device is attached, return an error.
12466 */
12467 if (scsi_cfg1 & HVD) {
12468 asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
12469 return ADV_ERROR;
12470 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012471
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012472 /*
12473 * Each function in the ASC-38C1600 uses only the SE cable detect and
12474 * termination because there are two connectors for each function. Each
12475 * function may use either LVD or SE mode. Corresponding the SE automatic
12476 * termination control EEPROM bits are used for each function. Each
12477 * function has its own EEPROM. If SE automatic control is enabled for
12478 * the function, then set the termination value based on a table listed
12479 * in a_condor.h.
12480 *
12481 * If manual termination is specified in the EEPROM for the function,
12482 * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is
12483 * ready to be 'ored' into SCSI_CFG1.
12484 */
12485 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
Matthew Wilcox13ac2d92007-07-30 08:10:23 -060012486 struct pci_dev *pdev = adv_dvc_to_pdev(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012487 /* SE automatic termination control is enabled. */
12488 switch (scsi_cfg1 & C_DET_SE) {
12489 /* TERM_SE_HI: on, TERM_SE_LO: on */
12490 case 0x1:
12491 case 0x2:
12492 case 0x3:
12493 asc_dvc->cfg->termination |= TERM_SE;
12494 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012495
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012496 case 0x0:
Matthew Wilcox13ac2d92007-07-30 08:10:23 -060012497 if (PCI_FUNC(pdev->devfn) == 0) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012498 /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */
12499 } else {
12500 /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */
12501 asc_dvc->cfg->termination |= TERM_SE_HI;
12502 }
12503 break;
12504 }
12505 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012506
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012507 /*
12508 * Clear any set TERM_SE bits.
12509 */
12510 scsi_cfg1 &= ~TERM_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012511
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012512 /*
12513 * Invert the TERM_SE bits and then set 'scsi_cfg1'.
12514 */
12515 scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012516
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012517 /*
12518 * Clear Big Endian and Terminator Polarity bits and set possibly
12519 * modified termination control bits in the Microcode SCSI_CFG1
12520 * Register Value.
12521 *
12522 * Big Endian bit is not used even on big endian machines.
12523 */
12524 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012525
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012526 /*
12527 * Set SCSI_CFG1 Microcode Default Value
12528 *
12529 * Set possibly modified termination control bits in the Microcode
12530 * SCSI_CFG1 Register Value.
12531 *
12532 * The microcode will set the SCSI_CFG1 register using this value
12533 * after it is started below.
12534 */
12535 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012536
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012537 /*
12538 * Set MEM_CFG Microcode Default Value
12539 *
12540 * The microcode will set the MEM_CFG register using this value
12541 * after it is started below.
12542 *
12543 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
12544 * are defined.
12545 *
12546 * ASC-38C1600 has 32KB internal memory.
12547 *
12548 * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come
12549 * out a special 16K Adv Library and Microcode version. After the issue
12550 * resolved, we should turn back to the 32K support. Both a_condor.h and
12551 * mcode.sas files also need to be updated.
12552 *
12553 * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
12554 * BIOS_EN | RAM_SZ_32KB);
12555 */
12556 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
12557 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012558
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012559 /*
12560 * Set SEL_MASK Microcode Default Value
12561 *
12562 * The microcode will set the SEL_MASK register using this value
12563 * after it is started below.
12564 */
12565 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
12566 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012567
Matthew Wilcoxa9f4a592007-09-09 08:56:27 -060012568 AdvBuildCarrierFreelist(asc_dvc);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012569
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012570 /*
12571 * Set-up the Host->RISC Initiator Command Queue (ICQ).
12572 */
12573 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
12574 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
12575 return ADV_ERROR;
12576 }
12577 asc_dvc->carr_freelist = (ADV_CARR_T *)
12578 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012579
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012580 /*
12581 * The first command issued will be placed in the stopper carrier.
12582 */
12583 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012584
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012585 /*
12586 * Set RISC ICQ physical address start value. Initialize the
12587 * COMMA register to the same value otherwise the RISC will
12588 * prematurely detect a command is available.
12589 */
12590 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
12591 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
12592 le32_to_cpu(asc_dvc->icq_sp->carr_pa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012593
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012594 /*
12595 * Set-up the RISC->Host Initiator Response Queue (IRQ).
12596 */
12597 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
12598 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
12599 return ADV_ERROR;
12600 }
12601 asc_dvc->carr_freelist = (ADV_CARR_T *)
12602 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012603
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012604 /*
12605 * The first command completed by the RISC will be placed in
12606 * the stopper.
12607 *
12608 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
12609 * completed the RISC will set the ASC_RQ_STOPPER bit.
12610 */
12611 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012612
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012613 /*
12614 * Set RISC IRQ physical address start value.
12615 */
12616 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
12617 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012618
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012619 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
12620 (ADV_INTR_ENABLE_HOST_INTR |
12621 ADV_INTR_ENABLE_GLOBAL_INTR));
12622 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
12623 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012624
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012625 /* finally, finally, gentlemen, start your engine */
12626 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012627
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012628 /*
12629 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
12630 * Resets should be performed. The RISC has to be running
12631 * to issue a SCSI Bus Reset.
12632 */
12633 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
12634 /*
12635 * If the BIOS Signature is present in memory, restore the
12636 * per TID microcode operating variables.
12637 */
12638 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
12639 0x55AA) {
12640 /*
12641 * Restore per TID negotiated values.
12642 */
12643 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
12644 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
12645 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
12646 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
12647 tagqng_able);
12648 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
12649 AdvWriteByteLram(iop_base,
12650 ASC_MC_NUMBER_OF_MAX_CMD + tid,
12651 max_cmd[tid]);
12652 }
12653 } else {
12654 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
12655 warn_code = ASC_WARN_BUSRESET_ERROR;
12656 }
12657 }
12658 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012659
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012660 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012661}
12662
12663/*
12664 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
12665 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
12666 * all of this is done.
12667 *
12668 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
12669 *
12670 * For a non-fatal error return a warning code. If there are no warnings
12671 * then 0 is returned.
12672 *
12673 * Note: Chip is stopped on entry.
12674 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060012675static int __devinit AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070012676{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012677 AdvPortAddr iop_base;
12678 ushort warn_code;
12679 ADVEEP_3550_CONFIG eep_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012680
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012681 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012682
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012683 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012684
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012685 /*
12686 * Read the board's EEPROM configuration.
12687 *
12688 * Set default values if a bad checksum is found.
12689 */
12690 if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum) {
12691 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012692
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012693 /*
12694 * Set EEPROM default values.
12695 */
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040012696 memcpy(&eep_config, &Default_3550_EEPROM_Config,
12697 sizeof(ADVEEP_3550_CONFIG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012698
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012699 /*
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040012700 * Assume the 6 byte board serial number that was read from
12701 * EEPROM is correct even if the EEPROM checksum failed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012702 */
12703 eep_config.serial_number_word3 =
12704 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012705
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012706 eep_config.serial_number_word2 =
12707 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012708
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012709 eep_config.serial_number_word1 =
12710 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012711
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012712 AdvSet3550EEPConfig(iop_base, &eep_config);
12713 }
12714 /*
12715 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
12716 * EEPROM configuration that was read.
12717 *
12718 * This is the mapping of EEPROM fields to Adv Library fields.
12719 */
12720 asc_dvc->wdtr_able = eep_config.wdtr_able;
12721 asc_dvc->sdtr_able = eep_config.sdtr_able;
12722 asc_dvc->ultra_able = eep_config.ultra_able;
12723 asc_dvc->tagqng_able = eep_config.tagqng_able;
12724 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
12725 asc_dvc->max_host_qng = eep_config.max_host_qng;
12726 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
12727 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
12728 asc_dvc->start_motor = eep_config.start_motor;
12729 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
12730 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
12731 asc_dvc->no_scam = eep_config.scam_tolerant;
12732 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
12733 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
12734 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012735
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012736 /*
12737 * Set the host maximum queuing (max. 253, min. 16) and the per device
12738 * maximum queuing (max. 63, min. 4).
12739 */
12740 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
12741 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
12742 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
12743 /* If the value is zero, assume it is uninitialized. */
12744 if (eep_config.max_host_qng == 0) {
12745 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
12746 } else {
12747 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
12748 }
12749 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012750
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012751 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
12752 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
12753 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
12754 /* If the value is zero, assume it is uninitialized. */
12755 if (eep_config.max_dvc_qng == 0) {
12756 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
12757 } else {
12758 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
12759 }
12760 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012761
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012762 /*
12763 * If 'max_dvc_qng' is greater than 'max_host_qng', then
12764 * set 'max_dvc_qng' to 'max_host_qng'.
12765 */
12766 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
12767 eep_config.max_dvc_qng = eep_config.max_host_qng;
12768 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012769
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012770 /*
12771 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
12772 * values based on possibly adjusted EEPROM values.
12773 */
12774 asc_dvc->max_host_qng = eep_config.max_host_qng;
12775 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012776
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012777 /*
12778 * If the EEPROM 'termination' field is set to automatic (0), then set
12779 * the ADV_DVC_CFG 'termination' field to automatic also.
12780 *
12781 * If the termination is specified with a non-zero 'termination'
12782 * value check that a legal value is set and set the ADV_DVC_CFG
12783 * 'termination' field appropriately.
12784 */
12785 if (eep_config.termination == 0) {
12786 asc_dvc->cfg->termination = 0; /* auto termination */
12787 } else {
12788 /* Enable manual control with low off / high off. */
12789 if (eep_config.termination == 1) {
12790 asc_dvc->cfg->termination = TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012791
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012792 /* Enable manual control with low off / high on. */
12793 } else if (eep_config.termination == 2) {
12794 asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012795
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012796 /* Enable manual control with low on / high on. */
12797 } else if (eep_config.termination == 3) {
12798 asc_dvc->cfg->termination =
12799 TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L;
12800 } else {
12801 /*
12802 * The EEPROM 'termination' field contains a bad value. Use
12803 * automatic termination instead.
12804 */
12805 asc_dvc->cfg->termination = 0;
12806 warn_code |= ASC_WARN_EEPROM_TERMINATION;
12807 }
12808 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012809
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012810 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012811}
12812
12813/*
12814 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
12815 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
12816 * all of this is done.
12817 *
12818 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
12819 *
12820 * For a non-fatal error return a warning code. If there are no warnings
12821 * then 0 is returned.
12822 *
12823 * Note: Chip is stopped on entry.
12824 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060012825static int __devinit AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070012826{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012827 AdvPortAddr iop_base;
12828 ushort warn_code;
12829 ADVEEP_38C0800_CONFIG eep_config;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012830 uchar tid, termination;
12831 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012832
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012833 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012834
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012835 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012836
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012837 /*
12838 * Read the board's EEPROM configuration.
12839 *
12840 * Set default values if a bad checksum is found.
12841 */
12842 if (AdvGet38C0800EEPConfig(iop_base, &eep_config) !=
12843 eep_config.check_sum) {
12844 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012845
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012846 /*
12847 * Set EEPROM default values.
12848 */
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040012849 memcpy(&eep_config, &Default_38C0800_EEPROM_Config,
12850 sizeof(ADVEEP_38C0800_CONFIG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012851
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012852 /*
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040012853 * Assume the 6 byte board serial number that was read from
12854 * EEPROM is correct even if the EEPROM checksum failed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012855 */
12856 eep_config.serial_number_word3 =
12857 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012858
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012859 eep_config.serial_number_word2 =
12860 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012861
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012862 eep_config.serial_number_word1 =
12863 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012864
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012865 AdvSet38C0800EEPConfig(iop_base, &eep_config);
12866 }
12867 /*
12868 * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
12869 * EEPROM configuration that was read.
12870 *
12871 * This is the mapping of EEPROM fields to Adv Library fields.
12872 */
12873 asc_dvc->wdtr_able = eep_config.wdtr_able;
12874 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
12875 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
12876 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
12877 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
12878 asc_dvc->tagqng_able = eep_config.tagqng_able;
12879 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
12880 asc_dvc->max_host_qng = eep_config.max_host_qng;
12881 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
12882 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
12883 asc_dvc->start_motor = eep_config.start_motor;
12884 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
12885 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
12886 asc_dvc->no_scam = eep_config.scam_tolerant;
12887 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
12888 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
12889 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012890
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012891 /*
12892 * For every Target ID if any of its 'sdtr_speed[1234]' bits
12893 * are set, then set an 'sdtr_able' bit for it.
12894 */
12895 asc_dvc->sdtr_able = 0;
12896 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
12897 if (tid == 0) {
12898 sdtr_speed = asc_dvc->sdtr_speed1;
12899 } else if (tid == 4) {
12900 sdtr_speed = asc_dvc->sdtr_speed2;
12901 } else if (tid == 8) {
12902 sdtr_speed = asc_dvc->sdtr_speed3;
12903 } else if (tid == 12) {
12904 sdtr_speed = asc_dvc->sdtr_speed4;
12905 }
12906 if (sdtr_speed & ADV_MAX_TID) {
12907 asc_dvc->sdtr_able |= (1 << tid);
12908 }
12909 sdtr_speed >>= 4;
12910 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012911
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012912 /*
12913 * Set the host maximum queuing (max. 253, min. 16) and the per device
12914 * maximum queuing (max. 63, min. 4).
12915 */
12916 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
12917 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
12918 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
12919 /* If the value is zero, assume it is uninitialized. */
12920 if (eep_config.max_host_qng == 0) {
12921 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
12922 } else {
12923 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
12924 }
12925 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012926
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012927 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
12928 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
12929 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
12930 /* If the value is zero, assume it is uninitialized. */
12931 if (eep_config.max_dvc_qng == 0) {
12932 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
12933 } else {
12934 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
12935 }
12936 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012937
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012938 /*
12939 * If 'max_dvc_qng' is greater than 'max_host_qng', then
12940 * set 'max_dvc_qng' to 'max_host_qng'.
12941 */
12942 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
12943 eep_config.max_dvc_qng = eep_config.max_host_qng;
12944 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012945
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012946 /*
12947 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
12948 * values based on possibly adjusted EEPROM values.
12949 */
12950 asc_dvc->max_host_qng = eep_config.max_host_qng;
12951 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012952
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012953 /*
12954 * If the EEPROM 'termination' field is set to automatic (0), then set
12955 * the ADV_DVC_CFG 'termination' field to automatic also.
12956 *
12957 * If the termination is specified with a non-zero 'termination'
12958 * value check that a legal value is set and set the ADV_DVC_CFG
12959 * 'termination' field appropriately.
12960 */
12961 if (eep_config.termination_se == 0) {
12962 termination = 0; /* auto termination for SE */
12963 } else {
12964 /* Enable manual control with low off / high off. */
12965 if (eep_config.termination_se == 1) {
12966 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012967
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012968 /* Enable manual control with low off / high on. */
12969 } else if (eep_config.termination_se == 2) {
12970 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012971
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012972 /* Enable manual control with low on / high on. */
12973 } else if (eep_config.termination_se == 3) {
12974 termination = TERM_SE;
12975 } else {
12976 /*
12977 * The EEPROM 'termination_se' field contains a bad value.
12978 * Use automatic termination instead.
12979 */
12980 termination = 0;
12981 warn_code |= ASC_WARN_EEPROM_TERMINATION;
12982 }
12983 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012984
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012985 if (eep_config.termination_lvd == 0) {
12986 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
12987 } else {
12988 /* Enable manual control with low off / high off. */
12989 if (eep_config.termination_lvd == 1) {
12990 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012991
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012992 /* Enable manual control with low off / high on. */
12993 } else if (eep_config.termination_lvd == 2) {
12994 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012995
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012996 /* Enable manual control with low on / high on. */
12997 } else if (eep_config.termination_lvd == 3) {
12998 asc_dvc->cfg->termination = termination | TERM_LVD;
12999 } else {
13000 /*
13001 * The EEPROM 'termination_lvd' field contains a bad value.
13002 * Use automatic termination instead.
13003 */
13004 asc_dvc->cfg->termination = termination;
13005 warn_code |= ASC_WARN_EEPROM_TERMINATION;
13006 }
13007 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013008
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013009 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013010}
13011
13012/*
13013 * Read the board's EEPROM configuration. Set fields in ASC_DVC_VAR and
13014 * ASC_DVC_CFG based on the EEPROM settings. The chip is stopped while
13015 * all of this is done.
13016 *
13017 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
13018 *
13019 * For a non-fatal error return a warning code. If there are no warnings
13020 * then 0 is returned.
13021 *
13022 * Note: Chip is stopped on entry.
13023 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013024static int __devinit AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013025{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013026 AdvPortAddr iop_base;
13027 ushort warn_code;
13028 ADVEEP_38C1600_CONFIG eep_config;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013029 uchar tid, termination;
13030 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013031
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013032 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013033
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013034 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013035
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013036 /*
13037 * Read the board's EEPROM configuration.
13038 *
13039 * Set default values if a bad checksum is found.
13040 */
13041 if (AdvGet38C1600EEPConfig(iop_base, &eep_config) !=
13042 eep_config.check_sum) {
Matthew Wilcox13ac2d92007-07-30 08:10:23 -060013043 struct pci_dev *pdev = adv_dvc_to_pdev(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013044 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013045
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013046 /*
13047 * Set EEPROM default values.
13048 */
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040013049 memcpy(&eep_config, &Default_38C1600_EEPROM_Config,
13050 sizeof(ADVEEP_38C1600_CONFIG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013051
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040013052 if (PCI_FUNC(pdev->devfn) != 0) {
13053 u8 ints;
13054 /*
13055 * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60
13056 * and old Mac system booting problem. The Expansion
13057 * ROM must be disabled in Function 1 for these systems
13058 */
13059 eep_config.cfg_lsw &= ~ADV_EEPROM_BIOS_ENABLE;
13060 /*
13061 * Clear the INTAB (bit 11) if the GPIO 0 input
13062 * indicates the Function 1 interrupt line is wired
13063 * to INTB.
13064 *
13065 * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input:
13066 * 1 - Function 1 interrupt line wired to INT A.
13067 * 0 - Function 1 interrupt line wired to INT B.
13068 *
13069 * Note: Function 0 is always wired to INTA.
13070 * Put all 5 GPIO bits in input mode and then read
13071 * their input values.
13072 */
13073 AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL, 0);
13074 ints = AdvReadByteRegister(iop_base, IOPB_GPIO_DATA);
13075 if ((ints & 0x01) == 0)
13076 eep_config.cfg_lsw &= ~ADV_EEPROM_INTAB;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013077 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013078
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013079 /*
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040013080 * Assume the 6 byte board serial number that was read from
13081 * EEPROM is correct even if the EEPROM checksum failed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013082 */
13083 eep_config.serial_number_word3 =
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040013084 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013085 eep_config.serial_number_word2 =
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040013086 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013087 eep_config.serial_number_word1 =
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040013088 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013089
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013090 AdvSet38C1600EEPConfig(iop_base, &eep_config);
13091 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013092
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013093 /*
13094 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
13095 * EEPROM configuration that was read.
13096 *
13097 * This is the mapping of EEPROM fields to Adv Library fields.
13098 */
13099 asc_dvc->wdtr_able = eep_config.wdtr_able;
13100 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
13101 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
13102 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
13103 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
13104 asc_dvc->ppr_able = 0;
13105 asc_dvc->tagqng_able = eep_config.tagqng_able;
13106 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
13107 asc_dvc->max_host_qng = eep_config.max_host_qng;
13108 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
13109 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ASC_MAX_TID);
13110 asc_dvc->start_motor = eep_config.start_motor;
13111 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
13112 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
13113 asc_dvc->no_scam = eep_config.scam_tolerant;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013114
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013115 /*
13116 * For every Target ID if any of its 'sdtr_speed[1234]' bits
13117 * are set, then set an 'sdtr_able' bit for it.
13118 */
13119 asc_dvc->sdtr_able = 0;
13120 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
13121 if (tid == 0) {
13122 sdtr_speed = asc_dvc->sdtr_speed1;
13123 } else if (tid == 4) {
13124 sdtr_speed = asc_dvc->sdtr_speed2;
13125 } else if (tid == 8) {
13126 sdtr_speed = asc_dvc->sdtr_speed3;
13127 } else if (tid == 12) {
13128 sdtr_speed = asc_dvc->sdtr_speed4;
13129 }
13130 if (sdtr_speed & ASC_MAX_TID) {
13131 asc_dvc->sdtr_able |= (1 << tid);
13132 }
13133 sdtr_speed >>= 4;
13134 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013135
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013136 /*
13137 * Set the host maximum queuing (max. 253, min. 16) and the per device
13138 * maximum queuing (max. 63, min. 4).
13139 */
13140 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
13141 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
13142 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
13143 /* If the value is zero, assume it is uninitialized. */
13144 if (eep_config.max_host_qng == 0) {
13145 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
13146 } else {
13147 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
13148 }
13149 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013150
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013151 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
13152 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
13153 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
13154 /* If the value is zero, assume it is uninitialized. */
13155 if (eep_config.max_dvc_qng == 0) {
13156 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
13157 } else {
13158 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
13159 }
13160 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013161
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013162 /*
13163 * If 'max_dvc_qng' is greater than 'max_host_qng', then
13164 * set 'max_dvc_qng' to 'max_host_qng'.
13165 */
13166 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
13167 eep_config.max_dvc_qng = eep_config.max_host_qng;
13168 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013169
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013170 /*
13171 * Set ASC_DVC_VAR 'max_host_qng' and ASC_DVC_VAR 'max_dvc_qng'
13172 * values based on possibly adjusted EEPROM values.
13173 */
13174 asc_dvc->max_host_qng = eep_config.max_host_qng;
13175 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013176
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013177 /*
13178 * If the EEPROM 'termination' field is set to automatic (0), then set
13179 * the ASC_DVC_CFG 'termination' field to automatic also.
13180 *
13181 * If the termination is specified with a non-zero 'termination'
13182 * value check that a legal value is set and set the ASC_DVC_CFG
13183 * 'termination' field appropriately.
13184 */
13185 if (eep_config.termination_se == 0) {
13186 termination = 0; /* auto termination for SE */
13187 } else {
13188 /* Enable manual control with low off / high off. */
13189 if (eep_config.termination_se == 1) {
13190 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013191
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013192 /* Enable manual control with low off / high on. */
13193 } else if (eep_config.termination_se == 2) {
13194 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013195
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013196 /* Enable manual control with low on / high on. */
13197 } else if (eep_config.termination_se == 3) {
13198 termination = TERM_SE;
13199 } else {
13200 /*
13201 * The EEPROM 'termination_se' field contains a bad value.
13202 * Use automatic termination instead.
13203 */
13204 termination = 0;
13205 warn_code |= ASC_WARN_EEPROM_TERMINATION;
13206 }
13207 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013208
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013209 if (eep_config.termination_lvd == 0) {
13210 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
13211 } else {
13212 /* Enable manual control with low off / high off. */
13213 if (eep_config.termination_lvd == 1) {
13214 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013215
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013216 /* Enable manual control with low off / high on. */
13217 } else if (eep_config.termination_lvd == 2) {
13218 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013219
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013220 /* Enable manual control with low on / high on. */
13221 } else if (eep_config.termination_lvd == 3) {
13222 asc_dvc->cfg->termination = termination | TERM_LVD;
13223 } else {
13224 /*
13225 * The EEPROM 'termination_lvd' field contains a bad value.
13226 * Use automatic termination instead.
13227 */
13228 asc_dvc->cfg->termination = termination;
13229 warn_code |= ASC_WARN_EEPROM_TERMINATION;
13230 }
13231 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013232
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013233 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013234}
13235
13236/*
13237 * Read EEPROM configuration into the specified buffer.
13238 *
13239 * Return a checksum based on the EEPROM configuration read.
13240 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013241static ushort __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -070013242AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
13243{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013244 ushort wval, chksum;
13245 ushort *wbuf;
13246 int eep_addr;
13247 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013248
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013249 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
13250 wbuf = (ushort *)cfg_buf;
13251 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013252
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013253 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
13254 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
13255 wval = AdvReadEEPWord(iop_base, eep_addr);
13256 chksum += wval; /* Checksum is calculated from word values. */
13257 if (*charfields++) {
13258 *wbuf = le16_to_cpu(wval);
13259 } else {
13260 *wbuf = wval;
13261 }
13262 }
13263 /* Read checksum word. */
13264 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
13265 wbuf++;
13266 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013267
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013268 /* Read rest of EEPROM not covered by the checksum. */
13269 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
13270 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
13271 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
13272 if (*charfields++) {
13273 *wbuf = le16_to_cpu(*wbuf);
13274 }
13275 }
13276 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013277}
13278
13279/*
13280 * Read EEPROM configuration into the specified buffer.
13281 *
13282 * Return a checksum based on the EEPROM configuration read.
13283 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013284static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013285AdvGet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013286{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013287 ushort wval, chksum;
13288 ushort *wbuf;
13289 int eep_addr;
13290 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013291
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013292 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
13293 wbuf = (ushort *)cfg_buf;
13294 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013295
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013296 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
13297 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
13298 wval = AdvReadEEPWord(iop_base, eep_addr);
13299 chksum += wval; /* Checksum is calculated from word values. */
13300 if (*charfields++) {
13301 *wbuf = le16_to_cpu(wval);
13302 } else {
13303 *wbuf = wval;
13304 }
13305 }
13306 /* Read checksum word. */
13307 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
13308 wbuf++;
13309 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013310
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013311 /* Read rest of EEPROM not covered by the checksum. */
13312 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
13313 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
13314 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
13315 if (*charfields++) {
13316 *wbuf = le16_to_cpu(*wbuf);
13317 }
13318 }
13319 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013320}
13321
13322/*
13323 * Read EEPROM configuration into the specified buffer.
13324 *
13325 * Return a checksum based on the EEPROM configuration read.
13326 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013327static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013328AdvGet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013329{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013330 ushort wval, chksum;
13331 ushort *wbuf;
13332 int eep_addr;
13333 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013334
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013335 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
13336 wbuf = (ushort *)cfg_buf;
13337 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013338
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013339 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
13340 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
13341 wval = AdvReadEEPWord(iop_base, eep_addr);
13342 chksum += wval; /* Checksum is calculated from word values. */
13343 if (*charfields++) {
13344 *wbuf = le16_to_cpu(wval);
13345 } else {
13346 *wbuf = wval;
13347 }
13348 }
13349 /* Read checksum word. */
13350 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
13351 wbuf++;
13352 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013353
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013354 /* Read rest of EEPROM not covered by the checksum. */
13355 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
13356 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
13357 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
13358 if (*charfields++) {
13359 *wbuf = le16_to_cpu(*wbuf);
13360 }
13361 }
13362 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013363}
13364
13365/*
13366 * Read the EEPROM from specified location
13367 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013368static ushort __devinit AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013369{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013370 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
13371 ASC_EEP_CMD_READ | eep_word_addr);
13372 AdvWaitEEPCmd(iop_base);
13373 return AdvReadWordRegister(iop_base, IOPW_EE_DATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013374}
13375
13376/*
13377 * Wait for EEPROM command to complete
13378 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013379static void __devinit AdvWaitEEPCmd(AdvPortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013380{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013381 int eep_delay_ms;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013382
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013383 for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++) {
13384 if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) &
13385 ASC_EEP_CMD_DONE) {
13386 break;
13387 }
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060013388 mdelay(1);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013389 }
13390 if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) ==
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060013391 0)
13392 BUG();
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013393 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013394}
13395
13396/*
13397 * Write the EEPROM from 'cfg_buf'.
13398 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013399void __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -070013400AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
13401{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013402 ushort *wbuf;
13403 ushort addr, chksum;
13404 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013405
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013406 wbuf = (ushort *)cfg_buf;
13407 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
13408 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013409
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013410 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
13411 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013412
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013413 /*
13414 * Write EEPROM from word 0 to word 20.
13415 */
13416 for (addr = ADV_EEP_DVC_CFG_BEGIN;
13417 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
13418 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013419
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013420 if (*charfields++) {
13421 word = cpu_to_le16(*wbuf);
13422 } else {
13423 word = *wbuf;
13424 }
13425 chksum += *wbuf; /* Checksum is calculated from word values. */
13426 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
13427 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
13428 ASC_EEP_CMD_WRITE | addr);
13429 AdvWaitEEPCmd(iop_base);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060013430 mdelay(ADV_EEP_DELAY_MS);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013431 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013432
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013433 /*
13434 * Write EEPROM checksum at word 21.
13435 */
13436 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
13437 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
13438 AdvWaitEEPCmd(iop_base);
13439 wbuf++;
13440 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013441
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013442 /*
13443 * Write EEPROM OEM name at words 22 to 29.
13444 */
13445 for (addr = ADV_EEP_DVC_CTL_BEGIN;
13446 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
13447 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013448
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013449 if (*charfields++) {
13450 word = cpu_to_le16(*wbuf);
13451 } else {
13452 word = *wbuf;
13453 }
13454 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
13455 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
13456 ASC_EEP_CMD_WRITE | addr);
13457 AdvWaitEEPCmd(iop_base);
13458 }
13459 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
13460 AdvWaitEEPCmd(iop_base);
13461 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013462}
13463
13464/*
13465 * Write the EEPROM from 'cfg_buf'.
13466 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013467void __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013468AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013469{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013470 ushort *wbuf;
13471 ushort *charfields;
13472 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013473
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013474 wbuf = (ushort *)cfg_buf;
13475 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
13476 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013477
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013478 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
13479 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013480
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013481 /*
13482 * Write EEPROM from word 0 to word 20.
13483 */
13484 for (addr = ADV_EEP_DVC_CFG_BEGIN;
13485 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
13486 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013487
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013488 if (*charfields++) {
13489 word = cpu_to_le16(*wbuf);
13490 } else {
13491 word = *wbuf;
13492 }
13493 chksum += *wbuf; /* Checksum is calculated from word values. */
13494 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
13495 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
13496 ASC_EEP_CMD_WRITE | addr);
13497 AdvWaitEEPCmd(iop_base);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060013498 mdelay(ADV_EEP_DELAY_MS);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013499 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013500
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013501 /*
13502 * Write EEPROM checksum at word 21.
13503 */
13504 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
13505 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
13506 AdvWaitEEPCmd(iop_base);
13507 wbuf++;
13508 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013509
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013510 /*
13511 * Write EEPROM OEM name at words 22 to 29.
13512 */
13513 for (addr = ADV_EEP_DVC_CTL_BEGIN;
13514 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
13515 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013516
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013517 if (*charfields++) {
13518 word = cpu_to_le16(*wbuf);
13519 } else {
13520 word = *wbuf;
13521 }
13522 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
13523 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
13524 ASC_EEP_CMD_WRITE | addr);
13525 AdvWaitEEPCmd(iop_base);
13526 }
13527 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
13528 AdvWaitEEPCmd(iop_base);
13529 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013530}
13531
13532/*
13533 * Write the EEPROM from 'cfg_buf'.
13534 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013535void __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013536AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013537{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013538 ushort *wbuf;
13539 ushort *charfields;
13540 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013541
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013542 wbuf = (ushort *)cfg_buf;
13543 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
13544 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013545
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013546 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
13547 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013548
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013549 /*
13550 * Write EEPROM from word 0 to word 20.
13551 */
13552 for (addr = ADV_EEP_DVC_CFG_BEGIN;
13553 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
13554 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013555
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013556 if (*charfields++) {
13557 word = cpu_to_le16(*wbuf);
13558 } else {
13559 word = *wbuf;
13560 }
13561 chksum += *wbuf; /* Checksum is calculated from word values. */
13562 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
13563 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
13564 ASC_EEP_CMD_WRITE | addr);
13565 AdvWaitEEPCmd(iop_base);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060013566 mdelay(ADV_EEP_DELAY_MS);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013567 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013568
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013569 /*
13570 * Write EEPROM checksum at word 21.
13571 */
13572 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
13573 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
13574 AdvWaitEEPCmd(iop_base);
13575 wbuf++;
13576 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013577
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013578 /*
13579 * Write EEPROM OEM name at words 22 to 29.
13580 */
13581 for (addr = ADV_EEP_DVC_CTL_BEGIN;
13582 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
13583 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013584
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013585 if (*charfields++) {
13586 word = cpu_to_le16(*wbuf);
13587 } else {
13588 word = *wbuf;
13589 }
13590 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
13591 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
13592 ASC_EEP_CMD_WRITE | addr);
13593 AdvWaitEEPCmd(iop_base);
13594 }
13595 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
13596 AdvWaitEEPCmd(iop_base);
13597 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013598}
13599
Linus Torvalds1da177e2005-04-16 15:20:36 -070013600/*
13601 * AdvExeScsiQueue() - Send a request to the RISC microcode program.
13602 *
13603 * Allocate a carrier structure, point the carrier to the ADV_SCSI_REQ_Q,
13604 * add the carrier to the ICQ (Initiator Command Queue), and tickle the
13605 * RISC to notify it a new command is ready to be executed.
13606 *
13607 * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be
13608 * set to SCSI_MAX_RETRY.
13609 *
13610 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the microcode
13611 * for DMA addresses or math operations are byte swapped to little-endian
13612 * order.
13613 *
13614 * Return:
13615 * ADV_SUCCESS(1) - The request was successfully queued.
13616 * ADV_BUSY(0) - Resource unavailable; Retry again after pending
13617 * request completes.
13618 * ADV_ERROR(-1) - Invalid ADV_SCSI_REQ_Q request structure
13619 * host IC error.
13620 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013621static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013622{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013623 AdvPortAddr iop_base;
13624 ADV_DCNT req_size;
13625 ADV_PADDR req_paddr;
13626 ADV_CARR_T *new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013627
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013628 /*
13629 * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
13630 */
13631 if (scsiq->target_id > ADV_MAX_TID) {
13632 scsiq->host_status = QHSTA_M_INVALID_DEVICE;
13633 scsiq->done_status = QD_WITH_ERROR;
13634 return ADV_ERROR;
13635 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013636
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013637 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013638
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013639 /*
13640 * Allocate a carrier ensuring at least one carrier always
13641 * remains on the freelist and initialize fields.
13642 */
13643 if ((new_carrp = asc_dvc->carr_freelist) == NULL) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013644 return ADV_BUSY;
13645 }
13646 asc_dvc->carr_freelist = (ADV_CARR_T *)
13647 ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa));
13648 asc_dvc->carr_pending_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013649
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013650 /*
13651 * Set the carrier to be a stopper by setting 'next_vpa'
13652 * to the stopper value. The current stopper will be changed
13653 * below to point to the new stopper.
13654 */
13655 new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013656
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013657 /*
13658 * Clear the ADV_SCSI_REQ_Q done flag.
13659 */
13660 scsiq->a_flag &= ~ADV_SCSIQ_DONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013661
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013662 req_size = sizeof(ADV_SCSI_REQ_Q);
13663 req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *)scsiq,
13664 (ADV_SDCNT *)&req_size, ADV_IS_SCSIQ_FLAG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013665
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060013666 BUG_ON(req_paddr & 31);
13667 BUG_ON(req_size < sizeof(ADV_SCSI_REQ_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013668
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013669 /* Wait for assertion before making little-endian */
13670 req_paddr = cpu_to_le32(req_paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013671
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013672 /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
13673 scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq));
13674 scsiq->scsiq_rptr = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013675
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013676 scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp));
13677 /*
13678 * Every ADV_CARR_T.carr_pa is byte swapped to little-endian
13679 * order during initialization.
13680 */
13681 scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013682
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013683 /*
13684 * Use the current stopper to send the ADV_SCSI_REQ_Q command to
13685 * the microcode. The newly allocated stopper will become the new
13686 * stopper.
13687 */
13688 asc_dvc->icq_sp->areq_vpa = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013689
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013690 /*
13691 * Set the 'next_vpa' pointer for the old stopper to be the
13692 * physical address of the new stopper. The RISC can only
13693 * follow physical addresses.
13694 */
13695 asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013696
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013697 /*
13698 * Set the host adapter stopper pointer to point to the new carrier.
13699 */
13700 asc_dvc->icq_sp = new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013701
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013702 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
13703 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
13704 /*
13705 * Tickle the RISC to tell it to read its Command Queue Head pointer.
13706 */
13707 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
13708 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
13709 /*
13710 * Clear the tickle value. In the ASC-3550 the RISC flag
13711 * command 'clr_tickle_a' does not work unless the host
13712 * value is cleared.
13713 */
13714 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
13715 ADV_TICKLE_NOP);
13716 }
13717 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
13718 /*
13719 * Notify the RISC a carrier is ready by writing the physical
13720 * address of the new carrier stopper to the COMMA register.
13721 */
13722 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
13723 le32_to_cpu(new_carrp->carr_pa));
13724 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013725
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013726 return ADV_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013727}
13728
13729/*
13730 * Reset SCSI Bus and purge all outstanding requests.
13731 *
13732 * Return Value:
13733 * ADV_TRUE(1) - All requests are purged and SCSI Bus is reset.
13734 * ADV_FALSE(0) - Microcode command failed.
13735 * ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC
13736 * may be hung which requires driver recovery.
13737 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013738static int AdvResetSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013739{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013740 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013741
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013742 /*
13743 * Send the SCSI Bus Reset idle start idle command which asserts
13744 * the SCSI Bus Reset signal.
13745 */
13746 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_START, 0L);
13747 if (status != ADV_TRUE) {
13748 return status;
13749 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013750
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013751 /*
13752 * Delay for the specified SCSI Bus Reset hold time.
13753 *
13754 * The hold time delay is done on the host because the RISC has no
13755 * microsecond accurate timer.
13756 */
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060013757 udelay(ASC_SCSI_RESET_HOLD_TIME_US);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013758
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013759 /*
13760 * Send the SCSI Bus Reset end idle command which de-asserts
13761 * the SCSI Bus Reset signal and purges any pending requests.
13762 */
13763 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_END, 0L);
13764 if (status != ADV_TRUE) {
13765 return status;
13766 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013767
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060013768 mdelay(asc_dvc->scsi_reset_wait * 1000); /* XXX: msleep? */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013769
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013770 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013771}
13772
13773/*
13774 * Reset chip and SCSI Bus.
13775 *
13776 * Return Value:
13777 * ADV_TRUE(1) - Chip re-initialization and SCSI Bus Reset successful.
13778 * ADV_FALSE(0) - Chip re-initialization and SCSI Bus Reset failure.
13779 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013780static int AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013781{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013782 int status;
13783 ushort wdtr_able, sdtr_able, tagqng_able;
13784 ushort ppr_able = 0;
13785 uchar tid, max_cmd[ADV_MAX_TID + 1];
13786 AdvPortAddr iop_base;
13787 ushort bios_sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013788
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013789 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013790
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013791 /*
13792 * Save current per TID negotiated values.
13793 */
13794 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
13795 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
13796 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
13797 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
13798 }
13799 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
13800 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
13801 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
13802 max_cmd[tid]);
13803 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013804
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013805 /*
13806 * Force the AdvInitAsc3550/38C0800Driver() function to
13807 * perform a SCSI Bus Reset by clearing the BIOS signature word.
13808 * The initialization functions assumes a SCSI Bus Reset is not
13809 * needed if the BIOS signature word is present.
13810 */
13811 AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
13812 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013813
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013814 /*
13815 * Stop chip and reset it.
13816 */
13817 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP);
13818 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060013819 mdelay(100);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013820 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
13821 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013822
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013823 /*
13824 * Reset Adv Library error code, if any, and try
13825 * re-initializing the chip.
13826 */
13827 asc_dvc->err_code = 0;
13828 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
13829 status = AdvInitAsc38C1600Driver(asc_dvc);
13830 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
13831 status = AdvInitAsc38C0800Driver(asc_dvc);
13832 } else {
13833 status = AdvInitAsc3550Driver(asc_dvc);
13834 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013835
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013836 /* Translate initialization return value to status value. */
13837 if (status == 0) {
13838 status = ADV_TRUE;
13839 } else {
13840 status = ADV_FALSE;
13841 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013842
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013843 /*
13844 * Restore the BIOS signature word.
13845 */
13846 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013847
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013848 /*
13849 * Restore per TID negotiated values.
13850 */
13851 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
13852 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
13853 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
13854 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
13855 }
13856 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
13857 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
13858 AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
13859 max_cmd[tid]);
13860 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013861
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013862 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013863}
13864
13865/*
13866 * Adv Library Interrupt Service Routine
13867 *
13868 * This function is called by a driver's interrupt service routine.
13869 * The function disables and re-enables interrupts.
13870 *
13871 * When a microcode idle command is completed, the ADV_DVC_VAR
13872 * 'idle_cmd_done' field is set to ADV_TRUE.
13873 *
13874 * Note: AdvISR() can be called when interrupts are disabled or even
13875 * when there is no hardware interrupt condition present. It will
13876 * always check for completed idle commands and microcode requests.
13877 * This is an important feature that shouldn't be changed because it
13878 * allows commands to be completed from polling mode loops.
13879 *
13880 * Return:
13881 * ADV_TRUE(1) - interrupt was pending
13882 * ADV_FALSE(0) - no interrupt was pending
13883 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013884static int AdvISR(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013885{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013886 AdvPortAddr iop_base;
13887 uchar int_stat;
13888 ushort target_bit;
13889 ADV_CARR_T *free_carrp;
13890 ADV_VADDR irq_next_vpa;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013891 ADV_SCSI_REQ_Q *scsiq;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013892
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013893 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013894
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013895 /* Reading the register clears the interrupt. */
13896 int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013897
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013898 if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB |
13899 ADV_INTR_STATUS_INTRC)) == 0) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013900 return ADV_FALSE;
13901 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013902
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013903 /*
13904 * Notify the driver of an asynchronous microcode condition by
Matthew Wilcox895d6b42007-07-26 11:57:06 -040013905 * calling the adv_async_callback function. The function
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013906 * is passed the microcode ASC_MC_INTRB_CODE byte value.
13907 */
13908 if (int_stat & ADV_INTR_STATUS_INTRB) {
13909 uchar intrb_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013910
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013911 AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013912
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013913 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
13914 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
13915 if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
13916 asc_dvc->carr_pending_cnt != 0) {
13917 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
13918 ADV_TICKLE_A);
13919 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
13920 AdvWriteByteRegister(iop_base,
13921 IOPB_TICKLE,
13922 ADV_TICKLE_NOP);
13923 }
13924 }
13925 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013926
Matthew Wilcox895d6b42007-07-26 11:57:06 -040013927 adv_async_callback(asc_dvc, intrb_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013928 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013929
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013930 /*
13931 * Check if the IRQ stopper carrier contains a completed request.
13932 */
13933 while (((irq_next_vpa =
13934 le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0) {
13935 /*
13936 * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
13937 * The RISC will have set 'areq_vpa' to a virtual address.
13938 *
13939 * The firmware will have copied the ASC_SCSI_REQ_Q.scsiq_ptr
13940 * field to the carrier ADV_CARR_T.areq_vpa field. The conversion
13941 * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr'
13942 * in AdvExeScsiQueue().
13943 */
13944 scsiq = (ADV_SCSI_REQ_Q *)
13945 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013946
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013947 /*
13948 * Request finished with good status and the queue was not
13949 * DMAed to host memory by the firmware. Set all status fields
13950 * to indicate good status.
13951 */
13952 if ((irq_next_vpa & ASC_RQ_GOOD) != 0) {
13953 scsiq->done_status = QD_NO_ERROR;
13954 scsiq->host_status = scsiq->scsi_status = 0;
13955 scsiq->data_cnt = 0L;
13956 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013957
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013958 /*
13959 * Advance the stopper pointer to the next carrier
13960 * ignoring the lower four bits. Free the previous
13961 * stopper carrier.
13962 */
13963 free_carrp = asc_dvc->irq_sp;
13964 asc_dvc->irq_sp = (ADV_CARR_T *)
13965 ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013966
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013967 free_carrp->next_vpa =
13968 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
13969 asc_dvc->carr_freelist = free_carrp;
13970 asc_dvc->carr_pending_cnt--;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013971
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013972 target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013973
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013974 /*
13975 * Clear request microcode control flag.
13976 */
13977 scsiq->cntl = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013978
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013979 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013980 * Notify the driver of the completed request by passing
13981 * the ADV_SCSI_REQ_Q pointer to its callback function.
13982 */
13983 scsiq->a_flag |= ADV_SCSIQ_DONE;
Matthew Wilcox895d6b42007-07-26 11:57:06 -040013984 adv_isr_callback(asc_dvc, scsiq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013985 /*
13986 * Note: After the driver callback function is called, 'scsiq'
13987 * can no longer be referenced.
13988 *
13989 * Fall through and continue processing other completed
13990 * requests...
13991 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013992 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013993 return ADV_TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013994}
13995
13996/*
13997 * Send an idle command to the chip and wait for completion.
13998 *
13999 * Command completion is polled for once per microsecond.
14000 *
14001 * The function can be called from anywhere including an interrupt handler.
14002 * But the function is not re-entrant, so it uses the DvcEnter/LeaveCritical()
14003 * functions to prevent reentrancy.
14004 *
14005 * Return Values:
14006 * ADV_TRUE - command completed successfully
14007 * ADV_FALSE - command failed
14008 * ADV_ERROR - command timed out
14009 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014010static int
Linus Torvalds1da177e2005-04-16 15:20:36 -070014011AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014012 ushort idle_cmd, ADV_DCNT idle_cmd_parameter)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014013{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014014 int result;
14015 ADV_DCNT i, j;
14016 AdvPortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014017
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014018 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014019
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014020 /*
14021 * Clear the idle command status which is set by the microcode
14022 * to a non-zero value to indicate when the command is completed.
14023 * The non-zero result is one of the IDLE_CMD_STATUS_* values
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014024 */
14025 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort)0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014026
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014027 /*
14028 * Write the idle command value after the idle command parameter
14029 * has been written to avoid a race condition. If the order is not
14030 * followed, the microcode may process the idle command before the
14031 * parameters have been written to LRAM.
14032 */
14033 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
14034 cpu_to_le32(idle_cmd_parameter));
14035 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014036
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014037 /*
14038 * Tickle the RISC to tell it to process the idle command.
14039 */
14040 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B);
14041 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
14042 /*
14043 * Clear the tickle value. In the ASC-3550 the RISC flag
14044 * command 'clr_tickle_b' does not work unless the host
14045 * value is cleared.
14046 */
14047 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
14048 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014049
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014050 /* Wait for up to 100 millisecond for the idle command to timeout. */
14051 for (i = 0; i < SCSI_WAIT_100_MSEC; i++) {
14052 /* Poll once each microsecond for command completion. */
14053 for (j = 0; j < SCSI_US_PER_MSEC; j++) {
14054 AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS,
14055 result);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060014056 if (result != 0)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014057 return result;
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060014058 udelay(1);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014059 }
14060 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014061
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060014062 BUG(); /* The idle command should never timeout. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014063 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014064}
14065
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060014066static int __devinit
14067advansys_wide_init_chip(asc_board_t *boardp, ADV_DVC_VAR *adv_dvc_varp)
14068{
14069 int req_cnt = 0;
14070 adv_req_t *reqp = NULL;
14071 int sg_cnt = 0;
14072 adv_sgblk_t *sgp;
14073 int warn_code, err_code;
14074
14075 /*
14076 * Allocate buffer carrier structures. The total size
14077 * is about 4 KB, so allocate all at once.
14078 */
14079 boardp->carrp = kmalloc(ADV_CARRIER_BUFSIZE, GFP_KERNEL);
14080 ASC_DBG1(1, "advansys_wide_init_chip: carrp 0x%p\n", boardp->carrp);
14081
14082 if (!boardp->carrp)
14083 goto kmalloc_failed;
14084
14085 /*
14086 * Allocate up to 'max_host_qng' request structures for the Wide
14087 * board. The total size is about 16 KB, so allocate all at once.
14088 * If the allocation fails decrement and try again.
14089 */
14090 for (req_cnt = adv_dvc_varp->max_host_qng; req_cnt > 0; req_cnt--) {
14091 reqp = kmalloc(sizeof(adv_req_t) * req_cnt, GFP_KERNEL);
14092
14093 ASC_DBG3(1, "advansys_wide_init_chip: reqp 0x%p, req_cnt %d, "
14094 "bytes %lu\n", reqp, req_cnt,
14095 (ulong)sizeof(adv_req_t) * req_cnt);
14096
14097 if (reqp)
14098 break;
14099 }
14100
14101 if (!reqp)
14102 goto kmalloc_failed;
14103
14104 boardp->orig_reqp = reqp;
14105
14106 /*
14107 * Allocate up to ADV_TOT_SG_BLOCK request structures for
14108 * the Wide board. Each structure is about 136 bytes.
14109 */
14110 boardp->adv_sgblkp = NULL;
14111 for (sg_cnt = 0; sg_cnt < ADV_TOT_SG_BLOCK; sg_cnt++) {
14112 sgp = kmalloc(sizeof(adv_sgblk_t), GFP_KERNEL);
14113
14114 if (!sgp)
14115 break;
14116
14117 sgp->next_sgblkp = boardp->adv_sgblkp;
14118 boardp->adv_sgblkp = sgp;
14119
14120 }
14121
14122 ASC_DBG3(1, "advansys_wide_init_chip: sg_cnt %d * %u = %u bytes\n",
14123 sg_cnt, sizeof(adv_sgblk_t),
14124 (unsigned)(sizeof(adv_sgblk_t) * sg_cnt));
14125
14126 if (!boardp->adv_sgblkp)
14127 goto kmalloc_failed;
14128
14129 adv_dvc_varp->carrier_buf = boardp->carrp;
14130
14131 /*
14132 * Point 'adv_reqp' to the request structures and
14133 * link them together.
14134 */
14135 req_cnt--;
14136 reqp[req_cnt].next_reqp = NULL;
14137 for (; req_cnt > 0; req_cnt--) {
14138 reqp[req_cnt - 1].next_reqp = &reqp[req_cnt];
14139 }
14140 boardp->adv_reqp = &reqp[0];
14141
14142 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
14143 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc3550Driver()\n");
14144 warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
14145 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
14146 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc38C0800Driver()"
14147 "\n");
14148 warn_code = AdvInitAsc38C0800Driver(adv_dvc_varp);
14149 } else {
14150 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc38C1600Driver()"
14151 "\n");
14152 warn_code = AdvInitAsc38C1600Driver(adv_dvc_varp);
14153 }
14154 err_code = adv_dvc_varp->err_code;
14155
14156 if (warn_code || err_code) {
14157 ASC_PRINT3("advansys_wide_init_chip: board %d error: warn 0x%x,"
14158 " error 0x%x\n", boardp->id, warn_code, err_code);
14159 }
14160
14161 goto exit;
14162
14163 kmalloc_failed:
14164 ASC_PRINT1("advansys_wide_init_chip: board %d error: kmalloc() "
14165 "failed\n", boardp->id);
14166 err_code = ADV_ERROR;
14167 exit:
14168 return err_code;
14169}
14170
14171static void advansys_wide_free_mem(asc_board_t *boardp)
14172{
14173 kfree(boardp->carrp);
14174 boardp->carrp = NULL;
14175 kfree(boardp->orig_reqp);
14176 boardp->orig_reqp = boardp->adv_reqp = NULL;
14177 while (boardp->adv_sgblkp) {
14178 adv_sgblk_t *sgp = boardp->adv_sgblkp;
14179 boardp->adv_sgblkp = sgp->next_sgblkp;
14180 kfree(sgp);
14181 }
14182}
14183
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014184static struct Scsi_Host *__devinit
14185advansys_board_found(int iop, struct device *dev, int bus_type)
14186{
14187 struct Scsi_Host *shost;
14188 struct pci_dev *pdev = bus_type == ASC_IS_PCI ? to_pci_dev(dev) : NULL;
14189 asc_board_t *boardp;
14190 ASC_DVC_VAR *asc_dvc_varp = NULL;
14191 ADV_DVC_VAR *adv_dvc_varp = NULL;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060014192 int share_irq;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014193 int warn_code, err_code;
14194 int ret;
14195
14196 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014197 * Register the adapter, get its configuration, and
14198 * initialize it.
14199 */
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060014200 ASC_DBG(2, "advansys_board_found: scsi_host_alloc()\n");
14201 shost = scsi_host_alloc(&advansys_template, sizeof(asc_board_t));
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014202 if (!shost)
14203 return NULL;
14204
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014205 /* Initialize private per board data */
14206 boardp = ASC_BOARDP(shost);
14207 memset(boardp, 0, sizeof(asc_board_t));
Matthew Wilcox78e77d82007-07-29 21:46:15 -060014208 boardp->id = asc_board_count++;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014209 spin_lock_init(&boardp->lock);
Matthew Wilcox394dbf32007-07-26 11:56:40 -040014210 boardp->dev = dev;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014211
14212 /*
14213 * Handle both narrow and wide boards.
14214 *
14215 * If a Wide board was detected, set the board structure
14216 * wide board flag. Set-up the board structure based on
14217 * the board type.
14218 */
14219#ifdef CONFIG_PCI
14220 if (bus_type == ASC_IS_PCI &&
14221 (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW ||
14222 pdev->device == PCI_DEVICE_ID_38C0800_REV1 ||
14223 pdev->device == PCI_DEVICE_ID_38C1600_REV1)) {
14224 boardp->flags |= ASC_IS_WIDE_BOARD;
14225 }
14226#endif /* CONFIG_PCI */
14227
14228 if (ASC_NARROW_BOARD(boardp)) {
14229 ASC_DBG(1, "advansys_board_found: narrow board\n");
14230 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
14231 asc_dvc_varp->bus_type = bus_type;
14232 asc_dvc_varp->drv_ptr = boardp;
14233 asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg;
14234 asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
14235 asc_dvc_varp->iop_base = iop;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014236 } else {
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040014237#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014238 ASC_DBG(1, "advansys_board_found: wide board\n");
14239 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
14240 adv_dvc_varp->drv_ptr = boardp;
14241 adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014242 if (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW) {
14243 ASC_DBG(1, "advansys_board_found: ASC-3550\n");
14244 adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
14245 } else if (pdev->device == PCI_DEVICE_ID_38C0800_REV1) {
14246 ASC_DBG(1, "advansys_board_found: ASC-38C0800\n");
14247 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
14248 } else {
14249 ASC_DBG(1, "advansys_board_found: ASC-38C1600\n");
14250 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C1600;
14251 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014252
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040014253 boardp->asc_n_io_port = pci_resource_len(pdev, 1);
14254 boardp->ioremap_addr = ioremap(pci_resource_start(pdev, 1),
14255 boardp->asc_n_io_port);
14256 if (!boardp->ioremap_addr) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014257 ASC_PRINT3
14258 ("advansys_board_found: board %d: ioremap(%x, %d) returned NULL\n",
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040014259 boardp->id, pci_resource_start(pdev, 1),
14260 boardp->asc_n_io_port);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060014261 goto err_shost;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014262 }
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040014263 adv_dvc_varp->iop_base = (AdvPortAddr)boardp->ioremap_addr
Matthew Wilcox71f36112007-07-30 08:04:53 -060014264 ASC_DBG1(1, "advansys_board_found: iop_base: 0x%lx\n",
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014265 adv_dvc_varp->iop_base);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014266
14267 /*
14268 * Even though it isn't used to access wide boards, other
14269 * than for the debug line below, save I/O Port address so
14270 * that it can be reported.
14271 */
14272 boardp->ioport = iop;
14273
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040014274 ASC_DBG2(1, "advansys_board_found: iopb_chip_id_1 0x%x, "
14275 "iopw_chip_id_0 0x%x\n", (ushort)inp(iop + 1),
14276 (ushort)inpw(iop));
14277#endif /* CONFIG_PCI */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014278 }
14279
14280#ifdef CONFIG_PROC_FS
14281 /*
14282 * Allocate buffer for printing information from
14283 * /proc/scsi/advansys/[0...].
14284 */
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060014285 boardp->prtbuf = kmalloc(ASC_PRTBUF_SIZE, GFP_KERNEL);
14286 if (!boardp->prtbuf) {
14287 ASC_PRINT2("advansys_board_found: board %d: kmalloc(%d) "
14288 "returned NULL\n", boardp->id, ASC_PRTBUF_SIZE);
14289 goto err_unmap;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014290 }
14291#endif /* CONFIG_PROC_FS */
14292
14293 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014294 /*
14295 * Set the board bus type and PCI IRQ before
14296 * calling AscInitGetConfig().
14297 */
14298 switch (asc_dvc_varp->bus_type) {
14299#ifdef CONFIG_ISA
14300 case ASC_IS_ISA:
14301 shost->unchecked_isa_dma = TRUE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060014302 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014303 break;
14304 case ASC_IS_VL:
14305 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060014306 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014307 break;
14308 case ASC_IS_EISA:
14309 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060014310 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014311 break;
14312#endif /* CONFIG_ISA */
14313#ifdef CONFIG_PCI
14314 case ASC_IS_PCI:
14315 shost->irq = asc_dvc_varp->irq_no = pdev->irq;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014316 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060014317 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014318 break;
14319#endif /* CONFIG_PCI */
14320 default:
14321 ASC_PRINT2
14322 ("advansys_board_found: board %d: unknown adapter type: %d\n",
14323 boardp->id, asc_dvc_varp->bus_type);
14324 shost->unchecked_isa_dma = TRUE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060014325 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014326 break;
14327 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014328
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014329 /*
14330 * NOTE: AscInitGetConfig() may change the board's
14331 * bus_type value. The bus_type value should no
14332 * longer be used. If the bus_type field must be
14333 * referenced only use the bit-wise AND operator "&".
14334 */
14335 ASC_DBG(2, "advansys_board_found: AscInitGetConfig()\n");
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060014336 err_code = AscInitGetConfig(boardp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014337 } else {
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060014338#ifdef CONFIG_PCI
14339 /*
14340 * For Wide boards set PCI information before calling
14341 * AdvInitGetConfig().
14342 */
14343 shost->irq = adv_dvc_varp->irq_no = pdev->irq;
14344 shost->unchecked_isa_dma = FALSE;
14345 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014346 ASC_DBG(2, "advansys_board_found: AdvInitGetConfig()\n");
Matthew Wilcox394dbf32007-07-26 11:56:40 -040014347
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060014348 err_code = AdvInitGetConfig(pdev, boardp);
14349#endif /* CONFIG_PCI */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014350 }
14351
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060014352 if (err_code != 0)
14353 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014354
14355 /*
14356 * Save the EEPROM configuration so that it can be displayed
14357 * from /proc/scsi/advansys/[0...].
14358 */
14359 if (ASC_NARROW_BOARD(boardp)) {
14360
14361 ASCEEP_CONFIG *ep;
14362
14363 /*
14364 * Set the adapter's target id bit in the 'init_tidmask' field.
14365 */
14366 boardp->init_tidmask |=
14367 ADV_TID_TO_TIDMASK(asc_dvc_varp->cfg->chip_scsi_id);
14368
14369 /*
14370 * Save EEPROM settings for the board.
14371 */
14372 ep = &boardp->eep_config.asc_eep;
14373
14374 ep->init_sdtr = asc_dvc_varp->cfg->sdtr_enable;
14375 ep->disc_enable = asc_dvc_varp->cfg->disc_enable;
14376 ep->use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled;
14377 ASC_EEP_SET_DMA_SPD(ep, asc_dvc_varp->cfg->isa_dma_speed);
14378 ep->start_motor = asc_dvc_varp->start_motor;
14379 ep->cntl = asc_dvc_varp->dvc_cntl;
14380 ep->no_scam = asc_dvc_varp->no_scam;
14381 ep->max_total_qng = asc_dvc_varp->max_total_qng;
14382 ASC_EEP_SET_CHIP_ID(ep, asc_dvc_varp->cfg->chip_scsi_id);
14383 /* 'max_tag_qng' is set to the same value for every device. */
14384 ep->max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0];
14385 ep->adapter_info[0] = asc_dvc_varp->cfg->adapter_info[0];
14386 ep->adapter_info[1] = asc_dvc_varp->cfg->adapter_info[1];
14387 ep->adapter_info[2] = asc_dvc_varp->cfg->adapter_info[2];
14388 ep->adapter_info[3] = asc_dvc_varp->cfg->adapter_info[3];
14389 ep->adapter_info[4] = asc_dvc_varp->cfg->adapter_info[4];
14390 ep->adapter_info[5] = asc_dvc_varp->cfg->adapter_info[5];
14391
14392 /*
14393 * Modify board configuration.
14394 */
14395 ASC_DBG(2, "advansys_board_found: AscInitSetConfig()\n");
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060014396 err_code = AscInitSetConfig(pdev, boardp);
14397 if (err_code)
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060014398 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014399
14400 /*
14401 * Finish initializing the 'Scsi_Host' structure.
14402 */
14403 /* AscInitSetConfig() will set the IRQ for non-PCI boards. */
14404 if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
14405 shost->irq = asc_dvc_varp->irq_no;
14406 }
14407 } else {
14408 ADVEEP_3550_CONFIG *ep_3550;
14409 ADVEEP_38C0800_CONFIG *ep_38C0800;
14410 ADVEEP_38C1600_CONFIG *ep_38C1600;
14411
14412 /*
14413 * Save Wide EEP Configuration Information.
14414 */
14415 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
14416 ep_3550 = &boardp->eep_config.adv_3550_eep;
14417
14418 ep_3550->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
14419 ep_3550->max_host_qng = adv_dvc_varp->max_host_qng;
14420 ep_3550->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
14421 ep_3550->termination = adv_dvc_varp->cfg->termination;
14422 ep_3550->disc_enable = adv_dvc_varp->cfg->disc_enable;
14423 ep_3550->bios_ctrl = adv_dvc_varp->bios_ctrl;
14424 ep_3550->wdtr_able = adv_dvc_varp->wdtr_able;
14425 ep_3550->sdtr_able = adv_dvc_varp->sdtr_able;
14426 ep_3550->ultra_able = adv_dvc_varp->ultra_able;
14427 ep_3550->tagqng_able = adv_dvc_varp->tagqng_able;
14428 ep_3550->start_motor = adv_dvc_varp->start_motor;
14429 ep_3550->scsi_reset_delay =
14430 adv_dvc_varp->scsi_reset_wait;
14431 ep_3550->serial_number_word1 =
14432 adv_dvc_varp->cfg->serial1;
14433 ep_3550->serial_number_word2 =
14434 adv_dvc_varp->cfg->serial2;
14435 ep_3550->serial_number_word3 =
14436 adv_dvc_varp->cfg->serial3;
14437 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
14438 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
14439
14440 ep_38C0800->adapter_scsi_id =
14441 adv_dvc_varp->chip_scsi_id;
14442 ep_38C0800->max_host_qng = adv_dvc_varp->max_host_qng;
14443 ep_38C0800->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
14444 ep_38C0800->termination_lvd =
14445 adv_dvc_varp->cfg->termination;
14446 ep_38C0800->disc_enable =
14447 adv_dvc_varp->cfg->disc_enable;
14448 ep_38C0800->bios_ctrl = adv_dvc_varp->bios_ctrl;
14449 ep_38C0800->wdtr_able = adv_dvc_varp->wdtr_able;
14450 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
14451 ep_38C0800->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
14452 ep_38C0800->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
14453 ep_38C0800->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
14454 ep_38C0800->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
14455 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
14456 ep_38C0800->start_motor = adv_dvc_varp->start_motor;
14457 ep_38C0800->scsi_reset_delay =
14458 adv_dvc_varp->scsi_reset_wait;
14459 ep_38C0800->serial_number_word1 =
14460 adv_dvc_varp->cfg->serial1;
14461 ep_38C0800->serial_number_word2 =
14462 adv_dvc_varp->cfg->serial2;
14463 ep_38C0800->serial_number_word3 =
14464 adv_dvc_varp->cfg->serial3;
14465 } else {
14466 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
14467
14468 ep_38C1600->adapter_scsi_id =
14469 adv_dvc_varp->chip_scsi_id;
14470 ep_38C1600->max_host_qng = adv_dvc_varp->max_host_qng;
14471 ep_38C1600->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
14472 ep_38C1600->termination_lvd =
14473 adv_dvc_varp->cfg->termination;
14474 ep_38C1600->disc_enable =
14475 adv_dvc_varp->cfg->disc_enable;
14476 ep_38C1600->bios_ctrl = adv_dvc_varp->bios_ctrl;
14477 ep_38C1600->wdtr_able = adv_dvc_varp->wdtr_able;
14478 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
14479 ep_38C1600->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
14480 ep_38C1600->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
14481 ep_38C1600->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
14482 ep_38C1600->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
14483 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
14484 ep_38C1600->start_motor = adv_dvc_varp->start_motor;
14485 ep_38C1600->scsi_reset_delay =
14486 adv_dvc_varp->scsi_reset_wait;
14487 ep_38C1600->serial_number_word1 =
14488 adv_dvc_varp->cfg->serial1;
14489 ep_38C1600->serial_number_word2 =
14490 adv_dvc_varp->cfg->serial2;
14491 ep_38C1600->serial_number_word3 =
14492 adv_dvc_varp->cfg->serial3;
14493 }
14494
14495 /*
14496 * Set the adapter's target id bit in the 'init_tidmask' field.
14497 */
14498 boardp->init_tidmask |=
14499 ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014500 }
14501
14502 /*
14503 * Channels are numbered beginning with 0. For AdvanSys one host
14504 * structure supports one channel. Multi-channel boards have a
14505 * separate host structure for each channel.
14506 */
14507 shost->max_channel = 0;
14508 if (ASC_NARROW_BOARD(boardp)) {
14509 shost->max_id = ASC_MAX_TID + 1;
14510 shost->max_lun = ASC_MAX_LUN + 1;
Matthew Wilcoxf05ec592007-09-09 08:56:36 -060014511 shost->max_cmd_len = ASC_MAX_CDB_LEN;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014512
14513 shost->io_port = asc_dvc_varp->iop_base;
14514 boardp->asc_n_io_port = ASC_IOADR_GAP;
14515 shost->this_id = asc_dvc_varp->cfg->chip_scsi_id;
14516
14517 /* Set maximum number of queues the adapter can handle. */
14518 shost->can_queue = asc_dvc_varp->max_total_qng;
14519 } else {
14520 shost->max_id = ADV_MAX_TID + 1;
14521 shost->max_lun = ADV_MAX_LUN + 1;
Matthew Wilcoxf05ec592007-09-09 08:56:36 -060014522 shost->max_cmd_len = ADV_MAX_CDB_LEN;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014523
14524 /*
14525 * Save the I/O Port address and length even though
14526 * I/O ports are not used to access Wide boards.
14527 * Instead the Wide boards are accessed with
14528 * PCI Memory Mapped I/O.
14529 */
14530 shost->io_port = iop;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014531
14532 shost->this_id = adv_dvc_varp->chip_scsi_id;
14533
14534 /* Set maximum number of queues the adapter can handle. */
14535 shost->can_queue = adv_dvc_varp->max_host_qng;
14536 }
14537
14538 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014539 * Following v1.3.89, 'cmd_per_lun' is no longer needed
14540 * and should be set to zero.
14541 *
14542 * But because of a bug introduced in v1.3.89 if the driver is
14543 * compiled as a module and 'cmd_per_lun' is zero, the Mid-Level
14544 * SCSI function 'allocate_device' will panic. To allow the driver
14545 * to work as a module in these kernels set 'cmd_per_lun' to 1.
14546 *
14547 * Note: This is wrong. cmd_per_lun should be set to the depth
14548 * you want on untagged devices always.
14549 #ifdef MODULE
14550 */
14551 shost->cmd_per_lun = 1;
14552/* #else
14553 shost->cmd_per_lun = 0;
14554#endif */
14555
14556 /*
14557 * Set the maximum number of scatter-gather elements the
14558 * adapter can handle.
14559 */
14560 if (ASC_NARROW_BOARD(boardp)) {
14561 /*
14562 * Allow two commands with 'sg_tablesize' scatter-gather
14563 * elements to be executed simultaneously. This value is
14564 * the theoretical hardware limit. It may be decreased
14565 * below.
14566 */
14567 shost->sg_tablesize =
14568 (((asc_dvc_varp->max_total_qng - 2) / 2) *
14569 ASC_SG_LIST_PER_Q) + 1;
14570 } else {
14571 shost->sg_tablesize = ADV_MAX_SG_LIST;
14572 }
14573
14574 /*
14575 * The value of 'sg_tablesize' can not exceed the SCSI
14576 * mid-level driver definition of SG_ALL. SG_ALL also
14577 * must not be exceeded, because it is used to define the
14578 * size of the scatter-gather table in 'struct asc_sg_head'.
14579 */
14580 if (shost->sg_tablesize > SG_ALL) {
14581 shost->sg_tablesize = SG_ALL;
14582 }
14583
14584 ASC_DBG1(1, "advansys_board_found: sg_tablesize: %d\n", shost->sg_tablesize);
14585
14586 /* BIOS start address. */
14587 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060014588 shost->base = AscGetChipBiosAddress(asc_dvc_varp->iop_base,
14589 asc_dvc_varp->bus_type);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014590 } else {
14591 /*
14592 * Fill-in BIOS board variables. The Wide BIOS saves
14593 * information in LRAM that is used by the driver.
14594 */
14595 AdvReadWordLram(adv_dvc_varp->iop_base,
14596 BIOS_SIGNATURE, boardp->bios_signature);
14597 AdvReadWordLram(adv_dvc_varp->iop_base,
14598 BIOS_VERSION, boardp->bios_version);
14599 AdvReadWordLram(adv_dvc_varp->iop_base,
14600 BIOS_CODESEG, boardp->bios_codeseg);
14601 AdvReadWordLram(adv_dvc_varp->iop_base,
14602 BIOS_CODELEN, boardp->bios_codelen);
14603
14604 ASC_DBG2(1,
14605 "advansys_board_found: bios_signature 0x%x, bios_version 0x%x\n",
14606 boardp->bios_signature, boardp->bios_version);
14607
14608 ASC_DBG2(1,
14609 "advansys_board_found: bios_codeseg 0x%x, bios_codelen 0x%x\n",
14610 boardp->bios_codeseg, boardp->bios_codelen);
14611
14612 /*
14613 * If the BIOS saved a valid signature, then fill in
14614 * the BIOS code segment base address.
14615 */
14616 if (boardp->bios_signature == 0x55AA) {
14617 /*
14618 * Convert x86 realmode code segment to a linear
14619 * address by shifting left 4.
14620 */
14621 shost->base = ((ulong)boardp->bios_codeseg << 4);
14622 } else {
14623 shost->base = 0;
14624 }
14625 }
14626
14627 /*
14628 * Register Board Resources - I/O Port, DMA, IRQ
14629 */
14630
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014631 /* Register DMA Channel for Narrow boards. */
14632 shost->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */
14633#ifdef CONFIG_ISA
14634 if (ASC_NARROW_BOARD(boardp)) {
14635 /* Register DMA channel for ISA bus. */
14636 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
14637 shost->dma_channel = asc_dvc_varp->cfg->isa_dma_channel;
Matthew Wilcox01fbfe02007-09-09 08:56:40 -060014638 ret = request_dma(shost->dma_channel, DRV_NAME);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060014639 if (ret) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014640 ASC_PRINT3
14641 ("advansys_board_found: board %d: request_dma() %d failed %d\n",
14642 boardp->id, shost->dma_channel, ret);
Matthew Wilcox71f36112007-07-30 08:04:53 -060014643 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014644 }
14645 AscEnableIsaDma(shost->dma_channel);
14646 }
14647 }
14648#endif /* CONFIG_ISA */
14649
14650 /* Register IRQ Number. */
14651 ASC_DBG1(2, "advansys_board_found: request_irq() %d\n", shost->irq);
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060014652
14653 ret = request_irq(shost->irq, advansys_interrupt, share_irq,
Matthew Wilcox01fbfe02007-09-09 08:56:40 -060014654 DRV_NAME, shost);
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060014655
14656 if (ret) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014657 if (ret == -EBUSY) {
14658 ASC_PRINT2
14659 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x already in use.\n",
14660 boardp->id, shost->irq);
14661 } else if (ret == -EINVAL) {
14662 ASC_PRINT2
14663 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x not valid.\n",
14664 boardp->id, shost->irq);
14665 } else {
14666 ASC_PRINT3
14667 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x failed with %d\n",
14668 boardp->id, shost->irq, ret);
14669 }
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060014670 goto err_free_dma;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014671 }
14672
14673 /*
14674 * Initialize board RISC chip and enable interrupts.
14675 */
14676 if (ASC_NARROW_BOARD(boardp)) {
14677 ASC_DBG(2, "advansys_board_found: AscInitAsc1000Driver()\n");
14678 warn_code = AscInitAsc1000Driver(asc_dvc_varp);
14679 err_code = asc_dvc_varp->err_code;
14680
14681 if (warn_code || err_code) {
14682 ASC_PRINT4
14683 ("advansys_board_found: board %d error: init_state 0x%x, warn 0x%x, error 0x%x\n",
14684 boardp->id,
14685 asc_dvc_varp->init_state, warn_code, err_code);
14686 }
14687 } else {
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060014688 err_code = advansys_wide_init_chip(boardp, adv_dvc_varp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014689 }
14690
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060014691 if (err_code != 0)
14692 goto err_free_wide_mem;
14693
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014694 ASC_DBG_PRT_SCSI_HOST(2, shost);
14695
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060014696 ret = scsi_add_host(shost, dev);
14697 if (ret)
14698 goto err_free_wide_mem;
14699
14700 scsi_scan_host(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014701 return shost;
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060014702
14703 err_free_wide_mem:
14704 advansys_wide_free_mem(boardp);
14705 free_irq(shost->irq, shost);
14706 err_free_dma:
14707 if (shost->dma_channel != NO_ISA_DMA)
14708 free_dma(shost->dma_channel);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060014709 err_free_proc:
14710 kfree(boardp->prtbuf);
14711 err_unmap:
14712 if (boardp->ioremap_addr)
14713 iounmap(boardp->ioremap_addr);
14714 err_shost:
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060014715 scsi_host_put(shost);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060014716 return NULL;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014717}
14718
14719/*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014720 * advansys_release()
14721 *
14722 * Release resources allocated for a single AdvanSys adapter.
14723 */
14724static int advansys_release(struct Scsi_Host *shost)
14725{
14726 asc_board_t *boardp;
14727
14728 ASC_DBG(1, "advansys_release: begin\n");
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060014729 scsi_remove_host(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014730 boardp = ASC_BOARDP(shost);
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060014731 free_irq(shost->irq, shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014732 if (shost->dma_channel != NO_ISA_DMA) {
14733 ASC_DBG(1, "advansys_release: free_dma()\n");
14734 free_dma(shost->dma_channel);
14735 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014736 if (ASC_WIDE_BOARD(boardp)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014737 iounmap(boardp->ioremap_addr);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060014738 advansys_wide_free_mem(boardp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014739 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014740 kfree(boardp->prtbuf);
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060014741 scsi_host_put(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014742 ASC_DBG(1, "advansys_release: end\n");
14743 return 0;
14744}
14745
Matthew Wilcox95c9f162007-09-09 08:56:39 -060014746#define ASC_IOADR_TABLE_MAX_IX 11
14747
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060014748static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __devinitdata = {
14749 0x100, 0x0110, 0x120, 0x0130, 0x140, 0x0150, 0x0190,
14750 0x0210, 0x0230, 0x0250, 0x0330
14751};
14752
14753static int __devinit advansys_isa_probe(struct device *dev, unsigned int id)
14754{
14755 PortAddr iop_base = _asc_def_iop_base[id];
14756 struct Scsi_Host *shost;
14757
Matthew Wilcox01fbfe02007-09-09 08:56:40 -060014758 if (!request_region(iop_base, ASC_IOADR_GAP, DRV_NAME)) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060014759 ASC_DBG1(1, "advansys_isa_match: I/O port 0x%x busy\n",
14760 iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060014761 return -ENODEV;
14762 }
14763 ASC_DBG1(1, "advansys_isa_match: probing I/O port 0x%x\n", iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060014764 if (!AscFindSignature(iop_base))
14765 goto nodev;
14766 if (!(AscGetChipVersion(iop_base, ASC_IS_ISA) & ASC_CHIP_VER_ISA_BIT))
14767 goto nodev;
14768
14769 shost = advansys_board_found(iop_base, dev, ASC_IS_ISA);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060014770 if (!shost)
14771 goto nodev;
14772
14773 dev_set_drvdata(dev, shost);
14774 return 0;
14775
14776 nodev:
Matthew Wilcox71f36112007-07-30 08:04:53 -060014777 release_region(iop_base, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060014778 return -ENODEV;
14779}
14780
14781static int __devexit advansys_isa_remove(struct device *dev, unsigned int id)
14782{
Matthew Wilcox71f36112007-07-30 08:04:53 -060014783 int ioport = _asc_def_iop_base[id];
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060014784 advansys_release(dev_get_drvdata(dev));
Matthew Wilcox71f36112007-07-30 08:04:53 -060014785 release_region(ioport, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060014786 return 0;
14787}
14788
14789static struct isa_driver advansys_isa_driver = {
14790 .probe = advansys_isa_probe,
14791 .remove = __devexit_p(advansys_isa_remove),
14792 .driver = {
14793 .owner = THIS_MODULE,
Matthew Wilcox01fbfe02007-09-09 08:56:40 -060014794 .name = DRV_NAME,
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060014795 },
14796};
14797
14798static int __devinit advansys_vlb_probe(struct device *dev, unsigned int id)
14799{
14800 PortAddr iop_base = _asc_def_iop_base[id];
14801 struct Scsi_Host *shost;
14802
Matthew Wilcox01fbfe02007-09-09 08:56:40 -060014803 if (!request_region(iop_base, ASC_IOADR_GAP, DRV_NAME)) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060014804 ASC_DBG1(1, "advansys_vlb_match: I/O port 0x%x busy\n",
14805 iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060014806 return -ENODEV;
14807 }
14808 ASC_DBG1(1, "advansys_vlb_match: probing I/O port 0x%x\n", iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060014809 if (!AscFindSignature(iop_base))
14810 goto nodev;
14811 /*
14812 * I don't think this condition can actually happen, but the old
14813 * driver did it, and the chances of finding a VLB setup in 2007
14814 * to do testing with is slight to none.
14815 */
14816 if (AscGetChipVersion(iop_base, ASC_IS_VL) > ASC_CHIP_MAX_VER_VL)
14817 goto nodev;
14818
14819 shost = advansys_board_found(iop_base, dev, ASC_IS_VL);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060014820 if (!shost)
14821 goto nodev;
14822
14823 dev_set_drvdata(dev, shost);
14824 return 0;
14825
14826 nodev:
Matthew Wilcox71f36112007-07-30 08:04:53 -060014827 release_region(iop_base, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060014828 return -ENODEV;
14829}
14830
14831static struct isa_driver advansys_vlb_driver = {
14832 .probe = advansys_vlb_probe,
14833 .remove = __devexit_p(advansys_isa_remove),
14834 .driver = {
14835 .owner = THIS_MODULE,
Matthew Wilcoxb8e5152b2007-09-09 08:56:26 -060014836 .name = "advansys_vlb",
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060014837 },
14838};
14839
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060014840static struct eisa_device_id advansys_eisa_table[] __devinitdata = {
14841 { "ABP7401" },
14842 { "ABP7501" },
14843 { "" }
14844};
14845
14846MODULE_DEVICE_TABLE(eisa, advansys_eisa_table);
14847
14848/*
14849 * EISA is a little more tricky than PCI; each EISA device may have two
14850 * channels, and this driver is written to make each channel its own Scsi_Host
14851 */
14852struct eisa_scsi_data {
14853 struct Scsi_Host *host[2];
14854};
14855
14856static int __devinit advansys_eisa_probe(struct device *dev)
14857{
14858 int i, ioport;
14859 int err;
14860 struct eisa_device *edev = to_eisa_device(dev);
14861 struct eisa_scsi_data *data;
14862
14863 err = -ENOMEM;
14864 data = kzalloc(sizeof(*data), GFP_KERNEL);
14865 if (!data)
14866 goto fail;
14867 ioport = edev->base_addr + 0xc30;
14868
14869 err = -ENODEV;
14870 for (i = 0; i < 2; i++, ioport += 0x20) {
Matthew Wilcox01fbfe02007-09-09 08:56:40 -060014871 if (!request_region(ioport, ASC_IOADR_GAP, DRV_NAME)) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060014872 printk(KERN_WARNING "Region %x-%x busy\n", ioport,
14873 ioport + ASC_IOADR_GAP - 1);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060014874 continue;
Matthew Wilcox71f36112007-07-30 08:04:53 -060014875 }
14876 if (!AscFindSignature(ioport)) {
14877 release_region(ioport, ASC_IOADR_GAP);
14878 continue;
14879 }
14880
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060014881 /*
14882 * I don't know why we need to do this for EISA chips, but
14883 * not for any others. It looks to be equivalent to
14884 * AscGetChipCfgMsw, but I may have overlooked something,
14885 * so I'm not converting it until I get an EISA board to
14886 * test with.
14887 */
14888 inw(ioport + 4);
14889 data->host[i] = advansys_board_found(ioport, dev, ASC_IS_EISA);
Matthew Wilcox71f36112007-07-30 08:04:53 -060014890 if (data->host[i]) {
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060014891 err = 0;
Matthew Wilcox71f36112007-07-30 08:04:53 -060014892 } else {
14893 release_region(ioport, ASC_IOADR_GAP);
14894 }
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060014895 }
14896
14897 if (err) {
14898 kfree(data);
14899 } else {
14900 dev_set_drvdata(dev, data);
14901 }
14902
14903 fail:
14904 return err;
14905}
14906
14907static __devexit int advansys_eisa_remove(struct device *dev)
14908{
14909 int i;
14910 struct eisa_scsi_data *data = dev_get_drvdata(dev);
14911
14912 for (i = 0; i < 2; i++) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060014913 int ioport;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060014914 struct Scsi_Host *shost = data->host[i];
14915 if (!shost)
14916 continue;
Matthew Wilcox71f36112007-07-30 08:04:53 -060014917 ioport = shost->io_port;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060014918 advansys_release(shost);
Matthew Wilcox71f36112007-07-30 08:04:53 -060014919 release_region(ioport, ASC_IOADR_GAP);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060014920 }
14921
14922 kfree(data);
14923 return 0;
14924}
14925
14926static struct eisa_driver advansys_eisa_driver = {
14927 .id_table = advansys_eisa_table,
14928 .driver = {
Matthew Wilcox01fbfe02007-09-09 08:56:40 -060014929 .name = DRV_NAME,
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060014930 .probe = advansys_eisa_probe,
14931 .remove = __devexit_p(advansys_eisa_remove),
14932 }
14933};
14934
Dave Jones2672ea82006-08-02 17:11:49 -040014935/* PCI Devices supported by this driver */
14936static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014937 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A,
14938 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
14939 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940,
14940 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
14941 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940U,
14942 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
14943 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940UW,
14944 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
14945 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C0800_REV1,
14946 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
14947 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C1600_REV1,
14948 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
14949 {}
Dave Jones2672ea82006-08-02 17:11:49 -040014950};
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014951
Dave Jones2672ea82006-08-02 17:11:49 -040014952MODULE_DEVICE_TABLE(pci, advansys_pci_tbl);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060014953
Matthew Wilcox9649af32007-07-26 21:51:47 -060014954static void __devinit advansys_set_latency(struct pci_dev *pdev)
14955{
14956 if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) ||
14957 (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) {
14958 pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0);
14959 } else {
14960 u8 latency;
14961 pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency);
14962 if (latency < 0x20)
14963 pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x20);
14964 }
14965}
14966
Matthew Wilcox78e77d82007-07-29 21:46:15 -060014967static int __devinit
14968advansys_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
14969{
14970 int err, ioport;
14971 struct Scsi_Host *shost;
14972
14973 err = pci_enable_device(pdev);
14974 if (err)
14975 goto fail;
Matthew Wilcox01fbfe02007-09-09 08:56:40 -060014976 err = pci_request_regions(pdev, DRV_NAME);
Matthew Wilcox71f36112007-07-30 08:04:53 -060014977 if (err)
14978 goto disable_device;
Matthew Wilcox9649af32007-07-26 21:51:47 -060014979 pci_set_master(pdev);
14980 advansys_set_latency(pdev);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060014981
14982 if (pci_resource_len(pdev, 0) == 0)
14983 goto nodev;
14984
14985 ioport = pci_resource_start(pdev, 0);
14986 shost = advansys_board_found(ioport, &pdev->dev, ASC_IS_PCI);
14987
14988 if (!shost)
14989 goto nodev;
14990
14991 pci_set_drvdata(pdev, shost);
14992 return 0;
14993
14994 nodev:
14995 err = -ENODEV;
Matthew Wilcox71f36112007-07-30 08:04:53 -060014996 pci_release_regions(pdev);
14997 disable_device:
Matthew Wilcox78e77d82007-07-29 21:46:15 -060014998 pci_disable_device(pdev);
14999 fail:
15000 return err;
15001}
15002
15003static void __devexit advansys_pci_remove(struct pci_dev *pdev)
15004{
15005 advansys_release(pci_get_drvdata(pdev));
Matthew Wilcox71f36112007-07-30 08:04:53 -060015006 pci_release_regions(pdev);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015007 pci_disable_device(pdev);
15008}
15009
15010static struct pci_driver advansys_pci_driver = {
Matthew Wilcox01fbfe02007-09-09 08:56:40 -060015011 .name = DRV_NAME,
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015012 .id_table = advansys_pci_tbl,
15013 .probe = advansys_pci_probe,
15014 .remove = __devexit_p(advansys_pci_remove),
15015};
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040015016
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060015017static int __init advansys_init(void)
15018{
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015019 int error;
15020
15021 error = isa_register_driver(&advansys_isa_driver,
15022 ASC_IOADR_TABLE_MAX_IX);
15023 if (error)
15024 goto fail;
15025
15026 error = isa_register_driver(&advansys_vlb_driver,
15027 ASC_IOADR_TABLE_MAX_IX);
15028 if (error)
15029 goto unregister_isa;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060015030
15031 error = eisa_driver_register(&advansys_eisa_driver);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015032 if (error)
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015033 goto unregister_vlb;
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060015034
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060015035 error = pci_register_driver(&advansys_pci_driver);
15036 if (error)
15037 goto unregister_eisa;
15038
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060015039 return 0;
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015040
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060015041 unregister_eisa:
15042 eisa_driver_unregister(&advansys_eisa_driver);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015043 unregister_vlb:
15044 isa_unregister_driver(&advansys_vlb_driver);
15045 unregister_isa:
15046 isa_unregister_driver(&advansys_isa_driver);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015047 fail:
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015048 return error;
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060015049}
15050
15051static void __exit advansys_exit(void)
15052{
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015053 pci_unregister_driver(&advansys_pci_driver);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060015054 eisa_driver_unregister(&advansys_eisa_driver);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015055 isa_unregister_driver(&advansys_vlb_driver);
15056 isa_unregister_driver(&advansys_isa_driver);
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060015057}
15058
15059module_init(advansys_init);
15060module_exit(advansys_exit);
15061
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040015062MODULE_LICENSE("GPL");