mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-12-28 16:31:01 +00:00
1626 lines
44 KiB
C
1626 lines
44 KiB
C
|
/*
|
|||
|
File: SIMmachine.c
|
|||
|
|
|||
|
Contains: routines that implement the SCSI state machine
|
|||
|
|
|||
|
Entry points:
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Written by: Paul Wolf
|
|||
|
|
|||
|
Copyright: <EFBFBD> 1992-1993 by Apple Computer, Inc., all rights reserved.
|
|||
|
|
|||
|
Change History (most recent first):
|
|||
|
|
|||
|
<SM22> 12/19/93 DCB Clear hdshkRemainder when we reconnect. This is to help solve
|
|||
|
the handshake across scatter gather boundries problem.
|
|||
|
<SM21> 11/22/93 pdw Rolling in from <MCxx>.
|
|||
|
<MC7> 11/9/93 pdw Fixed a problem with the CD300 rejecting an identify message.
|
|||
|
We now handle it and return an error.
|
|||
|
<MC6> 11/8/93 pdw Added some handling of unexpected bus free.
|
|||
|
<MC5> 11/5/93 pdw Series of attempts and re-attempts to fix various VM/FileShare
|
|||
|
problems.
|
|||
|
<SM20> 10/29/93 DCB <MC> roll-in.
|
|||
|
<MC4> 10/28/93 pdw Added a couple of states for use during Target mode.
|
|||
|
<SM19> 10/14/93 pdw <MC> roll-in.
|
|||
|
<MC3> 10/12/93 pdw Fixed some bugs in some messaging corner cases.
|
|||
|
<MC2> 10/12/93 pdw Added support for Synchronous data transfers, rewrote State
|
|||
|
Machine, message handling etc.
|
|||
|
<SM18> 8/13/93 pdw Changing the message handling in DoComplete.
|
|||
|
<SM17> 7/17/93 pdw Lots of little things. A few big things.
|
|||
|
<SM16> 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. Resolving
|
|||
|
with my Ludwig sources.
|
|||
|
<SM15> 5/29/93 PW Adding include of SCSIDebug.h
|
|||
|
<SM14> 5/25/93 DCB Rollin from Ludwig. (The next item below)
|
|||
|
<LW17> 5/21/93 PW Timeout bugs fixed. DebugStr stuff. Last minute target mode
|
|||
|
changes.
|
|||
|
<SM13> 5/5/93 PW Converted names to meanies-friendly names. Updated with latest
|
|||
|
from Ludwig stuff.
|
|||
|
<LW16> 5/1/93 PW Changed xxxResidualLength to xxxResidual.
|
|||
|
<LW15> 4/30/93 DCB Adding CallBusInquiry function so that we don't have to busy the
|
|||
|
HALAction routine.
|
|||
|
<LW14> 4/29/93 DCB Fixing Build - Sorry bout that.
|
|||
|
<LW13> 4/14/93 DCB Added calls the the SetParity HALAction for each reconnect and
|
|||
|
successful initiate.
|
|||
|
<LW12> 3/26/93 PW Rolled in SuperMario changes. Removed useless RejectMsg stuff. A
|
|||
|
few little optimizations. Fixed bug in autosense that showed up
|
|||
|
when deferring completions and fixed bug in ResetDevice. Added
|
|||
|
kWastePhase to bit bucket an unknown phase.
|
|||
|
<LW11> 3/22/93 DCB Adding code to reject an identify message from an unknown
|
|||
|
re-select to fix a test tool bug with the Seagate 400.
|
|||
|
<SM12> 3/20/93 PW Moving CallCompRoutine into SIM so that it can call
|
|||
|
ExitingSIM/EnteringSIM instead of XPT.
|
|||
|
<LW10> 3/22/93 PW Rolling in SuperMario changes. Removing useless RejectMsg stuff.
|
|||
|
Few little optimizations.
|
|||
|
<LW9> 3/1/93 DCB Re-worked message handling. This included changing the use of
|
|||
|
the event field for better tracking of abort and terminate IO
|
|||
|
and fixing the message reject code.
|
|||
|
<LW8> 2/18/93 DCB Added check for Bus Free phase before setting ATN to send a
|
|||
|
message. The c96 will bit bucket the next command after an
|
|||
|
illegal set of ATN causing a sync-wait hang.
|
|||
|
<LW7> 2/17/93 PW Optimizations - Removed some unneeded "what" usages and got rid
|
|||
|
of halPtr in Machine. Also got rid of halPBptr parameter in
|
|||
|
SwitchPhase and Reconnect. Added check for status phz just after
|
|||
|
recon to avoid implied restore pointers (for IBM drives). Fixed
|
|||
|
DontDisconnect bug.
|
|||
|
<SM10> 1/31/93 PW Update from the latest of Ludwig. Also changes required for PDM
|
|||
|
(will update Ludwig with these as needed myself).
|
|||
|
<LW6> 1/27/93 PW Fixed VM 'too many enables' bug by doing the 'double completion
|
|||
|
routine on autosense' stuff the right way - I call VMDisable and
|
|||
|
EnableUserCode at top and bottom of CompAutoSense.
|
|||
|
<LW5> 1/12/93 DCB Fixed handling of IOevent so that timeouts were reported as
|
|||
|
timeouts rather than aborted commands.
|
|||
|
<LW4> 1/8/93 PW Added RestorePointers call upon acceptance of Identify message
|
|||
|
during a reconnect.
|
|||
|
<LW3> 1/4/93 DCB Fixed SetupResetPB so that it fills in the completion routine
|
|||
|
field. The lack of the completion routine caused asynchronous
|
|||
|
ResetDevice calls to get stuck in a SyncWait. This fixes Radar
|
|||
|
bug 1059424 .
|
|||
|
<LW2> 12/17/92 DCB Fixed a bug in the auto-request sense feature which caused a
|
|||
|
sync-wait hang.
|
|||
|
<SM9> 12/9/92 PW Added check for invalid scsiIOFlags.
|
|||
|
<SM8> 12/5/92 PW Changed ValidateDI to return appropriate error instead of
|
|||
|
Boolean.
|
|||
|
<SM7> 11/20/92 DCB Support for async Abort, Terminate and Reset Device
|
|||
|
<SM6> 10/30/92 DCB Added call to Teardown routines to support Direct DMA into a
|
|||
|
user buffer
|
|||
|
<SM5> 10/8/92 PW (dcb) Added support for variable-sized SCSI_IO. Fixed AbortCmd
|
|||
|
bug which required addition of an ioEvent field.
|
|||
|
<SM4> 9/14/92 DCB Added some parameter block validation
|
|||
|
<SM3> 9/11/92 DCB Made numerous changes to the state machine so that the bus
|
|||
|
wouldn't hang after a failed TerminateIO or Abort Command. Also
|
|||
|
added BusDeviceReset.
|
|||
|
<SM2> 8/31/92 DCB Implementing Terminate/Abort IO
|
|||
|
|
|||
|
*/
|
|||
|
|
|||
|
#include <Types.h>
|
|||
|
#include <Memory.h>
|
|||
|
#include <Errors.h>
|
|||
|
#include <SCSIStandard.h>
|
|||
|
#include <SCSI.h>
|
|||
|
|
|||
|
#include "ACAM.h"
|
|||
|
#include "XPT.h"
|
|||
|
#include "XPTpriv.h"
|
|||
|
#include "CUtils.h"
|
|||
|
#include "SCSIGlue.h"
|
|||
|
|
|||
|
#include "SIMCore.h"
|
|||
|
#include "SIMCorePriv.h"
|
|||
|
#include "SIMQ.h"
|
|||
|
|
|||
|
#include "SCSIDebug.h"
|
|||
|
#include "Recorder.h"
|
|||
|
|
|||
|
|
|||
|
/********* External Function Prototypes **********/
|
|||
|
|
|||
|
|
|||
|
/********* Internal-only Function Prototypes **********/
|
|||
|
|
|||
|
void SwitchPhase( SIM_IO * ioPtr, SIMglobals * SIMg);
|
|||
|
void EarlySwitchPhase( SIM_IO * ioPtr, SIMglobals * SIMg);
|
|||
|
void WastePhase( SIM_IO * ioPtr, SIMglobals * SIMg);
|
|||
|
void Reconnect( SIMglobals * SIMg);
|
|||
|
void HandleEarlyMsgIn( SIM_IO * ioPtr, SIMglobals * SIMg);
|
|||
|
void HandleNoIdentifyMsg( SIM_IO * ioPtr, SIMglobals * SIMg);
|
|||
|
void HandleRejectedIdentify( SIM_IO * ioPtr, SIMglobals * SIMg);
|
|||
|
void HandleInitWErr( SIM_IO * ioPtr, SIMglobals * SIMg);
|
|||
|
|
|||
|
/*********************************************************************************
|
|||
|
Machine - the actual SSM!
|
|||
|
*********************************************************************************/
|
|||
|
/*
|
|||
|
The SSM works with the HAL to transact a SCSI connection. The communication
|
|||
|
between the SSM and HAL occur via a HALactionPB which is allocated in the
|
|||
|
SIM's globals. The same HALactionPB is used from the time of Initiation to
|
|||
|
Disconnection.
|
|||
|
*/
|
|||
|
|
|||
|
Boolean // freeTheMachine
|
|||
|
TheMachine( OSErr * finalStatus, SIM_IO ** completedIO, SIMglobals * SIMg)
|
|||
|
{
|
|||
|
HALresult result;
|
|||
|
HALactions halAct;
|
|||
|
SIM_IO * ioPtr;
|
|||
|
uchar targetID;
|
|||
|
uchar LUN;
|
|||
|
|
|||
|
|
|||
|
ioPtr = SIMg->halPB.ioPtr; // <SM2>
|
|||
|
targetID = ioPtr->scsiDevice.targetID;
|
|||
|
|
|||
|
/********** STATE MACHINE **********/
|
|||
|
|
|||
|
do
|
|||
|
{
|
|||
|
result = SIMg->halPB.result;
|
|||
|
|
|||
|
/* If we are connected to an io which needs a message - assert ATN
|
|||
|
SwitchPhase will figure out how to actually send it
|
|||
|
*/
|
|||
|
if (ioPtr) if (ioPtr->pendingMsgPB) // guarantee that this is the first test of the if
|
|||
|
{
|
|||
|
if (SIMg->state != kIdle &&
|
|||
|
SIMg->state != kGotR_selected &&
|
|||
|
(ioPtr->ioEvent & kmMsgSent) == 0 && // <LW9>
|
|||
|
SIMg->halPB.phase != kBusFreePhase )
|
|||
|
{
|
|||
|
if (SIMg->halPB.phase == kStatusPhase)
|
|||
|
{
|
|||
|
switch( ((SCSIHdr *)(ioPtr->pendingMsgPB))->scsiFunctionCode) { // <SM7>
|
|||
|
|
|||
|
case SCSITerminateIO:
|
|||
|
((SCSIHdr *)(ioPtr->pendingMsgPB))->scsiResult = scsiUnableToTerminate;
|
|||
|
IfRecordEvent( (long)ioPtr->pendingMsgPB, (long)'TrmC');
|
|||
|
CallCompRoutine( (SCSI_IO *)ioPtr->pendingMsgPB);
|
|||
|
(SCSI_IO *)ioPtr->pendingMsgPB = nil;
|
|||
|
break;
|
|||
|
case SCSIAbortCommand:
|
|||
|
((SCSIHdr *)(ioPtr->pendingMsgPB))->scsiResult = scsiUnableToAbort;
|
|||
|
IfRecordEvent( (long)ioPtr->pendingMsgPB, (long)'AbtC');
|
|||
|
CallCompRoutine( (SCSI_IO *)ioPtr->pendingMsgPB);
|
|||
|
(SCSI_IO *)ioPtr->pendingMsgPB = nil;
|
|||
|
break;
|
|||
|
case SCSIResetDevice:
|
|||
|
break;
|
|||
|
} // <SM7>
|
|||
|
}
|
|||
|
else { // (not status phase)
|
|||
|
CallHALAssertATN( SIMg->HALinfo.HALstaticPtr);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
IfRecordEvent( (long)((SIMg->state<<16) + result), (long)'Mach');
|
|||
|
|
|||
|
switch (SIMg->state)
|
|||
|
{
|
|||
|
|
|||
|
//==== IDLE ====
|
|||
|
|
|||
|
case kIdle:
|
|||
|
|
|||
|
if (ioPtr->scsiFunctionCode != SCSIOldCall)
|
|||
|
{
|
|||
|
//<2F><><EFBFBD><EFBFBD> NEW API <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
|||
|
// Set up for sending an Identify message during Initiate
|
|||
|
// depending on our default disc, we check the other Do/Don<6F>t flag to make sure
|
|||
|
|
|||
|
if (SIMg->defaultDisc) {
|
|||
|
if ( ioPtr->scsiFlags & scsiDontDisconnect) // if default=Do but client says Don<6F>t
|
|||
|
SIMg->halPB.msg[0] = IdentifyMsg( false, ioPtr->scsiDevice.LUN);
|
|||
|
else
|
|||
|
SIMg->halPB.msg[0] = IdentifyMsg( true, ioPtr->scsiDevice.LUN);
|
|||
|
}
|
|||
|
else {
|
|||
|
if ( ioPtr->scsiFlags & scsiDoDisconnect) // if default=Don<6F>t but client says Do
|
|||
|
SIMg->halPB.msg[0] = IdentifyMsg( true, ioPtr->scsiDevice.LUN);
|
|||
|
else
|
|||
|
SIMg->halPB.msg[0] = IdentifyMsg( false, ioPtr->scsiDevice.LUN);
|
|||
|
}
|
|||
|
|
|||
|
if (SIMg->syncRAoffset[targetID]) {
|
|||
|
CallHALSyncConfig( SIMg->syncRAoffset[targetID],
|
|||
|
SIMg->syncPeriod [targetID], SIMg->HALinfo.HALstaticPtr );
|
|||
|
}
|
|||
|
SIMg->halPB.msgOutLen = 1; // only 1 byte for now, Identify
|
|||
|
SIMg->halPB.sendCDB = true;
|
|||
|
|
|||
|
SIMg->state = kInitiatingNormal;
|
|||
|
|
|||
|
|
|||
|
// Check to see if this is a forced reconnection for the purpose of
|
|||
|
// issuing an abort, terminate io or reset device message
|
|||
|
|
|||
|
if( ioPtr->pendingMsgPB )
|
|||
|
{
|
|||
|
switch( ((SCSI_PB *)ioPtr->pendingMsgPB)->scsiFunctionCode) { // <SM7>
|
|||
|
|
|||
|
case SCSITerminateIO:
|
|||
|
SIMg->halPB.msg[1] = kTerminateIOProcessMsg;
|
|||
|
break;
|
|||
|
case SCSIAbortCommand:
|
|||
|
SIMg->halPB.msg[1] = kAbortMsg;
|
|||
|
break;
|
|||
|
case SCSIResetDevice:
|
|||
|
SIMg->halPB.msg[1] = kBusDeviceResetMsg;
|
|||
|
break;
|
|||
|
|
|||
|
}
|
|||
|
SIMg->halPB.msgOutLen = 2;
|
|||
|
SIMg->halPB.sendCDB = false;
|
|||
|
|
|||
|
ioPtr->ioEvent |= (kmMsgSent); // we'll undo this if it fails
|
|||
|
|
|||
|
SIMg->state = kInitiatingAsyncMsg;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// Check for need to perform Synchronous Data Transfer negotiation
|
|||
|
|
|||
|
if ( (ioPtr->scsiFlags & (scsiInitiateSyncData | scsiDisableSyncData)) ||
|
|||
|
SIMg->needNegot[targetID] )
|
|||
|
{
|
|||
|
SIMg->halPB.msg[1] = 0x01; // extended message
|
|||
|
SIMg->halPB.msg[2] = 0x03; // length
|
|||
|
SIMg->halPB.msg[3] = 0x01; // SDTR
|
|||
|
SIMg->halPB.msg[4] = SIMg->HALinfo.minPeriodFactor; // transfer period
|
|||
|
if (ioPtr->scsiFlags & scsiDisableSyncData) {
|
|||
|
SIMg->halPB.msg[5] = 0; // asynchronous
|
|||
|
}
|
|||
|
else {
|
|||
|
SIMg->halPB.msg[5] = SIMg->HALinfo.syncRAoffset; // REQ/ACK offset
|
|||
|
}
|
|||
|
SIMg->halPB.msgOutLen = 6;
|
|||
|
SIMg->halPB.sendCDB = false;
|
|||
|
|
|||
|
SIMg->state = kInitiatingSDTR;
|
|||
|
}
|
|||
|
}
|
|||
|
// Start initiation process (this could come back w/ a recon)
|
|||
|
|
|||
|
ioPtr->ioStat = kAttemptingInitiation;
|
|||
|
CallHALaction( kInitiate, &SIMg->halPB, SIMg);
|
|||
|
}
|
|||
|
|
|||
|
else // ioPtr->scsiFunctionCode == SCSIOldCall
|
|||
|
{
|
|||
|
//<2F><><EFBFBD><EFBFBD> OLD API <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
|||
|
ioPtr->ioStat = kAttemptingInitiation;
|
|||
|
SIMg->state = kInitiatingOldCall;
|
|||
|
CallHALaction( kSelect, &SIMg->halPB, SIMg);
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
//==== GotR_selected In Progress ====
|
|||
|
|
|||
|
case kGotR_selected:
|
|||
|
|
|||
|
CallHALaction( kGetReconnectInfo, &SIMg->halPB, SIMg); // always synchronous call
|
|||
|
if ( SIMg->halPB.result == kHALreselected) { // really was a reconnect
|
|||
|
Reconnect( SIMg);
|
|||
|
ioPtr = SIMg->halPB.ioPtr; // Reconnect can change which IO we're doing
|
|||
|
targetID = ioPtr->scsiDevice.targetID;
|
|||
|
}
|
|||
|
else if ( SIMg->halPB.result == kHALselectedAsTarget) {
|
|||
|
SIMg->state = kHandlingSelected;
|
|||
|
SIMg->pushedState = kFreeMachine; // after select is done, free the machine
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
//==== HandlingSelected In Progress ====
|
|||
|
|
|||
|
case kHandlingSelected:
|
|||
|
|
|||
|
SIMg->r_selectWaiting = false;
|
|||
|
CallHALaction( kHandleSelected, &SIMg->halPB, SIMg);
|
|||
|
SIMg->state = SIMg->pushedState;
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
//==== INITIATE In Progress - Normal ====
|
|||
|
|
|||
|
case kInitiatingNormal:
|
|||
|
|
|||
|
if (!result) //== noErr
|
|||
|
{
|
|||
|
ioPtr->ioStat = kSentCommand;
|
|||
|
SwitchPhase( ioPtr, SIMg);
|
|||
|
}
|
|||
|
else if (result == kHALreselected)
|
|||
|
{
|
|||
|
ioPtr->ioStat = kPBidle; // go back to Idle for this one
|
|||
|
Reconnect( SIMg);
|
|||
|
ioPtr = SIMg->halPB.ioPtr; // Reconnect can change which IO we're doing
|
|||
|
targetID = ioPtr->scsiDevice.targetID;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
HandleInitWErr( ioPtr, SIMg);
|
|||
|
ioPtr = SIMg->halPB.ioPtr; // Reconnect can change which IO we're doing
|
|||
|
targetID = ioPtr->scsiDevice.targetID;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//==== INITIATE In Progress - SDTR ====
|
|||
|
|
|||
|
case kInitiatingSDTR:
|
|||
|
|
|||
|
if (!result)
|
|||
|
{
|
|||
|
if (SIMg->halPB.msgInLen == 6)
|
|||
|
{
|
|||
|
if ((SIMg->halPB.msg[1] == 0x01) && (SIMg->halPB.msg[3] == 0x01)) {
|
|||
|
SIMg->syncPeriod [targetID] = SIMg->halPB.msg[4]; // transfer period
|
|||
|
SIMg->syncRAoffset[targetID] = SIMg->halPB.msg[5]; // REQ/ACK offset
|
|||
|
|
|||
|
CallHALSyncConfig( SIMg->syncRAoffset[ioPtr->scsiDevice.targetID],
|
|||
|
SIMg->syncPeriod [ioPtr->scsiDevice.targetID], SIMg->HALinfo.HALstaticPtr );
|
|||
|
|
|||
|
CallHALaction( kAcceptMsg, &SIMg->halPB, SIMg);
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
SIMg->syncRAoffset[targetID] = 0;
|
|||
|
if ((SIMg->halPB.msgInLen == 1) && (SIMg->halPB.msg[0] == kMsgRejectMsg))
|
|||
|
{
|
|||
|
CallHALaction( kAcceptMsg, &SIMg->halPB, SIMg);
|
|||
|
}
|
|||
|
}
|
|||
|
EarlySwitchPhase( ioPtr, SIMg);
|
|||
|
}
|
|||
|
else if (result == kHALreselected)
|
|||
|
{
|
|||
|
ioPtr->ioStat = kPBidle; // go back to Idle for this one
|
|||
|
Reconnect( SIMg);
|
|||
|
ioPtr = SIMg->halPB.ioPtr; // Reconnect can change which IO we're doing
|
|||
|
targetID = ioPtr->scsiDevice.targetID;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
HandleInitWErr( ioPtr, SIMg);
|
|||
|
ioPtr = SIMg->halPB.ioPtr; // Reconnect can change which IO we're doing
|
|||
|
targetID = ioPtr->scsiDevice.targetID;
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
//==== INITIATE In Progress - AsyncMsg ====
|
|||
|
|
|||
|
case kInitiatingAsyncMsg:
|
|||
|
|
|||
|
if (!result)
|
|||
|
{
|
|||
|
if (SIMg->halPB.phase == kBusFreePhase)
|
|||
|
{
|
|||
|
switch( ((SCSI_PB *)ioPtr->pendingMsgPB)->scsiFunctionCode)
|
|||
|
{
|
|||
|
case SCSITerminateIO:
|
|||
|
ioPtr->ioEvent |= (kmTerminated | kmMsgSent);
|
|||
|
// Remove this IO from the Disconnected array since we aborted cmd
|
|||
|
SIMg->discIOs [targetID] [ioPtr->scsiDevice.LUN] = 0;
|
|||
|
SIMg->LUNstate[targetID] [ioPtr->scsiDevice.LUN] &= ~km_LUNdisconnected;
|
|||
|
break;
|
|||
|
|
|||
|
case SCSIAbortCommand:
|
|||
|
ioPtr->ioEvent |= (kmAborted | kmMsgSent);
|
|||
|
// Remove this IO from the Disconnected array since we aborted cmd
|
|||
|
SIMg->discIOs [targetID] [ioPtr->scsiDevice.LUN] = 0;
|
|||
|
SIMg->LUNstate[targetID] [ioPtr->scsiDevice.LUN] &= ~km_LUNdisconnected;
|
|||
|
break;
|
|||
|
|
|||
|
case SCSIResetDevice:
|
|||
|
ioPtr->ioEvent |= (kmBDRSent | kmMsgSent);
|
|||
|
for( LUN = 0; LUN < 8; LUN+=1 ) {
|
|||
|
SIMg->discIOs [targetID][LUN] = 0;
|
|||
|
SIMg->LUNstate[targetID][LUN] &= ~km_LUNdisconnected;
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
*finalStatus = result;
|
|||
|
*completedIO = ioPtr;
|
|||
|
return (true);
|
|||
|
}
|
|||
|
else if ((SIMg->halPB.phase == kMessageInPhaseNACK) && (SIMg->halPB.msg[0] == kMsgRejectMsg))
|
|||
|
{
|
|||
|
CallHALaction( kAcceptMsg, &SIMg->halPB, SIMg);
|
|||
|
SIMg->state = kAcceptingRejectedAsyncMsg;
|
|||
|
break;
|
|||
|
}
|
|||
|
else {
|
|||
|
*finalStatus = scsiUnableToAbort;
|
|||
|
WastePhase( ioPtr, SIMg);
|
|||
|
}
|
|||
|
}
|
|||
|
else if (result == kHALreselected)
|
|||
|
{
|
|||
|
ioPtr->ioStat = kPBidle; // go back to Idle for this one
|
|||
|
Reconnect( SIMg);
|
|||
|
ioPtr = SIMg->halPB.ioPtr; // Reconnect can change which IO we're doing
|
|||
|
targetID = ioPtr->scsiDevice.targetID;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
HandleInitWErr( ioPtr, SIMg);
|
|||
|
ioPtr = SIMg->halPB.ioPtr; // Reconnect can change which IO we're doing
|
|||
|
targetID = ioPtr->scsiDevice.targetID;
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
//==== INITIATE In Progress - OldCall ====
|
|||
|
|
|||
|
case kInitiatingOldCall:
|
|||
|
|
|||
|
ioPtr->scsiCurrentPhase = SIMg->halPB.phase;
|
|||
|
if (result == noErr)
|
|||
|
{
|
|||
|
SIMg->state = kAwaitingOldCall;
|
|||
|
ioPtr->ioStat = kSelectComplete;
|
|||
|
ioPtr->scsiOldCallResult = noErr;
|
|||
|
return (false);
|
|||
|
}
|
|||
|
else if (result == kHALreselected) // i.e. we got reselected
|
|||
|
{
|
|||
|
ioPtr->ioStat = kPBidle; // go back to Idle for this one
|
|||
|
Reconnect( SIMg);
|
|||
|
ioPtr = SIMg->halPB.ioPtr; // Reconnect can change which IO we're doing
|
|||
|
targetID = ioPtr->scsiDevice.targetID;
|
|||
|
break;
|
|||
|
}
|
|||
|
else if (result == kHALselectedAsTarget) // we got selected
|
|||
|
{
|
|||
|
SIMg->state = kHandlingSelected;
|
|||
|
SIMg->pushedState = kIdle; // after select is done, retry this IO initiation
|
|||
|
break;
|
|||
|
}
|
|||
|
else if (result == kHALselectFld)
|
|||
|
{
|
|||
|
*finalStatus = scsiSelectTimeout;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
*finalStatus = result;
|
|||
|
}
|
|||
|
|
|||
|
ioPtr->scsiOldCallResult = *finalStatus;
|
|||
|
|
|||
|
if (SIMg->halPB.phase == kBusFreePhase)
|
|||
|
{
|
|||
|
*completedIO = ioPtr;
|
|||
|
return (true);
|
|||
|
}
|
|||
|
else {
|
|||
|
return (false);
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
//==== Accepting Msg after Rejected Async Msg ====
|
|||
|
|
|||
|
case kAcceptingRejectedAsyncMsg:
|
|||
|
|
|||
|
if (SIMg->halPB.phase == kBusFreePhase)
|
|||
|
{
|
|||
|
ioPtr->ioEvent |= (kmMsgSent);
|
|||
|
*finalStatus = scsiMessageRejectReceived;
|
|||
|
*completedIO = ioPtr;
|
|||
|
return (true);
|
|||
|
}
|
|||
|
WastePhase(ioPtr, SIMg);
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
//==== Accepting Msg after Rejected Identify Msg ====
|
|||
|
|
|||
|
case kAcceptingRejectedIdentify:
|
|||
|
|
|||
|
if (SIMg->halPB.phase == kMessageOutPhase)
|
|||
|
{
|
|||
|
SIMg->halPB.msg[0] = kAbortMsg;
|
|||
|
SIMg->halPB.msgOutLen = 1;
|
|||
|
SIMg->state = kAbortingRejectedIdentify;
|
|||
|
CallHALaction( kSendMsgOut, &SIMg->halPB, SIMg);
|
|||
|
|
|||
|
} else if (SIMg->halPB.phase == kBusFreePhase)
|
|||
|
{
|
|||
|
*finalStatus = scsiIdentifyMessageRejected;
|
|||
|
*completedIO = ioPtr;
|
|||
|
return (true);
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
//==== Aborting IO after Rejected Identify Msg ====
|
|||
|
|
|||
|
case kAbortingRejectedIdentify:
|
|||
|
|
|||
|
if (SIMg->halPB.phase == kBusFreePhase)
|
|||
|
{
|
|||
|
*finalStatus = scsiIdentifyMessageRejected;
|
|||
|
*completedIO = ioPtr;
|
|||
|
return (true);
|
|||
|
}
|
|||
|
else if (SIMg->halPB.phase == kMessageInPhaseNACK)
|
|||
|
{
|
|||
|
//if (SIMg->halPB.msg[0]==kMsgRejectMsg) enough of this, just accept it
|
|||
|
CallHALaction( kAcceptMsg, &SIMg->halPB, SIMg);
|
|||
|
SIMg->state = kEarlySwitchingPhase;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
//==== RECONNECT - Accepting Identify Message ====
|
|||
|
|
|||
|
case kReconAcceptingMsg:
|
|||
|
|
|||
|
if (ioPtr->ioStat == kDisconnected)
|
|||
|
{
|
|||
|
// for IBM drives, that don't do SaveDataPointer on last data connection of a write
|
|||
|
if (SIMg->halPB.phase != kStatusPhase)
|
|||
|
CallHALaction( kRestorePointers, &SIMg->halPB, SIMg);
|
|||
|
SwitchPhase( ioPtr, SIMg);
|
|||
|
}
|
|||
|
else
|
|||
|
EarlySwitchPhase( ioPtr, SIMg);
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
//==== Sending Message ====
|
|||
|
|
|||
|
case kSendingEarlyKillMsg:
|
|||
|
case kSendingKillMsg:
|
|||
|
|
|||
|
if (!result)
|
|||
|
{
|
|||
|
switch( ((SCSI_PB *)(ioPtr->pendingMsgPB))->scsiFunctionCode) {
|
|||
|
|
|||
|
case SCSITerminateIO:
|
|||
|
ioPtr->ioEvent |= (kmTerminated | kmMsgSent);
|
|||
|
// Remove this IO from the Disconnected array since we aborted cmd
|
|||
|
SIMg->discIOs [targetID] [ioPtr->scsiDevice.LUN] = 0;
|
|||
|
SIMg->LUNstate[targetID] [ioPtr->scsiDevice.LUN] &= ~km_LUNdisconnected;
|
|||
|
break;
|
|||
|
|
|||
|
case SCSIAbortCommand:
|
|||
|
ioPtr->ioEvent |= (kmAborted | kmMsgSent);
|
|||
|
// Remove this IO from the Disconnected array since we aborted cmd
|
|||
|
SIMg->discIOs [targetID] [ioPtr->scsiDevice.LUN] = 0;
|
|||
|
SIMg->LUNstate[targetID] [ioPtr->scsiDevice.LUN] &= ~km_LUNdisconnected;
|
|||
|
break;
|
|||
|
|
|||
|
case SCSIResetDevice:
|
|||
|
ioPtr->ioEvent |= (kmBDRSent | kmMsgSent);
|
|||
|
for( LUN = 0; LUN < 8; LUN+=1 ) {
|
|||
|
SIMg->discIOs [targetID][LUN] = 0;
|
|||
|
SIMg->LUNstate[targetID][LUN] &= ~km_LUNdisconnected;
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
if (SIMg->halPB.phase == kBusFreePhase) {
|
|||
|
*finalStatus = result;
|
|||
|
*completedIO = ioPtr;
|
|||
|
return (true);
|
|||
|
}
|
|||
|
else {
|
|||
|
if (SIMg->state == kSendingEarlyKillMsg)
|
|||
|
EarlySwitchPhase( ioPtr, SIMg);
|
|||
|
else
|
|||
|
SwitchPhase( ioPtr, SIMg);
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
//==== Sending Initiator Detected Error Msg ====
|
|||
|
|
|||
|
case kSendingDetectedErrorMsg:
|
|||
|
|
|||
|
if (!result)
|
|||
|
{
|
|||
|
IfDebugStr("\pkSendingDetectedErrorMsg not supported");
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
//==== Sending Command ====
|
|||
|
|
|||
|
case kSendingCommand:
|
|||
|
|
|||
|
ioPtr->ioStat = kSentCommand;
|
|||
|
SwitchPhase( ioPtr, SIMg);
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
//==== Sending Message ====
|
|||
|
|
|||
|
case kSendingMsg:
|
|||
|
|
|||
|
SwitchPhase( ioPtr, SIMg);
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
//==== Rejecting Early Message In ====
|
|||
|
|
|||
|
case kRejectingEarlyMsg:
|
|||
|
|
|||
|
if (SIMg->halPB.phase == kMessageOutPhase)
|
|||
|
{
|
|||
|
SIMg->state = kEarlySwitchingPhase;
|
|||
|
SIMg->halPB.msg[0] = kMsgRejectMsg;
|
|||
|
SIMg->halPB.msgOutLen = 1;
|
|||
|
CallHALaction( kSendMsgOut, &SIMg->halPB, SIMg);
|
|||
|
}
|
|||
|
else
|
|||
|
EarlySwitchPhase( ioPtr, SIMg);
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
//==== Accepting Early SDTR ====
|
|||
|
|
|||
|
case kAcceptingEarlySDTR:
|
|||
|
case kAcceptingSDTR:
|
|||
|
|
|||
|
if (result)
|
|||
|
{
|
|||
|
SIMg->syncRAoffset[targetID] = 0; // Something went wrong - target is asynchronous
|
|||
|
}
|
|||
|
EarlySwitchPhase( ioPtr, SIMg);
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
//==== Rejecting a message ====
|
|||
|
|
|||
|
case kReconRejectingMsg:
|
|||
|
case kRejectingDataMsg:
|
|||
|
|
|||
|
switch( SIMg->halPB.phase ) {
|
|||
|
|
|||
|
case kMessageInPhaseNACK: // in case of multiple message-in bytes
|
|||
|
CallHALaction( kAcceptMsg, &SIMg->halPB, SIMg);
|
|||
|
break;
|
|||
|
case kMessageOutPhase:
|
|||
|
SIMg->state = kSendingMsg;
|
|||
|
SIMg->halPB.msg[0] = kMsgRejectMsg;
|
|||
|
SIMg->halPB.msgOutLen = 1;
|
|||
|
CallHALaction( kSendMsgOut, &SIMg->halPB, SIMg);
|
|||
|
break;
|
|||
|
default:
|
|||
|
IfDebugStr("\pBogus phase while rejecting message!");
|
|||
|
SwitchPhase( ioPtr, SIMg);
|
|||
|
break;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
//==== Switching Phase ====
|
|||
|
|
|||
|
case kSwitchingPhase:
|
|||
|
|
|||
|
SwitchPhase( ioPtr, SIMg);
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
//==== Doing Data ====
|
|||
|
|
|||
|
case kDoingData:
|
|||
|
|
|||
|
if (!result) {
|
|||
|
SwitchPhase( ioPtr, SIMg);
|
|||
|
}
|
|||
|
else if (result == scsiWrongDirection) {
|
|||
|
ioPtr->scsiDataResidual = -ioPtr->scsiDataResidual;
|
|||
|
ioPtr->SIMprivFlags |= kmDataDone; // to get SwitchPhase to bitbucket
|
|||
|
ioPtr->firstError = scsiWrongDirection;
|
|||
|
SwitchPhase( ioPtr, SIMg);
|
|||
|
}
|
|||
|
else if (result == scsiUnexpectedBusFree) {
|
|||
|
SIMg->state = kWentBusFree;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
//==== Early Switching Phase ====
|
|||
|
|
|||
|
case kEarlySwitchingPhase:
|
|||
|
|
|||
|
EarlySwitchPhase( ioPtr, SIMg);
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
//==== Completing ====
|
|||
|
|
|||
|
case kGettingStatus:
|
|||
|
|
|||
|
if (result == noErr) // this means we got a status, msg and then bus free
|
|||
|
{
|
|||
|
*finalStatus = noErr;
|
|||
|
*completedIO = ioPtr;
|
|||
|
IfRecordEvent( (long)ioPtr, (long)'GtSt');
|
|||
|
return (true);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
IfDebugStr("\pError while kGettingStatus");
|
|||
|
*finalStatus = result;
|
|||
|
*completedIO = ioPtr;
|
|||
|
IfRecordError( result);
|
|||
|
return (true);
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
//==== Disconnecting Before Sending Command ====
|
|||
|
|
|||
|
case kDisconnectingB4Command:
|
|||
|
|
|||
|
if (SIMg->halPB.phase == kBusFreePhase) {
|
|||
|
*finalStatus = 0;
|
|||
|
*completedIO = 0;
|
|||
|
return (true);
|
|||
|
}
|
|||
|
else { // huh? we got a disconnect msg, I expected to disconnect!
|
|||
|
EarlySwitchPhase( ioPtr, SIMg); // only diff between this and next
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
//==== Disconnecting ====
|
|||
|
|
|||
|
case kDisconnecting:
|
|||
|
|
|||
|
if (SIMg->halPB.phase == kBusFreePhase) {
|
|||
|
*finalStatus = 0;
|
|||
|
*completedIO = 0;
|
|||
|
return (true);
|
|||
|
}
|
|||
|
else { // huh? we got a disconnect msg, I expected to disconnect!
|
|||
|
SwitchPhase( ioPtr, SIMg);
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
//==== Went Bus Free Unexpectedly ====
|
|||
|
|
|||
|
// Error condition
|
|||
|
// This is used to return from an unexpected bus free
|
|||
|
|
|||
|
case kWentBusFree:
|
|||
|
*finalStatus = scsiUnexpectedBusFree;
|
|||
|
// fall thru
|
|||
|
|
|||
|
//==== Bus Free From WastePhase ====
|
|||
|
|
|||
|
case kWastedToBusFree:
|
|||
|
*completedIO = ioPtr;
|
|||
|
return (true);
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
//==== FreeMachine ====
|
|||
|
|
|||
|
case kFreeMachine:
|
|||
|
*finalStatus = noErr;
|
|||
|
*completedIO = 0; // no IOpb was being worked on, none to complete
|
|||
|
return (true); // free the machine
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
//==== Returning from failed Select ====
|
|||
|
|
|||
|
// Error condition
|
|||
|
// Used by HandleInitWErr to return from an unexpected bus free
|
|||
|
|
|||
|
case kFailingSelect:
|
|||
|
*finalStatus = scsiSelectTimeout;
|
|||
|
*completedIO = ioPtr;
|
|||
|
return (true);
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
//==== AwaitingOldCall ====
|
|||
|
|
|||
|
case kAwaitingOldCall:
|
|||
|
|
|||
|
SIMg->state = kPerformingOldCall;
|
|||
|
//
|
|||
|
switch (ioPtr->scsiSelector)
|
|||
|
{
|
|||
|
case kSCSICmd:
|
|||
|
if (ioPtr->scsiCurrentPhase != kCommandPhase) {
|
|||
|
result = scPhaseErr;
|
|||
|
break;
|
|||
|
}
|
|||
|
halAct = kCommand;
|
|||
|
break;
|
|||
|
|
|||
|
case kSCSIComplete:
|
|||
|
halAct = kComplete;
|
|||
|
ioPtr->scTimer = ioPtr->scsiTimeout; /* Start timer <LW9> */
|
|||
|
break;
|
|||
|
|
|||
|
case kSCSIRead:
|
|||
|
case kSCSIRBlind:
|
|||
|
halAct = kDataIn;
|
|||
|
break;
|
|||
|
|
|||
|
case kSCSIWrite:
|
|||
|
case kSCSIWBlind:
|
|||
|
halAct = kDataOut;
|
|||
|
break;
|
|||
|
|
|||
|
case kSCSIMsgIn:
|
|||
|
if (ioPtr->scsiCurrentPhase != kMessageInPhase) {
|
|||
|
result = scPhaseErr;
|
|||
|
break;
|
|||
|
}
|
|||
|
// we autoMsgIn'd the message already so we just move it
|
|||
|
SIMg->halPB.msgInLen -= 1;
|
|||
|
ioPtr->scsiSCSImessage = SIMg->halPB.msg[0];
|
|||
|
// then we accept it, going to the next phase
|
|||
|
halAct = kAcceptMsg;
|
|||
|
break;
|
|||
|
|
|||
|
case kSCSIMsgOut: // need to get buffer set up in HALactionPB
|
|||
|
if (ioPtr->scsiCurrentPhase != kMessageOutPhase) {
|
|||
|
result = scPhaseErr;
|
|||
|
break;
|
|||
|
}
|
|||
|
SIMg->halPB.msg[0] = ioPtr->scsiSCSImessage;
|
|||
|
SIMg->halPB.msgOutLen = 1;
|
|||
|
halAct = kSendMsgOut;
|
|||
|
break;
|
|||
|
|
|||
|
// These selectors should never get down to the SIM - the XPT handles them
|
|||
|
case kSCSIStat: // data generated by XPT
|
|||
|
case kSCSIReset: // sent as ResetBus request(s)
|
|||
|
case kSCSIGet: // ignored
|
|||
|
case kSCSISelect: // sent as Initiate
|
|||
|
case kSCSISelAtn: // sent as Initiate
|
|||
|
default:
|
|||
|
IfDebugStr("\pUnknown old call selector in kAwaitingOldCall state");
|
|||
|
SysError( dsIOCoreErr);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
CallHALaction( halAct, &SIMg->halPB, SIMg);
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
//==== PerformingOldCall ====
|
|||
|
|
|||
|
case kPerformingOldCall:
|
|||
|
|
|||
|
if (SIMg->halPB.phase == kMessageInPhaseNACK)
|
|||
|
ioPtr->scsiCurrentPhase = kMessageInPhase; // convert (we already got the msg)
|
|||
|
else
|
|||
|
ioPtr->scsiCurrentPhase = SIMg->halPB.phase;
|
|||
|
|
|||
|
SIMg->state = kAwaitingOldCall;
|
|||
|
*finalStatus = result;
|
|||
|
ioPtr->scsiOldCallResult = *finalStatus;
|
|||
|
|
|||
|
if (SIMg->halPB.phase == kBusFreePhase)
|
|||
|
{
|
|||
|
*completedIO = ioPtr;
|
|||
|
return (true); // return out of machine and DO free it
|
|||
|
}
|
|||
|
return (false); // return out of machine but DON'T free it
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
//==== Getting SCSIMsgIn message ====
|
|||
|
|
|||
|
case kGettingSCSIMsgIn:
|
|||
|
|
|||
|
SIMg->state = kPerformingOldCall;
|
|||
|
CallHALaction( kAcceptMsg, &SIMg->halPB, SIMg);
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
//==== BitBucketing 1 phase ====
|
|||
|
|
|||
|
case kWastingPhase:
|
|||
|
|
|||
|
WastePhase( ioPtr, SIMg);
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
//==== ? ====
|
|||
|
|
|||
|
default:
|
|||
|
IfDebugStr("\pUnknown state");
|
|||
|
SIMg->state = SIMg->state;
|
|||
|
|
|||
|
} //============ end of switch on SIMg->state =================
|
|||
|
|
|||
|
} while (true);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*********************************************************************************
|
|||
|
Reconnect -
|
|||
|
*********************************************************************************/
|
|||
|
/*
|
|||
|
This is kind of tricky. This routine can be called at various stages in the
|
|||
|
reconnect process to determine what to do next. This can be thought of as
|
|||
|
another state but is not a part of TheMachine to avoid code duplication.
|
|||
|
|
|||
|
There are two possible ways to end up here - either by a Reconnect interrupt
|
|||
|
causing the HAL to send a ReconnectISR call to the SSM or by the SSM receiving
|
|||
|
a Reconnect event in response to a HALinitiate or Select call.
|
|||
|
|
|||
|
In the first case, the HAL will call the ReconnectISR entry point in the SSM
|
|||
|
which sets a flag and tries to start up the Machine.
|
|||
|
|
|||
|
In the second case, the SSM will be kIdle and be working on a kNewIO event,
|
|||
|
forming a new HALactionPB (in the SIM's globals) and issuing an Initiate request
|
|||
|
to the HAL. If a reconnect occurs after the StartMachine() call is made by
|
|||
|
SIMCore and before the arbitration of the bus has occurred, then the HAL ISR's
|
|||
|
call to ReconnectISR() will see that the Machine is busy, and return to the HAL
|
|||
|
without starting up the Machine (it's already running with the Initiate). The
|
|||
|
HAL will be in the middle of or shortly thereafter receiving the HALinitiate call.
|
|||
|
The HAL will respond to that call by placing the recon vals in the HALactionPB
|
|||
|
and calling Machine() which will call Reconnect() to complete the reconnection.
|
|||
|
*/
|
|||
|
|
|||
|
void
|
|||
|
Reconnect( SIMglobals * SIMg)
|
|||
|
{
|
|||
|
SIMg->r_selectWaiting = false;
|
|||
|
|
|||
|
// for c96
|
|||
|
if (SIMg->halPB.phase == kMessageInPhaseNACK) // got Identify, need a MsgAccept
|
|||
|
{
|
|||
|
SIMg->reconTargetID = SIMg->halPB.selectorID;
|
|||
|
SIMg->reconLUN = IdentifyToLUN( SIMg->halPB.msg[0]);
|
|||
|
|
|||
|
|
|||
|
// Get the IO that was talking to this Target/LUN
|
|||
|
|
|||
|
SIMg->halPB.ioPtr = SIMg->discIOs[SIMg->reconTargetID][SIMg->reconLUN];
|
|||
|
|
|||
|
// If unknown, reject, if known accept and complete the reconnection
|
|||
|
|
|||
|
if ( SIMg->halPB.ioPtr == 0)
|
|||
|
{
|
|||
|
// this is apparently an unknown IO, we'll reject the Identify
|
|||
|
// should do a message reject message (i.e. setAtn, send MsgRej) (per SCSI-2?)
|
|||
|
|
|||
|
// !!! We need to fill in the ioPtr field in the HalActionPB so that if
|
|||
|
// we need to do anything other than reject the message we won't explode!
|
|||
|
|
|||
|
SIMg->state = kReconRejectingMsg;
|
|||
|
CallHALAssertATN( SIMg->HALinfo.HALstaticPtr);
|
|||
|
CallHALaction( kAcceptMsg, &SIMg->halPB, SIMg);
|
|||
|
}
|
|||
|
else // we have an IO to reconnect to
|
|||
|
{
|
|||
|
ReconnectIO( SIMg->reconTargetID, SIMg->reconLUN);
|
|||
|
|
|||
|
CallHALSyncConfig( SIMg->syncRAoffset[SIMg->halPB.ioPtr->scsiDevice.targetID],
|
|||
|
SIMg->syncPeriod [SIMg->halPB.ioPtr->scsiDevice.targetID], SIMg->HALinfo.HALstaticPtr );
|
|||
|
|
|||
|
SIMg->state = kReconAcceptingMsg;
|
|||
|
SIMg->halPB.ioPtr->hdshkRemainder = 0; // Handshake gets re-started on a reconnect...
|
|||
|
CallHALaction( kSetParity, &SIMg->halPB, SIMg);
|
|||
|
CallHALaction( kAcceptMsg, &SIMg->halPB, SIMg);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
else if (SIMg->halPB.phase == kMessageInPhase) // need to get Identify
|
|||
|
{
|
|||
|
IfDebugStr("\pMessageInPhase after reconnect");
|
|||
|
SysError( dsIOCoreErr);
|
|||
|
}
|
|||
|
|
|||
|
else // not message phase at all
|
|||
|
{
|
|||
|
IfDebugStr("\pNot message phase after reconnect");
|
|||
|
SysError( dsIOCoreErr);
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/*********************************************************************************
|
|||
|
EarlySwitchPhase - we've sent the Identify but not yet the Command
|
|||
|
*********************************************************************************/
|
|||
|
|
|||
|
void
|
|||
|
EarlySwitchPhase( SIM_IO * ioPtr, SIMglobals * SIMg)
|
|||
|
{
|
|||
|
Boolean assertATN;
|
|||
|
|
|||
|
IfRecordEvent( (long)(SIMg->halPB.phase), (long)'ESwP');
|
|||
|
|
|||
|
switch (SIMg->halPB.phase) {
|
|||
|
|
|||
|
case kDataInPhase:
|
|||
|
case kDataOutPhase:
|
|||
|
|
|||
|
SIMg->state = kEarlySwitchingPhase;
|
|||
|
CallHALaction( kBitBucket, &SIMg->halPB, SIMg);
|
|||
|
break;
|
|||
|
|
|||
|
case kMessageInPhaseNACK:
|
|||
|
|
|||
|
assertATN = false;
|
|||
|
|
|||
|
switch ( SIMg->halPB.msg[0] )
|
|||
|
{
|
|||
|
case kDisconnectMsg:
|
|||
|
ioPtr->ioStat = kDisconnectedB4Command;
|
|||
|
DisconnectIO( ioPtr->scsiDevice.targetID,
|
|||
|
ioPtr->scsiDevice.LUN, ioPtr);
|
|||
|
SIMg->state = kDisconnectingB4Command;
|
|||
|
CallHALaction( kAcceptMsg, &SIMg->halPB, SIMg);
|
|||
|
break;
|
|||
|
|
|||
|
case kMsgRejectMsg: // Apparently the target didn't like our identify message
|
|||
|
HandleRejectedIdentify( ioPtr, SIMg);
|
|||
|
break;
|
|||
|
|
|||
|
case kExtendedMsg:
|
|||
|
#if 0
|
|||
|
if (SIMg->halPB.msgInLen >= 4)
|
|||
|
{
|
|||
|
if (SIMg->halPB.msg[2] == 0x01) // SDTR message
|
|||
|
{
|
|||
|
if ((SIMg->halPB.msgInLen == 6) && (SIMg->halPB.msg[2] == 0x03))
|
|||
|
{
|
|||
|
SIMg->halPB.msg[4] = MAX( SIMg->HALinfo.minPeriodFactor,
|
|||
|
SIMg->halPB.msg[4] );
|
|||
|
|
|||
|
SIMg->halPB.msg[5] = MIN( SIMg->HALinfo.syncRAoffset,
|
|||
|
SIMg->halPB.msg[5] );
|
|||
|
|
|||
|
SIMg->syncPeriod [ioPtr->scsiDevice.targetID] = SIMg->halPB.msg[4]; // transfer period
|
|||
|
SIMg->syncRAoffset[ioPtr->scsiDevice.targetID] = SIMg->halPB.msg[5]; // REQ/ACK offset
|
|||
|
|
|||
|
CallHALSyncConfig( SIMg->syncRAoffset[ioPtr->scsiDevice.targetID],
|
|||
|
SIMg->syncPeriod [ioPtr->scsiDevice.targetID], SIMg->HALinfo.HALstaticPtr );
|
|||
|
|
|||
|
CallHALAssertATN( SIMg->HALinfo.HALstaticPtr);
|
|||
|
CallHALaction( kAcceptMsg, &SIMg->halPB, SIMg);
|
|||
|
if (SIMg->halPB.phase == kMessageOutPhase)
|
|||
|
{
|
|||
|
SIMg->state = kAcceptingEarlySDTR;
|
|||
|
SIMg->halPB.msgOutLen = 6;
|
|||
|
CallHALaction( kSendMsgOut, &SIMg->halPB, SIMg);
|
|||
|
}
|
|||
|
else // no msg out phase - target async
|
|||
|
{
|
|||
|
SIMg->state = kEarlySwitchingPhase;
|
|||
|
SIMg->syncRAoffset[ioPtr->scsiDevice.targetID] = 0; // asynchronous
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
else // something wrong with format of SDTR
|
|||
|
{
|
|||
|
SIMg->syncRAoffset[ioPtr->scsiDevice.targetID] = 0; // asynchronous
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
// extended message that we don't care about
|
|||
|
SIMg->state = kRejectingEarlyMsg;
|
|||
|
CallHALAssertATN( SIMg->HALinfo.HALstaticPtr);
|
|||
|
CallHALaction( kAcceptMsg, &SIMg->halPB, SIMg);
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
CallHALAssertATN( SIMg->HALinfo.HALstaticPtr);
|
|||
|
CallHALaction( kAcceptMsg, &SIMg->halPB, SIMg);
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case kStatusPhase:
|
|||
|
|
|||
|
SIMg->state = kGettingStatus;
|
|||
|
CallHALaction( kStatus, &SIMg->halPB, SIMg);
|
|||
|
break;
|
|||
|
|
|||
|
case kMessageOutPhase: // we should only be here because we asserted ATN
|
|||
|
|
|||
|
SIMg->state = kSendingEarlyKillMsg;
|
|||
|
|
|||
|
if( !ioPtr->pendingMsgPB ) {
|
|||
|
if( ioPtr->ioEvent & kmBadParity )
|
|||
|
SIMg->halPB.msg[0] = kInitiatorDetectedErrorMsg;
|
|||
|
else
|
|||
|
SIMg->halPB.msg[0] = kNoOperationMsg; // NOP since we don't know what is going on!
|
|||
|
}
|
|||
|
else {
|
|||
|
switch( ((SCSI_PB *)(ioPtr->pendingMsgPB))->scsiFunctionCode) {
|
|||
|
|
|||
|
case SCSITerminateIO:
|
|||
|
SIMg->halPB.msg[0] = kTerminateIOProcessMsg;
|
|||
|
ioPtr->ioEvent |= (kmTerminated | kmMsgSent);
|
|||
|
break;
|
|||
|
case SCSIAbortCommand:
|
|||
|
SIMg->halPB.msg[0] = kAbortMsg;
|
|||
|
ioPtr->ioEvent |= (kmAborted | kmMsgSent);
|
|||
|
break;
|
|||
|
case SCSIResetDevice:
|
|||
|
SIMg->halPB.msg[0] = kBusDeviceResetMsg;
|
|||
|
ioPtr->ioEvent |= (kmBDRSent | kmMsgSent);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
SIMg->halPB.msgOutLen = 1;
|
|||
|
|
|||
|
CallHALaction( kSendMsgOut, &SIMg->halPB, SIMg);
|
|||
|
break;
|
|||
|
|
|||
|
case kCommandPhase:
|
|||
|
|
|||
|
CallHALaction( kCommand, &SIMg->halPB, SIMg);
|
|||
|
SIMg->state = kSendingCommand;
|
|||
|
break;
|
|||
|
|
|||
|
case kBusFreePhase:
|
|||
|
|
|||
|
SIMg->state = kWentBusFree;
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
|
|||
|
IfDebugStr("\pUnknown phase in EarlySwitchPhase");
|
|||
|
SysError( dsIOCoreErr);
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*********************************************************************************
|
|||
|
WastePhase - we're really confused, do what we need to to clear the bus
|
|||
|
*********************************************************************************/
|
|||
|
|
|||
|
void
|
|||
|
WastePhase( SIM_IO * ioPtr, SIMglobals * SIMg)
|
|||
|
{
|
|||
|
IfRecordEvent( (long)'DUMP', (long)'Err!');
|
|||
|
SIMg->state = kWastingPhase;
|
|||
|
|
|||
|
switch (SIMg->halPB.phase) {
|
|||
|
|
|||
|
case kDataInPhase:
|
|||
|
case kDataOutPhase:
|
|||
|
|
|||
|
CallHALaction( kBitBucket, &SIMg->halPB, SIMg);
|
|||
|
break;
|
|||
|
|
|||
|
case kMessageInPhaseNACK:
|
|||
|
|
|||
|
CallHALAssertATN( SIMg->HALinfo.HALstaticPtr);
|
|||
|
CallHALaction( kAcceptMsg, &SIMg->halPB, SIMg);
|
|||
|
break;
|
|||
|
|
|||
|
case kStatusPhase:
|
|||
|
|
|||
|
SIMg->state = kGettingStatus;
|
|||
|
CallHALaction( kStatus, &SIMg->halPB, SIMg);
|
|||
|
break;
|
|||
|
|
|||
|
case kMessageOutPhase: // we should only be here because we asserted ATN
|
|||
|
|
|||
|
SIMg->state = kSendingEarlyKillMsg;
|
|||
|
|
|||
|
if( !ioPtr->pendingMsgPB ) {
|
|||
|
if( ioPtr->ioEvent & kmBadParity )
|
|||
|
SIMg->halPB.msg[0] = kInitiatorDetectedErrorMsg;
|
|||
|
else
|
|||
|
SIMg->halPB.msg[0] = kNoOperationMsg; // NOP since we don't know what is going on!
|
|||
|
}
|
|||
|
else {
|
|||
|
switch( ((SCSI_PB *)(ioPtr->pendingMsgPB))->scsiFunctionCode) {
|
|||
|
|
|||
|
case SCSITerminateIO:
|
|||
|
SIMg->halPB.msg[0] = kTerminateIOProcessMsg;
|
|||
|
ioPtr->ioEvent |= (kmTerminated | kmMsgSent);
|
|||
|
break;
|
|||
|
case SCSIAbortCommand:
|
|||
|
SIMg->halPB.msg[0] = kAbortMsg;
|
|||
|
ioPtr->ioEvent |= (kmAborted | kmMsgSent);
|
|||
|
break;
|
|||
|
case SCSIResetDevice:
|
|||
|
SIMg->halPB.msg[0] = kBusDeviceResetMsg;
|
|||
|
ioPtr->ioEvent |= (kmBDRSent | kmMsgSent);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
SIMg->halPB.msgOutLen = 1;
|
|||
|
|
|||
|
CallHALaction( kSendMsgOut, &SIMg->halPB, SIMg);
|
|||
|
break;
|
|||
|
|
|||
|
case kCommandPhase:
|
|||
|
|
|||
|
CallHALaction( kCommand, &SIMg->halPB, SIMg);
|
|||
|
SIMg->state = kSendingCommand;
|
|||
|
break;
|
|||
|
|
|||
|
case kBusFreePhase:
|
|||
|
|
|||
|
SIMg->state = kWastedToBusFree;
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
|
|||
|
IfDebugStr("\pUnknown phase in WastePhase");
|
|||
|
SysError( dsIOCoreErr);
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*********************************************************************************
|
|||
|
HandleInitWErr -
|
|||
|
*********************************************************************************/
|
|||
|
|
|||
|
void
|
|||
|
HandleInitWErr( SIM_IO * ioPtr, SIMglobals * SIMg)
|
|||
|
{
|
|||
|
OSErr result;
|
|||
|
|
|||
|
result = SIMg->halPB.result;
|
|||
|
|
|||
|
IfRecordEvent( (long)( (SIMg->halPB.sendCDB<<24) + (SIMg->halPB.phase<<16) + (SIMg->halPB.msgInLen<<8) + SIMg->halPB.msgOutLen),
|
|||
|
(long)'IErr');
|
|||
|
|
|||
|
IfRecordEvent( (long)( (result<<16) + SIMg->halPB.action),
|
|||
|
(long)'Err!');
|
|||
|
|
|||
|
if (result == kHALreselected)
|
|||
|
{
|
|||
|
ioPtr->ioStat = kPBidle; // go back to Idle for this one
|
|||
|
Reconnect( SIMg);
|
|||
|
}
|
|||
|
else if (result == kHALpartialMsgOut)
|
|||
|
{
|
|||
|
if (SIMg->halPB.msgOutLen == 0) {
|
|||
|
HandleNoIdentifyMsg( ioPtr, SIMg);
|
|||
|
}
|
|||
|
else if (SIMg->halPB.msgOutLen == 1) {
|
|||
|
if ((SIMg->halPB.phase == kMessageInPhaseNACK) && (SIMg->halPB.msg[0] == kMsgRejectMsg)) {
|
|||
|
HandleRejectedIdentify( ioPtr, SIMg);
|
|||
|
}
|
|||
|
else
|
|||
|
EarlySwitchPhase( ioPtr, SIMg);
|
|||
|
}
|
|||
|
else // 2 or more msg bytes went out
|
|||
|
{
|
|||
|
if (SIMg->state == kInitiatingSDTR) {
|
|||
|
SIMg->syncRAoffset[ioPtr->scsiDevice.targetID] = 0;
|
|||
|
}
|
|||
|
else { // kInitiatingAsyncMsg
|
|||
|
if ((SIMg->halPB.phase == kMessageInPhaseNACK) && (SIMg->halPB.msg[0] == kMsgRejectMsg)) {
|
|||
|
ioPtr->firstError = scsiKillMsgRejected;
|
|||
|
}
|
|||
|
}
|
|||
|
EarlySwitchPhase( ioPtr, SIMg);
|
|||
|
}
|
|||
|
}
|
|||
|
else if (result == kHALnoCommand)
|
|||
|
{
|
|||
|
EarlySwitchPhase( ioPtr, SIMg);
|
|||
|
}
|
|||
|
else if (result == kHALpartialCommand)
|
|||
|
{
|
|||
|
ioPtr->ioStat = kSentCommand; // pretend like we got no error
|
|||
|
SwitchPhase( ioPtr, SIMg);
|
|||
|
}
|
|||
|
else if (result == kHALselectedAsTarget) // we got selected
|
|||
|
{
|
|||
|
SIMg->state = kHandlingSelected;
|
|||
|
SIMg->pushedState = kIdle; // retry this IO initiation
|
|||
|
}
|
|||
|
else if (result == kHALselectedAsTargetFld)
|
|||
|
{
|
|||
|
SIMg->state = kIdle; // retry this IO initiation
|
|||
|
}
|
|||
|
else if (result == kHALselectFld)
|
|||
|
{
|
|||
|
SIMg->state = kFailingSelect;
|
|||
|
}
|
|||
|
else if (result == scsiUnexpectedBusFree)
|
|||
|
{
|
|||
|
SIMg->state = kWentBusFree;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
IfDebugStr("\pUnknown result in HandleInitWErr");
|
|||
|
SysError( dsIOCoreErr);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/*********************************************************************************
|
|||
|
HandleRejectedIdentify -
|
|||
|
*********************************************************************************/
|
|||
|
|
|||
|
void
|
|||
|
HandleRejectedIdentify( SIM_IO * ioPtr, SIMglobals * SIMg)
|
|||
|
{
|
|||
|
#pragma unused (ioPtr)
|
|||
|
CallHALAssertATN( SIMg->HALinfo.HALstaticPtr);
|
|||
|
CallHALaction( kAcceptMsg, &SIMg->halPB, SIMg);
|
|||
|
ioPtr->firstError = scsiIdentifyMessageRejected;
|
|||
|
SIMg->state = kAcceptingRejectedIdentify;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*********************************************************************************
|
|||
|
HandleEarlyMsgIn -
|
|||
|
*********************************************************************************/
|
|||
|
|
|||
|
void
|
|||
|
HandleEarlyMsgIn( SIM_IO * ioPtr, SIMglobals * SIMg)
|
|||
|
{
|
|||
|
EarlySwitchPhase( ioPtr, SIMg);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*********************************************************************************
|
|||
|
HandleNoIdentifyMsg -
|
|||
|
*********************************************************************************/
|
|||
|
|
|||
|
void
|
|||
|
HandleNoIdentifyMsg( SIM_IO * ioPtr, SIMglobals * SIMg)
|
|||
|
{
|
|||
|
if (SIMg->halPB.phase == kCommandPhase)
|
|||
|
EarlySwitchPhase( ioPtr, SIMg);
|
|||
|
else // if (SIMg->halPB.phase == kMessageInPhaseNACK)
|
|||
|
EarlySwitchPhase( ioPtr, SIMg);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*********************************************************************************
|
|||
|
SwitchPhase -
|
|||
|
*********************************************************************************/
|
|||
|
|
|||
|
void
|
|||
|
SwitchPhase( SIM_IO * ioPtr, SIMglobals * SIMg)
|
|||
|
{
|
|||
|
Boolean assertATN;
|
|||
|
|
|||
|
IfRecordEvent( (long)(SIMg->halPB.phase), (long)'SwPz');
|
|||
|
|
|||
|
switch (SIMg->halPB.phase) {
|
|||
|
|
|||
|
case kDataInPhase:
|
|||
|
|
|||
|
if ( ioPtr->scsiDataResidual <= 0 || ( ioPtr->SIMprivFlags & kmDataDone) ) {
|
|||
|
ioPtr->SIMprivFlags |= kmBitBucketed;
|
|||
|
if ( ioPtr->scsiIOFlags & scsiNoBucketIn) {
|
|||
|
ioPtr->scsiResultFlags |= scsiBusNotFree;
|
|||
|
CompleteIO( scsiDataRunError, ioPtr, SIMg);
|
|||
|
}
|
|||
|
else {
|
|||
|
SIMg->state = kSwitchingPhase;
|
|||
|
CallHALaction( kBitBucket, &SIMg->halPB, SIMg);
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
SIMg->state = kDoingData;
|
|||
|
CallHALaction( kDataIn, &SIMg->halPB, SIMg);
|
|||
|
break;
|
|||
|
|
|||
|
case kDataOutPhase:
|
|||
|
|
|||
|
if ( ioPtr->scsiDataResidual <= 0 || ( ioPtr->SIMprivFlags & kmDataDone) ) {
|
|||
|
ioPtr->SIMprivFlags |= kmBitBucketed;
|
|||
|
if ( ioPtr->scsiIOFlags & scsiNoBucketOut) {
|
|||
|
ioPtr->scsiResultFlags |= scsiBusNotFree;
|
|||
|
CompleteIO( scsiDataRunError, ioPtr, SIMg);
|
|||
|
}
|
|||
|
else {
|
|||
|
SIMg->state = kSwitchingPhase;
|
|||
|
CallHALaction( kBitBucket, &SIMg->halPB, SIMg);
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
SIMg->state = kDoingData;
|
|||
|
CallHALaction( kDataOut, &SIMg->halPB, SIMg);
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
case kMessageInPhaseNACK:
|
|||
|
|
|||
|
assertATN = false;
|
|||
|
|
|||
|
switch ( SIMg->halPB.msg[0] )
|
|||
|
{
|
|||
|
case kSaveDataPointerMsg: // TAKEN CARE OF IN HAL NOW
|
|||
|
CallHALaction( kSaveDataPointer, &SIMg->halPB, SIMg); // is this perSCSI2? (or after accept)
|
|||
|
SIMg->state = kSwitchingPhase;
|
|||
|
break;
|
|||
|
|
|||
|
case kRestorePointersMsg: // TAKEN CARE OF IN HAL NOW
|
|||
|
CallHALaction( kRestorePointers, &SIMg->halPB, SIMg); // is this perSCSI2? (or after accept)
|
|||
|
SIMg->state = kSwitchingPhase;
|
|||
|
break;
|
|||
|
|
|||
|
case kDisconnectMsg:
|
|||
|
ioPtr->ioStat = kDisconnected;
|
|||
|
|
|||
|
// if SavePtrOnDisc flag is set, we should do that now
|
|||
|
if (ioPtr->scsiIOFlags & scsiSavePtrOnDisconnect)
|
|||
|
CallHALaction( kSaveDataPointer, &SIMg->halPB, SIMg);
|
|||
|
|
|||
|
SIMg->state = kDisconnecting;
|
|||
|
DisconnectIO( ioPtr->scsiDevice.targetID,
|
|||
|
ioPtr->scsiDevice.LUN, ioPtr);
|
|||
|
break;
|
|||
|
|
|||
|
case kMsgRejectMsg: // Apparently the target didn't like our message
|
|||
|
((SCSIHdr *)((SIM_IO *)ioPtr->pendingMsgPB))->scsiResult = scsiMessageRejectReceived;
|
|||
|
IfRecordEvent( (long)ioPtr->pendingMsgPB, (long)'RejC');
|
|||
|
CallCompRoutine( (SCSI_IO *)ioPtr->pendingMsgPB);
|
|||
|
ioPtr->ioEvent |= kmMsgRejected;
|
|||
|
break;
|
|||
|
|
|||
|
case kCmdCompleteMsg:
|
|||
|
break;
|
|||
|
|
|||
|
case kExtendedMsg:
|
|||
|
#if 0
|
|||
|
if (SIMg->halPB.msgInLen >= 4)
|
|||
|
{
|
|||
|
if (SIMg->halPB.msg[2] == 0x01) // SDTR message
|
|||
|
{
|
|||
|
if ((SIMg->halPB.msgInLen == 6) && (SIMg->halPB.msg[2] == 0x03))
|
|||
|
{
|
|||
|
SIMg->halPB.msg[4] = MAX( SIMg->HALinfo.minPeriodFactor,
|
|||
|
SIMg->halPB.msg[4] );
|
|||
|
|
|||
|
SIMg->halPB.msg[5] = MIN( SIMg->HALinfo.syncRAoffset,
|
|||
|
SIMg->halPB.msg[5] );
|
|||
|
|
|||
|
SIMg->syncPeriod [ioPtr->scsiDevice.targetID] = SIMg->halPB.msg[4]; // transfer period
|
|||
|
SIMg->syncRAoffset[ioPtr->scsiDevice.targetID] = SIMg->halPB.msg[5]; // REQ/ACK offset
|
|||
|
|
|||
|
CallHALSyncConfig( SIMg->syncRAoffset[ioPtr->scsiDevice.targetID],
|
|||
|
SIMg->syncPeriod [ioPtr->scsiDevice.targetID], SIMg->HALinfo.HALstaticPtr );
|
|||
|
|
|||
|
CallHALAssertATN( SIMg->HALinfo.HALstaticPtr);
|
|||
|
CallHALaction( kAcceptMsg, &SIMg->halPB, SIMg);
|
|||
|
if (SIMg->halPB.phase == kMessageOutPhase)
|
|||
|
{
|
|||
|
SIMg->state = kAcceptingSDTR;
|
|||
|
SIMg->halPB.msgOutLen = 6;
|
|||
|
CallHALaction( kSendMsgOut, &SIMg->halPB, SIMg);
|
|||
|
}
|
|||
|
else // no msg out phase - target async
|
|||
|
{
|
|||
|
SIMg->state = kSwitchingPhase;
|
|||
|
SIMg->syncRAoffset[ioPtr->scsiDevice.targetID] = 0; // asynchronous
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
else // something wrong with format of SDTR
|
|||
|
{
|
|||
|
SIMg->syncRAoffset[ioPtr->scsiDevice.targetID] = 0; // asynchronous
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
// extended message that we don't care about
|
|||
|
SIMg->state = kRejectingDataMsg;
|
|||
|
CallHALAssertATN( SIMg->HALinfo.HALstaticPtr);
|
|||
|
CallHALaction( kAcceptMsg, &SIMg->halPB, SIMg);
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
SIMg->state = kRejectingDataMsg;
|
|||
|
assertATN = true;
|
|||
|
}
|
|||
|
|
|||
|
if (!assertATN)
|
|||
|
{
|
|||
|
CallHALaction( kAcceptMsg, &SIMg->halPB, SIMg);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
CallHALAssertATN( SIMg->HALinfo.HALstaticPtr);
|
|||
|
CallHALaction( kAcceptMsg, &SIMg->halPB, SIMg);
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case kStatusPhase:
|
|||
|
|
|||
|
SIMg->state = kGettingStatus;
|
|||
|
CallHALaction( kStatus, &SIMg->halPB, SIMg);
|
|||
|
break;
|
|||
|
|
|||
|
case kMessageOutPhase: // we should only be here because we (or c96) asserted ATN
|
|||
|
|
|||
|
if( !ioPtr->pendingMsgPB ) {
|
|||
|
if( ioPtr->ioEvent & kmBadParity ) { // did c96 assert ATN for parity error?
|
|||
|
SIMg->halPB.msg[0] = kInitiatorDetectedErrorMsg;
|
|||
|
SIMg->state = kSendingDetectedErrorMsg;
|
|||
|
}
|
|||
|
else
|
|||
|
SIMg->halPB.msg[0] = kNoOperationMsg; // NOP since we don't know what is going on!
|
|||
|
}
|
|||
|
else {
|
|||
|
SIMg->state = kSendingKillMsg;
|
|||
|
|
|||
|
switch( ((SCSI_PB *)(ioPtr->pendingMsgPB))->scsiFunctionCode) { // <SM7>
|
|||
|
|
|||
|
case SCSITerminateIO:
|
|||
|
SIMg->halPB.msg[0] = kTerminateIOProcessMsg;
|
|||
|
break;
|
|||
|
case SCSIAbortCommand:
|
|||
|
SIMg->halPB.msg[0] = kAbortMsg;
|
|||
|
break;
|
|||
|
case SCSIResetDevice:
|
|||
|
SIMg->halPB.msg[0] = kBusDeviceResetMsg;
|
|||
|
break;
|
|||
|
} // <SM7>
|
|||
|
}
|
|||
|
SIMg->halPB.msgOutLen = 1;
|
|||
|
|
|||
|
CallHALaction( kSendMsgOut, &SIMg->halPB, SIMg);
|
|||
|
break;
|
|||
|
|
|||
|
case kCommandPhase:
|
|||
|
|
|||
|
ioPtr->scsiResult = scsiSequenceFailed;
|
|||
|
SIMg->state = kWastingPhase;
|
|||
|
CallHALaction( kBitBucket, &SIMg->halPB, SIMg);
|
|||
|
break;
|
|||
|
|
|||
|
case kBusFreePhase:
|
|||
|
|
|||
|
/* Note that this section no longer calls FreeMachine and StartMachine!
|
|||
|
BusFreePhase during a Switch Phase is an error or the result of an abort
|
|||
|
type message only! We shouldn't get here during a normal IO <SM3>
|
|||
|
*/
|
|||
|
SIMg->state = kWentBusFree;
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
|
|||
|
IfDebugStr("\pUnknown phase in SwitchPhase");
|
|||
|
SysError( dsIOCoreErr);
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|