blob: fe289b1d7ddbfd30772a39fc33846b01709cec93 [file] [log] [blame]
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -04001#define ASC_VERSION "3.4" /* AdvanSys Driver Version */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002
3/*
4 * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
5 *
6 * Copyright (c) 1995-2000 Advanced System Products, Inc.
7 * Copyright (c) 2000-2001 ConnectCom Solutions, Inc.
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -04008 * Copyright (c) 2007 Matthew Wilcox <matthew@wil.cx>
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * All Rights Reserved.
10 *
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040011 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 */
16
17/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070018 * As of March 8, 2000 Advanced System Products, Inc. (AdvanSys)
19 * changed its name to ConnectCom Solutions, Inc.
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040020 * On June 18, 2001 Initio Corp. acquired ConnectCom's SCSI assets
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 */
22
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <linux/string.h>
25#include <linux/kernel.h>
26#include <linux/types.h>
27#include <linux/ioport.h>
28#include <linux/interrupt.h>
29#include <linux/delay.h>
30#include <linux/slab.h>
31#include <linux/mm.h>
32#include <linux/proc_fs.h>
33#include <linux/init.h>
34#include <linux/blkdev.h>
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060035#include <linux/isa.h>
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060036#include <linux/eisa.h>
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040037#include <linux/pci.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <linux/spinlock.h>
39#include <linux/dma-mapping.h>
40
41#include <asm/io.h>
42#include <asm/system.h>
43#include <asm/dma.h>
44
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040045#include <scsi/scsi_cmnd.h>
46#include <scsi/scsi_device.h>
47#include <scsi/scsi_tcq.h>
48#include <scsi/scsi.h>
49#include <scsi/scsi_host.h>
50
Matthew Wilcox4bd6d7f2007-07-30 08:41:03 -060051/* FIXME:
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 *
Matthew Wilcox4bd6d7f2007-07-30 08:41:03 -060053 * 1. Although all of the necessary command mapping places have the
54 * appropriate dma_map.. APIs, the driver still processes its internal
55 * queue using bus_to_virt() and virt_to_bus() which are illegal under
56 * the API. The entire queue processing structure will need to be
57 * altered to fix this.
58 * 2. Need to add memory mapping workaround. Test the memory mapping.
59 * If it doesn't work revert to I/O port access. Can a test be done
60 * safely?
61 * 3. Handle an interrupt not working. Keep an interrupt counter in
62 * the interrupt handler. In the timeout function if the interrupt
63 * has not occurred then print a message and run in polled mode.
64 * 4. Need to add support for target mode commands, cf. CAM XPT.
65 * 5. check DMA mapping functions for failure
66 * 6. Remove internal queueing
67 * 7. Use scsi_transport_spi
68 * 8. advansys_info is not safe against multiple simultaneous callers
69 * 9. Kill boardp->id
70 * 10. Add module_param to override ISA/VLB ioport array
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 */
72#warning this driver is still not properly converted to the DMA API
73
Linus Torvalds1da177e2005-04-16 15:20:36 -070074/* Enable driver assertions. */
75#define ADVANSYS_ASSERT
76
77/* Enable driver /proc statistics. */
78#define ADVANSYS_STATS
79
80/* Enable driver tracing. */
81/* #define ADVANSYS_DEBUG */
82
Linus Torvalds1da177e2005-04-16 15:20:36 -070083/*
84 * --- Asc Library Constants and Macros
85 */
86
87#define ASC_LIB_VERSION_MAJOR 1
88#define ASC_LIB_VERSION_MINOR 24
89#define ASC_LIB_SERIAL_NUMBER 123
90
91/*
92 * Portable Data Types
93 *
94 * Any instance where a 32-bit long or pointer type is assumed
95 * for precision or HW defined structures, the following define
96 * types must be used. In Linux the char, short, and int types
97 * are all consistent at 8, 16, and 32 bits respectively. Pointers
98 * and long types are 64 bits on Alpha and UltraSPARC.
99 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400100#define ASC_PADDR __u32 /* Physical/Bus address data type. */
101#define ASC_VADDR __u32 /* Virtual address data type. */
102#define ASC_DCNT __u32 /* Unsigned Data count type. */
103#define ASC_SDCNT __s32 /* Signed Data count type. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
105/*
106 * These macros are used to convert a virtual address to a
107 * 32-bit value. This currently can be used on Linux Alpha
108 * which uses 64-bit virtual address but a 32-bit bus address.
109 * This is likely to break in the future, but doing this now
110 * will give us time to change the HW and FW to handle 64-bit
111 * addresses.
112 */
113#define ASC_VADDR_TO_U32 virt_to_bus
114#define ASC_U32_TO_VADDR bus_to_virt
115
116typedef unsigned char uchar;
117
118#ifndef TRUE
119#define TRUE (1)
120#endif
121#ifndef FALSE
122#define FALSE (0)
123#endif
124
125#define EOF (-1)
126#define ERR (-1)
127#define UW_ERR (uint)(0xFFFF)
128#define isodd_word(val) ((((uint)val) & (uint)0x0001) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
130#define ASC_DVCLIB_CALL_DONE (1)
131#define ASC_DVCLIB_CALL_FAILED (0)
132#define ASC_DVCLIB_CALL_ERROR (-1)
133
Dave Jones2672ea82006-08-02 17:11:49 -0400134#define PCI_VENDOR_ID_ASP 0x10cd
135#define PCI_DEVICE_ID_ASP_1200A 0x1100
136#define PCI_DEVICE_ID_ASP_ABP940 0x1200
137#define PCI_DEVICE_ID_ASP_ABP940U 0x1300
138#define PCI_DEVICE_ID_ASP_ABP940UW 0x2300
139#define PCI_DEVICE_ID_38C0800_REV1 0x2500
140#define PCI_DEVICE_ID_38C1600_REV1 0x2700
141
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142/*
143 * Enable CC_VERY_LONG_SG_LIST to support up to 64K element SG lists.
144 * The SRB structure will have to be changed and the ASC_SRB2SCSIQ()
145 * macro re-defined to be able to obtain a ASC_SCSI_Q pointer from the
146 * SRB structure.
147 */
148#define CC_VERY_LONG_SG_LIST 0
149#define ASC_SRB2SCSIQ(srb_ptr) (srb_ptr)
150
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400151#define PortAddr unsigned short /* port address size */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152#define inp(port) inb(port)
153#define outp(port, byte) outb((byte), (port))
154
155#define inpw(port) inw(port)
156#define outpw(port, word) outw((word), (port))
157
158#define ASC_MAX_SG_QUEUE 7
159#define ASC_MAX_SG_LIST 255
160
161#define ASC_CS_TYPE unsigned short
162
163#define ASC_IS_ISA (0x0001)
164#define ASC_IS_ISAPNP (0x0081)
165#define ASC_IS_EISA (0x0002)
166#define ASC_IS_PCI (0x0004)
167#define ASC_IS_PCI_ULTRA (0x0104)
168#define ASC_IS_PCMCIA (0x0008)
169#define ASC_IS_MCA (0x0020)
170#define ASC_IS_VL (0x0040)
171#define ASC_ISA_PNP_PORT_ADDR (0x279)
172#define ASC_ISA_PNP_PORT_WRITE (ASC_ISA_PNP_PORT_ADDR+0x800)
173#define ASC_IS_WIDESCSI_16 (0x0100)
174#define ASC_IS_WIDESCSI_32 (0x0200)
175#define ASC_IS_BIG_ENDIAN (0x8000)
176#define ASC_CHIP_MIN_VER_VL (0x01)
177#define ASC_CHIP_MAX_VER_VL (0x07)
178#define ASC_CHIP_MIN_VER_PCI (0x09)
179#define ASC_CHIP_MAX_VER_PCI (0x0F)
180#define ASC_CHIP_VER_PCI_BIT (0x08)
181#define ASC_CHIP_MIN_VER_ISA (0x11)
182#define ASC_CHIP_MIN_VER_ISA_PNP (0x21)
183#define ASC_CHIP_MAX_VER_ISA (0x27)
184#define ASC_CHIP_VER_ISA_BIT (0x30)
185#define ASC_CHIP_VER_ISAPNP_BIT (0x20)
186#define ASC_CHIP_VER_ASYN_BUG (0x21)
187#define ASC_CHIP_VER_PCI 0x08
188#define ASC_CHIP_VER_PCI_ULTRA_3150 (ASC_CHIP_VER_PCI | 0x02)
189#define ASC_CHIP_VER_PCI_ULTRA_3050 (ASC_CHIP_VER_PCI | 0x03)
190#define ASC_CHIP_MIN_VER_EISA (0x41)
191#define ASC_CHIP_MAX_VER_EISA (0x47)
192#define ASC_CHIP_VER_EISA_BIT (0x40)
193#define ASC_CHIP_LATEST_VER_EISA ((ASC_CHIP_MIN_VER_EISA - 1) + 3)
194#define ASC_MAX_LIB_SUPPORTED_ISA_CHIP_VER 0x21
195#define ASC_MAX_LIB_SUPPORTED_PCI_CHIP_VER 0x0A
196#define ASC_MAX_VL_DMA_ADDR (0x07FFFFFFL)
197#define ASC_MAX_VL_DMA_COUNT (0x07FFFFFFL)
198#define ASC_MAX_PCI_DMA_ADDR (0xFFFFFFFFL)
199#define ASC_MAX_PCI_DMA_COUNT (0xFFFFFFFFL)
200#define ASC_MAX_ISA_DMA_ADDR (0x00FFFFFFL)
201#define ASC_MAX_ISA_DMA_COUNT (0x00FFFFFFL)
202#define ASC_MAX_EISA_DMA_ADDR (0x07FFFFFFL)
203#define ASC_MAX_EISA_DMA_COUNT (0x07FFFFFFL)
204
205#define ASC_SCSI_ID_BITS 3
206#define ASC_SCSI_TIX_TYPE uchar
207#define ASC_ALL_DEVICE_BIT_SET 0xFF
208#define ASC_SCSI_BIT_ID_TYPE uchar
209#define ASC_MAX_TID 7
210#define ASC_MAX_LUN 7
211#define ASC_SCSI_WIDTH_BIT_SET 0xFF
212#define ASC_MAX_SENSE_LEN 32
213#define ASC_MIN_SENSE_LEN 14
214#define ASC_MAX_CDB_LEN 12
215#define ASC_SCSI_RESET_HOLD_TIME_US 60
216
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217/*
218 * Inquiry SPC-2 SPI Byte 1 EVPD (Enable Vital Product Data)
219 * and CmdDt (Command Support Data) field bit definitions.
220 */
221#define ADV_INQ_RTN_VPD_AND_CMDDT 0x3
222#define ADV_INQ_RTN_CMDDT_FOR_OP_CODE 0x2
223#define ADV_INQ_RTN_VPD_FOR_PG_CODE 0x1
224#define ADV_INQ_RTN_STD_INQUIRY_DATA 0x0
225
226#define ASC_SCSIDIR_NOCHK 0x00
227#define ASC_SCSIDIR_T2H 0x08
228#define ASC_SCSIDIR_H2T 0x10
229#define ASC_SCSIDIR_NODATA 0x18
230#define SCSI_ASC_NOMEDIA 0x3A
231#define ASC_SRB_HOST(x) ((uchar)((uchar)(x) >> 4))
232#define ASC_SRB_TID(x) ((uchar)((uchar)(x) & (uchar)0x0F))
233#define ASC_SRB_LUN(x) ((uchar)((uint)(x) >> 13))
234#define PUT_CDB1(x) ((uchar)((uint)(x) >> 8))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235#define MS_SDTR_LEN 0x03
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236#define MS_WDTR_LEN 0x02
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237
238#define ASC_SG_LIST_PER_Q 7
239#define QS_FREE 0x00
240#define QS_READY 0x01
241#define QS_DISC1 0x02
242#define QS_DISC2 0x04
243#define QS_BUSY 0x08
244#define QS_ABORTED 0x40
245#define QS_DONE 0x80
246#define QC_NO_CALLBACK 0x01
247#define QC_SG_SWAP_QUEUE 0x02
248#define QC_SG_HEAD 0x04
249#define QC_DATA_IN 0x08
250#define QC_DATA_OUT 0x10
251#define QC_URGENT 0x20
252#define QC_MSG_OUT 0x40
253#define QC_REQ_SENSE 0x80
254#define QCSG_SG_XFER_LIST 0x02
255#define QCSG_SG_XFER_MORE 0x04
256#define QCSG_SG_XFER_END 0x08
257#define QD_IN_PROGRESS 0x00
258#define QD_NO_ERROR 0x01
259#define QD_ABORTED_BY_HOST 0x02
260#define QD_WITH_ERROR 0x04
261#define QD_INVALID_REQUEST 0x80
262#define QD_INVALID_HOST_NUM 0x81
263#define QD_INVALID_DEVICE 0x82
264#define QD_ERR_INTERNAL 0xFF
265#define QHSTA_NO_ERROR 0x00
266#define QHSTA_M_SEL_TIMEOUT 0x11
267#define QHSTA_M_DATA_OVER_RUN 0x12
268#define QHSTA_M_DATA_UNDER_RUN 0x12
269#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
270#define QHSTA_M_BAD_BUS_PHASE_SEQ 0x14
271#define QHSTA_D_QDONE_SG_LIST_CORRUPTED 0x21
272#define QHSTA_D_ASC_DVC_ERROR_CODE_SET 0x22
273#define QHSTA_D_HOST_ABORT_FAILED 0x23
274#define QHSTA_D_EXE_SCSI_Q_FAILED 0x24
275#define QHSTA_D_EXE_SCSI_Q_BUSY_TIMEOUT 0x25
276#define QHSTA_D_ASPI_NO_BUF_POOL 0x26
277#define QHSTA_M_WTM_TIMEOUT 0x41
278#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42
279#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43
280#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
281#define QHSTA_M_TARGET_STATUS_BUSY 0x45
282#define QHSTA_M_BAD_TAG_CODE 0x46
283#define QHSTA_M_BAD_QUEUE_FULL_OR_BUSY 0x47
284#define QHSTA_M_HUNG_REQ_SCSI_BUS_RESET 0x48
285#define QHSTA_D_LRAM_CMP_ERROR 0x81
286#define QHSTA_M_MICRO_CODE_ERROR_HALT 0xA1
287#define ASC_FLAG_SCSIQ_REQ 0x01
288#define ASC_FLAG_BIOS_SCSIQ_REQ 0x02
289#define ASC_FLAG_BIOS_ASYNC_IO 0x04
290#define ASC_FLAG_SRB_LINEAR_ADDR 0x08
291#define ASC_FLAG_WIN16 0x10
292#define ASC_FLAG_WIN32 0x20
293#define ASC_FLAG_ISA_OVER_16MB 0x40
294#define ASC_FLAG_DOS_VM_CALLBACK 0x80
295#define ASC_TAG_FLAG_EXTRA_BYTES 0x10
296#define ASC_TAG_FLAG_DISABLE_DISCONNECT 0x04
297#define ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX 0x08
298#define ASC_TAG_FLAG_DISABLE_CHK_COND_INT_HOST 0x40
299#define ASC_SCSIQ_CPY_BEG 4
300#define ASC_SCSIQ_SGHD_CPY_BEG 2
301#define ASC_SCSIQ_B_FWD 0
302#define ASC_SCSIQ_B_BWD 1
303#define ASC_SCSIQ_B_STATUS 2
304#define ASC_SCSIQ_B_QNO 3
305#define ASC_SCSIQ_B_CNTL 4
306#define ASC_SCSIQ_B_SG_QUEUE_CNT 5
307#define ASC_SCSIQ_D_DATA_ADDR 8
308#define ASC_SCSIQ_D_DATA_CNT 12
309#define ASC_SCSIQ_B_SENSE_LEN 20
310#define ASC_SCSIQ_DONE_INFO_BEG 22
311#define ASC_SCSIQ_D_SRBPTR 22
312#define ASC_SCSIQ_B_TARGET_IX 26
313#define ASC_SCSIQ_B_CDB_LEN 28
314#define ASC_SCSIQ_B_TAG_CODE 29
315#define ASC_SCSIQ_W_VM_ID 30
316#define ASC_SCSIQ_DONE_STATUS 32
317#define ASC_SCSIQ_HOST_STATUS 33
318#define ASC_SCSIQ_SCSI_STATUS 34
319#define ASC_SCSIQ_CDB_BEG 36
320#define ASC_SCSIQ_DW_REMAIN_XFER_ADDR 56
321#define ASC_SCSIQ_DW_REMAIN_XFER_CNT 60
322#define ASC_SCSIQ_B_FIRST_SG_WK_QP 48
323#define ASC_SCSIQ_B_SG_WK_QP 49
324#define ASC_SCSIQ_B_SG_WK_IX 50
325#define ASC_SCSIQ_W_ALT_DC1 52
326#define ASC_SCSIQ_B_LIST_CNT 6
327#define ASC_SCSIQ_B_CUR_LIST_CNT 7
328#define ASC_SGQ_B_SG_CNTL 4
329#define ASC_SGQ_B_SG_HEAD_QP 5
330#define ASC_SGQ_B_SG_LIST_CNT 6
331#define ASC_SGQ_B_SG_CUR_LIST_CNT 7
332#define ASC_SGQ_LIST_BEG 8
333#define ASC_DEF_SCSI1_QNG 4
334#define ASC_MAX_SCSI1_QNG 4
335#define ASC_DEF_SCSI2_QNG 16
336#define ASC_MAX_SCSI2_QNG 32
337#define ASC_TAG_CODE_MASK 0x23
338#define ASC_STOP_REQ_RISC_STOP 0x01
339#define ASC_STOP_ACK_RISC_STOP 0x03
340#define ASC_STOP_CLEAN_UP_BUSY_Q 0x10
341#define ASC_STOP_CLEAN_UP_DISC_Q 0x20
342#define ASC_STOP_HOST_REQ_RISC_HALT 0x40
343#define ASC_TIDLUN_TO_IX(tid, lun) (ASC_SCSI_TIX_TYPE)((tid) + ((lun)<<ASC_SCSI_ID_BITS))
344#define ASC_TID_TO_TARGET_ID(tid) (ASC_SCSI_BIT_ID_TYPE)(0x01 << (tid))
345#define ASC_TIX_TO_TARGET_ID(tix) (0x01 << ((tix) & ASC_MAX_TID))
346#define ASC_TIX_TO_TID(tix) ((tix) & ASC_MAX_TID)
347#define ASC_TID_TO_TIX(tid) ((tid) & ASC_MAX_TID)
348#define ASC_TIX_TO_LUN(tix) (((tix) >> ASC_SCSI_ID_BITS) & ASC_MAX_LUN)
349#define ASC_QNO_TO_QADDR(q_no) ((ASC_QADR_BEG)+((int)(q_no) << 6))
350
351typedef struct asc_scsiq_1 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400352 uchar status;
353 uchar q_no;
354 uchar cntl;
355 uchar sg_queue_cnt;
356 uchar target_id;
357 uchar target_lun;
358 ASC_PADDR data_addr;
359 ASC_DCNT data_cnt;
360 ASC_PADDR sense_addr;
361 uchar sense_len;
362 uchar extra_bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363} ASC_SCSIQ_1;
364
365typedef struct asc_scsiq_2 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400366 ASC_VADDR srb_ptr;
367 uchar target_ix;
368 uchar flag;
369 uchar cdb_len;
370 uchar tag_code;
371 ushort vm_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372} ASC_SCSIQ_2;
373
374typedef struct asc_scsiq_3 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400375 uchar done_stat;
376 uchar host_stat;
377 uchar scsi_stat;
378 uchar scsi_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379} ASC_SCSIQ_3;
380
381typedef struct asc_scsiq_4 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400382 uchar cdb[ASC_MAX_CDB_LEN];
383 uchar y_first_sg_list_qp;
384 uchar y_working_sg_qp;
385 uchar y_working_sg_ix;
386 uchar y_res;
387 ushort x_req_count;
388 ushort x_reconnect_rtn;
389 ASC_PADDR x_saved_data_addr;
390 ASC_DCNT x_saved_data_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391} ASC_SCSIQ_4;
392
393typedef struct asc_q_done_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400394 ASC_SCSIQ_2 d2;
395 ASC_SCSIQ_3 d3;
396 uchar q_status;
397 uchar q_no;
398 uchar cntl;
399 uchar sense_len;
400 uchar extra_bytes;
401 uchar res;
402 ASC_DCNT remain_bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403} ASC_QDONE_INFO;
404
405typedef struct asc_sg_list {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400406 ASC_PADDR addr;
407 ASC_DCNT bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408} ASC_SG_LIST;
409
410typedef struct asc_sg_head {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400411 ushort entry_cnt;
412 ushort queue_cnt;
413 ushort entry_to_copy;
414 ushort res;
415 ASC_SG_LIST sg_list[ASC_MAX_SG_LIST];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416} ASC_SG_HEAD;
417
418#define ASC_MIN_SG_LIST 2
419
420typedef struct asc_min_sg_head {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400421 ushort entry_cnt;
422 ushort queue_cnt;
423 ushort entry_to_copy;
424 ushort res;
425 ASC_SG_LIST sg_list[ASC_MIN_SG_LIST];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426} ASC_MIN_SG_HEAD;
427
428#define QCX_SORT (0x0001)
429#define QCX_COALEASE (0x0002)
430
431typedef struct asc_scsi_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400432 ASC_SCSIQ_1 q1;
433 ASC_SCSIQ_2 q2;
434 uchar *cdbptr;
435 ASC_SG_HEAD *sg_head;
436 ushort remain_sg_entry_cnt;
437 ushort next_sg_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438} ASC_SCSI_Q;
439
440typedef struct asc_scsi_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400441 ASC_SCSIQ_1 r1;
442 ASC_SCSIQ_2 r2;
443 uchar *cdbptr;
444 ASC_SG_HEAD *sg_head;
445 uchar *sense_ptr;
446 ASC_SCSIQ_3 r3;
447 uchar cdb[ASC_MAX_CDB_LEN];
448 uchar sense[ASC_MIN_SENSE_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449} ASC_SCSI_REQ_Q;
450
451typedef struct asc_scsi_bios_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400452 ASC_SCSIQ_1 r1;
453 ASC_SCSIQ_2 r2;
454 uchar *cdbptr;
455 ASC_SG_HEAD *sg_head;
456 uchar *sense_ptr;
457 ASC_SCSIQ_3 r3;
458 uchar cdb[ASC_MAX_CDB_LEN];
459 uchar sense[ASC_MIN_SENSE_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460} ASC_SCSI_BIOS_REQ_Q;
461
462typedef struct asc_risc_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400463 uchar fwd;
464 uchar bwd;
465 ASC_SCSIQ_1 i1;
466 ASC_SCSIQ_2 i2;
467 ASC_SCSIQ_3 i3;
468 ASC_SCSIQ_4 i4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469} ASC_RISC_Q;
470
471typedef struct asc_sg_list_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400472 uchar seq_no;
473 uchar q_no;
474 uchar cntl;
475 uchar sg_head_qp;
476 uchar sg_list_cnt;
477 uchar sg_cur_list_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478} ASC_SG_LIST_Q;
479
480typedef struct asc_risc_sg_list_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400481 uchar fwd;
482 uchar bwd;
483 ASC_SG_LIST_Q sg;
484 ASC_SG_LIST sg_list[7];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485} ASC_RISC_SG_LIST_Q;
486
487#define ASC_EXE_SCSI_IO_MAX_IDLE_LOOP 0x1000000UL
488#define ASC_EXE_SCSI_IO_MAX_WAIT_LOOP 1024
489#define ASCQ_ERR_NO_ERROR 0
490#define ASCQ_ERR_IO_NOT_FOUND 1
491#define ASCQ_ERR_LOCAL_MEM 2
492#define ASCQ_ERR_CHKSUM 3
493#define ASCQ_ERR_START_CHIP 4
494#define ASCQ_ERR_INT_TARGET_ID 5
495#define ASCQ_ERR_INT_LOCAL_MEM 6
496#define ASCQ_ERR_HALT_RISC 7
497#define ASCQ_ERR_GET_ASPI_ENTRY 8
498#define ASCQ_ERR_CLOSE_ASPI 9
499#define ASCQ_ERR_HOST_INQUIRY 0x0A
500#define ASCQ_ERR_SAVED_SRB_BAD 0x0B
501#define ASCQ_ERR_QCNTL_SG_LIST 0x0C
502#define ASCQ_ERR_Q_STATUS 0x0D
503#define ASCQ_ERR_WR_SCSIQ 0x0E
504#define ASCQ_ERR_PC_ADDR 0x0F
505#define ASCQ_ERR_SYN_OFFSET 0x10
506#define ASCQ_ERR_SYN_XFER_TIME 0x11
507#define ASCQ_ERR_LOCK_DMA 0x12
508#define ASCQ_ERR_UNLOCK_DMA 0x13
509#define ASCQ_ERR_VDS_CHK_INSTALL 0x14
510#define ASCQ_ERR_MICRO_CODE_HALT 0x15
511#define ASCQ_ERR_SET_LRAM_ADDR 0x16
512#define ASCQ_ERR_CUR_QNG 0x17
513#define ASCQ_ERR_SG_Q_LINKS 0x18
514#define ASCQ_ERR_SCSIQ_PTR 0x19
515#define ASCQ_ERR_ISR_RE_ENTRY 0x1A
516#define ASCQ_ERR_CRITICAL_RE_ENTRY 0x1B
517#define ASCQ_ERR_ISR_ON_CRITICAL 0x1C
518#define ASCQ_ERR_SG_LIST_ODD_ADDRESS 0x1D
519#define ASCQ_ERR_XFER_ADDRESS_TOO_BIG 0x1E
520#define ASCQ_ERR_SCSIQ_NULL_PTR 0x1F
521#define ASCQ_ERR_SCSIQ_BAD_NEXT_PTR 0x20
522#define ASCQ_ERR_GET_NUM_OF_FREE_Q 0x21
523#define ASCQ_ERR_SEND_SCSI_Q 0x22
524#define ASCQ_ERR_HOST_REQ_RISC_HALT 0x23
525#define ASCQ_ERR_RESET_SDTR 0x24
526
527/*
528 * Warning code values are set in ASC_DVC_VAR 'warn_code'.
529 */
530#define ASC_WARN_NO_ERROR 0x0000
531#define ASC_WARN_IO_PORT_ROTATE 0x0001
532#define ASC_WARN_EEPROM_CHKSUM 0x0002
533#define ASC_WARN_IRQ_MODIFIED 0x0004
534#define ASC_WARN_AUTO_CONFIG 0x0008
535#define ASC_WARN_CMD_QNG_CONFLICT 0x0010
536#define ASC_WARN_EEPROM_RECOVER 0x0020
537#define ASC_WARN_CFG_MSW_RECOVER 0x0040
538#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080
539
540/*
541 * Error code values are set in ASC_DVC_VAR 'err_code'.
542 */
543#define ASC_IERR_WRITE_EEPROM 0x0001
544#define ASC_IERR_MCODE_CHKSUM 0x0002
545#define ASC_IERR_SET_PC_ADDR 0x0004
546#define ASC_IERR_START_STOP_CHIP 0x0008
547#define ASC_IERR_IRQ_NO 0x0010
548#define ASC_IERR_SET_IRQ_NO 0x0020
549#define ASC_IERR_CHIP_VERSION 0x0040
550#define ASC_IERR_SET_SCSI_ID 0x0080
551#define ASC_IERR_GET_PHY_ADDR 0x0100
552#define ASC_IERR_BAD_SIGNATURE 0x0200
553#define ASC_IERR_NO_BUS_TYPE 0x0400
554#define ASC_IERR_SCAM 0x0800
555#define ASC_IERR_SET_SDTR 0x1000
556#define ASC_IERR_RW_LRAM 0x8000
557
558#define ASC_DEF_IRQ_NO 10
559#define ASC_MAX_IRQ_NO 15
560#define ASC_MIN_IRQ_NO 10
561#define ASC_MIN_REMAIN_Q (0x02)
562#define ASC_DEF_MAX_TOTAL_QNG (0xF0)
563#define ASC_MIN_TAG_Q_PER_DVC (0x04)
564#define ASC_DEF_TAG_Q_PER_DVC (0x04)
565#define ASC_MIN_FREE_Q ASC_MIN_REMAIN_Q
566#define ASC_MIN_TOTAL_QNG ((ASC_MAX_SG_QUEUE)+(ASC_MIN_FREE_Q))
567#define ASC_MAX_TOTAL_QNG 240
568#define ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG 16
569#define ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG 8
570#define ASC_MAX_PCI_INRAM_TOTAL_QNG 20
571#define ASC_MAX_INRAM_TAG_QNG 16
572#define ASC_IOADR_TABLE_MAX_IX 11
573#define ASC_IOADR_GAP 0x10
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574#define ASC_LIB_SCSIQ_WK_SP 256
575#define ASC_MAX_SYN_XFER_NO 16
576#define ASC_SYN_MAX_OFFSET 0x0F
577#define ASC_DEF_SDTR_OFFSET 0x0F
578#define ASC_DEF_SDTR_INDEX 0x00
579#define ASC_SDTR_ULTRA_PCI_10MB_INDEX 0x02
580#define SYN_XFER_NS_0 25
581#define SYN_XFER_NS_1 30
582#define SYN_XFER_NS_2 35
583#define SYN_XFER_NS_3 40
584#define SYN_XFER_NS_4 50
585#define SYN_XFER_NS_5 60
586#define SYN_XFER_NS_6 70
587#define SYN_XFER_NS_7 85
588#define SYN_ULTRA_XFER_NS_0 12
589#define SYN_ULTRA_XFER_NS_1 19
590#define SYN_ULTRA_XFER_NS_2 25
591#define SYN_ULTRA_XFER_NS_3 32
592#define SYN_ULTRA_XFER_NS_4 38
593#define SYN_ULTRA_XFER_NS_5 44
594#define SYN_ULTRA_XFER_NS_6 50
595#define SYN_ULTRA_XFER_NS_7 57
596#define SYN_ULTRA_XFER_NS_8 63
597#define SYN_ULTRA_XFER_NS_9 69
598#define SYN_ULTRA_XFER_NS_10 75
599#define SYN_ULTRA_XFER_NS_11 82
600#define SYN_ULTRA_XFER_NS_12 88
601#define SYN_ULTRA_XFER_NS_13 94
602#define SYN_ULTRA_XFER_NS_14 100
603#define SYN_ULTRA_XFER_NS_15 107
604
605typedef struct ext_msg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400606 uchar msg_type;
607 uchar msg_len;
608 uchar msg_req;
609 union {
610 struct {
611 uchar sdtr_xfer_period;
612 uchar sdtr_req_ack_offset;
613 } sdtr;
614 struct {
615 uchar wdtr_width;
616 } wdtr;
617 struct {
618 uchar mdp_b3;
619 uchar mdp_b2;
620 uchar mdp_b1;
621 uchar mdp_b0;
622 } mdp;
623 } u_ext_msg;
624 uchar res;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625} EXT_MSG;
626
627#define xfer_period u_ext_msg.sdtr.sdtr_xfer_period
628#define req_ack_offset u_ext_msg.sdtr.sdtr_req_ack_offset
629#define wdtr_width u_ext_msg.wdtr.wdtr_width
630#define mdp_b3 u_ext_msg.mdp_b3
631#define mdp_b2 u_ext_msg.mdp_b2
632#define mdp_b1 u_ext_msg.mdp_b1
633#define mdp_b0 u_ext_msg.mdp_b0
634
635typedef struct asc_dvc_cfg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400636 ASC_SCSI_BIT_ID_TYPE can_tagged_qng;
637 ASC_SCSI_BIT_ID_TYPE cmd_qng_enabled;
638 ASC_SCSI_BIT_ID_TYPE disc_enable;
639 ASC_SCSI_BIT_ID_TYPE sdtr_enable;
640 uchar chip_scsi_id;
641 uchar isa_dma_speed;
642 uchar isa_dma_channel;
643 uchar chip_version;
644 ushort lib_serial_no;
645 ushort lib_version;
646 ushort mcode_date;
647 ushort mcode_version;
648 uchar max_tag_qng[ASC_MAX_TID + 1];
649 uchar *overrun_buf;
650 uchar sdtr_period_offset[ASC_MAX_TID + 1];
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400651 uchar adapter_info[6];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652} ASC_DVC_CFG;
653
654#define ASC_DEF_DVC_CNTL 0xFFFF
655#define ASC_DEF_CHIP_SCSI_ID 7
656#define ASC_DEF_ISA_DMA_SPEED 4
657#define ASC_INIT_STATE_NULL 0x0000
658#define ASC_INIT_STATE_BEG_GET_CFG 0x0001
659#define ASC_INIT_STATE_END_GET_CFG 0x0002
660#define ASC_INIT_STATE_BEG_SET_CFG 0x0004
661#define ASC_INIT_STATE_END_SET_CFG 0x0008
662#define ASC_INIT_STATE_BEG_LOAD_MC 0x0010
663#define ASC_INIT_STATE_END_LOAD_MC 0x0020
664#define ASC_INIT_STATE_BEG_INQUIRY 0x0040
665#define ASC_INIT_STATE_END_INQUIRY 0x0080
666#define ASC_INIT_RESET_SCSI_DONE 0x0100
667#define ASC_INIT_STATE_WITHOUT_EEP 0x8000
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668#define ASC_BUG_FIX_IF_NOT_DWB 0x0001
669#define ASC_BUG_FIX_ASYN_USE_SYN 0x0002
670#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41
671#define ASC_MIN_TAGGED_CMD 7
672#define ASC_MAX_SCSI_RESET_WAIT 30
673
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400674struct asc_dvc_var; /* Forward Declaration. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676typedef struct asc_dvc_var {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400677 PortAddr iop_base;
678 ushort err_code;
679 ushort dvc_cntl;
680 ushort bug_fix_cntl;
681 ushort bus_type;
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400682 ASC_SCSI_BIT_ID_TYPE init_sdtr;
683 ASC_SCSI_BIT_ID_TYPE sdtr_done;
684 ASC_SCSI_BIT_ID_TYPE use_tagged_qng;
685 ASC_SCSI_BIT_ID_TYPE unit_not_ready;
686 ASC_SCSI_BIT_ID_TYPE queue_full_or_busy;
687 ASC_SCSI_BIT_ID_TYPE start_motor;
688 uchar scsi_reset_wait;
689 uchar chip_no;
690 char is_in_int;
691 uchar max_total_qng;
692 uchar cur_total_qng;
693 uchar in_critical_cnt;
694 uchar irq_no;
695 uchar last_q_shortage;
696 ushort init_state;
697 uchar cur_dvc_qng[ASC_MAX_TID + 1];
698 uchar max_dvc_qng[ASC_MAX_TID + 1];
699 ASC_SCSI_Q *scsiq_busy_head[ASC_MAX_TID + 1];
700 ASC_SCSI_Q *scsiq_busy_tail[ASC_MAX_TID + 1];
701 uchar sdtr_period_tbl[ASC_MAX_SYN_XFER_NO];
702 ASC_DVC_CFG *cfg;
703 ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer_always;
704 char redo_scam;
705 ushort res2;
706 uchar dos_int13_table[ASC_MAX_TID + 1];
707 ASC_DCNT max_dma_count;
708 ASC_SCSI_BIT_ID_TYPE no_scam;
709 ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer;
710 uchar max_sdtr_index;
711 uchar host_init_sdtr_index;
712 struct asc_board *drv_ptr;
713 ASC_DCNT uc_break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714} ASC_DVC_VAR;
715
716typedef struct asc_dvc_inq_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400717 uchar type[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718} ASC_DVC_INQ_INFO;
719
720typedef struct asc_cap_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400721 ASC_DCNT lba;
722 ASC_DCNT blk_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723} ASC_CAP_INFO;
724
725typedef struct asc_cap_info_array {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400726 ASC_CAP_INFO cap_info[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727} ASC_CAP_INFO_ARRAY;
728
729#define ASC_MCNTL_NO_SEL_TIMEOUT (ushort)0x0001
730#define ASC_MCNTL_NULL_TARGET (ushort)0x0002
731#define ASC_CNTL_INITIATOR (ushort)0x0001
732#define ASC_CNTL_BIOS_GT_1GB (ushort)0x0002
733#define ASC_CNTL_BIOS_GT_2_DISK (ushort)0x0004
734#define ASC_CNTL_BIOS_REMOVABLE (ushort)0x0008
735#define ASC_CNTL_NO_SCAM (ushort)0x0010
736#define ASC_CNTL_INT_MULTI_Q (ushort)0x0080
737#define ASC_CNTL_NO_LUN_SUPPORT (ushort)0x0040
738#define ASC_CNTL_NO_VERIFY_COPY (ushort)0x0100
739#define ASC_CNTL_RESET_SCSI (ushort)0x0200
740#define ASC_CNTL_INIT_INQUIRY (ushort)0x0400
741#define ASC_CNTL_INIT_VERBOSE (ushort)0x0800
742#define ASC_CNTL_SCSI_PARITY (ushort)0x1000
743#define ASC_CNTL_BURST_MODE (ushort)0x2000
744#define ASC_CNTL_SDTR_ENABLE_ULTRA (ushort)0x4000
745#define ASC_EEP_DVC_CFG_BEG_VL 2
746#define ASC_EEP_MAX_DVC_ADDR_VL 15
747#define ASC_EEP_DVC_CFG_BEG 32
748#define ASC_EEP_MAX_DVC_ADDR 45
749#define ASC_EEP_DEFINED_WORDS 10
750#define ASC_EEP_MAX_ADDR 63
751#define ASC_EEP_RES_WORDS 0
752#define ASC_EEP_MAX_RETRY 20
753#define ASC_MAX_INIT_BUSY_RETRY 8
754#define ASC_EEP_ISA_PNP_WSIZE 16
755
756/*
757 * These macros keep the chip SCSI id and ISA DMA speed
758 * bitfields in board order. C bitfields aren't portable
759 * between big and little-endian platforms so they are
760 * not used.
761 */
762
763#define ASC_EEP_GET_CHIP_ID(cfg) ((cfg)->id_speed & 0x0f)
764#define ASC_EEP_GET_DMA_SPD(cfg) (((cfg)->id_speed & 0xf0) >> 4)
765#define ASC_EEP_SET_CHIP_ID(cfg, sid) \
766 ((cfg)->id_speed = ((cfg)->id_speed & 0xf0) | ((sid) & ASC_MAX_TID))
767#define ASC_EEP_SET_DMA_SPD(cfg, spd) \
768 ((cfg)->id_speed = ((cfg)->id_speed & 0x0f) | ((spd) & 0x0f) << 4)
769
770typedef struct asceep_config {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400771 ushort cfg_lsw;
772 ushort cfg_msw;
773 uchar init_sdtr;
774 uchar disc_enable;
775 uchar use_cmd_qng;
776 uchar start_motor;
777 uchar max_total_qng;
778 uchar max_tag_qng;
779 uchar bios_scan;
780 uchar power_up_wait;
781 uchar no_scam;
782 uchar id_speed; /* low order 4 bits is chip scsi id */
783 /* high order 4 bits is isa dma speed */
784 uchar dos_int13_table[ASC_MAX_TID + 1];
785 uchar adapter_info[6];
786 ushort cntl;
787 ushort chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788} ASCEEP_CONFIG;
789
790#define ASC_PCI_CFG_LSW_SCSI_PARITY 0x0800
791#define ASC_PCI_CFG_LSW_BURST_MODE 0x0080
792#define ASC_PCI_CFG_LSW_INTR_ABLE 0x0020
793
794#define ASC_EEP_CMD_READ 0x80
795#define ASC_EEP_CMD_WRITE 0x40
796#define ASC_EEP_CMD_WRITE_ABLE 0x30
797#define ASC_EEP_CMD_WRITE_DISABLE 0x00
798#define ASC_OVERRUN_BSIZE 0x00000048UL
799#define ASC_CTRL_BREAK_ONCE 0x0001
800#define ASC_CTRL_BREAK_STAY_IDLE 0x0002
801#define ASCV_MSGOUT_BEG 0x0000
802#define ASCV_MSGOUT_SDTR_PERIOD (ASCV_MSGOUT_BEG+3)
803#define ASCV_MSGOUT_SDTR_OFFSET (ASCV_MSGOUT_BEG+4)
804#define ASCV_BREAK_SAVED_CODE (ushort)0x0006
805#define ASCV_MSGIN_BEG (ASCV_MSGOUT_BEG+8)
806#define ASCV_MSGIN_SDTR_PERIOD (ASCV_MSGIN_BEG+3)
807#define ASCV_MSGIN_SDTR_OFFSET (ASCV_MSGIN_BEG+4)
808#define ASCV_SDTR_DATA_BEG (ASCV_MSGIN_BEG+8)
809#define ASCV_SDTR_DONE_BEG (ASCV_SDTR_DATA_BEG+8)
810#define ASCV_MAX_DVC_QNG_BEG (ushort)0x0020
811#define ASCV_BREAK_ADDR (ushort)0x0028
812#define ASCV_BREAK_NOTIFY_COUNT (ushort)0x002A
813#define ASCV_BREAK_CONTROL (ushort)0x002C
814#define ASCV_BREAK_HIT_COUNT (ushort)0x002E
815
816#define ASCV_ASCDVC_ERR_CODE_W (ushort)0x0030
817#define ASCV_MCODE_CHKSUM_W (ushort)0x0032
818#define ASCV_MCODE_SIZE_W (ushort)0x0034
819#define ASCV_STOP_CODE_B (ushort)0x0036
820#define ASCV_DVC_ERR_CODE_B (ushort)0x0037
821#define ASCV_OVERRUN_PADDR_D (ushort)0x0038
822#define ASCV_OVERRUN_BSIZE_D (ushort)0x003C
823#define ASCV_HALTCODE_W (ushort)0x0040
824#define ASCV_CHKSUM_W (ushort)0x0042
825#define ASCV_MC_DATE_W (ushort)0x0044
826#define ASCV_MC_VER_W (ushort)0x0046
827#define ASCV_NEXTRDY_B (ushort)0x0048
828#define ASCV_DONENEXT_B (ushort)0x0049
829#define ASCV_USE_TAGGED_QNG_B (ushort)0x004A
830#define ASCV_SCSIBUSY_B (ushort)0x004B
831#define ASCV_Q_DONE_IN_PROGRESS_B (ushort)0x004C
832#define ASCV_CURCDB_B (ushort)0x004D
833#define ASCV_RCLUN_B (ushort)0x004E
834#define ASCV_BUSY_QHEAD_B (ushort)0x004F
835#define ASCV_DISC1_QHEAD_B (ushort)0x0050
836#define ASCV_DISC_ENABLE_B (ushort)0x0052
837#define ASCV_CAN_TAGGED_QNG_B (ushort)0x0053
838#define ASCV_HOSTSCSI_ID_B (ushort)0x0055
839#define ASCV_MCODE_CNTL_B (ushort)0x0056
840#define ASCV_NULL_TARGET_B (ushort)0x0057
841#define ASCV_FREE_Q_HEAD_W (ushort)0x0058
842#define ASCV_DONE_Q_TAIL_W (ushort)0x005A
843#define ASCV_FREE_Q_HEAD_B (ushort)(ASCV_FREE_Q_HEAD_W+1)
844#define ASCV_DONE_Q_TAIL_B (ushort)(ASCV_DONE_Q_TAIL_W+1)
845#define ASCV_HOST_FLAG_B (ushort)0x005D
846#define ASCV_TOTAL_READY_Q_B (ushort)0x0064
847#define ASCV_VER_SERIAL_B (ushort)0x0065
848#define ASCV_HALTCODE_SAVED_W (ushort)0x0066
849#define ASCV_WTM_FLAG_B (ushort)0x0068
850#define ASCV_RISC_FLAG_B (ushort)0x006A
851#define ASCV_REQ_SG_LIST_QP (ushort)0x006B
852#define ASC_HOST_FLAG_IN_ISR 0x01
853#define ASC_HOST_FLAG_ACK_INT 0x02
854#define ASC_RISC_FLAG_GEN_INT 0x01
855#define ASC_RISC_FLAG_REQ_SG_LIST 0x02
856#define IOP_CTRL (0x0F)
857#define IOP_STATUS (0x0E)
858#define IOP_INT_ACK IOP_STATUS
859#define IOP_REG_IFC (0x0D)
860#define IOP_SYN_OFFSET (0x0B)
861#define IOP_EXTRA_CONTROL (0x0D)
862#define IOP_REG_PC (0x0C)
863#define IOP_RAM_ADDR (0x0A)
864#define IOP_RAM_DATA (0x08)
865#define IOP_EEP_DATA (0x06)
866#define IOP_EEP_CMD (0x07)
867#define IOP_VERSION (0x03)
868#define IOP_CONFIG_HIGH (0x04)
869#define IOP_CONFIG_LOW (0x02)
870#define IOP_SIG_BYTE (0x01)
871#define IOP_SIG_WORD (0x00)
872#define IOP_REG_DC1 (0x0E)
873#define IOP_REG_DC0 (0x0C)
874#define IOP_REG_SB (0x0B)
875#define IOP_REG_DA1 (0x0A)
876#define IOP_REG_DA0 (0x08)
877#define IOP_REG_SC (0x09)
878#define IOP_DMA_SPEED (0x07)
879#define IOP_REG_FLAG (0x07)
880#define IOP_FIFO_H (0x06)
881#define IOP_FIFO_L (0x04)
882#define IOP_REG_ID (0x05)
883#define IOP_REG_QP (0x03)
884#define IOP_REG_IH (0x02)
885#define IOP_REG_IX (0x01)
886#define IOP_REG_AX (0x00)
887#define IFC_REG_LOCK (0x00)
888#define IFC_REG_UNLOCK (0x09)
889#define IFC_WR_EN_FILTER (0x10)
890#define IFC_RD_NO_EEPROM (0x10)
891#define IFC_SLEW_RATE (0x20)
892#define IFC_ACT_NEG (0x40)
893#define IFC_INP_FILTER (0x80)
894#define IFC_INIT_DEFAULT (IFC_ACT_NEG | IFC_REG_UNLOCK)
895#define SC_SEL (uchar)(0x80)
896#define SC_BSY (uchar)(0x40)
897#define SC_ACK (uchar)(0x20)
898#define SC_REQ (uchar)(0x10)
899#define SC_ATN (uchar)(0x08)
900#define SC_IO (uchar)(0x04)
901#define SC_CD (uchar)(0x02)
902#define SC_MSG (uchar)(0x01)
903#define SEC_SCSI_CTL (uchar)(0x80)
904#define SEC_ACTIVE_NEGATE (uchar)(0x40)
905#define SEC_SLEW_RATE (uchar)(0x20)
906#define SEC_ENABLE_FILTER (uchar)(0x10)
907#define ASC_HALT_EXTMSG_IN (ushort)0x8000
908#define ASC_HALT_CHK_CONDITION (ushort)0x8100
909#define ASC_HALT_SS_QUEUE_FULL (ushort)0x8200
910#define ASC_HALT_DISABLE_ASYN_USE_SYN_FIX (ushort)0x8300
911#define ASC_HALT_ENABLE_ASYN_USE_SYN_FIX (ushort)0x8400
912#define ASC_HALT_SDTR_REJECTED (ushort)0x4000
913#define ASC_HALT_HOST_COPY_SG_LIST_TO_RISC ( ushort )0x2000
914#define ASC_MAX_QNO 0xF8
915#define ASC_DATA_SEC_BEG (ushort)0x0080
916#define ASC_DATA_SEC_END (ushort)0x0080
917#define ASC_CODE_SEC_BEG (ushort)0x0080
918#define ASC_CODE_SEC_END (ushort)0x0080
919#define ASC_QADR_BEG (0x4000)
920#define ASC_QADR_USED (ushort)(ASC_MAX_QNO * 64)
921#define ASC_QADR_END (ushort)0x7FFF
922#define ASC_QLAST_ADR (ushort)0x7FC0
923#define ASC_QBLK_SIZE 0x40
924#define ASC_BIOS_DATA_QBEG 0xF8
925#define ASC_MIN_ACTIVE_QNO 0x01
926#define ASC_QLINK_END 0xFF
927#define ASC_EEPROM_WORDS 0x10
928#define ASC_MAX_MGS_LEN 0x10
929#define ASC_BIOS_ADDR_DEF 0xDC00
930#define ASC_BIOS_SIZE 0x3800
931#define ASC_BIOS_RAM_OFF 0x3800
932#define ASC_BIOS_RAM_SIZE 0x800
933#define ASC_BIOS_MIN_ADDR 0xC000
934#define ASC_BIOS_MAX_ADDR 0xEC00
935#define ASC_BIOS_BANK_SIZE 0x0400
936#define ASC_MCODE_START_ADDR 0x0080
937#define ASC_CFG0_HOST_INT_ON 0x0020
938#define ASC_CFG0_BIOS_ON 0x0040
939#define ASC_CFG0_VERA_BURST_ON 0x0080
940#define ASC_CFG0_SCSI_PARITY_ON 0x0800
941#define ASC_CFG1_SCSI_TARGET_ON 0x0080
942#define ASC_CFG1_LRAM_8BITS_ON 0x0800
943#define ASC_CFG_MSW_CLR_MASK 0x3080
944#define CSW_TEST1 (ASC_CS_TYPE)0x8000
945#define CSW_AUTO_CONFIG (ASC_CS_TYPE)0x4000
946#define CSW_RESERVED1 (ASC_CS_TYPE)0x2000
947#define CSW_IRQ_WRITTEN (ASC_CS_TYPE)0x1000
948#define CSW_33MHZ_SELECTED (ASC_CS_TYPE)0x0800
949#define CSW_TEST2 (ASC_CS_TYPE)0x0400
950#define CSW_TEST3 (ASC_CS_TYPE)0x0200
951#define CSW_RESERVED2 (ASC_CS_TYPE)0x0100
952#define CSW_DMA_DONE (ASC_CS_TYPE)0x0080
953#define CSW_FIFO_RDY (ASC_CS_TYPE)0x0040
954#define CSW_EEP_READ_DONE (ASC_CS_TYPE)0x0020
955#define CSW_HALTED (ASC_CS_TYPE)0x0010
956#define CSW_SCSI_RESET_ACTIVE (ASC_CS_TYPE)0x0008
957#define CSW_PARITY_ERR (ASC_CS_TYPE)0x0004
958#define CSW_SCSI_RESET_LATCH (ASC_CS_TYPE)0x0002
959#define CSW_INT_PENDING (ASC_CS_TYPE)0x0001
960#define CIW_CLR_SCSI_RESET_INT (ASC_CS_TYPE)0x1000
961#define CIW_INT_ACK (ASC_CS_TYPE)0x0100
962#define CIW_TEST1 (ASC_CS_TYPE)0x0200
963#define CIW_TEST2 (ASC_CS_TYPE)0x0400
964#define CIW_SEL_33MHZ (ASC_CS_TYPE)0x0800
965#define CIW_IRQ_ACT (ASC_CS_TYPE)0x1000
966#define CC_CHIP_RESET (uchar)0x80
967#define CC_SCSI_RESET (uchar)0x40
968#define CC_HALT (uchar)0x20
969#define CC_SINGLE_STEP (uchar)0x10
970#define CC_DMA_ABLE (uchar)0x08
971#define CC_TEST (uchar)0x04
972#define CC_BANK_ONE (uchar)0x02
973#define CC_DIAG (uchar)0x01
974#define ASC_1000_ID0W 0x04C1
975#define ASC_1000_ID0W_FIX 0x00C1
976#define ASC_1000_ID1B 0x25
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977#define ASC_EISA_REV_IOP_MASK (0x0C83)
978#define ASC_EISA_PID_IOP_MASK (0x0C80)
979#define ASC_EISA_CFG_IOP_MASK (0x0C86)
980#define ASC_GET_EISA_SLOT(iop) (PortAddr)((iop) & 0xF000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981#define INS_HALTINT (ushort)0x6281
982#define INS_HALT (ushort)0x6280
983#define INS_SINT (ushort)0x6200
984#define INS_RFLAG_WTM (ushort)0x7380
985#define ASC_MC_SAVE_CODE_WSIZE 0x500
986#define ASC_MC_SAVE_DATA_WSIZE 0x40
987
988typedef struct asc_mc_saved {
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400989 ushort data[ASC_MC_SAVE_DATA_WSIZE];
990 ushort code[ASC_MC_SAVE_CODE_WSIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991} ASC_MC_SAVED;
992
993#define AscGetQDoneInProgress(port) AscReadLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B)
994#define AscPutQDoneInProgress(port, val) AscWriteLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B, val)
995#define AscGetVarFreeQHead(port) AscReadLramWord((port), ASCV_FREE_Q_HEAD_W)
996#define AscGetVarDoneQTail(port) AscReadLramWord((port), ASCV_DONE_Q_TAIL_W)
997#define AscPutVarFreeQHead(port, val) AscWriteLramWord((port), ASCV_FREE_Q_HEAD_W, val)
998#define AscPutVarDoneQTail(port, val) AscWriteLramWord((port), ASCV_DONE_Q_TAIL_W, val)
999#define AscGetRiscVarFreeQHead(port) AscReadLramByte((port), ASCV_NEXTRDY_B)
1000#define AscGetRiscVarDoneQTail(port) AscReadLramByte((port), ASCV_DONENEXT_B)
1001#define AscPutRiscVarFreeQHead(port, val) AscWriteLramByte((port), ASCV_NEXTRDY_B, val)
1002#define AscPutRiscVarDoneQTail(port, val) AscWriteLramByte((port), ASCV_DONENEXT_B, val)
1003#define AscPutMCodeSDTRDoneAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id), (data));
1004#define AscGetMCodeSDTRDoneAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id));
1005#define AscPutMCodeInitSDTRAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id), data);
1006#define AscGetMCodeInitSDTRAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id));
1007#define AscSynIndexToPeriod(index) (uchar)(asc_dvc->sdtr_period_tbl[ (index) ])
1008#define AscGetChipSignatureByte(port) (uchar)inp((port)+IOP_SIG_BYTE)
1009#define AscGetChipSignatureWord(port) (ushort)inpw((port)+IOP_SIG_WORD)
1010#define AscGetChipVerNo(port) (uchar)inp((port)+IOP_VERSION)
1011#define AscGetChipCfgLsw(port) (ushort)inpw((port)+IOP_CONFIG_LOW)
1012#define AscGetChipCfgMsw(port) (ushort)inpw((port)+IOP_CONFIG_HIGH)
1013#define AscSetChipCfgLsw(port, data) outpw((port)+IOP_CONFIG_LOW, data)
1014#define AscSetChipCfgMsw(port, data) outpw((port)+IOP_CONFIG_HIGH, data)
1015#define AscGetChipEEPCmd(port) (uchar)inp((port)+IOP_EEP_CMD)
1016#define AscSetChipEEPCmd(port, data) outp((port)+IOP_EEP_CMD, data)
1017#define AscGetChipEEPData(port) (ushort)inpw((port)+IOP_EEP_DATA)
1018#define AscSetChipEEPData(port, data) outpw((port)+IOP_EEP_DATA, data)
1019#define AscGetChipLramAddr(port) (ushort)inpw((PortAddr)((port)+IOP_RAM_ADDR))
1020#define AscSetChipLramAddr(port, addr) outpw((PortAddr)((port)+IOP_RAM_ADDR), addr)
1021#define AscGetChipLramData(port) (ushort)inpw((port)+IOP_RAM_DATA)
1022#define AscSetChipLramData(port, data) outpw((port)+IOP_RAM_DATA, data)
1023#define AscGetChipIFC(port) (uchar)inp((port)+IOP_REG_IFC)
1024#define AscSetChipIFC(port, data) outp((port)+IOP_REG_IFC, data)
1025#define AscGetChipStatus(port) (ASC_CS_TYPE)inpw((port)+IOP_STATUS)
1026#define AscSetChipStatus(port, cs_val) outpw((port)+IOP_STATUS, cs_val)
1027#define AscGetChipControl(port) (uchar)inp((port)+IOP_CTRL)
1028#define AscSetChipControl(port, cc_val) outp((port)+IOP_CTRL, cc_val)
1029#define AscGetChipSyn(port) (uchar)inp((port)+IOP_SYN_OFFSET)
1030#define AscSetChipSyn(port, data) outp((port)+IOP_SYN_OFFSET, data)
1031#define AscSetPCAddr(port, data) outpw((port)+IOP_REG_PC, data)
1032#define AscGetPCAddr(port) (ushort)inpw((port)+IOP_REG_PC)
1033#define AscIsIntPending(port) (AscGetChipStatus(port) & (CSW_INT_PENDING | CSW_SCSI_RESET_LATCH))
1034#define AscGetChipScsiID(port) ((AscGetChipCfgLsw(port) >> 8) & ASC_MAX_TID)
1035#define AscGetExtraControl(port) (uchar)inp((port)+IOP_EXTRA_CONTROL)
1036#define AscSetExtraControl(port, data) outp((port)+IOP_EXTRA_CONTROL, data)
1037#define AscReadChipAX(port) (ushort)inpw((port)+IOP_REG_AX)
1038#define AscWriteChipAX(port, data) outpw((port)+IOP_REG_AX, data)
1039#define AscReadChipIX(port) (uchar)inp((port)+IOP_REG_IX)
1040#define AscWriteChipIX(port, data) outp((port)+IOP_REG_IX, data)
1041#define AscReadChipIH(port) (ushort)inpw((port)+IOP_REG_IH)
1042#define AscWriteChipIH(port, data) outpw((port)+IOP_REG_IH, data)
1043#define AscReadChipQP(port) (uchar)inp((port)+IOP_REG_QP)
1044#define AscWriteChipQP(port, data) outp((port)+IOP_REG_QP, data)
1045#define AscReadChipFIFO_L(port) (ushort)inpw((port)+IOP_REG_FIFO_L)
1046#define AscWriteChipFIFO_L(port, data) outpw((port)+IOP_REG_FIFO_L, data)
1047#define AscReadChipFIFO_H(port) (ushort)inpw((port)+IOP_REG_FIFO_H)
1048#define AscWriteChipFIFO_H(port, data) outpw((port)+IOP_REG_FIFO_H, data)
1049#define AscReadChipDmaSpeed(port) (uchar)inp((port)+IOP_DMA_SPEED)
1050#define AscWriteChipDmaSpeed(port, data) outp((port)+IOP_DMA_SPEED, data)
1051#define AscReadChipDA0(port) (ushort)inpw((port)+IOP_REG_DA0)
1052#define AscWriteChipDA0(port) outpw((port)+IOP_REG_DA0, data)
1053#define AscReadChipDA1(port) (ushort)inpw((port)+IOP_REG_DA1)
1054#define AscWriteChipDA1(port) outpw((port)+IOP_REG_DA1, data)
1055#define AscReadChipDC0(port) (ushort)inpw((port)+IOP_REG_DC0)
1056#define AscWriteChipDC0(port) outpw((port)+IOP_REG_DC0, data)
1057#define AscReadChipDC1(port) (ushort)inpw((port)+IOP_REG_DC1)
1058#define AscWriteChipDC1(port) outpw((port)+IOP_REG_DC1, data)
1059#define AscReadChipDvcID(port) (uchar)inp((port)+IOP_REG_ID)
1060#define AscWriteChipDvcID(port, data) outp((port)+IOP_REG_ID, data)
1061
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001062static int AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg);
1063static int AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg);
1064static void AscWaitEEPRead(void);
1065static void AscWaitEEPWrite(void);
1066static ushort AscReadEEPWord(PortAddr, uchar);
1067static ushort AscWriteEEPWord(PortAddr, uchar, ushort);
1068static ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
1069static int AscSetEEPConfigOnce(PortAddr, ASCEEP_CONFIG *, ushort);
1070static int AscSetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
1071static int AscStartChip(PortAddr);
1072static int AscStopChip(PortAddr);
1073static void AscSetChipIH(PortAddr, ushort);
1074static int AscIsChipHalted(PortAddr);
1075static void AscAckInterrupt(PortAddr);
1076static void AscDisableInterrupt(PortAddr);
1077static void AscEnableInterrupt(PortAddr);
1078static void AscSetBank(PortAddr, uchar);
1079static int AscResetChipAndScsiBus(ASC_DVC_VAR *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001081static uchar AscGetIsaDmaSpeed(PortAddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001083static uchar AscReadLramByte(PortAddr, ushort);
1084static ushort AscReadLramWord(PortAddr, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001086static ASC_DCNT AscReadLramDWord(PortAddr, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001088static void AscWriteLramWord(PortAddr, ushort, ushort);
1089static void AscWriteLramByte(PortAddr, ushort, uchar);
1090static ASC_DCNT AscMemSumLramWord(PortAddr, ushort, int);
1091static void AscMemWordSetLram(PortAddr, ushort, ushort, int);
1092static void AscMemWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
1093static void AscMemDWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
1094static void AscMemWordCopyPtrFromLram(PortAddr, ushort, uchar *, int);
1095static ushort AscInitAscDvcVar(ASC_DVC_VAR *);
1096static ushort AscInitFromEEP(ASC_DVC_VAR *);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001097static ushort AscInitMicroCodeVar(ASC_DVC_VAR *);
1098static int AscTestExternalLram(ASC_DVC_VAR *);
1099static uchar AscMsgOutSDTR(ASC_DVC_VAR *, uchar, uchar);
1100static uchar AscCalSDTRData(ASC_DVC_VAR *, uchar, uchar);
1101static void AscSetChipSDTR(PortAddr, uchar, uchar);
1102static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *, uchar);
1103static uchar AscAllocFreeQueue(PortAddr, uchar);
1104static uchar AscAllocMultipleFreeQueue(PortAddr, uchar, uchar);
1105static int AscHostReqRiscHalt(PortAddr);
1106static int AscStopQueueExe(PortAddr);
1107static int AscSendScsiQueue(ASC_DVC_VAR *,
1108 ASC_SCSI_Q *scsiq, uchar n_q_required);
1109static int AscPutReadyQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
1110static int AscPutReadySgListQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
1111static int AscSetChipSynRegAtID(PortAddr, uchar, uchar);
1112static int AscSetRunChipSynRegAtID(PortAddr, uchar, uchar);
1113static ushort AscInitLram(ASC_DVC_VAR *);
1114static ushort AscInitQLinkVar(ASC_DVC_VAR *);
1115static int AscSetLibErrorCode(ASC_DVC_VAR *, ushort);
1116static int AscIsrChipHalted(ASC_DVC_VAR *);
1117static uchar _AscCopyLramScsiDoneQ(PortAddr, ushort,
1118 ASC_QDONE_INFO *, ASC_DCNT);
1119static int AscIsrQDone(ASC_DVC_VAR *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001121static ushort AscGetEisaChipCfg(PortAddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001123static uchar AscGetChipScsiCtrl(PortAddr);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001124static uchar AscGetChipVersion(PortAddr, ushort);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001125static ASC_DCNT AscLoadMicroCode(PortAddr, ushort, uchar *, ushort);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001126static void AscToggleIRQAct(PortAddr);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001127static inline ulong DvcEnterCritical(void);
1128static inline void DvcLeaveCritical(ulong);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001129static void DvcSleepMilliSecond(ASC_DCNT);
1130static void DvcDelayNanoSecond(ASC_DVC_VAR *, ASC_DCNT);
1131static void DvcPutScsiQ(PortAddr, ushort, uchar *, int);
1132static void DvcGetQinfo(PortAddr, ushort, uchar *, int);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001133static ushort AscInitAsc1000Driver(ASC_DVC_VAR *);
Matthew Wilcox47d853c2007-07-26 11:41:33 -04001134static void AscAsyncFix(ASC_DVC_VAR *, struct scsi_device *);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001135static int AscExeScsiQueue(ASC_DVC_VAR *, ASC_SCSI_Q *);
1136static int AscISR(ASC_DVC_VAR *);
1137static uint AscGetNumOfFreeQueue(ASC_DVC_VAR *, uchar, uchar);
1138static int AscSgListToQueue(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001140static void AscEnableIsaDma(uchar);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001142static const char *advansys_info(struct Scsi_Host *shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143
1144/*
1145 * --- Adv Library Constants and Macros
1146 */
1147
1148#define ADV_LIB_VERSION_MAJOR 5
1149#define ADV_LIB_VERSION_MINOR 14
1150
1151/*
1152 * Define Adv Library required special types.
1153 */
1154
1155/*
1156 * Portable Data Types
1157 *
1158 * Any instance where a 32-bit long or pointer type is assumed
1159 * for precision or HW defined structures, the following define
1160 * types must be used. In Linux the char, short, and int types
1161 * are all consistent at 8, 16, and 32 bits respectively. Pointers
1162 * and long types are 64 bits on Alpha and UltraSPARC.
1163 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001164#define ADV_PADDR __u32 /* Physical address data type. */
1165#define ADV_VADDR __u32 /* Virtual address data type. */
1166#define ADV_DCNT __u32 /* Unsigned Data count type. */
1167#define ADV_SDCNT __s32 /* Signed Data count type. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168
1169/*
1170 * These macros are used to convert a virtual address to a
1171 * 32-bit value. This currently can be used on Linux Alpha
1172 * which uses 64-bit virtual address but a 32-bit bus address.
1173 * This is likely to break in the future, but doing this now
1174 * will give us time to change the HW and FW to handle 64-bit
1175 * addresses.
1176 */
1177#define ADV_VADDR_TO_U32 virt_to_bus
1178#define ADV_U32_TO_VADDR bus_to_virt
1179
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001180#define AdvPortAddr void __iomem * /* Virtual memory address size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181
1182/*
1183 * Define Adv Library required memory access macros.
1184 */
1185#define ADV_MEM_READB(addr) readb(addr)
1186#define ADV_MEM_READW(addr) readw(addr)
1187#define ADV_MEM_WRITEB(addr, byte) writeb(byte, addr)
1188#define ADV_MEM_WRITEW(addr, word) writew(word, addr)
1189#define ADV_MEM_WRITEDW(addr, dword) writel(dword, addr)
1190
1191#define ADV_CARRIER_COUNT (ASC_DEF_MAX_HOST_QNG + 15)
1192
1193/*
1194 * For wide boards a CDB length maximum of 16 bytes
1195 * is supported.
1196 */
1197#define ADV_MAX_CDB_LEN 16
1198
1199/*
1200 * Define total number of simultaneous maximum element scatter-gather
1201 * request blocks per wide adapter. ASC_DEF_MAX_HOST_QNG (253) is the
1202 * maximum number of outstanding commands per wide host adapter. Each
1203 * command uses one or more ADV_SG_BLOCK each with 15 scatter-gather
1204 * elements. Allow each command to have at least one ADV_SG_BLOCK structure.
1205 * This allows about 15 commands to have the maximum 17 ADV_SG_BLOCK
1206 * structures or 255 scatter-gather elements.
1207 *
1208 */
1209#define ADV_TOT_SG_BLOCK ASC_DEF_MAX_HOST_QNG
1210
1211/*
1212 * Define Adv Library required maximum number of scatter-gather
1213 * elements per request.
1214 */
1215#define ADV_MAX_SG_LIST 255
1216
1217/* Number of SG blocks needed. */
1218#define ADV_NUM_SG_BLOCK \
1219 ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)
1220
1221/* Total contiguous memory needed for SG blocks. */
1222#define ADV_SG_TOTAL_MEM_SIZE \
1223 (sizeof(ADV_SG_BLOCK) * ADV_NUM_SG_BLOCK)
1224
1225#define ADV_PAGE_SIZE PAGE_SIZE
1226
1227#define ADV_NUM_PAGE_CROSSING \
1228 ((ADV_SG_TOTAL_MEM_SIZE + (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
1229
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230#define ADV_EEP_DVC_CFG_BEGIN (0x00)
1231#define ADV_EEP_DVC_CFG_END (0x15)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001232#define ADV_EEP_DVC_CTL_BEGIN (0x16) /* location of OEM name */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233#define ADV_EEP_MAX_WORD_ADDR (0x1E)
1234
1235#define ADV_EEP_DELAY_MS 100
1236
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001237#define ADV_EEPROM_BIG_ENDIAN 0x8000 /* EEPROM Bit 15 */
1238#define ADV_EEPROM_BIOS_ENABLE 0x4000 /* EEPROM Bit 14 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239/*
1240 * For the ASC3550 Bit 13 is Termination Polarity control bit.
1241 * For later ICs Bit 13 controls whether the CIS (Card Information
1242 * Service Section) is loaded from EEPROM.
1243 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001244#define ADV_EEPROM_TERM_POL 0x2000 /* EEPROM Bit 13 */
1245#define ADV_EEPROM_CIS_LD 0x2000 /* EEPROM Bit 13 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246/*
1247 * ASC38C1600 Bit 11
1248 *
1249 * If EEPROM Bit 11 is 0 for Function 0, then Function 0 will specify
1250 * INT A in the PCI Configuration Space Int Pin field. If it is 1, then
1251 * Function 0 will specify INT B.
1252 *
1253 * If EEPROM Bit 11 is 0 for Function 1, then Function 1 will specify
1254 * INT B in the PCI Configuration Space Int Pin field. If it is 1, then
1255 * Function 1 will specify INT A.
1256 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001257#define ADV_EEPROM_INTAB 0x0800 /* EEPROM Bit 11 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001259typedef struct adveep_3550_config {
1260 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001262 ushort cfg_lsw; /* 00 power up initialization */
1263 /* bit 13 set - Term Polarity Control */
1264 /* bit 14 set - BIOS Enable */
1265 /* bit 15 set - Big Endian Mode */
1266 ushort cfg_msw; /* 01 unused */
1267 ushort disc_enable; /* 02 disconnect enable */
1268 ushort wdtr_able; /* 03 Wide DTR able */
1269 ushort sdtr_able; /* 04 Synchronous DTR able */
1270 ushort start_motor; /* 05 send start up motor */
1271 ushort tagqng_able; /* 06 tag queuing able */
1272 ushort bios_scan; /* 07 BIOS device control */
1273 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001275 uchar adapter_scsi_id; /* 09 Host Adapter ID */
1276 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001278 uchar scsi_reset_delay; /* 10 reset delay */
1279 uchar bios_id_lun; /* first boot device scsi id & lun */
1280 /* high nibble is lun */
1281 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001283 uchar termination; /* 11 0 - automatic */
1284 /* 1 - low off / high off */
1285 /* 2 - low off / high on */
1286 /* 3 - low on / high on */
1287 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001289 uchar reserved1; /* reserved byte (not used) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001291 ushort bios_ctrl; /* 12 BIOS control bits */
1292 /* bit 0 BIOS don't act as initiator. */
1293 /* bit 1 BIOS > 1 GB support */
1294 /* bit 2 BIOS > 2 Disk Support */
1295 /* bit 3 BIOS don't support removables */
1296 /* bit 4 BIOS support bootable CD */
1297 /* bit 5 BIOS scan enabled */
1298 /* bit 6 BIOS support multiple LUNs */
1299 /* bit 7 BIOS display of message */
1300 /* bit 8 SCAM disabled */
1301 /* bit 9 Reset SCSI bus during init. */
1302 /* bit 10 */
1303 /* bit 11 No verbose initialization. */
1304 /* bit 12 SCSI parity enabled */
1305 /* bit 13 */
1306 /* bit 14 */
1307 /* bit 15 */
1308 ushort ultra_able; /* 13 ULTRA speed able */
1309 ushort reserved2; /* 14 reserved */
1310 uchar max_host_qng; /* 15 maximum host queuing */
1311 uchar max_dvc_qng; /* maximum per device queuing */
1312 ushort dvc_cntl; /* 16 control bit for driver */
1313 ushort bug_fix; /* 17 control bit for bug fix */
1314 ushort serial_number_word1; /* 18 Board serial number word 1 */
1315 ushort serial_number_word2; /* 19 Board serial number word 2 */
1316 ushort serial_number_word3; /* 20 Board serial number word 3 */
1317 ushort check_sum; /* 21 EEP check sum */
1318 uchar oem_name[16]; /* 22 OEM name */
1319 ushort dvc_err_code; /* 30 last device driver error code */
1320 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
1321 ushort adv_err_addr; /* 32 last uc error address */
1322 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
1323 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
1324 ushort saved_adv_err_addr; /* 35 saved last uc error address */
1325 ushort num_of_err; /* 36 number of error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326} ADVEEP_3550_CONFIG;
1327
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001328typedef struct adveep_38C0800_config {
1329 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001331 ushort cfg_lsw; /* 00 power up initialization */
1332 /* bit 13 set - Load CIS */
1333 /* bit 14 set - BIOS Enable */
1334 /* bit 15 set - Big Endian Mode */
1335 ushort cfg_msw; /* 01 unused */
1336 ushort disc_enable; /* 02 disconnect enable */
1337 ushort wdtr_able; /* 03 Wide DTR able */
1338 ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
1339 ushort start_motor; /* 05 send start up motor */
1340 ushort tagqng_able; /* 06 tag queuing able */
1341 ushort bios_scan; /* 07 BIOS device control */
1342 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001344 uchar adapter_scsi_id; /* 09 Host Adapter ID */
1345 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001347 uchar scsi_reset_delay; /* 10 reset delay */
1348 uchar bios_id_lun; /* first boot device scsi id & lun */
1349 /* high nibble is lun */
1350 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001352 uchar termination_se; /* 11 0 - automatic */
1353 /* 1 - low off / high off */
1354 /* 2 - low off / high on */
1355 /* 3 - low on / high on */
1356 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001358 uchar termination_lvd; /* 11 0 - automatic */
1359 /* 1 - low off / high off */
1360 /* 2 - low off / high on */
1361 /* 3 - low on / high on */
1362 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001364 ushort bios_ctrl; /* 12 BIOS control bits */
1365 /* bit 0 BIOS don't act as initiator. */
1366 /* bit 1 BIOS > 1 GB support */
1367 /* bit 2 BIOS > 2 Disk Support */
1368 /* bit 3 BIOS don't support removables */
1369 /* bit 4 BIOS support bootable CD */
1370 /* bit 5 BIOS scan enabled */
1371 /* bit 6 BIOS support multiple LUNs */
1372 /* bit 7 BIOS display of message */
1373 /* bit 8 SCAM disabled */
1374 /* bit 9 Reset SCSI bus during init. */
1375 /* bit 10 */
1376 /* bit 11 No verbose initialization. */
1377 /* bit 12 SCSI parity enabled */
1378 /* bit 13 */
1379 /* bit 14 */
1380 /* bit 15 */
1381 ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
1382 ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
1383 uchar max_host_qng; /* 15 maximum host queueing */
1384 uchar max_dvc_qng; /* maximum per device queuing */
1385 ushort dvc_cntl; /* 16 control bit for driver */
1386 ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
1387 ushort serial_number_word1; /* 18 Board serial number word 1 */
1388 ushort serial_number_word2; /* 19 Board serial number word 2 */
1389 ushort serial_number_word3; /* 20 Board serial number word 3 */
1390 ushort check_sum; /* 21 EEP check sum */
1391 uchar oem_name[16]; /* 22 OEM name */
1392 ushort dvc_err_code; /* 30 last device driver error code */
1393 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
1394 ushort adv_err_addr; /* 32 last uc error address */
1395 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
1396 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
1397 ushort saved_adv_err_addr; /* 35 saved last uc error address */
1398 ushort reserved36; /* 36 reserved */
1399 ushort reserved37; /* 37 reserved */
1400 ushort reserved38; /* 38 reserved */
1401 ushort reserved39; /* 39 reserved */
1402 ushort reserved40; /* 40 reserved */
1403 ushort reserved41; /* 41 reserved */
1404 ushort reserved42; /* 42 reserved */
1405 ushort reserved43; /* 43 reserved */
1406 ushort reserved44; /* 44 reserved */
1407 ushort reserved45; /* 45 reserved */
1408 ushort reserved46; /* 46 reserved */
1409 ushort reserved47; /* 47 reserved */
1410 ushort reserved48; /* 48 reserved */
1411 ushort reserved49; /* 49 reserved */
1412 ushort reserved50; /* 50 reserved */
1413 ushort reserved51; /* 51 reserved */
1414 ushort reserved52; /* 52 reserved */
1415 ushort reserved53; /* 53 reserved */
1416 ushort reserved54; /* 54 reserved */
1417 ushort reserved55; /* 55 reserved */
1418 ushort cisptr_lsw; /* 56 CIS PTR LSW */
1419 ushort cisprt_msw; /* 57 CIS PTR MSW */
1420 ushort subsysvid; /* 58 SubSystem Vendor ID */
1421 ushort subsysid; /* 59 SubSystem ID */
1422 ushort reserved60; /* 60 reserved */
1423 ushort reserved61; /* 61 reserved */
1424 ushort reserved62; /* 62 reserved */
1425 ushort reserved63; /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426} ADVEEP_38C0800_CONFIG;
1427
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001428typedef struct adveep_38C1600_config {
1429 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001431 ushort cfg_lsw; /* 00 power up initialization */
1432 /* bit 11 set - Func. 0 INTB, Func. 1 INTA */
1433 /* clear - Func. 0 INTA, Func. 1 INTB */
1434 /* bit 13 set - Load CIS */
1435 /* bit 14 set - BIOS Enable */
1436 /* bit 15 set - Big Endian Mode */
1437 ushort cfg_msw; /* 01 unused */
1438 ushort disc_enable; /* 02 disconnect enable */
1439 ushort wdtr_able; /* 03 Wide DTR able */
1440 ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
1441 ushort start_motor; /* 05 send start up motor */
1442 ushort tagqng_able; /* 06 tag queuing able */
1443 ushort bios_scan; /* 07 BIOS device control */
1444 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001446 uchar adapter_scsi_id; /* 09 Host Adapter ID */
1447 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001449 uchar scsi_reset_delay; /* 10 reset delay */
1450 uchar bios_id_lun; /* first boot device scsi id & lun */
1451 /* high nibble is lun */
1452 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001454 uchar termination_se; /* 11 0 - automatic */
1455 /* 1 - low off / high off */
1456 /* 2 - low off / high on */
1457 /* 3 - low on / high on */
1458 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001460 uchar termination_lvd; /* 11 0 - automatic */
1461 /* 1 - low off / high off */
1462 /* 2 - low off / high on */
1463 /* 3 - low on / high on */
1464 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001466 ushort bios_ctrl; /* 12 BIOS control bits */
1467 /* bit 0 BIOS don't act as initiator. */
1468 /* bit 1 BIOS > 1 GB support */
1469 /* bit 2 BIOS > 2 Disk Support */
1470 /* bit 3 BIOS don't support removables */
1471 /* bit 4 BIOS support bootable CD */
1472 /* bit 5 BIOS scan enabled */
1473 /* bit 6 BIOS support multiple LUNs */
1474 /* bit 7 BIOS display of message */
1475 /* bit 8 SCAM disabled */
1476 /* bit 9 Reset SCSI bus during init. */
1477 /* bit 10 Basic Integrity Checking disabled */
1478 /* bit 11 No verbose initialization. */
1479 /* bit 12 SCSI parity enabled */
1480 /* bit 13 AIPP (Asyn. Info. Ph. Prot.) dis. */
1481 /* bit 14 */
1482 /* bit 15 */
1483 ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
1484 ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
1485 uchar max_host_qng; /* 15 maximum host queueing */
1486 uchar max_dvc_qng; /* maximum per device queuing */
1487 ushort dvc_cntl; /* 16 control bit for driver */
1488 ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
1489 ushort serial_number_word1; /* 18 Board serial number word 1 */
1490 ushort serial_number_word2; /* 19 Board serial number word 2 */
1491 ushort serial_number_word3; /* 20 Board serial number word 3 */
1492 ushort check_sum; /* 21 EEP check sum */
1493 uchar oem_name[16]; /* 22 OEM name */
1494 ushort dvc_err_code; /* 30 last device driver error code */
1495 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
1496 ushort adv_err_addr; /* 32 last uc error address */
1497 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
1498 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
1499 ushort saved_adv_err_addr; /* 35 saved last uc error address */
1500 ushort reserved36; /* 36 reserved */
1501 ushort reserved37; /* 37 reserved */
1502 ushort reserved38; /* 38 reserved */
1503 ushort reserved39; /* 39 reserved */
1504 ushort reserved40; /* 40 reserved */
1505 ushort reserved41; /* 41 reserved */
1506 ushort reserved42; /* 42 reserved */
1507 ushort reserved43; /* 43 reserved */
1508 ushort reserved44; /* 44 reserved */
1509 ushort reserved45; /* 45 reserved */
1510 ushort reserved46; /* 46 reserved */
1511 ushort reserved47; /* 47 reserved */
1512 ushort reserved48; /* 48 reserved */
1513 ushort reserved49; /* 49 reserved */
1514 ushort reserved50; /* 50 reserved */
1515 ushort reserved51; /* 51 reserved */
1516 ushort reserved52; /* 52 reserved */
1517 ushort reserved53; /* 53 reserved */
1518 ushort reserved54; /* 54 reserved */
1519 ushort reserved55; /* 55 reserved */
1520 ushort cisptr_lsw; /* 56 CIS PTR LSW */
1521 ushort cisprt_msw; /* 57 CIS PTR MSW */
1522 ushort subsysvid; /* 58 SubSystem Vendor ID */
1523 ushort subsysid; /* 59 SubSystem ID */
1524 ushort reserved60; /* 60 reserved */
1525 ushort reserved61; /* 61 reserved */
1526 ushort reserved62; /* 62 reserved */
1527 ushort reserved63; /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528} ADVEEP_38C1600_CONFIG;
1529
1530/*
1531 * EEPROM Commands
1532 */
1533#define ASC_EEP_CMD_DONE 0x0200
1534#define ASC_EEP_CMD_DONE_ERR 0x0001
1535
1536/* cfg_word */
1537#define EEP_CFG_WORD_BIG_ENDIAN 0x8000
1538
1539/* bios_ctrl */
1540#define BIOS_CTRL_BIOS 0x0001
1541#define BIOS_CTRL_EXTENDED_XLAT 0x0002
1542#define BIOS_CTRL_GT_2_DISK 0x0004
1543#define BIOS_CTRL_BIOS_REMOVABLE 0x0008
1544#define BIOS_CTRL_BOOTABLE_CD 0x0010
1545#define BIOS_CTRL_MULTIPLE_LUN 0x0040
1546#define BIOS_CTRL_DISPLAY_MSG 0x0080
1547#define BIOS_CTRL_NO_SCAM 0x0100
1548#define BIOS_CTRL_RESET_SCSI_BUS 0x0200
1549#define BIOS_CTRL_INIT_VERBOSE 0x0800
1550#define BIOS_CTRL_SCSI_PARITY 0x1000
1551#define BIOS_CTRL_AIPP_DIS 0x2000
1552
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001553#define ADV_3550_MEMSIZE 0x2000 /* 8 KB Internal Memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001555#define ADV_38C0800_MEMSIZE 0x4000 /* 16 KB Internal Memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556
1557/*
1558 * XXX - Since ASC38C1600 Rev.3 has a local RAM failure issue, there is
1559 * a special 16K Adv Library and Microcode version. After the issue is
1560 * resolved, should restore 32K support.
1561 *
1562 * #define ADV_38C1600_MEMSIZE 0x8000L * 32 KB Internal Memory *
1563 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001564#define ADV_38C1600_MEMSIZE 0x4000 /* 16 KB Internal Memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565
1566/*
1567 * Byte I/O register address from base of 'iop_base'.
1568 */
1569#define IOPB_INTR_STATUS_REG 0x00
1570#define IOPB_CHIP_ID_1 0x01
1571#define IOPB_INTR_ENABLES 0x02
1572#define IOPB_CHIP_TYPE_REV 0x03
1573#define IOPB_RES_ADDR_4 0x04
1574#define IOPB_RES_ADDR_5 0x05
1575#define IOPB_RAM_DATA 0x06
1576#define IOPB_RES_ADDR_7 0x07
1577#define IOPB_FLAG_REG 0x08
1578#define IOPB_RES_ADDR_9 0x09
1579#define IOPB_RISC_CSR 0x0A
1580#define IOPB_RES_ADDR_B 0x0B
1581#define IOPB_RES_ADDR_C 0x0C
1582#define IOPB_RES_ADDR_D 0x0D
1583#define IOPB_SOFT_OVER_WR 0x0E
1584#define IOPB_RES_ADDR_F 0x0F
1585#define IOPB_MEM_CFG 0x10
1586#define IOPB_RES_ADDR_11 0x11
1587#define IOPB_GPIO_DATA 0x12
1588#define IOPB_RES_ADDR_13 0x13
1589#define IOPB_FLASH_PAGE 0x14
1590#define IOPB_RES_ADDR_15 0x15
1591#define IOPB_GPIO_CNTL 0x16
1592#define IOPB_RES_ADDR_17 0x17
1593#define IOPB_FLASH_DATA 0x18
1594#define IOPB_RES_ADDR_19 0x19
1595#define IOPB_RES_ADDR_1A 0x1A
1596#define IOPB_RES_ADDR_1B 0x1B
1597#define IOPB_RES_ADDR_1C 0x1C
1598#define IOPB_RES_ADDR_1D 0x1D
1599#define IOPB_RES_ADDR_1E 0x1E
1600#define IOPB_RES_ADDR_1F 0x1F
1601#define IOPB_DMA_CFG0 0x20
1602#define IOPB_DMA_CFG1 0x21
1603#define IOPB_TICKLE 0x22
1604#define IOPB_DMA_REG_WR 0x23
1605#define IOPB_SDMA_STATUS 0x24
1606#define IOPB_SCSI_BYTE_CNT 0x25
1607#define IOPB_HOST_BYTE_CNT 0x26
1608#define IOPB_BYTE_LEFT_TO_XFER 0x27
1609#define IOPB_BYTE_TO_XFER_0 0x28
1610#define IOPB_BYTE_TO_XFER_1 0x29
1611#define IOPB_BYTE_TO_XFER_2 0x2A
1612#define IOPB_BYTE_TO_XFER_3 0x2B
1613#define IOPB_ACC_GRP 0x2C
1614#define IOPB_RES_ADDR_2D 0x2D
1615#define IOPB_DEV_ID 0x2E
1616#define IOPB_RES_ADDR_2F 0x2F
1617#define IOPB_SCSI_DATA 0x30
1618#define IOPB_RES_ADDR_31 0x31
1619#define IOPB_RES_ADDR_32 0x32
1620#define IOPB_SCSI_DATA_HSHK 0x33
1621#define IOPB_SCSI_CTRL 0x34
1622#define IOPB_RES_ADDR_35 0x35
1623#define IOPB_RES_ADDR_36 0x36
1624#define IOPB_RES_ADDR_37 0x37
1625#define IOPB_RAM_BIST 0x38
1626#define IOPB_PLL_TEST 0x39
1627#define IOPB_PCI_INT_CFG 0x3A
1628#define IOPB_RES_ADDR_3B 0x3B
1629#define IOPB_RFIFO_CNT 0x3C
1630#define IOPB_RES_ADDR_3D 0x3D
1631#define IOPB_RES_ADDR_3E 0x3E
1632#define IOPB_RES_ADDR_3F 0x3F
1633
1634/*
1635 * Word I/O register address from base of 'iop_base'.
1636 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001637#define IOPW_CHIP_ID_0 0x00 /* CID0 */
1638#define IOPW_CTRL_REG 0x02 /* CC */
1639#define IOPW_RAM_ADDR 0x04 /* LA */
1640#define IOPW_RAM_DATA 0x06 /* LD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641#define IOPW_RES_ADDR_08 0x08
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001642#define IOPW_RISC_CSR 0x0A /* CSR */
1643#define IOPW_SCSI_CFG0 0x0C /* CFG0 */
1644#define IOPW_SCSI_CFG1 0x0E /* CFG1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645#define IOPW_RES_ADDR_10 0x10
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001646#define IOPW_SEL_MASK 0x12 /* SM */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647#define IOPW_RES_ADDR_14 0x14
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001648#define IOPW_FLASH_ADDR 0x16 /* FA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649#define IOPW_RES_ADDR_18 0x18
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001650#define IOPW_EE_CMD 0x1A /* EC */
1651#define IOPW_EE_DATA 0x1C /* ED */
1652#define IOPW_SFIFO_CNT 0x1E /* SFC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653#define IOPW_RES_ADDR_20 0x20
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001654#define IOPW_Q_BASE 0x22 /* QB */
1655#define IOPW_QP 0x24 /* QP */
1656#define IOPW_IX 0x26 /* IX */
1657#define IOPW_SP 0x28 /* SP */
1658#define IOPW_PC 0x2A /* PC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659#define IOPW_RES_ADDR_2C 0x2C
1660#define IOPW_RES_ADDR_2E 0x2E
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001661#define IOPW_SCSI_DATA 0x30 /* SD */
1662#define IOPW_SCSI_DATA_HSHK 0x32 /* SDH */
1663#define IOPW_SCSI_CTRL 0x34 /* SC */
1664#define IOPW_HSHK_CFG 0x36 /* HCFG */
1665#define IOPW_SXFR_STATUS 0x36 /* SXS */
1666#define IOPW_SXFR_CNTL 0x38 /* SXL */
1667#define IOPW_SXFR_CNTH 0x3A /* SXH */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668#define IOPW_RES_ADDR_3C 0x3C
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001669#define IOPW_RFIFO_DATA 0x3E /* RFD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670
1671/*
1672 * Doubleword I/O register address from base of 'iop_base'.
1673 */
1674#define IOPDW_RES_ADDR_0 0x00
1675#define IOPDW_RAM_DATA 0x04
1676#define IOPDW_RES_ADDR_8 0x08
1677#define IOPDW_RES_ADDR_C 0x0C
1678#define IOPDW_RES_ADDR_10 0x10
1679#define IOPDW_COMMA 0x14
1680#define IOPDW_COMMB 0x18
1681#define IOPDW_RES_ADDR_1C 0x1C
1682#define IOPDW_SDMA_ADDR0 0x20
1683#define IOPDW_SDMA_ADDR1 0x24
1684#define IOPDW_SDMA_COUNT 0x28
1685#define IOPDW_SDMA_ERROR 0x2C
1686#define IOPDW_RDMA_ADDR0 0x30
1687#define IOPDW_RDMA_ADDR1 0x34
1688#define IOPDW_RDMA_COUNT 0x38
1689#define IOPDW_RDMA_ERROR 0x3C
1690
1691#define ADV_CHIP_ID_BYTE 0x25
1692#define ADV_CHIP_ID_WORD 0x04C1
1693
1694#define ADV_SC_SCSI_BUS_RESET 0x2000
1695
1696#define ADV_INTR_ENABLE_HOST_INTR 0x01
1697#define ADV_INTR_ENABLE_SEL_INTR 0x02
1698#define ADV_INTR_ENABLE_DPR_INTR 0x04
1699#define ADV_INTR_ENABLE_RTA_INTR 0x08
1700#define ADV_INTR_ENABLE_RMA_INTR 0x10
1701#define ADV_INTR_ENABLE_RST_INTR 0x20
1702#define ADV_INTR_ENABLE_DPE_INTR 0x40
1703#define ADV_INTR_ENABLE_GLOBAL_INTR 0x80
1704
1705#define ADV_INTR_STATUS_INTRA 0x01
1706#define ADV_INTR_STATUS_INTRB 0x02
1707#define ADV_INTR_STATUS_INTRC 0x04
1708
1709#define ADV_RISC_CSR_STOP (0x0000)
1710#define ADV_RISC_TEST_COND (0x2000)
1711#define ADV_RISC_CSR_RUN (0x4000)
1712#define ADV_RISC_CSR_SINGLE_STEP (0x8000)
1713
1714#define ADV_CTRL_REG_HOST_INTR 0x0100
1715#define ADV_CTRL_REG_SEL_INTR 0x0200
1716#define ADV_CTRL_REG_DPR_INTR 0x0400
1717#define ADV_CTRL_REG_RTA_INTR 0x0800
1718#define ADV_CTRL_REG_RMA_INTR 0x1000
1719#define ADV_CTRL_REG_RES_BIT14 0x2000
1720#define ADV_CTRL_REG_DPE_INTR 0x4000
1721#define ADV_CTRL_REG_POWER_DONE 0x8000
1722#define ADV_CTRL_REG_ANY_INTR 0xFF00
1723
1724#define ADV_CTRL_REG_CMD_RESET 0x00C6
1725#define ADV_CTRL_REG_CMD_WR_IO_REG 0x00C5
1726#define ADV_CTRL_REG_CMD_RD_IO_REG 0x00C4
1727#define ADV_CTRL_REG_CMD_WR_PCI_CFG_SPACE 0x00C3
1728#define ADV_CTRL_REG_CMD_RD_PCI_CFG_SPACE 0x00C2
1729
1730#define ADV_TICKLE_NOP 0x00
1731#define ADV_TICKLE_A 0x01
1732#define ADV_TICKLE_B 0x02
1733#define ADV_TICKLE_C 0x03
1734
1735#define ADV_SCSI_CTRL_RSTOUT 0x2000
1736
1737#define AdvIsIntPending(port) \
1738 (AdvReadWordRegister(port, IOPW_CTRL_REG) & ADV_CTRL_REG_HOST_INTR)
1739
1740/*
1741 * SCSI_CFG0 Register bit definitions
1742 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001743#define TIMER_MODEAB 0xC000 /* Watchdog, Second, and Select. Timer Ctrl. */
1744#define PARITY_EN 0x2000 /* Enable SCSI Parity Error detection */
1745#define EVEN_PARITY 0x1000 /* Select Even Parity */
1746#define WD_LONG 0x0800 /* Watchdog Interval, 1: 57 min, 0: 13 sec */
1747#define QUEUE_128 0x0400 /* Queue Size, 1: 128 byte, 0: 64 byte */
1748#define PRIM_MODE 0x0100 /* Primitive SCSI mode */
1749#define SCAM_EN 0x0080 /* Enable SCAM selection */
1750#define SEL_TMO_LONG 0x0040 /* Sel/Resel Timeout, 1: 400 ms, 0: 1.6 ms */
1751#define CFRM_ID 0x0020 /* SCAM id sel. confirm., 1: fast, 0: 6.4 ms */
1752#define OUR_ID_EN 0x0010 /* Enable OUR_ID bits */
1753#define OUR_ID 0x000F /* SCSI ID */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754
1755/*
1756 * SCSI_CFG1 Register bit definitions
1757 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001758#define BIG_ENDIAN 0x8000 /* Enable Big Endian Mode MIO:15, EEP:15 */
1759#define TERM_POL 0x2000 /* Terminator Polarity Ctrl. MIO:13, EEP:13 */
1760#define SLEW_RATE 0x1000 /* SCSI output buffer slew rate */
1761#define FILTER_SEL 0x0C00 /* Filter Period Selection */
1762#define FLTR_DISABLE 0x0000 /* Input Filtering Disabled */
1763#define FLTR_11_TO_20NS 0x0800 /* Input Filtering 11ns to 20ns */
1764#define FLTR_21_TO_39NS 0x0C00 /* Input Filtering 21ns to 39ns */
1765#define ACTIVE_DBL 0x0200 /* Disable Active Negation */
1766#define DIFF_MODE 0x0100 /* SCSI differential Mode (Read-Only) */
1767#define DIFF_SENSE 0x0080 /* 1: No SE cables, 0: SE cable (Read-Only) */
1768#define TERM_CTL_SEL 0x0040 /* Enable TERM_CTL_H and TERM_CTL_L */
1769#define TERM_CTL 0x0030 /* External SCSI Termination Bits */
1770#define TERM_CTL_H 0x0020 /* Enable External SCSI Upper Termination */
1771#define TERM_CTL_L 0x0010 /* Enable External SCSI Lower Termination */
1772#define CABLE_DETECT 0x000F /* External SCSI Cable Connection Status */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773
1774/*
1775 * Addendum for ASC-38C0800 Chip
1776 *
1777 * The ASC-38C1600 Chip uses the same definitions except that the
1778 * bus mode override bits [12:10] have been moved to byte register
1779 * offset 0xE (IOPB_SOFT_OVER_WR) bits [12:10]. The [12:10] bits in
1780 * SCSI_CFG1 are read-only and always available. Bit 14 (DIS_TERM_DRV)
1781 * is not needed. The [12:10] bits in IOPB_SOFT_OVER_WR are write-only.
1782 * Also each ASC-38C1600 function or channel uses only cable bits [5:4]
1783 * and [1:0]. Bits [14], [7:6], [3:2] are unused.
1784 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001785#define DIS_TERM_DRV 0x4000 /* 1: Read c_det[3:0], 0: cannot read */
1786#define HVD_LVD_SE 0x1C00 /* Device Detect Bits */
1787#define HVD 0x1000 /* HVD Device Detect */
1788#define LVD 0x0800 /* LVD Device Detect */
1789#define SE 0x0400 /* SE Device Detect */
1790#define TERM_LVD 0x00C0 /* LVD Termination Bits */
1791#define TERM_LVD_HI 0x0080 /* Enable LVD Upper Termination */
1792#define TERM_LVD_LO 0x0040 /* Enable LVD Lower Termination */
1793#define TERM_SE 0x0030 /* SE Termination Bits */
1794#define TERM_SE_HI 0x0020 /* Enable SE Upper Termination */
1795#define TERM_SE_LO 0x0010 /* Enable SE Lower Termination */
1796#define C_DET_LVD 0x000C /* LVD Cable Detect Bits */
1797#define C_DET3 0x0008 /* Cable Detect for LVD External Wide */
1798#define C_DET2 0x0004 /* Cable Detect for LVD Internal Wide */
1799#define C_DET_SE 0x0003 /* SE Cable Detect Bits */
1800#define C_DET1 0x0002 /* Cable Detect for SE Internal Wide */
1801#define C_DET0 0x0001 /* Cable Detect for SE Internal Narrow */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802
1803#define CABLE_ILLEGAL_A 0x7
1804 /* x 0 0 0 | on on | Illegal (all 3 connectors are used) */
1805
1806#define CABLE_ILLEGAL_B 0xB
1807 /* 0 x 0 0 | on on | Illegal (all 3 connectors are used) */
1808
1809/*
1810 * MEM_CFG Register bit definitions
1811 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001812#define BIOS_EN 0x40 /* BIOS Enable MIO:14,EEP:14 */
1813#define FAST_EE_CLK 0x20 /* Diagnostic Bit */
1814#define RAM_SZ 0x1C /* Specify size of RAM to RISC */
1815#define RAM_SZ_2KB 0x00 /* 2 KB */
1816#define RAM_SZ_4KB 0x04 /* 4 KB */
1817#define RAM_SZ_8KB 0x08 /* 8 KB */
1818#define RAM_SZ_16KB 0x0C /* 16 KB */
1819#define RAM_SZ_32KB 0x10 /* 32 KB */
1820#define RAM_SZ_64KB 0x14 /* 64 KB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821
1822/*
1823 * DMA_CFG0 Register bit definitions
1824 *
1825 * This register is only accessible to the host.
1826 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001827#define BC_THRESH_ENB 0x80 /* PCI DMA Start Conditions */
1828#define FIFO_THRESH 0x70 /* PCI DMA FIFO Threshold */
1829#define FIFO_THRESH_16B 0x00 /* 16 bytes */
1830#define FIFO_THRESH_32B 0x20 /* 32 bytes */
1831#define FIFO_THRESH_48B 0x30 /* 48 bytes */
1832#define FIFO_THRESH_64B 0x40 /* 64 bytes */
1833#define FIFO_THRESH_80B 0x50 /* 80 bytes (default) */
1834#define FIFO_THRESH_96B 0x60 /* 96 bytes */
1835#define FIFO_THRESH_112B 0x70 /* 112 bytes */
1836#define START_CTL 0x0C /* DMA start conditions */
1837#define START_CTL_TH 0x00 /* Wait threshold level (default) */
1838#define START_CTL_ID 0x04 /* Wait SDMA/SBUS idle */
1839#define START_CTL_THID 0x08 /* Wait threshold and SDMA/SBUS idle */
1840#define START_CTL_EMFU 0x0C /* Wait SDMA FIFO empty/full */
1841#define READ_CMD 0x03 /* Memory Read Method */
1842#define READ_CMD_MR 0x00 /* Memory Read */
1843#define READ_CMD_MRL 0x02 /* Memory Read Long */
1844#define READ_CMD_MRM 0x03 /* Memory Read Multiple (default) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845
1846/*
1847 * ASC-38C0800 RAM BIST Register bit definitions
1848 */
1849#define RAM_TEST_MODE 0x80
1850#define PRE_TEST_MODE 0x40
1851#define NORMAL_MODE 0x00
1852#define RAM_TEST_DONE 0x10
1853#define RAM_TEST_STATUS 0x0F
1854#define RAM_TEST_HOST_ERROR 0x08
1855#define RAM_TEST_INTRAM_ERROR 0x04
1856#define RAM_TEST_RISC_ERROR 0x02
1857#define RAM_TEST_SCSI_ERROR 0x01
1858#define RAM_TEST_SUCCESS 0x00
1859#define PRE_TEST_VALUE 0x05
1860#define NORMAL_VALUE 0x00
1861
1862/*
1863 * ASC38C1600 Definitions
1864 *
1865 * IOPB_PCI_INT_CFG Bit Field Definitions
1866 */
1867
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001868#define INTAB_LD 0x80 /* Value loaded from EEPROM Bit 11. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869
1870/*
1871 * Bit 1 can be set to change the interrupt for the Function to operate in
1872 * Totem Pole mode. By default Bit 1 is 0 and the interrupt operates in
1873 * Open Drain mode. Both functions of the ASC38C1600 must be set to the same
1874 * mode, otherwise the operating mode is undefined.
1875 */
1876#define TOTEMPOLE 0x02
1877
1878/*
1879 * Bit 0 can be used to change the Int Pin for the Function. The value is
1880 * 0 by default for both Functions with Function 0 using INT A and Function
1881 * B using INT B. For Function 0 if set, INT B is used. For Function 1 if set,
1882 * INT A is used.
1883 *
1884 * EEPROM Word 0 Bit 11 for each Function may change the initial Int Pin
1885 * value specified in the PCI Configuration Space.
1886 */
1887#define INTAB 0x01
1888
1889/* a_advlib.h */
1890
1891/*
1892 * Adv Library Status Definitions
1893 */
1894#define ADV_TRUE 1
1895#define ADV_FALSE 0
1896#define ADV_NOERROR 1
1897#define ADV_SUCCESS 1
1898#define ADV_BUSY 0
1899#define ADV_ERROR (-1)
1900
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901/*
1902 * ADV_DVC_VAR 'warn_code' values
1903 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001904#define ASC_WARN_BUSRESET_ERROR 0x0001 /* SCSI Bus Reset error */
1905#define ASC_WARN_EEPROM_CHKSUM 0x0002 /* EEP check sum error */
1906#define ASC_WARN_EEPROM_TERMINATION 0x0004 /* EEP termination bad field */
1907#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080 /* PCI config space set error */
1908#define ASC_WARN_ERROR 0xFFFF /* ADV_ERROR return */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001910#define ADV_MAX_TID 15 /* max. target identifier */
1911#define ADV_MAX_LUN 7 /* max. logical unit number */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912
1913/*
1914 * Error code values are set in ADV_DVC_VAR 'err_code'.
1915 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001916#define ASC_IERR_WRITE_EEPROM 0x0001 /* write EEPROM error */
1917#define ASC_IERR_MCODE_CHKSUM 0x0002 /* micro code check sum error */
1918#define ASC_IERR_NO_CARRIER 0x0004 /* No more carrier memory. */
1919#define ASC_IERR_START_STOP_CHIP 0x0008 /* start/stop chip failed */
1920#define ASC_IERR_CHIP_VERSION 0x0040 /* wrong chip version */
1921#define ASC_IERR_SET_SCSI_ID 0x0080 /* set SCSI ID failed */
1922#define ASC_IERR_HVD_DEVICE 0x0100 /* HVD attached to LVD connector. */
1923#define ASC_IERR_BAD_SIGNATURE 0x0200 /* signature not found */
1924#define ASC_IERR_ILLEGAL_CONNECTION 0x0400 /* Illegal cable connection */
1925#define ASC_IERR_SINGLE_END_DEVICE 0x0800 /* Single-end used w/differential */
1926#define ASC_IERR_REVERSED_CABLE 0x1000 /* Narrow flat cable reversed */
1927#define ASC_IERR_BIST_PRE_TEST 0x2000 /* BIST pre-test error */
1928#define ASC_IERR_BIST_RAM_TEST 0x4000 /* BIST RAM test error */
1929#define ASC_IERR_BAD_CHIPTYPE 0x8000 /* Invalid 'chip_type' setting. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930
1931/*
1932 * Fixed locations of microcode operating variables.
1933 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001934#define ASC_MC_CODE_BEGIN_ADDR 0x0028 /* microcode start address */
1935#define ASC_MC_CODE_END_ADDR 0x002A /* microcode end address */
1936#define ASC_MC_CODE_CHK_SUM 0x002C /* microcode code checksum */
1937#define ASC_MC_VERSION_DATE 0x0038 /* microcode version */
1938#define ASC_MC_VERSION_NUM 0x003A /* microcode number */
1939#define ASC_MC_BIOSMEM 0x0040 /* BIOS RISC Memory Start */
1940#define ASC_MC_BIOSLEN 0x0050 /* BIOS RISC Memory Length */
1941#define ASC_MC_BIOS_SIGNATURE 0x0058 /* BIOS Signature 0x55AA */
1942#define ASC_MC_BIOS_VERSION 0x005A /* BIOS Version (2 bytes) */
1943#define ASC_MC_SDTR_SPEED1 0x0090 /* SDTR Speed for TID 0-3 */
1944#define ASC_MC_SDTR_SPEED2 0x0092 /* SDTR Speed for TID 4-7 */
1945#define ASC_MC_SDTR_SPEED3 0x0094 /* SDTR Speed for TID 8-11 */
1946#define ASC_MC_SDTR_SPEED4 0x0096 /* SDTR Speed for TID 12-15 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947#define ASC_MC_CHIP_TYPE 0x009A
1948#define ASC_MC_INTRB_CODE 0x009B
1949#define ASC_MC_WDTR_ABLE 0x009C
1950#define ASC_MC_SDTR_ABLE 0x009E
1951#define ASC_MC_TAGQNG_ABLE 0x00A0
1952#define ASC_MC_DISC_ENABLE 0x00A2
1953#define ASC_MC_IDLE_CMD_STATUS 0x00A4
1954#define ASC_MC_IDLE_CMD 0x00A6
1955#define ASC_MC_IDLE_CMD_PARAMETER 0x00A8
1956#define ASC_MC_DEFAULT_SCSI_CFG0 0x00AC
1957#define ASC_MC_DEFAULT_SCSI_CFG1 0x00AE
1958#define ASC_MC_DEFAULT_MEM_CFG 0x00B0
1959#define ASC_MC_DEFAULT_SEL_MASK 0x00B2
1960#define ASC_MC_SDTR_DONE 0x00B6
1961#define ASC_MC_NUMBER_OF_QUEUED_CMD 0x00C0
1962#define ASC_MC_NUMBER_OF_MAX_CMD 0x00D0
1963#define ASC_MC_DEVICE_HSHK_CFG_TABLE 0x0100
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001964#define ASC_MC_CONTROL_FLAG 0x0122 /* Microcode control flag. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965#define ASC_MC_WDTR_DONE 0x0124
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001966#define ASC_MC_CAM_MODE_MASK 0x015E /* CAM mode TID bitmask. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967#define ASC_MC_ICQ 0x0160
1968#define ASC_MC_IRQ 0x0164
1969#define ASC_MC_PPR_ABLE 0x017A
1970
1971/*
1972 * BIOS LRAM variable absolute offsets.
1973 */
1974#define BIOS_CODESEG 0x54
1975#define BIOS_CODELEN 0x56
1976#define BIOS_SIGNATURE 0x58
1977#define BIOS_VERSION 0x5A
1978
1979/*
1980 * Microcode Control Flags
1981 *
1982 * Flags set by the Adv Library in RISC variable 'control_flag' (0x122)
1983 * and handled by the microcode.
1984 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001985#define CONTROL_FLAG_IGNORE_PERR 0x0001 /* Ignore DMA Parity Errors */
1986#define CONTROL_FLAG_ENABLE_AIPP 0x0002 /* Enabled AIPP checking. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987
1988/*
1989 * ASC_MC_DEVICE_HSHK_CFG_TABLE microcode table or HSHK_CFG register format
1990 */
1991#define HSHK_CFG_WIDE_XFR 0x8000
1992#define HSHK_CFG_RATE 0x0F00
1993#define HSHK_CFG_OFFSET 0x001F
1994
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001995#define ASC_DEF_MAX_HOST_QNG 0xFD /* Max. number of host commands (253) */
1996#define ASC_DEF_MIN_HOST_QNG 0x10 /* Min. number of host commands (16) */
1997#define ASC_DEF_MAX_DVC_QNG 0x3F /* Max. number commands per device (63) */
1998#define ASC_DEF_MIN_DVC_QNG 0x04 /* Min. number commands per device (4) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002000#define ASC_QC_DATA_CHECK 0x01 /* Require ASC_QC_DATA_OUT set or clear. */
2001#define ASC_QC_DATA_OUT 0x02 /* Data out DMA transfer. */
2002#define ASC_QC_START_MOTOR 0x04 /* Send auto-start motor before request. */
2003#define ASC_QC_NO_OVERRUN 0x08 /* Don't report overrun. */
2004#define ASC_QC_FREEZE_TIDQ 0x10 /* Freeze TID queue after request. XXX TBD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002006#define ASC_QSC_NO_DISC 0x01 /* Don't allow disconnect for request. */
2007#define ASC_QSC_NO_TAGMSG 0x02 /* Don't allow tag queuing for request. */
2008#define ASC_QSC_NO_SYNC 0x04 /* Don't use Synch. transfer on request. */
2009#define ASC_QSC_NO_WIDE 0x08 /* Don't use Wide transfer on request. */
2010#define ASC_QSC_REDO_DTR 0x10 /* Renegotiate WDTR/SDTR before request. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011/*
2012 * Note: If a Tag Message is to be sent and neither ASC_QSC_HEAD_TAG or
2013 * ASC_QSC_ORDERED_TAG is set, then a Simple Tag Message (0x20) is used.
2014 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002015#define ASC_QSC_HEAD_TAG 0x40 /* Use Head Tag Message (0x21). */
2016#define ASC_QSC_ORDERED_TAG 0x80 /* Use Ordered Tag Message (0x22). */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017
2018/*
2019 * All fields here are accessed by the board microcode and need to be
2020 * little-endian.
2021 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002022typedef struct adv_carr_t {
2023 ADV_VADDR carr_va; /* Carrier Virtual Address */
2024 ADV_PADDR carr_pa; /* Carrier Physical Address */
2025 ADV_VADDR areq_vpa; /* ASC_SCSI_REQ_Q Virtual or Physical Address */
2026 /*
2027 * next_vpa [31:4] Carrier Virtual or Physical Next Pointer
2028 *
2029 * next_vpa [3:1] Reserved Bits
2030 * next_vpa [0] Done Flag set in Response Queue.
2031 */
2032 ADV_VADDR next_vpa;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033} ADV_CARR_T;
2034
2035/*
2036 * Mask used to eliminate low 4 bits of carrier 'next_vpa' field.
2037 */
2038#define ASC_NEXT_VPA_MASK 0xFFFFFFF0
2039
2040#define ASC_RQ_DONE 0x00000001
2041#define ASC_RQ_GOOD 0x00000002
2042#define ASC_CQ_STOPPER 0x00000000
2043
2044#define ASC_GET_CARRP(carrp) ((carrp) & ASC_NEXT_VPA_MASK)
2045
2046#define ADV_CARRIER_NUM_PAGE_CROSSING \
2047 (((ADV_CARRIER_COUNT * sizeof(ADV_CARR_T)) + \
2048 (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
2049
2050#define ADV_CARRIER_BUFSIZE \
2051 ((ADV_CARRIER_COUNT + ADV_CARRIER_NUM_PAGE_CROSSING) * sizeof(ADV_CARR_T))
2052
2053/*
2054 * ASC_SCSI_REQ_Q 'a_flag' definitions
2055 *
2056 * The Adv Library should limit use to the lower nibble (4 bits) of
2057 * a_flag. Drivers are free to use the upper nibble (4 bits) of a_flag.
2058 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002059#define ADV_POLL_REQUEST 0x01 /* poll for request completion */
2060#define ADV_SCSIQ_DONE 0x02 /* request done */
2061#define ADV_DONT_RETRY 0x08 /* don't do retry */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002063#define ADV_CHIP_ASC3550 0x01 /* Ultra-Wide IC */
2064#define ADV_CHIP_ASC38C0800 0x02 /* Ultra2-Wide/LVD IC */
2065#define ADV_CHIP_ASC38C1600 0x03 /* Ultra3-Wide/LVD2 IC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066
2067/*
2068 * Adapter temporary configuration structure
2069 *
2070 * This structure can be discarded after initialization. Don't add
2071 * fields here needed after initialization.
2072 *
2073 * Field naming convention:
2074 *
2075 * *_enable indicates the field enables or disables a feature. The
2076 * value of the field is never reset.
2077 */
2078typedef struct adv_dvc_cfg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002079 ushort disc_enable; /* enable disconnection */
2080 uchar chip_version; /* chip version */
2081 uchar termination; /* Term. Ctrl. bits 6-5 of SCSI_CFG1 register */
2082 ushort lib_version; /* Adv Library version number */
2083 ushort control_flag; /* Microcode Control Flag */
2084 ushort mcode_date; /* Microcode date */
2085 ushort mcode_version; /* Microcode version */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002086 ushort serial1; /* EEPROM serial number word 1 */
2087 ushort serial2; /* EEPROM serial number word 2 */
2088 ushort serial3; /* EEPROM serial number word 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089} ADV_DVC_CFG;
2090
2091struct adv_dvc_var;
2092struct adv_scsi_req_q;
2093
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094/*
2095 * Adapter operation variable structure.
2096 *
2097 * One structure is required per host adapter.
2098 *
2099 * Field naming convention:
2100 *
2101 * *_able indicates both whether a feature should be enabled or disabled
2102 * and whether a device isi capable of the feature. At initialization
2103 * this field may be set, but later if a device is found to be incapable
2104 * of the feature, the field is cleared.
2105 */
2106typedef struct adv_dvc_var {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002107 AdvPortAddr iop_base; /* I/O port address */
2108 ushort err_code; /* fatal error code */
2109 ushort bios_ctrl; /* BIOS control word, EEPROM word 12 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002110 ushort wdtr_able; /* try WDTR for a device */
2111 ushort sdtr_able; /* try SDTR for a device */
2112 ushort ultra_able; /* try SDTR Ultra speed for a device */
2113 ushort sdtr_speed1; /* EEPROM SDTR Speed for TID 0-3 */
2114 ushort sdtr_speed2; /* EEPROM SDTR Speed for TID 4-7 */
2115 ushort sdtr_speed3; /* EEPROM SDTR Speed for TID 8-11 */
2116 ushort sdtr_speed4; /* EEPROM SDTR Speed for TID 12-15 */
2117 ushort tagqng_able; /* try tagged queuing with a device */
2118 ushort ppr_able; /* PPR message capable per TID bitmask. */
2119 uchar max_dvc_qng; /* maximum number of tagged commands per device */
2120 ushort start_motor; /* start motor command allowed */
2121 uchar scsi_reset_wait; /* delay in seconds after scsi bus reset */
2122 uchar chip_no; /* should be assigned by caller */
2123 uchar max_host_qng; /* maximum number of Q'ed command allowed */
2124 uchar irq_no; /* IRQ number */
2125 ushort no_scam; /* scam_tolerant of EEPROM */
2126 struct asc_board *drv_ptr; /* driver pointer to private structure */
2127 uchar chip_scsi_id; /* chip SCSI target ID */
2128 uchar chip_type;
2129 uchar bist_err_code;
2130 ADV_CARR_T *carrier_buf;
2131 ADV_CARR_T *carr_freelist; /* Carrier free list. */
2132 ADV_CARR_T *icq_sp; /* Initiator command queue stopper pointer. */
2133 ADV_CARR_T *irq_sp; /* Initiator response queue stopper pointer. */
2134 ushort carr_pending_cnt; /* Count of pending carriers. */
2135 /*
2136 * Note: The following fields will not be used after initialization. The
2137 * driver may discard the buffer after initialization is done.
2138 */
2139 ADV_DVC_CFG *cfg; /* temporary configuration structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140} ADV_DVC_VAR;
2141
2142#define NO_OF_SG_PER_BLOCK 15
2143
2144typedef struct asc_sg_block {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002145 uchar reserved1;
2146 uchar reserved2;
2147 uchar reserved3;
2148 uchar sg_cnt; /* Valid entries in block. */
2149 ADV_PADDR sg_ptr; /* Pointer to next sg block. */
2150 struct {
2151 ADV_PADDR sg_addr; /* SG element address. */
2152 ADV_DCNT sg_count; /* SG element count. */
2153 } sg_list[NO_OF_SG_PER_BLOCK];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154} ADV_SG_BLOCK;
2155
2156/*
2157 * ADV_SCSI_REQ_Q - microcode request structure
2158 *
2159 * All fields in this structure up to byte 60 are used by the microcode.
2160 * The microcode makes assumptions about the size and ordering of fields
2161 * in this structure. Do not change the structure definition here without
2162 * coordinating the change with the microcode.
2163 *
2164 * All fields accessed by microcode must be maintained in little_endian
2165 * order.
2166 */
2167typedef struct adv_scsi_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002168 uchar cntl; /* Ucode flags and state (ASC_MC_QC_*). */
2169 uchar target_cmd;
2170 uchar target_id; /* Device target identifier. */
2171 uchar target_lun; /* Device target logical unit number. */
2172 ADV_PADDR data_addr; /* Data buffer physical address. */
2173 ADV_DCNT data_cnt; /* Data count. Ucode sets to residual. */
2174 ADV_PADDR sense_addr;
2175 ADV_PADDR carr_pa;
2176 uchar mflag;
2177 uchar sense_len;
2178 uchar cdb_len; /* SCSI CDB length. Must <= 16 bytes. */
2179 uchar scsi_cntl;
2180 uchar done_status; /* Completion status. */
2181 uchar scsi_status; /* SCSI status byte. */
2182 uchar host_status; /* Ucode host status. */
2183 uchar sg_working_ix;
2184 uchar cdb[12]; /* SCSI CDB bytes 0-11. */
2185 ADV_PADDR sg_real_addr; /* SG list physical address. */
2186 ADV_PADDR scsiq_rptr;
2187 uchar cdb16[4]; /* SCSI CDB bytes 12-15. */
2188 ADV_VADDR scsiq_ptr;
2189 ADV_VADDR carr_va;
2190 /*
2191 * End of microcode structure - 60 bytes. The rest of the structure
2192 * is used by the Adv Library and ignored by the microcode.
2193 */
2194 ADV_VADDR srb_ptr;
2195 ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */
2196 char *vdata_addr; /* Data buffer virtual address. */
2197 uchar a_flag;
2198 uchar pad[2]; /* Pad out to a word boundary. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199} ADV_SCSI_REQ_Q;
2200
2201/*
2202 * Microcode idle loop commands
2203 */
2204#define IDLE_CMD_COMPLETED 0
2205#define IDLE_CMD_STOP_CHIP 0x0001
2206#define IDLE_CMD_STOP_CHIP_SEND_INT 0x0002
2207#define IDLE_CMD_SEND_INT 0x0004
2208#define IDLE_CMD_ABORT 0x0008
2209#define IDLE_CMD_DEVICE_RESET 0x0010
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002210#define IDLE_CMD_SCSI_RESET_START 0x0020 /* Assert SCSI Bus Reset */
2211#define IDLE_CMD_SCSI_RESET_END 0x0040 /* Deassert SCSI Bus Reset */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212#define IDLE_CMD_SCSIREQ 0x0080
2213
2214#define IDLE_CMD_STATUS_SUCCESS 0x0001
2215#define IDLE_CMD_STATUS_FAILURE 0x0002
2216
2217/*
2218 * AdvSendIdleCmd() flag definitions.
2219 */
2220#define ADV_NOWAIT 0x01
2221
2222/*
2223 * Wait loop time out values.
2224 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002225#define SCSI_WAIT_10_SEC 10UL /* 10 seconds */
2226#define SCSI_WAIT_100_MSEC 100UL /* 100 milliseconds */
2227#define SCSI_US_PER_MSEC 1000 /* microseconds per millisecond */
2228#define SCSI_MS_PER_SEC 1000UL /* milliseconds per second */
2229#define SCSI_MAX_RETRY 10 /* retry count */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002231#define ADV_ASYNC_RDMA_FAILURE 0x01 /* Fatal RDMA failure. */
2232#define ADV_ASYNC_SCSI_BUS_RESET_DET 0x02 /* Detected SCSI Bus Reset. */
2233#define ADV_ASYNC_CARRIER_READY_FAILURE 0x03 /* Carrier Ready failure. */
2234#define ADV_RDMA_IN_CARR_AND_Q_INVALID 0x04 /* RDMAed-in data invalid. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002236#define ADV_HOST_SCSI_BUS_RESET 0x80 /* Host Initiated SCSI Bus Reset. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237
2238/*
2239 * Device drivers must define the following functions.
2240 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002241static inline ulong DvcEnterCritical(void);
2242static inline void DvcLeaveCritical(ulong);
2243static void DvcSleepMilliSecond(ADV_DCNT);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002244static ADV_PADDR DvcGetPhyAddr(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *,
2245 uchar *, ASC_SDCNT *, int);
2246static void DvcDelayMicroSecond(ADV_DVC_VAR *, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247
2248/*
2249 * Adv Library functions available to drivers.
2250 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002251static int AdvExeScsiQueue(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
2252static int AdvISR(ADV_DVC_VAR *);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002253static int AdvInitAsc3550Driver(ADV_DVC_VAR *);
2254static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *);
2255static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *);
2256static int AdvResetChipAndSB(ADV_DVC_VAR *);
2257static int AdvResetSB(ADV_DVC_VAR *asc_dvc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258
2259/*
2260 * Internal Adv Library functions.
2261 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002262static int AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ADV_DCNT);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002263static int AdvInitFrom3550EEP(ADV_DVC_VAR *);
2264static int AdvInitFrom38C0800EEP(ADV_DVC_VAR *);
2265static int AdvInitFrom38C1600EEP(ADV_DVC_VAR *);
2266static ushort AdvGet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
2267static void AdvSet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
2268static ushort AdvGet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
2269static void AdvSet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
2270static ushort AdvGet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
2271static void AdvSet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
2272static void AdvWaitEEPCmd(AdvPortAddr);
2273static ushort AdvReadEEPWord(AdvPortAddr, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275/* Read byte from a register. */
2276#define AdvReadByteRegister(iop_base, reg_off) \
2277 (ADV_MEM_READB((iop_base) + (reg_off)))
2278
2279/* Write byte to a register. */
2280#define AdvWriteByteRegister(iop_base, reg_off, byte) \
2281 (ADV_MEM_WRITEB((iop_base) + (reg_off), (byte)))
2282
2283/* Read word (2 bytes) from a register. */
2284#define AdvReadWordRegister(iop_base, reg_off) \
2285 (ADV_MEM_READW((iop_base) + (reg_off)))
2286
2287/* Write word (2 bytes) to a register. */
2288#define AdvWriteWordRegister(iop_base, reg_off, word) \
2289 (ADV_MEM_WRITEW((iop_base) + (reg_off), (word)))
2290
2291/* Write dword (4 bytes) to a register. */
2292#define AdvWriteDWordRegister(iop_base, reg_off, dword) \
2293 (ADV_MEM_WRITEDW((iop_base) + (reg_off), (dword)))
2294
2295/* Read byte from LRAM. */
2296#define AdvReadByteLram(iop_base, addr, byte) \
2297do { \
2298 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
2299 (byte) = ADV_MEM_READB((iop_base) + IOPB_RAM_DATA); \
2300} while (0)
2301
2302/* Write byte to LRAM. */
2303#define AdvWriteByteLram(iop_base, addr, byte) \
2304 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
2305 ADV_MEM_WRITEB((iop_base) + IOPB_RAM_DATA, (byte)))
2306
2307/* Read word (2 bytes) from LRAM. */
2308#define AdvReadWordLram(iop_base, addr, word) \
2309do { \
2310 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
2311 (word) = (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA)); \
2312} while (0)
2313
2314/* Write word (2 bytes) to LRAM. */
2315#define AdvWriteWordLram(iop_base, addr, word) \
2316 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
2317 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
2318
2319/* Write little-endian double word (4 bytes) to LRAM */
2320/* Because of unspecified C language ordering don't use auto-increment. */
2321#define AdvWriteDWordLramNoSwap(iop_base, addr, dword) \
2322 ((ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
2323 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
2324 cpu_to_le16((ushort) ((dword) & 0xFFFF)))), \
2325 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr) + 2), \
2326 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
2327 cpu_to_le16((ushort) ((dword >> 16) & 0xFFFF)))))
2328
2329/* Read word (2 bytes) from LRAM assuming that the address is already set. */
2330#define AdvReadWordAutoIncLram(iop_base) \
2331 (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA))
2332
2333/* Write word (2 bytes) to LRAM assuming that the address is already set. */
2334#define AdvWriteWordAutoIncLram(iop_base, word) \
2335 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
2336
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337/*
2338 * Define macro to check for Condor signature.
2339 *
2340 * Evaluate to ADV_TRUE if a Condor chip is found the specified port
2341 * address 'iop_base'. Otherwise evalue to ADV_FALSE.
2342 */
2343#define AdvFindSignature(iop_base) \
2344 (((AdvReadByteRegister((iop_base), IOPB_CHIP_ID_1) == \
2345 ADV_CHIP_ID_BYTE) && \
2346 (AdvReadWordRegister((iop_base), IOPW_CHIP_ID_0) == \
2347 ADV_CHIP_ID_WORD)) ? ADV_TRUE : ADV_FALSE)
2348
2349/*
2350 * Define macro to Return the version number of the chip at 'iop_base'.
2351 *
2352 * The second parameter 'bus_type' is currently unused.
2353 */
2354#define AdvGetChipVersion(iop_base, bus_type) \
2355 AdvReadByteRegister((iop_base), IOPB_CHIP_TYPE_REV)
2356
2357/*
2358 * Abort an SRB in the chip's RISC Memory. The 'srb_ptr' argument must
2359 * match the ASC_SCSI_REQ_Q 'srb_ptr' field.
2360 *
2361 * If the request has not yet been sent to the device it will simply be
2362 * aborted from RISC memory. If the request is disconnected it will be
2363 * aborted on reselection by sending an Abort Message to the target ID.
2364 *
2365 * Return value:
2366 * ADV_TRUE(1) - Queue was successfully aborted.
2367 * ADV_FALSE(0) - Queue was not found on the active queue list.
2368 */
2369#define AdvAbortQueue(asc_dvc, scsiq) \
2370 AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_ABORT, \
2371 (ADV_DCNT) (scsiq))
2372
2373/*
2374 * Send a Bus Device Reset Message to the specified target ID.
2375 *
2376 * All outstanding commands will be purged if sending the
2377 * Bus Device Reset Message is successful.
2378 *
2379 * Return Value:
2380 * ADV_TRUE(1) - All requests on the target are purged.
2381 * ADV_FALSE(0) - Couldn't issue Bus Device Reset Message; Requests
2382 * are not purged.
2383 */
2384#define AdvResetDevice(asc_dvc, target_id) \
2385 AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_DEVICE_RESET, \
2386 (ADV_DCNT) (target_id))
2387
2388/*
2389 * SCSI Wide Type definition.
2390 */
2391#define ADV_SCSI_BIT_ID_TYPE ushort
2392
2393/*
2394 * AdvInitScsiTarget() 'cntl_flag' options.
2395 */
2396#define ADV_SCAN_LUN 0x01
2397#define ADV_CAPINFO_NOLUN 0x02
2398
2399/*
2400 * Convert target id to target id bit mask.
2401 */
2402#define ADV_TID_TO_TIDMASK(tid) (0x01 << ((tid) & ADV_MAX_TID))
2403
2404/*
2405 * ASC_SCSI_REQ_Q 'done_status' and 'host_status' return values.
2406 */
2407
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002408#define QD_NO_STATUS 0x00 /* Request not completed yet. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409#define QD_NO_ERROR 0x01
2410#define QD_ABORTED_BY_HOST 0x02
2411#define QD_WITH_ERROR 0x04
2412
2413#define QHSTA_NO_ERROR 0x00
2414#define QHSTA_M_SEL_TIMEOUT 0x11
2415#define QHSTA_M_DATA_OVER_RUN 0x12
2416#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
2417#define QHSTA_M_QUEUE_ABORTED 0x15
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002418#define QHSTA_M_SXFR_SDMA_ERR 0x16 /* SXFR_STATUS SCSI DMA Error */
2419#define QHSTA_M_SXFR_SXFR_PERR 0x17 /* SXFR_STATUS SCSI Bus Parity Error */
2420#define QHSTA_M_RDMA_PERR 0x18 /* RISC PCI DMA parity error */
2421#define QHSTA_M_SXFR_OFF_UFLW 0x19 /* SXFR_STATUS Offset Underflow */
2422#define QHSTA_M_SXFR_OFF_OFLW 0x20 /* SXFR_STATUS Offset Overflow */
2423#define QHSTA_M_SXFR_WD_TMO 0x21 /* SXFR_STATUS Watchdog Timeout */
2424#define QHSTA_M_SXFR_DESELECTED 0x22 /* SXFR_STATUS Deselected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425/* Note: QHSTA_M_SXFR_XFR_OFLW is identical to QHSTA_M_DATA_OVER_RUN. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002426#define QHSTA_M_SXFR_XFR_OFLW 0x12 /* SXFR_STATUS Transfer Overflow */
2427#define QHSTA_M_SXFR_XFR_PH_ERR 0x24 /* SXFR_STATUS Transfer Phase Error */
2428#define QHSTA_M_SXFR_UNKNOWN_ERROR 0x25 /* SXFR_STATUS Unknown Error */
2429#define QHSTA_M_SCSI_BUS_RESET 0x30 /* Request aborted from SBR */
2430#define QHSTA_M_SCSI_BUS_RESET_UNSOL 0x31 /* Request aborted from unsol. SBR */
2431#define QHSTA_M_BUS_DEVICE_RESET 0x32 /* Request aborted from BDR */
2432#define QHSTA_M_DIRECTION_ERR 0x35 /* Data Phase mismatch */
2433#define QHSTA_M_DIRECTION_ERR_HUNG 0x36 /* Data Phase mismatch and bus hang */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434#define QHSTA_M_WTM_TIMEOUT 0x41
2435#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42
2436#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43
2437#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002438#define QHSTA_M_INVALID_DEVICE 0x45 /* Bad target ID */
2439#define QHSTA_M_FROZEN_TIDQ 0x46 /* TID Queue frozen. */
2440#define QHSTA_M_SGBACKUP_ERROR 0x47 /* Scatter-Gather backup error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441
2442/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 * DvcGetPhyAddr() flag arguments
2444 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002445#define ADV_IS_SCSIQ_FLAG 0x01 /* 'addr' is ASC_SCSI_REQ_Q pointer */
2446#define ADV_ASCGETSGLIST_VADDR 0x02 /* 'addr' is AscGetSGList() virtual addr */
2447#define ADV_IS_SENSE_FLAG 0x04 /* 'addr' is sense virtual pointer */
2448#define ADV_IS_DATA_FLAG 0x08 /* 'addr' is data virtual pointer */
2449#define ADV_IS_SGLIST_FLAG 0x10 /* 'addr' is sglist virtual pointer */
2450#define ADV_IS_CARRIER_FLAG 0x20 /* 'addr' is ADV_CARR_T pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451
2452/* Return the address that is aligned at the next doubleword >= to 'addr'. */
2453#define ADV_8BALIGN(addr) (((ulong) (addr) + 0x7) & ~0x7)
2454#define ADV_16BALIGN(addr) (((ulong) (addr) + 0xF) & ~0xF)
2455#define ADV_32BALIGN(addr) (((ulong) (addr) + 0x1F) & ~0x1F)
2456
2457/*
2458 * Total contiguous memory needed for driver SG blocks.
2459 *
2460 * ADV_MAX_SG_LIST must be defined by a driver. It is the maximum
2461 * number of scatter-gather elements the driver supports in a
2462 * single request.
2463 */
2464
2465#define ADV_SG_LIST_MAX_BYTE_SIZE \
2466 (sizeof(ADV_SG_BLOCK) * \
2467 ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK))
2468
2469/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 * --- Driver Constants and Macros
2471 */
2472
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473/* Reference Scsi_Host hostdata */
2474#define ASC_BOARDP(host) ((asc_board_t *) &((host)->hostdata))
2475
2476/* asc_board_t flags */
2477#define ASC_HOST_IN_RESET 0x01
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002478#define ASC_IS_WIDE_BOARD 0x04 /* AdvanSys Wide Board */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479#define ASC_SELECT_QUEUE_DEPTHS 0x08
2480
2481#define ASC_NARROW_BOARD(boardp) (((boardp)->flags & ASC_IS_WIDE_BOARD) == 0)
2482#define ASC_WIDE_BOARD(boardp) ((boardp)->flags & ASC_IS_WIDE_BOARD)
2483
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002484#define NO_ISA_DMA 0xff /* No ISA DMA Channel Used */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002486#define ASC_INFO_SIZE 128 /* advansys_info() line size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487
2488#ifdef CONFIG_PROC_FS
2489/* /proc/scsi/advansys/[0...] related definitions */
2490#define ASC_PRTBUF_SIZE 2048
2491#define ASC_PRTLINE_SIZE 160
2492
2493#define ASC_PRT_NEXT() \
2494 if (cp) { \
2495 totlen += len; \
2496 leftlen -= len; \
2497 if (leftlen == 0) { \
2498 return totlen; \
2499 } \
2500 cp += len; \
2501 }
2502#endif /* CONFIG_PROC_FS */
2503
2504/* Asc Library return codes */
2505#define ASC_TRUE 1
2506#define ASC_FALSE 0
2507#define ASC_NOERROR 1
2508#define ASC_BUSY 0
2509#define ASC_ERROR (-1)
2510
2511/* struct scsi_cmnd function return codes */
2512#define STATUS_BYTE(byte) (byte)
2513#define MSG_BYTE(byte) ((byte) << 8)
2514#define HOST_BYTE(byte) ((byte) << 16)
2515#define DRIVER_BYTE(byte) ((byte) << 24)
2516
2517/*
2518 * The following definitions and macros are OS independent interfaces to
2519 * the queue functions:
2520 * REQ - SCSI request structure
2521 * REQP - pointer to SCSI request structure
2522 * REQPTID(reqp) - reqp's target id
2523 * REQPNEXT(reqp) - reqp's next pointer
2524 * REQPNEXTP(reqp) - pointer to reqp's next pointer
2525 * REQPTIME(reqp) - reqp's time stamp value
2526 * REQTIMESTAMP() - system time stamp value
2527 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002528typedef struct scsi_cmnd REQ, *REQP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529#define REQPNEXT(reqp) ((REQP) ((reqp)->host_scribble))
2530#define REQPNEXTP(reqp) ((REQP *) &((reqp)->host_scribble))
2531#define REQPTID(reqp) ((reqp)->device->id)
2532#define REQPTIME(reqp) ((reqp)->SCp.this_residual)
2533#define REQTIMESTAMP() (jiffies)
2534
2535#define REQTIMESTAT(function, ascq, reqp, tid) \
2536{ \
2537 /*
2538 * If the request time stamp is less than the system time stamp, then \
2539 * maybe the system time stamp wrapped. Set the request time to zero.\
2540 */ \
2541 if (REQPTIME(reqp) <= REQTIMESTAMP()) { \
2542 REQPTIME(reqp) = REQTIMESTAMP() - REQPTIME(reqp); \
2543 } else { \
2544 /* Indicate an error occurred with the assertion. */ \
2545 ASC_ASSERT(REQPTIME(reqp) <= REQTIMESTAMP()); \
2546 REQPTIME(reqp) = 0; \
2547 } \
2548 /* Handle first minimum time case without external initialization. */ \
2549 if (((ascq)->q_tot_cnt[tid] == 1) || \
2550 (REQPTIME(reqp) < (ascq)->q_min_tim[tid])) { \
2551 (ascq)->q_min_tim[tid] = REQPTIME(reqp); \
2552 ASC_DBG3(1, "%s: new q_min_tim[%d] %u\n", \
2553 (function), (tid), (ascq)->q_min_tim[tid]); \
2554 } \
2555 if (REQPTIME(reqp) > (ascq)->q_max_tim[tid]) { \
2556 (ascq)->q_max_tim[tid] = REQPTIME(reqp); \
2557 ASC_DBG3(1, "%s: new q_max_tim[%d] %u\n", \
2558 (function), tid, (ascq)->q_max_tim[tid]); \
2559 } \
2560 (ascq)->q_tot_tim[tid] += REQPTIME(reqp); \
2561 /* Reset the time stamp field. */ \
2562 REQPTIME(reqp) = 0; \
2563}
2564
2565/* asc_enqueue() flags */
2566#define ASC_FRONT 1
2567#define ASC_BACK 2
2568
2569/* asc_dequeue_list() argument */
2570#define ASC_TID_ALL (-1)
2571
2572/* Return non-zero, if the queue is empty. */
2573#define ASC_QUEUE_EMPTY(ascq) ((ascq)->q_tidmask == 0)
2574
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575#ifndef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002576#define ASC_STATS(shost, counter)
2577#define ASC_STATS_ADD(shost, counter, count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578#else /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002579#define ASC_STATS(shost, counter) \
2580 (ASC_BOARDP(shost)->asc_stats.counter++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002582#define ASC_STATS_ADD(shost, counter, count) \
2583 (ASC_BOARDP(shost)->asc_stats.counter += (count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584#endif /* ADVANSYS_STATS */
2585
2586#define ASC_CEILING(val, unit) (((val) + ((unit) - 1))/(unit))
2587
2588/* If the result wraps when calculating tenths, return 0. */
2589#define ASC_TENTHS(num, den) \
2590 (((10 * ((num)/(den))) > (((num) * 10)/(den))) ? \
2591 0 : ((((num) * 10)/(den)) - (10 * ((num)/(den)))))
2592
2593/*
2594 * Display a message to the console.
2595 */
2596#define ASC_PRINT(s) \
2597 { \
2598 printk("advansys: "); \
2599 printk(s); \
2600 }
2601
2602#define ASC_PRINT1(s, a1) \
2603 { \
2604 printk("advansys: "); \
2605 printk((s), (a1)); \
2606 }
2607
2608#define ASC_PRINT2(s, a1, a2) \
2609 { \
2610 printk("advansys: "); \
2611 printk((s), (a1), (a2)); \
2612 }
2613
2614#define ASC_PRINT3(s, a1, a2, a3) \
2615 { \
2616 printk("advansys: "); \
2617 printk((s), (a1), (a2), (a3)); \
2618 }
2619
2620#define ASC_PRINT4(s, a1, a2, a3, a4) \
2621 { \
2622 printk("advansys: "); \
2623 printk((s), (a1), (a2), (a3), (a4)); \
2624 }
2625
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626#ifndef ADVANSYS_DEBUG
2627
2628#define ASC_DBG(lvl, s)
2629#define ASC_DBG1(lvl, s, a1)
2630#define ASC_DBG2(lvl, s, a1, a2)
2631#define ASC_DBG3(lvl, s, a1, a2, a3)
2632#define ASC_DBG4(lvl, s, a1, a2, a3, a4)
2633#define ASC_DBG_PRT_SCSI_HOST(lvl, s)
2634#define ASC_DBG_PRT_SCSI_CMND(lvl, s)
2635#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp)
2636#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
2637#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone)
2638#define ADV_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
2639#define ASC_DBG_PRT_HEX(lvl, name, start, length)
2640#define ASC_DBG_PRT_CDB(lvl, cdb, len)
2641#define ASC_DBG_PRT_SENSE(lvl, sense, len)
2642#define ASC_DBG_PRT_INQUIRY(lvl, inq, len)
2643
2644#else /* ADVANSYS_DEBUG */
2645
2646/*
2647 * Debugging Message Levels:
2648 * 0: Errors Only
2649 * 1: High-Level Tracing
2650 * 2-N: Verbose Tracing
2651 */
2652
2653#define ASC_DBG(lvl, s) \
2654 { \
2655 if (asc_dbglvl >= (lvl)) { \
2656 printk(s); \
2657 } \
2658 }
2659
2660#define ASC_DBG1(lvl, s, a1) \
2661 { \
2662 if (asc_dbglvl >= (lvl)) { \
2663 printk((s), (a1)); \
2664 } \
2665 }
2666
2667#define ASC_DBG2(lvl, s, a1, a2) \
2668 { \
2669 if (asc_dbglvl >= (lvl)) { \
2670 printk((s), (a1), (a2)); \
2671 } \
2672 }
2673
2674#define ASC_DBG3(lvl, s, a1, a2, a3) \
2675 { \
2676 if (asc_dbglvl >= (lvl)) { \
2677 printk((s), (a1), (a2), (a3)); \
2678 } \
2679 }
2680
2681#define ASC_DBG4(lvl, s, a1, a2, a3, a4) \
2682 { \
2683 if (asc_dbglvl >= (lvl)) { \
2684 printk((s), (a1), (a2), (a3), (a4)); \
2685 } \
2686 }
2687
2688#define ASC_DBG_PRT_SCSI_HOST(lvl, s) \
2689 { \
2690 if (asc_dbglvl >= (lvl)) { \
2691 asc_prt_scsi_host(s); \
2692 } \
2693 }
2694
2695#define ASC_DBG_PRT_SCSI_CMND(lvl, s) \
2696 { \
2697 if (asc_dbglvl >= (lvl)) { \
2698 asc_prt_scsi_cmnd(s); \
2699 } \
2700 }
2701
2702#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp) \
2703 { \
2704 if (asc_dbglvl >= (lvl)) { \
2705 asc_prt_asc_scsi_q(scsiqp); \
2706 } \
2707 }
2708
2709#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone) \
2710 { \
2711 if (asc_dbglvl >= (lvl)) { \
2712 asc_prt_asc_qdone_info(qdone); \
2713 } \
2714 }
2715
2716#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp) \
2717 { \
2718 if (asc_dbglvl >= (lvl)) { \
2719 asc_prt_adv_scsi_req_q(scsiqp); \
2720 } \
2721 }
2722
2723#define ASC_DBG_PRT_HEX(lvl, name, start, length) \
2724 { \
2725 if (asc_dbglvl >= (lvl)) { \
2726 asc_prt_hex((name), (start), (length)); \
2727 } \
2728 }
2729
2730#define ASC_DBG_PRT_CDB(lvl, cdb, len) \
2731 ASC_DBG_PRT_HEX((lvl), "CDB", (uchar *) (cdb), (len));
2732
2733#define ASC_DBG_PRT_SENSE(lvl, sense, len) \
2734 ASC_DBG_PRT_HEX((lvl), "SENSE", (uchar *) (sense), (len));
2735
2736#define ASC_DBG_PRT_INQUIRY(lvl, inq, len) \
2737 ASC_DBG_PRT_HEX((lvl), "INQUIRY", (uchar *) (inq), (len));
2738#endif /* ADVANSYS_DEBUG */
2739
2740#ifndef ADVANSYS_ASSERT
2741#define ASC_ASSERT(a)
2742#else /* ADVANSYS_ASSERT */
2743
2744#define ASC_ASSERT(a) \
2745 { \
2746 if (!(a)) { \
2747 printk("ASC_ASSERT() Failure: file %s, line %d\n", \
2748 __FILE__, __LINE__); \
2749 } \
2750 }
2751
2752#endif /* ADVANSYS_ASSERT */
2753
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754/*
2755 * --- Driver Structures
2756 */
2757
2758#ifdef ADVANSYS_STATS
2759
2760/* Per board statistics structure */
2761struct asc_stats {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002762 /* Driver Entrypoint Statistics */
2763 ADV_DCNT queuecommand; /* # calls to advansys_queuecommand() */
2764 ADV_DCNT reset; /* # calls to advansys_eh_bus_reset() */
2765 ADV_DCNT biosparam; /* # calls to advansys_biosparam() */
2766 ADV_DCNT interrupt; /* # advansys_interrupt() calls */
2767 ADV_DCNT callback; /* # calls to asc/adv_isr_callback() */
2768 ADV_DCNT done; /* # calls to request's scsi_done function */
2769 ADV_DCNT build_error; /* # asc/adv_build_req() ASC_ERROR returns. */
2770 ADV_DCNT adv_build_noreq; /* # adv_build_req() adv_req_t alloc. fail. */
2771 ADV_DCNT adv_build_nosg; /* # adv_build_req() adv_sgblk_t alloc. fail. */
2772 /* AscExeScsiQueue()/AdvExeScsiQueue() Statistics */
2773 ADV_DCNT exe_noerror; /* # ASC_NOERROR returns. */
2774 ADV_DCNT exe_busy; /* # ASC_BUSY returns. */
2775 ADV_DCNT exe_error; /* # ASC_ERROR returns. */
2776 ADV_DCNT exe_unknown; /* # unknown returns. */
2777 /* Data Transfer Statistics */
2778 ADV_DCNT cont_cnt; /* # non-scatter-gather I/O requests received */
2779 ADV_DCNT cont_xfer; /* # contiguous transfer 512-bytes */
2780 ADV_DCNT sg_cnt; /* # scatter-gather I/O requests received */
2781 ADV_DCNT sg_elem; /* # scatter-gather elements */
2782 ADV_DCNT sg_xfer; /* # scatter-gather transfer 512-bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783};
2784#endif /* ADVANSYS_STATS */
2785
2786/*
2787 * Request queuing structure
2788 */
2789typedef struct asc_queue {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002790 ADV_SCSI_BIT_ID_TYPE q_tidmask; /* queue mask */
2791 REQP q_first[ADV_MAX_TID + 1]; /* first queued request */
2792 REQP q_last[ADV_MAX_TID + 1]; /* last queued request */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002794 short q_cur_cnt[ADV_MAX_TID + 1]; /* current queue count */
2795 short q_max_cnt[ADV_MAX_TID + 1]; /* maximum queue count */
2796 ADV_DCNT q_tot_cnt[ADV_MAX_TID + 1]; /* total enqueue count */
2797 ADV_DCNT q_tot_tim[ADV_MAX_TID + 1]; /* total time queued */
2798 ushort q_max_tim[ADV_MAX_TID + 1]; /* maximum time queued */
2799 ushort q_min_tim[ADV_MAX_TID + 1]; /* minimum time queued */
2800#endif /* ADVANSYS_STATS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801} asc_queue_t;
2802
2803/*
2804 * Adv Library Request Structures
2805 *
2806 * The following two structures are used to process Wide Board requests.
2807 *
2808 * The ADV_SCSI_REQ_Q structure in adv_req_t is passed to the Adv Library
2809 * and microcode with the ADV_SCSI_REQ_Q field 'srb_ptr' pointing to the
2810 * adv_req_t. The adv_req_t structure 'cmndp' field in turn points to the
2811 * Mid-Level SCSI request structure.
2812 *
2813 * Zero or more ADV_SG_BLOCK are used with each ADV_SCSI_REQ_Q. Each
2814 * ADV_SG_BLOCK structure holds 15 scatter-gather elements. Under Linux
2815 * up to 255 scatter-gather elements may be used per request or
2816 * ADV_SCSI_REQ_Q.
2817 *
2818 * Both structures must be 32 byte aligned.
2819 */
2820typedef struct adv_sgblk {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002821 ADV_SG_BLOCK sg_block; /* Sgblock structure. */
2822 uchar align[32]; /* Sgblock structure padding. */
2823 struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824} adv_sgblk_t;
2825
2826typedef struct adv_req {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002827 ADV_SCSI_REQ_Q scsi_req_q; /* Adv Library request structure. */
2828 uchar align[32]; /* Request structure padding. */
2829 struct scsi_cmnd *cmndp; /* Mid-Level SCSI command pointer. */
2830 adv_sgblk_t *sgblkp; /* Adv Library scatter-gather pointer. */
2831 struct adv_req *next_reqp; /* Next Request Structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832} adv_req_t;
2833
2834/*
2835 * Structure allocated for each board.
2836 *
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06002837 * This structure is allocated by scsi_host_alloc() at the end
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838 * of the 'Scsi_Host' structure starting at the 'hostdata'
2839 * field. It is guaranteed to be allocated from DMA-able memory.
2840 */
2841typedef struct asc_board {
Matthew Wilcox394dbf32007-07-26 11:56:40 -04002842 struct device *dev;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002843 int id; /* Board Id */
2844 uint flags; /* Board flags */
2845 union {
2846 ASC_DVC_VAR asc_dvc_var; /* Narrow board */
2847 ADV_DVC_VAR adv_dvc_var; /* Wide board */
2848 } dvc_var;
2849 union {
2850 ASC_DVC_CFG asc_dvc_cfg; /* Narrow board */
2851 ADV_DVC_CFG adv_dvc_cfg; /* Wide board */
2852 } dvc_cfg;
2853 ushort asc_n_io_port; /* Number I/O ports. */
2854 asc_queue_t active; /* Active command queue */
2855 asc_queue_t waiting; /* Waiting command queue */
2856 asc_queue_t done; /* Done command queue */
2857 ADV_SCSI_BIT_ID_TYPE init_tidmask; /* Target init./valid mask */
2858 struct scsi_device *device[ADV_MAX_TID + 1]; /* Mid-Level Scsi Device */
2859 ushort reqcnt[ADV_MAX_TID + 1]; /* Starvation request count */
2860 ADV_SCSI_BIT_ID_TYPE queue_full; /* Queue full mask */
2861 ushort queue_full_cnt[ADV_MAX_TID + 1]; /* Queue full count */
2862 union {
2863 ASCEEP_CONFIG asc_eep; /* Narrow EEPROM config. */
2864 ADVEEP_3550_CONFIG adv_3550_eep; /* 3550 EEPROM config. */
2865 ADVEEP_38C0800_CONFIG adv_38C0800_eep; /* 38C0800 EEPROM config. */
2866 ADVEEP_38C1600_CONFIG adv_38C1600_eep; /* 38C1600 EEPROM config. */
2867 } eep_config;
2868 ulong last_reset; /* Saved last reset time */
2869 spinlock_t lock; /* Board spinlock */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002870 /* /proc/scsi/advansys/[0...] */
2871 char *prtbuf; /* /proc print buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002873 struct asc_stats asc_stats; /* Board statistics */
2874#endif /* ADVANSYS_STATS */
2875 /*
2876 * The following fields are used only for Narrow Boards.
2877 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002878 uchar sdtr_data[ASC_MAX_TID + 1]; /* SDTR information */
2879 /*
2880 * The following fields are used only for Wide Boards.
2881 */
2882 void __iomem *ioremap_addr; /* I/O Memory remap address. */
2883 ushort ioport; /* I/O Port address. */
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -06002884 ADV_CARR_T *carrp; /* ADV_CARR_T memory block. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002885 adv_req_t *orig_reqp; /* adv_req_t memory block. */
2886 adv_req_t *adv_reqp; /* Request structures. */
2887 adv_sgblk_t *adv_sgblkp; /* Scatter-gather structures. */
2888 ushort bios_signature; /* BIOS Signature. */
2889 ushort bios_version; /* BIOS Version. */
2890 ushort bios_codeseg; /* BIOS Code Segment. */
2891 ushort bios_codelen; /* BIOS Code Segment Length. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892} asc_board_t;
2893
Matthew Wilcox13ac2d92007-07-30 08:10:23 -06002894#define adv_dvc_to_board(adv_dvc) container_of(adv_dvc, struct asc_board, \
2895 dvc_var.adv_dvc_var)
2896#define adv_dvc_to_pdev(adv_dvc) to_pci_dev(adv_dvc_to_board(adv_dvc)->dev)
2897
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898/* Number of boards detected in system. */
Matthew Wilcox78e77d82007-07-29 21:46:15 -06002899static int asc_board_count;
2900
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901/* Overrun buffer used by all narrow boards. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002902static uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903
2904/*
2905 * Global structures required to issue a command.
2906 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002907static ASC_SCSI_Q asc_scsi_q = { {0} };
2908static ASC_SG_HEAD asc_sg_head = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002911static int asc_dbglvl = 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912#endif /* ADVANSYS_DEBUG */
2913
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914/*
2915 * --- Driver Function Prototypes
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916 */
2917
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002918static int advansys_slave_configure(struct scsi_device *);
2919static void asc_scsi_done_list(struct scsi_cmnd *);
2920static int asc_execute_scsi_cmnd(struct scsi_cmnd *);
2921static int asc_build_req(asc_board_t *, struct scsi_cmnd *);
2922static int adv_build_req(asc_board_t *, struct scsi_cmnd *, ADV_SCSI_REQ_Q **);
2923static int adv_get_sglist(asc_board_t *, adv_req_t *, struct scsi_cmnd *, int);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002924static void asc_enqueue(asc_queue_t *, REQP, int);
2925static REQP asc_dequeue(asc_queue_t *, int);
2926static REQP asc_dequeue_list(asc_queue_t *, REQP *, int);
2927static int asc_rmqueue(asc_queue_t *, REQP);
2928static void asc_execute_queue(asc_queue_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002930static int asc_proc_copy(off_t, off_t, char *, int, char *, int);
2931static int asc_prt_board_devices(struct Scsi_Host *, char *, int);
2932static int asc_prt_adv_bios(struct Scsi_Host *, char *, int);
2933static int asc_get_eeprom_string(ushort *serialnum, uchar *cp);
2934static int asc_prt_asc_board_eeprom(struct Scsi_Host *, char *, int);
2935static int asc_prt_adv_board_eeprom(struct Scsi_Host *, char *, int);
2936static int asc_prt_driver_conf(struct Scsi_Host *, char *, int);
2937static int asc_prt_asc_board_info(struct Scsi_Host *, char *, int);
2938static int asc_prt_adv_board_info(struct Scsi_Host *, char *, int);
2939static int asc_prt_line(char *, int, char *fmt, ...);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940#endif /* CONFIG_PROC_FS */
2941
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942/* Statistics function prototypes. */
2943#ifdef ADVANSYS_STATS
2944#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002945static int asc_prt_board_stats(struct Scsi_Host *, char *, int);
2946static int asc_prt_target_stats(struct Scsi_Host *, int, char *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947#endif /* CONFIG_PROC_FS */
2948#endif /* ADVANSYS_STATS */
2949
2950/* Debug function prototypes. */
2951#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002952static void asc_prt_scsi_host(struct Scsi_Host *);
2953static void asc_prt_scsi_cmnd(struct scsi_cmnd *);
2954static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *);
2955static void asc_prt_asc_dvc_var(ASC_DVC_VAR *);
2956static void asc_prt_asc_scsi_q(ASC_SCSI_Q *);
2957static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *);
2958static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *);
2959static void asc_prt_adv_dvc_var(ADV_DVC_VAR *);
2960static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *);
2961static void asc_prt_adv_sgblock(int, ADV_SG_BLOCK *);
2962static void asc_prt_hex(char *f, uchar *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963#endif /* ADVANSYS_DEBUG */
2964
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965#ifdef CONFIG_PROC_FS
2966/*
Matthew Wilcoxc304ec92007-07-30 09:18:45 -06002967 * advansys_proc_info() - /proc/scsi/advansys/{0,1,2,3,...}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968 *
2969 * *buffer: I/O buffer
2970 * **start: if inout == FALSE pointer into buffer where user read should start
2971 * offset: current offset into a /proc/scsi/advansys/[0...] file
2972 * length: length of buffer
2973 * hostno: Scsi_Host host_no
2974 * inout: TRUE - user is writing; FALSE - user is reading
2975 *
2976 * Return the number of bytes read from or written to a
2977 * /proc/scsi/advansys/[0...] file.
2978 *
2979 * Note: This function uses the per board buffer 'prtbuf' which is
2980 * allocated when the board is initialized in advansys_detect(). The
2981 * buffer is ASC_PRTBUF_SIZE bytes. The function asc_proc_copy() is
2982 * used to write to the buffer. The way asc_proc_copy() is written
2983 * if 'prtbuf' is too small it will not be overwritten. Instead the
2984 * user just won't get all the available statistics.
2985 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07002986static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002988 off_t offset, int length, int inout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002990 asc_board_t *boardp;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002991 char *cp;
2992 int cplen;
2993 int cnt;
2994 int totcnt;
2995 int leftlen;
2996 char *curbuf;
2997 off_t advoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002999 int tgt_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000#endif /* ADVANSYS_STATS */
3001
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003002 ASC_DBG(1, "advansys_proc_info: begin\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003004 /*
3005 * User write not supported.
3006 */
3007 if (inout == TRUE) {
3008 return (-ENOSYS);
3009 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003011 /*
3012 * User read of /proc/scsi/advansys/[0...] file.
3013 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014
Matthew Wilcox2a437952007-07-26 11:00:51 -04003015 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003017 /* Copy read data starting at the beginning of the buffer. */
3018 *start = buffer;
3019 curbuf = buffer;
3020 advoffset = 0;
3021 totcnt = 0;
3022 leftlen = length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003024 /*
3025 * Get board configuration information.
3026 *
3027 * advansys_info() returns the board string from its own static buffer.
3028 */
Matthew Wilcox2a437952007-07-26 11:00:51 -04003029 cp = (char *)advansys_info(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003030 strcat(cp, "\n");
3031 cplen = strlen(cp);
3032 /* Copy board information. */
3033 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3034 totcnt += cnt;
3035 leftlen -= cnt;
3036 if (leftlen == 0) {
3037 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3038 return totcnt;
3039 }
3040 advoffset += cplen;
3041 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003043 /*
3044 * Display Wide Board BIOS Information.
3045 */
3046 if (ASC_WIDE_BOARD(boardp)) {
3047 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003048 cplen = asc_prt_adv_bios(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003049 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003050 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003051 cplen);
3052 totcnt += cnt;
3053 leftlen -= cnt;
3054 if (leftlen == 0) {
3055 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3056 return totcnt;
3057 }
3058 advoffset += cplen;
3059 curbuf += cnt;
3060 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003062 /*
3063 * Display driver information for each device attached to the board.
3064 */
3065 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003066 cplen = asc_prt_board_devices(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003067 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3068 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3069 totcnt += cnt;
3070 leftlen -= cnt;
3071 if (leftlen == 0) {
3072 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3073 return totcnt;
3074 }
3075 advoffset += cplen;
3076 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003078 /*
3079 * Display EEPROM configuration for the board.
3080 */
3081 cp = boardp->prtbuf;
3082 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003083 cplen = asc_prt_asc_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003084 } else {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003085 cplen = asc_prt_adv_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003086 }
3087 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3088 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3089 totcnt += cnt;
3090 leftlen -= cnt;
3091 if (leftlen == 0) {
3092 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3093 return totcnt;
3094 }
3095 advoffset += cplen;
3096 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003098 /*
3099 * Display driver configuration and information for the board.
3100 */
3101 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003102 cplen = asc_prt_driver_conf(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003103 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3104 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3105 totcnt += cnt;
3106 leftlen -= cnt;
3107 if (leftlen == 0) {
3108 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3109 return totcnt;
3110 }
3111 advoffset += cplen;
3112 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113
3114#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003115 /*
3116 * Display driver statistics for the board.
3117 */
3118 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003119 cplen = asc_prt_board_stats(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003120 ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
3121 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3122 totcnt += cnt;
3123 leftlen -= cnt;
3124 if (leftlen == 0) {
3125 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3126 return totcnt;
3127 }
3128 advoffset += cplen;
3129 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003131 /*
3132 * Display driver statistics for each target.
3133 */
3134 for (tgt_id = 0; tgt_id <= ADV_MAX_TID; tgt_id++) {
3135 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003136 cplen = asc_prt_target_stats(shost, tgt_id, cp,
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003137 ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003138 ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003139 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
3140 cplen);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003141 totcnt += cnt;
3142 leftlen -= cnt;
3143 if (leftlen == 0) {
3144 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3145 return totcnt;
3146 }
3147 advoffset += cplen;
3148 curbuf += cnt;
3149 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150#endif /* ADVANSYS_STATS */
3151
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003152 /*
3153 * Display Asc Library dynamic configuration information
3154 * for the board.
3155 */
3156 cp = boardp->prtbuf;
3157 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003158 cplen = asc_prt_asc_board_info(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003159 } else {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003160 cplen = asc_prt_adv_board_info(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003161 }
3162 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3163 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3164 totcnt += cnt;
3165 leftlen -= cnt;
3166 if (leftlen == 0) {
3167 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3168 return totcnt;
3169 }
3170 advoffset += cplen;
3171 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003173 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003174
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003175 return totcnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176}
3177#endif /* CONFIG_PROC_FS */
3178
3179/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180 * advansys_info()
3181 *
3182 * Return suitable for printing on the console with the argument
3183 * adapter's configuration information.
3184 *
3185 * Note: The information line should not exceed ASC_INFO_SIZE bytes,
3186 * otherwise the static 'info' array will be overrun.
3187 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003188static const char *advansys_info(struct Scsi_Host *shost)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003190 static char info[ASC_INFO_SIZE];
3191 asc_board_t *boardp;
3192 ASC_DVC_VAR *asc_dvc_varp;
3193 ADV_DVC_VAR *adv_dvc_varp;
3194 char *busname;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003195 char *widename = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003197 boardp = ASC_BOARDP(shost);
3198 if (ASC_NARROW_BOARD(boardp)) {
3199 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
3200 ASC_DBG(1, "advansys_info: begin\n");
3201 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
3202 if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) ==
3203 ASC_IS_ISAPNP) {
3204 busname = "ISA PnP";
3205 } else {
3206 busname = "ISA";
3207 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003208 sprintf(info,
3209 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X",
3210 ASC_VERSION, busname,
3211 (ulong)shost->io_port,
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04003212 (ulong)shost->io_port + ASC_IOADR_GAP - 1,
3213 shost->irq, shost->dma_channel);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003214 } else {
3215 if (asc_dvc_varp->bus_type & ASC_IS_VL) {
3216 busname = "VL";
3217 } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
3218 busname = "EISA";
3219 } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
3220 if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
3221 == ASC_IS_PCI_ULTRA) {
3222 busname = "PCI Ultra";
3223 } else {
3224 busname = "PCI";
3225 }
3226 } else {
3227 busname = "?";
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003228 ASC_PRINT2("advansys_info: board %d: unknown "
3229 "bus type %d\n", boardp->id,
3230 asc_dvc_varp->bus_type);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003231 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003232 sprintf(info,
3233 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X",
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003234 ASC_VERSION, busname, (ulong)shost->io_port,
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04003235 (ulong)shost->io_port + ASC_IOADR_GAP - 1,
3236 shost->irq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003237 }
3238 } else {
3239 /*
3240 * Wide Adapter Information
3241 *
3242 * Memory-mapped I/O is used instead of I/O space to access
3243 * the adapter, but display the I/O Port range. The Memory
3244 * I/O address is displayed through the driver /proc file.
3245 */
3246 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
3247 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003248 widename = "Ultra-Wide";
3249 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003250 widename = "Ultra2-Wide";
3251 } else {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003252 widename = "Ultra3-Wide";
3253 }
3254 sprintf(info,
3255 "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X",
3256 ASC_VERSION, widename, (ulong)adv_dvc_varp->iop_base,
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04003257 (ulong)adv_dvc_varp->iop_base + boardp->asc_n_io_port - 1, shost->irq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003258 }
3259 ASC_ASSERT(strlen(info) < ASC_INFO_SIZE);
3260 ASC_DBG(1, "advansys_info: end\n");
3261 return info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262}
3263
3264/*
3265 * advansys_queuecommand() - interrupt-driven I/O entrypoint.
3266 *
3267 * This function always returns 0. Command return status is saved
3268 * in the 'scp' result field.
3269 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07003270static int
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003271advansys_queuecommand(struct scsi_cmnd *scp, void (*done) (struct scsi_cmnd *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003273 struct Scsi_Host *shost;
3274 asc_board_t *boardp;
3275 ulong flags;
3276 struct scsi_cmnd *done_scp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003277
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003278 shost = scp->device->host;
3279 boardp = ASC_BOARDP(shost);
3280 ASC_STATS(shost, queuecommand);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003281
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003282 /* host_lock taken by mid-level prior to call but need to protect */
3283 /* against own ISR */
3284 spin_lock_irqsave(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003285
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003286 /*
3287 * Block new commands while handling a reset or abort request.
3288 */
3289 if (boardp->flags & ASC_HOST_IN_RESET) {
3290 ASC_DBG1(1,
3291 "advansys_queuecommand: scp 0x%lx blocked for reset request\n",
3292 (ulong)scp);
3293 scp->result = HOST_BYTE(DID_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003295 /*
3296 * Add blocked requests to the board's 'done' queue. The queued
3297 * requests will be completed at the end of the abort or reset
3298 * handling.
3299 */
3300 asc_enqueue(&boardp->done, scp, ASC_BACK);
3301 spin_unlock_irqrestore(&boardp->lock, flags);
3302 return 0;
3303 }
3304
3305 /*
3306 * Attempt to execute any waiting commands for the board.
3307 */
3308 if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
3309 ASC_DBG(1,
3310 "advansys_queuecommand: before asc_execute_queue() waiting\n");
3311 asc_execute_queue(&boardp->waiting);
3312 }
3313
3314 /*
3315 * Save the function pointer to Linux mid-level 'done' function
3316 * and attempt to execute the command.
3317 *
3318 * If ASC_NOERROR is returned the request has been added to the
3319 * board's 'active' queue and will be completed by the interrupt
3320 * handler.
3321 *
3322 * If ASC_BUSY is returned add the request to the board's per
3323 * target waiting list. This is the first time the request has
3324 * been tried. Add it to the back of the waiting list. It will be
3325 * retried later.
3326 *
3327 * If an error occurred, the request will have been placed on the
3328 * board's 'done' queue and must be completed before returning.
3329 */
3330 scp->scsi_done = done;
3331 switch (asc_execute_scsi_cmnd(scp)) {
3332 case ASC_NOERROR:
3333 break;
3334 case ASC_BUSY:
3335 asc_enqueue(&boardp->waiting, scp, ASC_BACK);
3336 break;
3337 case ASC_ERROR:
3338 default:
3339 done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
3340 /* Interrupts could be enabled here. */
3341 asc_scsi_done_list(done_scp);
3342 break;
3343 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003346 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347}
3348
3349/*
3350 * advansys_reset()
3351 *
3352 * Reset the bus associated with the command 'scp'.
3353 *
3354 * This function runs its own thread. Interrupts must be blocked but
3355 * sleeping is allowed and no locking other than for host structures is
3356 * required. Returns SUCCESS or FAILED.
3357 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003358static int advansys_reset(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003360 struct Scsi_Host *shost;
3361 asc_board_t *boardp;
3362 ASC_DVC_VAR *asc_dvc_varp;
3363 ADV_DVC_VAR *adv_dvc_varp;
3364 ulong flags;
3365 struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
3366 struct scsi_cmnd *tscp, *new_last_scp;
3367 int status;
3368 int ret = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003370 ASC_DBG1(1, "advansys_reset: 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371
3372#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003373 if (scp->device->host != NULL) {
3374 ASC_STATS(scp->device->host, reset);
3375 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376#endif /* ADVANSYS_STATS */
3377
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003378 if ((shost = scp->device->host) == NULL) {
3379 scp->result = HOST_BYTE(DID_ERROR);
3380 return FAILED;
3381 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003382
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003383 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003385 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset started...\n",
3386 boardp->id);
3387 /*
3388 * Check for re-entrancy.
3389 */
3390 spin_lock_irqsave(&boardp->lock, flags);
3391 if (boardp->flags & ASC_HOST_IN_RESET) {
3392 spin_unlock_irqrestore(&boardp->lock, flags);
3393 return FAILED;
3394 }
3395 boardp->flags |= ASC_HOST_IN_RESET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003398 if (ASC_NARROW_BOARD(boardp)) {
3399 /*
3400 * Narrow Board
3401 */
3402 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003404 /*
3405 * Reset the chip and SCSI bus.
3406 */
3407 ASC_DBG(1, "advansys_reset: before AscInitAsc1000Driver()\n");
3408 status = AscInitAsc1000Driver(asc_dvc_varp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003409
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003410 /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */
3411 if (asc_dvc_varp->err_code) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003412 ASC_PRINT2("advansys_reset: board %d: SCSI bus reset "
3413 "error: 0x%x\n", boardp->id,
3414 asc_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003415 ret = FAILED;
3416 } else if (status) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003417 ASC_PRINT2("advansys_reset: board %d: SCSI bus reset "
3418 "warning: 0x%x\n", boardp->id, status);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003419 } else {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003420 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset "
3421 "successful.\n", boardp->id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003422 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003424 ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
3425 spin_lock_irqsave(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003427 } else {
3428 /*
3429 * Wide Board
3430 *
3431 * If the suggest reset bus flags are set, then reset the bus.
3432 * Otherwise only reset the device.
3433 */
3434 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003436 /*
3437 * Reset the target's SCSI bus.
3438 */
3439 ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n");
3440 switch (AdvResetChipAndSB(adv_dvc_varp)) {
3441 case ASC_TRUE:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003442 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset "
3443 "successful.\n", boardp->id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003444 break;
3445 case ASC_FALSE:
3446 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003447 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset "
3448 "error.\n", boardp->id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003449 ret = FAILED;
3450 break;
3451 }
3452 spin_lock_irqsave(&boardp->lock, flags);
3453 (void)AdvISR(adv_dvc_varp);
3454 }
3455 /* Board lock is held. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003457 /*
3458 * Dequeue all board 'done' requests. A pointer to the last request
3459 * is returned in 'last_scp'.
3460 */
3461 done_scp = asc_dequeue_list(&boardp->done, &last_scp, ASC_TID_ALL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003463 /*
3464 * Dequeue all board 'active' requests for all devices and set
3465 * the request status to DID_RESET. A pointer to the last request
3466 * is returned in 'last_scp'.
3467 */
3468 if (done_scp == NULL) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003469 done_scp = asc_dequeue_list(&boardp->active, &last_scp,
3470 ASC_TID_ALL);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003471 for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
3472 tscp->result = HOST_BYTE(DID_RESET);
3473 }
3474 } else {
3475 /* Append to 'done_scp' at the end with 'last_scp'. */
3476 ASC_ASSERT(last_scp != NULL);
3477 last_scp->host_scribble =
3478 (unsigned char *)asc_dequeue_list(&boardp->active,
3479 &new_last_scp,
3480 ASC_TID_ALL);
3481 if (new_last_scp != NULL) {
3482 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
3483 for (tscp = REQPNEXT(last_scp); tscp;
3484 tscp = REQPNEXT(tscp)) {
3485 tscp->result = HOST_BYTE(DID_RESET);
3486 }
3487 last_scp = new_last_scp;
3488 }
3489 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003491 /*
3492 * Dequeue all 'waiting' requests and set the request status
3493 * to DID_RESET.
3494 */
3495 if (done_scp == NULL) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003496 done_scp = asc_dequeue_list(&boardp->waiting, &last_scp,
3497 ASC_TID_ALL);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003498 for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
3499 tscp->result = HOST_BYTE(DID_RESET);
3500 }
3501 } else {
3502 /* Append to 'done_scp' at the end with 'last_scp'. */
3503 ASC_ASSERT(last_scp != NULL);
3504 last_scp->host_scribble =
3505 (unsigned char *)asc_dequeue_list(&boardp->waiting,
3506 &new_last_scp,
3507 ASC_TID_ALL);
3508 if (new_last_scp != NULL) {
3509 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
3510 for (tscp = REQPNEXT(last_scp); tscp;
3511 tscp = REQPNEXT(tscp)) {
3512 tscp->result = HOST_BYTE(DID_RESET);
3513 }
3514 last_scp = new_last_scp;
3515 }
3516 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003517
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003518 /* Save the time of the most recently completed reset. */
3519 boardp->last_reset = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003521 /* Clear reset flag. */
3522 boardp->flags &= ~ASC_HOST_IN_RESET;
3523 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003525 /*
3526 * Complete all the 'done_scp' requests.
3527 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003528 if (done_scp)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003529 asc_scsi_done_list(done_scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003531 ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003533 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534}
3535
3536/*
3537 * advansys_biosparam()
3538 *
3539 * Translate disk drive geometry if the "BIOS greater than 1 GB"
3540 * support is enabled for a drive.
3541 *
3542 * ip (information pointer) is an int array with the following definition:
3543 * ip[0]: heads
3544 * ip[1]: sectors
3545 * ip[2]: cylinders
3546 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07003547static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003549 sector_t capacity, int ip[])
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003551 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003553 ASC_DBG(1, "advansys_biosparam: begin\n");
3554 ASC_STATS(sdev->host, biosparam);
3555 boardp = ASC_BOARDP(sdev->host);
3556 if (ASC_NARROW_BOARD(boardp)) {
3557 if ((boardp->dvc_var.asc_dvc_var.dvc_cntl &
3558 ASC_CNTL_BIOS_GT_1GB) && capacity > 0x200000) {
3559 ip[0] = 255;
3560 ip[1] = 63;
3561 } else {
3562 ip[0] = 64;
3563 ip[1] = 32;
3564 }
3565 } else {
3566 if ((boardp->dvc_var.adv_dvc_var.bios_ctrl &
3567 BIOS_CTRL_EXTENDED_XLAT) && capacity > 0x200000) {
3568 ip[0] = 255;
3569 ip[1] = 63;
3570 } else {
3571 ip[0] = 64;
3572 ip[1] = 32;
3573 }
3574 }
3575 ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
3576 ASC_DBG(1, "advansys_biosparam: end\n");
3577 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578}
3579
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06003580static struct scsi_host_template advansys_template = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003581 .proc_name = "advansys",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003583 .proc_info = advansys_proc_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584#endif
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003585 .name = "advansys",
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003586 .info = advansys_info,
3587 .queuecommand = advansys_queuecommand,
3588 .eh_bus_reset_handler = advansys_reset,
3589 .bios_param = advansys_biosparam,
3590 .slave_configure = advansys_slave_configure,
3591 /*
3592 * Because the driver may control an ISA adapter 'unchecked_isa_dma'
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06003593 * must be set. The flag will be cleared in advansys_board_found
3594 * for non-ISA adapters.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003595 */
3596 .unchecked_isa_dma = 1,
3597 /*
3598 * All adapters controlled by this driver are capable of large
3599 * scatter-gather lists. According to the mid-level SCSI documentation
3600 * this obviates any performance gain provided by setting
3601 * 'use_clustering'. But empirically while CPU utilization is increased
3602 * by enabling clustering, I/O throughput increases as well.
3603 */
3604 .use_clustering = ENABLE_CLUSTERING,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607/*
3608 * --- Miscellaneous Driver Functions
3609 */
3610
3611/*
3612 * First-level interrupt handler.
3613 *
3614 * 'dev_id' is a pointer to the interrupting adapter's asc_board_t. Because
3615 * all boards are currently checked for interrupts on each interrupt, 'dev_id'
3616 * is not referenced. 'dev_id' could be used to identify an interrupt passed
3617 * to the AdvanSys driver which is for a device sharing an interrupt with
3618 * an AdvanSys adapter.
3619 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003620static irqreturn_t advansys_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621{
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003622 unsigned long flags;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003623 struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
3624 struct scsi_cmnd *new_last_scp;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003625 struct Scsi_Host *shost = dev_id;
3626 asc_board_t *boardp = ASC_BOARDP(shost);
3627 irqreturn_t result = IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003629 ASC_DBG1(2, "advansys_interrupt: boardp 0x%p\n", boardp);
3630 spin_lock_irqsave(&boardp->lock, flags);
3631 if (ASC_NARROW_BOARD(boardp)) {
3632 /*
3633 * Narrow Board
3634 */
3635 if (AscIsIntPending(shost->io_port)) {
3636 result = IRQ_HANDLED;
3637 ASC_STATS(shost, interrupt);
3638 ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
3639 AscISR(&boardp->dvc_var.asc_dvc_var);
3640 }
3641 } else {
3642 /*
3643 * Wide Board
3644 */
3645 ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
3646 if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
3647 result = IRQ_HANDLED;
3648 ASC_STATS(shost, interrupt);
3649 }
3650 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003652 /*
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003653 * Start waiting requests and create a list of completed requests.
3654 *
3655 * If a reset request is being performed for the board, the reset
3656 * handler will complete pending requests after it has completed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003657 */
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003658 if ((boardp->flags & ASC_HOST_IN_RESET) == 0) {
3659 ASC_DBG2(1, "advansys_interrupt: done_scp 0x%p, "
3660 "last_scp 0x%p\n", done_scp, last_scp);
3661
3662 /* Start any waiting commands for the board. */
3663 if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
3664 ASC_DBG(1, "advansys_interrupt: before "
3665 "asc_execute_queue()\n");
3666 asc_execute_queue(&boardp->waiting);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003667 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003669 /*
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003670 * Add to the list of requests that must be completed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003671 *
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003672 * 'done_scp' will always be NULL on the first iteration of
3673 * this loop. 'last_scp' is set at the same time as 'done_scp'.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003674 */
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003675 if (done_scp == NULL) {
3676 done_scp = asc_dequeue_list(&boardp->done,
3677 &last_scp, ASC_TID_ALL);
3678 } else {
3679 ASC_ASSERT(last_scp != NULL);
3680 last_scp->host_scribble =
3681 (unsigned char *)asc_dequeue_list(&boardp->
3682 done,
3683 &new_last_scp,
3684 ASC_TID_ALL);
3685 if (new_last_scp != NULL) {
3686 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
3687 last_scp = new_last_scp;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003688 }
3689 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003690 }
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003691 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003693 /*
3694 * If interrupts were enabled on entry, then they
3695 * are now enabled here.
3696 *
3697 * Complete all requests on the done list.
3698 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003700 asc_scsi_done_list(done_scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003702 ASC_DBG(1, "advansys_interrupt: end\n");
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06003703 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704}
3705
Matthew Wilcox47d853c2007-07-26 11:41:33 -04003706static void
3707advansys_narrow_slave_configure(struct scsi_device *sdev, ASC_DVC_VAR *asc_dvc)
3708{
3709 ASC_SCSI_BIT_ID_TYPE tid_bit = 1 << sdev->id;
3710 ASC_SCSI_BIT_ID_TYPE orig_use_tagged_qng = asc_dvc->use_tagged_qng;
3711
3712 if (sdev->lun == 0) {
3713 ASC_SCSI_BIT_ID_TYPE orig_init_sdtr = asc_dvc->init_sdtr;
3714 if ((asc_dvc->cfg->sdtr_enable & tid_bit) && sdev->sdtr) {
3715 asc_dvc->init_sdtr |= tid_bit;
3716 } else {
3717 asc_dvc->init_sdtr &= ~tid_bit;
3718 }
3719
3720 if (orig_init_sdtr != asc_dvc->init_sdtr)
3721 AscAsyncFix(asc_dvc, sdev);
3722 }
3723
3724 if (sdev->tagged_supported) {
3725 if (asc_dvc->cfg->cmd_qng_enabled & tid_bit) {
3726 if (sdev->lun == 0) {
3727 asc_dvc->cfg->can_tagged_qng |= tid_bit;
3728 asc_dvc->use_tagged_qng |= tid_bit;
3729 }
3730 scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
3731 asc_dvc->max_dvc_qng[sdev->id]);
3732 }
3733 } else {
3734 if (sdev->lun == 0) {
3735 asc_dvc->cfg->can_tagged_qng &= ~tid_bit;
3736 asc_dvc->use_tagged_qng &= ~tid_bit;
3737 }
3738 scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
3739 }
3740
3741 if ((sdev->lun == 0) &&
3742 (orig_use_tagged_qng != asc_dvc->use_tagged_qng)) {
3743 AscWriteLramByte(asc_dvc->iop_base, ASCV_DISC_ENABLE_B,
3744 asc_dvc->cfg->disc_enable);
3745 AscWriteLramByte(asc_dvc->iop_base, ASCV_USE_TAGGED_QNG_B,
3746 asc_dvc->use_tagged_qng);
3747 AscWriteLramByte(asc_dvc->iop_base, ASCV_CAN_TAGGED_QNG_B,
3748 asc_dvc->cfg->can_tagged_qng);
3749
3750 asc_dvc->max_dvc_qng[sdev->id] =
3751 asc_dvc->cfg->max_tag_qng[sdev->id];
3752 AscWriteLramByte(asc_dvc->iop_base,
3753 (ushort)(ASCV_MAX_DVC_QNG_BEG + sdev->id),
3754 asc_dvc->max_dvc_qng[sdev->id]);
3755 }
3756}
3757
3758/*
3759 * Wide Transfers
3760 *
3761 * If the EEPROM enabled WDTR for the device and the device supports wide
3762 * bus (16 bit) transfers, then turn on the device's 'wdtr_able' bit and
3763 * write the new value to the microcode.
3764 */
3765static void
3766advansys_wide_enable_wdtr(AdvPortAddr iop_base, unsigned short tidmask)
3767{
3768 unsigned short cfg_word;
3769 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
3770 if ((cfg_word & tidmask) != 0)
3771 return;
3772
3773 cfg_word |= tidmask;
3774 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
3775
3776 /*
3777 * Clear the microcode SDTR and WDTR negotiation done indicators for
3778 * the target to cause it to negotiate with the new setting set above.
3779 * WDTR when accepted causes the target to enter asynchronous mode, so
3780 * SDTR must be negotiated.
3781 */
3782 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
3783 cfg_word &= ~tidmask;
3784 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
3785 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
3786 cfg_word &= ~tidmask;
3787 AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
3788}
3789
3790/*
3791 * Synchronous Transfers
3792 *
3793 * If the EEPROM enabled SDTR for the device and the device
3794 * supports synchronous transfers, then turn on the device's
3795 * 'sdtr_able' bit. Write the new value to the microcode.
3796 */
3797static void
3798advansys_wide_enable_sdtr(AdvPortAddr iop_base, unsigned short tidmask)
3799{
3800 unsigned short cfg_word;
3801 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
3802 if ((cfg_word & tidmask) != 0)
3803 return;
3804
3805 cfg_word |= tidmask;
3806 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
3807
3808 /*
3809 * Clear the microcode "SDTR negotiation" done indicator for the
3810 * target to cause it to negotiate with the new setting set above.
3811 */
3812 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
3813 cfg_word &= ~tidmask;
3814 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
3815}
3816
3817/*
3818 * PPR (Parallel Protocol Request) Capable
3819 *
3820 * If the device supports DT mode, then it must be PPR capable.
3821 * The PPR message will be used in place of the SDTR and WDTR
3822 * messages to negotiate synchronous speed and offset, transfer
3823 * width, and protocol options.
3824 */
3825static void advansys_wide_enable_ppr(ADV_DVC_VAR *adv_dvc,
3826 AdvPortAddr iop_base, unsigned short tidmask)
3827{
3828 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able);
3829 adv_dvc->ppr_able |= tidmask;
3830 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able);
3831}
3832
3833static void
3834advansys_wide_slave_configure(struct scsi_device *sdev, ADV_DVC_VAR *adv_dvc)
3835{
3836 AdvPortAddr iop_base = adv_dvc->iop_base;
3837 unsigned short tidmask = 1 << sdev->id;
3838
3839 if (sdev->lun == 0) {
3840 /*
3841 * Handle WDTR, SDTR, and Tag Queuing. If the feature
3842 * is enabled in the EEPROM and the device supports the
3843 * feature, then enable it in the microcode.
3844 */
3845
3846 if ((adv_dvc->wdtr_able & tidmask) && sdev->wdtr)
3847 advansys_wide_enable_wdtr(iop_base, tidmask);
3848 if ((adv_dvc->sdtr_able & tidmask) && sdev->sdtr)
3849 advansys_wide_enable_sdtr(iop_base, tidmask);
3850 if (adv_dvc->chip_type == ADV_CHIP_ASC38C1600 && sdev->ppr)
3851 advansys_wide_enable_ppr(adv_dvc, iop_base, tidmask);
3852
3853 /*
3854 * Tag Queuing is disabled for the BIOS which runs in polled
3855 * mode and would see no benefit from Tag Queuing. Also by
3856 * disabling Tag Queuing in the BIOS devices with Tag Queuing
3857 * bugs will at least work with the BIOS.
3858 */
3859 if ((adv_dvc->tagqng_able & tidmask) &&
3860 sdev->tagged_supported) {
3861 unsigned short cfg_word;
3862 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
3863 cfg_word |= tidmask;
3864 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
3865 cfg_word);
3866 AdvWriteByteLram(iop_base,
3867 ASC_MC_NUMBER_OF_MAX_CMD + sdev->id,
3868 adv_dvc->max_dvc_qng);
3869 }
3870 }
3871
3872 if ((adv_dvc->tagqng_able & tidmask) && sdev->tagged_supported) {
3873 scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
3874 adv_dvc->max_dvc_qng);
3875 } else {
3876 scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
3877 }
3878}
3879
Linus Torvalds1da177e2005-04-16 15:20:36 -07003880/*
3881 * Set the number of commands to queue per device for the
3882 * specified host adapter.
3883 */
Matthew Wilcox47d853c2007-07-26 11:41:33 -04003884static int advansys_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003885{
Matthew Wilcox47d853c2007-07-26 11:41:33 -04003886 asc_board_t *boardp = ASC_BOARDP(sdev->host);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003887 boardp->flags |= ASC_SELECT_QUEUE_DEPTHS;
Matthew Wilcox47d853c2007-07-26 11:41:33 -04003888
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003889 /*
Matthew Wilcox47d853c2007-07-26 11:41:33 -04003890 * Save a pointer to the sdev and set its initial/maximum
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003891 * queue depth. Only save the pointer for a lun0 dev though.
3892 */
Matthew Wilcox47d853c2007-07-26 11:41:33 -04003893 if (sdev->lun == 0)
3894 boardp->device[sdev->id] = sdev;
3895
3896 if (ASC_NARROW_BOARD(boardp))
3897 advansys_narrow_slave_configure(sdev,
3898 &boardp->dvc_var.asc_dvc_var);
3899 else
3900 advansys_wide_slave_configure(sdev,
3901 &boardp->dvc_var.adv_dvc_var);
3902
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003903 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904}
3905
3906/*
3907 * Complete all requests on the singly linked list pointed
3908 * to by 'scp'.
3909 *
3910 * Interrupts can be enabled on entry.
3911 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003912static void asc_scsi_done_list(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003913{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003914 struct scsi_cmnd *tscp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003915
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003916 ASC_DBG(2, "asc_scsi_done_list: begin\n");
3917 while (scp != NULL) {
3918 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003919
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003920 ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lx\n", (ulong)scp);
3921 tscp = REQPNEXT(scp);
3922 scp->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003923
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003924 boardp = ASC_BOARDP(scp->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003925
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003926 if (scp->use_sg)
Matthew Wilcox394dbf32007-07-26 11:56:40 -04003927 dma_unmap_sg(boardp->dev,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003928 (struct scatterlist *)scp->request_buffer,
3929 scp->use_sg, scp->sc_data_direction);
3930 else if (scp->request_bufflen)
Matthew Wilcox394dbf32007-07-26 11:56:40 -04003931 dma_unmap_single(boardp->dev, scp->SCp.dma_handle,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003932 scp->request_bufflen,
3933 scp->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003934
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003935 ASC_STATS(scp->device->host, done);
3936 ASC_ASSERT(scp->scsi_done != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003938 scp->scsi_done(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003939
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003940 scp = tscp;
3941 }
3942 ASC_DBG(2, "asc_scsi_done_list: done\n");
3943 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944}
3945
3946/*
3947 * Execute a single 'Scsi_Cmnd'.
3948 *
3949 * The function 'done' is called when the request has been completed.
3950 *
3951 * Scsi_Cmnd:
3952 *
3953 * host - board controlling device
3954 * device - device to send command
3955 * target - target of device
3956 * lun - lun of device
3957 * cmd_len - length of SCSI CDB
3958 * cmnd - buffer for SCSI 8, 10, or 12 byte CDB
3959 * use_sg - if non-zero indicates scatter-gather request with use_sg elements
3960 *
3961 * if (use_sg == 0) {
3962 * request_buffer - buffer address for request
3963 * request_bufflen - length of request buffer
3964 * } else {
3965 * request_buffer - pointer to scatterlist structure
3966 * }
3967 *
3968 * sense_buffer - sense command buffer
3969 *
3970 * result (4 bytes of an int):
3971 * Byte Meaning
3972 * 0 SCSI Status Byte Code
3973 * 1 SCSI One Byte Message Code
3974 * 2 Host Error Code
3975 * 3 Mid-Level Error Code
3976 *
3977 * host driver fields:
3978 * SCp - Scsi_Pointer used for command processing status
3979 * scsi_done - used to save caller's done function
3980 * host_scribble - used for pointer to another struct scsi_cmnd
3981 *
3982 * If this function returns ASC_NOERROR the request has been enqueued
3983 * on the board's 'active' queue and will be completed from the
3984 * interrupt handler.
3985 *
3986 * If this function returns ASC_NOERROR the request has been enqueued
3987 * on the board's 'done' queue and must be completed by the caller.
3988 *
3989 * If ASC_BUSY is returned the request will be enqueued by the
3990 * caller on the target's waiting queue and re-tried later.
3991 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003992static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003994 asc_board_t *boardp;
3995 ASC_DVC_VAR *asc_dvc_varp;
3996 ADV_DVC_VAR *adv_dvc_varp;
3997 ADV_SCSI_REQ_Q *adv_scsiqp;
3998 struct scsi_device *device;
3999 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004001 ASC_DBG2(1, "asc_execute_scsi_cmnd: scp 0x%lx, done 0x%lx\n",
4002 (ulong)scp, (ulong)scp->scsi_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004003
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004004 boardp = ASC_BOARDP(scp->device->host);
4005 device = boardp->device[scp->device->id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004007 if (ASC_NARROW_BOARD(boardp)) {
4008 /*
4009 * Build and execute Narrow Board request.
4010 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004012 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004014 /*
4015 * Build Asc Library request structure using the
4016 * global structures 'asc_scsi_req' and 'asc_sg_head'.
4017 *
4018 * If an error is returned, then the request has been
4019 * queued on the board done queue. It will be completed
4020 * by the caller.
4021 *
4022 * asc_build_req() can not return ASC_BUSY.
4023 */
4024 if (asc_build_req(boardp, scp) == ASC_ERROR) {
4025 ASC_STATS(scp->device->host, build_error);
4026 return ASC_ERROR;
4027 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004029 /*
4030 * Execute the command. If there is no error, add the command
4031 * to the active queue.
4032 */
4033 switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
4034 case ASC_NOERROR:
4035 ASC_STATS(scp->device->host, exe_noerror);
4036 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004037 * Increment monotonically increasing per device
4038 * successful request counter. Wrapping doesn't matter.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004039 */
4040 boardp->reqcnt[scp->device->id]++;
4041 asc_enqueue(&boardp->active, scp, ASC_BACK);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004042 ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue(), "
4043 "ASC_NOERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004044 break;
4045 case ASC_BUSY:
4046 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004047 * Caller will enqueue request on the target's waiting
4048 * queue and retry later.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004049 */
4050 ASC_STATS(scp->device->host, exe_busy);
4051 break;
4052 case ASC_ERROR:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004053 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
4054 "AscExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
4055 boardp->id, asc_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004056 ASC_STATS(scp->device->host, exe_error);
4057 scp->result = HOST_BYTE(DID_ERROR);
4058 asc_enqueue(&boardp->done, scp, ASC_BACK);
4059 break;
4060 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004061 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
4062 "AscExeScsiQueue() unknown, err_code 0x%x\n",
4063 boardp->id, asc_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004064 ASC_STATS(scp->device->host, exe_unknown);
4065 scp->result = HOST_BYTE(DID_ERROR);
4066 asc_enqueue(&boardp->done, scp, ASC_BACK);
4067 break;
4068 }
4069 } else {
4070 /*
4071 * Build and execute Wide Board request.
4072 */
4073 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004074
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004075 /*
4076 * Build and get a pointer to an Adv Library request structure.
4077 *
4078 * If the request is successfully built then send it below,
4079 * otherwise return with an error.
4080 */
4081 switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
4082 case ASC_NOERROR:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004083 ASC_DBG(3, "asc_execute_scsi_cmnd: adv_build_req "
4084 "ASC_NOERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004085 break;
4086 case ASC_BUSY:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004087 ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req "
4088 "ASC_BUSY\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004089 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004090 * If busy is returned the request has not been
4091 * enqueued. It will be enqueued by the caller on the
4092 * target's waiting queue and retried later.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004093 *
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004094 * The asc_stats fields 'adv_build_noreq' and
4095 * 'adv_build_nosg' count wide board busy conditions.
4096 * They are updated in adv_build_req and
4097 * adv_get_sglist, respectively.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004098 */
4099 return ASC_BUSY;
4100 case ASC_ERROR:
4101 /*
4102 * If an error is returned, then the request has been
4103 * queued on the board done queue. It will be completed
4104 * by the caller.
4105 */
4106 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004107 ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req "
4108 "ASC_ERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004109 ASC_STATS(scp->device->host, build_error);
4110 return ASC_ERROR;
4111 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004112
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004113 /*
4114 * Execute the command. If there is no error, add the command
4115 * to the active queue.
4116 */
4117 switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) {
4118 case ASC_NOERROR:
4119 ASC_STATS(scp->device->host, exe_noerror);
4120 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004121 * Increment monotonically increasing per device
4122 * successful request counter. Wrapping doesn't matter.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004123 */
4124 boardp->reqcnt[scp->device->id]++;
4125 asc_enqueue(&boardp->active, scp, ASC_BACK);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004126 ASC_DBG(1, "asc_execute_scsi_cmnd: AdvExeScsiQueue(), "
4127 "ASC_NOERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004128 break;
4129 case ASC_BUSY:
4130 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004131 * Caller will enqueue request on the target's waiting
4132 * queue and retry later.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004133 */
4134 ASC_STATS(scp->device->host, exe_busy);
4135 break;
4136 case ASC_ERROR:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004137 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
4138 "AdvExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
4139 boardp->id, adv_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004140 ASC_STATS(scp->device->host, exe_error);
4141 scp->result = HOST_BYTE(DID_ERROR);
4142 asc_enqueue(&boardp->done, scp, ASC_BACK);
4143 break;
4144 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004145 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
4146 "AdvExeScsiQueue() unknown, err_code 0x%x\n",
4147 boardp->id, adv_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004148 ASC_STATS(scp->device->host, exe_unknown);
4149 scp->result = HOST_BYTE(DID_ERROR);
4150 asc_enqueue(&boardp->done, scp, ASC_BACK);
4151 break;
4152 }
4153 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004154
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004155 ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
4156 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004157}
4158
4159/*
4160 * Build a request structure for the Asc Library (Narrow Board).
4161 *
4162 * The global structures 'asc_scsi_q' and 'asc_sg_head' are
4163 * used to build the request.
4164 *
4165 * If an error occurs, then queue the request on the board done
4166 * queue and return ASC_ERROR.
4167 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004168static int asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004170 /*
4171 * Mutually exclusive access is required to 'asc_scsi_q' and
4172 * 'asc_sg_head' until after the request is started.
4173 */
4174 memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004176 /*
4177 * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'.
4178 */
4179 asc_scsi_q.q2.srb_ptr = ASC_VADDR_TO_U32(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004181 /*
4182 * Build the ASC_SCSI_Q request.
4183 *
4184 * For narrow boards a CDB length maximum of 12 bytes
4185 * is supported.
4186 */
4187 if (scp->cmd_len > ASC_MAX_CDB_LEN) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004188 ASC_PRINT3("asc_build_req: board %d: cmd_len %d > "
4189 "ASC_MAX_CDB_LEN %d\n", boardp->id, scp->cmd_len,
4190 ASC_MAX_CDB_LEN);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004191 scp->result = HOST_BYTE(DID_ERROR);
4192 asc_enqueue(&boardp->done, scp, ASC_BACK);
4193 return ASC_ERROR;
4194 }
4195 asc_scsi_q.cdbptr = &scp->cmnd[0];
4196 asc_scsi_q.q2.cdb_len = scp->cmd_len;
4197 asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id);
4198 asc_scsi_q.q1.target_lun = scp->device->lun;
4199 asc_scsi_q.q2.target_ix =
4200 ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
4201 asc_scsi_q.q1.sense_addr =
4202 cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
4203 asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004204
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004205 /*
4206 * If there are any outstanding requests for the current target,
4207 * then every 255th request send an ORDERED request. This heuristic
4208 * tries to retain the benefit of request sorting while preventing
4209 * request starvation. 255 is the max number of tags or pending commands
4210 * a device may have outstanding.
4211 *
4212 * The request count is incremented below for every successfully
4213 * started request.
4214 *
4215 */
4216 if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->device->id] > 0) &&
4217 (boardp->reqcnt[scp->device->id] % 255) == 0) {
4218 asc_scsi_q.q2.tag_code = MSG_ORDERED_TAG;
4219 } else {
4220 asc_scsi_q.q2.tag_code = MSG_SIMPLE_TAG;
4221 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004223 /*
4224 * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
4225 * buffer command.
4226 */
4227 if (scp->use_sg == 0) {
4228 /*
4229 * CDB request of single contiguous buffer.
4230 */
4231 ASC_STATS(scp->device->host, cont_cnt);
4232 scp->SCp.dma_handle = scp->request_bufflen ?
Matthew Wilcox394dbf32007-07-26 11:56:40 -04004233 dma_map_single(boardp->dev, scp->request_buffer,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004234 scp->request_bufflen,
4235 scp->sc_data_direction) : 0;
4236 asc_scsi_q.q1.data_addr = cpu_to_le32(scp->SCp.dma_handle);
4237 asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen);
4238 ASC_STATS_ADD(scp->device->host, cont_xfer,
4239 ASC_CEILING(scp->request_bufflen, 512));
4240 asc_scsi_q.q1.sg_queue_cnt = 0;
4241 asc_scsi_q.sg_head = NULL;
4242 } else {
4243 /*
4244 * CDB scatter-gather request list.
4245 */
4246 int sgcnt;
4247 int use_sg;
4248 struct scatterlist *slp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004249
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004250 slp = (struct scatterlist *)scp->request_buffer;
Matthew Wilcox394dbf32007-07-26 11:56:40 -04004251 use_sg = dma_map_sg(boardp->dev, slp, scp->use_sg,
4252 scp->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004253
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004254 if (use_sg > scp->device->host->sg_tablesize) {
Matthew Wilcox394dbf32007-07-26 11:56:40 -04004255 ASC_PRINT3("asc_build_req: board %d: use_sg %d > "
4256 "sg_tablesize %d\n", boardp->id, use_sg,
4257 scp->device->host->sg_tablesize);
4258 dma_unmap_sg(boardp->dev, slp, scp->use_sg,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004259 scp->sc_data_direction);
4260 scp->result = HOST_BYTE(DID_ERROR);
4261 asc_enqueue(&boardp->done, scp, ASC_BACK);
4262 return ASC_ERROR;
4263 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004264
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004265 ASC_STATS(scp->device->host, sg_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004266
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004267 /*
4268 * Use global ASC_SG_HEAD structure and set the ASC_SCSI_Q
4269 * structure to point to it.
4270 */
4271 memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004272
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004273 asc_scsi_q.q1.cntl |= QC_SG_HEAD;
4274 asc_scsi_q.sg_head = &asc_sg_head;
4275 asc_scsi_q.q1.data_cnt = 0;
4276 asc_scsi_q.q1.data_addr = 0;
4277 /* This is a byte value, otherwise it would need to be swapped. */
4278 asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = use_sg;
4279 ASC_STATS_ADD(scp->device->host, sg_elem,
4280 asc_sg_head.entry_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004282 /*
4283 * Convert scatter-gather list into ASC_SG_HEAD list.
4284 */
4285 for (sgcnt = 0; sgcnt < use_sg; sgcnt++, slp++) {
4286 asc_sg_head.sg_list[sgcnt].addr =
4287 cpu_to_le32(sg_dma_address(slp));
4288 asc_sg_head.sg_list[sgcnt].bytes =
4289 cpu_to_le32(sg_dma_len(slp));
4290 ASC_STATS_ADD(scp->device->host, sg_xfer,
4291 ASC_CEILING(sg_dma_len(slp), 512));
4292 }
4293 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004294
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004295 ASC_DBG_PRT_ASC_SCSI_Q(2, &asc_scsi_q);
4296 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004297
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004298 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004299}
4300
4301/*
4302 * Build a request structure for the Adv Library (Wide Board).
4303 *
4304 * If an adv_req_t can not be allocated to issue the request,
4305 * then return ASC_BUSY. If an error occurs, then return ASC_ERROR.
4306 *
4307 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the
4308 * microcode for DMA addresses or math operations are byte swapped
4309 * to little-endian order.
4310 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004311static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312adv_build_req(asc_board_t *boardp, struct scsi_cmnd *scp,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004313 ADV_SCSI_REQ_Q **adv_scsiqpp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004315 adv_req_t *reqp;
4316 ADV_SCSI_REQ_Q *scsiqp;
4317 int i;
4318 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004320 /*
4321 * Allocate an adv_req_t structure from the board to execute
4322 * the command.
4323 */
4324 if (boardp->adv_reqp == NULL) {
4325 ASC_DBG(1, "adv_build_req: no free adv_req_t\n");
4326 ASC_STATS(scp->device->host, adv_build_noreq);
4327 return ASC_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328 } else {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004329 reqp = boardp->adv_reqp;
4330 boardp->adv_reqp = reqp->next_reqp;
4331 reqp->next_reqp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004334 /*
4335 * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
4336 */
4337 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004339 /*
4340 * Initialize the structure.
4341 */
4342 scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004344 /*
4345 * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
4346 */
4347 scsiqp->srb_ptr = ASC_VADDR_TO_U32(reqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004349 /*
4350 * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure.
4351 */
4352 reqp->cmndp = scp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004354 /*
4355 * Build the ADV_SCSI_REQ_Q request.
4356 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004357
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004358 /*
4359 * Set CDB length and copy it to the request structure.
4360 * For wide boards a CDB length maximum of 16 bytes
4361 * is supported.
4362 */
4363 if (scp->cmd_len > ADV_MAX_CDB_LEN) {
4364 ASC_PRINT3
4365 ("adv_build_req: board %d: cmd_len %d > ADV_MAX_CDB_LEN %d\n",
4366 boardp->id, scp->cmd_len, ADV_MAX_CDB_LEN);
4367 scp->result = HOST_BYTE(DID_ERROR);
4368 asc_enqueue(&boardp->done, scp, ASC_BACK);
4369 return ASC_ERROR;
4370 }
4371 scsiqp->cdb_len = scp->cmd_len;
4372 /* Copy first 12 CDB bytes to cdb[]. */
4373 for (i = 0; i < scp->cmd_len && i < 12; i++) {
4374 scsiqp->cdb[i] = scp->cmnd[i];
4375 }
4376 /* Copy last 4 CDB bytes, if present, to cdb16[]. */
4377 for (; i < scp->cmd_len; i++) {
4378 scsiqp->cdb16[i - 12] = scp->cmnd[i];
4379 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004381 scsiqp->target_id = scp->device->id;
4382 scsiqp->target_lun = scp->device->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004384 scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
4385 scsiqp->sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004387 /*
4388 * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather
4389 * buffer command.
4390 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004391
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004392 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
4393 scsiqp->vdata_addr = scp->request_buffer;
4394 scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer));
4395
4396 if (scp->use_sg == 0) {
4397 /*
4398 * CDB request of single contiguous buffer.
4399 */
4400 reqp->sgblkp = NULL;
4401 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
4402 if (scp->request_bufflen) {
4403 scsiqp->vdata_addr = scp->request_buffer;
4404 scp->SCp.dma_handle =
Matthew Wilcox394dbf32007-07-26 11:56:40 -04004405 dma_map_single(boardp->dev, scp->request_buffer,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004406 scp->request_bufflen,
4407 scp->sc_data_direction);
4408 } else {
4409 scsiqp->vdata_addr = NULL;
4410 scp->SCp.dma_handle = 0;
4411 }
4412 scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle);
4413 scsiqp->sg_list_ptr = NULL;
4414 scsiqp->sg_real_addr = 0;
4415 ASC_STATS(scp->device->host, cont_cnt);
4416 ASC_STATS_ADD(scp->device->host, cont_xfer,
4417 ASC_CEILING(scp->request_bufflen, 512));
4418 } else {
4419 /*
4420 * CDB scatter-gather request list.
4421 */
4422 struct scatterlist *slp;
4423 int use_sg;
4424
4425 slp = (struct scatterlist *)scp->request_buffer;
Matthew Wilcox394dbf32007-07-26 11:56:40 -04004426 use_sg = dma_map_sg(boardp->dev, slp, scp->use_sg,
4427 scp->sc_data_direction);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004428
4429 if (use_sg > ADV_MAX_SG_LIST) {
Matthew Wilcox394dbf32007-07-26 11:56:40 -04004430 ASC_PRINT3("adv_build_req: board %d: use_sg %d > "
4431 "ADV_MAX_SG_LIST %d\n", boardp->id, use_sg,
4432 scp->device->host->sg_tablesize);
4433 dma_unmap_sg(boardp->dev, slp, scp->use_sg,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004434 scp->sc_data_direction);
4435 scp->result = HOST_BYTE(DID_ERROR);
4436 asc_enqueue(&boardp->done, scp, ASC_BACK);
4437
4438 /*
Matthew Wilcox394dbf32007-07-26 11:56:40 -04004439 * Free the 'adv_req_t' structure by adding it back
4440 * to the board free list.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004441 */
4442 reqp->next_reqp = boardp->adv_reqp;
4443 boardp->adv_reqp = reqp;
4444
4445 return ASC_ERROR;
4446 }
4447
Matthew Wilcox394dbf32007-07-26 11:56:40 -04004448 ret = adv_get_sglist(boardp, reqp, scp, use_sg);
4449 if (ret != ADV_SUCCESS) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004450 /*
Matthew Wilcox394dbf32007-07-26 11:56:40 -04004451 * Free the adv_req_t structure by adding it back to
4452 * the board free list.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004453 */
4454 reqp->next_reqp = boardp->adv_reqp;
4455 boardp->adv_reqp = reqp;
4456
4457 return ret;
4458 }
4459
4460 ASC_STATS(scp->device->host, sg_cnt);
4461 ASC_STATS_ADD(scp->device->host, sg_elem, use_sg);
4462 }
4463
4464 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
4465 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
4466
4467 *adv_scsiqpp = scsiqp;
4468
4469 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470}
4471
4472/*
4473 * Build scatter-gather list for Adv Library (Wide Board).
4474 *
4475 * Additional ADV_SG_BLOCK structures will need to be allocated
4476 * if the total number of scatter-gather elements exceeds
4477 * NO_OF_SG_PER_BLOCK (15). The ADV_SG_BLOCK structures are
4478 * assumed to be physically contiguous.
4479 *
4480 * Return:
4481 * ADV_SUCCESS(1) - SG List successfully created
4482 * ADV_ERROR(-1) - SG List creation failed
4483 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004484static int
4485adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, struct scsi_cmnd *scp,
4486 int use_sg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004488 adv_sgblk_t *sgblkp;
4489 ADV_SCSI_REQ_Q *scsiqp;
4490 struct scatterlist *slp;
4491 int sg_elem_cnt;
4492 ADV_SG_BLOCK *sg_block, *prev_sg_block;
4493 ADV_PADDR sg_block_paddr;
4494 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004496 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
4497 slp = (struct scatterlist *)scp->request_buffer;
4498 sg_elem_cnt = use_sg;
4499 prev_sg_block = NULL;
4500 reqp->sgblkp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004502 do {
4503 /*
4504 * Allocate a 'adv_sgblk_t' structure from the board free
4505 * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK
4506 * (15) scatter-gather elements.
4507 */
4508 if ((sgblkp = boardp->adv_sgblkp) == NULL) {
4509 ASC_DBG(1, "adv_get_sglist: no free adv_sgblk_t\n");
4510 ASC_STATS(scp->device->host, adv_build_nosg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004512 /*
4513 * Allocation failed. Free 'adv_sgblk_t' structures already
4514 * allocated for the request.
4515 */
4516 while ((sgblkp = reqp->sgblkp) != NULL) {
4517 /* Remove 'sgblkp' from the request list. */
4518 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004519
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004520 /* Add 'sgblkp' to the board free list. */
4521 sgblkp->next_sgblkp = boardp->adv_sgblkp;
4522 boardp->adv_sgblkp = sgblkp;
4523 }
4524 return ASC_BUSY;
4525 } else {
4526 /* Complete 'adv_sgblk_t' board allocation. */
4527 boardp->adv_sgblkp = sgblkp->next_sgblkp;
4528 sgblkp->next_sgblkp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004530 /*
4531 * Get 8 byte aligned virtual and physical addresses for
4532 * the allocated ADV_SG_BLOCK structure.
4533 */
4534 sg_block =
4535 (ADV_SG_BLOCK *)ADV_8BALIGN(&sgblkp->sg_block);
4536 sg_block_paddr = virt_to_bus(sg_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004538 /*
4539 * Check if this is the first 'adv_sgblk_t' for the request.
4540 */
4541 if (reqp->sgblkp == NULL) {
4542 /* Request's first scatter-gather block. */
4543 reqp->sgblkp = sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004545 /*
4546 * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical
4547 * address pointers.
4548 */
4549 scsiqp->sg_list_ptr = sg_block;
4550 scsiqp->sg_real_addr =
4551 cpu_to_le32(sg_block_paddr);
4552 } else {
4553 /* Request's second or later scatter-gather block. */
4554 sgblkp->next_sgblkp = reqp->sgblkp;
4555 reqp->sgblkp = sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004557 /*
4558 * Point the previous ADV_SG_BLOCK structure to
4559 * the newly allocated ADV_SG_BLOCK structure.
4560 */
4561 ASC_ASSERT(prev_sg_block != NULL);
4562 prev_sg_block->sg_ptr =
4563 cpu_to_le32(sg_block_paddr);
4564 }
4565 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004567 for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) {
4568 sg_block->sg_list[i].sg_addr =
4569 cpu_to_le32(sg_dma_address(slp));
4570 sg_block->sg_list[i].sg_count =
4571 cpu_to_le32(sg_dma_len(slp));
4572 ASC_STATS_ADD(scp->device->host, sg_xfer,
4573 ASC_CEILING(sg_dma_len(slp), 512));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004575 if (--sg_elem_cnt == 0) { /* Last ADV_SG_BLOCK and scatter-gather entry. */
4576 sg_block->sg_cnt = i + 1;
4577 sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */
4578 return ADV_SUCCESS;
4579 }
4580 slp++;
4581 }
4582 sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
4583 prev_sg_block = sg_block;
4584 }
4585 while (1);
4586 /* NOTREACHED */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004587}
4588
4589/*
4590 * asc_isr_callback() - Second Level Interrupt Handler called by AscISR().
4591 *
4592 * Interrupt callback function for the Narrow SCSI Asc Library.
4593 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004594static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004595{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004596 asc_board_t *boardp;
4597 struct scsi_cmnd *scp;
4598 struct Scsi_Host *shost;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004599
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004600 ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp 0x%lx, qdonep 0x%lx\n",
4601 (ulong)asc_dvc_varp, (ulong)qdonep);
4602 ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004604 /*
4605 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
4606 * command that has been completed.
4607 */
4608 scp = (struct scsi_cmnd *)ASC_U32_TO_VADDR(qdonep->d2.srb_ptr);
4609 ASC_DBG1(1, "asc_isr_callback: scp 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004610
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004611 if (scp == NULL) {
4612 ASC_PRINT("asc_isr_callback: scp is NULL\n");
4613 return;
4614 }
4615 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004617 shost = scp->device->host;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004618 ASC_STATS(shost, callback);
4619 ASC_DBG1(1, "asc_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004621 /*
4622 * If the request isn't found on the active queue, it may
4623 * have been removed to handle a reset request.
4624 * Display a message and return.
4625 */
4626 boardp = ASC_BOARDP(shost);
4627 ASC_ASSERT(asc_dvc_varp == &boardp->dvc_var.asc_dvc_var);
4628 if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
4629 ASC_PRINT2
4630 ("asc_isr_callback: board %d: scp 0x%lx not on active queue\n",
4631 boardp->id, (ulong)scp);
4632 return;
4633 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004635 /*
4636 * 'qdonep' contains the command's ending status.
4637 */
4638 switch (qdonep->d3.done_stat) {
4639 case QD_NO_ERROR:
4640 ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n");
4641 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004642
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004643 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004644 * Check for an underrun condition.
4645 *
4646 * If there was no error and an underrun condition, then
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004647 * return the number of underrun bytes.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004648 */
4649 if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 &&
4650 qdonep->remain_bytes <= scp->request_bufflen) {
4651 ASC_DBG1(1,
4652 "asc_isr_callback: underrun condition %u bytes\n",
4653 (unsigned)qdonep->remain_bytes);
4654 scp->resid = qdonep->remain_bytes;
4655 }
4656 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004658 case QD_WITH_ERROR:
4659 ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n");
4660 switch (qdonep->d3.host_stat) {
4661 case QHSTA_NO_ERROR:
4662 if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
4663 ASC_DBG(2,
4664 "asc_isr_callback: SAM_STAT_CHECK_CONDITION\n");
4665 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
4666 sizeof(scp->sense_buffer));
4667 /*
4668 * Note: The 'status_byte()' macro used by target drivers
4669 * defined in scsi.h shifts the status byte returned by
4670 * host drivers right by 1 bit. This is why target drivers
4671 * also use right shifted status byte definitions. For
4672 * instance target drivers use CHECK_CONDITION, defined to
4673 * 0x1, instead of the SCSI defined check condition value
4674 * of 0x2. Host drivers are supposed to return the status
4675 * byte as it is defined by SCSI.
4676 */
4677 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
4678 STATUS_BYTE(qdonep->d3.scsi_stat);
4679 } else {
4680 scp->result = STATUS_BYTE(qdonep->d3.scsi_stat);
4681 }
4682 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004683
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004684 default:
4685 /* QHSTA error occurred */
4686 ASC_DBG1(1, "asc_isr_callback: host_stat 0x%x\n",
4687 qdonep->d3.host_stat);
4688 scp->result = HOST_BYTE(DID_BAD_TARGET);
4689 break;
4690 }
4691 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004692
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004693 case QD_ABORTED_BY_HOST:
4694 ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOST\n");
4695 scp->result =
4696 HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.
4697 scsi_msg) |
4698 STATUS_BYTE(qdonep->d3.scsi_stat);
4699 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004700
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004701 default:
4702 ASC_DBG1(1, "asc_isr_callback: done_stat 0x%x\n",
4703 qdonep->d3.done_stat);
4704 scp->result =
4705 HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.
4706 scsi_msg) |
4707 STATUS_BYTE(qdonep->d3.scsi_stat);
4708 break;
4709 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004710
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004711 /*
4712 * If the 'init_tidmask' bit isn't already set for the target and the
4713 * current request finished normally, then set the bit for the target
4714 * to indicate that a device is present.
4715 */
4716 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
4717 qdonep->d3.done_stat == QD_NO_ERROR &&
4718 qdonep->d3.host_stat == QHSTA_NO_ERROR) {
4719 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
4720 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004722 /*
4723 * Because interrupts may be enabled by the 'struct scsi_cmnd' done
4724 * function, add the command to the end of the board's done queue.
4725 * The done function for the command will be called from
4726 * advansys_interrupt().
4727 */
4728 asc_enqueue(&boardp->done, scp, ASC_BACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004729
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004730 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004731}
4732
4733/*
4734 * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR().
4735 *
4736 * Callback function for the Wide SCSI Adv Library.
4737 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004738static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004739{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004740 asc_board_t *boardp;
4741 adv_req_t *reqp;
4742 adv_sgblk_t *sgblkp;
4743 struct scsi_cmnd *scp;
4744 struct Scsi_Host *shost;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004745 ADV_DCNT resid_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004746
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004747 ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp 0x%lx, scsiqp 0x%lx\n",
4748 (ulong)adv_dvc_varp, (ulong)scsiqp);
4749 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004750
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004751 /*
4752 * Get the adv_req_t structure for the command that has been
4753 * completed. The adv_req_t structure actually contains the
4754 * completed ADV_SCSI_REQ_Q structure.
4755 */
4756 reqp = (adv_req_t *)ADV_U32_TO_VADDR(scsiqp->srb_ptr);
4757 ASC_DBG1(1, "adv_isr_callback: reqp 0x%lx\n", (ulong)reqp);
4758 if (reqp == NULL) {
4759 ASC_PRINT("adv_isr_callback: reqp is NULL\n");
4760 return;
4761 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004763 /*
4764 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
4765 * command that has been completed.
4766 *
4767 * Note: The adv_req_t request structure and adv_sgblk_t structure,
4768 * if any, are dropped, because a board structure pointer can not be
4769 * determined.
4770 */
4771 scp = reqp->cmndp;
4772 ASC_DBG1(1, "adv_isr_callback: scp 0x%lx\n", (ulong)scp);
4773 if (scp == NULL) {
4774 ASC_PRINT
4775 ("adv_isr_callback: scp is NULL; adv_req_t dropped.\n");
4776 return;
4777 }
4778 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004780 shost = scp->device->host;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004781 ASC_STATS(shost, callback);
4782 ASC_DBG1(1, "adv_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004783
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004784 /*
4785 * If the request isn't found on the active queue, it may have been
4786 * removed to handle a reset request. Display a message and return.
4787 *
4788 * Note: Because the structure may still be in use don't attempt
4789 * to free the adv_req_t and adv_sgblk_t, if any, structures.
4790 */
4791 boardp = ASC_BOARDP(shost);
4792 ASC_ASSERT(adv_dvc_varp == &boardp->dvc_var.adv_dvc_var);
4793 if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
4794 ASC_PRINT2
4795 ("adv_isr_callback: board %d: scp 0x%lx not on active queue\n",
4796 boardp->id, (ulong)scp);
4797 return;
4798 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004800 /*
4801 * 'done_status' contains the command's ending status.
4802 */
4803 switch (scsiqp->done_status) {
4804 case QD_NO_ERROR:
4805 ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n");
4806 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004808 /*
4809 * Check for an underrun condition.
4810 *
4811 * If there was no error and an underrun condition, then
4812 * then return the number of underrun bytes.
4813 */
4814 resid_cnt = le32_to_cpu(scsiqp->data_cnt);
4815 if (scp->request_bufflen != 0 && resid_cnt != 0 &&
4816 resid_cnt <= scp->request_bufflen) {
4817 ASC_DBG1(1,
4818 "adv_isr_callback: underrun condition %lu bytes\n",
4819 (ulong)resid_cnt);
4820 scp->resid = resid_cnt;
4821 }
4822 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004824 case QD_WITH_ERROR:
4825 ASC_DBG(2, "adv_isr_callback: QD_WITH_ERROR\n");
4826 switch (scsiqp->host_status) {
4827 case QHSTA_NO_ERROR:
4828 if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
4829 ASC_DBG(2,
4830 "adv_isr_callback: SAM_STAT_CHECK_CONDITION\n");
4831 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
4832 sizeof(scp->sense_buffer));
4833 /*
4834 * Note: The 'status_byte()' macro used by target drivers
4835 * defined in scsi.h shifts the status byte returned by
4836 * host drivers right by 1 bit. This is why target drivers
4837 * also use right shifted status byte definitions. For
4838 * instance target drivers use CHECK_CONDITION, defined to
4839 * 0x1, instead of the SCSI defined check condition value
4840 * of 0x2. Host drivers are supposed to return the status
4841 * byte as it is defined by SCSI.
4842 */
4843 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
4844 STATUS_BYTE(scsiqp->scsi_status);
4845 } else {
4846 scp->result = STATUS_BYTE(scsiqp->scsi_status);
4847 }
4848 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004849
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004850 default:
4851 /* Some other QHSTA error occurred. */
4852 ASC_DBG1(1, "adv_isr_callback: host_status 0x%x\n",
4853 scsiqp->host_status);
4854 scp->result = HOST_BYTE(DID_BAD_TARGET);
4855 break;
4856 }
4857 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004858
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004859 case QD_ABORTED_BY_HOST:
4860 ASC_DBG(1, "adv_isr_callback: QD_ABORTED_BY_HOST\n");
4861 scp->result =
4862 HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status);
4863 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004864
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004865 default:
4866 ASC_DBG1(1, "adv_isr_callback: done_status 0x%x\n",
4867 scsiqp->done_status);
4868 scp->result =
4869 HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status);
4870 break;
4871 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004872
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004873 /*
4874 * If the 'init_tidmask' bit isn't already set for the target and the
4875 * current request finished normally, then set the bit for the target
4876 * to indicate that a device is present.
4877 */
4878 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
4879 scsiqp->done_status == QD_NO_ERROR &&
4880 scsiqp->host_status == QHSTA_NO_ERROR) {
4881 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
4882 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004883
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004884 /*
4885 * Because interrupts may be enabled by the 'struct scsi_cmnd' done
4886 * function, add the command to the end of the board's done queue.
4887 * The done function for the command will be called from
4888 * advansys_interrupt().
4889 */
4890 asc_enqueue(&boardp->done, scp, ASC_BACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004891
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004892 /*
4893 * Free all 'adv_sgblk_t' structures allocated for the request.
4894 */
4895 while ((sgblkp = reqp->sgblkp) != NULL) {
4896 /* Remove 'sgblkp' from the request list. */
4897 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004898
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004899 /* Add 'sgblkp' to the board free list. */
4900 sgblkp->next_sgblkp = boardp->adv_sgblkp;
4901 boardp->adv_sgblkp = sgblkp;
4902 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004903
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004904 /*
4905 * Free the adv_req_t structure used with the command by adding
4906 * it back to the board free list.
4907 */
4908 reqp->next_reqp = boardp->adv_reqp;
4909 boardp->adv_reqp = reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004911 ASC_DBG(1, "adv_isr_callback: done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004912
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004913 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004914}
4915
4916/*
4917 * adv_async_callback() - Adv Library asynchronous event callback function.
4918 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004919static void adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004920{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004921 switch (code) {
4922 case ADV_ASYNC_SCSI_BUS_RESET_DET:
4923 /*
4924 * The firmware detected a SCSI Bus reset.
4925 */
4926 ASC_DBG(0,
4927 "adv_async_callback: ADV_ASYNC_SCSI_BUS_RESET_DET\n");
4928 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004929
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004930 case ADV_ASYNC_RDMA_FAILURE:
4931 /*
4932 * Handle RDMA failure by resetting the SCSI Bus and
4933 * possibly the chip if it is unresponsive. Log the error
4934 * with a unique code.
4935 */
4936 ASC_DBG(0, "adv_async_callback: ADV_ASYNC_RDMA_FAILURE\n");
4937 AdvResetChipAndSB(adv_dvc_varp);
4938 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004939
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004940 case ADV_HOST_SCSI_BUS_RESET:
4941 /*
4942 * Host generated SCSI bus reset occurred.
4943 */
4944 ASC_DBG(0, "adv_async_callback: ADV_HOST_SCSI_BUS_RESET\n");
4945 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004946
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004947 default:
4948 ASC_DBG1(0, "DvcAsyncCallBack: unknown code 0x%x\n", code);
4949 break;
4950 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004951}
4952
4953/*
4954 * Add a 'REQP' to the end of specified queue. Set 'tidmask'
4955 * to indicate a command is queued for the device.
4956 *
4957 * 'flag' may be either ASC_FRONT or ASC_BACK.
4958 *
4959 * 'REQPNEXT(reqp)' returns reqp's next pointer.
4960 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004961static void asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004962{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004963 int tid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004964
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004965 ASC_DBG3(3, "asc_enqueue: ascq 0x%lx, reqp 0x%lx, flag %d\n",
4966 (ulong)ascq, (ulong)reqp, flag);
4967 ASC_ASSERT(reqp != NULL);
4968 ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
4969 tid = REQPTID(reqp);
4970 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
4971 if (flag == ASC_FRONT) {
4972 reqp->host_scribble = (unsigned char *)ascq->q_first[tid];
4973 ascq->q_first[tid] = reqp;
4974 /* If the queue was empty, set the last pointer. */
4975 if (ascq->q_last[tid] == NULL) {
4976 ascq->q_last[tid] = reqp;
4977 }
4978 } else { /* ASC_BACK */
4979 if (ascq->q_last[tid] != NULL) {
4980 ascq->q_last[tid]->host_scribble =
4981 (unsigned char *)reqp;
4982 }
4983 ascq->q_last[tid] = reqp;
4984 reqp->host_scribble = NULL;
4985 /* If the queue was empty, set the first pointer. */
4986 if (ascq->q_first[tid] == NULL) {
4987 ascq->q_first[tid] = reqp;
4988 }
4989 }
4990 /* The queue has at least one entry, set its bit. */
4991 ascq->q_tidmask |= ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004992#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004993 /* Maintain request queue statistics. */
4994 ascq->q_tot_cnt[tid]++;
4995 ascq->q_cur_cnt[tid]++;
4996 if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) {
4997 ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid];
4998 ASC_DBG2(2, "asc_enqueue: new q_max_cnt[%d] %d\n",
4999 tid, ascq->q_max_cnt[tid]);
5000 }
5001 REQPTIME(reqp) = REQTIMESTAMP();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005002#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005003 ASC_DBG1(3, "asc_enqueue: reqp 0x%lx\n", (ulong)reqp);
5004 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005005}
5006
5007/*
5008 * Return first queued 'REQP' on the specified queue for
5009 * the specified target device. Clear the 'tidmask' bit for
5010 * the device if no more commands are left queued for it.
5011 *
5012 * 'REQPNEXT(reqp)' returns reqp's next pointer.
5013 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005014static REQP asc_dequeue(asc_queue_t *ascq, int tid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005015{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005016 REQP reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005017
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005018 ASC_DBG2(3, "asc_dequeue: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
5019 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
5020 if ((reqp = ascq->q_first[tid]) != NULL) {
5021 ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid));
5022 ascq->q_first[tid] = REQPNEXT(reqp);
5023 /* If the queue is empty, clear its bit and the last pointer. */
5024 if (ascq->q_first[tid] == NULL) {
5025 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
5026 ASC_ASSERT(ascq->q_last[tid] == reqp);
5027 ascq->q_last[tid] = NULL;
5028 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005029#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005030 /* Maintain request queue statistics. */
5031 ascq->q_cur_cnt[tid]--;
5032 ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
5033 REQTIMESTAT("asc_dequeue", ascq, reqp, tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005034#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005035 }
5036 ASC_DBG1(3, "asc_dequeue: reqp 0x%lx\n", (ulong)reqp);
5037 return reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005038}
5039
5040/*
5041 * Return a pointer to a singly linked list of all the requests queued
5042 * for 'tid' on the 'asc_queue_t' pointed to by 'ascq'.
5043 *
5044 * If 'lastpp' is not NULL, '*lastpp' will be set to point to the
5045 * the last request returned in the singly linked list.
5046 *
5047 * 'tid' should either be a valid target id or if it is ASC_TID_ALL,
5048 * then all queued requests are concatenated into one list and
5049 * returned.
5050 *
5051 * Note: If 'lastpp' is used to append a new list to the end of
5052 * an old list, only change the old list last pointer if '*lastpp'
5053 * (or the function return value) is not NULL, i.e. use a temporary
5054 * variable for 'lastpp' and check its value after the function return
5055 * before assigning it to the list last pointer.
5056 *
5057 * Unfortunately collecting queuing time statistics adds overhead to
5058 * the function that isn't inherent to the function's algorithm.
5059 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005060static REQP asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005061{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005062 REQP firstp, lastp;
5063 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005064
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005065 ASC_DBG2(3, "asc_dequeue_list: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
5066 ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005067
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005068 /*
5069 * If 'tid' is not ASC_TID_ALL, return requests only for
5070 * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all
5071 * requests for all tids.
5072 */
5073 if (tid != ASC_TID_ALL) {
5074 /* Return all requests for the specified 'tid'. */
5075 if ((ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)) == 0) {
5076 /* List is empty; Set first and last return pointers to NULL. */
5077 firstp = lastp = NULL;
5078 } else {
5079 firstp = ascq->q_first[tid];
5080 lastp = ascq->q_last[tid];
5081 ascq->q_first[tid] = ascq->q_last[tid] = NULL;
5082 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005083#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005084 {
5085 REQP reqp;
5086 ascq->q_cur_cnt[tid] = 0;
5087 for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
5088 REQTIMESTAT("asc_dequeue_list", ascq,
5089 reqp, tid);
5090 }
5091 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005092#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005093 }
5094 } else {
5095 /* Return all requests for all tids. */
5096 firstp = lastp = NULL;
5097 for (i = 0; i <= ADV_MAX_TID; i++) {
5098 if (ascq->q_tidmask & ADV_TID_TO_TIDMASK(i)) {
5099 if (firstp == NULL) {
5100 firstp = ascq->q_first[i];
5101 lastp = ascq->q_last[i];
5102 } else {
5103 ASC_ASSERT(lastp != NULL);
5104 lastp->host_scribble =
5105 (unsigned char *)ascq->q_first[i];
5106 lastp = ascq->q_last[i];
5107 }
5108 ascq->q_first[i] = ascq->q_last[i] = NULL;
5109 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005110#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005111 ascq->q_cur_cnt[i] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005112#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005113 }
5114 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005115#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005116 {
5117 REQP reqp;
5118 for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
5119 REQTIMESTAT("asc_dequeue_list", ascq, reqp,
5120 reqp->device->id);
5121 }
5122 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005123#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005124 }
5125 if (lastpp) {
5126 *lastpp = lastp;
5127 }
5128 ASC_DBG1(3, "asc_dequeue_list: firstp 0x%lx\n", (ulong)firstp);
5129 return firstp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005130}
5131
5132/*
5133 * Remove the specified 'REQP' from the specified queue for
5134 * the specified target device. Clear the 'tidmask' bit for the
5135 * device if no more commands are left queued for it.
5136 *
5137 * 'REQPNEXT(reqp)' returns reqp's the next pointer.
5138 *
5139 * Return ASC_TRUE if the command was found and removed,
5140 * otherwise return ASC_FALSE.
5141 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005142static int asc_rmqueue(asc_queue_t *ascq, REQP reqp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005143{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005144 REQP currp, prevp;
5145 int tid;
5146 int ret = ASC_FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005147
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005148 ASC_DBG2(3, "asc_rmqueue: ascq 0x%lx, reqp 0x%lx\n",
5149 (ulong)ascq, (ulong)reqp);
5150 ASC_ASSERT(reqp != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005151
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005152 tid = REQPTID(reqp);
5153 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005154
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005155 /*
5156 * Handle the common case of 'reqp' being the first
5157 * entry on the queue.
5158 */
5159 if (reqp == ascq->q_first[tid]) {
5160 ret = ASC_TRUE;
5161 ascq->q_first[tid] = REQPNEXT(reqp);
5162 /* If the queue is now empty, clear its bit and the last pointer. */
5163 if (ascq->q_first[tid] == NULL) {
5164 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
5165 ASC_ASSERT(ascq->q_last[tid] == reqp);
5166 ascq->q_last[tid] = NULL;
5167 }
5168 } else if (ascq->q_first[tid] != NULL) {
5169 ASC_ASSERT(ascq->q_last[tid] != NULL);
5170 /*
5171 * Because the case of 'reqp' being the first entry has been
5172 * handled above and it is known the queue is not empty, if
5173 * 'reqp' is found on the queue it is guaranteed the queue will
5174 * not become empty and that 'q_first[tid]' will not be changed.
5175 *
5176 * Set 'prevp' to the first entry, 'currp' to the second entry,
5177 * and search for 'reqp'.
5178 */
5179 for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp);
5180 currp; prevp = currp, currp = REQPNEXT(currp)) {
5181 if (currp == reqp) {
5182 ret = ASC_TRUE;
5183 prevp->host_scribble =
5184 (unsigned char *)REQPNEXT(currp);
5185 reqp->host_scribble = NULL;
5186 if (ascq->q_last[tid] == reqp) {
5187 ascq->q_last[tid] = prevp;
5188 }
5189 break;
5190 }
5191 }
5192 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005193#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005194 /* Maintain request queue statistics. */
5195 if (ret == ASC_TRUE) {
5196 ascq->q_cur_cnt[tid]--;
5197 REQTIMESTAT("asc_rmqueue", ascq, reqp, tid);
5198 }
5199 ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005200#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005201 ASC_DBG2(3, "asc_rmqueue: reqp 0x%lx, ret %d\n", (ulong)reqp, ret);
5202 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005203}
5204
5205/*
5206 * Execute as many queued requests as possible for the specified queue.
5207 *
5208 * Calls asc_execute_scsi_cmnd() to execute a REQP/struct scsi_cmnd.
5209 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005210static void asc_execute_queue(asc_queue_t *ascq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005211{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005212 ADV_SCSI_BIT_ID_TYPE scan_tidmask;
5213 REQP reqp;
5214 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005215
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005216 ASC_DBG1(1, "asc_execute_queue: ascq 0x%lx\n", (ulong)ascq);
5217 /*
5218 * Execute queued commands for devices attached to
5219 * the current board in round-robin fashion.
5220 */
5221 scan_tidmask = ascq->q_tidmask;
5222 do {
5223 for (i = 0; i <= ADV_MAX_TID; i++) {
5224 if (scan_tidmask & ADV_TID_TO_TIDMASK(i)) {
5225 if ((reqp = asc_dequeue(ascq, i)) == NULL) {
5226 scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
5227 } else
5228 if (asc_execute_scsi_cmnd
5229 ((struct scsi_cmnd *)reqp)
5230 == ASC_BUSY) {
5231 scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
5232 /*
5233 * The request returned ASC_BUSY. Enqueue at the front of
5234 * target's waiting list to maintain correct ordering.
5235 */
5236 asc_enqueue(ascq, reqp, ASC_FRONT);
5237 }
5238 }
5239 }
5240 } while (scan_tidmask);
5241 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005242}
5243
5244#ifdef CONFIG_PROC_FS
5245/*
5246 * asc_prt_board_devices()
5247 *
5248 * Print driver information for devices attached to the board.
5249 *
5250 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
5251 * cf. asc_prt_line().
5252 *
5253 * Return the number of characters copied into 'cp'. No more than
5254 * 'cplen' characters will be copied to 'cp'.
5255 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005256static int asc_prt_board_devices(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005257{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005258 asc_board_t *boardp;
5259 int leftlen;
5260 int totlen;
5261 int len;
5262 int chip_scsi_id;
5263 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005264
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005265 boardp = ASC_BOARDP(shost);
5266 leftlen = cplen;
5267 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005268
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005269 len = asc_prt_line(cp, leftlen,
5270 "\nDevice Information for AdvanSys SCSI Host %d:\n",
5271 shost->host_no);
5272 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005273
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005274 if (ASC_NARROW_BOARD(boardp)) {
5275 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
5276 } else {
5277 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
5278 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005279
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005280 len = asc_prt_line(cp, leftlen, "Target IDs Detected:");
5281 ASC_PRT_NEXT();
5282 for (i = 0; i <= ADV_MAX_TID; i++) {
5283 if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) {
5284 len = asc_prt_line(cp, leftlen, " %X,", i);
5285 ASC_PRT_NEXT();
5286 }
5287 }
5288 len = asc_prt_line(cp, leftlen, " (%X=Host Adapter)\n", chip_scsi_id);
5289 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005290
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005291 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005292}
5293
5294/*
5295 * Display Wide Board BIOS Information.
5296 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005297static int asc_prt_adv_bios(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005298{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005299 asc_board_t *boardp;
5300 int leftlen;
5301 int totlen;
5302 int len;
5303 ushort major, minor, letter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005304
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005305 boardp = ASC_BOARDP(shost);
5306 leftlen = cplen;
5307 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005308
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005309 len = asc_prt_line(cp, leftlen, "\nROM BIOS Version: ");
5310 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005311
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005312 /*
5313 * If the BIOS saved a valid signature, then fill in
5314 * the BIOS code segment base address.
5315 */
5316 if (boardp->bios_signature != 0x55AA) {
5317 len = asc_prt_line(cp, leftlen, "Disabled or Pre-3.1\n");
5318 ASC_PRT_NEXT();
5319 len = asc_prt_line(cp, leftlen,
5320 "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n");
5321 ASC_PRT_NEXT();
5322 len = asc_prt_line(cp, leftlen,
5323 "can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n");
5324 ASC_PRT_NEXT();
5325 } else {
5326 major = (boardp->bios_version >> 12) & 0xF;
5327 minor = (boardp->bios_version >> 8) & 0xF;
5328 letter = (boardp->bios_version & 0xFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005329
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005330 len = asc_prt_line(cp, leftlen, "%d.%d%c\n",
5331 major, minor,
5332 letter >= 26 ? '?' : letter + 'A');
5333 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005334
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005335 /*
5336 * Current available ROM BIOS release is 3.1I for UW
5337 * and 3.2I for U2W. This code doesn't differentiate
5338 * UW and U2W boards.
5339 */
5340 if (major < 3 || (major <= 3 && minor < 1) ||
5341 (major <= 3 && minor <= 1 && letter < ('I' - 'A'))) {
5342 len = asc_prt_line(cp, leftlen,
5343 "Newer version of ROM BIOS is available at the ConnectCom FTP site:\n");
5344 ASC_PRT_NEXT();
5345 len = asc_prt_line(cp, leftlen,
5346 "ftp://ftp.connectcom.net/pub\n");
5347 ASC_PRT_NEXT();
5348 }
5349 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005350
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005351 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005352}
5353
5354/*
5355 * Add serial number to information bar if signature AAh
5356 * is found in at bit 15-9 (7 bits) of word 1.
5357 *
5358 * Serial Number consists fo 12 alpha-numeric digits.
5359 *
5360 * 1 - Product type (A,B,C,D..) Word0: 15-13 (3 bits)
5361 * 2 - MFG Location (A,B,C,D..) Word0: 12-10 (3 bits)
5362 * 3-4 - Product ID (0-99) Word0: 9-0 (10 bits)
5363 * 5 - Product revision (A-J) Word0: " "
5364 *
5365 * Signature Word1: 15-9 (7 bits)
5366 * 6 - Year (0-9) Word1: 8-6 (3 bits) & Word2: 15 (1 bit)
5367 * 7-8 - Week of the year (1-52) Word1: 5-0 (6 bits)
5368 *
5369 * 9-12 - Serial Number (A001-Z999) Word2: 14-0 (15 bits)
5370 *
5371 * Note 1: Only production cards will have a serial number.
5372 *
5373 * Note 2: Signature is most significant 7 bits (0xFE).
5374 *
5375 * Returns ASC_TRUE if serial number found, otherwise returns ASC_FALSE.
5376 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005377static int asc_get_eeprom_string(ushort *serialnum, uchar *cp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005378{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005379 ushort w, num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005380
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005381 if ((serialnum[1] & 0xFE00) != ((ushort)0xAA << 8)) {
5382 return ASC_FALSE;
5383 } else {
5384 /*
5385 * First word - 6 digits.
5386 */
5387 w = serialnum[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07005388
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005389 /* Product type - 1st digit. */
5390 if ((*cp = 'A' + ((w & 0xE000) >> 13)) == 'H') {
5391 /* Product type is P=Prototype */
5392 *cp += 0x8;
5393 }
5394 cp++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005395
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005396 /* Manufacturing location - 2nd digit. */
5397 *cp++ = 'A' + ((w & 0x1C00) >> 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005398
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005399 /* Product ID - 3rd, 4th digits. */
5400 num = w & 0x3FF;
5401 *cp++ = '0' + (num / 100);
5402 num %= 100;
5403 *cp++ = '0' + (num / 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005404
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005405 /* Product revision - 5th digit. */
5406 *cp++ = 'A' + (num % 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005408 /*
5409 * Second word
5410 */
5411 w = serialnum[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07005412
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005413 /*
5414 * Year - 6th digit.
5415 *
5416 * If bit 15 of third word is set, then the
5417 * last digit of the year is greater than 7.
5418 */
5419 if (serialnum[2] & 0x8000) {
5420 *cp++ = '8' + ((w & 0x1C0) >> 6);
5421 } else {
5422 *cp++ = '0' + ((w & 0x1C0) >> 6);
5423 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005425 /* Week of year - 7th, 8th digits. */
5426 num = w & 0x003F;
5427 *cp++ = '0' + num / 10;
5428 num %= 10;
5429 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005430
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005431 /*
5432 * Third word
5433 */
5434 w = serialnum[2] & 0x7FFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005435
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005436 /* Serial number - 9th digit. */
5437 *cp++ = 'A' + (w / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005438
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005439 /* 10th, 11th, 12th digits. */
5440 num = w % 1000;
5441 *cp++ = '0' + num / 100;
5442 num %= 100;
5443 *cp++ = '0' + num / 10;
5444 num %= 10;
5445 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005446
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005447 *cp = '\0'; /* Null Terminate the string. */
5448 return ASC_TRUE;
5449 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005450}
5451
5452/*
5453 * asc_prt_asc_board_eeprom()
5454 *
5455 * Print board EEPROM configuration.
5456 *
5457 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
5458 * cf. asc_prt_line().
5459 *
5460 * Return the number of characters copied into 'cp'. No more than
5461 * 'cplen' characters will be copied to 'cp'.
5462 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005463static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005464{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005465 asc_board_t *boardp;
5466 ASC_DVC_VAR *asc_dvc_varp;
5467 int leftlen;
5468 int totlen;
5469 int len;
5470 ASCEEP_CONFIG *ep;
5471 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005472#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005473 int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07005474#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005475 uchar serialstr[13];
Linus Torvalds1da177e2005-04-16 15:20:36 -07005476
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005477 boardp = ASC_BOARDP(shost);
5478 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
5479 ep = &boardp->eep_config.asc_eep;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005480
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005481 leftlen = cplen;
5482 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005483
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005484 len = asc_prt_line(cp, leftlen,
5485 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
5486 shost->host_no);
5487 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005488
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005489 if (asc_get_eeprom_string((ushort *)&ep->adapter_info[0], serialstr)
5490 == ASC_TRUE) {
5491 len =
5492 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
5493 serialstr);
5494 ASC_PRT_NEXT();
5495 } else {
5496 if (ep->adapter_info[5] == 0xBB) {
5497 len = asc_prt_line(cp, leftlen,
5498 " Default Settings Used for EEPROM-less Adapter.\n");
5499 ASC_PRT_NEXT();
5500 } else {
5501 len = asc_prt_line(cp, leftlen,
5502 " Serial Number Signature Not Present.\n");
5503 ASC_PRT_NEXT();
5504 }
5505 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005506
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005507 len = asc_prt_line(cp, leftlen,
5508 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
5509 ASC_EEP_GET_CHIP_ID(ep), ep->max_total_qng,
5510 ep->max_tag_qng);
5511 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005512
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005513 len = asc_prt_line(cp, leftlen,
5514 " cntl 0x%x, no_scam 0x%x\n", ep->cntl, ep->no_scam);
5515 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005516
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005517 len = asc_prt_line(cp, leftlen, " Target ID: ");
5518 ASC_PRT_NEXT();
5519 for (i = 0; i <= ASC_MAX_TID; i++) {
5520 len = asc_prt_line(cp, leftlen, " %d", i);
5521 ASC_PRT_NEXT();
5522 }
5523 len = asc_prt_line(cp, leftlen, "\n");
5524 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005525
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005526 len = asc_prt_line(cp, leftlen, " Disconnects: ");
5527 ASC_PRT_NEXT();
5528 for (i = 0; i <= ASC_MAX_TID; i++) {
5529 len = asc_prt_line(cp, leftlen, " %c",
5530 (ep->
5531 disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
5532 'N');
5533 ASC_PRT_NEXT();
5534 }
5535 len = asc_prt_line(cp, leftlen, "\n");
5536 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005537
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005538 len = asc_prt_line(cp, leftlen, " Command Queuing: ");
5539 ASC_PRT_NEXT();
5540 for (i = 0; i <= ASC_MAX_TID; i++) {
5541 len = asc_prt_line(cp, leftlen, " %c",
5542 (ep->
5543 use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
5544 'N');
5545 ASC_PRT_NEXT();
5546 }
5547 len = asc_prt_line(cp, leftlen, "\n");
5548 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005550 len = asc_prt_line(cp, leftlen, " Start Motor: ");
5551 ASC_PRT_NEXT();
5552 for (i = 0; i <= ASC_MAX_TID; i++) {
5553 len = asc_prt_line(cp, leftlen, " %c",
5554 (ep->
5555 start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
5556 'N');
5557 ASC_PRT_NEXT();
5558 }
5559 len = asc_prt_line(cp, leftlen, "\n");
5560 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005561
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005562 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
5563 ASC_PRT_NEXT();
5564 for (i = 0; i <= ASC_MAX_TID; i++) {
5565 len = asc_prt_line(cp, leftlen, " %c",
5566 (ep->
5567 init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
5568 'N');
5569 ASC_PRT_NEXT();
5570 }
5571 len = asc_prt_line(cp, leftlen, "\n");
5572 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005573
5574#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005575 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
5576 len = asc_prt_line(cp, leftlen,
5577 " Host ISA DMA speed: %d MB/S\n",
5578 isa_dma_speed[ASC_EEP_GET_DMA_SPD(ep)]);
5579 ASC_PRT_NEXT();
5580 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005581#endif /* CONFIG_ISA */
5582
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005583 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005584}
5585
5586/*
5587 * asc_prt_adv_board_eeprom()
5588 *
5589 * Print board EEPROM configuration.
5590 *
5591 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
5592 * cf. asc_prt_line().
5593 *
5594 * Return the number of characters copied into 'cp'. No more than
5595 * 'cplen' characters will be copied to 'cp'.
5596 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005597static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005598{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005599 asc_board_t *boardp;
5600 ADV_DVC_VAR *adv_dvc_varp;
5601 int leftlen;
5602 int totlen;
5603 int len;
5604 int i;
5605 char *termstr;
5606 uchar serialstr[13];
5607 ADVEEP_3550_CONFIG *ep_3550 = NULL;
5608 ADVEEP_38C0800_CONFIG *ep_38C0800 = NULL;
5609 ADVEEP_38C1600_CONFIG *ep_38C1600 = NULL;
5610 ushort word;
5611 ushort *wordp;
5612 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005613
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005614 boardp = ASC_BOARDP(shost);
5615 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
5616 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
5617 ep_3550 = &boardp->eep_config.adv_3550_eep;
5618 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
5619 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
5620 } else {
5621 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
5622 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005623
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005624 leftlen = cplen;
5625 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005626
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005627 len = asc_prt_line(cp, leftlen,
5628 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
5629 shost->host_no);
5630 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005631
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005632 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
5633 wordp = &ep_3550->serial_number_word1;
5634 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
5635 wordp = &ep_38C0800->serial_number_word1;
5636 } else {
5637 wordp = &ep_38C1600->serial_number_word1;
5638 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005639
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005640 if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) {
5641 len =
5642 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
5643 serialstr);
5644 ASC_PRT_NEXT();
5645 } else {
5646 len = asc_prt_line(cp, leftlen,
5647 " Serial Number Signature Not Present.\n");
5648 ASC_PRT_NEXT();
5649 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005650
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005651 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
5652 len = asc_prt_line(cp, leftlen,
5653 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
5654 ep_3550->adapter_scsi_id,
5655 ep_3550->max_host_qng, ep_3550->max_dvc_qng);
5656 ASC_PRT_NEXT();
5657 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
5658 len = asc_prt_line(cp, leftlen,
5659 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
5660 ep_38C0800->adapter_scsi_id,
5661 ep_38C0800->max_host_qng,
5662 ep_38C0800->max_dvc_qng);
5663 ASC_PRT_NEXT();
5664 } else {
5665 len = asc_prt_line(cp, leftlen,
5666 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
5667 ep_38C1600->adapter_scsi_id,
5668 ep_38C1600->max_host_qng,
5669 ep_38C1600->max_dvc_qng);
5670 ASC_PRT_NEXT();
5671 }
5672 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
5673 word = ep_3550->termination;
5674 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
5675 word = ep_38C0800->termination_lvd;
5676 } else {
5677 word = ep_38C1600->termination_lvd;
5678 }
5679 switch (word) {
5680 case 1:
5681 termstr = "Low Off/High Off";
5682 break;
5683 case 2:
5684 termstr = "Low Off/High On";
5685 break;
5686 case 3:
5687 termstr = "Low On/High On";
5688 break;
5689 default:
5690 case 0:
5691 termstr = "Automatic";
5692 break;
5693 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005694
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005695 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
5696 len = asc_prt_line(cp, leftlen,
5697 " termination: %u (%s), bios_ctrl: 0x%x\n",
5698 ep_3550->termination, termstr,
5699 ep_3550->bios_ctrl);
5700 ASC_PRT_NEXT();
5701 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
5702 len = asc_prt_line(cp, leftlen,
5703 " termination: %u (%s), bios_ctrl: 0x%x\n",
5704 ep_38C0800->termination_lvd, termstr,
5705 ep_38C0800->bios_ctrl);
5706 ASC_PRT_NEXT();
5707 } else {
5708 len = asc_prt_line(cp, leftlen,
5709 " termination: %u (%s), bios_ctrl: 0x%x\n",
5710 ep_38C1600->termination_lvd, termstr,
5711 ep_38C1600->bios_ctrl);
5712 ASC_PRT_NEXT();
5713 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005714
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005715 len = asc_prt_line(cp, leftlen, " Target ID: ");
5716 ASC_PRT_NEXT();
5717 for (i = 0; i <= ADV_MAX_TID; i++) {
5718 len = asc_prt_line(cp, leftlen, " %X", i);
5719 ASC_PRT_NEXT();
5720 }
5721 len = asc_prt_line(cp, leftlen, "\n");
5722 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005723
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005724 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
5725 word = ep_3550->disc_enable;
5726 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
5727 word = ep_38C0800->disc_enable;
5728 } else {
5729 word = ep_38C1600->disc_enable;
5730 }
5731 len = asc_prt_line(cp, leftlen, " Disconnects: ");
5732 ASC_PRT_NEXT();
5733 for (i = 0; i <= ADV_MAX_TID; i++) {
5734 len = asc_prt_line(cp, leftlen, " %c",
5735 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
5736 ASC_PRT_NEXT();
5737 }
5738 len = asc_prt_line(cp, leftlen, "\n");
5739 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005740
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005741 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
5742 word = ep_3550->tagqng_able;
5743 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
5744 word = ep_38C0800->tagqng_able;
5745 } else {
5746 word = ep_38C1600->tagqng_able;
5747 }
5748 len = asc_prt_line(cp, leftlen, " Command Queuing: ");
5749 ASC_PRT_NEXT();
5750 for (i = 0; i <= ADV_MAX_TID; i++) {
5751 len = asc_prt_line(cp, leftlen, " %c",
5752 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
5753 ASC_PRT_NEXT();
5754 }
5755 len = asc_prt_line(cp, leftlen, "\n");
5756 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005757
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005758 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
5759 word = ep_3550->start_motor;
5760 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
5761 word = ep_38C0800->start_motor;
5762 } else {
5763 word = ep_38C1600->start_motor;
5764 }
5765 len = asc_prt_line(cp, leftlen, " Start Motor: ");
5766 ASC_PRT_NEXT();
5767 for (i = 0; i <= ADV_MAX_TID; i++) {
5768 len = asc_prt_line(cp, leftlen, " %c",
5769 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
5770 ASC_PRT_NEXT();
5771 }
5772 len = asc_prt_line(cp, leftlen, "\n");
5773 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005774
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005775 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
5776 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
5777 ASC_PRT_NEXT();
5778 for (i = 0; i <= ADV_MAX_TID; i++) {
5779 len = asc_prt_line(cp, leftlen, " %c",
5780 (ep_3550->
5781 sdtr_able & ADV_TID_TO_TIDMASK(i)) ?
5782 'Y' : 'N');
5783 ASC_PRT_NEXT();
5784 }
5785 len = asc_prt_line(cp, leftlen, "\n");
5786 ASC_PRT_NEXT();
5787 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005788
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005789 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
5790 len = asc_prt_line(cp, leftlen, " Ultra Transfer: ");
5791 ASC_PRT_NEXT();
5792 for (i = 0; i <= ADV_MAX_TID; i++) {
5793 len = asc_prt_line(cp, leftlen, " %c",
5794 (ep_3550->
5795 ultra_able & ADV_TID_TO_TIDMASK(i))
5796 ? 'Y' : 'N');
5797 ASC_PRT_NEXT();
5798 }
5799 len = asc_prt_line(cp, leftlen, "\n");
5800 ASC_PRT_NEXT();
5801 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005802
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005803 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
5804 word = ep_3550->wdtr_able;
5805 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
5806 word = ep_38C0800->wdtr_able;
5807 } else {
5808 word = ep_38C1600->wdtr_able;
5809 }
5810 len = asc_prt_line(cp, leftlen, " Wide Transfer: ");
5811 ASC_PRT_NEXT();
5812 for (i = 0; i <= ADV_MAX_TID; i++) {
5813 len = asc_prt_line(cp, leftlen, " %c",
5814 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
5815 ASC_PRT_NEXT();
5816 }
5817 len = asc_prt_line(cp, leftlen, "\n");
5818 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005819
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005820 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800 ||
5821 adv_dvc_varp->chip_type == ADV_CHIP_ASC38C1600) {
5822 len = asc_prt_line(cp, leftlen,
5823 " Synchronous Transfer Speed (Mhz):\n ");
5824 ASC_PRT_NEXT();
5825 for (i = 0; i <= ADV_MAX_TID; i++) {
5826 char *speed_str;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005827
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005828 if (i == 0) {
5829 sdtr_speed = adv_dvc_varp->sdtr_speed1;
5830 } else if (i == 4) {
5831 sdtr_speed = adv_dvc_varp->sdtr_speed2;
5832 } else if (i == 8) {
5833 sdtr_speed = adv_dvc_varp->sdtr_speed3;
5834 } else if (i == 12) {
5835 sdtr_speed = adv_dvc_varp->sdtr_speed4;
5836 }
5837 switch (sdtr_speed & ADV_MAX_TID) {
5838 case 0:
5839 speed_str = "Off";
5840 break;
5841 case 1:
5842 speed_str = " 5";
5843 break;
5844 case 2:
5845 speed_str = " 10";
5846 break;
5847 case 3:
5848 speed_str = " 20";
5849 break;
5850 case 4:
5851 speed_str = " 40";
5852 break;
5853 case 5:
5854 speed_str = " 80";
5855 break;
5856 default:
5857 speed_str = "Unk";
5858 break;
5859 }
5860 len = asc_prt_line(cp, leftlen, "%X:%s ", i, speed_str);
5861 ASC_PRT_NEXT();
5862 if (i == 7) {
5863 len = asc_prt_line(cp, leftlen, "\n ");
5864 ASC_PRT_NEXT();
5865 }
5866 sdtr_speed >>= 4;
5867 }
5868 len = asc_prt_line(cp, leftlen, "\n");
5869 ASC_PRT_NEXT();
5870 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005871
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005872 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005873}
5874
5875/*
5876 * asc_prt_driver_conf()
5877 *
5878 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
5879 * cf. asc_prt_line().
5880 *
5881 * Return the number of characters copied into 'cp'. No more than
5882 * 'cplen' characters will be copied to 'cp'.
5883 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005884static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005885{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005886 asc_board_t *boardp;
5887 int leftlen;
5888 int totlen;
5889 int len;
5890 int chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005891
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005892 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005893
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005894 leftlen = cplen;
5895 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005896
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005897 len = asc_prt_line(cp, leftlen,
5898 "\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n",
5899 shost->host_no);
5900 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005901
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005902 len = asc_prt_line(cp, leftlen,
5903 " host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n",
5904 shost->host_busy, shost->last_reset, shost->max_id,
5905 shost->max_lun, shost->max_channel);
5906 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005907
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005908 len = asc_prt_line(cp, leftlen,
5909 " unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
5910 shost->unique_id, shost->can_queue, shost->this_id,
5911 shost->sg_tablesize, shost->cmd_per_lun);
5912 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005913
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005914 len = asc_prt_line(cp, leftlen,
5915 " unchecked_isa_dma %d, use_clustering %d\n",
5916 shost->unchecked_isa_dma, shost->use_clustering);
5917 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005918
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005919 len = asc_prt_line(cp, leftlen,
5920 " flags 0x%x, last_reset 0x%x, jiffies 0x%x, asc_n_io_port 0x%x\n",
5921 boardp->flags, boardp->last_reset, jiffies,
5922 boardp->asc_n_io_port);
5923 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005924
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04005925 len = asc_prt_line(cp, leftlen, " io_port 0x%x\n", shost->io_port);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005926 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005927
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005928 if (ASC_NARROW_BOARD(boardp)) {
5929 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
5930 } else {
5931 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
5932 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005933
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005934 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005935}
5936
5937/*
5938 * asc_prt_asc_board_info()
5939 *
5940 * Print dynamic board configuration information.
5941 *
5942 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
5943 * cf. asc_prt_line().
5944 *
5945 * Return the number of characters copied into 'cp'. No more than
5946 * 'cplen' characters will be copied to 'cp'.
5947 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005948static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005949{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005950 asc_board_t *boardp;
5951 int chip_scsi_id;
5952 int leftlen;
5953 int totlen;
5954 int len;
5955 ASC_DVC_VAR *v;
5956 ASC_DVC_CFG *c;
5957 int i;
5958 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005959
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005960 boardp = ASC_BOARDP(shost);
5961 v = &boardp->dvc_var.asc_dvc_var;
5962 c = &boardp->dvc_cfg.asc_dvc_cfg;
5963 chip_scsi_id = c->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005964
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005965 leftlen = cplen;
5966 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005967
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005968 len = asc_prt_line(cp, leftlen,
5969 "\nAsc Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
5970 shost->host_no);
5971 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005972
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005973 len = asc_prt_line(cp, leftlen,
5974 " chip_version %u, lib_version 0x%x, lib_serial_no %u, mcode_date 0x%x\n",
5975 c->chip_version, c->lib_version, c->lib_serial_no,
5976 c->mcode_date);
5977 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005978
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005979 len = asc_prt_line(cp, leftlen,
5980 " mcode_version 0x%x, err_code %u\n",
5981 c->mcode_version, v->err_code);
5982 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005983
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005984 /* Current number of commands waiting for the host. */
5985 len = asc_prt_line(cp, leftlen,
5986 " Total Command Pending: %d\n", v->cur_total_qng);
5987 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005988
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005989 len = asc_prt_line(cp, leftlen, " Command Queuing:");
5990 ASC_PRT_NEXT();
5991 for (i = 0; i <= ASC_MAX_TID; i++) {
5992 if ((chip_scsi_id == i) ||
5993 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
5994 continue;
5995 }
5996 len = asc_prt_line(cp, leftlen, " %X:%c",
5997 i,
5998 (v->
5999 use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ?
6000 'Y' : 'N');
6001 ASC_PRT_NEXT();
6002 }
6003 len = asc_prt_line(cp, leftlen, "\n");
6004 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006005
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006006 /* Current number of commands waiting for a device. */
6007 len = asc_prt_line(cp, leftlen, " Command Queue Pending:");
6008 ASC_PRT_NEXT();
6009 for (i = 0; i <= ASC_MAX_TID; i++) {
6010 if ((chip_scsi_id == i) ||
6011 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6012 continue;
6013 }
6014 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->cur_dvc_qng[i]);
6015 ASC_PRT_NEXT();
6016 }
6017 len = asc_prt_line(cp, leftlen, "\n");
6018 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006019
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006020 /* Current limit on number of commands that can be sent to a device. */
6021 len = asc_prt_line(cp, leftlen, " Command Queue Limit:");
6022 ASC_PRT_NEXT();
6023 for (i = 0; i <= ASC_MAX_TID; i++) {
6024 if ((chip_scsi_id == i) ||
6025 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6026 continue;
6027 }
6028 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->max_dvc_qng[i]);
6029 ASC_PRT_NEXT();
6030 }
6031 len = asc_prt_line(cp, leftlen, "\n");
6032 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006033
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006034 /* Indicate whether the device has returned queue full status. */
6035 len = asc_prt_line(cp, leftlen, " Command Queue Full:");
6036 ASC_PRT_NEXT();
6037 for (i = 0; i <= ASC_MAX_TID; i++) {
6038 if ((chip_scsi_id == i) ||
6039 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6040 continue;
6041 }
6042 if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) {
6043 len = asc_prt_line(cp, leftlen, " %X:Y-%d",
6044 i, boardp->queue_full_cnt[i]);
6045 } else {
6046 len = asc_prt_line(cp, leftlen, " %X:N", i);
6047 }
6048 ASC_PRT_NEXT();
6049 }
6050 len = asc_prt_line(cp, leftlen, "\n");
6051 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006052
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006053 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6054 ASC_PRT_NEXT();
6055 for (i = 0; i <= ASC_MAX_TID; i++) {
6056 if ((chip_scsi_id == i) ||
6057 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6058 continue;
6059 }
6060 len = asc_prt_line(cp, leftlen, " %X:%c",
6061 i,
6062 (v->
6063 sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6064 'N');
6065 ASC_PRT_NEXT();
6066 }
6067 len = asc_prt_line(cp, leftlen, "\n");
6068 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006069
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006070 for (i = 0; i <= ASC_MAX_TID; i++) {
6071 uchar syn_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006072
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006073 if ((chip_scsi_id == i) ||
6074 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
6075 ((v->init_sdtr & ADV_TID_TO_TIDMASK(i)) == 0)) {
6076 continue;
6077 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006078
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006079 len = asc_prt_line(cp, leftlen, " %X:", i);
6080 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006081
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006082 if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0) {
6083 len = asc_prt_line(cp, leftlen, " Asynchronous");
6084 ASC_PRT_NEXT();
6085 } else {
6086 syn_period_ix =
6087 (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index -
6088 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006089
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006090 len = asc_prt_line(cp, leftlen,
6091 " Transfer Period Factor: %d (%d.%d Mhz),",
6092 v->sdtr_period_tbl[syn_period_ix],
6093 250 /
6094 v->sdtr_period_tbl[syn_period_ix],
6095 ASC_TENTHS(250,
6096 v->
6097 sdtr_period_tbl
6098 [syn_period_ix]));
6099 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006100
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006101 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
6102 boardp->
6103 sdtr_data[i] & ASC_SYN_MAX_OFFSET);
6104 ASC_PRT_NEXT();
6105 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006106
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006107 if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
6108 len = asc_prt_line(cp, leftlen, "*\n");
6109 renegotiate = 1;
6110 } else {
6111 len = asc_prt_line(cp, leftlen, "\n");
6112 }
6113 ASC_PRT_NEXT();
6114 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006115
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006116 if (renegotiate) {
6117 len = asc_prt_line(cp, leftlen,
6118 " * = Re-negotiation pending before next command.\n");
6119 ASC_PRT_NEXT();
6120 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006121
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006122 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006123}
6124
6125/*
6126 * asc_prt_adv_board_info()
6127 *
6128 * Print dynamic board configuration information.
6129 *
6130 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6131 * cf. asc_prt_line().
6132 *
6133 * Return the number of characters copied into 'cp'. No more than
6134 * 'cplen' characters will be copied to 'cp'.
6135 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006136static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006137{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006138 asc_board_t *boardp;
6139 int leftlen;
6140 int totlen;
6141 int len;
6142 int i;
6143 ADV_DVC_VAR *v;
6144 ADV_DVC_CFG *c;
6145 AdvPortAddr iop_base;
6146 ushort chip_scsi_id;
6147 ushort lramword;
6148 uchar lrambyte;
6149 ushort tagqng_able;
6150 ushort sdtr_able, wdtr_able;
6151 ushort wdtr_done, sdtr_done;
6152 ushort period = 0;
6153 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006154
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006155 boardp = ASC_BOARDP(shost);
6156 v = &boardp->dvc_var.adv_dvc_var;
6157 c = &boardp->dvc_cfg.adv_dvc_cfg;
6158 iop_base = v->iop_base;
6159 chip_scsi_id = v->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006160
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006161 leftlen = cplen;
6162 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006163
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006164 len = asc_prt_line(cp, leftlen,
6165 "\nAdv Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
6166 shost->host_no);
6167 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006168
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006169 len = asc_prt_line(cp, leftlen,
6170 " iop_base 0x%lx, cable_detect: %X, err_code %u\n",
6171 v->iop_base,
6172 AdvReadWordRegister(iop_base,
6173 IOPW_SCSI_CFG1) & CABLE_DETECT,
6174 v->err_code);
6175 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006176
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006177 len = asc_prt_line(cp, leftlen,
6178 " chip_version %u, lib_version 0x%x, mcode_date 0x%x, mcode_version 0x%x\n",
6179 c->chip_version, c->lib_version, c->mcode_date,
6180 c->mcode_version);
6181 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006182
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006183 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
6184 len = asc_prt_line(cp, leftlen, " Queuing Enabled:");
6185 ASC_PRT_NEXT();
6186 for (i = 0; i <= ADV_MAX_TID; i++) {
6187 if ((chip_scsi_id == i) ||
6188 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6189 continue;
6190 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006191
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006192 len = asc_prt_line(cp, leftlen, " %X:%c",
6193 i,
6194 (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6195 'N');
6196 ASC_PRT_NEXT();
6197 }
6198 len = asc_prt_line(cp, leftlen, "\n");
6199 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006200
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006201 len = asc_prt_line(cp, leftlen, " Queue Limit:");
6202 ASC_PRT_NEXT();
6203 for (i = 0; i <= ADV_MAX_TID; i++) {
6204 if ((chip_scsi_id == i) ||
6205 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6206 continue;
6207 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006208
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006209 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + i,
6210 lrambyte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006211
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006212 len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
6213 ASC_PRT_NEXT();
6214 }
6215 len = asc_prt_line(cp, leftlen, "\n");
6216 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006217
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006218 len = asc_prt_line(cp, leftlen, " Command Pending:");
6219 ASC_PRT_NEXT();
6220 for (i = 0; i <= ADV_MAX_TID; i++) {
6221 if ((chip_scsi_id == i) ||
6222 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6223 continue;
6224 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006225
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006226 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_QUEUED_CMD + i,
6227 lrambyte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006228
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006229 len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
6230 ASC_PRT_NEXT();
6231 }
6232 len = asc_prt_line(cp, leftlen, "\n");
6233 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006234
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006235 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
6236 len = asc_prt_line(cp, leftlen, " Wide Enabled:");
6237 ASC_PRT_NEXT();
6238 for (i = 0; i <= ADV_MAX_TID; i++) {
6239 if ((chip_scsi_id == i) ||
6240 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6241 continue;
6242 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006243
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006244 len = asc_prt_line(cp, leftlen, " %X:%c",
6245 i,
6246 (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6247 'N');
6248 ASC_PRT_NEXT();
6249 }
6250 len = asc_prt_line(cp, leftlen, "\n");
6251 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006252
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006253 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done);
6254 len = asc_prt_line(cp, leftlen, " Transfer Bit Width:");
6255 ASC_PRT_NEXT();
6256 for (i = 0; i <= ADV_MAX_TID; i++) {
6257 if ((chip_scsi_id == i) ||
6258 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6259 continue;
6260 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006261
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006262 AdvReadWordLram(iop_base,
6263 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
6264 lramword);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006265
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006266 len = asc_prt_line(cp, leftlen, " %X:%d",
6267 i, (lramword & 0x8000) ? 16 : 8);
6268 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006269
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006270 if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) &&
6271 (wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
6272 len = asc_prt_line(cp, leftlen, "*");
6273 ASC_PRT_NEXT();
6274 renegotiate = 1;
6275 }
6276 }
6277 len = asc_prt_line(cp, leftlen, "\n");
6278 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006279
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006280 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
6281 len = asc_prt_line(cp, leftlen, " Synchronous Enabled:");
6282 ASC_PRT_NEXT();
6283 for (i = 0; i <= ADV_MAX_TID; i++) {
6284 if ((chip_scsi_id == i) ||
6285 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6286 continue;
6287 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006288
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006289 len = asc_prt_line(cp, leftlen, " %X:%c",
6290 i,
6291 (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6292 'N');
6293 ASC_PRT_NEXT();
6294 }
6295 len = asc_prt_line(cp, leftlen, "\n");
6296 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006297
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006298 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done);
6299 for (i = 0; i <= ADV_MAX_TID; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006300
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006301 AdvReadWordLram(iop_base,
6302 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
6303 lramword);
6304 lramword &= ~0x8000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006305
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006306 if ((chip_scsi_id == i) ||
6307 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
6308 ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0)) {
6309 continue;
6310 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006311
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006312 len = asc_prt_line(cp, leftlen, " %X:", i);
6313 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006314
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006315 if ((lramword & 0x1F) == 0) { /* Check for REQ/ACK Offset 0. */
6316 len = asc_prt_line(cp, leftlen, " Asynchronous");
6317 ASC_PRT_NEXT();
6318 } else {
6319 len =
6320 asc_prt_line(cp, leftlen,
6321 " Transfer Period Factor: ");
6322 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006323
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006324 if ((lramword & 0x1F00) == 0x1100) { /* 80 Mhz */
6325 len =
6326 asc_prt_line(cp, leftlen, "9 (80.0 Mhz),");
6327 ASC_PRT_NEXT();
6328 } else if ((lramword & 0x1F00) == 0x1000) { /* 40 Mhz */
6329 len =
6330 asc_prt_line(cp, leftlen, "10 (40.0 Mhz),");
6331 ASC_PRT_NEXT();
6332 } else { /* 20 Mhz or below. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006333
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006334 period = (((lramword >> 8) * 25) + 50) / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006335
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006336 if (period == 0) { /* Should never happen. */
6337 len =
6338 asc_prt_line(cp, leftlen,
6339 "%d (? Mhz), ");
6340 ASC_PRT_NEXT();
6341 } else {
6342 len = asc_prt_line(cp, leftlen,
6343 "%d (%d.%d Mhz),",
6344 period, 250 / period,
6345 ASC_TENTHS(250,
6346 period));
6347 ASC_PRT_NEXT();
6348 }
6349 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006350
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006351 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
6352 lramword & 0x1F);
6353 ASC_PRT_NEXT();
6354 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006355
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006356 if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
6357 len = asc_prt_line(cp, leftlen, "*\n");
6358 renegotiate = 1;
6359 } else {
6360 len = asc_prt_line(cp, leftlen, "\n");
6361 }
6362 ASC_PRT_NEXT();
6363 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006364
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006365 if (renegotiate) {
6366 len = asc_prt_line(cp, leftlen,
6367 " * = Re-negotiation pending before next command.\n");
6368 ASC_PRT_NEXT();
6369 }
6370
6371 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006372}
6373
6374/*
6375 * asc_proc_copy()
6376 *
6377 * Copy proc information to a read buffer taking into account the current
6378 * read offset in the file and the remaining space in the read buffer.
6379 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006380static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07006381asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006382 char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006383{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006384 int cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006385
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006386 ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n",
6387 (unsigned)offset, (unsigned)advoffset, cplen);
6388 if (offset <= advoffset) {
6389 /* Read offset below current offset, copy everything. */
6390 cnt = min(cplen, leftlen);
6391 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
6392 (ulong)curbuf, (ulong)cp, cnt);
6393 memcpy(curbuf, cp, cnt);
6394 } else if (offset < advoffset + cplen) {
6395 /* Read offset within current range, partial copy. */
6396 cnt = (advoffset + cplen) - offset;
6397 cp = (cp + cplen) - cnt;
6398 cnt = min(cnt, leftlen);
6399 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
6400 (ulong)curbuf, (ulong)cp, cnt);
6401 memcpy(curbuf, cp, cnt);
6402 }
6403 return cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006404}
6405
6406/*
6407 * asc_prt_line()
6408 *
6409 * If 'cp' is NULL print to the console, otherwise print to a buffer.
6410 *
6411 * Return 0 if printing to the console, otherwise return the number of
6412 * bytes written to the buffer.
6413 *
6414 * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack
6415 * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes.
6416 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006417static int asc_prt_line(char *buf, int buflen, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006418{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006419 va_list args;
6420 int ret;
6421 char s[ASC_PRTLINE_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006422
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006423 va_start(args, fmt);
6424 ret = vsprintf(s, fmt, args);
6425 ASC_ASSERT(ret < ASC_PRTLINE_SIZE);
6426 if (buf == NULL) {
6427 (void)printk(s);
6428 ret = 0;
6429 } else {
6430 ret = min(buflen, ret);
6431 memcpy(buf, s, ret);
6432 }
6433 va_end(args);
6434 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006435}
6436#endif /* CONFIG_PROC_FS */
6437
Linus Torvalds1da177e2005-04-16 15:20:36 -07006438/*
6439 * --- Functions Required by the Asc Library
6440 */
6441
6442/*
6443 * Delay for 'n' milliseconds. Don't use the 'jiffies'
6444 * global variable which is incremented once every 5 ms
6445 * from a timer interrupt, because this function may be
6446 * called when interrupts are disabled.
6447 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006448static void DvcSleepMilliSecond(ADV_DCNT n)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006449{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006450 ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", (ulong)n);
6451 mdelay(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006452}
6453
6454/*
6455 * Currently and inline noop but leave as a placeholder.
6456 * Leave DvcEnterCritical() as a noop placeholder.
6457 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006458static inline ulong DvcEnterCritical(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006459{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006460 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006461}
6462
6463/*
6464 * Critical sections are all protected by the board spinlock.
6465 * Leave DvcLeaveCritical() as a noop placeholder.
6466 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006467static inline void DvcLeaveCritical(ulong flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006468{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006469 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006470}
6471
6472/*
6473 * void
6474 * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
6475 *
6476 * Calling/Exit State:
6477 * none
6478 *
6479 * Description:
6480 * Output an ASC_SCSI_Q structure to the chip
6481 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006482static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07006483DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
6484{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006485 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006486
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006487 ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words);
6488 AscSetChipLramAddr(iop_base, s_addr);
6489 for (i = 0; i < 2 * words; i += 2) {
6490 if (i == 4 || i == 20) {
6491 continue;
6492 }
6493 outpw(iop_base + IOP_RAM_DATA,
6494 ((ushort)outbuf[i + 1] << 8) | outbuf[i]);
6495 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006496}
6497
6498/*
6499 * void
6500 * DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
6501 *
6502 * Calling/Exit State:
6503 * none
6504 *
6505 * Description:
6506 * Input an ASC_QDONE_INFO structure from the chip
6507 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006508static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07006509DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
6510{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006511 int i;
6512 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006513
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006514 AscSetChipLramAddr(iop_base, s_addr);
6515 for (i = 0; i < 2 * words; i += 2) {
6516 if (i == 10) {
6517 continue;
6518 }
6519 word = inpw(iop_base + IOP_RAM_DATA);
6520 inbuf[i] = word & 0xff;
6521 inbuf[i + 1] = (word >> 8) & 0xff;
6522 }
6523 ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006524}
6525
6526/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07006527 * Return the BIOS address of the adapter at the specified
6528 * I/O port and with the specified bus type.
6529 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006530static unsigned short __devinit
6531AscGetChipBiosAddress(PortAddr iop_base, unsigned short bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006532{
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006533 unsigned short cfg_lsw;
6534 unsigned short bios_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006535
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006536 /*
6537 * The PCI BIOS is re-located by the motherboard BIOS. Because
6538 * of this the driver can not determine where a PCI BIOS is
6539 * loaded and executes.
6540 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006541 if (bus_type & ASC_IS_PCI)
6542 return 0;
6543
Linus Torvalds1da177e2005-04-16 15:20:36 -07006544#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006545 if ((bus_type & ASC_IS_EISA) != 0) {
6546 cfg_lsw = AscGetEisaChipCfg(iop_base);
6547 cfg_lsw &= 0x000F;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006548 bios_addr = ASC_BIOS_MIN_ADDR + cfg_lsw * ASC_BIOS_BANK_SIZE;
6549 return bios_addr;
6550 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006551#endif /* CONFIG_ISA */
6552
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006553 cfg_lsw = AscGetChipCfgLsw(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006554
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006555 /*
6556 * ISA PnP uses the top bit as the 32K BIOS flag
6557 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006558 if (bus_type == ASC_IS_ISAPNP)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006559 cfg_lsw &= 0x7FFF;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006560 bios_addr = ASC_BIOS_MIN_ADDR + (cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE;
6561 return bios_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006562}
6563
Linus Torvalds1da177e2005-04-16 15:20:36 -07006564/*
6565 * --- Functions Required by the Adv Library
6566 */
6567
6568/*
6569 * DvcGetPhyAddr()
6570 *
6571 * Return the physical address of 'vaddr' and set '*lenp' to the
6572 * number of physically contiguous bytes that follow 'vaddr'.
6573 * 'flag' indicates the type of structure whose physical address
6574 * is being translated.
6575 *
6576 * Note: Because Linux currently doesn't page the kernel and all
6577 * kernel buffers are physically contiguous, leave '*lenp' unchanged.
6578 */
6579ADV_PADDR
6580DvcGetPhyAddr(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006581 uchar *vaddr, ADV_SDCNT *lenp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006582{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006583 ADV_PADDR paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006584
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006585 paddr = virt_to_bus(vaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006586
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006587 ASC_DBG4(4,
6588 "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n",
6589 (ulong)vaddr, (ulong)lenp, (ulong)*((ulong *)lenp),
6590 (ulong)paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006591
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006592 return paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006593}
6594
6595/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07006596 * --- Tracing and Debugging Functions
6597 */
6598
6599#ifdef ADVANSYS_STATS
6600#ifdef CONFIG_PROC_FS
6601/*
6602 * asc_prt_board_stats()
6603 *
6604 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6605 * cf. asc_prt_line().
6606 *
6607 * Return the number of characters copied into 'cp'. No more than
6608 * 'cplen' characters will be copied to 'cp'.
6609 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006610static int asc_prt_board_stats(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006611{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006612 int leftlen;
6613 int totlen;
6614 int len;
6615 struct asc_stats *s;
6616 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006617
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006618 leftlen = cplen;
6619 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006620
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006621 boardp = ASC_BOARDP(shost);
6622 s = &boardp->asc_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006623
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006624 len = asc_prt_line(cp, leftlen,
6625 "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n",
6626 shost->host_no);
6627 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006628
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006629 len = asc_prt_line(cp, leftlen,
6630 " queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n",
6631 s->queuecommand, s->reset, s->biosparam,
6632 s->interrupt);
6633 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006634
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006635 len = asc_prt_line(cp, leftlen,
6636 " callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n",
6637 s->callback, s->done, s->build_error,
6638 s->adv_build_noreq, s->adv_build_nosg);
6639 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006640
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006641 len = asc_prt_line(cp, leftlen,
6642 " exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n",
6643 s->exe_noerror, s->exe_busy, s->exe_error,
6644 s->exe_unknown);
6645 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006646
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006647 /*
6648 * Display data transfer statistics.
6649 */
6650 if (s->cont_cnt > 0) {
6651 len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt);
6652 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006653
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006654 len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ",
6655 s->cont_xfer / 2,
6656 ASC_TENTHS(s->cont_xfer, 2));
6657 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006658
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006659 /* Contiguous transfer average size */
6660 len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kb\n",
6661 (s->cont_xfer / 2) / s->cont_cnt,
6662 ASC_TENTHS((s->cont_xfer / 2), s->cont_cnt));
6663 ASC_PRT_NEXT();
6664 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006665
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006666 if (s->sg_cnt > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006667
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006668 len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ",
6669 s->sg_cnt, s->sg_elem);
6670 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006671
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006672 len = asc_prt_line(cp, leftlen, "sg_xfer %lu.%01lu kb\n",
6673 s->sg_xfer / 2, ASC_TENTHS(s->sg_xfer, 2));
6674 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006675
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006676 /* Scatter gather transfer statistics */
6677 len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ",
6678 s->sg_elem / s->sg_cnt,
6679 ASC_TENTHS(s->sg_elem, s->sg_cnt));
6680 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006681
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006682 len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ",
6683 (s->sg_xfer / 2) / s->sg_elem,
6684 ASC_TENTHS((s->sg_xfer / 2), s->sg_elem));
6685 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006686
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006687 len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n",
6688 (s->sg_xfer / 2) / s->sg_cnt,
6689 ASC_TENTHS((s->sg_xfer / 2), s->sg_cnt));
6690 ASC_PRT_NEXT();
6691 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006692
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006693 /*
6694 * Display request queuing statistics.
6695 */
6696 len = asc_prt_line(cp, leftlen,
6697 " Active and Waiting Request Queues (Time Unit: %d HZ):\n",
6698 HZ);
6699 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006700
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006701 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006702}
6703
6704/*
6705 * asc_prt_target_stats()
6706 *
6707 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6708 * cf. asc_prt_line().
6709 *
6710 * This is separated from asc_prt_board_stats because a full set
6711 * of targets will overflow ASC_PRTBUF_SIZE.
6712 *
6713 * Return the number of characters copied into 'cp'. No more than
6714 * 'cplen' characters will be copied to 'cp'.
6715 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006716static int
6717asc_prt_target_stats(struct Scsi_Host *shost, int tgt_id, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006718{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006719 int leftlen;
6720 int totlen;
6721 int len;
6722 struct asc_stats *s;
6723 ushort chip_scsi_id;
6724 asc_board_t *boardp;
6725 asc_queue_t *active;
6726 asc_queue_t *waiting;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006727
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006728 leftlen = cplen;
6729 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006730
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006731 boardp = ASC_BOARDP(shost);
6732 s = &boardp->asc_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006733
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006734 active = &ASC_BOARDP(shost)->active;
6735 waiting = &ASC_BOARDP(shost)->waiting;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006736
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006737 if (ASC_NARROW_BOARD(boardp)) {
6738 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
6739 } else {
6740 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
6741 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006742
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006743 if ((chip_scsi_id == tgt_id) ||
6744 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(tgt_id)) == 0)) {
6745 return 0;
6746 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006747
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006748 do {
6749 if (active->q_tot_cnt[tgt_id] > 0
6750 || waiting->q_tot_cnt[tgt_id] > 0) {
6751 len = asc_prt_line(cp, leftlen, " target %d\n", tgt_id);
6752 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006753
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006754 len = asc_prt_line(cp, leftlen,
6755 " active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n",
6756 active->q_cur_cnt[tgt_id],
6757 active->q_max_cnt[tgt_id],
6758 active->q_tot_cnt[tgt_id],
6759 active->q_min_tim[tgt_id],
6760 active->q_max_tim[tgt_id],
6761 (active->q_tot_cnt[tgt_id] ==
6762 0) ? 0 : (active->
6763 q_tot_tim[tgt_id] /
6764 active->
6765 q_tot_cnt[tgt_id]),
6766 (active->q_tot_cnt[tgt_id] ==
6767 0) ? 0 : ASC_TENTHS(active->
6768 q_tot_tim
6769 [tgt_id],
6770 active->
6771 q_tot_cnt
6772 [tgt_id]));
6773 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006774
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006775 len = asc_prt_line(cp, leftlen,
6776 " waiting: cnt [cur %d, max %d, tot %u], time [min %u, max %u, avg %lu.%01lu]\n",
6777 waiting->q_cur_cnt[tgt_id],
6778 waiting->q_max_cnt[tgt_id],
6779 waiting->q_tot_cnt[tgt_id],
6780 waiting->q_min_tim[tgt_id],
6781 waiting->q_max_tim[tgt_id],
6782 (waiting->q_tot_cnt[tgt_id] ==
6783 0) ? 0 : (waiting->
6784 q_tot_tim[tgt_id] /
6785 waiting->
6786 q_tot_cnt[tgt_id]),
6787 (waiting->q_tot_cnt[tgt_id] ==
6788 0) ? 0 : ASC_TENTHS(waiting->
6789 q_tot_tim
6790 [tgt_id],
6791 waiting->
6792 q_tot_cnt
6793 [tgt_id]));
6794 ASC_PRT_NEXT();
6795 }
6796 } while (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006797
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006798 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006799}
6800#endif /* CONFIG_PROC_FS */
6801#endif /* ADVANSYS_STATS */
6802
6803#ifdef ADVANSYS_DEBUG
6804/*
6805 * asc_prt_scsi_host()
6806 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006807static void asc_prt_scsi_host(struct Scsi_Host *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006808{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006809 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006810
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006811 boardp = ASC_BOARDP(s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006812
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006813 printk("Scsi_Host at addr 0x%lx\n", (ulong)s);
6814 printk(" host_busy %u, host_no %d, last_reset %d,\n",
6815 s->host_busy, s->host_no, (unsigned)s->last_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006816
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04006817 printk(" base 0x%lx, io_port 0x%lx, irq 0x%x,\n",
6818 (ulong)s->base, (ulong)s->io_port, s->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006819
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006820 printk(" dma_channel %d, this_id %d, can_queue %d,\n",
6821 s->dma_channel, s->this_id, s->can_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006822
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006823 printk(" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
6824 s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006825
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006826 if (ASC_NARROW_BOARD(boardp)) {
6827 asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var);
6828 asc_prt_asc_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.asc_dvc_cfg);
6829 } else {
6830 asc_prt_adv_dvc_var(&ASC_BOARDP(s)->dvc_var.adv_dvc_var);
6831 asc_prt_adv_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.adv_dvc_cfg);
6832 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006833}
6834
6835/*
6836 * asc_prt_scsi_cmnd()
6837 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006838static void asc_prt_scsi_cmnd(struct scsi_cmnd *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006839{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006840 printk("struct scsi_cmnd at addr 0x%lx\n", (ulong)s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006841
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006842 printk(" host 0x%lx, device 0x%lx, target %u, lun %u, channel %u,\n",
6843 (ulong)s->device->host, (ulong)s->device, s->device->id,
6844 s->device->lun, s->device->channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006845
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006846 asc_prt_hex(" CDB", s->cmnd, s->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006847
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006848 printk("sc_data_direction %u, resid %d\n",
6849 s->sc_data_direction, s->resid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006850
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006851 printk(" use_sg %u, sglist_len %u\n", s->use_sg, s->sglist_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006852
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006853 printk(" serial_number 0x%x, retries %d, allowed %d\n",
6854 (unsigned)s->serial_number, s->retries, s->allowed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006855
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006856 printk(" timeout_per_command %d\n", s->timeout_per_command);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006857
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006858 printk(" scsi_done 0x%p, done 0x%p, host_scribble 0x%p, result 0x%x\n",
6859 s->scsi_done, s->done, s->host_scribble, s->result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006860
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006861 printk(" tag %u, pid %u\n", (unsigned)s->tag, (unsigned)s->pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006862}
6863
6864/*
6865 * asc_prt_asc_dvc_var()
6866 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006867static void asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006868{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006869 printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006870
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006871 printk(" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl "
6872 "%d,\n", h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006873
Matthew Wilcox895d6b42007-07-26 11:57:06 -04006874 printk(" bus_type %d, init_sdtr 0x%x,\n", h->bus_type,
6875 (unsigned)h->init_sdtr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006876
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006877 printk(" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, "
6878 "chip_no 0x%x,\n", (unsigned)h->sdtr_done,
6879 (unsigned)h->use_tagged_qng, (unsigned)h->unit_not_ready,
6880 (unsigned)h->chip_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006881
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006882 printk(" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait "
6883 "%u,\n", (unsigned)h->queue_full_or_busy,
6884 (unsigned)h->start_motor, (unsigned)h->scsi_reset_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006885
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006886 printk(" is_in_int %u, max_total_qng %u, cur_total_qng %u, "
6887 "in_critical_cnt %u,\n", (unsigned)h->is_in_int,
6888 (unsigned)h->max_total_qng, (unsigned)h->cur_total_qng,
6889 (unsigned)h->in_critical_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006890
Matthew Wilcoxecec1942007-07-30 08:08:22 -06006891 printk(" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, "
6892 "pci_fix_asyn_xfer 0x%x,\n", (unsigned)h->last_q_shortage,
6893 (unsigned)h->init_state, (unsigned)h->no_scam,
6894 (unsigned)h->pci_fix_asyn_xfer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006895
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006896 printk(" cfg 0x%lx, irq_no 0x%x\n", (ulong)h->cfg, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006897}
6898
6899/*
6900 * asc_prt_asc_dvc_cfg()
6901 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006902static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006903{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006904 printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006905
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006906 printk(" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n",
6907 h->can_tagged_qng, h->cmd_qng_enabled);
6908 printk(" disc_enable 0x%x, sdtr_enable 0x%x,\n",
6909 h->disc_enable, h->sdtr_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006910
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006911 printk
6912 (" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n",
6913 h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel,
6914 h->chip_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006915
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006916 printk
6917 (" pci_device_id %d, lib_serial_no %u, lib_version %u, mcode_date 0x%x,\n",
6918 to_pci_dev(h->dev)->device, h->lib_serial_no, h->lib_version,
6919 h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006920
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006921 printk(" mcode_version %d, overrun_buf 0x%lx\n",
6922 h->mcode_version, (ulong)h->overrun_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006923}
6924
6925/*
6926 * asc_prt_asc_scsi_q()
6927 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006928static void asc_prt_asc_scsi_q(ASC_SCSI_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006929{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006930 ASC_SG_HEAD *sgp;
6931 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006932
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006933 printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006934
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006935 printk
6936 (" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n",
6937 q->q2.target_ix, q->q1.target_lun, (ulong)q->q2.srb_ptr,
6938 q->q2.tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006939
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006940 printk
6941 (" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
6942 (ulong)le32_to_cpu(q->q1.data_addr),
6943 (ulong)le32_to_cpu(q->q1.data_cnt),
6944 (ulong)le32_to_cpu(q->q1.sense_addr), q->q1.sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006945
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006946 printk(" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n",
6947 (ulong)q->cdbptr, q->q2.cdb_len,
6948 (ulong)q->sg_head, q->q1.sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006949
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006950 if (q->sg_head) {
6951 sgp = q->sg_head;
6952 printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong)sgp);
6953 printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt,
6954 sgp->queue_cnt);
6955 for (i = 0; i < sgp->entry_cnt; i++) {
6956 printk(" [%u]: addr 0x%lx, bytes %lu\n",
6957 i, (ulong)le32_to_cpu(sgp->sg_list[i].addr),
6958 (ulong)le32_to_cpu(sgp->sg_list[i].bytes));
6959 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006960
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006961 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006962}
6963
6964/*
6965 * asc_prt_asc_qdone_info()
6966 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006967static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006968{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006969 printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong)q);
6970 printk(" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n",
6971 (ulong)q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
6972 q->d2.tag_code);
6973 printk
6974 (" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n",
6975 q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006976}
6977
6978/*
6979 * asc_prt_adv_dvc_var()
6980 *
6981 * Display an ADV_DVC_VAR structure.
6982 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006983static void asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006984{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006985 printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006986
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006987 printk(" iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n",
6988 (ulong)h->iop_base, h->err_code, (unsigned)h->ultra_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006989
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006990 printk(" isr_callback 0x%lx, sdtr_able 0x%x, wdtr_able 0x%x\n",
6991 (ulong)h->isr_callback, (unsigned)h->sdtr_able,
6992 (unsigned)h->wdtr_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006993
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006994 printk(" start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n",
6995 (unsigned)h->start_motor,
6996 (unsigned)h->scsi_reset_wait, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006997
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006998 printk(" max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n",
6999 (unsigned)h->max_host_qng, (unsigned)h->max_dvc_qng,
7000 (ulong)h->carr_freelist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007001
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007002 printk(" icq_sp 0x%lx, irq_sp 0x%lx\n",
7003 (ulong)h->icq_sp, (ulong)h->irq_sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007004
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007005 printk(" no_scam 0x%x, tagqng_able 0x%x\n",
7006 (unsigned)h->no_scam, (unsigned)h->tagqng_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007007
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007008 printk(" chip_scsi_id 0x%x, cfg 0x%lx\n",
7009 (unsigned)h->chip_scsi_id, (ulong)h->cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007010}
7011
7012/*
7013 * asc_prt_adv_dvc_cfg()
7014 *
7015 * Display an ADV_DVC_CFG structure.
7016 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007017static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007018{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007019 printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007020
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007021 printk(" disc_enable 0x%x, termination 0x%x\n",
7022 h->disc_enable, h->termination);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007023
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007024 printk(" chip_version 0x%x, mcode_date 0x%x\n",
7025 h->chip_version, h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007026
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007027 printk(" mcode_version 0x%x, pci_device_id 0x%x, lib_version %u\n",
7028 h->mcode_version, to_pci_dev(h->dev)->device, h->lib_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007029
Matthew Wilcox13ac2d92007-07-30 08:10:23 -06007030 printk(" control_flag 0x%x\n", h->control_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007031}
7032
7033/*
7034 * asc_prt_adv_scsi_req_q()
7035 *
7036 * Display an ADV_SCSI_REQ_Q structure.
7037 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007038static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007039{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007040 int sg_blk_cnt;
7041 struct asc_sg_block *sg_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007042
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007043 printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007044
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007045 printk(" target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n",
7046 q->target_id, q->target_lun, (ulong)q->srb_ptr, q->a_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007047
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007048 printk(" cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
7049 q->cntl, (ulong)le32_to_cpu(q->data_addr), (ulong)q->vdata_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007050
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007051 printk(" data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
7052 (ulong)le32_to_cpu(q->data_cnt),
7053 (ulong)le32_to_cpu(q->sense_addr), q->sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007054
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007055 printk
7056 (" cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n",
7057 q->cdb_len, q->done_status, q->host_status, q->scsi_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007058
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007059 printk(" sg_working_ix 0x%x, target_cmd %u\n",
7060 q->sg_working_ix, q->target_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007061
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007062 printk(" scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n",
7063 (ulong)le32_to_cpu(q->scsiq_rptr),
7064 (ulong)le32_to_cpu(q->sg_real_addr), (ulong)q->sg_list_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007065
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007066 /* Display the request's ADV_SG_BLOCK structures. */
7067 if (q->sg_list_ptr != NULL) {
7068 sg_blk_cnt = 0;
7069 while (1) {
7070 /*
7071 * 'sg_ptr' is a physical address. Convert it to a virtual
7072 * address by indexing 'sg_blk_cnt' into the virtual address
7073 * array 'sg_list_ptr'.
7074 *
7075 * XXX - Assumes all SG physical blocks are virtually contiguous.
7076 */
7077 sg_ptr =
7078 &(((ADV_SG_BLOCK *)(q->sg_list_ptr))[sg_blk_cnt]);
7079 asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr);
7080 if (sg_ptr->sg_ptr == 0) {
7081 break;
7082 }
7083 sg_blk_cnt++;
7084 }
7085 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007086}
7087
7088/*
7089 * asc_prt_adv_sgblock()
7090 *
7091 * Display an ADV_SG_BLOCK structure.
7092 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007093static void asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007094{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007095 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007096
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007097 printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n",
7098 (ulong)b, sgblockno);
7099 printk(" sg_cnt %u, sg_ptr 0x%lx\n",
7100 b->sg_cnt, (ulong)le32_to_cpu(b->sg_ptr));
7101 ASC_ASSERT(b->sg_cnt <= NO_OF_SG_PER_BLOCK);
7102 if (b->sg_ptr != 0) {
7103 ASC_ASSERT(b->sg_cnt == NO_OF_SG_PER_BLOCK);
7104 }
7105 for (i = 0; i < b->sg_cnt; i++) {
7106 printk(" [%u]: sg_addr 0x%lx, sg_count 0x%lx\n",
7107 i, (ulong)b->sg_list[i].sg_addr,
7108 (ulong)b->sg_list[i].sg_count);
7109 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007110}
7111
7112/*
7113 * asc_prt_hex()
7114 *
7115 * Print hexadecimal output in 4 byte groupings 32 bytes
7116 * or 8 double-words per line.
7117 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007118static void asc_prt_hex(char *f, uchar *s, int l)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007119{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007120 int i;
7121 int j;
7122 int k;
7123 int m;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007124
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007125 printk("%s: (%d bytes)\n", f, l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007126
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007127 for (i = 0; i < l; i += 32) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007128
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007129 /* Display a maximum of 8 double-words per line. */
7130 if ((k = (l - i) / 4) >= 8) {
7131 k = 8;
7132 m = 0;
7133 } else {
7134 m = (l - i) % 4;
7135 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007136
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007137 for (j = 0; j < k; j++) {
7138 printk(" %2.2X%2.2X%2.2X%2.2X",
7139 (unsigned)s[i + (j * 4)],
7140 (unsigned)s[i + (j * 4) + 1],
7141 (unsigned)s[i + (j * 4) + 2],
7142 (unsigned)s[i + (j * 4) + 3]);
7143 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007144
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007145 switch (m) {
7146 case 0:
7147 default:
7148 break;
7149 case 1:
7150 printk(" %2.2X", (unsigned)s[i + (j * 4)]);
7151 break;
7152 case 2:
7153 printk(" %2.2X%2.2X",
7154 (unsigned)s[i + (j * 4)],
7155 (unsigned)s[i + (j * 4) + 1]);
7156 break;
7157 case 3:
7158 printk(" %2.2X%2.2X%2.2X",
7159 (unsigned)s[i + (j * 4) + 1],
7160 (unsigned)s[i + (j * 4) + 2],
7161 (unsigned)s[i + (j * 4) + 3]);
7162 break;
7163 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007164
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007165 printk("\n");
7166 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007167}
7168#endif /* ADVANSYS_DEBUG */
7169
7170/*
7171 * --- Asc Library Functions
7172 */
7173
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007174static ushort __devinit AscGetEisaChipCfg(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007175{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007176 PortAddr eisa_cfg_iop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007177
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007178 eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
7179 (PortAddr) (ASC_EISA_CFG_IOP_MASK);
7180 return (inpw(eisa_cfg_iop));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007181}
7182
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007183static uchar __devinit AscSetChipScsiID(PortAddr iop_base, uchar new_host_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007184{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007185 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007186
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007187 if (AscGetChipScsiID(iop_base) == new_host_id) {
7188 return (new_host_id);
7189 }
7190 cfg_lsw = AscGetChipCfgLsw(iop_base);
7191 cfg_lsw &= 0xF8FF;
7192 cfg_lsw |= (ushort)((new_host_id & ASC_MAX_TID) << 8);
7193 AscSetChipCfgLsw(iop_base, cfg_lsw);
7194 return (AscGetChipScsiID(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007195}
7196
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007197static unsigned char __devinit AscGetChipScsiCtrl(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007198{
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007199 unsigned char sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007200
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007201 AscSetBank(iop_base, 1);
7202 sc = inp(iop_base + IOP_REG_SC);
7203 AscSetBank(iop_base, 0);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007204 return sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007205}
7206
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007207static unsigned char __devinit
7208AscGetChipVersion(PortAddr iop_base, unsigned short bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007209{
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007210 if (bus_type & ASC_IS_EISA) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007211 PortAddr eisa_iop;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007212 unsigned char revision;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007213 eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
7214 (PortAddr) ASC_EISA_REV_IOP_MASK;
7215 revision = inp(eisa_iop);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007216 return ASC_CHIP_MIN_VER_EISA - 1 + revision;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007217 }
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007218 return AscGetChipVerNo(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007219}
7220
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007221static ASC_DCNT
7222AscLoadMicroCode(PortAddr iop_base,
7223 ushort s_addr, uchar *mcode_buf, ushort mcode_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007224{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007225 ASC_DCNT chksum;
7226 ushort mcode_word_size;
7227 ushort mcode_chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007228
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007229 /* Write the microcode buffer starting at LRAM address 0. */
7230 mcode_word_size = (ushort)(mcode_size >> 1);
7231 AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
7232 AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007233
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007234 chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size);
7235 ASC_DBG1(1, "AscLoadMicroCode: chksum 0x%lx\n", (ulong)chksum);
7236 mcode_chksum = (ushort)AscMemSumLramWord(iop_base,
7237 (ushort)ASC_CODE_SEC_BEG,
7238 (ushort)((mcode_size -
7239 s_addr - (ushort)
7240 ASC_CODE_SEC_BEG) /
7241 2));
7242 ASC_DBG1(1, "AscLoadMicroCode: mcode_chksum 0x%lx\n",
7243 (ulong)mcode_chksum);
7244 AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum);
7245 AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size);
7246 return (chksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007247}
7248
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007249static int AscFindSignature(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007250{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007251 ushort sig_word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007252
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007253 ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureByte(0x%x) 0x%x\n",
7254 iop_base, AscGetChipSignatureByte(iop_base));
7255 if (AscGetChipSignatureByte(iop_base) == (uchar)ASC_1000_ID1B) {
7256 ASC_DBG2(1,
7257 "AscFindSignature: AscGetChipSignatureWord(0x%x) 0x%x\n",
7258 iop_base, AscGetChipSignatureWord(iop_base));
7259 sig_word = AscGetChipSignatureWord(iop_base);
7260 if ((sig_word == (ushort)ASC_1000_ID0W) ||
7261 (sig_word == (ushort)ASC_1000_ID0W_FIX)) {
7262 return (1);
7263 }
7264 }
7265 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007266}
7267
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007268static void __devinit AscToggleIRQAct(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007269{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007270 AscSetChipStatus(iop_base, CIW_IRQ_ACT);
7271 AscSetChipStatus(iop_base, 0);
7272 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007273}
7274
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007275static uchar __devinit AscGetChipIRQ(PortAddr iop_base, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007276{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007277 ushort cfg_lsw;
7278 uchar chip_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007279
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007280 if ((bus_type & ASC_IS_EISA) != 0) {
7281 cfg_lsw = AscGetEisaChipCfg(iop_base);
7282 chip_irq = (uchar)(((cfg_lsw >> 8) & 0x07) + 10);
7283 if ((chip_irq == 13) || (chip_irq > 15)) {
7284 return (0);
7285 }
7286 return (chip_irq);
7287 }
7288 if ((bus_type & ASC_IS_VL) != 0) {
7289 cfg_lsw = AscGetChipCfgLsw(iop_base);
7290 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x07));
7291 if ((chip_irq == 0) || (chip_irq == 4) || (chip_irq == 7)) {
7292 return (0);
7293 }
7294 return ((uchar)(chip_irq + (ASC_MIN_IRQ_NO - 1)));
7295 }
7296 cfg_lsw = AscGetChipCfgLsw(iop_base);
7297 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x03));
7298 if (chip_irq == 3)
7299 chip_irq += (uchar)2;
7300 return ((uchar)(chip_irq + ASC_MIN_IRQ_NO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007301}
7302
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007303static uchar __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007304AscSetChipIRQ(PortAddr iop_base, uchar irq_no, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007305{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007306 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007307
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007308 if ((bus_type & ASC_IS_VL) != 0) {
7309 if (irq_no != 0) {
7310 if ((irq_no < ASC_MIN_IRQ_NO)
7311 || (irq_no > ASC_MAX_IRQ_NO)) {
7312 irq_no = 0;
7313 } else {
7314 irq_no -= (uchar)((ASC_MIN_IRQ_NO - 1));
7315 }
7316 }
7317 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE3);
7318 cfg_lsw |= (ushort)0x0010;
7319 AscSetChipCfgLsw(iop_base, cfg_lsw);
7320 AscToggleIRQAct(iop_base);
7321 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE0);
7322 cfg_lsw |= (ushort)((irq_no & 0x07) << 2);
7323 AscSetChipCfgLsw(iop_base, cfg_lsw);
7324 AscToggleIRQAct(iop_base);
7325 return (AscGetChipIRQ(iop_base, bus_type));
7326 }
7327 if ((bus_type & (ASC_IS_ISA)) != 0) {
7328 if (irq_no == 15)
7329 irq_no -= (uchar)2;
7330 irq_no -= (uchar)ASC_MIN_IRQ_NO;
7331 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFF3);
7332 cfg_lsw |= (ushort)((irq_no & 0x03) << 2);
7333 AscSetChipCfgLsw(iop_base, cfg_lsw);
7334 return (AscGetChipIRQ(iop_base, bus_type));
7335 }
7336 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007337}
7338
7339#ifdef CONFIG_ISA
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007340static void __devinit AscEnableIsaDma(uchar dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007341{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007342 if (dma_channel < 4) {
7343 outp(0x000B, (ushort)(0xC0 | dma_channel));
7344 outp(0x000A, dma_channel);
7345 } else if (dma_channel < 8) {
7346 outp(0x00D6, (ushort)(0xC0 | (dma_channel - 4)));
7347 outp(0x00D4, (ushort)(dma_channel - 4));
7348 }
7349 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007350}
7351#endif /* CONFIG_ISA */
7352
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007353static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007354{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007355 EXT_MSG ext_msg;
7356 EXT_MSG out_msg;
7357 ushort halt_q_addr;
7358 int sdtr_accept;
7359 ushort int_halt_code;
7360 ASC_SCSI_BIT_ID_TYPE scsi_busy;
7361 ASC_SCSI_BIT_ID_TYPE target_id;
7362 PortAddr iop_base;
7363 uchar tag_code;
7364 uchar q_status;
7365 uchar halt_qp;
7366 uchar sdtr_data;
7367 uchar target_ix;
7368 uchar q_cntl, tid_no;
7369 uchar cur_dvc_qng;
7370 uchar asyn_sdtr;
7371 uchar scsi_status;
7372 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007373
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007374 ASC_ASSERT(asc_dvc->drv_ptr != NULL);
7375 boardp = asc_dvc->drv_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007376
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007377 iop_base = asc_dvc->iop_base;
7378 int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007379
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007380 halt_qp = AscReadLramByte(iop_base, ASCV_CURCDB_B);
7381 halt_q_addr = ASC_QNO_TO_QADDR(halt_qp);
7382 target_ix = AscReadLramByte(iop_base,
7383 (ushort)(halt_q_addr +
7384 (ushort)ASC_SCSIQ_B_TARGET_IX));
7385 q_cntl =
7386 AscReadLramByte(iop_base,
7387 (ushort)(halt_q_addr + (ushort)ASC_SCSIQ_B_CNTL));
7388 tid_no = ASC_TIX_TO_TID(target_ix);
7389 target_id = (uchar)ASC_TID_TO_TARGET_ID(tid_no);
7390 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
7391 asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB;
7392 } else {
7393 asyn_sdtr = 0;
7394 }
7395 if (int_halt_code == ASC_HALT_DISABLE_ASYN_USE_SYN_FIX) {
7396 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
7397 AscSetChipSDTR(iop_base, 0, tid_no);
7398 boardp->sdtr_data[tid_no] = 0;
7399 }
7400 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
7401 return (0);
7402 } else if (int_halt_code == ASC_HALT_ENABLE_ASYN_USE_SYN_FIX) {
7403 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
7404 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
7405 boardp->sdtr_data[tid_no] = asyn_sdtr;
7406 }
7407 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
7408 return (0);
7409 } else if (int_halt_code == ASC_HALT_EXTMSG_IN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007410
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007411 AscMemWordCopyPtrFromLram(iop_base,
7412 ASCV_MSGIN_BEG,
7413 (uchar *)&ext_msg,
7414 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007415
Matthew Wilcox47d853c2007-07-26 11:41:33 -04007416 if (ext_msg.msg_type == EXTENDED_MESSAGE &&
7417 ext_msg.msg_req == EXTENDED_SDTR &&
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007418 ext_msg.msg_len == MS_SDTR_LEN) {
7419 sdtr_accept = TRUE;
7420 if ((ext_msg.req_ack_offset > ASC_SYN_MAX_OFFSET)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007421
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007422 sdtr_accept = FALSE;
7423 ext_msg.req_ack_offset = ASC_SYN_MAX_OFFSET;
7424 }
7425 if ((ext_msg.xfer_period <
7426 asc_dvc->sdtr_period_tbl[asc_dvc->
7427 host_init_sdtr_index])
7428 || (ext_msg.xfer_period >
7429 asc_dvc->sdtr_period_tbl[asc_dvc->
7430 max_sdtr_index])) {
7431 sdtr_accept = FALSE;
7432 ext_msg.xfer_period =
7433 asc_dvc->sdtr_period_tbl[asc_dvc->
7434 host_init_sdtr_index];
7435 }
7436 if (sdtr_accept) {
7437 sdtr_data =
7438 AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
7439 ext_msg.req_ack_offset);
7440 if ((sdtr_data == 0xFF)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007441
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007442 q_cntl |= QC_MSG_OUT;
7443 asc_dvc->init_sdtr &= ~target_id;
7444 asc_dvc->sdtr_done &= ~target_id;
7445 AscSetChipSDTR(iop_base, asyn_sdtr,
7446 tid_no);
7447 boardp->sdtr_data[tid_no] = asyn_sdtr;
7448 }
7449 }
7450 if (ext_msg.req_ack_offset == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007451
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007452 q_cntl &= ~QC_MSG_OUT;
7453 asc_dvc->init_sdtr &= ~target_id;
7454 asc_dvc->sdtr_done &= ~target_id;
7455 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
7456 } else {
7457 if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007458
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007459 q_cntl &= ~QC_MSG_OUT;
7460 asc_dvc->sdtr_done |= target_id;
7461 asc_dvc->init_sdtr |= target_id;
7462 asc_dvc->pci_fix_asyn_xfer &=
7463 ~target_id;
7464 sdtr_data =
7465 AscCalSDTRData(asc_dvc,
7466 ext_msg.xfer_period,
7467 ext_msg.
7468 req_ack_offset);
7469 AscSetChipSDTR(iop_base, sdtr_data,
7470 tid_no);
7471 boardp->sdtr_data[tid_no] = sdtr_data;
7472 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007473
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007474 q_cntl |= QC_MSG_OUT;
7475 AscMsgOutSDTR(asc_dvc,
7476 ext_msg.xfer_period,
7477 ext_msg.req_ack_offset);
7478 asc_dvc->pci_fix_asyn_xfer &=
7479 ~target_id;
7480 sdtr_data =
7481 AscCalSDTRData(asc_dvc,
7482 ext_msg.xfer_period,
7483 ext_msg.
7484 req_ack_offset);
7485 AscSetChipSDTR(iop_base, sdtr_data,
7486 tid_no);
7487 boardp->sdtr_data[tid_no] = sdtr_data;
7488 asc_dvc->sdtr_done |= target_id;
7489 asc_dvc->init_sdtr |= target_id;
7490 }
7491 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007492
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007493 AscWriteLramByte(iop_base,
7494 (ushort)(halt_q_addr +
7495 (ushort)ASC_SCSIQ_B_CNTL),
7496 q_cntl);
7497 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
7498 return (0);
Matthew Wilcox47d853c2007-07-26 11:41:33 -04007499 } else if (ext_msg.msg_type == EXTENDED_MESSAGE &&
7500 ext_msg.msg_req == EXTENDED_WDTR &&
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007501 ext_msg.msg_len == MS_WDTR_LEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007502
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007503 ext_msg.wdtr_width = 0;
7504 AscMemWordCopyPtrToLram(iop_base,
7505 ASCV_MSGOUT_BEG,
7506 (uchar *)&ext_msg,
7507 sizeof(EXT_MSG) >> 1);
7508 q_cntl |= QC_MSG_OUT;
7509 AscWriteLramByte(iop_base,
7510 (ushort)(halt_q_addr +
7511 (ushort)ASC_SCSIQ_B_CNTL),
7512 q_cntl);
7513 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
7514 return (0);
7515 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007516
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007517 ext_msg.msg_type = MESSAGE_REJECT;
7518 AscMemWordCopyPtrToLram(iop_base,
7519 ASCV_MSGOUT_BEG,
7520 (uchar *)&ext_msg,
7521 sizeof(EXT_MSG) >> 1);
7522 q_cntl |= QC_MSG_OUT;
7523 AscWriteLramByte(iop_base,
7524 (ushort)(halt_q_addr +
7525 (ushort)ASC_SCSIQ_B_CNTL),
7526 q_cntl);
7527 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
7528 return (0);
7529 }
7530 } else if (int_halt_code == ASC_HALT_CHK_CONDITION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007531
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007532 q_cntl |= QC_REQ_SENSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007533
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007534 if ((asc_dvc->init_sdtr & target_id) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007535
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007536 asc_dvc->sdtr_done &= ~target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007537
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007538 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
7539 q_cntl |= QC_MSG_OUT;
7540 AscMsgOutSDTR(asc_dvc,
7541 asc_dvc->
7542 sdtr_period_tbl[(sdtr_data >> 4) &
7543 (uchar)(asc_dvc->
7544 max_sdtr_index -
7545 1)],
7546 (uchar)(sdtr_data & (uchar)
7547 ASC_SYN_MAX_OFFSET));
7548 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007549
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007550 AscWriteLramByte(iop_base,
7551 (ushort)(halt_q_addr +
7552 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007553
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007554 tag_code = AscReadLramByte(iop_base,
7555 (ushort)(halt_q_addr + (ushort)
7556 ASC_SCSIQ_B_TAG_CODE));
7557 tag_code &= 0xDC;
7558 if ((asc_dvc->pci_fix_asyn_xfer & target_id)
7559 && !(asc_dvc->pci_fix_asyn_xfer_always & target_id)
7560 ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007561
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007562 tag_code |= (ASC_TAG_FLAG_DISABLE_DISCONNECT
7563 | ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007564
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007565 }
7566 AscWriteLramByte(iop_base,
7567 (ushort)(halt_q_addr +
7568 (ushort)ASC_SCSIQ_B_TAG_CODE),
7569 tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007570
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007571 q_status = AscReadLramByte(iop_base,
7572 (ushort)(halt_q_addr + (ushort)
7573 ASC_SCSIQ_B_STATUS));
7574 q_status |= (QS_READY | QS_BUSY);
7575 AscWriteLramByte(iop_base,
7576 (ushort)(halt_q_addr +
7577 (ushort)ASC_SCSIQ_B_STATUS),
7578 q_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007579
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007580 scsi_busy = AscReadLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B);
7581 scsi_busy &= ~target_id;
7582 AscWriteLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B, scsi_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007583
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007584 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
7585 return (0);
7586 } else if (int_halt_code == ASC_HALT_SDTR_REJECTED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007587
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007588 AscMemWordCopyPtrFromLram(iop_base,
7589 ASCV_MSGOUT_BEG,
7590 (uchar *)&out_msg,
7591 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007592
Matthew Wilcox47d853c2007-07-26 11:41:33 -04007593 if ((out_msg.msg_type == EXTENDED_MESSAGE) &&
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007594 (out_msg.msg_len == MS_SDTR_LEN) &&
Matthew Wilcox47d853c2007-07-26 11:41:33 -04007595 (out_msg.msg_req == EXTENDED_SDTR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007596
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007597 asc_dvc->init_sdtr &= ~target_id;
7598 asc_dvc->sdtr_done &= ~target_id;
7599 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
7600 boardp->sdtr_data[tid_no] = asyn_sdtr;
7601 }
7602 q_cntl &= ~QC_MSG_OUT;
7603 AscWriteLramByte(iop_base,
7604 (ushort)(halt_q_addr +
7605 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
7606 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
7607 return (0);
7608 } else if (int_halt_code == ASC_HALT_SS_QUEUE_FULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007609
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007610 scsi_status = AscReadLramByte(iop_base,
7611 (ushort)((ushort)halt_q_addr +
7612 (ushort)
7613 ASC_SCSIQ_SCSI_STATUS));
7614 cur_dvc_qng =
7615 AscReadLramByte(iop_base,
7616 (ushort)((ushort)ASC_QADR_BEG +
7617 (ushort)target_ix));
7618 if ((cur_dvc_qng > 0) && (asc_dvc->cur_dvc_qng[tid_no] > 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007619
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007620 scsi_busy = AscReadLramByte(iop_base,
7621 (ushort)ASCV_SCSIBUSY_B);
7622 scsi_busy |= target_id;
7623 AscWriteLramByte(iop_base,
7624 (ushort)ASCV_SCSIBUSY_B, scsi_busy);
7625 asc_dvc->queue_full_or_busy |= target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007626
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007627 if (scsi_status == SAM_STAT_TASK_SET_FULL) {
7628 if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) {
7629 cur_dvc_qng -= 1;
7630 asc_dvc->max_dvc_qng[tid_no] =
7631 cur_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007632
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007633 AscWriteLramByte(iop_base,
7634 (ushort)((ushort)
7635 ASCV_MAX_DVC_QNG_BEG
7636 + (ushort)
7637 tid_no),
7638 cur_dvc_qng);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007639
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007640 /*
7641 * Set the device queue depth to the number of
7642 * active requests when the QUEUE FULL condition
7643 * was encountered.
7644 */
7645 boardp->queue_full |= target_id;
7646 boardp->queue_full_cnt[tid_no] =
7647 cur_dvc_qng;
7648 }
7649 }
7650 }
7651 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
7652 return (0);
7653 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007654#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007655 else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC) {
7656 uchar q_no;
7657 ushort q_addr;
7658 uchar sg_wk_q_no;
7659 uchar first_sg_wk_q_no;
7660 ASC_SCSI_Q *scsiq; /* Ptr to driver request. */
7661 ASC_SG_HEAD *sg_head; /* Ptr to driver SG request. */
7662 ASC_SG_LIST_Q scsi_sg_q; /* Structure written to queue. */
7663 ushort sg_list_dwords;
7664 ushort sg_entry_cnt;
7665 uchar next_qp;
7666 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007667
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007668 q_no = AscReadLramByte(iop_base, (ushort)ASCV_REQ_SG_LIST_QP);
7669 if (q_no == ASC_QLINK_END) {
7670 return (0);
7671 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007672
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007673 q_addr = ASC_QNO_TO_QADDR(q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007674
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007675 /*
7676 * Convert the request's SRB pointer to a host ASC_SCSI_REQ
7677 * structure pointer using a macro provided by the driver.
7678 * The ASC_SCSI_REQ pointer provides a pointer to the
7679 * host ASC_SG_HEAD structure.
7680 */
7681 /* Read request's SRB pointer. */
7682 scsiq = (ASC_SCSI_Q *)
7683 ASC_SRB2SCSIQ(ASC_U32_TO_VADDR(AscReadLramDWord(iop_base,
7684 (ushort)
7685 (q_addr +
7686 ASC_SCSIQ_D_SRBPTR))));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007687
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007688 /*
7689 * Get request's first and working SG queue.
7690 */
7691 sg_wk_q_no = AscReadLramByte(iop_base,
7692 (ushort)(q_addr +
7693 ASC_SCSIQ_B_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007694
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007695 first_sg_wk_q_no = AscReadLramByte(iop_base,
7696 (ushort)(q_addr +
7697 ASC_SCSIQ_B_FIRST_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007698
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007699 /*
7700 * Reset request's working SG queue back to the
7701 * first SG queue.
7702 */
7703 AscWriteLramByte(iop_base,
7704 (ushort)(q_addr +
7705 (ushort)ASC_SCSIQ_B_SG_WK_QP),
7706 first_sg_wk_q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007707
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007708 sg_head = scsiq->sg_head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007709
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007710 /*
7711 * Set sg_entry_cnt to the number of SG elements
7712 * that will be completed on this interrupt.
7713 *
7714 * Note: The allocated SG queues contain ASC_MAX_SG_LIST - 1
7715 * SG elements. The data_cnt and data_addr fields which
7716 * add 1 to the SG element capacity are not used when
7717 * restarting SG handling after a halt.
7718 */
7719 if (scsiq->remain_sg_entry_cnt > (ASC_MAX_SG_LIST - 1)) {
7720 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007721
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007722 /*
7723 * Keep track of remaining number of SG elements that will
7724 * need to be handled on the next interrupt.
7725 */
7726 scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1);
7727 } else {
7728 sg_entry_cnt = scsiq->remain_sg_entry_cnt;
7729 scsiq->remain_sg_entry_cnt = 0;
7730 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007731
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007732 /*
7733 * Copy SG elements into the list of allocated SG queues.
7734 *
7735 * Last index completed is saved in scsiq->next_sg_index.
7736 */
7737 next_qp = first_sg_wk_q_no;
7738 q_addr = ASC_QNO_TO_QADDR(next_qp);
7739 scsi_sg_q.sg_head_qp = q_no;
7740 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
7741 for (i = 0; i < sg_head->queue_cnt; i++) {
7742 scsi_sg_q.seq_no = i + 1;
7743 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
7744 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
7745 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
7746 /*
7747 * After very first SG queue RISC FW uses next
7748 * SG queue first element then checks sg_list_cnt
7749 * against zero and then decrements, so set
7750 * sg_list_cnt 1 less than number of SG elements
7751 * in each SG queue.
7752 */
7753 scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
7754 scsi_sg_q.sg_cur_list_cnt =
7755 ASC_SG_LIST_PER_Q - 1;
7756 } else {
7757 /*
7758 * This is the last SG queue in the list of
7759 * allocated SG queues. If there are more
7760 * SG elements than will fit in the allocated
7761 * queues, then set the QCSG_SG_XFER_MORE flag.
7762 */
7763 if (scsiq->remain_sg_entry_cnt != 0) {
7764 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
7765 } else {
7766 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
7767 }
7768 /* equals sg_entry_cnt * 2 */
7769 sg_list_dwords = sg_entry_cnt << 1;
7770 scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
7771 scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
7772 sg_entry_cnt = 0;
7773 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007774
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007775 scsi_sg_q.q_no = next_qp;
7776 AscMemWordCopyPtrToLram(iop_base,
7777 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
7778 (uchar *)&scsi_sg_q,
7779 sizeof(ASC_SG_LIST_Q) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007780
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007781 AscMemDWordCopyPtrToLram(iop_base,
7782 q_addr + ASC_SGQ_LIST_BEG,
7783 (uchar *)&sg_head->
7784 sg_list[scsiq->next_sg_index],
7785 sg_list_dwords);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007786
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007787 scsiq->next_sg_index += ASC_SG_LIST_PER_Q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007788
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007789 /*
7790 * If the just completed SG queue contained the
7791 * last SG element, then no more SG queues need
7792 * to be written.
7793 */
7794 if (scsi_sg_q.cntl & QCSG_SG_XFER_END) {
7795 break;
7796 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007797
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007798 next_qp = AscReadLramByte(iop_base,
7799 (ushort)(q_addr +
7800 ASC_SCSIQ_B_FWD));
7801 q_addr = ASC_QNO_TO_QADDR(next_qp);
7802 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007803
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007804 /*
7805 * Clear the halt condition so the RISC will be restarted
7806 * after the return.
7807 */
7808 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
7809 return (0);
7810 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007811#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007812 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007813}
7814
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007815static uchar
7816_AscCopyLramScsiDoneQ(PortAddr iop_base,
7817 ushort q_addr,
7818 ASC_QDONE_INFO *scsiq, ASC_DCNT max_dma_count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007819{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007820 ushort _val;
7821 uchar sg_queue_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007822
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007823 DvcGetQinfo(iop_base,
7824 q_addr + ASC_SCSIQ_DONE_INFO_BEG,
7825 (uchar *)scsiq,
7826 (sizeof(ASC_SCSIQ_2) + sizeof(ASC_SCSIQ_3)) / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007827
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007828 _val = AscReadLramWord(iop_base,
7829 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS));
7830 scsiq->q_status = (uchar)_val;
7831 scsiq->q_no = (uchar)(_val >> 8);
7832 _val = AscReadLramWord(iop_base,
7833 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_CNTL));
7834 scsiq->cntl = (uchar)_val;
7835 sg_queue_cnt = (uchar)(_val >> 8);
7836 _val = AscReadLramWord(iop_base,
7837 (ushort)(q_addr +
7838 (ushort)ASC_SCSIQ_B_SENSE_LEN));
7839 scsiq->sense_len = (uchar)_val;
7840 scsiq->extra_bytes = (uchar)(_val >> 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007841
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007842 /*
7843 * Read high word of remain bytes from alternate location.
7844 */
7845 scsiq->remain_bytes = (((ADV_DCNT)AscReadLramWord(iop_base,
7846 (ushort)(q_addr +
7847 (ushort)
7848 ASC_SCSIQ_W_ALT_DC1)))
7849 << 16);
7850 /*
7851 * Read low word of remain bytes from original location.
7852 */
7853 scsiq->remain_bytes += AscReadLramWord(iop_base,
7854 (ushort)(q_addr + (ushort)
7855 ASC_SCSIQ_DW_REMAIN_XFER_CNT));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007856
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007857 scsiq->remain_bytes &= max_dma_count;
7858 return (sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007859}
7860
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007861static int AscIsrQDone(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007862{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007863 uchar next_qp;
7864 uchar n_q_used;
7865 uchar sg_list_qp;
7866 uchar sg_queue_cnt;
7867 uchar q_cnt;
7868 uchar done_q_tail;
7869 uchar tid_no;
7870 ASC_SCSI_BIT_ID_TYPE scsi_busy;
7871 ASC_SCSI_BIT_ID_TYPE target_id;
7872 PortAddr iop_base;
7873 ushort q_addr;
7874 ushort sg_q_addr;
7875 uchar cur_target_qng;
7876 ASC_QDONE_INFO scsiq_buf;
7877 ASC_QDONE_INFO *scsiq;
7878 int false_overrun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007879
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007880 iop_base = asc_dvc->iop_base;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007881 n_q_used = 1;
7882 scsiq = (ASC_QDONE_INFO *)&scsiq_buf;
7883 done_q_tail = (uchar)AscGetVarDoneQTail(iop_base);
7884 q_addr = ASC_QNO_TO_QADDR(done_q_tail);
7885 next_qp = AscReadLramByte(iop_base,
7886 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_FWD));
7887 if (next_qp != ASC_QLINK_END) {
7888 AscPutVarDoneQTail(iop_base, next_qp);
7889 q_addr = ASC_QNO_TO_QADDR(next_qp);
7890 sg_queue_cnt = _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq,
7891 asc_dvc->max_dma_count);
7892 AscWriteLramByte(iop_base,
7893 (ushort)(q_addr +
7894 (ushort)ASC_SCSIQ_B_STATUS),
7895 (uchar)(scsiq->
7896 q_status & (uchar)~(QS_READY |
7897 QS_ABORTED)));
7898 tid_no = ASC_TIX_TO_TID(scsiq->d2.target_ix);
7899 target_id = ASC_TIX_TO_TARGET_ID(scsiq->d2.target_ix);
7900 if ((scsiq->cntl & QC_SG_HEAD) != 0) {
7901 sg_q_addr = q_addr;
7902 sg_list_qp = next_qp;
7903 for (q_cnt = 0; q_cnt < sg_queue_cnt; q_cnt++) {
7904 sg_list_qp = AscReadLramByte(iop_base,
7905 (ushort)(sg_q_addr
7906 + (ushort)
7907 ASC_SCSIQ_B_FWD));
7908 sg_q_addr = ASC_QNO_TO_QADDR(sg_list_qp);
7909 if (sg_list_qp == ASC_QLINK_END) {
7910 AscSetLibErrorCode(asc_dvc,
7911 ASCQ_ERR_SG_Q_LINKS);
7912 scsiq->d3.done_stat = QD_WITH_ERROR;
7913 scsiq->d3.host_stat =
7914 QHSTA_D_QDONE_SG_LIST_CORRUPTED;
7915 goto FATAL_ERR_QDONE;
7916 }
7917 AscWriteLramByte(iop_base,
7918 (ushort)(sg_q_addr + (ushort)
7919 ASC_SCSIQ_B_STATUS),
7920 QS_FREE);
7921 }
7922 n_q_used = sg_queue_cnt + 1;
7923 AscPutVarDoneQTail(iop_base, sg_list_qp);
7924 }
7925 if (asc_dvc->queue_full_or_busy & target_id) {
7926 cur_target_qng = AscReadLramByte(iop_base,
7927 (ushort)((ushort)
7928 ASC_QADR_BEG
7929 + (ushort)
7930 scsiq->d2.
7931 target_ix));
7932 if (cur_target_qng < asc_dvc->max_dvc_qng[tid_no]) {
7933 scsi_busy = AscReadLramByte(iop_base, (ushort)
7934 ASCV_SCSIBUSY_B);
7935 scsi_busy &= ~target_id;
7936 AscWriteLramByte(iop_base,
7937 (ushort)ASCV_SCSIBUSY_B,
7938 scsi_busy);
7939 asc_dvc->queue_full_or_busy &= ~target_id;
7940 }
7941 }
7942 if (asc_dvc->cur_total_qng >= n_q_used) {
7943 asc_dvc->cur_total_qng -= n_q_used;
7944 if (asc_dvc->cur_dvc_qng[tid_no] != 0) {
7945 asc_dvc->cur_dvc_qng[tid_no]--;
7946 }
7947 } else {
7948 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CUR_QNG);
7949 scsiq->d3.done_stat = QD_WITH_ERROR;
7950 goto FATAL_ERR_QDONE;
7951 }
7952 if ((scsiq->d2.srb_ptr == 0UL) ||
7953 ((scsiq->q_status & QS_ABORTED) != 0)) {
7954 return (0x11);
7955 } else if (scsiq->q_status == QS_DONE) {
7956 false_overrun = FALSE;
7957 if (scsiq->extra_bytes != 0) {
7958 scsiq->remain_bytes +=
7959 (ADV_DCNT)scsiq->extra_bytes;
7960 }
7961 if (scsiq->d3.done_stat == QD_WITH_ERROR) {
7962 if (scsiq->d3.host_stat ==
7963 QHSTA_M_DATA_OVER_RUN) {
7964 if ((scsiq->
7965 cntl & (QC_DATA_IN | QC_DATA_OUT))
7966 == 0) {
7967 scsiq->d3.done_stat =
7968 QD_NO_ERROR;
7969 scsiq->d3.host_stat =
7970 QHSTA_NO_ERROR;
7971 } else if (false_overrun) {
7972 scsiq->d3.done_stat =
7973 QD_NO_ERROR;
7974 scsiq->d3.host_stat =
7975 QHSTA_NO_ERROR;
7976 }
7977 } else if (scsiq->d3.host_stat ==
7978 QHSTA_M_HUNG_REQ_SCSI_BUS_RESET) {
7979 AscStopChip(iop_base);
7980 AscSetChipControl(iop_base,
7981 (uchar)(CC_SCSI_RESET
7982 | CC_HALT));
7983 DvcDelayNanoSecond(asc_dvc, 60000);
7984 AscSetChipControl(iop_base, CC_HALT);
7985 AscSetChipStatus(iop_base,
7986 CIW_CLR_SCSI_RESET_INT);
7987 AscSetChipStatus(iop_base, 0);
7988 AscSetChipControl(iop_base, 0);
7989 }
7990 }
7991 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
Matthew Wilcox895d6b42007-07-26 11:57:06 -04007992 asc_isr_callback(asc_dvc, scsiq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007993 } else {
7994 if ((AscReadLramByte(iop_base,
7995 (ushort)(q_addr + (ushort)
7996 ASC_SCSIQ_CDB_BEG))
7997 == START_STOP)) {
7998 asc_dvc->unit_not_ready &= ~target_id;
7999 if (scsiq->d3.done_stat != QD_NO_ERROR) {
8000 asc_dvc->start_motor &=
8001 ~target_id;
8002 }
8003 }
8004 }
8005 return (1);
8006 } else {
8007 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS);
8008 FATAL_ERR_QDONE:
8009 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
Matthew Wilcox895d6b42007-07-26 11:57:06 -04008010 asc_isr_callback(asc_dvc, scsiq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008011 }
8012 return (0x80);
8013 }
8014 }
8015 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008016}
8017
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008018static int AscISR(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008019{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008020 ASC_CS_TYPE chipstat;
8021 PortAddr iop_base;
8022 ushort saved_ram_addr;
8023 uchar ctrl_reg;
8024 uchar saved_ctrl_reg;
8025 int int_pending;
8026 int status;
8027 uchar host_flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008028
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008029 iop_base = asc_dvc->iop_base;
8030 int_pending = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008031
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008032 if (AscIsIntPending(iop_base) == 0) {
8033 return int_pending;
8034 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008035
Matthew Wilcox895d6b42007-07-26 11:57:06 -04008036 if ((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008037 return (ERR);
8038 }
8039 if (asc_dvc->in_critical_cnt != 0) {
8040 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL);
8041 return (ERR);
8042 }
8043 if (asc_dvc->is_in_int) {
8044 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY);
8045 return (ERR);
8046 }
8047 asc_dvc->is_in_int = TRUE;
8048 ctrl_reg = AscGetChipControl(iop_base);
8049 saved_ctrl_reg = ctrl_reg & (~(CC_SCSI_RESET | CC_CHIP_RESET |
8050 CC_SINGLE_STEP | CC_DIAG | CC_TEST));
8051 chipstat = AscGetChipStatus(iop_base);
8052 if (chipstat & CSW_SCSI_RESET_LATCH) {
8053 if (!(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))) {
8054 int i = 10;
8055 int_pending = TRUE;
8056 asc_dvc->sdtr_done = 0;
8057 saved_ctrl_reg &= (uchar)(~CC_HALT);
8058 while ((AscGetChipStatus(iop_base) &
8059 CSW_SCSI_RESET_ACTIVE) && (i-- > 0)) {
8060 DvcSleepMilliSecond(100);
8061 }
8062 AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT));
8063 AscSetChipControl(iop_base, CC_HALT);
8064 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
8065 AscSetChipStatus(iop_base, 0);
8066 chipstat = AscGetChipStatus(iop_base);
8067 }
8068 }
8069 saved_ram_addr = AscGetChipLramAddr(iop_base);
8070 host_flag = AscReadLramByte(iop_base,
8071 ASCV_HOST_FLAG_B) &
8072 (uchar)(~ASC_HOST_FLAG_IN_ISR);
8073 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
8074 (uchar)(host_flag | (uchar)ASC_HOST_FLAG_IN_ISR));
8075 if ((chipstat & CSW_INT_PENDING)
8076 || (int_pending)
8077 ) {
8078 AscAckInterrupt(iop_base);
8079 int_pending = TRUE;
8080 if ((chipstat & CSW_HALTED) && (ctrl_reg & CC_SINGLE_STEP)) {
8081 if (AscIsrChipHalted(asc_dvc) == ERR) {
8082 goto ISR_REPORT_QDONE_FATAL_ERROR;
8083 } else {
8084 saved_ctrl_reg &= (uchar)(~CC_HALT);
8085 }
8086 } else {
8087 ISR_REPORT_QDONE_FATAL_ERROR:
8088 if ((asc_dvc->dvc_cntl & ASC_CNTL_INT_MULTI_Q) != 0) {
8089 while (((status =
8090 AscIsrQDone(asc_dvc)) & 0x01) != 0) {
8091 }
8092 } else {
8093 do {
8094 if ((status =
8095 AscIsrQDone(asc_dvc)) == 1) {
8096 break;
8097 }
8098 } while (status == 0x11);
8099 }
8100 if ((status & 0x80) != 0)
8101 int_pending = ERR;
8102 }
8103 }
8104 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
8105 AscSetChipLramAddr(iop_base, saved_ram_addr);
8106 AscSetChipControl(iop_base, saved_ctrl_reg);
8107 asc_dvc->is_in_int = FALSE;
8108 return (int_pending);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008109}
8110
8111/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008112static uchar _asc_mcode_buf[] = {
8113 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008114 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008115 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008116 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008117 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8118 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x12, 0x0D, 0x05,
8119 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8120 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008121 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008122 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
8123 0x00, 0x00, 0xE4, 0x88, 0x00, 0x00, 0x00, 0x00, 0x80, 0x73, 0x48, 0x04,
8124 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73, 0x03, 0x23, 0x36, 0x40,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008125 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008126 0xC2, 0x00, 0x92, 0x80, 0x1E, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x48, 0x98,
8127 0xDF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, 0x4F, 0x00, 0xF5, 0x00,
8128 0x48, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, 0x80, 0x62,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008129 0x92, 0x80, 0x00, 0x46, 0x15, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008130 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xD6, 0x00, 0xA6, 0x97, 0x7F, 0x23,
8131 0x04, 0x61, 0x84, 0x01, 0xE6, 0x84, 0xD2, 0xC1, 0x80, 0x73, 0xCD, 0x04,
8132 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x01, 0xA6, 0x97, 0xC6, 0x81, 0xC2, 0x88,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008133 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0xFE, 0x00, 0x4F, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008134 0x84, 0x97, 0x07, 0xA6, 0x08, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88,
8135 0x03, 0x03, 0x01, 0xDE, 0xC2, 0x88, 0xCE, 0x00, 0x69, 0x60, 0xCE, 0x00,
8136 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x78, 0x01, 0x80, 0x63, 0x07, 0xA6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008137 0x24, 0x01, 0x78, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008138 0x34, 0x01, 0x00, 0x33, 0x04, 0x00, 0xC2, 0x88, 0x03, 0x07, 0x02, 0x01,
8139 0x04, 0xCA, 0x0D, 0x23, 0x68, 0x98, 0x4D, 0x04, 0x04, 0x85, 0x05, 0xD8,
8140 0x0D, 0x23, 0x68, 0x98, 0xCD, 0x04, 0x15, 0x23, 0xF8, 0x88, 0xFB, 0x23,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008141 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x62, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008142 0x00, 0x33, 0x0A, 0x00, 0xC2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x6E, 0x01,
8143 0x00, 0x33, 0x0B, 0x00, 0xC2, 0x88, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33,
8144 0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x88, 0x81, 0x06, 0xAB, 0x82, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008145 0x88, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x92, 0x01, 0x50, 0x00, 0x00, 0xA3,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008146 0x3C, 0x01, 0x00, 0x05, 0x7C, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6,
8147 0x04, 0x23, 0xA0, 0x01, 0x15, 0x23, 0xA1, 0x01, 0xBE, 0x81, 0xFD, 0x23,
8148 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008149 0xB4, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008150 0xC2, 0x88, 0x06, 0x23, 0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01,
8151 0x00, 0xA2, 0xD4, 0x01, 0x57, 0x60, 0x00, 0xA0, 0xDA, 0x01, 0xE6, 0x84,
8152 0x80, 0x23, 0xA0, 0x01, 0xE6, 0x84, 0x80, 0x73, 0x4B, 0x00, 0x06, 0x61,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008153 0x00, 0xA2, 0x00, 0x02, 0x04, 0x01, 0x0C, 0xDE, 0x02, 0x01, 0x03, 0xCC,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008154 0x4F, 0x00, 0x84, 0x97, 0xFC, 0x81, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01,
8155 0x4F, 0x00, 0x62, 0x97, 0x48, 0x04, 0x84, 0x80, 0xF0, 0x97, 0x00, 0x46,
8156 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00, 0x81, 0x73, 0x06, 0x29,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008157 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x6B, 0xEB, 0x11, 0x23, 0xF8, 0x88,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008158 0x04, 0x98, 0xF0, 0x80, 0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x2A, 0x02,
8159 0x7C, 0x95, 0x06, 0xA6, 0x34, 0x02, 0x03, 0xA6, 0x4C, 0x04, 0x46, 0x82,
8160 0x04, 0x01, 0x03, 0xD8, 0xB4, 0x98, 0x6A, 0x96, 0x46, 0x82, 0xFE, 0x95,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008161 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x6C, 0x02,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008162 0x07, 0xA6, 0x5A, 0x02, 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x62, 0x02,
8163 0xC2, 0x88, 0x7C, 0x95, 0x48, 0x82, 0x60, 0x96, 0x48, 0x82, 0x04, 0x23,
8164 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84, 0x04, 0x01, 0x0C, 0xDC,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008165 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008166 0x6F, 0x00, 0xA5, 0x01, 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01,
8167 0x24, 0x2B, 0x1C, 0x01, 0x02, 0xA6, 0xAA, 0x02, 0x07, 0xA6, 0x5A, 0x02,
8168 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x20, 0x04, 0x01, 0xA6, 0xB4, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008169 0x00, 0xA6, 0xB4, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008170 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0x8C, 0x02, 0x4D, 0x04, 0x04, 0x01,
8171 0x0B, 0xDC, 0xE7, 0x23, 0x04, 0x61, 0x84, 0x01, 0x10, 0x31, 0x12, 0x35,
8172 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0xEA, 0x82,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008173 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0xA2, 0xC8,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008174 0x00, 0x33, 0x1F, 0x00, 0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39,
8175 0x0E, 0x3D, 0x7E, 0x98, 0xB6, 0x2D, 0x01, 0xA6, 0x14, 0x03, 0x00, 0xA6,
8176 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6, 0x10, 0x03, 0x03, 0xA6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008177 0x20, 0x04, 0x02, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008178 0x7C, 0x95, 0xEE, 0x82, 0x60, 0x96, 0xEE, 0x82, 0x82, 0x98, 0x80, 0x42,
8179 0x7E, 0x98, 0x64, 0xE4, 0x04, 0x01, 0x2D, 0xC8, 0x31, 0x05, 0x07, 0x01,
8180 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01, 0x05, 0x05, 0x86, 0x98,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008181 0x7E, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008182 0x3C, 0x04, 0x06, 0xA6, 0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33,
8183 0x25, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x32, 0x83, 0x60, 0x96, 0x32, 0x83,
8184 0x04, 0x01, 0x10, 0xCE, 0x07, 0xC8, 0x05, 0x05, 0xEB, 0x04, 0x00, 0x33,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008185 0x00, 0x20, 0xC0, 0x20, 0x81, 0x62, 0x72, 0x83, 0x00, 0x01, 0x05, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008186 0xFF, 0xA2, 0x7A, 0x03, 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83,
8187 0x05, 0x05, 0x15, 0x01, 0x00, 0xA2, 0x9A, 0x03, 0xEC, 0x00, 0x6E, 0x00,
8188 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0x01, 0xA6, 0x96, 0x03,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008189 0x00, 0xA6, 0x96, 0x03, 0x10, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008190 0xA4, 0x03, 0x00, 0xA6, 0xBC, 0x03, 0x10, 0x84, 0xA8, 0x98, 0x80, 0x42,
8191 0x01, 0xA6, 0xA4, 0x03, 0x07, 0xA6, 0xB2, 0x03, 0xD4, 0x83, 0x7C, 0x95,
8192 0xA8, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC2, 0x88, 0xA8, 0x98, 0x80, 0x42,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008193 0x00, 0xA6, 0xBC, 0x03, 0x07, 0xA6, 0xCA, 0x03, 0xD4, 0x83, 0x7C, 0x95,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008194 0xC0, 0x83, 0x00, 0x33, 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32,
8195 0x80, 0x36, 0x04, 0x23, 0xA0, 0x01, 0x12, 0x23, 0xA1, 0x01, 0x10, 0x84,
8196 0x07, 0xF0, 0x06, 0xA4, 0xF4, 0x03, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008197 0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x0E, 0x04, 0x07, 0xA6, 0x06, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008198 0x06, 0xA6, 0x0A, 0x04, 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x7C, 0x95,
8199 0xF4, 0x83, 0x60, 0x96, 0xF4, 0x83, 0x20, 0x84, 0x07, 0xF0, 0x06, 0xA4,
8200 0x20, 0x04, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23, 0x83, 0x03, 0x80, 0x63,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008201 0xB6, 0x2D, 0x03, 0xA6, 0x3C, 0x04, 0x07, 0xA6, 0x34, 0x04, 0x06, 0xA6,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008202 0x38, 0x04, 0x00, 0x33, 0x30, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x20, 0x84,
8203 0x60, 0x96, 0x20, 0x84, 0x1D, 0x01, 0x06, 0xCC, 0x00, 0x33, 0x00, 0x84,
8204 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62, 0xA2, 0x0D, 0x80, 0x63,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008205 0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008206 0x80, 0x63, 0xA3, 0x01, 0x07, 0xA4, 0x64, 0x04, 0x23, 0x01, 0x00, 0xA2,
8207 0x86, 0x04, 0x0A, 0xA0, 0x76, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1D, 0x00,
8208 0xC2, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1E, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008209 0xC2, 0x88, 0x42, 0x23, 0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008210 0x08, 0x23, 0x22, 0xA3, 0xA2, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xAE, 0x04,
8211 0x02, 0x23, 0x22, 0xA3, 0xC4, 0x04, 0x42, 0x23, 0xF8, 0x88, 0x4A, 0x00,
8212 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23, 0xF8, 0x88, 0x04, 0x98,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008213 0x00, 0xA2, 0xC0, 0x04, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008214 0x81, 0x62, 0xE8, 0x81, 0x47, 0x23, 0xF8, 0x88, 0x04, 0x01, 0x0B, 0xDE,
8215 0x04, 0x98, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x81, 0xC0, 0x20, 0x81, 0x62,
8216 0x14, 0x01, 0x00, 0xA0, 0x00, 0x02, 0x43, 0x23, 0xF8, 0x88, 0x04, 0x23,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008217 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008218 0xF4, 0x04, 0x00, 0x33, 0x27, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x04, 0xDC,
8219 0x02, 0x23, 0xA2, 0x01, 0x04, 0x23, 0xA0, 0x01, 0x04, 0x98, 0x26, 0x95,
8220 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00, 0x00, 0xA3, 0x22, 0x05,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008221 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x1C, 0x05, 0x0A, 0x85,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008222 0x46, 0x97, 0xCD, 0x04, 0x24, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01,
8223 0x03, 0xDA, 0x80, 0x23, 0x82, 0x01, 0x34, 0x85, 0x02, 0x23, 0xA0, 0x01,
8224 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x40, 0x05, 0x1D, 0x01, 0x04, 0xD6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008225 0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008226 0x49, 0x00, 0x81, 0x01, 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01,
8227 0xF7, 0x04, 0x03, 0x01, 0x49, 0x04, 0x80, 0x01, 0xC9, 0x00, 0x00, 0x05,
8228 0x00, 0x01, 0xFF, 0xA0, 0x60, 0x05, 0x77, 0x04, 0x01, 0x23, 0xEA, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008229 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008230 0x07, 0xA4, 0xF8, 0x05, 0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85,
8231 0x00, 0x33, 0x2D, 0x00, 0xC2, 0x88, 0x04, 0xA0, 0xB8, 0x05, 0x80, 0x63,
8232 0x00, 0x23, 0xDF, 0x00, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0xA4, 0x05,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008233 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008234 0x62, 0x97, 0x04, 0x85, 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0x04, 0x85,
8235 0x08, 0xA0, 0xBE, 0x05, 0xF4, 0x85, 0x03, 0xA0, 0xC4, 0x05, 0xF4, 0x85,
8236 0x01, 0xA0, 0xCE, 0x05, 0x88, 0x00, 0x80, 0x63, 0xCC, 0x86, 0x07, 0xA0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008237 0xEE, 0x05, 0x5F, 0x00, 0x00, 0x2B, 0xDF, 0x08, 0x00, 0xA2, 0xE6, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008238 0x80, 0x67, 0x80, 0x63, 0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23,
8239 0x68, 0x98, 0x48, 0x23, 0xF8, 0x88, 0x07, 0x23, 0x80, 0x00, 0x06, 0x87,
8240 0x80, 0x63, 0x7C, 0x85, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63, 0x4A, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008241 0x06, 0x61, 0x00, 0xA2, 0x36, 0x06, 0x1D, 0x01, 0x16, 0xD4, 0xC0, 0x23,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008242 0x07, 0x41, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33,
8243 0x37, 0x00, 0xC2, 0x88, 0x1D, 0x01, 0x01, 0xD6, 0x20, 0x23, 0x63, 0x60,
8244 0x83, 0x03, 0x80, 0x63, 0x02, 0x23, 0xDF, 0x00, 0x07, 0xA6, 0x7C, 0x05,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008245 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008246 0x52, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x4E, 0x06, 0x1D, 0x01, 0x03, 0xCA,
8247 0xC0, 0x23, 0x07, 0x41, 0x00, 0x63, 0x1D, 0x01, 0x04, 0xCC, 0x00, 0x33,
8248 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23, 0x07, 0x41, 0x00, 0x63,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008249 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x01, 0x23,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008250 0xDF, 0x00, 0x06, 0xA6, 0x84, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67,
8251 0x80, 0x63, 0x00, 0x33, 0x00, 0x40, 0xC0, 0x20, 0x81, 0x62, 0x00, 0x63,
8252 0x00, 0x00, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x94, 0x06,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008253 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x00, 0x01, 0xA0, 0x14, 0x07, 0x00, 0x2B,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008254 0x40, 0x0E, 0x80, 0x63, 0x01, 0x00, 0x06, 0xA6, 0xAA, 0x06, 0x07, 0xA6,
8255 0x7C, 0x05, 0x40, 0x0E, 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0xA2, 0x06,
8256 0x06, 0xA6, 0xBC, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x40, 0x0E,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008257 0x80, 0x63, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008258 0x07, 0xA6, 0xD6, 0x06, 0x00, 0x33, 0x2A, 0x00, 0xC2, 0x88, 0x03, 0x03,
8259 0x80, 0x63, 0x89, 0x00, 0x0A, 0x2B, 0x07, 0xA6, 0xE8, 0x06, 0x00, 0x33,
8260 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, 0x00, 0xA2, 0xF4, 0x06, 0xC0, 0x0E,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008261 0x80, 0x63, 0xDE, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008262 0x81, 0x62, 0x04, 0x01, 0x02, 0xDA, 0x80, 0x63, 0x7C, 0x85, 0x80, 0x7B,
8263 0x80, 0x63, 0x06, 0xA6, 0x8C, 0x06, 0x00, 0x33, 0x2C, 0x00, 0xC2, 0x88,
8264 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008265 0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008266 0x00, 0x00, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x44, 0x07,
8267 0x07, 0xA6, 0x7C, 0x05, 0xBF, 0x23, 0x04, 0x61, 0x84, 0x01, 0xE6, 0x84,
8268 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x00, 0x01, 0xF2, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008269 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008270 0x80, 0x05, 0x81, 0x05, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04,
8271 0x01, 0x01, 0xF1, 0x00, 0x70, 0x00, 0x81, 0x01, 0x70, 0x04, 0x71, 0x00,
8272 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04, 0x70, 0x00, 0x80, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008273 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008274 0xF1, 0x00, 0x70, 0x00, 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01,
8275 0x72, 0x00, 0x81, 0x01, 0x71, 0x04, 0x70, 0x00, 0x81, 0x01, 0x70, 0x04,
8276 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05, 0xA3, 0x01, 0xA2, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008277 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008278 0xC4, 0x07, 0x00, 0x33, 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05,
8279 0x04, 0x01, 0x11, 0xC8, 0x48, 0x00, 0xB0, 0x01, 0xB1, 0x01, 0x08, 0x23,
8280 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43, 0x00, 0xA2, 0xE4, 0x07,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008281 0x00, 0x05, 0xDA, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008282 0x05, 0x05, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04,
8283 0x00, 0x02, 0x80, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04, 0x00, 0x63,
8284 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x00, 0xA0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008285 0x14, 0x08, 0x16, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008286 0x00, 0x63, 0xF3, 0x04, 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43,
8287 0xF4, 0x00, 0xCF, 0x40, 0x00, 0xA2, 0x44, 0x08, 0x74, 0x04, 0x02, 0x01,
8288 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1, 0x24, 0x08, 0x04, 0x98,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008289 0x26, 0x95, 0x24, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008290 0x5A, 0x88, 0x02, 0x01, 0x04, 0xD8, 0x46, 0x97, 0x04, 0x98, 0x26, 0x95,
8291 0x4A, 0x88, 0x75, 0x00, 0x00, 0xA3, 0x64, 0x08, 0x00, 0x05, 0x4E, 0x88,
8292 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x76, 0x08,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008293 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008294 0x00, 0x63, 0x38, 0x2B, 0x9C, 0x88, 0x38, 0x2B, 0x92, 0x88, 0x32, 0x09,
8295 0x31, 0x05, 0x92, 0x98, 0x05, 0x05, 0xB2, 0x09, 0x00, 0x63, 0x00, 0x32,
8296 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63, 0x80, 0x32, 0x80, 0x36,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008297 0x80, 0x3A, 0x80, 0x3E, 0xB4, 0x3D, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008298 0x40, 0x36, 0x40, 0x3A, 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40,
8299 0x00, 0xA0, 0xB4, 0x08, 0x5D, 0x00, 0xFE, 0xC3, 0x00, 0x63, 0x80, 0x73,
8300 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73, 0xFF, 0xFD, 0x80, 0x73,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008301 0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -06008302 0xA1, 0x23, 0xA1, 0x01, 0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77,
8303 0x68, 0x00, 0x00, 0xA2, 0x80, 0x00, 0x03, 0xC2, 0xF1, 0xC7, 0x41, 0x23,
8304 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xE6, 0x84,
Linus Torvalds1da177e2005-04-16 15:20:36 -07008305};
8306
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008307static ushort _asc_mcode_size = sizeof(_asc_mcode_buf);
8308static ADV_DCNT _asc_mcode_chksum = 0x012C453FUL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008309
8310#define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008311static uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = {
8312 INQUIRY,
8313 REQUEST_SENSE,
8314 READ_CAPACITY,
8315 READ_TOC,
8316 MODE_SELECT,
8317 MODE_SENSE,
8318 MODE_SELECT_10,
8319 MODE_SENSE_10,
8320 0xFF,
8321 0xFF,
8322 0xFF,
8323 0xFF,
8324 0xFF,
8325 0xFF,
8326 0xFF,
8327 0xFF
Linus Torvalds1da177e2005-04-16 15:20:36 -07008328};
8329
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008330static int AscExeScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008331{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008332 PortAddr iop_base;
8333 ulong last_int_level;
8334 int sta;
8335 int n_q_required;
8336 int disable_syn_offset_one_fix;
8337 int i;
8338 ASC_PADDR addr;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008339 ushort sg_entry_cnt = 0;
8340 ushort sg_entry_cnt_minus_one = 0;
8341 uchar target_ix;
8342 uchar tid_no;
8343 uchar sdtr_data;
8344 uchar extra_bytes;
8345 uchar scsi_cmd;
8346 uchar disable_cmd;
8347 ASC_SG_HEAD *sg_head;
8348 ASC_DCNT data_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008349
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008350 iop_base = asc_dvc->iop_base;
8351 sg_head = scsiq->sg_head;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008352 if (asc_dvc->err_code != 0)
8353 return (ERR);
8354 if (scsiq == (ASC_SCSI_Q *)0L) {
8355 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_NULL_PTR);
8356 return (ERR);
8357 }
8358 scsiq->q1.q_no = 0;
8359 if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
8360 scsiq->q1.extra_bytes = 0;
8361 }
8362 sta = 0;
8363 target_ix = scsiq->q2.target_ix;
8364 tid_no = ASC_TIX_TO_TID(target_ix);
8365 n_q_required = 1;
8366 if (scsiq->cdbptr[0] == REQUEST_SENSE) {
8367 if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
8368 asc_dvc->sdtr_done &= ~scsiq->q1.target_id;
8369 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
8370 AscMsgOutSDTR(asc_dvc,
8371 asc_dvc->
8372 sdtr_period_tbl[(sdtr_data >> 4) &
8373 (uchar)(asc_dvc->
8374 max_sdtr_index -
8375 1)],
8376 (uchar)(sdtr_data & (uchar)
8377 ASC_SYN_MAX_OFFSET));
8378 scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
8379 }
8380 }
8381 last_int_level = DvcEnterCritical();
8382 if (asc_dvc->in_critical_cnt != 0) {
8383 DvcLeaveCritical(last_int_level);
8384 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY);
8385 return (ERR);
8386 }
8387 asc_dvc->in_critical_cnt++;
8388 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
8389 if ((sg_entry_cnt = sg_head->entry_cnt) == 0) {
8390 asc_dvc->in_critical_cnt--;
8391 DvcLeaveCritical(last_int_level);
8392 return (ERR);
8393 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008394#if !CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008395 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
8396 asc_dvc->in_critical_cnt--;
8397 DvcLeaveCritical(last_int_level);
8398 return (ERR);
8399 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008400#endif /* !CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008401 if (sg_entry_cnt == 1) {
8402 scsiq->q1.data_addr =
8403 (ADV_PADDR)sg_head->sg_list[0].addr;
8404 scsiq->q1.data_cnt =
8405 (ADV_DCNT)sg_head->sg_list[0].bytes;
8406 scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
8407 }
8408 sg_entry_cnt_minus_one = sg_entry_cnt - 1;
8409 }
8410 scsi_cmd = scsiq->cdbptr[0];
8411 disable_syn_offset_one_fix = FALSE;
8412 if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) &&
8413 !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) {
8414 if (scsiq->q1.cntl & QC_SG_HEAD) {
8415 data_cnt = 0;
8416 for (i = 0; i < sg_entry_cnt; i++) {
8417 data_cnt +=
8418 (ADV_DCNT)le32_to_cpu(sg_head->sg_list[i].
8419 bytes);
8420 }
8421 } else {
8422 data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
8423 }
8424 if (data_cnt != 0UL) {
8425 if (data_cnt < 512UL) {
8426 disable_syn_offset_one_fix = TRUE;
8427 } else {
8428 for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST;
8429 i++) {
8430 disable_cmd =
8431 _syn_offset_one_disable_cmd[i];
8432 if (disable_cmd == 0xFF) {
8433 break;
8434 }
8435 if (scsi_cmd == disable_cmd) {
8436 disable_syn_offset_one_fix =
8437 TRUE;
8438 break;
8439 }
8440 }
8441 }
8442 }
8443 }
8444 if (disable_syn_offset_one_fix) {
8445 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
8446 scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX |
8447 ASC_TAG_FLAG_DISABLE_DISCONNECT);
8448 } else {
8449 scsiq->q2.tag_code &= 0x27;
8450 }
8451 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
8452 if (asc_dvc->bug_fix_cntl) {
8453 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
8454 if ((scsi_cmd == READ_6) ||
8455 (scsi_cmd == READ_10)) {
8456 addr =
8457 (ADV_PADDR)le32_to_cpu(sg_head->
8458 sg_list
8459 [sg_entry_cnt_minus_one].
8460 addr) +
8461 (ADV_DCNT)le32_to_cpu(sg_head->
8462 sg_list
8463 [sg_entry_cnt_minus_one].
8464 bytes);
8465 extra_bytes =
8466 (uchar)((ushort)addr & 0x0003);
8467 if ((extra_bytes != 0)
8468 &&
8469 ((scsiq->q2.
8470 tag_code &
8471 ASC_TAG_FLAG_EXTRA_BYTES)
8472 == 0)) {
8473 scsiq->q2.tag_code |=
8474 ASC_TAG_FLAG_EXTRA_BYTES;
8475 scsiq->q1.extra_bytes =
8476 extra_bytes;
8477 data_cnt =
8478 le32_to_cpu(sg_head->
8479 sg_list
8480 [sg_entry_cnt_minus_one].
8481 bytes);
8482 data_cnt -=
8483 (ASC_DCNT) extra_bytes;
8484 sg_head->
8485 sg_list
8486 [sg_entry_cnt_minus_one].
8487 bytes =
8488 cpu_to_le32(data_cnt);
8489 }
8490 }
8491 }
8492 }
8493 sg_head->entry_to_copy = sg_head->entry_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008494#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008495 /*
8496 * Set the sg_entry_cnt to the maximum possible. The rest of
8497 * the SG elements will be copied when the RISC completes the
8498 * SG elements that fit and halts.
8499 */
8500 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
8501 sg_entry_cnt = ASC_MAX_SG_LIST;
8502 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008503#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008504 n_q_required = AscSgListToQueue(sg_entry_cnt);
8505 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
8506 (uint) n_q_required)
8507 || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
8508 if ((sta =
8509 AscSendScsiQueue(asc_dvc, scsiq,
8510 n_q_required)) == 1) {
8511 asc_dvc->in_critical_cnt--;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008512 DvcLeaveCritical(last_int_level);
8513 return (sta);
8514 }
8515 }
8516 } else {
8517 if (asc_dvc->bug_fix_cntl) {
8518 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
8519 if ((scsi_cmd == READ_6) ||
8520 (scsi_cmd == READ_10)) {
8521 addr =
8522 le32_to_cpu(scsiq->q1.data_addr) +
8523 le32_to_cpu(scsiq->q1.data_cnt);
8524 extra_bytes =
8525 (uchar)((ushort)addr & 0x0003);
8526 if ((extra_bytes != 0)
8527 &&
8528 ((scsiq->q2.
8529 tag_code &
8530 ASC_TAG_FLAG_EXTRA_BYTES)
8531 == 0)) {
8532 data_cnt =
8533 le32_to_cpu(scsiq->q1.
8534 data_cnt);
8535 if (((ushort)data_cnt & 0x01FF)
8536 == 0) {
8537 scsiq->q2.tag_code |=
8538 ASC_TAG_FLAG_EXTRA_BYTES;
8539 data_cnt -= (ASC_DCNT)
8540 extra_bytes;
8541 scsiq->q1.data_cnt =
8542 cpu_to_le32
8543 (data_cnt);
8544 scsiq->q1.extra_bytes =
8545 extra_bytes;
8546 }
8547 }
8548 }
8549 }
8550 }
8551 n_q_required = 1;
8552 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) ||
8553 ((scsiq->q1.cntl & QC_URGENT) != 0)) {
8554 if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
8555 n_q_required)) == 1) {
8556 asc_dvc->in_critical_cnt--;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008557 DvcLeaveCritical(last_int_level);
8558 return (sta);
8559 }
8560 }
8561 }
8562 asc_dvc->in_critical_cnt--;
8563 DvcLeaveCritical(last_int_level);
8564 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008565}
8566
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008567static int
8568AscSendScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar n_q_required)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008569{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008570 PortAddr iop_base;
8571 uchar free_q_head;
8572 uchar next_qp;
8573 uchar tid_no;
8574 uchar target_ix;
8575 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008576
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008577 iop_base = asc_dvc->iop_base;
8578 target_ix = scsiq->q2.target_ix;
8579 tid_no = ASC_TIX_TO_TID(target_ix);
8580 sta = 0;
8581 free_q_head = (uchar)AscGetVarFreeQHead(iop_base);
8582 if (n_q_required > 1) {
8583 if ((next_qp = AscAllocMultipleFreeQueue(iop_base,
8584 free_q_head, (uchar)
8585 (n_q_required)))
8586 != (uchar)ASC_QLINK_END) {
8587 asc_dvc->last_q_shortage = 0;
8588 scsiq->sg_head->queue_cnt = n_q_required - 1;
8589 scsiq->q1.q_no = free_q_head;
8590 if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq,
8591 free_q_head)) == 1) {
8592 AscPutVarFreeQHead(iop_base, next_qp);
8593 asc_dvc->cur_total_qng += (uchar)(n_q_required);
8594 asc_dvc->cur_dvc_qng[tid_no]++;
8595 }
8596 return (sta);
8597 }
8598 } else if (n_q_required == 1) {
8599 if ((next_qp = AscAllocFreeQueue(iop_base,
8600 free_q_head)) !=
8601 ASC_QLINK_END) {
8602 scsiq->q1.q_no = free_q_head;
8603 if ((sta = AscPutReadyQueue(asc_dvc, scsiq,
8604 free_q_head)) == 1) {
8605 AscPutVarFreeQHead(iop_base, next_qp);
8606 asc_dvc->cur_total_qng++;
8607 asc_dvc->cur_dvc_qng[tid_no]++;
8608 }
8609 return (sta);
8610 }
8611 }
8612 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008613}
8614
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008615static int AscSgListToQueue(int sg_list)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008616{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008617 int n_sg_list_qs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008618
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008619 n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q);
8620 if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0)
8621 n_sg_list_qs++;
8622 return (n_sg_list_qs + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008623}
8624
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008625static uint
8626AscGetNumOfFreeQueue(ASC_DVC_VAR *asc_dvc, uchar target_ix, uchar n_qs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008627{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008628 uint cur_used_qs;
8629 uint cur_free_qs;
8630 ASC_SCSI_BIT_ID_TYPE target_id;
8631 uchar tid_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008632
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008633 target_id = ASC_TIX_TO_TARGET_ID(target_ix);
8634 tid_no = ASC_TIX_TO_TID(target_ix);
8635 if ((asc_dvc->unit_not_ready & target_id) ||
8636 (asc_dvc->queue_full_or_busy & target_id)) {
8637 return (0);
8638 }
8639 if (n_qs == 1) {
8640 cur_used_qs = (uint) asc_dvc->cur_total_qng +
8641 (uint) asc_dvc->last_q_shortage + (uint) ASC_MIN_FREE_Q;
8642 } else {
8643 cur_used_qs = (uint) asc_dvc->cur_total_qng +
8644 (uint) ASC_MIN_FREE_Q;
8645 }
8646 if ((uint) (cur_used_qs + n_qs) <= (uint) asc_dvc->max_total_qng) {
8647 cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs;
8648 if (asc_dvc->cur_dvc_qng[tid_no] >=
8649 asc_dvc->max_dvc_qng[tid_no]) {
8650 return (0);
8651 }
8652 return (cur_free_qs);
8653 }
8654 if (n_qs > 1) {
8655 if ((n_qs > asc_dvc->last_q_shortage)
8656 && (n_qs <= (asc_dvc->max_total_qng - ASC_MIN_FREE_Q))) {
8657 asc_dvc->last_q_shortage = n_qs;
8658 }
8659 }
8660 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008661}
8662
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008663static int AscPutReadyQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008664{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008665 ushort q_addr;
8666 uchar tid_no;
8667 uchar sdtr_data;
8668 uchar syn_period_ix;
8669 uchar syn_offset;
8670 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008671
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008672 iop_base = asc_dvc->iop_base;
8673 if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) &&
8674 ((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) {
8675 tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix);
8676 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
8677 syn_period_ix =
8678 (sdtr_data >> 4) & (asc_dvc->max_sdtr_index - 1);
8679 syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET;
8680 AscMsgOutSDTR(asc_dvc,
8681 asc_dvc->sdtr_period_tbl[syn_period_ix],
8682 syn_offset);
8683 scsiq->q1.cntl |= QC_MSG_OUT;
8684 }
8685 q_addr = ASC_QNO_TO_QADDR(q_no);
8686 if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) {
8687 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
8688 }
8689 scsiq->q1.status = QS_FREE;
8690 AscMemWordCopyPtrToLram(iop_base,
8691 q_addr + ASC_SCSIQ_CDB_BEG,
8692 (uchar *)scsiq->cdbptr, scsiq->q2.cdb_len >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008693
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008694 DvcPutScsiQ(iop_base,
8695 q_addr + ASC_SCSIQ_CPY_BEG,
8696 (uchar *)&scsiq->q1.cntl,
8697 ((sizeof(ASC_SCSIQ_1) + sizeof(ASC_SCSIQ_2)) / 2) - 1);
8698 AscWriteLramWord(iop_base,
8699 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS),
8700 (ushort)(((ushort)scsiq->q1.
8701 q_no << 8) | (ushort)QS_READY));
8702 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008703}
8704
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008705static int
8706AscPutReadySgListQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008707{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008708 int sta;
8709 int i;
8710 ASC_SG_HEAD *sg_head;
8711 ASC_SG_LIST_Q scsi_sg_q;
8712 ASC_DCNT saved_data_addr;
8713 ASC_DCNT saved_data_cnt;
8714 PortAddr iop_base;
8715 ushort sg_list_dwords;
8716 ushort sg_index;
8717 ushort sg_entry_cnt;
8718 ushort q_addr;
8719 uchar next_qp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008720
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008721 iop_base = asc_dvc->iop_base;
8722 sg_head = scsiq->sg_head;
8723 saved_data_addr = scsiq->q1.data_addr;
8724 saved_data_cnt = scsiq->q1.data_cnt;
8725 scsiq->q1.data_addr = (ASC_PADDR) sg_head->sg_list[0].addr;
8726 scsiq->q1.data_cnt = (ASC_DCNT) sg_head->sg_list[0].bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008727#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008728 /*
8729 * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST
8730 * then not all SG elements will fit in the allocated queues.
8731 * The rest of the SG elements will be copied when the RISC
8732 * completes the SG elements that fit and halts.
8733 */
8734 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
8735 /*
8736 * Set sg_entry_cnt to be the number of SG elements that
8737 * will fit in the allocated SG queues. It is minus 1, because
8738 * the first SG element is handled above. ASC_MAX_SG_LIST is
8739 * already inflated by 1 to account for this. For example it
8740 * may be 50 which is 1 + 7 queues * 7 SG elements.
8741 */
8742 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008743
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008744 /*
8745 * Keep track of remaining number of SG elements that will
8746 * need to be handled from a_isr.c.
8747 */
8748 scsiq->remain_sg_entry_cnt =
8749 sg_head->entry_cnt - ASC_MAX_SG_LIST;
8750 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008751#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008752 /*
8753 * Set sg_entry_cnt to be the number of SG elements that
8754 * will fit in the allocated SG queues. It is minus 1, because
8755 * the first SG element is handled above.
8756 */
8757 sg_entry_cnt = sg_head->entry_cnt - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008758#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008759 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008760#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008761 if (sg_entry_cnt != 0) {
8762 scsiq->q1.cntl |= QC_SG_HEAD;
8763 q_addr = ASC_QNO_TO_QADDR(q_no);
8764 sg_index = 1;
8765 scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
8766 scsi_sg_q.sg_head_qp = q_no;
8767 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
8768 for (i = 0; i < sg_head->queue_cnt; i++) {
8769 scsi_sg_q.seq_no = i + 1;
8770 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
8771 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
8772 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
8773 if (i == 0) {
8774 scsi_sg_q.sg_list_cnt =
8775 ASC_SG_LIST_PER_Q;
8776 scsi_sg_q.sg_cur_list_cnt =
8777 ASC_SG_LIST_PER_Q;
8778 } else {
8779 scsi_sg_q.sg_list_cnt =
8780 ASC_SG_LIST_PER_Q - 1;
8781 scsi_sg_q.sg_cur_list_cnt =
8782 ASC_SG_LIST_PER_Q - 1;
8783 }
8784 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008785#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008786 /*
8787 * This is the last SG queue in the list of
8788 * allocated SG queues. If there are more
8789 * SG elements than will fit in the allocated
8790 * queues, then set the QCSG_SG_XFER_MORE flag.
8791 */
8792 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
8793 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
8794 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008795#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008796 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008797#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008798 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008799#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008800 sg_list_dwords = sg_entry_cnt << 1;
8801 if (i == 0) {
8802 scsi_sg_q.sg_list_cnt = sg_entry_cnt;
8803 scsi_sg_q.sg_cur_list_cnt =
8804 sg_entry_cnt;
8805 } else {
8806 scsi_sg_q.sg_list_cnt =
8807 sg_entry_cnt - 1;
8808 scsi_sg_q.sg_cur_list_cnt =
8809 sg_entry_cnt - 1;
8810 }
8811 sg_entry_cnt = 0;
8812 }
8813 next_qp = AscReadLramByte(iop_base,
8814 (ushort)(q_addr +
8815 ASC_SCSIQ_B_FWD));
8816 scsi_sg_q.q_no = next_qp;
8817 q_addr = ASC_QNO_TO_QADDR(next_qp);
8818 AscMemWordCopyPtrToLram(iop_base,
8819 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
8820 (uchar *)&scsi_sg_q,
8821 sizeof(ASC_SG_LIST_Q) >> 1);
8822 AscMemDWordCopyPtrToLram(iop_base,
8823 q_addr + ASC_SGQ_LIST_BEG,
8824 (uchar *)&sg_head->
8825 sg_list[sg_index],
8826 sg_list_dwords);
8827 sg_index += ASC_SG_LIST_PER_Q;
8828 scsiq->next_sg_index = sg_index;
8829 }
8830 } else {
8831 scsiq->q1.cntl &= ~QC_SG_HEAD;
8832 }
8833 sta = AscPutReadyQueue(asc_dvc, scsiq, q_no);
8834 scsiq->q1.data_addr = saved_data_addr;
8835 scsiq->q1.data_cnt = saved_data_cnt;
8836 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008837}
8838
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008839static int
8840AscSetRunChipSynRegAtID(PortAddr iop_base, uchar tid_no, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008841{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008842 int sta = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008843
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008844 if (AscHostReqRiscHalt(iop_base)) {
8845 sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
8846 AscStartChip(iop_base);
8847 return (sta);
8848 }
8849 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008850}
8851
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008852static int AscSetChipSynRegAtID(PortAddr iop_base, uchar id, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008853{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008854 ASC_SCSI_BIT_ID_TYPE org_id;
8855 int i;
8856 int sta = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008857
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008858 AscSetBank(iop_base, 1);
8859 org_id = AscReadChipDvcID(iop_base);
8860 for (i = 0; i <= ASC_MAX_TID; i++) {
8861 if (org_id == (0x01 << i))
8862 break;
8863 }
8864 org_id = (ASC_SCSI_BIT_ID_TYPE) i;
8865 AscWriteChipDvcID(iop_base, id);
8866 if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
8867 AscSetBank(iop_base, 0);
8868 AscSetChipSyn(iop_base, sdtr_data);
8869 if (AscGetChipSyn(iop_base) != sdtr_data) {
8870 sta = FALSE;
8871 }
8872 } else {
8873 sta = FALSE;
8874 }
8875 AscSetBank(iop_base, 1);
8876 AscWriteChipDvcID(iop_base, org_id);
8877 AscSetBank(iop_base, 0);
8878 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008879}
8880
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008881static ushort AscInitLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008882{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008883 uchar i;
8884 ushort s_addr;
8885 PortAddr iop_base;
8886 ushort warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008887
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008888 iop_base = asc_dvc->iop_base;
8889 warn_code = 0;
8890 AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0,
8891 (ushort)(((int)(asc_dvc->max_total_qng + 2 + 1) *
8892 64) >> 1)
8893 );
8894 i = ASC_MIN_ACTIVE_QNO;
8895 s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE;
8896 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
8897 (uchar)(i + 1));
8898 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
8899 (uchar)(asc_dvc->max_total_qng));
8900 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
8901 (uchar)i);
8902 i++;
8903 s_addr += ASC_QBLK_SIZE;
8904 for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) {
8905 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
8906 (uchar)(i + 1));
8907 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
8908 (uchar)(i - 1));
8909 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
8910 (uchar)i);
8911 }
8912 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
8913 (uchar)ASC_QLINK_END);
8914 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
8915 (uchar)(asc_dvc->max_total_qng - 1));
8916 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
8917 (uchar)asc_dvc->max_total_qng);
8918 i++;
8919 s_addr += ASC_QBLK_SIZE;
8920 for (; i <= (uchar)(asc_dvc->max_total_qng + 3);
8921 i++, s_addr += ASC_QBLK_SIZE) {
8922 AscWriteLramByte(iop_base,
8923 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_FWD), i);
8924 AscWriteLramByte(iop_base,
8925 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_BWD), i);
8926 AscWriteLramByte(iop_base,
8927 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_QNO), i);
8928 }
8929 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008930}
8931
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008932static ushort AscInitQLinkVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008933{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008934 PortAddr iop_base;
8935 int i;
8936 ushort lram_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008937
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008938 iop_base = asc_dvc->iop_base;
8939 AscPutRiscVarFreeQHead(iop_base, 1);
8940 AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng);
8941 AscPutVarFreeQHead(iop_base, 1);
8942 AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng);
8943 AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B,
8944 (uchar)((int)asc_dvc->max_total_qng + 1));
8945 AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B,
8946 (uchar)((int)asc_dvc->max_total_qng + 2));
8947 AscWriteLramByte(iop_base, (ushort)ASCV_TOTAL_READY_Q_B,
8948 asc_dvc->max_total_qng);
8949 AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0);
8950 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8951 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
8952 AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0);
8953 AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0);
8954 AscPutQDoneInProgress(iop_base, 0);
8955 lram_addr = ASC_QADR_BEG;
8956 for (i = 0; i < 32; i++, lram_addr += 2) {
8957 AscWriteLramWord(iop_base, lram_addr, 0);
8958 }
8959 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008960}
8961
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008962static int AscSetLibErrorCode(ASC_DVC_VAR *asc_dvc, ushort err_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008963{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008964 if (asc_dvc->err_code == 0) {
8965 asc_dvc->err_code = err_code;
8966 AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W,
8967 err_code);
8968 }
8969 return (err_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008970}
8971
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008972static uchar
8973AscMsgOutSDTR(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar sdtr_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008974{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008975 EXT_MSG sdtr_buf;
8976 uchar sdtr_period_index;
8977 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008978
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008979 iop_base = asc_dvc->iop_base;
Matthew Wilcox47d853c2007-07-26 11:41:33 -04008980 sdtr_buf.msg_type = EXTENDED_MESSAGE;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008981 sdtr_buf.msg_len = MS_SDTR_LEN;
Matthew Wilcox47d853c2007-07-26 11:41:33 -04008982 sdtr_buf.msg_req = EXTENDED_SDTR;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008983 sdtr_buf.xfer_period = sdtr_period;
8984 sdtr_offset &= ASC_SYN_MAX_OFFSET;
8985 sdtr_buf.req_ack_offset = sdtr_offset;
8986 if ((sdtr_period_index =
8987 AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <=
8988 asc_dvc->max_sdtr_index) {
8989 AscMemWordCopyPtrToLram(iop_base,
8990 ASCV_MSGOUT_BEG,
8991 (uchar *)&sdtr_buf,
8992 sizeof(EXT_MSG) >> 1);
8993 return ((sdtr_period_index << 4) | sdtr_offset);
8994 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008995
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008996 sdtr_buf.req_ack_offset = 0;
8997 AscMemWordCopyPtrToLram(iop_base,
8998 ASCV_MSGOUT_BEG,
8999 (uchar *)&sdtr_buf,
9000 sizeof(EXT_MSG) >> 1);
9001 return (0);
9002 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009003}
9004
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009005static uchar
9006AscCalSDTRData(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar syn_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009007{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009008 uchar byte;
9009 uchar sdtr_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009010
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009011 sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
9012 if ((sdtr_period_ix > asc_dvc->max_sdtr_index)
9013 ) {
9014 return (0xFF);
9015 }
9016 byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET);
9017 return (byte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009018}
9019
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009020static void AscSetChipSDTR(PortAddr iop_base, uchar sdtr_data, uchar tid_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009021{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009022 AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
9023 AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data);
9024 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009025}
9026
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009027static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *asc_dvc, uchar syn_time)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009028{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009029 uchar *period_table;
9030 int max_index;
9031 int min_index;
9032 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009033
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009034 period_table = asc_dvc->sdtr_period_tbl;
9035 max_index = (int)asc_dvc->max_sdtr_index;
9036 min_index = (int)asc_dvc->host_init_sdtr_index;
9037 if ((syn_time <= period_table[max_index])) {
9038 for (i = min_index; i < (max_index - 1); i++) {
9039 if (syn_time <= period_table[i]) {
9040 return ((uchar)i);
9041 }
9042 }
9043 return ((uchar)max_index);
9044 } else {
9045 return ((uchar)(max_index + 1));
9046 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009047}
9048
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009049static uchar AscAllocFreeQueue(PortAddr iop_base, uchar free_q_head)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009050{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009051 ushort q_addr;
9052 uchar next_qp;
9053 uchar q_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009054
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009055 q_addr = ASC_QNO_TO_QADDR(free_q_head);
9056 q_status = (uchar)AscReadLramByte(iop_base,
9057 (ushort)(q_addr +
9058 ASC_SCSIQ_B_STATUS));
9059 next_qp = AscReadLramByte(iop_base, (ushort)(q_addr + ASC_SCSIQ_B_FWD));
9060 if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END)) {
9061 return (next_qp);
9062 }
9063 return (ASC_QLINK_END);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009064}
9065
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009066static uchar
9067AscAllocMultipleFreeQueue(PortAddr iop_base, uchar free_q_head, uchar n_free_q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009068{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009069 uchar i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009070
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009071 for (i = 0; i < n_free_q; i++) {
9072 if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head))
9073 == ASC_QLINK_END) {
9074 return (ASC_QLINK_END);
9075 }
9076 }
9077 return (free_q_head);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009078}
9079
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009080static int AscHostReqRiscHalt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009081{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009082 int count = 0;
9083 int sta = 0;
9084 uchar saved_stop_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009085
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009086 if (AscIsChipHalted(iop_base))
9087 return (1);
9088 saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
9089 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
9090 ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP);
9091 do {
9092 if (AscIsChipHalted(iop_base)) {
9093 sta = 1;
9094 break;
9095 }
9096 DvcSleepMilliSecond(100);
9097 } while (count++ < 20);
9098 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code);
9099 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009100}
9101
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009102static int AscStopQueueExe(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009103{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009104 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009105
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009106 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) {
9107 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
9108 ASC_STOP_REQ_RISC_STOP);
9109 do {
9110 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) &
9111 ASC_STOP_ACK_RISC_STOP) {
9112 return (1);
9113 }
9114 DvcSleepMilliSecond(100);
9115 } while (count++ < 20);
9116 }
9117 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009118}
9119
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009120static void DvcDelayMicroSecond(ADV_DVC_VAR *asc_dvc, ushort micro_sec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009121{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009122 udelay(micro_sec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009123}
9124
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009125static void DvcDelayNanoSecond(ASC_DVC_VAR *asc_dvc, ASC_DCNT nano_sec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009126{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009127 udelay((nano_sec + 999) / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009128}
9129
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009130static int AscStartChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009131{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009132 AscSetChipControl(iop_base, 0);
9133 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
9134 return (0);
9135 }
9136 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009137}
9138
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009139static int AscStopChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009140{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009141 uchar cc_val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009142
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009143 cc_val =
9144 AscGetChipControl(iop_base) &
9145 (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG));
9146 AscSetChipControl(iop_base, (uchar)(cc_val | CC_HALT));
9147 AscSetChipIH(iop_base, INS_HALT);
9148 AscSetChipIH(iop_base, INS_RFLAG_WTM);
9149 if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) {
9150 return (0);
9151 }
9152 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009153}
9154
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009155static int AscIsChipHalted(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009156{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009157 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
9158 if ((AscGetChipControl(iop_base) & CC_HALT) != 0) {
9159 return (1);
9160 }
9161 }
9162 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009163}
9164
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009165static void AscSetChipIH(PortAddr iop_base, ushort ins_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009166{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009167 AscSetBank(iop_base, 1);
9168 AscWriteChipIH(iop_base, ins_code);
9169 AscSetBank(iop_base, 0);
9170 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009171}
9172
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009173static void AscAckInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009174{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009175 uchar host_flag;
9176 uchar risc_flag;
9177 ushort loop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009178
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009179 loop = 0;
9180 do {
9181 risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B);
9182 if (loop++ > 0x7FFF) {
9183 break;
9184 }
9185 } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0);
9186 host_flag =
9187 AscReadLramByte(iop_base,
9188 ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT);
9189 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
9190 (uchar)(host_flag | ASC_HOST_FLAG_ACK_INT));
9191 AscSetChipStatus(iop_base, CIW_INT_ACK);
9192 loop = 0;
9193 while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) {
9194 AscSetChipStatus(iop_base, CIW_INT_ACK);
9195 if (loop++ > 3) {
9196 break;
9197 }
9198 }
9199 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
9200 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009201}
9202
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009203static void AscDisableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009204{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009205 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009206
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009207 cfg = AscGetChipCfgLsw(iop_base);
9208 AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON));
9209 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009210}
9211
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009212static void AscEnableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009213{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009214 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009215
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009216 cfg = AscGetChipCfgLsw(iop_base);
9217 AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON);
9218 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009219}
9220
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009221static void AscSetBank(PortAddr iop_base, uchar bank)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009222{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009223 uchar val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009224
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009225 val = AscGetChipControl(iop_base) &
9226 (~
9227 (CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET |
9228 CC_CHIP_RESET));
9229 if (bank == 1) {
9230 val |= CC_BANK_ONE;
9231 } else if (bank == 2) {
9232 val |= CC_DIAG | CC_BANK_ONE;
9233 } else {
9234 val &= ~CC_BANK_ONE;
9235 }
9236 AscSetChipControl(iop_base, val);
9237 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009238}
9239
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009240static int AscResetChipAndScsiBus(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009241{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009242 PortAddr iop_base;
9243 int i = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009244
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009245 iop_base = asc_dvc->iop_base;
9246 while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE)
9247 && (i-- > 0)) {
9248 DvcSleepMilliSecond(100);
9249 }
9250 AscStopChip(iop_base);
9251 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
9252 DvcDelayNanoSecond(asc_dvc, 60000);
9253 AscSetChipIH(iop_base, INS_RFLAG_WTM);
9254 AscSetChipIH(iop_base, INS_HALT);
9255 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT);
9256 AscSetChipControl(iop_base, CC_HALT);
9257 DvcSleepMilliSecond(200);
9258 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
9259 AscSetChipStatus(iop_base, 0);
9260 return (AscIsChipHalted(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -07009261}
9262
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009263static ASC_DCNT __devinit AscGetMaxDmaCount(ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009264{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009265 if (bus_type & ASC_IS_ISA)
9266 return (ASC_MAX_ISA_DMA_COUNT);
9267 else if (bus_type & (ASC_IS_EISA | ASC_IS_VL))
9268 return (ASC_MAX_VL_DMA_COUNT);
9269 return (ASC_MAX_PCI_DMA_COUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009270}
9271
9272#ifdef CONFIG_ISA
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009273static ushort __devinit AscGetIsaDmaChannel(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009274{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009275 ushort channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009276
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009277 channel = AscGetChipCfgLsw(iop_base) & 0x0003;
9278 if (channel == 0x03)
9279 return (0);
9280 else if (channel == 0x00)
9281 return (7);
9282 return (channel + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009283}
9284
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009285static ushort __devinit AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009286{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009287 ushort cfg_lsw;
9288 uchar value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009289
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009290 if ((dma_channel >= 5) && (dma_channel <= 7)) {
9291 if (dma_channel == 7)
9292 value = 0x00;
9293 else
9294 value = dma_channel - 4;
9295 cfg_lsw = AscGetChipCfgLsw(iop_base) & 0xFFFC;
9296 cfg_lsw |= value;
9297 AscSetChipCfgLsw(iop_base, cfg_lsw);
9298 return (AscGetIsaDmaChannel(iop_base));
9299 }
9300 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009301}
9302
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009303static uchar __devinit AscSetIsaDmaSpeed(PortAddr iop_base, uchar speed_value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009304{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009305 speed_value &= 0x07;
9306 AscSetBank(iop_base, 1);
9307 AscWriteChipDmaSpeed(iop_base, speed_value);
9308 AscSetBank(iop_base, 0);
9309 return (AscGetIsaDmaSpeed(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -07009310}
9311
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009312static uchar __devinit AscGetIsaDmaSpeed(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009313{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009314 uchar speed_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009315
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009316 AscSetBank(iop_base, 1);
9317 speed_value = AscReadChipDmaSpeed(iop_base);
9318 speed_value &= 0x07;
9319 AscSetBank(iop_base, 0);
9320 return (speed_value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009321}
9322#endif /* CONFIG_ISA */
9323
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06009324static int __devinit AscInitGetConfig(asc_board_t *boardp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009325{
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06009326 ASC_DVC_VAR *asc_dvc = &boardp->dvc_var.asc_dvc_var;
Matthew Wilcox9649af32007-07-26 21:51:47 -06009327 unsigned short warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009328
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009329 asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG;
Matthew Wilcox9649af32007-07-26 21:51:47 -06009330 if (asc_dvc->err_code != 0)
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06009331 return asc_dvc->err_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009332
Matthew Wilcox9649af32007-07-26 21:51:47 -06009333 if (AscFindSignature(asc_dvc->iop_base)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009334 warn_code |= AscInitAscDvcVar(asc_dvc);
9335 warn_code |= AscInitFromEEP(asc_dvc);
9336 asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06009337 if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009338 asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009339 } else {
9340 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
9341 }
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06009342
9343 switch (warn_code) {
9344 case 0: /* No error */
9345 break;
9346 case ASC_WARN_IO_PORT_ROTATE:
9347 ASC_PRINT1("AscInitGetConfig: board %d: I/O port address "
9348 "modified\n", boardp->id);
9349 break;
9350 case ASC_WARN_AUTO_CONFIG:
9351 ASC_PRINT1("AscInitGetConfig: board %d: I/O port increment "
9352 "switch enabled\n", boardp->id);
9353 break;
9354 case ASC_WARN_EEPROM_CHKSUM:
9355 ASC_PRINT1("AscInitGetConfig: board %d: EEPROM checksum "
9356 "error\n", boardp->id);
9357 break;
9358 case ASC_WARN_IRQ_MODIFIED:
9359 ASC_PRINT1("AscInitGetConfig: board %d: IRQ modified\n",
9360 boardp->id);
9361 break;
9362 case ASC_WARN_CMD_QNG_CONFLICT:
9363 ASC_PRINT1("AscInitGetConfig: board %d: tag queuing enabled "
9364 "w/o disconnects\n", boardp->id);
9365 break;
9366 default:
9367 ASC_PRINT2("AscInitGetConfig: board %d: unknown warning: "
9368 "0x%x\n", boardp->id, warn_code);
9369 break;
9370 }
9371
9372 if (asc_dvc->err_code != 0) {
9373 ASC_PRINT3("AscInitGetConfig: board %d error: init_state 0x%x, "
9374 "err_code 0x%x\n", boardp->id, asc_dvc->init_state,
9375 asc_dvc->err_code);
9376 }
9377
9378 return asc_dvc->err_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009379}
9380
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06009381static int __devinit AscInitSetConfig(struct pci_dev *pdev, asc_board_t *boardp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009382{
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06009383 ASC_DVC_VAR *asc_dvc = &boardp->dvc_var.asc_dvc_var;
Matthew Wilcox394dbf32007-07-26 11:56:40 -04009384 PortAddr iop_base = asc_dvc->iop_base;
9385 unsigned short cfg_msw;
9386 unsigned short warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009387
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009388 asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG;
9389 if (asc_dvc->err_code != 0)
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06009390 return asc_dvc->err_code;
Matthew Wilcox394dbf32007-07-26 11:56:40 -04009391 if (!AscFindSignature(asc_dvc->iop_base)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009392 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06009393 return asc_dvc->err_code;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009394 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009395
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009396 cfg_msw = AscGetChipCfgMsw(iop_base);
9397 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06009398 cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009399 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
9400 AscSetChipCfgMsw(iop_base, cfg_msw);
9401 }
9402 if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) !=
9403 asc_dvc->cfg->cmd_qng_enabled) {
9404 asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled;
9405 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
9406 }
9407 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
9408 warn_code |= ASC_WARN_AUTO_CONFIG;
9409 }
9410 if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) {
9411 if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type)
9412 != asc_dvc->irq_no) {
9413 asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO;
9414 }
9415 }
Matthew Wilcox9649af32007-07-26 21:51:47 -06009416#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009417 if (asc_dvc->bus_type & ASC_IS_PCI) {
9418 cfg_msw &= 0xFFC0;
9419 AscSetChipCfgMsw(iop_base, cfg_msw);
9420 if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
9421 } else {
Matthew Wilcox9649af32007-07-26 21:51:47 -06009422 if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) ||
9423 (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009424 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
9425 asc_dvc->bug_fix_cntl |=
9426 ASC_BUG_FIX_ASYN_USE_SYN;
9427 }
9428 }
Matthew Wilcox9649af32007-07-26 21:51:47 -06009429 } else
9430#endif /* CONFIG_PCI */
9431 if (asc_dvc->bus_type == ASC_IS_ISAPNP) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009432 if (AscGetChipVersion(iop_base, asc_dvc->bus_type)
9433 == ASC_CHIP_VER_ASYN_BUG) {
9434 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
9435 }
9436 }
9437 if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) !=
9438 asc_dvc->cfg->chip_scsi_id) {
9439 asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID;
9440 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009441#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009442 if (asc_dvc->bus_type & ASC_IS_ISA) {
9443 AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel);
9444 AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed);
9445 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009446#endif /* CONFIG_ISA */
Matthew Wilcox394dbf32007-07-26 11:56:40 -04009447
9448 asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG;
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06009449
9450 switch (warn_code) {
9451 case 0: /* No error. */
9452 break;
9453 case ASC_WARN_IO_PORT_ROTATE:
9454 ASC_PRINT1("AscInitSetConfig: board %d: I/O port address "
9455 "modified\n", boardp->id);
9456 break;
9457 case ASC_WARN_AUTO_CONFIG:
9458 ASC_PRINT1("AscInitSetConfig: board %d: I/O port increment "
9459 "switch enabled\n", boardp->id);
9460 break;
9461 case ASC_WARN_EEPROM_CHKSUM:
9462 ASC_PRINT1("AscInitSetConfig: board %d: EEPROM checksum "
9463 "error\n", boardp->id);
9464 break;
9465 case ASC_WARN_IRQ_MODIFIED:
9466 ASC_PRINT1("AscInitSetConfig: board %d: IRQ modified\n",
9467 boardp->id);
9468 break;
9469 case ASC_WARN_CMD_QNG_CONFLICT:
9470 ASC_PRINT1("AscInitSetConfig: board %d: tag queuing w/o "
9471 "disconnects\n",
9472 boardp->id);
9473 break;
9474 default:
9475 ASC_PRINT2("AscInitSetConfig: board %d: unknown warning: "
9476 "0x%x\n", boardp->id, warn_code);
9477 break;
9478 }
9479
9480 if (asc_dvc->err_code != 0) {
9481 ASC_PRINT3("AscInitSetConfig: board %d error: init_state 0x%x, "
9482 "err_code 0x%x\n", boardp->id, asc_dvc->init_state,
9483 asc_dvc->err_code);
9484 }
9485
9486 return asc_dvc->err_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009487}
9488
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009489static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009490{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009491 ushort warn_code;
9492 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009493
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009494 iop_base = asc_dvc->iop_base;
9495 warn_code = 0;
9496 if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
9497 !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
9498 AscResetChipAndScsiBus(asc_dvc);
9499 DvcSleepMilliSecond((ASC_DCNT)
9500 ((ushort)asc_dvc->scsi_reset_wait * 1000));
9501 }
9502 asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
9503 if (asc_dvc->err_code != 0)
9504 return (UW_ERR);
9505 if (!AscFindSignature(asc_dvc->iop_base)) {
9506 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
9507 return (warn_code);
9508 }
9509 AscDisableInterrupt(iop_base);
9510 warn_code |= AscInitLram(asc_dvc);
9511 if (asc_dvc->err_code != 0)
9512 return (UW_ERR);
9513 ASC_DBG1(1, "AscInitAsc1000Driver: _asc_mcode_chksum 0x%lx\n",
9514 (ulong)_asc_mcode_chksum);
9515 if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf,
9516 _asc_mcode_size) != _asc_mcode_chksum) {
9517 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
9518 return (warn_code);
9519 }
9520 warn_code |= AscInitMicroCodeVar(asc_dvc);
9521 asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
9522 AscEnableInterrupt(iop_base);
9523 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009524}
9525
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009526static ushort __devinit AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009527{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009528 int i;
9529 PortAddr iop_base;
9530 ushort warn_code;
9531 uchar chip_version;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009532
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009533 iop_base = asc_dvc->iop_base;
9534 warn_code = 0;
9535 asc_dvc->err_code = 0;
9536 if ((asc_dvc->bus_type &
9537 (ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0) {
9538 asc_dvc->err_code |= ASC_IERR_NO_BUS_TYPE;
9539 }
9540 AscSetChipControl(iop_base, CC_HALT);
9541 AscSetChipStatus(iop_base, 0);
9542 asc_dvc->bug_fix_cntl = 0;
9543 asc_dvc->pci_fix_asyn_xfer = 0;
9544 asc_dvc->pci_fix_asyn_xfer_always = 0;
9545 /* asc_dvc->init_state initalized in AscInitGetConfig(). */
9546 asc_dvc->sdtr_done = 0;
9547 asc_dvc->cur_total_qng = 0;
9548 asc_dvc->is_in_int = 0;
9549 asc_dvc->in_critical_cnt = 0;
9550 asc_dvc->last_q_shortage = 0;
9551 asc_dvc->use_tagged_qng = 0;
9552 asc_dvc->no_scam = 0;
9553 asc_dvc->unit_not_ready = 0;
9554 asc_dvc->queue_full_or_busy = 0;
9555 asc_dvc->redo_scam = 0;
9556 asc_dvc->res2 = 0;
9557 asc_dvc->host_init_sdtr_index = 0;
9558 asc_dvc->cfg->can_tagged_qng = 0;
9559 asc_dvc->cfg->cmd_qng_enabled = 0;
9560 asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
9561 asc_dvc->init_sdtr = 0;
9562 asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG;
9563 asc_dvc->scsi_reset_wait = 3;
9564 asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET;
9565 asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
9566 asc_dvc->cfg->sdtr_enable = ASC_SCSI_WIDTH_BIT_SET;
9567 asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
9568 asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID;
9569 asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER;
9570 asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) |
9571 ASC_LIB_VERSION_MINOR;
9572 chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type);
9573 asc_dvc->cfg->chip_version = chip_version;
9574 asc_dvc->sdtr_period_tbl[0] = SYN_XFER_NS_0;
9575 asc_dvc->sdtr_period_tbl[1] = SYN_XFER_NS_1;
9576 asc_dvc->sdtr_period_tbl[2] = SYN_XFER_NS_2;
9577 asc_dvc->sdtr_period_tbl[3] = SYN_XFER_NS_3;
9578 asc_dvc->sdtr_period_tbl[4] = SYN_XFER_NS_4;
9579 asc_dvc->sdtr_period_tbl[5] = SYN_XFER_NS_5;
9580 asc_dvc->sdtr_period_tbl[6] = SYN_XFER_NS_6;
9581 asc_dvc->sdtr_period_tbl[7] = SYN_XFER_NS_7;
9582 asc_dvc->max_sdtr_index = 7;
9583 if ((asc_dvc->bus_type & ASC_IS_PCI) &&
9584 (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3150)) {
9585 asc_dvc->bus_type = ASC_IS_PCI_ULTRA;
9586 asc_dvc->sdtr_period_tbl[0] = SYN_ULTRA_XFER_NS_0;
9587 asc_dvc->sdtr_period_tbl[1] = SYN_ULTRA_XFER_NS_1;
9588 asc_dvc->sdtr_period_tbl[2] = SYN_ULTRA_XFER_NS_2;
9589 asc_dvc->sdtr_period_tbl[3] = SYN_ULTRA_XFER_NS_3;
9590 asc_dvc->sdtr_period_tbl[4] = SYN_ULTRA_XFER_NS_4;
9591 asc_dvc->sdtr_period_tbl[5] = SYN_ULTRA_XFER_NS_5;
9592 asc_dvc->sdtr_period_tbl[6] = SYN_ULTRA_XFER_NS_6;
9593 asc_dvc->sdtr_period_tbl[7] = SYN_ULTRA_XFER_NS_7;
9594 asc_dvc->sdtr_period_tbl[8] = SYN_ULTRA_XFER_NS_8;
9595 asc_dvc->sdtr_period_tbl[9] = SYN_ULTRA_XFER_NS_9;
9596 asc_dvc->sdtr_period_tbl[10] = SYN_ULTRA_XFER_NS_10;
9597 asc_dvc->sdtr_period_tbl[11] = SYN_ULTRA_XFER_NS_11;
9598 asc_dvc->sdtr_period_tbl[12] = SYN_ULTRA_XFER_NS_12;
9599 asc_dvc->sdtr_period_tbl[13] = SYN_ULTRA_XFER_NS_13;
9600 asc_dvc->sdtr_period_tbl[14] = SYN_ULTRA_XFER_NS_14;
9601 asc_dvc->sdtr_period_tbl[15] = SYN_ULTRA_XFER_NS_15;
9602 asc_dvc->max_sdtr_index = 15;
9603 if (chip_version == ASC_CHIP_VER_PCI_ULTRA_3150) {
9604 AscSetExtraControl(iop_base,
9605 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
9606 } else if (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3050) {
9607 AscSetExtraControl(iop_base,
9608 (SEC_ACTIVE_NEGATE |
9609 SEC_ENABLE_FILTER));
9610 }
9611 }
9612 if (asc_dvc->bus_type == ASC_IS_PCI) {
9613 AscSetExtraControl(iop_base,
9614 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
9615 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009616
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009617 asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009618#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009619 if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) {
Matthew Wilcox59fcf842007-07-26 11:54:15 -04009620 if (chip_version >= ASC_CHIP_MIN_VER_ISA_PNP) {
9621 AscSetChipIFC(iop_base, IFC_INIT_DEFAULT);
9622 asc_dvc->bus_type = ASC_IS_ISAPNP;
9623 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009624 asc_dvc->cfg->isa_dma_channel =
9625 (uchar)AscGetIsaDmaChannel(iop_base);
9626 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009627#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009628 for (i = 0; i <= ASC_MAX_TID; i++) {
9629 asc_dvc->cur_dvc_qng[i] = 0;
9630 asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG;
9631 asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q *)0L;
9632 asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q *)0L;
9633 asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG;
9634 }
9635 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009636}
9637
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009638static ushort __devinit AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009639{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009640 ASCEEP_CONFIG eep_config_buf;
9641 ASCEEP_CONFIG *eep_config;
9642 PortAddr iop_base;
9643 ushort chksum;
9644 ushort warn_code;
9645 ushort cfg_msw, cfg_lsw;
9646 int i;
9647 int write_eep = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009648
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009649 iop_base = asc_dvc->iop_base;
9650 warn_code = 0;
9651 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE);
9652 AscStopQueueExe(iop_base);
9653 if ((AscStopChip(iop_base) == FALSE) ||
9654 (AscGetChipScsiCtrl(iop_base) != 0)) {
9655 asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
9656 AscResetChipAndScsiBus(asc_dvc);
9657 DvcSleepMilliSecond((ASC_DCNT)
9658 ((ushort)asc_dvc->scsi_reset_wait * 1000));
9659 }
9660 if (AscIsChipHalted(iop_base) == FALSE) {
9661 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
9662 return (warn_code);
9663 }
9664 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
9665 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
9666 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
9667 return (warn_code);
9668 }
9669 eep_config = (ASCEEP_CONFIG *)&eep_config_buf;
9670 cfg_msw = AscGetChipCfgMsw(iop_base);
9671 cfg_lsw = AscGetChipCfgLsw(iop_base);
9672 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -06009673 cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009674 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
9675 AscSetChipCfgMsw(iop_base, cfg_msw);
9676 }
9677 chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
9678 ASC_DBG1(1, "AscInitFromEEP: chksum 0x%x\n", chksum);
9679 if (chksum == 0) {
9680 chksum = 0xaa55;
9681 }
9682 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
9683 warn_code |= ASC_WARN_AUTO_CONFIG;
9684 if (asc_dvc->cfg->chip_version == 3) {
9685 if (eep_config->cfg_lsw != cfg_lsw) {
9686 warn_code |= ASC_WARN_EEPROM_RECOVER;
9687 eep_config->cfg_lsw =
9688 AscGetChipCfgLsw(iop_base);
9689 }
9690 if (eep_config->cfg_msw != cfg_msw) {
9691 warn_code |= ASC_WARN_EEPROM_RECOVER;
9692 eep_config->cfg_msw =
9693 AscGetChipCfgMsw(iop_base);
9694 }
9695 }
9696 }
9697 eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
9698 eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
9699 ASC_DBG1(1, "AscInitFromEEP: eep_config->chksum 0x%x\n",
9700 eep_config->chksum);
9701 if (chksum != eep_config->chksum) {
9702 if (AscGetChipVersion(iop_base, asc_dvc->bus_type) ==
9703 ASC_CHIP_VER_PCI_ULTRA_3050) {
9704 ASC_DBG(1,
9705 "AscInitFromEEP: chksum error ignored; EEPROM-less board\n");
9706 eep_config->init_sdtr = 0xFF;
9707 eep_config->disc_enable = 0xFF;
9708 eep_config->start_motor = 0xFF;
9709 eep_config->use_cmd_qng = 0;
9710 eep_config->max_total_qng = 0xF0;
9711 eep_config->max_tag_qng = 0x20;
9712 eep_config->cntl = 0xBFFF;
9713 ASC_EEP_SET_CHIP_ID(eep_config, 7);
9714 eep_config->no_scam = 0;
9715 eep_config->adapter_info[0] = 0;
9716 eep_config->adapter_info[1] = 0;
9717 eep_config->adapter_info[2] = 0;
9718 eep_config->adapter_info[3] = 0;
9719 eep_config->adapter_info[4] = 0;
9720 /* Indicate EEPROM-less board. */
9721 eep_config->adapter_info[5] = 0xBB;
9722 } else {
9723 ASC_PRINT
9724 ("AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n");
9725 write_eep = 1;
9726 warn_code |= ASC_WARN_EEPROM_CHKSUM;
9727 }
9728 }
9729 asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr;
9730 asc_dvc->cfg->disc_enable = eep_config->disc_enable;
9731 asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
9732 asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config);
9733 asc_dvc->start_motor = eep_config->start_motor;
9734 asc_dvc->dvc_cntl = eep_config->cntl;
9735 asc_dvc->no_scam = eep_config->no_scam;
9736 asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0];
9737 asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1];
9738 asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2];
9739 asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3];
9740 asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4];
9741 asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5];
9742 if (!AscTestExternalLram(asc_dvc)) {
9743 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) ==
9744 ASC_IS_PCI_ULTRA)) {
9745 eep_config->max_total_qng =
9746 ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
9747 eep_config->max_tag_qng =
9748 ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG;
9749 } else {
9750 eep_config->cfg_msw |= 0x0800;
9751 cfg_msw |= 0x0800;
9752 AscSetChipCfgMsw(iop_base, cfg_msw);
9753 eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
9754 eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG;
9755 }
9756 } else {
9757 }
9758 if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) {
9759 eep_config->max_total_qng = ASC_MIN_TOTAL_QNG;
9760 }
9761 if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) {
9762 eep_config->max_total_qng = ASC_MAX_TOTAL_QNG;
9763 }
9764 if (eep_config->max_tag_qng > eep_config->max_total_qng) {
9765 eep_config->max_tag_qng = eep_config->max_total_qng;
9766 }
9767 if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) {
9768 eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC;
9769 }
9770 asc_dvc->max_total_qng = eep_config->max_total_qng;
9771 if ((eep_config->use_cmd_qng & eep_config->disc_enable) !=
9772 eep_config->use_cmd_qng) {
9773 eep_config->disc_enable = eep_config->use_cmd_qng;
9774 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
9775 }
9776 if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
9777 asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
9778 }
9779 ASC_EEP_SET_CHIP_ID(eep_config,
9780 ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID);
9781 asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config);
9782 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) &&
9783 !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
9784 asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
9785 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009786
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009787 for (i = 0; i <= ASC_MAX_TID; i++) {
9788 asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
9789 asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
9790 asc_dvc->cfg->sdtr_period_offset[i] =
9791 (uchar)(ASC_DEF_SDTR_OFFSET |
9792 (asc_dvc->host_init_sdtr_index << 4));
9793 }
9794 eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
9795 if (write_eep) {
9796 if ((i =
9797 AscSetEEPConfig(iop_base, eep_config,
9798 asc_dvc->bus_type)) != 0) {
9799 ASC_PRINT1
9800 ("AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n",
9801 i);
9802 } else {
9803 ASC_PRINT
9804 ("AscInitFromEEP: Successfully re-wrote EEPROM.\n");
9805 }
9806 }
9807 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009808}
9809
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009810static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009811{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009812 int i;
9813 ushort warn_code;
9814 PortAddr iop_base;
9815 ASC_PADDR phy_addr;
9816 ASC_DCNT phy_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009817
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009818 iop_base = asc_dvc->iop_base;
9819 warn_code = 0;
9820 for (i = 0; i <= ASC_MAX_TID; i++) {
9821 AscPutMCodeInitSDTRAtID(iop_base, i,
9822 asc_dvc->cfg->sdtr_period_offset[i]
9823 );
9824 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009825
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009826 AscInitQLinkVar(asc_dvc);
9827 AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
9828 asc_dvc->cfg->disc_enable);
9829 AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
9830 ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07009831
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009832 /* Align overrun buffer on an 8 byte boundary. */
9833 phy_addr = virt_to_bus(asc_dvc->cfg->overrun_buf);
9834 phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7);
9835 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
9836 (uchar *)&phy_addr, 1);
9837 phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE - 8);
9838 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D,
9839 (uchar *)&phy_size, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009840
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009841 asc_dvc->cfg->mcode_date =
9842 AscReadLramWord(iop_base, (ushort)ASCV_MC_DATE_W);
9843 asc_dvc->cfg->mcode_version =
9844 AscReadLramWord(iop_base, (ushort)ASCV_MC_VER_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009845
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009846 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
9847 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
9848 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
9849 return (warn_code);
9850 }
9851 if (AscStartChip(iop_base) != 1) {
9852 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
9853 return (warn_code);
9854 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009855
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009856 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009857}
9858
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009859static int __devinit AscTestExternalLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009860{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009861 PortAddr iop_base;
9862 ushort q_addr;
9863 ushort saved_word;
9864 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009865
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009866 iop_base = asc_dvc->iop_base;
9867 sta = 0;
9868 q_addr = ASC_QNO_TO_QADDR(241);
9869 saved_word = AscReadLramWord(iop_base, q_addr);
9870 AscSetChipLramAddr(iop_base, q_addr);
9871 AscSetChipLramData(iop_base, 0x55AA);
9872 DvcSleepMilliSecond(10);
9873 AscSetChipLramAddr(iop_base, q_addr);
9874 if (AscGetChipLramData(iop_base) == 0x55AA) {
9875 sta = 1;
9876 AscWriteLramWord(iop_base, q_addr, saved_word);
9877 }
9878 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009879}
9880
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009881static int __devinit AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009882{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009883 uchar read_back;
9884 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009885
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009886 retry = 0;
9887 while (TRUE) {
9888 AscSetChipEEPCmd(iop_base, cmd_reg);
9889 DvcSleepMilliSecond(1);
9890 read_back = AscGetChipEEPCmd(iop_base);
9891 if (read_back == cmd_reg) {
9892 return (1);
9893 }
9894 if (retry++ > ASC_EEP_MAX_RETRY) {
9895 return (0);
9896 }
9897 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009898}
9899
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009900static int __devinit AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009901{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009902 ushort read_back;
9903 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009904
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009905 retry = 0;
9906 while (TRUE) {
9907 AscSetChipEEPData(iop_base, data_reg);
9908 DvcSleepMilliSecond(1);
9909 read_back = AscGetChipEEPData(iop_base);
9910 if (read_back == data_reg) {
9911 return (1);
9912 }
9913 if (retry++ > ASC_EEP_MAX_RETRY) {
9914 return (0);
9915 }
9916 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009917}
9918
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009919static void __devinit AscWaitEEPRead(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009920{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009921 DvcSleepMilliSecond(1);
9922 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009923}
9924
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009925static void __devinit AscWaitEEPWrite(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009926{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009927 DvcSleepMilliSecond(20);
9928 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009929}
9930
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009931static ushort __devinit AscReadEEPWord(PortAddr iop_base, uchar addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009932{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009933 ushort read_wval;
9934 uchar cmd_reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009935
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009936 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
9937 AscWaitEEPRead();
9938 cmd_reg = addr | ASC_EEP_CMD_READ;
9939 AscWriteEEPCmdReg(iop_base, cmd_reg);
9940 AscWaitEEPRead();
9941 read_wval = AscGetChipEEPData(iop_base);
9942 AscWaitEEPRead();
9943 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009944}
9945
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009946static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009947AscWriteEEPWord(PortAddr iop_base, uchar addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009948{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009949 ushort read_wval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009950
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009951 read_wval = AscReadEEPWord(iop_base, addr);
9952 if (read_wval != word_val) {
9953 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE);
9954 AscWaitEEPRead();
9955 AscWriteEEPDataReg(iop_base, word_val);
9956 AscWaitEEPRead();
9957 AscWriteEEPCmdReg(iop_base,
9958 (uchar)((uchar)ASC_EEP_CMD_WRITE | addr));
9959 AscWaitEEPWrite();
9960 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
9961 AscWaitEEPRead();
9962 return (AscReadEEPWord(iop_base, addr));
9963 }
9964 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009965}
9966
Matthew Wilcox78e77d82007-07-29 21:46:15 -06009967static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009968AscGetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009969{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009970 ushort wval;
9971 ushort sum;
9972 ushort *wbuf;
9973 int cfg_beg;
9974 int cfg_end;
9975 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
9976 int s_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009977
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009978 wbuf = (ushort *)cfg_buf;
9979 sum = 0;
9980 /* Read two config words; Byte-swapping done by AscReadEEPWord(). */
9981 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
9982 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
9983 sum += *wbuf;
9984 }
9985 if (bus_type & ASC_IS_VL) {
9986 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
9987 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
9988 } else {
9989 cfg_beg = ASC_EEP_DVC_CFG_BEG;
9990 cfg_end = ASC_EEP_MAX_DVC_ADDR;
9991 }
9992 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
9993 wval = AscReadEEPWord(iop_base, (uchar)s_addr);
9994 if (s_addr <= uchar_end_in_config) {
9995 /*
9996 * Swap all char fields - must unswap bytes already swapped
9997 * by AscReadEEPWord().
9998 */
9999 *wbuf = le16_to_cpu(wval);
10000 } else {
10001 /* Don't swap word field at the end - cntl field. */
10002 *wbuf = wval;
10003 }
10004 sum += wval; /* Checksum treats all EEPROM data as words. */
10005 }
10006 /*
10007 * Read the checksum word which will be compared against 'sum'
10008 * by the caller. Word field already swapped.
10009 */
10010 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
10011 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010012}
10013
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010014static int __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010015AscSetEEPConfigOnce(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010016{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010017 int n_error;
10018 ushort *wbuf;
10019 ushort word;
10020 ushort sum;
10021 int s_addr;
10022 int cfg_beg;
10023 int cfg_end;
10024 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010025
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010026 wbuf = (ushort *)cfg_buf;
10027 n_error = 0;
10028 sum = 0;
10029 /* Write two config words; AscWriteEEPWord() will swap bytes. */
10030 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
10031 sum += *wbuf;
10032 if (*wbuf != AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
10033 n_error++;
10034 }
10035 }
10036 if (bus_type & ASC_IS_VL) {
10037 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
10038 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
10039 } else {
10040 cfg_beg = ASC_EEP_DVC_CFG_BEG;
10041 cfg_end = ASC_EEP_MAX_DVC_ADDR;
10042 }
10043 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
10044 if (s_addr <= uchar_end_in_config) {
10045 /*
10046 * This is a char field. Swap char fields before they are
10047 * swapped again by AscWriteEEPWord().
10048 */
10049 word = cpu_to_le16(*wbuf);
10050 if (word !=
10051 AscWriteEEPWord(iop_base, (uchar)s_addr, word)) {
10052 n_error++;
10053 }
10054 } else {
10055 /* Don't swap word field at the end - cntl field. */
10056 if (*wbuf !=
10057 AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
10058 n_error++;
10059 }
10060 }
10061 sum += *wbuf; /* Checksum calculated from word values. */
10062 }
10063 /* Write checksum word. It will be swapped by AscWriteEEPWord(). */
10064 *wbuf = sum;
10065 if (sum != AscWriteEEPWord(iop_base, (uchar)s_addr, sum)) {
10066 n_error++;
10067 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010068
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010069 /* Read EEPROM back again. */
10070 wbuf = (ushort *)cfg_buf;
10071 /*
10072 * Read two config words; Byte-swapping done by AscReadEEPWord().
10073 */
10074 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
10075 if (*wbuf != AscReadEEPWord(iop_base, (uchar)s_addr)) {
10076 n_error++;
10077 }
10078 }
10079 if (bus_type & ASC_IS_VL) {
10080 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
10081 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
10082 } else {
10083 cfg_beg = ASC_EEP_DVC_CFG_BEG;
10084 cfg_end = ASC_EEP_MAX_DVC_ADDR;
10085 }
10086 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
10087 if (s_addr <= uchar_end_in_config) {
10088 /*
10089 * Swap all char fields. Must unswap bytes already swapped
10090 * by AscReadEEPWord().
10091 */
10092 word =
10093 le16_to_cpu(AscReadEEPWord
10094 (iop_base, (uchar)s_addr));
10095 } else {
10096 /* Don't swap word field at the end - cntl field. */
10097 word = AscReadEEPWord(iop_base, (uchar)s_addr);
10098 }
10099 if (*wbuf != word) {
10100 n_error++;
10101 }
10102 }
10103 /* Read checksum; Byte swapping not needed. */
10104 if (AscReadEEPWord(iop_base, (uchar)s_addr) != sum) {
10105 n_error++;
10106 }
10107 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010108}
10109
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010110static int __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010111AscSetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010112{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010113 int retry;
10114 int n_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010115
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010116 retry = 0;
10117 while (TRUE) {
10118 if ((n_error = AscSetEEPConfigOnce(iop_base, cfg_buf,
10119 bus_type)) == 0) {
10120 break;
10121 }
10122 if (++retry > ASC_EEP_MAX_RETRY) {
10123 break;
10124 }
10125 }
10126 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010127}
10128
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010129static void AscAsyncFix(ASC_DVC_VAR *asc_dvc, struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010130{
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010131 char type = sdev->type;
10132 ASC_SCSI_BIT_ID_TYPE tid_bits = 1 << sdev->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010133
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010134 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) {
10135 if (!(asc_dvc->init_sdtr & tid_bits)) {
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010136 if ((type == TYPE_ROM) &&
10137 (strncmp(sdev->vendor, "HP ", 3) == 0)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010138 asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
10139 }
10140 asc_dvc->pci_fix_asyn_xfer |= tid_bits;
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010141 if ((type == TYPE_PROCESSOR) ||
10142 (type == TYPE_SCANNER) || (type == TYPE_ROM) ||
10143 (type == TYPE_TAPE)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010144 asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
10145 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010146
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010147 if (asc_dvc->pci_fix_asyn_xfer & tid_bits) {
10148 AscSetRunChipSynRegAtID(asc_dvc->iop_base,
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010149 sdev->id,
10150 ASYN_SDTR_DATA_FIX_PCI_REV_AB);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010151 }
10152 }
10153 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010154}
10155
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010156static uchar AscReadLramByte(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010157{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010158 uchar byte_data;
10159 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010160
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010161 if (isodd_word(addr)) {
10162 AscSetChipLramAddr(iop_base, addr - 1);
10163 word_data = AscGetChipLramData(iop_base);
10164 byte_data = (uchar)((word_data >> 8) & 0xFF);
10165 } else {
10166 AscSetChipLramAddr(iop_base, addr);
10167 word_data = AscGetChipLramData(iop_base);
10168 byte_data = (uchar)(word_data & 0xFF);
10169 }
10170 return (byte_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010171}
Linus Torvalds1da177e2005-04-16 15:20:36 -070010172
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010173static ushort AscReadLramWord(PortAddr iop_base, ushort addr)
10174{
10175 ushort word_data;
10176
10177 AscSetChipLramAddr(iop_base, addr);
10178 word_data = AscGetChipLramData(iop_base);
10179 return (word_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010180}
10181
10182#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010183static ASC_DCNT AscReadLramDWord(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010184{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010185 ushort val_low, val_high;
10186 ASC_DCNT dword_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010187
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010188 AscSetChipLramAddr(iop_base, addr);
10189 val_low = AscGetChipLramData(iop_base);
10190 val_high = AscGetChipLramData(iop_base);
10191 dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low;
10192 return (dword_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010193}
10194#endif /* CC_VERY_LONG_SG_LIST */
10195
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010196static void AscWriteLramWord(PortAddr iop_base, ushort addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010197{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010198 AscSetChipLramAddr(iop_base, addr);
10199 AscSetChipLramData(iop_base, word_val);
10200 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010201}
10202
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010203static void AscWriteLramByte(PortAddr iop_base, ushort addr, uchar byte_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010204{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010205 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010206
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010207 if (isodd_word(addr)) {
10208 addr--;
10209 word_data = AscReadLramWord(iop_base, addr);
10210 word_data &= 0x00FF;
10211 word_data |= (((ushort)byte_val << 8) & 0xFF00);
10212 } else {
10213 word_data = AscReadLramWord(iop_base, addr);
10214 word_data &= 0xFF00;
10215 word_data |= ((ushort)byte_val & 0x00FF);
10216 }
10217 AscWriteLramWord(iop_base, addr, word_data);
10218 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010219}
10220
10221/*
10222 * Copy 2 bytes to LRAM.
10223 *
10224 * The source data is assumed to be in little-endian order in memory
10225 * and is maintained in little-endian order when written to LRAM.
10226 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010227static void
10228AscMemWordCopyPtrToLram(PortAddr iop_base,
10229 ushort s_addr, uchar *s_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010230{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010231 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010232
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010233 AscSetChipLramAddr(iop_base, s_addr);
10234 for (i = 0; i < 2 * words; i += 2) {
10235 /*
10236 * On a little-endian system the second argument below
10237 * produces a little-endian ushort which is written to
10238 * LRAM in little-endian order. On a big-endian system
10239 * the second argument produces a big-endian ushort which
10240 * is "transparently" byte-swapped by outpw() and written
10241 * in little-endian order to LRAM.
10242 */
10243 outpw(iop_base + IOP_RAM_DATA,
10244 ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]);
10245 }
10246 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010247}
10248
10249/*
10250 * Copy 4 bytes to LRAM.
10251 *
10252 * The source data is assumed to be in little-endian order in memory
10253 * and is maintained in little-endian order when writen to LRAM.
10254 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010255static void
10256AscMemDWordCopyPtrToLram(PortAddr iop_base,
10257 ushort s_addr, uchar *s_buffer, int dwords)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010258{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010259 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010260
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010261 AscSetChipLramAddr(iop_base, s_addr);
10262 for (i = 0; i < 4 * dwords; i += 4) {
10263 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]); /* LSW */
10264 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 3] << 8) | s_buffer[i + 2]); /* MSW */
10265 }
10266 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010267}
10268
10269/*
10270 * Copy 2 bytes from LRAM.
10271 *
10272 * The source data is assumed to be in little-endian order in LRAM
10273 * and is maintained in little-endian order when written to memory.
10274 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010275static void
10276AscMemWordCopyPtrFromLram(PortAddr iop_base,
10277 ushort s_addr, uchar *d_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010278{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010279 int i;
10280 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010281
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010282 AscSetChipLramAddr(iop_base, s_addr);
10283 for (i = 0; i < 2 * words; i += 2) {
10284 word = inpw(iop_base + IOP_RAM_DATA);
10285 d_buffer[i] = word & 0xff;
10286 d_buffer[i + 1] = (word >> 8) & 0xff;
10287 }
10288 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010289}
10290
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010291static ASC_DCNT AscMemSumLramWord(PortAddr iop_base, ushort s_addr, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010292{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010293 ASC_DCNT sum;
10294 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010295
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010296 sum = 0L;
10297 for (i = 0; i < words; i++, s_addr += 2) {
10298 sum += AscReadLramWord(iop_base, s_addr);
10299 }
10300 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010301}
10302
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010303static void
10304AscMemWordSetLram(PortAddr iop_base, ushort s_addr, ushort set_wval, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010305{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010306 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010307
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010308 AscSetChipLramAddr(iop_base, s_addr);
10309 for (i = 0; i < words; i++) {
10310 AscSetChipLramData(iop_base, set_wval);
10311 }
10312 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010313}
10314
Linus Torvalds1da177e2005-04-16 15:20:36 -070010315/*
10316 * --- Adv Library Functions
10317 */
10318
10319/* a_mcode.h */
10320
10321/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010322static unsigned char _adv_asc3550_buf[] = {
10323 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x18, 0xe4, 0x00, 0xfc,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010324 0x01, 0x00, 0x48, 0xe4, 0xbe, 0x18, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00,
10325 0x00, 0xfa, 0xff, 0xff, 0x28, 0x0e, 0x9e, 0xe7, 0xff, 0x00, 0x82, 0xe7,
10326 0x00, 0xea, 0x00, 0xf6, 0x01, 0xe6, 0x09, 0xe7, 0x55, 0xf0, 0x01, 0xf6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010327 0x01, 0xfa, 0x08, 0x00, 0x03, 0x00, 0x04, 0x00, 0x18, 0xf4, 0x10, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010328 0x00, 0xec, 0x85, 0xf0, 0xbc, 0x00, 0xd5, 0xf0, 0x8e, 0x0c, 0x38, 0x54,
10329 0x00, 0xe6, 0x1e, 0xf0, 0x86, 0xf0, 0xb4, 0x00, 0x98, 0x57, 0xd0, 0x01,
10330 0x0c, 0x1c, 0x3e, 0x1c, 0x0c, 0x00, 0xbb, 0x00, 0xaa, 0x18, 0x02, 0x80,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010331 0x32, 0xf0, 0x01, 0xfc, 0x88, 0x0c, 0xc6, 0x12, 0x02, 0x13, 0x18, 0x40,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010332 0x00, 0x57, 0x01, 0xea, 0x3c, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12,
10333 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00, 0xc0, 0x00, 0x01, 0x01,
10334 0x3e, 0x01, 0xda, 0x0f, 0x22, 0x10, 0x08, 0x12, 0x02, 0x4a, 0xb9, 0x54,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010335 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x20, 0x00, 0x32, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010336 0x3e, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01,
10337 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01, 0x78, 0x01, 0x62, 0x0a,
10338 0x92, 0x0c, 0x2c, 0x10, 0x2e, 0x10, 0x06, 0x13, 0x4c, 0x1c, 0xbb, 0x55,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010339 0x3c, 0x56, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0xb1, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010340 0x03, 0xf7, 0x06, 0xf7, 0x03, 0xfc, 0x0f, 0x00, 0x40, 0x00, 0xbe, 0x00,
10341 0x00, 0x01, 0xb0, 0x08, 0x30, 0x13, 0x64, 0x15, 0x32, 0x1c, 0x38, 0x1c,
10342 0x4e, 0x1c, 0x10, 0x44, 0x02, 0x48, 0x00, 0x4c, 0x04, 0xea, 0x5d, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010343 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010344 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x4e, 0x0b, 0x1e, 0x0e, 0x0c, 0x10,
10345 0x0a, 0x12, 0x04, 0x13, 0x40, 0x13, 0x30, 0x1c, 0x00, 0x4e, 0xbd, 0x56,
10346 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0, 0x59, 0xf0, 0xa7, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010347 0xb8, 0xf0, 0x0e, 0xf7, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010348 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00,
10349 0xde, 0x03, 0x56, 0x0a, 0x14, 0x0e, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10,
10350 0x36, 0x10, 0x0a, 0x13, 0x12, 0x13, 0x52, 0x13, 0x10, 0x15, 0x14, 0x15,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010351 0xac, 0x16, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010352 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x83, 0x55,
10353 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0, 0x0c, 0xf0,
10354 0x5c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010355 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x1c, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010356 0x9e, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01,
10357 0x26, 0x01, 0x79, 0x01, 0x7a, 0x01, 0xc0, 0x01, 0xc2, 0x01, 0x7c, 0x02,
10358 0x5a, 0x03, 0xea, 0x04, 0xe8, 0x07, 0x68, 0x08, 0x69, 0x08, 0xba, 0x08,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010359 0xe9, 0x09, 0x06, 0x0b, 0x3a, 0x0e, 0x00, 0x10, 0x1a, 0x10, 0xed, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010360 0xf1, 0x10, 0x06, 0x12, 0x0c, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x82, 0x13,
10361 0x42, 0x14, 0xd6, 0x14, 0x8a, 0x15, 0xc6, 0x17, 0xd2, 0x17, 0x6b, 0x18,
10362 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0x48, 0x47,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010363 0x41, 0x48, 0x89, 0x48, 0x80, 0x4c, 0x00, 0x54, 0x44, 0x55, 0xe5, 0x55,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010364 0x14, 0x56, 0x77, 0x57, 0xbf, 0x57, 0x40, 0x5c, 0x06, 0x80, 0x08, 0x90,
10365 0x03, 0xa1, 0xfe, 0x9c, 0xf0, 0x29, 0x02, 0xfe, 0xb8, 0x0c, 0xff, 0x10,
10366 0x00, 0x00, 0xd0, 0xfe, 0xcc, 0x18, 0x00, 0xcf, 0xfe, 0x80, 0x01, 0xff,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010367 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010368 0x00, 0xfe, 0x57, 0x24, 0x00, 0xfe, 0x48, 0x00, 0x4f, 0xff, 0x04, 0x00,
10369 0x00, 0x10, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x08,
10370 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x0f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010371 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010372 0xfe, 0x04, 0xf7, 0xcf, 0x2a, 0x67, 0x0b, 0x01, 0xfe, 0xce, 0x0e, 0xfe,
10373 0x04, 0xf7, 0xcf, 0x67, 0x0b, 0x3c, 0x2a, 0xfe, 0x3d, 0xf0, 0xfe, 0x02,
10374 0x02, 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x91, 0xf0, 0xfe, 0xf0, 0x01, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010375 0x90, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, 0x8f, 0xf0, 0x9c, 0x05, 0x51, 0x3b,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010376 0x02, 0xfe, 0xd4, 0x0c, 0x01, 0xfe, 0x44, 0x0d, 0xfe, 0xdd, 0x12, 0xfe,
10377 0xfc, 0x10, 0xfe, 0x28, 0x1c, 0x05, 0xfe, 0xa6, 0x00, 0xfe, 0xd3, 0x12,
10378 0x47, 0x18, 0xfe, 0xa6, 0x00, 0xb5, 0xfe, 0x48, 0xf0, 0xfe, 0x86, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010379 0xfe, 0x49, 0xf0, 0xfe, 0xa0, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xbe, 0x02,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010380 0xfe, 0x46, 0xf0, 0xfe, 0x50, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x56, 0x02,
10381 0xfe, 0x43, 0xf0, 0xfe, 0x44, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x48, 0x02,
10382 0xfe, 0x45, 0xf0, 0xfe, 0x4c, 0x02, 0x17, 0x0b, 0xa0, 0x17, 0x06, 0x18,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010383 0x96, 0x02, 0x29, 0xfe, 0x00, 0x1c, 0xde, 0xfe, 0x02, 0x1c, 0xdd, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010384 0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0xfe, 0x20, 0x17, 0xfe, 0xe7, 0x10,
10385 0xfe, 0x06, 0xfc, 0xc7, 0x0a, 0x6b, 0x01, 0x9e, 0x02, 0x29, 0x14, 0x4d,
10386 0x37, 0x97, 0x01, 0xfe, 0x64, 0x0f, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xbd,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010387 0x10, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010388 0x58, 0x1c, 0x17, 0x06, 0x18, 0x96, 0x2a, 0x25, 0x29, 0xfe, 0x3d, 0xf0,
10389 0xfe, 0x02, 0x02, 0x21, 0xfe, 0x94, 0x02, 0xfe, 0x5a, 0x1c, 0xea, 0xfe,
10390 0x14, 0x1c, 0x14, 0xfe, 0x30, 0x00, 0x37, 0x97, 0x01, 0xfe, 0x54, 0x0f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010391 0x17, 0x06, 0x18, 0x96, 0x02, 0xd0, 0x1e, 0x20, 0x07, 0x10, 0x34, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010392 0x69, 0x10, 0x17, 0x06, 0x18, 0x96, 0xfe, 0x04, 0xec, 0x20, 0x46, 0x3d,
10393 0x12, 0x20, 0xfe, 0x05, 0xf6, 0xc7, 0x01, 0xfe, 0x52, 0x16, 0x09, 0x4a,
10394 0x4c, 0x35, 0x11, 0x2d, 0x3c, 0x8a, 0x01, 0xe6, 0x02, 0x29, 0x0a, 0x40,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010395 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x01, 0x6f, 0xfe, 0x18, 0x10, 0xfe, 0x41,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010396 0x58, 0x0a, 0x99, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x64, 0xfe, 0x0c, 0x03,
10397 0x01, 0xe6, 0x02, 0x29, 0x2a, 0x46, 0xfe, 0x02, 0xe8, 0x27, 0xf8, 0xfe,
10398 0x9e, 0x43, 0xf7, 0xfe, 0x27, 0xf0, 0xfe, 0xdc, 0x01, 0xfe, 0x07, 0x4b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010399 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x40, 0x1c, 0x25, 0xd2, 0xfe, 0x26, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010400 0xfe, 0x56, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x44, 0x03, 0xfe, 0x11, 0xf0,
10401 0x9c, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x64, 0x03, 0xeb, 0x0f,
10402 0xfe, 0x11, 0x00, 0x02, 0x5a, 0x2a, 0xfe, 0x48, 0x1c, 0xeb, 0x09, 0x04,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010403 0x1d, 0xfe, 0x18, 0x13, 0x23, 0x1e, 0x98, 0xac, 0x12, 0x98, 0x0a, 0x40,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010404 0x01, 0x0e, 0xac, 0x75, 0x01, 0xfe, 0xbc, 0x15, 0x11, 0xca, 0x25, 0xd2,
10405 0xfe, 0x01, 0xf0, 0xd2, 0xfe, 0x82, 0xf0, 0xfe, 0x92, 0x03, 0xec, 0x11,
10406 0xfe, 0xe4, 0x00, 0x65, 0xfe, 0xa4, 0x03, 0x25, 0x32, 0x1f, 0xfe, 0xb4,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010407 0x03, 0x01, 0x43, 0xfe, 0x06, 0xf0, 0xfe, 0xc4, 0x03, 0x8d, 0x81, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010408 0x0a, 0xf0, 0xfe, 0x7a, 0x06, 0x02, 0x22, 0x05, 0x6b, 0x28, 0x16, 0xfe,
10409 0xf6, 0x04, 0x14, 0x2c, 0x01, 0x33, 0x8f, 0xfe, 0x66, 0x02, 0x02, 0xd1,
10410 0xeb, 0x2a, 0x67, 0x1a, 0xfe, 0x67, 0x1b, 0xf8, 0xf7, 0xfe, 0x48, 0x1c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010411 0x70, 0x01, 0x6e, 0x87, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x16, 0xd3,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010412 0x0a, 0xca, 0x01, 0x0e, 0x74, 0x60, 0x59, 0x76, 0x27, 0x05, 0x6b, 0x28,
10413 0xfe, 0x10, 0x12, 0x14, 0x2c, 0x01, 0x33, 0x8f, 0xfe, 0x66, 0x02, 0x02,
10414 0xd1, 0xbc, 0x7d, 0xbd, 0x7f, 0x25, 0x22, 0x65, 0xfe, 0x3c, 0x04, 0x1f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010415 0xfe, 0x38, 0x04, 0x68, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010416 0x12, 0x2b, 0xff, 0x02, 0x00, 0x10, 0x01, 0x08, 0x1f, 0xfe, 0xe0, 0x04,
10417 0x2b, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd5, 0xfe, 0x4c, 0x44, 0xfe,
10418 0x4c, 0x12, 0x60, 0xfe, 0x44, 0x48, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010419 0xd3, 0x46, 0x76, 0x27, 0xfa, 0xef, 0xfe, 0x62, 0x13, 0x09, 0x04, 0x1d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010420 0xfe, 0x2a, 0x13, 0x2f, 0x07, 0x7e, 0xa5, 0xfe, 0x20, 0x10, 0x13, 0x2c,
10421 0xfe, 0x4c, 0x54, 0x64, 0xd3, 0xfa, 0xef, 0x86, 0x09, 0x04, 0x1d, 0xfe,
10422 0x08, 0x13, 0x2f, 0x07, 0x7e, 0x6e, 0x09, 0x04, 0x1d, 0xfe, 0x1c, 0x12,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010423 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010424 0x70, 0x0c, 0x02, 0x22, 0x2b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90,
10425 0xf9, 0x03, 0x14, 0x92, 0x01, 0x33, 0x02, 0x29, 0xfe, 0x42, 0x5b, 0x67,
10426 0x1a, 0xfe, 0x46, 0x59, 0xf8, 0xf7, 0xfe, 0x87, 0x80, 0xfe, 0x31, 0xe4,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010427 0x4f, 0x09, 0x04, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x1a,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010428 0xfe, 0x70, 0x12, 0x49, 0x04, 0x06, 0xfe, 0x60, 0x13, 0x05, 0xfe, 0xa2,
10429 0x00, 0x28, 0x16, 0xfe, 0x80, 0x05, 0xfe, 0x31, 0xe4, 0x6a, 0x49, 0x04,
10430 0x0b, 0xfe, 0x4a, 0x13, 0x05, 0xfe, 0xa0, 0x00, 0x28, 0xfe, 0x42, 0x12,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010431 0x5e, 0x01, 0x08, 0x25, 0x32, 0xf1, 0x01, 0x08, 0x26, 0xfe, 0x98, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010432 0x11, 0xfe, 0xe3, 0x00, 0x23, 0x49, 0xfe, 0x4a, 0xf0, 0xfe, 0x6a, 0x05,
10433 0xfe, 0x49, 0xf0, 0xfe, 0x64, 0x05, 0x83, 0x24, 0xfe, 0x21, 0x00, 0xa1,
10434 0x24, 0xfe, 0x22, 0x00, 0xa0, 0x24, 0x4c, 0xfe, 0x09, 0x48, 0x01, 0x08,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010435 0x26, 0xfe, 0x98, 0x05, 0xfe, 0xe2, 0x08, 0x49, 0x04, 0xc5, 0x3b, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010436 0x86, 0x24, 0x06, 0x12, 0xcc, 0x37, 0xfe, 0x27, 0x01, 0x09, 0x04, 0x1d,
10437 0xfe, 0x22, 0x12, 0x47, 0x01, 0xa7, 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b,
10438 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c, 0x02, 0x22, 0x05, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010439 0x9c, 0x00, 0x28, 0xfe, 0x3e, 0x12, 0x05, 0x50, 0x28, 0xfe, 0x36, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010440 0x47, 0x01, 0xa7, 0x26, 0xfe, 0x08, 0x06, 0x0a, 0x06, 0x49, 0x04, 0x19,
10441 0xfe, 0x02, 0x12, 0x5f, 0x01, 0xfe, 0xaa, 0x14, 0x1f, 0xfe, 0xfe, 0x05,
10442 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x50, 0xb4, 0x0c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010443 0x50, 0x05, 0xc6, 0x28, 0xfe, 0x62, 0x12, 0x05, 0x3f, 0x28, 0xfe, 0x5a,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010444 0x13, 0x01, 0xfe, 0x14, 0x18, 0x01, 0xfe, 0x66, 0x18, 0xfe, 0x43, 0x48,
10445 0xb7, 0x19, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0x1c, 0x3d,
10446 0x85, 0xb7, 0x69, 0x47, 0x01, 0xa7, 0x26, 0xfe, 0x72, 0x06, 0x49, 0x04,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010447 0x1b, 0xdf, 0x89, 0x0a, 0x4d, 0x01, 0xfe, 0xd8, 0x14, 0x1f, 0xfe, 0x68,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010448 0x06, 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x3f, 0xb4,
10449 0x0c, 0x3f, 0x17, 0x06, 0x01, 0xa7, 0xec, 0x72, 0x70, 0x01, 0x6e, 0x87,
10450 0x11, 0xfe, 0xe2, 0x00, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010451 0xa6, 0x06, 0x8c, 0xfe, 0x5c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, 0x64, 0x07,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010452 0x8d, 0x81, 0x02, 0x22, 0x09, 0x04, 0x0b, 0xfe, 0x2e, 0x12, 0x15, 0x1a,
10453 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00,
10454 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x15, 0x00, 0x02, 0xfe, 0x32,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010455 0x08, 0x61, 0x04, 0x1b, 0xfe, 0x38, 0x12, 0x09, 0x04, 0x1b, 0x6e, 0x15,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010456 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01,
10457 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x06, 0x01, 0x08, 0x15, 0x00, 0x02,
10458 0xd9, 0x66, 0x4c, 0xfe, 0x3a, 0x55, 0x5f, 0xfe, 0x9a, 0x81, 0x4b, 0x1d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010459 0xba, 0xfe, 0x32, 0x07, 0x0a, 0x1d, 0xfe, 0x09, 0x6f, 0xaf, 0xfe, 0xca,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010460 0x45, 0xfe, 0x32, 0x12, 0x62, 0x2c, 0x85, 0x66, 0x7b, 0x01, 0x08, 0x25,
10461 0x32, 0xfe, 0x0a, 0xf0, 0xfe, 0x32, 0x07, 0x8d, 0x81, 0x8c, 0xfe, 0x5c,
10462 0x07, 0x02, 0x22, 0x01, 0x43, 0x02, 0xfe, 0x8a, 0x06, 0x15, 0x19, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010463 0xfe, 0x8a, 0x06, 0xfe, 0x9c, 0xf7, 0xd4, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010464 0x90, 0x77, 0xfe, 0xca, 0x07, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x4a, 0x6a,
10465 0x35, 0x1e, 0x20, 0x07, 0x10, 0xfe, 0x0e, 0x12, 0x74, 0xfe, 0x80, 0x80,
10466 0x37, 0x20, 0x63, 0x27, 0xfe, 0x06, 0x10, 0xfe, 0x83, 0xe7, 0xc4, 0xa1,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010467 0xfe, 0x03, 0x40, 0x09, 0x4a, 0x4f, 0x35, 0x01, 0xa8, 0xad, 0xfe, 0x1f,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010468 0x40, 0x12, 0x58, 0x01, 0xa5, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe,
10469 0x44, 0x51, 0xfe, 0xc6, 0x51, 0x83, 0xfb, 0xfe, 0x8a, 0x90, 0x0c, 0x52,
10470 0x18, 0x53, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010471 0xc2, 0x50, 0x0c, 0x39, 0x18, 0x3a, 0xfe, 0x4a, 0x10, 0x09, 0x04, 0x6a,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010472 0xfe, 0x2a, 0x12, 0xfe, 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x54, 0x18,
10473 0x55, 0x09, 0x04, 0x4f, 0x85, 0x01, 0xa8, 0xfe, 0x1f, 0x80, 0x12, 0x58,
10474 0xfe, 0x44, 0x90, 0xfe, 0xc6, 0x90, 0x0c, 0x56, 0x18, 0x57, 0xfb, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010475 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010476 0x0c, 0x39, 0x18, 0x3a, 0x0c, 0x38, 0x18, 0x4e, 0x09, 0x4a, 0x19, 0x35,
10477 0x2a, 0x13, 0xfe, 0x4e, 0x11, 0x65, 0xfe, 0x48, 0x08, 0xfe, 0x9e, 0xf0,
10478 0xfe, 0x5c, 0x08, 0xb1, 0x16, 0x32, 0x2a, 0x73, 0xdd, 0xb8, 0xfe, 0x80,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010479 0x08, 0xb9, 0xfe, 0x9e, 0x08, 0x8c, 0xfe, 0x74, 0x08, 0xfe, 0x06, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010480 0xfe, 0x7a, 0x08, 0x8d, 0x81, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xc9, 0x10,
10481 0x15, 0x19, 0xfe, 0xc9, 0x10, 0x61, 0x04, 0x06, 0xfe, 0x10, 0x12, 0x61,
10482 0x04, 0x0b, 0x45, 0x09, 0x04, 0x0b, 0xfe, 0x68, 0x12, 0xfe, 0x2e, 0x1c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010483 0x02, 0xfe, 0x24, 0x0a, 0x61, 0x04, 0x06, 0x45, 0x61, 0x04, 0x0b, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010484 0x52, 0x12, 0xfe, 0x2c, 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x1e, 0x09, 0xfe,
10485 0xac, 0xf0, 0xfe, 0xbe, 0x08, 0xfe, 0x8a, 0x10, 0xaa, 0xfe, 0xf3, 0x10,
10486 0xfe, 0xad, 0xf0, 0xfe, 0xca, 0x08, 0x02, 0xfe, 0x24, 0x0a, 0xab, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010487 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0x9d, 0xe9, 0x1c, 0xfe, 0x00, 0xfe, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010488 0x1c, 0x12, 0xb5, 0xfe, 0xd2, 0xf0, 0x9d, 0xfe, 0x76, 0x18, 0x1c, 0x1a,
10489 0x16, 0x9d, 0x05, 0xcb, 0x1c, 0x06, 0x16, 0x9d, 0xb8, 0x6d, 0xb9, 0x6d,
10490 0xaa, 0xab, 0xfe, 0xb1, 0x10, 0x70, 0x5e, 0x2b, 0x14, 0x92, 0x01, 0x33,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010491 0x0f, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x5a, 0x0f, 0x7c, 0x02, 0x5a,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010492 0xfe, 0x74, 0x18, 0x1c, 0xfe, 0x00, 0xf8, 0x16, 0x6d, 0x67, 0x1b, 0x01,
10493 0xfe, 0x44, 0x0d, 0x3b, 0x01, 0xe6, 0x1e, 0x27, 0x74, 0x67, 0x1a, 0x02,
10494 0x6d, 0x09, 0x04, 0x0b, 0x21, 0xfe, 0x06, 0x0a, 0x09, 0x04, 0x6a, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010495 0x82, 0x12, 0x09, 0x04, 0x19, 0xfe, 0x66, 0x13, 0x1e, 0x58, 0xac, 0xfc,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010496 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91,
10497 0xfe, 0x86, 0x91, 0x63, 0x27, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x77,
10498 0xd7, 0x05, 0x54, 0x31, 0x55, 0x0c, 0x7b, 0x18, 0x7c, 0xbe, 0x54, 0xbf,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010499 0x55, 0x01, 0xa8, 0xad, 0x63, 0x27, 0x12, 0x58, 0xc0, 0x38, 0xc1, 0x4e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010500 0x79, 0x56, 0x68, 0x57, 0xf4, 0xf5, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05,
10501 0xfa, 0x4e, 0x01, 0xa5, 0xa2, 0x23, 0x0c, 0x7b, 0x0c, 0x7c, 0x79, 0x56,
10502 0x68, 0x57, 0xfe, 0x12, 0x10, 0x09, 0x04, 0x19, 0x16, 0xd7, 0x79, 0x39,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010503 0x68, 0x3a, 0x09, 0x04, 0xfe, 0xf7, 0x00, 0x35, 0x05, 0x52, 0x31, 0x53,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010504 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59,
10505 0x02, 0x6d, 0x09, 0x04, 0x19, 0x16, 0xd7, 0x09, 0x04, 0xfe, 0xf7, 0x00,
10506 0x35, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x5f, 0xfe, 0x10, 0x90, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010507 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x2f, 0x07, 0x9b, 0x16, 0xfe, 0xc6, 0x08,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010508 0x11, 0x9b, 0x09, 0x04, 0x0b, 0xfe, 0x14, 0x13, 0x05, 0x39, 0x31, 0x3a,
10509 0x77, 0xfe, 0xc6, 0x08, 0xfe, 0x0c, 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x6d,
10510 0x23, 0x47, 0xfe, 0x19, 0x80, 0xde, 0x09, 0x04, 0x0b, 0xfe, 0x1a, 0x12,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010511 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xe9, 0xb5, 0xfe, 0xd1, 0xf0, 0xd9,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010512 0x14, 0x7a, 0x01, 0x33, 0x0f, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe,
10513 0x6c, 0x19, 0xbe, 0x39, 0xfe, 0xed, 0x19, 0xbf, 0x3a, 0xfe, 0x0c, 0x51,
10514 0xfe, 0x8e, 0x51, 0xe9, 0x1c, 0xfe, 0x00, 0xff, 0x34, 0xfe, 0x74, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010515 0xb5, 0xfe, 0xd2, 0xf0, 0xfe, 0xb2, 0x0a, 0xfe, 0x76, 0x18, 0x1c, 0x1a,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010516 0x84, 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0x08, 0x13, 0x0f, 0xfe, 0x16, 0x00,
10517 0x02, 0x5a, 0xfe, 0xd1, 0xf0, 0xfe, 0xc4, 0x0a, 0x14, 0x7a, 0x01, 0x33,
10518 0x0f, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe, 0xce, 0xf0, 0xfe, 0xca,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010519 0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x0f, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010520 0x22, 0x00, 0x02, 0x5a, 0xfe, 0xcb, 0xf0, 0xfe, 0xe2, 0x0a, 0x0f, 0xfe,
10521 0x24, 0x00, 0x02, 0x5a, 0xfe, 0xd0, 0xf0, 0xfe, 0xec, 0x0a, 0x0f, 0x93,
10522 0xdc, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x0f, 0x4c, 0xfe, 0x10, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010523 0xfe, 0xcc, 0xf0, 0xd9, 0x61, 0x04, 0x19, 0x3b, 0x0f, 0xfe, 0x12, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010524 0x2a, 0x13, 0xfe, 0x4e, 0x11, 0x65, 0xfe, 0x0c, 0x0b, 0xfe, 0x9e, 0xf0,
10525 0xfe, 0x20, 0x0b, 0xb1, 0x16, 0x32, 0x2a, 0x73, 0xdd, 0xb8, 0x22, 0xb9,
10526 0x22, 0x2a, 0xec, 0x65, 0xfe, 0x2c, 0x0b, 0x25, 0x32, 0x8c, 0xfe, 0x48,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010527 0x0b, 0x8d, 0x81, 0xb8, 0xd4, 0xb9, 0xd4, 0x02, 0x22, 0x01, 0x43, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010528 0xdb, 0x10, 0x11, 0xfe, 0xe8, 0x00, 0xaa, 0xab, 0x70, 0xbc, 0x7d, 0xbd,
10529 0x7f, 0xfe, 0x89, 0xf0, 0x22, 0x30, 0x2e, 0xd8, 0xbc, 0x7d, 0xbd, 0x7f,
10530 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd6, 0xb1, 0x45, 0x0f, 0xfe, 0x42,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010531 0x00, 0x02, 0x5a, 0x78, 0x06, 0xfe, 0x81, 0x49, 0x16, 0xfe, 0x38, 0x0c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010532 0x09, 0x04, 0x0b, 0xfe, 0x44, 0x13, 0x0f, 0x00, 0x4b, 0x0b, 0xfe, 0x54,
10533 0x12, 0x4b, 0xfe, 0x28, 0x00, 0x21, 0xfe, 0xa6, 0x0c, 0x0a, 0x40, 0x01,
10534 0x0e, 0x07, 0x00, 0x5d, 0x3e, 0xfe, 0x28, 0x00, 0xfe, 0xe2, 0x10, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010535 0xe7, 0x01, 0xe8, 0x0a, 0x99, 0x01, 0xfe, 0x32, 0x0e, 0x59, 0x11, 0x2d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010536 0x01, 0x6f, 0x02, 0x29, 0x0f, 0xfe, 0x44, 0x00, 0x4b, 0x0b, 0xdf, 0x3e,
10537 0x0b, 0xfe, 0xb4, 0x10, 0x01, 0x86, 0x3e, 0x0b, 0xfe, 0xaa, 0x10, 0x01,
10538 0x86, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xa3, 0x3e, 0x0b, 0x0f, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010539 0x43, 0x00, 0xfe, 0x96, 0x10, 0x09, 0x4a, 0x0b, 0x35, 0x01, 0xe7, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010540 0xe8, 0x59, 0x11, 0x2d, 0x01, 0x6f, 0x67, 0x0b, 0x59, 0x3c, 0x8a, 0x02,
10541 0xfe, 0x2a, 0x03, 0x09, 0x04, 0x0b, 0x84, 0x3e, 0x0b, 0x0f, 0x00, 0xfe,
10542 0x5c, 0x10, 0x61, 0x04, 0x1b, 0xfe, 0x58, 0x12, 0x09, 0x04, 0x1b, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010543 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x5c, 0x0c, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010544 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x62, 0x0c, 0x09, 0x4a, 0x1b, 0x35,
10545 0xfe, 0xa9, 0x10, 0x0f, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0b, 0x5f,
10546 0x5c, 0x0f, 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x0f, 0xfe, 0x47, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010547 0xa1, 0x0f, 0xfe, 0x41, 0x00, 0xa0, 0x0f, 0xfe, 0x24, 0x00, 0x87, 0xaa,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010548 0xab, 0x70, 0x05, 0x6b, 0x28, 0x21, 0xd1, 0x5f, 0xfe, 0x04, 0xe6, 0x1b,
10549 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x59, 0x01, 0xda, 0x02, 0x29, 0xea,
10550 0x14, 0x0b, 0x37, 0x95, 0xa9, 0x14, 0xfe, 0x31, 0x00, 0x37, 0x97, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010551 0xfe, 0x54, 0x0f, 0x02, 0xd0, 0x3c, 0xfe, 0x06, 0xec, 0xc9, 0xee, 0x3e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010552 0x1d, 0xfe, 0xce, 0x45, 0x34, 0x3c, 0xfe, 0x06, 0xea, 0xc9, 0xfe, 0x47,
10553 0x4b, 0x89, 0xfe, 0x75, 0x57, 0x05, 0x51, 0xfe, 0x98, 0x56, 0xfe, 0x38,
10554 0x12, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x44, 0x48, 0x46, 0x09, 0x04, 0x1d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010555 0xfe, 0x1a, 0x13, 0x0a, 0x40, 0x01, 0x0e, 0x47, 0xfe, 0x41, 0x58, 0x0a,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010556 0x99, 0x01, 0x0e, 0xfe, 0x49, 0x54, 0x8e, 0xfe, 0x2a, 0x0d, 0x02, 0xfe,
10557 0x2a, 0x03, 0x0a, 0x51, 0xfe, 0xee, 0x14, 0xee, 0x3e, 0x1d, 0xfe, 0xce,
10558 0x45, 0x34, 0x3c, 0xfe, 0xce, 0x47, 0xfe, 0xad, 0x13, 0x02, 0x29, 0x1e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010559 0x20, 0x07, 0x10, 0xfe, 0x9e, 0x12, 0x23, 0x12, 0x4d, 0x12, 0x94, 0x12,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010560 0xce, 0x1e, 0x2d, 0x47, 0x37, 0x2d, 0xb1, 0xe0, 0xfe, 0xbc, 0xf0, 0xfe,
10561 0xec, 0x0d, 0x13, 0x06, 0x12, 0x4d, 0x01, 0xfe, 0xe2, 0x15, 0x05, 0xfe,
10562 0x38, 0x01, 0x31, 0xfe, 0x3a, 0x01, 0x77, 0xfe, 0xf0, 0x0d, 0xfe, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010563 0xec, 0xce, 0x62, 0x00, 0x5d, 0xfe, 0x04, 0xec, 0x20, 0x46, 0xfe, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010564 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x52, 0x16, 0xfb, 0xfe, 0x48, 0xf4,
10565 0x0d, 0xfe, 0x18, 0x13, 0xaf, 0xfe, 0x02, 0xea, 0xce, 0x62, 0x7a, 0xfe,
10566 0xc5, 0x13, 0x14, 0x1b, 0x37, 0x95, 0xa9, 0x5c, 0x05, 0xfe, 0x38, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010567 0x1c, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x05, 0xfe, 0x3a, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010568 0x0c, 0xfe, 0x62, 0x01, 0x3d, 0x12, 0x20, 0x24, 0x06, 0x12, 0x2d, 0x11,
10569 0x2d, 0x8a, 0x13, 0x06, 0x03, 0x23, 0x03, 0x1e, 0x4d, 0xfe, 0xf7, 0x12,
10570 0x1e, 0x94, 0xac, 0x12, 0x94, 0x07, 0x7a, 0xfe, 0x71, 0x13, 0xfe, 0x24,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010571 0x1c, 0x14, 0x1a, 0x37, 0x95, 0xa9, 0xfe, 0xd9, 0x10, 0xb6, 0xfe, 0x03,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010572 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x03, 0xb6, 0xfe, 0x03, 0xdc,
10573 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x03, 0xfe, 0x03, 0x57, 0xb6, 0x23,
10574 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0xb6, 0x75, 0x03, 0x09, 0x04,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010575 0x4c, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010576 0xfe, 0x1e, 0x80, 0xe1, 0xfe, 0x1d, 0x80, 0xa4, 0xfe, 0x0c, 0x90, 0xfe,
10577 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xa3, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
10578 0x0b, 0xfe, 0x3c, 0x50, 0xa0, 0x01, 0xfe, 0x82, 0x16, 0x2f, 0x07, 0x2d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010579 0xe0, 0x01, 0xfe, 0xbc, 0x15, 0x09, 0x04, 0x1d, 0x45, 0x01, 0xe7, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010580 0xe8, 0x11, 0xfe, 0xe9, 0x00, 0x09, 0x04, 0x4c, 0xfe, 0x2c, 0x13, 0x01,
10581 0xfe, 0x14, 0x16, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90,
10582 0x0c, 0xfe, 0x64, 0x01, 0x18, 0xfe, 0x66, 0x01, 0x09, 0x04, 0x4f, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010583 0x12, 0x12, 0xfe, 0x03, 0x80, 0x74, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010584 0x40, 0x12, 0x20, 0x63, 0x27, 0x11, 0xc8, 0x59, 0x1e, 0x20, 0xed, 0x76,
10585 0x20, 0x03, 0xfe, 0x08, 0x1c, 0x05, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58,
10586 0x05, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x05, 0xfe, 0xb0, 0x00, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010587 0x08, 0x58, 0x05, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010588 0x24, 0x69, 0x12, 0xc9, 0x23, 0x0c, 0x50, 0x0c, 0x3f, 0x13, 0x40, 0x48,
10589 0x5f, 0x17, 0x1d, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x21, 0xfe, 0x08,
10590 0x0f, 0x3e, 0x10, 0x13, 0x42, 0x48, 0x17, 0x4c, 0xfe, 0x90, 0x4d, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010591 0x91, 0x54, 0x21, 0xfe, 0x1e, 0x0f, 0x24, 0x10, 0x12, 0x20, 0x78, 0x2c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010592 0x46, 0x1e, 0x20, 0xed, 0x76, 0x20, 0x11, 0xc8, 0xf6, 0xfe, 0xd6, 0xf0,
10593 0xfe, 0x32, 0x0f, 0xea, 0x70, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
10594 0x18, 0x1c, 0x03, 0x3c, 0xfe, 0x0c, 0x14, 0xee, 0xfe, 0x07, 0xe6, 0x1d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010595 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x86, 0x78, 0x2c, 0x46,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010596 0xfa, 0xef, 0xfe, 0x42, 0x13, 0x2f, 0x07, 0x2d, 0xfe, 0x34, 0x13, 0x0a,
10597 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x36, 0x12, 0xf0, 0xfe, 0x45, 0x48, 0x01,
10598 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010599 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x6f, 0xfe, 0x0e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010600 0x10, 0x07, 0x7e, 0x45, 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x6c, 0x0f, 0x03,
10601 0xfe, 0x44, 0x58, 0x74, 0xfe, 0x01, 0xec, 0x97, 0xfe, 0x9e, 0x40, 0xfe,
10602 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1b, 0x76, 0x27, 0x01, 0xda, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010603 0xdd, 0x10, 0x2a, 0xbc, 0x7d, 0xbd, 0x7f, 0x30, 0x2e, 0xd5, 0x07, 0x1b,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010604 0xfe, 0x48, 0x12, 0x07, 0x0b, 0xfe, 0x56, 0x12, 0x07, 0x1a, 0xfe, 0x30,
10605 0x12, 0x07, 0xc2, 0x16, 0xfe, 0x3e, 0x11, 0x07, 0xfe, 0x23, 0x00, 0x16,
10606 0xfe, 0x4a, 0x11, 0x07, 0x06, 0x16, 0xfe, 0xa8, 0x11, 0x07, 0x19, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010607 0x12, 0x12, 0x07, 0x00, 0x16, 0x22, 0x14, 0xc2, 0x01, 0x33, 0x9f, 0x2b,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010608 0x01, 0x08, 0x8c, 0x43, 0x03, 0x2b, 0xfe, 0x62, 0x08, 0x0a, 0xca, 0x01,
10609 0xfe, 0x32, 0x0e, 0x11, 0x7e, 0x02, 0x29, 0x2b, 0x2f, 0x07, 0x9b, 0xfe,
10610 0xd9, 0x13, 0x79, 0x39, 0x68, 0x3a, 0x77, 0xfe, 0xfc, 0x10, 0x09, 0x04,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010611 0x6a, 0xfe, 0x72, 0x12, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x8e, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010612 0xc6, 0x10, 0x1e, 0x58, 0xfe, 0x26, 0x13, 0x05, 0x7b, 0x31, 0x7c, 0x77,
10613 0xfe, 0x82, 0x0c, 0x0c, 0x54, 0x18, 0x55, 0x23, 0x0c, 0x7b, 0x0c, 0x7c,
10614 0x01, 0xa8, 0x24, 0x69, 0x73, 0x12, 0x58, 0x01, 0xa5, 0xc0, 0x38, 0xc1,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010615 0x4e, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x38, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010616 0x05, 0xfa, 0x4e, 0xfe, 0x91, 0x10, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x40,
10617 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x56, 0x18, 0x57, 0x83, 0xc0, 0x38, 0xc1,
10618 0x4e, 0xf4, 0xf5, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x00, 0x56, 0xfe, 0xa1,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010619 0x56, 0x0c, 0x52, 0x18, 0x53, 0x09, 0x04, 0x6a, 0xfe, 0x1e, 0x12, 0x1e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010620 0x58, 0xfe, 0x1f, 0x40, 0x05, 0x54, 0x31, 0x55, 0xfe, 0x2c, 0x50, 0xfe,
10621 0xae, 0x50, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x44, 0x50, 0xfe, 0xc6, 0x50,
10622 0x05, 0x52, 0x31, 0x53, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x05, 0x39,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010623 0x31, 0x3a, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x5c, 0x24, 0x06,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010624 0x12, 0xcd, 0x02, 0x5b, 0x2b, 0x01, 0x08, 0x1f, 0x44, 0x30, 0x2e, 0xd5,
10625 0x07, 0x06, 0x21, 0x44, 0x2f, 0x07, 0x9b, 0x21, 0x5b, 0x01, 0x6e, 0x1c,
10626 0x3d, 0x16, 0x44, 0x09, 0x04, 0x0b, 0xe2, 0x79, 0x39, 0x68, 0x3a, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010627 0x0a, 0x55, 0x34, 0xfe, 0x8b, 0x55, 0xbe, 0x39, 0xbf, 0x3a, 0xfe, 0x0c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010628 0x51, 0xfe, 0x8e, 0x51, 0x02, 0x5b, 0xfe, 0x19, 0x81, 0xaf, 0xfe, 0x19,
10629 0x41, 0x02, 0x5b, 0x2b, 0x01, 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e,
10630 0xd8, 0x4b, 0x1a, 0xfe, 0xa6, 0x12, 0x4b, 0x0b, 0x3b, 0x02, 0x44, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010631 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, 0xd6, 0x07, 0x1a, 0x21, 0x44,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010632 0x01, 0x08, 0x1f, 0xa2, 0x30, 0x2e, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49,
10633 0x60, 0x05, 0xfe, 0x9c, 0x00, 0x28, 0x84, 0x49, 0x04, 0x19, 0x34, 0x9f,
10634 0xfe, 0xbb, 0x45, 0x4b, 0x00, 0x45, 0x3e, 0x06, 0x78, 0x3d, 0xfe, 0xda,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010635 0x14, 0x01, 0x6e, 0x87, 0xfe, 0x4b, 0x45, 0xe2, 0x2f, 0x07, 0x9a, 0xe1,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010636 0x05, 0xc6, 0x28, 0x84, 0x05, 0x3f, 0x28, 0x34, 0x5e, 0x02, 0x5b, 0xfe,
10637 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17, 0x05, 0x50, 0xb4, 0x0c,
10638 0x50, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe, 0xaa, 0x14, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010639 0x5c, 0x01, 0x08, 0x25, 0x32, 0x1f, 0x44, 0x30, 0x2e, 0xd6, 0x07, 0x06,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010640 0x21, 0x44, 0x01, 0xfe, 0x8e, 0x13, 0xfe, 0x42, 0x58, 0xfe, 0x82, 0x14,
10641 0xfe, 0xa4, 0x14, 0x87, 0xfe, 0x4a, 0xf4, 0x0b, 0x16, 0x44, 0xfe, 0x4a,
10642 0xf4, 0x06, 0xfe, 0x0c, 0x12, 0x2f, 0x07, 0x9a, 0x85, 0x02, 0x5b, 0x05,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010643 0x3f, 0xb4, 0x0c, 0x3f, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010644 0xd8, 0x14, 0x02, 0x5c, 0x13, 0x06, 0x65, 0xfe, 0xca, 0x12, 0x26, 0xfe,
10645 0xe0, 0x12, 0x72, 0xf1, 0x01, 0x08, 0x23, 0x72, 0x03, 0x8f, 0xfe, 0xdc,
10646 0x12, 0x25, 0xfe, 0xdc, 0x12, 0x1f, 0xfe, 0xca, 0x12, 0x5e, 0x2b, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010647 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010648 0x1c, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13,
10649 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0x1c, 0x3d, 0xfe, 0x30, 0x56,
10650 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010651 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0xfe, 0x0b, 0x58,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010652 0x03, 0x0a, 0x50, 0x01, 0x82, 0x0a, 0x3f, 0x01, 0x82, 0x03, 0xfc, 0x1c,
10653 0x10, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x19, 0x48, 0xfe, 0x00,
10654 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x63, 0x27,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010655 0x0c, 0x52, 0x18, 0x53, 0xbe, 0x56, 0xbf, 0x57, 0x03, 0xfe, 0x62, 0x08,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010656 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x74, 0x03, 0x01,
10657 0xfe, 0x14, 0x18, 0xfe, 0x42, 0x48, 0x5f, 0x60, 0x89, 0x01, 0x08, 0x1f,
10658 0xfe, 0xa2, 0x14, 0x30, 0x2e, 0xd8, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010659 0x30, 0x2e, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x05, 0xc6, 0x28, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010660 0xcc, 0x12, 0x49, 0x04, 0x1b, 0xfe, 0xc4, 0x13, 0x23, 0x62, 0x1b, 0xe2,
10661 0x4b, 0xc3, 0x64, 0xfe, 0xe8, 0x13, 0x3b, 0x13, 0x06, 0x17, 0xc3, 0x78,
10662 0xdb, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xa1, 0xff, 0x02, 0x83,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010663 0x55, 0x62, 0x1a, 0xa4, 0xbb, 0xfe, 0x30, 0x00, 0x8e, 0xe4, 0x17, 0x2c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010664 0x13, 0x06, 0xfe, 0x56, 0x10, 0x62, 0x0b, 0xe1, 0xbb, 0xfe, 0x64, 0x00,
10665 0x8e, 0xe4, 0x0a, 0xfe, 0x64, 0x00, 0x17, 0x93, 0x13, 0x06, 0xfe, 0x28,
10666 0x10, 0x62, 0x06, 0xfe, 0x60, 0x13, 0xbb, 0xfe, 0xc8, 0x00, 0x8e, 0xe4,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010667 0x0a, 0xfe, 0xc8, 0x00, 0x17, 0x4d, 0x13, 0x06, 0x83, 0xbb, 0xfe, 0x90,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010668 0x01, 0xba, 0xfe, 0x4e, 0x14, 0x89, 0xfe, 0x12, 0x10, 0xfe, 0x43, 0xf4,
10669 0x94, 0xfe, 0x56, 0xf0, 0xfe, 0x60, 0x14, 0xfe, 0x04, 0xf4, 0x6c, 0xfe,
10670 0x43, 0xf4, 0x93, 0xfe, 0xf3, 0x10, 0xf9, 0x01, 0xfe, 0x22, 0x13, 0x1c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010671 0x3d, 0xfe, 0x10, 0x13, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x69, 0xba,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010672 0xfe, 0x9c, 0x14, 0xb7, 0x69, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe,
10673 0x4d, 0xe4, 0x19, 0xba, 0xfe, 0x9c, 0x14, 0xb7, 0x19, 0x83, 0x60, 0x23,
10674 0xfe, 0x4d, 0xf4, 0x00, 0xdf, 0x89, 0x13, 0x06, 0xfe, 0xb4, 0x56, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010675 0xc3, 0x58, 0x03, 0x60, 0x13, 0x0b, 0x03, 0x15, 0x06, 0x01, 0x08, 0x26,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010676 0xe5, 0x15, 0x0b, 0x01, 0x08, 0x26, 0xe5, 0x15, 0x1a, 0x01, 0x08, 0x26,
10677 0xe5, 0x72, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x03, 0x15, 0x06, 0x01, 0x08,
10678 0x26, 0xa6, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x06, 0x01, 0x08,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010679 0x26, 0xa6, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x26, 0xa6, 0x72, 0xfe, 0x89,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010680 0x4a, 0x01, 0x08, 0x03, 0x60, 0x03, 0x1e, 0xcc, 0x07, 0x06, 0xfe, 0x44,
10681 0x13, 0xad, 0x12, 0xcc, 0xfe, 0x49, 0xf4, 0x00, 0x3b, 0x72, 0x9f, 0x5e,
10682 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01, 0x08, 0x2f, 0x07, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010683 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0x5a, 0x15, 0x23, 0x12, 0xcd,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010684 0x01, 0x43, 0x1e, 0xcd, 0x07, 0x06, 0x45, 0x09, 0x4a, 0x06, 0x35, 0x03,
10685 0x0a, 0x42, 0x01, 0x0e, 0xed, 0x88, 0x07, 0x10, 0xa4, 0x0a, 0x80, 0x01,
10686 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x80, 0x01, 0x0e, 0x88,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010687 0xfe, 0x80, 0xe7, 0x10, 0x07, 0x10, 0x84, 0xfe, 0x45, 0x58, 0x01, 0xe3,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010688 0x88, 0x03, 0x0a, 0x42, 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03,
10689 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x80, 0x80, 0xf2, 0xfe, 0x49, 0xe4, 0x10,
10690 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x0a, 0x51, 0x01, 0x82, 0x03, 0x17,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010691 0x10, 0x71, 0x66, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010692 0xfe, 0x24, 0x1c, 0xfe, 0x1d, 0xf7, 0x1d, 0x90, 0xfe, 0xf6, 0x15, 0x01,
10693 0xfe, 0xfc, 0x16, 0xe0, 0x91, 0x1d, 0x66, 0xfe, 0x2c, 0x01, 0xfe, 0x2f,
10694 0x19, 0x03, 0xae, 0x21, 0xfe, 0xe6, 0x15, 0xfe, 0xda, 0x10, 0x17, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010695 0x71, 0x05, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010696 0x05, 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0x91, 0x19, 0xfe, 0x3c, 0x90,
10697 0xfe, 0x30, 0xf4, 0x06, 0xfe, 0x3c, 0x50, 0x66, 0xfe, 0x38, 0x00, 0xfe,
10698 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x90, 0xfe, 0x40, 0x16, 0xfe, 0xb6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010699 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x18, 0x16, 0xfe, 0x9c, 0x10, 0x17,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010700 0x10, 0x71, 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe,
10701 0x1d, 0xf7, 0x38, 0x90, 0xfe, 0x62, 0x16, 0xfe, 0x94, 0x14, 0xfe, 0x10,
10702 0x13, 0x91, 0x38, 0x66, 0x1b, 0xfe, 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010703 0x03, 0xae, 0x21, 0xfe, 0x56, 0x16, 0xfe, 0x6c, 0x10, 0x17, 0x10, 0x71,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010704 0xfe, 0x30, 0xbc, 0xfe, 0xb2, 0xbc, 0x91, 0xc5, 0x66, 0x1b, 0xfe, 0x0f,
10705 0x79, 0xfe, 0x1c, 0xf7, 0xc5, 0x90, 0xfe, 0x9a, 0x16, 0xfe, 0x5c, 0x14,
10706 0x34, 0x03, 0xae, 0x21, 0xfe, 0x86, 0x16, 0xfe, 0x42, 0x10, 0xfe, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010707 0xf6, 0x10, 0x71, 0xfe, 0x18, 0xfe, 0x54, 0xfe, 0x19, 0xfe, 0x55, 0xfc,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010708 0xfe, 0x1d, 0xf7, 0x4f, 0x90, 0xfe, 0xc0, 0x16, 0xfe, 0x36, 0x14, 0xfe,
10709 0x1c, 0x13, 0x91, 0x4f, 0x47, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe,
10710 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11, 0xfe, 0xdd, 0x00, 0x63,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010711 0x27, 0x03, 0x63, 0x27, 0xfe, 0x12, 0x45, 0x21, 0xfe, 0xb0, 0x16, 0x14,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010712 0x06, 0x37, 0x95, 0xa9, 0x02, 0x29, 0xfe, 0x39, 0xf0, 0xfe, 0x04, 0x17,
10713 0x23, 0x03, 0xfe, 0x7e, 0x18, 0x1c, 0x1a, 0x5d, 0x13, 0x0d, 0x03, 0x71,
10714 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x78, 0x2c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010715 0x46, 0x2f, 0x07, 0x2d, 0xfe, 0x3c, 0x13, 0xfe, 0x82, 0x14, 0xfe, 0x42,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010716 0x13, 0x3c, 0x8a, 0x0a, 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x3e, 0x12, 0xf0,
10717 0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13,
10718 0x3d, 0x75, 0x07, 0x10, 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x01, 0x6f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010719 0xfe, 0x16, 0x10, 0x07, 0x7e, 0x85, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010720 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x24, 0x17, 0x17, 0x0b, 0x03, 0xfe, 0x9c,
10721 0xe7, 0x0b, 0x0f, 0xfe, 0x15, 0x00, 0x59, 0x76, 0x27, 0x01, 0xda, 0x17,
10722 0x06, 0x03, 0x3c, 0x8a, 0x09, 0x4a, 0x1d, 0x35, 0x11, 0x2d, 0x01, 0x6f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010723 0x17, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x79, 0xc7, 0x68,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010724 0xc8, 0xfe, 0x48, 0x55, 0x34, 0xfe, 0xc9, 0x55, 0x03, 0x1e, 0x98, 0x73,
10725 0x12, 0x98, 0x03, 0x0a, 0x99, 0x01, 0x0e, 0xf0, 0x0a, 0x40, 0x01, 0x0e,
10726 0xfe, 0x49, 0x44, 0x16, 0xfe, 0xf0, 0x17, 0x73, 0x75, 0x03, 0x0a, 0x42,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010727 0x01, 0x0e, 0x07, 0x10, 0x45, 0x0a, 0x51, 0x01, 0x9e, 0x0a, 0x40, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010728 0x0e, 0x73, 0x75, 0x03, 0xfe, 0x4e, 0xe4, 0x1a, 0x64, 0xfe, 0x24, 0x18,
10729 0x05, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0x5b, 0xfe, 0x4e, 0xe4, 0xc2,
10730 0x64, 0xfe, 0x36, 0x18, 0x05, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010731 0xdc, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x64, 0xfe, 0x48, 0x18, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010732 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x19, 0xfe, 0x08, 0x10, 0x05, 0xfe,
10733 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x2c, 0xfe, 0x4e, 0x45, 0xfe, 0x0c, 0x12,
10734 0xaf, 0xff, 0x04, 0x68, 0x54, 0xde, 0x1c, 0x69, 0x03, 0x07, 0x7a, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010735 0x5a, 0xf0, 0xfe, 0x74, 0x18, 0x24, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010736 0x07, 0x1b, 0xfe, 0x5a, 0xf0, 0xfe, 0x82, 0x18, 0x24, 0xc3, 0xfe, 0x26,
10737 0x10, 0x07, 0x1a, 0x5d, 0x24, 0x2c, 0xdc, 0x07, 0x0b, 0x5d, 0x24, 0x93,
10738 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x5d, 0x24, 0x4d, 0x9f, 0xad, 0x03, 0x14,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010739 0xfe, 0x09, 0x00, 0x01, 0x33, 0xfe, 0x04, 0xfe, 0x7d, 0x05, 0x7f, 0xf9,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010740 0x03, 0x25, 0xfe, 0xca, 0x18, 0xfe, 0x14, 0xf0, 0x08, 0x65, 0xfe, 0xc6,
10741 0x18, 0x03, 0xff, 0x1a, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070010742};
10743
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010744static unsigned short _adv_asc3550_size = sizeof(_adv_asc3550_buf); /* 0x13AD */
10745static ADV_DCNT _adv_asc3550_chksum = 0x04D52DDDUL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070010746
10747/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010748static unsigned char _adv_asc38C0800_buf[] = {
10749 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x16, 0x18, 0xe4,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010750 0x01, 0x00, 0x48, 0xe4, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0xce, 0x19,
10751 0x00, 0xfa, 0xff, 0xff, 0x1c, 0x0f, 0x00, 0xf6, 0x9e, 0xe7, 0xff, 0x00,
10752 0x82, 0xe7, 0x00, 0xea, 0x01, 0xfa, 0x01, 0xe6, 0x09, 0xe7, 0x55, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010753 0x01, 0xf6, 0x03, 0x00, 0x04, 0x00, 0x10, 0x00, 0x1e, 0xf0, 0x85, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010754 0x18, 0xf4, 0x08, 0x00, 0xbc, 0x00, 0x38, 0x54, 0x00, 0xec, 0xd5, 0xf0,
10755 0x82, 0x0d, 0x00, 0xe6, 0x86, 0xf0, 0xb1, 0xf0, 0x98, 0x57, 0x01, 0xfc,
10756 0xb4, 0x00, 0xd4, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x3c, 0x00, 0xbb, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010757 0x00, 0x10, 0xba, 0x19, 0x02, 0x80, 0x32, 0xf0, 0x7c, 0x0d, 0x02, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010758 0xba, 0x13, 0x18, 0x40, 0x00, 0x57, 0x01, 0xea, 0x02, 0xfc, 0x03, 0xfc,
10759 0x3e, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x74, 0x01, 0x76, 0x01, 0xb9, 0x54,
10760 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00, 0xc0, 0x00, 0x01, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010761 0x3e, 0x01, 0x7a, 0x01, 0xca, 0x08, 0xce, 0x10, 0x16, 0x11, 0x04, 0x12,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010762 0x08, 0x12, 0x02, 0x4a, 0xbb, 0x55, 0x3c, 0x56, 0x03, 0x58, 0x1b, 0x80,
10763 0x30, 0xe4, 0x4b, 0xe4, 0x5d, 0xf0, 0x02, 0xfa, 0x20, 0x00, 0x32, 0x00,
10764 0x40, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010765 0x70, 0x01, 0x72, 0x01, 0x78, 0x01, 0x7c, 0x01, 0x62, 0x0a, 0x86, 0x0d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010766 0x06, 0x13, 0x4c, 0x1c, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0,
10767 0x03, 0xf7, 0x0c, 0x00, 0x0f, 0x00, 0x47, 0x00, 0xbe, 0x00, 0x00, 0x01,
10768 0x20, 0x11, 0x5c, 0x16, 0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010769 0x00, 0x4c, 0x04, 0xea, 0x5c, 0xf0, 0xa7, 0xf0, 0x04, 0xf6, 0x03, 0xfa,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010770 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01,
10771 0x4e, 0x01, 0x4a, 0x0b, 0x42, 0x0c, 0x12, 0x0f, 0x0c, 0x10, 0x22, 0x11,
10772 0x0a, 0x12, 0x04, 0x13, 0x30, 0x1c, 0x02, 0x48, 0x00, 0x4e, 0x42, 0x54,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010773 0x44, 0x55, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010774 0x59, 0xf0, 0xb8, 0xf0, 0x4b, 0xf4, 0x06, 0xf7, 0x0e, 0xf7, 0x04, 0xfc,
10775 0x05, 0xfc, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00, 0xa4, 0x00,
10776 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xe2, 0x03,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010777 0x08, 0x0f, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, 0x0a, 0x13, 0x0c, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010778 0x12, 0x13, 0x24, 0x14, 0x34, 0x14, 0x04, 0x16, 0x08, 0x16, 0xa4, 0x17,
10779 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44, 0x91, 0x44,
10780 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x3a, 0x55, 0x83, 0x55,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010781 0xe5, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010782 0x0c, 0xf0, 0x04, 0xf8, 0x05, 0xf8, 0x07, 0x00, 0x0a, 0x00, 0x1c, 0x00,
10783 0x1e, 0x00, 0x9e, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00,
10784 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7e, 0x01, 0xc4, 0x01, 0xc6, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010785 0x80, 0x02, 0x5e, 0x03, 0xee, 0x04, 0x9a, 0x06, 0xf8, 0x07, 0x62, 0x08,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010786 0x68, 0x08, 0x69, 0x08, 0xd6, 0x08, 0xe9, 0x09, 0xfa, 0x0b, 0x2e, 0x0f,
10787 0x12, 0x10, 0x1a, 0x10, 0xed, 0x10, 0xf1, 0x10, 0x2a, 0x11, 0x06, 0x12,
10788 0x0c, 0x12, 0x3e, 0x12, 0x10, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x46, 0x14,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010789 0x76, 0x14, 0x82, 0x14, 0x36, 0x15, 0xca, 0x15, 0x6b, 0x18, 0xbe, 0x18,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010790 0xca, 0x18, 0xe6, 0x19, 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40,
10791 0x0e, 0x47, 0xfe, 0x9c, 0xf0, 0x2b, 0x02, 0xfe, 0xac, 0x0d, 0xff, 0x10,
10792 0x00, 0x00, 0xd7, 0xfe, 0xe8, 0x19, 0x00, 0xd6, 0xfe, 0x84, 0x01, 0xff,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010793 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010794 0x00, 0xfe, 0x57, 0x24, 0x00, 0xfe, 0x4c, 0x00, 0x5b, 0xff, 0x04, 0x00,
10795 0x00, 0x11, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x08,
10796 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x11,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010797 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010798 0xfe, 0x04, 0xf7, 0xd6, 0x2c, 0x99, 0x0a, 0x01, 0xfe, 0xc2, 0x0f, 0xfe,
10799 0x04, 0xf7, 0xd6, 0x99, 0x0a, 0x42, 0x2c, 0xfe, 0x3d, 0xf0, 0xfe, 0x06,
10800 0x02, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x91, 0xf0, 0xfe, 0xf4, 0x01, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010801 0x90, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, 0x8f, 0xf0, 0xa7, 0x03, 0x5d, 0x4d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010802 0x02, 0xfe, 0xc8, 0x0d, 0x01, 0xfe, 0x38, 0x0e, 0xfe, 0xdd, 0x12, 0xfe,
10803 0xfc, 0x10, 0xfe, 0x28, 0x1c, 0x03, 0xfe, 0xa6, 0x00, 0xfe, 0xd3, 0x12,
10804 0x41, 0x14, 0xfe, 0xa6, 0x00, 0xc2, 0xfe, 0x48, 0xf0, 0xfe, 0x8a, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010805 0xfe, 0x49, 0xf0, 0xfe, 0xa4, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc2, 0x02,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010806 0xfe, 0x46, 0xf0, 0xfe, 0x54, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x5a, 0x02,
10807 0xfe, 0x43, 0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x4c, 0x02,
10808 0xfe, 0x45, 0xf0, 0xfe, 0x50, 0x02, 0x18, 0x0a, 0xaa, 0x18, 0x06, 0x14,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010809 0xa1, 0x02, 0x2b, 0xfe, 0x00, 0x1c, 0xe7, 0xfe, 0x02, 0x1c, 0xe6, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010810 0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0xfe, 0x18, 0x18, 0xfe, 0xe7, 0x10,
10811 0xfe, 0x06, 0xfc, 0xce, 0x09, 0x70, 0x01, 0xa8, 0x02, 0x2b, 0x15, 0x59,
10812 0x39, 0xa2, 0x01, 0xfe, 0x58, 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xbd,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010813 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010814 0x58, 0x1c, 0x18, 0x06, 0x14, 0xa1, 0x2c, 0x1c, 0x2b, 0xfe, 0x3d, 0xf0,
10815 0xfe, 0x06, 0x02, 0x23, 0xfe, 0x98, 0x02, 0xfe, 0x5a, 0x1c, 0xf8, 0xfe,
10816 0x14, 0x1c, 0x15, 0xfe, 0x30, 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010817 0x18, 0x06, 0x14, 0xa1, 0x02, 0xd7, 0x22, 0x20, 0x07, 0x11, 0x35, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010818 0x69, 0x10, 0x18, 0x06, 0x14, 0xa1, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0x43,
10819 0x13, 0x20, 0xfe, 0x05, 0xf6, 0xce, 0x01, 0xfe, 0x4a, 0x17, 0x08, 0x54,
10820 0x58, 0x37, 0x12, 0x2f, 0x42, 0x92, 0x01, 0xfe, 0x82, 0x16, 0x02, 0x2b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010821 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x01, 0x73, 0xfe, 0x18, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010822 0xfe, 0x41, 0x58, 0x09, 0xa4, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x6b, 0xfe,
10823 0x10, 0x03, 0x01, 0xfe, 0x82, 0x16, 0x02, 0x2b, 0x2c, 0x4f, 0xfe, 0x02,
10824 0xe8, 0x2a, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010825 0x27, 0xf0, 0xfe, 0xe0, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xa7,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010826 0xfe, 0x40, 0x1c, 0x1c, 0xd9, 0xfe, 0x26, 0xf0, 0xfe, 0x5a, 0x03, 0xfe,
10827 0xa0, 0xf0, 0xfe, 0x48, 0x03, 0xfe, 0x11, 0xf0, 0xa7, 0xfe, 0xef, 0x10,
10828 0xfe, 0x9f, 0xf0, 0xfe, 0x68, 0x03, 0xf9, 0x10, 0xfe, 0x11, 0x00, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010829 0x65, 0x2c, 0xfe, 0x48, 0x1c, 0xf9, 0x08, 0x05, 0x1b, 0xfe, 0x18, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010830 0x21, 0x22, 0xa3, 0xb7, 0x13, 0xa3, 0x09, 0x46, 0x01, 0x0e, 0xb7, 0x78,
10831 0x01, 0xfe, 0xb4, 0x16, 0x12, 0xd1, 0x1c, 0xd9, 0xfe, 0x01, 0xf0, 0xd9,
10832 0xfe, 0x82, 0xf0, 0xfe, 0x96, 0x03, 0xfa, 0x12, 0xfe, 0xe4, 0x00, 0x27,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010833 0xfe, 0xa8, 0x03, 0x1c, 0x34, 0x1d, 0xfe, 0xb8, 0x03, 0x01, 0x4b, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010834 0x06, 0xf0, 0xfe, 0xc8, 0x03, 0x95, 0x86, 0xfe, 0x0a, 0xf0, 0xfe, 0x8a,
10835 0x06, 0x02, 0x24, 0x03, 0x70, 0x28, 0x17, 0xfe, 0xfa, 0x04, 0x15, 0x6d,
10836 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, 0xd8, 0xf9, 0x2c, 0x99, 0x19,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010837 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010838 0x74, 0x01, 0xaf, 0x8c, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x17, 0xda,
10839 0x09, 0xd1, 0x01, 0x0e, 0x8d, 0x51, 0x64, 0x79, 0x2a, 0x03, 0x70, 0x28,
10840 0xfe, 0x10, 0x12, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010841 0xd8, 0xc7, 0x81, 0xc8, 0x83, 0x1c, 0x24, 0x27, 0xfe, 0x40, 0x04, 0x1d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010842 0xfe, 0x3c, 0x04, 0x3b, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e,
10843 0x12, 0x2d, 0xff, 0x02, 0x00, 0x10, 0x01, 0x0b, 0x1d, 0xfe, 0xe4, 0x04,
10844 0x2d, 0x01, 0x0b, 0x1d, 0x24, 0x33, 0x31, 0xde, 0xfe, 0x4c, 0x44, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010845 0x4c, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010846 0xda, 0x4f, 0x79, 0x2a, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x62,
10847 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x2a, 0x13, 0x32, 0x07, 0x82, 0xfe, 0x52,
10848 0x13, 0xfe, 0x20, 0x10, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b, 0xda, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010849 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x40, 0x13, 0x08, 0x05, 0x1b, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010850 0x08, 0x13, 0x32, 0x07, 0x82, 0xfe, 0x30, 0x13, 0x08, 0x05, 0x1b, 0xfe,
10851 0x1c, 0x12, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe, 0x0d, 0x00,
10852 0x01, 0x36, 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x2d, 0x12, 0xfe, 0xe6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010853 0x00, 0xfe, 0x1c, 0x90, 0xfe, 0x40, 0x5c, 0x04, 0x15, 0x9d, 0x01, 0x36,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010854 0x02, 0x2b, 0xfe, 0x42, 0x5b, 0x99, 0x19, 0xfe, 0x46, 0x59, 0xfe, 0xbf,
10855 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x87, 0x80, 0xfe, 0x31, 0xe4, 0x5b, 0x08,
10856 0x05, 0x0a, 0xfe, 0x84, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x19, 0xfe, 0x7c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010857 0x12, 0x53, 0x05, 0x06, 0xfe, 0x6c, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x28,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010858 0x17, 0xfe, 0x90, 0x05, 0xfe, 0x31, 0xe4, 0x5a, 0x53, 0x05, 0x0a, 0xfe,
10859 0x56, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x28, 0xfe, 0x4e, 0x12, 0x67, 0xff,
10860 0x02, 0x00, 0x10, 0x27, 0xfe, 0x48, 0x05, 0x1c, 0x34, 0xfe, 0x89, 0x48,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010861 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x56, 0x05, 0x26, 0xfe, 0xa8, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010862 0x12, 0xfe, 0xe3, 0x00, 0x21, 0x53, 0xfe, 0x4a, 0xf0, 0xfe, 0x76, 0x05,
10863 0xfe, 0x49, 0xf0, 0xfe, 0x70, 0x05, 0x88, 0x25, 0xfe, 0x21, 0x00, 0xab,
10864 0x25, 0xfe, 0x22, 0x00, 0xaa, 0x25, 0x58, 0xfe, 0x09, 0x48, 0xff, 0x02,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010865 0x00, 0x10, 0x27, 0xfe, 0x86, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0xfe, 0xe2,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010866 0x08, 0x53, 0x05, 0xcb, 0x4d, 0x01, 0xb0, 0x25, 0x06, 0x13, 0xd3, 0x39,
10867 0xfe, 0x27, 0x01, 0x08, 0x05, 0x1b, 0xfe, 0x22, 0x12, 0x41, 0x01, 0xb2,
10868 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010869 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0xeb,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010870 0x03, 0x5c, 0x28, 0xfe, 0x36, 0x13, 0x41, 0x01, 0xb2, 0x26, 0xfe, 0x18,
10871 0x06, 0x09, 0x06, 0x53, 0x05, 0x1f, 0xfe, 0x02, 0x12, 0x50, 0x01, 0xfe,
10872 0x9e, 0x15, 0x1d, 0xfe, 0x0e, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010873 0xe5, 0x00, 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x03, 0xcd, 0x28, 0xfe, 0x62,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010874 0x12, 0x03, 0x45, 0x28, 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x0c, 0x19, 0x01,
10875 0xfe, 0x76, 0x19, 0xfe, 0x43, 0x48, 0xc4, 0xcc, 0x0f, 0x71, 0xff, 0x02,
10876 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0x8b, 0xc4, 0x6e, 0x41, 0x01, 0xb2,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010877 0x26, 0xfe, 0x82, 0x06, 0x53, 0x05, 0x1a, 0xe9, 0x91, 0x09, 0x59, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010878 0xfe, 0xcc, 0x15, 0x1d, 0xfe, 0x78, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12,
10879 0xfe, 0xe5, 0x00, 0x03, 0x45, 0xc1, 0x0c, 0x45, 0x18, 0x06, 0x01, 0xb2,
10880 0xfa, 0x76, 0x74, 0x01, 0xaf, 0x8c, 0x12, 0xfe, 0xe2, 0x00, 0x27, 0xdb,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010881 0x1c, 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0xb6, 0x06, 0x94, 0xfe, 0x6c, 0x07,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010882 0xfe, 0x06, 0xf0, 0xfe, 0x74, 0x07, 0x95, 0x86, 0x02, 0x24, 0x08, 0x05,
10883 0x0a, 0xfe, 0x2e, 0x12, 0x16, 0x19, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b,
10884 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0xfe, 0x99, 0xa4, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010885 0x0b, 0x16, 0x00, 0x02, 0xfe, 0x42, 0x08, 0x68, 0x05, 0x1a, 0xfe, 0x38,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010886 0x12, 0x08, 0x05, 0x1a, 0xfe, 0x30, 0x13, 0x16, 0xfe, 0x1b, 0x00, 0x01,
10887 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01,
10888 0x0b, 0x16, 0x06, 0x01, 0x0b, 0x16, 0x00, 0x02, 0xe2, 0x6c, 0x58, 0xbe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010889 0x50, 0xfe, 0x9a, 0x81, 0x55, 0x1b, 0x7a, 0xfe, 0x42, 0x07, 0x09, 0x1b,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010890 0xfe, 0x09, 0x6f, 0xba, 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x69, 0x6d,
10891 0x8b, 0x6c, 0x7f, 0x27, 0xfe, 0x54, 0x07, 0x1c, 0x34, 0xfe, 0x0a, 0xf0,
10892 0xfe, 0x42, 0x07, 0x95, 0x86, 0x94, 0xfe, 0x6c, 0x07, 0x02, 0x24, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010893 0x4b, 0x02, 0xdb, 0x16, 0x1f, 0x02, 0xdb, 0xfe, 0x9c, 0xf7, 0xdc, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010894 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x56, 0xfe, 0xda, 0x07, 0x0c, 0x60, 0x14,
10895 0x61, 0x08, 0x54, 0x5a, 0x37, 0x22, 0x20, 0x07, 0x11, 0xfe, 0x0e, 0x12,
10896 0x8d, 0xfe, 0x80, 0x80, 0x39, 0x20, 0x6a, 0x2a, 0xfe, 0x06, 0x10, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010897 0x83, 0xe7, 0xfe, 0x48, 0x00, 0xab, 0xfe, 0x03, 0x40, 0x08, 0x54, 0x5b,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010898 0x37, 0x01, 0xb3, 0xb8, 0xfe, 0x1f, 0x40, 0x13, 0x62, 0x01, 0xef, 0xfe,
10899 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0x88,
10900 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e, 0x14, 0x5f, 0xfe, 0x0c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010901 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x0c, 0x3d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010902 0x14, 0x3e, 0xfe, 0x4a, 0x10, 0x08, 0x05, 0x5a, 0xfe, 0x2a, 0x12, 0xfe,
10903 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x60, 0x14, 0x61, 0x08, 0x05, 0x5b,
10904 0x8b, 0x01, 0xb3, 0xfe, 0x1f, 0x80, 0x13, 0x62, 0xfe, 0x44, 0x90, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010905 0xc6, 0x90, 0x0c, 0x3f, 0x14, 0x40, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010906 0x0c, 0x5e, 0x14, 0x5f, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x3d,
10907 0x14, 0x3e, 0x0c, 0x2e, 0x14, 0x3c, 0x21, 0x0c, 0x49, 0x0c, 0x63, 0x08,
10908 0x54, 0x1f, 0x37, 0x2c, 0x0f, 0xfe, 0x4e, 0x11, 0x27, 0xdd, 0xfe, 0x9e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010909 0xf0, 0xfe, 0x76, 0x08, 0xbc, 0x17, 0x34, 0x2c, 0x77, 0xe6, 0xc5, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010910 0x9a, 0x08, 0xc6, 0xfe, 0xb8, 0x08, 0x94, 0xfe, 0x8e, 0x08, 0xfe, 0x06,
10911 0xf0, 0xfe, 0x94, 0x08, 0x95, 0x86, 0x02, 0x24, 0x01, 0x4b, 0xfe, 0xc9,
10912 0x10, 0x16, 0x1f, 0xfe, 0xc9, 0x10, 0x68, 0x05, 0x06, 0xfe, 0x10, 0x12,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010913 0x68, 0x05, 0x0a, 0x4e, 0x08, 0x05, 0x0a, 0xfe, 0x90, 0x12, 0xfe, 0x2e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010914 0x1c, 0x02, 0xfe, 0x18, 0x0b, 0x68, 0x05, 0x06, 0x4e, 0x68, 0x05, 0x0a,
10915 0xfe, 0x7a, 0x12, 0xfe, 0x2c, 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0xd2, 0x09,
10916 0xfe, 0xac, 0xf0, 0xfe, 0x00, 0x09, 0x02, 0xfe, 0xde, 0x09, 0xfe, 0xb7,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010917 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0x02, 0xf6, 0x1a, 0x50, 0xfe, 0x70, 0x18,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010918 0xfe, 0xf1, 0x18, 0xfe, 0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58,
10919 0xfe, 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x1c, 0x85, 0xfe,
10920 0x8c, 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0xac, 0xf0, 0xfe, 0xf0, 0x08, 0xb5,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010921 0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x0c, 0x09, 0x02, 0xfe, 0x18,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010922 0x0b, 0xb6, 0xfe, 0xbf, 0x10, 0xfe, 0x2b, 0xf0, 0x85, 0xf4, 0x1e, 0xfe,
10923 0x00, 0xfe, 0xfe, 0x1c, 0x12, 0xc2, 0xfe, 0xd2, 0xf0, 0x85, 0xfe, 0x76,
10924 0x18, 0x1e, 0x19, 0x17, 0x85, 0x03, 0xd2, 0x1e, 0x06, 0x17, 0x85, 0xc5,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010925 0x4a, 0xc6, 0x4a, 0xb5, 0xb6, 0xfe, 0x89, 0x10, 0x74, 0x67, 0x2d, 0x15,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010926 0x9d, 0x01, 0x36, 0x10, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x65, 0x10,
10927 0x80, 0x02, 0x65, 0xfe, 0x98, 0x80, 0xfe, 0x19, 0xe4, 0x0a, 0xfe, 0x1a,
10928 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18, 0xfe, 0x44, 0x54, 0xbe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010929 0xfe, 0x19, 0x81, 0xfe, 0x74, 0x18, 0x8f, 0x90, 0x17, 0xfe, 0xce, 0x08,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010930 0x02, 0x4a, 0x08, 0x05, 0x5a, 0xec, 0x03, 0x2e, 0x29, 0x3c, 0x0c, 0x3f,
10931 0x14, 0x40, 0x9b, 0x2e, 0x9c, 0x3c, 0xfe, 0x6c, 0x18, 0xfe, 0xed, 0x18,
10932 0xfe, 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x3a, 0x3f, 0x3b, 0x40, 0x03, 0x49,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010933 0x29, 0x63, 0x8f, 0xfe, 0xe3, 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010934 0x8f, 0xfe, 0xe3, 0x54, 0x90, 0xc0, 0x56, 0xfe, 0xce, 0x08, 0x02, 0x4a,
10935 0xfe, 0x37, 0xf0, 0xfe, 0xda, 0x09, 0xfe, 0x8b, 0xf0, 0xfe, 0x60, 0x09,
10936 0x02, 0x4a, 0x08, 0x05, 0x0a, 0x23, 0xfe, 0xfa, 0x0a, 0x3a, 0x49, 0x3b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010937 0x63, 0x56, 0xfe, 0x3e, 0x0a, 0x0f, 0xfe, 0xc0, 0x07, 0x41, 0x98, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010938 0xad, 0xfe, 0x01, 0x59, 0xfe, 0x52, 0xf0, 0xfe, 0x0c, 0x0a, 0x8f, 0x7a,
10939 0xfe, 0x24, 0x0a, 0x3a, 0x49, 0x8f, 0xfe, 0xe3, 0x54, 0x57, 0x49, 0x7d,
10940 0x63, 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02, 0x4a, 0x3a, 0x49, 0x3b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010941 0x63, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xbe, 0x57, 0x49, 0x57, 0x63,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010942 0x02, 0x4a, 0x08, 0x05, 0x5a, 0xfe, 0x82, 0x12, 0x08, 0x05, 0x1f, 0xfe,
10943 0x66, 0x13, 0x22, 0x62, 0xb7, 0xfe, 0x03, 0xa1, 0xfe, 0x83, 0x80, 0xfe,
10944 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x6a,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010945 0x2a, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x56, 0xe0, 0x03, 0x60, 0x29,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010946 0x61, 0x0c, 0x7f, 0x14, 0x80, 0x57, 0x60, 0x7d, 0x61, 0x01, 0xb3, 0xb8,
10947 0x6a, 0x2a, 0x13, 0x62, 0x9b, 0x2e, 0x9c, 0x3c, 0x3a, 0x3f, 0x3b, 0x40,
10948 0x90, 0xc0, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0x01, 0xef,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010949 0xfe, 0x36, 0x10, 0x21, 0x0c, 0x7f, 0x0c, 0x80, 0x3a, 0x3f, 0x3b, 0x40,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010950 0xe4, 0x08, 0x05, 0x1f, 0x17, 0xe0, 0x3a, 0x3d, 0x3b, 0x3e, 0x08, 0x05,
10951 0xfe, 0xf7, 0x00, 0x37, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x10, 0x58, 0xfe,
10952 0x91, 0x58, 0x57, 0x49, 0x7d, 0x63, 0x02, 0xfe, 0xf4, 0x09, 0x08, 0x05,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010953 0x1f, 0x17, 0xe0, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0xbe, 0xfe, 0x19,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010954 0x81, 0x50, 0xfe, 0x10, 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd3, 0x10, 0x32,
10955 0x07, 0xa6, 0x17, 0xfe, 0x08, 0x09, 0x12, 0xa6, 0x08, 0x05, 0x0a, 0xfe,
10956 0x14, 0x13, 0x03, 0x3d, 0x29, 0x3e, 0x56, 0xfe, 0x08, 0x09, 0xfe, 0x0c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010957 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x4a, 0x21, 0x41, 0xfe, 0x19, 0x80, 0xe7,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010958 0x08, 0x05, 0x0a, 0xfe, 0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41,
10959 0xf4, 0xc2, 0xfe, 0xd1, 0xf0, 0xe2, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe,
10960 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0x57, 0x3d, 0xfe, 0xed,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010961 0x19, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xf4, 0x1e, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010962 0x00, 0xff, 0x35, 0xfe, 0x74, 0x10, 0xc2, 0xfe, 0xd2, 0xf0, 0xfe, 0xa6,
10963 0x0b, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x8a, 0x03, 0xd2, 0x1e, 0x06, 0xfe,
10964 0x08, 0x13, 0x10, 0xfe, 0x16, 0x00, 0x02, 0x65, 0xfe, 0xd1, 0xf0, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010965 0xb8, 0x0b, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, 0x17, 0x00, 0xfe, 0x42,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010966 0x10, 0xfe, 0xce, 0xf0, 0xfe, 0xbe, 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd,
10967 0xf0, 0xfe, 0xca, 0x0b, 0x10, 0xfe, 0x22, 0x00, 0x02, 0x65, 0xfe, 0xcb,
10968 0xf0, 0xfe, 0xd6, 0x0b, 0x10, 0xfe, 0x24, 0x00, 0x02, 0x65, 0xfe, 0xd0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010969 0xf0, 0xfe, 0xe0, 0x0b, 0x10, 0x9e, 0xe5, 0xfe, 0xcf, 0xf0, 0xfe, 0xea,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010970 0x0b, 0x10, 0x58, 0xfe, 0x10, 0x10, 0xfe, 0xcc, 0xf0, 0xe2, 0x68, 0x05,
10971 0x1f, 0x4d, 0x10, 0xfe, 0x12, 0x00, 0x2c, 0x0f, 0xfe, 0x4e, 0x11, 0x27,
10972 0xfe, 0x00, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x14, 0x0c, 0xbc, 0x17, 0x34,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010973 0x2c, 0x77, 0xe6, 0xc5, 0x24, 0xc6, 0x24, 0x2c, 0xfa, 0x27, 0xfe, 0x20,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010974 0x0c, 0x1c, 0x34, 0x94, 0xfe, 0x3c, 0x0c, 0x95, 0x86, 0xc5, 0xdc, 0xc6,
10975 0xdc, 0x02, 0x24, 0x01, 0x4b, 0xfe, 0xdb, 0x10, 0x12, 0xfe, 0xe8, 0x00,
10976 0xb5, 0xb6, 0x74, 0xc7, 0x81, 0xc8, 0x83, 0xfe, 0x89, 0xf0, 0x24, 0x33,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010977 0x31, 0xe1, 0xc7, 0x81, 0xc8, 0x83, 0x27, 0xfe, 0x66, 0x0c, 0x1d, 0x24,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010978 0x33, 0x31, 0xdf, 0xbc, 0x4e, 0x10, 0xfe, 0x42, 0x00, 0x02, 0x65, 0x7c,
10979 0x06, 0xfe, 0x81, 0x49, 0x17, 0xfe, 0x2c, 0x0d, 0x08, 0x05, 0x0a, 0xfe,
10980 0x44, 0x13, 0x10, 0x00, 0x55, 0x0a, 0xfe, 0x54, 0x12, 0x55, 0xfe, 0x28,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010981 0x00, 0x23, 0xfe, 0x9a, 0x0d, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010982 0x44, 0xfe, 0x28, 0x00, 0xfe, 0xe2, 0x10, 0x01, 0xf5, 0x01, 0xf6, 0x09,
10983 0xa4, 0x01, 0xfe, 0x26, 0x0f, 0x64, 0x12, 0x2f, 0x01, 0x73, 0x02, 0x2b,
10984 0x10, 0xfe, 0x44, 0x00, 0x55, 0x0a, 0xe9, 0x44, 0x0a, 0xfe, 0xb4, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010985 0x01, 0xb0, 0x44, 0x0a, 0xfe, 0xaa, 0x10, 0x01, 0xb0, 0xfe, 0x19, 0x82,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010986 0xfe, 0x34, 0x46, 0xac, 0x44, 0x0a, 0x10, 0xfe, 0x43, 0x00, 0xfe, 0x96,
10987 0x10, 0x08, 0x54, 0x0a, 0x37, 0x01, 0xf5, 0x01, 0xf6, 0x64, 0x12, 0x2f,
10988 0x01, 0x73, 0x99, 0x0a, 0x64, 0x42, 0x92, 0x02, 0xfe, 0x2e, 0x03, 0x08,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010989 0x05, 0x0a, 0x8a, 0x44, 0x0a, 0x10, 0x00, 0xfe, 0x5c, 0x10, 0x68, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010990 0x1a, 0xfe, 0x58, 0x12, 0x08, 0x05, 0x1a, 0xfe, 0x50, 0x13, 0xfe, 0x1c,
10991 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x50, 0x0d, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d,
10992 0xf0, 0xfe, 0x56, 0x0d, 0x08, 0x54, 0x1a, 0x37, 0xfe, 0xa9, 0x10, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010993 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0a, 0x50, 0xfe, 0x2e, 0x10, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010994 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x10, 0x6f, 0xab, 0x10, 0xfe, 0x41,
10995 0x00, 0xaa, 0x10, 0xfe, 0x24, 0x00, 0x8c, 0xb5, 0xb6, 0x74, 0x03, 0x70,
10996 0x28, 0x23, 0xd8, 0x50, 0xfe, 0x04, 0xe6, 0x1a, 0xfe, 0x9d, 0x41, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010997 0x1c, 0x42, 0x64, 0x01, 0xe3, 0x02, 0x2b, 0xf8, 0x15, 0x0a, 0x39, 0xa0,
Matthew Wilcox629d6882007-09-09 08:56:29 -060010998 0xb4, 0x15, 0xfe, 0x31, 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, 0x02,
10999 0xd7, 0x42, 0xfe, 0x06, 0xec, 0xd0, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45,
11000 0x35, 0x42, 0xfe, 0x06, 0xea, 0xd0, 0xfe, 0x47, 0x4b, 0x91, 0xfe, 0x75,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011001 0x57, 0x03, 0x5d, 0xfe, 0x98, 0x56, 0xfe, 0x38, 0x12, 0x09, 0x48, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011002 0x0e, 0xfe, 0x44, 0x48, 0x4f, 0x08, 0x05, 0x1b, 0xfe, 0x1a, 0x13, 0x09,
11003 0x46, 0x01, 0x0e, 0x41, 0xfe, 0x41, 0x58, 0x09, 0xa4, 0x01, 0x0e, 0xfe,
11004 0x49, 0x54, 0x96, 0xfe, 0x1e, 0x0e, 0x02, 0xfe, 0x2e, 0x03, 0x09, 0x5d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011005 0xfe, 0xee, 0x14, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011006 0xce, 0x47, 0xfe, 0xad, 0x13, 0x02, 0x2b, 0x22, 0x20, 0x07, 0x11, 0xfe,
11007 0x9e, 0x12, 0x21, 0x13, 0x59, 0x13, 0x9f, 0x13, 0xd5, 0x22, 0x2f, 0x41,
11008 0x39, 0x2f, 0xbc, 0xad, 0xfe, 0xbc, 0xf0, 0xfe, 0xe0, 0x0e, 0x0f, 0x06,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011009 0x13, 0x59, 0x01, 0xfe, 0xda, 0x16, 0x03, 0xfe, 0x38, 0x01, 0x29, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011010 0x3a, 0x01, 0x56, 0xfe, 0xe4, 0x0e, 0xfe, 0x02, 0xec, 0xd5, 0x69, 0x00,
11011 0x66, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01,
11012 0x01, 0xfe, 0x4a, 0x17, 0xfe, 0x08, 0x90, 0xfe, 0x48, 0xf4, 0x0d, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011013 0x18, 0x13, 0xba, 0xfe, 0x02, 0xea, 0xd5, 0x69, 0x7e, 0xfe, 0xc5, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011014 0x15, 0x1a, 0x39, 0xa0, 0xb4, 0xfe, 0x2e, 0x10, 0x03, 0xfe, 0x38, 0x01,
11015 0x1e, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x03, 0xfe, 0x3a, 0x01,
11016 0x0c, 0xfe, 0x62, 0x01, 0x43, 0x13, 0x20, 0x25, 0x06, 0x13, 0x2f, 0x12,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011017 0x2f, 0x92, 0x0f, 0x06, 0x04, 0x21, 0x04, 0x22, 0x59, 0xfe, 0xf7, 0x12,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011018 0x22, 0x9f, 0xb7, 0x13, 0x9f, 0x07, 0x7e, 0xfe, 0x71, 0x13, 0xfe, 0x24,
11019 0x1c, 0x15, 0x19, 0x39, 0xa0, 0xb4, 0xfe, 0xd9, 0x10, 0xc3, 0xfe, 0x03,
11020 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xc3, 0xfe, 0x03, 0xdc,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011021 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x21,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011022 0xfe, 0x00, 0xcc, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x78, 0x04, 0x08, 0x05,
11023 0x58, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13,
11024 0xfe, 0x1e, 0x80, 0xed, 0xfe, 0x1d, 0x80, 0xae, 0xfe, 0x0c, 0x90, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011025 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xac, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011026 0x0a, 0xfe, 0x3c, 0x50, 0xaa, 0x01, 0xfe, 0x7a, 0x17, 0x32, 0x07, 0x2f,
11027 0xad, 0x01, 0xfe, 0xb4, 0x16, 0x08, 0x05, 0x1b, 0x4e, 0x01, 0xf5, 0x01,
11028 0xf6, 0x12, 0xfe, 0xe9, 0x00, 0x08, 0x05, 0x58, 0xfe, 0x2c, 0x13, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011029 0xfe, 0x0c, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011030 0x0c, 0xfe, 0x64, 0x01, 0x14, 0xfe, 0x66, 0x01, 0x08, 0x05, 0x5b, 0xfe,
11031 0x12, 0x12, 0xfe, 0x03, 0x80, 0x8d, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80,
11032 0x40, 0x13, 0x20, 0x6a, 0x2a, 0x12, 0xcf, 0x64, 0x22, 0x20, 0xfb, 0x79,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011033 0x20, 0x04, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011034 0x03, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe,
11035 0x08, 0x58, 0x03, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
11036 0x25, 0x6e, 0x13, 0xd0, 0x21, 0x0c, 0x5c, 0x0c, 0x45, 0x0f, 0x46, 0x52,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011037 0x50, 0x18, 0x1b, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xfe, 0xfc,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011038 0x0f, 0x44, 0x11, 0x0f, 0x48, 0x52, 0x18, 0x58, 0xfe, 0x90, 0x4d, 0xfe,
11039 0x91, 0x54, 0x23, 0xe4, 0x25, 0x11, 0x13, 0x20, 0x7c, 0x6f, 0x4f, 0x22,
11040 0x20, 0xfb, 0x79, 0x20, 0x12, 0xcf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011041 0xfe, 0x26, 0x10, 0xf8, 0x74, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011042 0x18, 0x1c, 0x04, 0x42, 0xfe, 0x0c, 0x14, 0xfc, 0xfe, 0x07, 0xe6, 0x1b,
11043 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x04, 0x01, 0xb0, 0x7c, 0x6f, 0x4f,
11044 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0x32, 0x07, 0x2f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011045 0xfe, 0x34, 0x13, 0x09, 0x48, 0x01, 0x0e, 0xbb, 0xfe, 0x36, 0x12, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011046 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe,
11047 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, 0x84, 0x01, 0x0e, 0xfe,
11048 0x80, 0x5c, 0x01, 0x73, 0xfe, 0x0e, 0x10, 0x07, 0x82, 0x4e, 0xfe, 0x14,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011049 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x60, 0x10, 0x04, 0xfe, 0x44, 0x58, 0x8d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011050 0xfe, 0x01, 0xec, 0xa2, 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe,
11051 0x9c, 0xe7, 0x1a, 0x79, 0x2a, 0x01, 0xe3, 0xfe, 0xdd, 0x10, 0x2c, 0xc7,
11052 0x81, 0xc8, 0x83, 0x33, 0x31, 0xde, 0x07, 0x1a, 0xfe, 0x48, 0x12, 0x07,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011053 0x0a, 0xfe, 0x56, 0x12, 0x07, 0x19, 0xfe, 0x30, 0x12, 0x07, 0xc9, 0x17,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011054 0xfe, 0x32, 0x12, 0x07, 0xfe, 0x23, 0x00, 0x17, 0xeb, 0x07, 0x06, 0x17,
11055 0xfe, 0x9c, 0x12, 0x07, 0x1f, 0xfe, 0x12, 0x12, 0x07, 0x00, 0x17, 0x24,
11056 0x15, 0xc9, 0x01, 0x36, 0xa9, 0x2d, 0x01, 0x0b, 0x94, 0x4b, 0x04, 0x2d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011057 0xdd, 0x09, 0xd1, 0x01, 0xfe, 0x26, 0x0f, 0x12, 0x82, 0x02, 0x2b, 0x2d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011058 0x32, 0x07, 0xa6, 0xfe, 0xd9, 0x13, 0x3a, 0x3d, 0x3b, 0x3e, 0x56, 0xfe,
11059 0xf0, 0x11, 0x08, 0x05, 0x5a, 0xfe, 0x72, 0x12, 0x9b, 0x2e, 0x9c, 0x3c,
11060 0x90, 0xc0, 0x96, 0xfe, 0xba, 0x11, 0x22, 0x62, 0xfe, 0x26, 0x13, 0x03,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011061 0x7f, 0x29, 0x80, 0x56, 0xfe, 0x76, 0x0d, 0x0c, 0x60, 0x14, 0x61, 0x21,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011062 0x0c, 0x7f, 0x0c, 0x80, 0x01, 0xb3, 0x25, 0x6e, 0x77, 0x13, 0x62, 0x01,
11063 0xef, 0x9b, 0x2e, 0x9c, 0x3c, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe,
11064 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0xfe, 0x91, 0x10, 0x03, 0x3f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011065 0x29, 0x40, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x3f, 0x14, 0x40,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011066 0x88, 0x9b, 0x2e, 0x9c, 0x3c, 0x90, 0xc0, 0x03, 0x5e, 0x29, 0x5f, 0xfe,
11067 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x0c, 0x5e, 0x14, 0x5f, 0x08, 0x05, 0x5a,
11068 0xfe, 0x1e, 0x12, 0x22, 0x62, 0xfe, 0x1f, 0x40, 0x03, 0x60, 0x29, 0x61,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011069 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x03, 0x3f, 0x29, 0x40, 0xfe, 0x44,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011070 0x50, 0xfe, 0xc6, 0x50, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x08, 0x50, 0xfe,
11071 0x8a, 0x50, 0x03, 0x3d, 0x29, 0x3e, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50,
11072 0x02, 0x89, 0x25, 0x06, 0x13, 0xd4, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011073 0x4c, 0x33, 0x31, 0xde, 0x07, 0x06, 0x23, 0x4c, 0x32, 0x07, 0xa6, 0x23,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011074 0x72, 0x01, 0xaf, 0x1e, 0x43, 0x17, 0x4c, 0x08, 0x05, 0x0a, 0xee, 0x3a,
11075 0x3d, 0x3b, 0x3e, 0xfe, 0x0a, 0x55, 0x35, 0xfe, 0x8b, 0x55, 0x57, 0x3d,
11076 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x02, 0x72, 0xfe, 0x19,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011077 0x81, 0xba, 0xfe, 0x19, 0x41, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1c, 0x34,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011078 0x1d, 0xe8, 0x33, 0x31, 0xe1, 0x55, 0x19, 0xfe, 0xa6, 0x12, 0x55, 0x0a,
11079 0x4d, 0x02, 0x4c, 0x01, 0x0b, 0x1c, 0x34, 0x1d, 0xe8, 0x33, 0x31, 0xdf,
11080 0x07, 0x19, 0x23, 0x4c, 0x01, 0x0b, 0x1d, 0xe8, 0x33, 0x31, 0xfe, 0xe8,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011081 0x09, 0xfe, 0xc2, 0x49, 0x51, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0x8a, 0x53,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011082 0x05, 0x1f, 0x35, 0xa9, 0xfe, 0xbb, 0x45, 0x55, 0x00, 0x4e, 0x44, 0x06,
11083 0x7c, 0x43, 0xfe, 0xda, 0x14, 0x01, 0xaf, 0x8c, 0xfe, 0x4b, 0x45, 0xee,
11084 0x32, 0x07, 0xa5, 0xed, 0x03, 0xcd, 0x28, 0x8a, 0x03, 0x45, 0x28, 0x35,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011085 0x67, 0x02, 0x72, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011086 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01,
11087 0xfe, 0x9e, 0x15, 0x02, 0x89, 0x01, 0x0b, 0x1c, 0x34, 0x1d, 0x4c, 0x33,
11088 0x31, 0xdf, 0x07, 0x06, 0x23, 0x4c, 0x01, 0xf1, 0xfe, 0x42, 0x58, 0xf1,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011089 0xfe, 0xa4, 0x14, 0x8c, 0xfe, 0x4a, 0xf4, 0x0a, 0x17, 0x4c, 0xfe, 0x4a,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011090 0xf4, 0x06, 0xea, 0x32, 0x07, 0xa5, 0x8b, 0x02, 0x72, 0x03, 0x45, 0xc1,
11091 0x0c, 0x45, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, 0xfe, 0xcc, 0x15,
11092 0x02, 0x89, 0x0f, 0x06, 0x27, 0xfe, 0xbe, 0x13, 0x26, 0xfe, 0xd4, 0x13,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011093 0x76, 0xfe, 0x89, 0x48, 0x01, 0x0b, 0x21, 0x76, 0x04, 0x7b, 0xfe, 0xd0,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011094 0x13, 0x1c, 0xfe, 0xd0, 0x13, 0x1d, 0xfe, 0xbe, 0x13, 0x67, 0x2d, 0x01,
11095 0x0b, 0xfe, 0xd5, 0x10, 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93,
11096 0x1e, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x04, 0x0f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011097 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0xfe, 0x30, 0x56,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011098 0xfe, 0x00, 0x5c, 0x04, 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93,
11099 0x04, 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0xfe, 0x0b, 0x58,
11100 0x04, 0x09, 0x5c, 0x01, 0x87, 0x09, 0x45, 0x01, 0x87, 0x04, 0xfe, 0x03,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011101 0xa1, 0x1e, 0x11, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x1f, 0x52,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011102 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c,
11103 0x6a, 0x2a, 0x0c, 0x5e, 0x14, 0x5f, 0x57, 0x3f, 0x7d, 0x40, 0x04, 0xdd,
11104 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x8d, 0x04, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011105 0xfe, 0x0c, 0x19, 0xfe, 0x42, 0x48, 0x50, 0x51, 0x91, 0x01, 0x0b, 0x1d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011106 0xfe, 0x96, 0x15, 0x33, 0x31, 0xe1, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15,
11107 0x33, 0x31, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x03, 0xcd, 0x28, 0xfe,
11108 0xcc, 0x12, 0x53, 0x05, 0x1a, 0xfe, 0xc4, 0x13, 0x21, 0x69, 0x1a, 0xee,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011109 0x55, 0xca, 0x6b, 0xfe, 0xdc, 0x14, 0x4d, 0x0f, 0x06, 0x18, 0xca, 0x7c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011110 0x30, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xab, 0xff, 0x02, 0x83,
11111 0x55, 0x69, 0x19, 0xae, 0x98, 0xfe, 0x30, 0x00, 0x96, 0xf2, 0x18, 0x6d,
11112 0x0f, 0x06, 0xfe, 0x56, 0x10, 0x69, 0x0a, 0xed, 0x98, 0xfe, 0x64, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011113 0x96, 0xf2, 0x09, 0xfe, 0x64, 0x00, 0x18, 0x9e, 0x0f, 0x06, 0xfe, 0x28,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011114 0x10, 0x69, 0x06, 0xfe, 0x60, 0x13, 0x98, 0xfe, 0xc8, 0x00, 0x96, 0xf2,
11115 0x09, 0xfe, 0xc8, 0x00, 0x18, 0x59, 0x0f, 0x06, 0x88, 0x98, 0xfe, 0x90,
11116 0x01, 0x7a, 0xfe, 0x42, 0x15, 0x91, 0xe4, 0xfe, 0x43, 0xf4, 0x9f, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011117 0x56, 0xf0, 0xfe, 0x54, 0x15, 0xfe, 0x04, 0xf4, 0x71, 0xfe, 0x43, 0xf4,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011118 0x9e, 0xfe, 0xf3, 0x10, 0xfe, 0x40, 0x5c, 0x01, 0xfe, 0x16, 0x14, 0x1e,
11119 0x43, 0xec, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x6e, 0x7a, 0xfe, 0x90,
11120 0x15, 0xc4, 0x6e, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011121 0xcc, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0xcc, 0x88, 0x51, 0x21, 0xfe, 0x4d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011122 0xf4, 0x00, 0xe9, 0x91, 0x0f, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58,
11123 0x04, 0x51, 0x0f, 0x0a, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xf3, 0x16,
11124 0x0a, 0x01, 0x0b, 0x26, 0xf3, 0x16, 0x19, 0x01, 0x0b, 0x26, 0xf3, 0x76,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011125 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011126 0x16, 0x19, 0x01, 0x0b, 0x26, 0xb1, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1,
11127 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x26, 0xb1, 0x76, 0xfe, 0x89, 0x4a, 0x01,
11128 0x0b, 0x04, 0x51, 0x04, 0x22, 0xd3, 0x07, 0x06, 0xfe, 0x48, 0x13, 0xb8,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011129 0x13, 0xd3, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x76, 0xa9, 0x67, 0xfe, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011130 0xec, 0xfe, 0x27, 0x01, 0xfe, 0x89, 0x48, 0xff, 0x02, 0x00, 0x10, 0x27,
11131 0xfe, 0x2e, 0x16, 0x32, 0x07, 0xfe, 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1d,
11132 0xfe, 0x52, 0x16, 0x21, 0x13, 0xd4, 0x01, 0x4b, 0x22, 0xd4, 0x07, 0x06,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011133 0x4e, 0x08, 0x54, 0x06, 0x37, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfb, 0x8e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011134 0x07, 0x11, 0xae, 0x09, 0x84, 0x01, 0x0e, 0x8e, 0x09, 0x5d, 0x01, 0xa8,
11135 0x04, 0x09, 0x84, 0x01, 0x0e, 0x8e, 0xfe, 0x80, 0xe7, 0x11, 0x07, 0x11,
11136 0x8a, 0xfe, 0x45, 0x58, 0x01, 0xf0, 0x8e, 0x04, 0x09, 0x48, 0x01, 0x0e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011137 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x80,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011138 0x80, 0xfe, 0x80, 0x4c, 0xfe, 0x49, 0xe4, 0x11, 0xae, 0x09, 0x84, 0x01,
11139 0x0e, 0xfe, 0x80, 0x4c, 0x09, 0x5d, 0x01, 0x87, 0x04, 0x18, 0x11, 0x75,
11140 0x6c, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011141 0x1c, 0xfe, 0x1d, 0xf7, 0x1b, 0x97, 0xfe, 0xee, 0x16, 0x01, 0xfe, 0xf4,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011142 0x17, 0xad, 0x9a, 0x1b, 0x6c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x04,
11143 0xb9, 0x23, 0xfe, 0xde, 0x16, 0xfe, 0xda, 0x10, 0x18, 0x11, 0x75, 0x03,
11144 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1f, 0xfe, 0x18, 0x58, 0x03, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011145 0x66, 0x01, 0xfe, 0x19, 0x58, 0x9a, 0x1f, 0xfe, 0x3c, 0x90, 0xfe, 0x30,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011146 0xf4, 0x06, 0xfe, 0x3c, 0x50, 0x6c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79,
11147 0xfe, 0x1c, 0xf7, 0x1f, 0x97, 0xfe, 0x38, 0x17, 0xfe, 0xb6, 0x14, 0x35,
11148 0x04, 0xb9, 0x23, 0xfe, 0x10, 0x17, 0xfe, 0x9c, 0x10, 0x18, 0x11, 0x75,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011149 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011150 0x2e, 0x97, 0xfe, 0x5a, 0x17, 0xfe, 0x94, 0x14, 0xec, 0x9a, 0x2e, 0x6c,
11151 0x1a, 0xfe, 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00, 0x04, 0xb9, 0x23, 0xfe,
11152 0x4e, 0x17, 0xfe, 0x6c, 0x10, 0x18, 0x11, 0x75, 0xfe, 0x30, 0xbc, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011153 0xb2, 0xbc, 0x9a, 0xcb, 0x6c, 0x1a, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011154 0xcb, 0x97, 0xfe, 0x92, 0x17, 0xfe, 0x5c, 0x14, 0x35, 0x04, 0xb9, 0x23,
11155 0xfe, 0x7e, 0x17, 0xfe, 0x42, 0x10, 0xfe, 0x02, 0xf6, 0x11, 0x75, 0xfe,
11156 0x18, 0xfe, 0x60, 0xfe, 0x19, 0xfe, 0x61, 0xfe, 0x03, 0xa1, 0xfe, 0x1d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011157 0xf7, 0x5b, 0x97, 0xfe, 0xb8, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011158 0x9a, 0x5b, 0x41, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7,
11159 0x11, 0xfe, 0x81, 0xe7, 0x11, 0x12, 0xfe, 0xdd, 0x00, 0x6a, 0x2a, 0x04,
11160 0x6a, 0x2a, 0xfe, 0x12, 0x45, 0x23, 0xfe, 0xa8, 0x17, 0x15, 0x06, 0x39,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011161 0xa0, 0xb4, 0x02, 0x2b, 0xfe, 0x39, 0xf0, 0xfe, 0xfc, 0x17, 0x21, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011162 0xfe, 0x7e, 0x18, 0x1e, 0x19, 0x66, 0x0f, 0x0d, 0x04, 0x75, 0x03, 0xd2,
11163 0x1e, 0x06, 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x7c, 0x6f, 0x4f, 0x32,
11164 0x07, 0x2f, 0xfe, 0x3c, 0x13, 0xf1, 0xfe, 0x42, 0x13, 0x42, 0x92, 0x09,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011165 0x48, 0x01, 0x0e, 0xbb, 0xeb, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011166 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11,
11167 0xac, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c, 0x01, 0x73, 0xfe, 0x16,
11168 0x10, 0x07, 0x82, 0x8b, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12, 0xfe, 0x14,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011169 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x1c, 0x18, 0x18, 0x0a, 0x04, 0xfe, 0x9c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011170 0xe7, 0x0a, 0x10, 0xfe, 0x15, 0x00, 0x64, 0x79, 0x2a, 0x01, 0xe3, 0x18,
11171 0x06, 0x04, 0x42, 0x92, 0x08, 0x54, 0x1b, 0x37, 0x12, 0x2f, 0x01, 0x73,
11172 0x18, 0x06, 0x04, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x3a, 0xce, 0x3b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011173 0xcf, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x04, 0x22, 0xa3, 0x77,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011174 0x13, 0xa3, 0x04, 0x09, 0xa4, 0x01, 0x0e, 0xfe, 0x41, 0x48, 0x09, 0x46,
11175 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x17, 0xfe, 0xe8, 0x18, 0x77, 0x78, 0x04,
11176 0x09, 0x48, 0x01, 0x0e, 0x07, 0x11, 0x4e, 0x09, 0x5d, 0x01, 0xa8, 0x09,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011177 0x46, 0x01, 0x0e, 0x77, 0x78, 0x04, 0xfe, 0x4e, 0xe4, 0x19, 0x6b, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011178 0x1c, 0x19, 0x03, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10,
11179 0xfe, 0x4e, 0xe4, 0xc9, 0x6b, 0xfe, 0x2e, 0x19, 0x03, 0xfe, 0x92, 0x00,
11180 0xfe, 0x02, 0xe6, 0x1a, 0xe5, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x6b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011181 0xfe, 0x40, 0x19, 0x03, 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x1f, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011182 0x08, 0x10, 0x03, 0xfe, 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x6d, 0xfe, 0x4e,
11183 0x45, 0xea, 0xba, 0xff, 0x04, 0x68, 0x54, 0xe7, 0x1e, 0x6e, 0xfe, 0x08,
11184 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe, 0x1a, 0xf4, 0xfe, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011185 0x04, 0xea, 0xfe, 0x48, 0xf4, 0x19, 0x7a, 0xfe, 0x74, 0x19, 0x0f, 0x19,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011186 0x04, 0x07, 0x7e, 0xfe, 0x5a, 0xf0, 0xfe, 0x84, 0x19, 0x25, 0xfe, 0x09,
11187 0x00, 0xfe, 0x34, 0x10, 0x07, 0x1a, 0xfe, 0x5a, 0xf0, 0xfe, 0x92, 0x19,
11188 0x25, 0xca, 0xfe, 0x26, 0x10, 0x07, 0x19, 0x66, 0x25, 0x6d, 0xe5, 0x07,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011189 0x0a, 0x66, 0x25, 0x9e, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x66, 0x25, 0x59,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011190 0xa9, 0xb8, 0x04, 0x15, 0xfe, 0x09, 0x00, 0x01, 0x36, 0xfe, 0x04, 0xfe,
11191 0x81, 0x03, 0x83, 0xfe, 0x40, 0x5c, 0x04, 0x1c, 0xf7, 0xfe, 0x14, 0xf0,
11192 0x0b, 0x27, 0xfe, 0xd6, 0x19, 0x1c, 0xf7, 0x7b, 0xf7, 0xfe, 0x82, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011193 0xfe, 0xda, 0x19, 0x04, 0xff, 0xcc, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070011194};
11195
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011196static unsigned short _adv_asc38C0800_size = sizeof(_adv_asc38C0800_buf); /* 0x14E1 */
11197static ADV_DCNT _adv_asc38C0800_chksum = 0x050D3FD8UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011198
11199/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011200static unsigned char _adv_asc38C1600_buf[] = {
11201 0x00, 0x00, 0x00, 0xf2, 0x00, 0x16, 0x00, 0xfc, 0x00, 0x10, 0x00, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011202 0x18, 0xe4, 0x01, 0x00, 0x04, 0x1e, 0x48, 0xe4, 0x03, 0xf6, 0xf7, 0x13,
11203 0x2e, 0x1e, 0x02, 0x00, 0x07, 0x17, 0xc0, 0x5f, 0x00, 0xfa, 0xff, 0xff,
11204 0x04, 0x00, 0x00, 0xf6, 0x09, 0xe7, 0x82, 0xe7, 0x85, 0xf0, 0x86, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011205 0x4e, 0x10, 0x9e, 0xe7, 0xff, 0x00, 0x55, 0xf0, 0x01, 0xf6, 0x03, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011206 0x98, 0x57, 0x01, 0xe6, 0x00, 0xea, 0x00, 0xec, 0x01, 0xfa, 0x18, 0xf4,
11207 0x08, 0x00, 0xf0, 0x1d, 0x38, 0x54, 0x32, 0xf0, 0x10, 0x00, 0xc2, 0x0e,
11208 0x1e, 0xf0, 0xd5, 0xf0, 0xbc, 0x00, 0x4b, 0xe4, 0x00, 0xe6, 0xb1, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011209 0xb4, 0x00, 0x02, 0x13, 0x3e, 0x1c, 0xc8, 0x47, 0x3e, 0x00, 0xd8, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011210 0x06, 0x13, 0x0c, 0x1c, 0x5e, 0x1e, 0x00, 0x57, 0xc8, 0x57, 0x01, 0xfc,
11211 0xbc, 0x0e, 0xa2, 0x12, 0xb9, 0x54, 0x00, 0x80, 0x62, 0x0a, 0x5a, 0x12,
11212 0xc8, 0x15, 0x3e, 0x1e, 0x18, 0x40, 0xbd, 0x56, 0x03, 0xe6, 0x01, 0xea,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011213 0x5c, 0xf0, 0x0f, 0x00, 0x20, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011214 0x04, 0x13, 0xbb, 0x55, 0x3c, 0x56, 0x3e, 0x57, 0x03, 0x58, 0x4a, 0xe4,
11215 0x40, 0x00, 0xb6, 0x00, 0xbb, 0x00, 0xc0, 0x00, 0x00, 0x01, 0x01, 0x01,
11216 0x3e, 0x01, 0x58, 0x0a, 0x44, 0x10, 0x0a, 0x12, 0x4c, 0x1c, 0x4e, 0x1c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011217 0x02, 0x4a, 0x30, 0xe4, 0x05, 0xe6, 0x0c, 0x00, 0x3c, 0x00, 0x80, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011218 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01,
11219 0x74, 0x01, 0x76, 0x01, 0x78, 0x01, 0x7c, 0x01, 0xc6, 0x0e, 0x0c, 0x10,
11220 0xac, 0x12, 0xae, 0x12, 0x16, 0x1a, 0x32, 0x1c, 0x6e, 0x1e, 0x02, 0x48,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011221 0x3a, 0x55, 0xc9, 0x57, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x06, 0xf7,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011222 0x03, 0xfc, 0x06, 0x00, 0x1e, 0x00, 0xbe, 0x00, 0xe1, 0x00, 0x0c, 0x12,
11223 0x18, 0x1a, 0x70, 0x1a, 0x30, 0x1c, 0x38, 0x1c, 0x10, 0x44, 0x00, 0x4c,
11224 0xb0, 0x57, 0x40, 0x5c, 0x4d, 0xe4, 0x04, 0xea, 0x5d, 0xf0, 0xa7, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011225 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x09, 0x00, 0x19, 0x00, 0x32, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011226 0x33, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00, 0x9e, 0x00, 0xcc, 0x00,
11227 0x20, 0x01, 0x4e, 0x01, 0x79, 0x01, 0x3c, 0x09, 0x68, 0x0d, 0x02, 0x10,
11228 0x04, 0x10, 0x3a, 0x10, 0x08, 0x12, 0x0a, 0x13, 0x40, 0x16, 0x50, 0x16,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011229 0x00, 0x17, 0x4a, 0x19, 0x00, 0x4e, 0x00, 0x54, 0x01, 0x58, 0x00, 0xdc,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011230 0x05, 0xf0, 0x09, 0xf0, 0x59, 0xf0, 0xb8, 0xf0, 0x48, 0xf4, 0x0e, 0xf7,
11231 0x0a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00,
11232 0xd0, 0x00, 0xe7, 0x00, 0xf0, 0x03, 0x69, 0x08, 0xe9, 0x09, 0x5c, 0x0c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011233 0xb6, 0x12, 0xbc, 0x19, 0xd8, 0x1b, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011234 0x42, 0x1d, 0x08, 0x44, 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46,
11235 0x89, 0x48, 0x68, 0x54, 0x83, 0x55, 0x83, 0x59, 0x31, 0xe4, 0x02, 0xe6,
11236 0x07, 0xf0, 0x08, 0xf0, 0x0b, 0xf0, 0x0c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011237 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011238 0xa8, 0x00, 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0x22, 0x01,
11239 0x26, 0x01, 0x60, 0x01, 0x7a, 0x01, 0x82, 0x01, 0xc8, 0x01, 0xca, 0x01,
11240 0x86, 0x02, 0x6a, 0x03, 0x18, 0x05, 0xb2, 0x07, 0x68, 0x08, 0x10, 0x0d,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011241 0x06, 0x10, 0x0a, 0x10, 0x0e, 0x10, 0x12, 0x10, 0x60, 0x10, 0xed, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011242 0xf3, 0x10, 0x06, 0x12, 0x10, 0x12, 0x1e, 0x12, 0x0c, 0x13, 0x0e, 0x13,
11243 0x10, 0x13, 0xfe, 0x9c, 0xf0, 0x35, 0x05, 0xfe, 0xec, 0x0e, 0xff, 0x10,
11244 0x00, 0x00, 0xe9, 0xfe, 0x34, 0x1f, 0x00, 0xe8, 0xfe, 0x88, 0x01, 0xff,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011245 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011246 0x00, 0xfe, 0x57, 0x24, 0x00, 0xfe, 0x4c, 0x00, 0x65, 0xff, 0x04, 0x00,
11247 0x00, 0x1a, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x08,
11248 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x13,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011249 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011250 0xfe, 0x04, 0xf7, 0xe8, 0x37, 0x7d, 0x0d, 0x01, 0xfe, 0x4a, 0x11, 0xfe,
11251 0x04, 0xf7, 0xe8, 0x7d, 0x0d, 0x51, 0x37, 0xfe, 0x3d, 0xf0, 0xfe, 0x0c,
11252 0x02, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x91, 0xf0, 0xfe, 0xf8, 0x01, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011253 0x90, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x8f, 0xf0, 0xbc, 0x03, 0x67, 0x4d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011254 0x05, 0xfe, 0x08, 0x0f, 0x01, 0xfe, 0x78, 0x0f, 0xfe, 0xdd, 0x12, 0x05,
11255 0xfe, 0x0e, 0x03, 0xfe, 0x28, 0x1c, 0x03, 0xfe, 0xa6, 0x00, 0xfe, 0xd1,
11256 0x12, 0x3e, 0x22, 0xfe, 0xa6, 0x00, 0xac, 0xfe, 0x48, 0xf0, 0xfe, 0x90,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011257 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0xaa, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc8,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011258 0x02, 0xfe, 0x46, 0xf0, 0xfe, 0x5a, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x60,
11259 0x02, 0xfe, 0x43, 0xf0, 0xfe, 0x4e, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x52,
11260 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x56, 0x02, 0x1c, 0x0d, 0xa2, 0x1c, 0x07,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011261 0x22, 0xb7, 0x05, 0x35, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011262 0x1c, 0xf5, 0xfe, 0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0x5f, 0xfe, 0xe7,
11263 0x10, 0xfe, 0x06, 0xfc, 0xde, 0x0a, 0x81, 0x01, 0xa3, 0x05, 0x35, 0x1f,
11264 0x95, 0x47, 0xb8, 0x01, 0xfe, 0xe4, 0x11, 0x0a, 0x81, 0x01, 0x5c, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011265 0xbd, 0x10, 0x0a, 0x81, 0x01, 0x5c, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011266 0xfe, 0x58, 0x1c, 0x1c, 0x07, 0x22, 0xb7, 0x37, 0x2a, 0x35, 0xfe, 0x3d,
11267 0xf0, 0xfe, 0x0c, 0x02, 0x2b, 0xfe, 0x9e, 0x02, 0xfe, 0x5a, 0x1c, 0xfe,
11268 0x12, 0x1c, 0xfe, 0x14, 0x1c, 0x1f, 0xfe, 0x30, 0x00, 0x47, 0xb8, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011269 0xfe, 0xd4, 0x11, 0x1c, 0x07, 0x22, 0xb7, 0x05, 0xe9, 0x21, 0x2c, 0x09,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011270 0x1a, 0x31, 0xfe, 0x69, 0x10, 0x1c, 0x07, 0x22, 0xb7, 0xfe, 0x04, 0xec,
11271 0x2c, 0x60, 0x01, 0xfe, 0x1e, 0x1e, 0x20, 0x2c, 0xfe, 0x05, 0xf6, 0xde,
11272 0x01, 0xfe, 0x62, 0x1b, 0x01, 0x0c, 0x61, 0x4a, 0x44, 0x15, 0x56, 0x51,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011273 0x01, 0xfe, 0x9e, 0x1e, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x0a, 0x57,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011274 0x01, 0x18, 0x09, 0x00, 0x36, 0x01, 0x85, 0xfe, 0x18, 0x10, 0xfe, 0x41,
11275 0x58, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0xc8, 0x54, 0x7b, 0xfe, 0x1c, 0x03,
11276 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x37, 0x60, 0xfe, 0x02, 0xe8, 0x30,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011277 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, 0x27, 0xf0,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011278 0xfe, 0xe4, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x40,
11279 0x1c, 0x2a, 0xeb, 0xfe, 0x26, 0xf0, 0xfe, 0x66, 0x03, 0xfe, 0xa0, 0xf0,
11280 0xfe, 0x54, 0x03, 0xfe, 0x11, 0xf0, 0xbc, 0xfe, 0xef, 0x10, 0xfe, 0x9f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011281 0xf0, 0xfe, 0x74, 0x03, 0xfe, 0x46, 0x1c, 0x19, 0xfe, 0x11, 0x00, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011282 0x70, 0x37, 0xfe, 0x48, 0x1c, 0xfe, 0x46, 0x1c, 0x01, 0x0c, 0x06, 0x28,
11283 0xfe, 0x18, 0x13, 0x26, 0x21, 0xb9, 0xc7, 0x20, 0xb9, 0x0a, 0x57, 0x01,
11284 0x18, 0xc7, 0x89, 0x01, 0xfe, 0xc8, 0x1a, 0x15, 0xe1, 0x2a, 0xeb, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011285 0x01, 0xf0, 0xeb, 0xfe, 0x82, 0xf0, 0xfe, 0xa4, 0x03, 0xfe, 0x9c, 0x32,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011286 0x15, 0xfe, 0xe4, 0x00, 0x2f, 0xfe, 0xb6, 0x03, 0x2a, 0x3c, 0x16, 0xfe,
11287 0xc6, 0x03, 0x01, 0x41, 0xfe, 0x06, 0xf0, 0xfe, 0xd6, 0x03, 0xaf, 0xa0,
11288 0xfe, 0x0a, 0xf0, 0xfe, 0xa2, 0x07, 0x05, 0x29, 0x03, 0x81, 0x1e, 0x1b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011289 0xfe, 0x24, 0x05, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, 0x05,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011290 0xea, 0xfe, 0x46, 0x1c, 0x37, 0x7d, 0x1d, 0xfe, 0x67, 0x1b, 0xfe, 0xbf,
11291 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c, 0x75, 0x01, 0xa6, 0x86, 0x0a,
11292 0x57, 0x01, 0x18, 0x09, 0x00, 0x1b, 0xec, 0x0a, 0xe1, 0x01, 0x18, 0x77,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011293 0x50, 0x40, 0x8d, 0x30, 0x03, 0x81, 0x1e, 0xf8, 0x1f, 0x63, 0x01, 0x42,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011294 0x8f, 0xfe, 0x70, 0x02, 0x05, 0xea, 0xd7, 0x99, 0xd8, 0x9c, 0x2a, 0x29,
11295 0x2f, 0xfe, 0x4e, 0x04, 0x16, 0xfe, 0x4a, 0x04, 0x7e, 0xfe, 0xa0, 0x00,
11296 0xfe, 0x9b, 0x57, 0xfe, 0x54, 0x12, 0x32, 0xff, 0x02, 0x00, 0x10, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011297 0x08, 0x16, 0xfe, 0x02, 0x05, 0x32, 0x01, 0x08, 0x16, 0x29, 0x27, 0x25,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011298 0xee, 0xfe, 0x4c, 0x44, 0xfe, 0x58, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x13,
11299 0x34, 0xfe, 0x4c, 0x54, 0x7b, 0xec, 0x60, 0x8d, 0x30, 0x01, 0xfe, 0x4e,
11300 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x7c, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011301 0x32, 0x13, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x68, 0x13, 0xfe, 0x26, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011302 0x13, 0x34, 0xfe, 0x4c, 0x54, 0x7b, 0xec, 0x01, 0xfe, 0x4e, 0x1e, 0xfe,
11303 0x48, 0x47, 0xfe, 0x54, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xa5, 0x01, 0x43,
11304 0x09, 0x9b, 0xfe, 0x40, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xf9, 0x1f, 0x7f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011305 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, 0x8f,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011306 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x32, 0x15, 0xfe, 0xe6, 0x00, 0x0f, 0xfe,
11307 0x1c, 0x90, 0x04, 0xfe, 0x9c, 0x93, 0x3a, 0x0b, 0x0e, 0x8b, 0x02, 0x1f,
11308 0x7f, 0x01, 0x42, 0x05, 0x35, 0xfe, 0x42, 0x5b, 0x7d, 0x1d, 0xfe, 0x46,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011309 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0x0f, 0xfe, 0x87, 0x80, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011310 0xfe, 0x87, 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0xd0, 0x65, 0x01, 0x0c,
11311 0x06, 0x0d, 0xfe, 0x98, 0x13, 0x0f, 0xfe, 0x20, 0x80, 0x04, 0xfe, 0xa0,
11312 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x1d, 0xfe, 0x84, 0x12, 0x01, 0x38, 0x06,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011313 0x07, 0xfe, 0x70, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x1e, 0x1b, 0xfe, 0xda,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011314 0x05, 0xd0, 0x54, 0x01, 0x38, 0x06, 0x0d, 0xfe, 0x58, 0x13, 0x03, 0xfe,
11315 0xa0, 0x00, 0x1e, 0xfe, 0x50, 0x12, 0x5e, 0xff, 0x02, 0x00, 0x10, 0x2f,
11316 0xfe, 0x90, 0x05, 0x2a, 0x3c, 0xcc, 0xff, 0x02, 0x00, 0x10, 0x2f, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011317 0x9e, 0x05, 0x17, 0xfe, 0xf4, 0x05, 0x15, 0xfe, 0xe3, 0x00, 0x26, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011318 0x38, 0xfe, 0x4a, 0xf0, 0xfe, 0xc0, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0xba,
11319 0x05, 0x71, 0x2e, 0xfe, 0x21, 0x00, 0xf1, 0x2e, 0xfe, 0x22, 0x00, 0xa2,
11320 0x2e, 0x4a, 0xfe, 0x09, 0x48, 0xff, 0x02, 0x00, 0x10, 0x2f, 0xfe, 0xd0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011321 0x05, 0x17, 0xfe, 0xf4, 0x05, 0xfe, 0xe2, 0x08, 0x01, 0x38, 0x06, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011322 0x1c, 0x00, 0x4d, 0x01, 0xa7, 0x2e, 0x07, 0x20, 0xe4, 0x47, 0xfe, 0x27,
11323 0x01, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x24, 0x12, 0x3e, 0x01, 0x84, 0x1f,
11324 0x7f, 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011325 0x8f, 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x03, 0xe6, 0x1e, 0xfe, 0xca, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011326 0x03, 0xb6, 0x1e, 0xfe, 0x40, 0x12, 0x03, 0x66, 0x1e, 0xfe, 0x38, 0x13,
11327 0x3e, 0x01, 0x84, 0x17, 0xfe, 0x72, 0x06, 0x0a, 0x07, 0x01, 0x38, 0x06,
11328 0x24, 0xfe, 0x02, 0x12, 0x4f, 0x01, 0xfe, 0x56, 0x19, 0x16, 0xfe, 0x68,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011329 0x06, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x66, 0x8a, 0x10, 0x66,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011330 0x03, 0x9a, 0x1e, 0xfe, 0x70, 0x12, 0x03, 0x55, 0x1e, 0xfe, 0x68, 0x13,
11331 0x01, 0xc6, 0x09, 0x12, 0x48, 0xfe, 0x92, 0x06, 0x2e, 0x12, 0x01, 0xfe,
11332 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0x13, 0x58, 0xff, 0x02, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011333 0x57, 0x52, 0xad, 0x23, 0x3f, 0x4e, 0x62, 0x49, 0x3e, 0x01, 0x84, 0x17,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011334 0xfe, 0xea, 0x06, 0x01, 0x38, 0x06, 0x12, 0xf7, 0x45, 0x0a, 0x95, 0x01,
11335 0xfe, 0x84, 0x19, 0x16, 0xfe, 0xe0, 0x06, 0x15, 0x82, 0x01, 0x41, 0x15,
11336 0xe2, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x1c, 0x07, 0x01, 0x84, 0xfe, 0xae,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011337 0x10, 0x03, 0x6f, 0x1e, 0xfe, 0x9e, 0x13, 0x3e, 0x01, 0x84, 0x03, 0x9a,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011338 0x1e, 0xfe, 0x1a, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfc, 0x01, 0xc6, 0x01,
11339 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0xf0, 0x45, 0x0a, 0x95,
11340 0x03, 0xb6, 0x1e, 0xf8, 0x01, 0x38, 0x06, 0x24, 0x36, 0xfe, 0x02, 0xf6,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011341 0x07, 0x71, 0x78, 0x8c, 0x00, 0x4d, 0x62, 0x49, 0x3e, 0x2d, 0x93, 0x4e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011342 0xd0, 0x0d, 0x17, 0xfe, 0x9a, 0x07, 0x01, 0xfe, 0xc0, 0x19, 0x16, 0xfe,
11343 0x90, 0x07, 0x26, 0x20, 0x9e, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x21,
11344 0x9e, 0x09, 0x07, 0xfb, 0x03, 0xe6, 0xfe, 0x58, 0x57, 0x10, 0xe6, 0x05,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011345 0xfe, 0x2a, 0x06, 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x1c, 0x07, 0x01, 0x84,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011346 0xfe, 0x9c, 0x32, 0x5f, 0x75, 0x01, 0xa6, 0x86, 0x15, 0xfe, 0xe2, 0x00,
11347 0x2f, 0xed, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe, 0xce, 0x07, 0xae, 0xfe,
11348 0x96, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x9e, 0x08, 0xaf, 0xa0, 0x05, 0x29,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011349 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x2e, 0x12, 0x14, 0x1d, 0x01, 0x08, 0x14,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011350 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0xfe,
11351 0x99, 0xa4, 0x01, 0x08, 0x14, 0x00, 0x05, 0xfe, 0xc6, 0x09, 0x01, 0x76,
11352 0x06, 0x12, 0xfe, 0x3a, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x30, 0x13,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011353 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011354 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x07, 0x01, 0x08, 0x14, 0x00,
11355 0x05, 0xef, 0x7c, 0x4a, 0x78, 0x4f, 0x0f, 0xfe, 0x9a, 0x81, 0x04, 0xfe,
11356 0x9a, 0x83, 0xfe, 0xcb, 0x47, 0x0b, 0x0e, 0x2d, 0x28, 0x48, 0xfe, 0x6c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011357 0x08, 0x0a, 0x28, 0xfe, 0x09, 0x6f, 0xca, 0xfe, 0xca, 0x45, 0xfe, 0x32,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011358 0x12, 0x53, 0x63, 0x4e, 0x7c, 0x97, 0x2f, 0xfe, 0x7e, 0x08, 0x2a, 0x3c,
11359 0xfe, 0x0a, 0xf0, 0xfe, 0x6c, 0x08, 0xaf, 0xa0, 0xae, 0xfe, 0x96, 0x08,
11360 0x05, 0x29, 0x01, 0x41, 0x05, 0xed, 0x14, 0x24, 0x05, 0xed, 0xfe, 0x9c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011361 0xf7, 0x9f, 0x01, 0xfe, 0xae, 0x1e, 0xfe, 0x18, 0x58, 0x01, 0xfe, 0xbe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011362 0x1e, 0xfe, 0x99, 0x58, 0xfe, 0x78, 0x18, 0xfe, 0xf9, 0x18, 0x8e, 0xfe,
11363 0x16, 0x09, 0x10, 0x6a, 0x22, 0x6b, 0x01, 0x0c, 0x61, 0x54, 0x44, 0x21,
11364 0x2c, 0x09, 0x1a, 0xf8, 0x77, 0x01, 0xfe, 0x7e, 0x1e, 0x47, 0x2c, 0x7a,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011365 0x30, 0xf0, 0xfe, 0x83, 0xe7, 0xfe, 0x3f, 0x00, 0x71, 0xfe, 0x03, 0x40,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011366 0x01, 0x0c, 0x61, 0x65, 0x44, 0x01, 0xc2, 0xc8, 0xfe, 0x1f, 0x40, 0x20,
11367 0x6e, 0x01, 0xfe, 0x6a, 0x16, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe,
11368 0x44, 0x51, 0xfe, 0xc6, 0x51, 0xfe, 0x10, 0x10, 0x01, 0xfe, 0xce, 0x1e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011369 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x01, 0xfe, 0xee, 0x1e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011370 0x01, 0xfe, 0xfe, 0x1e, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x10, 0x4b,
11371 0x22, 0x4c, 0xfe, 0x8a, 0x10, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0x50, 0x12,
11372 0x01, 0xfe, 0xae, 0x1e, 0x01, 0xfe, 0xbe, 0x1e, 0x10, 0x6a, 0x22, 0x6b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011373 0x01, 0x0c, 0x06, 0x65, 0x4e, 0x01, 0xc2, 0x0f, 0xfe, 0x1f, 0x80, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011374 0xfe, 0x9f, 0x83, 0x33, 0x0b, 0x0e, 0x20, 0x6e, 0x0f, 0xfe, 0x44, 0x90,
11375 0x04, 0xfe, 0xc4, 0x93, 0x3a, 0x0b, 0xfe, 0xc6, 0x90, 0x04, 0xfe, 0xc6,
11376 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x6c, 0x22, 0x6d, 0x01, 0xfe, 0xce, 0x1e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011377 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x0f, 0xfe, 0x40, 0x90,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011378 0x04, 0xfe, 0xc0, 0x93, 0x3a, 0x0b, 0xfe, 0xc2, 0x90, 0x04, 0xfe, 0xc2,
11379 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x4b, 0x22, 0x4c, 0x10, 0x64, 0x22, 0x34,
11380 0x01, 0x0c, 0x61, 0x24, 0x44, 0x37, 0x13, 0xfe, 0x4e, 0x11, 0x2f, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011381 0xde, 0x09, 0xfe, 0x9e, 0xf0, 0xfe, 0xf2, 0x09, 0xfe, 0x01, 0x48, 0x1b,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011382 0x3c, 0x37, 0x88, 0xf5, 0xd4, 0xfe, 0x1e, 0x0a, 0xd5, 0xfe, 0x42, 0x0a,
11383 0xd2, 0xfe, 0x1e, 0x0a, 0xd3, 0xfe, 0x42, 0x0a, 0xae, 0xfe, 0x12, 0x0a,
11384 0xfe, 0x06, 0xf0, 0xfe, 0x18, 0x0a, 0xaf, 0xa0, 0x05, 0x29, 0x01, 0x41,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011385 0xfe, 0xc1, 0x10, 0x14, 0x24, 0xfe, 0xc1, 0x10, 0x01, 0x76, 0x06, 0x07,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011386 0xfe, 0x14, 0x12, 0x01, 0x76, 0x06, 0x0d, 0x5d, 0x01, 0x0c, 0x06, 0x0d,
11387 0xfe, 0x74, 0x12, 0xfe, 0x2e, 0x1c, 0x05, 0xfe, 0x1a, 0x0c, 0x01, 0x76,
11388 0x06, 0x07, 0x5d, 0x01, 0x76, 0x06, 0x0d, 0x41, 0xfe, 0x2c, 0x1c, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011389 0xaa, 0xf0, 0xfe, 0xce, 0x0a, 0xfe, 0xac, 0xf0, 0xfe, 0x66, 0x0a, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011390 0x92, 0x10, 0xc4, 0xf6, 0xfe, 0xad, 0xf0, 0xfe, 0x72, 0x0a, 0x05, 0xfe,
11391 0x1a, 0x0c, 0xc5, 0xfe, 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0xbf, 0xfe, 0x6b,
11392 0x18, 0x23, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12, 0xac, 0xfe, 0xd2, 0xf0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011393 0xbf, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x1b, 0xbf, 0x03, 0xe3, 0x23, 0x07,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011394 0x1b, 0xbf, 0xd4, 0x5b, 0xd5, 0x5b, 0xd2, 0x5b, 0xd3, 0x5b, 0xc4, 0xc5,
11395 0xfe, 0xa9, 0x10, 0x75, 0x5e, 0x32, 0x1f, 0x7f, 0x01, 0x42, 0x19, 0xfe,
11396 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x70, 0x19, 0x98, 0x05, 0x70, 0xfe, 0x74,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011397 0x18, 0x23, 0xfe, 0x00, 0xf8, 0x1b, 0x5b, 0x7d, 0x12, 0x01, 0xfe, 0x78,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011398 0x0f, 0x4d, 0x01, 0xfe, 0x96, 0x1a, 0x21, 0x30, 0x77, 0x7d, 0x1d, 0x05,
11399 0x5b, 0x01, 0x0c, 0x06, 0x0d, 0x2b, 0xfe, 0xe2, 0x0b, 0x01, 0x0c, 0x06,
11400 0x54, 0xfe, 0xa6, 0x12, 0x01, 0x0c, 0x06, 0x24, 0xfe, 0x88, 0x13, 0x21,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011401 0x6e, 0xc7, 0x01, 0xfe, 0x1e, 0x1f, 0x0f, 0xfe, 0x83, 0x80, 0x04, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011402 0x83, 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0xfe, 0xc8, 0x44, 0xfe, 0x42,
11403 0x13, 0x0f, 0xfe, 0x04, 0x91, 0x04, 0xfe, 0x84, 0x93, 0xfe, 0xca, 0x57,
11404 0x0b, 0xfe, 0x86, 0x91, 0x04, 0xfe, 0x86, 0x93, 0xfe, 0xcb, 0x57, 0x0b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011405 0x0e, 0x7a, 0x30, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x8e, 0x40, 0x03,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011406 0x6a, 0x3b, 0x6b, 0x10, 0x97, 0x22, 0x98, 0xd9, 0x6a, 0xda, 0x6b, 0x01,
11407 0xc2, 0xc8, 0x7a, 0x30, 0x20, 0x6e, 0xdb, 0x64, 0xdc, 0x34, 0x91, 0x6c,
11408 0x7e, 0x6d, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55, 0xfe, 0x04, 0xfa, 0x64,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011409 0xfe, 0x05, 0xfa, 0x34, 0x01, 0xfe, 0x6a, 0x16, 0xa3, 0x26, 0x10, 0x97,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011410 0x10, 0x98, 0x91, 0x6c, 0x7e, 0x6d, 0xfe, 0x14, 0x10, 0x01, 0x0c, 0x06,
11411 0x24, 0x1b, 0x40, 0x91, 0x4b, 0x7e, 0x4c, 0x01, 0x0c, 0x06, 0xfe, 0xf7,
11412 0x00, 0x44, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011413 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x24,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011414 0x1b, 0x40, 0x01, 0x0c, 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x78, 0x01, 0xfe,
11415 0x8e, 0x1e, 0x4f, 0x0f, 0xfe, 0x10, 0x90, 0x04, 0xfe, 0x90, 0x93, 0x3a,
11416 0x0b, 0xfe, 0x92, 0x90, 0x04, 0xfe, 0x92, 0x93, 0x79, 0x0b, 0x0e, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011417 0xbd, 0x10, 0x01, 0x43, 0x09, 0xbb, 0x1b, 0xfe, 0x6e, 0x0a, 0x15, 0xbb,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011418 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x14, 0x13, 0x03, 0x4b, 0x3b, 0x4c, 0x8e,
11419 0xfe, 0x6e, 0x0a, 0xfe, 0x0c, 0x58, 0xfe, 0x8d, 0x58, 0x05, 0x5b, 0x26,
11420 0x3e, 0x0f, 0xfe, 0x19, 0x80, 0x04, 0xfe, 0x99, 0x83, 0x33, 0x0b, 0x0e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011421 0xfe, 0xe5, 0x10, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1a, 0x12, 0xfe, 0x6c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011422 0x19, 0xfe, 0x19, 0x41, 0xfe, 0x6b, 0x18, 0xac, 0xfe, 0xd1, 0xf0, 0xef,
11423 0x1f, 0x92, 0x01, 0x42, 0x19, 0xfe, 0x44, 0x00, 0xfe, 0x90, 0x10, 0xfe,
11424 0x6c, 0x19, 0xd9, 0x4b, 0xfe, 0xed, 0x19, 0xda, 0x4c, 0xfe, 0x0c, 0x51,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011425 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xff, 0x31, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011426 0x76, 0x10, 0xac, 0xfe, 0xd2, 0xf0, 0xfe, 0xba, 0x0c, 0xfe, 0x76, 0x18,
11427 0x23, 0x1d, 0x5d, 0x03, 0xe3, 0x23, 0x07, 0xfe, 0x08, 0x13, 0x19, 0xfe,
11428 0x16, 0x00, 0x05, 0x70, 0xfe, 0xd1, 0xf0, 0xfe, 0xcc, 0x0c, 0x1f, 0x92,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011429 0x01, 0x42, 0x19, 0xfe, 0x17, 0x00, 0x5c, 0xfe, 0xce, 0xf0, 0xfe, 0xd2,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011430 0x0c, 0xfe, 0x3e, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xde, 0x0c, 0x19, 0xfe,
11431 0x22, 0x00, 0x05, 0x70, 0xfe, 0xcb, 0xf0, 0xfe, 0xea, 0x0c, 0x19, 0xfe,
11432 0x24, 0x00, 0x05, 0x70, 0xfe, 0xd0, 0xf0, 0xfe, 0xf4, 0x0c, 0x19, 0x94,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011433 0xfe, 0x1c, 0x10, 0xfe, 0xcf, 0xf0, 0xfe, 0xfe, 0x0c, 0x19, 0x4a, 0xf3,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011434 0xfe, 0xcc, 0xf0, 0xef, 0x01, 0x76, 0x06, 0x24, 0x4d, 0x19, 0xfe, 0x12,
11435 0x00, 0x37, 0x13, 0xfe, 0x4e, 0x11, 0x2f, 0xfe, 0x16, 0x0d, 0xfe, 0x9e,
11436 0xf0, 0xfe, 0x2a, 0x0d, 0xfe, 0x01, 0x48, 0x1b, 0x3c, 0x37, 0x88, 0xf5,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011437 0xd4, 0x29, 0xd5, 0x29, 0xd2, 0x29, 0xd3, 0x29, 0x37, 0xfe, 0x9c, 0x32,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011438 0x2f, 0xfe, 0x3e, 0x0d, 0x2a, 0x3c, 0xae, 0xfe, 0x62, 0x0d, 0xaf, 0xa0,
11439 0xd4, 0x9f, 0xd5, 0x9f, 0xd2, 0x9f, 0xd3, 0x9f, 0x05, 0x29, 0x01, 0x41,
11440 0xfe, 0xd3, 0x10, 0x15, 0xfe, 0xe8, 0x00, 0xc4, 0xc5, 0x75, 0xd7, 0x99,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011441 0xd8, 0x9c, 0xfe, 0x89, 0xf0, 0x29, 0x27, 0x25, 0xbe, 0xd7, 0x99, 0xd8,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011442 0x9c, 0x2f, 0xfe, 0x8c, 0x0d, 0x16, 0x29, 0x27, 0x25, 0xbd, 0xfe, 0x01,
11443 0x48, 0xa4, 0x19, 0xfe, 0x42, 0x00, 0x05, 0x70, 0x90, 0x07, 0xfe, 0x81,
11444 0x49, 0x1b, 0xfe, 0x64, 0x0e, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x44, 0x13,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011445 0x19, 0x00, 0x2d, 0x0d, 0xfe, 0x54, 0x12, 0x2d, 0xfe, 0x28, 0x00, 0x2b,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011446 0xfe, 0xda, 0x0e, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, 0x36, 0x46, 0xfe,
11447 0x28, 0x00, 0xfe, 0xfa, 0x10, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe, 0x00,
11448 0x1d, 0x0a, 0xba, 0x01, 0xfe, 0x58, 0x10, 0x40, 0x15, 0x56, 0x01, 0x85,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011449 0x05, 0x35, 0x19, 0xfe, 0x44, 0x00, 0x2d, 0x0d, 0xf7, 0x46, 0x0d, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011450 0xcc, 0x10, 0x01, 0xa7, 0x46, 0x0d, 0xfe, 0xc2, 0x10, 0x01, 0xa7, 0x0f,
11451 0xfe, 0x19, 0x82, 0x04, 0xfe, 0x99, 0x83, 0xfe, 0xcc, 0x47, 0x0b, 0x0e,
11452 0xfe, 0x34, 0x46, 0xa5, 0x46, 0x0d, 0x19, 0xfe, 0x43, 0x00, 0xfe, 0xa2,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011453 0x10, 0x01, 0x0c, 0x61, 0x0d, 0x44, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011454 0x00, 0x1d, 0x40, 0x15, 0x56, 0x01, 0x85, 0x7d, 0x0d, 0x40, 0x51, 0x01,
11455 0xfe, 0x9e, 0x1e, 0x05, 0xfe, 0x3a, 0x03, 0x01, 0x0c, 0x06, 0x0d, 0x5d,
11456 0x46, 0x0d, 0x19, 0x00, 0xfe, 0x62, 0x10, 0x01, 0x76, 0x06, 0x12, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011457 0x5c, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x52, 0x13, 0xfe, 0x1c, 0x1c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011458 0xfe, 0x9d, 0xf0, 0xfe, 0x8e, 0x0e, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0,
11459 0xfe, 0x94, 0x0e, 0x01, 0x0c, 0x61, 0x12, 0x44, 0xfe, 0x9f, 0x10, 0x19,
11460 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0d, 0x4f, 0xfe, 0x2e, 0x10, 0x19,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011461 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x19, 0xfe, 0x47, 0x00, 0xf1, 0x19,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011462 0xfe, 0x41, 0x00, 0xa2, 0x19, 0xfe, 0x24, 0x00, 0x86, 0xc4, 0xc5, 0x75,
11463 0x03, 0x81, 0x1e, 0x2b, 0xea, 0x4f, 0xfe, 0x04, 0xe6, 0x12, 0xfe, 0x9d,
11464 0x41, 0xfe, 0x1c, 0x42, 0x40, 0x01, 0xf4, 0x05, 0x35, 0xfe, 0x12, 0x1c,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011465 0x1f, 0x0d, 0x47, 0xb5, 0xc3, 0x1f, 0xfe, 0x31, 0x00, 0x47, 0xb8, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011466 0xfe, 0xd4, 0x11, 0x05, 0xe9, 0x51, 0xfe, 0x06, 0xec, 0xe0, 0xfe, 0x0e,
11467 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0x06, 0xea, 0xe0,
11468 0xfe, 0x47, 0x4b, 0x45, 0xfe, 0x75, 0x57, 0x03, 0x67, 0xfe, 0x98, 0x56,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011469 0xfe, 0x38, 0x12, 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x44, 0x48, 0x60, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011470 0x0c, 0x06, 0x28, 0xfe, 0x18, 0x13, 0x0a, 0x57, 0x01, 0x18, 0x3e, 0xfe,
11471 0x41, 0x58, 0x0a, 0xba, 0xfe, 0xfa, 0x14, 0xfe, 0x49, 0x54, 0xb0, 0xfe,
11472 0x5e, 0x0f, 0x05, 0xfe, 0x3a, 0x03, 0x0a, 0x67, 0xfe, 0xe0, 0x14, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011473 0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0xce, 0x47,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011474 0xfe, 0xad, 0x13, 0x05, 0x35, 0x21, 0x2c, 0x09, 0x1a, 0xfe, 0x98, 0x12,
11475 0x26, 0x20, 0x96, 0x20, 0xe7, 0xfe, 0x08, 0x1c, 0xfe, 0x7c, 0x19, 0xfe,
11476 0xfd, 0x19, 0xfe, 0x0a, 0x1c, 0x03, 0xe5, 0xfe, 0x48, 0x55, 0xa5, 0x3b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011477 0xfe, 0x62, 0x01, 0xfe, 0xc9, 0x55, 0x31, 0xfe, 0x74, 0x10, 0x01, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011478 0xf0, 0x1a, 0x03, 0xfe, 0x38, 0x01, 0x3b, 0xfe, 0x3a, 0x01, 0x8e, 0xfe,
11479 0x1e, 0x10, 0xfe, 0x02, 0xec, 0xe7, 0x53, 0x00, 0x36, 0xfe, 0x04, 0xec,
11480 0x2c, 0x60, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x62, 0x1b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011481 0x01, 0xfe, 0xce, 0x1e, 0xb2, 0x11, 0xfe, 0x18, 0x13, 0xca, 0xfe, 0x02,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011482 0xea, 0xe7, 0x53, 0x92, 0xfe, 0xc3, 0x13, 0x1f, 0x12, 0x47, 0xb5, 0xc3,
11483 0xfe, 0x2a, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x23, 0xfe, 0xf0, 0xff, 0x10,
11484 0xe5, 0x03, 0xfe, 0x3a, 0x01, 0x10, 0xfe, 0x62, 0x01, 0x01, 0xfe, 0x1e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011485 0x1e, 0x20, 0x2c, 0x15, 0x56, 0x01, 0xfe, 0x9e, 0x1e, 0x13, 0x07, 0x02,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011486 0x26, 0x02, 0x21, 0x96, 0xc7, 0x20, 0x96, 0x09, 0x92, 0xfe, 0x79, 0x13,
11487 0x1f, 0x1d, 0x47, 0xb5, 0xc3, 0xfe, 0xe1, 0x10, 0xcf, 0xfe, 0x03, 0xdc,
11488 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xcf, 0xfe, 0x03, 0xdc, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011489 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x26, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011490 0x00, 0xcc, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x89, 0x02, 0x01, 0x0c, 0x06,
11491 0x4a, 0xfe, 0x4e, 0x13, 0x0f, 0xfe, 0x1c, 0x80, 0x04, 0xfe, 0x9c, 0x83,
11492 0x33, 0x0b, 0x0e, 0x09, 0x07, 0xfe, 0x3a, 0x13, 0x0f, 0xfe, 0x1e, 0x80,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011493 0x04, 0xfe, 0x9e, 0x83, 0x33, 0x0b, 0x0e, 0xfe, 0x2a, 0x13, 0x0f, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011494 0x1d, 0x80, 0x04, 0xfe, 0x9d, 0x83, 0xfe, 0xf9, 0x13, 0x0e, 0xfe, 0x1c,
11495 0x13, 0x01, 0xfe, 0xee, 0x1e, 0xac, 0xfe, 0x14, 0x13, 0x01, 0xfe, 0xfe,
11496 0x1e, 0xfe, 0x81, 0x58, 0xfa, 0x01, 0xfe, 0x0e, 0x1f, 0xfe, 0x30, 0xf4,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011497 0x0d, 0xfe, 0x3c, 0x50, 0xa2, 0x01, 0xfe, 0x92, 0x1b, 0x01, 0x43, 0x09,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011498 0x56, 0xfb, 0x01, 0xfe, 0xc8, 0x1a, 0x01, 0x0c, 0x06, 0x28, 0xa4, 0x01,
11499 0xfe, 0xf4, 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x15, 0xfe, 0xe9, 0x00, 0x01,
11500 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x01, 0xfe, 0x22, 0x1b, 0xfe, 0x1e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011501 0x1c, 0x0f, 0xfe, 0x14, 0x90, 0x04, 0xfe, 0x94, 0x93, 0x3a, 0x0b, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011502 0x96, 0x90, 0x04, 0xfe, 0x96, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0xfe, 0x64,
11503 0x01, 0x22, 0xfe, 0x66, 0x01, 0x01, 0x0c, 0x06, 0x65, 0xf9, 0x0f, 0xfe,
11504 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b, 0x0e, 0x77, 0xfe, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011505 0xec, 0x2c, 0xfe, 0x80, 0x40, 0x20, 0x2c, 0x7a, 0x30, 0x15, 0xdf, 0x40,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011506 0x21, 0x2c, 0xfe, 0x00, 0x40, 0x8d, 0x2c, 0x02, 0xfe, 0x08, 0x1c, 0x03,
11507 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58, 0x03, 0xfe, 0xae, 0x00, 0xfe, 0x07,
11508 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe, 0xb2, 0x00,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011509 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x2e, 0x49, 0x20, 0xe0, 0x26, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011510 0x66, 0x10, 0x55, 0x10, 0x6f, 0x13, 0x57, 0x52, 0x4f, 0x1c, 0x28, 0xfe,
11511 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x2b, 0xfe, 0x88, 0x11, 0x46, 0x1a, 0x13,
11512 0x5a, 0x52, 0x1c, 0x4a, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x2b, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011513 0x9e, 0x11, 0x2e, 0x1a, 0x20, 0x2c, 0x90, 0x34, 0x60, 0x21, 0x2c, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011514 0x00, 0x40, 0x8d, 0x2c, 0x15, 0xdf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0,
11515 0xfe, 0xb2, 0x11, 0xfe, 0x12, 0x1c, 0x75, 0xfe, 0x14, 0x1c, 0xfe, 0x10,
11516 0x1c, 0xfe, 0x18, 0x1c, 0x02, 0x51, 0xfe, 0x0c, 0x14, 0xfe, 0x0e, 0x47,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011517 0xfe, 0x07, 0xe6, 0x28, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x02, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011518 0xa7, 0x90, 0x34, 0x60, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42,
11519 0x13, 0xfe, 0x02, 0x80, 0x09, 0x56, 0xfe, 0x34, 0x13, 0x0a, 0x5a, 0x01,
11520 0x18, 0xcb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011521 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, 0x89,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011522 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x5c, 0x01, 0x85,
11523 0xf2, 0x09, 0x9b, 0xa4, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xec,
11524 0x11, 0x02, 0xfe, 0x44, 0x58, 0x77, 0xfe, 0x01, 0xec, 0xb8, 0xfe, 0x9e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011525 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x12, 0x8d, 0x30, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011526 0xf4, 0xfe, 0xdd, 0x10, 0x37, 0xd7, 0x99, 0xd8, 0x9c, 0x27, 0x25, 0xee,
11527 0x09, 0x12, 0xfe, 0x48, 0x12, 0x09, 0x0d, 0xfe, 0x56, 0x12, 0x09, 0x1d,
11528 0xfe, 0x30, 0x12, 0x09, 0xdd, 0x1b, 0xfe, 0xc4, 0x13, 0x09, 0xfe, 0x23,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011529 0x00, 0x1b, 0xfe, 0xd0, 0x13, 0x09, 0x07, 0x1b, 0xfe, 0x34, 0x14, 0x09,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011530 0x24, 0xfe, 0x12, 0x12, 0x09, 0x00, 0x1b, 0x29, 0x1f, 0xdd, 0x01, 0x42,
11531 0xa1, 0x32, 0x01, 0x08, 0xae, 0x41, 0x02, 0x32, 0xfe, 0x62, 0x08, 0x0a,
11532 0xe1, 0x01, 0xfe, 0x58, 0x10, 0x15, 0x9b, 0x05, 0x35, 0x32, 0x01, 0x43,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011533 0x09, 0xbb, 0xfe, 0xd7, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0x8e, 0xfe, 0x80,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011534 0x13, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0x72, 0x12, 0xdb, 0x64, 0xdc, 0x34,
11535 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55, 0xb0, 0xfe, 0x4a, 0x13, 0x21, 0x6e,
11536 0xfe, 0x26, 0x13, 0x03, 0x97, 0x3b, 0x98, 0x8e, 0xfe, 0xb6, 0x0e, 0x10,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011537 0x6a, 0x22, 0x6b, 0x26, 0x10, 0x97, 0x10, 0x98, 0x01, 0xc2, 0x2e, 0x49,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011538 0x88, 0x20, 0x6e, 0x01, 0xfe, 0x6a, 0x16, 0xdb, 0x64, 0xdc, 0x34, 0xfe,
11539 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x64, 0xfe, 0x05, 0xfa,
11540 0x34, 0xfe, 0x8f, 0x10, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x40, 0x56, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011541 0xe1, 0x56, 0x10, 0x6c, 0x22, 0x6d, 0x71, 0xdb, 0x64, 0xdc, 0x34, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011542 0x44, 0x55, 0xfe, 0xe5, 0x55, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x00, 0x56,
11543 0xfe, 0xa1, 0x56, 0x10, 0x68, 0x22, 0x69, 0x01, 0x0c, 0x06, 0x54, 0xf9,
11544 0x21, 0x6e, 0xfe, 0x1f, 0x40, 0x03, 0x6a, 0x3b, 0x6b, 0xfe, 0x2c, 0x50,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011545 0xfe, 0xae, 0x50, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x44, 0x50, 0xfe, 0xc6,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011546 0x50, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03,
11547 0x4b, 0x3b, 0x4c, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x05, 0x73, 0x2e,
11548 0x07, 0x20, 0x9e, 0x05, 0x72, 0x32, 0x01, 0x08, 0x16, 0x3d, 0x27, 0x25,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011549 0xee, 0x09, 0x07, 0x2b, 0x3d, 0x01, 0x43, 0x09, 0xbb, 0x2b, 0x72, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011550 0xa6, 0x23, 0x3f, 0x1b, 0x3d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1e, 0x13,
11551 0x91, 0x4b, 0x7e, 0x4c, 0xfe, 0x0a, 0x55, 0x31, 0xfe, 0x8b, 0x55, 0xd9,
11552 0x4b, 0xda, 0x4c, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x05, 0x72, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011553 0xfe, 0x8e, 0x1e, 0xca, 0xfe, 0x19, 0x41, 0x05, 0x72, 0x32, 0x01, 0x08,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011554 0x2a, 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbe, 0x2d, 0x1d, 0xc0, 0x2d, 0x0d,
11555 0x83, 0x2d, 0x7f, 0x1b, 0xfe, 0x66, 0x15, 0x05, 0x3d, 0x01, 0x08, 0x2a,
11556 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbd, 0x09, 0x1d, 0x2b, 0x3d, 0x01, 0x08,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011557 0x16, 0xc0, 0x27, 0x25, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x50, 0x03,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011558 0xb6, 0x1e, 0x83, 0x01, 0x38, 0x06, 0x24, 0x31, 0xa1, 0xfe, 0xbb, 0x45,
11559 0x2d, 0x00, 0xa4, 0x46, 0x07, 0x90, 0x3f, 0x01, 0xfe, 0xf8, 0x15, 0x01,
11560 0xa6, 0x86, 0xfe, 0x4b, 0x45, 0xfe, 0x20, 0x13, 0x01, 0x43, 0x09, 0x82,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011561 0xfe, 0x16, 0x13, 0x03, 0x9a, 0x1e, 0x5d, 0x03, 0x55, 0x1e, 0x31, 0x5e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011562 0x05, 0x72, 0xfe, 0xc0, 0x5d, 0x01, 0xa7, 0xfe, 0x03, 0x17, 0x03, 0x66,
11563 0x8a, 0x10, 0x66, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01, 0xfe, 0x56,
11564 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d, 0x27, 0x25, 0xbd,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011565 0x09, 0x07, 0x2b, 0x3d, 0x01, 0xfe, 0xbe, 0x16, 0xfe, 0x42, 0x58, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011566 0xe8, 0x14, 0x01, 0xa6, 0x86, 0xfe, 0x4a, 0xf4, 0x0d, 0x1b, 0x3d, 0xfe,
11567 0x4a, 0xf4, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09, 0x82, 0x4e, 0x05,
11568 0x72, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011569 0x01, 0xfe, 0x84, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011570 0x27, 0x25, 0xbd, 0x09, 0x12, 0x2b, 0x3d, 0x01, 0xfe, 0xe8, 0x17, 0x8b,
11571 0xfe, 0xaa, 0x14, 0xfe, 0xb6, 0x14, 0x86, 0xa8, 0xb2, 0x0d, 0x1b, 0x3d,
11572 0xb2, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09, 0x82, 0x4e, 0x05, 0x72,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011573 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011574 0xfe, 0xc0, 0x19, 0x05, 0x73, 0x13, 0x07, 0x2f, 0xfe, 0xcc, 0x15, 0x17,
11575 0xfe, 0xe2, 0x15, 0x5f, 0xcc, 0x01, 0x08, 0x26, 0x5f, 0x02, 0x8f, 0xfe,
11576 0xde, 0x15, 0x2a, 0xfe, 0xde, 0x15, 0x16, 0xfe, 0xcc, 0x15, 0x5e, 0x32,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011577 0x01, 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011578 0xad, 0x23, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02,
11579 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xad, 0x23, 0x3f, 0xfe, 0x30,
11580 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011581 0xad, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xfe, 0x00, 0x5e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011582 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xad, 0xfe, 0x0b, 0x58,
11583 0x02, 0x0a, 0x66, 0x01, 0x5c, 0x0a, 0x55, 0x01, 0x5c, 0x0a, 0x6f, 0x01,
11584 0x5c, 0x02, 0x01, 0xfe, 0x1e, 0x1f, 0x23, 0x1a, 0xff, 0x03, 0x00, 0x54,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011585 0xfe, 0x00, 0xf4, 0x24, 0x52, 0x0f, 0xfe, 0x00, 0x7c, 0x04, 0xfe, 0x07,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011586 0x7c, 0x3a, 0x0b, 0x0e, 0xfe, 0x00, 0x71, 0xfe, 0xf9, 0x18, 0xfe, 0x7a,
11587 0x19, 0xfe, 0xfb, 0x19, 0xfe, 0x1a, 0xf7, 0x00, 0xfe, 0x1b, 0xf7, 0x00,
11588 0x7a, 0x30, 0x10, 0x68, 0x22, 0x69, 0xd9, 0x6c, 0xda, 0x6d, 0x02, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011589 0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x77,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011590 0x02, 0x01, 0xc6, 0xfe, 0x42, 0x48, 0x4f, 0x50, 0x45, 0x01, 0x08, 0x16,
11591 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xbe, 0x01, 0x08, 0x16, 0xfe, 0xe0, 0x17,
11592 0x27, 0x25, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x03, 0x9a, 0x1e, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011593 0xda, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfe, 0xd0, 0x13, 0x26, 0x53, 0x12,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011594 0x48, 0xfe, 0x08, 0x17, 0xd1, 0x12, 0x53, 0x12, 0xfe, 0x1e, 0x13, 0x2d,
11595 0xb4, 0x7b, 0xfe, 0x26, 0x17, 0x4d, 0x13, 0x07, 0x1c, 0xb4, 0x90, 0x04,
11596 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xf1, 0xff, 0x02, 0x83, 0x55,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011597 0x53, 0x1d, 0xfe, 0x12, 0x13, 0xd6, 0xfe, 0x30, 0x00, 0xb0, 0xfe, 0x80,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011598 0x17, 0x1c, 0x63, 0x13, 0x07, 0xfe, 0x56, 0x10, 0x53, 0x0d, 0xfe, 0x16,
11599 0x13, 0xd6, 0xfe, 0x64, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0x64,
11600 0x00, 0x1c, 0x94, 0x13, 0x07, 0xfe, 0x28, 0x10, 0x53, 0x07, 0xfe, 0x60,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011601 0x13, 0xd6, 0xfe, 0xc8, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0xc8,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011602 0x00, 0x1c, 0x95, 0x13, 0x07, 0x71, 0xd6, 0xfe, 0x90, 0x01, 0x48, 0xfe,
11603 0x8c, 0x17, 0x45, 0xf3, 0xfe, 0x43, 0xf4, 0x96, 0xfe, 0x56, 0xf0, 0xfe,
11604 0x9e, 0x17, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x43, 0xf4, 0x94, 0xf6, 0x8b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011605 0x01, 0xfe, 0x24, 0x16, 0x23, 0x3f, 0xfc, 0xa8, 0x8c, 0x49, 0x48, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011606 0xda, 0x17, 0x62, 0x49, 0xfe, 0x1c, 0x10, 0xa8, 0x8c, 0x80, 0x48, 0xfe,
11607 0xda, 0x17, 0x62, 0x80, 0x71, 0x50, 0x26, 0xfe, 0x4d, 0xf4, 0x00, 0xf7,
11608 0x45, 0x13, 0x07, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x02, 0x50, 0x13,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011609 0x0d, 0x02, 0x50, 0x3e, 0x78, 0x4f, 0x45, 0x01, 0x08, 0x16, 0xa9, 0x27,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011610 0x25, 0xbe, 0xfe, 0x03, 0xea, 0xfe, 0x7e, 0x01, 0x01, 0x08, 0x16, 0xa9,
11611 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe,
11612 0xe9, 0x0a, 0xfe, 0x05, 0xea, 0xfe, 0x7f, 0x01, 0x01, 0x08, 0x16, 0xa9,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011613 0x27, 0x25, 0xfe, 0x69, 0x09, 0xfe, 0x02, 0xea, 0xfe, 0x80, 0x01, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011614 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, 0xe8, 0x08, 0x47, 0xfe, 0x81, 0x01,
11615 0x03, 0xb6, 0x1e, 0x83, 0x01, 0x38, 0x06, 0x24, 0x31, 0xa2, 0x78, 0xf2,
11616 0x53, 0x07, 0x36, 0xfe, 0x34, 0xf4, 0x3f, 0xa1, 0x78, 0x03, 0x9a, 0x1e,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011617 0x83, 0x01, 0x38, 0x06, 0x12, 0x31, 0xf0, 0x4f, 0x45, 0xfe, 0x90, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011618 0xfe, 0x40, 0x5a, 0x23, 0x3f, 0xfb, 0x8c, 0x49, 0x48, 0xfe, 0xaa, 0x18,
11619 0x62, 0x49, 0x71, 0x8c, 0x80, 0x48, 0xfe, 0xaa, 0x18, 0x62, 0x80, 0xfe,
11620 0xb4, 0x56, 0xfe, 0x40, 0x5d, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011621 0x02, 0x17, 0xfe, 0xc8, 0x45, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0, 0x18, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011622 0x43, 0x48, 0x2d, 0x93, 0x36, 0xfe, 0x34, 0xf4, 0xfe, 0x00, 0x11, 0xfe,
11623 0x40, 0x10, 0x2d, 0xb4, 0x36, 0xfe, 0x34, 0xf4, 0x04, 0xfe, 0x34, 0x10,
11624 0x2d, 0xfe, 0x0b, 0x00, 0x36, 0x46, 0x63, 0xfe, 0x28, 0x10, 0xfe, 0xc0,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011625 0x49, 0xff, 0x02, 0x00, 0x54, 0xb2, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0xfa,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011626 0x18, 0x45, 0xfe, 0x1c, 0xf4, 0x3f, 0xf3, 0xfe, 0x40, 0xf4, 0x96, 0xfe,
11627 0x56, 0xf0, 0xfe, 0x0c, 0x19, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x40, 0xf4,
11628 0x94, 0xf6, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d, 0x21, 0xfe, 0x7f, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011629 0xfe, 0xc8, 0x46, 0xfe, 0x24, 0x13, 0x8c, 0x00, 0x5d, 0x26, 0x21, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011630 0x7e, 0x01, 0xfe, 0xc8, 0x45, 0xfe, 0x14, 0x13, 0x21, 0xfe, 0x80, 0x01,
11631 0xfe, 0x48, 0x45, 0xfa, 0x21, 0xfe, 0x81, 0x01, 0xfe, 0xc8, 0x44, 0x4e,
11632 0x26, 0x02, 0x13, 0x07, 0x02, 0x78, 0x45, 0x50, 0x13, 0x0d, 0x02, 0x14,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011633 0x07, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, 0x0d, 0x01, 0x08, 0x17,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011634 0xfe, 0x82, 0x19, 0x14, 0x1d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x5f,
11635 0xfe, 0x89, 0x49, 0x01, 0x08, 0x02, 0x14, 0x07, 0x01, 0x08, 0x17, 0xc1,
11636 0x14, 0x1d, 0x01, 0x08, 0x17, 0xc1, 0x14, 0x07, 0x01, 0x08, 0x17, 0xc1,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011637 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0xc1, 0x5f, 0xfe, 0x89, 0x4a, 0x01,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011638 0x08, 0x02, 0x50, 0x02, 0x14, 0x07, 0x01, 0x08, 0x17, 0x74, 0x14, 0x7f,
11639 0x01, 0x08, 0x17, 0x74, 0x14, 0x12, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x89,
11640 0x49, 0x01, 0x08, 0x17, 0x74, 0x14, 0x00, 0x01, 0x08, 0x17, 0x74, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011641 0x89, 0x4a, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x09, 0x49, 0x01, 0x08, 0x17,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011642 0x74, 0x5f, 0xcc, 0x01, 0x08, 0x02, 0x21, 0xe4, 0x09, 0x07, 0xfe, 0x4c,
11643 0x13, 0xc8, 0x20, 0xe4, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x5f, 0xa1, 0x5e,
11644 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xcc, 0xff, 0x02, 0x00, 0x10, 0x2f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011645 0xfe, 0x3e, 0x1a, 0x01, 0x43, 0x09, 0xfe, 0xe3, 0x00, 0xfe, 0x22, 0x13,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011646 0x16, 0xfe, 0x64, 0x1a, 0x26, 0x20, 0x9e, 0x01, 0x41, 0x21, 0x9e, 0x09,
11647 0x07, 0x5d, 0x01, 0x0c, 0x61, 0x07, 0x44, 0x02, 0x0a, 0x5a, 0x01, 0x18,
11648 0xfe, 0x00, 0x40, 0xaa, 0x09, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011649 0x18, 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x9d, 0x01, 0x18, 0xaa,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011650 0xfe, 0x80, 0xe7, 0x1a, 0x09, 0x1a, 0x5d, 0xfe, 0x45, 0x58, 0x01, 0xfe,
11651 0xb2, 0x16, 0xaa, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0xaa, 0x0a, 0x67, 0x01,
11652 0xa3, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x01, 0xfe, 0x7e, 0x1e, 0xfe, 0x80,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011653 0x4c, 0xfe, 0x49, 0xe4, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, 0x18,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011654 0xfe, 0x80, 0x4c, 0x0a, 0x67, 0x01, 0x5c, 0x02, 0x1c, 0x1a, 0x87, 0x7c,
11655 0xe5, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24, 0x1c, 0xfe, 0x1d,
11656 0xf7, 0x28, 0xb1, 0xfe, 0x04, 0x1b, 0x01, 0xfe, 0x2a, 0x1c, 0xfa, 0xb3,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011657 0x28, 0x7c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x02, 0xc9, 0x2b, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011658 0xf4, 0x1a, 0xfe, 0xfa, 0x10, 0x1c, 0x1a, 0x87, 0x03, 0xfe, 0x64, 0x01,
11659 0xfe, 0x00, 0xf4, 0x24, 0xfe, 0x18, 0x58, 0x03, 0xfe, 0x66, 0x01, 0xfe,
11660 0x19, 0x58, 0xb3, 0x24, 0x01, 0xfe, 0x0e, 0x1f, 0xfe, 0x30, 0xf4, 0x07,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011661 0xfe, 0x3c, 0x50, 0x7c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011662 0xf7, 0x24, 0xb1, 0xfe, 0x50, 0x1b, 0xfe, 0xd4, 0x14, 0x31, 0x02, 0xc9,
11663 0x2b, 0xfe, 0x26, 0x1b, 0xfe, 0xba, 0x10, 0x1c, 0x1a, 0x87, 0xfe, 0x83,
11664 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x54, 0xb1,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011665 0xfe, 0x72, 0x1b, 0xfe, 0xb2, 0x14, 0xfc, 0xb3, 0x54, 0x7c, 0x12, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011666 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00, 0x02, 0xc9, 0x2b, 0xfe, 0x66, 0x1b,
11667 0xfe, 0x8a, 0x10, 0x1c, 0x1a, 0x87, 0x8b, 0x0f, 0xfe, 0x30, 0x90, 0x04,
11668 0xfe, 0xb0, 0x93, 0x3a, 0x0b, 0xfe, 0x18, 0x58, 0xfe, 0x32, 0x90, 0x04,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011669 0xfe, 0xb2, 0x93, 0x3a, 0x0b, 0xfe, 0x19, 0x58, 0x0e, 0xa8, 0xb3, 0x4a,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011670 0x7c, 0x12, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x4a, 0xb1, 0xfe, 0xc6,
11671 0x1b, 0xfe, 0x5e, 0x14, 0x31, 0x02, 0xc9, 0x2b, 0xfe, 0x96, 0x1b, 0x5c,
11672 0xfe, 0x02, 0xf6, 0x1a, 0x87, 0xfe, 0x18, 0xfe, 0x6a, 0xfe, 0x19, 0xfe,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011673 0x6b, 0x01, 0xfe, 0x1e, 0x1f, 0xfe, 0x1d, 0xf7, 0x65, 0xb1, 0xfe, 0xee,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011674 0x1b, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0xb3, 0x65, 0x3e, 0xfe, 0x83,
11675 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x1a, 0xfe, 0x81, 0xe7, 0x1a,
11676 0x15, 0xfe, 0xdd, 0x00, 0x7a, 0x30, 0x02, 0x7a, 0x30, 0xfe, 0x12, 0x45,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011677 0x2b, 0xfe, 0xdc, 0x1b, 0x1f, 0x07, 0x47, 0xb5, 0xc3, 0x05, 0x35, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011678 0x39, 0xf0, 0x75, 0x26, 0x02, 0xfe, 0x7e, 0x18, 0x23, 0x1d, 0x36, 0x13,
11679 0x11, 0x02, 0x87, 0x03, 0xe3, 0x23, 0x07, 0xfe, 0xef, 0x12, 0xfe, 0xe1,
11680 0x10, 0x90, 0x34, 0x60, 0xfe, 0x02, 0x80, 0x09, 0x56, 0xfe, 0x3c, 0x13,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011681 0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x51, 0xfe, 0x06, 0x83, 0x0a, 0x5a,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011682 0x01, 0x18, 0xcb, 0xfe, 0x3e, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48,
11683 0x01, 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f,
11684 0x89, 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x4c, 0x01,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011685 0x85, 0xfe, 0x16, 0x10, 0x09, 0x9b, 0x4e, 0xfe, 0x40, 0x14, 0xfe, 0x24,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011686 0x12, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x52, 0x1c, 0x1c, 0x0d,
11687 0x02, 0xfe, 0x9c, 0xe7, 0x0d, 0x19, 0xfe, 0x15, 0x00, 0x40, 0x8d, 0x30,
11688 0x01, 0xf4, 0x1c, 0x07, 0x02, 0x51, 0xfe, 0x06, 0x83, 0xfe, 0x18, 0x80,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011689 0x61, 0x28, 0x44, 0x15, 0x56, 0x01, 0x85, 0x1c, 0x07, 0x02, 0xfe, 0x38,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011690 0x90, 0xfe, 0xba, 0x90, 0x91, 0xde, 0x7e, 0xdf, 0xfe, 0x48, 0x55, 0x31,
11691 0xfe, 0xc9, 0x55, 0x02, 0x21, 0xb9, 0x88, 0x20, 0xb9, 0x02, 0x0a, 0xba,
11692 0x01, 0x18, 0xfe, 0x41, 0x48, 0x0a, 0x57, 0x01, 0x18, 0xfe, 0x49, 0x44,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011693 0x1b, 0xfe, 0x1e, 0x1d, 0x88, 0x89, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x09,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011694 0x1a, 0xa4, 0x0a, 0x67, 0x01, 0xa3, 0x0a, 0x57, 0x01, 0x18, 0x88, 0x89,
11695 0x02, 0xfe, 0x4e, 0xe4, 0x1d, 0x7b, 0xfe, 0x52, 0x1d, 0x03, 0xfe, 0x90,
11696 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xdd, 0x7b,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011697 0xfe, 0x64, 0x1d, 0x03, 0xfe, 0x92, 0x00, 0xd1, 0x12, 0xfe, 0x1a, 0x10,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011698 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x7b, 0xfe, 0x76, 0x1d, 0x03, 0xfe,
11699 0x94, 0x00, 0xd1, 0x24, 0xfe, 0x08, 0x10, 0x03, 0xfe, 0x96, 0x00, 0xd1,
11700 0x63, 0xfe, 0x4e, 0x45, 0x83, 0xca, 0xff, 0x04, 0x68, 0x54, 0xfe, 0xf1,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011701 0x10, 0x23, 0x49, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011702 0xfe, 0x1a, 0xf4, 0xfe, 0x00, 0x04, 0x83, 0xb2, 0x1d, 0x48, 0xfe, 0xaa,
11703 0x1d, 0x13, 0x1d, 0x02, 0x09, 0x92, 0xfe, 0x5a, 0xf0, 0xfe, 0xba, 0x1d,
11704 0x2e, 0x93, 0xfe, 0x34, 0x10, 0x09, 0x12, 0xfe, 0x5a, 0xf0, 0xfe, 0xc8,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011705 0x1d, 0x2e, 0xb4, 0xfe, 0x26, 0x10, 0x09, 0x1d, 0x36, 0x2e, 0x63, 0xfe,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011706 0x1a, 0x10, 0x09, 0x0d, 0x36, 0x2e, 0x94, 0xf2, 0x09, 0x07, 0x36, 0x2e,
11707 0x95, 0xa1, 0xc8, 0x02, 0x1f, 0x93, 0x01, 0x42, 0xfe, 0x04, 0xfe, 0x99,
11708 0x03, 0x9c, 0x8b, 0x02, 0x2a, 0xfe, 0x1c, 0x1e, 0xfe, 0x14, 0xf0, 0x08,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011709 0x2f, 0xfe, 0x0c, 0x1e, 0x2a, 0xfe, 0x1c, 0x1e, 0x8f, 0xfe, 0x1c, 0x1e,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011710 0xfe, 0x82, 0xf0, 0xfe, 0x10, 0x1e, 0x02, 0x0f, 0x3f, 0x04, 0xfe, 0x80,
11711 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x18, 0x80, 0x04, 0xfe, 0x98,
11712 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x02, 0x80, 0x04, 0xfe, 0x82,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011713 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x80, 0x04, 0xfe, 0x86,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011714 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x1b, 0x80, 0x04, 0xfe, 0x9b,
11715 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x04, 0x80, 0x04, 0xfe, 0x84,
11716 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x80, 0x80, 0x04, 0xfe, 0x80,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011717 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x19, 0x81, 0x04,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011718 0xfe, 0x99, 0x83, 0xfe, 0xca, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06,
11719 0x83, 0x04, 0xfe, 0x86, 0x83, 0xfe, 0xce, 0x47, 0x0b, 0x0e, 0x02, 0x0f,
11720 0xfe, 0x2c, 0x90, 0x04, 0xfe, 0xac, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011721 0xfe, 0xae, 0x90, 0x04, 0xfe, 0xae, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011722 0xfe, 0x08, 0x90, 0x04, 0xfe, 0x88, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f,
11723 0xfe, 0x8a, 0x90, 0x04, 0xfe, 0x8a, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
11724 0xfe, 0x0c, 0x90, 0x04, 0xfe, 0x8c, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011725 0xfe, 0x8e, 0x90, 0x04, 0xfe, 0x8e, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
Matthew Wilcox629d6882007-09-09 08:56:29 -060011726 0xfe, 0x3c, 0x90, 0x04, 0xfe, 0xbc, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x8b,
11727 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b, 0x77, 0x0e,
11728 0xa8, 0x02, 0xff, 0x66, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070011729};
11730
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011731static unsigned short _adv_asc38C1600_size = sizeof(_adv_asc38C1600_buf); /* 0x1673 */
11732static ADV_DCNT _adv_asc38C1600_chksum = 0x0604EF77UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011733
Linus Torvalds1da177e2005-04-16 15:20:36 -070011734/*
11735 * EEPROM Configuration.
11736 *
11737 * All drivers should use this structure to set the default EEPROM
11738 * configuration. The BIOS now uses this structure when it is built.
11739 * Additional structure information can be found in a_condor.h where
11740 * the structure is defined.
11741 *
11742 * The *_Field_IsChar structs are needed to correct for endianness.
11743 * These values are read from the board 16 bits at a time directly
11744 * into the structs. Because some fields are char, the values will be
11745 * in the wrong order. The *_Field_IsChar tells when to flip the
11746 * bytes. Data read and written to PCI memory is automatically swapped
11747 * on big-endian platforms so char fields read as words are actually being
11748 * unswapped on big-endian platforms.
11749 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060011750static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011751 ADV_EEPROM_BIOS_ENABLE, /* cfg_lsw */
11752 0x0000, /* cfg_msw */
11753 0xFFFF, /* disc_enable */
11754 0xFFFF, /* wdtr_able */
11755 0xFFFF, /* sdtr_able */
11756 0xFFFF, /* start_motor */
11757 0xFFFF, /* tagqng_able */
11758 0xFFFF, /* bios_scan */
11759 0, /* scam_tolerant */
11760 7, /* adapter_scsi_id */
11761 0, /* bios_boot_delay */
11762 3, /* scsi_reset_delay */
11763 0, /* bios_id_lun */
11764 0, /* termination */
11765 0, /* reserved1 */
11766 0xFFE7, /* bios_ctrl */
11767 0xFFFF, /* ultra_able */
11768 0, /* reserved2 */
11769 ASC_DEF_MAX_HOST_QNG, /* max_host_qng */
11770 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
11771 0, /* dvc_cntl */
11772 0, /* bug_fix */
11773 0, /* serial_number_word1 */
11774 0, /* serial_number_word2 */
11775 0, /* serial_number_word3 */
11776 0, /* check_sum */
11777 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
11778 , /* oem_name[16] */
11779 0, /* dvc_err_code */
11780 0, /* adv_err_code */
11781 0, /* adv_err_addr */
11782 0, /* saved_dvc_err_code */
11783 0, /* saved_adv_err_code */
11784 0, /* saved_adv_err_addr */
11785 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011786};
11787
Matthew Wilcox78e77d82007-07-29 21:46:15 -060011788static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011789 0, /* cfg_lsw */
11790 0, /* cfg_msw */
11791 0, /* -disc_enable */
11792 0, /* wdtr_able */
11793 0, /* sdtr_able */
11794 0, /* start_motor */
11795 0, /* tagqng_able */
11796 0, /* bios_scan */
11797 0, /* scam_tolerant */
11798 1, /* adapter_scsi_id */
11799 1, /* bios_boot_delay */
11800 1, /* scsi_reset_delay */
11801 1, /* bios_id_lun */
11802 1, /* termination */
11803 1, /* reserved1 */
11804 0, /* bios_ctrl */
11805 0, /* ultra_able */
11806 0, /* reserved2 */
11807 1, /* max_host_qng */
11808 1, /* max_dvc_qng */
11809 0, /* dvc_cntl */
11810 0, /* bug_fix */
11811 0, /* serial_number_word1 */
11812 0, /* serial_number_word2 */
11813 0, /* serial_number_word3 */
11814 0, /* check_sum */
11815 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
11816 , /* oem_name[16] */
11817 0, /* dvc_err_code */
11818 0, /* adv_err_code */
11819 0, /* adv_err_addr */
11820 0, /* saved_dvc_err_code */
11821 0, /* saved_adv_err_code */
11822 0, /* saved_adv_err_addr */
11823 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011824};
11825
Matthew Wilcox78e77d82007-07-29 21:46:15 -060011826static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011827 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
11828 0x0000, /* 01 cfg_msw */
11829 0xFFFF, /* 02 disc_enable */
11830 0xFFFF, /* 03 wdtr_able */
11831 0x4444, /* 04 sdtr_speed1 */
11832 0xFFFF, /* 05 start_motor */
11833 0xFFFF, /* 06 tagqng_able */
11834 0xFFFF, /* 07 bios_scan */
11835 0, /* 08 scam_tolerant */
11836 7, /* 09 adapter_scsi_id */
11837 0, /* bios_boot_delay */
11838 3, /* 10 scsi_reset_delay */
11839 0, /* bios_id_lun */
11840 0, /* 11 termination_se */
11841 0, /* termination_lvd */
11842 0xFFE7, /* 12 bios_ctrl */
11843 0x4444, /* 13 sdtr_speed2 */
11844 0x4444, /* 14 sdtr_speed3 */
11845 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
11846 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
11847 0, /* 16 dvc_cntl */
11848 0x4444, /* 17 sdtr_speed4 */
11849 0, /* 18 serial_number_word1 */
11850 0, /* 19 serial_number_word2 */
11851 0, /* 20 serial_number_word3 */
11852 0, /* 21 check_sum */
11853 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
11854 , /* 22-29 oem_name[16] */
11855 0, /* 30 dvc_err_code */
11856 0, /* 31 adv_err_code */
11857 0, /* 32 adv_err_addr */
11858 0, /* 33 saved_dvc_err_code */
11859 0, /* 34 saved_adv_err_code */
11860 0, /* 35 saved_adv_err_addr */
11861 0, /* 36 reserved */
11862 0, /* 37 reserved */
11863 0, /* 38 reserved */
11864 0, /* 39 reserved */
11865 0, /* 40 reserved */
11866 0, /* 41 reserved */
11867 0, /* 42 reserved */
11868 0, /* 43 reserved */
11869 0, /* 44 reserved */
11870 0, /* 45 reserved */
11871 0, /* 46 reserved */
11872 0, /* 47 reserved */
11873 0, /* 48 reserved */
11874 0, /* 49 reserved */
11875 0, /* 50 reserved */
11876 0, /* 51 reserved */
11877 0, /* 52 reserved */
11878 0, /* 53 reserved */
11879 0, /* 54 reserved */
11880 0, /* 55 reserved */
11881 0, /* 56 cisptr_lsw */
11882 0, /* 57 cisprt_msw */
11883 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
11884 PCI_DEVICE_ID_38C0800_REV1, /* 59 subsysid */
11885 0, /* 60 reserved */
11886 0, /* 61 reserved */
11887 0, /* 62 reserved */
11888 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011889};
11890
Matthew Wilcox78e77d82007-07-29 21:46:15 -060011891static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011892 0, /* 00 cfg_lsw */
11893 0, /* 01 cfg_msw */
11894 0, /* 02 disc_enable */
11895 0, /* 03 wdtr_able */
11896 0, /* 04 sdtr_speed1 */
11897 0, /* 05 start_motor */
11898 0, /* 06 tagqng_able */
11899 0, /* 07 bios_scan */
11900 0, /* 08 scam_tolerant */
11901 1, /* 09 adapter_scsi_id */
11902 1, /* bios_boot_delay */
11903 1, /* 10 scsi_reset_delay */
11904 1, /* bios_id_lun */
11905 1, /* 11 termination_se */
11906 1, /* termination_lvd */
11907 0, /* 12 bios_ctrl */
11908 0, /* 13 sdtr_speed2 */
11909 0, /* 14 sdtr_speed3 */
11910 1, /* 15 max_host_qng */
11911 1, /* max_dvc_qng */
11912 0, /* 16 dvc_cntl */
11913 0, /* 17 sdtr_speed4 */
11914 0, /* 18 serial_number_word1 */
11915 0, /* 19 serial_number_word2 */
11916 0, /* 20 serial_number_word3 */
11917 0, /* 21 check_sum */
11918 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
11919 , /* 22-29 oem_name[16] */
11920 0, /* 30 dvc_err_code */
11921 0, /* 31 adv_err_code */
11922 0, /* 32 adv_err_addr */
11923 0, /* 33 saved_dvc_err_code */
11924 0, /* 34 saved_adv_err_code */
11925 0, /* 35 saved_adv_err_addr */
11926 0, /* 36 reserved */
11927 0, /* 37 reserved */
11928 0, /* 38 reserved */
11929 0, /* 39 reserved */
11930 0, /* 40 reserved */
11931 0, /* 41 reserved */
11932 0, /* 42 reserved */
11933 0, /* 43 reserved */
11934 0, /* 44 reserved */
11935 0, /* 45 reserved */
11936 0, /* 46 reserved */
11937 0, /* 47 reserved */
11938 0, /* 48 reserved */
11939 0, /* 49 reserved */
11940 0, /* 50 reserved */
11941 0, /* 51 reserved */
11942 0, /* 52 reserved */
11943 0, /* 53 reserved */
11944 0, /* 54 reserved */
11945 0, /* 55 reserved */
11946 0, /* 56 cisptr_lsw */
11947 0, /* 57 cisprt_msw */
11948 0, /* 58 subsysvid */
11949 0, /* 59 subsysid */
11950 0, /* 60 reserved */
11951 0, /* 61 reserved */
11952 0, /* 62 reserved */
11953 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011954};
11955
Matthew Wilcox78e77d82007-07-29 21:46:15 -060011956static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011957 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
11958 0x0000, /* 01 cfg_msw */
11959 0xFFFF, /* 02 disc_enable */
11960 0xFFFF, /* 03 wdtr_able */
11961 0x5555, /* 04 sdtr_speed1 */
11962 0xFFFF, /* 05 start_motor */
11963 0xFFFF, /* 06 tagqng_able */
11964 0xFFFF, /* 07 bios_scan */
11965 0, /* 08 scam_tolerant */
11966 7, /* 09 adapter_scsi_id */
11967 0, /* bios_boot_delay */
11968 3, /* 10 scsi_reset_delay */
11969 0, /* bios_id_lun */
11970 0, /* 11 termination_se */
11971 0, /* termination_lvd */
11972 0xFFE7, /* 12 bios_ctrl */
11973 0x5555, /* 13 sdtr_speed2 */
11974 0x5555, /* 14 sdtr_speed3 */
11975 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
11976 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
11977 0, /* 16 dvc_cntl */
11978 0x5555, /* 17 sdtr_speed4 */
11979 0, /* 18 serial_number_word1 */
11980 0, /* 19 serial_number_word2 */
11981 0, /* 20 serial_number_word3 */
11982 0, /* 21 check_sum */
11983 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
11984 , /* 22-29 oem_name[16] */
11985 0, /* 30 dvc_err_code */
11986 0, /* 31 adv_err_code */
11987 0, /* 32 adv_err_addr */
11988 0, /* 33 saved_dvc_err_code */
11989 0, /* 34 saved_adv_err_code */
11990 0, /* 35 saved_adv_err_addr */
11991 0, /* 36 reserved */
11992 0, /* 37 reserved */
11993 0, /* 38 reserved */
11994 0, /* 39 reserved */
11995 0, /* 40 reserved */
11996 0, /* 41 reserved */
11997 0, /* 42 reserved */
11998 0, /* 43 reserved */
11999 0, /* 44 reserved */
12000 0, /* 45 reserved */
12001 0, /* 46 reserved */
12002 0, /* 47 reserved */
12003 0, /* 48 reserved */
12004 0, /* 49 reserved */
12005 0, /* 50 reserved */
12006 0, /* 51 reserved */
12007 0, /* 52 reserved */
12008 0, /* 53 reserved */
12009 0, /* 54 reserved */
12010 0, /* 55 reserved */
12011 0, /* 56 cisptr_lsw */
12012 0, /* 57 cisprt_msw */
12013 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
12014 PCI_DEVICE_ID_38C1600_REV1, /* 59 subsysid */
12015 0, /* 60 reserved */
12016 0, /* 61 reserved */
12017 0, /* 62 reserved */
12018 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012019};
12020
Matthew Wilcox78e77d82007-07-29 21:46:15 -060012021static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012022 0, /* 00 cfg_lsw */
12023 0, /* 01 cfg_msw */
12024 0, /* 02 disc_enable */
12025 0, /* 03 wdtr_able */
12026 0, /* 04 sdtr_speed1 */
12027 0, /* 05 start_motor */
12028 0, /* 06 tagqng_able */
12029 0, /* 07 bios_scan */
12030 0, /* 08 scam_tolerant */
12031 1, /* 09 adapter_scsi_id */
12032 1, /* bios_boot_delay */
12033 1, /* 10 scsi_reset_delay */
12034 1, /* bios_id_lun */
12035 1, /* 11 termination_se */
12036 1, /* termination_lvd */
12037 0, /* 12 bios_ctrl */
12038 0, /* 13 sdtr_speed2 */
12039 0, /* 14 sdtr_speed3 */
12040 1, /* 15 max_host_qng */
12041 1, /* max_dvc_qng */
12042 0, /* 16 dvc_cntl */
12043 0, /* 17 sdtr_speed4 */
12044 0, /* 18 serial_number_word1 */
12045 0, /* 19 serial_number_word2 */
12046 0, /* 20 serial_number_word3 */
12047 0, /* 21 check_sum */
12048 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
12049 , /* 22-29 oem_name[16] */
12050 0, /* 30 dvc_err_code */
12051 0, /* 31 adv_err_code */
12052 0, /* 32 adv_err_addr */
12053 0, /* 33 saved_dvc_err_code */
12054 0, /* 34 saved_adv_err_code */
12055 0, /* 35 saved_adv_err_addr */
12056 0, /* 36 reserved */
12057 0, /* 37 reserved */
12058 0, /* 38 reserved */
12059 0, /* 39 reserved */
12060 0, /* 40 reserved */
12061 0, /* 41 reserved */
12062 0, /* 42 reserved */
12063 0, /* 43 reserved */
12064 0, /* 44 reserved */
12065 0, /* 45 reserved */
12066 0, /* 46 reserved */
12067 0, /* 47 reserved */
12068 0, /* 48 reserved */
12069 0, /* 49 reserved */
12070 0, /* 50 reserved */
12071 0, /* 51 reserved */
12072 0, /* 52 reserved */
12073 0, /* 53 reserved */
12074 0, /* 54 reserved */
12075 0, /* 55 reserved */
12076 0, /* 56 cisptr_lsw */
12077 0, /* 57 cisprt_msw */
12078 0, /* 58 subsysvid */
12079 0, /* 59 subsysid */
12080 0, /* 60 reserved */
12081 0, /* 61 reserved */
12082 0, /* 62 reserved */
12083 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012084};
12085
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060012086#ifdef CONFIG_PCI
Linus Torvalds1da177e2005-04-16 15:20:36 -070012087/*
12088 * Initialize the ADV_DVC_VAR structure.
12089 *
12090 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
12091 *
12092 * For a non-fatal error return a warning code. If there are no warnings
12093 * then 0 is returned.
12094 */
Matthew Wilcox394dbf32007-07-26 11:56:40 -040012095static int __devinit
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060012096AdvInitGetConfig(struct pci_dev *pdev, asc_board_t *boardp)
Linus Torvalds1da177e2005-04-16 15:20:36 -070012097{
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060012098 ADV_DVC_VAR *asc_dvc = &boardp->dvc_var.adv_dvc_var;
Matthew Wilcox9649af32007-07-26 21:51:47 -060012099 unsigned short warn_code = 0;
12100 AdvPortAddr iop_base = asc_dvc->iop_base;
Matthew Wilcox9649af32007-07-26 21:51:47 -060012101 u16 cmd;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012102 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012103
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012104 asc_dvc->err_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012105
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012106 /*
12107 * Save the state of the PCI Configuration Command Register
12108 * "Parity Error Response Control" Bit. If the bit is clear (0),
12109 * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore
12110 * DMA parity errors.
12111 */
12112 asc_dvc->cfg->control_flag = 0;
Matthew Wilcox9649af32007-07-26 21:51:47 -060012113 pci_read_config_word(pdev, PCI_COMMAND, &cmd);
12114 if ((cmd & PCI_COMMAND_PARITY) == 0)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012115 asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012116
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012117 asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) |
12118 ADV_LIB_VERSION_MINOR;
12119 asc_dvc->cfg->chip_version =
12120 AdvGetChipVersion(iop_base, asc_dvc->bus_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012121
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012122 ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: 0x%x 0x%x\n",
12123 (ushort)AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
12124 (ushort)ADV_CHIP_ID_BYTE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012125
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012126 ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: 0x%x 0x%x\n",
12127 (ushort)AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
12128 (ushort)ADV_CHIP_ID_WORD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012129
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012130 /*
12131 * Reset the chip to start and allow register writes.
12132 */
12133 if (AdvFindSignature(iop_base) == 0) {
12134 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
12135 return ADV_ERROR;
12136 } else {
12137 /*
12138 * The caller must set 'chip_type' to a valid setting.
12139 */
12140 if (asc_dvc->chip_type != ADV_CHIP_ASC3550 &&
12141 asc_dvc->chip_type != ADV_CHIP_ASC38C0800 &&
12142 asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
12143 asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
12144 return ADV_ERROR;
12145 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012146
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012147 /*
12148 * Reset Chip.
12149 */
12150 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
12151 ADV_CTRL_REG_CMD_RESET);
12152 DvcSleepMilliSecond(100);
12153 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
12154 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012155
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012156 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
Matthew Wilcox9649af32007-07-26 21:51:47 -060012157 status = AdvInitFrom38C1600EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012158 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
Matthew Wilcox9649af32007-07-26 21:51:47 -060012159 status = AdvInitFrom38C0800EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012160 } else {
Matthew Wilcox9649af32007-07-26 21:51:47 -060012161 status = AdvInitFrom3550EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012162 }
12163 warn_code |= status;
12164 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012165
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060012166 if (warn_code != 0) {
12167 ASC_PRINT2("AdvInitGetConfig: board %d: warning: 0x%x\n",
12168 boardp->id, warn_code);
12169 }
12170
12171 if (asc_dvc->err_code) {
12172 ASC_PRINT2("AdvInitGetConfig: board %d error: err_code 0x%x\n",
12173 boardp->id, asc_dvc->err_code);
12174 }
12175
12176 return asc_dvc->err_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012177}
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060012178#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070012179
Matthew Wilcoxa9f4a592007-09-09 08:56:27 -060012180static void AdvBuildCarrierFreelist(struct adv_dvc_var *asc_dvc)
12181{
12182 ADV_CARR_T *carrp;
12183 ADV_SDCNT buf_size;
12184 ADV_PADDR carr_paddr;
12185
12186 BUG_ON(!asc_dvc->carrier_buf);
12187
12188 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
12189 asc_dvc->carr_freelist = NULL;
12190 if (carrp == asc_dvc->carrier_buf) {
12191 buf_size = ADV_CARRIER_BUFSIZE;
12192 } else {
12193 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
12194 }
12195
12196 do {
12197 /* Get physical address of the carrier 'carrp'. */
12198 ADV_DCNT contig_len = sizeof(ADV_CARR_T);
12199 carr_paddr = cpu_to_le32(DvcGetPhyAddr(asc_dvc, NULL,
12200 (uchar *)carrp,
12201 (ADV_SDCNT *)&contig_len,
12202 ADV_IS_CARRIER_FLAG));
12203
12204 buf_size -= sizeof(ADV_CARR_T);
12205
12206 /*
12207 * If the current carrier is not physically contiguous, then
12208 * maybe there was a page crossing. Try the next carrier
12209 * aligned start address.
12210 */
12211 if (contig_len < sizeof(ADV_CARR_T)) {
12212 carrp++;
12213 continue;
12214 }
12215
12216 carrp->carr_pa = carr_paddr;
12217 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
12218
12219 /*
12220 * Insert the carrier at the beginning of the freelist.
12221 */
12222 carrp->next_vpa =
12223 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
12224 asc_dvc->carr_freelist = carrp;
12225
12226 carrp++;
12227 } while (buf_size > 0);
12228}
12229
Linus Torvalds1da177e2005-04-16 15:20:36 -070012230/*
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012231 * Load the Microcode
12232 *
12233 * Write the microcode image to RISC memory starting at address 0.
12234 *
12235 * The microcode is stored compressed in the following format:
12236 *
12237 * 254 word (508 byte) table indexed by byte code followed
12238 * by the following byte codes:
12239 *
12240 * 1-Byte Code:
12241 * 00: Emit word 0 in table.
12242 * 01: Emit word 1 in table.
12243 * .
12244 * FD: Emit word 253 in table.
12245 *
12246 * Multi-Byte Code:
12247 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
12248 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
12249 *
12250 * Returns 0 or an error if the checksum doesn't match
12251 */
12252static int AdvLoadMicrocode(AdvPortAddr iop_base, unsigned char *buf, int size,
12253 int memsize, int chksum)
12254{
12255 int i, j, end, len = 0;
12256 ADV_DCNT sum;
12257
12258 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
12259
12260 for (i = 253 * 2; i < size; i++) {
12261 if (buf[i] == 0xff) {
12262 unsigned short word = (buf[i + 3] << 8) | buf[i + 2];
12263 for (j = 0; j < buf[i + 1]; j++) {
12264 AdvWriteWordAutoIncLram(iop_base, word);
12265 len += 2;
12266 }
12267 i += 3;
12268 } else if (buf[i] == 0xfe) {
12269 unsigned short word = (buf[i + 2] << 8) | buf[i + 1];
12270 AdvWriteWordAutoIncLram(iop_base, word);
12271 i += 2;
12272 len += 2;
12273 } else {
12274 unsigned char off = buf[i] * 2;
12275 unsigned short word = (buf[off + 1] << 8) | buf[off];
12276 AdvWriteWordAutoIncLram(iop_base, word);
12277 len += 2;
12278 }
12279 }
12280
12281 end = len;
12282
12283 while (len < memsize) {
12284 AdvWriteWordAutoIncLram(iop_base, 0);
12285 len += 2;
12286 }
12287
12288 /* Verify the microcode checksum. */
12289 sum = 0;
12290 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
12291
12292 for (len = 0; len < end; len += 2) {
12293 sum += AdvReadWordAutoIncLram(iop_base);
12294 }
12295
12296 if (sum != chksum)
12297 return ASC_IERR_MCODE_CHKSUM;
12298
12299 return 0;
12300}
12301
12302/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070012303 * Initialize the ASC-3550.
12304 *
12305 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
12306 *
12307 * For a non-fatal error return a warning code. If there are no warnings
12308 * then 0 is returned.
12309 *
12310 * Needed after initialization for error recovery.
12311 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012312static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070012313{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012314 AdvPortAddr iop_base;
12315 ushort warn_code;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012316 int begin_addr;
12317 int end_addr;
12318 ushort code_sum;
12319 int word;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012320 int i;
12321 ushort scsi_cfg1;
12322 uchar tid;
12323 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
12324 ushort wdtr_able = 0, sdtr_able, tagqng_able;
12325 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070012326
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012327 /* If there is already an error, don't continue. */
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012328 if (asc_dvc->err_code != 0)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012329 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012330
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012331 /*
12332 * The caller must set 'chip_type' to ADV_CHIP_ASC3550.
12333 */
12334 if (asc_dvc->chip_type != ADV_CHIP_ASC3550) {
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012335 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012336 return ADV_ERROR;
12337 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012338
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012339 warn_code = 0;
12340 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012341
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012342 /*
12343 * Save the RISC memory BIOS region before writing the microcode.
12344 * The BIOS may already be loaded and using its RISC LRAM region
12345 * so its region must be saved and restored.
12346 *
12347 * Note: This code makes the assumption, which is currently true,
12348 * that a chip reset does not clear RISC LRAM.
12349 */
12350 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
12351 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
12352 bios_mem[i]);
12353 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012354
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012355 /*
12356 * Save current per TID negotiated values.
12357 */
12358 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == 0x55AA) {
12359 ushort bios_version, major, minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012360
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012361 bios_version =
12362 bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM) / 2];
12363 major = (bios_version >> 12) & 0xF;
12364 minor = (bios_version >> 8) & 0xF;
12365 if (major < 3 || (major == 3 && minor == 1)) {
12366 /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
12367 AdvReadWordLram(iop_base, 0x120, wdtr_able);
12368 } else {
12369 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
12370 }
12371 }
12372 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
12373 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
12374 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
12375 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
12376 max_cmd[tid]);
12377 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012378
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012379 asc_dvc->err_code = AdvLoadMicrocode(iop_base, _adv_asc3550_buf,
12380 _adv_asc3550_size, ADV_3550_MEMSIZE,
12381 _adv_asc3550_chksum);
12382 if (asc_dvc->err_code)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012383 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012384
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012385 /*
12386 * Restore the RISC memory BIOS region.
12387 */
12388 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
12389 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
12390 bios_mem[i]);
12391 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012392
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012393 /*
12394 * Calculate and write the microcode code checksum to the microcode
12395 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
12396 */
12397 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
12398 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
12399 code_sum = 0;
12400 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
12401 for (word = begin_addr; word < end_addr; word += 2) {
12402 code_sum += AdvReadWordAutoIncLram(iop_base);
12403 }
12404 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012405
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012406 /*
12407 * Read and save microcode version and date.
12408 */
12409 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
12410 asc_dvc->cfg->mcode_date);
12411 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
12412 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012413
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012414 /*
12415 * Set the chip type to indicate the ASC3550.
12416 */
12417 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012418
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012419 /*
12420 * If the PCI Configuration Command Register "Parity Error Response
12421 * Control" Bit was clear (0), then set the microcode variable
12422 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
12423 * to ignore DMA parity errors.
12424 */
12425 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
12426 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
12427 word |= CONTROL_FLAG_IGNORE_PERR;
12428 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
12429 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012430
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012431 /*
12432 * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
12433 * threshold of 128 bytes. This register is only accessible to the host.
12434 */
12435 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
12436 START_CTL_EMFU | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012437
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012438 /*
12439 * Microcode operating variables for WDTR, SDTR, and command tag
Matthew Wilcox47d853c2007-07-26 11:41:33 -040012440 * queuing will be set in slave_configure() based on what a
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012441 * device reports it is capable of in Inquiry byte 7.
12442 *
12443 * If SCSI Bus Resets have been disabled, then directly set
12444 * SDTR and WDTR from the EEPROM configuration. This will allow
12445 * the BIOS and warm boot to work without a SCSI bus hang on
12446 * the Inquiry caused by host and target mismatched DTR values.
12447 * Without the SCSI Bus Reset, before an Inquiry a device can't
12448 * be assumed to be in Asynchronous, Narrow mode.
12449 */
12450 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
12451 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
12452 asc_dvc->wdtr_able);
12453 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
12454 asc_dvc->sdtr_able);
12455 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012456
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012457 /*
12458 * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
12459 * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
12460 * bitmask. These values determine the maximum SDTR speed negotiated
12461 * with a device.
12462 *
12463 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
12464 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
12465 * without determining here whether the device supports SDTR.
12466 *
12467 * 4-bit speed SDTR speed name
12468 * =========== ===============
12469 * 0000b (0x0) SDTR disabled
12470 * 0001b (0x1) 5 Mhz
12471 * 0010b (0x2) 10 Mhz
12472 * 0011b (0x3) 20 Mhz (Ultra)
12473 * 0100b (0x4) 40 Mhz (LVD/Ultra2)
12474 * 0101b (0x5) 80 Mhz (LVD2/Ultra3)
12475 * 0110b (0x6) Undefined
12476 * .
12477 * 1111b (0xF) Undefined
12478 */
12479 word = 0;
12480 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
12481 if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) {
12482 /* Set Ultra speed for TID 'tid'. */
12483 word |= (0x3 << (4 * (tid % 4)));
12484 } else {
12485 /* Set Fast speed for TID 'tid'. */
12486 word |= (0x2 << (4 * (tid % 4)));
12487 }
12488 if (tid == 3) { /* Check if done with sdtr_speed1. */
12489 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
12490 word = 0;
12491 } else if (tid == 7) { /* Check if done with sdtr_speed2. */
12492 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
12493 word = 0;
12494 } else if (tid == 11) { /* Check if done with sdtr_speed3. */
12495 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
12496 word = 0;
12497 } else if (tid == 15) { /* Check if done with sdtr_speed4. */
12498 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
12499 /* End of loop. */
12500 }
12501 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012502
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012503 /*
12504 * Set microcode operating variable for the disconnect per TID bitmask.
12505 */
12506 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
12507 asc_dvc->cfg->disc_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012508
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012509 /*
12510 * Set SCSI_CFG0 Microcode Default Value.
12511 *
12512 * The microcode will set the SCSI_CFG0 register using this value
12513 * after it is started below.
12514 */
12515 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
12516 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
12517 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012518
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012519 /*
12520 * Determine SCSI_CFG1 Microcode Default Value.
12521 *
12522 * The microcode will set the SCSI_CFG1 register using this value
12523 * after it is started below.
12524 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012525
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012526 /* Read current SCSI_CFG1 Register value. */
12527 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012528
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012529 /*
12530 * If all three connectors are in use, return an error.
12531 */
12532 if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
12533 (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) {
12534 asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
12535 return ADV_ERROR;
12536 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012537
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012538 /*
12539 * If the internal narrow cable is reversed all of the SCSI_CTRL
12540 * register signals will be set. Check for and return an error if
12541 * this condition is found.
12542 */
12543 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
12544 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
12545 return ADV_ERROR;
12546 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012547
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012548 /*
12549 * If this is a differential board and a single-ended device
12550 * is attached to one of the connectors, return an error.
12551 */
12552 if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) {
12553 asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE;
12554 return ADV_ERROR;
12555 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012556
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012557 /*
12558 * If automatic termination control is enabled, then set the
12559 * termination value based on a table listed in a_condor.h.
12560 *
12561 * If manual termination was specified with an EEPROM setting
12562 * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
12563 * is ready to be 'ored' into SCSI_CFG1.
12564 */
12565 if (asc_dvc->cfg->termination == 0) {
12566 /*
12567 * The software always controls termination by setting TERM_CTL_SEL.
12568 * If TERM_CTL_SEL were set to 0, the hardware would set termination.
12569 */
12570 asc_dvc->cfg->termination |= TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012571
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012572 switch (scsi_cfg1 & CABLE_DETECT) {
12573 /* TERM_CTL_H: on, TERM_CTL_L: on */
12574 case 0x3:
12575 case 0x7:
12576 case 0xB:
12577 case 0xD:
12578 case 0xE:
12579 case 0xF:
12580 asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L);
12581 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012582
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012583 /* TERM_CTL_H: on, TERM_CTL_L: off */
12584 case 0x1:
12585 case 0x5:
12586 case 0x9:
12587 case 0xA:
12588 case 0xC:
12589 asc_dvc->cfg->termination |= TERM_CTL_H;
12590 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012591
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012592 /* TERM_CTL_H: off, TERM_CTL_L: off */
12593 case 0x2:
12594 case 0x6:
12595 break;
12596 }
12597 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012598
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012599 /*
12600 * Clear any set TERM_CTL_H and TERM_CTL_L bits.
12601 */
12602 scsi_cfg1 &= ~TERM_CTL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012603
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012604 /*
12605 * Invert the TERM_CTL_H and TERM_CTL_L bits and then
12606 * set 'scsi_cfg1'. The TERM_POL bit does not need to be
12607 * referenced, because the hardware internally inverts
12608 * the Termination High and Low bits if TERM_POL is set.
12609 */
12610 scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012611
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012612 /*
12613 * Set SCSI_CFG1 Microcode Default Value
12614 *
12615 * Set filter value and possibly modified termination control
12616 * bits in the Microcode SCSI_CFG1 Register Value.
12617 *
12618 * The microcode will set the SCSI_CFG1 register using this value
12619 * after it is started below.
12620 */
12621 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
12622 FLTR_DISABLE | scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012623
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012624 /*
12625 * Set MEM_CFG Microcode Default Value
12626 *
12627 * The microcode will set the MEM_CFG register using this value
12628 * after it is started below.
12629 *
12630 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
12631 * are defined.
12632 *
12633 * ASC-3550 has 8KB internal memory.
12634 */
12635 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
12636 BIOS_EN | RAM_SZ_8KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012637
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012638 /*
12639 * Set SEL_MASK Microcode Default Value
12640 *
12641 * The microcode will set the SEL_MASK register using this value
12642 * after it is started below.
12643 */
12644 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
12645 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012646
Matthew Wilcoxa9f4a592007-09-09 08:56:27 -060012647 AdvBuildCarrierFreelist(asc_dvc);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012648
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012649 /*
12650 * Set-up the Host->RISC Initiator Command Queue (ICQ).
12651 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012652
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012653 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
12654 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
12655 return ADV_ERROR;
12656 }
12657 asc_dvc->carr_freelist = (ADV_CARR_T *)
12658 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012659
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012660 /*
12661 * The first command issued will be placed in the stopper carrier.
12662 */
12663 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012664
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012665 /*
12666 * Set RISC ICQ physical address start value.
12667 */
12668 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012669
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012670 /*
12671 * Set-up the RISC->Host Initiator Response Queue (IRQ).
12672 */
12673 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
12674 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
12675 return ADV_ERROR;
12676 }
12677 asc_dvc->carr_freelist = (ADV_CARR_T *)
12678 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012679
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012680 /*
12681 * The first command completed by the RISC will be placed in
12682 * the stopper.
12683 *
12684 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
12685 * completed the RISC will set the ASC_RQ_STOPPER bit.
12686 */
12687 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012688
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012689 /*
12690 * Set RISC IRQ physical address start value.
12691 */
12692 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
12693 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012694
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012695 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
12696 (ADV_INTR_ENABLE_HOST_INTR |
12697 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070012698
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012699 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
12700 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012701
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012702 /* finally, finally, gentlemen, start your engine */
12703 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012704
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012705 /*
12706 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
12707 * Resets should be performed. The RISC has to be running
12708 * to issue a SCSI Bus Reset.
12709 */
12710 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
12711 /*
12712 * If the BIOS Signature is present in memory, restore the
12713 * BIOS Handshake Configuration Table and do not perform
12714 * a SCSI Bus Reset.
12715 */
12716 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
12717 0x55AA) {
12718 /*
12719 * Restore per TID negotiated values.
12720 */
12721 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
12722 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
12723 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
12724 tagqng_able);
12725 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
12726 AdvWriteByteLram(iop_base,
12727 ASC_MC_NUMBER_OF_MAX_CMD + tid,
12728 max_cmd[tid]);
12729 }
12730 } else {
12731 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
12732 warn_code = ASC_WARN_BUSRESET_ERROR;
12733 }
12734 }
12735 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012736
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012737 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012738}
12739
12740/*
12741 * Initialize the ASC-38C0800.
12742 *
12743 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
12744 *
12745 * For a non-fatal error return a warning code. If there are no warnings
12746 * then 0 is returned.
12747 *
12748 * Needed after initialization for error recovery.
12749 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012750static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070012751{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012752 AdvPortAddr iop_base;
12753 ushort warn_code;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012754 int begin_addr;
12755 int end_addr;
12756 ushort code_sum;
12757 int word;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012758 int i;
12759 ushort scsi_cfg1;
12760 uchar byte;
12761 uchar tid;
12762 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
12763 ushort wdtr_able, sdtr_able, tagqng_able;
12764 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070012765
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012766 /* If there is already an error, don't continue. */
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012767 if (asc_dvc->err_code != 0)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012768 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012769
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012770 /*
12771 * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
12772 */
12773 if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) {
12774 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
12775 return ADV_ERROR;
12776 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012777
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012778 warn_code = 0;
12779 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012780
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012781 /*
12782 * Save the RISC memory BIOS region before writing the microcode.
12783 * The BIOS may already be loaded and using its RISC LRAM region
12784 * so its region must be saved and restored.
12785 *
12786 * Note: This code makes the assumption, which is currently true,
12787 * that a chip reset does not clear RISC LRAM.
12788 */
12789 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
12790 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
12791 bios_mem[i]);
12792 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012793
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012794 /*
12795 * Save current per TID negotiated values.
12796 */
12797 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
12798 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
12799 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
12800 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
12801 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
12802 max_cmd[tid]);
12803 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012804
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012805 /*
12806 * RAM BIST (RAM Built-In Self Test)
12807 *
12808 * Address : I/O base + offset 0x38h register (byte).
12809 * Function: Bit 7-6(RW) : RAM mode
12810 * Normal Mode : 0x00
12811 * Pre-test Mode : 0x40
12812 * RAM Test Mode : 0x80
12813 * Bit 5 : unused
12814 * Bit 4(RO) : Done bit
12815 * Bit 3-0(RO) : Status
12816 * Host Error : 0x08
12817 * Int_RAM Error : 0x04
12818 * RISC Error : 0x02
12819 * SCSI Error : 0x01
12820 * No Error : 0x00
12821 *
12822 * Note: RAM BIST code should be put right here, before loading the
12823 * microcode and after saving the RISC memory BIOS region.
12824 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012825
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012826 /*
12827 * LRAM Pre-test
12828 *
12829 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
12830 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
12831 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
12832 * to NORMAL_MODE, return an error too.
12833 */
12834 for (i = 0; i < 2; i++) {
12835 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
12836 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
12837 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
12838 if ((byte & RAM_TEST_DONE) == 0
12839 || (byte & 0x0F) != PRE_TEST_VALUE) {
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012840 asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012841 return ADV_ERROR;
12842 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012843
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012844 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
12845 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
12846 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
12847 != NORMAL_VALUE) {
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012848 asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012849 return ADV_ERROR;
12850 }
12851 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012852
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012853 /*
12854 * LRAM Test - It takes about 1.5 ms to run through the test.
12855 *
12856 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
12857 * If Done bit not set or Status not 0, save register byte, set the
12858 * err_code, and return an error.
12859 */
12860 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
12861 DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012862
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012863 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
12864 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
12865 /* Get here if Done bit not set or Status not 0. */
12866 asc_dvc->bist_err_code = byte; /* for BIOS display message */
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012867 asc_dvc->err_code = ASC_IERR_BIST_RAM_TEST;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012868 return ADV_ERROR;
12869 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012870
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012871 /* We need to reset back to normal mode after LRAM test passes. */
12872 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012873
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060012874 asc_dvc->err_code = AdvLoadMicrocode(iop_base, _adv_asc38C0800_buf,
12875 _adv_asc38C0800_size, ADV_38C0800_MEMSIZE,
12876 _adv_asc38C0800_chksum);
12877 if (asc_dvc->err_code)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012878 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070012879
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012880 /*
12881 * Restore the RISC memory BIOS region.
12882 */
12883 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
12884 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
12885 bios_mem[i]);
12886 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012887
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012888 /*
12889 * Calculate and write the microcode code checksum to the microcode
12890 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
12891 */
12892 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
12893 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
12894 code_sum = 0;
12895 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
12896 for (word = begin_addr; word < end_addr; word += 2) {
12897 code_sum += AdvReadWordAutoIncLram(iop_base);
12898 }
12899 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012900
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012901 /*
12902 * Read microcode version and date.
12903 */
12904 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
12905 asc_dvc->cfg->mcode_date);
12906 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
12907 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012908
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012909 /*
12910 * Set the chip type to indicate the ASC38C0800.
12911 */
12912 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012913
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012914 /*
12915 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
12916 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
12917 * cable detection and then we are able to read C_DET[3:0].
12918 *
12919 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
12920 * Microcode Default Value' section below.
12921 */
12922 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
12923 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
12924 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012925
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012926 /*
12927 * If the PCI Configuration Command Register "Parity Error Response
12928 * Control" Bit was clear (0), then set the microcode variable
12929 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
12930 * to ignore DMA parity errors.
12931 */
12932 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
12933 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
12934 word |= CONTROL_FLAG_IGNORE_PERR;
12935 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
12936 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012937
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012938 /*
12939 * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
12940 * bits for the default FIFO threshold.
12941 *
12942 * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
12943 *
12944 * For DMA Errata #4 set the BC_THRESH_ENB bit.
12945 */
12946 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
12947 BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH |
12948 READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012949
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012950 /*
12951 * Microcode operating variables for WDTR, SDTR, and command tag
Matthew Wilcox47d853c2007-07-26 11:41:33 -040012952 * queuing will be set in slave_configure() based on what a
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012953 * device reports it is capable of in Inquiry byte 7.
12954 *
12955 * If SCSI Bus Resets have been disabled, then directly set
12956 * SDTR and WDTR from the EEPROM configuration. This will allow
12957 * the BIOS and warm boot to work without a SCSI bus hang on
12958 * the Inquiry caused by host and target mismatched DTR values.
12959 * Without the SCSI Bus Reset, before an Inquiry a device can't
12960 * be assumed to be in Asynchronous, Narrow mode.
12961 */
12962 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
12963 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
12964 asc_dvc->wdtr_able);
12965 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
12966 asc_dvc->sdtr_able);
12967 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070012968
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012969 /*
12970 * Set microcode operating variables for DISC and SDTR_SPEED1,
12971 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
12972 * configuration values.
12973 *
12974 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
12975 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
12976 * without determining here whether the device supports SDTR.
12977 */
12978 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
12979 asc_dvc->cfg->disc_enable);
12980 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
12981 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
12982 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
12983 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012984
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012985 /*
12986 * Set SCSI_CFG0 Microcode Default Value.
12987 *
12988 * The microcode will set the SCSI_CFG0 register using this value
12989 * after it is started below.
12990 */
12991 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
12992 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
12993 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070012994
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012995 /*
12996 * Determine SCSI_CFG1 Microcode Default Value.
12997 *
12998 * The microcode will set the SCSI_CFG1 register using this value
12999 * after it is started below.
13000 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013001
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013002 /* Read current SCSI_CFG1 Register value. */
13003 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013004
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013005 /*
13006 * If the internal narrow cable is reversed all of the SCSI_CTRL
13007 * register signals will be set. Check for and return an error if
13008 * this condition is found.
13009 */
13010 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
13011 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
13012 return ADV_ERROR;
13013 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013014
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013015 /*
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060013016 * All kind of combinations of devices attached to one of four
13017 * connectors are acceptable except HVD device attached. For example,
13018 * LVD device can be attached to SE connector while SE device attached
13019 * to LVD connector. If LVD device attached to SE connector, it only
13020 * runs up to Ultra speed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013021 *
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060013022 * If an HVD device is attached to one of LVD connectors, return an
13023 * error. However, there is no way to detect HVD device attached to
13024 * SE connectors.
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013025 */
13026 if (scsi_cfg1 & HVD) {
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060013027 asc_dvc->err_code = ASC_IERR_HVD_DEVICE;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013028 return ADV_ERROR;
13029 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013030
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013031 /*
13032 * If either SE or LVD automatic termination control is enabled, then
13033 * set the termination value based on a table listed in a_condor.h.
13034 *
13035 * If manual termination was specified with an EEPROM setting then
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060013036 * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready
13037 * to be 'ored' into SCSI_CFG1.
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013038 */
13039 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
13040 /* SE automatic termination control is enabled. */
13041 switch (scsi_cfg1 & C_DET_SE) {
13042 /* TERM_SE_HI: on, TERM_SE_LO: on */
13043 case 0x1:
13044 case 0x2:
13045 case 0x3:
13046 asc_dvc->cfg->termination |= TERM_SE;
13047 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013048
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013049 /* TERM_SE_HI: on, TERM_SE_LO: off */
13050 case 0x0:
13051 asc_dvc->cfg->termination |= TERM_SE_HI;
13052 break;
13053 }
13054 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013055
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013056 if ((asc_dvc->cfg->termination & TERM_LVD) == 0) {
13057 /* LVD automatic termination control is enabled. */
13058 switch (scsi_cfg1 & C_DET_LVD) {
13059 /* TERM_LVD_HI: on, TERM_LVD_LO: on */
13060 case 0x4:
13061 case 0x8:
13062 case 0xC:
13063 asc_dvc->cfg->termination |= TERM_LVD;
13064 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013065
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013066 /* TERM_LVD_HI: off, TERM_LVD_LO: off */
13067 case 0x0:
13068 break;
13069 }
13070 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013071
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013072 /*
13073 * Clear any set TERM_SE and TERM_LVD bits.
13074 */
13075 scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013076
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013077 /*
13078 * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
13079 */
13080 scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013081
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013082 /*
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060013083 * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE
13084 * bits and set possibly modified termination control bits in the
13085 * Microcode SCSI_CFG1 Register Value.
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013086 */
13087 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013088
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013089 /*
13090 * Set SCSI_CFG1 Microcode Default Value
13091 *
13092 * Set possibly modified termination control and reset DIS_TERM_DRV
13093 * bits in the Microcode SCSI_CFG1 Register Value.
13094 *
13095 * The microcode will set the SCSI_CFG1 register using this value
13096 * after it is started below.
13097 */
13098 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013099
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013100 /*
13101 * Set MEM_CFG Microcode Default Value
13102 *
13103 * The microcode will set the MEM_CFG register using this value
13104 * after it is started below.
13105 *
13106 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
13107 * are defined.
13108 *
13109 * ASC-38C0800 has 16KB internal memory.
13110 */
13111 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
13112 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013113
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013114 /*
13115 * Set SEL_MASK Microcode Default Value
13116 *
13117 * The microcode will set the SEL_MASK register using this value
13118 * after it is started below.
13119 */
13120 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
13121 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013122
Matthew Wilcoxa9f4a592007-09-09 08:56:27 -060013123 AdvBuildCarrierFreelist(asc_dvc);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013124
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013125 /*
13126 * Set-up the Host->RISC Initiator Command Queue (ICQ).
13127 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013128
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013129 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
13130 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
13131 return ADV_ERROR;
13132 }
13133 asc_dvc->carr_freelist = (ADV_CARR_T *)
13134 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013135
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013136 /*
13137 * The first command issued will be placed in the stopper carrier.
13138 */
13139 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013140
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013141 /*
13142 * Set RISC ICQ physical address start value.
13143 * carr_pa is LE, must be native before write
13144 */
13145 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013146
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013147 /*
13148 * Set-up the RISC->Host Initiator Response Queue (IRQ).
13149 */
13150 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
13151 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
13152 return ADV_ERROR;
13153 }
13154 asc_dvc->carr_freelist = (ADV_CARR_T *)
13155 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013156
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013157 /*
13158 * The first command completed by the RISC will be placed in
13159 * the stopper.
13160 *
13161 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
13162 * completed the RISC will set the ASC_RQ_STOPPER bit.
13163 */
13164 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013165
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013166 /*
13167 * Set RISC IRQ physical address start value.
13168 *
13169 * carr_pa is LE, must be native before write *
13170 */
13171 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
13172 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013173
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013174 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
13175 (ADV_INTR_ENABLE_HOST_INTR |
13176 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013177
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013178 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
13179 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013180
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013181 /* finally, finally, gentlemen, start your engine */
13182 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013183
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013184 /*
13185 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
13186 * Resets should be performed. The RISC has to be running
13187 * to issue a SCSI Bus Reset.
13188 */
13189 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
13190 /*
13191 * If the BIOS Signature is present in memory, restore the
13192 * BIOS Handshake Configuration Table and do not perform
13193 * a SCSI Bus Reset.
13194 */
13195 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
13196 0x55AA) {
13197 /*
13198 * Restore per TID negotiated values.
13199 */
13200 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
13201 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
13202 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
13203 tagqng_able);
13204 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
13205 AdvWriteByteLram(iop_base,
13206 ASC_MC_NUMBER_OF_MAX_CMD + tid,
13207 max_cmd[tid]);
13208 }
13209 } else {
13210 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
13211 warn_code = ASC_WARN_BUSRESET_ERROR;
13212 }
13213 }
13214 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013215
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013216 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013217}
13218
13219/*
13220 * Initialize the ASC-38C1600.
13221 *
13222 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
13223 *
13224 * For a non-fatal error return a warning code. If there are no warnings
13225 * then 0 is returned.
13226 *
13227 * Needed after initialization for error recovery.
13228 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013229static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013230{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013231 AdvPortAddr iop_base;
13232 ushort warn_code;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013233 int begin_addr;
13234 int end_addr;
13235 ushort code_sum;
13236 long word;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013237 int i;
13238 ushort scsi_cfg1;
13239 uchar byte;
13240 uchar tid;
13241 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
13242 ushort wdtr_able, sdtr_able, ppr_able, tagqng_able;
13243 uchar max_cmd[ASC_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070013244
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013245 /* If there is already an error, don't continue. */
13246 if (asc_dvc->err_code != 0) {
13247 return ADV_ERROR;
13248 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013249
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013250 /*
13251 * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600.
13252 */
13253 if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
13254 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
13255 return ADV_ERROR;
13256 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013257
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013258 warn_code = 0;
13259 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013260
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013261 /*
13262 * Save the RISC memory BIOS region before writing the microcode.
13263 * The BIOS may already be loaded and using its RISC LRAM region
13264 * so its region must be saved and restored.
13265 *
13266 * Note: This code makes the assumption, which is currently true,
13267 * that a chip reset does not clear RISC LRAM.
13268 */
13269 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
13270 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
13271 bios_mem[i]);
13272 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013273
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013274 /*
13275 * Save current per TID negotiated values.
13276 */
13277 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
13278 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
13279 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
13280 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
13281 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
13282 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
13283 max_cmd[tid]);
13284 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013285
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013286 /*
13287 * RAM BIST (Built-In Self Test)
13288 *
13289 * Address : I/O base + offset 0x38h register (byte).
13290 * Function: Bit 7-6(RW) : RAM mode
13291 * Normal Mode : 0x00
13292 * Pre-test Mode : 0x40
13293 * RAM Test Mode : 0x80
13294 * Bit 5 : unused
13295 * Bit 4(RO) : Done bit
13296 * Bit 3-0(RO) : Status
13297 * Host Error : 0x08
13298 * Int_RAM Error : 0x04
13299 * RISC Error : 0x02
13300 * SCSI Error : 0x01
13301 * No Error : 0x00
13302 *
13303 * Note: RAM BIST code should be put right here, before loading the
13304 * microcode and after saving the RISC memory BIOS region.
13305 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013306
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013307 /*
13308 * LRAM Pre-test
13309 *
13310 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
13311 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
13312 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
13313 * to NORMAL_MODE, return an error too.
13314 */
13315 for (i = 0; i < 2; i++) {
13316 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
13317 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
13318 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
13319 if ((byte & RAM_TEST_DONE) == 0
13320 || (byte & 0x0F) != PRE_TEST_VALUE) {
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060013321 asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013322 return ADV_ERROR;
13323 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013324
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013325 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
13326 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
13327 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
13328 != NORMAL_VALUE) {
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060013329 asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013330 return ADV_ERROR;
13331 }
13332 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013333
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013334 /*
13335 * LRAM Test - It takes about 1.5 ms to run through the test.
13336 *
13337 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
13338 * If Done bit not set or Status not 0, save register byte, set the
13339 * err_code, and return an error.
13340 */
13341 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
13342 DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013343
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013344 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
13345 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
13346 /* Get here if Done bit not set or Status not 0. */
13347 asc_dvc->bist_err_code = byte; /* for BIOS display message */
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060013348 asc_dvc->err_code = ASC_IERR_BIST_RAM_TEST;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013349 return ADV_ERROR;
13350 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013351
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013352 /* We need to reset back to normal mode after LRAM test passes. */
13353 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013354
Matthew Wilcoxb9d96612007-09-09 08:56:28 -060013355 asc_dvc->err_code = AdvLoadMicrocode(iop_base, _adv_asc38C1600_buf,
13356 _adv_asc38C1600_size, ADV_38C1600_MEMSIZE,
13357 _adv_asc38C1600_chksum);
13358 if (asc_dvc->err_code)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013359 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013360
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013361 /*
13362 * Restore the RISC memory BIOS region.
13363 */
13364 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
13365 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
13366 bios_mem[i]);
13367 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013368
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013369 /*
13370 * Calculate and write the microcode code checksum to the microcode
13371 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
13372 */
13373 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
13374 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
13375 code_sum = 0;
13376 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
13377 for (word = begin_addr; word < end_addr; word += 2) {
13378 code_sum += AdvReadWordAutoIncLram(iop_base);
13379 }
13380 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013381
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013382 /*
13383 * Read microcode version and date.
13384 */
13385 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
13386 asc_dvc->cfg->mcode_date);
13387 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
13388 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013389
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013390 /*
13391 * Set the chip type to indicate the ASC38C1600.
13392 */
13393 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013394
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013395 /*
13396 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
13397 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
13398 * cable detection and then we are able to read C_DET[3:0].
13399 *
13400 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
13401 * Microcode Default Value' section below.
13402 */
13403 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
13404 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
13405 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013406
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013407 /*
13408 * If the PCI Configuration Command Register "Parity Error Response
13409 * Control" Bit was clear (0), then set the microcode variable
13410 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
13411 * to ignore DMA parity errors.
13412 */
13413 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
13414 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
13415 word |= CONTROL_FLAG_IGNORE_PERR;
13416 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
13417 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013418
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013419 /*
13420 * If the BIOS control flag AIPP (Asynchronous Information
13421 * Phase Protection) disable bit is not set, then set the firmware
13422 * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable
13423 * AIPP checking and encoding.
13424 */
13425 if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) {
13426 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
13427 word |= CONTROL_FLAG_ENABLE_AIPP;
13428 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
13429 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013430
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013431 /*
13432 * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4],
13433 * and START_CTL_TH [3:2].
13434 */
13435 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
13436 FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013437
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013438 /*
13439 * Microcode operating variables for WDTR, SDTR, and command tag
Matthew Wilcox47d853c2007-07-26 11:41:33 -040013440 * queuing will be set in slave_configure() based on what a
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013441 * device reports it is capable of in Inquiry byte 7.
13442 *
13443 * If SCSI Bus Resets have been disabled, then directly set
13444 * SDTR and WDTR from the EEPROM configuration. This will allow
13445 * the BIOS and warm boot to work without a SCSI bus hang on
13446 * the Inquiry caused by host and target mismatched DTR values.
13447 * Without the SCSI Bus Reset, before an Inquiry a device can't
13448 * be assumed to be in Asynchronous, Narrow mode.
13449 */
13450 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
13451 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
13452 asc_dvc->wdtr_able);
13453 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
13454 asc_dvc->sdtr_able);
13455 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013456
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013457 /*
13458 * Set microcode operating variables for DISC and SDTR_SPEED1,
13459 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
13460 * configuration values.
13461 *
13462 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
13463 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
13464 * without determining here whether the device supports SDTR.
13465 */
13466 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
13467 asc_dvc->cfg->disc_enable);
13468 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
13469 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
13470 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
13471 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013472
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013473 /*
13474 * Set SCSI_CFG0 Microcode Default Value.
13475 *
13476 * The microcode will set the SCSI_CFG0 register using this value
13477 * after it is started below.
13478 */
13479 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
13480 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
13481 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013482
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013483 /*
13484 * Calculate SCSI_CFG1 Microcode Default Value.
13485 *
13486 * The microcode will set the SCSI_CFG1 register using this value
13487 * after it is started below.
13488 *
13489 * Each ASC-38C1600 function has only two cable detect bits.
13490 * The bus mode override bits are in IOPB_SOFT_OVER_WR.
13491 */
13492 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013493
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013494 /*
13495 * If the cable is reversed all of the SCSI_CTRL register signals
13496 * will be set. Check for and return an error if this condition is
13497 * found.
13498 */
13499 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
13500 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
13501 return ADV_ERROR;
13502 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013503
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013504 /*
13505 * Each ASC-38C1600 function has two connectors. Only an HVD device
13506 * can not be connected to either connector. An LVD device or SE device
13507 * may be connected to either connecor. If an SE device is connected,
13508 * then at most Ultra speed (20 Mhz) can be used on both connectors.
13509 *
13510 * If an HVD device is attached, return an error.
13511 */
13512 if (scsi_cfg1 & HVD) {
13513 asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
13514 return ADV_ERROR;
13515 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013516
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013517 /*
13518 * Each function in the ASC-38C1600 uses only the SE cable detect and
13519 * termination because there are two connectors for each function. Each
13520 * function may use either LVD or SE mode. Corresponding the SE automatic
13521 * termination control EEPROM bits are used for each function. Each
13522 * function has its own EEPROM. If SE automatic control is enabled for
13523 * the function, then set the termination value based on a table listed
13524 * in a_condor.h.
13525 *
13526 * If manual termination is specified in the EEPROM for the function,
13527 * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is
13528 * ready to be 'ored' into SCSI_CFG1.
13529 */
13530 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
Matthew Wilcox13ac2d92007-07-30 08:10:23 -060013531 struct pci_dev *pdev = adv_dvc_to_pdev(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013532 /* SE automatic termination control is enabled. */
13533 switch (scsi_cfg1 & C_DET_SE) {
13534 /* TERM_SE_HI: on, TERM_SE_LO: on */
13535 case 0x1:
13536 case 0x2:
13537 case 0x3:
13538 asc_dvc->cfg->termination |= TERM_SE;
13539 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013540
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013541 case 0x0:
Matthew Wilcox13ac2d92007-07-30 08:10:23 -060013542 if (PCI_FUNC(pdev->devfn) == 0) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013543 /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */
13544 } else {
13545 /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */
13546 asc_dvc->cfg->termination |= TERM_SE_HI;
13547 }
13548 break;
13549 }
13550 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013551
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013552 /*
13553 * Clear any set TERM_SE bits.
13554 */
13555 scsi_cfg1 &= ~TERM_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013556
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013557 /*
13558 * Invert the TERM_SE bits and then set 'scsi_cfg1'.
13559 */
13560 scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013561
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013562 /*
13563 * Clear Big Endian and Terminator Polarity bits and set possibly
13564 * modified termination control bits in the Microcode SCSI_CFG1
13565 * Register Value.
13566 *
13567 * Big Endian bit is not used even on big endian machines.
13568 */
13569 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013570
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013571 /*
13572 * Set SCSI_CFG1 Microcode Default Value
13573 *
13574 * Set possibly modified termination control bits in the Microcode
13575 * SCSI_CFG1 Register Value.
13576 *
13577 * The microcode will set the SCSI_CFG1 register using this value
13578 * after it is started below.
13579 */
13580 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013581
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013582 /*
13583 * Set MEM_CFG Microcode Default Value
13584 *
13585 * The microcode will set the MEM_CFG register using this value
13586 * after it is started below.
13587 *
13588 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
13589 * are defined.
13590 *
13591 * ASC-38C1600 has 32KB internal memory.
13592 *
13593 * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come
13594 * out a special 16K Adv Library and Microcode version. After the issue
13595 * resolved, we should turn back to the 32K support. Both a_condor.h and
13596 * mcode.sas files also need to be updated.
13597 *
13598 * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
13599 * BIOS_EN | RAM_SZ_32KB);
13600 */
13601 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
13602 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013603
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013604 /*
13605 * Set SEL_MASK Microcode Default Value
13606 *
13607 * The microcode will set the SEL_MASK register using this value
13608 * after it is started below.
13609 */
13610 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
13611 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013612
Matthew Wilcoxa9f4a592007-09-09 08:56:27 -060013613 AdvBuildCarrierFreelist(asc_dvc);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013614
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013615 /*
13616 * Set-up the Host->RISC Initiator Command Queue (ICQ).
13617 */
13618 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
13619 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
13620 return ADV_ERROR;
13621 }
13622 asc_dvc->carr_freelist = (ADV_CARR_T *)
13623 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013624
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013625 /*
13626 * The first command issued will be placed in the stopper carrier.
13627 */
13628 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013629
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013630 /*
13631 * Set RISC ICQ physical address start value. Initialize the
13632 * COMMA register to the same value otherwise the RISC will
13633 * prematurely detect a command is available.
13634 */
13635 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
13636 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
13637 le32_to_cpu(asc_dvc->icq_sp->carr_pa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013638
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013639 /*
13640 * Set-up the RISC->Host Initiator Response Queue (IRQ).
13641 */
13642 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
13643 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
13644 return ADV_ERROR;
13645 }
13646 asc_dvc->carr_freelist = (ADV_CARR_T *)
13647 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013648
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013649 /*
13650 * The first command completed by the RISC will be placed in
13651 * the stopper.
13652 *
13653 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
13654 * completed the RISC will set the ASC_RQ_STOPPER bit.
13655 */
13656 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013657
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013658 /*
13659 * Set RISC IRQ physical address start value.
13660 */
13661 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
13662 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013663
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013664 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
13665 (ADV_INTR_ENABLE_HOST_INTR |
13666 ADV_INTR_ENABLE_GLOBAL_INTR));
13667 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
13668 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013669
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013670 /* finally, finally, gentlemen, start your engine */
13671 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013672
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013673 /*
13674 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
13675 * Resets should be performed. The RISC has to be running
13676 * to issue a SCSI Bus Reset.
13677 */
13678 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
13679 /*
13680 * If the BIOS Signature is present in memory, restore the
13681 * per TID microcode operating variables.
13682 */
13683 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
13684 0x55AA) {
13685 /*
13686 * Restore per TID negotiated values.
13687 */
13688 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
13689 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
13690 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
13691 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
13692 tagqng_able);
13693 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
13694 AdvWriteByteLram(iop_base,
13695 ASC_MC_NUMBER_OF_MAX_CMD + tid,
13696 max_cmd[tid]);
13697 }
13698 } else {
13699 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
13700 warn_code = ASC_WARN_BUSRESET_ERROR;
13701 }
13702 }
13703 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013704
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013705 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013706}
13707
13708/*
13709 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
13710 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
13711 * all of this is done.
13712 *
13713 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
13714 *
13715 * For a non-fatal error return a warning code. If there are no warnings
13716 * then 0 is returned.
13717 *
13718 * Note: Chip is stopped on entry.
13719 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013720static int __devinit AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013721{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013722 AdvPortAddr iop_base;
13723 ushort warn_code;
13724 ADVEEP_3550_CONFIG eep_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013725
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013726 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013727
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013728 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013729
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013730 /*
13731 * Read the board's EEPROM configuration.
13732 *
13733 * Set default values if a bad checksum is found.
13734 */
13735 if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum) {
13736 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013737
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013738 /*
13739 * Set EEPROM default values.
13740 */
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040013741 memcpy(&eep_config, &Default_3550_EEPROM_Config,
13742 sizeof(ADVEEP_3550_CONFIG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013743
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013744 /*
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040013745 * Assume the 6 byte board serial number that was read from
13746 * EEPROM is correct even if the EEPROM checksum failed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013747 */
13748 eep_config.serial_number_word3 =
13749 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013750
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013751 eep_config.serial_number_word2 =
13752 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013753
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013754 eep_config.serial_number_word1 =
13755 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013756
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013757 AdvSet3550EEPConfig(iop_base, &eep_config);
13758 }
13759 /*
13760 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
13761 * EEPROM configuration that was read.
13762 *
13763 * This is the mapping of EEPROM fields to Adv Library fields.
13764 */
13765 asc_dvc->wdtr_able = eep_config.wdtr_able;
13766 asc_dvc->sdtr_able = eep_config.sdtr_able;
13767 asc_dvc->ultra_able = eep_config.ultra_able;
13768 asc_dvc->tagqng_able = eep_config.tagqng_able;
13769 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
13770 asc_dvc->max_host_qng = eep_config.max_host_qng;
13771 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
13772 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
13773 asc_dvc->start_motor = eep_config.start_motor;
13774 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
13775 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
13776 asc_dvc->no_scam = eep_config.scam_tolerant;
13777 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
13778 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
13779 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013780
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013781 /*
13782 * Set the host maximum queuing (max. 253, min. 16) and the per device
13783 * maximum queuing (max. 63, min. 4).
13784 */
13785 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
13786 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
13787 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
13788 /* If the value is zero, assume it is uninitialized. */
13789 if (eep_config.max_host_qng == 0) {
13790 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
13791 } else {
13792 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
13793 }
13794 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013795
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013796 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
13797 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
13798 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
13799 /* If the value is zero, assume it is uninitialized. */
13800 if (eep_config.max_dvc_qng == 0) {
13801 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
13802 } else {
13803 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
13804 }
13805 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013806
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013807 /*
13808 * If 'max_dvc_qng' is greater than 'max_host_qng', then
13809 * set 'max_dvc_qng' to 'max_host_qng'.
13810 */
13811 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
13812 eep_config.max_dvc_qng = eep_config.max_host_qng;
13813 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013814
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013815 /*
13816 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
13817 * values based on possibly adjusted EEPROM values.
13818 */
13819 asc_dvc->max_host_qng = eep_config.max_host_qng;
13820 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013821
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013822 /*
13823 * If the EEPROM 'termination' field is set to automatic (0), then set
13824 * the ADV_DVC_CFG 'termination' field to automatic also.
13825 *
13826 * If the termination is specified with a non-zero 'termination'
13827 * value check that a legal value is set and set the ADV_DVC_CFG
13828 * 'termination' field appropriately.
13829 */
13830 if (eep_config.termination == 0) {
13831 asc_dvc->cfg->termination = 0; /* auto termination */
13832 } else {
13833 /* Enable manual control with low off / high off. */
13834 if (eep_config.termination == 1) {
13835 asc_dvc->cfg->termination = TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013836
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013837 /* Enable manual control with low off / high on. */
13838 } else if (eep_config.termination == 2) {
13839 asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013840
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013841 /* Enable manual control with low on / high on. */
13842 } else if (eep_config.termination == 3) {
13843 asc_dvc->cfg->termination =
13844 TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L;
13845 } else {
13846 /*
13847 * The EEPROM 'termination' field contains a bad value. Use
13848 * automatic termination instead.
13849 */
13850 asc_dvc->cfg->termination = 0;
13851 warn_code |= ASC_WARN_EEPROM_TERMINATION;
13852 }
13853 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013854
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013855 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013856}
13857
13858/*
13859 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
13860 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
13861 * all of this is done.
13862 *
13863 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
13864 *
13865 * For a non-fatal error return a warning code. If there are no warnings
13866 * then 0 is returned.
13867 *
13868 * Note: Chip is stopped on entry.
13869 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013870static int __devinit AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013871{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013872 AdvPortAddr iop_base;
13873 ushort warn_code;
13874 ADVEEP_38C0800_CONFIG eep_config;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013875 uchar tid, termination;
13876 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013877
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013878 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013879
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013880 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013881
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013882 /*
13883 * Read the board's EEPROM configuration.
13884 *
13885 * Set default values if a bad checksum is found.
13886 */
13887 if (AdvGet38C0800EEPConfig(iop_base, &eep_config) !=
13888 eep_config.check_sum) {
13889 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013890
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013891 /*
13892 * Set EEPROM default values.
13893 */
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040013894 memcpy(&eep_config, &Default_38C0800_EEPROM_Config,
13895 sizeof(ADVEEP_38C0800_CONFIG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070013896
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013897 /*
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040013898 * Assume the 6 byte board serial number that was read from
13899 * EEPROM is correct even if the EEPROM checksum failed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013900 */
13901 eep_config.serial_number_word3 =
13902 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013903
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013904 eep_config.serial_number_word2 =
13905 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013906
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013907 eep_config.serial_number_word1 =
13908 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013909
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013910 AdvSet38C0800EEPConfig(iop_base, &eep_config);
13911 }
13912 /*
13913 * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
13914 * EEPROM configuration that was read.
13915 *
13916 * This is the mapping of EEPROM fields to Adv Library fields.
13917 */
13918 asc_dvc->wdtr_able = eep_config.wdtr_able;
13919 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
13920 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
13921 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
13922 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
13923 asc_dvc->tagqng_able = eep_config.tagqng_able;
13924 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
13925 asc_dvc->max_host_qng = eep_config.max_host_qng;
13926 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
13927 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
13928 asc_dvc->start_motor = eep_config.start_motor;
13929 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
13930 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
13931 asc_dvc->no_scam = eep_config.scam_tolerant;
13932 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
13933 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
13934 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013935
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013936 /*
13937 * For every Target ID if any of its 'sdtr_speed[1234]' bits
13938 * are set, then set an 'sdtr_able' bit for it.
13939 */
13940 asc_dvc->sdtr_able = 0;
13941 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
13942 if (tid == 0) {
13943 sdtr_speed = asc_dvc->sdtr_speed1;
13944 } else if (tid == 4) {
13945 sdtr_speed = asc_dvc->sdtr_speed2;
13946 } else if (tid == 8) {
13947 sdtr_speed = asc_dvc->sdtr_speed3;
13948 } else if (tid == 12) {
13949 sdtr_speed = asc_dvc->sdtr_speed4;
13950 }
13951 if (sdtr_speed & ADV_MAX_TID) {
13952 asc_dvc->sdtr_able |= (1 << tid);
13953 }
13954 sdtr_speed >>= 4;
13955 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013956
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013957 /*
13958 * Set the host maximum queuing (max. 253, min. 16) and the per device
13959 * maximum queuing (max. 63, min. 4).
13960 */
13961 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
13962 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
13963 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
13964 /* If the value is zero, assume it is uninitialized. */
13965 if (eep_config.max_host_qng == 0) {
13966 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
13967 } else {
13968 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
13969 }
13970 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013971
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013972 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
13973 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
13974 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
13975 /* If the value is zero, assume it is uninitialized. */
13976 if (eep_config.max_dvc_qng == 0) {
13977 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
13978 } else {
13979 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
13980 }
13981 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013982
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013983 /*
13984 * If 'max_dvc_qng' is greater than 'max_host_qng', then
13985 * set 'max_dvc_qng' to 'max_host_qng'.
13986 */
13987 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
13988 eep_config.max_dvc_qng = eep_config.max_host_qng;
13989 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013990
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013991 /*
13992 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
13993 * values based on possibly adjusted EEPROM values.
13994 */
13995 asc_dvc->max_host_qng = eep_config.max_host_qng;
13996 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013997
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013998 /*
13999 * If the EEPROM 'termination' field is set to automatic (0), then set
14000 * the ADV_DVC_CFG 'termination' field to automatic also.
14001 *
14002 * If the termination is specified with a non-zero 'termination'
14003 * value check that a legal value is set and set the ADV_DVC_CFG
14004 * 'termination' field appropriately.
14005 */
14006 if (eep_config.termination_se == 0) {
14007 termination = 0; /* auto termination for SE */
14008 } else {
14009 /* Enable manual control with low off / high off. */
14010 if (eep_config.termination_se == 1) {
14011 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014012
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014013 /* Enable manual control with low off / high on. */
14014 } else if (eep_config.termination_se == 2) {
14015 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014016
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014017 /* Enable manual control with low on / high on. */
14018 } else if (eep_config.termination_se == 3) {
14019 termination = TERM_SE;
14020 } else {
14021 /*
14022 * The EEPROM 'termination_se' field contains a bad value.
14023 * Use automatic termination instead.
14024 */
14025 termination = 0;
14026 warn_code |= ASC_WARN_EEPROM_TERMINATION;
14027 }
14028 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014029
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014030 if (eep_config.termination_lvd == 0) {
14031 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
14032 } else {
14033 /* Enable manual control with low off / high off. */
14034 if (eep_config.termination_lvd == 1) {
14035 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014036
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014037 /* Enable manual control with low off / high on. */
14038 } else if (eep_config.termination_lvd == 2) {
14039 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014040
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014041 /* Enable manual control with low on / high on. */
14042 } else if (eep_config.termination_lvd == 3) {
14043 asc_dvc->cfg->termination = termination | TERM_LVD;
14044 } else {
14045 /*
14046 * The EEPROM 'termination_lvd' field contains a bad value.
14047 * Use automatic termination instead.
14048 */
14049 asc_dvc->cfg->termination = termination;
14050 warn_code |= ASC_WARN_EEPROM_TERMINATION;
14051 }
14052 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014053
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014054 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014055}
14056
14057/*
14058 * Read the board's EEPROM configuration. Set fields in ASC_DVC_VAR and
14059 * ASC_DVC_CFG based on the EEPROM settings. The chip is stopped while
14060 * all of this is done.
14061 *
14062 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
14063 *
14064 * For a non-fatal error return a warning code. If there are no warnings
14065 * then 0 is returned.
14066 *
14067 * Note: Chip is stopped on entry.
14068 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060014069static int __devinit AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014070{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014071 AdvPortAddr iop_base;
14072 ushort warn_code;
14073 ADVEEP_38C1600_CONFIG eep_config;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014074 uchar tid, termination;
14075 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014076
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014077 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014078
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014079 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014080
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014081 /*
14082 * Read the board's EEPROM configuration.
14083 *
14084 * Set default values if a bad checksum is found.
14085 */
14086 if (AdvGet38C1600EEPConfig(iop_base, &eep_config) !=
14087 eep_config.check_sum) {
Matthew Wilcox13ac2d92007-07-30 08:10:23 -060014088 struct pci_dev *pdev = adv_dvc_to_pdev(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014089 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014090
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014091 /*
14092 * Set EEPROM default values.
14093 */
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040014094 memcpy(&eep_config, &Default_38C1600_EEPROM_Config,
14095 sizeof(ADVEEP_38C1600_CONFIG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014096
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040014097 if (PCI_FUNC(pdev->devfn) != 0) {
14098 u8 ints;
14099 /*
14100 * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60
14101 * and old Mac system booting problem. The Expansion
14102 * ROM must be disabled in Function 1 for these systems
14103 */
14104 eep_config.cfg_lsw &= ~ADV_EEPROM_BIOS_ENABLE;
14105 /*
14106 * Clear the INTAB (bit 11) if the GPIO 0 input
14107 * indicates the Function 1 interrupt line is wired
14108 * to INTB.
14109 *
14110 * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input:
14111 * 1 - Function 1 interrupt line wired to INT A.
14112 * 0 - Function 1 interrupt line wired to INT B.
14113 *
14114 * Note: Function 0 is always wired to INTA.
14115 * Put all 5 GPIO bits in input mode and then read
14116 * their input values.
14117 */
14118 AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL, 0);
14119 ints = AdvReadByteRegister(iop_base, IOPB_GPIO_DATA);
14120 if ((ints & 0x01) == 0)
14121 eep_config.cfg_lsw &= ~ADV_EEPROM_INTAB;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014122 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014123
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014124 /*
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040014125 * Assume the 6 byte board serial number that was read from
14126 * EEPROM is correct even if the EEPROM checksum failed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014127 */
14128 eep_config.serial_number_word3 =
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040014129 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014130 eep_config.serial_number_word2 =
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040014131 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014132 eep_config.serial_number_word1 =
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040014133 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014134
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014135 AdvSet38C1600EEPConfig(iop_base, &eep_config);
14136 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014137
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014138 /*
14139 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
14140 * EEPROM configuration that was read.
14141 *
14142 * This is the mapping of EEPROM fields to Adv Library fields.
14143 */
14144 asc_dvc->wdtr_able = eep_config.wdtr_able;
14145 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
14146 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
14147 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
14148 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
14149 asc_dvc->ppr_able = 0;
14150 asc_dvc->tagqng_able = eep_config.tagqng_able;
14151 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
14152 asc_dvc->max_host_qng = eep_config.max_host_qng;
14153 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
14154 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ASC_MAX_TID);
14155 asc_dvc->start_motor = eep_config.start_motor;
14156 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
14157 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
14158 asc_dvc->no_scam = eep_config.scam_tolerant;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014159
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014160 /*
14161 * For every Target ID if any of its 'sdtr_speed[1234]' bits
14162 * are set, then set an 'sdtr_able' bit for it.
14163 */
14164 asc_dvc->sdtr_able = 0;
14165 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
14166 if (tid == 0) {
14167 sdtr_speed = asc_dvc->sdtr_speed1;
14168 } else if (tid == 4) {
14169 sdtr_speed = asc_dvc->sdtr_speed2;
14170 } else if (tid == 8) {
14171 sdtr_speed = asc_dvc->sdtr_speed3;
14172 } else if (tid == 12) {
14173 sdtr_speed = asc_dvc->sdtr_speed4;
14174 }
14175 if (sdtr_speed & ASC_MAX_TID) {
14176 asc_dvc->sdtr_able |= (1 << tid);
14177 }
14178 sdtr_speed >>= 4;
14179 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014180
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014181 /*
14182 * Set the host maximum queuing (max. 253, min. 16) and the per device
14183 * maximum queuing (max. 63, min. 4).
14184 */
14185 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
14186 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
14187 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
14188 /* If the value is zero, assume it is uninitialized. */
14189 if (eep_config.max_host_qng == 0) {
14190 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
14191 } else {
14192 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
14193 }
14194 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014195
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014196 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
14197 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
14198 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
14199 /* If the value is zero, assume it is uninitialized. */
14200 if (eep_config.max_dvc_qng == 0) {
14201 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
14202 } else {
14203 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
14204 }
14205 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014206
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014207 /*
14208 * If 'max_dvc_qng' is greater than 'max_host_qng', then
14209 * set 'max_dvc_qng' to 'max_host_qng'.
14210 */
14211 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
14212 eep_config.max_dvc_qng = eep_config.max_host_qng;
14213 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014214
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014215 /*
14216 * Set ASC_DVC_VAR 'max_host_qng' and ASC_DVC_VAR 'max_dvc_qng'
14217 * values based on possibly adjusted EEPROM values.
14218 */
14219 asc_dvc->max_host_qng = eep_config.max_host_qng;
14220 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014221
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014222 /*
14223 * If the EEPROM 'termination' field is set to automatic (0), then set
14224 * the ASC_DVC_CFG 'termination' field to automatic also.
14225 *
14226 * If the termination is specified with a non-zero 'termination'
14227 * value check that a legal value is set and set the ASC_DVC_CFG
14228 * 'termination' field appropriately.
14229 */
14230 if (eep_config.termination_se == 0) {
14231 termination = 0; /* auto termination for SE */
14232 } else {
14233 /* Enable manual control with low off / high off. */
14234 if (eep_config.termination_se == 1) {
14235 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014236
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014237 /* Enable manual control with low off / high on. */
14238 } else if (eep_config.termination_se == 2) {
14239 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014240
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014241 /* Enable manual control with low on / high on. */
14242 } else if (eep_config.termination_se == 3) {
14243 termination = TERM_SE;
14244 } else {
14245 /*
14246 * The EEPROM 'termination_se' field contains a bad value.
14247 * Use automatic termination instead.
14248 */
14249 termination = 0;
14250 warn_code |= ASC_WARN_EEPROM_TERMINATION;
14251 }
14252 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014253
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014254 if (eep_config.termination_lvd == 0) {
14255 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
14256 } else {
14257 /* Enable manual control with low off / high off. */
14258 if (eep_config.termination_lvd == 1) {
14259 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014260
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014261 /* Enable manual control with low off / high on. */
14262 } else if (eep_config.termination_lvd == 2) {
14263 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014264
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014265 /* Enable manual control with low on / high on. */
14266 } else if (eep_config.termination_lvd == 3) {
14267 asc_dvc->cfg->termination = termination | TERM_LVD;
14268 } else {
14269 /*
14270 * The EEPROM 'termination_lvd' field contains a bad value.
14271 * Use automatic termination instead.
14272 */
14273 asc_dvc->cfg->termination = termination;
14274 warn_code |= ASC_WARN_EEPROM_TERMINATION;
14275 }
14276 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014277
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014278 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014279}
14280
14281/*
14282 * Read EEPROM configuration into the specified buffer.
14283 *
14284 * Return a checksum based on the EEPROM configuration read.
14285 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060014286static ushort __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -070014287AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
14288{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014289 ushort wval, chksum;
14290 ushort *wbuf;
14291 int eep_addr;
14292 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014293
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014294 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
14295 wbuf = (ushort *)cfg_buf;
14296 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014297
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014298 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
14299 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
14300 wval = AdvReadEEPWord(iop_base, eep_addr);
14301 chksum += wval; /* Checksum is calculated from word values. */
14302 if (*charfields++) {
14303 *wbuf = le16_to_cpu(wval);
14304 } else {
14305 *wbuf = wval;
14306 }
14307 }
14308 /* Read checksum word. */
14309 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
14310 wbuf++;
14311 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014312
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014313 /* Read rest of EEPROM not covered by the checksum. */
14314 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
14315 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
14316 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
14317 if (*charfields++) {
14318 *wbuf = le16_to_cpu(*wbuf);
14319 }
14320 }
14321 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014322}
14323
14324/*
14325 * Read EEPROM configuration into the specified buffer.
14326 *
14327 * Return a checksum based on the EEPROM configuration read.
14328 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060014329static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014330AdvGet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014331{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014332 ushort wval, chksum;
14333 ushort *wbuf;
14334 int eep_addr;
14335 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014336
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014337 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
14338 wbuf = (ushort *)cfg_buf;
14339 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014340
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014341 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
14342 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
14343 wval = AdvReadEEPWord(iop_base, eep_addr);
14344 chksum += wval; /* Checksum is calculated from word values. */
14345 if (*charfields++) {
14346 *wbuf = le16_to_cpu(wval);
14347 } else {
14348 *wbuf = wval;
14349 }
14350 }
14351 /* Read checksum word. */
14352 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
14353 wbuf++;
14354 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014355
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014356 /* Read rest of EEPROM not covered by the checksum. */
14357 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
14358 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
14359 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
14360 if (*charfields++) {
14361 *wbuf = le16_to_cpu(*wbuf);
14362 }
14363 }
14364 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014365}
14366
14367/*
14368 * Read EEPROM configuration into the specified buffer.
14369 *
14370 * Return a checksum based on the EEPROM configuration read.
14371 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060014372static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014373AdvGet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014374{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014375 ushort wval, chksum;
14376 ushort *wbuf;
14377 int eep_addr;
14378 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014379
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014380 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
14381 wbuf = (ushort *)cfg_buf;
14382 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014383
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014384 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
14385 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
14386 wval = AdvReadEEPWord(iop_base, eep_addr);
14387 chksum += wval; /* Checksum is calculated from word values. */
14388 if (*charfields++) {
14389 *wbuf = le16_to_cpu(wval);
14390 } else {
14391 *wbuf = wval;
14392 }
14393 }
14394 /* Read checksum word. */
14395 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
14396 wbuf++;
14397 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014398
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014399 /* Read rest of EEPROM not covered by the checksum. */
14400 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
14401 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
14402 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
14403 if (*charfields++) {
14404 *wbuf = le16_to_cpu(*wbuf);
14405 }
14406 }
14407 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014408}
14409
14410/*
14411 * Read the EEPROM from specified location
14412 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060014413static ushort __devinit AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014414{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014415 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
14416 ASC_EEP_CMD_READ | eep_word_addr);
14417 AdvWaitEEPCmd(iop_base);
14418 return AdvReadWordRegister(iop_base, IOPW_EE_DATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014419}
14420
14421/*
14422 * Wait for EEPROM command to complete
14423 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060014424static void __devinit AdvWaitEEPCmd(AdvPortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014425{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014426 int eep_delay_ms;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014427
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014428 for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++) {
14429 if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) &
14430 ASC_EEP_CMD_DONE) {
14431 break;
14432 }
14433 DvcSleepMilliSecond(1);
14434 }
14435 if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) ==
14436 0) {
14437 ASC_ASSERT(0);
14438 }
14439 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014440}
14441
14442/*
14443 * Write the EEPROM from 'cfg_buf'.
14444 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060014445void __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -070014446AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
14447{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014448 ushort *wbuf;
14449 ushort addr, chksum;
14450 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014451
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014452 wbuf = (ushort *)cfg_buf;
14453 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
14454 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014455
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014456 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
14457 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014458
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014459 /*
14460 * Write EEPROM from word 0 to word 20.
14461 */
14462 for (addr = ADV_EEP_DVC_CFG_BEGIN;
14463 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
14464 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014465
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014466 if (*charfields++) {
14467 word = cpu_to_le16(*wbuf);
14468 } else {
14469 word = *wbuf;
14470 }
14471 chksum += *wbuf; /* Checksum is calculated from word values. */
14472 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
14473 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
14474 ASC_EEP_CMD_WRITE | addr);
14475 AdvWaitEEPCmd(iop_base);
14476 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
14477 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014478
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014479 /*
14480 * Write EEPROM checksum at word 21.
14481 */
14482 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
14483 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
14484 AdvWaitEEPCmd(iop_base);
14485 wbuf++;
14486 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014487
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014488 /*
14489 * Write EEPROM OEM name at words 22 to 29.
14490 */
14491 for (addr = ADV_EEP_DVC_CTL_BEGIN;
14492 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
14493 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014494
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014495 if (*charfields++) {
14496 word = cpu_to_le16(*wbuf);
14497 } else {
14498 word = *wbuf;
14499 }
14500 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
14501 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
14502 ASC_EEP_CMD_WRITE | addr);
14503 AdvWaitEEPCmd(iop_base);
14504 }
14505 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
14506 AdvWaitEEPCmd(iop_base);
14507 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014508}
14509
14510/*
14511 * Write the EEPROM from 'cfg_buf'.
14512 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060014513void __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014514AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014515{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014516 ushort *wbuf;
14517 ushort *charfields;
14518 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014519
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014520 wbuf = (ushort *)cfg_buf;
14521 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
14522 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014523
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014524 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
14525 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014526
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014527 /*
14528 * Write EEPROM from word 0 to word 20.
14529 */
14530 for (addr = ADV_EEP_DVC_CFG_BEGIN;
14531 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
14532 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014533
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014534 if (*charfields++) {
14535 word = cpu_to_le16(*wbuf);
14536 } else {
14537 word = *wbuf;
14538 }
14539 chksum += *wbuf; /* Checksum is calculated from word values. */
14540 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
14541 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
14542 ASC_EEP_CMD_WRITE | addr);
14543 AdvWaitEEPCmd(iop_base);
14544 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
14545 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014546
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014547 /*
14548 * Write EEPROM checksum at word 21.
14549 */
14550 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
14551 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
14552 AdvWaitEEPCmd(iop_base);
14553 wbuf++;
14554 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014555
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014556 /*
14557 * Write EEPROM OEM name at words 22 to 29.
14558 */
14559 for (addr = ADV_EEP_DVC_CTL_BEGIN;
14560 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
14561 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014562
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014563 if (*charfields++) {
14564 word = cpu_to_le16(*wbuf);
14565 } else {
14566 word = *wbuf;
14567 }
14568 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
14569 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
14570 ASC_EEP_CMD_WRITE | addr);
14571 AdvWaitEEPCmd(iop_base);
14572 }
14573 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
14574 AdvWaitEEPCmd(iop_base);
14575 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014576}
14577
14578/*
14579 * Write the EEPROM from 'cfg_buf'.
14580 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060014581void __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014582AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014583{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014584 ushort *wbuf;
14585 ushort *charfields;
14586 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014587
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014588 wbuf = (ushort *)cfg_buf;
14589 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
14590 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014591
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014592 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
14593 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014594
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014595 /*
14596 * Write EEPROM from word 0 to word 20.
14597 */
14598 for (addr = ADV_EEP_DVC_CFG_BEGIN;
14599 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
14600 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014601
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014602 if (*charfields++) {
14603 word = cpu_to_le16(*wbuf);
14604 } else {
14605 word = *wbuf;
14606 }
14607 chksum += *wbuf; /* Checksum is calculated from word values. */
14608 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
14609 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
14610 ASC_EEP_CMD_WRITE | addr);
14611 AdvWaitEEPCmd(iop_base);
14612 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
14613 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014614
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014615 /*
14616 * Write EEPROM checksum at word 21.
14617 */
14618 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
14619 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
14620 AdvWaitEEPCmd(iop_base);
14621 wbuf++;
14622 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014623
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014624 /*
14625 * Write EEPROM OEM name at words 22 to 29.
14626 */
14627 for (addr = ADV_EEP_DVC_CTL_BEGIN;
14628 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
14629 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014630
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014631 if (*charfields++) {
14632 word = cpu_to_le16(*wbuf);
14633 } else {
14634 word = *wbuf;
14635 }
14636 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
14637 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
14638 ASC_EEP_CMD_WRITE | addr);
14639 AdvWaitEEPCmd(iop_base);
14640 }
14641 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
14642 AdvWaitEEPCmd(iop_base);
14643 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014644}
14645
14646/* a_advlib.c */
14647/*
14648 * AdvExeScsiQueue() - Send a request to the RISC microcode program.
14649 *
14650 * Allocate a carrier structure, point the carrier to the ADV_SCSI_REQ_Q,
14651 * add the carrier to the ICQ (Initiator Command Queue), and tickle the
14652 * RISC to notify it a new command is ready to be executed.
14653 *
14654 * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be
14655 * set to SCSI_MAX_RETRY.
14656 *
14657 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the microcode
14658 * for DMA addresses or math operations are byte swapped to little-endian
14659 * order.
14660 *
14661 * Return:
14662 * ADV_SUCCESS(1) - The request was successfully queued.
14663 * ADV_BUSY(0) - Resource unavailable; Retry again after pending
14664 * request completes.
14665 * ADV_ERROR(-1) - Invalid ADV_SCSI_REQ_Q request structure
14666 * host IC error.
14667 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014668static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014669{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014670 ulong last_int_level;
14671 AdvPortAddr iop_base;
14672 ADV_DCNT req_size;
14673 ADV_PADDR req_paddr;
14674 ADV_CARR_T *new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014675
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014676 ASC_ASSERT(scsiq != NULL); /* 'scsiq' should never be NULL. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014677
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014678 /*
14679 * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
14680 */
14681 if (scsiq->target_id > ADV_MAX_TID) {
14682 scsiq->host_status = QHSTA_M_INVALID_DEVICE;
14683 scsiq->done_status = QD_WITH_ERROR;
14684 return ADV_ERROR;
14685 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014686
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014687 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014688
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014689 last_int_level = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070014690
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014691 /*
14692 * Allocate a carrier ensuring at least one carrier always
14693 * remains on the freelist and initialize fields.
14694 */
14695 if ((new_carrp = asc_dvc->carr_freelist) == NULL) {
14696 DvcLeaveCritical(last_int_level);
14697 return ADV_BUSY;
14698 }
14699 asc_dvc->carr_freelist = (ADV_CARR_T *)
14700 ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa));
14701 asc_dvc->carr_pending_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014702
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014703 /*
14704 * Set the carrier to be a stopper by setting 'next_vpa'
14705 * to the stopper value. The current stopper will be changed
14706 * below to point to the new stopper.
14707 */
14708 new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014709
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014710 /*
14711 * Clear the ADV_SCSI_REQ_Q done flag.
14712 */
14713 scsiq->a_flag &= ~ADV_SCSIQ_DONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014714
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014715 req_size = sizeof(ADV_SCSI_REQ_Q);
14716 req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *)scsiq,
14717 (ADV_SDCNT *)&req_size, ADV_IS_SCSIQ_FLAG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014718
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014719 ASC_ASSERT(ADV_32BALIGN(req_paddr) == req_paddr);
14720 ASC_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014721
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014722 /* Wait for assertion before making little-endian */
14723 req_paddr = cpu_to_le32(req_paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014724
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014725 /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
14726 scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq));
14727 scsiq->scsiq_rptr = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014728
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014729 scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp));
14730 /*
14731 * Every ADV_CARR_T.carr_pa is byte swapped to little-endian
14732 * order during initialization.
14733 */
14734 scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014735
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014736 /*
14737 * Use the current stopper to send the ADV_SCSI_REQ_Q command to
14738 * the microcode. The newly allocated stopper will become the new
14739 * stopper.
14740 */
14741 asc_dvc->icq_sp->areq_vpa = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014742
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014743 /*
14744 * Set the 'next_vpa' pointer for the old stopper to be the
14745 * physical address of the new stopper. The RISC can only
14746 * follow physical addresses.
14747 */
14748 asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014749
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014750 /*
14751 * Set the host adapter stopper pointer to point to the new carrier.
14752 */
14753 asc_dvc->icq_sp = new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014754
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014755 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
14756 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
14757 /*
14758 * Tickle the RISC to tell it to read its Command Queue Head pointer.
14759 */
14760 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
14761 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
14762 /*
14763 * Clear the tickle value. In the ASC-3550 the RISC flag
14764 * command 'clr_tickle_a' does not work unless the host
14765 * value is cleared.
14766 */
14767 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
14768 ADV_TICKLE_NOP);
14769 }
14770 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
14771 /*
14772 * Notify the RISC a carrier is ready by writing the physical
14773 * address of the new carrier stopper to the COMMA register.
14774 */
14775 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
14776 le32_to_cpu(new_carrp->carr_pa));
14777 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014778
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014779 DvcLeaveCritical(last_int_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014780
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014781 return ADV_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014782}
14783
14784/*
14785 * Reset SCSI Bus and purge all outstanding requests.
14786 *
14787 * Return Value:
14788 * ADV_TRUE(1) - All requests are purged and SCSI Bus is reset.
14789 * ADV_FALSE(0) - Microcode command failed.
14790 * ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC
14791 * may be hung which requires driver recovery.
14792 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014793static int AdvResetSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014794{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014795 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014796
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014797 /*
14798 * Send the SCSI Bus Reset idle start idle command which asserts
14799 * the SCSI Bus Reset signal.
14800 */
14801 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_START, 0L);
14802 if (status != ADV_TRUE) {
14803 return status;
14804 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014805
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014806 /*
14807 * Delay for the specified SCSI Bus Reset hold time.
14808 *
14809 * The hold time delay is done on the host because the RISC has no
14810 * microsecond accurate timer.
14811 */
14812 DvcDelayMicroSecond(asc_dvc, (ushort)ASC_SCSI_RESET_HOLD_TIME_US);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014813
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014814 /*
14815 * Send the SCSI Bus Reset end idle command which de-asserts
14816 * the SCSI Bus Reset signal and purges any pending requests.
14817 */
14818 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_END, 0L);
14819 if (status != ADV_TRUE) {
14820 return status;
14821 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014822
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014823 DvcSleepMilliSecond((ADV_DCNT)asc_dvc->scsi_reset_wait * 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014824
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014825 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014826}
14827
14828/*
14829 * Reset chip and SCSI Bus.
14830 *
14831 * Return Value:
14832 * ADV_TRUE(1) - Chip re-initialization and SCSI Bus Reset successful.
14833 * ADV_FALSE(0) - Chip re-initialization and SCSI Bus Reset failure.
14834 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014835static int AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014836{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014837 int status;
14838 ushort wdtr_able, sdtr_able, tagqng_able;
14839 ushort ppr_able = 0;
14840 uchar tid, max_cmd[ADV_MAX_TID + 1];
14841 AdvPortAddr iop_base;
14842 ushort bios_sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014843
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014844 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014845
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014846 /*
14847 * Save current per TID negotiated values.
14848 */
14849 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14850 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14851 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
14852 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
14853 }
14854 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
14855 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14856 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
14857 max_cmd[tid]);
14858 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014859
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014860 /*
14861 * Force the AdvInitAsc3550/38C0800Driver() function to
14862 * perform a SCSI Bus Reset by clearing the BIOS signature word.
14863 * The initialization functions assumes a SCSI Bus Reset is not
14864 * needed if the BIOS signature word is present.
14865 */
14866 AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
14867 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014868
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014869 /*
14870 * Stop chip and reset it.
14871 */
14872 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP);
14873 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
14874 DvcSleepMilliSecond(100);
14875 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
14876 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014877
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014878 /*
14879 * Reset Adv Library error code, if any, and try
14880 * re-initializing the chip.
14881 */
14882 asc_dvc->err_code = 0;
14883 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
14884 status = AdvInitAsc38C1600Driver(asc_dvc);
14885 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
14886 status = AdvInitAsc38C0800Driver(asc_dvc);
14887 } else {
14888 status = AdvInitAsc3550Driver(asc_dvc);
14889 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014890
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014891 /* Translate initialization return value to status value. */
14892 if (status == 0) {
14893 status = ADV_TRUE;
14894 } else {
14895 status = ADV_FALSE;
14896 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014897
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014898 /*
14899 * Restore the BIOS signature word.
14900 */
14901 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014902
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014903 /*
14904 * Restore per TID negotiated values.
14905 */
14906 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14907 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14908 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
14909 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
14910 }
14911 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
14912 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14913 AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
14914 max_cmd[tid]);
14915 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014916
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014917 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014918}
14919
14920/*
14921 * Adv Library Interrupt Service Routine
14922 *
14923 * This function is called by a driver's interrupt service routine.
14924 * The function disables and re-enables interrupts.
14925 *
14926 * When a microcode idle command is completed, the ADV_DVC_VAR
14927 * 'idle_cmd_done' field is set to ADV_TRUE.
14928 *
14929 * Note: AdvISR() can be called when interrupts are disabled or even
14930 * when there is no hardware interrupt condition present. It will
14931 * always check for completed idle commands and microcode requests.
14932 * This is an important feature that shouldn't be changed because it
14933 * allows commands to be completed from polling mode loops.
14934 *
14935 * Return:
14936 * ADV_TRUE(1) - interrupt was pending
14937 * ADV_FALSE(0) - no interrupt was pending
14938 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014939static int AdvISR(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014940{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014941 AdvPortAddr iop_base;
14942 uchar int_stat;
14943 ushort target_bit;
14944 ADV_CARR_T *free_carrp;
14945 ADV_VADDR irq_next_vpa;
14946 int flags;
14947 ADV_SCSI_REQ_Q *scsiq;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014948
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014949 flags = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070014950
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014951 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014952
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014953 /* Reading the register clears the interrupt. */
14954 int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014955
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014956 if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB |
14957 ADV_INTR_STATUS_INTRC)) == 0) {
14958 DvcLeaveCritical(flags);
14959 return ADV_FALSE;
14960 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014961
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014962 /*
14963 * Notify the driver of an asynchronous microcode condition by
Matthew Wilcox895d6b42007-07-26 11:57:06 -040014964 * calling the adv_async_callback function. The function
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014965 * is passed the microcode ASC_MC_INTRB_CODE byte value.
14966 */
14967 if (int_stat & ADV_INTR_STATUS_INTRB) {
14968 uchar intrb_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014969
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014970 AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014971
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014972 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
14973 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
14974 if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
14975 asc_dvc->carr_pending_cnt != 0) {
14976 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
14977 ADV_TICKLE_A);
14978 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
14979 AdvWriteByteRegister(iop_base,
14980 IOPB_TICKLE,
14981 ADV_TICKLE_NOP);
14982 }
14983 }
14984 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014985
Matthew Wilcox895d6b42007-07-26 11:57:06 -040014986 adv_async_callback(asc_dvc, intrb_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014987 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014988
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014989 /*
14990 * Check if the IRQ stopper carrier contains a completed request.
14991 */
14992 while (((irq_next_vpa =
14993 le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0) {
14994 /*
14995 * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
14996 * The RISC will have set 'areq_vpa' to a virtual address.
14997 *
14998 * The firmware will have copied the ASC_SCSI_REQ_Q.scsiq_ptr
14999 * field to the carrier ADV_CARR_T.areq_vpa field. The conversion
15000 * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr'
15001 * in AdvExeScsiQueue().
15002 */
15003 scsiq = (ADV_SCSI_REQ_Q *)
15004 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015005
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015006 /*
15007 * Request finished with good status and the queue was not
15008 * DMAed to host memory by the firmware. Set all status fields
15009 * to indicate good status.
15010 */
15011 if ((irq_next_vpa & ASC_RQ_GOOD) != 0) {
15012 scsiq->done_status = QD_NO_ERROR;
15013 scsiq->host_status = scsiq->scsi_status = 0;
15014 scsiq->data_cnt = 0L;
15015 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015016
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015017 /*
15018 * Advance the stopper pointer to the next carrier
15019 * ignoring the lower four bits. Free the previous
15020 * stopper carrier.
15021 */
15022 free_carrp = asc_dvc->irq_sp;
15023 asc_dvc->irq_sp = (ADV_CARR_T *)
15024 ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015025
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015026 free_carrp->next_vpa =
15027 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
15028 asc_dvc->carr_freelist = free_carrp;
15029 asc_dvc->carr_pending_cnt--;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015030
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015031 ASC_ASSERT(scsiq != NULL);
15032 target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015033
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015034 /*
15035 * Clear request microcode control flag.
15036 */
15037 scsiq->cntl = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015038
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015039 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015040 * Notify the driver of the completed request by passing
15041 * the ADV_SCSI_REQ_Q pointer to its callback function.
15042 */
15043 scsiq->a_flag |= ADV_SCSIQ_DONE;
Matthew Wilcox895d6b42007-07-26 11:57:06 -040015044 adv_isr_callback(asc_dvc, scsiq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015045 /*
15046 * Note: After the driver callback function is called, 'scsiq'
15047 * can no longer be referenced.
15048 *
15049 * Fall through and continue processing other completed
15050 * requests...
15051 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015052
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015053 /*
15054 * Disable interrupts again in case the driver inadvertently
15055 * enabled interrupts in its callback function.
15056 *
15057 * The DvcEnterCritical() return value is ignored, because
15058 * the 'flags' saved when AdvISR() was first entered will be
15059 * used to restore the interrupt flag on exit.
15060 */
15061 (void)DvcEnterCritical();
15062 }
15063 DvcLeaveCritical(flags);
15064 return ADV_TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015065}
15066
15067/*
15068 * Send an idle command to the chip and wait for completion.
15069 *
15070 * Command completion is polled for once per microsecond.
15071 *
15072 * The function can be called from anywhere including an interrupt handler.
15073 * But the function is not re-entrant, so it uses the DvcEnter/LeaveCritical()
15074 * functions to prevent reentrancy.
15075 *
15076 * Return Values:
15077 * ADV_TRUE - command completed successfully
15078 * ADV_FALSE - command failed
15079 * ADV_ERROR - command timed out
15080 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015081static int
Linus Torvalds1da177e2005-04-16 15:20:36 -070015082AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015083 ushort idle_cmd, ADV_DCNT idle_cmd_parameter)
Linus Torvalds1da177e2005-04-16 15:20:36 -070015084{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015085 ulong last_int_level;
15086 int result;
15087 ADV_DCNT i, j;
15088 AdvPortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015089
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015090 last_int_level = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070015091
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015092 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015093
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015094 /*
15095 * Clear the idle command status which is set by the microcode
15096 * to a non-zero value to indicate when the command is completed.
15097 * The non-zero result is one of the IDLE_CMD_STATUS_* values
15098 * defined in a_advlib.h.
15099 */
15100 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort)0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015101
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015102 /*
15103 * Write the idle command value after the idle command parameter
15104 * has been written to avoid a race condition. If the order is not
15105 * followed, the microcode may process the idle command before the
15106 * parameters have been written to LRAM.
15107 */
15108 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
15109 cpu_to_le32(idle_cmd_parameter));
15110 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015111
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015112 /*
15113 * Tickle the RISC to tell it to process the idle command.
15114 */
15115 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B);
15116 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
15117 /*
15118 * Clear the tickle value. In the ASC-3550 the RISC flag
15119 * command 'clr_tickle_b' does not work unless the host
15120 * value is cleared.
15121 */
15122 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
15123 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015124
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015125 /* Wait for up to 100 millisecond for the idle command to timeout. */
15126 for (i = 0; i < SCSI_WAIT_100_MSEC; i++) {
15127 /* Poll once each microsecond for command completion. */
15128 for (j = 0; j < SCSI_US_PER_MSEC; j++) {
15129 AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS,
15130 result);
15131 if (result != 0) {
15132 DvcLeaveCritical(last_int_level);
15133 return result;
15134 }
15135 DvcDelayMicroSecond(asc_dvc, (ushort)1);
15136 }
15137 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015138
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015139 ASC_ASSERT(0); /* The idle command should never timeout. */
15140 DvcLeaveCritical(last_int_level);
15141 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015142}
15143
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060015144static int __devinit
15145advansys_wide_init_chip(asc_board_t *boardp, ADV_DVC_VAR *adv_dvc_varp)
15146{
15147 int req_cnt = 0;
15148 adv_req_t *reqp = NULL;
15149 int sg_cnt = 0;
15150 adv_sgblk_t *sgp;
15151 int warn_code, err_code;
15152
15153 /*
15154 * Allocate buffer carrier structures. The total size
15155 * is about 4 KB, so allocate all at once.
15156 */
15157 boardp->carrp = kmalloc(ADV_CARRIER_BUFSIZE, GFP_KERNEL);
15158 ASC_DBG1(1, "advansys_wide_init_chip: carrp 0x%p\n", boardp->carrp);
15159
15160 if (!boardp->carrp)
15161 goto kmalloc_failed;
15162
15163 /*
15164 * Allocate up to 'max_host_qng' request structures for the Wide
15165 * board. The total size is about 16 KB, so allocate all at once.
15166 * If the allocation fails decrement and try again.
15167 */
15168 for (req_cnt = adv_dvc_varp->max_host_qng; req_cnt > 0; req_cnt--) {
15169 reqp = kmalloc(sizeof(adv_req_t) * req_cnt, GFP_KERNEL);
15170
15171 ASC_DBG3(1, "advansys_wide_init_chip: reqp 0x%p, req_cnt %d, "
15172 "bytes %lu\n", reqp, req_cnt,
15173 (ulong)sizeof(adv_req_t) * req_cnt);
15174
15175 if (reqp)
15176 break;
15177 }
15178
15179 if (!reqp)
15180 goto kmalloc_failed;
15181
15182 boardp->orig_reqp = reqp;
15183
15184 /*
15185 * Allocate up to ADV_TOT_SG_BLOCK request structures for
15186 * the Wide board. Each structure is about 136 bytes.
15187 */
15188 boardp->adv_sgblkp = NULL;
15189 for (sg_cnt = 0; sg_cnt < ADV_TOT_SG_BLOCK; sg_cnt++) {
15190 sgp = kmalloc(sizeof(adv_sgblk_t), GFP_KERNEL);
15191
15192 if (!sgp)
15193 break;
15194
15195 sgp->next_sgblkp = boardp->adv_sgblkp;
15196 boardp->adv_sgblkp = sgp;
15197
15198 }
15199
15200 ASC_DBG3(1, "advansys_wide_init_chip: sg_cnt %d * %u = %u bytes\n",
15201 sg_cnt, sizeof(adv_sgblk_t),
15202 (unsigned)(sizeof(adv_sgblk_t) * sg_cnt));
15203
15204 if (!boardp->adv_sgblkp)
15205 goto kmalloc_failed;
15206
15207 adv_dvc_varp->carrier_buf = boardp->carrp;
15208
15209 /*
15210 * Point 'adv_reqp' to the request structures and
15211 * link them together.
15212 */
15213 req_cnt--;
15214 reqp[req_cnt].next_reqp = NULL;
15215 for (; req_cnt > 0; req_cnt--) {
15216 reqp[req_cnt - 1].next_reqp = &reqp[req_cnt];
15217 }
15218 boardp->adv_reqp = &reqp[0];
15219
15220 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
15221 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc3550Driver()\n");
15222 warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
15223 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
15224 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc38C0800Driver()"
15225 "\n");
15226 warn_code = AdvInitAsc38C0800Driver(adv_dvc_varp);
15227 } else {
15228 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc38C1600Driver()"
15229 "\n");
15230 warn_code = AdvInitAsc38C1600Driver(adv_dvc_varp);
15231 }
15232 err_code = adv_dvc_varp->err_code;
15233
15234 if (warn_code || err_code) {
15235 ASC_PRINT3("advansys_wide_init_chip: board %d error: warn 0x%x,"
15236 " error 0x%x\n", boardp->id, warn_code, err_code);
15237 }
15238
15239 goto exit;
15240
15241 kmalloc_failed:
15242 ASC_PRINT1("advansys_wide_init_chip: board %d error: kmalloc() "
15243 "failed\n", boardp->id);
15244 err_code = ADV_ERROR;
15245 exit:
15246 return err_code;
15247}
15248
15249static void advansys_wide_free_mem(asc_board_t *boardp)
15250{
15251 kfree(boardp->carrp);
15252 boardp->carrp = NULL;
15253 kfree(boardp->orig_reqp);
15254 boardp->orig_reqp = boardp->adv_reqp = NULL;
15255 while (boardp->adv_sgblkp) {
15256 adv_sgblk_t *sgp = boardp->adv_sgblkp;
15257 boardp->adv_sgblkp = sgp->next_sgblkp;
15258 kfree(sgp);
15259 }
15260}
15261
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015262static struct Scsi_Host *__devinit
15263advansys_board_found(int iop, struct device *dev, int bus_type)
15264{
15265 struct Scsi_Host *shost;
15266 struct pci_dev *pdev = bus_type == ASC_IS_PCI ? to_pci_dev(dev) : NULL;
15267 asc_board_t *boardp;
15268 ASC_DVC_VAR *asc_dvc_varp = NULL;
15269 ADV_DVC_VAR *adv_dvc_varp = NULL;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060015270 int share_irq;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015271 int warn_code, err_code;
15272 int ret;
15273
15274 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015275 * Register the adapter, get its configuration, and
15276 * initialize it.
15277 */
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060015278 ASC_DBG(2, "advansys_board_found: scsi_host_alloc()\n");
15279 shost = scsi_host_alloc(&advansys_template, sizeof(asc_board_t));
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015280 if (!shost)
15281 return NULL;
15282
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015283 /* Initialize private per board data */
15284 boardp = ASC_BOARDP(shost);
15285 memset(boardp, 0, sizeof(asc_board_t));
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015286 boardp->id = asc_board_count++;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015287 spin_lock_init(&boardp->lock);
Matthew Wilcox394dbf32007-07-26 11:56:40 -040015288 boardp->dev = dev;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015289
15290 /*
15291 * Handle both narrow and wide boards.
15292 *
15293 * If a Wide board was detected, set the board structure
15294 * wide board flag. Set-up the board structure based on
15295 * the board type.
15296 */
15297#ifdef CONFIG_PCI
15298 if (bus_type == ASC_IS_PCI &&
15299 (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW ||
15300 pdev->device == PCI_DEVICE_ID_38C0800_REV1 ||
15301 pdev->device == PCI_DEVICE_ID_38C1600_REV1)) {
15302 boardp->flags |= ASC_IS_WIDE_BOARD;
15303 }
15304#endif /* CONFIG_PCI */
15305
15306 if (ASC_NARROW_BOARD(boardp)) {
15307 ASC_DBG(1, "advansys_board_found: narrow board\n");
15308 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
15309 asc_dvc_varp->bus_type = bus_type;
15310 asc_dvc_varp->drv_ptr = boardp;
15311 asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg;
15312 asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
15313 asc_dvc_varp->iop_base = iop;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015314 } else {
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040015315#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015316 ASC_DBG(1, "advansys_board_found: wide board\n");
15317 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
15318 adv_dvc_varp->drv_ptr = boardp;
15319 adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015320 if (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW) {
15321 ASC_DBG(1, "advansys_board_found: ASC-3550\n");
15322 adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
15323 } else if (pdev->device == PCI_DEVICE_ID_38C0800_REV1) {
15324 ASC_DBG(1, "advansys_board_found: ASC-38C0800\n");
15325 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
15326 } else {
15327 ASC_DBG(1, "advansys_board_found: ASC-38C1600\n");
15328 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C1600;
15329 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015330
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040015331 boardp->asc_n_io_port = pci_resource_len(pdev, 1);
15332 boardp->ioremap_addr = ioremap(pci_resource_start(pdev, 1),
15333 boardp->asc_n_io_port);
15334 if (!boardp->ioremap_addr) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015335 ASC_PRINT3
15336 ("advansys_board_found: board %d: ioremap(%x, %d) returned NULL\n",
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040015337 boardp->id, pci_resource_start(pdev, 1),
15338 boardp->asc_n_io_port);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060015339 goto err_shost;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015340 }
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040015341 adv_dvc_varp->iop_base = (AdvPortAddr)boardp->ioremap_addr
Matthew Wilcox71f361152007-07-30 08:04:53 -060015342 ASC_DBG1(1, "advansys_board_found: iop_base: 0x%lx\n",
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015343 adv_dvc_varp->iop_base);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015344
15345 /*
15346 * Even though it isn't used to access wide boards, other
15347 * than for the debug line below, save I/O Port address so
15348 * that it can be reported.
15349 */
15350 boardp->ioport = iop;
15351
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040015352 ASC_DBG2(1, "advansys_board_found: iopb_chip_id_1 0x%x, "
15353 "iopw_chip_id_0 0x%x\n", (ushort)inp(iop + 1),
15354 (ushort)inpw(iop));
15355#endif /* CONFIG_PCI */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015356 }
15357
15358#ifdef CONFIG_PROC_FS
15359 /*
15360 * Allocate buffer for printing information from
15361 * /proc/scsi/advansys/[0...].
15362 */
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060015363 boardp->prtbuf = kmalloc(ASC_PRTBUF_SIZE, GFP_KERNEL);
15364 if (!boardp->prtbuf) {
15365 ASC_PRINT2("advansys_board_found: board %d: kmalloc(%d) "
15366 "returned NULL\n", boardp->id, ASC_PRTBUF_SIZE);
15367 goto err_unmap;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015368 }
15369#endif /* CONFIG_PROC_FS */
15370
15371 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015372 /*
15373 * Set the board bus type and PCI IRQ before
15374 * calling AscInitGetConfig().
15375 */
15376 switch (asc_dvc_varp->bus_type) {
15377#ifdef CONFIG_ISA
15378 case ASC_IS_ISA:
15379 shost->unchecked_isa_dma = TRUE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060015380 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015381 break;
15382 case ASC_IS_VL:
15383 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060015384 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015385 break;
15386 case ASC_IS_EISA:
15387 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060015388 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015389 break;
15390#endif /* CONFIG_ISA */
15391#ifdef CONFIG_PCI
15392 case ASC_IS_PCI:
15393 shost->irq = asc_dvc_varp->irq_no = pdev->irq;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015394 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060015395 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015396 break;
15397#endif /* CONFIG_PCI */
15398 default:
15399 ASC_PRINT2
15400 ("advansys_board_found: board %d: unknown adapter type: %d\n",
15401 boardp->id, asc_dvc_varp->bus_type);
15402 shost->unchecked_isa_dma = TRUE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060015403 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015404 break;
15405 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015406
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015407 /*
15408 * NOTE: AscInitGetConfig() may change the board's
15409 * bus_type value. The bus_type value should no
15410 * longer be used. If the bus_type field must be
15411 * referenced only use the bit-wise AND operator "&".
15412 */
15413 ASC_DBG(2, "advansys_board_found: AscInitGetConfig()\n");
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060015414 err_code = AscInitGetConfig(boardp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015415 } else {
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060015416#ifdef CONFIG_PCI
15417 /*
15418 * For Wide boards set PCI information before calling
15419 * AdvInitGetConfig().
15420 */
15421 shost->irq = adv_dvc_varp->irq_no = pdev->irq;
15422 shost->unchecked_isa_dma = FALSE;
15423 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015424 ASC_DBG(2, "advansys_board_found: AdvInitGetConfig()\n");
Matthew Wilcox394dbf32007-07-26 11:56:40 -040015425
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060015426 err_code = AdvInitGetConfig(pdev, boardp);
15427#endif /* CONFIG_PCI */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015428 }
15429
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060015430 if (err_code != 0)
15431 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015432
15433 /*
15434 * Save the EEPROM configuration so that it can be displayed
15435 * from /proc/scsi/advansys/[0...].
15436 */
15437 if (ASC_NARROW_BOARD(boardp)) {
15438
15439 ASCEEP_CONFIG *ep;
15440
15441 /*
15442 * Set the adapter's target id bit in the 'init_tidmask' field.
15443 */
15444 boardp->init_tidmask |=
15445 ADV_TID_TO_TIDMASK(asc_dvc_varp->cfg->chip_scsi_id);
15446
15447 /*
15448 * Save EEPROM settings for the board.
15449 */
15450 ep = &boardp->eep_config.asc_eep;
15451
15452 ep->init_sdtr = asc_dvc_varp->cfg->sdtr_enable;
15453 ep->disc_enable = asc_dvc_varp->cfg->disc_enable;
15454 ep->use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled;
15455 ASC_EEP_SET_DMA_SPD(ep, asc_dvc_varp->cfg->isa_dma_speed);
15456 ep->start_motor = asc_dvc_varp->start_motor;
15457 ep->cntl = asc_dvc_varp->dvc_cntl;
15458 ep->no_scam = asc_dvc_varp->no_scam;
15459 ep->max_total_qng = asc_dvc_varp->max_total_qng;
15460 ASC_EEP_SET_CHIP_ID(ep, asc_dvc_varp->cfg->chip_scsi_id);
15461 /* 'max_tag_qng' is set to the same value for every device. */
15462 ep->max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0];
15463 ep->adapter_info[0] = asc_dvc_varp->cfg->adapter_info[0];
15464 ep->adapter_info[1] = asc_dvc_varp->cfg->adapter_info[1];
15465 ep->adapter_info[2] = asc_dvc_varp->cfg->adapter_info[2];
15466 ep->adapter_info[3] = asc_dvc_varp->cfg->adapter_info[3];
15467 ep->adapter_info[4] = asc_dvc_varp->cfg->adapter_info[4];
15468 ep->adapter_info[5] = asc_dvc_varp->cfg->adapter_info[5];
15469
15470 /*
15471 * Modify board configuration.
15472 */
15473 ASC_DBG(2, "advansys_board_found: AscInitSetConfig()\n");
Matthew Wilcoxc2dce2f2007-09-09 08:56:30 -060015474 err_code = AscInitSetConfig(pdev, boardp);
15475 if (err_code)
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060015476 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015477
15478 /*
15479 * Finish initializing the 'Scsi_Host' structure.
15480 */
15481 /* AscInitSetConfig() will set the IRQ for non-PCI boards. */
15482 if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
15483 shost->irq = asc_dvc_varp->irq_no;
15484 }
15485 } else {
15486 ADVEEP_3550_CONFIG *ep_3550;
15487 ADVEEP_38C0800_CONFIG *ep_38C0800;
15488 ADVEEP_38C1600_CONFIG *ep_38C1600;
15489
15490 /*
15491 * Save Wide EEP Configuration Information.
15492 */
15493 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
15494 ep_3550 = &boardp->eep_config.adv_3550_eep;
15495
15496 ep_3550->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
15497 ep_3550->max_host_qng = adv_dvc_varp->max_host_qng;
15498 ep_3550->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
15499 ep_3550->termination = adv_dvc_varp->cfg->termination;
15500 ep_3550->disc_enable = adv_dvc_varp->cfg->disc_enable;
15501 ep_3550->bios_ctrl = adv_dvc_varp->bios_ctrl;
15502 ep_3550->wdtr_able = adv_dvc_varp->wdtr_able;
15503 ep_3550->sdtr_able = adv_dvc_varp->sdtr_able;
15504 ep_3550->ultra_able = adv_dvc_varp->ultra_able;
15505 ep_3550->tagqng_able = adv_dvc_varp->tagqng_able;
15506 ep_3550->start_motor = adv_dvc_varp->start_motor;
15507 ep_3550->scsi_reset_delay =
15508 adv_dvc_varp->scsi_reset_wait;
15509 ep_3550->serial_number_word1 =
15510 adv_dvc_varp->cfg->serial1;
15511 ep_3550->serial_number_word2 =
15512 adv_dvc_varp->cfg->serial2;
15513 ep_3550->serial_number_word3 =
15514 adv_dvc_varp->cfg->serial3;
15515 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
15516 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
15517
15518 ep_38C0800->adapter_scsi_id =
15519 adv_dvc_varp->chip_scsi_id;
15520 ep_38C0800->max_host_qng = adv_dvc_varp->max_host_qng;
15521 ep_38C0800->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
15522 ep_38C0800->termination_lvd =
15523 adv_dvc_varp->cfg->termination;
15524 ep_38C0800->disc_enable =
15525 adv_dvc_varp->cfg->disc_enable;
15526 ep_38C0800->bios_ctrl = adv_dvc_varp->bios_ctrl;
15527 ep_38C0800->wdtr_able = adv_dvc_varp->wdtr_able;
15528 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
15529 ep_38C0800->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
15530 ep_38C0800->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
15531 ep_38C0800->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
15532 ep_38C0800->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
15533 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
15534 ep_38C0800->start_motor = adv_dvc_varp->start_motor;
15535 ep_38C0800->scsi_reset_delay =
15536 adv_dvc_varp->scsi_reset_wait;
15537 ep_38C0800->serial_number_word1 =
15538 adv_dvc_varp->cfg->serial1;
15539 ep_38C0800->serial_number_word2 =
15540 adv_dvc_varp->cfg->serial2;
15541 ep_38C0800->serial_number_word3 =
15542 adv_dvc_varp->cfg->serial3;
15543 } else {
15544 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
15545
15546 ep_38C1600->adapter_scsi_id =
15547 adv_dvc_varp->chip_scsi_id;
15548 ep_38C1600->max_host_qng = adv_dvc_varp->max_host_qng;
15549 ep_38C1600->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
15550 ep_38C1600->termination_lvd =
15551 adv_dvc_varp->cfg->termination;
15552 ep_38C1600->disc_enable =
15553 adv_dvc_varp->cfg->disc_enable;
15554 ep_38C1600->bios_ctrl = adv_dvc_varp->bios_ctrl;
15555 ep_38C1600->wdtr_able = adv_dvc_varp->wdtr_able;
15556 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
15557 ep_38C1600->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
15558 ep_38C1600->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
15559 ep_38C1600->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
15560 ep_38C1600->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
15561 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
15562 ep_38C1600->start_motor = adv_dvc_varp->start_motor;
15563 ep_38C1600->scsi_reset_delay =
15564 adv_dvc_varp->scsi_reset_wait;
15565 ep_38C1600->serial_number_word1 =
15566 adv_dvc_varp->cfg->serial1;
15567 ep_38C1600->serial_number_word2 =
15568 adv_dvc_varp->cfg->serial2;
15569 ep_38C1600->serial_number_word3 =
15570 adv_dvc_varp->cfg->serial3;
15571 }
15572
15573 /*
15574 * Set the adapter's target id bit in the 'init_tidmask' field.
15575 */
15576 boardp->init_tidmask |=
15577 ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015578 }
15579
15580 /*
15581 * Channels are numbered beginning with 0. For AdvanSys one host
15582 * structure supports one channel. Multi-channel boards have a
15583 * separate host structure for each channel.
15584 */
15585 shost->max_channel = 0;
15586 if (ASC_NARROW_BOARD(boardp)) {
15587 shost->max_id = ASC_MAX_TID + 1;
15588 shost->max_lun = ASC_MAX_LUN + 1;
15589
15590 shost->io_port = asc_dvc_varp->iop_base;
15591 boardp->asc_n_io_port = ASC_IOADR_GAP;
15592 shost->this_id = asc_dvc_varp->cfg->chip_scsi_id;
15593
15594 /* Set maximum number of queues the adapter can handle. */
15595 shost->can_queue = asc_dvc_varp->max_total_qng;
15596 } else {
15597 shost->max_id = ADV_MAX_TID + 1;
15598 shost->max_lun = ADV_MAX_LUN + 1;
15599
15600 /*
15601 * Save the I/O Port address and length even though
15602 * I/O ports are not used to access Wide boards.
15603 * Instead the Wide boards are accessed with
15604 * PCI Memory Mapped I/O.
15605 */
15606 shost->io_port = iop;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015607
15608 shost->this_id = adv_dvc_varp->chip_scsi_id;
15609
15610 /* Set maximum number of queues the adapter can handle. */
15611 shost->can_queue = adv_dvc_varp->max_host_qng;
15612 }
15613
15614 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015615 * Following v1.3.89, 'cmd_per_lun' is no longer needed
15616 * and should be set to zero.
15617 *
15618 * But because of a bug introduced in v1.3.89 if the driver is
15619 * compiled as a module and 'cmd_per_lun' is zero, the Mid-Level
15620 * SCSI function 'allocate_device' will panic. To allow the driver
15621 * to work as a module in these kernels set 'cmd_per_lun' to 1.
15622 *
15623 * Note: This is wrong. cmd_per_lun should be set to the depth
15624 * you want on untagged devices always.
15625 #ifdef MODULE
15626 */
15627 shost->cmd_per_lun = 1;
15628/* #else
15629 shost->cmd_per_lun = 0;
15630#endif */
15631
15632 /*
15633 * Set the maximum number of scatter-gather elements the
15634 * adapter can handle.
15635 */
15636 if (ASC_NARROW_BOARD(boardp)) {
15637 /*
15638 * Allow two commands with 'sg_tablesize' scatter-gather
15639 * elements to be executed simultaneously. This value is
15640 * the theoretical hardware limit. It may be decreased
15641 * below.
15642 */
15643 shost->sg_tablesize =
15644 (((asc_dvc_varp->max_total_qng - 2) / 2) *
15645 ASC_SG_LIST_PER_Q) + 1;
15646 } else {
15647 shost->sg_tablesize = ADV_MAX_SG_LIST;
15648 }
15649
15650 /*
15651 * The value of 'sg_tablesize' can not exceed the SCSI
15652 * mid-level driver definition of SG_ALL. SG_ALL also
15653 * must not be exceeded, because it is used to define the
15654 * size of the scatter-gather table in 'struct asc_sg_head'.
15655 */
15656 if (shost->sg_tablesize > SG_ALL) {
15657 shost->sg_tablesize = SG_ALL;
15658 }
15659
15660 ASC_DBG1(1, "advansys_board_found: sg_tablesize: %d\n", shost->sg_tablesize);
15661
15662 /* BIOS start address. */
15663 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060015664 shost->base = AscGetChipBiosAddress(asc_dvc_varp->iop_base,
15665 asc_dvc_varp->bus_type);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015666 } else {
15667 /*
15668 * Fill-in BIOS board variables. The Wide BIOS saves
15669 * information in LRAM that is used by the driver.
15670 */
15671 AdvReadWordLram(adv_dvc_varp->iop_base,
15672 BIOS_SIGNATURE, boardp->bios_signature);
15673 AdvReadWordLram(adv_dvc_varp->iop_base,
15674 BIOS_VERSION, boardp->bios_version);
15675 AdvReadWordLram(adv_dvc_varp->iop_base,
15676 BIOS_CODESEG, boardp->bios_codeseg);
15677 AdvReadWordLram(adv_dvc_varp->iop_base,
15678 BIOS_CODELEN, boardp->bios_codelen);
15679
15680 ASC_DBG2(1,
15681 "advansys_board_found: bios_signature 0x%x, bios_version 0x%x\n",
15682 boardp->bios_signature, boardp->bios_version);
15683
15684 ASC_DBG2(1,
15685 "advansys_board_found: bios_codeseg 0x%x, bios_codelen 0x%x\n",
15686 boardp->bios_codeseg, boardp->bios_codelen);
15687
15688 /*
15689 * If the BIOS saved a valid signature, then fill in
15690 * the BIOS code segment base address.
15691 */
15692 if (boardp->bios_signature == 0x55AA) {
15693 /*
15694 * Convert x86 realmode code segment to a linear
15695 * address by shifting left 4.
15696 */
15697 shost->base = ((ulong)boardp->bios_codeseg << 4);
15698 } else {
15699 shost->base = 0;
15700 }
15701 }
15702
15703 /*
15704 * Register Board Resources - I/O Port, DMA, IRQ
15705 */
15706
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015707 /* Register DMA Channel for Narrow boards. */
15708 shost->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */
15709#ifdef CONFIG_ISA
15710 if (ASC_NARROW_BOARD(boardp)) {
15711 /* Register DMA channel for ISA bus. */
15712 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
15713 shost->dma_channel = asc_dvc_varp->cfg->isa_dma_channel;
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060015714 ret = request_dma(shost->dma_channel, "advansys");
15715 if (ret) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015716 ASC_PRINT3
15717 ("advansys_board_found: board %d: request_dma() %d failed %d\n",
15718 boardp->id, shost->dma_channel, ret);
Matthew Wilcox71f361152007-07-30 08:04:53 -060015719 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015720 }
15721 AscEnableIsaDma(shost->dma_channel);
15722 }
15723 }
15724#endif /* CONFIG_ISA */
15725
15726 /* Register IRQ Number. */
15727 ASC_DBG1(2, "advansys_board_found: request_irq() %d\n", shost->irq);
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060015728
15729 ret = request_irq(shost->irq, advansys_interrupt, share_irq,
15730 "advansys", shost);
15731
15732 if (ret) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015733 if (ret == -EBUSY) {
15734 ASC_PRINT2
15735 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x already in use.\n",
15736 boardp->id, shost->irq);
15737 } else if (ret == -EINVAL) {
15738 ASC_PRINT2
15739 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x not valid.\n",
15740 boardp->id, shost->irq);
15741 } else {
15742 ASC_PRINT3
15743 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x failed with %d\n",
15744 boardp->id, shost->irq, ret);
15745 }
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060015746 goto err_free_dma;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015747 }
15748
15749 /*
15750 * Initialize board RISC chip and enable interrupts.
15751 */
15752 if (ASC_NARROW_BOARD(boardp)) {
15753 ASC_DBG(2, "advansys_board_found: AscInitAsc1000Driver()\n");
15754 warn_code = AscInitAsc1000Driver(asc_dvc_varp);
15755 err_code = asc_dvc_varp->err_code;
15756
15757 if (warn_code || err_code) {
15758 ASC_PRINT4
15759 ("advansys_board_found: board %d error: init_state 0x%x, warn 0x%x, error 0x%x\n",
15760 boardp->id,
15761 asc_dvc_varp->init_state, warn_code, err_code);
15762 }
15763 } else {
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060015764 err_code = advansys_wide_init_chip(boardp, adv_dvc_varp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015765 }
15766
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060015767 if (err_code != 0)
15768 goto err_free_wide_mem;
15769
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015770 ASC_DBG_PRT_SCSI_HOST(2, shost);
15771
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060015772 ret = scsi_add_host(shost, dev);
15773 if (ret)
15774 goto err_free_wide_mem;
15775
15776 scsi_scan_host(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015777 return shost;
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060015778
15779 err_free_wide_mem:
15780 advansys_wide_free_mem(boardp);
15781 free_irq(shost->irq, shost);
15782 err_free_dma:
15783 if (shost->dma_channel != NO_ISA_DMA)
15784 free_dma(shost->dma_channel);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060015785 err_free_proc:
15786 kfree(boardp->prtbuf);
15787 err_unmap:
15788 if (boardp->ioremap_addr)
15789 iounmap(boardp->ioremap_addr);
15790 err_shost:
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060015791 scsi_host_put(shost);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060015792 return NULL;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015793}
15794
15795/*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015796 * advansys_release()
15797 *
15798 * Release resources allocated for a single AdvanSys adapter.
15799 */
15800static int advansys_release(struct Scsi_Host *shost)
15801{
15802 asc_board_t *boardp;
15803
15804 ASC_DBG(1, "advansys_release: begin\n");
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060015805 scsi_remove_host(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015806 boardp = ASC_BOARDP(shost);
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060015807 free_irq(shost->irq, shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015808 if (shost->dma_channel != NO_ISA_DMA) {
15809 ASC_DBG(1, "advansys_release: free_dma()\n");
15810 free_dma(shost->dma_channel);
15811 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015812 if (ASC_WIDE_BOARD(boardp)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015813 iounmap(boardp->ioremap_addr);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060015814 advansys_wide_free_mem(boardp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015815 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015816 kfree(boardp->prtbuf);
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060015817 scsi_host_put(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015818 ASC_DBG(1, "advansys_release: end\n");
15819 return 0;
15820}
15821
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015822static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __devinitdata = {
15823 0x100, 0x0110, 0x120, 0x0130, 0x140, 0x0150, 0x0190,
15824 0x0210, 0x0230, 0x0250, 0x0330
15825};
15826
15827static int __devinit advansys_isa_probe(struct device *dev, unsigned int id)
15828{
15829 PortAddr iop_base = _asc_def_iop_base[id];
15830 struct Scsi_Host *shost;
15831
15832 if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) {
Matthew Wilcox71f361152007-07-30 08:04:53 -060015833 ASC_DBG1(1, "advansys_isa_match: I/O port 0x%x busy\n",
15834 iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015835 return -ENODEV;
15836 }
15837 ASC_DBG1(1, "advansys_isa_match: probing I/O port 0x%x\n", iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015838 if (!AscFindSignature(iop_base))
15839 goto nodev;
15840 if (!(AscGetChipVersion(iop_base, ASC_IS_ISA) & ASC_CHIP_VER_ISA_BIT))
15841 goto nodev;
15842
15843 shost = advansys_board_found(iop_base, dev, ASC_IS_ISA);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015844 if (!shost)
15845 goto nodev;
15846
15847 dev_set_drvdata(dev, shost);
15848 return 0;
15849
15850 nodev:
Matthew Wilcox71f361152007-07-30 08:04:53 -060015851 release_region(iop_base, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015852 return -ENODEV;
15853}
15854
15855static int __devexit advansys_isa_remove(struct device *dev, unsigned int id)
15856{
Matthew Wilcox71f361152007-07-30 08:04:53 -060015857 int ioport = _asc_def_iop_base[id];
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015858 advansys_release(dev_get_drvdata(dev));
Matthew Wilcox71f361152007-07-30 08:04:53 -060015859 release_region(ioport, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015860 return 0;
15861}
15862
15863static struct isa_driver advansys_isa_driver = {
15864 .probe = advansys_isa_probe,
15865 .remove = __devexit_p(advansys_isa_remove),
15866 .driver = {
15867 .owner = THIS_MODULE,
15868 .name = "advansys",
15869 },
15870};
15871
15872static int __devinit advansys_vlb_probe(struct device *dev, unsigned int id)
15873{
15874 PortAddr iop_base = _asc_def_iop_base[id];
15875 struct Scsi_Host *shost;
15876
15877 if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) {
Matthew Wilcox71f361152007-07-30 08:04:53 -060015878 ASC_DBG1(1, "advansys_vlb_match: I/O port 0x%x busy\n",
15879 iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015880 return -ENODEV;
15881 }
15882 ASC_DBG1(1, "advansys_vlb_match: probing I/O port 0x%x\n", iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015883 if (!AscFindSignature(iop_base))
15884 goto nodev;
15885 /*
15886 * I don't think this condition can actually happen, but the old
15887 * driver did it, and the chances of finding a VLB setup in 2007
15888 * to do testing with is slight to none.
15889 */
15890 if (AscGetChipVersion(iop_base, ASC_IS_VL) > ASC_CHIP_MAX_VER_VL)
15891 goto nodev;
15892
15893 shost = advansys_board_found(iop_base, dev, ASC_IS_VL);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015894 if (!shost)
15895 goto nodev;
15896
15897 dev_set_drvdata(dev, shost);
15898 return 0;
15899
15900 nodev:
Matthew Wilcox71f361152007-07-30 08:04:53 -060015901 release_region(iop_base, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015902 return -ENODEV;
15903}
15904
15905static struct isa_driver advansys_vlb_driver = {
15906 .probe = advansys_vlb_probe,
15907 .remove = __devexit_p(advansys_isa_remove),
15908 .driver = {
15909 .owner = THIS_MODULE,
Matthew Wilcoxb8e5152b2007-09-09 08:56:26 -060015910 .name = "advansys_vlb",
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060015911 },
15912};
15913
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060015914static struct eisa_device_id advansys_eisa_table[] __devinitdata = {
15915 { "ABP7401" },
15916 { "ABP7501" },
15917 { "" }
15918};
15919
15920MODULE_DEVICE_TABLE(eisa, advansys_eisa_table);
15921
15922/*
15923 * EISA is a little more tricky than PCI; each EISA device may have two
15924 * channels, and this driver is written to make each channel its own Scsi_Host
15925 */
15926struct eisa_scsi_data {
15927 struct Scsi_Host *host[2];
15928};
15929
15930static int __devinit advansys_eisa_probe(struct device *dev)
15931{
15932 int i, ioport;
15933 int err;
15934 struct eisa_device *edev = to_eisa_device(dev);
15935 struct eisa_scsi_data *data;
15936
15937 err = -ENOMEM;
15938 data = kzalloc(sizeof(*data), GFP_KERNEL);
15939 if (!data)
15940 goto fail;
15941 ioport = edev->base_addr + 0xc30;
15942
15943 err = -ENODEV;
15944 for (i = 0; i < 2; i++, ioport += 0x20) {
Matthew Wilcox71f361152007-07-30 08:04:53 -060015945 if (!request_region(ioport, ASC_IOADR_GAP, "advansys")) {
15946 printk(KERN_WARNING "Region %x-%x busy\n", ioport,
15947 ioport + ASC_IOADR_GAP - 1);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060015948 continue;
Matthew Wilcox71f361152007-07-30 08:04:53 -060015949 }
15950 if (!AscFindSignature(ioport)) {
15951 release_region(ioport, ASC_IOADR_GAP);
15952 continue;
15953 }
15954
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060015955 /*
15956 * I don't know why we need to do this for EISA chips, but
15957 * not for any others. It looks to be equivalent to
15958 * AscGetChipCfgMsw, but I may have overlooked something,
15959 * so I'm not converting it until I get an EISA board to
15960 * test with.
15961 */
15962 inw(ioport + 4);
15963 data->host[i] = advansys_board_found(ioport, dev, ASC_IS_EISA);
Matthew Wilcox71f361152007-07-30 08:04:53 -060015964 if (data->host[i]) {
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060015965 err = 0;
Matthew Wilcox71f361152007-07-30 08:04:53 -060015966 } else {
15967 release_region(ioport, ASC_IOADR_GAP);
15968 }
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060015969 }
15970
15971 if (err) {
15972 kfree(data);
15973 } else {
15974 dev_set_drvdata(dev, data);
15975 }
15976
15977 fail:
15978 return err;
15979}
15980
15981static __devexit int advansys_eisa_remove(struct device *dev)
15982{
15983 int i;
15984 struct eisa_scsi_data *data = dev_get_drvdata(dev);
15985
15986 for (i = 0; i < 2; i++) {
Matthew Wilcox71f361152007-07-30 08:04:53 -060015987 int ioport;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060015988 struct Scsi_Host *shost = data->host[i];
15989 if (!shost)
15990 continue;
Matthew Wilcox71f361152007-07-30 08:04:53 -060015991 ioport = shost->io_port;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060015992 advansys_release(shost);
Matthew Wilcox71f361152007-07-30 08:04:53 -060015993 release_region(ioport, ASC_IOADR_GAP);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060015994 }
15995
15996 kfree(data);
15997 return 0;
15998}
15999
16000static struct eisa_driver advansys_eisa_driver = {
16001 .id_table = advansys_eisa_table,
16002 .driver = {
16003 .name = "advansys",
16004 .probe = advansys_eisa_probe,
16005 .remove = __devexit_p(advansys_eisa_remove),
16006 }
16007};
16008
Dave Jones2672ea82006-08-02 17:11:49 -040016009/* PCI Devices supported by this driver */
16010static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016011 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A,
16012 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
16013 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940,
16014 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
16015 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940U,
16016 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
16017 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940UW,
16018 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
16019 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C0800_REV1,
16020 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
16021 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C1600_REV1,
16022 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
16023 {}
Dave Jones2672ea82006-08-02 17:11:49 -040016024};
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016025
Dave Jones2672ea82006-08-02 17:11:49 -040016026MODULE_DEVICE_TABLE(pci, advansys_pci_tbl);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016027
Matthew Wilcox9649af32007-07-26 21:51:47 -060016028static void __devinit advansys_set_latency(struct pci_dev *pdev)
16029{
16030 if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) ||
16031 (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) {
16032 pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0);
16033 } else {
16034 u8 latency;
16035 pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency);
16036 if (latency < 0x20)
16037 pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x20);
16038 }
16039}
16040
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016041static int __devinit
16042advansys_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
16043{
16044 int err, ioport;
16045 struct Scsi_Host *shost;
16046
16047 err = pci_enable_device(pdev);
16048 if (err)
16049 goto fail;
Matthew Wilcox71f361152007-07-30 08:04:53 -060016050 err = pci_request_regions(pdev, "advansys");
16051 if (err)
16052 goto disable_device;
Matthew Wilcox9649af32007-07-26 21:51:47 -060016053 pci_set_master(pdev);
16054 advansys_set_latency(pdev);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016055
16056 if (pci_resource_len(pdev, 0) == 0)
16057 goto nodev;
16058
16059 ioport = pci_resource_start(pdev, 0);
16060 shost = advansys_board_found(ioport, &pdev->dev, ASC_IS_PCI);
16061
16062 if (!shost)
16063 goto nodev;
16064
16065 pci_set_drvdata(pdev, shost);
16066 return 0;
16067
16068 nodev:
16069 err = -ENODEV;
Matthew Wilcox71f361152007-07-30 08:04:53 -060016070 pci_release_regions(pdev);
16071 disable_device:
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016072 pci_disable_device(pdev);
16073 fail:
16074 return err;
16075}
16076
16077static void __devexit advansys_pci_remove(struct pci_dev *pdev)
16078{
16079 advansys_release(pci_get_drvdata(pdev));
Matthew Wilcox71f361152007-07-30 08:04:53 -060016080 pci_release_regions(pdev);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016081 pci_disable_device(pdev);
16082}
16083
16084static struct pci_driver advansys_pci_driver = {
16085 .name = "advansys",
16086 .id_table = advansys_pci_tbl,
16087 .probe = advansys_pci_probe,
16088 .remove = __devexit_p(advansys_pci_remove),
16089};
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040016090
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060016091static int __init advansys_init(void)
16092{
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060016093 int error;
16094
16095 error = isa_register_driver(&advansys_isa_driver,
16096 ASC_IOADR_TABLE_MAX_IX);
16097 if (error)
16098 goto fail;
16099
16100 error = isa_register_driver(&advansys_vlb_driver,
16101 ASC_IOADR_TABLE_MAX_IX);
16102 if (error)
16103 goto unregister_isa;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060016104
16105 error = eisa_driver_register(&advansys_eisa_driver);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016106 if (error)
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060016107 goto unregister_vlb;
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060016108
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060016109 error = pci_register_driver(&advansys_pci_driver);
16110 if (error)
16111 goto unregister_eisa;
16112
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060016113 return 0;
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016114
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060016115 unregister_eisa:
16116 eisa_driver_unregister(&advansys_eisa_driver);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060016117 unregister_vlb:
16118 isa_unregister_driver(&advansys_vlb_driver);
16119 unregister_isa:
16120 isa_unregister_driver(&advansys_isa_driver);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016121 fail:
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016122 return error;
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060016123}
16124
16125static void __exit advansys_exit(void)
16126{
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016127 pci_unregister_driver(&advansys_pci_driver);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060016128 eisa_driver_unregister(&advansys_eisa_driver);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060016129 isa_unregister_driver(&advansys_vlb_driver);
16130 isa_unregister_driver(&advansys_isa_driver);
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060016131}
16132
16133module_init(advansys_init);
16134module_exit(advansys_exit);
16135
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040016136MODULE_LICENSE("GPL");