Blame view

drivers/scsi/initio.c 79.7 KB
c82ee6d3b   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
  /**************************************************************************
   * Initio 9100 device driver for Linux.
   *
   * Copyright (c) 1994-1998 Initio Corporation
   * Copyright (c) 1998 Bas Vermeulen <bvermeul@blackstar.xs4all.nl>
72d39fea9   Alan Cox   [SCSI] initio: Co...
7
   * Copyright (c) 2004 Christoph Hellwig <hch@lst.de>
fa195afe4   Alan Cox   [SCSI] Clean up m...
8
   * Copyright (c) 2007 Red Hat
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
   *************************************************************************
   *
   * DESCRIPTION:
   *
   * This is the Linux low-level SCSI driver for Initio INI-9X00U/UW SCSI host
   * adapters
   *
   * 08/06/97 hc	- v1.01h
   *		- Support inic-940 and inic-935
   * 09/26/97 hc	- v1.01i
   *		- Make correction from J.W. Schultz suggestion
   * 10/13/97 hc	- Support reset function
   * 10/21/97 hc	- v1.01j
   *		- Support 32 LUN (SCSI 3)
   * 01/14/98 hc	- v1.01k
   *		- Fix memory allocation problem
   * 03/04/98 hc	- v1.01l
   *		- Fix tape rewind which will hang the system problem
72d39fea9   Alan Cox   [SCSI] initio: Co...
28
   *		- Set can_queue to initio_num_scb
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
   * 06/25/98 hc	- v1.01m
   *		- Get it work for kernel version >= 2.1.75
72d39fea9   Alan Cox   [SCSI] initio: Co...
31
   *		- Dynamic assign SCSI bus reset holding time in initio_init()
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
34
   * 07/02/98 hc	- v1.01n
   *		- Support 0002134A
   * 08/07/98 hc  - v1.01o
72d39fea9   Alan Cox   [SCSI] initio: Co...
35
   *		- Change the initio_abort_srb routine to use scsi_done. <01>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
   * 09/07/98 hl  - v1.02
   *              - Change the INI9100U define and proc_dir_entry to
   *                reflect the newer Kernel 2.1.118, but the v1.o1o
   *                should work with Kernel 2.1.118.
   * 09/20/98 wh  - v1.02a
   *              - Support Abort command.
   *              - Handle reset routine.
   * 09/21/98 hl  - v1.03
   *              - remove comments.
   * 12/09/98 bv	- v1.03a
   *		- Removed unused code
   * 12/13/98 bv	- v1.03b
   *		- Remove cli() locking for kernels >= 2.1.95. This uses
   *		  spinlocks to serialize access to the pSRB_head and
   *		  pSRB_tail members of the HCS structure.
   * 09/01/99 bv	- v1.03d
   *		- Fixed a deadlock problem in SMP.
   * 21/01/99 bv	- v1.03e
   *		- Add support for the Domex 3192U PCI SCSI
   *		  This is a slightly modified patch by
   *		  Brian Macy <bmacy@sunshinecomputing.com>
   * 22/02/99 bv	- v1.03f
   *		- Didn't detect the INIC-950 in 2.0.x correctly.
   *		  Now fixed.
   * 05/07/99 bv	- v1.03g
   *		- Changed the assumption that HZ = 100
   * 10/17/03 mc	- v1.04
   *		- added new DMA API support
   * 06/01/04 jmd	- v1.04a
   *		- Re-add reset_bus support
   **************************************************************************/
  
  #include <linux/module.h>
  #include <linux/errno.h>
  #include <linux/delay.h>
  #include <linux/pci.h>
  #include <linux/init.h>
  #include <linux/blkdev.h>
  #include <linux/spinlock.h>
  #include <linux/stat.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
77
78
79
80
  #include <linux/kernel.h>
  #include <linux/proc_fs.h>
  #include <linux/string.h>
  #include <linux/interrupt.h>
  #include <linux/ioport.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
82
  #include <linux/slab.h>
  #include <linux/jiffies.h>
910638ae7   Matthias Gehre   [PATCH] Replace 0...
83
  #include <linux/dma-mapping.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
85
86
87
88
89
90
91
92
93
94
95
96
97
  #include <asm/io.h>
  
  #include <scsi/scsi.h>
  #include <scsi/scsi_cmnd.h>
  #include <scsi/scsi_device.h>
  #include <scsi/scsi_host.h>
  #include <scsi/scsi_tcq.h>
  
  #include "initio.h"
  
  #define SENSE_SIZE		14
  
  #define i91u_MAXQUEUE		2
  #define i91u_REVID "Initio INI-9X00U/UW SCSI device driver; Revision: 1.04a"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
99
100
  #ifdef DEBUG_i91u
  static unsigned int i91u_debug = DEBUG_DEFAULT;
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
101
  static int initio_tag_enable = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
103
104
105
  
  #ifdef DEBUG_i91u
  static int setup_debug = 0;
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
106
  static void i91uSCBPost(u8 * pHcb, u8 * pScb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
109
110
111
  #define DEBUG_INTERRUPT 0
  #define DEBUG_QUEUE     0
  #define DEBUG_STATE     0
  #define INT_DISC	0
72d39fea9   Alan Cox   [SCSI] initio: Co...
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
  /*--- forward references ---*/
  static struct scsi_ctrl_blk *initio_find_busy_scb(struct initio_host * host, u16 tarlun);
  static struct scsi_ctrl_blk *initio_find_done_scb(struct initio_host * host);
  
  static int tulip_main(struct initio_host * host);
  
  static int initio_next_state(struct initio_host * host);
  static int initio_state_1(struct initio_host * host);
  static int initio_state_2(struct initio_host * host);
  static int initio_state_3(struct initio_host * host);
  static int initio_state_4(struct initio_host * host);
  static int initio_state_5(struct initio_host * host);
  static int initio_state_6(struct initio_host * host);
  static int initio_state_7(struct initio_host * host);
  static int initio_xfer_data_in(struct initio_host * host);
  static int initio_xfer_data_out(struct initio_host * host);
  static int initio_xpad_in(struct initio_host * host);
  static int initio_xpad_out(struct initio_host * host);
  static int initio_status_msg(struct initio_host * host);
  
  static int initio_msgin(struct initio_host * host);
  static int initio_msgin_sync(struct initio_host * host);
  static int initio_msgin_accept(struct initio_host * host);
  static int initio_msgout_reject(struct initio_host * host);
  static int initio_msgin_extend(struct initio_host * host);
  
  static int initio_msgout_ide(struct initio_host * host);
  static int initio_msgout_abort_targ(struct initio_host * host);
  static int initio_msgout_abort_tag(struct initio_host * host);
  
  static int initio_bus_device_reset(struct initio_host * host);
  static void initio_select_atn(struct initio_host * host, struct scsi_ctrl_blk * scb);
  static void initio_select_atn3(struct initio_host * host, struct scsi_ctrl_blk * scb);
  static void initio_select_atn_stop(struct initio_host * host, struct scsi_ctrl_blk * scb);
  static int int_initio_busfree(struct initio_host * host);
  static int int_initio_scsi_rst(struct initio_host * host);
  static int int_initio_bad_seq(struct initio_host * host);
  static int int_initio_resel(struct initio_host * host);
  static int initio_sync_done(struct initio_host * host);
  static int wdtr_done(struct initio_host * host);
  static int wait_tulip(struct initio_host * host);
  static int initio_wait_done_disc(struct initio_host * host);
  static int initio_wait_disc(struct initio_host * host);
  static void tulip_scsi(struct initio_host * host);
  static int initio_post_scsi_rst(struct initio_host * host);
  
  static void initio_se2_ew_en(unsigned long base);
  static void initio_se2_ew_ds(unsigned long base);
  static int initio_se2_rd_all(unsigned long base);
  static void initio_se2_update_all(unsigned long base);	/* setup default pattern */
  static void initio_read_eeprom(unsigned long base);
  
  /* ---- INTERNAL VARIABLES ---- */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
166
  static NVRAM i91unvram;
  static NVRAM *i91unvramp;
72d39fea9   Alan Cox   [SCSI] initio: Co...
167
  static u8 i91udftNvRam[64] =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
169
  	/*----------- header -----------*/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
  	0x25, 0xc9,		/* Signature    */
  	0x40,			/* Size         */
  	0x01,			/* Revision     */
  	/* -- Host Adapter Structure -- */
  	0x95,			/* ModelByte0   */
  	0x00,			/* ModelByte1   */
  	0x00,			/* ModelInfo    */
  	0x01,			/* NumOfCh      */
  	NBC1_DEFAULT,		/* BIOSConfig1  */
  	0,			/* BIOSConfig2  */
  	0,			/* HAConfig1    */
  	0,			/* HAConfig2    */
  	/* SCSI channel 0 and target Structure  */
  	7,			/* SCSIid       */
  	NCC1_DEFAULT,		/* SCSIconfig1  */
  	0,			/* SCSIconfig2  */
  	0x10,			/* NumSCSItarget */
  
  	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
  	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
  	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
  	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
  
  	/* SCSI channel 1 and target Structure  */
  	7,			/* SCSIid       */
  	NCC1_DEFAULT,		/* SCSIconfig1  */
  	0,			/* SCSIconfig2  */
  	0x10,			/* NumSCSItarget */
  
  	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
  	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
  	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
  	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
  	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  	0, 0};			/*      - CheckSum -            */
72d39fea9   Alan Cox   [SCSI] initio: Co...
205
  static u8 initio_rate_tbl[8] =	/* fast 20      */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
206
  {
25985edce   Lucas De Marchi   Fix common misspe...
207
  				/* nanosecond divide by 4 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
210
211
212
213
214
215
216
  	12,			/* 50ns,  20M   */
  	18,			/* 75ns,  13.3M */
  	25,			/* 100ns, 10M   */
  	31,			/* 125ns, 8M    */
  	37,			/* 150ns, 6.6M  */
  	43,			/* 175ns, 5.7M  */
  	50,			/* 200ns, 5M    */
  	62			/* 250ns, 4M    */
  };
72d39fea9   Alan Cox   [SCSI] initio: Co...
217
218
219
  static void initio_do_pause(unsigned amount)
  {
  	/* Pause for amount jiffies */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220
  	unsigned long the_time = jiffies + amount;
72d39fea9   Alan Cox   [SCSI] initio: Co...
221
222
  	while (time_before_eq(jiffies, the_time))
  		cpu_relax();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
224
225
  }
  
  /*-- forward reference --*/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
  /******************************************************************
   Input: instruction for  Serial E2PROM
  
   EX: se2_rd(0 call se2_instr() to send address and read command
  
  	 StartBit  OP_Code   Address                Data
  	 --------- --------  ------------------     -------
  	 1         1 , 0     A5,A4,A3,A2,A1,A0      D15-D0
  
  		 +-----------------------------------------------------
  		 |
   CS -----+
  			+--+  +--+  +--+  +--+  +--+
  			^  |  ^  |  ^  |  ^  |  ^  |
  			|  |  |  |  |  |  |  |  |  |
   CLK -------+  +--+  +--+  +--+  +--+  +--
   (leading edge trigger)
  
  		 +--1-----1--+
  		 | SB    OP  |  OP    A5    A4
   DI  ----+           +--0------------------
   (address and cmd sent to nvram)
  
  	 -------------------------------------------+
  												|
   DO                                             +---
   (data sent from nvram)
  
  
  ******************************************************************/
72d39fea9   Alan Cox   [SCSI] initio: Co...
256
257
258
259
260
261
262
263
264
265
  
  /**
   *	initio_se2_instr	-	bitbang an instruction
   *	@base: Base of InitIO controller
   *	@instr: Instruction for serial E2PROM
   *
   *	Bitbang an instruction out to the serial E2Prom
   */
  
  static void initio_se2_instr(unsigned long base, u8 instr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
267
  {
  	int i;
72d39fea9   Alan Cox   [SCSI] initio: Co...
268
  	u8 b;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269

72d39fea9   Alan Cox   [SCSI] initio: Co...
270
271
272
273
  	outb(SE2CS | SE2DO, base + TUL_NVRAM);		/* cs+start bit */
  	udelay(30);
  	outb(SE2CS | SE2CLK | SE2DO, base + TUL_NVRAM);	/* +CLK */
  	udelay(30);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
275
276
  
  	for (i = 0; i < 8; i++) {
  		if (instr & 0x80)
72d39fea9   Alan Cox   [SCSI] initio: Co...
277
  			b = SE2CS | SE2DO;		/* -CLK+dataBit */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278
  		else
72d39fea9   Alan Cox   [SCSI] initio: Co...
279
280
281
282
283
  			b = SE2CS;			/* -CLK */
  		outb(b, base + TUL_NVRAM);
  		udelay(30);
  		outb(b | SE2CLK, base + TUL_NVRAM);	/* +CLK */
  		udelay(30);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
285
  		instr <<= 1;
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
286
287
  	outb(SE2CS, base + TUL_NVRAM);			/* -CLK */
  	udelay(30);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
289
290
291
292
293
294
295
  /**
   *	initio_se2_ew_en	-	Enable erase/write
   *	@base: Base address of InitIO controller
   *
   *	Enable erase/write state of serial EEPROM
   */
  void initio_se2_ew_en(unsigned long base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
297
298
299
  	initio_se2_instr(base, 0x30);	/* EWEN */
  	outb(0, base + TUL_NVRAM);	/* -CS  */
  	udelay(30);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
301
302
303
304
305
306
307
  /**
   *	initio_se2_ew_ds	-	Disable erase/write
   *	@base: Base address of InitIO controller
   *
   *	Disable erase/write state of serial EEPROM
   */
  void initio_se2_ew_ds(unsigned long base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
309
310
311
  	initio_se2_instr(base, 0);	/* EWDS */
  	outb(0, base + TUL_NVRAM);	/* -CS  */
  	udelay(30);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
313
314
315
316
317
318
319
320
  /**
   *	initio_se2_rd		-	read E2PROM word
   *	@base: Base of InitIO controller
   *	@addr: Address of word in E2PROM
   *
   *	Read a word from the NV E2PROM device
   */
  static u16 initio_se2_rd(unsigned long base, u8 addr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
322
323
  	u8 instr, rb;
  	u16 val = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
  	int i;
72d39fea9   Alan Cox   [SCSI] initio: Co...
325
326
  	instr = (u8) (addr | 0x80);
  	initio_se2_instr(base, instr);	/* READ INSTR */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
328
  
  	for (i = 15; i >= 0; i--) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
329
330
331
  		outb(SE2CS | SE2CLK, base + TUL_NVRAM);	/* +CLK */
  		udelay(30);
  		outb(SE2CS, base + TUL_NVRAM);		/* -CLK */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
333
  
  		/* sample data after the following edge of clock  */
72d39fea9   Alan Cox   [SCSI] initio: Co...
334
335
336
337
  		rb = inb(base + TUL_NVRAM);
  		rb &= SE2DI;
  		val += (rb << i);
  		udelay(30);	/* 6/20/95 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
339
340
341
  	outb(0, base + TUL_NVRAM);		/* no chip select */
  	udelay(30);
  	return val;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
343
344
345
346
347
348
349
350
351
352
  /**
   *	initio_se2_wr		-	read E2PROM word
   *	@base: Base of InitIO controller
   *	@addr: Address of word in E2PROM
   *	@val: Value to write
   *
   *	Write a word to the NV E2PROM device. Used when recovering from
   *	a problem with the NV.
   */
  static void initio_se2_wr(unsigned long base, u8 addr, u16 val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
354
355
  	u8 rb;
  	u8 instr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356
  	int i;
72d39fea9   Alan Cox   [SCSI] initio: Co...
357
358
  	instr = (u8) (addr | 0x40);
  	initio_se2_instr(base, instr);	/* WRITE INSTR */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
  	for (i = 15; i >= 0; i--) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
360
361
  		if (val & 0x8000)
  			outb(SE2CS | SE2DO, base + TUL_NVRAM);	/* -CLK+dataBit 1 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
  		else
72d39fea9   Alan Cox   [SCSI] initio: Co...
363
364
365
366
367
  			outb(SE2CS, base + TUL_NVRAM);		/* -CLK+dataBit 0 */
  		udelay(30);
  		outb(SE2CS | SE2CLK, base + TUL_NVRAM);		/* +CLK */
  		udelay(30);
  		val <<= 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
369
370
371
372
  	outb(SE2CS, base + TUL_NVRAM);				/* -CLK */
  	udelay(30);
  	outb(0, base + TUL_NVRAM);				/* -CS  */
  	udelay(30);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373

72d39fea9   Alan Cox   [SCSI] initio: Co...
374
375
  	outb(SE2CS, base + TUL_NVRAM);				/* +CS  */
  	udelay(30);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
377
  
  	for (;;) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
378
379
380
381
382
  		outb(SE2CS | SE2CLK, base + TUL_NVRAM);		/* +CLK */
  		udelay(30);
  		outb(SE2CS, base + TUL_NVRAM);			/* -CLK */
  		udelay(30);
  		if ((rb = inb(base + TUL_NVRAM)) & SE2DI)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383
384
  			break;	/* write complete */
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
385
  	outb(0, base + TUL_NVRAM);				/* -CS */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
387
388
389
390
391
392
393
  /**
   *	initio_se2_rd_all	-	read hostadapter NV configuration
   *	@base: Base address of InitIO controller
   *
   *	Reads the E2PROM data into main memory. Ensures that the checksum
   *	and header marker are valid. Returns 1 on success -1 on error.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394

72d39fea9   Alan Cox   [SCSI] initio: Co...
395
  static int initio_se2_rd_all(unsigned long base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
396
397
  {
  	int i;
72d39fea9   Alan Cox   [SCSI] initio: Co...
398
399
  	u16 chksum = 0;
  	u16 *np;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
401
  
  	i91unvramp = &i91unvram;
72d39fea9   Alan Cox   [SCSI] initio: Co...
402
403
404
  	np = (u16 *) i91unvramp;
  	for (i = 0; i < 32; i++)
  		*np++ = initio_se2_rd(base, i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405

72d39fea9   Alan Cox   [SCSI] initio: Co...
406
  	/* Is signature "ini" ok ? */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
408
  	if (i91unvramp->NVM_Signature != INI_SIGNATURE)
  		return -1;
72d39fea9   Alan Cox   [SCSI] initio: Co...
409
410
  	/* Is ckecksum ok ? */
  	np = (u16 *) i91unvramp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
412
  	for (i = 0; i < 31; i++)
  		chksum += *np++;
72d39fea9   Alan Cox   [SCSI] initio: Co...
413
  	if (i91unvramp->NVM_CheckSum != chksum)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414
415
416
  		return -1;
  	return 1;
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
417
418
419
420
421
422
423
424
  /**
   *	initio_se2_update_all		-	Update E2PROM
   *	@base: Base of InitIO controller
   *
   *	Update the E2PROM by wrting any changes into the E2PROM
   *	chip, rewriting the checksum.
   */
  static void initio_se2_update_all(unsigned long base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425
426
  {				/* setup default pattern */
  	int i;
72d39fea9   Alan Cox   [SCSI] initio: Co...
427
428
  	u16 chksum = 0;
  	u16 *np, *np1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
430
431
  
  	i91unvramp = &i91unvram;
  	/* Calculate checksum first */
72d39fea9   Alan Cox   [SCSI] initio: Co...
432
  	np = (u16 *) i91udftNvRam;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433
434
  	for (i = 0; i < 31; i++)
  		chksum += *np++;
72d39fea9   Alan Cox   [SCSI] initio: Co...
435
436
  	*np = chksum;
  	initio_se2_ew_en(base);	/* Enable write  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437

72d39fea9   Alan Cox   [SCSI] initio: Co...
438
439
  	np = (u16 *) i91udftNvRam;
  	np1 = (u16 *) i91unvramp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440
  	for (i = 0; i < 32; i++, np++, np1++) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
441
442
  		if (*np != *np1)
  			initio_se2_wr(base, i, *np);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
443
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
444
  	initio_se2_ew_ds(base);	/* Disable write   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
446
447
448
449
450
451
452
453
454
455
456
457
  /**
   *	initio_read_eeprom		-	Retrieve configuration
   *	@base: Base of InitIO Host Adapter
   *
   *	Retrieve the host adapter configuration data from E2Prom. If the
   *	data is invalid then the defaults are used and are also restored
   *	into the E2PROM. This forms the access point for the SCSI driver
   *	into the E2PROM layer, the other functions for the E2PROM are all
   *	internal use.
   *
   *	Must be called single threaded, uses a shared global area.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458

72d39fea9   Alan Cox   [SCSI] initio: Co...
459
  static void initio_read_eeprom(unsigned long base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
460
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
461
  	u8 gctrl;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462

72d39fea9   Alan Cox   [SCSI] initio: Co...
463
464
465
466
467
468
469
  	i91unvramp = &i91unvram;
  	/* Enable EEProm programming */
  	gctrl = inb(base + TUL_GCTRL);
  	outb(gctrl | TUL_GCTRL_EEPROM_BIT, base + TUL_GCTRL);
  	if (initio_se2_rd_all(base) != 1) {
  		initio_se2_update_all(base);	/* setup default pattern */
  		initio_se2_rd_all(base);	/* load again  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
471
472
473
  	/* Disable EEProm programming */
  	gctrl = inb(base + TUL_GCTRL);
  	outb(gctrl & ~TUL_GCTRL_EEPROM_BIT, base + TUL_GCTRL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
475
476
477
478
  /**
   *	initio_stop_bm		-	stop bus master
   *	@host: InitIO we are stopping
   *
3ad2f3fbb   Daniel Mack   tree-wide: Assort...
479
   *	Stop any pending DMA operation, aborting the DMA if necessary
72d39fea9   Alan Cox   [SCSI] initio: Co...
480
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481

72d39fea9   Alan Cox   [SCSI] initio: Co...
482
  static void initio_stop_bm(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
484
485
  	if (inb(host->addr + TUL_XStatus) & XPEND) {	/* if DMA xfer is pending, abort DMA xfer */
  		outb(TAX_X_ABT | TAX_X_CLR_FIFO, host->addr + TUL_XCmd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
486
  		/* wait Abort DMA xfer done */
72d39fea9   Alan Cox   [SCSI] initio: Co...
487
488
  		while ((inb(host->addr + TUL_Int) & XABT) == 0)
  			cpu_relax();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
490
  	outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
492
493
494
495
496
497
498
  /**
   *	initio_reset_scsi		-	Reset SCSI host controller
   *	@host: InitIO host to reset
   *	@seconds: Recovery time
   *
   *	Perform a full reset of the SCSI subsystem.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
499

72d39fea9   Alan Cox   [SCSI] initio: Co...
500
  static int initio_reset_scsi(struct initio_host * host, int seconds)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
502
  	outb(TSC_RST_BUS, host->addr + TUL_SCtrl0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503

72d39fea9   Alan Cox   [SCSI] initio: Co...
504
505
  	while (!((host->jsint = inb(host->addr + TUL_SInt)) & TSS_SCSIRST_INT))
  		cpu_relax();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506

72d39fea9   Alan Cox   [SCSI] initio: Co...
507
508
  	/* reset tulip chip */
  	outb(0, host->addr + TUL_SSignal);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
510
511
  
  	/* Stall for a while, wait for target's firmware ready,make it 2 sec ! */
  	/* SONY 5200 tape drive won't work if only stall for 1 sec */
72d39fea9   Alan Cox   [SCSI] initio: Co...
512
513
  	/* FIXME: this is a very long busy wait right now */
  	initio_do_pause(seconds * HZ);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514

72d39fea9   Alan Cox   [SCSI] initio: Co...
515
516
  	inb(host->addr + TUL_SInt);
  	return SCSI_RESET_SUCCESS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
518
519
520
521
522
523
524
525
526
527
528
529
530
531
  /**
   *	initio_init		-	set up an InitIO host adapter
   *	@host: InitIO host adapter
   *	@num_scbs: Number of SCBS
   *	@bios_addr: BIOS address
   *
   *	Set up the host adapter and devices according to the configuration
   *	retrieved from the E2PROM.
   *
   *	Locking: Calls E2PROM layer code which is not re-enterable so must
   *	run single threaded for now.
   */
  
  static void initio_init(struct initio_host * host, u8 *bios_addr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532
533
  {
  	int i;
72d39fea9   Alan Cox   [SCSI] initio: Co...
534
535
536
537
538
  	u8 *flags;
  	u8 *heads;
  
  	/* Get E2Prom configuration */
  	initio_read_eeprom(host->addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
  	if (i91unvramp->NVM_SCSIInfo[0].NVM_NumOfTarg == 8)
72d39fea9   Alan Cox   [SCSI] initio: Co...
540
  		host->max_tar = 8;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
  	else
72d39fea9   Alan Cox   [SCSI] initio: Co...
542
  		host->max_tar = 16;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
543

72d39fea9   Alan Cox   [SCSI] initio: Co...
544
  	host->config = i91unvramp->NVM_SCSIInfo[0].NVM_ChConfig1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545

72d39fea9   Alan Cox   [SCSI] initio: Co...
546
547
  	host->scsi_id = i91unvramp->NVM_SCSIInfo[0].NVM_ChSCSIID;
  	host->idmask = ~(1 << host->scsi_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548

44456d37b   Olaf Hering   [PATCH] turn many...
549
  #ifdef CHK_PARITY
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
  	/* Enable parity error response */
72d39fea9   Alan Cox   [SCSI] initio: Co...
551
  	outb(inb(host->addr + TUL_PCMD) | 0x40, host->addr + TUL_PCMD);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
552
553
554
  #endif
  
  	/* Mask all the interrupt       */
72d39fea9   Alan Cox   [SCSI] initio: Co...
555
  	outb(0x1F, host->addr + TUL_Mask);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556

72d39fea9   Alan Cox   [SCSI] initio: Co...
557
  	initio_stop_bm(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558
  	/* --- Initialize the tulip --- */
72d39fea9   Alan Cox   [SCSI] initio: Co...
559
  	outb(TSC_RST_CHIP, host->addr + TUL_SCtrl0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
560
561
  
  	/* program HBA's SCSI ID        */
72d39fea9   Alan Cox   [SCSI] initio: Co...
562
  	outb(host->scsi_id << 4, host->addr + TUL_SScsiId);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563
564
565
  
  	/* Enable Initiator Mode ,phase latch,alternate sync period mode,
  	   disable SCSI reset */
72d39fea9   Alan Cox   [SCSI] initio: Co...
566
567
  	if (host->config & HCC_EN_PAR)
  		host->sconf1 = (TSC_INITDEFAULT | TSC_EN_SCSI_PAR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568
  	else
72d39fea9   Alan Cox   [SCSI] initio: Co...
569
570
  		host->sconf1 = (TSC_INITDEFAULT);
  	outb(host->sconf1, host->addr + TUL_SConfig);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571

72d39fea9   Alan Cox   [SCSI] initio: Co...
572
573
  	/* Enable HW reselect */
  	outb(TSC_HW_RESELECT, host->addr + TUL_SCtrl1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574

72d39fea9   Alan Cox   [SCSI] initio: Co...
575
  	outb(0, host->addr + TUL_SPeriod);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
576
577
  
  	/* selection time out = 250 ms */
72d39fea9   Alan Cox   [SCSI] initio: Co...
578
  	outb(153, host->addr + TUL_STimeOut);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
579

72d39fea9   Alan Cox   [SCSI] initio: Co...
580
581
582
583
584
585
  	/* Enable SCSI terminator */
  	outb((host->config & (HCC_ACT_TERM1 | HCC_ACT_TERM2)),
  		host->addr + TUL_XCtrl);
  	outb(((host->config & HCC_AUTO_TERM) >> 4) |
  		(inb(host->addr + TUL_GCTRL1) & 0xFE),
  		host->addr + TUL_GCTRL1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
586
587
  
  	for (i = 0,
72d39fea9   Alan Cox   [SCSI] initio: Co...
588
589
590
591
592
593
594
  	     flags = & (i91unvramp->NVM_SCSIInfo[0].NVM_Targ0Config),
  	     heads = bios_addr + 0x180;
  	     i < host->max_tar;
  	     i++, flags++) {
  		host->targets[i].flags = *flags & ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
  		if (host->targets[i].flags & TCF_EN_255)
  			host->targets[i].drv_flags = TCF_DRV_255_63;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
595
  		else
72d39fea9   Alan Cox   [SCSI] initio: Co...
596
597
598
599
600
601
  			host->targets[i].drv_flags = 0;
  		host->targets[i].js_period = 0;
  		host->targets[i].sconfig0 = host->sconf1;
  		host->targets[i].heads = *heads++;
  		if (host->targets[i].heads == 255)
  			host->targets[i].drv_flags = TCF_DRV_255_63;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
  		else
72d39fea9   Alan Cox   [SCSI] initio: Co...
603
604
605
606
607
  			host->targets[i].drv_flags = 0;
  		host->targets[i].sectors = *heads++;
  		host->targets[i].flags &= ~TCF_BUSY;
  		host->act_tags[i] = 0;
  		host->max_tags[i] = 0xFF;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
608
609
610
  	}			/* for                          */
  	printk("i91u: PCI Base=0x%04X, IRQ=%d, BIOS=0x%04X0, SCSI ID=%d
  ",
e9e42faf4   Alan Cox   [SCSI] initio: Fi...
611
  	       host->addr, host->pci_dev->irq,
72d39fea9   Alan Cox   [SCSI] initio: Co...
612
613
614
615
616
617
  	       host->bios_addr, host->scsi_id);
  	/* Reset SCSI Bus */
  	if (host->config & HCC_SCSI_RESET) {
  		printk(KERN_INFO "i91u: Reset SCSI Bus ... 
  ");
  		initio_reset_scsi(host, 10);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
618
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
619
620
  	outb(0x17, host->addr + TUL_SCFG1);
  	outb(0xE9, host->addr + TUL_SIntEnable);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
622
623
624
625
626
627
628
629
  /**
   *	initio_alloc_scb		-	Allocate an SCB
   *	@host: InitIO host we are allocating for
   *
   *	Walk the SCB list for the controller and allocate a free SCB if
   *	one exists.
   */
  static struct scsi_ctrl_blk *initio_alloc_scb(struct initio_host *host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
631
632
633
634
635
  	struct scsi_ctrl_blk *scb;
  	unsigned long flags;
  
  	spin_lock_irqsave(&host->avail_lock, flags);
  	if ((scb = host->first_avail) != NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636
  #if DEBUG_QUEUE
72d39fea9   Alan Cox   [SCSI] initio: Co...
637
638
  		printk("find scb at %p
  ", scb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
639
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
640
641
642
643
  		if ((host->first_avail = scb->next) == NULL)
  			host->last_avail = NULL;
  		scb->next = NULL;
  		scb->status = SCB_RENT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
645
646
  	spin_unlock_irqrestore(&host->avail_lock, flags);
  	return scb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
648
649
650
651
652
653
654
655
656
  /**
   *	initio_release_scb		-	Release an SCB
   *	@host: InitIO host that owns the SCB
   *	@cmnd: SCB command block being returned
   *
   *	Return an allocated SCB to the host free list
   */
  
  static void initio_release_scb(struct initio_host * host, struct scsi_ctrl_blk * cmnd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
657
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
658
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659
660
  
  #if DEBUG_QUEUE
72d39fea9   Alan Cox   [SCSI] initio: Co...
661
  	printk("Release SCB %p; ", cmnd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
663
664
665
666
667
668
669
  	spin_lock_irqsave(&(host->avail_lock), flags);
  	cmnd->srb = NULL;
  	cmnd->status = 0;
  	cmnd->next = NULL;
  	if (host->last_avail != NULL) {
  		host->last_avail->next = cmnd;
  		host->last_avail = cmnd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670
  	} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
671
672
  		host->first_avail = cmnd;
  		host->last_avail = cmnd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
673
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
674
  	spin_unlock_irqrestore(&(host->avail_lock), flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
675
676
677
  }
  
  /***************************************************************************/
72d39fea9   Alan Cox   [SCSI] initio: Co...
678
  static void initio_append_pend_scb(struct initio_host * host, struct scsi_ctrl_blk * scbp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
679
680
681
  {
  
  #if DEBUG_QUEUE
72d39fea9   Alan Cox   [SCSI] initio: Co...
682
  	printk("Append pend SCB %p; ", scbp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
683
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
684
685
686
687
688
  	scbp->status = SCB_PEND;
  	scbp->next = NULL;
  	if (host->last_pending != NULL) {
  		host->last_pending->next = scbp;
  		host->last_pending = scbp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
689
  	} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
690
691
  		host->first_pending = scbp;
  		host->last_pending = scbp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
693
694
695
  	}
  }
  
  /***************************************************************************/
72d39fea9   Alan Cox   [SCSI] initio: Co...
696
  static void initio_push_pend_scb(struct initio_host * host, struct scsi_ctrl_blk * scbp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697
698
699
  {
  
  #if DEBUG_QUEUE
72d39fea9   Alan Cox   [SCSI] initio: Co...
700
  	printk("Push pend SCB %p; ", scbp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
701
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
702
703
704
  	scbp->status = SCB_PEND;
  	if ((scbp->next = host->first_pending) != NULL) {
  		host->first_pending = scbp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
705
  	} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
706
707
  		host->first_pending = scbp;
  		host->last_pending = scbp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
708
709
  	}
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
710
  static struct scsi_ctrl_blk *initio_find_first_pend_scb(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
711
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
712
  	struct scsi_ctrl_blk *first;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
713

72d39fea9   Alan Cox   [SCSI] initio: Co...
714
715
716
717
718
719
720
721
  	first = host->first_pending;
  	while (first != NULL) {
  		if (first->opcode != ExecSCSI)
  			return first;
  		if (first->tagmsg == 0) {
  			if ((host->act_tags[first->target] == 0) &&
  			    !(host->targets[first->target].flags & TCF_BUSY))
  				return first;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
  		} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
723
724
725
726
  			if ((host->act_tags[first->target] >=
  			  host->max_tags[first->target]) |
  			    (host->targets[first->target].flags & TCF_BUSY)) {
  				first = first->next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
728
  				continue;
  			}
72d39fea9   Alan Cox   [SCSI] initio: Co...
729
  			return first;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
731
  		first = first->next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
732
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
733
  	return first;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
735
736
  
  static void initio_unlink_pend_scb(struct initio_host * host, struct scsi_ctrl_blk * scb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
737
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
738
  	struct scsi_ctrl_blk *tmp, *prev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
739
740
  
  #if DEBUG_QUEUE
72d39fea9   Alan Cox   [SCSI] initio: Co...
741
  	printk("unlink pend SCB %p; ", scb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
742
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
743
744
745
746
747
748
  	prev = tmp = host->first_pending;
  	while (tmp != NULL) {
  		if (scb == tmp) {	/* Unlink this SCB              */
  			if (tmp == host->first_pending) {
  				if ((host->first_pending = tmp->next) == NULL)
  					host->last_pending = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
749
  			} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
750
751
752
  				prev->next = tmp->next;
  				if (tmp == host->last_pending)
  					host->last_pending = prev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
  			}
72d39fea9   Alan Cox   [SCSI] initio: Co...
754
  			tmp->next = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
755
756
  			break;
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
757
758
  		prev = tmp;
  		tmp = tmp->next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
759
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
760
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
761
762
  
  static void initio_append_busy_scb(struct initio_host * host, struct scsi_ctrl_blk * scbp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
763
764
765
  {
  
  #if DEBUG_QUEUE
e2d435ea4   Stuart Swales   [SCSI] initio: fi...
766
  	printk("append busy SCB %p; ", scbp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
767
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
768
769
  	if (scbp->tagmsg)
  		host->act_tags[scbp->target]++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
770
  	else
72d39fea9   Alan Cox   [SCSI] initio: Co...
771
772
773
774
775
776
  		host->targets[scbp->target].flags |= TCF_BUSY;
  	scbp->status = SCB_BUSY;
  	scbp->next = NULL;
  	if (host->last_busy != NULL) {
  		host->last_busy->next = scbp;
  		host->last_busy = scbp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777
  	} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
778
779
  		host->first_busy = scbp;
  		host->last_busy = scbp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
780
781
782
783
  	}
  }
  
  /***************************************************************************/
72d39fea9   Alan Cox   [SCSI] initio: Co...
784
  static struct scsi_ctrl_blk *initio_pop_busy_scb(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
785
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
786
  	struct scsi_ctrl_blk *tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
787

72d39fea9   Alan Cox   [SCSI] initio: Co...
788
789
790
791
792
793
  	if ((tmp = host->first_busy) != NULL) {
  		if ((host->first_busy = tmp->next) == NULL)
  			host->last_busy = NULL;
  		tmp->next = NULL;
  		if (tmp->tagmsg)
  			host->act_tags[tmp->target]--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
794
  		else
72d39fea9   Alan Cox   [SCSI] initio: Co...
795
  			host->targets[tmp->target].flags &= ~TCF_BUSY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
796
797
  	}
  #if DEBUG_QUEUE
72d39fea9   Alan Cox   [SCSI] initio: Co...
798
  	printk("Pop busy SCB %p; ", tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
799
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
800
  	return tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
801
802
803
  }
  
  /***************************************************************************/
72d39fea9   Alan Cox   [SCSI] initio: Co...
804
  static void initio_unlink_busy_scb(struct initio_host * host, struct scsi_ctrl_blk * scb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
805
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
806
  	struct scsi_ctrl_blk *tmp, *prev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807
808
  
  #if DEBUG_QUEUE
72d39fea9   Alan Cox   [SCSI] initio: Co...
809
  	printk("unlink busy SCB %p; ", scb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
810
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
811
812
813
814
815
816
  	prev = tmp = host->first_busy;
  	while (tmp != NULL) {
  		if (scb == tmp) {	/* Unlink this SCB              */
  			if (tmp == host->first_busy) {
  				if ((host->first_busy = tmp->next) == NULL)
  					host->last_busy = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
817
  			} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
818
819
820
  				prev->next = tmp->next;
  				if (tmp == host->last_busy)
  					host->last_busy = prev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
821
  			}
72d39fea9   Alan Cox   [SCSI] initio: Co...
822
823
824
  			tmp->next = NULL;
  			if (tmp->tagmsg)
  				host->act_tags[tmp->target]--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
825
  			else
72d39fea9   Alan Cox   [SCSI] initio: Co...
826
  				host->targets[tmp->target].flags &= ~TCF_BUSY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827
828
  			break;
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
829
830
  		prev = tmp;
  		tmp = tmp->next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831
832
833
  	}
  	return;
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
834
  struct scsi_ctrl_blk *initio_find_busy_scb(struct initio_host * host, u16 tarlun)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
835
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
836
837
  	struct scsi_ctrl_blk *tmp, *prev;
  	u16 scbp_tarlun;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
838

72d39fea9   Alan Cox   [SCSI] initio: Co...
839
840
841
  	prev = tmp = host->first_busy;
  	while (tmp != NULL) {
  		scbp_tarlun = (tmp->lun << 8) | (tmp->target);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
842
843
844
  		if (scbp_tarlun == tarlun) {	/* Unlink this SCB              */
  			break;
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
845
846
  		prev = tmp;
  		tmp = tmp->next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
847
848
  	}
  #if DEBUG_QUEUE
72d39fea9   Alan Cox   [SCSI] initio: Co...
849
  	printk("find busy SCB %p; ", tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
850
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
851
  	return tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
852
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
853
  static void initio_append_done_scb(struct initio_host * host, struct scsi_ctrl_blk * scbp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
854
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
855
  #if DEBUG_QUEUE
72d39fea9   Alan Cox   [SCSI] initio: Co...
856
  	printk("append done SCB %p; ", scbp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
857
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
858
859
860
861
862
  	scbp->status = SCB_DONE;
  	scbp->next = NULL;
  	if (host->last_done != NULL) {
  		host->last_done->next = scbp;
  		host->last_done = scbp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
863
  	} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
864
865
  		host->first_done = scbp;
  		host->last_done = scbp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
866
867
  	}
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
868
  struct scsi_ctrl_blk *initio_find_done_scb(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
869
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
870
  	struct scsi_ctrl_blk *tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
871

72d39fea9   Alan Cox   [SCSI] initio: Co...
872
873
874
875
  	if ((tmp = host->first_done) != NULL) {
  		if ((host->first_done = tmp->next) == NULL)
  			host->last_done = NULL;
  		tmp->next = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
876
877
  	}
  #if DEBUG_QUEUE
72d39fea9   Alan Cox   [SCSI] initio: Co...
878
  	printk("find done SCB %p; ",tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
879
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
880
  	return tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
881
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
882
  static int initio_abort_srb(struct initio_host * host, struct scsi_cmnd *srbp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
883
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
884
885
  	unsigned long flags;
  	struct scsi_ctrl_blk *tmp, *prev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
886

72d39fea9   Alan Cox   [SCSI] initio: Co...
887
  	spin_lock_irqsave(&host->semaph_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
888

72d39fea9   Alan Cox   [SCSI] initio: Co...
889
  	if ((host->semaph == 0) && (host->active == NULL)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
890
  		/* disable Jasmin SCSI Int        */
72d39fea9   Alan Cox   [SCSI] initio: Co...
891
892
893
894
895
896
897
898
  		outb(0x1F, host->addr + TUL_Mask);
  		spin_unlock_irqrestore(&host->semaph_lock, flags);
  		/* FIXME: synchronize_irq needed ? */
  		tulip_main(host);
  		spin_lock_irqsave(&host->semaph_lock, flags);
  		host->semaph = 1;
  		outb(0x0F, host->addr + TUL_Mask);
  		spin_unlock_irqrestore(&host->semaph_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
899
900
  		return SCSI_ABORT_SNOOZE;
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
901
902
  	prev = tmp = host->first_pending;	/* Check Pend queue */
  	while (tmp != NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
903
  		/* 07/27/98 */
72d39fea9   Alan Cox   [SCSI] initio: Co...
904
905
906
  		if (tmp->srb == srbp) {
  			if (tmp == host->active) {
  				spin_unlock_irqrestore(&host->semaph_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
907
  				return SCSI_ABORT_BUSY;
72d39fea9   Alan Cox   [SCSI] initio: Co...
908
909
910
  			} else if (tmp == host->first_pending) {
  				if ((host->first_pending = tmp->next) == NULL)
  					host->last_pending = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
911
  			} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
912
913
914
  				prev->next = tmp->next;
  				if (tmp == host->last_pending)
  					host->last_pending = prev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
915
  			}
72d39fea9   Alan Cox   [SCSI] initio: Co...
916
917
918
919
920
  			tmp->hastat = HOST_ABORTED;
  			tmp->flags |= SCF_DONE;
  			if (tmp->flags & SCF_POST)
  				(*tmp->post) ((u8 *) host, (u8 *) tmp);
  			spin_unlock_irqrestore(&host->semaph_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
921
922
  			return SCSI_ABORT_SUCCESS;
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
923
924
  		prev = tmp;
  		tmp = tmp->next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
925
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
926
927
928
929
930
  	prev = tmp = host->first_busy;	/* Check Busy queue */
  	while (tmp != NULL) {
  		if (tmp->srb == srbp) {
  			if (tmp == host->active) {
  				spin_unlock_irqrestore(&host->semaph_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
931
  				return SCSI_ABORT_BUSY;
72d39fea9   Alan Cox   [SCSI] initio: Co...
932
933
  			} else if (tmp->tagmsg == 0) {
  				spin_unlock_irqrestore(&host->semaph_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
934
935
  				return SCSI_ABORT_BUSY;
  			} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
936
937
938
939
  				host->act_tags[tmp->target]--;
  				if (tmp == host->first_busy) {
  					if ((host->first_busy = tmp->next) == NULL)
  						host->last_busy = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
940
  				} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
941
942
943
  					prev->next = tmp->next;
  					if (tmp == host->last_busy)
  						host->last_busy = prev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
944
  				}
72d39fea9   Alan Cox   [SCSI] initio: Co...
945
  				tmp->next = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
946

72d39fea9   Alan Cox   [SCSI] initio: Co...
947
948
949
950
951
  				tmp->hastat = HOST_ABORTED;
  				tmp->flags |= SCF_DONE;
  				if (tmp->flags & SCF_POST)
  					(*tmp->post) ((u8 *) host, (u8 *) tmp);
  				spin_unlock_irqrestore(&host->semaph_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
952
953
954
  				return SCSI_ABORT_SUCCESS;
  			}
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
955
956
  		prev = tmp;
  		tmp = tmp->next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
957
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
958
959
  	spin_unlock_irqrestore(&host->semaph_lock, flags);
  	return SCSI_ABORT_NOT_RUNNING;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
960
961
962
  }
  
  /***************************************************************************/
72d39fea9   Alan Cox   [SCSI] initio: Co...
963
  static int initio_bad_seq(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
964
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
965
  	struct scsi_ctrl_blk *scb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
966

72d39fea9   Alan Cox   [SCSI] initio: Co...
967
968
  	printk("initio_bad_seg c=%d
  ", host->index);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
969

72d39fea9   Alan Cox   [SCSI] initio: Co...
970
971
972
973
974
  	if ((scb = host->active) != NULL) {
  		initio_unlink_busy_scb(host, scb);
  		scb->hastat = HOST_BAD_PHAS;
  		scb->tastat = 0;
  		initio_append_done_scb(host, scb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
975
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
976
977
978
  	initio_stop_bm(host);
  	initio_reset_scsi(host, 8);	/* 7/29/98 */
  	return initio_post_scsi_rst(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
979
  }
a2ba192c9   Adrian Bunk   [PATCH] drivers/s...
980

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
981
  /************************************************************************/
72d39fea9   Alan Cox   [SCSI] initio: Co...
982
  static void initio_exec_scb(struct initio_host * host, struct scsi_ctrl_blk * scb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
983
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
984
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
985

72d39fea9   Alan Cox   [SCSI] initio: Co...
986
  	scb->mode = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
987

72d39fea9   Alan Cox   [SCSI] initio: Co...
988
989
  	scb->sgidx = 0;
  	scb->sgmax = scb->sglen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
990

72d39fea9   Alan Cox   [SCSI] initio: Co...
991
  	spin_lock_irqsave(&host->semaph_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
992

72d39fea9   Alan Cox   [SCSI] initio: Co...
993
  	initio_append_pend_scb(host, scb);	/* Append this SCB to Pending queue */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
994
995
  
  /* VVVVV 07/21/98 */
72d39fea9   Alan Cox   [SCSI] initio: Co...
996
997
998
999
1000
  	if (host->semaph == 1) {
  		/* Disable Jasmin SCSI Int */
  		outb(0x1F, host->addr + TUL_Mask);
  		host->semaph = 0;
  		spin_unlock_irqrestore(&host->semaph_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1001

72d39fea9   Alan Cox   [SCSI] initio: Co...
1002
  		tulip_main(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1003

72d39fea9   Alan Cox   [SCSI] initio: Co...
1004
1005
1006
  		spin_lock_irqsave(&host->semaph_lock, flags);
  		host->semaph = 1;
  		outb(0x0F, host->addr + TUL_Mask);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1007
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1008
  	spin_unlock_irqrestore(&host->semaph_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1009
1010
1011
1012
  	return;
  }
  
  /***************************************************************************/
72d39fea9   Alan Cox   [SCSI] initio: Co...
1013
  static int initio_isr(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1014
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1015
1016
1017
  	if (inb(host->addr + TUL_Int) & TSS_INT_PENDING) {
  		if (host->semaph == 1) {
  			outb(0x1F, host->addr + TUL_Mask);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1018
  			/* Disable Tulip SCSI Int */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1019
  			host->semaph = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1020

72d39fea9   Alan Cox   [SCSI] initio: Co...
1021
  			tulip_main(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1022

72d39fea9   Alan Cox   [SCSI] initio: Co...
1023
1024
1025
  			host->semaph = 1;
  			outb(0x0F, host->addr + TUL_Mask);
  			return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1026
1027
  		}
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1028
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1029
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1030
  static int tulip_main(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1031
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1032
  	struct scsi_ctrl_blk *scb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1033
1034
  
  	for (;;) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1035
1036
1037
1038
1039
1040
1041
1042
1043
  		tulip_scsi(host);	/* Call tulip_scsi              */
  
  		/* Walk the list of completed SCBs */
  		while ((scb = initio_find_done_scb(host)) != NULL) {	/* find done entry */
  			if (scb->tastat == INI_QUEUE_FULL) {
  				host->max_tags[scb->target] =
  				    host->act_tags[scb->target] - 1;
  				scb->tastat = 0;
  				initio_append_pend_scb(host, scb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1044
1045
  				continue;
  			}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1046
1047
  			if (!(scb->mode & SCM_RSENS)) {		/* not in auto req. sense mode */
  				if (scb->tastat == 2) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1048
1049
  
  					/* clr sync. nego flag */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1050
1051
1052
  					if (scb->flags & SCF_SENSE) {
  						u8 len;
  						len = scb->senselen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1053
1054
  						if (len == 0)
  							len = 1;
72d39fea9   Alan Cox   [SCSI] initio: Co...
1055
1056
1057
1058
  						scb->buflen = scb->senselen;
  						scb->bufptr = scb->senseptr;
  						scb->flags &= ~(SCF_SG | SCF_DIR);	/* for xfer_data_in */
  						/* so, we won't report wrong direction in xfer_data_in,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1059
  						   and won't report HOST_DO_DU in state_6 */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
  						scb->mode = SCM_RSENS;
  						scb->ident &= 0xBF;	/* Disable Disconnect */
  						scb->tagmsg = 0;
  						scb->tastat = 0;
  						scb->cdblen = 6;
  						scb->cdb[0] = SCSICMD_RequestSense;
  						scb->cdb[1] = 0;
  						scb->cdb[2] = 0;
  						scb->cdb[3] = 0;
  						scb->cdb[4] = len;
  						scb->cdb[5] = 0;
  						initio_push_pend_scb(host, scb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1072
1073
1074
1075
  						break;
  					}
  				}
  			} else {	/* in request sense mode */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1076
  				if (scb->tastat == 2) {		/* check contition status again after sending
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1077
  									   requset sense cmd 0x3 */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1078
  					scb->hastat = HOST_BAD_PHAS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1079
  				}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1080
  				scb->tastat = 2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1081
  			}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1082
1083
1084
1085
  			scb->flags |= SCF_DONE;
  			if (scb->flags & SCF_POST) {
  				/* FIXME: only one post method and lose casts */
  				(*scb->post) ((u8 *) host, (u8 *) scb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1086
1087
  			}
  		}		/* while */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1088
  		/* find_active: */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1089
  		if (inb(host->addr + TUL_SStatus0) & TSS_INT_PENDING)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1090
  			continue;
72d39fea9   Alan Cox   [SCSI] initio: Co...
1091
  		if (host->active)	/* return to OS and wait for xfer_done_ISR/Selected_ISR */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1092
  			return 1;	/* return to OS, enable interrupt */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1093
  		/* Check pending SCB            */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1094
  		if (initio_find_first_pend_scb(host) == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1095
  			return 1;	/* return to OS, enable interrupt */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1096
1097
1098
  	}			/* End of for loop */
  	/* statement won't reach here */
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1099
  static void tulip_scsi(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1100
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1101
1102
  	struct scsi_ctrl_blk *scb;
  	struct target_control *active_tc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1103
1104
  
  	/* make sure to service interrupt asap */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1105
1106
1107
1108
1109
1110
  	if ((host->jsstatus0 = inb(host->addr + TUL_SStatus0)) & TSS_INT_PENDING) {
  		host->phase = host->jsstatus0 & TSS_PH_MASK;
  		host->jsstatus1 = inb(host->addr + TUL_SStatus1);
  		host->jsint = inb(host->addr + TUL_SInt);
  		if (host->jsint & TSS_SCSIRST_INT) {	/* SCSI bus reset detected      */
  			int_initio_scsi_rst(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1111
1112
  			return;
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1113
1114
1115
  		if (host->jsint & TSS_RESEL_INT) {	/* if selected/reselected interrupt */
  			if (int_initio_resel(host) == 0)
  				initio_next_state(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1116
1117
  			return;
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1118
1119
  		if (host->jsint & TSS_SEL_TIMEOUT) {
  			int_initio_busfree(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1120
1121
  			return;
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1122
1123
  		if (host->jsint & TSS_DISC_INT) {	/* BUS disconnection            */
  			int_initio_busfree(host);	/* unexpected bus free or sel timeout */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1124
1125
  			return;
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1126
1127
1128
  		if (host->jsint & (TSS_FUNC_COMP | TSS_BUS_SERV)) {	/* func complete or Bus service */
  			if ((scb = host->active) != NULL)
  				initio_next_state(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1129
1130
1131
  			return;
  		}
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1132
  	if (host->active != NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1133
  		return;
72d39fea9   Alan Cox   [SCSI] initio: Co...
1134
  	if ((scb = initio_find_first_pend_scb(host)) == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1135
1136
1137
  		return;
  
  	/* program HBA's SCSI ID & target SCSI ID */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1138
1139
1140
1141
  	outb((host->scsi_id << 4) | (scb->target & 0x0F),
  		host->addr + TUL_SScsiId);
  	if (scb->opcode == ExecSCSI) {
  		active_tc = &host->targets[scb->target];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1142

72d39fea9   Alan Cox   [SCSI] initio: Co...
1143
1144
  		if (scb->tagmsg)
  			active_tc->drv_flags |= TCF_DRV_EN_TAG;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1145
  		else
72d39fea9   Alan Cox   [SCSI] initio: Co...
1146
  			active_tc->drv_flags &= ~TCF_DRV_EN_TAG;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1147

72d39fea9   Alan Cox   [SCSI] initio: Co...
1148
1149
1150
  		outb(active_tc->js_period, host->addr + TUL_SPeriod);
  		if ((active_tc->flags & (TCF_WDTR_DONE | TCF_NO_WDTR)) == 0) {	/* do wdtr negotiation          */
  			initio_select_atn_stop(host, scb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1151
  		} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1152
1153
  			if ((active_tc->flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) {	/* do sync negotiation          */
  				initio_select_atn_stop(host, scb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1154
  			} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1155
1156
  				if (scb->tagmsg)
  					initio_select_atn3(host, scb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1157
  				else
72d39fea9   Alan Cox   [SCSI] initio: Co...
1158
  					initio_select_atn(host, scb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1159
1160
  			}
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1161
1162
1163
  		if (scb->flags & SCF_POLL) {
  			while (wait_tulip(host) != -1) {
  				if (initio_next_state(host) == -1)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1164
1165
1166
  					break;
  			}
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1167
1168
1169
1170
1171
1172
  	} else if (scb->opcode == BusDevRst) {
  		initio_select_atn_stop(host, scb);
  		scb->next_state = 8;
  		if (scb->flags & SCF_POLL) {
  			while (wait_tulip(host) != -1) {
  				if (initio_next_state(host) == -1)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1173
1174
1175
  					break;
  			}
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1176
1177
1178
1179
  	} else if (scb->opcode == AbortCmd) {
  		if (initio_abort_srb(host, scb->srb) != 0) {
  			initio_unlink_pend_scb(host, scb);
  			initio_release_scb(host, scb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1180
  		} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1181
1182
1183
  			scb->opcode = BusDevRst;
  			initio_select_atn_stop(host, scb);
  			scb->next_state = 8;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1184
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1185
  	} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1186
1187
1188
  		initio_unlink_pend_scb(host, scb);
  		scb->hastat = 0x16;	/* bad command */
  		initio_append_done_scb(host, scb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1189
1190
1191
  	}
  	return;
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1192
1193
1194
1195
1196
1197
1198
1199
1200
  /**
   *	initio_next_state		-	Next SCSI state
   *	@host: InitIO host we are processing
   *
   *	Progress the active command block along the state machine
   *	until we hit a state which we must wait for activity to occur.
   *
   *	Returns zero or a negative code.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1201

72d39fea9   Alan Cox   [SCSI] initio: Co...
1202
  static int initio_next_state(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1203
1204
  {
  	int next;
72d39fea9   Alan Cox   [SCSI] initio: Co...
1205
  	next = host->active->next_state;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1206
1207
1208
  	for (;;) {
  		switch (next) {
  		case 1:
72d39fea9   Alan Cox   [SCSI] initio: Co...
1209
  			next = initio_state_1(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1210
1211
  			break;
  		case 2:
72d39fea9   Alan Cox   [SCSI] initio: Co...
1212
  			next = initio_state_2(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1213
1214
  			break;
  		case 3:
72d39fea9   Alan Cox   [SCSI] initio: Co...
1215
  			next = initio_state_3(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1216
1217
  			break;
  		case 4:
72d39fea9   Alan Cox   [SCSI] initio: Co...
1218
  			next = initio_state_4(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1219
1220
  			break;
  		case 5:
72d39fea9   Alan Cox   [SCSI] initio: Co...
1221
  			next = initio_state_5(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1222
1223
  			break;
  		case 6:
72d39fea9   Alan Cox   [SCSI] initio: Co...
1224
  			next = initio_state_6(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1225
1226
  			break;
  		case 7:
72d39fea9   Alan Cox   [SCSI] initio: Co...
1227
  			next = initio_state_7(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1228
1229
  			break;
  		case 8:
72d39fea9   Alan Cox   [SCSI] initio: Co...
1230
  			return initio_bus_device_reset(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1231
  		default:
72d39fea9   Alan Cox   [SCSI] initio: Co...
1232
  			return initio_bad_seq(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1233
1234
1235
1236
1237
  		}
  		if (next <= 0)
  			return next;
  	}
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1238
1239
1240
1241
1242
1243
1244
1245
  /**
   *	initio_state_1		-	SCSI state machine
   *	@host: InitIO host we are controlling
   *
   *	Perform SCSI state processing for Select/Attention/Stop
   */
  
  static int initio_state_1(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1246
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1247
1248
  	struct scsi_ctrl_blk *scb = host->active;
  	struct target_control *active_tc = host->active_tc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1249
1250
1251
  #if DEBUG_STATE
  	printk("-s1-");
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
1252
1253
1254
  	/* Move the SCB from pending to busy */
  	initio_unlink_pend_scb(host, scb);
  	initio_append_busy_scb(host, scb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1255

72d39fea9   Alan Cox   [SCSI] initio: Co...
1256
  	outb(active_tc->sconfig0, host->addr + TUL_SConfig );
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1257
  	/* ATN on */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
  	if (host->phase == MSG_OUT) {
  		outb(TSC_EN_BUS_IN | TSC_HW_RESELECT, host->addr + TUL_SCtrl1);
  		outb(scb->ident, host->addr + TUL_SFifo);
  
  		if (scb->tagmsg) {
  			outb(scb->tagmsg, host->addr + TUL_SFifo);
  			outb(scb->tagid, host->addr + TUL_SFifo);
  		}
  		if ((active_tc->flags & (TCF_WDTR_DONE | TCF_NO_WDTR)) == 0) {
  			active_tc->flags |= TCF_WDTR_DONE;
  			outb(MSG_EXTEND, host->addr + TUL_SFifo);
  			outb(2, host->addr + TUL_SFifo);	/* Extended msg length */
  			outb(3, host->addr + TUL_SFifo);	/* Sync request */
  			outb(1, host->addr + TUL_SFifo);	/* Start from 16 bits */
  		} else if ((active_tc->flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) {
  			active_tc->flags |= TCF_SYNC_DONE;
  			outb(MSG_EXTEND, host->addr + TUL_SFifo);
  			outb(3, host->addr + TUL_SFifo);	/* extended msg length */
  			outb(1, host->addr + TUL_SFifo);	/* sync request */
  			outb(initio_rate_tbl[active_tc->flags & TCF_SCSI_RATE], host->addr + TUL_SFifo);
  			outb(MAX_OFFSET, host->addr + TUL_SFifo);	/* REQ/ACK offset */
  		}
  		outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
  		if (wait_tulip(host) == -1)
  			return -1;
  	}
  	outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
  	outb((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)), host->addr + TUL_SSignal);
  	/* Into before CDB xfer */
  	return 3;
  }
  
  
  /**
   *	initio_state_2		-	SCSI state machine
   *	@host: InitIO host we are controlling
   *
   * state after selection with attention
   * state after selection with attention3
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1298

72d39fea9   Alan Cox   [SCSI] initio: Co...
1299
  static int initio_state_2(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1300
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1301
1302
  	struct scsi_ctrl_blk *scb = host->active;
  	struct target_control *active_tc = host->active_tc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1303
1304
1305
  #if DEBUG_STATE
  	printk("-s2-");
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
1306
1307
  	initio_unlink_pend_scb(host, scb);
  	initio_append_busy_scb(host, scb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1308

72d39fea9   Alan Cox   [SCSI] initio: Co...
1309
  	outb(active_tc->sconfig0, host->addr + TUL_SConfig);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1310

72d39fea9   Alan Cox   [SCSI] initio: Co...
1311
1312
1313
1314
1315
1316
1317
  	if (host->jsstatus1 & TSS_CMD_PH_CMP)
  		return 4;
  
  	outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
  	outb((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)), host->addr + TUL_SSignal);
  	/* Into before CDB xfer */
  	return 3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1318
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1319
1320
1321
1322
1323
1324
1325
1326
  /**
   *	initio_state_3		-	SCSI state machine
   *	@host: InitIO host we are controlling
   *
   * state before CDB xfer is done
   */
  
  static int initio_state_3(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1327
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1328
1329
  	struct scsi_ctrl_blk *scb = host->active;
  	struct target_control *active_tc = host->active_tc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1330
1331
1332
1333
1334
1335
  	int i;
  
  #if DEBUG_STATE
  	printk("-s3-");
  #endif
  	for (;;) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1336
  		switch (host->phase) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1337
  		case CMD_OUT:	/* Command out phase            */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1338
1339
1340
1341
1342
1343
1344
1345
  			for (i = 0; i < (int) scb->cdblen; i++)
  				outb(scb->cdb[i], host->addr + TUL_SFifo);
  			outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
  			if (wait_tulip(host) == -1)
  				return -1;
  			if (host->phase == CMD_OUT)
  				return initio_bad_seq(host);
  			return 4;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1346
1347
  
  		case MSG_IN:	/* Message in phase             */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1348
1349
1350
  			scb->next_state = 3;
  			if (initio_msgin(host) == -1)
  				return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1351
1352
1353
  			break;
  
  		case STATUS_IN:	/* Status phase                 */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1354
1355
  			if (initio_status_msg(host) == -1)
  				return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1356
1357
1358
  			break;
  
  		case MSG_OUT:	/* Message out phase            */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1359
1360
1361
1362
1363
  			if (active_tc->flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) {
  				outb(MSG_NOP, host->addr + TUL_SFifo);		/* msg nop */
  				outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
  				if (wait_tulip(host) == -1)
  					return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1364
  			} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
  				active_tc->flags |= TCF_SYNC_DONE;
  
  				outb(MSG_EXTEND, host->addr + TUL_SFifo);
  				outb(3, host->addr + TUL_SFifo);	/* ext. msg len */
  				outb(1, host->addr + TUL_SFifo);	/* sync request */
  				outb(initio_rate_tbl[active_tc->flags & TCF_SCSI_RATE], host->addr + TUL_SFifo);
  				outb(MAX_OFFSET, host->addr + TUL_SFifo);	/* REQ/ACK offset */
  				outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
  				if (wait_tulip(host) == -1)
  					return -1;
  				outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
  				outb(inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7), host->addr + TUL_SSignal);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1377
1378
1379
  
  			}
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1380
  		default:
72d39fea9   Alan Cox   [SCSI] initio: Co...
1381
  			return initio_bad_seq(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1382
1383
1384
  		}
  	}
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1385
1386
1387
1388
1389
1390
  /**
   *	initio_state_4		-	SCSI state machine
   *	@host: InitIO host we are controlling
   *
   *	SCSI state machine. State 4
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1391

72d39fea9   Alan Cox   [SCSI] initio: Co...
1392
  static int initio_state_4(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1393
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1394
  	struct scsi_ctrl_blk *scb = host->active;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1395
1396
1397
1398
  
  #if DEBUG_STATE
  	printk("-s4-");
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
1399
1400
  	if ((scb->flags & SCF_DIR) == SCF_NO_XF) {
  		return 6;	/* Go to state 6 (After data) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1401
1402
  	}
  	for (;;) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1403
1404
  		if (scb->buflen == 0)
  			return 6;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1405

72d39fea9   Alan Cox   [SCSI] initio: Co...
1406
  		switch (host->phase) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1407
1408
  
  		case STATUS_IN:	/* Status phase                 */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1409
1410
1411
1412
  			if ((scb->flags & SCF_DIR) != 0)	/* if direction bit set then report data underrun */
  				scb->hastat = HOST_DO_DU;
  			if ((initio_status_msg(host)) == -1)
  				return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1413
1414
1415
  			break;
  
  		case MSG_IN:	/* Message in phase             */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1416
1417
1418
  			scb->next_state = 0x4;
  			if (initio_msgin(host) == -1)
  				return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1419
1420
1421
  			break;
  
  		case MSG_OUT:	/* Message out phase            */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1422
1423
1424
1425
1426
1427
  			if (host->jsstatus0 & TSS_PAR_ERROR) {
  				scb->buflen = 0;
  				scb->hastat = HOST_DO_DU;
  				if (initio_msgout_ide(host) == -1)
  					return -1;
  				return 6;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1428
  			} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1429
1430
1431
1432
  				outb(MSG_NOP, host->addr + TUL_SFifo);		/* msg nop */
  				outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
  				if (wait_tulip(host) == -1)
  					return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1433
1434
1435
1436
  			}
  			break;
  
  		case DATA_IN:	/* Data in phase                */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1437
  			return initio_xfer_data_in(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1438
1439
  
  		case DATA_OUT:	/* Data out phase               */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1440
  			return initio_xfer_data_out(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1441
1442
  
  		default:
72d39fea9   Alan Cox   [SCSI] initio: Co...
1443
  			return initio_bad_seq(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1444
1445
1446
  		}
  	}
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1447
1448
1449
1450
1451
1452
1453
1454
  /**
   *	initio_state_5		-	SCSI state machine
   *	@host: InitIO host we are controlling
   *
   *	State after dma xfer done or phase change before xfer done
   */
  
  static int initio_state_5(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1455
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1456
  	struct scsi_ctrl_blk *scb = host->active;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1457
1458
1459
1460
1461
  	long cnt, xcnt;		/* cannot use unsigned !! code: if (xcnt < 0) */
  
  #if DEBUG_STATE
  	printk("-s5-");
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
1462
1463
  	/*------ get remaining count -------*/
  	cnt = inl(host->addr + TUL_SCnt0) & 0x0FFFFFF;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1464

72d39fea9   Alan Cox   [SCSI] initio: Co...
1465
  	if (inb(host->addr + TUL_XCmd) & 0x20) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1466
1467
  		/* ----------------------- DATA_IN ----------------------------- */
  		/* check scsi parity error */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1468
1469
1470
  		if (host->jsstatus0 & TSS_PAR_ERROR)
  			scb->hastat = HOST_DO_DU;
  		if (inb(host->addr + TUL_XStatus) & XPEND) {	/* DMA xfer pending, Send STOP  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1471
  			/* tell Hardware  scsi xfer has been terminated */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1472
  			outb(inb(host->addr + TUL_XCtrl) | 0x80, host->addr + TUL_XCtrl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1473
  			/* wait until DMA xfer not pending */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1474
1475
  			while (inb(host->addr + TUL_XStatus) & XPEND)
  				cpu_relax();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1476
1477
  		}
  	} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1478
1479
1480
1481
  		/*-------- DATA OUT -----------*/
  		if ((inb(host->addr + TUL_SStatus1) & TSS_XFER_CMP) == 0) {
  			if (host->active_tc->js_period & TSC_WIDE_SCSI)
  				cnt += (inb(host->addr + TUL_SFifoCnt) & 0x1F) << 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1482
  			else
72d39fea9   Alan Cox   [SCSI] initio: Co...
1483
  				cnt += (inb(host->addr + TUL_SFifoCnt) & 0x1F);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1484
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1485
1486
  		if (inb(host->addr + TUL_XStatus) & XPEND) {	/* if DMA xfer is pending, abort DMA xfer */
  			outb(TAX_X_ABT, host->addr + TUL_XCmd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1487
  			/* wait Abort DMA xfer done */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1488
1489
  			while ((inb(host->addr + TUL_Int) & XABT) == 0)
  				cpu_relax();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1490
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1491
1492
1493
1494
  		if ((cnt == 1) && (host->phase == DATA_OUT)) {
  			outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
  			if (wait_tulip(host) == -1)
  				return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1495
1496
  			cnt = 0;
  		} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1497
1498
  			if ((inb(host->addr + TUL_SStatus1) & TSS_XFER_CMP) == 0)
  				outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1499
1500
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1501
  	if (cnt == 0) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1502
1503
  		scb->buflen = 0;
  		return 6;	/* After Data */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1504
1505
  	}
  	/* Update active data pointer */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1506
1507
1508
1509
1510
1511
1512
1513
1514
  	xcnt = (long) scb->buflen - cnt;	/* xcnt== bytes already xferred */
  	scb->buflen = (u32) cnt;		/* cnt == bytes left to be xferred */
  	if (scb->flags & SCF_SG) {
  		struct sg_entry *sgp;
  		unsigned long i;
  
  		sgp = &scb->sglist[scb->sgidx];
  		for (i = scb->sgidx; i < scb->sgmax; sgp++, i++) {
  			xcnt -= (long) sgp->len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1515
  			if (xcnt < 0) {		/* this sgp xfer half done */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1516
1517
1518
1519
  				xcnt += (long) sgp->len;	/* xcnt == bytes xferred in this sgp */
  				sgp->data += (u32) xcnt;	/* new ptr to be xfer */
  				sgp->len -= (u32) xcnt;	/* new len to be xfer */
  				scb->bufptr += ((u32) (i - scb->sgidx) << 3);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1520
  				/* new SG table ptr */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1521
  				scb->sglen = (u8) (scb->sgmax - i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1522
  				/* new SG table len */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1523
  				scb->sgidx = (u16) i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1524
  				/* for next disc and come in this loop */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1525
  				return 4;	/* Go to state 4                */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1526
1527
1528
  			}
  			/* else (xcnt >= 0 , i.e. this sgp already xferred */
  		}		/* for */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1529
  		return 6;	/* Go to state 6                */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1530
  	} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1531
  		scb->bufptr += (u32) xcnt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1532
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1533
  	return 4;		/* Go to state 4                */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1534
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1535
1536
1537
1538
1539
1540
1541
1542
  /**
   *	initio_state_6		-	SCSI state machine
   *	@host: InitIO host we are controlling
   *
   *	State after Data phase
   */
  
  static int initio_state_6(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1543
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1544
  	struct scsi_ctrl_blk *scb = host->active;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1545
1546
1547
1548
1549
  
  #if DEBUG_STATE
  	printk("-s6-");
  #endif
  	for (;;) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1550
  		switch (host->phase) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1551
  		case STATUS_IN:	/* Status phase                 */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1552
1553
  			if ((initio_status_msg(host)) == -1)
  				return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1554
1555
1556
  			break;
  
  		case MSG_IN:	/* Message in phase             */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1557
1558
1559
  			scb->next_state = 6;
  			if ((initio_msgin(host)) == -1)
  				return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1560
1561
1562
  			break;
  
  		case MSG_OUT:	/* Message out phase            */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1563
1564
1565
1566
  			outb(MSG_NOP, host->addr + TUL_SFifo);		/* msg nop */
  			outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
  			if (wait_tulip(host) == -1)
  				return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1567
1568
1569
  			break;
  
  		case DATA_IN:	/* Data in phase                */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1570
  			return initio_xpad_in(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1571
1572
  
  		case DATA_OUT:	/* Data out phase               */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1573
  			return initio_xpad_out(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1574
1575
  
  		default:
72d39fea9   Alan Cox   [SCSI] initio: Co...
1576
  			return initio_bad_seq(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1577
1578
1579
  		}
  	}
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1580
1581
1582
1583
1584
  /**
   *	initio_state_7		-	SCSI state machine
   *	@host: InitIO host we are controlling
   *
   */
0c3dbdeb7   Chen Zhou   scsi: initio: mak...
1585
  static int initio_state_7(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1586
1587
1588
1589
1590
1591
1592
  {
  	int cnt, i;
  
  #if DEBUG_STATE
  	printk("-s7-");
  #endif
  	/* flush SCSI FIFO */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1593
  	cnt = inb(host->addr + TUL_SFifoCnt) & 0x1F;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1594
1595
  	if (cnt) {
  		for (i = 0; i < cnt; i++)
72d39fea9   Alan Cox   [SCSI] initio: Co...
1596
  			inb(host->addr + TUL_SFifo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1597
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1598
  	switch (host->phase) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1599
1600
  	case DATA_IN:		/* Data in phase                */
  	case DATA_OUT:		/* Data out phase               */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1601
  		return initio_bad_seq(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1602
  	default:
72d39fea9   Alan Cox   [SCSI] initio: Co...
1603
  		return 6;	/* Go to state 6                */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1604
1605
  	}
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1606
1607
1608
1609
1610
1611
1612
1613
1614
  /**
   *	initio_xfer_data_in	-	Commence data input
   *	@host: InitIO host in use
   *
   *	Commence a block of data transfer. The transfer itself will
   *	be managed by the controller and we will get a completion (or
   *	failure) interrupt.
   */
  static int initio_xfer_data_in(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1615
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1616
  	struct scsi_ctrl_blk *scb = host->active;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1617

72d39fea9   Alan Cox   [SCSI] initio: Co...
1618
1619
  	if ((scb->flags & SCF_DIR) == SCF_DOUT)
  		return 6;	/* wrong direction */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1620

72d39fea9   Alan Cox   [SCSI] initio: Co...
1621
1622
  	outl(scb->buflen, host->addr + TUL_SCnt0);
  	outb(TSC_XF_DMA_IN, host->addr + TUL_SCmd);	/* 7/25/95 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1623

72d39fea9   Alan Cox   [SCSI] initio: Co...
1624
1625
1626
1627
  	if (scb->flags & SCF_SG) {	/* S/G xfer */
  		outl(((u32) scb->sglen) << 3, host->addr + TUL_XCntH);
  		outl(scb->bufptr, host->addr + TUL_XAddH);
  		outb(TAX_SG_IN, host->addr + TUL_XCmd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1628
  	} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1629
1630
1631
  		outl(scb->buflen, host->addr + TUL_XCntH);
  		outl(scb->bufptr, host->addr + TUL_XAddH);
  		outb(TAX_X_IN, host->addr + TUL_XCmd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1632
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1633
1634
  	scb->next_state = 0x5;
  	return 0;		/* return to OS, wait xfer done , let jas_isr come in */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1635
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1636
1637
1638
1639
1640
1641
1642
1643
  /**
   *	initio_xfer_data_out	-	Commence data output
   *	@host: InitIO host in use
   *
   *	Commence a block of data transfer. The transfer itself will
   *	be managed by the controller and we will get a completion (or
   *	failure) interrupt.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1644

72d39fea9   Alan Cox   [SCSI] initio: Co...
1645
  static int initio_xfer_data_out(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1646
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1647
  	struct scsi_ctrl_blk *scb = host->active;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1648

72d39fea9   Alan Cox   [SCSI] initio: Co...
1649
1650
  	if ((scb->flags & SCF_DIR) == SCF_DIN)
  		return 6;	/* wrong direction */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1651

72d39fea9   Alan Cox   [SCSI] initio: Co...
1652
1653
1654
1655
1656
1657
1658
  	outl(scb->buflen, host->addr + TUL_SCnt0);
  	outb(TSC_XF_DMA_OUT, host->addr + TUL_SCmd);
  
  	if (scb->flags & SCF_SG) {	/* S/G xfer */
  		outl(((u32) scb->sglen) << 3, host->addr + TUL_XCntH);
  		outl(scb->bufptr, host->addr + TUL_XAddH);
  		outb(TAX_SG_OUT, host->addr + TUL_XCmd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1659
  	} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1660
1661
1662
  		outl(scb->buflen, host->addr + TUL_XCntH);
  		outl(scb->bufptr, host->addr + TUL_XAddH);
  		outb(TAX_X_OUT, host->addr + TUL_XCmd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1663
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1664
1665
  	scb->next_state = 0x5;
  	return 0;		/* return to OS, wait xfer done , let jas_isr come in */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1666
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1667
  int initio_xpad_in(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1668
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1669
1670
  	struct scsi_ctrl_blk *scb = host->active;
  	struct target_control *active_tc = host->active_tc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1671

72d39fea9   Alan Cox   [SCSI] initio: Co...
1672
1673
  	if ((scb->flags & SCF_DIR) != SCF_NO_DCHK)
  		scb->hastat = HOST_DO_DU;	/* over run             */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1674
  	for (;;) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1675
1676
  		if (active_tc->js_period & TSC_WIDE_SCSI)
  			outl(2, host->addr + TUL_SCnt0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1677
  		else
72d39fea9   Alan Cox   [SCSI] initio: Co...
1678
  			outl(1, host->addr + TUL_SCnt0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1679

72d39fea9   Alan Cox   [SCSI] initio: Co...
1680
1681
1682
1683
1684
1685
  		outb(TSC_XF_FIFO_IN, host->addr + TUL_SCmd);
  		if (wait_tulip(host) == -1)
  			return -1;
  		if (host->phase != DATA_IN) {
  			outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
  			return 6;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1686
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1687
  		inb(host->addr + TUL_SFifo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1688
1689
  	}
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1690
  int initio_xpad_out(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1691
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1692
1693
  	struct scsi_ctrl_blk *scb = host->active;
  	struct target_control *active_tc = host->active_tc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1694

72d39fea9   Alan Cox   [SCSI] initio: Co...
1695
1696
  	if ((scb->flags & SCF_DIR) != SCF_NO_DCHK)
  		scb->hastat = HOST_DO_DU;	/* over run             */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1697
  	for (;;) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1698
1699
  		if (active_tc->js_period & TSC_WIDE_SCSI)
  			outl(2, host->addr + TUL_SCnt0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1700
  		else
72d39fea9   Alan Cox   [SCSI] initio: Co...
1701
  			outl(1, host->addr + TUL_SCnt0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1702

72d39fea9   Alan Cox   [SCSI] initio: Co...
1703
1704
1705
1706
1707
1708
1709
1710
  		outb(0, host->addr + TUL_SFifo);
  		outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
  		if ((wait_tulip(host)) == -1)
  			return -1;
  		if (host->phase != DATA_OUT) {	/* Disable wide CPU to allow read 16 bits */
  			outb(TSC_HW_RESELECT, host->addr + TUL_SCtrl1);
  			outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
  			return 6;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1711
1712
1713
  		}
  	}
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1714
  int initio_status_msg(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1715
  {				/* status & MSG_IN */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1716
1717
1718
1719
1720
1721
  	struct scsi_ctrl_blk *scb = host->active;
  	u8 msg;
  
  	outb(TSC_CMD_COMP, host->addr + TUL_SCmd);
  	if (wait_tulip(host) == -1)
  		return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1722

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1723
  	/* get status */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1724
  	scb->tastat = inb(host->addr + TUL_SFifo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1725

72d39fea9   Alan Cox   [SCSI] initio: Co...
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
  	if (host->phase == MSG_OUT) {
  		if (host->jsstatus0 & TSS_PAR_ERROR)
  			outb(MSG_PARITY, host->addr + TUL_SFifo);
  		else
  			outb(MSG_NOP, host->addr + TUL_SFifo);
  		outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
  		return wait_tulip(host);
  	}
  	if (host->phase == MSG_IN) {
  		msg = inb(host->addr + TUL_SFifo);
  		if (host->jsstatus0 & TSS_PAR_ERROR) {	/* Parity error                 */
  			if ((initio_msgin_accept(host)) == -1)
  				return -1;
  			if (host->phase != MSG_OUT)
  				return initio_bad_seq(host);
  			outb(MSG_PARITY, host->addr + TUL_SFifo);
  			outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
  			return wait_tulip(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1744
1745
  		}
  		if (msg == 0) {	/* Command complete             */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1746
1747
1748
1749
1750
  			if ((scb->tastat & 0x18) == 0x10)	/* No link support              */
  				return initio_bad_seq(host);
  			outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
  			outb(TSC_MSG_ACCEPT, host->addr + TUL_SCmd);
  			return initio_wait_done_disc(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1751
1752
  
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1753
1754
1755
  		if (msg == MSG_LINK_COMP || msg == MSG_LINK_FLAG) {
  			if ((scb->tastat & 0x18) == 0x10)
  				return initio_msgin_accept(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1756
1757
  		}
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1758
  	return initio_bad_seq(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1759
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1760
  /* scsi bus free */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1761
  int int_initio_busfree(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1762
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1763
  	struct scsi_ctrl_blk *scb = host->active;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1764

72d39fea9   Alan Cox   [SCSI] initio: Co...
1765
1766
1767
1768
1769
  	if (scb != NULL) {
  		if (scb->status & SCB_SELECT) {		/* selection timeout */
  			initio_unlink_pend_scb(host, scb);
  			scb->hastat = HOST_SEL_TOUT;
  			initio_append_done_scb(host, scb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1770
  		} else {	/* Unexpected bus free          */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1771
1772
1773
  			initio_unlink_busy_scb(host, scb);
  			scb->hastat = HOST_BUS_FREE;
  			initio_append_done_scb(host, scb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1774
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1775
1776
  		host->active = NULL;
  		host->active_tc = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1777
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1778
1779
1780
1781
  	outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);		/* Flush SCSI FIFO  */
  	outb(TSC_INITDEFAULT, host->addr + TUL_SConfig);
  	outb(TSC_HW_RESELECT, host->addr + TUL_SCtrl1);	/* Enable HW reselect       */
  	return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1782
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
  /**
   *	int_initio_scsi_rst	-	SCSI reset occurred
   *	@host: Host seeing the reset
   *
   *	A SCSI bus reset has occurred. Clean up any pending transfer
   *	the hardware is doing by DMA and then abort all active and
   *	disconnected commands. The mid layer should sort the rest out
   *	for us
   */
  
  static int int_initio_scsi_rst(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1794
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1795
  	struct scsi_ctrl_blk *scb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1796
1797
1798
  	int i;
  
  	/* if DMA xfer is pending, abort DMA xfer */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1799
1800
  	if (inb(host->addr + TUL_XStatus) & 0x01) {
  		outb(TAX_X_ABT | TAX_X_CLR_FIFO, host->addr + TUL_XCmd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1801
  		/* wait Abort DMA xfer done */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1802
1803
1804
  		while ((inb(host->addr + TUL_Int) & 0x04) == 0)
  			cpu_relax();
  		outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1805
1806
  	}
  	/* Abort all active & disconnected scb */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1807
1808
1809
  	while ((scb = initio_pop_busy_scb(host)) != NULL) {
  		scb->hastat = HOST_BAD_PHAS;
  		initio_append_done_scb(host, scb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1810
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1811
1812
  	host->active = NULL;
  	host->active_tc = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1813
1814
  
  	/* clr sync nego. done flag */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1815
1816
1817
  	for (i = 0; i < host->max_tar; i++)
  		host->targets[i].flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
  	return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1818
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1819
  /**
25985edce   Lucas De Marchi   Fix common misspe...
1820
   *	int_initio_scsi_resel	-	Reselection occurred
72d39fea9   Alan Cox   [SCSI] initio: Co...
1821
1822
1823
1824
1825
1826
   *	@host: InitIO host adapter
   *
   *	A SCSI reselection event has been signalled and the interrupt
   *	is now being processed. Work out which command block needs attention
   *	and continue processing that command.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1827

72d39fea9   Alan Cox   [SCSI] initio: Co...
1828
  int int_initio_resel(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1829
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1830
1831
1832
1833
  	struct scsi_ctrl_blk *scb;
  	struct target_control *active_tc;
  	u8 tag, msg = 0;
  	u8 tar, lun;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1834

72d39fea9   Alan Cox   [SCSI] initio: Co...
1835
1836
1837
1838
1839
  	if ((scb = host->active) != NULL) {
  		/* FIXME: Why check and not just clear ? */
  		if (scb->status & SCB_SELECT)		/* if waiting for selection complete */
  			scb->status &= ~SCB_SELECT;
  		host->active = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1840
1841
  	}
  	/* --------- get target id---------------------- */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1842
  	tar = inb(host->addr + TUL_SBusId);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1843
  	/* ------ get LUN from Identify message----------- */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1844
  	lun = inb(host->addr + TUL_SIdent) & 0x0F;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1845
  	/* 07/22/98 from 0x1F -> 0x0F */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1846
1847
1848
1849
  	active_tc = &host->targets[tar];
  	host->active_tc = active_tc;
  	outb(active_tc->sconfig0, host->addr + TUL_SConfig);
  	outb(active_tc->js_period, host->addr + TUL_SPeriod);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1850
1851
  
  	/* ------------- tag queueing ? ------------------- */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1852
1853
1854
1855
  	if (active_tc->drv_flags & TCF_DRV_EN_TAG) {
  		if ((initio_msgin_accept(host)) == -1)
  			return -1;
  		if (host->phase != MSG_IN)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1856
  			goto no_tag;
72d39fea9   Alan Cox   [SCSI] initio: Co...
1857
1858
1859
1860
1861
  		outl(1, host->addr + TUL_SCnt0);
  		outb(TSC_XF_FIFO_IN, host->addr + TUL_SCmd);
  		if (wait_tulip(host) == -1)
  			return -1;
  		msg = inb(host->addr + TUL_SFifo);	/* Read Tag Message    */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1862

72d39fea9   Alan Cox   [SCSI] initio: Co...
1863
  		if (msg < MSG_STAG || msg > MSG_OTAG)		/* Is simple Tag      */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1864
  			goto no_tag;
72d39fea9   Alan Cox   [SCSI] initio: Co...
1865
1866
  		if (initio_msgin_accept(host) == -1)
  			return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1867

72d39fea9   Alan Cox   [SCSI] initio: Co...
1868
  		if (host->phase != MSG_IN)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1869
  			goto no_tag;
72d39fea9   Alan Cox   [SCSI] initio: Co...
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
  		outl(1, host->addr + TUL_SCnt0);
  		outb(TSC_XF_FIFO_IN, host->addr + TUL_SCmd);
  		if (wait_tulip(host) == -1)
  			return -1;
  		tag = inb(host->addr + TUL_SFifo);	/* Read Tag ID       */
  		scb = host->scb + tag;
  		if (scb->target != tar || scb->lun != lun) {
  			return initio_msgout_abort_tag(host);
  		}
  		if (scb->status != SCB_BUSY) {	/* 03/24/95             */
  			return initio_msgout_abort_tag(host);
  		}
  		host->active = scb;
  		if ((initio_msgin_accept(host)) == -1)
  			return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1885
1886
  	} else {		/* No tag               */
  	      no_tag:
72d39fea9   Alan Cox   [SCSI] initio: Co...
1887
1888
  		if ((scb = initio_find_busy_scb(host, tar | (lun << 8))) == NULL) {
  			return initio_msgout_abort_targ(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1889
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1890
1891
1892
1893
  		host->active = scb;
  		if (!(active_tc->drv_flags & TCF_DRV_EN_TAG)) {
  			if ((initio_msgin_accept(host)) == -1)
  				return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1894
1895
1896
1897
  		}
  	}
  	return 0;
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1898
1899
1900
1901
1902
1903
1904
  /**
   *	int_initio_bad_seq		-	out of phase
   *	@host: InitIO host flagging event
   *
   *	We have ended up out of phase somehow. Reset the host controller
   *	and throw all our toys out of the pram. Let the midlayer clean up
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1905

72d39fea9   Alan Cox   [SCSI] initio: Co...
1906
  static int int_initio_bad_seq(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1907
  {				/* target wrong phase           */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1908
  	struct scsi_ctrl_blk *scb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1909
  	int i;
72d39fea9   Alan Cox   [SCSI] initio: Co...
1910
  	initio_reset_scsi(host, 10);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1911

72d39fea9   Alan Cox   [SCSI] initio: Co...
1912
1913
1914
  	while ((scb = initio_pop_busy_scb(host)) != NULL) {
  		scb->hastat = HOST_BAD_PHAS;
  		initio_append_done_scb(host, scb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1915
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1916
1917
1918
  	for (i = 0; i < host->max_tar; i++)
  		host->targets[i].flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
  	return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1919
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1920
1921
1922
1923
1924
1925
1926
1927
1928
  /**
   *	initio_msgout_abort_targ		-	abort a tag
   *	@host: InitIO host
   *
   *	Abort when the target/lun does not match or when our SCB is not
   *	busy. Used by untagged commands.
   */
  
  static int initio_msgout_abort_targ(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1929
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1930
1931
1932
1933
1934
  	outb(((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN), host->addr + TUL_SSignal);
  	if (initio_msgin_accept(host) == -1)
  		return -1;
  	if (host->phase != MSG_OUT)
  		return initio_bad_seq(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1935

72d39fea9   Alan Cox   [SCSI] initio: Co...
1936
1937
  	outb(MSG_ABORT, host->addr + TUL_SFifo);
  	outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1938

72d39fea9   Alan Cox   [SCSI] initio: Co...
1939
  	return initio_wait_disc(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1940
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1941
1942
1943
1944
1945
1946
1947
1948
1949
  /**
   *	initio_msgout_abort_tag		-	abort a tag
   *	@host: InitIO host
   *
   *	Abort when the target/lun does not match or when our SCB is not
   *	busy. Used for tagged commands.
   */
  
  static int initio_msgout_abort_tag(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1950
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1951
1952
1953
1954
1955
  	outb(((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN), host->addr + TUL_SSignal);
  	if (initio_msgin_accept(host) == -1)
  		return -1;
  	if (host->phase != MSG_OUT)
  		return initio_bad_seq(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1956

72d39fea9   Alan Cox   [SCSI] initio: Co...
1957
1958
  	outb(MSG_ABORT_TAG, host->addr + TUL_SFifo);
  	outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1959

72d39fea9   Alan Cox   [SCSI] initio: Co...
1960
  	return initio_wait_disc(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1961
1962
  
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1963
1964
1965
1966
1967
1968
1969
  /**
   *	initio_msgin		-	Message in
   *	@host: InitIO Host
   *
   *	Process incoming message
   */
  static int initio_msgin(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1970
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1971
  	struct target_control *active_tc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1972
1973
  
  	for (;;) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1974
  		outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1975

72d39fea9   Alan Cox   [SCSI] initio: Co...
1976
1977
1978
1979
  		outl(1, host->addr + TUL_SCnt0);
  		outb(TSC_XF_FIFO_IN, host->addr + TUL_SCmd);
  		if (wait_tulip(host) == -1)
  			return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1980

72d39fea9   Alan Cox   [SCSI] initio: Co...
1981
  		switch (inb(host->addr + TUL_SFifo)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1982
  		case MSG_DISC:	/* Disconnect msg */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1983
1984
  			outb(TSC_MSG_ACCEPT, host->addr + TUL_SCmd);
  			return initio_wait_disc(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1985
1986
1987
  		case MSG_SDP:
  		case MSG_RESTORE:
  		case MSG_NOP:
72d39fea9   Alan Cox   [SCSI] initio: Co...
1988
  			initio_msgin_accept(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1989
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1990
  		case MSG_REJ:	/* Clear ATN first              */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1991
1992
1993
1994
1995
1996
1997
  			outb((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)),
  				host->addr + TUL_SSignal);
  			active_tc = host->active_tc;
  			if ((active_tc->flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0)	/* do sync nego */
  				outb(((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN),
  					host->addr + TUL_SSignal);
  			initio_msgin_accept(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1998
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1999
  		case MSG_EXTEND:	/* extended msg */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2000
  			initio_msgin_extend(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2001
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2002
  		case MSG_IGNOREWIDE:
72d39fea9   Alan Cox   [SCSI] initio: Co...
2003
  			initio_msgin_accept(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2004
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2005
  		case MSG_COMP:
72d39fea9   Alan Cox   [SCSI] initio: Co...
2006
2007
2008
  			outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
  			outb(TSC_MSG_ACCEPT, host->addr + TUL_SCmd);
  			return initio_wait_done_disc(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2009
  		default:
72d39fea9   Alan Cox   [SCSI] initio: Co...
2010
  			initio_msgout_reject(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2011
2012
  			break;
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2013
2014
  		if (host->phase != MSG_IN)
  			return host->phase;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2015
2016
2017
  	}
  	/* statement won't reach here */
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2018
  static int initio_msgout_reject(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2019
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2020
  	outb(((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN), host->addr + TUL_SSignal);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2021

72d39fea9   Alan Cox   [SCSI] initio: Co...
2022
2023
  	if (initio_msgin_accept(host) == -1)
  		return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2024

72d39fea9   Alan Cox   [SCSI] initio: Co...
2025
2026
2027
2028
  	if (host->phase == MSG_OUT) {
  		outb(MSG_REJ, host->addr + TUL_SFifo);		/* Msg reject           */
  		outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
  		return wait_tulip(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2029
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2030
  	return host->phase;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2031
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2032
  static int initio_msgout_ide(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2033
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2034
2035
2036
  	outb(MSG_IDE, host->addr + TUL_SFifo);		/* Initiator Detected Error */
  	outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
  	return wait_tulip(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2037
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2038
  static int initio_msgin_extend(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2039
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2040
  	u8 len, idx;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2041

72d39fea9   Alan Cox   [SCSI] initio: Co...
2042
2043
  	if (initio_msgin_accept(host) != MSG_IN)
  		return host->phase;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2044
2045
  
  	/* Get extended msg length      */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2046
2047
2048
2049
  	outl(1, host->addr + TUL_SCnt0);
  	outb(TSC_XF_FIFO_IN, host->addr + TUL_SCmd);
  	if (wait_tulip(host) == -1)
  		return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2050

72d39fea9   Alan Cox   [SCSI] initio: Co...
2051
2052
  	len = inb(host->addr + TUL_SFifo);
  	host->msg[0] = len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2053
  	for (idx = 1; len != 0; len--) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
  		if ((initio_msgin_accept(host)) != MSG_IN)
  			return host->phase;
  		outl(1, host->addr + TUL_SCnt0);
  		outb(TSC_XF_FIFO_IN, host->addr + TUL_SCmd);
  		if (wait_tulip(host) == -1)
  			return -1;
  		host->msg[idx++] = inb(host->addr + TUL_SFifo);
  	}
  	if (host->msg[1] == 1) {		/* if it's synchronous data transfer request */
  		u8 r;
  		if (host->msg[0] != 3)	/* if length is not right */
  			return initio_msgout_reject(host);
  		if (host->active_tc->flags & TCF_NO_SYNC_NEGO) {	/* Set OFFSET=0 to do async, nego back */
  			host->msg[3] = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2068
  		} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2069
2070
2071
2072
  			if (initio_msgin_sync(host) == 0 &&
  			    (host->active_tc->flags & TCF_SYNC_DONE)) {
  				initio_sync_done(host);
  				return initio_msgin_accept(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2073
2074
  			}
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2075
2076
2077
2078
2079
  		r = inb(host->addr + TUL_SSignal);
  		outb((r & (TSC_SET_ACK | 7)) | TSC_SET_ATN,
  			host->addr + TUL_SSignal);
  		if (initio_msgin_accept(host) != MSG_OUT)
  			return host->phase;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2080
  		/* sync msg out */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2081
  		outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2082

72d39fea9   Alan Cox   [SCSI] initio: Co...
2083
  		initio_sync_done(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2084

72d39fea9   Alan Cox   [SCSI] initio: Co...
2085
2086
2087
2088
2089
2090
2091
  		outb(MSG_EXTEND, host->addr + TUL_SFifo);
  		outb(3, host->addr + TUL_SFifo);
  		outb(1, host->addr + TUL_SFifo);
  		outb(host->msg[2], host->addr + TUL_SFifo);
  		outb(host->msg[3], host->addr + TUL_SFifo);
  		outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
  		return wait_tulip(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2092
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2093
2094
  	if (host->msg[0] != 2 || host->msg[1] != 3)
  		return initio_msgout_reject(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2095
  	/* if it's WIDE DATA XFER REQ   */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2096
2097
  	if (host->active_tc->flags & TCF_NO_WDTR) {
  		host->msg[2] = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2098
  	} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2099
2100
2101
2102
  		if (host->msg[2] > 2)	/* > 32 bits            */
  			return initio_msgout_reject(host);
  		if (host->msg[2] == 2) {		/* == 32                */
  			host->msg[2] = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2103
  		} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2104
2105
2106
2107
2108
  			if ((host->active_tc->flags & TCF_NO_WDTR) == 0) {
  				wdtr_done(host);
  				if ((host->active_tc->flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0)
  					outb(((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN), host->addr + TUL_SSignal);
  				return initio_msgin_accept(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2109
2110
2111
  			}
  		}
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2112
  	outb(((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN), host->addr + TUL_SSignal);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2113

72d39fea9   Alan Cox   [SCSI] initio: Co...
2114
2115
  	if (initio_msgin_accept(host) != MSG_OUT)
  		return host->phase;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2116
  	/* WDTR msg out                 */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2117
2118
2119
2120
2121
2122
  	outb(MSG_EXTEND, host->addr + TUL_SFifo);
  	outb(2, host->addr + TUL_SFifo);
  	outb(3, host->addr + TUL_SFifo);
  	outb(host->msg[2], host->addr + TUL_SFifo);
  	outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
  	return wait_tulip(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2123
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2124
  static int initio_msgin_sync(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2125
2126
  {
  	char default_period;
72d39fea9   Alan Cox   [SCSI] initio: Co...
2127
2128
2129
2130
2131
  	default_period = initio_rate_tbl[host->active_tc->flags & TCF_SCSI_RATE];
  	if (host->msg[3] > MAX_OFFSET) {
  		host->msg[3] = MAX_OFFSET;
  		if (host->msg[2] < default_period) {
  			host->msg[2] = default_period;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2132
2133
  			return 1;
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2134
2135
  		if (host->msg[2] >= 59)	/* Change to async              */
  			host->msg[3] = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2136
2137
2138
  		return 1;
  	}
  	/* offset requests asynchronous transfers ? */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2139
  	if (host->msg[3] == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2140
2141
  		return 0;
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2142
2143
  	if (host->msg[2] < default_period) {
  		host->msg[2] = default_period;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2144
2145
  		return 1;
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2146
2147
  	if (host->msg[2] >= 59) {
  		host->msg[3] = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2148
2149
2150
2151
  		return 1;
  	}
  	return 0;
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2152
  static int wdtr_done(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2153
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2154
2155
  	host->active_tc->flags &= ~TCF_SYNC_DONE;
  	host->active_tc->flags |= TCF_WDTR_DONE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2156

72d39fea9   Alan Cox   [SCSI] initio: Co...
2157
2158
2159
2160
2161
2162
  	host->active_tc->js_period = 0;
  	if (host->msg[2])	/* if 16 bit */
  		host->active_tc->js_period |= TSC_WIDE_SCSI;
  	host->active_tc->sconfig0 &= ~TSC_ALT_PERIOD;
  	outb(host->active_tc->sconfig0, host->addr + TUL_SConfig);
  	outb(host->active_tc->js_period, host->addr + TUL_SPeriod);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2163
2164
2165
  
  	return 1;
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2166
  static int initio_sync_done(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2167
2168
  {
  	int i;
72d39fea9   Alan Cox   [SCSI] initio: Co...
2169
  	host->active_tc->flags |= TCF_SYNC_DONE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2170

72d39fea9   Alan Cox   [SCSI] initio: Co...
2171
2172
  	if (host->msg[3]) {
  		host->active_tc->js_period |= host->msg[3];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2173
  		for (i = 0; i < 8; i++) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2174
  			if (initio_rate_tbl[i] >= host->msg[2])	/* pick the big one */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2175
2176
  				break;
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2177
2178
  		host->active_tc->js_period |= (i << 4);
  		host->active_tc->sconfig0 |= TSC_ALT_PERIOD;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2179
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2180
2181
  	outb(host->active_tc->sconfig0, host->addr + TUL_SConfig);
  	outb(host->active_tc->js_period, host->addr + TUL_SPeriod);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2182

72d39fea9   Alan Cox   [SCSI] initio: Co...
2183
  	return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2184
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2185
  static int initio_post_scsi_rst(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2186
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2187
2188
  	struct scsi_ctrl_blk *scb;
  	struct target_control *active_tc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2189
  	int i;
72d39fea9   Alan Cox   [SCSI] initio: Co...
2190
2191
2192
  	host->active = NULL;
  	host->active_tc = NULL;
  	host->flags = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2193

72d39fea9   Alan Cox   [SCSI] initio: Co...
2194
2195
2196
  	while ((scb = initio_pop_busy_scb(host)) != NULL) {
  		scb->hastat = HOST_BAD_PHAS;
  		initio_append_done_scb(host, scb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2197
2198
  	}
  	/* clear sync done flag         */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2199
2200
2201
  	active_tc = &host->targets[0];
  	for (i = 0; i < host->max_tar; active_tc++, i++) {
  		active_tc->flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2202
  		/* Initialize the sync. xfer register values to an asyn xfer */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2203
2204
2205
2206
  		active_tc->js_period = 0;
  		active_tc->sconfig0 = host->sconf1;
  		host->act_tags[0] = 0;	/* 07/22/98 */
  		host->targets[i].flags &= ~TCF_BUSY;	/* 07/22/98 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2207
  	}			/* for */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2208
  	return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2209
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2210
  static void initio_select_atn_stop(struct initio_host * host, struct scsi_ctrl_blk * scb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2211
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2212
2213
2214
2215
2216
  	scb->status |= SCB_SELECT;
  	scb->next_state = 0x1;
  	host->active = scb;
  	host->active_tc = &host->targets[scb->target];
  	outb(TSC_SELATNSTOP, host->addr + TUL_SCmd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2217
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2218
  static void initio_select_atn(struct initio_host * host, struct scsi_ctrl_blk * scb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2219
2220
  {
  	int i;
72d39fea9   Alan Cox   [SCSI] initio: Co...
2221
2222
  	scb->status |= SCB_SELECT;
  	scb->next_state = 0x2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2223

72d39fea9   Alan Cox   [SCSI] initio: Co...
2224
2225
2226
2227
2228
2229
  	outb(scb->ident, host->addr + TUL_SFifo);
  	for (i = 0; i < (int) scb->cdblen; i++)
  		outb(scb->cdb[i], host->addr + TUL_SFifo);
  	host->active_tc = &host->targets[scb->target];
  	host->active = scb;
  	outb(TSC_SEL_ATN, host->addr + TUL_SCmd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2230
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2231
  static void initio_select_atn3(struct initio_host * host, struct scsi_ctrl_blk * scb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2232
2233
  {
  	int i;
72d39fea9   Alan Cox   [SCSI] initio: Co...
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
  	scb->status |= SCB_SELECT;
  	scb->next_state = 0x2;
  
  	outb(scb->ident, host->addr + TUL_SFifo);
  	outb(scb->tagmsg, host->addr + TUL_SFifo);
  	outb(scb->tagid, host->addr + TUL_SFifo);
  	for (i = 0; i < scb->cdblen; i++)
  		outb(scb->cdb[i], host->addr + TUL_SFifo);
  	host->active_tc = &host->targets[scb->target];
  	host->active = scb;
  	outb(TSC_SEL_ATN3, host->addr + TUL_SCmd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2245
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2246
2247
2248
2249
2250
2251
2252
2253
  /**
   *	initio_bus_device_reset	-	 SCSI Bus Device Reset
   *	@host: InitIO host to reset
   *
   *	Perform a device reset and abort all pending SCBs for the
   *	victim device
   */
  int initio_bus_device_reset(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2254
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2255
2256
2257
2258
  	struct scsi_ctrl_blk *scb = host->active;
  	struct target_control *active_tc = host->active_tc;
  	struct scsi_ctrl_blk *tmp, *prev;
  	u8 tar;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2259

72d39fea9   Alan Cox   [SCSI] initio: Co...
2260
2261
2262
2263
2264
  	if (host->phase != MSG_OUT)
  		return int_initio_bad_seq(host);	/* Unexpected phase */
  
  	initio_unlink_pend_scb(host, scb);
  	initio_release_scb(host, scb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2265

72d39fea9   Alan Cox   [SCSI] initio: Co...
2266
2267
  	tar = scb->target;	/* target                       */
  	active_tc->flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE | TCF_BUSY);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2268
2269
2270
  	/* clr sync. nego & WDTR flags  07/22/98 */
  
  	/* abort all SCB with same target */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2271
2272
2273
  	prev = tmp = host->first_busy;	/* Check Busy queue */
  	while (tmp != NULL) {
  		if (tmp->target == tar) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2274
  			/* unlink it */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2275
2276
2277
  			if (tmp == host->first_busy) {
  				if ((host->first_busy = tmp->next) == NULL)
  					host->last_busy = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2278
  			} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2279
2280
2281
  				prev->next = tmp->next;
  				if (tmp == host->last_busy)
  					host->last_busy = prev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2282
  			}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2283
2284
  			tmp->hastat = HOST_ABORTED;
  			initio_append_done_scb(host, tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2285
2286
2287
  		}
  		/* Previous haven't change      */
  		else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2288
  			prev = tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2289
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2290
  		tmp = tmp->next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2291
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2292
2293
2294
  	outb(MSG_DEVRST, host->addr + TUL_SFifo);
  	outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
  	return initio_wait_disc(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2295
2296
  
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2297
  static int initio_msgin_accept(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2298
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2299
2300
  	outb(TSC_MSG_ACCEPT, host->addr + TUL_SCmd);
  	return wait_tulip(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2301
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2302
  static int wait_tulip(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2303
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2304
2305
2306
  	while (!((host->jsstatus0 = inb(host->addr + TUL_SStatus0))
  		 & TSS_INT_PENDING))
  			cpu_relax();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2307

72d39fea9   Alan Cox   [SCSI] initio: Co...
2308
2309
2310
  	host->jsint = inb(host->addr + TUL_SInt);
  	host->phase = host->jsstatus0 & TSS_PH_MASK;
  	host->jsstatus1 = inb(host->addr + TUL_SStatus1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2311

72d39fea9   Alan Cox   [SCSI] initio: Co...
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
  	if (host->jsint & TSS_RESEL_INT)	/* if SCSI bus reset detected */
  		return int_initio_resel(host);
  	if (host->jsint & TSS_SEL_TIMEOUT)	/* if selected/reselected timeout interrupt */
  		return int_initio_busfree(host);
  	if (host->jsint & TSS_SCSIRST_INT)	/* if SCSI bus reset detected   */
  		return int_initio_scsi_rst(host);
  
  	if (host->jsint & TSS_DISC_INT) {	/* BUS disconnection            */
  		if (host->flags & HCF_EXPECT_DONE_DISC) {
  			outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0); /* Flush SCSI FIFO */
  			initio_unlink_busy_scb(host, host->active);
  			host->active->hastat = 0;
  			initio_append_done_scb(host, host->active);
  			host->active = NULL;
  			host->active_tc = NULL;
  			host->flags &= ~HCF_EXPECT_DONE_DISC;
  			outb(TSC_INITDEFAULT, host->addr + TUL_SConfig);
  			outb(TSC_HW_RESELECT, host->addr + TUL_SCtrl1);	/* Enable HW reselect */
  			return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2331
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2332
2333
2334
2335
2336
2337
2338
2339
  		if (host->flags & HCF_EXPECT_DISC) {
  			outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0); /* Flush SCSI FIFO */
  			host->active = NULL;
  			host->active_tc = NULL;
  			host->flags &= ~HCF_EXPECT_DISC;
  			outb(TSC_INITDEFAULT, host->addr + TUL_SConfig);
  			outb(TSC_HW_RESELECT, host->addr + TUL_SCtrl1);	/* Enable HW reselect */
  			return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2340
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2341
  		return int_initio_busfree(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2342
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2343
2344
2345
2346
  	/* The old code really does the below. Can probably be removed */
  	if (host->jsint & (TSS_FUNC_COMP | TSS_BUS_SERV))
  		return host->phase;
  	return host->phase;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2347
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2348

72d39fea9   Alan Cox   [SCSI] initio: Co...
2349
2350
2351
2352
  static int initio_wait_disc(struct initio_host * host)
  {
  	while (!((host->jsstatus0 = inb(host->addr + TUL_SStatus0)) & TSS_INT_PENDING))
  		cpu_relax();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2353

72d39fea9   Alan Cox   [SCSI] initio: Co...
2354
  	host->jsint = inb(host->addr + TUL_SInt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2355

72d39fea9   Alan Cox   [SCSI] initio: Co...
2356
2357
2358
2359
2360
2361
2362
2363
  	if (host->jsint & TSS_SCSIRST_INT)	/* if SCSI bus reset detected */
  		return int_initio_scsi_rst(host);
  	if (host->jsint & TSS_DISC_INT) {	/* BUS disconnection */
  		outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0); /* Flush SCSI FIFO */
  		outb(TSC_INITDEFAULT, host->addr + TUL_SConfig);
  		outb(TSC_HW_RESELECT, host->addr + TUL_SCtrl1);	/* Enable HW reselect */
  		host->active = NULL;
  		return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2364
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2365
  	return initio_bad_seq(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2366
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2367
  static int initio_wait_done_disc(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2368
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2369
2370
2371
  	while (!((host->jsstatus0 = inb(host->addr + TUL_SStatus0))
  		 & TSS_INT_PENDING))
  		 cpu_relax();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2372

72d39fea9   Alan Cox   [SCSI] initio: Co...
2373
  	host->jsint = inb(host->addr + TUL_SInt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2374

72d39fea9   Alan Cox   [SCSI] initio: Co...
2375
2376
2377
2378
2379
2380
2381
  	if (host->jsint & TSS_SCSIRST_INT)	/* if SCSI bus reset detected */
  		return int_initio_scsi_rst(host);
  	if (host->jsint & TSS_DISC_INT) {	/* BUS disconnection */
  		outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);		/* Flush SCSI FIFO */
  		outb(TSC_INITDEFAULT, host->addr + TUL_SConfig);
  		outb(TSC_HW_RESELECT, host->addr + TUL_SCtrl1);		/* Enable HW reselect */
  		initio_unlink_busy_scb(host, host->active);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2382

72d39fea9   Alan Cox   [SCSI] initio: Co...
2383
2384
2385
  		initio_append_done_scb(host, host->active);
  		host->active = NULL;
  		return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2386
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2387
  	return initio_bad_seq(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2388
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2389
2390
2391
2392
2393
2394
2395
2396
  /**
   *	i91u_intr		-	IRQ handler
   *	@irqno: IRQ number
   *	@dev_id: IRQ identifier
   *
   *	Take the relevant locks and then invoke the actual isr processing
   *	code under the lock.
   */
7d12e780e   David Howells   IRQ: Maintain reg...
2397
  static irqreturn_t i91u_intr(int irqno, void *dev_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2398
2399
2400
  {
  	struct Scsi_Host *dev = dev_id;
  	unsigned long flags;
72d39fea9   Alan Cox   [SCSI] initio: Co...
2401
  	int r;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2402
2403
  	
  	spin_lock_irqsave(dev->host_lock, flags);
72d39fea9   Alan Cox   [SCSI] initio: Co...
2404
  	r = initio_isr((struct initio_host *)dev->hostdata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2405
  	spin_unlock_irqrestore(dev->host_lock, flags);
72d39fea9   Alan Cox   [SCSI] initio: Co...
2406
2407
2408
2409
  	if (r)
  		return IRQ_HANDLED;
  	else
  		return IRQ_NONE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2410
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2411

72d39fea9   Alan Cox   [SCSI] initio: Co...
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
  /**
   *	initio_build_scb		-	Build the mappings and SCB
   *	@host: InitIO host taking the command
   *	@cblk: Firmware command block
   *	@cmnd: SCSI midlayer command block
   *
   *	Translate the abstract SCSI command into a firmware command block
   *	suitable for feeding to the InitIO host controller. This also requires
   *	we build the scatter gather lists and ensure they are mapped properly.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2422

72d39fea9   Alan Cox   [SCSI] initio: Co...
2423
  static void initio_build_scb(struct initio_host * host, struct scsi_ctrl_blk * cblk, struct scsi_cmnd * cmnd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2424
  {				/* Create corresponding SCB     */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2425
2426
  	struct scatterlist *sglist;
  	struct sg_entry *sg;		/* Pointer to SG list           */
a258c85d0   FUJITA Tomonori   [SCSI] initio: co...
2427
  	int i, nseg;
72d39fea9   Alan Cox   [SCSI] initio: Co...
2428
  	long total_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2429
  	dma_addr_t dma_addr;
72d39fea9   Alan Cox   [SCSI] initio: Co...
2430
2431
2432
2433
2434
2435
2436
2437
  	/* Fill in the command headers */
  	cblk->post = i91uSCBPost;	/* i91u's callback routine      */
  	cblk->srb = cmnd;
  	cblk->opcode = ExecSCSI;
  	cblk->flags = SCF_POST;	/* After SCSI done, call post routine */
  	cblk->target = cmnd->device->id;
  	cblk->lun = cmnd->device->lun;
  	cblk->ident = cmnd->device->lun | DISC_ALLOW;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2438

72d39fea9   Alan Cox   [SCSI] initio: Co...
2439
  	cblk->flags |= SCF_SENSE;	/* Turn on auto request sense   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2440

72d39fea9   Alan Cox   [SCSI] initio: Co...
2441
2442
2443
  	/* Map the sense buffer into bus memory */
  	dma_addr = dma_map_single(&host->pci_dev->dev, cmnd->sense_buffer,
  				  SENSE_SIZE, DMA_FROM_DEVICE);
423eef6fb   Grant Grundler   [SCSI] initio: fi...
2444
2445
  	cblk->senseptr = (u32)dma_addr;
  	cblk->senselen = SENSE_SIZE;
72d39fea9   Alan Cox   [SCSI] initio: Co...
2446
2447
2448
2449
2450
2451
2452
  	cmnd->SCp.ptr = (char *)(unsigned long)dma_addr;
  	cblk->cdblen = cmnd->cmd_len;
  
  	/* Clear the returned status */
  	cblk->hastat = 0;
  	cblk->tastat = 0;
  	/* Command the command */
64a87b244   Boaz Harrosh   [SCSI] Let scsi_c...
2453
  	memcpy(cblk->cdb, cmnd->cmnd, cmnd->cmd_len);
72d39fea9   Alan Cox   [SCSI] initio: Co...
2454
2455
2456
2457
  
  	/* Set up tags */
  	if (cmnd->device->tagged_supported) {	/* Tag Support                  */
  		cblk->tagmsg = SIMPLE_QUEUE_TAG;	/* Do simple tag only   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2458
  	} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2459
  		cblk->tagmsg = 0;	/* No tag support               */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2460
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2461

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2462
  	/* todo handle map_sg error */
a258c85d0   FUJITA Tomonori   [SCSI] initio: co...
2463
2464
2465
  	nseg = scsi_dma_map(cmnd);
  	BUG_ON(nseg < 0);
  	if (nseg) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2466
2467
  		dma_addr = dma_map_single(&host->pci_dev->dev, &cblk->sglist[0],
  					  sizeof(struct sg_entry) * TOTAL_SG_ENTRY,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2468
  					  DMA_BIDIRECTIONAL);
423eef6fb   Grant Grundler   [SCSI] initio: fi...
2469
  		cblk->bufptr = (u32)dma_addr;
72d39fea9   Alan Cox   [SCSI] initio: Co...
2470
  		cmnd->SCp.dma_handle = dma_addr;
e2d435ea4   Stuart Swales   [SCSI] initio: fi...
2471
  		cblk->sglen = nseg;
72d39fea9   Alan Cox   [SCSI] initio: Co...
2472
2473
  
  		cblk->flags |= SCF_SG;	/* Turn on SG list flag       */
a258c85d0   FUJITA Tomonori   [SCSI] initio: co...
2474
2475
2476
  		total_len = 0;
  		sg = &cblk->sglist[0];
  		scsi_for_each_sg(cmnd, sglist, cblk->sglen, i) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2477
  			sg->data = cpu_to_le32((u32)sg_dma_address(sglist));
423eef6fb   Grant Grundler   [SCSI] initio: fi...
2478
2479
  			sg->len = cpu_to_le32((u32)sg_dma_len(sglist));
  			total_len += sg_dma_len(sglist);
a169e6374   Boaz Harrosh   [SCSI] initio: bu...
2480
  			++sg;
72d39fea9   Alan Cox   [SCSI] initio: Co...
2481
  		}
a258c85d0   FUJITA Tomonori   [SCSI] initio: co...
2482
2483
  		cblk->buflen = (scsi_bufflen(cmnd) > total_len) ?
  			total_len : scsi_bufflen(cmnd);
72d39fea9   Alan Cox   [SCSI] initio: Co...
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
  	} else {	/* No data transfer required */
  		cblk->buflen = 0;
  		cblk->sglen = 0;
  	}
  }
  
  /**
   *	i91u_queuecommand	-	Queue a new command if possible
   *	@cmd: SCSI command block from the mid layer
   *	@done: Completion handler
   *
   *	Attempts to queue a new command with the host adapter. Will return
   *	zero if successful or indicate a host busy condition if not (which
   *	will cause the mid layer to call us again later with the command)
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2499

f281233d3   Jeff Garzik   SCSI host lock pu...
2500
  static int i91u_queuecommand_lck(struct scsi_cmnd *cmd,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2501
2502
  		void (*done)(struct scsi_cmnd *))
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2503
2504
  	struct initio_host *host = (struct initio_host *) cmd->device->host->hostdata;
  	struct scsi_ctrl_blk *cmnd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2505
2506
  
  	cmd->scsi_done = done;
72d39fea9   Alan Cox   [SCSI] initio: Co...
2507
2508
  	cmnd = initio_alloc_scb(host);
  	if (!cmnd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2509
  		return SCSI_MLQUEUE_HOST_BUSY;
72d39fea9   Alan Cox   [SCSI] initio: Co...
2510
2511
  	initio_build_scb(host, cmnd, cmd);
  	initio_exec_scb(host, cmnd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2512
2513
  	return 0;
  }
f281233d3   Jeff Garzik   SCSI host lock pu...
2514
  static DEF_SCSI_QCMD(i91u_queuecommand)
72d39fea9   Alan Cox   [SCSI] initio: Co...
2515
2516
2517
2518
2519
  /**
   *	i91u_bus_reset		-	reset the SCSI bus
   *	@cmnd: Command block we want to trigger the reset for
   *
   *	Initiate a SCSI bus reset sequence
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2520
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2521

72d39fea9   Alan Cox   [SCSI] initio: Co...
2522
  static int i91u_bus_reset(struct scsi_cmnd * cmnd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2523
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2524
  	struct initio_host *host;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2525

72d39fea9   Alan Cox   [SCSI] initio: Co...
2526
  	host = (struct initio_host *) cmnd->device->host->hostdata;
68b3aa7c9   Jeff Garzik   [SCSI] allow slee...
2527

72d39fea9   Alan Cox   [SCSI] initio: Co...
2528
2529
2530
  	spin_lock_irq(cmnd->device->host->host_lock);
  	initio_reset_scsi(host, 0);
  	spin_unlock_irq(cmnd->device->host->host_lock);
68b3aa7c9   Jeff Garzik   [SCSI] allow slee...
2531

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2532
2533
  	return SUCCESS;
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
  /**
   *	i91u_biospararm			-	return the "logical geometry
   *	@sdev: SCSI device
   *	@dev; Matching block device
   *	@capacity: Sector size of drive
   *	@info_array: Return space for BIOS geometry
   *
   *	Map the device geometry in a manner compatible with the host
   *	controller BIOS behaviour.
   *
   *	FIXME: limited to 2^32 sector devices.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2545
   */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2546

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2547
2548
2549
  static int i91u_biosparam(struct scsi_device *sdev, struct block_device *dev,
  		sector_t capacity, int *info_array)
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2550
2551
  	struct initio_host *host;		/* Point to Host adapter control block */
  	struct target_control *tc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2552

72d39fea9   Alan Cox   [SCSI] initio: Co...
2553
2554
  	host = (struct initio_host *) sdev->host->hostdata;
  	tc = &host->targets[sdev->id];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2555

72d39fea9   Alan Cox   [SCSI] initio: Co...
2556
2557
2558
2559
  	if (tc->heads) {
  		info_array[0] = tc->heads;
  		info_array[1] = tc->sectors;
  		info_array[2] = (unsigned long)capacity / tc->heads / tc->sectors;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2560
  	} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2561
  		if (tc->drv_flags & TCF_DRV_255_63) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
  			info_array[0] = 255;
  			info_array[1] = 63;
  			info_array[2] = (unsigned long)capacity / 255 / 63;
  		} else {
  			info_array[0] = 64;
  			info_array[1] = 32;
  			info_array[2] = (unsigned long)capacity >> 11;
  		}
  	}
  
  #if defined(DEBUG_BIOSPARAM)
  	if (i91u_debug & debug_biosparam) {
  		printk("bios geometry: head=%d, sec=%d, cyl=%d
  ",
  		       info_array[0], info_array[1], info_array[2]);
  		printk("WARNING: check, if the bios geometry is correct.
  ");
  	}
  #endif
  
  	return 0;
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
  /**
   *	i91u_unmap_scb		-	Unmap a command
   *	@pci_dev: PCI device the command is for
   *	@cmnd: The command itself
   *
   *	Unmap any PCI mapping/IOMMU resources allocated when the command
   *	was mapped originally as part of initio_build_scb
   */
  
  static void i91u_unmap_scb(struct pci_dev *pci_dev, struct scsi_cmnd *cmnd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
  {
  	/* auto sense buffer */
  	if (cmnd->SCp.ptr) {
  		dma_unmap_single(&pci_dev->dev,
  				 (dma_addr_t)((unsigned long)cmnd->SCp.ptr),
  				 SENSE_SIZE, DMA_FROM_DEVICE);
  		cmnd->SCp.ptr = NULL;
  	}
  
  	/* request buffer */
a258c85d0   FUJITA Tomonori   [SCSI] initio: co...
2604
  	if (scsi_sg_count(cmnd)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2605
  		dma_unmap_single(&pci_dev->dev, cmnd->SCp.dma_handle,
72d39fea9   Alan Cox   [SCSI] initio: Co...
2606
  				 sizeof(struct sg_entry) * TOTAL_SG_ENTRY,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2607
  				 DMA_BIDIRECTIONAL);
a258c85d0   FUJITA Tomonori   [SCSI] initio: co...
2608
  		scsi_dma_unmap(cmnd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2609
2610
  	}
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2611
2612
2613
2614
2615
2616
2617
2618
  /**
   *	i91uSCBPost		-	SCSI callback
   *	@host: Pointer to host adapter control block.
   *	@cmnd: Pointer to SCSI control block.
   *
   *	This is callback routine be called when tulip finish one
   *	SCSI command.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2619

72d39fea9   Alan Cox   [SCSI] initio: Co...
2620
2621
2622
2623
2624
  static void i91uSCBPost(u8 * host_mem, u8 * cblk_mem)
  {
  	struct scsi_cmnd *cmnd;	/* Pointer to SCSI request block */
  	struct initio_host *host;
  	struct scsi_ctrl_blk *cblk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2625

72d39fea9   Alan Cox   [SCSI] initio: Co...
2626
2627
2628
2629
2630
2631
2632
  	host = (struct initio_host *) host_mem;
  	cblk = (struct scsi_ctrl_blk *) cblk_mem;
  	if ((cmnd = cblk->srb) == NULL) {
  		printk(KERN_ERR "i91uSCBPost: SRB pointer is empty
  ");
  		WARN_ON(1);
  		initio_release_scb(host, cblk);	/* Release SCB for current channel */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2633
2634
  		return;
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2635
2636
2637
2638
2639
  
  	/*
  	 *	Remap the firmware error status into a mid layer one
  	 */
  	switch (cblk->hastat) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2640
2641
2642
  	case 0x0:
  	case 0xa:		/* Linked command complete without error and linked normally */
  	case 0xb:		/* Linked command complete without error interrupt generated */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2643
  		cblk->hastat = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2644
2645
2646
2647
  		break;
  
  	case 0x11:		/* Selection time out-The initiator selection or target
  				   reselection was not complete within the SCSI Time out period */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2648
  		cblk->hastat = DID_TIME_OUT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2649
2650
2651
2652
2653
2654
  		break;
  
  	case 0x14:		/* Target bus phase sequence failure-An invalid bus phase or bus
  				   phase sequence was requested by the target. The host adapter
  				   will generate a SCSI Reset Condition, notifying the host with
  				   a SCRD interrupt */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2655
  		cblk->hastat = DID_RESET;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2656
2657
2658
  		break;
  
  	case 0x1a:		/* SCB Aborted. 07/21/98 */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2659
  		cblk->hastat = DID_ABORT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2660
2661
2662
2663
2664
2665
2666
2667
2668
  		break;
  
  	case 0x12:		/* Data overrun/underrun-The target attempted to transfer more data
  				   than was allocated by the Data Length field or the sum of the
  				   Scatter / Gather Data Length fields. */
  	case 0x13:		/* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */
  	case 0x16:		/* Invalid SCB Operation Code. */
  
  	default:
72d39fea9   Alan Cox   [SCSI] initio: Co...
2669
2670
2671
  		printk("ini9100u: %x %x
  ", cblk->hastat, cblk->tastat);
  		cblk->hastat = DID_ERROR;	/* Couldn't find any better */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2672
2673
  		break;
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2674
  	cmnd->result = cblk->tastat | (cblk->hastat << 16);
72d39fea9   Alan Cox   [SCSI] initio: Co...
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
  	i91u_unmap_scb(host->pci_dev, cmnd);
  	cmnd->scsi_done(cmnd);	/* Notify system DONE           */
  	initio_release_scb(host, cblk);	/* Release SCB for current channel */
  }
  
  static struct scsi_host_template initio_template = {
  	.proc_name		= "INI9100U",
  	.name			= "Initio INI-9X00U/UW SCSI device driver",
  	.queuecommand		= i91u_queuecommand,
  	.eh_bus_reset_handler	= i91u_bus_reset,
  	.bios_param		= i91u_biosparam,
  	.can_queue		= MAX_TARGETS * i91u_MAXQUEUE,
  	.this_id		= 1,
  	.sg_tablesize		= SG_ALL,
72d39fea9   Alan Cox   [SCSI] initio: Co...
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
  };
  
  static int initio_probe_one(struct pci_dev *pdev,
  	const struct pci_device_id *id)
  {
  	struct Scsi_Host *shost;
  	struct initio_host *host;
  	u32 reg;
  	u16 bios_seg;
  	struct scsi_ctrl_blk *scb, *tmp, *prev = NULL /* silence gcc */;
  	int num_scb, i, error;
  
  	error = pci_enable_device(pdev);
  	if (error)
  		return error;
  
  	pci_read_config_dword(pdev, 0x44, (u32 *) & reg);
  	bios_seg = (u16) (reg & 0xFF);
  	if (((reg & 0xFF00) >> 8) == 0xFF)
  		reg = 0;
  	bios_seg = (bios_seg << 8) + ((u16) ((reg & 0xFF00) >> 8));
663b4117d   Christoph Hellwig   scsi: initio: use...
2710
  	if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
  		printk(KERN_WARNING  "i91u: Could not set 32 bit DMA mask
  ");
  		error = -ENODEV;
  		goto out_disable_device;
  	}
  	shost = scsi_host_alloc(&initio_template, sizeof(struct initio_host));
  	if (!shost) {
  		printk(KERN_WARNING "initio: Could not allocate host structure.
  ");
  		error = -ENOMEM;
  		goto out_disable_device;
  	}
  	host = (struct initio_host *)shost->hostdata;
  	memset(host, 0, sizeof(struct initio_host));
99f1f5349   Alan Cox   [SCSI] initio: fi...
2725
  	host->addr = pci_resource_start(pdev, 0);
e2d435ea4   Stuart Swales   [SCSI] initio: fi...
2726
  	host->bios_addr = bios_seg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2727

72d39fea9   Alan Cox   [SCSI] initio: Co...
2728
2729
2730
2731
2732
  	if (!request_region(host->addr, 256, "i91u")) {
  		printk(KERN_WARNING "initio: I/O port range 0x%x is busy.
  ", host->addr);
  		error = -ENODEV;
  		goto out_host_put;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2733
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2734
2735
2736
2737
  	if (initio_tag_enable)	/* 1.01i */
  		num_scb = MAX_TARGETS * i91u_MAXQUEUE;
  	else
  		num_scb = MAX_TARGETS + 3;	/* 1-tape, 1-CD_ROM, 1- extra */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2738

72d39fea9   Alan Cox   [SCSI] initio: Co...
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
  	for (; num_scb >= MAX_TARGETS + 3; num_scb--) {
  		i = num_scb * sizeof(struct scsi_ctrl_blk);
  		if ((scb = kzalloc(i, GFP_DMA)) != NULL)
  			break;
  	}
  
  	if (!scb) {
  		printk(KERN_WARNING "initio: Cannot allocate SCB array.
  ");
  		error = -ENOMEM;
  		goto out_release_region;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2751

e9e42faf4   Alan Cox   [SCSI] initio: Fi...
2752
  	host->pci_dev = pdev;
e2d435ea4   Stuart Swales   [SCSI] initio: fi...
2753
2754
  	host->semaph = 1;
  	spin_lock_init(&host->semaph_lock);
72d39fea9   Alan Cox   [SCSI] initio: Co...
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
  	host->num_scbs = num_scb;
  	host->scb = scb;
  	host->next_pending = scb;
  	host->next_avail = scb;
  	for (i = 0, tmp = scb; i < num_scb; i++, tmp++) {
  		tmp->tagid = i;
  		if (i != 0)
  			prev->next = tmp;
  		prev = tmp;
  	}
  	prev->next = NULL;
  	host->scb_end = tmp;
  	host->first_avail = scb;
  	host->last_avail = prev;
e9e42faf4   Alan Cox   [SCSI] initio: Fi...
2769
  	spin_lock_init(&host->avail_lock);
72d39fea9   Alan Cox   [SCSI] initio: Co...
2770

e2d435ea4   Stuart Swales   [SCSI] initio: fi...
2771
  	initio_init(host, phys_to_virt(((u32)bios_seg << 4)));
72d39fea9   Alan Cox   [SCSI] initio: Co...
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
  
  	host->jsstatus0 = 0;
  
  	shost->io_port = host->addr;
  	shost->n_io_port = 0xff;
  	shost->can_queue = num_scb;		/* 03/05/98                      */
  	shost->unique_id = host->addr;
  	shost->max_id = host->max_tar;
  	shost->max_lun = 32;	/* 10/21/97                     */
  	shost->irq = pdev->irq;
  	shost->this_id = host->scsi_id;	/* Assign HCS index           */
  	shost->base = host->addr;
  	shost->sg_tablesize = TOTAL_SG_ENTRY;
4909cc2b8   Michael Opdenacker   [SCSI] remove dep...
2785
  	error = request_irq(pdev->irq, i91u_intr, IRQF_SHARED, "i91u", shost);
72d39fea9   Alan Cox   [SCSI] initio: Co...
2786
2787
2788
2789
2790
2791
2792
  	if (error < 0) {
  		printk(KERN_WARNING "initio: Unable to request IRQ %d
  ", pdev->irq);
  		goto out_free_scbs;
  	}
  
  	pci_set_drvdata(pdev, shost);
72d39fea9   Alan Cox   [SCSI] initio: Co...
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
  
  	error = scsi_add_host(shost, &pdev->dev);
  	if (error)
  		goto out_free_irq;
  	scsi_scan_host(shost);
  	return 0;
  out_free_irq:
  	free_irq(pdev->irq, shost);
  out_free_scbs:
  	kfree(host->scb);
  out_release_region:
  	release_region(host->addr, 256);
  out_host_put:
  	scsi_host_put(shost);
  out_disable_device:
  	pci_disable_device(pdev);
  	return error;
  }
  
  /**
   *	initio_remove_one	-	control shutdown
   *	@pdev:	PCI device being released
   *
   *	Release the resources assigned to this adapter after it has
   *	finished being used.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2818
   */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2819
2820
  
  static void initio_remove_one(struct pci_dev *pdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2821
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2822
2823
2824
2825
2826
2827
2828
  	struct Scsi_Host *host = pci_get_drvdata(pdev);
  	struct initio_host *s = (struct initio_host *)host->hostdata;
  	scsi_remove_host(host);
  	free_irq(pdev->irq, host);
  	release_region(s->addr, 256);
  	scsi_host_put(host);
  	pci_disable_device(pdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2829
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
  
  MODULE_LICENSE("GPL");
  
  static struct pci_device_id initio_pci_tbl[] = {
  	{PCI_VENDOR_ID_INIT, 0x9500, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
  	{PCI_VENDOR_ID_INIT, 0x9400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
  	{PCI_VENDOR_ID_INIT, 0x9401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
  	{PCI_VENDOR_ID_INIT, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
  	{PCI_VENDOR_ID_DOMEX, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
  	{0,}
  };
  MODULE_DEVICE_TABLE(pci, initio_pci_tbl);
  
  static struct pci_driver initio_pci_driver = {
  	.name		= "initio",
  	.id_table	= initio_pci_tbl,
  	.probe		= initio_probe_one,
6f0397905   Greg Kroah-Hartman   Drivers: scsi: re...
2847
  	.remove		= initio_remove_one,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2848
  };
ca57b0699   Liu Shixin   scsi: initio: Use...
2849
  module_pci_driver(initio_pci_driver);
72d39fea9   Alan Cox   [SCSI] initio: Co...
2850
2851
2852
2853
  
  MODULE_DESCRIPTION("Initio INI-9X00U/UW SCSI device driver");
  MODULE_AUTHOR("Initio Corporation");
  MODULE_LICENSE("GPL");