head     56.4;
access   paws bayes jws quist dew jwh;
symbols  ;
locks    ; strict;
comment  @# @;


56.4
date     93.01.27.13.53.24;  author jwh;  state Exp;
branches ;
next     56.3;

56.3
date     93.01.27.12.25.35;  author jwh;  state Exp;
branches ;
next     56.2;

56.2
date     92.05.26.17.06.23;  author cfb;  state Exp;
branches ;
next     56.1;

56.1
date     91.11.05.10.01.04;  author jwh;  state Exp;
branches ;
next     55.1;

55.1
date     91.08.25.10.35.52;  author jwh;  state Exp;
branches ;
next     54.1;

54.1
date     91.03.18.15.36.36;  author jwh;  state Exp;
branches ;
next     53.1;

53.1
date     91.03.11.19.35.18;  author jwh;  state Exp;
branches ;
next     52.1;

52.1
date     91.02.19.09.21.25;  author jwh;  state Exp;
branches ;
next     51.1;

51.1
date     91.01.30.16.20.00;  author jwh;  state Exp;
branches ;
next     50.2;

50.2
date     90.12.14.11.40.34;  author dew;  state Exp;
branches ;
next     50.1;

50.1
date     90.10.29.16.33.50;  author jwh;  state Exp;
branches ;
next     49.1;

49.1
date     90.08.14.14.17.35;  author jwh;  state Exp;
branches ;
next     48.1;

48.1
date     90.07.26.11.24.08;  author jwh;  state Exp;
branches ;
next     47.1;

47.1
date     90.05.14.11.10.29;  author dew;  state Exp;
branches ;
next     46.1;

46.1
date     90.05.07.08.57.35;  author jwh;  state Exp;
branches ;
next     45.2;

45.2
date     90.04.25.15.15.40;  author dew;  state Exp;
branches ;
next     45.1;

45.1
date     90.04.19.16.05.40;  author jwh;  state Exp;
branches ;
next     44.1;

44.1
date     90.04.01.22.24.36;  author jwh;  state Exp;
branches ;
next     43.1;

43.1
date     90.03.20.14.15.33;  author jwh;  state Exp;
branches ;
next     42.3;

42.3
date     90.03.13.16.21.44;  author dew;  state Exp;
branches ;
next     42.2;

42.2
date     90.03.08.14.05.52;  author dew;  state Exp;
branches ;
next     42.1;

42.1
date     90.01.23.17.59.32;  author jwh;  state Exp;
branches ;
next     41.3;

41.3
date     90.01.18.22.57.41;  author dew;  state Exp;
branches ;
next     41.2;

41.2
date     90.01.10.15.54.56;  author dew;  state Exp;
branches ;
next     41.1;

41.1
date     89.12.22.11.41.20;  author jwh;  state Exp;
branches ;
next     40.9;

40.9
date     89.12.19.09.28.46;  author dew;  state Exp;
branches ;
next     40.8;

40.8
date     89.11.29.10.23.37;  author dew;  state Exp;
branches ;
next     40.7;

40.7
date     89.11.10.19.29.12;  author dew;  state Exp;
branches ;
next     40.6;

40.6
date     89.10.24.13.18.54;  author dew;  state Exp;
branches ;
next     40.5;

40.5
date     89.10.18.17.01.35;  author dew;  state Exp;
branches ;
next     40.4;

40.4
date     89.10.13.10.52.11;  author dew;  state Exp;
branches ;
next     40.3;

40.3
date     89.10.13.09.56.43;  author dew;  state Exp;
branches ;
next     40.2;

40.2
date     89.10.11.16.51.48;  author dew;  state Exp;
branches ;
next     40.1;

40.1
date     89.09.29.12.02.29;  author jwh;  state Exp;
branches ;
next     39.1;

39.1
date     89.09.26.16.47.24;  author dew;  state Exp;
branches ;
next     1.1;

1.1
date     89.09.14.10.21.47;  author dew;  state Exp;
branches ;
next     ;


desc
@HWI_UTILS is a SCSI Generic Driver Module.
@


56.4
log
@
pws2rcs automatic delta on Wed Jan 27 13:14:25 MST 1993
@
text
@{
	Hardware Interface Utilities

	Utilities that interface to the SCSI hardware are placed here.

	NOTE: Access to the hardware is not limited to this module.
}
module HWI_UTILS;

import SCSI_DEFS, OSD_LL, SCSI_UTILS, HWIA_UTILS;

export

	{
	  Routines called by the state machine
	}
	Procedure hwiGetPhase(PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT);
	Procedure hwiInitHW(PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT);
	Procedure hwiHardReset(PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT);
	Procedure hwiGetMsgOut(PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT);

	{
	  hardware interface utility routines
	}
	Procedure hwiSCInitHW(Sc:S_TYPE_ISC);
	Procedure hwiSCHardReset(Sc:S_TYPE_ISC);
	function  hwiGetCardPtr(PtrSessionBlock:PtrSessionBlockType):PtrScsiCardType;
	function  hwiGetChipPtr(PtrSessionBlock:PtrSessionBlockType):PtrScsiChipType;
	function  hwiManXfer(pSB:PtrSessionBlockType; var b:s_byte;
			     hwPhase:phase_code; MORE, ReplyRequest:Boolean):Boolean;
	function  hwiProgXfer(pSB:PtrSessionBlockType):Boolean;
	function  hwiStartDMAXfer(pSB:PtrSessionBlockType):Boolean;
	function  hwiEndDMAXfer(pSB:PtrSessionBlockType; var ResultCode:S_SHORT):Boolean;
implement


{*************************************************************************
 *  hwiGetPhase
 *************************************************************************
 *
 * On Input: nothing expected.
 *
 *
 * Functional Description:
 *
 *      If the chip is not currently connected to the bus, then the
 *      phase is either BusFree or BusBusy.
 *      Otherwise, if this session is not running (chip is servicing another
 *      session, then the phase is BusBusy.
 *      Otherwise, the bus phase is that on the bus.
 *
 *
 * On Output:  A phase event (see SCSI_DEFS)
 *
 *
 *************************************************************************}
Procedure hwiGetPhase(PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT);
type
	PhaseTranslateType = Array[phase_code] of S_SHORT;
const
	PhaseTranslate = PhaseTranslateType[ord(DataPhase), ord(DataPhase),
					    ord(CmdPhase), ord(StatusPhase),
					    ord(BusFree), ord(ScsiErr),
					    ord(MsgOut), ord(MsgIn)];

var
	BusLines:psns_type;
begin
	with PtrSessionBlock^, InternalBlock.pScBlock^.PtrScsiChip^ do
	begin
		BusLines.psns := psns.psns;
		if ssts.action = spc_not_connected then {chip is not being used}
		begin
			if BusLines.bsy or BusLines.sel then
				ResultCode := ORD(BusBusy)
			else
				ResultCode := ORD(BusFree);
		end
		else if SessionState <> SessionRunning then
			ResultCode := ORD(BusBusy) {Another Session is running}
		else {this session must be in an information transfer phase}
		begin
			ResultCode := PhaseTranslate[BusLines.t_phase];
		end;
	end;
end;


{*************************************************************************
 *  hwiInitHW
 *************************************************************************
 *
 * On Input: nothing expected
 *
 *
 * Functional Description:
 *
 *      Initialize the hardware that this session is attached to.
 *
 * On Output:  Hardware is initialized, ResultCode is NoEvent.
 *
 *************************************************************************}
Procedure hwiInitHW(PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT);
begin
	hwiSCInitHW(PtrSessionBlock^.SelectCode);
	ResultCode := ORD(NoEvent);
end;

{*************************************************************************
 *  hwiHardReset
 *************************************************************************
 *
 * On Input: nothing expected
 *
 *
 * Functional Description:
 *
 *      Toggle the Scsi Bus Reset Line for the bus that this session is
 *      attached to.
 *
 *      Reset all of the H/W registers for this select code.
 *
 * On Output:  Reset Line is toggled, ResultCode is NoEvent.
 *
 *************************************************************************}
Procedure hwiHardReset(PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT);
begin
	hwiSCHardReset(PtrSessionBlock^.SelectCode);
	ResultCode := ORD(NoEvent);
end;

{*************************************************************************
 *  hwiGetMsgOut
 *************************************************************************
 *
 * On Input:    Path is active, but bus is not guaranteed to be in any
 *              particular phase.  A transfer may currently be active.
 *
 * Functional Description:
 *
 *      Get the bus to a MsgOut phase.  If a transfer is active, finish
 *      it up first.
 *
 * On Output:   MsgOut or ScsiErr.
 *
 *
 *************************************************************************}
Procedure hwiGetMsgOut(PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT);
label 1;
var
	XferCount:integer;
	RunLevel:integer;
	b:char;
	sb:s_byte;
begin
	with PtrSessionBlock^,InternalBlock.pScBlock^,PtrScsiChip^ do
	begin
		RunLevel := osdGetRunLevel;
		osdSetRunLevel(7);              {no interrupts during this code!}
		hwiGetPhase(PtrSessionBlock, ResultCode);
		if ResultCode in [ord(MsgOut), ord(BusFree), ord(BusBusy)] then goto 1;
		if ssts.action = spc_init_xfer then {transfer currently in progress}
		begin
			scmd.cmd := set_atn_cmd;
			osdDelay(100);
			osdStartTimer(2*one_second);
			repeat
				if scmd.prgx then {programattic transfer going on, probably won't happen}
				begin
					if psns.io then {inbound}
					begin
						if not ssts.dempty then
						begin
							b := data_regs.dreg;
						end;
					end
					else {output}
					begin
						if not ssts.dfull then
						begin
							data_regs.dreg := chr(0);
						end;
					end;
				end
				{else dma transfer going on, will happen!}
			until (ints.ints <> 0) or (osdTimeExpired);
			osdDelay(1);
			ints.ints := ints.ints;
			hwiGetPhase(PtrSessionBlock, ResultCode);
			if ResultCode in [ord(MsgOut), ord(BusFree), ord(BusBusy)] then goto 1;
		end
		else
		begin
			{
			  the chip may or may not have been reset prior to entering this routine,
			  so optionally transfer a byte manually.
			}
			if (psns.req) then {chip may have missed req so manual transfer}
			begin
				pctl.t_phase := psns.t_phase;
				if (psns.io) {input mode} then
				begin
					scmd.cmd := set_ack_req_cmd;
					repeat
					until (not psns.req) or (psns.t_phase = msg_out_phase);
					b := data_regs.temp;
				end
				else {output mode}
				begin
					data_regs.temp := #0;
					scmd.cmd := set_ack_req_cmd;
					repeat
					until (not psns.req) or (psns.t_phase = msg_out_phase);
				end;
				{raise atn prior to resetting ack}
				scmd.cmd := set_atn_cmd;
				osdDelay(1);
				scmd.cmd := reset_ack_req_cmd;
			end
			else
			begin
				scmd.cmd := set_atn_cmd;
				osdDelay(100); {let nice devices react.}
			end;

			hwiGetPhase(PtrSessionBlock, ResultCode);
			if ResultCode in [ord(MsgOut), ord(BusFree), ord(BusBusy)] then goto 1;
		end;

		{
		  continue to transfer at the targets beck and call until we get a
		  message out phase, bus free phase, or bus busy.
		}
		repeat
			data_regs.tch := chr(0);
			data_regs.tcm := chr(0);
			data_regs.tcl := chr(0);
			pctl.t_phase := psns.t_phase;
			scmd.cmd := set_atn_cmd;
			scmd.scmd := transfer_prgx + 1; {transfer with 0 padding}
			osdStartTimer(2 * one_second);
			repeat until (psns.t_phase = msg_out_phase) or
				     (ssts.action = spc_init_xfer) or
				     (ints.ints <> 0) or
				     (osdTimeExpired);
			if osdTimeExpired then {target is not talking}
			begin
				ints.ints := ints.ints;
				hwiGetPhase(PtrSessionBlock, ResultCode);
				goto 1;
			end;
			repeat until (psns.t_phase = msg_out_phase) or
				     (ints.ints <> 0);
			ints.ints := ints.ints;
			osdDelay(1);  {let bus lines settle}
			hwiGetPhase(PtrSessionBlock, ResultCode);
		until ResultCode in [ord(MsgOut), ord(BusFree), ord(BusBusy)];


		1:
		if ResultCode <> ord(MsgOut) then
			scmd.cmd := reset_atn_cmd;
		sctl.cr := TRUE;
		sctl.cr := FALSE;
		osdSetRunLevel(RunLevel);
	end;
end;


{*************************************************************************
 *  hwiSCInitHW
 *************************************************************************
 *
 * On Input: nothing expected
 *
 *
 * Functional Description:
 *
 *      Initialize the hardware that is on the given select code.
 *
 * On Output:  Hardware is initialized.
 *
 *************************************************************************}
procedure hwiSCInitHW(Sc:S_TYPE_ISC);
var
	pScBlock:PtrSelectCodeBlockType;
begin
	pScBlock := osdGetScBlock(Sc);
	with pScBlock^, PtrScsiChip^, PtrScsiCard^ do
	begin
		  id_reg.reset := 0; { reset the card }
		  sc_reg.ie := false; { disable card interupts }
		  sctl.sctl := 0;
		  sctl.sctl := reset_disable + control_reset; { ensure SPC disabled }
		  osdDelay(1);

		  { do required initialization of SPC registers }
		  bdid := chr(7-config_reg.dev_addr); { use ones compliment of dev_addr }
		  scmd.scmd := 0;
		  tmod.tmod := 0;
		  pctl.pctl := 0;
		  data_regs.temp := #0;
		  data_regs.tch  := #0;
		  data_regs.tcm  := #0;
		  data_regs.tcl  := #0;
		  psns.sdgc := 0;
		  ints.ints := ints.ints; { clear all interupts }

		  { set up the control register, note interupts are not enabled. }
		  if config_reg.parity
		     then sctl.sctl := RESET_DISABLE + arbit_enable + reselect_enable + parity_enable
						     + int_enable
		     else sctl.sctl := RESET_DISABLE + arbit_enable + reselect_enable
						     + int_enable;
		  sctl.rd := false; { clear reset disable }
		  config_reg.pal_reset := 1;
		  osdDelay(1);
	end;
end;

{*************************************************************************
 *  hwiSCHardReset
 *************************************************************************
 *
 * On Input: nothing expected
 *
 *
 * Functional Description:
 *
 *      Toggle the Scsi Bus Reset Line for the bus that is attached to the
 *      given select code.
 *
 *      Reset all of the H/W registers for this select code.
 *
 * On Output:  Reset Line is toggled.
 *
 *************************************************************************}
procedure hwiSCHardReset(Sc:S_TYPE_ISC);
var
	pScBlock:PtrSelectCodeBlockType;
	i:integer;
begin
  pScBlock := osdGetScBlock(Sc);
  with pScBlock^, PtrScsiCard^, PtrScsiChip^ do
  begin
    sc_reg.ie := false; { disable card interupts }
    sctl.sctl := 0;
    scmd.scmd := rst_out;
    osdDelay(1);
    hwiSCInitHW(Sc);
    for i := 0 to 7 do
	DeviceSynchParms[i].SynchState := NoSynch;
    osdDelay(one_second);
  end;
end;

{*************************************************************************
 *  hwiGetCardPtr
 *************************************************************************
 *
 * On Input: Nothing Expected
 *
 *
 * Functional Description:
 *
 *      Retrieve a pointer to the Card that this session is attached to.
 *
 * On Output:
 *
 *
 *************************************************************************}
function hwiGetCardPtr(PtrSessionBlock:PtrSessionBlockType):PtrScsiCardType;
begin
	hwiGetCardPtr := PtrSessionBlock^.InternalBlock.pScBlock^.PtrScsiCard;
end;


{*************************************************************************
 *  hwiGetChipPtr
 *************************************************************************
 *
 * On Input: Nothing Expected
 *
 *
 * Functional Description:
 *
 *      Retrieve a pointer to the Chip that this session is attached to.
 *
 * On Output:
 *
 *
 *************************************************************************}
function hwiGetChipPtr(PtrSessionBlock:PtrSessionBlockType):PtrScsiChipType;
begin
	hwiGetChipPtr := PtrSessionBlock^.InternalBlock.pScBlock^.PtrScsiChip;
end;

{*************************************************************************
 *  hwiManXfer
 *************************************************************************
 *
 * On Input: The bus is in the desired phase and the target is requesting
 *           data be transfered (direction of transfer will be based on
 *           what is on the bus).
 *
 * Functional Description:
 *
 *      Transfer one byte of data in or out of the SCSI bus that is attached
 *      to the given session.  The caller must supply the expected bus phase
 *      and the caller must anticipate the direction of the transfer.
 *
 *      If the caller anticipates that the ATN line should be on during the transfer
 *      (more bytes of message out data will follow), then the caller must
 *      indicate so in the MORE boolean.  (On the last byte of message out
 *      data, the MORE parameter should be set to false).
 *
 *      If the caller anticipates a need to reply to this data, then by
 *      definition, the ATN line must be raised prior to the ACK line being
 *      released.  In this case, set the ReplyRequest boolean.
 *
 * On Output:  TRUE if the transfer was successful, FALSE otherwise.
 *
 * tbd - need to check for parity error and retransmit
 *************************************************************************}
function hwiManXfer(pSB:PtrSessionBlockType; var b:s_byte;
		    hwPhase:phase_code; MORE, ReplyRequest:Boolean):Boolean;
var
	retry_count : integer;
begin
	with pSB^.InternalBlock.pScBlock^.PtrScsiChip^ do
	begin
		ints.ints := ints.ints;
		{
			wait for target to request transfer.  this ensures
			that the target has set the bus they way he wants it.
		}
		if (not psns.req) and (hwPhase = psns.t_phase) then
		begin
			osdStartTimer(one_second);
			repeat
			until (psns.req) or (hwPhase <> psns.t_phase) or osdTimeExpired;
		end;

		if (MORE) and (hwPhase = msg_out_phase) then
		begin
			scmd.cmd := set_atn_cmd;
		end
		else
		begin
			scmd.cmd := reset_atn_cmd;
		end;

		if (not psns.req) or (hwPhase <> psns.t_phase) then
		begin
			{peripheral isn't talking or requested phase is not equal to real bus phase}
			hwiManXfer := false;
		end
		else {target has raised req, requesting xfer}
		begin
			pctl.t_phase := hwPhase;

			if psns.io then {input operation}
			begin
				{
				  data is actually on the bus, but temp is not set until
				  ack command is given
				}
				scmd.cmd := set_ack_req_cmd;
				repeat until (not psns.req) or (ints.ints <> 0);
				b := ord(data_regs.temp);
			end
			else {output operation}
			begin
				data_regs.temp := chr(b);
				scmd.cmd := set_ack_req_cmd;
				repeat until (not psns.req) or (ints.ints <> 0);
			end;
			if (ints.ints = 0) then {xfer went o.k.}
			begin
				hwiManXfer := true;
				if (hwPhase = msg_in_phase) and (ReplyRequest) then
					scmd.cmd := set_atn_cmd;
			end
			else
				hwiManXfer := false;
			scmd.cmd := reset_ack_req_cmd;
			ints.ints := cmd_complete;
		end;


		{
		  if this is the end of the manual transfer, then
		  wait for a phase change.
		}
		if (not MORE) and (ints.ints = 0) and (psns.t_phase = hwPhase) then
		begin
			osdStartTimer(one_second);
			repeat until (psns.t_phase <> hwPhase) or osdTimeExpired;
			if (psns.t_phase = hwPhase) then
			begin
				hwiManXfer := false;
				utlSetInternalErr(pSB, ScsiPhaseErr);
			end;
		end;
	end;
end;



{*************************************************************************
 *  hwiProgXfer
 *************************************************************************
 *
 * On Input: The bus is in the desired phase and the target is requesting
 *           data be transfered (direction of transfer will be based on
 *           what is on the bus).  The XferBlock in the InternalBlock has
 *           been set up.
 *
 * Functional Description:
 *
 *      Set up the hardware for a programmatic transfer and execute it.
 *      Process all follow on interrupts.
 *
 * On Output:  TRUE if the transfer was successful, FALSE otherwise.
 *             if FALSE, internal error type has been set.
 *
 *************************************************************************}
function  hwiProgXfer(pSB:PtrSessionBlockType):Boolean;
label
	1,2;
Var
	SaveInts:ints_type;
	ResultCode:S_SHORT;
begin
	hwiProgXfer := false;
	with pSB^.InternalBlock, XferBlock, pScBlock^, PtrScsiChip^, PtrScsiCard^ do
	begin
		{
			set up transfer count
		}
		data_regs.tch := chr(XferBufBlock.BufLen Div HEX('100') Div HEX('100'));
		data_regs.tcm := chr(XferBufBlock.BufLen Div HEX('100'));
		data_regs.tcl := chr(XferBufBlock.BufLen);


		{
			tell the chip which phase we expect to xfer in.
		}
		pctl.t_phase := XferPhase;


		{
		  the transfer protocol (synchronous or asynchrnous) has already been
		  set up.
		}


		{
		 tell chip to commence a programmatic transfer
		}
		ints.ints := ints.ints;
		scmd.scmd := transfer_prgx;


		{
		wait for chip to respond
		}
		if ssts.action <> spc_init_xfer then
		begin
			osdStartTimer(one_second);
			repeat until (ssts.action = spc_init_xfer) or (ints.ints <> 0) or osdTimeExpired;
			if (ints.ints <> 0) then
				goto 2;
			if ssts.action <> spc_init_xfer then
			begin
				utlSetInternalErr(pSB, ScsiXferErr);
				goto 1;
			end;
		end;


		{
		  execute the programmatic transfer.
		}
		hwiAXfer(XferBlock, PtrScsiChip);

		{
		  don't need to wait for chip to finish up work because waiting for
		  an interrupt below.


		  Interrupts handled here are: cmd_complete, svc_required,
		  and spc_hard_err.
		}

		{
		  an interrupt of some kind must come through, wait for it.
		}
		if (ints.ints = 0) then
		begin
			osdStartTimer(one_second);
			repeat until (ints.ints <> 0) or osdTimeExpired;
			if (ints.ints = 0) then
			begin
				utlSetInternalErr(pSB, ScsiXferErr);
				goto 1;
			end;
		end;
		2:
		Saveints.ints := ints.ints;
		ints.ints := ints.ints;
		if serr.serr <> 0 then
			Saveints.spc_hard_err := true;
		if (Saveints.spc_hard_err) then
		begin
			Saveints.spc_hard_err := false;

			{
				call hwiGetMsgOut which will force the bus to message out
				phase (if target still expects to xfer data, this routine will
				pump no-op data, or read and throw away data, until message
				out phase has been granted.
			}
			hwiGetMsgOut(pSB, ResultCode);
			if (ResultCode = ord(ScsiErr)) then
				goto 1;

			{
			   reset the transfer control hardware on the chip/card.
			}
			sctl.cr := TRUE;
			sctl.cr := FALSE;
		end;

		if (Saveints.svc_required) then
		begin
			Saveints.svc_required := false;

			{
				get the residual count from tch, tcm, and tcl; this
				is the new buffer length.  Adjust the buffer pointer
				to point to the next byte to be transfered.
			}
			XferBufBlock.BufLen := (ord(data_regs.tch) * HEX('100') * HEX('100')) +
					       (ord(data_regs.tcm) * HEX('100'))   +
					       ord(data_regs.tcl);

			XferBufBlock.BufPtr := addr(XferSavedDataPointer^,
						XferSavedDataLength - XferBufBlock.BufLen);

			{
			   reset the transfer control hardware on the chip/card.
			}
			sctl.cr := TRUE;
			sctl.cr := FALSE;
		end;

		if (Saveints.cmd_complete) then
		begin
			Saveints.cmd_complete := false;
		end;

		if (Saveints.ints <> 0) {an unexpected interrupt has occured} then
		begin
			{
			   reset the transfer control hardware on the chip/card.
			}
			sctl.cr := TRUE;
			sctl.cr := FALSE;

			utlSetInternalErr(pSB, ScsiInteruptErr);
			goto 1;
		end;
	end; {with}
	hwiProgXfer := true;
	1:
end;



{*************************************************************************
 *  hwiStartDMAXfer
 *************************************************************************
 *
 * On Input: The bus is in the desired phase and the target is requesting
 *           data be transfered (direction of transfer will be based on
 *           what is on the bus).  The XferBlock in the InternalBlock has
 *           been set up.
 *
 *           The DMA channel has been determined and is stored in the
 *           InternalBlock.
 *
 * Functional Description:
 *
 *      Set up the hardware for a DMA transfer, and set up for an
 *      interrupt to occur from the CHIP only!  DMA should not cause
 *      an interrupt.
 *
 * On Output:  DMA started.
 *
 *************************************************************************}
function hwiStartDMAXfer(pSB:PtrSessionBlockType):boolean;
var
	Count:integer;
	locsc_reg:sc_reg_type;
begin
	hwiStartDMAXfer := true;
	with pSB^.InternalBlock, pScBlock^, PtrScsiCard^, PtrScsiChip^ do
	begin
		{
		  make sure the SCSI card is not doing DMA!
		}
		sc_reg.d_enab_0 := false;
		sc_reg.d_enab_1 := false;
		config_reg.pal_reset := 0;


		{
		  set up and arm the DMA card.
		  On entry, DMA32bit indicates the SCSI card DMA capabilities.
		  On exit,  DMA32bit indicates how the card was setup.
		}
		DMA32bit := not id_reg.d16;
		osdSetUpDMAChannel(DMAChannel, DMA32bit, XferBlock);


		{
		  set up and arm the Fujitsu CHIP
		}
		ints.ints := 0;
		Count := XferBlock.XferDMACount;
		data_regs.tch := chr(Count Div HEX('100') Div HEX('100'));
		data_regs.tcm := chr(Count Div HEX('100'));
		data_regs.tcl := chr(Count);
		pctl.t_phase := XferBlock.XferPhase;
		scmd.scmd := transfer_dmax;

		{
		  wait for chip to accept the transfer command.
		  if an interrupt has occured, then this is an error.
		}
		if (ssts.action <> spc_init_xfer) or (ints.ints <> 0) then
		begin
			osdStartTimer(one_second);
			repeat
			until (ssts.action = spc_init_xfer) or (ints.ints <> 0) or osdTimeExpired;
			if (ssts.action <> spc_init_xfer) or (ints.ints <> 0) then
			begin
				hwiStartDMAXfer := FALSE;
				utlSetInternalErr(pSB, ScsiCatastrophicErr);
			end;
		end;


		{
		  if no errors have occured, then
		    o set up the software to handle an interrupt.
		    o enable interrupts
		    o set up and enable the card to do DMA.
			- this will start the DMA process.
		}
		if  (ssts.action = spc_init_xfer) and (ints.ints = 0) then
		begin
			ISRWaiting := true;
			ISRMask := cmd_complete + svc_required + spc_hard_err;
			locsc_reg.control := 0;
			locsc_reg.ie := true;
			if DMA32bit then
				locsc_reg.dma_32 := true;
			if XferBlock.XferPhase = data_in_phase then
				locsc_reg.dma_dir := true;
			{ 375 h/w problem, write dma enable last!!!! }
			sc_reg.control := locsc_reg.control;
			if DMAChannel = 1 then
				sc_reg.d_enab_1 := true
			else
				sc_reg.d_enab_0 := true;
		end;
	end;
end;



{*************************************************************************
 *  hwiEndDMAXfer
 *************************************************************************
 *
 * On Input:
 *
 *      An interrupt (from the SCSI chip) has occured indicating the current
 *      DMA transfer has halted.
 *
 * Functional Description:
 *
 *      Determine the number of bytes transferred, and adjust
 *      XferBlock.  Determine the cause for the interrupt, and reset
 *      H/W accordingly.  If transfer should be continued (because of
 *      the 128K max transfer limitation with 16bit DMA) return FALSE to
 *      indicate DMA transfer did not end, otherwise TRUE.
 *
 *      Appropriate SCSI errors are placed in SessionBlock and ResultCode is set.
 *
 * On Output:  DMA transfer either stopped or killed.  H/W properly reset.
 *      FALSE is returned if DMA transfer must be continued, TRUE otherwise.
 *      ResultCode is set to ScsiErr if an error has occured, NoEvent otherwise.
 *
 *************************************************************************}
function  hwiEndDMAXfer(pSB:PtrSessionBlockType; Var ResultCode:S_SHORT):Boolean;
var
	Saveints:ints_type;
	AmtXfered,DMAStopCount:integer;
begin
	with pSB^.InternalBlock, XferBlock, pScBlock^, PtrScsiChip^, PtrScsiCard^ do
	begin
		sc_reg.ie := false;
		ISRWaiting := false;
		ResultCode := ord(NoEvent);
		hwiEndDMAXfer := TRUE;
		Saveints.ints := ints.ints;
		ints.ints := ints.ints;
		if (ISRError) or (serr.serr <> 0) then
			Saveints.spc_hard_err := true;

		DMAStopCount := (ord(data_regs.tch) * HEX('100') * HEX('100')) +
				(ord(data_regs.tcm) * HEX('100'))   +
				ord(data_regs.tcl);

		AmtXfered := XferDMACount - DMAStopCount;

		XferBufBlock.BufLen := XferBufBlock.BufLen - AmtXfered;

		{
		  note, use XferSavedDataPointer instead of BufPtr because the absolute
		  address from the beginning of the transfer is being calculated.
		}
		XferBufBlock.BufPtr := addr(XferSavedDataPointer^,
					XferSavedDataLength - XferBufBlock.BufLen);


		if (Saveints.spc_hard_err) then
		begin
			Saveints.spc_hard_err := false;

			{
				Reset the DMA channel.
			}
			osdKillDMA(DMAChannel);

			{
				reset the transfer control hardware on the chip/card.
			}
			sctl.cr := TRUE;
			sctl.cr := FALSE;

			if ISRError then
				ResultCode := ord(ScsiErr)
			else
			begin
				{
				  call hwiGetMsgOut which will force the bus to message out
				  phase (if target still expects to xfer data, this routine will
				  pump no-op data, or read and throw away data, until message
				  out phase has been granted.
				}
				hwiGetMsgOut(pSB, ResultCode);
			end;
		end
		else if (XferPhase = data_in_phase) then
		begin
			{
			  if this is an input DMA operation, then wait for DMA to
			  catch up to SCSI chip.

			  If DMA won't (osdStopDMA = false), then data has been lost.

			  (This is not necessary for output, because the count on the
			   SCSI chip reflects what actually has been transfered.)
			}
			if (not osdStopDMA(DMAChannel, DMA32bit, DMAStopCount)) then
			begin
				utlSetInternalErr(pSB, ScsiXferErr);
				ResultCode := ord(ScsiErr);
			end;
		end
		else
			osdKillDMA(DMAChannel);

		if (Saveints.svc_required) then
		begin
			Saveints.svc_required := false;

			{
				reset the transfer control hardware on the chip/card.
			}
			sctl.cr := TRUE;
			sctl.cr := FALSE;
		end;

		if (Saveints.cmd_complete) then
		begin
			Saveints.cmd_complete := false;
			if (ResultCode <> ord(ScsiErr)) and (XferBufBlock.BufLen > 0) then
					hwiEndDMAXfer := FALSE; {still more data to be xfered}
		end;

		if (Saveints.ints <> 0) {an unexpected interrupt has occured} then
		begin
			utlSetInternalErr(pSB, ScsiInteruptErr);
			ResultCode := ord(ScsiErr);

			{
				reset the transfer control hardware on the chip/card.
			}
			sctl.cr := TRUE;
			sctl.cr := FALSE;
		end;

		{
		   reset the igor PAL after every DMA transfer.
		}
		sc_reg.d_enab_1 := false;
		sc_reg.d_enab_0 := false;
		config_reg.pal_reset := 1;
	end;
end;

end;
@


56.3
log
@
pws2rcs automatic delta on Wed Jan 27 11:57:27 MST 1993
@
text
@d1 927
@


56.2
log
@Changed state from NeedSynch to NoSynch to fix bug with 400MB drives - CFB
@
text
@a0 927
{
	Hardware Interface Utilities

	Utilities that interface to the SCSI hardware are placed here.

	NOTE: Access to the hardware is not limited to this module.
}
module HWI_UTILS;

import SCSI_DEFS, OSD_LL, SCSI_UTILS, HWIA_UTILS;

export

	{
	  Routines called by the state machine
	}
	Procedure hwiGetPhase(PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT);
	Procedure hwiInitHW(PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT);
	Procedure hwiHardReset(PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT);
	Procedure hwiGetMsgOut(PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT);

	{
	  hardware interface utility routines
	}
	Procedure hwiSCInitHW(Sc:S_TYPE_ISC);
	Procedure hwiSCHardReset(Sc:S_TYPE_ISC);
	function  hwiGetCardPtr(PtrSessionBlock:PtrSessionBlockType):PtrScsiCardType;
	function  hwiGetChipPtr(PtrSessionBlock:PtrSessionBlockType):PtrScsiChipType;
	function  hwiManXfer(pSB:PtrSessionBlockType; var b:s_byte;
			     hwPhase:phase_code; MORE, ReplyRequest:Boolean):Boolean;
	function  hwiProgXfer(pSB:PtrSessionBlockType):Boolean;
	function  hwiStartDMAXfer(pSB:PtrSessionBlockType):Boolean;
	function  hwiEndDMAXfer(pSB:PtrSessionBlockType; var ResultCode:S_SHORT):Boolean;
implement


{*************************************************************************
 *  hwiGetPhase
 *************************************************************************
 *
 * On Input: nothing expected.
 *
 *
 * Functional Description:
 *
 *      If the chip is not currently connected to the bus, then the
 *      phase is either BusFree or BusBusy.
 *      Otherwise, if this session is not running (chip is servicing another
 *      session, then the phase is BusBusy.
 *      Otherwise, the bus phase is that on the bus.
 *
 *
 * On Output:  A phase event (see SCSI_DEFS)
 *
 *
 *************************************************************************}
Procedure hwiGetPhase(PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT);
type
	PhaseTranslateType = Array[phase_code] of S_SHORT;
const
	PhaseTranslate = PhaseTranslateType[ord(DataPhase), ord(DataPhase),
					    ord(CmdPhase), ord(StatusPhase),
					    ord(BusFree), ord(ScsiErr),
					    ord(MsgOut), ord(MsgIn)];

var
	BusLines:psns_type;
begin
	with PtrSessionBlock^, InternalBlock.pScBlock^.PtrScsiChip^ do
	begin
		BusLines.psns := psns.psns;
		if ssts.action = spc_not_connected then {chip is not being used}
		begin
			if BusLines.bsy or BusLines.sel then
				ResultCode := ORD(BusBusy)
			else
				ResultCode := ORD(BusFree);
		end
		else if SessionState <> SessionRunning then
			ResultCode := ORD(BusBusy) {Another Session is running}
		else {this session must be in an information transfer phase}
		begin
			ResultCode := PhaseTranslate[BusLines.t_phase];
		end;
	end;
end;


{*************************************************************************
 *  hwiInitHW
 *************************************************************************
 *
 * On Input: nothing expected
 *
 *
 * Functional Description:
 *
 *      Initialize the hardware that this session is attached to.
 *
 * On Output:  Hardware is initialized, ResultCode is NoEvent.
 *
 *************************************************************************}
Procedure hwiInitHW(PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT);
begin
	hwiSCInitHW(PtrSessionBlock^.SelectCode);
	ResultCode := ORD(NoEvent);
end;

{*************************************************************************
 *  hwiHardReset
 *************************************************************************
 *
 * On Input: nothing expected
 *
 *
 * Functional Description:
 *
 *      Toggle the Scsi Bus Reset Line for the bus that this session is
 *      attached to.
 *
 *      Reset all of the H/W registers for this select code.
 *
 * On Output:  Reset Line is toggled, ResultCode is NoEvent.
 *
 *************************************************************************}
Procedure hwiHardReset(PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT);
begin
	hwiSCHardReset(PtrSessionBlock^.SelectCode);
	ResultCode := ORD(NoEvent);
end;

{*************************************************************************
 *  hwiGetMsgOut
 *************************************************************************
 *
 * On Input:    Path is active, but bus is not guaranteed to be in any
 *              particular phase.  A transfer may currently be active.
 *
 * Functional Description:
 *
 *      Get the bus to a MsgOut phase.  If a transfer is active, finish
 *      it up first.
 *
 * On Output:   MsgOut or ScsiErr.
 *
 *
 *************************************************************************}
Procedure hwiGetMsgOut(PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT);
label 1;
var
	XferCount:integer;
	RunLevel:integer;
	b:char;
	sb:s_byte;
begin
	with PtrSessionBlock^,InternalBlock.pScBlock^,PtrScsiChip^ do
	begin
		RunLevel := osdGetRunLevel;
		osdSetRunLevel(7);              {no interrupts during this code!}
		hwiGetPhase(PtrSessionBlock, ResultCode);
		if ResultCode in [ord(MsgOut), ord(BusFree), ord(BusBusy)] then goto 1;
		if ssts.action = spc_init_xfer then {transfer currently in progress}
		begin
			scmd.cmd := set_atn_cmd;
			osdDelay(100);
			osdStartTimer(2*one_second);
			repeat
				if scmd.prgx then {programattic transfer going on, probably won't happen}
				begin
					if psns.io then {inbound}
					begin
						if not ssts.dempty then
						begin
							b := data_regs.dreg;
						end;
					end
					else {output}
					begin
						if not ssts.dfull then
						begin
							data_regs.dreg := chr(0);
						end;
					end;
				end
				{else dma transfer going on, will happen!}
			until (ints.ints <> 0) or (osdTimeExpired);
			osdDelay(1);
			ints.ints := ints.ints;
			hwiGetPhase(PtrSessionBlock, ResultCode);
			if ResultCode in [ord(MsgOut), ord(BusFree), ord(BusBusy)] then goto 1;
		end
		else
		begin
			{
			  the chip may or may not have been reset prior to entering this routine,
			  so optionally transfer a byte manually.
			}
			if (psns.req) then {chip may have missed req so manual transfer}
			begin
				pctl.t_phase := psns.t_phase;
				if (psns.io) {input mode} then
				begin
					scmd.cmd := set_ack_req_cmd;
					repeat
					until (not psns.req) or (psns.t_phase = msg_out_phase);
					b := data_regs.temp;
				end
				else {output mode}
				begin
					data_regs.temp := #0;
					scmd.cmd := set_ack_req_cmd;
					repeat
					until (not psns.req) or (psns.t_phase = msg_out_phase);
				end;
				{raise atn prior to resetting ack}
				scmd.cmd := set_atn_cmd;
				osdDelay(1);
				scmd.cmd := reset_ack_req_cmd;
			end
			else
			begin
				scmd.cmd := set_atn_cmd;
				osdDelay(100); {let nice devices react.}
			end;

			hwiGetPhase(PtrSessionBlock, ResultCode);
			if ResultCode in [ord(MsgOut), ord(BusFree), ord(BusBusy)] then goto 1;
		end;

		{
		  continue to transfer at the targets beck and call until we get a
		  message out phase, bus free phase, or bus busy.
		}
		repeat
			data_regs.tch := chr(0);
			data_regs.tcm := chr(0);
			data_regs.tcl := chr(0);
			pctl.t_phase := psns.t_phase;
			scmd.cmd := set_atn_cmd;
			scmd.scmd := transfer_prgx + 1; {transfer with 0 padding}
			osdStartTimer(2 * one_second);
			repeat until (psns.t_phase = msg_out_phase) or
				     (ssts.action = spc_init_xfer) or
				     (ints.ints <> 0) or
				     (osdTimeExpired);
			if osdTimeExpired then {target is not talking}
			begin
				ints.ints := ints.ints;
				hwiGetPhase(PtrSessionBlock, ResultCode);
				goto 1;
			end;
			repeat until (psns.t_phase = msg_out_phase) or
				     (ints.ints <> 0);
			ints.ints := ints.ints;
			osdDelay(1);  {let bus lines settle}
			hwiGetPhase(PtrSessionBlock, ResultCode);
		until ResultCode in [ord(MsgOut), ord(BusFree), ord(BusBusy)];


		1:
		if ResultCode <> ord(MsgOut) then
			scmd.cmd := reset_atn_cmd;
		sctl.cr := TRUE;
		sctl.cr := FALSE;
		osdSetRunLevel(RunLevel);
	end;
end;


{*************************************************************************
 *  hwiSCInitHW
 *************************************************************************
 *
 * On Input: nothing expected
 *
 *
 * Functional Description:
 *
 *      Initialize the hardware that is on the given select code.
 *
 * On Output:  Hardware is initialized.
 *
 *************************************************************************}
procedure hwiSCInitHW(Sc:S_TYPE_ISC);
var
	pScBlock:PtrSelectCodeBlockType;
begin
	pScBlock := osdGetScBlock(Sc);
	with pScBlock^, PtrScsiChip^, PtrScsiCard^ do
	begin
		  id_reg.reset := 0; { reset the card }
		  sc_reg.ie := false; { disable card interupts }
		  sctl.sctl := 0;
		  sctl.sctl := reset_disable + control_reset; { ensure SPC disabled }
		  osdDelay(1);

		  { do required initialization of SPC registers }
		  bdid := chr(7-config_reg.dev_addr); { use ones compliment of dev_addr }
		  scmd.scmd := 0;
		  tmod.tmod := 0;
		  pctl.pctl := 0;
		  data_regs.temp := #0;
		  data_regs.tch  := #0;
		  data_regs.tcm  := #0;
		  data_regs.tcl  := #0;
		  psns.sdgc := 0;
		  ints.ints := ints.ints; { clear all interupts }

		  { set up the control register, note interupts are not enabled. }
		  if config_reg.parity
		     then sctl.sctl := RESET_DISABLE + arbit_enable + reselect_enable + parity_enable
						     + int_enable
		     else sctl.sctl := RESET_DISABLE + arbit_enable + reselect_enable
						     + int_enable;
		  sctl.rd := false; { clear reset disable }
		  config_reg.pal_reset := 1;
		  osdDelay(1);
	end;
end;

{*************************************************************************
 *  hwiSCHardReset
 *************************************************************************
 *
 * On Input: nothing expected
 *
 *
 * Functional Description:
 *
 *      Toggle the Scsi Bus Reset Line for the bus that is attached to the
 *      given select code.
 *
 *      Reset all of the H/W registers for this select code.
 *
 * On Output:  Reset Line is toggled.
 *
 *************************************************************************}
procedure hwiSCHardReset(Sc:S_TYPE_ISC);
var
	pScBlock:PtrSelectCodeBlockType;
	i:integer;
begin
  pScBlock := osdGetScBlock(Sc);
  with pScBlock^, PtrScsiCard^, PtrScsiChip^ do
  begin
    sc_reg.ie := false; { disable card interupts }
    sctl.sctl := 0;
    scmd.scmd := rst_out;
    osdDelay(1);
    hwiSCInitHW(Sc);
    for i := 0 to 7 do
	DeviceSynchParms[i].SynchState := NoSynch;
    osdDelay(one_second);
  end;
end;

{*************************************************************************
 *  hwiGetCardPtr
 *************************************************************************
 *
 * On Input: Nothing Expected
 *
 *
 * Functional Description:
 *
 *      Retrieve a pointer to the Card that this session is attached to.
 *
 * On Output:
 *
 *
 *************************************************************************}
function hwiGetCardPtr(PtrSessionBlock:PtrSessionBlockType):PtrScsiCardType;
begin
	hwiGetCardPtr := PtrSessionBlock^.InternalBlock.pScBlock^.PtrScsiCard;
end;


{*************************************************************************
 *  hwiGetChipPtr
 *************************************************************************
 *
 * On Input: Nothing Expected
 *
 *
 * Functional Description:
 *
 *      Retrieve a pointer to the Chip that this session is attached to.
 *
 * On Output:
 *
 *
 *************************************************************************}
function hwiGetChipPtr(PtrSessionBlock:PtrSessionBlockType):PtrScsiChipType;
begin
	hwiGetChipPtr := PtrSessionBlock^.InternalBlock.pScBlock^.PtrScsiChip;
end;

{*************************************************************************
 *  hwiManXfer
 *************************************************************************
 *
 * On Input: The bus is in the desired phase and the target is requesting
 *           data be transfered (direction of transfer will be based on
 *           what is on the bus).
 *
 * Functional Description:
 *
 *      Transfer one byte of data in or out of the SCSI bus that is attached
 *      to the given session.  The caller must supply the expected bus phase
 *      and the caller must anticipate the direction of the transfer.
 *
 *      If the caller anticipates that the ATN line should be on during the transfer
 *      (more bytes of message out data will follow), then the caller must
 *      indicate so in the MORE boolean.  (On the last byte of message out
 *      data, the MORE parameter should be set to false).
 *
 *      If the caller anticipates a need to reply to this data, then by
 *      definition, the ATN line must be raised prior to the ACK line being
 *      released.  In this case, set the ReplyRequest boolean.
 *
 * On Output:  TRUE if the transfer was successful, FALSE otherwise.
 *
 * tbd - need to check for parity error and retransmit
 *************************************************************************}
function hwiManXfer(pSB:PtrSessionBlockType; var b:s_byte;
		    hwPhase:phase_code; MORE, ReplyRequest:Boolean):Boolean;
var
	retry_count : integer;
begin
	with pSB^.InternalBlock.pScBlock^.PtrScsiChip^ do
	begin
		ints.ints := ints.ints;
		{
			wait for target to request transfer.  this ensures
			that the target has set the bus they way he wants it.
		}
		if (not psns.req) and (hwPhase = psns.t_phase) then
		begin
			osdStartTimer(one_second);
			repeat
			until (psns.req) or (hwPhase <> psns.t_phase) or osdTimeExpired;
		end;

		if (MORE) and (hwPhase = msg_out_phase) then
		begin
			scmd.cmd := set_atn_cmd;
		end
		else
		begin
			scmd.cmd := reset_atn_cmd;
		end;

		if (not psns.req) or (hwPhase <> psns.t_phase) then
		begin
			{peripheral isn't talking or requested phase is not equal to real bus phase}
			hwiManXfer := false;
		end
		else {target has raised req, requesting xfer}
		begin
			pctl.t_phase := hwPhase;

			if psns.io then {input operation}
			begin
				{
				  data is actually on the bus, but temp is not set until
				  ack command is given
				}
				scmd.cmd := set_ack_req_cmd;
				repeat until (not psns.req) or (ints.ints <> 0);
				b := ord(data_regs.temp);
			end
			else {output operation}
			begin
				data_regs.temp := chr(b);
				scmd.cmd := set_ack_req_cmd;
				repeat until (not psns.req) or (ints.ints <> 0);
			end;
			if (ints.ints = 0) then {xfer went o.k.}
			begin
				hwiManXfer := true;
				if (hwPhase = msg_in_phase) and (ReplyRequest) then
					scmd.cmd := set_atn_cmd;
			end
			else
				hwiManXfer := false;
			scmd.cmd := reset_ack_req_cmd;
			ints.ints := cmd_complete;
		end;


		{
		  if this is the end of the manual transfer, then
		  wait for a phase change.
		}
		if (not MORE) and (ints.ints = 0) and (psns.t_phase = hwPhase) then
		begin
			osdStartTimer(one_second);
			repeat until (psns.t_phase <> hwPhase) or osdTimeExpired;
			if (psns.t_phase = hwPhase) then
			begin
				hwiManXfer := false;
				utlSetInternalErr(pSB, ScsiPhaseErr);
			end;
		end;
	end;
end;



{*************************************************************************
 *  hwiProgXfer
 *************************************************************************
 *
 * On Input: The bus is in the desired phase and the target is requesting
 *           data be transfered (direction of transfer will be based on
 *           what is on the bus).  The XferBlock in the InternalBlock has
 *           been set up.
 *
 * Functional Description:
 *
 *      Set up the hardware for a programmatic transfer and execute it.
 *      Process all follow on interrupts.
 *
 * On Output:  TRUE if the transfer was successful, FALSE otherwise.
 *             if FALSE, internal error type has been set.
 *
 *************************************************************************}
function  hwiProgXfer(pSB:PtrSessionBlockType):Boolean;
label
	1,2;
Var
	SaveInts:ints_type;
	ResultCode:S_SHORT;
begin
	hwiProgXfer := false;
	with pSB^.InternalBlock, XferBlock, pScBlock^, PtrScsiChip^, PtrScsiCard^ do
	begin
		{
			set up transfer count
		}
		data_regs.tch := chr(XferBufBlock.BufLen Div HEX('100') Div HEX('100'));
		data_regs.tcm := chr(XferBufBlock.BufLen Div HEX('100'));
		data_regs.tcl := chr(XferBufBlock.BufLen);


		{
			tell the chip which phase we expect to xfer in.
		}
		pctl.t_phase := XferPhase;


		{
		  the transfer protocol (synchronous or asynchrnous) has already been
		  set up.
		}


		{
		 tell chip to commence a programmatic transfer
		}
		ints.ints := ints.ints;
		scmd.scmd := transfer_prgx;


		{
		wait for chip to respond
		}
		if ssts.action <> spc_init_xfer then
		begin
			osdStartTimer(one_second);
			repeat until (ssts.action = spc_init_xfer) or (ints.ints <> 0) or osdTimeExpired;
			if (ints.ints <> 0) then
				goto 2;
			if ssts.action <> spc_init_xfer then
			begin
				utlSetInternalErr(pSB, ScsiXferErr);
				goto 1;
			end;
		end;


		{
		  execute the programmatic transfer.
		}
		hwiAXfer(XferBlock, PtrScsiChip);

		{
		  don't need to wait for chip to finish up work because waiting for
		  an interrupt below.


		  Interrupts handled here are: cmd_complete, svc_required,
		  and spc_hard_err.
		}

		{
		  an interrupt of some kind must come through, wait for it.
		}
		if (ints.ints = 0) then
		begin
			osdStartTimer(one_second);
			repeat until (ints.ints <> 0) or osdTimeExpired;
			if (ints.ints = 0) then
			begin
				utlSetInternalErr(pSB, ScsiXferErr);
				goto 1;
			end;
		end;
		2:
		Saveints.ints := ints.ints;
		ints.ints := ints.ints;
		if serr.serr <> 0 then
			Saveints.spc_hard_err := true;
		if (Saveints.spc_hard_err) then
		begin
			Saveints.spc_hard_err := false;

			{
				call hwiGetMsgOut which will force the bus to message out
				phase (if target still expects to xfer data, this routine will
				pump no-op data, or read and throw away data, until message
				out phase has been granted.
			}
			hwiGetMsgOut(pSB, ResultCode);
			if (ResultCode = ord(ScsiErr)) then
				goto 1;

			{
			   reset the transfer control hardware on the chip/card.
			}
			sctl.cr := TRUE;
			sctl.cr := FALSE;
		end;

		if (Saveints.svc_required) then
		begin
			Saveints.svc_required := false;

			{
				get the residual count from tch, tcm, and tcl; this
				is the new buffer length.  Adjust the buffer pointer
				to point to the next byte to be transfered.
			}
			XferBufBlock.BufLen := (ord(data_regs.tch) * HEX('100') * HEX('100')) +
					       (ord(data_regs.tcm) * HEX('100'))   +
					       ord(data_regs.tcl);

			XferBufBlock.BufPtr := addr(XferSavedDataPointer^,
						XferSavedDataLength - XferBufBlock.BufLen);

			{
			   reset the transfer control hardware on the chip/card.
			}
			sctl.cr := TRUE;
			sctl.cr := FALSE;
		end;

		if (Saveints.cmd_complete) then
		begin
			Saveints.cmd_complete := false;
		end;

		if (Saveints.ints <> 0) {an unexpected interrupt has occured} then
		begin
			{
			   reset the transfer control hardware on the chip/card.
			}
			sctl.cr := TRUE;
			sctl.cr := FALSE;

			utlSetInternalErr(pSB, ScsiInteruptErr);
			goto 1;
		end;
	end; {with}
	hwiProgXfer := true;
	1:
end;



{*************************************************************************
 *  hwiStartDMAXfer
 *************************************************************************
 *
 * On Input: The bus is in the desired phase and the target is requesting
 *           data be transfered (direction of transfer will be based on
 *           what is on the bus).  The XferBlock in the InternalBlock has
 *           been set up.
 *
 *           The DMA channel has been determined and is stored in the
 *           InternalBlock.
 *
 * Functional Description:
 *
 *      Set up the hardware for a DMA transfer, and set up for an
 *      interrupt to occur from the CHIP only!  DMA should not cause
 *      an interrupt.
 *
 * On Output:  DMA started.
 *
 *************************************************************************}
function hwiStartDMAXfer(pSB:PtrSessionBlockType):boolean;
var
	Count:integer;
	locsc_reg:sc_reg_type;
begin
	hwiStartDMAXfer := true;
	with pSB^.InternalBlock, pScBlock^, PtrScsiCard^, PtrScsiChip^ do
	begin
		{
		  make sure the SCSI card is not doing DMA!
		}
		sc_reg.d_enab_0 := false;
		sc_reg.d_enab_1 := false;
		config_reg.pal_reset := 0;


		{
		  set up and arm the DMA card.
		  On entry, DMA32bit indicates the SCSI card DMA capabilities.
		  On exit,  DMA32bit indicates how the card was setup.
		}
		DMA32bit := not id_reg.d16;
		osdSetUpDMAChannel(DMAChannel, DMA32bit, XferBlock);


		{
		  set up and arm the Fujitsu CHIP
		}
		ints.ints := 0;
		Count := XferBlock.XferDMACount;
		data_regs.tch := chr(Count Div HEX('100') Div HEX('100'));
		data_regs.tcm := chr(Count Div HEX('100'));
		data_regs.tcl := chr(Count);
		pctl.t_phase := XferBlock.XferPhase;
		scmd.scmd := transfer_dmax;

		{
		  wait for chip to accept the transfer command.
		  if an interrupt has occured, then this is an error.
		}
		if (ssts.action <> spc_init_xfer) or (ints.ints <> 0) then
		begin
			osdStartTimer(one_second);
			repeat
			until (ssts.action = spc_init_xfer) or (ints.ints <> 0) or osdTimeExpired;
			if (ssts.action <> spc_init_xfer) or (ints.ints <> 0) then
			begin
				hwiStartDMAXfer := FALSE;
				utlSetInternalErr(pSB, ScsiCatastrophicErr);
			end;
		end;


		{
		  if no errors have occured, then
		    o set up the software to handle an interrupt.
		    o enable interrupts
		    o set up and enable the card to do DMA.
			- this will start the DMA process.
		}
		if  (ssts.action = spc_init_xfer) and (ints.ints = 0) then
		begin
			ISRWaiting := true;
			ISRMask := cmd_complete + svc_required + spc_hard_err;
			locsc_reg.control := 0;
			locsc_reg.ie := true;
			if DMA32bit then
				locsc_reg.dma_32 := true;
			if XferBlock.XferPhase = data_in_phase then
				locsc_reg.dma_dir := true;
			{ 375 h/w problem, write dma enable last!!!! }
			sc_reg.control := locsc_reg.control;
			if DMAChannel = 1 then
				sc_reg.d_enab_1 := true
			else
				sc_reg.d_enab_0 := true;
		end;
	end;
end;



{*************************************************************************
 *  hwiEndDMAXfer
 *************************************************************************
 *
 * On Input:
 *
 *      An interrupt (from the SCSI chip) has occured indicating the current
 *      DMA transfer has halted.
 *
 * Functional Description:
 *
 *      Determine the number of bytes transferred, and adjust
 *      XferBlock.  Determine the cause for the interrupt, and reset
 *      H/W accordingly.  If transfer should be continued (because of
 *      the 128K max transfer limitation with 16bit DMA) return FALSE to
 *      indicate DMA transfer did not end, otherwise TRUE.
 *
 *      Appropriate SCSI errors are placed in SessionBlock and ResultCode is set.
 *
 * On Output:  DMA transfer either stopped or killed.  H/W properly reset.
 *      FALSE is returned if DMA transfer must be continued, TRUE otherwise.
 *      ResultCode is set to ScsiErr if an error has occured, NoEvent otherwise.
 *
 *************************************************************************}
function  hwiEndDMAXfer(pSB:PtrSessionBlockType; Var ResultCode:S_SHORT):Boolean;
var
	Saveints:ints_type;
	AmtXfered,DMAStopCount:integer;
begin
	with pSB^.InternalBlock, XferBlock, pScBlock^, PtrScsiChip^, PtrScsiCard^ do
	begin
		sc_reg.ie := false;
		ISRWaiting := false;
		ResultCode := ord(NoEvent);
		hwiEndDMAXfer := TRUE;
		Saveints.ints := ints.ints;
		ints.ints := ints.ints;
		if (ISRError) or (serr.serr <> 0) then
			Saveints.spc_hard_err := true;

		DMAStopCount := (ord(data_regs.tch) * HEX('100') * HEX('100')) +
				(ord(data_regs.tcm) * HEX('100'))   +
				ord(data_regs.tcl);

		AmtXfered := XferDMACount - DMAStopCount;

		XferBufBlock.BufLen := XferBufBlock.BufLen - AmtXfered;

		{
		  note, use XferSavedDataPointer instead of BufPtr because the absolute
		  address from the beginning of the transfer is being calculated.
		}
		XferBufBlock.BufPtr := addr(XferSavedDataPointer^,
					XferSavedDataLength - XferBufBlock.BufLen);


		if (Saveints.spc_hard_err) then
		begin
			Saveints.spc_hard_err := false;

			{
				Reset the DMA channel.
			}
			osdKillDMA(DMAChannel);

			{
				reset the transfer control hardware on the chip/card.
			}
			sctl.cr := TRUE;
			sctl.cr := FALSE;

			if ISRError then
				ResultCode := ord(ScsiErr)
			else
			begin
				{
				  call hwiGetMsgOut which will force the bus to message out
				  phase (if target still expects to xfer data, this routine will
				  pump no-op data, or read and throw away data, until message
				  out phase has been granted.
				}
				hwiGetMsgOut(pSB, ResultCode);
			end;
		end
		else if (XferPhase = data_in_phase) then
		begin
			{
			  if this is an input DMA operation, then wait for DMA to
			  catch up to SCSI chip.

			  If DMA won't (osdStopDMA = false), then data has been lost.

			  (This is not necessary for output, because the count on the
			   SCSI chip reflects what actually has been transfered.)
			}
			if (not osdStopDMA(DMAChannel, DMA32bit, DMAStopCount)) then
			begin
				utlSetInternalErr(pSB, ScsiXferErr);
				ResultCode := ord(ScsiErr);
			end;
		end
		else
			osdKillDMA(DMAChannel);

		if (Saveints.svc_required) then
		begin
			Saveints.svc_required := false;

			{
				reset the transfer control hardware on the chip/card.
			}
			sctl.cr := TRUE;
			sctl.cr := FALSE;
		end;

		if (Saveints.cmd_complete) then
		begin
			Saveints.cmd_complete := false;
			if (ResultCode <> ord(ScsiErr)) and (XferBufBlock.BufLen > 0) then
					hwiEndDMAXfer := FALSE; {still more data to be xfered}
		end;

		if (Saveints.ints <> 0) {an unexpected interrupt has occured} then
		begin
			utlSetInternalErr(pSB, ScsiInteruptErr);
			ResultCode := ord(ScsiErr);

			{
				reset the transfer control hardware on the chip/card.
			}
			sctl.cr := TRUE;
			sctl.cr := FALSE;
		end;

		{
		   reset the igor PAL after every DMA transfer.
		}
		sc_reg.d_enab_1 := false;
		sc_reg.d_enab_0 := false;
		config_reg.pal_reset := 1;
	end;
end;

end;
@


56.1
log
@Automatic bump of revision number for PWS version 3.25
@
text
@d352 1
a352 1
	DeviceSynchParms[i].SynchState := NeedSynch;
@


55.1
log
@Automatic bump of revision number for PWS version 3.25A
@
text
@@


54.1
log
@Automatic bump of revision number for PWS version 3.24
@
text
@@


53.1
log
@Automatic bump of revision number for PWS version 3.24B
@
text
@@


52.1
log
@Automatic bump of revision number for PWS version 3.24A
@
text
@@


51.1
log
@Automatic bump of revision number for PWS version 3.24d
@
text
@@


50.2
log
@
1) repaired defect in hwiManXfer.  An all encompassing clear of
the interrupts was being done at the end of this routine.  QTD
was seeing a disconnect immediately after the HOST acknowledged
receipt of the DISCONNECT message.  In hwiManXfer, this occurs
at the reset_ack command.  The disconnect interrupt was raised,
but then hwiManXfer was clearing all interrupt flags.  Ooops.

Do not believe that any clearing of interrupt flags is necessary,
but to be on the safe side, am clearing the command complete
interrupt after resetting the ack command.

2) cleaned up the hwiManXfer header to reflect reality.

@
text
@@


50.1
log
@Automatic bump of revision number for PWS version 3.23c
@
text
@d414 2
a415 2
 *      indicate so in the RaiseATN boolean.  (On the last byte of message out
 *      data, the RaiseATN parameter should be set to false).
d417 4
d487 1
a504 2

		ints.ints := ints.ints;
@


49.1
log
@Automatic bump of revision number for PWS version 3.24b
@
text
@@


48.1
log
@Automatic bump of revision number for PWS version 3.24a
@
text
@@


47.1
log
@Automatic bump of revision number for PWS version 3.23
@
text
@@


46.1
log
@Automatic bump of revision number for PWS version 3.23
@
text
@@


45.2
log
@
hwiMsgGetMsgOut

	completely rewritten.  The previous routine did not, could not
	ever work.  The new routine can handle DMA and Synchronous Xfer.

hwiManXfer

	Do not reset ATN line until after REQ line is raised by target.
	This closes a very unlikely timing window.  100% of time when
	hwiManXfer is called, the REQ line is already up, but you never know...
@
text
@@


45.1
log
@Automatic bump of revision number for PWS version 3.23C
@
text
@d150 5
a154 3
Var
      XferCount:integer;
      b        :char;
d156 1
a156 7
    with PtrSessionBlock^.InternalBlock.pScBlock^.PtrScsiChip^ do
    begin
	XferCount := osdBitLsL(ord(data_regs.tch), 16) + osdBitLsL(ord(data_regs.tcm), 8) +
		     ord(data_regs.tcl) + 1024;
	scmd.cmd := set_atn_cmd;  {Tell peripheral we want message out!}

	while (psns.t_phase <> msg_out_phase) and (XferCount > 0) do
d158 67
a224 7
	    {
		wait for peripheral to request a transfer
	    }
	    osdStartTimer(one_second);
	    repeat
	    until psns.req or osdTimeExpired;
	    if (not psns.req) or (psns.t_phase = msg_out_phase) then goto 1;
d226 8
a233 9
	    {
		Peripheral has requested a transfer and phase is NOT msg out
		NOTE: reading the data as if in asynchrnous mode always
		tbd - use programmatic mode this will work with synch protocol to!
	    }
	    pctl.t_phase := psns.t_phase;
	    if (psns.io) {input mode} then
	    begin
		scmd.cmd := set_ack_req_cmd;
d235 31
a265 12
		until (not psns.req) or (psns.t_phase = msg_out_phase);
		b := data_regs.temp;
	    end
	    else {output mode}
	    begin
		data_regs.temp := #0;
		scmd.cmd := set_ack_req_cmd;
		repeat
		until (not psns.req) or (psns.t_phase = msg_out_phase);
	    end;
	    scmd.cmd := reset_ack_req_cmd;
	    XferCount := XferCount - 1;
a266 10

	1:
	if psns.t_phase <> msg_out_phase then
	begin
	     ResultCode := ORD(ScsiErr);
	     utlSetInternalErr(PtrSessionBlock, ScsiPhaseErr);
	end
	else
	      ResultCode := ORD(MsgOut);
    end;
a428 9
		if (MORE) and (hwPhase = msg_out_phase) then
		begin
			scmd.cmd := set_atn_cmd;
		end
		else
		begin
			scmd.cmd := reset_atn_cmd;
		end;

d438 9
@


44.1
log
@Automatic bump of revision number for PWS version 3.23B
@
text
@@


43.1
log
@Automatic bump of revision number for PWS version 3.23aA
@
text
@@


42.3
log
@hwiGetPhase:	Cleaned up for a litter performance gain.
hwiManXfer:	Do NOT reset tmod.tmod!!!!! (caused problems
		w/synch transfers).
hwiProgXfer:    Only wait 1 second after prog transfer instead of 10.
                hwiAXfer now forces fifo to empty or interrupt to occur on
		data out transfers.
DMAXfer:	Added some comments
@
text
@@


42.2
log
@The programmatic transfer portion of hwiProgXfer was replaced by the
procedure hwiAXfer.  This routine is in the HWIA_UTILS module.  It
is a highly optimized assembler routine which significantly increased
programmatic transfer performance.
@
text
@d71 14
a84 18
		repeat
			BusLines.psns := psns.psns;
			if ssts.action = spc_not_connected then {chip is not being used}
			begin
				if BusLines.bsy then
					ResultCode := ORD(BusBusy)
				else
					ResultCode := ORD(BusFree);
			end
			else if SessionState <> SessionRunning then
				ResultCode := ORD(BusBusy) {Another Session is running}
			else {this session must be in an information transfer phase}
			begin
				ResultCode := PhaseTranslate[BusLines.t_phase];
				if ResultCode = ORD(ScsiErr) then {Bus is in transition}
					BusLines.psns := 255;
			end;
		until BusLines.psns = psns.psns; {incase bus is in transition}
a364 1
		tmod.tmod := 0;
d485 4
d490 1
d534 1
a534 1
			osdStartTimer(10*one_second);
d644 1
a644 1
		  make sure the card is not doing DMA!
d765 4
@


42.1
log
@Automatic bump of revision number for PWS version 3.23e
@
text
@d10 1
a10 1
import SCSI_DEFS, OSD_LL, SCSI_UTILS;
d36 1
a514 1

d516 1
a516 3
			execute the programmatic xfer
			if read, wait for data in fifo, then read data register
			if write, wait for fifo not full, then write data register
d518 1
a518 32
		if (XferPhase = data_in_phase) {read} then
		while (XferBufBlock.BufLen > 0) do
		begin
			if (not ssts.dempty) then
			begin
				PtrChar(XferBufBlock.BufPtr)^ := data_regs.dreg;
				XferBufBlock.BufPtr := addr(XferBufBlock.BufPtr^,1);
				XferBufBlock.BufLen := XferBufBlock.BufLen - 1;
			end
			else
			begin
				repeat until (not ssts.dempty) or (ints.ints <> 0);
				if ints.ints <> 0 then
					goto 2;
			end;
		end
		else {write}
		while (XferBufBlock.BufLen > 0) do
		begin
			if (not ssts.dfull) then
			begin
				data_regs.dreg := PtrChar(XferBufBlock.BufPtr)^;
				XferBufBlock.BufPtr := addr(XferBufBlock.BufPtr^,1);
				XferBufBlock.BufLen := XferBufBlock.BufLen - 1;
			end
			else
			begin
				repeat until (not ssts.dfull) or (ints.ints <> 0);
				if ints.ints <> 0 then
					goto 2;
			end;
		end;
@


41.3
log
@Updated hwiEndDMAXfer to recognize an ISRError.
@
text
@@


41.2
log
@When the reset line is toggled, HardReset, also initialize the
SCSI HW (InitHW).  This is done because code in HardReset which
had originally been the same as that in InitHW was not longer
the same, thus call InitHW to get common code for common job.

@
text
@d787 1
a787 1
		if serr.serr <> 0 then
d817 12
a828 7
			{
				call hwiGetMsgOut which will force the bus to message out
				phase (if target still expects to xfer data, this routine will
				pump no-op data, or read and throw away data, until message
				out phase has been granted.
			}
			hwiGetMsgOut(pSB, ResultCode);
@


41.1
log
@Automatic bump of revision number for PWS version 3.23d
@
text
@d124 2
d131 1
a131 1
	hwiSChardReset(PtrSessionBlock^.SelectCode);
d272 2
d289 1
a289 4
    sctl.sctl := reset_disable + control_reset; { ensure SPC disabled }
    osdDelay(1);
    sctl.rd := false; { clear reset disable }
    config_reg.pal_reset := 1;
@


40.9
log
@Fixed a potential problem with SCSI DMA on the 375.
@
text
@@


40.8
log
@Added error checking in getphase and progxfer
@
text
@d737 2
d740 1
a740 1
				locsc_reg.d_enab_1 := true
d742 1
a742 2
				locsc_reg.d_enab_0 := true;
			sc_reg.control := locsc_reg.control;
a874 1

@


40.7
log
@Rewrote the DMA set up methodology.  Used to be:

	1) Set up DMA, but do not ARM it.
	2) Set up and ARM the IGOR Card
	3) Set up the SCSI Chip
	4) ARM DMA which kicks transfer off.

Now is:

	1) Set up and ARM DMA
	2) Set up the SCSI Chip
	3) Set up and ARM IGOR card, which kicks transfer off.
@
text
@d82 1
d84 3
a86 2
			if ResultCode = ORD(ScsiErr) then {Bus is in transition}
				BusLines.psns := 0;
d466 1
a466 1
	1;
d502 3
a504 1
			repeat until (ssts.action = spc_init_xfer) or osdTimeExpired;
d520 1
a520 1
		while (XferBufBlock.BufLen > 0) and (ints.ints = 0) do
d531 2
d536 1
a536 1
		while (XferBufBlock.BufLen > 0) and (ints.ints = 0) do
d547 2
d574 1
@


40.6
log
@Updated DMA implementation such that the OSD routines handled the DMA count
modifications, and the HWI_UTILS routine used absolute count for the
DMAcount values.  Added better comments and documentation.
@
text
@d661 1
d666 6
a671 1
		DMA32bit := not id_reg.d16;
d673 1
d675 1
a675 1
		  set up the DMA card.
d679 1
a681 19
		{
		  set up the card to do DMA.
		}
		sc_reg.dma_32 :=DMA32bit;
		if XferBlock.XferPhase = data_in_phase then
			sc_reg.dma_dir := true
		else
			sc_reg.dma_dir := false;
		if DMAChannel = 1 then
		begin
			sc_reg.d_enab_0 := false;
			sc_reg.d_enab_1 := true;
		end
		else
		begin
			sc_reg.d_enab_1 := false;
			sc_reg.d_enab_0 := true;
		end;
		sc_reg.ie := true;
a682 1

d684 1
a684 1
		  set up software for an interrupt.
a686 7
		ISRWaiting := true;
		ISRMask := cmd_complete + svc_required + spc_hard_err;


		{
		  set up the chip for transfer
		}
d692 1
d695 2
a696 1
		  kick off DMA transfer.
d698 1
a698 2
		scmd.scmd := transfer_dmax;
		if (ssts.action <> spc_init_xfer) and (ints.ints = 0) then
d703 1
a703 1
			if (ssts.action <> spc_init_xfer) and (ints.ints = 0) then
d710 24
a733 2
		if (ints.ints = 0) then
			osdARMDMAChannel(DMAChannel, DMA32bit, XferBlock)
d798 1
a798 1
			osdKillDMA(DMAChannel, DMA32bit);
d832 1
a832 1
			osdKillDMA(DMAChannel, DMA32bit);
a867 1
		config_reg.pal_reset := 1;
d870 1
@


40.5
log
@Modifications for DMA support.
hwiStartDMAXfer and hwiEndDMAXfer added.
@
text
@d706 1
a706 6
		Count := XferBlock.XferDMACount+1;
		if (DMA32bit) then
			Count := Count * 4
		else
			Count := Count * 2;

d734 25
d762 1
a762 1
	Count,DMACount:integer;
d775 3
a777 3
		Count := (ord(data_regs.tch) * HEX('100') * HEX('100')) +
			 (ord(data_regs.tcm) * HEX('100'))   +
			  ord(data_regs.tcl);
d779 1
a779 10
		if DMA32bit then
		begin
			DMACount := (Count Div 4) - 1;
			Count := ((XferDMACount + 1) * 4) - Count;
		end
		else
		begin
			DMACount := (Count Div 2) - 1;
			Count := ((XferDMACount + 1) * 2) - Count;
		end;
d781 1
a781 1
		XferBufBlock.BufLen := XferBufBlock.BufLen - Count;
d821 1
a821 1
			if (not osdStopDMA(DMAChannel, DMA32bit, DMACount)) then
@


40.4
log
@Moved msgGetMsgOut to hwiGetMsgOut.
created hwiProgXfer.
@
text
@d32 2
d224 1
a224 1
	with pScBlock^.PtrScsiCard^, pScBlock^.PtrScsiChip^ do
d251 1
d286 1
d470 1
a470 1
	with pSB^.InternalBlock, XferBlock, pScBlock^.PtrScsiChip^ do
d585 1
a585 1
			reset the transfer control hardware on the chip.
d587 2
a588 1
			sctl.cr := TRUE;  sctl.cr := FALSE;
d608 1
a608 1
				reset the transfer control hardware on the chip.
d610 2
a611 1
			sctl.cr := TRUE;  sctl.cr := FALSE;
d615 1
d617 1
d621 6
d633 224
@


40.3
log
@Updated to reflect SCSI_DEFS modifications for programmer's interface.
@
text
@d20 1
d31 1
d130 74
d436 183
@


40.2
log
@Added modifications to support synchronous protocol.
hwiManXfer - new interface parameters to help it know when to wait for
             a new phase, and when and where to raise the atn line.
           - previous feeble attempt to retry taken out, and will not be
	     supported.
	   - additional error checking (ints.ints) when waiting for a req
	     change.
hwiScHardReset - set all synch parms to NeedSynch.
@
text
@d64 1
a64 1
	with PtrSessionBlock^.InternalBlock, pScBlock^.PtrScsiChip^ do
@


40.1
log
@Automatic bump of revision number for PWS version 3.23c
@
text
@d29 1
a29 1
			     hwPhase:phase_code; RaiseATN:Boolean):Boolean;
d195 1
d198 1
a198 1
  with pScBlock^.PtrScsiCard^, pScBlock^.PtrScsiChip^ do
d207 2
d277 2
a278 2
function hwiManXfer(pSB:PtrSessionBlockType; var b:s_byte; hwPhase:phase_code; RaiseATN:Boolean):Boolean;
label 1;
a283 1
		1:
d286 1
a286 1
		if RaiseATN then
d288 1
a288 1
		   scmd.cmd := set_atn_cmd;
d292 1
a292 1
		   scmd.cmd := reset_atn_cmd;
d299 1
a299 1
		if not psns.req then
d303 1
a303 1
			until psns.req or osdTimeExpired;
d322 1
a322 1
				repeat until not psns.req;
d329 1
a329 1
				repeat until not psns.req;
d331 8
a339 1
			hwiManXfer := true;
d341 7
a347 1
		if (not RaiseATN) then
d349 2
d353 2
a354 20
				if (psns.req) then {xmission retry required.}
				begin
					if (retry_count < XferRetryMax) then
					begin
						retry_count := retry_count + 1;
						goto 1;
					end;
					hwiManXfer := false;
					utlSetInternalErr(pSB, XferRetryErr);
				end
				else {wait for a phase change}
				begin
					osdStartTimer(one_second);
					repeat until (psns.t_phase <> hwPhase) or osdTimeExpired;
					if (psns.t_phase = hwPhase) then
					begin
						hwiManXfer := false;
						utlSetInternalErr(pSB, ScsiPhaseErr);
					end;
				end;
d357 2
@


39.1
log
@Automatic bump of revision number for PWS version 3.23b
@
text
@@


1.1
log
@Initial revision
@
text
@@
