summaryrefslogtreecommitdiffstats
path: root/private/ntos/miniport/always
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/ntos/miniport/always/33c93.c827
-rw-r--r--private/ntos/miniport/always/33c93.h145
-rw-r--r--private/ntos/miniport/always/33c93s.h26
-rw-r--r--private/ntos/miniport/always/adapters.c94
-rw-r--r--private/ntos/miniport/always/adapters.h63
-rw-r--r--private/ntos/miniport/always/always.rc12
-rw-r--r--private/ntos/miniport/always/api.h76
-rw-r--r--private/ntos/miniport/always/apiscsi.h170
-rw-r--r--private/ntos/miniport/always/debug.h25
-rw-r--r--private/ntos/miniport/always/environ.h89
-rw-r--r--private/ntos/miniport/always/envlib.h184
-rw-r--r--private/ntos/miniport/always/in2000.c801
-rw-r--r--private/ntos/miniport/always/in2000.h31
-rw-r--r--private/ntos/miniport/always/in2000s.h28
-rw-r--r--private/ntos/miniport/always/intrlreq.c359
-rw-r--r--private/ntos/miniport/always/intsrb.h100
-rw-r--r--private/ntos/miniport/always/makefile6
-rw-r--r--private/ntos/miniport/always/ntenv.c80
-rw-r--r--private/ntos/miniport/always/ntenv.h119
-rw-r--r--private/ntos/miniport/always/ntmgr.c547
-rw-r--r--private/ntos/miniport/always/rqm.c569
-rw-r--r--private/ntos/miniport/always/rqm.h330
-rw-r--r--private/ntos/miniport/always/scsi.c400
-rw-r--r--private/ntos/miniport/always/sources36
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