1 |
1275 |
phoenix |
/* fd_mcs.c -- Future Domain MCS 600/700 (or IBM OEM) driver
|
2 |
|
|
*
|
3 |
|
|
* FutureDomain MCS-600/700 v0.2 03/11/1998 by ZP Gu (zpg@castle.net)
|
4 |
|
|
*
|
5 |
|
|
* This driver is cloned from fdomain.* to specifically support
|
6 |
|
|
* the Future Domain MCS 600/700 MCA SCSI adapters. Some PS/2s
|
7 |
|
|
* also equipped with IBM Fast SCSI Adapter/A which is an OEM
|
8 |
|
|
* of MCS 700.
|
9 |
|
|
*
|
10 |
|
|
* This driver also supports Reply SB16/SCSI card (the SCSI part).
|
11 |
|
|
*
|
12 |
|
|
* What makes this driver different is that this driver is MCA only
|
13 |
|
|
* and it supports multiple adapters in the same system, IRQ
|
14 |
|
|
* sharing, some driver statistics, and maps highest SCSI id to sda.
|
15 |
|
|
* All cards are auto-detected.
|
16 |
|
|
*
|
17 |
|
|
* Assumptions: TMC-1800/18C50/18C30, BIOS >= 3.4
|
18 |
|
|
*
|
19 |
|
|
* LILO command-line options:
|
20 |
|
|
* fd_mcs=<FIFO_COUNT>[,<FIFO_SIZE>]
|
21 |
|
|
*
|
22 |
|
|
* ********************************************************
|
23 |
|
|
* Please see Copyrights/Comments in fdomain.* for credits.
|
24 |
|
|
* Following is from fdomain.c for acknowledgement:
|
25 |
|
|
*
|
26 |
|
|
* Created: Sun May 3 18:53:19 1992 by faith@cs.unc.edu
|
27 |
|
|
* Revised: Wed Oct 2 11:10:55 1996 by r.faith@ieee.org
|
28 |
|
|
* Author: Rickard E. Faith, faith@cs.unc.edu
|
29 |
|
|
* Copyright 1992, 1993, 1994, 1995, 1996 Rickard E. Faith
|
30 |
|
|
*
|
31 |
|
|
* $Id: fd_mcs.c,v 1.1.1.1 2004-04-15 02:10:51 phoenix Exp $
|
32 |
|
|
|
33 |
|
|
* This program is free software; you can redistribute it and/or modify it
|
34 |
|
|
* under the terms of the GNU General Public License as published by the
|
35 |
|
|
* Free Software Foundation; either version 2, or (at your option) any
|
36 |
|
|
* later version.
|
37 |
|
|
|
38 |
|
|
* This program is distributed in the hope that it will be useful, but
|
39 |
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
40 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
41 |
|
|
* General Public License for more details.
|
42 |
|
|
|
43 |
|
|
* You should have received a copy of the GNU General Public License along
|
44 |
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
45 |
|
|
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
46 |
|
|
|
47 |
|
|
**************************************************************************
|
48 |
|
|
|
49 |
|
|
NOTES ON USER DEFINABLE OPTIONS:
|
50 |
|
|
|
51 |
|
|
DEBUG: This turns on the printing of various debug information.
|
52 |
|
|
|
53 |
|
|
ENABLE_PARITY: This turns on SCSI parity checking. With the current
|
54 |
|
|
driver, all attached devices must support SCSI parity. If none of your
|
55 |
|
|
devices support parity, then you can probably get the driver to work by
|
56 |
|
|
turning this option off. I have no way of testing this, however, and it
|
57 |
|
|
would appear that no one ever uses this option.
|
58 |
|
|
|
59 |
|
|
FIFO_COUNT: The host adapter has an 8K cache (host adapters based on the
|
60 |
|
|
18C30 chip have a 2k cache). When this many 512 byte blocks are filled by
|
61 |
|
|
the SCSI device, an interrupt will be raised. Therefore, this could be as
|
62 |
|
|
low as 0, or as high as 16. Note, however, that values which are too high
|
63 |
|
|
or too low seem to prevent any interrupts from occurring, and thereby lock
|
64 |
|
|
up the machine. I have found that 2 is a good number, but throughput may
|
65 |
|
|
be increased by changing this value to values which are close to 2.
|
66 |
|
|
Please let me know if you try any different values.
|
67 |
|
|
[*****Now a runtime option*****]
|
68 |
|
|
|
69 |
|
|
RESELECTION: This is no longer an option, since I gave up trying to
|
70 |
|
|
implement it in version 4.x of this driver. It did not improve
|
71 |
|
|
performance at all and made the driver unstable (because I never found one
|
72 |
|
|
of the two race conditions which were introduced by the multiple
|
73 |
|
|
outstanding command code). The instability seems a very high price to pay
|
74 |
|
|
just so that you don't have to wait for the tape to rewind. If you want
|
75 |
|
|
this feature implemented, send me patches. I'll be happy to send a copy
|
76 |
|
|
of my (broken) driver to anyone who would like to see a copy.
|
77 |
|
|
|
78 |
|
|
**************************************************************************/
|
79 |
|
|
|
80 |
|
|
#include <linux/module.h>
|
81 |
|
|
|
82 |
|
|
#include <linux/sched.h>
|
83 |
|
|
#include <linux/blk.h>
|
84 |
|
|
#include <linux/errno.h>
|
85 |
|
|
#include <linux/string.h>
|
86 |
|
|
#include <linux/ioport.h>
|
87 |
|
|
#include <linux/proc_fs.h>
|
88 |
|
|
#include <linux/delay.h>
|
89 |
|
|
#include <linux/mca.h>
|
90 |
|
|
#include <linux/spinlock.h>
|
91 |
|
|
#include <asm/io.h>
|
92 |
|
|
#include <asm/system.h>
|
93 |
|
|
|
94 |
|
|
#include "scsi.h"
|
95 |
|
|
#include "hosts.h"
|
96 |
|
|
#include "fd_mcs.h"
|
97 |
|
|
|
98 |
|
|
#define DRIVER_VERSION "v0.2 by ZP Gu<zpg@castle.net>"
|
99 |
|
|
|
100 |
|
|
/* START OF USER DEFINABLE OPTIONS */
|
101 |
|
|
|
102 |
|
|
#define DEBUG 0 /* Enable debugging output */
|
103 |
|
|
#define ENABLE_PARITY 1 /* Enable SCSI Parity */
|
104 |
|
|
#define DO_DETECT 0 /* Do device detection here (see scsi.c) */
|
105 |
|
|
|
106 |
|
|
/* END OF USER DEFINABLE OPTIONS */
|
107 |
|
|
|
108 |
|
|
#if DEBUG
|
109 |
|
|
#define EVERY_ACCESS 0 /* Write a line on every scsi access */
|
110 |
|
|
#define ERRORS_ONLY 1 /* Only write a line if there is an error */
|
111 |
|
|
#define DEBUG_DETECT 1 /* Debug fd_mcs_detect() */
|
112 |
|
|
#define DEBUG_MESSAGES 1 /* Debug MESSAGE IN phase */
|
113 |
|
|
#define DEBUG_ABORT 1 /* Debug abort() routine */
|
114 |
|
|
#define DEBUG_RESET 1 /* Debug reset() routine */
|
115 |
|
|
#define DEBUG_RACE 1 /* Debug interrupt-driven race condition */
|
116 |
|
|
#else
|
117 |
|
|
#define EVERY_ACCESS 0 /* LEAVE THESE ALONE--CHANGE THE ONES ABOVE */
|
118 |
|
|
#define ERRORS_ONLY 0
|
119 |
|
|
#define DEBUG_DETECT 0
|
120 |
|
|
#define DEBUG_MESSAGES 0
|
121 |
|
|
#define DEBUG_ABORT 0
|
122 |
|
|
#define DEBUG_RESET 0
|
123 |
|
|
#define DEBUG_RACE 0
|
124 |
|
|
#endif
|
125 |
|
|
|
126 |
|
|
/* Errors are reported on the line, so we don't need to report them again */
|
127 |
|
|
#if EVERY_ACCESS
|
128 |
|
|
#undef ERRORS_ONLY
|
129 |
|
|
#define ERRORS_ONLY 0
|
130 |
|
|
#endif
|
131 |
|
|
|
132 |
|
|
#if ENABLE_PARITY
|
133 |
|
|
#define PARITY_MASK 0x08
|
134 |
|
|
#else
|
135 |
|
|
#define PARITY_MASK 0x00
|
136 |
|
|
#endif
|
137 |
|
|
|
138 |
|
|
enum chip_type {
|
139 |
|
|
unknown = 0x00,
|
140 |
|
|
tmc1800 = 0x01,
|
141 |
|
|
tmc18c50 = 0x02,
|
142 |
|
|
tmc18c30 = 0x03,
|
143 |
|
|
};
|
144 |
|
|
|
145 |
|
|
enum {
|
146 |
|
|
in_arbitration = 0x02,
|
147 |
|
|
in_selection = 0x04,
|
148 |
|
|
in_other = 0x08,
|
149 |
|
|
disconnect = 0x10,
|
150 |
|
|
aborted = 0x20,
|
151 |
|
|
sent_ident = 0x40,
|
152 |
|
|
};
|
153 |
|
|
|
154 |
|
|
enum in_port_type {
|
155 |
|
|
Read_SCSI_Data = 0,
|
156 |
|
|
SCSI_Status = 1,
|
157 |
|
|
TMC_Status = 2,
|
158 |
|
|
FIFO_Status = 3, /* tmc18c50/tmc18c30 only */
|
159 |
|
|
Interrupt_Cond = 4, /* tmc18c50/tmc18c30 only */
|
160 |
|
|
LSB_ID_Code = 5,
|
161 |
|
|
MSB_ID_Code = 6,
|
162 |
|
|
Read_Loopback = 7,
|
163 |
|
|
SCSI_Data_NoACK = 8,
|
164 |
|
|
Interrupt_Status = 9,
|
165 |
|
|
Configuration1 = 10,
|
166 |
|
|
Configuration2 = 11, /* tmc18c50/tmc18c30 only */
|
167 |
|
|
Read_FIFO = 12,
|
168 |
|
|
FIFO_Data_Count = 14
|
169 |
|
|
};
|
170 |
|
|
|
171 |
|
|
enum out_port_type {
|
172 |
|
|
Write_SCSI_Data = 0,
|
173 |
|
|
SCSI_Cntl = 1,
|
174 |
|
|
Interrupt_Cntl = 2,
|
175 |
|
|
SCSI_Mode_Cntl = 3,
|
176 |
|
|
TMC_Cntl = 4,
|
177 |
|
|
Memory_Cntl = 5, /* tmc18c50/tmc18c30 only */
|
178 |
|
|
Write_Loopback = 7,
|
179 |
|
|
IO_Control = 11, /* tmc18c30 only */
|
180 |
|
|
Write_FIFO = 12
|
181 |
|
|
};
|
182 |
|
|
|
183 |
|
|
struct fd_hostdata {
|
184 |
|
|
unsigned long _bios_base;
|
185 |
|
|
int _bios_major;
|
186 |
|
|
int _bios_minor;
|
187 |
|
|
volatile int _in_command;
|
188 |
|
|
Scsi_Cmnd *_current_SC;
|
189 |
|
|
enum chip_type _chip;
|
190 |
|
|
int _adapter_mask;
|
191 |
|
|
int _fifo_count; /* Number of 512 byte blocks before INTR */
|
192 |
|
|
|
193 |
|
|
char _adapter_name[64];
|
194 |
|
|
#if DEBUG_RACE
|
195 |
|
|
volatile int _in_interrupt_flag;
|
196 |
|
|
#endif
|
197 |
|
|
|
198 |
|
|
int _SCSI_Mode_Cntl_port;
|
199 |
|
|
int _FIFO_Data_Count_port;
|
200 |
|
|
int _Interrupt_Cntl_port;
|
201 |
|
|
int _Interrupt_Status_port;
|
202 |
|
|
int _Interrupt_Cond_port;
|
203 |
|
|
int _Read_FIFO_port;
|
204 |
|
|
int _Read_SCSI_Data_port;
|
205 |
|
|
int _SCSI_Cntl_port;
|
206 |
|
|
int _SCSI_Data_NoACK_port;
|
207 |
|
|
int _SCSI_Status_port;
|
208 |
|
|
int _TMC_Cntl_port;
|
209 |
|
|
int _TMC_Status_port;
|
210 |
|
|
int _Write_FIFO_port;
|
211 |
|
|
int _Write_SCSI_Data_port;
|
212 |
|
|
|
213 |
|
|
int _FIFO_Size; /* = 0x2000; 8k FIFO for
|
214 |
|
|
pre-tmc18c30 chips */
|
215 |
|
|
/* simple stats */
|
216 |
|
|
int _Bytes_Read;
|
217 |
|
|
int _Bytes_Written;
|
218 |
|
|
int _INTR_Processed;
|
219 |
|
|
};
|
220 |
|
|
|
221 |
|
|
#define FD_MAX_HOSTS 3 /* enough? */
|
222 |
|
|
|
223 |
|
|
#define HOSTDATA(shpnt) ((struct fd_hostdata *) shpnt->hostdata)
|
224 |
|
|
#define bios_base (HOSTDATA(shpnt)->_bios_base)
|
225 |
|
|
#define bios_major (HOSTDATA(shpnt)->_bios_major)
|
226 |
|
|
#define bios_minor (HOSTDATA(shpnt)->_bios_minor)
|
227 |
|
|
#define in_command (HOSTDATA(shpnt)->_in_command)
|
228 |
|
|
#define current_SC (HOSTDATA(shpnt)->_current_SC)
|
229 |
|
|
#define chip (HOSTDATA(shpnt)->_chip)
|
230 |
|
|
#define adapter_mask (HOSTDATA(shpnt)->_adapter_mask)
|
231 |
|
|
#define FIFO_COUNT (HOSTDATA(shpnt)->_fifo_count)
|
232 |
|
|
#define adapter_name (HOSTDATA(shpnt)->_adapter_name)
|
233 |
|
|
#if DEBUG_RACE
|
234 |
|
|
#define in_interrupt_flag (HOSTDATA(shpnt)->_in_interrupt_flag)
|
235 |
|
|
#endif
|
236 |
|
|
#define SCSI_Mode_Cntl_port (HOSTDATA(shpnt)->_SCSI_Mode_Cntl_port)
|
237 |
|
|
#define FIFO_Data_Count_port (HOSTDATA(shpnt)->_FIFO_Data_Count_port)
|
238 |
|
|
#define Interrupt_Cntl_port (HOSTDATA(shpnt)->_Interrupt_Cntl_port)
|
239 |
|
|
#define Interrupt_Status_port (HOSTDATA(shpnt)->_Interrupt_Status_port)
|
240 |
|
|
#define Interrupt_Cond_port (HOSTDATA(shpnt)->_Interrupt_Cond_port)
|
241 |
|
|
#define Read_FIFO_port (HOSTDATA(shpnt)->_Read_FIFO_port)
|
242 |
|
|
#define Read_SCSI_Data_port (HOSTDATA(shpnt)->_Read_SCSI_Data_port)
|
243 |
|
|
#define SCSI_Cntl_port (HOSTDATA(shpnt)->_SCSI_Cntl_port)
|
244 |
|
|
#define SCSI_Data_NoACK_port (HOSTDATA(shpnt)->_SCSI_Data_NoACK_port)
|
245 |
|
|
#define SCSI_Status_port (HOSTDATA(shpnt)->_SCSI_Status_port)
|
246 |
|
|
#define TMC_Cntl_port (HOSTDATA(shpnt)->_TMC_Cntl_port)
|
247 |
|
|
#define TMC_Status_port (HOSTDATA(shpnt)->_TMC_Status_port)
|
248 |
|
|
#define Write_FIFO_port (HOSTDATA(shpnt)->_Write_FIFO_port)
|
249 |
|
|
#define Write_SCSI_Data_port (HOSTDATA(shpnt)->_Write_SCSI_Data_port)
|
250 |
|
|
#define FIFO_Size (HOSTDATA(shpnt)->_FIFO_Size)
|
251 |
|
|
#define Bytes_Read (HOSTDATA(shpnt)->_Bytes_Read)
|
252 |
|
|
#define Bytes_Written (HOSTDATA(shpnt)->_Bytes_Written)
|
253 |
|
|
#define INTR_Processed (HOSTDATA(shpnt)->_INTR_Processed)
|
254 |
|
|
|
255 |
|
|
struct fd_mcs_adapters_struct {
|
256 |
|
|
char* name;
|
257 |
|
|
int id;
|
258 |
|
|
enum chip_type fd_chip;
|
259 |
|
|
int fifo_size;
|
260 |
|
|
int fifo_count;
|
261 |
|
|
};
|
262 |
|
|
|
263 |
|
|
#define REPLY_ID 0x5137
|
264 |
|
|
|
265 |
|
|
static struct fd_mcs_adapters_struct fd_mcs_adapters[] = {
|
266 |
|
|
{ "Future Domain SCSI Adapter MCS-700(18C50)",
|
267 |
|
|
0x60e9,
|
268 |
|
|
tmc18c50,
|
269 |
|
|
0x2000,
|
270 |
|
|
4 },
|
271 |
|
|
{ "Future Domain SCSI Adapter MCS-600/700(TMC-1800)",
|
272 |
|
|
0x6127,
|
273 |
|
|
tmc1800,
|
274 |
|
|
0x2000,
|
275 |
|
|
4 },
|
276 |
|
|
{ "Reply Sound Blaster/SCSI Adapter",
|
277 |
|
|
REPLY_ID,
|
278 |
|
|
tmc18c30,
|
279 |
|
|
0x800,
|
280 |
|
|
2 },
|
281 |
|
|
};
|
282 |
|
|
|
283 |
|
|
#define FD_BRDS sizeof(fd_mcs_adapters)/sizeof(struct fd_mcs_adapters_struct)
|
284 |
|
|
|
285 |
|
|
static void fd_mcs_intr( int irq, void *dev_id, struct pt_regs * regs );
|
286 |
|
|
|
287 |
|
|
static unsigned long addresses[] = {0xc8000, 0xca000, 0xce000, 0xde000};
|
288 |
|
|
static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 };
|
289 |
|
|
static unsigned short ints[] = { 3, 5, 10, 11, 12, 14, 15, 0 };
|
290 |
|
|
|
291 |
|
|
/* host information */
|
292 |
|
|
static int found = 0;
|
293 |
|
|
static struct Scsi_Host *hosts[FD_MAX_HOSTS+1] = { NULL };
|
294 |
|
|
|
295 |
|
|
static int user_fifo_count = 0;
|
296 |
|
|
static int user_fifo_size = 0;
|
297 |
|
|
|
298 |
|
|
void fd_mcs_setup( char *str, int *ints )
|
299 |
|
|
{
|
300 |
|
|
static int done_setup = 0;
|
301 |
|
|
|
302 |
|
|
if (done_setup++ || ints[0] < 1 || ints[0] > 2 ||
|
303 |
|
|
ints[1] < 1 || ints[1] > 16) {
|
304 |
|
|
printk( "fd_mcs: usage: fd_mcs=FIFO_COUNT, FIFO_SIZE\n" );
|
305 |
|
|
}
|
306 |
|
|
|
307 |
|
|
user_fifo_count = ints[0] >= 1 ? ints[1] : 0;
|
308 |
|
|
user_fifo_size = ints[0] >= 2 ? ints[2] : 0;
|
309 |
|
|
}
|
310 |
|
|
|
311 |
|
|
static void print_banner( struct Scsi_Host *shpnt )
|
312 |
|
|
{
|
313 |
|
|
printk( "scsi%d <fd_mcs>: ", shpnt->host_no);
|
314 |
|
|
|
315 |
|
|
if (bios_base) {
|
316 |
|
|
printk( "BIOS at 0x%lX", bios_base);
|
317 |
|
|
} else {
|
318 |
|
|
printk( "No BIOS");
|
319 |
|
|
}
|
320 |
|
|
|
321 |
|
|
printk( ", HostID %d, %s Chip, IRQ %d, IO 0x%lX\n",
|
322 |
|
|
shpnt->this_id,
|
323 |
|
|
chip == tmc18c50 ? "TMC-18C50"
|
324 |
|
|
: (chip == tmc18c30 ? "TMC-18C30" :
|
325 |
|
|
(chip == tmc1800 ? "TMC-1800" : "Unknown")),
|
326 |
|
|
shpnt->irq,
|
327 |
|
|
shpnt->io_port );
|
328 |
|
|
}
|
329 |
|
|
|
330 |
|
|
|
331 |
|
|
static void do_pause( unsigned amount ) /* Pause for amount*10 milliseconds */
|
332 |
|
|
{
|
333 |
|
|
do {
|
334 |
|
|
udelay(10*1000);
|
335 |
|
|
} while (--amount);
|
336 |
|
|
}
|
337 |
|
|
|
338 |
|
|
inline static void fd_mcs_make_bus_idle( struct Scsi_Host *shpnt )
|
339 |
|
|
{
|
340 |
|
|
outb( 0, SCSI_Cntl_port );
|
341 |
|
|
outb( 0, SCSI_Mode_Cntl_port );
|
342 |
|
|
if (chip == tmc18c50 || chip == tmc18c30)
|
343 |
|
|
outb( 0x21 | PARITY_MASK, TMC_Cntl_port ); /* Clear forced intr. */
|
344 |
|
|
else
|
345 |
|
|
outb( 0x01 | PARITY_MASK, TMC_Cntl_port );
|
346 |
|
|
}
|
347 |
|
|
|
348 |
|
|
int fd_mcs_detect( Scsi_Host_Template *tpnt )
|
349 |
|
|
{
|
350 |
|
|
int loop;
|
351 |
|
|
struct Scsi_Host *shpnt;
|
352 |
|
|
|
353 |
|
|
/* get id, port, bios, irq */
|
354 |
|
|
int slot;
|
355 |
|
|
u_char pos2, pos3, pos4;
|
356 |
|
|
int id, port, irq;
|
357 |
|
|
unsigned long bios;
|
358 |
|
|
|
359 |
|
|
/* if not MCA machine, return */
|
360 |
|
|
if (!MCA_bus)
|
361 |
|
|
return 0;
|
362 |
|
|
|
363 |
|
|
/* changeable? */
|
364 |
|
|
id = 7;
|
365 |
|
|
|
366 |
|
|
for( loop = 0; loop < FD_BRDS; loop++ ) {
|
367 |
|
|
slot = 0;
|
368 |
|
|
while ( MCA_NOTFOUND !=
|
369 |
|
|
(slot = mca_find_adapter(fd_mcs_adapters[loop].id,
|
370 |
|
|
slot)) ) {
|
371 |
|
|
|
372 |
|
|
/* if we get this far, an adapter has been detected and is
|
373 |
|
|
enabled */
|
374 |
|
|
|
375 |
|
|
printk("scsi <fd_mcs>: %s at slot %d\n",
|
376 |
|
|
fd_mcs_adapters[loop].name, slot + 1 );
|
377 |
|
|
|
378 |
|
|
pos2 = mca_read_stored_pos( slot, 2 );
|
379 |
|
|
pos3 = mca_read_stored_pos( slot, 3 );
|
380 |
|
|
pos4 = mca_read_stored_pos( slot, 4);
|
381 |
|
|
|
382 |
|
|
/* ready for next probe */
|
383 |
|
|
slot++;
|
384 |
|
|
|
385 |
|
|
if (fd_mcs_adapters[loop].id == REPLY_ID) { /* reply card */
|
386 |
|
|
static int reply_irq[] = {10, 11, 14, 15};
|
387 |
|
|
|
388 |
|
|
bios = 0; /* no bios */
|
389 |
|
|
|
390 |
|
|
if (pos2 & 0x2)
|
391 |
|
|
port = ports[pos4 & 0x3];
|
392 |
|
|
else
|
393 |
|
|
continue;
|
394 |
|
|
|
395 |
|
|
/* can't really disable it, same as irq=10 */
|
396 |
|
|
irq = reply_irq[((pos4 >> 2) & 0x1) + 2*((pos4 >> 4) & 0x1)];
|
397 |
|
|
} else {
|
398 |
|
|
bios = addresses[pos2 >> 6];
|
399 |
|
|
port = ports[(pos2 >> 4) & 0x03];
|
400 |
|
|
irq = ints[(pos2 >> 1) & 0x07];
|
401 |
|
|
}
|
402 |
|
|
|
403 |
|
|
if (irq) {
|
404 |
|
|
/* claim the slot */
|
405 |
|
|
mca_set_adapter_name( slot-1, fd_mcs_adapters[loop].name );
|
406 |
|
|
|
407 |
|
|
/* check irq/region */
|
408 |
|
|
if (check_region(port, 0x10) ||
|
409 |
|
|
request_irq(irq, fd_mcs_intr,
|
410 |
|
|
SA_SHIRQ, "fd_mcs", hosts)) {
|
411 |
|
|
printk( "fd_mcs: check_region() || request_irq() failed, Skip it\n");
|
412 |
|
|
|
413 |
|
|
continue;
|
414 |
|
|
}
|
415 |
|
|
|
416 |
|
|
/* register */
|
417 |
|
|
if (!(shpnt = scsi_register(tpnt, sizeof(struct fd_hostdata)))) {
|
418 |
|
|
printk( "fd_mcs: scsi_register() failed\n");
|
419 |
|
|
continue;
|
420 |
|
|
}
|
421 |
|
|
|
422 |
|
|
/* request I/O region */
|
423 |
|
|
request_region( port, 0x10, "fd_mcs" );
|
424 |
|
|
|
425 |
|
|
/* save name */
|
426 |
|
|
strcpy(adapter_name, fd_mcs_adapters[loop].name);
|
427 |
|
|
|
428 |
|
|
/* chip/fifo */
|
429 |
|
|
chip = fd_mcs_adapters[loop].fd_chip;
|
430 |
|
|
/* use boot time value if available */
|
431 |
|
|
FIFO_COUNT =
|
432 |
|
|
user_fifo_count?user_fifo_count:fd_mcs_adapters[loop].fifo_count;
|
433 |
|
|
FIFO_Size =
|
434 |
|
|
user_fifo_size?user_fifo_size:fd_mcs_adapters[loop].fifo_size;
|
435 |
|
|
|
436 |
|
|
#ifdef NOT_USED
|
437 |
|
|
/* *************************************************** */
|
438 |
|
|
/* Try to toggle 32-bit mode. This only
|
439 |
|
|
works on an 18c30 chip. (User reports
|
440 |
|
|
say this works, so we should switch to
|
441 |
|
|
it in the near future.) */
|
442 |
|
|
outb( 0x80, port + IO_Control );
|
443 |
|
|
if ((inb( port + Configuration2 ) & 0x80) == 0x80) {
|
444 |
|
|
outb( 0x00, port + IO_Control );
|
445 |
|
|
if ((inb( port + Configuration2 ) & 0x80) == 0x00) {
|
446 |
|
|
chip = tmc18c30;
|
447 |
|
|
FIFO_Size = 0x800; /* 2k FIFO */
|
448 |
|
|
|
449 |
|
|
printk("FIRST: chip=%s, fifo_size=0x%x\n",
|
450 |
|
|
(chip == tmc18c30)?"tmc18c30":"tmc18c50", FIFO_Size);
|
451 |
|
|
}
|
452 |
|
|
}
|
453 |
|
|
|
454 |
|
|
/* That should have worked, but appears to
|
455 |
|
|
have problems. Let's assume it is an
|
456 |
|
|
18c30 if the RAM is disabled. */
|
457 |
|
|
|
458 |
|
|
if (inb( port + Configuration2 ) & 0x02) {
|
459 |
|
|
chip = tmc18c30;
|
460 |
|
|
FIFO_Size = 0x800; /* 2k FIFO */
|
461 |
|
|
|
462 |
|
|
printk("SECOND: chip=%s, fifo_size=0x%x\n",
|
463 |
|
|
(chip == tmc18c30)?"tmc18c30":"tmc18c50", FIFO_Size);
|
464 |
|
|
}
|
465 |
|
|
/* *************************************************** */
|
466 |
|
|
#endif
|
467 |
|
|
|
468 |
|
|
/* IBM/ANSI scsi scan ordering */
|
469 |
|
|
/* Stick this back in when the scsi.c changes are there */
|
470 |
|
|
shpnt->reverse_ordering = 1;
|
471 |
|
|
|
472 |
|
|
|
473 |
|
|
/* saving info */
|
474 |
|
|
hosts[found++] = shpnt;
|
475 |
|
|
|
476 |
|
|
shpnt->this_id = id;
|
477 |
|
|
shpnt->irq = irq;
|
478 |
|
|
shpnt->io_port = port;
|
479 |
|
|
shpnt->n_io_port = 0x10;
|
480 |
|
|
|
481 |
|
|
/* save */
|
482 |
|
|
bios_base = bios;
|
483 |
|
|
adapter_mask = (1 << id);
|
484 |
|
|
|
485 |
|
|
/* save more */
|
486 |
|
|
SCSI_Mode_Cntl_port = port + SCSI_Mode_Cntl;
|
487 |
|
|
FIFO_Data_Count_port = port + FIFO_Data_Count;
|
488 |
|
|
Interrupt_Cntl_port = port + Interrupt_Cntl;
|
489 |
|
|
Interrupt_Status_port = port + Interrupt_Status;
|
490 |
|
|
Interrupt_Cond_port = port + Interrupt_Cond;
|
491 |
|
|
Read_FIFO_port = port + Read_FIFO;
|
492 |
|
|
Read_SCSI_Data_port = port + Read_SCSI_Data;
|
493 |
|
|
SCSI_Cntl_port = port + SCSI_Cntl;
|
494 |
|
|
SCSI_Data_NoACK_port = port + SCSI_Data_NoACK;
|
495 |
|
|
SCSI_Status_port = port + SCSI_Status;
|
496 |
|
|
TMC_Cntl_port = port + TMC_Cntl;
|
497 |
|
|
TMC_Status_port = port + TMC_Status;
|
498 |
|
|
Write_FIFO_port = port + Write_FIFO;
|
499 |
|
|
Write_SCSI_Data_port = port + Write_SCSI_Data;
|
500 |
|
|
|
501 |
|
|
Bytes_Read = 0;
|
502 |
|
|
Bytes_Written = 0;
|
503 |
|
|
INTR_Processed = 0;
|
504 |
|
|
|
505 |
|
|
/* say something */
|
506 |
|
|
print_banner( shpnt );
|
507 |
|
|
|
508 |
|
|
/* reset */
|
509 |
|
|
outb( 1, SCSI_Cntl_port );
|
510 |
|
|
do_pause( 2 );
|
511 |
|
|
outb( 0, SCSI_Cntl_port );
|
512 |
|
|
do_pause( 115 );
|
513 |
|
|
outb( 0, SCSI_Mode_Cntl_port );
|
514 |
|
|
outb( PARITY_MASK, TMC_Cntl_port );
|
515 |
|
|
/* done reset */
|
516 |
|
|
|
517 |
|
|
#if DO_DETECT
|
518 |
|
|
/* scan devices attached */
|
519 |
|
|
{
|
520 |
|
|
const int buflen = 255;
|
521 |
|
|
int i, j, retcode;
|
522 |
|
|
Scsi_Cmnd SCinit;
|
523 |
|
|
unsigned char do_inquiry[] = { INQUIRY, 0, 0, 0, buflen, 0 };
|
524 |
|
|
unsigned char do_request_sense[] = { REQUEST_SENSE,
|
525 |
|
|
0, 0, 0, buflen, 0 };
|
526 |
|
|
unsigned char do_read_capacity[] = { READ_CAPACITY,
|
527 |
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
528 |
|
|
unsigned char buf[buflen];
|
529 |
|
|
|
530 |
|
|
SCinit.request_buffer = SCinit.buffer = buf;
|
531 |
|
|
SCinit.request_bufflen = SCinit.bufflen = sizeof(buf)-1;
|
532 |
|
|
SCinit.use_sg = 0;
|
533 |
|
|
SCinit.lun = 0;
|
534 |
|
|
SCinit.host = shpnt;
|
535 |
|
|
|
536 |
|
|
printk( "fd_mcs: detection routine scanning for devices:\n" );
|
537 |
|
|
for (i = 0; i < 8; i++) {
|
538 |
|
|
if (i == shpnt->this_id) /* Skip host adapter */
|
539 |
|
|
continue;
|
540 |
|
|
SCinit.target = i;
|
541 |
|
|
memcpy(SCinit.cmnd, do_request_sense,
|
542 |
|
|
sizeof(do_request_sense));
|
543 |
|
|
retcode = fd_mcs_command(&SCinit);
|
544 |
|
|
if (!retcode) {
|
545 |
|
|
memcpy(SCinit.cmnd, do_inquiry, sizeof(do_inquiry));
|
546 |
|
|
retcode = fd_mcs_command(&SCinit);
|
547 |
|
|
if (!retcode) {
|
548 |
|
|
printk( " SCSI ID %d: ", i );
|
549 |
|
|
for (j = 8; j < (buf[4] < 32 ? buf[4] : 32); j++)
|
550 |
|
|
printk( "%c", buf[j] >= 20 ? buf[j] : ' ' );
|
551 |
|
|
memcpy(SCinit.cmnd, do_read_capacity,
|
552 |
|
|
sizeof(do_read_capacity));
|
553 |
|
|
retcode = fd_mcs_command(&SCinit);
|
554 |
|
|
if (!retcode) {
|
555 |
|
|
unsigned long blocks, size, capacity;
|
556 |
|
|
|
557 |
|
|
blocks = (buf[0] << 24) | (buf[1] << 16)
|
558 |
|
|
| (buf[2] << 8) | buf[3];
|
559 |
|
|
size = (buf[4] << 24) | (buf[5] << 16) |
|
560 |
|
|
(buf[6] << 8) | buf[7];
|
561 |
|
|
capacity = +( +(blocks / 1024L) * +(size * 10L)) / 1024L;
|
562 |
|
|
|
563 |
|
|
printk( "%lu MB (%lu byte blocks)\n",
|
564 |
|
|
((capacity + 5L) / 10L), size );
|
565 |
|
|
}
|
566 |
|
|
}
|
567 |
|
|
}
|
568 |
|
|
}
|
569 |
|
|
}
|
570 |
|
|
#endif
|
571 |
|
|
}
|
572 |
|
|
}
|
573 |
|
|
|
574 |
|
|
if (found == FD_MAX_HOSTS) {
|
575 |
|
|
printk( "fd_mcs: detecting reached max=%d host adapters.\n",
|
576 |
|
|
FD_MAX_HOSTS);
|
577 |
|
|
break;
|
578 |
|
|
}
|
579 |
|
|
}
|
580 |
|
|
|
581 |
|
|
return found;
|
582 |
|
|
}
|
583 |
|
|
|
584 |
|
|
const char *fd_mcs_info(struct Scsi_Host *shpnt)
|
585 |
|
|
{
|
586 |
|
|
return adapter_name;
|
587 |
|
|
}
|
588 |
|
|
|
589 |
|
|
static int TOTAL_INTR = 0;
|
590 |
|
|
|
591 |
|
|
/*
|
592 |
|
|
* inout : decides on the direction of the dataflow and the meaning of the
|
593 |
|
|
* variables
|
594 |
|
|
* buffer: If inout==FALSE data is being written to it else read from it
|
595 |
|
|
* *start: If inout==FALSE start of the valid data in the buffer
|
596 |
|
|
* offset: If inout==FALSE offset from the beginning of the imaginary file
|
597 |
|
|
* from which we start writing into the buffer
|
598 |
|
|
* length: If inout==FALSE max number of bytes to be written into the buffer
|
599 |
|
|
* else number of bytes in the buffer
|
600 |
|
|
*/
|
601 |
|
|
int fd_mcs_proc_info( char *buffer, char **start, off_t offset,
|
602 |
|
|
int length, int hostno, int inout )
|
603 |
|
|
{
|
604 |
|
|
struct Scsi_Host *shpnt;
|
605 |
|
|
int len = 0;
|
606 |
|
|
int i;
|
607 |
|
|
|
608 |
|
|
if (inout)
|
609 |
|
|
return(-ENOSYS);
|
610 |
|
|
|
611 |
|
|
*start = buffer + offset;
|
612 |
|
|
|
613 |
|
|
for (i = 0; hosts[i] && hosts[i]->host_no != hostno; i++);
|
614 |
|
|
shpnt = hosts[i];
|
615 |
|
|
|
616 |
|
|
if (!shpnt) {
|
617 |
|
|
return(-ENOENT);
|
618 |
|
|
} else {
|
619 |
|
|
len += sprintf(buffer+len, "Future Domain MCS-600/700 Driver %s\n",
|
620 |
|
|
DRIVER_VERSION);
|
621 |
|
|
|
622 |
|
|
len += sprintf(buffer+len, "HOST #%d: %s\n",
|
623 |
|
|
hostno, adapter_name);
|
624 |
|
|
|
625 |
|
|
len += sprintf(buffer+len, "FIFO Size=0x%x, FIFO Count=%d\n",
|
626 |
|
|
FIFO_Size, FIFO_COUNT);
|
627 |
|
|
|
628 |
|
|
len += sprintf(buffer+len, "DriverCalls=%d, Interrupts=%d, BytesRead=%d, BytesWrite=%d\n\n",
|
629 |
|
|
TOTAL_INTR, INTR_Processed, Bytes_Read, Bytes_Written);
|
630 |
|
|
}
|
631 |
|
|
|
632 |
|
|
if ((len -= offset) <= 0)
|
633 |
|
|
return 0;
|
634 |
|
|
if (len > length)
|
635 |
|
|
len = length;
|
636 |
|
|
return len;
|
637 |
|
|
}
|
638 |
|
|
|
639 |
|
|
static int fd_mcs_select(struct Scsi_Host *shpnt, int target )
|
640 |
|
|
{
|
641 |
|
|
int status;
|
642 |
|
|
unsigned long timeout;
|
643 |
|
|
|
644 |
|
|
outb( 0x82, SCSI_Cntl_port ); /* Bus Enable + Select */
|
645 |
|
|
outb( adapter_mask | (1 << target), SCSI_Data_NoACK_port );
|
646 |
|
|
|
647 |
|
|
/* Stop arbitration and enable parity */
|
648 |
|
|
outb( PARITY_MASK, TMC_Cntl_port );
|
649 |
|
|
|
650 |
|
|
timeout = 350; /* 350mS -- because of timeouts
|
651 |
|
|
(was 250mS) */
|
652 |
|
|
|
653 |
|
|
do {
|
654 |
|
|
status = inb( SCSI_Status_port ); /* Read adapter status */
|
655 |
|
|
if (status & 1) { /* Busy asserted */
|
656 |
|
|
/* Enable SCSI Bus (on error, should make bus idle with 0) */
|
657 |
|
|
outb( 0x80, SCSI_Cntl_port );
|
658 |
|
|
return 0;
|
659 |
|
|
}
|
660 |
|
|
udelay(1000); /* wait one msec */
|
661 |
|
|
} while (--timeout);
|
662 |
|
|
|
663 |
|
|
/* Make bus idle */
|
664 |
|
|
fd_mcs_make_bus_idle(shpnt);
|
665 |
|
|
#if EVERY_ACCESS
|
666 |
|
|
if (!target) printk( "Selection failed\n" );
|
667 |
|
|
#endif
|
668 |
|
|
#if ERRORS_ONLY
|
669 |
|
|
if (!target) {
|
670 |
|
|
static int flag = 0;
|
671 |
|
|
|
672 |
|
|
if (!flag) /* Skip first failure for all chips. */
|
673 |
|
|
++flag;
|
674 |
|
|
else
|
675 |
|
|
printk( "fd_mcs: Selection failed\n" );
|
676 |
|
|
}
|
677 |
|
|
#endif
|
678 |
|
|
return 1;
|
679 |
|
|
}
|
680 |
|
|
|
681 |
|
|
static void my_done( struct Scsi_Host *shpnt, int error )
|
682 |
|
|
{
|
683 |
|
|
if (in_command) {
|
684 |
|
|
in_command = 0;
|
685 |
|
|
outb( 0x00, Interrupt_Cntl_port );
|
686 |
|
|
fd_mcs_make_bus_idle(shpnt);
|
687 |
|
|
current_SC->result = error;
|
688 |
|
|
current_SC->scsi_done( current_SC );
|
689 |
|
|
} else {
|
690 |
|
|
panic( "fd_mcs: my_done() called outside of command\n" );
|
691 |
|
|
}
|
692 |
|
|
#if DEBUG_RACE
|
693 |
|
|
in_interrupt_flag = 0;
|
694 |
|
|
#endif
|
695 |
|
|
}
|
696 |
|
|
|
697 |
|
|
/* only my_done needs to be protected */
|
698 |
|
|
static void fd_mcs_intr( int irq, void *dev_id, struct pt_regs * regs )
|
699 |
|
|
{
|
700 |
|
|
unsigned long flags;
|
701 |
|
|
int status;
|
702 |
|
|
int done = 0;
|
703 |
|
|
unsigned data_count, tmp_count;
|
704 |
|
|
|
705 |
|
|
int i = 0;
|
706 |
|
|
struct Scsi_Host *shpnt;
|
707 |
|
|
|
708 |
|
|
TOTAL_INTR++;
|
709 |
|
|
|
710 |
|
|
/* search for one adapter-response on shared interrupt */
|
711 |
|
|
while ((shpnt = hosts[i++])) {
|
712 |
|
|
if ((inb(TMC_Status_port)) & 1)
|
713 |
|
|
break;
|
714 |
|
|
}
|
715 |
|
|
|
716 |
|
|
/* return if some other device on this IRQ caused the interrupt */
|
717 |
|
|
if (!shpnt) {
|
718 |
|
|
return;
|
719 |
|
|
}
|
720 |
|
|
|
721 |
|
|
INTR_Processed++;
|
722 |
|
|
|
723 |
|
|
outb( 0x00, Interrupt_Cntl_port );
|
724 |
|
|
|
725 |
|
|
/* Abort calls my_done, so we do nothing here. */
|
726 |
|
|
if (current_SC->SCp.phase & aborted) {
|
727 |
|
|
#if DEBUG_ABORT
|
728 |
|
|
printk( "Interrupt after abort, ignoring\n" );
|
729 |
|
|
#endif
|
730 |
|
|
/* return; */
|
731 |
|
|
}
|
732 |
|
|
|
733 |
|
|
#if DEBUG_RACE
|
734 |
|
|
++in_interrupt_flag;
|
735 |
|
|
#endif
|
736 |
|
|
|
737 |
|
|
if (current_SC->SCp.phase & in_arbitration) {
|
738 |
|
|
status = inb( TMC_Status_port ); /* Read adapter status */
|
739 |
|
|
if (!(status & 0x02)) {
|
740 |
|
|
#if EVERY_ACCESS
|
741 |
|
|
printk( " AFAIL " );
|
742 |
|
|
#endif
|
743 |
|
|
spin_lock_irqsave(&io_request_lock, flags);
|
744 |
|
|
my_done( shpnt, DID_BUS_BUSY << 16 );
|
745 |
|
|
spin_unlock_irqrestore(&io_request_lock, flags);
|
746 |
|
|
return;
|
747 |
|
|
}
|
748 |
|
|
current_SC->SCp.phase = in_selection;
|
749 |
|
|
|
750 |
|
|
outb( 0x40 | FIFO_COUNT, Interrupt_Cntl_port );
|
751 |
|
|
|
752 |
|
|
outb( 0x82, SCSI_Cntl_port ); /* Bus Enable + Select */
|
753 |
|
|
outb( adapter_mask | (1 << current_SC->target), SCSI_Data_NoACK_port );
|
754 |
|
|
|
755 |
|
|
/* Stop arbitration and enable parity */
|
756 |
|
|
outb( 0x10 | PARITY_MASK, TMC_Cntl_port );
|
757 |
|
|
#if DEBUG_RACE
|
758 |
|
|
in_interrupt_flag = 0;
|
759 |
|
|
#endif
|
760 |
|
|
return;
|
761 |
|
|
} else if (current_SC->SCp.phase & in_selection) {
|
762 |
|
|
status = inb( SCSI_Status_port );
|
763 |
|
|
if (!(status & 0x01)) {
|
764 |
|
|
/* Try again, for slow devices */
|
765 |
|
|
if (fd_mcs_select(shpnt, current_SC->target )) {
|
766 |
|
|
#if EVERY_ACCESS
|
767 |
|
|
printk( " SFAIL " );
|
768 |
|
|
#endif
|
769 |
|
|
spin_lock_irqsave(&io_request_lock, flags);
|
770 |
|
|
my_done( shpnt, DID_NO_CONNECT << 16 );
|
771 |
|
|
spin_unlock_irqrestore(&io_request_lock, flags);
|
772 |
|
|
return;
|
773 |
|
|
} else {
|
774 |
|
|
#if EVERY_ACCESS
|
775 |
|
|
printk( " AltSel " );
|
776 |
|
|
#endif
|
777 |
|
|
/* Stop arbitration and enable parity */
|
778 |
|
|
outb( 0x10 | PARITY_MASK, TMC_Cntl_port );
|
779 |
|
|
}
|
780 |
|
|
}
|
781 |
|
|
current_SC->SCp.phase = in_other;
|
782 |
|
|
outb( 0x90 | FIFO_COUNT, Interrupt_Cntl_port );
|
783 |
|
|
outb( 0x80, SCSI_Cntl_port );
|
784 |
|
|
#if DEBUG_RACE
|
785 |
|
|
in_interrupt_flag = 0;
|
786 |
|
|
#endif
|
787 |
|
|
return;
|
788 |
|
|
}
|
789 |
|
|
|
790 |
|
|
/* current_SC->SCp.phase == in_other: this is the body of the routine */
|
791 |
|
|
|
792 |
|
|
status = inb( SCSI_Status_port );
|
793 |
|
|
|
794 |
|
|
if (status & 0x10) { /* REQ */
|
795 |
|
|
|
796 |
|
|
switch (status & 0x0e) {
|
797 |
|
|
|
798 |
|
|
case 0x08: /* COMMAND OUT */
|
799 |
|
|
outb( current_SC->cmnd[current_SC->SCp.sent_command++],
|
800 |
|
|
Write_SCSI_Data_port );
|
801 |
|
|
#if EVERY_ACCESS
|
802 |
|
|
printk( "CMD = %x,",
|
803 |
|
|
current_SC->cmnd[ current_SC->SCp.sent_command - 1] );
|
804 |
|
|
#endif
|
805 |
|
|
break;
|
806 |
|
|
case 0x00: /* DATA OUT -- tmc18c50/tmc18c30 only */
|
807 |
|
|
if (chip != tmc1800 && !current_SC->SCp.have_data_in) {
|
808 |
|
|
current_SC->SCp.have_data_in = -1;
|
809 |
|
|
outb( 0xd0 | PARITY_MASK, TMC_Cntl_port );
|
810 |
|
|
}
|
811 |
|
|
break;
|
812 |
|
|
case 0x04: /* DATA IN -- tmc18c50/tmc18c30 only */
|
813 |
|
|
if (chip != tmc1800 && !current_SC->SCp.have_data_in) {
|
814 |
|
|
current_SC->SCp.have_data_in = 1;
|
815 |
|
|
outb( 0x90 | PARITY_MASK, TMC_Cntl_port );
|
816 |
|
|
}
|
817 |
|
|
break;
|
818 |
|
|
case 0x0c: /* STATUS IN */
|
819 |
|
|
current_SC->SCp.Status = inb( Read_SCSI_Data_port );
|
820 |
|
|
#if EVERY_ACCESS
|
821 |
|
|
printk( "Status = %x, ", current_SC->SCp.Status );
|
822 |
|
|
#endif
|
823 |
|
|
#if ERRORS_ONLY
|
824 |
|
|
if (current_SC->SCp.Status
|
825 |
|
|
&& current_SC->SCp.Status != 2
|
826 |
|
|
&& current_SC->SCp.Status != 8) {
|
827 |
|
|
printk( "ERROR fd_mcs: target = %d, command = %x, status = %x\n",
|
828 |
|
|
current_SC->target,
|
829 |
|
|
current_SC->cmnd[0],
|
830 |
|
|
current_SC->SCp.Status );
|
831 |
|
|
}
|
832 |
|
|
#endif
|
833 |
|
|
break;
|
834 |
|
|
case 0x0a: /* MESSAGE OUT */
|
835 |
|
|
outb( MESSAGE_REJECT, Write_SCSI_Data_port ); /* Reject */
|
836 |
|
|
break;
|
837 |
|
|
case 0x0e: /* MESSAGE IN */
|
838 |
|
|
current_SC->SCp.Message = inb( Read_SCSI_Data_port );
|
839 |
|
|
#if EVERY_ACCESS
|
840 |
|
|
printk( "Message = %x, ", current_SC->SCp.Message );
|
841 |
|
|
#endif
|
842 |
|
|
if (!current_SC->SCp.Message) ++done;
|
843 |
|
|
#if DEBUG_MESSAGES || EVERY_ACCESS
|
844 |
|
|
if (current_SC->SCp.Message) {
|
845 |
|
|
printk( "fd_mcs: message = %x\n", current_SC->SCp.Message );
|
846 |
|
|
}
|
847 |
|
|
#endif
|
848 |
|
|
break;
|
849 |
|
|
}
|
850 |
|
|
}
|
851 |
|
|
|
852 |
|
|
if (chip == tmc1800
|
853 |
|
|
&& !current_SC->SCp.have_data_in
|
854 |
|
|
&& (current_SC->SCp.sent_command
|
855 |
|
|
>= current_SC->cmd_len)) {
|
856 |
|
|
/* We have to get the FIFO direction
|
857 |
|
|
correct, so I've made a table based
|
858 |
|
|
on the SCSI Standard of which commands
|
859 |
|
|
appear to require a DATA OUT phase.
|
860 |
|
|
*/
|
861 |
|
|
/*
|
862 |
|
|
p. 94: Command for all device types
|
863 |
|
|
CHANGE DEFINITION 40 DATA OUT
|
864 |
|
|
COMPARE 39 DATA OUT
|
865 |
|
|
COPY 18 DATA OUT
|
866 |
|
|
COPY AND VERIFY 3a DATA OUT
|
867 |
|
|
INQUIRY 12
|
868 |
|
|
LOG SELECT 4c DATA OUT
|
869 |
|
|
LOG SENSE 4d
|
870 |
|
|
MODE SELECT (6) 15 DATA OUT
|
871 |
|
|
MODE SELECT (10) 55 DATA OUT
|
872 |
|
|
MODE SENSE (6) 1a
|
873 |
|
|
MODE SENSE (10) 5a
|
874 |
|
|
READ BUFFER 3c
|
875 |
|
|
RECEIVE DIAGNOSTIC RESULTS 1c
|
876 |
|
|
REQUEST SENSE 03
|
877 |
|
|
SEND DIAGNOSTIC 1d DATA OUT
|
878 |
|
|
TEST UNIT READY 00
|
879 |
|
|
WRITE BUFFER 3b DATA OUT
|
880 |
|
|
|
881 |
|
|
p.178: Commands for direct-access devices (not listed on p. 94)
|
882 |
|
|
FORMAT UNIT 04 DATA OUT
|
883 |
|
|
LOCK-UNLOCK CACHE 36
|
884 |
|
|
PRE-FETCH 34
|
885 |
|
|
PREVENT-ALLOW MEDIUM REMOVAL 1e
|
886 |
|
|
READ (6)/RECEIVE 08
|
887 |
|
|
READ (10) 3c
|
888 |
|
|
READ CAPACITY 25
|
889 |
|
|
READ DEFECT DATA (10) 37
|
890 |
|
|
READ LONG 3e
|
891 |
|
|
REASSIGN BLOCKS 07 DATA OUT
|
892 |
|
|
RELEASE 17
|
893 |
|
|
RESERVE 16 DATA OUT
|
894 |
|
|
REZERO UNIT/REWIND 01
|
895 |
|
|
SEARCH DATA EQUAL (10) 31 DATA OUT
|
896 |
|
|
SEARCH DATA HIGH (10) 30 DATA OUT
|
897 |
|
|
SEARCH DATA LOW (10) 32 DATA OUT
|
898 |
|
|
SEEK (6) 0b
|
899 |
|
|
SEEK (10) 2b
|
900 |
|
|
SET LIMITS (10) 33
|
901 |
|
|
START STOP UNIT 1b
|
902 |
|
|
SYNCHRONIZE CACHE 35
|
903 |
|
|
VERIFY (10) 2f
|
904 |
|
|
WRITE (6)/PRINT/SEND 0a DATA OUT
|
905 |
|
|
WRITE (10)/SEND 2a DATA OUT
|
906 |
|
|
WRITE AND VERIFY (10) 2e DATA OUT
|
907 |
|
|
WRITE LONG 3f DATA OUT
|
908 |
|
|
WRITE SAME 41 DATA OUT ?
|
909 |
|
|
|
910 |
|
|
p. 261: Commands for sequential-access devices (not previously listed)
|
911 |
|
|
ERASE 19
|
912 |
|
|
LOAD UNLOAD 1b
|
913 |
|
|
LOCATE 2b
|
914 |
|
|
READ BLOCK LIMITS 05
|
915 |
|
|
READ POSITION 34
|
916 |
|
|
READ REVERSE 0f
|
917 |
|
|
RECOVER BUFFERED DATA 14
|
918 |
|
|
SPACE 11
|
919 |
|
|
WRITE FILEMARKS 10 ?
|
920 |
|
|
|
921 |
|
|
p. 298: Commands for printer devices (not previously listed)
|
922 |
|
|
****** NOT SUPPORTED BY THIS DRIVER, since 0b is SEEK (6) *****
|
923 |
|
|
SLEW AND PRINT 0b DATA OUT -- same as seek
|
924 |
|
|
STOP PRINT 1b
|
925 |
|
|
SYNCHRONIZE BUFFER 10
|
926 |
|
|
|
927 |
|
|
p. 315: Commands for processor devices (not previously listed)
|
928 |
|
|
|
929 |
|
|
p. 321: Commands for write-once devices (not previously listed)
|
930 |
|
|
MEDIUM SCAN 38
|
931 |
|
|
READ (12) a8
|
932 |
|
|
SEARCH DATA EQUAL (12) b1 DATA OUT
|
933 |
|
|
SEARCH DATA HIGH (12) b0 DATA OUT
|
934 |
|
|
SEARCH DATA LOW (12) b2 DATA OUT
|
935 |
|
|
SET LIMITS (12) b3
|
936 |
|
|
VERIFY (12) af
|
937 |
|
|
WRITE (12) aa DATA OUT
|
938 |
|
|
WRITE AND VERIFY (12) ae DATA OUT
|
939 |
|
|
|
940 |
|
|
p. 332: Commands for CD-ROM devices (not previously listed)
|
941 |
|
|
PAUSE/RESUME 4b
|
942 |
|
|
PLAY AUDIO (10) 45
|
943 |
|
|
PLAY AUDIO (12) a5
|
944 |
|
|
PLAY AUDIO MSF 47
|
945 |
|
|
PLAY TRACK RELATIVE (10) 49
|
946 |
|
|
PLAY TRACK RELATIVE (12) a9
|
947 |
|
|
READ HEADER 44
|
948 |
|
|
READ SUB-CHANNEL 42
|
949 |
|
|
READ TOC 43
|
950 |
|
|
|
951 |
|
|
p. 370: Commands for scanner devices (not previously listed)
|
952 |
|
|
GET DATA BUFFER STATUS 34
|
953 |
|
|
GET WINDOW 25
|
954 |
|
|
OBJECT POSITION 31
|
955 |
|
|
SCAN 1b
|
956 |
|
|
SET WINDOW 24 DATA OUT
|
957 |
|
|
|
958 |
|
|
p. 391: Commands for optical memory devices (not listed)
|
959 |
|
|
ERASE (10) 2c
|
960 |
|
|
ERASE (12) ac
|
961 |
|
|
MEDIUM SCAN 38 DATA OUT
|
962 |
|
|
READ DEFECT DATA (12) b7
|
963 |
|
|
READ GENERATION 29
|
964 |
|
|
READ UPDATED BLOCK 2d
|
965 |
|
|
UPDATE BLOCK 3d DATA OUT
|
966 |
|
|
|
967 |
|
|
p. 419: Commands for medium changer devices (not listed)
|
968 |
|
|
EXCHANGE MEDIUM 46
|
969 |
|
|
INITIALIZE ELEMENT STATUS 07
|
970 |
|
|
MOVE MEDIUM a5
|
971 |
|
|
POSITION TO ELEMENT 2b
|
972 |
|
|
READ ELEMENT STATUS b8
|
973 |
|
|
REQUEST VOL. ELEMENT ADDRESS b5
|
974 |
|
|
SEND VOLUME TAG b6 DATA OUT
|
975 |
|
|
|
976 |
|
|
p. 454: Commands for communications devices (not listed previously)
|
977 |
|
|
GET MESSAGE (6) 08
|
978 |
|
|
GET MESSAGE (10) 28
|
979 |
|
|
GET MESSAGE (12) a8
|
980 |
|
|
*/
|
981 |
|
|
|
982 |
|
|
switch (current_SC->cmnd[0]) {
|
983 |
|
|
case CHANGE_DEFINITION: case COMPARE: case COPY:
|
984 |
|
|
case COPY_VERIFY: case LOG_SELECT: case MODE_SELECT:
|
985 |
|
|
case MODE_SELECT_10: case SEND_DIAGNOSTIC: case WRITE_BUFFER:
|
986 |
|
|
|
987 |
|
|
case FORMAT_UNIT: case REASSIGN_BLOCKS: case RESERVE:
|
988 |
|
|
case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW:
|
989 |
|
|
case WRITE_6: case WRITE_10: case WRITE_VERIFY:
|
990 |
|
|
case 0x3f: case 0x41:
|
991 |
|
|
|
992 |
|
|
case 0xb1: case 0xb0: case 0xb2:
|
993 |
|
|
case 0xaa: case 0xae:
|
994 |
|
|
|
995 |
|
|
case 0x24:
|
996 |
|
|
|
997 |
|
|
case 0x38: case 0x3d:
|
998 |
|
|
|
999 |
|
|
case 0xb6:
|
1000 |
|
|
|
1001 |
|
|
case 0xea: /* alternate number for WRITE LONG */
|
1002 |
|
|
|
1003 |
|
|
current_SC->SCp.have_data_in = -1;
|
1004 |
|
|
outb( 0xd0 | PARITY_MASK, TMC_Cntl_port );
|
1005 |
|
|
break;
|
1006 |
|
|
|
1007 |
|
|
case 0x00:
|
1008 |
|
|
default:
|
1009 |
|
|
|
1010 |
|
|
current_SC->SCp.have_data_in = 1;
|
1011 |
|
|
outb( 0x90 | PARITY_MASK, TMC_Cntl_port );
|
1012 |
|
|
break;
|
1013 |
|
|
}
|
1014 |
|
|
}
|
1015 |
|
|
|
1016 |
|
|
if (current_SC->SCp.have_data_in == -1) { /* DATA OUT */
|
1017 |
|
|
while ( (data_count = FIFO_Size - inw( FIFO_Data_Count_port )) > 512 ) {
|
1018 |
|
|
#if EVERY_ACCESS
|
1019 |
|
|
printk( "DC=%d, ", data_count ) ;
|
1020 |
|
|
#endif
|
1021 |
|
|
if (data_count > current_SC->SCp.this_residual)
|
1022 |
|
|
data_count = current_SC->SCp.this_residual;
|
1023 |
|
|
if (data_count > 0) {
|
1024 |
|
|
#if EVERY_ACCESS
|
1025 |
|
|
printk( "%d OUT, ", data_count );
|
1026 |
|
|
#endif
|
1027 |
|
|
if (data_count == 1) {
|
1028 |
|
|
Bytes_Written++;
|
1029 |
|
|
|
1030 |
|
|
outb( *current_SC->SCp.ptr++, Write_FIFO_port );
|
1031 |
|
|
--current_SC->SCp.this_residual;
|
1032 |
|
|
} else {
|
1033 |
|
|
data_count >>= 1;
|
1034 |
|
|
tmp_count = data_count << 1;
|
1035 |
|
|
outsw( Write_FIFO_port, current_SC->SCp.ptr, data_count );
|
1036 |
|
|
current_SC->SCp.ptr += tmp_count;
|
1037 |
|
|
Bytes_Written += tmp_count;
|
1038 |
|
|
current_SC->SCp.this_residual -= tmp_count;
|
1039 |
|
|
}
|
1040 |
|
|
}
|
1041 |
|
|
if (!current_SC->SCp.this_residual) {
|
1042 |
|
|
if (current_SC->SCp.buffers_residual) {
|
1043 |
|
|
--current_SC->SCp.buffers_residual;
|
1044 |
|
|
++current_SC->SCp.buffer;
|
1045 |
|
|
current_SC->SCp.ptr = current_SC->SCp.buffer->address;
|
1046 |
|
|
current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
|
1047 |
|
|
} else
|
1048 |
|
|
break;
|
1049 |
|
|
}
|
1050 |
|
|
}
|
1051 |
|
|
} else if (current_SC->SCp.have_data_in == 1) { /* DATA IN */
|
1052 |
|
|
while ((data_count = inw( FIFO_Data_Count_port )) > 0) {
|
1053 |
|
|
#if EVERY_ACCESS
|
1054 |
|
|
printk( "DC=%d, ", data_count );
|
1055 |
|
|
#endif
|
1056 |
|
|
if (data_count > current_SC->SCp.this_residual)
|
1057 |
|
|
data_count = current_SC->SCp.this_residual;
|
1058 |
|
|
if (data_count) {
|
1059 |
|
|
#if EVERY_ACCESS
|
1060 |
|
|
printk( "%d IN, ", data_count );
|
1061 |
|
|
#endif
|
1062 |
|
|
if (data_count == 1) {
|
1063 |
|
|
Bytes_Read++;
|
1064 |
|
|
*current_SC->SCp.ptr++ = inb( Read_FIFO_port );
|
1065 |
|
|
--current_SC->SCp.this_residual;
|
1066 |
|
|
} else {
|
1067 |
|
|
data_count >>= 1; /* Number of words */
|
1068 |
|
|
tmp_count = data_count << 1;
|
1069 |
|
|
insw( Read_FIFO_port, current_SC->SCp.ptr, data_count );
|
1070 |
|
|
current_SC->SCp.ptr += tmp_count;
|
1071 |
|
|
Bytes_Read += tmp_count;
|
1072 |
|
|
current_SC->SCp.this_residual -= tmp_count;
|
1073 |
|
|
}
|
1074 |
|
|
}
|
1075 |
|
|
if (!current_SC->SCp.this_residual
|
1076 |
|
|
&& current_SC->SCp.buffers_residual) {
|
1077 |
|
|
--current_SC->SCp.buffers_residual;
|
1078 |
|
|
++current_SC->SCp.buffer;
|
1079 |
|
|
current_SC->SCp.ptr = current_SC->SCp.buffer->address;
|
1080 |
|
|
current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
|
1081 |
|
|
}
|
1082 |
|
|
}
|
1083 |
|
|
}
|
1084 |
|
|
|
1085 |
|
|
if (done) {
|
1086 |
|
|
#if EVERY_ACCESS
|
1087 |
|
|
printk( " ** IN DONE %d ** ", current_SC->SCp.have_data_in );
|
1088 |
|
|
#endif
|
1089 |
|
|
|
1090 |
|
|
#if ERRORS_ONLY
|
1091 |
|
|
if (current_SC->cmnd[0] == REQUEST_SENSE && !current_SC->SCp.Status) {
|
1092 |
|
|
if ((unsigned char)(*((char *)current_SC->request_buffer+2)) & 0x0f) {
|
1093 |
|
|
unsigned char key;
|
1094 |
|
|
unsigned char code;
|
1095 |
|
|
unsigned char qualifier;
|
1096 |
|
|
|
1097 |
|
|
key = (unsigned char)(*((char *)current_SC->request_buffer + 2))
|
1098 |
|
|
& 0x0f;
|
1099 |
|
|
code = (unsigned char)(*((char *)current_SC->request_buffer + 12));
|
1100 |
|
|
qualifier = (unsigned char)(*((char *)current_SC->request_buffer
|
1101 |
|
|
+ 13));
|
1102 |
|
|
|
1103 |
|
|
if (key != UNIT_ATTENTION
|
1104 |
|
|
&& !(key == NOT_READY
|
1105 |
|
|
&& code == 0x04
|
1106 |
|
|
&& (!qualifier || qualifier == 0x02 || qualifier == 0x01))
|
1107 |
|
|
&& !(key == ILLEGAL_REQUEST && (code == 0x25
|
1108 |
|
|
|| code == 0x24
|
1109 |
|
|
|| !code)))
|
1110 |
|
|
|
1111 |
|
|
printk( "fd_mcs: REQUEST SENSE "
|
1112 |
|
|
"Key = %x, Code = %x, Qualifier = %x\n",
|
1113 |
|
|
key, code, qualifier );
|
1114 |
|
|
}
|
1115 |
|
|
}
|
1116 |
|
|
#endif
|
1117 |
|
|
#if EVERY_ACCESS
|
1118 |
|
|
printk( "BEFORE MY_DONE. . ." );
|
1119 |
|
|
#endif
|
1120 |
|
|
spin_lock_irqsave(&io_request_lock, flags);
|
1121 |
|
|
my_done( shpnt,
|
1122 |
|
|
(current_SC->SCp.Status & 0xff)
|
1123 |
|
|
| ((current_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16) );
|
1124 |
|
|
spin_unlock_irqrestore(&io_request_lock, flags);
|
1125 |
|
|
#if EVERY_ACCESS
|
1126 |
|
|
printk( "RETURNING.\n" );
|
1127 |
|
|
#endif
|
1128 |
|
|
|
1129 |
|
|
} else {
|
1130 |
|
|
if (current_SC->SCp.phase & disconnect) {
|
1131 |
|
|
outb( 0xd0 | FIFO_COUNT, Interrupt_Cntl_port );
|
1132 |
|
|
outb( 0x00, SCSI_Cntl_port );
|
1133 |
|
|
} else {
|
1134 |
|
|
outb( 0x90 | FIFO_COUNT, Interrupt_Cntl_port );
|
1135 |
|
|
}
|
1136 |
|
|
}
|
1137 |
|
|
#if DEBUG_RACE
|
1138 |
|
|
in_interrupt_flag = 0;
|
1139 |
|
|
#endif
|
1140 |
|
|
return;
|
1141 |
|
|
}
|
1142 |
|
|
|
1143 |
|
|
int fd_mcs_release(struct Scsi_Host *shpnt)
|
1144 |
|
|
{
|
1145 |
|
|
int i, this_host, irq_usage;
|
1146 |
|
|
|
1147 |
|
|
release_region(shpnt->io_port, shpnt->n_io_port);
|
1148 |
|
|
|
1149 |
|
|
this_host = -1;
|
1150 |
|
|
irq_usage = 0;
|
1151 |
|
|
for (i = 0; i < found; i++) {
|
1152 |
|
|
if (shpnt == hosts[i])
|
1153 |
|
|
this_host = i;
|
1154 |
|
|
if (shpnt->irq == hosts[i]->irq)
|
1155 |
|
|
irq_usage++;
|
1156 |
|
|
}
|
1157 |
|
|
|
1158 |
|
|
/* only for the last one */
|
1159 |
|
|
if (1 == irq_usage)
|
1160 |
|
|
free_irq(shpnt->irq, hosts);
|
1161 |
|
|
|
1162 |
|
|
found--;
|
1163 |
|
|
|
1164 |
|
|
for (i = this_host; i < found; i++)
|
1165 |
|
|
hosts[i] = hosts[i+1];
|
1166 |
|
|
|
1167 |
|
|
hosts[found] = NULL;
|
1168 |
|
|
|
1169 |
|
|
return 0;
|
1170 |
|
|
}
|
1171 |
|
|
|
1172 |
|
|
int fd_mcs_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
|
1173 |
|
|
{
|
1174 |
|
|
struct Scsi_Host *shpnt = SCpnt->host;
|
1175 |
|
|
|
1176 |
|
|
if (in_command) {
|
1177 |
|
|
panic( "fd_mcs: fd_mcs_queue() NOT REENTRANT!\n" );
|
1178 |
|
|
}
|
1179 |
|
|
#if EVERY_ACCESS
|
1180 |
|
|
printk( "queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n",
|
1181 |
|
|
SCpnt->target,
|
1182 |
|
|
*(unsigned char *)SCpnt->cmnd,
|
1183 |
|
|
SCpnt->use_sg,
|
1184 |
|
|
SCpnt->request_bufflen );
|
1185 |
|
|
#endif
|
1186 |
|
|
|
1187 |
|
|
fd_mcs_make_bus_idle(shpnt);
|
1188 |
|
|
|
1189 |
|
|
SCpnt->scsi_done = done; /* Save this for the done function */
|
1190 |
|
|
current_SC = SCpnt;
|
1191 |
|
|
|
1192 |
|
|
/* Initialize static data */
|
1193 |
|
|
|
1194 |
|
|
if (current_SC->use_sg) {
|
1195 |
|
|
current_SC->SCp.buffer =
|
1196 |
|
|
(struct scatterlist *)current_SC->request_buffer;
|
1197 |
|
|
current_SC->SCp.ptr = current_SC->SCp.buffer->address;
|
1198 |
|
|
current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
|
1199 |
|
|
current_SC->SCp.buffers_residual = current_SC->use_sg - 1;
|
1200 |
|
|
} else {
|
1201 |
|
|
current_SC->SCp.ptr = (char *)current_SC->request_buffer;
|
1202 |
|
|
current_SC->SCp.this_residual = current_SC->request_bufflen;
|
1203 |
|
|
current_SC->SCp.buffer = NULL;
|
1204 |
|
|
current_SC->SCp.buffers_residual = 0;
|
1205 |
|
|
}
|
1206 |
|
|
|
1207 |
|
|
|
1208 |
|
|
current_SC->SCp.Status = 0;
|
1209 |
|
|
current_SC->SCp.Message = 0;
|
1210 |
|
|
current_SC->SCp.have_data_in = 0;
|
1211 |
|
|
current_SC->SCp.sent_command = 0;
|
1212 |
|
|
current_SC->SCp.phase = in_arbitration;
|
1213 |
|
|
|
1214 |
|
|
/* Start arbitration */
|
1215 |
|
|
outb( 0x00, Interrupt_Cntl_port );
|
1216 |
|
|
outb( 0x00, SCSI_Cntl_port ); /* Disable data drivers */
|
1217 |
|
|
outb( adapter_mask, SCSI_Data_NoACK_port ); /* Set our id bit */
|
1218 |
|
|
in_command = 1;
|
1219 |
|
|
outb( 0x20, Interrupt_Cntl_port );
|
1220 |
|
|
outb( 0x14 | PARITY_MASK, TMC_Cntl_port ); /* Start arbitration */
|
1221 |
|
|
|
1222 |
|
|
return 0;
|
1223 |
|
|
}
|
1224 |
|
|
|
1225 |
|
|
static void internal_done( Scsi_Cmnd *SCpnt )
|
1226 |
|
|
{
|
1227 |
|
|
/* flag it done */
|
1228 |
|
|
SCpnt->host_scribble = (unsigned char *)1;
|
1229 |
|
|
}
|
1230 |
|
|
|
1231 |
|
|
int fd_mcs_command( Scsi_Cmnd *SCpnt )
|
1232 |
|
|
{
|
1233 |
|
|
fd_mcs_queue( SCpnt, internal_done );
|
1234 |
|
|
/* host_scribble is used for status here */
|
1235 |
|
|
SCpnt->host_scribble = NULL;
|
1236 |
|
|
while (!SCpnt->host_scribble)
|
1237 |
|
|
barrier();
|
1238 |
|
|
return SCpnt->result;
|
1239 |
|
|
}
|
1240 |
|
|
|
1241 |
|
|
#if DEBUG_ABORT || DEBUG_RESET
|
1242 |
|
|
static void fd_mcs_print_info( Scsi_Cmnd *SCpnt )
|
1243 |
|
|
{
|
1244 |
|
|
unsigned int imr;
|
1245 |
|
|
unsigned int irr;
|
1246 |
|
|
unsigned int isr;
|
1247 |
|
|
struct Scsi_Host *shpnt = SCpnt->host;
|
1248 |
|
|
|
1249 |
|
|
if (!SCpnt || !SCpnt->host) {
|
1250 |
|
|
printk( "fd_mcs: cannot provide detailed information\n" );
|
1251 |
|
|
}
|
1252 |
|
|
|
1253 |
|
|
printk( "%s\n", fd_mcs_info( SCpnt->host ) );
|
1254 |
|
|
print_banner( SCpnt->host );
|
1255 |
|
|
switch (SCpnt->SCp.phase) {
|
1256 |
|
|
case in_arbitration: printk( "arbitration " ); break;
|
1257 |
|
|
case in_selection: printk( "selection " ); break;
|
1258 |
|
|
case in_other: printk( "other " ); break;
|
1259 |
|
|
default: printk( "unknown " ); break;
|
1260 |
|
|
}
|
1261 |
|
|
|
1262 |
|
|
printk( "(%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n",
|
1263 |
|
|
SCpnt->SCp.phase,
|
1264 |
|
|
SCpnt->target,
|
1265 |
|
|
*(unsigned char *)SCpnt->cmnd,
|
1266 |
|
|
SCpnt->use_sg,
|
1267 |
|
|
SCpnt->request_bufflen );
|
1268 |
|
|
printk( "sent_command = %d, have_data_in = %d, timeout = %d\n",
|
1269 |
|
|
SCpnt->SCp.sent_command,
|
1270 |
|
|
SCpnt->SCp.have_data_in,
|
1271 |
|
|
SCpnt->timeout );
|
1272 |
|
|
#if DEBUG_RACE
|
1273 |
|
|
printk( "in_interrupt_flag = %d\n", in_interrupt_flag );
|
1274 |
|
|
#endif
|
1275 |
|
|
|
1276 |
|
|
imr = (inb( 0x0a1 ) << 8) + inb( 0x21 );
|
1277 |
|
|
outb( 0x0a, 0xa0 );
|
1278 |
|
|
irr = inb( 0xa0 ) << 8;
|
1279 |
|
|
outb( 0x0a, 0x20 );
|
1280 |
|
|
irr += inb( 0x20 );
|
1281 |
|
|
outb( 0x0b, 0xa0 );
|
1282 |
|
|
isr = inb( 0xa0 ) << 8;
|
1283 |
|
|
outb( 0x0b, 0x20 );
|
1284 |
|
|
isr += inb( 0x20 );
|
1285 |
|
|
|
1286 |
|
|
/* Print out interesting information */
|
1287 |
|
|
printk( "IMR = 0x%04x", imr );
|
1288 |
|
|
if (imr & (1 << shpnt->irq))
|
1289 |
|
|
printk( " (masked)" );
|
1290 |
|
|
printk( ", IRR = 0x%04x, ISR = 0x%04x\n", irr, isr );
|
1291 |
|
|
|
1292 |
|
|
printk( "SCSI Status = 0x%02x\n", inb( SCSI_Status_port ) );
|
1293 |
|
|
printk( "TMC Status = 0x%02x", inb( TMC_Status_port ) );
|
1294 |
|
|
if (inb( TMC_Status_port ) & 1)
|
1295 |
|
|
printk( " (interrupt)" );
|
1296 |
|
|
printk( "\n" );
|
1297 |
|
|
printk( "Interrupt Status = 0x%02x", inb( Interrupt_Status_port ) );
|
1298 |
|
|
if (inb( Interrupt_Status_port ) & 0x08)
|
1299 |
|
|
printk( " (enabled)" );
|
1300 |
|
|
printk( "\n" );
|
1301 |
|
|
if (chip == tmc18c50 || chip == tmc18c30) {
|
1302 |
|
|
printk( "FIFO Status = 0x%02x\n", inb( shpnt->io_port + FIFO_Status ) );
|
1303 |
|
|
printk( "Int. Condition = 0x%02x\n",
|
1304 |
|
|
inb( shpnt->io_port + Interrupt_Cond ) );
|
1305 |
|
|
}
|
1306 |
|
|
printk( "Configuration 1 = 0x%02x\n", inb( shpnt->io_port + Configuration1 ) );
|
1307 |
|
|
if (chip == tmc18c50 || chip == tmc18c30)
|
1308 |
|
|
printk( "Configuration 2 = 0x%02x\n",
|
1309 |
|
|
inb( shpnt->io_port + Configuration2 ) );
|
1310 |
|
|
}
|
1311 |
|
|
#endif
|
1312 |
|
|
|
1313 |
|
|
int fd_mcs_abort( Scsi_Cmnd *SCpnt)
|
1314 |
|
|
{
|
1315 |
|
|
struct Scsi_Host *shpnt = SCpnt->host;
|
1316 |
|
|
|
1317 |
|
|
unsigned long flags;
|
1318 |
|
|
#if EVERY_ACCESS || ERRORS_ONLY || DEBUG_ABORT
|
1319 |
|
|
printk( "fd_mcs: abort " );
|
1320 |
|
|
#endif
|
1321 |
|
|
|
1322 |
|
|
save_flags( flags );
|
1323 |
|
|
cli();
|
1324 |
|
|
if (!in_command) {
|
1325 |
|
|
#if EVERY_ACCESS || ERRORS_ONLY
|
1326 |
|
|
printk( " (not in command)\n" );
|
1327 |
|
|
#endif
|
1328 |
|
|
restore_flags( flags );
|
1329 |
|
|
return SCSI_ABORT_NOT_RUNNING;
|
1330 |
|
|
} else printk( "\n" );
|
1331 |
|
|
|
1332 |
|
|
#if DEBUG_ABORT
|
1333 |
|
|
fd_mcs_print_info( SCpnt );
|
1334 |
|
|
#endif
|
1335 |
|
|
|
1336 |
|
|
fd_mcs_make_bus_idle(shpnt);
|
1337 |
|
|
|
1338 |
|
|
current_SC->SCp.phase |= aborted;
|
1339 |
|
|
|
1340 |
|
|
current_SC->result = DID_ABORT << 16;
|
1341 |
|
|
|
1342 |
|
|
restore_flags( flags );
|
1343 |
|
|
|
1344 |
|
|
/* Aborts are not done well. . . */
|
1345 |
|
|
spin_lock_irqsave(&io_request_lock, flags);
|
1346 |
|
|
my_done( shpnt, DID_ABORT << 16 );
|
1347 |
|
|
spin_unlock_irqrestore(&io_request_lock, flags);
|
1348 |
|
|
|
1349 |
|
|
return SCSI_ABORT_SUCCESS;
|
1350 |
|
|
}
|
1351 |
|
|
|
1352 |
|
|
int fd_mcs_reset( Scsi_Cmnd *SCpnt, unsigned int reset_flags )
|
1353 |
|
|
{
|
1354 |
|
|
struct Scsi_Host *shpnt = SCpnt->host;
|
1355 |
|
|
|
1356 |
|
|
#if DEBUG_RESET
|
1357 |
|
|
static int called_once = 0;
|
1358 |
|
|
#endif
|
1359 |
|
|
|
1360 |
|
|
#if ERRORS_ONLY
|
1361 |
|
|
if (SCpnt) printk( "fd_mcs: SCSI Bus Reset\n" );
|
1362 |
|
|
#endif
|
1363 |
|
|
|
1364 |
|
|
#if DEBUG_RESET
|
1365 |
|
|
if (called_once) fd_mcs_print_info( current_SC );
|
1366 |
|
|
called_once = 1;
|
1367 |
|
|
#endif
|
1368 |
|
|
|
1369 |
|
|
outb( 1, SCSI_Cntl_port );
|
1370 |
|
|
do_pause( 2 );
|
1371 |
|
|
outb( 0, SCSI_Cntl_port );
|
1372 |
|
|
do_pause( 115 );
|
1373 |
|
|
outb( 0, SCSI_Mode_Cntl_port );
|
1374 |
|
|
outb( PARITY_MASK, TMC_Cntl_port );
|
1375 |
|
|
|
1376 |
|
|
/* Unless this is the very first call (i.e., SCPnt == NULL), everything
|
1377 |
|
|
is probably hosed at this point. We will, however, try to keep
|
1378 |
|
|
things going by informing the high-level code that we need help. */
|
1379 |
|
|
|
1380 |
|
|
return SCSI_RESET_WAKEUP;
|
1381 |
|
|
}
|
1382 |
|
|
|
1383 |
|
|
#include "sd.h"
|
1384 |
|
|
#include <scsi/scsi_ioctl.h>
|
1385 |
|
|
|
1386 |
|
|
int fd_mcs_biosparam( Scsi_Disk *disk, kdev_t dev, int *info_array )
|
1387 |
|
|
{
|
1388 |
|
|
int drive;
|
1389 |
|
|
unsigned char buf[512 + sizeof( int ) * 2];
|
1390 |
|
|
int size = disk->capacity;
|
1391 |
|
|
int *sizes = (int *)buf;
|
1392 |
|
|
unsigned char *data = (unsigned char *)(sizes + 2);
|
1393 |
|
|
unsigned char do_read[] = { READ_6, 0, 0, 0, 1, 0 };
|
1394 |
|
|
int retcode;
|
1395 |
|
|
|
1396 |
|
|
/* BIOS >= 3.4 for MCA cards */
|
1397 |
|
|
drive = MINOR(dev) / 16;
|
1398 |
|
|
|
1399 |
|
|
/* This algorithm was provided by Future Domain (much thanks!). */
|
1400 |
|
|
|
1401 |
|
|
sizes[0] = 0; /* zero bytes out */
|
1402 |
|
|
sizes[1] = 512; /* one sector in */
|
1403 |
|
|
memcpy( data, do_read, sizeof( do_read ) );
|
1404 |
|
|
retcode = kernel_scsi_ioctl( disk->device,
|
1405 |
|
|
SCSI_IOCTL_SEND_COMMAND,
|
1406 |
|
|
(void *)buf );
|
1407 |
|
|
if (!retcode /* SCSI command ok */
|
1408 |
|
|
&& data[511] == 0xaa && data[510] == 0x55 /* Partition table valid */
|
1409 |
|
|
&& data[0x1c2]) { /* Partition type */
|
1410 |
|
|
|
1411 |
|
|
/* The partition table layout is as follows:
|
1412 |
|
|
|
1413 |
|
|
Start: 0x1b3h
|
1414 |
|
|
Offset: 0 = partition status
|
1415 |
|
|
1 = starting head
|
1416 |
|
|
2 = starting sector and cylinder (word, encoded)
|
1417 |
|
|
4 = partition type
|
1418 |
|
|
5 = ending head
|
1419 |
|
|
6 = ending sector and cylinder (word, encoded)
|
1420 |
|
|
8 = starting absolute sector (double word)
|
1421 |
|
|
c = number of sectors (double word)
|
1422 |
|
|
Signature: 0x1fe = 0x55aa
|
1423 |
|
|
|
1424 |
|
|
So, this algorithm assumes:
|
1425 |
|
|
1) the first partition table is in use,
|
1426 |
|
|
2) the data in the first entry is correct, and
|
1427 |
|
|
3) partitions never divide cylinders
|
1428 |
|
|
|
1429 |
|
|
Note that (1) may be FALSE for NetBSD (and other BSD flavors),
|
1430 |
|
|
as well as for Linux. Note also, that Linux doesn't pay any
|
1431 |
|
|
attention to the fields that are used by this algorithm -- it
|
1432 |
|
|
only uses the absolute sector data. Recent versions of Linux's
|
1433 |
|
|
fdisk(1) will fill this data in correctly, and forthcoming
|
1434 |
|
|
versions will check for consistency.
|
1435 |
|
|
|
1436 |
|
|
Checking for a non-zero partition type is not part of the
|
1437 |
|
|
Future Domain algorithm, but it seemed to be a reasonable thing
|
1438 |
|
|
to do, especially in the Linux and BSD worlds. */
|
1439 |
|
|
|
1440 |
|
|
info_array[0] = data[0x1c3] + 1; /* heads */
|
1441 |
|
|
info_array[1] = data[0x1c4] & 0x3f; /* sectors */
|
1442 |
|
|
} else {
|
1443 |
|
|
|
1444 |
|
|
/* Note that this new method guarantees that there will always be
|
1445 |
|
|
less than 1024 cylinders on a platter. This is good for drives
|
1446 |
|
|
up to approximately 7.85GB (where 1GB = 1024 * 1024 kB). */
|
1447 |
|
|
|
1448 |
|
|
if ((unsigned int)size >= 0x7e0000U) {
|
1449 |
|
|
info_array[0] = 0xff; /* heads = 255 */
|
1450 |
|
|
info_array[1] = 0x3f; /* sectors = 63 */
|
1451 |
|
|
} else if ((unsigned int)size >= 0x200000U) {
|
1452 |
|
|
info_array[0] = 0x80; /* heads = 128 */
|
1453 |
|
|
info_array[1] = 0x3f; /* sectors = 63 */
|
1454 |
|
|
} else {
|
1455 |
|
|
info_array[0] = 0x40; /* heads = 64 */
|
1456 |
|
|
info_array[1] = 0x20; /* sectors = 32 */
|
1457 |
|
|
}
|
1458 |
|
|
}
|
1459 |
|
|
/* For both methods, compute the cylinders */
|
1460 |
|
|
info_array[2] = (unsigned int)size / (info_array[0] * info_array[1] );
|
1461 |
|
|
|
1462 |
|
|
|
1463 |
|
|
return 0;
|
1464 |
|
|
}
|
1465 |
|
|
|
1466 |
|
|
/* Eventually this will go into an include file, but this will be later */
|
1467 |
|
|
static Scsi_Host_Template driver_template = FD_MCS;
|
1468 |
|
|
|
1469 |
|
|
#include "scsi_module.c"
|