File: | obj-scan-build/../linux/src/drivers/scsi/fdomain.c |
Location: | line 1796, column 39 |
Description: | Access to field 'host' results in a dereference of a null pointer (loaded from variable 'SCpnt') |
1 | /* fdomain.c -- Future Domain TMC-16x0 SCSI driver | |||
2 | * Created: Sun May 3 18:53:19 1992 by faith@cs.unc.edu | |||
3 | * Revised: Sat Nov 2 09:27:47 1996 by root@cs.unc.edu | |||
4 | * Author: Rickard E. Faith, faith@cs.unc.edu | |||
5 | * Copyright 1992, 1993, 1994, 1995, 1996 Rickard E. Faith | |||
6 | * | |||
7 | * $Id: fdomain.c,v 1.1 1999/04/26 05:54:32 tb Exp $ | |||
8 | ||||
9 | * This program is free software; you can redistribute it and/or modify it | |||
10 | * under the terms of the GNU General Public License as published by the | |||
11 | * Free Software Foundation; either version 2, or (at your option) any | |||
12 | * later version. | |||
13 | ||||
14 | * This program is distributed in the hope that it will be useful, but | |||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
17 | * General Public License for more details. | |||
18 | ||||
19 | * You should have received a copy of the GNU General Public License along | |||
20 | * with this program; if not, write to the Free Software Foundation, Inc., | |||
21 | * 675 Mass Ave, Cambridge, MA 02139, USA. | |||
22 | ||||
23 | ************************************************************************** | |||
24 | ||||
25 | SUMMARY: | |||
26 | ||||
27 | Future Domain BIOS versions supported for autodetect: | |||
28 | 2.0, 3.0, 3.2, 3.4 (1.0), 3.5 (2.0), 3.6, 3.61 | |||
29 | Chips are supported: | |||
30 | TMC-1800, TMC-18C50, TMC-18C30, TMC-36C70 | |||
31 | Boards supported: | |||
32 | Future Domain TMC-1650, TMC-1660, TMC-1670, TMC-1680, TMC-1610M/MER/MEX | |||
33 | Future Domain TMC-3260 (PCI) | |||
34 | Quantum ISA-200S, ISA-250MG | |||
35 | Adaptec AHA-2920 (PCI) | |||
36 | IBM ? | |||
37 | LILO command-line options: | |||
38 | fdomain=<PORT_BASE>,<IRQ>[,<ADAPTER_ID>] | |||
39 | ||||
40 | ||||
41 | ||||
42 | DESCRIPTION: | |||
43 | ||||
44 | This is the Linux low-level SCSI driver for Future Domain TMC-1660/1680 | |||
45 | TMC-1650/1670, and TMC-3260 SCSI host adapters. The 1650 and 1670 have a | |||
46 | 25-pin external connector, whereas the 1660 and 1680 have a SCSI-2 50-pin | |||
47 | high-density external connector. The 1670 and 1680 have floppy disk | |||
48 | controllers built in. The TMC-3260 is a PCI bus card. | |||
49 | ||||
50 | Future Domain's older boards are based on the TMC-1800 chip, and this | |||
51 | driver was originally written for a TMC-1680 board with the TMC-1800 chip. | |||
52 | More recently, boards are being produced with the TMC-18C50 and TMC-18C30 | |||
53 | chips. The latest and greatest board may not work with this driver. If | |||
54 | you have to patch this driver so that it will recognize your board's BIOS | |||
55 | signature, then the driver may fail to function after the board is | |||
56 | detected. | |||
57 | ||||
58 | Please note that the drive ordering that Future Domain implemented in BIOS | |||
59 | versions 3.4 and 3.5 is the opposite of the order (currently) used by the | |||
60 | rest of the SCSI industry. If you have BIOS version 3.4 or 3.5, and have | |||
61 | more then one drive, then the drive ordering will be the reverse of that | |||
62 | which you see under DOS. For example, under DOS SCSI ID 0 will be D: and | |||
63 | SCSI ID 1 will be C: (the boot device). Under Linux, SCSI ID 0 will be | |||
64 | /dev/sda and SCSI ID 1 will be /dev/sdb. The Linux ordering is consistent | |||
65 | with that provided by all the other SCSI drivers for Linux. If you want | |||
66 | this changed, you will probably have to patch the higher level SCSI code. | |||
67 | If you do so, please send me patches that are protected by #ifdefs. | |||
68 | ||||
69 | If you have a TMC-8xx or TMC-9xx board, then this is not the driver for | |||
70 | your board. Please refer to the Seagate driver for more information and | |||
71 | possible support. | |||
72 | ||||
73 | ||||
74 | ||||
75 | HISTORY: | |||
76 | ||||
77 | Linux Driver Driver | |||
78 | Version Version Date Support/Notes | |||
79 | ||||
80 | 0.0 3 May 1992 V2.0 BIOS; 1800 chip | |||
81 | 0.97 1.9 28 Jul 1992 | |||
82 | 0.98.6 3.1 27 Nov 1992 | |||
83 | 0.99 3.2 9 Dec 1992 | |||
84 | ||||
85 | 0.99.3 3.3 10 Jan 1993 V3.0 BIOS | |||
86 | 0.99.5 3.5 18 Feb 1993 | |||
87 | 0.99.10 3.6 15 May 1993 V3.2 BIOS; 18C50 chip | |||
88 | 0.99.11 3.17 3 Jul 1993 (now under RCS) | |||
89 | 0.99.12 3.18 13 Aug 1993 | |||
90 | 0.99.14 5.6 31 Oct 1993 (reselection code removed) | |||
91 | ||||
92 | 0.99.15 5.9 23 Jan 1994 V3.4 BIOS (preliminary) | |||
93 | 1.0.8/1.1.1 5.15 1 Apr 1994 V3.4 BIOS; 18C30 chip (preliminary) | |||
94 | 1.0.9/1.1.3 5.16 7 Apr 1994 V3.4 BIOS; 18C30 chip | |||
95 | 1.1.38 5.18 30 Jul 1994 36C70 chip (PCI version of 18C30) | |||
96 | 1.1.62 5.20 2 Nov 1994 V3.5 BIOS | |||
97 | 1.1.73 5.22 7 Dec 1994 Quantum ISA-200S board; V2.0 BIOS | |||
98 | ||||
99 | 1.1.82 5.26 14 Jan 1995 V3.5 BIOS; TMC-1610M/MER/MEX board | |||
100 | 1.2.10 5.28 5 Jun 1995 Quantum ISA-250MG board; V2.0, V2.01 BIOS | |||
101 | 1.3.4 5.31 23 Jun 1995 PCI BIOS-32 detection (preliminary) | |||
102 | 1.3.7 5.33 4 Jul 1995 PCI BIOS-32 detection | |||
103 | 1.3.28 5.36 17 Sep 1995 V3.61 BIOS; LILO command-line support | |||
104 | 1.3.34 5.39 12 Oct 1995 V3.60 BIOS; /proc | |||
105 | 1.3.72 5.39 8 Feb 1996 Adaptec AHA-2920 board | |||
106 | 1.3.85 5.41 4 Apr 1996 | |||
107 | 2.0.12 5.44 8 Aug 1996 Use ID 7 for all PCI cards | |||
108 | ||||
109 | ||||
110 | ||||
111 | REFERENCES USED: | |||
112 | ||||
113 | "TMC-1800 SCSI Chip Specification (FDC-1800T)", Future Domain Corporation, | |||
114 | 1990. | |||
115 | ||||
116 | "Technical Reference Manual: 18C50 SCSI Host Adapter Chip", Future Domain | |||
117 | Corporation, January 1992. | |||
118 | ||||
119 | "LXT SCSI Products: Specifications and OEM Technical Manual (Revision | |||
120 | B/September 1991)", Maxtor Corporation, 1991. | |||
121 | ||||
122 | "7213S product Manual (Revision P3)", Maxtor Corporation, 1992. | |||
123 | ||||
124 | "Draft Proposed American National Standard: Small Computer System | |||
125 | Interface - 2 (SCSI-2)", Global Engineering Documents. (X3T9.2/86-109, | |||
126 | revision 10h, October 17, 1991) | |||
127 | ||||
128 | Private communications, Drew Eckhardt (drew@cs.colorado.edu) and Eric | |||
129 | Youngdale (ericy@cais.com), 1992. | |||
130 | ||||
131 | Private communication, Tuong Le (Future Domain Engineering department), | |||
132 | 1994. (Disk geometry computations for Future Domain BIOS version 3.4, and | |||
133 | TMC-18C30 detection.) | |||
134 | ||||
135 | Hogan, Thom. The Programmer's PC Sourcebook. Microsoft Press, 1988. Page | |||
136 | 60 (2.39: Disk Partition Table Layout). | |||
137 | ||||
138 | "18C30 Technical Reference Manual", Future Domain Corporation, 1993, page | |||
139 | 6-1. | |||
140 | ||||
141 | ||||
142 | ||||
143 | NOTES ON REFERENCES: | |||
144 | ||||
145 | The Maxtor manuals were free. Maxtor telephone technical support is | |||
146 | great! | |||
147 | ||||
148 | The Future Domain manuals were $25 and $35. They document the chip, not | |||
149 | the TMC-16x0 boards, so some information I had to guess at. In 1992, | |||
150 | Future Domain sold DOS BIOS source for $250 and the UN*X driver source was | |||
151 | $750, but these required a non-disclosure agreement, so even if I could | |||
152 | have afforded them, they would *not* have been useful for writing this | |||
153 | publically distributable driver. Future Domain technical support has | |||
154 | provided some information on the phone and have sent a few useful FAXs. | |||
155 | They have been much more helpful since they started to recognize that the | |||
156 | word "Linux" refers to an operating system :-). | |||
157 | ||||
158 | ||||
159 | ||||
160 | ALPHA TESTERS: | |||
161 | ||||
162 | There are many other alpha testers that come and go as the driver | |||
163 | develops. The people listed here were most helpful in times of greatest | |||
164 | need (mostly early on -- I've probably left out a few worthy people in | |||
165 | more recent times): | |||
166 | ||||
167 | Todd Carrico (todd@wutc.wustl.edu), Dan Poirier (poirier@cs.unc.edu ), Ken | |||
168 | Corey (kenc@sol.acs.unt.edu), C. de Bruin (bruin@bruin@sterbbs.nl), Sakari | |||
169 | Aaltonen (sakaria@vipunen.hit.fi), John Rice (rice@xanth.cs.odu.edu), Brad | |||
170 | Yearwood (brad@optilink.com), and Ray Toy (toy@soho.crd.ge.com). | |||
171 | ||||
172 | Special thanks to Tien-Wan Yang (twyang@cs.uh.edu), who graciously lent me | |||
173 | his 18C50-based card for debugging. He is the sole reason that this | |||
174 | driver works with the 18C50 chip. | |||
175 | ||||
176 | Thanks to Dave Newman (dnewman@crl.com) for providing initial patches for | |||
177 | the version 3.4 BIOS. | |||
178 | ||||
179 | Thanks to James T. McKinley (mckinley@msupa.pa.msu.edu) for providing | |||
180 | patches that support the TMC-3260, a PCI bus card with the 36C70 chip. | |||
181 | The 36C70 chip appears to be "completely compatible" with the 18C30 chip. | |||
182 | ||||
183 | Thanks to Eric Kasten (tigger@petroglyph.cl.msu.edu) for providing the | |||
184 | patch for the version 3.5 BIOS. | |||
185 | ||||
186 | Thanks for Stephen Henson (shenson@nyx10.cs.du.edu) for providing the | |||
187 | patch for the Quantum ISA-200S SCSI adapter. | |||
188 | ||||
189 | Thanks to Adam Bowen for the signature to the 1610M/MER/MEX scsi cards, to | |||
190 | Martin Andrews (andrewm@ccfadm.eeg.ccf.org) for the signature to some | |||
191 | random TMC-1680 repackaged by IBM; and to Mintak Ng (mintak@panix.com) for | |||
192 | the version 3.61 BIOS signature. | |||
193 | ||||
194 | Thanks for Mark Singer (elf@netcom.com) and Richard Simpson | |||
195 | (rsimpson@ewrcsdra.demon.co.uk) for more Quantum signatures and detective | |||
196 | work on the Quantum RAM layout. | |||
197 | ||||
198 | Special thanks to James T. McKinley (mckinley@msupa.pa.msu.edu) for | |||
199 | providing patches for proper PCI BIOS32-mediated detection of the TMC-3260 | |||
200 | card (a PCI bus card with the 36C70 chip). Please send James PCI-related | |||
201 | bug reports. | |||
202 | ||||
203 | Thanks to Tom Cavin (tec@usa1.com) for preliminary command-line option | |||
204 | patches. | |||
205 | ||||
206 | All of the alpha testers deserve much thanks. | |||
207 | ||||
208 | ||||
209 | ||||
210 | NOTES ON USER DEFINABLE OPTIONS: | |||
211 | ||||
212 | DEBUG: This turns on the printing of various debug information. | |||
213 | ||||
214 | ENABLE_PARITY: This turns on SCSI parity checking. With the current | |||
215 | driver, all attached devices must support SCSI parity. If none of your | |||
216 | devices support parity, then you can probably get the driver to work by | |||
217 | turning this option off. I have no way of testing this, however, and it | |||
218 | would appear that no one ever uses this option. | |||
219 | ||||
220 | FIFO_COUNT: The host adapter has an 8K cache (host adapters based on the | |||
221 | 18C30 chip have a 2k cache). When this many 512 byte blocks are filled by | |||
222 | the SCSI device, an interrupt will be raised. Therefore, this could be as | |||
223 | low as 0, or as high as 16. Note, however, that values which are too high | |||
224 | or too low seem to prevent any interrupts from occurring, and thereby lock | |||
225 | up the machine. I have found that 2 is a good number, but throughput may | |||
226 | be increased by changing this value to values which are close to 2. | |||
227 | Please let me know if you try any different values. | |||
228 | ||||
229 | DO_DETECT: This activates some old scan code which was needed before the | |||
230 | high level drivers got fixed. If you are having trouble with the driver, | |||
231 | turning this on should not hurt, and might help. Please let me know if | |||
232 | this is the case, since this code will be removed from future drivers. | |||
233 | ||||
234 | RESELECTION: This is no longer an option, since I gave up trying to | |||
235 | implement it in version 4.x of this driver. It did not improve | |||
236 | performance at all and made the driver unstable (because I never found one | |||
237 | of the two race conditions which were introduced by the multiple | |||
238 | outstanding command code). The instability seems a very high price to pay | |||
239 | just so that you don't have to wait for the tape to rewind. If you want | |||
240 | this feature implemented, send me patches. I'll be happy to send a copy | |||
241 | of my (broken) driver to anyone who would like to see a copy. | |||
242 | ||||
243 | **************************************************************************/ | |||
244 | ||||
245 | #ifdef PCMCIA | |||
246 | #define MODULE | |||
247 | #endif | |||
248 | ||||
249 | #ifdef MODULE | |||
250 | #include <linux/module.h> | |||
251 | #endif | |||
252 | ||||
253 | #ifdef PCMCIA | |||
254 | #undef MODULE | |||
255 | #endif | |||
256 | ||||
257 | #include <linux/sched.h> | |||
258 | #include <asm/io.h> | |||
259 | #include <linux/blk.h> | |||
260 | #include "scsi.h" | |||
261 | #include "hosts.h" | |||
262 | #include "fdomain.h" | |||
263 | #include <asm/system.h> | |||
264 | #include <linux/errno.h> | |||
265 | #include <linux/string.h> | |||
266 | #include <linux/ioport.h> | |||
267 | #include <linux/proc_fs.h> | |||
268 | #include <linux/bios32.h> | |||
269 | #include <linux/pci.h> | |||
270 | #include <linux/stat.h> | |||
271 | ||||
272 | #include <linux/config.h> /* for CONFIG_PCI */ | |||
273 | ||||
274 | struct proc_dir_entry proc_scsi_fdomain = { | |||
275 | PROC_SCSI_FDOMAIN, 7, "fdomain", | |||
276 | S_IFDIR0040000 | S_IRUGO(00400|00040|00004) | S_IXUGO(00100|00010|00001), 2 | |||
277 | }; | |||
278 | ||||
279 | #define VERSION"$Revision: 1.1 $" "$Revision: 1.1 $" | |||
280 | ||||
281 | /* START OF USER DEFINABLE OPTIONS */ | |||
282 | ||||
283 | #define DEBUG1 1 /* Enable debugging output */ | |||
284 | #define ENABLE_PARITY1 1 /* Enable SCSI Parity */ | |||
285 | #define FIFO_COUNT2 2 /* Number of 512 byte blocks before INTR */ | |||
286 | #define DO_DETECT0 0 /* Do device detection here (see scsi.c) */ | |||
287 | ||||
288 | /* END OF USER DEFINABLE OPTIONS */ | |||
289 | ||||
290 | #if DEBUG1 | |||
291 | #define EVERY_ACCESS0 0 /* Write a line on every scsi access */ | |||
292 | #define ERRORS_ONLY1 1 /* Only write a line if there is an error */ | |||
293 | #define DEBUG_DETECT0 0 /* Debug fdomain_16x0_detect() */ | |||
294 | #define DEBUG_MESSAGES1 1 /* Debug MESSAGE IN phase */ | |||
295 | #define DEBUG_ABORT1 1 /* Debug abort() routine */ | |||
296 | #define DEBUG_RESET1 1 /* Debug reset() routine */ | |||
297 | #define DEBUG_RACE1 1 /* Debug interrupt-driven race condition */ | |||
298 | #else | |||
299 | #define EVERY_ACCESS0 0 /* LEAVE THESE ALONE--CHANGE THE ONES ABOVE */ | |||
300 | #define ERRORS_ONLY1 0 | |||
301 | #define DEBUG_DETECT0 0 | |||
302 | #define DEBUG_MESSAGES1 0 | |||
303 | #define DEBUG_ABORT1 0 | |||
304 | #define DEBUG_RESET1 0 | |||
305 | #define DEBUG_RACE1 0 | |||
306 | #endif | |||
307 | ||||
308 | /* Errors are reported on the line, so we don't need to report them again */ | |||
309 | #if EVERY_ACCESS0 | |||
310 | #undef ERRORS_ONLY1 | |||
311 | #define ERRORS_ONLY1 0 | |||
312 | #endif | |||
313 | ||||
314 | #if ENABLE_PARITY1 | |||
315 | #define PARITY_MASK0x08 0x08 | |||
316 | #else | |||
317 | #define PARITY_MASK0x08 0x00 | |||
318 | #endif | |||
319 | ||||
320 | enum chip_type { | |||
321 | unknown = 0x00, | |||
322 | tmc1800 = 0x01, | |||
323 | tmc18c50 = 0x02, | |||
324 | tmc18c30 = 0x03, | |||
325 | }; | |||
326 | ||||
327 | enum { | |||
328 | in_arbitration = 0x02, | |||
329 | in_selection = 0x04, | |||
330 | in_other = 0x08, | |||
331 | disconnect = 0x10, | |||
332 | aborted = 0x20, | |||
333 | sent_ident = 0x40, | |||
334 | }; | |||
335 | ||||
336 | enum in_port_type { | |||
337 | Read_SCSI_Data = 0, | |||
338 | SCSI_Status = 1, | |||
339 | TMC_Status = 2, | |||
340 | FIFO_Status = 3, /* tmc18c50/tmc18c30 only */ | |||
341 | Interrupt_Cond = 4, /* tmc18c50/tmc18c30 only */ | |||
342 | LSB_ID_Code = 5, | |||
343 | MSB_ID_Code = 6, | |||
344 | Read_Loopback = 7, | |||
345 | SCSI_Data_NoACK = 8, | |||
346 | Interrupt_Status = 9, | |||
347 | Configuration1 = 10, | |||
348 | Configuration2 = 11, /* tmc18c50/tmc18c30 only */ | |||
349 | Read_FIFO = 12, | |||
350 | FIFO_Data_Count = 14 | |||
351 | }; | |||
352 | ||||
353 | enum out_port_type { | |||
354 | Write_SCSI_Data = 0, | |||
355 | SCSI_Cntl = 1, | |||
356 | Interrupt_Cntl = 2, | |||
357 | SCSI_Mode_Cntl = 3, | |||
358 | TMC_Cntl = 4, | |||
359 | Memory_Cntl = 5, /* tmc18c50/tmc18c30 only */ | |||
360 | Write_Loopback = 7, | |||
361 | IO_Control = 11, /* tmc18c30 only */ | |||
362 | Write_FIFO = 12 | |||
363 | }; | |||
364 | ||||
365 | static int port_base = 0; | |||
366 | static void *bios_base = NULL((void *) 0); | |||
367 | static int bios_major = 0; | |||
368 | static int bios_minor = 0; | |||
369 | static int PCI_bus = 0; | |||
370 | static int Quantum = 0; /* Quantum board variant */ | |||
371 | static int interrupt_level = 0; | |||
372 | static volatile int in_command = 0; | |||
373 | static Scsi_Cmnd *current_SC = NULL((void *) 0); | |||
374 | static enum chip_type chip = unknown; | |||
375 | static int adapter_mask = 0; | |||
376 | static int this_id = 0; | |||
377 | static int setup_called = 0; | |||
378 | ||||
379 | #if DEBUG_RACE1 | |||
380 | static volatile int in_interrupt_flag = 0; | |||
381 | #endif | |||
382 | ||||
383 | static int SCSI_Mode_Cntl_port; | |||
384 | static int FIFO_Data_Count_port; | |||
385 | static int Interrupt_Cntl_port; | |||
386 | static int Interrupt_Status_port; | |||
387 | static int Read_FIFO_port; | |||
388 | static int Read_SCSI_Data_port; | |||
389 | static int SCSI_Cntl_port; | |||
390 | static int SCSI_Data_NoACK_port; | |||
391 | static int SCSI_Status_port; | |||
392 | static int TMC_Cntl_port; | |||
393 | static int TMC_Status_port; | |||
394 | static int Write_FIFO_port; | |||
395 | static int Write_SCSI_Data_port; | |||
396 | ||||
397 | static int FIFO_Size = 0x2000; /* 8k FIFO for | |||
398 | pre-tmc18c30 chips */ | |||
399 | ||||
400 | extern void fdomain_16x0_intr( int irq, void *dev_id, struct pt_regs * regs ); | |||
401 | ||||
402 | static void *addresses[] = { | |||
403 | (void *)0xc8000, | |||
404 | (void *)0xca000, | |||
405 | (void *)0xce000, | |||
406 | (void *)0xde000, | |||
407 | (void *)0xcc000, /* Extra addresses for PCI boards */ | |||
408 | (void *)0xd0000, | |||
409 | (void *)0xe0000, | |||
410 | }; | |||
411 | #define ADDRESS_COUNT(sizeof( addresses ) / sizeof( unsigned )) (sizeof( addresses ) / sizeof( unsigned )) | |||
412 | ||||
413 | static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 }; | |||
414 | #define PORT_COUNT(sizeof( ports ) / sizeof( unsigned short )) (sizeof( ports ) / sizeof( unsigned short )) | |||
415 | ||||
416 | static unsigned short ints[] = { 3, 5, 10, 11, 12, 14, 15, 0 }; | |||
417 | ||||
418 | /* | |||
419 | ||||
420 | READ THIS BEFORE YOU ADD A SIGNATURE! | |||
421 | ||||
422 | READING THIS SHORT NOTE CAN SAVE YOU LOTS OF TIME! | |||
423 | ||||
424 | READ EVERY WORD, ESPECIALLY THE WORD *NOT* | |||
425 | ||||
426 | This driver works *ONLY* for Future Domain cards using the TMC-1800, | |||
427 | TMC-18C50, or TMC-18C30 chip. This includes models TMC-1650, 1660, 1670, | |||
428 | and 1680. | |||
429 | ||||
430 | The following BIOS signature signatures are for boards which do *NOT* | |||
431 | work with this driver (these TMC-8xx and TMC-9xx boards may work with the | |||
432 | Seagate driver): | |||
433 | ||||
434 | FUTURE DOMAIN CORP. (C) 1986-1988 V4.0I 03/16/88 | |||
435 | FUTURE DOMAIN CORP. (C) 1986-1989 V5.0C2/14/89 | |||
436 | FUTURE DOMAIN CORP. (C) 1986-1989 V6.0A7/28/89 | |||
437 | FUTURE DOMAIN CORP. (C) 1986-1990 V6.0105/31/90 | |||
438 | FUTURE DOMAIN CORP. (C) 1986-1990 V6.0209/18/90 | |||
439 | FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90 | |||
440 | FUTURE DOMAIN CORP. (C) 1992 V8.00.004/02/92 | |||
441 | ||||
442 | */ | |||
443 | ||||
444 | struct signature { | |||
445 | const char *signature; | |||
446 | int sig_offset; | |||
447 | int sig_length; | |||
448 | int major_bios_version; | |||
449 | int minor_bios_version; | |||
450 | int flag; /* 1 == PCI_bus, 2 == ISA_200S, 3 == ISA_250MG, 4 == ISA_200S */ | |||
451 | } signatures[] = { | |||
452 | /* 1 2 3 4 5 6 */ | |||
453 | /* 123456789012345678901234567890123456789012345678901234567890 */ | |||
454 | { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89", 5, 50, 2, 0, 0 }, | |||
455 | { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V1.07/28/89", 5, 50, 2, 0, 0 }, | |||
456 | { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89", 72, 50, 2, 0, 2 }, | |||
457 | { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.0", 73, 43, 2, 0, 3 }, | |||
458 | { "FUTURE DOMAIN CORP. (C) 1991 1800-V2.0.", 72, 39, 2, 0, 4 }, | |||
459 | { "FUTURE DOMAIN CORP. (C) 1992 V3.00.004/02/92", 5, 44, 3, 0, 0 }, | |||
460 | { "FUTURE DOMAIN TMC-18XX (C) 1993 V3.203/12/93", 5, 44, 3, 2, 0 }, | |||
461 | { "IBM F1 P2 BIOS v1.0104/29/93", 5, 28, 3, -1, 0 }, | |||
462 | { "Future Domain Corp. V1.0008/18/93", 5, 33, 3, 4, 0 }, | |||
463 | { "Future Domain Corp. V1.0008/18/93", 26, 33, 3, 4, 1 }, | |||
464 | { "Adaptec AHA-2920 PCI-SCSI Card", 42, 31, 3, -1, 1 }, | |||
465 | { "IBM F1 P264/32", 5, 14, 3, -1, 1 }, | |||
466 | /* This next signature may not be a 3.5 bios */ | |||
467 | { "Future Domain Corp. V2.0108/18/93", 5, 33, 3, 5, 0 }, | |||
468 | { "FUTURE DOMAIN CORP. V3.5008/18/93", 5, 34, 3, 5, 0 }, | |||
469 | { "FUTURE DOMAIN 18c30/18c50/1800 (C) 1994 V3.5", 5, 44, 3, 5, 0 }, | |||
470 | { "FUTURE DOMAIN CORP. V3.6008/18/93", 5, 34, 3, 6, 0 }, | |||
471 | { "FUTURE DOMAIN CORP. V3.6108/18/93", 5, 34, 3, 6, 0 }, | |||
472 | { "FUTURE DOMAIN TMC-18XX", 5, 22, -1, -1, 0 }, | |||
473 | ||||
474 | /* READ NOTICE ABOVE *BEFORE* YOU WASTE YOUR TIME ADDING A SIGNATURE | |||
475 | Also, fix the disk geometry code for your signature and send your | |||
476 | changes for faith@cs.unc.edu. Above all, do *NOT* change any old | |||
477 | signatures! | |||
478 | ||||
479 | Note that the last line will match a "generic" 18XX bios. Because | |||
480 | Future Domain has changed the host SCSI ID and/or the location of the | |||
481 | geometry information in the on-board RAM area for each of the first | |||
482 | three BIOS's, it is still important to enter a fully qualified | |||
483 | signature in the table for any new BIOS's (after the host SCSI ID and | |||
484 | geometry location are verified). */ | |||
485 | }; | |||
486 | ||||
487 | #define SIGNATURE_COUNT(sizeof( signatures ) / sizeof( struct signature )) (sizeof( signatures ) / sizeof( struct signature )) | |||
488 | ||||
489 | static void print_banner( struct Scsi_Host *shpnt ) | |||
490 | { | |||
491 | if (!shpnt) return; /* This won't ever happen */ | |||
492 | ||||
493 | if (bios_major < 0 && bios_minor < 0) { | |||
494 | printk( "scsi%d <fdomain>: No BIOS; using scsi id %d\n", | |||
495 | shpnt->host_no, shpnt->this_id ); | |||
496 | } else { | |||
497 | printk( "scsi%d <fdomain>: BIOS version ", shpnt->host_no ); | |||
498 | ||||
499 | if (bios_major >= 0) printk( "%d.", bios_major ); | |||
500 | else printk( "?." ); | |||
501 | ||||
502 | if (bios_minor >= 0) printk( "%d", bios_minor ); | |||
503 | else printk( "?." ); | |||
504 | ||||
505 | printk( " at 0x%x using scsi id %d\n", | |||
506 | (unsigned)bios_base, shpnt->this_id ); | |||
507 | } | |||
508 | ||||
509 | /* If this driver works for later FD PCI | |||
510 | boards, we will have to modify banner | |||
511 | for additional PCI cards, but for now if | |||
512 | it's PCI it's a TMC-3260 - JTM */ | |||
513 | printk( "scsi%d <fdomain>: %s chip at 0x%x irq ", | |||
514 | shpnt->host_no, | |||
515 | chip == tmc1800 ? "TMC-1800" | |||
516 | : (chip == tmc18c50 ? "TMC-18C50" | |||
517 | : (chip == tmc18c30 ? | |||
518 | (PCI_bus ? "TMC-36C70 (PCI bus)" : "TMC-18C30") | |||
519 | : "Unknown")), | |||
520 | port_base ); | |||
521 | ||||
522 | if (interrupt_level) printk( "%d", interrupt_level ); | |||
523 | else printk( "<none>" ); | |||
524 | ||||
525 | printk( "\n" ); | |||
526 | } | |||
527 | ||||
528 | void fdomain_setup( char *str, int *ints ) | |||
529 | { | |||
530 | if (setup_called++ || ints[0] < 2 || ints[0] > 3) { | |||
531 | printk( "fdomain: usage: fdomain=<PORT_BASE>,<IRQ>[,<ADAPTER_ID>]\n" ); | |||
532 | printk( "fdomain: bad LILO parameters?\n" ); | |||
533 | } | |||
534 | ||||
535 | port_base = ints[0] >= 1 ? ints[1] : 0; | |||
536 | interrupt_level = ints[0] >= 2 ? ints[2] : 0; | |||
537 | this_id = ints[0] >= 3 ? ints[3] : 0; | |||
538 | ||||
539 | bios_major = bios_minor = -1; /* Use geometry for BIOS version >= 3.4 */ | |||
540 | } | |||
541 | ||||
542 | ||||
543 | static void do_pause( unsigned amount ) /* Pause for amount*10 milliseconds */ | |||
544 | { | |||
545 | unsigned long the_time = jiffies + amount; /* 0.01 seconds per jiffy */ | |||
546 | ||||
547 | while (jiffies < the_time); | |||
548 | } | |||
549 | ||||
550 | inlineinline __attribute__((always_inline)) static void fdomain_make_bus_idle( void ) | |||
551 | { | |||
552 | outb( 0, SCSI_Cntl_port )((__builtin_constant_p((SCSI_Cntl_port)) && (SCSI_Cntl_port ) < 256) ? __outbc((0),(SCSI_Cntl_port)) : __outb((0),(SCSI_Cntl_port ))); | |||
553 | outb( 0, SCSI_Mode_Cntl_port )((__builtin_constant_p((SCSI_Mode_Cntl_port)) && (SCSI_Mode_Cntl_port ) < 256) ? __outbc((0),(SCSI_Mode_Cntl_port)) : __outb((0) ,(SCSI_Mode_Cntl_port))); | |||
554 | if (chip == tmc18c50 || chip == tmc18c30) | |||
555 | outb( 0x21 | PARITY_MASK, TMC_Cntl_port )((__builtin_constant_p((TMC_Cntl_port)) && (TMC_Cntl_port ) < 256) ? __outbc((0x21 | 0x08),(TMC_Cntl_port)) : __outb ((0x21 | 0x08),(TMC_Cntl_port))); /* Clear forced intr. */ | |||
556 | else | |||
557 | outb( 0x01 | PARITY_MASK, TMC_Cntl_port )((__builtin_constant_p((TMC_Cntl_port)) && (TMC_Cntl_port ) < 256) ? __outbc((0x01 | 0x08),(TMC_Cntl_port)) : __outb ((0x01 | 0x08),(TMC_Cntl_port))); | |||
558 | } | |||
559 | ||||
560 | static int fdomain_is_valid_port( int port ) | |||
561 | { | |||
562 | #if DEBUG_DETECT0 | |||
563 | printk( " (%x%x),", | |||
564 | inb( port + MSB_ID_Code )((__builtin_constant_p((port + MSB_ID_Code)) && (port + MSB_ID_Code) < 256) ? __inbc(port + MSB_ID_Code) : __inb (port + MSB_ID_Code)), inb( port + LSB_ID_Code )((__builtin_constant_p((port + LSB_ID_Code)) && (port + LSB_ID_Code) < 256) ? __inbc(port + LSB_ID_Code) : __inb (port + LSB_ID_Code)) ); | |||
565 | #endif | |||
566 | ||||
567 | /* The MCA ID is a unique id for each MCA compatible board. We | |||
568 | are using ISA boards, but Future Domain provides the MCA ID | |||
569 | anyway. We can use this ID to ensure that this is a Future | |||
570 | Domain TMC-1660/TMC-1680. | |||
571 | */ | |||
572 | ||||
573 | if (inb( port + LSB_ID_Code )((__builtin_constant_p((port + LSB_ID_Code)) && (port + LSB_ID_Code) < 256) ? __inbc(port + LSB_ID_Code) : __inb (port + LSB_ID_Code)) != 0xe9) { /* test for 0x6127 id */ | |||
574 | if (inb( port + LSB_ID_Code )((__builtin_constant_p((port + LSB_ID_Code)) && (port + LSB_ID_Code) < 256) ? __inbc(port + LSB_ID_Code) : __inb (port + LSB_ID_Code)) != 0x27) return 0; | |||
575 | if (inb( port + MSB_ID_Code )((__builtin_constant_p((port + MSB_ID_Code)) && (port + MSB_ID_Code) < 256) ? __inbc(port + MSB_ID_Code) : __inb (port + MSB_ID_Code)) != 0x61) return 0; | |||
576 | chip = tmc1800; | |||
577 | } else { /* test for 0xe960 id */ | |||
578 | if (inb( port + MSB_ID_Code )((__builtin_constant_p((port + MSB_ID_Code)) && (port + MSB_ID_Code) < 256) ? __inbc(port + MSB_ID_Code) : __inb (port + MSB_ID_Code)) != 0x60) return 0; | |||
579 | chip = tmc18c50; | |||
580 | ||||
581 | #if 0 | |||
582 | ||||
583 | /* Try to toggle 32-bit mode. This only | |||
584 | works on an 18c30 chip. (User reports | |||
585 | say this works, so we should switch to | |||
586 | it in the near future.) */ | |||
587 | ||||
588 | outb( 0x80, port + IO_Control )((__builtin_constant_p((port + IO_Control)) && (port + IO_Control) < 256) ? __outbc((0x80),(port + IO_Control)) : __outb((0x80),(port + IO_Control))); | |||
589 | if ((inb( port + Configuration2 )((__builtin_constant_p((port + Configuration2)) && (port + Configuration2) < 256) ? __inbc(port + Configuration2) : __inb(port + Configuration2)) & 0x80) == 0x80) { | |||
590 | outb( 0x00, port + IO_Control )((__builtin_constant_p((port + IO_Control)) && (port + IO_Control) < 256) ? __outbc((0x00),(port + IO_Control)) : __outb((0x00),(port + IO_Control))); | |||
591 | if ((inb( port + Configuration2 )((__builtin_constant_p((port + Configuration2)) && (port + Configuration2) < 256) ? __inbc(port + Configuration2) : __inb(port + Configuration2)) & 0x80) == 0x00) { | |||
592 | chip = tmc18c30; | |||
593 | FIFO_Size = 0x800; /* 2k FIFO */ | |||
594 | } | |||
595 | } | |||
596 | #else | |||
597 | ||||
598 | /* That should have worked, but appears to | |||
599 | have problems. Let's assume it is an | |||
600 | 18c30 if the RAM is disabled. */ | |||
601 | ||||
602 | if (inb( port + Configuration2 )((__builtin_constant_p((port + Configuration2)) && (port + Configuration2) < 256) ? __inbc(port + Configuration2) : __inb(port + Configuration2)) & 0x02) { | |||
603 | chip = tmc18c30; | |||
604 | FIFO_Size = 0x800; /* 2k FIFO */ | |||
605 | } | |||
606 | #endif | |||
607 | /* If that failed, we are an 18c50. */ | |||
608 | } | |||
609 | ||||
610 | return 1; | |||
611 | } | |||
612 | ||||
613 | static int fdomain_test_loopback( void ) | |||
614 | { | |||
615 | int i; | |||
616 | int result; | |||
617 | ||||
618 | for (i = 0; i < 255; i++) { | |||
619 | outb( i, port_base + Write_Loopback )((__builtin_constant_p((port_base + Write_Loopback)) && (port_base + Write_Loopback) < 256) ? __outbc((i),(port_base + Write_Loopback)) : __outb((i),(port_base + Write_Loopback) )); | |||
620 | result = inb( port_base + Read_Loopback )((__builtin_constant_p((port_base + Read_Loopback)) && (port_base + Read_Loopback) < 256) ? __inbc(port_base + Read_Loopback ) : __inb(port_base + Read_Loopback)); | |||
621 | if (i != result) | |||
622 | return 1; | |||
623 | } | |||
624 | return 0; | |||
625 | } | |||
626 | ||||
627 | /* fdomain_get_irq assumes that we have a valid MCA ID for a | |||
628 | TMC-1660/TMC-1680 Future Domain board. Now, check to be sure the | |||
629 | bios_base matches these ports. If someone was unlucky enough to have | |||
630 | purchased more than one Future Domain board, then they will have to | |||
631 | modify this code, as we only detect one board here. [The one with the | |||
632 | lowest bios_base.] | |||
633 | ||||
634 | Note that this routine is only used for systems without a PCI BIOS32 | |||
635 | (e.g., ISA bus). For PCI bus systems, this routine will likely fail | |||
636 | unless one of the IRQs listed in the ints array is used by the board. | |||
637 | Sometimes it is possible to use the computer's BIOS setup screen to | |||
638 | configure a PCI system so that one of these IRQs will be used by the | |||
639 | Future Domain card. */ | |||
640 | ||||
641 | static int fdomain_get_irq( int base ) | |||
642 | { | |||
643 | int options = inb( base + Configuration1 )((__builtin_constant_p((base + Configuration1)) && (base + Configuration1) < 256) ? __inbc(base + Configuration1) : __inb(base + Configuration1)); | |||
644 | ||||
645 | #if DEBUG_DETECT0 | |||
646 | printk( " Options = %x\n", options ); | |||
647 | #endif | |||
648 | ||||
649 | /* Check for board with lowest bios_base -- | |||
650 | this isn't valid for the 18c30 or for | |||
651 | boards on the PCI bus, so just assume we | |||
652 | have the right board. */ | |||
653 | ||||
654 | if (chip != tmc18c30 | |||
655 | && !PCI_bus | |||
656 | && addresses[ (options & 0xc0) >> 6 ] != bios_base) return 0; | |||
657 | ||||
658 | return ints[ (options & 0x0e) >> 1 ]; | |||
659 | } | |||
660 | ||||
661 | static int fdomain_isa_detect( int *irq, int *iobase ) | |||
662 | { | |||
663 | int i; | |||
664 | int base; | |||
665 | int flag = 0; | |||
666 | ||||
667 | if (bios_major == 2) { | |||
668 | /* The TMC-1660/TMC-1680 has a RAM area just after the BIOS ROM. | |||
669 | Assuming the ROM is enabled (otherwise we wouldn't have been | |||
670 | able to read the ROM signature :-), then the ROM sets up the | |||
671 | RAM area with some magic numbers, such as a list of port | |||
672 | base addresses and a list of the disk "geometry" reported to | |||
673 | DOS (this geometry has nothing to do with physical geometry). | |||
674 | */ | |||
675 | ||||
676 | switch (Quantum) { | |||
677 | case 2: /* ISA_200S */ | |||
678 | case 3: /* ISA_250MG */ | |||
679 | base = *((char *)bios_base + 0x1fa2) | |||
680 | + (*((char *)bios_base + 0x1fa3) << 8); | |||
681 | break; | |||
682 | case 4: /* ISA_200S (another one) */ | |||
683 | base = *((char *)bios_base + 0x1fa3) | |||
684 | + (*((char *)bios_base + 0x1fa4) << 8); | |||
685 | break; | |||
686 | default: | |||
687 | base = *((char *)bios_base + 0x1fcc) | |||
688 | + (*((char *)bios_base + 0x1fcd) << 8); | |||
689 | break; | |||
690 | } | |||
691 | ||||
692 | #if DEBUG_DETECT0 | |||
693 | printk( " %x,", base ); | |||
694 | #endif | |||
695 | ||||
696 | for (flag = 0, i = 0; !flag && i < PORT_COUNT(sizeof( ports ) / sizeof( unsigned short )); i++) { | |||
697 | if (base == ports[i]) | |||
698 | ++flag; | |||
699 | } | |||
700 | ||||
701 | if (flag && fdomain_is_valid_port( base )) { | |||
702 | *irq = fdomain_get_irq( base ); | |||
703 | *iobase = base; | |||
704 | return 1; | |||
705 | } | |||
706 | ||||
707 | /* This is a bad sign. It usually means that someone patched the | |||
708 | BIOS signature list (the signatures variable) to contain a BIOS | |||
709 | signature for a board *OTHER THAN* the TMC-1660/TMC-1680. */ | |||
710 | ||||
711 | #if DEBUG_DETECT0 | |||
712 | printk( " RAM FAILED, " ); | |||
713 | #endif | |||
714 | } | |||
715 | ||||
716 | /* Anyway, the alternative to finding the address in the RAM is to just | |||
717 | search through every possible port address for one that is attached | |||
718 | to the Future Domain card. Don't panic, though, about reading all | |||
719 | these random port addresses -- there are rumors that the Future | |||
720 | Domain BIOS does something very similar. | |||
721 | ||||
722 | Do not, however, check ports which the kernel knows are being used by | |||
723 | another driver. */ | |||
724 | ||||
725 | for (i = 0; i < PORT_COUNT(sizeof( ports ) / sizeof( unsigned short )); i++) { | |||
726 | base = ports[i]; | |||
727 | if (check_region( base, 0x10 )) { | |||
728 | #if DEBUG_DETECT0 | |||
729 | printk( " (%x inuse),", base ); | |||
730 | #endif | |||
731 | continue; | |||
732 | } | |||
733 | #if DEBUG_DETECT0 | |||
734 | printk( " %x,", base ); | |||
735 | #endif | |||
736 | if ((flag = fdomain_is_valid_port( base ))) break; | |||
737 | } | |||
738 | ||||
739 | if (!flag) return 0; /* iobase not found */ | |||
740 | ||||
741 | *irq = fdomain_get_irq( base ); | |||
742 | *iobase = base; | |||
743 | ||||
744 | return 1; /* success */ | |||
745 | } | |||
746 | ||||
747 | static int fdomain_pci_nobios_detect( int *irq, int *iobase ) | |||
748 | { | |||
749 | int i; | |||
750 | int flag = 0; | |||
751 | ||||
752 | /* The proper way of doing this is to use ask the PCI bus for the device | |||
753 | IRQ and interrupt level. But we can't do that if PCI BIOS32 support | |||
754 | isn't compiled into the kernel, or if a PCI BIOS32 isn't present. | |||
755 | ||||
756 | Instead, we scan down a bunch of addresses (Future Domain tech | |||
757 | support says we will probably find the address before we get to | |||
758 | 0xf800). This works fine on some systems -- other systems may have | |||
759 | to scan more addresses. If you have to modify this section for your | |||
760 | installation, please send mail to faith@cs.unc.edu. */ | |||
761 | ||||
762 | for (i = 0xfff8; i > 0xe000; i -= 8) { | |||
763 | if (check_region( i, 0x10 )) { | |||
764 | #if DEBUG_DETECT0 | |||
765 | printk( " (%x inuse)," , i ); | |||
766 | #endif | |||
767 | continue; | |||
768 | } | |||
769 | if ((flag = fdomain_is_valid_port( i ))) break; | |||
770 | } | |||
771 | ||||
772 | if (!flag) return 0; /* iobase not found */ | |||
773 | ||||
774 | *irq = fdomain_get_irq( i ); | |||
775 | *iobase = i; | |||
776 | ||||
777 | return 1; /* success */ | |||
778 | } | |||
779 | ||||
780 | /* PCI detection function: int fdomain_pci_bios_detect(int* irq, int* | |||
781 | iobase) This function gets the Interrupt Level and I/O base address from | |||
782 | the PCI configuration registers. The I/O base address is masked with | |||
783 | 0xfff8 since on my card the address read from the PCI config registers | |||
784 | is off by one from the actual I/O base address necessary for accessing | |||
785 | the status and control registers on the card (PCI config register gives | |||
786 | 0xf801, actual address is 0xf800). This is likely a bug in the FD | |||
787 | config code that writes to the PCI registers, however using a mask | |||
788 | should be safe since I think the scan done by the card to determine the | |||
789 | I/O base is done in increments of 8 (i.e., 0xf800, 0xf808, ...), at | |||
790 | least the old scan code we used to use to get the I/O base did... Also, | |||
791 | the device ID from the PCI config registers is 0x0 and should be 0x60e9 | |||
792 | as it is in the status registers (offset 5 from I/O base). If this is | |||
793 | changed in future hardware/BIOS changes it will need to be fixed in this | |||
794 | detection function. Comments, bug reports, etc... on this function | |||
795 | should be sent to mckinley@msupa.pa.msu.edu - James T. McKinley. */ | |||
796 | ||||
797 | #ifdef CONFIG_PCI1 | |||
798 | static int fdomain_pci_bios_detect( int *irq, int *iobase ) | |||
799 | { | |||
800 | int error; | |||
801 | unsigned char pci_bus, pci_dev_fn; /* PCI bus & device function */ | |||
802 | unsigned char pci_irq; /* PCI interrupt line */ | |||
803 | unsigned int pci_base; /* PCI I/O base address */ | |||
804 | unsigned short pci_vendor, pci_device; /* PCI vendor & device IDs */ | |||
805 | ||||
806 | /* If the PCI BIOS doesn't exist, use the old-style detection routines. | |||
807 | Otherwise, get the I/O base address and interrupt from the PCI config | |||
808 | registers. */ | |||
809 | ||||
810 | if (!pcibios_present()) return fdomain_pci_nobios_detect( irq, iobase ); | |||
811 | ||||
812 | #if DEBUG_DETECT0 | |||
813 | /* Tell how to print a list of the known PCI devices from bios32 and | |||
814 | list vendor and device IDs being used if in debug mode. */ | |||
815 | ||||
816 | printk( "\nINFO: cat /proc/pci to see list of PCI devices from bios32\n" ); | |||
817 | printk( "\nTMC-3260 detect:" | |||
818 | " Using PCI Vendor ID: 0x%x, PCI Device ID: 0x%x\n", | |||
819 | PCI_VENDOR_ID_FD0x1036, | |||
820 | PCI_DEVICE_ID_FD_36C700x0000 ); | |||
821 | #endif | |||
822 | ||||
823 | /* We will have to change this if more than 1 PCI bus is present and the | |||
824 | FD scsi host is not on the first bus (i.e., a PCI to PCI bridge, | |||
825 | which is not supported by bios32 right now anyway). This should | |||
826 | probably be done by a call to pcibios_find_device but I can't get it | |||
827 | to work... Also the device ID reported from the PCI config registers | |||
828 | does not match the device ID quoted in the tech manual or available | |||
829 | from offset 5 from the I/O base address. It should be 0x60E9, but it | |||
830 | is 0x0 if read from the PCI config registers. I guess the FD folks | |||
831 | neglected to write it to the PCI registers... This loop is necessary | |||
832 | to get the device function (at least until someone can get | |||
833 | pcibios_find_device to work, I cannot but 53c7,8xx.c uses it...). */ | |||
834 | ||||
835 | pci_bus = 0; | |||
836 | ||||
837 | for (pci_dev_fn = 0x0; pci_dev_fn < 0xff; pci_dev_fn++) { | |||
838 | pcibios_read_config_word( pci_bus, | |||
839 | pci_dev_fn, | |||
840 | PCI_VENDOR_ID0x00, | |||
841 | &pci_vendor ); | |||
842 | ||||
843 | if (pci_vendor == PCI_VENDOR_ID_FD0x1036) { | |||
844 | pcibios_read_config_word( pci_bus, | |||
845 | pci_dev_fn, | |||
846 | PCI_DEVICE_ID0x02, | |||
847 | &pci_device ); | |||
848 | ||||
849 | if (pci_device == PCI_DEVICE_ID_FD_36C700x0000) { | |||
850 | /* Break out once we have the correct device. If other FD | |||
851 | PCI devices are added to this driver we will need to add | |||
852 | an or of the other PCI_DEVICE_ID_FD_XXXXX's here. */ | |||
853 | break; | |||
854 | } else { | |||
855 | /* If we can't find an FD scsi card we give up. */ | |||
856 | return 0; | |||
857 | } | |||
858 | } | |||
859 | } | |||
860 | ||||
861 | #if DEBUG_DETECT0 | |||
862 | printk( "Future Domain 36C70 : at PCI bus %u, device %u, function %u\n", | |||
863 | pci_bus, | |||
864 | (pci_dev_fn & 0xf8) >> 3, | |||
865 | pci_dev_fn & 7 ); | |||
866 | #endif | |||
867 | ||||
868 | /* We now have the appropriate device function for the FD board so we | |||
869 | just read the PCI config info from the registers. */ | |||
870 | ||||
871 | if ((error = pcibios_read_config_dword( pci_bus, | |||
872 | pci_dev_fn, | |||
873 | PCI_BASE_ADDRESS_00x10, | |||
874 | &pci_base )) | |||
875 | || (error = pcibios_read_config_byte( pci_bus, | |||
876 | pci_dev_fn, | |||
877 | PCI_INTERRUPT_LINE0x3c, | |||
878 | &pci_irq ))) { | |||
879 | printk ( "PCI ERROR: Future Domain 36C70 not initializing" | |||
880 | " due to error reading configuration space\n" ); | |||
881 | return 0; | |||
882 | } else { | |||
883 | #if DEBUG_DETECT0 | |||
884 | printk( "TMC-3260 PCI: IRQ = %u, I/O base = 0x%lx\n", | |||
885 | pci_irq, pci_base ); | |||
886 | #endif | |||
887 | ||||
888 | /* Now we have the I/O base address and interrupt from the PCI | |||
889 | configuration registers. Unfortunately it seems that the I/O base | |||
890 | address is off by one on my card so I mask it with 0xfff8. This | |||
891 | must be some kind of goof in the FD code that does the autoconfig | |||
892 | and writes to the PCI registers (or maybe I just don't understand | |||
893 | something). If they fix it in later versions of the card or BIOS | |||
894 | we may have to adjust the address based on the signature or | |||
895 | something... */ | |||
896 | ||||
897 | *irq = pci_irq; | |||
898 | *iobase = (pci_base & 0xfff8); | |||
899 | ||||
900 | #if DEBUG_DETECT0 | |||
901 | printk( "TMC-3260 fix: Masking I/O base address with 0xff00.\n" ); | |||
902 | printk( "TMC-3260: IRQ = %d, I/O base = 0x%x\n", *irq, *iobase ); | |||
903 | #endif | |||
904 | ||||
905 | if (!fdomain_is_valid_port( *iobase )) return 0; | |||
906 | return 1; | |||
907 | } | |||
908 | return 0; | |||
909 | } | |||
910 | #endif | |||
911 | ||||
912 | int fdomain_16x0_detect( Scsi_Host_Template *tpnt ) | |||
913 | { | |||
914 | int i, j; | |||
915 | int retcode; | |||
916 | struct Scsi_Host *shpnt; | |||
917 | #if DO_DETECT0 | |||
918 | const int buflen = 255; | |||
919 | Scsi_Cmnd SCinit; | |||
920 | unsigned char do_inquiry[] = { INQUIRY0x12, 0, 0, 0, buflen, 0 }; | |||
921 | unsigned char do_request_sense[] = { REQUEST_SENSE0x03, 0, 0, 0, buflen, 0 }; | |||
922 | unsigned char do_read_capacity[] = { READ_CAPACITY0x25, | |||
923 | 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | |||
924 | unsigned char buf[buflen]; | |||
925 | #endif | |||
926 | ||||
927 | #if DEBUG_DETECT0 | |||
928 | printk( "fdomain_16x0_detect()," ); | |||
929 | #endif | |||
930 | tpnt->proc_dir = &proc_scsi_fdomain; | |||
931 | ||||
932 | if (setup_called) { | |||
933 | #if DEBUG_DETECT0 | |||
934 | printk( "no BIOS, using port_base = 0x%x, irq = %d\n", | |||
935 | port_base, interrupt_level ); | |||
936 | #endif | |||
937 | if (!fdomain_is_valid_port( port_base )) { | |||
938 | printk( "fdomain: cannot locate chip at port base 0x%x\n", | |||
939 | port_base ); | |||
940 | printk( "fdomain: bad LILO parameters?\n" ); | |||
941 | return 0; | |||
942 | } | |||
943 | } else { | |||
944 | int flag = 0; | |||
945 | ||||
946 | for (i = 0; !bios_base && i < ADDRESS_COUNT(sizeof( addresses ) / sizeof( unsigned )); i++) { | |||
947 | #if DEBUG_DETECT0 | |||
948 | printk( " %x(%x),", (unsigned)addresses[i], (unsigned)bios_base ); | |||
949 | #endif | |||
950 | for (j = 0; !bios_base && j < SIGNATURE_COUNT(sizeof( signatures ) / sizeof( struct signature )); j++) { | |||
951 | if (!memcmp__builtin_memcmp( ((char *)addresses[i] + signatures[j].sig_offset), | |||
952 | signatures[j].signature, signatures[j].sig_length )) { | |||
953 | bios_major = signatures[j].major_bios_version; | |||
954 | bios_minor = signatures[j].minor_bios_version; | |||
955 | PCI_bus = (signatures[j].flag == 1); | |||
956 | Quantum = (signatures[j].flag > 1) ? signatures[j].flag : 0; | |||
957 | bios_base = addresses[i]; | |||
958 | } | |||
959 | } | |||
960 | } | |||
961 | ||||
962 | if (!bios_base) { | |||
963 | #if DEBUG_DETECT0 | |||
964 | printk( " FAILED: NO BIOS\n" ); | |||
965 | #endif | |||
966 | return 0; | |||
967 | } | |||
968 | ||||
969 | if (!PCI_bus) { | |||
970 | flag = fdomain_isa_detect( &interrupt_level, &port_base ); | |||
971 | } else { | |||
972 | #ifdef CONFIG_PCI1 | |||
973 | flag = fdomain_pci_bios_detect( &interrupt_level, &port_base ); | |||
974 | #else | |||
975 | flag = fdomain_pci_nobios_detect( &interrupt_level, &port_base ); | |||
976 | #endif | |||
977 | } | |||
978 | ||||
979 | if (!flag) { | |||
980 | #if DEBUG_DETECT0 | |||
981 | printk( " FAILED: NO PORT\n" ); | |||
982 | #endif | |||
983 | #ifdef CONFIG_PCI1 | |||
984 | printk( "\nTMC-3260 36C70 PCI scsi chip detection failed.\n" ); | |||
985 | printk( "Send mail to mckinley@msupa.pa.msu.edu.\n" ); | |||
986 | #endif | |||
987 | return 0; /* Cannot find valid set of ports */ | |||
988 | } | |||
989 | } | |||
990 | ||||
991 | SCSI_Mode_Cntl_port = port_base + SCSI_Mode_Cntl; | |||
992 | FIFO_Data_Count_port = port_base + FIFO_Data_Count; | |||
993 | Interrupt_Cntl_port = port_base + Interrupt_Cntl; | |||
994 | Interrupt_Status_port = port_base + Interrupt_Status; | |||
995 | Read_FIFO_port = port_base + Read_FIFO; | |||
996 | Read_SCSI_Data_port = port_base + Read_SCSI_Data; | |||
997 | SCSI_Cntl_port = port_base + SCSI_Cntl; | |||
998 | SCSI_Data_NoACK_port = port_base + SCSI_Data_NoACK; | |||
999 | SCSI_Status_port = port_base + SCSI_Status; | |||
1000 | TMC_Cntl_port = port_base + TMC_Cntl; | |||
1001 | TMC_Status_port = port_base + TMC_Status; | |||
1002 | Write_FIFO_port = port_base + Write_FIFO; | |||
1003 | Write_SCSI_Data_port = port_base + Write_SCSI_Data; | |||
1004 | ||||
1005 | fdomain_16x0_reset( NULL((void *) 0), 0 ); | |||
1006 | ||||
1007 | if (fdomain_test_loopback()) { | |||
1008 | #if DEBUG_DETECT0 | |||
1009 | printk( "fdomain: LOOPBACK TEST FAILED, FAILING DETECT!\n" ); | |||
1010 | #endif | |||
1011 | if (setup_called) { | |||
1012 | printk( "fdomain: loopback test failed at port base 0x%x\n", | |||
1013 | port_base ); | |||
1014 | printk( "fdomain: bad LILO parameters?\n" ); | |||
1015 | } | |||
1016 | return 0; | |||
1017 | } | |||
1018 | ||||
1019 | if (this_id) { | |||
1020 | tpnt->this_id = (this_id & 0x07); | |||
1021 | adapter_mask = (1 << tpnt->this_id); | |||
1022 | } else { | |||
1023 | if (PCI_bus || (bios_major == 3 && bios_minor >= 2) || bios_major < 0) { | |||
1024 | tpnt->this_id = 7; | |||
1025 | adapter_mask = 0x80; | |||
1026 | } else { | |||
1027 | tpnt->this_id = 6; | |||
1028 | adapter_mask = 0x40; | |||
1029 | } | |||
1030 | } | |||
1031 | ||||
1032 | /* Print out a banner here in case we can't | |||
1033 | get resources. */ | |||
1034 | ||||
1035 | shpnt = scsi_register( tpnt, 0 ); | |||
1036 | shpnt->irq = interrupt_level; | |||
1037 | shpnt->io_port = port_base; | |||
1038 | shpnt->n_io_port = 0x10; | |||
1039 | print_banner( shpnt ); | |||
1040 | ||||
1041 | /* Log IRQ with kernel */ | |||
1042 | if (!interrupt_level) { | |||
1043 | panic( "fdomain: *NO* interrupt level selected!\n" ); | |||
1044 | } else { | |||
1045 | /* Register the IRQ with the kernel */ | |||
1046 | ||||
1047 | retcode = request_irq( interrupt_level, | |||
1048 | fdomain_16x0_intr, SA_INTERRUPT0x20000000, "fdomain", NULL((void *) 0)); | |||
1049 | ||||
1050 | if (retcode < 0) { | |||
1051 | if (retcode == -EINVAL22) { | |||
1052 | printk( "fdomain: IRQ %d is bad!\n", interrupt_level ); | |||
1053 | printk( " This shouldn't happen!\n" ); | |||
1054 | printk( " Send mail to faith@cs.unc.edu\n" ); | |||
1055 | } else if (retcode == -EBUSY16) { | |||
1056 | printk( "fdomain: IRQ %d is already in use!\n", interrupt_level ); | |||
1057 | printk( " Please use another IRQ!\n" ); | |||
1058 | } else { | |||
1059 | printk( "fdomain: Error getting IRQ %d\n", interrupt_level ); | |||
1060 | printk( " This shouldn't happen!\n" ); | |||
1061 | printk( " Send mail to faith@cs.unc.edu\n" ); | |||
1062 | } | |||
1063 | panic( "fdomain: Driver requires interruptions\n" ); | |||
1064 | } | |||
1065 | } | |||
1066 | ||||
1067 | /* Log I/O ports with kernel */ | |||
1068 | request_region( port_base, 0x10, "fdomain" ); | |||
1069 | ||||
1070 | #if DO_DETECT0 | |||
1071 | ||||
1072 | /* These routines are here because of the way the SCSI bus behaves after | |||
1073 | a reset. This appropriate behavior was not handled correctly by the | |||
1074 | higher level SCSI routines when I first wrote this driver. Now, | |||
1075 | however, correct scan routines are part of scsi.c and these routines | |||
1076 | are no longer needed. However, this code is still good for | |||
1077 | debugging. */ | |||
1078 | ||||
1079 | SCinit.request_buffer = SCinit.buffer = buf; | |||
1080 | SCinit.request_bufflen = SCinit.bufflen = sizeof(buf)-1; | |||
1081 | SCinit.use_sg = 0; | |||
1082 | SCinit.lun = 0; | |||
1083 | ||||
1084 | printk( "fdomain: detection routine scanning for devices:\n" ); | |||
1085 | for (i = 0; i < 8; i++) { | |||
1086 | SCinit.target = i; | |||
1087 | if (i == tpnt->this_id) /* Skip host adapter */ | |||
1088 | continue; | |||
1089 | memcpy(SCinit.cmnd, do_request_sense, sizeof(do_request_sense))(__builtin_constant_p(sizeof(do_request_sense)) ? __constant_memcpy ((SCinit.cmnd),(do_request_sense),(sizeof(do_request_sense))) : __memcpy((SCinit.cmnd),(do_request_sense),(sizeof(do_request_sense )))); | |||
1090 | retcode = fdomain_16x0_command(&SCinit); | |||
1091 | if (!retcode) { | |||
1092 | memcpy(SCinit.cmnd, do_inquiry, sizeof(do_inquiry))(__builtin_constant_p(sizeof(do_inquiry)) ? __constant_memcpy ((SCinit.cmnd),(do_inquiry),(sizeof(do_inquiry))) : __memcpy( (SCinit.cmnd),(do_inquiry),(sizeof(do_inquiry)))); | |||
1093 | retcode = fdomain_16x0_command(&SCinit); | |||
1094 | if (!retcode) { | |||
1095 | printk( " SCSI ID %d: ", i ); | |||
1096 | for (j = 8; j < (buf[4] < 32 ? buf[4] : 32); j++) | |||
1097 | printk( "%c", buf[j] >= 20 ? buf[j] : ' ' ); | |||
1098 | memcpy(SCinit.cmnd, do_read_capacity, sizeof(do_read_capacity))(__builtin_constant_p(sizeof(do_read_capacity)) ? __constant_memcpy ((SCinit.cmnd),(do_read_capacity),(sizeof(do_read_capacity))) : __memcpy((SCinit.cmnd),(do_read_capacity),(sizeof(do_read_capacity )))); | |||
1099 | retcode = fdomain_16x0_command(&SCinit); | |||
1100 | if (!retcode) { | |||
1101 | unsigned long blocks, size, capacity; | |||
1102 | ||||
1103 | blocks = (buf[0] << 24) | (buf[1] << 16) | |||
1104 | | (buf[2] << 8) | buf[3]; | |||
1105 | size = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7]; | |||
1106 | capacity = +( +(blocks / 1024L) * +(size * 10L)) / 1024L; | |||
1107 | ||||
1108 | printk( "%lu MB (%lu byte blocks)", | |||
1109 | ((capacity + 5L) / 10L), size ); | |||
1110 | } else { | |||
1111 | memcpy(SCinit.cmnd, do_request_sense, sizeof(do_request_sense))(__builtin_constant_p(sizeof(do_request_sense)) ? __constant_memcpy ((SCinit.cmnd),(do_request_sense),(sizeof(do_request_sense))) : __memcpy((SCinit.cmnd),(do_request_sense),(sizeof(do_request_sense )))); | |||
1112 | retcode = fdomain_16x0_command(&SCinit); | |||
1113 | } | |||
1114 | printk ("\n" ); | |||
1115 | } else { | |||
1116 | memcpy(SCinit.cmnd, do_request_sense, sizeof(do_request_sense))(__builtin_constant_p(sizeof(do_request_sense)) ? __constant_memcpy ((SCinit.cmnd),(do_request_sense),(sizeof(do_request_sense))) : __memcpy((SCinit.cmnd),(do_request_sense),(sizeof(do_request_sense )))); | |||
1117 | retcode = fdomain_16x0_command(&SCinit); | |||
1118 | } | |||
1119 | } | |||
1120 | } | |||
1121 | #endif | |||
1122 | ||||
1123 | return 1; /* Maximum of one adapter will be detected. */ | |||
1124 | } | |||
1125 | ||||
1126 | const char *fdomain_16x0_info( struct Scsi_Host *ignore ) | |||
1127 | { | |||
1128 | static char buffer[80]; | |||
1129 | char *pt; | |||
1130 | ||||
1131 | strcpy( buffer, "Future Domain TMC-16x0 SCSI driver, version" ); | |||
1132 | if (strchr( VERSION"$Revision: 1.1 $", ':')) { /* Assume VERSION is an RCS Revision string */ | |||
1133 | strcat( buffer, strchr( VERSION"$Revision: 1.1 $", ':' ) + 1 ); | |||
1134 | pt = strrchr( buffer, '$') - 1; | |||
1135 | if (!pt) /* Stripped RCS Revision string? */ | |||
1136 | pt = buffer + strlen( buffer ) - 1; | |||
1137 | if (*pt != ' ') | |||
1138 | ++pt; | |||
1139 | *pt = '\0'; | |||
1140 | } else { /* Assume VERSION is a number */ | |||
1141 | strcat( buffer, " " VERSION"$Revision: 1.1 $" ); | |||
1142 | } | |||
1143 | ||||
1144 | return buffer; | |||
1145 | } | |||
1146 | ||||
1147 | /* First pass at /proc information routine. */ | |||
1148 | /* | |||
1149 | * inout : decides on the direction of the dataflow and the meaning of the | |||
1150 | * variables | |||
1151 | * buffer: If inout==FALSE data is being written to it else read from it | |||
1152 | * *start: If inout==FALSE start of the valid data in the buffer | |||
1153 | * offset: If inout==FALSE offset from the beginning of the imaginary file | |||
1154 | * from which we start writing into the buffer | |||
1155 | * length: If inout==FALSE max number of bytes to be written into the buffer | |||
1156 | * else number of bytes in the buffer | |||
1157 | */ | |||
1158 | int fdomain_16x0_proc_info( char *buffer, char **start, off_t offset, | |||
1159 | int length, int hostno, int inout ) | |||
1160 | { | |||
1161 | const char *info = fdomain_16x0_info( NULL((void *) 0) ); | |||
1162 | int len; | |||
1163 | int pos; | |||
1164 | int begin; | |||
1165 | ||||
1166 | if (inout) return(-ENOSYS38); | |||
1167 | ||||
1168 | begin = 0; | |||
1169 | strcpy( buffer, info ); | |||
1170 | strcat( buffer, "\n" ); | |||
1171 | ||||
1172 | pos = len = strlen( buffer ); | |||
1173 | ||||
1174 | if(pos < offset) { | |||
1175 | len = 0; | |||
1176 | begin = pos; | |||
1177 | } | |||
1178 | ||||
1179 | *start = buffer + (offset - begin); /* Start of wanted data */ | |||
1180 | len -= (offset - begin); | |||
1181 | if(len > length) len = length; | |||
1182 | ||||
1183 | return(len); | |||
1184 | } | |||
1185 | ||||
1186 | #if 0 | |||
1187 | static int fdomain_arbitrate( void ) | |||
1188 | { | |||
1189 | int status = 0; | |||
1190 | unsigned long timeout; | |||
1191 | ||||
1192 | #if EVERY_ACCESS0 | |||
1193 | printk( "fdomain_arbitrate()\n" ); | |||
1194 | #endif | |||
1195 | ||||
1196 | outb( 0x00, SCSI_Cntl_port )((__builtin_constant_p((SCSI_Cntl_port)) && (SCSI_Cntl_port ) < 256) ? __outbc((0x00),(SCSI_Cntl_port)) : __outb((0x00 ),(SCSI_Cntl_port))); /* Disable data drivers */ | |||
1197 | outb( adapter_mask, port_base + SCSI_Data_NoACK )((__builtin_constant_p((port_base + SCSI_Data_NoACK)) && (port_base + SCSI_Data_NoACK) < 256) ? __outbc((adapter_mask ),(port_base + SCSI_Data_NoACK)) : __outb((adapter_mask),(port_base + SCSI_Data_NoACK))); /* Set our id bit */ | |||
1198 | outb( 0x04 | PARITY_MASK, TMC_Cntl_port )((__builtin_constant_p((TMC_Cntl_port)) && (TMC_Cntl_port ) < 256) ? __outbc((0x04 | 0x08),(TMC_Cntl_port)) : __outb ((0x04 | 0x08),(TMC_Cntl_port))); /* Start arbitration */ | |||
1199 | ||||
1200 | timeout = jiffies + 50; /* 500 mS */ | |||
1201 | while (jiffies < timeout) { | |||
1202 | status = inb( TMC_Status_port )((__builtin_constant_p((TMC_Status_port)) && (TMC_Status_port ) < 256) ? __inbc(TMC_Status_port) : __inb(TMC_Status_port )); /* Read adapter status */ | |||
1203 | if (status & 0x02) /* Arbitration complete */ | |||
1204 | return 0; | |||
1205 | } | |||
1206 | ||||
1207 | /* Make bus idle */ | |||
1208 | fdomain_make_bus_idle(); | |||
1209 | ||||
1210 | #if EVERY_ACCESS0 | |||
1211 | printk( "Arbitration failed, status = %x\n", status ); | |||
1212 | #endif | |||
1213 | #if ERRORS_ONLY1 | |||
1214 | printk( "fdomain: Arbitration failed, status = %x\n", status ); | |||
1215 | #endif | |||
1216 | return 1; | |||
1217 | } | |||
1218 | #endif | |||
1219 | ||||
1220 | static int fdomain_select( int target ) | |||
1221 | { | |||
1222 | int status; | |||
1223 | unsigned long timeout; | |||
1224 | static int flag = 0; | |||
1225 | ||||
1226 | ||||
1227 | outb( 0x82, SCSI_Cntl_port )((__builtin_constant_p((SCSI_Cntl_port)) && (SCSI_Cntl_port ) < 256) ? __outbc((0x82),(SCSI_Cntl_port)) : __outb((0x82 ),(SCSI_Cntl_port))); /* Bus Enable + Select */ | |||
1228 | outb( adapter_mask | (1 << target), SCSI_Data_NoACK_port )((__builtin_constant_p((SCSI_Data_NoACK_port)) && (SCSI_Data_NoACK_port ) < 256) ? __outbc((adapter_mask | (1 << target)),(SCSI_Data_NoACK_port )) : __outb((adapter_mask | (1 << target)),(SCSI_Data_NoACK_port ))); | |||
1229 | ||||
1230 | /* Stop arbitration and enable parity */ | |||
1231 | outb( PARITY_MASK, TMC_Cntl_port )((__builtin_constant_p((TMC_Cntl_port)) && (TMC_Cntl_port ) < 256) ? __outbc((0x08),(TMC_Cntl_port)) : __outb((0x08) ,(TMC_Cntl_port))); | |||
1232 | ||||
1233 | timeout = jiffies + 35; /* 350mS -- because of timeouts | |||
1234 | (was 250mS) */ | |||
1235 | ||||
1236 | while (jiffies < timeout) { | |||
1237 | status = inb( SCSI_Status_port )((__builtin_constant_p((SCSI_Status_port)) && (SCSI_Status_port ) < 256) ? __inbc(SCSI_Status_port) : __inb(SCSI_Status_port )); /* Read adapter status */ | |||
1238 | if (status & 1) { /* Busy asserted */ | |||
1239 | /* Enable SCSI Bus (on error, should make bus idle with 0) */ | |||
1240 | outb( 0x80, SCSI_Cntl_port )((__builtin_constant_p((SCSI_Cntl_port)) && (SCSI_Cntl_port ) < 256) ? __outbc((0x80),(SCSI_Cntl_port)) : __outb((0x80 ),(SCSI_Cntl_port))); | |||
1241 | return 0; | |||
1242 | } | |||
1243 | } | |||
1244 | /* Make bus idle */ | |||
1245 | fdomain_make_bus_idle(); | |||
1246 | #if EVERY_ACCESS0 | |||
1247 | if (!target) printk( "Selection failed\n" ); | |||
1248 | #endif | |||
1249 | #if ERRORS_ONLY1 | |||
1250 | if (!target) { | |||
1251 | if (!flag) /* Skip first failure for all chips. */ | |||
1252 | ++flag; | |||
1253 | else | |||
1254 | printk( "fdomain: Selection failed\n" ); | |||
1255 | } | |||
1256 | #endif | |||
1257 | return 1; | |||
1258 | } | |||
1259 | ||||
1260 | void my_done( int error ) | |||
1261 | { | |||
1262 | if (in_command) { | |||
1263 | in_command = 0; | |||
1264 | outb( 0x00, Interrupt_Cntl_port )((__builtin_constant_p((Interrupt_Cntl_port)) && (Interrupt_Cntl_port ) < 256) ? __outbc((0x00),(Interrupt_Cntl_port)) : __outb( (0x00),(Interrupt_Cntl_port))); | |||
1265 | fdomain_make_bus_idle(); | |||
1266 | current_SC->result = error; | |||
1267 | if (current_SC->scsi_done) | |||
1268 | current_SC->scsi_done( current_SC ); | |||
1269 | else panic( "fdomain: current_SC->scsi_done() == NULL" ); | |||
1270 | } else { | |||
1271 | panic( "fdomain: my_done() called outside of command\n" ); | |||
1272 | } | |||
1273 | #if DEBUG_RACE1 | |||
1274 | in_interrupt_flag = 0; | |||
1275 | #endif | |||
1276 | } | |||
1277 | ||||
1278 | void fdomain_16x0_intr( int irq, void *dev_id, struct pt_regs * regs ) | |||
1279 | { | |||
1280 | int status; | |||
1281 | int done = 0; | |||
1282 | unsigned data_count; | |||
1283 | ||||
1284 | /* The fdomain_16x0_intr is only called via | |||
1285 | the interrupt handler. The goal of the | |||
1286 | sti() here is to allow other | |||
1287 | interruptions while this routine is | |||
1288 | running. */ | |||
1289 | ||||
1290 | sti()__asm__ __volatile__ ("sti": : :"memory"); /* Yes, we really want sti() here */ | |||
1291 | ||||
1292 | outb( 0x00, Interrupt_Cntl_port )((__builtin_constant_p((Interrupt_Cntl_port)) && (Interrupt_Cntl_port ) < 256) ? __outbc((0x00),(Interrupt_Cntl_port)) : __outb( (0x00),(Interrupt_Cntl_port))); | |||
1293 | ||||
1294 | /* We usually have one spurious interrupt after each command. Ignore it. */ | |||
1295 | if (!in_command || !current_SC) { /* Spurious interrupt */ | |||
1296 | #if EVERY_ACCESS0 | |||
1297 | printk( "Spurious interrupt, in_command = %d, current_SC = %x\n", | |||
1298 | in_command, current_SC ); | |||
1299 | #endif | |||
1300 | return; | |||
1301 | } | |||
1302 | ||||
1303 | /* Abort calls my_done, so we do nothing here. */ | |||
1304 | if (current_SC->SCp.phase & aborted) { | |||
1305 | #if DEBUG_ABORT1 | |||
1306 | printk( "Interrupt after abort, ignoring\n" ); | |||
1307 | #endif | |||
1308 | /* | |||
1309 | return; */ | |||
1310 | } | |||
1311 | ||||
1312 | #if DEBUG_RACE1 | |||
1313 | ++in_interrupt_flag; | |||
1314 | #endif | |||
1315 | ||||
1316 | if (current_SC->SCp.phase & in_arbitration) { | |||
1317 | status = inb( TMC_Status_port )((__builtin_constant_p((TMC_Status_port)) && (TMC_Status_port ) < 256) ? __inbc(TMC_Status_port) : __inb(TMC_Status_port )); /* Read adapter status */ | |||
1318 | if (!(status & 0x02)) { | |||
1319 | #if EVERY_ACCESS0 | |||
1320 | printk( " AFAIL " ); | |||
1321 | #endif | |||
1322 | my_done( DID_BUS_BUSY0x02 << 16 ); | |||
1323 | return; | |||
1324 | } | |||
1325 | current_SC->SCp.phase = in_selection; | |||
1326 | ||||
1327 | outb( 0x40 | FIFO_COUNT, Interrupt_Cntl_port )((__builtin_constant_p((Interrupt_Cntl_port)) && (Interrupt_Cntl_port ) < 256) ? __outbc((0x40 | 2),(Interrupt_Cntl_port)) : __outb ((0x40 | 2),(Interrupt_Cntl_port))); | |||
1328 | ||||
1329 | outb( 0x82, SCSI_Cntl_port )((__builtin_constant_p((SCSI_Cntl_port)) && (SCSI_Cntl_port ) < 256) ? __outbc((0x82),(SCSI_Cntl_port)) : __outb((0x82 ),(SCSI_Cntl_port))); /* Bus Enable + Select */ | |||
1330 | outb( adapter_mask | (1 << current_SC->target), SCSI_Data_NoACK_port )((__builtin_constant_p((SCSI_Data_NoACK_port)) && (SCSI_Data_NoACK_port ) < 256) ? __outbc((adapter_mask | (1 << current_SC-> target)),(SCSI_Data_NoACK_port)) : __outb((adapter_mask | (1 << current_SC->target)),(SCSI_Data_NoACK_port))); | |||
1331 | ||||
1332 | /* Stop arbitration and enable parity */ | |||
1333 | outb( 0x10 | PARITY_MASK, TMC_Cntl_port )((__builtin_constant_p((TMC_Cntl_port)) && (TMC_Cntl_port ) < 256) ? __outbc((0x10 | 0x08),(TMC_Cntl_port)) : __outb ((0x10 | 0x08),(TMC_Cntl_port))); | |||
1334 | #if DEBUG_RACE1 | |||
1335 | in_interrupt_flag = 0; | |||
1336 | #endif | |||
1337 | return; | |||
1338 | } else if (current_SC->SCp.phase & in_selection) { | |||
1339 | status = inb( SCSI_Status_port )((__builtin_constant_p((SCSI_Status_port)) && (SCSI_Status_port ) < 256) ? __inbc(SCSI_Status_port) : __inb(SCSI_Status_port )); | |||
1340 | if (!(status & 0x01)) { | |||
1341 | /* Try again, for slow devices */ | |||
1342 | if (fdomain_select( current_SC->target )) { | |||
1343 | #if EVERY_ACCESS0 | |||
1344 | printk( " SFAIL " ); | |||
1345 | #endif | |||
1346 | my_done( DID_NO_CONNECT0x01 << 16 ); | |||
1347 | return; | |||
1348 | } else { | |||
1349 | #if EVERY_ACCESS0 | |||
1350 | printk( " AltSel " ); | |||
1351 | #endif | |||
1352 | /* Stop arbitration and enable parity */ | |||
1353 | outb( 0x10 | PARITY_MASK, TMC_Cntl_port )((__builtin_constant_p((TMC_Cntl_port)) && (TMC_Cntl_port ) < 256) ? __outbc((0x10 | 0x08),(TMC_Cntl_port)) : __outb ((0x10 | 0x08),(TMC_Cntl_port))); | |||
1354 | } | |||
1355 | } | |||
1356 | current_SC->SCp.phase = in_other; | |||
1357 | outb( 0x90 | FIFO_COUNT, Interrupt_Cntl_port )((__builtin_constant_p((Interrupt_Cntl_port)) && (Interrupt_Cntl_port ) < 256) ? __outbc((0x90 | 2),(Interrupt_Cntl_port)) : __outb ((0x90 | 2),(Interrupt_Cntl_port))); | |||
1358 | outb( 0x80, SCSI_Cntl_port )((__builtin_constant_p((SCSI_Cntl_port)) && (SCSI_Cntl_port ) < 256) ? __outbc((0x80),(SCSI_Cntl_port)) : __outb((0x80 ),(SCSI_Cntl_port))); | |||
1359 | #if DEBUG_RACE1 | |||
1360 | in_interrupt_flag = 0; | |||
1361 | #endif | |||
1362 | return; | |||
1363 | } | |||
1364 | ||||
1365 | /* current_SC->SCp.phase == in_other: this is the body of the routine */ | |||
1366 | ||||
1367 | status = inb( SCSI_Status_port )((__builtin_constant_p((SCSI_Status_port)) && (SCSI_Status_port ) < 256) ? __inbc(SCSI_Status_port) : __inb(SCSI_Status_port )); | |||
1368 | ||||
1369 | if (status & 0x10) { /* REQ */ | |||
1370 | ||||
1371 | switch (status & 0x0e) { | |||
1372 | ||||
1373 | case 0x08: /* COMMAND OUT */ | |||
1374 | outb( current_SC->cmnd[current_SC->SCp.sent_command++],((__builtin_constant_p((Write_SCSI_Data_port)) && (Write_SCSI_Data_port ) < 256) ? __outbc((current_SC->cmnd[current_SC->SCp .sent_command++]),(Write_SCSI_Data_port)) : __outb((current_SC ->cmnd[current_SC->SCp.sent_command++]),(Write_SCSI_Data_port ))) | |||
1375 | Write_SCSI_Data_port )((__builtin_constant_p((Write_SCSI_Data_port)) && (Write_SCSI_Data_port ) < 256) ? __outbc((current_SC->cmnd[current_SC->SCp .sent_command++]),(Write_SCSI_Data_port)) : __outb((current_SC ->cmnd[current_SC->SCp.sent_command++]),(Write_SCSI_Data_port ))); | |||
1376 | #if EVERY_ACCESS0 | |||
1377 | printk( "CMD = %x,", | |||
1378 | current_SC->cmnd[ current_SC->SCp.sent_command - 1] ); | |||
1379 | #endif | |||
1380 | break; | |||
1381 | case 0x00: /* DATA OUT -- tmc18c50/tmc18c30 only */ | |||
1382 | if (chip != tmc1800 && !current_SC->SCp.have_data_in) { | |||
1383 | current_SC->SCp.have_data_in = -1; | |||
1384 | outb( 0xd0 | PARITY_MASK, TMC_Cntl_port )((__builtin_constant_p((TMC_Cntl_port)) && (TMC_Cntl_port ) < 256) ? __outbc((0xd0 | 0x08),(TMC_Cntl_port)) : __outb ((0xd0 | 0x08),(TMC_Cntl_port))); | |||
1385 | } | |||
1386 | break; | |||
1387 | case 0x04: /* DATA IN -- tmc18c50/tmc18c30 only */ | |||
1388 | if (chip != tmc1800 && !current_SC->SCp.have_data_in) { | |||
1389 | current_SC->SCp.have_data_in = 1; | |||
1390 | outb( 0x90 | PARITY_MASK, TMC_Cntl_port )((__builtin_constant_p((TMC_Cntl_port)) && (TMC_Cntl_port ) < 256) ? __outbc((0x90 | 0x08),(TMC_Cntl_port)) : __outb ((0x90 | 0x08),(TMC_Cntl_port))); | |||
1391 | } | |||
1392 | break; | |||
1393 | case 0x0c: /* STATUS IN */ | |||
1394 | current_SC->SCp.Status = inb( Read_SCSI_Data_port )((__builtin_constant_p((Read_SCSI_Data_port)) && (Read_SCSI_Data_port ) < 256) ? __inbc(Read_SCSI_Data_port) : __inb(Read_SCSI_Data_port )); | |||
1395 | #if EVERY_ACCESS0 | |||
1396 | printk( "Status = %x, ", current_SC->SCp.Status ); | |||
1397 | #endif | |||
1398 | #if ERRORS_ONLY1 | |||
1399 | if (current_SC->SCp.Status | |||
1400 | && current_SC->SCp.Status != 2 | |||
1401 | && current_SC->SCp.Status != 8) { | |||
1402 | printk( "fdomain: target = %d, command = %x, status = %x\n", | |||
1403 | current_SC->target, | |||
1404 | current_SC->cmnd[0], | |||
1405 | current_SC->SCp.Status ); | |||
1406 | } | |||
1407 | #endif | |||
1408 | break; | |||
1409 | case 0x0a: /* MESSAGE OUT */ | |||
1410 | outb( MESSAGE_REJECT, Write_SCSI_Data_port )((__builtin_constant_p((Write_SCSI_Data_port)) && (Write_SCSI_Data_port ) < 256) ? __outbc((0x07),(Write_SCSI_Data_port)) : __outb ((0x07),(Write_SCSI_Data_port))); /* Reject */ | |||
1411 | break; | |||
1412 | case 0x0e: /* MESSAGE IN */ | |||
1413 | current_SC->SCp.Message = inb( Read_SCSI_Data_port )((__builtin_constant_p((Read_SCSI_Data_port)) && (Read_SCSI_Data_port ) < 256) ? __inbc(Read_SCSI_Data_port) : __inb(Read_SCSI_Data_port )); | |||
1414 | #if EVERY_ACCESS0 | |||
1415 | printk( "Message = %x, ", current_SC->SCp.Message ); | |||
1416 | #endif | |||
1417 | if (!current_SC->SCp.Message) ++done; | |||
1418 | #if DEBUG_MESSAGES1 || EVERY_ACCESS0 | |||
1419 | if (current_SC->SCp.Message) { | |||
1420 | printk( "fdomain: message = %x\n", current_SC->SCp.Message ); | |||
1421 | } | |||
1422 | #endif | |||
1423 | break; | |||
1424 | } | |||
1425 | } | |||
1426 | ||||
1427 | if (chip == tmc1800 | |||
1428 | && !current_SC->SCp.have_data_in | |||
1429 | && (current_SC->SCp.sent_command | |||
1430 | >= current_SC->cmd_len)) { | |||
1431 | /* We have to get the FIFO direction | |||
1432 | correct, so I've made a table based | |||
1433 | on the SCSI Standard of which commands | |||
1434 | appear to require a DATA OUT phase. | |||
1435 | */ | |||
1436 | /* | |||
1437 | p. 94: Command for all device types | |||
1438 | CHANGE DEFINITION 40 DATA OUT | |||
1439 | COMPARE 39 DATA OUT | |||
1440 | COPY 18 DATA OUT | |||
1441 | COPY AND VERIFY 3a DATA OUT | |||
1442 | INQUIRY 12 | |||
1443 | LOG SELECT 4c DATA OUT | |||
1444 | LOG SENSE 4d | |||
1445 | MODE SELECT (6) 15 DATA OUT | |||
1446 | MODE SELECT (10) 55 DATA OUT | |||
1447 | MODE SENSE (6) 1a | |||
1448 | MODE SENSE (10) 5a | |||
1449 | READ BUFFER 3c | |||
1450 | RECEIVE DIAGNOSTIC RESULTS 1c | |||
1451 | REQUEST SENSE 03 | |||
1452 | SEND DIAGNOSTIC 1d DATA OUT | |||
1453 | TEST UNIT READY 00 | |||
1454 | WRITE BUFFER 3b DATA OUT | |||
1455 | ||||
1456 | p.178: Commands for direct-access devices (not listed on p. 94) | |||
1457 | FORMAT UNIT 04 DATA OUT | |||
1458 | LOCK-UNLOCK CACHE 36 | |||
1459 | PRE-FETCH 34 | |||
1460 | PREVENT-ALLOW MEDIUM REMOVAL 1e | |||
1461 | READ (6)/RECEIVE 08 | |||
1462 | READ (10) 3c | |||
1463 | READ CAPACITY 25 | |||
1464 | READ DEFECT DATA (10) 37 | |||
1465 | READ LONG 3e | |||
1466 | REASSIGN BLOCKS 07 DATA OUT | |||
1467 | RELEASE 17 | |||
1468 | RESERVE 16 DATA OUT | |||
1469 | REZERO UNIT/REWIND 01 | |||
1470 | SEARCH DATA EQUAL (10) 31 DATA OUT | |||
1471 | SEARCH DATA HIGH (10) 30 DATA OUT | |||
1472 | SEARCH DATA LOW (10) 32 DATA OUT | |||
1473 | SEEK (6) 0b | |||
1474 | SEEK (10) 2b | |||
1475 | SET LIMITS (10) 33 | |||
1476 | START STOP UNIT 1b | |||
1477 | SYNCHRONIZE CACHE 35 | |||
1478 | VERIFY (10) 2f | |||
1479 | WRITE (6)/PRINT/SEND 0a DATA OUT | |||
1480 | WRITE (10)/SEND 2a DATA OUT | |||
1481 | WRITE AND VERIFY (10) 2e DATA OUT | |||
1482 | WRITE LONG 3f DATA OUT | |||
1483 | WRITE SAME 41 DATA OUT ? | |||
1484 | ||||
1485 | p. 261: Commands for sequential-access devices (not previously listed) | |||
1486 | ERASE 19 | |||
1487 | LOAD UNLOAD 1b | |||
1488 | LOCATE 2b | |||
1489 | READ BLOCK LIMITS 05 | |||
1490 | READ POSITION 34 | |||
1491 | READ REVERSE 0f | |||
1492 | RECOVER BUFFERED DATA 14 | |||
1493 | SPACE 11 | |||
1494 | WRITE FILEMARKS 10 ? | |||
1495 | ||||
1496 | p. 298: Commands for printer devices (not previously listed) | |||
1497 | ****** NOT SUPPORTED BY THIS DRIVER, since 0b is SEEK (6) ***** | |||
1498 | SLEW AND PRINT 0b DATA OUT -- same as seek | |||
1499 | STOP PRINT 1b | |||
1500 | SYNCHRONIZE BUFFER 10 | |||
1501 | ||||
1502 | p. 315: Commands for processor devices (not previously listed) | |||
1503 | ||||
1504 | p. 321: Commands for write-once devices (not previously listed) | |||
1505 | MEDIUM SCAN 38 | |||
1506 | READ (12) a8 | |||
1507 | SEARCH DATA EQUAL (12) b1 DATA OUT | |||
1508 | SEARCH DATA HIGH (12) b0 DATA OUT | |||
1509 | SEARCH DATA LOW (12) b2 DATA OUT | |||
1510 | SET LIMITS (12) b3 | |||
1511 | VERIFY (12) af | |||
1512 | WRITE (12) aa DATA OUT | |||
1513 | WRITE AND VERIFY (12) ae DATA OUT | |||
1514 | ||||
1515 | p. 332: Commands for CD-ROM devices (not previously listed) | |||
1516 | PAUSE/RESUME 4b | |||
1517 | PLAY AUDIO (10) 45 | |||
1518 | PLAY AUDIO (12) a5 | |||
1519 | PLAY AUDIO MSF 47 | |||
1520 | PLAY TRACK RELATIVE (10) 49 | |||
1521 | PLAY TRACK RELATIVE (12) a9 | |||
1522 | READ HEADER 44 | |||
1523 | READ SUB-CHANNEL 42 | |||
1524 | READ TOC 43 | |||
1525 | ||||
1526 | p. 370: Commands for scanner devices (not previously listed) | |||
1527 | GET DATA BUFFER STATUS 34 | |||
1528 | GET WINDOW 25 | |||
1529 | OBJECT POSITION 31 | |||
1530 | SCAN 1b | |||
1531 | SET WINDOW 24 DATA OUT | |||
1532 | ||||
1533 | p. 391: Commands for optical memory devices (not listed) | |||
1534 | ERASE (10) 2c | |||
1535 | ERASE (12) ac | |||
1536 | MEDIUM SCAN 38 DATA OUT | |||
1537 | READ DEFECT DATA (12) b7 | |||
1538 | READ GENERATION 29 | |||
1539 | READ UPDATED BLOCK 2d | |||
1540 | UPDATE BLOCK 3d DATA OUT | |||
1541 | ||||
1542 | p. 419: Commands for medium changer devices (not listed) | |||
1543 | EXCHANGE MEDIUM 46 | |||
1544 | INITIALIZE ELEMENT STATUS 07 | |||
1545 | MOVE MEDIUM a5 | |||
1546 | POSITION TO ELEMENT 2b | |||
1547 | READ ELEMENT STATUS b8 | |||
1548 | REQUEST VOL. ELEMENT ADDRESS b5 | |||
1549 | SEND VOLUME TAG b6 DATA OUT | |||
1550 | ||||
1551 | p. 454: Commands for communications devices (not listed previously) | |||
1552 | GET MESSAGE (6) 08 | |||
1553 | GET MESSAGE (10) 28 | |||
1554 | GET MESSAGE (12) a8 | |||
1555 | */ | |||
1556 | ||||
1557 | switch (current_SC->cmnd[0]) { | |||
1558 | case CHANGE_DEFINITION0x40: case COMPARE0x39: case COPY0x18: | |||
1559 | case COPY_VERIFY0x3a: case LOG_SELECT0x4c: case MODE_SELECT0x15: | |||
1560 | case MODE_SELECT_100x55: case SEND_DIAGNOSTIC0x1d: case WRITE_BUFFER0x3b: | |||
1561 | ||||
1562 | case FORMAT_UNIT0x04: case REASSIGN_BLOCKS0x07: case RESERVE0x16: | |||
1563 | case SEARCH_EQUAL0x31: case SEARCH_HIGH0x30: case SEARCH_LOW0x32: | |||
1564 | case WRITE_60x0a: case WRITE_100x2a: case WRITE_VERIFY0x2e: | |||
1565 | case 0x3f: case 0x41: | |||
1566 | ||||
1567 | case 0xb1: case 0xb0: case 0xb2: | |||
1568 | case 0xaa: case 0xae: | |||
1569 | ||||
1570 | case 0x24: | |||
1571 | ||||
1572 | case 0x38: case 0x3d: | |||
1573 | ||||
1574 | case 0xb6: | |||
1575 | ||||
1576 | case 0xea: /* alternate number for WRITE LONG */ | |||
1577 | ||||
1578 | current_SC->SCp.have_data_in = -1; | |||
1579 | outb( 0xd0 | PARITY_MASK, TMC_Cntl_port )((__builtin_constant_p((TMC_Cntl_port)) && (TMC_Cntl_port ) < 256) ? __outbc((0xd0 | 0x08),(TMC_Cntl_port)) : __outb ((0xd0 | 0x08),(TMC_Cntl_port))); | |||
1580 | break; | |||
1581 | ||||
1582 | case 0x00: | |||
1583 | default: | |||
1584 | ||||
1585 | current_SC->SCp.have_data_in = 1; | |||
1586 | outb( 0x90 | PARITY_MASK, TMC_Cntl_port )((__builtin_constant_p((TMC_Cntl_port)) && (TMC_Cntl_port ) < 256) ? __outbc((0x90 | 0x08),(TMC_Cntl_port)) : __outb ((0x90 | 0x08),(TMC_Cntl_port))); | |||
1587 | break; | |||
1588 | } | |||
1589 | } | |||
1590 | ||||
1591 | if (current_SC->SCp.have_data_in == -1) { /* DATA OUT */ | |||
1592 | while ( (data_count = FIFO_Size - inw( FIFO_Data_Count_port )((__builtin_constant_p((FIFO_Data_Count_port)) && (FIFO_Data_Count_port ) < 256) ? __inwc(FIFO_Data_Count_port) : __inw(FIFO_Data_Count_port ))) > 512 ) { | |||
1593 | #if EVERY_ACCESS0 | |||
1594 | printk( "DC=%d, ", data_count ) ; | |||
1595 | #endif | |||
1596 | if (data_count > current_SC->SCp.this_residual) | |||
1597 | data_count = current_SC->SCp.this_residual; | |||
1598 | if (data_count > 0) { | |||
1599 | #if EVERY_ACCESS0 | |||
1600 | printk( "%d OUT, ", data_count ); | |||
1601 | #endif | |||
1602 | if (data_count == 1) { | |||
1603 | outb( *current_SC->SCp.ptr++, Write_FIFO_port )((__builtin_constant_p((Write_FIFO_port)) && (Write_FIFO_port ) < 256) ? __outbc((*current_SC->SCp.ptr++),(Write_FIFO_port )) : __outb((*current_SC->SCp.ptr++),(Write_FIFO_port))); | |||
1604 | --current_SC->SCp.this_residual; | |||
1605 | } else { | |||
1606 | data_count >>= 1; | |||
1607 | outsw( Write_FIFO_port, current_SC->SCp.ptr, data_count ); | |||
1608 | current_SC->SCp.ptr += 2 * data_count; | |||
1609 | current_SC->SCp.this_residual -= 2 * data_count; | |||
1610 | } | |||
1611 | } | |||
1612 | if (!current_SC->SCp.this_residual) { | |||
1613 | if (current_SC->SCp.buffers_residual) { | |||
1614 | --current_SC->SCp.buffers_residual; | |||
1615 | ++current_SC->SCp.buffer; | |||
1616 | current_SC->SCp.ptr = current_SC->SCp.buffer->address; | |||
1617 | current_SC->SCp.this_residual = current_SC->SCp.buffer->length; | |||
1618 | } else | |||
1619 | break; | |||
1620 | } | |||
1621 | } | |||
1622 | } | |||
1623 | ||||
1624 | if (current_SC->SCp.have_data_in == 1) { /* DATA IN */ | |||
1625 | while ((data_count = inw( FIFO_Data_Count_port )((__builtin_constant_p((FIFO_Data_Count_port)) && (FIFO_Data_Count_port ) < 256) ? __inwc(FIFO_Data_Count_port) : __inw(FIFO_Data_Count_port ))) > 0) { | |||
1626 | #if EVERY_ACCESS0 | |||
1627 | printk( "DC=%d, ", data_count ); | |||
1628 | #endif | |||
1629 | if (data_count > current_SC->SCp.this_residual) | |||
1630 | data_count = current_SC->SCp.this_residual; | |||
1631 | if (data_count) { | |||
1632 | #if EVERY_ACCESS0 | |||
1633 | printk( "%d IN, ", data_count ); | |||
1634 | #endif | |||
1635 | if (data_count == 1) { | |||
1636 | *current_SC->SCp.ptr++ = inb( Read_FIFO_port )((__builtin_constant_p((Read_FIFO_port)) && (Read_FIFO_port ) < 256) ? __inbc(Read_FIFO_port) : __inb(Read_FIFO_port)); | |||
1637 | --current_SC->SCp.this_residual; | |||
1638 | } else { | |||
1639 | data_count >>= 1; /* Number of words */ | |||
1640 | insw( Read_FIFO_port, current_SC->SCp.ptr, data_count ); | |||
1641 | current_SC->SCp.ptr += 2 * data_count; | |||
1642 | current_SC->SCp.this_residual -= 2 * data_count; | |||
1643 | } | |||
1644 | } | |||
1645 | if (!current_SC->SCp.this_residual | |||
1646 | && current_SC->SCp.buffers_residual) { | |||
1647 | --current_SC->SCp.buffers_residual; | |||
1648 | ++current_SC->SCp.buffer; | |||
1649 | current_SC->SCp.ptr = current_SC->SCp.buffer->address; | |||
1650 | current_SC->SCp.this_residual = current_SC->SCp.buffer->length; | |||
1651 | } | |||
1652 | } | |||
1653 | } | |||
1654 | ||||
1655 | if (done) { | |||
1656 | #if EVERY_ACCESS0 | |||
1657 | printk( " ** IN DONE %d ** ", current_SC->SCp.have_data_in ); | |||
1658 | #endif | |||
1659 | ||||
1660 | #if ERRORS_ONLY1 | |||
1661 | if (current_SC->cmnd[0] == REQUEST_SENSE0x03 && !current_SC->SCp.Status) { | |||
1662 | if ((unsigned char)(*((char *)current_SC->request_buffer+2)) & 0x0f) { | |||
1663 | unsigned char key; | |||
1664 | unsigned char code; | |||
1665 | unsigned char qualifier; | |||
1666 | ||||
1667 | key = (unsigned char)(*((char *)current_SC->request_buffer + 2)) | |||
1668 | & 0x0f; | |||
1669 | code = (unsigned char)(*((char *)current_SC->request_buffer + 12)); | |||
1670 | qualifier = (unsigned char)(*((char *)current_SC->request_buffer | |||
1671 | + 13)); | |||
1672 | ||||
1673 | if (key != UNIT_ATTENTION0x06 | |||
1674 | && !(key == NOT_READY0x02 | |||
1675 | && code == 0x04 | |||
1676 | && (!qualifier || qualifier == 0x02 || qualifier == 0x01)) | |||
1677 | && !(key == ILLEGAL_REQUEST0x05 && (code == 0x25 | |||
1678 | || code == 0x24 | |||
1679 | || !code))) | |||
1680 | ||||
1681 | printk( "fdomain: REQUEST SENSE " | |||
1682 | "Key = %x, Code = %x, Qualifier = %x\n", | |||
1683 | key, code, qualifier ); | |||
1684 | } | |||
1685 | } | |||
1686 | #endif | |||
1687 | #if EVERY_ACCESS0 | |||
1688 | printk( "BEFORE MY_DONE. . ." ); | |||
1689 | #endif | |||
1690 | my_done( (current_SC->SCp.Status & 0xff) | |||
1691 | | ((current_SC->SCp.Message & 0xff) << 8) | (DID_OK0x00 << 16) ); | |||
1692 | #if EVERY_ACCESS0 | |||
1693 | printk( "RETURNING.\n" ); | |||
1694 | #endif | |||
1695 | ||||
1696 | } else { | |||
1697 | if (current_SC->SCp.phase & disconnect) { | |||
1698 | outb( 0xd0 | FIFO_COUNT, Interrupt_Cntl_port )((__builtin_constant_p((Interrupt_Cntl_port)) && (Interrupt_Cntl_port ) < 256) ? __outbc((0xd0 | 2),(Interrupt_Cntl_port)) : __outb ((0xd0 | 2),(Interrupt_Cntl_port))); | |||
1699 | outb( 0x00, SCSI_Cntl_port )((__builtin_constant_p((SCSI_Cntl_port)) && (SCSI_Cntl_port ) < 256) ? __outbc((0x00),(SCSI_Cntl_port)) : __outb((0x00 ),(SCSI_Cntl_port))); | |||
1700 | } else { | |||
1701 | outb( 0x90 | FIFO_COUNT, Interrupt_Cntl_port )((__builtin_constant_p((Interrupt_Cntl_port)) && (Interrupt_Cntl_port ) < 256) ? __outbc((0x90 | 2),(Interrupt_Cntl_port)) : __outb ((0x90 | 2),(Interrupt_Cntl_port))); | |||
1702 | } | |||
1703 | } | |||
1704 | #if DEBUG_RACE1 | |||
1705 | in_interrupt_flag = 0; | |||
1706 | #endif | |||
1707 | return; | |||
1708 | } | |||
1709 | ||||
1710 | int fdomain_16x0_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) | |||
1711 | { | |||
1712 | if (in_command) { | |||
1713 | panic( "fdomain: fdomain_16x0_queue() NOT REENTRANT!\n" ); | |||
1714 | } | |||
1715 | #if EVERY_ACCESS0 | |||
1716 | printk( "queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n", | |||
1717 | SCpnt->target, | |||
1718 | *(unsigned char *)SCpnt->cmnd, | |||
1719 | SCpnt->use_sg, | |||
1720 | SCpnt->request_bufflen ); | |||
1721 | #endif | |||
1722 | ||||
1723 | fdomain_make_bus_idle(); | |||
1724 | ||||
1725 | current_SC = SCpnt; /* Save this for the done function */ | |||
1726 | current_SC->scsi_done = done; | |||
1727 | ||||
1728 | /* Initialize static data */ | |||
1729 | ||||
1730 | if (current_SC->use_sg) { | |||
1731 | current_SC->SCp.buffer = | |||
1732 | (struct scatterlist *)current_SC->request_buffer; | |||
1733 | current_SC->SCp.ptr = current_SC->SCp.buffer->address; | |||
1734 | current_SC->SCp.this_residual = current_SC->SCp.buffer->length; | |||
1735 | current_SC->SCp.buffers_residual = current_SC->use_sg - 1; | |||
1736 | } else { | |||
1737 | current_SC->SCp.ptr = (char *)current_SC->request_buffer; | |||
1738 | current_SC->SCp.this_residual = current_SC->request_bufflen; | |||
1739 | current_SC->SCp.buffer = NULL((void *) 0); | |||
1740 | current_SC->SCp.buffers_residual = 0; | |||
1741 | } | |||
1742 | ||||
1743 | ||||
1744 | current_SC->SCp.Status = 0; | |||
1745 | current_SC->SCp.Message = 0; | |||
1746 | current_SC->SCp.have_data_in = 0; | |||
1747 | current_SC->SCp.sent_command = 0; | |||
1748 | current_SC->SCp.phase = in_arbitration; | |||
1749 | ||||
1750 | /* Start arbitration */ | |||
1751 | outb( 0x00, Interrupt_Cntl_port )((__builtin_constant_p((Interrupt_Cntl_port)) && (Interrupt_Cntl_port ) < 256) ? __outbc((0x00),(Interrupt_Cntl_port)) : __outb( (0x00),(Interrupt_Cntl_port))); | |||
1752 | outb( 0x00, SCSI_Cntl_port )((__builtin_constant_p((SCSI_Cntl_port)) && (SCSI_Cntl_port ) < 256) ? __outbc((0x00),(SCSI_Cntl_port)) : __outb((0x00 ),(SCSI_Cntl_port))); /* Disable data drivers */ | |||
1753 | outb( adapter_mask, SCSI_Data_NoACK_port )((__builtin_constant_p((SCSI_Data_NoACK_port)) && (SCSI_Data_NoACK_port ) < 256) ? __outbc((adapter_mask),(SCSI_Data_NoACK_port)) : __outb((adapter_mask),(SCSI_Data_NoACK_port))); /* Set our id bit */ | |||
1754 | ++in_command; | |||
1755 | outb( 0x20, Interrupt_Cntl_port )((__builtin_constant_p((Interrupt_Cntl_port)) && (Interrupt_Cntl_port ) < 256) ? __outbc((0x20),(Interrupt_Cntl_port)) : __outb( (0x20),(Interrupt_Cntl_port))); | |||
1756 | outb( 0x14 | PARITY_MASK, TMC_Cntl_port )((__builtin_constant_p((TMC_Cntl_port)) && (TMC_Cntl_port ) < 256) ? __outbc((0x14 | 0x08),(TMC_Cntl_port)) : __outb ((0x14 | 0x08),(TMC_Cntl_port))); /* Start arbitration */ | |||
1757 | ||||
1758 | return 0; | |||
1759 | } | |||
1760 | ||||
1761 | /* The following code, which simulates the old-style command function, was | |||
1762 | taken from Tommy Thorn's aha1542.c file. This code is Copyright (C) | |||
1763 | 1992 Tommy Thorn. */ | |||
1764 | ||||
1765 | static volatile int internal_done_flag = 0; | |||
1766 | static volatile int internal_done_errcode = 0; | |||
1767 | ||||
1768 | static void internal_done( Scsi_Cmnd *SCpnt ) | |||
1769 | { | |||
1770 | internal_done_errcode = SCpnt->result; | |||
1771 | ++internal_done_flag; | |||
1772 | } | |||
1773 | ||||
1774 | int fdomain_16x0_command( Scsi_Cmnd *SCpnt ) | |||
1775 | { | |||
1776 | fdomain_16x0_queue( SCpnt, internal_done ); | |||
1777 | ||||
1778 | while (!internal_done_flag) | |||
1779 | ; | |||
1780 | internal_done_flag = 0; | |||
1781 | return internal_done_errcode; | |||
1782 | } | |||
1783 | ||||
1784 | /* End of code derived from Tommy Thorn's work. */ | |||
1785 | ||||
1786 | void print_info( Scsi_Cmnd *SCpnt ) | |||
1787 | { | |||
1788 | unsigned int imr; | |||
1789 | unsigned int irr; | |||
1790 | unsigned int isr; | |||
1791 | ||||
1792 | if (!SCpnt || !SCpnt->host) { | |||
1793 | printk( "fdomain: cannot provide detailed information\n" ); | |||
1794 | } | |||
1795 | ||||
1796 | printk( "%s\n", fdomain_16x0_info( SCpnt->host ) ); | |||
| ||||
1797 | print_banner( SCpnt->host ); | |||
1798 | switch (SCpnt->SCp.phase) { | |||
1799 | case in_arbitration: printk( "arbitration " ); break; | |||
1800 | case in_selection: printk( "selection " ); break; | |||
1801 | case in_other: printk( "other " ); break; | |||
1802 | default: printk( "unknown " ); break; | |||
1803 | } | |||
1804 | ||||
1805 | printk( "(%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n", | |||
1806 | SCpnt->SCp.phase, | |||
1807 | SCpnt->target, | |||
1808 | *(unsigned char *)SCpnt->cmnd, | |||
1809 | SCpnt->use_sg, | |||
1810 | SCpnt->request_bufflen ); | |||
1811 | printk( "sent_command = %d, have_data_in = %d, timeout = %d\n", | |||
1812 | SCpnt->SCp.sent_command, | |||
1813 | SCpnt->SCp.have_data_in, | |||
1814 | SCpnt->timeout ); | |||
1815 | #if DEBUG_RACE1 | |||
1816 | printk( "in_interrupt_flag = %d\n", in_interrupt_flag ); | |||
1817 | #endif | |||
1818 | ||||
1819 | imr = (inb( 0x0a1 )((__builtin_constant_p((0x0a1)) && (0x0a1) < 256) ? __inbc(0x0a1) : __inb(0x0a1)) << 8) + inb( 0x21 )((__builtin_constant_p((0x21)) && (0x21) < 256) ? __inbc (0x21) : __inb(0x21)); | |||
1820 | outb( 0x0a, 0xa0 )((__builtin_constant_p((0xa0)) && (0xa0) < 256) ? __outbc ((0x0a),(0xa0)) : __outb((0x0a),(0xa0))); | |||
1821 | irr = inb( 0xa0 )((__builtin_constant_p((0xa0)) && (0xa0) < 256) ? __inbc (0xa0) : __inb(0xa0)) << 8; | |||
1822 | outb( 0x0a, 0x20 )((__builtin_constant_p((0x20)) && (0x20) < 256) ? __outbc ((0x0a),(0x20)) : __outb((0x0a),(0x20))); | |||
1823 | irr += inb( 0x20 )((__builtin_constant_p((0x20)) && (0x20) < 256) ? __inbc (0x20) : __inb(0x20)); | |||
1824 | outb( 0x0b, 0xa0 )((__builtin_constant_p((0xa0)) && (0xa0) < 256) ? __outbc ((0x0b),(0xa0)) : __outb((0x0b),(0xa0))); | |||
1825 | isr = inb( 0xa0 )((__builtin_constant_p((0xa0)) && (0xa0) < 256) ? __inbc (0xa0) : __inb(0xa0)) << 8; | |||
1826 | outb( 0x0b, 0x20 )((__builtin_constant_p((0x20)) && (0x20) < 256) ? __outbc ((0x0b),(0x20)) : __outb((0x0b),(0x20))); | |||
1827 | isr += inb( 0x20 )((__builtin_constant_p((0x20)) && (0x20) < 256) ? __inbc (0x20) : __inb(0x20)); | |||
1828 | ||||
1829 | /* Print out interesting information */ | |||
1830 | printk( "IMR = 0x%04x", imr ); | |||
1831 | if (imr & (1 << interrupt_level)) | |||
1832 | printk( " (masked)" ); | |||
1833 | printk( ", IRR = 0x%04x, ISR = 0x%04x\n", irr, isr ); | |||
1834 | ||||
1835 | printk( "SCSI Status = 0x%02x\n", inb( SCSI_Status_port )((__builtin_constant_p((SCSI_Status_port)) && (SCSI_Status_port ) < 256) ? __inbc(SCSI_Status_port) : __inb(SCSI_Status_port )) ); | |||
1836 | printk( "TMC Status = 0x%02x", inb( TMC_Status_port )((__builtin_constant_p((TMC_Status_port)) && (TMC_Status_port ) < 256) ? __inbc(TMC_Status_port) : __inb(TMC_Status_port )) ); | |||
1837 | if (inb( TMC_Status_port & 1)((__builtin_constant_p((TMC_Status_port & 1)) && ( TMC_Status_port & 1) < 256) ? __inbc(TMC_Status_port & 1) : __inb(TMC_Status_port & 1))) | |||
1838 | printk( " (interrupt)" ); | |||
1839 | printk( "\n" ); | |||
1840 | printk( "Interrupt Status = 0x%02x", inb( Interrupt_Status_port )((__builtin_constant_p((Interrupt_Status_port)) && (Interrupt_Status_port ) < 256) ? __inbc(Interrupt_Status_port) : __inb(Interrupt_Status_port )) ); | |||
1841 | if (inb( Interrupt_Status_port )((__builtin_constant_p((Interrupt_Status_port)) && (Interrupt_Status_port ) < 256) ? __inbc(Interrupt_Status_port) : __inb(Interrupt_Status_port )) & 0x08) | |||
1842 | printk( " (enabled)" ); | |||
1843 | printk( "\n" ); | |||
1844 | if (chip == tmc18c50 || chip == tmc18c30) { | |||
1845 | printk( "FIFO Status = 0x%02x\n", inb( port_base + FIFO_Status )((__builtin_constant_p((port_base + FIFO_Status)) && ( port_base + FIFO_Status) < 256) ? __inbc(port_base + FIFO_Status ) : __inb(port_base + FIFO_Status)) ); | |||
1846 | printk( "Int. Condition = 0x%02x\n", | |||
1847 | inb( port_base + Interrupt_Cond )((__builtin_constant_p((port_base + Interrupt_Cond)) && (port_base + Interrupt_Cond) < 256) ? __inbc(port_base + Interrupt_Cond ) : __inb(port_base + Interrupt_Cond)) ); | |||
1848 | } | |||
1849 | printk( "Configuration 1 = 0x%02x\n", inb( port_base + Configuration1 )((__builtin_constant_p((port_base + Configuration1)) && (port_base + Configuration1) < 256) ? __inbc(port_base + Configuration1 ) : __inb(port_base + Configuration1)) ); | |||
1850 | if (chip == tmc18c50 || chip == tmc18c30) | |||
1851 | printk( "Configuration 2 = 0x%02x\n", | |||
1852 | inb( port_base + Configuration2 )((__builtin_constant_p((port_base + Configuration2)) && (port_base + Configuration2) < 256) ? __inbc(port_base + Configuration2 ) : __inb(port_base + Configuration2)) ); | |||
1853 | } | |||
1854 | ||||
1855 | int fdomain_16x0_abort( Scsi_Cmnd *SCpnt) | |||
1856 | { | |||
1857 | unsigned long flags; | |||
1858 | #if EVERY_ACCESS0 || ERRORS_ONLY1 || DEBUG_ABORT1 | |||
1859 | printk( "fdomain: abort " ); | |||
1860 | #endif | |||
1861 | ||||
1862 | save_flags( flags )__asm__ __volatile__("pushf ; pop %0" : "=r" (flags): :"memory" ); | |||
1863 | cli()__asm__ __volatile__ ("cli": : :"memory"); | |||
1864 | if (!in_command) { | |||
| ||||
1865 | #if EVERY_ACCESS0 || ERRORS_ONLY1 | |||
1866 | printk( " (not in command)\n" ); | |||
1867 | #endif | |||
1868 | restore_flags( flags )__asm__ __volatile__("push %0 ; popf": :"g" (flags):"memory"); | |||
1869 | return SCSI_ABORT_NOT_RUNNING4; | |||
1870 | } else printk( "\n" ); | |||
1871 | ||||
1872 | #if DEBUG_ABORT1 | |||
1873 | print_info( SCpnt ); | |||
1874 | #endif | |||
1875 | ||||
1876 | fdomain_make_bus_idle(); | |||
1877 | ||||
1878 | current_SC->SCp.phase |= aborted; | |||
1879 | ||||
1880 | current_SC->result = DID_ABORT0x05 << 16; | |||
1881 | ||||
1882 | restore_flags( flags )__asm__ __volatile__("push %0 ; popf": :"g" (flags):"memory"); | |||
1883 | ||||
1884 | /* Aborts are not done well. . . */ | |||
1885 | my_done( DID_ABORT0x05 << 16 ); | |||
1886 | ||||
1887 | return SCSI_ABORT_SUCCESS1; | |||
1888 | } | |||
1889 | ||||
1890 | int fdomain_16x0_reset( Scsi_Cmnd *SCpnt, unsigned int flags ) | |||
1891 | { | |||
1892 | #if DEBUG_RESET1 | |||
1893 | static int called_once = 0; | |||
1894 | #endif | |||
1895 | ||||
1896 | #if ERRORS_ONLY1 | |||
1897 | if (SCpnt) printk( "fdomain: SCSI Bus Reset\n" ); | |||
1898 | #endif | |||
1899 | ||||
1900 | #if DEBUG_RESET1 | |||
1901 | if (called_once) print_info( current_SC ); | |||
1902 | called_once = 1; | |||
1903 | #endif | |||
1904 | ||||
1905 | outb( 1, SCSI_Cntl_port )((__builtin_constant_p((SCSI_Cntl_port)) && (SCSI_Cntl_port ) < 256) ? __outbc((1),(SCSI_Cntl_port)) : __outb((1),(SCSI_Cntl_port ))); | |||
1906 | do_pause( 2 ); | |||
1907 | outb( 0, SCSI_Cntl_port )((__builtin_constant_p((SCSI_Cntl_port)) && (SCSI_Cntl_port ) < 256) ? __outbc((0),(SCSI_Cntl_port)) : __outb((0),(SCSI_Cntl_port ))); | |||
1908 | do_pause( 115 ); | |||
1909 | outb( 0, SCSI_Mode_Cntl_port )((__builtin_constant_p((SCSI_Mode_Cntl_port)) && (SCSI_Mode_Cntl_port ) < 256) ? __outbc((0),(SCSI_Mode_Cntl_port)) : __outb((0) ,(SCSI_Mode_Cntl_port))); | |||
1910 | outb( PARITY_MASK, TMC_Cntl_port )((__builtin_constant_p((TMC_Cntl_port)) && (TMC_Cntl_port ) < 256) ? __outbc((0x08),(TMC_Cntl_port)) : __outb((0x08) ,(TMC_Cntl_port))); | |||
1911 | ||||
1912 | /* Unless this is the very first call (i.e., SCPnt == NULL), everything | |||
1913 | is probably hosed at this point. We will, however, try to keep | |||
1914 | things going by informing the high-level code that we need help. */ | |||
1915 | ||||
1916 | return SCSI_RESET_WAKEUP4; | |||
1917 | } | |||
1918 | ||||
1919 | #include "sd.h" | |||
1920 | #include <scsi/scsi_ioctl.h> | |||
1921 | ||||
1922 | int fdomain_16x0_biosparam( Scsi_Disk *disk, kdev_t dev, int *info_array ) | |||
1923 | { | |||
1924 | int drive; | |||
1925 | unsigned char buf[512 + sizeof( int ) * 2]; | |||
1926 | int size = disk->capacity; | |||
1927 | int *sizes = (int *)buf; | |||
1928 | unsigned char *data = (unsigned char *)(sizes + 2); | |||
1929 | unsigned char do_read[] = { READ_60x08, 0, 0, 0, 1, 0 }; | |||
1930 | int retcode; | |||
1931 | struct drive_info { | |||
1932 | unsigned short cylinders; | |||
1933 | unsigned char heads; | |||
1934 | unsigned char sectors; | |||
1935 | } *i; | |||
1936 | ||||
1937 | /* NOTES: | |||
1938 | The RAM area starts at 0x1f00 from the bios_base address. | |||
1939 | ||||
1940 | For BIOS Version 2.0: | |||
1941 | ||||
1942 | The drive parameter table seems to start at 0x1f30. | |||
1943 | The first byte's purpose is not known. | |||
1944 | Next is the cylinder, head, and sector information. | |||
1945 | The last 4 bytes appear to be the drive's size in sectors. | |||
1946 | The other bytes in the drive parameter table are unknown. | |||
1947 | If anyone figures them out, please send me mail, and I will | |||
1948 | update these notes. | |||
1949 | ||||
1950 | Tape drives do not get placed in this table. | |||
1951 | ||||
1952 | There is another table at 0x1fea: | |||
1953 | If the byte is 0x01, then the SCSI ID is not in use. | |||
1954 | If the byte is 0x18 or 0x48, then the SCSI ID is in use, | |||
1955 | although tapes don't seem to be in this table. I haven't | |||
1956 | seen any other numbers (in a limited sample). | |||
1957 | ||||
1958 | 0x1f2d is a drive count (i.e., not including tapes) | |||
1959 | ||||
1960 | The table at 0x1fcc are I/O ports addresses for the various | |||
1961 | operations. I calculate these by hand in this driver code. | |||
1962 | ||||
1963 | ||||
1964 | ||||
1965 | For the ISA-200S version of BIOS Version 2.0: | |||
1966 | ||||
1967 | The drive parameter table starts at 0x1f33. | |||
1968 | ||||
1969 | WARNING: Assume that the table entry is 25 bytes long. Someone needs | |||
1970 | to check this for the Quantum ISA-200S card. | |||
1971 | ||||
1972 | ||||
1973 | ||||
1974 | For BIOS Version 3.2: | |||
1975 | ||||
1976 | The drive parameter table starts at 0x1f70. Each entry is | |||
1977 | 0x0a bytes long. Heads are one less than we need to report. | |||
1978 | */ | |||
1979 | ||||
1980 | drive = MINOR(dev)((dev) & ((1<<8) - 1)) / 16; | |||
1981 | ||||
1982 | if (bios_major == 2) { | |||
1983 | switch (Quantum) { | |||
1984 | case 2: /* ISA_200S */ | |||
1985 | /* The value of 25 has never been verified. | |||
1986 | It should probably be 15. */ | |||
1987 | i = (struct drive_info *)( (char *)bios_base + 0x1f33 + drive * 25 ); | |||
1988 | break; | |||
1989 | case 3: /* ISA_250MG */ | |||
1990 | i = (struct drive_info *)( (char *)bios_base + 0x1f36 + drive * 15 ); | |||
1991 | break; | |||
1992 | case 4: /* ISA_200S (another one) */ | |||
1993 | i = (struct drive_info *)( (char *)bios_base + 0x1f34 + drive * 15 ); | |||
1994 | break; | |||
1995 | default: | |||
1996 | i = (struct drive_info *)( (char *)bios_base + 0x1f31 + drive * 25 ); | |||
1997 | break; | |||
1998 | } | |||
1999 | info_array[0] = i->heads; | |||
2000 | info_array[1] = i->sectors; | |||
2001 | info_array[2] = i->cylinders; | |||
2002 | } else if (bios_major == 3 | |||
2003 | && bios_minor >= 0 | |||
2004 | && bios_minor < 4) { /* 3.0 and 3.2 BIOS */ | |||
2005 | i = (struct drive_info *)( (char *)bios_base + 0x1f71 + drive * 10 ); | |||
2006 | info_array[0] = i->heads + 1; | |||
2007 | info_array[1] = i->sectors; | |||
2008 | info_array[2] = i->cylinders; | |||
2009 | } else { /* 3.4 BIOS (and up?) */ | |||
2010 | /* This algorithm was provided by Future Domain (much thanks!). */ | |||
2011 | ||||
2012 | sizes[0] = 0; /* zero bytes out */ | |||
2013 | sizes[1] = 512; /* one sector in */ | |||
2014 | memcpy( data, do_read, sizeof( do_read ) )(__builtin_constant_p(sizeof( do_read )) ? __constant_memcpy( (data),(do_read),(sizeof( do_read ))) : __memcpy((data),(do_read ),(sizeof( do_read )))); | |||
2015 | retcode = kernel_scsi_ioctl( disk->device, | |||
2016 | SCSI_IOCTL_SEND_COMMAND1, | |||
2017 | (void *)buf ); | |||
2018 | if (!retcode /* SCSI command ok */ | |||
2019 | && data[511] == 0xaa && data[510] == 0x55 /* Partition table valid */ | |||
2020 | && data[0x1c2]) { /* Partition type */ | |||
2021 | ||||
2022 | /* The partition table layout is as follows: | |||
2023 | ||||
2024 | Start: 0x1b3h | |||
2025 | Offset: 0 = partition status | |||
2026 | 1 = starting head | |||
2027 | 2 = starting sector and cylinder (word, encoded) | |||
2028 | 4 = partition type | |||
2029 | 5 = ending head | |||
2030 | 6 = ending sector and cylinder (word, encoded) | |||
2031 | 8 = starting absolute sector (double word) | |||
2032 | c = number of sectors (double word) | |||
2033 | Signature: 0x1fe = 0x55aa | |||
2034 | ||||
2035 | So, this algorithm assumes: | |||
2036 | 1) the first partition table is in use, | |||
2037 | 2) the data in the first entry is correct, and | |||
2038 | 3) partitions never divide cylinders | |||
2039 | ||||
2040 | Note that (1) may be FALSE for NetBSD (and other BSD flavors), | |||
2041 | as well as for Linux. Note also, that Linux doesn't pay any | |||
2042 | attention to the fields that are used by this algorithm -- it | |||
2043 | only uses the absolute sector data. Recent versions of Linux's | |||
2044 | fdisk(1) will fill this data in correctly, and forthcoming | |||
2045 | versions will check for consistency. | |||
2046 | ||||
2047 | Checking for a non-zero partition type is not part of the | |||
2048 | Future Domain algorithm, but it seemed to be a reasonable thing | |||
2049 | to do, especially in the Linux and BSD worlds. */ | |||
2050 | ||||
2051 | info_array[0] = data[0x1c3] + 1; /* heads */ | |||
2052 | info_array[1] = data[0x1c4] & 0x3f; /* sectors */ | |||
2053 | } else { | |||
2054 | ||||
2055 | /* Note that this new method guarantees that there will always be | |||
2056 | less than 1024 cylinders on a platter. This is good for drives | |||
2057 | up to approximately 7.85GB (where 1GB = 1024 * 1024 kB). */ | |||
2058 | ||||
2059 | if ((unsigned int)size >= 0x7e0000U) { | |||
2060 | info_array[0] = 0xff; /* heads = 255 */ | |||
2061 | info_array[1] = 0x3f; /* sectors = 63 */ | |||
2062 | } else if ((unsigned int)size >= 0x200000U) { | |||
2063 | info_array[0] = 0x80; /* heads = 128 */ | |||
2064 | info_array[1] = 0x3f; /* sectors = 63 */ | |||
2065 | } else { | |||
2066 | info_array[0] = 0x40; /* heads = 64 */ | |||
2067 | info_array[1] = 0x20; /* sectors = 32 */ | |||
2068 | } | |||
2069 | } | |||
2070 | /* For both methods, compute the cylinders */ | |||
2071 | info_array[2] = (unsigned int)size / (info_array[0] * info_array[1] ); | |||
2072 | } | |||
2073 | ||||
2074 | return 0; | |||
2075 | } | |||
2076 | ||||
2077 | #ifdef MODULE | |||
2078 | /* Eventually this will go into an include file, but this will be later */ | |||
2079 | Scsi_Host_Template driver_template = FDOMAIN_16X0{ ((void *) 0), ((void *) 0), ((void *) 0), fdomain_16x0_proc_info , ((void *) 0), fdomain_16x0_detect, ((void *) 0), fdomain_16x0_info , fdomain_16x0_command, fdomain_16x0_queue, fdomain_16x0_abort , fdomain_16x0_reset, ((void *) 0), fdomain_16x0_biosparam, 1 , 6, 64, 1, 0, 0, 0 }; | |||
2080 | ||||
2081 | #include "scsi_module.c" | |||
2082 | #endif |