leointerrupt.c 8.38 KB
/**************************************************************************
 *									  *
 *		 Copyright (C) 1994, Silicon Graphics, Inc.		  *
 *									  *
 *  These coded instructions, statements, and computer programs  contain  *
 *  unpublished  proprietary  information of Silicon Graphics, Inc., and  *
 *  are protected by Federal copyright law.  They  may  not be disclosed  *
 *  to  third  parties  or copied or duplicated in any form, in whole or  *
 *  in part, without the prior written consent of Silicon Graphics, Inc.  *
 *									  *
 **************************************************************************/

/*---------------------------------------------------------------------*
        Copyright (C) 1998 Nintendo. (Originated by SGI)
        
        $RCSfile: leointerrupt.c,v $
        $Revision: 1.1.1.1 $
        $Date: 2002/05/02 03:28:40 $
 *---------------------------------------------------------------------*/

#include <R4300.h>
#include <os.h>
#include <rcp.h>
#include <os_internal.h>
#include "osint.h"
#include "piint.h"
#include "leodrive.h"
#include "leo.h"

#define RESETMASK 		0xfffffbfe
#define LEO_DISK_STACKSIZE	4096
char	leoDiskStack[LEO_DISK_STACKSIZE];



extern __OSEventState __osEventStateTab[];

static void __osLeoAbnormalResume(void);
static void __osLeoResume(void);

#define LeoAbort(errCode) 	blockInfo->errStatus = errCode;	\
				__osLeoAbnormalResume(); 	\
				return(1)	

#define PIWait()		pi_stat = IO_READ(PI_STATUS_REG);	\
				while (pi_stat & (PI_STATUS_IO_BUSY | PI_STATUS_DMA_BUSY))  {  \
					pi_stat = IO_READ(PI_STATUS_REG);}

s32
__osLeoInterrupt(void)
{
	u32	stat=0;
	volatile u32	pi_stat;
	u32	bm_stat;
	__OSTranxInfo *info;
	__OSBlockInfo *blockInfo;

	
	info = &(__osDiskHandle->transferInfo);
	blockInfo = &(info->block[info->blockNum]);

	pi_stat = IO_READ(PI_STATUS_REG);

	/* TODO check for DMAing  PI is not disk */

	if (pi_stat & PI_STATUS_DMA_BUSY) {

		/* over run error */

		/* turn off CART interrupt */
			
		__OSGlobalIntMask &= ~(OS_IM_CART & RESETMASK);
		blockInfo->errStatus = SC_OVERRUN_ERROR; 
		/* send message to PI */
		__osLeoResume();

		return(1);
	}
	
	PIWait();
	stat = IO_READ(ASIC_STATUS);
	if (stat & LEO_STAT_MECHA_INT) {

		/* mecha int */

		/* clear MECHA interrupt */
		PIWait();
		IO_WRITE(ASIC_BM_CTL,info->bmCtlShadow|BM_MECHA_INT_RESET);

		/* back to exceptasm, with send_mesg */
		blockInfo->errStatus = LEO_SENSE_NO_ADDITIONAL_SENSE_INFOMATION;
		return(0);
	}

	/* BM interrupt */

	if (info->cmdType == OS_OTHERS) {        /*(1)*/
            return (1);
        }

	if (stat & LEO_STAT_BM_ERROR) {

		/* BM stopped */

		PIWait();
		stat = IO_READ(ASIC_STATUS);
		blockInfo->errStatus = LEO_SENSE_WRITE_FAULT; 
		/* send message to PI */
		__osLeoResume();

		/* enable PI interrupt */

		IO_WRITE(PI_STATUS_REG, PI_STATUS_CLR_INTR);
		__OSGlobalIntMask |= OS_IM_PI;
		return(1);

	}
		
	if (info->cmdType == OS_WRITE) {
		
		/* write operation */


		if ((stat & LEO_STAT_DATA_REQ) == 0) {


			if ((info->sectorNum + 1) != (s32)(USR_SECS_PER_BLK * 
						(s32)(info->transferMode))) {
				/* index error */

				LeoAbort(LEO_SENSE_NO_REFERENCE_POSITION_FOUND);
			}

			/* write operation is done */

			/* enable PI interrupt */

			IO_WRITE(PI_STATUS_REG, PI_STATUS_CLR_INTR);
			__OSGlobalIntMask |= OS_IM_PI;

			blockInfo->errStatus = LEO_SENSE_NO_ADDITIONAL_SENSE_INFOMATION;
			__osLeoResume();
			return(1);
		} else {

			/* DMA Write one sector */

			/* update tranxInfo */
			blockInfo->dramAddr = (void *)
			((u32)blockInfo->dramAddr + blockInfo->sectorSize);
			info->sectorNum++;

			__osEPiRawStartDma(__osDiskHandle, OS_WRITE, 
				ASIC_SECTOR_BUFF, blockInfo->dramAddr, 
				blockInfo->sectorSize);
			return(1);
		}
	} else if (info->cmdType == OS_READ) {
		if (info->transferMode == LEO_SECTOR_MODE){

			if (info->sectorNum > (s32)(blockInfo->C1ErrNum
				 + (USR_SECS_PER_BLK/5) )) {
				
				/* done with sector read */

				LeoAbort(LEO_SENSE_NO_ADDITIONAL_SENSE_INFOMATION);
			}
			if ((stat & LEO_STAT_DATA_REQ) == 0) {
				LeoAbort(LEO_SENSE_UNRECOVERED_READ_ERROR);
			}
		} else {
			blockInfo->dramAddr = (void *)
		((u32)blockInfo->dramAddr + blockInfo->sectorSize);
		}

		bm_stat = IO_READ(ASIC_BM_STATUS);
	
		/* check BM status register */

		if (((bm_stat & LEO_BMST_C1_SINGLE) && 
			(bm_stat & LEO_BMST_C1_DOUBLE)) ||
			(bm_stat & LEO_BMST_MICRO_STATUS)) {

			/* C1 ERROR */

			if (blockInfo->C1ErrNum >= C1_ERROR_LIMIT) {
				if ((info->transferMode != LEO_SECTOR_MODE) ||
				    (info->sectorNum >= (USR_SECS_PER_BLK-2))){

					/* block mode or last user sector */

					LeoAbort(LEO_SENSE_UNRECOVERED_READ_ERROR);
				}
			} else {
				
				/* store err position */

				int errNum = (int)(blockInfo->C1ErrNum);
				blockInfo->C1ErrSector[errNum] =
				(u32)(info->sectorNum + 1);
			}
			blockInfo->C1ErrNum++;
		}

		/* check index error */

		if (stat & LEO_STAT_C2_XFER) {
			if ((info->sectorNum + 1) != 
				(USR_SECS_PER_BLK+C2_SECS_PER_BLK - 1)) {

				/* index not found */

			    LeoAbort(LEO_SENSE_NO_REFERENCE_POSITION_FOUND);

			}

			/* end of read block */

			/* The message will be sent at sector 0 for block1 */

			if ((info->transferMode == LEO_TRACK_MODE) && 
				(info->blockNum == 0)) {

				/* renew  parameters for block1 */

				info->blockNum = 1;
				info->sectorNum = -1;
				info->block[1].dramAddr = (void *)
		((u32)info->block[1].dramAddr - info->block[1].sectorSize);
				blockInfo->errStatus = LEO_SENSE_WRITE_FAULT;  /*(2)*/
			} else {
				/* enable PI interrupt */

				IO_WRITE(PI_STATUS_REG, PI_STATUS_CLR_INTR);
				__OSGlobalIntMask |= OS_IM_PI;

	                        info->cmdType = OS_OTHERS;       /*(1)*/
				blockInfo->errStatus = LEO_SENSE_NO_ADDITIONAL_SENSE_INFOMATION; /*(2)*/
			}


			/* read C2 Syndrome */

			__osEPiRawStartDma(__osDiskHandle, OS_READ, 
				ASIC_C2_BUFF, blockInfo->C2Addr, 
				blockInfo->sectorSize * C2_SECS_PER_BLK);

			/* return back to exceptasm, no send_mesg */
		/*	blockInfo->errStatus = LEO_SENSE_NO_ADDITIONAL_SENSE_INFOMATION; */ /*(2)*/
			return(1);
		}

		/* 
		 * C1ErrNum is 0, but C2 Data is not 0.
		 * Note: At sector 0, we check index error for 
		 * previous block.
		 */

		if ((info->sectorNum == -1) && 
			(info->transferMode == LEO_TRACK_MODE) && 
			(info->blockNum == 1)) {

			__OSBlockInfo *bptr;

			bptr = &(info->block[0]);
			if (bptr->C1ErrNum == 0){
				if (*(int *)(bptr->C2Addr) | 
				    *(int *)((int *)(bptr->C2Addr) + 1) |
				    *(int *)((int *)(bptr->C2Addr) + 2) | 
				    *(int *)((int *)(bptr->C2Addr) + 3)) {
				        bptr->errStatus = LEO_SENSE_UNRECOVERED_READ_ERROR;
					__osLeoAbnormalResume();
					return(1);
				}
			}
			
			/* send message to indicate block0 is done */
			
			bptr->errStatus = LEO_SENSE_NO_ADDITIONAL_SENSE_INFOMATION; /*(2)*/
			__osLeoResume();	/* continue */
		}

		info->sectorNum++;
		if ((stat & LEO_STAT_DATA_REQ) != 0) {

			/* update tranxInfo */
			if (info->sectorNum >= USR_SECS_PER_BLK){
				LeoAbort(LEO_SENSE_NO_REFERENCE_POSITION_FOUND);
			}
				



			/* DMA Read one sector */

			__osEPiRawStartDma(__osDiskHandle, OS_READ, 
				ASIC_SECTOR_BUFF, blockInfo->dramAddr, 
				blockInfo->sectorSize);

			/* return back to exceptasm, no send_mesg */
			blockInfo->errStatus = LEO_SENSE_NO_ADDITIONAL_SENSE_INFOMATION;
			return(1);
		}
		else if (info->sectorNum < USR_SECS_PER_BLK){
			LeoAbort(LEO_SENSE_NO_REFERENCE_POSITION_FOUND);
		}
		return(1);

	} else {

		/* Extra INT1 */

		LeoAbort(LEO_SENSE_DATA_PHASE_ERROR);
	}
}

static void
__osLeoAbnormalResume(void)
{
	__OSTranxInfo *info;
	u32	pi_stat;


	info = &(__osDiskHandle->transferInfo);

	/* leoStop_sequencer */

	PIWait();
	IO_WRITE(ASIC_BM_CTL,info->bmCtlShadow|BM_RESET);
	PIWait();
	IO_WRITE(ASIC_BM_CTL,info->bmCtlShadow);

	/* send message to PI */
	__osLeoResume();

	/* enable PI interrupt */

	IO_WRITE(PI_STATUS_REG, PI_STATUS_CLR_INTR);
	__OSGlobalIntMask |= OS_IM_PI;

}

static void
__osLeoResume(void)
{
	__OSEventState *es;
	OSMesgQueue *mq;
	s32 last;

	/* send message to PI */
	
	es = &__osEventStateTab[OS_EVENT_PI];
	mq = es->messageQueue;
	if ((mq == NULL) || (MQ_IS_FULL(mq)))
		return;
	
	/* Increment the last ptr for next available slot */
        last = (mq->first + mq->validCount) % mq->msgCount;

	/* Copy message into the queue buffer */
	mq->msg[last] = es->message;

	/* Increment valid message counter */
	mq->validCount++;

	if (mq->mtqueue->next != NULL) {
		__osEnqueueThread(&__osRunQueue, __osPopThread(&mq->mtqueue));
	}
}