Blame view

drivers/scsi/initio.c 80.6 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
  /**************************************************************************
   * 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...
6
   * Copyright (c) 2004 Christoph Hellwig <hch@lst.de>
fa195afe4   Alan Cox   [SCSI] Clean up m...
7
   * Copyright (c) 2007 Red Hat
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2, or (at your option)
   * any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; see the file COPYING.  If not, write to
   * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
   *
   *************************************************************************
   *
   * 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...
42
   *		- Set can_queue to initio_num_scb
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
   * 06/25/98 hc	- v1.01m
   *		- Get it work for kernel version >= 2.1.75
72d39fea9   Alan Cox   [SCSI] initio: Co...
45
   *		- Dynamic assign SCSI bus reset holding time in initio_init()
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
48
   * 07/02/98 hc	- v1.01n
   *		- Support 0002134A
   * 08/07/98 hc  - v1.01o
72d39fea9   Alan Cox   [SCSI] initio: Co...
49
   *		- Change the initio_abort_srb routine to use scsi_done. <01>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
   * 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
90
91
92
93
94
  #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
95
96
  #include <linux/slab.h>
  #include <linux/jiffies.h>
910638ae7   Matthias Gehre   [PATCH] Replace 0...
97
  #include <linux/dma-mapping.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
99
100
101
102
103
104
105
106
107
108
109
110
111
  #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
112
113
114
  #ifdef DEBUG_i91u
  static unsigned int i91u_debug = DEBUG_DEFAULT;
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
115
  static int initio_tag_enable = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
117
118
119
  
  #ifdef DEBUG_i91u
  static int setup_debug = 0;
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
120
  static void i91uSCBPost(u8 * pHcb, u8 * pScb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
123
124
125
  #define DEBUG_INTERRUPT 0
  #define DEBUG_QUEUE     0
  #define DEBUG_STATE     0
  #define INT_DISC	0
72d39fea9   Alan Cox   [SCSI] initio: Co...
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
  /*--- 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
179
180
  static NVRAM i91unvram;
  static NVRAM *i91unvramp;
72d39fea9   Alan Cox   [SCSI] initio: Co...
181
  static u8 i91udftNvRam[64] =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
183
  	/*----------- header -----------*/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
  	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...
219
  static u8 initio_rate_tbl[8] =	/* fast 20      */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220
  {
25985edce   Lucas De Marchi   Fix common misspe...
221
  				/* nanosecond divide by 4 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
223
224
225
226
227
228
229
230
  	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...
231
232
233
  static void initio_do_pause(unsigned amount)
  {
  	/* Pause for amount jiffies */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
  	unsigned long the_time = jiffies + amount;
72d39fea9   Alan Cox   [SCSI] initio: Co...
235
236
  	while (time_before_eq(jiffies, the_time))
  		cpu_relax();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
238
239
  }
  
  /*-- forward reference --*/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
  /******************************************************************
   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...
270
271
272
273
274
275
276
277
278
279
  
  /**
   *	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
280
281
  {
  	int i;
72d39fea9   Alan Cox   [SCSI] initio: Co...
282
  	u8 b;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283

72d39fea9   Alan Cox   [SCSI] initio: Co...
284
285
286
287
  	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
288
289
290
  
  	for (i = 0; i < 8; i++) {
  		if (instr & 0x80)
72d39fea9   Alan Cox   [SCSI] initio: Co...
291
  			b = SE2CS | SE2DO;		/* -CLK+dataBit */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
  		else
72d39fea9   Alan Cox   [SCSI] initio: Co...
293
294
295
296
297
  			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
298
299
  		instr <<= 1;
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
300
301
  	outb(SE2CS, base + TUL_NVRAM);			/* -CLK */
  	udelay(30);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
303
304
305
306
307
308
309
  /**
   *	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
310
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
311
312
313
  	initio_se2_instr(base, 0x30);	/* EWEN */
  	outb(0, base + TUL_NVRAM);	/* -CS  */
  	udelay(30);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
315
316
317
318
319
320
321
  /**
   *	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
322
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
323
324
325
  	initio_se2_instr(base, 0);	/* EWDS */
  	outb(0, base + TUL_NVRAM);	/* -CS  */
  	udelay(30);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
327
328
329
330
331
332
333
334
  /**
   *	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
335
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
336
337
  	u8 instr, rb;
  	u16 val = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338
  	int i;
72d39fea9   Alan Cox   [SCSI] initio: Co...
339
340
  	instr = (u8) (addr | 0x80);
  	initio_se2_instr(base, instr);	/* READ INSTR */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
342
  
  	for (i = 15; i >= 0; i--) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
343
344
345
  		outb(SE2CS | SE2CLK, base + TUL_NVRAM);	/* +CLK */
  		udelay(30);
  		outb(SE2CS, base + TUL_NVRAM);		/* -CLK */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
347
  
  		/* sample data after the following edge of clock  */
72d39fea9   Alan Cox   [SCSI] initio: Co...
348
349
350
351
  		rb = inb(base + TUL_NVRAM);
  		rb &= SE2DI;
  		val += (rb << i);
  		udelay(30);	/* 6/20/95 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
353
354
355
  	outb(0, base + TUL_NVRAM);		/* no chip select */
  	udelay(30);
  	return val;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
357
358
359
360
361
362
363
364
365
366
  /**
   *	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
367
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
368
369
  	u8 rb;
  	u8 instr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
  	int i;
72d39fea9   Alan Cox   [SCSI] initio: Co...
371
372
  	instr = (u8) (addr | 0x40);
  	initio_se2_instr(base, instr);	/* WRITE INSTR */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
  	for (i = 15; i >= 0; i--) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
374
375
  		if (val & 0x8000)
  			outb(SE2CS | SE2DO, base + TUL_NVRAM);	/* -CLK+dataBit 1 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
  		else
72d39fea9   Alan Cox   [SCSI] initio: Co...
377
378
379
380
381
  			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
382
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
383
384
385
386
  	outb(SE2CS, base + TUL_NVRAM);				/* -CLK */
  	udelay(30);
  	outb(0, base + TUL_NVRAM);				/* -CS  */
  	udelay(30);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387

72d39fea9   Alan Cox   [SCSI] initio: Co...
388
389
  	outb(SE2CS, base + TUL_NVRAM);				/* +CS  */
  	udelay(30);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
391
  
  	for (;;) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
392
393
394
395
396
  		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
397
398
  			break;	/* write complete */
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
399
  	outb(0, base + TUL_NVRAM);				/* -CS */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
401
402
403
404
405
406
407
  /**
   *	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
408

72d39fea9   Alan Cox   [SCSI] initio: Co...
409
  static int initio_se2_rd_all(unsigned long base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
410
411
  {
  	int i;
72d39fea9   Alan Cox   [SCSI] initio: Co...
412
413
  	u16 chksum = 0;
  	u16 *np;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414
415
  
  	i91unvramp = &i91unvram;
72d39fea9   Alan Cox   [SCSI] initio: Co...
416
417
418
  	np = (u16 *) i91unvramp;
  	for (i = 0; i < 32; i++)
  		*np++ = initio_se2_rd(base, i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419

72d39fea9   Alan Cox   [SCSI] initio: Co...
420
  	/* Is signature "ini" ok ? */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421
422
  	if (i91unvramp->NVM_Signature != INI_SIGNATURE)
  		return -1;
72d39fea9   Alan Cox   [SCSI] initio: Co...
423
424
  	/* Is ckecksum ok ? */
  	np = (u16 *) i91unvramp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425
426
  	for (i = 0; i < 31; i++)
  		chksum += *np++;
72d39fea9   Alan Cox   [SCSI] initio: Co...
427
  	if (i91unvramp->NVM_CheckSum != chksum)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
429
430
  		return -1;
  	return 1;
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
431
432
433
434
435
436
437
438
  /**
   *	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
439
440
  {				/* setup default pattern */
  	int i;
72d39fea9   Alan Cox   [SCSI] initio: Co...
441
442
  	u16 chksum = 0;
  	u16 *np, *np1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
443
444
445
  
  	i91unvramp = &i91unvram;
  	/* Calculate checksum first */
72d39fea9   Alan Cox   [SCSI] initio: Co...
446
  	np = (u16 *) i91udftNvRam;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
447
448
  	for (i = 0; i < 31; i++)
  		chksum += *np++;
72d39fea9   Alan Cox   [SCSI] initio: Co...
449
450
  	*np = chksum;
  	initio_se2_ew_en(base);	/* Enable write  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
451

72d39fea9   Alan Cox   [SCSI] initio: Co...
452
453
  	np = (u16 *) i91udftNvRam;
  	np1 = (u16 *) i91unvramp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454
  	for (i = 0; i < 32; i++, np++, np1++) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
455
456
  		if (*np != *np1)
  			initio_se2_wr(base, i, *np);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
458
  	initio_se2_ew_ds(base);	/* Disable write   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
460
461
462
463
464
465
466
467
468
469
470
471
  /**
   *	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
472

72d39fea9   Alan Cox   [SCSI] initio: Co...
473
  static void initio_read_eeprom(unsigned long base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
475
  	u8 gctrl;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476

72d39fea9   Alan Cox   [SCSI] initio: Co...
477
478
479
480
481
482
483
  	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
484
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
485
486
487
  	/* 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
488
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
489
490
491
492
  /**
   *	initio_stop_bm		-	stop bus master
   *	@host: InitIO we are stopping
   *
3ad2f3fbb   Daniel Mack   tree-wide: Assort...
493
   *	Stop any pending DMA operation, aborting the DMA if necessary
72d39fea9   Alan Cox   [SCSI] initio: Co...
494
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
495

72d39fea9   Alan Cox   [SCSI] initio: Co...
496
  static void initio_stop_bm(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
498
499
  	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
500
  		/* wait Abort DMA xfer done */
72d39fea9   Alan Cox   [SCSI] initio: Co...
501
502
  		while ((inb(host->addr + TUL_Int) & XABT) == 0)
  			cpu_relax();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
504
  	outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
506
507
508
509
510
511
512
  /**
   *	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
513

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

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

72d39fea9   Alan Cox   [SCSI] initio: Co...
521
522
  	/* reset tulip chip */
  	outb(0, host->addr + TUL_SSignal);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
524
525
  
  	/* 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...
526
527
  	/* FIXME: this is a very long busy wait right now */
  	initio_do_pause(seconds * HZ);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
528

72d39fea9   Alan Cox   [SCSI] initio: Co...
529
530
  	inb(host->addr + TUL_SInt);
  	return SCSI_RESET_SUCCESS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
531
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
532
533
534
535
536
537
538
539
540
541
542
543
544
545
  /**
   *	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
546
547
  {
  	int i;
72d39fea9   Alan Cox   [SCSI] initio: Co...
548
549
550
551
552
  	u8 *flags;
  	u8 *heads;
  
  	/* Get E2Prom configuration */
  	initio_read_eeprom(host->addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
  	if (i91unvramp->NVM_SCSIInfo[0].NVM_NumOfTarg == 8)
72d39fea9   Alan Cox   [SCSI] initio: Co...
554
  		host->max_tar = 8;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
  	else
72d39fea9   Alan Cox   [SCSI] initio: Co...
556
  		host->max_tar = 16;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
557

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

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

44456d37b   Olaf Hering   [PATCH] turn many...
563
  #ifdef CHK_PARITY
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564
  	/* Enable parity error response */
72d39fea9   Alan Cox   [SCSI] initio: Co...
565
  	outb(inb(host->addr + TUL_PCMD) | 0x40, host->addr + TUL_PCMD);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
567
568
  #endif
  
  	/* Mask all the interrupt       */
72d39fea9   Alan Cox   [SCSI] initio: Co...
569
  	outb(0x1F, host->addr + TUL_Mask);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570

72d39fea9   Alan Cox   [SCSI] initio: Co...
571
  	initio_stop_bm(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
572
  	/* --- Initialize the tulip --- */
72d39fea9   Alan Cox   [SCSI] initio: Co...
573
  	outb(TSC_RST_CHIP, host->addr + TUL_SCtrl0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574
575
  
  	/* program HBA's SCSI ID        */
72d39fea9   Alan Cox   [SCSI] initio: Co...
576
  	outb(host->scsi_id << 4, host->addr + TUL_SScsiId);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577
578
579
  
  	/* Enable Initiator Mode ,phase latch,alternate sync period mode,
  	   disable SCSI reset */
72d39fea9   Alan Cox   [SCSI] initio: Co...
580
581
  	if (host->config & HCC_EN_PAR)
  		host->sconf1 = (TSC_INITDEFAULT | TSC_EN_SCSI_PAR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582
  	else
72d39fea9   Alan Cox   [SCSI] initio: Co...
583
584
  		host->sconf1 = (TSC_INITDEFAULT);
  	outb(host->sconf1, host->addr + TUL_SConfig);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585

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

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

72d39fea9   Alan Cox   [SCSI] initio: Co...
594
595
596
597
598
599
  	/* 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
600
601
  
  	for (i = 0,
72d39fea9   Alan Cox   [SCSI] initio: Co...
602
603
604
605
606
607
608
  	     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
609
  		else
72d39fea9   Alan Cox   [SCSI] initio: Co...
610
611
612
613
614
615
  			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
616
  		else
72d39fea9   Alan Cox   [SCSI] initio: Co...
617
618
619
620
621
  			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
622
623
624
  	}			/* for                          */
  	printk("i91u: PCI Base=0x%04X, IRQ=%d, BIOS=0x%04X0, SCSI ID=%d
  ",
e9e42faf4   Alan Cox   [SCSI] initio: Fi...
625
  	       host->addr, host->pci_dev->irq,
72d39fea9   Alan Cox   [SCSI] initio: Co...
626
627
628
629
630
631
  	       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
632
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
633
634
  	outb(0x17, host->addr + TUL_SCFG1);
  	outb(0xE9, host->addr + TUL_SIntEnable);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
635
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
636
637
638
639
640
641
642
643
  /**
   *	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
644
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
645
646
647
648
649
  	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
650
  #if DEBUG_QUEUE
72d39fea9   Alan Cox   [SCSI] initio: Co...
651
652
  		printk("find scb at %p
  ", scb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
653
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
654
655
656
657
  		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
658
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
659
660
  	spin_unlock_irqrestore(&host->avail_lock, flags);
  	return scb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
662
663
664
665
666
667
668
669
670
  /**
   *	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
671
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
672
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
673
674
  
  #if DEBUG_QUEUE
72d39fea9   Alan Cox   [SCSI] initio: Co...
675
  	printk("Release SCB %p; ", cmnd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
676
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
677
678
679
680
681
682
683
  	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
684
  	} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
685
686
  		host->first_avail = cmnd;
  		host->last_avail = cmnd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
687
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
688
  	spin_unlock_irqrestore(&(host->avail_lock), flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
689
690
691
  }
  
  /***************************************************************************/
72d39fea9   Alan Cox   [SCSI] initio: Co...
692
  static void initio_append_pend_scb(struct initio_host * host, struct scsi_ctrl_blk * scbp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693
694
695
  {
  
  #if DEBUG_QUEUE
72d39fea9   Alan Cox   [SCSI] initio: Co...
696
  	printk("Append pend SCB %p; ", scbp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
698
699
700
701
702
  	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
703
  	} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
704
705
  		host->first_pending = scbp;
  		host->last_pending = scbp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
706
707
708
709
  	}
  }
  
  /***************************************************************************/
72d39fea9   Alan Cox   [SCSI] initio: Co...
710
  static void initio_push_pend_scb(struct initio_host * host, struct scsi_ctrl_blk * scbp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
711
712
713
  {
  
  #if DEBUG_QUEUE
72d39fea9   Alan Cox   [SCSI] initio: Co...
714
  	printk("Push pend SCB %p; ", scbp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
715
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
716
717
718
  	scbp->status = SCB_PEND;
  	if ((scbp->next = host->first_pending) != NULL) {
  		host->first_pending = scbp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
719
  	} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
720
721
  		host->first_pending = scbp;
  		host->last_pending = scbp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
723
  	}
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
724
  static struct scsi_ctrl_blk *initio_find_first_pend_scb(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
725
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
726
  	struct scsi_ctrl_blk *first;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727

72d39fea9   Alan Cox   [SCSI] initio: Co...
728
729
730
731
732
733
734
735
  	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
736
  		} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
737
738
739
740
  			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
741
742
  				continue;
  			}
72d39fea9   Alan Cox   [SCSI] initio: Co...
743
  			return first;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
744
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
745
  		first = first->next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
746
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
747
  	return first;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
748
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
749
750
  
  static void initio_unlink_pend_scb(struct initio_host * host, struct scsi_ctrl_blk * scb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
752
  	struct scsi_ctrl_blk *tmp, *prev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
754
  
  #if DEBUG_QUEUE
72d39fea9   Alan Cox   [SCSI] initio: Co...
755
  	printk("unlink pend SCB %p; ", scb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
756
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
757
758
759
760
761
762
  	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
763
  			} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
764
765
766
  				prev->next = tmp->next;
  				if (tmp == host->last_pending)
  					host->last_pending = prev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
767
  			}
72d39fea9   Alan Cox   [SCSI] initio: Co...
768
  			tmp->next = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
769
770
  			break;
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
771
772
  		prev = tmp;
  		tmp = tmp->next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
774
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
775
776
  
  static void initio_append_busy_scb(struct initio_host * host, struct scsi_ctrl_blk * scbp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777
778
779
  {
  
  #if DEBUG_QUEUE
e2d435ea4   Stuart Swales   [SCSI] initio: fi...
780
  	printk("append busy SCB %p; ", scbp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
782
783
  	if (scbp->tagmsg)
  		host->act_tags[scbp->target]++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
784
  	else
72d39fea9   Alan Cox   [SCSI] initio: Co...
785
786
787
788
789
790
  		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
791
  	} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
792
793
  		host->first_busy = scbp;
  		host->last_busy = scbp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
794
795
796
797
  	}
  }
  
  /***************************************************************************/
72d39fea9   Alan Cox   [SCSI] initio: Co...
798
  static struct scsi_ctrl_blk *initio_pop_busy_scb(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
799
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
800
  	struct scsi_ctrl_blk *tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
801

72d39fea9   Alan Cox   [SCSI] initio: Co...
802
803
804
805
806
807
  	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
808
  		else
72d39fea9   Alan Cox   [SCSI] initio: Co...
809
  			host->targets[tmp->target].flags &= ~TCF_BUSY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
810
811
  	}
  #if DEBUG_QUEUE
72d39fea9   Alan Cox   [SCSI] initio: Co...
812
  	printk("Pop busy SCB %p; ", tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
813
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
814
  	return tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
815
816
817
  }
  
  /***************************************************************************/
72d39fea9   Alan Cox   [SCSI] initio: Co...
818
  static void initio_unlink_busy_scb(struct initio_host * host, struct scsi_ctrl_blk * scb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
819
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
820
  	struct scsi_ctrl_blk *tmp, *prev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
821
822
  
  #if DEBUG_QUEUE
72d39fea9   Alan Cox   [SCSI] initio: Co...
823
  	printk("unlink busy SCB %p; ", scb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
824
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
825
826
827
828
829
830
  	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
831
  			} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
832
833
834
  				prev->next = tmp->next;
  				if (tmp == host->last_busy)
  					host->last_busy = prev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
835
  			}
72d39fea9   Alan Cox   [SCSI] initio: Co...
836
837
838
  			tmp->next = NULL;
  			if (tmp->tagmsg)
  				host->act_tags[tmp->target]--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
839
  			else
72d39fea9   Alan Cox   [SCSI] initio: Co...
840
  				host->targets[tmp->target].flags &= ~TCF_BUSY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
841
842
  			break;
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
843
844
  		prev = tmp;
  		tmp = tmp->next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
845
846
847
  	}
  	return;
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
848
  struct scsi_ctrl_blk *initio_find_busy_scb(struct initio_host * host, u16 tarlun)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
849
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
850
851
  	struct scsi_ctrl_blk *tmp, *prev;
  	u16 scbp_tarlun;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
852

72d39fea9   Alan Cox   [SCSI] initio: Co...
853
854
855
  	prev = tmp = host->first_busy;
  	while (tmp != NULL) {
  		scbp_tarlun = (tmp->lun << 8) | (tmp->target);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
856
857
858
  		if (scbp_tarlun == tarlun) {	/* Unlink this SCB              */
  			break;
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
859
860
  		prev = tmp;
  		tmp = tmp->next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
861
862
  	}
  #if DEBUG_QUEUE
72d39fea9   Alan Cox   [SCSI] initio: Co...
863
  	printk("find busy SCB %p; ", tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
864
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
865
  	return tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
866
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
867
  static void initio_append_done_scb(struct initio_host * host, struct scsi_ctrl_blk * scbp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
868
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
869
  #if DEBUG_QUEUE
72d39fea9   Alan Cox   [SCSI] initio: Co...
870
  	printk("append done SCB %p; ", scbp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
871
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
872
873
874
875
876
  	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
877
  	} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
878
879
  		host->first_done = scbp;
  		host->last_done = scbp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
880
881
  	}
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
882
  struct scsi_ctrl_blk *initio_find_done_scb(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
883
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
884
  	struct scsi_ctrl_blk *tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
885

72d39fea9   Alan Cox   [SCSI] initio: Co...
886
887
888
889
  	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
890
891
  	}
  #if DEBUG_QUEUE
72d39fea9   Alan Cox   [SCSI] initio: Co...
892
  	printk("find done SCB %p; ",tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
893
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
894
  	return tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
895
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
896
  static int initio_abort_srb(struct initio_host * host, struct scsi_cmnd *srbp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
897
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
898
899
  	unsigned long flags;
  	struct scsi_ctrl_blk *tmp, *prev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
900

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

72d39fea9   Alan Cox   [SCSI] initio: Co...
903
  	if ((host->semaph == 0) && (host->active == NULL)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
904
  		/* disable Jasmin SCSI Int        */
72d39fea9   Alan Cox   [SCSI] initio: Co...
905
906
907
908
909
910
911
912
  		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
913
914
  		return SCSI_ABORT_SNOOZE;
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
915
916
  	prev = tmp = host->first_pending;	/* Check Pend queue */
  	while (tmp != NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
917
  		/* 07/27/98 */
72d39fea9   Alan Cox   [SCSI] initio: Co...
918
919
920
  		if (tmp->srb == srbp) {
  			if (tmp == host->active) {
  				spin_unlock_irqrestore(&host->semaph_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
921
  				return SCSI_ABORT_BUSY;
72d39fea9   Alan Cox   [SCSI] initio: Co...
922
923
924
  			} 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
925
  			} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
926
927
928
  				prev->next = tmp->next;
  				if (tmp == host->last_pending)
  					host->last_pending = prev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
929
  			}
72d39fea9   Alan Cox   [SCSI] initio: Co...
930
931
932
933
934
  			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
935
936
  			return SCSI_ABORT_SUCCESS;
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
937
938
  		prev = tmp;
  		tmp = tmp->next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
939
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
940
941
942
943
944
  	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
945
  				return SCSI_ABORT_BUSY;
72d39fea9   Alan Cox   [SCSI] initio: Co...
946
947
  			} else if (tmp->tagmsg == 0) {
  				spin_unlock_irqrestore(&host->semaph_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
948
949
  				return SCSI_ABORT_BUSY;
  			} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
950
951
952
953
  				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
954
  				} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
955
956
957
  					prev->next = tmp->next;
  					if (tmp == host->last_busy)
  						host->last_busy = prev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
958
  				}
72d39fea9   Alan Cox   [SCSI] initio: Co...
959
  				tmp->next = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
960

72d39fea9   Alan Cox   [SCSI] initio: Co...
961
962
963
964
965
  				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
966
967
968
  				return SCSI_ABORT_SUCCESS;
  			}
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
969
970
  		prev = tmp;
  		tmp = tmp->next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
971
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
972
973
  	spin_unlock_irqrestore(&host->semaph_lock, flags);
  	return SCSI_ABORT_NOT_RUNNING;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
974
975
976
  }
  
  /***************************************************************************/
72d39fea9   Alan Cox   [SCSI] initio: Co...
977
  static int initio_bad_seq(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
978
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
979
  	struct scsi_ctrl_blk *scb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
980

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

72d39fea9   Alan Cox   [SCSI] initio: Co...
984
985
986
987
988
  	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
989
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
990
991
992
  	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
993
  }
a2ba192c9   Adrian Bunk   [PATCH] drivers/s...
994

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
995
  /************************************************************************/
72d39fea9   Alan Cox   [SCSI] initio: Co...
996
  static void initio_exec_scb(struct initio_host * host, struct scsi_ctrl_blk * scb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
997
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
998
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
999

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

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

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

72d39fea9   Alan Cox   [SCSI] initio: Co...
1007
  	initio_append_pend_scb(host, scb);	/* Append this SCB to Pending queue */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1008
1009
  
  /* VVVVV 07/21/98 */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1010
1011
1012
1013
1014
  	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
1015

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

72d39fea9   Alan Cox   [SCSI] initio: Co...
1018
1019
1020
  		spin_lock_irqsave(&host->semaph_lock, flags);
  		host->semaph = 1;
  		outb(0x0F, host->addr + TUL_Mask);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1021
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1022
  	spin_unlock_irqrestore(&host->semaph_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1023
1024
1025
1026
  	return;
  }
  
  /***************************************************************************/
72d39fea9   Alan Cox   [SCSI] initio: Co...
1027
  static int initio_isr(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1028
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1029
1030
1031
  	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
1032
  			/* Disable Tulip SCSI Int */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1033
  			host->semaph = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1034

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

72d39fea9   Alan Cox   [SCSI] initio: Co...
1037
1038
1039
  			host->semaph = 1;
  			outb(0x0F, host->addr + TUL_Mask);
  			return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1040
1041
  		}
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1042
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1043
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1044
  static int tulip_main(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1045
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1046
  	struct scsi_ctrl_blk *scb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1047
1048
  
  	for (;;) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1049
1050
1051
1052
1053
1054
1055
1056
1057
  		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
1058
1059
  				continue;
  			}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1060
1061
  			if (!(scb->mode & SCM_RSENS)) {		/* not in auto req. sense mode */
  				if (scb->tastat == 2) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1062
1063
  
  					/* clr sync. nego flag */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1064
1065
1066
  					if (scb->flags & SCF_SENSE) {
  						u8 len;
  						len = scb->senselen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1067
1068
  						if (len == 0)
  							len = 1;
72d39fea9   Alan Cox   [SCSI] initio: Co...
1069
1070
1071
1072
  						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
1073
  						   and won't report HOST_DO_DU in state_6 */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
  						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
1086
1087
1088
1089
  						break;
  					}
  				}
  			} else {	/* in request sense mode */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1090
  				if (scb->tastat == 2) {		/* check contition status again after sending
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1091
  									   requset sense cmd 0x3 */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1092
  					scb->hastat = HOST_BAD_PHAS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1093
  				}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1094
  				scb->tastat = 2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1095
  			}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1096
1097
1098
1099
  			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
1100
1101
  			}
  		}		/* while */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1102
  		/* find_active: */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1103
  		if (inb(host->addr + TUL_SStatus0) & TSS_INT_PENDING)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1104
  			continue;
72d39fea9   Alan Cox   [SCSI] initio: Co...
1105
  		if (host->active)	/* return to OS and wait for xfer_done_ISR/Selected_ISR */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1106
  			return 1;	/* return to OS, enable interrupt */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1107
  		/* Check pending SCB            */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1108
  		if (initio_find_first_pend_scb(host) == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1109
  			return 1;	/* return to OS, enable interrupt */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1110
1111
1112
  	}			/* End of for loop */
  	/* statement won't reach here */
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1113
  static void tulip_scsi(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1114
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1115
1116
  	struct scsi_ctrl_blk *scb;
  	struct target_control *active_tc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1117
1118
  
  	/* make sure to service interrupt asap */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1119
1120
1121
1122
1123
1124
  	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
1125
1126
  			return;
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1127
1128
1129
  		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
1130
1131
  			return;
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1132
1133
  		if (host->jsint & TSS_SEL_TIMEOUT) {
  			int_initio_busfree(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1134
1135
  			return;
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1136
1137
  		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
1138
1139
  			return;
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1140
1141
1142
  		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
1143
1144
1145
  			return;
  		}
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1146
  	if (host->active != NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1147
  		return;
72d39fea9   Alan Cox   [SCSI] initio: Co...
1148
  	if ((scb = initio_find_first_pend_scb(host)) == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1149
1150
1151
  		return;
  
  	/* program HBA's SCSI ID & target SCSI ID */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1152
1153
1154
1155
  	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
1156

72d39fea9   Alan Cox   [SCSI] initio: Co...
1157
1158
  		if (scb->tagmsg)
  			active_tc->drv_flags |= TCF_DRV_EN_TAG;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1159
  		else
72d39fea9   Alan Cox   [SCSI] initio: Co...
1160
  			active_tc->drv_flags &= ~TCF_DRV_EN_TAG;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1161

72d39fea9   Alan Cox   [SCSI] initio: Co...
1162
1163
1164
  		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
1165
  		} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1166
1167
  			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
1168
  			} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1169
1170
  				if (scb->tagmsg)
  					initio_select_atn3(host, scb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1171
  				else
72d39fea9   Alan Cox   [SCSI] initio: Co...
1172
  					initio_select_atn(host, scb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1173
1174
  			}
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1175
1176
1177
  		if (scb->flags & SCF_POLL) {
  			while (wait_tulip(host) != -1) {
  				if (initio_next_state(host) == -1)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1178
1179
1180
  					break;
  			}
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1181
1182
1183
1184
1185
1186
  	} 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
1187
1188
1189
  					break;
  			}
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1190
1191
1192
1193
  	} 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
1194
  		} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1195
1196
1197
  			scb->opcode = BusDevRst;
  			initio_select_atn_stop(host, scb);
  			scb->next_state = 8;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1198
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1199
  	} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1200
1201
1202
  		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
1203
1204
1205
  	}
  	return;
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1206
1207
1208
1209
1210
1211
1212
1213
1214
  /**
   *	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
1215

72d39fea9   Alan Cox   [SCSI] initio: Co...
1216
  static int initio_next_state(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1217
1218
  {
  	int next;
72d39fea9   Alan Cox   [SCSI] initio: Co...
1219
  	next = host->active->next_state;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1220
1221
1222
  	for (;;) {
  		switch (next) {
  		case 1:
72d39fea9   Alan Cox   [SCSI] initio: Co...
1223
  			next = initio_state_1(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1224
1225
  			break;
  		case 2:
72d39fea9   Alan Cox   [SCSI] initio: Co...
1226
  			next = initio_state_2(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1227
1228
  			break;
  		case 3:
72d39fea9   Alan Cox   [SCSI] initio: Co...
1229
  			next = initio_state_3(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1230
1231
  			break;
  		case 4:
72d39fea9   Alan Cox   [SCSI] initio: Co...
1232
  			next = initio_state_4(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1233
1234
  			break;
  		case 5:
72d39fea9   Alan Cox   [SCSI] initio: Co...
1235
  			next = initio_state_5(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1236
1237
  			break;
  		case 6:
72d39fea9   Alan Cox   [SCSI] initio: Co...
1238
  			next = initio_state_6(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1239
1240
  			break;
  		case 7:
72d39fea9   Alan Cox   [SCSI] initio: Co...
1241
  			next = initio_state_7(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1242
1243
  			break;
  		case 8:
72d39fea9   Alan Cox   [SCSI] initio: Co...
1244
  			return initio_bus_device_reset(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1245
  		default:
72d39fea9   Alan Cox   [SCSI] initio: Co...
1246
  			return initio_bad_seq(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1247
1248
1249
1250
1251
  		}
  		if (next <= 0)
  			return next;
  	}
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1252
1253
1254
1255
1256
1257
1258
1259
  /**
   *	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
1260
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1261
1262
  	struct scsi_ctrl_blk *scb = host->active;
  	struct target_control *active_tc = host->active_tc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1263
1264
1265
  #if DEBUG_STATE
  	printk("-s1-");
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
1266
1267
1268
  	/* 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
1269

72d39fea9   Alan Cox   [SCSI] initio: Co...
1270
  	outb(active_tc->sconfig0, host->addr + TUL_SConfig );
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1271
  	/* ATN on */
72d39fea9   Alan Cox   [SCSI] initio: Co...
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
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
  	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
1312

72d39fea9   Alan Cox   [SCSI] initio: Co...
1313
  static int initio_state_2(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1314
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1315
1316
  	struct scsi_ctrl_blk *scb = host->active;
  	struct target_control *active_tc = host->active_tc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1317
1318
1319
  #if DEBUG_STATE
  	printk("-s2-");
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
1320
1321
  	initio_unlink_pend_scb(host, scb);
  	initio_append_busy_scb(host, scb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1322

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

72d39fea9   Alan Cox   [SCSI] initio: Co...
1325
1326
1327
1328
1329
1330
1331
  	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
1332
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1333
1334
1335
1336
1337
1338
1339
1340
  /**
   *	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
1341
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1342
1343
  	struct scsi_ctrl_blk *scb = host->active;
  	struct target_control *active_tc = host->active_tc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1344
1345
1346
1347
1348
1349
  	int i;
  
  #if DEBUG_STATE
  	printk("-s3-");
  #endif
  	for (;;) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1350
  		switch (host->phase) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1351
  		case CMD_OUT:	/* Command out phase            */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1352
1353
1354
1355
1356
1357
1358
1359
  			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
1360
1361
  
  		case MSG_IN:	/* Message in phase             */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1362
1363
1364
  			scb->next_state = 3;
  			if (initio_msgin(host) == -1)
  				return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1365
1366
1367
  			break;
  
  		case STATUS_IN:	/* Status phase                 */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1368
1369
  			if (initio_status_msg(host) == -1)
  				return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1370
1371
1372
  			break;
  
  		case MSG_OUT:	/* Message out phase            */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1373
1374
1375
1376
1377
  			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
1378
  			} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
  				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
1391
1392
1393
  
  			}
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1394
  		default:
72d39fea9   Alan Cox   [SCSI] initio: Co...
1395
  			return initio_bad_seq(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1396
1397
1398
  		}
  	}
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1399
1400
1401
1402
1403
1404
  /**
   *	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
1405

72d39fea9   Alan Cox   [SCSI] initio: Co...
1406
  static int initio_state_4(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1407
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1408
  	struct scsi_ctrl_blk *scb = host->active;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1409
1410
1411
1412
  
  #if DEBUG_STATE
  	printk("-s4-");
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
1413
1414
  	if ((scb->flags & SCF_DIR) == SCF_NO_XF) {
  		return 6;	/* Go to state 6 (After data) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1415
1416
  	}
  	for (;;) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1417
1418
  		if (scb->buflen == 0)
  			return 6;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1419

72d39fea9   Alan Cox   [SCSI] initio: Co...
1420
  		switch (host->phase) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1421
1422
  
  		case STATUS_IN:	/* Status phase                 */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1423
1424
1425
1426
  			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
1427
1428
1429
  			break;
  
  		case MSG_IN:	/* Message in phase             */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1430
1431
1432
  			scb->next_state = 0x4;
  			if (initio_msgin(host) == -1)
  				return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1433
1434
1435
  			break;
  
  		case MSG_OUT:	/* Message out phase            */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1436
1437
1438
1439
1440
1441
  			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
1442
  			} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1443
1444
1445
1446
  				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
1447
1448
1449
1450
  			}
  			break;
  
  		case DATA_IN:	/* Data in phase                */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1451
  			return initio_xfer_data_in(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1452
1453
  
  		case DATA_OUT:	/* Data out phase               */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1454
  			return initio_xfer_data_out(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1455
1456
  
  		default:
72d39fea9   Alan Cox   [SCSI] initio: Co...
1457
  			return initio_bad_seq(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1458
1459
1460
  		}
  	}
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1461
1462
1463
1464
1465
1466
1467
1468
  /**
   *	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
1469
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1470
  	struct scsi_ctrl_blk *scb = host->active;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1471
1472
1473
1474
1475
  	long cnt, xcnt;		/* cannot use unsigned !! code: if (xcnt < 0) */
  
  #if DEBUG_STATE
  	printk("-s5-");
  #endif
72d39fea9   Alan Cox   [SCSI] initio: Co...
1476
1477
  	/*------ get remaining count -------*/
  	cnt = inl(host->addr + TUL_SCnt0) & 0x0FFFFFF;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1478

72d39fea9   Alan Cox   [SCSI] initio: Co...
1479
  	if (inb(host->addr + TUL_XCmd) & 0x20) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1480
1481
  		/* ----------------------- DATA_IN ----------------------------- */
  		/* check scsi parity error */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1482
1483
1484
  		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
1485
  			/* tell Hardware  scsi xfer has been terminated */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1486
  			outb(inb(host->addr + TUL_XCtrl) | 0x80, host->addr + TUL_XCtrl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1487
  			/* wait until DMA xfer not pending */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1488
1489
  			while (inb(host->addr + TUL_XStatus) & XPEND)
  				cpu_relax();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1490
1491
  		}
  	} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1492
1493
1494
1495
  		/*-------- 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
1496
  			else
72d39fea9   Alan Cox   [SCSI] initio: Co...
1497
  				cnt += (inb(host->addr + TUL_SFifoCnt) & 0x1F);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1498
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1499
1500
  		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
1501
  			/* wait Abort DMA xfer done */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1502
1503
  			while ((inb(host->addr + TUL_Int) & XABT) == 0)
  				cpu_relax();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1504
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1505
1506
1507
1508
  		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
1509
1510
  			cnt = 0;
  		} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1511
1512
  			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
1513
1514
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1515
  	if (cnt == 0) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1516
1517
  		scb->buflen = 0;
  		return 6;	/* After Data */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1518
1519
  	}
  	/* Update active data pointer */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1520
1521
1522
1523
1524
1525
1526
1527
1528
  	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
1529
  			if (xcnt < 0) {		/* this sgp xfer half done */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1530
1531
1532
1533
  				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
1534
  				/* new SG table ptr */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1535
  				scb->sglen = (u8) (scb->sgmax - i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1536
  				/* new SG table len */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1537
  				scb->sgidx = (u16) i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1538
  				/* for next disc and come in this loop */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1539
  				return 4;	/* Go to state 4                */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1540
1541
1542
  			}
  			/* else (xcnt >= 0 , i.e. this sgp already xferred */
  		}		/* for */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1543
  		return 6;	/* Go to state 6                */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1544
  	} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1545
  		scb->bufptr += (u32) xcnt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1546
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1547
  	return 4;		/* Go to state 4                */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1548
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1549
1550
1551
1552
1553
1554
1555
1556
  /**
   *	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
1557
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1558
  	struct scsi_ctrl_blk *scb = host->active;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1559
1560
1561
1562
1563
  
  #if DEBUG_STATE
  	printk("-s6-");
  #endif
  	for (;;) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1564
  		switch (host->phase) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1565
  		case STATUS_IN:	/* Status phase                 */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1566
1567
  			if ((initio_status_msg(host)) == -1)
  				return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1568
1569
1570
  			break;
  
  		case MSG_IN:	/* Message in phase             */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1571
1572
1573
  			scb->next_state = 6;
  			if ((initio_msgin(host)) == -1)
  				return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1574
1575
1576
  			break;
  
  		case MSG_OUT:	/* Message out phase            */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1577
1578
1579
1580
  			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
1581
1582
1583
  			break;
  
  		case DATA_IN:	/* Data in phase                */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1584
  			return initio_xpad_in(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1585
1586
  
  		case DATA_OUT:	/* Data out phase               */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1587
  			return initio_xpad_out(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1588
1589
  
  		default:
72d39fea9   Alan Cox   [SCSI] initio: Co...
1590
  			return initio_bad_seq(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1591
1592
1593
  		}
  	}
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1594
1595
1596
1597
1598
1599
1600
  /**
   *	initio_state_7		-	SCSI state machine
   *	@host: InitIO host we are controlling
   *
   */
  
  int initio_state_7(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1601
1602
1603
1604
1605
1606
1607
  {
  	int cnt, i;
  
  #if DEBUG_STATE
  	printk("-s7-");
  #endif
  	/* flush SCSI FIFO */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1608
  	cnt = inb(host->addr + TUL_SFifoCnt) & 0x1F;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1609
1610
  	if (cnt) {
  		for (i = 0; i < cnt; i++)
72d39fea9   Alan Cox   [SCSI] initio: Co...
1611
  			inb(host->addr + TUL_SFifo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1612
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1613
  	switch (host->phase) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1614
1615
  	case DATA_IN:		/* Data in phase                */
  	case DATA_OUT:		/* Data out phase               */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1616
  		return initio_bad_seq(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1617
  	default:
72d39fea9   Alan Cox   [SCSI] initio: Co...
1618
  		return 6;	/* Go to state 6                */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1619
1620
  	}
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1621
1622
1623
1624
1625
1626
1627
1628
1629
  /**
   *	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
1630
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1631
  	struct scsi_ctrl_blk *scb = host->active;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1632

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

72d39fea9   Alan Cox   [SCSI] initio: Co...
1636
1637
  	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
1638

72d39fea9   Alan Cox   [SCSI] initio: Co...
1639
1640
1641
1642
  	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
1643
  	} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1644
1645
1646
  		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
1647
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1648
1649
  	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
1650
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1651
1652
1653
1654
1655
1656
1657
1658
  /**
   *	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
1659

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

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

72d39fea9   Alan Cox   [SCSI] initio: Co...
1667
1668
1669
1670
1671
1672
1673
  	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
1674
  	} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1675
1676
1677
  		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
1678
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1679
1680
  	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
1681
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1682
  int initio_xpad_in(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1683
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1684
1685
  	struct scsi_ctrl_blk *scb = host->active;
  	struct target_control *active_tc = host->active_tc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1686

72d39fea9   Alan Cox   [SCSI] initio: Co...
1687
1688
  	if ((scb->flags & SCF_DIR) != SCF_NO_DCHK)
  		scb->hastat = HOST_DO_DU;	/* over run             */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1689
  	for (;;) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1690
1691
  		if (active_tc->js_period & TSC_WIDE_SCSI)
  			outl(2, host->addr + TUL_SCnt0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1692
  		else
72d39fea9   Alan Cox   [SCSI] initio: Co...
1693
  			outl(1, host->addr + TUL_SCnt0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1694

72d39fea9   Alan Cox   [SCSI] initio: Co...
1695
1696
1697
1698
1699
1700
  		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
1701
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1702
  		inb(host->addr + TUL_SFifo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1703
1704
  	}
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1705
  int initio_xpad_out(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1706
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1707
1708
  	struct scsi_ctrl_blk *scb = host->active;
  	struct target_control *active_tc = host->active_tc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1709

72d39fea9   Alan Cox   [SCSI] initio: Co...
1710
1711
  	if ((scb->flags & SCF_DIR) != SCF_NO_DCHK)
  		scb->hastat = HOST_DO_DU;	/* over run             */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1712
  	for (;;) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1713
1714
  		if (active_tc->js_period & TSC_WIDE_SCSI)
  			outl(2, host->addr + TUL_SCnt0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1715
  		else
72d39fea9   Alan Cox   [SCSI] initio: Co...
1716
  			outl(1, host->addr + TUL_SCnt0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1717

72d39fea9   Alan Cox   [SCSI] initio: Co...
1718
1719
1720
1721
1722
1723
1724
1725
  		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
1726
1727
1728
  		}
  	}
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1729
  int initio_status_msg(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1730
  {				/* status & MSG_IN */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1731
1732
1733
1734
1735
1736
  	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
1737

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

72d39fea9   Alan Cox   [SCSI] initio: Co...
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
  	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
1759
1760
  		}
  		if (msg == 0) {	/* Command complete             */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1761
1762
1763
1764
1765
  			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
1766
1767
  
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1768
1769
1770
  		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
1771
1772
  		}
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1773
  	return initio_bad_seq(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1774
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1775
  /* scsi bus free */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1776
  int int_initio_busfree(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1777
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1778
  	struct scsi_ctrl_blk *scb = host->active;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1779

72d39fea9   Alan Cox   [SCSI] initio: Co...
1780
1781
1782
1783
1784
  	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
1785
  		} else {	/* Unexpected bus free          */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1786
1787
1788
  			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
1789
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1790
1791
  		host->active = NULL;
  		host->active_tc = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1792
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1793
1794
1795
1796
  	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
1797
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
  /**
   *	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
1809
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1810
  	struct scsi_ctrl_blk *scb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1811
1812
1813
  	int i;
  
  	/* if DMA xfer is pending, abort DMA xfer */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1814
1815
  	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
1816
  		/* wait Abort DMA xfer done */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1817
1818
1819
  		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
1820
1821
  	}
  	/* Abort all active & disconnected scb */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1822
1823
1824
  	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
1825
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1826
1827
  	host->active = NULL;
  	host->active_tc = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1828
1829
  
  	/* clr sync nego. done flag */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1830
1831
1832
  	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
1833
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1834
  /**
25985edce   Lucas De Marchi   Fix common misspe...
1835
   *	int_initio_scsi_resel	-	Reselection occurred
72d39fea9   Alan Cox   [SCSI] initio: Co...
1836
1837
1838
1839
1840
1841
   *	@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
1842

72d39fea9   Alan Cox   [SCSI] initio: Co...
1843
  int int_initio_resel(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1844
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1845
1846
1847
1848
  	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
1849

72d39fea9   Alan Cox   [SCSI] initio: Co...
1850
1851
1852
1853
1854
  	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
1855
1856
  	}
  	/* --------- get target id---------------------- */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1857
  	tar = inb(host->addr + TUL_SBusId);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1858
  	/* ------ get LUN from Identify message----------- */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1859
  	lun = inb(host->addr + TUL_SIdent) & 0x0F;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1860
  	/* 07/22/98 from 0x1F -> 0x0F */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1861
1862
1863
1864
  	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
1865
1866
  
  	/* ------------- tag queueing ? ------------------- */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1867
1868
1869
1870
  	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
1871
  			goto no_tag;
72d39fea9   Alan Cox   [SCSI] initio: Co...
1872
1873
1874
1875
1876
  		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
1877

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

72d39fea9   Alan Cox   [SCSI] initio: Co...
1883
  		if (host->phase != MSG_IN)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1884
  			goto no_tag;
72d39fea9   Alan Cox   [SCSI] initio: Co...
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
  		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
1900
1901
  	} else {		/* No tag               */
  	      no_tag:
72d39fea9   Alan Cox   [SCSI] initio: Co...
1902
1903
  		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
1904
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1905
1906
1907
1908
  		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
1909
1910
1911
1912
  		}
  	}
  	return 0;
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1913
1914
1915
1916
1917
1918
1919
  /**
   *	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
1920

72d39fea9   Alan Cox   [SCSI] initio: Co...
1921
  static int int_initio_bad_seq(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1922
  {				/* target wrong phase           */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1923
  	struct scsi_ctrl_blk *scb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1924
  	int i;
72d39fea9   Alan Cox   [SCSI] initio: Co...
1925
  	initio_reset_scsi(host, 10);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1926

72d39fea9   Alan Cox   [SCSI] initio: Co...
1927
1928
1929
  	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
1930
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
1931
1932
1933
  	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
1934
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1935
1936
1937
1938
1939
1940
1941
1942
1943
  /**
   *	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
1944
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1945
1946
1947
1948
1949
  	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
1950

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

72d39fea9   Alan Cox   [SCSI] initio: Co...
1954
  	return initio_wait_disc(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1955
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1956
1957
1958
1959
1960
1961
1962
1963
1964
  /**
   *	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
1965
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1966
1967
1968
1969
1970
  	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
1971

72d39fea9   Alan Cox   [SCSI] initio: Co...
1972
1973
  	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
1974

72d39fea9   Alan Cox   [SCSI] initio: Co...
1975
  	return initio_wait_disc(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1976
1977
  
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
1978
1979
1980
1981
1982
1983
1984
  /**
   *	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
1985
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1986
  	struct target_control *active_tc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1987
1988
  
  	for (;;) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
1989
  		outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1990

72d39fea9   Alan Cox   [SCSI] initio: Co...
1991
1992
1993
1994
  		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
1995

72d39fea9   Alan Cox   [SCSI] initio: Co...
1996
  		switch (inb(host->addr + TUL_SFifo)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1997
  		case MSG_DISC:	/* Disconnect msg */
72d39fea9   Alan Cox   [SCSI] initio: Co...
1998
1999
  			outb(TSC_MSG_ACCEPT, host->addr + TUL_SCmd);
  			return initio_wait_disc(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2000
2001
2002
  		case MSG_SDP:
  		case MSG_RESTORE:
  		case MSG_NOP:
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_REJ:	/* Clear ATN first              */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2006
2007
2008
2009
2010
2011
2012
  			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
2013
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2014
  		case MSG_EXTEND:	/* extended msg */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2015
  			initio_msgin_extend(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2016
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2017
  		case MSG_IGNOREWIDE:
72d39fea9   Alan Cox   [SCSI] initio: Co...
2018
  			initio_msgin_accept(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2019
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2020
  		case MSG_COMP:
72d39fea9   Alan Cox   [SCSI] initio: Co...
2021
2022
2023
  			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
2024
  		default:
72d39fea9   Alan Cox   [SCSI] initio: Co...
2025
  			initio_msgout_reject(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2026
2027
  			break;
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2028
2029
  		if (host->phase != MSG_IN)
  			return host->phase;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2030
2031
2032
  	}
  	/* statement won't reach here */
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2033
  static int initio_msgout_reject(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2034
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2035
  	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
2036

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

72d39fea9   Alan Cox   [SCSI] initio: Co...
2040
2041
2042
2043
  	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
2044
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2045
  	return host->phase;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2046
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2047
  static int initio_msgout_ide(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2048
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2049
2050
2051
  	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
2052
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2053
  static int initio_msgin_extend(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2054
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2055
  	u8 len, idx;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2056

72d39fea9   Alan Cox   [SCSI] initio: Co...
2057
2058
  	if (initio_msgin_accept(host) != MSG_IN)
  		return host->phase;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2059
2060
  
  	/* Get extended msg length      */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2061
2062
2063
2064
  	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
2065

72d39fea9   Alan Cox   [SCSI] initio: Co...
2066
2067
  	len = inb(host->addr + TUL_SFifo);
  	host->msg[0] = len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2068
  	for (idx = 1; len != 0; len--) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
  		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
2083
  		} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2084
2085
2086
2087
  			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
2088
2089
  			}
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2090
2091
2092
2093
2094
  		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
2095
  		/* sync msg out */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2096
  		outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2097

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

72d39fea9   Alan Cox   [SCSI] initio: Co...
2100
2101
2102
2103
2104
2105
2106
  		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
2107
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2108
2109
  	if (host->msg[0] != 2 || host->msg[1] != 3)
  		return initio_msgout_reject(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2110
  	/* if it's WIDE DATA XFER REQ   */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2111
2112
  	if (host->active_tc->flags & TCF_NO_WDTR) {
  		host->msg[2] = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2113
  	} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2114
2115
2116
2117
  		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
2118
  		} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2119
2120
2121
2122
2123
  			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
2124
2125
2126
  			}
  		}
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2127
  	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
2128

72d39fea9   Alan Cox   [SCSI] initio: Co...
2129
2130
  	if (initio_msgin_accept(host) != MSG_OUT)
  		return host->phase;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2131
  	/* WDTR msg out                 */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2132
2133
2134
2135
2136
2137
  	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
2138
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2139
  static int initio_msgin_sync(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2140
2141
  {
  	char default_period;
72d39fea9   Alan Cox   [SCSI] initio: Co...
2142
2143
2144
2145
2146
  	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
2147
2148
  			return 1;
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2149
2150
  		if (host->msg[2] >= 59)	/* Change to async              */
  			host->msg[3] = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2151
2152
2153
  		return 1;
  	}
  	/* offset requests asynchronous transfers ? */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2154
  	if (host->msg[3] == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2155
2156
  		return 0;
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2157
2158
  	if (host->msg[2] < default_period) {
  		host->msg[2] = default_period;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2159
2160
  		return 1;
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2161
2162
  	if (host->msg[2] >= 59) {
  		host->msg[3] = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2163
2164
2165
2166
  		return 1;
  	}
  	return 0;
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2167
  static int wdtr_done(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2168
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2169
2170
  	host->active_tc->flags &= ~TCF_SYNC_DONE;
  	host->active_tc->flags |= TCF_WDTR_DONE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2171

72d39fea9   Alan Cox   [SCSI] initio: Co...
2172
2173
2174
2175
2176
2177
  	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
2178
2179
2180
  
  	return 1;
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2181
  static int initio_sync_done(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2182
2183
  {
  	int i;
72d39fea9   Alan Cox   [SCSI] initio: Co...
2184
  	host->active_tc->flags |= TCF_SYNC_DONE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2185

72d39fea9   Alan Cox   [SCSI] initio: Co...
2186
2187
  	if (host->msg[3]) {
  		host->active_tc->js_period |= host->msg[3];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2188
  		for (i = 0; i < 8; i++) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2189
  			if (initio_rate_tbl[i] >= host->msg[2])	/* pick the big one */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2190
2191
  				break;
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2192
2193
  		host->active_tc->js_period |= (i << 4);
  		host->active_tc->sconfig0 |= TSC_ALT_PERIOD;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2194
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2195
2196
  	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
2197

72d39fea9   Alan Cox   [SCSI] initio: Co...
2198
  	return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2199
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2200
  static int initio_post_scsi_rst(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2201
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2202
2203
  	struct scsi_ctrl_blk *scb;
  	struct target_control *active_tc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2204
  	int i;
72d39fea9   Alan Cox   [SCSI] initio: Co...
2205
2206
2207
  	host->active = NULL;
  	host->active_tc = NULL;
  	host->flags = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2208

72d39fea9   Alan Cox   [SCSI] initio: Co...
2209
2210
2211
  	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
2212
2213
  	}
  	/* clear sync done flag         */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2214
2215
2216
  	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
2217
  		/* Initialize the sync. xfer register values to an asyn xfer */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2218
2219
2220
2221
  		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
2222
  	}			/* for */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2223
  	return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2224
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2225
  static void initio_select_atn_stop(struct initio_host * host, struct scsi_ctrl_blk * scb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2226
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2227
2228
2229
2230
2231
  	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
2232
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2233
  static void initio_select_atn(struct initio_host * host, struct scsi_ctrl_blk * scb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2234
2235
  {
  	int i;
72d39fea9   Alan Cox   [SCSI] initio: Co...
2236
2237
  	scb->status |= SCB_SELECT;
  	scb->next_state = 0x2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2238

72d39fea9   Alan Cox   [SCSI] initio: Co...
2239
2240
2241
2242
2243
2244
  	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
2245
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2246
  static void initio_select_atn3(struct initio_host * host, struct scsi_ctrl_blk * scb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2247
2248
  {
  	int i;
72d39fea9   Alan Cox   [SCSI] initio: Co...
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
  	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
2260
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2261
2262
2263
2264
2265
2266
2267
2268
  /**
   *	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
2269
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2270
2271
2272
2273
  	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
2274

72d39fea9   Alan Cox   [SCSI] initio: Co...
2275
2276
2277
2278
2279
  	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
2280

72d39fea9   Alan Cox   [SCSI] initio: Co...
2281
2282
  	tar = scb->target;	/* target                       */
  	active_tc->flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE | TCF_BUSY);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2283
2284
2285
  	/* clr sync. nego & WDTR flags  07/22/98 */
  
  	/* abort all SCB with same target */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2286
2287
2288
  	prev = tmp = host->first_busy;	/* Check Busy queue */
  	while (tmp != NULL) {
  		if (tmp->target == tar) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2289
  			/* unlink it */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2290
2291
2292
  			if (tmp == host->first_busy) {
  				if ((host->first_busy = tmp->next) == NULL)
  					host->last_busy = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2293
  			} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2294
2295
2296
  				prev->next = tmp->next;
  				if (tmp == host->last_busy)
  					host->last_busy = prev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2297
  			}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2298
2299
  			tmp->hastat = HOST_ABORTED;
  			initio_append_done_scb(host, tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2300
2301
2302
  		}
  		/* Previous haven't change      */
  		else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2303
  			prev = tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2304
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2305
  		tmp = tmp->next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2306
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2307
2308
2309
  	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
2310
2311
  
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2312
  static int initio_msgin_accept(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2313
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2314
2315
  	outb(TSC_MSG_ACCEPT, host->addr + TUL_SCmd);
  	return wait_tulip(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2316
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2317
  static int wait_tulip(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2318
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2319
2320
2321
  	while (!((host->jsstatus0 = inb(host->addr + TUL_SStatus0))
  		 & TSS_INT_PENDING))
  			cpu_relax();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2322

72d39fea9   Alan Cox   [SCSI] initio: Co...
2323
2324
2325
  	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
2326

72d39fea9   Alan Cox   [SCSI] initio: Co...
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
  	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
2346
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2347
2348
2349
2350
2351
2352
2353
2354
  		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
2355
  		}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2356
  		return int_initio_busfree(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2357
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2358
2359
2360
2361
  	/* 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
2362
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2363

72d39fea9   Alan Cox   [SCSI] initio: Co...
2364
2365
2366
2367
  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
2368

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

72d39fea9   Alan Cox   [SCSI] initio: Co...
2371
2372
2373
2374
2375
2376
2377
2378
  	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
2379
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2380
  	return initio_bad_seq(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2381
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2382
  static int initio_wait_done_disc(struct initio_host * host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2383
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2384
2385
2386
  	while (!((host->jsstatus0 = inb(host->addr + TUL_SStatus0))
  		 & TSS_INT_PENDING))
  		 cpu_relax();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2387

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

72d39fea9   Alan Cox   [SCSI] initio: Co...
2390
2391
2392
2393
2394
2395
2396
  	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
2397

72d39fea9   Alan Cox   [SCSI] initio: Co...
2398
2399
2400
  		initio_append_done_scb(host, host->active);
  		host->active = NULL;
  		return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2401
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2402
  	return initio_bad_seq(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2403
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2404
2405
2406
2407
2408
2409
2410
2411
  /**
   *	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...
2412
  static irqreturn_t i91u_intr(int irqno, void *dev_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2413
2414
2415
  {
  	struct Scsi_Host *dev = dev_id;
  	unsigned long flags;
72d39fea9   Alan Cox   [SCSI] initio: Co...
2416
  	int r;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2417
2418
  	
  	spin_lock_irqsave(dev->host_lock, flags);
72d39fea9   Alan Cox   [SCSI] initio: Co...
2419
  	r = initio_isr((struct initio_host *)dev->hostdata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2420
  	spin_unlock_irqrestore(dev->host_lock, flags);
72d39fea9   Alan Cox   [SCSI] initio: Co...
2421
2422
2423
2424
  	if (r)
  		return IRQ_HANDLED;
  	else
  		return IRQ_NONE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2425
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2426

72d39fea9   Alan Cox   [SCSI] initio: Co...
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
  /**
   *	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
2437

72d39fea9   Alan Cox   [SCSI] initio: Co...
2438
  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
2439
  {				/* Create corresponding SCB     */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2440
2441
  	struct scatterlist *sglist;
  	struct sg_entry *sg;		/* Pointer to SG list           */
a258c85d0   FUJITA Tomonori   [SCSI] initio: co...
2442
  	int i, nseg;
72d39fea9   Alan Cox   [SCSI] initio: Co...
2443
  	long total_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2444
  	dma_addr_t dma_addr;
72d39fea9   Alan Cox   [SCSI] initio: Co...
2445
2446
2447
2448
2449
2450
2451
2452
  	/* 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
2453

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

72d39fea9   Alan Cox   [SCSI] initio: Co...
2456
2457
2458
  	/* 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...
2459
2460
  	cblk->senseptr = (u32)dma_addr;
  	cblk->senselen = SENSE_SIZE;
72d39fea9   Alan Cox   [SCSI] initio: Co...
2461
2462
2463
2464
2465
2466
2467
  	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...
2468
  	memcpy(cblk->cdb, cmnd->cmnd, cmnd->cmd_len);
72d39fea9   Alan Cox   [SCSI] initio: Co...
2469
2470
2471
2472
  
  	/* 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
2473
  	} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2474
  		cblk->tagmsg = 0;	/* No tag support               */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2475
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2476

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2477
  	/* todo handle map_sg error */
a258c85d0   FUJITA Tomonori   [SCSI] initio: co...
2478
2479
2480
  	nseg = scsi_dma_map(cmnd);
  	BUG_ON(nseg < 0);
  	if (nseg) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2481
2482
  		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
2483
  					  DMA_BIDIRECTIONAL);
423eef6fb   Grant Grundler   [SCSI] initio: fi...
2484
  		cblk->bufptr = (u32)dma_addr;
72d39fea9   Alan Cox   [SCSI] initio: Co...
2485
  		cmnd->SCp.dma_handle = dma_addr;
e2d435ea4   Stuart Swales   [SCSI] initio: fi...
2486
  		cblk->sglen = nseg;
72d39fea9   Alan Cox   [SCSI] initio: Co...
2487
2488
  
  		cblk->flags |= SCF_SG;	/* Turn on SG list flag       */
a258c85d0   FUJITA Tomonori   [SCSI] initio: co...
2489
2490
2491
  		total_len = 0;
  		sg = &cblk->sglist[0];
  		scsi_for_each_sg(cmnd, sglist, cblk->sglen, i) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2492
  			sg->data = cpu_to_le32((u32)sg_dma_address(sglist));
423eef6fb   Grant Grundler   [SCSI] initio: fi...
2493
2494
  			sg->len = cpu_to_le32((u32)sg_dma_len(sglist));
  			total_len += sg_dma_len(sglist);
a169e6374   Boaz Harrosh   [SCSI] initio: bu...
2495
  			++sg;
72d39fea9   Alan Cox   [SCSI] initio: Co...
2496
  		}
a258c85d0   FUJITA Tomonori   [SCSI] initio: co...
2497
2498
  		cblk->buflen = (scsi_bufflen(cmnd) > total_len) ?
  			total_len : scsi_bufflen(cmnd);
72d39fea9   Alan Cox   [SCSI] initio: Co...
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
  	} 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
2514

f281233d3   Jeff Garzik   SCSI host lock pu...
2515
  static int i91u_queuecommand_lck(struct scsi_cmnd *cmd,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2516
2517
  		void (*done)(struct scsi_cmnd *))
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2518
2519
  	struct initio_host *host = (struct initio_host *) cmd->device->host->hostdata;
  	struct scsi_ctrl_blk *cmnd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2520
2521
  
  	cmd->scsi_done = done;
72d39fea9   Alan Cox   [SCSI] initio: Co...
2522
2523
  	cmnd = initio_alloc_scb(host);
  	if (!cmnd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2524
  		return SCSI_MLQUEUE_HOST_BUSY;
72d39fea9   Alan Cox   [SCSI] initio: Co...
2525
2526
  	initio_build_scb(host, cmnd, cmd);
  	initio_exec_scb(host, cmnd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2527
2528
  	return 0;
  }
f281233d3   Jeff Garzik   SCSI host lock pu...
2529
  static DEF_SCSI_QCMD(i91u_queuecommand)
72d39fea9   Alan Cox   [SCSI] initio: Co...
2530
2531
2532
2533
2534
  /**
   *	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
2535
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2536

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

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

72d39fea9   Alan Cox   [SCSI] initio: Co...
2543
2544
2545
  	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...
2546

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2547
2548
  	return SUCCESS;
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
  /**
   *	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
2560
   */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2561

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2562
2563
2564
  static int i91u_biosparam(struct scsi_device *sdev, struct block_device *dev,
  		sector_t capacity, int *info_array)
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2565
2566
  	struct initio_host *host;		/* Point to Host adapter control block */
  	struct target_control *tc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2567

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

72d39fea9   Alan Cox   [SCSI] initio: Co...
2571
2572
2573
2574
  	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
2575
  	} else {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2576
  		if (tc->drv_flags & TCF_DRV_255_63) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
  			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...
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
  /**
   *	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
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
  {
  	/* 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...
2619
  	if (scsi_sg_count(cmnd)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2620
  		dma_unmap_single(&pci_dev->dev, cmnd->SCp.dma_handle,
72d39fea9   Alan Cox   [SCSI] initio: Co...
2621
  				 sizeof(struct sg_entry) * TOTAL_SG_ENTRY,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2622
  				 DMA_BIDIRECTIONAL);
a258c85d0   FUJITA Tomonori   [SCSI] initio: co...
2623
  		scsi_dma_unmap(cmnd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2624
2625
  	}
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2626
2627
2628
2629
2630
2631
2632
2633
  /**
   *	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
2634

72d39fea9   Alan Cox   [SCSI] initio: Co...
2635
2636
2637
2638
2639
  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
2640

72d39fea9   Alan Cox   [SCSI] initio: Co...
2641
2642
2643
2644
2645
2646
2647
  	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
2648
2649
  		return;
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2650
2651
2652
2653
2654
  
  	/*
  	 *	Remap the firmware error status into a mid layer one
  	 */
  	switch (cblk->hastat) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2655
2656
2657
  	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...
2658
  		cblk->hastat = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2659
2660
2661
2662
  		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...
2663
  		cblk->hastat = DID_TIME_OUT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2664
2665
2666
2667
2668
2669
  		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...
2670
  		cblk->hastat = DID_RESET;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2671
2672
2673
  		break;
  
  	case 0x1a:		/* SCB Aborted. 07/21/98 */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2674
  		cblk->hastat = DID_ABORT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2675
2676
2677
2678
2679
2680
2681
2682
2683
  		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...
2684
2685
2686
  		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
2687
2688
  		break;
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2689
  	cmnd->result = cblk->tastat | (cblk->hastat << 16);
72d39fea9   Alan Cox   [SCSI] initio: Co...
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
  	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...
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
  	.use_clustering		= ENABLE_CLUSTERING,
  };
  
  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));
284901a90   Yang Hongyang   dma-mapping: repl...
2726
  	if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
  		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...
2741
  	host->addr = pci_resource_start(pdev, 0);
e2d435ea4   Stuart Swales   [SCSI] initio: fi...
2742
  	host->bios_addr = bios_seg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2743

72d39fea9   Alan Cox   [SCSI] initio: Co...
2744
2745
2746
2747
2748
  	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
2749
  	}
72d39fea9   Alan Cox   [SCSI] initio: Co...
2750
2751
2752
2753
  	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
2754

72d39fea9   Alan Cox   [SCSI] initio: Co...
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
  	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
2767

e9e42faf4   Alan Cox   [SCSI] initio: Fi...
2768
  	host->pci_dev = pdev;
e2d435ea4   Stuart Swales   [SCSI] initio: fi...
2769
2770
  	host->semaph = 1;
  	spin_lock_init(&host->semaph_lock);
72d39fea9   Alan Cox   [SCSI] initio: Co...
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
  	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...
2785
  	spin_lock_init(&host->avail_lock);
72d39fea9   Alan Cox   [SCSI] initio: Co...
2786

e2d435ea4   Stuart Swales   [SCSI] initio: fi...
2787
  	initio_init(host, phys_to_virt(((u32)bios_seg << 4)));
72d39fea9   Alan Cox   [SCSI] initio: Co...
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
  
  	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...
2801
  	error = request_irq(pdev->irq, i91u_intr, IRQF_SHARED, "i91u", shost);
72d39fea9   Alan Cox   [SCSI] initio: Co...
2802
2803
2804
2805
2806
2807
2808
  	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...
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
  
  	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
2834
   */
72d39fea9   Alan Cox   [SCSI] initio: Co...
2835
2836
  
  static void initio_remove_one(struct pci_dev *pdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2837
  {
72d39fea9   Alan Cox   [SCSI] initio: Co...
2838
2839
2840
2841
2842
2843
2844
  	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
2845
  }
72d39fea9   Alan Cox   [SCSI] initio: Co...
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
  
  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...
2863
  	.remove		= initio_remove_one,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2864
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2865

72d39fea9   Alan Cox   [SCSI] initio: Co...
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
  static int __init initio_init_driver(void)
  {
  	return pci_register_driver(&initio_pci_driver);
  }
  
  static void __exit initio_exit_driver(void)
  {
  	pci_unregister_driver(&initio_pci_driver);
  }
  
  MODULE_DESCRIPTION("Initio INI-9X00U/UW SCSI device driver");
  MODULE_AUTHOR("Initio Corporation");
  MODULE_LICENSE("GPL");
  
  module_init(initio_init_driver);
  module_exit(initio_exit_driver);