MODULE Adaptec7;
IMPORT
SYSTEM, KernelLog, PCI, Machine, Kernel, Objects, Modules,
SCSI, Script := Adaptec7Script;
CONST
traceCalls = 0;
traceInts = 1;
traceMsg = 2;
traceSequencer = 4;
traceReset = 5;
traceConfig = 6;
tracePeriod = 7;
traceCmds = 8;
traceSeeprom = 9;
traceTermination = 10;
traceSmall = 16;
traceAIC7880 = 17;
traceAIC7890 = 18;
traceAHA2940 = 19;
traceNoHandling = 20;
traceNoRegister = 22;
traceSync = 23;
QBufferSize = 3 * 256;
SCBBufferSize = 128*32;
BufferAlignment = 32;
Sending = 0; Receiving = 1;
Free = 0; InUse = 1; Terminated = 2;
AIC7770 = 1; AIC7850 = 2; AIC7860 = 3; AIC7870 = 4; AIC7880 = 5; AIC7890 = 6;
AIC7895 = 7; AIC7896 = 8;
FeatUltra = 1; FeatUltra2 = 2; FeatWide = 3; FeatTwin = 4; FeatMoreSRAM = 5; FeatCmdChan = 6;
FeatQueueRegs = 7; FeatSGPreload = 8; FeatSpioCap = 9;
FlagPageSCB = 1; FlagNewEepromFMT = 2; FlagBiosEnabled = 3; FlagMultiChannel = 4; FlagChnlB = 5; FlagChnlC = 6;
FlagSeepromFound = 7; FlagChannelBPrimary = 8; FlagExtendTransA = 9; FlagExternalSRam = 10; FlagAbortPending = 11;
FlagHandlingReqInits = 12;
HwScbTypeMask = 03X; HwScbMsgMask = 0F6X;
HwScbDisconnected = 3; HwScbDiscEnable = 6; HwScbMessage = 7;
SCSISEQ = 00H;
SCSIRSTO = 0;
ENAUTOATNP = 1;
ENRSELI = 4;
ENSELI = 5;
ENSELO = 6;
SXFRCTL0 = 01H;
SPIOEN = 3;
FAST20 = 5;
DFON = 7;
SXFRCTL1 = 02H;
STPWEN = 0;
ACTNEGEN = 1;
ENSTIMER = 2;
ENSPCHK = 5;
SCSISIG = 03H;
ACK = 0;
REQ = 1;
BSY = 2;
SEL = 3;
ATN = 4;
MSG = 5;
IO = 6;
CD = 7;
SCSIRATE = 04H;
WIDEXFER = 7;
SCSIID = 05H;
SCSIOFFSET = 05H;
SCSIDATL = 06H;
SSTAT0 = 0BH;
CLRSINT0 = 0BH;
CLRSPIORDY = 1;
CLRSWRAP = 3;
CLRSELINGO = 4;
CLRSELDI = 5;
CLRSELDO = 6;
SSTAT1 = 0CH;
REQINIT = 0;
SCSIPERR = 2;
BUSFREE = 3;
SCSIRSTI = 5;
SELTO = 7;
CLRSINT1 = 0CH;
CLRREQINIT = 0;
CLRPHASECHG = 1;
CLRSCSIPERR = 2;
CLRBUSFREE = 3;
CLRSCSIRSTI = 5;
CLRATNO = 6;
CLRSELTIMEO = 7;
CLRSINT1ALL = {0..3, 5..7};
SSTAT2 = 0DH;
EXPACTIVE = 4;
SSTAT3 = 0EH;
SCSIIDULTRA2 = 0FH;
SIMODE0 = 10H;
SIMODE1 = 11H;
ENREQINIT = 0;
ENSCSIPERR = 2;
ENBUSFREE = 3;
ENSCSIRST = 5;
ENSELTIMO = 7;
SCSIBUSL = 12H;
SPIOCAP = 1BH;
SSPIOCPS = 0;
BRDCTL = 1DH;
BRDSTBULTRA2 = 0;
BRDRWULTRA2 = 1;
BRDRW = 2;
BRDCS = 3;
BRDSTB = 4;
SEECTL = 1EH;
SEEDI = 0;
SEEDO = 1;
SEECK = 2;
SEECS = 3;
SEERDY = 4;
SEEMS = 5;
SBLKCTL = 1FH;
SELWIDE = 1;
SELBUSB = 3;
ENAB40 = 3;
AUTOFLUSHDIS = 5;
DIAGLEDON = 6;
DIAGLEDEN =7;
TARGSCSIRATE = 20H;
ULTRAENB = 30H;
DISCDSB = 32H;
MSGOUT = 34H;
DMAPARAMS = 35H;
SEQFLAGS = 36H;
SAVEDTCL = 37H;
LASTPHASE = 3DH;
PHASEMASK = {CD, MSG, IO};
PhaseStatus = {CD, IO};
PhaseCommand = {CD};
PhaseMsgOut = {CD, MSG};
PhaseMsgIn = {CD, MSG, IO};
PhaseDataIn = {IO};
PhaseDataOut = {};
PhaseBusFree = {0};
WAITINGSCBH = 3EH;
DISCONNECTEDSCBH = 3FH;
FREESCBH = 40H;
HSCBARRAY = 41H;
SCBIDADDR = 45H;
TMODECMDADDR = 49H;
KERNELQINPOS = 4DH;
QINPOS = 4EH;
QOUTPOS = 4FH;
TMODECMDADDRNEXT = 50H;
RETURN1 = 51H;
MSGOUTPHASEMIS = {4};
SENDSENSE = {6};
SENDMSG = {7};
LASTMSG = 53H;
SCSICONF = 5AH;
RESETSCSI = 6;
TERMENB = 7;
SEQCTL = 60H;
LOADRAM = 0;
SEQRESET = 1;
FASTMODE = 4;
FAILDIS = 5;
PERRORDIS = 7;
SEQRAM = 61H;
SEQADDR0 = 62H;
SEQADDR1 = 63H;
SINDEX = 65H;
TARGOFFSET = 70H;
BCTL = 84H;
ENABLE = 0;
DSCOMMAND0 = 84H;
CIOPARCKEN = 0;
USCBSIZE32 = 1;
MPARCKEN = 5;
DPARCKEN = 6;
CACHETHEN = 7;
DSPCISTATUS = 86H;
DFTHRSH100 = {6, 7};
HCNTRL = 87H;
CHIPRST = 0;
INTEN = 1;
PAUSE = 2;
SCBPTR = 90H;
INTSTAT = 91H;
SEQINT = 0H;
CMDCMPLT = 1H;
SCSIINT = 2H;
BRKADRINT = 3H;
SEQINTMASK = {0, 4..7};
DataOverrun = 0EH; MsgInPhaseMis = 0DH; TracePoint2 = 0CH;
TracePoint = 0BH; AwaitingMsg = 0AH; Residual = 08H;
BadStatus = 07H; RejectMsg = 06H; AbortRequested = 05H;
ExtendedMsg = 04H; NoMatch = 03H; NoIdent = 02H;
SendReject = 01H; BadPhase = 00H;
CLRINT = 92H;
CLRSEQINT = 0;
CLRCMDINT = 1;
CLRSCSIINT = 2;
CLRBRKADRINT = 3;
CLRPARERR = 4;
ERROR = 92H;
ILLHADDR = 0;
ILLSADDR = 1;
ILLOPCODE = 2;
SQPARERR = 3;
PCIERRSTAT = 6;
DFSTATUS = 94H;
SCBCONTROL = 0A0H;
DISCONNECTED = 3;
DISCENB = 6;
SCBTCL = 0A1H;
SCBTARGETSTATUS = 0A2H;
SCBSGCOUNT = 0A3H;
SCBSGPTR = 0A4H;
SCBRESIDSGCNT = 0A8H;
SCBRESIDDCNT = 0A9H;
SCBDATAPTR = 0ACH;
SCBDATACNT = 0B0H;
SCBCMDPTR = 0B4H;
SCBCMDLEN = 0B8H;
SCBTAG = 0B9H;
SCBNEXT = 0BAH;
SCBPREV = 0BBH;
SCBBUSYTARGETS = 0BCH;
CCSCBBADDR = 0F0H;
HNSCBQOFF = 0F4H;
SNSCBQOFF = 0F6H;
SDSCBQOFF = 0F8H;
QOFFCTLSTA = 0FAH;
SCBQSIZE256 = {1, 2};
DFFTHRSH = 0FBH;
WRDFFTHRSH75 = {6};
RDDFFTHRSH75 = {2};
DEVCONFIG = 40H;
RAMPSMULTRA2 = 2;
BERREN = 3;
SCBRAMSELULTRA2 = 3;
EXTSCBPEN = 4;
SCBRAMSEL = 7;
RAMPSM = 9;
SCBSIZE32 = 16;
PCIERRGENDIS = 31;
SCAMCTL = 1AH;
HScontrol = 0;
HStarget = 1;
HSstatus = 2;
HSSGcount = 3;
HSSGptr = 4;
HSresSGcnt = 8;
HSresDataCnt = 9;
HSdataPtr = 12;
HSdataCnt = 16;
HScmdPtr = 20;
HScmdLen = 24;
HStag = 25;
HSnext = 26;
HSprev = 27;
HSpar = 28;
TYPE
Interrupt = OBJECT
VAR
root: Bus; int: LONGINT;
PROCEDURE HandleInterrupt;
VAR int, err: SET; d: Bus;
BEGIN
INC(aIntCount);
d := root;
WHILE d # NIL DO
int := SYSTEM.VAL(SET, d.Get1(d, INTSTAT));
err := SYSTEM.VAL(SET, d.Get1(d, ERROR));
IF d.interruptable & ((int # {}) OR (err # {})) THEN
IF traceSmall IN trace THEN KernelLog.Char("<") END;
IF CMDCMPLT IN int THEN
IF traceSmall IN trace THEN KernelLog.Char("C") END;
IntCommand(d)
END;
IF (BRKADRINT IN int) OR (err # {}) THEN
IF traceSmall IN trace THEN KernelLog.Char("B") END;
IntBrkAdr(d)
END;
IF SEQINT IN int THEN
IF traceSmall IN trace THEN KernelLog.Char("S") END;
IntSeqHandle(d, SYSTEM.LSH(SYSTEM.VAL(LONGINT, int), -4))
END;
IF SCSIINT IN int THEN
IF traceSmall IN trace THEN KernelLog.Char("s") END;
IntScsiHandle(d)
END;
IF traceSmall IN trace THEN KernelLog.Char(">") END;
END;
d := d.next
END
END HandleInterrupt;
PROCEDURE Cleanup;
BEGIN
Objects.RemoveHandler(SELF.HandleInterrupt, int)
END Cleanup;
PROCEDURE & Init*(irq: LONGINT);
BEGIN
int := Machine.IRQ0 + irq;
Objects.InstallHandler(SELF.HandleInterrupt, int)
END Init;
END Interrupt;
Message = RECORD
buf: ARRAY 6 OF CHAR;
pos, len, dir: SHORTINT;
END;
Bus = OBJECT (SCSI.Bus)
VAR
flags, features: SET;
chip: SHORTINT;
interruptable: BOOLEAN;
irq: SHORTINT;
scsiId: SHORTINT;
sync: ARRAY 16 OF SHORTINT;
busNo, devNo, slotNo: LONGINT;
buffers: ARRAY (QBufferSize + SCBBufferSize + BufferAlignment) OF CHAR;
scbArea: LONGINT;
queueArea: LONGINT;
in, out: LONGINT;
base: SYSTEM.ADDRESS;
Put1: PROCEDURE (d: Bus; offset: LONGINT; val: CHAR);
Get1: PROCEDURE (d: Bus; offset: LONGINT): CHAR;
width: SHORTINT;
negotiateWidth: SET;
negotiateSync: SET;
msg: Message;
result, status: ARRAY 16 OF SHORTINT;
next: Bus;
PROCEDURE Synchronize(dev: LONGINT; await, set: SHORTINT);
PROCEDURE Data;
BEGIN
KernelLog.String("Sync ["); KernelLog.Int(dev, 0); KernelLog.String("] ");
KernelLog.Int(await, 0); KernelLog.String(" -> "); KernelLog.Int(set, 0)
END Data;
BEGIN {EXCLUSIVE}
IF traceSync IN trace THEN BusNameMsg(SELF, " ->"); Data; KernelLog.Ln; END;
AWAIT(sync[dev] = await);
IF traceSync IN trace THEN BusNameMsg(SELF, " <-"); Data; KernelLog.Ln END;
sync[dev] := set
END Synchronize;
PROCEDURE Submit*(VAR c: SCSI.Command);
BEGIN
Synchronize(c.target, Free, InUse);
BusSchedule(SELF, c);
c.result := result[c.target];
c.status := status[c.target];
Synchronize(c.target, Terminated, Free);
END Submit;
PROCEDURE & Init*(id, bus, dev, slot: LONGINT);
BEGIN
flags := card[id].flags;
features := card[id].features;
chip := card[id].chip;
interruptable := FALSE;
COPY(card[id].name, fullname);
busNo := bus; devNo := dev; slotNo := slot;
IF firstBus = NIL THEN firstBus := SELF END;
END Init;
END Bus;
RateTableDesc = RECORD
period: SHORTINT;
rate: CHAR;
u2rate: CHAR;
speed: LONGINT;
END;
CardTable = RECORD
signature: LONGINT;
chip: SHORTINT;
flags, features: SET;
name: ARRAY 32 OF CHAR;
END;
VAR
timer: Kernel.Timer;
interrupt: ARRAY 32 OF Interrupt;
card: ARRAY 19 OF CardTable;
rateTable: ARRAY 13 OF RateTableDesc;
firstBus: Bus;
trace: SET;
aExecute,
aIntScsiSeltoProblem1, aIntScsiSeltoProblem2,
aIntScsiReset, aIntScsiSelto, aIntScsiBusFree, aIntScsiParity, aIntScsiReqInit, aIntScsiSpecial, aIntScsiUnknown,
aIntSeqNoMatch, aIntSeqSendReject, aIntSeqNoIdent, aIntSeqBadPhase, aIntSeqExtendedMsg,
aIntSeqRejectMsg, aIntSeqBadStatus, aIntSeqAwaitingMsg, aIntSeqDataOverrun,
aIntCount, aIntCmdCount, aIntBrkAdrCount, aIntSeqCount, aIntScsiCount: LONGINT;
PROCEDURE ToDo(desc: ARRAY OF CHAR);
BEGIN
KernelLog.Enter;
KernelLog.String(desc); KernelLog.String(" not implemented yet");
KernelLog.Exit
END ToDo;
PROCEDURE BusName(b: Bus);
BEGIN
KernelLog.Char("["); KernelLog.Hex(b.busNo, -2);
KernelLog.Char("/"); KernelLog.Hex(b.devNo, -2);
KernelLog.Char("/"); KernelLog.Hex(b.slotNo, -2); KernelLog.String("] ");
END BusName;
PROCEDURE BusNameMsg(b: Bus; str: ARRAY OF CHAR);
BEGIN
KernelLog.Char("["); KernelLog.Hex(b.busNo, -2);
KernelLog.Char("/"); KernelLog.Hex(b.devNo, -2);
KernelLog.Char("/"); KernelLog.Hex(b.slotNo, -2); KernelLog.String("] ");
KernelLog.String(str)
END BusNameMsg;
PROCEDURE Reg(d: Bus; off: LONGINT; name: ARRAY OF CHAR);
BEGIN
KernelLog.String(name); KernelLog.Hex(ORD(d.Get1(d, off)), -2)
END Reg;
PROCEDURE DumpCurSCB(d: Bus);
BEGIN
Reg(d, SCBPTR, "CurSCB = ");
Reg(d, SCBCONTROL, " Ctrl = ");
Reg(d, SCBTCL, " Targ = ");
Reg(d, SCBTAG, " Tag = ");
Reg(d, SCBPREV, " Prev = ");
Reg(d, SCBNEXT, " Next = ");
KernelLog.Ln;
END DumpCurSCB;
PROCEDURE DumpBusList(d: Bus; list: LONGINT; name: ARRAY OF CHAR);
VAR ch, save: CHAR;
BEGIN
BusName(d); KernelLog.String(name);
save := d.Get1(d, SCBPTR);
ch := d.Get1(d, list);
WHILE ch # 0FFX DO
KernelLog.String("->"); KernelLog.Hex(ORD(ch), -2);
d.Put1(d, SCBPTR, ch); ch := d.Get1(d, SCBNEXT);
END;
KernelLog.Ln;
d.Put1(d, SCBPTR, save);
END DumpBusList;
PROCEDURE DumpAllLists(d: Bus);
BEGIN
DumpBusList(d, FREESCBH, "Free");
DumpBusList(d, WAITINGSCBH, "Wait");
DumpBusList(d, DISCONNECTEDSCBH, "Disc");
END DumpAllLists;
PROCEDURE PortPut(d: Bus; offset: LONGINT; val: CHAR);
BEGIN
Machine.Portout8(d.base+offset, val)
END PortPut;
PROCEDURE PortGet(d: Bus; offset: LONGINT): CHAR;
VAR ch: CHAR;
BEGIN
Machine.Portin8(d.base+offset, ch); RETURN ch
END PortGet;
PROCEDURE MemoryPut(d: Bus; offset: LONGINT; val: CHAR);
BEGIN
SYSTEM.PUT(d.base+offset, val)
END MemoryPut;
PROCEDURE MemoryGet(d: Bus; offset: LONGINT): CHAR;
VAR ch: CHAR;
BEGIN
SYSTEM.GET(d.base+offset, ch); RETURN ch
END MemoryGet;
PROCEDURE MakeTarget(targ, chan, lun: LONGINT): CHAR;
BEGIN
RETURN CHR(SYSTEM.LSH(targ MOD 16, 4)+SYSTEM.LSH(chan MOD 2, 3)+lun MOD 8)
END MakeTarget;
PROCEDURE GetTableIndex(ultra, ultra2: BOOLEAN): LONGINT;
BEGIN
IF ultra2 THEN RETURN 0 ELSIF ultra THEN RETURN 2 ELSE RETURN 5 END
END GetTableIndex;
PROCEDURE GetMaxOffset(wide, ultra2: BOOLEAN): CHAR;
BEGIN
IF ultra2 THEN RETURN 7FX
ELSIF wide THEN RETURN 08X
ELSE RETURN 0FX
END
END GetMaxOffset;
PROCEDURE SetWidth(d: Bus; wide: BOOLEAN);
VAR index: LONGINT; rate: SET;
BEGIN
index := ORD(d.Get1(d, SCBTAG));
rate := SYSTEM.VAL(SET, d.Get1(d, TARGSCSIRATE + index));
IF wide THEN
INCL(rate, WIDEXFER)
ELSE
EXCL(rate, WIDEXFER)
END;
d.Put1(d, TARGSCSIRATE + index, SYSTEM.VAL(CHAR, rate));
d.Put1(d, SCSIRATE, SYSTEM.VAL(CHAR, rate));
BusNameMsg(d, "Device["); KernelLog.Int(index, 0); KernelLog.String("].width=");
KernelLog.Int(SYSTEM.VAL(SHORTINT, wide), 0); KernelLog.Ln
END SetWidth;
PROCEDURE SetSyncRate(d: Bus; period, offset: LONGINT);
VAR i, index, speed: LONGINT; ultra2, ultra, wide: BOOLEAN; ctrl0, rate: CHAR; set: SET;
BEGIN
ultra2 := FeatUltra2 IN d.features;
ultra := FeatUltra IN d.features;
index := ORD(d.Get1(d, SCBTAG));
i := GetTableIndex(ultra, ultra2);
WHILE (i < LEN(rateTable)) & (period > rateTable[i].period) DO INC(i) END;
IF i = LEN(rateTable) THEN
i := -1; offset := 0;
END;
rate := d.Get1(d, TARGSCSIRATE + index);
rate := SYSTEM.VAL(CHAR, SYSTEM.VAL(SET, rate) * {WIDEXFER});
wide := rate # 0X;
IF ultra2 THEN
IF i # -1 THEN rate := CHR(ORD(rate) + ORD(rateTable[i].u2rate)) END;
d.Put1(d, SCSIRATE, rate);
d.Put1(d, SCSIOFFSET, CHR(offset));
d.Put1(d, TARGSCSIRATE+index, rate);
d.Put1(d, TARGOFFSET+index, CHR(offset))
ELSE
IF i # -1 THEN
ASSERT(offset < 10H);
rate := CHR(ORD(rate) + ORD(rateTable[i].rate) + (offset MOD 10H));
ultra := i < 5
ELSE
ultra := FALSE
END;
d.Put1(d, SCSIRATE, rate);
d.Put1(d, TARGSCSIRATE + index, rate);
ctrl0 := d.Get1(d, SXFRCTL0);
set := SYSTEM.VAL(SET, d.Get1(d, ULTRAENB + index DIV 8));
IF ultra THEN
ctrl0 := SYSTEM.VAL(CHAR, SYSTEM.VAL(SET, ctrl0) + {FAST20});
INCL(set, index MOD 8)
ELSE
ctrl0 := SYSTEM.VAL(CHAR, SYSTEM.VAL(SET, ctrl0) - {FAST20});
EXCL(set, index MOD 8)
END;
d.Put1(d, SXFRCTL0, ctrl0);
d.Put1(d, ULTRAENB + index DIV 8, SYSTEM.VAL(CHAR, set))
END;
BusNameMsg(d, "Device["); KernelLog.Int(index, 0); KernelLog.String("].rate=");
IF i = -1 THEN
KernelLog.String("async")
ELSE
KernelLog.Int(rateTable[i].period, 0); KernelLog.Char("/"); KernelLog.Int(offset, 0);
speed := rateTable[i].speed;
IF wide THEN speed := speed*2 END;
KernelLog.Int(speed DIV 10, 4); KernelLog.Char("."); KernelLog.Int(speed MOD 10, 0);
KernelLog.String(" MB/s")
END;
KernelLog.Ln
END SetSyncRate;
PROCEDURE QUntaggedSet(d: Bus; i: LONGINT; ch: CHAR);
BEGIN
SYSTEM.PUT(d.queueArea+i, ch)
END QUntaggedSet;
PROCEDURE QOutSet(d: Bus; i: LONGINT; ch: CHAR);
BEGIN
SYSTEM.PUT(d.queueArea+100H+i, ch)
END QOutSet;
PROCEDURE QOutGet(d: Bus; i: LONGINT): CHAR;
VAR ch: CHAR;
BEGIN
SYSTEM.GET(d.queueArea+100H+i, ch); RETURN ch
END QOutGet;
PROCEDURE QInSet(d: Bus; i: LONGINT; ch: CHAR);
BEGIN
SYSTEM.PUT(d.queueArea+200H+i, ch)
END QInSet;
PROCEDURE QInit(d: Bus);
VAR paddr, i: LONGINT;
BEGIN
IF traceCalls IN trace THEN BusNameMsg(d, "QInit"); KernelLog.Ln END;
paddr := SYSTEM.ADR(d.buffers[0]);
INC(paddr, (-paddr) MOD BufferAlignment);
d.queueArea := paddr;
FOR i := 0 TO 255 DO
QUntaggedSet(d, i, 0FFX); QOutSet(d, i, 0FFX); QInSet(d, i, 0FFX)
END;
d.in := 0;
d.out := 0;
d.Put1(d, SCBIDADDR, CHR(paddr));
d.Put1(d, SCBIDADDR+1, CHR(SYSTEM.LSH(paddr, -8)));
d.Put1(d, SCBIDADDR+2, CHR(SYSTEM.LSH(paddr, -16)));
d.Put1(d, SCBIDADDR+3, CHR(SYSTEM.LSH(paddr, -24)));
d.Put1(d, QINPOS, 0X);
d.Put1(d, KERNELQINPOS, 0X);
d.Put1(d, QOUTPOS, 0X);
IF FeatQueueRegs IN d.features THEN
d.Put1(d, QOFFCTLSTA, 6X);
d.Put1(d, SDSCBQOFF, 0X);
d.Put1(d, SNSCBQOFF, 0X);
d.Put1(d, HNSCBQOFF, 0X)
END;
d.Put1(d, WAITINGSCBH, 0FFX);
d.Put1(d, DISCONNECTEDSCBH, 0FFX);
END QInit;
PROCEDURE HSSet(d: Bus; num, offset: LONGINT; val: CHAR);
BEGIN SYSTEM.PUT(d.scbArea + num*32 + offset, val)
END HSSet;
PROCEDURE HSSet4(d: Bus; num, offset: LONGINT; val: LONGINT);
BEGIN SYSTEM.PUT(d.scbArea + num*32 + offset, val)
END HSSet4;
PROCEDURE HSFreeCurrent(d: Bus);
BEGIN
d.Put1(d, SCBTAG, 0FFX);
d.Put1(d, SCBCONTROL, 0X);
d.Put1(d, SCBNEXT, d.Get1(d, FREESCBH));
d.Put1(d, FREESCBH, d.Get1(d, SCBPTR))
END HSFreeCurrent;
PROCEDURE HSFreeScb(d: Bus; index: LONGINT);
BEGIN
HSSet(d, index, HScontrol, 0X);
HSSet(d, index, HSstatus, 0X);
HSSet(d, index, HStarget, 0FFX)
END HSFreeScb;
PROCEDURE HSInit(d: Bus);
VAR paddr, i: LONGINT; quit: BOOLEAN;
BEGIN
IF traceCalls IN trace THEN BusNameMsg(d, "HSInit"); KernelLog.Ln END;
paddr := SYSTEM.ADR(d.buffers[QBufferSize]);
INC(paddr, (-paddr) MOD BufferAlignment);
d.scbArea := paddr;
FOR i := 0 TO 127 DO
SYSTEM.PUT(d.scbArea + i*32 + HScontrol, 0X);
SYSTEM.PUT(d.scbArea + i*32 + HStag, CHR(i));
END;
d.Put1(d, HSCBARRAY, CHR(paddr));
d.Put1(d, HSCBARRAY+1, CHR(SYSTEM.LSH(paddr, -8)));
d.Put1(d, HSCBARRAY+2, CHR(SYSTEM.LSH(paddr, -16)));
d.Put1(d, HSCBARRAY+3, CHR(SYSTEM.LSH(paddr, -24)));
d.Put1(d, FREESCBH, 0X);
i := 0; quit := FALSE;
WHILE (i < 255) & ~quit DO
d.Put1(d, SCBPTR, CHR(i));
d.Put1(d, SCBCONTROL, CHR(i));
IF i # ORD(d.Get1(d, SCBCONTROL)) THEN
quit := TRUE
ELSE
d.Put1(d, SCBPTR, 0X);
IF d.Get1(d, SCBCONTROL) # 0X THEN
quit := TRUE
ELSE
d.Put1(d, SCBPTR, CHR(i));
d.Put1(d, SCBCONTROL, 0X);
d.Put1(d, SCBNEXT, CHR(i+1));
d.Put1(d, SCBPREV, CHR(i-1));
d.Put1(d, SCBTAG, 0FFX);
d.Put1(d, SCBBUSYTARGETS, 0FFX);
d.Put1(d, SCBBUSYTARGETS+1, 0FFX);
d.Put1(d, SCBBUSYTARGETS+2, 0FFX);
d.Put1(d, SCBBUSYTARGETS+3, 0FFX);
INC(i)
END
END
END;
d.Put1(d, SCBPTR, CHR(i-1));
d.Put1(d, SCBNEXT, 0FFX);
d.Put1(d, SCBPTR, 0X);
d.Put1(d, SCBCONTROL, 0X);
IF i = 255 THEN EXCL(d.flags, FlagPageSCB) END;
BusNameMsg(d, "SCB = "); KernelLog.Int(i, 0); KernelLog.Ln
END HSInit;
PROCEDURE SeqPause(d: Bus);
BEGIN
IF traceSequencer IN trace THEN BusNameMsg(d, "SeqPause"); KernelLog.Ln END;
d.Put1(d, HCNTRL, SYSTEM.VAL(CHAR, {INTEN, PAUSE}));
WHILE ~(PAUSE IN SYSTEM.VAL(SET, d.Get1(d, HCNTRL))) DO END;
END SeqPause;
PROCEDURE SeqUnpause(d: Bus);
BEGIN
IF traceSequencer IN trace THEN BusNameMsg(d, "SeqUnpause") END;
IF ~(FlagHandlingReqInits IN d.flags) THEN
IF traceSequencer IN trace THEN KernelLog.String("*") END;
d.Put1(d, HCNTRL, SYSTEM.VAL(CHAR, {INTEN}))
ELSE
ToDo("Ada7: Unpausing the sequencer while in message mode")
END;
IF traceSequencer IN trace THEN KernelLog.Ln END;
END SeqUnpause;
PROCEDURE SeqLoad(d: Bus);
VAR i, line: LONGINT;
BEGIN
IF traceCalls IN trace THEN BusNameMsg(d, "LoadSequencer"); KernelLog.Ln END;
Script.Init(FeatUltra2 IN d.features, FeatUltra IN d.features, FeatWide IN d.features, FeatTwin IN d.features,
FlagPageSCB IN d.flags, FeatQueueRegs IN d.features, FeatCmdChan IN d.features, FALSE, AIC7895 = d.chip);
i := 0;
d.Put1(d, SEQCTL, SYSTEM.VAL(CHAR, {PERRORDIS,LOADRAM,FAILDIS,FASTMODE}));
d.Put1(d, SEQADDR0, 0X);
d.Put1(d, SEQADDR1, 0X);
WHILE Script.GetNext(SYSTEM.VAL(SET, line)) DO
d.Put1(d, SEQRAM, CHR(line));
d.Put1(d, SEQRAM, CHR(SYSTEM.LSH(line, -8)));
d.Put1(d, SEQRAM, CHR(SYSTEM.LSH(line, -16)));
d.Put1(d, SEQRAM, CHR(SYSTEM.LSH(line, -24)));
INC(i)
END;
BusNameMsg(d, "Sequencer Loaded lines="); KernelLog.Int(i, 0); KernelLog.Ln;
d.Put1(d, SEQCTL, SYSTEM.VAL(CHAR, {FASTMODE,SEQRESET}));
END SeqLoad;
PROCEDURE PCIClearInt(d: Bus);
CONST DPR = 0; RMA = 5; RTA = 4;
VAR res, dw: LONGINT; bus, dev, slot: LONGINT;
BEGIN
bus := d.busNo; dev := d.devNo; slot := d.slotNo;
res := PCI.ReadConfigByte(bus, dev, slot, 7H, dw);
res := PCI.WriteConfigByte(bus, dev, slot, 7H, dw);
IF {DPR, RMA, RTA} * SYSTEM.VAL(SET, dw) # {} THEN
d.Put1(d, CLRINT, SYSTEM.VAL(CHAR, {CLRPARERR}))
END;
END PCIClearInt;
PROCEDURE PCIInit(d: Bus; bus, dev, slot: LONGINT);
VAR res, dw: LONGINT;
BEGIN
IF traceCalls IN trace THEN BusNameMsg(d, "PCIInit"); KernelLog.Ln END;
res:=PCI.ReadConfigByte(bus, dev, slot, PCI.IntlReg, dw);
d.irq := SHORT(SHORT(dw));
BusName(d); KernelLog.String("irq="); KernelLog.Int(d.irq, 0);
res:=PCI.ReadConfigDword(bus, dev, slot, PCI.Adr1Reg, dw);
IF dw = 0 THEN
res:=PCI.ReadConfigDword(bus, dev, slot, PCI.Adr0Reg, dw);
d.base := dw - 1;
d.Put1 := PortPut;
d.Get1 := PortGet;
KernelLog.String(" Port="); KernelLog.Int(d.base, 0)
ELSE
dw := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, dw) * {3..31});
Machine.MapPhysical(dw, 100H, d.base);
d.Put1 := MemoryPut;
d.Get1 := MemoryGet;
KernelLog.String(" MemMap="); KernelLog.Hex(dw, 0); KernelLog.String("/"); KernelLog.Hex(d.base, 0)
END;
KernelLog.Ln;
res:=PCI.ReadConfigWord(bus, dev, slot, PCI.CmdReg, dw);
dw := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, dw) + {8, 6, 4, 2, 1, 0});
res:=PCI.WriteConfigWord(bus, dev, slot, PCI.CmdReg, dw);
res:=PCI.ReadConfigDword(bus, dev, slot, DEVCONFIG, dw);
dw := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, dw) + {PCIERRGENDIS} - {BERREN});
IF d.chip = AIC7895 THEN
dw := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, dw) + {SCBSIZE32});
END;
res:=PCI.WriteConfigDword(bus, dev, slot, DEVCONFIG, dw);
SeqPause(d);
PCIClearInt(d);
END PCIInit;
PROCEDURE MsgStart(d: Bus);
VAR t: SET;
BEGIN
INCL(d.flags, FlagHandlingReqInits);
t := SYSTEM.VAL(SET, d.Get1(d, SIMODE1));
d.Put1(d, SIMODE1, SYSTEM.VAL(CHAR, t + {ENREQINIT}));
END MsgStart;
PROCEDURE MsgStop(d: Bus);
VAR t: SET;
BEGIN
t := SYSTEM.VAL(SET, d.Get1(d, SIMODE1));
d.Put1(d, SIMODE1, SYSTEM.VAL(CHAR, t - {ENREQINIT}));
d.Put1(d, CLRINT, SYSTEM.VAL(CHAR, {CLRSCSIINT}));
EXCL(d.flags, FlagHandlingReqInits);
END MsgStop;
PROCEDURE MsgCompose(d: Bus; index: LONGINT; VAR msg: Message);
VAR i: LONGINT;
BEGIN
IF index IN d.negotiateWidth THEN
EXCL(d.negotiateWidth, index);
msg.buf[0] := SCSI.MsgExtended;
msg.buf[1] := SCSI.MsgExtWdTrLen;
msg.buf[2] := SCSI.MsgExtWdTr;
msg.buf[3] := SCSI.MsgExtWdTr16Bit;
msg.len := 4;
msg.pos := 0;
msg.dir := Sending
ELSIF index IN d.negotiateSync THEN
EXCL(d.negotiateSync, index);
i := GetTableIndex(FeatUltra IN d.features, FeatUltra2 IN d.features);
msg.buf[0] := SCSI.MsgExtended;
msg.buf[1] := SCSI.MsgExtSdTrLen;
msg.buf[2] := SCSI.MsgExtSdTr;
msg.buf[3] := CHR(rateTable[i].period);
msg.buf[4] := GetMaxOffset(FeatWide IN d.features, FeatUltra2 IN d.features);
msg.len := 5;
msg.pos := 0;
msg.dir := Sending
ELSE
ToDo("Adaptec7.MsgCompose: negotiate what?");
END
END MsgCompose;
PROCEDURE MsgParse(d: Bus; VAR msg: Message): BOOLEAN;
VAR reject, done, wide: BOOLEAN; period, offset: LONGINT; t: SET;
BEGIN
reject := FALSE; done := FALSE;
IF msg.buf[0] # SCSI.MsgExtended THEN
reject := TRUE
ELSIF msg.len <= 2 THEN
done := FALSE
ELSIF msg.buf[2] = SCSI.MsgExtSdTr THEN
IF msg.buf[1] # SCSI.MsgExtSdTrLen THEN
reject := TRUE
ELSIF msg.len < ORD(SCSI.MsgExtSdTrLen)+2 THEN
done := FALSE
ELSE
done := TRUE;
period := ORD(msg.buf[3]);
offset := ORD(msg.buf[4]);
BusNameMsg(d, "SyncMsg "); KernelLog.Int(period, 0); KernelLog.Char("/");
KernelLog.Int(offset, 0); KernelLog.Ln;
SetSyncRate(d, period, offset)
END
ELSIF msg.buf[2] = SCSI.MsgExtWdTr THEN
IF msg.buf[1] # SCSI.MsgExtWdTrLen THEN
reject := TRUE
ELSIF msg.len < ORD(SCSI.MsgExtWdTrLen)+2 THEN
done := FALSE
ELSE
done := TRUE;
wide := msg.buf[3] = SCSI.MsgExtWdTr16Bit;
BusNameMsg(d, "WidthMsg "); KernelLog.Int(ORD(msg.buf[3]), 0); KernelLog.Ln;
SetWidth(d, wide);
END
ELSE
reject := TRUE
END;
IF reject THEN
d.Put1(d, MSGOUT, SCSI.MsgMessageReject);
t := SYSTEM.VAL(SET, d.Get1(d, SCSISIG));
d.Put1(d, SCSISIG, SYSTEM.VAL(CHAR, t + {ATN}))
END;
RETURN reject OR done
END MsgParse;
PROCEDURE MsgTransmit(d: Bus; VAR msg: Message);
VAR t: SET; done: BOOLEAN; ch: CHAR;
BEGIN
t := SYSTEM.VAL(SET, d.Get1(d, SCSISIG));
IF msg.dir = Sending THEN
IF traceSmall IN trace THEN
KernelLog.Char("["); KernelLog.Hex(ORD(msg.buf[msg.pos]), -2); KernelLog.Char("]")
END;
IF msg.pos = msg.len-1 THEN
done := TRUE;
d.Put1(d, SINDEX, msg.buf[msg.pos]);
d.Put1(d, RETURN1, 0X)
ELSIF (t * PHASEMASK) # PhaseMsgOut THEN
IF traceSmall IN trace THEN KernelLog.Char("&") END;
done := TRUE;
d.Put1(d, RETURN1, SYSTEM.VAL(CHAR, MSGOUTPHASEMIS))
ELSE
d.Put1(d, CLRSINT1, SYSTEM.VAL(CHAR, {CLRREQINIT}));
d.Put1(d, CLRINT, SYSTEM.VAL(CHAR, {CLRSCSIINT}));
d.Put1(d, SCSIDATL, msg.buf[msg.pos]);
INC(msg.pos);
END;
ELSE
done := (t * PHASEMASK) # PhaseMsgIn;
IF ~done THEN
msg.buf[msg.pos] := SYSTEM.VAL(CHAR, d.Get1(d, SCSIBUSL));
IF traceSmall IN trace THEN
KernelLog.Char("("); KernelLog.Hex(ORD(msg.buf[msg.pos]), -2); KernelLog.Char(")")
END;
INC(msg.len); INC(msg.pos);
done := MsgParse(d, d.msg);
d.Put1(d, CLRSINT1, SYSTEM.VAL(CHAR, {CLRREQINIT}));
d.Put1(d, CLRINT, SYSTEM.VAL(CHAR, {CLRSCSIINT}));
ch := d.Get1(d, SCSIDATL);
IF ch # msg.buf[msg.pos-1] THEN KernelLog.String("Ada7.MsgTransmit, strange"); KernelLog.Ln END;
ELSE
KernelLog.String("Ada7.MsgTransmit, phase mismatch "); KernelLog.Hex(SYSTEM.VAL(LONGINT, t), -2);
KernelLog.Ln
END
END;
IF done THEN
MsgStop(d); SeqUnpause(d)
END
END MsgTransmit;
PROCEDURE Done(d: Bus; index: LONGINT);
BEGIN
QUntaggedSet(d, index, 0FFX);
HSFreeScb(d, index);
IF d.sync[index] = InUse THEN
d.Synchronize(index, InUse, Terminated)
ELSE
KernelLog.String("PANIC: done called but not in use!"); KernelLog.Ln
END;
END Done;
PROCEDURE IntCommand(d: Bus);
VAR index: LONGINT;
BEGIN
INC(aIntCmdCount);
IF traceInts IN trace THEN
BusNameMsg(d, "IntCmdCmplt"); KernelLog.Ln;
DumpAllLists(d);
Reg(d, RETURN1, " RETURN = "); Reg(d, SCBPTR, " SCBPTR = "); KernelLog.Ln
END;
d.Put1(d, CLRINT, SYSTEM.VAL(CHAR, {CLRCMDINT}));
index := ORD(QOutGet(d, d.out));
WHILE index # ORD(0FFX) DO
QOutSet(d, d.out, 0FFX);
d.out := (d.out + 1) MOD 256;
Done(d, index);
index := ORD(QOutGet(d, d.out))
END
END IntCommand;
PROCEDURE IntBrkAdr(d: Bus);
VAR error: SET;
BEGIN
INC(aIntBrkAdrCount);
error := SYSTEM.VAL(SET, d.Get1(d, ERROR));
IF PCIERRSTAT IN error THEN
ToDo("Adaptec7.IntBrkAdr/PCIERRSTAT");
PCIClearInt(d)
END;
d.Put1(d, CLRINT, SYSTEM.VAL(CHAR, {CLRPARERR, CLRBRKADRINT}));
SeqUnpause(d)
END IntBrkAdr;
PROCEDURE IntSeqHandle(d: Bus; code: LONGINT);
CONST trace = {traceInts};
VAR active, ch: CHAR; index: LONGINT;
BEGIN
IF FALSE & (traceInts IN trace) THEN
BusNameMsg(d, "IntSeqHandle"); KernelLog.Ln;
DumpAllLists(d);
Reg(d, RETURN1, " RETURN = "); Reg(d, SCBPTR, " SCBPTR = "); Reg(d, SCBTARGETSTATUS, " TargStat = "); KernelLog.Ln
END;
INC(aIntSeqCount);
d.Put1(d, CLRINT, SYSTEM.VAL(CHAR, {CLRSEQINT}));
active := d.Get1(d, SCBPTR); index := ORD(d.Get1(d, SCBTAG));
CASE code OF
| NoMatch:
IF traceInts IN trace THEN BusNameMsg(d, "IntSeqHandle.NoMatch"); KernelLog.Ln END;
INC(aIntSeqNoMatch);
ch := d.Get1(d, SCSISEQ);
d.Put1(d, SCSISEQ, SYSTEM.VAL(CHAR, SYSTEM.VAL(SET, ch) * {ENSELI, ENRSELI, ENAUTOATNP}))
| SendReject:
IF traceInts IN trace THEN BusNameMsg(d, "IntSeqHandle.SendReject"); KernelLog.Ln END;
INC(aIntSeqSendReject)
| NoIdent:
INC(aIntSeqNoIdent);
ToDo("IntSeqHandle.NoIdent")
| BadPhase:
IF traceInts IN trace THEN BusNameMsg(d, "IntSeqHandle.BadPhase"); KernelLog.Ln END;
INC(aIntSeqBadPhase);
IF PhaseBusFree = SYSTEM.VAL(SET, d.Get1(d, LASTPHASE)) THEN
d.Put1(d, SEQCTL, SYSTEM.VAL(CHAR, {FASTMODE, SEQRESET}))
END
| ExtendedMsg:
IF (traceInts IN trace) THEN BusNameMsg(d, "IntSeqHandle.ExtendedMsg"); KernelLog.Ln END;
INC(aIntSeqExtendedMsg);
MsgStart(d);
d.msg.dir := Receiving; d.msg.pos := 0; d.msg.len := 0;
RETURN
| RejectMsg:
IF (traceInts IN trace) THEN BusNameMsg(d, "IntSeqHandle.RejectMsg"); KernelLog.Ln END;
INC(aIntSeqRejectMsg);
| BadStatus:
INC(aIntSeqBadStatus);
d.Put1(d, RETURN1, 0X);
d.status[index] := SHORT(ORD(d.Get1(d, SCBTARGETSTATUS)));
IF traceInts IN trace THEN
BusNameMsg(d, "IntSeq.BadStatus[");
KernelLog.Int(index, 0); KernelLog.String("] = "); KernelLog.Int(d.status[index], 0); KernelLog.Ln;
Reg(d, SSTAT0, "STAT0 = "); Reg(d, SSTAT1, " STAT1 = "); Reg(d, SSTAT2, " STAT2 = "); Reg(d, SSTAT3, " STAT3 = ");
Reg(d, ERROR, " ERROR = ");
Reg(d, DSCOMMAND0, " CMD0 = "); Reg(d, DSPCISTATUS, " DSPCISTATUS = "); KernelLog.Ln;
DumpAllLists(d);
Reg(d, RETURN1, " RETURN = "); Reg(d, SCBPTR, " SCBPTR = "); Reg(d, SCBTARGETSTATUS, " TargStat = ");
Reg(d, DFSTATUS, " DFSTATUS = "); Reg(d, DFFTHRSH, " DFFTHRSH = ");
KernelLog.Ln;
DumpCurSCB(d);
END
| AwaitingMsg:
IF traceInts IN trace THEN BusNameMsg(d, "IntSeqHandle.AwaitingMsg"); KernelLog.Ln END;
INC(aIntSeqAwaitingMsg);
MsgStart(d);
MsgCompose(d, index, d.msg);
RETURN
| DataOverrun:
INC(aIntSeqDataOverrun);
IF TRUE & (traceInts IN trace) THEN BusNameMsg(d, "IntSeqHandle.DataOverrun"); KernelLog.Ln END;
d.status[index] := SCSI.CommandTerminated;
d.result[index] := SCSI.Error;
END;
SeqUnpause(d)
END IntSeqHandle;
PROCEDURE IntScsiSeltoHandle(d: Bus);
VAR t: SET; index: LONGINT;
BEGIN
INC(aIntScsiSelto);
IF d.Get1(d, WAITINGSCBH) # d.Get1(d, SCBPTR) THEN
INC(aIntScsiSeltoProblem1);
BusNameMsg(d, "Selto: WAITING # SCBPTR"); KernelLog.Ln
END;
d.Put1(d, SCBPTR, d.Get1(d, WAITINGSCBH));
index := ORD(d.Get1(d, SCBTAG));
IF (traceInts IN trace) THEN
BusNameMsg(d, "IntScsiHandle.Selto"); KernelLog.Int(index, 0); KernelLog.Ln;
DumpCurSCB(d)
END;
IF d.sync[index] # InUse THEN
INC(aIntScsiSeltoProblem2);
ToDo("IntScsiHandle.Selto/Invalid Index");
BusNameMsg(d, "IntScsiHandle.Selto"); KernelLog.Int(ORD(d.Get1(d, WAITINGSCBH)), 0);
KernelLog.Char("/"); KernelLog.Int(index, 0); KernelLog.Ln;
DumpCurSCB(d);
DumpAllLists(d);
ELSE
d.status[index] := SCSI.CommandTerminated;
d.result[index] := SCSI.TimeOut;
EXCL(d.negotiateWidth, index);
EXCL(d.negotiateSync, index);
d.Put1(d, SCBCONTROL, 0X);
d.Put1(d, MSGOUT, SCSI.MsgNoop);
d.Put1(d, WAITINGSCBH, d.Get1(d, SCBNEXT));
HSFreeCurrent(d);
Done(d, index)
END;
d.Put1(d, SCSISEQ, 0X);
t := SYSTEM.VAL(SET, d.Get1(d, SIMODE1));
d.Put1(d, SIMODE1, SYSTEM.VAL(CHAR, t - {ENREQINIT, ENBUSFREE}));
EXCL(d.flags, FlagHandlingReqInits);
d.Put1(d, CLRSINT1, SYSTEM.VAL(CHAR, {CLRSELTIMEO,CLRBUSFREE}));
d.Put1(d, CLRINT, SYSTEM.VAL(CHAR, {CLRSCSIINT}));
d.Put1(d, SEQCTL, SYSTEM.VAL(CHAR, {FASTMODE, SEQRESET}));
SeqUnpause(d)
END IntScsiSeltoHandle;
PROCEDURE IntScsiResetHandle(d: Bus);
PROCEDURE TraverseList(d: Bus; list: LONGINT; debugMsg: ARRAY OF CHAR);
VAR ptr: CHAR; index: LONGINT;
BEGIN
ptr := d.Get1(d, list);
WHILE ptr # 0FFX DO
d.Put1(d, SCBPTR, ptr);
index := ORD(d.Get1(d, SCBTAG));
KernelLog.String(debugMsg); KernelLog.Hex(ORD(ptr), -2); KernelLog.Char("/");
KernelLog.Hex(index, -2); KernelLog.Ln;
ptr := d.Get1(d, SCBNEXT);
HSFreeCurrent(d);
d.status[index] := SCSI.NotGood;
d.result[index] := SCSI.Reset;
Done(d, index)
END;
END TraverseList;
BEGIN
IF TRUE & (traceInts IN trace) THEN
BusNameMsg(d, "IntScsiResetHandle"); KernelLog.Ln;
DumpAllLists(d);
END;
INC(aIntScsiReset);
BusConfigure(d);
TraverseList(d, WAITINGSCBH, "waiting list ");
TraverseList(d, DISCONNECTEDSCBH, "disc list");
d.Put1(d, CLRSINT1, SYSTEM.VAL(CHAR, {CLRSCSIRSTI}));
d.Put1(d, CLRINT, SYSTEM.VAL(CHAR, {CLRSCSIINT}));
SeqUnpause(d)
END IntScsiResetHandle;
PROCEDURE IntScsiHandle(d: Bus);
VAR status: SET;
BEGIN
IF traceInts IN trace THEN
BusNameMsg(d, "IntScsiHandle"); KernelLog.Ln;
DumpAllLists(d);
Reg(d, SSTAT1, "STAT1 = "); Reg(d, SIMODE1, " SIMODE1 = ");
Reg(d, RETURN1, " RETURN = "); Reg(d, SCBPTR, " SCBPTR = "); KernelLog.Ln
END;
INC(aIntScsiCount);
status := SYSTEM.VAL(SET, d.Get1(d, SSTAT1));
IF SCSIRSTI IN status THEN
IntScsiResetHandle(d)
ELSIF SELTO IN status THEN
IntScsiSeltoHandle(d)
ELSIF BUSFREE IN status THEN
INC(aIntScsiBusFree);
ToDo("IntScsiHandle.BusFree");
Reg(d, LASTPHASE, "LASTPHASE"); KernelLog.Ln;
d.Put1(d, CLRSINT1, SYSTEM.VAL(CHAR, {CLRBUSFREE}));
d.Put1(d, CLRINT, SYSTEM.VAL(CHAR, {CLRSCSIINT}));
d.Put1(d, SEQCTL, SYSTEM.VAL(CHAR, {FASTMODE, SEQRESET}));
SeqUnpause(d)
ELSIF SCSIPERR IN status THEN
INC(aIntScsiParity);
IF TRUE & (traceInts IN trace) THEN BusNameMsg(d, "IntScsiHandle.SCSIPERR"); KernelLog.Ln END;
d.Put1(d, CLRSINT1, SYSTEM.VAL(CHAR, {CLRSCSIPERR}));
d.Put1(d, CLRINT, SYSTEM.VAL(CHAR, {CLRSCSIINT}));
SeqUnpause(d)
ELSIF (REQINIT IN status) & (FlagHandlingReqInits IN d.flags) THEN
IF traceInts IN trace THEN BusNameMsg(d, "IntScsiHandle.ReqInit"); KernelLog.Ln END;
INC(aIntScsiReqInit);
MsgTransmit(d, d.msg);
ELSIF (1 IN status) & (FlagHandlingReqInits IN d.flags) THEN
INC(aIntScsiSpecial);
KernelLog.Char("("); KernelLog.Hex(ORD(d.Get1(d, SCSIBUSL)), -2); KernelLog.Char(")");
ToDo("IntScsiHandle.Unexpected message");
ELSE
INC(aIntScsiUnknown);
ToDo("IntScsiHandle.Unknown");
KernelLog.String("SSTAT1 = "); KernelLog.Hex(SYSTEM.VAL(LONGINT, status), -2); KernelLog.Ln;
d.Put1(d, CLRINT, SYSTEM.VAL(CHAR, {CLRSCSIINT}));
SeqUnpause(d)
END
END IntScsiHandle;
PROCEDURE IntClear(d: Bus);
BEGIN
d.Put1(d, CLRSINT0, SYSTEM.VAL(CHAR, {CLRSELDO, CLRSELDI, CLRSELINGO}));
d.Put1(d, CLRSINT1, SYSTEM.VAL(CHAR, CLRSINT1ALL));
d.Put1(d, CLRINT, SYSTEM.VAL(CHAR, {CLRSCSIINT, CLRSEQINT, CLRBRKADRINT, CLRPARERR}))
END IntClear;
PROCEDURE IntInstall(d: Bus);
BEGIN
IntClear(d);
IF interrupt[d.irq] = NIL THEN NEW(interrupt[d.irq], d.irq) END;
d.next := interrupt[d.irq].root; interrupt[d.irq].root := d;
BusNameMsg(d, "IntHandler installed, "); KernelLog.Int(d.irq, 0); KernelLog.Ln;
END IntInstall;
PROCEDURE ScbControl(d: Bus; dev: LONGINT): CHAR;
BEGIN
IF dev IN d.negotiateWidth THEN
IF traceSmall IN trace THEN KernelLog.Char("W") END;
RETURN SYSTEM.VAL(CHAR, {HwScbMessage})
ELSIF dev IN d.negotiateSync THEN
IF traceSmall IN trace THEN KernelLog.Char("S") END;
RETURN SYSTEM.VAL(CHAR, {HwScbMessage})
END;
RETURN 0X
END ScbControl;
PROCEDURE BusSchedule(d: Bus; VAR c: SCSI.Command);
CONST MaxRange = 64;
VAR index, num, useRange, sgaddr: LONGINT; target: CHAR; range: ARRAY 2, MaxRange+1 OF Machine.Range;
cmd: ARRAY 2, 16 OF CHAR; cmdBlock: LONGINT;
BEGIN
INC(aExecute);
IF (0 > c.target) OR (c.target >= d.width) OR ~(c.lun IN {0..7}) OR ~(c.chan IN {0,1}) THEN
d.Synchronize(c.target, InUse, Free);
HALT(200)
END;
IF (c.dlen > MaxRange * 4096) THEN
d.Synchronize(c.target, InUse, Free);
HALT(201)
END;
index := c.target;
IF traceSmall IN trace THEN
KernelLog.Char("{"); KernelLog.Hex(ORD(c.cmd[0]), -2); KernelLog.Char("}")
END;
IF traceCmds IN trace THEN
BusNameMsg(d, "schedule ["); KernelLog.Int(index, 0); KernelLog.String("] = ");
KernelLog.Hex(ORD(c.cmd[0]), -2);
END;
d.status[index] := SCSI.Good;
d.result[index] := SCSI.OK;
target := MakeTarget(c.target, c.chan, c.lun);
HSSet(d, index, HScontrol, ScbControl(d, index));
HSSet(d, index, HStarget, target);
Machine.TranslateVirtual(SYSTEM.ADR(c.cmd[0]), c.clen, num, range[0]);
ASSERT(num # 0, 202);
IF num > 1 THEN
cmdBlock := -1;
REPEAT
INC(cmdBlock);
Machine.TranslateVirtual(SYSTEM.ADR(cmd[cmdBlock, 0]), c.clen, num, range[0]);
UNTIL num = 1;
SYSTEM.MOVE(SYSTEM.ADR(c.cmd[0]), SYSTEM.ADR(cmd[cmdBlock, 0]), c.clen);
END;
HSSet4(d, index, HScmdPtr, range[0, 0].adr);
HSSet(d, index, HScmdLen, CHR(c.clen));
IF c.dlen = 0 THEN
IF traceCmds IN trace THEN
KernelLog.String(" No Data "); KernelLog.Ln
END;
HSSet(d, index, HSSGcount, 0X);
HSSet4(d, index, HSSGptr, 0);
HSSet4(d, index, HSdataPtr, 0);
HSSet4(d, index, HSdataCnt, 0)
ELSE
ASSERT(c.dataAddr # 0);
Machine.TranslateVirtual(SYSTEM.ADR(range[0, 0]), 16*SYSTEM.SIZEOF(Machine.Range), num, range[0]);
IF num = 1 THEN
useRange := 0;
ELSE
Machine.TranslateVirtual(SYSTEM.ADR(range[1, 0]), 16*SYSTEM.SIZEOF(Machine.Range), num, range[0]);
ASSERT(num = 1, 203);
useRange := 1;
IF traceCmds IN trace THEN KernelLog.Char("+")END;
END;
sgaddr := range[0, 0].adr;
Machine.TranslateVirtual(c.dataAddr, c.dlen, num, range[useRange]);
ASSERT(num # 0, 204);
IF traceCmds IN trace THEN
IF num > 1 THEN KernelLog.Char("%") ELSE KernelLog.Char("$") END
END;
HSSet(d, index, HSSGcount, CHR(num));
HSSet4(d, index, HSSGptr, sgaddr+SYSTEM.SIZEOF(Machine.Range));
HSSet4(d, index, HSdataPtr, range[useRange, 0].adr);
HSSet4(d, index, HSdataCnt, range[useRange, 0].size);
IF traceCmds IN trace THEN
KernelLog.String(" Data = "); KernelLog.Int(c.dlen, 0);
KernelLog.Int(useRange, 2);
KernelLog.Int(num, 2);
KernelLog.Ln;
END;
END;
QUntaggedSet(d, ORD(target), CHR(index));
QInSet(d, d.in, CHR(index));
d.in := (d.in+1) MOD 256;
IF FeatQueueRegs IN d.features THEN
d.Put1(d, HNSCBQOFF, CHR(d.in))
ELSE
SeqPause(d);
d.Put1(d, KERNELQINPOS, CHR(d.in));
SeqUnpause(d)
END;
d.Synchronize(c.target, Terminated, Terminated);
IF traceCmds IN trace THEN
BusNameMsg(d, "schedule ["); KernelLog.Int(index, 0); KernelLog.String("] result = ");
KernelLog.Int(d.status[index], 0); KernelLog.Char("/"); KernelLog.Int(d.result[index], 0);
KernelLog.Ln
END;
END BusSchedule;
PROCEDURE BusReset(d: Bus);
VAR mode1, seq: SET;
BEGIN
BusNameMsg(d, "BusR");
mode1 := SYSTEM.VAL(SET, d.Get1(d, SIMODE1));
d.Put1(d, SIMODE1, SYSTEM.VAL(CHAR, mode1 - {ENSCSIRST}));
d.Put1(d, SCSISEQ, SYSTEM.VAL(CHAR, {SCSIRSTO}));
KernelLog.Char("e");
REPEAT
timer.Sleep(5);
seq :=SYSTEM.VAL(SET, d.Get1(d, SCSISEQ))
UNTIL (SCSIRSTO IN seq);
KernelLog.Char("s");
timer.Sleep(10);
d.Put1(d, SCSISEQ, 0X);
timer.Sleep(5);
KernelLog.Char("e");
IntClear(d);
d.Put1(d, SIMODE1, SYSTEM.VAL(CHAR, mode1 + {ENSCSIRST}));
KernelLog.Char("t"); KernelLog.Ln
END BusReset;
PROCEDURE BusChipReset(d: Bus);
VAR t: Kernel.MilliTimer;
BEGIN
IF {traceCalls, traceReset} * trace # {} THEN BusNameMsg(d, "ResetChip"); KernelLog.Ln END;
d.Put1(d, HCNTRL, SYSTEM.VAL(CHAR, {PAUSE, CHIPRST}));
Kernel.SetTimer(t, 1000);
REPEAT
UNTIL (CHIPRST IN SYSTEM.VAL(SET, d.Get1(d, HCNTRL))) OR Kernel.Expired(t);
SeqPause(d);
END BusChipReset;
PROCEDURE BusDetectWidth(d: Bus);
VAR s: SET;
BEGIN
s := SYSTEM.VAL(SET, d.Get1(d, SBLKCTL));
s := s * {SELWIDE, SELBUSB};
d.wide := FALSE; d.width := 8;
IF s = {SELWIDE} THEN
BusNameMsg(d, "bus is wide"); KernelLog.Ln;
INCL(d.features, FeatWide);
d.wide := TRUE; d.width := 16
ELSIF s = {SELBUSB} THEN
BusNameMsg(d, "multichannel card"); KernelLog.Ln;
IF ~(FlagMultiChannel IN d.flags) THEN
BusNameMsg(d, "WARNING: this card is not declared as multichannel"); KernelLog.Ln
END;
INCL(d.features, FeatTwin);
INCL(d.flags, FlagMultiChannel)
ELSIF s # {} THEN
BusNameMsg(d, "PANIC: this card is both wide and multichannel"); KernelLog.Ln;
HALT(99)
END
END BusDetectWidth;
PROCEDURE BusConfigureChannels(d: Bus);
VAR chip: SHORTINT; set: SET;
BEGIN
chip := d.chip;
IF FlagMultiChannel IN d.flags THEN
IF chip IN {AIC7870, AIC7880} THEN
IF d.slotNo = 5 THEN INCL(d.flags, FlagChnlB)
ELSIF d.slotNo = 8 THEN INCL(d.flags, FlagChnlB)
ELSIF d.slotNo = 12 THEN INCL(d.flags, FlagChnlC)
END
ELSIF chip IN {AIC7895, AIC7896} THEN
IF d.devNo # 0 THEN INCL(d.flags, FlagChnlB) END;
END;
END;
set := SYSTEM.VAL(SET, d.Get1(d, DSCOMMAND0));
IF chip IN {AIC7890, AIC7896} THEN
d.Put1(d, SCAMCTL, 0X);
set := set + {CACHETHEN, MPARCKEN, USCBSIZE32, CIOPARCKEN} - {DPARCKEN}
ELSIF chip IN {AIC7850, AIC7860} THEN
set := set + {CACHETHEN, MPARCKEN}- {DPARCKEN}
END;
d.Put1(d, DSCOMMAND0, SYSTEM.VAL(CHAR, set))
END BusConfigureChannels;
PROCEDURE BusConfigure(d: Bus);
VAR i: LONGINT;
BEGIN
d.scsiId := 7;
i := d.width;
IF ~(traceNoHandling IN trace) THEN
IF d.wide THEN
d.negotiateWidth := {0 .. d.width-1};
END;
d.negotiateSync := {0 .. d.width-1}
END;
WHILE i > 0 DO
DEC(i);
d.Put1(d, TARGSCSIRATE+i, 0X);
IF FeatUltra2 IN d.features THEN
d.Put1(d, TARGOFFSET+i, 0X);
END
END;
d.Put1(d, ULTRAENB, 0X);
d.Put1(d, ULTRAENB+1, 0X);
d.Put1(d, DISCDSB, 0X);
d.Put1(d, DISCDSB+1, 0X);
d.Put1(d, SCSICONF, SYSTEM.VAL(CHAR, {ENSPCHK, RESETSCSI}));
d.Put1(d, SCSICONF+1, CHR(d.scsiId))
END BusConfigure;
PROCEDURE BusInit(d: Bus);
VAR sblkctr: SET;
PROCEDURE InitChannel;
BEGIN
IF FeatUltra2 IN d.flags THEN
d.Put1(d, SCSIIDULTRA2, CHR(d.scsiId))
ELSE
d.Put1(d, SCSIID, CHR(d.scsiId))
END;
d.Put1(d, SXFRCTL0, SYSTEM.VAL(CHAR, {DFON, SPIOEN}));
d.Put1(d, SXFRCTL1, SYSTEM.VAL(CHAR, {ENSPCHK, ENSTIMER, ACTNEGEN, STPWEN}));
d.Put1(d, SIMODE0, 0X);
d.Put1(d, SIMODE1, SYSTEM.VAL(CHAR,{ENSELTIMO, ENSCSIRST, ENSCSIPERR}));
d.Put1(d, SCSIRATE, 0X);
END InitChannel;
BEGIN
IF d.chip = AIC7770 THEN d.Put1(d, BCTL, SYSTEM.VAL(CHAR, {ENABLE})) END;
sblkctr := SYSTEM.VAL(SET, d.Get1(d, SBLKCTL));
sblkctr := sblkctr - {AUTOFLUSHDIS, DIAGLEDEN};
d.Put1(d, SBLKCTL, SYSTEM.VAL(CHAR, sblkctr));
d.Put1(d, MSGOUT, SCSI.MsgNoop);
d.Put1(d, LASTMSG, SCSI.MsgNoop);
d.Put1(d, SEQFLAGS, 0X);
d.Put1(d, TMODECMDADDR, 0X);
d.Put1(d, TMODECMDADDR+1, 0X);
d.Put1(d, TMODECMDADDR+2, 0X);
d.Put1(d, TMODECMDADDR+3, 0X);
d.Put1(d, TMODECMDADDRNEXT, 0X);
IF FeatTwin IN d.features THEN
d.Put1(d, SBLKCTL, SYSTEM.VAL(CHAR, sblkctr+{SELBUSB}));
InitChannel;
BusReset(d);
d.Put1(d, SBLKCTL, SYSTEM.VAL(CHAR, sblkctr))
END;
InitChannel;
IF FeatUltra2 IN d.features THEN
d.Put1(d, DFFTHRSH, SYSTEM.VAL(CHAR, WRDFFTHRSH75 + RDDFFTHRSH75))
ELSE
d.Put1(d, DSPCISTATUS, SYSTEM.VAL(CHAR, DFTHRSH100))
END;
BusReset(d);
d.interruptable := TRUE;
END BusInit;
PROCEDURE Detect;
VAR dummy, idx, bus, dev, slot, res, signature, i: LONGINT; host: Bus;
BEGIN
IF traceCalls IN trace THEN KernelLog.String("Ada7: Detect"); KernelLog.Ln END;
IF PCI.Done = PCI.PCIPresent(dummy, dummy, dummy) THEN
idx := 0;
WHILE PCI.Done = PCI.FindPCIClassCode(010000H , idx, bus, dev, slot) DO
res := PCI.ReadConfigDword(bus, dev, slot, PCI.DevReg, signature);
i := LEN(card)-1;
REPEAT DEC(i) UNTIL (i < 0) OR (card[i].signature = signature);
IF i >= 0 THEN
NEW(host, i, bus, dev, slot);
BusNameMsg(host, card[i].name); KernelLog.Ln;
PCIInit(host, bus, dev, slot);
BusChipReset(host);
BusDetectWidth(host);
BusConfigureChannels(host);
BusConfigure(host);
HSInit(host);
QInit(host);
SeqLoad(host);
BusInit(host);
IntInstall(host);
SeqUnpause(host);
IF ~(traceNoRegister IN trace) THEN
timer.Sleep(1000);
SCSI.RegisterBus(host)
END
END;
INC(idx)
END
ELSE
KernelLog.String("Ada7: No PCI present"); KernelLog.Ln
END;
END Detect;
PROCEDURE Cleanup;
VAR d: Bus; i: LONGINT;
BEGIN
IF Modules.shutdown # Modules.None THEN RETURN END;
FOR i := 0 TO 31 DO
IF interrupt[i] # NIL THEN
d := interrupt[i].root;
WHILE d # NIL DO
SeqPause(d);
SCSI.RemoveBus(d);
ToDo("Ada7: free buffers");
BusNameMsg(d, "Removed"); KernelLog.Ln;
d := d.next
END;
interrupt[i].Cleanup
END
END;
firstBus := NIL;
END Cleanup;
PROCEDURE Init;
CONST
ultraFlags = {FlagPageSCB, FlagNewEepromFMT, FlagBiosEnabled};
ultra2Features = {FeatMoreSRAM, FeatUltra2, FeatCmdChan, FeatQueueRegs, FeatSGPreload};
PROCEDURE Card(i: LONGINT; sig: HUGEINT; chip: SHORTINT; flags, features: SET; name: ARRAY OF CHAR);
BEGIN
card[i].signature := SHORT(sig);
card[i].chip := chip;
card[i].flags := flags; card[i].features := features;
COPY(name, card[i].name)
END Card;
PROCEDURE Table(i: LONGINT; period: SHORTINT; rate, u2rate: CHAR; speed: LONGINT);
BEGIN
rateTable[i].period := period;
rateTable[i].rate := rate;
rateTable[i].u2rate := u2rate;
rateTable[i].speed := speed
END Table;
BEGIN
IF traceAIC7890 IN trace THEN
Card(15, 001F9005H, AIC7890, ultraFlags, ultra2Features, "Adaptec AIC-7890/1 Ultra2");
ELSIF traceAIC7880 IN trace THEN
Card(9, 80789004H, AIC7880, {FlagPageSCB, FlagBiosEnabled}, {FeatUltra}, "Adaptec AIC-7880 Ultra");
ELSIF traceAHA2940 IN trace THEN
Card(10, 81789004H, AIC7880, {FlagPageSCB, FlagBiosEnabled}, {FeatUltra}, "Adaptec AHA-294X Ultra");
ELSE
Card(0, 50789004H, AIC7850, {}, {FeatSpioCap}, "Adaptec AIC-7850");
Card(1, 55789004H, AIC7850, {FlagPageSCB}, {FeatSpioCap}, "Adaptec AIC-7855");
Card(2, 60789004H, AIC7860, ultraFlags, {FeatUltra, FeatSpioCap}, "Adaptec AIC-7860 Ultra");
Card(3, 61789004H, AIC7860, ultraFlags, {FeatUltra, FeatSpioCap}, "Adaptec AHA-2940A Ultra");
Card(4, 70789004H, AIC7870, {FlagPageSCB, FlagBiosEnabled}, {}, "Adaptec AIC-7870");
Card(5, 71789004H, AIC7870, {FlagPageSCB, FlagBiosEnabled}, {}, "Adaptec AHA-294X");
Card(6, 72789004H, AIC7870, {FlagPageSCB, FlagBiosEnabled, FlagMultiChannel}, {}, "Adaptec AHA-394X");
Card(7, 73789004H, AIC7870, {FlagPageSCB, FlagBiosEnabled, FlagMultiChannel}, {}, "Adaptec AHA-398X");
Card(8, 74789004H, AIC7870, {FlagPageSCB, FlagBiosEnabled}, {}, "Adaptec AHA-2944");
Card(9, 80789004H, AIC7880, {FlagPageSCB, FlagBiosEnabled}, {FeatUltra}, "Adaptec AIC-7880 Ultra");
Card(10, 81789004H, AIC7880, {FlagPageSCB, FlagBiosEnabled}, {FeatUltra}, "Adaptec AHA-294X Ultra");
Card(11, 82789004H, AIC7880, {FlagPageSCB, FlagBiosEnabled, FlagMultiChannel}, {FeatUltra}, "Adaptec AHA-394X Ultra");
Card(12, 83789004H, AIC7880, {FlagPageSCB, FlagBiosEnabled, FlagMultiChannel}, {FeatUltra}, "Adaptec AHA-398X Ultra");
Card(13, 84789004H, AIC7880, {FlagPageSCB, FlagBiosEnabled}, {FeatUltra},"Adaptec AHA-2944 Ultra");
Card(14, 78959004H, AIC7895, ultraFlags + {FlagMultiChannel}, {FeatMoreSRAM, FeatUltra, FeatCmdChan}, "Adaptec AIC-7895 Ultra");
Card(15, 001F9005H, AIC7890, ultraFlags, ultra2Features, "Adaptec AIC-7890/1 Ultra2");
Card(16, 00109005H, AIC7890, ultraFlags, ultra2Features, "Adaptec AHA-294X Ultra2");
Card(17, 005F9005H, AIC7896, ultraFlags + {FlagMultiChannel}, ultra2Features, "Adaptec AIC-7896/7 Ultra2");
Card(18, 00509005H, AIC7896, ultraFlags + {FlagMultiChannel}, ultra2Features, "Adaptec AHA-394X Ultra2");
END;
Table(0, 10, 0FFX, 13X, 400);
Table(1, 11, 0FFX, 14X, 200);
Table(2, 12, 0X, 15X, 200);
Table(3, 15, 10X, 16X, 160);
Table(4, 18, 20X, 17X, 133);
Table(5, 25, 00X, 18X, 100);
Table(6, 31, 10X, 19X, 80);
Table(7, 37, 20X, 1AX, 67);
Table(8, 43, 30X, 1BX, 57);
Table(9, 50, 40X, 1CX, 50);
Table(10, 56, 50X, 0FFX, 44);
Table(11, 62, 60X, 0FFX, 40);
Table(12, 68, 70X, 0FFX, 36);
Modules.InstallTermHandler(Cleanup)
END Init;
PROCEDURE KillAll*;
VAR i, j: LONGINT; d: Bus;
BEGIN
FOR i := 0 TO 31 DO
IF interrupt[i] # NIL THEN
d := interrupt[i].root;
WHILE d # NIL DO
FOR j := 0 TO d.width-1 DO
d.Synchronize(j, d.sync[j], Terminated)
END;
d := d.next
END
END
END
END KillAll;
PROCEDURE Install*;
END Install;
BEGIN
KernelLog.String("Adaptec7 - 0.41 / prk"); KernelLog.Ln;
NEW(timer);
Init;
Detect;
END Adaptec7.
System.Free Adaptec7 ~ System.Free SCSI ~
System.State Adaptec7 ~
Adaptec7.Cleanup
Adaptec7.Detect
Adaptec7.FullDump
Adaptec7.WriteConfig
Adaptec7.BusState Adaptec7.ScsiState
Adaptec7.WriteLists
Adaptec7.Test
Adaptec7.Speed
Adaptec7.Scan
Adaptec7.Register
!OFSTools.Mount TEST AosFS SCSI0.2#2,R ~
OFSTools.Mount USER AosFS SCSI0.0#6,R ~
OFSTools.Unmount ^ ~
OFSTools.Watch
System.Directory USER:* ~
(*
15.10.01 0.41 prk wrong constant offset for DFF_THRSH discovered and corrected
26.03.01 0.4 prk adapted for the new Machine. Queue and SCB Buffers now anchored in Bus structure
20.02.01 0.3 prk own Timer removed, use Kernel.Timer instead, Watchdog commented out
Failures:
200: Invalid Target
201: Data Size > 64KB
202: TranslateVirtual, num = 0 for the cmd buffer
203: TranslateVirtual, num invalid for the range buffer
204: TranslateVirtual, num = 0 for the data buffer
Todos:
300: Command spans page boundary [obsolete]
*)
(*
ToDo:
2 Disconnection
2 Ultra handling in SetSync
3 use CHAR consts instead of Bits/SETs -> use memory IO always (port IO is not needed)
4 BusCleanup: free buffers
*)