mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-11-26 16:49:18 +00:00
1206 lines
37 KiB
C
1206 lines
37 KiB
C
/*
|
||
File: SIMCore.c
|
||
|
||
Contains: routines that implement the core of the Apple SIM layer
|
||
|
||
Entry points:
|
||
XPT Calls to SIM
|
||
|
||
void InitSIM( Ptr SIMstaticPtr, long busID)
|
||
|
||
Called by the XPT to initialize the SIM’s state. The SIM, in turn has the
|
||
responsibility of optionally initializing the HBA.
|
||
|
||
void SIMAction(SIM_IO *thePB, Ptr SIMstaticPtr)
|
||
|
||
Called by the XPT whenever a SCSIAction call is received that needs to be
|
||
serviced by the SIM. The SIMstaticPtr parameter is a pointer to the previously
|
||
allocated SIM static data area.
|
||
|
||
HAL Calls to SIM
|
||
|
||
ushort SIMRegisterHAL (long HALentry, ulong staticSize, Ptr * HALstaticPtr)
|
||
|
||
Called by a Hardware Abstraction Layer (HAL) to register itself (i.e. its bus)
|
||
with the Apple standard SIM. The SIM will in turn, register this new HBA with
|
||
the XPT and will return the BusID to the HAL.
|
||
|
||
void SIMDeregisterHAL (ushort busID)
|
||
|
||
Called by a Hardware Abstraction Layer to deregister itself from the Apple
|
||
standard SIM. The SIM will in turn, deregister this HBA with the XPT.
|
||
|
||
|
||
|
||
Written by: Paul Wolf
|
||
|
||
Copyright: © 1992-1994 by Apple Computer, Inc., all rights reserved.
|
||
|
||
Change History (most recent first):
|
||
|
||
<SM29> 1/31/94 DCB Added a call to SIMDualIntPoll for the Old API case. Also
|
||
changed SIMDualIntPoll so that it will always wait for 2
|
||
consecutive polls (1 on each bus) without an interrupt before
|
||
exiting.
|
||
<SM28> 1/29/94 DCB Added SIMDualIntPoll which is called when we exit the SIMAction
|
||
call. This ensures that we don't forget about an interrupt that
|
||
might have been cleared at the VIA for the other bus.
|
||
<SM27> 12/21/93 DCB If CompAutoSense() detects that senseWaiting is non-zero and
|
||
that no PBs are awaiting autosense it needs to clear sensePBBusy
|
||
as well as senseWaiting. Otherwise we hang the next time
|
||
autosense is used.
|
||
<SM26> 11/21/93 pdw Added support for dynamic supported-flags for scFlags, scIOFlags
|
||
and scDataTypes.
|
||
<SM25> 10/14/93 pdw <MC> roll-in.
|
||
<MC4> 10/12/93 pdw Added support for Synchronous data transfers, rewrote State
|
||
Machine, message handling etc.
|
||
<MC3> 9/26/93 pdw <SM24>
|
||
<SM24> 9/16/93 DCB Fixing ResetDevice so it doesn't validate a bogus parameter
|
||
block and then return from the procedure with interrupts
|
||
blocked.
|
||
<SM23> 9/13/93 pdw Changed the risky slash pattern.
|
||
<SM22> 9/12/93 pdw Added Reregister support. Split out common registration stuff
|
||
into separate routine.
|
||
<SM21> 7/17/93 pdw Lots of little things.
|
||
<SM20> 7/8/93 pdw Added calls to RecordError.
|
||
<SM19> 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.
|
||
<SM18> 5/25/93 DCB Rollin from Ludwig. (The next item below)
|
||
<LW13> 5/21/93 PW Adding SIMg parameter to ValidateDeviceIdent so that it can
|
||
check HostID.
|
||
<SM17> 5/5/93 PW Converted names to meanies-friendly names. Updated with latest
|
||
from Ludwig stuff.
|
||
<LW12> 5/1/93 PW Changed one last name: SCSI_RegisterWithNewXPT.
|
||
<LW11> 4/30/93 DCB Added call to CallBusInquiry function so that we don't have to
|
||
busy the HALAction routine.
|
||
<LW9> 4/14/93 DCB Added RegisterWithNewXPT action for the purpose of switching
|
||
XPTs on the fly.
|
||
<LW8> 3/26/93 PW Moved VMDisableUserCode and Enable into SIMaction (from XPT).
|
||
<SM15> 3/20/93 PW Made ReleaseQ return noErr (bug introduced by removing
|
||
finalStatus from CallCompRoutine).
|
||
<LW6> 3/3/93 PW Changed default disconnect action to false (don't disconnect).
|
||
<LW5> 3/1/93 DCB Fixed ResetDevice to match ResetBus. Also changed the parameters
|
||
to callcomproutine.
|
||
<LW4> 2/18/93 DCB Changed Reset's behavior to match the documentation. Only those
|
||
IOs actually started are dequeued after a reset.
|
||
<LW3> 1/27/93 PW Added support for register->SIMinit->HALinit way of
|
||
initialization. Added SIMInterruptPoll routine.
|
||
<LW2> 12/17/92 DCB Fixed a bug in the reset device,abort command and terminateIO
|
||
features which caused a sync-wait hang.
|
||
<SM13> 12/9/92 DCB Fixed SyncWait problem for synchronous Reset Bus commands by
|
||
returning a noErr after doing the reset.
|
||
<SM12> 12/5/92 PW Changed ValidateDI to return the appropriate error.
|
||
<SM11> 11/20/92 DCB Added support for asynchronous abort, terminate, reset device
|
||
and other functions
|
||
<SM10> 11/1/92 DCB Removed bogus validate check before doing BusInquiry.
|
||
<SM9> 10/30/92 DCB Changed to reflect new ACAM.h
|
||
<SM8> 10/8/92 PW Added stuff needed for variable-sized SCSI_IO support and for
|
||
new ioEvent field.
|
||
<SM7> 9/17/92 PW Added check for function code not supported.
|
||
<SM6> 9/14/92 DCB Added some parameter block validation
|
||
<SM5> 9/11/92 DCB Fixing Terminate and Abort IO and adding Reset Device
|
||
<SM4> 8/31/92 DCB Implementing Terminate/Abort IO
|
||
<SM3> 8/20/92 DCB Fixed SCSI Reset
|
||
<SM2> 8/1/92 PW Added comments, function headers and prototypes.
|
||
|
||
*/
|
||
|
||
#include <Types.h>
|
||
#include <Memory.h>
|
||
#include <Errors.h>
|
||
#include <SCSIStandard.h>
|
||
#include <SCSI.h>
|
||
|
||
#include "ACAM.h"
|
||
#include "XPT.h"
|
||
#include "CUtils.h"
|
||
|
||
#include "SIMCore.h"
|
||
#include "SIMCorePriv.h"
|
||
#include "SIMQ.h"
|
||
#include "SCSIGlue.h"
|
||
#include "HALc96.h"
|
||
|
||
#include "SCSIDebug.h"
|
||
#include "Recorder.h"
|
||
|
||
|
||
//———— Prototypes for functions used only within this file ————
|
||
|
||
void ResetDevice( SCSIResetDevicePB *resetPtr, SIMglobals * SIMg);
|
||
void TerminateIO( SCSITerminateIOPB *termPtr, SIMglobals * SIMg);
|
||
void AbortCommand( SCSIAbortCommandPB *abortPtr, SIMglobals * SIMg);
|
||
void SIMaction( SIM_IO *ioPtr, SIMglobals * SIMg);
|
||
Boolean StartMachine( SIMglobals * SIMg);
|
||
void SetupSensePB( SIM_IO * ioPtr, SIMglobals * SIMg );
|
||
Boolean CheckErrors( OSErr finalStatus, SIM_IO * ioPtr, SIMglobals * SIMg );
|
||
pascal void CompAutoSense( SIM_IO *ioPtr );
|
||
pascal void CompResetDevice( SIM_IO *ioPtr );
|
||
void FreeMachine( OSErr finalStatus, SIM_IO * ioPtr, SIMglobals * SIMg);
|
||
SIMinitInfo * SIMRegisterCommon( HALinitInfo *HALinfoPtr);
|
||
|
||
|
||
/*********************************************************************************
|
||
SIMRegisterHAL - register a HAL for the SIMCore
|
||
*********************************************************************************/
|
||
|
||
OSErr
|
||
SIMRegisterHAL( HALinitInfo *HALinfoPtr)
|
||
{
|
||
SIMinitInfo * SIMinfoPtr;
|
||
|
||
// Fill in our entry points
|
||
|
||
SIMinfoPtr = SIMRegisterCommon( HALinfoPtr);
|
||
|
||
// Make call ———————————————— (which in turn calls SIMinit)
|
||
|
||
return ( SCSIRegisterBus( SIMinfoPtr) );
|
||
}
|
||
|
||
|
||
/*********************************************************************************
|
||
SIMRegisterHAL - register a HAL for the SIMCore
|
||
*********************************************************************************/
|
||
|
||
OSErr
|
||
SIMReregisterHAL( HALinitInfo *HALinfoPtr)
|
||
{
|
||
OSErr err;
|
||
SIMinitInfo * SIMinfoPtr;
|
||
|
||
// Fill in our entry points
|
||
|
||
SIMinfoPtr = SIMRegisterCommon( HALinfoPtr);
|
||
|
||
// Make call ———————————————— (which doesn't call SIMinit)
|
||
|
||
SIMinfoPtr->busID = HALinfoPtr->busID;
|
||
err = SCSIReRegisterBus( SIMinfoPtr);
|
||
|
||
if (err) return(err);
|
||
|
||
return ( SIMinit( SIMinfoPtr));
|
||
}
|
||
|
||
|
||
/*********************************************************************************
|
||
SIMRegisterCommon -
|
||
*********************************************************************************/
|
||
|
||
SIMinitInfo *
|
||
SIMRegisterCommon( HALinitInfo *HALinfoPtr)
|
||
{
|
||
SIMinitInfo * SIMinfoPtr;
|
||
|
||
// Set up SIMinfoPtr for call to SCSIRegisterBus
|
||
|
||
if( 0==(SIMinfoPtr = (SIMinitInfo *) NewPtrSysClear(sizeof(SIMinitInfo)))) // We need to keep this around for re-registration
|
||
return (SIMinfoPtr);
|
||
|
||
// -> num bytes SIM needs for static vars
|
||
SIMinfoPtr->staticSize = sizeofSIMGlobals + HALinfoPtr->staticSize;
|
||
SIMinfoPtr->SIMinit = SIMinit; // -> SIM init routine
|
||
SIMinfoPtr->SIMaction = SIMaction; // -> SIM action routine
|
||
SIMinfoPtr->NewOldCall = NewOldCall; // -> SIM NewOldCall routine
|
||
SIMinfoPtr->SIM_ISR = SIM_ISR; // -> SIM int-> service routine
|
||
SIMinfoPtr->SIMInterruptPoll = SIMDualIntPoll; // -> SIM int-> poll routine
|
||
SIMinfoPtr->ioPBSize = sizeof(SIM_IO); // -> size of IO PB needed
|
||
SIMinfoPtr->oldCallCapable = HALinfoPtr->oldCallCapable; // -> capable of old calls
|
||
|
||
SIMinfoPtr->simInternalUse = (long)HALinfoPtr; // -> so SIMinit knows
|
||
|
||
return (SIMinfoPtr);
|
||
}
|
||
|
||
|
||
/*********************************************************************************
|
||
SIMinit -
|
||
*********************************************************************************/
|
||
|
||
OSErr
|
||
SIMinit (SIMinitInfo * SIMinfoPtr)
|
||
{
|
||
SIMglobals * SIMg;
|
||
HALinitInfo * HALinfoPtr;
|
||
OSErr err;
|
||
|
||
//--- Get results out of SIMinfo and put in SIMglobals and in HALInfo
|
||
|
||
// <- get G ptr from ptr allocated by XPT and copy entire SIMinfo over there
|
||
SIMg = (SIMglobals *)SIMinfoPtr->SIMstaticPtr;
|
||
|
||
HALinfoPtr = (HALinitInfo *)SIMinfoPtr->simInternalUse;
|
||
|
||
// give HAL its staticPtr which should point just past SIM's globals
|
||
HALinfoPtr->HALstaticPtr = (uchar *)SIMg + sizeofSIMGlobals;
|
||
|
||
// give HAL the SIMCore's global ptr also, for callbacks to SSM
|
||
HALinfoPtr->SIMstaticPtr = (uchar *)SIMg;
|
||
|
||
// and the addresses for callbacks to SSM
|
||
HALinfoPtr->ReconnectISR = ReconnectISR;
|
||
|
||
// The XPT gives the SIM its ISR so that it can install it - give it to the HAL instead
|
||
HALinfoPtr->XPT_ISR = SIMinfoPtr->XPT_ISR;
|
||
|
||
// <- busID returned - store it
|
||
HALinfoPtr->busID = SIMinfoPtr->busID;
|
||
|
||
// Store all of the HALinfo for later reference
|
||
SIMg->HALinfo = *HALinfoPtr;
|
||
|
||
SIMg->MakeCallback = SIMinfoPtr->MakeCallback;
|
||
|
||
|
||
//--- Set up various state things (that shouldn't be init'd at zero)
|
||
|
||
SIMg->state = kIdle;
|
||
SIMg->defaultDisc = false;
|
||
|
||
SIMg->initInfo = SIMinfoPtr; // Save this for re-registration
|
||
|
||
StartTimer( SIMg );
|
||
|
||
//--- Make call to HALinit then get what we need from HAL
|
||
|
||
if( err=(HALinfoPtr->HALinit)(HALinfoPtr) )
|
||
return (err);
|
||
|
||
SIMg->hostID = GetInitiatorID( (HBADesc_53c9x *)(HALinfoPtr->HALstaticPtr));
|
||
|
||
//--- Initialize fields in HALActionPB that will never change
|
||
|
||
SIMg->halPB.HALstaticPtr = SIMg->HALinfo.HALstaticPtr;
|
||
|
||
return ( noErr);
|
||
}
|
||
|
||
|
||
/*********************************************************************************
|
||
SIMaction - The main SIMCore entry point
|
||
*********************************************************************************/
|
||
|
||
void
|
||
SIMaction( SIM_IO *ioPtr, SIMglobals * SIMg)
|
||
{
|
||
VMDisableUserCode(); // disable user code (so page faults won't happen)
|
||
|
||
// What do we need to do?
|
||
|
||
// I moved this here because ALL of these routines are now considered to be
|
||
// asynchronous - not just those that are enqueued into the IOQ. <SM11> DCB
|
||
ioPtr->scsiResult = scsiRequestInProgress;
|
||
|
||
if (ioPtr->scsiFunctionCode == SCSIExecIO || ioPtr->scsiFunctionCode == SCSIOldCall)
|
||
{
|
||
if( ValidatePB(ioPtr, SIMg)) {
|
||
EnQIO( ioPtr, SIMg);
|
||
NewIOStartMachine( SIMg);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
switch (ioPtr->scsiFunctionCode)
|
||
{
|
||
case SCSIReleaseQ:
|
||
|
||
if( ioPtr->scsiResult = ValidateDeviceIdent( ioPtr->scsiDevice, SIMg)) {
|
||
CallCompRoutine( (SCSI_IO *)ioPtr);
|
||
}
|
||
else {
|
||
DefrostLUN( ioPtr->scsiDevice.targetID, ioPtr->scsiDevice.LUN );
|
||
NewIOStartMachine( SIMg);
|
||
ioPtr->scsiResult = noErr;
|
||
CallCompRoutine( (SCSI_IO *) ioPtr);
|
||
}
|
||
break;
|
||
case SCSIBusInquiry: // SIM
|
||
((SCSIBusInquiryPB *)ioPtr)->scsiSIMPrivatesPtr = SIMg;
|
||
((SCSIBusInquiryPB *)ioPtr)->scsiSIMPrivatesSize = sizeofSIMGlobals;
|
||
((SCSIBusInquiryPB *)ioPtr)->scsiIOpbSize = sizeof(SIM_IO);
|
||
CallBusInquiry( ioPtr, SIMg);
|
||
ioPtr->scsiResult = noErr;
|
||
CallCompRoutine( (SCSI_IO *) ioPtr);
|
||
break;
|
||
|
||
case SCSIResetBus: // SIM
|
||
ResetSIM( SIMg );
|
||
ioPtr->scsiResult = noErr;
|
||
IfRecordEvent( (long)ioPtr, (long)'RsOC');
|
||
CallCompRoutine( (SCSI_IO *)ioPtr); // <SM13>
|
||
break;
|
||
case SCSIResetDevice: // SIM
|
||
ResetDevice( (SCSIResetDevicePB *) ioPtr, SIMg);
|
||
break;
|
||
case SCSIAbortCommand: // SIM
|
||
AbortCommand( (SCSIAbortCommandPB *) ioPtr, SIMg);
|
||
break;
|
||
case SCSITerminateIO: // SIM
|
||
TerminateIO( (SCSITerminateIOPB *) ioPtr, SIMg);
|
||
break;
|
||
case SCSIRegisterWithNewXPT:
|
||
ioPtr->scsiResult = SCSIReRegisterBus( SIMg->initInfo );
|
||
break;
|
||
default:
|
||
ioPtr->scsiResult = scsiFunctionNotAvailable;
|
||
IfRecordError( (long)'FC?C');
|
||
IfRecordEvent( (long)ioPtr, (long)ioPtr->scsiFunctionCode);
|
||
CallCompRoutine( (SCSI_IO *)ioPtr);
|
||
break;
|
||
}
|
||
}
|
||
|
||
// If this was a Quadra 900 then we want to check to see if any interrupts
|
||
// for the other bus have occured and been cleared...
|
||
if( SIMg->otherSIMg )
|
||
SIMDualIntPoll(SIMg);
|
||
|
||
VMEnableUserCode(); // enable user code (allow page faults)
|
||
}
|
||
|
||
|
||
/*********************************************************************************
|
||
NewOldCall -
|
||
*********************************************************************************/
|
||
|
||
void
|
||
NewOldCall( SIM_IO * ioPtr, SIMglobals * SIMg)
|
||
{
|
||
VMDisableUserCode(); // disable user code (so page faults won't happen)
|
||
|
||
ioPtr->scsiResult = scsiRequestInProgress;
|
||
ioPtr->scsiOldCallResult = scsiRequestInProgress;
|
||
CallMachine( SIMg);
|
||
|
||
// If this was a Quadra 900 then we want to check to see if any interrupts
|
||
// for the other bus have occured and been cleared...
|
||
if( SIMg->otherSIMg )
|
||
SIMDualIntPoll(SIMg);
|
||
|
||
VMEnableUserCode(); // enable user code (allow page faults)
|
||
}
|
||
|
||
|
||
/*********************************************************************************
|
||
SIM_ISR -
|
||
*********************************************************************************/
|
||
#if 0
|
||
long
|
||
SIM_ISR (SIMglobals * SIMg)
|
||
{
|
||
return (((SIMg->HALinfo).HAL_ISR)((SIMg->HALinfo).HALstaticPtr));
|
||
}
|
||
#endif
|
||
|
||
|
||
/*********************************************************************************
|
||
SIMIntPoll -
|
||
*********************************************************************************/
|
||
|
||
long
|
||
SIMIntPoll (SIMglobals * SIMg)
|
||
{
|
||
return (((SIMg->HALinfo).HALIntPoll)((SIMg->HALinfo).HALstaticPtr));
|
||
}
|
||
|
||
/*********************************************************************************
|
||
SIMDualIntPoll -
|
||
*********************************************************************************/
|
||
|
||
long
|
||
SIMDualIntPoll (SIMglobals * SIMg)
|
||
{
|
||
SIMglobals * AltSIMg;
|
||
ulong GotInt;
|
||
|
||
if( SIMg->otherSIMg == nil )
|
||
return(SIMIntPoll(SIMg));
|
||
|
||
AltSIMg = SIMg;
|
||
|
||
do {
|
||
// IfRecordEvent((long)AltSIMg, (long)'SItp');
|
||
GotInt = SIMIntPoll(AltSIMg);
|
||
AltSIMg = (SIMglobals *) AltSIMg->otherSIMg;
|
||
|
||
if( GotInt )
|
||
continue;
|
||
|
||
// IfRecordEvent((long)AltSIMg, (long)'SItp');
|
||
GotInt = SIMIntPoll(AltSIMg);
|
||
AltSIMg = (SIMglobals *) AltSIMg->otherSIMg;
|
||
|
||
} while( GotInt ); // Repeat until 2 in a row didn't handle an interrupt
|
||
|
||
|
||
return(0); // !!! nobody is paying attention to this currently
|
||
}
|
||
|
||
|
||
/*********************************************************************************
|
||
CallBusInquiry - call HAL to get info on the bus
|
||
*********************************************************************************/
|
||
|
||
Boolean // completed Synchronously
|
||
CallBusInquiry( SIM_IO * ioPtr, SIMglobals * SIMg)
|
||
{
|
||
// Call HAL and return result
|
||
return ((SIMg->HALinfo.HALBusInquiry)( SIMg->HALinfo.HALstaticPtr, (SCSIBusInquiryPB *)ioPtr ));
|
||
}
|
||
|
||
|
||
/*********************************************************************************
|
||
ResetSIM - It's the end of the world as we know it...
|
||
And I feel fine.
|
||
*********************************************************************************/
|
||
|
||
void
|
||
ResetSIM( SIMglobals * SIMg)
|
||
{
|
||
int LUN,id;
|
||
SIM_IO * qPtr;
|
||
|
||
SIMg->SIMBusy = true; // Don't start IOs until we are done.
|
||
|
||
/* Reset Bus, Most of the chip, and go bus free */
|
||
CallHALResetBus( SIMg->HALinfo.HALstaticPtr ); /* Say goodbye to Hollywood */
|
||
|
||
for( id = 0; id < 7; id+=1 ) {
|
||
for( LUN = 0; LUN < 8; LUN+=1 ) {
|
||
SIMg->discIOs[id][LUN] = 0; /* Reset should have gotten rid of connected ios */
|
||
SIMg->LUNstate[id][LUN] = 0;
|
||
}
|
||
}
|
||
|
||
SIMg->state = kIdle;
|
||
SIMg->SSMflags = 0;
|
||
SIMg->senseWaiting = 0;
|
||
|
||
/* Don't send any reset device messages <SM11> */
|
||
while( qPtr = (SIM_IO *)SIMg->resetPBQ.qHead ) { // <SM11>
|
||
qPtr->scsiResult = scsiSCSIBusReset;
|
||
IfRecordEvent( (long)qPtr, (long)'RstC');
|
||
CallCompRoutine( (SCSI_IO *) qPtr);
|
||
Dequeue( (QElemPtr) qPtr,&SIMg->resetPBQ);
|
||
}
|
||
|
||
ResetQueues( SIMg, 0xFF ); /* Move the IO Q into the Reset Q */
|
||
while( qPtr = (SIM_IO *)SIMg->resetHdr.qHead ) { /* CompleteIO will dequeue each entry <LW4> <TOP> */
|
||
if( (qPtr->scsiFlags & scsiSIMQNoFreeze) || qPtr->scsiFunctionCode == SCSIOldCall ) {
|
||
DefrostLUN( qPtr->scsiDevice.targetID, qPtr->scsiDevice.LUN);
|
||
}
|
||
else {
|
||
FreezeLUN( qPtr->scsiDevice.targetID, qPtr->scsiDevice.LUN);
|
||
qPtr->scsiResultFlags |= scsiSIMQFrozen;
|
||
}
|
||
CompleteIO( scsiSCSIBusReset, (SIM_IO *) qPtr, SIMg);
|
||
} /* <LW4> <BOTTOM> */
|
||
|
||
SIMg->SIMBusy = false; // Allow IOs again
|
||
|
||
NewIOStartMachine(SIMg); // Make sure Machine gets run
|
||
}
|
||
|
||
|
||
/*********************************************************************************
|
||
ResetDevice - Reset a particular SCSI device with a ResetDevice Message <SM5>
|
||
*********************************************************************************/
|
||
|
||
void
|
||
ResetDevice( SCSIResetDevicePB *resetPtr, SIMglobals * SIMg)
|
||
{
|
||
SIM_IO *ioPtr, *qPtr;
|
||
ushort oldSR;
|
||
Boolean usedExisting = false;
|
||
uchar targetID;
|
||
|
||
if( resetPtr->scsiResult = ValidateDeviceIdent( resetPtr->scsiDevice, SIMg)) {
|
||
IfRecordEvent( (long)resetPtr, (long)'RsDC');
|
||
CallCompRoutine( (SCSI_IO *)resetPtr);
|
||
return;
|
||
}
|
||
|
||
oldSR = BlockInterrupts(); //-> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> ->
|
||
|
||
|
||
targetID = (resetPtr->scsiDevice).targetID;
|
||
|
||
IfRecordEvent( (long)targetID, (long)'RstD');
|
||
|
||
ioPtr = FindIOFromID( targetID, SIMg);
|
||
|
||
|
||
//……… If we are already connected to the device - then we can use the existing
|
||
// connection. If not we will have to use the one in the globals.
|
||
|
||
if( ioPtr && ioPtr->ioStat != kPBidle ) {
|
||
ioPtr->pendingMsgPB = (Ptr)resetPtr; // <SM11> DCB
|
||
SwitchQ(ioPtr, &SIMg->immedQHdr);
|
||
usedExisting = true;
|
||
}
|
||
|
||
|
||
//……… Get rid of ALL other PBs for this guy that haven't been started
|
||
|
||
ResetQueues( SIMg, targetID );
|
||
|
||
|
||
//……… For each IO in resetQ, freeze the LUN's Q if it's a new-API request w/o the NoFreeze bit set
|
||
|
||
while( qPtr = (SIM_IO *)SIMg->resetHdr.qHead ) { // CompleteIO will dequeue each entry
|
||
if( (qPtr->scsiFlags & scsiSIMQNoFreeze) || qPtr->scsiFunctionCode == SCSIOldCall ) {
|
||
DefrostLUN( qPtr->scsiDevice.targetID, qPtr->scsiDevice.LUN);
|
||
}
|
||
else
|
||
{
|
||
// Do actual freezing of LUN then indicate that it is so in the SCSI_IO PB
|
||
FreezeLUN( qPtr->scsiDevice.targetID, qPtr->scsiDevice.LUN);
|
||
qPtr->scsiResultFlags |= scsiSIMQFrozen;
|
||
}
|
||
CompleteIO( scsiBDRsent, (SIM_IO *) qPtr, SIMg);
|
||
} //<LW5> <BOTTOM>
|
||
|
||
//……… ResetDevice should have gotten rid of in-progress IOs - clear them from table
|
||
|
||
if( !usedExisting ) {
|
||
if( SIMg->resetPBQ.qHead == 0 ) { /* The global Reset PB is free */
|
||
SetupResetPB( targetID , SIMg);
|
||
EnQIO(&SIMg->resetDevPB,SIMg);
|
||
SIMg->resetDevPB.pendingMsgPB = (Ptr) resetPtr; /* Remember who started this <LW2> */
|
||
}
|
||
Enqueue((QElemPtr)resetPtr, &SIMg->resetPBQ);
|
||
}
|
||
|
||
UnblockInterrupts(oldSR); //<- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <-
|
||
|
||
NewIOStartMachine(SIMg); /* Make sure Machine gets run */
|
||
|
||
}
|
||
|
||
|
||
/*********************************************************************************
|
||
TerminateIO -
|
||
*********************************************************************************/
|
||
|
||
void
|
||
TerminateIO( SCSITerminateIOPB *termPtr, SIMglobals * SIMg) // <SM4>
|
||
{
|
||
SIM_IO * ioPtr;
|
||
ushort oldSR;
|
||
Boolean restartMachine = false;
|
||
|
||
oldSR = BlockInterrupts(); //-> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> ->
|
||
|
||
ioPtr = (SIM_IO *)(termPtr->scsiIOptr);
|
||
|
||
IfRecordEvent( (long)ioPtr, (long)'TmIO');
|
||
|
||
if( FindIO( ioPtr, SIMg) == 0 ) {
|
||
termPtr->scsiResult = scsiUnableToTerminate;
|
||
IfRecordEvent( (long)termPtr, (long)'Tm1C');
|
||
CallCompRoutine( (SCSI_IO *)termPtr); /* Dang - PB not in queue <LW5> */
|
||
goto exit;
|
||
}
|
||
if( ioPtr->ioStat == kPBidle ) { /* If it hasn't been started - just de-queue it */
|
||
CompleteIO( scsiTerminated, (SIM_IO *) ioPtr, SIMg );
|
||
goto exit;
|
||
}
|
||
|
||
/* If it has been started let Machine() deal with it */
|
||
if( ioPtr->pendingMsgPB ) {
|
||
termPtr->scsiResult = scsiUnableToTerminate;
|
||
IfRecordEvent( (long)termPtr, (long)'Tm2C');
|
||
CallCompRoutine( (SCSI_IO *)termPtr);
|
||
}
|
||
ioPtr->pendingMsgPB = (Ptr)termPtr; // <SM11> DCB
|
||
|
||
restartMachine = true;
|
||
SwitchQ(ioPtr, &SIMg->immedQHdr);
|
||
|
||
|
||
exit:
|
||
UnblockInterrupts( oldSR); //<- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <-
|
||
|
||
if( restartMachine )
|
||
NewIOStartMachine( SIMg); /* Make sure Machine gets run */
|
||
}
|
||
|
||
|
||
/*********************************************************************************
|
||
AbortCommand -
|
||
*********************************************************************************/
|
||
|
||
void
|
||
AbortCommand( SCSIAbortCommandPB *abortPtr, SIMglobals * SIMg) // <SM4>
|
||
{
|
||
SIM_IO * ioPtr;
|
||
ushort oldSR;
|
||
Boolean restartMachine = false;
|
||
|
||
oldSR = BlockInterrupts(); //-> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> ->
|
||
|
||
ioPtr = (SIM_IO *)(abortPtr->scsiIOptr);
|
||
|
||
IfRecordEvent( (long)ioPtr, (long)'Abt ');
|
||
|
||
if( FindIO( ioPtr, SIMg) == 0 ) {
|
||
abortPtr->scsiResult = scsiUnableToAbort;
|
||
IfRecordEvent( (long)abortPtr, (long)'Ab1C');
|
||
CallCompRoutine( (SCSI_IO *)abortPtr); /* Dang - PB not in queue <LW2> */
|
||
goto exit;
|
||
}
|
||
if( ioPtr->ioStat == kPBidle ) { /* If it hasn't been started - just de-queue it */
|
||
CompleteIO( scsiTerminated, (SIM_IO *) ioPtr, SIMg);
|
||
goto exit;
|
||
}
|
||
|
||
/* If it has been started let Machine() deal with it */
|
||
if( ioPtr->pendingMsgPB ) {
|
||
abortPtr->scsiResult = scsiUnableToAbort;
|
||
IfRecordEvent( (long)abortPtr, (long)'Ab2C');
|
||
CallCompRoutine( (SCSI_IO *)abortPtr);
|
||
}
|
||
ioPtr->pendingMsgPB = (Ptr)abortPtr; // <SM11> DCB
|
||
|
||
restartMachine = true;
|
||
SwitchQ(ioPtr,(QHdrPtr) &SIMg->immedQHdr);
|
||
|
||
exit:
|
||
UnblockInterrupts( oldSR); // <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <-
|
||
|
||
if( restartMachine )
|
||
NewIOStartMachine( SIMg); /* Make sure Machine gets run */
|
||
}
|
||
|
||
|
||
/*********************************************************************************
|
||
ValidatePB - Makes sure the PB is "right with GOD" (Us)
|
||
Errors with precedence should appear at the bottom in case
|
||
there is more than one thing wrong with the PB
|
||
*********************************************************************************/
|
||
|
||
Boolean
|
||
ValidatePB( SIM_IO * ioPtr, SIMglobals * SIMg )
|
||
{
|
||
OSErr finalStatus = noErr;
|
||
|
||
if( ioPtr->scsiPBLength < sizeof(SIM_IO) ) {
|
||
finalStatus = scsiPBLengthError; /* Not enough room for SIM and HAL privates <SM5> */
|
||
goto FinalCheck;
|
||
}
|
||
|
||
if( ioPtr->scsiFlags & (0xffffffff - SIMg->HALinfo.supported_scFlags) ) {
|
||
finalStatus = scsiProvideFail;
|
||
goto FinalCheck;
|
||
}
|
||
|
||
if( ioPtr->scsiIOFlags & (0xffff - SIMg->HALinfo.supported_scIOFlags) ) {
|
||
finalStatus = scsiProvideFail;
|
||
goto FinalCheck;
|
||
}
|
||
|
||
if( finalStatus = ValidateDeviceIdent( ioPtr->scsiDevice, SIMg)) {
|
||
if (finalStatus == scsiTIDInvalid)
|
||
ioPtr->scsiOldCallResult = scsiSelectTimeout;
|
||
goto FinalCheck;
|
||
}
|
||
|
||
if( ioPtr->scsiCDBLength > 12 ) {
|
||
finalStatus = scsiCDBLengthInvalid; /* We can't handle CDB's longer than 12 bytes */
|
||
goto FinalCheck;
|
||
}
|
||
|
||
// if( ioPtr->scsiFunctionCode != SCSIOldCall ) {
|
||
// if( ioPtr->scsiDataType == kTib )
|
||
// finalStatus = scsiProvideFail; /* TIBs not supported */
|
||
// goto FinalCheck;
|
||
// }
|
||
|
||
if( !( (1<<(ioPtr->scsiDataType)) & SIMg->HALinfo.supported_scDataTypes) ) {
|
||
finalStatus = scsiDataTypeInvalid; /* data type not supported */
|
||
goto FinalCheck;
|
||
}
|
||
|
||
if( ioPtr->scsiTransferType > kMaxTransferType ) {
|
||
finalStatus = scsiTransferTypeInvalid; /* xfer type too high */
|
||
goto FinalCheck;
|
||
}
|
||
|
||
|
||
FinalCheck:
|
||
if( finalStatus != noErr ) {
|
||
ioPtr->scsiResult = finalStatus;
|
||
IfRecordEvent( (long)ioPtr, (long)'InvC');
|
||
CallCompRoutine( (SCSI_IO *)ioPtr); /* Whoops, not a valid PB */
|
||
return(false);
|
||
}
|
||
return(true);
|
||
}
|
||
|
||
|
||
/*********************************************************************************
|
||
ValidateDeviceIdent - Makes sure the target ID is valid
|
||
*********************************************************************************/
|
||
|
||
OSErr
|
||
ValidateDeviceIdent( DeviceIdent devIdent, SIMglobals * SIMg )
|
||
{
|
||
|
||
if( devIdent.targetID > kHighestTarget )/* Make Sure ID is in range <SM4>*/
|
||
return( scsiTIDInvalid);
|
||
|
||
if( devIdent.targetID == SIMg->hostID ) /* Can't allow Mac's id <SM4>*/
|
||
return( scsiTIDInvalid);
|
||
|
||
if( devIdent.LUN > 7 ) /* Allow all 8 LUNs */
|
||
return( scsiLUNInvalid);
|
||
|
||
return( noErr );
|
||
}
|
||
|
||
|
||
/*********************************************************************************
|
||
StartMachine - if SSM isn't already running, start machine if there
|
||
is a ready IO or R_select waiting
|
||
*********************************************************************************/
|
||
|
||
Boolean
|
||
StartMachine( SIMglobals * SIMg)
|
||
{
|
||
Boolean wasBusy;
|
||
ushort oldSR;
|
||
|
||
wasBusy = bset(kbSSMBusy, &SIMg->SSMflags);
|
||
|
||
if (wasBusy)
|
||
return( false); // didn't get the state machine this time
|
||
|
||
oldSR = BlockInterrupts(); //-> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> ->
|
||
|
||
|
||
if ( SIMg->r_selectWaiting)
|
||
{
|
||
SIMg->state = kGotR_selected;
|
||
}
|
||
else if ( 0!=( SIMg->halPB.ioPtr= GetNextReadyIO(SIMg) ))
|
||
{
|
||
SIMg->state = kIdle;
|
||
}
|
||
else
|
||
{
|
||
(void) bclr(kbSSMBusy, &SIMg->SSMflags);
|
||
UnblockInterrupts( oldSR);
|
||
return( false); // nothing to do so don't start machine
|
||
}
|
||
|
||
UnblockInterrupts( oldSR); //<- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <-
|
||
|
||
SIMg->halPB.result = noErr;
|
||
|
||
return( true); // we did get the machine and we do have something to do
|
||
}
|
||
|
||
|
||
|
||
/*********************************************************************************
|
||
NewIOStartMachine - if SSM isn't already running, start it
|
||
*********************************************************************************/
|
||
|
||
void
|
||
NewIOStartMachine(SIMglobals * SIMg)
|
||
{
|
||
IfRecordEvent( sp(), (long)'NwIO');
|
||
|
||
if (StartMachine( SIMg))
|
||
CallMachine( SIMg);
|
||
}
|
||
|
||
|
||
|
||
/*********************************************************************************
|
||
ReconnectISR -
|
||
*********************************************************************************/
|
||
|
||
void
|
||
ReconnectISR( SIMglobals * SIMg)
|
||
{
|
||
SIMg->r_selectWaiting = true;
|
||
|
||
if (StartMachine( SIMg))
|
||
CallMachine( SIMg);
|
||
}
|
||
|
||
|
||
|
||
/*********************************************************************************
|
||
FreeMachine - free up SSM so that another connection can use it
|
||
*********************************************************************************/
|
||
|
||
void
|
||
FreeMachine( OSErr finalStatus, SIM_IO * ioPtr, SIMglobals * SIMg)
|
||
{
|
||
Boolean doingAutosense;
|
||
|
||
if (ioPtr)
|
||
{
|
||
//……… this is order-critical - we should free up the machine before calling comprtn in case of a sync req
|
||
// from the comprtn
|
||
|
||
doingAutosense = CheckErrors( finalStatus, ioPtr, SIMg);
|
||
SIMg->state = kIdle;
|
||
(void) bclr(kbSSMBusy, &SIMg->SSMflags);
|
||
if( !doingAutosense )
|
||
CompleteIO( finalStatus, ioPtr, SIMg);
|
||
}
|
||
else {
|
||
SIMg->state = kIdle;
|
||
(void) bclr(kbSSMBusy, &SIMg->SSMflags);
|
||
}
|
||
|
||
if (StartMachine( SIMg))
|
||
CallMachine( SIMg);
|
||
}
|
||
|
||
|
||
|
||
/*********************************************************************************
|
||
CompleteIO -
|
||
*********************************************************************************/
|
||
|
||
void
|
||
CompleteIO( OSErr finalStatus, SIM_IO * ioPtr, SIMglobals * SIMg )
|
||
{
|
||
|
||
IfRecordEvent( (long)(ioPtr), (long)'CpIO');
|
||
|
||
DeQIO( ioPtr, SIMg ); // <SM2>
|
||
|
||
//--- if we don't yet have an error reported on this IO request,
|
||
// check for data run problem or a non-zero SCSI status
|
||
|
||
if ( finalStatus==noErr ) {
|
||
if ( ioPtr->scsiSCSIstatus!=0 ) {
|
||
finalStatus = scsiNonZeroStatus;
|
||
IfRecordError(finalStatus);
|
||
}
|
||
else if ( ioPtr->firstError) {
|
||
finalStatus = ioPtr->firstError;
|
||
IfRecordError(finalStatus);
|
||
}
|
||
else if ( ioPtr->scsiDataResidual != 0 || ( ioPtr->SIMprivFlags & kmBitBucketed) ) {
|
||
finalStatus = scsiDataRunError;
|
||
IfRecordError(finalStatus);
|
||
}
|
||
}
|
||
else {
|
||
IfRecordError(finalStatus);
|
||
}
|
||
|
||
//--- If we tried to send a message (abort, TermIO etc) we need to figure out what happened to it
|
||
// and call the completion routine for the control parameter block that was responsible for the message
|
||
// Note that even if multiple events happened we can only report one in an error message... <LW9>
|
||
|
||
// %%%!!! Move this elsewhere - we don't need to check for a parity error on every I/O
|
||
if( ioPtr->ioEvent & kmBadParity )
|
||
finalStatus = scsiParityError;
|
||
else if( ioPtr->pendingMsgPB ) {
|
||
if( ioPtr->ioEvent & kmTimedOut ) // <SM7>
|
||
finalStatus = scsiCommandTimeout;
|
||
else if( ioPtr->ioEvent & kmAborted )
|
||
finalStatus = (ioPtr->ioEvent & kmMsgRejected ) ? scsiUnableToAbort : scsiRequestAborted;
|
||
else if( ioPtr->ioEvent & kmTerminated )
|
||
finalStatus = (ioPtr->ioEvent & kmMsgRejected ) ? scsiUnableToTerminate : scsiTerminated;
|
||
else if( ioPtr->ioEvent & kmBDRSent )
|
||
finalStatus = (ioPtr->ioEvent & kmMsgRejected ) ? scsiMessageRejectReceived : scsiBDRsent;
|
||
((SCSIHdr *)((SIM_IO *)ioPtr->pendingMsgPB))->scsiResult = noErr;
|
||
IfRecordEvent( (long)ioPtr->pendingMsgPB, (long)'PndC');
|
||
CallCompRoutine( (SCSI_IO *)ioPtr->pendingMsgPB);
|
||
}
|
||
|
||
/* unlock the user's buffers if necessary <SM6> DCB */
|
||
if( (ioPtr->SIMprivFlags & (1 << kbSetupComplete)) != 0 )
|
||
{
|
||
CallHALTeardownIO( ioPtr, SIMg->HALinfo.HALstaticPtr);
|
||
}
|
||
|
||
ioPtr->scsiResult = finalStatus;
|
||
CallCompRoutine( (SCSI_IO *)ioPtr);
|
||
}
|
||
|
||
|
||
/*********************************************************************************
|
||
CallCompRoutine -
|
||
*********************************************************************************/
|
||
|
||
void
|
||
CallCompRoutine( SCSI_IO * ioPtr ) // <SM7>
|
||
{
|
||
VMEnableUserCode(); // we're safe now
|
||
|
||
XPTCallCompRoutine( ioPtr); // MAKE CALLBACK
|
||
|
||
VMDisableUserCode(); // and now we're not safe again
|
||
}
|
||
|
||
|
||
/*********************************************************************************
|
||
CheckErrors - check for errors and do queue maintenance
|
||
*********************************************************************************/
|
||
|
||
Boolean
|
||
CheckErrors( OSErr finalStatus, SIM_IO * ioPtr, SIMglobals * SIMg )
|
||
{
|
||
SIM_IO * originalPB;
|
||
ushort oldSR;
|
||
|
||
// If this was a return from an autosense ………………………………
|
||
|
||
if( ioPtr == &SIMg->sensePB ) {
|
||
|
||
originalPB = (SIM_IO *)ioPtr->scsiDriverStorage; /* We stuffed it here earlier */
|
||
|
||
if( finalStatus == noErr ) /* Request Sense succeeded */
|
||
originalPB->scsiResultFlags |= scsiAutosenseValid;
|
||
|
||
originalPB->ioEvent |= kmAutoSense; // Remember that we did autosense
|
||
|
||
CheckErrors( originalPB->savedResult, originalPB, SIMg ); /* Freeze LUN if necessary */
|
||
|
||
return(false); /* Now do CompleteIO for the Request Sense which will
|
||
do a CompleteIO for the original Parameter block
|
||
*/
|
||
|
||
}
|
||
|
||
/* Check if there was a check condition
|
||
If check condition and autosense
|
||
If the autosense PB is available
|
||
Fill in the autosense PB
|
||
Set the "Enqueue at Head" bit
|
||
use ioPB's autosense buffer
|
||
Enqueue autosense PB
|
||
else
|
||
remember that we are in line for autosense
|
||
Remember the final status for later
|
||
return; That is let the autosense's instance of CheckErrors worry about the queue
|
||
*/
|
||
|
||
// if we're being called before autosense ………………………………
|
||
|
||
if ( !(ioPtr->ioEvent & kmAutoSense) ) // Just because it isn't valid doesn't mean we didn't try...
|
||
{
|
||
// if we need to do an autosense
|
||
if ( ioPtr->scsiSCSIstatus == scsiStatCheckCondition
|
||
&& !(ioPtr->scsiFlags & scsiDisableAutosense)
|
||
&& (ioPtr->scsiSenseLength) )
|
||
{
|
||
oldSR = BlockInterrupts(); //-> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> ->
|
||
SIMg->senseWaiting+=1;
|
||
ioPtr->ioStat = kNeedsSense;
|
||
ioPtr->savedResult = finalStatus;
|
||
if ( ! SIMg->sensePBBusy ) {
|
||
SIMg->sensePBBusy = true;
|
||
SetupSensePB(ioPtr,SIMg); /* Sets the "Enqueue at head" bit */
|
||
EnQIO(&SIMg->sensePB,SIMg);
|
||
}
|
||
UnblockInterrupts( oldSR); //<- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <-
|
||
|
||
/* Return true so completeIO doesn't get called */
|
||
return(true); /* SwitchPhase is next up - should startup the autosense */
|
||
}
|
||
}
|
||
|
||
/* If (there was an error - or we were supposed to freeze the queue)
|
||
AND it is OK to freeze the queue - then freeze it.
|
||
*/
|
||
if( (finalStatus != noErr
|
||
|| ioPtr->scsiSCSIstatus != 0
|
||
|| (ioPtr->scsiFlags & scsiSIMQFreeze))
|
||
&& (ioPtr->scsiFlags & scsiSIMQNoFreeze) == 0 ) {
|
||
FreezeLUN( ioPtr->scsiDevice.targetID, ioPtr->scsiDevice.LUN);
|
||
ioPtr->scsiResultFlags |= scsiSIMQFrozen;
|
||
}
|
||
|
||
return(false);
|
||
}
|
||
|
||
|
||
/*********************************************************************************
|
||
SetupSensePB - setup the parameter block for an automatic request sense
|
||
*********************************************************************************/
|
||
|
||
void
|
||
SetupSensePB( SIM_IO * ioPtr, SIMglobals * SIMg )
|
||
{
|
||
uchar *cmd;
|
||
|
||
cmd = (uchar *)&SIMg->sensePB.scsiCDB;
|
||
|
||
SIMg->sensePB.scsiResult = scsiRequestInProgress; // EnqIO doesn't do this anymore... <SM10>
|
||
|
||
cmd[0] = 0x03; /* Request Sense */
|
||
cmd[1] = (ioPtr->scsiDevice.LUN) << 5; /* Fill in LUN */
|
||
|
||
cmd[2] = 0;
|
||
cmd[3] = 0;
|
||
cmd[4] = ioPtr->scsiSenseLength;
|
||
cmd[5] = 0;
|
||
|
||
SIMg->sensePB.scsiCDBLength = 6;
|
||
|
||
SIMg->sensePB.scsiPBLength = sizeof(SIM_IO);
|
||
|
||
SIMg->sensePB.scsiDataPtr = ioPtr->scsiSensePtr;
|
||
SIMg->sensePB.scsiDataLength = ioPtr->scsiSenseLength;
|
||
|
||
if ( (ioPtr->scsiIOFlags & scsiRenegotiateSense) && SIMg->syncRAoffset[ioPtr->scsiDevice.targetID])
|
||
SIMg->sensePB.scsiFlags = scsiInitiateSyncData;
|
||
|
||
SIMg->sensePB.scsiFlags |= scsiDirectionIn | scsiSIMQHead | /* MUST enqueue at the head!!! */
|
||
(ioPtr->scsiFlags & (
|
||
scsiDoDisconnect |
|
||
scsiDontDisconnect));
|
||
|
||
SIMg->sensePB.scsiIOFlags = scsiNoParityCheck |
|
||
(ioPtr->scsiIOFlags & (
|
||
scsiDisableSelectWAtn |
|
||
scsiSavePtrOnDisconnect));
|
||
|
||
SIMg->sensePB.scsiDevice = ioPtr->scsiDevice;
|
||
|
||
SIMg->sensePB.scsiDriverStorage = (uchar *) ioPtr;
|
||
SIMg->sensePB.scsiCompletion = CompAutoSense;
|
||
|
||
SIMg->sensePB.scsiTransferType = scsiTransferPolled;
|
||
|
||
SIMg->sensePB.scsiFunctionCode = SCSIExecIO;
|
||
|
||
}
|
||
|
||
|
||
/*********************************************************************************
|
||
SetupResetPB - setup the parameter block for a reset device <SM3>
|
||
*********************************************************************************/
|
||
|
||
void
|
||
SetupResetPB( uchar TargetID, SIMglobals * SIMg )
|
||
{
|
||
uchar *cmd;
|
||
|
||
cmd = (uchar *)&SIMg->sensePB.scsiCDB;
|
||
|
||
cmd[0] = 0x00; /* TUR - Something Safe */
|
||
cmd[1] = 0;
|
||
cmd[2] = 0;
|
||
cmd[3] = 0;
|
||
cmd[4] = 0;
|
||
cmd[5] = 0;
|
||
|
||
SIMg->resetDevPB.scsiPBLength = sizeof(SIM_IO);
|
||
|
||
SIMg->resetDevPB.scsiCDBLength = 6;
|
||
|
||
SIMg->resetDevPB.scsiFlags = scsiDirectionNone | scsiSIMQHead; /* enqueue at the head */
|
||
SIMg->resetDevPB.scsiDevice.targetID = TargetID; /* Entire device will get reset */
|
||
|
||
SIMg->resetDevPB.scsiDriverStorage = 0;
|
||
SIMg->resetDevPB.scsiCompletion = CompResetDevice; // <LW3>
|
||
|
||
SIMg->resetDevPB.scsiFunctionCode = SCSIExecIO;
|
||
|
||
}
|
||
|
||
|
||
/*********************************************************************************
|
||
CompAutoSense - autosense PB completion routine
|
||
*********************************************************************************/
|
||
|
||
pascal void
|
||
CompAutoSense( SIM_IO * senseIOPtr )
|
||
{
|
||
SIM_IO * nextSense;
|
||
SIM_IO * originalIOPtr;
|
||
SIMglobals * SIMg;
|
||
ushort oldSR;
|
||
|
||
VMDisableUserCode();
|
||
|
||
// Get stuff from autosense PB that we need for original request and get SIMg
|
||
|
||
originalIOPtr = (SIM_IO *)senseIOPtr->scsiDriverStorage;
|
||
SIMg = (SIMglobals *)senseIOPtr->SIMg;
|
||
originalIOPtr->scsiSenseResidual = senseIOPtr->scsiDataResidual;
|
||
originalIOPtr->ioStat = kGotSense; // Don't decrement senseWaiting in Dequeue
|
||
|
||
// Get the next PB which is waiting with Check Condition
|
||
|
||
oldSR = BlockInterrupts(); //-> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> -> ->
|
||
if ( --(SIMg->senseWaiting) > 0 ) {
|
||
nextSense = GetNextAutoSense( SIMg);
|
||
if (!nextSense) {
|
||
IfDebugStr("\psenseWaiting !=0 but none say kNeedsSense");
|
||
SIMg->senseWaiting = 0;
|
||
SIMg->sensePBBusy = 0;
|
||
}
|
||
else {
|
||
SetupSensePB( nextSense, SIMg);
|
||
EnQIO( senseIOPtr, SIMg);
|
||
NewIOStartMachine( SIMg); /* Kick it off */
|
||
}
|
||
}
|
||
else {
|
||
SIMg->sensePBBusy = false;
|
||
}
|
||
UnblockInterrupts( oldSR); //<- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <-
|
||
|
||
// call the original PB's completion routine <SM10>
|
||
CompleteIO( originalIOPtr->savedResult, originalIOPtr, SIMg);
|
||
|
||
VMEnableUserCode();
|
||
}
|
||
|
||
|
||
/*********************************************************************************
|
||
CompResetDevice - reset device PB completion routine
|
||
*********************************************************************************/
|
||
|
||
pascal void
|
||
CompResetDevice( SIM_IO * ioPtr ) // <SM3>
|
||
{
|
||
int TargetID;
|
||
SIMglobals * SIMg;
|
||
SCSI_PB * oldRDPtr;
|
||
SCSI_PB * newRDPtr;
|
||
|
||
SIMg = (SIMglobals *)ioPtr->SIMg;
|
||
|
||
// oldRDPtr = ioPtr->pendingMsgPB; // this is what we want to move to
|
||
oldRDPtr = (SCSI_PB *)(SIMg->resetPBQ.qHead); // <LW3> removed call to comp routine
|
||
if ( !oldRDPtr) {
|
||
IfDebugStr("\pNo qHead in CompResetDevice");
|
||
SysError( dsIOCoreErr);
|
||
}
|
||
else if ( oldRDPtr != ioPtr->pendingMsgPB) {
|
||
IfDebugStr("\pqHead != ioPtr->pendingMsgPB (in CompResetDevice)");
|
||
SysError( dsIOCoreErr);
|
||
}
|
||
else
|
||
Dequeue( (QElemPtr)oldRDPtr, &SIMg->resetPBQ);
|
||
|
||
/* Get the next Device which needs to be reset */
|
||
|
||
newRDPtr = (SCSI_PB *)(SIMg->resetPBQ.qHead);
|
||
if ( newRDPtr )
|
||
{
|
||
TargetID = newRDPtr->scsiDevice.targetID;
|
||
SetupResetPB( TargetID, SIMg);
|
||
EnQIO( &(SIMg->resetDevPB), SIMg);
|
||
SIMg->resetDevPB.pendingMsgPB = (Ptr) newRDPtr; /* Remember who started this <LW2> */
|
||
NewIOStartMachine( SIMg); /* Kick it off */
|
||
}
|
||
}
|
||
|
||
|