blob: e5b26a1ea0ec16a975af83958e9bb3bf4aacba84 [file] [log] [blame]
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -04001#define ASC_VERSION "3.4" /* AdvanSys Driver Version */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002
3/*
4 * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
5 *
6 * Copyright (c) 1995-2000 Advanced System Products, Inc.
7 * Copyright (c) 2000-2001 ConnectCom Solutions, Inc.
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -04008 * Copyright (c) 2007 Matthew Wilcox <matthew@wil.cx>
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * All Rights Reserved.
10 *
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040011 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 */
16
17/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070018 * As of March 8, 2000 Advanced System Products, Inc. (AdvanSys)
19 * changed its name to ConnectCom Solutions, Inc.
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040020 * On June 18, 2001 Initio Corp. acquired ConnectCom's SCSI assets
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 */
22
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <linux/string.h>
25#include <linux/kernel.h>
26#include <linux/types.h>
27#include <linux/ioport.h>
28#include <linux/interrupt.h>
29#include <linux/delay.h>
30#include <linux/slab.h>
31#include <linux/mm.h>
32#include <linux/proc_fs.h>
33#include <linux/init.h>
34#include <linux/blkdev.h>
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060035#include <linux/isa.h>
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060036#include <linux/eisa.h>
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040037#include <linux/pci.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <linux/spinlock.h>
39#include <linux/dma-mapping.h>
40
41#include <asm/io.h>
42#include <asm/system.h>
43#include <asm/dma.h>
44
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040045#include <scsi/scsi_cmnd.h>
46#include <scsi/scsi_device.h>
47#include <scsi/scsi_tcq.h>
48#include <scsi/scsi.h>
49#include <scsi/scsi_host.h>
50
Matthew Wilcox4bd6d7f2007-07-30 08:41:03 -060051/* FIXME:
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 *
Matthew Wilcox4bd6d7f2007-07-30 08:41:03 -060053 * 1. Although all of the necessary command mapping places have the
54 * appropriate dma_map.. APIs, the driver still processes its internal
55 * queue using bus_to_virt() and virt_to_bus() which are illegal under
56 * the API. The entire queue processing structure will need to be
57 * altered to fix this.
58 * 2. Need to add memory mapping workaround. Test the memory mapping.
59 * If it doesn't work revert to I/O port access. Can a test be done
60 * safely?
61 * 3. Handle an interrupt not working. Keep an interrupt counter in
62 * the interrupt handler. In the timeout function if the interrupt
63 * has not occurred then print a message and run in polled mode.
64 * 4. Need to add support for target mode commands, cf. CAM XPT.
65 * 5. check DMA mapping functions for failure
Matthew Wilcox349d2c42007-09-09 08:56:34 -060066 * 6. Use scsi_transport_spi
67 * 7. advansys_info is not safe against multiple simultaneous callers
68 * 8. Kill boardp->id
69 * 9. Add module_param to override ISA/VLB ioport array
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 */
71#warning this driver is still not properly converted to the DMA API
72
Linus Torvalds1da177e2005-04-16 15:20:36 -070073/* Enable driver /proc statistics. */
74#define ADVANSYS_STATS
75
76/* Enable driver tracing. */
77/* #define ADVANSYS_DEBUG */
78
Linus Torvalds1da177e2005-04-16 15:20:36 -070079#define ASC_LIB_VERSION_MAJOR 1
80#define ASC_LIB_VERSION_MINOR 24
81#define ASC_LIB_SERIAL_NUMBER 123
82
83/*
84 * Portable Data Types
85 *
86 * Any instance where a 32-bit long or pointer type is assumed
87 * for precision or HW defined structures, the following define
88 * types must be used. In Linux the char, short, and int types
89 * are all consistent at 8, 16, and 32 bits respectively. Pointers
90 * and long types are 64 bits on Alpha and UltraSPARC.
91 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040092#define ASC_PADDR __u32 /* Physical/Bus address data type. */
93#define ASC_VADDR __u32 /* Virtual address data type. */
94#define ASC_DCNT __u32 /* Unsigned Data count type. */
95#define ASC_SDCNT __s32 /* Signed Data count type. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
97/*
98 * These macros are used to convert a virtual address to a
99 * 32-bit value. This currently can be used on Linux Alpha
100 * which uses 64-bit virtual address but a 32-bit bus address.
101 * This is likely to break in the future, but doing this now
102 * will give us time to change the HW and FW to handle 64-bit
103 * addresses.
104 */
105#define ASC_VADDR_TO_U32 virt_to_bus
106#define ASC_U32_TO_VADDR bus_to_virt
107
108typedef unsigned char uchar;
109
110#ifndef TRUE
111#define TRUE (1)
112#endif
113#ifndef FALSE
114#define FALSE (0)
115#endif
116
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117#define ERR (-1)
118#define UW_ERR (uint)(0xFFFF)
119#define isodd_word(val) ((((uint)val) & (uint)0x0001) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120
Dave Jones2672ea82006-08-02 17:11:49 -0400121#define PCI_VENDOR_ID_ASP 0x10cd
122#define PCI_DEVICE_ID_ASP_1200A 0x1100
123#define PCI_DEVICE_ID_ASP_ABP940 0x1200
124#define PCI_DEVICE_ID_ASP_ABP940U 0x1300
125#define PCI_DEVICE_ID_ASP_ABP940UW 0x2300
126#define PCI_DEVICE_ID_38C0800_REV1 0x2500
127#define PCI_DEVICE_ID_38C1600_REV1 0x2700
128
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129/*
130 * Enable CC_VERY_LONG_SG_LIST to support up to 64K element SG lists.
131 * The SRB structure will have to be changed and the ASC_SRB2SCSIQ()
132 * macro re-defined to be able to obtain a ASC_SCSI_Q pointer from the
133 * SRB structure.
134 */
135#define CC_VERY_LONG_SG_LIST 0
136#define ASC_SRB2SCSIQ(srb_ptr) (srb_ptr)
137
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400138#define PortAddr unsigned short /* port address size */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139#define inp(port) inb(port)
140#define outp(port, byte) outb((byte), (port))
141
142#define inpw(port) inw(port)
143#define outpw(port, word) outw((word), (port))
144
145#define ASC_MAX_SG_QUEUE 7
146#define ASC_MAX_SG_LIST 255
147
148#define ASC_CS_TYPE unsigned short
149
150#define ASC_IS_ISA (0x0001)
151#define ASC_IS_ISAPNP (0x0081)
152#define ASC_IS_EISA (0x0002)
153#define ASC_IS_PCI (0x0004)
154#define ASC_IS_PCI_ULTRA (0x0104)
155#define ASC_IS_PCMCIA (0x0008)
156#define ASC_IS_MCA (0x0020)
157#define ASC_IS_VL (0x0040)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158#define ASC_IS_WIDESCSI_16 (0x0100)
159#define ASC_IS_WIDESCSI_32 (0x0200)
160#define ASC_IS_BIG_ENDIAN (0x8000)
Matthew Wilcox95c9f162007-09-09 08:56:39 -0600161
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162#define ASC_CHIP_MIN_VER_VL (0x01)
163#define ASC_CHIP_MAX_VER_VL (0x07)
164#define ASC_CHIP_MIN_VER_PCI (0x09)
165#define ASC_CHIP_MAX_VER_PCI (0x0F)
166#define ASC_CHIP_VER_PCI_BIT (0x08)
167#define ASC_CHIP_MIN_VER_ISA (0x11)
168#define ASC_CHIP_MIN_VER_ISA_PNP (0x21)
169#define ASC_CHIP_MAX_VER_ISA (0x27)
170#define ASC_CHIP_VER_ISA_BIT (0x30)
171#define ASC_CHIP_VER_ISAPNP_BIT (0x20)
172#define ASC_CHIP_VER_ASYN_BUG (0x21)
173#define ASC_CHIP_VER_PCI 0x08
174#define ASC_CHIP_VER_PCI_ULTRA_3150 (ASC_CHIP_VER_PCI | 0x02)
175#define ASC_CHIP_VER_PCI_ULTRA_3050 (ASC_CHIP_VER_PCI | 0x03)
176#define ASC_CHIP_MIN_VER_EISA (0x41)
177#define ASC_CHIP_MAX_VER_EISA (0x47)
178#define ASC_CHIP_VER_EISA_BIT (0x40)
179#define ASC_CHIP_LATEST_VER_EISA ((ASC_CHIP_MIN_VER_EISA - 1) + 3)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180#define ASC_MAX_VL_DMA_COUNT (0x07FFFFFFL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181#define ASC_MAX_PCI_DMA_COUNT (0xFFFFFFFFL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182#define ASC_MAX_ISA_DMA_COUNT (0x00FFFFFFL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183
184#define ASC_SCSI_ID_BITS 3
185#define ASC_SCSI_TIX_TYPE uchar
186#define ASC_ALL_DEVICE_BIT_SET 0xFF
187#define ASC_SCSI_BIT_ID_TYPE uchar
188#define ASC_MAX_TID 7
189#define ASC_MAX_LUN 7
190#define ASC_SCSI_WIDTH_BIT_SET 0xFF
191#define ASC_MAX_SENSE_LEN 32
192#define ASC_MIN_SENSE_LEN 14
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193#define ASC_SCSI_RESET_HOLD_TIME_US 60
194
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195/*
Matthew Wilcoxf05ec592007-09-09 08:56:36 -0600196 * Narrow boards only support 12-byte commands, while wide boards
197 * extend to 16-byte commands.
198 */
199#define ASC_MAX_CDB_LEN 12
200#define ADV_MAX_CDB_LEN 16
201
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202#define MS_SDTR_LEN 0x03
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203#define MS_WDTR_LEN 0x02
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204
205#define ASC_SG_LIST_PER_Q 7
206#define QS_FREE 0x00
207#define QS_READY 0x01
208#define QS_DISC1 0x02
209#define QS_DISC2 0x04
210#define QS_BUSY 0x08
211#define QS_ABORTED 0x40
212#define QS_DONE 0x80
213#define QC_NO_CALLBACK 0x01
214#define QC_SG_SWAP_QUEUE 0x02
215#define QC_SG_HEAD 0x04
216#define QC_DATA_IN 0x08
217#define QC_DATA_OUT 0x10
218#define QC_URGENT 0x20
219#define QC_MSG_OUT 0x40
220#define QC_REQ_SENSE 0x80
221#define QCSG_SG_XFER_LIST 0x02
222#define QCSG_SG_XFER_MORE 0x04
223#define QCSG_SG_XFER_END 0x08
224#define QD_IN_PROGRESS 0x00
225#define QD_NO_ERROR 0x01
226#define QD_ABORTED_BY_HOST 0x02
227#define QD_WITH_ERROR 0x04
228#define QD_INVALID_REQUEST 0x80
229#define QD_INVALID_HOST_NUM 0x81
230#define QD_INVALID_DEVICE 0x82
231#define QD_ERR_INTERNAL 0xFF
232#define QHSTA_NO_ERROR 0x00
233#define QHSTA_M_SEL_TIMEOUT 0x11
234#define QHSTA_M_DATA_OVER_RUN 0x12
235#define QHSTA_M_DATA_UNDER_RUN 0x12
236#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
237#define QHSTA_M_BAD_BUS_PHASE_SEQ 0x14
238#define QHSTA_D_QDONE_SG_LIST_CORRUPTED 0x21
239#define QHSTA_D_ASC_DVC_ERROR_CODE_SET 0x22
240#define QHSTA_D_HOST_ABORT_FAILED 0x23
241#define QHSTA_D_EXE_SCSI_Q_FAILED 0x24
242#define QHSTA_D_EXE_SCSI_Q_BUSY_TIMEOUT 0x25
243#define QHSTA_D_ASPI_NO_BUF_POOL 0x26
244#define QHSTA_M_WTM_TIMEOUT 0x41
245#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42
246#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43
247#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
248#define QHSTA_M_TARGET_STATUS_BUSY 0x45
249#define QHSTA_M_BAD_TAG_CODE 0x46
250#define QHSTA_M_BAD_QUEUE_FULL_OR_BUSY 0x47
251#define QHSTA_M_HUNG_REQ_SCSI_BUS_RESET 0x48
252#define QHSTA_D_LRAM_CMP_ERROR 0x81
253#define QHSTA_M_MICRO_CODE_ERROR_HALT 0xA1
254#define ASC_FLAG_SCSIQ_REQ 0x01
255#define ASC_FLAG_BIOS_SCSIQ_REQ 0x02
256#define ASC_FLAG_BIOS_ASYNC_IO 0x04
257#define ASC_FLAG_SRB_LINEAR_ADDR 0x08
258#define ASC_FLAG_WIN16 0x10
259#define ASC_FLAG_WIN32 0x20
260#define ASC_FLAG_ISA_OVER_16MB 0x40
261#define ASC_FLAG_DOS_VM_CALLBACK 0x80
262#define ASC_TAG_FLAG_EXTRA_BYTES 0x10
263#define ASC_TAG_FLAG_DISABLE_DISCONNECT 0x04
264#define ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX 0x08
265#define ASC_TAG_FLAG_DISABLE_CHK_COND_INT_HOST 0x40
266#define ASC_SCSIQ_CPY_BEG 4
267#define ASC_SCSIQ_SGHD_CPY_BEG 2
268#define ASC_SCSIQ_B_FWD 0
269#define ASC_SCSIQ_B_BWD 1
270#define ASC_SCSIQ_B_STATUS 2
271#define ASC_SCSIQ_B_QNO 3
272#define ASC_SCSIQ_B_CNTL 4
273#define ASC_SCSIQ_B_SG_QUEUE_CNT 5
274#define ASC_SCSIQ_D_DATA_ADDR 8
275#define ASC_SCSIQ_D_DATA_CNT 12
276#define ASC_SCSIQ_B_SENSE_LEN 20
277#define ASC_SCSIQ_DONE_INFO_BEG 22
278#define ASC_SCSIQ_D_SRBPTR 22
279#define ASC_SCSIQ_B_TARGET_IX 26
280#define ASC_SCSIQ_B_CDB_LEN 28
281#define ASC_SCSIQ_B_TAG_CODE 29
282#define ASC_SCSIQ_W_VM_ID 30
283#define ASC_SCSIQ_DONE_STATUS 32
284#define ASC_SCSIQ_HOST_STATUS 33
285#define ASC_SCSIQ_SCSI_STATUS 34
286#define ASC_SCSIQ_CDB_BEG 36
287#define ASC_SCSIQ_DW_REMAIN_XFER_ADDR 56
288#define ASC_SCSIQ_DW_REMAIN_XFER_CNT 60
289#define ASC_SCSIQ_B_FIRST_SG_WK_QP 48
290#define ASC_SCSIQ_B_SG_WK_QP 49
291#define ASC_SCSIQ_B_SG_WK_IX 50
292#define ASC_SCSIQ_W_ALT_DC1 52
293#define ASC_SCSIQ_B_LIST_CNT 6
294#define ASC_SCSIQ_B_CUR_LIST_CNT 7
295#define ASC_SGQ_B_SG_CNTL 4
296#define ASC_SGQ_B_SG_HEAD_QP 5
297#define ASC_SGQ_B_SG_LIST_CNT 6
298#define ASC_SGQ_B_SG_CUR_LIST_CNT 7
299#define ASC_SGQ_LIST_BEG 8
300#define ASC_DEF_SCSI1_QNG 4
301#define ASC_MAX_SCSI1_QNG 4
302#define ASC_DEF_SCSI2_QNG 16
303#define ASC_MAX_SCSI2_QNG 32
304#define ASC_TAG_CODE_MASK 0x23
305#define ASC_STOP_REQ_RISC_STOP 0x01
306#define ASC_STOP_ACK_RISC_STOP 0x03
307#define ASC_STOP_CLEAN_UP_BUSY_Q 0x10
308#define ASC_STOP_CLEAN_UP_DISC_Q 0x20
309#define ASC_STOP_HOST_REQ_RISC_HALT 0x40
310#define ASC_TIDLUN_TO_IX(tid, lun) (ASC_SCSI_TIX_TYPE)((tid) + ((lun)<<ASC_SCSI_ID_BITS))
311#define ASC_TID_TO_TARGET_ID(tid) (ASC_SCSI_BIT_ID_TYPE)(0x01 << (tid))
312#define ASC_TIX_TO_TARGET_ID(tix) (0x01 << ((tix) & ASC_MAX_TID))
313#define ASC_TIX_TO_TID(tix) ((tix) & ASC_MAX_TID)
314#define ASC_TID_TO_TIX(tid) ((tid) & ASC_MAX_TID)
315#define ASC_TIX_TO_LUN(tix) (((tix) >> ASC_SCSI_ID_BITS) & ASC_MAX_LUN)
316#define ASC_QNO_TO_QADDR(q_no) ((ASC_QADR_BEG)+((int)(q_no) << 6))
317
318typedef struct asc_scsiq_1 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400319 uchar status;
320 uchar q_no;
321 uchar cntl;
322 uchar sg_queue_cnt;
323 uchar target_id;
324 uchar target_lun;
325 ASC_PADDR data_addr;
326 ASC_DCNT data_cnt;
327 ASC_PADDR sense_addr;
328 uchar sense_len;
329 uchar extra_bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330} ASC_SCSIQ_1;
331
332typedef struct asc_scsiq_2 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400333 ASC_VADDR srb_ptr;
334 uchar target_ix;
335 uchar flag;
336 uchar cdb_len;
337 uchar tag_code;
338 ushort vm_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339} ASC_SCSIQ_2;
340
341typedef struct asc_scsiq_3 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400342 uchar done_stat;
343 uchar host_stat;
344 uchar scsi_stat;
345 uchar scsi_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346} ASC_SCSIQ_3;
347
348typedef struct asc_scsiq_4 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400349 uchar cdb[ASC_MAX_CDB_LEN];
350 uchar y_first_sg_list_qp;
351 uchar y_working_sg_qp;
352 uchar y_working_sg_ix;
353 uchar y_res;
354 ushort x_req_count;
355 ushort x_reconnect_rtn;
356 ASC_PADDR x_saved_data_addr;
357 ASC_DCNT x_saved_data_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358} ASC_SCSIQ_4;
359
360typedef struct asc_q_done_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400361 ASC_SCSIQ_2 d2;
362 ASC_SCSIQ_3 d3;
363 uchar q_status;
364 uchar q_no;
365 uchar cntl;
366 uchar sense_len;
367 uchar extra_bytes;
368 uchar res;
369 ASC_DCNT remain_bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370} ASC_QDONE_INFO;
371
372typedef struct asc_sg_list {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400373 ASC_PADDR addr;
374 ASC_DCNT bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375} ASC_SG_LIST;
376
377typedef struct asc_sg_head {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400378 ushort entry_cnt;
379 ushort queue_cnt;
380 ushort entry_to_copy;
381 ushort res;
382 ASC_SG_LIST sg_list[ASC_MAX_SG_LIST];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383} ASC_SG_HEAD;
384
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385typedef struct asc_scsi_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400386 ASC_SCSIQ_1 q1;
387 ASC_SCSIQ_2 q2;
388 uchar *cdbptr;
389 ASC_SG_HEAD *sg_head;
390 ushort remain_sg_entry_cnt;
391 ushort next_sg_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392} ASC_SCSI_Q;
393
394typedef struct asc_scsi_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400395 ASC_SCSIQ_1 r1;
396 ASC_SCSIQ_2 r2;
397 uchar *cdbptr;
398 ASC_SG_HEAD *sg_head;
399 uchar *sense_ptr;
400 ASC_SCSIQ_3 r3;
401 uchar cdb[ASC_MAX_CDB_LEN];
402 uchar sense[ASC_MIN_SENSE_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403} ASC_SCSI_REQ_Q;
404
405typedef struct asc_scsi_bios_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400406 ASC_SCSIQ_1 r1;
407 ASC_SCSIQ_2 r2;
408 uchar *cdbptr;
409 ASC_SG_HEAD *sg_head;
410 uchar *sense_ptr;
411 ASC_SCSIQ_3 r3;
412 uchar cdb[ASC_MAX_CDB_LEN];
413 uchar sense[ASC_MIN_SENSE_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414} ASC_SCSI_BIOS_REQ_Q;
415
416typedef struct asc_risc_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400417 uchar fwd;
418 uchar bwd;
419 ASC_SCSIQ_1 i1;
420 ASC_SCSIQ_2 i2;
421 ASC_SCSIQ_3 i3;
422 ASC_SCSIQ_4 i4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423} ASC_RISC_Q;
424
425typedef struct asc_sg_list_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400426 uchar seq_no;
427 uchar q_no;
428 uchar cntl;
429 uchar sg_head_qp;
430 uchar sg_list_cnt;
431 uchar sg_cur_list_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432} ASC_SG_LIST_Q;
433
434typedef struct asc_risc_sg_list_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400435 uchar fwd;
436 uchar bwd;
437 ASC_SG_LIST_Q sg;
438 ASC_SG_LIST sg_list[7];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439} ASC_RISC_SG_LIST_Q;
440
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441#define ASCQ_ERR_Q_STATUS 0x0D
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442#define ASCQ_ERR_CUR_QNG 0x17
443#define ASCQ_ERR_SG_Q_LINKS 0x18
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444#define ASCQ_ERR_ISR_RE_ENTRY 0x1A
445#define ASCQ_ERR_CRITICAL_RE_ENTRY 0x1B
446#define ASCQ_ERR_ISR_ON_CRITICAL 0x1C
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447
448/*
449 * Warning code values are set in ASC_DVC_VAR 'warn_code'.
450 */
451#define ASC_WARN_NO_ERROR 0x0000
452#define ASC_WARN_IO_PORT_ROTATE 0x0001
453#define ASC_WARN_EEPROM_CHKSUM 0x0002
454#define ASC_WARN_IRQ_MODIFIED 0x0004
455#define ASC_WARN_AUTO_CONFIG 0x0008
456#define ASC_WARN_CMD_QNG_CONFLICT 0x0010
457#define ASC_WARN_EEPROM_RECOVER 0x0020
458#define ASC_WARN_CFG_MSW_RECOVER 0x0040
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459
460/*
461 * Error code values are set in ASC_DVC_VAR 'err_code'.
462 */
463#define ASC_IERR_WRITE_EEPROM 0x0001
464#define ASC_IERR_MCODE_CHKSUM 0x0002
465#define ASC_IERR_SET_PC_ADDR 0x0004
466#define ASC_IERR_START_STOP_CHIP 0x0008
467#define ASC_IERR_IRQ_NO 0x0010
468#define ASC_IERR_SET_IRQ_NO 0x0020
469#define ASC_IERR_CHIP_VERSION 0x0040
470#define ASC_IERR_SET_SCSI_ID 0x0080
471#define ASC_IERR_GET_PHY_ADDR 0x0100
472#define ASC_IERR_BAD_SIGNATURE 0x0200
473#define ASC_IERR_NO_BUS_TYPE 0x0400
474#define ASC_IERR_SCAM 0x0800
475#define ASC_IERR_SET_SDTR 0x1000
476#define ASC_IERR_RW_LRAM 0x8000
477
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478#define ASC_MAX_IRQ_NO 15
479#define ASC_MIN_IRQ_NO 10
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480#define ASC_DEF_MAX_TOTAL_QNG (0xF0)
481#define ASC_MIN_TAG_Q_PER_DVC (0x04)
Matthew Wilcox95c9f162007-09-09 08:56:39 -0600482#define ASC_MIN_FREE_Q (0x02)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483#define ASC_MIN_TOTAL_QNG ((ASC_MAX_SG_QUEUE)+(ASC_MIN_FREE_Q))
484#define ASC_MAX_TOTAL_QNG 240
485#define ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG 16
486#define ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG 8
487#define ASC_MAX_PCI_INRAM_TOTAL_QNG 20
488#define ASC_MAX_INRAM_TAG_QNG 16
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489#define ASC_IOADR_GAP 0x10
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490#define ASC_MAX_SYN_XFER_NO 16
491#define ASC_SYN_MAX_OFFSET 0x0F
492#define ASC_DEF_SDTR_OFFSET 0x0F
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493#define ASC_SDTR_ULTRA_PCI_10MB_INDEX 0x02
494#define SYN_XFER_NS_0 25
495#define SYN_XFER_NS_1 30
496#define SYN_XFER_NS_2 35
497#define SYN_XFER_NS_3 40
498#define SYN_XFER_NS_4 50
499#define SYN_XFER_NS_5 60
500#define SYN_XFER_NS_6 70
501#define SYN_XFER_NS_7 85
502#define SYN_ULTRA_XFER_NS_0 12
503#define SYN_ULTRA_XFER_NS_1 19
504#define SYN_ULTRA_XFER_NS_2 25
505#define SYN_ULTRA_XFER_NS_3 32
506#define SYN_ULTRA_XFER_NS_4 38
507#define SYN_ULTRA_XFER_NS_5 44
508#define SYN_ULTRA_XFER_NS_6 50
509#define SYN_ULTRA_XFER_NS_7 57
510#define SYN_ULTRA_XFER_NS_8 63
511#define SYN_ULTRA_XFER_NS_9 69
512#define SYN_ULTRA_XFER_NS_10 75
513#define SYN_ULTRA_XFER_NS_11 82
514#define SYN_ULTRA_XFER_NS_12 88
515#define SYN_ULTRA_XFER_NS_13 94
516#define SYN_ULTRA_XFER_NS_14 100
517#define SYN_ULTRA_XFER_NS_15 107
518
519typedef struct ext_msg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400520 uchar msg_type;
521 uchar msg_len;
522 uchar msg_req;
523 union {
524 struct {
525 uchar sdtr_xfer_period;
526 uchar sdtr_req_ack_offset;
527 } sdtr;
528 struct {
529 uchar wdtr_width;
530 } wdtr;
531 struct {
532 uchar mdp_b3;
533 uchar mdp_b2;
534 uchar mdp_b1;
535 uchar mdp_b0;
536 } mdp;
537 } u_ext_msg;
538 uchar res;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539} EXT_MSG;
540
541#define xfer_period u_ext_msg.sdtr.sdtr_xfer_period
542#define req_ack_offset u_ext_msg.sdtr.sdtr_req_ack_offset
543#define wdtr_width u_ext_msg.wdtr.wdtr_width
544#define mdp_b3 u_ext_msg.mdp_b3
545#define mdp_b2 u_ext_msg.mdp_b2
546#define mdp_b1 u_ext_msg.mdp_b1
547#define mdp_b0 u_ext_msg.mdp_b0
548
549typedef struct asc_dvc_cfg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400550 ASC_SCSI_BIT_ID_TYPE can_tagged_qng;
551 ASC_SCSI_BIT_ID_TYPE cmd_qng_enabled;
552 ASC_SCSI_BIT_ID_TYPE disc_enable;
553 ASC_SCSI_BIT_ID_TYPE sdtr_enable;
554 uchar chip_scsi_id;
555 uchar isa_dma_speed;
556 uchar isa_dma_channel;
557 uchar chip_version;
558 ushort lib_serial_no;
559 ushort lib_version;
560 ushort mcode_date;
561 ushort mcode_version;
562 uchar max_tag_qng[ASC_MAX_TID + 1];
563 uchar *overrun_buf;
564 uchar sdtr_period_offset[ASC_MAX_TID + 1];
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400565 uchar adapter_info[6];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566} ASC_DVC_CFG;
567
568#define ASC_DEF_DVC_CNTL 0xFFFF
569#define ASC_DEF_CHIP_SCSI_ID 7
570#define ASC_DEF_ISA_DMA_SPEED 4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571#define ASC_INIT_STATE_BEG_GET_CFG 0x0001
572#define ASC_INIT_STATE_END_GET_CFG 0x0002
573#define ASC_INIT_STATE_BEG_SET_CFG 0x0004
574#define ASC_INIT_STATE_END_SET_CFG 0x0008
575#define ASC_INIT_STATE_BEG_LOAD_MC 0x0010
576#define ASC_INIT_STATE_END_LOAD_MC 0x0020
577#define ASC_INIT_STATE_BEG_INQUIRY 0x0040
578#define ASC_INIT_STATE_END_INQUIRY 0x0080
579#define ASC_INIT_RESET_SCSI_DONE 0x0100
580#define ASC_INIT_STATE_WITHOUT_EEP 0x8000
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581#define ASC_BUG_FIX_IF_NOT_DWB 0x0001
582#define ASC_BUG_FIX_ASYN_USE_SYN 0x0002
583#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41
584#define ASC_MIN_TAGGED_CMD 7
585#define ASC_MAX_SCSI_RESET_WAIT 30
586
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400587struct asc_dvc_var; /* Forward Declaration. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589typedef struct asc_dvc_var {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400590 PortAddr iop_base;
591 ushort err_code;
592 ushort dvc_cntl;
593 ushort bug_fix_cntl;
594 ushort bus_type;
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400595 ASC_SCSI_BIT_ID_TYPE init_sdtr;
596 ASC_SCSI_BIT_ID_TYPE sdtr_done;
597 ASC_SCSI_BIT_ID_TYPE use_tagged_qng;
598 ASC_SCSI_BIT_ID_TYPE unit_not_ready;
599 ASC_SCSI_BIT_ID_TYPE queue_full_or_busy;
600 ASC_SCSI_BIT_ID_TYPE start_motor;
601 uchar scsi_reset_wait;
602 uchar chip_no;
603 char is_in_int;
604 uchar max_total_qng;
605 uchar cur_total_qng;
606 uchar in_critical_cnt;
607 uchar irq_no;
608 uchar last_q_shortage;
609 ushort init_state;
610 uchar cur_dvc_qng[ASC_MAX_TID + 1];
611 uchar max_dvc_qng[ASC_MAX_TID + 1];
612 ASC_SCSI_Q *scsiq_busy_head[ASC_MAX_TID + 1];
613 ASC_SCSI_Q *scsiq_busy_tail[ASC_MAX_TID + 1];
614 uchar sdtr_period_tbl[ASC_MAX_SYN_XFER_NO];
615 ASC_DVC_CFG *cfg;
616 ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer_always;
617 char redo_scam;
618 ushort res2;
619 uchar dos_int13_table[ASC_MAX_TID + 1];
620 ASC_DCNT max_dma_count;
621 ASC_SCSI_BIT_ID_TYPE no_scam;
622 ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer;
623 uchar max_sdtr_index;
624 uchar host_init_sdtr_index;
625 struct asc_board *drv_ptr;
626 ASC_DCNT uc_break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627} ASC_DVC_VAR;
628
629typedef struct asc_dvc_inq_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400630 uchar type[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631} ASC_DVC_INQ_INFO;
632
633typedef struct asc_cap_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400634 ASC_DCNT lba;
635 ASC_DCNT blk_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636} ASC_CAP_INFO;
637
638typedef struct asc_cap_info_array {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400639 ASC_CAP_INFO cap_info[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640} ASC_CAP_INFO_ARRAY;
641
642#define ASC_MCNTL_NO_SEL_TIMEOUT (ushort)0x0001
643#define ASC_MCNTL_NULL_TARGET (ushort)0x0002
644#define ASC_CNTL_INITIATOR (ushort)0x0001
645#define ASC_CNTL_BIOS_GT_1GB (ushort)0x0002
646#define ASC_CNTL_BIOS_GT_2_DISK (ushort)0x0004
647#define ASC_CNTL_BIOS_REMOVABLE (ushort)0x0008
648#define ASC_CNTL_NO_SCAM (ushort)0x0010
649#define ASC_CNTL_INT_MULTI_Q (ushort)0x0080
650#define ASC_CNTL_NO_LUN_SUPPORT (ushort)0x0040
651#define ASC_CNTL_NO_VERIFY_COPY (ushort)0x0100
652#define ASC_CNTL_RESET_SCSI (ushort)0x0200
653#define ASC_CNTL_INIT_INQUIRY (ushort)0x0400
654#define ASC_CNTL_INIT_VERBOSE (ushort)0x0800
655#define ASC_CNTL_SCSI_PARITY (ushort)0x1000
656#define ASC_CNTL_BURST_MODE (ushort)0x2000
657#define ASC_CNTL_SDTR_ENABLE_ULTRA (ushort)0x4000
658#define ASC_EEP_DVC_CFG_BEG_VL 2
659#define ASC_EEP_MAX_DVC_ADDR_VL 15
660#define ASC_EEP_DVC_CFG_BEG 32
661#define ASC_EEP_MAX_DVC_ADDR 45
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662#define ASC_EEP_MAX_RETRY 20
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663
664/*
665 * These macros keep the chip SCSI id and ISA DMA speed
666 * bitfields in board order. C bitfields aren't portable
667 * between big and little-endian platforms so they are
668 * not used.
669 */
670
671#define ASC_EEP_GET_CHIP_ID(cfg) ((cfg)->id_speed & 0x0f)
672#define ASC_EEP_GET_DMA_SPD(cfg) (((cfg)->id_speed & 0xf0) >> 4)
673#define ASC_EEP_SET_CHIP_ID(cfg, sid) \
674 ((cfg)->id_speed = ((cfg)->id_speed & 0xf0) | ((sid) & ASC_MAX_TID))
675#define ASC_EEP_SET_DMA_SPD(cfg, spd) \
676 ((cfg)->id_speed = ((cfg)->id_speed & 0x0f) | ((spd) & 0x0f) << 4)
677
678typedef struct asceep_config {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400679 ushort cfg_lsw;
680 ushort cfg_msw;
681 uchar init_sdtr;
682 uchar disc_enable;
683 uchar use_cmd_qng;
684 uchar start_motor;
685 uchar max_total_qng;
686 uchar max_tag_qng;
687 uchar bios_scan;
688 uchar power_up_wait;
689 uchar no_scam;
690 uchar id_speed; /* low order 4 bits is chip scsi id */
691 /* high order 4 bits is isa dma speed */
692 uchar dos_int13_table[ASC_MAX_TID + 1];
693 uchar adapter_info[6];
694 ushort cntl;
695 ushort chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696} ASCEEP_CONFIG;
697
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698#define ASC_EEP_CMD_READ 0x80
699#define ASC_EEP_CMD_WRITE 0x40
700#define ASC_EEP_CMD_WRITE_ABLE 0x30
701#define ASC_EEP_CMD_WRITE_DISABLE 0x00
702#define ASC_OVERRUN_BSIZE 0x00000048UL
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703#define ASCV_MSGOUT_BEG 0x0000
704#define ASCV_MSGOUT_SDTR_PERIOD (ASCV_MSGOUT_BEG+3)
705#define ASCV_MSGOUT_SDTR_OFFSET (ASCV_MSGOUT_BEG+4)
706#define ASCV_BREAK_SAVED_CODE (ushort)0x0006
707#define ASCV_MSGIN_BEG (ASCV_MSGOUT_BEG+8)
708#define ASCV_MSGIN_SDTR_PERIOD (ASCV_MSGIN_BEG+3)
709#define ASCV_MSGIN_SDTR_OFFSET (ASCV_MSGIN_BEG+4)
710#define ASCV_SDTR_DATA_BEG (ASCV_MSGIN_BEG+8)
711#define ASCV_SDTR_DONE_BEG (ASCV_SDTR_DATA_BEG+8)
712#define ASCV_MAX_DVC_QNG_BEG (ushort)0x0020
713#define ASCV_BREAK_ADDR (ushort)0x0028
714#define ASCV_BREAK_NOTIFY_COUNT (ushort)0x002A
715#define ASCV_BREAK_CONTROL (ushort)0x002C
716#define ASCV_BREAK_HIT_COUNT (ushort)0x002E
717
718#define ASCV_ASCDVC_ERR_CODE_W (ushort)0x0030
719#define ASCV_MCODE_CHKSUM_W (ushort)0x0032
720#define ASCV_MCODE_SIZE_W (ushort)0x0034
721#define ASCV_STOP_CODE_B (ushort)0x0036
722#define ASCV_DVC_ERR_CODE_B (ushort)0x0037
723#define ASCV_OVERRUN_PADDR_D (ushort)0x0038
724#define ASCV_OVERRUN_BSIZE_D (ushort)0x003C
725#define ASCV_HALTCODE_W (ushort)0x0040
726#define ASCV_CHKSUM_W (ushort)0x0042
727#define ASCV_MC_DATE_W (ushort)0x0044
728#define ASCV_MC_VER_W (ushort)0x0046
729#define ASCV_NEXTRDY_B (ushort)0x0048
730#define ASCV_DONENEXT_B (ushort)0x0049
731#define ASCV_USE_TAGGED_QNG_B (ushort)0x004A
732#define ASCV_SCSIBUSY_B (ushort)0x004B
733#define ASCV_Q_DONE_IN_PROGRESS_B (ushort)0x004C
734#define ASCV_CURCDB_B (ushort)0x004D
735#define ASCV_RCLUN_B (ushort)0x004E
736#define ASCV_BUSY_QHEAD_B (ushort)0x004F
737#define ASCV_DISC1_QHEAD_B (ushort)0x0050
738#define ASCV_DISC_ENABLE_B (ushort)0x0052
739#define ASCV_CAN_TAGGED_QNG_B (ushort)0x0053
740#define ASCV_HOSTSCSI_ID_B (ushort)0x0055
741#define ASCV_MCODE_CNTL_B (ushort)0x0056
742#define ASCV_NULL_TARGET_B (ushort)0x0057
743#define ASCV_FREE_Q_HEAD_W (ushort)0x0058
744#define ASCV_DONE_Q_TAIL_W (ushort)0x005A
745#define ASCV_FREE_Q_HEAD_B (ushort)(ASCV_FREE_Q_HEAD_W+1)
746#define ASCV_DONE_Q_TAIL_B (ushort)(ASCV_DONE_Q_TAIL_W+1)
747#define ASCV_HOST_FLAG_B (ushort)0x005D
748#define ASCV_TOTAL_READY_Q_B (ushort)0x0064
749#define ASCV_VER_SERIAL_B (ushort)0x0065
750#define ASCV_HALTCODE_SAVED_W (ushort)0x0066
751#define ASCV_WTM_FLAG_B (ushort)0x0068
752#define ASCV_RISC_FLAG_B (ushort)0x006A
753#define ASCV_REQ_SG_LIST_QP (ushort)0x006B
754#define ASC_HOST_FLAG_IN_ISR 0x01
755#define ASC_HOST_FLAG_ACK_INT 0x02
756#define ASC_RISC_FLAG_GEN_INT 0x01
757#define ASC_RISC_FLAG_REQ_SG_LIST 0x02
758#define IOP_CTRL (0x0F)
759#define IOP_STATUS (0x0E)
760#define IOP_INT_ACK IOP_STATUS
761#define IOP_REG_IFC (0x0D)
762#define IOP_SYN_OFFSET (0x0B)
763#define IOP_EXTRA_CONTROL (0x0D)
764#define IOP_REG_PC (0x0C)
765#define IOP_RAM_ADDR (0x0A)
766#define IOP_RAM_DATA (0x08)
767#define IOP_EEP_DATA (0x06)
768#define IOP_EEP_CMD (0x07)
769#define IOP_VERSION (0x03)
770#define IOP_CONFIG_HIGH (0x04)
771#define IOP_CONFIG_LOW (0x02)
772#define IOP_SIG_BYTE (0x01)
773#define IOP_SIG_WORD (0x00)
774#define IOP_REG_DC1 (0x0E)
775#define IOP_REG_DC0 (0x0C)
776#define IOP_REG_SB (0x0B)
777#define IOP_REG_DA1 (0x0A)
778#define IOP_REG_DA0 (0x08)
779#define IOP_REG_SC (0x09)
780#define IOP_DMA_SPEED (0x07)
781#define IOP_REG_FLAG (0x07)
782#define IOP_FIFO_H (0x06)
783#define IOP_FIFO_L (0x04)
784#define IOP_REG_ID (0x05)
785#define IOP_REG_QP (0x03)
786#define IOP_REG_IH (0x02)
787#define IOP_REG_IX (0x01)
788#define IOP_REG_AX (0x00)
789#define IFC_REG_LOCK (0x00)
790#define IFC_REG_UNLOCK (0x09)
791#define IFC_WR_EN_FILTER (0x10)
792#define IFC_RD_NO_EEPROM (0x10)
793#define IFC_SLEW_RATE (0x20)
794#define IFC_ACT_NEG (0x40)
795#define IFC_INP_FILTER (0x80)
796#define IFC_INIT_DEFAULT (IFC_ACT_NEG | IFC_REG_UNLOCK)
797#define SC_SEL (uchar)(0x80)
798#define SC_BSY (uchar)(0x40)
799#define SC_ACK (uchar)(0x20)
800#define SC_REQ (uchar)(0x10)
801#define SC_ATN (uchar)(0x08)
802#define SC_IO (uchar)(0x04)
803#define SC_CD (uchar)(0x02)
804#define SC_MSG (uchar)(0x01)
805#define SEC_SCSI_CTL (uchar)(0x80)
806#define SEC_ACTIVE_NEGATE (uchar)(0x40)
807#define SEC_SLEW_RATE (uchar)(0x20)
808#define SEC_ENABLE_FILTER (uchar)(0x10)
809#define ASC_HALT_EXTMSG_IN (ushort)0x8000
810#define ASC_HALT_CHK_CONDITION (ushort)0x8100
811#define ASC_HALT_SS_QUEUE_FULL (ushort)0x8200
812#define ASC_HALT_DISABLE_ASYN_USE_SYN_FIX (ushort)0x8300
813#define ASC_HALT_ENABLE_ASYN_USE_SYN_FIX (ushort)0x8400
814#define ASC_HALT_SDTR_REJECTED (ushort)0x4000
815#define ASC_HALT_HOST_COPY_SG_LIST_TO_RISC ( ushort )0x2000
816#define ASC_MAX_QNO 0xF8
817#define ASC_DATA_SEC_BEG (ushort)0x0080
818#define ASC_DATA_SEC_END (ushort)0x0080
819#define ASC_CODE_SEC_BEG (ushort)0x0080
820#define ASC_CODE_SEC_END (ushort)0x0080
821#define ASC_QADR_BEG (0x4000)
822#define ASC_QADR_USED (ushort)(ASC_MAX_QNO * 64)
823#define ASC_QADR_END (ushort)0x7FFF
824#define ASC_QLAST_ADR (ushort)0x7FC0
825#define ASC_QBLK_SIZE 0x40
826#define ASC_BIOS_DATA_QBEG 0xF8
827#define ASC_MIN_ACTIVE_QNO 0x01
828#define ASC_QLINK_END 0xFF
829#define ASC_EEPROM_WORDS 0x10
830#define ASC_MAX_MGS_LEN 0x10
831#define ASC_BIOS_ADDR_DEF 0xDC00
832#define ASC_BIOS_SIZE 0x3800
833#define ASC_BIOS_RAM_OFF 0x3800
834#define ASC_BIOS_RAM_SIZE 0x800
835#define ASC_BIOS_MIN_ADDR 0xC000
836#define ASC_BIOS_MAX_ADDR 0xEC00
837#define ASC_BIOS_BANK_SIZE 0x0400
838#define ASC_MCODE_START_ADDR 0x0080
839#define ASC_CFG0_HOST_INT_ON 0x0020
840#define ASC_CFG0_BIOS_ON 0x0040
841#define ASC_CFG0_VERA_BURST_ON 0x0080
842#define ASC_CFG0_SCSI_PARITY_ON 0x0800
843#define ASC_CFG1_SCSI_TARGET_ON 0x0080
844#define ASC_CFG1_LRAM_8BITS_ON 0x0800
845#define ASC_CFG_MSW_CLR_MASK 0x3080
846#define CSW_TEST1 (ASC_CS_TYPE)0x8000
847#define CSW_AUTO_CONFIG (ASC_CS_TYPE)0x4000
848#define CSW_RESERVED1 (ASC_CS_TYPE)0x2000
849#define CSW_IRQ_WRITTEN (ASC_CS_TYPE)0x1000
850#define CSW_33MHZ_SELECTED (ASC_CS_TYPE)0x0800
851#define CSW_TEST2 (ASC_CS_TYPE)0x0400
852#define CSW_TEST3 (ASC_CS_TYPE)0x0200
853#define CSW_RESERVED2 (ASC_CS_TYPE)0x0100
854#define CSW_DMA_DONE (ASC_CS_TYPE)0x0080
855#define CSW_FIFO_RDY (ASC_CS_TYPE)0x0040
856#define CSW_EEP_READ_DONE (ASC_CS_TYPE)0x0020
857#define CSW_HALTED (ASC_CS_TYPE)0x0010
858#define CSW_SCSI_RESET_ACTIVE (ASC_CS_TYPE)0x0008
859#define CSW_PARITY_ERR (ASC_CS_TYPE)0x0004
860#define CSW_SCSI_RESET_LATCH (ASC_CS_TYPE)0x0002
861#define CSW_INT_PENDING (ASC_CS_TYPE)0x0001
862#define CIW_CLR_SCSI_RESET_INT (ASC_CS_TYPE)0x1000
863#define CIW_INT_ACK (ASC_CS_TYPE)0x0100
864#define CIW_TEST1 (ASC_CS_TYPE)0x0200
865#define CIW_TEST2 (ASC_CS_TYPE)0x0400
866#define CIW_SEL_33MHZ (ASC_CS_TYPE)0x0800
867#define CIW_IRQ_ACT (ASC_CS_TYPE)0x1000
868#define CC_CHIP_RESET (uchar)0x80
869#define CC_SCSI_RESET (uchar)0x40
870#define CC_HALT (uchar)0x20
871#define CC_SINGLE_STEP (uchar)0x10
872#define CC_DMA_ABLE (uchar)0x08
873#define CC_TEST (uchar)0x04
874#define CC_BANK_ONE (uchar)0x02
875#define CC_DIAG (uchar)0x01
876#define ASC_1000_ID0W 0x04C1
877#define ASC_1000_ID0W_FIX 0x00C1
878#define ASC_1000_ID1B 0x25
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879#define ASC_EISA_REV_IOP_MASK (0x0C83)
880#define ASC_EISA_PID_IOP_MASK (0x0C80)
881#define ASC_EISA_CFG_IOP_MASK (0x0C86)
882#define ASC_GET_EISA_SLOT(iop) (PortAddr)((iop) & 0xF000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883#define INS_HALTINT (ushort)0x6281
884#define INS_HALT (ushort)0x6280
885#define INS_SINT (ushort)0x6200
886#define INS_RFLAG_WTM (ushort)0x7380
887#define ASC_MC_SAVE_CODE_WSIZE 0x500
888#define ASC_MC_SAVE_DATA_WSIZE 0x40
889
890typedef struct asc_mc_saved {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400891 ushort data[ASC_MC_SAVE_DATA_WSIZE];
892 ushort code[ASC_MC_SAVE_CODE_WSIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893} ASC_MC_SAVED;
894
895#define AscGetQDoneInProgress(port) AscReadLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B)
896#define AscPutQDoneInProgress(port, val) AscWriteLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B, val)
897#define AscGetVarFreeQHead(port) AscReadLramWord((port), ASCV_FREE_Q_HEAD_W)
898#define AscGetVarDoneQTail(port) AscReadLramWord((port), ASCV_DONE_Q_TAIL_W)
899#define AscPutVarFreeQHead(port, val) AscWriteLramWord((port), ASCV_FREE_Q_HEAD_W, val)
900#define AscPutVarDoneQTail(port, val) AscWriteLramWord((port), ASCV_DONE_Q_TAIL_W, val)
901#define AscGetRiscVarFreeQHead(port) AscReadLramByte((port), ASCV_NEXTRDY_B)
902#define AscGetRiscVarDoneQTail(port) AscReadLramByte((port), ASCV_DONENEXT_B)
903#define AscPutRiscVarFreeQHead(port, val) AscWriteLramByte((port), ASCV_NEXTRDY_B, val)
904#define AscPutRiscVarDoneQTail(port, val) AscWriteLramByte((port), ASCV_DONENEXT_B, val)
905#define AscPutMCodeSDTRDoneAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id), (data));
906#define AscGetMCodeSDTRDoneAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id));
907#define AscPutMCodeInitSDTRAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id), data);
908#define AscGetMCodeInitSDTRAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id));
909#define AscSynIndexToPeriod(index) (uchar)(asc_dvc->sdtr_period_tbl[ (index) ])
910#define AscGetChipSignatureByte(port) (uchar)inp((port)+IOP_SIG_BYTE)
911#define AscGetChipSignatureWord(port) (ushort)inpw((port)+IOP_SIG_WORD)
912#define AscGetChipVerNo(port) (uchar)inp((port)+IOP_VERSION)
913#define AscGetChipCfgLsw(port) (ushort)inpw((port)+IOP_CONFIG_LOW)
914#define AscGetChipCfgMsw(port) (ushort)inpw((port)+IOP_CONFIG_HIGH)
915#define AscSetChipCfgLsw(port, data) outpw((port)+IOP_CONFIG_LOW, data)
916#define AscSetChipCfgMsw(port, data) outpw((port)+IOP_CONFIG_HIGH, data)
917#define AscGetChipEEPCmd(port) (uchar)inp((port)+IOP_EEP_CMD)
918#define AscSetChipEEPCmd(port, data) outp((port)+IOP_EEP_CMD, data)
919#define AscGetChipEEPData(port) (ushort)inpw((port)+IOP_EEP_DATA)
920#define AscSetChipEEPData(port, data) outpw((port)+IOP_EEP_DATA, data)
921#define AscGetChipLramAddr(port) (ushort)inpw((PortAddr)((port)+IOP_RAM_ADDR))
922#define AscSetChipLramAddr(port, addr) outpw((PortAddr)((port)+IOP_RAM_ADDR), addr)
923#define AscGetChipLramData(port) (ushort)inpw((port)+IOP_RAM_DATA)
924#define AscSetChipLramData(port, data) outpw((port)+IOP_RAM_DATA, data)
925#define AscGetChipIFC(port) (uchar)inp((port)+IOP_REG_IFC)
926#define AscSetChipIFC(port, data) outp((port)+IOP_REG_IFC, data)
927#define AscGetChipStatus(port) (ASC_CS_TYPE)inpw((port)+IOP_STATUS)
928#define AscSetChipStatus(port, cs_val) outpw((port)+IOP_STATUS, cs_val)
929#define AscGetChipControl(port) (uchar)inp((port)+IOP_CTRL)
930#define AscSetChipControl(port, cc_val) outp((port)+IOP_CTRL, cc_val)
931#define AscGetChipSyn(port) (uchar)inp((port)+IOP_SYN_OFFSET)
932#define AscSetChipSyn(port, data) outp((port)+IOP_SYN_OFFSET, data)
933#define AscSetPCAddr(port, data) outpw((port)+IOP_REG_PC, data)
934#define AscGetPCAddr(port) (ushort)inpw((port)+IOP_REG_PC)
935#define AscIsIntPending(port) (AscGetChipStatus(port) & (CSW_INT_PENDING | CSW_SCSI_RESET_LATCH))
936#define AscGetChipScsiID(port) ((AscGetChipCfgLsw(port) >> 8) & ASC_MAX_TID)
937#define AscGetExtraControl(port) (uchar)inp((port)+IOP_EXTRA_CONTROL)
938#define AscSetExtraControl(port, data) outp((port)+IOP_EXTRA_CONTROL, data)
939#define AscReadChipAX(port) (ushort)inpw((port)+IOP_REG_AX)
940#define AscWriteChipAX(port, data) outpw((port)+IOP_REG_AX, data)
941#define AscReadChipIX(port) (uchar)inp((port)+IOP_REG_IX)
942#define AscWriteChipIX(port, data) outp((port)+IOP_REG_IX, data)
943#define AscReadChipIH(port) (ushort)inpw((port)+IOP_REG_IH)
944#define AscWriteChipIH(port, data) outpw((port)+IOP_REG_IH, data)
945#define AscReadChipQP(port) (uchar)inp((port)+IOP_REG_QP)
946#define AscWriteChipQP(port, data) outp((port)+IOP_REG_QP, data)
947#define AscReadChipFIFO_L(port) (ushort)inpw((port)+IOP_REG_FIFO_L)
948#define AscWriteChipFIFO_L(port, data) outpw((port)+IOP_REG_FIFO_L, data)
949#define AscReadChipFIFO_H(port) (ushort)inpw((port)+IOP_REG_FIFO_H)
950#define AscWriteChipFIFO_H(port, data) outpw((port)+IOP_REG_FIFO_H, data)
951#define AscReadChipDmaSpeed(port) (uchar)inp((port)+IOP_DMA_SPEED)
952#define AscWriteChipDmaSpeed(port, data) outp((port)+IOP_DMA_SPEED, data)
953#define AscReadChipDA0(port) (ushort)inpw((port)+IOP_REG_DA0)
954#define AscWriteChipDA0(port) outpw((port)+IOP_REG_DA0, data)
955#define AscReadChipDA1(port) (ushort)inpw((port)+IOP_REG_DA1)
956#define AscWriteChipDA1(port) outpw((port)+IOP_REG_DA1, data)
957#define AscReadChipDC0(port) (ushort)inpw((port)+IOP_REG_DC0)
958#define AscWriteChipDC0(port) outpw((port)+IOP_REG_DC0, data)
959#define AscReadChipDC1(port) (ushort)inpw((port)+IOP_REG_DC1)
960#define AscWriteChipDC1(port) outpw((port)+IOP_REG_DC1, data)
961#define AscReadChipDvcID(port) (uchar)inp((port)+IOP_REG_ID)
962#define AscWriteChipDvcID(port, data) outp((port)+IOP_REG_ID, data)
963
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400964static int AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg);
965static int AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg);
966static void AscWaitEEPRead(void);
967static void AscWaitEEPWrite(void);
968static ushort AscReadEEPWord(PortAddr, uchar);
969static ushort AscWriteEEPWord(PortAddr, uchar, ushort);
970static ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
971static int AscSetEEPConfigOnce(PortAddr, ASCEEP_CONFIG *, ushort);
972static int AscSetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
973static int AscStartChip(PortAddr);
974static int AscStopChip(PortAddr);
975static void AscSetChipIH(PortAddr, ushort);
976static int AscIsChipHalted(PortAddr);
977static void AscAckInterrupt(PortAddr);
978static void AscDisableInterrupt(PortAddr);
979static void AscEnableInterrupt(PortAddr);
980static void AscSetBank(PortAddr, uchar);
981static int AscResetChipAndScsiBus(ASC_DVC_VAR *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400983static uchar AscGetIsaDmaSpeed(PortAddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400985static uchar AscReadLramByte(PortAddr, ushort);
986static ushort AscReadLramWord(PortAddr, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400988static ASC_DCNT AscReadLramDWord(PortAddr, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400990static void AscWriteLramWord(PortAddr, ushort, ushort);
991static void AscWriteLramByte(PortAddr, ushort, uchar);
992static ASC_DCNT AscMemSumLramWord(PortAddr, ushort, int);
993static void AscMemWordSetLram(PortAddr, ushort, ushort, int);
994static void AscMemWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
995static void AscMemDWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
996static void AscMemWordCopyPtrFromLram(PortAddr, ushort, uchar *, int);
997static ushort AscInitAscDvcVar(ASC_DVC_VAR *);
998static ushort AscInitFromEEP(ASC_DVC_VAR *);
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400999static ushort AscInitMicroCodeVar(ASC_DVC_VAR *);
1000static int AscTestExternalLram(ASC_DVC_VAR *);
1001static uchar AscMsgOutSDTR(ASC_DVC_VAR *, uchar, uchar);
1002static uchar AscCalSDTRData(ASC_DVC_VAR *, uchar, uchar);
1003static void AscSetChipSDTR(PortAddr, uchar, uchar);
1004static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *, uchar);
1005static uchar AscAllocFreeQueue(PortAddr, uchar);
1006static uchar AscAllocMultipleFreeQueue(PortAddr, uchar, uchar);
1007static int AscHostReqRiscHalt(PortAddr);
1008static int AscStopQueueExe(PortAddr);
1009static int AscSendScsiQueue(ASC_DVC_VAR *,
1010 ASC_SCSI_Q *scsiq, uchar n_q_required);
1011static int AscPutReadyQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
1012static int AscPutReadySgListQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
1013static int AscSetChipSynRegAtID(PortAddr, uchar, uchar);
1014static int AscSetRunChipSynRegAtID(PortAddr, uchar, uchar);
1015static ushort AscInitLram(ASC_DVC_VAR *);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001016static int AscSetLibErrorCode(ASC_DVC_VAR *, ushort);
1017static int AscIsrChipHalted(ASC_DVC_VAR *);
1018static uchar _AscCopyLramScsiDoneQ(PortAddr, ushort,
1019 ASC_QDONE_INFO *, ASC_DCNT);
1020static int AscIsrQDone(ASC_DVC_VAR *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001022static ushort AscGetEisaChipCfg(PortAddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001024static uchar AscGetChipScsiCtrl(PortAddr);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001025static uchar AscGetChipVersion(PortAddr, ushort);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001026static ASC_DCNT AscLoadMicroCode(PortAddr, ushort, uchar *, ushort);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001027static void AscToggleIRQAct(PortAddr);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001028static void DvcPutScsiQ(PortAddr, ushort, uchar *, int);
1029static void DvcGetQinfo(PortAddr, ushort, uchar *, int);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001030static ushort AscInitAsc1000Driver(ASC_DVC_VAR *);
Matthew Wilcox47d853c2007-07-26 11:41:33 -04001031static void AscAsyncFix(ASC_DVC_VAR *, struct scsi_device *);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001032static int AscExeScsiQueue(ASC_DVC_VAR *, ASC_SCSI_Q *);
1033static int AscISR(ASC_DVC_VAR *);
1034static uint AscGetNumOfFreeQueue(ASC_DVC_VAR *, uchar, uchar);
1035static int AscSgListToQueue(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001037static void AscEnableIsaDma(uchar);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001039static const char *advansys_info(struct Scsi_Host *shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041#define ADV_LIB_VERSION_MAJOR 5
1042#define ADV_LIB_VERSION_MINOR 14
1043
1044/*
1045 * Define Adv Library required special types.
1046 */
1047
1048/*
1049 * Portable Data Types
1050 *
1051 * Any instance where a 32-bit long or pointer type is assumed
1052 * for precision or HW defined structures, the following define
1053 * types must be used. In Linux the char, short, and int types
1054 * are all consistent at 8, 16, and 32 bits respectively. Pointers
1055 * and long types are 64 bits on Alpha and UltraSPARC.
1056 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001057#define ADV_PADDR __u32 /* Physical address data type. */
1058#define ADV_VADDR __u32 /* Virtual address data type. */
1059#define ADV_DCNT __u32 /* Unsigned Data count type. */
1060#define ADV_SDCNT __s32 /* Signed Data count type. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061
1062/*
1063 * These macros are used to convert a virtual address to a
1064 * 32-bit value. This currently can be used on Linux Alpha
1065 * which uses 64-bit virtual address but a 32-bit bus address.
1066 * This is likely to break in the future, but doing this now
1067 * will give us time to change the HW and FW to handle 64-bit
1068 * addresses.
1069 */
1070#define ADV_VADDR_TO_U32 virt_to_bus
1071#define ADV_U32_TO_VADDR bus_to_virt
1072
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001073#define AdvPortAddr void __iomem * /* Virtual memory address size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074
1075/*
1076 * Define Adv Library required memory access macros.
1077 */
1078#define ADV_MEM_READB(addr) readb(addr)
1079#define ADV_MEM_READW(addr) readw(addr)
1080#define ADV_MEM_WRITEB(addr, byte) writeb(byte, addr)
1081#define ADV_MEM_WRITEW(addr, word) writew(word, addr)
1082#define ADV_MEM_WRITEDW(addr, dword) writel(dword, addr)
1083
1084#define ADV_CARRIER_COUNT (ASC_DEF_MAX_HOST_QNG + 15)
1085
1086/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 * Define total number of simultaneous maximum element scatter-gather
1088 * request blocks per wide adapter. ASC_DEF_MAX_HOST_QNG (253) is the
1089 * maximum number of outstanding commands per wide host adapter. Each
1090 * command uses one or more ADV_SG_BLOCK each with 15 scatter-gather
1091 * elements. Allow each command to have at least one ADV_SG_BLOCK structure.
1092 * This allows about 15 commands to have the maximum 17 ADV_SG_BLOCK
1093 * structures or 255 scatter-gather elements.
1094 *
1095 */
1096#define ADV_TOT_SG_BLOCK ASC_DEF_MAX_HOST_QNG
1097
1098/*
1099 * Define Adv Library required maximum number of scatter-gather
1100 * elements per request.
1101 */
1102#define ADV_MAX_SG_LIST 255
1103
1104/* Number of SG blocks needed. */
1105#define ADV_NUM_SG_BLOCK \
1106 ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)
1107
1108/* Total contiguous memory needed for SG blocks. */
1109#define ADV_SG_TOTAL_MEM_SIZE \
1110 (sizeof(ADV_SG_BLOCK) * ADV_NUM_SG_BLOCK)
1111
1112#define ADV_PAGE_SIZE PAGE_SIZE
1113
1114#define ADV_NUM_PAGE_CROSSING \
1115 ((ADV_SG_TOTAL_MEM_SIZE + (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
1116
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117#define ADV_EEP_DVC_CFG_BEGIN (0x00)
1118#define ADV_EEP_DVC_CFG_END (0x15)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001119#define ADV_EEP_DVC_CTL_BEGIN (0x16) /* location of OEM name */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120#define ADV_EEP_MAX_WORD_ADDR (0x1E)
1121
1122#define ADV_EEP_DELAY_MS 100
1123
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001124#define ADV_EEPROM_BIG_ENDIAN 0x8000 /* EEPROM Bit 15 */
1125#define ADV_EEPROM_BIOS_ENABLE 0x4000 /* EEPROM Bit 14 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126/*
1127 * For the ASC3550 Bit 13 is Termination Polarity control bit.
1128 * For later ICs Bit 13 controls whether the CIS (Card Information
1129 * Service Section) is loaded from EEPROM.
1130 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001131#define ADV_EEPROM_TERM_POL 0x2000 /* EEPROM Bit 13 */
1132#define ADV_EEPROM_CIS_LD 0x2000 /* EEPROM Bit 13 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133/*
1134 * ASC38C1600 Bit 11
1135 *
1136 * If EEPROM Bit 11 is 0 for Function 0, then Function 0 will specify
1137 * INT A in the PCI Configuration Space Int Pin field. If it is 1, then
1138 * Function 0 will specify INT B.
1139 *
1140 * If EEPROM Bit 11 is 0 for Function 1, then Function 1 will specify
1141 * INT B in the PCI Configuration Space Int Pin field. If it is 1, then
1142 * Function 1 will specify INT A.
1143 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001144#define ADV_EEPROM_INTAB 0x0800 /* EEPROM Bit 11 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001146typedef struct adveep_3550_config {
1147 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001149 ushort cfg_lsw; /* 00 power up initialization */
1150 /* bit 13 set - Term Polarity Control */
1151 /* bit 14 set - BIOS Enable */
1152 /* bit 15 set - Big Endian Mode */
1153 ushort cfg_msw; /* 01 unused */
1154 ushort disc_enable; /* 02 disconnect enable */
1155 ushort wdtr_able; /* 03 Wide DTR able */
1156 ushort sdtr_able; /* 04 Synchronous DTR able */
1157 ushort start_motor; /* 05 send start up motor */
1158 ushort tagqng_able; /* 06 tag queuing able */
1159 ushort bios_scan; /* 07 BIOS device control */
1160 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001162 uchar adapter_scsi_id; /* 09 Host Adapter ID */
1163 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001165 uchar scsi_reset_delay; /* 10 reset delay */
1166 uchar bios_id_lun; /* first boot device scsi id & lun */
1167 /* high nibble is lun */
1168 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001170 uchar termination; /* 11 0 - automatic */
1171 /* 1 - low off / high off */
1172 /* 2 - low off / high on */
1173 /* 3 - low on / high on */
1174 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001176 uchar reserved1; /* reserved byte (not used) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001178 ushort bios_ctrl; /* 12 BIOS control bits */
1179 /* bit 0 BIOS don't act as initiator. */
1180 /* bit 1 BIOS > 1 GB support */
1181 /* bit 2 BIOS > 2 Disk Support */
1182 /* bit 3 BIOS don't support removables */
1183 /* bit 4 BIOS support bootable CD */
1184 /* bit 5 BIOS scan enabled */
1185 /* bit 6 BIOS support multiple LUNs */
1186 /* bit 7 BIOS display of message */
1187 /* bit 8 SCAM disabled */
1188 /* bit 9 Reset SCSI bus during init. */
1189 /* bit 10 */
1190 /* bit 11 No verbose initialization. */
1191 /* bit 12 SCSI parity enabled */
1192 /* bit 13 */
1193 /* bit 14 */
1194 /* bit 15 */
1195 ushort ultra_able; /* 13 ULTRA speed able */
1196 ushort reserved2; /* 14 reserved */
1197 uchar max_host_qng; /* 15 maximum host queuing */
1198 uchar max_dvc_qng; /* maximum per device queuing */
1199 ushort dvc_cntl; /* 16 control bit for driver */
1200 ushort bug_fix; /* 17 control bit for bug fix */
1201 ushort serial_number_word1; /* 18 Board serial number word 1 */
1202 ushort serial_number_word2; /* 19 Board serial number word 2 */
1203 ushort serial_number_word3; /* 20 Board serial number word 3 */
1204 ushort check_sum; /* 21 EEP check sum */
1205 uchar oem_name[16]; /* 22 OEM name */
1206 ushort dvc_err_code; /* 30 last device driver error code */
1207 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
1208 ushort adv_err_addr; /* 32 last uc error address */
1209 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
1210 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
1211 ushort saved_adv_err_addr; /* 35 saved last uc error address */
1212 ushort num_of_err; /* 36 number of error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213} ADVEEP_3550_CONFIG;
1214
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001215typedef struct adveep_38C0800_config {
1216 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001218 ushort cfg_lsw; /* 00 power up initialization */
1219 /* bit 13 set - Load CIS */
1220 /* bit 14 set - BIOS Enable */
1221 /* bit 15 set - Big Endian Mode */
1222 ushort cfg_msw; /* 01 unused */
1223 ushort disc_enable; /* 02 disconnect enable */
1224 ushort wdtr_able; /* 03 Wide DTR able */
1225 ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
1226 ushort start_motor; /* 05 send start up motor */
1227 ushort tagqng_able; /* 06 tag queuing able */
1228 ushort bios_scan; /* 07 BIOS device control */
1229 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001231 uchar adapter_scsi_id; /* 09 Host Adapter ID */
1232 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001234 uchar scsi_reset_delay; /* 10 reset delay */
1235 uchar bios_id_lun; /* first boot device scsi id & lun */
1236 /* high nibble is lun */
1237 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001239 uchar termination_se; /* 11 0 - automatic */
1240 /* 1 - low off / high off */
1241 /* 2 - low off / high on */
1242 /* 3 - low on / high on */
1243 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001245 uchar termination_lvd; /* 11 0 - automatic */
1246 /* 1 - low off / high off */
1247 /* 2 - low off / high on */
1248 /* 3 - low on / high on */
1249 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001251 ushort bios_ctrl; /* 12 BIOS control bits */
1252 /* bit 0 BIOS don't act as initiator. */
1253 /* bit 1 BIOS > 1 GB support */
1254 /* bit 2 BIOS > 2 Disk Support */
1255 /* bit 3 BIOS don't support removables */
1256 /* bit 4 BIOS support bootable CD */
1257 /* bit 5 BIOS scan enabled */
1258 /* bit 6 BIOS support multiple LUNs */
1259 /* bit 7 BIOS display of message */
1260 /* bit 8 SCAM disabled */
1261 /* bit 9 Reset SCSI bus during init. */
1262 /* bit 10 */
1263 /* bit 11 No verbose initialization. */
1264 /* bit 12 SCSI parity enabled */
1265 /* bit 13 */
1266 /* bit 14 */
1267 /* bit 15 */
1268 ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
1269 ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
1270 uchar max_host_qng; /* 15 maximum host queueing */
1271 uchar max_dvc_qng; /* maximum per device queuing */
1272 ushort dvc_cntl; /* 16 control bit for driver */
1273 ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
1274 ushort serial_number_word1; /* 18 Board serial number word 1 */
1275 ushort serial_number_word2; /* 19 Board serial number word 2 */
1276 ushort serial_number_word3; /* 20 Board serial number word 3 */
1277 ushort check_sum; /* 21 EEP check sum */
1278 uchar oem_name[16]; /* 22 OEM name */
1279 ushort dvc_err_code; /* 30 last device driver error code */
1280 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
1281 ushort adv_err_addr; /* 32 last uc error address */
1282 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
1283 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
1284 ushort saved_adv_err_addr; /* 35 saved last uc error address */
1285 ushort reserved36; /* 36 reserved */
1286 ushort reserved37; /* 37 reserved */
1287 ushort reserved38; /* 38 reserved */
1288 ushort reserved39; /* 39 reserved */
1289 ushort reserved40; /* 40 reserved */
1290 ushort reserved41; /* 41 reserved */
1291 ushort reserved42; /* 42 reserved */
1292 ushort reserved43; /* 43 reserved */
1293 ushort reserved44; /* 44 reserved */
1294 ushort reserved45; /* 45 reserved */
1295 ushort reserved46; /* 46 reserved */
1296 ushort reserved47; /* 47 reserved */
1297 ushort reserved48; /* 48 reserved */
1298 ushort reserved49; /* 49 reserved */
1299 ushort reserved50; /* 50 reserved */
1300 ushort reserved51; /* 51 reserved */
1301 ushort reserved52; /* 52 reserved */
1302 ushort reserved53; /* 53 reserved */
1303 ushort reserved54; /* 54 reserved */
1304 ushort reserved55; /* 55 reserved */
1305 ushort cisptr_lsw; /* 56 CIS PTR LSW */
1306 ushort cisprt_msw; /* 57 CIS PTR MSW */
1307 ushort subsysvid; /* 58 SubSystem Vendor ID */
1308 ushort subsysid; /* 59 SubSystem ID */
1309 ushort reserved60; /* 60 reserved */
1310 ushort reserved61; /* 61 reserved */
1311 ushort reserved62; /* 62 reserved */
1312 ushort reserved63; /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313} ADVEEP_38C0800_CONFIG;
1314
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001315typedef struct adveep_38C1600_config {
1316 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001318 ushort cfg_lsw; /* 00 power up initialization */
1319 /* bit 11 set - Func. 0 INTB, Func. 1 INTA */
1320 /* clear - Func. 0 INTA, Func. 1 INTB */
1321 /* bit 13 set - Load CIS */
1322 /* bit 14 set - BIOS Enable */
1323 /* bit 15 set - Big Endian Mode */
1324 ushort cfg_msw; /* 01 unused */
1325 ushort disc_enable; /* 02 disconnect enable */
1326 ushort wdtr_able; /* 03 Wide DTR able */
1327 ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
1328 ushort start_motor; /* 05 send start up motor */
1329 ushort tagqng_able; /* 06 tag queuing able */
1330 ushort bios_scan; /* 07 BIOS device control */
1331 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001333 uchar adapter_scsi_id; /* 09 Host Adapter ID */
1334 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001336 uchar scsi_reset_delay; /* 10 reset delay */
1337 uchar bios_id_lun; /* first boot device scsi id & lun */
1338 /* high nibble is lun */
1339 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001341 uchar termination_se; /* 11 0 - automatic */
1342 /* 1 - low off / high off */
1343 /* 2 - low off / high on */
1344 /* 3 - low on / high on */
1345 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001347 uchar termination_lvd; /* 11 0 - automatic */
1348 /* 1 - low off / high off */
1349 /* 2 - low off / high on */
1350 /* 3 - low on / high on */
1351 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001353 ushort bios_ctrl; /* 12 BIOS control bits */
1354 /* bit 0 BIOS don't act as initiator. */
1355 /* bit 1 BIOS > 1 GB support */
1356 /* bit 2 BIOS > 2 Disk Support */
1357 /* bit 3 BIOS don't support removables */
1358 /* bit 4 BIOS support bootable CD */
1359 /* bit 5 BIOS scan enabled */
1360 /* bit 6 BIOS support multiple LUNs */
1361 /* bit 7 BIOS display of message */
1362 /* bit 8 SCAM disabled */
1363 /* bit 9 Reset SCSI bus during init. */
1364 /* bit 10 Basic Integrity Checking disabled */
1365 /* bit 11 No verbose initialization. */
1366 /* bit 12 SCSI parity enabled */
1367 /* bit 13 AIPP (Asyn. Info. Ph. Prot.) dis. */
1368 /* bit 14 */
1369 /* bit 15 */
1370 ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
1371 ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
1372 uchar max_host_qng; /* 15 maximum host queueing */
1373 uchar max_dvc_qng; /* maximum per device queuing */
1374 ushort dvc_cntl; /* 16 control bit for driver */
1375 ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
1376 ushort serial_number_word1; /* 18 Board serial number word 1 */
1377 ushort serial_number_word2; /* 19 Board serial number word 2 */
1378 ushort serial_number_word3; /* 20 Board serial number word 3 */
1379 ushort check_sum; /* 21 EEP check sum */
1380 uchar oem_name[16]; /* 22 OEM name */
1381 ushort dvc_err_code; /* 30 last device driver error code */
1382 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
1383 ushort adv_err_addr; /* 32 last uc error address */
1384 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
1385 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
1386 ushort saved_adv_err_addr; /* 35 saved last uc error address */
1387 ushort reserved36; /* 36 reserved */
1388 ushort reserved37; /* 37 reserved */
1389 ushort reserved38; /* 38 reserved */
1390 ushort reserved39; /* 39 reserved */
1391 ushort reserved40; /* 40 reserved */
1392 ushort reserved41; /* 41 reserved */
1393 ushort reserved42; /* 42 reserved */
1394 ushort reserved43; /* 43 reserved */
1395 ushort reserved44; /* 44 reserved */
1396 ushort reserved45; /* 45 reserved */
1397 ushort reserved46; /* 46 reserved */
1398 ushort reserved47; /* 47 reserved */
1399 ushort reserved48; /* 48 reserved */
1400 ushort reserved49; /* 49 reserved */
1401 ushort reserved50; /* 50 reserved */
1402 ushort reserved51; /* 51 reserved */
1403 ushort reserved52; /* 52 reserved */
1404 ushort reserved53; /* 53 reserved */
1405 ushort reserved54; /* 54 reserved */
1406 ushort reserved55; /* 55 reserved */
1407 ushort cisptr_lsw; /* 56 CIS PTR LSW */
1408 ushort cisprt_msw; /* 57 CIS PTR MSW */
1409 ushort subsysvid; /* 58 SubSystem Vendor ID */
1410 ushort subsysid; /* 59 SubSystem ID */
1411 ushort reserved60; /* 60 reserved */
1412 ushort reserved61; /* 61 reserved */
1413 ushort reserved62; /* 62 reserved */
1414 ushort reserved63; /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415} ADVEEP_38C1600_CONFIG;
1416
1417/*
1418 * EEPROM Commands
1419 */
1420#define ASC_EEP_CMD_DONE 0x0200
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421
1422/* bios_ctrl */
1423#define BIOS_CTRL_BIOS 0x0001
1424#define BIOS_CTRL_EXTENDED_XLAT 0x0002
1425#define BIOS_CTRL_GT_2_DISK 0x0004
1426#define BIOS_CTRL_BIOS_REMOVABLE 0x0008
1427#define BIOS_CTRL_BOOTABLE_CD 0x0010
1428#define BIOS_CTRL_MULTIPLE_LUN 0x0040
1429#define BIOS_CTRL_DISPLAY_MSG 0x0080
1430#define BIOS_CTRL_NO_SCAM 0x0100
1431#define BIOS_CTRL_RESET_SCSI_BUS 0x0200
1432#define BIOS_CTRL_INIT_VERBOSE 0x0800
1433#define BIOS_CTRL_SCSI_PARITY 0x1000
1434#define BIOS_CTRL_AIPP_DIS 0x2000
1435
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001436#define ADV_3550_MEMSIZE 0x2000 /* 8 KB Internal Memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001438#define ADV_38C0800_MEMSIZE 0x4000 /* 16 KB Internal Memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439
1440/*
1441 * XXX - Since ASC38C1600 Rev.3 has a local RAM failure issue, there is
1442 * a special 16K Adv Library and Microcode version. After the issue is
1443 * resolved, should restore 32K support.
1444 *
1445 * #define ADV_38C1600_MEMSIZE 0x8000L * 32 KB Internal Memory *
1446 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001447#define ADV_38C1600_MEMSIZE 0x4000 /* 16 KB Internal Memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448
1449/*
1450 * Byte I/O register address from base of 'iop_base'.
1451 */
1452#define IOPB_INTR_STATUS_REG 0x00
1453#define IOPB_CHIP_ID_1 0x01
1454#define IOPB_INTR_ENABLES 0x02
1455#define IOPB_CHIP_TYPE_REV 0x03
1456#define IOPB_RES_ADDR_4 0x04
1457#define IOPB_RES_ADDR_5 0x05
1458#define IOPB_RAM_DATA 0x06
1459#define IOPB_RES_ADDR_7 0x07
1460#define IOPB_FLAG_REG 0x08
1461#define IOPB_RES_ADDR_9 0x09
1462#define IOPB_RISC_CSR 0x0A
1463#define IOPB_RES_ADDR_B 0x0B
1464#define IOPB_RES_ADDR_C 0x0C
1465#define IOPB_RES_ADDR_D 0x0D
1466#define IOPB_SOFT_OVER_WR 0x0E
1467#define IOPB_RES_ADDR_F 0x0F
1468#define IOPB_MEM_CFG 0x10
1469#define IOPB_RES_ADDR_11 0x11
1470#define IOPB_GPIO_DATA 0x12
1471#define IOPB_RES_ADDR_13 0x13
1472#define IOPB_FLASH_PAGE 0x14
1473#define IOPB_RES_ADDR_15 0x15
1474#define IOPB_GPIO_CNTL 0x16
1475#define IOPB_RES_ADDR_17 0x17
1476#define IOPB_FLASH_DATA 0x18
1477#define IOPB_RES_ADDR_19 0x19
1478#define IOPB_RES_ADDR_1A 0x1A
1479#define IOPB_RES_ADDR_1B 0x1B
1480#define IOPB_RES_ADDR_1C 0x1C
1481#define IOPB_RES_ADDR_1D 0x1D
1482#define IOPB_RES_ADDR_1E 0x1E
1483#define IOPB_RES_ADDR_1F 0x1F
1484#define IOPB_DMA_CFG0 0x20
1485#define IOPB_DMA_CFG1 0x21
1486#define IOPB_TICKLE 0x22
1487#define IOPB_DMA_REG_WR 0x23
1488#define IOPB_SDMA_STATUS 0x24
1489#define IOPB_SCSI_BYTE_CNT 0x25
1490#define IOPB_HOST_BYTE_CNT 0x26
1491#define IOPB_BYTE_LEFT_TO_XFER 0x27
1492#define IOPB_BYTE_TO_XFER_0 0x28
1493#define IOPB_BYTE_TO_XFER_1 0x29
1494#define IOPB_BYTE_TO_XFER_2 0x2A
1495#define IOPB_BYTE_TO_XFER_3 0x2B
1496#define IOPB_ACC_GRP 0x2C
1497#define IOPB_RES_ADDR_2D 0x2D
1498#define IOPB_DEV_ID 0x2E
1499#define IOPB_RES_ADDR_2F 0x2F
1500#define IOPB_SCSI_DATA 0x30
1501#define IOPB_RES_ADDR_31 0x31
1502#define IOPB_RES_ADDR_32 0x32
1503#define IOPB_SCSI_DATA_HSHK 0x33
1504#define IOPB_SCSI_CTRL 0x34
1505#define IOPB_RES_ADDR_35 0x35
1506#define IOPB_RES_ADDR_36 0x36
1507#define IOPB_RES_ADDR_37 0x37
1508#define IOPB_RAM_BIST 0x38
1509#define IOPB_PLL_TEST 0x39
1510#define IOPB_PCI_INT_CFG 0x3A
1511#define IOPB_RES_ADDR_3B 0x3B
1512#define IOPB_RFIFO_CNT 0x3C
1513#define IOPB_RES_ADDR_3D 0x3D
1514#define IOPB_RES_ADDR_3E 0x3E
1515#define IOPB_RES_ADDR_3F 0x3F
1516
1517/*
1518 * Word I/O register address from base of 'iop_base'.
1519 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001520#define IOPW_CHIP_ID_0 0x00 /* CID0 */
1521#define IOPW_CTRL_REG 0x02 /* CC */
1522#define IOPW_RAM_ADDR 0x04 /* LA */
1523#define IOPW_RAM_DATA 0x06 /* LD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524#define IOPW_RES_ADDR_08 0x08
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001525#define IOPW_RISC_CSR 0x0A /* CSR */
1526#define IOPW_SCSI_CFG0 0x0C /* CFG0 */
1527#define IOPW_SCSI_CFG1 0x0E /* CFG1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528#define IOPW_RES_ADDR_10 0x10
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001529#define IOPW_SEL_MASK 0x12 /* SM */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530#define IOPW_RES_ADDR_14 0x14
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001531#define IOPW_FLASH_ADDR 0x16 /* FA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532#define IOPW_RES_ADDR_18 0x18
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001533#define IOPW_EE_CMD 0x1A /* EC */
1534#define IOPW_EE_DATA 0x1C /* ED */
1535#define IOPW_SFIFO_CNT 0x1E /* SFC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536#define IOPW_RES_ADDR_20 0x20
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001537#define IOPW_Q_BASE 0x22 /* QB */
1538#define IOPW_QP 0x24 /* QP */
1539#define IOPW_IX 0x26 /* IX */
1540#define IOPW_SP 0x28 /* SP */
1541#define IOPW_PC 0x2A /* PC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542#define IOPW_RES_ADDR_2C 0x2C
1543#define IOPW_RES_ADDR_2E 0x2E
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001544#define IOPW_SCSI_DATA 0x30 /* SD */
1545#define IOPW_SCSI_DATA_HSHK 0x32 /* SDH */
1546#define IOPW_SCSI_CTRL 0x34 /* SC */
1547#define IOPW_HSHK_CFG 0x36 /* HCFG */
1548#define IOPW_SXFR_STATUS 0x36 /* SXS */
1549#define IOPW_SXFR_CNTL 0x38 /* SXL */
1550#define IOPW_SXFR_CNTH 0x3A /* SXH */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551#define IOPW_RES_ADDR_3C 0x3C
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001552#define IOPW_RFIFO_DATA 0x3E /* RFD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553
1554/*
1555 * Doubleword I/O register address from base of 'iop_base'.
1556 */
1557#define IOPDW_RES_ADDR_0 0x00
1558#define IOPDW_RAM_DATA 0x04
1559#define IOPDW_RES_ADDR_8 0x08
1560#define IOPDW_RES_ADDR_C 0x0C
1561#define IOPDW_RES_ADDR_10 0x10
1562#define IOPDW_COMMA 0x14
1563#define IOPDW_COMMB 0x18
1564#define IOPDW_RES_ADDR_1C 0x1C
1565#define IOPDW_SDMA_ADDR0 0x20
1566#define IOPDW_SDMA_ADDR1 0x24
1567#define IOPDW_SDMA_COUNT 0x28
1568#define IOPDW_SDMA_ERROR 0x2C
1569#define IOPDW_RDMA_ADDR0 0x30
1570#define IOPDW_RDMA_ADDR1 0x34
1571#define IOPDW_RDMA_COUNT 0x38
1572#define IOPDW_RDMA_ERROR 0x3C
1573
1574#define ADV_CHIP_ID_BYTE 0x25
1575#define ADV_CHIP_ID_WORD 0x04C1
1576
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577#define ADV_INTR_ENABLE_HOST_INTR 0x01
1578#define ADV_INTR_ENABLE_SEL_INTR 0x02
1579#define ADV_INTR_ENABLE_DPR_INTR 0x04
1580#define ADV_INTR_ENABLE_RTA_INTR 0x08
1581#define ADV_INTR_ENABLE_RMA_INTR 0x10
1582#define ADV_INTR_ENABLE_RST_INTR 0x20
1583#define ADV_INTR_ENABLE_DPE_INTR 0x40
1584#define ADV_INTR_ENABLE_GLOBAL_INTR 0x80
1585
1586#define ADV_INTR_STATUS_INTRA 0x01
1587#define ADV_INTR_STATUS_INTRB 0x02
1588#define ADV_INTR_STATUS_INTRC 0x04
1589
1590#define ADV_RISC_CSR_STOP (0x0000)
1591#define ADV_RISC_TEST_COND (0x2000)
1592#define ADV_RISC_CSR_RUN (0x4000)
1593#define ADV_RISC_CSR_SINGLE_STEP (0x8000)
1594
1595#define ADV_CTRL_REG_HOST_INTR 0x0100
1596#define ADV_CTRL_REG_SEL_INTR 0x0200
1597#define ADV_CTRL_REG_DPR_INTR 0x0400
1598#define ADV_CTRL_REG_RTA_INTR 0x0800
1599#define ADV_CTRL_REG_RMA_INTR 0x1000
1600#define ADV_CTRL_REG_RES_BIT14 0x2000
1601#define ADV_CTRL_REG_DPE_INTR 0x4000
1602#define ADV_CTRL_REG_POWER_DONE 0x8000
1603#define ADV_CTRL_REG_ANY_INTR 0xFF00
1604
1605#define ADV_CTRL_REG_CMD_RESET 0x00C6
1606#define ADV_CTRL_REG_CMD_WR_IO_REG 0x00C5
1607#define ADV_CTRL_REG_CMD_RD_IO_REG 0x00C4
1608#define ADV_CTRL_REG_CMD_WR_PCI_CFG_SPACE 0x00C3
1609#define ADV_CTRL_REG_CMD_RD_PCI_CFG_SPACE 0x00C2
1610
1611#define ADV_TICKLE_NOP 0x00
1612#define ADV_TICKLE_A 0x01
1613#define ADV_TICKLE_B 0x02
1614#define ADV_TICKLE_C 0x03
1615
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616#define AdvIsIntPending(port) \
1617 (AdvReadWordRegister(port, IOPW_CTRL_REG) & ADV_CTRL_REG_HOST_INTR)
1618
1619/*
1620 * SCSI_CFG0 Register bit definitions
1621 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001622#define TIMER_MODEAB 0xC000 /* Watchdog, Second, and Select. Timer Ctrl. */
1623#define PARITY_EN 0x2000 /* Enable SCSI Parity Error detection */
1624#define EVEN_PARITY 0x1000 /* Select Even Parity */
1625#define WD_LONG 0x0800 /* Watchdog Interval, 1: 57 min, 0: 13 sec */
1626#define QUEUE_128 0x0400 /* Queue Size, 1: 128 byte, 0: 64 byte */
1627#define PRIM_MODE 0x0100 /* Primitive SCSI mode */
1628#define SCAM_EN 0x0080 /* Enable SCAM selection */
1629#define SEL_TMO_LONG 0x0040 /* Sel/Resel Timeout, 1: 400 ms, 0: 1.6 ms */
1630#define CFRM_ID 0x0020 /* SCAM id sel. confirm., 1: fast, 0: 6.4 ms */
1631#define OUR_ID_EN 0x0010 /* Enable OUR_ID bits */
1632#define OUR_ID 0x000F /* SCSI ID */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633
1634/*
1635 * SCSI_CFG1 Register bit definitions
1636 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001637#define BIG_ENDIAN 0x8000 /* Enable Big Endian Mode MIO:15, EEP:15 */
1638#define TERM_POL 0x2000 /* Terminator Polarity Ctrl. MIO:13, EEP:13 */
1639#define SLEW_RATE 0x1000 /* SCSI output buffer slew rate */
1640#define FILTER_SEL 0x0C00 /* Filter Period Selection */
1641#define FLTR_DISABLE 0x0000 /* Input Filtering Disabled */
1642#define FLTR_11_TO_20NS 0x0800 /* Input Filtering 11ns to 20ns */
1643#define FLTR_21_TO_39NS 0x0C00 /* Input Filtering 21ns to 39ns */
1644#define ACTIVE_DBL 0x0200 /* Disable Active Negation */
1645#define DIFF_MODE 0x0100 /* SCSI differential Mode (Read-Only) */
1646#define DIFF_SENSE 0x0080 /* 1: No SE cables, 0: SE cable (Read-Only) */
1647#define TERM_CTL_SEL 0x0040 /* Enable TERM_CTL_H and TERM_CTL_L */
1648#define TERM_CTL 0x0030 /* External SCSI Termination Bits */
1649#define TERM_CTL_H 0x0020 /* Enable External SCSI Upper Termination */
1650#define TERM_CTL_L 0x0010 /* Enable External SCSI Lower Termination */
1651#define CABLE_DETECT 0x000F /* External SCSI Cable Connection Status */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652
1653/*
1654 * Addendum for ASC-38C0800 Chip
1655 *
1656 * The ASC-38C1600 Chip uses the same definitions except that the
1657 * bus mode override bits [12:10] have been moved to byte register
1658 * offset 0xE (IOPB_SOFT_OVER_WR) bits [12:10]. The [12:10] bits in
1659 * SCSI_CFG1 are read-only and always available. Bit 14 (DIS_TERM_DRV)
1660 * is not needed. The [12:10] bits in IOPB_SOFT_OVER_WR are write-only.
1661 * Also each ASC-38C1600 function or channel uses only cable bits [5:4]
1662 * and [1:0]. Bits [14], [7:6], [3:2] are unused.
1663 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001664#define DIS_TERM_DRV 0x4000 /* 1: Read c_det[3:0], 0: cannot read */
1665#define HVD_LVD_SE 0x1C00 /* Device Detect Bits */
1666#define HVD 0x1000 /* HVD Device Detect */
1667#define LVD 0x0800 /* LVD Device Detect */
1668#define SE 0x0400 /* SE Device Detect */
1669#define TERM_LVD 0x00C0 /* LVD Termination Bits */
1670#define TERM_LVD_HI 0x0080 /* Enable LVD Upper Termination */
1671#define TERM_LVD_LO 0x0040 /* Enable LVD Lower Termination */
1672#define TERM_SE 0x0030 /* SE Termination Bits */
1673#define TERM_SE_HI 0x0020 /* Enable SE Upper Termination */
1674#define TERM_SE_LO 0x0010 /* Enable SE Lower Termination */
1675#define C_DET_LVD 0x000C /* LVD Cable Detect Bits */
1676#define C_DET3 0x0008 /* Cable Detect for LVD External Wide */
1677#define C_DET2 0x0004 /* Cable Detect for LVD Internal Wide */
1678#define C_DET_SE 0x0003 /* SE Cable Detect Bits */
1679#define C_DET1 0x0002 /* Cable Detect for SE Internal Wide */
1680#define C_DET0 0x0001 /* Cable Detect for SE Internal Narrow */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681
1682#define CABLE_ILLEGAL_A 0x7
1683 /* x 0 0 0 | on on | Illegal (all 3 connectors are used) */
1684
1685#define CABLE_ILLEGAL_B 0xB
1686 /* 0 x 0 0 | on on | Illegal (all 3 connectors are used) */
1687
1688/*
1689 * MEM_CFG Register bit definitions
1690 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001691#define BIOS_EN 0x40 /* BIOS Enable MIO:14,EEP:14 */
1692#define FAST_EE_CLK 0x20 /* Diagnostic Bit */
1693#define RAM_SZ 0x1C /* Specify size of RAM to RISC */
1694#define RAM_SZ_2KB 0x00 /* 2 KB */
1695#define RAM_SZ_4KB 0x04 /* 4 KB */
1696#define RAM_SZ_8KB 0x08 /* 8 KB */
1697#define RAM_SZ_16KB 0x0C /* 16 KB */
1698#define RAM_SZ_32KB 0x10 /* 32 KB */
1699#define RAM_SZ_64KB 0x14 /* 64 KB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700
1701/*
1702 * DMA_CFG0 Register bit definitions
1703 *
1704 * This register is only accessible to the host.
1705 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001706#define BC_THRESH_ENB 0x80 /* PCI DMA Start Conditions */
1707#define FIFO_THRESH 0x70 /* PCI DMA FIFO Threshold */
1708#define FIFO_THRESH_16B 0x00 /* 16 bytes */
1709#define FIFO_THRESH_32B 0x20 /* 32 bytes */
1710#define FIFO_THRESH_48B 0x30 /* 48 bytes */
1711#define FIFO_THRESH_64B 0x40 /* 64 bytes */
1712#define FIFO_THRESH_80B 0x50 /* 80 bytes (default) */
1713#define FIFO_THRESH_96B 0x60 /* 96 bytes */
1714#define FIFO_THRESH_112B 0x70 /* 112 bytes */
1715#define START_CTL 0x0C /* DMA start conditions */
1716#define START_CTL_TH 0x00 /* Wait threshold level (default) */
1717#define START_CTL_ID 0x04 /* Wait SDMA/SBUS idle */
1718#define START_CTL_THID 0x08 /* Wait threshold and SDMA/SBUS idle */
1719#define START_CTL_EMFU 0x0C /* Wait SDMA FIFO empty/full */
1720#define READ_CMD 0x03 /* Memory Read Method */
1721#define READ_CMD_MR 0x00 /* Memory Read */
1722#define READ_CMD_MRL 0x02 /* Memory Read Long */
1723#define READ_CMD_MRM 0x03 /* Memory Read Multiple (default) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724
1725/*
1726 * ASC-38C0800 RAM BIST Register bit definitions
1727 */
1728#define RAM_TEST_MODE 0x80
1729#define PRE_TEST_MODE 0x40
1730#define NORMAL_MODE 0x00
1731#define RAM_TEST_DONE 0x10
1732#define RAM_TEST_STATUS 0x0F
1733#define RAM_TEST_HOST_ERROR 0x08
1734#define RAM_TEST_INTRAM_ERROR 0x04
1735#define RAM_TEST_RISC_ERROR 0x02
1736#define RAM_TEST_SCSI_ERROR 0x01
1737#define RAM_TEST_SUCCESS 0x00
1738#define PRE_TEST_VALUE 0x05
1739#define NORMAL_VALUE 0x00
1740
1741/*
1742 * ASC38C1600 Definitions
1743 *
1744 * IOPB_PCI_INT_CFG Bit Field Definitions
1745 */
1746
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001747#define INTAB_LD 0x80 /* Value loaded from EEPROM Bit 11. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748
1749/*
1750 * Bit 1 can be set to change the interrupt for the Function to operate in
1751 * Totem Pole mode. By default Bit 1 is 0 and the interrupt operates in
1752 * Open Drain mode. Both functions of the ASC38C1600 must be set to the same
1753 * mode, otherwise the operating mode is undefined.
1754 */
1755#define TOTEMPOLE 0x02
1756
1757/*
1758 * Bit 0 can be used to change the Int Pin for the Function. The value is
1759 * 0 by default for both Functions with Function 0 using INT A and Function
1760 * B using INT B. For Function 0 if set, INT B is used. For Function 1 if set,
1761 * INT A is used.
1762 *
1763 * EEPROM Word 0 Bit 11 for each Function may change the initial Int Pin
1764 * value specified in the PCI Configuration Space.
1765 */
1766#define INTAB 0x01
1767
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768/*
1769 * Adv Library Status Definitions
1770 */
1771#define ADV_TRUE 1
1772#define ADV_FALSE 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773#define ADV_SUCCESS 1
1774#define ADV_BUSY 0
1775#define ADV_ERROR (-1)
1776
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777/*
1778 * ADV_DVC_VAR 'warn_code' values
1779 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001780#define ASC_WARN_BUSRESET_ERROR 0x0001 /* SCSI Bus Reset error */
1781#define ASC_WARN_EEPROM_CHKSUM 0x0002 /* EEP check sum error */
1782#define ASC_WARN_EEPROM_TERMINATION 0x0004 /* EEP termination bad field */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001783#define ASC_WARN_ERROR 0xFFFF /* ADV_ERROR return */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001785#define ADV_MAX_TID 15 /* max. target identifier */
1786#define ADV_MAX_LUN 7 /* max. logical unit number */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787
1788/*
1789 * Error code values are set in ADV_DVC_VAR 'err_code'.
1790 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001791#define ASC_IERR_WRITE_EEPROM 0x0001 /* write EEPROM error */
1792#define ASC_IERR_MCODE_CHKSUM 0x0002 /* micro code check sum error */
1793#define ASC_IERR_NO_CARRIER 0x0004 /* No more carrier memory. */
1794#define ASC_IERR_START_STOP_CHIP 0x0008 /* start/stop chip failed */
1795#define ASC_IERR_CHIP_VERSION 0x0040 /* wrong chip version */
1796#define ASC_IERR_SET_SCSI_ID 0x0080 /* set SCSI ID failed */
1797#define ASC_IERR_HVD_DEVICE 0x0100 /* HVD attached to LVD connector. */
1798#define ASC_IERR_BAD_SIGNATURE 0x0200 /* signature not found */
1799#define ASC_IERR_ILLEGAL_CONNECTION 0x0400 /* Illegal cable connection */
1800#define ASC_IERR_SINGLE_END_DEVICE 0x0800 /* Single-end used w/differential */
1801#define ASC_IERR_REVERSED_CABLE 0x1000 /* Narrow flat cable reversed */
1802#define ASC_IERR_BIST_PRE_TEST 0x2000 /* BIST pre-test error */
1803#define ASC_IERR_BIST_RAM_TEST 0x4000 /* BIST RAM test error */
1804#define ASC_IERR_BAD_CHIPTYPE 0x8000 /* Invalid 'chip_type' setting. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805
1806/*
1807 * Fixed locations of microcode operating variables.
1808 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001809#define ASC_MC_CODE_BEGIN_ADDR 0x0028 /* microcode start address */
1810#define ASC_MC_CODE_END_ADDR 0x002A /* microcode end address */
1811#define ASC_MC_CODE_CHK_SUM 0x002C /* microcode code checksum */
1812#define ASC_MC_VERSION_DATE 0x0038 /* microcode version */
1813#define ASC_MC_VERSION_NUM 0x003A /* microcode number */
1814#define ASC_MC_BIOSMEM 0x0040 /* BIOS RISC Memory Start */
1815#define ASC_MC_BIOSLEN 0x0050 /* BIOS RISC Memory Length */
1816#define ASC_MC_BIOS_SIGNATURE 0x0058 /* BIOS Signature 0x55AA */
1817#define ASC_MC_BIOS_VERSION 0x005A /* BIOS Version (2 bytes) */
1818#define ASC_MC_SDTR_SPEED1 0x0090 /* SDTR Speed for TID 0-3 */
1819#define ASC_MC_SDTR_SPEED2 0x0092 /* SDTR Speed for TID 4-7 */
1820#define ASC_MC_SDTR_SPEED3 0x0094 /* SDTR Speed for TID 8-11 */
1821#define ASC_MC_SDTR_SPEED4 0x0096 /* SDTR Speed for TID 12-15 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822#define ASC_MC_CHIP_TYPE 0x009A
1823#define ASC_MC_INTRB_CODE 0x009B
1824#define ASC_MC_WDTR_ABLE 0x009C
1825#define ASC_MC_SDTR_ABLE 0x009E
1826#define ASC_MC_TAGQNG_ABLE 0x00A0
1827#define ASC_MC_DISC_ENABLE 0x00A2
1828#define ASC_MC_IDLE_CMD_STATUS 0x00A4
1829#define ASC_MC_IDLE_CMD 0x00A6
1830#define ASC_MC_IDLE_CMD_PARAMETER 0x00A8
1831#define ASC_MC_DEFAULT_SCSI_CFG0 0x00AC
1832#define ASC_MC_DEFAULT_SCSI_CFG1 0x00AE
1833#define ASC_MC_DEFAULT_MEM_CFG 0x00B0
1834#define ASC_MC_DEFAULT_SEL_MASK 0x00B2
1835#define ASC_MC_SDTR_DONE 0x00B6
1836#define ASC_MC_NUMBER_OF_QUEUED_CMD 0x00C0
1837#define ASC_MC_NUMBER_OF_MAX_CMD 0x00D0
1838#define ASC_MC_DEVICE_HSHK_CFG_TABLE 0x0100
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001839#define ASC_MC_CONTROL_FLAG 0x0122 /* Microcode control flag. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840#define ASC_MC_WDTR_DONE 0x0124
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001841#define ASC_MC_CAM_MODE_MASK 0x015E /* CAM mode TID bitmask. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842#define ASC_MC_ICQ 0x0160
1843#define ASC_MC_IRQ 0x0164
1844#define ASC_MC_PPR_ABLE 0x017A
1845
1846/*
1847 * BIOS LRAM variable absolute offsets.
1848 */
1849#define BIOS_CODESEG 0x54
1850#define BIOS_CODELEN 0x56
1851#define BIOS_SIGNATURE 0x58
1852#define BIOS_VERSION 0x5A
1853
1854/*
1855 * Microcode Control Flags
1856 *
1857 * Flags set by the Adv Library in RISC variable 'control_flag' (0x122)
1858 * and handled by the microcode.
1859 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001860#define CONTROL_FLAG_IGNORE_PERR 0x0001 /* Ignore DMA Parity Errors */
1861#define CONTROL_FLAG_ENABLE_AIPP 0x0002 /* Enabled AIPP checking. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862
1863/*
1864 * ASC_MC_DEVICE_HSHK_CFG_TABLE microcode table or HSHK_CFG register format
1865 */
1866#define HSHK_CFG_WIDE_XFR 0x8000
1867#define HSHK_CFG_RATE 0x0F00
1868#define HSHK_CFG_OFFSET 0x001F
1869
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001870#define ASC_DEF_MAX_HOST_QNG 0xFD /* Max. number of host commands (253) */
1871#define ASC_DEF_MIN_HOST_QNG 0x10 /* Min. number of host commands (16) */
1872#define ASC_DEF_MAX_DVC_QNG 0x3F /* Max. number commands per device (63) */
1873#define ASC_DEF_MIN_DVC_QNG 0x04 /* Min. number commands per device (4) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001875#define ASC_QC_DATA_CHECK 0x01 /* Require ASC_QC_DATA_OUT set or clear. */
1876#define ASC_QC_DATA_OUT 0x02 /* Data out DMA transfer. */
1877#define ASC_QC_START_MOTOR 0x04 /* Send auto-start motor before request. */
1878#define ASC_QC_NO_OVERRUN 0x08 /* Don't report overrun. */
1879#define ASC_QC_FREEZE_TIDQ 0x10 /* Freeze TID queue after request. XXX TBD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001881#define ASC_QSC_NO_DISC 0x01 /* Don't allow disconnect for request. */
1882#define ASC_QSC_NO_TAGMSG 0x02 /* Don't allow tag queuing for request. */
1883#define ASC_QSC_NO_SYNC 0x04 /* Don't use Synch. transfer on request. */
1884#define ASC_QSC_NO_WIDE 0x08 /* Don't use Wide transfer on request. */
1885#define ASC_QSC_REDO_DTR 0x10 /* Renegotiate WDTR/SDTR before request. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886/*
1887 * Note: If a Tag Message is to be sent and neither ASC_QSC_HEAD_TAG or
1888 * ASC_QSC_ORDERED_TAG is set, then a Simple Tag Message (0x20) is used.
1889 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001890#define ASC_QSC_HEAD_TAG 0x40 /* Use Head Tag Message (0x21). */
1891#define ASC_QSC_ORDERED_TAG 0x80 /* Use Ordered Tag Message (0x22). */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892
1893/*
1894 * All fields here are accessed by the board microcode and need to be
1895 * little-endian.
1896 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001897typedef struct adv_carr_t {
1898 ADV_VADDR carr_va; /* Carrier Virtual Address */
1899 ADV_PADDR carr_pa; /* Carrier Physical Address */
1900 ADV_VADDR areq_vpa; /* ASC_SCSI_REQ_Q Virtual or Physical Address */
1901 /*
1902 * next_vpa [31:4] Carrier Virtual or Physical Next Pointer
1903 *
1904 * next_vpa [3:1] Reserved Bits
1905 * next_vpa [0] Done Flag set in Response Queue.
1906 */
1907 ADV_VADDR next_vpa;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908} ADV_CARR_T;
1909
1910/*
1911 * Mask used to eliminate low 4 bits of carrier 'next_vpa' field.
1912 */
1913#define ASC_NEXT_VPA_MASK 0xFFFFFFF0
1914
1915#define ASC_RQ_DONE 0x00000001
1916#define ASC_RQ_GOOD 0x00000002
1917#define ASC_CQ_STOPPER 0x00000000
1918
1919#define ASC_GET_CARRP(carrp) ((carrp) & ASC_NEXT_VPA_MASK)
1920
1921#define ADV_CARRIER_NUM_PAGE_CROSSING \
1922 (((ADV_CARRIER_COUNT * sizeof(ADV_CARR_T)) + \
1923 (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
1924
1925#define ADV_CARRIER_BUFSIZE \
1926 ((ADV_CARRIER_COUNT + ADV_CARRIER_NUM_PAGE_CROSSING) * sizeof(ADV_CARR_T))
1927
1928/*
1929 * ASC_SCSI_REQ_Q 'a_flag' definitions
1930 *
1931 * The Adv Library should limit use to the lower nibble (4 bits) of
1932 * a_flag. Drivers are free to use the upper nibble (4 bits) of a_flag.
1933 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001934#define ADV_POLL_REQUEST 0x01 /* poll for request completion */
1935#define ADV_SCSIQ_DONE 0x02 /* request done */
1936#define ADV_DONT_RETRY 0x08 /* don't do retry */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001938#define ADV_CHIP_ASC3550 0x01 /* Ultra-Wide IC */
1939#define ADV_CHIP_ASC38C0800 0x02 /* Ultra2-Wide/LVD IC */
1940#define ADV_CHIP_ASC38C1600 0x03 /* Ultra3-Wide/LVD2 IC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941
1942/*
1943 * Adapter temporary configuration structure
1944 *
1945 * This structure can be discarded after initialization. Don't add
1946 * fields here needed after initialization.
1947 *
1948 * Field naming convention:
1949 *
1950 * *_enable indicates the field enables or disables a feature. The
1951 * value of the field is never reset.
1952 */
1953typedef struct adv_dvc_cfg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001954 ushort disc_enable; /* enable disconnection */
1955 uchar chip_version; /* chip version */
1956 uchar termination; /* Term. Ctrl. bits 6-5 of SCSI_CFG1 register */
1957 ushort lib_version; /* Adv Library version number */
1958 ushort control_flag; /* Microcode Control Flag */
1959 ushort mcode_date; /* Microcode date */
1960 ushort mcode_version; /* Microcode version */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001961 ushort serial1; /* EEPROM serial number word 1 */
1962 ushort serial2; /* EEPROM serial number word 2 */
1963 ushort serial3; /* EEPROM serial number word 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964} ADV_DVC_CFG;
1965
1966struct adv_dvc_var;
1967struct adv_scsi_req_q;
1968
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969/*
1970 * Adapter operation variable structure.
1971 *
1972 * One structure is required per host adapter.
1973 *
1974 * Field naming convention:
1975 *
1976 * *_able indicates both whether a feature should be enabled or disabled
1977 * and whether a device isi capable of the feature. At initialization
1978 * this field may be set, but later if a device is found to be incapable
1979 * of the feature, the field is cleared.
1980 */
1981typedef struct adv_dvc_var {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001982 AdvPortAddr iop_base; /* I/O port address */
1983 ushort err_code; /* fatal error code */
1984 ushort bios_ctrl; /* BIOS control word, EEPROM word 12 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001985 ushort wdtr_able; /* try WDTR for a device */
1986 ushort sdtr_able; /* try SDTR for a device */
1987 ushort ultra_able; /* try SDTR Ultra speed for a device */
1988 ushort sdtr_speed1; /* EEPROM SDTR Speed for TID 0-3 */
1989 ushort sdtr_speed2; /* EEPROM SDTR Speed for TID 4-7 */
1990 ushort sdtr_speed3; /* EEPROM SDTR Speed for TID 8-11 */
1991 ushort sdtr_speed4; /* EEPROM SDTR Speed for TID 12-15 */
1992 ushort tagqng_able; /* try tagged queuing with a device */
1993 ushort ppr_able; /* PPR message capable per TID bitmask. */
1994 uchar max_dvc_qng; /* maximum number of tagged commands per device */
1995 ushort start_motor; /* start motor command allowed */
1996 uchar scsi_reset_wait; /* delay in seconds after scsi bus reset */
1997 uchar chip_no; /* should be assigned by caller */
1998 uchar max_host_qng; /* maximum number of Q'ed command allowed */
1999 uchar irq_no; /* IRQ number */
2000 ushort no_scam; /* scam_tolerant of EEPROM */
2001 struct asc_board *drv_ptr; /* driver pointer to private structure */
2002 uchar chip_scsi_id; /* chip SCSI target ID */
2003 uchar chip_type;
2004 uchar bist_err_code;
2005 ADV_CARR_T *carrier_buf;
2006 ADV_CARR_T *carr_freelist; /* Carrier free list. */
2007 ADV_CARR_T *icq_sp; /* Initiator command queue stopper pointer. */
2008 ADV_CARR_T *irq_sp; /* Initiator response queue stopper pointer. */
2009 ushort carr_pending_cnt; /* Count of pending carriers. */
2010 /*
2011 * Note: The following fields will not be used after initialization. The
2012 * driver may discard the buffer after initialization is done.
2013 */
2014 ADV_DVC_CFG *cfg; /* temporary configuration structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015} ADV_DVC_VAR;
2016
2017#define NO_OF_SG_PER_BLOCK 15
2018
2019typedef struct asc_sg_block {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002020 uchar reserved1;
2021 uchar reserved2;
2022 uchar reserved3;
2023 uchar sg_cnt; /* Valid entries in block. */
2024 ADV_PADDR sg_ptr; /* Pointer to next sg block. */
2025 struct {
2026 ADV_PADDR sg_addr; /* SG element address. */
2027 ADV_DCNT sg_count; /* SG element count. */
2028 } sg_list[NO_OF_SG_PER_BLOCK];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029} ADV_SG_BLOCK;
2030
2031/*
2032 * ADV_SCSI_REQ_Q - microcode request structure
2033 *
2034 * All fields in this structure up to byte 60 are used by the microcode.
2035 * The microcode makes assumptions about the size and ordering of fields
2036 * in this structure. Do not change the structure definition here without
2037 * coordinating the change with the microcode.
2038 *
2039 * All fields accessed by microcode must be maintained in little_endian
2040 * order.
2041 */
2042typedef struct adv_scsi_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002043 uchar cntl; /* Ucode flags and state (ASC_MC_QC_*). */
2044 uchar target_cmd;
2045 uchar target_id; /* Device target identifier. */
2046 uchar target_lun; /* Device target logical unit number. */
2047 ADV_PADDR data_addr; /* Data buffer physical address. */
2048 ADV_DCNT data_cnt; /* Data count. Ucode sets to residual. */
2049 ADV_PADDR sense_addr;
2050 ADV_PADDR carr_pa;
2051 uchar mflag;
2052 uchar sense_len;
2053 uchar cdb_len; /* SCSI CDB length. Must <= 16 bytes. */
2054 uchar scsi_cntl;
2055 uchar done_status; /* Completion status. */
2056 uchar scsi_status; /* SCSI status byte. */
2057 uchar host_status; /* Ucode host status. */
2058 uchar sg_working_ix;
2059 uchar cdb[12]; /* SCSI CDB bytes 0-11. */
2060 ADV_PADDR sg_real_addr; /* SG list physical address. */
2061 ADV_PADDR scsiq_rptr;
2062 uchar cdb16[4]; /* SCSI CDB bytes 12-15. */
2063 ADV_VADDR scsiq_ptr;
2064 ADV_VADDR carr_va;
2065 /*
2066 * End of microcode structure - 60 bytes. The rest of the structure
2067 * is used by the Adv Library and ignored by the microcode.
2068 */
2069 ADV_VADDR srb_ptr;
2070 ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */
2071 char *vdata_addr; /* Data buffer virtual address. */
2072 uchar a_flag;
2073 uchar pad[2]; /* Pad out to a word boundary. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074} ADV_SCSI_REQ_Q;
2075
2076/*
2077 * Microcode idle loop commands
2078 */
2079#define IDLE_CMD_COMPLETED 0
2080#define IDLE_CMD_STOP_CHIP 0x0001
2081#define IDLE_CMD_STOP_CHIP_SEND_INT 0x0002
2082#define IDLE_CMD_SEND_INT 0x0004
2083#define IDLE_CMD_ABORT 0x0008
2084#define IDLE_CMD_DEVICE_RESET 0x0010
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002085#define IDLE_CMD_SCSI_RESET_START 0x0020 /* Assert SCSI Bus Reset */
2086#define IDLE_CMD_SCSI_RESET_END 0x0040 /* Deassert SCSI Bus Reset */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087#define IDLE_CMD_SCSIREQ 0x0080
2088
2089#define IDLE_CMD_STATUS_SUCCESS 0x0001
2090#define IDLE_CMD_STATUS_FAILURE 0x0002
2091
2092/*
2093 * AdvSendIdleCmd() flag definitions.
2094 */
2095#define ADV_NOWAIT 0x01
2096
2097/*
2098 * Wait loop time out values.
2099 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002100#define SCSI_WAIT_100_MSEC 100UL /* 100 milliseconds */
2101#define SCSI_US_PER_MSEC 1000 /* microseconds per millisecond */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002102#define SCSI_MAX_RETRY 10 /* retry count */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002104#define ADV_ASYNC_RDMA_FAILURE 0x01 /* Fatal RDMA failure. */
2105#define ADV_ASYNC_SCSI_BUS_RESET_DET 0x02 /* Detected SCSI Bus Reset. */
2106#define ADV_ASYNC_CARRIER_READY_FAILURE 0x03 /* Carrier Ready failure. */
2107#define ADV_RDMA_IN_CARR_AND_Q_INVALID 0x04 /* RDMAed-in data invalid. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002109#define ADV_HOST_SCSI_BUS_RESET 0x80 /* Host Initiated SCSI Bus Reset. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002111static ADV_PADDR DvcGetPhyAddr(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *,
2112 uchar *, ASC_SDCNT *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113
2114/*
2115 * Adv Library functions available to drivers.
2116 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002117static int AdvExeScsiQueue(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
2118static int AdvISR(ADV_DVC_VAR *);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002119static int AdvInitAsc3550Driver(ADV_DVC_VAR *);
2120static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *);
2121static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *);
2122static int AdvResetChipAndSB(ADV_DVC_VAR *);
2123static int AdvResetSB(ADV_DVC_VAR *asc_dvc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124
2125/*
2126 * Internal Adv Library functions.
2127 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002128static int AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ADV_DCNT);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002129static int AdvInitFrom3550EEP(ADV_DVC_VAR *);
2130static int AdvInitFrom38C0800EEP(ADV_DVC_VAR *);
2131static int AdvInitFrom38C1600EEP(ADV_DVC_VAR *);
2132static ushort AdvGet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
2133static void AdvSet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
2134static ushort AdvGet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
2135static void AdvSet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
2136static ushort AdvGet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
2137static void AdvSet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
2138static void AdvWaitEEPCmd(AdvPortAddr);
2139static ushort AdvReadEEPWord(AdvPortAddr, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141/* Read byte from a register. */
2142#define AdvReadByteRegister(iop_base, reg_off) \
2143 (ADV_MEM_READB((iop_base) + (reg_off)))
2144
2145/* Write byte to a register. */
2146#define AdvWriteByteRegister(iop_base, reg_off, byte) \
2147 (ADV_MEM_WRITEB((iop_base) + (reg_off), (byte)))
2148
2149/* Read word (2 bytes) from a register. */
2150#define AdvReadWordRegister(iop_base, reg_off) \
2151 (ADV_MEM_READW((iop_base) + (reg_off)))
2152
2153/* Write word (2 bytes) to a register. */
2154#define AdvWriteWordRegister(iop_base, reg_off, word) \
2155 (ADV_MEM_WRITEW((iop_base) + (reg_off), (word)))
2156
2157/* Write dword (4 bytes) to a register. */
2158#define AdvWriteDWordRegister(iop_base, reg_off, dword) \
2159 (ADV_MEM_WRITEDW((iop_base) + (reg_off), (dword)))
2160
2161/* Read byte from LRAM. */
2162#define AdvReadByteLram(iop_base, addr, byte) \
2163do { \
2164 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
2165 (byte) = ADV_MEM_READB((iop_base) + IOPB_RAM_DATA); \
2166} while (0)
2167
2168/* Write byte to LRAM. */
2169#define AdvWriteByteLram(iop_base, addr, byte) \
2170 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
2171 ADV_MEM_WRITEB((iop_base) + IOPB_RAM_DATA, (byte)))
2172
2173/* Read word (2 bytes) from LRAM. */
2174#define AdvReadWordLram(iop_base, addr, word) \
2175do { \
2176 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
2177 (word) = (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA)); \
2178} while (0)
2179
2180/* Write word (2 bytes) to LRAM. */
2181#define AdvWriteWordLram(iop_base, addr, word) \
2182 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
2183 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
2184
2185/* Write little-endian double word (4 bytes) to LRAM */
2186/* Because of unspecified C language ordering don't use auto-increment. */
2187#define AdvWriteDWordLramNoSwap(iop_base, addr, dword) \
2188 ((ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
2189 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
2190 cpu_to_le16((ushort) ((dword) & 0xFFFF)))), \
2191 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr) + 2), \
2192 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
2193 cpu_to_le16((ushort) ((dword >> 16) & 0xFFFF)))))
2194
2195/* Read word (2 bytes) from LRAM assuming that the address is already set. */
2196#define AdvReadWordAutoIncLram(iop_base) \
2197 (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA))
2198
2199/* Write word (2 bytes) to LRAM assuming that the address is already set. */
2200#define AdvWriteWordAutoIncLram(iop_base, word) \
2201 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
2202
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203/*
2204 * Define macro to check for Condor signature.
2205 *
2206 * Evaluate to ADV_TRUE if a Condor chip is found the specified port
2207 * address 'iop_base'. Otherwise evalue to ADV_FALSE.
2208 */
2209#define AdvFindSignature(iop_base) \
2210 (((AdvReadByteRegister((iop_base), IOPB_CHIP_ID_1) == \
2211 ADV_CHIP_ID_BYTE) && \
2212 (AdvReadWordRegister((iop_base), IOPW_CHIP_ID_0) == \
2213 ADV_CHIP_ID_WORD)) ? ADV_TRUE : ADV_FALSE)
2214
2215/*
2216 * Define macro to Return the version number of the chip at 'iop_base'.
2217 *
2218 * The second parameter 'bus_type' is currently unused.
2219 */
2220#define AdvGetChipVersion(iop_base, bus_type) \
2221 AdvReadByteRegister((iop_base), IOPB_CHIP_TYPE_REV)
2222
2223/*
2224 * Abort an SRB in the chip's RISC Memory. The 'srb_ptr' argument must
2225 * match the ASC_SCSI_REQ_Q 'srb_ptr' field.
2226 *
2227 * If the request has not yet been sent to the device it will simply be
2228 * aborted from RISC memory. If the request is disconnected it will be
2229 * aborted on reselection by sending an Abort Message to the target ID.
2230 *
2231 * Return value:
2232 * ADV_TRUE(1) - Queue was successfully aborted.
2233 * ADV_FALSE(0) - Queue was not found on the active queue list.
2234 */
2235#define AdvAbortQueue(asc_dvc, scsiq) \
2236 AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_ABORT, \
2237 (ADV_DCNT) (scsiq))
2238
2239/*
2240 * Send a Bus Device Reset Message to the specified target ID.
2241 *
2242 * All outstanding commands will be purged if sending the
2243 * Bus Device Reset Message is successful.
2244 *
2245 * Return Value:
2246 * ADV_TRUE(1) - All requests on the target are purged.
2247 * ADV_FALSE(0) - Couldn't issue Bus Device Reset Message; Requests
2248 * are not purged.
2249 */
2250#define AdvResetDevice(asc_dvc, target_id) \
2251 AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_DEVICE_RESET, \
2252 (ADV_DCNT) (target_id))
2253
2254/*
2255 * SCSI Wide Type definition.
2256 */
2257#define ADV_SCSI_BIT_ID_TYPE ushort
2258
2259/*
2260 * AdvInitScsiTarget() 'cntl_flag' options.
2261 */
2262#define ADV_SCAN_LUN 0x01
2263#define ADV_CAPINFO_NOLUN 0x02
2264
2265/*
2266 * Convert target id to target id bit mask.
2267 */
2268#define ADV_TID_TO_TIDMASK(tid) (0x01 << ((tid) & ADV_MAX_TID))
2269
2270/*
2271 * ASC_SCSI_REQ_Q 'done_status' and 'host_status' return values.
2272 */
2273
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002274#define QD_NO_STATUS 0x00 /* Request not completed yet. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275#define QD_NO_ERROR 0x01
2276#define QD_ABORTED_BY_HOST 0x02
2277#define QD_WITH_ERROR 0x04
2278
2279#define QHSTA_NO_ERROR 0x00
2280#define QHSTA_M_SEL_TIMEOUT 0x11
2281#define QHSTA_M_DATA_OVER_RUN 0x12
2282#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
2283#define QHSTA_M_QUEUE_ABORTED 0x15
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002284#define QHSTA_M_SXFR_SDMA_ERR 0x16 /* SXFR_STATUS SCSI DMA Error */
2285#define QHSTA_M_SXFR_SXFR_PERR 0x17 /* SXFR_STATUS SCSI Bus Parity Error */
2286#define QHSTA_M_RDMA_PERR 0x18 /* RISC PCI DMA parity error */
2287#define QHSTA_M_SXFR_OFF_UFLW 0x19 /* SXFR_STATUS Offset Underflow */
2288#define QHSTA_M_SXFR_OFF_OFLW 0x20 /* SXFR_STATUS Offset Overflow */
2289#define QHSTA_M_SXFR_WD_TMO 0x21 /* SXFR_STATUS Watchdog Timeout */
2290#define QHSTA_M_SXFR_DESELECTED 0x22 /* SXFR_STATUS Deselected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291/* Note: QHSTA_M_SXFR_XFR_OFLW is identical to QHSTA_M_DATA_OVER_RUN. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002292#define QHSTA_M_SXFR_XFR_OFLW 0x12 /* SXFR_STATUS Transfer Overflow */
2293#define QHSTA_M_SXFR_XFR_PH_ERR 0x24 /* SXFR_STATUS Transfer Phase Error */
2294#define QHSTA_M_SXFR_UNKNOWN_ERROR 0x25 /* SXFR_STATUS Unknown Error */
2295#define QHSTA_M_SCSI_BUS_RESET 0x30 /* Request aborted from SBR */
2296#define QHSTA_M_SCSI_BUS_RESET_UNSOL 0x31 /* Request aborted from unsol. SBR */
2297#define QHSTA_M_BUS_DEVICE_RESET 0x32 /* Request aborted from BDR */
2298#define QHSTA_M_DIRECTION_ERR 0x35 /* Data Phase mismatch */
2299#define QHSTA_M_DIRECTION_ERR_HUNG 0x36 /* Data Phase mismatch and bus hang */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300#define QHSTA_M_WTM_TIMEOUT 0x41
2301#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42
2302#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43
2303#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002304#define QHSTA_M_INVALID_DEVICE 0x45 /* Bad target ID */
2305#define QHSTA_M_FROZEN_TIDQ 0x46 /* TID Queue frozen. */
2306#define QHSTA_M_SGBACKUP_ERROR 0x47 /* Scatter-Gather backup error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307
2308/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 * DvcGetPhyAddr() flag arguments
2310 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002311#define ADV_IS_SCSIQ_FLAG 0x01 /* 'addr' is ASC_SCSI_REQ_Q pointer */
2312#define ADV_ASCGETSGLIST_VADDR 0x02 /* 'addr' is AscGetSGList() virtual addr */
2313#define ADV_IS_SENSE_FLAG 0x04 /* 'addr' is sense virtual pointer */
2314#define ADV_IS_DATA_FLAG 0x08 /* 'addr' is data virtual pointer */
2315#define ADV_IS_SGLIST_FLAG 0x10 /* 'addr' is sglist virtual pointer */
2316#define ADV_IS_CARRIER_FLAG 0x20 /* 'addr' is ADV_CARR_T pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317
2318/* Return the address that is aligned at the next doubleword >= to 'addr'. */
2319#define ADV_8BALIGN(addr) (((ulong) (addr) + 0x7) & ~0x7)
2320#define ADV_16BALIGN(addr) (((ulong) (addr) + 0xF) & ~0xF)
2321#define ADV_32BALIGN(addr) (((ulong) (addr) + 0x1F) & ~0x1F)
2322
2323/*
2324 * Total contiguous memory needed for driver SG blocks.
2325 *
2326 * ADV_MAX_SG_LIST must be defined by a driver. It is the maximum
2327 * number of scatter-gather elements the driver supports in a
2328 * single request.
2329 */
2330
2331#define ADV_SG_LIST_MAX_BYTE_SIZE \
2332 (sizeof(ADV_SG_BLOCK) * \
2333 ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK))
2334
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335/* Reference Scsi_Host hostdata */
2336#define ASC_BOARDP(host) ((asc_board_t *) &((host)->hostdata))
2337
2338/* asc_board_t flags */
2339#define ASC_HOST_IN_RESET 0x01
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002340#define ASC_IS_WIDE_BOARD 0x04 /* AdvanSys Wide Board */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341#define ASC_SELECT_QUEUE_DEPTHS 0x08
2342
2343#define ASC_NARROW_BOARD(boardp) (((boardp)->flags & ASC_IS_WIDE_BOARD) == 0)
2344#define ASC_WIDE_BOARD(boardp) ((boardp)->flags & ASC_IS_WIDE_BOARD)
2345
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002346#define NO_ISA_DMA 0xff /* No ISA DMA Channel Used */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002348#define ASC_INFO_SIZE 128 /* advansys_info() line size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349
2350#ifdef CONFIG_PROC_FS
2351/* /proc/scsi/advansys/[0...] related definitions */
2352#define ASC_PRTBUF_SIZE 2048
2353#define ASC_PRTLINE_SIZE 160
2354
2355#define ASC_PRT_NEXT() \
2356 if (cp) { \
2357 totlen += len; \
2358 leftlen -= len; \
2359 if (leftlen == 0) { \
2360 return totlen; \
2361 } \
2362 cp += len; \
2363 }
2364#endif /* CONFIG_PROC_FS */
2365
2366/* Asc Library return codes */
2367#define ASC_TRUE 1
2368#define ASC_FALSE 0
2369#define ASC_NOERROR 1
2370#define ASC_BUSY 0
2371#define ASC_ERROR (-1)
2372
2373/* struct scsi_cmnd function return codes */
2374#define STATUS_BYTE(byte) (byte)
2375#define MSG_BYTE(byte) ((byte) << 8)
2376#define HOST_BYTE(byte) ((byte) << 16)
2377#define DRIVER_BYTE(byte) ((byte) << 24)
2378
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379#ifndef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002380#define ASC_STATS(shost, counter)
2381#define ASC_STATS_ADD(shost, counter, count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382#else /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002383#define ASC_STATS(shost, counter) \
2384 (ASC_BOARDP(shost)->asc_stats.counter++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002386#define ASC_STATS_ADD(shost, counter, count) \
2387 (ASC_BOARDP(shost)->asc_stats.counter += (count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388#endif /* ADVANSYS_STATS */
2389
2390#define ASC_CEILING(val, unit) (((val) + ((unit) - 1))/(unit))
2391
2392/* If the result wraps when calculating tenths, return 0. */
2393#define ASC_TENTHS(num, den) \
2394 (((10 * ((num)/(den))) > (((num) * 10)/(den))) ? \
2395 0 : ((((num) * 10)/(den)) - (10 * ((num)/(den)))))
2396
2397/*
2398 * Display a message to the console.
2399 */
2400#define ASC_PRINT(s) \
2401 { \
2402 printk("advansys: "); \
2403 printk(s); \
2404 }
2405
2406#define ASC_PRINT1(s, a1) \
2407 { \
2408 printk("advansys: "); \
2409 printk((s), (a1)); \
2410 }
2411
2412#define ASC_PRINT2(s, a1, a2) \
2413 { \
2414 printk("advansys: "); \
2415 printk((s), (a1), (a2)); \
2416 }
2417
2418#define ASC_PRINT3(s, a1, a2, a3) \
2419 { \
2420 printk("advansys: "); \
2421 printk((s), (a1), (a2), (a3)); \
2422 }
2423
2424#define ASC_PRINT4(s, a1, a2, a3, a4) \
2425 { \
2426 printk("advansys: "); \
2427 printk((s), (a1), (a2), (a3), (a4)); \
2428 }
2429
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430#ifndef ADVANSYS_DEBUG
2431
2432#define ASC_DBG(lvl, s)
2433#define ASC_DBG1(lvl, s, a1)
2434#define ASC_DBG2(lvl, s, a1, a2)
2435#define ASC_DBG3(lvl, s, a1, a2, a3)
2436#define ASC_DBG4(lvl, s, a1, a2, a3, a4)
2437#define ASC_DBG_PRT_SCSI_HOST(lvl, s)
2438#define ASC_DBG_PRT_SCSI_CMND(lvl, s)
2439#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp)
2440#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
2441#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone)
2442#define ADV_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
2443#define ASC_DBG_PRT_HEX(lvl, name, start, length)
2444#define ASC_DBG_PRT_CDB(lvl, cdb, len)
2445#define ASC_DBG_PRT_SENSE(lvl, sense, len)
2446#define ASC_DBG_PRT_INQUIRY(lvl, inq, len)
2447
2448#else /* ADVANSYS_DEBUG */
2449
2450/*
2451 * Debugging Message Levels:
2452 * 0: Errors Only
2453 * 1: High-Level Tracing
2454 * 2-N: Verbose Tracing
2455 */
2456
2457#define ASC_DBG(lvl, s) \
2458 { \
2459 if (asc_dbglvl >= (lvl)) { \
2460 printk(s); \
2461 } \
2462 }
2463
2464#define ASC_DBG1(lvl, s, a1) \
2465 { \
2466 if (asc_dbglvl >= (lvl)) { \
2467 printk((s), (a1)); \
2468 } \
2469 }
2470
2471#define ASC_DBG2(lvl, s, a1, a2) \
2472 { \
2473 if (asc_dbglvl >= (lvl)) { \
2474 printk((s), (a1), (a2)); \
2475 } \
2476 }
2477
2478#define ASC_DBG3(lvl, s, a1, a2, a3) \
2479 { \
2480 if (asc_dbglvl >= (lvl)) { \
2481 printk((s), (a1), (a2), (a3)); \
2482 } \
2483 }
2484
2485#define ASC_DBG4(lvl, s, a1, a2, a3, a4) \
2486 { \
2487 if (asc_dbglvl >= (lvl)) { \
2488 printk((s), (a1), (a2), (a3), (a4)); \
2489 } \
2490 }
2491
2492#define ASC_DBG_PRT_SCSI_HOST(lvl, s) \
2493 { \
2494 if (asc_dbglvl >= (lvl)) { \
2495 asc_prt_scsi_host(s); \
2496 } \
2497 }
2498
2499#define ASC_DBG_PRT_SCSI_CMND(lvl, s) \
2500 { \
2501 if (asc_dbglvl >= (lvl)) { \
2502 asc_prt_scsi_cmnd(s); \
2503 } \
2504 }
2505
2506#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp) \
2507 { \
2508 if (asc_dbglvl >= (lvl)) { \
2509 asc_prt_asc_scsi_q(scsiqp); \
2510 } \
2511 }
2512
2513#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone) \
2514 { \
2515 if (asc_dbglvl >= (lvl)) { \
2516 asc_prt_asc_qdone_info(qdone); \
2517 } \
2518 }
2519
2520#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp) \
2521 { \
2522 if (asc_dbglvl >= (lvl)) { \
2523 asc_prt_adv_scsi_req_q(scsiqp); \
2524 } \
2525 }
2526
2527#define ASC_DBG_PRT_HEX(lvl, name, start, length) \
2528 { \
2529 if (asc_dbglvl >= (lvl)) { \
2530 asc_prt_hex((name), (start), (length)); \
2531 } \
2532 }
2533
2534#define ASC_DBG_PRT_CDB(lvl, cdb, len) \
2535 ASC_DBG_PRT_HEX((lvl), "CDB", (uchar *) (cdb), (len));
2536
2537#define ASC_DBG_PRT_SENSE(lvl, sense, len) \
2538 ASC_DBG_PRT_HEX((lvl), "SENSE", (uchar *) (sense), (len));
2539
2540#define ASC_DBG_PRT_INQUIRY(lvl, inq, len) \
2541 ASC_DBG_PRT_HEX((lvl), "INQUIRY", (uchar *) (inq), (len));
2542#endif /* ADVANSYS_DEBUG */
2543
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544#ifdef ADVANSYS_STATS
2545
2546/* Per board statistics structure */
2547struct asc_stats {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002548 /* Driver Entrypoint Statistics */
2549 ADV_DCNT queuecommand; /* # calls to advansys_queuecommand() */
2550 ADV_DCNT reset; /* # calls to advansys_eh_bus_reset() */
2551 ADV_DCNT biosparam; /* # calls to advansys_biosparam() */
2552 ADV_DCNT interrupt; /* # advansys_interrupt() calls */
2553 ADV_DCNT callback; /* # calls to asc/adv_isr_callback() */
2554 ADV_DCNT done; /* # calls to request's scsi_done function */
2555 ADV_DCNT build_error; /* # asc/adv_build_req() ASC_ERROR returns. */
2556 ADV_DCNT adv_build_noreq; /* # adv_build_req() adv_req_t alloc. fail. */
2557 ADV_DCNT adv_build_nosg; /* # adv_build_req() adv_sgblk_t alloc. fail. */
2558 /* AscExeScsiQueue()/AdvExeScsiQueue() Statistics */
2559 ADV_DCNT exe_noerror; /* # ASC_NOERROR returns. */
2560 ADV_DCNT exe_busy; /* # ASC_BUSY returns. */
2561 ADV_DCNT exe_error; /* # ASC_ERROR returns. */
2562 ADV_DCNT exe_unknown; /* # unknown returns. */
2563 /* Data Transfer Statistics */
2564 ADV_DCNT cont_cnt; /* # non-scatter-gather I/O requests received */
2565 ADV_DCNT cont_xfer; /* # contiguous transfer 512-bytes */
2566 ADV_DCNT sg_cnt; /* # scatter-gather I/O requests received */
2567 ADV_DCNT sg_elem; /* # scatter-gather elements */
2568 ADV_DCNT sg_xfer; /* # scatter-gather transfer 512-bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569};
2570#endif /* ADVANSYS_STATS */
2571
2572/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 * Adv Library Request Structures
2574 *
2575 * The following two structures are used to process Wide Board requests.
2576 *
2577 * The ADV_SCSI_REQ_Q structure in adv_req_t is passed to the Adv Library
2578 * and microcode with the ADV_SCSI_REQ_Q field 'srb_ptr' pointing to the
2579 * adv_req_t. The adv_req_t structure 'cmndp' field in turn points to the
2580 * Mid-Level SCSI request structure.
2581 *
2582 * Zero or more ADV_SG_BLOCK are used with each ADV_SCSI_REQ_Q. Each
2583 * ADV_SG_BLOCK structure holds 15 scatter-gather elements. Under Linux
2584 * up to 255 scatter-gather elements may be used per request or
2585 * ADV_SCSI_REQ_Q.
2586 *
2587 * Both structures must be 32 byte aligned.
2588 */
2589typedef struct adv_sgblk {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002590 ADV_SG_BLOCK sg_block; /* Sgblock structure. */
2591 uchar align[32]; /* Sgblock structure padding. */
2592 struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593} adv_sgblk_t;
2594
2595typedef struct adv_req {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002596 ADV_SCSI_REQ_Q scsi_req_q; /* Adv Library request structure. */
2597 uchar align[32]; /* Request structure padding. */
2598 struct scsi_cmnd *cmndp; /* Mid-Level SCSI command pointer. */
2599 adv_sgblk_t *sgblkp; /* Adv Library scatter-gather pointer. */
2600 struct adv_req *next_reqp; /* Next Request Structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601} adv_req_t;
2602
2603/*
2604 * Structure allocated for each board.
2605 *
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06002606 * This structure is allocated by scsi_host_alloc() at the end
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 * of the 'Scsi_Host' structure starting at the 'hostdata'
2608 * field. It is guaranteed to be allocated from DMA-able memory.
2609 */
2610typedef struct asc_board {
Matthew Wilcox394dbf32007-07-26 11:56:40 -04002611 struct device *dev;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002612 int id; /* Board Id */
2613 uint flags; /* Board flags */
2614 union {
2615 ASC_DVC_VAR asc_dvc_var; /* Narrow board */
2616 ADV_DVC_VAR adv_dvc_var; /* Wide board */
2617 } dvc_var;
2618 union {
2619 ASC_DVC_CFG asc_dvc_cfg; /* Narrow board */
2620 ADV_DVC_CFG adv_dvc_cfg; /* Wide board */
2621 } dvc_cfg;
2622 ushort asc_n_io_port; /* Number I/O ports. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002623 ADV_SCSI_BIT_ID_TYPE init_tidmask; /* Target init./valid mask */
2624 struct scsi_device *device[ADV_MAX_TID + 1]; /* Mid-Level Scsi Device */
2625 ushort reqcnt[ADV_MAX_TID + 1]; /* Starvation request count */
2626 ADV_SCSI_BIT_ID_TYPE queue_full; /* Queue full mask */
2627 ushort queue_full_cnt[ADV_MAX_TID + 1]; /* Queue full count */
2628 union {
2629 ASCEEP_CONFIG asc_eep; /* Narrow EEPROM config. */
2630 ADVEEP_3550_CONFIG adv_3550_eep; /* 3550 EEPROM config. */
2631 ADVEEP_38C0800_CONFIG adv_38C0800_eep; /* 38C0800 EEPROM config. */
2632 ADVEEP_38C1600_CONFIG adv_38C1600_eep; /* 38C1600 EEPROM config. */
2633 } eep_config;
2634 ulong last_reset; /* Saved last reset time */
2635 spinlock_t lock; /* Board spinlock */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002636 /* /proc/scsi/advansys/[0...] */
2637 char *prtbuf; /* /proc print buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002639 struct asc_stats asc_stats; /* Board statistics */
2640#endif /* ADVANSYS_STATS */
2641 /*
2642 * The following fields are used only for Narrow Boards.
2643 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002644 uchar sdtr_data[ASC_MAX_TID + 1]; /* SDTR information */
2645 /*
2646 * The following fields are used only for Wide Boards.
2647 */
2648 void __iomem *ioremap_addr; /* I/O Memory remap address. */
2649 ushort ioport; /* I/O Port address. */
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -06002650 ADV_CARR_T *carrp; /* ADV_CARR_T memory block. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002651 adv_req_t *orig_reqp; /* adv_req_t memory block. */
2652 adv_req_t *adv_reqp; /* Request structures. */
2653 adv_sgblk_t *adv_sgblkp; /* Scatter-gather structures. */
2654 ushort bios_signature; /* BIOS Signature. */
2655 ushort bios_version; /* BIOS Version. */
2656 ushort bios_codeseg; /* BIOS Code Segment. */
2657 ushort bios_codelen; /* BIOS Code Segment Length. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658} asc_board_t;
2659
Matthew Wilcox13ac2d92007-07-30 08:10:23 -06002660#define adv_dvc_to_board(adv_dvc) container_of(adv_dvc, struct asc_board, \
2661 dvc_var.adv_dvc_var)
2662#define adv_dvc_to_pdev(adv_dvc) to_pci_dev(adv_dvc_to_board(adv_dvc)->dev)
2663
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664/* Number of boards detected in system. */
Matthew Wilcox78e77d82007-07-29 21:46:15 -06002665static int asc_board_count;
2666
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667/* Overrun buffer used by all narrow boards. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002668static uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669
2670/*
2671 * Global structures required to issue a command.
2672 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002673static ASC_SCSI_Q asc_scsi_q = { {0} };
2674static ASC_SG_HEAD asc_sg_head = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002677static int asc_dbglvl = 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678#endif /* ADVANSYS_DEBUG */
2679
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002680static int advansys_slave_configure(struct scsi_device *);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002681static int asc_execute_scsi_cmnd(struct scsi_cmnd *);
2682static int asc_build_req(asc_board_t *, struct scsi_cmnd *);
2683static int adv_build_req(asc_board_t *, struct scsi_cmnd *, ADV_SCSI_REQ_Q **);
2684static int adv_get_sglist(asc_board_t *, adv_req_t *, struct scsi_cmnd *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002686static int asc_proc_copy(off_t, off_t, char *, int, char *, int);
2687static int asc_prt_board_devices(struct Scsi_Host *, char *, int);
2688static int asc_prt_adv_bios(struct Scsi_Host *, char *, int);
2689static int asc_get_eeprom_string(ushort *serialnum, uchar *cp);
2690static int asc_prt_asc_board_eeprom(struct Scsi_Host *, char *, int);
2691static int asc_prt_adv_board_eeprom(struct Scsi_Host *, char *, int);
2692static int asc_prt_driver_conf(struct Scsi_Host *, char *, int);
2693static int asc_prt_asc_board_info(struct Scsi_Host *, char *, int);
2694static int asc_prt_adv_board_info(struct Scsi_Host *, char *, int);
2695static int asc_prt_line(char *, int, char *fmt, ...);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696#endif /* CONFIG_PROC_FS */
2697
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698/* Statistics function prototypes. */
2699#ifdef ADVANSYS_STATS
2700#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002701static int asc_prt_board_stats(struct Scsi_Host *, char *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702#endif /* CONFIG_PROC_FS */
2703#endif /* ADVANSYS_STATS */
2704
2705/* Debug function prototypes. */
2706#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002707static void asc_prt_scsi_host(struct Scsi_Host *);
2708static void asc_prt_scsi_cmnd(struct scsi_cmnd *);
2709static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *);
2710static void asc_prt_asc_dvc_var(ASC_DVC_VAR *);
2711static void asc_prt_asc_scsi_q(ASC_SCSI_Q *);
2712static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *);
2713static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *);
2714static void asc_prt_adv_dvc_var(ADV_DVC_VAR *);
2715static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *);
2716static void asc_prt_adv_sgblock(int, ADV_SG_BLOCK *);
2717static void asc_prt_hex(char *f, uchar *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718#endif /* ADVANSYS_DEBUG */
2719
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720#ifdef CONFIG_PROC_FS
2721/*
Matthew Wilcoxc304ec92007-07-30 09:18:45 -06002722 * advansys_proc_info() - /proc/scsi/advansys/{0,1,2,3,...}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 *
2724 * *buffer: I/O buffer
2725 * **start: if inout == FALSE pointer into buffer where user read should start
2726 * offset: current offset into a /proc/scsi/advansys/[0...] file
2727 * length: length of buffer
2728 * hostno: Scsi_Host host_no
2729 * inout: TRUE - user is writing; FALSE - user is reading
2730 *
2731 * Return the number of bytes read from or written to a
2732 * /proc/scsi/advansys/[0...] file.
2733 *
2734 * Note: This function uses the per board buffer 'prtbuf' which is
2735 * allocated when the board is initialized in advansys_detect(). The
2736 * buffer is ASC_PRTBUF_SIZE bytes. The function asc_proc_copy() is
2737 * used to write to the buffer. The way asc_proc_copy() is written
2738 * if 'prtbuf' is too small it will not be overwritten. Instead the
2739 * user just won't get all the available statistics.
2740 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07002741static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002743 off_t offset, int length, int inout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002745 asc_board_t *boardp;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002746 char *cp;
2747 int cplen;
2748 int cnt;
2749 int totcnt;
2750 int leftlen;
2751 char *curbuf;
2752 off_t advoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002754 ASC_DBG(1, "advansys_proc_info: begin\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002756 /*
2757 * User write not supported.
2758 */
2759 if (inout == TRUE) {
2760 return (-ENOSYS);
2761 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002763 /*
2764 * User read of /proc/scsi/advansys/[0...] file.
2765 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766
Matthew Wilcox2a437952007-07-26 11:00:51 -04002767 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002769 /* Copy read data starting at the beginning of the buffer. */
2770 *start = buffer;
2771 curbuf = buffer;
2772 advoffset = 0;
2773 totcnt = 0;
2774 leftlen = length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002776 /*
2777 * Get board configuration information.
2778 *
2779 * advansys_info() returns the board string from its own static buffer.
2780 */
Matthew Wilcox2a437952007-07-26 11:00:51 -04002781 cp = (char *)advansys_info(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002782 strcat(cp, "\n");
2783 cplen = strlen(cp);
2784 /* Copy board information. */
2785 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
2786 totcnt += cnt;
2787 leftlen -= cnt;
2788 if (leftlen == 0) {
2789 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
2790 return totcnt;
2791 }
2792 advoffset += cplen;
2793 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002795 /*
2796 * Display Wide Board BIOS Information.
2797 */
2798 if (ASC_WIDE_BOARD(boardp)) {
2799 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04002800 cplen = asc_prt_adv_bios(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06002801 BUG_ON(cplen >= ASC_PRTBUF_SIZE);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06002802 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002803 cplen);
2804 totcnt += cnt;
2805 leftlen -= cnt;
2806 if (leftlen == 0) {
2807 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
2808 return totcnt;
2809 }
2810 advoffset += cplen;
2811 curbuf += cnt;
2812 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002814 /*
2815 * Display driver information for each device attached to the board.
2816 */
2817 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04002818 cplen = asc_prt_board_devices(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06002819 BUG_ON(cplen >= ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002820 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
2821 totcnt += cnt;
2822 leftlen -= cnt;
2823 if (leftlen == 0) {
2824 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
2825 return totcnt;
2826 }
2827 advoffset += cplen;
2828 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002830 /*
2831 * Display EEPROM configuration for the board.
2832 */
2833 cp = boardp->prtbuf;
2834 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox2a437952007-07-26 11:00:51 -04002835 cplen = asc_prt_asc_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002836 } else {
Matthew Wilcox2a437952007-07-26 11:00:51 -04002837 cplen = asc_prt_adv_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002838 }
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06002839 BUG_ON(cplen >= ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002840 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
2841 totcnt += cnt;
2842 leftlen -= cnt;
2843 if (leftlen == 0) {
2844 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
2845 return totcnt;
2846 }
2847 advoffset += cplen;
2848 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002850 /*
2851 * Display driver configuration and information for the board.
2852 */
2853 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04002854 cplen = asc_prt_driver_conf(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06002855 BUG_ON(cplen >= ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002856 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
2857 totcnt += cnt;
2858 leftlen -= cnt;
2859 if (leftlen == 0) {
2860 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
2861 return totcnt;
2862 }
2863 advoffset += cplen;
2864 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865
2866#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002867 /*
2868 * Display driver statistics for the board.
2869 */
2870 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04002871 cplen = asc_prt_board_stats(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06002872 BUG_ON(cplen >= ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002873 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
2874 totcnt += cnt;
2875 leftlen -= cnt;
2876 if (leftlen == 0) {
2877 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
2878 return totcnt;
2879 }
2880 advoffset += cplen;
2881 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882#endif /* ADVANSYS_STATS */
2883
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002884 /*
2885 * Display Asc Library dynamic configuration information
2886 * for the board.
2887 */
2888 cp = boardp->prtbuf;
2889 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox2a437952007-07-26 11:00:51 -04002890 cplen = asc_prt_asc_board_info(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002891 } else {
Matthew Wilcox2a437952007-07-26 11:00:51 -04002892 cplen = asc_prt_adv_board_info(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002893 }
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06002894 BUG_ON(cplen >= ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002895 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
2896 totcnt += cnt;
2897 leftlen -= cnt;
2898 if (leftlen == 0) {
2899 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
2900 return totcnt;
2901 }
2902 advoffset += cplen;
2903 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002905 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002907 return totcnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908}
2909#endif /* CONFIG_PROC_FS */
2910
2911/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 * advansys_info()
2913 *
2914 * Return suitable for printing on the console with the argument
2915 * adapter's configuration information.
2916 *
2917 * Note: The information line should not exceed ASC_INFO_SIZE bytes,
2918 * otherwise the static 'info' array will be overrun.
2919 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002920static const char *advansys_info(struct Scsi_Host *shost)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002922 static char info[ASC_INFO_SIZE];
2923 asc_board_t *boardp;
2924 ASC_DVC_VAR *asc_dvc_varp;
2925 ADV_DVC_VAR *adv_dvc_varp;
2926 char *busname;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002927 char *widename = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002929 boardp = ASC_BOARDP(shost);
2930 if (ASC_NARROW_BOARD(boardp)) {
2931 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
2932 ASC_DBG(1, "advansys_info: begin\n");
2933 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
2934 if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) ==
2935 ASC_IS_ISAPNP) {
2936 busname = "ISA PnP";
2937 } else {
2938 busname = "ISA";
2939 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002940 sprintf(info,
2941 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X",
2942 ASC_VERSION, busname,
2943 (ulong)shost->io_port,
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04002944 (ulong)shost->io_port + ASC_IOADR_GAP - 1,
2945 shost->irq, shost->dma_channel);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002946 } else {
2947 if (asc_dvc_varp->bus_type & ASC_IS_VL) {
2948 busname = "VL";
2949 } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
2950 busname = "EISA";
2951 } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
2952 if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
2953 == ASC_IS_PCI_ULTRA) {
2954 busname = "PCI Ultra";
2955 } else {
2956 busname = "PCI";
2957 }
2958 } else {
2959 busname = "?";
Matthew Wilcoxecec1942007-07-30 08:08:22 -06002960 ASC_PRINT2("advansys_info: board %d: unknown "
2961 "bus type %d\n", boardp->id,
2962 asc_dvc_varp->bus_type);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002963 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002964 sprintf(info,
2965 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X",
Matthew Wilcoxecec1942007-07-30 08:08:22 -06002966 ASC_VERSION, busname, (ulong)shost->io_port,
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04002967 (ulong)shost->io_port + ASC_IOADR_GAP - 1,
2968 shost->irq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002969 }
2970 } else {
2971 /*
2972 * Wide Adapter Information
2973 *
2974 * Memory-mapped I/O is used instead of I/O space to access
2975 * the adapter, but display the I/O Port range. The Memory
2976 * I/O address is displayed through the driver /proc file.
2977 */
2978 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
2979 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002980 widename = "Ultra-Wide";
2981 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002982 widename = "Ultra2-Wide";
2983 } else {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002984 widename = "Ultra3-Wide";
2985 }
2986 sprintf(info,
2987 "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X",
2988 ASC_VERSION, widename, (ulong)adv_dvc_varp->iop_base,
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04002989 (ulong)adv_dvc_varp->iop_base + boardp->asc_n_io_port - 1, shost->irq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002990 }
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06002991 BUG_ON(strlen(info) >= ASC_INFO_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002992 ASC_DBG(1, "advansys_info: end\n");
2993 return info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994}
2995
Matthew Wilcox6ed1ef02007-09-09 08:56:33 -06002996static void asc_scsi_done(struct scsi_cmnd *scp)
2997{
2998 struct asc_board *boardp = ASC_BOARDP(scp->device->host);
2999
3000 if (scp->use_sg)
3001 dma_unmap_sg(boardp->dev,
3002 (struct scatterlist *)scp->request_buffer,
3003 scp->use_sg, scp->sc_data_direction);
3004 else if (scp->request_bufflen)
3005 dma_unmap_single(boardp->dev, scp->SCp.dma_handle,
3006 scp->request_bufflen, scp->sc_data_direction);
3007
3008 ASC_STATS(scp->device->host, done);
3009
3010 scp->scsi_done(scp);
3011}
3012
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013/*
3014 * advansys_queuecommand() - interrupt-driven I/O entrypoint.
3015 *
3016 * This function always returns 0. Command return status is saved
3017 * in the 'scp' result field.
3018 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07003019static int
Matthew Wilcoxb2a7a4b2007-09-09 08:56:35 -06003020advansys_queuecommand(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021{
Matthew Wilcoxb2a7a4b2007-09-09 08:56:35 -06003022 struct Scsi_Host *shost = scp->device->host;
3023 asc_board_t *boardp = ASC_BOARDP(shost);
3024 unsigned long flags;
Matthew Wilcoxb6622922007-09-09 08:56:31 -06003025 int asc_res, result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003027 ASC_STATS(shost, queuecommand);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003028 scp->scsi_done = done;
Matthew Wilcoxb2a7a4b2007-09-09 08:56:35 -06003029
3030 /*
3031 * host_lock taken by mid-level prior to call, but need
3032 * to protect against own ISR
3033 */
3034 spin_lock_irqsave(&boardp->lock, flags);
Matthew Wilcoxb6622922007-09-09 08:56:31 -06003035 asc_res = asc_execute_scsi_cmnd(scp);
Matthew Wilcoxb2a7a4b2007-09-09 08:56:35 -06003036 spin_unlock_irqrestore(&boardp->lock, flags);
3037
Matthew Wilcoxb6622922007-09-09 08:56:31 -06003038 switch (asc_res) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003039 case ASC_NOERROR:
3040 break;
3041 case ASC_BUSY:
Matthew Wilcoxb6622922007-09-09 08:56:31 -06003042 result = SCSI_MLQUEUE_HOST_BUSY;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003043 break;
3044 case ASC_ERROR:
3045 default:
Matthew Wilcox6ed1ef02007-09-09 08:56:33 -06003046 asc_scsi_done(scp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003047 break;
3048 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003049
Matthew Wilcoxb6622922007-09-09 08:56:31 -06003050 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051}
3052
3053/*
3054 * advansys_reset()
3055 *
3056 * Reset the bus associated with the command 'scp'.
3057 *
3058 * This function runs its own thread. Interrupts must be blocked but
3059 * sleeping is allowed and no locking other than for host structures is
3060 * required. Returns SUCCESS or FAILED.
3061 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003062static int advansys_reset(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003064 struct Scsi_Host *shost;
3065 asc_board_t *boardp;
3066 ASC_DVC_VAR *asc_dvc_varp;
3067 ADV_DVC_VAR *adv_dvc_varp;
3068 ulong flags;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003069 int status;
3070 int ret = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003072 ASC_DBG1(1, "advansys_reset: 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073
3074#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003075 if (scp->device->host != NULL) {
3076 ASC_STATS(scp->device->host, reset);
3077 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078#endif /* ADVANSYS_STATS */
3079
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003080 if ((shost = scp->device->host) == NULL) {
3081 scp->result = HOST_BYTE(DID_ERROR);
3082 return FAILED;
3083 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003085 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003087 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset started...\n",
3088 boardp->id);
3089 /*
3090 * Check for re-entrancy.
3091 */
3092 spin_lock_irqsave(&boardp->lock, flags);
3093 if (boardp->flags & ASC_HOST_IN_RESET) {
3094 spin_unlock_irqrestore(&boardp->lock, flags);
3095 return FAILED;
3096 }
3097 boardp->flags |= ASC_HOST_IN_RESET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003100 if (ASC_NARROW_BOARD(boardp)) {
3101 /*
3102 * Narrow Board
3103 */
3104 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003106 /*
3107 * Reset the chip and SCSI bus.
3108 */
3109 ASC_DBG(1, "advansys_reset: before AscInitAsc1000Driver()\n");
3110 status = AscInitAsc1000Driver(asc_dvc_varp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003112 /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */
3113 if (asc_dvc_varp->err_code) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003114 ASC_PRINT2("advansys_reset: board %d: SCSI bus reset "
3115 "error: 0x%x\n", boardp->id,
3116 asc_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003117 ret = FAILED;
3118 } else if (status) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003119 ASC_PRINT2("advansys_reset: board %d: SCSI bus reset "
3120 "warning: 0x%x\n", boardp->id, status);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003121 } else {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003122 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset "
3123 "successful.\n", boardp->id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003124 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003126 ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
3127 spin_lock_irqsave(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003129 } else {
3130 /*
3131 * Wide Board
3132 *
3133 * If the suggest reset bus flags are set, then reset the bus.
3134 * Otherwise only reset the device.
3135 */
3136 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003138 /*
3139 * Reset the target's SCSI bus.
3140 */
3141 ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n");
3142 switch (AdvResetChipAndSB(adv_dvc_varp)) {
3143 case ASC_TRUE:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003144 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset "
3145 "successful.\n", boardp->id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003146 break;
3147 case ASC_FALSE:
3148 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003149 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset "
3150 "error.\n", boardp->id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003151 ret = FAILED;
3152 break;
3153 }
3154 spin_lock_irqsave(&boardp->lock, flags);
3155 (void)AdvISR(adv_dvc_varp);
3156 }
3157 /* Board lock is held. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003159 /* Save the time of the most recently completed reset. */
3160 boardp->last_reset = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003162 /* Clear reset flag. */
3163 boardp->flags &= ~ASC_HOST_IN_RESET;
3164 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003166 ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003168 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169}
3170
3171/*
3172 * advansys_biosparam()
3173 *
3174 * Translate disk drive geometry if the "BIOS greater than 1 GB"
3175 * support is enabled for a drive.
3176 *
3177 * ip (information pointer) is an int array with the following definition:
3178 * ip[0]: heads
3179 * ip[1]: sectors
3180 * ip[2]: cylinders
3181 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07003182static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003184 sector_t capacity, int ip[])
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003186 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003188 ASC_DBG(1, "advansys_biosparam: begin\n");
3189 ASC_STATS(sdev->host, biosparam);
3190 boardp = ASC_BOARDP(sdev->host);
3191 if (ASC_NARROW_BOARD(boardp)) {
3192 if ((boardp->dvc_var.asc_dvc_var.dvc_cntl &
3193 ASC_CNTL_BIOS_GT_1GB) && capacity > 0x200000) {
3194 ip[0] = 255;
3195 ip[1] = 63;
3196 } else {
3197 ip[0] = 64;
3198 ip[1] = 32;
3199 }
3200 } else {
3201 if ((boardp->dvc_var.adv_dvc_var.bios_ctrl &
3202 BIOS_CTRL_EXTENDED_XLAT) && capacity > 0x200000) {
3203 ip[0] = 255;
3204 ip[1] = 63;
3205 } else {
3206 ip[0] = 64;
3207 ip[1] = 32;
3208 }
3209 }
3210 ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
3211 ASC_DBG(1, "advansys_biosparam: end\n");
3212 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213}
3214
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06003215static struct scsi_host_template advansys_template = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003216 .proc_name = "advansys",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003218 .proc_info = advansys_proc_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219#endif
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003220 .name = "advansys",
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003221 .info = advansys_info,
3222 .queuecommand = advansys_queuecommand,
3223 .eh_bus_reset_handler = advansys_reset,
3224 .bios_param = advansys_biosparam,
3225 .slave_configure = advansys_slave_configure,
3226 /*
3227 * Because the driver may control an ISA adapter 'unchecked_isa_dma'
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06003228 * must be set. The flag will be cleared in advansys_board_found
3229 * for non-ISA adapters.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003230 */
3231 .unchecked_isa_dma = 1,
3232 /*
3233 * All adapters controlled by this driver are capable of large
3234 * scatter-gather lists. According to the mid-level SCSI documentation
3235 * this obviates any performance gain provided by setting
3236 * 'use_clustering'. But empirically while CPU utilization is increased
3237 * by enabling clustering, I/O throughput increases as well.
3238 */
3239 .use_clustering = ENABLE_CLUSTERING,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243 * First-level interrupt handler.
3244 *
Matthew Wilcox95c9f162007-09-09 08:56:39 -06003245 * 'dev_id' is a pointer to the interrupting adapter's Scsi_Host.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003247static irqreturn_t advansys_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248{
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003249 unsigned long flags;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003250 struct Scsi_Host *shost = dev_id;
3251 asc_board_t *boardp = ASC_BOARDP(shost);
3252 irqreturn_t result = IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003254 ASC_DBG1(2, "advansys_interrupt: boardp 0x%p\n", boardp);
3255 spin_lock_irqsave(&boardp->lock, flags);
3256 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003257 if (AscIsIntPending(shost->io_port)) {
3258 result = IRQ_HANDLED;
3259 ASC_STATS(shost, interrupt);
3260 ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
3261 AscISR(&boardp->dvc_var.asc_dvc_var);
3262 }
3263 } else {
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003264 ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
3265 if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
3266 result = IRQ_HANDLED;
3267 ASC_STATS(shost, interrupt);
3268 }
3269 }
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003270 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003272 ASC_DBG(1, "advansys_interrupt: end\n");
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003273 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003274}
3275
Matthew Wilcox47d853c2007-07-26 11:41:33 -04003276static void
3277advansys_narrow_slave_configure(struct scsi_device *sdev, ASC_DVC_VAR *asc_dvc)
3278{
3279 ASC_SCSI_BIT_ID_TYPE tid_bit = 1 << sdev->id;
3280 ASC_SCSI_BIT_ID_TYPE orig_use_tagged_qng = asc_dvc->use_tagged_qng;
3281
3282 if (sdev->lun == 0) {
3283 ASC_SCSI_BIT_ID_TYPE orig_init_sdtr = asc_dvc->init_sdtr;
3284 if ((asc_dvc->cfg->sdtr_enable & tid_bit) && sdev->sdtr) {
3285 asc_dvc->init_sdtr |= tid_bit;
3286 } else {
3287 asc_dvc->init_sdtr &= ~tid_bit;
3288 }
3289
3290 if (orig_init_sdtr != asc_dvc->init_sdtr)
3291 AscAsyncFix(asc_dvc, sdev);
3292 }
3293
3294 if (sdev->tagged_supported) {
3295 if (asc_dvc->cfg->cmd_qng_enabled & tid_bit) {
3296 if (sdev->lun == 0) {
3297 asc_dvc->cfg->can_tagged_qng |= tid_bit;
3298 asc_dvc->use_tagged_qng |= tid_bit;
3299 }
3300 scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
3301 asc_dvc->max_dvc_qng[sdev->id]);
3302 }
3303 } else {
3304 if (sdev->lun == 0) {
3305 asc_dvc->cfg->can_tagged_qng &= ~tid_bit;
3306 asc_dvc->use_tagged_qng &= ~tid_bit;
3307 }
3308 scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
3309 }
3310
3311 if ((sdev->lun == 0) &&
3312 (orig_use_tagged_qng != asc_dvc->use_tagged_qng)) {
3313 AscWriteLramByte(asc_dvc->iop_base, ASCV_DISC_ENABLE_B,
3314 asc_dvc->cfg->disc_enable);
3315 AscWriteLramByte(asc_dvc->iop_base, ASCV_USE_TAGGED_QNG_B,
3316 asc_dvc->use_tagged_qng);
3317 AscWriteLramByte(asc_dvc->iop_base, ASCV_CAN_TAGGED_QNG_B,
3318 asc_dvc->cfg->can_tagged_qng);
3319
3320 asc_dvc->max_dvc_qng[sdev->id] =
3321 asc_dvc->cfg->max_tag_qng[sdev->id];
3322 AscWriteLramByte(asc_dvc->iop_base,
3323 (ushort)(ASCV_MAX_DVC_QNG_BEG + sdev->id),
3324 asc_dvc->max_dvc_qng[sdev->id]);
3325 }
3326}
3327
3328/*
3329 * Wide Transfers
3330 *
3331 * If the EEPROM enabled WDTR for the device and the device supports wide
3332 * bus (16 bit) transfers, then turn on the device's 'wdtr_able' bit and
3333 * write the new value to the microcode.
3334 */
3335static void
3336advansys_wide_enable_wdtr(AdvPortAddr iop_base, unsigned short tidmask)
3337{
3338 unsigned short cfg_word;
3339 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
3340 if ((cfg_word & tidmask) != 0)
3341 return;
3342
3343 cfg_word |= tidmask;
3344 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
3345
3346 /*
3347 * Clear the microcode SDTR and WDTR negotiation done indicators for
3348 * the target to cause it to negotiate with the new setting set above.
3349 * WDTR when accepted causes the target to enter asynchronous mode, so
3350 * SDTR must be negotiated.
3351 */
3352 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
3353 cfg_word &= ~tidmask;
3354 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
3355 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
3356 cfg_word &= ~tidmask;
3357 AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
3358}
3359
3360/*
3361 * Synchronous Transfers
3362 *
3363 * If the EEPROM enabled SDTR for the device and the device
3364 * supports synchronous transfers, then turn on the device's
3365 * 'sdtr_able' bit. Write the new value to the microcode.
3366 */
3367static void
3368advansys_wide_enable_sdtr(AdvPortAddr iop_base, unsigned short tidmask)
3369{
3370 unsigned short cfg_word;
3371 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
3372 if ((cfg_word & tidmask) != 0)
3373 return;
3374
3375 cfg_word |= tidmask;
3376 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
3377
3378 /*
3379 * Clear the microcode "SDTR negotiation" done indicator for the
3380 * target to cause it to negotiate with the new setting set above.
3381 */
3382 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
3383 cfg_word &= ~tidmask;
3384 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
3385}
3386
3387/*
3388 * PPR (Parallel Protocol Request) Capable
3389 *
3390 * If the device supports DT mode, then it must be PPR capable.
3391 * The PPR message will be used in place of the SDTR and WDTR
3392 * messages to negotiate synchronous speed and offset, transfer
3393 * width, and protocol options.
3394 */
3395static void advansys_wide_enable_ppr(ADV_DVC_VAR *adv_dvc,
3396 AdvPortAddr iop_base, unsigned short tidmask)
3397{
3398 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able);
3399 adv_dvc->ppr_able |= tidmask;
3400 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able);
3401}
3402
3403static void
3404advansys_wide_slave_configure(struct scsi_device *sdev, ADV_DVC_VAR *adv_dvc)
3405{
3406 AdvPortAddr iop_base = adv_dvc->iop_base;
3407 unsigned short tidmask = 1 << sdev->id;
3408
3409 if (sdev->lun == 0) {
3410 /*
3411 * Handle WDTR, SDTR, and Tag Queuing. If the feature
3412 * is enabled in the EEPROM and the device supports the
3413 * feature, then enable it in the microcode.
3414 */
3415
3416 if ((adv_dvc->wdtr_able & tidmask) && sdev->wdtr)
3417 advansys_wide_enable_wdtr(iop_base, tidmask);
3418 if ((adv_dvc->sdtr_able & tidmask) && sdev->sdtr)
3419 advansys_wide_enable_sdtr(iop_base, tidmask);
3420 if (adv_dvc->chip_type == ADV_CHIP_ASC38C1600 && sdev->ppr)
3421 advansys_wide_enable_ppr(adv_dvc, iop_base, tidmask);
3422
3423 /*
3424 * Tag Queuing is disabled for the BIOS which runs in polled
3425 * mode and would see no benefit from Tag Queuing. Also by
3426 * disabling Tag Queuing in the BIOS devices with Tag Queuing
3427 * bugs will at least work with the BIOS.
3428 */
3429 if ((adv_dvc->tagqng_able & tidmask) &&
3430 sdev->tagged_supported) {
3431 unsigned short cfg_word;
3432 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
3433 cfg_word |= tidmask;
3434 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
3435 cfg_word);
3436 AdvWriteByteLram(iop_base,
3437 ASC_MC_NUMBER_OF_MAX_CMD + sdev->id,
3438 adv_dvc->max_dvc_qng);
3439 }
3440 }
3441
3442 if ((adv_dvc->tagqng_able & tidmask) && sdev->tagged_supported) {
3443 scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
3444 adv_dvc->max_dvc_qng);
3445 } else {
3446 scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
3447 }
3448}
3449
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450/*
3451 * Set the number of commands to queue per device for the
3452 * specified host adapter.
3453 */
Matthew Wilcox47d853c2007-07-26 11:41:33 -04003454static int advansys_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455{
Matthew Wilcox47d853c2007-07-26 11:41:33 -04003456 asc_board_t *boardp = ASC_BOARDP(sdev->host);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003457 boardp->flags |= ASC_SELECT_QUEUE_DEPTHS;
Matthew Wilcox47d853c2007-07-26 11:41:33 -04003458
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003459 /*
Matthew Wilcox47d853c2007-07-26 11:41:33 -04003460 * Save a pointer to the sdev and set its initial/maximum
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003461 * queue depth. Only save the pointer for a lun0 dev though.
3462 */
Matthew Wilcox47d853c2007-07-26 11:41:33 -04003463 if (sdev->lun == 0)
3464 boardp->device[sdev->id] = sdev;
3465
3466 if (ASC_NARROW_BOARD(boardp))
3467 advansys_narrow_slave_configure(sdev,
3468 &boardp->dvc_var.asc_dvc_var);
3469 else
3470 advansys_wide_slave_configure(sdev,
3471 &boardp->dvc_var.adv_dvc_var);
3472
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003473 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474}
3475
3476/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477 * Execute a single 'Scsi_Cmnd'.
3478 *
3479 * The function 'done' is called when the request has been completed.
3480 *
3481 * Scsi_Cmnd:
3482 *
3483 * host - board controlling device
3484 * device - device to send command
3485 * target - target of device
3486 * lun - lun of device
3487 * cmd_len - length of SCSI CDB
3488 * cmnd - buffer for SCSI 8, 10, or 12 byte CDB
3489 * use_sg - if non-zero indicates scatter-gather request with use_sg elements
3490 *
3491 * if (use_sg == 0) {
3492 * request_buffer - buffer address for request
3493 * request_bufflen - length of request buffer
3494 * } else {
3495 * request_buffer - pointer to scatterlist structure
3496 * }
3497 *
3498 * sense_buffer - sense command buffer
3499 *
3500 * result (4 bytes of an int):
3501 * Byte Meaning
3502 * 0 SCSI Status Byte Code
3503 * 1 SCSI One Byte Message Code
3504 * 2 Host Error Code
3505 * 3 Mid-Level Error Code
3506 *
3507 * host driver fields:
3508 * SCp - Scsi_Pointer used for command processing status
3509 * scsi_done - used to save caller's done function
3510 * host_scribble - used for pointer to another struct scsi_cmnd
3511 *
Matthew Wilcox349d2c42007-09-09 08:56:34 -06003512 * If this function returns ASC_NOERROR the request will be completed
3513 * from the interrupt handler.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514 *
Matthew Wilcox6ed1ef02007-09-09 08:56:33 -06003515 * If this function returns ASC_ERROR the host error code has been set,
3516 * and the called must call asc_scsi_done.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003517 *
Matthew Wilcoxb6622922007-09-09 08:56:31 -06003518 * If ASC_BUSY is returned the request will be returned to the midlayer
3519 * and re-tried later.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003521static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003523 asc_board_t *boardp;
3524 ASC_DVC_VAR *asc_dvc_varp;
3525 ADV_DVC_VAR *adv_dvc_varp;
3526 ADV_SCSI_REQ_Q *adv_scsiqp;
3527 struct scsi_device *device;
3528 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003530 ASC_DBG2(1, "asc_execute_scsi_cmnd: scp 0x%lx, done 0x%lx\n",
3531 (ulong)scp, (ulong)scp->scsi_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003533 boardp = ASC_BOARDP(scp->device->host);
3534 device = boardp->device[scp->device->id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003536 if (ASC_NARROW_BOARD(boardp)) {
3537 /*
3538 * Build and execute Narrow Board request.
3539 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003540
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003541 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003543 /*
3544 * Build Asc Library request structure using the
3545 * global structures 'asc_scsi_req' and 'asc_sg_head'.
3546 *
3547 * If an error is returned, then the request has been
3548 * queued on the board done queue. It will be completed
3549 * by the caller.
3550 *
3551 * asc_build_req() can not return ASC_BUSY.
3552 */
3553 if (asc_build_req(boardp, scp) == ASC_ERROR) {
3554 ASC_STATS(scp->device->host, build_error);
3555 return ASC_ERROR;
3556 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003558 switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
3559 case ASC_NOERROR:
3560 ASC_STATS(scp->device->host, exe_noerror);
3561 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003562 * Increment monotonically increasing per device
3563 * successful request counter. Wrapping doesn't matter.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003564 */
3565 boardp->reqcnt[scp->device->id]++;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003566 ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue(), "
3567 "ASC_NOERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003568 break;
3569 case ASC_BUSY:
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003570 ASC_STATS(scp->device->host, exe_busy);
3571 break;
3572 case ASC_ERROR:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003573 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
3574 "AscExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
3575 boardp->id, asc_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003576 ASC_STATS(scp->device->host, exe_error);
3577 scp->result = HOST_BYTE(DID_ERROR);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003578 break;
3579 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003580 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
3581 "AscExeScsiQueue() unknown, err_code 0x%x\n",
3582 boardp->id, asc_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003583 ASC_STATS(scp->device->host, exe_unknown);
3584 scp->result = HOST_BYTE(DID_ERROR);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003585 break;
3586 }
3587 } else {
3588 /*
3589 * Build and execute Wide Board request.
3590 */
3591 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003593 /*
3594 * Build and get a pointer to an Adv Library request structure.
3595 *
3596 * If the request is successfully built then send it below,
3597 * otherwise return with an error.
3598 */
3599 switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
3600 case ASC_NOERROR:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003601 ASC_DBG(3, "asc_execute_scsi_cmnd: adv_build_req "
3602 "ASC_NOERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003603 break;
3604 case ASC_BUSY:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003605 ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req "
3606 "ASC_BUSY\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003607 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003608 * The asc_stats fields 'adv_build_noreq' and
3609 * 'adv_build_nosg' count wide board busy conditions.
3610 * They are updated in adv_build_req and
3611 * adv_get_sglist, respectively.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003612 */
3613 return ASC_BUSY;
3614 case ASC_ERROR:
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003615 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003616 ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req "
3617 "ASC_ERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003618 ASC_STATS(scp->device->host, build_error);
3619 return ASC_ERROR;
3620 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003622 switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) {
3623 case ASC_NOERROR:
3624 ASC_STATS(scp->device->host, exe_noerror);
3625 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003626 * Increment monotonically increasing per device
3627 * successful request counter. Wrapping doesn't matter.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003628 */
3629 boardp->reqcnt[scp->device->id]++;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003630 ASC_DBG(1, "asc_execute_scsi_cmnd: AdvExeScsiQueue(), "
3631 "ASC_NOERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003632 break;
3633 case ASC_BUSY:
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003634 ASC_STATS(scp->device->host, exe_busy);
3635 break;
3636 case ASC_ERROR:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003637 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
3638 "AdvExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
3639 boardp->id, adv_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003640 ASC_STATS(scp->device->host, exe_error);
3641 scp->result = HOST_BYTE(DID_ERROR);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003642 break;
3643 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003644 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
3645 "AdvExeScsiQueue() unknown, err_code 0x%x\n",
3646 boardp->id, adv_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003647 ASC_STATS(scp->device->host, exe_unknown);
3648 scp->result = HOST_BYTE(DID_ERROR);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003649 break;
3650 }
3651 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003652
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003653 ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
3654 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655}
3656
3657/*
3658 * Build a request structure for the Asc Library (Narrow Board).
3659 *
3660 * The global structures 'asc_scsi_q' and 'asc_sg_head' are
3661 * used to build the request.
3662 *
Matthew Wilcox6ed1ef02007-09-09 08:56:33 -06003663 * If an error occurs, then return ASC_ERROR.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003665static int asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003667 /*
3668 * Mutually exclusive access is required to 'asc_scsi_q' and
3669 * 'asc_sg_head' until after the request is started.
3670 */
3671 memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003672
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003673 /*
3674 * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'.
3675 */
3676 asc_scsi_q.q2.srb_ptr = ASC_VADDR_TO_U32(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003678 /*
3679 * Build the ASC_SCSI_Q request.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003680 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003681 asc_scsi_q.cdbptr = &scp->cmnd[0];
3682 asc_scsi_q.q2.cdb_len = scp->cmd_len;
3683 asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id);
3684 asc_scsi_q.q1.target_lun = scp->device->lun;
3685 asc_scsi_q.q2.target_ix =
3686 ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
3687 asc_scsi_q.q1.sense_addr =
3688 cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
3689 asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003690
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003691 /*
3692 * If there are any outstanding requests for the current target,
3693 * then every 255th request send an ORDERED request. This heuristic
3694 * tries to retain the benefit of request sorting while preventing
3695 * request starvation. 255 is the max number of tags or pending commands
3696 * a device may have outstanding.
3697 *
3698 * The request count is incremented below for every successfully
3699 * started request.
3700 *
3701 */
3702 if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->device->id] > 0) &&
3703 (boardp->reqcnt[scp->device->id] % 255) == 0) {
3704 asc_scsi_q.q2.tag_code = MSG_ORDERED_TAG;
3705 } else {
3706 asc_scsi_q.q2.tag_code = MSG_SIMPLE_TAG;
3707 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003709 /*
3710 * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
3711 * buffer command.
3712 */
3713 if (scp->use_sg == 0) {
3714 /*
3715 * CDB request of single contiguous buffer.
3716 */
3717 ASC_STATS(scp->device->host, cont_cnt);
3718 scp->SCp.dma_handle = scp->request_bufflen ?
Matthew Wilcox394dbf32007-07-26 11:56:40 -04003719 dma_map_single(boardp->dev, scp->request_buffer,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003720 scp->request_bufflen,
3721 scp->sc_data_direction) : 0;
3722 asc_scsi_q.q1.data_addr = cpu_to_le32(scp->SCp.dma_handle);
3723 asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen);
3724 ASC_STATS_ADD(scp->device->host, cont_xfer,
3725 ASC_CEILING(scp->request_bufflen, 512));
3726 asc_scsi_q.q1.sg_queue_cnt = 0;
3727 asc_scsi_q.sg_head = NULL;
3728 } else {
3729 /*
3730 * CDB scatter-gather request list.
3731 */
3732 int sgcnt;
3733 int use_sg;
3734 struct scatterlist *slp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003736 slp = (struct scatterlist *)scp->request_buffer;
Matthew Wilcox394dbf32007-07-26 11:56:40 -04003737 use_sg = dma_map_sg(boardp->dev, slp, scp->use_sg,
3738 scp->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003739
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003740 if (use_sg > scp->device->host->sg_tablesize) {
Matthew Wilcox394dbf32007-07-26 11:56:40 -04003741 ASC_PRINT3("asc_build_req: board %d: use_sg %d > "
3742 "sg_tablesize %d\n", boardp->id, use_sg,
3743 scp->device->host->sg_tablesize);
3744 dma_unmap_sg(boardp->dev, slp, scp->use_sg,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003745 scp->sc_data_direction);
3746 scp->result = HOST_BYTE(DID_ERROR);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003747 return ASC_ERROR;
3748 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003749
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003750 ASC_STATS(scp->device->host, sg_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003752 /*
3753 * Use global ASC_SG_HEAD structure and set the ASC_SCSI_Q
3754 * structure to point to it.
3755 */
3756 memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003758 asc_scsi_q.q1.cntl |= QC_SG_HEAD;
3759 asc_scsi_q.sg_head = &asc_sg_head;
3760 asc_scsi_q.q1.data_cnt = 0;
3761 asc_scsi_q.q1.data_addr = 0;
3762 /* This is a byte value, otherwise it would need to be swapped. */
3763 asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = use_sg;
3764 ASC_STATS_ADD(scp->device->host, sg_elem,
3765 asc_sg_head.entry_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003766
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003767 /*
3768 * Convert scatter-gather list into ASC_SG_HEAD list.
3769 */
3770 for (sgcnt = 0; sgcnt < use_sg; sgcnt++, slp++) {
3771 asc_sg_head.sg_list[sgcnt].addr =
3772 cpu_to_le32(sg_dma_address(slp));
3773 asc_sg_head.sg_list[sgcnt].bytes =
3774 cpu_to_le32(sg_dma_len(slp));
3775 ASC_STATS_ADD(scp->device->host, sg_xfer,
3776 ASC_CEILING(sg_dma_len(slp), 512));
3777 }
3778 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003779
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003780 ASC_DBG_PRT_ASC_SCSI_Q(2, &asc_scsi_q);
3781 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003783 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003784}
3785
3786/*
3787 * Build a request structure for the Adv Library (Wide Board).
3788 *
3789 * If an adv_req_t can not be allocated to issue the request,
3790 * then return ASC_BUSY. If an error occurs, then return ASC_ERROR.
3791 *
3792 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the
3793 * microcode for DMA addresses or math operations are byte swapped
3794 * to little-endian order.
3795 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003796static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003797adv_build_req(asc_board_t *boardp, struct scsi_cmnd *scp,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003798 ADV_SCSI_REQ_Q **adv_scsiqpp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003800 adv_req_t *reqp;
3801 ADV_SCSI_REQ_Q *scsiqp;
3802 int i;
3803 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003804
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003805 /*
3806 * Allocate an adv_req_t structure from the board to execute
3807 * the command.
3808 */
3809 if (boardp->adv_reqp == NULL) {
3810 ASC_DBG(1, "adv_build_req: no free adv_req_t\n");
3811 ASC_STATS(scp->device->host, adv_build_noreq);
3812 return ASC_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003813 } else {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003814 reqp = boardp->adv_reqp;
3815 boardp->adv_reqp = reqp->next_reqp;
3816 reqp->next_reqp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003818
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003819 /*
3820 * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
3821 */
3822 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003823
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003824 /*
3825 * Initialize the structure.
3826 */
3827 scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003829 /*
3830 * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
3831 */
3832 scsiqp->srb_ptr = ASC_VADDR_TO_U32(reqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003834 /*
3835 * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure.
3836 */
3837 reqp->cmndp = scp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003839 /*
3840 * Build the ADV_SCSI_REQ_Q request.
3841 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003842
Matthew Wilcoxf05ec592007-09-09 08:56:36 -06003843 /* Set CDB length and copy it to the request structure. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003844 scsiqp->cdb_len = scp->cmd_len;
3845 /* Copy first 12 CDB bytes to cdb[]. */
3846 for (i = 0; i < scp->cmd_len && i < 12; i++) {
3847 scsiqp->cdb[i] = scp->cmnd[i];
3848 }
3849 /* Copy last 4 CDB bytes, if present, to cdb16[]. */
3850 for (; i < scp->cmd_len; i++) {
3851 scsiqp->cdb16[i - 12] = scp->cmnd[i];
3852 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003853
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003854 scsiqp->target_id = scp->device->id;
3855 scsiqp->target_lun = scp->device->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003857 scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
3858 scsiqp->sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003859
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003860 /*
3861 * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather
3862 * buffer command.
3863 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003864
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003865 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
3866 scsiqp->vdata_addr = scp->request_buffer;
3867 scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer));
3868
3869 if (scp->use_sg == 0) {
3870 /*
3871 * CDB request of single contiguous buffer.
3872 */
3873 reqp->sgblkp = NULL;
3874 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
3875 if (scp->request_bufflen) {
3876 scsiqp->vdata_addr = scp->request_buffer;
3877 scp->SCp.dma_handle =
Matthew Wilcox394dbf32007-07-26 11:56:40 -04003878 dma_map_single(boardp->dev, scp->request_buffer,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003879 scp->request_bufflen,
3880 scp->sc_data_direction);
3881 } else {
3882 scsiqp->vdata_addr = NULL;
3883 scp->SCp.dma_handle = 0;
3884 }
3885 scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle);
3886 scsiqp->sg_list_ptr = NULL;
3887 scsiqp->sg_real_addr = 0;
3888 ASC_STATS(scp->device->host, cont_cnt);
3889 ASC_STATS_ADD(scp->device->host, cont_xfer,
3890 ASC_CEILING(scp->request_bufflen, 512));
3891 } else {
3892 /*
3893 * CDB scatter-gather request list.
3894 */
3895 struct scatterlist *slp;
3896 int use_sg;
3897
3898 slp = (struct scatterlist *)scp->request_buffer;
Matthew Wilcox394dbf32007-07-26 11:56:40 -04003899 use_sg = dma_map_sg(boardp->dev, slp, scp->use_sg,
3900 scp->sc_data_direction);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003901
3902 if (use_sg > ADV_MAX_SG_LIST) {
Matthew Wilcox394dbf32007-07-26 11:56:40 -04003903 ASC_PRINT3("adv_build_req: board %d: use_sg %d > "
3904 "ADV_MAX_SG_LIST %d\n", boardp->id, use_sg,
3905 scp->device->host->sg_tablesize);
3906 dma_unmap_sg(boardp->dev, slp, scp->use_sg,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003907 scp->sc_data_direction);
3908 scp->result = HOST_BYTE(DID_ERROR);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003909
3910 /*
Matthew Wilcox394dbf32007-07-26 11:56:40 -04003911 * Free the 'adv_req_t' structure by adding it back
3912 * to the board free list.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003913 */
3914 reqp->next_reqp = boardp->adv_reqp;
3915 boardp->adv_reqp = reqp;
3916
3917 return ASC_ERROR;
3918 }
3919
Matthew Wilcox394dbf32007-07-26 11:56:40 -04003920 ret = adv_get_sglist(boardp, reqp, scp, use_sg);
3921 if (ret != ADV_SUCCESS) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003922 /*
Matthew Wilcox394dbf32007-07-26 11:56:40 -04003923 * Free the adv_req_t structure by adding it back to
3924 * the board free list.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003925 */
3926 reqp->next_reqp = boardp->adv_reqp;
3927 boardp->adv_reqp = reqp;
3928
3929 return ret;
3930 }
3931
3932 ASC_STATS(scp->device->host, sg_cnt);
3933 ASC_STATS_ADD(scp->device->host, sg_elem, use_sg);
3934 }
3935
3936 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
3937 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
3938
3939 *adv_scsiqpp = scsiqp;
3940
3941 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003942}
3943
3944/*
3945 * Build scatter-gather list for Adv Library (Wide Board).
3946 *
3947 * Additional ADV_SG_BLOCK structures will need to be allocated
3948 * if the total number of scatter-gather elements exceeds
3949 * NO_OF_SG_PER_BLOCK (15). The ADV_SG_BLOCK structures are
3950 * assumed to be physically contiguous.
3951 *
3952 * Return:
3953 * ADV_SUCCESS(1) - SG List successfully created
3954 * ADV_ERROR(-1) - SG List creation failed
3955 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003956static int
3957adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, struct scsi_cmnd *scp,
3958 int use_sg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003960 adv_sgblk_t *sgblkp;
3961 ADV_SCSI_REQ_Q *scsiqp;
3962 struct scatterlist *slp;
3963 int sg_elem_cnt;
3964 ADV_SG_BLOCK *sg_block, *prev_sg_block;
3965 ADV_PADDR sg_block_paddr;
3966 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003968 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
3969 slp = (struct scatterlist *)scp->request_buffer;
3970 sg_elem_cnt = use_sg;
3971 prev_sg_block = NULL;
3972 reqp->sgblkp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973
Matthew Wilcox95c9f162007-09-09 08:56:39 -06003974 for (;;) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003975 /*
3976 * Allocate a 'adv_sgblk_t' structure from the board free
3977 * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK
3978 * (15) scatter-gather elements.
3979 */
3980 if ((sgblkp = boardp->adv_sgblkp) == NULL) {
3981 ASC_DBG(1, "adv_get_sglist: no free adv_sgblk_t\n");
3982 ASC_STATS(scp->device->host, adv_build_nosg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003984 /*
Matthew Wilcox95c9f162007-09-09 08:56:39 -06003985 * Allocation failed. Free 'adv_sgblk_t' structures
3986 * already allocated for the request.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003987 */
3988 while ((sgblkp = reqp->sgblkp) != NULL) {
3989 /* Remove 'sgblkp' from the request list. */
3990 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003992 /* Add 'sgblkp' to the board free list. */
3993 sgblkp->next_sgblkp = boardp->adv_sgblkp;
3994 boardp->adv_sgblkp = sgblkp;
3995 }
3996 return ASC_BUSY;
Matthew Wilcox95c9f162007-09-09 08:56:39 -06003997 }
3998
3999 /* Complete 'adv_sgblk_t' board allocation. */
4000 boardp->adv_sgblkp = sgblkp->next_sgblkp;
4001 sgblkp->next_sgblkp = NULL;
4002
4003 /*
4004 * Get 8 byte aligned virtual and physical addresses
4005 * for the allocated ADV_SG_BLOCK structure.
4006 */
4007 sg_block = (ADV_SG_BLOCK *)ADV_8BALIGN(&sgblkp->sg_block);
4008 sg_block_paddr = virt_to_bus(sg_block);
4009
4010 /*
4011 * Check if this is the first 'adv_sgblk_t' for the
4012 * request.
4013 */
4014 if (reqp->sgblkp == NULL) {
4015 /* Request's first scatter-gather block. */
4016 reqp->sgblkp = sgblkp;
4017
4018 /*
4019 * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical
4020 * address pointers.
4021 */
4022 scsiqp->sg_list_ptr = sg_block;
4023 scsiqp->sg_real_addr = cpu_to_le32(sg_block_paddr);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004024 } else {
Matthew Wilcox95c9f162007-09-09 08:56:39 -06004025 /* Request's second or later scatter-gather block. */
4026 sgblkp->next_sgblkp = reqp->sgblkp;
4027 reqp->sgblkp = sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004029 /*
Matthew Wilcox95c9f162007-09-09 08:56:39 -06004030 * Point the previous ADV_SG_BLOCK structure to
4031 * the newly allocated ADV_SG_BLOCK structure.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004032 */
Matthew Wilcox95c9f162007-09-09 08:56:39 -06004033 prev_sg_block->sg_ptr = cpu_to_le32(sg_block_paddr);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004034 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004035
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004036 for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) {
4037 sg_block->sg_list[i].sg_addr =
Matthew Wilcox95c9f162007-09-09 08:56:39 -06004038 cpu_to_le32(sg_dma_address(slp));
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004039 sg_block->sg_list[i].sg_count =
Matthew Wilcox95c9f162007-09-09 08:56:39 -06004040 cpu_to_le32(sg_dma_len(slp));
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004041 ASC_STATS_ADD(scp->device->host, sg_xfer,
4042 ASC_CEILING(sg_dma_len(slp), 512));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004044 if (--sg_elem_cnt == 0) { /* Last ADV_SG_BLOCK and scatter-gather entry. */
4045 sg_block->sg_cnt = i + 1;
4046 sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */
4047 return ADV_SUCCESS;
4048 }
4049 slp++;
4050 }
4051 sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
4052 prev_sg_block = sg_block;
4053 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054}
4055
4056/*
4057 * asc_isr_callback() - Second Level Interrupt Handler called by AscISR().
4058 *
4059 * Interrupt callback function for the Narrow SCSI Asc Library.
4060 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004061static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004062{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004063 asc_board_t *boardp;
4064 struct scsi_cmnd *scp;
4065 struct Scsi_Host *shost;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004066
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004067 ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp 0x%lx, qdonep 0x%lx\n",
4068 (ulong)asc_dvc_varp, (ulong)qdonep);
4069 ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004070
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004071 /*
4072 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
4073 * command that has been completed.
4074 */
4075 scp = (struct scsi_cmnd *)ASC_U32_TO_VADDR(qdonep->d2.srb_ptr);
4076 ASC_DBG1(1, "asc_isr_callback: scp 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004077
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004078 if (scp == NULL) {
4079 ASC_PRINT("asc_isr_callback: scp is NULL\n");
4080 return;
4081 }
4082 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004083
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004084 shost = scp->device->host;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004085 ASC_STATS(shost, callback);
4086 ASC_DBG1(1, "asc_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004087
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004088 boardp = ASC_BOARDP(shost);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06004089 BUG_ON(asc_dvc_varp != &boardp->dvc_var.asc_dvc_var);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004090
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004091 /*
4092 * 'qdonep' contains the command's ending status.
4093 */
4094 switch (qdonep->d3.done_stat) {
4095 case QD_NO_ERROR:
4096 ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n");
4097 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004098
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004099 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004100 * Check for an underrun condition.
4101 *
4102 * If there was no error and an underrun condition, then
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004103 * return the number of underrun bytes.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004104 */
4105 if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 &&
4106 qdonep->remain_bytes <= scp->request_bufflen) {
4107 ASC_DBG1(1,
4108 "asc_isr_callback: underrun condition %u bytes\n",
4109 (unsigned)qdonep->remain_bytes);
4110 scp->resid = qdonep->remain_bytes;
4111 }
4112 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004113
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004114 case QD_WITH_ERROR:
4115 ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n");
4116 switch (qdonep->d3.host_stat) {
4117 case QHSTA_NO_ERROR:
4118 if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
4119 ASC_DBG(2,
4120 "asc_isr_callback: SAM_STAT_CHECK_CONDITION\n");
4121 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
4122 sizeof(scp->sense_buffer));
4123 /*
Matthew Wilcox95c9f162007-09-09 08:56:39 -06004124 * Note: The 'status_byte()' macro used by
4125 * target drivers defined in scsi.h shifts the
4126 * status byte returned by host drivers right
4127 * by 1 bit. This is why target drivers also
4128 * use right shifted status byte definitions.
4129 * For instance target drivers use
4130 * CHECK_CONDITION, defined to 0x1, instead of
4131 * the SCSI defined check condition value of
4132 * 0x2. Host drivers are supposed to return
4133 * the status byte as it is defined by SCSI.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004134 */
4135 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
4136 STATUS_BYTE(qdonep->d3.scsi_stat);
4137 } else {
4138 scp->result = STATUS_BYTE(qdonep->d3.scsi_stat);
4139 }
4140 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004142 default:
4143 /* QHSTA error occurred */
4144 ASC_DBG1(1, "asc_isr_callback: host_stat 0x%x\n",
4145 qdonep->d3.host_stat);
4146 scp->result = HOST_BYTE(DID_BAD_TARGET);
4147 break;
4148 }
4149 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004151 case QD_ABORTED_BY_HOST:
4152 ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOST\n");
4153 scp->result =
4154 HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.
4155 scsi_msg) |
4156 STATUS_BYTE(qdonep->d3.scsi_stat);
4157 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004158
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004159 default:
4160 ASC_DBG1(1, "asc_isr_callback: done_stat 0x%x\n",
4161 qdonep->d3.done_stat);
4162 scp->result =
4163 HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.
4164 scsi_msg) |
4165 STATUS_BYTE(qdonep->d3.scsi_stat);
4166 break;
4167 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004169 /*
4170 * If the 'init_tidmask' bit isn't already set for the target and the
4171 * current request finished normally, then set the bit for the target
4172 * to indicate that a device is present.
4173 */
4174 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
4175 qdonep->d3.done_stat == QD_NO_ERROR &&
4176 qdonep->d3.host_stat == QHSTA_NO_ERROR) {
4177 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
4178 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004179
Matthew Wilcox6ed1ef02007-09-09 08:56:33 -06004180 asc_scsi_done(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004182 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004183}
4184
4185/*
4186 * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR().
4187 *
4188 * Callback function for the Wide SCSI Adv Library.
4189 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004190static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004192 asc_board_t *boardp;
4193 adv_req_t *reqp;
4194 adv_sgblk_t *sgblkp;
4195 struct scsi_cmnd *scp;
4196 struct Scsi_Host *shost;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004197 ADV_DCNT resid_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004198
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004199 ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp 0x%lx, scsiqp 0x%lx\n",
4200 (ulong)adv_dvc_varp, (ulong)scsiqp);
4201 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004202
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004203 /*
4204 * Get the adv_req_t structure for the command that has been
4205 * completed. The adv_req_t structure actually contains the
4206 * completed ADV_SCSI_REQ_Q structure.
4207 */
4208 reqp = (adv_req_t *)ADV_U32_TO_VADDR(scsiqp->srb_ptr);
4209 ASC_DBG1(1, "adv_isr_callback: reqp 0x%lx\n", (ulong)reqp);
4210 if (reqp == NULL) {
4211 ASC_PRINT("adv_isr_callback: reqp is NULL\n");
4212 return;
4213 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004214
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004215 /*
4216 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
4217 * command that has been completed.
4218 *
4219 * Note: The adv_req_t request structure and adv_sgblk_t structure,
4220 * if any, are dropped, because a board structure pointer can not be
4221 * determined.
4222 */
4223 scp = reqp->cmndp;
4224 ASC_DBG1(1, "adv_isr_callback: scp 0x%lx\n", (ulong)scp);
4225 if (scp == NULL) {
4226 ASC_PRINT
4227 ("adv_isr_callback: scp is NULL; adv_req_t dropped.\n");
4228 return;
4229 }
4230 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004232 shost = scp->device->host;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004233 ASC_STATS(shost, callback);
4234 ASC_DBG1(1, "adv_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004235
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004236 boardp = ASC_BOARDP(shost);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06004237 BUG_ON(adv_dvc_varp != &boardp->dvc_var.adv_dvc_var);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004238
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004239 /*
4240 * 'done_status' contains the command's ending status.
4241 */
4242 switch (scsiqp->done_status) {
4243 case QD_NO_ERROR:
4244 ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n");
4245 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004247 /*
4248 * Check for an underrun condition.
4249 *
4250 * If there was no error and an underrun condition, then
4251 * then return the number of underrun bytes.
4252 */
4253 resid_cnt = le32_to_cpu(scsiqp->data_cnt);
4254 if (scp->request_bufflen != 0 && resid_cnt != 0 &&
4255 resid_cnt <= scp->request_bufflen) {
4256 ASC_DBG1(1,
4257 "adv_isr_callback: underrun condition %lu bytes\n",
4258 (ulong)resid_cnt);
4259 scp->resid = resid_cnt;
4260 }
4261 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004263 case QD_WITH_ERROR:
4264 ASC_DBG(2, "adv_isr_callback: QD_WITH_ERROR\n");
4265 switch (scsiqp->host_status) {
4266 case QHSTA_NO_ERROR:
4267 if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
4268 ASC_DBG(2,
4269 "adv_isr_callback: SAM_STAT_CHECK_CONDITION\n");
4270 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
4271 sizeof(scp->sense_buffer));
4272 /*
Matthew Wilcox95c9f162007-09-09 08:56:39 -06004273 * Note: The 'status_byte()' macro used by
4274 * target drivers defined in scsi.h shifts the
4275 * status byte returned by host drivers right
4276 * by 1 bit. This is why target drivers also
4277 * use right shifted status byte definitions.
4278 * For instance target drivers use
4279 * CHECK_CONDITION, defined to 0x1, instead of
4280 * the SCSI defined check condition value of
4281 * 0x2. Host drivers are supposed to return
4282 * the status byte as it is defined by SCSI.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004283 */
4284 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
4285 STATUS_BYTE(scsiqp->scsi_status);
4286 } else {
4287 scp->result = STATUS_BYTE(scsiqp->scsi_status);
4288 }
4289 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004291 default:
4292 /* Some other QHSTA error occurred. */
4293 ASC_DBG1(1, "adv_isr_callback: host_status 0x%x\n",
4294 scsiqp->host_status);
4295 scp->result = HOST_BYTE(DID_BAD_TARGET);
4296 break;
4297 }
4298 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004299
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004300 case QD_ABORTED_BY_HOST:
4301 ASC_DBG(1, "adv_isr_callback: QD_ABORTED_BY_HOST\n");
4302 scp->result =
4303 HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status);
4304 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004306 default:
4307 ASC_DBG1(1, "adv_isr_callback: done_status 0x%x\n",
4308 scsiqp->done_status);
4309 scp->result =
4310 HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status);
4311 break;
4312 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004314 /*
4315 * If the 'init_tidmask' bit isn't already set for the target and the
4316 * current request finished normally, then set the bit for the target
4317 * to indicate that a device is present.
4318 */
4319 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
4320 scsiqp->done_status == QD_NO_ERROR &&
4321 scsiqp->host_status == QHSTA_NO_ERROR) {
4322 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
4323 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324
Matthew Wilcox6ed1ef02007-09-09 08:56:33 -06004325 asc_scsi_done(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004326
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004327 /*
4328 * Free all 'adv_sgblk_t' structures allocated for the request.
4329 */
4330 while ((sgblkp = reqp->sgblkp) != NULL) {
4331 /* Remove 'sgblkp' from the request list. */
4332 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004334 /* Add 'sgblkp' to the board free list. */
4335 sgblkp->next_sgblkp = boardp->adv_sgblkp;
4336 boardp->adv_sgblkp = sgblkp;
4337 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004339 /*
4340 * Free the adv_req_t structure used with the command by adding
4341 * it back to the board free list.
4342 */
4343 reqp->next_reqp = boardp->adv_reqp;
4344 boardp->adv_reqp = reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004346 ASC_DBG(1, "adv_isr_callback: done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004347
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004348 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349}
4350
4351/*
4352 * adv_async_callback() - Adv Library asynchronous event callback function.
4353 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004354static void adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004356 switch (code) {
4357 case ADV_ASYNC_SCSI_BUS_RESET_DET:
4358 /*
4359 * The firmware detected a SCSI Bus reset.
4360 */
4361 ASC_DBG(0,
4362 "adv_async_callback: ADV_ASYNC_SCSI_BUS_RESET_DET\n");
4363 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004365 case ADV_ASYNC_RDMA_FAILURE:
4366 /*
4367 * Handle RDMA failure by resetting the SCSI Bus and
4368 * possibly the chip if it is unresponsive. Log the error
4369 * with a unique code.
4370 */
4371 ASC_DBG(0, "adv_async_callback: ADV_ASYNC_RDMA_FAILURE\n");
4372 AdvResetChipAndSB(adv_dvc_varp);
4373 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004375 case ADV_HOST_SCSI_BUS_RESET:
4376 /*
4377 * Host generated SCSI bus reset occurred.
4378 */
4379 ASC_DBG(0, "adv_async_callback: ADV_HOST_SCSI_BUS_RESET\n");
4380 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004382 default:
4383 ASC_DBG1(0, "DvcAsyncCallBack: unknown code 0x%x\n", code);
4384 break;
4385 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386}
4387
Linus Torvalds1da177e2005-04-16 15:20:36 -07004388#ifdef CONFIG_PROC_FS
4389/*
4390 * asc_prt_board_devices()
4391 *
4392 * Print driver information for devices attached to the board.
4393 *
4394 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
4395 * cf. asc_prt_line().
4396 *
4397 * Return the number of characters copied into 'cp'. No more than
4398 * 'cplen' characters will be copied to 'cp'.
4399 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004400static int asc_prt_board_devices(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004401{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004402 asc_board_t *boardp;
4403 int leftlen;
4404 int totlen;
4405 int len;
4406 int chip_scsi_id;
4407 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004408
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004409 boardp = ASC_BOARDP(shost);
4410 leftlen = cplen;
4411 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004413 len = asc_prt_line(cp, leftlen,
4414 "\nDevice Information for AdvanSys SCSI Host %d:\n",
4415 shost->host_no);
4416 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004418 if (ASC_NARROW_BOARD(boardp)) {
4419 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
4420 } else {
4421 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
4422 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004423
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004424 len = asc_prt_line(cp, leftlen, "Target IDs Detected:");
4425 ASC_PRT_NEXT();
4426 for (i = 0; i <= ADV_MAX_TID; i++) {
4427 if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) {
4428 len = asc_prt_line(cp, leftlen, " %X,", i);
4429 ASC_PRT_NEXT();
4430 }
4431 }
4432 len = asc_prt_line(cp, leftlen, " (%X=Host Adapter)\n", chip_scsi_id);
4433 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004435 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004436}
4437
4438/*
4439 * Display Wide Board BIOS Information.
4440 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004441static int asc_prt_adv_bios(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004442{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004443 asc_board_t *boardp;
4444 int leftlen;
4445 int totlen;
4446 int len;
4447 ushort major, minor, letter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004448
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004449 boardp = ASC_BOARDP(shost);
4450 leftlen = cplen;
4451 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004453 len = asc_prt_line(cp, leftlen, "\nROM BIOS Version: ");
4454 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004456 /*
4457 * If the BIOS saved a valid signature, then fill in
4458 * the BIOS code segment base address.
4459 */
4460 if (boardp->bios_signature != 0x55AA) {
4461 len = asc_prt_line(cp, leftlen, "Disabled or Pre-3.1\n");
4462 ASC_PRT_NEXT();
4463 len = asc_prt_line(cp, leftlen,
4464 "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n");
4465 ASC_PRT_NEXT();
4466 len = asc_prt_line(cp, leftlen,
4467 "can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n");
4468 ASC_PRT_NEXT();
4469 } else {
4470 major = (boardp->bios_version >> 12) & 0xF;
4471 minor = (boardp->bios_version >> 8) & 0xF;
4472 letter = (boardp->bios_version & 0xFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004474 len = asc_prt_line(cp, leftlen, "%d.%d%c\n",
4475 major, minor,
4476 letter >= 26 ? '?' : letter + 'A');
4477 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004479 /*
4480 * Current available ROM BIOS release is 3.1I for UW
4481 * and 3.2I for U2W. This code doesn't differentiate
4482 * UW and U2W boards.
4483 */
4484 if (major < 3 || (major <= 3 && minor < 1) ||
4485 (major <= 3 && minor <= 1 && letter < ('I' - 'A'))) {
4486 len = asc_prt_line(cp, leftlen,
4487 "Newer version of ROM BIOS is available at the ConnectCom FTP site:\n");
4488 ASC_PRT_NEXT();
4489 len = asc_prt_line(cp, leftlen,
4490 "ftp://ftp.connectcom.net/pub\n");
4491 ASC_PRT_NEXT();
4492 }
4493 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004495 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004496}
4497
4498/*
4499 * Add serial number to information bar if signature AAh
4500 * is found in at bit 15-9 (7 bits) of word 1.
4501 *
4502 * Serial Number consists fo 12 alpha-numeric digits.
4503 *
4504 * 1 - Product type (A,B,C,D..) Word0: 15-13 (3 bits)
4505 * 2 - MFG Location (A,B,C,D..) Word0: 12-10 (3 bits)
4506 * 3-4 - Product ID (0-99) Word0: 9-0 (10 bits)
4507 * 5 - Product revision (A-J) Word0: " "
4508 *
4509 * Signature Word1: 15-9 (7 bits)
4510 * 6 - Year (0-9) Word1: 8-6 (3 bits) & Word2: 15 (1 bit)
4511 * 7-8 - Week of the year (1-52) Word1: 5-0 (6 bits)
4512 *
4513 * 9-12 - Serial Number (A001-Z999) Word2: 14-0 (15 bits)
4514 *
4515 * Note 1: Only production cards will have a serial number.
4516 *
4517 * Note 2: Signature is most significant 7 bits (0xFE).
4518 *
4519 * Returns ASC_TRUE if serial number found, otherwise returns ASC_FALSE.
4520 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004521static int asc_get_eeprom_string(ushort *serialnum, uchar *cp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004522{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004523 ushort w, num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004525 if ((serialnum[1] & 0xFE00) != ((ushort)0xAA << 8)) {
4526 return ASC_FALSE;
4527 } else {
4528 /*
4529 * First word - 6 digits.
4530 */
4531 w = serialnum[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004533 /* Product type - 1st digit. */
4534 if ((*cp = 'A' + ((w & 0xE000) >> 13)) == 'H') {
4535 /* Product type is P=Prototype */
4536 *cp += 0x8;
4537 }
4538 cp++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004540 /* Manufacturing location - 2nd digit. */
4541 *cp++ = 'A' + ((w & 0x1C00) >> 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004543 /* Product ID - 3rd, 4th digits. */
4544 num = w & 0x3FF;
4545 *cp++ = '0' + (num / 100);
4546 num %= 100;
4547 *cp++ = '0' + (num / 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004548
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004549 /* Product revision - 5th digit. */
4550 *cp++ = 'A' + (num % 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004551
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004552 /*
4553 * Second word
4554 */
4555 w = serialnum[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004557 /*
4558 * Year - 6th digit.
4559 *
4560 * If bit 15 of third word is set, then the
4561 * last digit of the year is greater than 7.
4562 */
4563 if (serialnum[2] & 0x8000) {
4564 *cp++ = '8' + ((w & 0x1C0) >> 6);
4565 } else {
4566 *cp++ = '0' + ((w & 0x1C0) >> 6);
4567 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004569 /* Week of year - 7th, 8th digits. */
4570 num = w & 0x003F;
4571 *cp++ = '0' + num / 10;
4572 num %= 10;
4573 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004575 /*
4576 * Third word
4577 */
4578 w = serialnum[2] & 0x7FFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004579
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004580 /* Serial number - 9th digit. */
4581 *cp++ = 'A' + (w / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004583 /* 10th, 11th, 12th digits. */
4584 num = w % 1000;
4585 *cp++ = '0' + num / 100;
4586 num %= 100;
4587 *cp++ = '0' + num / 10;
4588 num %= 10;
4589 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004591 *cp = '\0'; /* Null Terminate the string. */
4592 return ASC_TRUE;
4593 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004594}
4595
4596/*
4597 * asc_prt_asc_board_eeprom()
4598 *
4599 * Print board EEPROM configuration.
4600 *
4601 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
4602 * cf. asc_prt_line().
4603 *
4604 * Return the number of characters copied into 'cp'. No more than
4605 * 'cplen' characters will be copied to 'cp'.
4606 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004607static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004608{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004609 asc_board_t *boardp;
4610 ASC_DVC_VAR *asc_dvc_varp;
4611 int leftlen;
4612 int totlen;
4613 int len;
4614 ASCEEP_CONFIG *ep;
4615 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004617 int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004619 uchar serialstr[13];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004621 boardp = ASC_BOARDP(shost);
4622 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
4623 ep = &boardp->eep_config.asc_eep;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004625 leftlen = cplen;
4626 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004627
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004628 len = asc_prt_line(cp, leftlen,
4629 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
4630 shost->host_no);
4631 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004633 if (asc_get_eeprom_string((ushort *)&ep->adapter_info[0], serialstr)
4634 == ASC_TRUE) {
4635 len =
4636 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
4637 serialstr);
4638 ASC_PRT_NEXT();
4639 } else {
4640 if (ep->adapter_info[5] == 0xBB) {
4641 len = asc_prt_line(cp, leftlen,
4642 " Default Settings Used for EEPROM-less Adapter.\n");
4643 ASC_PRT_NEXT();
4644 } else {
4645 len = asc_prt_line(cp, leftlen,
4646 " Serial Number Signature Not Present.\n");
4647 ASC_PRT_NEXT();
4648 }
4649 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004651 len = asc_prt_line(cp, leftlen,
4652 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
4653 ASC_EEP_GET_CHIP_ID(ep), ep->max_total_qng,
4654 ep->max_tag_qng);
4655 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004656
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004657 len = asc_prt_line(cp, leftlen,
4658 " cntl 0x%x, no_scam 0x%x\n", ep->cntl, ep->no_scam);
4659 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004660
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004661 len = asc_prt_line(cp, leftlen, " Target ID: ");
4662 ASC_PRT_NEXT();
4663 for (i = 0; i <= ASC_MAX_TID; i++) {
4664 len = asc_prt_line(cp, leftlen, " %d", i);
4665 ASC_PRT_NEXT();
4666 }
4667 len = asc_prt_line(cp, leftlen, "\n");
4668 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004670 len = asc_prt_line(cp, leftlen, " Disconnects: ");
4671 ASC_PRT_NEXT();
4672 for (i = 0; i <= ASC_MAX_TID; i++) {
4673 len = asc_prt_line(cp, leftlen, " %c",
4674 (ep->
4675 disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
4676 'N');
4677 ASC_PRT_NEXT();
4678 }
4679 len = asc_prt_line(cp, leftlen, "\n");
4680 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004681
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004682 len = asc_prt_line(cp, leftlen, " Command Queuing: ");
4683 ASC_PRT_NEXT();
4684 for (i = 0; i <= ASC_MAX_TID; i++) {
4685 len = asc_prt_line(cp, leftlen, " %c",
4686 (ep->
4687 use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
4688 'N');
4689 ASC_PRT_NEXT();
4690 }
4691 len = asc_prt_line(cp, leftlen, "\n");
4692 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004693
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004694 len = asc_prt_line(cp, leftlen, " Start Motor: ");
4695 ASC_PRT_NEXT();
4696 for (i = 0; i <= ASC_MAX_TID; i++) {
4697 len = asc_prt_line(cp, leftlen, " %c",
4698 (ep->
4699 start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
4700 'N');
4701 ASC_PRT_NEXT();
4702 }
4703 len = asc_prt_line(cp, leftlen, "\n");
4704 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004705
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004706 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
4707 ASC_PRT_NEXT();
4708 for (i = 0; i <= ASC_MAX_TID; i++) {
4709 len = asc_prt_line(cp, leftlen, " %c",
4710 (ep->
4711 init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
4712 'N');
4713 ASC_PRT_NEXT();
4714 }
4715 len = asc_prt_line(cp, leftlen, "\n");
4716 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004717
4718#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004719 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
4720 len = asc_prt_line(cp, leftlen,
4721 " Host ISA DMA speed: %d MB/S\n",
4722 isa_dma_speed[ASC_EEP_GET_DMA_SPD(ep)]);
4723 ASC_PRT_NEXT();
4724 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004725#endif /* CONFIG_ISA */
4726
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004727 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004728}
4729
4730/*
4731 * asc_prt_adv_board_eeprom()
4732 *
4733 * Print board EEPROM configuration.
4734 *
4735 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
4736 * cf. asc_prt_line().
4737 *
4738 * Return the number of characters copied into 'cp'. No more than
4739 * 'cplen' characters will be copied to 'cp'.
4740 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004741static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004743 asc_board_t *boardp;
4744 ADV_DVC_VAR *adv_dvc_varp;
4745 int leftlen;
4746 int totlen;
4747 int len;
4748 int i;
4749 char *termstr;
4750 uchar serialstr[13];
4751 ADVEEP_3550_CONFIG *ep_3550 = NULL;
4752 ADVEEP_38C0800_CONFIG *ep_38C0800 = NULL;
4753 ADVEEP_38C1600_CONFIG *ep_38C1600 = NULL;
4754 ushort word;
4755 ushort *wordp;
4756 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004758 boardp = ASC_BOARDP(shost);
4759 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
4760 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
4761 ep_3550 = &boardp->eep_config.adv_3550_eep;
4762 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
4763 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
4764 } else {
4765 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
4766 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004767
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004768 leftlen = cplen;
4769 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004770
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004771 len = asc_prt_line(cp, leftlen,
4772 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
4773 shost->host_no);
4774 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004776 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
4777 wordp = &ep_3550->serial_number_word1;
4778 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
4779 wordp = &ep_38C0800->serial_number_word1;
4780 } else {
4781 wordp = &ep_38C1600->serial_number_word1;
4782 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004783
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004784 if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) {
4785 len =
4786 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
4787 serialstr);
4788 ASC_PRT_NEXT();
4789 } else {
4790 len = asc_prt_line(cp, leftlen,
4791 " Serial Number Signature Not Present.\n");
4792 ASC_PRT_NEXT();
4793 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004794
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004795 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
4796 len = asc_prt_line(cp, leftlen,
4797 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
4798 ep_3550->adapter_scsi_id,
4799 ep_3550->max_host_qng, ep_3550->max_dvc_qng);
4800 ASC_PRT_NEXT();
4801 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
4802 len = asc_prt_line(cp, leftlen,
4803 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
4804 ep_38C0800->adapter_scsi_id,
4805 ep_38C0800->max_host_qng,
4806 ep_38C0800->max_dvc_qng);
4807 ASC_PRT_NEXT();
4808 } else {
4809 len = asc_prt_line(cp, leftlen,
4810 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
4811 ep_38C1600->adapter_scsi_id,
4812 ep_38C1600->max_host_qng,
4813 ep_38C1600->max_dvc_qng);
4814 ASC_PRT_NEXT();
4815 }
4816 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
4817 word = ep_3550->termination;
4818 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
4819 word = ep_38C0800->termination_lvd;
4820 } else {
4821 word = ep_38C1600->termination_lvd;
4822 }
4823 switch (word) {
4824 case 1:
4825 termstr = "Low Off/High Off";
4826 break;
4827 case 2:
4828 termstr = "Low Off/High On";
4829 break;
4830 case 3:
4831 termstr = "Low On/High On";
4832 break;
4833 default:
4834 case 0:
4835 termstr = "Automatic";
4836 break;
4837 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004839 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
4840 len = asc_prt_line(cp, leftlen,
4841 " termination: %u (%s), bios_ctrl: 0x%x\n",
4842 ep_3550->termination, termstr,
4843 ep_3550->bios_ctrl);
4844 ASC_PRT_NEXT();
4845 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
4846 len = asc_prt_line(cp, leftlen,
4847 " termination: %u (%s), bios_ctrl: 0x%x\n",
4848 ep_38C0800->termination_lvd, termstr,
4849 ep_38C0800->bios_ctrl);
4850 ASC_PRT_NEXT();
4851 } else {
4852 len = asc_prt_line(cp, leftlen,
4853 " termination: %u (%s), bios_ctrl: 0x%x\n",
4854 ep_38C1600->termination_lvd, termstr,
4855 ep_38C1600->bios_ctrl);
4856 ASC_PRT_NEXT();
4857 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004858
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004859 len = asc_prt_line(cp, leftlen, " Target ID: ");
4860 ASC_PRT_NEXT();
4861 for (i = 0; i <= ADV_MAX_TID; i++) {
4862 len = asc_prt_line(cp, leftlen, " %X", i);
4863 ASC_PRT_NEXT();
4864 }
4865 len = asc_prt_line(cp, leftlen, "\n");
4866 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004867
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004868 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
4869 word = ep_3550->disc_enable;
4870 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
4871 word = ep_38C0800->disc_enable;
4872 } else {
4873 word = ep_38C1600->disc_enable;
4874 }
4875 len = asc_prt_line(cp, leftlen, " Disconnects: ");
4876 ASC_PRT_NEXT();
4877 for (i = 0; i <= ADV_MAX_TID; i++) {
4878 len = asc_prt_line(cp, leftlen, " %c",
4879 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
4880 ASC_PRT_NEXT();
4881 }
4882 len = asc_prt_line(cp, leftlen, "\n");
4883 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004884
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004885 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
4886 word = ep_3550->tagqng_able;
4887 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
4888 word = ep_38C0800->tagqng_able;
4889 } else {
4890 word = ep_38C1600->tagqng_able;
4891 }
4892 len = asc_prt_line(cp, leftlen, " Command Queuing: ");
4893 ASC_PRT_NEXT();
4894 for (i = 0; i <= ADV_MAX_TID; i++) {
4895 len = asc_prt_line(cp, leftlen, " %c",
4896 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
4897 ASC_PRT_NEXT();
4898 }
4899 len = asc_prt_line(cp, leftlen, "\n");
4900 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004901
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004902 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
4903 word = ep_3550->start_motor;
4904 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
4905 word = ep_38C0800->start_motor;
4906 } else {
4907 word = ep_38C1600->start_motor;
4908 }
4909 len = asc_prt_line(cp, leftlen, " Start Motor: ");
4910 ASC_PRT_NEXT();
4911 for (i = 0; i <= ADV_MAX_TID; i++) {
4912 len = asc_prt_line(cp, leftlen, " %c",
4913 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
4914 ASC_PRT_NEXT();
4915 }
4916 len = asc_prt_line(cp, leftlen, "\n");
4917 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004918
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004919 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
4920 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
4921 ASC_PRT_NEXT();
4922 for (i = 0; i <= ADV_MAX_TID; i++) {
4923 len = asc_prt_line(cp, leftlen, " %c",
4924 (ep_3550->
4925 sdtr_able & ADV_TID_TO_TIDMASK(i)) ?
4926 'Y' : 'N');
4927 ASC_PRT_NEXT();
4928 }
4929 len = asc_prt_line(cp, leftlen, "\n");
4930 ASC_PRT_NEXT();
4931 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004932
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004933 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
4934 len = asc_prt_line(cp, leftlen, " Ultra Transfer: ");
4935 ASC_PRT_NEXT();
4936 for (i = 0; i <= ADV_MAX_TID; i++) {
4937 len = asc_prt_line(cp, leftlen, " %c",
4938 (ep_3550->
4939 ultra_able & ADV_TID_TO_TIDMASK(i))
4940 ? 'Y' : 'N');
4941 ASC_PRT_NEXT();
4942 }
4943 len = asc_prt_line(cp, leftlen, "\n");
4944 ASC_PRT_NEXT();
4945 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004946
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004947 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
4948 word = ep_3550->wdtr_able;
4949 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
4950 word = ep_38C0800->wdtr_able;
4951 } else {
4952 word = ep_38C1600->wdtr_able;
4953 }
4954 len = asc_prt_line(cp, leftlen, " Wide Transfer: ");
4955 ASC_PRT_NEXT();
4956 for (i = 0; i <= ADV_MAX_TID; i++) {
4957 len = asc_prt_line(cp, leftlen, " %c",
4958 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
4959 ASC_PRT_NEXT();
4960 }
4961 len = asc_prt_line(cp, leftlen, "\n");
4962 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004963
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004964 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800 ||
4965 adv_dvc_varp->chip_type == ADV_CHIP_ASC38C1600) {
4966 len = asc_prt_line(cp, leftlen,
4967 " Synchronous Transfer Speed (Mhz):\n ");
4968 ASC_PRT_NEXT();
4969 for (i = 0; i <= ADV_MAX_TID; i++) {
4970 char *speed_str;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004971
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004972 if (i == 0) {
4973 sdtr_speed = adv_dvc_varp->sdtr_speed1;
4974 } else if (i == 4) {
4975 sdtr_speed = adv_dvc_varp->sdtr_speed2;
4976 } else if (i == 8) {
4977 sdtr_speed = adv_dvc_varp->sdtr_speed3;
4978 } else if (i == 12) {
4979 sdtr_speed = adv_dvc_varp->sdtr_speed4;
4980 }
4981 switch (sdtr_speed & ADV_MAX_TID) {
4982 case 0:
4983 speed_str = "Off";
4984 break;
4985 case 1:
4986 speed_str = " 5";
4987 break;
4988 case 2:
4989 speed_str = " 10";
4990 break;
4991 case 3:
4992 speed_str = " 20";
4993 break;
4994 case 4:
4995 speed_str = " 40";
4996 break;
4997 case 5:
4998 speed_str = " 80";
4999 break;
5000 default:
5001 speed_str = "Unk";
5002 break;
5003 }
5004 len = asc_prt_line(cp, leftlen, "%X:%s ", i, speed_str);
5005 ASC_PRT_NEXT();
5006 if (i == 7) {
5007 len = asc_prt_line(cp, leftlen, "\n ");
5008 ASC_PRT_NEXT();
5009 }
5010 sdtr_speed >>= 4;
5011 }
5012 len = asc_prt_line(cp, leftlen, "\n");
5013 ASC_PRT_NEXT();
5014 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005015
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005016 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005017}
5018
5019/*
5020 * asc_prt_driver_conf()
5021 *
5022 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
5023 * cf. asc_prt_line().
5024 *
5025 * Return the number of characters copied into 'cp'. No more than
5026 * 'cplen' characters will be copied to 'cp'.
5027 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005028static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005029{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005030 asc_board_t *boardp;
5031 int leftlen;
5032 int totlen;
5033 int len;
5034 int chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005035
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005036 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005037
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005038 leftlen = cplen;
5039 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005040
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005041 len = asc_prt_line(cp, leftlen,
5042 "\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n",
5043 shost->host_no);
5044 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005045
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005046 len = asc_prt_line(cp, leftlen,
5047 " host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n",
5048 shost->host_busy, shost->last_reset, shost->max_id,
5049 shost->max_lun, shost->max_channel);
5050 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005051
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005052 len = asc_prt_line(cp, leftlen,
5053 " unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
5054 shost->unique_id, shost->can_queue, shost->this_id,
5055 shost->sg_tablesize, shost->cmd_per_lun);
5056 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005057
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005058 len = asc_prt_line(cp, leftlen,
5059 " unchecked_isa_dma %d, use_clustering %d\n",
5060 shost->unchecked_isa_dma, shost->use_clustering);
5061 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005062
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005063 len = asc_prt_line(cp, leftlen,
5064 " flags 0x%x, last_reset 0x%x, jiffies 0x%x, asc_n_io_port 0x%x\n",
5065 boardp->flags, boardp->last_reset, jiffies,
5066 boardp->asc_n_io_port);
5067 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005068
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04005069 len = asc_prt_line(cp, leftlen, " io_port 0x%x\n", shost->io_port);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005070 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005071
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005072 if (ASC_NARROW_BOARD(boardp)) {
5073 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
5074 } else {
5075 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
5076 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005078 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005079}
5080
5081/*
5082 * asc_prt_asc_board_info()
5083 *
5084 * Print dynamic board configuration information.
5085 *
5086 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
5087 * cf. asc_prt_line().
5088 *
5089 * Return the number of characters copied into 'cp'. No more than
5090 * 'cplen' characters will be copied to 'cp'.
5091 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005092static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005093{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005094 asc_board_t *boardp;
5095 int chip_scsi_id;
5096 int leftlen;
5097 int totlen;
5098 int len;
5099 ASC_DVC_VAR *v;
5100 ASC_DVC_CFG *c;
5101 int i;
5102 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005103
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005104 boardp = ASC_BOARDP(shost);
5105 v = &boardp->dvc_var.asc_dvc_var;
5106 c = &boardp->dvc_cfg.asc_dvc_cfg;
5107 chip_scsi_id = c->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005108
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005109 leftlen = cplen;
5110 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005111
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005112 len = asc_prt_line(cp, leftlen,
5113 "\nAsc Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
5114 shost->host_no);
5115 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005116
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005117 len = asc_prt_line(cp, leftlen,
5118 " chip_version %u, lib_version 0x%x, lib_serial_no %u, mcode_date 0x%x\n",
5119 c->chip_version, c->lib_version, c->lib_serial_no,
5120 c->mcode_date);
5121 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005122
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005123 len = asc_prt_line(cp, leftlen,
5124 " mcode_version 0x%x, err_code %u\n",
5125 c->mcode_version, v->err_code);
5126 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005127
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005128 /* Current number of commands waiting for the host. */
5129 len = asc_prt_line(cp, leftlen,
5130 " Total Command Pending: %d\n", v->cur_total_qng);
5131 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005132
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005133 len = asc_prt_line(cp, leftlen, " Command Queuing:");
5134 ASC_PRT_NEXT();
5135 for (i = 0; i <= ASC_MAX_TID; i++) {
5136 if ((chip_scsi_id == i) ||
5137 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
5138 continue;
5139 }
5140 len = asc_prt_line(cp, leftlen, " %X:%c",
5141 i,
5142 (v->
5143 use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ?
5144 'Y' : 'N');
5145 ASC_PRT_NEXT();
5146 }
5147 len = asc_prt_line(cp, leftlen, "\n");
5148 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005149
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005150 /* Current number of commands waiting for a device. */
5151 len = asc_prt_line(cp, leftlen, " Command Queue Pending:");
5152 ASC_PRT_NEXT();
5153 for (i = 0; i <= ASC_MAX_TID; i++) {
5154 if ((chip_scsi_id == i) ||
5155 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
5156 continue;
5157 }
5158 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->cur_dvc_qng[i]);
5159 ASC_PRT_NEXT();
5160 }
5161 len = asc_prt_line(cp, leftlen, "\n");
5162 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005163
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005164 /* Current limit on number of commands that can be sent to a device. */
5165 len = asc_prt_line(cp, leftlen, " Command Queue Limit:");
5166 ASC_PRT_NEXT();
5167 for (i = 0; i <= ASC_MAX_TID; i++) {
5168 if ((chip_scsi_id == i) ||
5169 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
5170 continue;
5171 }
5172 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->max_dvc_qng[i]);
5173 ASC_PRT_NEXT();
5174 }
5175 len = asc_prt_line(cp, leftlen, "\n");
5176 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005177
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005178 /* Indicate whether the device has returned queue full status. */
5179 len = asc_prt_line(cp, leftlen, " Command Queue Full:");
5180 ASC_PRT_NEXT();
5181 for (i = 0; i <= ASC_MAX_TID; i++) {
5182 if ((chip_scsi_id == i) ||
5183 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
5184 continue;
5185 }
5186 if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) {
5187 len = asc_prt_line(cp, leftlen, " %X:Y-%d",
5188 i, boardp->queue_full_cnt[i]);
5189 } else {
5190 len = asc_prt_line(cp, leftlen, " %X:N", i);
5191 }
5192 ASC_PRT_NEXT();
5193 }
5194 len = asc_prt_line(cp, leftlen, "\n");
5195 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005196
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005197 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
5198 ASC_PRT_NEXT();
5199 for (i = 0; i <= ASC_MAX_TID; i++) {
5200 if ((chip_scsi_id == i) ||
5201 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
5202 continue;
5203 }
5204 len = asc_prt_line(cp, leftlen, " %X:%c",
5205 i,
5206 (v->
5207 sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
5208 'N');
5209 ASC_PRT_NEXT();
5210 }
5211 len = asc_prt_line(cp, leftlen, "\n");
5212 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005213
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005214 for (i = 0; i <= ASC_MAX_TID; i++) {
5215 uchar syn_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005216
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005217 if ((chip_scsi_id == i) ||
5218 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
5219 ((v->init_sdtr & ADV_TID_TO_TIDMASK(i)) == 0)) {
5220 continue;
5221 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005222
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005223 len = asc_prt_line(cp, leftlen, " %X:", i);
5224 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005225
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005226 if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0) {
5227 len = asc_prt_line(cp, leftlen, " Asynchronous");
5228 ASC_PRT_NEXT();
5229 } else {
5230 syn_period_ix =
5231 (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index -
5232 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005233
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005234 len = asc_prt_line(cp, leftlen,
5235 " Transfer Period Factor: %d (%d.%d Mhz),",
5236 v->sdtr_period_tbl[syn_period_ix],
5237 250 /
5238 v->sdtr_period_tbl[syn_period_ix],
5239 ASC_TENTHS(250,
5240 v->
5241 sdtr_period_tbl
5242 [syn_period_ix]));
5243 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005244
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005245 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
5246 boardp->
5247 sdtr_data[i] & ASC_SYN_MAX_OFFSET);
5248 ASC_PRT_NEXT();
5249 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005251 if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
5252 len = asc_prt_line(cp, leftlen, "*\n");
5253 renegotiate = 1;
5254 } else {
5255 len = asc_prt_line(cp, leftlen, "\n");
5256 }
5257 ASC_PRT_NEXT();
5258 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005259
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005260 if (renegotiate) {
5261 len = asc_prt_line(cp, leftlen,
5262 " * = Re-negotiation pending before next command.\n");
5263 ASC_PRT_NEXT();
5264 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005265
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005266 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005267}
5268
5269/*
5270 * asc_prt_adv_board_info()
5271 *
5272 * Print dynamic board configuration information.
5273 *
5274 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
5275 * cf. asc_prt_line().
5276 *
5277 * Return the number of characters copied into 'cp'. No more than
5278 * 'cplen' characters will be copied to 'cp'.
5279 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005280static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005281{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005282 asc_board_t *boardp;
5283 int leftlen;
5284 int totlen;
5285 int len;
5286 int i;
5287 ADV_DVC_VAR *v;
5288 ADV_DVC_CFG *c;
5289 AdvPortAddr iop_base;
5290 ushort chip_scsi_id;
5291 ushort lramword;
5292 uchar lrambyte;
5293 ushort tagqng_able;
5294 ushort sdtr_able, wdtr_able;
5295 ushort wdtr_done, sdtr_done;
5296 ushort period = 0;
5297 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005298
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005299 boardp = ASC_BOARDP(shost);
5300 v = &boardp->dvc_var.adv_dvc_var;
5301 c = &boardp->dvc_cfg.adv_dvc_cfg;
5302 iop_base = v->iop_base;
5303 chip_scsi_id = v->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005304
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005305 leftlen = cplen;
5306 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005307
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005308 len = asc_prt_line(cp, leftlen,
5309 "\nAdv Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
5310 shost->host_no);
5311 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005312
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005313 len = asc_prt_line(cp, leftlen,
5314 " iop_base 0x%lx, cable_detect: %X, err_code %u\n",
5315 v->iop_base,
5316 AdvReadWordRegister(iop_base,
5317 IOPW_SCSI_CFG1) & CABLE_DETECT,
5318 v->err_code);
5319 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005320
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005321 len = asc_prt_line(cp, leftlen,
5322 " chip_version %u, lib_version 0x%x, mcode_date 0x%x, mcode_version 0x%x\n",
5323 c->chip_version, c->lib_version, c->mcode_date,
5324 c->mcode_version);
5325 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005326
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005327 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
5328 len = asc_prt_line(cp, leftlen, " Queuing Enabled:");
5329 ASC_PRT_NEXT();
5330 for (i = 0; i <= ADV_MAX_TID; i++) {
5331 if ((chip_scsi_id == i) ||
5332 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
5333 continue;
5334 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005335
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005336 len = asc_prt_line(cp, leftlen, " %X:%c",
5337 i,
5338 (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
5339 'N');
5340 ASC_PRT_NEXT();
5341 }
5342 len = asc_prt_line(cp, leftlen, "\n");
5343 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005344
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005345 len = asc_prt_line(cp, leftlen, " Queue Limit:");
5346 ASC_PRT_NEXT();
5347 for (i = 0; i <= ADV_MAX_TID; i++) {
5348 if ((chip_scsi_id == i) ||
5349 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
5350 continue;
5351 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005352
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005353 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + i,
5354 lrambyte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005355
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005356 len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
5357 ASC_PRT_NEXT();
5358 }
5359 len = asc_prt_line(cp, leftlen, "\n");
5360 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005361
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005362 len = asc_prt_line(cp, leftlen, " Command Pending:");
5363 ASC_PRT_NEXT();
5364 for (i = 0; i <= ADV_MAX_TID; i++) {
5365 if ((chip_scsi_id == i) ||
5366 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
5367 continue;
5368 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005369
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005370 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_QUEUED_CMD + i,
5371 lrambyte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005372
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005373 len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
5374 ASC_PRT_NEXT();
5375 }
5376 len = asc_prt_line(cp, leftlen, "\n");
5377 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005378
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005379 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
5380 len = asc_prt_line(cp, leftlen, " Wide Enabled:");
5381 ASC_PRT_NEXT();
5382 for (i = 0; i <= ADV_MAX_TID; i++) {
5383 if ((chip_scsi_id == i) ||
5384 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
5385 continue;
5386 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005387
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005388 len = asc_prt_line(cp, leftlen, " %X:%c",
5389 i,
5390 (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
5391 'N');
5392 ASC_PRT_NEXT();
5393 }
5394 len = asc_prt_line(cp, leftlen, "\n");
5395 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005396
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005397 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done);
5398 len = asc_prt_line(cp, leftlen, " Transfer Bit Width:");
5399 ASC_PRT_NEXT();
5400 for (i = 0; i <= ADV_MAX_TID; i++) {
5401 if ((chip_scsi_id == i) ||
5402 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
5403 continue;
5404 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005405
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005406 AdvReadWordLram(iop_base,
5407 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
5408 lramword);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005409
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005410 len = asc_prt_line(cp, leftlen, " %X:%d",
5411 i, (lramword & 0x8000) ? 16 : 8);
5412 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005413
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005414 if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) &&
5415 (wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
5416 len = asc_prt_line(cp, leftlen, "*");
5417 ASC_PRT_NEXT();
5418 renegotiate = 1;
5419 }
5420 }
5421 len = asc_prt_line(cp, leftlen, "\n");
5422 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005423
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005424 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
5425 len = asc_prt_line(cp, leftlen, " Synchronous Enabled:");
5426 ASC_PRT_NEXT();
5427 for (i = 0; i <= ADV_MAX_TID; i++) {
5428 if ((chip_scsi_id == i) ||
5429 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
5430 continue;
5431 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005432
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005433 len = asc_prt_line(cp, leftlen, " %X:%c",
5434 i,
5435 (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
5436 'N');
5437 ASC_PRT_NEXT();
5438 }
5439 len = asc_prt_line(cp, leftlen, "\n");
5440 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005441
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005442 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done);
5443 for (i = 0; i <= ADV_MAX_TID; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005444
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005445 AdvReadWordLram(iop_base,
5446 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
5447 lramword);
5448 lramword &= ~0x8000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005449
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005450 if ((chip_scsi_id == i) ||
5451 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
5452 ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0)) {
5453 continue;
5454 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005455
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005456 len = asc_prt_line(cp, leftlen, " %X:", i);
5457 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005458
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005459 if ((lramword & 0x1F) == 0) { /* Check for REQ/ACK Offset 0. */
5460 len = asc_prt_line(cp, leftlen, " Asynchronous");
5461 ASC_PRT_NEXT();
5462 } else {
5463 len =
5464 asc_prt_line(cp, leftlen,
5465 " Transfer Period Factor: ");
5466 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005467
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005468 if ((lramword & 0x1F00) == 0x1100) { /* 80 Mhz */
5469 len =
5470 asc_prt_line(cp, leftlen, "9 (80.0 Mhz),");
5471 ASC_PRT_NEXT();
5472 } else if ((lramword & 0x1F00) == 0x1000) { /* 40 Mhz */
5473 len =
5474 asc_prt_line(cp, leftlen, "10 (40.0 Mhz),");
5475 ASC_PRT_NEXT();
5476 } else { /* 20 Mhz or below. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005477
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005478 period = (((lramword >> 8) * 25) + 50) / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005480 if (period == 0) { /* Should never happen. */
5481 len =
5482 asc_prt_line(cp, leftlen,
5483 "%d (? Mhz), ");
5484 ASC_PRT_NEXT();
5485 } else {
5486 len = asc_prt_line(cp, leftlen,
5487 "%d (%d.%d Mhz),",
5488 period, 250 / period,
5489 ASC_TENTHS(250,
5490 period));
5491 ASC_PRT_NEXT();
5492 }
5493 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005494
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005495 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
5496 lramword & 0x1F);
5497 ASC_PRT_NEXT();
5498 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005499
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005500 if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
5501 len = asc_prt_line(cp, leftlen, "*\n");
5502 renegotiate = 1;
5503 } else {
5504 len = asc_prt_line(cp, leftlen, "\n");
5505 }
5506 ASC_PRT_NEXT();
5507 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005508
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005509 if (renegotiate) {
5510 len = asc_prt_line(cp, leftlen,
5511 " * = Re-negotiation pending before next command.\n");
5512 ASC_PRT_NEXT();
5513 }
5514
5515 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005516}
5517
5518/*
5519 * asc_proc_copy()
5520 *
5521 * Copy proc information to a read buffer taking into account the current
5522 * read offset in the file and the remaining space in the read buffer.
5523 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005524static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005525asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005526 char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005527{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005528 int cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005529
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005530 ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n",
5531 (unsigned)offset, (unsigned)advoffset, cplen);
5532 if (offset <= advoffset) {
5533 /* Read offset below current offset, copy everything. */
5534 cnt = min(cplen, leftlen);
5535 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
5536 (ulong)curbuf, (ulong)cp, cnt);
5537 memcpy(curbuf, cp, cnt);
5538 } else if (offset < advoffset + cplen) {
5539 /* Read offset within current range, partial copy. */
5540 cnt = (advoffset + cplen) - offset;
5541 cp = (cp + cplen) - cnt;
5542 cnt = min(cnt, leftlen);
5543 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
5544 (ulong)curbuf, (ulong)cp, cnt);
5545 memcpy(curbuf, cp, cnt);
5546 }
5547 return cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005548}
5549
5550/*
5551 * asc_prt_line()
5552 *
5553 * If 'cp' is NULL print to the console, otherwise print to a buffer.
5554 *
5555 * Return 0 if printing to the console, otherwise return the number of
5556 * bytes written to the buffer.
5557 *
5558 * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack
5559 * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes.
5560 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005561static int asc_prt_line(char *buf, int buflen, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005562{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005563 va_list args;
5564 int ret;
5565 char s[ASC_PRTLINE_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07005566
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005567 va_start(args, fmt);
5568 ret = vsprintf(s, fmt, args);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06005569 BUG_ON(ret >= ASC_PRTLINE_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005570 if (buf == NULL) {
5571 (void)printk(s);
5572 ret = 0;
5573 } else {
5574 ret = min(buflen, ret);
5575 memcpy(buf, s, ret);
5576 }
5577 va_end(args);
5578 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005579}
5580#endif /* CONFIG_PROC_FS */
5581
Linus Torvalds1da177e2005-04-16 15:20:36 -07005582/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583 * void
5584 * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
5585 *
5586 * Calling/Exit State:
5587 * none
5588 *
5589 * Description:
5590 * Output an ASC_SCSI_Q structure to the chip
5591 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005592static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07005593DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
5594{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005595 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005596
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005597 ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words);
5598 AscSetChipLramAddr(iop_base, s_addr);
5599 for (i = 0; i < 2 * words; i += 2) {
5600 if (i == 4 || i == 20) {
5601 continue;
5602 }
5603 outpw(iop_base + IOP_RAM_DATA,
5604 ((ushort)outbuf[i + 1] << 8) | outbuf[i]);
5605 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005606}
5607
5608/*
5609 * void
5610 * DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
5611 *
5612 * Calling/Exit State:
5613 * none
5614 *
5615 * Description:
5616 * Input an ASC_QDONE_INFO structure from the chip
5617 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005618static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07005619DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
5620{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005621 int i;
5622 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005623
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005624 AscSetChipLramAddr(iop_base, s_addr);
5625 for (i = 0; i < 2 * words; i += 2) {
5626 if (i == 10) {
5627 continue;
5628 }
5629 word = inpw(iop_base + IOP_RAM_DATA);
5630 inbuf[i] = word & 0xff;
5631 inbuf[i + 1] = (word >> 8) & 0xff;
5632 }
5633 ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005634}
5635
5636/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07005637 * Return the BIOS address of the adapter at the specified
5638 * I/O port and with the specified bus type.
5639 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06005640static unsigned short __devinit
5641AscGetChipBiosAddress(PortAddr iop_base, unsigned short bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005642{
Matthew Wilcoxecec1942007-07-30 08:08:22 -06005643 unsigned short cfg_lsw;
5644 unsigned short bios_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005645
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005646 /*
5647 * The PCI BIOS is re-located by the motherboard BIOS. Because
5648 * of this the driver can not determine where a PCI BIOS is
5649 * loaded and executes.
5650 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06005651 if (bus_type & ASC_IS_PCI)
5652 return 0;
5653
Linus Torvalds1da177e2005-04-16 15:20:36 -07005654#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005655 if ((bus_type & ASC_IS_EISA) != 0) {
5656 cfg_lsw = AscGetEisaChipCfg(iop_base);
5657 cfg_lsw &= 0x000F;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06005658 bios_addr = ASC_BIOS_MIN_ADDR + cfg_lsw * ASC_BIOS_BANK_SIZE;
5659 return bios_addr;
5660 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005661#endif /* CONFIG_ISA */
5662
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005663 cfg_lsw = AscGetChipCfgLsw(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005664
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005665 /*
5666 * ISA PnP uses the top bit as the 32K BIOS flag
5667 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06005668 if (bus_type == ASC_IS_ISAPNP)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005669 cfg_lsw &= 0x7FFF;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06005670 bios_addr = ASC_BIOS_MIN_ADDR + (cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE;
5671 return bios_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005672}
5673
Linus Torvalds1da177e2005-04-16 15:20:36 -07005674/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07005675 * DvcGetPhyAddr()
5676 *
5677 * Return the physical address of 'vaddr' and set '*lenp' to the
5678 * number of physically contiguous bytes that follow 'vaddr'.
5679 * 'flag' indicates the type of structure whose physical address
5680 * is being translated.
5681 *
5682 * Note: Because Linux currently doesn't page the kernel and all
5683 * kernel buffers are physically contiguous, leave '*lenp' unchanged.
5684 */
5685ADV_PADDR
5686DvcGetPhyAddr(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005687 uchar *vaddr, ADV_SDCNT *lenp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005688{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005689 ADV_PADDR paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005690
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005691 paddr = virt_to_bus(vaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005692
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005693 ASC_DBG4(4,
5694 "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n",
5695 (ulong)vaddr, (ulong)lenp, (ulong)*((ulong *)lenp),
5696 (ulong)paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005697
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005698 return paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005699}
5700
Linus Torvalds1da177e2005-04-16 15:20:36 -07005701#ifdef ADVANSYS_STATS
5702#ifdef CONFIG_PROC_FS
5703/*
5704 * asc_prt_board_stats()
5705 *
5706 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
5707 * cf. asc_prt_line().
5708 *
5709 * Return the number of characters copied into 'cp'. No more than
5710 * 'cplen' characters will be copied to 'cp'.
5711 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005712static int asc_prt_board_stats(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005713{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005714 int leftlen;
5715 int totlen;
5716 int len;
5717 struct asc_stats *s;
5718 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005719
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005720 leftlen = cplen;
5721 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005722
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005723 boardp = ASC_BOARDP(shost);
5724 s = &boardp->asc_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005725
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005726 len = asc_prt_line(cp, leftlen,
5727 "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n",
5728 shost->host_no);
5729 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005730
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005731 len = asc_prt_line(cp, leftlen,
5732 " queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n",
5733 s->queuecommand, s->reset, s->biosparam,
5734 s->interrupt);
5735 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005736
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005737 len = asc_prt_line(cp, leftlen,
5738 " callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n",
5739 s->callback, s->done, s->build_error,
5740 s->adv_build_noreq, s->adv_build_nosg);
5741 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005742
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005743 len = asc_prt_line(cp, leftlen,
5744 " exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n",
5745 s->exe_noerror, s->exe_busy, s->exe_error,
5746 s->exe_unknown);
5747 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005748
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005749 /*
5750 * Display data transfer statistics.
5751 */
5752 if (s->cont_cnt > 0) {
5753 len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt);
5754 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005755
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005756 len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ",
5757 s->cont_xfer / 2,
5758 ASC_TENTHS(s->cont_xfer, 2));
5759 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005760
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005761 /* Contiguous transfer average size */
5762 len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kb\n",
5763 (s->cont_xfer / 2) / s->cont_cnt,
5764 ASC_TENTHS((s->cont_xfer / 2), s->cont_cnt));
5765 ASC_PRT_NEXT();
5766 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005767
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005768 if (s->sg_cnt > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005769
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005770 len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ",
5771 s->sg_cnt, s->sg_elem);
5772 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005773
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005774 len = asc_prt_line(cp, leftlen, "sg_xfer %lu.%01lu kb\n",
5775 s->sg_xfer / 2, ASC_TENTHS(s->sg_xfer, 2));
5776 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005777
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005778 /* Scatter gather transfer statistics */
5779 len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ",
5780 s->sg_elem / s->sg_cnt,
5781 ASC_TENTHS(s->sg_elem, s->sg_cnt));
5782 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005783
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005784 len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ",
5785 (s->sg_xfer / 2) / s->sg_elem,
5786 ASC_TENTHS((s->sg_xfer / 2), s->sg_elem));
5787 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005788
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005789 len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n",
5790 (s->sg_xfer / 2) / s->sg_cnt,
5791 ASC_TENTHS((s->sg_xfer / 2), s->sg_cnt));
5792 ASC_PRT_NEXT();
5793 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005794
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005795 /*
5796 * Display request queuing statistics.
5797 */
5798 len = asc_prt_line(cp, leftlen,
5799 " Active and Waiting Request Queues (Time Unit: %d HZ):\n",
5800 HZ);
5801 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005802
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005803 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005804}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005805#endif /* CONFIG_PROC_FS */
5806#endif /* ADVANSYS_STATS */
5807
5808#ifdef ADVANSYS_DEBUG
5809/*
5810 * asc_prt_scsi_host()
5811 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005812static void asc_prt_scsi_host(struct Scsi_Host *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005813{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005814 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005815
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005816 boardp = ASC_BOARDP(s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005817
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005818 printk("Scsi_Host at addr 0x%lx\n", (ulong)s);
5819 printk(" host_busy %u, host_no %d, last_reset %d,\n",
5820 s->host_busy, s->host_no, (unsigned)s->last_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005821
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04005822 printk(" base 0x%lx, io_port 0x%lx, irq 0x%x,\n",
5823 (ulong)s->base, (ulong)s->io_port, s->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005824
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005825 printk(" dma_channel %d, this_id %d, can_queue %d,\n",
5826 s->dma_channel, s->this_id, s->can_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005827
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005828 printk(" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
5829 s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005830
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005831 if (ASC_NARROW_BOARD(boardp)) {
5832 asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var);
5833 asc_prt_asc_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.asc_dvc_cfg);
5834 } else {
5835 asc_prt_adv_dvc_var(&ASC_BOARDP(s)->dvc_var.adv_dvc_var);
5836 asc_prt_adv_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.adv_dvc_cfg);
5837 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005838}
5839
5840/*
5841 * asc_prt_scsi_cmnd()
5842 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005843static void asc_prt_scsi_cmnd(struct scsi_cmnd *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005844{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005845 printk("struct scsi_cmnd at addr 0x%lx\n", (ulong)s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005846
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005847 printk(" host 0x%lx, device 0x%lx, target %u, lun %u, channel %u,\n",
5848 (ulong)s->device->host, (ulong)s->device, s->device->id,
5849 s->device->lun, s->device->channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005850
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005851 asc_prt_hex(" CDB", s->cmnd, s->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005852
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005853 printk("sc_data_direction %u, resid %d\n",
5854 s->sc_data_direction, s->resid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005855
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005856 printk(" use_sg %u, sglist_len %u\n", s->use_sg, s->sglist_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005857
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005858 printk(" serial_number 0x%x, retries %d, allowed %d\n",
5859 (unsigned)s->serial_number, s->retries, s->allowed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005860
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005861 printk(" timeout_per_command %d\n", s->timeout_per_command);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005862
Matthew Wilcoxecec1942007-07-30 08:08:22 -06005863 printk(" scsi_done 0x%p, done 0x%p, host_scribble 0x%p, result 0x%x\n",
5864 s->scsi_done, s->done, s->host_scribble, s->result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005865
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005866 printk(" tag %u, pid %u\n", (unsigned)s->tag, (unsigned)s->pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005867}
5868
5869/*
5870 * asc_prt_asc_dvc_var()
5871 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005872static void asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005873{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005874 printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005875
Matthew Wilcoxecec1942007-07-30 08:08:22 -06005876 printk(" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl "
5877 "%d,\n", h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005878
Matthew Wilcox895d6b42007-07-26 11:57:06 -04005879 printk(" bus_type %d, init_sdtr 0x%x,\n", h->bus_type,
5880 (unsigned)h->init_sdtr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005881
Matthew Wilcoxecec1942007-07-30 08:08:22 -06005882 printk(" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, "
5883 "chip_no 0x%x,\n", (unsigned)h->sdtr_done,
5884 (unsigned)h->use_tagged_qng, (unsigned)h->unit_not_ready,
5885 (unsigned)h->chip_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005886
Matthew Wilcoxecec1942007-07-30 08:08:22 -06005887 printk(" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait "
5888 "%u,\n", (unsigned)h->queue_full_or_busy,
5889 (unsigned)h->start_motor, (unsigned)h->scsi_reset_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005890
Matthew Wilcoxecec1942007-07-30 08:08:22 -06005891 printk(" is_in_int %u, max_total_qng %u, cur_total_qng %u, "
5892 "in_critical_cnt %u,\n", (unsigned)h->is_in_int,
5893 (unsigned)h->max_total_qng, (unsigned)h->cur_total_qng,
5894 (unsigned)h->in_critical_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005895
Matthew Wilcoxecec1942007-07-30 08:08:22 -06005896 printk(" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, "
5897 "pci_fix_asyn_xfer 0x%x,\n", (unsigned)h->last_q_shortage,
5898 (unsigned)h->init_state, (unsigned)h->no_scam,
5899 (unsigned)h->pci_fix_asyn_xfer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005900
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005901 printk(" cfg 0x%lx, irq_no 0x%x\n", (ulong)h->cfg, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005902}
5903
5904/*
5905 * asc_prt_asc_dvc_cfg()
5906 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005907static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005908{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005909 printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005910
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005911 printk(" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n",
5912 h->can_tagged_qng, h->cmd_qng_enabled);
5913 printk(" disc_enable 0x%x, sdtr_enable 0x%x,\n",
5914 h->disc_enable, h->sdtr_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005915
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005916 printk
5917 (" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n",
5918 h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel,
5919 h->chip_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005920
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005921 printk
5922 (" pci_device_id %d, lib_serial_no %u, lib_version %u, mcode_date 0x%x,\n",
5923 to_pci_dev(h->dev)->device, h->lib_serial_no, h->lib_version,
5924 h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005925
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005926 printk(" mcode_version %d, overrun_buf 0x%lx\n",
5927 h->mcode_version, (ulong)h->overrun_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005928}
5929
5930/*
5931 * asc_prt_asc_scsi_q()
5932 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005933static void asc_prt_asc_scsi_q(ASC_SCSI_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005934{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005935 ASC_SG_HEAD *sgp;
5936 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005937
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005938 printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005939
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005940 printk
5941 (" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n",
5942 q->q2.target_ix, q->q1.target_lun, (ulong)q->q2.srb_ptr,
5943 q->q2.tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005944
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005945 printk
5946 (" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
5947 (ulong)le32_to_cpu(q->q1.data_addr),
5948 (ulong)le32_to_cpu(q->q1.data_cnt),
5949 (ulong)le32_to_cpu(q->q1.sense_addr), q->q1.sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005950
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005951 printk(" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n",
5952 (ulong)q->cdbptr, q->q2.cdb_len,
5953 (ulong)q->sg_head, q->q1.sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005954
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005955 if (q->sg_head) {
5956 sgp = q->sg_head;
5957 printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong)sgp);
5958 printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt,
5959 sgp->queue_cnt);
5960 for (i = 0; i < sgp->entry_cnt; i++) {
5961 printk(" [%u]: addr 0x%lx, bytes %lu\n",
5962 i, (ulong)le32_to_cpu(sgp->sg_list[i].addr),
5963 (ulong)le32_to_cpu(sgp->sg_list[i].bytes));
5964 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005965
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005966 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005967}
5968
5969/*
5970 * asc_prt_asc_qdone_info()
5971 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005972static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005973{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005974 printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong)q);
5975 printk(" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n",
5976 (ulong)q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
5977 q->d2.tag_code);
5978 printk
5979 (" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n",
5980 q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005981}
5982
5983/*
5984 * asc_prt_adv_dvc_var()
5985 *
5986 * Display an ADV_DVC_VAR structure.
5987 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005988static void asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005989{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005990 printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005991
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005992 printk(" iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n",
5993 (ulong)h->iop_base, h->err_code, (unsigned)h->ultra_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005994
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005995 printk(" isr_callback 0x%lx, sdtr_able 0x%x, wdtr_able 0x%x\n",
5996 (ulong)h->isr_callback, (unsigned)h->sdtr_able,
5997 (unsigned)h->wdtr_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005998
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005999 printk(" start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n",
6000 (unsigned)h->start_motor,
6001 (unsigned)h->scsi_reset_wait, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006002
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006003 printk(" max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n",
6004 (unsigned)h->max_host_qng, (unsigned)h->max_dvc_qng,
6005 (ulong)h->carr_freelist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006006
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006007 printk(" icq_sp 0x%lx, irq_sp 0x%lx\n",
6008 (ulong)h->icq_sp, (ulong)h->irq_sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006009
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006010 printk(" no_scam 0x%x, tagqng_able 0x%x\n",
6011 (unsigned)h->no_scam, (unsigned)h->tagqng_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006012
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006013 printk(" chip_scsi_id 0x%x, cfg 0x%lx\n",
6014 (unsigned)h->chip_scsi_id, (ulong)h->cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006015}
6016
6017/*
6018 * asc_prt_adv_dvc_cfg()
6019 *
6020 * Display an ADV_DVC_CFG structure.
6021 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006022static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006023{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006024 printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006025
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006026 printk(" disc_enable 0x%x, termination 0x%x\n",
6027 h->disc_enable, h->termination);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006028
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006029 printk(" chip_version 0x%x, mcode_date 0x%x\n",
6030 h->chip_version, h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006031
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006032 printk(" mcode_version 0x%x, pci_device_id 0x%x, lib_version %u\n",
6033 h->mcode_version, to_pci_dev(h->dev)->device, h->lib_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006034
Matthew Wilcox13ac2d92007-07-30 08:10:23 -06006035 printk(" control_flag 0x%x\n", h->control_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006036}
6037
6038/*
6039 * asc_prt_adv_scsi_req_q()
6040 *
6041 * Display an ADV_SCSI_REQ_Q structure.
6042 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006043static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006044{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006045 int sg_blk_cnt;
6046 struct asc_sg_block *sg_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006047
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006048 printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006049
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006050 printk(" target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n",
6051 q->target_id, q->target_lun, (ulong)q->srb_ptr, q->a_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006052
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006053 printk(" cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
6054 q->cntl, (ulong)le32_to_cpu(q->data_addr), (ulong)q->vdata_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006055
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006056 printk(" data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
6057 (ulong)le32_to_cpu(q->data_cnt),
6058 (ulong)le32_to_cpu(q->sense_addr), q->sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006059
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006060 printk
6061 (" cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n",
6062 q->cdb_len, q->done_status, q->host_status, q->scsi_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006063
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006064 printk(" sg_working_ix 0x%x, target_cmd %u\n",
6065 q->sg_working_ix, q->target_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006066
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006067 printk(" scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n",
6068 (ulong)le32_to_cpu(q->scsiq_rptr),
6069 (ulong)le32_to_cpu(q->sg_real_addr), (ulong)q->sg_list_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006070
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006071 /* Display the request's ADV_SG_BLOCK structures. */
6072 if (q->sg_list_ptr != NULL) {
6073 sg_blk_cnt = 0;
6074 while (1) {
6075 /*
6076 * 'sg_ptr' is a physical address. Convert it to a virtual
6077 * address by indexing 'sg_blk_cnt' into the virtual address
6078 * array 'sg_list_ptr'.
6079 *
6080 * XXX - Assumes all SG physical blocks are virtually contiguous.
6081 */
6082 sg_ptr =
6083 &(((ADV_SG_BLOCK *)(q->sg_list_ptr))[sg_blk_cnt]);
6084 asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr);
6085 if (sg_ptr->sg_ptr == 0) {
6086 break;
6087 }
6088 sg_blk_cnt++;
6089 }
6090 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006091}
6092
6093/*
6094 * asc_prt_adv_sgblock()
6095 *
6096 * Display an ADV_SG_BLOCK structure.
6097 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006098static void asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006099{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006100 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006101
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006102 printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n",
6103 (ulong)b, sgblockno);
6104 printk(" sg_cnt %u, sg_ptr 0x%lx\n",
6105 b->sg_cnt, (ulong)le32_to_cpu(b->sg_ptr));
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06006106 BUG_ON(b->sg_cnt > NO_OF_SG_PER_BLOCK);
6107 if (b->sg_ptr != 0)
6108 BUG_ON(b->sg_cnt != NO_OF_SG_PER_BLOCK);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006109 for (i = 0; i < b->sg_cnt; i++) {
6110 printk(" [%u]: sg_addr 0x%lx, sg_count 0x%lx\n",
6111 i, (ulong)b->sg_list[i].sg_addr,
6112 (ulong)b->sg_list[i].sg_count);
6113 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006114}
6115
6116/*
6117 * asc_prt_hex()
6118 *
6119 * Print hexadecimal output in 4 byte groupings 32 bytes
6120 * or 8 double-words per line.
6121 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006122static void asc_prt_hex(char *f, uchar *s, int l)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006123{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006124 int i;
6125 int j;
6126 int k;
6127 int m;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006128
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006129 printk("%s: (%d bytes)\n", f, l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006130
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006131 for (i = 0; i < l; i += 32) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006132
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006133 /* Display a maximum of 8 double-words per line. */
6134 if ((k = (l - i) / 4) >= 8) {
6135 k = 8;
6136 m = 0;
6137 } else {
6138 m = (l - i) % 4;
6139 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006140
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006141 for (j = 0; j < k; j++) {
6142 printk(" %2.2X%2.2X%2.2X%2.2X",
6143 (unsigned)s[i + (j * 4)],
6144 (unsigned)s[i + (j * 4) + 1],
6145 (unsigned)s[i + (j * 4) + 2],
6146 (unsigned)s[i + (j * 4) + 3]);
6147 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006148
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006149 switch (m) {
6150 case 0:
6151 default:
6152 break;
6153 case 1:
6154 printk(" %2.2X", (unsigned)s[i + (j * 4)]);
6155 break;
6156 case 2:
6157 printk(" %2.2X%2.2X",
6158 (unsigned)s[i + (j * 4)],
6159 (unsigned)s[i + (j * 4) + 1]);
6160 break;
6161 case 3:
6162 printk(" %2.2X%2.2X%2.2X",
6163 (unsigned)s[i + (j * 4) + 1],
6164 (unsigned)s[i + (j * 4) + 2],
6165 (unsigned)s[i + (j * 4) + 3]);
6166 break;
6167 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006168
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006169 printk("\n");
6170 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006171}
6172#endif /* ADVANSYS_DEBUG */
6173
Matthew Wilcox78e77d82007-07-29 21:46:15 -06006174static ushort __devinit AscGetEisaChipCfg(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006175{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006176 PortAddr eisa_cfg_iop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006177
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006178 eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
6179 (PortAddr) (ASC_EISA_CFG_IOP_MASK);
6180 return (inpw(eisa_cfg_iop));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006181}
6182
Matthew Wilcox78e77d82007-07-29 21:46:15 -06006183static uchar __devinit AscSetChipScsiID(PortAddr iop_base, uchar new_host_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006184{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006185 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006186
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006187 if (AscGetChipScsiID(iop_base) == new_host_id) {
6188 return (new_host_id);
6189 }
6190 cfg_lsw = AscGetChipCfgLsw(iop_base);
6191 cfg_lsw &= 0xF8FF;
6192 cfg_lsw |= (ushort)((new_host_id & ASC_MAX_TID) << 8);
6193 AscSetChipCfgLsw(iop_base, cfg_lsw);
6194 return (AscGetChipScsiID(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006195}
6196
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006197static unsigned char __devinit AscGetChipScsiCtrl(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006198{
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006199 unsigned char sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006200
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006201 AscSetBank(iop_base, 1);
6202 sc = inp(iop_base + IOP_REG_SC);
6203 AscSetBank(iop_base, 0);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006204 return sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006205}
6206
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006207static unsigned char __devinit
6208AscGetChipVersion(PortAddr iop_base, unsigned short bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006209{
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006210 if (bus_type & ASC_IS_EISA) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006211 PortAddr eisa_iop;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006212 unsigned char revision;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006213 eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
6214 (PortAddr) ASC_EISA_REV_IOP_MASK;
6215 revision = inp(eisa_iop);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006216 return ASC_CHIP_MIN_VER_EISA - 1 + revision;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006217 }
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006218 return AscGetChipVerNo(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006219}
6220
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006221static ASC_DCNT
6222AscLoadMicroCode(PortAddr iop_base,
6223 ushort s_addr, uchar *mcode_buf, ushort mcode_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006224{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006225 ASC_DCNT chksum;
6226 ushort mcode_word_size;
6227 ushort mcode_chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006228
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006229 /* Write the microcode buffer starting at LRAM address 0. */
6230 mcode_word_size = (ushort)(mcode_size >> 1);
6231 AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
6232 AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006233
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006234 chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size);
6235 ASC_DBG1(1, "AscLoadMicroCode: chksum 0x%lx\n", (ulong)chksum);
6236 mcode_chksum = (ushort)AscMemSumLramWord(iop_base,
6237 (ushort)ASC_CODE_SEC_BEG,
6238 (ushort)((mcode_size -
6239 s_addr - (ushort)
6240 ASC_CODE_SEC_BEG) /
6241 2));
6242 ASC_DBG1(1, "AscLoadMicroCode: mcode_chksum 0x%lx\n",
6243 (ulong)mcode_chksum);
6244 AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum);
6245 AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size);
6246 return (chksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006247}
6248
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006249static int AscFindSignature(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006250{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006251 ushort sig_word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006252
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006253 ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureByte(0x%x) 0x%x\n",
6254 iop_base, AscGetChipSignatureByte(iop_base));
6255 if (AscGetChipSignatureByte(iop_base) == (uchar)ASC_1000_ID1B) {
6256 ASC_DBG2(1,
6257 "AscFindSignature: AscGetChipSignatureWord(0x%x) 0x%x\n",
6258 iop_base, AscGetChipSignatureWord(iop_base));
6259 sig_word = AscGetChipSignatureWord(iop_base);
6260 if ((sig_word == (ushort)ASC_1000_ID0W) ||
6261 (sig_word == (ushort)ASC_1000_ID0W_FIX)) {
6262 return (1);
6263 }
6264 }
6265 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006266}
6267
Matthew Wilcox78e77d82007-07-29 21:46:15 -06006268static void __devinit AscToggleIRQAct(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006269{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006270 AscSetChipStatus(iop_base, CIW_IRQ_ACT);
6271 AscSetChipStatus(iop_base, 0);
6272 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006273}
6274
Matthew Wilcox78e77d82007-07-29 21:46:15 -06006275static uchar __devinit AscGetChipIRQ(PortAddr iop_base, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006276{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006277 ushort cfg_lsw;
6278 uchar chip_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006279
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006280 if ((bus_type & ASC_IS_EISA) != 0) {
6281 cfg_lsw = AscGetEisaChipCfg(iop_base);
6282 chip_irq = (uchar)(((cfg_lsw >> 8) & 0x07) + 10);
6283 if ((chip_irq == 13) || (chip_irq > 15)) {
6284 return (0);
6285 }
6286 return (chip_irq);
6287 }
6288 if ((bus_type & ASC_IS_VL) != 0) {
6289 cfg_lsw = AscGetChipCfgLsw(iop_base);
6290 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x07));
6291 if ((chip_irq == 0) || (chip_irq == 4) || (chip_irq == 7)) {
6292 return (0);
6293 }
6294 return ((uchar)(chip_irq + (ASC_MIN_IRQ_NO - 1)));
6295 }
6296 cfg_lsw = AscGetChipCfgLsw(iop_base);
6297 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x03));
6298 if (chip_irq == 3)
6299 chip_irq += (uchar)2;
6300 return ((uchar)(chip_irq + ASC_MIN_IRQ_NO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006301}
6302
Matthew Wilcox78e77d82007-07-29 21:46:15 -06006303static uchar __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006304AscSetChipIRQ(PortAddr iop_base, uchar irq_no, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006305{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006306 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006307
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006308 if ((bus_type & ASC_IS_VL) != 0) {
6309 if (irq_no != 0) {
6310 if ((irq_no < ASC_MIN_IRQ_NO)
6311 || (irq_no > ASC_MAX_IRQ_NO)) {
6312 irq_no = 0;
6313 } else {
6314 irq_no -= (uchar)((ASC_MIN_IRQ_NO - 1));
6315 }
6316 }
6317 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE3);
6318 cfg_lsw |= (ushort)0x0010;
6319 AscSetChipCfgLsw(iop_base, cfg_lsw);
6320 AscToggleIRQAct(iop_base);
6321 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE0);
6322 cfg_lsw |= (ushort)((irq_no & 0x07) << 2);
6323 AscSetChipCfgLsw(iop_base, cfg_lsw);
6324 AscToggleIRQAct(iop_base);
6325 return (AscGetChipIRQ(iop_base, bus_type));
6326 }
6327 if ((bus_type & (ASC_IS_ISA)) != 0) {
6328 if (irq_no == 15)
6329 irq_no -= (uchar)2;
6330 irq_no -= (uchar)ASC_MIN_IRQ_NO;
6331 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFF3);
6332 cfg_lsw |= (ushort)((irq_no & 0x03) << 2);
6333 AscSetChipCfgLsw(iop_base, cfg_lsw);
6334 return (AscGetChipIRQ(iop_base, bus_type));
6335 }
6336 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006337}
6338
6339#ifdef CONFIG_ISA
Matthew Wilcox78e77d82007-07-29 21:46:15 -06006340static void __devinit AscEnableIsaDma(uchar dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006341{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006342 if (dma_channel < 4) {
6343 outp(0x000B, (ushort)(0xC0 | dma_channel));
6344 outp(0x000A, dma_channel);
6345 } else if (dma_channel < 8) {
6346 outp(0x00D6, (ushort)(0xC0 | (dma_channel - 4)));
6347 outp(0x00D4, (ushort)(dma_channel - 4));
6348 }
6349 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006350}
6351#endif /* CONFIG_ISA */
6352
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006353static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006354{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006355 EXT_MSG ext_msg;
6356 EXT_MSG out_msg;
6357 ushort halt_q_addr;
6358 int sdtr_accept;
6359 ushort int_halt_code;
6360 ASC_SCSI_BIT_ID_TYPE scsi_busy;
6361 ASC_SCSI_BIT_ID_TYPE target_id;
6362 PortAddr iop_base;
6363 uchar tag_code;
6364 uchar q_status;
6365 uchar halt_qp;
6366 uchar sdtr_data;
6367 uchar target_ix;
6368 uchar q_cntl, tid_no;
6369 uchar cur_dvc_qng;
6370 uchar asyn_sdtr;
6371 uchar scsi_status;
6372 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006373
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06006374 BUG_ON(!asc_dvc->drv_ptr);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006375 boardp = asc_dvc->drv_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006376
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006377 iop_base = asc_dvc->iop_base;
6378 int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006379
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006380 halt_qp = AscReadLramByte(iop_base, ASCV_CURCDB_B);
6381 halt_q_addr = ASC_QNO_TO_QADDR(halt_qp);
6382 target_ix = AscReadLramByte(iop_base,
6383 (ushort)(halt_q_addr +
6384 (ushort)ASC_SCSIQ_B_TARGET_IX));
Matthew Wilcox95c9f162007-09-09 08:56:39 -06006385 q_cntl = AscReadLramByte(iop_base,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006386 (ushort)(halt_q_addr + (ushort)ASC_SCSIQ_B_CNTL));
6387 tid_no = ASC_TIX_TO_TID(target_ix);
6388 target_id = (uchar)ASC_TID_TO_TARGET_ID(tid_no);
6389 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
6390 asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB;
6391 } else {
6392 asyn_sdtr = 0;
6393 }
6394 if (int_halt_code == ASC_HALT_DISABLE_ASYN_USE_SYN_FIX) {
6395 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
6396 AscSetChipSDTR(iop_base, 0, tid_no);
6397 boardp->sdtr_data[tid_no] = 0;
6398 }
6399 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
6400 return (0);
6401 } else if (int_halt_code == ASC_HALT_ENABLE_ASYN_USE_SYN_FIX) {
6402 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
6403 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
6404 boardp->sdtr_data[tid_no] = asyn_sdtr;
6405 }
6406 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
6407 return (0);
6408 } else if (int_halt_code == ASC_HALT_EXTMSG_IN) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006409 AscMemWordCopyPtrFromLram(iop_base,
6410 ASCV_MSGIN_BEG,
6411 (uchar *)&ext_msg,
6412 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006413
Matthew Wilcox47d853c2007-07-26 11:41:33 -04006414 if (ext_msg.msg_type == EXTENDED_MESSAGE &&
6415 ext_msg.msg_req == EXTENDED_SDTR &&
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006416 ext_msg.msg_len == MS_SDTR_LEN) {
6417 sdtr_accept = TRUE;
6418 if ((ext_msg.req_ack_offset > ASC_SYN_MAX_OFFSET)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006419
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006420 sdtr_accept = FALSE;
6421 ext_msg.req_ack_offset = ASC_SYN_MAX_OFFSET;
6422 }
6423 if ((ext_msg.xfer_period <
6424 asc_dvc->sdtr_period_tbl[asc_dvc->
6425 host_init_sdtr_index])
6426 || (ext_msg.xfer_period >
6427 asc_dvc->sdtr_period_tbl[asc_dvc->
6428 max_sdtr_index])) {
6429 sdtr_accept = FALSE;
6430 ext_msg.xfer_period =
6431 asc_dvc->sdtr_period_tbl[asc_dvc->
6432 host_init_sdtr_index];
6433 }
6434 if (sdtr_accept) {
6435 sdtr_data =
6436 AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
6437 ext_msg.req_ack_offset);
6438 if ((sdtr_data == 0xFF)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006439
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006440 q_cntl |= QC_MSG_OUT;
6441 asc_dvc->init_sdtr &= ~target_id;
6442 asc_dvc->sdtr_done &= ~target_id;
6443 AscSetChipSDTR(iop_base, asyn_sdtr,
6444 tid_no);
6445 boardp->sdtr_data[tid_no] = asyn_sdtr;
6446 }
6447 }
6448 if (ext_msg.req_ack_offset == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006449
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006450 q_cntl &= ~QC_MSG_OUT;
6451 asc_dvc->init_sdtr &= ~target_id;
6452 asc_dvc->sdtr_done &= ~target_id;
6453 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
6454 } else {
6455 if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006456
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006457 q_cntl &= ~QC_MSG_OUT;
6458 asc_dvc->sdtr_done |= target_id;
6459 asc_dvc->init_sdtr |= target_id;
6460 asc_dvc->pci_fix_asyn_xfer &=
6461 ~target_id;
6462 sdtr_data =
6463 AscCalSDTRData(asc_dvc,
6464 ext_msg.xfer_period,
6465 ext_msg.
6466 req_ack_offset);
6467 AscSetChipSDTR(iop_base, sdtr_data,
6468 tid_no);
6469 boardp->sdtr_data[tid_no] = sdtr_data;
6470 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006471
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006472 q_cntl |= QC_MSG_OUT;
6473 AscMsgOutSDTR(asc_dvc,
6474 ext_msg.xfer_period,
6475 ext_msg.req_ack_offset);
6476 asc_dvc->pci_fix_asyn_xfer &=
6477 ~target_id;
6478 sdtr_data =
6479 AscCalSDTRData(asc_dvc,
6480 ext_msg.xfer_period,
6481 ext_msg.
6482 req_ack_offset);
6483 AscSetChipSDTR(iop_base, sdtr_data,
6484 tid_no);
6485 boardp->sdtr_data[tid_no] = sdtr_data;
6486 asc_dvc->sdtr_done |= target_id;
6487 asc_dvc->init_sdtr |= target_id;
6488 }
6489 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006490
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006491 AscWriteLramByte(iop_base,
6492 (ushort)(halt_q_addr +
6493 (ushort)ASC_SCSIQ_B_CNTL),
6494 q_cntl);
6495 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
6496 return (0);
Matthew Wilcox47d853c2007-07-26 11:41:33 -04006497 } else if (ext_msg.msg_type == EXTENDED_MESSAGE &&
6498 ext_msg.msg_req == EXTENDED_WDTR &&
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006499 ext_msg.msg_len == MS_WDTR_LEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006500
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006501 ext_msg.wdtr_width = 0;
6502 AscMemWordCopyPtrToLram(iop_base,
6503 ASCV_MSGOUT_BEG,
6504 (uchar *)&ext_msg,
6505 sizeof(EXT_MSG) >> 1);
6506 q_cntl |= QC_MSG_OUT;
6507 AscWriteLramByte(iop_base,
6508 (ushort)(halt_q_addr +
6509 (ushort)ASC_SCSIQ_B_CNTL),
6510 q_cntl);
6511 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
6512 return (0);
6513 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006514
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006515 ext_msg.msg_type = MESSAGE_REJECT;
6516 AscMemWordCopyPtrToLram(iop_base,
6517 ASCV_MSGOUT_BEG,
6518 (uchar *)&ext_msg,
6519 sizeof(EXT_MSG) >> 1);
6520 q_cntl |= QC_MSG_OUT;
6521 AscWriteLramByte(iop_base,
6522 (ushort)(halt_q_addr +
6523 (ushort)ASC_SCSIQ_B_CNTL),
6524 q_cntl);
6525 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
6526 return (0);
6527 }
6528 } else if (int_halt_code == ASC_HALT_CHK_CONDITION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006529
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006530 q_cntl |= QC_REQ_SENSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006531
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006532 if ((asc_dvc->init_sdtr & target_id) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006533
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006534 asc_dvc->sdtr_done &= ~target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006535
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006536 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
6537 q_cntl |= QC_MSG_OUT;
6538 AscMsgOutSDTR(asc_dvc,
6539 asc_dvc->
6540 sdtr_period_tbl[(sdtr_data >> 4) &
6541 (uchar)(asc_dvc->
6542 max_sdtr_index -
6543 1)],
6544 (uchar)(sdtr_data & (uchar)
6545 ASC_SYN_MAX_OFFSET));
6546 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006547
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006548 AscWriteLramByte(iop_base,
6549 (ushort)(halt_q_addr +
6550 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006551
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006552 tag_code = AscReadLramByte(iop_base,
6553 (ushort)(halt_q_addr + (ushort)
6554 ASC_SCSIQ_B_TAG_CODE));
6555 tag_code &= 0xDC;
6556 if ((asc_dvc->pci_fix_asyn_xfer & target_id)
6557 && !(asc_dvc->pci_fix_asyn_xfer_always & target_id)
6558 ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006559
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006560 tag_code |= (ASC_TAG_FLAG_DISABLE_DISCONNECT
6561 | ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006562
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006563 }
6564 AscWriteLramByte(iop_base,
6565 (ushort)(halt_q_addr +
6566 (ushort)ASC_SCSIQ_B_TAG_CODE),
6567 tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006568
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006569 q_status = AscReadLramByte(iop_base,
6570 (ushort)(halt_q_addr + (ushort)
6571 ASC_SCSIQ_B_STATUS));
6572 q_status |= (QS_READY | QS_BUSY);
6573 AscWriteLramByte(iop_base,
6574 (ushort)(halt_q_addr +
6575 (ushort)ASC_SCSIQ_B_STATUS),
6576 q_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006577
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006578 scsi_busy = AscReadLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B);
6579 scsi_busy &= ~target_id;
6580 AscWriteLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B, scsi_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006581
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006582 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
6583 return (0);
6584 } else if (int_halt_code == ASC_HALT_SDTR_REJECTED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006585
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006586 AscMemWordCopyPtrFromLram(iop_base,
6587 ASCV_MSGOUT_BEG,
6588 (uchar *)&out_msg,
6589 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006590
Matthew Wilcox47d853c2007-07-26 11:41:33 -04006591 if ((out_msg.msg_type == EXTENDED_MESSAGE) &&
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006592 (out_msg.msg_len == MS_SDTR_LEN) &&
Matthew Wilcox47d853c2007-07-26 11:41:33 -04006593 (out_msg.msg_req == EXTENDED_SDTR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006594
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006595 asc_dvc->init_sdtr &= ~target_id;
6596 asc_dvc->sdtr_done &= ~target_id;
6597 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
6598 boardp->sdtr_data[tid_no] = asyn_sdtr;
6599 }
6600 q_cntl &= ~QC_MSG_OUT;
6601 AscWriteLramByte(iop_base,
6602 (ushort)(halt_q_addr +
6603 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
6604 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
6605 return (0);
6606 } else if (int_halt_code == ASC_HALT_SS_QUEUE_FULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006607
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006608 scsi_status = AscReadLramByte(iop_base,
6609 (ushort)((ushort)halt_q_addr +
6610 (ushort)
6611 ASC_SCSIQ_SCSI_STATUS));
6612 cur_dvc_qng =
6613 AscReadLramByte(iop_base,
6614 (ushort)((ushort)ASC_QADR_BEG +
6615 (ushort)target_ix));
6616 if ((cur_dvc_qng > 0) && (asc_dvc->cur_dvc_qng[tid_no] > 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006617
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006618 scsi_busy = AscReadLramByte(iop_base,
6619 (ushort)ASCV_SCSIBUSY_B);
6620 scsi_busy |= target_id;
6621 AscWriteLramByte(iop_base,
6622 (ushort)ASCV_SCSIBUSY_B, scsi_busy);
6623 asc_dvc->queue_full_or_busy |= target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006624
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006625 if (scsi_status == SAM_STAT_TASK_SET_FULL) {
6626 if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) {
6627 cur_dvc_qng -= 1;
6628 asc_dvc->max_dvc_qng[tid_no] =
6629 cur_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006630
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006631 AscWriteLramByte(iop_base,
6632 (ushort)((ushort)
6633 ASCV_MAX_DVC_QNG_BEG
6634 + (ushort)
6635 tid_no),
6636 cur_dvc_qng);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006637
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006638 /*
Matthew Wilcox95c9f162007-09-09 08:56:39 -06006639 * Set the device queue depth to the
6640 * number of active requests when the
6641 * QUEUE FULL condition was encountered.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006642 */
6643 boardp->queue_full |= target_id;
6644 boardp->queue_full_cnt[tid_no] =
6645 cur_dvc_qng;
6646 }
6647 }
6648 }
6649 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
6650 return (0);
6651 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006652#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006653 else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC) {
6654 uchar q_no;
6655 ushort q_addr;
6656 uchar sg_wk_q_no;
6657 uchar first_sg_wk_q_no;
6658 ASC_SCSI_Q *scsiq; /* Ptr to driver request. */
6659 ASC_SG_HEAD *sg_head; /* Ptr to driver SG request. */
6660 ASC_SG_LIST_Q scsi_sg_q; /* Structure written to queue. */
6661 ushort sg_list_dwords;
6662 ushort sg_entry_cnt;
6663 uchar next_qp;
6664 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006665
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006666 q_no = AscReadLramByte(iop_base, (ushort)ASCV_REQ_SG_LIST_QP);
Matthew Wilcox95c9f162007-09-09 08:56:39 -06006667 if (q_no == ASC_QLINK_END)
6668 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006669
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006670 q_addr = ASC_QNO_TO_QADDR(q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006671
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006672 /*
6673 * Convert the request's SRB pointer to a host ASC_SCSI_REQ
6674 * structure pointer using a macro provided by the driver.
6675 * The ASC_SCSI_REQ pointer provides a pointer to the
6676 * host ASC_SG_HEAD structure.
6677 */
6678 /* Read request's SRB pointer. */
6679 scsiq = (ASC_SCSI_Q *)
6680 ASC_SRB2SCSIQ(ASC_U32_TO_VADDR(AscReadLramDWord(iop_base,
6681 (ushort)
6682 (q_addr +
6683 ASC_SCSIQ_D_SRBPTR))));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006684
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006685 /*
6686 * Get request's first and working SG queue.
6687 */
6688 sg_wk_q_no = AscReadLramByte(iop_base,
6689 (ushort)(q_addr +
6690 ASC_SCSIQ_B_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006691
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006692 first_sg_wk_q_no = AscReadLramByte(iop_base,
6693 (ushort)(q_addr +
6694 ASC_SCSIQ_B_FIRST_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006695
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006696 /*
6697 * Reset request's working SG queue back to the
6698 * first SG queue.
6699 */
6700 AscWriteLramByte(iop_base,
6701 (ushort)(q_addr +
6702 (ushort)ASC_SCSIQ_B_SG_WK_QP),
6703 first_sg_wk_q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006704
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006705 sg_head = scsiq->sg_head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006706
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006707 /*
6708 * Set sg_entry_cnt to the number of SG elements
6709 * that will be completed on this interrupt.
6710 *
6711 * Note: The allocated SG queues contain ASC_MAX_SG_LIST - 1
6712 * SG elements. The data_cnt and data_addr fields which
6713 * add 1 to the SG element capacity are not used when
6714 * restarting SG handling after a halt.
6715 */
6716 if (scsiq->remain_sg_entry_cnt > (ASC_MAX_SG_LIST - 1)) {
6717 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006718
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006719 /*
Matthew Wilcox95c9f162007-09-09 08:56:39 -06006720 * Keep track of remaining number of SG elements that
6721 * will need to be handled on the next interrupt.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006722 */
6723 scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1);
6724 } else {
6725 sg_entry_cnt = scsiq->remain_sg_entry_cnt;
6726 scsiq->remain_sg_entry_cnt = 0;
6727 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006728
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006729 /*
6730 * Copy SG elements into the list of allocated SG queues.
6731 *
6732 * Last index completed is saved in scsiq->next_sg_index.
6733 */
6734 next_qp = first_sg_wk_q_no;
6735 q_addr = ASC_QNO_TO_QADDR(next_qp);
6736 scsi_sg_q.sg_head_qp = q_no;
6737 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
6738 for (i = 0; i < sg_head->queue_cnt; i++) {
6739 scsi_sg_q.seq_no = i + 1;
6740 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
6741 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
6742 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
6743 /*
6744 * After very first SG queue RISC FW uses next
6745 * SG queue first element then checks sg_list_cnt
6746 * against zero and then decrements, so set
6747 * sg_list_cnt 1 less than number of SG elements
6748 * in each SG queue.
6749 */
6750 scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
6751 scsi_sg_q.sg_cur_list_cnt =
6752 ASC_SG_LIST_PER_Q - 1;
6753 } else {
6754 /*
6755 * This is the last SG queue in the list of
6756 * allocated SG queues. If there are more
6757 * SG elements than will fit in the allocated
6758 * queues, then set the QCSG_SG_XFER_MORE flag.
6759 */
6760 if (scsiq->remain_sg_entry_cnt != 0) {
6761 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
6762 } else {
6763 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
6764 }
6765 /* equals sg_entry_cnt * 2 */
6766 sg_list_dwords = sg_entry_cnt << 1;
6767 scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
6768 scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
6769 sg_entry_cnt = 0;
6770 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006771
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006772 scsi_sg_q.q_no = next_qp;
6773 AscMemWordCopyPtrToLram(iop_base,
6774 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
6775 (uchar *)&scsi_sg_q,
6776 sizeof(ASC_SG_LIST_Q) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006777
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006778 AscMemDWordCopyPtrToLram(iop_base,
6779 q_addr + ASC_SGQ_LIST_BEG,
6780 (uchar *)&sg_head->
6781 sg_list[scsiq->next_sg_index],
6782 sg_list_dwords);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006783
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006784 scsiq->next_sg_index += ASC_SG_LIST_PER_Q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006785
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006786 /*
6787 * If the just completed SG queue contained the
6788 * last SG element, then no more SG queues need
6789 * to be written.
6790 */
6791 if (scsi_sg_q.cntl & QCSG_SG_XFER_END) {
6792 break;
6793 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006794
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006795 next_qp = AscReadLramByte(iop_base,
6796 (ushort)(q_addr +
6797 ASC_SCSIQ_B_FWD));
6798 q_addr = ASC_QNO_TO_QADDR(next_qp);
6799 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006800
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006801 /*
6802 * Clear the halt condition so the RISC will be restarted
6803 * after the return.
6804 */
6805 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
6806 return (0);
6807 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006808#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006809 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006810}
6811
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006812static uchar
6813_AscCopyLramScsiDoneQ(PortAddr iop_base,
6814 ushort q_addr,
6815 ASC_QDONE_INFO *scsiq, ASC_DCNT max_dma_count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006816{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006817 ushort _val;
6818 uchar sg_queue_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006819
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006820 DvcGetQinfo(iop_base,
6821 q_addr + ASC_SCSIQ_DONE_INFO_BEG,
6822 (uchar *)scsiq,
6823 (sizeof(ASC_SCSIQ_2) + sizeof(ASC_SCSIQ_3)) / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006824
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006825 _val = AscReadLramWord(iop_base,
6826 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS));
6827 scsiq->q_status = (uchar)_val;
6828 scsiq->q_no = (uchar)(_val >> 8);
6829 _val = AscReadLramWord(iop_base,
6830 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_CNTL));
6831 scsiq->cntl = (uchar)_val;
6832 sg_queue_cnt = (uchar)(_val >> 8);
6833 _val = AscReadLramWord(iop_base,
6834 (ushort)(q_addr +
6835 (ushort)ASC_SCSIQ_B_SENSE_LEN));
6836 scsiq->sense_len = (uchar)_val;
6837 scsiq->extra_bytes = (uchar)(_val >> 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006838
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006839 /*
6840 * Read high word of remain bytes from alternate location.
6841 */
6842 scsiq->remain_bytes = (((ADV_DCNT)AscReadLramWord(iop_base,
6843 (ushort)(q_addr +
6844 (ushort)
6845 ASC_SCSIQ_W_ALT_DC1)))
6846 << 16);
6847 /*
6848 * Read low word of remain bytes from original location.
6849 */
6850 scsiq->remain_bytes += AscReadLramWord(iop_base,
6851 (ushort)(q_addr + (ushort)
6852 ASC_SCSIQ_DW_REMAIN_XFER_CNT));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006853
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006854 scsiq->remain_bytes &= max_dma_count;
6855 return (sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006856}
6857
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006858static int AscIsrQDone(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006859{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006860 uchar next_qp;
6861 uchar n_q_used;
6862 uchar sg_list_qp;
6863 uchar sg_queue_cnt;
6864 uchar q_cnt;
6865 uchar done_q_tail;
6866 uchar tid_no;
6867 ASC_SCSI_BIT_ID_TYPE scsi_busy;
6868 ASC_SCSI_BIT_ID_TYPE target_id;
6869 PortAddr iop_base;
6870 ushort q_addr;
6871 ushort sg_q_addr;
6872 uchar cur_target_qng;
6873 ASC_QDONE_INFO scsiq_buf;
6874 ASC_QDONE_INFO *scsiq;
6875 int false_overrun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006876
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006877 iop_base = asc_dvc->iop_base;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006878 n_q_used = 1;
6879 scsiq = (ASC_QDONE_INFO *)&scsiq_buf;
6880 done_q_tail = (uchar)AscGetVarDoneQTail(iop_base);
6881 q_addr = ASC_QNO_TO_QADDR(done_q_tail);
6882 next_qp = AscReadLramByte(iop_base,
6883 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_FWD));
6884 if (next_qp != ASC_QLINK_END) {
6885 AscPutVarDoneQTail(iop_base, next_qp);
6886 q_addr = ASC_QNO_TO_QADDR(next_qp);
6887 sg_queue_cnt = _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq,
6888 asc_dvc->max_dma_count);
6889 AscWriteLramByte(iop_base,
6890 (ushort)(q_addr +
6891 (ushort)ASC_SCSIQ_B_STATUS),
6892 (uchar)(scsiq->
6893 q_status & (uchar)~(QS_READY |
6894 QS_ABORTED)));
6895 tid_no = ASC_TIX_TO_TID(scsiq->d2.target_ix);
6896 target_id = ASC_TIX_TO_TARGET_ID(scsiq->d2.target_ix);
6897 if ((scsiq->cntl & QC_SG_HEAD) != 0) {
6898 sg_q_addr = q_addr;
6899 sg_list_qp = next_qp;
6900 for (q_cnt = 0; q_cnt < sg_queue_cnt; q_cnt++) {
6901 sg_list_qp = AscReadLramByte(iop_base,
6902 (ushort)(sg_q_addr
6903 + (ushort)
6904 ASC_SCSIQ_B_FWD));
6905 sg_q_addr = ASC_QNO_TO_QADDR(sg_list_qp);
6906 if (sg_list_qp == ASC_QLINK_END) {
6907 AscSetLibErrorCode(asc_dvc,
6908 ASCQ_ERR_SG_Q_LINKS);
6909 scsiq->d3.done_stat = QD_WITH_ERROR;
6910 scsiq->d3.host_stat =
6911 QHSTA_D_QDONE_SG_LIST_CORRUPTED;
6912 goto FATAL_ERR_QDONE;
6913 }
6914 AscWriteLramByte(iop_base,
6915 (ushort)(sg_q_addr + (ushort)
6916 ASC_SCSIQ_B_STATUS),
6917 QS_FREE);
6918 }
6919 n_q_used = sg_queue_cnt + 1;
6920 AscPutVarDoneQTail(iop_base, sg_list_qp);
6921 }
6922 if (asc_dvc->queue_full_or_busy & target_id) {
6923 cur_target_qng = AscReadLramByte(iop_base,
6924 (ushort)((ushort)
6925 ASC_QADR_BEG
6926 + (ushort)
6927 scsiq->d2.
6928 target_ix));
6929 if (cur_target_qng < asc_dvc->max_dvc_qng[tid_no]) {
6930 scsi_busy = AscReadLramByte(iop_base, (ushort)
6931 ASCV_SCSIBUSY_B);
6932 scsi_busy &= ~target_id;
6933 AscWriteLramByte(iop_base,
6934 (ushort)ASCV_SCSIBUSY_B,
6935 scsi_busy);
6936 asc_dvc->queue_full_or_busy &= ~target_id;
6937 }
6938 }
6939 if (asc_dvc->cur_total_qng >= n_q_used) {
6940 asc_dvc->cur_total_qng -= n_q_used;
6941 if (asc_dvc->cur_dvc_qng[tid_no] != 0) {
6942 asc_dvc->cur_dvc_qng[tid_no]--;
6943 }
6944 } else {
6945 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CUR_QNG);
6946 scsiq->d3.done_stat = QD_WITH_ERROR;
6947 goto FATAL_ERR_QDONE;
6948 }
6949 if ((scsiq->d2.srb_ptr == 0UL) ||
6950 ((scsiq->q_status & QS_ABORTED) != 0)) {
6951 return (0x11);
6952 } else if (scsiq->q_status == QS_DONE) {
6953 false_overrun = FALSE;
6954 if (scsiq->extra_bytes != 0) {
6955 scsiq->remain_bytes +=
6956 (ADV_DCNT)scsiq->extra_bytes;
6957 }
6958 if (scsiq->d3.done_stat == QD_WITH_ERROR) {
6959 if (scsiq->d3.host_stat ==
6960 QHSTA_M_DATA_OVER_RUN) {
6961 if ((scsiq->
6962 cntl & (QC_DATA_IN | QC_DATA_OUT))
6963 == 0) {
6964 scsiq->d3.done_stat =
6965 QD_NO_ERROR;
6966 scsiq->d3.host_stat =
6967 QHSTA_NO_ERROR;
6968 } else if (false_overrun) {
6969 scsiq->d3.done_stat =
6970 QD_NO_ERROR;
6971 scsiq->d3.host_stat =
6972 QHSTA_NO_ERROR;
6973 }
6974 } else if (scsiq->d3.host_stat ==
6975 QHSTA_M_HUNG_REQ_SCSI_BUS_RESET) {
6976 AscStopChip(iop_base);
6977 AscSetChipControl(iop_base,
6978 (uchar)(CC_SCSI_RESET
6979 | CC_HALT));
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06006980 udelay(60);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006981 AscSetChipControl(iop_base, CC_HALT);
6982 AscSetChipStatus(iop_base,
6983 CIW_CLR_SCSI_RESET_INT);
6984 AscSetChipStatus(iop_base, 0);
6985 AscSetChipControl(iop_base, 0);
6986 }
6987 }
6988 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
Matthew Wilcox895d6b42007-07-26 11:57:06 -04006989 asc_isr_callback(asc_dvc, scsiq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006990 } else {
6991 if ((AscReadLramByte(iop_base,
6992 (ushort)(q_addr + (ushort)
6993 ASC_SCSIQ_CDB_BEG))
6994 == START_STOP)) {
6995 asc_dvc->unit_not_ready &= ~target_id;
6996 if (scsiq->d3.done_stat != QD_NO_ERROR) {
6997 asc_dvc->start_motor &=
6998 ~target_id;
6999 }
7000 }
7001 }
7002 return (1);
7003 } else {
7004 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS);
7005 FATAL_ERR_QDONE:
7006 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
Matthew Wilcox895d6b42007-07-26 11:57:06 -04007007 asc_isr_callback(asc_dvc, scsiq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007008 }
7009 return (0x80);
7010 }
7011 }
7012 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007013}
7014
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007015static int AscISR(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007016{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007017 ASC_CS_TYPE chipstat;
7018 PortAddr iop_base;
7019 ushort saved_ram_addr;
7020 uchar ctrl_reg;
7021 uchar saved_ctrl_reg;
7022 int int_pending;
7023 int status;
7024 uchar host_flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007025
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007026 iop_base = asc_dvc->iop_base;
7027 int_pending = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007028
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007029 if (AscIsIntPending(iop_base) == 0) {
7030 return int_pending;
7031 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007032
Matthew Wilcox895d6b42007-07-26 11:57:06 -04007033 if ((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007034 return (ERR);
7035 }
7036 if (asc_dvc->in_critical_cnt != 0) {
7037 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL);
7038 return (ERR);
7039 }
7040 if (asc_dvc->is_in_int) {
7041 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY);
7042 return (ERR);
7043 }
7044 asc_dvc->is_in_int = TRUE;
7045 ctrl_reg = AscGetChipControl(iop_base);
7046 saved_ctrl_reg = ctrl_reg & (~(CC_SCSI_RESET | CC_CHIP_RESET |
7047 CC_SINGLE_STEP | CC_DIAG | CC_TEST));
7048 chipstat = AscGetChipStatus(iop_base);
7049 if (chipstat & CSW_SCSI_RESET_LATCH) {
7050 if (!(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))) {
7051 int i = 10;
7052 int_pending = TRUE;
7053 asc_dvc->sdtr_done = 0;
7054 saved_ctrl_reg &= (uchar)(~CC_HALT);
7055 while ((AscGetChipStatus(iop_base) &
7056 CSW_SCSI_RESET_ACTIVE) && (i-- > 0)) {
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06007057 mdelay(100);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007058 }
7059 AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT));
7060 AscSetChipControl(iop_base, CC_HALT);
7061 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
7062 AscSetChipStatus(iop_base, 0);
7063 chipstat = AscGetChipStatus(iop_base);
7064 }
7065 }
7066 saved_ram_addr = AscGetChipLramAddr(iop_base);
7067 host_flag = AscReadLramByte(iop_base,
7068 ASCV_HOST_FLAG_B) &
7069 (uchar)(~ASC_HOST_FLAG_IN_ISR);
7070 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
7071 (uchar)(host_flag | (uchar)ASC_HOST_FLAG_IN_ISR));
7072 if ((chipstat & CSW_INT_PENDING)
7073 || (int_pending)
7074 ) {
7075 AscAckInterrupt(iop_base);
7076 int_pending = TRUE;
7077 if ((chipstat & CSW_HALTED) && (ctrl_reg & CC_SINGLE_STEP)) {
7078 if (AscIsrChipHalted(asc_dvc) == ERR) {
7079 goto ISR_REPORT_QDONE_FATAL_ERROR;
7080 } else {
7081 saved_ctrl_reg &= (uchar)(~CC_HALT);
7082 }
7083 } else {
7084 ISR_REPORT_QDONE_FATAL_ERROR:
7085 if ((asc_dvc->dvc_cntl & ASC_CNTL_INT_MULTI_Q) != 0) {
7086 while (((status =
7087 AscIsrQDone(asc_dvc)) & 0x01) != 0) {
7088 }
7089 } else {
7090 do {
7091 if ((status =
7092 AscIsrQDone(asc_dvc)) == 1) {
7093 break;
7094 }
7095 } while (status == 0x11);
7096 }
7097 if ((status & 0x80) != 0)
7098 int_pending = ERR;
7099 }
7100 }
7101 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
7102 AscSetChipLramAddr(iop_base, saved_ram_addr);
7103 AscSetChipControl(iop_base, saved_ctrl_reg);
7104 asc_dvc->is_in_int = FALSE;
7105 return (int_pending);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007106}
7107
7108/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007109static uchar _asc_mcode_buf[] = {
7110 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007111 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007112 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007113 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007114 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7115 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x12, 0x0D, 0x05,
7116 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7117 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007118 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007119 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
7120 0x00, 0x00, 0xE4, 0x88, 0x00, 0x00, 0x00, 0x00, 0x80, 0x73, 0x48, 0x04,
7121 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73, 0x03, 0x23, 0x36, 0x40,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007122 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007123 0xC2, 0x00, 0x92, 0x80, 0x1E, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x48, 0x98,
7124 0xDF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, 0x4F, 0x00, 0xF5, 0x00,
7125 0x48, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, 0x80, 0x62,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007126 0x92, 0x80, 0x00, 0x46, 0x15, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007127 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xD6, 0x00, 0xA6, 0x97, 0x7F, 0x23,
7128 0x04, 0x61, 0x84, 0x01, 0xE6, 0x84, 0xD2, 0xC1, 0x80, 0x73, 0xCD, 0x04,
7129 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x01, 0xA6, 0x97, 0xC6, 0x81, 0xC2, 0x88,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007130 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0xFE, 0x00, 0x4F, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007131 0x84, 0x97, 0x07, 0xA6, 0x08, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88,
7132 0x03, 0x03, 0x01, 0xDE, 0xC2, 0x88, 0xCE, 0x00, 0x69, 0x60, 0xCE, 0x00,
7133 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x78, 0x01, 0x80, 0x63, 0x07, 0xA6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007134 0x24, 0x01, 0x78, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007135 0x34, 0x01, 0x00, 0x33, 0x04, 0x00, 0xC2, 0x88, 0x03, 0x07, 0x02, 0x01,
7136 0x04, 0xCA, 0x0D, 0x23, 0x68, 0x98, 0x4D, 0x04, 0x04, 0x85, 0x05, 0xD8,
7137 0x0D, 0x23, 0x68, 0x98, 0xCD, 0x04, 0x15, 0x23, 0xF8, 0x88, 0xFB, 0x23,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007138 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x62, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007139 0x00, 0x33, 0x0A, 0x00, 0xC2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x6E, 0x01,
7140 0x00, 0x33, 0x0B, 0x00, 0xC2, 0x88, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33,
7141 0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x88, 0x81, 0x06, 0xAB, 0x82, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007142 0x88, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x92, 0x01, 0x50, 0x00, 0x00, 0xA3,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007143 0x3C, 0x01, 0x00, 0x05, 0x7C, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6,
7144 0x04, 0x23, 0xA0, 0x01, 0x15, 0x23, 0xA1, 0x01, 0xBE, 0x81, 0xFD, 0x23,
7145 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007146 0xB4, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007147 0xC2, 0x88, 0x06, 0x23, 0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01,
7148 0x00, 0xA2, 0xD4, 0x01, 0x57, 0x60, 0x00, 0xA0, 0xDA, 0x01, 0xE6, 0x84,
7149 0x80, 0x23, 0xA0, 0x01, 0xE6, 0x84, 0x80, 0x73, 0x4B, 0x00, 0x06, 0x61,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007150 0x00, 0xA2, 0x00, 0x02, 0x04, 0x01, 0x0C, 0xDE, 0x02, 0x01, 0x03, 0xCC,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007151 0x4F, 0x00, 0x84, 0x97, 0xFC, 0x81, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01,
7152 0x4F, 0x00, 0x62, 0x97, 0x48, 0x04, 0x84, 0x80, 0xF0, 0x97, 0x00, 0x46,
7153 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00, 0x81, 0x73, 0x06, 0x29,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007154 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x6B, 0xEB, 0x11, 0x23, 0xF8, 0x88,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007155 0x04, 0x98, 0xF0, 0x80, 0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x2A, 0x02,
7156 0x7C, 0x95, 0x06, 0xA6, 0x34, 0x02, 0x03, 0xA6, 0x4C, 0x04, 0x46, 0x82,
7157 0x04, 0x01, 0x03, 0xD8, 0xB4, 0x98, 0x6A, 0x96, 0x46, 0x82, 0xFE, 0x95,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007158 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x6C, 0x02,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007159 0x07, 0xA6, 0x5A, 0x02, 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x62, 0x02,
7160 0xC2, 0x88, 0x7C, 0x95, 0x48, 0x82, 0x60, 0x96, 0x48, 0x82, 0x04, 0x23,
7161 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84, 0x04, 0x01, 0x0C, 0xDC,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007162 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007163 0x6F, 0x00, 0xA5, 0x01, 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01,
7164 0x24, 0x2B, 0x1C, 0x01, 0x02, 0xA6, 0xAA, 0x02, 0x07, 0xA6, 0x5A, 0x02,
7165 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x20, 0x04, 0x01, 0xA6, 0xB4, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007166 0x00, 0xA6, 0xB4, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007167 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0x8C, 0x02, 0x4D, 0x04, 0x04, 0x01,
7168 0x0B, 0xDC, 0xE7, 0x23, 0x04, 0x61, 0x84, 0x01, 0x10, 0x31, 0x12, 0x35,
7169 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0xEA, 0x82,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007170 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0xA2, 0xC8,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007171 0x00, 0x33, 0x1F, 0x00, 0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39,
7172 0x0E, 0x3D, 0x7E, 0x98, 0xB6, 0x2D, 0x01, 0xA6, 0x14, 0x03, 0x00, 0xA6,
7173 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6, 0x10, 0x03, 0x03, 0xA6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007174 0x20, 0x04, 0x02, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007175 0x7C, 0x95, 0xEE, 0x82, 0x60, 0x96, 0xEE, 0x82, 0x82, 0x98, 0x80, 0x42,
7176 0x7E, 0x98, 0x64, 0xE4, 0x04, 0x01, 0x2D, 0xC8, 0x31, 0x05, 0x07, 0x01,
7177 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01, 0x05, 0x05, 0x86, 0x98,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007178 0x7E, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007179 0x3C, 0x04, 0x06, 0xA6, 0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33,
7180 0x25, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x32, 0x83, 0x60, 0x96, 0x32, 0x83,
7181 0x04, 0x01, 0x10, 0xCE, 0x07, 0xC8, 0x05, 0x05, 0xEB, 0x04, 0x00, 0x33,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007182 0x00, 0x20, 0xC0, 0x20, 0x81, 0x62, 0x72, 0x83, 0x00, 0x01, 0x05, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007183 0xFF, 0xA2, 0x7A, 0x03, 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83,
7184 0x05, 0x05, 0x15, 0x01, 0x00, 0xA2, 0x9A, 0x03, 0xEC, 0x00, 0x6E, 0x00,
7185 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0x01, 0xA6, 0x96, 0x03,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007186 0x00, 0xA6, 0x96, 0x03, 0x10, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007187 0xA4, 0x03, 0x00, 0xA6, 0xBC, 0x03, 0x10, 0x84, 0xA8, 0x98, 0x80, 0x42,
7188 0x01, 0xA6, 0xA4, 0x03, 0x07, 0xA6, 0xB2, 0x03, 0xD4, 0x83, 0x7C, 0x95,
7189 0xA8, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC2, 0x88, 0xA8, 0x98, 0x80, 0x42,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007190 0x00, 0xA6, 0xBC, 0x03, 0x07, 0xA6, 0xCA, 0x03, 0xD4, 0x83, 0x7C, 0x95,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007191 0xC0, 0x83, 0x00, 0x33, 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32,
7192 0x80, 0x36, 0x04, 0x23, 0xA0, 0x01, 0x12, 0x23, 0xA1, 0x01, 0x10, 0x84,
7193 0x07, 0xF0, 0x06, 0xA4, 0xF4, 0x03, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007194 0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x0E, 0x04, 0x07, 0xA6, 0x06, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007195 0x06, 0xA6, 0x0A, 0x04, 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x7C, 0x95,
7196 0xF4, 0x83, 0x60, 0x96, 0xF4, 0x83, 0x20, 0x84, 0x07, 0xF0, 0x06, 0xA4,
7197 0x20, 0x04, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23, 0x83, 0x03, 0x80, 0x63,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007198 0xB6, 0x2D, 0x03, 0xA6, 0x3C, 0x04, 0x07, 0xA6, 0x34, 0x04, 0x06, 0xA6,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007199 0x38, 0x04, 0x00, 0x33, 0x30, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x20, 0x84,
7200 0x60, 0x96, 0x20, 0x84, 0x1D, 0x01, 0x06, 0xCC, 0x00, 0x33, 0x00, 0x84,
7201 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62, 0xA2, 0x0D, 0x80, 0x63,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007202 0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007203 0x80, 0x63, 0xA3, 0x01, 0x07, 0xA4, 0x64, 0x04, 0x23, 0x01, 0x00, 0xA2,
7204 0x86, 0x04, 0x0A, 0xA0, 0x76, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1D, 0x00,
7205 0xC2, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1E, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007206 0xC2, 0x88, 0x42, 0x23, 0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007207 0x08, 0x23, 0x22, 0xA3, 0xA2, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xAE, 0x04,
7208 0x02, 0x23, 0x22, 0xA3, 0xC4, 0x04, 0x42, 0x23, 0xF8, 0x88, 0x4A, 0x00,
7209 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23, 0xF8, 0x88, 0x04, 0x98,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007210 0x00, 0xA2, 0xC0, 0x04, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007211 0x81, 0x62, 0xE8, 0x81, 0x47, 0x23, 0xF8, 0x88, 0x04, 0x01, 0x0B, 0xDE,
7212 0x04, 0x98, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x81, 0xC0, 0x20, 0x81, 0x62,
7213 0x14, 0x01, 0x00, 0xA0, 0x00, 0x02, 0x43, 0x23, 0xF8, 0x88, 0x04, 0x23,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007214 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007215 0xF4, 0x04, 0x00, 0x33, 0x27, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x04, 0xDC,
7216 0x02, 0x23, 0xA2, 0x01, 0x04, 0x23, 0xA0, 0x01, 0x04, 0x98, 0x26, 0x95,
7217 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00, 0x00, 0xA3, 0x22, 0x05,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007218 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x1C, 0x05, 0x0A, 0x85,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007219 0x46, 0x97, 0xCD, 0x04, 0x24, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01,
7220 0x03, 0xDA, 0x80, 0x23, 0x82, 0x01, 0x34, 0x85, 0x02, 0x23, 0xA0, 0x01,
7221 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x40, 0x05, 0x1D, 0x01, 0x04, 0xD6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007222 0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007223 0x49, 0x00, 0x81, 0x01, 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01,
7224 0xF7, 0x04, 0x03, 0x01, 0x49, 0x04, 0x80, 0x01, 0xC9, 0x00, 0x00, 0x05,
7225 0x00, 0x01, 0xFF, 0xA0, 0x60, 0x05, 0x77, 0x04, 0x01, 0x23, 0xEA, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007226 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007227 0x07, 0xA4, 0xF8, 0x05, 0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85,
7228 0x00, 0x33, 0x2D, 0x00, 0xC2, 0x88, 0x04, 0xA0, 0xB8, 0x05, 0x80, 0x63,
7229 0x00, 0x23, 0xDF, 0x00, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0xA4, 0x05,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007230 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007231 0x62, 0x97, 0x04, 0x85, 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0x04, 0x85,
7232 0x08, 0xA0, 0xBE, 0x05, 0xF4, 0x85, 0x03, 0xA0, 0xC4, 0x05, 0xF4, 0x85,
7233 0x01, 0xA0, 0xCE, 0x05, 0x88, 0x00, 0x80, 0x63, 0xCC, 0x86, 0x07, 0xA0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007234 0xEE, 0x05, 0x5F, 0x00, 0x00, 0x2B, 0xDF, 0x08, 0x00, 0xA2, 0xE6, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007235 0x80, 0x67, 0x80, 0x63, 0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23,
7236 0x68, 0x98, 0x48, 0x23, 0xF8, 0x88, 0x07, 0x23, 0x80, 0x00, 0x06, 0x87,
7237 0x80, 0x63, 0x7C, 0x85, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63, 0x4A, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007238 0x06, 0x61, 0x00, 0xA2, 0x36, 0x06, 0x1D, 0x01, 0x16, 0xD4, 0xC0, 0x23,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007239 0x07, 0x41, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33,
7240 0x37, 0x00, 0xC2, 0x88, 0x1D, 0x01, 0x01, 0xD6, 0x20, 0x23, 0x63, 0x60,
7241 0x83, 0x03, 0x80, 0x63, 0x02, 0x23, 0xDF, 0x00, 0x07, 0xA6, 0x7C, 0x05,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007242 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007243 0x52, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x4E, 0x06, 0x1D, 0x01, 0x03, 0xCA,
7244 0xC0, 0x23, 0x07, 0x41, 0x00, 0x63, 0x1D, 0x01, 0x04, 0xCC, 0x00, 0x33,
7245 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23, 0x07, 0x41, 0x00, 0x63,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007246 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x01, 0x23,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007247 0xDF, 0x00, 0x06, 0xA6, 0x84, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67,
7248 0x80, 0x63, 0x00, 0x33, 0x00, 0x40, 0xC0, 0x20, 0x81, 0x62, 0x00, 0x63,
7249 0x00, 0x00, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x94, 0x06,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007250 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x00, 0x01, 0xA0, 0x14, 0x07, 0x00, 0x2B,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007251 0x40, 0x0E, 0x80, 0x63, 0x01, 0x00, 0x06, 0xA6, 0xAA, 0x06, 0x07, 0xA6,
7252 0x7C, 0x05, 0x40, 0x0E, 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0xA2, 0x06,
7253 0x06, 0xA6, 0xBC, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x40, 0x0E,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007254 0x80, 0x63, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007255 0x07, 0xA6, 0xD6, 0x06, 0x00, 0x33, 0x2A, 0x00, 0xC2, 0x88, 0x03, 0x03,
7256 0x80, 0x63, 0x89, 0x00, 0x0A, 0x2B, 0x07, 0xA6, 0xE8, 0x06, 0x00, 0x33,
7257 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, 0x00, 0xA2, 0xF4, 0x06, 0xC0, 0x0E,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007258 0x80, 0x63, 0xDE, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007259 0x81, 0x62, 0x04, 0x01, 0x02, 0xDA, 0x80, 0x63, 0x7C, 0x85, 0x80, 0x7B,
7260 0x80, 0x63, 0x06, 0xA6, 0x8C, 0x06, 0x00, 0x33, 0x2C, 0x00, 0xC2, 0x88,
7261 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007262 0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007263 0x00, 0x00, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x44, 0x07,
7264 0x07, 0xA6, 0x7C, 0x05, 0xBF, 0x23, 0x04, 0x61, 0x84, 0x01, 0xE6, 0x84,
7265 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x00, 0x01, 0xF2, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007266 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007267 0x80, 0x05, 0x81, 0x05, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04,
7268 0x01, 0x01, 0xF1, 0x00, 0x70, 0x00, 0x81, 0x01, 0x70, 0x04, 0x71, 0x00,
7269 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04, 0x70, 0x00, 0x80, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007270 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007271 0xF1, 0x00, 0x70, 0x00, 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01,
7272 0x72, 0x00, 0x81, 0x01, 0x71, 0x04, 0x70, 0x00, 0x81, 0x01, 0x70, 0x04,
7273 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05, 0xA3, 0x01, 0xA2, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007274 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007275 0xC4, 0x07, 0x00, 0x33, 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05,
7276 0x04, 0x01, 0x11, 0xC8, 0x48, 0x00, 0xB0, 0x01, 0xB1, 0x01, 0x08, 0x23,
7277 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43, 0x00, 0xA2, 0xE4, 0x07,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007278 0x00, 0x05, 0xDA, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007279 0x05, 0x05, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04,
7280 0x00, 0x02, 0x80, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04, 0x00, 0x63,
7281 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x00, 0xA0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007282 0x14, 0x08, 0x16, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007283 0x00, 0x63, 0xF3, 0x04, 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43,
7284 0xF4, 0x00, 0xCF, 0x40, 0x00, 0xA2, 0x44, 0x08, 0x74, 0x04, 0x02, 0x01,
7285 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1, 0x24, 0x08, 0x04, 0x98,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007286 0x26, 0x95, 0x24, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007287 0x5A, 0x88, 0x02, 0x01, 0x04, 0xD8, 0x46, 0x97, 0x04, 0x98, 0x26, 0x95,
7288 0x4A, 0x88, 0x75, 0x00, 0x00, 0xA3, 0x64, 0x08, 0x00, 0x05, 0x4E, 0x88,
7289 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x76, 0x08,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007290 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007291 0x00, 0x63, 0x38, 0x2B, 0x9C, 0x88, 0x38, 0x2B, 0x92, 0x88, 0x32, 0x09,
7292 0x31, 0x05, 0x92, 0x98, 0x05, 0x05, 0xB2, 0x09, 0x00, 0x63, 0x00, 0x32,
7293 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63, 0x80, 0x32, 0x80, 0x36,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007294 0x80, 0x3A, 0x80, 0x3E, 0xB4, 0x3D, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007295 0x40, 0x36, 0x40, 0x3A, 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40,
7296 0x00, 0xA0, 0xB4, 0x08, 0x5D, 0x00, 0xFE, 0xC3, 0x00, 0x63, 0x80, 0x73,
7297 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73, 0xFF, 0xFD, 0x80, 0x73,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007298 0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06007299 0xA1, 0x23, 0xA1, 0x01, 0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77,
7300 0x68, 0x00, 0x00, 0xA2, 0x80, 0x00, 0x03, 0xC2, 0xF1, 0xC7, 0x41, 0x23,
7301 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xE6, 0x84,
Linus Torvalds1da177e2005-04-16 15:20:36 -07007302};
7303
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007304static ushort _asc_mcode_size = sizeof(_asc_mcode_buf);
7305static ADV_DCNT _asc_mcode_chksum = 0x012C453FUL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007306
7307#define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007308static uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = {
7309 INQUIRY,
7310 REQUEST_SENSE,
7311 READ_CAPACITY,
7312 READ_TOC,
7313 MODE_SELECT,
7314 MODE_SENSE,
7315 MODE_SELECT_10,
7316 MODE_SENSE_10,
7317 0xFF,
7318 0xFF,
7319 0xFF,
7320 0xFF,
7321 0xFF,
7322 0xFF,
7323 0xFF,
7324 0xFF
Linus Torvalds1da177e2005-04-16 15:20:36 -07007325};
7326
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007327static int AscExeScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007328{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007329 PortAddr iop_base;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007330 int sta;
7331 int n_q_required;
7332 int disable_syn_offset_one_fix;
7333 int i;
7334 ASC_PADDR addr;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007335 ushort sg_entry_cnt = 0;
7336 ushort sg_entry_cnt_minus_one = 0;
7337 uchar target_ix;
7338 uchar tid_no;
7339 uchar sdtr_data;
7340 uchar extra_bytes;
7341 uchar scsi_cmd;
7342 uchar disable_cmd;
7343 ASC_SG_HEAD *sg_head;
7344 ASC_DCNT data_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007345
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007346 iop_base = asc_dvc->iop_base;
7347 sg_head = scsiq->sg_head;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007348 if (asc_dvc->err_code != 0)
7349 return (ERR);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007350 scsiq->q1.q_no = 0;
7351 if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
7352 scsiq->q1.extra_bytes = 0;
7353 }
7354 sta = 0;
7355 target_ix = scsiq->q2.target_ix;
7356 tid_no = ASC_TIX_TO_TID(target_ix);
7357 n_q_required = 1;
7358 if (scsiq->cdbptr[0] == REQUEST_SENSE) {
7359 if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
7360 asc_dvc->sdtr_done &= ~scsiq->q1.target_id;
7361 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
7362 AscMsgOutSDTR(asc_dvc,
7363 asc_dvc->
7364 sdtr_period_tbl[(sdtr_data >> 4) &
7365 (uchar)(asc_dvc->
7366 max_sdtr_index -
7367 1)],
7368 (uchar)(sdtr_data & (uchar)
7369 ASC_SYN_MAX_OFFSET));
7370 scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
7371 }
7372 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007373 if (asc_dvc->in_critical_cnt != 0) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007374 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY);
7375 return (ERR);
7376 }
7377 asc_dvc->in_critical_cnt++;
7378 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
7379 if ((sg_entry_cnt = sg_head->entry_cnt) == 0) {
7380 asc_dvc->in_critical_cnt--;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007381 return (ERR);
7382 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007383#if !CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007384 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
7385 asc_dvc->in_critical_cnt--;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007386 return (ERR);
7387 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007388#endif /* !CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007389 if (sg_entry_cnt == 1) {
7390 scsiq->q1.data_addr =
7391 (ADV_PADDR)sg_head->sg_list[0].addr;
7392 scsiq->q1.data_cnt =
7393 (ADV_DCNT)sg_head->sg_list[0].bytes;
7394 scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
7395 }
7396 sg_entry_cnt_minus_one = sg_entry_cnt - 1;
7397 }
7398 scsi_cmd = scsiq->cdbptr[0];
7399 disable_syn_offset_one_fix = FALSE;
7400 if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) &&
7401 !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) {
7402 if (scsiq->q1.cntl & QC_SG_HEAD) {
7403 data_cnt = 0;
7404 for (i = 0; i < sg_entry_cnt; i++) {
7405 data_cnt +=
7406 (ADV_DCNT)le32_to_cpu(sg_head->sg_list[i].
7407 bytes);
7408 }
7409 } else {
7410 data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
7411 }
7412 if (data_cnt != 0UL) {
7413 if (data_cnt < 512UL) {
7414 disable_syn_offset_one_fix = TRUE;
7415 } else {
7416 for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST;
7417 i++) {
7418 disable_cmd =
7419 _syn_offset_one_disable_cmd[i];
7420 if (disable_cmd == 0xFF) {
7421 break;
7422 }
7423 if (scsi_cmd == disable_cmd) {
7424 disable_syn_offset_one_fix =
7425 TRUE;
7426 break;
7427 }
7428 }
7429 }
7430 }
7431 }
7432 if (disable_syn_offset_one_fix) {
7433 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
7434 scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX |
7435 ASC_TAG_FLAG_DISABLE_DISCONNECT);
7436 } else {
7437 scsiq->q2.tag_code &= 0x27;
7438 }
7439 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
7440 if (asc_dvc->bug_fix_cntl) {
7441 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
7442 if ((scsi_cmd == READ_6) ||
7443 (scsi_cmd == READ_10)) {
7444 addr =
7445 (ADV_PADDR)le32_to_cpu(sg_head->
7446 sg_list
7447 [sg_entry_cnt_minus_one].
7448 addr) +
7449 (ADV_DCNT)le32_to_cpu(sg_head->
7450 sg_list
7451 [sg_entry_cnt_minus_one].
7452 bytes);
7453 extra_bytes =
7454 (uchar)((ushort)addr & 0x0003);
7455 if ((extra_bytes != 0)
7456 &&
7457 ((scsiq->q2.
7458 tag_code &
7459 ASC_TAG_FLAG_EXTRA_BYTES)
7460 == 0)) {
7461 scsiq->q2.tag_code |=
7462 ASC_TAG_FLAG_EXTRA_BYTES;
7463 scsiq->q1.extra_bytes =
7464 extra_bytes;
7465 data_cnt =
7466 le32_to_cpu(sg_head->
7467 sg_list
7468 [sg_entry_cnt_minus_one].
7469 bytes);
7470 data_cnt -=
7471 (ASC_DCNT) extra_bytes;
7472 sg_head->
7473 sg_list
7474 [sg_entry_cnt_minus_one].
7475 bytes =
7476 cpu_to_le32(data_cnt);
7477 }
7478 }
7479 }
7480 }
7481 sg_head->entry_to_copy = sg_head->entry_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007482#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007483 /*
7484 * Set the sg_entry_cnt to the maximum possible. The rest of
7485 * the SG elements will be copied when the RISC completes the
7486 * SG elements that fit and halts.
7487 */
7488 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
7489 sg_entry_cnt = ASC_MAX_SG_LIST;
7490 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007491#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007492 n_q_required = AscSgListToQueue(sg_entry_cnt);
7493 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
7494 (uint) n_q_required)
7495 || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
7496 if ((sta =
7497 AscSendScsiQueue(asc_dvc, scsiq,
7498 n_q_required)) == 1) {
7499 asc_dvc->in_critical_cnt--;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007500 return (sta);
7501 }
7502 }
7503 } else {
7504 if (asc_dvc->bug_fix_cntl) {
7505 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
7506 if ((scsi_cmd == READ_6) ||
7507 (scsi_cmd == READ_10)) {
7508 addr =
7509 le32_to_cpu(scsiq->q1.data_addr) +
7510 le32_to_cpu(scsiq->q1.data_cnt);
7511 extra_bytes =
7512 (uchar)((ushort)addr & 0x0003);
7513 if ((extra_bytes != 0)
7514 &&
7515 ((scsiq->q2.
7516 tag_code &
7517 ASC_TAG_FLAG_EXTRA_BYTES)
7518 == 0)) {
7519 data_cnt =
7520 le32_to_cpu(scsiq->q1.
7521 data_cnt);
7522 if (((ushort)data_cnt & 0x01FF)
7523 == 0) {
7524 scsiq->q2.tag_code |=
7525 ASC_TAG_FLAG_EXTRA_BYTES;
7526 data_cnt -= (ASC_DCNT)
7527 extra_bytes;
7528 scsiq->q1.data_cnt =
7529 cpu_to_le32
7530 (data_cnt);
7531 scsiq->q1.extra_bytes =
7532 extra_bytes;
7533 }
7534 }
7535 }
7536 }
7537 }
7538 n_q_required = 1;
7539 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) ||
7540 ((scsiq->q1.cntl & QC_URGENT) != 0)) {
7541 if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
7542 n_q_required)) == 1) {
7543 asc_dvc->in_critical_cnt--;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007544 return (sta);
7545 }
7546 }
7547 }
7548 asc_dvc->in_critical_cnt--;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007549 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007550}
7551
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007552static int
7553AscSendScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar n_q_required)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007554{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007555 PortAddr iop_base;
7556 uchar free_q_head;
7557 uchar next_qp;
7558 uchar tid_no;
7559 uchar target_ix;
7560 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007561
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007562 iop_base = asc_dvc->iop_base;
7563 target_ix = scsiq->q2.target_ix;
7564 tid_no = ASC_TIX_TO_TID(target_ix);
7565 sta = 0;
7566 free_q_head = (uchar)AscGetVarFreeQHead(iop_base);
7567 if (n_q_required > 1) {
Matthew Wilcox95c9f162007-09-09 08:56:39 -06007568 next_qp = AscAllocMultipleFreeQueue(iop_base, free_q_head,
7569 (uchar)n_q_required);
7570 if (next_qp != ASC_QLINK_END) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007571 asc_dvc->last_q_shortage = 0;
7572 scsiq->sg_head->queue_cnt = n_q_required - 1;
7573 scsiq->q1.q_no = free_q_head;
Matthew Wilcox95c9f162007-09-09 08:56:39 -06007574 sta = AscPutReadySgListQueue(asc_dvc, scsiq,
7575 free_q_head);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007576 }
7577 } else if (n_q_required == 1) {
Matthew Wilcox95c9f162007-09-09 08:56:39 -06007578 next_qp = AscAllocFreeQueue(iop_base, free_q_head);
7579 if (next_qp != ASC_QLINK_END) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007580 scsiq->q1.q_no = free_q_head;
Matthew Wilcox95c9f162007-09-09 08:56:39 -06007581 sta = AscPutReadyQueue(asc_dvc, scsiq, free_q_head);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007582 }
7583 }
Matthew Wilcox95c9f162007-09-09 08:56:39 -06007584 if (sta == 1) {
7585 AscPutVarFreeQHead(iop_base, next_qp);
7586 asc_dvc->cur_total_qng += (uchar)(n_q_required);
7587 asc_dvc->cur_dvc_qng[tid_no]++;
7588 }
7589 return sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007590}
7591
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007592static int AscSgListToQueue(int sg_list)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007593{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007594 int n_sg_list_qs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007595
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007596 n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q);
7597 if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0)
7598 n_sg_list_qs++;
7599 return (n_sg_list_qs + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007600}
7601
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007602static uint
7603AscGetNumOfFreeQueue(ASC_DVC_VAR *asc_dvc, uchar target_ix, uchar n_qs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007604{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007605 uint cur_used_qs;
7606 uint cur_free_qs;
7607 ASC_SCSI_BIT_ID_TYPE target_id;
7608 uchar tid_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007609
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007610 target_id = ASC_TIX_TO_TARGET_ID(target_ix);
7611 tid_no = ASC_TIX_TO_TID(target_ix);
7612 if ((asc_dvc->unit_not_ready & target_id) ||
7613 (asc_dvc->queue_full_or_busy & target_id)) {
7614 return (0);
7615 }
7616 if (n_qs == 1) {
7617 cur_used_qs = (uint) asc_dvc->cur_total_qng +
7618 (uint) asc_dvc->last_q_shortage + (uint) ASC_MIN_FREE_Q;
7619 } else {
7620 cur_used_qs = (uint) asc_dvc->cur_total_qng +
7621 (uint) ASC_MIN_FREE_Q;
7622 }
7623 if ((uint) (cur_used_qs + n_qs) <= (uint) asc_dvc->max_total_qng) {
7624 cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs;
7625 if (asc_dvc->cur_dvc_qng[tid_no] >=
7626 asc_dvc->max_dvc_qng[tid_no]) {
7627 return (0);
7628 }
7629 return (cur_free_qs);
7630 }
7631 if (n_qs > 1) {
7632 if ((n_qs > asc_dvc->last_q_shortage)
7633 && (n_qs <= (asc_dvc->max_total_qng - ASC_MIN_FREE_Q))) {
7634 asc_dvc->last_q_shortage = n_qs;
7635 }
7636 }
7637 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007638}
7639
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007640static int AscPutReadyQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007641{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007642 ushort q_addr;
7643 uchar tid_no;
7644 uchar sdtr_data;
7645 uchar syn_period_ix;
7646 uchar syn_offset;
7647 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007648
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007649 iop_base = asc_dvc->iop_base;
7650 if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) &&
7651 ((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) {
7652 tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix);
7653 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
7654 syn_period_ix =
7655 (sdtr_data >> 4) & (asc_dvc->max_sdtr_index - 1);
7656 syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET;
7657 AscMsgOutSDTR(asc_dvc,
7658 asc_dvc->sdtr_period_tbl[syn_period_ix],
7659 syn_offset);
7660 scsiq->q1.cntl |= QC_MSG_OUT;
7661 }
7662 q_addr = ASC_QNO_TO_QADDR(q_no);
7663 if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) {
7664 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
7665 }
7666 scsiq->q1.status = QS_FREE;
7667 AscMemWordCopyPtrToLram(iop_base,
7668 q_addr + ASC_SCSIQ_CDB_BEG,
7669 (uchar *)scsiq->cdbptr, scsiq->q2.cdb_len >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007670
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007671 DvcPutScsiQ(iop_base,
7672 q_addr + ASC_SCSIQ_CPY_BEG,
7673 (uchar *)&scsiq->q1.cntl,
7674 ((sizeof(ASC_SCSIQ_1) + sizeof(ASC_SCSIQ_2)) / 2) - 1);
7675 AscWriteLramWord(iop_base,
7676 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS),
7677 (ushort)(((ushort)scsiq->q1.
7678 q_no << 8) | (ushort)QS_READY));
7679 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007680}
7681
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007682static int
7683AscPutReadySgListQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007684{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007685 int sta;
7686 int i;
7687 ASC_SG_HEAD *sg_head;
7688 ASC_SG_LIST_Q scsi_sg_q;
7689 ASC_DCNT saved_data_addr;
7690 ASC_DCNT saved_data_cnt;
7691 PortAddr iop_base;
7692 ushort sg_list_dwords;
7693 ushort sg_index;
7694 ushort sg_entry_cnt;
7695 ushort q_addr;
7696 uchar next_qp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007697
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007698 iop_base = asc_dvc->iop_base;
7699 sg_head = scsiq->sg_head;
7700 saved_data_addr = scsiq->q1.data_addr;
7701 saved_data_cnt = scsiq->q1.data_cnt;
7702 scsiq->q1.data_addr = (ASC_PADDR) sg_head->sg_list[0].addr;
7703 scsiq->q1.data_cnt = (ASC_DCNT) sg_head->sg_list[0].bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007704#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007705 /*
7706 * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST
7707 * then not all SG elements will fit in the allocated queues.
7708 * The rest of the SG elements will be copied when the RISC
7709 * completes the SG elements that fit and halts.
7710 */
7711 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
7712 /*
7713 * Set sg_entry_cnt to be the number of SG elements that
7714 * will fit in the allocated SG queues. It is minus 1, because
7715 * the first SG element is handled above. ASC_MAX_SG_LIST is
7716 * already inflated by 1 to account for this. For example it
7717 * may be 50 which is 1 + 7 queues * 7 SG elements.
7718 */
7719 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007720
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007721 /*
7722 * Keep track of remaining number of SG elements that will
7723 * need to be handled from a_isr.c.
7724 */
7725 scsiq->remain_sg_entry_cnt =
7726 sg_head->entry_cnt - ASC_MAX_SG_LIST;
7727 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007728#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007729 /*
7730 * Set sg_entry_cnt to be the number of SG elements that
7731 * will fit in the allocated SG queues. It is minus 1, because
7732 * the first SG element is handled above.
7733 */
7734 sg_entry_cnt = sg_head->entry_cnt - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007735#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007736 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007737#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007738 if (sg_entry_cnt != 0) {
7739 scsiq->q1.cntl |= QC_SG_HEAD;
7740 q_addr = ASC_QNO_TO_QADDR(q_no);
7741 sg_index = 1;
7742 scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
7743 scsi_sg_q.sg_head_qp = q_no;
7744 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
7745 for (i = 0; i < sg_head->queue_cnt; i++) {
7746 scsi_sg_q.seq_no = i + 1;
7747 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
7748 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
7749 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
7750 if (i == 0) {
7751 scsi_sg_q.sg_list_cnt =
7752 ASC_SG_LIST_PER_Q;
7753 scsi_sg_q.sg_cur_list_cnt =
7754 ASC_SG_LIST_PER_Q;
7755 } else {
7756 scsi_sg_q.sg_list_cnt =
7757 ASC_SG_LIST_PER_Q - 1;
7758 scsi_sg_q.sg_cur_list_cnt =
7759 ASC_SG_LIST_PER_Q - 1;
7760 }
7761 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007762#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007763 /*
7764 * This is the last SG queue in the list of
7765 * allocated SG queues. If there are more
7766 * SG elements than will fit in the allocated
7767 * queues, then set the QCSG_SG_XFER_MORE flag.
7768 */
7769 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
7770 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
7771 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007772#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007773 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007774#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007775 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007776#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007777 sg_list_dwords = sg_entry_cnt << 1;
7778 if (i == 0) {
7779 scsi_sg_q.sg_list_cnt = sg_entry_cnt;
7780 scsi_sg_q.sg_cur_list_cnt =
7781 sg_entry_cnt;
7782 } else {
7783 scsi_sg_q.sg_list_cnt =
7784 sg_entry_cnt - 1;
7785 scsi_sg_q.sg_cur_list_cnt =
7786 sg_entry_cnt - 1;
7787 }
7788 sg_entry_cnt = 0;
7789 }
7790 next_qp = AscReadLramByte(iop_base,
7791 (ushort)(q_addr +
7792 ASC_SCSIQ_B_FWD));
7793 scsi_sg_q.q_no = next_qp;
7794 q_addr = ASC_QNO_TO_QADDR(next_qp);
7795 AscMemWordCopyPtrToLram(iop_base,
7796 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
7797 (uchar *)&scsi_sg_q,
7798 sizeof(ASC_SG_LIST_Q) >> 1);
7799 AscMemDWordCopyPtrToLram(iop_base,
7800 q_addr + ASC_SGQ_LIST_BEG,
7801 (uchar *)&sg_head->
7802 sg_list[sg_index],
7803 sg_list_dwords);
7804 sg_index += ASC_SG_LIST_PER_Q;
7805 scsiq->next_sg_index = sg_index;
7806 }
7807 } else {
7808 scsiq->q1.cntl &= ~QC_SG_HEAD;
7809 }
7810 sta = AscPutReadyQueue(asc_dvc, scsiq, q_no);
7811 scsiq->q1.data_addr = saved_data_addr;
7812 scsiq->q1.data_cnt = saved_data_cnt;
7813 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007814}
7815
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007816static int
7817AscSetRunChipSynRegAtID(PortAddr iop_base, uchar tid_no, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007818{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007819 int sta = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007820
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007821 if (AscHostReqRiscHalt(iop_base)) {
7822 sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
7823 AscStartChip(iop_base);
7824 return (sta);
7825 }
7826 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007827}
7828
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007829static int AscSetChipSynRegAtID(PortAddr iop_base, uchar id, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007830{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007831 ASC_SCSI_BIT_ID_TYPE org_id;
7832 int i;
7833 int sta = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007834
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007835 AscSetBank(iop_base, 1);
7836 org_id = AscReadChipDvcID(iop_base);
7837 for (i = 0; i <= ASC_MAX_TID; i++) {
7838 if (org_id == (0x01 << i))
7839 break;
7840 }
7841 org_id = (ASC_SCSI_BIT_ID_TYPE) i;
7842 AscWriteChipDvcID(iop_base, id);
7843 if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
7844 AscSetBank(iop_base, 0);
7845 AscSetChipSyn(iop_base, sdtr_data);
7846 if (AscGetChipSyn(iop_base) != sdtr_data) {
7847 sta = FALSE;
7848 }
7849 } else {
7850 sta = FALSE;
7851 }
7852 AscSetBank(iop_base, 1);
7853 AscWriteChipDvcID(iop_base, org_id);
7854 AscSetBank(iop_base, 0);
7855 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007856}
7857
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007858static ushort AscInitLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007859{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007860 uchar i;
7861 ushort s_addr;
7862 PortAddr iop_base;
7863 ushort warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007864
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007865 iop_base = asc_dvc->iop_base;
7866 warn_code = 0;
7867 AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0,
7868 (ushort)(((int)(asc_dvc->max_total_qng + 2 + 1) *
7869 64) >> 1)
7870 );
7871 i = ASC_MIN_ACTIVE_QNO;
7872 s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE;
7873 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
7874 (uchar)(i + 1));
7875 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
7876 (uchar)(asc_dvc->max_total_qng));
7877 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
7878 (uchar)i);
7879 i++;
7880 s_addr += ASC_QBLK_SIZE;
7881 for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) {
7882 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
7883 (uchar)(i + 1));
7884 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
7885 (uchar)(i - 1));
7886 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
7887 (uchar)i);
7888 }
7889 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
7890 (uchar)ASC_QLINK_END);
7891 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
7892 (uchar)(asc_dvc->max_total_qng - 1));
7893 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
7894 (uchar)asc_dvc->max_total_qng);
7895 i++;
7896 s_addr += ASC_QBLK_SIZE;
7897 for (; i <= (uchar)(asc_dvc->max_total_qng + 3);
7898 i++, s_addr += ASC_QBLK_SIZE) {
7899 AscWriteLramByte(iop_base,
7900 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_FWD), i);
7901 AscWriteLramByte(iop_base,
7902 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_BWD), i);
7903 AscWriteLramByte(iop_base,
7904 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_QNO), i);
7905 }
7906 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007907}
7908
Matthew Wilcox95c9f162007-09-09 08:56:39 -06007909static void AscInitQLinkVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007910{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007911 PortAddr iop_base;
7912 int i;
7913 ushort lram_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007914
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007915 iop_base = asc_dvc->iop_base;
7916 AscPutRiscVarFreeQHead(iop_base, 1);
7917 AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng);
7918 AscPutVarFreeQHead(iop_base, 1);
7919 AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng);
7920 AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B,
7921 (uchar)((int)asc_dvc->max_total_qng + 1));
7922 AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B,
7923 (uchar)((int)asc_dvc->max_total_qng + 2));
7924 AscWriteLramByte(iop_base, (ushort)ASCV_TOTAL_READY_Q_B,
7925 asc_dvc->max_total_qng);
7926 AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0);
7927 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
7928 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
7929 AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0);
7930 AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0);
7931 AscPutQDoneInProgress(iop_base, 0);
7932 lram_addr = ASC_QADR_BEG;
7933 for (i = 0; i < 32; i++, lram_addr += 2) {
7934 AscWriteLramWord(iop_base, lram_addr, 0);
7935 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007936}
7937
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007938static int AscSetLibErrorCode(ASC_DVC_VAR *asc_dvc, ushort err_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007939{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007940 if (asc_dvc->err_code == 0) {
7941 asc_dvc->err_code = err_code;
7942 AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W,
7943 err_code);
7944 }
7945 return (err_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007946}
7947
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007948static uchar
7949AscMsgOutSDTR(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar sdtr_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007950{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007951 EXT_MSG sdtr_buf;
7952 uchar sdtr_period_index;
7953 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007954
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007955 iop_base = asc_dvc->iop_base;
Matthew Wilcox47d853c2007-07-26 11:41:33 -04007956 sdtr_buf.msg_type = EXTENDED_MESSAGE;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007957 sdtr_buf.msg_len = MS_SDTR_LEN;
Matthew Wilcox47d853c2007-07-26 11:41:33 -04007958 sdtr_buf.msg_req = EXTENDED_SDTR;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007959 sdtr_buf.xfer_period = sdtr_period;
7960 sdtr_offset &= ASC_SYN_MAX_OFFSET;
7961 sdtr_buf.req_ack_offset = sdtr_offset;
7962 if ((sdtr_period_index =
7963 AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <=
7964 asc_dvc->max_sdtr_index) {
7965 AscMemWordCopyPtrToLram(iop_base,
7966 ASCV_MSGOUT_BEG,
7967 (uchar *)&sdtr_buf,
7968 sizeof(EXT_MSG) >> 1);
7969 return ((sdtr_period_index << 4) | sdtr_offset);
7970 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007971
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007972 sdtr_buf.req_ack_offset = 0;
7973 AscMemWordCopyPtrToLram(iop_base,
7974 ASCV_MSGOUT_BEG,
7975 (uchar *)&sdtr_buf,
7976 sizeof(EXT_MSG) >> 1);
7977 return (0);
7978 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007979}
7980
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007981static uchar
7982AscCalSDTRData(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar syn_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007983{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007984 uchar byte;
7985 uchar sdtr_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007986
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007987 sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
7988 if ((sdtr_period_ix > asc_dvc->max_sdtr_index)
7989 ) {
7990 return (0xFF);
7991 }
7992 byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET);
7993 return (byte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007994}
7995
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007996static void AscSetChipSDTR(PortAddr iop_base, uchar sdtr_data, uchar tid_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007997{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007998 AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
7999 AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data);
8000 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008001}
8002
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008003static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *asc_dvc, uchar syn_time)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008004{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008005 uchar *period_table;
8006 int max_index;
8007 int min_index;
8008 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008009
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008010 period_table = asc_dvc->sdtr_period_tbl;
8011 max_index = (int)asc_dvc->max_sdtr_index;
8012 min_index = (int)asc_dvc->host_init_sdtr_index;
8013 if ((syn_time <= period_table[max_index])) {
8014 for (i = min_index; i < (max_index - 1); i++) {
8015 if (syn_time <= period_table[i]) {
8016 return ((uchar)i);
8017 }
8018 }
8019 return ((uchar)max_index);
8020 } else {
8021 return ((uchar)(max_index + 1));
8022 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008023}
8024
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008025static uchar AscAllocFreeQueue(PortAddr iop_base, uchar free_q_head)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008026{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008027 ushort q_addr;
8028 uchar next_qp;
8029 uchar q_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008030
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008031 q_addr = ASC_QNO_TO_QADDR(free_q_head);
8032 q_status = (uchar)AscReadLramByte(iop_base,
8033 (ushort)(q_addr +
8034 ASC_SCSIQ_B_STATUS));
8035 next_qp = AscReadLramByte(iop_base, (ushort)(q_addr + ASC_SCSIQ_B_FWD));
8036 if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END)) {
8037 return (next_qp);
8038 }
8039 return (ASC_QLINK_END);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008040}
8041
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008042static uchar
8043AscAllocMultipleFreeQueue(PortAddr iop_base, uchar free_q_head, uchar n_free_q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008044{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008045 uchar i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008046
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008047 for (i = 0; i < n_free_q; i++) {
8048 if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head))
8049 == ASC_QLINK_END) {
8050 return (ASC_QLINK_END);
8051 }
8052 }
8053 return (free_q_head);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008054}
8055
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008056static int AscHostReqRiscHalt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008057{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008058 int count = 0;
8059 int sta = 0;
8060 uchar saved_stop_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008061
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008062 if (AscIsChipHalted(iop_base))
8063 return (1);
8064 saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
8065 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
8066 ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP);
8067 do {
8068 if (AscIsChipHalted(iop_base)) {
8069 sta = 1;
8070 break;
8071 }
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06008072 mdelay(100);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008073 } while (count++ < 20);
8074 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code);
8075 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008076}
8077
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008078static int AscStopQueueExe(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008079{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008080 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008081
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008082 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) {
8083 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
8084 ASC_STOP_REQ_RISC_STOP);
8085 do {
8086 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) &
8087 ASC_STOP_ACK_RISC_STOP) {
8088 return (1);
8089 }
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06008090 mdelay(100);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008091 } while (count++ < 20);
8092 }
8093 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008094}
8095
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008096static int AscStartChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008097{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008098 AscSetChipControl(iop_base, 0);
8099 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
8100 return (0);
8101 }
8102 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008103}
8104
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008105static int AscStopChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008106{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008107 uchar cc_val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008108
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008109 cc_val =
8110 AscGetChipControl(iop_base) &
8111 (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG));
8112 AscSetChipControl(iop_base, (uchar)(cc_val | CC_HALT));
8113 AscSetChipIH(iop_base, INS_HALT);
8114 AscSetChipIH(iop_base, INS_RFLAG_WTM);
8115 if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) {
8116 return (0);
8117 }
8118 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008119}
8120
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008121static int AscIsChipHalted(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008122{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008123 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
8124 if ((AscGetChipControl(iop_base) & CC_HALT) != 0) {
8125 return (1);
8126 }
8127 }
8128 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008129}
8130
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008131static void AscSetChipIH(PortAddr iop_base, ushort ins_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008132{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008133 AscSetBank(iop_base, 1);
8134 AscWriteChipIH(iop_base, ins_code);
8135 AscSetBank(iop_base, 0);
8136 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008137}
8138
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008139static void AscAckInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008140{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008141 uchar host_flag;
8142 uchar risc_flag;
8143 ushort loop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008144
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008145 loop = 0;
8146 do {
8147 risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B);
8148 if (loop++ > 0x7FFF) {
8149 break;
8150 }
8151 } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0);
8152 host_flag =
8153 AscReadLramByte(iop_base,
8154 ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT);
8155 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
8156 (uchar)(host_flag | ASC_HOST_FLAG_ACK_INT));
8157 AscSetChipStatus(iop_base, CIW_INT_ACK);
8158 loop = 0;
8159 while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) {
8160 AscSetChipStatus(iop_base, CIW_INT_ACK);
8161 if (loop++ > 3) {
8162 break;
8163 }
8164 }
8165 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
8166 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008167}
8168
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008169static void AscDisableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008170{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008171 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008172
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008173 cfg = AscGetChipCfgLsw(iop_base);
8174 AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON));
8175 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008176}
8177
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008178static void AscEnableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008179{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008180 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008181
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008182 cfg = AscGetChipCfgLsw(iop_base);
8183 AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON);
8184 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008185}
8186
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008187static void AscSetBank(PortAddr iop_base, uchar bank)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008188{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008189 uchar val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008190
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008191 val = AscGetChipControl(iop_base) &
8192 (~
8193 (CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET |
8194 CC_CHIP_RESET));
8195 if (bank == 1) {
8196 val |= CC_BANK_ONE;
8197 } else if (bank == 2) {
8198 val |= CC_DIAG | CC_BANK_ONE;
8199 } else {
8200 val &= ~CC_BANK_ONE;
8201 }
8202 AscSetChipControl(iop_base, val);
8203 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008204}
8205
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008206static int AscResetChipAndScsiBus(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008207{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008208 PortAddr iop_base;
8209 int i = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008210
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008211 iop_base = asc_dvc->iop_base;
8212 while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE)
8213 && (i-- > 0)) {
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06008214 mdelay(100);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008215 }
8216 AscStopChip(iop_base);
8217 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06008218 udelay(60);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008219 AscSetChipIH(iop_base, INS_RFLAG_WTM);
8220 AscSetChipIH(iop_base, INS_HALT);
8221 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT);
8222 AscSetChipControl(iop_base, CC_HALT);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06008223 mdelay(200);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008224 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
8225 AscSetChipStatus(iop_base, 0);
8226 return (AscIsChipHalted(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008227}
8228
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008229static ASC_DCNT __devinit AscGetMaxDmaCount(ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008230{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008231 if (bus_type & ASC_IS_ISA)
Matthew Wilcox95c9f162007-09-09 08:56:39 -06008232 return ASC_MAX_ISA_DMA_COUNT;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008233 else if (bus_type & (ASC_IS_EISA | ASC_IS_VL))
Matthew Wilcox95c9f162007-09-09 08:56:39 -06008234 return ASC_MAX_VL_DMA_COUNT;
8235 return ASC_MAX_PCI_DMA_COUNT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008236}
8237
8238#ifdef CONFIG_ISA
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008239static ushort __devinit AscGetIsaDmaChannel(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008240{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008241 ushort channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008242
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008243 channel = AscGetChipCfgLsw(iop_base) & 0x0003;
8244 if (channel == 0x03)
8245 return (0);
8246 else if (channel == 0x00)
8247 return (7);
8248 return (channel + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008249}
8250
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008251static ushort __devinit AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008252{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008253 ushort cfg_lsw;
8254 uchar value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008255
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008256 if ((dma_channel >= 5) && (dma_channel <= 7)) {
8257 if (dma_channel == 7)
8258 value = 0x00;
8259 else
8260 value = dma_channel - 4;
8261 cfg_lsw = AscGetChipCfgLsw(iop_base) & 0xFFFC;
8262 cfg_lsw |= value;
8263 AscSetChipCfgLsw(iop_base, cfg_lsw);
8264 return (AscGetIsaDmaChannel(iop_base));
8265 }
8266 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008267}
8268
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008269static uchar __devinit AscSetIsaDmaSpeed(PortAddr iop_base, uchar speed_value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008270{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008271 speed_value &= 0x07;
8272 AscSetBank(iop_base, 1);
8273 AscWriteChipDmaSpeed(iop_base, speed_value);
8274 AscSetBank(iop_base, 0);
8275 return (AscGetIsaDmaSpeed(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008276}
8277
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008278static uchar __devinit AscGetIsaDmaSpeed(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008279{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008280 uchar speed_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008281
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008282 AscSetBank(iop_base, 1);
8283 speed_value = AscReadChipDmaSpeed(iop_base);
8284 speed_value &= 0x07;
8285 AscSetBank(iop_base, 0);
8286 return (speed_value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008287}
8288#endif /* CONFIG_ISA */
8289
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06008290static int __devinit AscInitGetConfig(asc_board_t *boardp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008291{
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06008292 ASC_DVC_VAR *asc_dvc = &boardp->dvc_var.asc_dvc_var;
Matthew Wilcox9649af32007-07-26 21:51:47 -06008293 unsigned short warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008294
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008295 asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG;
Matthew Wilcox9649af32007-07-26 21:51:47 -06008296 if (asc_dvc->err_code != 0)
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06008297 return asc_dvc->err_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008298
Matthew Wilcox9649af32007-07-26 21:51:47 -06008299 if (AscFindSignature(asc_dvc->iop_base)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008300 warn_code |= AscInitAscDvcVar(asc_dvc);
8301 warn_code |= AscInitFromEEP(asc_dvc);
8302 asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06008303 if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008304 asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008305 } else {
8306 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
8307 }
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06008308
8309 switch (warn_code) {
8310 case 0: /* No error */
8311 break;
8312 case ASC_WARN_IO_PORT_ROTATE:
8313 ASC_PRINT1("AscInitGetConfig: board %d: I/O port address "
8314 "modified\n", boardp->id);
8315 break;
8316 case ASC_WARN_AUTO_CONFIG:
8317 ASC_PRINT1("AscInitGetConfig: board %d: I/O port increment "
8318 "switch enabled\n", boardp->id);
8319 break;
8320 case ASC_WARN_EEPROM_CHKSUM:
8321 ASC_PRINT1("AscInitGetConfig: board %d: EEPROM checksum "
8322 "error\n", boardp->id);
8323 break;
8324 case ASC_WARN_IRQ_MODIFIED:
8325 ASC_PRINT1("AscInitGetConfig: board %d: IRQ modified\n",
8326 boardp->id);
8327 break;
8328 case ASC_WARN_CMD_QNG_CONFLICT:
8329 ASC_PRINT1("AscInitGetConfig: board %d: tag queuing enabled "
8330 "w/o disconnects\n", boardp->id);
8331 break;
8332 default:
8333 ASC_PRINT2("AscInitGetConfig: board %d: unknown warning: "
8334 "0x%x\n", boardp->id, warn_code);
8335 break;
8336 }
8337
8338 if (asc_dvc->err_code != 0) {
8339 ASC_PRINT3("AscInitGetConfig: board %d error: init_state 0x%x, "
8340 "err_code 0x%x\n", boardp->id, asc_dvc->init_state,
8341 asc_dvc->err_code);
8342 }
8343
8344 return asc_dvc->err_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008345}
8346
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06008347static int __devinit AscInitSetConfig(struct pci_dev *pdev, asc_board_t *boardp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008348{
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06008349 ASC_DVC_VAR *asc_dvc = &boardp->dvc_var.asc_dvc_var;
Matthew Wilcox394dbf32007-07-26 11:56:40 -04008350 PortAddr iop_base = asc_dvc->iop_base;
8351 unsigned short cfg_msw;
8352 unsigned short warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008353
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008354 asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG;
8355 if (asc_dvc->err_code != 0)
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06008356 return asc_dvc->err_code;
Matthew Wilcox394dbf32007-07-26 11:56:40 -04008357 if (!AscFindSignature(asc_dvc->iop_base)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008358 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06008359 return asc_dvc->err_code;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008360 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008361
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008362 cfg_msw = AscGetChipCfgMsw(iop_base);
8363 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06008364 cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008365 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
8366 AscSetChipCfgMsw(iop_base, cfg_msw);
8367 }
8368 if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) !=
8369 asc_dvc->cfg->cmd_qng_enabled) {
8370 asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled;
8371 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
8372 }
8373 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
8374 warn_code |= ASC_WARN_AUTO_CONFIG;
8375 }
8376 if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) {
8377 if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type)
8378 != asc_dvc->irq_no) {
8379 asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO;
8380 }
8381 }
Matthew Wilcox9649af32007-07-26 21:51:47 -06008382#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008383 if (asc_dvc->bus_type & ASC_IS_PCI) {
8384 cfg_msw &= 0xFFC0;
8385 AscSetChipCfgMsw(iop_base, cfg_msw);
8386 if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
8387 } else {
Matthew Wilcox9649af32007-07-26 21:51:47 -06008388 if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) ||
8389 (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008390 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
8391 asc_dvc->bug_fix_cntl |=
8392 ASC_BUG_FIX_ASYN_USE_SYN;
8393 }
8394 }
Matthew Wilcox9649af32007-07-26 21:51:47 -06008395 } else
8396#endif /* CONFIG_PCI */
8397 if (asc_dvc->bus_type == ASC_IS_ISAPNP) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008398 if (AscGetChipVersion(iop_base, asc_dvc->bus_type)
8399 == ASC_CHIP_VER_ASYN_BUG) {
8400 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
8401 }
8402 }
8403 if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) !=
8404 asc_dvc->cfg->chip_scsi_id) {
8405 asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID;
8406 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008407#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008408 if (asc_dvc->bus_type & ASC_IS_ISA) {
8409 AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel);
8410 AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed);
8411 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008412#endif /* CONFIG_ISA */
Matthew Wilcox394dbf32007-07-26 11:56:40 -04008413
8414 asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG;
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06008415
8416 switch (warn_code) {
8417 case 0: /* No error. */
8418 break;
8419 case ASC_WARN_IO_PORT_ROTATE:
8420 ASC_PRINT1("AscInitSetConfig: board %d: I/O port address "
8421 "modified\n", boardp->id);
8422 break;
8423 case ASC_WARN_AUTO_CONFIG:
8424 ASC_PRINT1("AscInitSetConfig: board %d: I/O port increment "
8425 "switch enabled\n", boardp->id);
8426 break;
8427 case ASC_WARN_EEPROM_CHKSUM:
8428 ASC_PRINT1("AscInitSetConfig: board %d: EEPROM checksum "
8429 "error\n", boardp->id);
8430 break;
8431 case ASC_WARN_IRQ_MODIFIED:
8432 ASC_PRINT1("AscInitSetConfig: board %d: IRQ modified\n",
8433 boardp->id);
8434 break;
8435 case ASC_WARN_CMD_QNG_CONFLICT:
8436 ASC_PRINT1("AscInitSetConfig: board %d: tag queuing w/o "
8437 "disconnects\n",
8438 boardp->id);
8439 break;
8440 default:
8441 ASC_PRINT2("AscInitSetConfig: board %d: unknown warning: "
8442 "0x%x\n", boardp->id, warn_code);
8443 break;
8444 }
8445
8446 if (asc_dvc->err_code != 0) {
8447 ASC_PRINT3("AscInitSetConfig: board %d error: init_state 0x%x, "
8448 "err_code 0x%x\n", boardp->id, asc_dvc->init_state,
8449 asc_dvc->err_code);
8450 }
8451
8452 return asc_dvc->err_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008453}
8454
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008455static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008456{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008457 ushort warn_code;
8458 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008459
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008460 iop_base = asc_dvc->iop_base;
8461 warn_code = 0;
8462 if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
8463 !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
8464 AscResetChipAndScsiBus(asc_dvc);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06008465 mdelay(asc_dvc->scsi_reset_wait * 1000); /* XXX: msleep? */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008466 }
8467 asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
8468 if (asc_dvc->err_code != 0)
8469 return (UW_ERR);
8470 if (!AscFindSignature(asc_dvc->iop_base)) {
8471 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
8472 return (warn_code);
8473 }
8474 AscDisableInterrupt(iop_base);
8475 warn_code |= AscInitLram(asc_dvc);
8476 if (asc_dvc->err_code != 0)
8477 return (UW_ERR);
8478 ASC_DBG1(1, "AscInitAsc1000Driver: _asc_mcode_chksum 0x%lx\n",
8479 (ulong)_asc_mcode_chksum);
8480 if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf,
8481 _asc_mcode_size) != _asc_mcode_chksum) {
8482 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
8483 return (warn_code);
8484 }
8485 warn_code |= AscInitMicroCodeVar(asc_dvc);
8486 asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
8487 AscEnableInterrupt(iop_base);
8488 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008489}
8490
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008491static ushort __devinit AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008492{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008493 int i;
8494 PortAddr iop_base;
8495 ushort warn_code;
8496 uchar chip_version;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008497
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008498 iop_base = asc_dvc->iop_base;
8499 warn_code = 0;
8500 asc_dvc->err_code = 0;
8501 if ((asc_dvc->bus_type &
8502 (ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0) {
8503 asc_dvc->err_code |= ASC_IERR_NO_BUS_TYPE;
8504 }
8505 AscSetChipControl(iop_base, CC_HALT);
8506 AscSetChipStatus(iop_base, 0);
8507 asc_dvc->bug_fix_cntl = 0;
8508 asc_dvc->pci_fix_asyn_xfer = 0;
8509 asc_dvc->pci_fix_asyn_xfer_always = 0;
8510 /* asc_dvc->init_state initalized in AscInitGetConfig(). */
8511 asc_dvc->sdtr_done = 0;
8512 asc_dvc->cur_total_qng = 0;
8513 asc_dvc->is_in_int = 0;
8514 asc_dvc->in_critical_cnt = 0;
8515 asc_dvc->last_q_shortage = 0;
8516 asc_dvc->use_tagged_qng = 0;
8517 asc_dvc->no_scam = 0;
8518 asc_dvc->unit_not_ready = 0;
8519 asc_dvc->queue_full_or_busy = 0;
8520 asc_dvc->redo_scam = 0;
8521 asc_dvc->res2 = 0;
8522 asc_dvc->host_init_sdtr_index = 0;
8523 asc_dvc->cfg->can_tagged_qng = 0;
8524 asc_dvc->cfg->cmd_qng_enabled = 0;
8525 asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
8526 asc_dvc->init_sdtr = 0;
8527 asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG;
8528 asc_dvc->scsi_reset_wait = 3;
8529 asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET;
8530 asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
8531 asc_dvc->cfg->sdtr_enable = ASC_SCSI_WIDTH_BIT_SET;
8532 asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
8533 asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID;
8534 asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER;
8535 asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) |
8536 ASC_LIB_VERSION_MINOR;
8537 chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type);
8538 asc_dvc->cfg->chip_version = chip_version;
8539 asc_dvc->sdtr_period_tbl[0] = SYN_XFER_NS_0;
8540 asc_dvc->sdtr_period_tbl[1] = SYN_XFER_NS_1;
8541 asc_dvc->sdtr_period_tbl[2] = SYN_XFER_NS_2;
8542 asc_dvc->sdtr_period_tbl[3] = SYN_XFER_NS_3;
8543 asc_dvc->sdtr_period_tbl[4] = SYN_XFER_NS_4;
8544 asc_dvc->sdtr_period_tbl[5] = SYN_XFER_NS_5;
8545 asc_dvc->sdtr_period_tbl[6] = SYN_XFER_NS_6;
8546 asc_dvc->sdtr_period_tbl[7] = SYN_XFER_NS_7;
8547 asc_dvc->max_sdtr_index = 7;
8548 if ((asc_dvc->bus_type & ASC_IS_PCI) &&
8549 (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3150)) {
8550 asc_dvc->bus_type = ASC_IS_PCI_ULTRA;
8551 asc_dvc->sdtr_period_tbl[0] = SYN_ULTRA_XFER_NS_0;
8552 asc_dvc->sdtr_period_tbl[1] = SYN_ULTRA_XFER_NS_1;
8553 asc_dvc->sdtr_period_tbl[2] = SYN_ULTRA_XFER_NS_2;
8554 asc_dvc->sdtr_period_tbl[3] = SYN_ULTRA_XFER_NS_3;
8555 asc_dvc->sdtr_period_tbl[4] = SYN_ULTRA_XFER_NS_4;
8556 asc_dvc->sdtr_period_tbl[5] = SYN_ULTRA_XFER_NS_5;
8557 asc_dvc->sdtr_period_tbl[6] = SYN_ULTRA_XFER_NS_6;
8558 asc_dvc->sdtr_period_tbl[7] = SYN_ULTRA_XFER_NS_7;
8559 asc_dvc->sdtr_period_tbl[8] = SYN_ULTRA_XFER_NS_8;
8560 asc_dvc->sdtr_period_tbl[9] = SYN_ULTRA_XFER_NS_9;
8561 asc_dvc->sdtr_period_tbl[10] = SYN_ULTRA_XFER_NS_10;
8562 asc_dvc->sdtr_period_tbl[11] = SYN_ULTRA_XFER_NS_11;
8563 asc_dvc->sdtr_period_tbl[12] = SYN_ULTRA_XFER_NS_12;
8564 asc_dvc->sdtr_period_tbl[13] = SYN_ULTRA_XFER_NS_13;
8565 asc_dvc->sdtr_period_tbl[14] = SYN_ULTRA_XFER_NS_14;
8566 asc_dvc->sdtr_period_tbl[15] = SYN_ULTRA_XFER_NS_15;
8567 asc_dvc->max_sdtr_index = 15;
8568 if (chip_version == ASC_CHIP_VER_PCI_ULTRA_3150) {
8569 AscSetExtraControl(iop_base,
8570 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
8571 } else if (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3050) {
8572 AscSetExtraControl(iop_base,
8573 (SEC_ACTIVE_NEGATE |
8574 SEC_ENABLE_FILTER));
8575 }
8576 }
8577 if (asc_dvc->bus_type == ASC_IS_PCI) {
8578 AscSetExtraControl(iop_base,
8579 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
8580 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008581
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008582 asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008583#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008584 if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) {
Matthew Wilcox59fcf842007-07-26 11:54:15 -04008585 if (chip_version >= ASC_CHIP_MIN_VER_ISA_PNP) {
8586 AscSetChipIFC(iop_base, IFC_INIT_DEFAULT);
8587 asc_dvc->bus_type = ASC_IS_ISAPNP;
8588 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008589 asc_dvc->cfg->isa_dma_channel =
8590 (uchar)AscGetIsaDmaChannel(iop_base);
8591 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008592#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008593 for (i = 0; i <= ASC_MAX_TID; i++) {
8594 asc_dvc->cur_dvc_qng[i] = 0;
8595 asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG;
8596 asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q *)0L;
8597 asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q *)0L;
8598 asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG;
8599 }
8600 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008601}
8602
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008603static ushort __devinit AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008604{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008605 ASCEEP_CONFIG eep_config_buf;
8606 ASCEEP_CONFIG *eep_config;
8607 PortAddr iop_base;
8608 ushort chksum;
8609 ushort warn_code;
8610 ushort cfg_msw, cfg_lsw;
8611 int i;
8612 int write_eep = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008613
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008614 iop_base = asc_dvc->iop_base;
8615 warn_code = 0;
8616 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE);
8617 AscStopQueueExe(iop_base);
8618 if ((AscStopChip(iop_base) == FALSE) ||
8619 (AscGetChipScsiCtrl(iop_base) != 0)) {
8620 asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
8621 AscResetChipAndScsiBus(asc_dvc);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06008622 mdelay(asc_dvc->scsi_reset_wait * 1000); /* XXX: msleep? */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008623 }
8624 if (AscIsChipHalted(iop_base) == FALSE) {
8625 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
8626 return (warn_code);
8627 }
8628 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
8629 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
8630 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
8631 return (warn_code);
8632 }
8633 eep_config = (ASCEEP_CONFIG *)&eep_config_buf;
8634 cfg_msw = AscGetChipCfgMsw(iop_base);
8635 cfg_lsw = AscGetChipCfgLsw(iop_base);
8636 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06008637 cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008638 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
8639 AscSetChipCfgMsw(iop_base, cfg_msw);
8640 }
8641 chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
8642 ASC_DBG1(1, "AscInitFromEEP: chksum 0x%x\n", chksum);
8643 if (chksum == 0) {
8644 chksum = 0xaa55;
8645 }
8646 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
8647 warn_code |= ASC_WARN_AUTO_CONFIG;
8648 if (asc_dvc->cfg->chip_version == 3) {
8649 if (eep_config->cfg_lsw != cfg_lsw) {
8650 warn_code |= ASC_WARN_EEPROM_RECOVER;
8651 eep_config->cfg_lsw =
8652 AscGetChipCfgLsw(iop_base);
8653 }
8654 if (eep_config->cfg_msw != cfg_msw) {
8655 warn_code |= ASC_WARN_EEPROM_RECOVER;
8656 eep_config->cfg_msw =
8657 AscGetChipCfgMsw(iop_base);
8658 }
8659 }
8660 }
8661 eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
8662 eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
8663 ASC_DBG1(1, "AscInitFromEEP: eep_config->chksum 0x%x\n",
8664 eep_config->chksum);
8665 if (chksum != eep_config->chksum) {
8666 if (AscGetChipVersion(iop_base, asc_dvc->bus_type) ==
8667 ASC_CHIP_VER_PCI_ULTRA_3050) {
8668 ASC_DBG(1,
8669 "AscInitFromEEP: chksum error ignored; EEPROM-less board\n");
8670 eep_config->init_sdtr = 0xFF;
8671 eep_config->disc_enable = 0xFF;
8672 eep_config->start_motor = 0xFF;
8673 eep_config->use_cmd_qng = 0;
8674 eep_config->max_total_qng = 0xF0;
8675 eep_config->max_tag_qng = 0x20;
8676 eep_config->cntl = 0xBFFF;
8677 ASC_EEP_SET_CHIP_ID(eep_config, 7);
8678 eep_config->no_scam = 0;
8679 eep_config->adapter_info[0] = 0;
8680 eep_config->adapter_info[1] = 0;
8681 eep_config->adapter_info[2] = 0;
8682 eep_config->adapter_info[3] = 0;
8683 eep_config->adapter_info[4] = 0;
8684 /* Indicate EEPROM-less board. */
8685 eep_config->adapter_info[5] = 0xBB;
8686 } else {
8687 ASC_PRINT
8688 ("AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n");
8689 write_eep = 1;
8690 warn_code |= ASC_WARN_EEPROM_CHKSUM;
8691 }
8692 }
8693 asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr;
8694 asc_dvc->cfg->disc_enable = eep_config->disc_enable;
8695 asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
8696 asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config);
8697 asc_dvc->start_motor = eep_config->start_motor;
8698 asc_dvc->dvc_cntl = eep_config->cntl;
8699 asc_dvc->no_scam = eep_config->no_scam;
8700 asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0];
8701 asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1];
8702 asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2];
8703 asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3];
8704 asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4];
8705 asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5];
8706 if (!AscTestExternalLram(asc_dvc)) {
8707 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) ==
8708 ASC_IS_PCI_ULTRA)) {
8709 eep_config->max_total_qng =
8710 ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
8711 eep_config->max_tag_qng =
8712 ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG;
8713 } else {
8714 eep_config->cfg_msw |= 0x0800;
8715 cfg_msw |= 0x0800;
8716 AscSetChipCfgMsw(iop_base, cfg_msw);
8717 eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
8718 eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG;
8719 }
8720 } else {
8721 }
8722 if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) {
8723 eep_config->max_total_qng = ASC_MIN_TOTAL_QNG;
8724 }
8725 if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) {
8726 eep_config->max_total_qng = ASC_MAX_TOTAL_QNG;
8727 }
8728 if (eep_config->max_tag_qng > eep_config->max_total_qng) {
8729 eep_config->max_tag_qng = eep_config->max_total_qng;
8730 }
8731 if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) {
8732 eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC;
8733 }
8734 asc_dvc->max_total_qng = eep_config->max_total_qng;
8735 if ((eep_config->use_cmd_qng & eep_config->disc_enable) !=
8736 eep_config->use_cmd_qng) {
8737 eep_config->disc_enable = eep_config->use_cmd_qng;
8738 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
8739 }
8740 if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
8741 asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
8742 }
8743 ASC_EEP_SET_CHIP_ID(eep_config,
8744 ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID);
8745 asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config);
8746 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) &&
8747 !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
8748 asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
8749 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008750
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008751 for (i = 0; i <= ASC_MAX_TID; i++) {
8752 asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
8753 asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
8754 asc_dvc->cfg->sdtr_period_offset[i] =
8755 (uchar)(ASC_DEF_SDTR_OFFSET |
8756 (asc_dvc->host_init_sdtr_index << 4));
8757 }
8758 eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
8759 if (write_eep) {
8760 if ((i =
8761 AscSetEEPConfig(iop_base, eep_config,
8762 asc_dvc->bus_type)) != 0) {
8763 ASC_PRINT1
8764 ("AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n",
8765 i);
8766 } else {
8767 ASC_PRINT
8768 ("AscInitFromEEP: Successfully re-wrote EEPROM.\n");
8769 }
8770 }
8771 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008772}
8773
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008774static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008775{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008776 int i;
8777 ushort warn_code;
8778 PortAddr iop_base;
8779 ASC_PADDR phy_addr;
8780 ASC_DCNT phy_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008781
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008782 iop_base = asc_dvc->iop_base;
8783 warn_code = 0;
8784 for (i = 0; i <= ASC_MAX_TID; i++) {
8785 AscPutMCodeInitSDTRAtID(iop_base, i,
8786 asc_dvc->cfg->sdtr_period_offset[i]
8787 );
8788 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008789
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008790 AscInitQLinkVar(asc_dvc);
8791 AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
8792 asc_dvc->cfg->disc_enable);
8793 AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
8794 ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008795
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008796 /* Align overrun buffer on an 8 byte boundary. */
8797 phy_addr = virt_to_bus(asc_dvc->cfg->overrun_buf);
8798 phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7);
8799 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
8800 (uchar *)&phy_addr, 1);
8801 phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE - 8);
8802 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D,
8803 (uchar *)&phy_size, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008804
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008805 asc_dvc->cfg->mcode_date =
8806 AscReadLramWord(iop_base, (ushort)ASCV_MC_DATE_W);
8807 asc_dvc->cfg->mcode_version =
8808 AscReadLramWord(iop_base, (ushort)ASCV_MC_VER_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008809
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008810 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
8811 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
8812 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
8813 return (warn_code);
8814 }
8815 if (AscStartChip(iop_base) != 1) {
8816 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
8817 return (warn_code);
8818 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008819
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008820 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008821}
8822
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008823static int __devinit AscTestExternalLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008824{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008825 PortAddr iop_base;
8826 ushort q_addr;
8827 ushort saved_word;
8828 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008829
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008830 iop_base = asc_dvc->iop_base;
8831 sta = 0;
8832 q_addr = ASC_QNO_TO_QADDR(241);
8833 saved_word = AscReadLramWord(iop_base, q_addr);
8834 AscSetChipLramAddr(iop_base, q_addr);
8835 AscSetChipLramData(iop_base, 0x55AA);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06008836 mdelay(10);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008837 AscSetChipLramAddr(iop_base, q_addr);
8838 if (AscGetChipLramData(iop_base) == 0x55AA) {
8839 sta = 1;
8840 AscWriteLramWord(iop_base, q_addr, saved_word);
8841 }
8842 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008843}
8844
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008845static int __devinit AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008846{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008847 uchar read_back;
8848 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008849
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008850 retry = 0;
8851 while (TRUE) {
8852 AscSetChipEEPCmd(iop_base, cmd_reg);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06008853 mdelay(1);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008854 read_back = AscGetChipEEPCmd(iop_base);
8855 if (read_back == cmd_reg) {
8856 return (1);
8857 }
8858 if (retry++ > ASC_EEP_MAX_RETRY) {
8859 return (0);
8860 }
8861 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008862}
8863
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008864static int __devinit AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008865{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008866 ushort read_back;
8867 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008868
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008869 retry = 0;
8870 while (TRUE) {
8871 AscSetChipEEPData(iop_base, data_reg);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06008872 mdelay(1);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008873 read_back = AscGetChipEEPData(iop_base);
8874 if (read_back == data_reg) {
8875 return (1);
8876 }
8877 if (retry++ > ASC_EEP_MAX_RETRY) {
8878 return (0);
8879 }
8880 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008881}
8882
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008883static void __devinit AscWaitEEPRead(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008884{
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06008885 mdelay(1);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008886 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008887}
8888
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008889static void __devinit AscWaitEEPWrite(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008890{
Matthew Wilcoxb009bef2007-09-09 08:56:38 -06008891 mdelay(20);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008892 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008893}
8894
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008895static ushort __devinit AscReadEEPWord(PortAddr iop_base, uchar addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008896{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008897 ushort read_wval;
8898 uchar cmd_reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008899
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008900 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
8901 AscWaitEEPRead();
8902 cmd_reg = addr | ASC_EEP_CMD_READ;
8903 AscWriteEEPCmdReg(iop_base, cmd_reg);
8904 AscWaitEEPRead();
8905 read_wval = AscGetChipEEPData(iop_base);
8906 AscWaitEEPRead();
8907 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008908}
8909
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008910static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008911AscWriteEEPWord(PortAddr iop_base, uchar addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008912{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008913 ushort read_wval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008914
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008915 read_wval = AscReadEEPWord(iop_base, addr);
8916 if (read_wval != word_val) {
8917 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE);
8918 AscWaitEEPRead();
8919 AscWriteEEPDataReg(iop_base, word_val);
8920 AscWaitEEPRead();
8921 AscWriteEEPCmdReg(iop_base,
8922 (uchar)((uchar)ASC_EEP_CMD_WRITE | addr));
8923 AscWaitEEPWrite();
8924 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
8925 AscWaitEEPRead();
8926 return (AscReadEEPWord(iop_base, addr));
8927 }
8928 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008929}
8930
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008931static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008932AscGetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008933{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008934 ushort wval;
8935 ushort sum;
8936 ushort *wbuf;
8937 int cfg_beg;
8938 int cfg_end;
8939 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
8940 int s_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008941
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008942 wbuf = (ushort *)cfg_buf;
8943 sum = 0;
8944 /* Read two config words; Byte-swapping done by AscReadEEPWord(). */
8945 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
8946 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
8947 sum += *wbuf;
8948 }
8949 if (bus_type & ASC_IS_VL) {
8950 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
8951 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
8952 } else {
8953 cfg_beg = ASC_EEP_DVC_CFG_BEG;
8954 cfg_end = ASC_EEP_MAX_DVC_ADDR;
8955 }
8956 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
8957 wval = AscReadEEPWord(iop_base, (uchar)s_addr);
8958 if (s_addr <= uchar_end_in_config) {
8959 /*
8960 * Swap all char fields - must unswap bytes already swapped
8961 * by AscReadEEPWord().
8962 */
8963 *wbuf = le16_to_cpu(wval);
8964 } else {
8965 /* Don't swap word field at the end - cntl field. */
8966 *wbuf = wval;
8967 }
8968 sum += wval; /* Checksum treats all EEPROM data as words. */
8969 }
8970 /*
8971 * Read the checksum word which will be compared against 'sum'
8972 * by the caller. Word field already swapped.
8973 */
8974 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
8975 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008976}
8977
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008978static int __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008979AscSetEEPConfigOnce(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008980{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008981 int n_error;
8982 ushort *wbuf;
8983 ushort word;
8984 ushort sum;
8985 int s_addr;
8986 int cfg_beg;
8987 int cfg_end;
8988 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008989
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008990 wbuf = (ushort *)cfg_buf;
8991 n_error = 0;
8992 sum = 0;
8993 /* Write two config words; AscWriteEEPWord() will swap bytes. */
8994 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
8995 sum += *wbuf;
8996 if (*wbuf != AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
8997 n_error++;
8998 }
8999 }
9000 if (bus_type & ASC_IS_VL) {
9001 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
9002 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
9003 } else {
9004 cfg_beg = ASC_EEP_DVC_CFG_BEG;
9005 cfg_end = ASC_EEP_MAX_DVC_ADDR;
9006 }
9007 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
9008 if (s_addr <= uchar_end_in_config) {
9009 /*
9010 * This is a char field. Swap char fields before they are
9011 * swapped again by AscWriteEEPWord().
9012 */
9013 word = cpu_to_le16(*wbuf);
9014 if (word !=
9015 AscWriteEEPWord(iop_base, (uchar)s_addr, word)) {
9016 n_error++;
9017 }
9018 } else {
9019 /* Don't swap word field at the end - cntl field. */
9020 if (*wbuf !=
9021 AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
9022 n_error++;
9023 }
9024 }
9025 sum += *wbuf; /* Checksum calculated from word values. */
9026 }
9027 /* Write checksum word. It will be swapped by AscWriteEEPWord(). */
9028 *wbuf = sum;
9029 if (sum != AscWriteEEPWord(iop_base, (uchar)s_addr, sum)) {
9030 n_error++;
9031 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009032
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009033 /* Read EEPROM back again. */
9034 wbuf = (ushort *)cfg_buf;
9035 /*
9036 * Read two config words; Byte-swapping done by AscReadEEPWord().
9037 */
9038 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
9039 if (*wbuf != AscReadEEPWord(iop_base, (uchar)s_addr)) {
9040 n_error++;
9041 }
9042 }
9043 if (bus_type & ASC_IS_VL) {
9044 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
9045 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
9046 } else {
9047 cfg_beg = ASC_EEP_DVC_CFG_BEG;
9048 cfg_end = ASC_EEP_MAX_DVC_ADDR;
9049 }
9050 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
9051 if (s_addr <= uchar_end_in_config) {
9052 /*
9053 * Swap all char fields. Must unswap bytes already swapped
9054 * by AscReadEEPWord().
9055 */
9056 word =
9057 le16_to_cpu(AscReadEEPWord
9058 (iop_base, (uchar)s_addr));
9059 } else {
9060 /* Don't swap word field at the end - cntl field. */
9061 word = AscReadEEPWord(iop_base, (uchar)s_addr);
9062 }
9063 if (*wbuf != word) {
9064 n_error++;
9065 }
9066 }
9067 /* Read checksum; Byte swapping not needed. */
9068 if (AscReadEEPWord(iop_base, (uchar)s_addr) != sum) {
9069 n_error++;
9070 }
9071 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009072}
9073
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009074static int __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009075AscSetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009076{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009077 int retry;
9078 int n_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009079
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009080 retry = 0;
9081 while (TRUE) {
9082 if ((n_error = AscSetEEPConfigOnce(iop_base, cfg_buf,
9083 bus_type)) == 0) {
9084 break;
9085 }
9086 if (++retry > ASC_EEP_MAX_RETRY) {
9087 break;
9088 }
9089 }
9090 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009091}
9092
Matthew Wilcox47d853c2007-07-26 11:41:33 -04009093static void AscAsyncFix(ASC_DVC_VAR *asc_dvc, struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009094{
Matthew Wilcox47d853c2007-07-26 11:41:33 -04009095 char type = sdev->type;
9096 ASC_SCSI_BIT_ID_TYPE tid_bits = 1 << sdev->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009097
Matthew Wilcox95c9f162007-09-09 08:56:39 -06009098 if (!(asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN))
9099 return;
9100 if (asc_dvc->init_sdtr & tid_bits)
9101 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009102
Matthew Wilcox95c9f162007-09-09 08:56:39 -06009103 if ((type == TYPE_ROM) && (strncmp(sdev->vendor, "HP ", 3) == 0))
9104 asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
9105
9106 asc_dvc->pci_fix_asyn_xfer |= tid_bits;
9107 if ((type == TYPE_PROCESSOR) || (type == TYPE_SCANNER) ||
9108 (type == TYPE_ROM) || (type == TYPE_TAPE))
9109 asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
9110
9111 if (asc_dvc->pci_fix_asyn_xfer & tid_bits)
9112 AscSetRunChipSynRegAtID(asc_dvc->iop_base, sdev->id,
Matthew Wilcox47d853c2007-07-26 11:41:33 -04009113 ASYN_SDTR_DATA_FIX_PCI_REV_AB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009114}
9115
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009116static uchar AscReadLramByte(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009117{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009118 uchar byte_data;
9119 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009120
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009121 if (isodd_word(addr)) {
9122 AscSetChipLramAddr(iop_base, addr - 1);
9123 word_data = AscGetChipLramData(iop_base);
9124 byte_data = (uchar)((word_data >> 8) & 0xFF);
9125 } else {
9126 AscSetChipLramAddr(iop_base, addr);
9127 word_data = AscGetChipLramData(iop_base);
9128 byte_data = (uchar)(word_data & 0xFF);
9129 }
9130 return (byte_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009131}
Linus Torvalds1da177e2005-04-16 15:20:36 -07009132
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009133static ushort AscReadLramWord(PortAddr iop_base, ushort addr)
9134{
9135 ushort word_data;
9136
9137 AscSetChipLramAddr(iop_base, addr);
9138 word_data = AscGetChipLramData(iop_base);
9139 return (word_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009140}
9141
9142#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009143static ASC_DCNT AscReadLramDWord(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009144{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009145 ushort val_low, val_high;
9146 ASC_DCNT dword_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009147
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009148 AscSetChipLramAddr(iop_base, addr);
9149 val_low = AscGetChipLramData(iop_base);
9150 val_high = AscGetChipLramData(iop_base);
9151 dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low;
9152 return (dword_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009153}
9154#endif /* CC_VERY_LONG_SG_LIST */
9155
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009156static void AscWriteLramWord(PortAddr iop_base, ushort addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009157{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009158 AscSetChipLramAddr(iop_base, addr);
9159 AscSetChipLramData(iop_base, word_val);
9160 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009161}
9162
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009163static void AscWriteLramByte(PortAddr iop_base, ushort addr, uchar byte_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009164{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009165 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009166
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009167 if (isodd_word(addr)) {
9168 addr--;
9169 word_data = AscReadLramWord(iop_base, addr);
9170 word_data &= 0x00FF;
9171 word_data |= (((ushort)byte_val << 8) & 0xFF00);
9172 } else {
9173 word_data = AscReadLramWord(iop_base, addr);
9174 word_data &= 0xFF00;
9175 word_data |= ((ushort)byte_val & 0x00FF);
9176 }
9177 AscWriteLramWord(iop_base, addr, word_data);
9178 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009179}
9180
9181/*
9182 * Copy 2 bytes to LRAM.
9183 *
9184 * The source data is assumed to be in little-endian order in memory
9185 * and is maintained in little-endian order when written to LRAM.
9186 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009187static void
9188AscMemWordCopyPtrToLram(PortAddr iop_base,
9189 ushort s_addr, uchar *s_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009190{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009191 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009192
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009193 AscSetChipLramAddr(iop_base, s_addr);
9194 for (i = 0; i < 2 * words; i += 2) {
9195 /*
9196 * On a little-endian system the second argument below
9197 * produces a little-endian ushort which is written to
9198 * LRAM in little-endian order. On a big-endian system
9199 * the second argument produces a big-endian ushort which
9200 * is "transparently" byte-swapped by outpw() and written
9201 * in little-endian order to LRAM.
9202 */
9203 outpw(iop_base + IOP_RAM_DATA,
9204 ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]);
9205 }
9206 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009207}
9208
9209/*
9210 * Copy 4 bytes to LRAM.
9211 *
9212 * The source data is assumed to be in little-endian order in memory
9213 * and is maintained in little-endian order when writen to LRAM.
9214 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009215static void
9216AscMemDWordCopyPtrToLram(PortAddr iop_base,
9217 ushort s_addr, uchar *s_buffer, int dwords)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009218{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009219 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009220
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009221 AscSetChipLramAddr(iop_base, s_addr);
9222 for (i = 0; i < 4 * dwords; i += 4) {
9223 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]); /* LSW */
9224 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 3] << 8) | s_buffer[i + 2]); /* MSW */
9225 }
9226 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009227}
9228
9229/*
9230 * Copy 2 bytes from LRAM.
9231 *
9232 * The source data is assumed to be in little-endian order in LRAM
9233 * and is maintained in little-endian order when written to memory.
9234 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009235static void
9236AscMemWordCopyPtrFromLram(PortAddr iop_base,
9237 ushort s_addr, uchar *d_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009238{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009239 int i;
9240 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009241
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009242 AscSetChipLramAddr(iop_base, s_addr);
9243 for (i = 0; i < 2 * words; i += 2) {
9244 word = inpw(iop_base + IOP_RAM_DATA);
9245 d_buffer[i] = word & 0xff;
9246 d_buffer[i + 1] = (word >> 8) & 0xff;
9247 }
9248 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009249}
9250
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009251static ASC_DCNT AscMemSumLramWord(PortAddr iop_base, ushort s_addr, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009252{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009253 ASC_DCNT sum;
9254 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009255
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009256 sum = 0L;
9257 for (i = 0; i < words; i++, s_addr += 2) {
9258 sum += AscReadLramWord(iop_base, s_addr);
9259 }
9260 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009261}
9262
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009263static void
9264AscMemWordSetLram(PortAddr iop_base, ushort s_addr, ushort set_wval, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009265{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009266 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009267
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009268 AscSetChipLramAddr(iop_base, s_addr);
9269 for (i = 0; i < words; i++) {
9270 AscSetChipLramData(iop_base, set_wval);
9271 }
9272 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009273}
9274
Linus Torvalds1da177e2005-04-16 15:20:36 -07009275/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009276static unsigned char _adv_asc3550_buf[] = {
9277 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x18, 0xe4, 0x00, 0xfc,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009278 0x01, 0x00, 0x48, 0xe4, 0xbe, 0x18, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00,
9279 0x00, 0xfa, 0xff, 0xff, 0x28, 0x0e, 0x9e, 0xe7, 0xff, 0x00, 0x82, 0xe7,
9280 0x00, 0xea, 0x00, 0xf6, 0x01, 0xe6, 0x09, 0xe7, 0x55, 0xf0, 0x01, 0xf6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009281 0x01, 0xfa, 0x08, 0x00, 0x03, 0x00, 0x04, 0x00, 0x18, 0xf4, 0x10, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009282 0x00, 0xec, 0x85, 0xf0, 0xbc, 0x00, 0xd5, 0xf0, 0x8e, 0x0c, 0x38, 0x54,
9283 0x00, 0xe6, 0x1e, 0xf0, 0x86, 0xf0, 0xb4, 0x00, 0x98, 0x57, 0xd0, 0x01,
9284 0x0c, 0x1c, 0x3e, 0x1c, 0x0c, 0x00, 0xbb, 0x00, 0xaa, 0x18, 0x02, 0x80,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009285 0x32, 0xf0, 0x01, 0xfc, 0x88, 0x0c, 0xc6, 0x12, 0x02, 0x13, 0x18, 0x40,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009286 0x00, 0x57, 0x01, 0xea, 0x3c, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12,
9287 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00, 0xc0, 0x00, 0x01, 0x01,
9288 0x3e, 0x01, 0xda, 0x0f, 0x22, 0x10, 0x08, 0x12, 0x02, 0x4a, 0xb9, 0x54,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009289 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x20, 0x00, 0x32, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009290 0x3e, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01,
9291 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01, 0x78, 0x01, 0x62, 0x0a,
9292 0x92, 0x0c, 0x2c, 0x10, 0x2e, 0x10, 0x06, 0x13, 0x4c, 0x1c, 0xbb, 0x55,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009293 0x3c, 0x56, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0xb1, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009294 0x03, 0xf7, 0x06, 0xf7, 0x03, 0xfc, 0x0f, 0x00, 0x40, 0x00, 0xbe, 0x00,
9295 0x00, 0x01, 0xb0, 0x08, 0x30, 0x13, 0x64, 0x15, 0x32, 0x1c, 0x38, 0x1c,
9296 0x4e, 0x1c, 0x10, 0x44, 0x02, 0x48, 0x00, 0x4c, 0x04, 0xea, 0x5d, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009297 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009298 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x4e, 0x0b, 0x1e, 0x0e, 0x0c, 0x10,
9299 0x0a, 0x12, 0x04, 0x13, 0x40, 0x13, 0x30, 0x1c, 0x00, 0x4e, 0xbd, 0x56,
9300 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0, 0x59, 0xf0, 0xa7, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009301 0xb8, 0xf0, 0x0e, 0xf7, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009302 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00,
9303 0xde, 0x03, 0x56, 0x0a, 0x14, 0x0e, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10,
9304 0x36, 0x10, 0x0a, 0x13, 0x12, 0x13, 0x52, 0x13, 0x10, 0x15, 0x14, 0x15,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009305 0xac, 0x16, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009306 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x83, 0x55,
9307 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0, 0x0c, 0xf0,
9308 0x5c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009309 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x1c, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009310 0x9e, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01,
9311 0x26, 0x01, 0x79, 0x01, 0x7a, 0x01, 0xc0, 0x01, 0xc2, 0x01, 0x7c, 0x02,
9312 0x5a, 0x03, 0xea, 0x04, 0xe8, 0x07, 0x68, 0x08, 0x69, 0x08, 0xba, 0x08,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009313 0xe9, 0x09, 0x06, 0x0b, 0x3a, 0x0e, 0x00, 0x10, 0x1a, 0x10, 0xed, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009314 0xf1, 0x10, 0x06, 0x12, 0x0c, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x82, 0x13,
9315 0x42, 0x14, 0xd6, 0x14, 0x8a, 0x15, 0xc6, 0x17, 0xd2, 0x17, 0x6b, 0x18,
9316 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0x48, 0x47,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009317 0x41, 0x48, 0x89, 0x48, 0x80, 0x4c, 0x00, 0x54, 0x44, 0x55, 0xe5, 0x55,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009318 0x14, 0x56, 0x77, 0x57, 0xbf, 0x57, 0x40, 0x5c, 0x06, 0x80, 0x08, 0x90,
9319 0x03, 0xa1, 0xfe, 0x9c, 0xf0, 0x29, 0x02, 0xfe, 0xb8, 0x0c, 0xff, 0x10,
9320 0x00, 0x00, 0xd0, 0xfe, 0xcc, 0x18, 0x00, 0xcf, 0xfe, 0x80, 0x01, 0xff,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009321 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009322 0x00, 0xfe, 0x57, 0x24, 0x00, 0xfe, 0x48, 0x00, 0x4f, 0xff, 0x04, 0x00,
9323 0x00, 0x10, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x08,
9324 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x0f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009325 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009326 0xfe, 0x04, 0xf7, 0xcf, 0x2a, 0x67, 0x0b, 0x01, 0xfe, 0xce, 0x0e, 0xfe,
9327 0x04, 0xf7, 0xcf, 0x67, 0x0b, 0x3c, 0x2a, 0xfe, 0x3d, 0xf0, 0xfe, 0x02,
9328 0x02, 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x91, 0xf0, 0xfe, 0xf0, 0x01, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009329 0x90, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, 0x8f, 0xf0, 0x9c, 0x05, 0x51, 0x3b,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009330 0x02, 0xfe, 0xd4, 0x0c, 0x01, 0xfe, 0x44, 0x0d, 0xfe, 0xdd, 0x12, 0xfe,
9331 0xfc, 0x10, 0xfe, 0x28, 0x1c, 0x05, 0xfe, 0xa6, 0x00, 0xfe, 0xd3, 0x12,
9332 0x47, 0x18, 0xfe, 0xa6, 0x00, 0xb5, 0xfe, 0x48, 0xf0, 0xfe, 0x86, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009333 0xfe, 0x49, 0xf0, 0xfe, 0xa0, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xbe, 0x02,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009334 0xfe, 0x46, 0xf0, 0xfe, 0x50, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x56, 0x02,
9335 0xfe, 0x43, 0xf0, 0xfe, 0x44, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x48, 0x02,
9336 0xfe, 0x45, 0xf0, 0xfe, 0x4c, 0x02, 0x17, 0x0b, 0xa0, 0x17, 0x06, 0x18,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009337 0x96, 0x02, 0x29, 0xfe, 0x00, 0x1c, 0xde, 0xfe, 0x02, 0x1c, 0xdd, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009338 0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0xfe, 0x20, 0x17, 0xfe, 0xe7, 0x10,
9339 0xfe, 0x06, 0xfc, 0xc7, 0x0a, 0x6b, 0x01, 0x9e, 0x02, 0x29, 0x14, 0x4d,
9340 0x37, 0x97, 0x01, 0xfe, 0x64, 0x0f, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xbd,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009341 0x10, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009342 0x58, 0x1c, 0x17, 0x06, 0x18, 0x96, 0x2a, 0x25, 0x29, 0xfe, 0x3d, 0xf0,
9343 0xfe, 0x02, 0x02, 0x21, 0xfe, 0x94, 0x02, 0xfe, 0x5a, 0x1c, 0xea, 0xfe,
9344 0x14, 0x1c, 0x14, 0xfe, 0x30, 0x00, 0x37, 0x97, 0x01, 0xfe, 0x54, 0x0f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009345 0x17, 0x06, 0x18, 0x96, 0x02, 0xd0, 0x1e, 0x20, 0x07, 0x10, 0x34, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009346 0x69, 0x10, 0x17, 0x06, 0x18, 0x96, 0xfe, 0x04, 0xec, 0x20, 0x46, 0x3d,
9347 0x12, 0x20, 0xfe, 0x05, 0xf6, 0xc7, 0x01, 0xfe, 0x52, 0x16, 0x09, 0x4a,
9348 0x4c, 0x35, 0x11, 0x2d, 0x3c, 0x8a, 0x01, 0xe6, 0x02, 0x29, 0x0a, 0x40,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009349 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x01, 0x6f, 0xfe, 0x18, 0x10, 0xfe, 0x41,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009350 0x58, 0x0a, 0x99, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x64, 0xfe, 0x0c, 0x03,
9351 0x01, 0xe6, 0x02, 0x29, 0x2a, 0x46, 0xfe, 0x02, 0xe8, 0x27, 0xf8, 0xfe,
9352 0x9e, 0x43, 0xf7, 0xfe, 0x27, 0xf0, 0xfe, 0xdc, 0x01, 0xfe, 0x07, 0x4b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009353 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x40, 0x1c, 0x25, 0xd2, 0xfe, 0x26, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009354 0xfe, 0x56, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x44, 0x03, 0xfe, 0x11, 0xf0,
9355 0x9c, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x64, 0x03, 0xeb, 0x0f,
9356 0xfe, 0x11, 0x00, 0x02, 0x5a, 0x2a, 0xfe, 0x48, 0x1c, 0xeb, 0x09, 0x04,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009357 0x1d, 0xfe, 0x18, 0x13, 0x23, 0x1e, 0x98, 0xac, 0x12, 0x98, 0x0a, 0x40,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009358 0x01, 0x0e, 0xac, 0x75, 0x01, 0xfe, 0xbc, 0x15, 0x11, 0xca, 0x25, 0xd2,
9359 0xfe, 0x01, 0xf0, 0xd2, 0xfe, 0x82, 0xf0, 0xfe, 0x92, 0x03, 0xec, 0x11,
9360 0xfe, 0xe4, 0x00, 0x65, 0xfe, 0xa4, 0x03, 0x25, 0x32, 0x1f, 0xfe, 0xb4,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009361 0x03, 0x01, 0x43, 0xfe, 0x06, 0xf0, 0xfe, 0xc4, 0x03, 0x8d, 0x81, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009362 0x0a, 0xf0, 0xfe, 0x7a, 0x06, 0x02, 0x22, 0x05, 0x6b, 0x28, 0x16, 0xfe,
9363 0xf6, 0x04, 0x14, 0x2c, 0x01, 0x33, 0x8f, 0xfe, 0x66, 0x02, 0x02, 0xd1,
9364 0xeb, 0x2a, 0x67, 0x1a, 0xfe, 0x67, 0x1b, 0xf8, 0xf7, 0xfe, 0x48, 0x1c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009365 0x70, 0x01, 0x6e, 0x87, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x16, 0xd3,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009366 0x0a, 0xca, 0x01, 0x0e, 0x74, 0x60, 0x59, 0x76, 0x27, 0x05, 0x6b, 0x28,
9367 0xfe, 0x10, 0x12, 0x14, 0x2c, 0x01, 0x33, 0x8f, 0xfe, 0x66, 0x02, 0x02,
9368 0xd1, 0xbc, 0x7d, 0xbd, 0x7f, 0x25, 0x22, 0x65, 0xfe, 0x3c, 0x04, 0x1f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009369 0xfe, 0x38, 0x04, 0x68, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009370 0x12, 0x2b, 0xff, 0x02, 0x00, 0x10, 0x01, 0x08, 0x1f, 0xfe, 0xe0, 0x04,
9371 0x2b, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd5, 0xfe, 0x4c, 0x44, 0xfe,
9372 0x4c, 0x12, 0x60, 0xfe, 0x44, 0x48, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009373 0xd3, 0x46, 0x76, 0x27, 0xfa, 0xef, 0xfe, 0x62, 0x13, 0x09, 0x04, 0x1d,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009374 0xfe, 0x2a, 0x13, 0x2f, 0x07, 0x7e, 0xa5, 0xfe, 0x20, 0x10, 0x13, 0x2c,
9375 0xfe, 0x4c, 0x54, 0x64, 0xd3, 0xfa, 0xef, 0x86, 0x09, 0x04, 0x1d, 0xfe,
9376 0x08, 0x13, 0x2f, 0x07, 0x7e, 0x6e, 0x09, 0x04, 0x1d, 0xfe, 0x1c, 0x12,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009377 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009378 0x70, 0x0c, 0x02, 0x22, 0x2b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90,
9379 0xf9, 0x03, 0x14, 0x92, 0x01, 0x33, 0x02, 0x29, 0xfe, 0x42, 0x5b, 0x67,
9380 0x1a, 0xfe, 0x46, 0x59, 0xf8, 0xf7, 0xfe, 0x87, 0x80, 0xfe, 0x31, 0xe4,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009381 0x4f, 0x09, 0x04, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x1a,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009382 0xfe, 0x70, 0x12, 0x49, 0x04, 0x06, 0xfe, 0x60, 0x13, 0x05, 0xfe, 0xa2,
9383 0x00, 0x28, 0x16, 0xfe, 0x80, 0x05, 0xfe, 0x31, 0xe4, 0x6a, 0x49, 0x04,
9384 0x0b, 0xfe, 0x4a, 0x13, 0x05, 0xfe, 0xa0, 0x00, 0x28, 0xfe, 0x42, 0x12,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009385 0x5e, 0x01, 0x08, 0x25, 0x32, 0xf1, 0x01, 0x08, 0x26, 0xfe, 0x98, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009386 0x11, 0xfe, 0xe3, 0x00, 0x23, 0x49, 0xfe, 0x4a, 0xf0, 0xfe, 0x6a, 0x05,
9387 0xfe, 0x49, 0xf0, 0xfe, 0x64, 0x05, 0x83, 0x24, 0xfe, 0x21, 0x00, 0xa1,
9388 0x24, 0xfe, 0x22, 0x00, 0xa0, 0x24, 0x4c, 0xfe, 0x09, 0x48, 0x01, 0x08,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009389 0x26, 0xfe, 0x98, 0x05, 0xfe, 0xe2, 0x08, 0x49, 0x04, 0xc5, 0x3b, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009390 0x86, 0x24, 0x06, 0x12, 0xcc, 0x37, 0xfe, 0x27, 0x01, 0x09, 0x04, 0x1d,
9391 0xfe, 0x22, 0x12, 0x47, 0x01, 0xa7, 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b,
9392 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c, 0x02, 0x22, 0x05, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009393 0x9c, 0x00, 0x28, 0xfe, 0x3e, 0x12, 0x05, 0x50, 0x28, 0xfe, 0x36, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009394 0x47, 0x01, 0xa7, 0x26, 0xfe, 0x08, 0x06, 0x0a, 0x06, 0x49, 0x04, 0x19,
9395 0xfe, 0x02, 0x12, 0x5f, 0x01, 0xfe, 0xaa, 0x14, 0x1f, 0xfe, 0xfe, 0x05,
9396 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x50, 0xb4, 0x0c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009397 0x50, 0x05, 0xc6, 0x28, 0xfe, 0x62, 0x12, 0x05, 0x3f, 0x28, 0xfe, 0x5a,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009398 0x13, 0x01, 0xfe, 0x14, 0x18, 0x01, 0xfe, 0x66, 0x18, 0xfe, 0x43, 0x48,
9399 0xb7, 0x19, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0x1c, 0x3d,
9400 0x85, 0xb7, 0x69, 0x47, 0x01, 0xa7, 0x26, 0xfe, 0x72, 0x06, 0x49, 0x04,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009401 0x1b, 0xdf, 0x89, 0x0a, 0x4d, 0x01, 0xfe, 0xd8, 0x14, 0x1f, 0xfe, 0x68,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009402 0x06, 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x3f, 0xb4,
9403 0x0c, 0x3f, 0x17, 0x06, 0x01, 0xa7, 0xec, 0x72, 0x70, 0x01, 0x6e, 0x87,
9404 0x11, 0xfe, 0xe2, 0x00, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009405 0xa6, 0x06, 0x8c, 0xfe, 0x5c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, 0x64, 0x07,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009406 0x8d, 0x81, 0x02, 0x22, 0x09, 0x04, 0x0b, 0xfe, 0x2e, 0x12, 0x15, 0x1a,
9407 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00,
9408 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x15, 0x00, 0x02, 0xfe, 0x32,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009409 0x08, 0x61, 0x04, 0x1b, 0xfe, 0x38, 0x12, 0x09, 0x04, 0x1b, 0x6e, 0x15,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009410 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01,
9411 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x06, 0x01, 0x08, 0x15, 0x00, 0x02,
9412 0xd9, 0x66, 0x4c, 0xfe, 0x3a, 0x55, 0x5f, 0xfe, 0x9a, 0x81, 0x4b, 0x1d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009413 0xba, 0xfe, 0x32, 0x07, 0x0a, 0x1d, 0xfe, 0x09, 0x6f, 0xaf, 0xfe, 0xca,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009414 0x45, 0xfe, 0x32, 0x12, 0x62, 0x2c, 0x85, 0x66, 0x7b, 0x01, 0x08, 0x25,
9415 0x32, 0xfe, 0x0a, 0xf0, 0xfe, 0x32, 0x07, 0x8d, 0x81, 0x8c, 0xfe, 0x5c,
9416 0x07, 0x02, 0x22, 0x01, 0x43, 0x02, 0xfe, 0x8a, 0x06, 0x15, 0x19, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009417 0xfe, 0x8a, 0x06, 0xfe, 0x9c, 0xf7, 0xd4, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009418 0x90, 0x77, 0xfe, 0xca, 0x07, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x4a, 0x6a,
9419 0x35, 0x1e, 0x20, 0x07, 0x10, 0xfe, 0x0e, 0x12, 0x74, 0xfe, 0x80, 0x80,
9420 0x37, 0x20, 0x63, 0x27, 0xfe, 0x06, 0x10, 0xfe, 0x83, 0xe7, 0xc4, 0xa1,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009421 0xfe, 0x03, 0x40, 0x09, 0x4a, 0x4f, 0x35, 0x01, 0xa8, 0xad, 0xfe, 0x1f,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009422 0x40, 0x12, 0x58, 0x01, 0xa5, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe,
9423 0x44, 0x51, 0xfe, 0xc6, 0x51, 0x83, 0xfb, 0xfe, 0x8a, 0x90, 0x0c, 0x52,
9424 0x18, 0x53, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009425 0xc2, 0x50, 0x0c, 0x39, 0x18, 0x3a, 0xfe, 0x4a, 0x10, 0x09, 0x04, 0x6a,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009426 0xfe, 0x2a, 0x12, 0xfe, 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x54, 0x18,
9427 0x55, 0x09, 0x04, 0x4f, 0x85, 0x01, 0xa8, 0xfe, 0x1f, 0x80, 0x12, 0x58,
9428 0xfe, 0x44, 0x90, 0xfe, 0xc6, 0x90, 0x0c, 0x56, 0x18, 0x57, 0xfb, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009429 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009430 0x0c, 0x39, 0x18, 0x3a, 0x0c, 0x38, 0x18, 0x4e, 0x09, 0x4a, 0x19, 0x35,
9431 0x2a, 0x13, 0xfe, 0x4e, 0x11, 0x65, 0xfe, 0x48, 0x08, 0xfe, 0x9e, 0xf0,
9432 0xfe, 0x5c, 0x08, 0xb1, 0x16, 0x32, 0x2a, 0x73, 0xdd, 0xb8, 0xfe, 0x80,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009433 0x08, 0xb9, 0xfe, 0x9e, 0x08, 0x8c, 0xfe, 0x74, 0x08, 0xfe, 0x06, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009434 0xfe, 0x7a, 0x08, 0x8d, 0x81, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xc9, 0x10,
9435 0x15, 0x19, 0xfe, 0xc9, 0x10, 0x61, 0x04, 0x06, 0xfe, 0x10, 0x12, 0x61,
9436 0x04, 0x0b, 0x45, 0x09, 0x04, 0x0b, 0xfe, 0x68, 0x12, 0xfe, 0x2e, 0x1c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009437 0x02, 0xfe, 0x24, 0x0a, 0x61, 0x04, 0x06, 0x45, 0x61, 0x04, 0x0b, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009438 0x52, 0x12, 0xfe, 0x2c, 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x1e, 0x09, 0xfe,
9439 0xac, 0xf0, 0xfe, 0xbe, 0x08, 0xfe, 0x8a, 0x10, 0xaa, 0xfe, 0xf3, 0x10,
9440 0xfe, 0xad, 0xf0, 0xfe, 0xca, 0x08, 0x02, 0xfe, 0x24, 0x0a, 0xab, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009441 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0x9d, 0xe9, 0x1c, 0xfe, 0x00, 0xfe, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009442 0x1c, 0x12, 0xb5, 0xfe, 0xd2, 0xf0, 0x9d, 0xfe, 0x76, 0x18, 0x1c, 0x1a,
9443 0x16, 0x9d, 0x05, 0xcb, 0x1c, 0x06, 0x16, 0x9d, 0xb8, 0x6d, 0xb9, 0x6d,
9444 0xaa, 0xab, 0xfe, 0xb1, 0x10, 0x70, 0x5e, 0x2b, 0x14, 0x92, 0x01, 0x33,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009445 0x0f, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x5a, 0x0f, 0x7c, 0x02, 0x5a,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009446 0xfe, 0x74, 0x18, 0x1c, 0xfe, 0x00, 0xf8, 0x16, 0x6d, 0x67, 0x1b, 0x01,
9447 0xfe, 0x44, 0x0d, 0x3b, 0x01, 0xe6, 0x1e, 0x27, 0x74, 0x67, 0x1a, 0x02,
9448 0x6d, 0x09, 0x04, 0x0b, 0x21, 0xfe, 0x06, 0x0a, 0x09, 0x04, 0x6a, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009449 0x82, 0x12, 0x09, 0x04, 0x19, 0xfe, 0x66, 0x13, 0x1e, 0x58, 0xac, 0xfc,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009450 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91,
9451 0xfe, 0x86, 0x91, 0x63, 0x27, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x77,
9452 0xd7, 0x05, 0x54, 0x31, 0x55, 0x0c, 0x7b, 0x18, 0x7c, 0xbe, 0x54, 0xbf,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009453 0x55, 0x01, 0xa8, 0xad, 0x63, 0x27, 0x12, 0x58, 0xc0, 0x38, 0xc1, 0x4e,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009454 0x79, 0x56, 0x68, 0x57, 0xf4, 0xf5, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05,
9455 0xfa, 0x4e, 0x01, 0xa5, 0xa2, 0x23, 0x0c, 0x7b, 0x0c, 0x7c, 0x79, 0x56,
9456 0x68, 0x57, 0xfe, 0x12, 0x10, 0x09, 0x04, 0x19, 0x16, 0xd7, 0x79, 0x39,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009457 0x68, 0x3a, 0x09, 0x04, 0xfe, 0xf7, 0x00, 0x35, 0x05, 0x52, 0x31, 0x53,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009458 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59,
9459 0x02, 0x6d, 0x09, 0x04, 0x19, 0x16, 0xd7, 0x09, 0x04, 0xfe, 0xf7, 0x00,
9460 0x35, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x5f, 0xfe, 0x10, 0x90, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009461 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x2f, 0x07, 0x9b, 0x16, 0xfe, 0xc6, 0x08,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009462 0x11, 0x9b, 0x09, 0x04, 0x0b, 0xfe, 0x14, 0x13, 0x05, 0x39, 0x31, 0x3a,
9463 0x77, 0xfe, 0xc6, 0x08, 0xfe, 0x0c, 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x6d,
9464 0x23, 0x47, 0xfe, 0x19, 0x80, 0xde, 0x09, 0x04, 0x0b, 0xfe, 0x1a, 0x12,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009465 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xe9, 0xb5, 0xfe, 0xd1, 0xf0, 0xd9,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009466 0x14, 0x7a, 0x01, 0x33, 0x0f, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe,
9467 0x6c, 0x19, 0xbe, 0x39, 0xfe, 0xed, 0x19, 0xbf, 0x3a, 0xfe, 0x0c, 0x51,
9468 0xfe, 0x8e, 0x51, 0xe9, 0x1c, 0xfe, 0x00, 0xff, 0x34, 0xfe, 0x74, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009469 0xb5, 0xfe, 0xd2, 0xf0, 0xfe, 0xb2, 0x0a, 0xfe, 0x76, 0x18, 0x1c, 0x1a,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009470 0x84, 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0x08, 0x13, 0x0f, 0xfe, 0x16, 0x00,
9471 0x02, 0x5a, 0xfe, 0xd1, 0xf0, 0xfe, 0xc4, 0x0a, 0x14, 0x7a, 0x01, 0x33,
9472 0x0f, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe, 0xce, 0xf0, 0xfe, 0xca,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009473 0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x0f, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009474 0x22, 0x00, 0x02, 0x5a, 0xfe, 0xcb, 0xf0, 0xfe, 0xe2, 0x0a, 0x0f, 0xfe,
9475 0x24, 0x00, 0x02, 0x5a, 0xfe, 0xd0, 0xf0, 0xfe, 0xec, 0x0a, 0x0f, 0x93,
9476 0xdc, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x0f, 0x4c, 0xfe, 0x10, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009477 0xfe, 0xcc, 0xf0, 0xd9, 0x61, 0x04, 0x19, 0x3b, 0x0f, 0xfe, 0x12, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009478 0x2a, 0x13, 0xfe, 0x4e, 0x11, 0x65, 0xfe, 0x0c, 0x0b, 0xfe, 0x9e, 0xf0,
9479 0xfe, 0x20, 0x0b, 0xb1, 0x16, 0x32, 0x2a, 0x73, 0xdd, 0xb8, 0x22, 0xb9,
9480 0x22, 0x2a, 0xec, 0x65, 0xfe, 0x2c, 0x0b, 0x25, 0x32, 0x8c, 0xfe, 0x48,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009481 0x0b, 0x8d, 0x81, 0xb8, 0xd4, 0xb9, 0xd4, 0x02, 0x22, 0x01, 0x43, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009482 0xdb, 0x10, 0x11, 0xfe, 0xe8, 0x00, 0xaa, 0xab, 0x70, 0xbc, 0x7d, 0xbd,
9483 0x7f, 0xfe, 0x89, 0xf0, 0x22, 0x30, 0x2e, 0xd8, 0xbc, 0x7d, 0xbd, 0x7f,
9484 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd6, 0xb1, 0x45, 0x0f, 0xfe, 0x42,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009485 0x00, 0x02, 0x5a, 0x78, 0x06, 0xfe, 0x81, 0x49, 0x16, 0xfe, 0x38, 0x0c,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009486 0x09, 0x04, 0x0b, 0xfe, 0x44, 0x13, 0x0f, 0x00, 0x4b, 0x0b, 0xfe, 0x54,
9487 0x12, 0x4b, 0xfe, 0x28, 0x00, 0x21, 0xfe, 0xa6, 0x0c, 0x0a, 0x40, 0x01,
9488 0x0e, 0x07, 0x00, 0x5d, 0x3e, 0xfe, 0x28, 0x00, 0xfe, 0xe2, 0x10, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009489 0xe7, 0x01, 0xe8, 0x0a, 0x99, 0x01, 0xfe, 0x32, 0x0e, 0x59, 0x11, 0x2d,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009490 0x01, 0x6f, 0x02, 0x29, 0x0f, 0xfe, 0x44, 0x00, 0x4b, 0x0b, 0xdf, 0x3e,
9491 0x0b, 0xfe, 0xb4, 0x10, 0x01, 0x86, 0x3e, 0x0b, 0xfe, 0xaa, 0x10, 0x01,
9492 0x86, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xa3, 0x3e, 0x0b, 0x0f, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009493 0x43, 0x00, 0xfe, 0x96, 0x10, 0x09, 0x4a, 0x0b, 0x35, 0x01, 0xe7, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009494 0xe8, 0x59, 0x11, 0x2d, 0x01, 0x6f, 0x67, 0x0b, 0x59, 0x3c, 0x8a, 0x02,
9495 0xfe, 0x2a, 0x03, 0x09, 0x04, 0x0b, 0x84, 0x3e, 0x0b, 0x0f, 0x00, 0xfe,
9496 0x5c, 0x10, 0x61, 0x04, 0x1b, 0xfe, 0x58, 0x12, 0x09, 0x04, 0x1b, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009497 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x5c, 0x0c, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009498 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x62, 0x0c, 0x09, 0x4a, 0x1b, 0x35,
9499 0xfe, 0xa9, 0x10, 0x0f, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0b, 0x5f,
9500 0x5c, 0x0f, 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x0f, 0xfe, 0x47, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009501 0xa1, 0x0f, 0xfe, 0x41, 0x00, 0xa0, 0x0f, 0xfe, 0x24, 0x00, 0x87, 0xaa,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009502 0xab, 0x70, 0x05, 0x6b, 0x28, 0x21, 0xd1, 0x5f, 0xfe, 0x04, 0xe6, 0x1b,
9503 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x59, 0x01, 0xda, 0x02, 0x29, 0xea,
9504 0x14, 0x0b, 0x37, 0x95, 0xa9, 0x14, 0xfe, 0x31, 0x00, 0x37, 0x97, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009505 0xfe, 0x54, 0x0f, 0x02, 0xd0, 0x3c, 0xfe, 0x06, 0xec, 0xc9, 0xee, 0x3e,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009506 0x1d, 0xfe, 0xce, 0x45, 0x34, 0x3c, 0xfe, 0x06, 0xea, 0xc9, 0xfe, 0x47,
9507 0x4b, 0x89, 0xfe, 0x75, 0x57, 0x05, 0x51, 0xfe, 0x98, 0x56, 0xfe, 0x38,
9508 0x12, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x44, 0x48, 0x46, 0x09, 0x04, 0x1d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009509 0xfe, 0x1a, 0x13, 0x0a, 0x40, 0x01, 0x0e, 0x47, 0xfe, 0x41, 0x58, 0x0a,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009510 0x99, 0x01, 0x0e, 0xfe, 0x49, 0x54, 0x8e, 0xfe, 0x2a, 0x0d, 0x02, 0xfe,
9511 0x2a, 0x03, 0x0a, 0x51, 0xfe, 0xee, 0x14, 0xee, 0x3e, 0x1d, 0xfe, 0xce,
9512 0x45, 0x34, 0x3c, 0xfe, 0xce, 0x47, 0xfe, 0xad, 0x13, 0x02, 0x29, 0x1e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009513 0x20, 0x07, 0x10, 0xfe, 0x9e, 0x12, 0x23, 0x12, 0x4d, 0x12, 0x94, 0x12,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009514 0xce, 0x1e, 0x2d, 0x47, 0x37, 0x2d, 0xb1, 0xe0, 0xfe, 0xbc, 0xf0, 0xfe,
9515 0xec, 0x0d, 0x13, 0x06, 0x12, 0x4d, 0x01, 0xfe, 0xe2, 0x15, 0x05, 0xfe,
9516 0x38, 0x01, 0x31, 0xfe, 0x3a, 0x01, 0x77, 0xfe, 0xf0, 0x0d, 0xfe, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009517 0xec, 0xce, 0x62, 0x00, 0x5d, 0xfe, 0x04, 0xec, 0x20, 0x46, 0xfe, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009518 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x52, 0x16, 0xfb, 0xfe, 0x48, 0xf4,
9519 0x0d, 0xfe, 0x18, 0x13, 0xaf, 0xfe, 0x02, 0xea, 0xce, 0x62, 0x7a, 0xfe,
9520 0xc5, 0x13, 0x14, 0x1b, 0x37, 0x95, 0xa9, 0x5c, 0x05, 0xfe, 0x38, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009521 0x1c, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x05, 0xfe, 0x3a, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009522 0x0c, 0xfe, 0x62, 0x01, 0x3d, 0x12, 0x20, 0x24, 0x06, 0x12, 0x2d, 0x11,
9523 0x2d, 0x8a, 0x13, 0x06, 0x03, 0x23, 0x03, 0x1e, 0x4d, 0xfe, 0xf7, 0x12,
9524 0x1e, 0x94, 0xac, 0x12, 0x94, 0x07, 0x7a, 0xfe, 0x71, 0x13, 0xfe, 0x24,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009525 0x1c, 0x14, 0x1a, 0x37, 0x95, 0xa9, 0xfe, 0xd9, 0x10, 0xb6, 0xfe, 0x03,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009526 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x03, 0xb6, 0xfe, 0x03, 0xdc,
9527 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x03, 0xfe, 0x03, 0x57, 0xb6, 0x23,
9528 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0xb6, 0x75, 0x03, 0x09, 0x04,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009529 0x4c, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009530 0xfe, 0x1e, 0x80, 0xe1, 0xfe, 0x1d, 0x80, 0xa4, 0xfe, 0x0c, 0x90, 0xfe,
9531 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xa3, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
9532 0x0b, 0xfe, 0x3c, 0x50, 0xa0, 0x01, 0xfe, 0x82, 0x16, 0x2f, 0x07, 0x2d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009533 0xe0, 0x01, 0xfe, 0xbc, 0x15, 0x09, 0x04, 0x1d, 0x45, 0x01, 0xe7, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009534 0xe8, 0x11, 0xfe, 0xe9, 0x00, 0x09, 0x04, 0x4c, 0xfe, 0x2c, 0x13, 0x01,
9535 0xfe, 0x14, 0x16, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90,
9536 0x0c, 0xfe, 0x64, 0x01, 0x18, 0xfe, 0x66, 0x01, 0x09, 0x04, 0x4f, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009537 0x12, 0x12, 0xfe, 0x03, 0x80, 0x74, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009538 0x40, 0x12, 0x20, 0x63, 0x27, 0x11, 0xc8, 0x59, 0x1e, 0x20, 0xed, 0x76,
9539 0x20, 0x03, 0xfe, 0x08, 0x1c, 0x05, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58,
9540 0x05, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x05, 0xfe, 0xb0, 0x00, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009541 0x08, 0x58, 0x05, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009542 0x24, 0x69, 0x12, 0xc9, 0x23, 0x0c, 0x50, 0x0c, 0x3f, 0x13, 0x40, 0x48,
9543 0x5f, 0x17, 0x1d, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x21, 0xfe, 0x08,
9544 0x0f, 0x3e, 0x10, 0x13, 0x42, 0x48, 0x17, 0x4c, 0xfe, 0x90, 0x4d, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009545 0x91, 0x54, 0x21, 0xfe, 0x1e, 0x0f, 0x24, 0x10, 0x12, 0x20, 0x78, 0x2c,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009546 0x46, 0x1e, 0x20, 0xed, 0x76, 0x20, 0x11, 0xc8, 0xf6, 0xfe, 0xd6, 0xf0,
9547 0xfe, 0x32, 0x0f, 0xea, 0x70, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
9548 0x18, 0x1c, 0x03, 0x3c, 0xfe, 0x0c, 0x14, 0xee, 0xfe, 0x07, 0xe6, 0x1d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009549 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x86, 0x78, 0x2c, 0x46,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009550 0xfa, 0xef, 0xfe, 0x42, 0x13, 0x2f, 0x07, 0x2d, 0xfe, 0x34, 0x13, 0x0a,
9551 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x36, 0x12, 0xf0, 0xfe, 0x45, 0x48, 0x01,
9552 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009553 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x6f, 0xfe, 0x0e,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009554 0x10, 0x07, 0x7e, 0x45, 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x6c, 0x0f, 0x03,
9555 0xfe, 0x44, 0x58, 0x74, 0xfe, 0x01, 0xec, 0x97, 0xfe, 0x9e, 0x40, 0xfe,
9556 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1b, 0x76, 0x27, 0x01, 0xda, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009557 0xdd, 0x10, 0x2a, 0xbc, 0x7d, 0xbd, 0x7f, 0x30, 0x2e, 0xd5, 0x07, 0x1b,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009558 0xfe, 0x48, 0x12, 0x07, 0x0b, 0xfe, 0x56, 0x12, 0x07, 0x1a, 0xfe, 0x30,
9559 0x12, 0x07, 0xc2, 0x16, 0xfe, 0x3e, 0x11, 0x07, 0xfe, 0x23, 0x00, 0x16,
9560 0xfe, 0x4a, 0x11, 0x07, 0x06, 0x16, 0xfe, 0xa8, 0x11, 0x07, 0x19, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009561 0x12, 0x12, 0x07, 0x00, 0x16, 0x22, 0x14, 0xc2, 0x01, 0x33, 0x9f, 0x2b,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009562 0x01, 0x08, 0x8c, 0x43, 0x03, 0x2b, 0xfe, 0x62, 0x08, 0x0a, 0xca, 0x01,
9563 0xfe, 0x32, 0x0e, 0x11, 0x7e, 0x02, 0x29, 0x2b, 0x2f, 0x07, 0x9b, 0xfe,
9564 0xd9, 0x13, 0x79, 0x39, 0x68, 0x3a, 0x77, 0xfe, 0xfc, 0x10, 0x09, 0x04,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009565 0x6a, 0xfe, 0x72, 0x12, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x8e, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009566 0xc6, 0x10, 0x1e, 0x58, 0xfe, 0x26, 0x13, 0x05, 0x7b, 0x31, 0x7c, 0x77,
9567 0xfe, 0x82, 0x0c, 0x0c, 0x54, 0x18, 0x55, 0x23, 0x0c, 0x7b, 0x0c, 0x7c,
9568 0x01, 0xa8, 0x24, 0x69, 0x73, 0x12, 0x58, 0x01, 0xa5, 0xc0, 0x38, 0xc1,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009569 0x4e, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x38, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009570 0x05, 0xfa, 0x4e, 0xfe, 0x91, 0x10, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x40,
9571 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x56, 0x18, 0x57, 0x83, 0xc0, 0x38, 0xc1,
9572 0x4e, 0xf4, 0xf5, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x00, 0x56, 0xfe, 0xa1,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009573 0x56, 0x0c, 0x52, 0x18, 0x53, 0x09, 0x04, 0x6a, 0xfe, 0x1e, 0x12, 0x1e,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009574 0x58, 0xfe, 0x1f, 0x40, 0x05, 0x54, 0x31, 0x55, 0xfe, 0x2c, 0x50, 0xfe,
9575 0xae, 0x50, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x44, 0x50, 0xfe, 0xc6, 0x50,
9576 0x05, 0x52, 0x31, 0x53, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x05, 0x39,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009577 0x31, 0x3a, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x5c, 0x24, 0x06,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009578 0x12, 0xcd, 0x02, 0x5b, 0x2b, 0x01, 0x08, 0x1f, 0x44, 0x30, 0x2e, 0xd5,
9579 0x07, 0x06, 0x21, 0x44, 0x2f, 0x07, 0x9b, 0x21, 0x5b, 0x01, 0x6e, 0x1c,
9580 0x3d, 0x16, 0x44, 0x09, 0x04, 0x0b, 0xe2, 0x79, 0x39, 0x68, 0x3a, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009581 0x0a, 0x55, 0x34, 0xfe, 0x8b, 0x55, 0xbe, 0x39, 0xbf, 0x3a, 0xfe, 0x0c,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009582 0x51, 0xfe, 0x8e, 0x51, 0x02, 0x5b, 0xfe, 0x19, 0x81, 0xaf, 0xfe, 0x19,
9583 0x41, 0x02, 0x5b, 0x2b, 0x01, 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e,
9584 0xd8, 0x4b, 0x1a, 0xfe, 0xa6, 0x12, 0x4b, 0x0b, 0x3b, 0x02, 0x44, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009585 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, 0xd6, 0x07, 0x1a, 0x21, 0x44,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009586 0x01, 0x08, 0x1f, 0xa2, 0x30, 0x2e, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49,
9587 0x60, 0x05, 0xfe, 0x9c, 0x00, 0x28, 0x84, 0x49, 0x04, 0x19, 0x34, 0x9f,
9588 0xfe, 0xbb, 0x45, 0x4b, 0x00, 0x45, 0x3e, 0x06, 0x78, 0x3d, 0xfe, 0xda,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009589 0x14, 0x01, 0x6e, 0x87, 0xfe, 0x4b, 0x45, 0xe2, 0x2f, 0x07, 0x9a, 0xe1,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009590 0x05, 0xc6, 0x28, 0x84, 0x05, 0x3f, 0x28, 0x34, 0x5e, 0x02, 0x5b, 0xfe,
9591 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17, 0x05, 0x50, 0xb4, 0x0c,
9592 0x50, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe, 0xaa, 0x14, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009593 0x5c, 0x01, 0x08, 0x25, 0x32, 0x1f, 0x44, 0x30, 0x2e, 0xd6, 0x07, 0x06,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009594 0x21, 0x44, 0x01, 0xfe, 0x8e, 0x13, 0xfe, 0x42, 0x58, 0xfe, 0x82, 0x14,
9595 0xfe, 0xa4, 0x14, 0x87, 0xfe, 0x4a, 0xf4, 0x0b, 0x16, 0x44, 0xfe, 0x4a,
9596 0xf4, 0x06, 0xfe, 0x0c, 0x12, 0x2f, 0x07, 0x9a, 0x85, 0x02, 0x5b, 0x05,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009597 0x3f, 0xb4, 0x0c, 0x3f, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009598 0xd8, 0x14, 0x02, 0x5c, 0x13, 0x06, 0x65, 0xfe, 0xca, 0x12, 0x26, 0xfe,
9599 0xe0, 0x12, 0x72, 0xf1, 0x01, 0x08, 0x23, 0x72, 0x03, 0x8f, 0xfe, 0xdc,
9600 0x12, 0x25, 0xfe, 0xdc, 0x12, 0x1f, 0xfe, 0xca, 0x12, 0x5e, 0x2b, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009601 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009602 0x1c, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13,
9603 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0x1c, 0x3d, 0xfe, 0x30, 0x56,
9604 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009605 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0xfe, 0x0b, 0x58,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009606 0x03, 0x0a, 0x50, 0x01, 0x82, 0x0a, 0x3f, 0x01, 0x82, 0x03, 0xfc, 0x1c,
9607 0x10, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x19, 0x48, 0xfe, 0x00,
9608 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x63, 0x27,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009609 0x0c, 0x52, 0x18, 0x53, 0xbe, 0x56, 0xbf, 0x57, 0x03, 0xfe, 0x62, 0x08,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009610 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x74, 0x03, 0x01,
9611 0xfe, 0x14, 0x18, 0xfe, 0x42, 0x48, 0x5f, 0x60, 0x89, 0x01, 0x08, 0x1f,
9612 0xfe, 0xa2, 0x14, 0x30, 0x2e, 0xd8, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009613 0x30, 0x2e, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x05, 0xc6, 0x28, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009614 0xcc, 0x12, 0x49, 0x04, 0x1b, 0xfe, 0xc4, 0x13, 0x23, 0x62, 0x1b, 0xe2,
9615 0x4b, 0xc3, 0x64, 0xfe, 0xe8, 0x13, 0x3b, 0x13, 0x06, 0x17, 0xc3, 0x78,
9616 0xdb, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xa1, 0xff, 0x02, 0x83,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009617 0x55, 0x62, 0x1a, 0xa4, 0xbb, 0xfe, 0x30, 0x00, 0x8e, 0xe4, 0x17, 0x2c,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009618 0x13, 0x06, 0xfe, 0x56, 0x10, 0x62, 0x0b, 0xe1, 0xbb, 0xfe, 0x64, 0x00,
9619 0x8e, 0xe4, 0x0a, 0xfe, 0x64, 0x00, 0x17, 0x93, 0x13, 0x06, 0xfe, 0x28,
9620 0x10, 0x62, 0x06, 0xfe, 0x60, 0x13, 0xbb, 0xfe, 0xc8, 0x00, 0x8e, 0xe4,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009621 0x0a, 0xfe, 0xc8, 0x00, 0x17, 0x4d, 0x13, 0x06, 0x83, 0xbb, 0xfe, 0x90,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009622 0x01, 0xba, 0xfe, 0x4e, 0x14, 0x89, 0xfe, 0x12, 0x10, 0xfe, 0x43, 0xf4,
9623 0x94, 0xfe, 0x56, 0xf0, 0xfe, 0x60, 0x14, 0xfe, 0x04, 0xf4, 0x6c, 0xfe,
9624 0x43, 0xf4, 0x93, 0xfe, 0xf3, 0x10, 0xf9, 0x01, 0xfe, 0x22, 0x13, 0x1c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009625 0x3d, 0xfe, 0x10, 0x13, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x69, 0xba,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009626 0xfe, 0x9c, 0x14, 0xb7, 0x69, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe,
9627 0x4d, 0xe4, 0x19, 0xba, 0xfe, 0x9c, 0x14, 0xb7, 0x19, 0x83, 0x60, 0x23,
9628 0xfe, 0x4d, 0xf4, 0x00, 0xdf, 0x89, 0x13, 0x06, 0xfe, 0xb4, 0x56, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009629 0xc3, 0x58, 0x03, 0x60, 0x13, 0x0b, 0x03, 0x15, 0x06, 0x01, 0x08, 0x26,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009630 0xe5, 0x15, 0x0b, 0x01, 0x08, 0x26, 0xe5, 0x15, 0x1a, 0x01, 0x08, 0x26,
9631 0xe5, 0x72, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x03, 0x15, 0x06, 0x01, 0x08,
9632 0x26, 0xa6, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x06, 0x01, 0x08,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009633 0x26, 0xa6, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x26, 0xa6, 0x72, 0xfe, 0x89,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009634 0x4a, 0x01, 0x08, 0x03, 0x60, 0x03, 0x1e, 0xcc, 0x07, 0x06, 0xfe, 0x44,
9635 0x13, 0xad, 0x12, 0xcc, 0xfe, 0x49, 0xf4, 0x00, 0x3b, 0x72, 0x9f, 0x5e,
9636 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01, 0x08, 0x2f, 0x07, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009637 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0x5a, 0x15, 0x23, 0x12, 0xcd,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009638 0x01, 0x43, 0x1e, 0xcd, 0x07, 0x06, 0x45, 0x09, 0x4a, 0x06, 0x35, 0x03,
9639 0x0a, 0x42, 0x01, 0x0e, 0xed, 0x88, 0x07, 0x10, 0xa4, 0x0a, 0x80, 0x01,
9640 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x80, 0x01, 0x0e, 0x88,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009641 0xfe, 0x80, 0xe7, 0x10, 0x07, 0x10, 0x84, 0xfe, 0x45, 0x58, 0x01, 0xe3,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009642 0x88, 0x03, 0x0a, 0x42, 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03,
9643 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x80, 0x80, 0xf2, 0xfe, 0x49, 0xe4, 0x10,
9644 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x0a, 0x51, 0x01, 0x82, 0x03, 0x17,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009645 0x10, 0x71, 0x66, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009646 0xfe, 0x24, 0x1c, 0xfe, 0x1d, 0xf7, 0x1d, 0x90, 0xfe, 0xf6, 0x15, 0x01,
9647 0xfe, 0xfc, 0x16, 0xe0, 0x91, 0x1d, 0x66, 0xfe, 0x2c, 0x01, 0xfe, 0x2f,
9648 0x19, 0x03, 0xae, 0x21, 0xfe, 0xe6, 0x15, 0xfe, 0xda, 0x10, 0x17, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009649 0x71, 0x05, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009650 0x05, 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0x91, 0x19, 0xfe, 0x3c, 0x90,
9651 0xfe, 0x30, 0xf4, 0x06, 0xfe, 0x3c, 0x50, 0x66, 0xfe, 0x38, 0x00, 0xfe,
9652 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x90, 0xfe, 0x40, 0x16, 0xfe, 0xb6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009653 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x18, 0x16, 0xfe, 0x9c, 0x10, 0x17,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009654 0x10, 0x71, 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe,
9655 0x1d, 0xf7, 0x38, 0x90, 0xfe, 0x62, 0x16, 0xfe, 0x94, 0x14, 0xfe, 0x10,
9656 0x13, 0x91, 0x38, 0x66, 0x1b, 0xfe, 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009657 0x03, 0xae, 0x21, 0xfe, 0x56, 0x16, 0xfe, 0x6c, 0x10, 0x17, 0x10, 0x71,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009658 0xfe, 0x30, 0xbc, 0xfe, 0xb2, 0xbc, 0x91, 0xc5, 0x66, 0x1b, 0xfe, 0x0f,
9659 0x79, 0xfe, 0x1c, 0xf7, 0xc5, 0x90, 0xfe, 0x9a, 0x16, 0xfe, 0x5c, 0x14,
9660 0x34, 0x03, 0xae, 0x21, 0xfe, 0x86, 0x16, 0xfe, 0x42, 0x10, 0xfe, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009661 0xf6, 0x10, 0x71, 0xfe, 0x18, 0xfe, 0x54, 0xfe, 0x19, 0xfe, 0x55, 0xfc,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009662 0xfe, 0x1d, 0xf7, 0x4f, 0x90, 0xfe, 0xc0, 0x16, 0xfe, 0x36, 0x14, 0xfe,
9663 0x1c, 0x13, 0x91, 0x4f, 0x47, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe,
9664 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11, 0xfe, 0xdd, 0x00, 0x63,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009665 0x27, 0x03, 0x63, 0x27, 0xfe, 0x12, 0x45, 0x21, 0xfe, 0xb0, 0x16, 0x14,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009666 0x06, 0x37, 0x95, 0xa9, 0x02, 0x29, 0xfe, 0x39, 0xf0, 0xfe, 0x04, 0x17,
9667 0x23, 0x03, 0xfe, 0x7e, 0x18, 0x1c, 0x1a, 0x5d, 0x13, 0x0d, 0x03, 0x71,
9668 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x78, 0x2c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009669 0x46, 0x2f, 0x07, 0x2d, 0xfe, 0x3c, 0x13, 0xfe, 0x82, 0x14, 0xfe, 0x42,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009670 0x13, 0x3c, 0x8a, 0x0a, 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x3e, 0x12, 0xf0,
9671 0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13,
9672 0x3d, 0x75, 0x07, 0x10, 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x01, 0x6f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009673 0xfe, 0x16, 0x10, 0x07, 0x7e, 0x85, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009674 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x24, 0x17, 0x17, 0x0b, 0x03, 0xfe, 0x9c,
9675 0xe7, 0x0b, 0x0f, 0xfe, 0x15, 0x00, 0x59, 0x76, 0x27, 0x01, 0xda, 0x17,
9676 0x06, 0x03, 0x3c, 0x8a, 0x09, 0x4a, 0x1d, 0x35, 0x11, 0x2d, 0x01, 0x6f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009677 0x17, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x79, 0xc7, 0x68,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009678 0xc8, 0xfe, 0x48, 0x55, 0x34, 0xfe, 0xc9, 0x55, 0x03, 0x1e, 0x98, 0x73,
9679 0x12, 0x98, 0x03, 0x0a, 0x99, 0x01, 0x0e, 0xf0, 0x0a, 0x40, 0x01, 0x0e,
9680 0xfe, 0x49, 0x44, 0x16, 0xfe, 0xf0, 0x17, 0x73, 0x75, 0x03, 0x0a, 0x42,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009681 0x01, 0x0e, 0x07, 0x10, 0x45, 0x0a, 0x51, 0x01, 0x9e, 0x0a, 0x40, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009682 0x0e, 0x73, 0x75, 0x03, 0xfe, 0x4e, 0xe4, 0x1a, 0x64, 0xfe, 0x24, 0x18,
9683 0x05, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0x5b, 0xfe, 0x4e, 0xe4, 0xc2,
9684 0x64, 0xfe, 0x36, 0x18, 0x05, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009685 0xdc, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x64, 0xfe, 0x48, 0x18, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009686 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x19, 0xfe, 0x08, 0x10, 0x05, 0xfe,
9687 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x2c, 0xfe, 0x4e, 0x45, 0xfe, 0x0c, 0x12,
9688 0xaf, 0xff, 0x04, 0x68, 0x54, 0xde, 0x1c, 0x69, 0x03, 0x07, 0x7a, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009689 0x5a, 0xf0, 0xfe, 0x74, 0x18, 0x24, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009690 0x07, 0x1b, 0xfe, 0x5a, 0xf0, 0xfe, 0x82, 0x18, 0x24, 0xc3, 0xfe, 0x26,
9691 0x10, 0x07, 0x1a, 0x5d, 0x24, 0x2c, 0xdc, 0x07, 0x0b, 0x5d, 0x24, 0x93,
9692 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x5d, 0x24, 0x4d, 0x9f, 0xad, 0x03, 0x14,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009693 0xfe, 0x09, 0x00, 0x01, 0x33, 0xfe, 0x04, 0xfe, 0x7d, 0x05, 0x7f, 0xf9,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009694 0x03, 0x25, 0xfe, 0xca, 0x18, 0xfe, 0x14, 0xf0, 0x08, 0x65, 0xfe, 0xc6,
9695 0x18, 0x03, 0xff, 0x1a, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -07009696};
9697
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009698static unsigned short _adv_asc3550_size = sizeof(_adv_asc3550_buf); /* 0x13AD */
9699static ADV_DCNT _adv_asc3550_chksum = 0x04D52DDDUL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07009700
9701/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009702static unsigned char _adv_asc38C0800_buf[] = {
9703 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x16, 0x18, 0xe4,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009704 0x01, 0x00, 0x48, 0xe4, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0xce, 0x19,
9705 0x00, 0xfa, 0xff, 0xff, 0x1c, 0x0f, 0x00, 0xf6, 0x9e, 0xe7, 0xff, 0x00,
9706 0x82, 0xe7, 0x00, 0xea, 0x01, 0xfa, 0x01, 0xe6, 0x09, 0xe7, 0x55, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009707 0x01, 0xf6, 0x03, 0x00, 0x04, 0x00, 0x10, 0x00, 0x1e, 0xf0, 0x85, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009708 0x18, 0xf4, 0x08, 0x00, 0xbc, 0x00, 0x38, 0x54, 0x00, 0xec, 0xd5, 0xf0,
9709 0x82, 0x0d, 0x00, 0xe6, 0x86, 0xf0, 0xb1, 0xf0, 0x98, 0x57, 0x01, 0xfc,
9710 0xb4, 0x00, 0xd4, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x3c, 0x00, 0xbb, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009711 0x00, 0x10, 0xba, 0x19, 0x02, 0x80, 0x32, 0xf0, 0x7c, 0x0d, 0x02, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009712 0xba, 0x13, 0x18, 0x40, 0x00, 0x57, 0x01, 0xea, 0x02, 0xfc, 0x03, 0xfc,
9713 0x3e, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x74, 0x01, 0x76, 0x01, 0xb9, 0x54,
9714 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00, 0xc0, 0x00, 0x01, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009715 0x3e, 0x01, 0x7a, 0x01, 0xca, 0x08, 0xce, 0x10, 0x16, 0x11, 0x04, 0x12,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009716 0x08, 0x12, 0x02, 0x4a, 0xbb, 0x55, 0x3c, 0x56, 0x03, 0x58, 0x1b, 0x80,
9717 0x30, 0xe4, 0x4b, 0xe4, 0x5d, 0xf0, 0x02, 0xfa, 0x20, 0x00, 0x32, 0x00,
9718 0x40, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009719 0x70, 0x01, 0x72, 0x01, 0x78, 0x01, 0x7c, 0x01, 0x62, 0x0a, 0x86, 0x0d,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009720 0x06, 0x13, 0x4c, 0x1c, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0,
9721 0x03, 0xf7, 0x0c, 0x00, 0x0f, 0x00, 0x47, 0x00, 0xbe, 0x00, 0x00, 0x01,
9722 0x20, 0x11, 0x5c, 0x16, 0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009723 0x00, 0x4c, 0x04, 0xea, 0x5c, 0xf0, 0xa7, 0xf0, 0x04, 0xf6, 0x03, 0xfa,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009724 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01,
9725 0x4e, 0x01, 0x4a, 0x0b, 0x42, 0x0c, 0x12, 0x0f, 0x0c, 0x10, 0x22, 0x11,
9726 0x0a, 0x12, 0x04, 0x13, 0x30, 0x1c, 0x02, 0x48, 0x00, 0x4e, 0x42, 0x54,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009727 0x44, 0x55, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009728 0x59, 0xf0, 0xb8, 0xf0, 0x4b, 0xf4, 0x06, 0xf7, 0x0e, 0xf7, 0x04, 0xfc,
9729 0x05, 0xfc, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00, 0xa4, 0x00,
9730 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xe2, 0x03,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009731 0x08, 0x0f, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, 0x0a, 0x13, 0x0c, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009732 0x12, 0x13, 0x24, 0x14, 0x34, 0x14, 0x04, 0x16, 0x08, 0x16, 0xa4, 0x17,
9733 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44, 0x91, 0x44,
9734 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x3a, 0x55, 0x83, 0x55,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009735 0xe5, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009736 0x0c, 0xf0, 0x04, 0xf8, 0x05, 0xf8, 0x07, 0x00, 0x0a, 0x00, 0x1c, 0x00,
9737 0x1e, 0x00, 0x9e, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00,
9738 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7e, 0x01, 0xc4, 0x01, 0xc6, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009739 0x80, 0x02, 0x5e, 0x03, 0xee, 0x04, 0x9a, 0x06, 0xf8, 0x07, 0x62, 0x08,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009740 0x68, 0x08, 0x69, 0x08, 0xd6, 0x08, 0xe9, 0x09, 0xfa, 0x0b, 0x2e, 0x0f,
9741 0x12, 0x10, 0x1a, 0x10, 0xed, 0x10, 0xf1, 0x10, 0x2a, 0x11, 0x06, 0x12,
9742 0x0c, 0x12, 0x3e, 0x12, 0x10, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x46, 0x14,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009743 0x76, 0x14, 0x82, 0x14, 0x36, 0x15, 0xca, 0x15, 0x6b, 0x18, 0xbe, 0x18,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009744 0xca, 0x18, 0xe6, 0x19, 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40,
9745 0x0e, 0x47, 0xfe, 0x9c, 0xf0, 0x2b, 0x02, 0xfe, 0xac, 0x0d, 0xff, 0x10,
9746 0x00, 0x00, 0xd7, 0xfe, 0xe8, 0x19, 0x00, 0xd6, 0xfe, 0x84, 0x01, 0xff,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009747 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009748 0x00, 0xfe, 0x57, 0x24, 0x00, 0xfe, 0x4c, 0x00, 0x5b, 0xff, 0x04, 0x00,
9749 0x00, 0x11, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x08,
9750 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x11,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009751 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009752 0xfe, 0x04, 0xf7, 0xd6, 0x2c, 0x99, 0x0a, 0x01, 0xfe, 0xc2, 0x0f, 0xfe,
9753 0x04, 0xf7, 0xd6, 0x99, 0x0a, 0x42, 0x2c, 0xfe, 0x3d, 0xf0, 0xfe, 0x06,
9754 0x02, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x91, 0xf0, 0xfe, 0xf4, 0x01, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009755 0x90, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, 0x8f, 0xf0, 0xa7, 0x03, 0x5d, 0x4d,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009756 0x02, 0xfe, 0xc8, 0x0d, 0x01, 0xfe, 0x38, 0x0e, 0xfe, 0xdd, 0x12, 0xfe,
9757 0xfc, 0x10, 0xfe, 0x28, 0x1c, 0x03, 0xfe, 0xa6, 0x00, 0xfe, 0xd3, 0x12,
9758 0x41, 0x14, 0xfe, 0xa6, 0x00, 0xc2, 0xfe, 0x48, 0xf0, 0xfe, 0x8a, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009759 0xfe, 0x49, 0xf0, 0xfe, 0xa4, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc2, 0x02,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009760 0xfe, 0x46, 0xf0, 0xfe, 0x54, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x5a, 0x02,
9761 0xfe, 0x43, 0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x4c, 0x02,
9762 0xfe, 0x45, 0xf0, 0xfe, 0x50, 0x02, 0x18, 0x0a, 0xaa, 0x18, 0x06, 0x14,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009763 0xa1, 0x02, 0x2b, 0xfe, 0x00, 0x1c, 0xe7, 0xfe, 0x02, 0x1c, 0xe6, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009764 0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0xfe, 0x18, 0x18, 0xfe, 0xe7, 0x10,
9765 0xfe, 0x06, 0xfc, 0xce, 0x09, 0x70, 0x01, 0xa8, 0x02, 0x2b, 0x15, 0x59,
9766 0x39, 0xa2, 0x01, 0xfe, 0x58, 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xbd,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009767 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009768 0x58, 0x1c, 0x18, 0x06, 0x14, 0xa1, 0x2c, 0x1c, 0x2b, 0xfe, 0x3d, 0xf0,
9769 0xfe, 0x06, 0x02, 0x23, 0xfe, 0x98, 0x02, 0xfe, 0x5a, 0x1c, 0xf8, 0xfe,
9770 0x14, 0x1c, 0x15, 0xfe, 0x30, 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009771 0x18, 0x06, 0x14, 0xa1, 0x02, 0xd7, 0x22, 0x20, 0x07, 0x11, 0x35, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009772 0x69, 0x10, 0x18, 0x06, 0x14, 0xa1, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0x43,
9773 0x13, 0x20, 0xfe, 0x05, 0xf6, 0xce, 0x01, 0xfe, 0x4a, 0x17, 0x08, 0x54,
9774 0x58, 0x37, 0x12, 0x2f, 0x42, 0x92, 0x01, 0xfe, 0x82, 0x16, 0x02, 0x2b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009775 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x01, 0x73, 0xfe, 0x18, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009776 0xfe, 0x41, 0x58, 0x09, 0xa4, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x6b, 0xfe,
9777 0x10, 0x03, 0x01, 0xfe, 0x82, 0x16, 0x02, 0x2b, 0x2c, 0x4f, 0xfe, 0x02,
9778 0xe8, 0x2a, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009779 0x27, 0xf0, 0xfe, 0xe0, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xa7,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009780 0xfe, 0x40, 0x1c, 0x1c, 0xd9, 0xfe, 0x26, 0xf0, 0xfe, 0x5a, 0x03, 0xfe,
9781 0xa0, 0xf0, 0xfe, 0x48, 0x03, 0xfe, 0x11, 0xf0, 0xa7, 0xfe, 0xef, 0x10,
9782 0xfe, 0x9f, 0xf0, 0xfe, 0x68, 0x03, 0xf9, 0x10, 0xfe, 0x11, 0x00, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009783 0x65, 0x2c, 0xfe, 0x48, 0x1c, 0xf9, 0x08, 0x05, 0x1b, 0xfe, 0x18, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009784 0x21, 0x22, 0xa3, 0xb7, 0x13, 0xa3, 0x09, 0x46, 0x01, 0x0e, 0xb7, 0x78,
9785 0x01, 0xfe, 0xb4, 0x16, 0x12, 0xd1, 0x1c, 0xd9, 0xfe, 0x01, 0xf0, 0xd9,
9786 0xfe, 0x82, 0xf0, 0xfe, 0x96, 0x03, 0xfa, 0x12, 0xfe, 0xe4, 0x00, 0x27,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009787 0xfe, 0xa8, 0x03, 0x1c, 0x34, 0x1d, 0xfe, 0xb8, 0x03, 0x01, 0x4b, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009788 0x06, 0xf0, 0xfe, 0xc8, 0x03, 0x95, 0x86, 0xfe, 0x0a, 0xf0, 0xfe, 0x8a,
9789 0x06, 0x02, 0x24, 0x03, 0x70, 0x28, 0x17, 0xfe, 0xfa, 0x04, 0x15, 0x6d,
9790 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, 0xd8, 0xf9, 0x2c, 0x99, 0x19,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009791 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009792 0x74, 0x01, 0xaf, 0x8c, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x17, 0xda,
9793 0x09, 0xd1, 0x01, 0x0e, 0x8d, 0x51, 0x64, 0x79, 0x2a, 0x03, 0x70, 0x28,
9794 0xfe, 0x10, 0x12, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009795 0xd8, 0xc7, 0x81, 0xc8, 0x83, 0x1c, 0x24, 0x27, 0xfe, 0x40, 0x04, 0x1d,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009796 0xfe, 0x3c, 0x04, 0x3b, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e,
9797 0x12, 0x2d, 0xff, 0x02, 0x00, 0x10, 0x01, 0x0b, 0x1d, 0xfe, 0xe4, 0x04,
9798 0x2d, 0x01, 0x0b, 0x1d, 0x24, 0x33, 0x31, 0xde, 0xfe, 0x4c, 0x44, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009799 0x4c, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009800 0xda, 0x4f, 0x79, 0x2a, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x62,
9801 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x2a, 0x13, 0x32, 0x07, 0x82, 0xfe, 0x52,
9802 0x13, 0xfe, 0x20, 0x10, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b, 0xda, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009803 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x40, 0x13, 0x08, 0x05, 0x1b, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009804 0x08, 0x13, 0x32, 0x07, 0x82, 0xfe, 0x30, 0x13, 0x08, 0x05, 0x1b, 0xfe,
9805 0x1c, 0x12, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe, 0x0d, 0x00,
9806 0x01, 0x36, 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x2d, 0x12, 0xfe, 0xe6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009807 0x00, 0xfe, 0x1c, 0x90, 0xfe, 0x40, 0x5c, 0x04, 0x15, 0x9d, 0x01, 0x36,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009808 0x02, 0x2b, 0xfe, 0x42, 0x5b, 0x99, 0x19, 0xfe, 0x46, 0x59, 0xfe, 0xbf,
9809 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x87, 0x80, 0xfe, 0x31, 0xe4, 0x5b, 0x08,
9810 0x05, 0x0a, 0xfe, 0x84, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x19, 0xfe, 0x7c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009811 0x12, 0x53, 0x05, 0x06, 0xfe, 0x6c, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x28,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009812 0x17, 0xfe, 0x90, 0x05, 0xfe, 0x31, 0xe4, 0x5a, 0x53, 0x05, 0x0a, 0xfe,
9813 0x56, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x28, 0xfe, 0x4e, 0x12, 0x67, 0xff,
9814 0x02, 0x00, 0x10, 0x27, 0xfe, 0x48, 0x05, 0x1c, 0x34, 0xfe, 0x89, 0x48,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009815 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x56, 0x05, 0x26, 0xfe, 0xa8, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009816 0x12, 0xfe, 0xe3, 0x00, 0x21, 0x53, 0xfe, 0x4a, 0xf0, 0xfe, 0x76, 0x05,
9817 0xfe, 0x49, 0xf0, 0xfe, 0x70, 0x05, 0x88, 0x25, 0xfe, 0x21, 0x00, 0xab,
9818 0x25, 0xfe, 0x22, 0x00, 0xaa, 0x25, 0x58, 0xfe, 0x09, 0x48, 0xff, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009819 0x00, 0x10, 0x27, 0xfe, 0x86, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0xfe, 0xe2,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009820 0x08, 0x53, 0x05, 0xcb, 0x4d, 0x01, 0xb0, 0x25, 0x06, 0x13, 0xd3, 0x39,
9821 0xfe, 0x27, 0x01, 0x08, 0x05, 0x1b, 0xfe, 0x22, 0x12, 0x41, 0x01, 0xb2,
9822 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009823 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0xeb,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009824 0x03, 0x5c, 0x28, 0xfe, 0x36, 0x13, 0x41, 0x01, 0xb2, 0x26, 0xfe, 0x18,
9825 0x06, 0x09, 0x06, 0x53, 0x05, 0x1f, 0xfe, 0x02, 0x12, 0x50, 0x01, 0xfe,
9826 0x9e, 0x15, 0x1d, 0xfe, 0x0e, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009827 0xe5, 0x00, 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x03, 0xcd, 0x28, 0xfe, 0x62,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009828 0x12, 0x03, 0x45, 0x28, 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x0c, 0x19, 0x01,
9829 0xfe, 0x76, 0x19, 0xfe, 0x43, 0x48, 0xc4, 0xcc, 0x0f, 0x71, 0xff, 0x02,
9830 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0x8b, 0xc4, 0x6e, 0x41, 0x01, 0xb2,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009831 0x26, 0xfe, 0x82, 0x06, 0x53, 0x05, 0x1a, 0xe9, 0x91, 0x09, 0x59, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009832 0xfe, 0xcc, 0x15, 0x1d, 0xfe, 0x78, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12,
9833 0xfe, 0xe5, 0x00, 0x03, 0x45, 0xc1, 0x0c, 0x45, 0x18, 0x06, 0x01, 0xb2,
9834 0xfa, 0x76, 0x74, 0x01, 0xaf, 0x8c, 0x12, 0xfe, 0xe2, 0x00, 0x27, 0xdb,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009835 0x1c, 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0xb6, 0x06, 0x94, 0xfe, 0x6c, 0x07,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009836 0xfe, 0x06, 0xf0, 0xfe, 0x74, 0x07, 0x95, 0x86, 0x02, 0x24, 0x08, 0x05,
9837 0x0a, 0xfe, 0x2e, 0x12, 0x16, 0x19, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b,
9838 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0xfe, 0x99, 0xa4, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009839 0x0b, 0x16, 0x00, 0x02, 0xfe, 0x42, 0x08, 0x68, 0x05, 0x1a, 0xfe, 0x38,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009840 0x12, 0x08, 0x05, 0x1a, 0xfe, 0x30, 0x13, 0x16, 0xfe, 0x1b, 0x00, 0x01,
9841 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01,
9842 0x0b, 0x16, 0x06, 0x01, 0x0b, 0x16, 0x00, 0x02, 0xe2, 0x6c, 0x58, 0xbe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009843 0x50, 0xfe, 0x9a, 0x81, 0x55, 0x1b, 0x7a, 0xfe, 0x42, 0x07, 0x09, 0x1b,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009844 0xfe, 0x09, 0x6f, 0xba, 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x69, 0x6d,
9845 0x8b, 0x6c, 0x7f, 0x27, 0xfe, 0x54, 0x07, 0x1c, 0x34, 0xfe, 0x0a, 0xf0,
9846 0xfe, 0x42, 0x07, 0x95, 0x86, 0x94, 0xfe, 0x6c, 0x07, 0x02, 0x24, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009847 0x4b, 0x02, 0xdb, 0x16, 0x1f, 0x02, 0xdb, 0xfe, 0x9c, 0xf7, 0xdc, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009848 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x56, 0xfe, 0xda, 0x07, 0x0c, 0x60, 0x14,
9849 0x61, 0x08, 0x54, 0x5a, 0x37, 0x22, 0x20, 0x07, 0x11, 0xfe, 0x0e, 0x12,
9850 0x8d, 0xfe, 0x80, 0x80, 0x39, 0x20, 0x6a, 0x2a, 0xfe, 0x06, 0x10, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009851 0x83, 0xe7, 0xfe, 0x48, 0x00, 0xab, 0xfe, 0x03, 0x40, 0x08, 0x54, 0x5b,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009852 0x37, 0x01, 0xb3, 0xb8, 0xfe, 0x1f, 0x40, 0x13, 0x62, 0x01, 0xef, 0xfe,
9853 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0x88,
9854 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e, 0x14, 0x5f, 0xfe, 0x0c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009855 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x0c, 0x3d,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009856 0x14, 0x3e, 0xfe, 0x4a, 0x10, 0x08, 0x05, 0x5a, 0xfe, 0x2a, 0x12, 0xfe,
9857 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x60, 0x14, 0x61, 0x08, 0x05, 0x5b,
9858 0x8b, 0x01, 0xb3, 0xfe, 0x1f, 0x80, 0x13, 0x62, 0xfe, 0x44, 0x90, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009859 0xc6, 0x90, 0x0c, 0x3f, 0x14, 0x40, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009860 0x0c, 0x5e, 0x14, 0x5f, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x3d,
9861 0x14, 0x3e, 0x0c, 0x2e, 0x14, 0x3c, 0x21, 0x0c, 0x49, 0x0c, 0x63, 0x08,
9862 0x54, 0x1f, 0x37, 0x2c, 0x0f, 0xfe, 0x4e, 0x11, 0x27, 0xdd, 0xfe, 0x9e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009863 0xf0, 0xfe, 0x76, 0x08, 0xbc, 0x17, 0x34, 0x2c, 0x77, 0xe6, 0xc5, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009864 0x9a, 0x08, 0xc6, 0xfe, 0xb8, 0x08, 0x94, 0xfe, 0x8e, 0x08, 0xfe, 0x06,
9865 0xf0, 0xfe, 0x94, 0x08, 0x95, 0x86, 0x02, 0x24, 0x01, 0x4b, 0xfe, 0xc9,
9866 0x10, 0x16, 0x1f, 0xfe, 0xc9, 0x10, 0x68, 0x05, 0x06, 0xfe, 0x10, 0x12,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009867 0x68, 0x05, 0x0a, 0x4e, 0x08, 0x05, 0x0a, 0xfe, 0x90, 0x12, 0xfe, 0x2e,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009868 0x1c, 0x02, 0xfe, 0x18, 0x0b, 0x68, 0x05, 0x06, 0x4e, 0x68, 0x05, 0x0a,
9869 0xfe, 0x7a, 0x12, 0xfe, 0x2c, 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0xd2, 0x09,
9870 0xfe, 0xac, 0xf0, 0xfe, 0x00, 0x09, 0x02, 0xfe, 0xde, 0x09, 0xfe, 0xb7,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009871 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0x02, 0xf6, 0x1a, 0x50, 0xfe, 0x70, 0x18,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009872 0xfe, 0xf1, 0x18, 0xfe, 0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58,
9873 0xfe, 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x1c, 0x85, 0xfe,
9874 0x8c, 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0xac, 0xf0, 0xfe, 0xf0, 0x08, 0xb5,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009875 0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x0c, 0x09, 0x02, 0xfe, 0x18,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009876 0x0b, 0xb6, 0xfe, 0xbf, 0x10, 0xfe, 0x2b, 0xf0, 0x85, 0xf4, 0x1e, 0xfe,
9877 0x00, 0xfe, 0xfe, 0x1c, 0x12, 0xc2, 0xfe, 0xd2, 0xf0, 0x85, 0xfe, 0x76,
9878 0x18, 0x1e, 0x19, 0x17, 0x85, 0x03, 0xd2, 0x1e, 0x06, 0x17, 0x85, 0xc5,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009879 0x4a, 0xc6, 0x4a, 0xb5, 0xb6, 0xfe, 0x89, 0x10, 0x74, 0x67, 0x2d, 0x15,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009880 0x9d, 0x01, 0x36, 0x10, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x65, 0x10,
9881 0x80, 0x02, 0x65, 0xfe, 0x98, 0x80, 0xfe, 0x19, 0xe4, 0x0a, 0xfe, 0x1a,
9882 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18, 0xfe, 0x44, 0x54, 0xbe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009883 0xfe, 0x19, 0x81, 0xfe, 0x74, 0x18, 0x8f, 0x90, 0x17, 0xfe, 0xce, 0x08,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009884 0x02, 0x4a, 0x08, 0x05, 0x5a, 0xec, 0x03, 0x2e, 0x29, 0x3c, 0x0c, 0x3f,
9885 0x14, 0x40, 0x9b, 0x2e, 0x9c, 0x3c, 0xfe, 0x6c, 0x18, 0xfe, 0xed, 0x18,
9886 0xfe, 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x3a, 0x3f, 0x3b, 0x40, 0x03, 0x49,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009887 0x29, 0x63, 0x8f, 0xfe, 0xe3, 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009888 0x8f, 0xfe, 0xe3, 0x54, 0x90, 0xc0, 0x56, 0xfe, 0xce, 0x08, 0x02, 0x4a,
9889 0xfe, 0x37, 0xf0, 0xfe, 0xda, 0x09, 0xfe, 0x8b, 0xf0, 0xfe, 0x60, 0x09,
9890 0x02, 0x4a, 0x08, 0x05, 0x0a, 0x23, 0xfe, 0xfa, 0x0a, 0x3a, 0x49, 0x3b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009891 0x63, 0x56, 0xfe, 0x3e, 0x0a, 0x0f, 0xfe, 0xc0, 0x07, 0x41, 0x98, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009892 0xad, 0xfe, 0x01, 0x59, 0xfe, 0x52, 0xf0, 0xfe, 0x0c, 0x0a, 0x8f, 0x7a,
9893 0xfe, 0x24, 0x0a, 0x3a, 0x49, 0x8f, 0xfe, 0xe3, 0x54, 0x57, 0x49, 0x7d,
9894 0x63, 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02, 0x4a, 0x3a, 0x49, 0x3b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009895 0x63, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xbe, 0x57, 0x49, 0x57, 0x63,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009896 0x02, 0x4a, 0x08, 0x05, 0x5a, 0xfe, 0x82, 0x12, 0x08, 0x05, 0x1f, 0xfe,
9897 0x66, 0x13, 0x22, 0x62, 0xb7, 0xfe, 0x03, 0xa1, 0xfe, 0x83, 0x80, 0xfe,
9898 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x6a,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009899 0x2a, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x56, 0xe0, 0x03, 0x60, 0x29,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009900 0x61, 0x0c, 0x7f, 0x14, 0x80, 0x57, 0x60, 0x7d, 0x61, 0x01, 0xb3, 0xb8,
9901 0x6a, 0x2a, 0x13, 0x62, 0x9b, 0x2e, 0x9c, 0x3c, 0x3a, 0x3f, 0x3b, 0x40,
9902 0x90, 0xc0, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0x01, 0xef,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009903 0xfe, 0x36, 0x10, 0x21, 0x0c, 0x7f, 0x0c, 0x80, 0x3a, 0x3f, 0x3b, 0x40,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009904 0xe4, 0x08, 0x05, 0x1f, 0x17, 0xe0, 0x3a, 0x3d, 0x3b, 0x3e, 0x08, 0x05,
9905 0xfe, 0xf7, 0x00, 0x37, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x10, 0x58, 0xfe,
9906 0x91, 0x58, 0x57, 0x49, 0x7d, 0x63, 0x02, 0xfe, 0xf4, 0x09, 0x08, 0x05,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009907 0x1f, 0x17, 0xe0, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0xbe, 0xfe, 0x19,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009908 0x81, 0x50, 0xfe, 0x10, 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd3, 0x10, 0x32,
9909 0x07, 0xa6, 0x17, 0xfe, 0x08, 0x09, 0x12, 0xa6, 0x08, 0x05, 0x0a, 0xfe,
9910 0x14, 0x13, 0x03, 0x3d, 0x29, 0x3e, 0x56, 0xfe, 0x08, 0x09, 0xfe, 0x0c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009911 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x4a, 0x21, 0x41, 0xfe, 0x19, 0x80, 0xe7,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009912 0x08, 0x05, 0x0a, 0xfe, 0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41,
9913 0xf4, 0xc2, 0xfe, 0xd1, 0xf0, 0xe2, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe,
9914 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0x57, 0x3d, 0xfe, 0xed,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009915 0x19, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xf4, 0x1e, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009916 0x00, 0xff, 0x35, 0xfe, 0x74, 0x10, 0xc2, 0xfe, 0xd2, 0xf0, 0xfe, 0xa6,
9917 0x0b, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x8a, 0x03, 0xd2, 0x1e, 0x06, 0xfe,
9918 0x08, 0x13, 0x10, 0xfe, 0x16, 0x00, 0x02, 0x65, 0xfe, 0xd1, 0xf0, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009919 0xb8, 0x0b, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, 0x17, 0x00, 0xfe, 0x42,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009920 0x10, 0xfe, 0xce, 0xf0, 0xfe, 0xbe, 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd,
9921 0xf0, 0xfe, 0xca, 0x0b, 0x10, 0xfe, 0x22, 0x00, 0x02, 0x65, 0xfe, 0xcb,
9922 0xf0, 0xfe, 0xd6, 0x0b, 0x10, 0xfe, 0x24, 0x00, 0x02, 0x65, 0xfe, 0xd0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009923 0xf0, 0xfe, 0xe0, 0x0b, 0x10, 0x9e, 0xe5, 0xfe, 0xcf, 0xf0, 0xfe, 0xea,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009924 0x0b, 0x10, 0x58, 0xfe, 0x10, 0x10, 0xfe, 0xcc, 0xf0, 0xe2, 0x68, 0x05,
9925 0x1f, 0x4d, 0x10, 0xfe, 0x12, 0x00, 0x2c, 0x0f, 0xfe, 0x4e, 0x11, 0x27,
9926 0xfe, 0x00, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x14, 0x0c, 0xbc, 0x17, 0x34,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009927 0x2c, 0x77, 0xe6, 0xc5, 0x24, 0xc6, 0x24, 0x2c, 0xfa, 0x27, 0xfe, 0x20,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009928 0x0c, 0x1c, 0x34, 0x94, 0xfe, 0x3c, 0x0c, 0x95, 0x86, 0xc5, 0xdc, 0xc6,
9929 0xdc, 0x02, 0x24, 0x01, 0x4b, 0xfe, 0xdb, 0x10, 0x12, 0xfe, 0xe8, 0x00,
9930 0xb5, 0xb6, 0x74, 0xc7, 0x81, 0xc8, 0x83, 0xfe, 0x89, 0xf0, 0x24, 0x33,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009931 0x31, 0xe1, 0xc7, 0x81, 0xc8, 0x83, 0x27, 0xfe, 0x66, 0x0c, 0x1d, 0x24,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009932 0x33, 0x31, 0xdf, 0xbc, 0x4e, 0x10, 0xfe, 0x42, 0x00, 0x02, 0x65, 0x7c,
9933 0x06, 0xfe, 0x81, 0x49, 0x17, 0xfe, 0x2c, 0x0d, 0x08, 0x05, 0x0a, 0xfe,
9934 0x44, 0x13, 0x10, 0x00, 0x55, 0x0a, 0xfe, 0x54, 0x12, 0x55, 0xfe, 0x28,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009935 0x00, 0x23, 0xfe, 0x9a, 0x0d, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009936 0x44, 0xfe, 0x28, 0x00, 0xfe, 0xe2, 0x10, 0x01, 0xf5, 0x01, 0xf6, 0x09,
9937 0xa4, 0x01, 0xfe, 0x26, 0x0f, 0x64, 0x12, 0x2f, 0x01, 0x73, 0x02, 0x2b,
9938 0x10, 0xfe, 0x44, 0x00, 0x55, 0x0a, 0xe9, 0x44, 0x0a, 0xfe, 0xb4, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009939 0x01, 0xb0, 0x44, 0x0a, 0xfe, 0xaa, 0x10, 0x01, 0xb0, 0xfe, 0x19, 0x82,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009940 0xfe, 0x34, 0x46, 0xac, 0x44, 0x0a, 0x10, 0xfe, 0x43, 0x00, 0xfe, 0x96,
9941 0x10, 0x08, 0x54, 0x0a, 0x37, 0x01, 0xf5, 0x01, 0xf6, 0x64, 0x12, 0x2f,
9942 0x01, 0x73, 0x99, 0x0a, 0x64, 0x42, 0x92, 0x02, 0xfe, 0x2e, 0x03, 0x08,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009943 0x05, 0x0a, 0x8a, 0x44, 0x0a, 0x10, 0x00, 0xfe, 0x5c, 0x10, 0x68, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009944 0x1a, 0xfe, 0x58, 0x12, 0x08, 0x05, 0x1a, 0xfe, 0x50, 0x13, 0xfe, 0x1c,
9945 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x50, 0x0d, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d,
9946 0xf0, 0xfe, 0x56, 0x0d, 0x08, 0x54, 0x1a, 0x37, 0xfe, 0xa9, 0x10, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009947 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0a, 0x50, 0xfe, 0x2e, 0x10, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009948 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x10, 0x6f, 0xab, 0x10, 0xfe, 0x41,
9949 0x00, 0xaa, 0x10, 0xfe, 0x24, 0x00, 0x8c, 0xb5, 0xb6, 0x74, 0x03, 0x70,
9950 0x28, 0x23, 0xd8, 0x50, 0xfe, 0x04, 0xe6, 0x1a, 0xfe, 0x9d, 0x41, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009951 0x1c, 0x42, 0x64, 0x01, 0xe3, 0x02, 0x2b, 0xf8, 0x15, 0x0a, 0x39, 0xa0,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009952 0xb4, 0x15, 0xfe, 0x31, 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, 0x02,
9953 0xd7, 0x42, 0xfe, 0x06, 0xec, 0xd0, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45,
9954 0x35, 0x42, 0xfe, 0x06, 0xea, 0xd0, 0xfe, 0x47, 0x4b, 0x91, 0xfe, 0x75,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009955 0x57, 0x03, 0x5d, 0xfe, 0x98, 0x56, 0xfe, 0x38, 0x12, 0x09, 0x48, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009956 0x0e, 0xfe, 0x44, 0x48, 0x4f, 0x08, 0x05, 0x1b, 0xfe, 0x1a, 0x13, 0x09,
9957 0x46, 0x01, 0x0e, 0x41, 0xfe, 0x41, 0x58, 0x09, 0xa4, 0x01, 0x0e, 0xfe,
9958 0x49, 0x54, 0x96, 0xfe, 0x1e, 0x0e, 0x02, 0xfe, 0x2e, 0x03, 0x09, 0x5d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009959 0xfe, 0xee, 0x14, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009960 0xce, 0x47, 0xfe, 0xad, 0x13, 0x02, 0x2b, 0x22, 0x20, 0x07, 0x11, 0xfe,
9961 0x9e, 0x12, 0x21, 0x13, 0x59, 0x13, 0x9f, 0x13, 0xd5, 0x22, 0x2f, 0x41,
9962 0x39, 0x2f, 0xbc, 0xad, 0xfe, 0xbc, 0xf0, 0xfe, 0xe0, 0x0e, 0x0f, 0x06,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009963 0x13, 0x59, 0x01, 0xfe, 0xda, 0x16, 0x03, 0xfe, 0x38, 0x01, 0x29, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009964 0x3a, 0x01, 0x56, 0xfe, 0xe4, 0x0e, 0xfe, 0x02, 0xec, 0xd5, 0x69, 0x00,
9965 0x66, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01,
9966 0x01, 0xfe, 0x4a, 0x17, 0xfe, 0x08, 0x90, 0xfe, 0x48, 0xf4, 0x0d, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009967 0x18, 0x13, 0xba, 0xfe, 0x02, 0xea, 0xd5, 0x69, 0x7e, 0xfe, 0xc5, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009968 0x15, 0x1a, 0x39, 0xa0, 0xb4, 0xfe, 0x2e, 0x10, 0x03, 0xfe, 0x38, 0x01,
9969 0x1e, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x03, 0xfe, 0x3a, 0x01,
9970 0x0c, 0xfe, 0x62, 0x01, 0x43, 0x13, 0x20, 0x25, 0x06, 0x13, 0x2f, 0x12,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009971 0x2f, 0x92, 0x0f, 0x06, 0x04, 0x21, 0x04, 0x22, 0x59, 0xfe, 0xf7, 0x12,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009972 0x22, 0x9f, 0xb7, 0x13, 0x9f, 0x07, 0x7e, 0xfe, 0x71, 0x13, 0xfe, 0x24,
9973 0x1c, 0x15, 0x19, 0x39, 0xa0, 0xb4, 0xfe, 0xd9, 0x10, 0xc3, 0xfe, 0x03,
9974 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xc3, 0xfe, 0x03, 0xdc,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009975 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x21,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009976 0xfe, 0x00, 0xcc, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x78, 0x04, 0x08, 0x05,
9977 0x58, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13,
9978 0xfe, 0x1e, 0x80, 0xed, 0xfe, 0x1d, 0x80, 0xae, 0xfe, 0x0c, 0x90, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009979 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xac, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009980 0x0a, 0xfe, 0x3c, 0x50, 0xaa, 0x01, 0xfe, 0x7a, 0x17, 0x32, 0x07, 0x2f,
9981 0xad, 0x01, 0xfe, 0xb4, 0x16, 0x08, 0x05, 0x1b, 0x4e, 0x01, 0xf5, 0x01,
9982 0xf6, 0x12, 0xfe, 0xe9, 0x00, 0x08, 0x05, 0x58, 0xfe, 0x2c, 0x13, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009983 0xfe, 0x0c, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009984 0x0c, 0xfe, 0x64, 0x01, 0x14, 0xfe, 0x66, 0x01, 0x08, 0x05, 0x5b, 0xfe,
9985 0x12, 0x12, 0xfe, 0x03, 0x80, 0x8d, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80,
9986 0x40, 0x13, 0x20, 0x6a, 0x2a, 0x12, 0xcf, 0x64, 0x22, 0x20, 0xfb, 0x79,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009987 0x20, 0x04, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009988 0x03, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe,
9989 0x08, 0x58, 0x03, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
9990 0x25, 0x6e, 0x13, 0xd0, 0x21, 0x0c, 0x5c, 0x0c, 0x45, 0x0f, 0x46, 0x52,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009991 0x50, 0x18, 0x1b, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xfe, 0xfc,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009992 0x0f, 0x44, 0x11, 0x0f, 0x48, 0x52, 0x18, 0x58, 0xfe, 0x90, 0x4d, 0xfe,
9993 0x91, 0x54, 0x23, 0xe4, 0x25, 0x11, 0x13, 0x20, 0x7c, 0x6f, 0x4f, 0x22,
9994 0x20, 0xfb, 0x79, 0x20, 0x12, 0xcf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009995 0xfe, 0x26, 0x10, 0xf8, 0x74, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -06009996 0x18, 0x1c, 0x04, 0x42, 0xfe, 0x0c, 0x14, 0xfc, 0xfe, 0x07, 0xe6, 0x1b,
9997 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x04, 0x01, 0xb0, 0x7c, 0x6f, 0x4f,
9998 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0x32, 0x07, 0x2f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009999 0xfe, 0x34, 0x13, 0x09, 0x48, 0x01, 0x0e, 0xbb, 0xfe, 0x36, 0x12, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010000 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe,
10001 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, 0x84, 0x01, 0x0e, 0xfe,
10002 0x80, 0x5c, 0x01, 0x73, 0xfe, 0x0e, 0x10, 0x07, 0x82, 0x4e, 0xfe, 0x14,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010003 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x60, 0x10, 0x04, 0xfe, 0x44, 0x58, 0x8d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010004 0xfe, 0x01, 0xec, 0xa2, 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe,
10005 0x9c, 0xe7, 0x1a, 0x79, 0x2a, 0x01, 0xe3, 0xfe, 0xdd, 0x10, 0x2c, 0xc7,
10006 0x81, 0xc8, 0x83, 0x33, 0x31, 0xde, 0x07, 0x1a, 0xfe, 0x48, 0x12, 0x07,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010007 0x0a, 0xfe, 0x56, 0x12, 0x07, 0x19, 0xfe, 0x30, 0x12, 0x07, 0xc9, 0x17,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010008 0xfe, 0x32, 0x12, 0x07, 0xfe, 0x23, 0x00, 0x17, 0xeb, 0x07, 0x06, 0x17,
10009 0xfe, 0x9c, 0x12, 0x07, 0x1f, 0xfe, 0x12, 0x12, 0x07, 0x00, 0x17, 0x24,
10010 0x15, 0xc9, 0x01, 0x36, 0xa9, 0x2d, 0x01, 0x0b, 0x94, 0x4b, 0x04, 0x2d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010011 0xdd, 0x09, 0xd1, 0x01, 0xfe, 0x26, 0x0f, 0x12, 0x82, 0x02, 0x2b, 0x2d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010012 0x32, 0x07, 0xa6, 0xfe, 0xd9, 0x13, 0x3a, 0x3d, 0x3b, 0x3e, 0x56, 0xfe,
10013 0xf0, 0x11, 0x08, 0x05, 0x5a, 0xfe, 0x72, 0x12, 0x9b, 0x2e, 0x9c, 0x3c,
10014 0x90, 0xc0, 0x96, 0xfe, 0xba, 0x11, 0x22, 0x62, 0xfe, 0x26, 0x13, 0x03,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010015 0x7f, 0x29, 0x80, 0x56, 0xfe, 0x76, 0x0d, 0x0c, 0x60, 0x14, 0x61, 0x21,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010016 0x0c, 0x7f, 0x0c, 0x80, 0x01, 0xb3, 0x25, 0x6e, 0x77, 0x13, 0x62, 0x01,
10017 0xef, 0x9b, 0x2e, 0x9c, 0x3c, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe,
10018 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0xfe, 0x91, 0x10, 0x03, 0x3f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010019 0x29, 0x40, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x3f, 0x14, 0x40,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010020 0x88, 0x9b, 0x2e, 0x9c, 0x3c, 0x90, 0xc0, 0x03, 0x5e, 0x29, 0x5f, 0xfe,
10021 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x0c, 0x5e, 0x14, 0x5f, 0x08, 0x05, 0x5a,
10022 0xfe, 0x1e, 0x12, 0x22, 0x62, 0xfe, 0x1f, 0x40, 0x03, 0x60, 0x29, 0x61,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010023 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x03, 0x3f, 0x29, 0x40, 0xfe, 0x44,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010024 0x50, 0xfe, 0xc6, 0x50, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x08, 0x50, 0xfe,
10025 0x8a, 0x50, 0x03, 0x3d, 0x29, 0x3e, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50,
10026 0x02, 0x89, 0x25, 0x06, 0x13, 0xd4, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010027 0x4c, 0x33, 0x31, 0xde, 0x07, 0x06, 0x23, 0x4c, 0x32, 0x07, 0xa6, 0x23,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010028 0x72, 0x01, 0xaf, 0x1e, 0x43, 0x17, 0x4c, 0x08, 0x05, 0x0a, 0xee, 0x3a,
10029 0x3d, 0x3b, 0x3e, 0xfe, 0x0a, 0x55, 0x35, 0xfe, 0x8b, 0x55, 0x57, 0x3d,
10030 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x02, 0x72, 0xfe, 0x19,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010031 0x81, 0xba, 0xfe, 0x19, 0x41, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1c, 0x34,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010032 0x1d, 0xe8, 0x33, 0x31, 0xe1, 0x55, 0x19, 0xfe, 0xa6, 0x12, 0x55, 0x0a,
10033 0x4d, 0x02, 0x4c, 0x01, 0x0b, 0x1c, 0x34, 0x1d, 0xe8, 0x33, 0x31, 0xdf,
10034 0x07, 0x19, 0x23, 0x4c, 0x01, 0x0b, 0x1d, 0xe8, 0x33, 0x31, 0xfe, 0xe8,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010035 0x09, 0xfe, 0xc2, 0x49, 0x51, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0x8a, 0x53,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010036 0x05, 0x1f, 0x35, 0xa9, 0xfe, 0xbb, 0x45, 0x55, 0x00, 0x4e, 0x44, 0x06,
10037 0x7c, 0x43, 0xfe, 0xda, 0x14, 0x01, 0xaf, 0x8c, 0xfe, 0x4b, 0x45, 0xee,
10038 0x32, 0x07, 0xa5, 0xed, 0x03, 0xcd, 0x28, 0x8a, 0x03, 0x45, 0x28, 0x35,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010039 0x67, 0x02, 0x72, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010040 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01,
10041 0xfe, 0x9e, 0x15, 0x02, 0x89, 0x01, 0x0b, 0x1c, 0x34, 0x1d, 0x4c, 0x33,
10042 0x31, 0xdf, 0x07, 0x06, 0x23, 0x4c, 0x01, 0xf1, 0xfe, 0x42, 0x58, 0xf1,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010043 0xfe, 0xa4, 0x14, 0x8c, 0xfe, 0x4a, 0xf4, 0x0a, 0x17, 0x4c, 0xfe, 0x4a,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010044 0xf4, 0x06, 0xea, 0x32, 0x07, 0xa5, 0x8b, 0x02, 0x72, 0x03, 0x45, 0xc1,
10045 0x0c, 0x45, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, 0xfe, 0xcc, 0x15,
10046 0x02, 0x89, 0x0f, 0x06, 0x27, 0xfe, 0xbe, 0x13, 0x26, 0xfe, 0xd4, 0x13,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010047 0x76, 0xfe, 0x89, 0x48, 0x01, 0x0b, 0x21, 0x76, 0x04, 0x7b, 0xfe, 0xd0,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010048 0x13, 0x1c, 0xfe, 0xd0, 0x13, 0x1d, 0xfe, 0xbe, 0x13, 0x67, 0x2d, 0x01,
10049 0x0b, 0xfe, 0xd5, 0x10, 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93,
10050 0x1e, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x04, 0x0f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010051 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0xfe, 0x30, 0x56,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010052 0xfe, 0x00, 0x5c, 0x04, 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93,
10053 0x04, 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0xfe, 0x0b, 0x58,
10054 0x04, 0x09, 0x5c, 0x01, 0x87, 0x09, 0x45, 0x01, 0x87, 0x04, 0xfe, 0x03,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010055 0xa1, 0x1e, 0x11, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x1f, 0x52,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010056 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c,
10057 0x6a, 0x2a, 0x0c, 0x5e, 0x14, 0x5f, 0x57, 0x3f, 0x7d, 0x40, 0x04, 0xdd,
10058 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x8d, 0x04, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010059 0xfe, 0x0c, 0x19, 0xfe, 0x42, 0x48, 0x50, 0x51, 0x91, 0x01, 0x0b, 0x1d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010060 0xfe, 0x96, 0x15, 0x33, 0x31, 0xe1, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15,
10061 0x33, 0x31, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x03, 0xcd, 0x28, 0xfe,
10062 0xcc, 0x12, 0x53, 0x05, 0x1a, 0xfe, 0xc4, 0x13, 0x21, 0x69, 0x1a, 0xee,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010063 0x55, 0xca, 0x6b, 0xfe, 0xdc, 0x14, 0x4d, 0x0f, 0x06, 0x18, 0xca, 0x7c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010064 0x30, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xab, 0xff, 0x02, 0x83,
10065 0x55, 0x69, 0x19, 0xae, 0x98, 0xfe, 0x30, 0x00, 0x96, 0xf2, 0x18, 0x6d,
10066 0x0f, 0x06, 0xfe, 0x56, 0x10, 0x69, 0x0a, 0xed, 0x98, 0xfe, 0x64, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010067 0x96, 0xf2, 0x09, 0xfe, 0x64, 0x00, 0x18, 0x9e, 0x0f, 0x06, 0xfe, 0x28,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010068 0x10, 0x69, 0x06, 0xfe, 0x60, 0x13, 0x98, 0xfe, 0xc8, 0x00, 0x96, 0xf2,
10069 0x09, 0xfe, 0xc8, 0x00, 0x18, 0x59, 0x0f, 0x06, 0x88, 0x98, 0xfe, 0x90,
10070 0x01, 0x7a, 0xfe, 0x42, 0x15, 0x91, 0xe4, 0xfe, 0x43, 0xf4, 0x9f, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010071 0x56, 0xf0, 0xfe, 0x54, 0x15, 0xfe, 0x04, 0xf4, 0x71, 0xfe, 0x43, 0xf4,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010072 0x9e, 0xfe, 0xf3, 0x10, 0xfe, 0x40, 0x5c, 0x01, 0xfe, 0x16, 0x14, 0x1e,
10073 0x43, 0xec, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x6e, 0x7a, 0xfe, 0x90,
10074 0x15, 0xc4, 0x6e, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010075 0xcc, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0xcc, 0x88, 0x51, 0x21, 0xfe, 0x4d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010076 0xf4, 0x00, 0xe9, 0x91, 0x0f, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58,
10077 0x04, 0x51, 0x0f, 0x0a, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xf3, 0x16,
10078 0x0a, 0x01, 0x0b, 0x26, 0xf3, 0x16, 0x19, 0x01, 0x0b, 0x26, 0xf3, 0x76,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010079 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010080 0x16, 0x19, 0x01, 0x0b, 0x26, 0xb1, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1,
10081 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x26, 0xb1, 0x76, 0xfe, 0x89, 0x4a, 0x01,
10082 0x0b, 0x04, 0x51, 0x04, 0x22, 0xd3, 0x07, 0x06, 0xfe, 0x48, 0x13, 0xb8,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010083 0x13, 0xd3, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x76, 0xa9, 0x67, 0xfe, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010084 0xec, 0xfe, 0x27, 0x01, 0xfe, 0x89, 0x48, 0xff, 0x02, 0x00, 0x10, 0x27,
10085 0xfe, 0x2e, 0x16, 0x32, 0x07, 0xfe, 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1d,
10086 0xfe, 0x52, 0x16, 0x21, 0x13, 0xd4, 0x01, 0x4b, 0x22, 0xd4, 0x07, 0x06,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010087 0x4e, 0x08, 0x54, 0x06, 0x37, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfb, 0x8e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010088 0x07, 0x11, 0xae, 0x09, 0x84, 0x01, 0x0e, 0x8e, 0x09, 0x5d, 0x01, 0xa8,
10089 0x04, 0x09, 0x84, 0x01, 0x0e, 0x8e, 0xfe, 0x80, 0xe7, 0x11, 0x07, 0x11,
10090 0x8a, 0xfe, 0x45, 0x58, 0x01, 0xf0, 0x8e, 0x04, 0x09, 0x48, 0x01, 0x0e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010091 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x80,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010092 0x80, 0xfe, 0x80, 0x4c, 0xfe, 0x49, 0xe4, 0x11, 0xae, 0x09, 0x84, 0x01,
10093 0x0e, 0xfe, 0x80, 0x4c, 0x09, 0x5d, 0x01, 0x87, 0x04, 0x18, 0x11, 0x75,
10094 0x6c, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010095 0x1c, 0xfe, 0x1d, 0xf7, 0x1b, 0x97, 0xfe, 0xee, 0x16, 0x01, 0xfe, 0xf4,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010096 0x17, 0xad, 0x9a, 0x1b, 0x6c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x04,
10097 0xb9, 0x23, 0xfe, 0xde, 0x16, 0xfe, 0xda, 0x10, 0x18, 0x11, 0x75, 0x03,
10098 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1f, 0xfe, 0x18, 0x58, 0x03, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010099 0x66, 0x01, 0xfe, 0x19, 0x58, 0x9a, 0x1f, 0xfe, 0x3c, 0x90, 0xfe, 0x30,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010100 0xf4, 0x06, 0xfe, 0x3c, 0x50, 0x6c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79,
10101 0xfe, 0x1c, 0xf7, 0x1f, 0x97, 0xfe, 0x38, 0x17, 0xfe, 0xb6, 0x14, 0x35,
10102 0x04, 0xb9, 0x23, 0xfe, 0x10, 0x17, 0xfe, 0x9c, 0x10, 0x18, 0x11, 0x75,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010103 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010104 0x2e, 0x97, 0xfe, 0x5a, 0x17, 0xfe, 0x94, 0x14, 0xec, 0x9a, 0x2e, 0x6c,
10105 0x1a, 0xfe, 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00, 0x04, 0xb9, 0x23, 0xfe,
10106 0x4e, 0x17, 0xfe, 0x6c, 0x10, 0x18, 0x11, 0x75, 0xfe, 0x30, 0xbc, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010107 0xb2, 0xbc, 0x9a, 0xcb, 0x6c, 0x1a, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010108 0xcb, 0x97, 0xfe, 0x92, 0x17, 0xfe, 0x5c, 0x14, 0x35, 0x04, 0xb9, 0x23,
10109 0xfe, 0x7e, 0x17, 0xfe, 0x42, 0x10, 0xfe, 0x02, 0xf6, 0x11, 0x75, 0xfe,
10110 0x18, 0xfe, 0x60, 0xfe, 0x19, 0xfe, 0x61, 0xfe, 0x03, 0xa1, 0xfe, 0x1d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010111 0xf7, 0x5b, 0x97, 0xfe, 0xb8, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010112 0x9a, 0x5b, 0x41, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7,
10113 0x11, 0xfe, 0x81, 0xe7, 0x11, 0x12, 0xfe, 0xdd, 0x00, 0x6a, 0x2a, 0x04,
10114 0x6a, 0x2a, 0xfe, 0x12, 0x45, 0x23, 0xfe, 0xa8, 0x17, 0x15, 0x06, 0x39,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010115 0xa0, 0xb4, 0x02, 0x2b, 0xfe, 0x39, 0xf0, 0xfe, 0xfc, 0x17, 0x21, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010116 0xfe, 0x7e, 0x18, 0x1e, 0x19, 0x66, 0x0f, 0x0d, 0x04, 0x75, 0x03, 0xd2,
10117 0x1e, 0x06, 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x7c, 0x6f, 0x4f, 0x32,
10118 0x07, 0x2f, 0xfe, 0x3c, 0x13, 0xf1, 0xfe, 0x42, 0x13, 0x42, 0x92, 0x09,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010119 0x48, 0x01, 0x0e, 0xbb, 0xeb, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010120 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11,
10121 0xac, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c, 0x01, 0x73, 0xfe, 0x16,
10122 0x10, 0x07, 0x82, 0x8b, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12, 0xfe, 0x14,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010123 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x1c, 0x18, 0x18, 0x0a, 0x04, 0xfe, 0x9c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010124 0xe7, 0x0a, 0x10, 0xfe, 0x15, 0x00, 0x64, 0x79, 0x2a, 0x01, 0xe3, 0x18,
10125 0x06, 0x04, 0x42, 0x92, 0x08, 0x54, 0x1b, 0x37, 0x12, 0x2f, 0x01, 0x73,
10126 0x18, 0x06, 0x04, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x3a, 0xce, 0x3b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010127 0xcf, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x04, 0x22, 0xa3, 0x77,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010128 0x13, 0xa3, 0x04, 0x09, 0xa4, 0x01, 0x0e, 0xfe, 0x41, 0x48, 0x09, 0x46,
10129 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x17, 0xfe, 0xe8, 0x18, 0x77, 0x78, 0x04,
10130 0x09, 0x48, 0x01, 0x0e, 0x07, 0x11, 0x4e, 0x09, 0x5d, 0x01, 0xa8, 0x09,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010131 0x46, 0x01, 0x0e, 0x77, 0x78, 0x04, 0xfe, 0x4e, 0xe4, 0x19, 0x6b, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010132 0x1c, 0x19, 0x03, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10,
10133 0xfe, 0x4e, 0xe4, 0xc9, 0x6b, 0xfe, 0x2e, 0x19, 0x03, 0xfe, 0x92, 0x00,
10134 0xfe, 0x02, 0xe6, 0x1a, 0xe5, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x6b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010135 0xfe, 0x40, 0x19, 0x03, 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x1f, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010136 0x08, 0x10, 0x03, 0xfe, 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x6d, 0xfe, 0x4e,
10137 0x45, 0xea, 0xba, 0xff, 0x04, 0x68, 0x54, 0xe7, 0x1e, 0x6e, 0xfe, 0x08,
10138 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe, 0x1a, 0xf4, 0xfe, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010139 0x04, 0xea, 0xfe, 0x48, 0xf4, 0x19, 0x7a, 0xfe, 0x74, 0x19, 0x0f, 0x19,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010140 0x04, 0x07, 0x7e, 0xfe, 0x5a, 0xf0, 0xfe, 0x84, 0x19, 0x25, 0xfe, 0x09,
10141 0x00, 0xfe, 0x34, 0x10, 0x07, 0x1a, 0xfe, 0x5a, 0xf0, 0xfe, 0x92, 0x19,
10142 0x25, 0xca, 0xfe, 0x26, 0x10, 0x07, 0x19, 0x66, 0x25, 0x6d, 0xe5, 0x07,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010143 0x0a, 0x66, 0x25, 0x9e, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x66, 0x25, 0x59,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010144 0xa9, 0xb8, 0x04, 0x15, 0xfe, 0x09, 0x00, 0x01, 0x36, 0xfe, 0x04, 0xfe,
10145 0x81, 0x03, 0x83, 0xfe, 0x40, 0x5c, 0x04, 0x1c, 0xf7, 0xfe, 0x14, 0xf0,
10146 0x0b, 0x27, 0xfe, 0xd6, 0x19, 0x1c, 0xf7, 0x7b, 0xf7, 0xfe, 0x82, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010147 0xfe, 0xda, 0x19, 0x04, 0xff, 0xcc, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070010148};
10149
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010150static unsigned short _adv_asc38C0800_size = sizeof(_adv_asc38C0800_buf); /* 0x14E1 */
10151static ADV_DCNT _adv_asc38C0800_chksum = 0x050D3FD8UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070010152
10153/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010154static unsigned char _adv_asc38C1600_buf[] = {
10155 0x00, 0x00, 0x00, 0xf2, 0x00, 0x16, 0x00, 0xfc, 0x00, 0x10, 0x00, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010156 0x18, 0xe4, 0x01, 0x00, 0x04, 0x1e, 0x48, 0xe4, 0x03, 0xf6, 0xf7, 0x13,
10157 0x2e, 0x1e, 0x02, 0x00, 0x07, 0x17, 0xc0, 0x5f, 0x00, 0xfa, 0xff, 0xff,
10158 0x04, 0x00, 0x00, 0xf6, 0x09, 0xe7, 0x82, 0xe7, 0x85, 0xf0, 0x86, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010159 0x4e, 0x10, 0x9e, 0xe7, 0xff, 0x00, 0x55, 0xf0, 0x01, 0xf6, 0x03, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010160 0x98, 0x57, 0x01, 0xe6, 0x00, 0xea, 0x00, 0xec, 0x01, 0xfa, 0x18, 0xf4,
10161 0x08, 0x00, 0xf0, 0x1d, 0x38, 0x54, 0x32, 0xf0, 0x10, 0x00, 0xc2, 0x0e,
10162 0x1e, 0xf0, 0xd5, 0xf0, 0xbc, 0x00, 0x4b, 0xe4, 0x00, 0xe6, 0xb1, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010163 0xb4, 0x00, 0x02, 0x13, 0x3e, 0x1c, 0xc8, 0x47, 0x3e, 0x00, 0xd8, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010164 0x06, 0x13, 0x0c, 0x1c, 0x5e, 0x1e, 0x00, 0x57, 0xc8, 0x57, 0x01, 0xfc,
10165 0xbc, 0x0e, 0xa2, 0x12, 0xb9, 0x54, 0x00, 0x80, 0x62, 0x0a, 0x5a, 0x12,
10166 0xc8, 0x15, 0x3e, 0x1e, 0x18, 0x40, 0xbd, 0x56, 0x03, 0xe6, 0x01, 0xea,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010167 0x5c, 0xf0, 0x0f, 0x00, 0x20, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010168 0x04, 0x13, 0xbb, 0x55, 0x3c, 0x56, 0x3e, 0x57, 0x03, 0x58, 0x4a, 0xe4,
10169 0x40, 0x00, 0xb6, 0x00, 0xbb, 0x00, 0xc0, 0x00, 0x00, 0x01, 0x01, 0x01,
10170 0x3e, 0x01, 0x58, 0x0a, 0x44, 0x10, 0x0a, 0x12, 0x4c, 0x1c, 0x4e, 0x1c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010171 0x02, 0x4a, 0x30, 0xe4, 0x05, 0xe6, 0x0c, 0x00, 0x3c, 0x00, 0x80, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010172 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01,
10173 0x74, 0x01, 0x76, 0x01, 0x78, 0x01, 0x7c, 0x01, 0xc6, 0x0e, 0x0c, 0x10,
10174 0xac, 0x12, 0xae, 0x12, 0x16, 0x1a, 0x32, 0x1c, 0x6e, 0x1e, 0x02, 0x48,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010175 0x3a, 0x55, 0xc9, 0x57, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x06, 0xf7,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010176 0x03, 0xfc, 0x06, 0x00, 0x1e, 0x00, 0xbe, 0x00, 0xe1, 0x00, 0x0c, 0x12,
10177 0x18, 0x1a, 0x70, 0x1a, 0x30, 0x1c, 0x38, 0x1c, 0x10, 0x44, 0x00, 0x4c,
10178 0xb0, 0x57, 0x40, 0x5c, 0x4d, 0xe4, 0x04, 0xea, 0x5d, 0xf0, 0xa7, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010179 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x09, 0x00, 0x19, 0x00, 0x32, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010180 0x33, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00, 0x9e, 0x00, 0xcc, 0x00,
10181 0x20, 0x01, 0x4e, 0x01, 0x79, 0x01, 0x3c, 0x09, 0x68, 0x0d, 0x02, 0x10,
10182 0x04, 0x10, 0x3a, 0x10, 0x08, 0x12, 0x0a, 0x13, 0x40, 0x16, 0x50, 0x16,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010183 0x00, 0x17, 0x4a, 0x19, 0x00, 0x4e, 0x00, 0x54, 0x01, 0x58, 0x00, 0xdc,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010184 0x05, 0xf0, 0x09, 0xf0, 0x59, 0xf0, 0xb8, 0xf0, 0x48, 0xf4, 0x0e, 0xf7,
10185 0x0a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00,
10186 0xd0, 0x00, 0xe7, 0x00, 0xf0, 0x03, 0x69, 0x08, 0xe9, 0x09, 0x5c, 0x0c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010187 0xb6, 0x12, 0xbc, 0x19, 0xd8, 0x1b, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010188 0x42, 0x1d, 0x08, 0x44, 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46,
10189 0x89, 0x48, 0x68, 0x54, 0x83, 0x55, 0x83, 0x59, 0x31, 0xe4, 0x02, 0xe6,
10190 0x07, 0xf0, 0x08, 0xf0, 0x0b, 0xf0, 0x0c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010191 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010192 0xa8, 0x00, 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0x22, 0x01,
10193 0x26, 0x01, 0x60, 0x01, 0x7a, 0x01, 0x82, 0x01, 0xc8, 0x01, 0xca, 0x01,
10194 0x86, 0x02, 0x6a, 0x03, 0x18, 0x05, 0xb2, 0x07, 0x68, 0x08, 0x10, 0x0d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010195 0x06, 0x10, 0x0a, 0x10, 0x0e, 0x10, 0x12, 0x10, 0x60, 0x10, 0xed, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010196 0xf3, 0x10, 0x06, 0x12, 0x10, 0x12, 0x1e, 0x12, 0x0c, 0x13, 0x0e, 0x13,
10197 0x10, 0x13, 0xfe, 0x9c, 0xf0, 0x35, 0x05, 0xfe, 0xec, 0x0e, 0xff, 0x10,
10198 0x00, 0x00, 0xe9, 0xfe, 0x34, 0x1f, 0x00, 0xe8, 0xfe, 0x88, 0x01, 0xff,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010199 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010200 0x00, 0xfe, 0x57, 0x24, 0x00, 0xfe, 0x4c, 0x00, 0x65, 0xff, 0x04, 0x00,
10201 0x00, 0x1a, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x08,
10202 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x13,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010203 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010204 0xfe, 0x04, 0xf7, 0xe8, 0x37, 0x7d, 0x0d, 0x01, 0xfe, 0x4a, 0x11, 0xfe,
10205 0x04, 0xf7, 0xe8, 0x7d, 0x0d, 0x51, 0x37, 0xfe, 0x3d, 0xf0, 0xfe, 0x0c,
10206 0x02, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x91, 0xf0, 0xfe, 0xf8, 0x01, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010207 0x90, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x8f, 0xf0, 0xbc, 0x03, 0x67, 0x4d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010208 0x05, 0xfe, 0x08, 0x0f, 0x01, 0xfe, 0x78, 0x0f, 0xfe, 0xdd, 0x12, 0x05,
10209 0xfe, 0x0e, 0x03, 0xfe, 0x28, 0x1c, 0x03, 0xfe, 0xa6, 0x00, 0xfe, 0xd1,
10210 0x12, 0x3e, 0x22, 0xfe, 0xa6, 0x00, 0xac, 0xfe, 0x48, 0xf0, 0xfe, 0x90,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010211 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0xaa, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc8,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010212 0x02, 0xfe, 0x46, 0xf0, 0xfe, 0x5a, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x60,
10213 0x02, 0xfe, 0x43, 0xf0, 0xfe, 0x4e, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x52,
10214 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x56, 0x02, 0x1c, 0x0d, 0xa2, 0x1c, 0x07,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010215 0x22, 0xb7, 0x05, 0x35, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010216 0x1c, 0xf5, 0xfe, 0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0x5f, 0xfe, 0xe7,
10217 0x10, 0xfe, 0x06, 0xfc, 0xde, 0x0a, 0x81, 0x01, 0xa3, 0x05, 0x35, 0x1f,
10218 0x95, 0x47, 0xb8, 0x01, 0xfe, 0xe4, 0x11, 0x0a, 0x81, 0x01, 0x5c, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010219 0xbd, 0x10, 0x0a, 0x81, 0x01, 0x5c, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010220 0xfe, 0x58, 0x1c, 0x1c, 0x07, 0x22, 0xb7, 0x37, 0x2a, 0x35, 0xfe, 0x3d,
10221 0xf0, 0xfe, 0x0c, 0x02, 0x2b, 0xfe, 0x9e, 0x02, 0xfe, 0x5a, 0x1c, 0xfe,
10222 0x12, 0x1c, 0xfe, 0x14, 0x1c, 0x1f, 0xfe, 0x30, 0x00, 0x47, 0xb8, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010223 0xfe, 0xd4, 0x11, 0x1c, 0x07, 0x22, 0xb7, 0x05, 0xe9, 0x21, 0x2c, 0x09,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010224 0x1a, 0x31, 0xfe, 0x69, 0x10, 0x1c, 0x07, 0x22, 0xb7, 0xfe, 0x04, 0xec,
10225 0x2c, 0x60, 0x01, 0xfe, 0x1e, 0x1e, 0x20, 0x2c, 0xfe, 0x05, 0xf6, 0xde,
10226 0x01, 0xfe, 0x62, 0x1b, 0x01, 0x0c, 0x61, 0x4a, 0x44, 0x15, 0x56, 0x51,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010227 0x01, 0xfe, 0x9e, 0x1e, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x0a, 0x57,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010228 0x01, 0x18, 0x09, 0x00, 0x36, 0x01, 0x85, 0xfe, 0x18, 0x10, 0xfe, 0x41,
10229 0x58, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0xc8, 0x54, 0x7b, 0xfe, 0x1c, 0x03,
10230 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x37, 0x60, 0xfe, 0x02, 0xe8, 0x30,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010231 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, 0x27, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010232 0xfe, 0xe4, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x40,
10233 0x1c, 0x2a, 0xeb, 0xfe, 0x26, 0xf0, 0xfe, 0x66, 0x03, 0xfe, 0xa0, 0xf0,
10234 0xfe, 0x54, 0x03, 0xfe, 0x11, 0xf0, 0xbc, 0xfe, 0xef, 0x10, 0xfe, 0x9f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010235 0xf0, 0xfe, 0x74, 0x03, 0xfe, 0x46, 0x1c, 0x19, 0xfe, 0x11, 0x00, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010236 0x70, 0x37, 0xfe, 0x48, 0x1c, 0xfe, 0x46, 0x1c, 0x01, 0x0c, 0x06, 0x28,
10237 0xfe, 0x18, 0x13, 0x26, 0x21, 0xb9, 0xc7, 0x20, 0xb9, 0x0a, 0x57, 0x01,
10238 0x18, 0xc7, 0x89, 0x01, 0xfe, 0xc8, 0x1a, 0x15, 0xe1, 0x2a, 0xeb, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010239 0x01, 0xf0, 0xeb, 0xfe, 0x82, 0xf0, 0xfe, 0xa4, 0x03, 0xfe, 0x9c, 0x32,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010240 0x15, 0xfe, 0xe4, 0x00, 0x2f, 0xfe, 0xb6, 0x03, 0x2a, 0x3c, 0x16, 0xfe,
10241 0xc6, 0x03, 0x01, 0x41, 0xfe, 0x06, 0xf0, 0xfe, 0xd6, 0x03, 0xaf, 0xa0,
10242 0xfe, 0x0a, 0xf0, 0xfe, 0xa2, 0x07, 0x05, 0x29, 0x03, 0x81, 0x1e, 0x1b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010243 0xfe, 0x24, 0x05, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010244 0xea, 0xfe, 0x46, 0x1c, 0x37, 0x7d, 0x1d, 0xfe, 0x67, 0x1b, 0xfe, 0xbf,
10245 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c, 0x75, 0x01, 0xa6, 0x86, 0x0a,
10246 0x57, 0x01, 0x18, 0x09, 0x00, 0x1b, 0xec, 0x0a, 0xe1, 0x01, 0x18, 0x77,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010247 0x50, 0x40, 0x8d, 0x30, 0x03, 0x81, 0x1e, 0xf8, 0x1f, 0x63, 0x01, 0x42,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010248 0x8f, 0xfe, 0x70, 0x02, 0x05, 0xea, 0xd7, 0x99, 0xd8, 0x9c, 0x2a, 0x29,
10249 0x2f, 0xfe, 0x4e, 0x04, 0x16, 0xfe, 0x4a, 0x04, 0x7e, 0xfe, 0xa0, 0x00,
10250 0xfe, 0x9b, 0x57, 0xfe, 0x54, 0x12, 0x32, 0xff, 0x02, 0x00, 0x10, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010251 0x08, 0x16, 0xfe, 0x02, 0x05, 0x32, 0x01, 0x08, 0x16, 0x29, 0x27, 0x25,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010252 0xee, 0xfe, 0x4c, 0x44, 0xfe, 0x58, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x13,
10253 0x34, 0xfe, 0x4c, 0x54, 0x7b, 0xec, 0x60, 0x8d, 0x30, 0x01, 0xfe, 0x4e,
10254 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x7c, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010255 0x32, 0x13, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x68, 0x13, 0xfe, 0x26, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010256 0x13, 0x34, 0xfe, 0x4c, 0x54, 0x7b, 0xec, 0x01, 0xfe, 0x4e, 0x1e, 0xfe,
10257 0x48, 0x47, 0xfe, 0x54, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xa5, 0x01, 0x43,
10258 0x09, 0x9b, 0xfe, 0x40, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xf9, 0x1f, 0x7f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010259 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, 0x8f,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010260 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x32, 0x15, 0xfe, 0xe6, 0x00, 0x0f, 0xfe,
10261 0x1c, 0x90, 0x04, 0xfe, 0x9c, 0x93, 0x3a, 0x0b, 0x0e, 0x8b, 0x02, 0x1f,
10262 0x7f, 0x01, 0x42, 0x05, 0x35, 0xfe, 0x42, 0x5b, 0x7d, 0x1d, 0xfe, 0x46,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010263 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0x0f, 0xfe, 0x87, 0x80, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010264 0xfe, 0x87, 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0xd0, 0x65, 0x01, 0x0c,
10265 0x06, 0x0d, 0xfe, 0x98, 0x13, 0x0f, 0xfe, 0x20, 0x80, 0x04, 0xfe, 0xa0,
10266 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x1d, 0xfe, 0x84, 0x12, 0x01, 0x38, 0x06,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010267 0x07, 0xfe, 0x70, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x1e, 0x1b, 0xfe, 0xda,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010268 0x05, 0xd0, 0x54, 0x01, 0x38, 0x06, 0x0d, 0xfe, 0x58, 0x13, 0x03, 0xfe,
10269 0xa0, 0x00, 0x1e, 0xfe, 0x50, 0x12, 0x5e, 0xff, 0x02, 0x00, 0x10, 0x2f,
10270 0xfe, 0x90, 0x05, 0x2a, 0x3c, 0xcc, 0xff, 0x02, 0x00, 0x10, 0x2f, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010271 0x9e, 0x05, 0x17, 0xfe, 0xf4, 0x05, 0x15, 0xfe, 0xe3, 0x00, 0x26, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010272 0x38, 0xfe, 0x4a, 0xf0, 0xfe, 0xc0, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0xba,
10273 0x05, 0x71, 0x2e, 0xfe, 0x21, 0x00, 0xf1, 0x2e, 0xfe, 0x22, 0x00, 0xa2,
10274 0x2e, 0x4a, 0xfe, 0x09, 0x48, 0xff, 0x02, 0x00, 0x10, 0x2f, 0xfe, 0xd0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010275 0x05, 0x17, 0xfe, 0xf4, 0x05, 0xfe, 0xe2, 0x08, 0x01, 0x38, 0x06, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010276 0x1c, 0x00, 0x4d, 0x01, 0xa7, 0x2e, 0x07, 0x20, 0xe4, 0x47, 0xfe, 0x27,
10277 0x01, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x24, 0x12, 0x3e, 0x01, 0x84, 0x1f,
10278 0x7f, 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010279 0x8f, 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x03, 0xe6, 0x1e, 0xfe, 0xca, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010280 0x03, 0xb6, 0x1e, 0xfe, 0x40, 0x12, 0x03, 0x66, 0x1e, 0xfe, 0x38, 0x13,
10281 0x3e, 0x01, 0x84, 0x17, 0xfe, 0x72, 0x06, 0x0a, 0x07, 0x01, 0x38, 0x06,
10282 0x24, 0xfe, 0x02, 0x12, 0x4f, 0x01, 0xfe, 0x56, 0x19, 0x16, 0xfe, 0x68,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010283 0x06, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x66, 0x8a, 0x10, 0x66,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010284 0x03, 0x9a, 0x1e, 0xfe, 0x70, 0x12, 0x03, 0x55, 0x1e, 0xfe, 0x68, 0x13,
10285 0x01, 0xc6, 0x09, 0x12, 0x48, 0xfe, 0x92, 0x06, 0x2e, 0x12, 0x01, 0xfe,
10286 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0x13, 0x58, 0xff, 0x02, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010287 0x57, 0x52, 0xad, 0x23, 0x3f, 0x4e, 0x62, 0x49, 0x3e, 0x01, 0x84, 0x17,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010288 0xfe, 0xea, 0x06, 0x01, 0x38, 0x06, 0x12, 0xf7, 0x45, 0x0a, 0x95, 0x01,
10289 0xfe, 0x84, 0x19, 0x16, 0xfe, 0xe0, 0x06, 0x15, 0x82, 0x01, 0x41, 0x15,
10290 0xe2, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x1c, 0x07, 0x01, 0x84, 0xfe, 0xae,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010291 0x10, 0x03, 0x6f, 0x1e, 0xfe, 0x9e, 0x13, 0x3e, 0x01, 0x84, 0x03, 0x9a,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010292 0x1e, 0xfe, 0x1a, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfc, 0x01, 0xc6, 0x01,
10293 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0xf0, 0x45, 0x0a, 0x95,
10294 0x03, 0xb6, 0x1e, 0xf8, 0x01, 0x38, 0x06, 0x24, 0x36, 0xfe, 0x02, 0xf6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010295 0x07, 0x71, 0x78, 0x8c, 0x00, 0x4d, 0x62, 0x49, 0x3e, 0x2d, 0x93, 0x4e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010296 0xd0, 0x0d, 0x17, 0xfe, 0x9a, 0x07, 0x01, 0xfe, 0xc0, 0x19, 0x16, 0xfe,
10297 0x90, 0x07, 0x26, 0x20, 0x9e, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x21,
10298 0x9e, 0x09, 0x07, 0xfb, 0x03, 0xe6, 0xfe, 0x58, 0x57, 0x10, 0xe6, 0x05,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010299 0xfe, 0x2a, 0x06, 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x1c, 0x07, 0x01, 0x84,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010300 0xfe, 0x9c, 0x32, 0x5f, 0x75, 0x01, 0xa6, 0x86, 0x15, 0xfe, 0xe2, 0x00,
10301 0x2f, 0xed, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe, 0xce, 0x07, 0xae, 0xfe,
10302 0x96, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x9e, 0x08, 0xaf, 0xa0, 0x05, 0x29,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010303 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x2e, 0x12, 0x14, 0x1d, 0x01, 0x08, 0x14,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010304 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0xfe,
10305 0x99, 0xa4, 0x01, 0x08, 0x14, 0x00, 0x05, 0xfe, 0xc6, 0x09, 0x01, 0x76,
10306 0x06, 0x12, 0xfe, 0x3a, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x30, 0x13,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010307 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010308 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x07, 0x01, 0x08, 0x14, 0x00,
10309 0x05, 0xef, 0x7c, 0x4a, 0x78, 0x4f, 0x0f, 0xfe, 0x9a, 0x81, 0x04, 0xfe,
10310 0x9a, 0x83, 0xfe, 0xcb, 0x47, 0x0b, 0x0e, 0x2d, 0x28, 0x48, 0xfe, 0x6c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010311 0x08, 0x0a, 0x28, 0xfe, 0x09, 0x6f, 0xca, 0xfe, 0xca, 0x45, 0xfe, 0x32,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010312 0x12, 0x53, 0x63, 0x4e, 0x7c, 0x97, 0x2f, 0xfe, 0x7e, 0x08, 0x2a, 0x3c,
10313 0xfe, 0x0a, 0xf0, 0xfe, 0x6c, 0x08, 0xaf, 0xa0, 0xae, 0xfe, 0x96, 0x08,
10314 0x05, 0x29, 0x01, 0x41, 0x05, 0xed, 0x14, 0x24, 0x05, 0xed, 0xfe, 0x9c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010315 0xf7, 0x9f, 0x01, 0xfe, 0xae, 0x1e, 0xfe, 0x18, 0x58, 0x01, 0xfe, 0xbe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010316 0x1e, 0xfe, 0x99, 0x58, 0xfe, 0x78, 0x18, 0xfe, 0xf9, 0x18, 0x8e, 0xfe,
10317 0x16, 0x09, 0x10, 0x6a, 0x22, 0x6b, 0x01, 0x0c, 0x61, 0x54, 0x44, 0x21,
10318 0x2c, 0x09, 0x1a, 0xf8, 0x77, 0x01, 0xfe, 0x7e, 0x1e, 0x47, 0x2c, 0x7a,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010319 0x30, 0xf0, 0xfe, 0x83, 0xe7, 0xfe, 0x3f, 0x00, 0x71, 0xfe, 0x03, 0x40,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010320 0x01, 0x0c, 0x61, 0x65, 0x44, 0x01, 0xc2, 0xc8, 0xfe, 0x1f, 0x40, 0x20,
10321 0x6e, 0x01, 0xfe, 0x6a, 0x16, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe,
10322 0x44, 0x51, 0xfe, 0xc6, 0x51, 0xfe, 0x10, 0x10, 0x01, 0xfe, 0xce, 0x1e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010323 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x01, 0xfe, 0xee, 0x1e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010324 0x01, 0xfe, 0xfe, 0x1e, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x10, 0x4b,
10325 0x22, 0x4c, 0xfe, 0x8a, 0x10, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0x50, 0x12,
10326 0x01, 0xfe, 0xae, 0x1e, 0x01, 0xfe, 0xbe, 0x1e, 0x10, 0x6a, 0x22, 0x6b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010327 0x01, 0x0c, 0x06, 0x65, 0x4e, 0x01, 0xc2, 0x0f, 0xfe, 0x1f, 0x80, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010328 0xfe, 0x9f, 0x83, 0x33, 0x0b, 0x0e, 0x20, 0x6e, 0x0f, 0xfe, 0x44, 0x90,
10329 0x04, 0xfe, 0xc4, 0x93, 0x3a, 0x0b, 0xfe, 0xc6, 0x90, 0x04, 0xfe, 0xc6,
10330 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x6c, 0x22, 0x6d, 0x01, 0xfe, 0xce, 0x1e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010331 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x0f, 0xfe, 0x40, 0x90,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010332 0x04, 0xfe, 0xc0, 0x93, 0x3a, 0x0b, 0xfe, 0xc2, 0x90, 0x04, 0xfe, 0xc2,
10333 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x4b, 0x22, 0x4c, 0x10, 0x64, 0x22, 0x34,
10334 0x01, 0x0c, 0x61, 0x24, 0x44, 0x37, 0x13, 0xfe, 0x4e, 0x11, 0x2f, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010335 0xde, 0x09, 0xfe, 0x9e, 0xf0, 0xfe, 0xf2, 0x09, 0xfe, 0x01, 0x48, 0x1b,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010336 0x3c, 0x37, 0x88, 0xf5, 0xd4, 0xfe, 0x1e, 0x0a, 0xd5, 0xfe, 0x42, 0x0a,
10337 0xd2, 0xfe, 0x1e, 0x0a, 0xd3, 0xfe, 0x42, 0x0a, 0xae, 0xfe, 0x12, 0x0a,
10338 0xfe, 0x06, 0xf0, 0xfe, 0x18, 0x0a, 0xaf, 0xa0, 0x05, 0x29, 0x01, 0x41,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010339 0xfe, 0xc1, 0x10, 0x14, 0x24, 0xfe, 0xc1, 0x10, 0x01, 0x76, 0x06, 0x07,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010340 0xfe, 0x14, 0x12, 0x01, 0x76, 0x06, 0x0d, 0x5d, 0x01, 0x0c, 0x06, 0x0d,
10341 0xfe, 0x74, 0x12, 0xfe, 0x2e, 0x1c, 0x05, 0xfe, 0x1a, 0x0c, 0x01, 0x76,
10342 0x06, 0x07, 0x5d, 0x01, 0x76, 0x06, 0x0d, 0x41, 0xfe, 0x2c, 0x1c, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010343 0xaa, 0xf0, 0xfe, 0xce, 0x0a, 0xfe, 0xac, 0xf0, 0xfe, 0x66, 0x0a, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010344 0x92, 0x10, 0xc4, 0xf6, 0xfe, 0xad, 0xf0, 0xfe, 0x72, 0x0a, 0x05, 0xfe,
10345 0x1a, 0x0c, 0xc5, 0xfe, 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0xbf, 0xfe, 0x6b,
10346 0x18, 0x23, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12, 0xac, 0xfe, 0xd2, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010347 0xbf, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x1b, 0xbf, 0x03, 0xe3, 0x23, 0x07,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010348 0x1b, 0xbf, 0xd4, 0x5b, 0xd5, 0x5b, 0xd2, 0x5b, 0xd3, 0x5b, 0xc4, 0xc5,
10349 0xfe, 0xa9, 0x10, 0x75, 0x5e, 0x32, 0x1f, 0x7f, 0x01, 0x42, 0x19, 0xfe,
10350 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x70, 0x19, 0x98, 0x05, 0x70, 0xfe, 0x74,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010351 0x18, 0x23, 0xfe, 0x00, 0xf8, 0x1b, 0x5b, 0x7d, 0x12, 0x01, 0xfe, 0x78,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010352 0x0f, 0x4d, 0x01, 0xfe, 0x96, 0x1a, 0x21, 0x30, 0x77, 0x7d, 0x1d, 0x05,
10353 0x5b, 0x01, 0x0c, 0x06, 0x0d, 0x2b, 0xfe, 0xe2, 0x0b, 0x01, 0x0c, 0x06,
10354 0x54, 0xfe, 0xa6, 0x12, 0x01, 0x0c, 0x06, 0x24, 0xfe, 0x88, 0x13, 0x21,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010355 0x6e, 0xc7, 0x01, 0xfe, 0x1e, 0x1f, 0x0f, 0xfe, 0x83, 0x80, 0x04, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010356 0x83, 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0xfe, 0xc8, 0x44, 0xfe, 0x42,
10357 0x13, 0x0f, 0xfe, 0x04, 0x91, 0x04, 0xfe, 0x84, 0x93, 0xfe, 0xca, 0x57,
10358 0x0b, 0xfe, 0x86, 0x91, 0x04, 0xfe, 0x86, 0x93, 0xfe, 0xcb, 0x57, 0x0b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010359 0x0e, 0x7a, 0x30, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x8e, 0x40, 0x03,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010360 0x6a, 0x3b, 0x6b, 0x10, 0x97, 0x22, 0x98, 0xd9, 0x6a, 0xda, 0x6b, 0x01,
10361 0xc2, 0xc8, 0x7a, 0x30, 0x20, 0x6e, 0xdb, 0x64, 0xdc, 0x34, 0x91, 0x6c,
10362 0x7e, 0x6d, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55, 0xfe, 0x04, 0xfa, 0x64,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010363 0xfe, 0x05, 0xfa, 0x34, 0x01, 0xfe, 0x6a, 0x16, 0xa3, 0x26, 0x10, 0x97,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010364 0x10, 0x98, 0x91, 0x6c, 0x7e, 0x6d, 0xfe, 0x14, 0x10, 0x01, 0x0c, 0x06,
10365 0x24, 0x1b, 0x40, 0x91, 0x4b, 0x7e, 0x4c, 0x01, 0x0c, 0x06, 0xfe, 0xf7,
10366 0x00, 0x44, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010367 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x24,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010368 0x1b, 0x40, 0x01, 0x0c, 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x78, 0x01, 0xfe,
10369 0x8e, 0x1e, 0x4f, 0x0f, 0xfe, 0x10, 0x90, 0x04, 0xfe, 0x90, 0x93, 0x3a,
10370 0x0b, 0xfe, 0x92, 0x90, 0x04, 0xfe, 0x92, 0x93, 0x79, 0x0b, 0x0e, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010371 0xbd, 0x10, 0x01, 0x43, 0x09, 0xbb, 0x1b, 0xfe, 0x6e, 0x0a, 0x15, 0xbb,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010372 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x14, 0x13, 0x03, 0x4b, 0x3b, 0x4c, 0x8e,
10373 0xfe, 0x6e, 0x0a, 0xfe, 0x0c, 0x58, 0xfe, 0x8d, 0x58, 0x05, 0x5b, 0x26,
10374 0x3e, 0x0f, 0xfe, 0x19, 0x80, 0x04, 0xfe, 0x99, 0x83, 0x33, 0x0b, 0x0e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010375 0xfe, 0xe5, 0x10, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1a, 0x12, 0xfe, 0x6c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010376 0x19, 0xfe, 0x19, 0x41, 0xfe, 0x6b, 0x18, 0xac, 0xfe, 0xd1, 0xf0, 0xef,
10377 0x1f, 0x92, 0x01, 0x42, 0x19, 0xfe, 0x44, 0x00, 0xfe, 0x90, 0x10, 0xfe,
10378 0x6c, 0x19, 0xd9, 0x4b, 0xfe, 0xed, 0x19, 0xda, 0x4c, 0xfe, 0x0c, 0x51,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010379 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xff, 0x31, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010380 0x76, 0x10, 0xac, 0xfe, 0xd2, 0xf0, 0xfe, 0xba, 0x0c, 0xfe, 0x76, 0x18,
10381 0x23, 0x1d, 0x5d, 0x03, 0xe3, 0x23, 0x07, 0xfe, 0x08, 0x13, 0x19, 0xfe,
10382 0x16, 0x00, 0x05, 0x70, 0xfe, 0xd1, 0xf0, 0xfe, 0xcc, 0x0c, 0x1f, 0x92,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010383 0x01, 0x42, 0x19, 0xfe, 0x17, 0x00, 0x5c, 0xfe, 0xce, 0xf0, 0xfe, 0xd2,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010384 0x0c, 0xfe, 0x3e, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xde, 0x0c, 0x19, 0xfe,
10385 0x22, 0x00, 0x05, 0x70, 0xfe, 0xcb, 0xf0, 0xfe, 0xea, 0x0c, 0x19, 0xfe,
10386 0x24, 0x00, 0x05, 0x70, 0xfe, 0xd0, 0xf0, 0xfe, 0xf4, 0x0c, 0x19, 0x94,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010387 0xfe, 0x1c, 0x10, 0xfe, 0xcf, 0xf0, 0xfe, 0xfe, 0x0c, 0x19, 0x4a, 0xf3,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010388 0xfe, 0xcc, 0xf0, 0xef, 0x01, 0x76, 0x06, 0x24, 0x4d, 0x19, 0xfe, 0x12,
10389 0x00, 0x37, 0x13, 0xfe, 0x4e, 0x11, 0x2f, 0xfe, 0x16, 0x0d, 0xfe, 0x9e,
10390 0xf0, 0xfe, 0x2a, 0x0d, 0xfe, 0x01, 0x48, 0x1b, 0x3c, 0x37, 0x88, 0xf5,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010391 0xd4, 0x29, 0xd5, 0x29, 0xd2, 0x29, 0xd3, 0x29, 0x37, 0xfe, 0x9c, 0x32,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010392 0x2f, 0xfe, 0x3e, 0x0d, 0x2a, 0x3c, 0xae, 0xfe, 0x62, 0x0d, 0xaf, 0xa0,
10393 0xd4, 0x9f, 0xd5, 0x9f, 0xd2, 0x9f, 0xd3, 0x9f, 0x05, 0x29, 0x01, 0x41,
10394 0xfe, 0xd3, 0x10, 0x15, 0xfe, 0xe8, 0x00, 0xc4, 0xc5, 0x75, 0xd7, 0x99,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010395 0xd8, 0x9c, 0xfe, 0x89, 0xf0, 0x29, 0x27, 0x25, 0xbe, 0xd7, 0x99, 0xd8,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010396 0x9c, 0x2f, 0xfe, 0x8c, 0x0d, 0x16, 0x29, 0x27, 0x25, 0xbd, 0xfe, 0x01,
10397 0x48, 0xa4, 0x19, 0xfe, 0x42, 0x00, 0x05, 0x70, 0x90, 0x07, 0xfe, 0x81,
10398 0x49, 0x1b, 0xfe, 0x64, 0x0e, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x44, 0x13,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010399 0x19, 0x00, 0x2d, 0x0d, 0xfe, 0x54, 0x12, 0x2d, 0xfe, 0x28, 0x00, 0x2b,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010400 0xfe, 0xda, 0x0e, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, 0x36, 0x46, 0xfe,
10401 0x28, 0x00, 0xfe, 0xfa, 0x10, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe, 0x00,
10402 0x1d, 0x0a, 0xba, 0x01, 0xfe, 0x58, 0x10, 0x40, 0x15, 0x56, 0x01, 0x85,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010403 0x05, 0x35, 0x19, 0xfe, 0x44, 0x00, 0x2d, 0x0d, 0xf7, 0x46, 0x0d, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010404 0xcc, 0x10, 0x01, 0xa7, 0x46, 0x0d, 0xfe, 0xc2, 0x10, 0x01, 0xa7, 0x0f,
10405 0xfe, 0x19, 0x82, 0x04, 0xfe, 0x99, 0x83, 0xfe, 0xcc, 0x47, 0x0b, 0x0e,
10406 0xfe, 0x34, 0x46, 0xa5, 0x46, 0x0d, 0x19, 0xfe, 0x43, 0x00, 0xfe, 0xa2,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010407 0x10, 0x01, 0x0c, 0x61, 0x0d, 0x44, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010408 0x00, 0x1d, 0x40, 0x15, 0x56, 0x01, 0x85, 0x7d, 0x0d, 0x40, 0x51, 0x01,
10409 0xfe, 0x9e, 0x1e, 0x05, 0xfe, 0x3a, 0x03, 0x01, 0x0c, 0x06, 0x0d, 0x5d,
10410 0x46, 0x0d, 0x19, 0x00, 0xfe, 0x62, 0x10, 0x01, 0x76, 0x06, 0x12, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010411 0x5c, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x52, 0x13, 0xfe, 0x1c, 0x1c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010412 0xfe, 0x9d, 0xf0, 0xfe, 0x8e, 0x0e, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0,
10413 0xfe, 0x94, 0x0e, 0x01, 0x0c, 0x61, 0x12, 0x44, 0xfe, 0x9f, 0x10, 0x19,
10414 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0d, 0x4f, 0xfe, 0x2e, 0x10, 0x19,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010415 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x19, 0xfe, 0x47, 0x00, 0xf1, 0x19,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010416 0xfe, 0x41, 0x00, 0xa2, 0x19, 0xfe, 0x24, 0x00, 0x86, 0xc4, 0xc5, 0x75,
10417 0x03, 0x81, 0x1e, 0x2b, 0xea, 0x4f, 0xfe, 0x04, 0xe6, 0x12, 0xfe, 0x9d,
10418 0x41, 0xfe, 0x1c, 0x42, 0x40, 0x01, 0xf4, 0x05, 0x35, 0xfe, 0x12, 0x1c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010419 0x1f, 0x0d, 0x47, 0xb5, 0xc3, 0x1f, 0xfe, 0x31, 0x00, 0x47, 0xb8, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010420 0xfe, 0xd4, 0x11, 0x05, 0xe9, 0x51, 0xfe, 0x06, 0xec, 0xe0, 0xfe, 0x0e,
10421 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0x06, 0xea, 0xe0,
10422 0xfe, 0x47, 0x4b, 0x45, 0xfe, 0x75, 0x57, 0x03, 0x67, 0xfe, 0x98, 0x56,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010423 0xfe, 0x38, 0x12, 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x44, 0x48, 0x60, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010424 0x0c, 0x06, 0x28, 0xfe, 0x18, 0x13, 0x0a, 0x57, 0x01, 0x18, 0x3e, 0xfe,
10425 0x41, 0x58, 0x0a, 0xba, 0xfe, 0xfa, 0x14, 0xfe, 0x49, 0x54, 0xb0, 0xfe,
10426 0x5e, 0x0f, 0x05, 0xfe, 0x3a, 0x03, 0x0a, 0x67, 0xfe, 0xe0, 0x14, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010427 0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0xce, 0x47,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010428 0xfe, 0xad, 0x13, 0x05, 0x35, 0x21, 0x2c, 0x09, 0x1a, 0xfe, 0x98, 0x12,
10429 0x26, 0x20, 0x96, 0x20, 0xe7, 0xfe, 0x08, 0x1c, 0xfe, 0x7c, 0x19, 0xfe,
10430 0xfd, 0x19, 0xfe, 0x0a, 0x1c, 0x03, 0xe5, 0xfe, 0x48, 0x55, 0xa5, 0x3b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010431 0xfe, 0x62, 0x01, 0xfe, 0xc9, 0x55, 0x31, 0xfe, 0x74, 0x10, 0x01, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010432 0xf0, 0x1a, 0x03, 0xfe, 0x38, 0x01, 0x3b, 0xfe, 0x3a, 0x01, 0x8e, 0xfe,
10433 0x1e, 0x10, 0xfe, 0x02, 0xec, 0xe7, 0x53, 0x00, 0x36, 0xfe, 0x04, 0xec,
10434 0x2c, 0x60, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x62, 0x1b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010435 0x01, 0xfe, 0xce, 0x1e, 0xb2, 0x11, 0xfe, 0x18, 0x13, 0xca, 0xfe, 0x02,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010436 0xea, 0xe7, 0x53, 0x92, 0xfe, 0xc3, 0x13, 0x1f, 0x12, 0x47, 0xb5, 0xc3,
10437 0xfe, 0x2a, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x23, 0xfe, 0xf0, 0xff, 0x10,
10438 0xe5, 0x03, 0xfe, 0x3a, 0x01, 0x10, 0xfe, 0x62, 0x01, 0x01, 0xfe, 0x1e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010439 0x1e, 0x20, 0x2c, 0x15, 0x56, 0x01, 0xfe, 0x9e, 0x1e, 0x13, 0x07, 0x02,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010440 0x26, 0x02, 0x21, 0x96, 0xc7, 0x20, 0x96, 0x09, 0x92, 0xfe, 0x79, 0x13,
10441 0x1f, 0x1d, 0x47, 0xb5, 0xc3, 0xfe, 0xe1, 0x10, 0xcf, 0xfe, 0x03, 0xdc,
10442 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xcf, 0xfe, 0x03, 0xdc, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010443 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x26, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010444 0x00, 0xcc, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x89, 0x02, 0x01, 0x0c, 0x06,
10445 0x4a, 0xfe, 0x4e, 0x13, 0x0f, 0xfe, 0x1c, 0x80, 0x04, 0xfe, 0x9c, 0x83,
10446 0x33, 0x0b, 0x0e, 0x09, 0x07, 0xfe, 0x3a, 0x13, 0x0f, 0xfe, 0x1e, 0x80,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010447 0x04, 0xfe, 0x9e, 0x83, 0x33, 0x0b, 0x0e, 0xfe, 0x2a, 0x13, 0x0f, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010448 0x1d, 0x80, 0x04, 0xfe, 0x9d, 0x83, 0xfe, 0xf9, 0x13, 0x0e, 0xfe, 0x1c,
10449 0x13, 0x01, 0xfe, 0xee, 0x1e, 0xac, 0xfe, 0x14, 0x13, 0x01, 0xfe, 0xfe,
10450 0x1e, 0xfe, 0x81, 0x58, 0xfa, 0x01, 0xfe, 0x0e, 0x1f, 0xfe, 0x30, 0xf4,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010451 0x0d, 0xfe, 0x3c, 0x50, 0xa2, 0x01, 0xfe, 0x92, 0x1b, 0x01, 0x43, 0x09,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010452 0x56, 0xfb, 0x01, 0xfe, 0xc8, 0x1a, 0x01, 0x0c, 0x06, 0x28, 0xa4, 0x01,
10453 0xfe, 0xf4, 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x15, 0xfe, 0xe9, 0x00, 0x01,
10454 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x01, 0xfe, 0x22, 0x1b, 0xfe, 0x1e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010455 0x1c, 0x0f, 0xfe, 0x14, 0x90, 0x04, 0xfe, 0x94, 0x93, 0x3a, 0x0b, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010456 0x96, 0x90, 0x04, 0xfe, 0x96, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0xfe, 0x64,
10457 0x01, 0x22, 0xfe, 0x66, 0x01, 0x01, 0x0c, 0x06, 0x65, 0xf9, 0x0f, 0xfe,
10458 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b, 0x0e, 0x77, 0xfe, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010459 0xec, 0x2c, 0xfe, 0x80, 0x40, 0x20, 0x2c, 0x7a, 0x30, 0x15, 0xdf, 0x40,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010460 0x21, 0x2c, 0xfe, 0x00, 0x40, 0x8d, 0x2c, 0x02, 0xfe, 0x08, 0x1c, 0x03,
10461 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58, 0x03, 0xfe, 0xae, 0x00, 0xfe, 0x07,
10462 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe, 0xb2, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010463 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x2e, 0x49, 0x20, 0xe0, 0x26, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010464 0x66, 0x10, 0x55, 0x10, 0x6f, 0x13, 0x57, 0x52, 0x4f, 0x1c, 0x28, 0xfe,
10465 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x2b, 0xfe, 0x88, 0x11, 0x46, 0x1a, 0x13,
10466 0x5a, 0x52, 0x1c, 0x4a, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x2b, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010467 0x9e, 0x11, 0x2e, 0x1a, 0x20, 0x2c, 0x90, 0x34, 0x60, 0x21, 0x2c, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010468 0x00, 0x40, 0x8d, 0x2c, 0x15, 0xdf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0,
10469 0xfe, 0xb2, 0x11, 0xfe, 0x12, 0x1c, 0x75, 0xfe, 0x14, 0x1c, 0xfe, 0x10,
10470 0x1c, 0xfe, 0x18, 0x1c, 0x02, 0x51, 0xfe, 0x0c, 0x14, 0xfe, 0x0e, 0x47,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010471 0xfe, 0x07, 0xe6, 0x28, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x02, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010472 0xa7, 0x90, 0x34, 0x60, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42,
10473 0x13, 0xfe, 0x02, 0x80, 0x09, 0x56, 0xfe, 0x34, 0x13, 0x0a, 0x5a, 0x01,
10474 0x18, 0xcb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010475 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, 0x89,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010476 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x5c, 0x01, 0x85,
10477 0xf2, 0x09, 0x9b, 0xa4, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xec,
10478 0x11, 0x02, 0xfe, 0x44, 0x58, 0x77, 0xfe, 0x01, 0xec, 0xb8, 0xfe, 0x9e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010479 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x12, 0x8d, 0x30, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010480 0xf4, 0xfe, 0xdd, 0x10, 0x37, 0xd7, 0x99, 0xd8, 0x9c, 0x27, 0x25, 0xee,
10481 0x09, 0x12, 0xfe, 0x48, 0x12, 0x09, 0x0d, 0xfe, 0x56, 0x12, 0x09, 0x1d,
10482 0xfe, 0x30, 0x12, 0x09, 0xdd, 0x1b, 0xfe, 0xc4, 0x13, 0x09, 0xfe, 0x23,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010483 0x00, 0x1b, 0xfe, 0xd0, 0x13, 0x09, 0x07, 0x1b, 0xfe, 0x34, 0x14, 0x09,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010484 0x24, 0xfe, 0x12, 0x12, 0x09, 0x00, 0x1b, 0x29, 0x1f, 0xdd, 0x01, 0x42,
10485 0xa1, 0x32, 0x01, 0x08, 0xae, 0x41, 0x02, 0x32, 0xfe, 0x62, 0x08, 0x0a,
10486 0xe1, 0x01, 0xfe, 0x58, 0x10, 0x15, 0x9b, 0x05, 0x35, 0x32, 0x01, 0x43,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010487 0x09, 0xbb, 0xfe, 0xd7, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0x8e, 0xfe, 0x80,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010488 0x13, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0x72, 0x12, 0xdb, 0x64, 0xdc, 0x34,
10489 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55, 0xb0, 0xfe, 0x4a, 0x13, 0x21, 0x6e,
10490 0xfe, 0x26, 0x13, 0x03, 0x97, 0x3b, 0x98, 0x8e, 0xfe, 0xb6, 0x0e, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010491 0x6a, 0x22, 0x6b, 0x26, 0x10, 0x97, 0x10, 0x98, 0x01, 0xc2, 0x2e, 0x49,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010492 0x88, 0x20, 0x6e, 0x01, 0xfe, 0x6a, 0x16, 0xdb, 0x64, 0xdc, 0x34, 0xfe,
10493 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x64, 0xfe, 0x05, 0xfa,
10494 0x34, 0xfe, 0x8f, 0x10, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x40, 0x56, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010495 0xe1, 0x56, 0x10, 0x6c, 0x22, 0x6d, 0x71, 0xdb, 0x64, 0xdc, 0x34, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010496 0x44, 0x55, 0xfe, 0xe5, 0x55, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x00, 0x56,
10497 0xfe, 0xa1, 0x56, 0x10, 0x68, 0x22, 0x69, 0x01, 0x0c, 0x06, 0x54, 0xf9,
10498 0x21, 0x6e, 0xfe, 0x1f, 0x40, 0x03, 0x6a, 0x3b, 0x6b, 0xfe, 0x2c, 0x50,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010499 0xfe, 0xae, 0x50, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x44, 0x50, 0xfe, 0xc6,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010500 0x50, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03,
10501 0x4b, 0x3b, 0x4c, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x05, 0x73, 0x2e,
10502 0x07, 0x20, 0x9e, 0x05, 0x72, 0x32, 0x01, 0x08, 0x16, 0x3d, 0x27, 0x25,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010503 0xee, 0x09, 0x07, 0x2b, 0x3d, 0x01, 0x43, 0x09, 0xbb, 0x2b, 0x72, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010504 0xa6, 0x23, 0x3f, 0x1b, 0x3d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1e, 0x13,
10505 0x91, 0x4b, 0x7e, 0x4c, 0xfe, 0x0a, 0x55, 0x31, 0xfe, 0x8b, 0x55, 0xd9,
10506 0x4b, 0xda, 0x4c, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x05, 0x72, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010507 0xfe, 0x8e, 0x1e, 0xca, 0xfe, 0x19, 0x41, 0x05, 0x72, 0x32, 0x01, 0x08,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010508 0x2a, 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbe, 0x2d, 0x1d, 0xc0, 0x2d, 0x0d,
10509 0x83, 0x2d, 0x7f, 0x1b, 0xfe, 0x66, 0x15, 0x05, 0x3d, 0x01, 0x08, 0x2a,
10510 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbd, 0x09, 0x1d, 0x2b, 0x3d, 0x01, 0x08,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010511 0x16, 0xc0, 0x27, 0x25, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x50, 0x03,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010512 0xb6, 0x1e, 0x83, 0x01, 0x38, 0x06, 0x24, 0x31, 0xa1, 0xfe, 0xbb, 0x45,
10513 0x2d, 0x00, 0xa4, 0x46, 0x07, 0x90, 0x3f, 0x01, 0xfe, 0xf8, 0x15, 0x01,
10514 0xa6, 0x86, 0xfe, 0x4b, 0x45, 0xfe, 0x20, 0x13, 0x01, 0x43, 0x09, 0x82,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010515 0xfe, 0x16, 0x13, 0x03, 0x9a, 0x1e, 0x5d, 0x03, 0x55, 0x1e, 0x31, 0x5e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010516 0x05, 0x72, 0xfe, 0xc0, 0x5d, 0x01, 0xa7, 0xfe, 0x03, 0x17, 0x03, 0x66,
10517 0x8a, 0x10, 0x66, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01, 0xfe, 0x56,
10518 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d, 0x27, 0x25, 0xbd,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010519 0x09, 0x07, 0x2b, 0x3d, 0x01, 0xfe, 0xbe, 0x16, 0xfe, 0x42, 0x58, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010520 0xe8, 0x14, 0x01, 0xa6, 0x86, 0xfe, 0x4a, 0xf4, 0x0d, 0x1b, 0x3d, 0xfe,
10521 0x4a, 0xf4, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09, 0x82, 0x4e, 0x05,
10522 0x72, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010523 0x01, 0xfe, 0x84, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010524 0x27, 0x25, 0xbd, 0x09, 0x12, 0x2b, 0x3d, 0x01, 0xfe, 0xe8, 0x17, 0x8b,
10525 0xfe, 0xaa, 0x14, 0xfe, 0xb6, 0x14, 0x86, 0xa8, 0xb2, 0x0d, 0x1b, 0x3d,
10526 0xb2, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09, 0x82, 0x4e, 0x05, 0x72,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010527 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010528 0xfe, 0xc0, 0x19, 0x05, 0x73, 0x13, 0x07, 0x2f, 0xfe, 0xcc, 0x15, 0x17,
10529 0xfe, 0xe2, 0x15, 0x5f, 0xcc, 0x01, 0x08, 0x26, 0x5f, 0x02, 0x8f, 0xfe,
10530 0xde, 0x15, 0x2a, 0xfe, 0xde, 0x15, 0x16, 0xfe, 0xcc, 0x15, 0x5e, 0x32,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010531 0x01, 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010532 0xad, 0x23, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02,
10533 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xad, 0x23, 0x3f, 0xfe, 0x30,
10534 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010535 0xad, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xfe, 0x00, 0x5e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010536 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xad, 0xfe, 0x0b, 0x58,
10537 0x02, 0x0a, 0x66, 0x01, 0x5c, 0x0a, 0x55, 0x01, 0x5c, 0x0a, 0x6f, 0x01,
10538 0x5c, 0x02, 0x01, 0xfe, 0x1e, 0x1f, 0x23, 0x1a, 0xff, 0x03, 0x00, 0x54,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010539 0xfe, 0x00, 0xf4, 0x24, 0x52, 0x0f, 0xfe, 0x00, 0x7c, 0x04, 0xfe, 0x07,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010540 0x7c, 0x3a, 0x0b, 0x0e, 0xfe, 0x00, 0x71, 0xfe, 0xf9, 0x18, 0xfe, 0x7a,
10541 0x19, 0xfe, 0xfb, 0x19, 0xfe, 0x1a, 0xf7, 0x00, 0xfe, 0x1b, 0xf7, 0x00,
10542 0x7a, 0x30, 0x10, 0x68, 0x22, 0x69, 0xd9, 0x6c, 0xda, 0x6d, 0x02, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010543 0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x77,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010544 0x02, 0x01, 0xc6, 0xfe, 0x42, 0x48, 0x4f, 0x50, 0x45, 0x01, 0x08, 0x16,
10545 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xbe, 0x01, 0x08, 0x16, 0xfe, 0xe0, 0x17,
10546 0x27, 0x25, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x03, 0x9a, 0x1e, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010547 0xda, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfe, 0xd0, 0x13, 0x26, 0x53, 0x12,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010548 0x48, 0xfe, 0x08, 0x17, 0xd1, 0x12, 0x53, 0x12, 0xfe, 0x1e, 0x13, 0x2d,
10549 0xb4, 0x7b, 0xfe, 0x26, 0x17, 0x4d, 0x13, 0x07, 0x1c, 0xb4, 0x90, 0x04,
10550 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xf1, 0xff, 0x02, 0x83, 0x55,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010551 0x53, 0x1d, 0xfe, 0x12, 0x13, 0xd6, 0xfe, 0x30, 0x00, 0xb0, 0xfe, 0x80,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010552 0x17, 0x1c, 0x63, 0x13, 0x07, 0xfe, 0x56, 0x10, 0x53, 0x0d, 0xfe, 0x16,
10553 0x13, 0xd6, 0xfe, 0x64, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0x64,
10554 0x00, 0x1c, 0x94, 0x13, 0x07, 0xfe, 0x28, 0x10, 0x53, 0x07, 0xfe, 0x60,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010555 0x13, 0xd6, 0xfe, 0xc8, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0xc8,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010556 0x00, 0x1c, 0x95, 0x13, 0x07, 0x71, 0xd6, 0xfe, 0x90, 0x01, 0x48, 0xfe,
10557 0x8c, 0x17, 0x45, 0xf3, 0xfe, 0x43, 0xf4, 0x96, 0xfe, 0x56, 0xf0, 0xfe,
10558 0x9e, 0x17, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x43, 0xf4, 0x94, 0xf6, 0x8b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010559 0x01, 0xfe, 0x24, 0x16, 0x23, 0x3f, 0xfc, 0xa8, 0x8c, 0x49, 0x48, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010560 0xda, 0x17, 0x62, 0x49, 0xfe, 0x1c, 0x10, 0xa8, 0x8c, 0x80, 0x48, 0xfe,
10561 0xda, 0x17, 0x62, 0x80, 0x71, 0x50, 0x26, 0xfe, 0x4d, 0xf4, 0x00, 0xf7,
10562 0x45, 0x13, 0x07, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x02, 0x50, 0x13,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010563 0x0d, 0x02, 0x50, 0x3e, 0x78, 0x4f, 0x45, 0x01, 0x08, 0x16, 0xa9, 0x27,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010564 0x25, 0xbe, 0xfe, 0x03, 0xea, 0xfe, 0x7e, 0x01, 0x01, 0x08, 0x16, 0xa9,
10565 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe,
10566 0xe9, 0x0a, 0xfe, 0x05, 0xea, 0xfe, 0x7f, 0x01, 0x01, 0x08, 0x16, 0xa9,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010567 0x27, 0x25, 0xfe, 0x69, 0x09, 0xfe, 0x02, 0xea, 0xfe, 0x80, 0x01, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010568 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, 0xe8, 0x08, 0x47, 0xfe, 0x81, 0x01,
10569 0x03, 0xb6, 0x1e, 0x83, 0x01, 0x38, 0x06, 0x24, 0x31, 0xa2, 0x78, 0xf2,
10570 0x53, 0x07, 0x36, 0xfe, 0x34, 0xf4, 0x3f, 0xa1, 0x78, 0x03, 0x9a, 0x1e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010571 0x83, 0x01, 0x38, 0x06, 0x12, 0x31, 0xf0, 0x4f, 0x45, 0xfe, 0x90, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010572 0xfe, 0x40, 0x5a, 0x23, 0x3f, 0xfb, 0x8c, 0x49, 0x48, 0xfe, 0xaa, 0x18,
10573 0x62, 0x49, 0x71, 0x8c, 0x80, 0x48, 0xfe, 0xaa, 0x18, 0x62, 0x80, 0xfe,
10574 0xb4, 0x56, 0xfe, 0x40, 0x5d, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010575 0x02, 0x17, 0xfe, 0xc8, 0x45, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0, 0x18, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010576 0x43, 0x48, 0x2d, 0x93, 0x36, 0xfe, 0x34, 0xf4, 0xfe, 0x00, 0x11, 0xfe,
10577 0x40, 0x10, 0x2d, 0xb4, 0x36, 0xfe, 0x34, 0xf4, 0x04, 0xfe, 0x34, 0x10,
10578 0x2d, 0xfe, 0x0b, 0x00, 0x36, 0x46, 0x63, 0xfe, 0x28, 0x10, 0xfe, 0xc0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010579 0x49, 0xff, 0x02, 0x00, 0x54, 0xb2, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0xfa,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010580 0x18, 0x45, 0xfe, 0x1c, 0xf4, 0x3f, 0xf3, 0xfe, 0x40, 0xf4, 0x96, 0xfe,
10581 0x56, 0xf0, 0xfe, 0x0c, 0x19, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x40, 0xf4,
10582 0x94, 0xf6, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d, 0x21, 0xfe, 0x7f, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010583 0xfe, 0xc8, 0x46, 0xfe, 0x24, 0x13, 0x8c, 0x00, 0x5d, 0x26, 0x21, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010584 0x7e, 0x01, 0xfe, 0xc8, 0x45, 0xfe, 0x14, 0x13, 0x21, 0xfe, 0x80, 0x01,
10585 0xfe, 0x48, 0x45, 0xfa, 0x21, 0xfe, 0x81, 0x01, 0xfe, 0xc8, 0x44, 0x4e,
10586 0x26, 0x02, 0x13, 0x07, 0x02, 0x78, 0x45, 0x50, 0x13, 0x0d, 0x02, 0x14,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010587 0x07, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, 0x0d, 0x01, 0x08, 0x17,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010588 0xfe, 0x82, 0x19, 0x14, 0x1d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x5f,
10589 0xfe, 0x89, 0x49, 0x01, 0x08, 0x02, 0x14, 0x07, 0x01, 0x08, 0x17, 0xc1,
10590 0x14, 0x1d, 0x01, 0x08, 0x17, 0xc1, 0x14, 0x07, 0x01, 0x08, 0x17, 0xc1,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010591 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0xc1, 0x5f, 0xfe, 0x89, 0x4a, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010592 0x08, 0x02, 0x50, 0x02, 0x14, 0x07, 0x01, 0x08, 0x17, 0x74, 0x14, 0x7f,
10593 0x01, 0x08, 0x17, 0x74, 0x14, 0x12, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x89,
10594 0x49, 0x01, 0x08, 0x17, 0x74, 0x14, 0x00, 0x01, 0x08, 0x17, 0x74, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010595 0x89, 0x4a, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x09, 0x49, 0x01, 0x08, 0x17,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010596 0x74, 0x5f, 0xcc, 0x01, 0x08, 0x02, 0x21, 0xe4, 0x09, 0x07, 0xfe, 0x4c,
10597 0x13, 0xc8, 0x20, 0xe4, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x5f, 0xa1, 0x5e,
10598 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xcc, 0xff, 0x02, 0x00, 0x10, 0x2f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010599 0xfe, 0x3e, 0x1a, 0x01, 0x43, 0x09, 0xfe, 0xe3, 0x00, 0xfe, 0x22, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010600 0x16, 0xfe, 0x64, 0x1a, 0x26, 0x20, 0x9e, 0x01, 0x41, 0x21, 0x9e, 0x09,
10601 0x07, 0x5d, 0x01, 0x0c, 0x61, 0x07, 0x44, 0x02, 0x0a, 0x5a, 0x01, 0x18,
10602 0xfe, 0x00, 0x40, 0xaa, 0x09, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010603 0x18, 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x9d, 0x01, 0x18, 0xaa,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010604 0xfe, 0x80, 0xe7, 0x1a, 0x09, 0x1a, 0x5d, 0xfe, 0x45, 0x58, 0x01, 0xfe,
10605 0xb2, 0x16, 0xaa, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0xaa, 0x0a, 0x67, 0x01,
10606 0xa3, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x01, 0xfe, 0x7e, 0x1e, 0xfe, 0x80,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010607 0x4c, 0xfe, 0x49, 0xe4, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, 0x18,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010608 0xfe, 0x80, 0x4c, 0x0a, 0x67, 0x01, 0x5c, 0x02, 0x1c, 0x1a, 0x87, 0x7c,
10609 0xe5, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24, 0x1c, 0xfe, 0x1d,
10610 0xf7, 0x28, 0xb1, 0xfe, 0x04, 0x1b, 0x01, 0xfe, 0x2a, 0x1c, 0xfa, 0xb3,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010611 0x28, 0x7c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x02, 0xc9, 0x2b, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010612 0xf4, 0x1a, 0xfe, 0xfa, 0x10, 0x1c, 0x1a, 0x87, 0x03, 0xfe, 0x64, 0x01,
10613 0xfe, 0x00, 0xf4, 0x24, 0xfe, 0x18, 0x58, 0x03, 0xfe, 0x66, 0x01, 0xfe,
10614 0x19, 0x58, 0xb3, 0x24, 0x01, 0xfe, 0x0e, 0x1f, 0xfe, 0x30, 0xf4, 0x07,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010615 0xfe, 0x3c, 0x50, 0x7c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010616 0xf7, 0x24, 0xb1, 0xfe, 0x50, 0x1b, 0xfe, 0xd4, 0x14, 0x31, 0x02, 0xc9,
10617 0x2b, 0xfe, 0x26, 0x1b, 0xfe, 0xba, 0x10, 0x1c, 0x1a, 0x87, 0xfe, 0x83,
10618 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x54, 0xb1,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010619 0xfe, 0x72, 0x1b, 0xfe, 0xb2, 0x14, 0xfc, 0xb3, 0x54, 0x7c, 0x12, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010620 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00, 0x02, 0xc9, 0x2b, 0xfe, 0x66, 0x1b,
10621 0xfe, 0x8a, 0x10, 0x1c, 0x1a, 0x87, 0x8b, 0x0f, 0xfe, 0x30, 0x90, 0x04,
10622 0xfe, 0xb0, 0x93, 0x3a, 0x0b, 0xfe, 0x18, 0x58, 0xfe, 0x32, 0x90, 0x04,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010623 0xfe, 0xb2, 0x93, 0x3a, 0x0b, 0xfe, 0x19, 0x58, 0x0e, 0xa8, 0xb3, 0x4a,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010624 0x7c, 0x12, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x4a, 0xb1, 0xfe, 0xc6,
10625 0x1b, 0xfe, 0x5e, 0x14, 0x31, 0x02, 0xc9, 0x2b, 0xfe, 0x96, 0x1b, 0x5c,
10626 0xfe, 0x02, 0xf6, 0x1a, 0x87, 0xfe, 0x18, 0xfe, 0x6a, 0xfe, 0x19, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010627 0x6b, 0x01, 0xfe, 0x1e, 0x1f, 0xfe, 0x1d, 0xf7, 0x65, 0xb1, 0xfe, 0xee,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010628 0x1b, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0xb3, 0x65, 0x3e, 0xfe, 0x83,
10629 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x1a, 0xfe, 0x81, 0xe7, 0x1a,
10630 0x15, 0xfe, 0xdd, 0x00, 0x7a, 0x30, 0x02, 0x7a, 0x30, 0xfe, 0x12, 0x45,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010631 0x2b, 0xfe, 0xdc, 0x1b, 0x1f, 0x07, 0x47, 0xb5, 0xc3, 0x05, 0x35, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010632 0x39, 0xf0, 0x75, 0x26, 0x02, 0xfe, 0x7e, 0x18, 0x23, 0x1d, 0x36, 0x13,
10633 0x11, 0x02, 0x87, 0x03, 0xe3, 0x23, 0x07, 0xfe, 0xef, 0x12, 0xfe, 0xe1,
10634 0x10, 0x90, 0x34, 0x60, 0xfe, 0x02, 0x80, 0x09, 0x56, 0xfe, 0x3c, 0x13,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010635 0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x51, 0xfe, 0x06, 0x83, 0x0a, 0x5a,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010636 0x01, 0x18, 0xcb, 0xfe, 0x3e, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48,
10637 0x01, 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f,
10638 0x89, 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x4c, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010639 0x85, 0xfe, 0x16, 0x10, 0x09, 0x9b, 0x4e, 0xfe, 0x40, 0x14, 0xfe, 0x24,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010640 0x12, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x52, 0x1c, 0x1c, 0x0d,
10641 0x02, 0xfe, 0x9c, 0xe7, 0x0d, 0x19, 0xfe, 0x15, 0x00, 0x40, 0x8d, 0x30,
10642 0x01, 0xf4, 0x1c, 0x07, 0x02, 0x51, 0xfe, 0x06, 0x83, 0xfe, 0x18, 0x80,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010643 0x61, 0x28, 0x44, 0x15, 0x56, 0x01, 0x85, 0x1c, 0x07, 0x02, 0xfe, 0x38,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010644 0x90, 0xfe, 0xba, 0x90, 0x91, 0xde, 0x7e, 0xdf, 0xfe, 0x48, 0x55, 0x31,
10645 0xfe, 0xc9, 0x55, 0x02, 0x21, 0xb9, 0x88, 0x20, 0xb9, 0x02, 0x0a, 0xba,
10646 0x01, 0x18, 0xfe, 0x41, 0x48, 0x0a, 0x57, 0x01, 0x18, 0xfe, 0x49, 0x44,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010647 0x1b, 0xfe, 0x1e, 0x1d, 0x88, 0x89, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x09,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010648 0x1a, 0xa4, 0x0a, 0x67, 0x01, 0xa3, 0x0a, 0x57, 0x01, 0x18, 0x88, 0x89,
10649 0x02, 0xfe, 0x4e, 0xe4, 0x1d, 0x7b, 0xfe, 0x52, 0x1d, 0x03, 0xfe, 0x90,
10650 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xdd, 0x7b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010651 0xfe, 0x64, 0x1d, 0x03, 0xfe, 0x92, 0x00, 0xd1, 0x12, 0xfe, 0x1a, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010652 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x7b, 0xfe, 0x76, 0x1d, 0x03, 0xfe,
10653 0x94, 0x00, 0xd1, 0x24, 0xfe, 0x08, 0x10, 0x03, 0xfe, 0x96, 0x00, 0xd1,
10654 0x63, 0xfe, 0x4e, 0x45, 0x83, 0xca, 0xff, 0x04, 0x68, 0x54, 0xfe, 0xf1,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010655 0x10, 0x23, 0x49, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010656 0xfe, 0x1a, 0xf4, 0xfe, 0x00, 0x04, 0x83, 0xb2, 0x1d, 0x48, 0xfe, 0xaa,
10657 0x1d, 0x13, 0x1d, 0x02, 0x09, 0x92, 0xfe, 0x5a, 0xf0, 0xfe, 0xba, 0x1d,
10658 0x2e, 0x93, 0xfe, 0x34, 0x10, 0x09, 0x12, 0xfe, 0x5a, 0xf0, 0xfe, 0xc8,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010659 0x1d, 0x2e, 0xb4, 0xfe, 0x26, 0x10, 0x09, 0x1d, 0x36, 0x2e, 0x63, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010660 0x1a, 0x10, 0x09, 0x0d, 0x36, 0x2e, 0x94, 0xf2, 0x09, 0x07, 0x36, 0x2e,
10661 0x95, 0xa1, 0xc8, 0x02, 0x1f, 0x93, 0x01, 0x42, 0xfe, 0x04, 0xfe, 0x99,
10662 0x03, 0x9c, 0x8b, 0x02, 0x2a, 0xfe, 0x1c, 0x1e, 0xfe, 0x14, 0xf0, 0x08,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010663 0x2f, 0xfe, 0x0c, 0x1e, 0x2a, 0xfe, 0x1c, 0x1e, 0x8f, 0xfe, 0x1c, 0x1e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010664 0xfe, 0x82, 0xf0, 0xfe, 0x10, 0x1e, 0x02, 0x0f, 0x3f, 0x04, 0xfe, 0x80,
10665 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x18, 0x80, 0x04, 0xfe, 0x98,
10666 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x02, 0x80, 0x04, 0xfe, 0x82,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010667 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x80, 0x04, 0xfe, 0x86,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010668 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x1b, 0x80, 0x04, 0xfe, 0x9b,
10669 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x04, 0x80, 0x04, 0xfe, 0x84,
10670 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x80, 0x80, 0x04, 0xfe, 0x80,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010671 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x19, 0x81, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010672 0xfe, 0x99, 0x83, 0xfe, 0xca, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06,
10673 0x83, 0x04, 0xfe, 0x86, 0x83, 0xfe, 0xce, 0x47, 0x0b, 0x0e, 0x02, 0x0f,
10674 0xfe, 0x2c, 0x90, 0x04, 0xfe, 0xac, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010675 0xfe, 0xae, 0x90, 0x04, 0xfe, 0xae, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010676 0xfe, 0x08, 0x90, 0x04, 0xfe, 0x88, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f,
10677 0xfe, 0x8a, 0x90, 0x04, 0xfe, 0x8a, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
10678 0xfe, 0x0c, 0x90, 0x04, 0xfe, 0x8c, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010679 0xfe, 0x8e, 0x90, 0x04, 0xfe, 0x8e, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010680 0xfe, 0x3c, 0x90, 0x04, 0xfe, 0xbc, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x8b,
10681 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b, 0x77, 0x0e,
10682 0xa8, 0x02, 0xff, 0x66, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070010683};
10684
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010685static unsigned short _adv_asc38C1600_size = sizeof(_adv_asc38C1600_buf); /* 0x1673 */
10686static ADV_DCNT _adv_asc38C1600_chksum = 0x0604EF77UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070010687
Linus Torvalds1da177e2005-04-16 15:20:36 -070010688/*
10689 * EEPROM Configuration.
10690 *
10691 * All drivers should use this structure to set the default EEPROM
10692 * configuration. The BIOS now uses this structure when it is built.
10693 * Additional structure information can be found in a_condor.h where
10694 * the structure is defined.
10695 *
10696 * The *_Field_IsChar structs are needed to correct for endianness.
10697 * These values are read from the board 16 bits at a time directly
10698 * into the structs. Because some fields are char, the values will be
10699 * in the wrong order. The *_Field_IsChar tells when to flip the
10700 * bytes. Data read and written to PCI memory is automatically swapped
10701 * on big-endian platforms so char fields read as words are actually being
10702 * unswapped on big-endian platforms.
10703 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010704static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010705 ADV_EEPROM_BIOS_ENABLE, /* cfg_lsw */
10706 0x0000, /* cfg_msw */
10707 0xFFFF, /* disc_enable */
10708 0xFFFF, /* wdtr_able */
10709 0xFFFF, /* sdtr_able */
10710 0xFFFF, /* start_motor */
10711 0xFFFF, /* tagqng_able */
10712 0xFFFF, /* bios_scan */
10713 0, /* scam_tolerant */
10714 7, /* adapter_scsi_id */
10715 0, /* bios_boot_delay */
10716 3, /* scsi_reset_delay */
10717 0, /* bios_id_lun */
10718 0, /* termination */
10719 0, /* reserved1 */
10720 0xFFE7, /* bios_ctrl */
10721 0xFFFF, /* ultra_able */
10722 0, /* reserved2 */
10723 ASC_DEF_MAX_HOST_QNG, /* max_host_qng */
10724 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
10725 0, /* dvc_cntl */
10726 0, /* bug_fix */
10727 0, /* serial_number_word1 */
10728 0, /* serial_number_word2 */
10729 0, /* serial_number_word3 */
10730 0, /* check_sum */
10731 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
10732 , /* oem_name[16] */
10733 0, /* dvc_err_code */
10734 0, /* adv_err_code */
10735 0, /* adv_err_addr */
10736 0, /* saved_dvc_err_code */
10737 0, /* saved_adv_err_code */
10738 0, /* saved_adv_err_addr */
10739 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070010740};
10741
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010742static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010743 0, /* cfg_lsw */
10744 0, /* cfg_msw */
10745 0, /* -disc_enable */
10746 0, /* wdtr_able */
10747 0, /* sdtr_able */
10748 0, /* start_motor */
10749 0, /* tagqng_able */
10750 0, /* bios_scan */
10751 0, /* scam_tolerant */
10752 1, /* adapter_scsi_id */
10753 1, /* bios_boot_delay */
10754 1, /* scsi_reset_delay */
10755 1, /* bios_id_lun */
10756 1, /* termination */
10757 1, /* reserved1 */
10758 0, /* bios_ctrl */
10759 0, /* ultra_able */
10760 0, /* reserved2 */
10761 1, /* max_host_qng */
10762 1, /* max_dvc_qng */
10763 0, /* dvc_cntl */
10764 0, /* bug_fix */
10765 0, /* serial_number_word1 */
10766 0, /* serial_number_word2 */
10767 0, /* serial_number_word3 */
10768 0, /* check_sum */
10769 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
10770 , /* oem_name[16] */
10771 0, /* dvc_err_code */
10772 0, /* adv_err_code */
10773 0, /* adv_err_addr */
10774 0, /* saved_dvc_err_code */
10775 0, /* saved_adv_err_code */
10776 0, /* saved_adv_err_addr */
10777 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070010778};
10779
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010780static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010781 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
10782 0x0000, /* 01 cfg_msw */
10783 0xFFFF, /* 02 disc_enable */
10784 0xFFFF, /* 03 wdtr_able */
10785 0x4444, /* 04 sdtr_speed1 */
10786 0xFFFF, /* 05 start_motor */
10787 0xFFFF, /* 06 tagqng_able */
10788 0xFFFF, /* 07 bios_scan */
10789 0, /* 08 scam_tolerant */
10790 7, /* 09 adapter_scsi_id */
10791 0, /* bios_boot_delay */
10792 3, /* 10 scsi_reset_delay */
10793 0, /* bios_id_lun */
10794 0, /* 11 termination_se */
10795 0, /* termination_lvd */
10796 0xFFE7, /* 12 bios_ctrl */
10797 0x4444, /* 13 sdtr_speed2 */
10798 0x4444, /* 14 sdtr_speed3 */
10799 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
10800 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
10801 0, /* 16 dvc_cntl */
10802 0x4444, /* 17 sdtr_speed4 */
10803 0, /* 18 serial_number_word1 */
10804 0, /* 19 serial_number_word2 */
10805 0, /* 20 serial_number_word3 */
10806 0, /* 21 check_sum */
10807 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
10808 , /* 22-29 oem_name[16] */
10809 0, /* 30 dvc_err_code */
10810 0, /* 31 adv_err_code */
10811 0, /* 32 adv_err_addr */
10812 0, /* 33 saved_dvc_err_code */
10813 0, /* 34 saved_adv_err_code */
10814 0, /* 35 saved_adv_err_addr */
10815 0, /* 36 reserved */
10816 0, /* 37 reserved */
10817 0, /* 38 reserved */
10818 0, /* 39 reserved */
10819 0, /* 40 reserved */
10820 0, /* 41 reserved */
10821 0, /* 42 reserved */
10822 0, /* 43 reserved */
10823 0, /* 44 reserved */
10824 0, /* 45 reserved */
10825 0, /* 46 reserved */
10826 0, /* 47 reserved */
10827 0, /* 48 reserved */
10828 0, /* 49 reserved */
10829 0, /* 50 reserved */
10830 0, /* 51 reserved */
10831 0, /* 52 reserved */
10832 0, /* 53 reserved */
10833 0, /* 54 reserved */
10834 0, /* 55 reserved */
10835 0, /* 56 cisptr_lsw */
10836 0, /* 57 cisprt_msw */
10837 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
10838 PCI_DEVICE_ID_38C0800_REV1, /* 59 subsysid */
10839 0, /* 60 reserved */
10840 0, /* 61 reserved */
10841 0, /* 62 reserved */
10842 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070010843};
10844
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010845static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010846 0, /* 00 cfg_lsw */
10847 0, /* 01 cfg_msw */
10848 0, /* 02 disc_enable */
10849 0, /* 03 wdtr_able */
10850 0, /* 04 sdtr_speed1 */
10851 0, /* 05 start_motor */
10852 0, /* 06 tagqng_able */
10853 0, /* 07 bios_scan */
10854 0, /* 08 scam_tolerant */
10855 1, /* 09 adapter_scsi_id */
10856 1, /* bios_boot_delay */
10857 1, /* 10 scsi_reset_delay */
10858 1, /* bios_id_lun */
10859 1, /* 11 termination_se */
10860 1, /* termination_lvd */
10861 0, /* 12 bios_ctrl */
10862 0, /* 13 sdtr_speed2 */
10863 0, /* 14 sdtr_speed3 */
10864 1, /* 15 max_host_qng */
10865 1, /* max_dvc_qng */
10866 0, /* 16 dvc_cntl */
10867 0, /* 17 sdtr_speed4 */
10868 0, /* 18 serial_number_word1 */
10869 0, /* 19 serial_number_word2 */
10870 0, /* 20 serial_number_word3 */
10871 0, /* 21 check_sum */
10872 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
10873 , /* 22-29 oem_name[16] */
10874 0, /* 30 dvc_err_code */
10875 0, /* 31 adv_err_code */
10876 0, /* 32 adv_err_addr */
10877 0, /* 33 saved_dvc_err_code */
10878 0, /* 34 saved_adv_err_code */
10879 0, /* 35 saved_adv_err_addr */
10880 0, /* 36 reserved */
10881 0, /* 37 reserved */
10882 0, /* 38 reserved */
10883 0, /* 39 reserved */
10884 0, /* 40 reserved */
10885 0, /* 41 reserved */
10886 0, /* 42 reserved */
10887 0, /* 43 reserved */
10888 0, /* 44 reserved */
10889 0, /* 45 reserved */
10890 0, /* 46 reserved */
10891 0, /* 47 reserved */
10892 0, /* 48 reserved */
10893 0, /* 49 reserved */
10894 0, /* 50 reserved */
10895 0, /* 51 reserved */
10896 0, /* 52 reserved */
10897 0, /* 53 reserved */
10898 0, /* 54 reserved */
10899 0, /* 55 reserved */
10900 0, /* 56 cisptr_lsw */
10901 0, /* 57 cisprt_msw */
10902 0, /* 58 subsysvid */
10903 0, /* 59 subsysid */
10904 0, /* 60 reserved */
10905 0, /* 61 reserved */
10906 0, /* 62 reserved */
10907 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070010908};
10909
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010910static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010911 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
10912 0x0000, /* 01 cfg_msw */
10913 0xFFFF, /* 02 disc_enable */
10914 0xFFFF, /* 03 wdtr_able */
10915 0x5555, /* 04 sdtr_speed1 */
10916 0xFFFF, /* 05 start_motor */
10917 0xFFFF, /* 06 tagqng_able */
10918 0xFFFF, /* 07 bios_scan */
10919 0, /* 08 scam_tolerant */
10920 7, /* 09 adapter_scsi_id */
10921 0, /* bios_boot_delay */
10922 3, /* 10 scsi_reset_delay */
10923 0, /* bios_id_lun */
10924 0, /* 11 termination_se */
10925 0, /* termination_lvd */
10926 0xFFE7, /* 12 bios_ctrl */
10927 0x5555, /* 13 sdtr_speed2 */
10928 0x5555, /* 14 sdtr_speed3 */
10929 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
10930 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
10931 0, /* 16 dvc_cntl */
10932 0x5555, /* 17 sdtr_speed4 */
10933 0, /* 18 serial_number_word1 */
10934 0, /* 19 serial_number_word2 */
10935 0, /* 20 serial_number_word3 */
10936 0, /* 21 check_sum */
10937 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
10938 , /* 22-29 oem_name[16] */
10939 0, /* 30 dvc_err_code */
10940 0, /* 31 adv_err_code */
10941 0, /* 32 adv_err_addr */
10942 0, /* 33 saved_dvc_err_code */
10943 0, /* 34 saved_adv_err_code */
10944 0, /* 35 saved_adv_err_addr */
10945 0, /* 36 reserved */
10946 0, /* 37 reserved */
10947 0, /* 38 reserved */
10948 0, /* 39 reserved */
10949 0, /* 40 reserved */
10950 0, /* 41 reserved */
10951 0, /* 42 reserved */
10952 0, /* 43 reserved */
10953 0, /* 44 reserved */
10954 0, /* 45 reserved */
10955 0, /* 46 reserved */
10956 0, /* 47 reserved */
10957 0, /* 48 reserved */
10958 0, /* 49 reserved */
10959 0, /* 50 reserved */
10960 0, /* 51 reserved */
10961 0, /* 52 reserved */
10962 0, /* 53 reserved */
10963 0, /* 54 reserved */
10964 0, /* 55 reserved */
10965 0, /* 56 cisptr_lsw */
10966 0, /* 57 cisprt_msw */
10967 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
10968 PCI_DEVICE_ID_38C1600_REV1, /* 59 subsysid */
10969 0, /* 60 reserved */
10970 0, /* 61 reserved */
10971 0, /* 62 reserved */
10972 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070010973};
10974
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010975static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010976 0, /* 00 cfg_lsw */
10977 0, /* 01 cfg_msw */
10978 0, /* 02 disc_enable */
10979 0, /* 03 wdtr_able */
10980 0, /* 04 sdtr_speed1 */
10981 0, /* 05 start_motor */
10982 0, /* 06 tagqng_able */
10983 0, /* 07 bios_scan */
10984 0, /* 08 scam_tolerant */
10985 1, /* 09 adapter_scsi_id */
10986 1, /* bios_boot_delay */
10987 1, /* 10 scsi_reset_delay */
10988 1, /* bios_id_lun */
10989 1, /* 11 termination_se */
10990 1, /* termination_lvd */
10991 0, /* 12 bios_ctrl */
10992 0, /* 13 sdtr_speed2 */
10993 0, /* 14 sdtr_speed3 */
10994 1, /* 15 max_host_qng */
10995 1, /* max_dvc_qng */
10996 0, /* 16 dvc_cntl */
10997 0, /* 17 sdtr_speed4 */
10998 0, /* 18 serial_number_word1 */
10999 0, /* 19 serial_number_word2 */
11000 0, /* 20 serial_number_word3 */
11001 0, /* 21 check_sum */
11002 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
11003 , /* 22-29 oem_name[16] */
11004 0, /* 30 dvc_err_code */
11005 0, /* 31 adv_err_code */
11006 0, /* 32 adv_err_addr */
11007 0, /* 33 saved_dvc_err_code */
11008 0, /* 34 saved_adv_err_code */
11009 0, /* 35 saved_adv_err_addr */
11010 0, /* 36 reserved */
11011 0, /* 37 reserved */
11012 0, /* 38 reserved */
11013 0, /* 39 reserved */
11014 0, /* 40 reserved */
11015 0, /* 41 reserved */
11016 0, /* 42 reserved */
11017 0, /* 43 reserved */
11018 0, /* 44 reserved */
11019 0, /* 45 reserved */
11020 0, /* 46 reserved */
11021 0, /* 47 reserved */
11022 0, /* 48 reserved */
11023 0, /* 49 reserved */
11024 0, /* 50 reserved */
11025 0, /* 51 reserved */
11026 0, /* 52 reserved */
11027 0, /* 53 reserved */
11028 0, /* 54 reserved */
11029 0, /* 55 reserved */
11030 0, /* 56 cisptr_lsw */
11031 0, /* 57 cisprt_msw */
11032 0, /* 58 subsysvid */
11033 0, /* 59 subsysid */
11034 0, /* 60 reserved */
11035 0, /* 61 reserved */
11036 0, /* 62 reserved */
11037 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011038};
11039
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060011040#ifdef CONFIG_PCI
Linus Torvalds1da177e2005-04-16 15:20:36 -070011041/*
11042 * Initialize the ADV_DVC_VAR structure.
11043 *
11044 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
11045 *
11046 * For a non-fatal error return a warning code. If there are no warnings
11047 * then 0 is returned.
11048 */
Matthew Wilcox394dbf32007-07-26 11:56:40 -040011049static int __devinit
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060011050AdvInitGetConfig(struct pci_dev *pdev, asc_board_t *boardp)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011051{
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060011052 ADV_DVC_VAR *asc_dvc = &boardp->dvc_var.adv_dvc_var;
Matthew Wilcox9649af32007-07-26 21:51:47 -060011053 unsigned short warn_code = 0;
11054 AdvPortAddr iop_base = asc_dvc->iop_base;
Matthew Wilcox9649af32007-07-26 21:51:47 -060011055 u16 cmd;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011056 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011057
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011058 asc_dvc->err_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011059
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011060 /*
11061 * Save the state of the PCI Configuration Command Register
11062 * "Parity Error Response Control" Bit. If the bit is clear (0),
11063 * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore
11064 * DMA parity errors.
11065 */
11066 asc_dvc->cfg->control_flag = 0;
Matthew Wilcox9649af32007-07-26 21:51:47 -060011067 pci_read_config_word(pdev, PCI_COMMAND, &cmd);
11068 if ((cmd & PCI_COMMAND_PARITY) == 0)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011069 asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011070
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011071 asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) |
11072 ADV_LIB_VERSION_MINOR;
11073 asc_dvc->cfg->chip_version =
11074 AdvGetChipVersion(iop_base, asc_dvc->bus_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011075
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011076 ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: 0x%x 0x%x\n",
11077 (ushort)AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
11078 (ushort)ADV_CHIP_ID_BYTE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011079
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011080 ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: 0x%x 0x%x\n",
11081 (ushort)AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
11082 (ushort)ADV_CHIP_ID_WORD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011083
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011084 /*
11085 * Reset the chip to start and allow register writes.
11086 */
11087 if (AdvFindSignature(iop_base) == 0) {
11088 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
11089 return ADV_ERROR;
11090 } else {
11091 /*
11092 * The caller must set 'chip_type' to a valid setting.
11093 */
11094 if (asc_dvc->chip_type != ADV_CHIP_ASC3550 &&
11095 asc_dvc->chip_type != ADV_CHIP_ASC38C0800 &&
11096 asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
11097 asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
11098 return ADV_ERROR;
11099 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011100
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011101 /*
11102 * Reset Chip.
11103 */
11104 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
11105 ADV_CTRL_REG_CMD_RESET);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060011106 mdelay(100);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011107 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
11108 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011109
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011110 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
Matthew Wilcox9649af32007-07-26 21:51:47 -060011111 status = AdvInitFrom38C1600EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011112 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
Matthew Wilcox9649af32007-07-26 21:51:47 -060011113 status = AdvInitFrom38C0800EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011114 } else {
Matthew Wilcox9649af32007-07-26 21:51:47 -060011115 status = AdvInitFrom3550EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011116 }
11117 warn_code |= status;
11118 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011119
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060011120 if (warn_code != 0) {
11121 ASC_PRINT2("AdvInitGetConfig: board %d: warning: 0x%x\n",
11122 boardp->id, warn_code);
11123 }
11124
11125 if (asc_dvc->err_code) {
11126 ASC_PRINT2("AdvInitGetConfig: board %d error: err_code 0x%x\n",
11127 boardp->id, asc_dvc->err_code);
11128 }
11129
11130 return asc_dvc->err_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011131}
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060011132#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070011133
Matthew Wilcoxa9f4a592007-09-09 08:56:27 -060011134static void AdvBuildCarrierFreelist(struct adv_dvc_var *asc_dvc)
11135{
11136 ADV_CARR_T *carrp;
11137 ADV_SDCNT buf_size;
11138 ADV_PADDR carr_paddr;
11139
11140 BUG_ON(!asc_dvc->carrier_buf);
11141
11142 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
11143 asc_dvc->carr_freelist = NULL;
11144 if (carrp == asc_dvc->carrier_buf) {
11145 buf_size = ADV_CARRIER_BUFSIZE;
11146 } else {
11147 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
11148 }
11149
11150 do {
11151 /* Get physical address of the carrier 'carrp'. */
11152 ADV_DCNT contig_len = sizeof(ADV_CARR_T);
11153 carr_paddr = cpu_to_le32(DvcGetPhyAddr(asc_dvc, NULL,
11154 (uchar *)carrp,
11155 (ADV_SDCNT *)&contig_len,
11156 ADV_IS_CARRIER_FLAG));
11157
11158 buf_size -= sizeof(ADV_CARR_T);
11159
11160 /*
11161 * If the current carrier is not physically contiguous, then
11162 * maybe there was a page crossing. Try the next carrier
11163 * aligned start address.
11164 */
11165 if (contig_len < sizeof(ADV_CARR_T)) {
11166 carrp++;
11167 continue;
11168 }
11169
11170 carrp->carr_pa = carr_paddr;
11171 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
11172
11173 /*
11174 * Insert the carrier at the beginning of the freelist.
11175 */
11176 carrp->next_vpa =
11177 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
11178 asc_dvc->carr_freelist = carrp;
11179
11180 carrp++;
11181 } while (buf_size > 0);
11182}
11183
Linus Torvalds1da177e2005-04-16 15:20:36 -070011184/*
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060011185 * Load the Microcode
11186 *
11187 * Write the microcode image to RISC memory starting at address 0.
11188 *
11189 * The microcode is stored compressed in the following format:
11190 *
11191 * 254 word (508 byte) table indexed by byte code followed
11192 * by the following byte codes:
11193 *
11194 * 1-Byte Code:
11195 * 00: Emit word 0 in table.
11196 * 01: Emit word 1 in table.
11197 * .
11198 * FD: Emit word 253 in table.
11199 *
11200 * Multi-Byte Code:
11201 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
11202 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
11203 *
11204 * Returns 0 or an error if the checksum doesn't match
11205 */
11206static int AdvLoadMicrocode(AdvPortAddr iop_base, unsigned char *buf, int size,
11207 int memsize, int chksum)
11208{
11209 int i, j, end, len = 0;
11210 ADV_DCNT sum;
11211
11212 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
11213
11214 for (i = 253 * 2; i < size; i++) {
11215 if (buf[i] == 0xff) {
11216 unsigned short word = (buf[i + 3] << 8) | buf[i + 2];
11217 for (j = 0; j < buf[i + 1]; j++) {
11218 AdvWriteWordAutoIncLram(iop_base, word);
11219 len += 2;
11220 }
11221 i += 3;
11222 } else if (buf[i] == 0xfe) {
11223 unsigned short word = (buf[i + 2] << 8) | buf[i + 1];
11224 AdvWriteWordAutoIncLram(iop_base, word);
11225 i += 2;
11226 len += 2;
11227 } else {
11228 unsigned char off = buf[i] * 2;
11229 unsigned short word = (buf[off + 1] << 8) | buf[off];
11230 AdvWriteWordAutoIncLram(iop_base, word);
11231 len += 2;
11232 }
11233 }
11234
11235 end = len;
11236
11237 while (len < memsize) {
11238 AdvWriteWordAutoIncLram(iop_base, 0);
11239 len += 2;
11240 }
11241
11242 /* Verify the microcode checksum. */
11243 sum = 0;
11244 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
11245
11246 for (len = 0; len < end; len += 2) {
11247 sum += AdvReadWordAutoIncLram(iop_base);
11248 }
11249
11250 if (sum != chksum)
11251 return ASC_IERR_MCODE_CHKSUM;
11252
11253 return 0;
11254}
11255
11256/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070011257 * Initialize the ASC-3550.
11258 *
11259 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
11260 *
11261 * For a non-fatal error return a warning code. If there are no warnings
11262 * then 0 is returned.
11263 *
11264 * Needed after initialization for error recovery.
11265 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011266static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011267{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011268 AdvPortAddr iop_base;
11269 ushort warn_code;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011270 int begin_addr;
11271 int end_addr;
11272 ushort code_sum;
11273 int word;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011274 int i;
11275 ushort scsi_cfg1;
11276 uchar tid;
11277 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
11278 ushort wdtr_able = 0, sdtr_able, tagqng_able;
11279 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070011280
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011281 /* If there is already an error, don't continue. */
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060011282 if (asc_dvc->err_code != 0)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011283 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011284
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011285 /*
11286 * The caller must set 'chip_type' to ADV_CHIP_ASC3550.
11287 */
11288 if (asc_dvc->chip_type != ADV_CHIP_ASC3550) {
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060011289 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011290 return ADV_ERROR;
11291 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011292
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011293 warn_code = 0;
11294 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011295
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011296 /*
11297 * Save the RISC memory BIOS region before writing the microcode.
11298 * The BIOS may already be loaded and using its RISC LRAM region
11299 * so its region must be saved and restored.
11300 *
11301 * Note: This code makes the assumption, which is currently true,
11302 * that a chip reset does not clear RISC LRAM.
11303 */
11304 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
11305 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
11306 bios_mem[i]);
11307 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011308
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011309 /*
11310 * Save current per TID negotiated values.
11311 */
11312 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == 0x55AA) {
11313 ushort bios_version, major, minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011314
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011315 bios_version =
11316 bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM) / 2];
11317 major = (bios_version >> 12) & 0xF;
11318 minor = (bios_version >> 8) & 0xF;
11319 if (major < 3 || (major == 3 && minor == 1)) {
11320 /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
11321 AdvReadWordLram(iop_base, 0x120, wdtr_able);
11322 } else {
11323 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
11324 }
11325 }
11326 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
11327 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
11328 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
11329 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
11330 max_cmd[tid]);
11331 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011332
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060011333 asc_dvc->err_code = AdvLoadMicrocode(iop_base, _adv_asc3550_buf,
11334 _adv_asc3550_size, ADV_3550_MEMSIZE,
11335 _adv_asc3550_chksum);
11336 if (asc_dvc->err_code)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011337 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011338
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011339 /*
11340 * Restore the RISC memory BIOS region.
11341 */
11342 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
11343 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
11344 bios_mem[i]);
11345 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011346
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011347 /*
11348 * Calculate and write the microcode code checksum to the microcode
11349 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
11350 */
11351 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
11352 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
11353 code_sum = 0;
11354 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
11355 for (word = begin_addr; word < end_addr; word += 2) {
11356 code_sum += AdvReadWordAutoIncLram(iop_base);
11357 }
11358 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011359
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011360 /*
11361 * Read and save microcode version and date.
11362 */
11363 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
11364 asc_dvc->cfg->mcode_date);
11365 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
11366 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011367
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011368 /*
11369 * Set the chip type to indicate the ASC3550.
11370 */
11371 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011372
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011373 /*
11374 * If the PCI Configuration Command Register "Parity Error Response
11375 * Control" Bit was clear (0), then set the microcode variable
11376 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
11377 * to ignore DMA parity errors.
11378 */
11379 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
11380 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
11381 word |= CONTROL_FLAG_IGNORE_PERR;
11382 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
11383 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011384
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011385 /*
11386 * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
11387 * threshold of 128 bytes. This register is only accessible to the host.
11388 */
11389 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
11390 START_CTL_EMFU | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011391
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011392 /*
11393 * Microcode operating variables for WDTR, SDTR, and command tag
Matthew Wilcox47d853c2007-07-26 11:41:33 -040011394 * queuing will be set in slave_configure() based on what a
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011395 * device reports it is capable of in Inquiry byte 7.
11396 *
11397 * If SCSI Bus Resets have been disabled, then directly set
11398 * SDTR and WDTR from the EEPROM configuration. This will allow
11399 * the BIOS and warm boot to work without a SCSI bus hang on
11400 * the Inquiry caused by host and target mismatched DTR values.
11401 * Without the SCSI Bus Reset, before an Inquiry a device can't
11402 * be assumed to be in Asynchronous, Narrow mode.
11403 */
11404 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
11405 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
11406 asc_dvc->wdtr_able);
11407 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
11408 asc_dvc->sdtr_able);
11409 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011410
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011411 /*
11412 * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
11413 * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
11414 * bitmask. These values determine the maximum SDTR speed negotiated
11415 * with a device.
11416 *
11417 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
11418 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
11419 * without determining here whether the device supports SDTR.
11420 *
11421 * 4-bit speed SDTR speed name
11422 * =========== ===============
11423 * 0000b (0x0) SDTR disabled
11424 * 0001b (0x1) 5 Mhz
11425 * 0010b (0x2) 10 Mhz
11426 * 0011b (0x3) 20 Mhz (Ultra)
11427 * 0100b (0x4) 40 Mhz (LVD/Ultra2)
11428 * 0101b (0x5) 80 Mhz (LVD2/Ultra3)
11429 * 0110b (0x6) Undefined
11430 * .
11431 * 1111b (0xF) Undefined
11432 */
11433 word = 0;
11434 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
11435 if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) {
11436 /* Set Ultra speed for TID 'tid'. */
11437 word |= (0x3 << (4 * (tid % 4)));
11438 } else {
11439 /* Set Fast speed for TID 'tid'. */
11440 word |= (0x2 << (4 * (tid % 4)));
11441 }
11442 if (tid == 3) { /* Check if done with sdtr_speed1. */
11443 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
11444 word = 0;
11445 } else if (tid == 7) { /* Check if done with sdtr_speed2. */
11446 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
11447 word = 0;
11448 } else if (tid == 11) { /* Check if done with sdtr_speed3. */
11449 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
11450 word = 0;
11451 } else if (tid == 15) { /* Check if done with sdtr_speed4. */
11452 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
11453 /* End of loop. */
11454 }
11455 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011456
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011457 /*
11458 * Set microcode operating variable for the disconnect per TID bitmask.
11459 */
11460 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
11461 asc_dvc->cfg->disc_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011462
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011463 /*
11464 * Set SCSI_CFG0 Microcode Default Value.
11465 *
11466 * The microcode will set the SCSI_CFG0 register using this value
11467 * after it is started below.
11468 */
11469 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
11470 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
11471 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011472
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011473 /*
11474 * Determine SCSI_CFG1 Microcode Default Value.
11475 *
11476 * The microcode will set the SCSI_CFG1 register using this value
11477 * after it is started below.
11478 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011479
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011480 /* Read current SCSI_CFG1 Register value. */
11481 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011482
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011483 /*
11484 * If all three connectors are in use, return an error.
11485 */
11486 if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
11487 (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) {
11488 asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
11489 return ADV_ERROR;
11490 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011491
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011492 /*
11493 * If the internal narrow cable is reversed all of the SCSI_CTRL
11494 * register signals will be set. Check for and return an error if
11495 * this condition is found.
11496 */
11497 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
11498 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
11499 return ADV_ERROR;
11500 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011501
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011502 /*
11503 * If this is a differential board and a single-ended device
11504 * is attached to one of the connectors, return an error.
11505 */
11506 if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) {
11507 asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE;
11508 return ADV_ERROR;
11509 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011510
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011511 /*
11512 * If automatic termination control is enabled, then set the
11513 * termination value based on a table listed in a_condor.h.
11514 *
11515 * If manual termination was specified with an EEPROM setting
11516 * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
11517 * is ready to be 'ored' into SCSI_CFG1.
11518 */
11519 if (asc_dvc->cfg->termination == 0) {
11520 /*
11521 * The software always controls termination by setting TERM_CTL_SEL.
11522 * If TERM_CTL_SEL were set to 0, the hardware would set termination.
11523 */
11524 asc_dvc->cfg->termination |= TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011525
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011526 switch (scsi_cfg1 & CABLE_DETECT) {
11527 /* TERM_CTL_H: on, TERM_CTL_L: on */
11528 case 0x3:
11529 case 0x7:
11530 case 0xB:
11531 case 0xD:
11532 case 0xE:
11533 case 0xF:
11534 asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L);
11535 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011536
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011537 /* TERM_CTL_H: on, TERM_CTL_L: off */
11538 case 0x1:
11539 case 0x5:
11540 case 0x9:
11541 case 0xA:
11542 case 0xC:
11543 asc_dvc->cfg->termination |= TERM_CTL_H;
11544 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011545
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011546 /* TERM_CTL_H: off, TERM_CTL_L: off */
11547 case 0x2:
11548 case 0x6:
11549 break;
11550 }
11551 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011552
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011553 /*
11554 * Clear any set TERM_CTL_H and TERM_CTL_L bits.
11555 */
11556 scsi_cfg1 &= ~TERM_CTL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011557
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011558 /*
11559 * Invert the TERM_CTL_H and TERM_CTL_L bits and then
11560 * set 'scsi_cfg1'. The TERM_POL bit does not need to be
11561 * referenced, because the hardware internally inverts
11562 * the Termination High and Low bits if TERM_POL is set.
11563 */
11564 scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
Linus Torvalds1da177e2005-04-16 15:20:36 -070011565
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011566 /*
11567 * Set SCSI_CFG1 Microcode Default Value
11568 *
11569 * Set filter value and possibly modified termination control
11570 * bits in the Microcode SCSI_CFG1 Register Value.
11571 *
11572 * The microcode will set the SCSI_CFG1 register using this value
11573 * after it is started below.
11574 */
11575 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
11576 FLTR_DISABLE | scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011577
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011578 /*
11579 * Set MEM_CFG Microcode Default Value
11580 *
11581 * The microcode will set the MEM_CFG register using this value
11582 * after it is started below.
11583 *
11584 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
11585 * are defined.
11586 *
11587 * ASC-3550 has 8KB internal memory.
11588 */
11589 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
11590 BIOS_EN | RAM_SZ_8KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011591
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011592 /*
11593 * Set SEL_MASK Microcode Default Value
11594 *
11595 * The microcode will set the SEL_MASK register using this value
11596 * after it is started below.
11597 */
11598 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
11599 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070011600
Matthew Wilcoxa9f4a592007-09-09 08:56:27 -060011601 AdvBuildCarrierFreelist(asc_dvc);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011602
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011603 /*
11604 * Set-up the Host->RISC Initiator Command Queue (ICQ).
11605 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011606
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011607 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
11608 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
11609 return ADV_ERROR;
11610 }
11611 asc_dvc->carr_freelist = (ADV_CARR_T *)
11612 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070011613
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011614 /*
11615 * The first command issued will be placed in the stopper carrier.
11616 */
11617 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011618
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011619 /*
11620 * Set RISC ICQ physical address start value.
11621 */
11622 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011623
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011624 /*
11625 * Set-up the RISC->Host Initiator Response Queue (IRQ).
11626 */
11627 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
11628 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
11629 return ADV_ERROR;
11630 }
11631 asc_dvc->carr_freelist = (ADV_CARR_T *)
11632 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070011633
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011634 /*
11635 * The first command completed by the RISC will be placed in
11636 * the stopper.
11637 *
11638 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
11639 * completed the RISC will set the ASC_RQ_STOPPER bit.
11640 */
11641 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011642
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011643 /*
11644 * Set RISC IRQ physical address start value.
11645 */
11646 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
11647 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011648
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011649 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
11650 (ADV_INTR_ENABLE_HOST_INTR |
11651 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070011652
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011653 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
11654 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011655
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011656 /* finally, finally, gentlemen, start your engine */
11657 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011658
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011659 /*
11660 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
11661 * Resets should be performed. The RISC has to be running
11662 * to issue a SCSI Bus Reset.
11663 */
11664 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
11665 /*
11666 * If the BIOS Signature is present in memory, restore the
11667 * BIOS Handshake Configuration Table and do not perform
11668 * a SCSI Bus Reset.
11669 */
11670 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
11671 0x55AA) {
11672 /*
11673 * Restore per TID negotiated values.
11674 */
11675 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
11676 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
11677 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
11678 tagqng_able);
11679 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
11680 AdvWriteByteLram(iop_base,
11681 ASC_MC_NUMBER_OF_MAX_CMD + tid,
11682 max_cmd[tid]);
11683 }
11684 } else {
11685 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
11686 warn_code = ASC_WARN_BUSRESET_ERROR;
11687 }
11688 }
11689 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011690
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011691 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011692}
11693
11694/*
11695 * Initialize the ASC-38C0800.
11696 *
11697 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
11698 *
11699 * For a non-fatal error return a warning code. If there are no warnings
11700 * then 0 is returned.
11701 *
11702 * Needed after initialization for error recovery.
11703 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011704static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011705{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011706 AdvPortAddr iop_base;
11707 ushort warn_code;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011708 int begin_addr;
11709 int end_addr;
11710 ushort code_sum;
11711 int word;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011712 int i;
11713 ushort scsi_cfg1;
11714 uchar byte;
11715 uchar tid;
11716 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
11717 ushort wdtr_able, sdtr_able, tagqng_able;
11718 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070011719
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011720 /* If there is already an error, don't continue. */
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060011721 if (asc_dvc->err_code != 0)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011722 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011723
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011724 /*
11725 * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
11726 */
11727 if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) {
11728 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
11729 return ADV_ERROR;
11730 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011731
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011732 warn_code = 0;
11733 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011734
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011735 /*
11736 * Save the RISC memory BIOS region before writing the microcode.
11737 * The BIOS may already be loaded and using its RISC LRAM region
11738 * so its region must be saved and restored.
11739 *
11740 * Note: This code makes the assumption, which is currently true,
11741 * that a chip reset does not clear RISC LRAM.
11742 */
11743 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
11744 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
11745 bios_mem[i]);
11746 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011747
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011748 /*
11749 * Save current per TID negotiated values.
11750 */
11751 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
11752 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
11753 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
11754 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
11755 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
11756 max_cmd[tid]);
11757 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011758
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011759 /*
11760 * RAM BIST (RAM Built-In Self Test)
11761 *
11762 * Address : I/O base + offset 0x38h register (byte).
11763 * Function: Bit 7-6(RW) : RAM mode
11764 * Normal Mode : 0x00
11765 * Pre-test Mode : 0x40
11766 * RAM Test Mode : 0x80
11767 * Bit 5 : unused
11768 * Bit 4(RO) : Done bit
11769 * Bit 3-0(RO) : Status
11770 * Host Error : 0x08
11771 * Int_RAM Error : 0x04
11772 * RISC Error : 0x02
11773 * SCSI Error : 0x01
11774 * No Error : 0x00
11775 *
11776 * Note: RAM BIST code should be put right here, before loading the
11777 * microcode and after saving the RISC memory BIOS region.
11778 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011779
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011780 /*
11781 * LRAM Pre-test
11782 *
11783 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
11784 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
11785 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
11786 * to NORMAL_MODE, return an error too.
11787 */
11788 for (i = 0; i < 2; i++) {
11789 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060011790 mdelay(10); /* Wait for 10ms before reading back. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011791 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
11792 if ((byte & RAM_TEST_DONE) == 0
11793 || (byte & 0x0F) != PRE_TEST_VALUE) {
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060011794 asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011795 return ADV_ERROR;
11796 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011797
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011798 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060011799 mdelay(10); /* Wait for 10ms before reading back. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011800 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
11801 != NORMAL_VALUE) {
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060011802 asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011803 return ADV_ERROR;
11804 }
11805 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011806
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011807 /*
11808 * LRAM Test - It takes about 1.5 ms to run through the test.
11809 *
11810 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
11811 * If Done bit not set or Status not 0, save register byte, set the
11812 * err_code, and return an error.
11813 */
11814 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060011815 mdelay(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011816
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011817 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
11818 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
11819 /* Get here if Done bit not set or Status not 0. */
11820 asc_dvc->bist_err_code = byte; /* for BIOS display message */
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060011821 asc_dvc->err_code = ASC_IERR_BIST_RAM_TEST;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011822 return ADV_ERROR;
11823 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011824
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011825 /* We need to reset back to normal mode after LRAM test passes. */
11826 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011827
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060011828 asc_dvc->err_code = AdvLoadMicrocode(iop_base, _adv_asc38C0800_buf,
11829 _adv_asc38C0800_size, ADV_38C0800_MEMSIZE,
11830 _adv_asc38C0800_chksum);
11831 if (asc_dvc->err_code)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011832 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011833
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011834 /*
11835 * Restore the RISC memory BIOS region.
11836 */
11837 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
11838 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
11839 bios_mem[i]);
11840 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011841
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011842 /*
11843 * Calculate and write the microcode code checksum to the microcode
11844 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
11845 */
11846 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
11847 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
11848 code_sum = 0;
11849 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
11850 for (word = begin_addr; word < end_addr; word += 2) {
11851 code_sum += AdvReadWordAutoIncLram(iop_base);
11852 }
11853 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011854
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011855 /*
11856 * Read microcode version and date.
11857 */
11858 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
11859 asc_dvc->cfg->mcode_date);
11860 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
11861 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011862
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011863 /*
11864 * Set the chip type to indicate the ASC38C0800.
11865 */
11866 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011867
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011868 /*
11869 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
11870 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
11871 * cable detection and then we are able to read C_DET[3:0].
11872 *
11873 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
11874 * Microcode Default Value' section below.
11875 */
11876 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
11877 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
11878 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011879
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011880 /*
11881 * If the PCI Configuration Command Register "Parity Error Response
11882 * Control" Bit was clear (0), then set the microcode variable
11883 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
11884 * to ignore DMA parity errors.
11885 */
11886 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
11887 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
11888 word |= CONTROL_FLAG_IGNORE_PERR;
11889 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
11890 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011891
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011892 /*
11893 * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
11894 * bits for the default FIFO threshold.
11895 *
11896 * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
11897 *
11898 * For DMA Errata #4 set the BC_THRESH_ENB bit.
11899 */
11900 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
11901 BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH |
11902 READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011903
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011904 /*
11905 * Microcode operating variables for WDTR, SDTR, and command tag
Matthew Wilcox47d853c2007-07-26 11:41:33 -040011906 * queuing will be set in slave_configure() based on what a
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011907 * device reports it is capable of in Inquiry byte 7.
11908 *
11909 * If SCSI Bus Resets have been disabled, then directly set
11910 * SDTR and WDTR from the EEPROM configuration. This will allow
11911 * the BIOS and warm boot to work without a SCSI bus hang on
11912 * the Inquiry caused by host and target mismatched DTR values.
11913 * Without the SCSI Bus Reset, before an Inquiry a device can't
11914 * be assumed to be in Asynchronous, Narrow mode.
11915 */
11916 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
11917 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
11918 asc_dvc->wdtr_able);
11919 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
11920 asc_dvc->sdtr_able);
11921 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011922
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011923 /*
11924 * Set microcode operating variables for DISC and SDTR_SPEED1,
11925 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
11926 * configuration values.
11927 *
11928 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
11929 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
11930 * without determining here whether the device supports SDTR.
11931 */
11932 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
11933 asc_dvc->cfg->disc_enable);
11934 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
11935 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
11936 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
11937 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011938
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011939 /*
11940 * Set SCSI_CFG0 Microcode Default Value.
11941 *
11942 * The microcode will set the SCSI_CFG0 register using this value
11943 * after it is started below.
11944 */
11945 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
11946 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
11947 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011948
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011949 /*
11950 * Determine SCSI_CFG1 Microcode Default Value.
11951 *
11952 * The microcode will set the SCSI_CFG1 register using this value
11953 * after it is started below.
11954 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011955
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011956 /* Read current SCSI_CFG1 Register value. */
11957 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011958
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011959 /*
11960 * If the internal narrow cable is reversed all of the SCSI_CTRL
11961 * register signals will be set. Check for and return an error if
11962 * this condition is found.
11963 */
11964 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
11965 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
11966 return ADV_ERROR;
11967 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011968
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011969 /*
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060011970 * All kind of combinations of devices attached to one of four
11971 * connectors are acceptable except HVD device attached. For example,
11972 * LVD device can be attached to SE connector while SE device attached
11973 * to LVD connector. If LVD device attached to SE connector, it only
11974 * runs up to Ultra speed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011975 *
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060011976 * If an HVD device is attached to one of LVD connectors, return an
11977 * error. However, there is no way to detect HVD device attached to
11978 * SE connectors.
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011979 */
11980 if (scsi_cfg1 & HVD) {
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060011981 asc_dvc->err_code = ASC_IERR_HVD_DEVICE;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011982 return ADV_ERROR;
11983 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011984
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011985 /*
11986 * If either SE or LVD automatic termination control is enabled, then
11987 * set the termination value based on a table listed in a_condor.h.
11988 *
11989 * If manual termination was specified with an EEPROM setting then
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060011990 * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready
11991 * to be 'ored' into SCSI_CFG1.
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011992 */
11993 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
11994 /* SE automatic termination control is enabled. */
11995 switch (scsi_cfg1 & C_DET_SE) {
11996 /* TERM_SE_HI: on, TERM_SE_LO: on */
11997 case 0x1:
11998 case 0x2:
11999 case 0x3:
12000 asc_dvc->cfg->termination |= TERM_SE;
12001 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012002
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012003 /* TERM_SE_HI: on, TERM_SE_LO: off */
12004 case 0x0:
12005 asc_dvc->cfg->termination |= TERM_SE_HI;
12006 break;
12007 }
12008 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012009
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012010 if ((asc_dvc->cfg->termination & TERM_LVD) == 0) {
12011 /* LVD automatic termination control is enabled. */
12012 switch (scsi_cfg1 & C_DET_LVD) {
12013 /* TERM_LVD_HI: on, TERM_LVD_LO: on */
12014 case 0x4:
12015 case 0x8:
12016 case 0xC:
12017 asc_dvc->cfg->termination |= TERM_LVD;
12018 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012019
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012020 /* TERM_LVD_HI: off, TERM_LVD_LO: off */
12021 case 0x0:
12022 break;
12023 }
12024 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012025
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012026 /*
12027 * Clear any set TERM_SE and TERM_LVD bits.
12028 */
12029 scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012030
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012031 /*
12032 * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
12033 */
12034 scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012035
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012036 /*
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012037 * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE
12038 * bits and set possibly modified termination control bits in the
12039 * Microcode SCSI_CFG1 Register Value.
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012040 */
12041 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012042
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012043 /*
12044 * Set SCSI_CFG1 Microcode Default Value
12045 *
12046 * Set possibly modified termination control and reset DIS_TERM_DRV
12047 * bits in the Microcode SCSI_CFG1 Register Value.
12048 *
12049 * The microcode will set the SCSI_CFG1 register using this value
12050 * after it is started below.
12051 */
12052 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012053
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012054 /*
12055 * Set MEM_CFG Microcode Default Value
12056 *
12057 * The microcode will set the MEM_CFG register using this value
12058 * after it is started below.
12059 *
12060 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
12061 * are defined.
12062 *
12063 * ASC-38C0800 has 16KB internal memory.
12064 */
12065 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
12066 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012067
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012068 /*
12069 * Set SEL_MASK Microcode Default Value
12070 *
12071 * The microcode will set the SEL_MASK register using this value
12072 * after it is started below.
12073 */
12074 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
12075 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012076
Matthew Wilcoxa9f4a592007-09-09 08:56:27 -060012077 AdvBuildCarrierFreelist(asc_dvc);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012078
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012079 /*
12080 * Set-up the Host->RISC Initiator Command Queue (ICQ).
12081 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012082
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012083 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
12084 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
12085 return ADV_ERROR;
12086 }
12087 asc_dvc->carr_freelist = (ADV_CARR_T *)
12088 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012089
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012090 /*
12091 * The first command issued will be placed in the stopper carrier.
12092 */
12093 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012094
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012095 /*
12096 * Set RISC ICQ physical address start value.
12097 * carr_pa is LE, must be native before write
12098 */
12099 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012100
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012101 /*
12102 * Set-up the RISC->Host Initiator Response Queue (IRQ).
12103 */
12104 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
12105 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
12106 return ADV_ERROR;
12107 }
12108 asc_dvc->carr_freelist = (ADV_CARR_T *)
12109 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012110
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012111 /*
12112 * The first command completed by the RISC will be placed in
12113 * the stopper.
12114 *
12115 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
12116 * completed the RISC will set the ASC_RQ_STOPPER bit.
12117 */
12118 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012119
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012120 /*
12121 * Set RISC IRQ physical address start value.
12122 *
12123 * carr_pa is LE, must be native before write *
12124 */
12125 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
12126 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012127
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012128 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
12129 (ADV_INTR_ENABLE_HOST_INTR |
12130 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012131
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012132 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
12133 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012134
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012135 /* finally, finally, gentlemen, start your engine */
12136 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012137
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012138 /*
12139 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
12140 * Resets should be performed. The RISC has to be running
12141 * to issue a SCSI Bus Reset.
12142 */
12143 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
12144 /*
12145 * If the BIOS Signature is present in memory, restore the
12146 * BIOS Handshake Configuration Table and do not perform
12147 * a SCSI Bus Reset.
12148 */
12149 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
12150 0x55AA) {
12151 /*
12152 * Restore per TID negotiated values.
12153 */
12154 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
12155 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
12156 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
12157 tagqng_able);
12158 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
12159 AdvWriteByteLram(iop_base,
12160 ASC_MC_NUMBER_OF_MAX_CMD + tid,
12161 max_cmd[tid]);
12162 }
12163 } else {
12164 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
12165 warn_code = ASC_WARN_BUSRESET_ERROR;
12166 }
12167 }
12168 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012169
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012170 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012171}
12172
12173/*
12174 * Initialize the ASC-38C1600.
12175 *
12176 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
12177 *
12178 * For a non-fatal error return a warning code. If there are no warnings
12179 * then 0 is returned.
12180 *
12181 * Needed after initialization for error recovery.
12182 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012183static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070012184{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012185 AdvPortAddr iop_base;
12186 ushort warn_code;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012187 int begin_addr;
12188 int end_addr;
12189 ushort code_sum;
12190 long word;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012191 int i;
12192 ushort scsi_cfg1;
12193 uchar byte;
12194 uchar tid;
12195 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
12196 ushort wdtr_able, sdtr_able, ppr_able, tagqng_able;
12197 uchar max_cmd[ASC_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070012198
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012199 /* If there is already an error, don't continue. */
12200 if (asc_dvc->err_code != 0) {
12201 return ADV_ERROR;
12202 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012203
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012204 /*
12205 * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600.
12206 */
12207 if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
12208 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
12209 return ADV_ERROR;
12210 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012211
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012212 warn_code = 0;
12213 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012214
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012215 /*
12216 * Save the RISC memory BIOS region before writing the microcode.
12217 * The BIOS may already be loaded and using its RISC LRAM region
12218 * so its region must be saved and restored.
12219 *
12220 * Note: This code makes the assumption, which is currently true,
12221 * that a chip reset does not clear RISC LRAM.
12222 */
12223 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
12224 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
12225 bios_mem[i]);
12226 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012227
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012228 /*
12229 * Save current per TID negotiated values.
12230 */
12231 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
12232 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
12233 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
12234 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
12235 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
12236 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
12237 max_cmd[tid]);
12238 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012239
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012240 /*
12241 * RAM BIST (Built-In Self Test)
12242 *
12243 * Address : I/O base + offset 0x38h register (byte).
12244 * Function: Bit 7-6(RW) : RAM mode
12245 * Normal Mode : 0x00
12246 * Pre-test Mode : 0x40
12247 * RAM Test Mode : 0x80
12248 * Bit 5 : unused
12249 * Bit 4(RO) : Done bit
12250 * Bit 3-0(RO) : Status
12251 * Host Error : 0x08
12252 * Int_RAM Error : 0x04
12253 * RISC Error : 0x02
12254 * SCSI Error : 0x01
12255 * No Error : 0x00
12256 *
12257 * Note: RAM BIST code should be put right here, before loading the
12258 * microcode and after saving the RISC memory BIOS region.
12259 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012260
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012261 /*
12262 * LRAM Pre-test
12263 *
12264 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
12265 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
12266 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
12267 * to NORMAL_MODE, return an error too.
12268 */
12269 for (i = 0; i < 2; i++) {
12270 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060012271 mdelay(10); /* Wait for 10ms before reading back. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012272 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
12273 if ((byte & RAM_TEST_DONE) == 0
12274 || (byte & 0x0F) != PRE_TEST_VALUE) {
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012275 asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012276 return ADV_ERROR;
12277 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012278
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012279 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060012280 mdelay(10); /* Wait for 10ms before reading back. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012281 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
12282 != NORMAL_VALUE) {
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012283 asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012284 return ADV_ERROR;
12285 }
12286 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012287
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012288 /*
12289 * LRAM Test - It takes about 1.5 ms to run through the test.
12290 *
12291 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
12292 * If Done bit not set or Status not 0, save register byte, set the
12293 * err_code, and return an error.
12294 */
12295 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060012296 mdelay(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012297
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012298 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
12299 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
12300 /* Get here if Done bit not set or Status not 0. */
12301 asc_dvc->bist_err_code = byte; /* for BIOS display message */
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012302 asc_dvc->err_code = ASC_IERR_BIST_RAM_TEST;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012303 return ADV_ERROR;
12304 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012305
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012306 /* We need to reset back to normal mode after LRAM test passes. */
12307 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012308
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012309 asc_dvc->err_code = AdvLoadMicrocode(iop_base, _adv_asc38C1600_buf,
12310 _adv_asc38C1600_size, ADV_38C1600_MEMSIZE,
12311 _adv_asc38C1600_chksum);
12312 if (asc_dvc->err_code)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012313 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012314
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012315 /*
12316 * Restore the RISC memory BIOS region.
12317 */
12318 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
12319 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
12320 bios_mem[i]);
12321 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012322
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012323 /*
12324 * Calculate and write the microcode code checksum to the microcode
12325 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
12326 */
12327 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
12328 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
12329 code_sum = 0;
12330 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
12331 for (word = begin_addr; word < end_addr; word += 2) {
12332 code_sum += AdvReadWordAutoIncLram(iop_base);
12333 }
12334 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012335
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012336 /*
12337 * Read microcode version and date.
12338 */
12339 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
12340 asc_dvc->cfg->mcode_date);
12341 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
12342 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012343
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012344 /*
12345 * Set the chip type to indicate the ASC38C1600.
12346 */
12347 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012348
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012349 /*
12350 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
12351 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
12352 * cable detection and then we are able to read C_DET[3:0].
12353 *
12354 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
12355 * Microcode Default Value' section below.
12356 */
12357 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
12358 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
12359 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012360
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012361 /*
12362 * If the PCI Configuration Command Register "Parity Error Response
12363 * Control" Bit was clear (0), then set the microcode variable
12364 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
12365 * to ignore DMA parity errors.
12366 */
12367 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
12368 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
12369 word |= CONTROL_FLAG_IGNORE_PERR;
12370 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
12371 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012372
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012373 /*
12374 * If the BIOS control flag AIPP (Asynchronous Information
12375 * Phase Protection) disable bit is not set, then set the firmware
12376 * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable
12377 * AIPP checking and encoding.
12378 */
12379 if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) {
12380 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
12381 word |= CONTROL_FLAG_ENABLE_AIPP;
12382 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
12383 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012384
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012385 /*
12386 * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4],
12387 * and START_CTL_TH [3:2].
12388 */
12389 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
12390 FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012391
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012392 /*
12393 * Microcode operating variables for WDTR, SDTR, and command tag
Matthew Wilcox47d853c2007-07-26 11:41:33 -040012394 * queuing will be set in slave_configure() based on what a
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012395 * device reports it is capable of in Inquiry byte 7.
12396 *
12397 * If SCSI Bus Resets have been disabled, then directly set
12398 * SDTR and WDTR from the EEPROM configuration. This will allow
12399 * the BIOS and warm boot to work without a SCSI bus hang on
12400 * the Inquiry caused by host and target mismatched DTR values.
12401 * Without the SCSI Bus Reset, before an Inquiry a device can't
12402 * be assumed to be in Asynchronous, Narrow mode.
12403 */
12404 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
12405 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
12406 asc_dvc->wdtr_able);
12407 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
12408 asc_dvc->sdtr_able);
12409 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012410
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012411 /*
12412 * Set microcode operating variables for DISC and SDTR_SPEED1,
12413 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
12414 * configuration values.
12415 *
12416 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
12417 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
12418 * without determining here whether the device supports SDTR.
12419 */
12420 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
12421 asc_dvc->cfg->disc_enable);
12422 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
12423 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
12424 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
12425 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012426
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012427 /*
12428 * Set SCSI_CFG0 Microcode Default Value.
12429 *
12430 * The microcode will set the SCSI_CFG0 register using this value
12431 * after it is started below.
12432 */
12433 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
12434 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
12435 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012436
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012437 /*
12438 * Calculate SCSI_CFG1 Microcode Default Value.
12439 *
12440 * The microcode will set the SCSI_CFG1 register using this value
12441 * after it is started below.
12442 *
12443 * Each ASC-38C1600 function has only two cable detect bits.
12444 * The bus mode override bits are in IOPB_SOFT_OVER_WR.
12445 */
12446 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012447
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012448 /*
12449 * If the cable is reversed all of the SCSI_CTRL register signals
12450 * will be set. Check for and return an error if this condition is
12451 * found.
12452 */
12453 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
12454 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
12455 return ADV_ERROR;
12456 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012457
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012458 /*
12459 * Each ASC-38C1600 function has two connectors. Only an HVD device
12460 * can not be connected to either connector. An LVD device or SE device
12461 * may be connected to either connecor. If an SE device is connected,
12462 * then at most Ultra speed (20 Mhz) can be used on both connectors.
12463 *
12464 * If an HVD device is attached, return an error.
12465 */
12466 if (scsi_cfg1 & HVD) {
12467 asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
12468 return ADV_ERROR;
12469 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012470
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012471 /*
12472 * Each function in the ASC-38C1600 uses only the SE cable detect and
12473 * termination because there are two connectors for each function. Each
12474 * function may use either LVD or SE mode. Corresponding the SE automatic
12475 * termination control EEPROM bits are used for each function. Each
12476 * function has its own EEPROM. If SE automatic control is enabled for
12477 * the function, then set the termination value based on a table listed
12478 * in a_condor.h.
12479 *
12480 * If manual termination is specified in the EEPROM for the function,
12481 * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is
12482 * ready to be 'ored' into SCSI_CFG1.
12483 */
12484 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
Matthew Wilcox13ac2d92007-07-30 08:10:23 -060012485 struct pci_dev *pdev = adv_dvc_to_pdev(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012486 /* SE automatic termination control is enabled. */
12487 switch (scsi_cfg1 & C_DET_SE) {
12488 /* TERM_SE_HI: on, TERM_SE_LO: on */
12489 case 0x1:
12490 case 0x2:
12491 case 0x3:
12492 asc_dvc->cfg->termination |= TERM_SE;
12493 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012494
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012495 case 0x0:
Matthew Wilcox13ac2d92007-07-30 08:10:23 -060012496 if (PCI_FUNC(pdev->devfn) == 0) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012497 /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */
12498 } else {
12499 /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */
12500 asc_dvc->cfg->termination |= TERM_SE_HI;
12501 }
12502 break;
12503 }
12504 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012505
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012506 /*
12507 * Clear any set TERM_SE bits.
12508 */
12509 scsi_cfg1 &= ~TERM_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012510
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012511 /*
12512 * Invert the TERM_SE bits and then set 'scsi_cfg1'.
12513 */
12514 scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012515
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012516 /*
12517 * Clear Big Endian and Terminator Polarity bits and set possibly
12518 * modified termination control bits in the Microcode SCSI_CFG1
12519 * Register Value.
12520 *
12521 * Big Endian bit is not used even on big endian machines.
12522 */
12523 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012524
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012525 /*
12526 * Set SCSI_CFG1 Microcode Default Value
12527 *
12528 * Set possibly modified termination control bits in the Microcode
12529 * SCSI_CFG1 Register Value.
12530 *
12531 * The microcode will set the SCSI_CFG1 register using this value
12532 * after it is started below.
12533 */
12534 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012535
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012536 /*
12537 * Set MEM_CFG Microcode Default Value
12538 *
12539 * The microcode will set the MEM_CFG register using this value
12540 * after it is started below.
12541 *
12542 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
12543 * are defined.
12544 *
12545 * ASC-38C1600 has 32KB internal memory.
12546 *
12547 * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come
12548 * out a special 16K Adv Library and Microcode version. After the issue
12549 * resolved, we should turn back to the 32K support. Both a_condor.h and
12550 * mcode.sas files also need to be updated.
12551 *
12552 * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
12553 * BIOS_EN | RAM_SZ_32KB);
12554 */
12555 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
12556 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012557
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012558 /*
12559 * Set SEL_MASK Microcode Default Value
12560 *
12561 * The microcode will set the SEL_MASK register using this value
12562 * after it is started below.
12563 */
12564 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
12565 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012566
Matthew Wilcoxa9f4a592007-09-09 08:56:27 -060012567 AdvBuildCarrierFreelist(asc_dvc);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012568
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012569 /*
12570 * Set-up the Host->RISC Initiator Command Queue (ICQ).
12571 */
12572 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
12573 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
12574 return ADV_ERROR;
12575 }
12576 asc_dvc->carr_freelist = (ADV_CARR_T *)
12577 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012578
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012579 /*
12580 * The first command issued will be placed in the stopper carrier.
12581 */
12582 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012583
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012584 /*
12585 * Set RISC ICQ physical address start value. Initialize the
12586 * COMMA register to the same value otherwise the RISC will
12587 * prematurely detect a command is available.
12588 */
12589 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
12590 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
12591 le32_to_cpu(asc_dvc->icq_sp->carr_pa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012592
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012593 /*
12594 * Set-up the RISC->Host Initiator Response Queue (IRQ).
12595 */
12596 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
12597 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
12598 return ADV_ERROR;
12599 }
12600 asc_dvc->carr_freelist = (ADV_CARR_T *)
12601 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012602
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012603 /*
12604 * The first command completed by the RISC will be placed in
12605 * the stopper.
12606 *
12607 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
12608 * completed the RISC will set the ASC_RQ_STOPPER bit.
12609 */
12610 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012611
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012612 /*
12613 * Set RISC IRQ physical address start value.
12614 */
12615 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
12616 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012617
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012618 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
12619 (ADV_INTR_ENABLE_HOST_INTR |
12620 ADV_INTR_ENABLE_GLOBAL_INTR));
12621 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
12622 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012623
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012624 /* finally, finally, gentlemen, start your engine */
12625 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012626
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012627 /*
12628 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
12629 * Resets should be performed. The RISC has to be running
12630 * to issue a SCSI Bus Reset.
12631 */
12632 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
12633 /*
12634 * If the BIOS Signature is present in memory, restore the
12635 * per TID microcode operating variables.
12636 */
12637 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
12638 0x55AA) {
12639 /*
12640 * Restore per TID negotiated values.
12641 */
12642 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
12643 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
12644 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
12645 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
12646 tagqng_able);
12647 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
12648 AdvWriteByteLram(iop_base,
12649 ASC_MC_NUMBER_OF_MAX_CMD + tid,
12650 max_cmd[tid]);
12651 }
12652 } else {
12653 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
12654 warn_code = ASC_WARN_BUSRESET_ERROR;
12655 }
12656 }
12657 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012658
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012659 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012660}
12661
12662/*
12663 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
12664 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
12665 * all of this is done.
12666 *
12667 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
12668 *
12669 * For a non-fatal error return a warning code. If there are no warnings
12670 * then 0 is returned.
12671 *
12672 * Note: Chip is stopped on entry.
12673 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060012674static int __devinit AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070012675{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012676 AdvPortAddr iop_base;
12677 ushort warn_code;
12678 ADVEEP_3550_CONFIG eep_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012679
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012680 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012681
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012682 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012683
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012684 /*
12685 * Read the board's EEPROM configuration.
12686 *
12687 * Set default values if a bad checksum is found.
12688 */
12689 if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum) {
12690 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012691
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012692 /*
12693 * Set EEPROM default values.
12694 */
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040012695 memcpy(&eep_config, &Default_3550_EEPROM_Config,
12696 sizeof(ADVEEP_3550_CONFIG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012697
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012698 /*
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040012699 * Assume the 6 byte board serial number that was read from
12700 * EEPROM is correct even if the EEPROM checksum failed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012701 */
12702 eep_config.serial_number_word3 =
12703 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012704
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012705 eep_config.serial_number_word2 =
12706 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012707
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012708 eep_config.serial_number_word1 =
12709 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012710
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012711 AdvSet3550EEPConfig(iop_base, &eep_config);
12712 }
12713 /*
12714 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
12715 * EEPROM configuration that was read.
12716 *
12717 * This is the mapping of EEPROM fields to Adv Library fields.
12718 */
12719 asc_dvc->wdtr_able = eep_config.wdtr_able;
12720 asc_dvc->sdtr_able = eep_config.sdtr_able;
12721 asc_dvc->ultra_able = eep_config.ultra_able;
12722 asc_dvc->tagqng_able = eep_config.tagqng_able;
12723 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
12724 asc_dvc->max_host_qng = eep_config.max_host_qng;
12725 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
12726 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
12727 asc_dvc->start_motor = eep_config.start_motor;
12728 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
12729 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
12730 asc_dvc->no_scam = eep_config.scam_tolerant;
12731 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
12732 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
12733 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012734
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012735 /*
12736 * Set the host maximum queuing (max. 253, min. 16) and the per device
12737 * maximum queuing (max. 63, min. 4).
12738 */
12739 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
12740 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
12741 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
12742 /* If the value is zero, assume it is uninitialized. */
12743 if (eep_config.max_host_qng == 0) {
12744 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
12745 } else {
12746 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
12747 }
12748 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012749
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012750 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
12751 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
12752 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
12753 /* If the value is zero, assume it is uninitialized. */
12754 if (eep_config.max_dvc_qng == 0) {
12755 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
12756 } else {
12757 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
12758 }
12759 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012760
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012761 /*
12762 * If 'max_dvc_qng' is greater than 'max_host_qng', then
12763 * set 'max_dvc_qng' to 'max_host_qng'.
12764 */
12765 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
12766 eep_config.max_dvc_qng = eep_config.max_host_qng;
12767 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012768
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012769 /*
12770 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
12771 * values based on possibly adjusted EEPROM values.
12772 */
12773 asc_dvc->max_host_qng = eep_config.max_host_qng;
12774 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012775
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012776 /*
12777 * If the EEPROM 'termination' field is set to automatic (0), then set
12778 * the ADV_DVC_CFG 'termination' field to automatic also.
12779 *
12780 * If the termination is specified with a non-zero 'termination'
12781 * value check that a legal value is set and set the ADV_DVC_CFG
12782 * 'termination' field appropriately.
12783 */
12784 if (eep_config.termination == 0) {
12785 asc_dvc->cfg->termination = 0; /* auto termination */
12786 } else {
12787 /* Enable manual control with low off / high off. */
12788 if (eep_config.termination == 1) {
12789 asc_dvc->cfg->termination = TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012790
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012791 /* Enable manual control with low off / high on. */
12792 } else if (eep_config.termination == 2) {
12793 asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012794
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012795 /* Enable manual control with low on / high on. */
12796 } else if (eep_config.termination == 3) {
12797 asc_dvc->cfg->termination =
12798 TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L;
12799 } else {
12800 /*
12801 * The EEPROM 'termination' field contains a bad value. Use
12802 * automatic termination instead.
12803 */
12804 asc_dvc->cfg->termination = 0;
12805 warn_code |= ASC_WARN_EEPROM_TERMINATION;
12806 }
12807 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012808
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012809 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012810}
12811
12812/*
12813 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
12814 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
12815 * all of this is done.
12816 *
12817 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
12818 *
12819 * For a non-fatal error return a warning code. If there are no warnings
12820 * then 0 is returned.
12821 *
12822 * Note: Chip is stopped on entry.
12823 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060012824static int __devinit AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070012825{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012826 AdvPortAddr iop_base;
12827 ushort warn_code;
12828 ADVEEP_38C0800_CONFIG eep_config;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012829 uchar tid, termination;
12830 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012831
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012832 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012833
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012834 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012835
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012836 /*
12837 * Read the board's EEPROM configuration.
12838 *
12839 * Set default values if a bad checksum is found.
12840 */
12841 if (AdvGet38C0800EEPConfig(iop_base, &eep_config) !=
12842 eep_config.check_sum) {
12843 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012844
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012845 /*
12846 * Set EEPROM default values.
12847 */
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040012848 memcpy(&eep_config, &Default_38C0800_EEPROM_Config,
12849 sizeof(ADVEEP_38C0800_CONFIG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012850
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012851 /*
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040012852 * Assume the 6 byte board serial number that was read from
12853 * EEPROM is correct even if the EEPROM checksum failed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012854 */
12855 eep_config.serial_number_word3 =
12856 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012857
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012858 eep_config.serial_number_word2 =
12859 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012860
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012861 eep_config.serial_number_word1 =
12862 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012863
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012864 AdvSet38C0800EEPConfig(iop_base, &eep_config);
12865 }
12866 /*
12867 * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
12868 * EEPROM configuration that was read.
12869 *
12870 * This is the mapping of EEPROM fields to Adv Library fields.
12871 */
12872 asc_dvc->wdtr_able = eep_config.wdtr_able;
12873 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
12874 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
12875 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
12876 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
12877 asc_dvc->tagqng_able = eep_config.tagqng_able;
12878 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
12879 asc_dvc->max_host_qng = eep_config.max_host_qng;
12880 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
12881 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
12882 asc_dvc->start_motor = eep_config.start_motor;
12883 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
12884 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
12885 asc_dvc->no_scam = eep_config.scam_tolerant;
12886 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
12887 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
12888 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012889
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012890 /*
12891 * For every Target ID if any of its 'sdtr_speed[1234]' bits
12892 * are set, then set an 'sdtr_able' bit for it.
12893 */
12894 asc_dvc->sdtr_able = 0;
12895 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
12896 if (tid == 0) {
12897 sdtr_speed = asc_dvc->sdtr_speed1;
12898 } else if (tid == 4) {
12899 sdtr_speed = asc_dvc->sdtr_speed2;
12900 } else if (tid == 8) {
12901 sdtr_speed = asc_dvc->sdtr_speed3;
12902 } else if (tid == 12) {
12903 sdtr_speed = asc_dvc->sdtr_speed4;
12904 }
12905 if (sdtr_speed & ADV_MAX_TID) {
12906 asc_dvc->sdtr_able |= (1 << tid);
12907 }
12908 sdtr_speed >>= 4;
12909 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012910
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012911 /*
12912 * Set the host maximum queuing (max. 253, min. 16) and the per device
12913 * maximum queuing (max. 63, min. 4).
12914 */
12915 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
12916 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
12917 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
12918 /* If the value is zero, assume it is uninitialized. */
12919 if (eep_config.max_host_qng == 0) {
12920 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
12921 } else {
12922 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
12923 }
12924 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012925
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012926 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
12927 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
12928 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
12929 /* If the value is zero, assume it is uninitialized. */
12930 if (eep_config.max_dvc_qng == 0) {
12931 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
12932 } else {
12933 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
12934 }
12935 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012936
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012937 /*
12938 * If 'max_dvc_qng' is greater than 'max_host_qng', then
12939 * set 'max_dvc_qng' to 'max_host_qng'.
12940 */
12941 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
12942 eep_config.max_dvc_qng = eep_config.max_host_qng;
12943 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012944
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012945 /*
12946 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
12947 * values based on possibly adjusted EEPROM values.
12948 */
12949 asc_dvc->max_host_qng = eep_config.max_host_qng;
12950 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012951
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012952 /*
12953 * If the EEPROM 'termination' field is set to automatic (0), then set
12954 * the ADV_DVC_CFG 'termination' field to automatic also.
12955 *
12956 * If the termination is specified with a non-zero 'termination'
12957 * value check that a legal value is set and set the ADV_DVC_CFG
12958 * 'termination' field appropriately.
12959 */
12960 if (eep_config.termination_se == 0) {
12961 termination = 0; /* auto termination for SE */
12962 } else {
12963 /* Enable manual control with low off / high off. */
12964 if (eep_config.termination_se == 1) {
12965 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012966
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012967 /* Enable manual control with low off / high on. */
12968 } else if (eep_config.termination_se == 2) {
12969 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012970
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012971 /* Enable manual control with low on / high on. */
12972 } else if (eep_config.termination_se == 3) {
12973 termination = TERM_SE;
12974 } else {
12975 /*
12976 * The EEPROM 'termination_se' field contains a bad value.
12977 * Use automatic termination instead.
12978 */
12979 termination = 0;
12980 warn_code |= ASC_WARN_EEPROM_TERMINATION;
12981 }
12982 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012983
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012984 if (eep_config.termination_lvd == 0) {
12985 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
12986 } else {
12987 /* Enable manual control with low off / high off. */
12988 if (eep_config.termination_lvd == 1) {
12989 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012990
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012991 /* Enable manual control with low off / high on. */
12992 } else if (eep_config.termination_lvd == 2) {
12993 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012994
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012995 /* Enable manual control with low on / high on. */
12996 } else if (eep_config.termination_lvd == 3) {
12997 asc_dvc->cfg->termination = termination | TERM_LVD;
12998 } else {
12999 /*
13000 * The EEPROM 'termination_lvd' field contains a bad value.
13001 * Use automatic termination instead.
13002 */
13003 asc_dvc->cfg->termination = termination;
13004 warn_code |= ASC_WARN_EEPROM_TERMINATION;
13005 }
13006 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013007
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013008 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013009}
13010
13011/*
13012 * Read the board's EEPROM configuration. Set fields in ASC_DVC_VAR and
13013 * ASC_DVC_CFG based on the EEPROM settings. The chip is stopped while
13014 * all of this is done.
13015 *
13016 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
13017 *
13018 * For a non-fatal error return a warning code. If there are no warnings
13019 * then 0 is returned.
13020 *
13021 * Note: Chip is stopped on entry.
13022 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013023static int __devinit AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013024{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013025 AdvPortAddr iop_base;
13026 ushort warn_code;
13027 ADVEEP_38C1600_CONFIG eep_config;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013028 uchar tid, termination;
13029 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013030
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013031 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013032
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013033 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013034
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013035 /*
13036 * Read the board's EEPROM configuration.
13037 *
13038 * Set default values if a bad checksum is found.
13039 */
13040 if (AdvGet38C1600EEPConfig(iop_base, &eep_config) !=
13041 eep_config.check_sum) {
Matthew Wilcox13ac2d92007-07-30 08:10:23 -060013042 struct pci_dev *pdev = adv_dvc_to_pdev(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013043 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013044
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013045 /*
13046 * Set EEPROM default values.
13047 */
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040013048 memcpy(&eep_config, &Default_38C1600_EEPROM_Config,
13049 sizeof(ADVEEP_38C1600_CONFIG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013050
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040013051 if (PCI_FUNC(pdev->devfn) != 0) {
13052 u8 ints;
13053 /*
13054 * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60
13055 * and old Mac system booting problem. The Expansion
13056 * ROM must be disabled in Function 1 for these systems
13057 */
13058 eep_config.cfg_lsw &= ~ADV_EEPROM_BIOS_ENABLE;
13059 /*
13060 * Clear the INTAB (bit 11) if the GPIO 0 input
13061 * indicates the Function 1 interrupt line is wired
13062 * to INTB.
13063 *
13064 * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input:
13065 * 1 - Function 1 interrupt line wired to INT A.
13066 * 0 - Function 1 interrupt line wired to INT B.
13067 *
13068 * Note: Function 0 is always wired to INTA.
13069 * Put all 5 GPIO bits in input mode and then read
13070 * their input values.
13071 */
13072 AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL, 0);
13073 ints = AdvReadByteRegister(iop_base, IOPB_GPIO_DATA);
13074 if ((ints & 0x01) == 0)
13075 eep_config.cfg_lsw &= ~ADV_EEPROM_INTAB;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013076 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013077
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013078 /*
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040013079 * Assume the 6 byte board serial number that was read from
13080 * EEPROM is correct even if the EEPROM checksum failed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013081 */
13082 eep_config.serial_number_word3 =
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040013083 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013084 eep_config.serial_number_word2 =
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040013085 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013086 eep_config.serial_number_word1 =
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040013087 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013088
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013089 AdvSet38C1600EEPConfig(iop_base, &eep_config);
13090 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013091
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013092 /*
13093 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
13094 * EEPROM configuration that was read.
13095 *
13096 * This is the mapping of EEPROM fields to Adv Library fields.
13097 */
13098 asc_dvc->wdtr_able = eep_config.wdtr_able;
13099 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
13100 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
13101 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
13102 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
13103 asc_dvc->ppr_able = 0;
13104 asc_dvc->tagqng_able = eep_config.tagqng_able;
13105 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
13106 asc_dvc->max_host_qng = eep_config.max_host_qng;
13107 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
13108 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ASC_MAX_TID);
13109 asc_dvc->start_motor = eep_config.start_motor;
13110 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
13111 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
13112 asc_dvc->no_scam = eep_config.scam_tolerant;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013113
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013114 /*
13115 * For every Target ID if any of its 'sdtr_speed[1234]' bits
13116 * are set, then set an 'sdtr_able' bit for it.
13117 */
13118 asc_dvc->sdtr_able = 0;
13119 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
13120 if (tid == 0) {
13121 sdtr_speed = asc_dvc->sdtr_speed1;
13122 } else if (tid == 4) {
13123 sdtr_speed = asc_dvc->sdtr_speed2;
13124 } else if (tid == 8) {
13125 sdtr_speed = asc_dvc->sdtr_speed3;
13126 } else if (tid == 12) {
13127 sdtr_speed = asc_dvc->sdtr_speed4;
13128 }
13129 if (sdtr_speed & ASC_MAX_TID) {
13130 asc_dvc->sdtr_able |= (1 << tid);
13131 }
13132 sdtr_speed >>= 4;
13133 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013134
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013135 /*
13136 * Set the host maximum queuing (max. 253, min. 16) and the per device
13137 * maximum queuing (max. 63, min. 4).
13138 */
13139 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
13140 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
13141 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
13142 /* If the value is zero, assume it is uninitialized. */
13143 if (eep_config.max_host_qng == 0) {
13144 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
13145 } else {
13146 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
13147 }
13148 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013149
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013150 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
13151 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
13152 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
13153 /* If the value is zero, assume it is uninitialized. */
13154 if (eep_config.max_dvc_qng == 0) {
13155 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
13156 } else {
13157 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
13158 }
13159 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013160
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013161 /*
13162 * If 'max_dvc_qng' is greater than 'max_host_qng', then
13163 * set 'max_dvc_qng' to 'max_host_qng'.
13164 */
13165 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
13166 eep_config.max_dvc_qng = eep_config.max_host_qng;
13167 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013168
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013169 /*
13170 * Set ASC_DVC_VAR 'max_host_qng' and ASC_DVC_VAR 'max_dvc_qng'
13171 * values based on possibly adjusted EEPROM values.
13172 */
13173 asc_dvc->max_host_qng = eep_config.max_host_qng;
13174 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013175
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013176 /*
13177 * If the EEPROM 'termination' field is set to automatic (0), then set
13178 * the ASC_DVC_CFG 'termination' field to automatic also.
13179 *
13180 * If the termination is specified with a non-zero 'termination'
13181 * value check that a legal value is set and set the ASC_DVC_CFG
13182 * 'termination' field appropriately.
13183 */
13184 if (eep_config.termination_se == 0) {
13185 termination = 0; /* auto termination for SE */
13186 } else {
13187 /* Enable manual control with low off / high off. */
13188 if (eep_config.termination_se == 1) {
13189 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013190
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013191 /* Enable manual control with low off / high on. */
13192 } else if (eep_config.termination_se == 2) {
13193 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013194
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013195 /* Enable manual control with low on / high on. */
13196 } else if (eep_config.termination_se == 3) {
13197 termination = TERM_SE;
13198 } else {
13199 /*
13200 * The EEPROM 'termination_se' field contains a bad value.
13201 * Use automatic termination instead.
13202 */
13203 termination = 0;
13204 warn_code |= ASC_WARN_EEPROM_TERMINATION;
13205 }
13206 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013207
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013208 if (eep_config.termination_lvd == 0) {
13209 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
13210 } else {
13211 /* Enable manual control with low off / high off. */
13212 if (eep_config.termination_lvd == 1) {
13213 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013214
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013215 /* Enable manual control with low off / high on. */
13216 } else if (eep_config.termination_lvd == 2) {
13217 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013218
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013219 /* Enable manual control with low on / high on. */
13220 } else if (eep_config.termination_lvd == 3) {
13221 asc_dvc->cfg->termination = termination | TERM_LVD;
13222 } else {
13223 /*
13224 * The EEPROM 'termination_lvd' field contains a bad value.
13225 * Use automatic termination instead.
13226 */
13227 asc_dvc->cfg->termination = termination;
13228 warn_code |= ASC_WARN_EEPROM_TERMINATION;
13229 }
13230 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013231
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013232 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013233}
13234
13235/*
13236 * Read EEPROM configuration into the specified buffer.
13237 *
13238 * Return a checksum based on the EEPROM configuration read.
13239 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013240static ushort __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -070013241AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
13242{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013243 ushort wval, chksum;
13244 ushort *wbuf;
13245 int eep_addr;
13246 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013247
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013248 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
13249 wbuf = (ushort *)cfg_buf;
13250 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013251
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013252 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
13253 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
13254 wval = AdvReadEEPWord(iop_base, eep_addr);
13255 chksum += wval; /* Checksum is calculated from word values. */
13256 if (*charfields++) {
13257 *wbuf = le16_to_cpu(wval);
13258 } else {
13259 *wbuf = wval;
13260 }
13261 }
13262 /* Read checksum word. */
13263 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
13264 wbuf++;
13265 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013266
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013267 /* Read rest of EEPROM not covered by the checksum. */
13268 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
13269 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
13270 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
13271 if (*charfields++) {
13272 *wbuf = le16_to_cpu(*wbuf);
13273 }
13274 }
13275 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013276}
13277
13278/*
13279 * Read EEPROM configuration into the specified buffer.
13280 *
13281 * Return a checksum based on the EEPROM configuration read.
13282 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013283static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013284AdvGet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013285{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013286 ushort wval, chksum;
13287 ushort *wbuf;
13288 int eep_addr;
13289 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013290
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013291 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
13292 wbuf = (ushort *)cfg_buf;
13293 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013294
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013295 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
13296 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
13297 wval = AdvReadEEPWord(iop_base, eep_addr);
13298 chksum += wval; /* Checksum is calculated from word values. */
13299 if (*charfields++) {
13300 *wbuf = le16_to_cpu(wval);
13301 } else {
13302 *wbuf = wval;
13303 }
13304 }
13305 /* Read checksum word. */
13306 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
13307 wbuf++;
13308 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013309
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013310 /* Read rest of EEPROM not covered by the checksum. */
13311 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
13312 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
13313 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
13314 if (*charfields++) {
13315 *wbuf = le16_to_cpu(*wbuf);
13316 }
13317 }
13318 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013319}
13320
13321/*
13322 * Read EEPROM configuration into the specified buffer.
13323 *
13324 * Return a checksum based on the EEPROM configuration read.
13325 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013326static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013327AdvGet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013328{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013329 ushort wval, chksum;
13330 ushort *wbuf;
13331 int eep_addr;
13332 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013333
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013334 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
13335 wbuf = (ushort *)cfg_buf;
13336 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013337
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013338 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
13339 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
13340 wval = AdvReadEEPWord(iop_base, eep_addr);
13341 chksum += wval; /* Checksum is calculated from word values. */
13342 if (*charfields++) {
13343 *wbuf = le16_to_cpu(wval);
13344 } else {
13345 *wbuf = wval;
13346 }
13347 }
13348 /* Read checksum word. */
13349 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
13350 wbuf++;
13351 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013352
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013353 /* Read rest of EEPROM not covered by the checksum. */
13354 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
13355 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
13356 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
13357 if (*charfields++) {
13358 *wbuf = le16_to_cpu(*wbuf);
13359 }
13360 }
13361 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013362}
13363
13364/*
13365 * Read the EEPROM from specified location
13366 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013367static ushort __devinit AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013368{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013369 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
13370 ASC_EEP_CMD_READ | eep_word_addr);
13371 AdvWaitEEPCmd(iop_base);
13372 return AdvReadWordRegister(iop_base, IOPW_EE_DATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013373}
13374
13375/*
13376 * Wait for EEPROM command to complete
13377 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013378static void __devinit AdvWaitEEPCmd(AdvPortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013379{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013380 int eep_delay_ms;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013381
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013382 for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++) {
13383 if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) &
13384 ASC_EEP_CMD_DONE) {
13385 break;
13386 }
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060013387 mdelay(1);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013388 }
13389 if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) ==
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060013390 0)
13391 BUG();
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013392 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013393}
13394
13395/*
13396 * Write the EEPROM from 'cfg_buf'.
13397 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013398void __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -070013399AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
13400{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013401 ushort *wbuf;
13402 ushort addr, chksum;
13403 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013404
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013405 wbuf = (ushort *)cfg_buf;
13406 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
13407 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013408
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013409 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
13410 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013411
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013412 /*
13413 * Write EEPROM from word 0 to word 20.
13414 */
13415 for (addr = ADV_EEP_DVC_CFG_BEGIN;
13416 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
13417 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013418
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013419 if (*charfields++) {
13420 word = cpu_to_le16(*wbuf);
13421 } else {
13422 word = *wbuf;
13423 }
13424 chksum += *wbuf; /* Checksum is calculated from word values. */
13425 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
13426 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
13427 ASC_EEP_CMD_WRITE | addr);
13428 AdvWaitEEPCmd(iop_base);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060013429 mdelay(ADV_EEP_DELAY_MS);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013430 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013431
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013432 /*
13433 * Write EEPROM checksum at word 21.
13434 */
13435 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
13436 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
13437 AdvWaitEEPCmd(iop_base);
13438 wbuf++;
13439 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013440
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013441 /*
13442 * Write EEPROM OEM name at words 22 to 29.
13443 */
13444 for (addr = ADV_EEP_DVC_CTL_BEGIN;
13445 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
13446 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013447
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013448 if (*charfields++) {
13449 word = cpu_to_le16(*wbuf);
13450 } else {
13451 word = *wbuf;
13452 }
13453 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
13454 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
13455 ASC_EEP_CMD_WRITE | addr);
13456 AdvWaitEEPCmd(iop_base);
13457 }
13458 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
13459 AdvWaitEEPCmd(iop_base);
13460 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013461}
13462
13463/*
13464 * Write the EEPROM from 'cfg_buf'.
13465 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013466void __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013467AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013468{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013469 ushort *wbuf;
13470 ushort *charfields;
13471 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013472
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013473 wbuf = (ushort *)cfg_buf;
13474 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
13475 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013476
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013477 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
13478 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013479
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013480 /*
13481 * Write EEPROM from word 0 to word 20.
13482 */
13483 for (addr = ADV_EEP_DVC_CFG_BEGIN;
13484 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
13485 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013486
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013487 if (*charfields++) {
13488 word = cpu_to_le16(*wbuf);
13489 } else {
13490 word = *wbuf;
13491 }
13492 chksum += *wbuf; /* Checksum is calculated from word values. */
13493 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
13494 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
13495 ASC_EEP_CMD_WRITE | addr);
13496 AdvWaitEEPCmd(iop_base);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060013497 mdelay(ADV_EEP_DELAY_MS);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013498 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013499
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013500 /*
13501 * Write EEPROM checksum at word 21.
13502 */
13503 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
13504 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
13505 AdvWaitEEPCmd(iop_base);
13506 wbuf++;
13507 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013508
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013509 /*
13510 * Write EEPROM OEM name at words 22 to 29.
13511 */
13512 for (addr = ADV_EEP_DVC_CTL_BEGIN;
13513 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
13514 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013515
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013516 if (*charfields++) {
13517 word = cpu_to_le16(*wbuf);
13518 } else {
13519 word = *wbuf;
13520 }
13521 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
13522 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
13523 ASC_EEP_CMD_WRITE | addr);
13524 AdvWaitEEPCmd(iop_base);
13525 }
13526 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
13527 AdvWaitEEPCmd(iop_base);
13528 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013529}
13530
13531/*
13532 * Write the EEPROM from 'cfg_buf'.
13533 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013534void __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013535AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013536{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013537 ushort *wbuf;
13538 ushort *charfields;
13539 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013540
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013541 wbuf = (ushort *)cfg_buf;
13542 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
13543 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013544
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013545 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
13546 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013547
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013548 /*
13549 * Write EEPROM from word 0 to word 20.
13550 */
13551 for (addr = ADV_EEP_DVC_CFG_BEGIN;
13552 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
13553 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013554
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013555 if (*charfields++) {
13556 word = cpu_to_le16(*wbuf);
13557 } else {
13558 word = *wbuf;
13559 }
13560 chksum += *wbuf; /* Checksum is calculated from word values. */
13561 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
13562 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
13563 ASC_EEP_CMD_WRITE | addr);
13564 AdvWaitEEPCmd(iop_base);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060013565 mdelay(ADV_EEP_DELAY_MS);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013566 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013567
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013568 /*
13569 * Write EEPROM checksum at word 21.
13570 */
13571 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
13572 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
13573 AdvWaitEEPCmd(iop_base);
13574 wbuf++;
13575 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013576
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013577 /*
13578 * Write EEPROM OEM name at words 22 to 29.
13579 */
13580 for (addr = ADV_EEP_DVC_CTL_BEGIN;
13581 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
13582 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013583
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013584 if (*charfields++) {
13585 word = cpu_to_le16(*wbuf);
13586 } else {
13587 word = *wbuf;
13588 }
13589 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
13590 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
13591 ASC_EEP_CMD_WRITE | addr);
13592 AdvWaitEEPCmd(iop_base);
13593 }
13594 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
13595 AdvWaitEEPCmd(iop_base);
13596 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013597}
13598
Linus Torvalds1da177e2005-04-16 15:20:36 -070013599/*
13600 * AdvExeScsiQueue() - Send a request to the RISC microcode program.
13601 *
13602 * Allocate a carrier structure, point the carrier to the ADV_SCSI_REQ_Q,
13603 * add the carrier to the ICQ (Initiator Command Queue), and tickle the
13604 * RISC to notify it a new command is ready to be executed.
13605 *
13606 * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be
13607 * set to SCSI_MAX_RETRY.
13608 *
13609 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the microcode
13610 * for DMA addresses or math operations are byte swapped to little-endian
13611 * order.
13612 *
13613 * Return:
13614 * ADV_SUCCESS(1) - The request was successfully queued.
13615 * ADV_BUSY(0) - Resource unavailable; Retry again after pending
13616 * request completes.
13617 * ADV_ERROR(-1) - Invalid ADV_SCSI_REQ_Q request structure
13618 * host IC error.
13619 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013620static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013621{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013622 AdvPortAddr iop_base;
13623 ADV_DCNT req_size;
13624 ADV_PADDR req_paddr;
13625 ADV_CARR_T *new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013626
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013627 /*
13628 * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
13629 */
13630 if (scsiq->target_id > ADV_MAX_TID) {
13631 scsiq->host_status = QHSTA_M_INVALID_DEVICE;
13632 scsiq->done_status = QD_WITH_ERROR;
13633 return ADV_ERROR;
13634 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013635
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013636 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013637
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013638 /*
13639 * Allocate a carrier ensuring at least one carrier always
13640 * remains on the freelist and initialize fields.
13641 */
13642 if ((new_carrp = asc_dvc->carr_freelist) == NULL) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013643 return ADV_BUSY;
13644 }
13645 asc_dvc->carr_freelist = (ADV_CARR_T *)
13646 ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa));
13647 asc_dvc->carr_pending_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013648
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013649 /*
13650 * Set the carrier to be a stopper by setting 'next_vpa'
13651 * to the stopper value. The current stopper will be changed
13652 * below to point to the new stopper.
13653 */
13654 new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013655
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013656 /*
13657 * Clear the ADV_SCSI_REQ_Q done flag.
13658 */
13659 scsiq->a_flag &= ~ADV_SCSIQ_DONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013660
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013661 req_size = sizeof(ADV_SCSI_REQ_Q);
13662 req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *)scsiq,
13663 (ADV_SDCNT *)&req_size, ADV_IS_SCSIQ_FLAG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013664
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060013665 BUG_ON(req_paddr & 31);
13666 BUG_ON(req_size < sizeof(ADV_SCSI_REQ_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013667
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013668 /* Wait for assertion before making little-endian */
13669 req_paddr = cpu_to_le32(req_paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013670
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013671 /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
13672 scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq));
13673 scsiq->scsiq_rptr = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013674
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013675 scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp));
13676 /*
13677 * Every ADV_CARR_T.carr_pa is byte swapped to little-endian
13678 * order during initialization.
13679 */
13680 scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013681
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013682 /*
13683 * Use the current stopper to send the ADV_SCSI_REQ_Q command to
13684 * the microcode. The newly allocated stopper will become the new
13685 * stopper.
13686 */
13687 asc_dvc->icq_sp->areq_vpa = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013688
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013689 /*
13690 * Set the 'next_vpa' pointer for the old stopper to be the
13691 * physical address of the new stopper. The RISC can only
13692 * follow physical addresses.
13693 */
13694 asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013695
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013696 /*
13697 * Set the host adapter stopper pointer to point to the new carrier.
13698 */
13699 asc_dvc->icq_sp = new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013700
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013701 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
13702 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
13703 /*
13704 * Tickle the RISC to tell it to read its Command Queue Head pointer.
13705 */
13706 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
13707 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
13708 /*
13709 * Clear the tickle value. In the ASC-3550 the RISC flag
13710 * command 'clr_tickle_a' does not work unless the host
13711 * value is cleared.
13712 */
13713 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
13714 ADV_TICKLE_NOP);
13715 }
13716 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
13717 /*
13718 * Notify the RISC a carrier is ready by writing the physical
13719 * address of the new carrier stopper to the COMMA register.
13720 */
13721 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
13722 le32_to_cpu(new_carrp->carr_pa));
13723 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013724
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013725 return ADV_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013726}
13727
13728/*
13729 * Reset SCSI Bus and purge all outstanding requests.
13730 *
13731 * Return Value:
13732 * ADV_TRUE(1) - All requests are purged and SCSI Bus is reset.
13733 * ADV_FALSE(0) - Microcode command failed.
13734 * ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC
13735 * may be hung which requires driver recovery.
13736 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013737static int AdvResetSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013738{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013739 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013740
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013741 /*
13742 * Send the SCSI Bus Reset idle start idle command which asserts
13743 * the SCSI Bus Reset signal.
13744 */
13745 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_START, 0L);
13746 if (status != ADV_TRUE) {
13747 return status;
13748 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013749
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013750 /*
13751 * Delay for the specified SCSI Bus Reset hold time.
13752 *
13753 * The hold time delay is done on the host because the RISC has no
13754 * microsecond accurate timer.
13755 */
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060013756 udelay(ASC_SCSI_RESET_HOLD_TIME_US);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013757
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013758 /*
13759 * Send the SCSI Bus Reset end idle command which de-asserts
13760 * the SCSI Bus Reset signal and purges any pending requests.
13761 */
13762 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_END, 0L);
13763 if (status != ADV_TRUE) {
13764 return status;
13765 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013766
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060013767 mdelay(asc_dvc->scsi_reset_wait * 1000); /* XXX: msleep? */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013768
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013769 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013770}
13771
13772/*
13773 * Reset chip and SCSI Bus.
13774 *
13775 * Return Value:
13776 * ADV_TRUE(1) - Chip re-initialization and SCSI Bus Reset successful.
13777 * ADV_FALSE(0) - Chip re-initialization and SCSI Bus Reset failure.
13778 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013779static int AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013780{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013781 int status;
13782 ushort wdtr_able, sdtr_able, tagqng_able;
13783 ushort ppr_able = 0;
13784 uchar tid, max_cmd[ADV_MAX_TID + 1];
13785 AdvPortAddr iop_base;
13786 ushort bios_sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013787
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013788 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013789
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013790 /*
13791 * Save current per TID negotiated values.
13792 */
13793 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
13794 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
13795 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
13796 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
13797 }
13798 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
13799 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
13800 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
13801 max_cmd[tid]);
13802 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013803
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013804 /*
13805 * Force the AdvInitAsc3550/38C0800Driver() function to
13806 * perform a SCSI Bus Reset by clearing the BIOS signature word.
13807 * The initialization functions assumes a SCSI Bus Reset is not
13808 * needed if the BIOS signature word is present.
13809 */
13810 AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
13811 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013812
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013813 /*
13814 * Stop chip and reset it.
13815 */
13816 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP);
13817 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060013818 mdelay(100);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013819 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
13820 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013821
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013822 /*
13823 * Reset Adv Library error code, if any, and try
13824 * re-initializing the chip.
13825 */
13826 asc_dvc->err_code = 0;
13827 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
13828 status = AdvInitAsc38C1600Driver(asc_dvc);
13829 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
13830 status = AdvInitAsc38C0800Driver(asc_dvc);
13831 } else {
13832 status = AdvInitAsc3550Driver(asc_dvc);
13833 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013834
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013835 /* Translate initialization return value to status value. */
13836 if (status == 0) {
13837 status = ADV_TRUE;
13838 } else {
13839 status = ADV_FALSE;
13840 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013841
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013842 /*
13843 * Restore the BIOS signature word.
13844 */
13845 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013846
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013847 /*
13848 * Restore per TID negotiated values.
13849 */
13850 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
13851 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
13852 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
13853 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
13854 }
13855 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
13856 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
13857 AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
13858 max_cmd[tid]);
13859 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013860
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013861 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013862}
13863
13864/*
13865 * Adv Library Interrupt Service Routine
13866 *
13867 * This function is called by a driver's interrupt service routine.
13868 * The function disables and re-enables interrupts.
13869 *
13870 * When a microcode idle command is completed, the ADV_DVC_VAR
13871 * 'idle_cmd_done' field is set to ADV_TRUE.
13872 *
13873 * Note: AdvISR() can be called when interrupts are disabled or even
13874 * when there is no hardware interrupt condition present. It will
13875 * always check for completed idle commands and microcode requests.
13876 * This is an important feature that shouldn't be changed because it
13877 * allows commands to be completed from polling mode loops.
13878 *
13879 * Return:
13880 * ADV_TRUE(1) - interrupt was pending
13881 * ADV_FALSE(0) - no interrupt was pending
13882 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013883static int AdvISR(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013884{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013885 AdvPortAddr iop_base;
13886 uchar int_stat;
13887 ushort target_bit;
13888 ADV_CARR_T *free_carrp;
13889 ADV_VADDR irq_next_vpa;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013890 ADV_SCSI_REQ_Q *scsiq;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013891
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013892 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013893
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013894 /* Reading the register clears the interrupt. */
13895 int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013896
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013897 if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB |
13898 ADV_INTR_STATUS_INTRC)) == 0) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013899 return ADV_FALSE;
13900 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013901
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013902 /*
13903 * Notify the driver of an asynchronous microcode condition by
Matthew Wilcox895d6b42007-07-26 11:57:06 -040013904 * calling the adv_async_callback function. The function
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013905 * is passed the microcode ASC_MC_INTRB_CODE byte value.
13906 */
13907 if (int_stat & ADV_INTR_STATUS_INTRB) {
13908 uchar intrb_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013909
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013910 AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013911
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013912 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
13913 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
13914 if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
13915 asc_dvc->carr_pending_cnt != 0) {
13916 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
13917 ADV_TICKLE_A);
13918 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
13919 AdvWriteByteRegister(iop_base,
13920 IOPB_TICKLE,
13921 ADV_TICKLE_NOP);
13922 }
13923 }
13924 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013925
Matthew Wilcox895d6b42007-07-26 11:57:06 -040013926 adv_async_callback(asc_dvc, intrb_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013927 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013928
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013929 /*
13930 * Check if the IRQ stopper carrier contains a completed request.
13931 */
13932 while (((irq_next_vpa =
13933 le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0) {
13934 /*
13935 * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
13936 * The RISC will have set 'areq_vpa' to a virtual address.
13937 *
13938 * The firmware will have copied the ASC_SCSI_REQ_Q.scsiq_ptr
13939 * field to the carrier ADV_CARR_T.areq_vpa field. The conversion
13940 * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr'
13941 * in AdvExeScsiQueue().
13942 */
13943 scsiq = (ADV_SCSI_REQ_Q *)
13944 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013945
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013946 /*
13947 * Request finished with good status and the queue was not
13948 * DMAed to host memory by the firmware. Set all status fields
13949 * to indicate good status.
13950 */
13951 if ((irq_next_vpa & ASC_RQ_GOOD) != 0) {
13952 scsiq->done_status = QD_NO_ERROR;
13953 scsiq->host_status = scsiq->scsi_status = 0;
13954 scsiq->data_cnt = 0L;
13955 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013956
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013957 /*
13958 * Advance the stopper pointer to the next carrier
13959 * ignoring the lower four bits. Free the previous
13960 * stopper carrier.
13961 */
13962 free_carrp = asc_dvc->irq_sp;
13963 asc_dvc->irq_sp = (ADV_CARR_T *)
13964 ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013965
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013966 free_carrp->next_vpa =
13967 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
13968 asc_dvc->carr_freelist = free_carrp;
13969 asc_dvc->carr_pending_cnt--;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013970
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013971 target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013972
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013973 /*
13974 * Clear request microcode control flag.
13975 */
13976 scsiq->cntl = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013977
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013978 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013979 * Notify the driver of the completed request by passing
13980 * the ADV_SCSI_REQ_Q pointer to its callback function.
13981 */
13982 scsiq->a_flag |= ADV_SCSIQ_DONE;
Matthew Wilcox895d6b42007-07-26 11:57:06 -040013983 adv_isr_callback(asc_dvc, scsiq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013984 /*
13985 * Note: After the driver callback function is called, 'scsiq'
13986 * can no longer be referenced.
13987 *
13988 * Fall through and continue processing other completed
13989 * requests...
13990 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013991 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013992 return ADV_TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013993}
13994
13995/*
13996 * Send an idle command to the chip and wait for completion.
13997 *
13998 * Command completion is polled for once per microsecond.
13999 *
14000 * The function can be called from anywhere including an interrupt handler.
14001 * But the function is not re-entrant, so it uses the DvcEnter/LeaveCritical()
14002 * functions to prevent reentrancy.
14003 *
14004 * Return Values:
14005 * ADV_TRUE - command completed successfully
14006 * ADV_FALSE - command failed
14007 * ADV_ERROR - command timed out
14008 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014009static int
Linus Torvalds1da177e2005-04-16 15:20:36 -070014010AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014011 ushort idle_cmd, ADV_DCNT idle_cmd_parameter)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014012{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014013 int result;
14014 ADV_DCNT i, j;
14015 AdvPortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014016
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014017 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014018
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014019 /*
14020 * Clear the idle command status which is set by the microcode
14021 * to a non-zero value to indicate when the command is completed.
14022 * The non-zero result is one of the IDLE_CMD_STATUS_* values
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014023 */
14024 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort)0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014025
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014026 /*
14027 * Write the idle command value after the idle command parameter
14028 * has been written to avoid a race condition. If the order is not
14029 * followed, the microcode may process the idle command before the
14030 * parameters have been written to LRAM.
14031 */
14032 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
14033 cpu_to_le32(idle_cmd_parameter));
14034 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014035
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014036 /*
14037 * Tickle the RISC to tell it to process the idle command.
14038 */
14039 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B);
14040 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
14041 /*
14042 * Clear the tickle value. In the ASC-3550 the RISC flag
14043 * command 'clr_tickle_b' does not work unless the host
14044 * value is cleared.
14045 */
14046 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
14047 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014048
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014049 /* Wait for up to 100 millisecond for the idle command to timeout. */
14050 for (i = 0; i < SCSI_WAIT_100_MSEC; i++) {
14051 /* Poll once each microsecond for command completion. */
14052 for (j = 0; j < SCSI_US_PER_MSEC; j++) {
14053 AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS,
14054 result);
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060014055 if (result != 0)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014056 return result;
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060014057 udelay(1);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014058 }
14059 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014060
Matthew Wilcoxb009bef2007-09-09 08:56:38 -060014061 BUG(); /* The idle command should never timeout. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014062 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014063}
14064
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060014065static int __devinit
14066advansys_wide_init_chip(asc_board_t *boardp, ADV_DVC_VAR *adv_dvc_varp)
14067{
14068 int req_cnt = 0;
14069 adv_req_t *reqp = NULL;
14070 int sg_cnt = 0;
14071 adv_sgblk_t *sgp;
14072 int warn_code, err_code;
14073
14074 /*
14075 * Allocate buffer carrier structures. The total size
14076 * is about 4 KB, so allocate all at once.
14077 */
14078 boardp->carrp = kmalloc(ADV_CARRIER_BUFSIZE, GFP_KERNEL);
14079 ASC_DBG1(1, "advansys_wide_init_chip: carrp 0x%p\n", boardp->carrp);
14080
14081 if (!boardp->carrp)
14082 goto kmalloc_failed;
14083
14084 /*
14085 * Allocate up to 'max_host_qng' request structures for the Wide
14086 * board. The total size is about 16 KB, so allocate all at once.
14087 * If the allocation fails decrement and try again.
14088 */
14089 for (req_cnt = adv_dvc_varp->max_host_qng; req_cnt > 0; req_cnt--) {
14090 reqp = kmalloc(sizeof(adv_req_t) * req_cnt, GFP_KERNEL);
14091
14092 ASC_DBG3(1, "advansys_wide_init_chip: reqp 0x%p, req_cnt %d, "
14093 "bytes %lu\n", reqp, req_cnt,
14094 (ulong)sizeof(adv_req_t) * req_cnt);
14095
14096 if (reqp)
14097 break;
14098 }
14099
14100 if (!reqp)
14101 goto kmalloc_failed;
14102
14103 boardp->orig_reqp = reqp;
14104
14105 /*
14106 * Allocate up to ADV_TOT_SG_BLOCK request structures for
14107 * the Wide board. Each structure is about 136 bytes.
14108 */
14109 boardp->adv_sgblkp = NULL;
14110 for (sg_cnt = 0; sg_cnt < ADV_TOT_SG_BLOCK; sg_cnt++) {
14111 sgp = kmalloc(sizeof(adv_sgblk_t), GFP_KERNEL);
14112
14113 if (!sgp)
14114 break;
14115
14116 sgp->next_sgblkp = boardp->adv_sgblkp;
14117 boardp->adv_sgblkp = sgp;
14118
14119 }
14120
14121 ASC_DBG3(1, "advansys_wide_init_chip: sg_cnt %d * %u = %u bytes\n",
14122 sg_cnt, sizeof(adv_sgblk_t),
14123 (unsigned)(sizeof(adv_sgblk_t) * sg_cnt));
14124
14125 if (!boardp->adv_sgblkp)
14126 goto kmalloc_failed;
14127
14128 adv_dvc_varp->carrier_buf = boardp->carrp;
14129
14130 /*
14131 * Point 'adv_reqp' to the request structures and
14132 * link them together.
14133 */
14134 req_cnt--;
14135 reqp[req_cnt].next_reqp = NULL;
14136 for (; req_cnt > 0; req_cnt--) {
14137 reqp[req_cnt - 1].next_reqp = &reqp[req_cnt];
14138 }
14139 boardp->adv_reqp = &reqp[0];
14140
14141 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
14142 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc3550Driver()\n");
14143 warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
14144 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
14145 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc38C0800Driver()"
14146 "\n");
14147 warn_code = AdvInitAsc38C0800Driver(adv_dvc_varp);
14148 } else {
14149 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc38C1600Driver()"
14150 "\n");
14151 warn_code = AdvInitAsc38C1600Driver(adv_dvc_varp);
14152 }
14153 err_code = adv_dvc_varp->err_code;
14154
14155 if (warn_code || err_code) {
14156 ASC_PRINT3("advansys_wide_init_chip: board %d error: warn 0x%x,"
14157 " error 0x%x\n", boardp->id, warn_code, err_code);
14158 }
14159
14160 goto exit;
14161
14162 kmalloc_failed:
14163 ASC_PRINT1("advansys_wide_init_chip: board %d error: kmalloc() "
14164 "failed\n", boardp->id);
14165 err_code = ADV_ERROR;
14166 exit:
14167 return err_code;
14168}
14169
14170static void advansys_wide_free_mem(asc_board_t *boardp)
14171{
14172 kfree(boardp->carrp);
14173 boardp->carrp = NULL;
14174 kfree(boardp->orig_reqp);
14175 boardp->orig_reqp = boardp->adv_reqp = NULL;
14176 while (boardp->adv_sgblkp) {
14177 adv_sgblk_t *sgp = boardp->adv_sgblkp;
14178 boardp->adv_sgblkp = sgp->next_sgblkp;
14179 kfree(sgp);
14180 }
14181}
14182
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014183static struct Scsi_Host *__devinit
14184advansys_board_found(int iop, struct device *dev, int bus_type)
14185{
14186 struct Scsi_Host *shost;
14187 struct pci_dev *pdev = bus_type == ASC_IS_PCI ? to_pci_dev(dev) : NULL;
14188 asc_board_t *boardp;
14189 ASC_DVC_VAR *asc_dvc_varp = NULL;
14190 ADV_DVC_VAR *adv_dvc_varp = NULL;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060014191 int share_irq;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014192 int warn_code, err_code;
14193 int ret;
14194
14195 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014196 * Register the adapter, get its configuration, and
14197 * initialize it.
14198 */
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060014199 ASC_DBG(2, "advansys_board_found: scsi_host_alloc()\n");
14200 shost = scsi_host_alloc(&advansys_template, sizeof(asc_board_t));
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014201 if (!shost)
14202 return NULL;
14203
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014204 /* Initialize private per board data */
14205 boardp = ASC_BOARDP(shost);
14206 memset(boardp, 0, sizeof(asc_board_t));
Matthew Wilcox78e77d82007-07-29 21:46:15 -060014207 boardp->id = asc_board_count++;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014208 spin_lock_init(&boardp->lock);
Matthew Wilcox394dbf32007-07-26 11:56:40 -040014209 boardp->dev = dev;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014210
14211 /*
14212 * Handle both narrow and wide boards.
14213 *
14214 * If a Wide board was detected, set the board structure
14215 * wide board flag. Set-up the board structure based on
14216 * the board type.
14217 */
14218#ifdef CONFIG_PCI
14219 if (bus_type == ASC_IS_PCI &&
14220 (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW ||
14221 pdev->device == PCI_DEVICE_ID_38C0800_REV1 ||
14222 pdev->device == PCI_DEVICE_ID_38C1600_REV1)) {
14223 boardp->flags |= ASC_IS_WIDE_BOARD;
14224 }
14225#endif /* CONFIG_PCI */
14226
14227 if (ASC_NARROW_BOARD(boardp)) {
14228 ASC_DBG(1, "advansys_board_found: narrow board\n");
14229 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
14230 asc_dvc_varp->bus_type = bus_type;
14231 asc_dvc_varp->drv_ptr = boardp;
14232 asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg;
14233 asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
14234 asc_dvc_varp->iop_base = iop;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014235 } else {
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040014236#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014237 ASC_DBG(1, "advansys_board_found: wide board\n");
14238 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
14239 adv_dvc_varp->drv_ptr = boardp;
14240 adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014241 if (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW) {
14242 ASC_DBG(1, "advansys_board_found: ASC-3550\n");
14243 adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
14244 } else if (pdev->device == PCI_DEVICE_ID_38C0800_REV1) {
14245 ASC_DBG(1, "advansys_board_found: ASC-38C0800\n");
14246 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
14247 } else {
14248 ASC_DBG(1, "advansys_board_found: ASC-38C1600\n");
14249 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C1600;
14250 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014251
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040014252 boardp->asc_n_io_port = pci_resource_len(pdev, 1);
14253 boardp->ioremap_addr = ioremap(pci_resource_start(pdev, 1),
14254 boardp->asc_n_io_port);
14255 if (!boardp->ioremap_addr) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014256 ASC_PRINT3
14257 ("advansys_board_found: board %d: ioremap(%x, %d) returned NULL\n",
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040014258 boardp->id, pci_resource_start(pdev, 1),
14259 boardp->asc_n_io_port);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060014260 goto err_shost;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014261 }
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040014262 adv_dvc_varp->iop_base = (AdvPortAddr)boardp->ioremap_addr
Matthew Wilcox71f361152007-07-30 08:04:53 -060014263 ASC_DBG1(1, "advansys_board_found: iop_base: 0x%lx\n",
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014264 adv_dvc_varp->iop_base);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014265
14266 /*
14267 * Even though it isn't used to access wide boards, other
14268 * than for the debug line below, save I/O Port address so
14269 * that it can be reported.
14270 */
14271 boardp->ioport = iop;
14272
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040014273 ASC_DBG2(1, "advansys_board_found: iopb_chip_id_1 0x%x, "
14274 "iopw_chip_id_0 0x%x\n", (ushort)inp(iop + 1),
14275 (ushort)inpw(iop));
14276#endif /* CONFIG_PCI */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014277 }
14278
14279#ifdef CONFIG_PROC_FS
14280 /*
14281 * Allocate buffer for printing information from
14282 * /proc/scsi/advansys/[0...].
14283 */
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060014284 boardp->prtbuf = kmalloc(ASC_PRTBUF_SIZE, GFP_KERNEL);
14285 if (!boardp->prtbuf) {
14286 ASC_PRINT2("advansys_board_found: board %d: kmalloc(%d) "
14287 "returned NULL\n", boardp->id, ASC_PRTBUF_SIZE);
14288 goto err_unmap;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014289 }
14290#endif /* CONFIG_PROC_FS */
14291
14292 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014293 /*
14294 * Set the board bus type and PCI IRQ before
14295 * calling AscInitGetConfig().
14296 */
14297 switch (asc_dvc_varp->bus_type) {
14298#ifdef CONFIG_ISA
14299 case ASC_IS_ISA:
14300 shost->unchecked_isa_dma = TRUE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060014301 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014302 break;
14303 case ASC_IS_VL:
14304 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060014305 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014306 break;
14307 case ASC_IS_EISA:
14308 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060014309 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014310 break;
14311#endif /* CONFIG_ISA */
14312#ifdef CONFIG_PCI
14313 case ASC_IS_PCI:
14314 shost->irq = asc_dvc_varp->irq_no = pdev->irq;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014315 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060014316 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014317 break;
14318#endif /* CONFIG_PCI */
14319 default:
14320 ASC_PRINT2
14321 ("advansys_board_found: board %d: unknown adapter type: %d\n",
14322 boardp->id, asc_dvc_varp->bus_type);
14323 shost->unchecked_isa_dma = TRUE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060014324 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014325 break;
14326 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014327
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014328 /*
14329 * NOTE: AscInitGetConfig() may change the board's
14330 * bus_type value. The bus_type value should no
14331 * longer be used. If the bus_type field must be
14332 * referenced only use the bit-wise AND operator "&".
14333 */
14334 ASC_DBG(2, "advansys_board_found: AscInitGetConfig()\n");
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060014335 err_code = AscInitGetConfig(boardp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014336 } else {
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060014337#ifdef CONFIG_PCI
14338 /*
14339 * For Wide boards set PCI information before calling
14340 * AdvInitGetConfig().
14341 */
14342 shost->irq = adv_dvc_varp->irq_no = pdev->irq;
14343 shost->unchecked_isa_dma = FALSE;
14344 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014345 ASC_DBG(2, "advansys_board_found: AdvInitGetConfig()\n");
Matthew Wilcox394dbf32007-07-26 11:56:40 -040014346
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060014347 err_code = AdvInitGetConfig(pdev, boardp);
14348#endif /* CONFIG_PCI */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014349 }
14350
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060014351 if (err_code != 0)
14352 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014353
14354 /*
14355 * Save the EEPROM configuration so that it can be displayed
14356 * from /proc/scsi/advansys/[0...].
14357 */
14358 if (ASC_NARROW_BOARD(boardp)) {
14359
14360 ASCEEP_CONFIG *ep;
14361
14362 /*
14363 * Set the adapter's target id bit in the 'init_tidmask' field.
14364 */
14365 boardp->init_tidmask |=
14366 ADV_TID_TO_TIDMASK(asc_dvc_varp->cfg->chip_scsi_id);
14367
14368 /*
14369 * Save EEPROM settings for the board.
14370 */
14371 ep = &boardp->eep_config.asc_eep;
14372
14373 ep->init_sdtr = asc_dvc_varp->cfg->sdtr_enable;
14374 ep->disc_enable = asc_dvc_varp->cfg->disc_enable;
14375 ep->use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled;
14376 ASC_EEP_SET_DMA_SPD(ep, asc_dvc_varp->cfg->isa_dma_speed);
14377 ep->start_motor = asc_dvc_varp->start_motor;
14378 ep->cntl = asc_dvc_varp->dvc_cntl;
14379 ep->no_scam = asc_dvc_varp->no_scam;
14380 ep->max_total_qng = asc_dvc_varp->max_total_qng;
14381 ASC_EEP_SET_CHIP_ID(ep, asc_dvc_varp->cfg->chip_scsi_id);
14382 /* 'max_tag_qng' is set to the same value for every device. */
14383 ep->max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0];
14384 ep->adapter_info[0] = asc_dvc_varp->cfg->adapter_info[0];
14385 ep->adapter_info[1] = asc_dvc_varp->cfg->adapter_info[1];
14386 ep->adapter_info[2] = asc_dvc_varp->cfg->adapter_info[2];
14387 ep->adapter_info[3] = asc_dvc_varp->cfg->adapter_info[3];
14388 ep->adapter_info[4] = asc_dvc_varp->cfg->adapter_info[4];
14389 ep->adapter_info[5] = asc_dvc_varp->cfg->adapter_info[5];
14390
14391 /*
14392 * Modify board configuration.
14393 */
14394 ASC_DBG(2, "advansys_board_found: AscInitSetConfig()\n");
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060014395 err_code = AscInitSetConfig(pdev, boardp);
14396 if (err_code)
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060014397 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014398
14399 /*
14400 * Finish initializing the 'Scsi_Host' structure.
14401 */
14402 /* AscInitSetConfig() will set the IRQ for non-PCI boards. */
14403 if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
14404 shost->irq = asc_dvc_varp->irq_no;
14405 }
14406 } else {
14407 ADVEEP_3550_CONFIG *ep_3550;
14408 ADVEEP_38C0800_CONFIG *ep_38C0800;
14409 ADVEEP_38C1600_CONFIG *ep_38C1600;
14410
14411 /*
14412 * Save Wide EEP Configuration Information.
14413 */
14414 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
14415 ep_3550 = &boardp->eep_config.adv_3550_eep;
14416
14417 ep_3550->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
14418 ep_3550->max_host_qng = adv_dvc_varp->max_host_qng;
14419 ep_3550->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
14420 ep_3550->termination = adv_dvc_varp->cfg->termination;
14421 ep_3550->disc_enable = adv_dvc_varp->cfg->disc_enable;
14422 ep_3550->bios_ctrl = adv_dvc_varp->bios_ctrl;
14423 ep_3550->wdtr_able = adv_dvc_varp->wdtr_able;
14424 ep_3550->sdtr_able = adv_dvc_varp->sdtr_able;
14425 ep_3550->ultra_able = adv_dvc_varp->ultra_able;
14426 ep_3550->tagqng_able = adv_dvc_varp->tagqng_able;
14427 ep_3550->start_motor = adv_dvc_varp->start_motor;
14428 ep_3550->scsi_reset_delay =
14429 adv_dvc_varp->scsi_reset_wait;
14430 ep_3550->serial_number_word1 =
14431 adv_dvc_varp->cfg->serial1;
14432 ep_3550->serial_number_word2 =
14433 adv_dvc_varp->cfg->serial2;
14434 ep_3550->serial_number_word3 =
14435 adv_dvc_varp->cfg->serial3;
14436 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
14437 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
14438
14439 ep_38C0800->adapter_scsi_id =
14440 adv_dvc_varp->chip_scsi_id;
14441 ep_38C0800->max_host_qng = adv_dvc_varp->max_host_qng;
14442 ep_38C0800->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
14443 ep_38C0800->termination_lvd =
14444 adv_dvc_varp->cfg->termination;
14445 ep_38C0800->disc_enable =
14446 adv_dvc_varp->cfg->disc_enable;
14447 ep_38C0800->bios_ctrl = adv_dvc_varp->bios_ctrl;
14448 ep_38C0800->wdtr_able = adv_dvc_varp->wdtr_able;
14449 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
14450 ep_38C0800->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
14451 ep_38C0800->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
14452 ep_38C0800->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
14453 ep_38C0800->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
14454 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
14455 ep_38C0800->start_motor = adv_dvc_varp->start_motor;
14456 ep_38C0800->scsi_reset_delay =
14457 adv_dvc_varp->scsi_reset_wait;
14458 ep_38C0800->serial_number_word1 =
14459 adv_dvc_varp->cfg->serial1;
14460 ep_38C0800->serial_number_word2 =
14461 adv_dvc_varp->cfg->serial2;
14462 ep_38C0800->serial_number_word3 =
14463 adv_dvc_varp->cfg->serial3;
14464 } else {
14465 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
14466
14467 ep_38C1600->adapter_scsi_id =
14468 adv_dvc_varp->chip_scsi_id;
14469 ep_38C1600->max_host_qng = adv_dvc_varp->max_host_qng;
14470 ep_38C1600->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
14471 ep_38C1600->termination_lvd =
14472 adv_dvc_varp->cfg->termination;
14473 ep_38C1600->disc_enable =
14474 adv_dvc_varp->cfg->disc_enable;
14475 ep_38C1600->bios_ctrl = adv_dvc_varp->bios_ctrl;
14476 ep_38C1600->wdtr_able = adv_dvc_varp->wdtr_able;
14477 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
14478 ep_38C1600->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
14479 ep_38C1600->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
14480 ep_38C1600->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
14481 ep_38C1600->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
14482 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
14483 ep_38C1600->start_motor = adv_dvc_varp->start_motor;
14484 ep_38C1600->scsi_reset_delay =
14485 adv_dvc_varp->scsi_reset_wait;
14486 ep_38C1600->serial_number_word1 =
14487 adv_dvc_varp->cfg->serial1;
14488 ep_38C1600->serial_number_word2 =
14489 adv_dvc_varp->cfg->serial2;
14490 ep_38C1600->serial_number_word3 =
14491 adv_dvc_varp->cfg->serial3;
14492 }
14493
14494 /*
14495 * Set the adapter's target id bit in the 'init_tidmask' field.
14496 */
14497 boardp->init_tidmask |=
14498 ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014499 }
14500
14501 /*
14502 * Channels are numbered beginning with 0. For AdvanSys one host
14503 * structure supports one channel. Multi-channel boards have a
14504 * separate host structure for each channel.
14505 */
14506 shost->max_channel = 0;
14507 if (ASC_NARROW_BOARD(boardp)) {
14508 shost->max_id = ASC_MAX_TID + 1;
14509 shost->max_lun = ASC_MAX_LUN + 1;
Matthew Wilcoxf05ec592007-09-09 08:56:36 -060014510 shost->max_cmd_len = ASC_MAX_CDB_LEN;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014511
14512 shost->io_port = asc_dvc_varp->iop_base;
14513 boardp->asc_n_io_port = ASC_IOADR_GAP;
14514 shost->this_id = asc_dvc_varp->cfg->chip_scsi_id;
14515
14516 /* Set maximum number of queues the adapter can handle. */
14517 shost->can_queue = asc_dvc_varp->max_total_qng;
14518 } else {
14519 shost->max_id = ADV_MAX_TID + 1;
14520 shost->max_lun = ADV_MAX_LUN + 1;
Matthew Wilcoxf05ec592007-09-09 08:56:36 -060014521 shost->max_cmd_len = ADV_MAX_CDB_LEN;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014522
14523 /*
14524 * Save the I/O Port address and length even though
14525 * I/O ports are not used to access Wide boards.
14526 * Instead the Wide boards are accessed with
14527 * PCI Memory Mapped I/O.
14528 */
14529 shost->io_port = iop;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014530
14531 shost->this_id = adv_dvc_varp->chip_scsi_id;
14532
14533 /* Set maximum number of queues the adapter can handle. */
14534 shost->can_queue = adv_dvc_varp->max_host_qng;
14535 }
14536
14537 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014538 * Following v1.3.89, 'cmd_per_lun' is no longer needed
14539 * and should be set to zero.
14540 *
14541 * But because of a bug introduced in v1.3.89 if the driver is
14542 * compiled as a module and 'cmd_per_lun' is zero, the Mid-Level
14543 * SCSI function 'allocate_device' will panic. To allow the driver
14544 * to work as a module in these kernels set 'cmd_per_lun' to 1.
14545 *
14546 * Note: This is wrong. cmd_per_lun should be set to the depth
14547 * you want on untagged devices always.
14548 #ifdef MODULE
14549 */
14550 shost->cmd_per_lun = 1;
14551/* #else
14552 shost->cmd_per_lun = 0;
14553#endif */
14554
14555 /*
14556 * Set the maximum number of scatter-gather elements the
14557 * adapter can handle.
14558 */
14559 if (ASC_NARROW_BOARD(boardp)) {
14560 /*
14561 * Allow two commands with 'sg_tablesize' scatter-gather
14562 * elements to be executed simultaneously. This value is
14563 * the theoretical hardware limit. It may be decreased
14564 * below.
14565 */
14566 shost->sg_tablesize =
14567 (((asc_dvc_varp->max_total_qng - 2) / 2) *
14568 ASC_SG_LIST_PER_Q) + 1;
14569 } else {
14570 shost->sg_tablesize = ADV_MAX_SG_LIST;
14571 }
14572
14573 /*
14574 * The value of 'sg_tablesize' can not exceed the SCSI
14575 * mid-level driver definition of SG_ALL. SG_ALL also
14576 * must not be exceeded, because it is used to define the
14577 * size of the scatter-gather table in 'struct asc_sg_head'.
14578 */
14579 if (shost->sg_tablesize > SG_ALL) {
14580 shost->sg_tablesize = SG_ALL;
14581 }
14582
14583 ASC_DBG1(1, "advansys_board_found: sg_tablesize: %d\n", shost->sg_tablesize);
14584
14585 /* BIOS start address. */
14586 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060014587 shost->base = AscGetChipBiosAddress(asc_dvc_varp->iop_base,
14588 asc_dvc_varp->bus_type);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014589 } else {
14590 /*
14591 * Fill-in BIOS board variables. The Wide BIOS saves
14592 * information in LRAM that is used by the driver.
14593 */
14594 AdvReadWordLram(adv_dvc_varp->iop_base,
14595 BIOS_SIGNATURE, boardp->bios_signature);
14596 AdvReadWordLram(adv_dvc_varp->iop_base,
14597 BIOS_VERSION, boardp->bios_version);
14598 AdvReadWordLram(adv_dvc_varp->iop_base,
14599 BIOS_CODESEG, boardp->bios_codeseg);
14600 AdvReadWordLram(adv_dvc_varp->iop_base,
14601 BIOS_CODELEN, boardp->bios_codelen);
14602
14603 ASC_DBG2(1,
14604 "advansys_board_found: bios_signature 0x%x, bios_version 0x%x\n",
14605 boardp->bios_signature, boardp->bios_version);
14606
14607 ASC_DBG2(1,
14608 "advansys_board_found: bios_codeseg 0x%x, bios_codelen 0x%x\n",
14609 boardp->bios_codeseg, boardp->bios_codelen);
14610
14611 /*
14612 * If the BIOS saved a valid signature, then fill in
14613 * the BIOS code segment base address.
14614 */
14615 if (boardp->bios_signature == 0x55AA) {
14616 /*
14617 * Convert x86 realmode code segment to a linear
14618 * address by shifting left 4.
14619 */
14620 shost->base = ((ulong)boardp->bios_codeseg << 4);
14621 } else {
14622 shost->base = 0;
14623 }
14624 }
14625
14626 /*
14627 * Register Board Resources - I/O Port, DMA, IRQ
14628 */
14629
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014630 /* Register DMA Channel for Narrow boards. */
14631 shost->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */
14632#ifdef CONFIG_ISA
14633 if (ASC_NARROW_BOARD(boardp)) {
14634 /* Register DMA channel for ISA bus. */
14635 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
14636 shost->dma_channel = asc_dvc_varp->cfg->isa_dma_channel;
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060014637 ret = request_dma(shost->dma_channel, "advansys");
14638 if (ret) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014639 ASC_PRINT3
14640 ("advansys_board_found: board %d: request_dma() %d failed %d\n",
14641 boardp->id, shost->dma_channel, ret);
Matthew Wilcox71f361152007-07-30 08:04:53 -060014642 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014643 }
14644 AscEnableIsaDma(shost->dma_channel);
14645 }
14646 }
14647#endif /* CONFIG_ISA */
14648
14649 /* Register IRQ Number. */
14650 ASC_DBG1(2, "advansys_board_found: request_irq() %d\n", shost->irq);
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060014651
14652 ret = request_irq(shost->irq, advansys_interrupt, share_irq,
14653 "advansys", shost);
14654
14655 if (ret) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014656 if (ret == -EBUSY) {
14657 ASC_PRINT2
14658 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x already in use.\n",
14659 boardp->id, shost->irq);
14660 } else if (ret == -EINVAL) {
14661 ASC_PRINT2
14662 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x not valid.\n",
14663 boardp->id, shost->irq);
14664 } else {
14665 ASC_PRINT3
14666 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x failed with %d\n",
14667 boardp->id, shost->irq, ret);
14668 }
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060014669 goto err_free_dma;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014670 }
14671
14672 /*
14673 * Initialize board RISC chip and enable interrupts.
14674 */
14675 if (ASC_NARROW_BOARD(boardp)) {
14676 ASC_DBG(2, "advansys_board_found: AscInitAsc1000Driver()\n");
14677 warn_code = AscInitAsc1000Driver(asc_dvc_varp);
14678 err_code = asc_dvc_varp->err_code;
14679
14680 if (warn_code || err_code) {
14681 ASC_PRINT4
14682 ("advansys_board_found: board %d error: init_state 0x%x, warn 0x%x, error 0x%x\n",
14683 boardp->id,
14684 asc_dvc_varp->init_state, warn_code, err_code);
14685 }
14686 } else {
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060014687 err_code = advansys_wide_init_chip(boardp, adv_dvc_varp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014688 }
14689
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060014690 if (err_code != 0)
14691 goto err_free_wide_mem;
14692
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014693 ASC_DBG_PRT_SCSI_HOST(2, shost);
14694
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060014695 ret = scsi_add_host(shost, dev);
14696 if (ret)
14697 goto err_free_wide_mem;
14698
14699 scsi_scan_host(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014700 return shost;
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060014701
14702 err_free_wide_mem:
14703 advansys_wide_free_mem(boardp);
14704 free_irq(shost->irq, shost);
14705 err_free_dma:
14706 if (shost->dma_channel != NO_ISA_DMA)
14707 free_dma(shost->dma_channel);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060014708 err_free_proc:
14709 kfree(boardp->prtbuf);
14710 err_unmap:
14711 if (boardp->ioremap_addr)
14712 iounmap(boardp->ioremap_addr);
14713 err_shost:
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060014714 scsi_host_put(shost);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060014715 return NULL;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014716}
14717
14718/*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014719 * advansys_release()
14720 *
14721 * Release resources allocated for a single AdvanSys adapter.
14722 */
14723static int advansys_release(struct Scsi_Host *shost)
14724{
14725 asc_board_t *boardp;
14726
14727 ASC_DBG(1, "advansys_release: begin\n");
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060014728 scsi_remove_host(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014729 boardp = ASC_BOARDP(shost);
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060014730 free_irq(shost->irq, shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014731 if (shost->dma_channel != NO_ISA_DMA) {
14732 ASC_DBG(1, "advansys_release: free_dma()\n");
14733 free_dma(shost->dma_channel);
14734 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014735 if (ASC_WIDE_BOARD(boardp)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014736 iounmap(boardp->ioremap_addr);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060014737 advansys_wide_free_mem(boardp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014738 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014739 kfree(boardp->prtbuf);
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060014740 scsi_host_put(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014741 ASC_DBG(1, "advansys_release: end\n");
14742 return 0;
14743}
14744
Matthew Wilcox95c9f162007-09-09 08:56:39 -060014745#define ASC_IOADR_TABLE_MAX_IX 11
14746
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060014747static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __devinitdata = {
14748 0x100, 0x0110, 0x120, 0x0130, 0x140, 0x0150, 0x0190,
14749 0x0210, 0x0230, 0x0250, 0x0330
14750};
14751
14752static int __devinit advansys_isa_probe(struct device *dev, unsigned int id)
14753{
14754 PortAddr iop_base = _asc_def_iop_base[id];
14755 struct Scsi_Host *shost;
14756
14757 if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) {
Matthew Wilcox71f361152007-07-30 08:04:53 -060014758 ASC_DBG1(1, "advansys_isa_match: I/O port 0x%x busy\n",
14759 iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060014760 return -ENODEV;
14761 }
14762 ASC_DBG1(1, "advansys_isa_match: probing I/O port 0x%x\n", iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060014763 if (!AscFindSignature(iop_base))
14764 goto nodev;
14765 if (!(AscGetChipVersion(iop_base, ASC_IS_ISA) & ASC_CHIP_VER_ISA_BIT))
14766 goto nodev;
14767
14768 shost = advansys_board_found(iop_base, dev, ASC_IS_ISA);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060014769 if (!shost)
14770 goto nodev;
14771
14772 dev_set_drvdata(dev, shost);
14773 return 0;
14774
14775 nodev:
Matthew Wilcox71f361152007-07-30 08:04:53 -060014776 release_region(iop_base, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060014777 return -ENODEV;
14778}
14779
14780static int __devexit advansys_isa_remove(struct device *dev, unsigned int id)
14781{
Matthew Wilcox71f361152007-07-30 08:04:53 -060014782 int ioport = _asc_def_iop_base[id];
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060014783 advansys_release(dev_get_drvdata(dev));
Matthew Wilcox71f361152007-07-30 08:04:53 -060014784 release_region(ioport, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060014785 return 0;
14786}
14787
14788static struct isa_driver advansys_isa_driver = {
14789 .probe = advansys_isa_probe,
14790 .remove = __devexit_p(advansys_isa_remove),
14791 .driver = {
14792 .owner = THIS_MODULE,
14793 .name = "advansys",
14794 },
14795};
14796
14797static int __devinit advansys_vlb_probe(struct device *dev, unsigned int id)
14798{
14799 PortAddr iop_base = _asc_def_iop_base[id];
14800 struct Scsi_Host *shost;
14801
14802 if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) {
Matthew Wilcox71f361152007-07-30 08:04:53 -060014803 ASC_DBG1(1, "advansys_vlb_match: I/O port 0x%x busy\n",
14804 iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060014805 return -ENODEV;
14806 }
14807 ASC_DBG1(1, "advansys_vlb_match: probing I/O port 0x%x\n", iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060014808 if (!AscFindSignature(iop_base))
14809 goto nodev;
14810 /*
14811 * I don't think this condition can actually happen, but the old
14812 * driver did it, and the chances of finding a VLB setup in 2007
14813 * to do testing with is slight to none.
14814 */
14815 if (AscGetChipVersion(iop_base, ASC_IS_VL) > ASC_CHIP_MAX_VER_VL)
14816 goto nodev;
14817
14818 shost = advansys_board_found(iop_base, dev, ASC_IS_VL);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060014819 if (!shost)
14820 goto nodev;
14821
14822 dev_set_drvdata(dev, shost);
14823 return 0;
14824
14825 nodev:
Matthew Wilcox71f361152007-07-30 08:04:53 -060014826 release_region(iop_base, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060014827 return -ENODEV;
14828}
14829
14830static struct isa_driver advansys_vlb_driver = {
14831 .probe = advansys_vlb_probe,
14832 .remove = __devexit_p(advansys_isa_remove),
14833 .driver = {
14834 .owner = THIS_MODULE,
Matthew Wilcoxb8e5152b2007-09-09 08:56:26 -060014835 .name = "advansys_vlb",
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060014836 },
14837};
14838
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060014839static struct eisa_device_id advansys_eisa_table[] __devinitdata = {
14840 { "ABP7401" },
14841 { "ABP7501" },
14842 { "" }
14843};
14844
14845MODULE_DEVICE_TABLE(eisa, advansys_eisa_table);
14846
14847/*
14848 * EISA is a little more tricky than PCI; each EISA device may have two
14849 * channels, and this driver is written to make each channel its own Scsi_Host
14850 */
14851struct eisa_scsi_data {
14852 struct Scsi_Host *host[2];
14853};
14854
14855static int __devinit advansys_eisa_probe(struct device *dev)
14856{
14857 int i, ioport;
14858 int err;
14859 struct eisa_device *edev = to_eisa_device(dev);
14860 struct eisa_scsi_data *data;
14861
14862 err = -ENOMEM;
14863 data = kzalloc(sizeof(*data), GFP_KERNEL);
14864 if (!data)
14865 goto fail;
14866 ioport = edev->base_addr + 0xc30;
14867
14868 err = -ENODEV;
14869 for (i = 0; i < 2; i++, ioport += 0x20) {
Matthew Wilcox71f361152007-07-30 08:04:53 -060014870 if (!request_region(ioport, ASC_IOADR_GAP, "advansys")) {
14871 printk(KERN_WARNING "Region %x-%x busy\n", ioport,
14872 ioport + ASC_IOADR_GAP - 1);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060014873 continue;
Matthew Wilcox71f361152007-07-30 08:04:53 -060014874 }
14875 if (!AscFindSignature(ioport)) {
14876 release_region(ioport, ASC_IOADR_GAP);
14877 continue;
14878 }
14879
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060014880 /*
14881 * I don't know why we need to do this for EISA chips, but
14882 * not for any others. It looks to be equivalent to
14883 * AscGetChipCfgMsw, but I may have overlooked something,
14884 * so I'm not converting it until I get an EISA board to
14885 * test with.
14886 */
14887 inw(ioport + 4);
14888 data->host[i] = advansys_board_found(ioport, dev, ASC_IS_EISA);
Matthew Wilcox71f361152007-07-30 08:04:53 -060014889 if (data->host[i]) {
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060014890 err = 0;
Matthew Wilcox71f361152007-07-30 08:04:53 -060014891 } else {
14892 release_region(ioport, ASC_IOADR_GAP);
14893 }
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060014894 }
14895
14896 if (err) {
14897 kfree(data);
14898 } else {
14899 dev_set_drvdata(dev, data);
14900 }
14901
14902 fail:
14903 return err;
14904}
14905
14906static __devexit int advansys_eisa_remove(struct device *dev)
14907{
14908 int i;
14909 struct eisa_scsi_data *data = dev_get_drvdata(dev);
14910
14911 for (i = 0; i < 2; i++) {
Matthew Wilcox71f361152007-07-30 08:04:53 -060014912 int ioport;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060014913 struct Scsi_Host *shost = data->host[i];
14914 if (!shost)
14915 continue;
Matthew Wilcox71f361152007-07-30 08:04:53 -060014916 ioport = shost->io_port;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060014917 advansys_release(shost);
Matthew Wilcox71f361152007-07-30 08:04:53 -060014918 release_region(ioport, ASC_IOADR_GAP);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060014919 }
14920
14921 kfree(data);
14922 return 0;
14923}
14924
14925static struct eisa_driver advansys_eisa_driver = {
14926 .id_table = advansys_eisa_table,
14927 .driver = {
14928 .name = "advansys",
14929 .probe = advansys_eisa_probe,
14930 .remove = __devexit_p(advansys_eisa_remove),
14931 }
14932};
14933
Dave Jones2672ea82006-08-02 17:11:49 -040014934/* PCI Devices supported by this driver */
14935static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014936 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A,
14937 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
14938 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940,
14939 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
14940 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940U,
14941 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
14942 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940UW,
14943 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
14944 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C0800_REV1,
14945 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
14946 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C1600_REV1,
14947 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
14948 {}
Dave Jones2672ea82006-08-02 17:11:49 -040014949};
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014950
Dave Jones2672ea82006-08-02 17:11:49 -040014951MODULE_DEVICE_TABLE(pci, advansys_pci_tbl);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060014952
Matthew Wilcox9649af32007-07-26 21:51:47 -060014953static void __devinit advansys_set_latency(struct pci_dev *pdev)
14954{
14955 if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) ||
14956 (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) {
14957 pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0);
14958 } else {
14959 u8 latency;
14960 pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency);
14961 if (latency < 0x20)
14962 pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x20);
14963 }
14964}
14965
Matthew Wilcox78e77d82007-07-29 21:46:15 -060014966static int __devinit
14967advansys_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
14968{
14969 int err, ioport;
14970 struct Scsi_Host *shost;
14971
14972 err = pci_enable_device(pdev);
14973 if (err)
14974 goto fail;
Matthew Wilcox71f361152007-07-30 08:04:53 -060014975 err = pci_request_regions(pdev, "advansys");
14976 if (err)
14977 goto disable_device;
Matthew Wilcox9649af32007-07-26 21:51:47 -060014978 pci_set_master(pdev);
14979 advansys_set_latency(pdev);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060014980
14981 if (pci_resource_len(pdev, 0) == 0)
14982 goto nodev;
14983
14984 ioport = pci_resource_start(pdev, 0);
14985 shost = advansys_board_found(ioport, &pdev->dev, ASC_IS_PCI);
14986
14987 if (!shost)
14988 goto nodev;
14989
14990 pci_set_drvdata(pdev, shost);
14991 return 0;
14992
14993 nodev:
14994 err = -ENODEV;
Matthew Wilcox71f361152007-07-30 08:04:53 -060014995 pci_release_regions(pdev);
14996 disable_device:
Matthew Wilcox78e77d82007-07-29 21:46:15 -060014997 pci_disable_device(pdev);
14998 fail:
14999 return err;
15000}
15001
15002static void __devexit advansys_pci_remove(struct pci_dev *pdev)
15003{
15004 advansys_release(pci_get_drvdata(pdev));
Matthew Wilcox71f361152007-07-30 08:04:53 -060015005 pci_release_regions(pdev);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015006 pci_disable_device(pdev);
15007}
15008
15009static struct pci_driver advansys_pci_driver = {
15010 .name = "advansys",
15011 .id_table = advansys_pci_tbl,
15012 .probe = advansys_pci_probe,
15013 .remove = __devexit_p(advansys_pci_remove),
15014};
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040015015
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060015016static int __init advansys_init(void)
15017{
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015018 int error;
15019
15020 error = isa_register_driver(&advansys_isa_driver,
15021 ASC_IOADR_TABLE_MAX_IX);
15022 if (error)
15023 goto fail;
15024
15025 error = isa_register_driver(&advansys_vlb_driver,
15026 ASC_IOADR_TABLE_MAX_IX);
15027 if (error)
15028 goto unregister_isa;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060015029
15030 error = eisa_driver_register(&advansys_eisa_driver);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015031 if (error)
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015032 goto unregister_vlb;
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060015033
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060015034 error = pci_register_driver(&advansys_pci_driver);
15035 if (error)
15036 goto unregister_eisa;
15037
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060015038 return 0;
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015039
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060015040 unregister_eisa:
15041 eisa_driver_unregister(&advansys_eisa_driver);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015042 unregister_vlb:
15043 isa_unregister_driver(&advansys_vlb_driver);
15044 unregister_isa:
15045 isa_unregister_driver(&advansys_isa_driver);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015046 fail:
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015047 return error;
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060015048}
15049
15050static void __exit advansys_exit(void)
15051{
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015052 pci_unregister_driver(&advansys_pci_driver);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060015053 eisa_driver_unregister(&advansys_eisa_driver);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015054 isa_unregister_driver(&advansys_vlb_driver);
15055 isa_unregister_driver(&advansys_isa_driver);
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060015056}
15057
15058module_init(advansys_init);
15059module_exit(advansys_exit);
15060
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040015061MODULE_LICENSE("GPL");