/* 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); }