xref: /OK3568_Linux_fs/kernel/drivers/scsi/pcmcia/nsp_cs.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*======================================================================
2*4882a593Smuzhiyun 
3*4882a593Smuzhiyun     NinjaSCSI-3 / NinjaSCSI-32Bi PCMCIA SCSI host adapter card driver
4*4882a593Smuzhiyun       By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun     Ver.2.8   Support 32bit MMIO mode
7*4882a593Smuzhiyun               Support Synchronous Data Transfer Request (SDTR) mode
8*4882a593Smuzhiyun     Ver.2.0   Support 32bit PIO mode
9*4882a593Smuzhiyun     Ver.1.1.2 Fix for scatter list buffer exceeds
10*4882a593Smuzhiyun     Ver.1.1   Support scatter list
11*4882a593Smuzhiyun     Ver.0.1   Initial version
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun     This software may be used and distributed according to the terms of
14*4882a593Smuzhiyun     the GNU General Public License.
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun ======================================================================*/
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun /***********************************************************************
19*4882a593Smuzhiyun     This driver is for these PCcards.
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun 	I-O DATA PCSC-F	 (Workbit NinjaSCSI-3)
22*4882a593Smuzhiyun 			"WBT", "NinjaSCSI-3", "R1.0"
23*4882a593Smuzhiyun 	I-O DATA CBSC-II (Workbit NinjaSCSI-32Bi in 16bit mode)
24*4882a593Smuzhiyun 			"IO DATA", "CBSC16	 ", "1"
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun ***********************************************************************/
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #include <linux/module.h>
29*4882a593Smuzhiyun #include <linux/kernel.h>
30*4882a593Smuzhiyun #include <linux/init.h>
31*4882a593Smuzhiyun #include <linux/slab.h>
32*4882a593Smuzhiyun #include <linux/string.h>
33*4882a593Smuzhiyun #include <linux/timer.h>
34*4882a593Smuzhiyun #include <linux/ioport.h>
35*4882a593Smuzhiyun #include <linux/delay.h>
36*4882a593Smuzhiyun #include <linux/interrupt.h>
37*4882a593Smuzhiyun #include <linux/major.h>
38*4882a593Smuzhiyun #include <linux/blkdev.h>
39*4882a593Smuzhiyun #include <linux/stat.h>
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun #include <asm/io.h>
42*4882a593Smuzhiyun #include <asm/irq.h>
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun #include <../drivers/scsi/scsi.h>
45*4882a593Smuzhiyun #include <scsi/scsi_host.h>
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun #include <scsi/scsi.h>
48*4882a593Smuzhiyun #include <scsi/scsi_ioctl.h>
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun #include <pcmcia/cistpl.h>
51*4882a593Smuzhiyun #include <pcmcia/cisreg.h>
52*4882a593Smuzhiyun #include <pcmcia/ds.h>
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun #include "nsp_cs.h"
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun MODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>");
57*4882a593Smuzhiyun MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module");
58*4882a593Smuzhiyun MODULE_SUPPORTED_DEVICE("sd,sr,sg,st");
59*4882a593Smuzhiyun MODULE_LICENSE("GPL");
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun #include "nsp_io.h"
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun /*====================================================================*/
64*4882a593Smuzhiyun /* Parameters that can be set with 'insmod' */
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun static int       nsp_burst_mode = BURST_MEM32;
67*4882a593Smuzhiyun module_param(nsp_burst_mode, int, 0);
68*4882a593Smuzhiyun MODULE_PARM_DESC(nsp_burst_mode, "Burst transfer mode (0=io8, 1=io32, 2=mem32(default))");
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun /* Release IO ports after configuration? */
71*4882a593Smuzhiyun static bool       free_ports = 0;
72*4882a593Smuzhiyun module_param(free_ports, bool, 0);
73*4882a593Smuzhiyun MODULE_PARM_DESC(free_ports, "Release IO ports after configuration? (default: 0 (=no))");
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun static struct scsi_host_template nsp_driver_template = {
76*4882a593Smuzhiyun 	.proc_name	         = "nsp_cs",
77*4882a593Smuzhiyun 	.show_info		 = nsp_show_info,
78*4882a593Smuzhiyun 	.name			 = "WorkBit NinjaSCSI-3/32Bi(16bit)",
79*4882a593Smuzhiyun 	.info			 = nsp_info,
80*4882a593Smuzhiyun 	.queuecommand		 = nsp_queuecommand,
81*4882a593Smuzhiyun /*	.eh_abort_handler	 = nsp_eh_abort,*/
82*4882a593Smuzhiyun 	.eh_bus_reset_handler	 = nsp_eh_bus_reset,
83*4882a593Smuzhiyun 	.eh_host_reset_handler	 = nsp_eh_host_reset,
84*4882a593Smuzhiyun 	.can_queue		 = 1,
85*4882a593Smuzhiyun 	.this_id		 = NSP_INITIATOR_ID,
86*4882a593Smuzhiyun 	.sg_tablesize		 = SG_ALL,
87*4882a593Smuzhiyun 	.dma_boundary		 = PAGE_SIZE - 1,
88*4882a593Smuzhiyun };
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun static nsp_hw_data nsp_data_base; /* attach <-> detect glue */
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun /*
95*4882a593Smuzhiyun  * debug, error print
96*4882a593Smuzhiyun  */
97*4882a593Smuzhiyun #ifndef NSP_DEBUG
98*4882a593Smuzhiyun # define NSP_DEBUG_MASK		0x000000
99*4882a593Smuzhiyun # define nsp_msg(type, args...) nsp_cs_message("", 0, (type), args)
100*4882a593Smuzhiyun # define nsp_dbg(mask, args...) /* */
101*4882a593Smuzhiyun #else
102*4882a593Smuzhiyun # define NSP_DEBUG_MASK		0xffffff
103*4882a593Smuzhiyun # define nsp_msg(type, args...) \
104*4882a593Smuzhiyun 	nsp_cs_message (__func__, __LINE__, (type), args)
105*4882a593Smuzhiyun # define nsp_dbg(mask, args...) \
106*4882a593Smuzhiyun 	nsp_cs_dmessage(__func__, __LINE__, (mask), args)
107*4882a593Smuzhiyun #endif
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun #define NSP_DEBUG_QUEUECOMMAND		BIT(0)
110*4882a593Smuzhiyun #define NSP_DEBUG_REGISTER		BIT(1)
111*4882a593Smuzhiyun #define NSP_DEBUG_AUTOSCSI		BIT(2)
112*4882a593Smuzhiyun #define NSP_DEBUG_INTR			BIT(3)
113*4882a593Smuzhiyun #define NSP_DEBUG_SGLIST		BIT(4)
114*4882a593Smuzhiyun #define NSP_DEBUG_BUSFREE		BIT(5)
115*4882a593Smuzhiyun #define NSP_DEBUG_CDB_CONTENTS		BIT(6)
116*4882a593Smuzhiyun #define NSP_DEBUG_RESELECTION		BIT(7)
117*4882a593Smuzhiyun #define NSP_DEBUG_MSGINOCCUR		BIT(8)
118*4882a593Smuzhiyun #define NSP_DEBUG_EEPROM		BIT(9)
119*4882a593Smuzhiyun #define NSP_DEBUG_MSGOUTOCCUR		BIT(10)
120*4882a593Smuzhiyun #define NSP_DEBUG_BUSRESET		BIT(11)
121*4882a593Smuzhiyun #define NSP_DEBUG_RESTART		BIT(12)
122*4882a593Smuzhiyun #define NSP_DEBUG_SYNC			BIT(13)
123*4882a593Smuzhiyun #define NSP_DEBUG_WAIT			BIT(14)
124*4882a593Smuzhiyun #define NSP_DEBUG_TARGETFLAG		BIT(15)
125*4882a593Smuzhiyun #define NSP_DEBUG_PROC			BIT(16)
126*4882a593Smuzhiyun #define NSP_DEBUG_INIT			BIT(17)
127*4882a593Smuzhiyun #define NSP_DEBUG_DATA_IO      		BIT(18)
128*4882a593Smuzhiyun #define NSP_SPECIAL_PRINT_REGISTER	BIT(20)
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun #define NSP_DEBUG_BUF_LEN		150
131*4882a593Smuzhiyun 
nsp_inc_resid(struct scsi_cmnd * SCpnt,int residInc)132*4882a593Smuzhiyun static inline void nsp_inc_resid(struct scsi_cmnd *SCpnt, int residInc)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun 	scsi_set_resid(SCpnt, scsi_get_resid(SCpnt) + residInc);
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun __printf(4, 5)
nsp_cs_message(const char * func,int line,char * type,char * fmt,...)138*4882a593Smuzhiyun static void nsp_cs_message(const char *func, int line, char *type, char *fmt, ...)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun 	va_list args;
141*4882a593Smuzhiyun 	char buf[NSP_DEBUG_BUF_LEN];
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	va_start(args, fmt);
144*4882a593Smuzhiyun 	vsnprintf(buf, sizeof(buf), fmt, args);
145*4882a593Smuzhiyun 	va_end(args);
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun #ifndef NSP_DEBUG
148*4882a593Smuzhiyun 	printk("%snsp_cs: %s\n", type, buf);
149*4882a593Smuzhiyun #else
150*4882a593Smuzhiyun 	printk("%snsp_cs: %s (%d): %s\n", type, func, line, buf);
151*4882a593Smuzhiyun #endif
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun #ifdef NSP_DEBUG
nsp_cs_dmessage(const char * func,int line,int mask,char * fmt,...)155*4882a593Smuzhiyun static void nsp_cs_dmessage(const char *func, int line, int mask, char *fmt, ...)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun 	va_list args;
158*4882a593Smuzhiyun 	char buf[NSP_DEBUG_BUF_LEN];
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	va_start(args, fmt);
161*4882a593Smuzhiyun 	vsnprintf(buf, sizeof(buf), fmt, args);
162*4882a593Smuzhiyun 	va_end(args);
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	if (mask & NSP_DEBUG_MASK) {
165*4882a593Smuzhiyun 		printk("nsp_cs-debug: 0x%x %s (%d): %s\n", mask, func, line, buf);
166*4882a593Smuzhiyun 	}
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun #endif
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun /***********************************************************/
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun /*====================================================
173*4882a593Smuzhiyun  * Clenaup parameters and call done() functions.
174*4882a593Smuzhiyun  * You must be set SCpnt->result before call this function.
175*4882a593Smuzhiyun  */
nsp_scsi_done(struct scsi_cmnd * SCpnt)176*4882a593Smuzhiyun static void nsp_scsi_done(struct scsi_cmnd *SCpnt)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun 	nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	data->CurrentSC = NULL;
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	SCpnt->scsi_done(SCpnt);
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun 
nsp_queuecommand_lck(struct scsi_cmnd * SCpnt,void (* done)(struct scsi_cmnd *))185*4882a593Smuzhiyun static int nsp_queuecommand_lck(struct scsi_cmnd *SCpnt,
186*4882a593Smuzhiyun 			    void (*done)(struct scsi_cmnd *))
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun #ifdef NSP_DEBUG
189*4882a593Smuzhiyun 	/*unsigned int host_id = SCpnt->device->host->this_id;*/
190*4882a593Smuzhiyun 	/*unsigned int base    = SCpnt->device->host->io_port;*/
191*4882a593Smuzhiyun 	unsigned char target = scmd_id(SCpnt);
192*4882a593Smuzhiyun #endif
193*4882a593Smuzhiyun 	nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	nsp_dbg(NSP_DEBUG_QUEUECOMMAND,
196*4882a593Smuzhiyun 		"SCpnt=0x%p target=%d lun=%llu sglist=0x%p bufflen=%d sg_count=%d",
197*4882a593Smuzhiyun 		SCpnt, target, SCpnt->device->lun, scsi_sglist(SCpnt),
198*4882a593Smuzhiyun 		scsi_bufflen(SCpnt), scsi_sg_count(SCpnt));
199*4882a593Smuzhiyun 	//nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "before CurrentSC=0x%p", data->CurrentSC);
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	SCpnt->scsi_done	= done;
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	if (data->CurrentSC != NULL) {
204*4882a593Smuzhiyun 		nsp_msg(KERN_DEBUG, "CurrentSC!=NULL this can't be happen");
205*4882a593Smuzhiyun 		SCpnt->result   = DID_BAD_TARGET << 16;
206*4882a593Smuzhiyun 		nsp_scsi_done(SCpnt);
207*4882a593Smuzhiyun 		return 0;
208*4882a593Smuzhiyun 	}
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun #if 0
211*4882a593Smuzhiyun 	/* XXX: pcmcia-cs generates SCSI command with "scsi_info" utility.
212*4882a593Smuzhiyun 	        This makes kernel crash when suspending... */
213*4882a593Smuzhiyun 	if (data->ScsiInfo->stop != 0) {
214*4882a593Smuzhiyun 		nsp_msg(KERN_INFO, "suspending device. reject command.");
215*4882a593Smuzhiyun 		SCpnt->result  = DID_BAD_TARGET << 16;
216*4882a593Smuzhiyun 		nsp_scsi_done(SCpnt);
217*4882a593Smuzhiyun 		return SCSI_MLQUEUE_HOST_BUSY;
218*4882a593Smuzhiyun 	}
219*4882a593Smuzhiyun #endif
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	show_command(SCpnt);
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	data->CurrentSC		= SCpnt;
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	SCpnt->SCp.Status	= CHECK_CONDITION;
226*4882a593Smuzhiyun 	SCpnt->SCp.Message	= 0;
227*4882a593Smuzhiyun 	SCpnt->SCp.have_data_in = IO_UNKNOWN;
228*4882a593Smuzhiyun 	SCpnt->SCp.sent_command = 0;
229*4882a593Smuzhiyun 	SCpnt->SCp.phase	= PH_UNDETERMINED;
230*4882a593Smuzhiyun 	scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	/* setup scratch area
233*4882a593Smuzhiyun 	   SCp.ptr		: buffer pointer
234*4882a593Smuzhiyun 	   SCp.this_residual	: buffer length
235*4882a593Smuzhiyun 	   SCp.buffer		: next buffer
236*4882a593Smuzhiyun 	   SCp.buffers_residual : left buffers in list
237*4882a593Smuzhiyun 	   SCp.phase		: current state of the command */
238*4882a593Smuzhiyun 	if (scsi_bufflen(SCpnt)) {
239*4882a593Smuzhiyun 		SCpnt->SCp.buffer	    = scsi_sglist(SCpnt);
240*4882a593Smuzhiyun 		SCpnt->SCp.ptr		    = BUFFER_ADDR;
241*4882a593Smuzhiyun 		SCpnt->SCp.this_residual    = SCpnt->SCp.buffer->length;
242*4882a593Smuzhiyun 		SCpnt->SCp.buffers_residual = scsi_sg_count(SCpnt) - 1;
243*4882a593Smuzhiyun 	} else {
244*4882a593Smuzhiyun 		SCpnt->SCp.ptr		    = NULL;
245*4882a593Smuzhiyun 		SCpnt->SCp.this_residual    = 0;
246*4882a593Smuzhiyun 		SCpnt->SCp.buffer	    = NULL;
247*4882a593Smuzhiyun 		SCpnt->SCp.buffers_residual = 0;
248*4882a593Smuzhiyun 	}
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 	if (nsphw_start_selection(SCpnt) == FALSE) {
251*4882a593Smuzhiyun 		nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "selection fail");
252*4882a593Smuzhiyun 		SCpnt->result   = DID_BUS_BUSY << 16;
253*4882a593Smuzhiyun 		nsp_scsi_done(SCpnt);
254*4882a593Smuzhiyun 		return 0;
255*4882a593Smuzhiyun 	}
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	//nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "out");
259*4882a593Smuzhiyun #ifdef NSP_DEBUG
260*4882a593Smuzhiyun 	data->CmdId++;
261*4882a593Smuzhiyun #endif
262*4882a593Smuzhiyun 	return 0;
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun 
DEF_SCSI_QCMD(nsp_queuecommand)265*4882a593Smuzhiyun static DEF_SCSI_QCMD(nsp_queuecommand)
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun /*
268*4882a593Smuzhiyun  * setup PIO FIFO transfer mode and enable/disable to data out
269*4882a593Smuzhiyun  */
270*4882a593Smuzhiyun static void nsp_setup_fifo(nsp_hw_data *data, int enabled)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun 	unsigned int  base = data->BaseAddress;
273*4882a593Smuzhiyun 	unsigned char transfer_mode_reg;
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	//nsp_dbg(NSP_DEBUG_DATA_IO, "enabled=%d", enabled);
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	if (enabled != FALSE) {
278*4882a593Smuzhiyun 		transfer_mode_reg = TRANSFER_GO | BRAIND;
279*4882a593Smuzhiyun 	} else {
280*4882a593Smuzhiyun 		transfer_mode_reg = 0;
281*4882a593Smuzhiyun 	}
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	transfer_mode_reg |= data->TransferMode;
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	nsp_index_write(base, TRANSFERMODE, transfer_mode_reg);
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun 
nsphw_init_sync(nsp_hw_data * data)288*4882a593Smuzhiyun static void nsphw_init_sync(nsp_hw_data *data)
289*4882a593Smuzhiyun {
290*4882a593Smuzhiyun 	sync_data tmp_sync = { .SyncNegotiation = SYNC_NOT_YET,
291*4882a593Smuzhiyun 			       .SyncPeriod      = 0,
292*4882a593Smuzhiyun 			       .SyncOffset      = 0
293*4882a593Smuzhiyun 	};
294*4882a593Smuzhiyun 	int i;
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	/* setup sync data */
297*4882a593Smuzhiyun 	for ( i = 0; i < ARRAY_SIZE(data->Sync); i++ ) {
298*4882a593Smuzhiyun 		data->Sync[i] = tmp_sync;
299*4882a593Smuzhiyun 	}
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun /*
303*4882a593Smuzhiyun  * Initialize Ninja hardware
304*4882a593Smuzhiyun  */
nsphw_init(nsp_hw_data * data)305*4882a593Smuzhiyun static int nsphw_init(nsp_hw_data *data)
306*4882a593Smuzhiyun {
307*4882a593Smuzhiyun 	unsigned int base     = data->BaseAddress;
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	nsp_dbg(NSP_DEBUG_INIT, "in base=0x%x", base);
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	data->ScsiClockDiv = CLOCK_40M | FAST_20;
312*4882a593Smuzhiyun 	data->CurrentSC    = NULL;
313*4882a593Smuzhiyun 	data->FifoCount    = 0;
314*4882a593Smuzhiyun 	data->TransferMode = MODE_IO8;
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 	nsphw_init_sync(data);
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 	/* block all interrupts */
319*4882a593Smuzhiyun 	nsp_write(base,	      IRQCONTROL,   IRQCONTROL_ALLMASK);
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	/* setup SCSI interface */
322*4882a593Smuzhiyun 	nsp_write(base,	      IFSELECT,	    IF_IFSEL);
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	nsp_index_write(base, SCSIIRQMODE,  0);
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	nsp_index_write(base, TRANSFERMODE, MODE_IO8);
327*4882a593Smuzhiyun 	nsp_index_write(base, CLOCKDIV,	    data->ScsiClockDiv);
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	nsp_index_write(base, PARITYCTRL,   0);
330*4882a593Smuzhiyun 	nsp_index_write(base, POINTERCLR,   POINTER_CLEAR     |
331*4882a593Smuzhiyun 					    ACK_COUNTER_CLEAR |
332*4882a593Smuzhiyun 					    REQ_COUNTER_CLEAR |
333*4882a593Smuzhiyun 					    HOST_COUNTER_CLEAR);
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	/* setup fifo asic */
336*4882a593Smuzhiyun 	nsp_write(base,	      IFSELECT,	    IF_REGSEL);
337*4882a593Smuzhiyun 	nsp_index_write(base, TERMPWRCTRL,  0);
338*4882a593Smuzhiyun 	if ((nsp_index_read(base, OTHERCONTROL) & TPWR_SENSE) == 0) {
339*4882a593Smuzhiyun 		nsp_msg(KERN_INFO, "terminator power on");
340*4882a593Smuzhiyun 		nsp_index_write(base, TERMPWRCTRL, POWER_ON);
341*4882a593Smuzhiyun 	}
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 	nsp_index_write(base, TIMERCOUNT,   0);
344*4882a593Smuzhiyun 	nsp_index_write(base, TIMERCOUNT,   0); /* requires 2 times!! */
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	nsp_index_write(base, SYNCREG,	    0);
347*4882a593Smuzhiyun 	nsp_index_write(base, ACKWIDTH,	    0);
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun 	/* enable interrupts and ack them */
350*4882a593Smuzhiyun 	nsp_index_write(base, SCSIIRQMODE,  SCSI_PHASE_CHANGE_EI |
351*4882a593Smuzhiyun 					    RESELECT_EI		 |
352*4882a593Smuzhiyun 					    SCSI_RESET_IRQ_EI	 );
353*4882a593Smuzhiyun 	nsp_write(base,	      IRQCONTROL,   IRQCONTROL_ALLCLEAR);
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	nsp_setup_fifo(data, FALSE);
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 	return TRUE;
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun /*
361*4882a593Smuzhiyun  * Start selection phase
362*4882a593Smuzhiyun  */
nsphw_start_selection(struct scsi_cmnd * SCpnt)363*4882a593Smuzhiyun static int nsphw_start_selection(struct scsi_cmnd *SCpnt)
364*4882a593Smuzhiyun {
365*4882a593Smuzhiyun 	unsigned int  host_id	 = SCpnt->device->host->this_id;
366*4882a593Smuzhiyun 	unsigned int  base	 = SCpnt->device->host->io_port;
367*4882a593Smuzhiyun 	unsigned char target	 = scmd_id(SCpnt);
368*4882a593Smuzhiyun 	nsp_hw_data  *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
369*4882a593Smuzhiyun 	int	      time_out;
370*4882a593Smuzhiyun 	unsigned char phase, arbit;
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	//nsp_dbg(NSP_DEBUG_RESELECTION, "in");
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	phase = nsp_index_read(base, SCSIBUSMON);
375*4882a593Smuzhiyun 	if(phase != BUSMON_BUS_FREE) {
376*4882a593Smuzhiyun 		//nsp_dbg(NSP_DEBUG_RESELECTION, "bus busy");
377*4882a593Smuzhiyun 		return FALSE;
378*4882a593Smuzhiyun 	}
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 	/* start arbitration */
381*4882a593Smuzhiyun 	//nsp_dbg(NSP_DEBUG_RESELECTION, "start arbit");
382*4882a593Smuzhiyun 	SCpnt->SCp.phase = PH_ARBSTART;
383*4882a593Smuzhiyun 	nsp_index_write(base, SETARBIT, ARBIT_GO);
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	time_out = 1000;
386*4882a593Smuzhiyun 	do {
387*4882a593Smuzhiyun 		/* XXX: what a stupid chip! */
388*4882a593Smuzhiyun 		arbit = nsp_index_read(base, ARBITSTATUS);
389*4882a593Smuzhiyun 		//nsp_dbg(NSP_DEBUG_RESELECTION, "arbit=%d, wait_count=%d", arbit, wait_count);
390*4882a593Smuzhiyun 		udelay(1); /* hold 1.2us */
391*4882a593Smuzhiyun 	} while((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 &&
392*4882a593Smuzhiyun 		(time_out-- != 0));
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	if (!(arbit & ARBIT_WIN)) {
395*4882a593Smuzhiyun 		//nsp_dbg(NSP_DEBUG_RESELECTION, "arbit fail");
396*4882a593Smuzhiyun 		nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR);
397*4882a593Smuzhiyun 		return FALSE;
398*4882a593Smuzhiyun 	}
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 	/* assert select line */
401*4882a593Smuzhiyun 	//nsp_dbg(NSP_DEBUG_RESELECTION, "assert SEL line");
402*4882a593Smuzhiyun 	SCpnt->SCp.phase = PH_SELSTART;
403*4882a593Smuzhiyun 	udelay(3); /* wait 2.4us */
404*4882a593Smuzhiyun 	nsp_index_write(base, SCSIDATALATCH, BIT(host_id) | BIT(target));
405*4882a593Smuzhiyun 	nsp_index_write(base, SCSIBUSCTRL,   SCSI_SEL | SCSI_BSY                    | SCSI_ATN);
406*4882a593Smuzhiyun 	udelay(2); /* wait >1.2us */
407*4882a593Smuzhiyun 	nsp_index_write(base, SCSIBUSCTRL,   SCSI_SEL | SCSI_BSY | SCSI_DATAOUT_ENB | SCSI_ATN);
408*4882a593Smuzhiyun 	nsp_index_write(base, SETARBIT,	     ARBIT_FLAG_CLEAR);
409*4882a593Smuzhiyun 	/*udelay(1);*/ /* wait >90ns */
410*4882a593Smuzhiyun 	nsp_index_write(base, SCSIBUSCTRL,   SCSI_SEL            | SCSI_DATAOUT_ENB | SCSI_ATN);
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 	/* check selection timeout */
413*4882a593Smuzhiyun 	nsp_start_timer(SCpnt, 1000/51);
414*4882a593Smuzhiyun 	data->SelectionTimeOut = 1;
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	return TRUE;
417*4882a593Smuzhiyun }
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun struct nsp_sync_table {
420*4882a593Smuzhiyun 	unsigned int min_period;
421*4882a593Smuzhiyun 	unsigned int max_period;
422*4882a593Smuzhiyun 	unsigned int chip_period;
423*4882a593Smuzhiyun 	unsigned int ack_width;
424*4882a593Smuzhiyun };
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun static struct nsp_sync_table nsp_sync_table_40M[] = {
427*4882a593Smuzhiyun 	{0x0c, 0x0c, 0x1, 0},	/* 20MB	  50ns*/
428*4882a593Smuzhiyun 	{0x19, 0x19, 0x3, 1},	/* 10MB	 100ns*/
429*4882a593Smuzhiyun 	{0x1a, 0x25, 0x5, 2},	/* 7.5MB 150ns*/
430*4882a593Smuzhiyun 	{0x26, 0x32, 0x7, 3},	/* 5MB	 200ns*/
431*4882a593Smuzhiyun 	{   0,    0,   0, 0},
432*4882a593Smuzhiyun };
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun static struct nsp_sync_table nsp_sync_table_20M[] = {
435*4882a593Smuzhiyun 	{0x19, 0x19, 0x1, 0},	/* 10MB	 100ns*/
436*4882a593Smuzhiyun 	{0x1a, 0x25, 0x2, 0},	/* 7.5MB 150ns*/
437*4882a593Smuzhiyun 	{0x26, 0x32, 0x3, 1},	/* 5MB	 200ns*/
438*4882a593Smuzhiyun 	{   0,    0,   0, 0},
439*4882a593Smuzhiyun };
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun /*
442*4882a593Smuzhiyun  * setup synchronous data transfer mode
443*4882a593Smuzhiyun  */
nsp_analyze_sdtr(struct scsi_cmnd * SCpnt)444*4882a593Smuzhiyun static int nsp_analyze_sdtr(struct scsi_cmnd *SCpnt)
445*4882a593Smuzhiyun {
446*4882a593Smuzhiyun 	unsigned char	       target = scmd_id(SCpnt);
447*4882a593Smuzhiyun //	unsigned char	       lun    = SCpnt->device->lun;
448*4882a593Smuzhiyun 	nsp_hw_data           *data   = (nsp_hw_data *)SCpnt->device->host->hostdata;
449*4882a593Smuzhiyun 	sync_data	      *sync   = &(data->Sync[target]);
450*4882a593Smuzhiyun 	struct nsp_sync_table *sync_table;
451*4882a593Smuzhiyun 	unsigned int	       period, offset;
452*4882a593Smuzhiyun 	int		       i;
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun 	nsp_dbg(NSP_DEBUG_SYNC, "in");
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 	period = sync->SyncPeriod;
458*4882a593Smuzhiyun 	offset = sync->SyncOffset;
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	nsp_dbg(NSP_DEBUG_SYNC, "period=0x%x, offset=0x%x", period, offset);
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 	if ((data->ScsiClockDiv & (BIT(0)|BIT(1))) == CLOCK_20M) {
463*4882a593Smuzhiyun 		sync_table = nsp_sync_table_20M;
464*4882a593Smuzhiyun 	} else {
465*4882a593Smuzhiyun 		sync_table = nsp_sync_table_40M;
466*4882a593Smuzhiyun 	}
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 	for ( i = 0; sync_table->max_period != 0; i++, sync_table++) {
469*4882a593Smuzhiyun 		if ( period >= sync_table->min_period &&
470*4882a593Smuzhiyun 		     period <= sync_table->max_period	 ) {
471*4882a593Smuzhiyun 			break;
472*4882a593Smuzhiyun 		}
473*4882a593Smuzhiyun 	}
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun 	if (period != 0 && sync_table->max_period == 0) {
476*4882a593Smuzhiyun 		/*
477*4882a593Smuzhiyun 		 * No proper period/offset found
478*4882a593Smuzhiyun 		 */
479*4882a593Smuzhiyun 		nsp_dbg(NSP_DEBUG_SYNC, "no proper period/offset");
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun 		sync->SyncPeriod      = 0;
482*4882a593Smuzhiyun 		sync->SyncOffset      = 0;
483*4882a593Smuzhiyun 		sync->SyncRegister    = 0;
484*4882a593Smuzhiyun 		sync->AckWidth	      = 0;
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 		return FALSE;
487*4882a593Smuzhiyun 	}
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	sync->SyncRegister    = (sync_table->chip_period << SYNCREG_PERIOD_SHIFT) |
490*4882a593Smuzhiyun 		                (offset & SYNCREG_OFFSET_MASK);
491*4882a593Smuzhiyun 	sync->AckWidth	      = sync_table->ack_width;
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 	nsp_dbg(NSP_DEBUG_SYNC, "sync_reg=0x%x, ack_width=0x%x", sync->SyncRegister, sync->AckWidth);
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 	return TRUE;
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun /*
500*4882a593Smuzhiyun  * start ninja hardware timer
501*4882a593Smuzhiyun  */
nsp_start_timer(struct scsi_cmnd * SCpnt,int time)502*4882a593Smuzhiyun static void nsp_start_timer(struct scsi_cmnd *SCpnt, int time)
503*4882a593Smuzhiyun {
504*4882a593Smuzhiyun 	unsigned int base = SCpnt->device->host->io_port;
505*4882a593Smuzhiyun 	nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 	//nsp_dbg(NSP_DEBUG_INTR, "in SCpnt=0x%p, time=%d", SCpnt, time);
508*4882a593Smuzhiyun 	data->TimerCount = time;
509*4882a593Smuzhiyun 	nsp_index_write(base, TIMERCOUNT, time);
510*4882a593Smuzhiyun }
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun /*
513*4882a593Smuzhiyun  * wait for bus phase change
514*4882a593Smuzhiyun  */
nsp_negate_signal(struct scsi_cmnd * SCpnt,unsigned char mask,char * str)515*4882a593Smuzhiyun static int nsp_negate_signal(struct scsi_cmnd *SCpnt, unsigned char mask,
516*4882a593Smuzhiyun 			     char *str)
517*4882a593Smuzhiyun {
518*4882a593Smuzhiyun 	unsigned int  base = SCpnt->device->host->io_port;
519*4882a593Smuzhiyun 	unsigned char reg;
520*4882a593Smuzhiyun 	int	      time_out;
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun 	//nsp_dbg(NSP_DEBUG_INTR, "in");
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	time_out = 100;
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	do {
527*4882a593Smuzhiyun 		reg = nsp_index_read(base, SCSIBUSMON);
528*4882a593Smuzhiyun 		if (reg == 0xff) {
529*4882a593Smuzhiyun 			break;
530*4882a593Smuzhiyun 		}
531*4882a593Smuzhiyun 	} while ((--time_out != 0) && (reg & mask) != 0);
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun 	if (time_out == 0) {
534*4882a593Smuzhiyun 		nsp_msg(KERN_DEBUG, " %s signal off timeout", str);
535*4882a593Smuzhiyun 	}
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun 	return 0;
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun /*
541*4882a593Smuzhiyun  * expect Ninja Irq
542*4882a593Smuzhiyun  */
nsp_expect_signal(struct scsi_cmnd * SCpnt,unsigned char current_phase,unsigned char mask)543*4882a593Smuzhiyun static int nsp_expect_signal(struct scsi_cmnd *SCpnt,
544*4882a593Smuzhiyun 			     unsigned char current_phase,
545*4882a593Smuzhiyun 			     unsigned char mask)
546*4882a593Smuzhiyun {
547*4882a593Smuzhiyun 	unsigned int  base	 = SCpnt->device->host->io_port;
548*4882a593Smuzhiyun 	int	      time_out;
549*4882a593Smuzhiyun 	unsigned char phase, i_src;
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun 	//nsp_dbg(NSP_DEBUG_INTR, "current_phase=0x%x, mask=0x%x", current_phase, mask);
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun 	time_out = 100;
554*4882a593Smuzhiyun 	do {
555*4882a593Smuzhiyun 		phase = nsp_index_read(base, SCSIBUSMON);
556*4882a593Smuzhiyun 		if (phase == 0xff) {
557*4882a593Smuzhiyun 			//nsp_dbg(NSP_DEBUG_INTR, "ret -1");
558*4882a593Smuzhiyun 			return -1;
559*4882a593Smuzhiyun 		}
560*4882a593Smuzhiyun 		i_src = nsp_read(base, IRQSTATUS);
561*4882a593Smuzhiyun 		if (i_src & IRQSTATUS_SCSI) {
562*4882a593Smuzhiyun 			//nsp_dbg(NSP_DEBUG_INTR, "ret 0 found scsi signal");
563*4882a593Smuzhiyun 			return 0;
564*4882a593Smuzhiyun 		}
565*4882a593Smuzhiyun 		if ((phase & mask) != 0 && (phase & BUSMON_PHASE_MASK) == current_phase) {
566*4882a593Smuzhiyun 			//nsp_dbg(NSP_DEBUG_INTR, "ret 1 phase=0x%x", phase);
567*4882a593Smuzhiyun 			return 1;
568*4882a593Smuzhiyun 		}
569*4882a593Smuzhiyun 	} while(time_out-- != 0);
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun 	//nsp_dbg(NSP_DEBUG_INTR, "timeout");
572*4882a593Smuzhiyun 	return -1;
573*4882a593Smuzhiyun }
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun /*
576*4882a593Smuzhiyun  * transfer SCSI message
577*4882a593Smuzhiyun  */
nsp_xfer(struct scsi_cmnd * SCpnt,int phase)578*4882a593Smuzhiyun static int nsp_xfer(struct scsi_cmnd *SCpnt, int phase)
579*4882a593Smuzhiyun {
580*4882a593Smuzhiyun 	unsigned int  base = SCpnt->device->host->io_port;
581*4882a593Smuzhiyun 	nsp_hw_data  *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
582*4882a593Smuzhiyun 	char	     *buf  = data->MsgBuffer;
583*4882a593Smuzhiyun 	int	      len  = min(MSGBUF_SIZE, data->MsgLen);
584*4882a593Smuzhiyun 	int	      ptr;
585*4882a593Smuzhiyun 	int	      ret;
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun 	//nsp_dbg(NSP_DEBUG_DATA_IO, "in");
588*4882a593Smuzhiyun 	for (ptr = 0; len > 0; len--, ptr++) {
589*4882a593Smuzhiyun 
590*4882a593Smuzhiyun 		ret = nsp_expect_signal(SCpnt, phase, BUSMON_REQ);
591*4882a593Smuzhiyun 		if (ret <= 0) {
592*4882a593Smuzhiyun 			nsp_dbg(NSP_DEBUG_DATA_IO, "xfer quit");
593*4882a593Smuzhiyun 			return 0;
594*4882a593Smuzhiyun 		}
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 		/* if last byte, negate ATN */
597*4882a593Smuzhiyun 		if (len == 1 && SCpnt->SCp.phase == PH_MSG_OUT) {
598*4882a593Smuzhiyun 			nsp_index_write(base, SCSIBUSCTRL, AUTODIRECTION | ACKENB);
599*4882a593Smuzhiyun 		}
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun 		/* read & write message */
602*4882a593Smuzhiyun 		if (phase & BUSMON_IO) {
603*4882a593Smuzhiyun 			nsp_dbg(NSP_DEBUG_DATA_IO, "read msg");
604*4882a593Smuzhiyun 			buf[ptr] = nsp_index_read(base, SCSIDATAWITHACK);
605*4882a593Smuzhiyun 		} else {
606*4882a593Smuzhiyun 			nsp_dbg(NSP_DEBUG_DATA_IO, "write msg");
607*4882a593Smuzhiyun 			nsp_index_write(base, SCSIDATAWITHACK, buf[ptr]);
608*4882a593Smuzhiyun 		}
609*4882a593Smuzhiyun 		nsp_negate_signal(SCpnt, BUSMON_ACK, "xfer<ack>");
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun 	}
612*4882a593Smuzhiyun 	return len;
613*4882a593Smuzhiyun }
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun /*
616*4882a593Smuzhiyun  * get extra SCSI data from fifo
617*4882a593Smuzhiyun  */
nsp_dataphase_bypass(struct scsi_cmnd * SCpnt)618*4882a593Smuzhiyun static int nsp_dataphase_bypass(struct scsi_cmnd *SCpnt)
619*4882a593Smuzhiyun {
620*4882a593Smuzhiyun 	nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
621*4882a593Smuzhiyun 	unsigned int count;
622*4882a593Smuzhiyun 
623*4882a593Smuzhiyun 	//nsp_dbg(NSP_DEBUG_DATA_IO, "in");
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 	if (SCpnt->SCp.have_data_in != IO_IN) {
626*4882a593Smuzhiyun 		return 0;
627*4882a593Smuzhiyun 	}
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun 	count = nsp_fifo_count(SCpnt);
630*4882a593Smuzhiyun 	if (data->FifoCount == count) {
631*4882a593Smuzhiyun 		//nsp_dbg(NSP_DEBUG_DATA_IO, "not use bypass quirk");
632*4882a593Smuzhiyun 		return 0;
633*4882a593Smuzhiyun 	}
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun 	/*
636*4882a593Smuzhiyun 	 * XXX: NSP_QUIRK
637*4882a593Smuzhiyun 	 * data phase skip only occures in case of SCSI_LOW_READ
638*4882a593Smuzhiyun 	 */
639*4882a593Smuzhiyun 	nsp_dbg(NSP_DEBUG_DATA_IO, "use bypass quirk");
640*4882a593Smuzhiyun 	SCpnt->SCp.phase = PH_DATA;
641*4882a593Smuzhiyun 	nsp_pio_read(SCpnt);
642*4882a593Smuzhiyun 	nsp_setup_fifo(data, FALSE);
643*4882a593Smuzhiyun 
644*4882a593Smuzhiyun 	return 0;
645*4882a593Smuzhiyun }
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun /*
648*4882a593Smuzhiyun  * accept reselection
649*4882a593Smuzhiyun  */
nsp_reselected(struct scsi_cmnd * SCpnt)650*4882a593Smuzhiyun static int nsp_reselected(struct scsi_cmnd *SCpnt)
651*4882a593Smuzhiyun {
652*4882a593Smuzhiyun 	unsigned int  base    = SCpnt->device->host->io_port;
653*4882a593Smuzhiyun 	unsigned int  host_id = SCpnt->device->host->this_id;
654*4882a593Smuzhiyun 	//nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
655*4882a593Smuzhiyun 	unsigned char bus_reg;
656*4882a593Smuzhiyun 	unsigned char id_reg, tmp;
657*4882a593Smuzhiyun 	int target;
658*4882a593Smuzhiyun 
659*4882a593Smuzhiyun 	nsp_dbg(NSP_DEBUG_RESELECTION, "in");
660*4882a593Smuzhiyun 
661*4882a593Smuzhiyun 	id_reg = nsp_index_read(base, RESELECTID);
662*4882a593Smuzhiyun 	tmp    = id_reg & (~BIT(host_id));
663*4882a593Smuzhiyun 	target = 0;
664*4882a593Smuzhiyun 	while(tmp != 0) {
665*4882a593Smuzhiyun 		if (tmp & BIT(0)) {
666*4882a593Smuzhiyun 			break;
667*4882a593Smuzhiyun 		}
668*4882a593Smuzhiyun 		tmp >>= 1;
669*4882a593Smuzhiyun 		target++;
670*4882a593Smuzhiyun 	}
671*4882a593Smuzhiyun 
672*4882a593Smuzhiyun 	if (scmd_id(SCpnt) != target) {
673*4882a593Smuzhiyun 		nsp_msg(KERN_ERR, "XXX: reselect ID must be %d in this implementation.", target);
674*4882a593Smuzhiyun 	}
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 	nsp_negate_signal(SCpnt, BUSMON_SEL, "reselect<SEL>");
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun 	nsp_nexus(SCpnt);
679*4882a593Smuzhiyun 	bus_reg = nsp_index_read(base, SCSIBUSCTRL) & ~(SCSI_BSY | SCSI_ATN);
680*4882a593Smuzhiyun 	nsp_index_write(base, SCSIBUSCTRL, bus_reg);
681*4882a593Smuzhiyun 	nsp_index_write(base, SCSIBUSCTRL, bus_reg | AUTODIRECTION | ACKENB);
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun 	return TRUE;
684*4882a593Smuzhiyun }
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun /*
687*4882a593Smuzhiyun  * count how many data transferd
688*4882a593Smuzhiyun  */
nsp_fifo_count(struct scsi_cmnd * SCpnt)689*4882a593Smuzhiyun static int nsp_fifo_count(struct scsi_cmnd *SCpnt)
690*4882a593Smuzhiyun {
691*4882a593Smuzhiyun 	unsigned int base = SCpnt->device->host->io_port;
692*4882a593Smuzhiyun 	unsigned int count;
693*4882a593Smuzhiyun 	unsigned int l, m, h;
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 	nsp_index_write(base, POINTERCLR, POINTER_CLEAR | ACK_COUNTER);
696*4882a593Smuzhiyun 
697*4882a593Smuzhiyun 	l     = nsp_index_read(base, TRANSFERCOUNT);
698*4882a593Smuzhiyun 	m     = nsp_index_read(base, TRANSFERCOUNT);
699*4882a593Smuzhiyun 	h     = nsp_index_read(base, TRANSFERCOUNT);
700*4882a593Smuzhiyun 	nsp_index_read(base, TRANSFERCOUNT); /* required this! */
701*4882a593Smuzhiyun 
702*4882a593Smuzhiyun 	count = (h << 16) | (m << 8) | (l << 0);
703*4882a593Smuzhiyun 
704*4882a593Smuzhiyun 	//nsp_dbg(NSP_DEBUG_DATA_IO, "count=0x%x", count);
705*4882a593Smuzhiyun 
706*4882a593Smuzhiyun 	return count;
707*4882a593Smuzhiyun }
708*4882a593Smuzhiyun 
709*4882a593Smuzhiyun /* fifo size */
710*4882a593Smuzhiyun #define RFIFO_CRIT 64
711*4882a593Smuzhiyun #define WFIFO_CRIT 64
712*4882a593Smuzhiyun 
713*4882a593Smuzhiyun /*
714*4882a593Smuzhiyun  * read data in DATA IN phase
715*4882a593Smuzhiyun  */
nsp_pio_read(struct scsi_cmnd * SCpnt)716*4882a593Smuzhiyun static void nsp_pio_read(struct scsi_cmnd *SCpnt)
717*4882a593Smuzhiyun {
718*4882a593Smuzhiyun 	unsigned int  base      = SCpnt->device->host->io_port;
719*4882a593Smuzhiyun 	unsigned long mmio_base = SCpnt->device->host->base;
720*4882a593Smuzhiyun 	nsp_hw_data  *data      = (nsp_hw_data *)SCpnt->device->host->hostdata;
721*4882a593Smuzhiyun 	long	      time_out;
722*4882a593Smuzhiyun 	int	      ocount, res;
723*4882a593Smuzhiyun 	unsigned char stat, fifo_stat;
724*4882a593Smuzhiyun 
725*4882a593Smuzhiyun 	ocount = data->FifoCount;
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun 	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",
728*4882a593Smuzhiyun 		SCpnt, scsi_get_resid(SCpnt), ocount, SCpnt->SCp.ptr,
729*4882a593Smuzhiyun 		SCpnt->SCp.this_residual, SCpnt->SCp.buffer,
730*4882a593Smuzhiyun 		SCpnt->SCp.buffers_residual);
731*4882a593Smuzhiyun 
732*4882a593Smuzhiyun 	time_out = 1000;
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun 	while ((time_out-- != 0) &&
735*4882a593Smuzhiyun 	       (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0 ) ) {
736*4882a593Smuzhiyun 
737*4882a593Smuzhiyun 		stat = nsp_index_read(base, SCSIBUSMON);
738*4882a593Smuzhiyun 		stat &= BUSMON_PHASE_MASK;
739*4882a593Smuzhiyun 
740*4882a593Smuzhiyun 
741*4882a593Smuzhiyun 		res = nsp_fifo_count(SCpnt) - ocount;
742*4882a593Smuzhiyun 		//nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this=0x%x ocount=0x%x res=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount, res);
743*4882a593Smuzhiyun 		if (res == 0) { /* if some data available ? */
744*4882a593Smuzhiyun 			if (stat == BUSPHASE_DATA_IN) { /* phase changed? */
745*4882a593Smuzhiyun 				//nsp_dbg(NSP_DEBUG_DATA_IO, " wait for data this=%d", SCpnt->SCp.this_residual);
746*4882a593Smuzhiyun 				continue;
747*4882a593Smuzhiyun 			} else {
748*4882a593Smuzhiyun 				nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x", stat);
749*4882a593Smuzhiyun 				break;
750*4882a593Smuzhiyun 			}
751*4882a593Smuzhiyun 		}
752*4882a593Smuzhiyun 
753*4882a593Smuzhiyun 		fifo_stat = nsp_read(base, FIFOSTATUS);
754*4882a593Smuzhiyun 		if ((fifo_stat & FIFOSTATUS_FULL_EMPTY) == 0 &&
755*4882a593Smuzhiyun 		    stat                                == BUSPHASE_DATA_IN) {
756*4882a593Smuzhiyun 			continue;
757*4882a593Smuzhiyun 		}
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun 		res = min(res, SCpnt->SCp.this_residual);
760*4882a593Smuzhiyun 
761*4882a593Smuzhiyun 		switch (data->TransferMode) {
762*4882a593Smuzhiyun 		case MODE_IO32:
763*4882a593Smuzhiyun 			res &= ~(BIT(1)|BIT(0)); /* align 4 */
764*4882a593Smuzhiyun 			nsp_fifo32_read(base, SCpnt->SCp.ptr, res >> 2);
765*4882a593Smuzhiyun 			break;
766*4882a593Smuzhiyun 		case MODE_IO8:
767*4882a593Smuzhiyun 			nsp_fifo8_read (base, SCpnt->SCp.ptr, res     );
768*4882a593Smuzhiyun 			break;
769*4882a593Smuzhiyun 
770*4882a593Smuzhiyun 		case MODE_MEM32:
771*4882a593Smuzhiyun 			res &= ~(BIT(1)|BIT(0)); /* align 4 */
772*4882a593Smuzhiyun 			nsp_mmio_fifo32_read(mmio_base, SCpnt->SCp.ptr, res >> 2);
773*4882a593Smuzhiyun 			break;
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun 		default:
776*4882a593Smuzhiyun 			nsp_dbg(NSP_DEBUG_DATA_IO, "unknown read mode");
777*4882a593Smuzhiyun 			return;
778*4882a593Smuzhiyun 		}
779*4882a593Smuzhiyun 
780*4882a593Smuzhiyun 		nsp_inc_resid(SCpnt, -res);
781*4882a593Smuzhiyun 		SCpnt->SCp.ptr		 += res;
782*4882a593Smuzhiyun 		SCpnt->SCp.this_residual -= res;
783*4882a593Smuzhiyun 		ocount			 += res;
784*4882a593Smuzhiyun 		//nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this_residual=0x%x ocount=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount);
785*4882a593Smuzhiyun 
786*4882a593Smuzhiyun 		/* go to next scatter list if available */
787*4882a593Smuzhiyun 		if (SCpnt->SCp.this_residual	== 0 &&
788*4882a593Smuzhiyun 		    SCpnt->SCp.buffers_residual != 0 ) {
789*4882a593Smuzhiyun 			//nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next timeout=%d", time_out);
790*4882a593Smuzhiyun 			SCpnt->SCp.buffers_residual--;
791*4882a593Smuzhiyun 			SCpnt->SCp.buffer = sg_next(SCpnt->SCp.buffer);
792*4882a593Smuzhiyun 			SCpnt->SCp.ptr		 = BUFFER_ADDR;
793*4882a593Smuzhiyun 			SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
794*4882a593Smuzhiyun 			time_out = 1000;
795*4882a593Smuzhiyun 
796*4882a593Smuzhiyun 			//nsp_dbg(NSP_DEBUG_DATA_IO, "page: 0x%p, off: 0x%x", SCpnt->SCp.buffer->page, SCpnt->SCp.buffer->offset);
797*4882a593Smuzhiyun 		}
798*4882a593Smuzhiyun 	}
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun 	data->FifoCount = ocount;
801*4882a593Smuzhiyun 
802*4882a593Smuzhiyun 	if (time_out < 0) {
803*4882a593Smuzhiyun 		nsp_msg(KERN_DEBUG, "pio read timeout resid=%d this_residual=%d buffers_residual=%d",
804*4882a593Smuzhiyun 			scsi_get_resid(SCpnt), SCpnt->SCp.this_residual,
805*4882a593Smuzhiyun 			SCpnt->SCp.buffers_residual);
806*4882a593Smuzhiyun 	}
807*4882a593Smuzhiyun 	nsp_dbg(NSP_DEBUG_DATA_IO, "read ocount=0x%x", ocount);
808*4882a593Smuzhiyun 	nsp_dbg(NSP_DEBUG_DATA_IO, "r cmd=%d resid=0x%x\n", data->CmdId,
809*4882a593Smuzhiyun 	                                                scsi_get_resid(SCpnt));
810*4882a593Smuzhiyun }
811*4882a593Smuzhiyun 
812*4882a593Smuzhiyun /*
813*4882a593Smuzhiyun  * write data in DATA OUT phase
814*4882a593Smuzhiyun  */
nsp_pio_write(struct scsi_cmnd * SCpnt)815*4882a593Smuzhiyun static void nsp_pio_write(struct scsi_cmnd *SCpnt)
816*4882a593Smuzhiyun {
817*4882a593Smuzhiyun 	unsigned int  base      = SCpnt->device->host->io_port;
818*4882a593Smuzhiyun 	unsigned long mmio_base = SCpnt->device->host->base;
819*4882a593Smuzhiyun 	nsp_hw_data  *data      = (nsp_hw_data *)SCpnt->device->host->hostdata;
820*4882a593Smuzhiyun 	int	      time_out;
821*4882a593Smuzhiyun 	int           ocount, res;
822*4882a593Smuzhiyun 	unsigned char stat;
823*4882a593Smuzhiyun 
824*4882a593Smuzhiyun 	ocount	 = data->FifoCount;
825*4882a593Smuzhiyun 
826*4882a593Smuzhiyun 	nsp_dbg(NSP_DEBUG_DATA_IO, "in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x",
827*4882a593Smuzhiyun 		data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual,
828*4882a593Smuzhiyun 		SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual,
829*4882a593Smuzhiyun 		scsi_get_resid(SCpnt));
830*4882a593Smuzhiyun 
831*4882a593Smuzhiyun 	time_out = 1000;
832*4882a593Smuzhiyun 
833*4882a593Smuzhiyun 	while ((time_out-- != 0) &&
834*4882a593Smuzhiyun 	       (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0)) {
835*4882a593Smuzhiyun 		stat = nsp_index_read(base, SCSIBUSMON);
836*4882a593Smuzhiyun 		stat &= BUSMON_PHASE_MASK;
837*4882a593Smuzhiyun 
838*4882a593Smuzhiyun 		if (stat != BUSPHASE_DATA_OUT) {
839*4882a593Smuzhiyun 			res = ocount - nsp_fifo_count(SCpnt);
840*4882a593Smuzhiyun 
841*4882a593Smuzhiyun 			nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x, res=%d\n", stat, res);
842*4882a593Smuzhiyun 			/* Put back pointer */
843*4882a593Smuzhiyun 			nsp_inc_resid(SCpnt, res);
844*4882a593Smuzhiyun 			SCpnt->SCp.ptr		 -= res;
845*4882a593Smuzhiyun 			SCpnt->SCp.this_residual += res;
846*4882a593Smuzhiyun 			ocount			 -= res;
847*4882a593Smuzhiyun 
848*4882a593Smuzhiyun 			break;
849*4882a593Smuzhiyun 		}
850*4882a593Smuzhiyun 
851*4882a593Smuzhiyun 		res = ocount - nsp_fifo_count(SCpnt);
852*4882a593Smuzhiyun 		if (res > 0) { /* write all data? */
853*4882a593Smuzhiyun 			nsp_dbg(NSP_DEBUG_DATA_IO, "wait for all data out. ocount=0x%x res=%d", ocount, res);
854*4882a593Smuzhiyun 			continue;
855*4882a593Smuzhiyun 		}
856*4882a593Smuzhiyun 
857*4882a593Smuzhiyun 		res = min(SCpnt->SCp.this_residual, WFIFO_CRIT);
858*4882a593Smuzhiyun 
859*4882a593Smuzhiyun 		//nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this=0x%x res=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, res);
860*4882a593Smuzhiyun 		switch (data->TransferMode) {
861*4882a593Smuzhiyun 		case MODE_IO32:
862*4882a593Smuzhiyun 			res &= ~(BIT(1)|BIT(0)); /* align 4 */
863*4882a593Smuzhiyun 			nsp_fifo32_write(base, SCpnt->SCp.ptr, res >> 2);
864*4882a593Smuzhiyun 			break;
865*4882a593Smuzhiyun 		case MODE_IO8:
866*4882a593Smuzhiyun 			nsp_fifo8_write (base, SCpnt->SCp.ptr, res     );
867*4882a593Smuzhiyun 			break;
868*4882a593Smuzhiyun 
869*4882a593Smuzhiyun 		case MODE_MEM32:
870*4882a593Smuzhiyun 			res &= ~(BIT(1)|BIT(0)); /* align 4 */
871*4882a593Smuzhiyun 			nsp_mmio_fifo32_write(mmio_base, SCpnt->SCp.ptr, res >> 2);
872*4882a593Smuzhiyun 			break;
873*4882a593Smuzhiyun 
874*4882a593Smuzhiyun 		default:
875*4882a593Smuzhiyun 			nsp_dbg(NSP_DEBUG_DATA_IO, "unknown write mode");
876*4882a593Smuzhiyun 			break;
877*4882a593Smuzhiyun 		}
878*4882a593Smuzhiyun 
879*4882a593Smuzhiyun 		nsp_inc_resid(SCpnt, -res);
880*4882a593Smuzhiyun 		SCpnt->SCp.ptr		 += res;
881*4882a593Smuzhiyun 		SCpnt->SCp.this_residual -= res;
882*4882a593Smuzhiyun 		ocount			 += res;
883*4882a593Smuzhiyun 
884*4882a593Smuzhiyun 		/* go to next scatter list if available */
885*4882a593Smuzhiyun 		if (SCpnt->SCp.this_residual	== 0 &&
886*4882a593Smuzhiyun 		    SCpnt->SCp.buffers_residual != 0 ) {
887*4882a593Smuzhiyun 			//nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next");
888*4882a593Smuzhiyun 			SCpnt->SCp.buffers_residual--;
889*4882a593Smuzhiyun 			SCpnt->SCp.buffer = sg_next(SCpnt->SCp.buffer);
890*4882a593Smuzhiyun 			SCpnt->SCp.ptr		 = BUFFER_ADDR;
891*4882a593Smuzhiyun 			SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
892*4882a593Smuzhiyun 			time_out = 1000;
893*4882a593Smuzhiyun 		}
894*4882a593Smuzhiyun 	}
895*4882a593Smuzhiyun 
896*4882a593Smuzhiyun 	data->FifoCount = ocount;
897*4882a593Smuzhiyun 
898*4882a593Smuzhiyun 	if (time_out < 0) {
899*4882a593Smuzhiyun 		nsp_msg(KERN_DEBUG, "pio write timeout resid=0x%x",
900*4882a593Smuzhiyun 		                                        scsi_get_resid(SCpnt));
901*4882a593Smuzhiyun 	}
902*4882a593Smuzhiyun 	nsp_dbg(NSP_DEBUG_DATA_IO, "write ocount=0x%x", ocount);
903*4882a593Smuzhiyun 	nsp_dbg(NSP_DEBUG_DATA_IO, "w cmd=%d resid=0x%x\n", data->CmdId,
904*4882a593Smuzhiyun 	                                                scsi_get_resid(SCpnt));
905*4882a593Smuzhiyun }
906*4882a593Smuzhiyun #undef RFIFO_CRIT
907*4882a593Smuzhiyun #undef WFIFO_CRIT
908*4882a593Smuzhiyun 
909*4882a593Smuzhiyun /*
910*4882a593Smuzhiyun  * setup synchronous/asynchronous data transfer mode
911*4882a593Smuzhiyun  */
nsp_nexus(struct scsi_cmnd * SCpnt)912*4882a593Smuzhiyun static int nsp_nexus(struct scsi_cmnd *SCpnt)
913*4882a593Smuzhiyun {
914*4882a593Smuzhiyun 	unsigned int   base   = SCpnt->device->host->io_port;
915*4882a593Smuzhiyun 	unsigned char  target = scmd_id(SCpnt);
916*4882a593Smuzhiyun //	unsigned char  lun    = SCpnt->device->lun;
917*4882a593Smuzhiyun 	nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
918*4882a593Smuzhiyun 	sync_data     *sync   = &(data->Sync[target]);
919*4882a593Smuzhiyun 
920*4882a593Smuzhiyun 	//nsp_dbg(NSP_DEBUG_DATA_IO, "in SCpnt=0x%p", SCpnt);
921*4882a593Smuzhiyun 
922*4882a593Smuzhiyun 	/* setup synch transfer registers */
923*4882a593Smuzhiyun 	nsp_index_write(base, SYNCREG,	sync->SyncRegister);
924*4882a593Smuzhiyun 	nsp_index_write(base, ACKWIDTH, sync->AckWidth);
925*4882a593Smuzhiyun 
926*4882a593Smuzhiyun 	if (scsi_get_resid(SCpnt) % 4 != 0 ||
927*4882a593Smuzhiyun 	    scsi_get_resid(SCpnt) <= PAGE_SIZE ) {
928*4882a593Smuzhiyun 		data->TransferMode = MODE_IO8;
929*4882a593Smuzhiyun 	} else if (nsp_burst_mode == BURST_MEM32) {
930*4882a593Smuzhiyun 		data->TransferMode = MODE_MEM32;
931*4882a593Smuzhiyun 	} else if (nsp_burst_mode == BURST_IO32) {
932*4882a593Smuzhiyun 		data->TransferMode = MODE_IO32;
933*4882a593Smuzhiyun 	} else {
934*4882a593Smuzhiyun 		data->TransferMode = MODE_IO8;
935*4882a593Smuzhiyun 	}
936*4882a593Smuzhiyun 
937*4882a593Smuzhiyun 	/* setup pdma fifo */
938*4882a593Smuzhiyun 	nsp_setup_fifo(data, TRUE);
939*4882a593Smuzhiyun 
940*4882a593Smuzhiyun 	/* clear ack counter */
941*4882a593Smuzhiyun  	data->FifoCount = 0;
942*4882a593Smuzhiyun 	nsp_index_write(base, POINTERCLR, POINTER_CLEAR	    |
943*4882a593Smuzhiyun 					  ACK_COUNTER_CLEAR |
944*4882a593Smuzhiyun 					  REQ_COUNTER_CLEAR |
945*4882a593Smuzhiyun 					  HOST_COUNTER_CLEAR);
946*4882a593Smuzhiyun 
947*4882a593Smuzhiyun 	return 0;
948*4882a593Smuzhiyun }
949*4882a593Smuzhiyun 
950*4882a593Smuzhiyun #include "nsp_message.c"
951*4882a593Smuzhiyun /*
952*4882a593Smuzhiyun  * interrupt handler
953*4882a593Smuzhiyun  */
nspintr(int irq,void * dev_id)954*4882a593Smuzhiyun static irqreturn_t nspintr(int irq, void *dev_id)
955*4882a593Smuzhiyun {
956*4882a593Smuzhiyun 	unsigned int   base;
957*4882a593Smuzhiyun 	unsigned char  irq_status, irq_phase, phase;
958*4882a593Smuzhiyun 	struct scsi_cmnd *tmpSC;
959*4882a593Smuzhiyun 	unsigned char  target, lun;
960*4882a593Smuzhiyun 	unsigned int  *sync_neg;
961*4882a593Smuzhiyun 	int            i, tmp;
962*4882a593Smuzhiyun 	nsp_hw_data   *data;
963*4882a593Smuzhiyun 
964*4882a593Smuzhiyun 
965*4882a593Smuzhiyun 	//nsp_dbg(NSP_DEBUG_INTR, "dev_id=0x%p", dev_id);
966*4882a593Smuzhiyun 	//nsp_dbg(NSP_DEBUG_INTR, "host=0x%p", ((scsi_info_t *)dev_id)->host);
967*4882a593Smuzhiyun 
968*4882a593Smuzhiyun 	if (                dev_id        != NULL &&
969*4882a593Smuzhiyun 	    ((scsi_info_t *)dev_id)->host != NULL  ) {
970*4882a593Smuzhiyun 		scsi_info_t *info = (scsi_info_t *)dev_id;
971*4882a593Smuzhiyun 
972*4882a593Smuzhiyun 		data = (nsp_hw_data *)info->host->hostdata;
973*4882a593Smuzhiyun 	} else {
974*4882a593Smuzhiyun 		nsp_dbg(NSP_DEBUG_INTR, "host data wrong");
975*4882a593Smuzhiyun 		return IRQ_NONE;
976*4882a593Smuzhiyun 	}
977*4882a593Smuzhiyun 
978*4882a593Smuzhiyun 	//nsp_dbg(NSP_DEBUG_INTR, "&nsp_data_base=0x%p, dev_id=0x%p", &nsp_data_base, dev_id);
979*4882a593Smuzhiyun 
980*4882a593Smuzhiyun 	base = data->BaseAddress;
981*4882a593Smuzhiyun 	//nsp_dbg(NSP_DEBUG_INTR, "base=0x%x", base);
982*4882a593Smuzhiyun 
983*4882a593Smuzhiyun 	/*
984*4882a593Smuzhiyun 	 * interrupt check
985*4882a593Smuzhiyun 	 */
986*4882a593Smuzhiyun 	nsp_write(base, IRQCONTROL, IRQCONTROL_IRQDISABLE);
987*4882a593Smuzhiyun 	irq_status = nsp_read(base, IRQSTATUS);
988*4882a593Smuzhiyun 	//nsp_dbg(NSP_DEBUG_INTR, "irq_status=0x%x", irq_status);
989*4882a593Smuzhiyun 	if ((irq_status == 0xff) || ((irq_status & IRQSTATUS_MASK) == 0)) {
990*4882a593Smuzhiyun 		nsp_write(base, IRQCONTROL, 0);
991*4882a593Smuzhiyun 		//nsp_dbg(NSP_DEBUG_INTR, "no irq/shared irq");
992*4882a593Smuzhiyun 		return IRQ_NONE;
993*4882a593Smuzhiyun 	}
994*4882a593Smuzhiyun 
995*4882a593Smuzhiyun 	/* XXX: IMPORTANT
996*4882a593Smuzhiyun 	 * Do not read an irq_phase register if no scsi phase interrupt.
997*4882a593Smuzhiyun 	 * Unless, you should lose a scsi phase interrupt.
998*4882a593Smuzhiyun 	 */
999*4882a593Smuzhiyun 	phase = nsp_index_read(base, SCSIBUSMON);
1000*4882a593Smuzhiyun 	if((irq_status & IRQSTATUS_SCSI) != 0) {
1001*4882a593Smuzhiyun 		irq_phase = nsp_index_read(base, IRQPHASESENCE);
1002*4882a593Smuzhiyun 	} else {
1003*4882a593Smuzhiyun 		irq_phase = 0;
1004*4882a593Smuzhiyun 	}
1005*4882a593Smuzhiyun 
1006*4882a593Smuzhiyun 	//nsp_dbg(NSP_DEBUG_INTR, "irq_phase=0x%x", irq_phase);
1007*4882a593Smuzhiyun 
1008*4882a593Smuzhiyun 	/*
1009*4882a593Smuzhiyun 	 * timer interrupt handler (scsi vs timer interrupts)
1010*4882a593Smuzhiyun 	 */
1011*4882a593Smuzhiyun 	//nsp_dbg(NSP_DEBUG_INTR, "timercount=%d", data->TimerCount);
1012*4882a593Smuzhiyun 	if (data->TimerCount != 0) {
1013*4882a593Smuzhiyun 		//nsp_dbg(NSP_DEBUG_INTR, "stop timer");
1014*4882a593Smuzhiyun 		nsp_index_write(base, TIMERCOUNT, 0);
1015*4882a593Smuzhiyun 		nsp_index_write(base, TIMERCOUNT, 0);
1016*4882a593Smuzhiyun 		data->TimerCount = 0;
1017*4882a593Smuzhiyun 	}
1018*4882a593Smuzhiyun 
1019*4882a593Smuzhiyun 	if ((irq_status & IRQSTATUS_MASK) == IRQSTATUS_TIMER &&
1020*4882a593Smuzhiyun 	    data->SelectionTimeOut == 0) {
1021*4882a593Smuzhiyun 		//nsp_dbg(NSP_DEBUG_INTR, "timer start");
1022*4882a593Smuzhiyun 		nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR);
1023*4882a593Smuzhiyun 		return IRQ_HANDLED;
1024*4882a593Smuzhiyun 	}
1025*4882a593Smuzhiyun 
1026*4882a593Smuzhiyun 	nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR | IRQCONTROL_FIFO_CLEAR);
1027*4882a593Smuzhiyun 
1028*4882a593Smuzhiyun 	if ((irq_status & IRQSTATUS_SCSI) &&
1029*4882a593Smuzhiyun 	    (irq_phase  & SCSI_RESET_IRQ)) {
1030*4882a593Smuzhiyun 		nsp_msg(KERN_ERR, "bus reset (power off?)");
1031*4882a593Smuzhiyun 
1032*4882a593Smuzhiyun 		nsphw_init(data);
1033*4882a593Smuzhiyun 		nsp_bus_reset(data);
1034*4882a593Smuzhiyun 
1035*4882a593Smuzhiyun 		if(data->CurrentSC != NULL) {
1036*4882a593Smuzhiyun 			tmpSC = data->CurrentSC;
1037*4882a593Smuzhiyun 			tmpSC->result  = (DID_RESET                   << 16) |
1038*4882a593Smuzhiyun 				         ((tmpSC->SCp.Message & 0xff) <<  8) |
1039*4882a593Smuzhiyun 				         ((tmpSC->SCp.Status  & 0xff) <<  0);
1040*4882a593Smuzhiyun 			nsp_scsi_done(tmpSC);
1041*4882a593Smuzhiyun 		}
1042*4882a593Smuzhiyun 		return IRQ_HANDLED;
1043*4882a593Smuzhiyun 	}
1044*4882a593Smuzhiyun 
1045*4882a593Smuzhiyun 	if (data->CurrentSC == NULL) {
1046*4882a593Smuzhiyun 		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);
1047*4882a593Smuzhiyun 		nsphw_init(data);
1048*4882a593Smuzhiyun 		nsp_bus_reset(data);
1049*4882a593Smuzhiyun 		return IRQ_HANDLED;
1050*4882a593Smuzhiyun 	}
1051*4882a593Smuzhiyun 
1052*4882a593Smuzhiyun 	tmpSC    = data->CurrentSC;
1053*4882a593Smuzhiyun 	target   = tmpSC->device->id;
1054*4882a593Smuzhiyun 	lun      = tmpSC->device->lun;
1055*4882a593Smuzhiyun 	sync_neg = &(data->Sync[target].SyncNegotiation);
1056*4882a593Smuzhiyun 
1057*4882a593Smuzhiyun 	/*
1058*4882a593Smuzhiyun 	 * parse hardware SCSI irq reasons register
1059*4882a593Smuzhiyun 	 */
1060*4882a593Smuzhiyun 	if (irq_status & IRQSTATUS_SCSI) {
1061*4882a593Smuzhiyun 		if (irq_phase & RESELECT_IRQ) {
1062*4882a593Smuzhiyun 			nsp_dbg(NSP_DEBUG_INTR, "reselect");
1063*4882a593Smuzhiyun 			nsp_write(base, IRQCONTROL, IRQCONTROL_RESELECT_CLEAR);
1064*4882a593Smuzhiyun 			if (nsp_reselected(tmpSC) != FALSE) {
1065*4882a593Smuzhiyun 				return IRQ_HANDLED;
1066*4882a593Smuzhiyun 			}
1067*4882a593Smuzhiyun 		}
1068*4882a593Smuzhiyun 
1069*4882a593Smuzhiyun 		if ((irq_phase & (PHASE_CHANGE_IRQ | LATCHED_BUS_FREE)) == 0) {
1070*4882a593Smuzhiyun 			return IRQ_HANDLED;
1071*4882a593Smuzhiyun 		}
1072*4882a593Smuzhiyun 	}
1073*4882a593Smuzhiyun 
1074*4882a593Smuzhiyun 	//show_phase(tmpSC);
1075*4882a593Smuzhiyun 
1076*4882a593Smuzhiyun 	switch(tmpSC->SCp.phase) {
1077*4882a593Smuzhiyun 	case PH_SELSTART:
1078*4882a593Smuzhiyun 		// *sync_neg = SYNC_NOT_YET;
1079*4882a593Smuzhiyun 		if ((phase & BUSMON_BSY) == 0) {
1080*4882a593Smuzhiyun 			//nsp_dbg(NSP_DEBUG_INTR, "selection count=%d", data->SelectionTimeOut);
1081*4882a593Smuzhiyun 			if (data->SelectionTimeOut >= NSP_SELTIMEOUT) {
1082*4882a593Smuzhiyun 				nsp_dbg(NSP_DEBUG_INTR, "selection time out");
1083*4882a593Smuzhiyun 				data->SelectionTimeOut = 0;
1084*4882a593Smuzhiyun 				nsp_index_write(base, SCSIBUSCTRL, 0);
1085*4882a593Smuzhiyun 
1086*4882a593Smuzhiyun 				tmpSC->result   = DID_TIME_OUT << 16;
1087*4882a593Smuzhiyun 				nsp_scsi_done(tmpSC);
1088*4882a593Smuzhiyun 
1089*4882a593Smuzhiyun 				return IRQ_HANDLED;
1090*4882a593Smuzhiyun 			}
1091*4882a593Smuzhiyun 			data->SelectionTimeOut += 1;
1092*4882a593Smuzhiyun 			nsp_start_timer(tmpSC, 1000/51);
1093*4882a593Smuzhiyun 			return IRQ_HANDLED;
1094*4882a593Smuzhiyun 		}
1095*4882a593Smuzhiyun 
1096*4882a593Smuzhiyun 		/* attention assert */
1097*4882a593Smuzhiyun 		//nsp_dbg(NSP_DEBUG_INTR, "attention assert");
1098*4882a593Smuzhiyun 		data->SelectionTimeOut = 0;
1099*4882a593Smuzhiyun 		tmpSC->SCp.phase       = PH_SELECTED;
1100*4882a593Smuzhiyun 		nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN);
1101*4882a593Smuzhiyun 		udelay(1);
1102*4882a593Smuzhiyun 		nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN | AUTODIRECTION | ACKENB);
1103*4882a593Smuzhiyun 		return IRQ_HANDLED;
1104*4882a593Smuzhiyun 
1105*4882a593Smuzhiyun 		break;
1106*4882a593Smuzhiyun 
1107*4882a593Smuzhiyun 	case PH_RESELECT:
1108*4882a593Smuzhiyun 		//nsp_dbg(NSP_DEBUG_INTR, "phase reselect");
1109*4882a593Smuzhiyun 		// *sync_neg = SYNC_NOT_YET;
1110*4882a593Smuzhiyun 		if ((phase & BUSMON_PHASE_MASK) != BUSPHASE_MESSAGE_IN) {
1111*4882a593Smuzhiyun 
1112*4882a593Smuzhiyun 			tmpSC->result	= DID_ABORT << 16;
1113*4882a593Smuzhiyun 			nsp_scsi_done(tmpSC);
1114*4882a593Smuzhiyun 			return IRQ_HANDLED;
1115*4882a593Smuzhiyun 		}
1116*4882a593Smuzhiyun 		fallthrough;
1117*4882a593Smuzhiyun 	default:
1118*4882a593Smuzhiyun 		if ((irq_status & (IRQSTATUS_SCSI | IRQSTATUS_FIFO)) == 0) {
1119*4882a593Smuzhiyun 			return IRQ_HANDLED;
1120*4882a593Smuzhiyun 		}
1121*4882a593Smuzhiyun 		break;
1122*4882a593Smuzhiyun 	}
1123*4882a593Smuzhiyun 
1124*4882a593Smuzhiyun 	/*
1125*4882a593Smuzhiyun 	 * SCSI sequencer
1126*4882a593Smuzhiyun 	 */
1127*4882a593Smuzhiyun 	//nsp_dbg(NSP_DEBUG_INTR, "start scsi seq");
1128*4882a593Smuzhiyun 
1129*4882a593Smuzhiyun 	/* normal disconnect */
1130*4882a593Smuzhiyun 	if (((tmpSC->SCp.phase == PH_MSG_IN) || (tmpSC->SCp.phase == PH_MSG_OUT)) &&
1131*4882a593Smuzhiyun 	    (irq_phase & LATCHED_BUS_FREE) != 0 ) {
1132*4882a593Smuzhiyun 		nsp_dbg(NSP_DEBUG_INTR, "normal disconnect irq_status=0x%x, phase=0x%x, irq_phase=0x%x", irq_status, phase, irq_phase);
1133*4882a593Smuzhiyun 
1134*4882a593Smuzhiyun 		//*sync_neg       = SYNC_NOT_YET;
1135*4882a593Smuzhiyun 
1136*4882a593Smuzhiyun 		/* all command complete and return status */
1137*4882a593Smuzhiyun 		if (tmpSC->SCp.Message == MSG_COMMAND_COMPLETE) {
1138*4882a593Smuzhiyun 			tmpSC->result = (DID_OK		             << 16) |
1139*4882a593Smuzhiyun 					((tmpSC->SCp.Message & 0xff) <<  8) |
1140*4882a593Smuzhiyun 					((tmpSC->SCp.Status  & 0xff) <<  0);
1141*4882a593Smuzhiyun 			nsp_dbg(NSP_DEBUG_INTR, "command complete result=0x%x", tmpSC->result);
1142*4882a593Smuzhiyun 			nsp_scsi_done(tmpSC);
1143*4882a593Smuzhiyun 
1144*4882a593Smuzhiyun 			return IRQ_HANDLED;
1145*4882a593Smuzhiyun 		}
1146*4882a593Smuzhiyun 
1147*4882a593Smuzhiyun 		return IRQ_HANDLED;
1148*4882a593Smuzhiyun 	}
1149*4882a593Smuzhiyun 
1150*4882a593Smuzhiyun 
1151*4882a593Smuzhiyun 	/* check unexpected bus free state */
1152*4882a593Smuzhiyun 	if (phase == 0) {
1153*4882a593Smuzhiyun 		nsp_msg(KERN_DEBUG, "unexpected bus free. irq_status=0x%x, phase=0x%x, irq_phase=0x%x", irq_status, phase, irq_phase);
1154*4882a593Smuzhiyun 
1155*4882a593Smuzhiyun 		*sync_neg       = SYNC_NG;
1156*4882a593Smuzhiyun 		tmpSC->result   = DID_ERROR << 16;
1157*4882a593Smuzhiyun 		nsp_scsi_done(tmpSC);
1158*4882a593Smuzhiyun 		return IRQ_HANDLED;
1159*4882a593Smuzhiyun 	}
1160*4882a593Smuzhiyun 
1161*4882a593Smuzhiyun 	switch (phase & BUSMON_PHASE_MASK) {
1162*4882a593Smuzhiyun 	case BUSPHASE_COMMAND:
1163*4882a593Smuzhiyun 		nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_COMMAND");
1164*4882a593Smuzhiyun 		if ((phase & BUSMON_REQ) == 0) {
1165*4882a593Smuzhiyun 			nsp_dbg(NSP_DEBUG_INTR, "REQ == 0");
1166*4882a593Smuzhiyun 			return IRQ_HANDLED;
1167*4882a593Smuzhiyun 		}
1168*4882a593Smuzhiyun 
1169*4882a593Smuzhiyun 		tmpSC->SCp.phase = PH_COMMAND;
1170*4882a593Smuzhiyun 
1171*4882a593Smuzhiyun 		nsp_nexus(tmpSC);
1172*4882a593Smuzhiyun 
1173*4882a593Smuzhiyun 		/* write scsi command */
1174*4882a593Smuzhiyun 		nsp_dbg(NSP_DEBUG_INTR, "cmd_len=%d", tmpSC->cmd_len);
1175*4882a593Smuzhiyun 		nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER);
1176*4882a593Smuzhiyun 		for (i = 0; i < tmpSC->cmd_len; i++) {
1177*4882a593Smuzhiyun 			nsp_index_write(base, COMMANDDATA, tmpSC->cmnd[i]);
1178*4882a593Smuzhiyun 		}
1179*4882a593Smuzhiyun 		nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER | AUTO_COMMAND_GO);
1180*4882a593Smuzhiyun 		break;
1181*4882a593Smuzhiyun 
1182*4882a593Smuzhiyun 	case BUSPHASE_DATA_OUT:
1183*4882a593Smuzhiyun 		nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_DATA_OUT");
1184*4882a593Smuzhiyun 
1185*4882a593Smuzhiyun 		tmpSC->SCp.phase        = PH_DATA;
1186*4882a593Smuzhiyun 		tmpSC->SCp.have_data_in = IO_OUT;
1187*4882a593Smuzhiyun 
1188*4882a593Smuzhiyun 		nsp_pio_write(tmpSC);
1189*4882a593Smuzhiyun 
1190*4882a593Smuzhiyun 		break;
1191*4882a593Smuzhiyun 
1192*4882a593Smuzhiyun 	case BUSPHASE_DATA_IN:
1193*4882a593Smuzhiyun 		nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_DATA_IN");
1194*4882a593Smuzhiyun 
1195*4882a593Smuzhiyun 		tmpSC->SCp.phase        = PH_DATA;
1196*4882a593Smuzhiyun 		tmpSC->SCp.have_data_in = IO_IN;
1197*4882a593Smuzhiyun 
1198*4882a593Smuzhiyun 		nsp_pio_read(tmpSC);
1199*4882a593Smuzhiyun 
1200*4882a593Smuzhiyun 		break;
1201*4882a593Smuzhiyun 
1202*4882a593Smuzhiyun 	case BUSPHASE_STATUS:
1203*4882a593Smuzhiyun 		nsp_dataphase_bypass(tmpSC);
1204*4882a593Smuzhiyun 		nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_STATUS");
1205*4882a593Smuzhiyun 
1206*4882a593Smuzhiyun 		tmpSC->SCp.phase = PH_STATUS;
1207*4882a593Smuzhiyun 
1208*4882a593Smuzhiyun 		tmpSC->SCp.Status = nsp_index_read(base, SCSIDATAWITHACK);
1209*4882a593Smuzhiyun 		nsp_dbg(NSP_DEBUG_INTR, "message=0x%x status=0x%x", tmpSC->SCp.Message, tmpSC->SCp.Status);
1210*4882a593Smuzhiyun 
1211*4882a593Smuzhiyun 		break;
1212*4882a593Smuzhiyun 
1213*4882a593Smuzhiyun 	case BUSPHASE_MESSAGE_OUT:
1214*4882a593Smuzhiyun 		nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_MESSAGE_OUT");
1215*4882a593Smuzhiyun 		if ((phase & BUSMON_REQ) == 0) {
1216*4882a593Smuzhiyun 			goto timer_out;
1217*4882a593Smuzhiyun 		}
1218*4882a593Smuzhiyun 
1219*4882a593Smuzhiyun 		tmpSC->SCp.phase = PH_MSG_OUT;
1220*4882a593Smuzhiyun 
1221*4882a593Smuzhiyun 		//*sync_neg = SYNC_NOT_YET;
1222*4882a593Smuzhiyun 
1223*4882a593Smuzhiyun 		data->MsgLen = i = 0;
1224*4882a593Smuzhiyun 		data->MsgBuffer[i] = IDENTIFY(TRUE, lun); i++;
1225*4882a593Smuzhiyun 
1226*4882a593Smuzhiyun 		if (*sync_neg == SYNC_NOT_YET) {
1227*4882a593Smuzhiyun 			data->Sync[target].SyncPeriod = 0;
1228*4882a593Smuzhiyun 			data->Sync[target].SyncOffset = 0;
1229*4882a593Smuzhiyun 
1230*4882a593Smuzhiyun 			/**/
1231*4882a593Smuzhiyun 			data->MsgBuffer[i] = MSG_EXTENDED; i++;
1232*4882a593Smuzhiyun 			data->MsgBuffer[i] = 3;            i++;
1233*4882a593Smuzhiyun 			data->MsgBuffer[i] = MSG_EXT_SDTR; i++;
1234*4882a593Smuzhiyun 			data->MsgBuffer[i] = 0x0c;         i++;
1235*4882a593Smuzhiyun 			data->MsgBuffer[i] = 15;           i++;
1236*4882a593Smuzhiyun 			/**/
1237*4882a593Smuzhiyun 		}
1238*4882a593Smuzhiyun 		data->MsgLen = i;
1239*4882a593Smuzhiyun 
1240*4882a593Smuzhiyun 		nsp_analyze_sdtr(tmpSC);
1241*4882a593Smuzhiyun 		show_message(data);
1242*4882a593Smuzhiyun 		nsp_message_out(tmpSC);
1243*4882a593Smuzhiyun 		break;
1244*4882a593Smuzhiyun 
1245*4882a593Smuzhiyun 	case BUSPHASE_MESSAGE_IN:
1246*4882a593Smuzhiyun 		nsp_dataphase_bypass(tmpSC);
1247*4882a593Smuzhiyun 		nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_MESSAGE_IN");
1248*4882a593Smuzhiyun 		if ((phase & BUSMON_REQ) == 0) {
1249*4882a593Smuzhiyun 			goto timer_out;
1250*4882a593Smuzhiyun 		}
1251*4882a593Smuzhiyun 
1252*4882a593Smuzhiyun 		tmpSC->SCp.phase = PH_MSG_IN;
1253*4882a593Smuzhiyun 		nsp_message_in(tmpSC);
1254*4882a593Smuzhiyun 
1255*4882a593Smuzhiyun 		/**/
1256*4882a593Smuzhiyun 		if (*sync_neg == SYNC_NOT_YET) {
1257*4882a593Smuzhiyun 			//nsp_dbg(NSP_DEBUG_INTR, "sync target=%d,lun=%d",target,lun);
1258*4882a593Smuzhiyun 
1259*4882a593Smuzhiyun 			if (data->MsgLen       >= 5            &&
1260*4882a593Smuzhiyun 			    data->MsgBuffer[0] == MSG_EXTENDED &&
1261*4882a593Smuzhiyun 			    data->MsgBuffer[1] == 3            &&
1262*4882a593Smuzhiyun 			    data->MsgBuffer[2] == MSG_EXT_SDTR ) {
1263*4882a593Smuzhiyun 				data->Sync[target].SyncPeriod = data->MsgBuffer[3];
1264*4882a593Smuzhiyun 				data->Sync[target].SyncOffset = data->MsgBuffer[4];
1265*4882a593Smuzhiyun 				//nsp_dbg(NSP_DEBUG_INTR, "sync ok, %d %d", data->MsgBuffer[3], data->MsgBuffer[4]);
1266*4882a593Smuzhiyun 				*sync_neg = SYNC_OK;
1267*4882a593Smuzhiyun 			} else {
1268*4882a593Smuzhiyun 				data->Sync[target].SyncPeriod = 0;
1269*4882a593Smuzhiyun 				data->Sync[target].SyncOffset = 0;
1270*4882a593Smuzhiyun 				*sync_neg = SYNC_NG;
1271*4882a593Smuzhiyun 			}
1272*4882a593Smuzhiyun 			nsp_analyze_sdtr(tmpSC);
1273*4882a593Smuzhiyun 		}
1274*4882a593Smuzhiyun 		/**/
1275*4882a593Smuzhiyun 
1276*4882a593Smuzhiyun 		/* search last messeage byte */
1277*4882a593Smuzhiyun 		tmp = -1;
1278*4882a593Smuzhiyun 		for (i = 0; i < data->MsgLen; i++) {
1279*4882a593Smuzhiyun 			tmp = data->MsgBuffer[i];
1280*4882a593Smuzhiyun 			if (data->MsgBuffer[i] == MSG_EXTENDED) {
1281*4882a593Smuzhiyun 				i += (1 + data->MsgBuffer[i+1]);
1282*4882a593Smuzhiyun 			}
1283*4882a593Smuzhiyun 		}
1284*4882a593Smuzhiyun 		tmpSC->SCp.Message = tmp;
1285*4882a593Smuzhiyun 
1286*4882a593Smuzhiyun 		nsp_dbg(NSP_DEBUG_INTR, "message=0x%x len=%d", tmpSC->SCp.Message, data->MsgLen);
1287*4882a593Smuzhiyun 		show_message(data);
1288*4882a593Smuzhiyun 
1289*4882a593Smuzhiyun 		break;
1290*4882a593Smuzhiyun 
1291*4882a593Smuzhiyun 	case BUSPHASE_SELECT:
1292*4882a593Smuzhiyun 	default:
1293*4882a593Smuzhiyun 		nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE other");
1294*4882a593Smuzhiyun 
1295*4882a593Smuzhiyun 		break;
1296*4882a593Smuzhiyun 	}
1297*4882a593Smuzhiyun 
1298*4882a593Smuzhiyun 	//nsp_dbg(NSP_DEBUG_INTR, "out");
1299*4882a593Smuzhiyun 	return IRQ_HANDLED;
1300*4882a593Smuzhiyun 
1301*4882a593Smuzhiyun timer_out:
1302*4882a593Smuzhiyun 	nsp_start_timer(tmpSC, 1000/102);
1303*4882a593Smuzhiyun 	return IRQ_HANDLED;
1304*4882a593Smuzhiyun }
1305*4882a593Smuzhiyun 
1306*4882a593Smuzhiyun #ifdef NSP_DEBUG
1307*4882a593Smuzhiyun #include "nsp_debug.c"
1308*4882a593Smuzhiyun #endif	/* NSP_DEBUG */
1309*4882a593Smuzhiyun 
1310*4882a593Smuzhiyun /*----------------------------------------------------------------*/
1311*4882a593Smuzhiyun /* look for ninja3 card and init if found			  */
1312*4882a593Smuzhiyun /*----------------------------------------------------------------*/
nsp_detect(struct scsi_host_template * sht)1313*4882a593Smuzhiyun static struct Scsi_Host *nsp_detect(struct scsi_host_template *sht)
1314*4882a593Smuzhiyun {
1315*4882a593Smuzhiyun 	struct Scsi_Host *host;	/* registered host structure */
1316*4882a593Smuzhiyun 	nsp_hw_data *data_b = &nsp_data_base, *data;
1317*4882a593Smuzhiyun 
1318*4882a593Smuzhiyun 	nsp_dbg(NSP_DEBUG_INIT, "this_id=%d", sht->this_id);
1319*4882a593Smuzhiyun 	host = scsi_host_alloc(&nsp_driver_template, sizeof(nsp_hw_data));
1320*4882a593Smuzhiyun 	if (host == NULL) {
1321*4882a593Smuzhiyun 		nsp_dbg(NSP_DEBUG_INIT, "host failed");
1322*4882a593Smuzhiyun 		return NULL;
1323*4882a593Smuzhiyun 	}
1324*4882a593Smuzhiyun 
1325*4882a593Smuzhiyun 	memcpy(host->hostdata, data_b, sizeof(nsp_hw_data));
1326*4882a593Smuzhiyun 	data = (nsp_hw_data *)host->hostdata;
1327*4882a593Smuzhiyun 	data->ScsiInfo->host = host;
1328*4882a593Smuzhiyun #ifdef NSP_DEBUG
1329*4882a593Smuzhiyun 	data->CmdId = 0;
1330*4882a593Smuzhiyun #endif
1331*4882a593Smuzhiyun 
1332*4882a593Smuzhiyun 	nsp_dbg(NSP_DEBUG_INIT, "irq=%d,%d", data_b->IrqNumber, ((nsp_hw_data *)host->hostdata)->IrqNumber);
1333*4882a593Smuzhiyun 
1334*4882a593Smuzhiyun 	host->unique_id	  = data->BaseAddress;
1335*4882a593Smuzhiyun 	host->io_port	  = data->BaseAddress;
1336*4882a593Smuzhiyun 	host->n_io_port	  = data->NumAddress;
1337*4882a593Smuzhiyun 	host->irq	  = data->IrqNumber;
1338*4882a593Smuzhiyun 	host->base        = data->MmioAddress;
1339*4882a593Smuzhiyun 
1340*4882a593Smuzhiyun 	spin_lock_init(&(data->Lock));
1341*4882a593Smuzhiyun 
1342*4882a593Smuzhiyun 	snprintf(data->nspinfo,
1343*4882a593Smuzhiyun 		 sizeof(data->nspinfo),
1344*4882a593Smuzhiyun 		 "NinjaSCSI-3/32Bi Driver $Revision: 1.23 $ IO:0x%04lx-0x%04lx MMIO(virt addr):0x%04lx IRQ:%02d",
1345*4882a593Smuzhiyun 		 host->io_port, host->io_port + host->n_io_port - 1,
1346*4882a593Smuzhiyun 		 host->base,
1347*4882a593Smuzhiyun 		 host->irq);
1348*4882a593Smuzhiyun 	sht->name	  = data->nspinfo;
1349*4882a593Smuzhiyun 
1350*4882a593Smuzhiyun 	nsp_dbg(NSP_DEBUG_INIT, "end");
1351*4882a593Smuzhiyun 
1352*4882a593Smuzhiyun 
1353*4882a593Smuzhiyun 	return host; /* detect done. */
1354*4882a593Smuzhiyun }
1355*4882a593Smuzhiyun 
1356*4882a593Smuzhiyun /*----------------------------------------------------------------*/
1357*4882a593Smuzhiyun /* return info string						  */
1358*4882a593Smuzhiyun /*----------------------------------------------------------------*/
nsp_info(struct Scsi_Host * shpnt)1359*4882a593Smuzhiyun static const char *nsp_info(struct Scsi_Host *shpnt)
1360*4882a593Smuzhiyun {
1361*4882a593Smuzhiyun 	nsp_hw_data *data = (nsp_hw_data *)shpnt->hostdata;
1362*4882a593Smuzhiyun 
1363*4882a593Smuzhiyun 	return data->nspinfo;
1364*4882a593Smuzhiyun }
1365*4882a593Smuzhiyun 
nsp_show_info(struct seq_file * m,struct Scsi_Host * host)1366*4882a593Smuzhiyun static int nsp_show_info(struct seq_file *m, struct Scsi_Host *host)
1367*4882a593Smuzhiyun {
1368*4882a593Smuzhiyun 	int id;
1369*4882a593Smuzhiyun 	int speed;
1370*4882a593Smuzhiyun 	unsigned long flags;
1371*4882a593Smuzhiyun 	nsp_hw_data *data;
1372*4882a593Smuzhiyun 	int hostno;
1373*4882a593Smuzhiyun 
1374*4882a593Smuzhiyun 	hostno = host->host_no;
1375*4882a593Smuzhiyun 	data = (nsp_hw_data *)host->hostdata;
1376*4882a593Smuzhiyun 
1377*4882a593Smuzhiyun 	seq_puts(m, "NinjaSCSI status\n\n"
1378*4882a593Smuzhiyun 		"Driver version:        $Revision: 1.23 $\n");
1379*4882a593Smuzhiyun 	seq_printf(m, "SCSI host No.:         %d\n",          hostno);
1380*4882a593Smuzhiyun 	seq_printf(m, "IRQ:                   %d\n",          host->irq);
1381*4882a593Smuzhiyun 	seq_printf(m, "IO:                    0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1);
1382*4882a593Smuzhiyun 	seq_printf(m, "MMIO(virtual address): 0x%lx-0x%lx\n", host->base, host->base + data->MmioLength - 1);
1383*4882a593Smuzhiyun 	seq_printf(m, "sg_tablesize:          %d\n",          host->sg_tablesize);
1384*4882a593Smuzhiyun 
1385*4882a593Smuzhiyun 	seq_puts(m, "burst transfer mode:   ");
1386*4882a593Smuzhiyun 	switch (nsp_burst_mode) {
1387*4882a593Smuzhiyun 	case BURST_IO8:
1388*4882a593Smuzhiyun 		seq_puts(m, "io8");
1389*4882a593Smuzhiyun 		break;
1390*4882a593Smuzhiyun 	case BURST_IO32:
1391*4882a593Smuzhiyun 		seq_puts(m, "io32");
1392*4882a593Smuzhiyun 		break;
1393*4882a593Smuzhiyun 	case BURST_MEM32:
1394*4882a593Smuzhiyun 		seq_puts(m, "mem32");
1395*4882a593Smuzhiyun 		break;
1396*4882a593Smuzhiyun 	default:
1397*4882a593Smuzhiyun 		seq_puts(m, "???");
1398*4882a593Smuzhiyun 		break;
1399*4882a593Smuzhiyun 	}
1400*4882a593Smuzhiyun 	seq_putc(m, '\n');
1401*4882a593Smuzhiyun 
1402*4882a593Smuzhiyun 
1403*4882a593Smuzhiyun 	spin_lock_irqsave(&(data->Lock), flags);
1404*4882a593Smuzhiyun 	seq_printf(m, "CurrentSC:             0x%p\n\n",      data->CurrentSC);
1405*4882a593Smuzhiyun 	spin_unlock_irqrestore(&(data->Lock), flags);
1406*4882a593Smuzhiyun 
1407*4882a593Smuzhiyun 	seq_puts(m, "SDTR status\n");
1408*4882a593Smuzhiyun 	for(id = 0; id < ARRAY_SIZE(data->Sync); id++) {
1409*4882a593Smuzhiyun 
1410*4882a593Smuzhiyun 		seq_printf(m, "id %d: ", id);
1411*4882a593Smuzhiyun 
1412*4882a593Smuzhiyun 		if (id == host->this_id) {
1413*4882a593Smuzhiyun 			seq_puts(m, "----- NinjaSCSI-3 host adapter\n");
1414*4882a593Smuzhiyun 			continue;
1415*4882a593Smuzhiyun 		}
1416*4882a593Smuzhiyun 
1417*4882a593Smuzhiyun 		switch(data->Sync[id].SyncNegotiation) {
1418*4882a593Smuzhiyun 		case SYNC_OK:
1419*4882a593Smuzhiyun 			seq_puts(m, " sync");
1420*4882a593Smuzhiyun 			break;
1421*4882a593Smuzhiyun 		case SYNC_NG:
1422*4882a593Smuzhiyun 			seq_puts(m, "async");
1423*4882a593Smuzhiyun 			break;
1424*4882a593Smuzhiyun 		case SYNC_NOT_YET:
1425*4882a593Smuzhiyun 			seq_puts(m, " none");
1426*4882a593Smuzhiyun 			break;
1427*4882a593Smuzhiyun 		default:
1428*4882a593Smuzhiyun 			seq_puts(m, "?????");
1429*4882a593Smuzhiyun 			break;
1430*4882a593Smuzhiyun 		}
1431*4882a593Smuzhiyun 
1432*4882a593Smuzhiyun 		if (data->Sync[id].SyncPeriod != 0) {
1433*4882a593Smuzhiyun 			speed = 1000000 / (data->Sync[id].SyncPeriod * 4);
1434*4882a593Smuzhiyun 
1435*4882a593Smuzhiyun 			seq_printf(m, " transfer %d.%dMB/s, offset %d",
1436*4882a593Smuzhiyun 				speed / 1000,
1437*4882a593Smuzhiyun 				speed % 1000,
1438*4882a593Smuzhiyun 				data->Sync[id].SyncOffset
1439*4882a593Smuzhiyun 				);
1440*4882a593Smuzhiyun 		}
1441*4882a593Smuzhiyun 		seq_putc(m, '\n');
1442*4882a593Smuzhiyun 	}
1443*4882a593Smuzhiyun 	return 0;
1444*4882a593Smuzhiyun }
1445*4882a593Smuzhiyun 
1446*4882a593Smuzhiyun /*---------------------------------------------------------------*/
1447*4882a593Smuzhiyun /* error handler                                                 */
1448*4882a593Smuzhiyun /*---------------------------------------------------------------*/
1449*4882a593Smuzhiyun 
1450*4882a593Smuzhiyun /*
1451*4882a593Smuzhiyun static int nsp_eh_abort(struct scsi_cmnd *SCpnt)
1452*4882a593Smuzhiyun {
1453*4882a593Smuzhiyun 	nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt);
1454*4882a593Smuzhiyun 
1455*4882a593Smuzhiyun 	return nsp_eh_bus_reset(SCpnt);
1456*4882a593Smuzhiyun }*/
1457*4882a593Smuzhiyun 
nsp_bus_reset(nsp_hw_data * data)1458*4882a593Smuzhiyun static int nsp_bus_reset(nsp_hw_data *data)
1459*4882a593Smuzhiyun {
1460*4882a593Smuzhiyun 	unsigned int base = data->BaseAddress;
1461*4882a593Smuzhiyun 	int	     i;
1462*4882a593Smuzhiyun 
1463*4882a593Smuzhiyun 	nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK);
1464*4882a593Smuzhiyun 
1465*4882a593Smuzhiyun 	nsp_index_write(base, SCSIBUSCTRL, SCSI_RST);
1466*4882a593Smuzhiyun 	mdelay(100); /* 100ms */
1467*4882a593Smuzhiyun 	nsp_index_write(base, SCSIBUSCTRL, 0);
1468*4882a593Smuzhiyun 	for(i = 0; i < 5; i++) {
1469*4882a593Smuzhiyun 		nsp_index_read(base, IRQPHASESENCE); /* dummy read */
1470*4882a593Smuzhiyun 	}
1471*4882a593Smuzhiyun 
1472*4882a593Smuzhiyun 	nsphw_init_sync(data);
1473*4882a593Smuzhiyun 
1474*4882a593Smuzhiyun 	nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR);
1475*4882a593Smuzhiyun 
1476*4882a593Smuzhiyun 	return SUCCESS;
1477*4882a593Smuzhiyun }
1478*4882a593Smuzhiyun 
nsp_eh_bus_reset(struct scsi_cmnd * SCpnt)1479*4882a593Smuzhiyun static int nsp_eh_bus_reset(struct scsi_cmnd *SCpnt)
1480*4882a593Smuzhiyun {
1481*4882a593Smuzhiyun 	nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
1482*4882a593Smuzhiyun 
1483*4882a593Smuzhiyun 	nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt);
1484*4882a593Smuzhiyun 
1485*4882a593Smuzhiyun 	return nsp_bus_reset(data);
1486*4882a593Smuzhiyun }
1487*4882a593Smuzhiyun 
nsp_eh_host_reset(struct scsi_cmnd * SCpnt)1488*4882a593Smuzhiyun static int nsp_eh_host_reset(struct scsi_cmnd *SCpnt)
1489*4882a593Smuzhiyun {
1490*4882a593Smuzhiyun 	nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
1491*4882a593Smuzhiyun 
1492*4882a593Smuzhiyun 	nsp_dbg(NSP_DEBUG_BUSRESET, "in");
1493*4882a593Smuzhiyun 
1494*4882a593Smuzhiyun 	nsphw_init(data);
1495*4882a593Smuzhiyun 
1496*4882a593Smuzhiyun 	return SUCCESS;
1497*4882a593Smuzhiyun }
1498*4882a593Smuzhiyun 
1499*4882a593Smuzhiyun 
1500*4882a593Smuzhiyun /**********************************************************************
1501*4882a593Smuzhiyun   PCMCIA functions
1502*4882a593Smuzhiyun **********************************************************************/
1503*4882a593Smuzhiyun 
nsp_cs_probe(struct pcmcia_device * link)1504*4882a593Smuzhiyun static int nsp_cs_probe(struct pcmcia_device *link)
1505*4882a593Smuzhiyun {
1506*4882a593Smuzhiyun 	scsi_info_t  *info;
1507*4882a593Smuzhiyun 	nsp_hw_data  *data = &nsp_data_base;
1508*4882a593Smuzhiyun 	int ret;
1509*4882a593Smuzhiyun 
1510*4882a593Smuzhiyun 	nsp_dbg(NSP_DEBUG_INIT, "in");
1511*4882a593Smuzhiyun 
1512*4882a593Smuzhiyun 	/* Create new SCSI device */
1513*4882a593Smuzhiyun 	info = kzalloc(sizeof(*info), GFP_KERNEL);
1514*4882a593Smuzhiyun 	if (info == NULL) { return -ENOMEM; }
1515*4882a593Smuzhiyun 	info->p_dev = link;
1516*4882a593Smuzhiyun 	link->priv = info;
1517*4882a593Smuzhiyun 	data->ScsiInfo = info;
1518*4882a593Smuzhiyun 
1519*4882a593Smuzhiyun 	nsp_dbg(NSP_DEBUG_INIT, "info=0x%p", info);
1520*4882a593Smuzhiyun 
1521*4882a593Smuzhiyun 	ret = nsp_cs_config(link);
1522*4882a593Smuzhiyun 
1523*4882a593Smuzhiyun 	nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link);
1524*4882a593Smuzhiyun 	return ret;
1525*4882a593Smuzhiyun } /* nsp_cs_attach */
1526*4882a593Smuzhiyun 
1527*4882a593Smuzhiyun 
nsp_cs_detach(struct pcmcia_device * link)1528*4882a593Smuzhiyun static void nsp_cs_detach(struct pcmcia_device *link)
1529*4882a593Smuzhiyun {
1530*4882a593Smuzhiyun 	nsp_dbg(NSP_DEBUG_INIT, "in, link=0x%p", link);
1531*4882a593Smuzhiyun 
1532*4882a593Smuzhiyun 	((scsi_info_t *)link->priv)->stop = 1;
1533*4882a593Smuzhiyun 	nsp_cs_release(link);
1534*4882a593Smuzhiyun 
1535*4882a593Smuzhiyun 	kfree(link->priv);
1536*4882a593Smuzhiyun 	link->priv = NULL;
1537*4882a593Smuzhiyun } /* nsp_cs_detach */
1538*4882a593Smuzhiyun 
1539*4882a593Smuzhiyun 
nsp_cs_config_check(struct pcmcia_device * p_dev,void * priv_data)1540*4882a593Smuzhiyun static int nsp_cs_config_check(struct pcmcia_device *p_dev, void *priv_data)
1541*4882a593Smuzhiyun {
1542*4882a593Smuzhiyun 	nsp_hw_data		*data = priv_data;
1543*4882a593Smuzhiyun 
1544*4882a593Smuzhiyun 	if (p_dev->config_index == 0)
1545*4882a593Smuzhiyun 		return -ENODEV;
1546*4882a593Smuzhiyun 
1547*4882a593Smuzhiyun 	/* This reserves IO space but doesn't actually enable it */
1548*4882a593Smuzhiyun 	if (pcmcia_request_io(p_dev) != 0)
1549*4882a593Smuzhiyun 		goto next_entry;
1550*4882a593Smuzhiyun 
1551*4882a593Smuzhiyun 	if (resource_size(p_dev->resource[2])) {
1552*4882a593Smuzhiyun 		p_dev->resource[2]->flags |= (WIN_DATA_WIDTH_16 |
1553*4882a593Smuzhiyun 					WIN_MEMORY_TYPE_CM |
1554*4882a593Smuzhiyun 					WIN_ENABLE);
1555*4882a593Smuzhiyun 		if (p_dev->resource[2]->end < 0x1000)
1556*4882a593Smuzhiyun 			p_dev->resource[2]->end = 0x1000;
1557*4882a593Smuzhiyun 		if (pcmcia_request_window(p_dev, p_dev->resource[2], 0) != 0)
1558*4882a593Smuzhiyun 			goto next_entry;
1559*4882a593Smuzhiyun 		if (pcmcia_map_mem_page(p_dev, p_dev->resource[2],
1560*4882a593Smuzhiyun 						p_dev->card_addr) != 0)
1561*4882a593Smuzhiyun 			goto next_entry;
1562*4882a593Smuzhiyun 
1563*4882a593Smuzhiyun 		data->MmioAddress = (unsigned long)
1564*4882a593Smuzhiyun 			ioremap(p_dev->resource[2]->start,
1565*4882a593Smuzhiyun 					resource_size(p_dev->resource[2]));
1566*4882a593Smuzhiyun 		data->MmioLength  = resource_size(p_dev->resource[2]);
1567*4882a593Smuzhiyun 	}
1568*4882a593Smuzhiyun 	/* If we got this far, we're cool! */
1569*4882a593Smuzhiyun 	return 0;
1570*4882a593Smuzhiyun 
1571*4882a593Smuzhiyun next_entry:
1572*4882a593Smuzhiyun 	nsp_dbg(NSP_DEBUG_INIT, "next");
1573*4882a593Smuzhiyun 	pcmcia_disable_device(p_dev);
1574*4882a593Smuzhiyun 	return -ENODEV;
1575*4882a593Smuzhiyun }
1576*4882a593Smuzhiyun 
nsp_cs_config(struct pcmcia_device * link)1577*4882a593Smuzhiyun static int nsp_cs_config(struct pcmcia_device *link)
1578*4882a593Smuzhiyun {
1579*4882a593Smuzhiyun 	int		  ret;
1580*4882a593Smuzhiyun 	scsi_info_t	 *info	 = link->priv;
1581*4882a593Smuzhiyun 	struct Scsi_Host *host;
1582*4882a593Smuzhiyun 	nsp_hw_data      *data = &nsp_data_base;
1583*4882a593Smuzhiyun 
1584*4882a593Smuzhiyun 	nsp_dbg(NSP_DEBUG_INIT, "in");
1585*4882a593Smuzhiyun 
1586*4882a593Smuzhiyun 	link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_CHECK_VCC |
1587*4882a593Smuzhiyun 		CONF_AUTO_SET_VPP | CONF_AUTO_AUDIO | CONF_AUTO_SET_IOMEM |
1588*4882a593Smuzhiyun 		CONF_AUTO_SET_IO;
1589*4882a593Smuzhiyun 
1590*4882a593Smuzhiyun 	ret = pcmcia_loop_config(link, nsp_cs_config_check, data);
1591*4882a593Smuzhiyun 	if (ret)
1592*4882a593Smuzhiyun 		goto cs_failed;
1593*4882a593Smuzhiyun 
1594*4882a593Smuzhiyun 	if (pcmcia_request_irq(link, nspintr))
1595*4882a593Smuzhiyun 		goto cs_failed;
1596*4882a593Smuzhiyun 
1597*4882a593Smuzhiyun 	ret = pcmcia_enable_device(link);
1598*4882a593Smuzhiyun 	if (ret)
1599*4882a593Smuzhiyun 		goto cs_failed;
1600*4882a593Smuzhiyun 
1601*4882a593Smuzhiyun 	if (free_ports) {
1602*4882a593Smuzhiyun 		if (link->resource[0]) {
1603*4882a593Smuzhiyun 			release_region(link->resource[0]->start,
1604*4882a593Smuzhiyun 					resource_size(link->resource[0]));
1605*4882a593Smuzhiyun 		}
1606*4882a593Smuzhiyun 		if (link->resource[1]) {
1607*4882a593Smuzhiyun 			release_region(link->resource[1]->start,
1608*4882a593Smuzhiyun 					resource_size(link->resource[1]));
1609*4882a593Smuzhiyun 		}
1610*4882a593Smuzhiyun 	}
1611*4882a593Smuzhiyun 
1612*4882a593Smuzhiyun 	/* Set port and IRQ */
1613*4882a593Smuzhiyun 	data->BaseAddress = link->resource[0]->start;
1614*4882a593Smuzhiyun 	data->NumAddress  = resource_size(link->resource[0]);
1615*4882a593Smuzhiyun 	data->IrqNumber   = link->irq;
1616*4882a593Smuzhiyun 
1617*4882a593Smuzhiyun 	nsp_dbg(NSP_DEBUG_INIT, "I/O[0x%x+0x%x] IRQ %d",
1618*4882a593Smuzhiyun 		data->BaseAddress, data->NumAddress, data->IrqNumber);
1619*4882a593Smuzhiyun 
1620*4882a593Smuzhiyun 	if(nsphw_init(data) == FALSE) {
1621*4882a593Smuzhiyun 		goto cs_failed;
1622*4882a593Smuzhiyun 	}
1623*4882a593Smuzhiyun 
1624*4882a593Smuzhiyun 	host = nsp_detect(&nsp_driver_template);
1625*4882a593Smuzhiyun 
1626*4882a593Smuzhiyun 	if (host == NULL) {
1627*4882a593Smuzhiyun 		nsp_dbg(NSP_DEBUG_INIT, "detect failed");
1628*4882a593Smuzhiyun 		goto cs_failed;
1629*4882a593Smuzhiyun 	}
1630*4882a593Smuzhiyun 
1631*4882a593Smuzhiyun 
1632*4882a593Smuzhiyun 	ret = scsi_add_host (host, NULL);
1633*4882a593Smuzhiyun 	if (ret)
1634*4882a593Smuzhiyun 		goto cs_failed;
1635*4882a593Smuzhiyun 
1636*4882a593Smuzhiyun 	scsi_scan_host(host);
1637*4882a593Smuzhiyun 
1638*4882a593Smuzhiyun 	info->host = host;
1639*4882a593Smuzhiyun 
1640*4882a593Smuzhiyun 	return 0;
1641*4882a593Smuzhiyun 
1642*4882a593Smuzhiyun  cs_failed:
1643*4882a593Smuzhiyun 	nsp_dbg(NSP_DEBUG_INIT, "config fail");
1644*4882a593Smuzhiyun 	nsp_cs_release(link);
1645*4882a593Smuzhiyun 
1646*4882a593Smuzhiyun 	return -ENODEV;
1647*4882a593Smuzhiyun } /* nsp_cs_config */
1648*4882a593Smuzhiyun 
1649*4882a593Smuzhiyun 
nsp_cs_release(struct pcmcia_device * link)1650*4882a593Smuzhiyun static void nsp_cs_release(struct pcmcia_device *link)
1651*4882a593Smuzhiyun {
1652*4882a593Smuzhiyun 	scsi_info_t *info = link->priv;
1653*4882a593Smuzhiyun 	nsp_hw_data *data = NULL;
1654*4882a593Smuzhiyun 
1655*4882a593Smuzhiyun 	if (info->host == NULL) {
1656*4882a593Smuzhiyun 		nsp_msg(KERN_DEBUG, "unexpected card release call.");
1657*4882a593Smuzhiyun 	} else {
1658*4882a593Smuzhiyun 		data = (nsp_hw_data *)info->host->hostdata;
1659*4882a593Smuzhiyun 	}
1660*4882a593Smuzhiyun 
1661*4882a593Smuzhiyun 	nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link);
1662*4882a593Smuzhiyun 
1663*4882a593Smuzhiyun 	/* Unlink the device chain */
1664*4882a593Smuzhiyun 	if (info->host != NULL) {
1665*4882a593Smuzhiyun 		scsi_remove_host(info->host);
1666*4882a593Smuzhiyun 	}
1667*4882a593Smuzhiyun 
1668*4882a593Smuzhiyun 	if (resource_size(link->resource[2])) {
1669*4882a593Smuzhiyun 		if (data != NULL) {
1670*4882a593Smuzhiyun 			iounmap((void *)(data->MmioAddress));
1671*4882a593Smuzhiyun 		}
1672*4882a593Smuzhiyun 	}
1673*4882a593Smuzhiyun 	pcmcia_disable_device(link);
1674*4882a593Smuzhiyun 
1675*4882a593Smuzhiyun 	if (info->host != NULL) {
1676*4882a593Smuzhiyun 		scsi_host_put(info->host);
1677*4882a593Smuzhiyun 	}
1678*4882a593Smuzhiyun } /* nsp_cs_release */
1679*4882a593Smuzhiyun 
nsp_cs_suspend(struct pcmcia_device * link)1680*4882a593Smuzhiyun static int nsp_cs_suspend(struct pcmcia_device *link)
1681*4882a593Smuzhiyun {
1682*4882a593Smuzhiyun 	scsi_info_t *info = link->priv;
1683*4882a593Smuzhiyun 	nsp_hw_data *data;
1684*4882a593Smuzhiyun 
1685*4882a593Smuzhiyun 	nsp_dbg(NSP_DEBUG_INIT, "event: suspend");
1686*4882a593Smuzhiyun 
1687*4882a593Smuzhiyun 	if (info->host != NULL) {
1688*4882a593Smuzhiyun 		nsp_msg(KERN_INFO, "clear SDTR status");
1689*4882a593Smuzhiyun 
1690*4882a593Smuzhiyun 		data = (nsp_hw_data *)info->host->hostdata;
1691*4882a593Smuzhiyun 
1692*4882a593Smuzhiyun 		nsphw_init_sync(data);
1693*4882a593Smuzhiyun 	}
1694*4882a593Smuzhiyun 
1695*4882a593Smuzhiyun 	info->stop = 1;
1696*4882a593Smuzhiyun 
1697*4882a593Smuzhiyun 	return 0;
1698*4882a593Smuzhiyun }
1699*4882a593Smuzhiyun 
nsp_cs_resume(struct pcmcia_device * link)1700*4882a593Smuzhiyun static int nsp_cs_resume(struct pcmcia_device *link)
1701*4882a593Smuzhiyun {
1702*4882a593Smuzhiyun 	scsi_info_t *info = link->priv;
1703*4882a593Smuzhiyun 	nsp_hw_data *data;
1704*4882a593Smuzhiyun 
1705*4882a593Smuzhiyun 	nsp_dbg(NSP_DEBUG_INIT, "event: resume");
1706*4882a593Smuzhiyun 
1707*4882a593Smuzhiyun 	info->stop = 0;
1708*4882a593Smuzhiyun 
1709*4882a593Smuzhiyun 	if (info->host != NULL) {
1710*4882a593Smuzhiyun 		nsp_msg(KERN_INFO, "reset host and bus");
1711*4882a593Smuzhiyun 
1712*4882a593Smuzhiyun 		data = (nsp_hw_data *)info->host->hostdata;
1713*4882a593Smuzhiyun 
1714*4882a593Smuzhiyun 		nsphw_init   (data);
1715*4882a593Smuzhiyun 		nsp_bus_reset(data);
1716*4882a593Smuzhiyun 	}
1717*4882a593Smuzhiyun 
1718*4882a593Smuzhiyun 	return 0;
1719*4882a593Smuzhiyun }
1720*4882a593Smuzhiyun 
1721*4882a593Smuzhiyun /*======================================================================*
1722*4882a593Smuzhiyun  *	module entry point
1723*4882a593Smuzhiyun  *====================================================================*/
1724*4882a593Smuzhiyun static const struct pcmcia_device_id nsp_cs_ids[] = {
1725*4882a593Smuzhiyun 	PCMCIA_DEVICE_PROD_ID123("IO DATA", "CBSC16       ", "1", 0x547e66dc, 0x0d63a3fd, 0x51de003a),
1726*4882a593Smuzhiyun 	PCMCIA_DEVICE_PROD_ID123("KME    ", "SCSI-CARD-001", "1", 0x534c02bc, 0x52008408, 0x51de003a),
1727*4882a593Smuzhiyun 	PCMCIA_DEVICE_PROD_ID123("KME    ", "SCSI-CARD-002", "1", 0x534c02bc, 0xcb09d5b2, 0x51de003a),
1728*4882a593Smuzhiyun 	PCMCIA_DEVICE_PROD_ID123("KME    ", "SCSI-CARD-003", "1", 0x534c02bc, 0xbc0ee524, 0x51de003a),
1729*4882a593Smuzhiyun 	PCMCIA_DEVICE_PROD_ID123("KME    ", "SCSI-CARD-004", "1", 0x534c02bc, 0x226a7087, 0x51de003a),
1730*4882a593Smuzhiyun 	PCMCIA_DEVICE_PROD_ID123("WBT", "NinjaSCSI-3", "R1.0", 0xc7ba805f, 0xfdc7c97d, 0x6973710e),
1731*4882a593Smuzhiyun 	PCMCIA_DEVICE_PROD_ID123("WORKBIT", "UltraNinja-16", "1", 0x28191418, 0xb70f4b09, 0x51de003a),
1732*4882a593Smuzhiyun 	PCMCIA_DEVICE_NULL
1733*4882a593Smuzhiyun };
1734*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pcmcia, nsp_cs_ids);
1735*4882a593Smuzhiyun 
1736*4882a593Smuzhiyun static struct pcmcia_driver nsp_driver = {
1737*4882a593Smuzhiyun 	.owner		= THIS_MODULE,
1738*4882a593Smuzhiyun 	.name		= "nsp_cs",
1739*4882a593Smuzhiyun 	.probe		= nsp_cs_probe,
1740*4882a593Smuzhiyun 	.remove		= nsp_cs_detach,
1741*4882a593Smuzhiyun 	.id_table	= nsp_cs_ids,
1742*4882a593Smuzhiyun 	.suspend	= nsp_cs_suspend,
1743*4882a593Smuzhiyun 	.resume		= nsp_cs_resume,
1744*4882a593Smuzhiyun };
1745*4882a593Smuzhiyun module_pcmcia_driver(nsp_driver);
1746*4882a593Smuzhiyun 
1747*4882a593Smuzhiyun /* end */
1748