diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/miniport/always | |
download | NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2 NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip |
Diffstat (limited to '')
24 files changed, 5117 insertions, 0 deletions
diff --git a/private/ntos/miniport/always/33c93.c b/private/ntos/miniport/always/33c93.c new file mode 100644 index 000000000..f44dc9fab --- /dev/null +++ b/private/ntos/miniport/always/33c93.c @@ -0,0 +1,827 @@ +/* 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" + +#include "33c93.h" + +#define ReadWDReg(HA,WDReg) (outb(HA->Ext->SBIC.WD33C93.WDSelPort, (WDReg)), inb(HA->Ext->SBIC.WD33C93.WDDataPort)) + +#ifndef ReadWDReg +unsigned const +ReadWDReg (const ADAPTER_PTR HA, const unsigned reg) +{ + + outb(HA->Ext->SBIC.WD33C93.WDSelPort, (WDReg)); + return inb(HA->IOBase + INWDDataOff); + +} +#endif + + + + +U8 REGPARMS +ReadTilStable (ADAPTER_PTR HA, unsigned Reg) +{ + U8 Stat1, Stat2; + + Stat2 = ReadWDReg(HA, Reg); + do { + + Stat1 = Stat2; + Stat2 &= ReadWDReg(HA, Reg); + Stat2 &= ReadWDReg(HA, Reg); + + } while (Stat1 != Stat2); + + return Stat1; + +} + + + +// Wait for WD command in progress to complete, then issue a new command: +#define SendWDCmd(WDSelPort, WDDataPort, WDCmd) {while (inb(WDSelPort) & (WD_Busy | WD_CIP)) ; \ + outb(WDSelPort, WDCMDReg); outb(WDDataPort, WDCmd); } + +#if !defined(SendWDCmd) +void const REGPARMS +SendWDCmd (IOHandle WDSelPort, IOHandle WDDataPort, unsigned WDCmd) +{ + + while (inb(WDSelPort) & (WD_Busy | WD_CIP)) ; // Spin on WD busy + + outb(WDSelPort, WDCMDReg); // Select command register + outb(WDDataPort, WDCmd); // Issue command + +} +#endif + + +int REGPARMS +WaitForDataReady (ADAPTER_PTR HA) +{ + unsigned stat; + unsigned long Spin=100000l; + + while ( ((((stat = inb(HA->Ext->SBIC.WD33C93.WDSelPort)) & WD_DBR) == 0) + || (stat & WD_CIP) ) && Spin--) { + + if (stat & (IntPending | CommandIGN)) + return -1; + + } + + if ((stat & WD_DBR) == 0) { // Fell out of loop because of spin loop exhaustion + + TRACE(0, ("WaitForDataReady(): Spun out waiting for data ready\n")); + return -1; + + } + + outb(HA->Ext->SBIC.WD33C93.WDSelPort, WDDataReg); + return 0; + +} + + + +int REGPARMS +WaitForWrite (const ADAPTER_PTR HA, const U8 Data) +{ + + if (WaitForDataReady(HA)) + return -1; + outb(HA->Ext->SBIC.WD33C93.WDDataPort, Data); + return 0; + +} + + + +int REGPARMS +WaitForRead (const ADAPTER_PTR HA, + U8 FAR *const Data) +{ + + if (WaitForDataReady(HA)) + return -1; + *Data = inb(HA->Ext->SBIC.WD33C93.WDDataPort); + return 0; + +} + + + +//#define XferInByte(HA,Data) (SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort, HA->Ext->SBIC.WD33C93.WDDataPort, WDXferInfo | WDSingleByte), WaitForRead(HA, Data)) +#if !defined(XferInByte) + +int REGPARMS +XferInByte (const ADAPTER_PTR HA, U8 FAR *Data) +{ + + SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort, HA->Ext->SBIC.WD33C93.WDDataPort, WDXferInfo | WDSingleByte); + return WaitForRead(HA, Data); + +} +#endif + + +//#define XferOutByte(HA,Data) (SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort, HA->Ext->SBIC.WD33C93.WDDataPort, WDXferInfo | WDSingleByte), WaitForWrite(HA, Data)) +#if !defined(XferOutByte) + +int REGPARMS +XferOutByte (const ADAPTER_PTR HA, const U8 Data) +{ + + SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort, HA->Ext->SBIC.WD33C93.WDDataPort, WDXferInfo | WDSingleByte); + return WaitForWrite(HA, Data); + +} +#endif + + + +unsigned +PIORead (ADAPTER_PTR const HA, + U8 FAR *Block, + unsigned Count) +{ + unsigned i; + + TRACE(5,("in2000: PIORead(): ")); + + for (i = 0; i < Count; i++) { + if (WaitForRead(HA, Block++)) + break; + } + TRACE(5, ("%d read bytes\n", i)); + return i; + +} + + + +unsigned +PIOWrite (ADAPTER_PTR HA, + U8 FAR *Block, + unsigned Count) +{ + unsigned i; + + for (i = 0; i < Count; i++) { + if (WaitForWrite(HA, *Block++)) + break; + } + return i; + +} + + + +static +PIOWriteBlk (ADAPTER_PTR HA, + U8 FAR *Block, + unsigned Count) +{ + unsigned i; + + outb(HA->Ext->SBIC.WD33C93.WDSelPort, WDCountReg); + outb(HA->Ext->SBIC.WD33C93.WDDataPort, 0); + outb(HA->Ext->SBIC.WD33C93.WDDataPort, Count >> 8); + outb(HA->Ext->SBIC.WD33C93.WDDataPort, Count); + + SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort, HA->Ext->SBIC.WD33C93.WDDataPort, WDXferInfo); /* Start data xfer */ + + for (i = 0; i < Count; i++) { + if (WaitForWrite(HA, *Block++)) + break; + } + return i; +} + + +void REGPARMS +Abort (ADAPTER_PTR HA) +{ + + SCSISendAbort(HA); + SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort, HA->Ext->SBIC.WD33C93.WDDataPort, WDSetAtnCmd); /* Set attention */ + +} + + +void +WD33C93_Reset (ADAPTER_PTR HA) +{ + int Divisor; + + /* Set freq devisor & default SCSI ID; must be set before reset */ + if (HA->Ext->SBIC.WD33C93.MHz >= 16) + Divisor = 4; + else if (HA->Ext->SBIC.WD33C93.MHz >= 12) + Divisor = 3; + else Divisor = 2; + + //IFreq = Internal freq and max xfer rate + HA->Ext->SBIC.WD33C93.IFreq = HA->Ext->SBIC.WD33C93.MHz / Divisor; + outb(HA->Ext->SBIC.WD33C93.WDSelPort, WDOwnIDReg); + outb(HA->Ext->SBIC.WD33C93.WDDataPort, (((Divisor - 2) & 3) << 6) | HA->SCSI_ID); + + critical(HA); + + /* Reset chip, then wait for reset complete interrupt */ + SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort, HA->Ext->SBIC.WD33C93.WDDataPort, WDResetCmd); + + while ((ReadTilStable(HA, WDAuxStatReg) & IntPending) == 0) + ; + ReadWDReg(HA, WDStatusReg); /* Clear the interrupt */ + + outb(HA->Ext->SBIC.WD33C93.WDSelPort, WDControlReg); + outb(HA->Ext->SBIC.WD33C93.WDDataPort, HaltPE); // Enable parity checking + + /* Set default selection timeout to 250 ms (x = ms * MHz / 80) */ + outb(HA->Ext->SBIC.WD33C93.WDSelPort, WDTimeoutReg); + outb(HA->Ext->SBIC.WD33C93.WDDataPort, ((25*HA->Ext->SBIC.WD33C93.MHz)+7) / 8); + + /* Allow reselections: */ + outb(HA->Ext->SBIC.WD33C93.WDSelPort, WDSourceReg); + outb(HA->Ext->SBIC.WD33C93.WDDataPort, EnableRSel); + + uncritical(HA); + +} + +int +WD33C93_Init (ADAPTER_PTR HA) +{ + + WD33C93_Reset(HA); + + /* Sync period in SCSI terms (nS/4) */ + // Rate(Hz) = IFreq. + // Period(ns) = 1,000,000,000 / Rate(Hz) == 1000/Rate(MHz) + // SCSI period (Period(ns)/2) == (1000/4)/Rate(MHz) + HA->Sync_Period = (((HA->Ext->SBIC.WD33C93.MHz >= 16) ? 500 : 1000)/4) / HA->Ext->SBIC.WD33C93.IFreq; + HA->Sync_Offset = 12; + TRACE(5, ("WD33C93_Init(): HA Sync. period set to: %d, offset set to %d\n", HA->Sync_Period, HA->Sync_Offset)); + + /* This is an 8-bit SCSI bus: */ + HA->Max_TID = 7; + return 0; + +} + + +// Set a devices adapter specific sync. value +LOCAL void REGPARMS +WD33C93UpdateSync (ADAPTER_PTR HA) +{ + + unsigned Cycles; + unsigned FastSCSI=0; // In case we're FAST SCSI on 33C93B + + /* Magic math: */ + if (HA->Ext->SBIC.WD33C93.MHz >= 16) { // Assume > 16MHz is "B" part + + // First calc. the period in nS for the 33C93 SCSI clock: + if ((unsigned)HA->CurrDev->Sync_Period < (200/4)) { + + TRACE(3, ("WD33C93UpdateSync(): Device is asking for fast SCSI: %d\n", (unsigned)HA->CurrDev->Sync_Period)); + FastSCSI = 0x80; // "B" part, < 200nS xfer period + Cycles = 2000/(2*HA->Ext->SBIC.WD33C93.MHz); + + } else { + + Cycles = 2000/(HA->Ext->SBIC.WD33C93.MHz); + + } + + TRACE(3, ("WD33C93UpdateSync(): Period/Cycle =%dnS\n", Cycles)); + + // Then calc. the SCSI xfer period by the 33C93 internal period for number of cycles: + Cycles = ((unsigned)HA->CurrDev->Sync_Period * 4) / Cycles; + TRACE(3, ("WD33C93UpdateSync(): Cycles/Xfer =%d\n", Cycles)); + + } else Cycles = ((unsigned)HA->CurrDev->Sync_Period * (4 * 2) * HA->Ext->SBIC.WD33C93.IFreq + 999) / 1000; + + if (Cycles >= 8) + Cycles = 0; + + HA->DevInfo[HA->CurrDev->SCSI_ID].HASync1 = ((Cycles & 7)<< 4) | HA->CurrDev->Sync_Offset | FastSCSI; + outb(HA->Ext->SBIC.WD33C93.WDSelPort, WDSyncReg); + outb(HA->Ext->SBIC.WD33C93.WDDataPort, HA->DevInfo[HA->CurrDev->SCSI_ID].HASync1); + TRACE(2, ("WD33C93UpdateSync(): HA Sync period set to: %02x\n", HA->DevInfo[HA->CurrDev->SCSI_ID].HASync1)); + +} + + + +void REGPARMS +Resel (ADAPTER_PTR HA, U8 MSG) +{ + + HA->ReqStarting = 0; // Don't accept starting command + + HA->Ext->SBIC.WD33C93.TID = ReadTilStable(HA, WDSourceReg); + + if ((HA->Ext->SBIC.WD33C93.TID & IDValid) + && (Reselect(HA, (U8)(HA->Ext->SBIC.WD33C93.TID & 0x7), (U8)(MSG & 0x7), 0) == 0)) { + + if (HA->DevInfo[HA->CurrDev->SCSI_ID].Flags.UseSync) { + + outb(HA->Ext->SBIC.WD33C93.WDSelPort, WDSyncReg); + outb(HA->Ext->SBIC.WD33C93.WDDataPort, HA->DevInfo[HA->CurrDev->SCSI_ID].HASync1); + + } else { + + outb(HA->Ext->SBIC.WD33C93.WDSelPort, WDSyncReg); + outb(HA->Ext->SBIC.WD33C93.WDDataPort, HA->Ext->SBIC.WD33C93.AsyncValue); + + } + + } else { + + TRACE(1,("Reselection rejected, TID == %02x, MSG == %02x\n", HA->Ext->SBIC.WD33C93.TID, MSG)); + LogMessage(HA, NILL, HA->Ext->SBIC.WD33C93.TID, MSG, MSG_BAD_RESEL, __LINE__); + + SCSISendReject(HA); + SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort, HA->Ext->SBIC.WD33C93.WDDataPort, WDSetAtnCmd); /* Set attention */ + + } +} + + + +static void REGPARMS +HandleMessageByte (ADAPTER_PTR HA) +{ + switch (Receive_Msg(HA, HA->Ext->SBIC.WD33C93.MI_Temp)) { + + case MI_SYNC_RESP: /* Response from sync req; update values */ + + WD33C93UpdateSync(HA); + break; /* All done */ + + + case MI_SYNC_REQ: /* got sync req; update values, and respond */ + + WD33C93UpdateSync(HA); + // Fall Through !! + + case MI_SEND_MSG: /* Msg in resulted in message out request: */ + + TRACE(4,("WD33C93_ISR(): Send message requested\n")); + SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort, HA->Ext->SBIC.WD33C93.WDDataPort, + WDSetAtnCmd); // Have a response msg, set attention + break; + + + case MSG_IDENTIFY: /* Identify? */ + + Resel(HA, HA->Ext->SBIC.WD33C93.MI_Temp); + break; + + + default: + + break; + + } + + SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort, HA->Ext->SBIC.WD33C93.WDDataPort, WDNegAckCmd); // Message received, negate ACK to signal acceptance + + +} + + + +void +WD33c93_ISR (ADAPTER_PTR HA) +{ + /* Remember, when defining automatics that SS may not equal DS, so + don't use pointers to automatics in ISRs. -- This is only a problem + in brain dead "real" mode environments. This is not a problem in + flat model systems. + + Q: Why is a processor which is limited to 1MB and uses segments in + "real" mode? Such a mode should be called "Bogus mode." A "real" + processor has none of these characteristics. + */ + + U32 S; + U8 Stat; + +#if defined(KEEP_STATS) + HA->Ext->SBICInterrupts++; +#endif + + ReadTilStable(HA, WDAuxStatReg); + Stat = ReadWDReg(HA, WDStatusReg); + + TRACE(4,("WD33c93_ISR(): WD status = %02x\n", Stat)); + if (Stat == 0xff) + return; + + if (HA->Ext->SBIC.WD33C93.State & WD_BLOCK_XFER) { + + HA->Service(HA_DATA_CMPLT, HA, (U32)0); + HA->Ext->SBIC.WD33C93.State &= ~WD_BLOCK_XFER; + + } + + + + /* See if this is a new bus phase interrupt (bit 0x08 set). If so, + mask off the most sig. nibble, and case on the new phase: */ + if (Stat & 0x08) + Stat &= WD_PHASE_MASK; + + switch (Stat) { + + case WD_STAT_RESET: /* Chip has reset; Who did that??? */ + case WD_STAT_RESETA: + + TRACE(1, ("33c93_ISR(): Bus reset detected\n")); + HA->ReqStarting = 0; + WD33C93_Reset(HA); + SCSIBusHasReset(HA); + break; + + + /* + The following are the bus phase changes; The most significant + nibble is masked off, since we are only interested in the new + bus phase. + */ + + case WD_MDATA_OUT: // Data out phase + case WD_MDATA_IN: // Data in phase + + if (HA->ReqCurrentCount == 0) { + + GetXferSegment(HA, HA->CurrReq, &HA->SGDescr, HA->ReqCurrentIndex, FALSE); + HA->ReqCurrentCount = HA->SGDescr.SegmentLength; + + } + + +#if defined(COMPOUND_CMD) + // If we are using compound commands, the only way we can leave compound mode is by a message interrupt, or a data interrupt + HA->Ext->SBIC.WD33C93.State &= ~WD_COMPOUND_CMD; +#endif + + if ( (((Stat & 1) != 0) && !ReqDataIn(HA->CurrReq)) // Phase is in, no req data + || (((Stat & 1) == 0) && !ReqDataOut(HA->CurrReq)) // Phase is out, no req data +#if defined(ReqNoData) + || ReqNoData(HA->CurrReq) // Req. wants no data +#endif + || HA->ReqCurrentCount == 0) { // No data left + + TRACE(0,("WD33C93_ISR(): Data xfer pad: flags = %x, CurrCount = %d, direction = %s\n", ReqFlags(HA->CurrReq), HA->ReqCurrentCount, ((Stat & 1) ? "In" : "Out") )); +// BreakPoint(HA); + + ReqAPIStatus(HA->CurrReq) = S_REQ_OVERRUN; + /* Do a single byte xfer pad: */ + if (Stat & 1) + XferInByte(HA, (U8 FAR *)&Stat); + else + XferOutByte(HA, (U8)Stat); + break; + + } + + TRACE(3,("WD33C93_ISR(): Data xfer of %ld bytes started\n", HA->ReqCurrentCount)); + +#if defined(NATIVE32) + + /* Set the XFER count register: */ + outb(HA->Ext->SBIC.WD33C93.WDSelPort, WDCountReg); + outb(HA->Ext->SBIC.WD33C93.WDDataPort, (U8)(HA->ReqCurrentCount / (long)0x10000)); + outb(HA->Ext->SBIC.WD33C93.WDDataPort, (U8)(HA->ReqCurrentCount / (long)0x100)); + outb(HA->Ext->SBIC.WD33C93.WDDataPort, (U8)HA->ReqCurrentCount); + +#else + + /* Set the XFER count register: */ + outb(HA->Ext->SBIC.WD33C93.WDSelPort, WDCountReg); + outb(HA->Ext->SBIC.WD33C93.WDDataPort, (((U8 FAR *)&HA->ReqCurrentCount)[2])); + outb(HA->Ext->SBIC.WD33C93.WDDataPort, (((U8 FAR *)&HA->ReqCurrentCount)[1])); + outb(HA->Ext->SBIC.WD33C93.WDDataPort, (((U8 FAR *)&HA->ReqCurrentCount)[0])); + +#endif + + HA->State.DataIn = (Stat & 1); /* Data in or out */ + S = HA->Service(HA_DATA_SETUP, HA, (U32)(Stat & 1)); + + /* Start the data transfer */ + SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort, HA->Ext->SBIC.WD33C93.WDDataPort, WDXferInfo); + + if (S == HAServiceResponse_UseByteIO) { + + S = (Stat & 1) ? + PIORead(HA, + (U8 FAR *)&(((U8 FAR *)(ReqDataPtr(HA->CurrReq)))[(unsigned)HA->ReqCurrentIndex]), + (unsigned)HA->ReqCurrentCount) + : PIOWrite(HA, + (U8 FAR *)&(((U8 FAR *)(ReqDataPtr(HA->CurrReq)))[(unsigned)HA->ReqCurrentIndex]), + (unsigned)HA->ReqCurrentCount); + HA->ReqCurrentIndex += S; + HA->ReqCurrentCount -= S; + TRACE(4,("WD33C93_ISR(): Xfer of %d bytes complete\n", S)); + + } else { + + HA->State.DataXfer = 1; + HA->Ext->SBIC.WD33C93.State |= WD_BLOCK_XFER; + + } + break; + + + case WD_MCOMMAND: /* Command phase */ + + TRACE(3,("WD33C93_ISR(): command phase\n")); + + if (HA->DevInfo[HA->CurrDev->SCSI_ID].Flags.UseSync) { // Sync. xfer been established? + + outb(HA->Ext->SBIC.WD33C93.WDSelPort, WDSyncReg); + outb(HA->Ext->SBIC.WD33C93.WDDataPort, HA->DevInfo[HA->CurrDev->SCSI_ID].HASync1); + + } else { + + outb(HA->Ext->SBIC.WD33C93.WDSelPort, WDSyncReg); + outb(HA->Ext->SBIC.WD33C93.WDDataPort, HA->Ext->SBIC.WD33C93.AsyncValue); + + } + + PIOWriteBlk(HA, ReqCDB(HA->CurrReq), ReqCDBLen(HA->CurrReq)); + break; + + + + case WD_STAT_BAD_STATUS: /* Status phase w/ parity */ + + TRACE(2, ("WD33C93_ISR(): Parity error detected\n")); + SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort, HA->Ext->SBIC.WD33C93.WDDataPort, WDSetAtnCmd); + HA->Ext->MO_Buff[HA->Ext->MO_Count++] = MSG_INIT_ERROR; + SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort, HA->Ext->SBIC.WD33C93.WDDataPort, WDNegAckCmd); + LogMessage(HA, HA->CurrReq, HA->CurrDev->SCSI_ID, 0, MSG_PARITY, __LINE__); + // Fall through + + case WD_MSTATUS: /* status phase */ + + XferInByte(HA, (U8 FAR *)&Stat); + if (ReqAPIStatus(HA->CurrReq) == S_REQ_STARTED || ReqAPIStatus(HA->CurrReq) == S_REQ_ACCEPTED) + ReqAPIStatus(HA->CurrReq) = TargetStatus(Stat); + + // Update the saved index to reflect the number of bytes actually + // transfered: + ReqSavedIndex(HA->CurrReq) = HA->ReqCurrentIndex; + + TRACE(3, ("WD33C93_ISR(): status phase %02x\n", Stat)); + break; + + + /* + A disconnect will occur either as an intermediate disconnect, + followed by a later reselect, or it happens after command + completion. If there is a request in progress, then a later + reselect is expected. + + After cleaning up as necessary, the first request for the next + pending target is initiated. + */ + case WD_MMSG_OUT: // Message out phase + + TRACE(4,("MsgOutP: sending message %02x\n", HA->Ext->MO_Buff[HA->Ext->MO_Index])); + + if (HA->Ext->MO_Count) { // Any messages waiting? + + PIOWriteBlk(HA, HA->Ext->MO_Buff, HA->Ext->MO_Count); // Then send them + + } else + XferOutByte(HA, MSG_NOP); // Otherwise, send a no-op + + HA->Ext->MO_Index = HA->Ext->MO_Count = 0; // Reset the Message Out counters + +#if defined(COMPOUND_CMD) + // If we are using compound commands, the only way we can leave compound mode is by a message interrupt, or a data interrupt + HA->Ext->SBIC.WD33C93.State &= ~WD_COMPOUND_CMD; +#endif + + break; + + + + case WD_MMSG_IN: /* Message in phase */ + + if (XferInByte(HA, &HA->Ext->SBIC.WD33C93.MI_Temp)) // Read the message byte + TRACE(3,("WD33C93_ISR(): WD_MSG_IN failed: %02x\n", inb(HA->Ext->SBIC.WD33C93.WDSelPort))); + if (HA->ReqStarting) // Don't know yet if this message is for the staring request + HA->ReqStarting++; + TRACE(3, ("WD33C93_ISR(): Message in phase: %02x\n", HA->Ext->SBIC.WD33C93.MI_Temp)); + /* We should next get a WD_STAT_XFER_PAUSED (0x20) state, process the message there */ + +#if defined(COMPOUND_CMD) + // If we are using compound commands, the only way we can leave compound mode is by a message interrupt, or a data interrupt + HA->Ext->SBIC.WD33C93.State &= ~WD_COMPOUND_CMD; +#endif + + break; + + + + case WD_STAT_SELECT_CMPLT: /* Select complete */ + + break; + + + + /* + + On reselection, get the reselecting target ID. From there, get + the first request structure for that ID, and verify that a + reselection is pending. If a proper disconnect occured, then + the disconnected request is the first on the list for that + target ID. If reselection is not pending, send an abort to the + reselecting target If a request was started, but reselection + occurred out from under it, clear the ReqStarting flag. If at + the end of the interrupt, the flag is non-zero, it is + decremented. If the flag decrements to zero, the request will + be flagged as accepted (by incrementing the command pointer). + If the decrement does not set the flag to zero, then the command + was just started by the interrupt being processed, so we wait + for the next interrupt to occur (with the flag set to 1). + + */ + /* + + The select and transfer command has completed, and therefore, + the request is complete. Retreive the command status into the + request structure, de-queue the request, and notify the + requestor. + + */ + + case WD_STAT_SandT_CMPLT: // Select and transfer complete + + HA->Ext->SBIC.WD33C93.State |= WD_COMPOUND_CMPLT; + ReqAPIStatus(HA->CurrReq) = TargetStatus(ReadTilStable(HA, WDTarLUNReg)); + ReqDone(HA, HA->CurrReq); + break; + + + case WD_STAT_SAVE_PTR: /* Save data pointer */ + + TRACE(4, ("WD33C93_ISR(): Saved data pointer status received\n")); + HA->Ext->SBIC.WD33C93.MI_Temp = MSG_SAVE_PTR; + + /* Fall through */ + case WD_STAT_XFER_PAUSED: /* Paused w/ ACK (message in) */ + + HandleMessageByte(HA); + break; + + + case WD_STAT_BAD_DISC: // Unexpected bus free + + ReqAPIStatus(HA->CurrReq) = S_AD_FREE; + ReqDone(HA, HA->CurrReq); + BusFree(HA, 2); + break; + + + case WD_STAT_SEL_TO: /* Select timeout */ + + ReqAPIStatus(HA->CurrReq) = S_REQ_NOTAR; // Target not responding + ReqDone(HA, HA->CurrReq); + BusFree(HA, 2); + break; + + + case WD_STAT_RESELECTED: /* Reselection */ + + HA->ReqStarting = 0; /* Don't accept starting command */ + HA->State.Busy = 1; + + // The actual attachment to a request will be done when we get the + // identify message + TRACE(3,("WD33c93_ISR(): Reselect phase\n")); + + do { + + HA->Ext->SBIC.WD33C93.TID = ReadTilStable(HA, WDSourceReg); + + } while ((HA->Ext->SBIC.WD33C93.TID & IDValid) == 0); + + + + TRACE(3,("WD33c93_ISR(): Reselect, TID = 0x%02x\n", HA->Ext->SBIC.WD33C93.TID)); + break; + + + case WD_STAT_RESELECTED_A: // Advanced mode reselection; unexpected, but has been seen + + HA->ReqStarting = 0; /* Don't accept starting command */ + HA->State.Busy = 1; + + // The actual attachment to a request will be done when we get the + // identify message + TRACE(3,("WD33c93_ISR(): Reselect phase\n")); + + do { + + HA->Ext->SBIC.WD33C93.TID = ReadTilStable(HA, WDSourceReg); + + } while ((HA->Ext->SBIC.WD33C93.TID & IDValid) == 0); + + TRACE(0, ("WD33C93_ISR(): Unusual advanced mode reselect; TID = 0x%02x, LUN = 0x%02x\n", HA->Ext->SBIC.WD33C93.TID, HA->Ext->MI_Buff[0])); + TRACE(3, ("WD33c93_ISR(): Reselect, TID = 0x%02x\n", HA->Ext->SBIC.WD33C93.TID)); + + HA->Ext->SBIC.WD33C93.MI_Temp = ReadWDReg(HA, WDDataReg); + HandleMessageByte(HA); + break; + + + case WD_STAT_SELECTED: /* Selected */ + case WD_STAT_SELECTED_ATN: /* Selected w/ATN */ + + SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort, + HA->Ext->SBIC.WD33C93.WDDataPort, + WDDisconnectCmd); /* disconnect */ + break; + + + case WD_STAT_DISCONNECT: /* Normal disconnect */ + + /* + If there is no "CurrReq", then the request has been completed through + normal Status and message phases (Status for completion, message for + disconnect). + + If the WD "compound" (level II) commands are being used, then the + disconnect interrupt will ccur with "CurrReq" still set. In this + case, it is a normal disconnect, and the status and message bytes + should be examined here. + */ + + if ((HA->CurrReq == NILL) || ((HA->Ext->SBIC.WD33C93.State & WD_COMPOUND_CMD) && (HA->Ext->SBIC.WD33C93.State & WD_COMPOUND_CMPLT))) { + + TRACE(3,("WD33C93_ISR(): Expected disconnect\n")); + + } else { + + if (ErrorClass(ReqAPIStatus(HA->CurrReq)) !=TargetClass) { + + // The request status is not of target class, so we have not seen a status phase + TRACE(3, ("WD33C93_ISR(): Unexpected disconnect\n")); + ReqAPIStatus(HA->CurrReq) = S_AD_FREE; // Unexpected bus free + + } else { + + // We have seen a status phase, so this is an expected bus free + TRACE(3,("WD33C93_ISR(): Expected disconnect\n")); + + } + + ReqDone(HA, HA->CurrReq); + + } + HA->State.Busy = 0; // Mark the adapter as free, to allow new requests to start + BusFree(HA, 2); + break; + + + case WD_STAT_PARITY: + + SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort, HA->Ext->SBIC.WD33C93.WDDataPort, WDSetAtnCmd); /* Set attention */ + // Fall Through + + case WD_STAT_PARITY_ATN: + + TRACE(2, ("WD33C93_ISR(): Parity error detected\n")); + LogMessage(HA, HA->CurrReq, HA->CurrDev->SCSI_ID, 0, MSG_PARITY, __LINE__); + HA->Ext->MO_Buff[HA->Ext->MO_Count++] = MSG_INIT_ERROR; + SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort, HA->Ext->SBIC.WD33C93.WDDataPort, WDNegAckCmd); + break; + + + default: + +// LogMessage(HA, HA->CurrReq, 0, 0, MSG_INTERNAL_ERROR, Stat); + TRACE(0, ("WD33C93_ISR(): Unknown status 0x%02x\n", Stat)); +// BreakPoint(HA); + HA->Service(HA_RESET_BUS, HA, (U32)0); + break; + + } + AcceptReq(HA); +} diff --git a/private/ntos/miniport/always/33c93.h b/private/ntos/miniport/always/33c93.h new file mode 100644 index 000000000..f2b171052 --- /dev/null +++ b/private/ntos/miniport/always/33c93.h @@ -0,0 +1,145 @@ +/* Copyright (C) 1991, 1992 by Always Technology Corporation. + This module contains information proprietary to + Always Technology Corporation, and is be treated as confidential. +*/ + +#ifndef __33C93_H__ +#define __33C93_H__ + +#define WDOwnIDReg 0 /* (R/W) */ +#define WDCDBSizeReg 0 /* (R/W) */ +#define WDControlReg 1 /* (R/W) */ +#define WDTimeoutReg 2 +#define WDCDBReg 3 +#define WDTarLUNReg 0xf /* Write: Sets target LUN; Read: Target status */ + /* byte from Select-and-Transfer commands */ +#define WDPhaseReg 0x10 /* WD Current phase */ +#define WDSyncReg 0x11 /* Sync. xfer configuration */ +#define WDCountReg 0x12 /* Xfer count msb, mid and lsb follow */ +#define WDDestIDReg 0x15 /* Destination SCSI ID for Sel or Resel */ +#define WDSourceReg 0x16 /* Who selected us; enable sel/resel */ +#define WDStatusReg 0x17 /* WD Command status */ +#define WDCMDReg 0x18 /* WD COmmand code register */ +#define WDDataReg 0x19 /* WD Data xfer register */ +#define WDAuxStatReg 0x1f /* Indirect access to aux. status */ + +/* Aux Status bits: */ +#define WD_DBR 0x1 /* Data buffer ready */ +#define WD_Parity 0x2 /* Parity error */ +#define WD_CIP 0x10 /* Command in progress */ +#define WD_Busy 0x20 /* Level II command in progress */ +#define CommandIGN 0x40 // Last command ignored +#define IntPending 0x80 // Interrupt pending + +/* Own ID register */ +#define DefualtHostID 0x7 /* Own SCSI ID */ +#define EnADV 0x8 /* Enable advanced features */ +#define EnHParity 0x10 /* Enable host parity */ +#define FreqSel 0xc0 /* Input frequency select */ + +/* Western Digital control register */ +#define HaltPE 0x1 /* Halt on parity error */ +#define HaltATN 0x2 /* Halt on attention */ +#define EnableIDI 0x4 /* enable intermediate disc. inter. */ +#define EnableEDI 0x8 /* Enable ending disconnect inter. */ +#define EnableHHP 0x10 /* Enable halt on host parity */ +#define DMAModeMask 0xe0 /* DMA Mode select */ +#define DMAPIO 0x00 /* DMA mode: Polled I/O */ +#define DMABurst 0x20 /* DMA mode: Burst DMA */ +#define DMABus 0x40 /* DMA mode: 33C93 BUS mode */ +#define DMAStd 0x80 /* DMA mode: standard async. handshake */ + +/* Target LUN register */ +#define WDTargetLUNMask 0x7 /* LUN of target */ +#define DisconOK 0x40 /* Allow disconnects */ +#define Valid 0x80 /* LUN fieldis valid */ + +/* Destination ID register */ +#define DestID 0x7 /* Destination ID */ +#define DataReadDir 0x40 /* Data phase direction 1=Read */ +#define EnableSCC 0x80 /* Enable selct command chain */ + +/* Source ID register */ +#define SourceID 0x7 /* Source ID */ +#define IDValid 0x8 /* Source ID valid */ +#define DisSelPar 0x20 /* Disable sel/resel parity */ +#define EnableSel 0x40 /* Enable selection */ +#define EnableRSel 0x80 /* Enable reselection */ + + + +/* WD Status, read from registr 0x17 */ +//#define SubCode 0xf /* WD Status code */ +//#define StatusCode 0xf0 /* WD Status */ +#define WD_STAT_RESET 0x00 /* Reset received */ +#define WD_STAT_RESETA 0x01 /* Reset in advanced mode */ +#define WD_STAT_RESEL_OK 0x10 /* Reselct command OK */ +#define WD_STAT_SELECT_CMPLT 0x11 // Select command completed successfully +#define WD_STAT_SandT_CMPLT 0x16 // Select and xfer completed OK +#define WD_STAT_XFER_PAUSED 0x20 +#define WD_STAT_BAD_DISC 0x41 // Unexpected disconnect (bus free) +#define WD_STAT_SEL_TO 0x42 // Selection timeout +#define WD_STAT_PARITY 0x43 // A parity error caused the xfer to terminate, no atn +#define WD_STAT_PARITY_ATN 0x44 // A parity error caused the xfer to terminate, atn asserted +#define WD_STAT_SAVE_PTR 0x21 // A save data pointers during a S & T +#define WD_STAT_BAD_STATUS 0x47 // An incorrect status byte +#define WD_STAT_RESELECTED 0x80 // A device has reselected us +#define WD_STAT_RESELECTED_A 0x81 // Been reselected in advanced mode +#define WD_STAT_SELECTED 0x82 // We have been selected +#define WD_STAT_SELECTED_ATN 0x83 // "" with ATN +#define WD_STAT_DISCONNECT 0x85 /* Disconnect occured */ + +/* Masked phase bits, makes use of fact that phase changes always have the 0x08 bit set */ +#define WD_PHASE_MASK 0x0f /* Mask for new phase */ +#define WD_MDATA_OUT 0x08 /* Masked-- Data out phase */ +#define WD_MDATA_IN 0x09 +#define WD_MCOMMAND 0x0a +#define WD_MSTATUS 0x0b +#define WD_MMSG_OUT 0x0e +#define WD_MMSG_IN 0x0f + + +/* WD Commands 0x */ +/* Level I */ +#define WDResetCmd 0 +#define WDAbortCmd 1 +#define WDSetAtnCmd 2 +#define WDNegAckCmd 3 +#define WDDisconnectCmd 4 +#define WDStatCmpltCmd 0xd /* Send Status and Command complete */ +#define WDSetIDICmd 0xf + +/* Level II */ +#define WDReselCmd 5 +#define WDSelATNCmd 6 /* Select w/ATN */ +#define WDSelCmd 7 /* Select w/o ATN */ +#define WDSelATNXCmd 8 /* Select w/ATN and transfer */ +#define WDSelXCmd 9 /* Select and transfer */ +#define WDRselRcvCmd 0xa /* Reselect and receive */ +#define WDRselSndCmd 0xb /* Reselect and send data */ +#define WDWaitRcvCmd 0xc /* Wait for select and receive */ +#define WDSendDiscCmd 0xe /* Send discconect message */ +#define WDRcvCmdCmd 0x10 /* Receive command */ +#define WDRcvDataCmd 0x11 /* Receive data */ +#define WDRcvMsgCmd 0x12 /* Receive message out */ +#define WDRcvUnspecCmd 0x13 /* Receive unspecified data */ +#define WDSendStatCmd 0x14 /* Send status */ +#define WDSendDataCmd 0x15 +#define WDSendMsgINCmd 0x16 /* Send message in */ +#define WDSendUnspecCmd 0x17 /* Send unspecified info */ +#define WDXlateAddrCmd 0x18 /* Translate address */ +#define WDXferInfo 0x20 /* Transfer info */ +#define WDSingleByte 0x80 /* Single byte xfer mask for xfer commands */ + + + +/* State bits for the state field in the wd33c93s struct: + (see wd33c93s.h) +*/ + +#define WD_NO_STATE 0x00 /* Non-descript state */ +#define WD_BLOCK_XFER 0x01 /* Doing a block xfer */ +#define WD_COMPOUND_CMD 0x02 /* Using WD's compound command */ +#define WD_COMPOUND_CMPLT 0x04 // WD Command complete interrupt seen + +#endif /* __33C93_H__ */ diff --git a/private/ntos/miniport/always/33c93s.h b/private/ntos/miniport/always/33c93s.h new file mode 100644 index 000000000..3cafe0cbb --- /dev/null +++ b/private/ntos/miniport/always/33c93s.h @@ -0,0 +1,26 @@ +/* Copyright (C) 1991, 1992 by Always Technology Corporation. + This module contains information proprietary to + Always Technology Corporation, and is be treated as confidential. +*/ + +#ifndef __33C93S_H__ +#define __33C93S_H__ + +#define USES33C93 + +struct WD33C93S { + + IOHandle WDSelPort; /* IO address of select/status register */ + IOHandle WDDataPort; /* IO address on this board for data port */ + + U8 MHz; /* Ext. clock freq. */ + U8 IFreq; /* Internal freq (X-clock/clock divisor) */ + U8 AsyncValue; /* Board sync. xfer value for async xfers */ + U8 State; + U8 MI_Temp; /* Temp holding register for received msgs */ + U8 TID; /* Target ID of reselection */ + + }; + + +#endif /* __33C93S_H__ */ diff --git a/private/ntos/miniport/always/adapters.c b/private/ntos/miniport/always/adapters.c new file mode 100644 index 000000000..6e778adbe --- /dev/null +++ b/private/ntos/miniport/always/adapters.c @@ -0,0 +1,94 @@ +/* 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" + + +#if defined(AL7000) + extern int Find_AL7000(ADAPTER_PTR HA, unsigned *Context); +#endif + +#ifdef AL4000H + extern int Find_AL4000H(ADAPTER_PTR HA, unsigned *Context); +#endif + +#ifdef IN2000 + extern int Find_IN2000(ADAPTER_PTR HA, unsigned *Context); +#endif + +#ifdef AL4000I + extern int Find_AL4000I(ADAPTER_PTR HA, unsigned *Context); +#endif + +#ifdef NCREVAL /* Emulex FAS216 eval unit */ + extern int Find_NCR_Eval(ADAPTER_PTR HA, unsigned *Context); +#endif + + + +static int ((*HA_List[])(ADAPTER_PTR HA, unsigned *Context)) = { + +#ifdef AL4000H + Find_AL4000H, /* Host side AL4000 code */ +#endif + +#if defined(AL7000) + Find_AL7000, +#endif + +#ifdef IN2000 + Find_IN2000, +#endif + +#ifdef AL4000I + Find_AL4000I, /* AL4000 imbedded firmware */ +#endif + +#ifdef NCREVAL /* NCR 53C94 eval board */ + Find_NCR_Eval, +#endif + + NULL}; + + + +/* + + This procedure is repeatedly called to find all adapters. It searches the list of all adapters, calling +their find routine until an adapter is located. It is passed a pointer to an int (Context), which is zero on +the first call. The find routine updates the Context to a value it can use to restart the search. Only one +adapter is found per call. Subsequent adapters are found on later calls. An adapters find routine will be +called repeatedly, until it returns a zero, which means it found no additional adapters. When an adapter is +found, the passed adapter structure (HA) is filled in, and a value of 1 is returned. + + */ + +int +Adapter_Init (ADAPTER_PTR HA, unsigned *Context) +{ + unsigned i=(*Context) >> 8, j=(*Context) & 0xff; + + /* Step through the list of adapter find routines to find all adapters */ + while (HA_List[i] != NULL) { + + TRACE(4, ("Adapter_Init(): Calling find routine at %x for adapter %x, Context = %x\n", HA_List[i], HA, *Context)); + if ((HA_List[i])(HA, &j)) { + + *Context = (i << 8) | j; + TRACE(4, ("Adapter_Init(): Adapter found, new context = %x\n", *Context)); + return 1; + + } + + i++; + j = 0; + + } + return 0; +} diff --git a/private/ntos/miniport/always/adapters.h b/private/ntos/miniport/always/adapters.h new file mode 100644 index 000000000..69e73ab2c --- /dev/null +++ b/private/ntos/miniport/always/adapters.h @@ -0,0 +1,63 @@ +#ifndef __ADAPTERS_H__ +#define __ADAPTERS_H__ + +#ifdef IN2000 +#include "in2000s.h" +#endif + +#ifdef AL4000h +#include "al4000hs.h" +#endif + +#ifdef AL4000I +#include "al4000is.h" +#endif + +#ifdef NCREVAL +#include "ncrevals.h" +#endif + +#ifdef AL7000 +#include "al7000s.h" +#endif + +#ifdef EVAL710 +#define USES710 +#include "eval7x0s.h" +#endif + +union AdapterU { +#ifdef IN2000 + struct IN2000S IN2000U; +#endif /* IN2000 */ +#ifdef AL4000 + struct AL4000HS AL4000HU; +#endif +#ifdef AL4000I /* AL4000 on board scsi interface */ + struct AL4000IS AL4000IU; +#endif +#if defined(AL7000) + struct AL7000S AL7000U; +#endif +}; + +union SBICU { +#ifdef USESCDV + struct CDVS CDV; +#endif + +#ifdef USES33C93 + struct WD33C93S WD33C93; +#endif + +#ifdef USES53C94 + struct NCR53C94S NCR53C94; +#endif +#if defined(USES710) || defined(USES720) + struct NCR53c7x0S NCR53C7x0; +#endif +}; + +extern int Adapter_Init(ADAPTER_PTR HA, unsigned *Context); + +#endif diff --git a/private/ntos/miniport/always/always.rc b/private/ntos/miniport/always/always.rc new file mode 100644 index 000000000..68f021b74 --- /dev/null +++ b/private/ntos/miniport/always/always.rc @@ -0,0 +1,12 @@ +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "Always Technology SCSI Controller Driver" +#define VER_INTERNALNAME_STR "always.sys" +#define VER_ORIGINALFILENAME_STR "always.sys" + +#include "common.ver" + diff --git a/private/ntos/miniport/always/api.h b/private/ntos/miniport/always/api.h new file mode 100644 index 000000000..61257ff7b --- /dev/null +++ b/private/ntos/miniport/always/api.h @@ -0,0 +1,76 @@ +/* Copyright (C) 1991, 1992 by Always Technology Corporation. + This module contains information proprietary to + Always Technology Corporation, and should be treated as confidential. + */ + +#ifndef __API_H__ +#define __API_H__ + + +/* Classes of error conditions */ +#define RequestClass 0x000 +#define AdapterClass 0x100 +#define TargetClass 0x200 +#define SystemClass 0x300 +#define ErrorClass(Error) ((Error) & 0xff00) +#define ErrorCode(Error) ((Error) & 0x00ff) +#define TargetStatus(Status) (TargetClass | (unsigned)Status) + + +/* Codes by class: Request Class */ +#define S_REQ_ACCEPTED RequestClass + 0x00 // Request accepted and queued +#define S_REQ_STARTED RequestClass + 0x01 // Request started execution +#define S_REQ_ABORT RequestClass + 0x02 // Request was aborted via abort command +#define S_REQ_OPCODE RequestClass + 0x03 // Request has bad operation code +#define S_REQ_REQUEST RequestClass + 0x04 // Request is otherwise malformed +#define S_REQ_BADHA RequestClass + 0x05 // Bad adapter identifier +#define S_REQ_OVERRUN RequestClass + 0x06 // The target requested to transfer more data than available +#define S_REQ_NOTAR RequestClass + 0x07 // The requested target is not responding +#define S_REQ_BADTAR RequestClass + 0x08 // The SCSI ID is out of range for this adapter +#define S_REQ_BADLUN RequestClass + 0x09 // The SCSI LUN is out of range for this adapter + + +/* Codes by class: Adapter Class */ +#define S_AD_OFF AdapterClass + 0x00 // Adapter offline +#define S_AD_BUSY AdapterClass + 0x01 // Adapter busy or full +#define S_AD_FREE AdapterClass + 0x02 // Unexpected bus free +#define S_AD_PHASE AdapterClass + 0x03 // Unexpected phase +#define S_AD_RESET AdapterClass + 0x04 // Request aborted due to reset +#define S_AD_AUTOSENSE_OK AdapterClass + 0x05 // Req received OK autosense data +#define S_AD_AUTOSENSE_FAIL AdapterClass + 0x05 // Req failed to receive autosense data + + +/* Codes by class: Target Class (Target status phase) */ +#define S_TAR_NOERROR TargetClass + 0x00 // Target completed request w/no error +#define S_TAR_CHECKCOND TargetClass + 0x02 // Request completed with Check condition status +#define S_TAR_BUSY TargetClass + 0x08 // Device busy +#define S_TAR_QUEUEFULL TargetClass + 0x28 // Target queue full + + +/* Codes by class: System Class */ + + +// Last internal S_xx codes, for consistancy checks: +#define S_LAST_S_REQ 0x09 +#define S_LAST_S_AD 0x06 +#define S_LAST_S_SYS 0x00 + +typedef enum {NonTerminal, Terminal, DetectTerminal} TerminateCode; +typedef enum {NotSenseable, Senseable} AutosenseCode; + +typedef U16 APIStatus; + +extern int API_Init(void); +extern void APISetStatus(IO_REQ_PTR Req, APIStatus Status, TerminateCode Terminal, AutosenseCode IsSenseable); + +#if !defined(APINotifyReset) +extern void APINotifyReset(ADAPTER_PTR HA); +#endif + +#if !defined(APIFindDev) // See if it's already a macro +extern DEVICE_PTR APIFindDev(const ADAPTER_PTR HA, const U16 TID, const U16 LUN); +#endif + +extern void GetXferSegment(const ADAPTER_PTR HA, IO_REQ_PTR Req, SegmentDescr *SGDescr, U32 Offset, BOOLEAN DemandPhysical); + +#endif /* __API_H__ */ diff --git a/private/ntos/miniport/always/apiscsi.h b/private/ntos/miniport/always/apiscsi.h new file mode 100644 index 000000000..b033273fd --- /dev/null +++ b/private/ntos/miniport/always/apiscsi.h @@ -0,0 +1,170 @@ +/* Copyright (C) 1991, 1992 by Always Technology Corporation. + This module contains information proprietary to + Always Technology Corporation, and should be treated as confidential. + */ + +#ifndef __SCSI_H__ +#define __SCSI_H__ + +typedef U8 SCSI24[3]; +typedef U8 SCSI32[4]; + + +/* Standard SCSI commands and codes and things: */ + +#define STATUS_GOOD 0x00 // Request completed OK +#define STATUS_CKCOND 0x02 // Check condition +#define STATUS_CONDMET 0x04 // Search condition met +#define STATUS_BUSY 0x08 // Device busy +#define STATUS_INTGOOD 0x10 // Intermediate good condition +#define STATUS_INTCONDMET 0x14 // Intermediate condition met +#define STATUS_RESCONF 0x18 // Reservation conflict +#define STATUS_QUEUEFULL 0x28 // Request queue full + +#define MSG_IDENTIFY 0x80 +#define MSG_ALLOW_DISC 0x40 +#define MSG_LUN_MASK 0x07 + +/* Extended messages (Command 1): */ +#define MSG_EXTD_MSG 0x1 +#define XMSG_MODIFY_PTR 0x00 // Modify data pointers +#define XMSG_SYNC_REQ 0x01 +#define XMSG_EXTD_IDENT 0x02 /* Pre-SCSI 2 */ +#define XMSG_WIDE_REQ 0x03 + +/* Single byte messages (0, 0x02-0x1f) */ +#define MSG_COMPLETE 0x00 /* Command complete */ +#define MSG_SAVE_PTR 0x02 /* Save data pointers */ +#define MSG_RESTORE_PTR 0x03 /* Restore from saved data pointers */ +#define MSG_DISCONNECT 0x04 /* Target is temp. disconnecting */ +#define MSG_INIT_ERROR 0x05 /* Initiator detected error */ +#define MSG_ABORT 0x06 /* Abort all active target operations */ +#define MSG_REJECT 0x07 /* Last message is rejected */ +#define MSG_NOP 0x08 /* No operation */ +#define MSG_MSG_PARITY 0x09 /* Parity error on last message */ +#define MSG_LINK_CMPLT 0x0a /* Linked command complete */ +#define MSG_LINKF_CMPLT 0x0b /* Linked command with flag complete */ +#define MSG_DEVICE_RESET 0x0c /* Reset device */ +#define MSG_ABORT_TAG 0x0d /* Abort current I/O */ +#define MSG_CLEAR_Q 0x0e /* Clear queue */ +#define MSG_INIT_RECOVERY 0x0f +#define MSG_REL_RECOVERY 0x10 +#define MSG_TERM_IO 0x11 + +/* Two byte messages */ +#define MSG_SIMPLEQUEUE 0x20 /* Simple tage queue message */ +#define MSG_HEADQUEUE 0x21 /* Head of tag queue */ +#define MSG_ORDEREDQUEUE 0x22 /* Ordered tag queue */ +#define MSG_IGNORERES 0x23 /* Ignore wide residue */ + + +/* Response codes from Receive_Msg: (in addition to standard messages): */ +#define MI_MORE 0xf0 /* More message bytes expected */ +#define MI_SEND_MSG 0xf1 /* Response is in MO buffer; goto msg out phase */ +#define MI_SYNC_RESP 0xf2 /* Got a response from our sync. request; update values */ +#define MI_SYNC_REQ 0xf3 /* Got a sync. request; update ptrs; send MSG OUT buffer */ + +struct RSenseStruct { + unsigned ErrorCode:7; + unsigned Valid:1; + + U8 Res1; + + unsigned SenseKey:4; + unsigned res2:4; + + U8 Info[4]; + U8 AddlLen; + U8 CmdInfo[4]; + U8 AddlCode; + U8 AddlQual; + U8 res3, res4; + }; + + +struct MSenseStruct { + + U8 DataLen; + U8 MediumType; + + unsigned res1:7; + unsigned WProtect:1; + + U8 BlockDiscLen; + U8 DensityCode; /* Start of default block descriptor */ + SCSI24 BlockCount; + U8 res2; + SCSI24 BlockLen; +}; + + +struct CapacityStruct { + SCSI32 LastBlock; + SCSI32 BlockLen; +}; + + + +struct InquiryStruct { + + unsigned PeriphDevType:5; // See DT_ codes below + unsigned PeriphQual:3; + + unsigned DTQual:7; // Device type qualifier + unsigned RMB:1; // Removable media bit + + unsigned ANSIVersion:3; // ANSI version of SCSI supported (s.b. 1 or 2) + unsigned ECMAVersion:3; + unsigned ISOVersion:2; + + unsigned ResponseFormat:4; + unsigned Res1:3; + unsigned AENC:1; // Device can generate (periph)/accept (processor) aysync. event notifications + + U8 AddlLength; // Number of additional bytes following + + U8 Res2; + U8 Res3; + + unsigned SoftRes:1; // Device uses soft resets + unsigned CmdQueue:1; // Device supports command queuing + unsigned Res4:1; + unsigned Linked:1; // Device supports linked commands + unsigned Sync:1; // Device supports synchronous xfers + unsigned WBus16:1; // Device supports 16 bit wide SCSI + unsigned WBus32:1; // Device supports 32 bit wide SCSI + unsigned RelAddr:1; // Device supports relative addressing + + U8 VendorID[8]; // Vendor name (ASCII) + U8 ProductID[16]; // Product name (ASCII) + U8 Revision[4]; // Revision, ASCII or binary + U8 AddlInfo[1]; // Additional information + +}; + +// device type codes from inquiry command: +#define DT_DIRECT 0 // Direct access storage device (disk ...) +#define DT_SEQUENTIAL 1 // Sequential (Tape, ...) +#define DT_PRINTER 2 // guess... +#define DT_PROCESSOR 3 +#define DT_WORM 4 +#define DT_ROM 5 // CD-ROM, other rad only direct access device +#define DT_SCANNER 6 +#define DT_OPTMEM 7 // Other types of optical memory +#define DT_CHANGER 8 // Changer (tape, cartridge, disk, ...) +#define DT_COMM 9 // Communications device +#define DT_REMOVEABLE 0x80 // Removable media qualifier +#define DT_NOTPRESENT 0x1f // LUN not present or not supported + +#define SCSIIn 1 +#define SCSIOut 0 + +extern void BusFree(ADAPTER_PTR HA, int StartLevel); +extern void SCSIBusHasReset(ADAPTER_PTR HA); +extern int Interpret_MSG(ADAPTER_PTR HA); +extern void SCSIMakeIdentify(ADAPTER_PTR HA, unsigned LUN, BOOLEAN AllowDisc); +extern int SCSISendAbort(ADAPTER_PTR HA); +extern int SCSISendReject(ADAPTER_PTR HA); +extern int Receive_Msg(ADAPTER_PTR HA, U8 Msg); + +#endif /* __SCSI_H__ */ diff --git a/private/ntos/miniport/always/debug.h b/private/ntos/miniport/always/debug.h new file mode 100644 index 000000000..b1be949e3 --- /dev/null +++ b/private/ntos/miniport/always/debug.h @@ -0,0 +1,25 @@ +#ifndef __DEBUG_H__ +#define __DEBUG_H__ + +#if defined(DEBUG_ON) + + #if !defined(DEBUG_TOKEN) + #define DEBUG_TOKEN debug + #endif + extern int DEBUG_TOKEN; + + #define TRACE(l,s) if (l <= DEBUG_TOKEN) ScsiDebugPrint s + #define DmsPause(l, p) if (l <= DEBUG_TOKEN) msPause(p) + #define BreakPoint(HA) EnvBreakPoint(HA) + #define DEBUG(l,e) if (l <= DEBUG_TOKEN) ScsiDebugPrint e + +#else + + #define TRACE(l,s) + #define DmsPause(l,p) + #define BreakPoint(HA) + #define DEBUG(l,e) + +#endif + +#endif /* __debug_h__ */ diff --git a/private/ntos/miniport/always/environ.h b/private/ntos/miniport/always/environ.h new file mode 100644 index 000000000..17637d836 --- /dev/null +++ b/private/ntos/miniport/always/environ.h @@ -0,0 +1,89 @@ +#ifndef __ENVIRON_H__ +#define __ENVIRON_H__ + +#ifdef DOSDRIVER +#define NATIVE16 +#define DEBUG_TOKEN debug_api +#include "std.h" +#include "types.h" +#include "msdrvenv.h" +#include "idosaspi.h" +#endif + + + +#ifdef DOSTEST +#define NATIVE16 +#define DEBUG_TOKEN debug_api +#include <dos.h> +#include "types.h" +#include "msdosenv.h" +#include "idosaspi.h" +#endif + + + +#ifdef SCOUNIX +#define NATIVE32 +#define DEBUG_TOKEN debug_api +#include "scounix.h" +#endif + + + +#ifdef NW386 +#define LOCAL +#define NATIVE32 +#define DEBUG_TOKEN debug_api +#include "std.h" +#include "nw386.h" +#include "inline.h" +#include "aspimacs.h" +#include "inwaspi.h" +#endif + + + +#ifdef WINNT + +#if DBG!=0 // If this is a checked build... +#undef USEFASTCALLS // disable _fastcall, which forces static +#endif + +#define NATIVE32 +#include "..\..\inc\miniport.h" +#include "ntenv.h" +#include "intsrb.h" +#define SEPERATELUNS + +// If this is a free build, shut off debug messages and tests: +#if DBG==0 +#undef DEBUG_ON +#else +#define DEBUG_TOKEN debug_api +#undef ASSERT // miniport.h defines ASSERT as null +#endif + +#endif + + + + +#ifdef AL4000I +#define NATIVE16 +#define DEBUG_TOKEN debug_api +#define SMARTHA +#include "std.h" +#include "rtkenv.h" +#include "rtk.h" +#include "rtklib.h" +#include "pim.h" +#include "haaspi.h" +#include "smartha.h" +#endif + + + +#include "envlib.h" + +#endif /* __ENVIRON_H__ */ diff --git a/private/ntos/miniport/always/envlib.h b/private/ntos/miniport/always/envlib.h new file mode 100644 index 000000000..afea3e3c5 --- /dev/null +++ b/private/ntos/miniport/always/envlib.h @@ -0,0 +1,184 @@ +/* Copyright (C) 1991 by Always Technology Corporation. + This module contains information proprietary to + Always Technology Corporation, and should be treated as confidential. +*/ + +#ifndef __ENVLIB_H__ +#define __ENVLIB_H__ + +#define FourCharVers "13.14" + +/* Revision: + .13.14- Added "NO DISCONNECT" flag to DOS ASPIrequests. Int 13 sets this flag. + .13.13- Fix rounding of sync. period in 53c7x0.c. + .13.12- 53C7x0 plug handles Reject messages on sync. negotiations. + .13.11- Map to physical now uses the same segment descriptor as GetXferSegment() + .13.10- Support for revert & resume configurations; add power down commands + to board plugs. + .13.9 - Fixed '720 driver to DWORD align the script only once in a multi- + adapter configuration. + .13.8 - 53c7x0: Added support for phase verification. + .13.7 - Support for discontiguous SCSI IDs for INT 13. + .13.6 - Fixed '7000 load of burst length register, switch polarity for + cache line burst + .13.5 - Attach sync. negotiations to non-data commands. + - Added timer support to msdrvenv.c - Currently disabled + .13.4 - Change from leaving ints disabeld in IN2000_ISR() to using + InDOSFlag in General_ISR() in MSDRVENV.C + - Increase timeout count in WaitForRead in 33c93.c + .13.3 - Fix report of last cyl. number in Int 13 GetParam + .13.2 - Fix AL-7000 IRQ decode. + .13.1 - VDS support + .13 - Additional fixes to '720 disconnects. First real release + for AL7000. + .12.16- Fixed 53c7x0 to not get illegal instr. when reselect comes in + when a select is started. + .12.15- Changed I/O decodes for AL-7000 + .12.14- Support for Chicago; S/G fix to IN2000.c + .12.11- Added S/G support to ASPIMGR and to AL7000 pieces. + .12.10- Added Int 15 support to Int 13 handler + .12.9 - Fixed connect/disconnect in 53c7x0.c + .12.8 - Added variables "GlobalAllowDisc" & "GlobalAllowSync" to ASPIMGR.C. + - Changed DOS ASPIDRVR.ASM to scan command line and set these variables. + .12.7 - Added int-13 support for AL-7000, and others using BIOS control interface + .12.6 - Added support for AL-7000 + .12.5 - Changed INT 13 code to be compatable with VCN: 1-04 BIOS + .12.4 - Fixed "GetDASD" to preserve ES. + .12.3 - Corrected target initiated sync. xfer. request by adding a parameter + to AskSync() + - Corrected the conditionals for xfer period and offset in target initiated + sync. xfer. request. + - Modified Int 13 code to support VCN: 1-04 bios + .12.2 - Fixed bug in IN2000_ISR(), where it would spin flushing the FIFO + upon completion of a write, while waiting for the 33C93 interrupt. + - EVAL720 code. + .12.1 - Added size definitive typeing (i.e. U32) + .12 - Release of 11.9 + .11.9 - Fixed problem with release of device descriptors on device timeout. + Fixed long delay on selection timeout + .11.8 - Fixed synchronous calculation in 33c93 initalize + Enabled Synchronous as default + .11.7 - Made DOS driver work with 11.6 changes + .11.6 - Started work on NT driver + .11.5 - More generalizing stuff + .11.4 - Robert Lou added AL6K plug + .11.3 - Changed Adapter structure to add Physical & Supports structures + .11.2 - Modified to common error code, returned through APISetStatus + .11 - Release of 10.3 + .10.3 - Added delay in IN2000.c after reset to allow 33C93 to settle. + - Reduced the min. number of device descr., since LUNs no longer + require unique device descr. + .10.2 - Fixed adapter id message from ASPI adapter info command + .10.1 - Internal; Shortens reset time from 250 ms to a pulse + .10 - First non-beta release; fixed problems w/ smart drive + +*/ + + +// Scatter / gather segment descriptor: +typedef struct { + + // Offset of last use of this descr.; -1 if invalid + U32 LastOffset; + + // Work areas for S/G handler; preserved from last call only if LastOffset != -1 + U32 APIScratch[2]; + U32 MappingScratch[2]; // Area reserved for MapToPhysical and UnlockRegion + + // Length in bytes of (remaining) segment described by SegmentPtr + U32 SegmentLength; + + // Pointer to data buffer, to start/resume data xfer + U32 SegmentPtr; + + struct { + + BOOLEAN Valid; // Is SegmentPtr a valid address? + BOOLEAN IsPhysical; // Is SegmentPtr (above) physical? + BOOLEAN SegmentNeedsUnlocking; // Do we need to Unlock when done? + + } Flags; + +} SegmentDescr; + + +#if !defined(critical) +extern void critical(struct Adapter ALLOC_D *HA); // Conditional (nested) start critical context +extern void uncritical(struct Adapter ALLOC_D *HA); // Conditional (nested) end critical context +extern int MaybeCritical(void); // Set critical if machine in critical state +extern void MaybeUncritical(int Was); // Balance the MaybeUncritical, using its return value +#endif + +extern void Notify(struct Adapter ALLOC_D *HA, IO_REQ_PTR Req); // Signal a request completion + +#if !defined(min) +#define min(X, Y) ((X <= Y) ? X : Y) +#endif + +#if !defined(max) +#define max(X, Y) ((X >= Y) ? X : Y) +#endif + + +#if !defined(NW386) +#if !defined(LogMessage) +extern void LogMessage(ADAPTER_PTR HA, IO_REQ_PTR Req, int TID, int LUN, int ErrCode, int Misc); +#endif +#endif + +extern ALLOC_T allocm(unsigned count); + +extern void freem(ALLOC_T block, unsigned count); + +extern void copym(ALLOC_T dest, ALLOC_T src, unsigned count); + +extern void DMASetup(unsigned Channel, void FAR *MemHndl, U32 Index, + U32 Count, int UseSGList, unsigned Direction); + +extern void DMAComplete(unsigned Channel, void FAR *MemHndl, U32 Index, + U32 Count, int UseSGList, unsigned Direction); + +extern U32 MapToPhysical(void ALLOC_D *HA, SegmentDescr *Descr); +extern void UnlockRegion(void ALLOC_D *HA, SegmentDescr *Descr); +extern void FAR *MapToVirtual(void ALLOC_D *HA, U32 PAddr); + +#if !defined(ExportReq) +extern IO_REQ_PTR ExportReq(IO_REQ_PTR Req); +#endif + +#if !defined(ImportReq) +extern IO_REQ_PTR ImportReq(IO_REQ_PTR Req); +#endif + +#if !defined(msPause) +extern void msPause(unsigned msTicks); +#endif + +#if !defined(PanicMsg) +extern void PanicMsg(char *Msg); +#endif + +#if !defined(RegisterIO) +extern IOHandle RegisterIO(struct Adapter ALLOC_D *HA, U16 Base, U16 Length, int AddrSpace); +#endif + +#if !defined(repinsb) +extern void repinsb(const unsigned port, unsigned char far *bufferp, unsigned count); +#endif + +#if !defined(repoutsb) +extern void repoutsb(const unsigned port, unsigned char far *bufferp, unsigned count); +#endif + +#if !defined(repinsw) +extern void repinsw(const unsigned port, unsigned short far *bufferp, unsigned wcount); +#endif + +#if !defined(repoutsw) +extern void repoutsw(const unsigned port, unsigned short far *bufferp, unsigned wcount); +#endif + +extern void setm(ALLOC_T block, int val, unsigned count); +extern ALLOC_T shrinkm(ALLOC_T oldblock, unsigned oldsize, unsigned newsize); + +#endif /* __ENVLIB_H__ */ diff --git a/private/ntos/miniport/always/in2000.c b/private/ntos/miniport/always/in2000.c new file mode 100644 index 000000000..b433a7f87 --- /dev/null +++ b/private/ntos/miniport/always/in2000.c @@ -0,0 +1,801 @@ +/* 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" + +#include "33c93.h" +#include "in2000.h" + +#define StatMask 0xc1 // Bits of interest in FIFO status register + +#define FIFOThresh 16 // Minimum xfer lenth for FIFOed xfers +#define FIFOPad 32 // How many bytes must be added to writes to push data out of FIFO +#define FIFOFillOffset 64 // Minimum amout of room to leave at top of FIFO +#define FIFOSize 2048 // Total size of FIFO +#define MaxPreFill (FIFOSize / 2) + +#define AuxStat HA->IOBase+INAuxOff +#define WDSelect HA->IOBase+INWDSelOff +#define WDData HA->IOBase+INWDDataOff +#define INData HA->IOBase+INDataOff + +#define lengthof(x) (sizeof(x) / sizeof(x[0])) + +// Prototypes: +int IN2000_ISR(ADAPTER_PTR HA); +U32 IN2000_Service(int Func, ADAPTER_PTR HA, U32 Misc); + +#define SetWDReg(HA,WDReg) outb(HA->Ext->AD.IN2000U.IOMap[INWDSelOff], (WDReg)) +#define ReadWDData(HA) inb(HA->Ext->AD.IN2000U.IOMap[INWDDataOff]) +#define ReadWDReg(HA,reg) (SetWDReg(HA,reg), ReadWDData(HA)) +#define WriteWDData(HA, val) outb(HA->Ext->AD.IN2000U.IOMap[INWDDataOff], (val)) +#define WriteWDReg(HA,reg,val) SetWDReg(HA,(reg));WriteWDData(HA, val) +extern void WD33c93_ISR(ADAPTER_PTR HA); +extern void WD33C93_Init(ADAPTER_PTR HA); +extern BOOLEAN GlobalAllowSync; + + +typedef struct { + + U8 OwnID; + U8 CtrlReg; + U8 TimeOutReg; + U8 SourceReg; + +} StateBuffer; + + +LOCAL void +IN2000ReInit (ADAPTER_PTR HA) +{ + // Reset the chip with a reset command. The reset is complete when + // the interrupt register is set + WriteWDReg(HA, WDCMDReg, WDResetCmd); + + while ((ReadWDReg(HA, WDAuxStatReg) & IntPending) == 0) + ; + ReadWDReg(HA, WDStatusReg); /* Clear the interrupt */ + + WD33C93_Init(HA); + + HA->Ext->AD.IN2000U.CurrIntMask = INFIFOMask; + outb(HA->IOBase+INIntMaskOff, INFIFOMask); /* Mask off FIFO, allow 33c93 ints. */ +} + + +LOCAL void +IN2000ResetBus (ADAPTER_PTR HA) +{ + unsigned j; + + TRACE(2, ("IN2000ResetBus(): \n")); + HA->Ext->AD.IN2000U.CurrIntMask = INFIFOMask; + outb(HA->Ext->AD.IN2000U.IOMap[INIntMaskOff], INFIFOMask); /* Mask off FIFO, allow 33c93 ints. */ + + // Issue a SCSI bus reset; SCSI-2 says reset can any length > 25uS, + // however, some devices lose their mind if reset is too long, + // So, we'll try for 50uS, assumeing an 8-MHz bus: + outb(HA->Ext->AD.IN2000U.IOMap[INResetOff], 0); // Assert reset + for (j=30; j; j--) // don't make reset too short, figure 10Mhz ISA bus, 4 cycles / IO + inb(HA->Ext->AD.IN2000U.IOMap[INFIFOOff]); // but too long breaks some drives + inb(HA->Ext->AD.IN2000U.IOMap[INHWRevOff]); // de-assert reset + + WriteWDReg(HA, WDCMDReg, WDResetCmd); // Reset chip, intr. will re-initialize it + +} + + +LOCAL U32 +IN2000Init (ADAPTER_PTR HA) +{ + int j; + + /* Mask off ints while we're in init. routine */ + outb(HA->IOBase+INIntMaskOff, INFIFOMask | INSBICMask); + + // Set up the I/O port map: + for (j=0; j<= 15; j++) + HA->Ext->AD.IN2000U.IOMap[j] = HA->IOBase + j; + + // Issue a SCSI bus reset; SCSI-2 says reset can any length > 25uS, + // however, some devices lose their mind if reset is too long, + // So, we'll try for 50uS, assumeing an 8-MHz bus: + inb(HA->IOBase + INHWRevOff); // Precautionary deassert reset + outb(HA->IOBase + INResetOff, 0); // Reset the board + for (j=30; j; j--) // don't make reset too short, figure 10Mhz ISA bus, 4 cycles / IO + inb(HA->Ext->AD.IN2000U.IOMap[INFIFOOff]); // but too long breaks some drives + inb(HA->IOBase + INHWRevOff); /* de-assert reset */ + APINotifyReset(HA); + + ((StateBuffer *)(HA->Ext->InitialState))->OwnID = 7; + ((StateBuffer *)(HA->Ext->InitialState))->CtrlReg = ReadWDReg(HA, WDControlReg); + ((StateBuffer *)(HA->Ext->InitialState))->TimeOutReg = ReadWDReg(HA, WDTimeoutReg); + ((StateBuffer *)(HA->Ext->InitialState))->SourceReg = ReadWDReg(HA, WDSourceReg); + + HA->Ext->SBIC.WD33C93.WDSelPort = HA->IOBase; + HA->Ext->SBIC.WD33C93.WDDataPort = HA->IOBase+1; + + HA->Ext->SBIC.WD33C93.MHz = 10; /* The IN-2000 uses a 10Mhz 33c93 */ + HA->Ext->SBIC.WD33C93.AsyncValue = 0x30; + + IN2000ReInit(HA); + + HA->State.Allow = 1; // Allow request processing + return 0; // OK +} + + + +int +Find_IN2000 (ADAPTER_PTR HA, unsigned *Context) +{ + static const unsigned BaseList[]= + {0x100, 0x110, 0x200, 0x220}; /* Bits are inverted */ + static const unsigned IRQList[]={10, 11, 14, 15}; + unsigned Switch; + IOHandle INBase; + int HWVers; + unsigned Terminal = lengthof(BaseList); + + + // For Chicago: + // + // If HA->IOBase is entered != 0, then we need to find the index of the + // matching I/O address. If we find one, limit the terminus of the + // primary check below, so we check only one instance. If we don't find + // a match, then the primary loop below will fail to start. Not pretty, + // but it works. + + if (HA->IOBaseAddr != 0) { + + for (*Context = 0; *Context < lengthof(BaseList); (*Context)++) + if (HA->IOBaseAddr == BaseList[*Context]) + break; + + Terminal = min(*Context + 1, lengthof(BaseList)); + + } + + + TRACE(4, ("Find_IN2000(): HA Ptr = %x,Context = %x\n", HA, *Context)); + for (; *Context < Terminal; DeregisterIO(HA, INBase), (*Context)++) { + + INBase = RegisterIO(HA, BaseList[*Context], 15, AddrSpaceIO); + Switch = inb(INBase+INSwitchOff); + TRACE(5,("Find_IN2000(): Switch value read was: %02x\n", Switch)); + if ((Switch & 3) != *Context) /* Do switch settings match? */ + continue; + + /* Check the version number port, see if it appears IN-2000-ish */ + HWVers = inb(INBase+INHWRevOff); + TRACE(5,("Find_IN2000(): H/W version read as: %02x\n", HWVers)); + if ((HWVers < 0x20) || (HWVers > 0x29)) + continue; + + if (HWVers < MinHWVers) { + + LogMessage(HA, NILL, 0, 0, MSG_BAD_FIRMWARE, HWVers); + + TRACE(1,("Version of the IN-2000 SPROM at I/O address %x is %02x. Please" + " call Always\nfor upgrade instructions. Board is being " + "ignored.\n\n", INBase, HWVers)); + continue; + + } + + if (Switch & 0x04) + HA->IRQNumber = IRQList[(Switch >> 3) & 0x3]; + else { + + LogMessage(HA, NILL, 0, 0, MSG_NO_INT_ENABLE, BaseList[*Context]); + TRACE(1,("IN-2000 at I/O %xh must have its interrupts enabled." + " Board is being ignored.\n\n", INBase)); + continue; + + } + + HA->IOBase = INBase; + HA->IOBaseAddr = BaseList[*Context]; + HA->IOAddrLen = 15; + HA->SCSI_ID = 7; + HA->Service = IN2000_Service; + HA->ISR = IN2000_ISR; + HA->Name = "IN-2000"; + +#if defined(WINNT) + // Test the DOS 5/Sync. switch (8); On, supports DOS 5 & synchronous + HA->Supports.Synchronous = ((Switch & 0x20) == 0); // Support sync. if switch 8 is on +#else + HA->Supports.Synchronous = GlobalAllowSync; // Support sync. if switch 8 is on +#endif + + HA->Supports.Identify = TRUE; + HA->Physical.BusType = BT_ISA; + + (*Context)++; // Found one, so inc. for next entry + return 1; + + } + return 0; +} + + +void +SetUpXfer (ADAPTER_PTR HA, IO_REQ_PTR Req, unsigned Dir) +{ + unsigned i; + + HA->Ext->AD.IN2000U.CBuff = (char FAR *)&(((char FAR *)(ReqDataPtr(Req)))[(unsigned)(HA->ReqCurrentIndex)]); + HA->Ext->AD.IN2000U.CRemain = HA->ReqCurrentCount; + HA->Ext->AD.IN2000U.CurrDir = (Dir == SCSIIn) ? IN2000DataIn : IN2000DataOut; + TRACE(5,("SetUpXfer(): %ld (0x%lx) bytes to transfered to/from 0x%08lx\n", HA->Ext->AD.IN2000U.CRemain, HA->Ext->AD.IN2000U.CRemain, HA->Ext->AD.IN2000U.CBuff)); + outb(HA->Ext->AD.IN2000U.IOMap[INFIFOResetOff], 1); /* Reset the FIFO */ + + if (HA->ReqCurrentCount >= FIFOThresh) { + + TRACE(5,("SetUpXfer(): Setting up for FIFO xfer\n")); + if (Dir == SCSIIn) { + + TRACE(5,("SetUpXfer(): Setting FIFO direction to read\n")); + outb(HA->Ext->AD.IN2000U.IOMap[INDirOff], 1); /* set read mode */ + HA->Ext->AD.IN2000U.CurrIntMask = + (HA->Ext->AD.IN2000U.CRemain >= (FIFOSize-FIFOFillOffset)) ? 0 : INFIFOMask; + + } + + i = (ReadWDReg(HA, WDControlReg) & ~DMAModeMask) | DMABus; + do { + WriteWDReg(HA, WDControlReg, i); + } while (i != ReadWDReg(HA, WDControlReg)); + + if (Dir != SCSIIn) { // Doing DATA OUT + + /* The IN-2000 FIFO mechinism requires pre-loading on write + operations. At least 32 bytes must be pre-loaded, or else + data loss may occur. Upon transfering the final bytes to the + FIFO, it must be padded by writing 32 bytes of junk, to move + the valid data up from the first 32 byte "twilight-zone". This + will be done in the FIFO fill routine. + */ + + i = (unsigned)min(HA->ReqCurrentCount, (U32)MaxPreFill); // Don't overfill FIFO + + TRACE(5,("SetUpXfer(): Preloading %d bytes for write.\n", i)); + repoutsw(HA->Ext->AD.IN2000U.IOMap[INDataOff], (U16 FAR *)HA->Ext->AD.IN2000U.CBuff, (i+1)/2); // Pre-fill FIFO + HA->Ext->AD.IN2000U.CBuff += i; // Offset buffer ptr by amount written + HA->Ext->AD.IN2000U.CRemain -= i; // Decrement remaining count + + if (HA->Ext->AD.IN2000U.CRemain) // is there more stuff after this? + HA->Ext->AD.IN2000U.CurrIntMask = 0; // Then don't mask FIFO ints + else { // If not, send pad characters + + TRACE(5, ("SetupXfer(): Padding FIFO\n")); + for (i=(FIFOPad / 2); i; i--) + outw(HA->Ext->AD.IN2000U.IOMap[INDataOff], (U16)i); + HA->Ext->AD.IN2000U.CurrIntMask = INFIFOMask; // Block FIFO ints + + } + + } + + } else { + + TRACE(5, ("SetupXfer(): Using byte I/O\n")); + i = (ReadWDReg(HA, WDControlReg) & ~DMAModeMask) | DMAPIO; + do { + WriteWDReg(HA, WDControlReg, i); + } while (i != ReadWDReg(HA, WDControlReg)); + + } + + TRACE(5,("SetUpXfer(): SetUpXfer complete\n")); + +} + + +U8 REGPARMS +FIFOStat (const IOHandle Port) +{ +#ifdef ASMIO + + asm { + mov dx, word ptr Port + in al, dx + } +InAgain: + asm { + mov ah, al + in al, dx + sub ah, al + jnz InAgain + } + return _AX; /* AH is already zeroed for unsigned promotion */ +#else + + int i; + U8 Stat1, Stat2; + + Stat2 = inb(Port) & StatMask; + do { + + Stat1 = Stat2; + + for (i=3; i; i--) + Stat2 &= inb(Port); // Find which bits are stable for 4 reads + + Stat2 &= StatMask; // Most sig. two bits, and int bit are interesting + + } while (Stat1 != Stat2); + + return Stat1; +#endif +} + + +void +EmptyFIFO (ADAPTER_PTR HA) +{ + union { + U32 l; + unsigned char b[4]; + } Count; + unsigned InFIFO, i; + +/* + Update the pointers; First get the number of bytes + the SCSI chip thinks remain to be transfered. Then compare + to the number of bytes the HA structure says remain. The + differance is the number of bytes in the FIFO. + + In the case of read data, we need to read the bytes out of + the FIFO. The number of bytes in the FIFO is the number + of bytes the structure says we've read, minus what the SCSI + chip has sent to the FIFO. The buffer pointer is then + incremented, and the remaining count is decremented by that + amount. + + For write data, the number of bytes in the FIFO is the amount + the SCSI chip has yet to write, minus what the driver has yet + to send to the FIFO. The data in the FIFO is dropped, the + buffer pointer is set back, and the remaining count is + incremented. +*/ + + if ((HA->Ext->AD.IN2000U.CurrDir == IN2000DataIn) && (HA->Ext->AD.IN2000U.CRemain == 0)) { + + HA->ReqCurrentIndex += HA->ReqCurrentCount; + HA->ReqCurrentCount = 0; + + } else { + +#if defined(NATIVE32) + + Count.l = (U32)ReadWDReg(HA, WDCountReg); + Count.l = (Count.l * 256) + (U32)ReadWDData(HA); + Count.l = (Count.l * 256) + (U32)ReadWDData(HA); + +#else + + Count.b[3] = 0; + Count.b[2] = ReadWDReg(HA, WDCountReg); + Count.b[1] = ReadWDData(HA); + Count.b[0] = ReadWDData(HA); + +#endif + + TRACE(4,("EmptyFIFO(): Value of Xfer count registers: 0x%08lx\n", Count.l)); + + if (HA->Ext->AD.IN2000U.CurrDir == IN2000DataIn) { + + // Get number we have untransfered, minus what the chip has left untransfered + // to give the number held in the FIFO: + InFIFO = (unsigned)(HA->Ext->AD.IN2000U.CRemain - Count.l); + + TRACE(4,("EmptyFIFO(): CRemain=0x%08lx, in FIFO to read: %04x\n", HA->Ext->AD.IN2000U.CRemain, InFIFO)); + + if (InFIFO > 0) { + + TRACE(5, ("EmptyFIFO(): final read %d bytes\n", InFIFO)); + repinsw(HA->Ext->AD.IN2000U.IOMap[INDataOff], (U16 FAR *)HA->Ext->AD.IN2000U.CBuff, (InFIFO+1)/2); + + } + } + + // When the transfer was set up, the count registers where loaded with + // ReqCurrCount(); now the counters reflect the number of bytes untransfered + // Increment the index by (StartBytesToXfer - RemainBytesToXfer); and save + // away the new remaining count: + HA->ReqCurrentIndex += HA->ReqCurrentCount - Count.l; + HA->ReqCurrentCount = Count.l; + TRACE(4,("EmptyFIFO(): New remaining count: %ld(dec)\n", HA->ReqCurrentCount)); + + } + + TRACE(5,("EmptyFIFO(): Reseting xfer mode.\n")); + HA->Ext->AD.IN2000U.CurrIntMask |= INFIFOMask; /* Block the FIFO ints */ + outb(HA->Ext->AD.IN2000U.IOMap[INFIFOResetOff], 1); /* Reset the FIFO */ + + i = (ReadWDReg(HA, WDControlReg) & 0x1f); + do { /* Clear WD Bus mode */ + WriteWDReg(HA, WDControlReg, i); + } while (ReadWDReg(HA, WDControlReg) != i); + + HA->Ext->AD.IN2000U.CurrDir = IN2000NoData; + HA->Ext->AD.IN2000U.CRemain = 0; + +} + + +void +FIFO_ISR (ADAPTER_PTR HA) +{ + unsigned S; + +#if defined(KEEP_STATS) + HA->DataInterrupts++; +#endif + + // Stay in here as long as there is no 33C93 interrupt (bit 0), and there is + // at least 512 bytes in the FIFO (0xc0), and there is data remaining. + // FIFOStat is called to repeatedly read the FIFO status port, since it + // may be unstable for a single read. + + while (!((S = FIFOStat(HA->Ext->AD.IN2000U.IOMap[INFIFOOff])) & 1) + && (S & 0xc0) && HA->Ext->AD.IN2000U.CRemain) { + + TRACE(5, ("IN2000_ISR(): FIFO status port read as %x\n", S)); + + // Value read from port (bits 1-7) is number of bytes / 16; Bit one is the + // WD interrupt pending bit; so the count is effectively already multiplied + // by two. Multiply it again by 8 to get the number of bytes in FIFO +// S = (S & 0xc0) * 8; + S = 512; + + if (HA->Ext->AD.IN2000U.CurrDir == IN2000DataIn) { + +// if ((U32)S > HA->Ext->AD.IN2000U.CRemain) { +// +// TRACE(0, ("FIFO_ISR(): FIFO says %ld, expected remaining is %ld\n", S, HA->Ext->AD.IN2000U.CRemain)); +// S = (unsigned)HA->Ext->AD.IN2000U.CRemain; +// +// } + S = (unsigned)min(S, HA->Ext->AD.IN2000U.CRemain); + TRACE(4, ("FIFO_ISR(): reading %d bytes to %lx\n", S, HA->Ext->AD.IN2000U.CBuff)); + +#if !defined(ASMIO) + + repinsw(HA->Ext->AD.IN2000U.IOMap[INDataOff], HA->Ext->AD.IN2000U.CBuff, S/2); + +#else /* ASMIO */ + +#if sizeof(HA) == 4 /* far HA ptr */ + asm { + mov ax, di + les bx, HA + mov dx, es:[bx].IOBase + les di, es:[bx].AD.IN2000U.CBuff + } +#else /* near HA ptr */ + asm { + mov ax, di + mov bx, HA + mov dx, [bx].IOBase + les di, [bx].AD.IN2000U.CBuff + } +#endif + asm { + add dx, INDataOff + mov cx, S + shr cx, 1 + cld + rep insw + mov di, ax + } + +#endif /* ASMIO */ + + } else { + + // Leave 16 bytes (FIFOFillOffset) in FIFO for write flush (see below): + S = (unsigned)min(min(S - FIFOFillOffset, FIFOSize/2), HA->Ext->AD.IN2000U.CRemain); + + TRACE(5, ("FIFO_ISR(): Writing next %d chunk from %lx\n", S, HA->Ext->AD.IN2000U.CBuff)); + repoutsw(HA->Ext->AD.IN2000U.IOMap[INDataOff], (U16 FAR *)HA->Ext->AD.IN2000U.CBuff, S/2); + + } + + HA->Ext->AD.IN2000U.CBuff += S; + HA->Ext->AD.IN2000U.CRemain -= S; + TRACE(5, ("FIFO_ISR(): New remaining is %ld (0x%lx)\n", HA->Ext->AD.IN2000U.CRemain, HA->Ext->AD.IN2000U.CRemain)); +// if (HA->Ext->AD.IN2000U.CRemain) +// for(S=16; S && ((inb(HA->Ext->AD.IN2000U.IOMap[INFIFOOff]) & 0xc1) == 0); S--) ; + } + + /* The FIFO logic on the IN-2000 requires writing FIFOPad bytes of garbage + into the FIFO to push the end of the valid data out. This flush + occurs here: + */ + + if (HA->Ext->AD.IN2000U.CRemain == 0) { /* Don't expect any more FIFO ints */ + + HA->Ext->AD.IN2000U.CurrIntMask |= INFIFOMask; /* Block the FIFO ints */ + if (HA->Ext->AD.IN2000U.CurrDir == IN2000DataOut) { // Pad the FIFO + + for (S=(FIFOPad / 2); S; S--) + outw(HA->Ext->AD.IN2000U.IOMap[INDataOff], (U16)S); + + } + } +} + + +int +IN2000_ISR (ADAPTER_PTR HA) +{ + unsigned char Stat, Taken = 0; + + TRACE(5, ("IN2000_ISR(): \n")); + outb(HA->Ext->AD.IN2000U.IOMap[INIntMaskOff], INFIFOMask | INSBICMask); + + HA->Ext->AD.IN2000U.LastPollHadIntPending = FALSE; + + while (((Stat = inb(HA->Ext->AD.IN2000U.IOMap[INFIFOOff])) & 1) + || ((Stat & 0xc0) && (HA->Ext->AD.IN2000U.CRemain != 0))) { + + Taken = 1; + TRACE(5, ("IN2000_ISR(): FIFOStatus is : %x\n", Stat)); + if ( !(Stat & 1) ) + FIFO_ISR(HA); + + while(inb(HA->Ext->AD.IN2000U.IOMap[INFIFOOff]) & 0x1) + WD33c93_ISR(HA); + + } + + outb(HA->Ext->AD.IN2000U.IOMap[INIntMaskOff], HA->Ext->AD.IN2000U.CurrIntMask); + return Taken; +} + + +void +IN2000_Initiate (ADAPTER_PTR HA, IO_REQ_PTR Req, const int StartLevel) +{ +#if defined(COMPOUND_CMD) + unsigned char C; +#endif + + TRACE(5, ("IN2000_Initiate(): initiating\n")); + + critical(HA); // Block interrupts for now + + HA->ReqCurrentCount = 0; // Next DXFER phase will cause a GetXferSegment() + HA->ReqCurrentIndex = 0; + + HA->Ext->SBIC.WD33C93.State = WD_NO_STATE; // Currently not in any state + + WriteWDReg(HA, WDDestIDReg, ReqTargetID(Req)); // Set the ID of the target + + HA->State.Busy = 1; // Mark flag for adapter in use + + if (HA->DevInfo[ReqTargetID(Req)].Flags.UseSync) { // Do we use sync. xfers on this device? + + WriteWDReg(HA, WDSyncReg, HA->DevInfo[ReqTargetID(Req)].HASync1); // Then write the Sync. values + + } else { + + WriteWDReg(HA, WDSyncReg, HA->Ext->SBIC.WD33C93.AsyncValue); // Alright then, async. values + + } + + // enable reselection + WriteWDReg(HA, WDSourceReg, EnableRSel); + + SCSIMakeIdentify(HA, ReqTargetLUN(Req), (BOOLEAN)(ReqAllowDisconnect(Req) && HA->CurrDev->Flags.Allow_Disc)); // Then build Identify with disconnect + +#if defined(COMPOUND_CMD) + + // WD Compound commands only know group 0, 1, & 5 CDBs: + C = ReqCDB(Req)[0] & 0xe0; + if ((HA->Ext->MO_Count > 1) || !(C <= 0x10 || C == 0x50)) { + + WriteWDReg(HA, WDCMDReg, WDSelATNCmd); // Select with attention + TRACE(3, ("IN2000_Initiate(): Using discreet commands\n")); + + } else { + + TRACE(3, ("IN2000_Initiate(): Using compound commands\n")); + + WriteWDReg(HA, WDControlReg, EnableIDI); + WriteWDReg(HA, WDTarLUNReg, ReqTargetLUN(Req) | ((BOOLEAN)(ReqAllowDisconnect(Req) && HA->CurrDev->Flags.Allow_Disc)) ? 0x40 : 0); // Set ID of target LUN + + if ((HA->ReqCurrentCount >= FIFOThresh) && (ReqDataIn(Req) || ReqDataOut(Req))) { + + TRACE(4, ("IN2000_Initiate(): Early prepare for data xfer; Preparing for %ld byte xfer\n", HA->ReqCurrentCount)); + HA->State.DataXfer = 1; + HA->Ext->SBIC.WD33C93.State |= WD_BLOCK_XFER; + + HA->Ext->AD.IN2000U.CurrIntMask = 0; + SetUpXfer(HA, HA->CurrReq, ReqDataIn(Req)); + outb(HA->Ext->SBIC.WD33C93.WDSelPort, WDCountReg); + outb(HA->Ext->SBIC.WD33C93.WDDataPort, (((char FAR *)&ReqCurrCount(HA->CurrReq))[2])); + outb(HA->Ext->SBIC.WD33C93.WDDataPort, (((char FAR *)&ReqCurrCount(HA->CurrReq))[1])); + outb(HA->Ext->SBIC.WD33C93.WDDataPort, (((char FAR *)&ReqCurrCount(HA->CurrReq))[0])); + + } else { + + HA->Ext->AD.IN2000U.CurrIntMask = INFIFOMask; + outb(HA->Ext->SBIC.WD33C93.WDSelPort, WDCountReg); + outb(HA->Ext->SBIC.WD33C93.WDDataPort, 0); + outb(HA->Ext->SBIC.WD33C93.WDDataPort, 0); + outb(HA->Ext->SBIC.WD33C93.WDDataPort, 0); + + } + + if (StartLevel <= 1) + outb(HA->Ext->AD.IN2000U.IOMap[INIntMaskOff], HA->Ext->AD.IN2000U.CurrIntMask); + + SetWDReg(HA, WDCDBReg); // Send the CDB + repoutsb(WDData, ReqCDB(Req), ReqCDBLen(Req)); + HA->Ext->SBIC.WD33C93.State |= WD_COMPOUND_CMD; // Flag the use of LEVEL II commands + + WriteWDReg(HA, WDCMDReg, WDSelATNXCmd); // Start select & xfer w/ attention + + } + +#else + + WriteWDReg(HA, WDCMDReg, WDSelATNCmd); // Select with attention + +#endif + + HA->ReqStarting = StartLevel; + inb(HA->Ext->AD.IN2000U.IOMap[INLEDOnOff]); // Turn on LED + uncritical(HA); // OK, allow ints again + + TRACE(5, ("IN2000_Initiate(): initiating complete\n")); + +} + + +U32 +IN2000_Service (int Func, ADAPTER_PTR HA, U32 Misc) +{ + int j; + + switch (Func) { + + case HA_INITIALIZE: + + return IN2000Init(HA); + break; + + + case HA_START: + + TRACE(2, ("IN2000_Service(): Got HA_START command\n")); + HA->State.Allow = 1; + StartNext(HA, 1); + break; + + + case HA_STOP: + + TRACE(2, ("IN2000_Service(): Got HA_STOP command\n")); + HA->State.Allow = 0; + break; + + + case HA_TICKLE: + + if (!(HA->State.Busy) && (HA->State.Allow)) { + + TRACE(5, ("IN2000_Service(): Tickling adapter\n")); + StartNext(HA,1); + + } else { + + TRACE(5, ("IN2000_Service(): Tickle ignored; Busy = %d, Allow = %d\n", HA->State.Busy, HA->State.Allow)); + + } + + break; + + + case HA_TIMER: + + j = inb(HA->Ext->AD.IN2000U.IOMap[INFIFOOff]) & StatMask; + if (HA->Ext->AD.IN2000U.LastPollHadIntPending && j ) { + + if (IN2000_ISR(HA)) { + + LogMessage(HA, HA->CurrReq, 0, 0, MSG_NO_INTERRUPTS, __LINE__); + TRACE(0, ("IN2000_Service(): Serviced interrupt on timer\n")); + + } + + } else + HA->Ext->AD.IN2000U.LastPollHadIntPending = j; + break; + + + case HA_LED: + + if ((int)Misc) inb(HA->Ext->AD.IN2000U.IOMap[INLEDOnOff]); + else inb(HA->Ext->AD.IN2000U.IOMap[INLEDOffOff]); + break; + + + case HA_INITIATE: + + IN2000_Initiate(HA, HA->CurrReq, (unsigned)Misc); + break; + + + case HA_DATA_SETUP: + + SetUpXfer(HA, HA->CurrReq, (unsigned)Misc); + if (HA->ReqCurrentCount < FIFOThresh) + return HAServiceResponse_UseByteIO; + else + return HA->Ext->AD.IN2000U.CRemain; +// break; + + + case HA_DATA_CMPLT: + + if (HA->Ext->AD.IN2000U.CurrDir != IN2000NoData) + EmptyFIFO(HA); + break; + + case HA_RESET_BUS: + + IN2000ResetBus(HA); + break; + + + case HA_REVERT_STATE: + + // Restore the board back to its preveous state. This is used by + // Netware / Chicago to switch back to BIOS mode. + WriteWDReg(HA, WDOwnIDReg, ((StateBuffer *)(HA->Ext->InitialState))->OwnID); + + critical(HA); + + // Reset chip, then wait for reset complete interrupt. This causes the chip + // to accept the set ID. + WriteWDReg(HA, WDCMDReg, WDResetCmd); + + while ((ReadWDReg(HA, WDAuxStatReg) & IntPending) == 0) + ; + ReadWDReg(HA, WDStatusReg); // Clear the interrupt + + uncritical(HA); + + WriteWDReg(HA, WDControlReg, ((StateBuffer *)(HA->Ext->InitialState))->CtrlReg); + WriteWDReg(HA, WDTimeoutReg, ((StateBuffer *)(HA->Ext->InitialState))->TimeOutReg); + WriteWDReg(HA, WDSourceReg, ((StateBuffer *)(HA->Ext->InitialState))->SourceReg); + break; + + + case HA_RESTORE_STATE: + + IN2000ReInit(HA); + IN2000ResetBus(HA); + break; + + + case HA_POWER_MODE: + + + break; + + } + + return 0; +} diff --git a/private/ntos/miniport/always/in2000.h b/private/ntos/miniport/always/in2000.h new file mode 100644 index 000000000..9d8a03900 --- /dev/null +++ b/private/ntos/miniport/always/in2000.h @@ -0,0 +1,31 @@ +/* in2000.h -- Port definitions for IN-2000 */ +#ifndef __IN2000_H__ +#define __IN2000_H__ + +/* Minimum hardware (Xilinx SProm) version supported: */ +#define MinHWVers 0x27 + +/* Offsets for IN-2000 I/O ports: */ +#define INAuxOff 0 /* WD Aux stat/Register select */ +#define INWDSelOff 0 /* WD register select offset */ +#define INWDDataOff 1 /* 8 bit R/W WD data port */ +#define INDataOff 2 /* 16-bit R/W data port */ +#define INResetOff 3 /* Write sets WD & SCSI bus reset; clear + by reading hardware revision */ +#define INFIFOOff 4 /* FIFO byte count/ Int. status: + upper 7 bit = # of 16 byte pieces ready + in FIFO + bit 0 = interrupt status (FIFO | WD) */ +#define INFIFOResetOff 5 /* Resets FIFO count and direction */ +#define INDirOff 7 /* Write sets data direction to read */ +#define INLEDOffOff 8 /* Turn LED off */ +#define INSwitchOff 8 /* Read IN2000 switch positions 2-9 */ +#define INLEDOnOff 9 /* Turn LED on */ +#define INHWRevOff 0xa /* Get IN Xilinx version number; clears + reset from write to port +3 */ +#define INIntMaskOff 0xc /* Set masks below to block ints */ +#define INSBICMask 1 /* Mask off 33c93 ints */ +#define INFIFOMask 2 /* mask off FIFO ints */ + + +#endif __IN2000_H__ diff --git a/private/ntos/miniport/always/in2000s.h b/private/ntos/miniport/always/in2000s.h new file mode 100644 index 000000000..6a9eeb1fa --- /dev/null +++ b/private/ntos/miniport/always/in2000s.h @@ -0,0 +1,28 @@ +/* Copyright (C) 1991, 1992 by Always Technology Corporation. + This module contains information proprietary to + Always Technology Corporation, and is be treated as confidential. +*/ + +#ifndef __IN2000S_H__ +#define __IN2000S_H__ + +typedef enum {IN2000NoData, IN2000DataIn, IN2000DataOut} IN2000DataDirection; + +/* Structure for Adapter union in scsi.h */ +struct IN2000S { + + char FAR *CBuff; + U32 CRemain; + int LastPollHadIntPending; + IOHandle IOMap[16]; + IN2000DataDirection CurrDir; + char CurrIntMask; + char InISR; + +}; + +#define SCSI_8 + +#include<33c93s.h> + +#endif /* __IN2000S_H__ */ diff --git a/private/ntos/miniport/always/intrlreq.c b/private/ntos/miniport/always/intrlreq.c new file mode 100644 index 000000000..71753aa22 --- /dev/null +++ b/private/ntos/miniport/always/intrlreq.c @@ -0,0 +1,359 @@ +/* Copyright (C) 1994 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" + + +LOCAL void REGPARMS StartNextInternalRequest(ADAPTER_PTR HA); +LOCAL void REGPARMS DeviceInfo(const ADAPTER_PTR HA); +LOCAL void REGPARMS AutoSense(ADAPTER_PTR HA); +LOCAL void REGPARMS CompleteDeferedRequest(ADAPTER_PTR HA, APIStatus Status); +LOCAL void REGPARMS ExecuteDeferedRequest(ADAPTER_PTR HA); +LOCAL void DoTestUnitReadyComplete(IO_REQ_PTR IReq); +LOCAL void REGPARMS DoTestUnitReady(ADAPTER_PTR HA); + + +#if !defined(LocalPostCallback) +extern U32 LocalPostCallback(void (*CallBack)(IO_REQ_PTR)); +#endif + +enum ASPI_Priority {NORMAL_REQ, PRIORTY_REQ, IPRIORTY_REQ}; +extern void IExecuteReq(ADAPTER_PTR HA, DEVICE_PTR DevP, IO_REQ_PTR Req, + enum ASPI_Priorty Priorty); + +void +QueueInternalRequest (ADAPTER_PTR HA, IO_REQ_PTR XReq, RequestType Type) +{ + IO_REQ_PTR *ReqScan = &(HA->Ext->InternalReqDeferQueue); + + critical(HA); + ReqState(XReq).ReqType = Type; + while(*ReqScan != (IO_REQ_PTR)NILL) + ReqScan = &ReqNext(*ReqScan); + + *ReqScan = XReq; + uncritical(HA); + + StartNextInternalRequest(HA); +} + + +LOCAL void REGPARMS +StartNextInternalRequest (ADAPTER_PTR HA) +{ + IO_REQ_PTR IReq = &HA->Ext->InternalRequest; + IO_REQ_PTR XReq; + int i; + + TRACE(2, ("StartNextInternalRequest(): InUse flag == %s\n", + (HA->State.InternalReqInUse) ? "True" : "False")); + + critical(HA); + while (!HA->State.InternalReqInUse + && HA->Ext->InternalReqDeferQueue != (IO_REQ_PTR)NILL) { + + HA->State.InternalReqInUse = TRUE; + XReq = HA->Ext->InternalReqDeferQueue; + + uncritical(HA); + + ReqTargetID(IReq) = ReqTargetID(XReq); + ReqTargetLUN(IReq) = ReqTargetLUN(XReq); + ReqDevP(IReq) = ReqDevP(XReq); + + for (i=0; i<12;i++) + ReqCDB(IReq)[i] = 0; + + ReqState(IReq).ReqType = ReqState(XReq).ReqType; + switch(ReqState(XReq).ReqType) { + + case RTGetInfoReq: + + DeviceInfo(HA); + break; + + + case RTAutoSenseReq: + + AutoSense(HA); + break; + + + case RTSyncNegReq: + + DoTestUnitReady(HA); + break; + + + default: + CompleteDeferedRequest(HA, S_REQ_REQUEST); + continue; + + } + + critical(HA); + } + uncritical(HA); + +} + + + + +void AutoSenseReqComplete(IO_REQ_PTR Req); + +LOCAL void REGPARMS +AutoSense (ADAPTER_PTR HA) +{ + IO_REQ_PTR IReq = &HA->Ext->InternalRequest; + IO_REQ_PTR XReq = HA->Ext->InternalReqDeferQueue; + + TRACE(4, ("AutoSense(): Starting auto sense for request %lx\n", XReq)); + + ReqCDBLen(IReq) = 6; + ReqSenseCount(IReq) = 0; + ReqDataCount(IReq) = ReqSenseCount(XReq); + ReqDataPtr(IReq) = ReqSensePtr(XReq); + TRACE(4, ("AutoSense(): Sense data pointer = %lx, sense count = %d\n", + ReqSensePtr(XReq), ReqSenseCount(XReq))); + + ReqSetDataInFlags(IReq); + + // First do a request sense to clear the reset, etc conditions: + ReqCDB(IReq)[0] = 0x03; // Request Sense is command 0x03 + ReqCDB(IReq)[4] = min(255, ReqSenseCount(XReq)); + ReqPost(IReq) = LocalPostCallback(AutoSenseReqComplete); + + TRACE(3, ("AutoSense(): request built, calling IExecuteReq()\n")); + QueueReq(HA, IReq, TRUE); + +} + + + +LOCAL void +AutoSenseReqComplete (IO_REQ_PTR Req) +{ + IO_REQ_PTR XReq = ReqAdapterPtr(Req)->Ext->InternalReqDeferQueue; + + TRACE(3, ("AutoSenseReqComplete(): Completion of autosense for request %lx ", XReq)); + TRACE(3, ("cmd = %02x\n", ReqCommand(XReq))); + DmsPause(7, 200); + + FreeMemHandle(Req->ReqDataPtr); + + TRACE(3, ("AutoSenseReqComplete(): Completion of auto sense\n")); + DmsPause(7, 100); + CompleteDeferedRequest(ReqAdapterPtr(Req), + (APIStatus)((ReqAPIStatus(Req) == S_TAR_NOERROR) ? S_AD_AUTOSENSE_OK : S_AD_AUTOSENSE_FAIL)); + +} + + + +// The request completed +LOCAL void +DevInfoDone (ADAPTER_PTR HA, APIStatus Status) +{ + if (Status == S_TAR_NOERROR) + ExecuteDeferedRequest(HA); // Queue up request + else + CompleteDeferedRequest(HA, Status); + +} + + + +// This is the POST routine called when the second step (Inquiry) of the device info completes +// This completes this devices inquiry. Start the next DevInfoReq for this adapter. +LOCAL void +DevInfoInqDone (IO_REQ_PTR Req) +{ + DEVICE_PTR DevP = ReqDevP(Req); + ADAPTER_PTR HA = ReqAdapterPtr(Req); + + TRACE(4, ("DevInfoInqDone(): Status of Inquiry: %04x\n", ReqAPIStatus(Req))); + if (ReqAPIStatus(Req) == S_TAR_NOERROR) { + + TRACE(4, ("DevInfoInqDone(): Inquiry completed without error\n")); + if (HA->Ext->InternalReqBuffer[0] == 0x7f) { // Check for LUN not present + + TRACE(2, ("DeviceInfo(): LUN not present\n")); + DevInfoDone(HA, S_REQ_NOTAR); + return; + + } + + DevP->Device_Type = HA->Ext->InternalReqBuffer[0]; // Get device type + TRACE(2, ("DevInfoInqDone(): Device type = %02x\n", DevP->Device_Type)); + TRACE(3, ("DevInfoInqDone(): Device is SCSI-%d, Flags = %02x\n", + (HA->Ext->InternalReqBuffer[3] & 0x0f), (unsigned)HA->Ext->InternalReqBuffer[7])); + + if ((HA->Ext->InternalReqBuffer[3] & 0x0f) > 1) { // Is this dev. SCSI2 or later? + + DevP->Flags.IsSCSI2 = 1; // Set SCSI-2 params valid flag + DevP->SCSI2_Flags.Byte = HA->Ext->InternalReqBuffer[7]; // Get the SCSI-2 parameter bytes + if (DevP->SCSI_LUN == 0) + HA->DevInfo[DevP->SCSI_ID].Flags.NeedSync = (HA->DevInfo[DevP->SCSI_ID].Flags.AllowSync &= DevP->SCSI2_Flags.Bits.Sync); // Use the inquiry info on Sync xfer + + } else { // All right; we'll do thigns the SCSI-1 way + + DevP->SCSI2_Flags.Byte = 0; // Clear all SCSI-2 mode bits + HA->DevInfo[DevP->SCSI_ID].Flags.NeedSync = + HA->DevInfo[DevP->SCSI_ID].Flags.AllowSync; + TRACE(2, ("DevInfoInqDone(): Setting NEED_SYNC flag to %d\n", + HA->DevInfo[DevP->SCSI_ID].Flags.NeedSync)); + + } + DevP->Flags.Allow_Disc = HA->Supports.Identify; // If the adapter supports identify messages, is allows disconnects + DevP->Flags.Initialized = 1; + + } + + DevInfoDone(HA, ReqAPIStatus(Req)); + +} + + + +// This is the POST routine called when the first step (Request Sense) of the device info completes +// The next step will be to do the inquiry, initiated here, completed above +LOCAL void +DevInfoSenseDone (IO_REQ_PTR Req) +{ + ADAPTER_PTR HA = ReqAdapterPtr(Req); + + TRACE(3, ("DevInfoSenseDone(): Status of ReqSense: %02x\n", ReqAPIStatus(Req))); + if (ReqAPIStatus(Req) != S_TAR_NOERROR) { + + TRACE(4, ("DevInfoSenseDone(): Completed with error\n")); + DevInfoDone(HA, ReqAPIStatus(Req)); + return; + + } + + // OK, the Request Sense completed OK, now do the inquiry + TRACE(3, ("DevInfoSenseDone(): Req. sense completed OK, setting up inquiry\n")); + ReqCDB(Req)[0] = (U8)0x12; // Inquiry is command 0x12 + + ReqDataCount(Req) = DevInfoInqSize; + ReqDataPtr(Req) = HA->Ext->InternalReqBuffer; + + ReqPost(Req) = DevInfoInqDone; + + QueueReq(ReqAdapterPtr(Req), Req, FALSE); // Queue up request + +} + + + +LOCAL void REGPARMS +DeviceInfo (const ADAPTER_PTR HA) +{ + int i; + DEVICE_PTR DevP=ReqDevP(HA->Ext->InternalReqDeferQueue); + IO_REQ_PTR IReq = &(HA->Ext->InternalRequest); + + TRACE(2, ("DeviceInfo(): for adapter %x\n")); + + for (i = 0; i < sizeof(DevP->Flags); i++) + ((char ALLOC_D *)&(DevP->Flags))[i] = 0; + + DevP->SCSI_ID = ReqTargetID(IReq); + DevP->SCSI_LUN = ReqTargetLUN(IReq); + if (DevP->SCSI_LUN == 0) { + + HA->DevInfo[ReqTargetID(IReq)].Flags.AllowSync = HA->Supports.Synchronous + /* && (HA->Parms[DRIVE_PL(ReqTargetID(IReq))] & PL_ALLOW_SYNC) */; + + } + + DevP->HA = HA; + DevP->MaxDepth = 1; + DevP->CurrDepth = 0; + DevP->Device_Type = 0xff; + + DevP->PendingReqList = DevP->AcceptedList = (IO_REQ_PTR)NILL; + ReqCDBLen(IReq) = 6; + ReqSenseCount(IReq) = 0; + ReqDataCount(IReq) = DevInfoInqSize; + ReqDataPtr(IReq) = HA->Ext->InternalReqBuffer; + + ReqSetDataInFlags(IReq); + + // First do a request sense to clear the reset, etc conditions: + ReqCDB(IReq)[0] = 0x03; // Request Sense is command 0x03 + ReqCDB(IReq)[4] = (unsigned char)DevInfoInqSize; + ReqPost(IReq) = DevInfoSenseDone; + + QueueReq(HA, IReq, FALSE); // Queue up request + +} + + + + +LOCAL void REGPARMS +DoTestUnitReady (ADAPTER_PTR HA) +{ + IO_REQ_PTR IReq = &HA->Ext->InternalRequest; + IO_REQ_PTR XReq = HA->Ext->InternalReqDeferQueue; + + TRACE(4, ("DoTestUnitReady(): Starting Test Unit Ready for request %lx\n", XReq)); + + ReqCDBLen(IReq) = 6; + ReqSenseCount(IReq) = 0; + ReqDataCount(IReq) = 0; + + ReqPost(IReq) = LocalPostCallback(DoTestUnitReadyComplete); + + TRACE(3, ("DoTestUnitReady(): request built, calling IExecuteReq()\n")); + QueueReq(HA, IReq, FALSE); // Queue up request + +} + + +LOCAL void +DoTestUnitReadyComplete (IO_REQ_PTR IReq) +{ + + ExecuteDeferedRequest(ReqAdapterPtr(IReq)); // Queue up original request + +} + + +LOCAL void REGPARMS +CompleteDeferedRequest (ADAPTER_PTR HA, APIStatus Status) +{ + IO_REQ_PTR XReq = HA->Ext->InternalReqDeferQueue; + HA->Ext->InternalReqDeferQueue = ReqNext(XReq); + + TRACE(3, ("CompleteDeferedRequest(): Completing defered request %x on adapter %x\n", XReq, HA)); + HA->State.InternalReqInUse = FALSE; + StartNextInternalRequest(HA); + ReqState(XReq).ReqType = RTNormalReq; + APISetStatus(XReq, Status, Terminal, NotSenseable); + +} + + + +LOCAL void REGPARMS +ExecuteDeferedRequest (ADAPTER_PTR HA) +{ + IO_REQ_PTR XReq = HA->Ext->InternalReqDeferQueue; + HA->Ext->InternalReqDeferQueue = ReqNext(XReq); + + TRACE(3, ("ExecuteDeferedRequest(): Executing defered request %x on adapter %x\n", XReq, HA)); + HA->State.InternalReqInUse = FALSE; + StartNextInternalRequest(HA); + ReqState(XReq).ReqType = RTNormalReq; + IExecuteReq(HA, ReqDevP(XReq), XReq, NORMAL_REQ); // Queue up request + +} diff --git a/private/ntos/miniport/always/intsrb.h b/private/ntos/miniport/always/intsrb.h new file mode 100644 index 000000000..5818af4de --- /dev/null +++ b/private/ntos/miniport/always/intsrb.h @@ -0,0 +1,100 @@ +/* Copyright (C) 1991-1993 by Always Technology Corporation. + This module contains information proprietary to + Always Technology Corporation, and is be treated as confidential. +*/ +// Microsoft Windows NT SRB internalizations: This module defines the +// abstractions used throught the SCSI API, mapping to NT's SRB structure. + +#if !defined(__intsrb_h__) +#define __intsrb_h__ + +// Define the SRB extension; this is an area added to each SRB from the SCSIPort +// as an adapter scratch area: + +struct IOReqExtension { + + U32 SavedIndex; // Value stored by "Save data pointers" + struct Adapter *HA; + struct _SCSI_REQUEST_BLOCK *NextReq; + struct DeviceDescr *DevP; + U16 Status; + struct { + + unsigned Connected:1; + unsigned ReselPending:1; + unsigned InternalRequest:1; + enum RequestType ReqType:4; + + } State; + +}; +typedef struct IOReqExtension *IOReqExtensionPtr; + +#include "..\..\inc\scsi.h" + +#define AUTOSENSE + +typedef SCSI_REQUEST_BLOCK IO_REQ; +typedef PSCSI_REQUEST_BLOCK IO_REQ_PTR; + +// API generic Req->ReqXXX fields: +// Macro "functions" for getting request info + +#define ReqCommand(Req) (Req)->Function +//#define ReqSGLength(Req) (Req)->SGListLength +//#define ReqSGPtr(Req) (Req)->DataPtr +#define ReqDataPtr(Req) (Req)->DataBuffer +#define ReqIsDataPtrPhys(Req) (FALSE) +#define ReqDataCount(Req) (Req)->DataTransferLength +#define ReqSensePtr(Req) (Req)->SenseInfoBuffer +#define ReqSenseCount(Req) (Req)->SenseInfoBufferLength + +#define ReqCDB(Req) (Req)->Cdb +#define ReqCDBLen(Req) (Req)->CdbLength + +#define ReqTargetID(Req) (Req)->TargetId +#define ReqTargetLUN(Req) (Req)->Lun +//#define ReqQID(Req) (Req)->QueueTag +#define ReqFlags(Req) ((Req)->SrbFlags) + +#define ReqExtensionPtr(Req) (((IOReqExtensionPtr)(Req)->SrbExtension)) // Used as flag for allocating extensions for internal IO_REQs +#define ReqSavedIndex(Req) (((IOReqExtensionPtr)(Req)->SrbExtension))->SavedIndex +#define ReqState(Req) (((IOReqExtensionPtr)(Req)->SrbExtension))->State +#define ReqAPIStatus(Req) (((IOReqExtensionPtr)(Req)->SrbExtension))->Status +#define ReqDevP(Req) (((IOReqExtensionPtr)(Req)->SrbExtension))->DevP +#define ReqNext(Req) (((IOReqExtensionPtr)(Req)->SrbExtension))->NextReq +#define ReqAdapterPtr(Req) ((ADAPTER_PTR)((((IOReqExtensionPtr)(Req)->SrbExtension)))->HA) + +// This entry is used only for internal requests +typedef void (*PFV_R)(IO_REQ_PTR); +#define ReqPost(Req) ((PFV_R)(Req)->OriginalRequest) + +#define ReqQueueAction(Req) (((Req)->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) ? (Req)->QueueAction : 0) +#define ReqAllowAutoSense(Req) !((Req)->SrbFlags & SRB_FLAGS_DISABLE_AUTOSENSE) +#define ReqAllowDisconnect(Req) !((Req)->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT) +#define ReqAllowCache(Req) ((Req)->SrbFlags & SRB_FLAGS_ENABLE_ADAPTER_CACHE)) + +#define ReqDataIn(Req) ((Req)->SrbFlags & SRB_FLAGS_DATA_IN) +#define ReqSetDataInFlags(Req) (Req)->SrbFlags |= SRB_FLAGS_DATA_IN +#define ReqDataOut(Req) ((Req)->SrbFlags & SRB_FLAGS_DATA_OUT) +#define ReqSetDataOutFlags(Req) (Req)->SrbFlags |= SRB_FLAGS_DATA_OUT +#define ReqNoData(Req) (((Req)->SrbFlags & (SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT)) == 0) +#define ReqSetNoDataFlags(Req) (Req)->SrbFlags &= ~(SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT) + + +// API functions: +#define APIFindDev(HA, TID, LUN) ((DEVICE_PTR)(ScsiPortGetLogicalUnit(HA, 0, (char)(TID), (char)(LUN)))) + + +typedef struct SG_LIST FAR *SGListPtr; +typedef struct SG_LIST SGList; + +struct SG_LIST { + + U32 Addr; + U32 Count; + +}; + + +#endif diff --git a/private/ntos/miniport/always/makefile b/private/ntos/miniport/always/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/ntos/miniport/always/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/ntos/miniport/always/ntenv.c b/private/ntos/miniport/always/ntenv.c new file mode 100644 index 000000000..0a4eb402e --- /dev/null +++ b/private/ntos/miniport/always/ntenv.c @@ -0,0 +1,80 @@ +/* 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" + +#include <stdarg.h> +#include <stdio.h> + +#if defined(DEBUG_ON) +int DEBUG_TOKEN=0; +#endif + + +void +PanicMsg (char *Message) +{ + + TRACE(0,Message); + BreakPoint(HA); + +} + + + +U32 +MapToPhysical (void ALLOC_D *HA, SegmentDescr *Descr) +{ + U32 T; + U32 Size = Descr->SegmentLength; + + TRACE(5, ("MapToPhysical(): Request to map addr: 0x%x for a length of: %d\n", + Descr->SegmentPtr, Size)); + + T = (U32)ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress(HA, NULL, (PVOID)(Descr->SegmentPtr), &Size)); + if (Size < Descr->SegmentLength) + Descr->SegmentLength = Size; + + Descr->SegmentPtr = T; + Descr->Flags.IsPhysical = TRUE; + + TRACE(5, ("MapToPhysical(): Mapped to 0x%lx\n", T)); + + return T; +} + + + +#if !defined(NO_MALLOC) +ALLOC_T +allocm (unsigned Count) +{ + // This is a cludge until we do it the right way. + // It's too late in the evening to do anything else: + static U8 MemoryPool[8192]; + static int MemPoolIndex=0; + ALLOC_T T; + + TRACE(4, ("allocm(): Requesting %d bytes; current pool index at: %d\n", + Count, MemPoolIndex)); + T = (ALLOC_T)&MemoryPool[MemPoolIndex]; + MemPoolIndex += Count; + + return T; +} +#endif + + +void +EnvLib_Init (void) +{ + +} diff --git a/private/ntos/miniport/always/ntenv.h b/private/ntos/miniport/always/ntenv.h new file mode 100644 index 000000000..0e0a6eb88 --- /dev/null +++ b/private/ntos/miniport/always/ntenv.h @@ -0,0 +1,119 @@ +/* Copyright (C) 1993 by Always Technology Corporation. + This module contains information proprietary to + Always Technology Corporation, and should be treated as confidential. +*/ + +#ifndef __NTENV_H__ +#define __NTENV_H__ + +#define VCN "655" + +#define FAR +#define ALLOC_D /* Distance of a allocm (far or blank) */ +#define FARLOCALNOTIFY /* The internal notify procs are FAR */ +#define NILL NULL /* Local definition of what is usually NULL */ + +// In a debug build, export all procedures for the debugger: +#if !defined(DEBUG_ON) + #define LOCAL static /* Optional for those who don't like statics (i.e. symdeb'ers */ +#else + #define LOCAL +#endif + + +#ifdef USEFASTCALLS +#define REGPARMS _fastcall +#else +#define REGPARMS +#endif + +#define ALLOC_T void ALLOC_D * /* Type and distance of a malloc */ + +typedef signed char I8; +typedef UCHAR U8; +typedef signed short int I16; +typedef USHORT U16; +typedef LONG I32; +typedef ULONG U32; + + +#ifdef USEFASTCALLS +#define REGPARMS _fastcall +#else +#define REGPARMS +#endif + + +/* Envlib type things: */ + +#define inb(Port) ScsiPortReadPortUchar((PUCHAR)(Port)) +#define inw(Port) ScsiPortReadPortUshort((PUSHORT)(Port)) +#define outb(Port, Val) ScsiPortWritePortUchar((PUCHAR)(Port), (UCHAR)(Val)) +#define outw(Port, Val) ScsiPortWritePortUshort((PUSHORT)(Port), (USHORT)(Val)) +#define repinsb(Port, Buffer, Count) ScsiPortReadPortBufferUchar((PUCHAR)(Port), (PUCHAR)(Buffer), (ULONG)(Count)) +#define repinsw(Port, Buffer, Count) ScsiPortReadPortBufferUshort((PUSHORT)(Port), (PUSHORT)(Buffer), (ULONG)(Count)) +#define repoutsb(Port, Buffer, Count) ScsiPortWritePortBufferUchar((PUCHAR)(Port), (PUCHAR)(Buffer), (ULONG)(Count)) +#define repoutsw(Port, Buffer, Count) ScsiPortWritePortBufferUshort((PUSHORT)(Port), (PUSHORT)(Buffer), (ULONG)(Count)) + +#define FreeMemHandle(MemHandle) +#define LocalMemHandle(MHP, MemPtr)(*(MHP) = (void FAR *)(MemPtr)) +#define LocalPostCallback(ofs) ofs +#define msPause(msTicks) {unsigned register i = msTicks;while(i--) ScsiPortStallExecution(1000L);} +#define ImportReq(Req) Req +#define ExportReq(Req) Req +#define RegisterIO(HA, Base, Length, AddrSpace) ((PUCHAR)ScsiPortGetDeviceBase(HA, Isa, 0, ScsiPortConvertUlongToPhysicalAddress((ULONG)Base), Length, (AddrSpace == AddrSpaceIO) )) + #define AddrSpaceIO 0 + #define AddrSpaceMem 1 +#define DeregisterIO(HA, Handle) ScsiPortFreeDeviceBase(HA, Handle) + +typedef PUCHAR IOHandle; +typedef unsigned short CriticalT; + +#define critical(HA) +#define uncritical(HA) + +//#define EnvBreakPoint(HA) DbgBreakPoint() // Define the break call for the DEBUG breakpoit +#define EnvBreakPoint(HA) + + +/* Load time permanent parameters and parm list type: */ +#define ParmStrucVersion 0x1010 /* Structure format 1.0, content version 1.0 */ +struct AD_ParmStruc { + + unsigned short Version; /* Version of this entry */ + unsigned short ParmLength; /* Number of parm bytes to follow */ + unsigned short ADStrucEntries; /* Number of AD Parm structs */ + struct AD_ParmList *AD_List; /* Pointer to list AD Parm strucs */ + unsigned short DebugEntries; /* Number of debug things */ + int *DebugPtr; /* Pointer to debug level control */ + +}; + +struct AD_ParmList { + + unsigned short IO_Addr; /* IO address for this addapter */ + unsigned char ParmList[16]; /* Parm bytes for the adapter at this address */ + +}; + +// ParmList array index defines: +#define PL_ID_PARMS 0 /* Start of drive parms per SCSI ID (0-7) */ + #define PL_ALLOW_SYNC 0x01 /* Attempt sync. xfer on this SCSI_ID */ + #define PL_USE_DISC 0x02 /* Attempt disconnect/reconnect on this SCSI ID */ + #define DRIVE_PL(SCSI_ID) (PL_ID_PARMS + SCSI_ID) +#define PL_HA_ID 15 + +typedef unsigned char ADParmList[16]; /* Type for adapter parm list; an array, or pointer to array */ + +#define LogMessage(HA, Req, TID, LUN, Code, Info) ScsiPortLogError(HA, Req, 0, TID, LUN, Code, Info) +#define MSG_PARITY SP_BUS_PARITY_ERROR +#define MSG_INTERNAL_ERROR SP_INTERNAL_ADAPTER_ERROR // Some form of internal error +#define MSG_BUS_FREE SP_UNEXPECTED_DISCONNECT +#define MSG_SCSI_PROTCOL SP_PROTOCOL_ERROR +#define MSG_BAD_RESEL SP_INVALID_RESELECTION +#define MSG_SEL_TIMEOUT SP_BUS_TIMEOUT +#define MSG_NO_INTERRUPTS SP_IRQ_NOT_RESPONDING +#define MSG_BAD_FIRMWARE SP_BAD_FW_ERROR +#define MSG_NO_INT_ENABLE SP_IRQ_NOT_RESPONDING + +#endif /* __NTENV_H__ */ diff --git a/private/ntos/miniport/always/ntmgr.c b/private/ntos/miniport/always/ntmgr.c new file mode 100644 index 000000000..511f7b4d2 --- /dev/null +++ b/private/ntos/miniport/always/ntmgr.c @@ -0,0 +1,547 @@ +/* Copyright (C) 1991-1994 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" + +#define HAExtentLen sizeof(struct Adapter) +#define DEVExtentLen sizeof(struct DeviceDescr) +#define REQExtentLen sizeof(struct IOReqExtension) + + +enum ASPI_Priority {NORMAL_REQ, PRIORTY_REQ, IPRIORTY_REQ}; +void IExecuteReq(ADAPTER_PTR HA, DEVICE_PTR DevP, IO_REQ_PTR Req, enum ASPI_Priorty Priorty); + +extern void EnvLib_Init(void); + + +#define FreeDev(DevP) + +#if !defined(APIFindDev) +DEVICE_PTR +APIFindDev (const ADAPTER_PTR HA, const unsigned TID, const unsigned LUN) +{ + + return ScsiPortGetLogicalUnit(HA, 0, (char)TID, (char)LUN); + +} +#endif + + +void +APISetStatus (IO_REQ_PTR Req, // Request structure + APIStatus Status, // Status + TerminateCode Terminal, // Is this the terminal (Notify completion) + AutosenseCode IsSenseable) // Auto sense allowed? +{ + static U8 REQStats[]={ + SRB_STATUS_PENDING, SRB_STATUS_PENDING, SRB_STATUS_ABORTED, + SRB_STATUS_BAD_FUNCTION, SRB_STATUS_INVALID_REQUEST, SRB_STATUS_NO_HBA, + SRB_STATUS_DATA_OVERRUN, SRB_STATUS_SELECTION_TIMEOUT, + SRB_STATUS_INVALID_TARGET_ID, SRB_STATUS_INVALID_LUN + }; + + static U8 ADStats[]={ + SRB_STATUS_NO_HBA, SRB_STATUS_BUSY, SRB_STATUS_UNEXPECTED_BUS_FREE, + SRB_STATUS_PHASE_SEQUENCE_FAILURE, SRB_STATUS_BUS_RESET, + SRB_STATUS_AUTOSENSE_VALID, SRB_STATUS_ERROR}; + + +// Make sure the high numbers match what this module knows of: +#if S_LAST_S_REQ != 0x09 +#err +#endif + +#if S_LAST_S_AD != 0x06 +#err +#endif + +#if S_LAST_S_SYS != 0 +#err +#endif + + + switch (ErrorClass(Status)) { + + case RequestClass: + + DEBUG(0, if (Status == S_REQ_ABORT) + TRACE(0, ("APISetStatus(): Set Req (%x) status to aborted\n")) ); + Req->SrbStatus = REQStats[ErrorCode(Status)]; + break; + + + case AdapterClass: + + Req->SrbStatus = ADStats[ErrorCode(Status)]; + break; + + + case TargetClass: + + Req->ScsiStatus = ErrorCode(Status); + switch (ErrorCode(Status)) { + + case STATUS_CKCOND: + + ReqDataCount(Req) = ReqSavedIndex(Req); +#if defined(AUTOSENSE) + if ((IsSenseable == Senseable) && ReqSenseCount(Req)) { + + Terminal = NonTerminal; + QueueInternalRequest(ReqAdapterPtr(Req), Req, RTAutoSenseReq); + + } else +#endif + Req->SrbStatus = SRB_STATUS_ERROR; + break; + + + case STATUS_GOOD: + case STATUS_CONDMET: + case STATUS_INTGOOD: + case STATUS_INTCONDMET: + + Req->SrbStatus = SRB_STATUS_SUCCESS; + if (ReqDataCount(Req) > ReqSavedIndex(Req)) { + + Req->SrbStatus = SRB_STATUS_DATA_OVERRUN; + + // Update number of bytes transferred. + + // ReqSavedIndex is the number of bytes successfully transfered + + // One thing the NT people will have to address is zero latency + // xfers. How will number of bytes xfered be represented + // on an error, when the xfer has holes? + ReqDataCount(Req) = ReqSavedIndex(Req); + + } + break; + + + default: + + Req->SrbStatus = SRB_STATUS_ERROR; + break; + + } + TRACE(4, ("APISetStatus(): Setting target status to %02x\n", + Req->ScsiStatus)); + + break; + } + + TRACE(4, ("APISetStatus(): Setting request status to %02x\n", Req->SrbStatus)); + + if (Terminal != NonTerminal) { + + TRACE(3, ("APISetStatus(): Notifying completion\n")); + Notify(ReqAdapterPtr(Req), Req); + + } +} + + + +void +Notify (ADAPTER_PTR HA, IO_REQ_PTR Req) +{ + + if (ReqState(Req).InternalRequest) + (*(ReqPost(Req)))(Req); + else + ScsiPortNotification(RequestComplete, HA, Req); + +} + + +void +APINotifyReset (ADAPTER_PTR HA) +{ + TRACE(0, ("APINotifyReset():\n")); + ScsiPortNotification(ResetDetected, HA); +} + + + +void +IExecuteReq (ADAPTER_PTR HA, DEVICE_PTR DevP, IO_REQ_PTR Req, enum ASPI_Priorty Priorty) +{ + TRACE(5, ("IExecuteReq(): Got request %x for device %x on adapter %x\n", Req, DevP, HA)); + + if (HA->DevInfo[ReqTargetID(Req)].Flags.NeedSync) + QueueInternalRequest(HA, Req, RTSyncNegReq); + else + QueueReq(HA, (IO_REQ_PTR)Req, (Priorty > NORMAL_REQ)); + +} + + +#define HAPollTime (ULONG)500000 // Time in uS for 500mS +void +HATimer (IN PVOID HAObject) +{ + + TRACE(6, ("HATimer(): Timer entered\n")); + ((ADAPTER_PTR)HAObject)->Service(HA_TIMER, (ADAPTER_PTR)HAObject, 0l); + ScsiPortNotification(RequestTimerCall, HAObject, HATimer, HAPollTime); + +} + + + +BOOLEAN +HAInit (PVOID HAObject) +{ + ADAPTER_PTR HA = HAObject; + + TRACE(3, ("HAInit(): \n")); + + HA->Ext->InternalRequest.Length = sizeof(HA->Ext->InternalRequest); + HA->Ext->InternalRequest.SrbExtension = &(HA->Ext->IntlReqExtension); + ReqCommand(&(HA->Ext->InternalRequest)) = SRB_FUNCTION_EXECUTE_SCSI; // internally generated command + ReqAdapterPtr(&HA->Ext->InternalRequest) = HA; + ReqState(&(HA->Ext->InternalRequest)).InternalRequest = 1; + + ((ADAPTER_PTR)HAObject)->Service(HA_INITIALIZE, (ADAPTER_PTR)HAObject, 0l); + ScsiPortNotification(RequestTimerCall, HAObject, HATimer, HAPollTime); + return TRUE; + +} + + + +BOOLEAN +ResetBus (PVOID HAObject, ULONG PathID) +{ + + TRACE(0, ("ResetBus(): \n")); + + ((ADAPTER_PTR)HAObject)->Service(HA_RESET_BUS, (ADAPTER_PTR)HAObject, 0l); + + // Stall here, to allow the interrupt service routine to handle the reset + // and blow off requests, etc. + ScsiPortStallExecution(100l); + + // Send completion of reset request: + ScsiPortCompleteRequest(HAObject, (UCHAR)PathID, (UCHAR)-1, (UCHAR)-1, SRB_STATUS_BUS_RESET); + return TRUE; + +} + + + +BOOLEAN +AdapterState (IN PVOID HAObject, IN PVOID Context, IN BOOLEAN SaveState) +{ + + if (SaveState) + ((ADAPTER_PTR)HAObject)->Service(HA_RESTORE_STATE, (ADAPTER_PTR)HAObject, + (U32)0); + return TRUE; + +} + + +BOOLEAN +StartIO (IN PVOID HAObject, IN PSCSI_REQUEST_BLOCK Req) +{ + ADAPTER_PTR HA = HAObject; + DEVICE_PTR DevP; + int i; + + TRACE(2, ("StartIO(): Req @%x, Function = 0x%x, Req->SrbExtension @%x\n", Req, Req->Function, Req->SrbExtension)); + + switch (Req->Function) { + + case SRB_FUNCTION_EXECUTE_SCSI: + + + ReqNext(Req) = (IO_REQ_PTR)NILL; + ReqAdapterPtr(Req) = HA; + for (i=0; i < sizeof(ReqState(Req)); i++) + ((U8 *)&ReqState(Req))[i] = 0; + + ReqState(Req).ReqType = RTNormalReq; + + if ( (DevP = ScsiPortGetLogicalUnit(HA, Req->PathId, ReqTargetID(Req), ReqTargetLUN(Req))) == NILL) { + + TRACE(3, ("ExecuteReq(): Unable to get device info\n")); + Req->SrbStatus = SRB_STATUS_NO_DEVICE; + return FALSE; + + } + + ReqDevP(Req) = DevP; + if (!DevP->Flags.Initialized) + QueueInternalRequest(HA, Req, RTGetInfoReq); + else + IExecuteReq(HA, DevP, Req, NORMAL_REQ); + break; + + + case SRB_FUNCTION_RESET_BUS: + + TRACE(3, ("StartIO(): RESET_BUS command\n")); + ResetBus(HAObject, Req->PathId); + break; + + + case SRB_FUNCTION_RESET_DEVICE: + case SRB_FUNCTION_TERMINATE_IO: + case SRB_FUNCTION_FLUSH: + case SRB_FUNCTION_SHUTDOWN: + + Req->SrbStatus = SRB_STATUS_SUCCESS; + ScsiPortNotification(RequestComplete, HA, Req); + break; + + + case SRB_FUNCTION_ABORT_COMMAND: + + TRACE(0, ("StartIO(): Request at %x to abort request %x\n", Req, Req->NextSrb)); + if ((DevP = ScsiPortGetLogicalUnit(HA, Req->PathId, ReqTargetID(Req), ReqTargetLUN(Req))) == NILL + || (DevP->Flags.Initialized == 0) + || !AbortRequest(HA, DevP, Req->NextSrb) ) { + + TRACE(0, ("StartIO(): Abort operation failed\n")); + Req->SrbStatus = SRB_STATUS_ABORT_FAILED; + + } else { + + + TRACE(0, ("StartIO(): Abort operation success\n")); + Req->SrbStatus = SRB_STATUS_SUCCESS; + + } + ScsiPortNotification(RequestComplete, HA, Req); + break; + + + case SRB_FUNCTION_RELEASE_RECOVERY: + case SRB_FUNCTION_RECEIVE_EVENT: + case SRB_FUNCTION_IO_CONTROL: + default: + + TRACE(0, ("StartIO(): Unsupported command: 0x%x\n", Req->Function)); + APISetStatus(Req, S_REQ_OPCODE, Terminal, NotSenseable); + return FALSE; + break; + + + } + + ScsiPortNotification(NextLuRequest, HA, Req->PathId, Req->TargetId, Req->Lun); + return TRUE; + +} + + +BOOLEAN +GeneralISR (PVOID HAObject) +{ + + return (BOOLEAN) ( ((ADAPTER_PTR)HAObject)->ISR((ADAPTER_PTR)HAObject) ); + +} + + +ULONG +FindAdapter (IN PVOID HAObject, IN PVOID PContext, IN PVOID BusInfo, + IN PCHAR ArgString, IN OUT PPORT_CONFIGURATION_INFORMATION Config, + OUT PBOOLEAN PAgain) +{ + ADAPTER_PTR HA = HAObject; + + TRACE(3, ("FindAdapter(): Adapter ptr = %x, Config ptr = %x, Len = 0x%x\n", HA, Config, sizeof(struct _PORT_CONFIGURATION_INFORMATION))); + + /* Hunt down and register the adapters in the system: */ + HA->IOBaseAddr = (U16)ScsiPortConvertPhysicalAddressToUlong( + (*Config->AccessRanges)[0].RangeStart); + + if (Adapter_Init(HA, (unsigned *)PContext)) { + + // Set Again TRUE, only if we're being called with a non-sepcific access range + *PAgain = ScsiPortConvertPhysicalAddressToUlong( + (*Config->AccessRanges)[0].RangeStart) == 0; + + Config->BusInterruptLevel = HA->IRQNumber; + + Config->ScatterGather = HA->Supports.ScatterGather; + Config->MaximumTransferLength = 0x400000; + Config->NumberOfPhysicalBreaks = 0x400; +// Config->NumberOfPhysicalBreaks = HA->MaxSGListLength; + + (*Config->AccessRanges)[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(HA->IOBaseAddr); + (*Config->AccessRanges)[0].RangeLength = HA->IOAddrLen; + (*Config->AccessRanges)[0].RangeInMemory = FALSE; + + Config->NumberOfBuses = 1; + Config->InitiatorBusId[0] = HA->SCSI_ID; + Config->Master = (HA->Physical.Xfermode == XM_MASTER) || (HA->Physical.Xfermode == XM_MASTER24); + Config->Dma32BitAddresses = (HA->Physical.Xfermode == XM_MASTER); + Config->DemandMode = (HA->Physical.Xfermode == XM_DMAD); + Config->NeedPhysicalAddresses = XM_PHYSICAL(HA->Physical.Xfermode); + Config->MapBuffers = TRUE; + Config->CachesData = HA->Supports.Caching; + Config->AlignmentMask = 0x3; + + Config->TaggedQueuing = FALSE; + +#if defined(AUTOSENSE) + Config->AutoRequestSense = TRUE; +#else + Config->AutoRequestSense = FALSE; +#endif + + Config->MultipleRequestPerLu = Config->AutoRequestSense; + + Config->ReceiveEvent = FALSE; + + HA->Ext = ScsiPortGetUncachedExtension(HA, Config, sizeof(AdapterExtension)); + + return SP_RETURN_FOUND; + + } else { + + *PAgain = FALSE; + return SP_RETURN_NOT_FOUND; + + } +} + + +ULONG +DriverEntry (IN PVOID HAObject, IN PVOID ARG) +{ + HW_INITIALIZATION_DATA InitData; // Adapter init. struct + unsigned i; + ULONG AdapterCount; + ULONG ISAStatus, EISAStatus; +// ULONG MCAStatus, LocalStatus; + + /* Initialize the environment: */ + EnvLib_Init(); + + // Initialize the object + for (i=0; i < sizeof(InitData); i++) + ((char *)&InitData)[i] = 0; + + InitData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA); + + // Set pointers to service functions: + InitData.HwInitialize = HAInit; + InitData.HwStartIo = StartIO; + InitData.HwInterrupt = GeneralISR; + InitData.HwFindAdapter = FindAdapter; + InitData.HwResetBus = ResetBus; + InitData.HwAdapterState = AdapterState; // + + // Set capabilities + InitData.MapBuffers = TRUE; // This should be in PORT config info + InitData.NeedPhysicalAddresses = FALSE; + InitData.TaggedQueuing = FALSE; + +#if defined(AUTOSENSE) + InitData.AutoRequestSense = TRUE; +#else + InitData.AutoRequestSense = FALSE; +#endif + + InitData.MultipleRequestPerLu = InitData.AutoRequestSense; + + InitData.ReceiveEvent = FALSE; + + // Set misc. things: + InitData.NumberOfAccessRanges = 1; + + // Set the size of extensions + InitData.DeviceExtensionSize = HAExtentLen; + InitData.SpecificLuExtensionSize = DEVExtentLen; + InitData.SrbExtensionSize = REQExtentLen; + + AdapterCount = 0; + + TRACE(3, ("DriverEntry(): Trying EISA adapters\n")); + InitData.AdapterInterfaceType = Eisa; + EISAStatus = ScsiPortInitialize(HAObject, ARG, &InitData, (PVOID)&AdapterCount); + TRACE(2, ("DriverEntry(): ScsiPortInitialize() returned: %x\n", EISAStatus)); + + if (EISAStatus != 0) { + + TRACE(3, ("DriverEntry(): Trying ISA adapters\n")); + InitData.AdapterInterfaceType = Isa; + ISAStatus = ScsiPortInitialize(HAObject, ARG, &InitData, (PVOID)&AdapterCount); + TRACE(2, ("DriverEntry(): ScsiPortInitialize() returned: %x\n", ISAStatus)); + + } + + return min(ISAStatus, EISAStatus); + +} + + + +void +GetXferSegment (const ADAPTER_PTR HA, IO_REQ_PTR Req, SegmentDescr *SGDescr, + U32 Offset, BOOLEAN DemandPhysicalAddr) +{ + + TRACE(4, ("GetXferSegment(): Offset = %d\n", Offset)); + TRACE(4, ("GetXferSegment(): Non-S/G request, ReqDataCount = %d\n", ReqDataCount(Req))); + + if (Offset < ReqDataCount(Req)) { // Make sure we don't over run + + SGDescr->SegmentLength = ReqDataCount(Req) - Offset; + SGDescr->SegmentPtr = (U32)ReqDataPtr(Req) + Offset; + + } else { + + SGDescr->SegmentLength = 0; // No data left + SGDescr->SegmentPtr = 0; + BreakPoint(HA); + + } + TRACE(4, ("GetXferSegment(): %d bytes remain in segment at %08x (offset %d)\n", + SGDescr->SegmentLength, SGDescr->SegmentPtr, Offset)); + + SGDescr->Flags.IsPhysical = FALSE; + + if (DemandPhysicalAddr) { + + if (ReqState(Req).InternalRequest) { + + TRACE(5, ("GetXferSegment(): Mapping internal request\n")); + MapToPhysical(HA, SGDescr); + + } else { + + ULONG Size = SGDescr->SegmentLength; + + SGDescr->SegmentPtr = (U32)ScsiPortConvertPhysicalAddressToUlong( + ScsiPortGetPhysicalAddress(HA, Req, + (PVOID)((U32)ReqDataPtr(Req) + Offset) /*(SGDescr->SegmentPtr)*/, + &Size)); + + if (Size < SGDescr->SegmentLength) + SGDescr->SegmentLength = Size; + + DEBUG(5, { + if (SGDescr->SegmentLength < (ReqDataCount(Req) - Offset)) + DPrintf("Segment length is %d out of %d\n", + SGDescr->SegmentLength, ReqDataCount(Req) - Offset);}); + + SGDescr->Flags.IsPhysical = TRUE; + + TRACE(5, ("GetXferSegment(): Mapped to 0x%lx for %lu bytes\n", + SGDescr->SegmentPtr, Size)); + + } + } +} diff --git a/private/ntos/miniport/always/rqm.c b/private/ntos/miniport/always/rqm.c new file mode 100644 index 000000000..e68ad9b62 --- /dev/null +++ b/private/ntos/miniport/always/rqm.c @@ -0,0 +1,569 @@ +/* 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" + +/* + Add the device index for a request to the tail of the FIFO. AddReqFIFO + is called only when a request is moved to the head of the queue, i.e., + the first command for a device or when the current request for a device + completes, and the second command moves to the head. +*/ + +void REGPARMS +AddReqFIFO (ADAPTER_PTR HA, DEVICE_PTR DevP) +{ + DevP->FIFO_Next = NILL; + + TRACE(3,("AddReqFIFO(): Adding device %02x to FIFO\n", DevP)); + + if (HA->FIFO_Head == DevP) { + + PanicMsg("AddReqFIFO(): Circular device chain\n"); + + } + + critical(HA); + if (HA->FIFO_Head == NILL) + HA->FIFO_Head = DevP; + else + HA->FIFO_Tail->FIFO_Next = DevP; + + HA->FIFO_Tail = DevP; + uncritical(HA); + +} + + + +/* + Get the next request in the request FIFO. The FIFO is not incremented + until AcceptReq is called. See the comment below for more details. +*/ + +IO_REQ_PTR REGPARMS +GetReqFIFO (ADAPTER_PTR HA) +{ + IO_REQ_PTR Req=NILL; + + // Because an abort request may empty the pending queue, we will scan the + // device FIFO until we find a device with an non-empty request list. If we + // don't find one, return NULL, which says there are not more pending requests. + while (HA->FIFO_Head != NILL) { + + Req = HA->FIFO_Head->PendingReqList; + if (Req == NILL) + HA->FIFO_Head = HA->FIFO_Head->FIFO_Next; + else + break; + + } + + return Req; +} + + + +/* Start the next request for a given adapter: */ +void +StartNext (ADAPTER_PTR HA, int StartLevel) +{ + IO_REQ_PTR Req; + + if (!(HA->State.Busy) && (Req = GetReqFIFO(HA)) != NILL) { + + critical(HA); + HA->Ext->MI_Count = HA->Ext->MI_Needed = HA->Ext->MO_Count = 0; /* Clear msg buffers */ + HA->CurrReq = Req; + HA->CurrDev = (DEVICE_PTR)ReqDevP(Req); + HA->Service(HA_INITIATE, HA, (long)StartLevel); + uncritical(HA); + TRACE(3,("StartNext(): Starting request: %lx\n", (long)Req)); + + } else { + + TRACE(3,("StartNext(): Empty queue\n")); + + } +} + + +/* + If the adapter has taken a request off the queue, and has attempted + to initiate it, it will set the "ReqStarting" flag. When the controller + acknowledges the start of the command, then the following procedure is + called to remove it from the queue. If the controller does not accept the + command (usually caused if a reselection occuring before the new + target is selected), the flag will be cleared, and the request not removed + from the queue. So the next time GetReqFIFO is called, the same request + will be returned. +*/ + +void +AcceptReq (ADAPTER_PTR HA) +{ + DEVICE_PTR DevP; + IO_REQ_PTR Req; + + if ((HA->ReqStarting !=0) && (--(HA->ReqStarting) == 0)) { + + + critical(HA); + + DevP = HA->FIFO_Head; + + DevP->CurrDepth++; // Bump the numberof active requests + HA->FIFO_Head = DevP->FIFO_Next; // Advance the next device w/ pending requests + + Req = DevP->PendingReqList; + + DevP->PendingReqList = ReqNext(Req); + ReqNext(Req) = DevP->AcceptedList; + DevP->AcceptedList = Req; + + ReqState(Req).Connected = 1; + + uncritical(HA); + +#if defined(KEEP_STATS) + HA->ReqsAccepted++; +#endif + + TRACE(5,("AcceptReq(): Request (@%lx) accepted for device %x\n", Req, DevP)); + + } +} + + + +/* + Find a request block by device and queue tag; returns a pointer to + the request, or NULL if it not found. +*/ +IO_REQ_PTR +Find_Req (DEVICE_PTR DevP, const unsigned LUN, const unsigned QID) +{ + IO_REQ_PTR Req = DevP->AcceptedList; + + while ((Req != NILL) && ((ReqTargetLUN(Req) != LUN) +#if defined(ReqQID) + || (ReqQID(Req) != QID) +#endif + )) { + + Req = ReqNext(Req); + + } + return Req; +} + + + +int +Reselect_Req (ADAPTER_PTR HA, IO_REQ_PTR Req) +{ + + HA->CurrReq = Req; + HA->CurrDev = (DEVICE_PTR)ReqDevP(Req); + HA->State.Busy = 1; + HA->State.Reselecting = 0; + HA->Ext->MI_Count = HA->Ext->MI_Needed = HA->Ext->MO_Count = 0; /* Clear message buffers */ + + /* Reselection performs an implied restore pointers: */ + HA->ReqCurrentIndex = ReqSavedIndex(HA->CurrReq); + TRACE(3, ("Reselect_Req(): Implied restore data ptr, ReqSavedIndex() = %d\n", + ReqSavedIndex(HA->CurrReq))); + // CurrentCounts == 0 will cause a GetXferSegment from the above offset + HA->ReqCurrentCount = 0; + + TRACE(4,("Reselect_Req(): reselect on TID %d, req @ %lx\n", ReqTargetID(Req), Req)); + HA->Service(HA_LED, HA, 1); + + ReqState(Req).Connected = 1; + return 0; + +} + + + +int +Reselect (ADAPTER_PTR HA, const unsigned TID, const unsigned LUN, const unsigned QID) +{ + DEVICE_PTR DevP; + IO_REQ_PTR Req; + + HA->CurrReq = NILL; + DevP = APIFindDev(HA, TID, LUN); + if (DevP == NILL) + return 1; + + Req = Find_Req(DevP, LUN, QID); + if (Req == NILL) + return 1; + return Reselect_Req(HA, Req); + +} + + +/* + This function handles completion of an arbitrary request by: + + 1) De-queuing the request + + 2) Handling of temporary device descriptor disposal + + 3) Handling sync. negotiations which fail with a check condition status + + 4) Notify the request call back (if ReqFlags(Req).Post is true) + + 5) --->> Sets HA->CurrReq to NILL; <<--- + This is highlighted because the request passed in is not necessarly + the one in HA->CurrReq. However, if an adapter is completing a + request, then it's attention can't be on a differant one too. +*/ + +void +ReqDone (ADAPTER_PTR HA, IO_REQ_PTR Req) +{ + DEVICE_PTR DevP; + + + if (Req == (IO_REQ_PTR)NILL) { + + TRACE(0, ("ReqDone(): Completing NULL request\n")); + return; + + } + + /* Get the descriptor for the device which processed this request: */ + DevP = (DEVICE_PTR)ReqDevP(Req); + if (DevP->PendingReqList == Req) + AcceptReq(HA); + + DevP->CurrDepth--; // Dec. number of active reqs. + + if (DevP->AcceptedList == Req) + DevP->AcceptedList = ReqNext(Req); + else { + + /* Search for the pointer to this request in the accepted list: */ + IO_REQ_PTR Req2 = DevP->AcceptedList; + while (ReqNext(Req2) != Req && Req2 != NILL) + Req2 = ReqNext(Req2); + + if (Req2 == NILL) + PanicMsg("ReqDone(): Request not on list. Catastrophic failure.\n"); + + /* Unlink by pointing this one's predicessor to this one's next. */ + ReqNext(Req2) = ReqNext(Req); + + } + + + /* + Since we just finished up one request, add the next (if any) to the FIFO + of devices with pending requests. + */ + if ((DevP->PendingReqList != NILL) && (DevP->CurrDepth < DevP->MaxDepth)) + AddReqFIFO(HA, DevP); + + /* If we get a check condition during sync. negotiaitons (Need_Sync still + true, then the target rejected the synchronous request via by 1) not + completing the negotiaition (no msg in phase); & 2) going directly + to the status phase (by passing command phase). Clean up the sync. + control bits for the device, saying that sync. is not allowed, don't + use it, and don't ask for it. + */ + + if ((ReqAPIStatus(Req) == S_TAR_CHECKCOND) && (HA->DevInfo[ReqTargetID(Req)].Flags.NeedSync)) { + + HA->DevInfo[ReqTargetID(Req)].Flags.UseSync = HA->DevInfo[ReqTargetID(Req)].Flags.AllowSync = + HA->DevInfo[ReqTargetID(Req)].Flags.NeedSync = FALSE; + TRACE(3,("ReqDone(): Sync. negotiation aborted by CHECK CONDITION\n")); + + } + + HA->CurrReq = NILL; + + /* If we are to notify someone of the command completion, do so now: */ + + TRACE(4,("ReqDone(): Status = %04x\n", ReqAPIStatus(Req))); + +#if defined(KEEP_STATS) + HA->ReqsCompleted++; +#endif + + ReqState(Req).Connected = 0; + APISetStatus(Req, ReqAPIStatus(Req), Terminal, HA->Supports.OnBoardQueuing ? NotSenseable : Senseable); + +} + + + +LOCAL IO_REQ_PTR * REGPARMS +ScanReqList (IO_REQ_PTR *List, IO_REQ_PTR Req) +{ + if (List == (IO_REQ_PTR *)NILL) + return List; + + while (*List != (IO_REQ_PTR)NILL && *List != Req) + List = (IO_REQ_PTR *)&(ReqNext(*List)); + return List; + +} + + +BOOLEAN +AbortRequest (ADAPTER_PTR HA, DEVICE_PTR DevP, IO_REQ_PTR Req) +{ + IO_REQ_PTR *ReqScan = &(DevP->PendingReqList); + BOOLEAN OnAccepted=FALSE; + + if (HA->CurrReq == Req) { + + TRACE(1, ("AbortRequest(): Request is active; not aborting\n")); + return FALSE; + + } + + if (*ReqScan == Req) { + + TRACE(2, ("AbortRequest(): Request to abort found at PendingHead\n")); + if ((DevP->PendingReqList = ReqNext(Req)) == NILL) { + + // We have removed the only request for this device, so now + // remove the device from the chain of pending devices: + if (HA->FIFO_Head == DevP) { + + HA->FIFO_Head = DevP->FIFO_Next; + DevP->FIFO_Next = NILL; + + } else { + + DEVICE_PTR ScanDev=HA->FIFO_Head; + while (ScanDev != NILL && ScanDev->FIFO_Next != DevP) + ScanDev = ScanDev->FIFO_Next; + + if (ScanDev != NILL) + ScanDev->FIFO_Next = DevP->FIFO_Next; + + if (HA->FIFO_Tail == DevP) + HA->FIFO_Tail = ScanDev; + + } + } + + } else { + + if ((ReqScan = ScanReqList(ReqScan, Req)) == NILL) { + + TRACE(2, ("AbortRequest(): Scanning accepted list\n")); + ReqScan = ScanReqList(&(DevP->AcceptedList), Req); + OnAccepted = TRUE; + + } + + } + + if (ReqScan == NILL) { + + TRACE(2, ("AbortRequest(): Request not found in pending list\n")); + return FALSE; // but the abort didn't work directly + + } + + // At this point, ReqScan points to pointer to the request we want to abort + *ReqScan = ReqNext(Req); // Take Req out of chain + + // OK, so Req has been verified as being on the pending queue, and has + // been removed. Now we can complete the request, with an aborted status. + + APISetStatus(Req, S_REQ_ABORT, Terminal, NotSenseable); + + if (OnAccepted) { + + // This was an accpted request. Decrement the pending count to allow + // more requests to pass to the target. + DevP->CurrDepth--; + + } + + return TRUE; // Abort was successful + +} + + +/* + Queue up a request. The queues are kept by Target ID. If an entry already + exists for a particular Target ID, then the new request is appended to the + queue. If the queue is empty, the request is added as the head, and the + target ID is added to the FIFO of targets with requests pending. +*/ + +void +QueueReq (ADAPTER_PTR HA, IO_REQ_PTR Req, int AtHead) +{ + DEVICE_PTR DevP = (DEVICE_PTR)ReqDevP(Req); + + TRACE(4,("QueueReq(): Got request @%lx for TID/LUN %d/%d(device %lx)\n", Req, ReqTargetID(Req), ReqTargetLUN(Req), DevP)); + + DmsPause(6, 1000); + + if (HA->State.OffLine) { + + APISetStatus(Req, S_AD_OFF, Terminal, NotSenseable); + return; + + } + + ReqAPIStatus(Req) = S_REQ_ACCEPTED; + APISetStatus(Req, S_REQ_ACCEPTED, NonTerminal, NotSenseable); + + if (ReqCDBLen(Req) == 10 || ReqCDBLen(Req) == 6 || ReqCDBLen(Req) == 12) { + + } else { + + TRACE(0,("QueueReq(): Request rejected; CDB Length = %d\n", ReqCDBLen(Req))); + APISetStatus(Req, S_REQ_OPCODE, NonTerminal, NotSenseable); + return; + + } + + ReqSavedIndex(Req) = 0; // Index used for saved data pointers + + /* If we support linked commands, see if this one is linked; if it is not, + force the link chain pointer to NILL. If linked commands are not + supported, then always force link field to zero + */ + + critical(HA); + + /* At head will only come from an auto-request sense; therefore, the first + entry (if any) will NOT be in progress. If AtHEad is requested at any + other time, the top request on the queue must be checked to see if it + in progress; and if so, the AtHead request must be made the second + request on the queue. + */ + + if (AtHead) { + + TRACE(5, ("QueueReq(): Queing at head\n")); + + ReqNext(Req) = DevP->PendingReqList; + DevP->PendingReqList = Req; + if ((ReqNext(Req) == NILL) && (DevP->CurrDepth < DevP->MaxDepth)) + AddReqFIFO(HA, DevP); + + } else { + +#if defined(RF_LINKED) + if (!(ReqFlags(Req) & RF_LINKED)) + ReqNext(Req) = NILL; +#else + ReqNext(Req) = NILL; +#endif + + if (DevP->PendingReqList == NILL) { + + DevP->PendingReqList = Req; + if (DevP->CurrDepth < DevP->MaxDepth) + AddReqFIFO(HA, DevP); + + } else { + + IO_REQ_PTR ReqScan = DevP->PendingReqList; + while (ReqNext(ReqScan) != NILL) + ReqScan = ReqNext(ReqScan); + ReqNext(ReqScan) = Req; + + } + + } + +#if defined(KEEP_STATS) + HA->ReqsQueued++; +#endif + + TRACE(2,("QueueReq(): Request @ %0lx", Req)); + TRACE(2,(" CDB[0] = %02x, Data @%08lx, Count = %ld\n", ReqCDB(Req)[0], ReqDataPtr(Req), ReqDataCount(Req))); + + DmsPause(6, 2000); + if (DevP->CurrDepth < DevP->MaxDepth) { + + TRACE(5,("About to tickle adapter\n")); + HA->Service(HA_TICKLE, HA, (long)0); + + } + + uncritical(HA); + +} + + + +void +BlowAwayRequests (ADAPTER_PTR HA, int Which, APIStatus Status) +{ + + unsigned ID, LUN; + DEVICE_PTR DevP; + IO_REQ_PTR Req; + + /* Walk the device tables, and abort accepted commands. Then set the + device states to require re-negotiating sync. xfers */ + + TRACE(1, ("BlowAwayRequests(): Scaning for device IDs 0-%d on HA %x\n", HA->Max_TID, HA)); + for (ID = 0; ID <= HA->Max_TID; ID++) { + + HA->DevInfo[ID].Flags.UseSync = 0; + HA->DevInfo[ID].Flags.NeedSync = HA->DevInfo[ID].Flags.AllowSync; + + for (LUN = 0; LUN <= 7; LUN++) { + + DevP = APIFindDev(HA, ID, LUN); + if (DevP == NILL || DevP->Flags.Initialized == 0) + continue; + + TRACE(2, ("BlowAwayRequests(): Got device descriptor for %d/%d\n", ID, LUN)); + if (Which == ACTIVE_REQUESTS || Which == ALL_REQUESTS) { + + while (DevP->AcceptedList != NILL) { + + TRACE(4, ("BlowAwayRequests(): Completeing request %x\n", DevP->AcceptedList)); + ReqAPIStatus(DevP->AcceptedList) = Status; + if (HA->Supports.OnBoardQueuing) + HA->Service(HA_ABORT_REQ, HA, (U32)DevP->AcceptedList); + else + ReqDone(HA, DevP->AcceptedList); + + } + } // if (Which ... + + if (Which == PENDING_REQUESTS || Which == ALL_REQUESTS) { + + for (Req=DevP->PendingReqList; Req != NILL; Req=DevP->PendingReqList) { + + TRACE(4, ("BlowAwayRequests(): Completeing request %x\n", Req)); + DevP->PendingReqList = ReqNext(Req); + APISetStatus(Req, Status, Terminal, NotSenseable); + + } // for (Req ... + } // if (Which ... + } // for (LUN = ... + } // for (ID = ... +} + + + +void +HAParmChange (ADAPTER_PTR HA) +{ + HA->Service(HA_PARM_CHANGE, HA, (U32)0); +} + diff --git a/private/ntos/miniport/always/rqm.h b/private/ntos/miniport/always/rqm.h new file mode 100644 index 000000000..28f67562a --- /dev/null +++ b/private/ntos/miniport/always/rqm.h @@ -0,0 +1,330 @@ +/* Copyright (C) 1991, 1992 by Always Technology Corporation. + This module contains information proprietary to + Always Technology Corporation, and should be treated as confidential. + */ + +#ifndef __RQM_H__ +#define __RQM_H__ + +#define DevInfoInqSize 8 // 8 bytes of Inquiry buffer for Device info requests + +typedef struct DeviceDescr *DEVICE_PTR; +typedef struct Adapter *ADAPTER_PTR; + + +#include "adapters.h" + + +// Find the maximum width of SCSI defined for all adapters: +#if defined(SCSI_32) // Is WIDE 32 defined? + #define MAX_SCSI_WIDTH 32 +#else + #if defined(SCSI_16) // Is WIDE 16 defined? + #define MAX_SCSI_WIDTH 16 + #else + #define MAX_SCSI_WIDTH 8 // Then default to 8 bit SCSI + #endif +#endif + + +#define MAX_HA 8 // Max number of adapters to try for +#if defined(SEPERATELUNS) + #define MIN_DEVS 32 +#else + #define MIN_DEVS MAX_SCSI_WIDTH // Min number of dev. descrs. allocated +#endif + + +#if defined(NATIVE64) + typedef U64 QueueIDMask; + #define QueueIDMaskWidth 64 +#else + #if defined(NATIVE32) + typedef U32 QueueIDMask; + #define QueueIDMaskWidth 32 + #else + typedef U16 QueueIDMask; + #define QueueIDMaskWidth 16 + #endif +#endif + + +struct DeviceDescr { + + // Word aligned things here: + IO_REQ_PTR PendingReqList; // Head of request chain for this device + IO_REQ_PTR AcceptedList; // Chain of requests accepted on this device + ADAPTER_PTR HA; // The HA this device is attached to + + QueueIDMask TaggedQueueMask; // Bit array for generating unique tagged queue IDs + + // Byte aligned things here: + U8 SCSI_ID; // SCSI ID of the device described here + +#if defined(SEPERATELUNS) + U8 SCSI_LUN; // SCSI LUN of the device described here + DEVICE_PTR Next_LUN; // Pointer to device with same SCSIID, next higher LUN +#endif + + U8 MaxDepth; // Max number of queued requests + U8 CurrDepth; // Curr number of queued requests + + struct { + + unsigned Initialized:1; // Has this entry been initialized? + unsigned Allow_Disc:1; // Allow use of disc/reconnect + unsigned AllowsQueued:1; // Supports queued commands + unsigned OnFIFO:1; // Is this device already on the FIFO? + unsigned IsSCSI2:1; // The SCSI-2 flags below are meaningful + + } Flags; + + U8 Device_Type; // Dev. type field from inquiry data + union { // + struct { // + unsigned SoftReset:1; // Device supports soft reset option + unsigned Queuing:1; // Supports tagged queuing + unsigned Reserved:1; // + unsigned Linked:1; // Device supports linked commands + unsigned Sync:1; // Device supports sync. xfers + unsigned WBus16:1; // Supports 16 bit wide SCSI + unsigned WBus32:1; // Supports 32 bit wide SCSI + unsigned RelAddr:1; // Linked commands support rel. addressing + } Bits; + U8 Byte; // easy byte access; set from inquiry data + } SCSI2_Flags; + + DEVICE_PTR FIFO_Next; // Next Dev_Index on adapter to start a req. + + U8 Sync_Period; // Raw (SCSI message byte) negotiated period value + U8 Sync_Offset; // Negotiated SCSI sync. offset + +}; + + + + +// Synchronous info. by SCSI ID in adapter terms: +struct HADeviceStruct { + U8 HASync1; // These fields are adapter specific; the adapter driver puts + U8 HASync2; // what ever values it needs for setting its registers when selecting a device + struct { + unsigned AllowSync:1; // Allow Syncronous negotiation + unsigned UseSync:1; // Allow Syncronous negotiation + unsigned NeedSync:1; // Allow Syncronous negotiation + } Flags; +}; + + +typedef struct { + + union AdapterU AD; // Adapter specific unions + + union SBICU SBIC; // SBIC specific unions + + U8 MI_Buff[8]; // Message interp. buffer + int MI_Count; // Count of messages in buffer + int MI_Needed; // Number of messages still needed + + int MO_Count; // Number of messages in the message out buffer + int MO_Index; // Current index of messages as they are sent + U8 MO_Buff[8]; // Buffer where message out bytes are stored + + U8 InitialState[16]; // Area into which to save the initial state + + IO_REQ_PTR InternalReqDeferQueue; // List of requests waiting for internal request + U8 InternalReqBuffer[DevInfoInqSize]; // Buffer for internal req data + +#if defined(ReqExtensionPtr) + struct IOReqExtension IntlReqExtension; // Request extension for internal requests +#endif + + IO_REQ InternalRequest; // Internal Request block + +} AdapterExtension; + + +struct Adapter { + + IOHandle IOBase; // IO base address handle of described adapter + U16 IOBaseAddr; // Raw I/O address + U16 IOAddrLen; // Number of ports used + U8 Channel; // DMA or ??? channel + U8 IRQNumber; // IRQ number of adapter + + int (*ISR)(struct Adapter ALLOC_D *HA); // Interrupt service routine for this model + U32 (*Service)(int Function, ADAPTER_PTR HA, U32 Misc); // Helper routine for this model + AdapterExtension ALLOC_D *Ext; // Adapter, SBIC, Env extensions + + IO_REQ_PTR CurrReq; // Pointer to the active request + U32 ReqCurrentCount; // Remain xfer count for active request + U32 ReqCurrentIndex; // Xfer index for active request + + short MaxSGListLength; // Max. number of SG list entries + CriticalT CriticalFlag; // Count, semiphore, ??? used by critical/uncritical + + DEVICE_PTR DeviceList[MAX_SCSI_WIDTH]; // list of device indicies by SCSI ID (allow for wide) + struct HADeviceStruct DevInfo[MAX_SCSI_WIDTH]; + DEVICE_PTR FIFO_Head, FIFO_Tail; // First and last devs with reqs pending + DEVICE_PTR CurrDev; // Pointer to device of curr. req + + SegmentDescr SGDescr; // S/G segment descriptor data xfer setup + + struct { + + unsigned Busy:1; // there is stuff going on or pending + unsigned Reselecting:1; // In the process of reselecting + unsigned DataIn:1; // Data function is input to adapter + unsigned DataXfer:1; // Doing some data xfer; dir. defd. above + unsigned DoingSync:1; // We have initiated a sync. negotiation + unsigned Allow:1; // Debug to defer initiating commands + unsigned OffLine:1; // Adapter has gone off line + unsigned Connected:1; // Actively on the bus + unsigned InternalReqInUse:1; // Internal request in use flag + + } State; + + struct { // Flags describing this adapter functionality + + unsigned TargetMode:1; // Supports selection as a target + unsigned AEN:1; // Asynchronous event notification + + unsigned Caching:1; // Adapter caches (either on board, or host side), and cache is enabled + unsigned HostSideCache:1; // Has host side cache (opposed to on board cache (6x00)) + + unsigned Identify:1; // Identify messages and therefore disc/reconnect + unsigned Synchronous:1; // Synchronous xfer + unsigned TaggedQueuing:1; // Tagged queuing + unsigned ScatterGather:1; // Scatter/gather xfers + + unsigned OnBoardQueuing:1; // Has onboard request queue (don't confuse with tagged queuing) + + } Supports; + + struct { // Physical descriptors + + unsigned BusType:4; // Support upto 16 host bus types (ISA, EISA, etc), see BT_xxx + unsigned Xfermode:3; // Data xfer mode (PIO, Bus master, ...), see XM_xxx + + } Physical; + + + ADParmList Parms; // Either an array, or a pointer to an array + + char *Name; // Adapter name + + U8 SCSI_ID; // ID of this adapter + U8 ReqStarting; // Flag for state of issued command + + U8 Sync_Period; // The best period (in SCSI terms) for sync. xfers + U8 Sync_Offset; // The best offset e can support + + unsigned Max_TID; // Maximum target ID: 7, 15, or 31 for 8, 16, and 32 bit wide SCSI + + +#if defined(KEEP_STATS) + + U32 ReqsRequested; // Number of requests passed in, whether queued or not + U32 ReqsQueued; // Number of requests queued + U32 ReqsAccepted; // Number of requests accepted + U32 ReqsCompleted; // Number of requests completed (error or no) + U32 ReqsAborted; // Number of requests aborted via abort command + U32 DataInterrupts; // Number of times the DATA move ISR entered + U32 SBICInterrupts; // Number of times the SBIC ISR entered + +#endif // KEEP_STATS +}; + + +// Bus type defines: +#define BT_ISA 0 // ISA bus +#define BT_EISA 1 // EISA bus +#define BT_VESA 2 // VESA local bus +#define BT_PCI 3 // PCI local bus +#define BT_MC 4 // Micro channel +#define BT_PCMCIA 5 // PC Memory Card International Association +#define BT_ANY -1 // Match any bus type + +// Tranfer types supported: (Type to be used if multiple are supported): +// Types 0-3 use virtual addresses, 4->* use physical: +#define XM_PIO 0x01 // PIO transfer type +#define XM_MEMORY 0x00 // Memory mapped xfers +#define XM_DMAS 0x04 // System DMA, single xfer mode +#define XM_DMAD 0x05 // System DMA, demand mode +#define XM_MASTER24 0x06 // Bus mastering, 24 bits (< 16MB) +#define XM_MASTER 0x07 // Bus mastering, 32+ bits (> 16MB) +#define XM_PHYSICAL(Mode) (Mode >= 4) // Test for need physical memory + +// Defines for HA->State +#define HA_BUSY 1 // There is stuff going on or pending +#define HA_Reselecting 0x8 // In the process of reselecting +#define HA_DataIn 0x10 // Data function is input to adapter +#define HA_DataXfer 0x20 // Doing some data xfer; dir. defd. above +#define HA_DoingSync 0x40 // We have initiated a sync. negotiation +#define HA_Allow 0x80 // Debug to defer initiating commands +#define HA_Connected 0x100 // Adapter is on the SCSI bus + + +// HA.Service function codes: +#define HA_INITIALIZE 0 // Initialize the adapter +#define HA_START 1 // Start processing requests, if ready +#define HA_STOP 2 // Stop accepting new requests +#define HA_TICKLE 3 // New FIFO head entered, starti it if ready +#define HA_TIMER 4 // Timer poll +#define HA_LED 5 // Set LED to (Misc == 0) ? Off : On +#define HA_INITIATE 6 // Initiate a SCSI request for the adapter +#define HA_DATA_SETUP 7 // Begin data transfer +#define HA_DATA_CMPLT 8 // End data transfer +#define HA_RESET_BUS 9 // Reset adapters SCSI bus +#define HA_PARM_CHANGE 10 // One or some of the HA or device parms has changed +#define HA_REVERT_STATE 11 // Revert to state saved during init. +#define HA_RESTORE_STATE 12 // Restore to run configuration +#define HA_POWER_MODE 13 // Set power to (PARM) level: Down, low, normal +#define HA_ABORT_REQ 32 // On board queuing only; Abort the request passed as parm +#define HA_RESET_DEV 33 // On board queuing/autonomous only; Reset the target identified +#define HA_PRE_QUEUE_REQ 34 // On board queuing only; Board is given chance to queue up request(s) + // passed Parm. Returns number of requests accepted, else the value below +#define HA_IOCTL 48 // Adapter defined IOCTL; Parm points to IOCTL structure + +// Parms for HA_POWER_MODE +// Note: A NORMAL_POWER signal may occur without first seeing a TO_LOW or +// POWER_DOWN signal. NORMAL_POWER assumes system RAM is OK (i.e., the HA +// structre), but the board is in an unknown state. +#define HA_PARM_TO_POWER_DOWN 0 // Power level 0: going to loss of power +#define HA_PARM_TO_LOW_POWER 1 // Request to set board to low power +#define HA_PARM_NORMAL_POWER 2 // Power has been restored, RAM is OK, board is ?? + + +// Response codes from HA->Service(HA_DATA_SETUP): +#define HAServiceResponse_UseByteIO (U32)-1 // -1 for byte I/O, Otherwise, return byte count + +// Response codes for HA_PRE_QUEUE_REQ; return the value below, or number of chained requests accepted: +#define HAServiceResponse_NotAccepted 0 + + +// Class of requests: Used by the likes of BlowAwayRequests +#define ACTIVE_REQUESTS 0x01 +#define PENDING_REQUESTS 0x02 +#define ALL_REQUESTS 0x03 + + +extern void AcceptReq(ADAPTER_PTR HA); +extern void BlowAwayRequests(ADAPTER_PTR HA, int Which, U16 Status); +extern void HAParmChange(ADAPTER_PTR HA); +extern void QueueReq(ADAPTER_PTR HA, IO_REQ_PTR Req, int AtHead); +extern void ReqDone(ADAPTER_PTR HA, IO_REQ_PTR Req); +extern int Reselect(ADAPTER_PTR HA, const unsigned TID, const unsigned LUN, const unsigned QID); +extern void StartNext(ADAPTER_PTR HA, int StartLevel); + +#define SL_APPL 1 // StartNext level for "application" context +#define SL_ISR 2 // StartNext level for "interrupt" context + + +// Stuff in the SCSILIB +extern BOOLEAN AbortRequest(ADAPTER_PTR HA, DEVICE_PTR DevP, IO_REQ_PTR Req); +extern int Initialize(void); + +typedef enum RequestType {RTNormalReq, RTGetInfoReq, RTAutoSenseReq, RTSyncNegReq} RequestType; +extern void QueueInternalRequest(ADAPTER_PTR HA, IO_REQ_PTR Req, RequestType Type); + +#endif // __RQM_H__ diff --git a/private/ntos/miniport/always/scsi.c b/private/ntos/miniport/always/scsi.c new file mode 100644 index 000000000..89c91ebdd --- /dev/null +++ b/private/ntos/miniport/always/scsi.c @@ -0,0 +1,400 @@ +/* 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; +} diff --git a/private/ntos/miniport/always/sources b/private/ntos/miniport/always/sources new file mode 100644 index 000000000..b0b66830f --- /dev/null +++ b/private/ntos/miniport/always/sources @@ -0,0 +1,36 @@ +!IF 0 + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + Steve Wood (stevewo) 12-Apr-1990 + +NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl + +!ENDIF + +MAJORCOMP=ntos +MINORCOMP=miniport + +TARGETNAME=always +TARGETPATH=\nt\public\sdk\lib +TARGETTYPE=DRIVER + +NTCPPFLAGS=/DIN2000 /DWINNT /DUSEFASTCALLS /DDEBUG_OFF +TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib + + +SOURCES=33c93.c adapters.c in2000.c ntenv.c ntmgr.c rqm.c scsi.c intrlreq.c always.rc |