/* File: HALc96PSC.c Contains: routines that implement the PSC portion of the HAL Notes: Entry points: Written by: Paul Wolf Copyright: © 1992-1993 by Apple Computer, Inc., all rights reserved. Change History (most recent first): 11/10/93 chp Fix some outdated and misleading comments warning of doom should certain parameters change. 10/14/93 pdw roll-in. 9/13/93 pdw Roll-in from SuperMario. 9/13/93 pdw Changed the risky slash pattern. 9/9/93 pdw Lots of little changes. Name changes, temporary cache_bug stuff. 7/17/93 pdw Made it PSC-specific (created HALc96AMIC.c also). 7/8/93 pdw Replaced ifdef with if to test for GPHYSICAL. 6/29/93 pdw Fixed up that little "optimization" that slowed things down immensely. 6/29/93 pdw Massive checkins: Change asynchronicity mechanism to CallMachine stack switching mechanism. Adding support for Cold Fusion. Rearranging HW/SW Init code. Some code optimizations. 5/5/93 PW Converted names to meanies-friendly names. Updated with latest from Ludwig stuff. 4/14/93 DCB Blocking interrupts around LockMemory/GetPhysical setup to prevent a re-select from causing this to happen twice or not at all. 3/26/93 PW Removed the generic DMA transfer routines from this file and put them into HALc96DMA.a. 3/20/93 PW Rolled in Ludwig changes. 1/31/93 PW Update from the latest of Ludwig. Also changes required for PDM (will update Ludwig with these as needed myself). 3/8/93 DCB Increased the size of the locked down buffer. This helps the performance of old-API transactions. 3/1/93 DCB Added conditional compile for GetPhysical call. This aids performance testing. 1/29/93 PW Passing HALg into SetupIOPB function in order to check for HBAhasDMA. 1/27/93 PW Changed scsiDataPhys to Physical. 1/27/93 DCB Added workaround to a bug in the HWPriv.a GetPhysical. Seems that in cases where the logical range was not contiguous the logical address and count in the table were not updated correctly. The workaround reconstructs these fields manually so we don't get stuck in a loop. 1/27/93 PW Changed scsiScatterValid use to scsiDataType. 1/6/93 DCB Set kbUseDblBuffer bit in the SIMprivFlags if an address in the Parameter Block is in the ROM or above. This fixes the SCSI into NuBus bug. Radar Bug # 1059322. This prevents the PSC from doing DMA to addresses it can't handle by DMAing into a known locked down buffer and then blockmoving out to the NuBus address. 12/17/92 DCB Fixed GetPhysical call which caused a user break in VM. 11/20/92 DCB Removed unnecessary include 10/30/92 DCB Added Setup and Teardown routines to support Direct DMA into a user 7/28/92 PW Resolved differences between Paul's and Clinton's sources. 7/25/92 PW Initial check-in. */ #include #include #include #include #include #include "SCSIDebug.h" #include "ACAM.h" #include "SIMCore.h" #include "HALc96.h" #include "SIMCorePriv.h" #define MAX(a,b) ((a)>=(b)?(a):(b)) /****** Function Prototypes For Inside only *******/ /****** Transfer Constants (Check HALc96DMA.a as well!) *******/ #define MIN_PSC_DMA_SIZE 0x200 // /********************************************************************************* InitHW_PSC - Initialize DMA Hardware *********************************************************************************/ // external OSErr InitHW_PSC( HALc96Globals *HALg) { #pragma unused (HALg) return (noErr); } /********************************************************************************* InitSW_PSC - Initialize Software stuff required for DMA support *********************************************************************************/ // external OSErr InitSW_PSC( HALc96Globals *HALg) { OSErr err; ulong numBlocks, pageSize, bufferSize; void *memStart, *pageStart; MemoryBlock lockedBlock; LogicalToPhysicalTable l2pTable; //*** WARNING: The following code is Page Size Dependent !!! *** //*** WARNING: Don't change these unless you change HALc96DMA.a as well pageSize = 8192; bufferSize = 1*pageSize; memStart = NewPtrSys( bufferSize+pageSize); if (memStart==0) return (memFullErr); pageStart = (void *)((((long)memStart-1) & ~(pageSize-1)) + pageSize); SetPtrSize( memStart, (long)pageStart + MAX(bufferSize,pageSize) - (long)memStart); err = LockMemory(pageStart, bufferSize); if (err!=noErr) return (err); lockedBlock.address = pageStart; lockedBlock.count = bufferSize; l2pTable.logical = lockedBlock; numBlocks = 1; GetPhysical( &l2pTable, &numBlocks); HALg->physicalCopyBuffer = l2pTable.physical[0].address; HALg->logicalCopyBuffer = pageStart; HALg->minDMAsize = MIN_PSC_DMA_SIZE; return (noErr); } /********************************************************************************* SetupIOPB - LockMemory on user buffers as necessary *********************************************************************************/ void SetupIOPSC( SIM_IO *ioPtr) { int i; SGRecord *sgList; Ptr firstAddr = nil; ulong firstLen = 0; ulong cnt = 1; ushort oldSR; // Have we already done it ? If so, return // (this could happen if we started it then got a reselect and then retried this one again) if( ioPtr->SIMprivFlags & (1 << kbSetupComplete) ) return; // Note that we don't do TIB's, Windows or CPM-86 if ( (ioPtr->scsiFlags & scsiDataPhysical) || ioPtr->scsiFunctionCode == SCSIOldCall ) return; oldSR = BlockInterrupts(); //-> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> if ( ioPtr->scsiDataType == scsiDataSG ) { /* Scatter/Gather List */ sgList = (SGRecord *) ioPtr->scsiDataPtr; for( i = 0; i < ioPtr->scsiSGListCount; i+=1 ) { /* No sense fooling with small transfers due to lock memory overhead The data xfer routine will know that the buffer is not locked down and will use the old routine instead of direct DMA. (DMA to known locked buffer and then BlockMove) */ if( sgList[i].SGCount <= MIN_PSC_DMA_SIZE ) continue; /* Don't bother */ if( sgList[i].SGAddr >= 0x40000000 ) { // Up in ROM or NuBus Land ioPtr->SIMprivFlags |= (1 << kbUseDblBuffer); // break; } if( LockMemory((Ptr)sgList[i].SGAddr,sgList[i].SGCount) != noErr ) { ioPtr->SIMprivFlags |= (1 << kbUseDblBuffer); // break; } else { ioPtr->SIMprivFlags |= (1 << kbSetupComplete); if( !firstAddr ) { firstAddr = (Ptr)sgList[i].SGAddr; firstLen = sgList[i].SGCount; } } } } else { /* else Address/Count */ /* Don't bother with small buffers */ if( ioPtr->scsiDataLength <= MIN_PSC_DMA_SIZE ) goto exit; if( ioPtr->scsiDataPtr >= 0x40000000 ) { // Up in ROM or NuBus Land ioPtr->SIMprivFlags |= (1 << kbUseDblBuffer); // } else { if( LockMemory(ioPtr->scsiDataPtr,ioPtr->scsiDataLength) != noErr ) ioPtr->SIMprivFlags |= (1 << kbUseDblBuffer); else { ioPtr->SIMprivFlags |= (1 << kbSetupComplete); firstAddr = (Ptr)ioPtr->scsiDataPtr; firstLen = ioPtr->scsiDataLength; } } } if( (ioPtr->SIMprivFlags & (1 << kbUseDblBuffer)) == 0 && firstAddr && firstLen ) { // ioPtr->logical.address = firstAddr; ioPtr->logical.count = firstLen; if( GetPhysical((LogicalToPhysicalTable *)&ioPtr->logical,&cnt) ) ioPtr->SIMprivFlags |= (1 << kbUseDblBuffer); // else { // Check to see if the bug in GetPhysical caught us. // If it did we need to setup logical.address and logical.count // the way they are supposed to be. if( ioPtr->logical.address == firstAddr ) { (char *)ioPtr->logical.address += ioPtr->physical.count; ioPtr->logical.count -= ioPtr->physical.count; } ioPtr->transLogEnd = firstAddr + ioPtr->physical.count; } } exit: UnblockInterrupts( oldSR); //<- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- } /********************************************************************************* TeardownIOPSC - UnlockMemory user buffers as necessary *********************************************************************************/ void TeardownIOPSC( SIM_IO * ioPtr, HALc96Globals * HALg) { #pragma unused(HALg) int i; SGRecord *sgList; /* Note that we don't do TIB's, Windows or CPM-86 */ if( (ioPtr->scsiFlags & scsiDataPhysical) || ioPtr->scsiFunctionCode == SCSIOldCall ) return; /* Nothing more to do */ if ( ioPtr->scsiDataType == scsiDataSG ) { /* Scatter/Gather List */ sgList = (SGRecord *) ioPtr->scsiDataPtr; for( i = 0; i < ioPtr->scsiSGListCount; i+=1 ) { /* Don't bother with small buffers */ if( sgList[i].SGCount <= MIN_PSC_DMA_SIZE ) continue; if( sgList[i].SGAddr >= 0x40000000 ) // Up in ROM or NuBus Land break; // UnlockMemory((Ptr)sgList[i].SGAddr,sgList[i].SGCount); // Can't do anything about errors } } else { /* Address/Count */ /* Don't bother with small buffers */ if( ioPtr->scsiDataLength <= MIN_PSC_DMA_SIZE ) return; if( ioPtr->scsiDataPtr < 0x40000000 ) // Up in ROM or NuBus Land UnlockMemory(ioPtr->scsiDataPtr,ioPtr->scsiDataLength); // Can't do anything about errors } }