| 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 |