devmgr.c 6.98 KB

/**************************************************************************
 *                                                                        *
 *               Copyright (C) 1995, 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.  *
 *                                                                        *
 **************************************************************************/

/**************************************************************************
 *
 *  Module: devicemgr.c
 *
 *  $Revision: 1.1.1.2 $
 *  $Date: 2002/10/29 08:06:43 $
 *  $Author: blythe $
 *  $Source: /root/leakn64/depot/rf/sw/n64os20l/libultra/nintendo/pi/devmgr.c,v $
 *
 *  Description:
 *	This file contains the main routine for a Device Manager (GDM).
 *
 **************************************************************************/


#include <os.h>
#include "osint.h"
#include "rcp.h"
#include "piint.h"
#include "leodrive.h"
#include "leoappli.h"


/*
 * Name:   __osDevMgrMain
 *
 * Description:
 *	This is the main loop for the device manager.
 *
 * Note:
 * 	As a policy, all messages sent to the command queue are pointers to
 *	an I/O message block.
 *
 * Pseudo-code:
 *	// The idea here is to alternately listen between 2 message queues,
 *	// one for command and one for event notification.
 *	while always {
 *	    Listen (w/ blocking) on input command queue
 *	    Check for valid message type
 *	    Decode message type
 *	    Process message type (i.e., DMA ROM->DRAM)
 *	    Listen (w/ blocking) on input event queue
 *		// Note that only registered event is sent to this queue
 *	    Send message back to I/O requestor
 *	}
 *
 * Globals Referenced: 
 *	None
 */
void
__osDevMgrMain(void *arg)
{

    OSIoMesg		*mb;
    OSMesg		em, dummy;
    s32			ret;
    OSDevMgr		*dm;
    s32 		messageSend = 0;
	

    dm = (OSDevMgr *)arg;
    mb = NULL;
    ret = 0;
    while (1) {

	/* We assume that all messages in this queue are pointers to 
	 * I/O message blocks (OSIoMesg)
	 */
        (void)osRecvMesg(dm->cmdQueue, (OSMesg *)&mb, OS_MESG_BLOCK);

	if ((mb->piHandle != NULL) && 
			(mb->piHandle->type == DEVICE_TYPE_64DD) &&
			((mb->piHandle->transferInfo.cmdType == OS_READ) ||
			(mb->piHandle->transferInfo.cmdType == OS_WRITE))) {

		__OSBlockInfo *blockInfo;
		__OSTranxInfo *info;

		/* prepare for Disk Dma */
		info = &(mb->piHandle->transferInfo);
		blockInfo = &(info->block[info->blockNum]);
		info->sectorNum = -1;
		if (info->transferMode != LEO_SECTOR_MODE)
			blockInfo->dramAddr = (void *)
			   ((u32)blockInfo->dramAddr - blockInfo->sectorSize);
		if ((info->transferMode == LEO_TRACK_MODE) &&
		    (mb->piHandle->transferInfo.cmdType == OS_READ)){
			messageSend = 1;
		} else 
			messageSend = 0;
		
		/* Block to get resource token */
		(void)osRecvMesg(dm->acsQueue, &dummy, OS_MESG_BLOCK);
		
		/* Leo Disk, turn off PI interrupt during DMA */

		__osResetGlobalIntMask(OS_IM_PI); 

		/* start sequencer */

		__osEPiRawWriteIo(mb->piHandle, ASIC_BM_CTL, 
					(info->bmCtlShadow|START_BM));

readblock1:
	    	/* 
	     	* Listen on the Event Queue 
	     	*/
            	(void)osRecvMesg(dm->evtQueue, &em, OS_MESG_BLOCK);

            	/*
             	 * This signals an I/O completion (i.e., DMA request) from 
		 * device.  Device generates interrupt which is caught by 
		 * the exception  handler and sends us an event.
             	 */

		/*
		 * Handle disk over run case 
		 */

		info = &(mb->piHandle->transferInfo);
		blockInfo = &(info->block[info->blockNum]);
		if (blockInfo->errStatus == SC_OVERRUN_ERROR) {

			u32 stat;

			/* Stop_sequencer */
	
			__osEPiRawWriteIo(mb->piHandle, ASIC_BM_CTL,
						info->bmCtlShadow|BM_RESET);
			__osEPiRawWriteIo(mb->piHandle, ASIC_BM_CTL,
						info->bmCtlShadow);

			/* clear CART interrupt */

			__osEPiRawReadIo(mb->piHandle,  ASIC_STATUS, &stat);
			if (stat & LEO_STAT_MECHA_INT)
				/* clear MECHA interrupt */
				__osEPiRawWriteIo(mb->piHandle, ASIC_BM_CTL,
					info->bmCtlShadow|BM_MECHA_INT_RESET);

			blockInfo->errStatus = LEO_SENSE_DATA_PHASE_ERROR;
			
			/* clear PI interrupt */

			IO_WRITE(PI_STATUS_REG, PI_STATUS_CLR_INTR);
			
			/* Enable CART and PI interrupt */
			__osSetGlobalIntMask(OS_IM_CART | OS_IM_PI);
		}
			
            	/* Send I/O request message back to requestor */
            	osSendMesg(mb->hdr.retQueue, (OSMesg)mb, OS_MESG_NOBLOCK);
		if ((messageSend == 1)
			&& (mb->piHandle->transferInfo.block[0].errStatus == 0)) {

			messageSend = 0;

			goto readblock1;
	        }
                /* Return resource token */
                (void)osSendMesg(dm->acsQueue, (OSMesg)0, OS_MESG_NOBLOCK);
		
		/* 
	   	 * Yield the PI manager at the end of block1 DMA.
		 * So, command thread can issue seek command before
		 * PI manager serve next PI DMA.
		 */
		if (mb->piHandle->transferInfo.blockNum == 1)  
			osYieldThread();
	} else {

		switch (mb->hdr.type) {
		    case OS_MESG_TYPE_DMAREAD: {
			/* Block to get resource token */
			(void)osRecvMesg(dm->acsQueue, &dummy, OS_MESG_BLOCK);
			ret = dm->dma(OS_READ, mb->devAddr, mb->dramAddr, 
			mb->size);
			break;
		    }
		    case OS_MESG_TYPE_DMAWRITE: {
			/* Block to get resource token */
			(void)osRecvMesg(dm->acsQueue, &dummy, OS_MESG_BLOCK);
			ret = dm->dma(OS_WRITE, mb->devAddr, mb->dramAddr, 
			mb->size);
			break;
		    }
		    case OS_MESG_TYPE_EDMAREAD: {
			/* Block to get resource token */
			(void)osRecvMesg(dm->acsQueue, &dummy, OS_MESG_BLOCK);
			ret = dm->edma(mb->piHandle, OS_READ, mb->devAddr, 
			mb->dramAddr, mb->size);
			break;
		    }
		    case OS_MESG_TYPE_EDMAWRITE: {
			/* Block to get resource token */
			(void)osRecvMesg(dm->acsQueue, &dummy, OS_MESG_BLOCK);
			ret = dm->edma(mb->piHandle, OS_WRITE, mb->devAddr, 
			mb->dramAddr, mb->size);
			break;
		    }
		    case OS_MESG_TYPE_LOOPBACK: {
			/* Special message type to loopback to caller */
			(void)osSendMesg(mb->hdr.retQueue, (OSMesg)mb, 
			OS_MESG_NOBLOCK);
			ret = -1;
			break;
		    }
		    default: {  /* NOT REACHED */
			ret = -1;
			break;
		    }
		}

		if (ret == 0) {
		    /* 
		     * Listen on the Event Queue 
		     */
		    (void)osRecvMesg(dm->evtQueue, &em, OS_MESG_BLOCK);

		    /*
		     * This signals an I/O completion (i.e., DMA request) 
		     * from device.  Device generates interrupt which 
		     * is caught by the exception handler and sends us 
		     * an event.
		     */

		    /* Send I/O request message back to requestor */
		    osSendMesg(mb->hdr.retQueue, (OSMesg)mb, 
			OS_MESG_NOBLOCK);

		    /* Return resource token */
		    (void)osSendMesg(dm->acsQueue, (OSMesg)0, OS_MESG_NOBLOCK);

		}  /* if */
	}
    }  /* while */

}  /* __osDevMgrMain */