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