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

  Copyright(c) 2002 - 2005 Promise Technology, Inc. All rights reserved.
  
  cam_ata.c - CAM ATA module functions

  This program is free software; you can redistribute it and/or modify it 
  under the terms of the GNU General Public License as published by the Free 
  Software Foundation; either version 2 of the License, or (at your option) 
  any later version.
  
  This program is distributed in the hope that it will be useful, but WITHOUT 
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
  more details.
  
  You should have received a copy of the GNU General Public License along with
  this program; if not, write to the Free Software Foundation, Inc., 59 
  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  
  The full GNU General Public License is included in this distribution in the
  file called LICENSE.
  
  Contact Information:
  Promise Technology, Inc.
  <support@promise.com.tw>	[TAIWAN]
  <support@promise.com>		[U.S.A]
  <support-china@promise.com>	[CHINA]

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

#include "cam_con.h"
#include "cam_def.h"
#include "cam_imp.h"
#include "cam_macr.h"
#include "cam_gb.h"
#include "cam_exp.h"


U8 IssueIdentify(U8 bCh, U8 bID, PU8 pBuf, U8 command);
U8 CAMInitDevice(PDEV_CONFIG pDevConfig);
void prepareATAPacket(PCAM_ATA_PACKET CAM_ATAPacket,PCAM_ATA_SG CAM_ATASG,PATA_TASK pATATask);
U8 WaitOnBusy(U32 IDEBaseAddress);
U8 WaitOnBaseBusy(U32 IDEBaseAddress);
void AtapiSoftReset(U32 IDEBaseAddress, U8 DeviceNumber);
U8 WaitForDrq(U32 IDEBaseAddress);
U8 WaitOnReady(U8 bChannelNumber);
U8 WaitForINT(U32 IDEBaseAddress);
U8 Put2ATAQueue(PCAM_ATA_PACKET CAM_ATAPacket,U8 direction);

void InternalATAReturn(PATA_TASK pATATask)
{
	U8 bCh=pATATask->bCh;
	
 	/*For SATA channel. After SET Feature command, 
        	program BA#3 offset 24Ch/2CCh/34Ch/3CCh to 5FDF0020h,
               	and BA#3 offset 250h/2D0h/350h/3D0h to 03CB014Ah,
    		no matter what PIO mode and UDMA mode reported by HD */
    	
	if (gChnlConfig[bCh].ChnlType == CHNL_SATA ) {
		WriteIndexUlong( ATABaseAddr[bCh], iNDEXIDEDrvTiming1, 0x25CB014A);
	}
	return;
}

U8 CAM_ConfigATADevice(PDEV_CONFIG pDevConfig)
{
	U8			bCh=pDevConfig->bCh;
	U8			bID=pDevConfig->bID;
	U8			bTmp;
	PDEV_CONFIG pCurDevConfig = &gDrvConfig[bCh][bID];
	PDEV_CONFIG pNxtDevConfig = &gDrvConfig[bCh][(bID+1)&0x01];
	PATA_TASK pATATask = &InternalATATask[bCh][bID];
	PATA_TASK pATANxtTask = &InternalATATask[bCh][(bID+1)&0x01];
	
	U8 bAdapterNumber = bCh/MAX_ATA_CHNL;
	PCAM_ATA_PACKET CAM_ATAPacket;
	PCAM_ATA_SG CAM_ATASG;	
	
	if (bID > 1)
		return(camFAIL);
		
	if (!(pCurDevConfig->DevFlag & DEV_EXIST))
		return(camFAIL); /* no drive */
		
	if( ( gChnlConfig[bCh].CableType < CABLE_80 )
			  ||(  gChnlConfig[bCh].ChnlSpeed < CHNL_U100 ) )	/* the channle support upto Ultra DMA mode 2 */
	{
		if (pDevConfig->UDMAMode > 2)
			pDevConfig->UDMAMode = 2;
	}
			
	if (  gChnlConfig[bCh].ChnlSpeed < CHNL_U133 )	/* the channel support upto Ultra DMA mode 5 */
	{
		if (pDevConfig->UDMAMode > 5)
			pDevConfig->UDMAMode = 5;
	}		
		
	if (pCurDevConfig->UDMAMode != 0xFF) 
	{
		if (pCurDevConfig->UDMAMode == pDevConfig->UDMAMode)
			return (camSUCCESS);	/* no change of udma mode */
	}
	else if (pCurDevConfig->MDMAMode != 0xFF) 
	{
		if (pCurDevConfig->MDMAMode == pDevConfig->MDMAMode)
			return (camSUCCESS);	/* no change of dma mode(not support udma mode) */		
	}
			
	/* get the user setting, only can down speed */
	if ( (pCurDevConfig->UDMAMode != 0xFF) 
	  && (pCurDevConfig->UDMAMode > pDevConfig->UDMAMode ) )
		pCurDevConfig->UDMAMode = pDevConfig->UDMAMode;	
		
	if ( (pCurDevConfig->MDMAMode != 0xFF) 
	  && (pCurDevConfig->MDMAMode > pDevConfig->MDMAMode ) )
		pCurDevConfig->MDMAMode = pDevConfig->MDMAMode;	
	
	/* master/slave drive must run at the same transfer timing */
	bTmp = 0xFF;
	if (pNxtDevConfig->DevFlag & DEV_EXIST)	
	{
		/* master/slave drive must run at the same transfer timing */
		if ( (pNxtDevConfig->UDMAMode != 0xFF)
		  && (pCurDevConfig->UDMAMode != 0xFF) ) 
		{
			if ( pCurDevConfig->UDMAMode >= pNxtDevConfig->UDMAMode )
				pCurDevConfig->UDMAMode =  pNxtDevConfig->UDMAMode;
			else {
				bTmp = pNxtDevConfig->UDMAMode;
				pNxtDevConfig->UDMAMode = pCurDevConfig->UDMAMode;
			}
		}
		if ( (pNxtDevConfig->MDMAMode != 0xFF)
		  && (pCurDevConfig->MDMAMode != 0xFF) ) 
		{
			if ( pCurDevConfig->MDMAMode >= pNxtDevConfig->MDMAMode )
				pCurDevConfig->MDMAMode =  pNxtDevConfig->MDMAMode;
			else {
				bTmp = pNxtDevConfig->MDMAMode;
				pNxtDevConfig->MDMAMode = pCurDevConfig->MDMAMode;
			}
		}
	}

	if (bTmp != 0xFF)	/* with master/slave, and need set feature for the other */
	{
		/* set feature mode for DMA/UDMA */
		pATANxtTask->bCh = bCh;
		pATANxtTask->bID = (bID+1)&0x01;
		pATANxtTask->callback = InternalATAReturn;		

		pATANxtTask->ATACmdFlag = ATA_DEVICE;
		pATANxtTask->Cmd.ATACmd.bCmd = IDE_COMMAND_SET_FEATURES;
		pATANxtTask->Cmd.ATACmd.bFeature=0x03;

		if ( pNxtDevConfig->UDMAMode != 0xFF )
			pATANxtTask->Cmd.ATACmd.bCount = (U8)(pNxtDevConfig->UDMAMode | 0x40);
		else
			pATANxtTask->Cmd.ATACmd.bCount = (U8)(pNxtDevConfig->MDMAMode | 0x20);
		
		pATANxtTask->Cmd.ATACmd.LBAl = 0;
		pATANxtTask->Cmd.ATACmd.LBAh = 0;
	
		/* get free packet address */
		CAM_ATAPacket= CAMAllocPacket(bAdapterNumber, ATA_PAC);

		if (CAM_ATAPacket==(PVOID)U32NULL){	/* no free ata packet. */
			return(camFAIL);
		}	

		/* get free SG address */
		CAM_ATASG=CAMAllocSG(bAdapterNumber, ATA_PAC);
	
		if (CAM_ATASG==(PVOID)U32NULL){	/* no free ata sg. */
			CAMFreePacket(bAdapterNumber, ATA_PAC, (PVOID)CAM_ATAPacket);
			return(camFAIL);
		}

		/* prepare ata packet */
		prepareATAPacket(CAM_ATAPacket,CAM_ATASG,pATANxtTask);
	
		/* put the atapacket to the haed of ata queue */
		Put2ATAQueue(CAM_ATAPacket,QUEUEHead);

		/* start ata module */
		StartATAOperation(pATANxtTask->bCh);	
	}

	if ( (pCurDevConfig->UDMAMode != 0xFF) || (pCurDevConfig->MDMAMode != 0xFF) )
	{
		/* set feature mode for DMA/UDMA */
		pATATask->bCh = bCh;
		pATATask->bID = bID;
		pATATask->callback = InternalATAReturn;		

		pATATask->ATACmdFlag = ATA_DEVICE;
		pATATask->Cmd.ATACmd.bCmd = IDE_COMMAND_SET_FEATURES;
		pATATask->Cmd.ATACmd.bFeature=0x03;

		if ( pCurDevConfig->UDMAMode != 0xFF )
			pATATask->Cmd.ATACmd.bCount = (U8)(pCurDevConfig->UDMAMode | 0x40);
		else
			pATATask->Cmd.ATACmd.bCount = (U8)(pCurDevConfig->MDMAMode | 0x20);
		
		pATATask->Cmd.ATACmd.LBAl = 0;
		pATATask->Cmd.ATACmd.LBAh = 0;
	

		/* get free packet address */
		CAM_ATAPacket= CAMAllocPacket(bAdapterNumber, ATA_PAC);

		if (CAM_ATAPacket==(PVOID)U32NULL){	/* no free ata packet. */
			return(camFAIL);
		}	

		/* get free SG address */
		CAM_ATASG=CAMAllocSG(bAdapterNumber, ATA_PAC);
	
		if (CAM_ATASG==(PVOID)U32NULL){	/* no free ata sg. */
			CAMFreePacket(bAdapterNumber, ATA_PAC, (PVOID)CAM_ATAPacket);
			return(camFAIL);
		}

		/* prepare ata packet */
		prepareATAPacket(CAM_ATAPacket,CAM_ATASG,pATATask);
	
		/* put the atapacket to the haed of ata queue */
		Put2ATAQueue(CAM_ATAPacket,QUEUEHead);

		/* start ata module */
		StartATAOperation(pATATask->bCh);
	}


	if (bTmp != 0xFF)
		return (camWARNING);
	return (camSUCCESS);
}

U8 CAM_GetATADeviceConfig(PDEV_CONFIG pDevConfig)
{
	U8			bCh=pDevConfig->bCh;
	U8			bID=pDevConfig->bID;
	PDEV_CONFIG	pCurDevConfig = &gDrvConfig[bCh][bID]; 
	PDEV_CONFIG pNxtDevConfig = &gDrvConfig[bCh][(bID+1)&0x01];
	U32			BaseIOAddress = ATABaseAddr[bCh];
	U8			statusByte;
	U8			signatureLow, signatureHigh;
	U8			i,bTmp;
	U8			bAdapterNumber = bCh/MAX_ATA_CHNL;
	PCAM_IDENTIFY_DATA	pIdentifybuf = &gIdentify_Data[bCh][bID];
	
	/* if master drive is in the swapbox, don't try to find slave drive */
	if(( bID == 1 ) && (pNxtDevConfig->pEnclosure)) {
		pDevConfig->DevFlag = DEV_NOTFOUND;
		return(camDEVICE_NOT_FOUND);
	}
	
	if ( (bCh >= MAX_ATA_MODULE )|| (bID > 1) ) {
		pDevConfig->DevFlag = DEV_NOTFOUND;
		return(camDEVICE_NOT_FOUND);
	}
	
	if ( gChnlConfig[bCh].bCh == camCHNL_NOT_FOUND )
		return (camDEVICE_NOT_FOUND);	
	
	if( ( pCurDevConfig->DevFlag & DEV_EXIST ) 
	 && (!(pCurDevConfig->pEnclosure) || ( gBOXStatus[bCh].NeedCheck == FALSE) ) ) 	
	{
		*pDevConfig = *pCurDevConfig;
		return(camSUCCESS);
	}

	pCurDevConfig->DevFlag = DEV_NOTFOUND;
	
	/* first init device or just plug-in new device */
	/* Check if the device in swapbox */

	if (gBOXConfig[bCh].BOXType == camUNKNOWNBOX )
	{	
		bTmp = CAM_EnumEnclosure( bCh, (PENCLOSURE_TYPE)&gBOXConfig[bCh]);
		if ( bTmp == 0xFF ) 
			pCurDevConfig->pEnclosure = 0;	
		else
			pCurDevConfig->pEnclosure = &gBOXConfig[bTmp];
	}
	
	if ( pCurDevConfig->pEnclosure )
	{
		gBOXStatus[bCh].NeedCheck = FALSE;
		/* make sure the power is on */
		CAM_Enclosure_PowerOn(pCurDevConfig->pEnclosure->BOXID);
		camStallExecution(100);/* wait a while */
		if(gBOXStatus[bCh].PowerState == PowerOFF)
			return (camDEVICE_NOT_FOUND); /* no device */

	}

	/* disable INTA here, it will be re-enable when CAM use SEQ 0 for packets */
	WriteIndexUchar(BaseIOAddress, iNDEXIDECICR, 0x0);  /* that the drive INT pass to SEQ 0*/
	WritePortUchar( HostBaseAddr[bAdapterNumber], 0, 0x20); /* but mask SEQ 0 INT */
	
	/* select drive */	
	WriteIndexUchar(BaseIOAddress, iNDEXIDEDeviceHead, (U8)(((bID & 0x01) << 4) | 0xA0));
	/* read drive status */
	if ( WaitOnBaseBusy(BaseIOAddress) & 0x80) {
		return (camDEVICE_NOT_FOUND); /* no device */
	}
	
	if (!(gChnlConfig[bCh].ChnlType == CHNL_SATA))
	{
		WriteIndexUchar(BaseIOAddress, iNDEXIDEDeviceHead, (U8)(((bID & 0x01) << 4) | 0xA0));
		WriteIndexUchar(BaseIOAddress, iNDEXIDECylinderLow, 0x55 );
		WriteIndexUchar(BaseIOAddress, iNDEXIDECylinderHigh, 0xAA );
		statusByte = ReadIndexUchar( BaseIOAddress, iNDEXIDECylinderLow);
		if ( statusByte != 0x55 )
			return(camDEVICE_NOT_FOUND); /* no device */
	}
	
	/* ATA or ATAPI device ? */
	AtapiSoftReset(BaseIOAddress, bID);
	signatureLow = ReadIndexUchar(BaseIOAddress, iNDEXIDECylinderLow);
	signatureHigh = ReadIndexUchar(BaseIOAddress, iNDEXIDECylinderHigh);

	/* issue identify command */ 
	if (signatureLow == 0x14 && signatureHigh == 0xEB) {
		/*
		 * ATAPI signature found, Issue ATAPI packet identify command.
		 */ 
		if ( IssueIdentify( bCh,
							bID,
							(PU8)pIdentifybuf,
							IDE_COMMAND_ATAPI_IDENTIFY) == camFAIL ) 								
			return(camDEVICE_NOT_FOUND);
		else {
			pCurDevConfig->DevFlag = DEV_EXIST+DEV_ATAPI_DEVICE;
			if ( pIdentifybuf->GeneralConfiguration & 0x20 )
				pCurDevConfig->DevFlag |= DEV_INT_DRQ;
		}

	}
	else {
		/*
		 * Issue IDE Identify. 
		 */
		if ( IssueIdentify( bCh, bID, (PU8)pIdentifybuf, IDE_COMMAND_IDENTIFY)  == camFAIL ) {
			if ( IssueIdentify( bCh, bID, (PU8)pIdentifybuf, IDE_COMMAND_IDENTIFY)  == camFAIL )			      			
				return(camDEVICE_NOT_FOUND);
		}
		pCurDevConfig->DevFlag = DEV_EXIST+DEV_ATA_DEVICE;
	}
	
	/* put parameters to device info structure */
	for ( i = 0; i < 11; i++ ) {
		bTmp =(U8)pIdentifybuf->ModelNumber[i];
		pIdentifybuf->ModelNumber[i] >>= 8;
		pIdentifybuf->ModelNumber[i] |= (U16)bTmp << 8;
		*(PU16)(&pCurDevConfig->Model[i*2]) = pIdentifybuf->ModelNumber[i];
	}
	pCurDevConfig->Model[21] = (U8)0;		/* end of string */
	pCurDevConfig->CylNum = pIdentifybuf->NumberOfCylinders;
	pCurDevConfig->HeadNum = (U8)pIdentifybuf->NumberOfHeads;
	pCurDevConfig->SecPerTrk = (U8)pIdentifybuf->SectorsPerTrack;
		
	if (pIdentifybuf->CommandSetSupport2 & bit(10)){
		pCurDevConfig->DevFlag |= DEV_48BIT;
		pCurDevConfig->MAXLBAL = *((PU32)&pIdentifybuf->MaxLBA1);
		pCurDevConfig->MAXLBAH = *((PU32)&pIdentifybuf->MaxLBA3);
	}
	else {
		pCurDevConfig->MAXLBAL = *((U32 FARPTR *)&pIdentifybuf->UserAddressableSectors1); 
		pCurDevConfig->MAXLBAH = (U32)0;
	}
	if ( pIdentifybuf->MajorRevision != 0xFFFF && (pIdentifybuf->MajorRevision & bit(5)) )
		pCurDevConfig->DevFlag |= DEV_ATA5;

	/* Get Transfer mode */	
	if ( (pIdentifybuf->FieldsValid & 0x02) && (pIdentifybuf->AdvancedPIOModes & 0xf)
	  && (!pCurDevConfig->pEnclosure) )
	{
		U8 bPIO = (U8)pIdentifybuf->AdvancedPIOModes;
		if ( bPIO >= 0x02)
	  		pCurDevConfig->PIOMode = 0x04; 
		else
	  		pCurDevConfig->PIOMode = 0x03; 
	}
	else {
		pCurDevConfig->PIOMode = 0x02;
	}
    
	pCurDevConfig->MDMAMode = 0xFF;
	pCurDevConfig->UDMAMode = 0xFF;   
    
	if ( (pIdentifybuf->FieldsValid & 0x02) && (pIdentifybuf->MultiWordDMAModes & 0xf))
	{
		U8	bMultiDMA = (U8)pIdentifybuf->MultiWordDMAModes;
		while( bMultiDMA & 0x01 ) {
			pCurDevConfig->MDMAMode++;
			 bMultiDMA >>= 1;
	  	}
	}
	if ( (pIdentifybuf->FieldsValid & 0x04) &&
		(pIdentifybuf->CommandSetSupport7 & 0x7f))
	{
		U8	UMode = (U8)pIdentifybuf->CommandSetSupport7;
    	
		if( ( gChnlConfig[bCh].CableType < CABLE_80 )
		  ||(  gChnlConfig[bCh].ChnlSpeed < CHNL_U100 ) )
			UMode &= 0x07;
			
		if (  gChnlConfig[bCh].ChnlSpeed < CHNL_U133 )
			UMode &= 0x3F;
			
   		while (UMode & 0x01) {
   			pCurDevConfig->UDMAMode++;
   			UMode >>= 1;
		}
	}	
	
	bTmp = 0xFF;
	if (pNxtDevConfig->DevFlag & DEV_EXIST)	
	{
		/* master/slave drive must run at the same transfer timing */
		if ( (pNxtDevConfig->UDMAMode != 0xFF)
		  && (pCurDevConfig->UDMAMode != 0xFF) ) 
		{
			if ( pCurDevConfig->UDMAMode >= pNxtDevConfig->UDMAMode )
				pCurDevConfig->UDMAMode =  pNxtDevConfig->UDMAMode;
			else {
				bTmp = pNxtDevConfig->UDMAMode;
				pNxtDevConfig->UDMAMode = pCurDevConfig->UDMAMode;
			}
		}
		if ( (pNxtDevConfig->MDMAMode != 0xFF)
		  && (pCurDevConfig->MDMAMode != 0xFF) ) 
		{
			if ( pCurDevConfig->MDMAMode >= pNxtDevConfig->MDMAMode )
				pCurDevConfig->MDMAMode =  pNxtDevConfig->MDMAMode;
			else {
				bTmp = pNxtDevConfig->MDMAMode;
				pNxtDevConfig->MDMAMode = pCurDevConfig->MDMAMode;
			}
		}
	}
	
	/* get serial no. and f/w version */
	for ( i = 0; i < 10; i++ ) {
		bTmp =(U8)pIdentifybuf->SerialNumber[i];
		pIdentifybuf->SerialNumber[i] >>= 8;
		pIdentifybuf->SerialNumber[i] |= (U16)bTmp << 8;
		*(PU16)(&pCurDevConfig->SerialNo[i*2]) = pIdentifybuf->SerialNumber[i];
	}
	pCurDevConfig->SerialNo[20] =(U8)0;		/* end of string */
	
	for ( i = 0; i < 4; i++ ) {
		bTmp =(U8)pIdentifybuf->FirmwareRevision[i];
		pIdentifybuf->FirmwareRevision[i] >>= 8;
		pIdentifybuf->FirmwareRevision[i] |= (U16)bTmp << 8;
		*(PU16)(&pCurDevConfig->FWVersion[i*2]) = pIdentifybuf->FirmwareRevision[i];
	}
	pCurDevConfig->FWVersion[8] =(U8)0;		/* end of string */
	
	/* get feature status */
	pCurDevConfig->Features = 0;
	if ( pIdentifybuf->CommandSetSupport1 & 0x01 ) {
		pCurDevConfig->Features |= DEV_SMART;
		if ( pIdentifybuf->CommandSetSupport4 & 0x01 )
			pCurDevConfig->Features |= DEV_EN_SMART;	
	}
	if ( pIdentifybuf->CommandSetSupport1 & 0x20 ) {
		pCurDevConfig->Features |= DEV_WRITECACHE;
		if ( pIdentifybuf->CommandSetSupport4 & 0x20 )
			pCurDevConfig->Features |= DEV_EN_WRITECACHE;
	}
	
	if ( CAMInitDevice(pCurDevConfig) != camSUCCESS ) {
		pCurDevConfig->DevFlag = DEV_NOTFOUND;
		return (camDEVICE_NOT_FOUND);			
	}	
	*pDevConfig = *pCurDevConfig;

	if ( bTmp == 0xFF )
		return (camSUCCESS);
	else
		return(camWARNING);

}

U8 CAM_EnumATADevice(PDEV_CONFIG pDevConfig)
{
	U8			bCh=pDevConfig->bCh;
	U8			bID=pDevConfig->bID;
	PDEV_CONFIG	pCurDevConfig = &gDrvConfig[bCh][bID]; 
	PDEV_CONFIG pNxtDevConfig = &gDrvConfig[bCh][(bID+1)&0x01];
	
	/* if master drive is in the swapbox, don't try to find slave drive */
	if(( bID == 1 ) && (pNxtDevConfig->pEnclosure)) {
		pDevConfig->DevFlag = DEV_NOTFOUND;
		return(camDEVICE_NOT_FOUND);
	}
	
	if ( (bCh >= MAX_ATA_MODULE )|| (bID > 1) ) {
		pDevConfig->DevFlag = DEV_NOTFOUND;
		return(camDEVICE_NOT_FOUND);
	}
	
	if ( gChnlConfig[bCh].bCh == camCHNL_NOT_FOUND ){
		return (camDEVICE_NOT_FOUND);	
	}

	*pDevConfig = *pCurDevConfig;
	if ( pCurDevConfig->DevFlag & DEV_EXIST )
		return(camSUCCESS);
	else
		return (camDEVICE_NOT_FOUND);		
}


U8 CAM_ConfigATAChannel(PCHNL_CONFIG pChnlConfig)
{
	PCHNL_CONFIG	pChnl= &gChnlConfig[pChnlConfig->bCh];
	DEV_CONFIG 		TmpDevConfig;
	
	if (pChnlConfig->bCh >= MAX_ATA_MODULE )
		return (camCHNL_NOT_FOUND);	
		
	if ( pChnl->bCh == camCHNL_NOT_FOUND )
		return (camCHNL_NOT_FOUND);	
		
	if ( pChnlConfig->ChnlSpeed > pChnl->ChnlSpeed )
		return (camFAIL);							/* can't set faster speed than max supported speed */
	
	if (pChnl->ChnlSpeed == pChnlConfig->ChnlSpeed)	/* no change */
		return(camSUCCESS);
	
	pChnl->ChnlSpeed = pChnlConfig->ChnlSpeed;		/*only ChnlSpeed can be changed*/

	TmpDevConfig.bCh=pChnlConfig->bCh;
	TmpDevConfig.bID=0;
	if (CAM_EnumATADevice(&TmpDevConfig) != camSUCCESS)
		return (camFAIL);
		
	return (CAM_ConfigATADevice(&TmpDevConfig));
}

U8 CAM_EnumATAChannel(PCHNL_CONFIG pChnlConfig)
{
	PCHNL_CONFIG	pChnl= &gChnlConfig[pChnlConfig->bCh];
	
	if (pChnlConfig->bCh >= MAX_ATA_MODULE )
		return (camCHNL_NOT_FOUND);	
		
	if ( pChnl->bCh == camCHNL_NOT_FOUND )
		return (camCHNL_NOT_FOUND);	
	
	*pChnlConfig = *pChnl;
	return(camSUCCESS);
}

U8 CAM_HardResetSATAChannel(U8 bChannelNumber)
{
	U8 	bAdapterNumber = bChannelNumber/MAX_ATA_CHNL;
	U8	i;
	U8	INTMask, bData;
	char 	bCh =  bChannelNumber%MAX_ATA_CHNL;
	U32	ldata = 0;	
	
	/* mask plug/unplug INT */
	ReadPortUchar( HostBaseAddr[bAdapterNumber], oFFSETHOSTSATAPLUG+2, bData );	
	INTMask = bData;
	bData |= (0x11 << bCh);		/* mask plug/unplug INT */
	WritePortUchar( HostBaseAddr[bAdapterNumber], oFFSETHOSTSATAPLUG+2, bData );
			
	/* do hard reset */ 
	ReadPortUchar(HostBaseAddr[bAdapterNumber],oFFSETHOSTPCICTL+1 , bData );
	bData &= ~ (0x10 << bCh);
	WritePortUchar(HostBaseAddr[bAdapterNumber],oFFSETHOSTPCICTL+1 , bData );
	camStallExecution(1);			
	bData |= (0x10 << bCh);
	WritePortUchar(HostBaseAddr[bAdapterNumber],oFFSETHOSTPCICTL+1 , bData );
	
	/* soft reset ATA Module. */
	ATASoftResetModule(bChannelNumber);	
								
	/* wait SATA connect well in 1 second */
	for( i = 0; i < 100; i++ )
	{
		ReadPortUlong( HostBaseAddr[bAdapterNumber], oFFSETHOSTSATAPLUG, ldata );
		ldata >>= bCh;
		if ( ldata & 0x100 )
			break;
		camStallExecution(1);
	}
	
	/* clear plug/unplug flags */
	ReadPortUchar( HostBaseAddr[bAdapterNumber], oFFSETHOSTSATAPLUG, bData );	
	bData |= (0x11 << bCh);		/* clear plug/unplug flags */
	WritePortUchar( HostBaseAddr[bAdapterNumber], oFFSETHOSTSATAPLUG, bData );
	/* restore plug/unplug INT */
	bData = INTMask;
	WritePortUchar( HostBaseAddr[bAdapterNumber], oFFSETHOSTSATAPLUG+2, bData );
	
	if( i < 100 )
		return(camSUCCESS);
	else
		return(camDEVICE_NOT_FOUND);
}

U8 CAM_InitATAChannel(U8 bChannelNumber)
{
	U8	receiveStatus;
	
	if ( gChnlConfig[bChannelNumber].bCh == camCHNL_NOT_FOUND )
		return (camCHNL_NOT_FOUND);	
		
	if (bChannelNumber >= MAX_ATA_MODULE)
		return (camCHNL_NOT_FOUND);
	
	/* disable receive task.*/
	receiveStatus=ATAModuleReceiveTask[bChannelNumber];
	ATAModuleReceiveTask[bChannelNumber]=FALSE;
		
	/* Find attached devices */
	gDrvConfig[bChannelNumber][0].DevFlag = DEV_NOTFOUND;
	gDrvConfig[bChannelNumber][1].DevFlag = DEV_NOTFOUND;
	
	/* soft reset ATA Module ANYWAY. */
	ATASoftResetModule(bChannelNumber);	
	
	if (gChnlConfig[bChannelNumber].ChnlType == CHNL_SATA )
	{
		U8 	bAdapterNumber = bChannelNumber/MAX_ATA_CHNL;
		char	bCh =  bChannelNumber%MAX_ATA_CHNL;
		U32	ldata = 0;
		U8 	i;
		U8	count=0;
		U8	status=0;


		for (count=0;count<DEF_SATA_INITCOUNT;count++) 
		{
			/* wait SATA connect well in 1 second */
			for ( i = 0; i < 100; i++ )
			{
				ReadPortUlong( HostBaseAddr[bAdapterNumber], oFFSETHOSTSATAPLUG, ldata );
				ldata >>= bCh;
				if ( ldata & 0x100 )
					break;
				camStallExecution(1);
			}		
			if ( i >= 100 ) 
			{
				ATAModuleReceiveTask[bChannelNumber]=receiveStatus;	
				return(camFAIL);	/* no drive connected */				
			}			
				
			/* wait 30 seconds, following the ATA spec. special for dongle+ ATA HDD combination */	
			for ( i = 0; i < 10 ; i++ ) {
				if ( (status=WaitOnReady(bChannelNumber)) == camSUCCESS ) 
					break;
				if (status==camWARNING) {
					if ( CAM_HardResetSATAChannel(bChannelNumber) == camDEVICE_NOT_FOUND ) {
						ATAModuleReceiveTask[bChannelNumber]=receiveStatus;
						return(camFAIL);	/* no drive connected */
					}
				}	
			}
			if( i >= 10 ) {
				if (status==camFAIL) {
					if ( CAM_HardResetSATAChannel(bChannelNumber) == camDEVICE_NOT_FOUND ) {
						ATAModuleReceiveTask[bChannelNumber]=receiveStatus;
						return(camFAIL);	/* no drive connected */
					}
				}				
				continue;	/* drive not ready after 30 seconds. */
			}
			
			if ( CAM_GetATADeviceConfig(&gDrvConfig[bChannelNumber][0]) != camDEVICE_NOT_FOUND )
				break;	/* device is found */
		}
		if ( count >= DEF_SATA_INITCOUNT ) {
			ATAModuleReceiveTask[bChannelNumber]=receiveStatus;
			return(camFAIL);	/* no drive connected */
		}
	}
	else
	{
		/* when master and slave drives attached at a parallel channel, but the master drive not power-on, as some special case, the STATUS will
			always BUSY when CAM_InitATAChannel, but if drive exist and select drive before read STATUS, the drive STATUS will not BUSY and
			can detect the slave drive only at this case. */
		/*
		if ( WaitOnBusy(ATABaseAddr[bChannelNumber]) & IDE_STATUS_BUSY )
		{
			ATAModuleReceiveTask[bChannelNumber]=receiveStatus;
			return(camFAIL);
		}
		*/

		/* not check this , because is we have swap box at this channel but the power is off
			, it will not be found. */
		/*
		WriteIndexUchar(ATABaseAddr[bChannelNumber], iNDEXIDECylinderLow, 0x55 );
		WriteIndexUchar(ATABaseAddr[bChannelNumber], iNDEXIDECylinderHigh, 0xAA );
		if ( ReadIndexUchar( ATABaseAddr[bChannelNumber], iNDEXIDECylinderLow) != 0x55 )
			return(camFAIL);
		*/
		
		CAM_GetATADeviceConfig(&gDrvConfig[bChannelNumber][0]);
		CAM_GetATADeviceConfig(&gDrvConfig[bChannelNumber][1]);
		
		if ( (gDrvConfig[bChannelNumber][0].DevFlag == DEV_NOTFOUND)
		  & ( gDrvConfig[bChannelNumber][1].DevFlag == DEV_NOTFOUND ) )
		{
			ATAModuleReceiveTask[bChannelNumber]=receiveStatus;
			return(camFAIL);	/* no drive connected */;
		}
	}	
	/* ATASoftResetModule(bChannelNumber);*/	/* turn off the disk active LED */
	
	ATAModuleReceiveTask[bChannelNumber]=receiveStatus;
	return(camSUCCESS);
}

U8 CAM_ResetATAChannel(U8 bChannelNumber)
{
	U8	bAdapterNumber;
	U8	SEQID;
	U8 	STOPFlag=FALSE;
	U8	bData=0;
	U8	SEQCntCtrl;
	U8	bCh;
	U32	i;
	PSEQ_INFO	pCurSEQ_INFO=(PSEQ_INFO)U32NULL;
	PATA_TASK pATATask;
	PCAM_ATA_PACKET ultmpATAPacketAddress;
	PCAM_ATA_PACKET ultmpATAPacketAddress_next;
	U8	receiveStatus;	
	U8	count=0;
	
	if ( gChnlConfig[bChannelNumber].bCh  == camCHNL_NOT_FOUND )
		return (camCHNL_NOT_FOUND);	

	if (bChannelNumber >= MAX_ATA_MODULE )
		return (camCHNL_NOT_FOUND);	
		
	/* disable receive task.*/
	receiveStatus=ATAModuleReceiveTask[bChannelNumber];
	ATAModuleReceiveTask[bChannelNumber]=FALSE;
		
	bAdapterNumber = bChannelNumber/MAX_ATA_CHNL;
	bCh = bChannelNumber%MAX_ATA_CHNL;
	
	SEQID = ATAModuleSEQID[bChannelNumber];
	if (SEQID != U8NULL)
	{
		ATAModuleSEQID[bChannelNumber] = U8NULL;
		pCurSEQ_INFO = &(gSEQ_INFO[bAdapterNumber][SEQID]);
		ultmpATAPacketAddress = (PCAM_ATA_PACKET)pCurSEQ_INFO->SEQID2PacketHead;
		pCurSEQ_INFO->SEQID2PacketHead=(PVOID)U32NULL;
		pCurSEQ_INFO->SEQID2PacketTail=(PVOID)U32NULL;
	}
	else
		ultmpATAPacketAddress = (PCAM_ATA_PACKET)U32NULL;
	
	/* remove ata timeout timer */
	if (ATA_Timeout_TimerID[bChannelNumber]!=ZERO_NULL){
		camTimer(0,(void *)ATA_Timeout_TimerID[bChannelNumber]);	
		ATA_Timeout_TimerID[bChannelNumber]=ZERO_NULL;
	}
	
	/* Ask ATA engine don't execute the next command packet, so the ata module will stop after done current packet. */
	WritePortUchar(ATABaseAddr[bChannelNumber], ATA_STATUS_REGISTER_OFFSET, 1 );		
	for (i = 0; i < 300; i++ ) {	
		ReadPortUchar(ATABaseAddr[bChannelNumber], (ATA_STATUS_REGISTER_OFFSET+3), bData);
		if ( !(bData & 0x20) )
			break;	/* not in packet command cycle. */
		camStallExecution(1);	/* wait 3 secs */
	} ;	
	/* soft reset ATA Module. */
	ATASoftResetModule(bChannelNumber);
		
	if (gChnlConfig[bChannelNumber].ChnlType == CHNL_SATA )
	{
		U8  status=0;

		status=camWARNING;			
		for (count=0;count<DEF_SATA_INITCOUNT;count++) 
		{							
			for ( i = 0; i < 10 ; i++ ) {
				if (status==camWARNING) {
					if ( CAM_HardResetSATAChannel(bChannelNumber) == camDEVICE_NOT_FOUND )
					{	/* no drive connected */
						ATAModuleReceiveTask[bChannelNumber]=receiveStatus;
			
						/* if CAM detects the drives of the channel been set down, 
						call camCheckDriveStatus() with status:NO_DRIVE to notify the channel driver. */
						if ( gDrvConfig[bChannelNumber][0].DevFlag & DEV_EXIST ){
							gDrvConfig[bChannelNumber][0].DevFlag = DEV_NOTFOUND;
							camCheckDriveStatus(bChannelNumber, 0, NO_DRIVE);
						}
						break;
					}
				}
				/* wait 3 seconds, following the ATA spec. special for dongle+ ATA HDD combination */			
				if ( (status=WaitOnReady(bChannelNumber)) == camSUCCESS ) 
					break;
			}

			if ( gDrvConfig[bChannelNumber][0].DevFlag == DEV_NOTFOUND)
				break;	/* disk is gone or bad */
				
			if( i >= 10 ) {
				if (status==camFAIL) {
					if ( CAM_HardResetSATAChannel(bChannelNumber) == camDEVICE_NOT_FOUND ) {
						ATAModuleReceiveTask[bChannelNumber]=receiveStatus;
			
						/* if CAM detects the drives of the channel been set down, 
						call camCheckDriveStatus() with status:NO_DRIVE to notify the channel driver. */
						if ( gDrvConfig[bChannelNumber][0].DevFlag & DEV_EXIST ){
							gDrvConfig[bChannelNumber][0].DevFlag = DEV_NOTFOUND;
							camCheckDriveStatus(bChannelNumber, 0, NO_DRIVE);
							break;
						}						
					}
				}				
				continue;	/* drive not ready after 30 seconds. */
			}

			/* init disks */
			if ( gDrvConfig[bChannelNumber][0].DevFlag & DEV_EXIST ) {
				if (CAMInitDevice(&(gDrvConfig[bChannelNumber][0])) != camFAIL)
					break;	/* disk is back. */
				else if (count == (DEF_SATA_INITCOUNT-1)) {
					/* if CAM detects the drives of the channel been set down, 
					call camCheckDriveStatus() with status:NO_DRIVE to notify the channel driver. */
					gDrvConfig[bChannelNumber][0].DevFlag = DEV_NOTFOUND;
					camCheckDriveStatus(bChannelNumber, 0, NO_DRIVE);
					break;
				}
			}				
		}/* count for loop*/
	}
	else	/* parallel channel */
	{
		/* When Drive DMARQ still exist, we can't do any PIO access to ATA bus. */
		/* But do hard reset, that will reset 199. It should be a problem for dual master mode!*/	
		/* do hard reset */ 
		ReadPortUchar(HostBaseAddr[bAdapterNumber],oFFSETHOSTPCICTL+1 , bData );
		bData &= ~ (0x10 << bCh);
		WritePortUchar(HostBaseAddr[bAdapterNumber],oFFSETHOSTPCICTL+1 , bData );
		camStallExecution(1);
		bData |= (0x10 << bCh);
		WritePortUchar(HostBaseAddr[bAdapterNumber],oFFSETHOSTPCICTL+1 , bData );

		/* soft reset ATA Module. */
		ATASoftResetModule(bChannelNumber);
		
		camStallExecution(1);
		/* init disks */
		if ( gDrvConfig[bChannelNumber][0].DevFlag & DEV_EXIST ) {
			if (CAMInitDevice(&(gDrvConfig[bChannelNumber][0])) == camFAIL) {
				/* if CAM detects the drives of the channel been set down, 
				call camCheckDriveStatus() with status:NO_DRIVE to notify the channel driver. */
				gDrvConfig[bChannelNumber][0].DevFlag = DEV_NOTFOUND;
				camCheckDriveStatus(bChannelNumber, 0, NO_DRIVE);
			}
		}	
							
		if ( gDrvConfig[bChannelNumber][1].DevFlag & DEV_EXIST ) {
			if (CAMInitDevice(&(gDrvConfig[bChannelNumber][1])) == camFAIL) {
				/* if CAM detects the drives of the channel been set down, 
				call camCheckDriveStatus() with status:NO_DRIVE to notify the channel driver. */
				gDrvConfig[bChannelNumber][1].DevFlag = DEV_NOTFOUND;
				camCheckDriveStatus(bChannelNumber, 1, NO_DRIVE);
			}
		}
	}

	/* check with executing packets in seqID */
	if((U32)ultmpATAPacketAddress != U32NULL) {
		
		/* read Sequence Counter Control Register # */
		ReadPortUchar(HostBaseAddr[bAdapterNumber], SEQID*4, SEQCntCtrl);
		SEQCntCtrl &= 0x1F;
		
		while ((U32)ultmpATAPacketAddress != U32NULL){						

			pATATask=(PATA_TASK)ultmpATAPacketAddress->PacketHead.PTA;
			
			/* check is error packet */
			if (pCurSEQ_INFO->PACCNT == SEQCntCtrl)
			{	/* current packet */

				/* abort packets queue at the rear of this packet and and wait queue packets. */
				Abort_All_Undone_ATAPackets(bChannelNumber,(PCAM_ATA_PACKET)ultmpATAPacketAddress->PacketHead.NPA);
				ultmpATAPacketAddress->PacketHead.NPA=(PVOID)U32NULL;			

				pATATask->ATAStatus = ATA_ABORT;
				STOPFlag = TRUE;
			}
			else
			{
				pCurSEQ_INFO->PACCNT--;
				pATATask->ATAStatus= 0;		/* no error */
				if (pATATask->ATACmdFlag & ATA_STATUS_RETURN) /* need read it's ata registers statses when command success completed */
					ATAErrorStatus(pATATask);				
			}
								
			pATATask->ATACmdFlag &= ~INTERNAL_SENSE;

			/* free sg resource */
			CAMFreeSG(bAdapterNumber, ATA_PAC, (PVOID)ultmpATAPacketAddress->PacketHead.PSG);	
			
			ultmpATAPacketAddress_next = (PCAM_ATA_PACKET)ultmpATAPacketAddress->PacketHead.NPA;
			
			/* free packet resource. */
			CAMFreePacket(bAdapterNumber, ATA_PAC, (PVOID)ultmpATAPacketAddress);		
			
			/* next packet */
			ultmpATAPacketAddress = ultmpATAPacketAddress_next;

			pATATask->callback(pATATask);
			
			if( STOPFlag == TRUE)
				break;
		}
		

		pCurSEQ_INFO->SEQID2PacketHead=(PVOID)U32NULL;
		pCurSEQ_INFO->SEQID2PacketTail=(PVOID)U32NULL;
		ATAModuleBusy[bChannelNumber]=FALSE;
		CAMFreeSEQID(bAdapterNumber,SEQID);
	}
	else{
		/* no executing packets,abort packets queue at wait queue packets. */
		Abort_All_Undone_ATAPackets(bChannelNumber,(PCAM_ATA_PACKET)U32NULL);
	}
		
	ATAModuleReceiveTask[bChannelNumber]=receiveStatus;
	
	if ( (gDrvConfig[bChannelNumber][0].DevFlag == DEV_NOTFOUND)
	  & ( gDrvConfig[bChannelNumber][1].DevFlag == DEV_NOTFOUND ) )
			return(camFAIL);	/* no drive connected */;
			
	return(camSUCCESS);
}


/*-------------------------------------------------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------------------------------------------------*/

U8 CAMInitDevice(PDEV_CONFIG pDevConfig)
{
	U8			bCh=pDevConfig->bCh;
	U8			bID=pDevConfig->bID;
	U8			statusByte= 0;
	U8			bAdapterNumber = bCh/MAX_ATA_CHNL;
	U32			BaseAddress = ATABaseAddr[bCh];
	U8			i;
	
	
	/* disable INTA here, it will be re-enable when CAM use SEQ 0 for packets */
	WriteIndexUchar(BaseAddress, iNDEXIDECICR, 0x0);  /* that the drive INT pass to SEQ 0*/
	WritePortUchar( HostBaseAddr[bAdapterNumber], 0, 0x20); /* but mask SEQ 0 INT */
	
	/* In parallel, prevent single slave condition */
	if (gChnlConfig[bCh].ChnlType == CHNL_ATA ){
		/* wait for BUSY */
		for (i = 0; i < 10; i++) {
			statusByte = WaitOnBusy(ATABaseAddr[bCh]);
			if( !(statusByte & IDE_STATUS_BUSY))
				break;
		}		
		
		/* check if device exist */ 
		/* select drive */	
		WriteIndexUchar(ATABaseAddr[bCh], iNDEXIDEDeviceHead, (U8)(((bID & 0x01) << 4) | 0xA0));
		/* read drive status */
		if ( WaitOnBaseBusy(ATABaseAddr[bCh]) & 0x80) {
			return (camFAIL); /* no device */
		}
		
		/* select drive  again */
		WriteIndexUchar(ATABaseAddr[bCh], iNDEXIDEDeviceHead, (U8)(((bID & 0x01) << 4) | 0xA0));
		WriteIndexUchar(ATABaseAddr[bCh], iNDEXIDECylinderLow, 0x55 );
		WriteIndexUchar(ATABaseAddr[bCh], iNDEXIDECylinderHigh, 0xAA );
		statusByte = ReadIndexUchar( ATABaseAddr[bCh], iNDEXIDECylinderLow);
		if ( statusByte != 0x55 ){ /* no device */
			return(camFAIL);
		}
	}
	
	/* set paramters */	
	if ( pDevConfig->DevFlag & DEV_ATA_DEVICE )
	{
		/* select drive */	
		WriteIndexUchar(BaseAddress, iNDEXIDEDeviceHead, (U8)(((bID & 0x01) << 4) | 0xA0));
 		statusByte = WaitOnBusy(BaseAddress);
    	statusByte &= ~(IDE_STATUS_ERROR | IDE_STATUS_INDEX | IDE_STATUS_DRQ );
    	if (statusByte != IDE_STATUS_IDLE){
			return(camFAIL); /* bad device */
		}
			
		/* send command */
		WriteIndexUchar(BaseAddress, iNDEXIDESectorCount , pDevConfig->SecPerTrk);
		WriteIndexUchar(BaseAddress, iNDEXIDEDeviceHead, (U8)((pDevConfig->HeadNum - 1)|(bID << 4)) );
		WriteIndexUchar(BaseAddress, iNDEXIDECommand, IDE_COMMAND_SET_DRIVE_PARAMETERS);
		if ( WaitForINT(BaseAddress) != camSUCCESS ){
			return(camFAIL); /* bad device */
		}
			
	}
	
	/* set feature */
	WriteIndexUchar(BaseAddress, iNDEXIDEFeature , 0x03);	/* set transfer mode */
	WriteIndexUchar(BaseAddress, iNDEXIDESectorCount, (U8)(pDevConfig->PIOMode | 0x08));	/* PIO transfer */
	WriteIndexUchar(BaseAddress, iNDEXIDEDeviceHead, (U8)(0xE0 |(bID << 4)) );
	WriteIndexUchar(BaseAddress, iNDEXIDECommand, IDE_COMMAND_SET_FEATURES);
	if ( WaitForINT(BaseAddress) != camSUCCESS ){
		return(camFAIL); /* bad device */
	}

	WriteIndexUchar(BaseAddress, iNDEXIDEFeature, 0x03);	/* set transfer mode */
	if ( pDevConfig->UDMAMode != 0xFF )	{	
		WriteIndexUchar(BaseAddress, iNDEXIDESectorCount, (U8)(pDevConfig->UDMAMode | 0x40));
	}
	else {
		WriteIndexUchar(BaseAddress, iNDEXIDESectorCount, (U8)(pDevConfig->MDMAMode | 0x20));
	}
	WriteIndexUchar(BaseAddress, iNDEXIDEDeviceHead, (U8)(0xE0 |(bID << 4)) );
	WriteIndexUchar(BaseAddress, iNDEXIDECommand, IDE_COMMAND_SET_FEATURES);
	if ( WaitForINT(BaseAddress) != camSUCCESS ){
		return(camFAIL); /* bad device */
	}
		
 	/*For SATA channel. After SET Feature command, 
        	program BA#3 offset 24Ch/2CCh/34Ch/3CCh to 5FDF0020h,
               	and BA#3 offset 250h/2D0h/350h/3D0h to 03CB014Ah,
    		no matter what PIO mode and UDMA mode reported by HD */		
	if (gChnlConfig[bCh].ChnlType == CHNL_SATA ) {
		WriteIndexUlong( ATABaseAddr[bCh], iNDEXIDEDrvTiming1, 0x25CB014A);
	}		
		
	if (( pDevConfig->DevFlag & DEV_ATA_DEVICE )
	 && ( pDevConfig->Features & DEV_SMART ) )
	{
		/* enable smart */
		WriteIndexUchar(BaseAddress, iNDEXIDEFeature , 0xD8);	
		WriteIndexUchar(BaseAddress, iNDEXIDECylinderLow, 0x4F);	
		WriteIndexUchar(BaseAddress, iNDEXIDECylinderHigh, 0xC2);
		WriteIndexUchar(BaseAddress, iNDEXIDEDeviceHead, (U8)(0xE0 |(bID << 4)) );
		WriteIndexUchar(BaseAddress, iNDEXIDECommand, IDE_COMMAND_SMART_CMD);
		if ( WaitForINT(BaseAddress) != camSUCCESS ){
			pDevConfig->Features &= ~DEV_EN_SMART;	
			return(camFAIL); /* bad device */
		}
		pDevConfig->Features |= DEV_EN_SMART;
	}
			
	return(camSUCCESS); /* OK */
}

U8 IssueIdentify(U8 bCh, U8 bID, PU8 pBuf, U8 command) 
{
	U8	statusByte;
	U32		BaseIOAddress = ATABaseAddr[bCh];

		
	/* select drive */
	WriteIndexUchar(BaseIOAddress, iNDEXIDEDeviceHead, (U8)(((bID & 0x01) << 4) | 0xA0));
	GetBaseStatus(BaseIOAddress, statusByte);	
	if (command == IDE_COMMAND_IDENTIFY)
    {
    	statusByte &= ~(IDE_STATUS_ERROR | IDE_STATUS_INDEX | IDE_STATUS_DRQ );
	    if (statusByte != IDE_STATUS_IDLE)
			return(camFAIL); /* bad device */	
	}
    else
    {
	    /*
    	 * Load CylinderHigh and CylinderLow with number bytes to transfer.
    	 */

    	WriteIndexUchar(BaseIOAddress,iNDEXIDECylinderHigh, (0x200 >> 8));
    	WriteIndexUchar(BaseIOAddress,iNDEXIDECylinderLow,  (0x200 & 0xFF));
	}
	
   	/* Send IDENTIFY command. */
	WriteIndexUchar(BaseIOAddress, iNDEXIDEDeviceHead, (U8)(((bID & 0x01) << 4) | 0xA0));
   	WriteIndexUchar(BaseIOAddress, iNDEXIDECommand, command);
	if ( WaitForINT(BaseIOAddress) != camSUCCESS )
		return(camFAIL); /* bad device */
		
    /* Wait for DRQ */
   	statusByte = WaitForDrq(BaseIOAddress);
   	
	if (!(statusByte & IDE_STATUS_DRQ)) {	
		return(camFAIL); /* bad device */	
	}

    /*
     * Check for error on really stupid master devices that assert random
     * patterns of bits in the status register at the slave address.
     */

    if ((command == IDE_COMMAND_IDENTIFY) && (statusByte & IDE_STATUS_ERROR)) {
		return(camFAIL); /* bad device */	
    }

	/*
	 * Suck out 256 words. 
	 */
	 
    ReadBuffer(BaseIOAddress,(PU16)pBuf, 256);
    
	/* check status again, if DRQ still is 1. This command is failed. */	
	GetBaseStatus(BaseIOAddress, statusByte);
    if ( statusByte & IDE_STATUS_DRQ )
			return(camFAIL); /* bad device */		    

	return(camSUCCESS); /* OK */	
}


void ATASoftResetModule(U8 bChannelNumber)
{
	U32  tmpData;
	U8	i;

	ReadIndexUlong(ATABaseAddr[bChannelNumber], iNDEXIDECICR, tmpData);
	tmpData |=0x00000800;	/* bit 11.*/
	WriteIndexUlong(ATABaseAddr[bChannelNumber], iNDEXIDECICR, tmpData);
	for( i = 0; i <= 10; i++ )
	{
		ReadIndexUlong(ATABaseAddr[bChannelNumber], iNDEXIDECICR, tmpData);
		if ( tmpData & 0x00000800 )
			break;
		camStallExecution(1); 	
		tmpData |=0x00000800;	/* bit 11.*/
		WriteIndexUlong(ATABaseAddr[bChannelNumber], iNDEXIDECICR, tmpData);
	};
	tmpData &=0xfffff7ff;	/* bit 11.*/
	WriteIndexUlong(ATABaseAddr[bChannelNumber], iNDEXIDECICR, tmpData);
}

        
U8 checkLargeLBA(PATA_TASK pATATask)
{
	U8 LargeLBA=FALSE;
	/* ckeck is 48-bit LBA */
	switch(pATATask->Cmd.ATACmd.bCmd){
		case IDE_COMMAND_READ:
		case IDE_COMMAND_READ_DMA:
		case IDE_COMMAND_WRITE:
		case IDE_COMMAND_WRITE_DMA:	
		case IDE_COMMAND_VERIFY:
			/*1.When R/W command start address is less than 128G but the end address across the 128G, cam still do 
				standard R/W command(no extended R/W command) will cause R/W datas error.
	     		  2.When R/W command, if the address less 128G, use standard R/W command, and if large than 128G, use extended R/W command,
	     			but this seem cause the drive confused.	*/
			/* check lba address large than 2^28*/
			/* if ( (pATATask->Cmd.ATACmd.LBAh) 
				|| (pATATask->Cmd.ATACmd.LBAl & 0xF0000000) ) */
			if (gDrvConfig[pATATask->bCh][pATATask->bID].DevFlag & DEV_48BIT)
				LargeLBA=TRUE;
			break;
		case IDE_COMMAND_READ_EXT:
		case IDE_COMMAND_READ_DMA_EXT:
		case IDE_COMMAND_READ_DMA_QUEUED_EXT:
		case IDE_COMMAND_READ_MULTIPLE_EXT:
		case IDE_COMMAND_WRITE_EXT:
		case IDE_COMMAND_WRITE_DMA_EXT:
		case IDE_COMMAND_WRITE_DMA_QUEUED_EXT:
		case IDE_COMMAND_WRITE_MULTIPLE_EXT:
		case IDE_COMMAND_VERIFY_EXT:
				LargeLBA=TRUE;
			break;
	}
	return LargeLBA;
}

/* set disk status when error */
/* 1. return bStatus 
    2. return berror 
    3 return bCount
    4 return LBAl and LBAh */
void ATAErrorStatus(PATA_TASK pATATask)
{
	U32 Data;
	U8 bChannelNumber;
	U8 LargeLBA=FALSE;

	bChannelNumber=pATATask->bCh;

	/*    1. return bStatus , 3f6*/
	pATATask->Cmd.ATACmd.bStatus = ReadIndexUchar(ATABaseAddr[bChannelNumber], iNDEXIDEAlternateStatus);
	/*    2. return berror , 1f1*/
	pATATask->Cmd.ATACmd.bError = ReadIndexUchar(ATABaseAddr[bChannelNumber], iNDEXIDEError);

	/* ckeck is 48-bit LBA */
	LargeLBA=checkLargeLBA(pATATask);
	pATATask->Cmd.ATACmd.bCount = 0;
	pATATask->Cmd.ATACmd.LBAh= 0;
	pATATask->Cmd.ATACmd.LBAl = 0;		

	if (LargeLBA){
		/* most recently written */
		WriteIndexUchar(ATABaseAddr[bChannelNumber], iNDEXIDEDeviceControl, 0x0 ); 	/* set HOB=0 */	
		pATATask->Cmd.ATACmd.bCount = (U16)ReadIndexUchar(ATABaseAddr[bChannelNumber], iNDEXIDESectorCount);
		pATATask->Cmd.ATACmd.LBAl = (U32)ReadIndexUchar(ATABaseAddr[bChannelNumber], iNDEXIDESectorNumber);
		Data = (U32)ReadIndexUchar(ATABaseAddr[bChannelNumber], iNDEXIDECylinderLow);
		pATATask->Cmd.ATACmd.LBAl |= (Data << 8);
		Data = (U32)ReadIndexUchar(ATABaseAddr[bChannelNumber], iNDEXIDECylinderHigh);
		pATATask->Cmd.ATACmd.LBAl |= (Data << 16);
		
		/* previous content */
		WriteIndexUchar(ATABaseAddr[bChannelNumber], iNDEXIDEDeviceControl, 0x80 );	/* set HOB=1 */
		Data = (U32)ReadIndexUchar(ATABaseAddr[bChannelNumber], iNDEXIDESectorCount);
		pATATask->Cmd.ATACmd.bCount |= (U16)(Data  << 8);
		Data = (U32)ReadIndexUchar(ATABaseAddr[bChannelNumber], iNDEXIDESectorNumber);
		pATATask->Cmd.ATACmd.LBAl |= (Data << 24);
		pATATask->Cmd.ATACmd.LBAh = (U32)ReadIndexUchar(ATABaseAddr[bChannelNumber], iNDEXIDECylinderLow);
		Data = (U32)ReadIndexUchar(ATABaseAddr[bChannelNumber], iNDEXIDECylinderHigh);
		pATATask->Cmd.ATACmd.LBAh |= (Data << 8);			
		
	}
	else{
		/*    3 return bCount , 1f2 */
		pATATask->Cmd.ATACmd.bCount = (U16)ReadIndexUchar(ATABaseAddr[bChannelNumber], iNDEXIDESectorCount);

		/*    4 return LBAl and LBAh */
		Data = (U32)ReadIndexUchar(ATABaseAddr[bChannelNumber], iNDEXIDESectorNumber);
		pATATask->Cmd.ATACmd.LBAl |= Data;
		Data = (U32)ReadIndexUchar(ATABaseAddr[bChannelNumber], iNDEXIDECylinderLow);
		pATATask->Cmd.ATACmd.LBAl |= (Data << 8);
		Data = (U32)ReadIndexUchar(ATABaseAddr[bChannelNumber], iNDEXIDECylinderHigh);
		pATATask->Cmd.ATACmd.LBAl |= (Data << 16);
		Data = (U32)ReadIndexUchar(ATABaseAddr[bChannelNumber], iNDEXIDEDeviceHead);
		pATATask->Cmd.ATACmd.LBAl |= (Data << 24);

	}
	
	return;
}

/* set ATAPI error status */
void ATAPIErrorStatus(PATA_TASK pATATask)
{
	U8 bChannelNumber;

	bChannelNumber=pATATask->bCh;

	/* 1. ATAPI Error Register */
	pATATask->Cmd.ATACmd.bError = ReadIndexUchar(ATABaseAddr[bChannelNumber], iNDEXIDEError);

	/* 2. ATAPI Status */
	pATATask->Cmd.ATACmd.bStatus = ReadIndexUchar(ATABaseAddr[bChannelNumber], iNDEXIDEAlternateStatus);
	
	return;
}

void prepareATAPISENSECommand(PCAM_ATA_PACKET CAM_ATAPacket,PATA_TASK pATATask)
{
	PU8          pAtrl;

	/* set bATRL */

	pAtrl = &(CAM_ATAPacket->ATAPacket.bATRL[0]);	

	/* select drive */
	*pAtrl++=ATRLREG_REG_SIZE_1|ATRLREG_DEVICESELECT;				
	*pAtrl++ = (U8) (0xE0 | (pATATask->bID << 4));

	/* select drive , Device register */
	*pAtrl++=ATRLREG_REG_SIZE_1|
				ATRLREG_CONDITION_CHECK_NOT_BUSY|
				ATRLREG_DEVICESELECT;
	*pAtrl++ = (U8) (0xE0 | (pATATask->bID << 4));
	
	/* for ATAPI, some will assert INTRQ and others not , following the asswetion of DRQ, so disable interrupt
	    and will ingore this interrupt */

	/* disable device interrupt */
	*pAtrl++=ATRLREG_REG_SIZE_1|
				ATRLREG_X_3F6;
	*pAtrl++=0x02;

	/* feature register */
    *pAtrl++ = ATRLREG_REG_SIZE_1|
     				ATRLREG_FEATURE;
	*pAtrl++ = 0x00; 	/* we get sense data by PIO ! */
	
	/* byte counter register (cylinder low/high) , set to 0 */
    *pAtrl++ = ATRLREG_REG_SIZE_1|
     				ATRLREG_LBA8_15;   	/* cylinder low */
	*pAtrl++ = 0;
    *pAtrl++ = ATRLREG_REG_SIZE_1|
     				ATRLREG_LBA16_23 ;	/* cylinder high */
	 *pAtrl++ = 0;

	/* ATAPI packet command */
	 *pAtrl++ = ATRLREG_REG_SIZE_1|
     				ATRLREG_COMMAND;
     *pAtrl++ = IDE_COMMAND_ATAPI_PACKET;

	/* after DRQ, enable interrupt */

	/* select drive , and check DRQ */
	*pAtrl++=ATRLREG_REG_SIZE_1|
				ATRLREG_CONDITION_CHECK_DRQ|
				ATRLREG_DEVICESELECT;
	*pAtrl++ = (U8) (0xE0 | (pATATask->bID << 4));	
      	 
	/* enable interrupt */
	*pAtrl++=ATRLREG_REG_SIZE_1|
				ATRLREG_X_3F6;
	*pAtrl++=0x00;

	/* send 12 bytes(6 words) command datas */	
	*pAtrl++=ATRLREG_REG_SIZE_6|
				ATRLREG_DATA|
				ATRLREG_X_END_1F0;
	
	*pAtrl++=REQUEST_SENSE_COMMAND;	/* 0x03 */
	*pAtrl++=0;

	*pAtrl++=0;
	*pAtrl++=0;

	/* SenseInfoLength must be a multiple of 2 */
	*pAtrl++=(pATATask->SenseInfoLength/2)*2;
	*pAtrl++=0;

	*pAtrl++=0;
	*pAtrl++=0;

	*pAtrl++=0;
	*pAtrl++=0;

	*pAtrl++=0;
	*pAtrl++=0;

	return;
}

		
void SubmitInternelSense(PATA_TASK pATATask)
{

	U8 bAdapterNumber;
	PCAM_ATA_PACKET CAM_ATAPacket;
	PCAM_ATA_SG CAM_ATASG;

	bAdapterNumber = pATATask->bCh/MAX_ATA_CHNL;
	
	/* parepare REQUEST SENSE task */
	pATATask->ATACmdFlag |= PIO_XFER + camDATA_IN;
	pATATask->Cmd.Cdb[0] = REQUEST_SENSE_COMMAND;
	pATATask->Cmd.Cdb[1] = 0;
	pATATask->Cmd.Cdb[2] = 0;
	pATATask->Cmd.Cdb[3] = 0;
	pATATask->Cmd.Cdb[4] = (pATATask->SenseInfoLength/2)*2;	/* SenseInfoLength must be a multiple of 2 */
	pATATask->Cmd.Cdb[5] = 0;
	pATATask->Cmd.Cdb[6] = 0;
	pATATask->Cmd.Cdb[7] = 0;
	pATATask->Cmd.Cdb[8] = 0;
	pATATask->Cmd.Cdb[9] = 0;
	pATATask->Cmd.Cdb[10] = 0;
	pATATask->Cmd.Cdb[11] = 0;
	pATATask->SGCount = 0;	/* no SG */
	
	/* get free packet address */
	CAM_ATAPacket = CAMAllocPacket(bAdapterNumber, ATA_PAC);
	
	/* get free SG address */
	CAM_ATASG = CAMAllocSG(bAdapterNumber, ATA_PAC);
	
	/* prepare ata packet */
	prepareATAPacket(CAM_ATAPacket,CAM_ATASG,pATATask);
	
	/* put the atapacket to the haed of ata queue */
	Put2ATAQueue(CAM_ATAPacket,QUEUEHead);
	
	return;
}

PCAM_ATA_PACKET GetATA_PacketFromATAQueue(U8 bChannelNumber);

void Abort_All_Undone_ATAPackets(U8 bCh,PCAM_ATA_PACKET CAM_ATAPacket) 
{
	PATA_TASK pATATask;
	U8 bAdapterNumber;
	PCAM_ATA_PACKET CAM_ATAPacket_next;

	bAdapterNumber = bCh/MAX_ATA_CHNL;
	
	/* 1.abort all packets at execute queue */
	while ((U32)CAM_ATAPacket != U32NULL){						

		pATATask=(PATA_TASK)CAM_ATAPacket->PacketHead.PTA;

		pATATask->ATAStatus = ATA_ABORT;

		/* free sg resource */
		CAMFreeSG(bAdapterNumber, ATA_PAC, (PVOID)CAM_ATAPacket->PacketHead.PSG);
		
		CAM_ATAPacket_next = (PCAM_ATA_PACKET)CAM_ATAPacket->PacketHead.NPA;
		
		/* free packet resource. */
		CAMFreePacket(bAdapterNumber, ATA_PAC, (PVOID)CAM_ATAPacket);		

		/* next packet */
		CAM_ATAPacket = CAM_ATAPacket_next;

		pATATask->callback(pATATask);

	}

	/* 2. abort all packet at wait queue */
	while(1){
		CAM_ATAPacket = GetATA_PacketFromATAQueue(bCh);
		
		if ( CAM_ATAPacket == ZERO_NULL)	/* no packet */
			break;
			

		pATATask=(PATA_TASK)CAM_ATAPacket->PacketHead.PTA;

		pATATask->ATAStatus = ATA_ABORT;

		/* free sg resource */
		CAMFreeSG(bAdapterNumber, ATA_PAC, (PVOID)CAM_ATAPacket->PacketHead.PSG);
		
		/* free packet resource. */
		CAMFreePacket(bAdapterNumber, ATA_PAC, (PVOID)CAM_ATAPacket);		

		pATATask->callback(pATATask);
	}
	return;
}


void stopATAModule(U8 bChannelNumber)
{
	U8	bAdapterNumber;
	U8	SEQID;
	U8 	STOPFlag=FALSE;
	PSEQ_INFO	pCurSEQ_INFO=(PSEQ_INFO)U32NULL;
	U8	SEQCntCtrl;
	PATA_TASK pATATask;
	PCAM_ATA_PACKET ultmpATAPacketAddress;
	PCAM_ATA_PACKET ultmpATAPacketAddress_next;
	U8	receiveStatus;
	U32	i;
	U8	bData;
	
	if ( gChnlConfig[bChannelNumber].bCh  == camCHNL_NOT_FOUND )
		return;

	if (bChannelNumber >= MAX_ATA_MODULE )
		return;
		
	/* disable receive task.*/
	receiveStatus=ATAModuleReceiveTask[bChannelNumber];
	ATAModuleReceiveTask[bChannelNumber]=FALSE;
				
	bAdapterNumber = bChannelNumber/MAX_ATA_CHNL;
	
	SEQID = ATAModuleSEQID[bChannelNumber];
	if (SEQID != U8NULL)
	{
		ATAModuleSEQID[bChannelNumber] = U8NULL;
		pCurSEQ_INFO = &(gSEQ_INFO[bAdapterNumber][SEQID]);
		ultmpATAPacketAddress = (PCAM_ATA_PACKET)pCurSEQ_INFO->SEQID2PacketHead;
		pCurSEQ_INFO->SEQID2PacketHead=(PVOID)U32NULL;
		pCurSEQ_INFO->SEQID2PacketTail=(PVOID)U32NULL;
	}
	else
		ultmpATAPacketAddress = (PCAM_ATA_PACKET)U32NULL;

	/* Ask ATA engine don't execute the next command packet, so the ata module will stop after done current packet. */
	WritePortUchar(ATABaseAddr[bChannelNumber], ATA_STATUS_REGISTER_OFFSET, 1 );		
	for (i = 0; i < 300; i++ ) {	
		ReadPortUchar(ATABaseAddr[bChannelNumber], (ATA_STATUS_REGISTER_OFFSET+3), bData);
		if ( !(bData & 0x20) )
			break;	/* not in packet command cycle. */
		camStallExecution(1);	/* wait 3 secs */
	} ;	
	/* soft reset ATA Module. */
	ATASoftResetModule(bChannelNumber);		

	/* remove ata timeout timer */
	if (ATA_Timeout_TimerID[bChannelNumber]!=ZERO_NULL){
		camTimer(0,(void *)ATA_Timeout_TimerID[bChannelNumber]);	
		ATA_Timeout_TimerID[bChannelNumber]=ZERO_NULL;
	}
	
	/* check with executing packets in seqID */
	if((U32)ultmpATAPacketAddress != U32NULL) {
		
		/* read Sequence Counter Control Register # */
		ReadPortUchar(HostBaseAddr[bAdapterNumber], SEQID*4, SEQCntCtrl);
		SEQCntCtrl &= 0x1F;		
		
		while ((U32)ultmpATAPacketAddress != U32NULL){						

			pATATask=(PATA_TASK)ultmpATAPacketAddress->PacketHead.PTA;
			
			/* check is error packet */
			if (pCurSEQ_INFO->PACCNT == SEQCntCtrl)
			{ 	/* error packet */

				/* abort packets queue at the rear of this packet and and wait queue packets. */
				Abort_All_Undone_ATAPackets(bChannelNumber,(PCAM_ATA_PACKET)ultmpATAPacketAddress->PacketHead.NPA);
				ultmpATAPacketAddress->PacketHead.NPA=(PVOID)U32NULL;			

				pATATask->ATAStatus = ATA_ABORT;
				STOPFlag = TRUE;
			}
			else
			{
				pCurSEQ_INFO->PACCNT--;
				pATATask->ATAStatus= 0;		/* no error */
				if (pATATask->ATACmdFlag & ATA_STATUS_RETURN) /* need read it's ata registers statses when command success completed */
					ATAErrorStatus(pATATask);				
			}
								
			pATATask->ATACmdFlag &= ~INTERNAL_SENSE;

			/* free sg resource */
			CAMFreeSG(bAdapterNumber, ATA_PAC, (PVOID)ultmpATAPacketAddress->PacketHead.PSG);
			
			ultmpATAPacketAddress_next = (PCAM_ATA_PACKET)ultmpATAPacketAddress->PacketHead.NPA;
						
			/* free packet resource. */
			CAMFreePacket(bAdapterNumber, ATA_PAC, (PVOID)ultmpATAPacketAddress);		
			
			/* next packet */
			ultmpATAPacketAddress = ultmpATAPacketAddress_next;

			pATATask->callback(pATATask);
			
			if( STOPFlag == TRUE)
				break;
		}
		

		pCurSEQ_INFO->SEQID2PacketHead=(PVOID)U32NULL;
		pCurSEQ_INFO->SEQID2PacketTail=(PVOID)U32NULL;
		ATAModuleBusy[bChannelNumber]=FALSE;
		CAMFreeSEQID(bAdapterNumber,SEQID);
	}
	else{
		/* no executing packets,abort packets queue at wait queue packets. */
		Abort_All_Undone_ATAPackets(bChannelNumber,(PCAM_ATA_PACKET)U32NULL);
	}	
	
	ATAModuleReceiveTask[bChannelNumber]=receiveStatus;
	return;
}

void HandleInternalSwapbox_CMD(U8 bChannelNumber, U8 SEQID)
{
	PSEQ_INFO	pCurSEQ_INFO;
	PCAM_ATA_PACKET ultmpATAPacketAddress;
	PATA_TASK pATATask=ZERO_NULL;
	U8 i;
	U8	bAdapterNumber;

	bAdapterNumber = bChannelNumber/MAX_ATA_CHNL;	
	
	pCurSEQ_INFO = &(gSEQ_INFO[bAdapterNumber][SEQID]);

	/*If a packet is PIO_XFER or SWAPBOX_CMD, it will not queue with other packets when executing.*/
	ultmpATAPacketAddress = (PCAM_ATA_PACKET)pCurSEQ_INFO->SEQID2PacketHead;

	pATATask=(PATA_TASK)ultmpATAPacketAddress->PacketHead.PTA;

	pCurSEQ_INFO->SEQID2PacketHead=(PVOID)U32NULL;
	pCurSEQ_INFO->SEQID2PacketTail=(PVOID)U32NULL;			
			
	pATATask->ATAStatus= 0;		/* no error */
								
	pATATask->ATACmdFlag &= ~INTERNAL_SENSE;
	
	/* free sg resource */
	CAMFreeSG(bAdapterNumber, ATA_PAC, (PVOID)ultmpATAPacketAddress->PacketHead.PSG);			
	/* free packet resource. */
	CAMFreePacket(bAdapterNumber, ATA_PAC, (PVOID)ultmpATAPacketAddress);		

	pATATask->callback(pATATask);

	ATAModuleBusy[bChannelNumber]=FALSE;
	ATAModuleSEQID[bChannelNumber] = U8NULL;
	CAMFreeSEQID(bAdapterNumber,SEQID);

	/* must check module is need to push, By it maybe pushed when no SQEID. */
	for (i=(bAdapterNumber*MAX_ATA_CHNL);i<((bAdapterNumber+1)*MAX_ATA_CHNL);i++) {
		if ( (ATAModuleNeedPush[i]==TRUE) && (ATAModuleBusy[i]==FALSE) ){
			/* start ata module */
			StartATAOperation(i);
			break;
		}
	}
	
	return;
}
void IssueATAPIPktCmd(U8 bChannelNumber, U8 SEQID)
{
	U8	bAdapterNumber = bChannelNumber/MAX_ATA_CHNL;
	U8	bID;
	U32			BaseAddress = ATABaseAddr[bChannelNumber];
	PATA_TASK pATATask = (PATA_TASK)((PCAM_ATA_PACKET)gSEQ_INFO[bAdapterNumber][SEQID].SEQID2PacketHead)->PacketHead.PTA;
	
	
	bID = pATATask->bID;

	/* disable INTA here, it will be re-enable when CAM use SEQ 0 for packets */
	WriteIndexUchar(BaseAddress, iNDEXIDECICR, 0x0);  /* that the drive INT pass to SEQ 0*/
	WritePortUchar( HostBaseAddr[bAdapterNumber], 0, 0x20); /* but mask SEQ 0 INT */

	/* select drive */
	WriteIndexUchar(BaseAddress, iNDEXIDEDeviceHead, (U8)(((bID & 0x01) << 4) | 0xA0));
 	WaitOnBusy(BaseAddress);
 	
  	/* set feature register */   				
	if ( pATATask->ATACmdFlag & PIO_XFER ) {
 		WriteIndexUchar(BaseAddress, iNDEXIDEFeature, 0x00); 	/* data xfer by PIO ! */
		/* set real transfer byte count to byte counter register (cylinder low/high) */	
		WriteIndexUchar(BaseAddress, iNDEXIDECylinderLow, (U8)pATATask->DataTransferLength);
 		WriteIndexUchar(BaseAddress, iNDEXIDECylinderHigh, (U8)(pATATask->DataTransferLength >> 8));
	}
	else {
		WriteIndexUchar(BaseAddress, iNDEXIDEFeature, 0x01); 	/* set DMA bit */
		/* byte counter register (cylinder low/high) , set to 0 */
		WriteIndexUchar(BaseAddress, iNDEXIDECylinderLow, 0x00);
 		WriteIndexUchar(BaseAddress, iNDEXIDECylinderHigh, 0x00);
	}
	
	/* send ATAPI packet command 0xA0 */
	WriteIndexUchar(BaseAddress, iNDEXIDECommand, IDE_COMMAND_ATAPI_PACKET);

	/* Do we have to wait INT ? */	
	if ( gDrvConfig[bChannelNumber][bID].DevFlag & DEV_INT_DRQ )
		WaitForINT(BaseAddress);
	
	WaitForDrq(BaseAddress);
	
	/* now device wait CDB only */

	return;
}

void ATA_Timeout(U8 bChannelNumber)
{
	PSEQ_INFO	pCurSEQ_INFO;
	U8	SEQCntCtrl;
	PCAM_ATA_PACKET ultmpATAPacketAddress;
	PCAM_ATA_PACKET ultmpATAPacketAddress_next;

	PATA_TASK pATATask=ZERO_NULL;
	U8 	SEQID;
	U8 	i;
	U8	bAdapterNumber;
	U8	bCh;
	U8	errorFlag=FALSE;
	U8	bData=0;
	U32	ldata;
	U8    SATAerrorFlag=FALSE;
	U8	count=0;
	U8	receiveStatus;	
	
	ATA_Timeout_TimerID[bChannelNumber]=ZERO_NULL;
	
	bAdapterNumber = bChannelNumber/MAX_ATA_CHNL;
	bCh = bChannelNumber%MAX_ATA_CHNL;
	SEQID = ATAModuleSEQID[bChannelNumber];
	
	/* error timeout. If no SEQID assign to channel packets, timeout will not happen, so if timeout function be called at this case, it is a error timeout.*/
	if (SEQID == U8NULL)
		return;

	/* disable receive task.*/
	receiveStatus=ATAModuleReceiveTask[bChannelNumber];
	ATAModuleReceiveTask[bChannelNumber]=FALSE;
		
	ATAModuleSEQID[bChannelNumber] = U8NULL;
		
	pCurSEQ_INFO = &(gSEQ_INFO[bAdapterNumber][SEQID]);

	ultmpATAPacketAddress = (PCAM_ATA_PACKET)pCurSEQ_INFO->SEQID2PacketHead;

	/* soft reset ATA Module. */
	ATASoftResetModule(bChannelNumber);
	
	/* read Sequence Counter Control Register # */
	ReadPortUchar(HostBaseAddr[bAdapterNumber], SEQID*4, SEQCntCtrl);
	SEQCntCtrl &= 0x1F;
		
	if ((U32)ultmpATAPacketAddress != U32NULL){
		if ( gChnlConfig[bChannelNumber].ChnlType == CHNL_SATA )
		{	/* check SATA Error Register */						

			/* if the regidter offset large than 0x80, when use MMIO, must use this method */
			#ifdef	_MMIO_
			ReadIndexUlong( ATABaseAddr[bAdapterNumber*MAX_ATA_CHNL]  + 0x100 * (bChannelNumber%MAX_ATA_CHNL) , iNDEXIDESATAError, ldata );
			WriteIndexUlong( ATABaseAddr[bAdapterNumber*MAX_ATA_CHNL]  + 0x100 * (bChannelNumber%MAX_ATA_CHNL) , iNDEXIDESATAError, ldata );
			#else
			ReadIndexUlong( ATABaseAddr[bChannelNumber], iNDEXIDESATAError, ldata );
			WriteIndexUlong( ATABaseAddr[bChannelNumber], iNDEXIDESATAError, ldata );
			#endif				
			if ( ldata & (R_ERR|CRC_ERR|DISPARITY_ERR|Decode_10B_TO_8B_ERR|DATA_ERR) ) { /* 0x00780100 */
				SATAerrorFlag = TRUE;
			}
		}
	}
				
	while ((U32)ultmpATAPacketAddress != U32NULL){						

		pATATask=(PATA_TASK)ultmpATAPacketAddress->PacketHead.PTA;

		/* check is error packet */
		if ((pCurSEQ_INFO->PACCNT == SEQCntCtrl) | (SATAerrorFlag == TRUE) )
		{ 	/* error packet */

			errorFlag = TRUE;

			pCurSEQ_INFO->SEQID2PacketHead=(PVOID)U32NULL;
			pCurSEQ_INFO->SEQID2PacketTail=(PVOID)U32NULL;			
			/* abort packets queue at the rear of this packet and and wait queue packets. */
			Abort_All_Undone_ATAPackets(bChannelNumber,(PCAM_ATA_PACKET)ultmpATAPacketAddress->PacketHead.NPA);
			ultmpATAPacketAddress->PacketHead.NPA=(PVOID)U32NULL;			

			/* get ATA Global control & Status Register */
			ReadPortUchar(ATABaseAddr[bChannelNumber], (ATA_STATUS_REGISTER_OFFSET+2), pATATask->ATAStatus);

			if (gChnlConfig[bChannelNumber].ChnlType == CHNL_SATA )
			{
				U8  status=0;

				status=camWARNING;			
				for (count=0;count<DEF_SATA_INITCOUNT;count++) 
				{							
					for ( i = 0; i < 10 ; i++ ) {
						if (status==camWARNING) {
							if ( CAM_HardResetSATAChannel(bChannelNumber) == camDEVICE_NOT_FOUND )
							{	/* no drive connected */
			
								/* if CAM detects the drives of the channel been set down, 
								call camCheckDriveStatus() with status:NO_DRIVE to notify the channel driver. */
								if ( gDrvConfig[bChannelNumber][0].DevFlag & DEV_EXIST ){
									gDrvConfig[bChannelNumber][0].DevFlag = DEV_NOTFOUND;
									camCheckDriveStatus(bChannelNumber, 0, NO_DRIVE);
								}
								break;
							}
						}
						/* wait 3 seconds, following the ATA spec. special for dongle+ ATA HDD combination */			
						if ( (status=WaitOnReady(bChannelNumber)) == camSUCCESS ) 
							break;
					}

					if ( gDrvConfig[bChannelNumber][0].DevFlag == DEV_NOTFOUND)
						break;	/* disk is gone or bad */
				
					if( i >= 10 ) {
						if (status==camFAIL) {
							if ( CAM_HardResetSATAChannel(bChannelNumber) == camDEVICE_NOT_FOUND ) {
			
								/* if CAM detects the drives of the channel been set down, 
								call camCheckDriveStatus() with status:NO_DRIVE to notify the channel driver. */
								if ( gDrvConfig[bChannelNumber][0].DevFlag & DEV_EXIST ){
									gDrvConfig[bChannelNumber][0].DevFlag = DEV_NOTFOUND;
									camCheckDriveStatus(bChannelNumber, 0, NO_DRIVE);
									break;
								}						
							}
						}				
						continue;	/* drive not ready after 30 seconds. */
					}

					/* init disks */
					if ( gDrvConfig[bChannelNumber][0].DevFlag & DEV_EXIST ) {
						if (CAMInitDevice(&(gDrvConfig[bChannelNumber][0])) != camFAIL)
							break;	/* disk is back. */
						else if (count == (DEF_SATA_INITCOUNT-1)) {
							/* if CAM detects the drives of the channel been set down, 
							call camCheckDriveStatus() with status:NO_DRIVE to notify the channel driver. */
							gDrvConfig[bChannelNumber][0].DevFlag = DEV_NOTFOUND;
							camCheckDriveStatus(bChannelNumber, 0, NO_DRIVE);
							break;
						}
					}				
				}/* count for loop*/
			}
			else	/* parallel channel */
			{
				
				/* When Drive DMARQ still exist, we can't do any PIO access to ATA bus. */
				/* But do hard reset, that will reset 199. It should be a problem for dual master mode!*/	
				/* do hard reset */ 
				ReadPortUchar(HostBaseAddr[bAdapterNumber],oFFSETHOSTPCICTL+1 , bData );
				bData &= ~ (0x10 << bCh);
				WritePortUchar(HostBaseAddr[bAdapterNumber],oFFSETHOSTPCICTL+1 , bData );
				camStallExecution(1);
				bData |= (0x10 << bCh);
				WritePortUchar(HostBaseAddr[bAdapterNumber],oFFSETHOSTPCICTL+1 , bData );

				/* soft reset ATA Module. */
				ATASoftResetModule(bChannelNumber);
	
				camStallExecution(1);
				/* init disks */
				if ( gDrvConfig[bChannelNumber][0].DevFlag & DEV_EXIST ) {
					if (CAMInitDevice(&(gDrvConfig[bChannelNumber][0])) == camFAIL) {
						/* if CAM detects the drives of the channel been set down, 
						call camCheckDriveStatus() with status:NO_DRIVE to notify the channel driver. */
						gDrvConfig[bChannelNumber][0].DevFlag = DEV_NOTFOUND;
						camCheckDriveStatus(bChannelNumber, 0, NO_DRIVE);
					}
				}	
							
				if ( gDrvConfig[bChannelNumber][1].DevFlag & DEV_EXIST ) {
					if (CAMInitDevice(&(gDrvConfig[bChannelNumber][1])) == camFAIL) {
						/* if CAM detects the drives of the channel been set down, 
						call camCheckDriveStatus() with status:NO_DRIVE to notify the channel driver. */
						gDrvConfig[bChannelNumber][1].DevFlag = DEV_NOTFOUND;
						camCheckDriveStatus(bChannelNumber, 1, NO_DRIVE);
					}
				}					
			}

			pATATask->ATAStatus &= ATAERR_HWERROR;
			pATATask->ATAStatus &= ~ATAERR_DRV;	
			pATATask->ATAStatus |= (ATA_ERROR|ATA_TIMEOUT);	
																				
			/* read 3f6 */
			pATATask->Cmd.ATACmd.bStatus = ReadIndexUchar(ATABaseAddr[pATATask->bCh], iNDEXIDEAlternateStatus);

			if (pATATask->Cmd.ATACmd.bStatus & IDE_STATUS_BUSY){
				pATATask->ATAStatus &= ~ATAERR_DRV;
				pATATask->ATAStatus|=ATA_TIMEOUT;
			}
			else{
				/* set disk status */
				if (pATATask->ATACmdFlag & ATA_DEVICE)									
					ATAErrorStatus(pATATask);
				else {	/* ATAPI device */
					/* ATAPI error and not internel sense */
					if (!(pATATask->ATACmdFlag & INTERNAL_SENSE)){
						/* get ATAPI error , if INTERNAL_SENSE error, ingore it.*/
						ATAPIErrorStatus(pATATask);

						/* must have sense buffer so can do internel sense command */
						if ((pATATask->SenseInfoLength > 1)) {
							/* If ATAPI packet command error, than send a internel "REQUEST SENSE Command" 
							     to get the sense datas. 	*/
							pATATask->ATACmdFlag = INTERNAL_SENSE;
						}
					}
					else {
							pATATask->ATACmdFlag &= ~INTERNAL_SENSE;
							ATAPIErrorStatus(pATATask); /* even request sense is failed. */			
							ReadIndexUchar(ATABaseAddr[pATATask->bCh], iNDEXIDEStatus); /*clear possible device INT */
   					}												
				}
			}
		}
		else
		{
			pCurSEQ_INFO->PACCNT--;
			pATATask->ATAStatus= 0;		/* no error */
			if (pATATask->ATACmdFlag & ATA_STATUS_RETURN) /* need read it's ata registers statses when command success completed */
				ATAErrorStatus(pATATask);
								
			if ( gChnlConfig[bChannelNumber].ChnlType == CHNL_SATA )
			{
				if (SATAerrorFlag == TRUE) {
					pATATask->ATAStatus = ATA_ERROR+ATAERR_DRV;
					pATATask->Cmd.ATACmd.bStatus |= IDE_STATUS_DF+IDE_STATUS_IDLE;
				}
			}			
		}
								
	
		/* free sg resource */
		CAMFreeSG(bAdapterNumber, ATA_PAC, (PVOID)ultmpATAPacketAddress->PacketHead.PSG);
		
		ultmpATAPacketAddress_next = (PCAM_ATA_PACKET)ultmpATAPacketAddress->PacketHead.NPA;	
		
		/* free packet resource. */
		CAMFreePacket(bAdapterNumber, ATA_PAC, (PVOID)ultmpATAPacketAddress);		

		if (pATATask->ATACmdFlag & INTERNAL_SENSE)
			SubmitInternelSense(pATATask);
								
		if ( !(pATATask->ATACmdFlag & INTERNAL_SENSE) )
			pATATask->callback(pATATask);

		if (errorFlag == TRUE)
			break;
			
		/* next packet */
		ultmpATAPacketAddress = ultmpATAPacketAddress_next;
		
	}

	pCurSEQ_INFO->SEQID2PacketHead=(PVOID)U32NULL;
	pCurSEQ_INFO->SEQID2PacketTail=(PVOID)U32NULL;
	ATAModuleBusy[bChannelNumber]=FALSE;
	CAMFreeSEQID(bAdapterNumber,SEQID);
	/* if ( ATAModuleNeedPush[bChannelNumber]==FALSE )
		ATASoftResetModule(bChannelNumber); */	/* turn off the LED */
	
	/* Is caused by disk off ? */
	if (pATATask)
	{
		if( !pATATask->bID)
		{
			U8	bCh = pATATask->bCh;
			if ( gDrvConfig[bCh][0].pEnclosure ) {
				Check_Enclosure_PowerState(bCh);
				if ( gBOXStatus[bCh].PowerState == PowerOFF ) {
					if ( gDrvConfig[bCh][0].DevFlag & DEV_EXIST ){
						gDrvConfig[bCh][0].DevFlag = DEV_NOTFOUND;
						camCheckDriveStatus(bCh, 0, NO_DRIVE);
					}
				}					
			}	
		}		
	}

	/* must check module is need to push, By it maybe pushed when no SQEID. */
	for (i=(bAdapterNumber*MAX_ATA_CHNL);i<((bAdapterNumber+1)*MAX_ATA_CHNL);i++) {
		if ( (ATAModuleNeedPush[i]==TRUE) && (ATAModuleBusy[i]==FALSE) ){
			/* start ata module */
			StartATAOperation(i);
			break;
		}
	}
	
	ATAModuleReceiveTask[bChannelNumber]=receiveStatus;
	
	return;
}

#if (MAX_ADAPTER_NUM>0)
void ATA_Timeout0(void)
{
	ATA_Timeout(0x00);
	return;
}

void ATA_Timeout1(void)
{
	ATA_Timeout(0x01);
	return;
}

void ATA_Timeout2(void)
{
	ATA_Timeout(0x02);
	return;
}

void ATA_Timeout3(void)
{
	ATA_Timeout(0x03);
	return;
}
#endif
#if (MAX_ADAPTER_NUM>1)
void ATA_Timeout4(void)
{
	ATA_Timeout(0x04);
	return;
}

void ATA_Timeout5(void)
{
	ATA_Timeout(0x05);
	return;
}

void ATA_Timeout6(void)
{
	ATA_Timeout(0x06);
	return;
}

void ATA_Timeout7(void)
{
	ATA_Timeout(0x07);
	return;
}
#endif
#if (MAX_ADAPTER_NUM>2)
void ATA_Timeout8(void)
{
	ATA_Timeout(0x08);
	return;
}

void ATA_Timeout9(void)
{
	ATA_Timeout(0x09);
	return;
}

void ATA_TimeoutA(void)
{
	ATA_Timeout(0x0A);
	return;
}

void ATA_TimeoutB(void)
{
	ATA_Timeout(0x0B);
	return;
}
#endif
#if (MAX_ADAPTER_NUM>3)
void ATA_TimeoutC(void)
{
	ATA_Timeout(0x0C);
	return;
}

void ATA_TimeoutD(void)
{
	ATA_Timeout(0x0D);
	return;
}

void ATA_TimeoutE(void)
{
	ATA_Timeout(0x0E);
	return;
}

void ATA_TimeoutF(void)
{
	ATA_Timeout(0x0F);
	return;
}
#endif

void (*ATA_Timeout_Function[]) (void) = {

#if (MAX_ADAPTER_NUM>0)
  ATA_Timeout0,
  ATA_Timeout1,
  ATA_Timeout2,
  ATA_Timeout3,
#endif
#if (MAX_ADAPTER_NUM>1)
  ATA_Timeout4,
  ATA_Timeout5,
  ATA_Timeout6,
  ATA_Timeout7,
#endif
#if (MAX_ADAPTER_NUM>2)
  ATA_Timeout8,
  ATA_Timeout9,
  ATA_TimeoutA,
  ATA_TimeoutB,
#endif  
#if (MAX_ADAPTER_NUM>3)
  ATA_TimeoutC,
  ATA_TimeoutD,
  ATA_TimeoutE,
  ATA_TimeoutF,  
#endif  
};



/* if can allocate packet, it can insert to ataqueue. */
U8 Put2ATAQueue(PCAM_ATA_PACKET CAM_ATAPacket,U8 direction)
{
	PATA_TASK pATATask;

	pATATask=CAM_ATAPacket->PacketHead.PTA;	

	if (direction == QUEUETail){	/* put packet at the tail of packet queue */
		ATAQueue[pATATask->bCh][ATAQueueTail[pATATask->bCh]].pATAPacket=CAM_ATAPacket;

		ATAQueueTail[pATATask->bCh]++;

		if (ATAQueueTail[pATATask->bCh]== (MAX_ATA_PAC+1))
			ATAQueueTail[pATATask->bCh]=0;
	}
	else{	/* direction == QUEUEHead  */	 /* put packet at the head of packet queue */
		
		if (ATAQueueHead[pATATask->bCh]==0)
			ATAQueueHead[pATATask->bCh]=MAX_ATA_PAC;
		else
			ATAQueueHead[pATATask->bCh]--;

		ATAQueue[pATATask->bCh][ATAQueueHead[pATATask->bCh]].pATAPacket=CAM_ATAPacket;
	}
	
	ATAModuleNeedPush[pATATask->bCh]=TRUE;

	return TRUE;
}

PCAM_ATA_PACKET GetATA_PacketFromATAQueue(U8 bChannelNumber)
{
	PCAM_ATA_PACKET pATAPacket;

	if(ATAQueueHead[bChannelNumber]==ATAQueueTail[bChannelNumber])	/* no queue packet */
	{
		ATAModuleNeedPush[bChannelNumber]=FALSE;
		return ZERO_NULL;
	}
	
	pATAPacket=ATAQueue[bChannelNumber][ATAQueueHead[bChannelNumber]].pATAPacket;

	ATAQueueHead[bChannelNumber]++;
	if (ATAQueueHead[bChannelNumber]== (MAX_ATA_PAC+1))
		ATAQueueHead[bChannelNumber]=0;

	/* still have packet */
	if(	ATAQueueHead[bChannelNumber]!=ATAQueueTail[bChannelNumber]){
		ATAModuleNeedPush[bChannelNumber]=TRUE;

	}else {
		ATAModuleNeedPush[bChannelNumber]=FALSE;
	}

	return pATAPacket;
}
   

/* if packet at seq queue, return the first packet ATACmdFlag, else return ZERO_NULL*/
U8 SeqIDQueueFirstATATaskType(U8 bAdapterNumber, U8 SeqID)
{
	PSEQ_INFO	pCurSEQ_INFO;
	PCAM_ATA_PACKET ultmpATAPacketAddress;
	PATA_TASK pATATask;
	
	pCurSEQ_INFO = &(gSEQ_INFO[bAdapterNumber][SeqID]);
	
	if(pCurSEQ_INFO->SEQID2PacketHead==(PVOID)U32NULL)
		return ZERO_NULL;
	else{
		
		ultmpATAPacketAddress = (PCAM_ATA_PACKET)pCurSEQ_INFO->SEQID2PacketHead;
					
		pATATask=(PATA_TASK)ultmpATAPacketAddress->PacketHead.PTA;

		return (pATATask->ATACmdFlag);
		
	}
}


U8 ATAQueueType(U8 bChannelNumber)
{
	PCAM_ATA_PACKET pATAPacket;
	PATA_TASK pATATask;

	if(ATAQueueHead[bChannelNumber]==ATAQueueTail[bChannelNumber])	/* no queue packet */
		return ZERO_NULL;
	
	
	pATAPacket=ATAQueue[bChannelNumber][ATAQueueHead[bChannelNumber]].pATAPacket;
	pATATask=(PATA_TASK)pATAPacket->PacketHead.PTA;

	return (pATATask->ATACmdFlag);
}



U8 prepareATAPacketSEQID(U8 bChannelNumber, U8 FreeSEQID)
{
	U8 PacketCount=ZERO_NULL;
	PCAM_ATA_PACKET CAM_ATAPacket;
	
	U8 bAdapterNumber;
	U8 SeqIDType;
	U8 packetTaskType;

	U8 bAdapterChannelNumber;
	U8 putAtLastPacket=FALSE;
	PSEQ_INFO	pCurSEQ_INFO;
	
	bAdapterChannelNumber=bChannelNumber%MAX_ATA_CHNL;	

	bAdapterNumber = bChannelNumber/MAX_ATA_CHNL;	
	
	pCurSEQ_INFO = &(gSEQ_INFO[bAdapterNumber][FreeSEQID]);	
	pCurSEQ_INFO->GO=TRUE;

	/* get ata packet. */
	while(1)
	{
		SeqIDType = SeqIDQueueFirstATATaskType(bAdapterNumber, FreeSEQID);

		/* If a packet is PIO_XFER or SWAPBOX_CMD, it will not queue with other packets when executing.
			(Only DMA XFER and non-data packet can queued at executing packet queue.)		
		*/

		/* If the packet is ATAPI_DEVICE , it only can queued at the tail of execute packets queue(or only itself at the queue),
		    Because when errors occurred at ATAPI packet command, it must run "Request Sense Buffer" to get the sense datas before other
		    command had be sent.
		*/
		
		/* If the packet's ATACmdFlag be set with ATA_STATUS_RETURN , it only can queued at the tail of execute packets queue(or only itself at the queue),
		    Because when command success completed, also need read it's ata registers statses.
		*/
				
		if (SeqIDType == ZERO_NULL){	/* no packet at SeqIDQueue */

			packetTaskType = ATAQueueType(bChannelNumber);
			if (packetTaskType & PIO_XFER)
				pCurSEQ_INFO->GO=FALSE;
			if (packetTaskType & SWAPBOX_CMD)
				pCurSEQ_INFO->GO=FALSE;
			else if (!(packetTaskType & ATA_DEVICE))	/* ATAPI Packet */
				pCurSEQ_INFO->GO=FALSE;
			else if (SeqIDType & ATA_STATUS_RETURN)	/* need read it's ata registers statses */
				pCurSEQ_INFO->GO=FALSE;
			CAM_ATAPacket = GetATA_PacketFromATAQueue(bChannelNumber);
		}
		else{	/* have packet at SeqIDQueue */
			if (SeqIDType & PIO_XFER){ /* Is PIO transfer command at SeqID queue */
				return PacketCount;
			}
			else if (SeqIDType & SWAPBOX_CMD){ /* Is SWAPBOX_CMD at SeqID queue */
				return PacketCount;
			}
			else if (!(SeqIDType & ATA_DEVICE))	/* ATAPI Packet */
				return PacketCount;
			else if (SeqIDType & ATA_STATUS_RETURN)	/* need read it's ata registers statses */
				return PacketCount;				
			else{
				/* get next packet type */
				packetTaskType = ATAQueueType(bChannelNumber);
				if (packetTaskType & PIO_XFER){
					pCurSEQ_INFO->GO=FALSE;
					return PacketCount;
				}
 				if (packetTaskType & SWAPBOX_CMD){ /* SWAPBOX_CMD packet*/
 					pCurSEQ_INFO->GO=FALSE;
					return PacketCount;
				}				
 				else if (!(packetTaskType & ATA_DEVICE))	/* ATAPI Packet */
					putAtLastPacket=TRUE;			
				else if (SeqIDType & ATA_STATUS_RETURN)	/* need read it's ata registers statses */
					putAtLastPacket=TRUE;				
				CAM_ATAPacket = GetATA_PacketFromATAQueue(bChannelNumber);
			}
		}
		
		if ( CAM_ATAPacket == ZERO_NULL)	/* no packet */
			break;
			
		PacketCount++;
		
		/* set SEQID */
		CAM_ATAPacket->ATAPacket.bSynSeqID=FreeSEQID; 		

		/* put ata packets to seqid2packet queue,so in isr, */
		/* driver can release the relevant resource and  */
		/* can point to the right PTA pointer */
		Put2SeqIDQueue(bAdapterNumber,(PVOID)CAM_ATAPacket,FreeSEQID);

		if (putAtLastPacket)
		{
			pCurSEQ_INFO->GO=FALSE;
			break;
		}
			
		if (PacketCount>=PacketQueueCount[bAdapterNumber].ATAModule[bAdapterChannelNumber])
			break;		
	}
	return PacketCount;

}


void StartATAOperation(U8 bChannelNumber)
{
	U8 PacketCount=ZERO_NULL;
	U8 FreeSEQID;
	U8 bAdapterNumber;
	U8 SeqIDType;

	bAdapterNumber = bChannelNumber/MAX_ATA_CHNL;
	
	if (ATAModuleBusy[bChannelNumber]==TRUE)
		return;
	

	/* get free seqid */
	FreeSEQID=CAMAllocSEQID(bAdapterNumber);	

	if (FreeSEQID==U8NULL){
		return;
	}

	PacketCount = prepareATAPacketSEQID(bChannelNumber,FreeSEQID);
	if ( PacketCount== ZERO_NULL)	/* no packet */
	{
		CAMFreeSEQID(bAdapterNumber,FreeSEQID);	
		return;		
	}

	ATAModuleBusy[bChannelNumber]=TRUE;
	ATAModuleSEQID[bChannelNumber]=FreeSEQID;

	/* if swap box command, not send command to device , only get the priority*/
	SeqIDType = SeqIDQueueFirstATATaskType(bAdapterNumber, FreeSEQID);
	
	if (SeqIDType & SWAPBOX_CMD){ /* Is SWAPBOX_CMD at SeqID queue */
		HandleInternalSwapbox_CMD(bChannelNumber, FreeSEQID);
	}
	else{			
		/* set ATA Module timeout timer. */
		if ( !(((PPACKET_HEAD)gSEQ_INFO[bAdapterNumber][FreeSEQID].SEQID2PacketHead)->Flag & PACFLAG_ATAPI) )
			ATA_Timeout_TimerID[bChannelNumber]=camTimer(CAMTimeoutTimes[bAdapterNumber].ATACommand,ATA_Timeout_Function[bChannelNumber]);	
		else {
			/* ATAPI devices need special care */
			IssueATAPIPktCmd(bChannelNumber, FreeSEQID);
			ATA_Timeout_TimerID[bChannelNumber]=camTimer(CAMTimeoutTimes[bAdapterNumber].ATAPICommand,ATA_Timeout_Function[bChannelNumber]);
			((PPACKET_HEAD)gSEQ_INFO[bAdapterNumber][FreeSEQID].SEQID2PacketHead)->Flag &= ~PACFLAG_ATAPI; /* clear this */
		}

		/* set Sequence Counter Control Register */
		WritePortUlong(HostBaseAddr[bAdapterNumber], FreeSEQID*4, PacketCount);
	
		/* start ata module */
		WritePortUlong(ATABaseAddr[bChannelNumber], ATA_PACSTART_REGISTER_OFFSET, ((PPACKET_HEAD)gSEQ_INFO[bAdapterNumber][FreeSEQID].SEQID2PacketHead)->Address);
	}
	return;
}


void prepareATACommand(PCAM_ATA_PACKET CAM_ATAPacket,PATA_TASK pATATask)
{
	PU8		pAtrl;
	U32 	startingSector;
	U8 		LargeLBA = checkLargeLBA(pATATask);

	/* set bATRL */

	pAtrl = &(CAM_ATAPacket->ATAPacket.bATRL[0]);	
			
	/* select drive */
	*pAtrl++=ATRLREG_REG_SIZE_1|ATRLREG_DEVICESELECT;				
	*pAtrl++ = (U8) (0xE0 | (pATATask->bID << 4));
	
	*pAtrl++=ATRLREG_REG_SIZE_1|
				ATRLREG_CONDITION_CHECK_NOT_BUSY|
				ATRLREG_DEVICESELECT;
	*pAtrl++ = (U8) (0xE0 | (pATATask->bID << 4));	/* twice, to make sure drive is ready */
				
	*pAtrl++=ATRLREG_REG_SIZE_1|
				ATRLREG_X_3F6;
	*pAtrl++=0x08; 	/* enable interrupt */

    *pAtrl++ = ATRLREG_REG_SIZE_1|
     				ATRLREG_FEATURE;
	*pAtrl++ = pATATask->Cmd.ATACmd.bFeature; 
	
	if ( LargeLBA == TRUE )
	{
		/* previous content */
		*pAtrl++ = ATRLREG_REG_SIZE_1|
     				ATRLREG_SECTOR_COUNT;
		*pAtrl++ =(U8)(pATATask->Cmd.ATACmd.bCount >> 8); 	/* SecCnt 15:8 */

		startingSector=pATATask->Cmd.ATACmd.LBAl;			
 		*pAtrl++ = ATRLREG_REG_SIZE_1|
     				ATRLREG_LBA0_7 ; 
		*pAtrl++ = (U8) *((U8 *)(&startingSector) + 3);	/* LBA 31:24 */

		startingSector=pATATask->Cmd.ATACmd.LBAh;
 		*pAtrl++ = ATRLREG_REG_SIZE_1|
     					ATRLREG_LBA8_15;   
 		*pAtrl++ = (U8) *((U8 *)(&startingSector));	/* LBA 39:32 */

   		*pAtrl++ = ATRLREG_REG_SIZE_1|
     				ATRLREG_LBA16_23 ;
   		*pAtrl++ = (U8) *((U8 *)(&startingSector) + 1); /* LBA 47:40 */
   	
	}
 	/* most recently written */
 	
	*pAtrl++ = ATRLREG_REG_SIZE_1|
     				ATRLREG_SECTOR_COUNT;
	*pAtrl++ = (U8)pATATask->Cmd.ATACmd.bCount; /* SecCnt 7:0 */
	
	startingSector=pATATask->Cmd.ATACmd.LBAl;
    *pAtrl++ = ATRLREG_REG_SIZE_1|
     				ATRLREG_LBA0_7 ; 
	*pAtrl++ = (U8) *((U8 *)(&startingSector)); /* LBA 7:0 */
    
    *pAtrl++ = ATRLREG_REG_SIZE_1|
     				ATRLREG_LBA8_15;   
	*pAtrl++ = (U8) *((U8 *)(&startingSector) + 1); /* LBA 15:8 */

    *pAtrl++ = ATRLREG_REG_SIZE_1|
     				ATRLREG_LBA16_23;
	*pAtrl++ = (U8) *((U8 *)(&startingSector) + 2); /* LBA 23:16 */
				
	*pAtrl++=	ATRLREG_REG_SIZE_1|
				ATRLREG_CONDITION_CHECK_NOT_BUSY|
				ATRLREG_DEVICESELECT;				
				
	if ( LargeLBA != TRUE )
 		*pAtrl++ = (U8) ((*((U8 *)(&startingSector) + 3) & 0x0F) | 0xE0 | (pATATask->bID << 4)); /* LBA 27:24 */
 	else
		*pAtrl++ = (U8) (0xE0 | (pATATask->bID << 4)); /* lba bit must be set */

	*pAtrl++ = ATRLREG_REG_SIZE_1|
     				ATRLREG_COMMAND |
     				ATRLREG_X_END_1F7;
	*pAtrl++ = pATATask->Cmd.ATACmd.bCmd;  
      	   
	return;
}

void prepareATAPICommand(PCAM_ATA_PACKET CAM_ATAPacket,PATA_TASK pATATask)
{
	PU8          pAtrl;

	/* set bATRL */

	pAtrl = &(CAM_ATAPacket->ATAPacket.bATRL[0]);	

	/* send 12 bytes(6 words) command datas */	
	*pAtrl++=ATRLREG_REG_SIZE_6|
				ATRLREG_DATA|
				ATRLREG_X_END_1F0;
	
	*pAtrl++=pATATask->Cmd.Cdb[0];
	*pAtrl++=pATATask->Cmd.Cdb[1];

	*pAtrl++=pATATask->Cmd.Cdb[2];
	*pAtrl++=pATATask->Cmd.Cdb[3];

	*pAtrl++=pATATask->Cmd.Cdb[4];
	*pAtrl++=pATATask->Cmd.Cdb[5];

	*pAtrl++=pATATask->Cmd.Cdb[6];
	*pAtrl++=pATATask->Cmd.Cdb[7];

	*pAtrl++=pATATask->Cmd.Cdb[8];
	*pAtrl++=pATATask->Cmd.Cdb[9];

	*pAtrl++=pATATask->Cmd.Cdb[10];
	*pAtrl++=pATATask->Cmd.Cdb[11];
	
	return;
}

void prepareATAPacket(PCAM_ATA_PACKET CAM_ATAPacket,PCAM_ATA_SG CAM_ATASG,PATA_TASK pATATask)
{


	CAM_ATAPacket->PacketHead.NPA=(PVOID)U32NULL;
	CAM_ATAPacket->PacketHead.PTA=pATATask;
	CAM_ATAPacket->PacketHead.ModelType=ATA_PAC;
	CAM_ATAPacket->PacketHead.PSG=(PVOID)CAM_ATASG;


	CAM_ATAPacket->ATAPacket.bControl = 0;
	/* set packet bControl */
	/* check is a data transfer */
	if (pATATask->ATACmdFlag & camDATA_XFER)
	{
		/* if PIO transfer command, send it as packet command, and at ISR(), must read 
		    all needed datas by PIO transfer. So set this to nondata transfer packet.
		*/
		if (pATATask->ATACmdFlag & PIO_XFER){		/* PIO transfer */
			CAM_ATAPacket->ATAPacket.bControl |= ATACTRL_NONDATA;	
		}
		else{	/* DMA transfer */

			/* set DMA R/W */
			if (pATATask->ATACmdFlag & camDATA_IN)	
				CAM_ATAPacket->ATAPacket.bControl |= ATACTRL_DMAREAD;
			else
				CAM_ATAPacket->ATAPacket.bControl &= ~ATACTRL_DMAREAD;
					
			
			/* check is ATA and with PSEUDO_CMD? */	/* ATAPI not support seudo CMD */
			if ( (pATATask->ATACmdFlag & ATA_DEVICE)
				&& (pATATask->ATACmdFlag & PSEUDO_CMD))
			{		
				/* check is need change command? */
				switch(pATATask->Cmd.ATACmd.bCmd){
					case IDE_COMMAND_READ:
						pATATask->Cmd.ATACmd.bCmd =IDE_COMMAND_READ_DMA;
					case IDE_COMMAND_READ_DMA:
						/*1.When R/W command start address is less than 128G but the end address across the 128G, cam still do 
							standard R/W command(no extended R/W command) will cause R/W datas error.
				     		  2.When R/W command, if the address less 128G, use standard R/W command, and if large than 128G, use extended R/W command,
				     			but this seem cause the drive confused.	*/
						/* check lba address large than 2^28*/
						/* if ( (pATATask->Cmd.ATACmd.LBAh) 
							|| (pATATask->Cmd.ATACmd.LBAl & 0xF0000000) ) */
						if (gDrvConfig[pATATask->bCh][pATATask->bID].DevFlag & DEV_48BIT)
							pATATask->Cmd.ATACmd.bCmd = IDE_COMMAND_READ_DMA_EXT;
						break;
					
					case IDE_COMMAND_WRITE:
						pATATask->Cmd.ATACmd.bCmd =IDE_COMMAND_WRITE_DMA;
					case IDE_COMMAND_WRITE_DMA:
						/*1.When R/W command start address is less than 128G but the end address across the 128G, cam still do 
							standard R/W command(no extended R/W command) will cause R/W datas error.
				     		  2.When R/W command, if the address less 128G, use standard R/W command, and if large than 128G, use extended R/W command,
				     			but this seem cause the drive confused.	*/					
						/* check lba address large than 2^28*/
						/* if ( (pATATask->Cmd.ATACmd.LBAh) 
							|| (pATATask->Cmd.ATACmd.LBAl & 0xF0000000) ) */
						if (gDrvConfig[pATATask->bCh][pATATask->bID].DevFlag & DEV_48BIT)
							pATATask->Cmd.ATACmd.bCmd = IDE_COMMAND_WRITE_DMA_EXT;					
						break;
					default:
						break;
				}			
			}
		}
	}
	else
	{
		CAM_ATAPacket->ATAPacket.bControl |= ATACTRL_NONDATA;

		/* check is ATA and with PSEUDO_CMD? */	/* ATAPI not support seudo CMD */
		if ( (pATATask->ATACmdFlag & ATA_DEVICE)
			&& (pATATask->ATACmdFlag & PSEUDO_CMD))
		{		
			/* check is need change command? */
			switch(pATATask->Cmd.ATACmd.bCmd){
				case IDE_COMMAND_VERIFY:
					/*1.When R/W command start address is less than 128G but the end address across the 128G, cam still do 
						standard R/W command(no extended R/W command) will cause R/W datas error.
				     	  2.When R/W command, if the address less 128G, use standard R/W command, and if large than 128G, use extended R/W command,
				     		but this seem cause the drive confused.	*/					
					/* check lba address large than 2^28*/
					/* if ( (pATATask->Cmd.ATACmd.LBAh) 
						|| (pATATask->Cmd.ATACmd.LBAl & 0xF0000000) ) */
					if (gDrvConfig[pATATask->bCh][pATATask->bID].DevFlag & DEV_48BIT)
						pATATask->Cmd.ATACmd.bCmd = IDE_COMMAND_VERIFY_EXT;
					break;
				case IDE_COMMAND_SMART_CMD:
				 	if ( gDrvConfig[pATATask->bCh][pATATask->bID].Features & DEV_SMART ) {
						if ( pATATask->Cmd.ATACmd.bFeature == 0xD8 )
							gDrvConfig[pATATask->bCh][pATATask->bID].Features |= DEV_EN_SMART;
						if ( pATATask->Cmd.ATACmd.bFeature == 0xD9 )
							gDrvConfig[pATATask->bCh][pATATask->bID].Features &= ~DEV_EN_SMART;
					}
					break;
				case IDE_COMMAND_SET_FEATURES:
				 	if ( gDrvConfig[pATATask->bCh][pATATask->bID].Features & DEV_WRITECACHE ) {
						if ( pATATask->Cmd.ATACmd.bFeature == 0x02 )
							gDrvConfig[pATATask->bCh][pATATask->bID].Features |= DEV_EN_WRITECACHE;
						if ( pATATask->Cmd.ATACmd.bFeature == 0x82 )
							gDrvConfig[pATATask->bCh][pATATask->bID].Features &= ~DEV_EN_WRITECACHE;
					}
					break;
				default:
					break;
			}			
		}
	}
	
	CAM_ATAPacket->ATAPacket.bSynSeqID = SEQ_NO_SEQID;	/* no SEQID now. */
	CAM_ATAPacket->ATAPacket.bDelaySeqID = SEQ_NO_DELAY;	
	CAM_ATAPacket->ATAPacket.ulNCA = ZERO_NULL;

	/* set ulpSG. */
	if (pATATask->SGCount){	/* have SG table */
		checkConvertSG((PCAMSG)pATATask->pSG,(PCAMSG)CAM_ATASG);
		CAM_ATAPacket->ATAPacket.ulPSG=CAM_ATASG->Address;
	}
	else{	/* no SG table */
		CAM_ATAPacket->ATAPacket.ulPSG=ZERO_NULL;
	}


	/* set bATRL */

	/* check is ATA or not? */
	if (pATATask->ATACmdFlag & ATA_DEVICE){		/* ATA device */
		prepareATACommand(CAM_ATAPacket,pATATask);
	}
	else if (!(pATATask->ATACmdFlag & SWAPBOX_CMD)) {	/* ATAPI device */
		CAM_ATAPacket->PacketHead.Flag |= PACFLAG_ATAPI;
		prepareATAPICommand(CAM_ATAPacket, pATATask);
		if ( CAM_ATAPacket->ATAPacket.ulPSG!= ZERO_NULL )
		{
			U32	TotalBytes = 0 ;
			PCAMSG pSG = (PCAMSG)CAM_ATASG;
			while(1){
				TotalBytes += pSG->wCount;
				if(pSG->CtrlFlag & EOT)
					break;
				pSG++;
			}
			if ( TotalBytes & 0x03 )
			{
				pSG->CtrlFlag &= ~EOT;
				pSG++;
				pSG->StartAddr = CAM_ATASG->Address + CAM_PRD_TBL_SIZE;
				pSG->wCount = (U16)4 - (U16)(TotalBytes & 0x03);
				pSG->CtrlFlag = EOT;
			}
		}
	}
	
	return;
}
		
U8 CAM_SubmitATA (PATA_TASK pATATask)
{
	U8 bAdapterNumber;

	PCAM_ATA_PACKET CAM_ATAPacket;
	PCAM_ATA_SG CAM_ATASG;

	bAdapterNumber = pATATask->bCh/MAX_ATA_CHNL;
	
	/* can Receive task? */
	if (ATAModuleReceiveTask[pATATask->bCh] != TRUE)
		return camBUSY;
			
	/* get free packet address */
	CAM_ATAPacket= CAMAllocPacket(bAdapterNumber, ATA_PAC);

	if (CAM_ATAPacket==(PVOID)U32NULL){	/* no free ata packet. */
		return camBUSY;		
	}	

	/* get free SG address */
	CAM_ATASG=CAMAllocSG(bAdapterNumber, ATA_PAC);
	
	if (CAM_ATASG==(PVOID)U32NULL){	/* no free ata sg. */
		CAMFreePacket(bAdapterNumber, ATA_PAC, (PVOID)CAM_ATAPacket);
		return camBUSY;
	}
	

	/* prepare ata packet */
	prepareATAPacket(CAM_ATAPacket,CAM_ATASG,pATATask);
	
	/* put atapacket to ata queue */
	Put2ATAQueue(CAM_ATAPacket,QUEUETail);

	/* start ata module */
	StartATAOperation(pATATask->bCh);

	return camACCEPTED;
}


U8 WaitOnBusy(U32 IDEBaseAddress)
{ 
	U32	i;
	U8	Status=0;
	
	for (i=0; i<300; i++) {
		Status = ReadIndexUchar(IDEBaseAddress, iNDEXIDEAlternateStatus);
		if ( Status == 0xFF)
			break;
      	if ( Status & IDE_STATUS_BUSY) {
			camStallExecution(1);
			continue;
       	} else {
			break;
   		}
	}
	return(Status);
}

U8 WaitOnBaseBusy(U32 IDEBaseAddress)
{ 
	U32 i;
	U8	Status=0;
	
	for (i=0; i<300; i++) {
		Status = ReadIndexUchar(IDEBaseAddress, iNDEXIDEStatus);
		if ( Status == 0xFF)
			break;
      	if ( Status & IDE_STATUS_BUSY) {
			camStallExecution(1);
			continue;
       	} else {
			break;
   		}
	}
	return(Status);	
}

void AtapiSoftReset(U32 IDEBaseAddress, U8 DeviceNumber)
{
	
	WriteIndexUchar(IDEBaseAddress, iNDEXIDEDeviceHead, (U8)(((DeviceNumber & 0x01) << 4) | 0xA0));
	WriteIndexUchar(IDEBaseAddress, iNDEXIDEDeviceControl, 0x02);
	camStallExecution(1);
	WriteIndexUchar(IDEBaseAddress, iNDEXIDECommand, IDE_COMMAND_ATAPI_RESET);
	camStallExecution(1);
	WriteIndexUchar(IDEBaseAddress, iNDEXIDEDeviceHead, (U8)(((DeviceNumber & 0x01) << 4) | 0xA0));
	WaitOnBaseBusy(IDEBaseAddress);
	camStallExecution(1);
	ReadIndexUchar(IDEBaseAddress, iNDEXIDEStatus);
	WriteIndexUchar(IDEBaseAddress, iNDEXIDEDeviceControl, 0x08 );
	return;
}

U8 WaitForDrq(U32 IDEBaseAddress) 
{ 
	U32 i; 
	U8	Status=0;
	
	for (i=0; i<100; i++) { 
		GetStatus(IDEBaseAddress, Status); 
		if (Status==0xFF)
			break;
		if (Status & IDE_STATUS_BUSY) { 
			camStallExecution(3); 
		} else if (Status & IDE_STATUS_DRQ) { 
			break; 
		} else if (Status & IDE_STATUS_ERROR) { 
			break; 
		} else { 
			camStallExecution(3); 
		} 
	} 
	return( Status );
}

U8 WaitOnReady(U8 bChannelNumber)
{ 
	U32 i;
	U8	status;
	U32 IDEBaseAddress=ATABaseAddr[bChannelNumber];

	/* wait 3 seconds */
	for (i=0; i<300; i++) {
		status = ReadIndexUchar(IDEBaseAddress, iNDEXIDEStatus);
 		status &= ~(IDE_STATUS_ERROR | IDE_STATUS_INDEX | IDE_STATUS_DRQ );
       	if ( status == IDE_STATUS_IDLE )
       		break;
		if ((status == 0x7F) && (i > 0)) {
			if (gChnlConfig[bChannelNumber].ChnlType == CHNL_SATA)
				return(camWARNING); /* no device */
		}
			
 		camStallExecution(1);
	}

	if ( i >=300 )
		return( camFAIL ); /* time-out */
			
	return(camSUCCESS);	
}

U8 WaitForINT(U32 IDEBaseAddress) 
{ 
	U32 i; 
	U8	status;
	
	for (i=0; i<1000; i++) { 
		status = ReadIndexUchar(IDEBaseAddress, iNDEXIDECICR+3);
		if (status & 0x08)
			break;
		camStallExecution(3); 
	}
	if ( i >=1000 )
		return( camFAIL ); /* time-out */
	
	/* clear drive INT */
	status = ReadIndexUchar(IDEBaseAddress, iNDEXIDEStatus);
    status &= ~(IDE_STATUS_ERROR | IDE_STATUS_INDEX | IDE_STATUS_DRQ );
	if (status != IDE_STATUS_IDLE)
		return(camFAIL); /* bad device */	
			
	return( camSUCCESS );
}


