/*======================================================================/

    This driver for the Ninja SCSI-3 card

    Ver.1.0.1 Kernel 2.3.99 support
	    yokota@netlab.is.tsukuba.ac.jp <横田 裕思>
    Ver.1.0 Support disk change.
	    yokota@netlab.is.tsukuba.ac.jp <横田 裕思>
    Ver.0.4 Support 32bit PIO mode.
	    yokota@netlab.is.tsukuba.ac.jp <横田 裕思>
    Ver 0.2.1 Header path name fix by
	    yokota@netlab.is.tsukuba.ac.jp <横田 裕思>
    Ver 0.2 Adapted for Linux 2.2.x and some fix by
	    y5t0964@students.chiba-u.ac.jp <横田 裕思>
    Ver 0.1 Original version from Workbit Corp.

    This driver referred some parts of following code.
     mps110_cs.c: qlogic pcmcia scsi driver
	 written by N.Katayama (kata-n@po.iijnet.or.jp)
    
    This software may be used and distributed according to the terms of
    the GNU Public License.
	
	Copyright (c) 1998 Qvision.
	All rights reserved.

======================================================================*/

/***********************************************************************
    This driver is for these PCcards.

	I/O data PCSC-F (Workbit NinjaSCSI-3)
			"WBT" "NinjaSCSI-3" "R1.0"
	I/O data CBSC-2 (Workbit NinjaSCSI-32Bi / 16Bit)
			"IO DATA", "CBSC16	 ", "1"

***********************************************************************/

/* $Id: nin_cs.c,v 1.22 2000/06/01 23:26:39 elca Exp $ */

#include <pcmcia/config.h>
#include <pcmcia/k_compat.h>

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/malloc.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/tqueue.h>
#include <linux/interrupt.h>

#include <linux/major.h>

#include BLK_DEV_HDR
#include <../drivers/scsi/scsi.h>
#include <../drivers/scsi/hosts.h>

#include <scsi/scsi.h>
#include <scsi/scsi_ioctl.h>

#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>

MODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>");
MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) SCSI host adapter module");

#ifdef PCMCIA_DEBUG
static int pc_debug = PCMCIA_DEBUG;
static char *version = "$Id: nin_cs.c,v 1.22 2000/06/01 23:26:39 elca Exp $";
#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
#else
#define DEBUG(n, args...)
#endif


/*====================================================================*/

typedef struct scsi_info_t {
	dev_link_t  link;
	int	    ndev;
	dev_node_t  node[8];
} scsi_info_t;

static void ninja3_release(u_long arg);
static int ninja3_event(event_t event, int priority,
			event_callback_args_t *args);

static dev_link_t *ninja3_attach(void);
static void ninja3_detach(dev_link_t *);

static void ninja3_interrupt(void *);
#ifdef USE_IRQ_HANDLE_PRESENT
static void ninja3_interrupt2(int irq,void *dev_id,struct pt_regs *regs);
#endif


/*----------------------------------------------------------------*/
#include <linux/module.h>
#include <linux/blk.h>	/* to get disk capacity */

#include <asm/io.h>
#include <asm/irq.h>
#include <../drivers/scsi/sd.h>
#include <linux/stat.h>

#include "nin_cs.h"

#if KERNEL_VERSION(2,3,99) > LINUX_VERSION_CODE
/* PROC_SCSI_SCSI = proc_fs.h*/
static struct proc_dir_entry proc_scsi_ninja3 = {
    PROC_SCSI_SCSI, 6, "nin_cs",
    S_IFDIR | S_IRUGO | S_IXUGO, 2
};
#endif

/*====================================================================*/
/* Parameters that can be set with 'insmod' */
/* Bit map of interrupts to choose from */
/* This driver never use IRQ */ 
static u_long irq_mask = 0xfff0;
MODULE_PARM(irq_mask,"h");

/* ns3 transfer mode */
/*
 *  0 = IO8
 *  1 = IO32 (defalt)
 */
#define IO8MODE	 0
#define IO32MODE 1
static int ns3mode = IO32MODE;
MODULE_PARM(ns3mode, "0-1i");


/*----------------------------------------------------------------*/
static int Owattayo = 1;	/* 0713 ORESAMA atode*/ 

/*----------------------------------------------------------------*/
/* driver state info, local to driver */
static int	    ns3abort;	     /* Flag to cause an abort */
static char	    ns3info[100];     /* description */

/*include/linux/tqueue.h(42): struct tq_struct*/
#ifndef USE_IRQ_HANDLE_PRESENT
/* task queue entry */
static struct tq_struct ns3_tq = {
	NULL, 0, ninja3_interrupt, NULL
};
#endif
static int ninja3_detect(Scsi_Host_Template * );
static const char * ninja3_info(struct Scsi_Host *);
static int ninja3_command(Scsi_Cmnd *);
static int ninja3_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
static int ninja3_abort(Scsi_Cmnd *);
static int ninja3_reset(Scsi_Cmnd *, unsigned int);
static int ninja3_biosparam(Disk * , kdev_t, int []);

/* /usr/src/linux/drivers/scsi/hosts.h */
#define NINJA3 {					\
/*	next:			NULL,*/			\
/*	proc_dir:		NULL,*/				\
/*	proc_info:		NULL,*/				\
	name:			"WorkBit NinjaSCSI-3/32Bi", \
	detect:			ninja3_detect,		\
/*	release:		NULL,*/			\
	info:			ninja3_info,		\
	command:		ninja3_command,		\
	queuecommand:		ninja3_queuecommand,	\
/*	eh_strategy_handler:	ninjs3_eh_strategy,*/	\
/*	eh_abort_handler:	ninja3_eh_abort,*/	\
/*	eh_device_reset_handler: ninja3_eh_device_reset,*/	\
/*	eh_bus_reset_handler:	ninja3_eh_bus_reset,*/	\
/*	eh_host_reset_handler:	ninja3_eh_host_reset,*/	\
	abort:			ninja3_abort,		\
	reset:			ninja3_reset,		\
/*	slave_attach:		NULL,*/			\
	bios_param:		ninja3_biosparam,	\
	can_queue:		1,			\
	this_id:		-1,			\
	sg_tablesize:		SG_NONE,			\
	cmd_per_lun:		1,			\
/*	present:		0,*/			\
/*	unchecked_isa_dma:	0,*/			\
	use_clustering:		DISABLE_CLUSTERING,	\
	use_new_eh_code:	0,			\
/*	emulated:		0,*/			\
}

static Scsi_Host_Template driver_template = NINJA3;


static dev_link_t *dev_list = NULL;
static dev_info_t dev_info = "nin_cs";

#ifdef USE_SLEEP_WAKE
static struct wait_queue *read_wait = NULL;
#endif /* USE_SLEEP_WAKE */


/***********************************************************/

static PSPECIFIC_LU_EXTENSION table[7][10];
static nin_softc nin_data = {
	BaseAddress: 0,
	IrqNumber: -1,
	HostId: -1,
};

static PSPECIFIC_LU_EXTENSION
ScsiPortGetLogicalUnit(unsigned char TargetId,unsigned char Lun)
{
	if (!table[TargetId][Lun]) {
		table[TargetId][Lun] = 
			kmalloc(sizeof(SPECIFIC_LU_EXTENSION),GFP_BUFFER);
	}
	return table[TargetId][Lun];
}

static void ScsiPortFreeLogicalUnit(unsigned char TargetId,unsigned char Lun)
{
	if (table[TargetId][Lun]) {
		kfree(table[TargetId][Lun]);
		table[TargetId][Lun] = 0;
	}
}

static u_char Ns3FifoTest(IN PFIFO_TEST pTestMode)
{
	TRANSFER_MODE saveMode = {
		TransferGo:	 1,
		FifoTest_Braind: 0,
		MemMap8:	 0,
		AdrData24:	 0,
		MemMap16_32:	 0,
		IO8:		 0,
		IO16_32:	 0,
	};

	switch(ns3mode) {
	case IO32MODE:
		saveMode.IO16_32 = 1;
		break;
	case IO8MODE:
	default:
		saveMode.IO8 = 1;
		break;
	}

	return (*((u_char *)(&saveMode))); /* u_char 型に直して返す */
}


static void Ns3ResetScsiBus( pnin_softc DevExt )
{
	PSPECIFIC_TARGET_EXTENSION targetState;
	u_long i;
	unsigned long	flags;

	u_char dataByte;
	int    baseAddress = DevExt->BaseAddress;

	save_flags( flags );
	cli();

	if (DevExt->DmaPending == TRUE) {
		DevExt->DmaPending = FALSE;
	}
	DevExt->InterruptPending = FALSE;
	/**/
	SCSI_IRQ_CONTROL(baseAddress, 0xff);  /* IRQ all Mssk & clear */

	/*
	// RESET SCSI bus.
	//
	*/
	dataByte = 0;
	((PSCSI_BUS_CONTROL)&dataByte)->ScsiRst = 1;
	SCSI_WRITE(baseAddress, SCSIBUSCTRL, dataByte);	/* SCSI RST On! */

	udelay(RESET_HOLD_TIME);

	((PSCSI_BUS_CONTROL)&dataByte)->ScsiRst = 0;
	SCSI_WRITE(baseAddress, SCSIBUSCTRL, dataByte);	/* SCSI RST Off! */

	/* dummy read for SCSI RST IRQ/Phase Change */
	for ( i= 0; i < 5; i++) {
		SCSI_READ(baseAddress,IRQPHASESENCE);
	}

	/* Set unsyncronus 5MB*/
	for (i = 0; i < 7; i++) {
		targetState = &DevExt->TargetState[i];	/* Get pointer */
		targetState->TargetFlags &= ~PD_SYNCHRONOUS_NEGOTIATION_DONE;
		targetState->SynchronousOffset = ASYNCHRONOUS_OFFSET;
		targetState->SynchronousPeriod = ASYNCHRONOUS_PERIOD;
	}
#ifdef USE_IRQ_MASK
	SCSI_IRQ_CONTROL(baseAddress, 0xff);	/* IRQ mask & clear*/
	DevExt->IrqMaskData = 0xff;
#else
	SCSI_IRQ_CONTROL(baseAddress, 0x0f);	/* IRQ mask & clear*/
	DevExt->IrqMaskData = 0x0f;
#endif /* USE_IRQ_MASK */

	udelay(RESET_RECOVER_TIME);
	restore_flags(flags);
}

/*----------------------------------------------------------------*/
/* global functions						  */
/*----------------------------------------------------------------*/

static int ninja3_precommand(PSPECIFIC_LU_EXTENSION *luExt,
			     pnin_softc devExt,
			     Scsi_Cmnd * Srb)
{
	Ns3DebugPrint(0x10,(KERN_DEBUG __FUNCTION__ "\n"));

	sti();
	/*
	 * Determine the logical unit that this request is for.
	 */
	ns3abort = 0;
	(*luExt) = ScsiPortGetLogicalUnit(Srb->target, Srb->lun);
	if( !(*luExt) ) {
		Srb->result = DID_ERROR << 16;
		return FALSE;
	}

	/* fuckin cable is too heat...*/
	/*
	if ( !devExt->ScsiCable ) {
		Srb->SrbStatus = SRB_STATUS_SELECTION_TIMEOUT;
		ScsiPortNotification(RequestComplete,(void *) devExt,Srb);
		ScsiPortNotification(NextRequest,devExt,NULL);
		break;
	}
	*/

	/*
	** Setup the context for this target/lun.
	*/

	(*luExt)->ActiveCommand = Srb;
	(*luExt)->SavedDataPointer = Srb->request_buffer;
	(*luExt)->SavedDataLength = Srb->request_bufflen;

	(*luExt)->PhaseWaitCounter = 0;
	devExt->ScsiState = SC_SELECT;

	return TRUE;
} /*ninja3_precommand end*/

static int ninja3_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
{
	PSPECIFIC_LU_EXTENSION luExtension;
	pnin_softc DevExt = &nin_data;
	unsigned long flags;

	Ns3DebugPrint(0x10,(KERN_DEBUG __FUNCTION__ " target=%d cmnd=0x%02x use_sg=%d size=%u owattayo=%d\n",
			    SCpnt->target, SCpnt->cmnd[0], SCpnt->use_sg, SCpnt->request_bufflen, Owattayo));
#ifdef DBG_SHOWCOMMAND
	show_command(SCpnt);
#endif

/*    sti();*/

	if( !Owattayo ) {
		Ns3DebugPrint(0x10,(KERN_DEBUG __FUNCTION__ "Owattayo\n"));
		SCpnt->result = DID_OK << 16;
		done(SCpnt);
		return 0;
	}

	if( SCpnt->target == DevExt->HostId ) {
		Ns3DebugPrint(0x10,(KERN_DEBUG __FUNCTION__ " target and host are same id\n"));
		SCpnt->result = DID_BAD_TARGET << 16;
		done(SCpnt);
		return 0;
	}

	SCpnt->scsi_done = done;

	if( !ninja3_precommand(&luExtension,DevExt,SCpnt) ) {
		Ns3DebugPrint(0x10,(KERN_DEBUG __FUNCTION__ "precmd fail\n"));
		return 0;	/* error */
	}

	Ns3StartExecution(DevExt, luExtension, SCpnt);

#ifndef USE_SELECTSAVEFLAG
	save_flags(flags);
	cli();
#endif /* USE_SELECTSAVEFLAG */

	Ns3Select(DevExt,SCpnt);


#ifdef USE_IRQ_MASK /* 0704 */
	((PIRQ_CONTROLP)&DevExt->IrqMaskData)->TimerIrqMask = 1; /* Timer IRQ Enable*/
	((PIRQ_CONTROLP)&DevExt->IrqMaskData)->ScsiIrqMask = 0;	 /* SCSI IRQ Enable*/
	SCSI_IRQ_CONTROL(DevExt->BaseAddress, DevExt->IrqMaskData);
#endif /* USE_IRQ_MASK */

#ifndef USE_SELECTSAVEFLAG
	restore_flags(flags);
#endif /* USE_SELECTSAVEFLAG */

#ifndef USE_IRQ_HANDLE_PRESENT
	queue_task(&ns3_tq,&tq_scheduler);
#endif

	Ns3DebugPrint(0x10,(KERN_DEBUG __FUNCTION__ " end\n"));

	return 0;
}

/* from aha1542.c */
static void internal_done(Scsi_Cmnd *SCpnt )
{
	SCpnt->SCp.Status++;
}

static int ninja3_command(Scsi_Cmnd * SCpnt)
{
	Ns3DebugPrint(0x10,(KERN_DEBUG __FUNCTION__ "\n"));

	ninja3_queuecommand(SCpnt, internal_done);

	SCpnt->SCp.Status = 0;
	while (!SCpnt->SCp.Status)
		barrier();
	return SCpnt->result;
}

/*
//-----------------------------------------------------------------------
// Routine Name:
//
//    Ns3StartExecution
//
// Routine Description:
// 
//    This routine will start the execution of a SCSI request.
// 
// Arguments:
// 
//    DevExt -	 Device adapter context pointer.
//    LuExtension -	  The logical unit specific information.
//    Srb -		  The Srb command to execute.
// 
// Return Value:
// 
//    None.
// 
//-----------------------------------------------------------------------
*/
static void Ns3StartExecution(IN pnin_softc		  DevExt,
			      IN PSPECIFIC_LU_EXTENSION LuExtension,
			      IN Scsi_Cmnd		  *Srb )
{
	PSPECIFIC_TARGET_EXTENSION targetState;

	if ((Srb->cmnd[1] >> 5) != Srb->lun) {
		Srb->cmnd[1] &= 0x1f;
		Srb->cmnd[1] |= (Srb->lun << 5);
	}

	DevExt->TargetId = Srb->target;

	/*
	  Setup the context for this adapter.
	*/
	DevExt->ActiveUnit = LuExtension;
	DevExt->CurDataPointer = DevExt->ActiveUnit->SavedDataPointer;
	DevExt->CurDataLength =	 DevExt->ActiveUnit->SavedDataLength;

	/* Set TargetState Ns3MessageDecode */
	DevExt->TargetId = Srb->target;
	targetState = &DevExt->TargetState[Srb->target];

	/*
	//
	// Create the identify command.
	//
	*/	
/* #define MSG_IDENTIFY(lun)	   (0xc0 | ((lun) & 0x7)) */

	/* DevExt->AdapterOption = OPT_NON_DISCONECT;	 0605	*/
	/* NOT supported DISCONECT */
	if ((DevExt->AdapterOption & OPT_NON_DISCONECT)) {
		DevExt->MessageBuffer[0] = MSG_IDENTIFYFLAG | Srb->lun;
	} else {
		DevExt->MessageBuffer[0] = MSG_IDENTIFYFLAG_WITH_DISCON | Srb->lun;
	}
	DevExt->MessageCount = 1;

	/*
	 * Make SyncMessage if don't Sync Nego
	 */
/* #define INQUIRY			0x12	 scsi_all.h */

	if (!(targetState->TargetFlags & PD_SYNCHRONOUS_NEGOTIATION_DONE ) &&
	    !(targetState->TargetFlags & PD_DO_NOT_NEGOTIATE) &&
	    (Srb->cmnd[0] != INQUIRY)	/* INQUIRY:Don't Sync Nego */
		)
	{
		/* Sync message exchange [sync]*/
		DevExt->MessageCount = 6;
		/* extended message out */
		DevExt->MessageBuffer[1] = MSG_EXTENDED;		

		/* length */
		DevExt->MessageBuffer[2] = MSG_EXT_SDTR_LEN;		

		/* extended message out command */
		DevExt->MessageBuffer[3] = SCSIMESS_SYNCHRONOUS_DATA_REQ;

#ifdef ULTRA
		DevExt->MessageBuffer[4] = DevExt->SynchronousPeriod;
#else
		/* Transfer interval 100n = 10M ByteS */
		DevExt->MessageBuffer[4] = SYNCHRONOUS_PERIOD;		
#endif
		DevExt->MessageBuffer[5] = SYNCHRONOUS_OFFSET;
		targetState->TargetFlags |= PD_SYNCHRONOUS_NEGOTIATION_DONE | 
						PD_SYNCHRONOUS_TRANSFER_SENT;

		DevExt->MessageCount = 1;	/* ORESAMA 0629 */
	}

} /* end Ns3StartExecution()*/

#if 0
/*
//-----------------------------------------------------------------------
// Routine Name:
//
//    Ns3IrqPolling
//
// Routine Description:
// 
//    Interrupt Polling
// 
///
//-----------------------------------------------------------------------*/
static void Ns3IrqPolling(void)
{
	pnin_softc DevExt = &nin_data;
	int i;

	i = INT_POLL_SEL;

	while (i > 0 ) {
		if(Owattayo) {	/* 0704 */
			break;
		}

		if ( SCSI_IRQ_MONITOR(DevExt->BaseAddress) & 0xb ) { /* 0706 */
			ninintr();
			break;
		}
		/* loop interval 530CS-133MHz : 4.5us */
		udelay(5);	/* udelay -> udelay */

		i--;
	}

#ifdef USE_IRQ_MASK
	((PIRQ_CONTROLP)&DevExt->IrqMaskData)->TimerIrqMask = 1; /* Timer IRQ Enable*/
	((PIRQ_CONTROLP)&DevExt->IrqMaskData)->ScsiIrqMask = 0;	 /* SCSI IRQ Enable*/
	SCSI_IRQ_CONTROL(DevExt->BaseAddress, DevExt->IrqMaskData);
#endif /* USE_IRQ_MASK */

}
#endif

/*
//-----------------------------------------------------------------------
// Routine Name:
//
//    ninintr
//
// Routine Description:
// 
//    This routine handles the interrupts for the Ns3.	The intention is to
//    quickly determine the cause of the interrupt, clear the interrupt, and
//    setup to process the SCSI command that is affected by the
//    interrupt.
// 
// Arguments:
// 
//    Context - Device adapter context pointer.
// 
// Return Value:
// 
//    TRUE indicates that the interrupt was from this Ns3 adapter,
//    FALSE indicates that this interrupt was NOT from us.
// 
//-----------------------------------------------------------------------
// boolean -> void
*/
static void ninintr(void)
{
	long i;
	pnin_softc DevExt = &nin_data;
	int baseAddress = DevExt->BaseAddress;


	IRQ_STATUS	IntIrqStatus;
	IRQ_PHASE_SENSE IntIrqPhase;

	unsigned char	dataByte;
	char		TargetId;
	PSPECIFIC_TARGET_EXTENSION targetState;

	/*Ns3DebugPrint(0x10,(KERN_DEBUG __FUNCTION__ "\n"));*/

	*((unsigned char *) &IntIrqStatus) = SCSI_IRQ_MONITOR(baseAddress);

	dataByte = 0;
#ifdef USE_IRQ_MASK
	((PIRQ_CONTROLP)&dataByte)->ExtIrqMask = 1;
	((PIRQ_CONTROLP)&dataByte)->FifoIrqMask = 1;
	((PIRQ_CONTROLP)&dataByte)->TimerIrqMask = 1;
	((PIRQ_CONTROLP)&dataByte)->ScsiIrqMask = 1;
#endif /* USE_IRQ_MASK */
	SCSI_IRQ_CONTROL(baseAddress, dataByte); /* IRQ All mask */

IntEntry:
	/* from nin_unload */

	if ( *((unsigned char *) &IntIrqStatus) == 0xff ) {
		DevExt->ScsiState = SC_BUSFREE;
		DevExt->IntWait = FALSE;
		Ns3NotifyCompletion(DevExt, DID_ERROR);
		return;
	}

	DevExt->InterruptPending = FALSE;

	/*
	// --- Timer interrupt? ---
	*/
	if ( IntIrqStatus.TimerIrqStatus ) {
		dataByte = 0xf0;
		((PIRQ_CONTROLP)&dataByte)->TimerIrqClear = 1;
		/* Timer IRQ Clear*/
		SCSI_IRQ_CONTROL(DevExt->BaseAddress, dataByte);

		if ( DevExt->TimerCount != 0 ) {
			/* Next TIMER START*/
			SCSI_WRITE(DevExt->BaseAddress, TIMERCOUNT, DevExt->TimerCycle);
			DevExt->TimerCount--;
		}
	}

	/*
	// ---- SCSI IRQ ? ----
	*/
	if ( IntIrqStatus.ScsiIrqStatus ) {
		*((unsigned char *)&IntIrqPhase) = SCSI_READ(baseAddress, IRQPHASESENCE);

		/*
		//---- ReSelection IRQ ? ----
		*/
		if (IntIrqPhase.ReselectIrq) {
			TargetId =(unsigned char)(SCSI_READ(baseAddress, RESELECTID) & 0x7f);
			i = 0xffffffff;
			while ( TargetId > 0 ) {
				i++;
				TargetId >>= 1;
			}

			DevExt->TargetId = i;
			DevExt->TargetLun = DevExt->ActiveUnit->ActiveCommand->lun;
			do {
				dataByte = SCSI_READ(baseAddress, SCSIBUSMON);
			} while ( ((PSCSI_BUS_MONITOR)&dataByte)-> Scsi_SEL ); 
			/* SEL off ?*/

			dataByte = SCSI_READ(baseAddress, SCSIBUSCTRL);
			((PSCSI_BUS_CONTROL)&dataByte)->ScsiBSY = 0; /* BUSY Off !*/
			SCSI_WRITE(baseAddress , SCSIBUSCTRL, dataByte);
			((PSCSI_BUS_CONTROL)&dataByte)->AutoDirection = 1;
			/* AckEnb , AutoDirection ON !*/
			((PSCSI_BUS_CONTROL)&dataByte)->AckEnb = 1;
			/* ( Not same time in BUSY off)*/
			SCSI_WRITE(baseAddress, SCSIBUSCTRL, dataByte);

			/* set Sync-parameter*/
			targetState = &DevExt->TargetState[DevExt->TargetId];
			dataByte = 0;
			((PSYNC_REG)&dataByte)->SyncPeriod = targetState->SynchronousPeriod;
			((PSYNC_REG)&dataByte)->SyncOffset = targetState->SynchronousOffset;

			SCSI_WRITE(baseAddress, SYNCREG, dataByte);
			SCSI_WRITE(baseAddress, ACKWIDTH, targetState->AckWidth);

			/* Clear transfer clear*/
			dataByte = 0;
			((PPOINTER_CLEAR)&dataByte)->PointerClear = 1;
			((PPOINTER_CLEAR)&dataByte)->AckCounterClear = 1;
			((PPOINTER_CLEAR)&dataByte)->ReqCounterClear = 1;
			((PPOINTER_CLEAR)&dataByte)->HostCounterClear = 1;
			SCSI_WRITE(baseAddress, POINTERCLR, dataByte);

			/* LUN isn't defined, not use LunExtension... 
			   wait for Message IN */
			DevExt->ScsiState = SC_RESELECT;
			goto IntEnd;
		}

		/*
		  --- SCSI RESET Irq ?----
		*/
		if ( IntIrqPhase.ScsiResetIrq ) {
			/* Set unsync 5mb */
			for (i = 0; i < 7; i++) {
				targetState = &DevExt->TargetState[i];
				targetState->TargetFlags &= ~PD_SYNCHRONOUS_NEGOTIATION_DONE;
				targetState->SynchronousOffset = ASYNCHRONOUS_OFFSET;
				targetState->SynchronousPeriod = ASYNCHRONOUS_PERIOD;
			}
			goto IntEnd;
		}

		/*
		  --- Phase Change Interrupt  ? ---
		*/
		if ( IntIrqPhase.PhaseChgIrq ) {
			Ns3RunPhase(DevExt, IntIrqPhase );
			goto IntEnd;
		}
	}

	/*
	  ---- FIFO Interrupt  ? ----
	*/
	if ( IntIrqStatus.FifoIrqStatus ) {
		/* Interrupt Clear*/
		*((unsigned char *) &IntIrqPhase) = SCSI_READ(baseAddress, IRQPHASESENCE);
		/* まだ残りがあるか? */
		if ( DevExt->CurDataLength ) {
			/* before Phase*/
			if ( DevExt->ScsiPrePhase == BP_DATA_IN)
				Ns3DataInPhase(DevExt);
			else if (DevExt->ScsiPrePhase == BP_DATA_OUT)
				Ns3DataOutPhase(DevExt);
		}
		/* PhaseChange same time に発生 ?*/
		if ( IntIrqPhase.PhaseChgIrq ) {
			Ns3RunPhase(DevExt, IntIrqPhase );
		}
		goto IntEnd;
	}

IntEnd:
#ifdef USE_INTENTRY
	if ( !DevExt->IntWait ) {
		*((unsigned char *) &IntIrqStatus) = SCSI_IRQ_MONITOR(baseAddress);
		if ( *((unsigned char *)&IntIrqStatus) & 0xf ) {
			goto IntEntry;/* INT */
			/* l.434 */
		}
	} else {
		int polltimes;
#ifdef USE_WRITE_SPECIAL
		if(DevExt->ActiveUnit->ActiveCommand->cmnd[0] == 0x0a) { /* 0x0a = Linked Cmmand Complete */
			/* 10000 -> 100 ORESAMA 0703 */
			polltimes = INT_POLL_IRQ * 100;
		} else {
			polltimes = INT_POLL_IRQ;
		}
#else
		polltimes = INT_POLL_IRQ;
#endif /* USE_WRITE_SPECIAL */
		for ( i = 0; i< polltimes; i++) {
			*((unsigned char *)&IntIrqStatus) = SCSI_IRQ_MONITOR(baseAddress);
			if ( *((unsigned char *)&IntIrqStatus) & 0x0f ) {
				goto IntEntry;/* INT */
				/* l.434 */
			}
			udelay(5);
		}
	}
#endif /* USE_INTENTRY */

	/*
	  --- Reverse IRQ MASK MODE ----
	*/
#ifdef USE_IRQ_MASK
	SCSI_IRQ_CONTROL(baseAddress, DevExt->IrqMaskData);
#endif /* USE_IRQ_MASK */
	DevExt->IntWait = TRUE;

	return ;	/* TRUE;*/
} /* end ninintr()*/


/*
//-----------------------------------------------------------------------
// Routine Name:
//
//    Ns3Select
//
// Routine Description:
// 
//    Perform selection process on SCSI bus.
// 
// Arguments:
// 
//    DevExt - Device adapter context pointer.
// 
// Return Value:
// 
//    TRUE : Select Success
///
//-----------------------------------------------------------------------
*/
static boolean Ns3Select( IN pnin_softc DevExt ,Scsi_Cmnd *srb)
{
	PSPECIFIC_TARGET_EXTENSION targetState;

	int  baseAddress = DevExt->BaseAddress;
	unsigned char	cdbLength = COMMAND_SIZE(srb->cmnd[0]);/*srb->cmdlen;*/
	unsigned char	*cdb = srb->cmnd;      /*srb->cmd->bytes;  srb->cmd;*/
	unsigned char	BusyByte, dataByte, AtnByte;
#ifdef USE_SELECTSAVEFLAG
	unsigned long flags;
#endif /* USE_SELECTSAVEFLAG */

	Ns3DebugPrint(0x10,(KERN_DEBUG __FUNCTION__ "\n"));

	AtnByte = 0;
	((PSCSI_BUS_CONTROL)&AtnByte)->ScsiATN = 1;
	if ( DevExt->AdapterOption & OPT_NO_ATN ) {
		Ns3DebugPrint(0x10,(KERN_DEBUG "noATN\n"));
		((PSCSI_BUS_CONTROL)&AtnByte)->ScsiATN = 0;
	}

#ifdef USE_SELECTSAVEFLAG
	save_flags(flags);
	cli();
#endif /* USE_SELECTSAVEFLAG */
	/*
	  --- Didable all interrupt
	*/
	dataByte = 0;
#ifdef USE_IRQ_MASK
	((PIRQ_CONTROLP)&dataByte)->FifoIrqMask = 1;
	((PIRQ_CONTROLP)&dataByte)->TimerIrqMask = 1;
	((PIRQ_CONTROLP)&dataByte)->ExtIrqMask = 1;
	((PIRQ_CONTROLP)&dataByte)->ScsiIrqMask = 1;
	SCSI_IRQ_CONTROL(baseAddress, dataByte);
#endif /*  USE_IRQ_MASK */

	DevExt->IrqMaskData = dataByte;

	/*
	   --- CDB -> COMMAND FIFO --- INITIATOR -> target
	*/
	dataByte = 0;
	((PCOMMAND_CONTROL)&dataByte)->ClrCommandPointer = 1;
	SCSI_WRITE(baseAddress,COMMANDCTRL, dataByte);	/* CDB FIFO counter Clear*/
	/* cdb <- srb <- DevExt->ActiveUnit->ActiveCommand;*/
#ifdef DBG_SHOWCOMMAND
	show_command(srb);
#endif /* DBG_SHOWCOMMAND */

	/* cdbLength--;	 cdbLength - 1 */
	/*Ns3DebugPrint(0x10,(KERN_DEBUG "COMMAND "));*/
	while (cdbLength > 0) {
		/*Ns3DebugPrint(0x10,("[%01x]",*cdb));*/
		SCSI_WRITE(baseAddress, COMMANDDATA, *cdb++);
		cdbLength--;
	}
	/*Ns3DebugPrint(0x10,("\n"));*/

	Owattayo = 0;

	/*
	  --- Start Arbitration for Get Bus---
	*/
	dataByte = 0;
	((PSET_ARBIT)&dataByte)->ArbitGo = 1;
	SCSI_WRITE(baseAddress, SETARBIT, dataByte);	/* Start Arbitration */
	Ns3DebugPrint(0x10,(KERN_DEBUG "-- Start Arbitration --\n"));

	dataByte = 0;
	while (!( ((PARBIT_STATUS)&dataByte)->ArbitWin ||
		  ((PARBIT_STATUS)&dataByte)->ArbitFail ) ) {
		dataByte = SCSI_READ(baseAddress, ARBITSTATUS);	/* Get bus? */
	}


	if ( ((PARBIT_STATUS)&dataByte)->ArbitFail ) {	/* ...I'm looser */
		dataByte = 0;
		((PSET_ARBIT)&dataByte)->ArbitFlagClear = 1;
		SCSI_WRITE(baseAddress, SETARBIT, dataByte);/* Arbitration flg Clear*/

		DevExt->ScsiState = SC_BUSFREE;
		srb->result = DID_TIME_OUT <<16;
		Ns3NotifyCompletion(DevExt, DID_NO_CONNECT);

#ifdef USE_IRQ_MASK
		((PIRQ_CONTROLP)&DevExt->IrqMaskData)->TimerIrqMask = 0; /* Timer IRQ Enable*/
		((PIRQ_CONTROLP)&DevExt->IrqMaskData)->ScsiIrqMask = 0;	 /* SCSI IRQ Enable*/
		SCSI_IRQ_CONTROL(baseAddress, DevExt->IrqMaskData);
#endif /* USE_IRQ_MASK */

#ifdef USE_SELECTSAVEFLAG
		restore_flags(flags);
#endif /* USE_SELECTSAVEFLAG */
		return(FALSE);
	}

	/* Win !*/
	udelay(2);

	/*-----	 selection phase -----*/
	dataByte = (1 << SCSI_INITIATOR_ID) | (1 << (srb->target));
	/* set initiator ID + target ID */
	SCSI_WRITE(baseAddress, SCSIDATALATCH, dataByte);

	dataByte = 0;
	((PSCSI_BUS_CONTROL)&dataByte)->ScsiSel = 1;
	((PSCSI_BUS_CONTROL)&dataByte)->ScsiBSY = 1;
	dataByte |= AtnByte;
	SCSI_WRITE(baseAddress,SCSIBUSCTRL, dataByte);/* put SEL + Busy + ATN*/

	udelay(2); /*DELEY ScsiPortStallExecution(1); wait 1.2us*/

	((PSCSI_BUS_CONTROL)&dataByte)->ScsiDataOutEnb = 1;
	SCSI_WRITE(baseAddress,SCSIBUSCTRL , dataByte);	/* enable ID out */

	dataByte = 0;
	((PSET_ARBIT)&dataByte)->ArbitFlagClear = 1;
	SCSI_WRITE(baseAddress, SETARBIT, dataByte);/* Arbitration flag Clear*/

	dataByte = 0;
	((PSCSI_BUS_CONTROL)&dataByte)->ScsiSel = 1;
	dataByte |= AtnByte;
	((PSCSI_BUS_CONTROL)&dataByte)->ScsiDataOutEnb = 1;
	SCSI_WRITE(baseAddress,SCSIBUSCTRL, dataByte);	 /*  Busy off*/

	DevExt->TimerCount = 250;
	DevExt->TimerCycle = 1000/51;
	SCSI_WRITE(baseAddress, TIMERCOUNT, 1000/51);	 /* 1msec TIMER START*/

	do {
		BusyByte = SCSI_READ(baseAddress, SCSIBUSMON);
		if ( ((PSCSI_BUS_MONITOR)&BusyByte)->Scsi_BSY ) { /*? (busy)*/
			break;
		}

		dataByte = SCSI_IRQ_MONITOR(baseAddress);
		if ( ((PIRQ_STATUS)&dataByte)->TimerIrqStatus ) {
			SCSI_IRQ_CONTROL(baseAddress, dataByte);
			DevExt->TimerCount--;
			SCSI_WRITE(baseAddress, TIMERCOUNT, 1000/51);/* 1msec TIMER START*/
		}
	} while ( DevExt->TimerCount != 0 );

	dataByte = SCSI_IRQ_MONITOR(baseAddress) & 0xf0;
	((PIRQ_CONTROLP)&dataByte)->TimerIrqClear = 1;	/* Clear Timer IRQ*/
	SCSI_IRQ_CONTROL(baseAddress, dataByte);
	DevExt->TimerCount = 0;

	if ( ! (((PSCSI_BUS_MONITOR)&BusyByte)->Scsi_BSY) ) {
		/*
		  ----- None... -----
		*/
		SCSI_WRITE(baseAddress, SCSIBUSCTRL, 0);	/* SEL Off*/
		DevExt->ScsiState = SC_BUSFREE;
		Ns3NotifyCompletion(DevExt, DID_NO_CONNECT);

#ifdef USE_IRQ_MASK
		/* Timer IRQ Enable*/
		((PIRQ_CONTROLP)&DevExt->IrqMaskData)->TimerIrqMask = 0;
		/* SCSI IRQ Enable*/
		((PIRQ_CONTROLP)&DevExt->IrqMaskData)->ScsiIrqMask = 0;	
		SCSI_IRQ_CONTROL(baseAddress, DevExt->IrqMaskData);
#endif/* USE_IRQ_MASK */

#ifdef USE_SELECTSAVEFLAG
		  restore_flags(flags);
#endif /* USE_SELECTSAVEFLAG */
		  return(FALSE);
	}
	/*
	//--- Success Selection	 ---
	*/
	dataByte = 0;
	dataByte |= AtnByte;
	SCSI_WRITE(baseAddress,SCSIBUSCTRL, dataByte); /* SEL off */

	DevExt->TimerCount = 0;
	SCSI_WRITE(baseAddress, TIMERCOUNT, 0);	/* Timer stop9 */
	SCSI_WRITE(baseAddress, TIMERCOUNT, 0);	/* Timer stop needs 2times */

	/* AutoDirec / ACK Enable (Not same time in SEL off ...) */
	((PSCSI_BUS_CONTROL)&dataByte)->AutoDirection = 1;
	((PSCSI_BUS_CONTROL)&dataByte)->AckEnb = 1;
	SCSI_WRITE(baseAddress,SCSIBUSCTRL, dataByte);

	targetState = &DevExt->TargetState[srb->target];

	/* set sync parameter*/
	dataByte = 0;
	((PSYNC_REG)&dataByte)->SyncPeriod = targetState->SynchronousPeriod;
	((PSYNC_REG)&dataByte)->SyncOffset = targetState->SynchronousOffset;
	SCSI_WRITE(baseAddress, SYNCREG,dataByte);

	SCSI_WRITE(baseAddress, ACKWIDTH, targetState->AckWidth);

#ifdef MUST_USEIO8  /* 0630 */
	dataByte = DevExt->TransferMode;
	((PTRANSFER_MODE)&dataByte)->AdrData24 = 0;
	((PTRANSFER_MODE)&dataByte)->MemMap8 = 0;
	((PTRANSFER_MODE)&dataByte)->MemMap16_32 = 0;
	((PTRANSFER_MODE)&dataByte)->AdrData32 = 0;
	((PTRANSFER_MODE)&dataByte)->IO8 = 1;
	((PTRANSFER_MODE)&dataByte)->IO16_32 = 0;
#else
	Ns3SetTransferMode( DevExt );
#endif
	DevExt->ScsiState = SC_SELECT;

	/*
	  Adapter ready for next request.
	*/


	DevExt->IntWait = TRUE;
#ifdef USE_SELECTSAVEFLAG
	restore_flags(flags);
#endif /* USE_SELECTSAVEFLAG */
	return(TRUE);

} /* end Ns3Select()*/


static void ninja3_interrupt(void *unused)
{
	Scsi_Cmnd *cmd;
	pnin_softc DevExt = &nin_data;

	Ns3DebugPrint(0x10,(KERN_DEBUG __FUNCTION__ "\n"));

	cmd = DevExt->ActiveUnit->ActiveCommand; /* 0629 ?*/

	if( !cmd ) {
		return;
	}

	if( ns3abort ) {
		if( ns3abort == 1 ) {
			cmd->result = DID_ABORT << 16;
		} else {
			cmd->result = DID_RESET << 16;
		}
		cmd->scsi_done(cmd);
		DevExt->ActiveUnit->ActiveCommand = NULL;
		return;
	}
	ninintr();

#ifndef USE_IRQ_HANDLE_PRESENT
	if(!Owattayo) {
		queue_task(&ns3_tq,&tq_scheduler);
	}
#endif

	return;
}


static boolean Ns3Initialize(void)
{
	pnin_softc DevExt = &nin_data;

/*	PSPECIFIC_TARGET_EXTENSION targetState;*/
	u_long	i;	u_long FifoMax = 0x10000;
	u_char dataByte;
	TRANSFER_MODE	xferMode;
	int  baseAddress = DevExt->BaseAddress;
	u_char DefaultXfer = 0;
	int rev_reg;

#ifndef USE_DISCONECT
	DevExt->AdapterOption = OPT_NON_DISCONECT;
#endif /* USE_DISCONECT */


	/* Check Chip version */
	dataByte = 0;
	((PIF_SELECT)&dataByte)->RegSelect = 0;
	SCSI_IF_SELECT(baseAddress, dataByte); /* Chip revision Read set*/
	rev_reg = SCSI_FIFO_STATUS(baseAddress);
	Ns3DebugPrint(0x200, (KERN_DEBUG __FUNCTION__ "() rev_reg=0x%1x\n", rev_reg));
	DevExt->ChipID = ((PFIFO_STATUS)&rev_reg)->ChipId;
	DevExt->ChipRev = ((PFIFO_STATUS)&rev_reg)->ChipRev;


	FifoMax = 0x10000;


	/* Set default-trans-mode */
	*(u_char *)&xferMode = 0;
	switch (ns3mode) {
	case IO32MODE:
		xferMode.IO16_32 = 1;
		break;
	case IO8MODE:
	default:
		xferMode.IO8 = 1;
		break;
	}
	xferMode.TransferGo = 0;	/* disable HOST<->TARGET data transfer */
	xferMode.FifoTest_Braind = 0;	/* disable blined transfer mode */

	DevExt->SSEntry = 0;
	DevExt->TransferMode= *(u_char *)&xferMode;

	/* TransferModeSet & TEST MODE OFF */
	SCSI_WRITE(baseAddress, TRANSFERMODE, *(u_char *)&xferMode);

	/* 最初は確実な IO8 モードで通信 */
	DevExt->pXferRead  = pio8_datain;
	DevExt->pXferWrite = pio8_dataout;

	/* FindAdapter*/

	/* if hang-up any Phase and reset hen Busfree Interrupt*/
	SCSI_WRITE(baseAddress, SCSIIRQMODE, 0); /* SCSI IRQ ALL DISABLE*/
	SCSI_IRQ_CONTROL(baseAddress, 0xff);	/* IRQ all Mssk & clear */
#ifdef ULTRA
	SCSI_WRITE(baseAddress, CLOCKDIV , 2);	/* 40MHz */
#else
	SCSI_WRITE(baseAddress, CLOCKDIV , 1);	/* 20MHz */
#endif
	dataByte = 0;
	((PSCSI_IRQ_MODE)&dataByte)->ScsiResetIrqEi = 1;
	((PSCSI_IRQ_MODE)&dataByte)->FifoIrqEi= 0;   /* Disable FIFO IRQ*/
	((PSCSI_IRQ_MODE)&dataByte)->ReselectIrqEi = 1;
	((PSCSI_IRQ_MODE)&dataByte)->ScsiPhaseChangeEi = 1;
	SCSI_WRITE(baseAddress, SCSIIRQMODE, dataByte);

	SCSI_WRITE(baseAddress, PARITYCTRL , 0);     /* Parity Disable*/
	SCSI_WRITE(baseAddress, POINTERCLR , 0xf);   /* All Pointer Clear*/

	dataByte = 0;
	((PIF_SELECT)&dataByte)->RegSelect = 1;
	SCSI_IF_SELECT(baseAddress, dataByte);	     /* FIFO Status Read set*/

	/*------------------------*/
	/* Reset Ns3 and SCSI bus.*/
	/*------------------------*/
	DevExt->InterruptPending = FALSE;
	DevExt->DmaPending = FALSE;

	/*Terminator Off !*/
	SCSI_WRITE(baseAddress, TERMPWRCTRL, 0);     /* Terminator Off !*/
	dataByte = SCSI_READ(baseAddress, OTHERCONTROL);
	if ( ! ((POTHER_CONTROL)&dataByte)->TermPwrSence ) /* Term Power ?;*/
		SCSI_WRITE(baseAddress, TERMPWRCTRL, 1);   /* Terminator ON !*/

	/**/
	/*--- SCSI BUS RESET ---*/
	/**/
	Ns3ResetScsiBus( DevExt );

	/**/
	/*--- Cable Check ---*/
	/**/
	DevExt->ScsiCable = TRUE;
	if ((SCSI_READ(baseAddress,SCSIDATAIN)) ||  /* SCSI Cable is connected to Ninja? */
	    (SCSI_READ(baseAddress,SCSIBUSMON)) ) {
		DevExt->ScsiCable = FALSE;
		SCSI_WRITE(baseAddress, TERMPWRCTRL, 0); /* Terminator Off !*/
	}

	*(u_char *)&xferMode = DevExt->TransferMode;

	/**/
	/* Can TransferMode Clear*/
	/**/
	for ( i = 0; i < Ns3Number(DefaultOk); i++ ) {
		DevExt->CanTransMode[i] = DefaultOk[i];
	}
	/**/
	/* At first, Test for TransferMode in default */
	/**/
	DefaultXfer = Ns3FifoTest(DevExt->CanTransMode);

	xferMode =(*(PTRANSFER_MODE)&DefaultXfer);

	DevExt->TransferMode= *(u_char *)&xferMode;
	/* TransferModeSet & TEST MODE OFF */
	SCSI_WRITE(baseAddress, TRANSFERMODE, *(u_char *)&xferMode);


	if ( xferMode.IO16_32 ) {
		DevExt->pXferRead  = pio32_datain;
		DevExt->pXferWrite = pio32_dataout;
	} else	if ( xferMode.IO8 ) {
		DevExt->pXferRead  = pio8_datain;
		DevExt->pXferWrite = pio8_dataout;
	} else {
		printk(__FUNCTION__ " Unknown xfer mode. go to io8 mode\n");
		DevExt->pXferRead  = pio8_datain;
		DevExt->pXferWrite = pio8_dataout;
	}
	SCSI_WRITE(baseAddress, CLOCKDIV , 2);	/* 20MHz *[v1.03]*/

	return TRUE;
} /* end Ns3Initialize()*/

/*
//-----------------------------------------------------------------------
// Routine Name:
//    Ns3NotifyCompletion
//
// Routine Description:
// 
//    This routine will perform any clean up operations for the Srb
//    and notify the ScsiPort driver of completion.
// 
//-----------------------------------------------------------------------
*/
static void Ns3NotifyCompletion( IN pnin_softc DevExt,
				 IN boolean host_byte )
{
	Scsi_Cmnd	*srb = DevExt->ActiveUnit->ActiveCommand;

	Ns3DebugPrint(0x10,(KERN_DEBUG __FUNCTION__ " scsi_done[%x]\n",srb->cmnd[0]));
	ScsiPortFreeLogicalUnit(srb->target, srb->lun);

	Owattayo = 1;

	srb->result = (host_byte		 << 16) 
		    | ((srb->SCp.Message & 0xff) << 8 )
		    | ((srb->SCp.Status	 & 0xff) << 0 );
	Ns3DebugPrint(0x10,(KERN_DEBUG __FUNCTION__ " result[%x],Status[%x]\n",srb->result, srb->SCp.Status));
#ifdef DBG_SHOWCOMMAND
	show_command(srb);
#endif

	srb->scsi_done(srb);

#ifdef USE_SLEEP_WAKE
	wake_up_interruptible(&read_wait);
#endif /* USE_SLEEP_WAKE */

} /* end Ns3NotifyCompletion()*/

/*
//----------------------------------------------------------------------------
//		Set transger mode & ruotine
//----------------------------------------------------------------------------
*/
static void Ns3SetTransferMode( IN pnin_softc DevExt )
{
	PSPECIFIC_LU_EXTENSION LuExtension = DevExt->ActiveUnit;
	unsigned char dataByte;

	LuExtension->pXferRead	= DevExt->pXferRead;
	LuExtension->pXferWrite = DevExt->pXferWrite;

	/* FIFOTest & Option Set TransferMode*/
	dataByte = DevExt->TransferMode;

	((PTRANSFER_MODE)&dataByte)->TransferGo = 1;
	((PTRANSFER_MODE)&dataByte)->FifoTest_Braind = 1;
	/* Set transfer mode*/
	SCSI_WRITE(DevExt->BaseAddress, TRANSFERMODE, dataByte);
}


/*
//-----------------------------------------------------------------------
//				 read FIFO
//-----------------------------------------------------------------------
*/
static unsigned long read_ack_count ( IN pnin_softc DevExt )
{
	int  baseAddress = DevExt->BaseAddress;
	unsigned char	dataByte;
	unsigned char	CountL,CountM, CountH, CountDummy;
	unsigned long	Count, Counter;

	dataByte = 0;
	((PPOINTER_CLEAR)&dataByte)->PointerClear = 1;
	SCSI_WRITE(baseAddress, POINTERCLR, dataByte);/* ACK counter read set*/

	CountL	   = inb(baseAddress+DATAREG);
	CountM	   = inb(baseAddress+DATAREG);
	CountH	   = inb(baseAddress+DATAREG);
	CountDummy = inb(baseAddress+DATAREG);
	/* ScsiPortReadPortUchar((unsigned char *)&((baseAddress)->DATAREG));*/

	Counter = (unsigned long)(  ((unsigned long)CountH << 16) 
				   |((unsigned long)CountM <<  8)
				   |((unsigned long)CountL	));

	/* Check Card */
	if ( Counter == 0xffffff ) return (0); /* Counter is 24 bit width */

	/* Counter value at Disconnect */
	Ns3DebugPrint(0x008, (KERN_DEBUG "read_ack_count[%lx]\n",Counter));
	Count = Counter + DevExt->ActiveUnit->AckCounter;

	Count -= DevExt->ActiveUnit->TransferedLength;

	return ( Count );
}

/************************************************************/

/*
//-----------------------------------------------------------------------
//     TransferRoutine
//-----------------------------------------------------------------------
*/
/*
  --- PIO 32bit DataInTransfer ----
*/
static void pio32_datain (int BaseAddress ,
			  char*	 Buffer,
			  u_long Length )
{
	/*Ns3DebugPrint(0x01,("R"));*/
	if ( Length & 0x3 ) {
		/*Ns3DebugPrint(0x01,(KERN_DEBUG "SCSI_READ_FIFOW [%lx] (%lx)byte\n", (unsigned long)Buffer , Length));*/
		SCSI_READ_FIFOW(BaseAddress, (char *)Buffer , Length);
	} else {
		SCSI_READ_FIFOD(BaseAddress, Buffer , Length);
	}
}

/*
  --- PIO 32bit DataOutTransfer ----
*/
static void pio32_dataout (int BaseAddress ,
			   char* Buffer,
			   u_long Length )
{
	/*Ns3DebugPrint(0x01,("W"));*/
	if ( Length & 0x3 ) {
		SCSI_WRITE_FIFOW(BaseAddress, (char *)Buffer , Length);
	} else {
		SCSI_WRITE_FIFOD(BaseAddress, (char *)Buffer , Length);
	}
}

/*
  --- PIO 8bit DataInTransfer ----
*/
static void pio8_datain (int BaseAddress ,
			 char*	Buffer,
			 u_long Length )
{
	/*Ns3DebugPrint(0x01,("r"));*/
	SCSI_READ_FIFO(BaseAddress, Buffer , Length);
}

/*
  --- PIO 8bit DataOutTransfer ----
*/
static void pio8_dataout (int BaseAddress ,
			  char*	 Buffer,
			  u_long Length )
{
	/*Ns3DebugPrint(0x01,("w"));*/
	SCSI_WRITE_FIFO(BaseAddress, Buffer , Length);
}


static void Ns3BurstRead( IN pnin_softc DevExt )
{
	u_long	Length;
	IRQ_STATUS		IrqStatus;
	FIFO_STATUS		FifoStatus;
	int  baseAddress = DevExt->BaseAddress;
	PSPECIFIC_LU_EXTENSION LuExtension = DevExt->ActiveUnit;

	while( DevExt->CurDataLength > 0 ) {
		*((u_char *) &IrqStatus) = SCSI_IRQ_MONITOR(baseAddress);
		/*  0629 ORESAMA*/
		if ( IrqStatus.ScsiIrqStatus ) {
			break;		
			/** PhaseChange ? ***/
		}
		/*  0629 ORESAMA*/
		*((u_char *) &FifoStatus) = SCSI_FIFO_STATUS(baseAddress);
		if ( FifoStatus.FifoFullEmpty ) {
			Length = DevExt->CurDataLength;
			/* change maxmum transfer size*/
			if ( Length > READ_XFER_CNT) Length = READ_XFER_CNT;

			/* Call for TransferRoutine */
			(*LuExtension->pXferRead)( baseAddress, 
						DevExt->CurDataPointer, Length );

			DevExt->CurDataPointer += Length;
			DevExt->CurDataLength -= Length;
			DevExt->ActiveUnit->TransferedLength += Length;
		}
	}

	/* See now,but PhaseChange */
	*((u_char *) &IrqStatus) = SCSI_IRQ_MONITOR(baseAddress);

	/*  Stop PhaseChange interrupt */
	if ( IrqStatus.ScsiIrqStatus ) { /* PhaseChange ?*/
		if ( DevExt->CurDataLength > 0) {
			Length = read_ack_count(DevExt);
			if (!(Length & 0x80000000)) {	/* +[v0.32]*/
				(*LuExtension->pXferRead)( baseAddress, 
						DevExt->CurDataPointer, Length );
			}
			DevExt->CurDataPointer += Length;
			DevExt->CurDataLength -= Length;
			DevExt->ActiveUnit->TransferedLength += Length;
		}
	}

	DevExt->ScsiState = SC_DATA;
}
/*
//-----------------------------------------------------------------------
//	       blind write
//
//-----------------------------------------------------------------------
*/
static void Ns3BurstWrite( IN pnin_softc DevExt )
{
	u_long	Length;
	IRQ_STATUS		IrqStatus;
	FIFO_STATUS		FifoStatus;
	int  baseAddress = DevExt->BaseAddress;
	PSPECIFIC_LU_EXTENSION LuExtension = DevExt->ActiveUnit;

	while( DevExt->CurDataLength > 0 ) {
		*((u_char *) &IrqStatus) = SCSI_IRQ_MONITOR(baseAddress);
		if ( IrqStatus.ScsiIrqStatus ) break; /* PhaseChange ?*/

		*((u_char *) &FifoStatus) = SCSI_FIFO_STATUS(baseAddress);
		if ( FifoStatus.FifoFullEmpty) {

			Length = DevExt->CurDataLength;
			/* change maximum transfer number*/
			if ( Length > WRITE_BURST_CNT) Length = WRITE_BURST_CNT;

			/* Call for TransferRoutine */
			(*LuExtension->pXferWrite)( baseAddress, 
						    DevExt->CurDataPointer, Length );

			DevExt->CurDataPointer += Length;
			DevExt->CurDataLength -= Length;
			DevExt->ActiveUnit->TransferedLength += Length ;
		}
	}

	/* See now,but PhaseChange after sending */
	*((u_char *) &IrqStatus) = SCSI_IRQ_MONITOR(baseAddress);

	/* remain data inFIFO at PhaseChange */
	if ( IrqStatus.ScsiIrqStatus ) {			/* PhaseChange ?*/
		if ( (Length = read_ack_count(DevExt)) ) {	/* Length is Minus*/
			DevExt->CurDataPointer += Length;
			DevExt->CurDataLength -= Length;	/* pointerwomodosu*/
			DevExt->ActiveUnit->TransferedLength += Length ;
		}
	}

	DevExt->ScsiState = SC_DATA;
}

/*
//-----------------------------------------------------------------------
//				spot read 
//-----------------------------------------------------------------------
*/
static void Ns3SpotRead ( IN pnin_softc DevExt )
{
	u_char	dataByte;
	int  baseAddress = DevExt->BaseAddress;
	IRQ_STATUS		IrqStatus;
	FIFO_STATUS		FifoStatus;
	u_long			FifoCount;
	long			LoopCount = 0;
	u_char			ScsiPhase;
	long			i;
	PSPECIFIC_LU_EXTENSION LuExtension = DevExt->ActiveUnit;

	ScsiPhase = SCSI_READ(baseAddress, SCSIBUSMON) & 0x7;

	if ( ScsiPhase == BP_DATA_IN ) {
		if ( ((PIRQ_CONTROLP)&DevExt->IrqMaskData)->FifoIrqMask) { 
			dataByte = SCSI_READ(DevExt->BaseAddress, SCSIIRQMODE);
			((PSCSI_IRQ_MODE)&dataByte)->FifoIrqEi= 1;  /* FIFO IRQ Enable*/
			SCSI_WRITE(DevExt->BaseAddress, SCSIIRQMODE, dataByte);
			/* Release FIFO IRQ MASK */
			((PIRQ_CONTROLP)&DevExt->IrqMaskData)->FifoIrqMask = 0; 
		}

		while (LoopCount == 0) {
			*((u_char *) &IrqStatus) = SCSI_IRQ_MONITOR(baseAddress);
			if ( IrqStatus.ScsiIrqStatus ) break;/* PhaseChange ?*/

			*((u_char *) &FifoStatus) = SCSI_FIFO_STATUS(baseAddress);
			if ( FifoStatus.FifoFullEmpty ) {
				dataByte = 0xf0;
				((PIRQ_CONTROLP)&dataByte)->FifoIrqClear = 1;
				SCSI_IRQ_CONTROL(baseAddress, dataByte); /* IRQ Clear*/

				/* Read FIFO */
				FifoCount = read_ack_count( DevExt ) & 0xfffffe;

				/* Call for TransferRoutine */
				(*LuExtension->pXferRead)( baseAddress, 
							   DevExt->CurDataPointer, FifoCount );

				DevExt->CurDataLength -= FifoCount ;
				DevExt->CurDataPointer += FifoCount;
				DevExt->ActiveUnit->TransferedLength += FifoCount ;
				LoopCount++;

				DevExt->IntWait = FALSE;

				for ( i = 0; i< INT_POLL_IRQ ; i++) {
					*((u_char *) &IrqStatus) = SCSI_IRQ_MONITOR(baseAddress);
					if ( IrqStatus.ScsiIrqStatus ) break;	/* PhaseChange ?*/

					*((u_char *) &FifoStatus) = SCSI_FIFO_STATUS(baseAddress);
					if ( FifoStatus.FifoFullEmpty )	{ /* FIFO FULL */
						LoopCount = 0;	/* One moer*/
						break;
					}
					udelay(2);/*ScsiPortStallExecution(2);*/
				}
			}
		}
	} else {
	/* other phase*/
		FifoCount = read_ack_count( DevExt );	/* Get FIFOremain*/
		(*LuExtension->pXferRead)( baseAddress, 
					   DevExt->CurDataPointer, FifoCount );

		DevExt->CurDataLength -= FifoCount ;
		DevExt->CurDataPointer += FifoCount;
		DevExt->ActiveUnit->TransferedLength += FifoCount ;

		dataByte = SCSI_READ(DevExt->BaseAddress, SCSIIRQMODE);
		/* Disable FIFO IRQ */
		((PSCSI_IRQ_MODE)&dataByte)->FifoIrqEi= 0;			
		SCSI_WRITE(DevExt->BaseAddress, SCSIIRQMODE, dataByte);
#ifdef USE_IRQ_MASK
		/* FIFO IRQ MASK*/
		((PIRQ_CONTROLP)&DevExt->IrqMaskData)->FifoIrqMask = 1; 
#endif /*  USE_IRQ_MASK */

		DevExt->IntWait = TRUE;
		return;
	}

	/* Stoped in PhaseChange */
	if (IrqStatus.ScsiIrqStatus &&
	    ( FifoCount = read_ack_count(DevExt))) 
	{
		(*LuExtension->pXferRead)( baseAddress, 
					   DevExt->CurDataPointer, FifoCount );
		DevExt->CurDataPointer += FifoCount;
		DevExt->CurDataLength -= FifoCount;
		DevExt->ActiveUnit->TransferedLength += FifoCount;

		dataByte = SCSI_READ(DevExt->BaseAddress, SCSIIRQMODE);
		/* Disable FIFO IRQ */
		((PSCSI_IRQ_MODE)&dataByte)->FifoIrqEi= 0;
		SCSI_WRITE(DevExt->BaseAddress, SCSIIRQMODE, dataByte);

#ifdef USE_IRQ_MASK
		/* FIFO IRQ MASK*/
		((PIRQ_CONTROLP)&DevExt->IrqMaskData)->FifoIrqMask = 1; 
		DevExt->IntWait = TRUE;
#endif /*  USE_IRQ_MASK	 */
	}

	DevExt->ScsiState = SC_DATA; /* Wait for next FifoFull */
}
/*
//-----------------------------------------------------------------------
//
//-----------------------------------------------------------------------
*/
static void Ns3SpotWrite ( IN pnin_softc DevExt )
{
	u_char	dataByte;
	int  baseAddress = DevExt->BaseAddress;
	IRQ_STATUS		IrqStatus;
	FIFO_STATUS		FifoStatus;
	u_long			FifoCount;
	long			LoopCount = 0;
	long			i;
	PSPECIFIC_LU_EXTENSION LuExtension = DevExt->ActiveUnit;

	if ( ((PIRQ_CONTROLP)&DevExt->IrqMaskData)->FifoIrqMask) { 
		dataByte = SCSI_READ(DevExt->BaseAddress, SCSIIRQMODE);
		/* FIFO IRQ Enable*/
		((PSCSI_IRQ_MODE)&dataByte)->FifoIrqEi= 1;
		SCSI_WRITE(DevExt->BaseAddress, SCSIIRQMODE, dataByte);
		/* Release FIFO IRQ MASK */
		((PIRQ_CONTROLP)&DevExt->IrqMaskData)->FifoIrqMask = 0; 
	}

	while (LoopCount == 0) {
		*((u_char *) &IrqStatus) = SCSI_IRQ_MONITOR(baseAddress);
		if ( IrqStatus.ScsiIrqStatus ) {
			break;			/* PhaseChange ?*/
		}
		*((u_char *) &FifoStatus) = SCSI_FIFO_STATUS(baseAddress);
		if ( FifoStatus.FifoFullEmpty) {
			dataByte = 0xf0;
			((PIRQ_CONTROLP)&dataByte)->FifoIrqClear = 1;
			SCSI_IRQ_CONTROL(baseAddress, dataByte); /* IRQ Clear*/

			FifoCount = WRITE_SPOT_CNT;
			if ( DevExt->CurDataLength < WRITE_SPOT_CNT ){
				FifoCount = DevExt->CurDataLength;
			}

			/* Call for TransferRoutine */
			(*LuExtension->pXferWrite)( baseAddress, 
						    DevExt->CurDataPointer, FifoCount );

			DevExt->CurDataLength -= FifoCount ;
			DevExt->CurDataPointer += FifoCount;;
			DevExt->ActiveUnit->TransferedLength += FifoCount ;
			if ( DevExt->CurDataLength == 0 ) { 
				DevExt->IntWait = TRUE;
				break;
			}

			LoopCount++;
			DevExt->IntWait = FALSE;

			for ( i = 0; i< INT_POLL_IRQ ; i++) {
				*((u_char *) &IrqStatus) = SCSI_IRQ_MONITOR(baseAddress);
				if ( IrqStatus.ScsiIrqStatus ) {
					break;	/* PhaseChange ?*/
				}

				*((u_char *) &FifoStatus) = SCSI_FIFO_STATUS(baseAddress);
				if ( FifoStatus.FifoFullEmpty )	{ /* if FIFO Empty*/
					LoopCount = 0;	      /* Once more*/
					break;
				}
				udelay(2);   /* ScsiPortStallExecution(2); */
			}
		}
	}

	if ( IrqStatus.ScsiIrqStatus )	{	/* PhaseChange ?*/
		DevExt->IntWait = TRUE;
	}
	DevExt->ScsiState = SC_DATA;		/* Next FifoEmpty Wait*/
}
/*
//-----------------------------------------------------------------------
//				Slow Read
//
//-----------------------------------------------------------------------
*/
static void Ns3SlowRead ( IN pnin_softc DevExt )
{
	char*	Buffer = DevExt->CurDataPointer;
	u_char	dataByte;
	int  baseAddress = DevExt->BaseAddress;
	IRQ_STATUS		IrqStatus;
	FIFO_STATUS		FifoStatus;
	u_long			FifoCount;
	long			LoopCount = 0;
	u_char			ScsiPhase;

	dataByte = 0;
	((PTRANSFER_MODE)&dataByte)->TransferGo = 1;
	((PTRANSFER_MODE)&dataByte)->IO8 = 1;
	((PTRANSFER_MODE)&dataByte)->FifoTest_Braind = 0;
	SCSI_WRITE(baseAddress, TRANSFERMODE, dataByte); /* Set Transfer Mode*/

	ScsiPhase = SCSI_READ(baseAddress, SCSIBUSMON) & 0x7;

	if ( ScsiPhase == BP_DATA_IN ) {
		if ( ((PIRQ_CONTROLP)&DevExt->IrqMaskData)->FifoIrqMask) { 
			dataByte = SCSI_READ(DevExt->BaseAddress, SCSIIRQMODE);
			/* FIFO IRQ Enable*/
			((PSCSI_IRQ_MODE)&dataByte)->FifoIrqEi= 1;
			SCSI_WRITE(DevExt->BaseAddress, SCSIIRQMODE, dataByte);
			/* Release FIFO IRQ MASK*/
			((PIRQ_CONTROLP)&DevExt->IrqMaskData)->FifoIrqMask = 0; 
		}
		while (LoopCount == 0) {
			*((u_char *) &IrqStatus) = SCSI_IRQ_MONITOR(baseAddress);
			*((u_char *) &FifoStatus) = SCSI_FIFO_STATUS(baseAddress);
			if ( FifoStatus.FifoFullEmpty )	{  /* FIFO FULL? */
				dataByte = 0xf0;
				((PIRQ_CONTROLP)&dataByte)->FifoIrqClear = 1;
				SCSI_IRQ_CONTROL(baseAddress, dataByte); /* Clear IRQ*/
			}
			if ( FifoStatus.FifoFullEmpty || IrqStatus.ScsiIrqStatus) {
				FifoCount = read_ack_count( DevExt );/* Get FIFO remain*/
				SCSI_READ_FIFO( baseAddress, Buffer, FifoCount );
				Buffer += FifoCount;

				DevExt->CurDataLength -= FifoCount ;
				DevExt->CurDataPointer = Buffer;
				DevExt->ActiveUnit->TransferedLength += FifoCount ;
				LoopCount++;
			}
		}
	} else {
	/* otheer Phase*/
		FifoCount = read_ack_count( DevExt );	/* read FIFO remain*/
		SCSI_READ_FIFO( baseAddress, Buffer, FifoCount );
		Buffer += FifoCount;

		DevExt->CurDataLength -= FifoCount ;
		DevExt->CurDataPointer = Buffer;
		DevExt->ActiveUnit->TransferedLength += FifoCount ;
		return;
	}

	DevExt->ScsiState = SC_DATA;		/* Wait for next FifoFull */
}
/*
//-----------------------------------------------------------------------
//
//-----------------------------------------------------------------------
*/
static void Ns3SlowWrite ( IN pnin_softc DevExt )
{
	char*	       Buffer = DevExt->CurDataPointer;
	u_char	       dataByte;
	int	       baseAddress = DevExt->BaseAddress;
	/* IRQ_STATUS  IrqStatus;*/
	FIFO_STATUS    FifoStatus;
	u_long	       FifoCount;

	dataByte = 0;
	((PTRANSFER_MODE)&dataByte)->TransferGo = 1;
	((PTRANSFER_MODE)&dataByte)->IO8 = 1;
	((PTRANSFER_MODE)&dataByte)->FifoTest_Braind = 0;
	SCSI_WRITE(baseAddress, TRANSFERMODE, dataByte); /* TransferModeSet*/

	if ( ((PIRQ_CONTROLP)&DevExt->IrqMaskData)->FifoIrqMask) { 
		dataByte = SCSI_READ(DevExt->BaseAddress, SCSIIRQMODE);
		/* FIFO IRQ Enable*/
		((PSCSI_IRQ_MODE)&dataByte)->FifoIrqEi= 1;
		SCSI_WRITE(DevExt->BaseAddress, SCSIIRQMODE, dataByte);
		/* Enable FIFO IRQ MAS K*/
		((PIRQ_CONTROLP)&DevExt->IrqMaskData)->FifoIrqMask = 0; 
	}

	/**((u_char *) &IrqStatus) = SCSI_IRQ_MONITOR(baseAddress);*/
	*((u_char *) &FifoStatus) = SCSI_FIFO_STATUS(baseAddress);

	if ( FifoStatus.FifoFullEmpty) {
		dataByte = 0xf0;
		((PIRQ_CONTROLP)&dataByte)->FifoIrqClear = 1;
		SCSI_IRQ_CONTROL(baseAddress, dataByte); /* IRQ Clear*/

		FifoCount = 32;
		if ( DevExt->CurDataLength < 32 )
			FifoCount = DevExt->CurDataLength;

		SCSI_WRITE_FIFO ( baseAddress, Buffer, FifoCount );
		Buffer += FifoCount;

		DevExt->CurDataLength -= FifoCount ;
		DevExt->CurDataPointer = Buffer;
		DevExt->ActiveUnit->TransferedLength += FifoCount ;
	}

	DevExt->ScsiState = SC_DATA; /* Wait for Next FifoEmpty*/

}

/*
//-----------------------------------------------------------------------
// Routine Name:
//
//    Ns3RunPhase
//
// Routine Description:
// 
//    This routine runs through the bus phases until some type of completion
//    indication is received.  
// 
// Arguments:
// 
//    DevExt - Device adapter context pointer.
// 
// Return Value:
// 
//    None.
// 
//-----------------------------------------------------------------------
*/
static void Ns3RunPhase( IN pnin_softc DevExt,
			 IN IRQ_PHASE_SENSE IrqPhase )
{
	int  baseAddress = DevExt->BaseAddress;
	u_char	dataByte;
	u_long	Count;
	PSPECIFIC_TARGET_EXTENSION targetState;

	/* slow transfer proc*/
	if ( IrqPhase.PhaseChgIrq && 
		((PIRQ_CONTROLP)&DevExt->IrqMaskData)->FifoIrqMask == 0 ) {

		/* still ?*/
		if ( (Count = read_ack_count(DevExt)) ) {
			if ( DevExt->ScsiPrePhase == BP_DATA_IN) {/* prvious phase*/
				Ns3DataInPhase(DevExt);
			}else {
				DevExt->CurDataLength -= Count;	/* back pointer*/
				DevExt->CurDataPointer += Count;
				/* Number of transfer-length */
				DevExt->ActiveUnit->TransferedLength += Count;	
			}
		}
		dataByte = SCSI_READ(DevExt->BaseAddress, SCSIIRQMODE);
		/* FIFO IRQ desable*/
		((PSCSI_IRQ_MODE)&dataByte)->FifoIrqEi= 0;
		SCSI_WRITE(DevExt->BaseAddress, SCSIIRQMODE, dataByte);
#ifdef USE_IRQ_MASK
		/* FIFO IRQ MASK*/
		((PIRQ_CONTROLP)&DevExt->IrqMaskData)->FifoIrqMask = 1; 
#endif /* USE_IRQ_MASK */
	}

	/*
	//--- BUS FREE ( DISCONNETCT ) ? ----
	*/
	/*interrput in BusFree*/
	if ( IrqPhase.LatchBusFree )
	{
		/* trans-mode is FIFOtest/option*/
		dataByte = DevExt->TransferMode;
		((PTRANSFER_MODE)&dataByte)->TransferGo = 0;
		((PTRANSFER_MODE)&dataByte)->FifoTest_Braind = 0;
		/* TransferModeSet*/
		SCSI_WRITE(baseAddress, TRANSFERMODE, dataByte);	

		/* Save AckCounter*/
		DevExt->ActiveUnit->AckCounter = DevExt->ActiveUnit->TransferedLength;

		if ( DevExt->ScsiState == SC_COMPLETE ) {
			Ns3NotifyCompletion(DevExt, DID_OK);
			DevExt->ScsiState = SC_BUSFREE;
			DevExt->IntWait = FALSE;
			return;
		} else if (DevExt->ScsiState == SC_DISCONNECT ) {
			Ns3DebugPrint(0x008, (KERN_DEBUG __FUNCTION__ ":ScsiState == SC_DISCONNECT \n"));
			DevExt->ScsiState = SC_BUSFREE;
			return;
		}

		Ns3DebugPrint(0x10,(KERN_DEBUG __FUNCTION__ ": Unexpected bus disconnect[%x].\n",
				    DevExt->ScsiState));

		targetState = &DevExt->TargetState[DevExt ->TargetId];
		if (targetState->TargetFlags & PD_SYNCHRONOUS_TRANSFER_SENT) {
			targetState->TargetFlags &= ~PD_SYNCHRONOUS_TRANSFER_SENT;
			targetState->TargetFlags |= PD_DO_NOT_NEGOTIATE;
		}
		DevExt->ScsiState = SC_BUSFREE;
		/* ScsiPortLogError(DevExt,SP_UNEXPECTED_DISCONNECT,10);*/
		Ns3DebugPrint(0x10,(KERN_DEBUG __FUNCTION__ ":SC_BUSFREE-bye!\n"));
		return;
	}


	(*(u_char *)&IrqPhase) &= 0x7;
	DevExt->ScsiPrePhase = (*(u_char *)&IrqPhase);

	switch (DevExt->ScsiPrePhase) {
	case BP_COMMAND:
	/*	Ns3DebugPrint(0x10,(KERN_DEBUG "Ns3RunPhase: BP_COMMAND\n"));*/
		Ns3SendCDB(DevExt); /*Start commans phase*/
		break;

	case BP_DATA_IN:
		Ns3DebugPrint(0x10,(KERN_DEBUG __FUNCTION__ ": BP_DATA_IN\n"));
		Ns3DataInPhase(DevExt);	/* Start data phase*/
		break;

	case BP_DATA_OUT:
		Ns3DebugPrint(0x10,(KERN_DEBUG __FUNCTION__ ": BP_DATA_OUT\n"));
		Ns3DataOutPhase(DevExt); /* Start data phase*/
		break;

	case BP_STATUS:
		Ns3DebugPrint(0x10,(KERN_DEBUG __FUNCTION__ ": BP_STATUS\n"));
		Ns3Status(DevExt);
		break;

	case BP_MESSAGE_IN:
		Ns3DebugPrint(0x10,(KERN_DEBUG __FUNCTION__ ": BP_MESSAGE_IN\n"));
		Ns3MessageIn(DevExt);
		break;

	case BP_MESSAGE_OUT:
		Ns3DebugPrint(0x10,(KERN_DEBUG __FUNCTION__ ": BP_MESSAGE_OUT\n"));
		Ns3MessageOut(DevExt);
		break;

	default:
		DevExt->ScsiState = SC_COMPLETE;
		break;
	}
	
#ifdef RUNPHASE_AUTODIRECTION
	dataByte = SCSI_READ(baseAddress, SCSIBUSCTRL);

	((PSCSI_BUS_CONTROL)&dataByte)->AutoDirection = 1;
	SCSI_WRITE(baseAddress , SCSIBUSCTRL, dataByte);
#endif /* RUNPHASE_AUTODIRECTION  0704 */

} /* end Ns3RunPhase()*/

/*
//-----------------------------------------------------------------------
// Routine Name:
//
//    Ns3DataInPhase
//
// Routine Description:
// 
//    This routine sets the DmaPending flag in the device extension,
//    calls the OS-specific driver to set up the system DMA chip,
//    and returns. Control is received again in DmaStarted when the DMA
//    setup is complete.
// 
// Arguments:
// 
//    DevExt - Device adapter context pointer.
// 
// Return Value:
// 
//    TRUE if DMA started
//    FALSE if missed request
// 
//-----------------------------------------------------------------------
*/
static void Ns3DataInPhase( IN pnin_softc DevExt )
{
	u_char	targetId = DevExt->TargetId;
	u_char	devType;

	DevExt->InterruptPending = FALSE; /* flag clear*/

	DevExt->DmaPending = TRUE;
	devType = DevExt->DeviceType[targetId];

	Ns3DebugPrint(0x10, (KERN_DEBUG __FUNCTION__ " in\n"));

	if ((DevExt->ActiveUnit->ActiveCommand->request_bufflen < 0x100) ||
	    (DevExt->ActiveUnit->ActiveCommand->request_bufflen & 3)) {
		Ns3SlowRead ( DevExt );	/* 256以下か, 4で割り切れない? */
		return;
	}

#ifdef USE_SPOTREAD_ONLY
	Ns3SpotRead ( DevExt );
#else
	switch ( devType ) {
	case TYPE_DISK: /* disk */
	case TYPE_ROM: /* CD-ROM */
	case TYPE_MOD: /* MO */
		Ns3BurstRead( DevExt );
		break;

	default:
		Ns3SpotRead ( DevExt );
		break;
	}
#endif /* USE_SPOTREAD_ONLY */
	
#ifdef USE_SLEEP_WAKE
	interruptible_sleep_on(&read_wait);
#endif /* USE_SLEEP_WAKE */

	/* ------ ORESAMA ------
	   if(!DevExt->CurDataLength) {
		   Ns3NotifyCompletion(DevExt, FALSE);
		   DevExt->ScsiState = SC_COMPLETE;
	   }
	   ------ ORESAMA ------ */

} /* end Ns3DataInPhase()*/

/*
//-----------------------------------------------------------------------
// Routine Name:
//
//    Ns3DataOutPhase
//
// Routine Description:
// 
//    This routine sets the DmaPending flag in the device extension,
//    calls the OS-specific driver to set up the system DMA chip,
//    and returns. Control is received again in DmaStarted when the DMA
//    setup is complete.
// 
// Arguments:
// 
//    DevExt - Device adapter context pointer.
// 
// Return Value:
// 
//    TRUE if DMA started
//    FALSE if missed request
// 
//-----------------------------------------------------------------------
*/
static void Ns3DataOutPhase( IN pnin_softc DevExt )
{
	u_char	targetId = DevExt->TargetId;
	u_char	devType;
	/*u_char	dataByte;*/

	DevExt->InterruptPending = FALSE; /* flag clear*/

	DevExt->DmaPending = TRUE;

	devType = DevExt->DeviceType[targetId];

	if ((DevExt->ActiveUnit->ActiveCommand->request_bufflen < 0x100) ||
	    (DevExt->ActiveUnit->ActiveCommand->request_bufflen & 3)) {
		Ns3SlowWrite ( DevExt );  /* 256以下または 4で割り切れない? */
		return;
	}

	/*dataByte = DevExt->TransferMode;*/  /* Set TransferMode in FIFOTest / Option */
	/*Ns3SetTransferMode(DevExt);*/
	/* munya.. */

/*	Ns3SpotWrite ( DevExt );*/

	switch ( devType ) {
	case TYPE_DISK: /* disk */
	case TYPE_ROM: /* CD-ROM */
	case TYPE_MOD: /* MO */
		Ns3BurstWrite( DevExt );
		break;

	default:
		Ns3SpotWrite( DevExt );
		break;
	}

} /* end Ns3DataOutPhase()*/

/*
//-----------------------------------------------------------------------
// Routine Name:
//
//    Ns3SendCDB
//
// Routine Description:
// 
//    Send the SCSI Command Descriptor Block (CDB) to the indicated target/lun.
// 
// Arguments:
// 
//    DevExt - Device adapter context pointer.
// 
// Return Value:
// 
//    None
// 
//-----------------------------------------------------------------------
*/
static void Ns3SendCDB( IN pnin_softc DevExt )
{
	int  baseAddress = DevExt->BaseAddress;
	u_char	dataByte;

#ifdef DBG_PRINT
	Scsi_Cmnd *cmd = DevExt->ActiveUnit->ActiveCommand;
	Ns3DebugPrint(0x10,(KERN_DEBUG __FUNCTION__ " in(target=%x)!\n",cmd->target));
#endif	

	dataByte = SCSI_READ(baseAddress, SCSIBUSMON);
	if ( ((PSCSI_BUS_MONITOR)&dataByte)->Scsi_ATN )	{ /* Still ATN ?*/
		/* SCSI-1 Device */
		dataByte  = 0;
		((PSCSI_BUS_CONTROL)&dataByte)->AutoDirection = 1;
		((PSCSI_BUS_CONTROL)&dataByte)->AckEnb = 1;
		SCSI_WRITE(baseAddress, SCSIBUSCTRL, dataByte);	/* ATN off*/
	}

	/* Clear transfer counter*/
	dataByte = 0;
	((PPOINTER_CLEAR)&dataByte)->PointerClear = 1;
	((PPOINTER_CLEAR)&dataByte)->AckCounterClear = 1;
	((PPOINTER_CLEAR)&dataByte)->ReqCounterClear = 1;
	((PPOINTER_CLEAR)&dataByte)->HostCounterClear = 1;
	SCSI_WRITE(baseAddress, POINTERCLR, dataByte);

	DevExt->ActiveUnit->AckCounter = 0;
	DevExt->ActiveUnit->HostCounter = 0;

	/* send CDB*/
	dataByte = 0;
	((PCOMMAND_CONTROL)&dataByte)->AutoCommandGo = 1;
	((PCOMMAND_CONTROL)&dataByte)->ClrCommandPointer = 1;
	SCSI_WRITE(baseAddress, COMMANDCTRL, dataByte);

	DevExt->ScsiState = SC_UNDETERMINED;

	/*
	 * Set up the running data pointer info for a possible data transfer.
	 */
	DevExt->CurDataPointer = DevExt->ActiveUnit->SavedDataPointer;
	DevExt->CurDataLength = DevExt->ActiveUnit->SavedDataLength;

	DevExt->ActiveUnit->TransferedLength = 0;

	/* Enable Interrupt */
	DevExt->InterruptPending = TRUE;

} /* end Ns3SendCDB()*/

/*
//-----------------------------------------------------------------------
// Routine Name:
//
//    Ns3MessageOut
//
// Routine Description:
// 
//    This routine will sent the message to the target.
// 
//-----------------------------------------------------------------------
*/
static void Ns3MessageOut( IN pnin_softc DevExt )
{
	int	    baseAddress = DevExt->BaseAddress;
	u_char	    dataByte;
	u_char *    msg = &DevExt->MessageBuffer[0];
	IRQ_STATUS  IrqStatus;

	/* MessageOut,NoOperation*/
	if ( DevExt->MessageCount == 0 ) {
		DevExt->MessageBuffer[0] = MSG_NOOP;
		DevExt->MessageCount = 1;
	}

	do {
		*((u_char *) &IrqStatus) = SCSI_IRQ_MONITOR(baseAddress);
		if (IrqStatus.ScsiIrqStatus) {
			break;
		}

		dataByte = SCSI_READ(baseAddress, SCSIBUSMON) & S_PHASE_MASK;
		if ( dataByte == BM_MESSAGE_OUT ) {		

			if ( DevExt->MessageCount == 1) { /* last byte ?*/
				dataByte = 0;
				((PSCSI_BUS_CONTROL)&dataByte)->AutoDirection = 1;
				((PSCSI_BUS_CONTROL)&dataByte)->AckEnb = 1;
				/* ATN Off !*/
				SCSI_WRITE(baseAddress , SCSIBUSCTRL, dataByte);
			}

			/* message output*/
			SCSI_WRITE(baseAddress ,SCSIDATAWITHACK, *msg);

			Ns3WaitForAckOff(DevExt);

			msg++;
			DevExt->MessageCount--;
		}
	} while ( DevExt->MessageCount != 0 );

	/* phase change. Off ATN  */
	if ( IrqStatus.ScsiIrqStatus && DevExt->MessageCount != 0) {
		dataByte = 0;
		((PSCSI_BUS_CONTROL)&dataByte)->AutoDirection = 1;
		((PSCSI_BUS_CONTROL)&dataByte)->AckEnb = 1;
		SCSI_WRITE(baseAddress , SCSIBUSCTRL, dataByte);/* ATN Off !*/
	}

	DevExt->ScsiState = SC_UNDETERMINED;
} /* end Ns3MessageOut()*/

/*
//-----------------------------------------------------------------------
// Routine Name:
//
//    Ns3MessageIn
//
// Routine Description:
// 
//    This routine will receive the message from the target.
// 
//-----------------------------------------------------------------------
*/
static void Ns3MessageIn( IN pnin_softc DevExt )
{
	PSPECIFIC_LU_EXTENSION	luExtension;
	Scsi_Cmnd *		srb;
	int			baseAddress = DevExt->BaseAddress;
	u_char *		msg = &DevExt->MessageBuffer[0];
	u_char			dataByte;
	IRQ_STATUS		IrqStatus;
	u_long			MessageCount = 0;
	boolean			NegAck = TRUE;
	PSPECIFIC_TARGET_EXTENSION targetState;

	DevExt->MessageCount = 0;

	Ns3DebugPrint(0x008, (KERN_DEBUG __FUNCTION__ " in\n"));
	luExtension = DevExt->ActiveUnit;
	if ( luExtension ) {  /* reselection = NULL*/
		srb = luExtension->ActiveCommand;
		targetState = &DevExt->TargetState[srb ->target];
	} else {
		return;
	}

	/*
	// --- message first byte
	//
	// read Ninja */  
	dataByte = SCSI_READ(baseAddress, SCSIBUSMON) & S_PHASE_MASK;
	/* message in phase? is &req?*/
	if ( dataByte == BM_MESSAGE_IN ) {
		/* read msg byte*/
		*msg = SCSI_READ(baseAddress, SCSIDATAIN);
		srb->SCp.Message = *msg;

		dataByte = SCSI_READ(baseAddress, SCSIBUSCTRL);
		((PSCSI_BUS_CONTROL)&dataByte)->ScsiACK = 1;
		SCSI_WRITE(baseAddress , SCSIBUSCTRL, dataByte); /* ACK On !*/

		/* if return value is FALSE? */
		Ns3WaitForReqOff(DevExt);			/* REQ off ?*/

		/*
		//---  Identify Message ? ----
		*/
		if ( *msg & MSG_IDENTIFYFLAG ) {/* 0x80 = MSG_IDENTIFYFLAG ? */
			DevExt->TargetLun = *msg & 0xf;
			/* now reselecting?*/
			if ( DevExt->ScsiState == SC_RESELECT ) {
				Ns3DebugPrint(0x10,(KERN_DEBUG "ScsiState == SC_RESELECT \n"));
				Ns3ProcessReselection(DevExt);
			}
		} else {
			DevExt->ScsiState = SC_UNDETERMINED;
			switch ( *msg ) {
			case MSG_CMDCOMPLETE :
				DevExt->ScsiState = SC_COMPLETE;
				break;

			case MSG_DISCONNECT :
				Ns3DebugPrint(0x008, (KERN_DEBUG "MSG_DISCONNECT!!\n"));
				srb->device->disconnect = 1;
				DevExt->ScsiState = SC_DISCONNECT;
				/* 0722 */
				dataByte = SCSI_READ(baseAddress, SCSIBUSCTRL);
				((PSCSI_BUS_CONTROL)&dataByte)->ScsiACK = 0;
				SCSI_WRITE(baseAddress , SCSIBUSCTRL, dataByte); /* ACK off !*/
				return;
				/* 0722 */
				break;

			case MSG_SAVEDATAPOINTER :
				Ns3DebugPrint(0x008, (KERN_DEBUG "MSG_SAVEDATAPOINTER\n"));
				MessageCount = 1;  /* Wait DISCONNECT msg*/
				DevExt->ScsiState = SC_DISCONNECT;
				luExtension->SavedDataPointer = DevExt->CurDataPointer;
				luExtension->SavedDataLength = DevExt->CurDataLength;
				break;

			case MSG_RESTOREPOINTERS:
				Ns3DebugPrint(0x008, (KERN_DEBUG "MSG_RESTOREPOINTERS\n"));
				DevExt->CurDataPointer = luExtension->SavedDataPointer;
				DevExt->CurDataLength = luExtension->SavedDataLength;
				break;

			case MSG_EXTENDED :
				MessageCount = 6; /* max-len ext-msg*/
				if (targetState->TargetFlags & PD_SYNCHRONOUS_TRANSFER_SENT)
					MessageCount = 4;
				NegAck = FALSE;	  /* Not NEG ACK at last byte*/
				break;

			case MSG_MESSAGE_REJECT:
				if (targetState->TargetFlags & PD_SYNCHRONOUS_TRANSFER_SENT) {
					targetState->TargetFlags &= ~PD_SYNCHRONOUS_TRANSFER_SENT;
					targetState->TargetFlags |= PD_DO_NOT_NEGOTIATE;
				}
				break;

			}
		}

		dataByte = SCSI_READ(baseAddress, SCSIBUSCTRL);
		((PSCSI_BUS_CONTROL)&dataByte)->ScsiACK = 0;
		SCSI_WRITE(baseAddress , SCSIBUSCTRL, dataByte); /* ACK Off !*/

		msg++;
		DevExt->MessageCount ++;
	}

	/**/
	/* --- get next-message*/
	*((u_char *) &IrqStatus) = SCSI_IRQ_MONITOR(baseAddress);
	while ( !(IrqStatus.ScsiIrqStatus)) { /* still phase-chg*/

		dataByte = SCSI_READ(baseAddress, SCSIBUSMON) & S_PHASE_MASK;

		/* no next-msg & control-line not message-in*/
		/*-[v0.50] for OLY MO*/
		/*
		if ((MessageCount == 0) &&
		    ((dataByte & 0x7) != BP_MESSAGE_IN) )
			break;
		*/

		/* Is mgs-in phase & req ?*/
		if ( dataByte == BM_MESSAGE_IN ) {	
			*((u_char *) &IrqStatus) = SCSI_IRQ_MONITOR(baseAddress);
			/*if PhaseChange here,maybe Reselection Message*/
			if ( IrqStatus.ScsiIrqStatus ) break;

			*msg = SCSI_READ(baseAddress, SCSIDATAIN);/* read msg-byte */

			if ( *msg == MSG_DISCONNECT ) {
				Ns3DebugPrint(0x008, (KERN_DEBUG "MsgIn:msg == MSG_DISCONNECT\n"));
				srb->device->disconnect = 1;
				DevExt->ScsiState = SC_DISCONNECT;
			}


			dataByte = SCSI_READ(baseAddress, SCSIBUSCTRL);
			((PSCSI_BUS_CONTROL)&dataByte)->ScsiACK = 1;
			SCSI_WRITE(baseAddress , SCSIBUSCTRL, dataByte); /* ACK On !*/

			/* if return value is FALSE? */
			if ( !Ns3WaitForReqOff(DevExt) ) { /* REQ Off ?*/
				Ns3NotifyCompletion(DevExt, DID_NO_CONNECT);
			}
			if ( ( MessageCount != 1) || ( MessageCount == 1 && NegAck )) {
				dataByte = SCSI_READ(baseAddress, SCSIBUSCTRL);
				((PSCSI_BUS_CONTROL)&dataByte)->ScsiACK = 0;
				SCSI_WRITE(baseAddress , SCSIBUSCTRL, dataByte);/* ACK Off !*/
			}

			msg++;
			DevExt->MessageCount ++;
			if ( MessageCount != 0 ) MessageCount--;

			/* if Neg ACK at last Byte Mod, finish*/
			if ( MessageCount == 0 && !NegAck ) break;
		}
		*((u_char *) &IrqStatus) = SCSI_IRQ_MONITOR(baseAddress);
	} /* while ( !(IrqStatus.ScsiIrqStatus)); wait for PhaseChange */

	if (DevExt->MessageBuffer[0] == MSG_EXT_SDTR ) {
		dataByte = SCSI_READ(baseAddress, SCSIBUSCTRL);
		((PSCSI_BUS_CONTROL)&dataByte)->ScsiACK = 0; /* ACK Off !*/
		if (Ns3MessageDecode( DevExt ))	/* Is Message after Decode*/
			((PSCSI_BUS_CONTROL)&dataByte)->ScsiATN = 1; /* ATN On !*/
		SCSI_WRITE(baseAddress , SCSIBUSCTRL, dataByte);
	}

} /* end Ns3MessageIn()*/

/*
//-----------------------------------------------------------------------
// Routine Name:
//
//    Ns3Status
//
// Routine Description:
// 
//    This routine will obtain the status from the target.
// 
// Arguments:
// 
//    DevExt - Device adapter context pointer.
// 
// Return Value:
// 
//    None
// 
//-----------------------------------------------------------------------
*/
static void Ns3Status( IN pnin_softc DevExt )
{
	u_char status;
	u_char dataByte;
	Scsi_Cmnd *srb;
	/*= DevExt->ActiveUnit->ActiveCommand;*/
	int baseAddress = DevExt->BaseAddress;

	if(!DevExt->ActiveUnit) {
		panic(__FUNCTION__ ":DevExt->ActiveUnit == NULL");
	}

	srb = DevExt->ActiveUnit->ActiveCommand;

	dataByte = SCSI_READ(baseAddress, SCSIBUSMON) & S_PHASE_MASK;
	if ( dataByte == BM_STATUS ) { /* Is Status Phase &req ?*/

		status = SCSI_READ(baseAddress, SCSIDATAWITHACK);/* read Status byte*/

		srb->SCp.Status = status;
		Ns3DebugPrint(0x008, (KERN_DEBUG __FUNCTION__ " status:%02x", status));
		switch (status) {
		case SCSI_CONDITION_MET:
			srb->flags |= WAS_SENSE;
		case SCSI_OK:
		case SCSI_INTERM:
		case SCSI_INTERMEDIATE_COND_MET:
			Ns3DebugPrint(0x008, (" ok"));
			if (srb->cmnd[0] == 0x12 && srb->lun == 0) { /* Inquiry cmd */
				DevExt->DeviceType[srb->target] = 
					*(u_char *)(srb->request_buffer);
				if ( DevExt->DeviceType[srb->target] == 6 || /*+[v1.02]*/
				     DevExt->DeviceType[srb->target] == 3) {
					PSPECIFIC_TARGET_EXTENSION targetState;
					targetState = &DevExt->TargetState[srb->target];
					targetState->TargetFlags |= 
						PD_SYNCHRONOUS_NEGOTIATION_DONE;
				}
			}
			srb->request_bufflen = DevExt->ActiveUnit->TransferedLength;
			break;

		case SCSI_CHECK:
		case SCSI_COMMAND_TERMINATED:
			Ns3DebugPrint(0x008, (" check"));
			break;

		case SCSI_BUSY:
		case SCSI_RESERVATION_CONFLICT:
		case SCSI_QUEUE_FULL:
		default:
			Ns3DebugPrint(0x008, (" busy"));
			break;
		}
		Ns3DebugPrint(0x008, ("\n"));

		Ns3WaitForAckOff(DevExt);

		/**/
		/* If some error condition already occurred (e.g., parity error), we'll*/
		/* let that one take priority.*/
		/**/
		/*
		if (srb->SrbStatus == SRB_STATUS_PENDING)
			srb->SrbStatus = srbStatus;
		*/
	} /* if BM_STATUS*/

	DevExt->ScsiState = SC_UNDETERMINED;

} /* end Ns3Status()*/

/*
//-----------------------------------------------------------------------
// Routine Name:
//    Ns3WaitForAckOff
//
// Routine Description:
//    Spin checking the status of the Ns3 adapter until it indicates that
//    the SCSI ACK line is Low 
// 
// Return Value:
//    TRUE    - indicates that the SCSI REQUEST line was Negated in time.
//    FALSE   - indicates timeout occurred while waiting for the SCSI REQUEST
//		line.
//-----------------------------------------------------------------------
*/
static boolean Ns3WaitForAckOff( pnin_softc DevExt )
{
	int  baseAddress = DevExt->BaseAddress;
	u_long	 spinCount   = REQUEST_SPIN_WAIT;
	u_char	dataByte;

	do {
		dataByte = SCSI_READ(baseAddress, SCSIBUSMON);
		if( !((PSCSI_BUS_MONITOR)&dataByte)-> Scsi_ACK){/* ACK Off ?*/
			return TRUE;
		}
		udelay(2);
	} while (spinCount--);

	Ns3NotifyCompletion(DevExt, DID_TIME_OUT);
	return FALSE;

} /* end Ns3WaitForAckOff()*/


/*
//-----------------------------------------------------------------------
// Routine Name:
//
//    Ns3WaitForReqOff
//
// Routine Description:
// 
//    Spin checking the status of the Ns3 adapter until it indicates that
//    the SCSI REQUEST line is high.
// 
// Arguments:
// 
//    DevExt - Device adapter context pointer.
// 
// Return Value:
// 
//    TRUE    - indicates that the SCSI REQUEST line was asserted in time.
//    FALSE   - indicates timeout occurred while waiting for the SCSI REQUEST
//		line.
//-----------------------------------------------------------------------
*/
static boolean Ns3WaitForReqOff( pnin_softc DevExt )
{
	int  baseAddress = DevExt->BaseAddress;
	u_long	 spinCount   = REQUEST_SPIN_WAIT;
	u_char	dataByte;

	do {
		dataByte = SCSI_READ(baseAddress, SCSIBUSMON);
		if( !((PSCSI_BUS_MONITOR)&dataByte)-> Scsi_REQ ) /* REQ Off ?*/
			return TRUE;
	} while (spinCount--);

	/* must call scsi_done()? */

	Ns3DebugPrint(0x04, (KERN_DEBUG "Ns3WaitForReqOff() TIMEOUT\n"));
	/*
	if (DevExt->ActiveUnit) {
		ScsiPortLogError(DevExt,
				DevExt->ActiveUnit->ActiveCommand,
				DevExt->ActiveUnit->ActiveCommand->PathId,
				DevExt->ActiveUnit->ActiveCommand->TargetId,
				DevExt->ActiveUnit->ActiveCommand->Lun,
				SP_REQUEST_TIMEOUT,
				17);
	}
	*/
	Ns3NotifyCompletion(DevExt, DID_TIME_OUT);
	return FALSE;

} /* end Ns3WaitForReqOff()*/


/*
//-----------------------------------------------------------------------------
//			      RESELECTION
//-----------------------------------------------------------------------------
*/
static boolean Ns3ProcessReselection( IN pnin_softc DevExt )
{
	PSPECIFIC_LU_EXTENSION luExtension;
	Scsi_Cmnd *srb;
	PSPECIFIC_TARGET_EXTENSION targetState;
	int  baseAddress = DevExt->BaseAddress;
	u_char dataByte;

	targetState = &DevExt->TargetState[DevExt->TargetId];

	/**/
	/* Get the specific logical unit extension.*/
	/**/
	Ns3DebugPrint(0x008,(KERN_DEBUG "Ns3ProcessReselection\n"));

	luExtension = ScsiPortGetLogicalUnit(DevExt->TargetId,
					     DevExt->TargetLun);

	DevExt->ActiveUnit = luExtension;

	if (!luExtension || !luExtension->ActiveCommand) {
		/*	SP_INVALID_RESELECTION	ErrorCode,*/
		Ns3DebugPrint(0x10,(KERN_DEBUG "Reselection Failed.\n"));

		/*
		 * Send an abort message.  Put the message-in the buffer, set the
		 * state,  indicate that a disconnect is expected after this, and
		 * set the attention signal.
		 */

		DevExt->MessageBuffer[0] = MSG_ABORT;
		DevExt->MessageCount = 1;

/*		DevExt->AdapterState = MessageOut;*/
/*		DevExt->AdapterFlags &= ~PD_ADAPTER_DISCONNECT_MASK;*/
/*		DevExt->AdapterFlags |= PD_MESSAGE_OUT_VALID |*/
/*					PD_DISCONNECT_EXPECTED;*/

		/*
		 * The target and logical unit specified are not valid.	 A
		 * MESSAGE REJECT message has been set up.  Set ATN and accept the
		 * message.
		 */

		dataByte = SCSI_READ(baseAddress, SCSIBUSCTRL);
		/* ATN ON !-> send-mdg mode*/
		((PSCSI_BUS_CONTROL)&dataByte)->ScsiATN = 1;	
		/* ACK Off !*/
		((PSCSI_BUS_CONTROL)&dataByte)->ScsiACK = 0;	
		SCSI_WRITE(baseAddress , SCSIBUSCTRL, dataByte);
		Ns3NotifyCompletion(DevExt,DID_BUS_BUSY);
		return(FALSE);

	}

	Ns3DebugPrint(0x10,(KERN_DEBUG "Ns3ProResel: Resel Start ID=%d\n",
			    DevExt->TargetId));

	srb = luExtension->ActiveCommand;

#ifdef MUST_USEIO8
	((PTRANSFER_MODE)&DevExt->TransferMode)->AdrData24 = 0;
	((PTRANSFER_MODE)&DevExt->TransferMode)->MemMap8 = 0;		
	((PTRANSFER_MODE)&DevExt->TransferMode)->MemMap16_32 = 0;	
	((PTRANSFER_MODE)&DevExt->TransferMode)->AdrData32 = 0;		
	((PTRANSFER_MODE)&DevExt->TransferMode)->IO8 = 1;			
	((PTRANSFER_MODE)&DevExt->TransferMode)->IO16_32 = 0;
#endif /* 0630 */

	Ns3SetTransferMode( DevExt ); /* TransferModeSet*/
	/*
	//
	// A reselection has been completed.  Set the active logical unit,
	// restore the active data pointer, set the state.
	// In addition, any adapter flags set by a pending select must be
	// cleared using the disconnect mask.
	//
	*/
	DevExt->CurDataPointer = luExtension->SavedDataPointer;
	DevExt->CurDataLength = luExtension->SavedDataLength;
	DevExt->MessageCount = 0;

	dataByte = SCSI_READ(baseAddress, SCSIBUSCTRL);
	((PSCSI_BUS_CONTROL)&dataByte)->ScsiACK = 0;		/* ACK Off !*/
	SCSI_WRITE(baseAddress , SCSIBUSCTRL, dataByte);

	return(TRUE);
}


static boolean Ns3MessageDecode( IN pnin_softc DevExt )
{
	Scsi_Cmnd *srb = DevExt->ActiveUnit->ActiveCommand;
	PSPECIFIC_TARGET_EXTENSION targetState = &DevExt->TargetState[srb ->target];
	PSCSI_EXMSG exMsg;
	long offset;
	long i;
/*	u_long savedAdapterFlags;*/

	exMsg = (PSCSI_EXMSG)DevExt->MessageBuffer;

	switch (exMsg->MessageType) {
	case SCSIMESS_MODIFY_DATA_POINTER:
		/**/
		/* Verify the message length.*/
		/**/
		if (exMsg->MessageLength != SCSIMESS_MODIFY_DATA_LENGTH) {
			/**/
			/* Reject the message.*/
			/**/
			DevExt->MessageCount = 1;
			DevExt->MessageBuffer[0] = MSG_MESSAGE_REJECT;
			return(TRUE);
		}

		/**/
		/* Calculate the modification to be added to the data pointer.*/
		/**/
		offset = 0;
		for (i = 0; i < 4; i++) {
			offset += exMsg->ExArg.MODIFY.modifier[i];
		}

		/**/
		/* Verify that the new data pointer is still within the range*/
		/* of the buffer.*/
		/**/

		if (DevExt->CurDataLength - offset > srb->request_bufflen ||
		    ((long) DevExt->CurDataLength - offset) < 0 ) {
			/**/
			/* The new pointer is not valid, so reject the message.*/
			/**/
			DevExt->MessageCount = 1;
			DevExt->MessageBuffer[0] = MSG_MESSAGE_REJECT;
			return(TRUE);
		}
		/**/
		/* Everything has checked out, so update the pointer.*/
		/**/
		DevExt->CurDataPointer += offset;
		DevExt->CurDataLength -= offset;

		/**/
		/* Everything is ok, so accept the message as is.*/
		/**/
		DevExt->MessageCount = 0;
		DevExt->ScsiState = SC_COMPLETE_OK; /*MessageAccepted;*/
		return(FALSE);

	case SCSIMESS_SYNCHRONOUS_DATA_REQ:
		/**/
		/* A SYNCHRONOUS DATA TRANSFER REQUEST message was received.*/
		/* Make sure the length is correct.*/
		/**/

		if ( exMsg->MessageLength != SCSIMESS_SYNCH_DATA_LENGTH) {
			/**/
			/* The length is invalid reject the message.*/
			/**/
			DevExt->MessageCount = 1;
			DevExt->MessageBuffer[0] = MSG_MESSAGE_REJECT;
			return(TRUE);
		}

		/**/
		/* If synchrouns negotiation has been disabled for this request,*/
		/* then reject any synchronous messages; however, when synchronous*/
		/* transfers are allowed then a new attempt can be made.*/
		/**/

		if (srb != NULL &&
		    !(targetState->TargetFlags & PD_SYNCHRONOUS_TRANSFER_SENT)) {
			/**/
			/* Reject the synchronous transfer message since synchonrous*/
			/* transfers are not desired at this time.*/
			/**/
			DevExt->MessageCount = 1;
			DevExt->MessageBuffer[0] = MSG_MESSAGE_REJECT;
			return(TRUE);
		}
		/**/
		/* Call WdDecodeSynchronousMessage to decode the message and*/
		/* formulate a response if necessary.*/
		/* NcrDecodeSynchronousRequest will return FALSE if the*/
		/* message is not accepable and should be rejected.*/
		/**/
		if (!Ns3DecodeSynchronousRequest(DevExt, targetState, srb->target,
						 (boolean)!(targetState->TargetFlags & PD_SYNCHRONOUS_TRANSFER_SENT) )) {
			/**/
			/* Indicate that a negotiation has been done in the logical*/
			/* unit and clear the negotiation flags.*/
			/**/
			targetState->TargetFlags |= PD_SYNCHRONOUS_NEGOTIATION_DONE;
			targetState->TargetFlags &=~(PD_SYNCHRONOUS_TRANSFER_SENT);

			/**/
			/* The message was not acceptable so send a MESSAGE_REJECT.*/
			/**/
			DevExt->MessageCount = 1;
			DevExt->MessageBuffer[0] = MSG_MESSAGE_REJECT;
			return(TRUE);
		}

		/**/
		/* If a reponse was expected, then set the state for a message-out.*/
		/* Otherwise, NcrDecodeSynchronousRequest has put a reponse*/
		/* in the message buffer to be returned to the target.*/
		/**/

		if (targetState->TargetFlags & PD_SYNCHRONOUS_TRANSFER_SENT){
			/**/
			/* We initiated the negotiation, so no response is necessary.*/
			/**/
			targetState->TargetFlags &= ~PD_SYNCHRONOUS_TRANSFER_SENT;
			targetState->TargetFlags |= PD_SYNCHRONOUS_NEGOTIATION_DONE;
			return(FALSE);
		}

		/**/
		/* Set up the state to send the reponse.  The message count is*/
		/* still correct.*/
		/**/
		DevExt->ScsiState = SC_MSG_OUT;/* MessageOut;*/
		targetState->TargetFlags &= ~PD_SYNCHRONOUS_TRANSFER_SENT;
		return(TRUE);

	case SCSIMESS_WIDE_DATA_REQUEST:
		/**/
		/* A WIDE DATA TRANSFER REQUEST message was received.*/
		/**/
		DevExt->MessageCount = 1;
		DevExt->MessageBuffer[0] = MSG_MESSAGE_REJECT;
		return(TRUE);

	default:
		/**/
		/* This is an unknown or illegal message, so send message REJECT.*/
		/**/
		DevExt->MessageCount = 1;
		DevExt->MessageBuffer[0] = MSG_MESSAGE_REJECT;
		return(TRUE);
	}
}
/*
//-----------------------------------------------------------------------------
//	SYNCHRONOUS_DATA_REQ
//
//Routine Description: Ns3DecodeSynchronousRequest
//
//    This function decodes the synchronous data transfer request message from
//    the target.  It will update the synchronous message in the buffer and the
//    synchronous transfer parameters in the logical unit extension.  These
//    parameters are specific for the WD 53C9X protocol chip.  The updated
//    message in the device extension message buffer might be returned to the
//    target.
//
//    This function should be called before the final byte of the message is
//    accepted from the SCSI bus.
//
//Arguments:
//
//    DevExt - Supplies a pointer to the adapter-specific device
//	  extension.
//
//    LuExtension - Supplies a pointer to the logical unit's device extension.
//	  The synchronous transfer fields are updated  in this structure to
//	  reflect the new parameter in the message.
//
//    ResponseExpected - When set, indicates that the target initiated the
//	  negotiation and that it expects a response.
//
//Return Value:
//
//    TRUE - Returned if the request is acceptable.
//
//    FALSE - Returned if the request should be rejected and a synchronous
//	  transfer should be used.
//
//-----------------------------------------------------------------------------
*/
static boolean Ns3DecodeSynchronousRequest(IN pnin_softc DevExt,
					   PSPECIFIC_TARGET_EXTENSION TargetState,
					   IN u_char TargetID,
					   IN boolean ResponseExpected	)
{
	PSCSI_EXMSG exMsg;
	long period;
	long i;
	u_char	dataByte;

	exMsg = (PSCSI_EXMSG) DevExt->MessageBuffer;

	/**/
	/* Determine the transfer offset.  It is the minimum of the SCSI protocol*/
	/* chip's maximum offset and the requested offset.*/
	/**/
	if (exMsg->ExArg.SYNCS.ReqAckOffset > SYNCHRONOUS_OFFSET) {

		if (!ResponseExpected) {
			/**/
			/* The negotiation failed for some reason, fall back to*/
			/* asynchronous data transfer.*/
			/**/
			TargetState->SynchronousOffset = ASYNCHRONOUS_OFFSET;
			TargetState->SynchronousPeriod = ASYNCHRONOUS_PERIOD;
			TargetState->AckWidth = 0;
			return(FALSE);
		}

		exMsg->ExArg.SYNCS.ReqAckOffset = SYNCHRONOUS_OFFSET;
		TargetState->SynchronousOffset = SYNCHRONOUS_OFFSET;

	} else {
		TargetState->SynchronousOffset = exMsg->ExArg.SYNCS.ReqAckOffset;
	}

	/**/
	/* If the offset requests asynchronous transfers then set the default*/
	/* period and return.*/
	/**/

	if (exMsg->ExArg.SYNCS.ReqAckOffset == ASYNCHRONOUS_OFFSET) 
	{
		TargetState->SynchronousPeriod = ASYNCHRONOUS_PERIOD;
		TargetState->SynchronousOffset = ASYNCHRONOUS_OFFSET;
		TargetState->AckWidth = 0;
		return(TRUE);
	}

	/**/
	/* Check to see if the period is less than the SCSI protocol chip can*/
	/* use.	 If it is then update the message with our minimum and return.*/
	/**/

	if (exMsg->ExArg.SYNCS.TransferPeriod < SYNCHRONOUS_PERIOD ) 
	{
		if (!ResponseExpected) {
			/**/
			/* The negotiation failed for some reason, fall back to*/
			/* asynchronous data transfer.*/
			/**/
			TargetState->SynchronousOffset = ASYNCHRONOUS_OFFSET;
			TargetState->SynchronousPeriod = ASYNCHRONOUS_PERIOD;
			TargetState->AckWidth = 0;
			return(FALSE);
		}

		exMsg->ExArg.SYNCS.TransferPeriod = SYNCHRONOUS_PERIOD;
	}

	period = exMsg->ExArg.SYNCS.TransferPeriod;

	for ( i=0; i<SYNC_TABLE_MAX ; i++) {
		if(	(period >= SyncTable[i].StartPeriod) && 
			(period <= SyncTable[i].EndPeriod) 
		)
			break;
	}
	if (i >= SYNC_TABLE_MAX) {
		/**/
		/* The requested transfer period is too long for the SCSI protocol*/
		/* chip.  Fall back to synchronous and reject the request.*/
		/**/
		TargetState->SynchronousOffset = ASYNCHRONOUS_OFFSET;
		TargetState->SynchronousPeriod = ASYNCHRONOUS_PERIOD;
		TargetState->AckWidth = 0;
		return(FALSE);
	} else {
		TargetState->SynchronousPeriod = SyncTable[i].TransferPeriod;
		TargetState->AckWidth = SyncTable[i].AckWidth;
	}

	/**/
	/* Set the synchronous data transfer parameter registers*/
	/* to the new values.  These must be set before a data transfer*/
	/* is started.	If a response message is received then the parameters*/
	/* must be reset.*/
	/**/

	dataByte = 0;
	((PSYNC_REG)&dataByte)->SyncPeriod = TargetState->SynchronousPeriod;
	((PSYNC_REG)&dataByte)->SyncOffset = TargetState->SynchronousOffset;

	SCSI_WRITE(DevExt->BaseAddress, ACKWIDTH,TargetState->AckWidth);
	SCSI_WRITE(DevExt->BaseAddress, SYNCREG ,dataByte);

	return(TRUE);

}

#ifdef DBG_SHOWCOMMAND
#include "nin_debug.c"
#endif	/* DBG_SHOWCOMMAND */

/*====================================================================*/
static void cs_error(client_handle_t handle, int func, int ret)
{
	error_info_t err = { func, ret };
	CardServices(ReportError, handle, &err);
}

#ifdef USE_IRQ_HANDLE_PRESENT
static void ninja3_interrupt2(int irq, void *dev_id, struct pt_regs *regs)
{
	int *unused;

	ninja3_interrupt(unused);
}
#endif

/*======================================================================
    ninja3_attach() creates an "instance" of the driver, allocating
    local data structures for one device.  The device is registered
    with Card Services.

    The dev_link structure is initialized, but we don't actually
    configure the card at this point -- we wait until we receive a
    card insertion event.
======================================================================*/
static dev_link_t *ninja3_attach(void)
{
	scsi_info_t *info;
	client_reg_t client_reg;
	dev_link_t *link;
	int ret;

	DEBUG(0, __FUNCTION__ "()\n");

	/* Create new SCSI device */
	info = kmalloc(sizeof(*info), GFP_KERNEL);
	if (!info) return NULL;
	memset(info, 0, sizeof(*info));
	link = &info->link;
	link->priv = info;
	link->release.function = &ninja3_release;
	link->release.data = (u_long)link;

	/* The io structure describes IO port mapping */
	link->io.NumPorts1 = 16;
	link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
	link->io.IOAddrLines = 5;	/* not used */

	/* Interrupt setup */
#ifdef USE_IRQ_HANDLE_PRESENT
	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE| IRQ_HANDLE_PRESENT;
#else
	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
#endif
	link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
	link->irq.IRQInfo2 = irq_mask;
    
	/* General socket configuration */
	link->conf.Attributes = CONF_ENABLE_IRQ;
	link->conf.Vcc = 50;
	link->conf.IntType = INT_MEMORY_AND_IO;
	link->conf.Present = PRESENT_OPTION;

#ifdef USE_IRQ_HANDLE_PRESENT
	link->irq.Handler = &ninja3_interrupt2;
#else
	link->irq.Handler = NULL;
#endif

	/* Register with Card Services */
	link->next = dev_list;
	dev_list = link;
	client_reg.dev_info = &dev_info;
	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
	client_reg.EventMask =
		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
	client_reg.event_handler = &ninja3_event;
	client_reg.Version = 0x0210;
	client_reg.event_callback_args.client_data = link;
	ret = CardServices(RegisterClient, &link->handle, &client_reg);
	if (ret != CS_SUCCESS) {
		cs_error(link->handle, RegisterClient, ret);
		ninja3_detach(link);
		return NULL;
	}

	return link;
} /* ninja3_attach */


/*======================================================================
    This deletes a driver "instance".  The device is de-registered
    with Card Services.	 If it has been released, all local data
    structures are freed.  Otherwise, the structures will be freed
    when the device is released.
======================================================================*/

static void ninja3_detach(dev_link_t *link)
{
	dev_link_t **linkp;

	DEBUG(0, "ninja3_detach(0x%p)\n", link);
    
	/* Locate device structure */
	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
		if (*linkp == link)
			break;
	if (*linkp == NULL)
		return;

	/*
	  If the device is currently configured and active, we won't
	  actually delete it yet.  Instead, it is marked so that when
	  the release() function is called, that will trigger a proper
	  detach().
	  */
	if (link->state & DEV_CONFIG) {
#ifdef PCMCIA_DEBUG
		Ns3DebugPrint(0x10,(KERN_DEBUG "ninja3_cs: detach postponed, '%s' still locked\n", link->dev->dev_name));
#endif
		ninja3_release((u_long)link);
		if (link->state & DEV_STALE_CONFIG) {
			link->state |= DEV_STALE_LINK;
			return;
		}
	}

	/* Break the link with Card Services */
	if (link->handle)
		CardServices(DeregisterClient, link->handle);

	/* Unlink device structure, free bits */
	*linkp = link->next;
	kfree(link->priv);

} /* ninja3_detach */


/*======================================================================
    ninja3_config() is scheduled to run after a CARD_INSERTION event
    is received, to configure the PCMCIA socket, and to make the
    ethernet device available to the system.
======================================================================*/
#define CS_CHECK(fn, args...) \
while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed
#define CFG_CHECK(fn, args...) \
if (CardServices(fn, args) != 0) goto next_entry
/*====================================================================*/

static void ninja3_config(dev_link_t *link)
{
	client_handle_t handle = link->handle;
	scsi_info_t *info = link->priv;
	tuple_t tuple;
	cisparse_t parse;
	int i, last_ret, last_fn;
	u_char tuple_data[64];
	config_info_t conf;
#ifdef GET_SCSI_INFO
	Scsi_Device *dev;
	dev_node_t **tail, *node;
	struct Scsi_Host *host;
#endif


	tuple.DesiredTuple = CISTPL_CONFIG;
	tuple.Attributes = 0;
	tuple.TupleData = tuple_data;
	tuple.TupleDataMax = sizeof(tuple_data);
	tuple.TupleOffset = 0;
	CS_CHECK(GetFirstTuple, handle, &tuple);
	CS_CHECK(GetTupleData, handle, &tuple);
	CS_CHECK(ParseTuple, handle, &tuple, &parse);
	link->conf.ConfigBase = parse.config.base;
	link->conf.Present = parse.config.rmask[0];

	/* Configure card */
	driver_template.module = &__this_module;
	link->state |= DEV_CONFIG;

	/* Look up the current Vcc */
	CS_CHECK(GetConfigurationInfo, handle, &conf);
	link->conf.Vcc = conf.Vcc;

	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
	CS_CHECK(GetFirstTuple, handle, &tuple);
	while (1) {
		CFG_CHECK(GetTupleData, handle, &tuple);
		CFG_CHECK(ParseTuple, handle, &tuple, &parse);
		link->conf.ConfigIndex = parse.cftable_entry.index;
		link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
		i = CardServices(RequestIO, handle, &link->io);
		if (i == CS_SUCCESS) break;
	next_entry:
		Ns3DebugPrint(0x10,(KERN_DEBUG "ninja3_config next\n"));
		CS_CHECK(GetNextTuple, handle, &tuple);
	}

	CS_CHECK(RequestIRQ, handle, &link->irq);
	CS_CHECK(RequestConfiguration, handle, &link->conf);

	/* A bad hack... */
	release_region(link->io.BasePort1, link->io.NumPorts1);

	/* Set port and IRQ */
	nin_data.BaseAddress = link->io.BasePort1;
	nin_data.NumAddress = link->io.NumPorts1;
	nin_data.IrqNumber = link->irq.AssignedIRQ;

	Ns3DebugPrint(0x10,(KERN_DEBUG "ninja3_config I/Obase[%x]\n",
			    nin_data.BaseAddress));

	if( !Ns3Initialize() ){
		goto cs_failed;
	}

	scsi_register_module(MODULE_SCSI_HA, &driver_template);

	Ns3DebugPrint(0x10,(KERN_DEBUG "GET_SCSI_INFO\n"));
	tail = &link->dev;
	info->ndev = 0;
	for (host = scsi_hostlist; host != NULL; host = host->next) {
		if (host->hostt == &driver_template) {
			for (dev = host->host_queue; dev != NULL; dev = dev->next) {
				u_long arg[2], id;
				kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg);
				id = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) +
					((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000);
				node = &info->node[info->ndev];
				node->minor = 0;
				switch (dev->type) {
				case TYPE_TAPE:
					node->major = SCSI_TAPE_MAJOR;
					sprintf(node->dev_name, "st#%04lx", id);
					break;
				case TYPE_DISK:
				case TYPE_MOD:
					node->major = SCSI_DISK0_MAJOR;
					sprintf(node->dev_name, "sd#%04lx", id);
					break;
				case TYPE_ROM:
				case TYPE_WORM:
					node->major = SCSI_CDROM_MAJOR;
					sprintf(node->dev_name, "sr#%04lx", id);
					break;
				default:
					node->major = SCSI_GENERIC_MAJOR;
					sprintf(node->dev_name, "sg#%04lx", id);
					break;
				}
				*tail = node; tail = &node->next;
				info->ndev++;
			}
		}
	}
	*tail = NULL;
	if (info->ndev == 0) {
#ifdef DBG_PRINT
		Ns3DebugPrint(0x10,(KERN_DEBUG "ninja3_cs: no SCSI devices found\n"));
#else
		printk(KERN_INFO "ninja3_cs: no SCSI devices found\n");
#endif
	}

	/* Finally, report what we've done */
	printk(KERN_INFO "ninja3: index 0x%02x: Vcc %d.%d",
	       link->conf.ConfigIndex,
	       link->conf.Vcc/10, link->conf.Vcc%10);
	if (link->conf.Vpp1)
		printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);
	if (link->conf.Attributes & CONF_ENABLE_IRQ)
		printk(", irq %d", link->irq.AssignedIRQ);
	if (link->io.NumPorts1)
		printk(", io 0x%04x-0x%04x", link->io.BasePort1,
		       link->io.BasePort1+link->io.NumPorts1-1);
	printk("\n");

	link->state &= ~DEV_CONFIG_PENDING;
	return;

cs_failed:
	cs_error(link->handle, last_fn, last_ret);
	ninja3_release((u_long)link);
	return;

} /* ninja3_config */
#undef CS_CHECK
#undef CFG_CHECK

/*======================================================================

    After a card is removed, ninja3_release() will unregister the net
    device, and release the PCMCIA configuration.  If the device is
    still open, this will be postponed until it is closed.
    
======================================================================*/

static void ninja3_release(u_long arg)
{
	dev_link_t *link = (dev_link_t *)arg;
	/*local_info_t	 scsi_info_t *local = link->priv;	*/


	DEBUG(0, "ninja3_release(0x%p)\n", link);

	/*
	  If the device is currently in use, we won't release until it
	  is actually closed.
	  */
	if (link->open) {
		DEBUG(1, "ninja3_cs: release postponed, '%s' still open\n",
		      link->dev->dev_name);
		link->state |= DEV_STALE_CONFIG;
		return;
	}

	/* Unlink the device chain */
	scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
	link->dev = NULL;

	/* Don't bother checking to see if these succeed or not */

	CardServices(ReleaseWindow, link->win);
	CardServices(ReleaseConfiguration, link->handle);
	CardServices(ReleaseIO, link->handle, &link->io);
	CardServices(ReleaseIRQ, link->handle, &link->irq);
	link->state &= ~DEV_CONFIG;

	if (link->state & DEV_STALE_LINK)
		ninja3_detach(link);

} /* ninja3_release */

/*======================================================================

    The card status event handler.  Mostly, this schedules other
    stuff to run after an event is received.  A CARD_REMOVAL event
    also sets some flags to discourage the net drivers from trying
    to talk to the card any more.

    When a CARD_REMOVAL event is received, we immediately set a flag
    to block future accesses to this device.  All the functions that
    actually access the device should check this flag to make sure
    the card is still present.
    
======================================================================*/

static int ninja3_event(event_t event, int priority,
			event_callback_args_t *args)
{
	dev_link_t *link = args->client_data;

	DEBUG(1, "ninja3_event(0x%06x)\n", event);

	switch (event) {
	case CS_EVENT_CARD_REMOVAL:
		Ns3DebugPrint(0x10,(KERN_DEBUG "event: remove\n"));
		link->state &= ~DEV_PRESENT;
		if (link->state & DEV_CONFIG) {
			link->release.expires = RUN_AT(HZ/20);
			add_timer(&link->release);
		}
		break;
	case CS_EVENT_CARD_INSERTION:
		Ns3DebugPrint(0x10,(KERN_DEBUG "event: insert\n"));
		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
		ninja3_config(link);
		break;
	case CS_EVENT_PM_SUSPEND:
		link->state |= DEV_SUSPEND;
		/* Fall through... */
	case CS_EVENT_RESET_PHYSICAL:
		if (link->state & DEV_CONFIG)
			CardServices(ReleaseConfiguration, link->handle);
		break;
	case CS_EVENT_PM_RESUME:
		link->state &= ~DEV_SUSPEND;
		/* Fall through... */
	case CS_EVENT_CARD_RESET:
		Ns3DebugPrint(0x10,(KERN_DEBUG "event: reset\n"));
		if (link->state & DEV_CONFIG) {
			CardServices(RequestConfiguration, link->handle, &link->conf);
			ninja3_reset(NULL, 0);
		}
		break;
	default:
		Ns3DebugPrint(0x10,(KERN_DEBUG "event: unknown\n"));
	}
	Ns3DebugPrint(0x10,(KERN_DEBUG "ninja3_event end\n"));
	return 0;
} /* ninja3_event */

/*----------------------------------------------------------------*/
/* look for ninja3 card and init if found			  */
/*----------------------------------------------------------------*/
static int ninja3_detect(Scsi_Host_Template * host)
{
	struct Scsi_Host *hreg;	/* registered host structure */
	nin_softc *p = &nin_data;

	/*Ns3DebugPrint(0x10,(KERN_DEBUG __FUNCTION__ " host=%p,nin_data=%p this_id=%d\n", host, &nin_data, host->this_id));*/

#if KERNEL_VERSION(2,3,99) > LINUX_VERSION_CODE
	host->proc_dir =  &proc_scsi_ninja3; /* kernel 2.2 */
#else
        host->proc_name = "ninja3"; /* kernel 2.3 */
#endif

	p->HostId = host->this_id;
	if (p->HostId < 0)
		p->HostId = SCSI_INITIATOR_ID; /* if no ID, use 7 */

	Ns3DebugPrint(0x10,(KERN_DEBUG "ninja3_detect: I/O[%x+%x] hostid[%x] irq[%x]\n",
			    p->BaseAddress,
			    p->NumAddress,
			    p->HostId,
			    p->IrqNumber));

	request_region(p->BaseAddress, 0x10 ,"nin_cs");
	hreg = scsi_register(host, 0); /* no host data */
	hreg->io_port = p->BaseAddress;
	hreg->n_io_port = 0x10;
	hreg->dma_channel = -1;
	if(p->IrqNumber != -1)
		hreg->irq = p->IrqNumber;

	sprintf(ns3info,
/* Buffer size is 100 bytes */
/*  0	      1		2	  3	    4	      5		6	  7	    8	      9		0*/
/*  01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890*/
   "NinjaSCSI-3/32Bi Driver version 1.0, I/O 0x%04x-0x%04x IRQ %2d ID %1d, Chip ID %1d/Rev %1d",
		p->BaseAddress, p->BaseAddress + p->NumAddress,
		p->IrqNumber, p->HostId, p->ChipID, p->ChipRev);
	host->name = ns3info;
	Ns3DebugPrint(0x10,(KERN_DEBUG "ninja3_detect end\n"));

	return 1; /* detect done. */
}


/*----------------------------------------------------------------*/
/* return info string						  */
/*----------------------------------------------------------------*/
static const char *ninja3_info(struct Scsi_Host * host)
{
	return ns3info;
}

/*----------------------------------------------------------------*/
/* return bios parameters					  */
/*----------------------------------------------------------------*/
int ninja3_biosparam(Disk * disk, kdev_t dev, int ip[])
{
	ip[0] = 0x40;
	ip[1] = 0x20;
	ip[2] = disk->capacity / (ip[0] * ip[1]);
	if (ip[2] > 1024) {
		ip[0] = 0xff;
		ip[1] = 0x3f;
		ip[2] = disk->capacity / (ip[0] * ip[1]);
		if (ip[2] > 1023)
			ip[2] = 1023;
	}
	return 0;
}

/*----------------------------------------------------------------*/
/* abort command in progress					  */
/*----------------------------------------------------------------*/
static int ninja3_abort(Scsi_Cmnd * cmd)
{
	ns3abort = 1;
	Ns3DebugPrint(0x10,(KERN_DEBUG "ninja3_abort\n"));
	/* ns3_zap(); */
	Ns3ResetScsiBus(&nin_data);

	return 0;
}

/*----------------------------------------------------------------*/
/* reset SCSI bus						  */
/*----------------------------------------------------------------*/
static int ninja3_reset(Scsi_Cmnd * cmd, unsigned int why)
{
	ns3abort = 2;
	Ns3DebugPrint(0x10,(KERN_DEBUG "ninja3_reset / bus unlock - %d\n", why));
	/* ns3_zap(); */
	Ns3ResetScsiBus(&nin_data);
	cmd->result = DID_RESET << 16;
	cmd->scsi_done(cmd);
	ns3abort = 0;
	return 1;
}


/*static int ninjs3_eh_strategy(struct Scsi_Host *)
{
}
static int ninja3_eh_abort(Scsi_Cmnd * cmd)
{
	Ns3DebugPrint(0x2,(KERN_DEBUG __FUNCTION__"\n"));
}
static ninja3_eh_device_reset(Scsi_Cmnd *)
{
}
static ninja3_eh_bus_reset(Scsi_Cmnd *)
{
}
static ninja3_eh_host_reset(Scsi_Cmnd *)
{
}*/

/*======================================================================*
 *	module entry point
 *====================================================================*/
static int __init init_nin_cs(void)
{
	servinfo_t serv;

	DEBUG(0, "%s\n", version);
	CardServices(GetCardServicesInfo, &serv);
	if (serv.Revision != CS_RELEASE_CODE) {
		printk(KERN_DEBUG "Ninja3: Card Services release "
		       "does not match!\n");
		return -1;
	}
	register_pcmcia_driver(&dev_info, &ninja3_attach, &ninja3_detach);
	return 0;
}


static void __exit exit_nin_cs(void)
{
	DEBUG(0, "ninja3_cs: unloading\n");
	unregister_pcmcia_driver(&dev_info);
	while (dev_list != NULL) {
		if (dev_list->state & DEV_CONFIG)
			ninja3_release((u_long)dev_list);
		ninja3_detach(dev_list);
	}
}

module_init(init_nin_cs);
module_exit(exit_nin_cs);

/*
 *
 *
 */

/* end */
