401 lines
9.6 KiB
C
401 lines
9.6 KiB
C
|
/* Copyright (C) 1991, 1992 by Always Technology Corporation.
|
||
|
This module contains information proprietary to
|
||
|
Always Technology Corporation, and is be treated as confidential.
|
||
|
|
||
|
*/
|
||
|
|
||
|
#include "environ.h"
|
||
|
#include "rqm.h"
|
||
|
#include "api.h"
|
||
|
#include "apiscsi.h"
|
||
|
#include "debug.h"
|
||
|
|
||
|
/*
|
||
|
This function is called by the adapter/chip interrupt service routine
|
||
|
to handle going to SCSI bus free. This means that the bus has gone
|
||
|
to the free state, and the adpter is ready to start a new request.
|
||
|
*/
|
||
|
|
||
|
|
||
|
/* Called from interrupt context */
|
||
|
void
|
||
|
BusFree (ADAPTER_PTR HA, int StartLevel)
|
||
|
{
|
||
|
|
||
|
HA->State.Busy = HA->State.DataIn = HA->State.DoingSync = FALSE;
|
||
|
HA->CurrDev = NILL;
|
||
|
HA->CurrReq = NILL;
|
||
|
HA->ReqCurrentCount = 0;
|
||
|
HA->ReqCurrentIndex = 0;
|
||
|
HA->Service(HA_LED, HA, (long)0);
|
||
|
StartNext(HA, StartLevel); /* Called from interrupt, so level = 2 */
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
This functions is called by the adapter drivers when the detect a
|
||
|
bus reset. All requests in the accepted queues of the devices
|
||
|
attached to this adapter will be completed with a HAS_BADPHASE error
|
||
|
|
||
|
Called from interrupt context
|
||
|
*/
|
||
|
|
||
|
void
|
||
|
SCSIBusHasReset (ADAPTER_PTR HA)
|
||
|
{
|
||
|
|
||
|
BlowAwayRequests(HA, ACTIVE_REQUESTS, S_AD_RESET);
|
||
|
APINotifyReset(HA);
|
||
|
BusFree(HA, 2);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
int
|
||
|
SCSISendAbort (ADAPTER_PTR HA)
|
||
|
{
|
||
|
|
||
|
HA->Ext->MO_Buff[0] = MSG_ABORT;
|
||
|
HA->Ext->MO_Index = 0;
|
||
|
HA->Ext->MO_Count = 1;
|
||
|
TRACE(0,("SCSISendAbort(): Abort message requested\n"));
|
||
|
return MI_SEND_MSG; /* Tell driver we have a message to send */
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
int
|
||
|
SCSISendReject (ADAPTER_PTR HA)
|
||
|
{
|
||
|
|
||
|
HA->Ext->MO_Buff[0] = MSG_REJECT;
|
||
|
HA->Ext->MO_Index = 0;
|
||
|
HA->Ext->MO_Count = 1;
|
||
|
TRACE(0, ("SCSISendReject(): Reject message requested\n"));
|
||
|
return MI_SEND_MSG; /* Tell driver we have a message to send */
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
LOCAL void REGPARMS
|
||
|
SCSIAskSyncMsg (ADAPTER_PTR HA, BOOLEAN Initiate)
|
||
|
{
|
||
|
U8 ALLOC_D *Buff = &HA->Ext->MO_Buff[HA->Ext->MO_Count];
|
||
|
|
||
|
*Buff++ = MSG_EXTD_MSG;
|
||
|
*Buff++ = 3;
|
||
|
*Buff++ = XMSG_SYNC_REQ;
|
||
|
|
||
|
*Buff++ = HA->Sync_Period;
|
||
|
*Buff = HA->Sync_Offset;
|
||
|
|
||
|
HA->Ext->MO_Count += 5;
|
||
|
HA->Ext->MO_Index = 0;
|
||
|
HA->State.DoingSync = Initiate;
|
||
|
HA->DevInfo[ReqTargetID(HA->CurrReq)].Flags.UseSync = 0;
|
||
|
TRACE(3,("SCSIAskSyncMsg(): Sync. request message created: %d/%d\n",
|
||
|
HA->Sync_Period, HA->Sync_Offset));
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
SCSIMakeIdentify (ADAPTER_PTR HA, unsigned LUN, BOOLEAN AllowDisc)
|
||
|
{
|
||
|
|
||
|
HA->Ext->MO_Buff[0] = MSG_IDENTIFY | LUN | (AllowDisc ? MSG_ALLOW_DISC : 0);
|
||
|
HA->Ext->MO_Index = 0;
|
||
|
HA->Ext->MO_Count = 1;
|
||
|
TRACE(3,("SCSIMakeIDentify(): Identify message (%02x) requested\n",
|
||
|
(unsigned)HA->Ext->MO_Buff[0]));
|
||
|
|
||
|
if (ReqState(HA->CurrReq).ReqType == RTSyncNegReq) { // Allow sync. xfers on this device?
|
||
|
|
||
|
SCSIAskSyncMsg(HA, TRUE); // Then build sync. message
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
LOCAL U32
|
||
|
S32toU32 (U8 *b)
|
||
|
{
|
||
|
|
||
|
#if defined(NATIVE32)
|
||
|
|
||
|
return ( ((((U32)(b[0]) * 256) + (U32)(b[1])) * 256)
|
||
|
+ (U32)(b[2])) * 256 + (U32)(b[3]);
|
||
|
|
||
|
#else
|
||
|
struct {
|
||
|
U32 l;
|
||
|
U8 b[4];
|
||
|
} X32;
|
||
|
|
||
|
X32.b[0] = b[3];
|
||
|
X32.b[1] = b[2];
|
||
|
X32.b[2] = b[1];
|
||
|
X32.b[3] = b[0];
|
||
|
return X32.l;
|
||
|
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
LOCAL int
|
||
|
ExtdMessage(ADAPTER_PTR HA)
|
||
|
{
|
||
|
I32 Offset;
|
||
|
unsigned char Resp = MSG_NOP;
|
||
|
|
||
|
TRACE(4,("Inerpret_MSG: Extended message\n"));
|
||
|
switch (HA->Ext->MI_Buff[2]) { /* Extened message code; length is in [1] */
|
||
|
|
||
|
case XMSG_MODIFY_PTR: /* Got a Modify data pointers request */
|
||
|
|
||
|
TRACE(0,("Interpret_MSG(): The rarely seen Modify Data Ptr message received\n"));
|
||
|
/* Make sure the length of the message is correct and that the signed offset is in range: */
|
||
|
if (HA->Ext->MI_Buff[1] != 5)
|
||
|
return SCSISendReject(HA);
|
||
|
|
||
|
Offset = S32toU32(&(HA->Ext->MI_Buff[3]));
|
||
|
|
||
|
// If the offset is less than zero (going to back up), then see if that
|
||
|
// would make index (the number of bytes xfered so far) less than 0;
|
||
|
// If offset > 0, then check to see if is greater than the number of
|
||
|
// bytes remaining:
|
||
|
|
||
|
if (Offset < 0) {
|
||
|
|
||
|
if (((U32)-Offset) > HA->ReqCurrentIndex)
|
||
|
return SCSISendReject(HA);
|
||
|
|
||
|
} else {
|
||
|
|
||
|
if ((U32)Offset > HA->ReqCurrentCount)
|
||
|
return SCSISendReject(HA);
|
||
|
|
||
|
}
|
||
|
|
||
|
HA->ReqCurrentIndex += Offset;
|
||
|
HA->ReqCurrentCount -= Offset;
|
||
|
Resp = MSG_NOP;
|
||
|
break;
|
||
|
|
||
|
|
||
|
case XMSG_SYNC_REQ:
|
||
|
|
||
|
/* Sync negotiaition request; may be a response to our request */
|
||
|
TRACE(4,("Interpret_MSG: sync. negotiation\n"));
|
||
|
if ((HA->Ext->MI_Buff[1] != 3) || !HA->Supports.Synchronous)
|
||
|
return SCSISendReject(HA);
|
||
|
|
||
|
HA->DevInfo[ReqTargetID(HA->CurrReq)].Flags.NeedSync = FALSE;
|
||
|
|
||
|
if (HA->State.DoingSync) { /* Did we initiate sync. neg? */
|
||
|
|
||
|
TRACE(4,(" Response to host initiated negotiation\n"));
|
||
|
HA->State.DoingSync = FALSE; /* then we are done */
|
||
|
Resp = MI_SYNC_RESP; /* We got a sync response */
|
||
|
|
||
|
} else { /* Else, respond */
|
||
|
|
||
|
TRACE(4,("Target initiated negotiation\n"));
|
||
|
SCSIAskSyncMsg(HA, FALSE); /* Request sync. negotiation be done */
|
||
|
|
||
|
/* use the values most suited for the adapter and target: */
|
||
|
if (HA->Sync_Period < HA->Ext->MI_Buff[3])
|
||
|
HA->Ext->MO_Buff[3] = HA->Ext->MI_Buff[3];
|
||
|
|
||
|
if (HA->Sync_Offset > HA->Ext->MI_Buff[4])
|
||
|
HA->Ext->MO_Buff[4] = HA->Ext->MI_Buff[4];
|
||
|
Resp = MI_SYNC_REQ; /* We got a sync req; so send resp */
|
||
|
|
||
|
}
|
||
|
|
||
|
HA->CurrDev->Sync_Period = HA->Ext->MI_Buff[3];
|
||
|
HA->CurrDev->Sync_Offset = HA->Ext->MI_Buff[4];
|
||
|
HA->DevInfo[ReqTargetID(HA->CurrReq)].Flags.UseSync = TRUE;
|
||
|
if (HA->Ext->MI_Buff[4] == 0) {
|
||
|
|
||
|
/* no sync. support; clear allowed flag; no handling of msg needed */
|
||
|
HA->DevInfo[ReqTargetID(HA->CurrReq)].Flags.AllowSync = FALSE;
|
||
|
HA->DevInfo[ReqTargetID(HA->CurrReq)].Flags.UseSync = FALSE;
|
||
|
Resp = MSG_NOP;
|
||
|
|
||
|
}
|
||
|
|
||
|
TRACE(4,("Using sync period of: %d and offset of: %d\n", (unsigned)HA->Ext->MI_Buff[3], (unsigned)HA->Ext->MI_Buff[4]));
|
||
|
|
||
|
}
|
||
|
return Resp;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
Interpret_MSG (ADAPTER_PTR HA)
|
||
|
{
|
||
|
unsigned char Resp = HA->Ext->MI_Buff[0];
|
||
|
|
||
|
HA->Ext->MI_Count = HA->Ext->MI_Needed = 0; /* Reset for next time */
|
||
|
TRACE(3,("Interpret_MSG: 1st Message byte: %02x\n", HA->Ext->MI_Buff[0]));
|
||
|
|
||
|
if (HA->Ext->MI_Buff[0] & 0x80) /* Identify message? */
|
||
|
return 0x80; // Return identify code
|
||
|
|
||
|
switch (HA->Ext->MI_Buff[0]) {
|
||
|
|
||
|
case MSG_SAVE_PTR:
|
||
|
|
||
|
TRACE(5, ("Interpret_MSG(): Save Data Ptr, Saved index=%d\n", HA->ReqCurrentIndex));
|
||
|
ReqSavedIndex(HA->CurrReq) = HA->ReqCurrentIndex;
|
||
|
break;
|
||
|
|
||
|
|
||
|
case MSG_RESTORE_PTR:
|
||
|
|
||
|
HA->ReqCurrentIndex = ReqSavedIndex(HA->CurrReq);
|
||
|
HA->ReqCurrentCount = 0;
|
||
|
TRACE(5, ("Interpret_MSG(): Restore Data Ptr, Saved index=%d\n", HA->ReqCurrentIndex));
|
||
|
break;
|
||
|
|
||
|
|
||
|
case MSG_DISCONNECT:
|
||
|
|
||
|
ReqState(HA->CurrReq).ReselPending = TRUE;
|
||
|
ReqState(HA->CurrReq).Connected = FALSE;
|
||
|
HA->CurrReq = 0;
|
||
|
break;
|
||
|
|
||
|
|
||
|
case MSG_REJECT:
|
||
|
|
||
|
HA->Ext->MO_Count = HA->Ext->MO_Index = 0; /* Clear message out indicators */
|
||
|
if (HA->State.DoingSync) {
|
||
|
|
||
|
TRACE(2,("Synchronous negotiation rejected by target\n"));
|
||
|
HA->DevInfo[ReqTargetID(HA->CurrReq)].Flags.NeedSync = 0;
|
||
|
HA->DevInfo[ReqTargetID(HA->CurrReq)].Flags.AllowSync = 0;
|
||
|
HA->DevInfo[ReqTargetID(HA->CurrReq)].Flags.UseSync = 0;
|
||
|
HA->State.DoingSync = 0;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
// See if the reject is in response to an Identify with LUN:
|
||
|
if ((HA->Ext->MO_Buff[0] & 0x80) && (HA->Ext->MO_Buff[0] & 7))
|
||
|
ReqAPIStatus(HA->CurrReq) = S_REQ_BADLUN;
|
||
|
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
|
||
|
case MSG_EXTD_MSG:
|
||
|
|
||
|
Resp = ExtdMessage(HA);
|
||
|
break;
|
||
|
|
||
|
|
||
|
case MSG_COMPLETE:
|
||
|
case MSG_NOP:
|
||
|
|
||
|
break;
|
||
|
|
||
|
|
||
|
default:
|
||
|
|
||
|
TRACE(0, ("Interpret_MSG(): Unknown message: 0x%02x %02x %02x %02x\n", HA->Ext->MI_Buff[0], HA->Ext->MI_Buff[1], HA->Ext->MI_Buff[2], HA->Ext->MI_Buff[3]));
|
||
|
Resp = SCSISendReject(HA);
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
return Resp;
|
||
|
}
|
||
|
|
||
|
|
||
|
LOCAL unsigned
|
||
|
NewMessage (ADAPTER_PTR HA, unsigned char Msg)
|
||
|
{
|
||
|
|
||
|
TRACE(4,("NewMessage(): %02x\n", Msg));
|
||
|
switch (Msg) {
|
||
|
|
||
|
case MSG_EXTD_MSG:
|
||
|
|
||
|
HA->Ext->MI_Count = -1; /* Special flag for first byte of extd. msg */
|
||
|
HA->Ext->MI_Needed = -1;
|
||
|
return MI_MORE;
|
||
|
|
||
|
|
||
|
default:
|
||
|
|
||
|
if ((Msg & 0xf0) == 0x20) { /* Two byte messages */
|
||
|
|
||
|
HA->Ext->MI_Buff[0] = Msg;
|
||
|
HA->Ext->MI_Count = 1;
|
||
|
HA->Ext->MI_Needed = 1; /* One more byte needed */
|
||
|
return MI_MORE;
|
||
|
|
||
|
} else
|
||
|
Msg = Interpret_MSG(HA);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
return Msg;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* Called from interrupt context */
|
||
|
int
|
||
|
Receive_Msg (ADAPTER_PTR HA, unsigned char Msg)
|
||
|
{
|
||
|
unsigned char NM;
|
||
|
|
||
|
TRACE(4,("Receive_Msg(): MI_Count = %d, Needed = %d\n", HA->Ext->MI_Count, HA->Ext->MI_Needed));
|
||
|
switch (HA->Ext->MI_Count) {
|
||
|
|
||
|
case 0: /* New first message byte */
|
||
|
|
||
|
HA->Ext->MI_Buff[0] = Msg;
|
||
|
NM = NewMessage(HA, Msg);
|
||
|
TRACE(5,("Receive_Msg(): NewMessage says: 0x%02x\n", NM));
|
||
|
return NM;
|
||
|
|
||
|
|
||
|
case -1: /* Second byte (length) of extended message */
|
||
|
|
||
|
TRACE(4,("Receive_Msg(): Extd msg length = %d\n", Msg));
|
||
|
if (Msg == 0) {
|
||
|
|
||
|
HA->Ext->MI_Needed = 0;
|
||
|
HA->Ext->MI_Buff[1] = 0;
|
||
|
HA->Ext->MI_Count = 0;
|
||
|
return SCSISendReject(HA);
|
||
|
|
||
|
}
|
||
|
HA->Ext->MI_Needed = Msg;
|
||
|
HA->Ext->MI_Buff[1] = Msg;
|
||
|
HA->Ext->MI_Count = 2;
|
||
|
return MI_MORE;
|
||
|
|
||
|
|
||
|
default: /* Subsequent bytes of multi-byte message */
|
||
|
|
||
|
HA->Ext->MI_Buff[HA->Ext->MI_Count++] = Msg;
|
||
|
if (--(HA->Ext->MI_Needed) == 0)
|
||
|
return Interpret_MSG(HA);
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
return MI_MORE;
|
||
|
}
|