xref: /openbmc/linux/drivers/scsi/pcmcia/nsp_cs.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
11da177e4SLinus Torvalds /*======================================================================
21da177e4SLinus Torvalds 
31da177e4SLinus Torvalds     NinjaSCSI-3 / NinjaSCSI-32Bi PCMCIA SCSI host adapter card driver
41da177e4SLinus Torvalds       By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
51da177e4SLinus Torvalds 
61da177e4SLinus Torvalds     Ver.2.8   Support 32bit MMIO mode
71da177e4SLinus Torvalds               Support Synchronous Data Transfer Request (SDTR) mode
81da177e4SLinus Torvalds     Ver.2.0   Support 32bit PIO mode
91da177e4SLinus Torvalds     Ver.1.1.2 Fix for scatter list buffer exceeds
101da177e4SLinus Torvalds     Ver.1.1   Support scatter list
111da177e4SLinus Torvalds     Ver.0.1   Initial version
121da177e4SLinus Torvalds 
131da177e4SLinus Torvalds     This software may be used and distributed according to the terms of
141da177e4SLinus Torvalds     the GNU General Public License.
151da177e4SLinus Torvalds 
161da177e4SLinus Torvalds ======================================================================*/
171da177e4SLinus Torvalds 
181da177e4SLinus Torvalds /***********************************************************************
191da177e4SLinus Torvalds     This driver is for these PCcards.
201da177e4SLinus Torvalds 
211da177e4SLinus Torvalds 	I-O DATA PCSC-F	 (Workbit NinjaSCSI-3)
221da177e4SLinus Torvalds 			"WBT", "NinjaSCSI-3", "R1.0"
231da177e4SLinus Torvalds 	I-O DATA CBSC-II (Workbit NinjaSCSI-32Bi in 16bit mode)
241da177e4SLinus Torvalds 			"IO DATA", "CBSC16	 ", "1"
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds ***********************************************************************/
271da177e4SLinus Torvalds 
281da177e4SLinus Torvalds #include <linux/module.h>
291da177e4SLinus Torvalds #include <linux/kernel.h>
301da177e4SLinus Torvalds #include <linux/init.h>
311da177e4SLinus Torvalds #include <linux/slab.h>
321da177e4SLinus Torvalds #include <linux/string.h>
331da177e4SLinus Torvalds #include <linux/timer.h>
341da177e4SLinus Torvalds #include <linux/ioport.h>
351da177e4SLinus Torvalds #include <linux/delay.h>
361da177e4SLinus Torvalds #include <linux/interrupt.h>
371da177e4SLinus Torvalds #include <linux/major.h>
381da177e4SLinus Torvalds #include <linux/blkdev.h>
391da177e4SLinus Torvalds #include <linux/stat.h>
401da177e4SLinus Torvalds 
411da177e4SLinus Torvalds #include <asm/io.h>
421da177e4SLinus Torvalds #include <asm/irq.h>
431da177e4SLinus Torvalds 
441da177e4SLinus Torvalds #include <scsi/scsi.h>
4553555fb7SBart Van Assche #include <scsi/scsi_cmnd.h>
4653555fb7SBart Van Assche #include <scsi/scsi_host.h>
471da177e4SLinus Torvalds #include <scsi/scsi_ioctl.h>
481da177e4SLinus Torvalds 
491da177e4SLinus Torvalds #include <pcmcia/cistpl.h>
501da177e4SLinus Torvalds #include <pcmcia/cisreg.h>
511da177e4SLinus Torvalds #include <pcmcia/ds.h>
521da177e4SLinus Torvalds 
531da177e4SLinus Torvalds #include "nsp_cs.h"
541da177e4SLinus Torvalds 
551da177e4SLinus Torvalds MODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>");
56774251efSAdrian Bunk MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module");
571da177e4SLinus Torvalds MODULE_LICENSE("GPL");
581da177e4SLinus Torvalds 
591da177e4SLinus Torvalds #include "nsp_io.h"
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds /*====================================================================*/
621da177e4SLinus Torvalds /* Parameters that can be set with 'insmod' */
631da177e4SLinus Torvalds 
641da177e4SLinus Torvalds static int       nsp_burst_mode = BURST_MEM32;
651da177e4SLinus Torvalds module_param(nsp_burst_mode, int, 0);
661da177e4SLinus Torvalds MODULE_PARM_DESC(nsp_burst_mode, "Burst transfer mode (0=io8, 1=io32, 2=mem32(default))");
671da177e4SLinus Torvalds 
681da177e4SLinus Torvalds /* Release IO ports after configuration? */
6990ab5ee9SRusty Russell static bool       free_ports = 0;
701da177e4SLinus Torvalds module_param(free_ports, bool, 0);
711da177e4SLinus Torvalds MODULE_PARM_DESC(free_ports, "Release IO ports after configuration? (default: 0 (=no))");
721da177e4SLinus Torvalds 
nsp_priv(struct scsi_cmnd * cmd)73ea39700fSBart Van Assche static struct scsi_pointer *nsp_priv(struct scsi_cmnd *cmd)
74ea39700fSBart Van Assche {
75ea39700fSBart Van Assche 	return scsi_cmd_priv(cmd);
76ea39700fSBart Van Assche }
77ea39700fSBart Van Assche 
78d0be4a7dSChristoph Hellwig static struct scsi_host_template nsp_driver_template = {
791da177e4SLinus Torvalds 	.proc_name	         = "nsp_cs",
8063fd57cbSAl Viro 	.show_info		 = nsp_show_info,
811da177e4SLinus Torvalds 	.name			 = "WorkBit NinjaSCSI-3/32Bi(16bit)",
821da177e4SLinus Torvalds 	.info			 = nsp_info,
831da177e4SLinus Torvalds 	.queuecommand		 = nsp_queuecommand,
841da177e4SLinus Torvalds /*	.eh_abort_handler	 = nsp_eh_abort,*/
851da177e4SLinus Torvalds 	.eh_bus_reset_handler	 = nsp_eh_bus_reset,
861da177e4SLinus Torvalds 	.eh_host_reset_handler	 = nsp_eh_host_reset,
871da177e4SLinus Torvalds 	.can_queue		 = 1,
881da177e4SLinus Torvalds 	.this_id		 = NSP_INITIATOR_ID,
891da177e4SLinus Torvalds 	.sg_tablesize		 = SG_ALL,
904af14d11SChristoph Hellwig 	.dma_boundary		 = PAGE_SIZE - 1,
91ea39700fSBart Van Assche 	.cmd_size		 = sizeof(struct scsi_pointer),
921da177e4SLinus Torvalds };
931da177e4SLinus Torvalds 
941da177e4SLinus Torvalds static nsp_hw_data nsp_data_base; /* attach <-> detect glue */
951da177e4SLinus Torvalds 
961da177e4SLinus Torvalds 
971da177e4SLinus Torvalds 
981da177e4SLinus Torvalds /*
991da177e4SLinus Torvalds  * debug, error print
1001da177e4SLinus Torvalds  */
1011da177e4SLinus Torvalds #ifndef NSP_DEBUG
1021da177e4SLinus Torvalds # define NSP_DEBUG_MASK		0x000000
1031da177e4SLinus Torvalds # define nsp_msg(type, args...) nsp_cs_message("", 0, (type), args)
1041da177e4SLinus Torvalds # define nsp_dbg(mask, args...) /* */
1051da177e4SLinus Torvalds #else
1061da177e4SLinus Torvalds # define NSP_DEBUG_MASK		0xffffff
1071da177e4SLinus Torvalds # define nsp_msg(type, args...) \
108cadbd4a5SHarvey Harrison 	nsp_cs_message (__func__, __LINE__, (type), args)
1091da177e4SLinus Torvalds # define nsp_dbg(mask, args...) \
110cadbd4a5SHarvey Harrison 	nsp_cs_dmessage(__func__, __LINE__, (mask), args)
1111da177e4SLinus Torvalds #endif
1121da177e4SLinus Torvalds 
1131da177e4SLinus Torvalds #define NSP_DEBUG_QUEUECOMMAND		BIT(0)
1141da177e4SLinus Torvalds #define NSP_DEBUG_REGISTER		BIT(1)
1151da177e4SLinus Torvalds #define NSP_DEBUG_AUTOSCSI		BIT(2)
1161da177e4SLinus Torvalds #define NSP_DEBUG_INTR			BIT(3)
1171da177e4SLinus Torvalds #define NSP_DEBUG_SGLIST		BIT(4)
1181da177e4SLinus Torvalds #define NSP_DEBUG_BUSFREE		BIT(5)
1191da177e4SLinus Torvalds #define NSP_DEBUG_CDB_CONTENTS		BIT(6)
1201da177e4SLinus Torvalds #define NSP_DEBUG_RESELECTION		BIT(7)
1211da177e4SLinus Torvalds #define NSP_DEBUG_MSGINOCCUR		BIT(8)
1221da177e4SLinus Torvalds #define NSP_DEBUG_EEPROM		BIT(9)
1231da177e4SLinus Torvalds #define NSP_DEBUG_MSGOUTOCCUR		BIT(10)
1241da177e4SLinus Torvalds #define NSP_DEBUG_BUSRESET		BIT(11)
1251da177e4SLinus Torvalds #define NSP_DEBUG_RESTART		BIT(12)
1261da177e4SLinus Torvalds #define NSP_DEBUG_SYNC			BIT(13)
1271da177e4SLinus Torvalds #define NSP_DEBUG_WAIT			BIT(14)
1281da177e4SLinus Torvalds #define NSP_DEBUG_TARGETFLAG		BIT(15)
1291da177e4SLinus Torvalds #define NSP_DEBUG_PROC			BIT(16)
1301da177e4SLinus Torvalds #define NSP_DEBUG_INIT			BIT(17)
1311da177e4SLinus Torvalds #define NSP_DEBUG_DATA_IO      		BIT(18)
1321da177e4SLinus Torvalds #define NSP_SPECIAL_PRINT_REGISTER	BIT(20)
1331da177e4SLinus Torvalds 
1341da177e4SLinus Torvalds #define NSP_DEBUG_BUF_LEN		150
1351da177e4SLinus Torvalds 
nsp_inc_resid(struct scsi_cmnd * SCpnt,int residInc)136040cd232SBoaz Harrosh static inline void nsp_inc_resid(struct scsi_cmnd *SCpnt, int residInc)
137040cd232SBoaz Harrosh {
138040cd232SBoaz Harrosh 	scsi_set_resid(SCpnt, scsi_get_resid(SCpnt) + residInc);
139040cd232SBoaz Harrosh }
140040cd232SBoaz Harrosh 
141af0b55d0SLee Jones __printf(4, 5)
nsp_cs_message(const char * func,int line,char * type,char * fmt,...)1421da177e4SLinus Torvalds static void nsp_cs_message(const char *func, int line, char *type, char *fmt, ...)
1431da177e4SLinus Torvalds {
1441da177e4SLinus Torvalds 	va_list args;
1451da177e4SLinus Torvalds 	char buf[NSP_DEBUG_BUF_LEN];
1461da177e4SLinus Torvalds 
1471da177e4SLinus Torvalds 	va_start(args, fmt);
1481da177e4SLinus Torvalds 	vsnprintf(buf, sizeof(buf), fmt, args);
1491da177e4SLinus Torvalds 	va_end(args);
1501da177e4SLinus Torvalds 
1511da177e4SLinus Torvalds #ifndef NSP_DEBUG
1521da177e4SLinus Torvalds 	printk("%snsp_cs: %s\n", type, buf);
1531da177e4SLinus Torvalds #else
1541da177e4SLinus Torvalds 	printk("%snsp_cs: %s (%d): %s\n", type, func, line, buf);
1551da177e4SLinus Torvalds #endif
1561da177e4SLinus Torvalds }
1571da177e4SLinus Torvalds 
1581da177e4SLinus Torvalds #ifdef NSP_DEBUG
nsp_cs_dmessage(const char * func,int line,int mask,char * fmt,...)1591da177e4SLinus Torvalds static void nsp_cs_dmessage(const char *func, int line, int mask, char *fmt, ...)
1601da177e4SLinus Torvalds {
1611da177e4SLinus Torvalds 	va_list args;
1621da177e4SLinus Torvalds 	char buf[NSP_DEBUG_BUF_LEN];
1631da177e4SLinus Torvalds 
1641da177e4SLinus Torvalds 	va_start(args, fmt);
1651da177e4SLinus Torvalds 	vsnprintf(buf, sizeof(buf), fmt, args);
1661da177e4SLinus Torvalds 	va_end(args);
1671da177e4SLinus Torvalds 
1681da177e4SLinus Torvalds 	if (mask & NSP_DEBUG_MASK) {
1691da177e4SLinus Torvalds 		printk("nsp_cs-debug: 0x%x %s (%d): %s\n", mask, func, line, buf);
1701da177e4SLinus Torvalds 	}
1711da177e4SLinus Torvalds }
1721da177e4SLinus Torvalds #endif
1731da177e4SLinus Torvalds 
1741da177e4SLinus Torvalds /***********************************************************/
1751da177e4SLinus Torvalds 
1761da177e4SLinus Torvalds /*====================================================
1771da177e4SLinus Torvalds  * Clenaup parameters and call done() functions.
1781da177e4SLinus Torvalds  * You must be set SCpnt->result before call this function.
1791da177e4SLinus Torvalds  */
nsp_scsi_done(struct scsi_cmnd * SCpnt)1800fc82d5eSHenrik Kretzschmar static void nsp_scsi_done(struct scsi_cmnd *SCpnt)
1811da177e4SLinus Torvalds {
1821da177e4SLinus Torvalds 	nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
1831da177e4SLinus Torvalds 
1841da177e4SLinus Torvalds 	data->CurrentSC = NULL;
1851da177e4SLinus Torvalds 
186ca0d62d2SBart Van Assche 	scsi_done(SCpnt);
1871da177e4SLinus Torvalds }
1881da177e4SLinus Torvalds 
nsp_queuecommand_lck(struct scsi_cmnd * const SCpnt)189ea39700fSBart Van Assche static int nsp_queuecommand_lck(struct scsi_cmnd *const SCpnt)
1901da177e4SLinus Torvalds {
191ea39700fSBart Van Assche 	struct scsi_pointer *scsi_pointer = nsp_priv(SCpnt);
1921da177e4SLinus Torvalds #ifdef NSP_DEBUG
1931da177e4SLinus Torvalds 	/*unsigned int host_id = SCpnt->device->host->this_id;*/
1941da177e4SLinus Torvalds 	/*unsigned int base    = SCpnt->device->host->io_port;*/
195422c0d61SJeff Garzik 	unsigned char target = scmd_id(SCpnt);
1961da177e4SLinus Torvalds #endif
1971da177e4SLinus Torvalds 	nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
1981da177e4SLinus Torvalds 
199040cd232SBoaz Harrosh 	nsp_dbg(NSP_DEBUG_QUEUECOMMAND,
2009cb78c16SHannes Reinecke 		"SCpnt=0x%p target=%d lun=%llu sglist=0x%p bufflen=%d sg_count=%d",
201040cd232SBoaz Harrosh 		SCpnt, target, SCpnt->device->lun, scsi_sglist(SCpnt),
202040cd232SBoaz Harrosh 		scsi_bufflen(SCpnt), scsi_sg_count(SCpnt));
2031da177e4SLinus Torvalds 	//nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "before CurrentSC=0x%p", data->CurrentSC);
2041da177e4SLinus Torvalds 
2051da177e4SLinus Torvalds 	if (data->CurrentSC != NULL) {
2061da177e4SLinus Torvalds 		nsp_msg(KERN_DEBUG, "CurrentSC!=NULL this can't be happen");
2071da177e4SLinus Torvalds 		SCpnt->result   = DID_BAD_TARGET << 16;
2081da177e4SLinus Torvalds 		nsp_scsi_done(SCpnt);
2091da177e4SLinus Torvalds 		return 0;
2101da177e4SLinus Torvalds 	}
2111da177e4SLinus Torvalds 
2121da177e4SLinus Torvalds #if 0
2131da177e4SLinus Torvalds 	/* XXX: pcmcia-cs generates SCSI command with "scsi_info" utility.
2141da177e4SLinus Torvalds 	        This makes kernel crash when suspending... */
2151da177e4SLinus Torvalds 	if (data->ScsiInfo->stop != 0) {
2161da177e4SLinus Torvalds 		nsp_msg(KERN_INFO, "suspending device. reject command.");
2171da177e4SLinus Torvalds 		SCpnt->result  = DID_BAD_TARGET << 16;
2181da177e4SLinus Torvalds 		nsp_scsi_done(SCpnt);
2191da177e4SLinus Torvalds 		return SCSI_MLQUEUE_HOST_BUSY;
2201da177e4SLinus Torvalds 	}
2211da177e4SLinus Torvalds #endif
2221da177e4SLinus Torvalds 
2231da177e4SLinus Torvalds 	show_command(SCpnt);
2241da177e4SLinus Torvalds 
2251da177e4SLinus Torvalds 	data->CurrentSC		= SCpnt;
2261da177e4SLinus Torvalds 
227ea39700fSBart Van Assche 	scsi_pointer->Status	   = SAM_STAT_CHECK_CONDITION;
228ea39700fSBart Van Assche 	scsi_pointer->Message	   = 0;
229ea39700fSBart Van Assche 	scsi_pointer->have_data_in = IO_UNKNOWN;
230ea39700fSBart Van Assche 	scsi_pointer->sent_command = 0;
231ea39700fSBart Van Assche 	scsi_pointer->phase	   = PH_UNDETERMINED;
232040cd232SBoaz Harrosh 	scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
2331da177e4SLinus Torvalds 
2341da177e4SLinus Torvalds 	/* setup scratch area
2351da177e4SLinus Torvalds 	   SCp.ptr		: buffer pointer
2361da177e4SLinus Torvalds 	   SCp.this_residual	: buffer length
2371da177e4SLinus Torvalds 	   SCp.buffer		: next buffer
2381da177e4SLinus Torvalds 	   SCp.buffers_residual : left buffers in list
2391da177e4SLinus Torvalds 	   SCp.phase		: current state of the command */
240040cd232SBoaz Harrosh 	if (scsi_bufflen(SCpnt)) {
241ea39700fSBart Van Assche 		scsi_pointer->buffer	       = scsi_sglist(SCpnt);
242ea39700fSBart Van Assche 		scsi_pointer->ptr	       = BUFFER_ADDR(SCpnt);
243ea39700fSBart Van Assche 		scsi_pointer->this_residual    = scsi_pointer->buffer->length;
244ea39700fSBart Van Assche 		scsi_pointer->buffers_residual = scsi_sg_count(SCpnt) - 1;
2451da177e4SLinus Torvalds 	} else {
246ea39700fSBart Van Assche 		scsi_pointer->ptr	       = NULL;
247ea39700fSBart Van Assche 		scsi_pointer->this_residual    = 0;
248ea39700fSBart Van Assche 		scsi_pointer->buffer	       = NULL;
249ea39700fSBart Van Assche 		scsi_pointer->buffers_residual = 0;
2501da177e4SLinus Torvalds 	}
2511da177e4SLinus Torvalds 
252dfab1e53SBart Van Assche 	if (!nsphw_start_selection(SCpnt)) {
2531da177e4SLinus Torvalds 		nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "selection fail");
2541da177e4SLinus Torvalds 		SCpnt->result   = DID_BUS_BUSY << 16;
2551da177e4SLinus Torvalds 		nsp_scsi_done(SCpnt);
2561da177e4SLinus Torvalds 		return 0;
2571da177e4SLinus Torvalds 	}
2581da177e4SLinus Torvalds 
2591da177e4SLinus Torvalds 
2601da177e4SLinus Torvalds 	//nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "out");
2611da177e4SLinus Torvalds #ifdef NSP_DEBUG
2621da177e4SLinus Torvalds 	data->CmdId++;
2631da177e4SLinus Torvalds #endif
2641da177e4SLinus Torvalds 	return 0;
2651da177e4SLinus Torvalds }
2661da177e4SLinus Torvalds 
DEF_SCSI_QCMD(nsp_queuecommand)267f281233dSJeff Garzik static DEF_SCSI_QCMD(nsp_queuecommand)
268f281233dSJeff Garzik 
2691da177e4SLinus Torvalds /*
2701da177e4SLinus Torvalds  * setup PIO FIFO transfer mode and enable/disable to data out
2711da177e4SLinus Torvalds  */
272dfab1e53SBart Van Assche static void nsp_setup_fifo(nsp_hw_data *data, bool enabled)
2731da177e4SLinus Torvalds {
2741da177e4SLinus Torvalds 	unsigned int  base = data->BaseAddress;
2751da177e4SLinus Torvalds 	unsigned char transfer_mode_reg;
2761da177e4SLinus Torvalds 
2771da177e4SLinus Torvalds 	//nsp_dbg(NSP_DEBUG_DATA_IO, "enabled=%d", enabled);
2781da177e4SLinus Torvalds 
279dfab1e53SBart Van Assche 	if (enabled) {
2801da177e4SLinus Torvalds 		transfer_mode_reg = TRANSFER_GO | BRAIND;
2811da177e4SLinus Torvalds 	} else {
2821da177e4SLinus Torvalds 		transfer_mode_reg = 0;
2831da177e4SLinus Torvalds 	}
2841da177e4SLinus Torvalds 
2851da177e4SLinus Torvalds 	transfer_mode_reg |= data->TransferMode;
2861da177e4SLinus Torvalds 
2871da177e4SLinus Torvalds 	nsp_index_write(base, TRANSFERMODE, transfer_mode_reg);
2881da177e4SLinus Torvalds }
2891da177e4SLinus Torvalds 
nsphw_init_sync(nsp_hw_data * data)2901da177e4SLinus Torvalds static void nsphw_init_sync(nsp_hw_data *data)
2911da177e4SLinus Torvalds {
2921da177e4SLinus Torvalds 	sync_data tmp_sync = { .SyncNegotiation = SYNC_NOT_YET,
2931da177e4SLinus Torvalds 			       .SyncPeriod      = 0,
2941da177e4SLinus Torvalds 			       .SyncOffset      = 0
2951da177e4SLinus Torvalds 	};
2961da177e4SLinus Torvalds 	int i;
2971da177e4SLinus Torvalds 
2981da177e4SLinus Torvalds 	/* setup sync data */
2991da177e4SLinus Torvalds 	for ( i = 0; i < ARRAY_SIZE(data->Sync); i++ ) {
3001da177e4SLinus Torvalds 		data->Sync[i] = tmp_sync;
3011da177e4SLinus Torvalds 	}
3021da177e4SLinus Torvalds }
3031da177e4SLinus Torvalds 
3041da177e4SLinus Torvalds /*
3051da177e4SLinus Torvalds  * Initialize Ninja hardware
3061da177e4SLinus Torvalds  */
nsphw_init(nsp_hw_data * data)30772961735SBart Van Assche static void nsphw_init(nsp_hw_data *data)
3081da177e4SLinus Torvalds {
3091da177e4SLinus Torvalds 	unsigned int base     = data->BaseAddress;
3101da177e4SLinus Torvalds 
3111da177e4SLinus Torvalds 	nsp_dbg(NSP_DEBUG_INIT, "in base=0x%x", base);
3121da177e4SLinus Torvalds 
3131da177e4SLinus Torvalds 	data->ScsiClockDiv = CLOCK_40M | FAST_20;
3141da177e4SLinus Torvalds 	data->CurrentSC    = NULL;
3151da177e4SLinus Torvalds 	data->FifoCount    = 0;
3161da177e4SLinus Torvalds 	data->TransferMode = MODE_IO8;
3171da177e4SLinus Torvalds 
3181da177e4SLinus Torvalds 	nsphw_init_sync(data);
3191da177e4SLinus Torvalds 
3201da177e4SLinus Torvalds 	/* block all interrupts */
3211da177e4SLinus Torvalds 	nsp_write(base,	      IRQCONTROL,   IRQCONTROL_ALLMASK);
3221da177e4SLinus Torvalds 
3231da177e4SLinus Torvalds 	/* setup SCSI interface */
3241da177e4SLinus Torvalds 	nsp_write(base,	      IFSELECT,	    IF_IFSEL);
3251da177e4SLinus Torvalds 
3261da177e4SLinus Torvalds 	nsp_index_write(base, SCSIIRQMODE,  0);
3271da177e4SLinus Torvalds 
3281da177e4SLinus Torvalds 	nsp_index_write(base, TRANSFERMODE, MODE_IO8);
3291da177e4SLinus Torvalds 	nsp_index_write(base, CLOCKDIV,	    data->ScsiClockDiv);
3301da177e4SLinus Torvalds 
3311da177e4SLinus Torvalds 	nsp_index_write(base, PARITYCTRL,   0);
3321da177e4SLinus Torvalds 	nsp_index_write(base, POINTERCLR,   POINTER_CLEAR     |
3331da177e4SLinus Torvalds 					    ACK_COUNTER_CLEAR |
3341da177e4SLinus Torvalds 					    REQ_COUNTER_CLEAR |
3351da177e4SLinus Torvalds 					    HOST_COUNTER_CLEAR);
3361da177e4SLinus Torvalds 
3371da177e4SLinus Torvalds 	/* setup fifo asic */
3381da177e4SLinus Torvalds 	nsp_write(base,	      IFSELECT,	    IF_REGSEL);
3391da177e4SLinus Torvalds 	nsp_index_write(base, TERMPWRCTRL,  0);
3401da177e4SLinus Torvalds 	if ((nsp_index_read(base, OTHERCONTROL) & TPWR_SENSE) == 0) {
3411da177e4SLinus Torvalds 		nsp_msg(KERN_INFO, "terminator power on");
3421da177e4SLinus Torvalds 		nsp_index_write(base, TERMPWRCTRL, POWER_ON);
3431da177e4SLinus Torvalds 	}
3441da177e4SLinus Torvalds 
3451da177e4SLinus Torvalds 	nsp_index_write(base, TIMERCOUNT,   0);
3461da177e4SLinus Torvalds 	nsp_index_write(base, TIMERCOUNT,   0); /* requires 2 times!! */
3471da177e4SLinus Torvalds 
3481da177e4SLinus Torvalds 	nsp_index_write(base, SYNCREG,	    0);
3491da177e4SLinus Torvalds 	nsp_index_write(base, ACKWIDTH,	    0);
3501da177e4SLinus Torvalds 
3511da177e4SLinus Torvalds 	/* enable interrupts and ack them */
3521da177e4SLinus Torvalds 	nsp_index_write(base, SCSIIRQMODE,  SCSI_PHASE_CHANGE_EI |
3531da177e4SLinus Torvalds 					    RESELECT_EI		 |
3541da177e4SLinus Torvalds 					    SCSI_RESET_IRQ_EI	 );
3551da177e4SLinus Torvalds 	nsp_write(base,	      IRQCONTROL,   IRQCONTROL_ALLCLEAR);
3561da177e4SLinus Torvalds 
357dfab1e53SBart Van Assche 	nsp_setup_fifo(data, false);
3581da177e4SLinus Torvalds }
3591da177e4SLinus Torvalds 
3601da177e4SLinus Torvalds /*
3611da177e4SLinus Torvalds  * Start selection phase
3621da177e4SLinus Torvalds  */
nsphw_start_selection(struct scsi_cmnd * const SCpnt)363ea39700fSBart Van Assche static bool nsphw_start_selection(struct scsi_cmnd *const SCpnt)
3641da177e4SLinus Torvalds {
365ea39700fSBart Van Assche 	struct scsi_pointer *scsi_pointer = nsp_priv(SCpnt);
3661da177e4SLinus Torvalds 	unsigned int  host_id	 = SCpnt->device->host->this_id;
3671da177e4SLinus Torvalds 	unsigned int  base	 = SCpnt->device->host->io_port;
368422c0d61SJeff Garzik 	unsigned char target	 = scmd_id(SCpnt);
3691da177e4SLinus Torvalds 	nsp_hw_data  *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
3701da177e4SLinus Torvalds 	int	      time_out;
3711da177e4SLinus Torvalds 	unsigned char phase, arbit;
3721da177e4SLinus Torvalds 
3731da177e4SLinus Torvalds 	//nsp_dbg(NSP_DEBUG_RESELECTION, "in");
3741da177e4SLinus Torvalds 
3751da177e4SLinus Torvalds 	phase = nsp_index_read(base, SCSIBUSMON);
3761da177e4SLinus Torvalds 	if(phase != BUSMON_BUS_FREE) {
3771da177e4SLinus Torvalds 		//nsp_dbg(NSP_DEBUG_RESELECTION, "bus busy");
378dfab1e53SBart Van Assche 		return false;
3791da177e4SLinus Torvalds 	}
3801da177e4SLinus Torvalds 
3811da177e4SLinus Torvalds 	/* start arbitration */
3821da177e4SLinus Torvalds 	//nsp_dbg(NSP_DEBUG_RESELECTION, "start arbit");
383ea39700fSBart Van Assche 	scsi_pointer->phase = PH_ARBSTART;
3841da177e4SLinus Torvalds 	nsp_index_write(base, SETARBIT, ARBIT_GO);
3851da177e4SLinus Torvalds 
3861da177e4SLinus Torvalds 	time_out = 1000;
3871da177e4SLinus Torvalds 	do {
3881da177e4SLinus Torvalds 		/* XXX: what a stupid chip! */
3891da177e4SLinus Torvalds 		arbit = nsp_index_read(base, ARBITSTATUS);
3901da177e4SLinus Torvalds 		//nsp_dbg(NSP_DEBUG_RESELECTION, "arbit=%d, wait_count=%d", arbit, wait_count);
3911da177e4SLinus Torvalds 		udelay(1); /* hold 1.2us */
3921da177e4SLinus Torvalds 	} while((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 &&
3931da177e4SLinus Torvalds 		(time_out-- != 0));
3941da177e4SLinus Torvalds 
3951da177e4SLinus Torvalds 	if (!(arbit & ARBIT_WIN)) {
3961da177e4SLinus Torvalds 		//nsp_dbg(NSP_DEBUG_RESELECTION, "arbit fail");
3971da177e4SLinus Torvalds 		nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR);
398dfab1e53SBart Van Assche 		return false;
3991da177e4SLinus Torvalds 	}
4001da177e4SLinus Torvalds 
4011da177e4SLinus Torvalds 	/* assert select line */
4021da177e4SLinus Torvalds 	//nsp_dbg(NSP_DEBUG_RESELECTION, "assert SEL line");
403ea39700fSBart Van Assche 	scsi_pointer->phase = PH_SELSTART;
4041da177e4SLinus Torvalds 	udelay(3); /* wait 2.4us */
4051da177e4SLinus Torvalds 	nsp_index_write(base, SCSIDATALATCH, BIT(host_id) | BIT(target));
4061da177e4SLinus Torvalds 	nsp_index_write(base, SCSIBUSCTRL,   SCSI_SEL | SCSI_BSY                    | SCSI_ATN);
4071da177e4SLinus Torvalds 	udelay(2); /* wait >1.2us */
4081da177e4SLinus Torvalds 	nsp_index_write(base, SCSIBUSCTRL,   SCSI_SEL | SCSI_BSY | SCSI_DATAOUT_ENB | SCSI_ATN);
4091da177e4SLinus Torvalds 	nsp_index_write(base, SETARBIT,	     ARBIT_FLAG_CLEAR);
4101da177e4SLinus Torvalds 	/*udelay(1);*/ /* wait >90ns */
4111da177e4SLinus Torvalds 	nsp_index_write(base, SCSIBUSCTRL,   SCSI_SEL            | SCSI_DATAOUT_ENB | SCSI_ATN);
4121da177e4SLinus Torvalds 
4131da177e4SLinus Torvalds 	/* check selection timeout */
4141da177e4SLinus Torvalds 	nsp_start_timer(SCpnt, 1000/51);
4151da177e4SLinus Torvalds 	data->SelectionTimeOut = 1;
4161da177e4SLinus Torvalds 
417dfab1e53SBart Van Assche 	return true;
4181da177e4SLinus Torvalds }
4191da177e4SLinus Torvalds 
4201da177e4SLinus Torvalds struct nsp_sync_table {
4211da177e4SLinus Torvalds 	unsigned int min_period;
4221da177e4SLinus Torvalds 	unsigned int max_period;
4231da177e4SLinus Torvalds 	unsigned int chip_period;
4241da177e4SLinus Torvalds 	unsigned int ack_width;
4251da177e4SLinus Torvalds };
4261da177e4SLinus Torvalds 
4271da177e4SLinus Torvalds static struct nsp_sync_table nsp_sync_table_40M[] = {
4281da177e4SLinus Torvalds 	{0x0c, 0x0c, 0x1, 0},	/* 20MB	  50ns*/
4291da177e4SLinus Torvalds 	{0x19, 0x19, 0x3, 1},	/* 10MB	 100ns*/
4301da177e4SLinus Torvalds 	{0x1a, 0x25, 0x5, 2},	/* 7.5MB 150ns*/
4311da177e4SLinus Torvalds 	{0x26, 0x32, 0x7, 3},	/* 5MB	 200ns*/
4321da177e4SLinus Torvalds 	{   0,    0,   0, 0},
4331da177e4SLinus Torvalds };
4341da177e4SLinus Torvalds 
4351da177e4SLinus Torvalds static struct nsp_sync_table nsp_sync_table_20M[] = {
4361da177e4SLinus Torvalds 	{0x19, 0x19, 0x1, 0},	/* 10MB	 100ns*/
4371da177e4SLinus Torvalds 	{0x1a, 0x25, 0x2, 0},	/* 7.5MB 150ns*/
4381da177e4SLinus Torvalds 	{0x26, 0x32, 0x3, 1},	/* 5MB	 200ns*/
4391da177e4SLinus Torvalds 	{   0,    0,   0, 0},
4401da177e4SLinus Torvalds };
4411da177e4SLinus Torvalds 
4421da177e4SLinus Torvalds /*
4431da177e4SLinus Torvalds  * setup synchronous data transfer mode
4441da177e4SLinus Torvalds  */
nsp_analyze_sdtr(struct scsi_cmnd * SCpnt)4450fc82d5eSHenrik Kretzschmar static int nsp_analyze_sdtr(struct scsi_cmnd *SCpnt)
4461da177e4SLinus Torvalds {
447422c0d61SJeff Garzik 	unsigned char	       target = scmd_id(SCpnt);
4481da177e4SLinus Torvalds //	unsigned char	       lun    = SCpnt->device->lun;
4491da177e4SLinus Torvalds 	nsp_hw_data           *data   = (nsp_hw_data *)SCpnt->device->host->hostdata;
4501da177e4SLinus Torvalds 	sync_data	      *sync   = &(data->Sync[target]);
4511da177e4SLinus Torvalds 	struct nsp_sync_table *sync_table;
4521da177e4SLinus Torvalds 	unsigned int	       period, offset;
4531da177e4SLinus Torvalds 
4541da177e4SLinus Torvalds 	nsp_dbg(NSP_DEBUG_SYNC, "in");
4551da177e4SLinus Torvalds 
4561da177e4SLinus Torvalds 	period = sync->SyncPeriod;
4571da177e4SLinus Torvalds 	offset = sync->SyncOffset;
4581da177e4SLinus Torvalds 
4591da177e4SLinus Torvalds 	nsp_dbg(NSP_DEBUG_SYNC, "period=0x%x, offset=0x%x", period, offset);
4601da177e4SLinus Torvalds 
4611da177e4SLinus Torvalds 	if ((data->ScsiClockDiv & (BIT(0)|BIT(1))) == CLOCK_20M) {
4621da177e4SLinus Torvalds 		sync_table = nsp_sync_table_20M;
4631da177e4SLinus Torvalds 	} else {
4641da177e4SLinus Torvalds 		sync_table = nsp_sync_table_40M;
4651da177e4SLinus Torvalds 	}
4661da177e4SLinus Torvalds 
467*25ad6f63SColin Ian King 	for (; sync_table->max_period != 0; sync_table++) {
4681da177e4SLinus Torvalds 		if ( period >= sync_table->min_period &&
4691da177e4SLinus Torvalds 		     period <= sync_table->max_period	 ) {
4701da177e4SLinus Torvalds 			break;
4711da177e4SLinus Torvalds 		}
4721da177e4SLinus Torvalds 	}
4731da177e4SLinus Torvalds 
4741da177e4SLinus Torvalds 	if (period != 0 && sync_table->max_period == 0) {
4751da177e4SLinus Torvalds 		/*
4761da177e4SLinus Torvalds 		 * No proper period/offset found
4771da177e4SLinus Torvalds 		 */
4781da177e4SLinus Torvalds 		nsp_dbg(NSP_DEBUG_SYNC, "no proper period/offset");
4791da177e4SLinus Torvalds 
4801da177e4SLinus Torvalds 		sync->SyncPeriod      = 0;
4811da177e4SLinus Torvalds 		sync->SyncOffset      = 0;
4821da177e4SLinus Torvalds 		sync->SyncRegister    = 0;
4831da177e4SLinus Torvalds 		sync->AckWidth	      = 0;
4841da177e4SLinus Torvalds 
485dfab1e53SBart Van Assche 		return false;
4861da177e4SLinus Torvalds 	}
4871da177e4SLinus Torvalds 
4881da177e4SLinus Torvalds 	sync->SyncRegister    = (sync_table->chip_period << SYNCREG_PERIOD_SHIFT) |
4891da177e4SLinus Torvalds 		                (offset & SYNCREG_OFFSET_MASK);
4901da177e4SLinus Torvalds 	sync->AckWidth	      = sync_table->ack_width;
4911da177e4SLinus Torvalds 
4921da177e4SLinus Torvalds 	nsp_dbg(NSP_DEBUG_SYNC, "sync_reg=0x%x, ack_width=0x%x", sync->SyncRegister, sync->AckWidth);
4931da177e4SLinus Torvalds 
494dfab1e53SBart Van Assche 	return true;
4951da177e4SLinus Torvalds }
4961da177e4SLinus Torvalds 
4971da177e4SLinus Torvalds 
4981da177e4SLinus Torvalds /*
4991da177e4SLinus Torvalds  * start ninja hardware timer
5001da177e4SLinus Torvalds  */
nsp_start_timer(struct scsi_cmnd * SCpnt,int time)5010fc82d5eSHenrik Kretzschmar static void nsp_start_timer(struct scsi_cmnd *SCpnt, int time)
5021da177e4SLinus Torvalds {
5031da177e4SLinus Torvalds 	unsigned int base = SCpnt->device->host->io_port;
5041da177e4SLinus Torvalds 	nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
5051da177e4SLinus Torvalds 
5061da177e4SLinus Torvalds 	//nsp_dbg(NSP_DEBUG_INTR, "in SCpnt=0x%p, time=%d", SCpnt, time);
5071da177e4SLinus Torvalds 	data->TimerCount = time;
5081da177e4SLinus Torvalds 	nsp_index_write(base, TIMERCOUNT, time);
5091da177e4SLinus Torvalds }
5101da177e4SLinus Torvalds 
5111da177e4SLinus Torvalds /*
5121da177e4SLinus Torvalds  * wait for bus phase change
5131da177e4SLinus Torvalds  */
nsp_negate_signal(struct scsi_cmnd * SCpnt,unsigned char mask,char * str)5140fc82d5eSHenrik Kretzschmar static int nsp_negate_signal(struct scsi_cmnd *SCpnt, unsigned char mask,
5150fc82d5eSHenrik Kretzschmar 			     char *str)
5161da177e4SLinus Torvalds {
5171da177e4SLinus Torvalds 	unsigned int  base = SCpnt->device->host->io_port;
5181da177e4SLinus Torvalds 	unsigned char reg;
5191da177e4SLinus Torvalds 	int	      time_out;
5201da177e4SLinus Torvalds 
5211da177e4SLinus Torvalds 	//nsp_dbg(NSP_DEBUG_INTR, "in");
5221da177e4SLinus Torvalds 
5231da177e4SLinus Torvalds 	time_out = 100;
5241da177e4SLinus Torvalds 
5251da177e4SLinus Torvalds 	do {
5261da177e4SLinus Torvalds 		reg = nsp_index_read(base, SCSIBUSMON);
5271da177e4SLinus Torvalds 		if (reg == 0xff) {
5281da177e4SLinus Torvalds 			break;
5291da177e4SLinus Torvalds 		}
5300454c740SRoel Kluin 	} while ((--time_out != 0) && (reg & mask) != 0);
5311da177e4SLinus Torvalds 
5321da177e4SLinus Torvalds 	if (time_out == 0) {
5339b13494cSMasanari Iida 		nsp_msg(KERN_DEBUG, " %s signal off timeout", str);
5341da177e4SLinus Torvalds 	}
5351da177e4SLinus Torvalds 
5361da177e4SLinus Torvalds 	return 0;
5371da177e4SLinus Torvalds }
5381da177e4SLinus Torvalds 
5391da177e4SLinus Torvalds /*
5401da177e4SLinus Torvalds  * expect Ninja Irq
5411da177e4SLinus Torvalds  */
nsp_expect_signal(struct scsi_cmnd * SCpnt,unsigned char current_phase,unsigned char mask)5420fc82d5eSHenrik Kretzschmar static int nsp_expect_signal(struct scsi_cmnd *SCpnt,
5431da177e4SLinus Torvalds 			     unsigned char current_phase,
5441da177e4SLinus Torvalds 			     unsigned char mask)
5451da177e4SLinus Torvalds {
5461da177e4SLinus Torvalds 	unsigned int  base	 = SCpnt->device->host->io_port;
5471da177e4SLinus Torvalds 	int	      time_out;
5481da177e4SLinus Torvalds 	unsigned char phase, i_src;
5491da177e4SLinus Torvalds 
5501da177e4SLinus Torvalds 	//nsp_dbg(NSP_DEBUG_INTR, "current_phase=0x%x, mask=0x%x", current_phase, mask);
5511da177e4SLinus Torvalds 
5521da177e4SLinus Torvalds 	time_out = 100;
5531da177e4SLinus Torvalds 	do {
5541da177e4SLinus Torvalds 		phase = nsp_index_read(base, SCSIBUSMON);
5551da177e4SLinus Torvalds 		if (phase == 0xff) {
5561da177e4SLinus Torvalds 			//nsp_dbg(NSP_DEBUG_INTR, "ret -1");
5571da177e4SLinus Torvalds 			return -1;
5581da177e4SLinus Torvalds 		}
5591da177e4SLinus Torvalds 		i_src = nsp_read(base, IRQSTATUS);
5601da177e4SLinus Torvalds 		if (i_src & IRQSTATUS_SCSI) {
5611da177e4SLinus Torvalds 			//nsp_dbg(NSP_DEBUG_INTR, "ret 0 found scsi signal");
5621da177e4SLinus Torvalds 			return 0;
5631da177e4SLinus Torvalds 		}
5641da177e4SLinus Torvalds 		if ((phase & mask) != 0 && (phase & BUSMON_PHASE_MASK) == current_phase) {
5651da177e4SLinus Torvalds 			//nsp_dbg(NSP_DEBUG_INTR, "ret 1 phase=0x%x", phase);
5661da177e4SLinus Torvalds 			return 1;
5671da177e4SLinus Torvalds 		}
5681da177e4SLinus Torvalds 	} while(time_out-- != 0);
5691da177e4SLinus Torvalds 
5701da177e4SLinus Torvalds 	//nsp_dbg(NSP_DEBUG_INTR, "timeout");
5711da177e4SLinus Torvalds 	return -1;
5721da177e4SLinus Torvalds }
5731da177e4SLinus Torvalds 
5741da177e4SLinus Torvalds /*
5751da177e4SLinus Torvalds  * transfer SCSI message
5761da177e4SLinus Torvalds  */
nsp_xfer(struct scsi_cmnd * const SCpnt,int phase)577ea39700fSBart Van Assche static int nsp_xfer(struct scsi_cmnd *const SCpnt, int phase)
5781da177e4SLinus Torvalds {
579ea39700fSBart Van Assche 	struct scsi_pointer *scsi_pointer = nsp_priv(SCpnt);
5801da177e4SLinus Torvalds 	unsigned int  base = SCpnt->device->host->io_port;
5811da177e4SLinus Torvalds 	nsp_hw_data  *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
5821da177e4SLinus Torvalds 	char	     *buf  = data->MsgBuffer;
5831da177e4SLinus Torvalds 	int	      len  = min(MSGBUF_SIZE, data->MsgLen);
5841da177e4SLinus Torvalds 	int	      ptr;
5851da177e4SLinus Torvalds 	int	      ret;
5861da177e4SLinus Torvalds 
5871da177e4SLinus Torvalds 	//nsp_dbg(NSP_DEBUG_DATA_IO, "in");
5881da177e4SLinus Torvalds 	for (ptr = 0; len > 0; len--, ptr++) {
5891da177e4SLinus Torvalds 
5901da177e4SLinus Torvalds 		ret = nsp_expect_signal(SCpnt, phase, BUSMON_REQ);
5911da177e4SLinus Torvalds 		if (ret <= 0) {
5921da177e4SLinus Torvalds 			nsp_dbg(NSP_DEBUG_DATA_IO, "xfer quit");
5931da177e4SLinus Torvalds 			return 0;
5941da177e4SLinus Torvalds 		}
5951da177e4SLinus Torvalds 
5961da177e4SLinus Torvalds 		/* if last byte, negate ATN */
597ea39700fSBart Van Assche 		if (len == 1 && scsi_pointer->phase == PH_MSG_OUT) {
5981da177e4SLinus Torvalds 			nsp_index_write(base, SCSIBUSCTRL, AUTODIRECTION | ACKENB);
5991da177e4SLinus Torvalds 		}
6001da177e4SLinus Torvalds 
6011da177e4SLinus Torvalds 		/* read & write message */
6021da177e4SLinus Torvalds 		if (phase & BUSMON_IO) {
6031da177e4SLinus Torvalds 			nsp_dbg(NSP_DEBUG_DATA_IO, "read msg");
6041da177e4SLinus Torvalds 			buf[ptr] = nsp_index_read(base, SCSIDATAWITHACK);
6051da177e4SLinus Torvalds 		} else {
6061da177e4SLinus Torvalds 			nsp_dbg(NSP_DEBUG_DATA_IO, "write msg");
6071da177e4SLinus Torvalds 			nsp_index_write(base, SCSIDATAWITHACK, buf[ptr]);
6081da177e4SLinus Torvalds 		}
6091da177e4SLinus Torvalds 		nsp_negate_signal(SCpnt, BUSMON_ACK, "xfer<ack>");
6101da177e4SLinus Torvalds 
6111da177e4SLinus Torvalds 	}
6121da177e4SLinus Torvalds 	return len;
6131da177e4SLinus Torvalds }
6141da177e4SLinus Torvalds 
6151da177e4SLinus Torvalds /*
6161da177e4SLinus Torvalds  * get extra SCSI data from fifo
6171da177e4SLinus Torvalds  */
nsp_dataphase_bypass(struct scsi_cmnd * const SCpnt)618ea39700fSBart Van Assche static int nsp_dataphase_bypass(struct scsi_cmnd *const SCpnt)
6191da177e4SLinus Torvalds {
620ea39700fSBart Van Assche 	struct scsi_pointer *scsi_pointer = nsp_priv(SCpnt);
6211da177e4SLinus Torvalds 	nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
6221da177e4SLinus Torvalds 	unsigned int count;
6231da177e4SLinus Torvalds 
6241da177e4SLinus Torvalds 	//nsp_dbg(NSP_DEBUG_DATA_IO, "in");
6251da177e4SLinus Torvalds 
626ea39700fSBart Van Assche 	if (scsi_pointer->have_data_in != IO_IN) {
6271da177e4SLinus Torvalds 		return 0;
6281da177e4SLinus Torvalds 	}
6291da177e4SLinus Torvalds 
6301da177e4SLinus Torvalds 	count = nsp_fifo_count(SCpnt);
6311da177e4SLinus Torvalds 	if (data->FifoCount == count) {
6321da177e4SLinus Torvalds 		//nsp_dbg(NSP_DEBUG_DATA_IO, "not use bypass quirk");
6331da177e4SLinus Torvalds 		return 0;
6341da177e4SLinus Torvalds 	}
6351da177e4SLinus Torvalds 
6361da177e4SLinus Torvalds 	/*
6371da177e4SLinus Torvalds 	 * XXX: NSP_QUIRK
6381da177e4SLinus Torvalds 	 * data phase skip only occures in case of SCSI_LOW_READ
6391da177e4SLinus Torvalds 	 */
6401da177e4SLinus Torvalds 	nsp_dbg(NSP_DEBUG_DATA_IO, "use bypass quirk");
641ea39700fSBart Van Assche 	scsi_pointer->phase = PH_DATA;
6421da177e4SLinus Torvalds 	nsp_pio_read(SCpnt);
643dfab1e53SBart Van Assche 	nsp_setup_fifo(data, false);
6441da177e4SLinus Torvalds 
6451da177e4SLinus Torvalds 	return 0;
6461da177e4SLinus Torvalds }
6471da177e4SLinus Torvalds 
6481da177e4SLinus Torvalds /*
6491da177e4SLinus Torvalds  * accept reselection
6501da177e4SLinus Torvalds  */
nsp_reselected(struct scsi_cmnd * SCpnt)65172961735SBart Van Assche static void nsp_reselected(struct scsi_cmnd *SCpnt)
6521da177e4SLinus Torvalds {
6531da177e4SLinus Torvalds 	unsigned int  base    = SCpnt->device->host->io_port;
6541da177e4SLinus Torvalds 	unsigned int  host_id = SCpnt->device->host->this_id;
6551da177e4SLinus Torvalds 	//nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
6561da177e4SLinus Torvalds 	unsigned char bus_reg;
6571da177e4SLinus Torvalds 	unsigned char id_reg, tmp;
6581da177e4SLinus Torvalds 	int target;
6591da177e4SLinus Torvalds 
6601da177e4SLinus Torvalds 	nsp_dbg(NSP_DEBUG_RESELECTION, "in");
6611da177e4SLinus Torvalds 
6621da177e4SLinus Torvalds 	id_reg = nsp_index_read(base, RESELECTID);
6631da177e4SLinus Torvalds 	tmp    = id_reg & (~BIT(host_id));
6641da177e4SLinus Torvalds 	target = 0;
6651da177e4SLinus Torvalds 	while(tmp != 0) {
6661da177e4SLinus Torvalds 		if (tmp & BIT(0)) {
6671da177e4SLinus Torvalds 			break;
6681da177e4SLinus Torvalds 		}
6691da177e4SLinus Torvalds 		tmp >>= 1;
6701da177e4SLinus Torvalds 		target++;
6711da177e4SLinus Torvalds 	}
6721da177e4SLinus Torvalds 
673422c0d61SJeff Garzik 	if (scmd_id(SCpnt) != target) {
6741da177e4SLinus Torvalds 		nsp_msg(KERN_ERR, "XXX: reselect ID must be %d in this implementation.", target);
6751da177e4SLinus Torvalds 	}
6761da177e4SLinus Torvalds 
6771da177e4SLinus Torvalds 	nsp_negate_signal(SCpnt, BUSMON_SEL, "reselect<SEL>");
6781da177e4SLinus Torvalds 
6791da177e4SLinus Torvalds 	nsp_nexus(SCpnt);
6801da177e4SLinus Torvalds 	bus_reg = nsp_index_read(base, SCSIBUSCTRL) & ~(SCSI_BSY | SCSI_ATN);
6811da177e4SLinus Torvalds 	nsp_index_write(base, SCSIBUSCTRL, bus_reg);
6821da177e4SLinus Torvalds 	nsp_index_write(base, SCSIBUSCTRL, bus_reg | AUTODIRECTION | ACKENB);
6831da177e4SLinus Torvalds }
6841da177e4SLinus Torvalds 
6851da177e4SLinus Torvalds /*
6861da177e4SLinus Torvalds  * count how many data transferd
6871da177e4SLinus Torvalds  */
nsp_fifo_count(struct scsi_cmnd * SCpnt)6880fc82d5eSHenrik Kretzschmar static int nsp_fifo_count(struct scsi_cmnd *SCpnt)
6891da177e4SLinus Torvalds {
6901da177e4SLinus Torvalds 	unsigned int base = SCpnt->device->host->io_port;
6911da177e4SLinus Torvalds 	unsigned int count;
69297a33483SLee Jones 	unsigned int l, m, h;
6931da177e4SLinus Torvalds 
6941da177e4SLinus Torvalds 	nsp_index_write(base, POINTERCLR, POINTER_CLEAR | ACK_COUNTER);
6951da177e4SLinus Torvalds 
6961da177e4SLinus Torvalds 	l     = nsp_index_read(base, TRANSFERCOUNT);
6971da177e4SLinus Torvalds 	m     = nsp_index_read(base, TRANSFERCOUNT);
6981da177e4SLinus Torvalds 	h     = nsp_index_read(base, TRANSFERCOUNT);
69997a33483SLee Jones 	nsp_index_read(base, TRANSFERCOUNT); /* required this! */
7001da177e4SLinus Torvalds 
7011da177e4SLinus Torvalds 	count = (h << 16) | (m << 8) | (l << 0);
7021da177e4SLinus Torvalds 
7031da177e4SLinus Torvalds 	//nsp_dbg(NSP_DEBUG_DATA_IO, "count=0x%x", count);
7041da177e4SLinus Torvalds 
7051da177e4SLinus Torvalds 	return count;
7061da177e4SLinus Torvalds }
7071da177e4SLinus Torvalds 
7081da177e4SLinus Torvalds /* fifo size */
7091da177e4SLinus Torvalds #define RFIFO_CRIT 64
7101da177e4SLinus Torvalds #define WFIFO_CRIT 64
7111da177e4SLinus Torvalds 
7121da177e4SLinus Torvalds /*
7131da177e4SLinus Torvalds  * read data in DATA IN phase
7141da177e4SLinus Torvalds  */
nsp_pio_read(struct scsi_cmnd * const SCpnt)715ea39700fSBart Van Assche static void nsp_pio_read(struct scsi_cmnd *const SCpnt)
7161da177e4SLinus Torvalds {
717ea39700fSBart Van Assche 	struct scsi_pointer *scsi_pointer = nsp_priv(SCpnt);
7181da177e4SLinus Torvalds 	unsigned int  base      = SCpnt->device->host->io_port;
7191da177e4SLinus Torvalds 	unsigned long mmio_base = SCpnt->device->host->base;
7201da177e4SLinus Torvalds 	nsp_hw_data  *data      = (nsp_hw_data *)SCpnt->device->host->hostdata;
7211da177e4SLinus Torvalds 	long	      time_out;
7221da177e4SLinus Torvalds 	int	      ocount, res;
7231da177e4SLinus Torvalds 	unsigned char stat, fifo_stat;
7241da177e4SLinus Torvalds 
7251da177e4SLinus Torvalds 	ocount = data->FifoCount;
7261da177e4SLinus Torvalds 
7271da177e4SLinus Torvalds 	nsp_dbg(NSP_DEBUG_DATA_IO, "in SCpnt=0x%p resid=%d ocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d",
728ea39700fSBart Van Assche 		SCpnt, scsi_get_resid(SCpnt), ocount, scsi_pointer->ptr,
729ea39700fSBart Van Assche 		scsi_pointer->this_residual, scsi_pointer->buffer,
730ea39700fSBart Van Assche 		scsi_pointer->buffers_residual);
7311da177e4SLinus Torvalds 
7321da177e4SLinus Torvalds 	time_out = 1000;
7331da177e4SLinus Torvalds 
7341da177e4SLinus Torvalds 	while ((time_out-- != 0) &&
735ea39700fSBart Van Assche 	       (scsi_pointer->this_residual > 0 ||
736ea39700fSBart Van Assche 		scsi_pointer->buffers_residual > 0)) {
7371da177e4SLinus Torvalds 
7381da177e4SLinus Torvalds 		stat = nsp_index_read(base, SCSIBUSMON);
7391da177e4SLinus Torvalds 		stat &= BUSMON_PHASE_MASK;
7401da177e4SLinus Torvalds 
7411da177e4SLinus Torvalds 
7421da177e4SLinus Torvalds 		res = nsp_fifo_count(SCpnt) - ocount;
743ea39700fSBart Van Assche 		//nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this=0x%x ocount=0x%x res=0x%x", scsi_pointer->ptr, scsi_pointer->this_residual, ocount, res);
74425985edcSLucas De Marchi 		if (res == 0) { /* if some data available ? */
7451da177e4SLinus Torvalds 			if (stat == BUSPHASE_DATA_IN) { /* phase changed? */
746ea39700fSBart Van Assche 				//nsp_dbg(NSP_DEBUG_DATA_IO, " wait for data this=%d", scsi_pointer->this_residual);
7471da177e4SLinus Torvalds 				continue;
7481da177e4SLinus Torvalds 			} else {
7491da177e4SLinus Torvalds 				nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x", stat);
7501da177e4SLinus Torvalds 				break;
7511da177e4SLinus Torvalds 			}
7521da177e4SLinus Torvalds 		}
7531da177e4SLinus Torvalds 
7541da177e4SLinus Torvalds 		fifo_stat = nsp_read(base, FIFOSTATUS);
7551da177e4SLinus Torvalds 		if ((fifo_stat & FIFOSTATUS_FULL_EMPTY) == 0 &&
7561da177e4SLinus Torvalds 		    stat                                == BUSPHASE_DATA_IN) {
7571da177e4SLinus Torvalds 			continue;
7581da177e4SLinus Torvalds 		}
7591da177e4SLinus Torvalds 
760ea39700fSBart Van Assche 		res = min(res, scsi_pointer->this_residual);
7611da177e4SLinus Torvalds 
7621da177e4SLinus Torvalds 		switch (data->TransferMode) {
7631da177e4SLinus Torvalds 		case MODE_IO32:
7641da177e4SLinus Torvalds 			res &= ~(BIT(1)|BIT(0)); /* align 4 */
765ea39700fSBart Van Assche 			nsp_fifo32_read(base, scsi_pointer->ptr, res >> 2);
7661da177e4SLinus Torvalds 			break;
7671da177e4SLinus Torvalds 		case MODE_IO8:
768ea39700fSBart Van Assche 			nsp_fifo8_read(base, scsi_pointer->ptr, res);
7691da177e4SLinus Torvalds 			break;
7701da177e4SLinus Torvalds 
7711da177e4SLinus Torvalds 		case MODE_MEM32:
7721da177e4SLinus Torvalds 			res &= ~(BIT(1)|BIT(0)); /* align 4 */
773ea39700fSBart Van Assche 			nsp_mmio_fifo32_read(mmio_base, scsi_pointer->ptr,
774ea39700fSBart Van Assche 					     res >> 2);
7751da177e4SLinus Torvalds 			break;
7761da177e4SLinus Torvalds 
7771da177e4SLinus Torvalds 		default:
7781da177e4SLinus Torvalds 			nsp_dbg(NSP_DEBUG_DATA_IO, "unknown read mode");
7791da177e4SLinus Torvalds 			return;
7801da177e4SLinus Torvalds 		}
7811da177e4SLinus Torvalds 
782040cd232SBoaz Harrosh 		nsp_inc_resid(SCpnt, -res);
783ea39700fSBart Van Assche 		scsi_pointer->ptr += res;
784ea39700fSBart Van Assche 		scsi_pointer->this_residual -= res;
7851da177e4SLinus Torvalds 		ocount			 += res;
786ea39700fSBart Van Assche 		//nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this_residual=0x%x ocount=0x%x", scsi_pointer->ptr, scsi_pointer->this_residual, ocount);
7871da177e4SLinus Torvalds 
7881da177e4SLinus Torvalds 		/* go to next scatter list if available */
789ea39700fSBart Van Assche 		if (scsi_pointer->this_residual	== 0 &&
790ea39700fSBart Van Assche 		    scsi_pointer->buffers_residual != 0 ) {
7911da177e4SLinus Torvalds 			//nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next timeout=%d", time_out);
792ea39700fSBart Van Assche 			scsi_pointer->buffers_residual--;
793ea39700fSBart Van Assche 			scsi_pointer->buffer = sg_next(scsi_pointer->buffer);
794ea39700fSBart Van Assche 			scsi_pointer->ptr = BUFFER_ADDR(SCpnt);
795ea39700fSBart Van Assche 			scsi_pointer->this_residual =
796ea39700fSBart Van Assche 				scsi_pointer->buffer->length;
7971da177e4SLinus Torvalds 			time_out = 1000;
7981da177e4SLinus Torvalds 
799ea39700fSBart Van Assche 			//nsp_dbg(NSP_DEBUG_DATA_IO, "page: 0x%p, off: 0x%x", scsi_pointer->buffer->page, scsi_pointer->buffer->offset);
8001da177e4SLinus Torvalds 		}
8011da177e4SLinus Torvalds 	}
8021da177e4SLinus Torvalds 
8031da177e4SLinus Torvalds 	data->FifoCount = ocount;
8041da177e4SLinus Torvalds 
8050454c740SRoel Kluin 	if (time_out < 0) {
8061da177e4SLinus Torvalds 		nsp_msg(KERN_DEBUG, "pio read timeout resid=%d this_residual=%d buffers_residual=%d",
807ea39700fSBart Van Assche 			scsi_get_resid(SCpnt), scsi_pointer->this_residual,
808ea39700fSBart Van Assche 			scsi_pointer->buffers_residual);
8091da177e4SLinus Torvalds 	}
8101da177e4SLinus Torvalds 	nsp_dbg(NSP_DEBUG_DATA_IO, "read ocount=0x%x", ocount);
811040cd232SBoaz Harrosh 	nsp_dbg(NSP_DEBUG_DATA_IO, "r cmd=%d resid=0x%x\n", data->CmdId,
812040cd232SBoaz Harrosh 	                                                scsi_get_resid(SCpnt));
8131da177e4SLinus Torvalds }
8141da177e4SLinus Torvalds 
8151da177e4SLinus Torvalds /*
8161da177e4SLinus Torvalds  * write data in DATA OUT phase
8171da177e4SLinus Torvalds  */
nsp_pio_write(struct scsi_cmnd * SCpnt)8180fc82d5eSHenrik Kretzschmar static void nsp_pio_write(struct scsi_cmnd *SCpnt)
8191da177e4SLinus Torvalds {
820ea39700fSBart Van Assche 	struct scsi_pointer *scsi_pointer = nsp_priv(SCpnt);
8211da177e4SLinus Torvalds 	unsigned int  base      = SCpnt->device->host->io_port;
8221da177e4SLinus Torvalds 	unsigned long mmio_base = SCpnt->device->host->base;
8231da177e4SLinus Torvalds 	nsp_hw_data  *data      = (nsp_hw_data *)SCpnt->device->host->hostdata;
8241da177e4SLinus Torvalds 	int	      time_out;
8251da177e4SLinus Torvalds 	int           ocount, res;
8261da177e4SLinus Torvalds 	unsigned char stat;
8271da177e4SLinus Torvalds 
8281da177e4SLinus Torvalds 	ocount	 = data->FifoCount;
8291da177e4SLinus Torvalds 
8301da177e4SLinus Torvalds 	nsp_dbg(NSP_DEBUG_DATA_IO, "in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x",
831ea39700fSBart Van Assche 		data->FifoCount, scsi_pointer->ptr, scsi_pointer->this_residual,
832ea39700fSBart Van Assche 		scsi_pointer->buffer, scsi_pointer->buffers_residual,
833040cd232SBoaz Harrosh 		scsi_get_resid(SCpnt));
8341da177e4SLinus Torvalds 
8351da177e4SLinus Torvalds 	time_out = 1000;
8361da177e4SLinus Torvalds 
8371da177e4SLinus Torvalds 	while ((time_out-- != 0) &&
838ea39700fSBart Van Assche 	       (scsi_pointer->this_residual > 0 ||
839ea39700fSBart Van Assche 		scsi_pointer->buffers_residual > 0)) {
8401da177e4SLinus Torvalds 		stat = nsp_index_read(base, SCSIBUSMON);
8411da177e4SLinus Torvalds 		stat &= BUSMON_PHASE_MASK;
8421da177e4SLinus Torvalds 
8431da177e4SLinus Torvalds 		if (stat != BUSPHASE_DATA_OUT) {
8441da177e4SLinus Torvalds 			res = ocount - nsp_fifo_count(SCpnt);
8451da177e4SLinus Torvalds 
8461da177e4SLinus Torvalds 			nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x, res=%d\n", stat, res);
8471da177e4SLinus Torvalds 			/* Put back pointer */
848040cd232SBoaz Harrosh 			nsp_inc_resid(SCpnt, res);
849ea39700fSBart Van Assche 			scsi_pointer->ptr -= res;
850ea39700fSBart Van Assche 			scsi_pointer->this_residual += res;
8511da177e4SLinus Torvalds 			ocount -= res;
8521da177e4SLinus Torvalds 
8531da177e4SLinus Torvalds 			break;
8541da177e4SLinus Torvalds 		}
8551da177e4SLinus Torvalds 
8561da177e4SLinus Torvalds 		res = ocount - nsp_fifo_count(SCpnt);
8571da177e4SLinus Torvalds 		if (res > 0) { /* write all data? */
8581da177e4SLinus Torvalds 			nsp_dbg(NSP_DEBUG_DATA_IO, "wait for all data out. ocount=0x%x res=%d", ocount, res);
8591da177e4SLinus Torvalds 			continue;
8601da177e4SLinus Torvalds 		}
8611da177e4SLinus Torvalds 
862ea39700fSBart Van Assche 		res = min(scsi_pointer->this_residual, WFIFO_CRIT);
8631da177e4SLinus Torvalds 
864ea39700fSBart Van Assche 		//nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this=0x%x res=0x%x", scsi_pointer->ptr, scsi_pointer->this_residual, res);
8651da177e4SLinus Torvalds 		switch (data->TransferMode) {
8661da177e4SLinus Torvalds 		case MODE_IO32:
8671da177e4SLinus Torvalds 			res &= ~(BIT(1)|BIT(0)); /* align 4 */
868ea39700fSBart Van Assche 			nsp_fifo32_write(base, scsi_pointer->ptr, res >> 2);
8691da177e4SLinus Torvalds 			break;
8701da177e4SLinus Torvalds 		case MODE_IO8:
871ea39700fSBart Van Assche 			nsp_fifo8_write(base, scsi_pointer->ptr, res);
8721da177e4SLinus Torvalds 			break;
8731da177e4SLinus Torvalds 
8741da177e4SLinus Torvalds 		case MODE_MEM32:
8751da177e4SLinus Torvalds 			res &= ~(BIT(1)|BIT(0)); /* align 4 */
876ea39700fSBart Van Assche 			nsp_mmio_fifo32_write(mmio_base, scsi_pointer->ptr,
877ea39700fSBart Van Assche 					      res >> 2);
8781da177e4SLinus Torvalds 			break;
8791da177e4SLinus Torvalds 
8801da177e4SLinus Torvalds 		default:
8811da177e4SLinus Torvalds 			nsp_dbg(NSP_DEBUG_DATA_IO, "unknown write mode");
8821da177e4SLinus Torvalds 			break;
8831da177e4SLinus Torvalds 		}
8841da177e4SLinus Torvalds 
885040cd232SBoaz Harrosh 		nsp_inc_resid(SCpnt, -res);
886ea39700fSBart Van Assche 		scsi_pointer->ptr += res;
887ea39700fSBart Van Assche 		scsi_pointer->this_residual -= res;
8881da177e4SLinus Torvalds 		ocount += res;
8891da177e4SLinus Torvalds 
8901da177e4SLinus Torvalds 		/* go to next scatter list if available */
891ea39700fSBart Van Assche 		if (scsi_pointer->this_residual	== 0 &&
892ea39700fSBart Van Assche 		    scsi_pointer->buffers_residual != 0 ) {
8931da177e4SLinus Torvalds 			//nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next");
894ea39700fSBart Van Assche 			scsi_pointer->buffers_residual--;
895ea39700fSBart Van Assche 			scsi_pointer->buffer = sg_next(scsi_pointer->buffer);
896ea39700fSBart Van Assche 			scsi_pointer->ptr = BUFFER_ADDR(SCpnt);
897ea39700fSBart Van Assche 			scsi_pointer->this_residual =
898ea39700fSBart Van Assche 				scsi_pointer->buffer->length;
8991da177e4SLinus Torvalds 			time_out = 1000;
9001da177e4SLinus Torvalds 		}
9011da177e4SLinus Torvalds 	}
9021da177e4SLinus Torvalds 
9031da177e4SLinus Torvalds 	data->FifoCount = ocount;
9041da177e4SLinus Torvalds 
9050454c740SRoel Kluin 	if (time_out < 0) {
906040cd232SBoaz Harrosh 		nsp_msg(KERN_DEBUG, "pio write timeout resid=0x%x",
907040cd232SBoaz Harrosh 		                                        scsi_get_resid(SCpnt));
9081da177e4SLinus Torvalds 	}
9091da177e4SLinus Torvalds 	nsp_dbg(NSP_DEBUG_DATA_IO, "write ocount=0x%x", ocount);
910040cd232SBoaz Harrosh 	nsp_dbg(NSP_DEBUG_DATA_IO, "w cmd=%d resid=0x%x\n", data->CmdId,
911040cd232SBoaz Harrosh 	                                                scsi_get_resid(SCpnt));
9121da177e4SLinus Torvalds }
9131da177e4SLinus Torvalds #undef RFIFO_CRIT
9141da177e4SLinus Torvalds #undef WFIFO_CRIT
9151da177e4SLinus Torvalds 
9161da177e4SLinus Torvalds /*
9171da177e4SLinus Torvalds  * setup synchronous/asynchronous data transfer mode
9181da177e4SLinus Torvalds  */
nsp_nexus(struct scsi_cmnd * SCpnt)9190fc82d5eSHenrik Kretzschmar static int nsp_nexus(struct scsi_cmnd *SCpnt)
9201da177e4SLinus Torvalds {
9211da177e4SLinus Torvalds 	unsigned int   base   = SCpnt->device->host->io_port;
922422c0d61SJeff Garzik 	unsigned char  target = scmd_id(SCpnt);
9231da177e4SLinus Torvalds //	unsigned char  lun    = SCpnt->device->lun;
9241da177e4SLinus Torvalds 	nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
9251da177e4SLinus Torvalds 	sync_data     *sync   = &(data->Sync[target]);
9261da177e4SLinus Torvalds 
9271da177e4SLinus Torvalds 	//nsp_dbg(NSP_DEBUG_DATA_IO, "in SCpnt=0x%p", SCpnt);
9281da177e4SLinus Torvalds 
9291da177e4SLinus Torvalds 	/* setup synch transfer registers */
9301da177e4SLinus Torvalds 	nsp_index_write(base, SYNCREG,	sync->SyncRegister);
9311da177e4SLinus Torvalds 	nsp_index_write(base, ACKWIDTH, sync->AckWidth);
9321da177e4SLinus Torvalds 
933040cd232SBoaz Harrosh 	if (scsi_get_resid(SCpnt) % 4 != 0 ||
934040cd232SBoaz Harrosh 	    scsi_get_resid(SCpnt) <= PAGE_SIZE ) {
9351da177e4SLinus Torvalds 		data->TransferMode = MODE_IO8;
9361da177e4SLinus Torvalds 	} else if (nsp_burst_mode == BURST_MEM32) {
9371da177e4SLinus Torvalds 		data->TransferMode = MODE_MEM32;
9381da177e4SLinus Torvalds 	} else if (nsp_burst_mode == BURST_IO32) {
9391da177e4SLinus Torvalds 		data->TransferMode = MODE_IO32;
9401da177e4SLinus Torvalds 	} else {
9411da177e4SLinus Torvalds 		data->TransferMode = MODE_IO8;
9421da177e4SLinus Torvalds 	}
9431da177e4SLinus Torvalds 
9441da177e4SLinus Torvalds 	/* setup pdma fifo */
945dfab1e53SBart Van Assche 	nsp_setup_fifo(data, true);
9461da177e4SLinus Torvalds 
9471da177e4SLinus Torvalds 	/* clear ack counter */
9481da177e4SLinus Torvalds  	data->FifoCount = 0;
9491da177e4SLinus Torvalds 	nsp_index_write(base, POINTERCLR, POINTER_CLEAR	    |
9501da177e4SLinus Torvalds 					  ACK_COUNTER_CLEAR |
9511da177e4SLinus Torvalds 					  REQ_COUNTER_CLEAR |
9521da177e4SLinus Torvalds 					  HOST_COUNTER_CLEAR);
9531da177e4SLinus Torvalds 
9541da177e4SLinus Torvalds 	return 0;
9551da177e4SLinus Torvalds }
9561da177e4SLinus Torvalds 
9571da177e4SLinus Torvalds #include "nsp_message.c"
9581da177e4SLinus Torvalds /*
9591da177e4SLinus Torvalds  * interrupt handler
9601da177e4SLinus Torvalds  */
nspintr(int irq,void * dev_id)9617d12e780SDavid Howells static irqreturn_t nspintr(int irq, void *dev_id)
9621da177e4SLinus Torvalds {
9631da177e4SLinus Torvalds 	unsigned int   base;
9641da177e4SLinus Torvalds 	unsigned char  irq_status, irq_phase, phase;
9650fc82d5eSHenrik Kretzschmar 	struct scsi_cmnd *tmpSC;
966ea39700fSBart Van Assche 	struct scsi_pointer *scsi_pointer;
9671da177e4SLinus Torvalds 	unsigned char  target, lun;
9681da177e4SLinus Torvalds 	unsigned int  *sync_neg;
9691da177e4SLinus Torvalds 	int            i, tmp;
9701da177e4SLinus Torvalds 	nsp_hw_data   *data;
9711da177e4SLinus Torvalds 
9721da177e4SLinus Torvalds 
9731da177e4SLinus Torvalds 	//nsp_dbg(NSP_DEBUG_INTR, "dev_id=0x%p", dev_id);
9741da177e4SLinus Torvalds 	//nsp_dbg(NSP_DEBUG_INTR, "host=0x%p", ((scsi_info_t *)dev_id)->host);
9751da177e4SLinus Torvalds 
9761da177e4SLinus Torvalds 	if (                dev_id        != NULL &&
9771da177e4SLinus Torvalds 	    ((scsi_info_t *)dev_id)->host != NULL  ) {
9781da177e4SLinus Torvalds 		scsi_info_t *info = (scsi_info_t *)dev_id;
9791da177e4SLinus Torvalds 
9801da177e4SLinus Torvalds 		data = (nsp_hw_data *)info->host->hostdata;
9811da177e4SLinus Torvalds 	} else {
9821da177e4SLinus Torvalds 		nsp_dbg(NSP_DEBUG_INTR, "host data wrong");
9831da177e4SLinus Torvalds 		return IRQ_NONE;
9841da177e4SLinus Torvalds 	}
9851da177e4SLinus Torvalds 
9861da177e4SLinus Torvalds 	//nsp_dbg(NSP_DEBUG_INTR, "&nsp_data_base=0x%p, dev_id=0x%p", &nsp_data_base, dev_id);
9871da177e4SLinus Torvalds 
9881da177e4SLinus Torvalds 	base = data->BaseAddress;
9891da177e4SLinus Torvalds 	//nsp_dbg(NSP_DEBUG_INTR, "base=0x%x", base);
9901da177e4SLinus Torvalds 
9911da177e4SLinus Torvalds 	/*
9921da177e4SLinus Torvalds 	 * interrupt check
9931da177e4SLinus Torvalds 	 */
9941da177e4SLinus Torvalds 	nsp_write(base, IRQCONTROL, IRQCONTROL_IRQDISABLE);
9951da177e4SLinus Torvalds 	irq_status = nsp_read(base, IRQSTATUS);
9961da177e4SLinus Torvalds 	//nsp_dbg(NSP_DEBUG_INTR, "irq_status=0x%x", irq_status);
9971da177e4SLinus Torvalds 	if ((irq_status == 0xff) || ((irq_status & IRQSTATUS_MASK) == 0)) {
9981da177e4SLinus Torvalds 		nsp_write(base, IRQCONTROL, 0);
9991da177e4SLinus Torvalds 		//nsp_dbg(NSP_DEBUG_INTR, "no irq/shared irq");
10001da177e4SLinus Torvalds 		return IRQ_NONE;
10011da177e4SLinus Torvalds 	}
10021da177e4SLinus Torvalds 
10031da177e4SLinus Torvalds 	/* XXX: IMPORTANT
10041da177e4SLinus Torvalds 	 * Do not read an irq_phase register if no scsi phase interrupt.
10051da177e4SLinus Torvalds 	 * Unless, you should lose a scsi phase interrupt.
10061da177e4SLinus Torvalds 	 */
10071da177e4SLinus Torvalds 	phase = nsp_index_read(base, SCSIBUSMON);
10081da177e4SLinus Torvalds 	if((irq_status & IRQSTATUS_SCSI) != 0) {
10091da177e4SLinus Torvalds 		irq_phase = nsp_index_read(base, IRQPHASESENCE);
10101da177e4SLinus Torvalds 	} else {
10111da177e4SLinus Torvalds 		irq_phase = 0;
10121da177e4SLinus Torvalds 	}
10131da177e4SLinus Torvalds 
10141da177e4SLinus Torvalds 	//nsp_dbg(NSP_DEBUG_INTR, "irq_phase=0x%x", irq_phase);
10151da177e4SLinus Torvalds 
10161da177e4SLinus Torvalds 	/*
10171da177e4SLinus Torvalds 	 * timer interrupt handler (scsi vs timer interrupts)
10181da177e4SLinus Torvalds 	 */
10191da177e4SLinus Torvalds 	//nsp_dbg(NSP_DEBUG_INTR, "timercount=%d", data->TimerCount);
10201da177e4SLinus Torvalds 	if (data->TimerCount != 0) {
10211da177e4SLinus Torvalds 		//nsp_dbg(NSP_DEBUG_INTR, "stop timer");
10221da177e4SLinus Torvalds 		nsp_index_write(base, TIMERCOUNT, 0);
10231da177e4SLinus Torvalds 		nsp_index_write(base, TIMERCOUNT, 0);
10241da177e4SLinus Torvalds 		data->TimerCount = 0;
10251da177e4SLinus Torvalds 	}
10261da177e4SLinus Torvalds 
10271da177e4SLinus Torvalds 	if ((irq_status & IRQSTATUS_MASK) == IRQSTATUS_TIMER &&
10281da177e4SLinus Torvalds 	    data->SelectionTimeOut == 0) {
10291da177e4SLinus Torvalds 		//nsp_dbg(NSP_DEBUG_INTR, "timer start");
10301da177e4SLinus Torvalds 		nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR);
10311da177e4SLinus Torvalds 		return IRQ_HANDLED;
10321da177e4SLinus Torvalds 	}
10331da177e4SLinus Torvalds 
10341da177e4SLinus Torvalds 	nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR | IRQCONTROL_FIFO_CLEAR);
10351da177e4SLinus Torvalds 
10361da177e4SLinus Torvalds 	if ((irq_status & IRQSTATUS_SCSI) &&
10371da177e4SLinus Torvalds 	    (irq_phase  & SCSI_RESET_IRQ)) {
10381da177e4SLinus Torvalds 		nsp_msg(KERN_ERR, "bus reset (power off?)");
10391da177e4SLinus Torvalds 
10401da177e4SLinus Torvalds 		nsphw_init(data);
10411da177e4SLinus Torvalds 		nsp_bus_reset(data);
10421da177e4SLinus Torvalds 
10431da177e4SLinus Torvalds 		if(data->CurrentSC != NULL) {
10441da177e4SLinus Torvalds 			tmpSC = data->CurrentSC;
1045ea39700fSBart Van Assche 			scsi_pointer = nsp_priv(tmpSC);
10461da177e4SLinus Torvalds 			tmpSC->result = (DID_RESET              << 16) |
1047ea39700fSBart Van Assche 				((scsi_pointer->Message & 0xff) <<  8) |
1048ea39700fSBart Van Assche 				((scsi_pointer->Status  & 0xff) <<  0);
10491da177e4SLinus Torvalds 			nsp_scsi_done(tmpSC);
10501da177e4SLinus Torvalds 		}
10511da177e4SLinus Torvalds 		return IRQ_HANDLED;
10521da177e4SLinus Torvalds 	}
10531da177e4SLinus Torvalds 
10541da177e4SLinus Torvalds 	if (data->CurrentSC == NULL) {
10551da177e4SLinus Torvalds 		nsp_msg(KERN_ERR, "CurrentSC==NULL irq_status=0x%x phase=0x%x irq_phase=0x%x this can't be happen. reset everything", irq_status, phase, irq_phase);
10561da177e4SLinus Torvalds 		nsphw_init(data);
10571da177e4SLinus Torvalds 		nsp_bus_reset(data);
10581da177e4SLinus Torvalds 		return IRQ_HANDLED;
10591da177e4SLinus Torvalds 	}
10601da177e4SLinus Torvalds 
10611da177e4SLinus Torvalds 	tmpSC    = data->CurrentSC;
1062ea39700fSBart Van Assche 	scsi_pointer = nsp_priv(tmpSC);
10631da177e4SLinus Torvalds 	target   = tmpSC->device->id;
10641da177e4SLinus Torvalds 	lun      = tmpSC->device->lun;
10651da177e4SLinus Torvalds 	sync_neg = &(data->Sync[target].SyncNegotiation);
10661da177e4SLinus Torvalds 
10671da177e4SLinus Torvalds 	/*
10681da177e4SLinus Torvalds 	 * parse hardware SCSI irq reasons register
10691da177e4SLinus Torvalds 	 */
10701da177e4SLinus Torvalds 	if (irq_status & IRQSTATUS_SCSI) {
10711da177e4SLinus Torvalds 		if (irq_phase & RESELECT_IRQ) {
10721da177e4SLinus Torvalds 			nsp_dbg(NSP_DEBUG_INTR, "reselect");
10731da177e4SLinus Torvalds 			nsp_write(base, IRQCONTROL, IRQCONTROL_RESELECT_CLEAR);
107472961735SBart Van Assche 			nsp_reselected(tmpSC);
10751da177e4SLinus Torvalds 			return IRQ_HANDLED;
10761da177e4SLinus Torvalds 		}
10771da177e4SLinus Torvalds 
10781da177e4SLinus Torvalds 		if ((irq_phase & (PHASE_CHANGE_IRQ | LATCHED_BUS_FREE)) == 0) {
10791da177e4SLinus Torvalds 			return IRQ_HANDLED;
10801da177e4SLinus Torvalds 		}
10811da177e4SLinus Torvalds 	}
10821da177e4SLinus Torvalds 
10831da177e4SLinus Torvalds 	//show_phase(tmpSC);
10841da177e4SLinus Torvalds 
1085ea39700fSBart Van Assche 	switch (scsi_pointer->phase) {
10861da177e4SLinus Torvalds 	case PH_SELSTART:
10871da177e4SLinus Torvalds 		// *sync_neg = SYNC_NOT_YET;
10881da177e4SLinus Torvalds 		if ((phase & BUSMON_BSY) == 0) {
10891da177e4SLinus Torvalds 			//nsp_dbg(NSP_DEBUG_INTR, "selection count=%d", data->SelectionTimeOut);
10901da177e4SLinus Torvalds 			if (data->SelectionTimeOut >= NSP_SELTIMEOUT) {
10911da177e4SLinus Torvalds 				nsp_dbg(NSP_DEBUG_INTR, "selection time out");
10921da177e4SLinus Torvalds 				data->SelectionTimeOut = 0;
10931da177e4SLinus Torvalds 				nsp_index_write(base, SCSIBUSCTRL, 0);
10941da177e4SLinus Torvalds 
10951da177e4SLinus Torvalds 				tmpSC->result   = DID_TIME_OUT << 16;
10961da177e4SLinus Torvalds 				nsp_scsi_done(tmpSC);
10971da177e4SLinus Torvalds 
10981da177e4SLinus Torvalds 				return IRQ_HANDLED;
10991da177e4SLinus Torvalds 			}
11001da177e4SLinus Torvalds 			data->SelectionTimeOut += 1;
11011da177e4SLinus Torvalds 			nsp_start_timer(tmpSC, 1000/51);
11021da177e4SLinus Torvalds 			return IRQ_HANDLED;
11031da177e4SLinus Torvalds 		}
11041da177e4SLinus Torvalds 
11051da177e4SLinus Torvalds 		/* attention assert */
11061da177e4SLinus Torvalds 		//nsp_dbg(NSP_DEBUG_INTR, "attention assert");
11071da177e4SLinus Torvalds 		data->SelectionTimeOut = 0;
1108ea39700fSBart Van Assche 		scsi_pointer->phase = PH_SELECTED;
11091da177e4SLinus Torvalds 		nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN);
11101da177e4SLinus Torvalds 		udelay(1);
11111da177e4SLinus Torvalds 		nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN | AUTODIRECTION | ACKENB);
11121da177e4SLinus Torvalds 		return IRQ_HANDLED;
11131da177e4SLinus Torvalds 
11141da177e4SLinus Torvalds 	case PH_RESELECT:
11151da177e4SLinus Torvalds 		//nsp_dbg(NSP_DEBUG_INTR, "phase reselect");
11161da177e4SLinus Torvalds 		// *sync_neg = SYNC_NOT_YET;
11171da177e4SLinus Torvalds 		if ((phase & BUSMON_PHASE_MASK) != BUSPHASE_MESSAGE_IN) {
11181da177e4SLinus Torvalds 
11191da177e4SLinus Torvalds 			tmpSC->result	= DID_ABORT << 16;
11201da177e4SLinus Torvalds 			nsp_scsi_done(tmpSC);
11211da177e4SLinus Torvalds 			return IRQ_HANDLED;
11221da177e4SLinus Torvalds 		}
1123df561f66SGustavo A. R. Silva 		fallthrough;
11241da177e4SLinus Torvalds 	default:
11251da177e4SLinus Torvalds 		if ((irq_status & (IRQSTATUS_SCSI | IRQSTATUS_FIFO)) == 0) {
11261da177e4SLinus Torvalds 			return IRQ_HANDLED;
11271da177e4SLinus Torvalds 		}
11281da177e4SLinus Torvalds 		break;
11291da177e4SLinus Torvalds 	}
11301da177e4SLinus Torvalds 
11311da177e4SLinus Torvalds 	/*
11321da177e4SLinus Torvalds 	 * SCSI sequencer
11331da177e4SLinus Torvalds 	 */
11341da177e4SLinus Torvalds 	//nsp_dbg(NSP_DEBUG_INTR, "start scsi seq");
11351da177e4SLinus Torvalds 
11361da177e4SLinus Torvalds 	/* normal disconnect */
1137ea39700fSBart Van Assche 	if ((scsi_pointer->phase == PH_MSG_IN ||
1138ea39700fSBart Van Assche 	     scsi_pointer->phase == PH_MSG_OUT) &&
11391da177e4SLinus Torvalds 	    (irq_phase & LATCHED_BUS_FREE) != 0) {
11401da177e4SLinus Torvalds 		nsp_dbg(NSP_DEBUG_INTR, "normal disconnect irq_status=0x%x, phase=0x%x, irq_phase=0x%x", irq_status, phase, irq_phase);
11411da177e4SLinus Torvalds 
11421da177e4SLinus Torvalds 		//*sync_neg       = SYNC_NOT_YET;
11431da177e4SLinus Torvalds 
11447e1c99e5SNathan Chancellor 		/* all command complete and return status */
1145ea39700fSBart Van Assche 		if (scsi_pointer->Message == COMMAND_COMPLETE) {
11461da177e4SLinus Torvalds 			tmpSC->result = (DID_OK		        << 16) |
1147ea39700fSBart Van Assche 				((scsi_pointer->Message & 0xff) <<  8) |
1148ea39700fSBart Van Assche 				((scsi_pointer->Status  & 0xff) <<  0);
11491da177e4SLinus Torvalds 			nsp_dbg(NSP_DEBUG_INTR, "command complete result=0x%x", tmpSC->result);
11501da177e4SLinus Torvalds 			nsp_scsi_done(tmpSC);
11511da177e4SLinus Torvalds 
11521da177e4SLinus Torvalds 			return IRQ_HANDLED;
11531da177e4SLinus Torvalds 		}
11541da177e4SLinus Torvalds 
11551da177e4SLinus Torvalds 		return IRQ_HANDLED;
11561da177e4SLinus Torvalds 	}
11571da177e4SLinus Torvalds 
11581da177e4SLinus Torvalds 
11591da177e4SLinus Torvalds 	/* check unexpected bus free state */
11601da177e4SLinus Torvalds 	if (phase == 0) {
11611da177e4SLinus Torvalds 		nsp_msg(KERN_DEBUG, "unexpected bus free. irq_status=0x%x, phase=0x%x, irq_phase=0x%x", irq_status, phase, irq_phase);
11621da177e4SLinus Torvalds 
11631da177e4SLinus Torvalds 		*sync_neg       = SYNC_NG;
11641da177e4SLinus Torvalds 		tmpSC->result   = DID_ERROR << 16;
11651da177e4SLinus Torvalds 		nsp_scsi_done(tmpSC);
11661da177e4SLinus Torvalds 		return IRQ_HANDLED;
11671da177e4SLinus Torvalds 	}
11681da177e4SLinus Torvalds 
11691da177e4SLinus Torvalds 	switch (phase & BUSMON_PHASE_MASK) {
11701da177e4SLinus Torvalds 	case BUSPHASE_COMMAND:
11711da177e4SLinus Torvalds 		nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_COMMAND");
11721da177e4SLinus Torvalds 		if ((phase & BUSMON_REQ) == 0) {
11731da177e4SLinus Torvalds 			nsp_dbg(NSP_DEBUG_INTR, "REQ == 0");
11741da177e4SLinus Torvalds 			return IRQ_HANDLED;
11751da177e4SLinus Torvalds 		}
11761da177e4SLinus Torvalds 
1177ea39700fSBart Van Assche 		scsi_pointer->phase = PH_COMMAND;
11781da177e4SLinus Torvalds 
11791da177e4SLinus Torvalds 		nsp_nexus(tmpSC);
11801da177e4SLinus Torvalds 
11811da177e4SLinus Torvalds 		/* write scsi command */
11821da177e4SLinus Torvalds 		nsp_dbg(NSP_DEBUG_INTR, "cmd_len=%d", tmpSC->cmd_len);
11831da177e4SLinus Torvalds 		nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER);
11841da177e4SLinus Torvalds 		for (i = 0; i < tmpSC->cmd_len; i++) {
11851da177e4SLinus Torvalds 			nsp_index_write(base, COMMANDDATA, tmpSC->cmnd[i]);
11861da177e4SLinus Torvalds 		}
11871da177e4SLinus Torvalds 		nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER | AUTO_COMMAND_GO);
11881da177e4SLinus Torvalds 		break;
11891da177e4SLinus Torvalds 
11901da177e4SLinus Torvalds 	case BUSPHASE_DATA_OUT:
11911da177e4SLinus Torvalds 		nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_DATA_OUT");
11921da177e4SLinus Torvalds 
1193ea39700fSBart Van Assche 		scsi_pointer->phase        = PH_DATA;
1194ea39700fSBart Van Assche 		scsi_pointer->have_data_in = IO_OUT;
11951da177e4SLinus Torvalds 
11961da177e4SLinus Torvalds 		nsp_pio_write(tmpSC);
11971da177e4SLinus Torvalds 
11981da177e4SLinus Torvalds 		break;
11991da177e4SLinus Torvalds 
12001da177e4SLinus Torvalds 	case BUSPHASE_DATA_IN:
12011da177e4SLinus Torvalds 		nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_DATA_IN");
12021da177e4SLinus Torvalds 
1203ea39700fSBart Van Assche 		scsi_pointer->phase        = PH_DATA;
1204ea39700fSBart Van Assche 		scsi_pointer->have_data_in = IO_IN;
12051da177e4SLinus Torvalds 
12061da177e4SLinus Torvalds 		nsp_pio_read(tmpSC);
12071da177e4SLinus Torvalds 
12081da177e4SLinus Torvalds 		break;
12091da177e4SLinus Torvalds 
12101da177e4SLinus Torvalds 	case BUSPHASE_STATUS:
12111da177e4SLinus Torvalds 		nsp_dataphase_bypass(tmpSC);
12121da177e4SLinus Torvalds 		nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_STATUS");
12131da177e4SLinus Torvalds 
1214ea39700fSBart Van Assche 		scsi_pointer->phase = PH_STATUS;
12151da177e4SLinus Torvalds 
1216ea39700fSBart Van Assche 		scsi_pointer->Status = nsp_index_read(base, SCSIDATAWITHACK);
1217ea39700fSBart Van Assche 		nsp_dbg(NSP_DEBUG_INTR, "message=0x%x status=0x%x",
1218ea39700fSBart Van Assche 			scsi_pointer->Message, scsi_pointer->Status);
12191da177e4SLinus Torvalds 
12201da177e4SLinus Torvalds 		break;
12211da177e4SLinus Torvalds 
12221da177e4SLinus Torvalds 	case BUSPHASE_MESSAGE_OUT:
12231da177e4SLinus Torvalds 		nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_MESSAGE_OUT");
12241da177e4SLinus Torvalds 		if ((phase & BUSMON_REQ) == 0) {
12251da177e4SLinus Torvalds 			goto timer_out;
12261da177e4SLinus Torvalds 		}
12271da177e4SLinus Torvalds 
1228ea39700fSBart Van Assche 		scsi_pointer->phase = PH_MSG_OUT;
12291da177e4SLinus Torvalds 
12301da177e4SLinus Torvalds 		//*sync_neg = SYNC_NOT_YET;
12311da177e4SLinus Torvalds 
12321da177e4SLinus Torvalds 		data->MsgLen = i = 0;
1233dfab1e53SBart Van Assche 		data->MsgBuffer[i] = IDENTIFY(true, lun); i++;
12341da177e4SLinus Torvalds 
12351da177e4SLinus Torvalds 		if (*sync_neg == SYNC_NOT_YET) {
12361da177e4SLinus Torvalds 			data->Sync[target].SyncPeriod = 0;
12371da177e4SLinus Torvalds 			data->Sync[target].SyncOffset = 0;
12381da177e4SLinus Torvalds 
12391da177e4SLinus Torvalds 			/**/
12401c9eb798SHannes Reinecke 			data->MsgBuffer[i] = EXTENDED_MESSAGE; i++;
12411da177e4SLinus Torvalds 			data->MsgBuffer[i] = 3;            i++;
12421c9eb798SHannes Reinecke 			data->MsgBuffer[i] = EXTENDED_SDTR; i++;
12431da177e4SLinus Torvalds 			data->MsgBuffer[i] = 0x0c;         i++;
12441da177e4SLinus Torvalds 			data->MsgBuffer[i] = 15;           i++;
12451da177e4SLinus Torvalds 			/**/
12461da177e4SLinus Torvalds 		}
12471da177e4SLinus Torvalds 		data->MsgLen = i;
12481da177e4SLinus Torvalds 
12491da177e4SLinus Torvalds 		nsp_analyze_sdtr(tmpSC);
12501da177e4SLinus Torvalds 		show_message(data);
12511da177e4SLinus Torvalds 		nsp_message_out(tmpSC);
12521da177e4SLinus Torvalds 		break;
12531da177e4SLinus Torvalds 
12541da177e4SLinus Torvalds 	case BUSPHASE_MESSAGE_IN:
12551da177e4SLinus Torvalds 		nsp_dataphase_bypass(tmpSC);
12561da177e4SLinus Torvalds 		nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_MESSAGE_IN");
12571da177e4SLinus Torvalds 		if ((phase & BUSMON_REQ) == 0) {
12581da177e4SLinus Torvalds 			goto timer_out;
12591da177e4SLinus Torvalds 		}
12601da177e4SLinus Torvalds 
1261ea39700fSBart Van Assche 		scsi_pointer->phase = PH_MSG_IN;
12621da177e4SLinus Torvalds 		nsp_message_in(tmpSC);
12631da177e4SLinus Torvalds 
12641da177e4SLinus Torvalds 		/**/
12651da177e4SLinus Torvalds 		if (*sync_neg == SYNC_NOT_YET) {
12661da177e4SLinus Torvalds 			//nsp_dbg(NSP_DEBUG_INTR, "sync target=%d,lun=%d",target,lun);
12671da177e4SLinus Torvalds 
12681da177e4SLinus Torvalds 			if (data->MsgLen       >= 5            &&
12691c9eb798SHannes Reinecke 			    data->MsgBuffer[0] == EXTENDED_MESSAGE &&
12701da177e4SLinus Torvalds 			    data->MsgBuffer[1] == 3            &&
12711c9eb798SHannes Reinecke 			    data->MsgBuffer[2] == EXTENDED_SDTR ) {
12721da177e4SLinus Torvalds 				data->Sync[target].SyncPeriod = data->MsgBuffer[3];
12731da177e4SLinus Torvalds 				data->Sync[target].SyncOffset = data->MsgBuffer[4];
12741da177e4SLinus Torvalds 				//nsp_dbg(NSP_DEBUG_INTR, "sync ok, %d %d", data->MsgBuffer[3], data->MsgBuffer[4]);
12751da177e4SLinus Torvalds 				*sync_neg = SYNC_OK;
12761da177e4SLinus Torvalds 			} else {
12771da177e4SLinus Torvalds 				data->Sync[target].SyncPeriod = 0;
12781da177e4SLinus Torvalds 				data->Sync[target].SyncOffset = 0;
12791da177e4SLinus Torvalds 				*sync_neg = SYNC_NG;
12801da177e4SLinus Torvalds 			}
12811da177e4SLinus Torvalds 			nsp_analyze_sdtr(tmpSC);
12821da177e4SLinus Torvalds 		}
12831da177e4SLinus Torvalds 		/**/
12841da177e4SLinus Torvalds 
12851da177e4SLinus Torvalds 		/* search last messeage byte */
12861da177e4SLinus Torvalds 		tmp = -1;
12871da177e4SLinus Torvalds 		for (i = 0; i < data->MsgLen; i++) {
12881da177e4SLinus Torvalds 			tmp = data->MsgBuffer[i];
12891c9eb798SHannes Reinecke 			if (data->MsgBuffer[i] == EXTENDED_MESSAGE) {
12901da177e4SLinus Torvalds 				i += (1 + data->MsgBuffer[i+1]);
12911da177e4SLinus Torvalds 			}
12921da177e4SLinus Torvalds 		}
1293ea39700fSBart Van Assche 		scsi_pointer->Message = tmp;
12941da177e4SLinus Torvalds 
1295ea39700fSBart Van Assche 		nsp_dbg(NSP_DEBUG_INTR, "message=0x%x len=%d",
1296ea39700fSBart Van Assche 			scsi_pointer->Message, data->MsgLen);
12971da177e4SLinus Torvalds 		show_message(data);
12981da177e4SLinus Torvalds 
12991da177e4SLinus Torvalds 		break;
13001da177e4SLinus Torvalds 
13011da177e4SLinus Torvalds 	case BUSPHASE_SELECT:
13021da177e4SLinus Torvalds 	default:
13031da177e4SLinus Torvalds 		nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE other");
13041da177e4SLinus Torvalds 
13051da177e4SLinus Torvalds 		break;
13061da177e4SLinus Torvalds 	}
13071da177e4SLinus Torvalds 
13081da177e4SLinus Torvalds 	//nsp_dbg(NSP_DEBUG_INTR, "out");
13091da177e4SLinus Torvalds 	return IRQ_HANDLED;
13101da177e4SLinus Torvalds 
13111da177e4SLinus Torvalds timer_out:
13121da177e4SLinus Torvalds 	nsp_start_timer(tmpSC, 1000/102);
13131da177e4SLinus Torvalds 	return IRQ_HANDLED;
13141da177e4SLinus Torvalds }
13151da177e4SLinus Torvalds 
13161da177e4SLinus Torvalds #ifdef NSP_DEBUG
13171da177e4SLinus Torvalds #include "nsp_debug.c"
13181da177e4SLinus Torvalds #endif	/* NSP_DEBUG */
13191da177e4SLinus Torvalds 
13201da177e4SLinus Torvalds /*----------------------------------------------------------------*/
13211da177e4SLinus Torvalds /* look for ninja3 card and init if found			  */
13221da177e4SLinus Torvalds /*----------------------------------------------------------------*/
nsp_detect(struct scsi_host_template * sht)1323d0be4a7dSChristoph Hellwig static struct Scsi_Host *nsp_detect(struct scsi_host_template *sht)
13241da177e4SLinus Torvalds {
13251da177e4SLinus Torvalds 	struct Scsi_Host *host;	/* registered host structure */
13261da177e4SLinus Torvalds 	nsp_hw_data *data_b = &nsp_data_base, *data;
13271da177e4SLinus Torvalds 
13281da177e4SLinus Torvalds 	nsp_dbg(NSP_DEBUG_INIT, "this_id=%d", sht->this_id);
13291da177e4SLinus Torvalds 	host = scsi_host_alloc(&nsp_driver_template, sizeof(nsp_hw_data));
13301da177e4SLinus Torvalds 	if (host == NULL) {
13311da177e4SLinus Torvalds 		nsp_dbg(NSP_DEBUG_INIT, "host failed");
13321da177e4SLinus Torvalds 		return NULL;
13331da177e4SLinus Torvalds 	}
13341da177e4SLinus Torvalds 
13351da177e4SLinus Torvalds 	memcpy(host->hostdata, data_b, sizeof(nsp_hw_data));
13361da177e4SLinus Torvalds 	data = (nsp_hw_data *)host->hostdata;
13371da177e4SLinus Torvalds 	data->ScsiInfo->host = host;
13381da177e4SLinus Torvalds #ifdef NSP_DEBUG
13391da177e4SLinus Torvalds 	data->CmdId = 0;
13401da177e4SLinus Torvalds #endif
13411da177e4SLinus Torvalds 
13421da177e4SLinus Torvalds 	nsp_dbg(NSP_DEBUG_INIT, "irq=%d,%d", data_b->IrqNumber, ((nsp_hw_data *)host->hostdata)->IrqNumber);
13431da177e4SLinus Torvalds 
13441da177e4SLinus Torvalds 	host->unique_id	  = data->BaseAddress;
13451da177e4SLinus Torvalds 	host->io_port	  = data->BaseAddress;
13461da177e4SLinus Torvalds 	host->n_io_port	  = data->NumAddress;
13471da177e4SLinus Torvalds 	host->irq	  = data->IrqNumber;
13481da177e4SLinus Torvalds 	host->base        = data->MmioAddress;
13491da177e4SLinus Torvalds 
13501da177e4SLinus Torvalds 	spin_lock_init(&(data->Lock));
13511da177e4SLinus Torvalds 
13521da177e4SLinus Torvalds 	snprintf(data->nspinfo,
13531da177e4SLinus Torvalds 		 sizeof(data->nspinfo),
13541da177e4SLinus Torvalds 		 "NinjaSCSI-3/32Bi Driver $Revision: 1.23 $ IO:0x%04lx-0x%04lx MMIO(virt addr):0x%04lx IRQ:%02d",
13551da177e4SLinus Torvalds 		 host->io_port, host->io_port + host->n_io_port - 1,
13561da177e4SLinus Torvalds 		 host->base,
13571da177e4SLinus Torvalds 		 host->irq);
13581da177e4SLinus Torvalds 	sht->name	  = data->nspinfo;
13591da177e4SLinus Torvalds 
13601da177e4SLinus Torvalds 	nsp_dbg(NSP_DEBUG_INIT, "end");
13611da177e4SLinus Torvalds 
13621da177e4SLinus Torvalds 
13631da177e4SLinus Torvalds 	return host; /* detect done. */
13641da177e4SLinus Torvalds }
13651da177e4SLinus Torvalds 
13661da177e4SLinus Torvalds /*----------------------------------------------------------------*/
13671da177e4SLinus Torvalds /* return info string						  */
13681da177e4SLinus Torvalds /*----------------------------------------------------------------*/
nsp_info(struct Scsi_Host * shpnt)13691da177e4SLinus Torvalds static const char *nsp_info(struct Scsi_Host *shpnt)
13701da177e4SLinus Torvalds {
13711da177e4SLinus Torvalds 	nsp_hw_data *data = (nsp_hw_data *)shpnt->hostdata;
13721da177e4SLinus Torvalds 
13731da177e4SLinus Torvalds 	return data->nspinfo;
13741da177e4SLinus Torvalds }
13751da177e4SLinus Torvalds 
nsp_show_info(struct seq_file * m,struct Scsi_Host * host)137663fd57cbSAl Viro static int nsp_show_info(struct seq_file *m, struct Scsi_Host *host)
13771da177e4SLinus Torvalds {
13781da177e4SLinus Torvalds 	int id;
13791da177e4SLinus Torvalds 	int speed;
13801da177e4SLinus Torvalds 	unsigned long flags;
13811da177e4SLinus Torvalds 	nsp_hw_data *data;
13821da177e4SLinus Torvalds 	int hostno;
1383774251efSAdrian Bunk 
13841da177e4SLinus Torvalds 	hostno = host->host_no;
13851da177e4SLinus Torvalds 	data = (nsp_hw_data *)host->hostdata;
13861da177e4SLinus Torvalds 
13873d30079cSRasmus Villemoes 	seq_puts(m, "NinjaSCSI status\n\n"
13883d30079cSRasmus Villemoes 		"Driver version:        $Revision: 1.23 $\n");
13890c3de38fSRasmus Villemoes 	seq_printf(m, "SCSI host No.:         %d\n",          hostno);
13900c3de38fSRasmus Villemoes 	seq_printf(m, "IRQ:                   %d\n",          host->irq);
13910c3de38fSRasmus Villemoes 	seq_printf(m, "IO:                    0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1);
13920c3de38fSRasmus Villemoes 	seq_printf(m, "MMIO(virtual address): 0x%lx-0x%lx\n", host->base, host->base + data->MmioLength - 1);
13930c3de38fSRasmus Villemoes 	seq_printf(m, "sg_tablesize:          %d\n",          host->sg_tablesize);
13941da177e4SLinus Torvalds 
139591c40f24SRasmus Villemoes 	seq_puts(m, "burst transfer mode:   ");
13961da177e4SLinus Torvalds 	switch (nsp_burst_mode) {
13971da177e4SLinus Torvalds 	case BURST_IO8:
139891c40f24SRasmus Villemoes 		seq_puts(m, "io8");
13991da177e4SLinus Torvalds 		break;
14001da177e4SLinus Torvalds 	case BURST_IO32:
140191c40f24SRasmus Villemoes 		seq_puts(m, "io32");
14021da177e4SLinus Torvalds 		break;
14031da177e4SLinus Torvalds 	case BURST_MEM32:
140491c40f24SRasmus Villemoes 		seq_puts(m, "mem32");
14051da177e4SLinus Torvalds 		break;
14061da177e4SLinus Torvalds 	default:
140791c40f24SRasmus Villemoes 		seq_puts(m, "???");
14081da177e4SLinus Torvalds 		break;
14091da177e4SLinus Torvalds 	}
1410f50332ffSRasmus Villemoes 	seq_putc(m, '\n');
14111da177e4SLinus Torvalds 
14121da177e4SLinus Torvalds 
14131da177e4SLinus Torvalds 	spin_lock_irqsave(&(data->Lock), flags);
14140c3de38fSRasmus Villemoes 	seq_printf(m, "CurrentSC:             0x%p\n\n",      data->CurrentSC);
14151da177e4SLinus Torvalds 	spin_unlock_irqrestore(&(data->Lock), flags);
14161da177e4SLinus Torvalds 
141791c40f24SRasmus Villemoes 	seq_puts(m, "SDTR status\n");
14181da177e4SLinus Torvalds 	for(id = 0; id < ARRAY_SIZE(data->Sync); id++) {
14191da177e4SLinus Torvalds 
14200c3de38fSRasmus Villemoes 		seq_printf(m, "id %d: ", id);
14211da177e4SLinus Torvalds 
14221da177e4SLinus Torvalds 		if (id == host->this_id) {
142391c40f24SRasmus Villemoes 			seq_puts(m, "----- NinjaSCSI-3 host adapter\n");
14241da177e4SLinus Torvalds 			continue;
14251da177e4SLinus Torvalds 		}
14261da177e4SLinus Torvalds 
14271da177e4SLinus Torvalds 		switch(data->Sync[id].SyncNegotiation) {
14281da177e4SLinus Torvalds 		case SYNC_OK:
142991c40f24SRasmus Villemoes 			seq_puts(m, " sync");
14301da177e4SLinus Torvalds 			break;
14311da177e4SLinus Torvalds 		case SYNC_NG:
143291c40f24SRasmus Villemoes 			seq_puts(m, "async");
14331da177e4SLinus Torvalds 			break;
14341da177e4SLinus Torvalds 		case SYNC_NOT_YET:
143591c40f24SRasmus Villemoes 			seq_puts(m, " none");
14361da177e4SLinus Torvalds 			break;
14371da177e4SLinus Torvalds 		default:
143891c40f24SRasmus Villemoes 			seq_puts(m, "?????");
14391da177e4SLinus Torvalds 			break;
14401da177e4SLinus Torvalds 		}
14411da177e4SLinus Torvalds 
14421da177e4SLinus Torvalds 		if (data->Sync[id].SyncPeriod != 0) {
14431da177e4SLinus Torvalds 			speed = 1000000 / (data->Sync[id].SyncPeriod * 4);
14441da177e4SLinus Torvalds 
14450c3de38fSRasmus Villemoes 			seq_printf(m, " transfer %d.%dMB/s, offset %d",
14461da177e4SLinus Torvalds 				speed / 1000,
14471da177e4SLinus Torvalds 				speed % 1000,
14481da177e4SLinus Torvalds 				data->Sync[id].SyncOffset
14491da177e4SLinus Torvalds 				);
14501da177e4SLinus Torvalds 		}
1451f50332ffSRasmus Villemoes 		seq_putc(m, '\n');
14521da177e4SLinus Torvalds 	}
14531da177e4SLinus Torvalds 	return 0;
14541da177e4SLinus Torvalds }
14551da177e4SLinus Torvalds 
14561da177e4SLinus Torvalds /*---------------------------------------------------------------*/
14571da177e4SLinus Torvalds /* error handler                                                 */
14581da177e4SLinus Torvalds /*---------------------------------------------------------------*/
14591da177e4SLinus Torvalds 
14601da177e4SLinus Torvalds /*
14610fc82d5eSHenrik Kretzschmar static int nsp_eh_abort(struct scsi_cmnd *SCpnt)
14621da177e4SLinus Torvalds {
14631da177e4SLinus Torvalds 	nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt);
14641da177e4SLinus Torvalds 
14651da177e4SLinus Torvalds 	return nsp_eh_bus_reset(SCpnt);
14661da177e4SLinus Torvalds }*/
14671da177e4SLinus Torvalds 
nsp_bus_reset(nsp_hw_data * data)14681da177e4SLinus Torvalds static int nsp_bus_reset(nsp_hw_data *data)
14691da177e4SLinus Torvalds {
14701da177e4SLinus Torvalds 	unsigned int base = data->BaseAddress;
14711da177e4SLinus Torvalds 	int	     i;
14721da177e4SLinus Torvalds 
14731da177e4SLinus Torvalds 	nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK);
14741da177e4SLinus Torvalds 
14751da177e4SLinus Torvalds 	nsp_index_write(base, SCSIBUSCTRL, SCSI_RST);
14761da177e4SLinus Torvalds 	mdelay(100); /* 100ms */
14771da177e4SLinus Torvalds 	nsp_index_write(base, SCSIBUSCTRL, 0);
14781da177e4SLinus Torvalds 	for(i = 0; i < 5; i++) {
14791da177e4SLinus Torvalds 		nsp_index_read(base, IRQPHASESENCE); /* dummy read */
14801da177e4SLinus Torvalds 	}
14811da177e4SLinus Torvalds 
14821da177e4SLinus Torvalds 	nsphw_init_sync(data);
14831da177e4SLinus Torvalds 
14841da177e4SLinus Torvalds 	nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR);
14851da177e4SLinus Torvalds 
14861da177e4SLinus Torvalds 	return SUCCESS;
14871da177e4SLinus Torvalds }
14881da177e4SLinus Torvalds 
nsp_eh_bus_reset(struct scsi_cmnd * SCpnt)14890fc82d5eSHenrik Kretzschmar static int nsp_eh_bus_reset(struct scsi_cmnd *SCpnt)
14901da177e4SLinus Torvalds {
14911da177e4SLinus Torvalds 	nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
14921da177e4SLinus Torvalds 
14931da177e4SLinus Torvalds 	nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt);
14941da177e4SLinus Torvalds 
14951da177e4SLinus Torvalds 	return nsp_bus_reset(data);
14961da177e4SLinus Torvalds }
14971da177e4SLinus Torvalds 
nsp_eh_host_reset(struct scsi_cmnd * SCpnt)14980fc82d5eSHenrik Kretzschmar static int nsp_eh_host_reset(struct scsi_cmnd *SCpnt)
14991da177e4SLinus Torvalds {
15001da177e4SLinus Torvalds 	nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
15011da177e4SLinus Torvalds 
15021da177e4SLinus Torvalds 	nsp_dbg(NSP_DEBUG_BUSRESET, "in");
15031da177e4SLinus Torvalds 
15041da177e4SLinus Torvalds 	nsphw_init(data);
15051da177e4SLinus Torvalds 
15061da177e4SLinus Torvalds 	return SUCCESS;
15071da177e4SLinus Torvalds }
15081da177e4SLinus Torvalds 
15091da177e4SLinus Torvalds 
15101da177e4SLinus Torvalds /**********************************************************************
15111da177e4SLinus Torvalds   PCMCIA functions
15121da177e4SLinus Torvalds **********************************************************************/
15131da177e4SLinus Torvalds 
nsp_cs_probe(struct pcmcia_device * link)151415b99ac1SDominik Brodowski static int nsp_cs_probe(struct pcmcia_device *link)
15151da177e4SLinus Torvalds {
15161da177e4SLinus Torvalds 	scsi_info_t  *info;
15171da177e4SLinus Torvalds 	nsp_hw_data  *data = &nsp_data_base;
151815b99ac1SDominik Brodowski 	int ret;
15191da177e4SLinus Torvalds 
15201da177e4SLinus Torvalds 	nsp_dbg(NSP_DEBUG_INIT, "in");
15211da177e4SLinus Torvalds 
15221da177e4SLinus Torvalds 	/* Create new SCSI device */
1523dd00cc48SYoann Padioleau 	info = kzalloc(sizeof(*info), GFP_KERNEL);
1524f8cfa618SDominik Brodowski 	if (info == NULL) { return -ENOMEM; }
1525fba395eeSDominik Brodowski 	info->p_dev = link;
15261da177e4SLinus Torvalds 	link->priv = info;
15271da177e4SLinus Torvalds 	data->ScsiInfo = info;
15281da177e4SLinus Torvalds 
15291da177e4SLinus Torvalds 	nsp_dbg(NSP_DEBUG_INIT, "info=0x%p", info);
15301da177e4SLinus Torvalds 
153115b99ac1SDominik Brodowski 	ret = nsp_cs_config(link);
15321da177e4SLinus Torvalds 
15331da177e4SLinus Torvalds 	nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link);
153415b99ac1SDominik Brodowski 	return ret;
15351da177e4SLinus Torvalds } /* nsp_cs_attach */
15361da177e4SLinus Torvalds 
15371da177e4SLinus Torvalds 
nsp_cs_detach(struct pcmcia_device * link)1538fba395eeSDominik Brodowski static void nsp_cs_detach(struct pcmcia_device *link)
15391da177e4SLinus Torvalds {
15401da177e4SLinus Torvalds 	nsp_dbg(NSP_DEBUG_INIT, "in, link=0x%p", link);
15411da177e4SLinus Torvalds 
1542cc3b4866SDominik Brodowski 	((scsi_info_t *)link->priv)->stop = 1;
15431da177e4SLinus Torvalds 	nsp_cs_release(link);
15441da177e4SLinus Torvalds 
15451da177e4SLinus Torvalds 	kfree(link->priv);
15461da177e4SLinus Torvalds 	link->priv = NULL;
15471da177e4SLinus Torvalds } /* nsp_cs_detach */
15481da177e4SLinus Torvalds 
15491da177e4SLinus Torvalds 
nsp_cs_config_check(struct pcmcia_device * p_dev,void * priv_data)155000990e7cSDominik Brodowski static int nsp_cs_config_check(struct pcmcia_device *p_dev, void *priv_data)
15510e6f9d27SDominik Brodowski {
1552cdb13808SDominik Brodowski 	nsp_hw_data		*data = priv_data;
15531da177e4SLinus Torvalds 
155400990e7cSDominik Brodowski 	if (p_dev->config_index == 0)
15550e6f9d27SDominik Brodowski 		return -ENODEV;
15561da177e4SLinus Torvalds 
15571da177e4SLinus Torvalds 	/* This reserves IO space but doesn't actually enable it */
155890abdc3bSDominik Brodowski 	if (pcmcia_request_io(p_dev) != 0)
15591da177e4SLinus Torvalds 		goto next_entry;
15601da177e4SLinus Torvalds 
156100990e7cSDominik Brodowski 	if (resource_size(p_dev->resource[2])) {
1562cdb13808SDominik Brodowski 		p_dev->resource[2]->flags |= (WIN_DATA_WIDTH_16 |
1563cdb13808SDominik Brodowski 					WIN_MEMORY_TYPE_CM |
1564cdb13808SDominik Brodowski 					WIN_ENABLE);
1565cdb13808SDominik Brodowski 		if (p_dev->resource[2]->end < 0x1000)
1566cdb13808SDominik Brodowski 			p_dev->resource[2]->end = 0x1000;
1567440eed43SDominik Brodowski 		if (pcmcia_request_window(p_dev, p_dev->resource[2], 0) != 0)
15681da177e4SLinus Torvalds 			goto next_entry;
1569cdb13808SDominik Brodowski 		if (pcmcia_map_mem_page(p_dev, p_dev->resource[2],
157000990e7cSDominik Brodowski 						p_dev->card_addr) != 0)
15711da177e4SLinus Torvalds 			goto next_entry;
15721da177e4SLinus Torvalds 
1573cdb13808SDominik Brodowski 		data->MmioAddress = (unsigned long)
15744bdc0d67SChristoph Hellwig 			ioremap(p_dev->resource[2]->start,
1575cdb13808SDominik Brodowski 					resource_size(p_dev->resource[2]));
15762576e153SJiasheng Jiang 		if (!data->MmioAddress)
15772576e153SJiasheng Jiang 			goto next_entry;
15782576e153SJiasheng Jiang 
1579cdb13808SDominik Brodowski 		data->MmioLength  = resource_size(p_dev->resource[2]);
15801da177e4SLinus Torvalds 	}
15811da177e4SLinus Torvalds 	/* If we got this far, we're cool! */
15820e6f9d27SDominik Brodowski 	return 0;
15831da177e4SLinus Torvalds 
15841da177e4SLinus Torvalds next_entry:
15851da177e4SLinus Torvalds 	nsp_dbg(NSP_DEBUG_INIT, "next");
15860e6f9d27SDominik Brodowski 	pcmcia_disable_device(p_dev);
15870e6f9d27SDominik Brodowski 	return -ENODEV;
15881da177e4SLinus Torvalds }
15891da177e4SLinus Torvalds 
nsp_cs_config(struct pcmcia_device * link)15900e6f9d27SDominik Brodowski static int nsp_cs_config(struct pcmcia_device *link)
15910e6f9d27SDominik Brodowski {
15920e6f9d27SDominik Brodowski 	int		  ret;
15930e6f9d27SDominik Brodowski 	scsi_info_t	 *info	 = link->priv;
15940e6f9d27SDominik Brodowski 	struct Scsi_Host *host;
15950e6f9d27SDominik Brodowski 	nsp_hw_data      *data = &nsp_data_base;
15960e6f9d27SDominik Brodowski 
15970e6f9d27SDominik Brodowski 	nsp_dbg(NSP_DEBUG_INIT, "in");
15980e6f9d27SDominik Brodowski 
1599440eed43SDominik Brodowski 	link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_CHECK_VCC |
160000990e7cSDominik Brodowski 		CONF_AUTO_SET_VPP | CONF_AUTO_AUDIO | CONF_AUTO_SET_IOMEM |
160100990e7cSDominik Brodowski 		CONF_AUTO_SET_IO;
1602440eed43SDominik Brodowski 
1603cdb13808SDominik Brodowski 	ret = pcmcia_loop_config(link, nsp_cs_config_check, data);
1604e794c01bSDan Carpenter 	if (ret)
16050e6f9d27SDominik Brodowski 		goto cs_failed;
16060e6f9d27SDominik Brodowski 
1607eb14120fSDominik Brodowski 	if (pcmcia_request_irq(link, nspintr))
16080e6f9d27SDominik Brodowski 		goto cs_failed;
16090e6f9d27SDominik Brodowski 
16101ac71e5aSDominik Brodowski 	ret = pcmcia_enable_device(link);
16110e6f9d27SDominik Brodowski 	if (ret)
16120e6f9d27SDominik Brodowski 		goto cs_failed;
16131da177e4SLinus Torvalds 
16141da177e4SLinus Torvalds 	if (free_ports) {
16159a017a91SDominik Brodowski 		if (link->resource[0]) {
16169a017a91SDominik Brodowski 			release_region(link->resource[0]->start,
16179a017a91SDominik Brodowski 					resource_size(link->resource[0]));
16181da177e4SLinus Torvalds 		}
16199a017a91SDominik Brodowski 		if (link->resource[1]) {
16209a017a91SDominik Brodowski 			release_region(link->resource[1]->start,
16219a017a91SDominik Brodowski 					resource_size(link->resource[1]));
16221da177e4SLinus Torvalds 		}
16231da177e4SLinus Torvalds 	}
16241da177e4SLinus Torvalds 
16251da177e4SLinus Torvalds 	/* Set port and IRQ */
16269a017a91SDominik Brodowski 	data->BaseAddress = link->resource[0]->start;
16279a017a91SDominik Brodowski 	data->NumAddress  = resource_size(link->resource[0]);
1628eb14120fSDominik Brodowski 	data->IrqNumber   = link->irq;
16291da177e4SLinus Torvalds 
16301da177e4SLinus Torvalds 	nsp_dbg(NSP_DEBUG_INIT, "I/O[0x%x+0x%x] IRQ %d",
16311da177e4SLinus Torvalds 		data->BaseAddress, data->NumAddress, data->IrqNumber);
16321da177e4SLinus Torvalds 
163372961735SBart Van Assche 	nsphw_init(data);
16341da177e4SLinus Torvalds 
16351da177e4SLinus Torvalds 	host = nsp_detect(&nsp_driver_template);
16361da177e4SLinus Torvalds 
16371da177e4SLinus Torvalds 	if (host == NULL) {
16381da177e4SLinus Torvalds 		nsp_dbg(NSP_DEBUG_INIT, "detect failed");
16391da177e4SLinus Torvalds 		goto cs_failed;
16401da177e4SLinus Torvalds 	}
16411da177e4SLinus Torvalds 
16421da177e4SLinus Torvalds 
164315b99ac1SDominik Brodowski 	ret = scsi_add_host (host, NULL);
164415b99ac1SDominik Brodowski 	if (ret)
164515b99ac1SDominik Brodowski 		goto cs_failed;
164615b99ac1SDominik Brodowski 
16471da177e4SLinus Torvalds 	scsi_scan_host(host);
16481da177e4SLinus Torvalds 
16491da177e4SLinus Torvalds 	info->host = host;
16501da177e4SLinus Torvalds 
165115b99ac1SDominik Brodowski 	return 0;
16521da177e4SLinus Torvalds 
16531da177e4SLinus Torvalds  cs_failed:
16541da177e4SLinus Torvalds 	nsp_dbg(NSP_DEBUG_INIT, "config fail");
16551da177e4SLinus Torvalds 	nsp_cs_release(link);
16561da177e4SLinus Torvalds 
165715b99ac1SDominik Brodowski 	return -ENODEV;
16581da177e4SLinus Torvalds } /* nsp_cs_config */
16591da177e4SLinus Torvalds 
16601da177e4SLinus Torvalds 
nsp_cs_release(struct pcmcia_device * link)1661fba395eeSDominik Brodowski static void nsp_cs_release(struct pcmcia_device *link)
16621da177e4SLinus Torvalds {
16631da177e4SLinus Torvalds 	scsi_info_t *info = link->priv;
16641da177e4SLinus Torvalds 	nsp_hw_data *data = NULL;
16651da177e4SLinus Torvalds 
16661da177e4SLinus Torvalds 	if (info->host == NULL) {
16671da177e4SLinus Torvalds 		nsp_msg(KERN_DEBUG, "unexpected card release call.");
16681da177e4SLinus Torvalds 	} else {
16691da177e4SLinus Torvalds 		data = (nsp_hw_data *)info->host->hostdata;
16701da177e4SLinus Torvalds 	}
16711da177e4SLinus Torvalds 
16721da177e4SLinus Torvalds 	nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link);
16731da177e4SLinus Torvalds 
16741da177e4SLinus Torvalds 	/* Unlink the device chain */
16751da177e4SLinus Torvalds 	if (info->host != NULL) {
16761da177e4SLinus Torvalds 		scsi_remove_host(info->host);
16771da177e4SLinus Torvalds 	}
16781da177e4SLinus Torvalds 
1679cdb13808SDominik Brodowski 	if (resource_size(link->resource[2])) {
16801da177e4SLinus Torvalds 		if (data != NULL) {
16811da177e4SLinus Torvalds 			iounmap((void *)(data->MmioAddress));
16821da177e4SLinus Torvalds 		}
16831da177e4SLinus Torvalds 	}
1684fba395eeSDominik Brodowski 	pcmcia_disable_device(link);
16855f2a71fcSDominik Brodowski 
16861da177e4SLinus Torvalds 	if (info->host != NULL) {
16871da177e4SLinus Torvalds 		scsi_host_put(info->host);
16881da177e4SLinus Torvalds 	}
16891da177e4SLinus Torvalds } /* nsp_cs_release */
16901da177e4SLinus Torvalds 
nsp_cs_suspend(struct pcmcia_device * link)1691fba395eeSDominik Brodowski static int nsp_cs_suspend(struct pcmcia_device *link)
169298e4c28bSDominik Brodowski {
169398e4c28bSDominik Brodowski 	scsi_info_t *info = link->priv;
169498e4c28bSDominik Brodowski 	nsp_hw_data *data;
169598e4c28bSDominik Brodowski 
169698e4c28bSDominik Brodowski 	nsp_dbg(NSP_DEBUG_INIT, "event: suspend");
169798e4c28bSDominik Brodowski 
169898e4c28bSDominik Brodowski 	if (info->host != NULL) {
169998e4c28bSDominik Brodowski 		nsp_msg(KERN_INFO, "clear SDTR status");
170098e4c28bSDominik Brodowski 
170198e4c28bSDominik Brodowski 		data = (nsp_hw_data *)info->host->hostdata;
170298e4c28bSDominik Brodowski 
170398e4c28bSDominik Brodowski 		nsphw_init_sync(data);
170498e4c28bSDominik Brodowski 	}
170598e4c28bSDominik Brodowski 
170698e4c28bSDominik Brodowski 	info->stop = 1;
170798e4c28bSDominik Brodowski 
170898e4c28bSDominik Brodowski 	return 0;
170998e4c28bSDominik Brodowski }
171098e4c28bSDominik Brodowski 
nsp_cs_resume(struct pcmcia_device * link)1711fba395eeSDominik Brodowski static int nsp_cs_resume(struct pcmcia_device *link)
171298e4c28bSDominik Brodowski {
171398e4c28bSDominik Brodowski 	scsi_info_t *info = link->priv;
171498e4c28bSDominik Brodowski 	nsp_hw_data *data;
171598e4c28bSDominik Brodowski 
171698e4c28bSDominik Brodowski 	nsp_dbg(NSP_DEBUG_INIT, "event: resume");
171798e4c28bSDominik Brodowski 
171898e4c28bSDominik Brodowski 	info->stop = 0;
171998e4c28bSDominik Brodowski 
172098e4c28bSDominik Brodowski 	if (info->host != NULL) {
172198e4c28bSDominik Brodowski 		nsp_msg(KERN_INFO, "reset host and bus");
172298e4c28bSDominik Brodowski 
172398e4c28bSDominik Brodowski 		data = (nsp_hw_data *)info->host->hostdata;
172498e4c28bSDominik Brodowski 
172598e4c28bSDominik Brodowski 		nsphw_init   (data);
172698e4c28bSDominik Brodowski 		nsp_bus_reset(data);
172798e4c28bSDominik Brodowski 	}
172898e4c28bSDominik Brodowski 
172998e4c28bSDominik Brodowski 	return 0;
173098e4c28bSDominik Brodowski }
173198e4c28bSDominik Brodowski 
17321da177e4SLinus Torvalds /*======================================================================*
17331da177e4SLinus Torvalds  *	module entry point
17341da177e4SLinus Torvalds  *====================================================================*/
173525f8f54fSJoe Perches static const struct pcmcia_device_id nsp_cs_ids[] = {
1736aba14100SDominik Brodowski 	PCMCIA_DEVICE_PROD_ID123("IO DATA", "CBSC16       ", "1", 0x547e66dc, 0x0d63a3fd, 0x51de003a),
1737aba14100SDominik Brodowski 	PCMCIA_DEVICE_PROD_ID123("KME    ", "SCSI-CARD-001", "1", 0x534c02bc, 0x52008408, 0x51de003a),
1738aba14100SDominik Brodowski 	PCMCIA_DEVICE_PROD_ID123("KME    ", "SCSI-CARD-002", "1", 0x534c02bc, 0xcb09d5b2, 0x51de003a),
1739aba14100SDominik Brodowski 	PCMCIA_DEVICE_PROD_ID123("KME    ", "SCSI-CARD-003", "1", 0x534c02bc, 0xbc0ee524, 0x51de003a),
1740aba14100SDominik Brodowski 	PCMCIA_DEVICE_PROD_ID123("KME    ", "SCSI-CARD-004", "1", 0x534c02bc, 0x226a7087, 0x51de003a),
1741aba14100SDominik Brodowski 	PCMCIA_DEVICE_PROD_ID123("WBT", "NinjaSCSI-3", "R1.0", 0xc7ba805f, 0xfdc7c97d, 0x6973710e),
1742aba14100SDominik Brodowski 	PCMCIA_DEVICE_PROD_ID123("WORKBIT", "UltraNinja-16", "1", 0x28191418, 0xb70f4b09, 0x51de003a),
1743aba14100SDominik Brodowski 	PCMCIA_DEVICE_NULL
1744aba14100SDominik Brodowski };
1745aba14100SDominik Brodowski MODULE_DEVICE_TABLE(pcmcia, nsp_cs_ids);
1746aba14100SDominik Brodowski 
17471da177e4SLinus Torvalds static struct pcmcia_driver nsp_driver = {
17481da177e4SLinus Torvalds 	.owner		= THIS_MODULE,
17491da177e4SLinus Torvalds 	.name		= "nsp_cs",
175015b99ac1SDominik Brodowski 	.probe		= nsp_cs_probe,
1751cc3b4866SDominik Brodowski 	.remove		= nsp_cs_detach,
1752aba14100SDominik Brodowski 	.id_table	= nsp_cs_ids,
175398e4c28bSDominik Brodowski 	.suspend	= nsp_cs_suspend,
175498e4c28bSDominik Brodowski 	.resume		= nsp_cs_resume,
17551da177e4SLinus Torvalds };
1756dc245cfaSVaishali Thakkar module_pcmcia_driver(nsp_driver);
17571da177e4SLinus Torvalds 
17581da177e4SLinus Torvalds /* end */
1759