fd_mcs.c revision 7d12e780e003f93433d49ce78cfedf4b4c52adc5
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* fd_mcs.c -- Future Domain MCS 600/700 (or IBM OEM) driver
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FutureDomain MCS-600/700 v0.2 03/11/1998 by ZP Gu (zpg@castle.net)
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This driver is cloned from fdomain.* to specifically support
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Future Domain MCS 600/700 MCA SCSI adapters. Some PS/2s
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * also equipped with IBM Fast SCSI Adapter/A which is an OEM
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of MCS 700.
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This driver also supports Reply SB16/SCSI card (the SCSI part).
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * What makes this driver different is that this driver is MCA only
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and it supports multiple adapters in the same system, IRQ
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sharing, some driver statistics, and maps highest SCSI id to sda.
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * All cards are auto-detected.
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Assumptions: TMC-1800/18C50/18C30, BIOS >= 3.4
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * LILO command-line options:
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   fd_mcs=<FIFO_COUNT>[,<FIFO_SIZE>]
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ********************************************************
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Please see Copyrights/Comments in fdomain.* for credits.
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Following is from fdomain.c for acknowledgement:
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Created: Sun May  3 18:53:19 1992 by faith@cs.unc.edu
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revised: Wed Oct  2 11:10:55 1996 by r.faith@ieee.org
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Author: Rickard E. Faith, faith@cs.unc.edu
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright 1992, 1993, 1994, 1995, 1996 Rickard E. Faith
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * $Id: fdomain.c,v 5.45 1996/10/02 15:13:06 root Exp $
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify it
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * under the terms of the GNU General Public License as published by the
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Free Software Foundation; either version 2, or (at your option) any
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * later version.
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, but
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * WITHOUT ANY WARRANTY; without even the implied warranty of
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * General Public License for more details.
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License along
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with this program; if not, write to the Free Software Foundation, Inc.,
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 675 Mass Ave, Cambridge, MA 02139, USA.
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds **************************************************************************
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NOTES ON USER DEFINABLE OPTIONS:
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DEBUG: This turns on the printing of various debug information.
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ENABLE_PARITY: This turns on SCSI parity checking.  With the current
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds driver, all attached devices must support SCSI parity.  If none of your
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devices support parity, then you can probably get the driver to work by
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds turning this option off.  I have no way of testing this, however, and it
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds would appear that no one ever uses this option.
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FIFO_COUNT: The host adapter has an 8K cache (host adapters based on the
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18C30 chip have a 2k cache).  When this many 512 byte blocks are filled by
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the SCSI device, an interrupt will be raised.  Therefore, this could be as
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds low as 0, or as high as 16.  Note, however, that values which are too high
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds or too low seem to prevent any interrupts from occurring, and thereby lock
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up the machine.  I have found that 2 is a good number, but throughput may
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds be increased by changing this value to values which are close to 2.
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Please let me know if you try any different values.
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds [*****Now a runtime option*****]
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds RESELECTION: This is no longer an option, since I gave up trying to
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds implement it in version 4.x of this driver.  It did not improve
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds performance at all and made the driver unstable (because I never found one
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds of the two race conditions which were introduced by the multiple
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outstanding command code).  The instability seems a very high price to pay
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds just so that you don't have to wait for the tape to rewind.  If you want
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds this feature implemented, send me patches.  I'll be happy to send a copy
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds of my (broken) driver to anyone who would like to see a copy.
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds **************************************************************************/
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/blkdev.h>
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/proc_fs.h>
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mca.h>
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h>
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsicam.h>
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mca-legacy.h>
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.h>
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "scsi.h"
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi_host.h>
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_VERSION "v0.2 by ZP Gu<zpg@castle.net>"
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* START OF USER DEFINABLE OPTIONS */
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEBUG            0	/* Enable debugging output */
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ENABLE_PARITY    1	/* Enable SCSI Parity */
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* END OF USER DEFINABLE OPTIONS */
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if DEBUG
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EVERY_ACCESS     0	/* Write a line on every scsi access */
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ERRORS_ONLY      1	/* Only write a line if there is an error */
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEBUG_MESSAGES   1	/* Debug MESSAGE IN phase */
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEBUG_ABORT      1	/* Debug abort() routine */
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEBUG_RESET      1	/* Debug reset() routine */
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEBUG_RACE       1	/* Debug interrupt-driven race condition */
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EVERY_ACCESS     0	/* LEAVE THESE ALONE--CHANGE THE ONES ABOVE */
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ERRORS_ONLY      0
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEBUG_MESSAGES   0
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEBUG_ABORT      0
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEBUG_RESET      0
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEBUG_RACE       0
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Errors are reported on the line, so we don't need to report them again */
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if EVERY_ACCESS
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef ERRORS_ONLY
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ERRORS_ONLY      0
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if ENABLE_PARITY
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PARITY_MASK      0x08
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PARITY_MASK      0x00
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum chip_type {
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unknown = 0x00,
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmc1800 = 0x01,
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmc18c50 = 0x02,
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmc18c30 = 0x03,
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum {
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	in_arbitration = 0x02,
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	in_selection = 0x04,
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	in_other = 0x08,
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	disconnect = 0x10,
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	aborted = 0x20,
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sent_ident = 0x40,
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum in_port_type {
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Read_SCSI_Data = 0,
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SCSI_Status = 1,
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	TMC_Status = 2,
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FIFO_Status = 3,	/* tmc18c50/tmc18c30 only */
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Interrupt_Cond = 4,	/* tmc18c50/tmc18c30 only */
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	LSB_ID_Code = 5,
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MSB_ID_Code = 6,
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Read_Loopback = 7,
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SCSI_Data_NoACK = 8,
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Interrupt_Status = 9,
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Configuration1 = 10,
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Configuration2 = 11,	/* tmc18c50/tmc18c30 only */
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Read_FIFO = 12,
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FIFO_Data_Count = 14
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum out_port_type {
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Write_SCSI_Data = 0,
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SCSI_Cntl = 1,
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Interrupt_Cntl = 2,
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SCSI_Mode_Cntl = 3,
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	TMC_Cntl = 4,
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Memory_Cntl = 5,	/* tmc18c50/tmc18c30 only */
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Write_Loopback = 7,
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IO_Control = 11,	/* tmc18c30 only */
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Write_FIFO = 12
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct fd_hostdata {
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long _bios_base;
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int _bios_major;
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int _bios_minor;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile int _in_command;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Scsi_Cmnd *_current_SC;
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enum chip_type _chip;
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int _adapter_mask;
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int _fifo_count;	/* Number of 512 byte blocks before INTR */
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char _adapter_name[64];
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if DEBUG_RACE
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile int _in_interrupt_flag;
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int _SCSI_Mode_Cntl_port;
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int _FIFO_Data_Count_port;
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int _Interrupt_Cntl_port;
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int _Interrupt_Status_port;
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int _Interrupt_Cond_port;
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int _Read_FIFO_port;
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int _Read_SCSI_Data_port;
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int _SCSI_Cntl_port;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int _SCSI_Data_NoACK_port;
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int _SCSI_Status_port;
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int _TMC_Cntl_port;
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int _TMC_Status_port;
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int _Write_FIFO_port;
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int _Write_SCSI_Data_port;
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int _FIFO_Size;		/* = 0x2000;  8k FIFO for
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   pre-tmc18c30 chips */
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* simple stats */
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int _Bytes_Read;
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int _Bytes_Written;
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int _INTR_Processed;
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FD_MAX_HOSTS 3		/* enough? */
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define HOSTDATA(shpnt) ((struct fd_hostdata *) shpnt->hostdata)
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define bios_base             (HOSTDATA(shpnt)->_bios_base)
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define bios_major            (HOSTDATA(shpnt)->_bios_major)
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define bios_minor            (HOSTDATA(shpnt)->_bios_minor)
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define in_command            (HOSTDATA(shpnt)->_in_command)
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define current_SC            (HOSTDATA(shpnt)->_current_SC)
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define chip                  (HOSTDATA(shpnt)->_chip)
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define adapter_mask          (HOSTDATA(shpnt)->_adapter_mask)
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FIFO_COUNT            (HOSTDATA(shpnt)->_fifo_count)
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define adapter_name          (HOSTDATA(shpnt)->_adapter_name)
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if DEBUG_RACE
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define in_interrupt_flag     (HOSTDATA(shpnt)->_in_interrupt_flag)
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SCSI_Mode_Cntl_port   (HOSTDATA(shpnt)->_SCSI_Mode_Cntl_port)
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FIFO_Data_Count_port  (HOSTDATA(shpnt)->_FIFO_Data_Count_port)
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Interrupt_Cntl_port   (HOSTDATA(shpnt)->_Interrupt_Cntl_port)
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Interrupt_Status_port (HOSTDATA(shpnt)->_Interrupt_Status_port)
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Interrupt_Cond_port   (HOSTDATA(shpnt)->_Interrupt_Cond_port)
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Read_FIFO_port        (HOSTDATA(shpnt)->_Read_FIFO_port)
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Read_SCSI_Data_port   (HOSTDATA(shpnt)->_Read_SCSI_Data_port)
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SCSI_Cntl_port        (HOSTDATA(shpnt)->_SCSI_Cntl_port)
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SCSI_Data_NoACK_port  (HOSTDATA(shpnt)->_SCSI_Data_NoACK_port)
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SCSI_Status_port      (HOSTDATA(shpnt)->_SCSI_Status_port)
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMC_Cntl_port         (HOSTDATA(shpnt)->_TMC_Cntl_port)
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMC_Status_port       (HOSTDATA(shpnt)->_TMC_Status_port)
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Write_FIFO_port       (HOSTDATA(shpnt)->_Write_FIFO_port)
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Write_SCSI_Data_port  (HOSTDATA(shpnt)->_Write_SCSI_Data_port)
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FIFO_Size             (HOSTDATA(shpnt)->_FIFO_Size)
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Bytes_Read            (HOSTDATA(shpnt)->_Bytes_Read)
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Bytes_Written         (HOSTDATA(shpnt)->_Bytes_Written)
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define INTR_Processed        (HOSTDATA(shpnt)->_INTR_Processed)
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct fd_mcs_adapters_struct {
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *name;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int id;
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enum chip_type fd_chip;
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int fifo_size;
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int fifo_count;
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define REPLY_ID 0x5137
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct fd_mcs_adapters_struct fd_mcs_adapters[] = {
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{"Future Domain SCSI Adapter MCS-700(18C50)",
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 0x60e9,
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 tmc18c50,
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 0x2000,
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 4},
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{"Future Domain SCSI Adapter MCS-600/700(TMC-1800)",
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 0x6127,
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 tmc1800,
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 0x2000,
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 4},
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{"Reply Sound Blaster/SCSI Adapter",
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 REPLY_ID,
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 tmc18c30,
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 0x800,
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 2},
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2826391a11375de5e2bb1eb8481e54619761dc65d9fTobias Klauser#define FD_BRDS ARRAY_SIZE(fd_mcs_adapters)
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2847d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t fd_mcs_intr(int irq, void *dev_id);
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long addresses[] = { 0xc8000, 0xca000, 0xce000, 0xde000 };
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 };
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned short interrupts[] = { 3, 5, 10, 11, 12, 14, 15, 0 };
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* host information */
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int found = 0;
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct Scsi_Host *hosts[FD_MAX_HOSTS + 1] = { NULL };
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int user_fifo_count = 0;
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int user_fifo_size = 0;
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init fd_mcs_setup(char *str)
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static int done_setup = 0;
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ints[3];
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	get_options(str, 3, ints);
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (done_setup++ || ints[0] < 1 || ints[0] > 2 || ints[1] < 1 || ints[1] > 16) {
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("fd_mcs: usage: fd_mcs=FIFO_COUNT, FIFO_SIZE\n");
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	user_fifo_count = ints[0] >= 1 ? ints[1] : 0;
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	user_fifo_size = ints[0] >= 2 ? ints[2] : 0;
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds__setup("fd_mcs=", fd_mcs_setup);
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void print_banner(struct Scsi_Host *shpnt)
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("scsi%d <fd_mcs>: ", shpnt->host_no);
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bios_base) {
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("BIOS at 0x%lX", bios_base);
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("No BIOS");
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(", HostID %d, %s Chip, IRQ %d, IO 0x%lX\n", shpnt->this_id, chip == tmc18c50 ? "TMC-18C50" : (chip == tmc18c30 ? "TMC-18C30" : (chip == tmc1800 ? "TMC-1800" : "Unknown")), shpnt->irq, shpnt->io_port);
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void do_pause(unsigned amount)
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{				/* Pause for amount*10 milliseconds */
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mdelay(10);
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while (--amount);
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void fd_mcs_make_bus_idle(struct Scsi_Host *shpnt)
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0, SCSI_Cntl_port);
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0, SCSI_Mode_Cntl_port);
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (chip == tmc18c50 || chip == tmc18c30)
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(0x21 | PARITY_MASK, TMC_Cntl_port);	/* Clear forced intr. */
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(0x01 | PARITY_MASK, TMC_Cntl_port);
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
346d0be4a7d29ad0bd3ce2209dd9e46d410b632db59Christoph Hellwigstatic int fd_mcs_detect(struct scsi_host_template * tpnt)
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int loop;
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Scsi_Host *shpnt;
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* get id, port, bios, irq */
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int slot;
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char pos2, pos3, pos4;
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int id, port, irq;
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long bios;
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* if not MCA machine, return */
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!MCA_bus)
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* changeable? */
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	id = 7;
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (loop = 0; loop < FD_BRDS; loop++) {
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		slot = 0;
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (MCA_NOTFOUND != (slot = mca_find_adapter(fd_mcs_adapters[loop].id, slot))) {
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* if we get this far, an adapter has been detected and is
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   enabled */
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_INFO "scsi  <fd_mcs>: %s at slot %d\n", fd_mcs_adapters[loop].name, slot + 1);
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pos2 = mca_read_stored_pos(slot, 2);
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pos3 = mca_read_stored_pos(slot, 3);
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pos4 = mca_read_stored_pos(slot, 4);
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* ready for next probe */
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			slot++;
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (fd_mcs_adapters[loop].id == REPLY_ID) {	/* reply card */
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				static int reply_irq[] = { 10, 11, 14, 15 };
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bios = 0;	/* no bios */
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (pos2 & 0x2)
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					port = ports[pos4 & 0x3];
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					continue;
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* can't really disable it, same as irq=10 */
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				irq = reply_irq[((pos4 >> 2) & 0x1) + 2 * ((pos4 >> 4) & 0x1)];
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bios = addresses[pos2 >> 6];
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				port = ports[(pos2 >> 4) & 0x03];
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				irq = interrupts[(pos2 >> 1) & 0x07];
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (irq) {
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* claim the slot */
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				mca_set_adapter_name(slot - 1, fd_mcs_adapters[loop].name);
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* check irq/region */
4031d6f359a2e06296418481239f8054a878f36e819Thomas Gleixner				if (request_irq(irq, fd_mcs_intr, IRQF_SHARED, "fd_mcs", hosts)) {
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printk(KERN_ERR "fd_mcs: interrupt is not available, skipping...\n");
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					continue;
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* request I/O region */
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (request_region(port, 0x10, "fd_mcs")) {
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printk(KERN_ERR "fd_mcs: I/O region is already in use, skipping...\n");
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					continue;
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* register */
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!(shpnt = scsi_register(tpnt, sizeof(struct fd_hostdata)))) {
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printk(KERN_ERR "fd_mcs: scsi_register() failed\n");
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					release_region(port, 0x10);
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					free_irq(irq, hosts);
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					continue;
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* save name */
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				strcpy(adapter_name, fd_mcs_adapters[loop].name);
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* chip/fifo */
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				chip = fd_mcs_adapters[loop].fd_chip;
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* use boot time value if available */
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				FIFO_COUNT = user_fifo_count ? user_fifo_count : fd_mcs_adapters[loop].fifo_count;
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				FIFO_Size = user_fifo_size ? user_fifo_size : fd_mcs_adapters[loop].fifo_size;
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* FIXME: Do we need to keep this bit of code inside NOT_USED around at all? */
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef NOT_USED
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* *************************************************** */
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* Try to toggle 32-bit mode.  This only
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   works on an 18c30 chip.  (User reports
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   say this works, so we should switch to
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   it in the near future.) */
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				outb(0x80, port + IO_Control);
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if ((inb(port + Configuration2) & 0x80) == 0x80) {
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					outb(0x00, port + IO_Control);
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if ((inb(port + Configuration2) & 0x80) == 0x00) {
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						chip = tmc18c30;
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						FIFO_Size = 0x800;	/* 2k FIFO */
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						printk("FIRST: chip=%s, fifo_size=0x%x\n", (chip == tmc18c30) ? "tmc18c30" : "tmc18c50", FIFO_Size);
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* That should have worked, but appears to
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   have problems.  Let's assume it is an
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   18c30 if the RAM is disabled. */
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (inb(port + Configuration2) & 0x02) {
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					chip = tmc18c30;
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					FIFO_Size = 0x800;	/* 2k FIFO */
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printk("SECOND: chip=%s, fifo_size=0x%x\n", (chip == tmc18c30) ? "tmc18c30" : "tmc18c50", FIFO_Size);
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* *************************************************** */
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* IBM/ANSI scsi scan ordering */
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* Stick this back in when the scsi.c changes are there */
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				shpnt->reverse_ordering = 1;
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* saving info */
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				hosts[found++] = shpnt;
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				shpnt->this_id = id;
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				shpnt->irq = irq;
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				shpnt->io_port = port;
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				shpnt->n_io_port = 0x10;
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* save */
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bios_base = bios;
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				adapter_mask = (1 << id);
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* save more */
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				SCSI_Mode_Cntl_port = port + SCSI_Mode_Cntl;
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				FIFO_Data_Count_port = port + FIFO_Data_Count;
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				Interrupt_Cntl_port = port + Interrupt_Cntl;
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				Interrupt_Status_port = port + Interrupt_Status;
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				Interrupt_Cond_port = port + Interrupt_Cond;
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				Read_FIFO_port = port + Read_FIFO;
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				Read_SCSI_Data_port = port + Read_SCSI_Data;
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				SCSI_Cntl_port = port + SCSI_Cntl;
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				SCSI_Data_NoACK_port = port + SCSI_Data_NoACK;
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				SCSI_Status_port = port + SCSI_Status;
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				TMC_Cntl_port = port + TMC_Cntl;
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				TMC_Status_port = port + TMC_Status;
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				Write_FIFO_port = port + Write_FIFO;
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				Write_SCSI_Data_port = port + Write_SCSI_Data;
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				Bytes_Read = 0;
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				Bytes_Written = 0;
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				INTR_Processed = 0;
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* say something */
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				print_banner(shpnt);
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* reset */
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				outb(1, SCSI_Cntl_port);
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				do_pause(2);
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				outb(0, SCSI_Cntl_port);
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				do_pause(115);
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				outb(0, SCSI_Mode_Cntl_port);
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				outb(PARITY_MASK, TMC_Cntl_port);
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* done reset */
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (found == FD_MAX_HOSTS) {
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("fd_mcs: detecting reached max=%d host adapters.\n", FD_MAX_HOSTS);
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return found;
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char *fd_mcs_info(struct Scsi_Host *shpnt)
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return adapter_name;
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int TOTAL_INTR = 0;
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * inout : decides on the direction of the dataflow and the meaning of the
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *         variables
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * buffer: If inout==FALSE data is being written to it else read from it
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * *start: If inout==FALSE start of the valid data in the buffer
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * offset: If inout==FALSE offset from the beginning of the imaginary file
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *         from which we start writing into the buffer
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * length: If inout==FALSE max number of bytes to be written into the buffer
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *         else number of bytes in the buffer
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int fd_mcs_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start, off_t offset, int length, int inout)
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int len = 0;
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (inout)
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (-ENOSYS);
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*start = buffer + offset;
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len += sprintf(buffer + len, "Future Domain MCS-600/700 Driver %s\n", DRIVER_VERSION);
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len += sprintf(buffer + len, "HOST #%d: %s\n", shpnt->host_no, adapter_name);
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len += sprintf(buffer + len, "FIFO Size=0x%x, FIFO Count=%d\n", FIFO_Size, FIFO_COUNT);
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len += sprintf(buffer + len, "DriverCalls=%d, Interrupts=%d, BytesRead=%d, BytesWrite=%d\n\n", TOTAL_INTR, INTR_Processed, Bytes_Read, Bytes_Written);
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((len -= offset) <= 0)
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (len > length)
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len = length;
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return len;
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int fd_mcs_select(struct Scsi_Host *shpnt, int target)
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int status;
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long timeout;
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x82, SCSI_Cntl_port);	/* Bus Enable + Select */
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(adapter_mask | (1 << target), SCSI_Data_NoACK_port);
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Stop arbitration and enable parity */
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(PARITY_MASK, TMC_Cntl_port);
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timeout = 350;		/* 350mS -- because of timeouts
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   (was 250mS) */
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = inb(SCSI_Status_port);	/* Read adapter status */
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (status & 1) {	/* Busy asserted */
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Enable SCSI Bus (on error, should make bus idle with 0) */
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb(0x80, SCSI_Cntl_port);
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		udelay(1000);	/* wait one msec */
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while (--timeout);
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Make bus idle */
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fd_mcs_make_bus_idle(shpnt);
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if EVERY_ACCESS
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!target)
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("Selection failed\n");
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if ERRORS_ONLY
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!target) {
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		static int flag = 0;
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!flag)	/* Skip first failure for all chips. */
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			++flag;
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("fd_mcs: Selection failed\n");
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void my_done(struct Scsi_Host *shpnt, int error)
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (in_command) {
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		in_command = 0;
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(0x00, Interrupt_Cntl_port);
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fd_mcs_make_bus_idle(shpnt);
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		current_SC->result = error;
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		current_SC->scsi_done(current_SC);
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		panic("fd_mcs: my_done() called outside of command\n");
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if DEBUG_RACE
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	in_interrupt_flag = 0;
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* only my_done needs to be protected  */
6207d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t fd_mcs_intr(int irq, void *dev_id)
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int status;
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int done = 0;
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned data_count, tmp_count;
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i = 0;
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Scsi_Host *shpnt;
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	TOTAL_INTR++;
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* search for one adapter-response on shared interrupt */
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((shpnt = hosts[i++])) {
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((inb(TMC_Status_port)) & 1)
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* return if some other device on this IRQ caused the interrupt */
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!shpnt) {
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return IRQ_NONE;
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	INTR_Processed++;
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x00, Interrupt_Cntl_port);
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Abort calls my_done, so we do nothing here. */
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (current_SC->SCp.phase & aborted) {
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if DEBUG_ABORT
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("Interrupt after abort, ignoring\n");
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* return IRQ_HANDLED; */
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if DEBUG_RACE
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	++in_interrupt_flag;
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (current_SC->SCp.phase & in_arbitration) {
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = inb(TMC_Status_port);	/* Read adapter status */
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(status & 0x02)) {
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if EVERY_ACCESS
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(" AFAIL ");
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_lock_irqsave(shpnt->host_lock, flags);
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			my_done(shpnt, DID_BUS_BUSY << 16);
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_unlock_irqrestore(shpnt->host_lock, flags);
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return IRQ_HANDLED;
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		current_SC->SCp.phase = in_selection;
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(0x40 | FIFO_COUNT, Interrupt_Cntl_port);
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(0x82, SCSI_Cntl_port);	/* Bus Enable + Select */
674422c0d61d591cbfb70f029e13505fb437e169d68Jeff Garzik		outb(adapter_mask | (1 << scmd_id(current_SC)), SCSI_Data_NoACK_port);
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Stop arbitration and enable parity */
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(0x10 | PARITY_MASK, TMC_Cntl_port);
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if DEBUG_RACE
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		in_interrupt_flag = 0;
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return IRQ_HANDLED;
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (current_SC->SCp.phase & in_selection) {
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = inb(SCSI_Status_port);
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(status & 0x01)) {
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Try again, for slow devices */
686422c0d61d591cbfb70f029e13505fb437e169d68Jeff Garzik			if (fd_mcs_select(shpnt, scmd_id(current_SC))) {
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if EVERY_ACCESS
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk(" SFAIL ");
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_lock_irqsave(shpnt->host_lock, flags);
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				my_done(shpnt, DID_NO_CONNECT << 16);
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_unlock_irqrestore(shpnt->host_lock, flags);
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return IRQ_HANDLED;
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if EVERY_ACCESS
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk(" AltSel ");
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* Stop arbitration and enable parity */
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				outb(0x10 | PARITY_MASK, TMC_Cntl_port);
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		current_SC->SCp.phase = in_other;
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(0x90 | FIFO_COUNT, Interrupt_Cntl_port);
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(0x80, SCSI_Cntl_port);
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if DEBUG_RACE
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		in_interrupt_flag = 0;
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return IRQ_HANDLED;
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* current_SC->SCp.phase == in_other: this is the body of the routine */
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = inb(SCSI_Status_port);
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & 0x10) {	/* REQ */
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (status & 0x0e) {
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x08:	/* COMMAND OUT */
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb(current_SC->cmnd[current_SC->SCp.sent_command++], Write_SCSI_Data_port);
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if EVERY_ACCESS
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("CMD = %x,", current_SC->cmnd[current_SC->SCp.sent_command - 1]);
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x00:	/* DATA OUT -- tmc18c50/tmc18c30 only */
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (chip != tmc1800 && !current_SC->SCp.have_data_in) {
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				current_SC->SCp.have_data_in = -1;
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				outb(0xd0 | PARITY_MASK, TMC_Cntl_port);
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x04:	/* DATA IN -- tmc18c50/tmc18c30 only */
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (chip != tmc1800 && !current_SC->SCp.have_data_in) {
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				current_SC->SCp.have_data_in = 1;
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				outb(0x90 | PARITY_MASK, TMC_Cntl_port);
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x0c:	/* STATUS IN */
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			current_SC->SCp.Status = inb(Read_SCSI_Data_port);
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if EVERY_ACCESS
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("Status = %x, ", current_SC->SCp.Status);
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if ERRORS_ONLY
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (current_SC->SCp.Status && current_SC->SCp.Status != 2 && current_SC->SCp.Status != 8) {
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk("ERROR fd_mcs: target = %d, command = %x, status = %x\n", current_SC->device->id, current_SC->cmnd[0], current_SC->SCp.Status);
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x0a:	/* MESSAGE OUT */
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb(MESSAGE_REJECT, Write_SCSI_Data_port);	/* Reject */
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x0e:	/* MESSAGE IN */
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			current_SC->SCp.Message = inb(Read_SCSI_Data_port);
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if EVERY_ACCESS
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("Message = %x, ", current_SC->SCp.Message);
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!current_SC->SCp.Message)
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				++done;
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if DEBUG_MESSAGES || EVERY_ACCESS
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (current_SC->SCp.Message) {
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk("fd_mcs: message = %x\n", current_SC->SCp.Message);
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (chip == tmc1800 && !current_SC->SCp.have_data_in && (current_SC->SCp.sent_command >= current_SC->cmd_len)) {
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* We have to get the FIFO direction
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   correct, so I've made a table based
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   on the SCSI Standard of which commands
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   appear to require a DATA OUT phase.
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   p. 94: Command for all device types
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   CHANGE DEFINITION            40 DATA OUT
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   COMPARE                      39 DATA OUT
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   COPY                         18 DATA OUT
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   COPY AND VERIFY              3a DATA OUT
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   INQUIRY                      12
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   LOG SELECT                   4c DATA OUT
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   LOG SENSE                    4d
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   MODE SELECT (6)              15 DATA OUT
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   MODE SELECT (10)             55 DATA OUT
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   MODE SENSE (6)               1a
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   MODE SENSE (10)              5a
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   READ BUFFER                  3c
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   RECEIVE DIAGNOSTIC RESULTS   1c
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   REQUEST SENSE                03
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   SEND DIAGNOSTIC              1d DATA OUT
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   TEST UNIT READY              00
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   WRITE BUFFER                 3b DATA OUT
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   p.178: Commands for direct-access devices (not listed on p. 94)
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   FORMAT UNIT                  04 DATA OUT
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   LOCK-UNLOCK CACHE            36
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   PRE-FETCH                    34
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   PREVENT-ALLOW MEDIUM REMOVAL 1e
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   READ (6)/RECEIVE             08
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   READ (10)                    3c
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   READ CAPACITY                25
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   READ DEFECT DATA (10)        37
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   READ LONG                    3e
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   REASSIGN BLOCKS              07 DATA OUT
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   RELEASE                      17
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   RESERVE                      16 DATA OUT
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   REZERO UNIT/REWIND           01
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   SEARCH DATA EQUAL (10)       31 DATA OUT
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   SEARCH DATA HIGH (10)        30 DATA OUT
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   SEARCH DATA LOW (10)         32 DATA OUT
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   SEEK (6)                     0b
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   SEEK (10)                    2b
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   SET LIMITS (10)              33
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   START STOP UNIT              1b
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   SYNCHRONIZE CACHE            35
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   VERIFY (10)                  2f
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   WRITE (6)/PRINT/SEND         0a DATA OUT
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   WRITE (10)/SEND              2a DATA OUT
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   WRITE AND VERIFY (10)        2e DATA OUT
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   WRITE LONG                   3f DATA OUT
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   WRITE SAME                   41 DATA OUT ?
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   p. 261: Commands for sequential-access devices (not previously listed)
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   ERASE                        19
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   LOAD UNLOAD                  1b
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   LOCATE                       2b
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   READ BLOCK LIMITS            05
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   READ POSITION                34
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   READ REVERSE                 0f
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   RECOVER BUFFERED DATA        14
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   SPACE                        11
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   WRITE FILEMARKS              10 ?
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   p. 298: Commands for printer devices (not previously listed)
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   ****** NOT SUPPORTED BY THIS DRIVER, since 0b is SEEK (6) *****
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   SLEW AND PRINT               0b DATA OUT  -- same as seek
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   STOP PRINT                   1b
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   SYNCHRONIZE BUFFER           10
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   p. 315: Commands for processor devices (not previously listed)
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   p. 321: Commands for write-once devices (not previously listed)
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   MEDIUM SCAN                  38
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   READ (12)                    a8
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   SEARCH DATA EQUAL (12)       b1 DATA OUT
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   SEARCH DATA HIGH (12)        b0 DATA OUT
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   SEARCH DATA LOW (12)         b2 DATA OUT
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   SET LIMITS (12)              b3
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   VERIFY (12)                  af
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   WRITE (12)                   aa DATA OUT
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   WRITE AND VERIFY (12)        ae DATA OUT
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   p. 332: Commands for CD-ROM devices (not previously listed)
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   PAUSE/RESUME                 4b
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   PLAY AUDIO (10)              45
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   PLAY AUDIO (12)              a5
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   PLAY AUDIO MSF               47
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   PLAY TRACK RELATIVE (10)     49
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   PLAY TRACK RELATIVE (12)     a9
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   READ HEADER                  44
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   READ SUB-CHANNEL             42
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   READ TOC                     43
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   p. 370: Commands for scanner devices (not previously listed)
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   GET DATA BUFFER STATUS       34
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   GET WINDOW                   25
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   OBJECT POSITION              31
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   SCAN                         1b
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   SET WINDOW                   24 DATA OUT
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   p. 391: Commands for optical memory devices (not listed)
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   ERASE (10)                   2c
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   ERASE (12)                   ac
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   MEDIUM SCAN                  38 DATA OUT
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   READ DEFECT DATA (12)        b7
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   READ GENERATION              29
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   READ UPDATED BLOCK           2d
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   UPDATE BLOCK                 3d DATA OUT
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   p. 419: Commands for medium changer devices (not listed)
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   EXCHANGE MEDIUM              46
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   INITIALIZE ELEMENT STATUS    07
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   MOVE MEDIUM                  a5
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   POSITION TO ELEMENT          2b
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   READ ELEMENT STATUS          b8
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   REQUEST VOL. ELEMENT ADDRESS b5
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   SEND VOLUME TAG              b6 DATA OUT
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   p. 454: Commands for communications devices (not listed previously)
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   GET MESSAGE (6)              08
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   GET MESSAGE (10)             28
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   GET MESSAGE (12)             a8
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (current_SC->cmnd[0]) {
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case CHANGE_DEFINITION:
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case COMPARE:
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case COPY:
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case COPY_VERIFY:
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case LOG_SELECT:
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case MODE_SELECT:
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case MODE_SELECT_10:
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SEND_DIAGNOSTIC:
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case WRITE_BUFFER:
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case FORMAT_UNIT:
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case REASSIGN_BLOCKS:
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case RESERVE:
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SEARCH_EQUAL:
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SEARCH_HIGH:
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SEARCH_LOW:
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case WRITE_6:
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case WRITE_10:
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case WRITE_VERIFY:
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x3f:
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x41:
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0xb1:
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0xb0:
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0xb2:
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0xaa:
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0xae:
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x24:
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x38:
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x3d:
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0xb6:
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0xea:	/* alternate number for WRITE LONG */
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			current_SC->SCp.have_data_in = -1;
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb(0xd0 | PARITY_MASK, TMC_Cntl_port);
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x00:
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			current_SC->SCp.have_data_in = 1;
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb(0x90 | PARITY_MASK, TMC_Cntl_port);
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (current_SC->SCp.have_data_in == -1) {	/* DATA OUT */
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while ((data_count = FIFO_Size - inw(FIFO_Data_Count_port)) > 512) {
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if EVERY_ACCESS
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("DC=%d, ", data_count);
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (data_count > current_SC->SCp.this_residual)
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				data_count = current_SC->SCp.this_residual;
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (data_count > 0) {
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if EVERY_ACCESS
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk("%d OUT, ", data_count);
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (data_count == 1) {
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					Bytes_Written++;
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					outb(*current_SC->SCp.ptr++, Write_FIFO_port);
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					--current_SC->SCp.this_residual;
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else {
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					data_count >>= 1;
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					tmp_count = data_count << 1;
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					outsw(Write_FIFO_port, current_SC->SCp.ptr, data_count);
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					current_SC->SCp.ptr += tmp_count;
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					Bytes_Written += tmp_count;
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					current_SC->SCp.this_residual -= tmp_count;
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!current_SC->SCp.this_residual) {
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (current_SC->SCp.buffers_residual) {
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					--current_SC->SCp.buffers_residual;
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					++current_SC->SCp.buffer;
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page) + current_SC->SCp.buffer->offset;
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (current_SC->SCp.have_data_in == 1) {	/* DATA IN */
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while ((data_count = inw(FIFO_Data_Count_port)) > 0) {
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if EVERY_ACCESS
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("DC=%d, ", data_count);
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (data_count > current_SC->SCp.this_residual)
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				data_count = current_SC->SCp.this_residual;
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (data_count) {
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if EVERY_ACCESS
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk("%d IN, ", data_count);
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (data_count == 1) {
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					Bytes_Read++;
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					*current_SC->SCp.ptr++ = inb(Read_FIFO_port);
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					--current_SC->SCp.this_residual;
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else {
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					data_count >>= 1;	/* Number of words */
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					tmp_count = data_count << 1;
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					insw(Read_FIFO_port, current_SC->SCp.ptr, data_count);
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					current_SC->SCp.ptr += tmp_count;
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					Bytes_Read += tmp_count;
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					current_SC->SCp.this_residual -= tmp_count;
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!current_SC->SCp.this_residual && current_SC->SCp.buffers_residual) {
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				--current_SC->SCp.buffers_residual;
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				++current_SC->SCp.buffer;
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page) + current_SC->SCp.buffer->offset;
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (done) {
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if EVERY_ACCESS
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(" ** IN DONE %d ** ", current_SC->SCp.have_data_in);
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if ERRORS_ONLY
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (current_SC->cmnd[0] == REQUEST_SENSE && !current_SC->SCp.Status) {
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((unsigned char) (*((char *) current_SC->request_buffer + 2)) & 0x0f) {
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unsigned char key;
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unsigned char code;
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unsigned char qualifier;
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				key = (unsigned char) (*((char *) current_SC->request_buffer + 2)) & 0x0f;
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				code = (unsigned char) (*((char *) current_SC->request_buffer + 12));
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				qualifier = (unsigned char) (*((char *) current_SC->request_buffer + 13));
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (key != UNIT_ATTENTION && !(key == NOT_READY && code == 0x04 && (!qualifier || qualifier == 0x02 || qualifier == 0x01))
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    && !(key == ILLEGAL_REQUEST && (code == 0x25 || code == 0x24 || !code)))
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printk("fd_mcs: REQUEST SENSE " "Key = %x, Code = %x, Qualifier = %x\n", key, code, qualifier);
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if EVERY_ACCESS
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("BEFORE MY_DONE. . .");
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock_irqsave(shpnt->host_lock, flags);
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		my_done(shpnt, (current_SC->SCp.Status & 0xff)
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			| ((current_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16));
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(shpnt->host_lock, flags);
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if EVERY_ACCESS
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("RETURNING.\n");
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (current_SC->SCp.phase & disconnect) {
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb(0xd0 | FIFO_COUNT, Interrupt_Cntl_port);
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb(0x00, SCSI_Cntl_port);
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb(0x90 | FIFO_COUNT, Interrupt_Cntl_port);
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if DEBUG_RACE
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	in_interrupt_flag = 0;
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return IRQ_HANDLED;
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int fd_mcs_release(struct Scsi_Host *shpnt)
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, this_host, irq_usage;
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_region(shpnt->io_port, shpnt->n_io_port);
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	this_host = -1;
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	irq_usage = 0;
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < found; i++) {
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (shpnt == hosts[i])
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			this_host = i;
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (shpnt->irq == hosts[i]->irq)
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			irq_usage++;
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* only for the last one */
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (1 == irq_usage)
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free_irq(shpnt->irq, hosts);
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	found--;
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = this_host; i < found; i++)
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hosts[i] = hosts[i + 1];
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hosts[found] = NULL;
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int fd_mcs_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Scsi_Host *shpnt = SCpnt->device->host;
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (in_command) {
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		panic("fd_mcs: fd_mcs_queue() NOT REENTRANT!\n");
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if EVERY_ACCESS
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n", SCpnt->target, *(unsigned char *) SCpnt->cmnd, SCpnt->use_sg, SCpnt->request_bufflen);
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fd_mcs_make_bus_idle(shpnt);
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SCpnt->scsi_done = done;	/* Save this for the done function */
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	current_SC = SCpnt;
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Initialize static data */
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (current_SC->use_sg) {
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		current_SC->SCp.buffer = (struct scatterlist *) current_SC->request_buffer;
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page) + current_SC->SCp.buffer->offset;
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		current_SC->SCp.buffers_residual = current_SC->use_sg - 1;
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		current_SC->SCp.ptr = (char *) current_SC->request_buffer;
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		current_SC->SCp.this_residual = current_SC->request_bufflen;
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		current_SC->SCp.buffer = NULL;
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		current_SC->SCp.buffers_residual = 0;
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	current_SC->SCp.Status = 0;
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	current_SC->SCp.Message = 0;
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	current_SC->SCp.have_data_in = 0;
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	current_SC->SCp.sent_command = 0;
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	current_SC->SCp.phase = in_arbitration;
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Start arbitration */
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x00, Interrupt_Cntl_port);
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x00, SCSI_Cntl_port);	/* Disable data drivers */
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(adapter_mask, SCSI_Data_NoACK_port);	/* Set our id bit */
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	in_command = 1;
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x20, Interrupt_Cntl_port);
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x14 | PARITY_MASK, TMC_Cntl_port);	/* Start arbitration */
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if DEBUG_ABORT || DEBUG_RESET
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void fd_mcs_print_info(Scsi_Cmnd * SCpnt)
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int imr;
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int irr;
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int isr;
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Scsi_Host *shpnt = SCpnt->host;
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!SCpnt || !SCpnt->host) {
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("fd_mcs: cannot provide detailed information\n");
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("%s\n", fd_mcs_info(SCpnt->host));
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	print_banner(SCpnt->host);
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (SCpnt->SCp.phase) {
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case in_arbitration:
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("arbitration ");
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case in_selection:
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("selection ");
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case in_other:
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("other ");
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("unknown ");
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("(%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n", SCpnt->SCp.phase, SCpnt->device->id, *(unsigned char *) SCpnt->cmnd, SCpnt->use_sg, SCpnt->request_bufflen);
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("sent_command = %d, have_data_in = %d, timeout = %d\n", SCpnt->SCp.sent_command, SCpnt->SCp.have_data_in, SCpnt->timeout);
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if DEBUG_RACE
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("in_interrupt_flag = %d\n", in_interrupt_flag);
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	imr = (inb(0x0a1) << 8) + inb(0x21);
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x0a, 0xa0);
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	irr = inb(0xa0) << 8;
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x0a, 0x20);
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	irr += inb(0x20);
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x0b, 0xa0);
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	isr = inb(0xa0) << 8;
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0x0b, 0x20);
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	isr += inb(0x20);
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Print out interesting information */
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("IMR = 0x%04x", imr);
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (imr & (1 << shpnt->irq))
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(" (masked)");
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(", IRR = 0x%04x, ISR = 0x%04x\n", irr, isr);
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("SCSI Status      = 0x%02x\n", inb(SCSI_Status_port));
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("TMC Status       = 0x%02x", inb(TMC_Status_port));
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (inb(TMC_Status_port) & 1)
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(" (interrupt)");
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("\n");
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("Interrupt Status = 0x%02x", inb(Interrupt_Status_port));
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (inb(Interrupt_Status_port) & 0x08)
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(" (enabled)");
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("\n");
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (chip == tmc18c50 || chip == tmc18c30) {
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("FIFO Status      = 0x%02x\n", inb(shpnt->io_port + FIFO_Status));
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("Int. Condition   = 0x%02x\n", inb(shpnt->io_port + Interrupt_Cond));
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("Configuration 1  = 0x%02x\n", inb(shpnt->io_port + Configuration1));
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (chip == tmc18c50 || chip == tmc18c30)
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("Configuration 2  = 0x%02x\n", inb(shpnt->io_port + Configuration2));
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int fd_mcs_abort(Scsi_Cmnd * SCpnt)
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Scsi_Host *shpnt = SCpnt->device->host;
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if EVERY_ACCESS || ERRORS_ONLY || DEBUG_ABORT
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("fd_mcs: abort ");
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(shpnt->host_lock, flags);
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!in_command) {
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if EVERY_ACCESS || ERRORS_ONLY
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(" (not in command)\n");
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(shpnt->host_lock, flags);
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return FAILED;
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("\n");
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if DEBUG_ABORT
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fd_mcs_print_info(SCpnt);
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fd_mcs_make_bus_idle(shpnt);
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	current_SC->SCp.phase |= aborted;
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	current_SC->result = DID_ABORT << 16;
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Aborts are not done well. . . */
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	my_done(shpnt, DID_ABORT << 16);
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(shpnt->host_lock, flags);
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return SUCCESS;
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int fd_mcs_bus_reset(Scsi_Cmnd * SCpnt) {
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Scsi_Host *shpnt = SCpnt->device->host;
124668b3aa7c9805aee9005a8ca53c5e99177961fbb9Jeff Garzik	unsigned long flags;
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if DEBUG_RESET
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static int called_once = 0;
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if ERRORS_ONLY
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (SCpnt)
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("fd_mcs: SCSI Bus Reset\n");
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if DEBUG_RESET
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (called_once)
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fd_mcs_print_info(current_SC);
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	called_once = 1;
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
126368b3aa7c9805aee9005a8ca53c5e99177961fbb9Jeff Garzik	spin_lock_irqsave(shpnt->host_lock, flags);
126468b3aa7c9805aee9005a8ca53c5e99177961fbb9Jeff Garzik
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(1, SCSI_Cntl_port);
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do_pause(2);
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0, SCSI_Cntl_port);
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do_pause(115);
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(0, SCSI_Mode_Cntl_port);
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(PARITY_MASK, TMC_Cntl_port);
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
127268b3aa7c9805aee9005a8ca53c5e99177961fbb9Jeff Garzik	spin_unlock_irqrestore(shpnt->host_lock, flags);
127368b3aa7c9805aee9005a8ca53c5e99177961fbb9Jeff Garzik
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Unless this is the very first call (i.e., SCPnt == NULL), everything
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   is probably hosed at this point.  We will, however, try to keep
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   things going by informing the high-level code that we need help. */
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return SUCCESS;
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi_ioctl.h>
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int fd_mcs_biosparam(struct scsi_device * disk, struct block_device *bdev,
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    sector_t capacity, int *info_array)
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *p = scsi_bios_ptable(bdev);
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int size = capacity;
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* BIOS >= 3.4 for MCA cards */
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* This algorithm was provided by Future Domain (much thanks!). */
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (p && p[65] == 0xaa && p[64] == 0x55	/* Partition table valid */
12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    && p[4]) {	/* Partition type */
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* The partition table layout is as follows:
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   Start: 0x1b3h
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   Offset: 0 = partition status
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   1 = starting head
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   2 = starting sector and cylinder (word, encoded)
12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   4 = partition type
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   5 = ending head
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   6 = ending sector and cylinder (word, encoded)
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   8 = starting absolute sector (double word)
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   c = number of sectors (double word)
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   Signature: 0x1fe = 0x55aa
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   So, this algorithm assumes:
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   1) the first partition table is in use,
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   2) the data in the first entry is correct, and
13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   3) partitions never divide cylinders
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   Note that (1) may be FALSE for NetBSD (and other BSD flavors),
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   as well as for Linux.  Note also, that Linux doesn't pay any
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   attention to the fields that are used by this algorithm -- it
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   only uses the absolute sector data.  Recent versions of Linux's
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   fdisk(1) will fill this data in correctly, and forthcoming
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   versions will check for consistency.
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   Checking for a non-zero partition type is not part of the
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   Future Domain algorithm, but it seemed to be a reasonable thing
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   to do, especially in the Linux and BSD worlds. */
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info_array[0] = p[5] + 1;	/* heads */
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info_array[1] = p[6] & 0x3f;	/* sectors */
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Note that this new method guarantees that there will always be
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   less than 1024 cylinders on a platter.  This is good for drives
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   up to approximately 7.85GB (where 1GB = 1024 * 1024 kB). */
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((unsigned int) size >= 0x7e0000U)
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			info_array[0] = 0xff;	/* heads   = 255 */
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			info_array[1] = 0x3f;	/* sectors =  63 */
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else if ((unsigned int) size >= 0x200000U) {
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			info_array[0] = 0x80;	/* heads   = 128 */
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			info_array[1] = 0x3f;	/* sectors =  63 */
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			info_array[0] = 0x40;	/* heads   =  64 */
13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			info_array[1] = 0x20;	/* sectors =  32 */
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* For both methods, compute the cylinders */
13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info_array[2] = (unsigned int) size / (info_array[0] * info_array[1]);
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(p);
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1346d0be4a7d29ad0bd3ce2209dd9e46d410b632db59Christoph Hellwigstatic struct scsi_host_template driver_template = {
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.proc_name			= "fd_mcs",
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.proc_info			= fd_mcs_proc_info,
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.detect				= fd_mcs_detect,
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.release			= fd_mcs_release,
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.info				= fd_mcs_info,
13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.queuecommand   		= fd_mcs_queue,
13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.eh_abort_handler		= fd_mcs_abort,
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.eh_bus_reset_handler		= fd_mcs_bus_reset,
13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.bios_param     		= fd_mcs_biosparam,
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.can_queue      		= 1,
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.this_id        		= 7,
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.sg_tablesize   		= 64,
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.cmd_per_lun    		= 1,
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.use_clustering 		= DISABLE_CLUSTERING,
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "scsi_module.c"
1363d39a942c3f4061d2218dcadf79ce10010dbcdb3cRandy.Dunlap
1364d39a942c3f4061d2218dcadf79ce10010dbcdb3cRandy.DunlapMODULE_LICENSE("GPL");
1365