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


56.7
date     93.07.06.10.04.55;  author jwh;  state Exp;
branches ;
next     56.6;

56.6
date     93.07.06.09.37.10;  author jwh;  state Exp;
branches ;
next     56.5;

56.5
date     93.03.11.15.51.14;  author jwh;  state Exp;
branches ;
next     56.4;

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

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

56.2
date     93.01.27.12.26.12;  author jwh;  state Exp;
branches ;
next     56.1;

56.1
date     91.11.05.10.01.52;  author jwh;  state Exp;
branches ;
next     55.3;

55.3
date     91.10.08.14.15.56;  author jwh;  state Exp;
branches ;
next     55.2;

55.2
date     91.10.08.14.05.46;  author jwh;  state Exp;
branches ;
next     55.1;

55.1
date     91.08.25.10.36.43;  author jwh;  state Exp;
branches ;
next     54.11;

54.11
date     91.08.04.15.45.22;  author jwh;  state Exp;
branches ;
next     54.10;

54.10
date     91.07.10.12.42.15;  author jwh;  state Exp;
branches ;
next     54.9;

54.9
date     91.06.25.15.30.59;  author jwh;  state Exp;
branches ;
next     54.8;

54.8
date     91.06.21.10.23.03;  author jwh;  state Exp;
branches ;
next     54.7;

54.7
date     91.06.21.09.57.23;  author jwh;  state Exp;
branches ;
next     54.6;

54.6
date     91.06.20.14.40.17;  author jwh;  state Exp;
branches ;
next     54.5;

54.5
date     91.06.20.14.13.11;  author jwh;  state Exp;
branches ;
next     54.4;

54.4
date     91.06.20.14.04.00;  author jwh;  state Exp;
branches ;
next     54.3;

54.3
date     91.06.20.13.52.28;  author jwh;  state Exp;
branches ;
next     54.2;

54.2
date     91.06.20.13.47.08;  author jwh;  state Exp;
branches ;
next     54.1;

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

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

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

51.1
date     91.01.30.16.20.33;  author jwh;  state Exp;
branches ;
next     50.1;

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

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

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

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

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

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

45.1
date     90.04.19.16.06.10;  author jwh;  state Exp;
branches ;
next     44.3;

44.3
date     90.04.10.10.28.31;  author dew;  state Exp;
branches ;
next     44.2;

44.2
date     90.04.04.10.11.30;  author dew;  state Exp;
branches ;
next     44.1;

44.1
date     90.04.01.22.26.07;  author jwh;  state Exp;
branches ;
next     43.2;

43.2
date     90.03.26.16.00.51;  author dew;  state Exp;
branches ;
next     43.1;

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

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

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

42.1
date     90.01.23.18.00.09;  author jwh;  state Exp;
branches ;
next     41.5;

41.5
date     90.01.19.09.16.12;  author dew;  state Exp;
branches ;
next     41.4;

41.4
date     90.01.18.23.04.34;  author dew;  state Exp;
branches ;
next     41.3;

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

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

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

40.9
date     89.12.21.15.56.53;  author jwh;  state Exp;
branches ;
next     40.8;

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

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

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

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

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

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

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

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

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

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


desc
@SCSIIF is the programmer's interface file.
@


56.7
log
@Changes for McBeth support, fixing editing errors from last time.
@
text
@{system options}
$modcal on$
$allow_packed on$
$partial_eval on$

{code generation options}
$debug off$
$LINENUM 20000$
$iocheck on$
$ovflcheck on$
$range on$
$stackcheck on$

{listing options}
$tables off$
$lines 57$
$pagewidth 130$
$copyright 'Hewlett Packard Company, 1989'$

{{
$search 'PWS_SCSI'$
{Needed for TDEBUG - Don't delete SCSIDVR symbols during LINK!}
$PAGE$

{
	SCSI Interface Module.
	Contains a definition of all of the SCSI commands.  and provides
	the routine ScsiHandleSession.
	It is intended that all outside users would search/link this module, using
	it to get inteface to the scsi driver.
}
module SCSILIB;

import sysglobals, asm, iodeclarations {{, STATE_PROCS, LOADER{needed for TDEBUG};

export

{---- begin of SCSIIF common. do not modify!!! below is copied from SCSI_DEFS during turn process}


type
	s_byte = 0 .. 255;
	s_short = 0..65535;
	s_short_signed = -32768..32767;
	PtrS_byte = ^s_byte;
	PtrChar = ^char;
	s_TYPE_ISC = 0..31;
const
	trace_size = 1000;


type
	PtrSessionBlockType = ^SessionBlockType;
	ScsiDeviceType = 0 .. 7;

	InternalErrType = ( NoIntErr, ScsiStackingErr, RunLevelErr,
			    StateMachineErr, ScsiInteruptErr, ScsiAddressErr,
			    SelectRetryErr, ScsiManXferErr, ScsiXferErr,
			    XferRetryErr, ScsiEscapeErr, ScsiPhaseErr,
			    ScsiCatastrophicErr, ScsiBadMsg, ScsiTimeOutErr,
			    ScsiXferParmErr, ScsiMiscErr );

	SessionStateType = (
			    SessionWaiting,     {Session is initialized and waiting to be started.}
			    SessionRunning,     {Session running (State Machine is started)}
			    SessionSuspended,   {Target disconnected, bus released, awaiting reselection}
			    SessionComplete     {Session terminated, either normally or with an err}
			   );


	ScsiCallBackType = Procedure(pSB:PtrSessionBlockType);

	BufferBlockType = RECORD
				BufPtr:PtrS_byte;
				BufLen:integer;
				DoDMA:Boolean;
			END;


	SessionBlockType = RECORD
				{Caller sets before session}
				SelectCode:s_TYPE_ISC;
				Device:ScsiDeviceType;
				LUN:s_byte;
				SUN:s_byte;
				Overlap:Boolean;
				DoNotDisconnect:Boolean;
				CmdPtr:ANYPTR;
				CmdLen:s_byte;
				BufIn:BufferBlockType;
				BufOut:BufferBlockType;
				SessionCompleteCallBack:ScsiCallBackType;

				{set by SCSI Bus Driver during session}
				SessionState:SessionStateType;
				SessionStatus:s_byte;
				InternalStatus:InternalErrType;
				ResidualCount: INTEGER;

				{Internal Use Only}
				{Trace set by caller}
				{InternalBlock used by driver}
				DoTrace:Boolean;
				TracePtr:ANYPTR;
				TraceSize:integer;
				TraceStuff:ANYPTR;
				InternalBlock:PACKED ARRAY [1..128] of CHAR;
			END;



{---- end of SCSIIF common. do not modify!!! above is copied from SCSI_DEFS during turn process}

type
      uep_type = ^unitentry;

      mode_select_cmd_type = packed record
			   op_code : byte;
			   lunit   : 0..7;
			   pf      : 0..1;
			   rsvd1   : 0..7;
			   sp      : 0..1;
			   rsvd2   : byte;
			   rsvd3   : byte;
			   reqlen  : byte;
			   pad2    : byte;
			 end;

     mode_select_data_type = packed record
			   ms_len  : byte;
			   medtype : byte;
			   wp      : boolean;
			   rsvd1   : 0 .. 127;
			   bd_len  : byte;
			   ms_data : packed array [ 0 .. 255 ] of char;
			 end;



      PtrModeSenseDataType = ^mode_sense_data_type;
      PtrModeSelectDataType = ^mode_select_data_type;

    PtrDeviceAddressVectorsType = ^DeviceAddressVectorsType;
    DeviceAddressVectorsType = PACKED RECORD
		sc,  {select code}
		ba,  {bus address   - Session Device}
		du,  {device unit   - Session LUN}
		dv  {device volume - Session SUN}
		  :-128..127;
		    END;



	procedure IsScsiCard(       sc:S_TYPE_ISC;
				var b:boolean);

	procedure ScsiSBSize(   var size:integer);

	procedure ScsiSBInit(       pSB:ANYPTR;
				    pDAV:ANYPTR);

	function  ScsiHandleSession(pSB:PtrSessionBlockType;
				    pCmd:ANYPTR; lCmd:integer;
				    pDIn:ANYPTR; lDIn:integer; DMAIn:boolean;
				    pDOut:ANYPTR; lDOut:integer; DMAOut:boolean
				   ):integer;

	function ScsiSessionComplete(pSB:PtrSessionBlockType):BOOLEAN;

	function ScsiCheckError(pSB:PtrSessionBlockType):integer;

	procedure ScsiSessionSense( SelectCode:S_TYPE_ISC;
				    pBuf:ANYPTR;
				var Length:integer);

	procedure ScsiSessionAbort(pSB:PtrSessionBlockType);

	procedure ScsiReset(        SelectCode:S_TYPE_ISC);

	procedure ScsiModeSelect(pSB:PtrSessionBlockType;
				 pDB : PtrModeSelectDataType;
				 sector_size : integer);

	procedure ScsiModeSense(pSB:PtrSessionBlockType;
				pDB : PtrModeSenseDataType ;
				var sector_size : integer);

	procedure ConfigureMcBeth(pSB : PtrSessionBlockType);

	function SyncMcBeth(pSB : PtrSessionBlockType): integer;

	procedure TapeName( uep : uep_type; var i : string80) ;

	procedure ScsiTapeUnload(pDAV : PtrDeviceAddressVectorsType);

	procedure SyncTeac(pSB : PtrSessionBlockType);

	procedure ScsiCheckDev(     pSB:PtrSessionBlockType);

	procedure ScsiDevInfo(      pSB:PtrSessionBlockType;
				var DevType, AnsiVersion:integer;
				var Removable:boolean;
				var VendorString:string255);

	procedure ScsiDiscSize(     pSB:PtrSessionBlockType;
				var NumBytesBlock, NumBlocksTrack,
				    NumTracksCylinder, NumCylinders:integer);

	procedure ScsiDiscBlocks(   pSB:PtrSessionBlockType;
				var NumBytesBlock, TotBlocks:integer);

	procedure ScsiTapeRead(     pSB:PtrSessionBlockType;
				    BlockStart, NumBlocks,
				    NumBytesBlock:integer;
				    Buffer:ANYPTR);

	procedure ScsiTapeWrite(    pSB:PtrSessionBlockType;
				    BlockStart, NumBlocks,
				    NumBytesBlock:integer;
				    Buffer:ANYPTR);

	procedure ScsiDiscRead(     pSB:PtrSessionBlockType;
				    BlockStart, NumBlocks, NumBytesBlock:integer;
				    Buffer:ANYPTR);

	procedure ScsiDiscWrite(    pSB:PtrSessionBlockType;
				    BlockStart, NumBlocks, NumBytesBlock:integer;
				    Buffer:ANYPTR);

	procedure ScsiDiscFormat(   pSB:PtrSessionBlockType;
				    InterLeave:s_short);

	procedure ScsiDiscPrevent(  pSB:PtrSessionBlockType);

	procedure ScsiDiscAllow(    pSB:PtrSessionBlockType);

implement
const
	DEBUG  = FALSE;
	TDEBUG = FALSE;

type
	MiscTemplate = packed record
		MiscpScBlock:ANYPTR;
		MiscpSenseSpace:PtrChar;
		MiscSenseLength:integer;
	end;
	PtrMiscTemplateType = ^MiscTemplate;

type
       test_cmd_type = packed record
			   op_code : byte;
			   lunit   : 0..7;
			   pad0    : 0..31;
			   pad1    : shortint;
			   pad2    : byte;
			   pad3    : byte;
			 end;
const
      test_cmd_const = test_cmd_type[
			   op_code:hex('00'),
			   lunit:0,
			   pad0:0,
			   pad1:0,
			   pad2:0,
			   pad3:0];

type
      inq_string = string255;
      inquiry_cmd_type = packed record
			   op_code : byte;
			   lunit   : 0..7;
			   pad0    : 0..31;
			   pad1    : shortint;
			   reqlen  : byte;
			   pad2    : byte;
			 end;

      inquiry_data_type = packed record
			    case integer of
			    1:(device_code : shortint);
			    2:(device_type : byte;
			       rmb         : boolean;
			       qualifier   : 0..127;
			       iso_version : 0..3;
			       ecma_version: 0..7;
			       ansi_version: 0..7;
			       pad1        : byte;
			       vendor      : inq_string);
			    3:(inqjunk     : integer;
			       vendlen     : byte);
			  end;
const
      inquiry_cmd_const = inquiry_cmd_type[
				  op_code:hex('12'),
				  lunit:0,
				  pad0:0,
				  pad1:0,
				  reqlen:255,
				  pad2:0];

type
      read_capacity_cmd_type = packed record
				 op_code : byte;
				 lunit   : 0..7;
				 pad0    : 0..15;
				 reladr  : boolean;
				 block_n : integer;
				 case integer of
				 1:(pad1 : integer);
				 2:(pad2 : shortint;
				    v0   : 0..3;
				    pad3 : 0..31;
				    pmi  : boolean;
				    v1   : 0..3;
				    pad4 : 0..15;
				    flag : boolean;
				    link : boolean);
			       end;
      read_capacity_data_type = packed record
				  block_n : integer;
				  capacity: integer;
				end;

const
      read_capacity_cmd_const = read_capacity_cmd_type[
				  op_code:hex('25'),
				  lunit:0,
				  pad0:0,
				  reladr:false,
				  block_n:0,
				  pad1:0];

type

      mode_sense_cmd_type = packed record
			   op_code : byte;
			   lunit   : 0..7;
			   pad0    : 0..31;
			   pcf     : 0..3;
			   pg_code : 0..hex('3f');
			   pad1    : byte;
			   reqlen  : byte;
			   pad2    : byte;
			 end;

     mode_sense_data_type = packed record
			   ms_len  : byte;
			   medtype : byte;
			   wp      : boolean;
			   rsvd1   : 0 .. 127;
			   bd_len  : byte;
			   ms_data : packed array [ 0 .. 255 ] of char;
			 end;

     block_descript_type = packed record
			   d_code  : byte;
			   nb_msb  : byte;
			   nb_2    : byte;
			   nb_lsb  : byte;
			   rsvd1   : byte;
			   bl_msb  : byte;
			   bl_2    : byte;
			   bl_lsb  : byte;
			 end;

      page_header_type = packed record
			   r1      : boolean;
			   r2      : boolean;
			   PageCode: 0 .. 63;
			   PageLen : byte;
			 end;
      pPageType = ^page_header_type;

const
	mode_sense_cmd_const = mode_sense_cmd_type[
			   op_code : hex('1a'),
			   lunit   : 0,
			   pad0    : 0,
			   pcf     : 0,
			   pg_code : hex('3f'),
			   pad1    : 0,
			   reqlen  : 255,
			   pad2    : 0];


       mode_select_cmd_const = mode_select_cmd_type[
			   op_code : hex('15'),
			   lunit   : 0,
			   pf      : 0,
			   rsvd1   : 0,
			   sp      : 0,
			   rsvd2   : 0,
			   rsvd3   : 0,
			   reqlen  : HEX('0C'),
			   pad2    : 0];

type
      read_cmd_type = packed record
			op_code : byte;
			lunit   : 0..7;
			pad0    : 0..15;
			reladr  : boolean;
			block_n : integer;
			{case integer of
			1:(pad1 : integer);
			2:(pad2    : byte;
			   n_blocks: shortint;
			   pad3    : byte);
			3:(}pad4    : byte;
			   lmsb    : byte;
			   llsb    : byte;
			   v0      : 0..3;
			   pad5    : 0..15;
			   flag    : boolean;
			   link    : boolean;
		      end;

const
      read_cmd_const = read_cmd_type[
			   op_code : hex('28'),
			   lunit:0,
			   pad0:0,
			   reladr:false,
			   block_n:0,
			   pad4    : 0,
			   lmsb    : 0,
			   llsb    : 0,
			   v0      : 0,
			   pad5    : 0,
			   flag    : FALSE,
			   link    : FALSE];

type
      write_cmd_type = read_cmd_type;

const
      write_cmd_const = write_cmd_type[
			   op_code : hex('2a'),
			   lunit:0,
			   pad0:0,
			   reladr:false,
			   block_n:0,
			   pad4    : 0,
			   lmsb    : 0,
			   llsb    : 0,
			   v0      : 0,
			   pad5    : 0,
			   flag    : FALSE,
			   link    : FALSE];
			   {pad1:0,
			   n_blocks:0,
			   pad2:0];}

type
      request_sense_cmd_type = packed record
				 op_code : byte;
				 lunit   : 0..7;
				 pad0    : 0..31;
				 pad1    : shortint;
				 len     : byte;
				 case integer of
				 1:(byte5 : byte);
				 2:(v0    : 0..3;
				    pad2  : 0..15;
				    flag  : boolean;
				    link  : boolean);
			       end;
      pac18 = packed array [1..18] of byte;
      request_sense_data_type = packed record
				  case integer of
				  1:(sensedata:packed array[1..255] of char);
				  2:(advalid : boolean;
				     e_class : 0..7;
				     e_code  : 0..15;
				     case integer of
				     1:(seg_num : byte;
					filemark: boolean;
					eom     : boolean;
					ili     : boolean;
					pad0    : boolean;
					sensekey: 0..15;
					byte3   : byte;
					more    : pac18;);
				     2:(block_n : 0..16777215));
				 end;
      ptr_request_sense_data_type = ^request_sense_data_type;
      SenseType  = (sNoSense, sRecoveredError, sNotReady, sMediumError,
		    sHardwareError, sIllegalRequest, sUnitAttention,
		    sDataProtect, sBlankCheck, sVendor, sCopyAbort,
		    sCommandAbort, sEqual, sVolumeOverflow, sMisCompare,
		    sReserved,
		    DriverError, IllegalStatus, GetSenseFailed);

const
      request_sense_cmd_const = request_sense_cmd_type[
				  op_code:hex('03'),
				  lunit:0,
				  pad0:0,
				  pad1:0,
				  len:sizeof(request_sense_data_type),
				  byte5:0];

type
       format_cmd_type = packed record
			   op_code : byte;
			   lunit   : 0..7;
			   fmtdata : boolean;
			   cmplst  : boolean;
			   dlf     : 0..7;
			   v0      : byte;
			   il_msb  : byte;
			   il_lsb  : byte;
			   v1      : 0..3;
			   rsvd    : 0..15;
			   flag    : boolean;
			   link    : boolean;
			 end;
	defect_header_type = packed record
			   rsvd1   : byte;
			   fov     : boolean;
			   dpry    : boolean;
			   dcrt    : boolean;
			   stpf    : boolean;
			   rsvd2   : 0 .. 7;
			   v0      : boolean;
			   lmsb    : byte;
			   llsb    : byte;
			   end;
const
      format_cmd_const = format_cmd_type[
			   op_code:hex('04'),
			   lunit:0,
			   fmtdata:false,
			   cmplst:false,
			   dlf:0,
			   v0:0,
			   il_msb:0,
			   il_lsb:0,
			   v1:0,
			   rsvd:0,
			   flag:false,
			   link:false];

	defect_header_const = defect_header_type[
			    rsvd1:0,
			    fov:false,
			    dpry:false,
			    dcrt:false,
			    stpf:false,
			    rsvd2:0,
			    v0:false,
			    lmsb:0, llsb:0];

type

      prevent_allow_cmd_type = packed record
			   op_code : byte;
			   lunit   : 0..7;
			   pad0    : 0..31;
			   pad1    : shortint;
			   pad2    : 0..hex('7f');
			   prevent : boolean;
			   pad3    : byte;
			 end;


const
	prevent_cmd_const = prevent_allow_cmd_type[
			   op_code : hex('1e'),
			   lunit   : 0,
			   pad0    : 0,
			   pad1    : 0,
			   pad2    : 0,
			   prevent : true,
			   pad3    : 0];

	allow_cmd_const = prevent_allow_cmd_type[
			   op_code : hex('1e'),
			   lunit   : 0,
			   pad0    : 0,
			   pad1    : 0,
			   pad2    : 0,
			   prevent : false,
			   pad3    : 0];
type
      status_type = packed record
		       case integer of
			  1:(b:byte;);
			  2:(r:boolean;
			     v1:0..3;
			     stat:0..15;
			     v2:boolean;);
		    end;

type
      read_tape_cmd_type = packed record
			op_code : byte;
			lunit   : 0..7;
			pad0    : 0..7;
			sili    : 0..1;
			fixed   : 0..1;
			xferlen1 : s_byte;
			xferlen2 : s_byte;
			xferlen3 : s_byte;
			pad2 : 0..63;
			flag : 0..1;
			link : 0..1;
		      end;

const
      read_tape_cmd_const = read_tape_cmd_type[
			   op_code : hex('08'),
			   lunit:0,
			   pad0:0,
			   sili:0,
			   fixed:1,
			   xferlen1:0,
			   xferlen2:0,
			   xferlen3:0,
			   pad2:0,
			   flag:0,
			   link:0];
type
      write_tape_cmd_type = packed record
			op_code : byte;
			lunit   : 0..7;
			pad0    : 0..15;
			fixed   : 0..1;
			xferlen1 : s_byte;
			xferlen2 : s_byte;
			xferlen3 : s_byte;
			pad2 : 0..63;
			flag : 0..1;
			link : 0..1;
		      end;

const
      write_tape_cmd_const = write_tape_cmd_type[
			   op_code : hex('0A'),
			   lunit:0,
			   pad0:0,
			   fixed:1,
			   xferlen1:0,
			   xferlen2:0,
			   xferlen3:0,
			   pad2:0,
			   flag:0,
			   link:0];
type
      rewind_tape_cmd_type = packed record
			op_code : byte;
			lunit   : 0..7;
			pad0    : 0..15;
			immed   : 0..1;
			pad1    : byte;
			pad2    : byte;
			pad3    : byte;
			pad4 : 0..63;
			flag : 0..1;
			link : 0..1;
		      end;
const
      rewind_tape_cmd_const = rewind_tape_cmd_type[
			op_code : hex('01'),
			lunit   : 0,
			pad0    : 0,
			immed   : 1,
			pad1    : 0,
			pad2    : 0,
			pad3    : 0,
			pad4 : 0,
			flag : 0,
			link : 0];
type
      read_tape_position = packed record
			op_code : byte;
			lunit   : 0..7;
			pad0    : 0..15;
			  bt    : 0..1;
			pad1    : byte;
			pad2    : byte;
			pad3    : byte;
			pad4    : byte;
			pad5    : byte;
			pad6    : byte;
			pad7    : byte;
			pad8 : 0..63;
			flag : 0..1;
			link : 0..1;
		       end;

tape_position_data_type = packed record
	      bop : 0..1;
	      eop : 0..1;
	      pad0 : 0..7;
	      bpu : 0..1;
	      pad1 : 0..3;
	      partition : byte;
	      pad2 : shortint;
	      first : integer;
	      last : integer;
	      pad3 : byte;
	      blocks_in_buff1 : byte;
	      blocks_in_buff2 : byte;
	      blocks_in_buff3 : byte;
	      bytes_in_buff1 : byte;
	      bytes_in_buff2 : byte;
	      bytes_in_buff3 : byte;
	      bytes_in_buff4 : byte;
	     end;

const
      read_tape_position_const = read_tape_position[
			   op_code : hex('34'),
			   lunit:0,
			   pad0:0,
			   bt : 1,
			   pad1 : 0,
			   pad2 : 0,
			   pad3 : 0,
			   pad4 : 0,
			   pad5 : 0,
			   pad6 : 0,
			   pad7 : 0,
			   pad8 : 0,
			   flag:0,
			   link:0];

type
      unload_tape_cmd = packed record
			op_code : byte;
			lunit   : 0..7;
			pad0    : 0..15;
			immed   : 0..1;
			pad1    : byte;
			pad2    : byte;
			pad3 : byte;
			pad4 : byte;
		      end;
const
      unload_tape_cmd_const = unload_tape_cmd[
			op_code : hex('1B'),
			lunit   : 0,
			pad0    : 0,
			immed   : 0,
			pad1    : 0,
			pad2    : 0,
			pad3    : 0,
			pad4 : 0];

      allow_tape_cmd_const = unload_tape_cmd[
			op_code : hex('1E'),
			lunit   : 0,
			pad0    : 0,
			immed   : 0,
			pad1    : 0,
			pad2    : 0,
			pad3    : 0,
			pad4 : 0];

{ NOTE - locate and space are not the same thing }
type
      locate_tape_cmd = packed record
			op_code : byte;
			lunit_etc   : byte;
			pad1 : byte;
			baddr : integer;
			pad2 : byte;
			partition : byte;
			last : byte;
		      end;

const
      locate_tape_cmd_const = locate_tape_cmd[
			op_code : hex('2B'),
			lunit_etc   : 4,
			pad1 : 0,
			baddr : 0,
			pad2 : 0,
			partition : 0,
			last : 0];

type
      read_block_limits_cmd = packed record
			op_code : byte;
			lunit   : 0..7;
			pad0    : 0..31;
			pad1    : byte;
			pad2    : byte;
			pad3    : byte;
			pad4 : 0..63;
			flag : 0..1;
			link : 0..1;
		      end;

     read_block_limits_data = packed record
			pad0 : byte;
			max_length1 : byte;
			max_length2 : byte;
			max_length3 : byte;
			min_length : s_short;
		      end;
const
     read_block_limits_const = read_block_limits_cmd[
			op_code : hex('05'),
			lunit   : 0,
			pad0    : 0,
			pad1    : 0,
			pad2    : 0,
			pad3    : 0,
			pad4 : 0,
			flag : 0,
			link : 0];

type
      SenseXlateType = packed array [ SenseType ] of iorsltwd;
      InternalXlateType = packed array [ InternalErrType ] of iorsltwd;
const
      SenseXlateConst = SenseXlateType[
		    inoerror,           {sNoSense}
		    inoerror,           {sRecoveredError}
		    znotready,          {sNotReady}
		    zbadblock,          {sMediumError}
		    zbadhardware,       {sHardwareError}
		    zbadmode,           {sIllegalRequest}
		    zmediumchanged,     {sUnitAttention}
		    zprotected,         {sDataProtect}
		    znoblock,           {sBlankCheck}
		    zcatchall,          {sVendor}
		    zcatchall,          {sCopyAbort}
		    znodevice,          {sCommandAbort - only sense with this translation}
		    zcatchall,          {sEqual}
		    znosuchblk,         {sVolumeOverflow}
		    zcatchall,          {sMisCompare}
		    zcatchall,          {sReserved}
		    zbadmode,           {DriverError}
		    zcatchall,          {IllegalStatus}
		    zcatchall];         {GetSenseFailed}

      InternalXlateConst = InternalXlateType[
		    inoerror,           {NoIntErr}
		    zcatchall,          {ScsiStackingErr}
		    zcatchall,          {RunlevelErr}
		    zcatchall,          {StateMachineErr}
		    zstrangei,          {ScsiInteruptErr}
		    znodevice,          {ScsiAddressErr}
		    znodevice,          {SelectRetryErr}
		    zbadhardware,       {ScsiManXferErr}
		    zbadhardware,       {ScsiXferErr}
		    ztimeout,           {XferRetryErr}
		    zcatchall,          {ScsiEscapeErr}
		    zcatchall,          {ScsiPhaseErr}
		    zcatchall,          {ScsiCatastrophicErr}
		    zcatchall,          {ScsiBadMsg}
		    ztimeout,           {ScsiTimeOutErr}
		    zbadmode,           {ScsiXferParmErr}
		    zcatchall];         {ScsiMiscErr}



$IF TDEBUG$
procedure dump_trace(var sb:SessionBlockType);
label 1;
  TYPE

	EventType =     (
			{
			 NOTE: The following event list must match the assembler event
			 list defined in ST_EQU
			}

			{Standard events}
			NoEvent, ScsiErr, WaitForISR,

			{Bus Phase Events, returned by hwiGetPhase}
			BusFree, BusBusy, MsgIn, MsgOut, CmdPhase, DataPhase, StatusPhase,

			{Message In Events}
			Synch, SaveDataPtr, RestorePtrs, Disconnect, CmdComplete,
			Reject, Identify, LCC, LCCwFlag,

			{Establish Path}
			NeedSynchParms,

			{Do a Transfer}
			OriginalPhase
			);




	TRICKYDICKY = RECORD CASE BOOLEAN OF
			TRUE:(S:ST_SHORT);
			FALSE:(B1:CHAR;B2:CHAR;E:EVENTTYPE);
		      END;
  var
    control: control_ptr;
    i : integer;
    nametable : trace_name_table_ptr;
    symbolname: string255;
    T:TRICKYDICKY;
    EVENT:EVENTTYPE;

  function value(symbol: string255): integer;
    var
      modp: moddescptr;
      ptr, valueptr: addrec;
      found: boolean;
    begin {value}
      value := 0;
      found := false;
      modp := sysdefs;
      while (modp<>nil) and not found do
	with modp^ do
	  begin
	    ptr := defaddr;
	    while (ptr.a<defaddr.a+defsize) and not found do
	      begin
		found := ptr.syp^=symbol;
		ptr.a := ptr.a+strlen(ptr.syp^)+1;
		ptr.a := ptr.a+ord(odd(ptr.a));
		valueptr.a := ptr.a+2;
		if found then
		  value := valueptr.vep^.value;
		ptr.a := ptr.a+ptr.gvp^.short;
	      end; {while}
	    modp := link;
	  end; {with modp^}
    end; {value}

  function symbolforaddr(value:integer): string255;
    var
      modp: moddescptr;
      ptr, valueptr: addrec;
      found: boolean;
    begin {value}
      found := false;
      modp := sysdefs;
      while (modp<>nil) and not found do
	with modp^ do
	  begin
	    ptr := defaddr;
	    while (ptr.a<defaddr.a+defsize) and not found do
	      begin
		symbolforaddr:= ptr.syp^;
		ptr.a := ptr.a+strlen(ptr.syp^)+1;
		ptr.a := ptr.a+ord(odd(ptr.a));
		valueptr.a := ptr.a+2;
		found := value = valueptr.vep^.value;
		ptr.a := ptr.a+ptr.gvp^.short;
	      end; {while}
	    modp := link;
	  end; {with modp^}
    end; {symbolforaddr}

  function stateforoffset(value:integer): state_name_string;
    var
      done : boolean;
      i    : integer;
      temp : state_name_string;
    begin
      temp := '';
      strwrite(temp,1,i,value:1);
      stateforoffset := temp;
      i := 1; done := false;
      if nametable<>nil then
	repeat
	  with nametable^[i] do
	  begin
	    if offset=value then
	    begin
	      done:= true;
	      stateforoffset := name;
	    end
	    else
	    if offset=0 then done := true
			     else i := i + 1;
	  end;
	until done;
    end; { stateforoffset}

  begin { dump_trace }
    {REWRITE(LISTING,'#6:');}
    if not sb.DoTrace then
	goto 1;
    control := sb.tracestuff;
    nametable := nil;
    with control^, sb do
    begin
	i := ttotal;
	repeat
		while(i = tremaining) and (sessionstate <> sessioncomplete) do
			;
		with tdata^[i] do
			case data_type of
			tstate:  writeln(listing,'state = ',stateforoffset(short_data));
			tproc:   writeln(listing,'    procedure = ',symbolforaddr(long_data));
			tmachine:begin
				   symbolname := symbolforaddr(long_data);
				   writeln(listing,' machine = ',symbolname);
				   symbolname := symbolname+'_T';
				   nametable := anyptr(value(symbolname));
				 end;
			tevent:  BEGIN
				   T.S := SHORT_DATA;
				   EVENT := T.E;
				   writeln(listing,'    event     = ',EVENT);
				 END;
			end;
		i := i - 1;
	until (i = tremaining) and (sessionstate = sessioncomplete);
    end;
    {CLOSE(LISTING,'SAVE');}
    1:
  end; { dump_trace }
  $end$

procedure IsScsiCard(sc:S_TYPE_ISC; var b:boolean);
begin
	b := (isc_table[sc].card_type = scsi_card);
end;

function GetpMisc(SelectCode:S_TYPE_ISC):PtrMiscTemplateType;
var
	pMisc:PtrMiscTemplateType;
begin
	GetpMisc := NIL;
	with isc_table[SelectCode] do
	begin
		if card_type = scsi_card then
		begin
			pMisc := addr(io_tmp_ptr^.drv_misc[1]);
			{
			  verify that misc block is for real.
			}
			if pMisc^.MiscpScBlock <> NIL then
				GetpMisc := pMisc;
		end;
	end;
end;

procedure ScsiSBSize(var size:integer);
begin
	size := sizeof(SessionBlockType);
end;

procedure ScsiSBInit(pSB:ANYPTR; pDAV:ANYPTR);
var
	i:integer;
	pChar1, pChar2:PtrChar;
begin
	pChar1 := pSB;
	pChar2 := addr(pChar1^, 1);
	pChar1^ := #0;
	moveleft(pChar1^, pChar2^, sizeof(SessionBlockType)-1);
	with PtrSessionBlockType(pSB)^, PtrDeviceAddressVectorsType(pDAV)^ do
	begin
		SelectCode := sc;
		Device     := ba;
		LUN        := du;
		SUN        := dv;
		Overlap    := false;
		DoNotDisconnect := true;
		DoTrace    := false;
	end;
end;


function  RequestSense(pSB:PtrSessionBlockType):SenseType;
var
	SB:SessionBlockType; {save the user's session block}
	rscmd:request_sense_cmd_type;
	prsdata:ptr_request_sense_data_type;
	i:integer;
begin
	RequestSense := GetSenseFailed;

	SB := pSB^;
	with SB do
	begin
		rscmd := request_sense_cmd_const;
		rscmd.lunit := LUN;
		Overlap := FALSE;
		DoNotDisconnect := TRUE;
		with GetpMisc(SelectCode)^ do
		begin
			prsdata := ANYPTR(MiscpSenseSpace);
			i := ScsiHandleSession(addr(SB),
				     addr(rscmd), sizeof(rscmd),
				     prsdata, 255, false,
				     Nil, 0, false);
			if i = ord(inoerror) then
			begin
				MiscSenseLength := 255 - ResidualCount;
				with prsdata^ do
				begin
					if (e_class = 7) and (e_code = 0) then
						RequestSense := SenseType(sensekey);
				end;
			end;
		end;
	end;
end;

function ScsiHandleSession(pSB:PtrSessionBlockType;
			pCmd:ANYPTR; lCmd:integer;
			pDIn:ANYPTR; lDIn:integer; DMAIn:Boolean;
			pDOut:ANYPTR; lDOut:integer; DMAOut:Boolean):integer;
label 1;
var
	OkToCall:BOOLEAN;
	AbortCommandRetry:integer;
	i:integer;
	$IF DEBUG$
		C:CHAR;
	$END$
begin
	with pSB^ do
	begin
	try
		AbortCommandRetry := 0;
		1:
		CmdPtr := pCmd;
		CmdLen := lCmd;
		with BufIn do
		begin
			BufPtr := pDIn;
			BufLen := lDIn;
			DoDma  := DMAIn;
		end;
		with BufOut do
		begin
			BufPtr := pDOut;
			BufLen := lDOut;
			DoDma  := DMAOut;
		end;
		InternalStatus := NoIntErr ;
		SessionStatus := 0;
		ResidualCount := 0;
		{ $IF DEBUG$
		{         C := CHARPTR(PCMD)^;
		{          WRITELN; WRITELN('SCSI COMMAND IS: ',ord(c):1);
		{  $END$
		{}
		OkToCall := (GetpMisc(SelectCode) <> Nil);
		if not OkToCall then
			escape(0);
		call(isc_table[SelectCode].io_drv_ptr^.iod_tfr, nil, pSB);
		if not Overlap then
		begin
			i := ScsiCheckError(pSB);
			if (i = ord(znodevice)) and ((InternalStatus = NoIntErr)) then
			begin
				{sense was sCommandAbort}
				if AbortCommandRetry < 1 then
				begin
					$IF DEBUG$
						WRITELN('Retrying because of aborted command.');
					$END$

					AbortCommandRetry := AbortCommandRetry + 1;
					goto 1;
				end;
			end;
			ScsiHandleSession := i;
		end
		else
			ScsiHandleSession := ord(inoerror);
	recover
	begin
		if NOT OkToCall then
		begin
			SessionState := SessionComplete;
			InternalStatus := ScsiAddressErr;
			if not Overlap then
				ScsiHandleSession := ScsiCheckError(pSB)
			else
				ScsiHandleSession := ord(inoerror);
		end
		else
			escape(escapecode);
	end;
	end;
end;

function ScsiSessionComplete(pSB:PtrSessionBlockType):BOOLEAN;
begin
	ScsiSessionComplete := (pSB^.SessionState = SessionComplete);
end;

function ScsiCheckError(   pSB:PtrSessionBlockType):integer;
var
	status:status_type;
	sense:SenseType;
	$IF DEBUG OR TDEBUG$
		C:CHAR;
	$END$
begin
	with pSB^ do
	begin
		$IF DEBUG OR TDEBUG$
			C := CHARPTR(CmdPtr)^;
		$END$
		if SessionState <> SessionComplete then
			ScsiCheckError := ord(inoerror)
		else if InternalStatus <> NoIntErr then
		begin
			$IF DEBUG$
				WRITELN('DRIVER ERROR: ', INTERNALSTATUS);
				WRITELN('SCSI COMMAND IS: ',ord(c):1);
				{}
			$END$
			$IF TDEBUG$
			if (ord(charptr(CmdPtr)^) <> 0) then
			begin
				writeln(listing);
				writeln(listing, '----------------------------------------');
				writeln(listing, 'TRACE FOR SCSI COMMAND: ',ord(c):1);
				writeln(listing, '----------------------------------------');
				dump_trace(pSB^);
			end;
			$END$
			ScsiCheckError := Ord(InternalXlateConst[InternalStatus]);
		end
		else if SessionStatus <> 0 then
		begin
			$IF DEBUG$
				WRITELN('BAD SESSION STATUS: ', SessionStatus:1);
				WRITELN('SCSI COMMAND IS: ',ord(c):1);
				{}
			$END$
			status.b := SessionStatus;
			if (status.stat <> 0) then
			begin
				if (status.stat = 1) then
				begin
					if CharPtr(CmdPtr)^ <> #3 {request_sense} then
					begin
						$IF DEBUG$
						  writeln('Calling Request Sense.');
						$END$
						sense := RequestSense(pSB);
					end
					else
					begin
						$IF DEBUG$
						  writeln('Request Sense Failed!.');
						$END$
						sense := GetSenseFailed;
					end;
				end
				else if (status.stat = 4) then
				begin
					$IF DEBUG$
					  writeln('Sense is sNotReady.');
					$END$
					sense := sNotReady
				end
				else
				begin
					$IF DEBUG$
					  writeln('Illegal status.');
					$END$
					sense := IllegalStatus;
				end;
				$IF DEBUG$
					WRITELN('BAD SESSION SENSE: ', SENSE);
					WRITELN('SCSI COMMAND IS: ',ord(c):1);
					{}
				$END$
				ScsiCheckError := ord(SenseXlateConst[sense]);
			end
			else {Good Status}
				ScsiCheckError := ord(inoerror);
		end
		else {Good Status}
			ScsiCheckError := ord(inoerror);
	end;
end;


procedure ScsiSessionSense( SelectCode:S_TYPE_ISC;
			    pBuf:ANYPTR;
			var Length:integer);
var
	pMisc:PtrMiscTemplateType;
begin
	pMisc := GetpMisc(SelectCode);
	if pMisc <> Nil then
	with pMisc^ do
	begin
		if Length > MiscSenseLength then
			Length := MiscSenseLength;
		moveleft(MiscpSenseSpace^, PtrChar(pBuf)^, Length);
	end
	else
		Length := 0;
end;

procedure ScsiSessionAbort(pSB:PtrSessionBlockType);
begin
	with pSB^ do
	begin
		if (Overlap) and (SessionState = SessionRunning) then
			call(isc_table[SelectCode].io_drv_ptr^.iod_tfr, ANYPTR(1), pSB);
	end;
end;

procedure ScsiReset(        SelectCode:S_TYPE_ISC);
var
	i:integer;
begin
	i := SelectCode;
	call(isc_table[SelectCode].io_drv_ptr^.iod_tfr, ANYPTR(2), ANYPTR(i));
end;

{======================================================================}
function ChangeTapePosition(pSB:PtrSessionBlockType;
			     newpos : integer) : integer;
var ltpcmd : locate_tape_cmd;
    iotemp : integer;

begin
 ltpcmd := locate_tape_cmd_const;
 ltpcmd.baddr := newpos;
 iotemp := 0;
 iotemp := ScsiHandleSession(pSB,
		     addr(ltpcmd), sizeof(ltpcmd),
		     NIL, 0, false,
		     nil, 0, false);
 if iotemp <> 0 then { allow one retry }
    iotemp := ScsiHandleSession(pSB,
		     addr(ltpcmd), sizeof(ltpcmd),
		     NIL, 0, false,
		     nil, 0, false);
 ChangeTapePosition := iotemp;
end;
{======================================================================}
procedure ScsiTapeUnload(pDAV : PtrDeviceAddressVectorsType);
var SB : SessionBlockType;
   pSB : PtrSessionBlockType;
   utcmd : unload_tape_cmd; iotemp, saveior : integer;
begin
   saveior := ioresult;

   pSB := addr(SB); ScsiSBInit(pSB,pDAV);

   { Allow it to be unloaded : }

   utcmd := allow_tape_cmd_const;
   iotemp := ScsiHandleSession(pSB,
		     addr(utcmd), sizeof(utcmd),
		     NIL, 0, false,
		     NIL, 0, false );

   if iotemp <> 0 then { try once more }
	  iotemp := ScsiHandleSession(pSB,
		     addr(utcmd), sizeof(utcmd),
		     NIL, 0, false,
		     NIL, 0, false );

   { .. Then, unload it : }

   utcmd := unload_tape_cmd_const;
   utcmd.immed := 1;
   iotemp := ScsiHandleSession(pSB,
		     addr(utcmd), sizeof(utcmd),
		     NIL, 0, false,
		     NIL, 0, false );

   if iotemp <> 0 then { try once more }
       iotemp := ScsiHandleSession(pSB,
		     addr(utcmd), sizeof(utcmd),
		     NIL, 0, false,
		     NIL, 0, false );
  ioresult := saveior;
end;
{=======================================================================}
function ReadTapePosition(pSB:PtrSessionBlockType;
			   var where : integer) : integer;

var rtpcmd : read_tape_position;
    rtpdata : tape_position_data_type;
    iotemp : integer;

begin

 rtpcmd := read_tape_position_const;
 iotemp := 0;
 iotemp := ScsiHandleSession(pSB,
		     addr(rtpcmd), sizeof(rtpcmd),
		     addr(rtpdata), sizeof(rtpdata), false,
		     NIL, 0, false );
 if iotemp <> 0 then { one retry }
     iotemp := ScsiHandleSession(pSB,
		     addr(rtpcmd), sizeof(rtpcmd),
		     addr(rtpdata), sizeof(rtpdata), false,
		     NIL, 0, false );

 if iotemp = 0 then
   where := rtpdata.first
 else
   where := -1;
 ReadTapePosition := iotemp;

end;
{======================================================================}
procedure ScsiTapeRead( pSB:PtrSessionBlockType;
			BlockStart, NumBlocks, NumBytesBlock:integer;
			Buffer:ANYPTR);
label 100;
var
	rtcmd:read_tape_cmd_type;
	tries,remaining :integer;
	current_location : integer;
	iotemp : integer;
begin



      iotemp := 0;
      if NumBlocks > 0 then
       begin

    { Make sure the tape is in the correct spot before reading ... }

	iotemp := ReadTapePosition(pSB,current_location);
	if iotemp <> 0 then
	  begin ioresult := iotemp; goto 100; end;

	if current_location <> BlockStart then
	  iotemp := ChangeTapePosition(pSB, BlockStart );
	if iotemp <> 0 then
	 begin  ioresult := iotemp; goto 100; end;

       end;


     { Set up the command correctly ... }

     rtcmd := read_tape_cmd_const;

      rtcmd.xferlen1 := NumBlocks DIV 65536;
      remaining := NumBlocks MOD 65536;
      rtcmd.xferlen2 := remaining DIV 256;
      rtcmd.xferlen3 := remaining MOD 256;

	with pSB^ do
		if Overlap then
			ioresult := ord(zbadmode)
		else
		begin
			tries := 0;
			repeat
				tries := tries + 1;
				ioresult   := ScsiHandleSession(pSB,
						 addr(rtcmd), sizeof(rtcmd),
						 Buffer,
						 NumBlocks*NumBytesBlock, true,
						 Nil, 0, false);
			until (ioresult <> ord(zbadblock)) or (tries >= 2);
		end;
100:
end;

{======================================================================}
procedure ScsiTapeWrite(pSB:PtrSessionBlockType;
			BlockStart, NumBlocks, NumBytesBlock:integer;
			Buffer:ANYPTR);
label 100;
var
	wtcmd:write_tape_cmd_type;
	current_location : integer;
	tries,iotemp,remaining : integer;
	wrsense : SenseType;
	addlsense : integer;
begin

      iotemp := 0;
      if NumBlocks > 0 then
       begin

    { Make sure the tape is in the correct spot before writing ... }

	iotemp := ReadTapePosition(pSB,current_location);
	if iotemp <> 0 then
	  begin ioresult := iotemp; goto 100; end;

	if current_location <> BlockStart then
	  iotemp := ChangeTapePosition(pSB, BlockStart );
	if iotemp <> 0 then
	 begin  ioresult := iotemp; goto 100; end;

       end;



      wtcmd := write_tape_cmd_const;

      wtcmd.xferlen1 := NumBlocks DIV 65536;
      remaining := NumBlocks MOD 65536;
      wtcmd.xferlen2 := remaining DIV 256;
      wtcmd.xferlen3 := remaining MOD 256;

	with pSB^ do
		if Overlap then
			ioresult := ord(zbadmode)
		else
		begin
			tries := 0;
			repeat
				tries := tries + 1;
				ioresult   := ScsiHandleSession(pSB,
						   addr(wtcmd), sizeof(wtcmd),
						   Nil, 0, false,
						   Buffer,
						   NumBlocks*NumBytesBlock,
						   true);
			until (ioresult <> ord(zbadblock)) or (tries >= 2);
		end;
100:


    { status = 2 and sense = sNoSense means we are near the }
    { end of the tape. }

  { if pSB^.SessionStatus = 2 then
    begin
     writeln('near the end, ioresult is set to 1 ...');
     ioresult := 1;
    end;
  }
end;

{======================================================================}
procedure ScsiModeSense(pSB:PtrSessionBlockType;
			pDB : PtrModeSenseDataType ;
			var sector_size : integer);
 type tricky_as_hell = record
     case boolean of
     FALSE: (i : integer);
     TRUE:  (c1,c2,c3,c4 : char);
  end;

 var mscmd : mode_sense_cmd_type;
     msdata : mode_sense_data_type;
     iotemp : integer;
     grab_it : tricky_as_hell;

 { Makes a call to ScsiHandleSession to query the controller }
begin
  grab_it.i := 0;
  mscmd := mode_sense_cmd_const;
  mscmd.lunit := pSB^.LUN;
  iotemp := ScsiHandleSession(pSB,
			      addr(mscmd), sizeof(mscmd),
			      pDB, { addr(msdata),} sizeof(msdata), false,
			      nil, 0, false);

  if iotemp <> 0 then { allow one retry }
    iotemp := ScsiHandleSession(pSB,
			      addr(mscmd), sizeof(mscmd),
			      pDB, { addr(msdata),} sizeof(msdata), false,
			      nil, 0, false);
  if iotemp = 0 then
    begin
     grab_it.c2 := pDB^.ms_data[5];
     grab_it.c3 := pDB^.ms_data[6];
     grab_it.c4 := pDB^.ms_data[7];
     sector_size := grab_it.i;
   end
  else
    sector_size := 666; { sector from HELL  !!!! }
end;
{======================================================================}
procedure InitModeSense(pSB:PtrSessionBlockType;
			pDB : PtrModeSenseDataType ;
			var sector_size : integer);
 type tricky_as_hell = record
     case boolean of
     FALSE: (i : integer);
     TRUE:  (c1,c2,c3,c4 : char);
  end;

 var mscmd : mode_sense_cmd_type;
     msdata : mode_sense_data_type;
     iotemp : integer;
     grab_it : tricky_as_hell;
     my_ptr : ^mode_sense_data_type;

 { Makes a call to ScsiHandleSession to query the controller }
begin
  grab_it.i := 0;
  mscmd := mode_sense_cmd_const;
  mscmd.lunit := pSB^.LUN;
  iotemp := ScsiHandleSession(pSB,
			      addr(mscmd), sizeof(mscmd),
			      pDB, { addr(msdata),} sizeof(msdata), false,
			      nil, 0, false);

  if iotemp <> 0 then { allow one retry }
    iotemp := ScsiHandleSession(pSB,
			      addr(mscmd), sizeof(mscmd),
			      pDB, { addr(msdata),} sizeof(msdata), false,
			      nil, 0, false);
  if iotemp = 0 then
    begin
     my_ptr := anyptr(pDB);
     grab_it.c2 := my_ptr^.ms_data[5];
     grab_it.c3 := my_ptr^.ms_data[6];
     grab_it.c4 := my_ptr^.ms_data[7];
     sector_size := grab_it.i;
   end
  else
    sector_size := 666; { sector from HELL  !!!! }
  if iotemp <> 0 then
     ioresult := iotemp; { ?????????? }
end;

{======================================================================}
procedure InitModeSelect(pSB:PtrSessionBlockType;
			 pDB : PtrModeSelectDataType;
			 sector_size : integer;
			 cylinders : integer);
 type tricky_as_hell = record
     case boolean of
     FALSE: (i : integer);
     TRUE:  (c1,c2,c3,c4 : char);
  end;
 var mscmd : mode_select_cmd_type;
     msdata : mode_select_data_type;
     iotemp : integer;
     cram_it : tricky_as_hell;
     brute_force : packed array [0..255] of char;
     counter : integer;
begin

     for counter := 0 to 31 do
       pDB^.ms_data[counter] := pDB^.ms_data[counter+16]; { shift down }

     mscmd := mode_select_cmd_const;
     pDB^.ms_data[0] := chr(5);  { JAB said so }
     pDB^.ms_data[8] := chr(0);
     pDB^.ms_data[9] := chr(cylinders);  { 77 or 80 cylinders }

     cram_it.i := sector_size;
     pDB^.ms_data[6] := cram_it.c3;
     pDB^.ms_data[7] := cram_it.c4;

     pDB^.ms_len := 0;
     pDB^.wp := false;
     pDB^.rsvd1 := 0;
     pDB^.medtype := 0;
     pDB^.bd_len := 0;


     mscmd.lunit := pSB^.LUN;
     mscmd.reqlen := 36;

     iotemp := ScsiHandleSession(pSB,
			      addr(mscmd), sizeof(mscmd),
			      { addr(msdata)} nil, 0, {sizeof(msdata), }
				    false,
			      pDB, 36 {sizeof(msdata)} , false);

     IF IOTEMP <> 0 THEN  { allow one re-try }
	iotemp := ScsiHandleSession(pSB,
			      addr(mscmd), sizeof(mscmd),
			      { addr(msdata)} nil, 0, {sizeof(msdata), }
				    false,
			      pDB, 36 {sizeof(msdata)} , false);

     if iotemp <> 0 then
	ioresult := iotemp; { ?????????? }
end;
{==========================================================================}


{======================================================================}
procedure ScsiModeSelect(pSB:PtrSessionBlockType;
			 pDB : PtrModeSelectDataType;
			 sector_size : integer);
 type tricky_as_hell = record
     case boolean of
     FALSE: (i : integer);
     TRUE:  (c1,c2,c3,c4 : char);
  end;
 var mscmd : mode_select_cmd_type;
     msdata : mode_select_data_type;
     iotemp : integer;
     cram_it : tricky_as_hell;
     brute_force : packed array [0..255] of char;
begin
     mscmd := mode_select_cmd_const;
     cram_it.i := sector_size;
     pDB^.ms_data[5] := cram_it.c2;
     pDB^.ms_data[6] := cram_it.c3;
     pDB^.ms_data[7] := cram_it.c4;

     pDB^.ms_data[1] := chr(0);
     pDB^.ms_data[2] := chr(0);
     pDB^.ms_data[3] := chr(0);

     pDB^.ms_len := 0;
     pDB^.wp := false;
     pDB^.rsvd1 := 0;
     pDB^.medtype := 0;

     mscmd.lunit := pSB^.LUN;
     iotemp := ScsiHandleSession(pSB,
			      addr(mscmd), sizeof(mscmd),
			      { addr(msdata)} nil, 0, {sizeof(msdata), }
				    false,
			      pDB, 12 {sizeof(msdata)} , false);

     IF IOTEMP <> 0 THEN  { allow one re-try }
	iotemp := ScsiHandleSession(pSB,
			      addr(mscmd), sizeof(mscmd),
			      { addr(msdata)} nil, 0, {sizeof(msdata), }
				    false,
			      pDB, 12 {sizeof(msdata)} , false);

     if iotemp <> 0 then
	ioresult := iotemp; { ?????????? }
end;
{==========================================================================}
procedure ScsiDiscReadOnce( pSB:PtrSessionBlockType;
			BlockStart, NumBlocks, NumBytesBlock:integer;
			Buffer:ANYPTR);
var
	rcmd:read_cmd_type;
	tries:integer;
begin
	with pSB^ do
		if Overlap then
			ioresult := ord(zbadmode)
		else
		begin
			tries := 1;
			repeat
				tries := tries + 1;
				rcmd := read_cmd_const;
				rcmd.lunit := LUN;
				rcmd.block_n := BlockStart;
				rcmd.lmsb  := NumBlocks div Hex('100');
				rcmd.llsb  := NumBlocks mod Hex('100');
				ioresult   := ScsiHandleSession(pSB,
						   addr(rcmd), sizeof(rcmd),
						   Buffer, NumBlocks*NumBytesBlock, true,
						   Nil, 0, false);
			until (ioresult <> ord(zbadblock)) or (tries >= 2);
		end;
end;

{=================================================================}
procedure McBethSelect(pSB:PtrSessionBlockType;
			 pDB : PtrModeSelectDataType;
			 var success : integer);
 type tricky_as_hell = record
     case boolean of
     FALSE: (i : integer);
     TRUE:  (c1,c2,c3,c4 : char);
  end;
 var mscmd : mode_select_cmd_type;
     msdata : mode_select_data_type;
     iotemp : integer;
     cram_it : tricky_as_hell;
     brute_force : packed array [0..255] of char;
begin
     mscmd := mode_select_cmd_const;
     mscmd.reqlen := 28;
     mscmd.pf := 1;

     iotemp := ScsiHandleSession(pSB,
			      addr(mscmd), sizeof(mscmd),
			      { addr(msdata)} nil, 0, {sizeof(msdata), }
				    false,
			      pDB, 28 {sizeof(msdata)} , false);

     IF IOTEMP <> 0 THEN  { allow one re-try }
	iotemp := ScsiHandleSession(pSB,
			      addr(mscmd), sizeof(mscmd),
			      { addr(msdata)} nil, 0, {sizeof(msdata), }
				    false,
			      pDB, 28 {sizeof(msdata)} , false);

     if iotemp <> 0 then
	ioresult := iotemp; { ?????????? }

     success := iotemp;

end;

{================================================================}
{ If valid media in the drive return 0 else return 1 }
function SyncMcBeth(pSB : PtrSessionBlockType) : integer;
label 100;
var
  fake_buffer : packed array[0..4095] of char;
  iotemp, saveior : integer;
  utcmd : unload_tape_cmd;
begin
  saveior := ioresult;
  SyncMcBeth := 0;

   utcmd := allow_tape_cmd_const;
   utcmd.op_code := hex('01'); { change it to a rewind command }

   iotemp := ScsiHandleSession(pSB,
		     addr(utcmd), sizeof(utcmd),
		     NIL, 0, false,
		     NIL, 0, false );


   if iotemp <> 0 then { try once more }
	  iotemp := ScsiHandleSession(pSB,
		     addr(utcmd), sizeof(utcmd),
		     NIL, 0, false,
		     NIL, 0, false );

    if iotemp = 0 then goto 100;

    SyncMcBeth := 1; { media not present in drive }

100:
  ioresult := saveior;
end;
{================================================================}
{ called from CTABLE. set McBeth parameters for use with the PaWS }
{ BACKUP utility. JWH 6/93 }

procedure ConfigureMcBeth(pSB : PtrSessionBlockType);
var
    data_block : mode_sense_data_type;
    iotemp, saveior, errval  : integer;
begin

  saveior := ioresult;
  ioresult := 0;

  { Get the current configuration from the drive : }
  ScsiModeSense(pSB,ADDR(data_block),errval);

  { Adjust the size of fixed blocks to 65536 bytes : }
  data_block.ms_len := 0; { a requirement }
  data_block.ms_data[5] := chr(1); { set fixed block size to 64k }
  data_block.ms_data[6] := chr(0); { set fixed block size to 64k }
  data_block.ms_data[7] := chr(0); { set fixed block size to 64k }

  { Set it to what you want : }
  McBethSelect(pSB,ADDR(data_block),errval);

  ioresult := saveior; { RESTORE PREVIOUS IORESULT }
end;
{================================================================}
procedure TapeName ( uep : uep_type; var i : string80 ) ;

var SB : SessionBlockType;
   pSB : PtrSessionBlockType;
   DAV : DeviceAddressVectorsType;
   pDAV : PtrDeviceAddressVectorsType;
   iotemp, saveior, devtype, ver  : integer;
   moveable : boolean;
   vstring : string255;
begin
   saveior := ioresult;

   pSB := addr(SB); pDAV := addr(DAV);
   DAV.sc := uep^.sc;
   DAV.ba := uep^.ba;
   DAV.du := 0; DAV.dv := 0;

   ScsiSBInit(pSB,pDAV);

   ScsiDevInfo(pSB,devtype,ver,moveable,vstring);
   i := vstring;

  ioresult := saveior;
end;

{================================================================}
procedure SyncTeac(pSB : PtrSessionBlockType);
var sense_size : integer;
    data_block : mode_sense_data_type;

    fake_buffer : packed array[0..2047] of char; { big enough for what we do }
    real_buf : BufferBlockType;

    save_first : integer;
    read_worked : boolean;
    done : boolean;
    cylinders_should_be : integer;
    test_block : integer;
    saved_cylinders : integer;
    TEMPIOR : integer;
    saveior : integer;
    maxbytes_should_be : integer;
    high_density : boolean;
    i,j,scode,baddr,dunit : byte;

begin
  saveior := ioresult;
  ioresult := 0;
  read_worked := FALSE;
  done := false;

  real_buf.BufPtr := addr(fake_buffer);
  real_buf.BufLen := 4;
  real_buf.DoDMA := FALSE;

  scode := pSB^.SelectCode;
  baddr := pSB^.Device;
  dunit := pSB^.LUN;
  high_density := FALSE;
  maxbytes_should_be := 0;

{*********************************************************************}
{ Temporarily knock out HFS unit(s) associated with the TEAC }
{ Put it (them) back below - if appropriate. }

   if (h_unitable <> NIL) then
    for i := 1 to maxunit do
     begin
      with unitable^[i] do
       if ((sc = scode) and (baddr = ba) and (dunit = du)) then
	begin
	 with h_unitable^.tbl[i] do
	  if is_hfsunit then
	   begin
	    call(h_unitable^.inval_cache_proc,i);
	    umaxbytes := 0;
	   end;
	end;
     end;
{*********************************************************************}

  { Find out what the controller thinks the sector size is : }

  ScsiModeSense(pSB,ADDR(data_block),sense_size);
  cylinders_should_be := ord(data_block.ms_data[25]);

  if sense_size = 666 then { mode sense did not work }
    begin
     tempior := ioresult;
     { writeln('WARNING - SCSI MODE SENSE FAILURE'); }
     done := TRUE; { just quit }
     ioresult := tempior;
    end;

  save_first := sense_size;


  while not done do
   begin

    ioresult := 0;
    ScsiDiscReadOnce(pSB,0,1,sense_size,addr(real_buf));

    if ioresult = 0 then
     begin
      read_worked := TRUE;
      done := TRUE; { now in sync }
    end;

   if ioresult = 1 then   { Read Failure }
    begin

      { vary the sector size and then try again , until
	we read successfully or we try all 3 possible
	sizes }

      if sense_size = 256 then sense_size := 1024
      else if sense_size = 1024 then sense_size := 512
      else if sense_size = 512 then sense_size := 256
      else done := TRUE; { should never happen but ... just quit }

      if not done then
	begin
	 { WRITELN('SECTOR SIZE ADJUST - CYLINDERS : ',cylinders_should_be); }
	 ioresult := 0; { reset it first }
	 InitModeSelect(pSB,addr(data_block),sense_size,
			cylinders_should_be);
	 if ioresult <> 0 then { mode select failed - just quit }
	  begin
	   tempior := ioresult;
	   { writeln('WARNING - SCSI MODE SELECT FAILURE'); }
	   done := TRUE;
	   ioresult := tempior;
	  end;
	end; { if not done }

     end { if ioresult = 1 }
    else
	{ if read failed with something not -1, there are other problems.
	  just fall through and do nothing }
	   done := TRUE;   { just give up }

      if sense_size = save_first then done := TRUE; { tried them all }
      if not done then
	  ScsiModeSense(pSB,ADDR(data_block),sense_size);

  end; { while not done }


     if read_worked then { Pascal Workstation Only }
      begin
	{ WRITELN('READ WORKED - ADJUSTING CYLINDER COUNT'); }


{******************************************************************}
   for i := 1 to maxunit do
    begin
     with unitable^[i] do
      if ((sc = scode) and (baddr = ba) and (dunit = du)) then
	dvrtemp := sense_size;
    end;
{******************************************************************}

       ScsiModeSense(pSB,ADDR(data_block),sense_size);

       if sense_size <> 666 then
	begin
	 SAVED_CYLINDERS := ord(data_block.ms_data[25]);
	 { WRITELN('MODE SENSE - SENSE SIZE  : ',SENSE_SIZE);
	 writeln;
	 writeln;
	 writeln;
	 writeln;
	 WRITELN('MODE SENSE - SAVED CYLINDERS : ',saved_cylinders); }

{*******************************************************************}
	 if data_block.medtype = 136 then
	   high_density := TRUE;
{*******************************************************************}

	{ make sure cylinders = 77 or 80 depending ... }
	 if sense_size = 512 then
	   begin { could be 77 or 80 ? }

	    if data_block.medtype = 128 then { medium density }
	     begin
	      { WRITELN('GOT MEDIUM DENSITY <<<<<<<<<<<<<<<<'); }
	      ioresult := 0;
	      test_block := 1390; { in cylinder 78 }

	      { controller has to think 80 before this test : }
	      if SAVED_CYLINDERS  <> 80 then
		InitModeSelect(pSB,ADDR(data_block),sense_size,80);

	      ScsiDiscReadOnce(pSB,test_block,1,sense_size,addr(real_buf));
	      { IF IORESULT <> 0 THEN
	       BEGIN
		ioresult := 0;
		ScsiDiscReadOnce(pSB,test_block,1,sense_size,addr(real_buf));
	       END; }

	      if ioresult <> 0 then
	       begin
		{ writeln('read failed from ',test_block); }
		cylinders_should_be := 77;
	       end
	      else
	       BEGIN
		{ writeln('read worked from ',test_block); }
		cylinders_should_be := 80;
	       end;
	    end; { medtype = 128 }

	    if data_block.medtype = 136 then { HIGH density }
	     begin
	      { WRITELN('GOT HIGH DENSITY <<<<<<<<<<<<<<<<'); }
	      ioresult := 0;
	      test_block := 2860; { in cylinder 78 }

	      { controller has to think 80 before this test : }
	      if SAVED_CYLINDERS  <> 80 then
		InitModeSelect(pSB,ADDR(data_block),sense_size,80);

	      ScsiDiscReadOnce(pSB,test_block,1,sense_size,addr(real_buf));
	      { IF IORESULT <> 0 THEN
	       BEGIN
		ioresult := 0;
		ScsiDiscReadOnce(pSB,test_block,1,sense_size,addr(real_buf));
	       END; }

	      if ioresult <> 0 then
	       begin
		{ writeln('read failed from ',test_block); }
		cylinders_should_be := 77;
	       end
	      else
	       BEGIN
		{ writeln('read worked from ',test_block); }
		cylinders_should_be := 80;
	       end;
	    end; { medtype = 136 }

	   end { SENSE SIZE = 512 }

      ELSE { not 512 byte sectors }
	begin
	 cylinders_should_be := 77;
	 { writeln('NOT 512 - setting to 77'); }
	end;

     { writeln; writeln; writeln; writeln; }
    ScsiModeSense(pSB,ADDR(data_block),sense_size);
    { tempior := ioresult;
    if ioresult <> 0 then
      writeln('MODE SENSE FAILED AT : ',sense_size)
    ELSE
      writeln('mode sense worked at : ',sense_size);
    ioresult := tempior; }

    SAVED_CYLINDERS := ord(data_block.ms_data[25]);

    { if saved_cylinders  <> cylinders_should_be then
     begin }
      { writeln('mode select - changing cylinders to : ',cylinders_should_be); }
      InitModeSelect(pSB,ADDR(data_block),sense_size,
		      cylinders_should_be);
      { if ioresult <> 0 then
       begin
	tempior := ioresult;
	writeln('WARNING - MODE SELECT FAILURE');
	ioresult := tempior;
       end
      else
	writeln('MODE SELECT SUCCESSFUL TO : ',sense_size,' ',cylinders_should_be); }
     { end
     else
    writeln('mode select not called - cylinders : ',cylinders_should_be); }
   end;
   { WRITELN('end OF READ_WORKED'); }

{*********************************************************************}
     case sense_size of
       256 : maxbytes_should_be := 630784;
       1024: maxbytes_should_be := 788480;
       512: if cylinders_should_be = 77 then
	      maxbytes_should_be := 709632
	    else
	      maxbytes_should_be := 737280;
       otherwise
	     begin { should never happen }
	       maxbytes_should_be := 630784; { ????? }
	     end;
     end;
     if high_density then
	maxbytes_should_be := 2*maxbytes_should_be;

     if (h_unitable <> NIL) then
      for i := 1 to maxunit do
      begin
       with unitable^[i] do
	if ((sc = scode) and (ba = baddr) and (du = dunit)) then
	  if h_unitable^.tbl[i].is_hfsunit then
	   begin
	    umaxbytes := maxbytes_should_be;
	    call(dam,uvid,i,getvolumename);
	    if ((ioresult <> ord(inoerror)) or (strlen(uvid) = 0)) then
	       umaxbytes := 0; { knock this unit out }
	    { update umaxbytes for any friends that this unit has }
	    for j := 1 to i-1 do
	     begin
	      with unitable^[j] do
	       if ((sc = scode) and (ba = baddr) and (du = dunit)) then
		 umaxbytes := maxbytes_should_be;
	     end;
	    for j := i+1 to maxunit do
	     begin
	      with unitable^[j] do
	       if ((sc = scode) and (ba = baddr) and (du = dunit)) then
		 umaxbytes := maxbytes_should_be;
	     end;
	  end;
      end;

 {*********************************************************************}
 end; { read worked }
     ioresult := saveior; { RESTORE PREVIOUS IORESULT }
end; { procedure sync_teac }


procedure ScsiDevInfo(  pSB:PtrSessionBlockType;
			var DevType, AnsiVersion:integer;
			var Removable:boolean;
			var VendorString:string255);
var
	icmd:inquiry_cmd_type;
	idata:inquiry_data_type;
	len:integer;
	s1, s2:string255;
begin
	with pSB^ do
		if Overlap then
			ioresult := ord(zbadmode)
		else
		begin
			icmd := inquiry_cmd_const;
			icmd.lunit := LUN;
			ioresult := ScsiHandleSession(pSB,
						  addr(icmd), sizeof(icmd),
						  addr(idata), sizeof(idata), false,
						  Nil, 0, false);
		end;

	s1 := '<indeterminate SCSI device>';
	setstrlen(s2, 0);
	if ioresult = ORD(inoerror) then
	begin
		DevType := idata.device_type;
		AnsiVersion := idata.ansi_version;
		Removable := idata.rmb;

		len := idata.vendlen;
		if len >= 3 then
			len := len - 3
		else
			len := 0;
		if (len > 0) then
		begin
			if len >= 8 then {get the vendor name}
			begin
				s1 := strrtrim(str(idata.vendor, 4, 8));
				len := len - 8;
			end
			else
				len := 0;

			if len > 16 then
				len := 16;

			if len > 0 then {get the product number}
			begin
				s2 := strrtrim(str(idata.vendor, 4+8, len));
				len := 0;
			end;
		end;
	end;

	if strlen(s2) > 0 then
		VendorString := s1 + '-' + s2
	else
		VendorString := s1;
end;


procedure ScsiCheckDev(    pSB:PtrSessionBlockType);
var
	tcmd:test_cmd_type;
	devtype, ver : integer;
	moveable : boolean;
	vstring : STRING255;
begin
	with pSB^ do
		if Overlap then
			ioresult := ord(zbadmode)
		else
		begin
			tcmd := test_cmd_const;
			tcmd.lunit := LUN;
			ioresult := ScsiHandleSession(pSB,
						  addr(tcmd), sizeof(tcmd),
						  Nil, 0, false,
						  Nil, 0, false);


			if ioresult = ord(zmediumchanged) then
			 begin
			     VSTRING := 'xxxx';
			     ScsiDevInfo(pSB,devtype,ver,moveable,vstring);
			      IF ((vstring[1] = 'T') and (vstring[2] = 'E')
				 and (vstring[3] = 'A') and (vstring[4] = 'C'))
				 then  syncteac(pSB)  ;
			  ioresult := ord(zmediumchanged);
			 end;


		end;
end;



procedure ScsiDiscSize( pSB:PtrSessionBlockType;
			var NumBytesBlock, NumBlocksTrack,
			    NumTracksCylinder, NumCylinders:integer);
var
	rccmd:read_capacity_cmd_type;
	rcdata:read_capacity_data_type;
	mscmd:mode_sense_cmd_type;
	msdata:mode_sense_data_type;
	i,iotemp:integer;
	NumBlocks, TotBytes, NumBytesTrack:integer;
	Page4Found:boolean;
	pPage:pPageType;
	TotLen:integer;

	devtype, ver : integer;
	moveable,have_teac  : boolean;
	vstring : STRING255;

begin
	ioresult := ord(inoerror);
	try
		with pSB^ do
			if Overlap then
			begin
				iotemp := ord(zbadmode);
				escape(-10);
			end
			else
			begin
				rccmd := read_capacity_cmd_const;
				rccmd.lunit := LUN;
			end;
		{
		  get the disk capacity and the number of sectors per track.
		  If unable to obtain the sectors per track, then use
		  the following table:

			0 -   8 Meg =  4Ksectors/track
			8 - 128 Meg =  8Ksectors/track
		      128 - 256 Meg = 16
		      256+          = 32
		}

			     VSTRING := 'xxxx';
			     have_teac := FALSE;
			     ScsiDevInfo(pSB,devtype,ver,moveable,vstring);
			       if strlen(vstring) >= 4 then
				 IF ((vstring[1] = 'T') and (vstring[2] = 'E')
				 and (vstring[3] = 'A') and (vstring[4] = 'C'))
				 then begin
					have_teac := TRUE;
					syncteac(pSB);
					end;

		for i := 1 to 2 do
		begin
			iotemp := ScsiHandleSession(pSB,
						addr(rccmd), sizeof(rccmd),
						addr(rcdata), sizeof(rcdata), false,
						nil, 0, false);

			if iotemp = ord(inoerror) then
			begin
				if i = 1 then
				begin
					NumBlocks := rcdata.block_n;
					NumBytesBlock := rcdata.capacity;
					TotBytes := NumBlocks*NumBytesBlock;
				end
				else
				 begin
					NumBlocksTrack := rcdata.block_n + 1;
				 end;
			end
			else
			begin
			     { IF have_teac then
			       begin
				    writeln('IT WAS A TEAC and escaping : ',iotemp);
			       end; }
				escape(-10);
			end;
			if (i = 1) then
				rccmd.pmi := true;
		end;


		if (NumBlocksTrack >= NumBlocks) or (NumBlocksTrack < 0) then
		begin
			{
			  no delay block so have to fake it as per above table.
			}
			if TotBytes < 8*hex('100000') then
				NumBytesTrack := 4*hex('400')
			else if TotBytes < 128*hex('100000') then
				NumBytesTrack := 8*hex('400')
			else if TotBytes < 256*hex('100000') then
				NumBytesTrack := 16*hex('400')
			else
				NumBytesTrack := 32*hex('400');
			{TotBytes in a sector is a power of 2, so #blocks will divide evently}
			NumBlocksTrack := NumBytesTrack DIV NumBytesBlock
		end;


		{
		  attempt to get the number of tracks per cylinder.  This is actually
		  the number of surfaces, which is the number of heads.  Page 4 of the
		  data returned from the Mode Sense command contains the number of
		  heads.  However, this is not a required command, nor is this required
		  information.  Therefore, attempt to get the info, and if unsuccessful
		  use the following table:

			  0 -  64Mbytes =  2 heads
			 64 - 128Mbytes =  4 heads
			128 - 256Mbytes =  8 heads
			256+            = 16 heads
		}
		Page4Found := false;
		mscmd := mode_sense_cmd_const;
		mscmd.lunit := pSB^.LUN;
		iotemp := ScsiHandleSession(pSB,
					addr(mscmd), sizeof(mscmd),
					addr(msdata), sizeof(msdata), false,
					nil, 0, false);
		if iotemp = ord(inoerror) then
		begin
		  IF have_teac then { page 5 not page 4 !!!!!! }
		    begin
		      TotLen := msdata.ms_len - msdata.bd_len - 3;
		      pPage := addr(msdata.ms_data[msdata.bd_len]);
			while (TotLen > 0) and (pPage^.PageCode <> 5) do
			begin
				TotLen := TotLen - (pPage^.PageLen + 2);
				pPage := addr(pPage^, pPage^.PageLen + 2);
			end;
			if pPage^.PageCode = 5 then
			begin
				Page4Found := true;
				NumCylinders := ord(charptr(addr(pPage^,9))^);
				NumBlocksTrack := ord(charptr(addr(pPage^,5))^);
				NumTracksCylinder := ord(charptr(addr(pPage^,4))^);
			end;


		    end
		   else  { same as before }
		     begin
			TotLen := msdata.ms_len - msdata.bd_len - 3;
			pPage := addr(msdata.ms_data[msdata.bd_len]);
			while (TotLen > 0) and (pPage^.PageCode <> 4) do
			begin
				TotLen := TotLen - (pPage^.PageLen + 2);
				pPage := addr(pPage^, pPage^.PageLen + 2);
			end;
			if pPage^.PageCode = 4 then
			begin
				Page4Found := true;
				NumTracksCylinder := ord(charptr(addr(pPage^,5))^);
			end;
		      end; { else }
		end;

		if not Page4Found then
		begin
			if TotBytes < 64*hex('100000') then
				NumTracksCylinder := 2
			else if TotBytes < 128*hex('100000') then
				NumTracksCylinder := 4
			else if TotBytes < 256*hex('100000') then
				NumTracksCylinder := 8
			else
				NumTracksCylinder := 16;
		end;

		if ((not have_teac) or (not Page4Found)) then
		  NumCylinders := TotBytes Div NumBytesBlock      {yields #blocks}
					 Div NumBlocksTrack     {yields #tracks}
					 Div NumTracksCylinder; {yields #cylinders}
	recover
		if escapecode <> -10 then
			escape(escapecode)
		else
			ioresult := iotemp;

end;

procedure ScsiDiscBlocks(pSB:PtrSessionBlockType;
			var NumBytesBlock, TotBlocks:integer);
var
      rccmd : read_capacity_cmd_type;
      rcdata : read_capacity_data_type;
      i:integer;
	devtype, ver : integer;
	moveable : boolean;
	vstring : STRING255;
	have_teac : boolean;
begin
	with pSB^ do
		if Overlap then
			ioresult := ord(zbadmode)
		else
		begin
		       have_teac := FALSE;
		       VSTRING := 'xxxx';
		       ScsiDevInfo(pSB,devtype,ver,moveable,vstring);
			if strlen(vstring) >= 4 then
			 IF ((vstring[1] = 'T') and (vstring[2] = 'E')
			  and (vstring[3] = 'A') and (vstring[4] = 'C'))
			    then
			     BEGIN
			       syncteac(pSB);
			       { writeln('SYNCED FROM ScsiDiscBlocks'); }
			       have_teac := TRUE;
			     END;

			rccmd := read_capacity_cmd_const;
			rccmd.lunit := LUN;
			ioresult := ScsiHandleSession(pSB,
					 addr(rccmd), sizeof(rccmd),
					 addr(rcdata), sizeof(rcdata), false,
					 Nil, 0, false);
		end;

	if ioresult = ORD(inoerror) then
	begin
		NumBytesBlock := rcdata.capacity;
		TotBlocks := rcdata.block_n+1;
	end;


end;

procedure ScsiDiscRead( pSB:PtrSessionBlockType;
			BlockStart, NumBlocks, NumBytesBlock:integer;
			Buffer:ANYPTR);
var
	rcmd:read_cmd_type;
	tries:integer;
begin
	with pSB^ do
		if Overlap then
			ioresult := ord(zbadmode)
		else
		begin
			tries := 0;
			repeat
				tries := tries + 1;
				rcmd := read_cmd_const;
				rcmd.lunit := LUN;
				rcmd.block_n := BlockStart;
				rcmd.lmsb  := NumBlocks div Hex('100');
				rcmd.llsb  := NumBlocks mod Hex('100');
				ioresult   := ScsiHandleSession(pSB,
						   addr(rcmd), sizeof(rcmd),
						   Buffer, NumBlocks*NumBytesBlock, true,
						   Nil, 0, false);
			until (ioresult <> ord(zbadblock)) or (tries >= 2);
		end;
end;

procedure ScsiDiscWrite(pSB:PtrSessionBlockType;
			BlockStart, NumBlocks, NumBytesBlock:integer;
			Buffer:ANYPTR);
var
	wcmd:write_cmd_type;
	tries:integer;
begin
	with pSB^ do
		if Overlap then
			ioresult := ord(zbadmode)
		else
		begin
			tries := 0;
			repeat
				tries := tries + 1;
				wcmd := write_cmd_const;
				wcmd.lunit := LUN;
				wcmd.block_n := BlockStart;
				wcmd.lmsb  := NumBlocks div Hex('100');
				wcmd.llsb  := NumBlocks mod Hex('100');
				ioresult   := ScsiHandleSession(pSB,
						   addr(wcmd), sizeof(wcmd),
						   Nil, 0, false,
						   Buffer, NumBlocks*NumBytesBlock, true);
			until (ioresult <> ord(zbadblock)) or (tries >= 2);
		end;
end;

procedure ScsiDiscFormat(pSB:PtrSessionBlockType;
			InterLeave:s_short);
var
	saveDoNotDisconnect:boolean;
	fcmd:format_cmd_type;
begin
	with pSB^ do
		if Overlap then
			ioresult := ord(zbadmode)
		else
		begin
			fcmd := format_cmd_const;
			fcmd.lunit := LUN;
			fcmd.il_msb := Interleave Div HEX('100');
			fcmd.il_lsb := Interleave Mod HEX('100');
			saveDoNotDisconnect := DoNotDisconnect;
			DoNotDisconnect := false;
			ioresult    := ScsiHandleSession(pSB,
						    addr(fcmd), sizeof(fcmd),
						    nil, 0, false,
						    nil, 0, false);
			DoNotDisconnect := saveDoNotDisconnect;
		end;
end;

procedure ScsiDiscPrevent(  pSB:PtrSessionBlockType);
var
	pcmd:prevent_allow_cmd_type;
begin
	with pSB^ do
		if Overlap then
			ioresult := ord(zbadmode)
		else
		begin
			pcmd := prevent_cmd_const;
			pcmd.lunit := LUN;
			ioresult := ScsiHandleSession(pSB,
					 addr(pcmd), sizeof(pcmd),
					 Nil, 0, false,
					 Nil, 0, false);
		end;
end;

procedure ScsiDiscAllow(    pSB:PtrSessionBlockType);
var
	acmd:prevent_allow_cmd_type;
begin
	with pSB^ do
		if Overlap then
			ioresult := ord(zbadmode)
		else
		begin
			acmd := allow_cmd_const;
			acmd.lunit := LUN;
			ioresult := ScsiHandleSession(pSB,
					 addr(acmd), sizeof(acmd),
					 Nil, 0, false,
					 Nil, 0, false);
		end;
end;


end. {module SCSIIF}
@


56.6
log
@Changes for McBeth tape support with BACKUP.
@
text
@d115 2
d213 2
a214 2
				    BlockStart, NumBlocks, NumBytesBlock:integer
;
d218 3
a220 2
				    BlockStart, NumBlocks, NumBytesBlock:integer
;
d816 1
a816 1

@


56.5
log
@forgot to set the value of high_density.
ZZ
@
text
@d186 8
d210 9
d593 221
d1316 218
d1751 126
@


56.4
log
@

Changs to SyncTeac to solve the hfs floppy problem first noted in
Japan.

@
text
@d1447 5
@


56.3
log
@
pws2rcs automatic delta on Wed Jan 27 13:14:25 MST 1993
@
text
@d1313 3
d1327 26
a1423 4
	if unitable^[43].letter = 'S' then
	  unitable^[43].dvrtemp := sense_size;
	if unitable^[3].letter = 'S' then
	  unitable^[3].dvrtemp := sense_size;
d1425 10
d1546 45
@


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


56.1
log
@Automatic bump of revision number for PWS version 3.25
@
text
@a0 1967
{system options}
$modcal on$
$allow_packed on$
$partial_eval on$

{code generation options}
$debug off$
$LINENUM 20000$
$iocheck on$
$ovflcheck on$
$range on$
$stackcheck on$

{listing options}
$tables off$
$lines 57$
$pagewidth 130$
$copyright 'Hewlett Packard Company, 1989'$

{{
$search 'PWS_SCSI'$
{Needed for TDEBUG - Don't delete SCSIDVR symbols during LINK!}
$PAGE$

{
	SCSI Interface Module.
	Contains a definition of all of the SCSI commands.  and provides
	the routine ScsiHandleSession.
	It is intended that all outside users would search/link this module, using
	it to get inteface to the scsi driver.
}
module SCSILIB;

import sysglobals, asm, iodeclarations {{, STATE_PROCS, LOADER{needed for TDEBUG};

export

{---- begin of SCSIIF common. do not modify!!! below is copied from SCSI_DEFS during turn process}


type
	s_byte = 0 .. 255;
	s_short = 0..65535;
	s_short_signed = -32768..32767;
	PtrS_byte = ^s_byte;
	PtrChar = ^char;
	s_TYPE_ISC = 0..31;
const
	trace_size = 1000;


type
	PtrSessionBlockType = ^SessionBlockType;
	ScsiDeviceType = 0 .. 7;

	InternalErrType = ( NoIntErr, ScsiStackingErr, RunLevelErr,
			    StateMachineErr, ScsiInteruptErr, ScsiAddressErr,
			    SelectRetryErr, ScsiManXferErr, ScsiXferErr,
			    XferRetryErr, ScsiEscapeErr, ScsiPhaseErr,
			    ScsiCatastrophicErr, ScsiBadMsg, ScsiTimeOutErr,
			    ScsiXferParmErr, ScsiMiscErr );

	SessionStateType = (
			    SessionWaiting,     {Session is initialized and waiting to be started.}
			    SessionRunning,     {Session running (State Machine is started)}
			    SessionSuspended,   {Target disconnected, bus released, awaiting reselection}
			    SessionComplete     {Session terminated, either normally or with an err}
			   );


	ScsiCallBackType = Procedure(pSB:PtrSessionBlockType);

	BufferBlockType = RECORD
				BufPtr:PtrS_byte;
				BufLen:integer;
				DoDMA:Boolean;
			END;


	SessionBlockType = RECORD
				{Caller sets before session}
				SelectCode:s_TYPE_ISC;
				Device:ScsiDeviceType;
				LUN:s_byte;
				SUN:s_byte;
				Overlap:Boolean;
				DoNotDisconnect:Boolean;
				CmdPtr:ANYPTR;
				CmdLen:s_byte;
				BufIn:BufferBlockType;
				BufOut:BufferBlockType;
				SessionCompleteCallBack:ScsiCallBackType;

				{set by SCSI Bus Driver during session}
				SessionState:SessionStateType;
				SessionStatus:s_byte;
				InternalStatus:InternalErrType;
				ResidualCount: INTEGER;

				{Internal Use Only}
				{Trace set by caller}
				{InternalBlock used by driver}
				DoTrace:Boolean;
				TracePtr:ANYPTR;
				TraceSize:integer;
				TraceStuff:ANYPTR;
				InternalBlock:PACKED ARRAY [1..128] of CHAR;
			END;



{---- end of SCSIIF common. do not modify!!! above is copied from SCSI_DEFS during turn process}

type
      mode_select_cmd_type = packed record
			   op_code : byte;
			   lunit   : 0..7;
			   pf      : 0..1;
			   rsvd1   : 0..7;
			   sp      : 0..1;
			   rsvd2   : byte;
			   rsvd3   : byte;
			   reqlen  : byte;
			   pad2    : byte;
			 end;

     mode_select_data_type = packed record
			   ms_len  : byte;
			   medtype : byte;
			   wp      : boolean;
			   rsvd1   : 0 .. 127;
			   bd_len  : byte;
			   ms_data : packed array [ 0 .. 255 ] of char;
			 end;



      PtrModeSenseDataType = ^mode_sense_data_type;
      PtrModeSelectDataType = ^mode_select_data_type;

    PtrDeviceAddressVectorsType = ^DeviceAddressVectorsType;
    DeviceAddressVectorsType = PACKED RECORD
		sc,  {select code}
		ba,  {bus address   - Session Device}
		du,  {device unit   - Session LUN}
		dv  {device volume - Session SUN}
		  :-128..127;
		    END;



	procedure IsScsiCard(       sc:S_TYPE_ISC;
				var b:boolean);

	procedure ScsiSBSize(   var size:integer);

	procedure ScsiSBInit(       pSB:ANYPTR;
				    pDAV:ANYPTR);

	function  ScsiHandleSession(pSB:PtrSessionBlockType;
				    pCmd:ANYPTR; lCmd:integer;
				    pDIn:ANYPTR; lDIn:integer; DMAIn:boolean;
				    pDOut:ANYPTR; lDOut:integer; DMAOut:boolean
				   ):integer;

	function ScsiSessionComplete(pSB:PtrSessionBlockType):BOOLEAN;

	function ScsiCheckError(pSB:PtrSessionBlockType):integer;

	procedure ScsiSessionSense( SelectCode:S_TYPE_ISC;
				    pBuf:ANYPTR;
				var Length:integer);

	procedure ScsiSessionAbort(pSB:PtrSessionBlockType);

	procedure ScsiReset(        SelectCode:S_TYPE_ISC);

	procedure ScsiModeSelect(pSB:PtrSessionBlockType;
				 pDB : PtrModeSelectDataType;
				 sector_size : integer);

	procedure ScsiModeSense(pSB:PtrSessionBlockType;
				pDB : PtrModeSenseDataType ;
				var sector_size : integer);

	procedure SyncTeac(pSB : PtrSessionBlockType);

	procedure ScsiCheckDev(     pSB:PtrSessionBlockType);

	procedure ScsiDevInfo(      pSB:PtrSessionBlockType;
				var DevType, AnsiVersion:integer;
				var Removable:boolean;
				var VendorString:string255);

	procedure ScsiDiscSize(     pSB:PtrSessionBlockType;
				var NumBytesBlock, NumBlocksTrack,
				    NumTracksCylinder, NumCylinders:integer);

	procedure ScsiDiscBlocks(   pSB:PtrSessionBlockType;
				var NumBytesBlock, TotBlocks:integer);

	procedure ScsiDiscRead(     pSB:PtrSessionBlockType;
				    BlockStart, NumBlocks, NumBytesBlock:integer;
				    Buffer:ANYPTR);

	procedure ScsiDiscWrite(    pSB:PtrSessionBlockType;
				    BlockStart, NumBlocks, NumBytesBlock:integer;
				    Buffer:ANYPTR);

	procedure ScsiDiscFormat(   pSB:PtrSessionBlockType;
				    InterLeave:s_short);

	procedure ScsiDiscPrevent(  pSB:PtrSessionBlockType);

	procedure ScsiDiscAllow(    pSB:PtrSessionBlockType);

implement
const
	DEBUG  = FALSE;
	TDEBUG = FALSE;

type
	MiscTemplate = packed record
		MiscpScBlock:ANYPTR;
		MiscpSenseSpace:PtrChar;
		MiscSenseLength:integer;
	end;
	PtrMiscTemplateType = ^MiscTemplate;

type
       test_cmd_type = packed record
			   op_code : byte;
			   lunit   : 0..7;
			   pad0    : 0..31;
			   pad1    : shortint;
			   pad2    : byte;
			   pad3    : byte;
			 end;
const
      test_cmd_const = test_cmd_type[
			   op_code:hex('00'),
			   lunit:0,
			   pad0:0,
			   pad1:0,
			   pad2:0,
			   pad3:0];

type
      inq_string = string255;
      inquiry_cmd_type = packed record
			   op_code : byte;
			   lunit   : 0..7;
			   pad0    : 0..31;
			   pad1    : shortint;
			   reqlen  : byte;
			   pad2    : byte;
			 end;

      inquiry_data_type = packed record
			    case integer of
			    1:(device_code : shortint);
			    2:(device_type : byte;
			       rmb         : boolean;
			       qualifier   : 0..127;
			       iso_version : 0..3;
			       ecma_version: 0..7;
			       ansi_version: 0..7;
			       pad1        : byte;
			       vendor      : inq_string);
			    3:(inqjunk     : integer;
			       vendlen     : byte);
			  end;
const
      inquiry_cmd_const = inquiry_cmd_type[
				  op_code:hex('12'),
				  lunit:0,
				  pad0:0,
				  pad1:0,
				  reqlen:255,
				  pad2:0];

type
      read_capacity_cmd_type = packed record
				 op_code : byte;
				 lunit   : 0..7;
				 pad0    : 0..15;
				 reladr  : boolean;
				 block_n : integer;
				 case integer of
				 1:(pad1 : integer);
				 2:(pad2 : shortint;
				    v0   : 0..3;
				    pad3 : 0..31;
				    pmi  : boolean;
				    v1   : 0..3;
				    pad4 : 0..15;
				    flag : boolean;
				    link : boolean);
			       end;
      read_capacity_data_type = packed record
				  block_n : integer;
				  capacity: integer;
				end;

const
      read_capacity_cmd_const = read_capacity_cmd_type[
				  op_code:hex('25'),
				  lunit:0,
				  pad0:0,
				  reladr:false,
				  block_n:0,
				  pad1:0];

type

      mode_sense_cmd_type = packed record
			   op_code : byte;
			   lunit   : 0..7;
			   pad0    : 0..31;
			   pcf     : 0..3;
			   pg_code : 0..hex('3f');
			   pad1    : byte;
			   reqlen  : byte;
			   pad2    : byte;
			 end;

     mode_sense_data_type = packed record
			   ms_len  : byte;
			   medtype : byte;
			   wp      : boolean;
			   rsvd1   : 0 .. 127;
			   bd_len  : byte;
			   ms_data : packed array [ 0 .. 255 ] of char;
			 end;

     block_descript_type = packed record
			   d_code  : byte;
			   nb_msb  : byte;
			   nb_2    : byte;
			   nb_lsb  : byte;
			   rsvd1   : byte;
			   bl_msb  : byte;
			   bl_2    : byte;
			   bl_lsb  : byte;
			 end;

      page_header_type = packed record
			   r1      : boolean;
			   r2      : boolean;
			   PageCode: 0 .. 63;
			   PageLen : byte;
			 end;
      pPageType = ^page_header_type;

const
	mode_sense_cmd_const = mode_sense_cmd_type[
			   op_code : hex('1a'),
			   lunit   : 0,
			   pad0    : 0,
			   pcf     : 0,
			   pg_code : hex('3f'),
			   pad1    : 0,
			   reqlen  : 255,
			   pad2    : 0];


       mode_select_cmd_const = mode_select_cmd_type[
			   op_code : hex('15'),
			   lunit   : 0,
			   pf      : 0,
			   rsvd1   : 0,
			   sp      : 0,
			   rsvd2   : 0,
			   rsvd3   : 0,
			   reqlen  : HEX('0C'),
			   pad2    : 0];

type
      read_cmd_type = packed record
			op_code : byte;
			lunit   : 0..7;
			pad0    : 0..15;
			reladr  : boolean;
			block_n : integer;
			{case integer of
			1:(pad1 : integer);
			2:(pad2    : byte;
			   n_blocks: shortint;
			   pad3    : byte);
			3:(}pad4    : byte;
			   lmsb    : byte;
			   llsb    : byte;
			   v0      : 0..3;
			   pad5    : 0..15;
			   flag    : boolean;
			   link    : boolean;
		      end;

const
      read_cmd_const = read_cmd_type[
			   op_code : hex('28'),
			   lunit:0,
			   pad0:0,
			   reladr:false,
			   block_n:0,
			   pad4    : 0,
			   lmsb    : 0,
			   llsb    : 0,
			   v0      : 0,
			   pad5    : 0,
			   flag    : FALSE,
			   link    : FALSE];

type
      write_cmd_type = read_cmd_type;

const
      write_cmd_const = write_cmd_type[
			   op_code : hex('2a'),
			   lunit:0,
			   pad0:0,
			   reladr:false,
			   block_n:0,
			   pad4    : 0,
			   lmsb    : 0,
			   llsb    : 0,
			   v0      : 0,
			   pad5    : 0,
			   flag    : FALSE,
			   link    : FALSE];
			   {pad1:0,
			   n_blocks:0,
			   pad2:0];}

type
      request_sense_cmd_type = packed record
				 op_code : byte;
				 lunit   : 0..7;
				 pad0    : 0..31;
				 pad1    : shortint;
				 len     : byte;
				 case integer of
				 1:(byte5 : byte);
				 2:(v0    : 0..3;
				    pad2  : 0..15;
				    flag  : boolean;
				    link  : boolean);
			       end;
      pac18 = packed array [1..18] of byte;
      request_sense_data_type = packed record
				  case integer of
				  1:(sensedata:packed array[1..255] of char);
				  2:(advalid : boolean;
				     e_class : 0..7;
				     e_code  : 0..15;
				     case integer of
				     1:(seg_num : byte;
					filemark: boolean;
					eom     : boolean;
					ili     : boolean;
					pad0    : boolean;
					sensekey: 0..15;
					byte3   : byte;
					more    : pac18;);
				     2:(block_n : 0..16777215));
				 end;
      ptr_request_sense_data_type = ^request_sense_data_type;
      SenseType  = (sNoSense, sRecoveredError, sNotReady, sMediumError,
		    sHardwareError, sIllegalRequest, sUnitAttention,
		    sDataProtect, sBlankCheck, sVendor, sCopyAbort,
		    sCommandAbort, sEqual, sVolumeOverflow, sMisCompare,
		    sReserved,
		    DriverError, IllegalStatus, GetSenseFailed);

const
      request_sense_cmd_const = request_sense_cmd_type[
				  op_code:hex('03'),
				  lunit:0,
				  pad0:0,
				  pad1:0,
				  len:sizeof(request_sense_data_type),
				  byte5:0];

type
       format_cmd_type = packed record
			   op_code : byte;
			   lunit   : 0..7;
			   fmtdata : boolean;
			   cmplst  : boolean;
			   dlf     : 0..7;
			   v0      : byte;
			   il_msb  : byte;
			   il_lsb  : byte;
			   v1      : 0..3;
			   rsvd    : 0..15;
			   flag    : boolean;
			   link    : boolean;
			 end;
	defect_header_type = packed record
			   rsvd1   : byte;
			   fov     : boolean;
			   dpry    : boolean;
			   dcrt    : boolean;
			   stpf    : boolean;
			   rsvd2   : 0 .. 7;
			   v0      : boolean;
			   lmsb    : byte;
			   llsb    : byte;
			   end;
const
      format_cmd_const = format_cmd_type[
			   op_code:hex('04'),
			   lunit:0,
			   fmtdata:false,
			   cmplst:false,
			   dlf:0,
			   v0:0,
			   il_msb:0,
			   il_lsb:0,
			   v1:0,
			   rsvd:0,
			   flag:false,
			   link:false];

	defect_header_const = defect_header_type[
			    rsvd1:0,
			    fov:false,
			    dpry:false,
			    dcrt:false,
			    stpf:false,
			    rsvd2:0,
			    v0:false,
			    lmsb:0, llsb:0];

type

      prevent_allow_cmd_type = packed record
			   op_code : byte;
			   lunit   : 0..7;
			   pad0    : 0..31;
			   pad1    : shortint;
			   pad2    : 0..hex('7f');
			   prevent : boolean;
			   pad3    : byte;
			 end;


const
	prevent_cmd_const = prevent_allow_cmd_type[
			   op_code : hex('1e'),
			   lunit   : 0,
			   pad0    : 0,
			   pad1    : 0,
			   pad2    : 0,
			   prevent : true,
			   pad3    : 0];

	allow_cmd_const = prevent_allow_cmd_type[
			   op_code : hex('1e'),
			   lunit   : 0,
			   pad0    : 0,
			   pad1    : 0,
			   pad2    : 0,
			   prevent : false,
			   pad3    : 0];
type
      status_type = packed record
		       case integer of
			  1:(b:byte;);
			  2:(r:boolean;
			     v1:0..3;
			     stat:0..15;
			     v2:boolean;);
		    end;

      SenseXlateType = packed array [ SenseType ] of iorsltwd;
      InternalXlateType = packed array [ InternalErrType ] of iorsltwd;
const
      SenseXlateConst = SenseXlateType[
		    inoerror,           {sNoSense}
		    inoerror,           {sRecoveredError}
		    znotready,          {sNotReady}
		    zbadblock,          {sMediumError}
		    zbadhardware,       {sHardwareError}
		    zbadmode,           {sIllegalRequest}
		    zmediumchanged,     {sUnitAttention}
		    zprotected,         {sDataProtect}
		    znoblock,           {sBlankCheck}
		    zcatchall,          {sVendor}
		    zcatchall,          {sCopyAbort}
		    znodevice,          {sCommandAbort - only sense with this translation}
		    zcatchall,          {sEqual}
		    znosuchblk,         {sVolumeOverflow}
		    zcatchall,          {sMisCompare}
		    zcatchall,          {sReserved}
		    zbadmode,           {DriverError}
		    zcatchall,          {IllegalStatus}
		    zcatchall];         {GetSenseFailed}

      InternalXlateConst = InternalXlateType[
		    inoerror,           {NoIntErr}
		    zcatchall,          {ScsiStackingErr}
		    zcatchall,          {RunlevelErr}
		    zcatchall,          {StateMachineErr}
		    zstrangei,          {ScsiInteruptErr}
		    znodevice,          {ScsiAddressErr}
		    znodevice,          {SelectRetryErr}
		    zbadhardware,       {ScsiManXferErr}
		    zbadhardware,       {ScsiXferErr}
		    ztimeout,           {XferRetryErr}
		    zcatchall,          {ScsiEscapeErr}
		    zcatchall,          {ScsiPhaseErr}
		    zcatchall,          {ScsiCatastrophicErr}
		    zcatchall,          {ScsiBadMsg}
		    ztimeout,           {ScsiTimeOutErr}
		    zbadmode,           {ScsiXferParmErr}
		    zcatchall];         {ScsiMiscErr}



$IF TDEBUG$
procedure dump_trace(var sb:SessionBlockType);
label 1;
  TYPE

	EventType =     (
			{
			 NOTE: The following event list must match the assembler event
			 list defined in ST_EQU
			}

			{Standard events}
			NoEvent, ScsiErr, WaitForISR,

			{Bus Phase Events, returned by hwiGetPhase}
			BusFree, BusBusy, MsgIn, MsgOut, CmdPhase, DataPhase, StatusPhase,

			{Message In Events}
			Synch, SaveDataPtr, RestorePtrs, Disconnect, CmdComplete,
			Reject, Identify, LCC, LCCwFlag,

			{Establish Path}
			NeedSynchParms,

			{Do a Transfer}
			OriginalPhase
			);




	TRICKYDICKY = RECORD CASE BOOLEAN OF
			TRUE:(S:ST_SHORT);
			FALSE:(B1:CHAR;B2:CHAR;E:EVENTTYPE);
		      END;
  var
    control: control_ptr;
    i : integer;
    nametable : trace_name_table_ptr;
    symbolname: string255;
    T:TRICKYDICKY;
    EVENT:EVENTTYPE;

  function value(symbol: string255): integer;
    var
      modp: moddescptr;
      ptr, valueptr: addrec;
      found: boolean;
    begin {value}
      value := 0;
      found := false;
      modp := sysdefs;
      while (modp<>nil) and not found do
	with modp^ do
	  begin
	    ptr := defaddr;
	    while (ptr.a<defaddr.a+defsize) and not found do
	      begin
		found := ptr.syp^=symbol;
		ptr.a := ptr.a+strlen(ptr.syp^)+1;
		ptr.a := ptr.a+ord(odd(ptr.a));
		valueptr.a := ptr.a+2;
		if found then
		  value := valueptr.vep^.value;
		ptr.a := ptr.a+ptr.gvp^.short;
	      end; {while}
	    modp := link;
	  end; {with modp^}
    end; {value}

  function symbolforaddr(value:integer): string255;
    var
      modp: moddescptr;
      ptr, valueptr: addrec;
      found: boolean;
    begin {value}
      found := false;
      modp := sysdefs;
      while (modp<>nil) and not found do
	with modp^ do
	  begin
	    ptr := defaddr;
	    while (ptr.a<defaddr.a+defsize) and not found do
	      begin
		symbolforaddr:= ptr.syp^;
		ptr.a := ptr.a+strlen(ptr.syp^)+1;
		ptr.a := ptr.a+ord(odd(ptr.a));
		valueptr.a := ptr.a+2;
		found := value = valueptr.vep^.value;
		ptr.a := ptr.a+ptr.gvp^.short;
	      end; {while}
	    modp := link;
	  end; {with modp^}
    end; {symbolforaddr}

  function stateforoffset(value:integer): state_name_string;
    var
      done : boolean;
      i    : integer;
      temp : state_name_string;
    begin
      temp := '';
      strwrite(temp,1,i,value:1);
      stateforoffset := temp;
      i := 1; done := false;
      if nametable<>nil then
	repeat
	  with nametable^[i] do
	  begin
	    if offset=value then
	    begin
	      done:= true;
	      stateforoffset := name;
	    end
	    else
	    if offset=0 then done := true
			     else i := i + 1;
	  end;
	until done;
    end; { stateforoffset}

  begin { dump_trace }
    {REWRITE(LISTING,'#6:');}
    if not sb.DoTrace then
	goto 1;
    control := sb.tracestuff;
    nametable := nil;
    with control^, sb do
    begin
	i := ttotal;
	repeat
		while(i = tremaining) and (sessionstate <> sessioncomplete) do
			;
		with tdata^[i] do
			case data_type of
			tstate:  writeln(listing,'state = ',stateforoffset(short_data));
			tproc:   writeln(listing,'    procedure = ',symbolforaddr(long_data));
			tmachine:begin
				   symbolname := symbolforaddr(long_data);
				   writeln(listing,' machine = ',symbolname);
				   symbolname := symbolname+'_T';
				   nametable := anyptr(value(symbolname));
				 end;
			tevent:  BEGIN
				   T.S := SHORT_DATA;
				   EVENT := T.E;
				   writeln(listing,'    event     = ',EVENT);
				 END;
			end;
		i := i - 1;
	until (i = tremaining) and (sessionstate = sessioncomplete);
    end;
    {CLOSE(LISTING,'SAVE');}
    1:
  end; { dump_trace }
  $end$

procedure IsScsiCard(sc:S_TYPE_ISC; var b:boolean);
begin
	b := (isc_table[sc].card_type = scsi_card);
end;

function GetpMisc(SelectCode:S_TYPE_ISC):PtrMiscTemplateType;
var
	pMisc:PtrMiscTemplateType;
begin
	GetpMisc := NIL;
	with isc_table[SelectCode] do
	begin
		if card_type = scsi_card then
		begin
			pMisc := addr(io_tmp_ptr^.drv_misc[1]);
			{
			  verify that misc block is for real.
			}
			if pMisc^.MiscpScBlock <> NIL then
				GetpMisc := pMisc;
		end;
	end;
end;

procedure ScsiSBSize(var size:integer);
begin
	size := sizeof(SessionBlockType);
end;

procedure ScsiSBInit(pSB:ANYPTR; pDAV:ANYPTR);
var
	i:integer;
	pChar1, pChar2:PtrChar;
begin
	pChar1 := pSB;
	pChar2 := addr(pChar1^, 1);
	pChar1^ := #0;
	moveleft(pChar1^, pChar2^, sizeof(SessionBlockType)-1);
	with PtrSessionBlockType(pSB)^, PtrDeviceAddressVectorsType(pDAV)^ do
	begin
		SelectCode := sc;
		Device     := ba;
		LUN        := du;
		SUN        := dv;
		Overlap    := false;
		DoNotDisconnect := true;
		DoTrace    := false;
	end;
end;


function  RequestSense(pSB:PtrSessionBlockType):SenseType;
var
	SB:SessionBlockType; {save the user's session block}
	rscmd:request_sense_cmd_type;
	prsdata:ptr_request_sense_data_type;
	i:integer;
begin
	RequestSense := GetSenseFailed;

	SB := pSB^;
	with SB do
	begin
		rscmd := request_sense_cmd_const;
		rscmd.lunit := LUN;
		Overlap := FALSE;
		DoNotDisconnect := TRUE;
		with GetpMisc(SelectCode)^ do
		begin
			prsdata := ANYPTR(MiscpSenseSpace);
			i := ScsiHandleSession(addr(SB),
				     addr(rscmd), sizeof(rscmd),
				     prsdata, 255, false,
				     Nil, 0, false);
			if i = ord(inoerror) then
			begin
				MiscSenseLength := 255 - ResidualCount;
				with prsdata^ do
				begin
					if (e_class = 7) and (e_code = 0) then
						RequestSense := SenseType(sensekey);
				end;
			end;
		end;
	end;
end;

function ScsiHandleSession(pSB:PtrSessionBlockType;
			pCmd:ANYPTR; lCmd:integer;
			pDIn:ANYPTR; lDIn:integer; DMAIn:Boolean;
			pDOut:ANYPTR; lDOut:integer; DMAOut:Boolean):integer;
label 1;
var
	OkToCall:BOOLEAN;
	AbortCommandRetry:integer;
	i:integer;
	$IF DEBUG$
		C:CHAR;
	$END$
begin
	with pSB^ do
	begin
	try
		AbortCommandRetry := 0;
		1:
		CmdPtr := pCmd;
		CmdLen := lCmd;
		with BufIn do
		begin
			BufPtr := pDIn;
			BufLen := lDIn;
			DoDma  := DMAIn;
		end;
		with BufOut do
		begin
			BufPtr := pDOut;
			BufLen := lDOut;
			DoDma  := DMAOut;
		end;
		InternalStatus := NoIntErr ;
		SessionStatus := 0;
		ResidualCount := 0;
		{ $IF DEBUG$
		{         C := CHARPTR(PCMD)^;
		{          WRITELN; WRITELN('SCSI COMMAND IS: ',ord(c):1);
		{  $END$
		{}
		OkToCall := (GetpMisc(SelectCode) <> Nil);
		if not OkToCall then
			escape(0);
		call(isc_table[SelectCode].io_drv_ptr^.iod_tfr, nil, pSB);
		if not Overlap then
		begin
			i := ScsiCheckError(pSB);
			if (i = ord(znodevice)) and ((InternalStatus = NoIntErr)) then
			begin
				{sense was sCommandAbort}
				if AbortCommandRetry < 1 then
				begin
					$IF DEBUG$
						WRITELN('Retrying because of aborted command.');
					$END$

					AbortCommandRetry := AbortCommandRetry + 1;
					goto 1;
				end;
			end;
			ScsiHandleSession := i;
		end
		else
			ScsiHandleSession := ord(inoerror);
	recover
	begin
		if NOT OkToCall then
		begin
			SessionState := SessionComplete;
			InternalStatus := ScsiAddressErr;
			if not Overlap then
				ScsiHandleSession := ScsiCheckError(pSB)
			else
				ScsiHandleSession := ord(inoerror);
		end
		else
			escape(escapecode);
	end;
	end;
end;

function ScsiSessionComplete(pSB:PtrSessionBlockType):BOOLEAN;
begin
	ScsiSessionComplete := (pSB^.SessionState = SessionComplete);
end;

function ScsiCheckError(   pSB:PtrSessionBlockType):integer;
var
	status:status_type;
	sense:SenseType;
	$IF DEBUG OR TDEBUG$
		C:CHAR;
	$END$
begin
	with pSB^ do
	begin
		$IF DEBUG OR TDEBUG$
			C := CHARPTR(CmdPtr)^;
		$END$
		if SessionState <> SessionComplete then
			ScsiCheckError := ord(inoerror)
		else if InternalStatus <> NoIntErr then
		begin
			$IF DEBUG$
				WRITELN('DRIVER ERROR: ', INTERNALSTATUS);
				WRITELN('SCSI COMMAND IS: ',ord(c):1);
				{}
			$END$
			$IF TDEBUG$
			if (ord(charptr(CmdPtr)^) <> 0) then
			begin
				writeln(listing);
				writeln(listing, '----------------------------------------');
				writeln(listing, 'TRACE FOR SCSI COMMAND: ',ord(c):1);
				writeln(listing, '----------------------------------------');
				dump_trace(pSB^);
			end;
			$END$
			ScsiCheckError := Ord(InternalXlateConst[InternalStatus]);
		end
		else if SessionStatus <> 0 then
		begin
			$IF DEBUG$
				WRITELN('BAD SESSION STATUS: ', SessionStatus:1);
				WRITELN('SCSI COMMAND IS: ',ord(c):1);
				{}
			$END$
			status.b := SessionStatus;
			if (status.stat <> 0) then
			begin
				if (status.stat = 1) then
				begin
					if CharPtr(CmdPtr)^ <> #3 {request_sense} then
					begin
						$IF DEBUG$
						  writeln('Calling Request Sense.');
						$END$
						sense := RequestSense(pSB);
					end
					else
					begin
						$IF DEBUG$
						  writeln('Request Sense Failed!.');
						$END$
						sense := GetSenseFailed;
					end;
				end
				else if (status.stat = 4) then
				begin
					$IF DEBUG$
					  writeln('Sense is sNotReady.');
					$END$
					sense := sNotReady
				end
				else
				begin
					$IF DEBUG$
					  writeln('Illegal status.');
					$END$
					sense := IllegalStatus;
				end;
				$IF DEBUG$
					WRITELN('BAD SESSION SENSE: ', SENSE);
					WRITELN('SCSI COMMAND IS: ',ord(c):1);
					{}
				$END$
				ScsiCheckError := ord(SenseXlateConst[sense]);
			end
			else {Good Status}
				ScsiCheckError := ord(inoerror);
		end
		else {Good Status}
			ScsiCheckError := ord(inoerror);
	end;
end;


procedure ScsiSessionSense( SelectCode:S_TYPE_ISC;
			    pBuf:ANYPTR;
			var Length:integer);
var
	pMisc:PtrMiscTemplateType;
begin
	pMisc := GetpMisc(SelectCode);
	if pMisc <> Nil then
	with pMisc^ do
	begin
		if Length > MiscSenseLength then
			Length := MiscSenseLength;
		moveleft(MiscpSenseSpace^, PtrChar(pBuf)^, Length);
	end
	else
		Length := 0;
end;

procedure ScsiSessionAbort(pSB:PtrSessionBlockType);
begin
	with pSB^ do
	begin
		if (Overlap) and (SessionState = SessionRunning) then
			call(isc_table[SelectCode].io_drv_ptr^.iod_tfr, ANYPTR(1), pSB);
	end;
end;

procedure ScsiReset(        SelectCode:S_TYPE_ISC);
var
	i:integer;
begin
	i := SelectCode;
	call(isc_table[SelectCode].io_drv_ptr^.iod_tfr, ANYPTR(2), ANYPTR(i));
end;

{======================================================================}
procedure ScsiModeSense(pSB:PtrSessionBlockType;
			pDB : PtrModeSenseDataType ;
			var sector_size : integer);
 type tricky_as_hell = record
     case boolean of
     FALSE: (i : integer);
     TRUE:  (c1,c2,c3,c4 : char);
  end;

 var mscmd : mode_sense_cmd_type;
     msdata : mode_sense_data_type;
     iotemp : integer;
     grab_it : tricky_as_hell;

 { Makes a call to ScsiHandleSession to query the controller }
begin
  grab_it.i := 0;
  mscmd := mode_sense_cmd_const;
  mscmd.lunit := pSB^.LUN;
  iotemp := ScsiHandleSession(pSB,
			      addr(mscmd), sizeof(mscmd),
			      pDB, { addr(msdata),} sizeof(msdata), false,
			      nil, 0, false);

  if iotemp <> 0 then { allow one retry }
    iotemp := ScsiHandleSession(pSB,
			      addr(mscmd), sizeof(mscmd),
			      pDB, { addr(msdata),} sizeof(msdata), false,
			      nil, 0, false);
  if iotemp = 0 then
    begin
     grab_it.c2 := pDB^.ms_data[5];
     grab_it.c3 := pDB^.ms_data[6];
     grab_it.c4 := pDB^.ms_data[7];
     sector_size := grab_it.i;
   end
  else
    sector_size := 666; { sector from HELL  !!!! }
end;
{======================================================================}
procedure InitModeSense(pSB:PtrSessionBlockType;
			pDB : PtrModeSenseDataType ;
			var sector_size : integer);
 type tricky_as_hell = record
     case boolean of
     FALSE: (i : integer);
     TRUE:  (c1,c2,c3,c4 : char);
  end;

 var mscmd : mode_sense_cmd_type;
     msdata : mode_sense_data_type;
     iotemp : integer;
     grab_it : tricky_as_hell;
     my_ptr : ^mode_sense_data_type;

 { Makes a call to ScsiHandleSession to query the controller }
begin
  grab_it.i := 0;
  mscmd := mode_sense_cmd_const;
  mscmd.lunit := pSB^.LUN;
  iotemp := ScsiHandleSession(pSB,
			      addr(mscmd), sizeof(mscmd),
			      pDB, { addr(msdata),} sizeof(msdata), false,
			      nil, 0, false);

  if iotemp <> 0 then { allow one retry }
    iotemp := ScsiHandleSession(pSB,
			      addr(mscmd), sizeof(mscmd),
			      pDB, { addr(msdata),} sizeof(msdata), false,
			      nil, 0, false);
  if iotemp = 0 then
    begin
     my_ptr := anyptr(pDB);
     grab_it.c2 := my_ptr^.ms_data[5];
     grab_it.c3 := my_ptr^.ms_data[6];
     grab_it.c4 := my_ptr^.ms_data[7];
     sector_size := grab_it.i;
   end
  else
    sector_size := 666; { sector from HELL  !!!! }
  if iotemp <> 0 then
     ioresult := iotemp; { ?????????? }
end;

{======================================================================}
procedure InitModeSelect(pSB:PtrSessionBlockType;
			 pDB : PtrModeSelectDataType;
			 sector_size : integer;
			 cylinders : integer);
 type tricky_as_hell = record
     case boolean of
     FALSE: (i : integer);
     TRUE:  (c1,c2,c3,c4 : char);
  end;
 var mscmd : mode_select_cmd_type;
     msdata : mode_select_data_type;
     iotemp : integer;
     cram_it : tricky_as_hell;
     brute_force : packed array [0..255] of char;
     counter : integer;
begin

     for counter := 0 to 31 do
       pDB^.ms_data[counter] := pDB^.ms_data[counter+16]; { shift down }

     mscmd := mode_select_cmd_const;
     pDB^.ms_data[0] := chr(5);  { JAB said so }
     pDB^.ms_data[8] := chr(0);
     pDB^.ms_data[9] := chr(cylinders);  { 77 or 80 cylinders }

     cram_it.i := sector_size;
     pDB^.ms_data[6] := cram_it.c3;
     pDB^.ms_data[7] := cram_it.c4;

     pDB^.ms_len := 0;
     pDB^.wp := false;
     pDB^.rsvd1 := 0;
     pDB^.medtype := 0;
     pDB^.bd_len := 0;


     mscmd.lunit := pSB^.LUN;
     mscmd.reqlen := 36;

     iotemp := ScsiHandleSession(pSB,
			      addr(mscmd), sizeof(mscmd),
			      { addr(msdata)} nil, 0, {sizeof(msdata), }
				    false,
			      pDB, 36 {sizeof(msdata)} , false);

     IF IOTEMP <> 0 THEN  { allow one re-try }
	iotemp := ScsiHandleSession(pSB,
			      addr(mscmd), sizeof(mscmd),
			      { addr(msdata)} nil, 0, {sizeof(msdata), }
				    false,
			      pDB, 36 {sizeof(msdata)} , false);

     if iotemp <> 0 then
	ioresult := iotemp; { ?????????? }
end;
{==========================================================================}


{======================================================================}
procedure ScsiModeSelect(pSB:PtrSessionBlockType;
			 pDB : PtrModeSelectDataType;
			 sector_size : integer);
 type tricky_as_hell = record
     case boolean of
     FALSE: (i : integer);
     TRUE:  (c1,c2,c3,c4 : char);
  end;
 var mscmd : mode_select_cmd_type;
     msdata : mode_select_data_type;
     iotemp : integer;
     cram_it : tricky_as_hell;
     brute_force : packed array [0..255] of char;
begin
     mscmd := mode_select_cmd_const;
     cram_it.i := sector_size;
     pDB^.ms_data[5] := cram_it.c2;
     pDB^.ms_data[6] := cram_it.c3;
     pDB^.ms_data[7] := cram_it.c4;

     pDB^.ms_data[1] := chr(0);
     pDB^.ms_data[2] := chr(0);
     pDB^.ms_data[3] := chr(0);

     pDB^.ms_len := 0;
     pDB^.wp := false;
     pDB^.rsvd1 := 0;
     pDB^.medtype := 0;

     mscmd.lunit := pSB^.LUN;
     iotemp := ScsiHandleSession(pSB,
			      addr(mscmd), sizeof(mscmd),
			      { addr(msdata)} nil, 0, {sizeof(msdata), }
				    false,
			      pDB, 12 {sizeof(msdata)} , false);

     IF IOTEMP <> 0 THEN  { allow one re-try }
	iotemp := ScsiHandleSession(pSB,
			      addr(mscmd), sizeof(mscmd),
			      { addr(msdata)} nil, 0, {sizeof(msdata), }
				    false,
			      pDB, 12 {sizeof(msdata)} , false);

     if iotemp <> 0 then
	ioresult := iotemp; { ?????????? }
end;
{==========================================================================}
procedure ScsiDiscReadOnce( pSB:PtrSessionBlockType;
			BlockStart, NumBlocks, NumBytesBlock:integer;
			Buffer:ANYPTR);
var
	rcmd:read_cmd_type;
	tries:integer;
begin
	with pSB^ do
		if Overlap then
			ioresult := ord(zbadmode)
		else
		begin
			tries := 1;
			repeat
				tries := tries + 1;
				rcmd := read_cmd_const;
				rcmd.lunit := LUN;
				rcmd.block_n := BlockStart;
				rcmd.lmsb  := NumBlocks div Hex('100');
				rcmd.llsb  := NumBlocks mod Hex('100');
				ioresult   := ScsiHandleSession(pSB,
						   addr(rcmd), sizeof(rcmd),
						   Buffer, NumBlocks*NumBytesBlock, true,
						   Nil, 0, false);
			until (ioresult <> ord(zbadblock)) or (tries >= 2);
		end;
end;

{================================================================}
procedure SyncTeac(pSB : PtrSessionBlockType);
var sense_size : integer;
    data_block : mode_sense_data_type;

    fake_buffer : packed array[0..2047] of char; { big enough for what we do }
    real_buf : BufferBlockType;

    save_first : integer;
    read_worked : boolean;
    done : boolean;
    cylinders_should_be : integer;
    test_block : integer;
    saved_cylinders : integer;
    TEMPIOR : integer;
    saveior : integer;

begin
  saveior := ioresult;
  ioresult := 0;
  read_worked := FALSE;
  done := false;

  real_buf.BufPtr := addr(fake_buffer);
  real_buf.BufLen := 4;
  real_buf.DoDMA := FALSE;

  { Find out what the controller thinks the sector size is : }

  ScsiModeSense(pSB,ADDR(data_block),sense_size);
  cylinders_should_be := ord(data_block.ms_data[25]);

  if sense_size = 666 then { mode sense did not work }
    begin
     tempior := ioresult;
     { writeln('WARNING - SCSI MODE SENSE FAILURE'); }
     done := TRUE; { just quit }
     ioresult := tempior;
    end;

  save_first := sense_size;


  while not done do
   begin

    ioresult := 0;
    ScsiDiscReadOnce(pSB,0,1,sense_size,addr(real_buf));

    if ioresult = 0 then
     begin
      read_worked := TRUE;
      done := TRUE; { now in sync }
    end;

   if ioresult = 1 then   { Read Failure }
    begin

      { vary the sector size and then try again , until
	we read successfully or we try all 3 possible
	sizes }

      if sense_size = 256 then sense_size := 1024
      else if sense_size = 1024 then sense_size := 512
      else if sense_size = 512 then sense_size := 256
      else done := TRUE; { should never happen but ... just quit }

      if not done then
	begin
	 { WRITELN('SECTOR SIZE ADJUST - CYLINDERS : ',cylinders_should_be); }
	 ioresult := 0; { reset it first }
	 InitModeSelect(pSB,addr(data_block),sense_size,
			cylinders_should_be);
	 if ioresult <> 0 then { mode select failed - just quit }
	  begin
	   tempior := ioresult;
	   { writeln('WARNING - SCSI MODE SELECT FAILURE'); }
	   done := TRUE;
	   ioresult := tempior;
	  end;
	end; { if not done }

     end { if ioresult = 1 }
    else
	{ if read failed with something not -1, there are other problems.
	  just fall through and do nothing }
	   done := TRUE;   { just give up }

      if sense_size = save_first then done := TRUE; { tried them all }
      if not done then
	  ScsiModeSense(pSB,ADDR(data_block),sense_size);

  end; { while not done }


     if read_worked then { Pascal Workstation Only }
      begin
	{ WRITELN('READ WORKED - ADJUSTING CYLINDER COUNT'); }
	if unitable^[43].letter = 'S' then
	  unitable^[43].dvrtemp := sense_size;
	if unitable^[3].letter = 'S' then
	  unitable^[3].dvrtemp := sense_size;

       ScsiModeSense(pSB,ADDR(data_block),sense_size);

       if sense_size <> 666 then
	begin
	 SAVED_CYLINDERS := ord(data_block.ms_data[25]);
	 { WRITELN('MODE SENSE - SENSE SIZE  : ',SENSE_SIZE);
	 writeln;
	 writeln;
	 writeln;
	 writeln;
	 WRITELN('MODE SENSE - SAVED CYLINDERS : ',saved_cylinders); }

	{ make sure cylinders = 77 or 80 depending ... }
	 if sense_size = 512 then
	   begin { could be 77 or 80 ? }

	    if data_block.medtype = 128 then { medium density }
	     begin
	      { WRITELN('GOT MEDIUM DENSITY <<<<<<<<<<<<<<<<'); }
	      ioresult := 0;
	      test_block := 1390; { in cylinder 78 }

	      { controller has to think 80 before this test : }
	      if SAVED_CYLINDERS  <> 80 then
		InitModeSelect(pSB,ADDR(data_block),sense_size,80);

	      ScsiDiscReadOnce(pSB,test_block,1,sense_size,addr(real_buf));
	      { IF IORESULT <> 0 THEN
	       BEGIN
		ioresult := 0;
		ScsiDiscReadOnce(pSB,test_block,1,sense_size,addr(real_buf));
	       END; }

	      if ioresult <> 0 then
	       begin
		{ writeln('read failed from ',test_block); }
		cylinders_should_be := 77;
	       end
	      else
	       BEGIN
		{ writeln('read worked from ',test_block); }
		cylinders_should_be := 80;
	       end;
	    end; { medtype = 128 }

	    if data_block.medtype = 136 then { HIGH density }
	     begin
	      { WRITELN('GOT HIGH DENSITY <<<<<<<<<<<<<<<<'); }
	      ioresult := 0;
	      test_block := 2860; { in cylinder 78 }

	      { controller has to think 80 before this test : }
	      if SAVED_CYLINDERS  <> 80 then
		InitModeSelect(pSB,ADDR(data_block),sense_size,80);

	      ScsiDiscReadOnce(pSB,test_block,1,sense_size,addr(real_buf));
	      { IF IORESULT <> 0 THEN
	       BEGIN
		ioresult := 0;
		ScsiDiscReadOnce(pSB,test_block,1,sense_size,addr(real_buf));
	       END; }

	      if ioresult <> 0 then
	       begin
		{ writeln('read failed from ',test_block); }
		cylinders_should_be := 77;
	       end
	      else
	       BEGIN
		{ writeln('read worked from ',test_block); }
		cylinders_should_be := 80;
	       end;
	    end; { medtype = 136 }

	   end { SENSE SIZE = 512 }

      ELSE { not 512 byte sectors }
	begin
	 cylinders_should_be := 77;
	 { writeln('NOT 512 - setting to 77'); }
	end;

     { writeln; writeln; writeln; writeln; }
    ScsiModeSense(pSB,ADDR(data_block),sense_size);
    { tempior := ioresult;
    if ioresult <> 0 then
      writeln('MODE SENSE FAILED AT : ',sense_size)
    ELSE
      writeln('mode sense worked at : ',sense_size);
    ioresult := tempior; }

    SAVED_CYLINDERS := ord(data_block.ms_data[25]);

    { if saved_cylinders  <> cylinders_should_be then
     begin }
      { writeln('mode select - changing cylinders to : ',cylinders_should_be); }
      InitModeSelect(pSB,ADDR(data_block),sense_size,
		      cylinders_should_be);
      { if ioresult <> 0 then
       begin
	tempior := ioresult;
	writeln('WARNING - MODE SELECT FAILURE');
	ioresult := tempior;
       end
      else
	writeln('MODE SELECT SUCCESSFUL TO : ',sense_size,' ',cylinders_should_be); }
     { end
     else
    writeln('mode select not called - cylinders : ',cylinders_should_be); }
   end;
   { WRITELN('end OF READ_WORKED'); }
 end; { read worked }
     ioresult := saveior; { RESTORE PREVIOUS IORESULT }
end; { procedure sync_teac }


procedure ScsiDevInfo(  pSB:PtrSessionBlockType;
			var DevType, AnsiVersion:integer;
			var Removable:boolean;
			var VendorString:string255);
var
	icmd:inquiry_cmd_type;
	idata:inquiry_data_type;
	len:integer;
	s1, s2:string255;
begin
	with pSB^ do
		if Overlap then
			ioresult := ord(zbadmode)
		else
		begin
			icmd := inquiry_cmd_const;
			icmd.lunit := LUN;
			ioresult := ScsiHandleSession(pSB,
						  addr(icmd), sizeof(icmd),
						  addr(idata), sizeof(idata), false,
						  Nil, 0, false);
		end;

	s1 := '<indeterminate SCSI device>';
	setstrlen(s2, 0);
	if ioresult = ORD(inoerror) then
	begin
		DevType := idata.device_type;
		AnsiVersion := idata.ansi_version;
		Removable := idata.rmb;

		len := idata.vendlen;
		if len >= 3 then
			len := len - 3
		else
			len := 0;
		if (len > 0) then
		begin
			if len >= 8 then {get the vendor name}
			begin
				s1 := strrtrim(str(idata.vendor, 4, 8));
				len := len - 8;
			end
			else
				len := 0;

			if len > 16 then
				len := 16;

			if len > 0 then {get the product number}
			begin
				s2 := strrtrim(str(idata.vendor, 4+8, len));
				len := 0;
			end;
		end;
	end;

	if strlen(s2) > 0 then
		VendorString := s1 + '-' + s2
	else
		VendorString := s1;
end;


procedure ScsiCheckDev(    pSB:PtrSessionBlockType);
var
	tcmd:test_cmd_type;
	devtype, ver : integer;
	moveable : boolean;
	vstring : STRING255;
begin
	with pSB^ do
		if Overlap then
			ioresult := ord(zbadmode)
		else
		begin
			tcmd := test_cmd_const;
			tcmd.lunit := LUN;
			ioresult := ScsiHandleSession(pSB,
						  addr(tcmd), sizeof(tcmd),
						  Nil, 0, false,
						  Nil, 0, false);


			if ioresult = ord(zmediumchanged) then
			 begin
			     VSTRING := 'xxxx';
			     ScsiDevInfo(pSB,devtype,ver,moveable,vstring);
			      IF ((vstring[1] = 'T') and (vstring[2] = 'E')
				 and (vstring[3] = 'A') and (vstring[4] = 'C'))
				 then  syncteac(pSB)  ;
			  ioresult := ord(zmediumchanged);
			 end;


		end;
end;



procedure ScsiDiscSize( pSB:PtrSessionBlockType;
			var NumBytesBlock, NumBlocksTrack,
			    NumTracksCylinder, NumCylinders:integer);
var
	rccmd:read_capacity_cmd_type;
	rcdata:read_capacity_data_type;
	mscmd:mode_sense_cmd_type;
	msdata:mode_sense_data_type;
	i,iotemp:integer;
	NumBlocks, TotBytes, NumBytesTrack:integer;
	Page4Found:boolean;
	pPage:pPageType;
	TotLen:integer;

	devtype, ver : integer;
	moveable,have_teac  : boolean;
	vstring : STRING255;

begin
	ioresult := ord(inoerror);
	try
		with pSB^ do
			if Overlap then
			begin
				iotemp := ord(zbadmode);
				escape(-10);
			end
			else
			begin
				rccmd := read_capacity_cmd_const;
				rccmd.lunit := LUN;
			end;
		{
		  get the disk capacity and the number of sectors per track.
		  If unable to obtain the sectors per track, then use
		  the following table:

			0 -   8 Meg =  4Ksectors/track
			8 - 128 Meg =  8Ksectors/track
		      128 - 256 Meg = 16
		      256+          = 32
		}

			     VSTRING := 'xxxx';
			     have_teac := FALSE;
			     ScsiDevInfo(pSB,devtype,ver,moveable,vstring);
			       if strlen(vstring) >= 4 then
				 IF ((vstring[1] = 'T') and (vstring[2] = 'E')
				 and (vstring[3] = 'A') and (vstring[4] = 'C'))
				 then begin
					have_teac := TRUE;
					syncteac(pSB);
					end;

		for i := 1 to 2 do
		begin
			iotemp := ScsiHandleSession(pSB,
						addr(rccmd), sizeof(rccmd),
						addr(rcdata), sizeof(rcdata), false,
						nil, 0, false);

			if iotemp = ord(inoerror) then
			begin
				if i = 1 then
				begin
					NumBlocks := rcdata.block_n;
					NumBytesBlock := rcdata.capacity;
					TotBytes := NumBlocks*NumBytesBlock;
				end
				else
				 begin
					NumBlocksTrack := rcdata.block_n + 1;
				 end;
			end
			else
			begin
			     { IF have_teac then
			       begin
				    writeln('IT WAS A TEAC and escaping : ',iotemp);
			       end; }
				escape(-10);
			end;
			if (i = 1) then
				rccmd.pmi := true;
		end;


		if (NumBlocksTrack >= NumBlocks) or (NumBlocksTrack < 0) then
		begin
			{
			  no delay block so have to fake it as per above table.
			}
			if TotBytes < 8*hex('100000') then
				NumBytesTrack := 4*hex('400')
			else if TotBytes < 128*hex('100000') then
				NumBytesTrack := 8*hex('400')
			else if TotBytes < 256*hex('100000') then
				NumBytesTrack := 16*hex('400')
			else
				NumBytesTrack := 32*hex('400');
			{TotBytes in a sector is a power of 2, so #blocks will divide evently}
			NumBlocksTrack := NumBytesTrack DIV NumBytesBlock
		end;


		{
		  attempt to get the number of tracks per cylinder.  This is actually
		  the number of surfaces, which is the number of heads.  Page 4 of the
		  data returned from the Mode Sense command contains the number of
		  heads.  However, this is not a required command, nor is this required
		  information.  Therefore, attempt to get the info, and if unsuccessful
		  use the following table:

			  0 -  64Mbytes =  2 heads
			 64 - 128Mbytes =  4 heads
			128 - 256Mbytes =  8 heads
			256+            = 16 heads
		}
		Page4Found := false;
		mscmd := mode_sense_cmd_const;
		mscmd.lunit := pSB^.LUN;
		iotemp := ScsiHandleSession(pSB,
					addr(mscmd), sizeof(mscmd),
					addr(msdata), sizeof(msdata), false,
					nil, 0, false);
		if iotemp = ord(inoerror) then
		begin
		  IF have_teac then { page 5 not page 4 !!!!!! }
		    begin
		      TotLen := msdata.ms_len - msdata.bd_len - 3;
		      pPage := addr(msdata.ms_data[msdata.bd_len]);
			while (TotLen > 0) and (pPage^.PageCode <> 5) do
			begin
				TotLen := TotLen - (pPage^.PageLen + 2);
				pPage := addr(pPage^, pPage^.PageLen + 2);
			end;
			if pPage^.PageCode = 5 then
			begin
				Page4Found := true;
				NumCylinders := ord(charptr(addr(pPage^,9))^);
				NumBlocksTrack := ord(charptr(addr(pPage^,5))^);
				NumTracksCylinder := ord(charptr(addr(pPage^,4))^);
			end;


		    end
		   else  { same as before }
		     begin
			TotLen := msdata.ms_len - msdata.bd_len - 3;
			pPage := addr(msdata.ms_data[msdata.bd_len]);
			while (TotLen > 0) and (pPage^.PageCode <> 4) do
			begin
				TotLen := TotLen - (pPage^.PageLen + 2);
				pPage := addr(pPage^, pPage^.PageLen + 2);
			end;
			if pPage^.PageCode = 4 then
			begin
				Page4Found := true;
				NumTracksCylinder := ord(charptr(addr(pPage^,5))^);
			end;
		      end; { else }
		end;

		if not Page4Found then
		begin
			if TotBytes < 64*hex('100000') then
				NumTracksCylinder := 2
			else if TotBytes < 128*hex('100000') then
				NumTracksCylinder := 4
			else if TotBytes < 256*hex('100000') then
				NumTracksCylinder := 8
			else
				NumTracksCylinder := 16;
		end;

		if ((not have_teac) or (not Page4Found)) then
		  NumCylinders := TotBytes Div NumBytesBlock      {yields #blocks}
					 Div NumBlocksTrack     {yields #tracks}
					 Div NumTracksCylinder; {yields #cylinders}
	recover
		if escapecode <> -10 then
			escape(escapecode)
		else
			ioresult := iotemp;

end;

procedure ScsiDiscBlocks(pSB:PtrSessionBlockType;
			var NumBytesBlock, TotBlocks:integer);
var
      rccmd : read_capacity_cmd_type;
      rcdata : read_capacity_data_type;
      i:integer;
	devtype, ver : integer;
	moveable : boolean;
	vstring : STRING255;
	have_teac : boolean;
begin
	with pSB^ do
		if Overlap then
			ioresult := ord(zbadmode)
		else
		begin
		       have_teac := FALSE;
		       VSTRING := 'xxxx';
		       ScsiDevInfo(pSB,devtype,ver,moveable,vstring);
			if strlen(vstring) >= 4 then
			 IF ((vstring[1] = 'T') and (vstring[2] = 'E')
			  and (vstring[3] = 'A') and (vstring[4] = 'C'))
			    then
			     BEGIN
			       syncteac(pSB);
			       { writeln('SYNCED FROM ScsiDiscBlocks'); }
			       have_teac := TRUE;
			     END;

			rccmd := read_capacity_cmd_const;
			rccmd.lunit := LUN;
			ioresult := ScsiHandleSession(pSB,
					 addr(rccmd), sizeof(rccmd),
					 addr(rcdata), sizeof(rcdata), false,
					 Nil, 0, false);
		end;

	if ioresult = ORD(inoerror) then
	begin
		NumBytesBlock := rcdata.capacity;
		TotBlocks := rcdata.block_n+1;
	end;


end;

procedure ScsiDiscRead( pSB:PtrSessionBlockType;
			BlockStart, NumBlocks, NumBytesBlock:integer;
			Buffer:ANYPTR);
var
	rcmd:read_cmd_type;
	tries:integer;
begin
	with pSB^ do
		if Overlap then
			ioresult := ord(zbadmode)
		else
		begin
			tries := 0;
			repeat
				tries := tries + 1;
				rcmd := read_cmd_const;
				rcmd.lunit := LUN;
				rcmd.block_n := BlockStart;
				rcmd.lmsb  := NumBlocks div Hex('100');
				rcmd.llsb  := NumBlocks mod Hex('100');
				ioresult   := ScsiHandleSession(pSB,
						   addr(rcmd), sizeof(rcmd),
						   Buffer, NumBlocks*NumBytesBlock, true,
						   Nil, 0, false);
			until (ioresult <> ord(zbadblock)) or (tries >= 2);
		end;
end;

procedure ScsiDiscWrite(pSB:PtrSessionBlockType;
			BlockStart, NumBlocks, NumBytesBlock:integer;
			Buffer:ANYPTR);
var
	wcmd:write_cmd_type;
	tries:integer;
begin
	with pSB^ do
		if Overlap then
			ioresult := ord(zbadmode)
		else
		begin
			tries := 0;
			repeat
				tries := tries + 1;
				wcmd := write_cmd_const;
				wcmd.lunit := LUN;
				wcmd.block_n := BlockStart;
				wcmd.lmsb  := NumBlocks div Hex('100');
				wcmd.llsb  := NumBlocks mod Hex('100');
				ioresult   := ScsiHandleSession(pSB,
						   addr(wcmd), sizeof(wcmd),
						   Nil, 0, false,
						   Buffer, NumBlocks*NumBytesBlock, true);
			until (ioresult <> ord(zbadblock)) or (tries >= 2);
		end;
end;

procedure ScsiDiscFormat(pSB:PtrSessionBlockType;
			InterLeave:s_short);
var
	saveDoNotDisconnect:boolean;
	fcmd:format_cmd_type;
begin
	with pSB^ do
		if Overlap then
			ioresult := ord(zbadmode)
		else
		begin
			fcmd := format_cmd_const;
			fcmd.lunit := LUN;
			fcmd.il_msb := Interleave Div HEX('100');
			fcmd.il_lsb := Interleave Mod HEX('100');
			saveDoNotDisconnect := DoNotDisconnect;
			DoNotDisconnect := false;
			ioresult    := ScsiHandleSession(pSB,
						    addr(fcmd), sizeof(fcmd),
						    nil, 0, false,
						    nil, 0, false);
			DoNotDisconnect := saveDoNotDisconnect;
		end;
end;

procedure ScsiDiscPrevent(  pSB:PtrSessionBlockType);
var
	pcmd:prevent_allow_cmd_type;
begin
	with pSB^ do
		if Overlap then
			ioresult := ord(zbadmode)
		else
		begin
			pcmd := prevent_cmd_const;
			pcmd.lunit := LUN;
			ioresult := ScsiHandleSession(pSB,
					 addr(pcmd), sizeof(pcmd),
					 Nil, 0, false,
					 Nil, 0, false);
		end;
end;

procedure ScsiDiscAllow(    pSB:PtrSessionBlockType);
var
	acmd:prevent_allow_cmd_type;
begin
	with pSB^ do
		if Overlap then
			ioresult := ord(zbadmode)
		else
		begin
			acmd := allow_cmd_const;
			acmd.lunit := LUN;
			ioresult := ScsiHandleSession(pSB,
					 addr(acmd), sizeof(acmd),
					 Nil, 0, false,
					 Nil, 0, false);
		end;
end;


end. {module SCSIIF}
@


55.3
log
@a few minor changes where checking device string for TEAC.
@
text
@@


55.2
log
@added a few lines to save and restore ioresult upon entry and
exit to SyncTeac.
@
text
@d1662 2
a1663 1
			     IF ((vstring[1] = 'T') and (vstring[2] = 'E')
d1822 2
a1823 1
		       IF ((vstring[1] = 'T') and (vstring[2] = 'E')
@


55.1
log
@Automatic bump of revision number for PWS version 3.25A
@
text
@d1312 1
d1315 1
d1512 1
a1512 1

@


54.11
log
@Continued enhancements to SyncTeac. JWH 8/4/91.
@
text
@@


54.10
log
@Changed the way vstring is initialized in ScsiCheckDev.
@
text
@a52 4




d178 10
d1117 9
d1127 35
d1163 59
d1298 1
a1298 1
procedure Sync_Teac(pSB : PtrSessionBlockType);
d1308 4
d1325 2
d1329 1
d1332 1
d1364 1
d1366 2
a1367 1
	 ScsiModeSelect(pSB,addr(data_block),sense_size);
d1370 1
d1373 1
d1384 2
d1392 1
a1396 1
      end;
d1398 113
d1583 1
a1583 1
	vstring : string255;
d1600 3
a1602 3
			   vstring := 'xxxx';
			   ScsiDevInfo(pSB,devtype,ver,moveable,vstring);
			   IF ((vstring[1] = 'T') and (vstring[2] = 'E')
d1604 1
a1604 1
				 then sync_teac(pSB);
d1627 5
d1656 11
d1683 1
d1685 1
d1689 4
d1740 21
d1773 1
d1788 2
a1789 1
		NumCylinders := TotBytes Div NumBytesBlock      {yields #blocks}
d1806 4
d1816 12
d1841 2
@


54.9
log
@initialized a variable.
@
text
@d1364 1
a1364 2
			   vstring[1] := ' '; vstring[2] := ' ';
			   vstring[3] := ' '; vstring[4] := ' ';
@


54.8
log
@Added routine ScsiDiscReadOnce for use with the rouitne Sync_Teac.
@
text
@d1364 2
@


54.7
log
@Removed the second read try from Sync_Teac as ScsiReadDisc already does
at least two tries. This is for performance reasons.
@
text
@a1112 1

d1160 29
a1189 1

d1225 1
a1225 1
    ScsiDiscRead(pSB,0,1,sense_size,addr(real_buf));
@


54.6
log
@minor changes.
@
text
@a1205 14
  { allow one READ retry }

    if ioresult <> 0 then
     begin
      ioresult := 0;
      ScsiDiscRead(pSB,0,1,sense_size,addr(real_buf));
      if ioresult = 0 then { this time it worked }
       begin
	read_worked := TRUE;
	done := TRUE; { now in sync }
       end;
     end;


@


54.5
log
@moved a new type out of the SCSI common area.
@
text
@d1185 1
a1185 1
  if sense_size = 666 then
d1187 1
a1187 1
     writeln('WARNING - SCSI MODE SENSE FAILURE');
d1190 1
a1231 2
      if sense_size = save_first then done := TRUE; { tried them all }

d1236 1
a1236 1
	 if ioresult <> 0 then
d1238 1
a1238 1
	   writeln('WARNING - SCSI MODE SELECT FAILURE');
d1248 3
@


54.4
log
@getting the parameters right, etc.
@
text
@a55 11
      mode_select_cmd_type = packed record
			   op_code : byte;
			   lunit   : 0..7;
			   pf      : 0..1;
			   rsvd1   : 0..7;
			   sp      : 0..1;
			   rsvd2   : byte;
			   rsvd3   : byte;
			   reqlen  : byte;
			   pad2    : byte;
			 end;
a56 14
     mode_select_data_type = packed record
			   ms_len  : byte;
			   medtype : byte;
			   wp      : boolean;
			   rsvd1   : 0 .. 127;
			   bd_len  : byte;
			   ms_data : packed array [ 0 .. 255 ] of char;
			 end;



      PtrModeSenseDataType = ^mode_sense_data_type;
      PtrModeSelectDataType = ^mode_select_data_type;

d119 25
@


54.3
log
@Added a couple types I forgot.
@
text
@a55 20
      mode_sense_cmd_type = packed record
			   op_code : byte;
			   lunit   : 0..7;
			   pad0    : 0..31;
			   pcf     : 0..3;
			   pg_code : 0..hex('3f');
			   pad1    : byte;
			   reqlen  : byte;
			   pad2    : byte;
			 end;

     mode_sense_data_type = packed record
			   ms_len  : byte;
			   medtype : byte;
			   wp      : boolean;
			   rsvd1   : 0 .. 127;
			   bd_len  : byte;
			   ms_data : packed array [ 0 .. 255 ] of char;
			 end;

d360 12
d1330 3
@


54.2
log
@Added the routines scsimodesense, scsimodeselect, and sync_teac. Also
shifted the position of ScsiDevInfo to be above ScsiCheckDev so it can
be called by the latter. Also added code to ScsiCheckDev to rty syncing
the TEAC in the event a TEAC has the medium changed. JWH 6/20/91.
@
text
@d53 49
@


54.1
log
@Automatic bump of revision number for PWS version 3.24
@
text
@d1030 16
a1045 3
procedure ScsiCheckDev(    pSB:PtrSessionBlockType);
var
	tcmd:test_cmd_type;
d1047 22
a1068 12
	with pSB^ do
		if Overlap then
			ioresult := ord(zbadmode)
		else
		begin
			tcmd := test_cmd_const;
			tcmd.lunit := LUN;
			ioresult := ScsiHandleSession(pSB,
						  addr(tcmd), sizeof(tcmd),
						  Nil, 0, false,
						  Nil, 0, false);
		end;
d1071 1
d1073 149
d1283 31
@


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.1
log
@Automatic bump of revision number for PWS version 3.23c
@
text
@@


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
@
Fixed problem with recursive call to RequestSense not actually
stopping!  Also, a bunch more $DEBUG$ code was added.
Finally, for ScsiDiscSize, a safer check was put in for
verifying page 4 is found.
@
text
@@


45.1
log
@Automatic bump of revision number for PWS version 3.23C
@
text
@d285 3
a287 1
			   pad1    : shortint;
d325 2
d940 5
d950 7
a956 2
					if PtrS_Byte(CmdPtr)^ <> hex('03') {request_sense} then
						sense := RequestSense(pSB)
d958 4
d963 1
d966 4
d971 1
d973 4
d978 1
a980 1
					C := CHARPTR(CmdPtr)^;
d1225 1
a1225 1
			if (TotLen > 0) then
@


44.3
log
@
SCSILIB was missing NIL pointers for pSB.  SCSILIB really should
have all of the compiler built in error checking as it is
a buffer between the users program and the driver.
@
text
@@


44.2
log
@
Updated ScsiSBInit interface to match documentation. ANYPTR was
changed to PtrDeviceAddressVectorsType.
@
text
@d9 4
a12 4
$iocheck off$
$ovflcheck off$
$range off$
$stackcheck off$
@


44.1
log
@Automatic bump of revision number for PWS version 3.23B
@
text
@d133 1
a133 1
				    pDAV:PtrDeviceAddressVectorsType);
d756 1
a756 1
procedure ScsiSBInit(pSB:ANYPTR; pDAV:PtrDeviceAddressVectorsType);
d765 1
a765 1
	with PtrSessionBlockType(pSB)^, pDAV^ do
@


43.2
log
@Updated interface to ScsiSBInit.  Got rid of ANYPTR for pDAV.
@
text
@@


43.1
log
@Automatic bump of revision number for PWS version 3.23aA
@
text
@d133 1
a133 1
				    pDAV:ANYPTR);
d756 1
a756 1
procedure ScsiSBInit(pSB:ANYPTR; pDAV:ANYPTR);
d765 1
a765 1
	with PtrSessionBlockType(pSB)^, PtrDeviceAddressVectorsType(pDAV)^ do
@


42.3
log
@changed tables on to table off.
two new internal error codes were added.
TDEBUG code was fixed up.
GetpMisc was added to verify that miscellaneous block is indeed legal.
lots of code was changed to call GetpMisc.
ScsiHandleSession modified to check if driver is really there, and generate
an error if it is not.
@
text
@@


42.2
log
@When requesting sense, the transfer type must be non overlapped
without disconnect.  Before, request sense used whatever the
original session block had, now it explicitly states what
is required.
@
text
@d15 1
a15 1
$tables on$
d60 2
a61 1
			    ScsiCatastrophicErr, ScsiBadMsg, ScsiTimeOutErr );
d564 3
a566 1
		    ztimeout];          {ScsiTimeOutErr}
d569 1
d572 1
d693 2
d723 1
d732 19
a782 1
	pMisc:PtrMiscTemplateType;
d794 1
a794 2
		pMisc := addr(isc_table[SelectCode].io_tmp_ptr^.drv_misc[1]);
		with pMisc^ do
d820 1
a826 2
	AbortCommandRetry := 0;
	1:
d829 3
d854 3
d878 13
d892 1
d904 1
a904 1
	$IF DEBUG$
d910 3
a918 1
				C := CHARPTR(PCMD)^;
d923 1
a923 1
			if (ord(charptr(pCmd)^) <> 0) then
d927 1
a927 1
				writeln(listing, 'TRACE FOR SCSI COMMAND: ',ord(c));
d952 1
a952 1
					C := CHARPTR(PCMD)^;
d966 1
d973 2
a974 1
	pMisc := addr(isc_table[SelectCode].io_tmp_ptr^.drv_misc[1]);
d980 3
a982 1
	end;
@


42.1
log
@Automatic bump of revision number for PWS version 3.23e
@
text
@d766 2
@


41.5
log
@Only abort sessions that are in the SessionRunning state.
@
text
@@


41.4
log
@Brought SCSIIF to functional complete (code complete) with
respect to the programmer's interface as defined in the SCSI ERS.
@
text
@d937 1
a937 1
		if (Overlap) and (SessionState <> SessionComplete) then
@


41.3
log
@For Command Stacking the tbderr was converted into the ScsiStackingErr.
@
text
@d15 1
d140 12
d187 6
a192 1
	pUnitType = ^unitentry;
a398 3
				  advalid : boolean;
				  e_class : 0..7;
				  e_code  : 0..15;
d400 14
a413 9
				  1:(seg_num : byte;
				     filemark: boolean;
				     eom     : boolean;
				     ili     : boolean;
				     pad0    : boolean;
				     sensekey: 0..15;
				     byte3   : byte;
				     more    : pac18;);
				  2:(block_n : 0..16777215);
d415 1
d484 31
d528 19
a546 17
		    inoerror,
		    inoerror,
		    znotready,
		    zbadblock,
		    zbadhardware,
		    zbadmode,
		    zmediumchanged,
		    zprotected,
		    znoblock,
		    zcatchall,
		    zcatchall,
		    znodevice,
		    zcatchall,
		    znosuchblk,
		    zcatchall,
		    zcatchall,
		    zbadmode, zcatchall, zcatchall];
d549 15
a563 15
		    inoerror,
		    zcatchall,
		    zcatchall,
		    zcatchall,
		    zstrangei,
		    znodevice,
		    znodevice,
		    zbadhardware,
		    zbadhardware,
		    ztimeout,
		    zcatchall,
		    zcatchall,
		    zcatchall,
		    zcatchall,
		    ztimeout];
d755 2
a756 1
	rsdata:request_sense_data_type;
d759 2
d762 1
a762 7
	rscmd := request_sense_cmd_const;
	rscmd.lunit := pSB^.LUN;
	i := ScsiHandleSession(addr(SB),
		     addr(rscmd), sizeof(rscmd),
		     addr(rsdata), sizeof(rsdata), false,
		     Nil, 0, false);
	if i = ord(inoerror) then
d764 20
a783 8
		if (rsdata.e_class = 7) and (rsdata.e_code = 0) then
			RequestSense := SenseType(rsdata.sensekey)
		else
			RequestSense := GetSenseFailed;
	end
	else
	begin
		RequestSense := GetSenseFailed;
a792 3
	status:status_type;
	sense:SenseType;
	uheep:anyptr;
d794 1
d826 1
a826 1
		if InternalStatus <> NoIntErr then
d828 40
d875 1
a875 1
			if (ord(charptr(pcmd)^) <> 0) then
d884 1
a884 1
			ScsiHandleSession := Ord(InternalXlateConst[InternalStatus]);
d893 1
a893 1
					if PtrS_Byte(pCmd)^ <> hex('03') {request_sense} then
d908 1
a908 10
				if (sense = sCommandAbort) and (AbortCommandRetry < 1) then
				begin
					$IF DEBUG$
						WRITELN('Retrying because of aborted command.');
					$END$

					AbortCommandRetry := AbortCommandRetry + 1;
					goto 1;
				end;
				ScsiHandleSession := ord(SenseXlateConst[sense]);
d911 1
a911 1
				ScsiHandleSession := ord(inoerror);
d914 1
a914 1
			ScsiHandleSession := ord(inoerror);
d918 32
d954 12
a965 6
	tcmd := test_cmd_const;
	tcmd.lunit := pSB^.LUN;
	ioresult := ScsiHandleSession(pSB,
				  addr(tcmd), sizeof(tcmd),
				  Nil, 0, false,
				  Nil, 0, false);
d979 13
a991 6
	icmd := inquiry_cmd_const;
	icmd.lunit := pSB^.LUN;
	ioresult := ScsiHandleSession(pSB,
				  addr(icmd), sizeof(icmd),
				  addr(idata), sizeof(idata), false,
				  Nil, 0, false);
d1050 11
a1060 2
		rccmd := read_capacity_cmd_const;
		rccmd.lunit := pSB^.LUN;
d1182 13
a1194 6
	rccmd := read_capacity_cmd_const;
	rccmd.lunit := pSB^.LUN;
	ioresult := ScsiHandleSession(pSB,
			 addr(rccmd), sizeof(rccmd),
			 addr(rcdata), sizeof(rcdata), false,
			 Nil, 0, false);
d1209 19
a1227 13
	tries := 0;
	repeat
		tries := tries + 1;
		rcmd := read_cmd_const;
		rcmd.lunit := pSB^.LUN;
		rcmd.block_n := BlockStart;
		rcmd.lmsb  := NumBlocks div Hex('100');
		rcmd.llsb  := NumBlocks mod Hex('100');
		ioresult   := ScsiHandleSession(pSB,
				   addr(rcmd), sizeof(rcmd),
				   Buffer, NumBlocks*NumBytesBlock, true,
				   Nil, 0, false);
	until (ioresult <> ord(zbadblock)) or (tries >= 2);
d1237 19
a1255 14
	tries := 0;
	repeat
		tries := tries + 1;
		wcmd := write_cmd_const;
		wcmd.lunit := pSB^.LUN;
		wcmd.block_n := BlockStart;
		wcmd.lmsb  := NumBlocks div Hex('100');
		wcmd.llsb  := NumBlocks mod Hex('100');
		ioresult   := ScsiHandleSession(pSB,
				   addr(wcmd), sizeof(wcmd),
				   Nil, 0, false,
				   Buffer, NumBlocks*NumBytesBlock, true);
	until (ioresult <> ord(zbadblock)) or (tries >= 2);

d1261 1
d1264 17
a1280 9
	fcmd := format_cmd_const;
	fcmd.lunit := pSB^.LUN;
	fcmd.il_msb := Interleave Div HEX('100');
	fcmd.il_lsb := Interleave Mod HEX('100');
	pSB^.DoNotDisconnect := false;
	ioresult    := ScsiHandleSession(pSB,
				    addr(fcmd), sizeof(fcmd),
				    nil, 0, false,
				    nil, 0, false);
d1284 2
d1287 12
d1302 2
d1305 12
@


41.2
log
@Added the DAV interface for ScsiSBInit.
Also, updated some DEBUG code (this is not normally compiled in).
Also, SCSI_DEFS was modified a little, so the corresponding
changes took place here.
@
text
@d55 5
a59 5
	InternalErrType = ( NoIntErr, tbderr, RunLevelErr, StateMachineErr,
			    ScsiInteruptErr, ScsiAddressErr, SelectRetryErr,
			    ScsiManXferErr, ScsiXferErr,XferRetryErr,
			    ScsiEscapeErr, ScsiPhaseErr, ScsiCatastrophicErr,
			    ScsiBadMsg, ScsiTimeOutErr );
@


41.1
log
@Automatic bump of revision number for PWS version 3.23d
@
text
@d21 1
a21 1
{}
d52 1
a54 2
	ScsiProtoType = (Asynchronous, Synchronous, Fastest);

d69 2
d90 1
a90 1
				SessionCompleteCallBack:Procedure;
a106 1
       PtrSessionBlockType = ^SessionBlockType;
d112 13
d131 1
a131 1
				    pUnit:ANYPTR);
d675 1
a675 1
procedure ScsiSBInit(pSB:ANYPTR; pUnit:ANYPTR);
d684 1
a684 1
	with PtrSessionBlockType(pSB)^, pUnitType(pUnit)^ do
d759 5
a763 4
		$IF DEBUG$
			C := CHARPTR(PCMD)^;
			 WRITELN; WRITELN('SCSI COMMAND IS: ',ord(c):1);
		 $END$
d769 2
a770 2
				{ C := CHARPTR(PCMD)^;
				{ WRITELN('SCSI COMMAND IS: ',ord(c):1);
d774 2
d781 1
d803 2
a804 2
					{ C := CHARPTR(PCMD)^;
					{ WRITELN('SCSI COMMAND IS: ',ord(c):1);
@


40.9
log
@
pws2rcs automatic delta on Thu Dec 21 14:54:59 MST 1989
@
text
@@


40.8
log
@corrected retry loop logic for disc read and write.
@
text
@d31 1
a31 1
module SCSIIF;
@


40.7
log
@Use moveleft to initialize SCSI block to 0 instead of my own loop.
Added stubs for ScsiDiscPrevent and ScsiDiscAllow - required for CTABLE.
@
text
@d1051 1
a1051 1
	until (ioresult <> ord(zbadblock)) or (tries < 2);
d1073 1
a1073 1
	until (ioresult <> ord(zbadblock)) or (tries < 2);
@


40.6
log
@Updated to support tracing after programmer's interface changes have been made.
@
text
@d33 1
a33 1
import sysglobals, iodeclarations {{, STATE_PROCS, LOADER{needed for TDEBUG};
d150 5
d665 1
a665 1
	pChar:PtrChar;
d667 4
a670 6
	pChar := pSB;
	for i := 1 to sizeof(SessionBlockType) do
	begin
		pChar^ := #0;
		pChar  := addr(pChar^, 1);
	end;
d1092 9
@


40.5
log
@Updated SCSIIF to match current version of Programmer's Interface.
@
text
@d33 1
a33 1
import sysglobals, iodeclarations {{, SCSI_DEFS ,STATE_PROCS, LOADER{needed for TDEBUG};
d47 2
d103 1
d497 27
d616 1
a616 1
    control := addr(sb.internalblock.StateControlRec);
d618 1
a618 1
    with control^, sb, sb.internalblock do
d745 2
a746 2
			WRITELN; WRITELN('SCSI COMMAND IS: ',ord(c));
		$END$
d752 3
d783 3
@


40.4
log
@Updated SCSIIF to be a true programmer's interface file.  The SCSIIF module now
exports the types/consts required by the programmer and the programmer has
no knowledge of SCSI_DEFS.  A stream file has been created to copy out the
necessary info from SCSI_DEFS into SCSIIF with every compile.  OSFS:TURNIT.TEXT
requires modification.
@
text
@d130 1
a130 1
	procedure ScsiDiskSize(     pSB:PtrSessionBlockType;
d134 1
a134 1
	procedure ScsiDiskBlocks(    pSB:PtrSessionBlockType;
d137 1
a137 1
	procedure ScsiRead(         pSB:PtrSessionBlockType;
d141 1
a141 1
	procedure ScsiWrite(        pSB:PtrSessionBlockType;
d145 1
a145 1
	procedure ScsiFormat(       pSB:PtrSessionBlockType;
d841 1
a841 1
procedure ScsiDiskSize( pSB:PtrSessionBlockType;
d973 1
a973 1
procedure ScsiDiskBlocks(pSB:PtrSessionBlockType;
d993 1
a993 1
procedure ScsiRead(     pSB:PtrSessionBlockType;
d1015 1
a1015 1
procedure ScsiWrite(    pSB:PtrSessionBlockType;
d1038 1
a1038 1
procedure ScsiFormat(   pSB:PtrSessionBlockType;
@


40.3
log
@Modifications for DMA support.
DMA is only done with disc read and disc writes.
@
text
@a18 2
{}
$include 'SCSI_DEFS'$
d33 1
a33 1
import sysglobals, iodeclarations, SCSI_DEFS {{,STATE_PROCS, LOADER{needed for TDEBUG};
d36 72
@


40.2
log
@Modifications to help out when debugging.

Modifications to perform one retry of the command when the sense
is AbortCommand.
@
text
@d49 3
a51 2
				    pDIn:ANYPTR; lDIn:integer;
				    pDOut:ANYPTR; lDOut:integer):integer;
d593 2
a594 2
		     addr(rsdata), sizeof(rsdata),
		     Nil, 0);
d610 2
a611 2
			pDIn:ANYPTR; lDIn:integer;
			pDOut:ANYPTR; lDOut:integer):integer;
d632 1
a632 4
			if BufLen < 32 then
				DoDMA := FALSE
			else
				DoDMA := TRUE;
d638 1
a638 4
			if BufLen < 32 then
				DoDMA := FALSE
			else
				DoDMA := TRUE;
d708 2
a709 2
				  Nil, 0,
				  Nil, 0);
d727 2
a728 2
				  addr(idata), sizeof(idata),
				  Nil, 0);
d803 2
a804 1
						addr(rcdata), sizeof(rcdata), nil, 0);
d862 2
a863 1
					addr(msdata), sizeof(msdata), nil, 0);
d914 2
a915 2
			 addr(rcdata), sizeof(rcdata),
			 Nil, 0);
d940 3
a942 4
				   Buffer, NumBlocks*NumBytesBlock,
				   Nil, 0);
	until (ioresult = ord(inoerror)) or
	      ((ioresult = ord(zbadblock)) and (tries < 2));
d962 3
a964 4
				   Nil, 0,
				   Buffer, NumBlocks*NumBytesBlock);
	until (ioresult = ord(inoerror)) or
	      ((ioresult = ord(zbadblock)) and (tries < 2));
d980 2
a981 2
				    nil, 0,
				    nil, 0);
@


40.1
log
@Automatic bump of revision number for PWS version 3.23c
@
text
@d19 1
d21 3
d35 1
a35 3
{{
$search 'PWS_SCSI'$
{}
a36 2
import sysglobals, iodeclarations, SCSI_DEFS {{,STATE_PROCS, LOADER{};

d514 1
a514 1
    REWRITE(LISTING,'#6:');
d542 1
a542 1
    CLOSE(LISTING,'SAVE');
d611 1
d616 1
d621 2
a630 1
			Protocol := fastest;
a639 1
			Protocol := fastest {Asynchronous};
d659 4
d686 9
@


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


1.1
log
@Initial revision
@
text
@@
