IMD 1.17: 14/03/2012 8:40:51 SCSI B3466A 3.5" DS      SCSI  M'XHWIA_UTILTK B$HWI_UTILSTKfB)eMACHINE2T_KB1MACHINE3T_KB3MACHINE4T_K B5MACHINE5T_K B6 nOSD_HLT___KBG>OSD_LLT___KIBQHOSD_LLAT__K BSPWS_SCSIT_KBTSCSIIFT___K!CMSCSI_ISRT_K C SCSI_UTILTK$CSTATE_DRVTK'C OST_APT____K/CST_EPT____K4 CST_PROCST_K="C !ST_SDT____K_C#ST_TPT____KnC&FscsidiskT_KsPC2OCOMMANDST_KBC7AMACHINE1T_KCAMESSAGEST_K$CI]SCSI_DEFSTK2CT1  nosyms mname HWIA_UTILS src MODULE HWIA_UTILS; src import SCSI_DEFS; src export src procedure hwiAXfer(var XferBlock:XferBlockType; PtrScsiChip:PtrScsiChipType); src END; def HWIA_UTILS_HWIAXFER def HWIA_UTILS_HWIA_UST_EQUT___KCWST_XFERT__KD WMATCHSTRT_K/U).YMAKE_SCSITK. UGrMAKERT____K7@ &?*COMPILER 2w "READMET___)p S7READMET___K+  nTILS def HWIA_UTILS__BASE regScsiChip equ a4 intsOffset equ 9 sstsOffset equ 13 dataOffset equ 21 BitFIFOEmpty equ 0 BitFIFOFull  equ 1 regXferBlock equ a3 XferPhaseOffset equ 0 XferRetryCountOffset equ 2 XferSavedDataPointerOffset equ 4 XferSavedDataLengthOffset equ 8 XferDMACountOffset equ 12 XferBufPtrOffset equ 16 XferBufLenOffset equ 20 XferDoDMAOffset equ 24 regBufPtr equ a2 regChipData equ a1 regChipSst     y clr.w regBufLen ; dbra only works on 16 bits subq.l #1,regBufLen ; check for > 16 bit transfer bgt.s check_fifo_empty bra.s exit_restore fifo_empty equ * tst.b intsOffset(regScsiChip) beq.s check_f{ Hardware Interface Utilities Utilities that interface to the SCSI hardware are placed here. NOTE: Access to the hardware is not limited to this module. } module HWI_UTILS; import SCSI_DEFS, OSD_LL, SCSI_UTILS, HWIA_UTILS; export { Routines caifo_empty bra.s exit_restore outbound_xfer equ * ******************************************************************* * while (there is data in the buffer) * if fifo not full * output data * else fifo is full * lled by the state machine } Procedure hwiGetPhase(PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); Procedure hwiInitHW(PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); Procedure hwiHardReset(PtrSessionBlock:PtrSessionBlockTypes equ a0 regBufLen equ d2 HWIA_UTILS__BASE equ * HWIA_UTILS_HWIAXFER equ * ******************************************************************* * set up registers * predecrement regBu wait for an interrupt or fifo not full * on interrupt exit * wait for fifo to empty or an interrupt to occur ******************************************************************* check_fifo_full equ * btst #BitFIFOFull,(regChipSsts)fLen to compensate for dbra termination on -1. * if the register is < 0, then 0 or negative length, do nothing in * this case. ******************************************************************* move.l 8(sp),regXferBlock move.l 4(sp),regScsiChip le bne.s fifo_full move.b (regBufPtr)+,(regChipData) dbra regBufLen,check_fifo_full clr.w regBufLen ; dbra only works on 16 bits subq.l #1,regBufLen ; check for > 16 bit transfer bgt.s check_fifo_full wait_fifoa dataOffset(regScsiChip),regChipData lea sstsOffset(regScsiChip),regChipSsts move.l XferBufPtrOffset(regXferBlock),regBufPtr move.l XferBufLenOffset(regXferBlock),regBufLen subq.l #1,regBufLen blt.s exit_restore *******************_empty equ * btst #BitFIFOEmpty,(regChipSsts) bne.s exit_restore tst.b intsOffset(regScsiChip) beq.s wait_fifo_empty bra.s exit_restore fifo_full equ * tst.b intsOffset(regScsiChip) beq.s check_fifo_full * ************************************************ * determine if this is an inbound or outbound transfer ******************************************************************* cmpi.w #1,XferPhaseOffset(regXferBlock) bne.w outbound_xfer inbound_xfer  bra.s exit_restore exit_restore equ * ******************************************************************* * restore registers into the XferBlock. Add 1 to regBufLen * to get the true final count. This compensates for dbra * terminating onequ * ******************************************************************* * while (there is room in the buffer) * if fifo not empty * input data * else fifo is empty * wait for an interrupt or fifo not empty *  -1. ******************************************************************* move.l regBufPtr,XferBufPtrOffset(regXferBlock) addq.l #1,regBufLen move.l regBufLen,XferBufLenOffset(regXferBlock) ********************************************************* on interrupt exit ******************************************************************* check_fifo_empty equ * btst #BitFIFOEmpty,(regChipSsts) bne.s fifo_empty move.b (regChipData),(regBufPtr)+ dbra regBufLen,check_fifo_empt********** * restore stack and go back to caller ******************************************************************* move.l (sp)+,a0 addq.w #8,sp jmp (a0) HWIA_UTILS_HWIA_UTILS equ * rts END      ; Var ResultCode:S_SHORT); Procedure hwiGetMsgOut(PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); { hardware interface utility routines } Procedure hwiSCInitHW(Sc:S_TYPE_ISC); Procedure hwiSCHardReset(Sc:S_TYPE_ISC); function hwiGe else if SessionState <> SessionRunning then ResultCode := ORD(BusBusy) {Another Session is running} else {this session must be in an information transfer phase} begin ResultCode := PhaseTranslate[BusLines.t_phase]; end; end; end; {*********tCardPtr(PtrSessionBlock:PtrSessionBlockType):PtrScsiCardType; function hwiGetChipPtr(PtrSessionBlock:PtrSessionBlockType):PtrScsiChipType; function hwiManXfer(pSB:PtrSessionBlockType; var b:s_byte; hwPhase:phase_code; MORE, ReplyRequest:Boolea**************************************************************** * hwiInitHW ************************************************************************* * * On Input: nothing expected * * * Functional Description: * * Initialize the hardware tn):Boolean; function hwiProgXfer(pSB:PtrSessionBlockType):Boolean; function hwiStartDMAXfer(pSB:PtrSessionBlockType):Boolean; function hwiEndDMAXfer(pSB:PtrSessionBlockType; var ResultCode:S_SHORT):Boolean; implement {******************************hat this session is attached to. * * On Output: Hardware is initialized, ResultCode is NoEvent. * *************************************************************************} Procedure hwiInitHW(PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHOR******************************************* * hwiGetPhase ************************************************************************* * * On Input: nothing expected. * * * Functional Description: * * If the chip is not currently connected to tT); begin hwiSCInitHW(PtrSessionBlock^.SelectCode); ResultCode := ORD(NoEvent); end; {************************************************************************* * hwiHardReset ************************************************************************* he bus, then the * phase is either BusFree or BusBusy. * Otherwise, if this session is not running (chip is servicing another * session, then the phase is BusBusy. * Otherwise, the bus phase is that on the bus. * * * On Output: * * On Input: nothing expected * * * Functional Description: * * Toggle the Scsi Bus Reset Line for the bus that this session is * attached to. * * Reset all of the H/W registers for this select code. * * On Output: Reset Line isA phase event (see SCSI_DEFS) * * *************************************************************************} Procedure hwiGetPhase(PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); type PhaseTranslateType = Array[phase_code] of S_SHORT; con toggled, ResultCode is NoEvent. * *************************************************************************} Procedure hwiHardReset(PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); begin hwiSCHardReset(PtrSessionBlock^.SelectCode); Resultst PhaseTranslate = PhaseTranslateType[ord(DataPhase), ord(DataPhase), ord(CmdPhase), ord(StatusPhase), ord(BusFree), ord(ScsiErr), ord(MsgOut), ord(MsgIn)]; var BusLines:psns_type; begin with PtrSessionBlock^, InternalBlock.Code := ORD(NoEvent); end; {************************************************************************* * hwiGetMsgOut ************************************************************************* * * On Input: Path is active, but bus is not guaranteed pScBlock^.PtrScsiChip^ do begin BusLines.psns := psns.psns; if ssts.action = spc_not_connected then {chip is not being used} begin if BusLines.bsy or BusLines.sel then ResultCode := ORD(BusBusy) else ResultCode := ORD(BusFree); end to be in any * particular phase. A transfer may currently be active. * * Functional Description: * * Get the bus to a MsgOut phase. If a transfer is active, finish * it up first. * * On Output: MsgOut or ScsiErr. * * *     ctl.t_phase := psns.t_phase; if (psns.io) {input mode} then begin scmd.cmd := set_ack_req_cmd; repeat until (not psns.req) or (psns.t_phase = msg_out_phase); b := data_regs.temp; end else {output mode} begin datal Description: * * Initialize the hardware that is on the given select code. * * On Output: Hardware is initialized. * *************************************************************************} procedure hwiSCInitHW(Sc:S_TYPE_ISC); var pScBloa_regs.temp := #0; scmd.cmd := set_ack_req_cmd; repeat until (not psns.req) or (psns.t_phase = msg_out_phase); end; {raise atn prior to resetting ack} scmd.cmd := set_atn_cmd; osdDelay(1); scmd.cmd := reset_ack_req_cmd; ck:PtrSelectCodeBlockType; begin pScBlock := osdGetScBlock(Sc); with pScBlock^, PtrScsiChip^, PtrScsiCard^ do begin id_reg.reset := 0; { reset the card } sc_reg.ie := false; { disable card interupts } sctl.sctl := 0; sctl.sctl := reset_d************************************************************************} Procedure hwiGetMsgOut(PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); label 1; var XferCount:integer; RunLevel:integer; b:char; sb:s_byte; begin with PtrSessionBl end else begin scmd.cmd := set_atn_cmd; osdDelay(100); {let nice devices react.} end; hwiGetPhase(PtrSessionBlock, ResultCode); if ResultCode in [ord(MsgOut), ord(BusFree), ord(BusBusy)] then goto 1; end; { continue to trock^,InternalBlock.pScBlock^,PtrScsiChip^ do begin RunLevel := osdGetRunLevel; osdSetRunLevel(7); {no interrupts during this code!} hwiGetPhase(PtrSessionBlock, ResultCode); if ResultCode in [ord(MsgOut), ord(BusFree), ord(BusBusy)] tansfer at the targets beck and call until we get a message out phase, bus free phase, or bus busy. } repeat data_regs.tch := chr(0); data_regs.tcm := chr(0); data_regs.tcl := chr(0); pctl.t_phase := psns.t_phase; scmd.cmd := set_atn_hen goto 1; if ssts.action = spc_init_xfer then {transfer currently in progress} begin scmd.cmd := set_atn_cmd; osdDelay(100); osdStartTimer(2*one_second); repeat if scmd.prgx then {programattic transfer going on, probably won't happen}cmd; scmd.scmd := transfer_prgx + 1; {transfer with 0 padding} osdStartTimer(2 * one_second); repeat until (psns.t_phase = msg_out_phase) or (ssts.action = spc_init_xfer) or (ints.ints <> 0) or (osdTimeExpired); if os begin if psns.io then {inbound} begin if not ssts.dempty then begin b := data_regs.dreg; end; end else {output} begin if not ssts.dfull then begin data_regs.dreg := chr(0); enddTimeExpired then {target is not talking} begin ints.ints := ints.ints; hwiGetPhase(PtrSessionBlock, ResultCode); goto 1; end; repeat until (psns.t_phase = msg_out_phase) or (ints.ints <> 0); ints.ints := ints.ints; osdD; end; end {else dma transfer going on, will happen!} until (ints.ints <> 0) or (osdTimeExpired); osdDelay(1); ints.ints := ints.ints; hwiGetPhase(PtrSessionBlock, ResultCode); if ResultCode in [ord(MsgOut), ord(BusFree), ord(Buelay(1); {let bus lines settle} hwiGetPhase(PtrSessionBlock, ResultCode); until ResultCode in [ord(MsgOut), ord(BusFree), ord(BusBusy)]; 1: if ResultCode <> ord(MsgOut) then scmd.cmd := reset_atn_cmd; sctl.cr := TRUE; sctl.cr := FALSE; sBusy)] then goto 1; end else begin { the chip may or may not have been reset prior to entering this routine, so optionally transfer a byte manually. } if (psns.req) then {chip may have missed req so manual transfer} begin p osdSetRunLevel(RunLevel); end; end; {************************************************************************* * hwiSCInitHW ************************************************************************* * * On Input: nothing expected * * * Function     isable + control_reset; { ensure SPC disabled } osdDelay(1); { do required initialization of SPC registers } bdid := chr(7-config_reg.dev_addr); { use ones compliment of dev_addr } scmd.scmd := 0; tmod.tmod := 0; pctl.pctl := 0; ointer to the Card that this session is attached to. * * On Output: * * *************************************************************************} function hwiGetCardPtr(PtrSessionBlock:PtrSessionBlockType):PtrScsiCardType; begin hwiGetCardPtr := Ptr data_regs.temp := #0; data_regs.tch := #0; data_regs.tcm := #0; data_regs.tcl := #0; psns.sdgc := 0; ints.ints := ints.ints; { clear all interupts } { set up the control register, note interupts are not enabled. } if confiSessionBlock^.InternalBlock.pScBlock^.PtrScsiCard; end; {************************************************************************* * hwiGetChipPtr ************************************************************************* * * On Input: Nothing Expectg_reg.parity then sctl.sctl := RESET_DISABLE + arbit_enable + reselect_enable + parity_enable + int_enable else sctl.sctl := RESET_DISABLE + arbit_enable + reselect_enable + int_enable; sctl.rd := false; { clear reseed * * * Functional Description: * * Retrieve a pointer to the Chip that this session is attached to. * * On Output: * * *************************************************************************} function hwiGetChipPtr(PtrSessionBlock:PtrSest disable } config_reg.pal_reset := 1; osdDelay(1); end; end; {************************************************************************* * hwiSCHardReset ************************************************************************* * * On Input:sionBlockType):PtrScsiChipType; begin hwiGetChipPtr := PtrSessionBlock^.InternalBlock.pScBlock^.PtrScsiChip; end; {************************************************************************* * hwiManXfer ************************************************* nothing expected * * * Functional Description: * * Toggle the Scsi Bus Reset Line for the bus that is attached to the * given select code. * * Reset all of the H/W registers for this select code. * * On Output: Reset Line is togg************************ * * On Input: The bus is in the desired phase and the target is requesting * data be transfered (direction of transfer will be based on * what is on the bus). * * Functional Description: * * Transfeled. * *************************************************************************} procedure hwiSCHardReset(Sc:S_TYPE_ISC); var pScBlock:PtrSelectCodeBlockType; i:integer; begin pScBlock := osdGetScBlock(Sc); with pScBlock^, PtrScsiCard^, PtrScsiChir one byte of data in or out of the SCSI bus that is attached * to the given session. The caller must supply the expected bus phase * and the caller must anticipate the direction of the transfer. * * If the caller anticipates that the Ap^ do begin sc_reg.ie := false; { disable card interupts } sctl.sctl := 0; scmd.scmd := rst_out; osdDelay(1); hwiSCInitHW(Sc); for i := 0 to 7 do DeviceSynchParms[i].SynchState := NoSynch; osdDelay(one_second); end; end; {TN line should be on during the transfer * (more bytes of message out data will follow), then the caller must * indicate so in the MORE boolean. (On the last byte of message out * data, the MORE parameter should be set to false). * * ************************************************************************* * hwiGetCardPtr ************************************************************************* * * On Input: Nothing Expected * * * Functional Description: * * Retrieve a p If the caller anticipates a need to reply to this data, then by * definition, the ATN line must be raised prior to the ACK line being * released. In this case, set the ReplyRequest boolean. * * On Output: TRUE if the transfer was succes     ts = 0) then {xfer went o.k.} begin hwiManXfer := true; if (hwPhase = msg_in_phase) and (ReplyRequest) then scmd.cmd := set_atn_cmd; end else hwiManXfer := false; scmd.cmd := reset_ack_req_cmd; ints.ints := cmd_complete; et up. } { tell chip to commence a programmatic transfer } ints.ints := ints.ints; scmd.scmd := transfer_prgx; { wait for chip to respond } if ssts.action <> spc_init_xfer then begin osdStartTimer(one_second); repeat until (nd; { if this is the end of the manual transfer, then wait for a phase change. } if (not MORE) and (ints.ints = 0) and (psns.t_phase = hwPhase) then begin osdStartTimer(one_second); repeat until (psns.t_phase <> hwPhase) or osdTimeEssts.action = spc_init_xfer) or (ints.ints <> 0) or osdTimeExpired; if (ints.ints <> 0) then goto 2; if ssts.action <> spc_init_xfer then begin utlSetInternalErr(pSB, ScsiXferErr); goto 1; end; end; { execute the programmasful, FALSE otherwise. * * tbd - need to check for parity error and retransmit *************************************************************************} function hwiManXfer(pSB:PtrSessionBlockType; var b:s_byte; hwPhase:phase_code; MORE, ReplyReqxpired; if (psns.t_phase = hwPhase) then begin hwiManXfer := false; utlSetInternalErr(pSB, ScsiPhaseErr); end; end; end; end; {************************************************************************* * hwiProgXfer ***************uest:Boolean):Boolean; var retry_count : integer; begin with pSB^.InternalBlock.pScBlock^.PtrScsiChip^ do begin ints.ints := ints.ints; { wait for target to request transfer. this ensures that the target has set the bus they way he wants it. ********************************************************** * * On Input: The bus is in the desired phase and the target is requesting * data be transfered (direction of transfer will be based on * what is on the bus). The XferBlock } if (not psns.req) and (hwPhase = psns.t_phase) then begin osdStartTimer(one_second); repeat until (psns.req) or (hwPhase <> psns.t_phase) or osdTimeExpired; end; if (MORE) and (hwPhase = msg_out_phase) then begin scmd.cmd := set_ in the InternalBlock has * been set up. * * Functional Description: * * Set up the hardware for a programmatic transfer and execute it. * Process all follow on interrupts. * * On Output: TRUE if the transfer was successful, FAatn_cmd; end else begin scmd.cmd := reset_atn_cmd; end; if (not psns.req) or (hwPhase <> psns.t_phase) then begin {peripheral isn't talking or requested phase is not equal to real bus phase} hwiManXfer := false; end else {target hLSE otherwise. * if FALSE, internal error type has been set. * *************************************************************************} function hwiProgXfer(pSB:PtrSessionBlockType):Boolean; label 1,2; Var SaveInts:ints_type; ResultCodas raised req, requesting xfer} begin pctl.t_phase := hwPhase; if psns.io then {input operation} begin { data is actually on the bus, but temp is not set until ack command is given } scmd.cmd := set_ack_req_cmd; repee:S_SHORT; begin hwiProgXfer := false; with pSB^.InternalBlock, XferBlock, pScBlock^, PtrScsiChip^, PtrScsiCard^ do begin { set up transfer count } data_regs.tch := chr(XferBufBlock.BufLen Div HEX('100') Div HEX('100')); data_regs.tcm := chr(at until (not psns.req) or (ints.ints <> 0); b := ord(data_regs.temp); end else {output operation} begin data_regs.temp := chr(b); scmd.cmd := set_ack_req_cmd; repeat until (not psns.req) or (ints.ints <> 0); end; if (ints.inXferBufBlock.BufLen Div HEX('100')); data_regs.tcl := chr(XferBufBlock.BufLen); { tell the chip which phase we expect to xfer in. } pctl.t_phase := XferPhase; { the transfer protocol (synchronous or asynchrnous) has already been se     tic transfer. } hwiAXfer(XferBlock, PtrScsiChip); { don't need to wait for chip to finish up work because waiting for an interrupt below. Interrupts handled here are: cmd_complete, svc_required, and spc_hard_err. } { an inTRUE; sctl.cr := FALSE; utlSetInternalErr(pSB, ScsiInteruptErr); goto 1; end; end; {with} hwiProgXfer := true; 1: end; {************************************************************************* * hwiStartDMAXfer ***********************terrupt of some kind must come through, wait for it. } if (ints.ints = 0) then begin osdStartTimer(one_second); repeat until (ints.ints <> 0) or osdTimeExpired; if (ints.ints = 0) then begin utlSetInternalErr(pSB, ScsiXferErr); go************************************************** * * On Input: The bus is in the desired phase and the target is requesting * data be transfered (direction of transfer will be based on * what is on the bus). The XferBlock in the to 1; end; end; 2: Saveints.ints := ints.ints; ints.ints := ints.ints; if serr.serr <> 0 then Saveints.spc_hard_err := true; if (Saveints.spc_hard_err) then begin Saveints.spc_hard_err := false; { call hwiGetMsgOut which willInternalBlock has * been set up. * * The DMA channel has been determined and is stored in the * InternalBlock. * * Functional Description: * * Set up the hardware for a DMA transfer, and set up for an * inte force the bus to message out phase (if target still expects to xfer data, this routine will pump no-op data, or read and throw away data, until message out phase has been granted. } hwiGetMsgOut(pSB, ResultCode); if (ResultCode = ord(rrupt to occur from the CHIP only! DMA should not cause * an interrupt. * * On Output: DMA started. * *************************************************************************} function hwiStartDMAXfer(pSB:PtrSessionBlockType):boolean; var CouScsiErr)) then goto 1; { reset the transfer control hardware on the chip/card. } sctl.cr := TRUE; sctl.cr := FALSE; end; if (Saveints.svc_required) then begin Saveints.svc_required := false; { get the residual countnt:integer; locsc_reg:sc_reg_type; begin hwiStartDMAXfer := true; with pSB^.InternalBlock, pScBlock^, PtrScsiCard^, PtrScsiChip^ do begin { make sure the SCSI card is not doing DMA! } sc_reg.d_enab_0 := false; sc_reg.d_enab_1 := false; co from tch, tcm, and tcl; this is the new buffer length. Adjust the buffer pointer to point to the next byte to be transfered. } XferBufBlock.BufLen := (ord(data_regs.tch) * HEX('100') * HEX('100')) + (ord(data_regs.tcm) * HEX('10nfig_reg.pal_reset := 0; { set up and arm the DMA card. On entry, DMA32bit indicates the SCSI card DMA capabilities. On exit, DMA32bit indicates how the card was setup. } DMA32bit := not id_reg.d16; osdSetUpDMAChannel(DMAChannel, DMA0')) + ord(data_regs.tcl); XferBufBlock.BufPtr := addr(XferSavedDataPointer^, XferSavedDataLength - XferBufBlock.BufLen); { reset the transfer control hardware on the chip/card. } sctl.cr := TRUE; sctl.cr := FALSE32bit, XferBlock); { set up and arm the Fujitsu CHIP } ints.ints := 0; Count := XferBlock.XferDMACount; data_regs.tch := chr(Count Div HEX('100') Div HEX('100')); data_regs.tcm := chr(Count Div HEX('100')); data_regs.tcl := chr(Count); ; end; if (Saveints.cmd_complete) then begin Saveints.cmd_complete := false; end; if (Saveints.ints <> 0) {an unexpected interrupt has occured} then begin { reset the transfer control hardware on the chip/card. } sctl.cr :=  pctl.t_phase := XferBlock.XferPhase; scmd.scmd := transfer_dmax; { wait for chip to accept the transfer command. if an interrupt has occured, then this is an error. } if (ssts.action <> spc_init_xfer) or (ints.ints <> 0) then begin      ed (because of * the 128K max transfer limitation with 16bit DMA) return FALSE to * indicate DMA transfer did not end, otherwise TRUE. * * Appropriate SCSI errors are placed in SessionBlock and ResultCode is set. * * On Output: DMA trbeen granted. } hwiGetMsgOut(pSB, ResultCode); end; end else if (XferPhase = data_in_phase) then begin { if this is an input DMA operation, then wait for DMA to catch up to SCSI chip. If DMA won't (osdStopDMA = false), tansfer either stopped or killed. H/W properly reset. * FALSE is returned if DMA transfer must be continued, TRUE otherwise. * ResultCode is set to ScsiErr if an error has occured, NoEvent otherwise. * ****************************************hen data has been lost. (This is not necessary for output, because the count on the SCSI chip reflects what actually has been transfered.) } if (not osdStopDMA(DMAChannel, DMA32bit, DMAStopCount)) then begin utlSetInternalErr(pSB, osdStartTimer(one_second); repeat until (ssts.action = spc_init_xfer) or (ints.ints <> 0) or osdTimeExpired; if (ssts.action <> spc_init_xfer) or (ints.ints <> 0) then begin hwiStartDMAXfer := FALSE; utlSetInternalErr(pSB, ScsiCatastrop*********************************} function hwiEndDMAXfer(pSB:PtrSessionBlockType; Var ResultCode:S_SHORT):Boolean; var Saveints:ints_type; AmtXfered,DMAStopCount:integer; begin with pSB^.InternalBlock, XferBlock, pScBlock^, PtrScsiChip^, PtrScsiCard^ hicErr); end; end; { if no errors have occured, then o set up the software to handle an interrupt. o enable interrupts o set up and enable the card to do DMA. - this will start the DMA process. } if (ssts.action = spcdo begin sc_reg.ie := false; ISRWaiting := false; ResultCode := ord(NoEvent); hwiEndDMAXfer := TRUE; Saveints.ints := ints.ints; ints.ints := ints.ints; if (ISRError) or (serr.serr <> 0) then Saveints.spc_hard_err := true; DMAStopCount_init_xfer) and (ints.ints = 0) then begin ISRWaiting := true; ISRMask := cmd_complete + svc_required + spc_hard_err; locsc_reg.control := 0; locsc_reg.ie := true; if DMA32bit then locsc_reg.dma_32 := true; if XferBlock.XferPhase =  := (ord(data_regs.tch) * HEX('100') * HEX('100')) + (ord(data_regs.tcm) * HEX('100')) + ord(data_regs.tcl); AmtXfered := XferDMACount - DMAStopCount; XferBufBlock.BufLen := XferBufBlock.BufLen - AmtXfered; { note, use XferSavedDataPdata_in_phase then locsc_reg.dma_dir := true; { 375 h/w problem, write dma enable last!!!! } sc_reg.control := locsc_reg.control; if DMAChannel = 1 then sc_reg.d_enab_1 := true else sc_reg.d_enab_0 := true; end; end; end; {***ointer instead of BufPtr because the absolute address from the beginning of the transfer is being calculated. } XferBufBlock.BufPtr := addr(XferSavedDataPointer^, XferSavedDataLength - XferBufBlock.BufLen); if (Saveints.spc_hard_err) then ********************************************************************** * hwiEndDMAXfer ************************************************************************* * * On Input: * * An interrupt (from the SCSI chip) has occured indicating the curr begin Saveints.spc_hard_err := false; { Reset the DMA channel. } osdKillDMA(DMAChannel); { reset the transfer control hardware on the chip/card. } sctl.cr := TRUE; sctl.cr := FALSE; if ISRError then ResultCode :=ent * DMA transfer has halted. * * Functional Description: * * Determine the number of bytes transferred, and adjust * XferBlock. Determine the cause for the interrupt, and reset * H/W accordingly. If transfer should be continu ord(ScsiErr) else begin { call hwiGetMsgOut which will force the bus to message out phase (if target still expects to xfer data, this routine will pump no-op data, or read and throw away data, until message out phase has      ScsiXferErr); ResultCode := ord(ScsiErr); end; end else osdKillDMA(DMAChannel); if (Saveints.svc_required) then begin Saveints.svc_required := false; { reset the transfer control hardware on the chip/card. } sctl.cr := T_4 standard * MESSAGES_msgGetMsg *$event_pairs_catch * Synch,state_5 * ScsiErr,state_exit * state_6 ******************************************************* *state_5 standard * RUE; sctl.cr := FALSE; end; if (Saveints.cmd_complete) then begin Saveints.cmd_complete := false; if (ResultCode <> ord(ScsiErr)) and (XferBufBlock.BufLen > 0) then hwiEndDMAXfer := FALSE; {still more data to be xfered} end; if (S MESSAGES_msgTargetSynchParms * HWI_UTILS_hwiGetPhase *$event_pairs_catch * state_exit ******************************************************* *state_6 standard * MESSAGES_msgRejectMsg * HWIaveints.ints <> 0) {an unexpected interrupt has occured} then begin utlSetInternalErr(pSB, ScsiInteruptErr); ResultCode := ord(ScsiErr); { reset the transfer control hardware on the chip/card. } sctl.cr := TRUE; sctl.cr := FALSE; _UTILS_hwiGetPhase *$event_pairs_catch * MsgIn,state_4 * MsgOut,state_2 * state_exit ******************************************************* *exec_err standard * COMMANDS_cmdStateErr *$event_pai end; { reset the igor PAL after every DMA transfer. } sc_reg.d_enab_1 := false; sc_reg.d_enab_0 := false; config_reg.pal_reset := 1; end; end; end; rs_catch * state_exit ******************************************************* *state_exit mexit * 0 ******************************************************* *$end_machine REFA COMMANDS_CMDSTATEERR LMODE COMMANDS_CMDSTATE INCLUDE ST_EQU *$machine_name EstablishPath *$global_recover exec_err ******************************************************* *state_1 standard * MESSAGES_msgSelect * HWI_UTILS_hwiGetPhase *$event_pairs_catch * ERR REFA MESSAGES_MSGREJECTMSG LMODE MESSAGES_MSGREJECTMSG REFA MESSAGES_MSGTARGETSYNCHPARMS LMODE MESSAGES_MSGTARGETSYNCHPARMS REFA MESSAGES_MSGGETMSG LMODE MESSAGES_MSGGETMSG REFA MESSAGES_MSGINITSYNCHPARMS LMODE MESSAGES_MSGINITSYNCH WaitForIsr,state_1a * MsgOut,state_2 * state_exit ******************************************************* *state_1a suspend * state_1 ******************************************************* *state_2 PARMS REFA MESSAGES_MSGIDENTIFYMSG LMODE MESSAGES_MSGIDENTIFYMSG REFA HWI_UTILS_HWIGETPHASE LMODE HWI_UTILS_HWIGETPHASE REFA MESSAGES_MSGSELECT LMODE MESSAGES_MSGSELECT STANDARD equ 0 MCALL equ 1 MEXIT equ 2 SUSPEND equ 3 DONE_EXIT equ 4 SIN standard * MESSAGES_msgIdentifyMsg * HWI_UTILS_hwiGetPhase *$event_pairs_catch * NeedSynchParms,state_3 * MsgIn,state_4 * ScsiErr,state_exit * state_exit ***************GLES equ 0 SINGLES_CATCH equ 1 PAIRS equ 2 PAIRS_CATCH equ 3 DEF ESTABLISHPATH ESTABLISHPATH dc.w EXEC_ERR-ESTABLISHPATH STATE_1 dc.b STANDARD,PAIRS_CATCH dc.b 3,2 dc.w WAITFORISR,STATE_1A-ESTABLISHPATH dc.w MSGOUT,STATE_2**************************************** *state_3 standard * MESSAGES_msgInitSynchParms * HWI_UTILS_hwiGetPhase *$event_pairs_catch * state_exit ******************************************************* *state-ESTABLISHPATH dc.w 000,STATE_EXIT-ESTABLISHPATH dc.l MESSAGES_MSGSELECT dc.l HWI_UTILS_HWIGETPHASE STATE_1A dc.b SUSPEND,SINGLES dc.w STATE_1-ESTABLISHPATH STATE_2 dc.b STANDARD,PAIRS_CATCH dc.b 4,2 dc.w NEED     state_2 ******************************************************* *state_2 standard * MESSAGES_msgDoXfer * HWI_UTILS_hwiGetPhase *$event_pairs_catch * WaitForISR,state_2a * MsgIn,state_4 * S_msgWaitReselect *$event_pairs_catch * WaitForISR,state_9a * MsgIn,state_4 * ScsiErr,state_exit * state_exit ******************************************************* *state_9a suspend *  MsgOut,state_3 * state_exit ******************************************************* *state_2a suspend * state_2 ******************************************************* *state_3 standard * MESSA state_9 ******************************************************* *state_10 standard * MESSAGES_msgIsOriginalPhase *$event_pairs_catch * OriginalPhase,state_2 * state_exit ********************************SYNCHPARMS,STATE_3-ESTABLISHPATH dc.w MSGIN,STATE_4-ESTABLISHPATH dc.w SCSIERR,STATE_EXIT-ESTABLISHPATH dc.w 000,STATE_EXIT-ESTABLISHPATH dc.l MESSAGES_MSGIDENTIFYMSG dc.l HWI_UTILS_HWIGETPHASE STATE_EXIT dc.b MEXIT,SINGLES dcGES_msgSawErrMsg * HWI_UTILS_hwiGetPhase *$event_pairs_catch * MsgIn,state_4 * state_exit ******************************************************* *state_4 standard * MESSAGES_msgGetMsg *$event_.w 0 STATE_3 dc.b STANDARD,PAIRS_CATCH dc.b 1,2 dc.w 000,STATE_EXIT-ESTABLISHPATH dc.l MESSAGES_MSGINITSYNCHPARMS dc.l HWI_UTILS_HWIGETPHASE STATE_4 dc.b STANDARD,PAIRS_CATCH dc.b 3,1 dc.w SYNCH,STATE_5-ESTABpairs_catch * SaveDataPtr,state_5 * Identify,state_6 * RestorePtrs,state_6 * Disconnect,state_7 * Synch,state_12 * ScsiErr,state_exit * state_8 **************LISHPATH dc.w SCSIERR,STATE_EXIT-ESTABLISHPATH dc.w 000,STATE_6-ESTABLISHPATH dc.l MESSAGES_MSGGETMSG STATE_5 dc.b STANDARD,PAIRS_CATCH dc.b 1,2 dc.w 000,STATE_EXIT-ESTABLISHPATH dc.l MESSAGES_MSGTARGETSYNCHPARMS dc.l ***************************************** *state_5 standard * MESSAGES_msgPrepareDisc * HWI_UTILS_hwiGetPhase *$event_pairs_catch * MsgIn,state_4 * state_10 ************************************HWI_UTILS_HWIGETPHASE STATE_6 dc.b STANDARD,PAIRS_CATCH dc.b 3,2 dc.w MSGIN,STATE_4-ESTABLISHPATH dc.w MSGOUT,STATE_2-ESTABLISHPATH dc.w 000,STATE_EXIT-ESTABLISHPATH dc.l MESSAGES_MSGREJECTMSG dc.l HWI_UTILS_HWIGETPHASE ******************* *state_6 standard * MESSAGES_msgPrepareRetry * HWI_UTILS_hwiGetPhase *$event_pairs_catch * MsgIn,state_4 * state_10 ******************************************************* * EXEC_ERR dc.b STANDARD,PAIRS_CATCH dc.b 1,1 dc.w 000,STATE_EXIT-ESTABLISHPATH dc.l COMMANDS_CMDSTATEERR * state trace table OPTION = TABLE OFF END state_7 standard * MESSAGES_msgSetDisc *$event_pairs * BusFree,state_9 * ScsiErr,state_exit ******************************************************* *state_8 standard * MESSAGES_msgReject INCLUDE ST_EQU *$machine_name DoTransfer *$global_recover exec_err ******************************************************* *state_1 standard * MESSAGES_msgSetXfer *$event_pairs_catch * ScsiErr,state_exit * Msg * HWI_UTILS_hwiGetPhase *$event_pairs_catch * MsgIn,state_4 * ScsiErr,state_exit * state_10 ******************************************************* *state_9 standard * MESSAGE     *********************** *state_12 standard * MESSAGES_msgTargetSynchParms * HWI_UTILS_hwiGetPhase *$event_pairs_catch * ScsiErr,state_exit * state_10 ******************************************** dc.w STATE_2-DOTRANSFER STATE_4 dc.b STANDARD,PAIRS_CATCH dc.b 7,1 dc.w SAVEDATAPTR,STATE_5-DOTRANSFER dc.w IDENTIFY,STATE_6-DOTRANSFER dc.w RESTOREPTRS,STATE_6-DOTRANSFER dc.w DISCONNECT,STATE_7-DOTRANSFER dc.w*********** *exec_err standard * COMMANDS_cmdStateErr *$event_pairs_catch * state_exit ******************************************************* *state_exit mexit * 0 *************************************** SYNCH,STATE_12-DOTRANSFER dc.w SCSIERR,STATE_EXIT-DOTRANSFER dc.w 000,STATE_8-DOTRANSFER dc.l MESSAGES_MSGGETMSG STATE_3 dc.b STANDARD,PAIRS_CATCH dc.b 2,2 dc.w MSGIN,STATE_4-DOTRANSFER dc.w 000,STATE_EXIT-DOTRANS**************** *$end_machine REFA COMMANDS_CMDSTATEERR LMODE COMMANDS_CMDSTATEERR REFA MESSAGES_MSGTARGETSYNCHPARMS LMODE MESSAGES_MSGTARGETSYNCHPARMS REFA MESSAGES_MSGISORIGINALPHASE LMODE MESSAGES_MSGISORIGINALPHASE REFA MESSAGES_MSGWFER dc.l MESSAGES_MSGSAWERRMSG dc.l HWI_UTILS_HWIGETPHASE STATE_5 dc.b STANDARD,PAIRS_CATCH dc.b 2,2 dc.w MSGIN,STATE_4-DOTRANSFER dc.w 000,STATE_10-DOTRANSFER dc.l MESSAGES_MSGPREPAREDISC dc.l HWI_UTILS_HWIGETPHASE STATAITRESELECT LMODE MESSAGES_MSGWAITRESELECT REFA MESSAGES_MSGREJECTMSG LMODE MESSAGES_MSGREJECTMSG REFA MESSAGES_MSGSETDISC LMODE MESSAGES_MSGSETDISC REFA MESSAGES_MSGPREPARERETRY LMODE MESSAGES_MSGPREPARERETRY REFA MESSAGES_MSGPREPAREDIE_6 dc.b STANDARD,PAIRS_CATCH dc.b 2,2 dc.w MSGIN,STATE_4-DOTRANSFER dc.w 000,STATE_10-DOTRANSFER dc.l MESSAGES_MSGPREPARERETRY dc.l HWI_UTILS_HWIGETPHASE STATE_7 dc.b STANDARD,PAIRS dc.b 2,1 dc.w BUSFREESC LMODE MESSAGES_MSGPREPAREDISC REFA MESSAGES_MSGGETMSG LMODE MESSAGES_MSGGETMSG REFA MESSAGES_MSGSAWERRMSG LMODE MESSAGES_MSGSAWERRMSG REFA HWI_UTILS_HWIGETPHASE LMODE HWI_UTILS_HWIGETPHASE REFA MESSAGES_MSGDOXFER LMODE MESSAGES_MSG,STATE_9-DOTRANSFER dc.w SCSIERR,STATE_EXIT-DOTRANSFER dc.l MESSAGES_MSGSETDISC STATE_12 dc.b STANDARD,PAIRS_CATCH dc.b 2,2 dc.w SCSIERR,STATE_EXIT-DOTRANSFER dc.w 000,STATE_10-DOTRANSFER dc.l MESSAGES_MSGTARGETSYNCHPARMSDOXFER REFA MESSAGES_MSGSETXFER LMODE MESSAGES_MSGSETXFER STANDARD equ 0 MCALL equ 1 MEXIT equ 2 SUSPEND equ 3 DONE_EXIT equ 4 SINGLES equ 0 SINGLES_CATCH equ 1 PAIRS equ 2 PAIRS_CATCH equ 3 DEF DOTRANSFER DOTRANSFER dc.w EXEC_ERR-DOTRANSFE dc.l HWI_UTILS_HWIGETPHASE STATE_8 dc.b STANDARD,PAIRS_CATCH dc.b 3,2 dc.w MSGIN,STATE_4-DOTRANSFER dc.w SCSIERR,STATE_EXIT-DOTRANSFER dc.w 000,STATE_10-DOTRANSFER dc.l MESSAGES_MSGREJECTMSG dc.l HWI_UTILS_HWIGETPHASER STATE_1 dc.b STANDARD,PAIRS_CATCH dc.b 2,1 dc.w SCSIERR,STATE_EXIT-DOTRANSFER dc.w 000,STATE_2-DOTRANSFER dc.l MESSAGES_MSGSETXFER STATE_EXIT dc.b MEXIT,SINGLES dc.w 0 STATE_2 dc.b STANDARD,PAIRS_CATCH  STATE_10 dc.b STANDARD,PAIRS_CATCH dc.b 2,1 dc.w ORIGINALPHASE,STATE_2-DOTRANSFER dc.w 000,STATE_EXIT-DOTRANSFER dc.l MESSAGES_MSGISORIGINALPHASE STATE_9 dc.b STANDARD,PAIRS_CATCH dc.b 4,1 dc.w WAITFORISR, dc.b 4,2 dc.w WAITFORISR,STATE_2A-DOTRANSFER dc.w MSGIN,STATE_4-DOTRANSFER dc.w MSGOUT,STATE_3-DOTRANSFER dc.w 000,STATE_EXIT-DOTRANSFER dc.l MESSAGES_MSGDOXFER dc.l HWI_UTILS_HWIGETPHASE STATE_2A dc.b SUSPEND,SINGLESSTATE_9A-DOTRANSFER dc.w MSGIN,STATE_4-DOTRANSFER dc.w SCSIERR,STATE_EXIT-DOTRANSFER dc.w 000,STATE_EXIT-DOTRANSFER dc.l MESSAGES_MSGWAITRESELECT STATE_9A dc.b SUSPEND,SINGLES dc.w STATE_9-DOTRANSFER EXEC_ERR dc.b      RFREE REFA MESSAGES_MSGGETMSG LMODE MESSAGES_MSGGETMSG STANDARD equ 0 MCALL equ 1 MEXIT equ 2 SUSPEND equ 3 DONE_EXIT equ 4 SINGLES equ 0 SINGLES_CATCH equ 1 PAIRS equ 2 PAIRS_CATCH equ 3 DEF TERMINATEPATH TERMINATEPATH dc.w EXEC_ERR-TERMINATE 0 ******************************************************* *$end_machine REFA COMMANDS_CMDSTATEERR LMODE COMMANDS_CMDSTATEERR REFA HWI_UTILS_HWIGETPHASE LMODE HWI_UTILS_HWIGETPHASE REFA MESSAGES_MSGABORTMSG LMODE MESSAGES_MSGABORTMPATH STATE_1 dc.b STANDARD,PAIRS_CATCH dc.b 3,1 dc.w CMDCOMPLETE,STATE_2-TERMINATEPATH dc.w SCSIERR,STATE_EXIT-TERMINATEPATH dc.w 000,STATE_3-TERMINATEPATH dc.l MESSAGES_MSGGETMSG STATE_2 dc.b STANDARD,PAIRS_CATSG REFA HWI_UTILS_HWIGETMSGOUT LMODE HWI_UTILS_HWIGETMSGOUT REFA MESSAGES_MSGISPATHACTIVE LMODE MESSAGES_MSGISPATHACTIVE STANDARD equ 0 MCALL equ 1 MEXIT equ 2 SUSPEND equ 3 DONE_EXIT equ 4 SINGLES equ 0 SINGLES_CATCH equ 1 PAIRS equ 2 PAIRS_CATC STANDARD,PAIRS_CATCH dc.b 1,1 dc.w 000,STATE_EXIT-DOTRANSFER dc.l COMMANDS_CMDSTATEERR * state trace table OPTION = TABLE OFF END CH dc.b 1,1 dc.w 000,STATE_EXIT-TERMINATEPATH dc.l MESSAGES_MSGWAITTIMEORFREE STATE_EXIT dc.b MEXIT,SINGLES dc.w 0 STATE_3 dc.b STANDARD,PAIRS_CATCH dc.b 2,2 dc.w MSGIN,STATE_1-TERMINATEPATH dc.w 000,STATE_ INCLUDE ST_EQU *$machine_name TerminatePath *$global_recover exec_err ******************************************************* *state_1 standard * MESSAGES_msgGetMsg *$event_pairs_catch * CmdComplete,state_2 * EXIT-TERMINATEPATH dc.l MESSAGES_MSGREJECTMSG dc.l HWI_UTILS_HWIGETPHASE EXEC_ERR dc.b STANDARD,PAIRS_CATCH dc.b 1,1 dc.w 000,STATE_EXIT-TERMINATEPATH dc.l COMMANDS_CMDSTATEERR * state trace table OPTION = TABLE OFF END  ScsiErr,state_exit * state_3 ******************************************************* *state_2 standard * MESSAGES_msgWaitTimeOrFree *$event_pairs_catch * state_exit *************************************** INCLUDE ST_EQU *$machine_name AbortPath *$global_recover exec_err ******************************************************* *state_1 standard * MESSAGES_msgIsPathActive *$event_pairs_catch * NoEvent,state_2 * **************** *state_3 standard * MESSAGES_msgRejectMsg * HWI_UTILS_hwiGetPhase *$event_pairs_catch * MsgIn,state_1 * state_exit ******************************************************* *exec state_exit ******************************************************* *state_2 standard * HWI_UTILS_hwiGetMsgOut *$event_pairs * MsgOut,state_3 * ScsiErr,state_exit * BusFree,state_exit * _err standard * COMMANDS_cmdStateErr *$event_pairs_catch * state_exit ******************************************************* *state_exit mexit * 0 *******************************************************  BusBusy,state_exit ******************************************************* *state_3 standard * MESSAGES_msgAbortMsg * HWI_UTILS_hwiGetPhase *$event_pairs_catch * ScsiErr,state_exit * sta*$end_machine REFA COMMANDS_CMDSTATEERR LMODE COMMANDS_CMDSTATEERR REFA HWI_UTILS_HWIGETPHASE LMODE HWI_UTILS_HWIGETPHASE REFA MESSAGES_MSGREJECTMSG LMODE MESSAGES_MSGREJECTMSG REFA MESSAGES_MSGWAITTIMEORFREE LMODE MESSAGES_MSGWAITTIMEOte_exit ******************************************************* *exec_err standard * COMMANDS_cmdStateErr *$event_pairs_catch * state_exit ******************************************************* *state_exit mexit *      H equ 3 DEF ABORTPATH ABORTPATH dc.w EXEC_ERR-ABORTPATH STATE_1 dc.b STANDARD,PAIRS_CATCH dc.b 2,1 dc.w NOEVENT,STATE_2-ABORTPATH dc.w 000,STATE_EXIT-ABORTPATH dc.l MESSAGES_MSGISPATHACTIVE STATE_2 dc.b S the hardware } hwiSCInitHW(sc); { get space for the SCSI driver table. Initialize it to the contents of the system driver table. update the pointer in the isc_table to the SCSI driver table. } newbytes(pScsiDvrTable, sizeof(TANDARD,PAIRS dc.b 4,1 dc.w MSGOUT,STATE_3-ABORTPATH dc.w SCSIERR,STATE_EXIT-ABORTPATH dc.w BUSFREE,STATE_EXIT-ABORTPATH dc.w BUSBUSY,STATE_EXIT-ABORTPATH dc.l HWI_UTILS_HWIGETMSGOUT STATE_EXIT dc.b MEXIT,SINGLES dc.w drv_table_type)); pScsiDvrTable^ := PtrScsiDvrType(io_drv_ptr)^; PtrScsiDvrType(io_drv_ptr) := pScsiDvrTable; { initialize the SCSI driver table to our procedures. } io_drv_ptr^.iod_tfr := ScsiIOD_TFR; io_drv_ptr^.iod_init := ScsiIO0 STATE_3 dc.b STANDARD,PAIRS_CATCH dc.b 2,2 dc.w SCSIERR,STATE_EXIT-ABORTPATH dc.w 000,STATE_EXIT-ABORTPATH dc.l MESSAGES_MSGABORTMSG dc.l HWI_UTILS_HWIGETPHASE EXEC_ERR dc.b STANDARD,PAIRS_CATCH dc.b 1,1 dD_INIT; end; end; if card_found then markuser; end; end; c.w 000,STATE_EXIT-ABORTPATH dc.l COMMANDS_CMDSTATEERR * state trace table OPTION = TABLE OFF END { This module interfaces the scsi driver to the lowest parts of an O/S. This module is responsible for allowing access to the SelectCodeBlock, allowing one to read and set interrupt levels, interfacing the interrupt level routine to the o/s's interrupmodule OSD_HL; export Procedure osdhStartUp; implement import sysglobals, GENERAL_0, SCSI_DEFS,OSD_LL,HWI_UTILS,COMMANDS,SCSI_ISR, LOADER, IODECLARATIONS, ASM; Procedure ScsiIOD_TFR(temp, v:ANYPTR); var i:integer; begin i := ord(temp); if it handling mechanism, etc. } MODULE OSD_LL; {Operating System Dependent Low Level interface} import SCSI_DEFS, OSD_LLA, IODECLARATIONS, GENERAL_0, SYSGLOBALS, ISR, ASM, IOCOMASM; export const one_second = 1000; { Driver Initialization routin = 0 then DoSession(v) else if i = 1 then DoAbort(v) else if i = 2 then begin i := ord(v); DoReset(i); end; end; Procedure ScsiIOD_INIT(temp:ANYPTR); begin { temp is an pio_tmp_ptr. } cmdScCleanUp(pio_tmp_ptr(temp)^.my_isc); end; Proces } Procedure osdInitScBlock(Sc:S_TYPE_ISC); Function osdGetScBlock(Sc:S_TYPE_ISC):PtrSelectCodeBlockType; Procedure osdLinkIsrRoutine(IsrProc:ScsiIsrProcType; Sc:S_TYPE_ISC); { Timer Routines } Procedure osdDelay(ms:integer); Procedure osdStedure osdhStartUp; type PtrScsiDvrType=^drv_table_type; var card_found:boolean; sc:TYPE_ISC; pScsiDvrTable:PtrScsiDvrType; begin card_found:= false; for sc := minrealisc to maxrealisc do with isc_table[sc] do begin if (card_ptr <> nil) and (artTimer(ms:integer); Function osdTimeExpired:boolean; { General O/S specific routines } Function osdGetRunLevel:io_byte; Procedure osdSetRunLevel(Level:io_byte); Function osdBitOr(b1,b2:integer):integer; Function osdBitAnd(b1,b2:integer):incard_type = scsi_card) then begin card_found := true; { Initialize this card's select code block and link the scsi ISR routine into this select code. } osdInitScBlock(sc); osdLinkIsrRoutine(isrScsiIsr, sc); { Initializeteger; Function osdBitLsL(b,Num:integer):integer; Function osdBitLsR(b,Num:integer):integer; { DMA routines } Function osdDMA32bit:boolean; Function osdGetDMAChannel(Sc:S_TYPE_ISC):integer; Procedure osdSetUpDMAChannel(Channel:integer; var D     te; var PtrMiscTemplate:PtrMiscTemplateType; i:ScsiDeviceType; begin with isc_table[Sc] do begin PtrMiscTemplate := addr(io_tmp_ptr^.drv_misc[1]); with PtrMiscTemplate^ do begin newbytes(MiscpScBlock, sizeof(SelectCodeBlockType)); with MiselectCodeBlock, * get and call the SCSI Driver ISR routine. * * On Output: SCSI Driver ISR routine is linked into the O/S. * *************************************************************************} Procedure osdScsiIsr(isribptr:pisrib)cpScBlock^ do begin for i := 0 to 7 do begin DeviceSessionPtrs[i] := nil; DeviceSynchParms[i].SynchState := NoSynch; DeviceSynchParms[i].TMODvalue.tmod := 0; end; PtrScsiCard := card_ptr; PtrScsiChip := addr(PtrChar(Pt; var io_ptr:pio_tmp_ptr; pScBlock:PtrSelectCodeBlockType; begin io_ptr := pio_tmp_ptr(isribptr); pScBlock := osdGetScBlock(io_ptr^.my_isc); call(pScBlock^.ScsiIsrProc, io_ptr^.my_isc); end; Procedure osdLinkIsrRoutine(IsrProc:ScsiIsrProcType; Sc:S_TMA32bit:boolean; var XferBlock:XferBlockType); Procedure osdKillDMA(Channel:integer); Function osdStopDMA(Channel:integer; DMA32bit:boolean; StopCount:integer):boolean; Procedure osdReleaseDMAChannel(Sc:S_TYPE_ISC); implement { define record structrScsiCard)^,32); ScsiIntLevel := PtrScsiCard^.sc_reg.intlevel+3; ScsiSelectCode := Sc; DMAInProgress := FALSE; DMAChannel := -1; end; newbytes(MiscpSenseSpace, 256); MiscSenseLength := 0; end; end; end; {***********************ures for the DMA registers } type Channel16BitType = packed record address:ANYPTR; count:S_SHORT; cont_stat:S_SHORT; end; Channel32BitType = packed record address:ANYPTR; count:integer; cont_stat:S_SHORT; end; Channel32BitGeneralType = p************************************************** * osdGetScBlock ************************************************************************* * * On Input: nothing expected. * * * Functional Description: * * Given a select code, return a poinacked record id1:S_SHORT; id2:S_SHORT; case integer of 1:(control:S_SHORT); 2:(pad :0..hex('3ff'); reset1 :boolean; reset0 :boolean; bt :0..hex('3'); br :0..hex('3')); end; var timer:timer_rec; {*************ter to the SelectCode block. * * On Output: Ptr to SelectCodeBlock or Nil. * *************************************************************************} Function osdGetScBlock(Sc:S_TYPE_ISC):PtrSelectCodeBlockType; type ppScBlock = ^PtrSelectCodeBlock************************************************************ * osdInitScBlock ************************************************************************* * * On Input: nothing expected. * * * Functional Description: * * Acquire memory for a SeType; begin with isc_table[Sc] do begin if (card_type = scsi_card) then osdGetScBlock := ppScBlock(addr(io_tmp_ptr^.drv_misc[1]))^ else osdGetScBlock := Nil; end; end; {************************************************************************lect Code Block (defined in SCSI_DEFS), * hook the memory into a memory chain accessible through a select * code, and initialize. * * On Output: SelectCode block acquired, hooked into the O/S and initialized. * ***************************** * osdLinkIsrRoutine ************************************************************************* * * On Input: nothing expected. * * * Functional Description: * * Takes as paramters a select code and an ISR routine. The ISR * routine i*********************************************} Procedure osdInitScBlock(Sc:S_TYPE_ISC); type MiscTemplate = packed record MiscpScBlock:PtrSelectCodeBlockType; MiscpSenseSpace:PtrChar; MiscSenseLength:integer; end; PtrMiscTemplateType = ^MiscTemplas linked into the O/S for the given Select Code. * * The ISR routine address can be stored off of the SelectCodeBlock. * * PWS implmentation: Use a procedure that can recieve an ISRIB. * From this get the select code, get the S     YPE_ISC); var pScBlock:PtrSelectCodeBlockType; pCard:PtrScsiCardType; p:ANYPTR; begin pScBlock := osdGetScBlock(Sc); with isc_table[Sc], io_tmp_ptr^, pScBlock^, pScBlock^.PtrScsiCard^ do begin { Check for ISR already in place. } if myisrib.***} Procedure osdStartTimer(ms:integer); begin timer.time := ms; start_timer(timer); end; Function osdTimeExpired:boolean; begin osdTimeExpired := time_expired(timer); end; {************************************************************************* intregaddr <> nil then {isr already exits} begin { unlink existing isr hook. } isrunlink(ScsiIntLevel, addr(myisrib)); end; ScsiIsrProc := IsrProc; p := addr(sc_reg,1); {sc_reg.status, compiler won't let me otherwise} permisrlink( * osdGetRunLevel ************************************************************************* * * On Input: nothing expected. * * * Functional Description: * * Returns the current run level of the 680x0 processor. * * On Output: * * ******osdScsiIsr, p, hex('c0'), hex('c0'), ScsiIntLevel, addr(myisrib)); end; end; {************************************************************************* * osdDelay ************************************************************************* * * On I*******************************************************************} Function osdGetRunLevel:io_byte; begin osdGetRunLevel := intlevel; end; {************************************************************************* * osdSetRunLevel *****************nput: Nothing is expected. * * * Functional Description: * * Delay the given number of milliseconds. * * On Output: Nothing is changed, however the given number of milliseconds * has passed. * ************************************************************************************************** * * On Input: nothing expected. * * * Functional Description: * * Sets the current run level of the 680x0 processor to the requested * level. * * On Output: 680x0 run level is at*******************************} Procedure osdDelay(ms:integer); begin timer.time := ms; start_timer(timer); repeat until time_expired(timer); end; {************************************************************************* * osdStartTimer & osdTimeE requested level. * *************************************************************************} Procedure osdSetRunLevel(Level:io_byte); begin setintlevel(level); end; {************************************************************************* * Bit xpired ************************************************************************* * * On Input: Nothing is expected. * * * Functional Description: * * These two routines are used to start a timer that will expire after * a given number ofmanipulation routintes ************************************************************************* * * On Input: nothing expected. * * * Functional Description: * * * * On Output: * * ************************************************************* milliseconds and then check to see if the timer * has expired. * * They are used to wait while waiting for an event to happen, thus * preventing an eternal wait. * * On Output: osdStartTimer: the timer has been started - this should ************} Function osdBitOr(b1,b2:integer):integer; begin osdBitOr := binior(b1,b2); end; Function osdBitAnd(b1,b2:integer):integer; begin osdBitAnd := binand(b1,b2); end; Function osdBitLsL(b,Num:integer):integer; begin osdBitLsL := binlsl(b,Num); not * affect the driver in any way. osdTimeExpired: returns TRUE if the * timer has expired, FALSE otherwise. This routine should have no * affect on the driver. * **********************************************************************end; Function osdBitLsR(b,Num:integer):integer; begin osdBitLsR := binlsr(b,Num); end; {************************************************************************* * osdDMA32bit *************************************************************************     ********************************* * osdSetUpDMAChannel ************************************************************************* * * On Input: DMA is present, and a Channel has been acquired. * XferBlock.BufPtr is guaranteed to be on a word := TRUE; end; end; end; osdKillDMA(Channel); DMAPtr := isc_table[3].card_ptr; if Use32BitChannel then begin {Get pointers to DMA channel} p32Gen := addr(DMAPtr^,hex('10')); pChannel32 := addr(DMAPtr^,(Channel+1)*hex('100')); with  boundary and * XferBlock.BufLen is guaranteed to be an even length. * * Functional Description: * * Initialize and ARM the given DMA channel. The DMA H/W should * be set up to NOT interrupt. * * The incomming * DMA3p32Gen^, pChannel32^, XferBlock do begin {set bus control registers to 16 bit defaults} br := 0; bt := 2; {DMA address} address := XferBufBlock.BufPtr; { DMA Count. Can do the entire DMA in one go around, however the amount  * * On Input: nothing expected. * * * Functional Description: * * Determines if the current hardware supports 32 bit wide DMA. * * On Output: TRUE if 32bit wide DMA is supported; FALSE otherwise. * Modified to always FALSE due 2bit parameter indicates if the SCSI H/W can handle 32 bit DMA or * not, on exit DMA32bit should indicate if 32 bit DMA is being performed * or not. (NOTE: SCSI driver expects either 16 or 32 bit DMA - 8 bit DMA * is NOT acceptable). * to hardware bug - 27AUG91 - CFB * *************************************************************************} Function osdDMA32bit:boolean; var io_dummy_word:io_word; begin if dma_here then {from IODECLARATIONS} begin try io_dummy_word := ioread_w* XferBlock contains buffer address, length, and direction of transfer. * * Because 16bit DMA can only transfer 128K max, the amount of data being * transfered should be stored in the XferBlock (XferDMACount). The value * stored isord(3, hex('10')); if (io_dummy_word = hex('3230')) then {ascii'2', '0'} osdDMA32bit := true else osdDMA32bit := false; recover osdDMA32bit := false; end else osdDMA32bit := false; osdDMA32bit := false; {always false due to hardwar the actual number of bytes the DMA channel will transfer. * * On Output: DMA channel is initialized and ARMed. * *************************************************************************} Procedure osdSetUpDMAChannel(Channel:integer; var DMA32bit:booe bug 27AUG91 - CFB} end; {************************************************************************* * osdGetDMAChannel ************************************************************************* * * On Input: nothing expected. * * * Functional Deslean; var XferBlock:XferBlockType); var DMAPtr:PtrChar; Use32BitChannel:boolean; pChannel16:^Channel16BitType; pChannel32:^Channel32BitType; p32Gen:^Channel32BitGeneralType; i:integer; begin { Determine if a 16 or 32 bit channel should be used. cription: * * Acquire, if possible, a DMA Channel from the operating system. * Once acquired, this channel will be used by the SCSI Driver until * the SCSI driver releases it. * * On Output: 0 for channel 0, 1 for channel 1, -1 for no} Use32BitChannel := osdDMA32bit; { Determine what kind of DMA should be used, 16 or 32 bit. } if (DMA32bit) then begin DMA32bit := false; {prove that SPU can do 32 bit first.} {is 32 bit wide DMA available in the SPU?} if (Use32BitChannel channel. * * *************************************************************************} Function osdGetDMAChannel(Sc:S_TYPE_ISC):integer; begin osdGetDMAChannel := dma_request(isc_table[Sc].io_tmp_ptr); end; {****************************************) then begin {is the buffer on a long word boundary?} i := integer(XferBlock.XferBufBlock.BufPtr); if (i mod 4) = 0 then begin {is the length divisible by 4?} i := XferBlock.XferBufBlock.BufLen; if (i mod 4) = 0 then DMA32bit     of transfers depends on the width of the transfer. } XferDMACount := XferBufBlock.BufLen; if (DMA32bit) then count := (XferBufBlock.BufLen Div 4)-1 else count := (XferBufBlock.BufLen Div 2)-1; { Writing the start bit in thown. * * *************************************************************************} Procedure osdKillDMA(Channel:integer); var io_dummy_word:io_word; pGen32:^Channel32bitGeneralType; begin { Kill the 16 bit channel by reading the channel address re control register arms the DMA chip. } if (XferBlock.XferPhase = data_in_phase) then begin if DMA32bit then {start, 32bit, priority, input, word, no interrupt} cont_stat := hex('810A') else {start, 16bit, priority, input, wegister. } io_dummy_word := ioread_word(3, Channel*8); { Kill the 32 bit channel by specifically resetting the appropriate channel. } pGen32 := isc_table[3].card_ptr; pGen32 := addr(pGen32^, hex('10')); if Channel = 0 then pGen32^.reset0 :=ord, no interrupt} cont_stat := hex ('800A'); end else begin if DMA32bit then {start, 32bit, priority, output, word, no interrupt} cont_stat := hex('810E') else {start, 16bit, priority, output, word, no interrupt}  true else pGen32^.reset1 := true; { Flush the cache on 68020 and newer processors. - this happens automatically with dma_release. } end; {************************************************************************* * osdStopDMA ************cont_stat := hex('800E'); end; end; end else begin {Get pointer to DMA channel} pChannel16 := addr(DMAPtr^, Channel*8); with pChannel16^, XferBlock do begin {DMA address} address := XferBufBlock.BufPtr; {DMA count (in words). DMA************************************************************* * * On Input: DMA channel is actively transfering data. * * * Functional Description: * * Wait for the DMA channel to get to the desired count, and then kill it. * (After an ap count is 1 less than total request. 128K transfer MAX.} if XferBufBlock.BufLen >= hex('20000') then {len >= 128K} begin XferDMACount := hex('20000'); i := hex('ffff'); end else begin XferDMACount := XferBufBlock.BufLen; i :=propriate wait, kill the channel even if the desired count * hasn't been reached). * * On Output: TRUE: desired count reached and channel killed. * FALSE: desired count NOT reached, channel killed. * * ***************************** (XferBufBlock.BufLen Div 2)-1; end; count := i; { Writing the control register arms the DMA chip. } if (XferBlock.XferPhase = data_in_phase) then cont_stat := hex('000A') {priority, input, word, no interrupt} else cont_st********************************************} Function osdStopDMA(Channel:integer; DMA32bit:boolean; StopCount:integer):boolean; var DMAPtr:PtrChar; Use32BitChannel:boolean; pChannel32:^Channel32BitType; Count32:integer; pChannel16:^Channel16BitType; at := hex('000E'); {priority, output, word, no interrupt} end; end; end; {************************************************************************* * osdKillDMA ************************************************************************* * * On Input Count16:S_SHORT; begin Use32BitChannel := osdDMA32bit; osdStopDMA := true; DMAPtr := isc_table[3].card_ptr; if Use32BitChannel then begin {Get pointer to 32 bit DMA channel} pChannel32 := addr(DMAPtr^,(Channel+1)*hex('100')); with pChannel32^ d: DMA channel is actively transfering data. * * * Functional Description: * * shutdown active DMA Channel. * Force all data (instruction and data) in the processor's cache * to be flushed. * * On Output: active DMA channel is shutdo begin if DMA32bit then Count32 := (StopCount Div 4) - 1 else Count32 := (StopCount Div 2) - 1; if (count <> Count32) then begin {wait} osdStartTimer(one_second); repeat until (count <= Count32) or (osdTimeExpired);      equ 1 sysflag2 equ $FFFFFEDA REFA CHECK_TIMER in system POWERUP code LMODE CHECK_TIMER ************************************************************************* * START_TIMER timing setup * * ASSUMES: * Pascal Workstation SCSI onion skin. The file/module OSD_HL is responsible for interfacing the O/S to the scsi driver from a high level. (i.e. link into isc_table, get memory, and initialize system) The file/module OSD_LL is responsible for interfacin - sp+4 points to location of a timer record * the TIME field is a delay in milliseconds * RETURNS: * - The TIME field contains a value to match against the timer * (no timer present then this field is a scaled count) ***g the driver to the lowest levels. } PROGRAM PWS_SCSI{{(OUTPUT){for debug}; $SEARCH 'OSD_LLA', 'HWIA_UTIL'$ $PAGE$ $INCLUDE 'ST_PROCS'$ $PAGE$ $INCLUDE 'SCSI_DEFS'$ $PAGE$ $INCLUDE 'SCSI_UTIL'$ $PAGE$ $INCLUDE 'OSD_LL'$ $PAGE$ $INCLUDE 'HWI_UTILS'$ $PA if (count <> Count32) then osdStopDMA := false; end; end; end else begin {Get pointer to DMA channel} pChannel16 := addr(DMAPtr^, Channel*8); with pChannel16^ do begin Count16 := ((StopCount Div 2) - 1) MOD hex('10000'); if ********************************************************************** OSD_LLA_START_TIMER equ * movea.l 4(sp),a0 get addr of timer rec btst #timer_present,sysflag2 bne.s soft_start st 4(a0) set the first time flag jmp CHECK_TIM(count <> Count16) then begin {wait} osdStartTimer(one_second); repeat until (count <= Count16) or (osdTimeExpired); if (count <> Count16) then osdStopDMA := false; end; end; end; osdKillDMA(Channel); end; {************ER soft_start equ * * scale the time out value for use as a counter move.l (a0),d0 lsl.l #4,d0 x 16 move.l d0,(a0) move.l (sp)+,(sp) move the return address rts *************************************************************************************************************************** * osdReleaseDMAChannel ************************************************************************* * * On Input: Channel is NOT active. * * * Functional Description: * * Give the ch*********** * FUNCTION TIME_EXPIRED(VAR TIME: INTEGER):BOOLEAN; * ASSUMES: * - sp+4 points to a timer record (set up by start_timer) ************************************************************************* OSD_LLA_TIME_EXPIRED EQU * clr.b 8(sannel back to the O/S. * * On Output: * * *************************************************************************} Procedure osdReleaseDMAChannel(Sc:S_TYPE_ISC); begin {release a DMA channel} dma_release(isc_table[Sc].io_tmp_ptr); end; end; p) clear the function value btst #timer_present,sysflag2 bne.s soft_check move.l 4(sp),-(sp) copy the timer rec address jsr CHECK_TIMER bpl.s timex1 timex0 move.b #1,8(sp) timex1 move.l (sp)+,(sp) move the return add MNAME OSD_LLA SRC MODULE OSD_LLA; SRC IMPORT SCSI_DEFS, iodeclarations; SRC EXPORT SRC TYPE SRC TIMER_REC = RECORD SRC TIME : INTEGER; SRC FLAG : s_short; { MSR } SRC END;ress rts soft_check equ * movea.l 4(sp),a0 subq.l #1,(a0) bpl timex1 bra timex0 * * module initialization * OSD_LLA_OSD_LLA EQU * RTS end  SRC SRC PROCEDURE START_TIMER(VAR TIME : TIMER_REC); SRC FUNCTION TIME_EXPIRED(VAR TIME : TIMER_REC):BOOLEAN; SRC SRC END; { OSD_LLA } DEF OSD_LLA_OSD_LLA DEF OSD_LLA_START_TIMER DEF OSD_LLA_TIME_EXPIRED timer_present {system options} $modcal on$ $allow_packed on$ $partial_eval on$ {code generation options} $debug off$ $iocheck off$ $ovflcheck off$ $range off$ $stackcheck off$ {listing options} $lines 57$ $pagewidth 130$ $copyright 'Hewlett Packard Company, 1989'$ {       GE$ $INCLUDE 'STATE_DRV'$ $PAGE$ $INCLUDE 'MESSAGES'$ $PAGE$ $INCLUDE 'COMMANDS'$ $PAGE$ $INCLUDE 'SCSI_ISR'$ $PAGE$ $INCLUDE 'OSD_HL'$ $PAGE$ import OSD_HL; begin osdhStartUp; end. ufferBlockType = 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:Boo{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 Palean; DoNotDisconnect:Boolean; CmdPtr:ANYPTR; CmdLen:s_byte; BufIn:BufferBlockType; BufOut:BufferBlockType; SessionCompleteCallBack:ScsiCallBackType; {set by SCSI Bus Driver during session} SessionState:SessionStateType; ckard 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 intende 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:ANd 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 modifyYPTR; 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 !!! 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 = ^S: 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 : bytessionBlockType; ScsiDeviceType = 0 .. 7; InternalErrType = ( NoIntErr, ScsiStackingErr, RunLevelErr, StateMachineErr, ScsiInteruptErr, ScsiAddressErr, SelectRetryErr, ScsiManXferErr, ScsiXferErr, XferRetryErr, ScsiEscapeErr, ScsiPhe; 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_aseErr, ScsiCatastrophicErr, ScsiBadMsg, ScsiTimeOutErr, ScsiXferParmErr, ScsiMiscErr ); SessionStateType = ( SessionWaiting, {Session is initialized and waiting to be started.} SessionRunning, {Session running (State 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} Machine is started)} SessionSuspended, {Target disconnected, bus released, awaiting reselection} SessionComplete {Session terminated, either normally or with an err} ); ScsiCallBackType = Procedure(pSB:PtrSessionBlockType); B:-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;       ks, NumBytesBlock:integer; Buffer:ANYPTR); procedure ScsiTapeWrite( pSB:PtrSessionBlockType; BlockStart, NumBlocks, NumBytesBlock:integer; Buffer:ANYPTR); procedure ScsiDiscRead( pSB:PtrSessionBlockType;  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;  BlockStart, NumBlocks, NumBytesBlock:integer; Buffer:ANYPTR); procedure ScsiDiscWrite( pSB:PtrSessionBlockType; BlockStart, NumBlocks, NumBytesBlock:integer; Buffer:ANYPTR); procedure ScsiDiscFormat( pSB:PtrSessionBl 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_capaci 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:PtrSessiockType; InterLeave:s_short); procedure ScsiDiscPrevent( pSB:PtrSessionBlockType); procedure ScsiDiscAllow( pSB:PtrSessionBlockType); implement const DEBUG = FALSE; TDEBUG = FALSE; type MiscTemplate = packed record MiscpScBlock:ANYPonBlockType):integer; procedure ScsiSessionSense( SelectCode:S_TYPE_ISC; pBuf:ANYPTR; var Length:integer); procedure ScsiSessionAbort(pSB:PtrSessionBlockType); procedure ScsiReset( SelectCode:S_TYPE_ISC); procedure ScsiModeSelectTR; 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 : by(pSB:PtrSessionBlockType; pDB : PtrModeSelectDataType; sector_size : integer); procedure ScsiModeSense(pSB:PtrSessionBlockType; pDB : PtrModeSenseDataType ; var sector_size : integer); procedure ConfigureMcBeth(pSB : PtrSessionBlockTyte; 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 pe); function SyncMcBeth(pSB : PtrSessionBlockType): integer; procedure TapeName( uep : uep_type; var i : string80) ; procedure ScsiTapeUnload(pDAV : PtrDeviceAddressVectorsType); procedure SyncTeac(pSB : PtrSessionBlockType); procedure ScsiCheck 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:(deviceDev( pSB:PtrSessionBlockType); procedure ScsiDevInfo( pSB:PtrSessionBlockType; var DevType, AnsiVersion:integer; var Removable:boolean; var VendorString:string255); procedure ScsiDiscSize( pSB:PtrSessionBlockType; var NumBy_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 tesBlock, NumBlocksTrack, NumTracksCylinder, NumCylinders:integer); procedure ScsiDiscBlocks( pSB:PtrSessionBlockType; var NumBytesBlock, TotBlocks:integer); procedure ScsiTapeRead( pSB:PtrSessionBlockType; BlockStart, NumBloc : 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       ty_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; 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,  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 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 re : 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 quest_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 : bool : 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 = mean; 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 : 0ode_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_c..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;); ode : 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..72:(block_n : 0..16777215)); end; ptr_request_sense_data_type = ^request_sense_data_type; SenseType = (sNoSense, sRecoveredError, sNotReady, sMediumError, sHardwareError, sIllegalRequest, sUnitAttention, sDataProtect, sBlankChe; 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 ck, 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,  : 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,  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       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. 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_i.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,n_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,  : 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  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_byt : 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, e; 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,  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, 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 : by 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 :te; 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, 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, p 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 ad3 : 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  : 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;        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 :areError} zbadmode, {sIllegalRequest} zmediumchanged, {sUnitAttention} zprotected, {sDataProtect} znoblock, {sBlankCheck} zcatchall, {sVendor} zcatchall, {sCopyAbort}  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 = unl znodevice, {sCommandAbort - only sense with this translation} zcatchall, {sEqual} znosuchblk, {sVolumeOverflow} zcatchall, {sMisCompare} zcatchall, {sReserved} zbadmode, oad_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 :  {DriverError} zcatchall, {IllegalStatus} zcatchall]; {GetSenseFailed} InternalXlateConst = InternalXlateType[ inoerror, {NoIntErr} zcatchall, {ScsiStackingErr} zcatchall, {Rbyte; 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, unlevelErr} zcatchall, {StateMachineErr} zstrangei, {ScsiInteruptErr} znodevice, {ScsiAddressErr} znodevice, {SelectRetryErr} zbadhardware, {ScsiManXferErr} zbadhardware, { 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..ScsiXferErr} ztimeout, {XferRetryErr} zcatchall, {ScsiEscapeErr} zcatchall, {ScsiPhaseErr} zcatchall, {ScsiCatastrophicErr} zcatchall, {ScsiBadMsg} ztimeout, {ScsiT1; 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 :imeOutErr} zbadmode, {ScsiXferParmErr} zcatchall]; {ScsiMiscErr} $IF TDEBUG$ procedure dump_trace(var sb:SessionBlockType); label 1; TYPE EventType = ( { NOTE: The following event list must match the assemble 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 [ InternalErrTypr 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, SaveDataPe ] of iorsltwd; const SenseXlateConst = SenseXlateType[ inoerror, {sNoSense} inoerror, {sRecoveredError} znotready, {sNotReady} zbadblock, {sMediumError} zbadhardware, {sHardwtr, 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:EVE      ne : 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 ber; 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; Devigin 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(ce := 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}NTTYPE); 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; 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 c 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.anil) and not found do with modp^ do begin ptr := defaddr; while (ptr.a 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:intege       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 := TRU(inoerror); recover begin if NOT OkToCall then begin SessionState := SessionComplete; InternalStatus := ScsiAddressErr; if not Overlap then ScsiHandleSession := ScsiCheckError(pSB) else ScsiHandleSession := ord(inoerror); end E; 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 Miscelse escape(escapecode); end; end; end; function ScsiSessionComplete(pSB:PtrSessionBlockType):BOOLEAN; begin ScsiSessionComplete := (pSB^.SessionState = SessionComplete); end; function ScsiCheckError( pSB:PtrSessionBlockType):integer; var statusSenseLength := 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: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; 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 Abo <> 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, '--rtCommandRetry := 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; InternalSt--------------------------------------'); writeln(listing, 'TRACE FOR SCSI COMMAND: ',ord(c):1); writeln(listing, '----------------------------------------'); dump_trace(pSB^); end; $END$ ScsiCheckError := Ord(InternalXlateConst[Internatus := 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 alStatus]); 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  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 AbortComma 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$ ndRetry < 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 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        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 ScsiTapeRead( pSB:PtrSessionBlockType; BlockStart, NumBlocks, NumBytesBlock:integer; Buffer:ANYPTR); label 100; var rtcmd:read_tape_cmd_type; tries,remaining :integer; c=========================================================} procedure ScsiTapeUnload(pDAV : PtrDeviceAddressVectorsType); var SB : SessionBlockType; pSB : PtrSessionBlockType; utcmd : unload_tape_cmd; iotemp, saveior : integer; begin saveior := iorurrent_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 the 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 := ordesult; 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 t(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:inthen { 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(eger); 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 LepSB, 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 ); ioresngth := 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( ult := saveior; end; {=======================================================================} function ReadTapePosition(pSB:PtrSessionBlockType; var where : integer) : integer; var rtpcmd : read_tape_position; rtpdata : tape_position_data_type; 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:PtrS 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 essionBlockType; 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),} 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; {====      n 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 .. 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 writel. } 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 ioresultn('near the end, ioresult is set to 1 ...'); ioresult := 1; end; } end; {======================================================================} procedure ScsiModeSense(pSB:PtrSessionBlockType; pDB : PtrModeSenseDataType ; var sector_size := 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 <>  : 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;ord(zbadblock)) or (tries >= 2); end; 100: end; {======================================================================} procedure ScsiTapeWrite(pSB:PtrSessionBlockType; BlockStart, NumBlocks, NumBytesBlock:integer; Buffer:ANYPTR); label 100; var  { 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),} size 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 befoof(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 re 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 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; {===============================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 2=======================================} 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 56; 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, : 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_i      := 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_lenscmd), sizeof(mscmd), { addr(msdata)} nil, 0, {sizeof(msdata), } false, pDB, 12 {sizeof(msdata)} , false); if iotemp <> 0 then ioresult := iotemp; { ?????????? } end; {======================================================= := 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); ===================} 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) elset.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  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 ioreretry } 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[5sult := iotemp; { ?????????? } end; {==========================================================================} {======================================================================} procedure ScsiModeSelect(pSB:PtrSessionBlockType; pDB : PtrModeS]; 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; {==========electDataType; 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;============================================================} procedure InitModeSelect(pSB:PtrSessionBlockType; pDB : PtrModeSelectDataType; sector_size : integer; cylinders : integer); type tricky_as_hell = record case boolean of FA 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] := cramLSE: (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 : inte_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 := ScsiHandleSeger; 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] ssion(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(m      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 := ScsiHandl, 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; { mediaeSession(pSB, addr(rcmd), sizeof(rcmd), Buffer, NumBlocks*NumBytesBlock, true, Nil, 0, false); until (ioresult <> ord(zbadblock)) or (tries >= 2); end; end; {================================================================= 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 : P} 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_ctrSessionBlockType); 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); { md_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 := ScAdjust 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] := siHandleSession(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, 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 Ta 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; {==================peName ( uep : uep_type; var i : string80 ) ; var SB : SessionBlockType; pSB : PtrSessionBlockType; DAV : DeviceAddressVectorsType; pDAV : PtrDeviceAddressVectorsType; iotemp, saveior, devtype, ver : integer; moveable : boolean; vstring==============================================} { 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; ut : 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; iocmd : 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, 0result := saveior; end; {================================================================} procedure SyncTeac(pSB : PtrSessionBlockType); var sense_size : integer; data_block : mode_sense_data_type; fake_buffer : packed array[0..2047] of char; {      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 tSAVED_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); } {*******************************************hen 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 data_block.medtype = 136 then high_density := TRUE; {*******************************************************************} { make sure cylinders = 77 or 80 depending ... } if sense_size = 512 then begin { could be 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; sav 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 eior : 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.BufL { 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 ten := 4; real_buf.DoDMA := FALSE; scode := pSB^.SelectCode; baddr := pSB^.Device; dunit := pSB^.LUN; high_density := FALSE; maxbytes_should_be := 0; {*********************************************************************} { Temporarily knock oempior := 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. ut 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 beg 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 in 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 controllread_worked then { Pascal Workstation Only } begin { WRITELN('READ WORKED - ADJUSTING CYLINDER COUNT'); } {******************************************************************} for i := 1 to maxunit do begin with unitable^[i] do ifer 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 -  ((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      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 theln('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 : ',cylinderis 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(ps_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 wriSB,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_blteln('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'); } {************************************ock); } 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*********************************} 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_shou 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 ld_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 <> 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 := 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 ((ior 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('Nesult <> 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 OT 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 writ(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;      eger; 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), ta), 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 Nu 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] =mBlocksTrack := 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; end; end; {*********************************************************************} end; { read worked } ioresult := saveior; { RESTORE PREVIOUS IORESULT } end; { procedure sync_teac } procedure ScsiDevInfo( pSB:PtrSessionBlock 'A') and (vstring[4] = 'C')) then syncteac(pSB) ; ioresult := ord(zmediumchanged); end; end; end; procedure ScsiDiscSize( pSB:PtrSessionBlockType; var NumBytesBlock, NumBlocksTrack, NumTracksCylinder, NumCylinders:integer)Type; 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) ; 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; devtyp 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 := ''; setse, 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_trlen(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 beconst; 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 gin 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 := strrtri 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] = 'Em(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 : int') 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(rcda      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('1000; 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(00') 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} NumBlocksTrcharptr(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 ack := 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 < 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 #tracnumber 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 -ks} 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 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, ni : 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 l, 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 (pPag 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')) the^.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))^); NumBlocen BEGIN syncteac(pSB); { writeln('SYNCED FROM ScsiDiscBlocks'); } have_teac := TRUE; END; rccmd := read_capacity_cmd_const; rccmd.lunit := LUN; ioresult := ScsiHandleSession(pSB, addr(rccmd), sksTrack := 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])izeof(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:PtrSessionBlockTy     ormat_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, addrthen begin IsrSessionFound := true; mask := IsrMask; end; end; i := i + 1; until (IsrSessionFound) or (i > 7); if (not IsrSessionFound) and (ints.ints = Reselected) then begin i := ord(data_regs.temp) - ord(bdid); j := (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 0; while (i <> 1) and (j < 7) do begin i := osdBitLsR(i, 1); j := j + 1; end; pSB := DeviceSessionPtrs[j]; if pSB <> nil then with pSB^, InternalBlock do begin if (SessionState = SessionSuspended) and (ISRWaiting) then pe; 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 :=  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:Ptrread_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, NumBSessionBlockType); 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), locks*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 Nil, 0, false, Nil, 0, false); end; end; end. {module SCSIIF} _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 := { SCSI ISR handler. Contains the SCSI ISR interface. } module SCSI_ISR; import SCSI_DEFS, SCSI_UTILS, OSD_LL, HWI_UTILS, STATE_DRIVE, COMMANDS; export procedure isrScsiISR(Sc:S_TYPE_ISC); implement procedure isrScsiISR(Sc:S_TYPE_ISC); var pScBlock: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))PtrSelectCodeBlockType; pSB:PtrSessionBlockType; i,j:integer; IsrSessionFound:Boolean; ResultCode:EventType; b:integer; mask:integer; begin try { Find the first session block that is in a run state (only one allowed) } mask := 0; pScBlock := o 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 := fsdGetScBlock(Sc); with pScBlock^, PtrScsiChip^ do begin IsrSessionFound := false; i := 0; repeat pSB := DeviceSessionPtrs[i]; if pSB <> nil then with pSB^, InternalBlock do begin if (SessionState = SessionRunning) and (ISRWaiting)      begin IsrSessionFound := true; mask := IsrMask; end; end; end; if (IsrSessionFound) and (mask <> 0) and (osdBitOr(ints.ints, mask) = mask) then begin { session isrproc is expecting and can handle the isr } StartState(pSB)tartState(PtrSessionBlock:PtrSessionBlockType); Var SaveLevel:integer; i:integer; MyMachine['SCSI_DRIVER'] : integer; begin with PtrSessionBlock^, InternalBlock.pScBlock^ do begin { set interrupt level } SaveLevel := osdGetRunLevel; if SaveLevel; end else begin { Either no session claims ISR or session can't handle it. } if IsrSessionFound then begin { session can not handle the isr, kill the session and reset the device } utlSetInternalErr(pSB, ScsiIn < ScsiIntLevel then osdSetRunLevel(ScsiIntLevel) else SaveLevel := 100; {larger than the largest interupt level} { If session is not running, initialize the exec's control record. } if SessionState = SessionWaiting then begin SessionState :teruptErr); pSB^.InternalBlock.ISRError := True; StartState(pSB); end else begin { Reset the Hardware and unlink all sessions. } cmdSCCleanUp(Sc); end; end; end; recover begin cmdSCCleanUp(Sc); end; {recover} en= SessionRunning; init_exec_control(addr(InternalBlock.StateControlRec), PtrSessionBlock, MyMachine, state_stack_size); if DoTrace then begin i := TraceSize Div sizeof(trace_data_elt); TraceStuff := addr(InternalBlock.StateControlRec); d; end; end else begin i := 0; TracePtr := Nil; end; init_trace(addr(InternalBlock.StateControlRec), i, TracePtr); trace_control(addr(InternalBlock.StateControlRec), DoTrace); { turn on tracing } end; { Call the state machine. } exec(addr(I{ Scsi Utilities Routines Utilities that are specifically related to SCSI operations, and do not have a home in HWI_UTILS, MESSAGES, or COMMANDS should be placed here. } module SCSI_UTILS; import SCSI_DEFS; export Procedure utlSetInternalErr(pSB:PnternalBlock.StateControlRec)); { If the state machine terminated abnormally, be sure that the sessioncomplete flag is set. } with InternalBlock.StateControlRec do begin if (mdone) and (exit_code < 0) and (SessionState <> SessionComplete)trSessionBlockType; ie:InternalErrType); implement Procedure utlSetInternalErr(pSB:PtrSessionBlockType; ie:InternalErrType); begin with pSB^ do if InternalStatus = NoIntErr then {No internal error has been encountered} InternalStatus := ie; end; end then begin utlSetInternalErr(PtrSessionBlock, StateMachineErr); InternalBlock.StateErrCode := exit_code; InternalBlock.StateErrExt := exit_extension; call(InternalBlock.SysCleanUp, SelectCode); end; end; { reset interrupt level } ; if SaveLevel < ScsiIntLevel then osdSetRunLevel(SaveLevel); end; end; end; { Module: State_Drive interfaces the scsi driver to the state driver (exec) in state_procs } MODULE STATE_DRIVE; import STATE_PROCS, SCSI_DEFS, SCSI_UTILS, OSD_LL; export Procedure StartState(PtrSessionBlock:PtrSessionBlockType); implement Procedure S INCLUDE ST_EQU *$machine_name AbortPath *$global_recover exec_err ******************************************************* *state_1 standard * MESSAGES_msgIsPathActive *$event_pairs_catch * NoEvent,state_2 *       standard * MESSAGES_msgIdentifyMsg * HWI_UTILS_hwiGetPhase *$event_pairs_catch * NeedSynchParms,state_3 * MsgIn,state_4 * ScsiErr,state_exit * state_exit ***************2767; state_name_string = string[17]; control_recp = ^control_rec; stack_rec = record machine : anyptr; oldstate: anyptr; end; trace_data_type = (tstate,tproc,tmachine,tevent); trace_data_elt = record case data_type : trace**************************************** *state_3 standard * MESSAGES_msgInitSynchParms * HWI_UTILS_hwiGetPhase *$event_pairs_catch * state_exit ******************************************************* *state_data_type of tstate, tevent : (short_data : st_short); tproc, tmachine : (long_data : integer); end; trace_data_ptr = ^trace_data; trace_data = array[1..maxint] of trace_data_elt; trace_name_elt = packed record  state_exit ******************************************************* *state_2 standard * HWI_UTILS_hwiGetMsgOut *$event_pairs * MsgOut,state_3 * ScsiErr,state_exit * BusFree,state_exit * _4 standard * MESSAGES_msgGetMsg *$event_pairs_catch * Synch,state_5 * ScsiErr,state_exit * state_6 ******************************************************* *state_5 standard *  BusBusy,state_exit ******************************************************* *state_3 standard * MESSAGES_msgAbortMsg * HWI_UTILS_hwiGetPhase *$event_pairs_catch * ScsiErr,state_exit * sta MESSAGES_msgTargetSynchParms * HWI_UTILS_hwiGetPhase *$event_pairs_catch * state_exit ******************************************************* *state_6 standard * MESSAGES_msgRejectMsg * HWIte_exit ******************************************************* *exec_err standard * COMMANDS_cmdStateErr *$event_pairs_catch * state_exit ******************************************************* *state_exit mexit * _UTILS_hwiGetPhase *$event_pairs_catch * MsgIn,state_4 * MsgOut,state_2 * state_exit ******************************************************* *exec_err standard * COMMANDS_cmdStateErr *$event_pai 0 ******************************************************* *$end_machine ******************************************************* rs_catch * state_exit ******************************************************* *state_exit mexit * 0 ******************************************************* *$end_machine ****************************************************** INCLUDE ST_EQU *$machine_name EstablishPath *$global_recover exec_err ******************************************************* *state_1 standard * MESSAGES_msgSelect * HWI_UTILS_hwiGetPhase *$event_pairs_catch * *  WaitForIsr,state_1a * MsgOut,state_2 * state_exit ******************************************************* *state_1a suspend * state_1 ******************************************************* *state_2 MODULE STATE_PROCS; { state machine executive for machine maker 4.0 } EXPORT CONST bad_state_type = -1; bad_exit_type = -2; event_not_found = -3; too_many_calls = -4; proc_escaped = -5; TYPE st_short = 0..65535; short_signed= -32768..3      offset : st_short; name : state_name_string; end; trace_name_table_ptr = ^trace_name_table_type; trace_name_table_type = array[1..maxint] of trace_name_elt; control_ptr = ^control_rec; control_rec = record user_space : anyph cont^ do begin tactive := false; ttotal := size; tremaining := size; tdata := p; end; end; { init_trace } procedure trace_control(cont : control_ptr; on_off : boolean); begin with cont^ do begin tactive := on_off;tr; states : anyptr; { state machine table } current_state : st_short; { offset into states } exit_code : short_signed; exit_extension: short_signed; mdone : boolean; tactive : boolean; tremaining : if on_off then tactive := tremaining>0; end; end; { trace_control } procedure init_exec_control( cont : control_ptr; user : anyptr; anyvar machine : integer; stack_size : integer); begin with cont^ do  integer; ttotal : integer; tdata : trace_data_ptr; max_stack : st_short; last : st_short; stack : array[1..1] of stack_rec; { this record will be allocated to contain the space specified inbegin user_space := user; states := addr(machine); current_state := 0; exit_code := 0; exit_extension:= 0; mdone := false; tactive := false; { disable tracing } tremaining := 0; max_stack := stack_size; last := 0; end the max_stack field } end; procedure exec(cont : control_ptr); procedure init_exec_control(cont : control_ptr; user : anyptr; anyvar machine : integer; stack_size : integer); procedure reset_exec_control(cont : control_p; end; { init_exec_control } procedure reset_exec_control(cont : control_ptr; user : anyptr); begin with cont^ do begin user_space := user; current_state := 0; exit_code := 0; exit_extension:= 0; mdone := false; tr; user : anyptr); procedure init_trace(cont : control_ptr; size : integer; p:ANYPTR); procedure trace_control(cont : control_ptr; on_off : boolean); IMPLEMENT TYPE short_ap = ^short_array; state_proc = procedure(stuff:anyptr; var event:st_stactive := false; tremaining := ttotal; if last<>0 then states := stack[1].machine; last := 0; end; end; { reset_exec_control } procedure exec(cont :control_ptr); const first_state = 2; type intp =hort); pairs_rec = packed record event, next : st_short; end; short_array = packed array[0..100] of st_short; short_pairs = packed array[0..100] of pairs_rec; int_array = packed array[0..100] of integer; mixed_array = record case in ^integer; var running: boolean; state : state_ptr; { also global error state offset } prev_state : state_ptr; procp : intp; count : st_short; event : st_short; temps : st_short; funny : record cteger of 1:(exits:short_array); 2:(exit_pairs:short_pairs); 3:(procs:int_array); end; state_ptr = ^state_rec; state_rec = packed record class : char; exits_type: char; case integer of 0:(); 1:(nexits : charase integer of 1:(proc : state_proc); 2:(proca : integer; static : integer); end; procedure do_trace(ttype:trace_data_type); begin with cont^, tdata^[tremaining] do begin data_type := ttype; case data_type of ; nprocs : char; table : mixed_array); 2:(next_s : short_signed); 3:(next_m : anyptr); 4:(next_p : integer) end; $RANGE OFF$ procedure init_trace(cont : control_ptr; size : integer; p:anyptr); begin wit tstate : short_data := current_state; tmachine : long_data := ord(states); tproc : long_data := funny.proca; tevent : short_data := event; otherwise end; tremaining := tremaining - 1; tactive := trem     d_exit_type); end; { case exit_type } end; { with state^ } end; { find_next_state } begin { exec } funny.static := 0; running := true; state := nil; with cont^ do begin if tactive then do_trace(tmachine); mdone_state := next_s; end; #4:{ DONE_EXIT } begin shutdown(next_s); end; otherwise shutdown(bad_state_type); end; end; until not running; end; end;{ exec } END; { STATE_PROCS }  := false; if current_state = 0 then current_state := first_state; { skip error index } repeat prev_state := state; state := addr(intp(states)^,current_state); if tactive then do_trace(tstate); with state^ do begin case class of  INCLUDE ST_EQU *$machine_name SCSI_DRIVER *$global_recover state_10 ******************************************************* *state_1 standard * HWI_UTILS_hwiGetPhase *$event_pairs * BusFree,state_3 * BusBusaining>0; end; end; { do_trace } procedure shutdown(ecode:short_signed); var is_bad : boolean; begin with cont^ do begin is_bad := true; if exit_code=0 then if (ecode=proc_escaped) or (ecode=event_not_found) then #0:{ STANDARD } begin try case exits_type of #0,#1:procp := addr(table.exits[ord(nexits)]); #2,#3:procp := addr(table.exit_pairs[ord(nexits)]); otherwise shutdown(bad_exit_type); end; count := ord(nprocs); begin exit_code := ecode; if (ecode=proc_escaped) then exit_extension := escapecode else if (ecode=event_not_found) then exit_extension := event; current_state := short_ap(states)^[0]; is_bad := false; end; if is_bad then begin while count>0 do { execute all the procedures } begin funny.proca := procp^; if tactive then do_trace(tproc); call(funny.proc,user_space,event); if tactive then do_trace(tevent); if event<>0 then count := 0  mdone := true; running := false; exit_code := ecode; end; end; end; { shutdown } procedure find_next_state; label 1; begin with cont^, state^ do begin case exits_type of #0,#1: { singles & singles_catch } else begin count := count-1; procp := addr(procp^,sizeof(procp^)); end; end; find_next_state; recover begin shutdown(proc_escaped); end; end; #1:{ MCALL } if last0 then begin } end else count := succ(count); end; { check for catch all } if exits_type = #3 then current_state := table.exit_pairs[ord(nexits)-1].next else shutdown(event_not_found); 1: end; otherwise shutdown(bastates := stack[last].machine; state := stack[last].oldstate; last := last - 1; if tactive then do_trace(tmachine); find_next_state; end else shutdown(next_s); #3:{ SUSPEND } begin running := false; current     y,state_2 * ScsiErr,state_12 ******************************************************* *state_2 standard * MESSAGES_msgWaitTimeOrFree *$event_pairs * BusFree,state_3 * ScsiErr,state_12 **********In,state_11 * CmdPhase,state_11 * DataPhase,state_11 * StatusPhase,state_11 * BusBusy,state_11 * MsgOut,state_11 ******************************************************* *state_8 s********************************************* *state_3 mcall * EstablishPath *$event_pairs * CmdPhase,state_4 * BusBusy,state_2 * StatusPhase,state_6 * ScsiErr,state_12 * tandard * COMMANDS_cmdTerminateSession *$event_pairs_catch * state_exit ******************************************************* *state_10 standard * COMMANDS_cmdStateErr *$event_pairs_catch * st BusFree,state_11 * MsgIn,state_11 * MsgOut,state_11 * DataPhase,state_11 ******************************************************* *state_4 mcall * DoTransfer *$event_pairs * ate_12 ******************************************************* *state_11 standard * COMMANDS_cmdPhaseErr *$event_pairs_catch * state_12 ******************************************************* *state_12 mcall * DataPhase,state_5 * StatusPhase,state_6 * ScsiErr,state_12 * BusBusy,state_11 * CmdPhase,state_11 * BusFree,state_11 * MsgIn,state_11 * MsgOut,state_11 ****** AbortPath *$event_pairs_catch * BusFree,state_13 * BusBusy,state_13 * state_14 ******************************************************* *state_13 standard * COMMANDS_cmdTerminateSession ************************************************** *state_5 mcall * DoTransfer *$event_pairs * StatusPhase,state_6 * ScsiErr,state_12 * BusBusy,state_11 * CmdPhase,state_11 * $event_pairs_catch * state_exit ******************************************************* *state_14 standard * HWI_UTILS_hwiHardReset * COMMANDS_cmdUnlinkAllSessions *$event_pairs_catch * state_ex DataPhase,state_11 * BusFree,state_11 * MsgIn,state_11 * MsgOut,state_11 ******************************************************* *state_6 standard * COMMANDS_cmdGetStatus * it ******************************************************* *state_exit mexit * 0 ******************************************************* *$end_machine  HWI_UTILS_hwiGetPhase *$event_pairs * MsgIn,state_7 * ScsiErr,state_12 * DataPhase,state_11 * StatusPhase,state_11 * BusBusy,state_11 * CmdPhase,state_11 *  INCLUDE ST_EQU *$machine_name TerminatePath *$global_recover exec_err ******************************************************* *state_1 standard * MESSAGES_msgGetMsg *$event_pairs_catch * CmdComplete,state_2 *  BusFree,state_11 * MsgOut,state_11 ******************************************************* *state_7 mcall * TerminatePath *$event_pairs * BusFree,state_8 * ScsiErr,state_12 * Msg ScsiErr,state_exit * state_3 ******************************************************* *state_2 standard * MESSAGES_msgWaitTimeOrFree *$event_pairs_catch * state_exit ***************************************     r information output to screen} { dvrtemp2 values. dvrtemp2 initialized to -1 by CTABLE. } DeviceOK = -1; DeviceAlwaysOffline = 1; type ScsiTmRecType = packed record CurrentBlock:integer; BlockBuffer:packed array [ 0 .. (MAXBLOCKSIZE-1) ]  NumBlocks); if ioresult = ORD(inoerror) then begin dvrtemp := BlockSize; $IF DEBUG$ WRITELN('READ CAPACITY: BLOCK SIZE IS ',BlockSize); WRITELN('READ CAPACITY: MEDIUM SIZE IS ', BlockSize*(NumBlocks)); $END$ { if block is of char; SB:SessionBlockType; end; PtrScsiTmRecType = ^ScsiTmRecType; var $if TDEBUG$ LISTING:TEXT; LocTracePtr:ANYPTR; $END$ pTmRec:PtrScsiTmRecType; procedure scsidisc(fp : fibp; request : amrequesttype; anyvar bnot a power of 2, then then can't support this device. } i := BlockSize; while(i > 0) and not odd(i) do begin i := i div 2; end; if (i <> 1) {blocksize isn't a power of 2!} or (BlockSize > MAXBLOCKSIZE) then begin dvrtemp**************** *state_3 standard * MESSAGES_msgRejectMsg * HWI_UTILS_hwiGetPhase *$event_pairs_catch * MsgIn,state_1 * state_exit ******************************************************* *execuffer : window; length, position : integer); implement { type uep_type = ^unitentry; } { JWH now in SCSIIF } Function CheckDev(pUnit:uep_type; pSB:PtrSessionBlockType):boolean; begin { return TRUE if medium has changed, FALSE for ALL ot_err standard * COMMANDS_cmdStateErr *$event_pairs_catch * state_exit ******************************************************* *state_exit mexit * 0 ******************************************************* her cases } with pTmRec^ do begin ScsiCheckDev(pSB); if (ioresult = ord(zmediumchanged)) then begin CheckDev := TRUE; if (not pUnit^.ureportchange) then begin { continue to talk with device, but force internal buffers to b*$end_machine ******************************************************* e empty. } CurrentBlock := -1; ioresult := ord(inoerror); end; { for McBeth tape drive : } if pUnit^.devid = -2 then begin if SyncMcBeth(pSB) = 0 then begin CheckDev := FALSE; ioresult := ord(inoerror); {system options} $modcal on$ $allow_packed on$ $partial_eval on$ {code generation options} $debug off$ $LINENUM 10000$ $iocheck off$ $ovflcheck off$ $range off$ $stackcheck off$ {listing options} $lines 57$ $pagewidth 130$ $copyright 'Hewlett Packard Com end; end; end else CheckDev := FALSE; end; end; Procedure Inquire(pUnit:uep_type; pSB:PtrSessionBlockType); var DevType, AnsiVersion:integer; Removable:boolean; s:string255; begin with pUnit^ do begin ScsiDevInfo(pSB, DevType, AnsiVerpany, 1989'$ program scsidisc_init{{(INPUT, OUTPUT){For DEBUG and XDEBUG}; {} $search 'SCSILIB.'$ {{ $search 'SCSILIB.', 'PWS_SCSI'$ {PWS_SCSI needed for TDEBUG} $page$ module SCSIDISCMODULE; import sysglobals, asm, IODECLARATIONS, SCSILIB, LOADER; exsion, Removable, s); if ioresult = ORD(inoerror) then begin { set the uisfixed flag in the unitable. pad = 1 means to treat removable media like hard disk. } if (pad = 1) then begin uisfixed := TRUE; if (NOT Removable) theport const MAXBLOCKSIZE = 65536; { 4096; } { JWH for McBeth support } DEBUG = FALSE; {general debug info output to screen - have to change SCSIIF!} TDEBUG = FALSE; {trace is generated on internal err - have to change SCSIIF!} XDEBUG = FALSE; {transfen pad := 0; end else uisfixed := NOT Removable; end; end; end; Procedure ReadCapacity(pUnit:uep_type; pSB:PtrSessionBlockType); var i:integer; BlockSize, NumBlocks:integer; begin with pUnit^ do begin ScsiDiscBlocks(pSB, BlockSize,      := 0; ioresult := ord(znomedium); end else if NOT uisfixed OR (umaxbytes = -1) then umaxbytes := BlockSize * NumBlocks; end else dvrtemp := 0; end; end; Procedure tmSCSIstatus(pUnit:uep_type; pSB:PtrSessionBlockType); var NewDevice ( (MediumHasChanged) or (ioresult = ord(znotready)) ) then begin { user has removed a floppy that is supposed to be treated like a hard disk - do not talk to it any more. } dvrtemp2 := DeviceAlwaysOffline; io, MediumHasChanged:boolean; DAV:DeviceAddressVectorsType; iotemp:integer; begin with pUnit^, pTmRec^, pSB^ do begin NewDevice := FALSE; MediumHasChanged := FALSE; if (sc <> SelectCode) or (ba <> Device) or (du <> LUN) or (dv <> SUN) result := ord(znodevice); end; end; if (NewDevice) or (MediumHasChanged) or (ioresult <> ord(inoerror)) then CurrentBlock := -1; end; end; {*******************************************************************} { Same as transfer but for sequent or (dvrtemp = 0) then begin $IF DEBUG$ WRITELN('INITIALIZING SCSI'); $END$ NewDevice := TRUE; DAV.sc := sc; DAV.ba := ba; DAV.du := du; DAV.dv := 0; ScsiSBInit(pSB, addr(DAV)); $if TDEBUG$ DoTrace :=ial devices , dt = 1. } { For McBeth support 5/18/93 JWH , devid = -2 in the unit table. } { } { Note - for tape_transfer, the number of bytes to transfer must be } { a TRUE; TraceSize := trace_size; TracePtr := LocTracePtr; $end$ end; if (NewDevice) or (NOT uisfixed) then begin MediumHasChanged := CheckDev(pUnit, pSB); { CRITICAL HOTSITE DEFECT REPAIR DEW 09/26/90 Problem is that n exact multiple of the blocksize ! } { Also, the transfer must begin exactly on a block boundary !} {*******************************************************************} procedure tape_transfer(pSB:PtrSessionBlockType; uumaxbytes is being overwritten in tmSCSIstatus on first call to TM. This causes partitioned discs to loose their boundaries, opening up the disc to potential data loss, i.e. unit #11 can now overwrite unit#12. Umaxbytes is being overwritteep: uep_type; request: amrequesttype; bufptr: charptr; abs_position, length: integer); var blocksize: integer; block, intra_block_offset, partial_length: integer; procedure checkio; begin if ioresult <> ord(inoerror) then escape(-10); end; n in the ReadCapacity call below because uisfixed is not set correctly. The uisfixed field is set by the Inquire command. An Inquire only needs to be done when dvrtemp = 0, which indicates CTABLE has just called the TM for the first ti begin {tape_transfer} with pTmRec^ do begin try {block size is known } blocksize := uep^.dvrtemp; block := abs_position div blocksize; intra_block_offset := abs_position mod blocksize; partial_length := length mod blocksize; length := length div me. As Inquire will swallow the status required by CheckDev, the Inquire follows this call. As the ioresult value set by CheckDev is checked after the Inqurie, ioresult needs to be saved. } if (dvrtemp = 0) then begin iotemp :blocksize; { now holds # blocks not bytes } $IF XDEBUG$ WRITELN; WRITELN; WRITELN; WRITELN('TAPE TRANSFER REQUEST: ', REQUEST); WRITELN('LENGTH: ', LENGTH); WRITELN('POSITION: ', ABS_POSITION); WRITELN('SCSI BLOCK: = ioresult; Inquire(pUnit, pSB); ioresult := iotemp; end; if (dvrtemp = 0) or ((MediumHasChanged) and (NOT uisfixed)) then begin ReadCapacity(pUnit, pSB); end else if (pad = 1) and {removable media treated like hard disk} ', BLOCK); WRITELN('SCSI INTRA-BLOCK: ', INTRA_BLOCK_OFFSET); WRITELN('SCSI BLOCKSIZE: ', BLOCKSIZE); readln; $END$ if ((intra_block_offset<>0) { doesn't start on block boundary !! } OR (partial_length <> 0)) { not even multiple of bl      ', ABS_POSITION); WRITELN('SCSI BLOCK: ', BLOCK); WRITELN('SCSI INTRA-BLOCK: ', INTRA_BLOCK_OFFSET); WRITELN('SCSI BLOCKSIZE: ', BLOCKSIZE); readln; $END$ if (blocksize <= 256) and (intra_block_offset<>0) then begin ioresult := ordIAL BLOCK'); $END$ {read block into TmRec} if CurrentBlock <> block then begin $IF XDEBUG$ WRITELN('ScsiDiscRead necessary: ',BLOCKSIZE:1,' ',BLOCK:1); $END$ CurrentBlock := block; ScsiDiscRead(pSB, block, 1, blocksize, add(zbadmode); escape(-10); end; { Calculate partial first block parameters. } partial_length := blocksize-intra_block_offset; if partial_length > length then {entire transfer in one block} partial_length := length; case request of readbytes, sr(BlockBuffer[0])); checkio; end; {read data from TmRec into user's buffer} moveleft(BlockBuffer[0], bufptr^, partial_length); end; end; writebytes, startwrite: begin { handle partial block at beginning of transfer. } if intra_ocks !! } then begin ioresult := ord(zbadmode); escape(-10); end; case request of readbytes, startread: begin { read the number of blocks requested } { directly into users buffer : } if (length>0) then begin {read directlytartread: begin { handle partial block at beginning of transfer. } if intra_block_offset>0 then begin $IF XDEBUG$ WRITELN('READING FIRST PARTIAL BLOCK'); $END$ {read block into TMRec} if CurrentBlock <> block then begin  into user's buffer} ScsiTapeRead(pSB, block, length, blocksize, bufptr); checkio; end; end; writebytes, startwrite: begin { write the number of blocks requested } { directly from users buffer : } if length>0 then begin  $IF XDEBUG$ WRITELN('ScsiDiscRead necessary: ',BLOCKSIZE:1,' ',BLOCK:1); $END$ CurrentBlock := block; ScsiDiscRead(pSB, block, 1, BlockSize, addr(BlockBuffer[0])); checkio; end; {move data from TMRec into user's buffer} move {write user's buffer to disc} ScsiTapeWrite(pSB, block, length, blocksize, bufptr); checkio; end; end; { writebytes } end; {case} recover begin if escapecode <> -10 then escape(escapecode); $IF XDEBUG$ blocksize := ioresult; WRITELN('TRANleft(BlockBuffer[intra_block_offset], bufptr^, partial_length); bufptr := addr(bufptr^, partial_length); block := block + 1; length := length-partial_length; end; { set up for multiple block read in middle and partial read on last bloSFER ERROR, IOTEMP: ',BLOCKSIZE); ioresult := blocksize; $END$ end; {try/recover} end; {with} end; {tape_transfer} procedure transfer(pSB:PtrSessionBlockType; uep: uep_type; request: amrequesttype; bufptr: charptr; abs_position, length: inteck. } partial_length := length mod blocksize; length := length div blocksize; if (blocksize <= 256) and (partial_length <> 0) then begin {read entire last block for small last partial block reads} partial_length := 0; length := length + ger); var blocksize: integer; block, intra_block_offset, partial_length: integer; procedure checkio; begin if ioresult <> ord(inoerror) then escape(-10); end; begin {transfer} with pTmRec^ do begin try {block size is known} blocksize := uep^.1; end; { handle multiple block reads } if (length>0) then begin $IF XDEBUG$ WRITELN('READING MULTIPLE MIDDLE BLOCKS'); $END$ {read directly into user's buffer} ScsiDiscRead(pSB, block, length, blocksize, bufptr); checkio; dvrtemp; block := abs_position div blocksize; intra_block_offset := abs_position mod blocksize; $IF XDEBUG$ WRITELN; WRITELN; WRITELN; WRITELN('TRANSFER REQUEST: ', REQUEST); WRITELN('LENGTH: ', LENGTH); WRITELN('POSITION:  bufptr := addr(bufptr^, length*blocksize); block := block+length; length:=0; end; { handle partial block at end of transfer. } if (partial_length > 0) then {partial block at back} begin $IF XDEBUG$ WRITELN('READING LAST PART     block_offset>0 then begin $IF XDEBUG$ WRITELN('WRITING PARTIAL BLOCK AT FRONT'); $END$ {read block into TMRec} if CurrentBlock <> block then begin $IF XDEBUG$ WRITELN('ScsiDiscRead necessary: ',BLOCKSIZE:1,' ',BLOCK:1); $EcRead(pSB, block, 1, blocksize, addr(BlockBuffer[0])); checkio; end; {move user's buffer into TmRec} moveleft(bufptr^, BlockBuffer[0], partial_length); end; {write out TmRec into last block} ScsiDiscWrite(pSB, block, 1, BlockSizND$ CurrentBlock := block; ScsiDiscRead(pSB, block, 1, BlockSize, addr(BlockBuffer[0])); checkio; end; {read user's data into TmRec block} moveleft(bufptr^, BlockBuffer[intra_block_offset], partial_length); {write TmRec block backe, addr(BlockBuffer[0])); checkio; end; CurrentBlock := -1; { JWH 8/30/91 } end; { writebytes } end; {case} recover begin if escapecode <> -10 then escape(escapecode); CurrentBlock := -1; $IF XDEBUG$ blocksize := ioresult; WRITELN( to disc} ScsiDiscWrite(pSB, block, 1, BlockSize, addr(BlockBuffer[0])); checkio; bufptr := addr(bufptr^, partial_length); block := block + 1; length := length-partial_length; end; { set up for multiple block write in middle and 'TRANSFER ERROR, IOTEMP: ',BLOCKSIZE); ioresult := blocksize; $END$ end; {try/recover} end; {with} end; {transfer} Procedure ZapBadDevice(pUnit:uep_type); type CompareType = packed record Ctm:amtype; Csc: byte; Cba: byte; Cdu: byte; Cd partial write on last block. } partial_length := length mod blocksize; length := length div blocksize; {length is number of blocks} { handle blocks in middle. } if length>0 then begin $IF XDEBUG$ WRITELN('WRITING MIDDLE BLOCKSv: byte; end; pCompareType = ^CompareType; var i:integer; pC:pCompareType; begin { Kill all units that are talking to the same device as this unit. } pC := addr(pUnit^.tm); for i := 0 to maxunit do with uep_type(addr(unitable^[i]))^, pC^ do'); $END$ {write user's buffer to disc} ScsiDiscWrite(pSB, block, length, blocksize, bufptr); checkio; bufptr := addr(bufptr^, length*blocksize); block := block + length; end; { handle partial block at end of transfer. } if p begin if (sc = Csc) and (ba = Cba) and (du = Cdu) and (dv = Cdv) then dvrtemp2 := DeviceAlwaysOffLine; end; end; procedure scsidisc(fp : fibp; request : amrequesttype; anyvar buffer : window; length, position : integeartial_length>0 then begin $IF XDEBUG$ WRITELN('WRITING LAST PARTIAL BLOCK'); $END$ { zero pad small sectors instead of the read modify write operation used for big block sizes } if blocksize < 256 then begin {overwrir); label 1; var pSB:PtrSessionBlockType; pUnit:uep_type; Num16MXfer, Mod16MSize, i:integer; begin $IF DEBUG$ WRITELN('SCSITM REQUEST: ',REQUEST); $END$ ioresult := ord(inoerror); pSB := addr(pTmRec^.SB); pUnit := addr(unitable^[fp^.funit]); witte block in TmRec, using zero pad} CurrentBlock := block; moveleft(bufptr^, BlockBuffer[0], partial_length); BlockBuffer[partial_length] := #0; moveleft(BlockBuffer[partial_length], BlockBuffer[partial_length+1], blocksize-partialh fp^, pUnit^, pSB^ do begin if (offline) or (dvrtemp2 = DeviceAlwaysOffline) then begin ioresult := ord(znodevice); goto 1; end; case request of clearunit: begin dvrtemp2 := DeviceOK; LUN := 255; tmSCSIstatus(pUnit, pSB); i_length-1); end else begin {read last partial block into TmRec} if CurrentBlock <> block then begin $IF XDEBUG$ WRITELN('ScsiDiscRead necessary: ',BLOCKSIZE:1,' ',BLOCK:1); $END$ CurrentBlock := block; ScsiDisf (ioresult = ord(zmediumchanged)) or (ioresult = ord(znotready)) then ioresult := ord(inoerror); { CRITICAL HOTSITE DEFECT REPAIR DEW 09/26/90 Problem is that umaxbytes is being overwritten in tmSCSIstatus on first call to TM      while (Num16MXfer > 0) do begin if devid = -2 then { JWH 6/93 } tape_transfer(pSB, pUnit, request, addr(buffer), position+fileid+byteoffset, hex('00ffffff')) else { disks - same as before } trans 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} modpfer(pSB, pUnit, request, addr(buffer), position+fileid+byteoffset, hex('00ffffff')); if (ioresult <> ord(inoerror)) then goto 1; position := position + hex('00ffffff'); Num16MXfer := Num16MXfer - 1; end;  := link; end; {with modp^} end; {value} $end$ BEGIN newbytes(pTmRec, sizeof(ScsiTmRecType)+4); pTmRec := addr(pTmRec^, 4 - (integer(pTmRec) mod 4)); {force long word alignment} $if TDEBUG$ newbytes(LocTracePtr, trace_size); . This causes partitioned discs to loose their boundaries, opening up the disc to potential data loss, i.e. unit #11 can now overwrite unit#12. The fact the uisfixed field of the unitable is not set correctly prior to calling tmSCSIstatus  if devid = -2 then { JWH 6/93 } tape_transfer(pSB, pUnit, request, addr(buffer), position+fileid+byteoffset, Mod16MSize) else { disks ... } transfer(pSB, pUnit, request, addr(buffer), position+fileicauses the problem. The purpose of the Inquire call (below) is to set the uisfixed field. This is done to complete the handshake between CTABLE and the TM. The Inquire call can not be made prior to tmSCSIstatus because the Inquire cod+byteoffset, Mod16MSize); end; end; end; otherwise ioresult := ord(ibadrequest); end; {case} 1: if ioresult <> ord(inoerror) then begin LUN := 255; if ioresult = ord(zmediumchanged) then begin umediavalid := fauld swallow the status needed by a call to CheckDev that determines if the media has been changed. CheckDev is made in tmSCSIstatus and is appropriate there. Thus, Inquire is moved to tmSCSIstatus. if (ioresult = ord(inoerror)) then lse; end; if (ioresult = ord(znodevice)) and (dvrtemp2 = DeviceAlwaysOffLine) then begin { find all other units this device is attached to, and make sure they are turned off! } ZapBadDevice(pUnit); end; end; $IF DE Inquire(pUnit, pSB); } end; unitstatus: fbusy := false; {overlap not implemented} flush:; readbytes, writebytes, startread, startwrite: {startread, startwrite means overlap - not implemented} begin tmSCSIstatus(pUnit, pSB); iBUG$ i := IORESULT; WRITELN('EXITING TM RESULT IS: ',i); ioresult := i; $END$ end; {with} end; end; {SCSIDISCMODULE} import SCSIDISCMODULE, loader, ASM {{,sysglobals,iodeclarations {for auto insertion into unitable} {{,SCSILIBf ioresult = ord(inoerror) then begin if ureportchange and not umediavalid then ioresult := ord(zmediumchanged) else if (position<0) or (length<0) or (position+length>fpeof) then ioresult := ord(ieof) else begin if (length {FOR TDEBUG} ; $if FALSE$ VAR dam_proc: packed record case integer of 0: (dam: damtype); 1: (value, slink: integer); end; function value(symbol: string255): integer; var modp: moddescptr; ptr, valueptr: addrec;  > hex('00ffffff')) then {scsi max xfer is $00ffffff} begin Num16MXfer := length div hex('00ffffff'); Mod16MSize := length mod hex('00ffffff'); end else begin Num16MXfer := 0; Mod16MSize := length; end;  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 Nil then begin PtrSessionBlock := DeviceSessionPtrs[i]; t(SelectCode:S_TYPE_ISC); { State Machine Procedures } Procedure CmdGetStatus (PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); Procedure CmdTerminateSession (PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); Pro repeat with PtrSessionBlock^ do begin utlSetInternalErr(PtrSessionBlock, ScsiCatastrophicErr); if (SessionState = SessionSuspended) then DoAReset := true else if (SessionState = SessionRunning) then begin      rScsiChip^.psns.bsy then begin hwiSCHardReset(Sc); end else hwiSCInitHW(Sc); end; {************************************************************************* * Procedure CmdInitSession *************************************************************k^.SessionState := SessionComplete; ResultCode := ORD(ScsiErr); end; begin with PtrSessionBlock^, PtrSessionBlock^.InternalBlock do begin { Initialize the error fields. } InternalStatus := NoIntErr; SessionStatus := 0; { Verify the ************ * * On Input: * * * Functional Description: * * * Initialize the session block and internal block variables. * * ensure that the inbound run level (isr level) will allow * SCSI interrupts to occur. * * Link thisession block is not being used. } if SessionState in [SessionRunning, SessionSuspended] then begin LocSetErr(ScsiStackingErr); goto 1; end; { verify the session address parameters are correct. If one or more are not, then ScsiAddr init_exec_control(addr(InternalBlock.StateControlRec), PtrSessionBlock, MyMachine, state_stack_size); init_trace(addr(InternalBlock.StateControlRec), 0, Nil); trace_control(addr(InternalBlock.StateControlRec), FALSE); exec(addr(Is session block into the select code chain. * In the select code block exists a session block pointer for each device. * Link this session block in, and determine if this session can run or not. * * Rule1: If another session block existsnternalBlock.StateControlRec)); end; SessionState := SessionComplete; if (InternalBlock.CallBackLoaded) then call(SessionCompleteCallBack, PtrSessionBlock); PtrSessionBlock := InternalBlock.NextSession; end;  for this device, then link this * session block in, and set the ResultCode to WaitForIsr. It will * be the responsibity of TerminateSession to start this session. * * Rule2: If a session block exists for another device,until PtrSessionBlock = NIL; DeviceSessionPtrs[i] := Nil; end; end; if DMAInProgress then begin osdKillDMA(DMAChannel); osdReleaseDMAChannel(Sc); DMAInProgress := FALSE; config_reg.pal_reset := 1; end; end;  and that session * is Running or Suspended, then this session can not run (set ResultCode to WaitForISR). * In this case, TerminateSession will start this * session. * * Rule3: If Rule1 or Rule2 have not berecover ; if DoAReset then hwiSCHardReset(Sc); osdSetRunLevel(RunLevel); end; {************************************************************************* * CmdScCleanUP ************************************************************************* * en satisfied, then the session CAN run. * * * On Output: NoEvent if the session can run. ScsiErr if it can not. If the * Session is to be killed, then InternalStatus will be set, otherwise * the session has been linked in * On Input: Nothing expected. * Called when everything on this Scsi Select Code needs to * be cleaned up. * * Functional Description: * * Reset the scsi bus. * initialize the scsi hardware. * Clean up anto SelectCodeBlock and will run * when it can. * *************************************************************************} Procedure CmdInitSession(PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); label 1; type tricky = recoy outstanding sessions. * * On Output: Scsi Select Code is cleaned up. * * *************************************************************************} Procedure CmdSCCleanUp(Sc:S_TYPE_ISC); begin cmdSCUnlinkAllSessions(Sc); if osdGetScBlock(Sc)^.Ptrd case boolean of true:(i:integer); false:(p:ScsiCallBackType); end; Var t:tricky; i:integer; locpSB:PtrSessionBlockType; procedure LocSetErr(ErrCode:InternalErrType); begin utlSetInternalErr(PtrSessionBlock, ErrCode); PtrSessionBloc     essErr } pScBlock := osdGetScBlock(SelectCode); if (pScBlock = Nil) or (Device < 0) or (Device > 7) or (LUN < 0) or (LUN > 7) or (SUN <> 0) then begin LocSetErr(ScsiAddressErr); goto 1; end; { Initialize the session and internao be started. * Initialize the session block and call the state driver to kick * things off. * * If the session can not run, then either it is complete or * it has been linked into the selectcode block and will run at * a latl blocks } SessionState := SessionWaiting; NextSession := NIL; ISRWaiting := False; SelectRetryCount := 0; t.p := SessionCompleteCallBack; CallBackLoaded := ((Overlap) and (t.i <> 0)); SysCleanUp := cmdSCCleanUp; { Make sure the incoter time. * * On Output: SessionResults are inthe session block. * *************************************************************************} Procedure DoSession(PtrSessionBlock:PtrSessionBlockType); Var ResultCode:S_SHORT; begin { if an escape mming interrupt level is not to high. } with pScBlock^ do begin if osdGetRunLevel >= ScsiIntLevel then begin LocSetErr(RunLevelErr); goto 1; end; { Check for Rule 1 } locpSB := DeviceSessionPtrs[Device]; if locpSB <gets this far out, be sure to clean up. } with PtrSessionBlock^ do try CmdInitSession(PtrSessionBlock, ResultCode); if (ResultCode = ORD(NoEvent)) then begin StartState(PtrSessionBlock); end; if not Overlap then while SessionState <> Ses> Nil then begin { Link this SessionBlock into the SessionBlock chain. } if not Overlap then begin LocSetErr(ScsiStackingErr); goto 1; end; while locpSB^.InternalBlock.NextSession <> NIL do locpSB := locpSB^sionComplete do ; recover begin CmdSCCleanUp(SelectCode); escape(escapecode); end; end; {************************************************************************* * DoAbort *******************************************************************.InternalBlock.NextSession; locpSB^.InternalBlock.NextSession := PtrSessionBlock; ResultCode := ORD(WaitForISR); goto 1; end; { CheckforRule 2 } DeviceSessionPtrs[Device] := PtrSessionBlock; for i := 0 to 7 do if i <> D****** * * On Input: SessionBlock comes from user. The session is overlapped. * The session was active at the time of the call, but they may have * changed. * * Functional Description: * * set interrupt level so that SCSI can no evice then begin locpSB := DeviceSessionPtrs[i]; if (locpSB <> Nil) and (locpSB^.SessionState in [SessionRunning, SessionSuspended]) then begin if not Overlap then begin LocSetErr(ScsiStackingErr); goto 1;longer interrupt * and make sure that the session is still active. * Set ISRError to TRUE and restart the session, This will * force the driver to attempt to send an ABORT message, and * if that fails, reset the bus. * * On Output end; ResultCode := ORD(WaitForISR); goto 1; end; end; { This session can Run. } ResultCode := ORD(NoEvent); end; end; 1: end; {************************************************************************* * DoSessio: * *************************************************************************} Procedure DoAbort(PtrSessionBlock:PtrSessionBlockType); var SaveLevel:integer; begin with PtrSessionBlock^, InternalBlock, pScBlock^ do begin { set interrupt level n ************************************************************************* * * On Input: SessionBlock has been filled out by user with Session * required information. * * * Functional Description: * * Called when session is t} SaveLevel := osdGetRunLevel; if SaveLevel < ScsiIntLevel then osdSetRunLevel(ScsiIntLevel) else SaveLevel := 100; {larger than the largest interupt level} if SessionState = SessionRunning then begin ISRError := TRUE; StartState(Pt     n begin ResultCode := ORD(NoEvent); with PtrSessionBlock^ do begin SessionStatus := xfer_code; ResidualCount := InternalBlock.XferBlock.XferBufBlock.BufLen; end; end else begin ResultCode := ORD(ScsiErr); * * Functional Description: * * Determine the state machine error type and log it appropirately in * the session block. * * On Output: NoEvent * * *************************************************************************} Procedure Cm utlSetInternalErr(PtrSessionBlock, ScsiXferErr); end; end; {************************************************************************* * CmdTerminateSession ************************************************************************* * * On IdStateErr(PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); begin utlSetInternalErr(PtrSessionBlock, StateMachineErr); ResultCode := Ord(NoEvent); end; {************************************************************************* * CmdPhaseErrSessionBlock); end; { reset interrupt level } if SaveLevel < ScsiIntLevel then osdSetRunLevel(SaveLevel); end; end; {************************************************************************* * DoReset ********************************nput: The session is to be properly terminated. * * * Functional Description: * * Terminate the session by setting it to complete and taking it out * of the select code block. If a call back routine is to be called, * do it now. ***************************************** * * On Input: Nothing is known. * * * Functional Description: * * Verify the select code is indeed a SCSI select code and then * reset the select code and the bus. * * On Output: * *************** * Look in the select code block for sessions that are waiting to be * started. * * On Output: NoEvent * * *************************************************************************} Procedure CmdTerminateSession(PtrSessionBlock:PtrSessi***********************************************************} Procedure DoReset(SelectCode:S_TYPE_ISC); begin if osdGetScBlock(SelectCode) <> NIL then begin cmdSCUnlinkAllSessions(SelectCode); hwiSCHardReset(SelectCode); end; end; {*****************onBlockType; Var ResultCode:S_SHORT); var Idx:integer; Done:boolean; locpSB:PtrSessionBlockType; begin ResultCode := ORD(NoEvent); with PtrSessionBlock^, InternalBlock, pScBlock^ do begin if (CallBackLoaded) then call(SessionCompleteCallBack, Pt******************************************************** * CmdGetStatus ************************************************************************* * * On Input: Bus is in Status Phase * * * Functional Description: * * Get the status from trSessionBlock); SessionState := SessionComplete; DeviceSessionPtrs[Device] := NextSession; Idx := Device; Done := FALSE; while not Done do begin if Idx = 7 then Idx := 0 else Idx := Idx + 1; locpSB := DeviceSessionPtrs[Idx]; he target and set it in the SessionStatus * variable in the session block. * * This routine will also set the ResidualCount to what is in the * XferBlock. * * On Output: NoEvent or ScsiErr if xfer error has occured. * * ********** if (locpSB <> Nil) and (locpSB^.SessionState = SessionWaiting) then begin Done := TRUE; StartState(locpSB); end else if Idx = Device then Done := TRUE; end; end; end; {***************************************************************************************************************************} Procedure CmdGetStatus(PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); var xfer_code : s_byte; begin if hwiManXfer(PtrSessionBlock,xfer_code,status_phase,false,false) the************* * CmdStateErr ************************************************************************* * * On Input: The state machine has detected an internal error type of * no event found in event/nextstate list or escape error. *      r ************************************************************************* * * On Input: The current bus phase is not anticipated. * * * Functional Description: * * Set internal error to bus phase error * * * * * On Output: NoEvent  BusFree,state_11 * MsgIn,state_11 * MsgOut,state_11 * DataPhase,state_11 ******************************************************* *state_4 mcall * DoTransfer *$event_pairs *  * * *************************************************************************} Procedure CmdPhaseErr(PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); begin utlSetInternalErr(PtrSessionBlock, ScsiPhaseErr); ResultCode := Ord(NoEvent); end;DataPhase,state_5 * StatusPhase,state_6 * ScsiErr,state_12 * BusBusy,state_11 * CmdPhase,state_11 * BusFree,state_11 * MsgIn,state_11 * MsgOut,state_11 ****** {************************************************************************* * CmdUnlinkAllSessions ************************************************************************* * * On Input: State Machine is handling a catastrophic error. * * * Fun************************************************* *state_5 mcall * DoTransfer *$event_pairs * StatusPhase,state_6 * ScsiErr,state_12 * BusBusy,state_11 * CmdPhase,state_11 * ctional Description: * * Unlink all sessions by call cmdScUnlinkAllSessions * * On Output: NoEvent * * *************************************************************************} Procedure CmdUnlinkAllSessions(PtrSessionBlock:PtrSessionBlockTy DataPhase,state_11 * BusFree,state_11 * MsgIn,state_11 * MsgOut,state_11 ******************************************************* *state_6 standard * COMMANDS_cmdGetStatus * pe; Var ResultCode:S_SHORT); begin cmdSCUnlinkAllSessions(PtrSessionBlock^.SelectCode); ResultCode := Ord(NoEvent); end; end;  HWI_UTILS_hwiGetPhase *$event_pairs * MsgIn,state_7 * ScsiErr,state_12 * DataPhase,state_11 * StatusPhase,state_11 * BusBusy,state_11 * CmdPhase,state_11 *  INCLUDE ST_EQU *$machine_name SCSI_DRIVER *$global_recover state_10 ******************************************************* *state_1 standard * HWI_UTILS_hwiGetPhase *$event_pairs * BusFree,state_3 * BusBus BusFree,state_11 * MsgOut,state_11 ******************************************************* *state_7 mcall * TerminatePath *$event_pairs * BusFree,state_8 * ScsiErr,state_12 * Msgy,state_2 * ScsiErr,state_12 ******************************************************* *state_2 standard * MESSAGES_msgWaitTimeOrFree *$event_pairs * BusFree,state_3 * ScsiErr,state_12 **********In,state_11 * CmdPhase,state_11 * DataPhase,state_11 * StatusPhase,state_11 * BusBusy,state_11 * MsgOut,state_11 ******************************************************* *state_8 s********************************************* *state_3 mcall * EstablishPath *$event_pairs * CmdPhase,state_4 * BusBusy,state_2 * StatusPhase,state_6 * ScsiErr,state_12 * tandard * COMMANDS_cmdTerminateSession *$event_pairs_catch * state_exit ******************************************************* *state_10 standard * COMMANDS_cmdStateErr *$event_pairs_catch * st     ES_MSGWAITTIMEORFREE REFA HWI_UTILS_HWIGETPHASE LMODE HWI_UTILS_HWIGETPHASE STANDARD equ 0 MCALL equ 1 MEXIT equ 2 SUSPEND equ 3 DONE_EXIT equ 4 SINGLES equ 0 SINGLES_CATCH equ 1 PAIRS equ 2 PAIRS_CATCH equ 3 DEF SCSI_DRIVER SCSI_DRIVER dc.w TANDARD,PAIRS_CATCH dc.b 1,1 dc.w 000,STATE_12-SCSI_DRIVER dc.l COMMANDS_CMDPHASEERR STATE_5 dc.b MCALL,PAIRS dc.b 8,1 dc.w STATUSPHASE,STATE_6-SCSI_DRIVER dc.w SCSIERR,STATE_12-SCSI_DRIVER dc.w BUSBUSY,STATE_11- STATE_10-SCSI_DRIVER STATE_1 dc.b STANDARD,PAIRS dc.b 3,1 dc.w BUSFREE,STATE_3-SCSI_DRIVER dc.w BUSBUSY,STATE_2-SCSI_DRIVER dc.w SCSIERR,STATE_12-SCSI_DRIVER dc.l HWI_UTILS_HWIGETPHASE STATE_3 dc.b MCALL,PAIRS SCSI_DRIVER dc.w CMDPHASE,STATE_11-SCSI_DRIVER dc.w DATAPHASE,STATE_11-SCSI_DRIVER dc.w BUSFREE,STATE_11-SCSI_DRIVER dc.w MSGIN,STATE_11-SCSI_DRIVER dc.w MSGOUT,STATE_11-SCSI_DRIVER dc.l DOTRANSFER STATE_7 dc.b MCALL,ate_12 ******************************************************* *state_11 standard * COMMANDS_cmdPhaseErr *$event_pairs_catch * state_12 ******************************************************* *state_12 mcall *  dc.b 8,1 dc.w CMDPHASE,STATE_4-SCSI_DRIVER dc.w BUSBUSY,STATE_2-SCSI_DRIVER dc.w STATUSPHASE,STATE_6-SCSI_DRIVER dc.w SCSIERR,STATE_12-SCSI_DRIVER dc.w BUSFREE,STATE_11-SCSI_DRIVER dc.w MSGIN,STATE_11-SCSI_DRIVER dc.w  AbortPath *$event_pairs_catch * BusFree,state_13 * BusBusy,state_13 * state_14 ******************************************************* *state_13 standard * COMMANDS_cmdTerminateSession * MSGOUT,STATE_11-SCSI_DRIVER dc.w DATAPHASE,STATE_11-SCSI_DRIVER dc.l ESTABLISHPATH STATE_2 dc.b STANDARD,PAIRS dc.b 2,1 dc.w BUSFREE,STATE_3-SCSI_DRIVER dc.w SCSIERR,STATE_12-SCSI_DRIVER dc.l MESSAGES_MSGWAITTIMEORFREE$event_pairs_catch * state_exit ******************************************************* *state_14 standard * HWI_UTILS_hwiHardReset * COMMANDS_cmdUnlinkAllSessions *$event_pairs_catch * state_ex STATE_12 dc.b MCALL,PAIRS_CATCH dc.b 3,1 dc.w BUSFREE,STATE_13-SCSI_DRIVER dc.w BUSBUSY,STATE_13-SCSI_DRIVER dc.w 000,STATE_14-SCSI_DRIVER dc.l ABORTPATH STATE_4 dc.b MCALL,PAIRS dc.b 8,1 dc.w DATAPHAit ******************************************************* *state_exit mexit * 0 ******************************************************* *$end_machine REFA COMMANDS_CMDUNLINKALLSESSIONS LMODE COMMANDS_CMDUNLINKALLSESSIONS REFA HWISE,STATE_5-SCSI_DRIVER dc.w STATUSPHASE,STATE_6-SCSI_DRIVER dc.w SCSIERR,STATE_12-SCSI_DRIVER dc.w BUSBUSY,STATE_11-SCSI_DRIVER dc.w CMDPHASE,STATE_11-SCSI_DRIVER dc.w BUSFREE,STATE_11-SCSI_DRIVER dc.w MSGIN,STATE_11-SCSI_DRIV_UTILS_HWIHARDRESET LMODE HWI_UTILS_HWIHARDRESET REFA ABORTPATH LMODE ABORTPATH REFA COMMANDS_CMDPHASEERR LMODE COMMANDS_CMDPHASEERR REFA COMMANDS_CMDSTATEERR LMODE COMMANDS_CMDSTATEERR REFA COMMANDS_CMDTERMINATESESSION LMODE COMMANDSER dc.w MSGOUT,STATE_11-SCSI_DRIVER dc.l DOTRANSFER STATE_6 dc.b STANDARD,PAIRS dc.b 8,2 dc.w MSGIN,STATE_7-SCSI_DRIVER dc.w SCSIERR,STATE_12-SCSI_DRIVER dc.w DATAPHASE,STATE_11-SCSI_DRIVER dc.w STATUSPHASE,STATE_CMDTERMINATESESSION REFA TERMINATEPATH LMODE TERMINATEPATH REFA COMMANDS_CMDGETSTATUS LMODE COMMANDS_CMDGETSTATUS REFA DOTRANSFER LMODE DOTRANSFER REFA ESTABLISHPATH LMODE ESTABLISHPATH REFA MESSAGES_MSGWAITTIMEORFREE LMODE MESSAG_11-SCSI_DRIVER dc.w BUSBUSY,STATE_11-SCSI_DRIVER dc.w CMDPHASE,STATE_11-SCSI_DRIVER dc.w BUSFREE,STATE_11-SCSI_DRIVER dc.w MSGOUT,STATE_11-SCSI_DRIVER dc.l COMMANDS_CMDGETSTATUS dc.l HWI_UTILS_HWIGETPHASE STATE_11 dc.b S     PAIRS dc.b 8,1 dc.w BUSFREE,STATE_8-SCSI_DRIVER dc.w SCSIERR,STATE_12-SCSI_DRIVER dc.w MSGIN,STATE_11-SCSI_DRIVER dc.w CMDPHASE,STATE_11-SCSI_DRIVER dc.w DATAPHASE,STATE_11-SCSI_DRIVER dc.w STATUSPHASE,STATE_11-SCSI_DRIVEnchParms (PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); Procedure MsgTargetSynchParms (PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); Procedure MsgGetMsg (PtrSessionBlock:PtrSessionBlockType; Var ResultCodR dc.w BUSBUSY,STATE_11-SCSI_DRIVER dc.w MSGOUT,STATE_11-SCSI_DRIVER dc.l TERMINATEPATH STATE_8 dc.b STANDARD,PAIRS_CATCH dc.b 1,1 dc.w 000,STATE_EXIT-SCSI_DRIVER dc.l COMMANDS_CMDTERMINATESESSION STATE_EXIT dc.b e:S_SHORT); Procedure MsgRejectMsg (PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); Procedure MsgSetXfer (PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); Procedure MsgDoXfer (PtrSessionBlock:Pt MEXIT,SINGLES dc.w 0 STATE_10 dc.b STANDARD,PAIRS_CATCH dc.b 1,1 dc.w 000,STATE_12-SCSI_DRIVER dc.l COMMANDS_CMDSTATEERR STATE_13 dc.b STANDARD,PAIRS_CATCH dc.b 1,1 dc.w 000,STATE_EXIT-SCSI_DRIVER dc.l COMMrSessionBlockType; Var ResultCode:S_SHORT); Procedure MsgSawErrMsg (PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); Procedure MsgPrepareDisc (PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); Procedure MsgSetDisANDS_CMDTERMINATESESSION STATE_14 dc.b STANDARD,PAIRS_CATCH dc.b 1,2 dc.w 000,STATE_EXIT-SCSI_DRIVER dc.l HWI_UTILS_HWIHARDRESET dc.l COMMANDS_CMDUNLINKALLSESSIONS * state trace table OPTION = TABLE OFF END c (PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); Procedure MsgPrepareRetry (PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); Procedure MsgIsOriginalPhase (PtrSessionBlock:PtrSessionBlockType; Var ResultCod{ SCSI Messages Module. Contains the SCSI driver message level interface. This includes all actions as defined by the network level, that is to: 1) set up a path between the host and target, 2) maintain that path (handle comminication, transmie:S_SHORT); Procedure MsgWaitReselect (PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); Procedure MsgIsPathActive (PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); Procedure MsgAbortMsg (PtrSessionBlock:Ptssion errors, disconnect/reconnect) 3) terminate the path. The transport (command) level interacts with the network (message) level to set up paths, handle transmission errors, etc. The SCSI Driver is state machine driven. The State MachirSessionBlockType; Var ResultCode:S_SHORT); implement type SynchParmsType = PACKED RECORD SynchExtend:s_byte; SynchLength:s_byte; SynchCode:s_byte; SynchPeriod:s_byte; SynchReqAck:s_byte; END; const SynchParmsConst = SynchParmsType[ Synchne actually makes all of the calls, and the state tables enforce the division of labor (commands/messages) as defined above. } module MESSAGES; import SCSI_DEFS, SCSI_UTILS, HWI_UTILS, OSD_LL; export Procedure MsgWaitTimeOrFree (PtrSessionBlock:PtExtend:1, SynchLength:3, SynchCode:1, SynchPeriod:0, SynchReqAck:8]; type Xlate16vs32Type = array[0..1] of s_byte; PeriodXlateType = array[0..3] of Xlate16vs32Type; const PeriodXlate = PeriodXlateType[ {16bit 32bit} Xlate16vs32Type [rSessionBlockType; Var ResultCode:S_SHORT); Procedure MsgSelect (PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); Procedure MsgIdentifyMsg (PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); Procedure MsgInitSy 125, 62 ], Xlate16vs32Type [ 168, 93 ], Xlate16vs32Type [ 0, 125 ], Xlate16vs32Type [ 0, 0 ] ]; function GetSynchN(PeriodParm:integer):integer; var i:integer; begin { compute from the transfer period parameter, the number      . * Select with the attention line on to indicate that messages are * supported and the MsgOut phase is desired upon successful selection. * * Maintain a count of select attempts and err if count exceeds max. * If select is unsucce ints.cmd_complete then begin { wait for chip to settle down } if (ssts.action <> spc_init_idle) and (ssts.action <> spc_init_wait_xfer) then begin osdStartTimer(one_second); repeat until (ssts.action = spc_init_idlssful, set result code to BusBusy. * * * On Output: WaitForIsr while waiting for a Select. This is the point * where overlap transfer begins and the state machine becomes interrupt * driven. * BusBusy for select fail. * ScsiErr.e) or (ssts.action = spc_init_wait_xfer) or osdTimeExpired; if (ssts.action <> spc_init_idle) and (ssts.action <> spc_init_wait_xfer) then begin ResultCode := ORD(ScsiErr); utlSetInternalErr(PtrSessionBloto be placed in H/W. The number to be placed in hardware is n-1 where n = (4m/125)-1 The PeriodParm is m. Because of rounding when m is generated, 4m needs to be modified to be an exact multiple of 125. } i := PeriodParm * 4; GetSynch * NoEvent if sucessful. * *************************************************************************} Procedure MsgSelect (PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); var i:integer; begin with PtrSessionBlock^, InterN := ((i + (i mod 125)) Div 125) - 2; end; {************************************************************************* * msgWaitTimeOrFree ************************************************************************* * * On Input: Scsi Bus is busy. * nalBlock.pScBlock^, PtrScsiCard^, PtrScsiChip^ do if not InternalBlock.ISRWaiting then begin i := osdBitLsL(1,Device); if (i = ord(bdid)) then begin utlSetInternalErr(PtrSessionBlock, ScsiAddressErr); ResultCode := ORD(ScsiErr); end else * * Functional Description: * * Wait for either the bus to free up or timeout. * * * * On Output: BusFree, ScsiErr (InternalStatus set to ScsiTimeoutErr). * * *************************************************************************} Proced begin ResultCode := ORD(WaitForISR); InternalBlock.ISRWaiting := True; InternalBlock.ISRMask := cmd_complete + timeout; ints.ints := ints.ints; pctl.pctl := 0; data_regs.temp := chr(osdBitOr(ord(bdid), i)); scmd.cmd := set_atn_cmd; ure MsgWaitTimeOrFree (PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); begin with PtrSessionBlock^.InternalBlock.pScBlock^.PtrScsiChip^ do begin ResultCode := ORD(BusFree); if (ssts.init) then begin osdStartTimer(one_second);  data_regs.tch := chr(hex('0f')); data_regs.tcm := chr(hex('42')); data_regs.tcl := #4; scmd.cmd := select_cmd; sc_reg.ie := true; end; end else {ISR has occured} begin InternalBlock.ISRWaiting := false; sc_reg.ie := false; scmd.cmd repeat until (not ssts.init) or (osdTimeExpired); if (ssts.init) then begin utlSetInternalErr(PtrSessionBlock, ScsiTimeOutErr); ResultCode := ORD(ScsiErr); end; end; end; end; {**************************************************** := reset_atn_cmd; if InternalBlock.ISRError then ResultCode := ORD(ScsiErr) else begin if ints.time_out then begin if InternalBlock.SelectRetryCount >= SelectRetryMax then begin ResultCode := ORD(ScsiErr); utlSetInternalEr********************* * MsgSelect ************************************************************************* * * On Input: bus is in a free state. * * * Functional Description: * * Select the device that this session wants to communicate withr(PtrSessionBlock, SelectRetryErr); DeviceSynchParms[Device].SynchState := NoSynch; end else begin InternalBlock.SelectRetryCount := InternalBlock.SelectRetryCount + 1; ResultCode := ORD(BusBusy); end; end else if     ck, ScsiTimeOutErr); end else ResultCode := ORD(NoEvent); end else ResultCode := ORD(NoEvent); if (psns.t_phase <> msg_out_phase) and (psns.t_phase <> cmd_phase) then begin osdStartTimer(one_seco DevLun := LUN; XferByte := b; MaintainATN := (DeviceSynchParms[Device].SynchState = NeedSynch); if hwiManXfer(PtrSessionBlock, XferByte, msg_out_phase, MaintainATN, false) then begin if MaintainATN then ResultCode := ORD(NeedSynchParms) nd); repeat until (psns.t_phase = msg_out_phase) or (psns.t_phase = cmd_phase) or (osdTimeExpired); end; end; end; ints.ints := ints.ints; end; end; {***************************************************************** else ResultCode := ORD(NoEvent); end else begin utlSetInternalErr(PtrSessionBlock, ScsiManXferErr); ResultCode := ORD(ScsiErr); end; end else begin utlSetInternalErr(PtrSessionBlock, ScsiAddressErr); ResultCode := ORD(ScsiErr); ******** * MsgIdentifyMsg ************************************************************************* * * On Input: Bus is in a MsgOut phase. * * * Functional Description: * * Format and transmit an identify message to the device. * The  end; end; {************************************************************************* * MsgInitSynchParms ************************************************************************* * * On Input: It has been determined that Synchronous transmission *SUN (Seconday Unit Number) parameter is not supported. * Range checking on the LUN value is performed here. * The session parameter 'DoNotDisconnect' determines if disconnect * will be allowed in this session. * * This routine, bef parameters must be set up. The Bus should be in MsgOut phase. * Agreement protocol used begins with initiator. * * Functional Description: * * This routine handles all of the message passing required to agree * with ore sending the identify message, must determine * if synch parameters with this device should be discussed. If this is * the case, maintain the ATN line set during the identify transfer and * set the ResultCode to NeedSynchParms. * * Othe target on synchronous transmission parameters. * * The agreed upon synchronous parameters must be stored in the select * code block. * * * On Output: NoEvent if successful. ScsiErr Otherwise. * Agreed upon synch. parms are in seln Output: NoEvent or NeedSynchParms if successful, otherwise ScsiErr. * *************************************************************************} Procedure MsgIdentifyMsg (PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); type Identiect code block. * *************************************************************************} Procedure MsgInitSynchParms (PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); var SynchParms:SynchParmsType; SynchMsgBuf:SynchParmsType; DMA3fyMsgType = packed record case boolean of true:( IdentifyBit:boolean; AllowDisconnect:boolean; rsrvd:0..7; DevLun:0..7); false:(b:s_byte); end; Var IdentifyData:IdentifyMsgType; XferByte:s_byte; MaintainATN:Boolean; 2BitIdx:integer; XferCode:s_byte; i:integer; pByte:PtrChar; begin with PtrSessionBlock^, InternalBlock.pScBlock^, PtrScsiCard^, PtrScsiChip^, DeviceSynchParms[Device] do begin ResultCode := ord(NoEvent); SynchParms := SynchParmsConst; DMA3begin { Guaranteed to be in msgout phase when this routine is called. } With IdentifyData, PtrSessionBlock^, InternalBlock.pScBlock^, PtrScsiChip^ do if LUN < 8 then begin IdentifyBit := true; AllowDisconnect := not DoNotDisconnect; rsrvd := 0; 2bitIdx := ord( ((osdDMA32bit) and (not id_reg.d16)) ); SynchParms.SynchPeriod := PeriodXlate[config_reg.sync_rate][DMA32bitIdx]; if SynchParms.SynchPeriod = 0 then {current h/w can't synch} begin SynchState := NoSynch; { turn off the attentio     tCode := ord(ScsiErr); utlSetInternalErr(PtrSessionBlock, ScsiManXferErr); end; { else if the phase has changed, then this is not an error. } end; if (ResultCode = ord(NoEvent)) and (i > 0) then {target's reply is o.k.}se. * * Functional Description: * * This routine handles all of the message passing required to agree * with the target on synchronous transmission parameters. * * The agreed upon synchronous parameters must be stored in the select * begin if (i = 1) and (SynchMsgBuf.SynchExtend = hex('07')) then {message reject} begin SynchState := NoSynch; end else if (i = 5) and (SynchMsgBuf.SynchExtend = hex('01')) and (SynchMsgBuf.SynchCode = he code block. * * On Output: NoEvent if successful. ScsiErr Otherwise. * Agreed upon synch. parms are in select code block. * * *************************************************************************} Procedure MsgTargetSynchParms (PtrSn line } XferCode := hex('08'); {noop message} if not hwiManXfer(PtrSessionBlock,XferCode,msg_out_phase,false,false) then begin ResultCode := ord(ScsiErr); utlSetInternalErr(PtrSessionBlock, ScsiManXferErr); end else ResultCode :x('01')) then {Synch parms message brought in} begin if (SynchMsgBuf.SynchReqAck = 0) then begin {target says do asynch} SynchState := NoSynch; end else {target negotiated synch parms} begin i := ord(NoEvent); end else {h/w can synch, attempt to synch with device} begin pByte := addr(SynchParms); i := sizeof(SynchParms); XferCode := ord(pByte^); while (psns.t_phase = msg_out_phase) and (i > 0) and (ResultCode == GetSynchN(SynchMsgBuf.SynchPeriod); if (SynchMsgBuf.SynchReqAck <= SynchParms.SynchReqAck) and (SynchMsgBuf.SynchPeriod >= SynchParms.SynchPeriod) and (i < 4) then begin {all parms are o.k.}  ord(NoEvent)) do begin if (hwiManXfer(PtrSessionBlock, XferCode, msg_out_phase, (i>1),false)) then begin pByte := addr(pByte^, 1); XferCode := ord(pByte^); i := i - 1; end else if (psns.t_phase = msg_out_phase SynchState := Synched; TMODvalue.sx := true; TMODvalue.maxto := SynchParms.SynchReqAck MOD 8; TMODvalue.mintp := i; TMODvalue.pad := 0; end else {illegal parms} begin SynchState :) then begin SynchState := NoSynch; ResultCode := ord(ScsiErr); utlSetInternalErr(PtrSessionBlock, ScsiManXferErr); end; { else if the phase has changed, then this is not an error. } end; if (ResultCode = ord(NoE= NoSynch; MsgRejectMsg(PtrSessionBlock, ResultCode); end; end; end else begin {msg is not what is expected.} SynchState := NoSynch; MsgRejectMsg(PtrSessionBlock, ResultCode); end; end elsevent)) then {synch sent out o.k., now get the target's reply} begin {get the message} pByte := addr(SynchMsgBuf); i := 0; while (psns.t_phase = msg_in_phase) and (ResultCode = ord(NoEvent)) do begin if hwiManXfer(PtrSessionBlock if (i = 0) then {illegal phase} begin SynchState := NoSynch; end; end; end; end; end; {************************************************************************* * MsgTargetSynchParms *************************************************, XferCode, msg_in_phase, (i<4),false) then begin pByte^ := chr(XferCode); pByte := addr(pByte^, 1); i := i + 1; end else if (psns.t_phase = msg_in_phase) then begin SynchState := NoSynch; Resul************************ * * On Input: The target has requested that synchronous parms be set up. * The target's parms are in the select code block. * Agreement protocol used begins with target. * Bus is in MsgOut pha     essionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); var SynchParms:SynchParmsType; DMA32BitIdx:integer; XferCode:s_byte; i:integer; N:integer; pByte:PtrChar; begin with PtrSessionBlock^, InternalBlock, pScBlock^, PtrScsiCard^, PtrScsiChi N := GetSynchN(SynchParms.SynchPeriod); end; if (SynchState = NeedSynch) then {send back a valid response to target} begin ResultCode := ord(NoEvent); pByte := addr(SynchParms); i := sizeof(SynchParms); XferCode := ord(pByte^p^, DeviceSynchParms[Device] do begin SynchState := NoSynch; ResultCode := ord(NoEvent); SynchParms := SynchParmsConst; DMA32bitIdx := ord( ((osdDMA32bit) and (not id_reg.d16)) ); SynchParms.SynchPeriod := PeriodXlate[config_reg.sync_rate][DMA32); while (psns.t_phase = msg_out_phase) and (i > 0) and (ResultCode = ord(NoEvent)) do begin if (hwiManXfer(PtrSessionBlock, XferCode, msg_out_phase, (i>1),false)) then begin pByte := addr(pByte^, 1)bitIdx]; if SynchParms.SynchPeriod = 0 then {current h/w can't synch} begin { reject the request } SynchState := NoSynch; MsgRejectMsg(PtrSessionBlock, ResultCode); end else {h/w can synch, attempt to synch with device} begin { N; XferCode := ord(pByte^); i := i - 1; end else begin SynchState := NoSynch; ResultCode := ord(ScsiErr); utlSetInternalErr(PtrSessionBlock, ScsiManXferErr); end; end; if (ResultCode = ord(NoEvent))ow evaluate and modify the targets req/ack parm as necessary. } if (TargetSynchReqAck = 0) then begin {target is really requesting asynchronous mode!} SynchState := NoSynch; MsgRejectMsg(PtrSessionBlock, ResultCode); end else if  then {all synched!} begin {all parms are o.k., send back } SynchState := Synched; TMODvalue.sx := true; TMODvalue.maxto := SynchParms.SynchReqAck MOD 8; TMODvalue.mintp := N; TMODvalue.pad := 0; end; end; { else(TargetSynchReqAck < SynchParms.SynchReqAck) then begin {Conform to targets ReqAck request} SynchParms.SynchReqAck := TargetSynchReqAck; end; { else, target will be asked to conform to our max by default. } { Evaluate an a Reject Msg has already been sent. } end; end; end; {************************************************************************* * MsgGetMsg ************************************************************************* * * On Input: Bus is in the MsgId modify the targets synch parm as necessary. } if (TargetSynchPeriod > SynchParms.SynchPeriod) then begin { Target's request is less greater than our smallest period, so go with it!. First check if for validity! } N n phase. * * * Functional Description: * * Acquire the incomming message. If the message has data that * needs to be stored for later reference, store in either the * sessionblock or in the select code block. * * If a parity e:= GetSynchN(TargetSynchPeriod); if (N < 4) then {valid synch request} begin {Conform to targets Period request} SynchParms.SynchPeriod := TargetSynchPeriod; end else begin {target is requesting a period impossible for ourror is detected, send the MessageParityError * message and await a retry. * * On Output: Message has been acquired and the message code is set in * the ResultCode. ScsiErr if an error has occured. * **************************************r H/W!} SynchState := NoSynch; MsgRejectMsg(PtrSessionBlock, ResultCode); end; end else begin { ask target to conform to our smallest period. This will occur naturally, however the var N needs to be recomputed. } ***********************************} Procedure MsgGetMsg (PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); type XlateMsgType = array [0..12] of S_SHORT; const XlateMsgCode = XlateMsgType[ ORD(CmdComplete),ORD(ScsiErr),ORD(Sav     ) and (not psns.req) then begin osdStartTimer(one_second); repeat until ( (psns.t_phase <> msg_in_phase) or ( (psns.t_phase = msg_in_phase) and (psns.req) ) or (osdTimeExpired) ); if (psns.t_phase = msg_in_phase) andscription: * * Set up the XferBlock which is located in the InternalBlock of the * SessionBlock. * * The XferPhase is the current bus phase. * The XferRetryCount is set to 0. * The XferBlock is set up according to the bus ph (not psns.req) then begin utlSetInternalErr(PtrSessionBlock, ScsiPhaseErr); ResultCode := ord(ScsiErr); end; end; end else if (XferCode = hex('01')) {extended message} and (i = 5) and (ord(Buf[3]) = hex('01')) and {synchronoase: * * CmdPhase: Use the CmdPtr and CmdLen. * DoDMA is always false. * Set up TMOD: if the device has synched, used TMODvalue. * * DataIn or DataOut: Use BufIeDataPtr), ORD(RestorePtrs),ORD(Disconnect),ORD(ScsiErr), ORD(ScsiErr),ORD(ScsiErr),ORD(ScsiErr),ORD(ScsiErr), ORD(LCC),ORD(LCCwFlag),ORD(ScsiErr)]; var Buf:packed array [ 1 .. 5 ] of char; XferCode:s_byte; i : integer; begin with PtrSeus message} (psns.t_phase = msg_out_phase) then {guarantee msgout phase} begin ResultCode := ord(Synch); TargetSynchPeriod := ord(Buf[4]); TargetSynchReqAck := ord(Buf[5]); end else {unknown message} ResultCode := ord(ScsiErr); if ssionBlock^.InternalBlock, pScBlock^.PtrScsiChip^ do begin ResultCode := ord(NoEvent); { read in the message. - special note: if this is a synchronous parms message comming in, then before the last byte is brought in, we have to request ResultCode = ORD(ScsiErr) then utlSetInternalErr(PtrSessionBlock, ScsiBadMsg); end; end; {************************************************************************* * MsgRejectMsg *********************************************************************message out phase for a reply. } i := 0; repeat if hwiManXfer(PtrSessionBlock, XferCode, msg_in_phase, (i<4), ((i = 4) and (ord(buf[3]) = 1))) then begin i := i + 1; Buf[i] := chr(XferCode); end else if (psns.t_pha**** * * On Input: Bus can be in any phase. * * * Functional Description: * * Acquire the MsgOut phase (hwiGetMsgOut) * Format and send a MessageReject Message. * * On Output: NoEvent if successful. ScsiErr otherwise. * *************se = msg_in_phase) then begin ResultCode := ord(ScsiErr); utlSetInternalErr(PtrSessionBlock, ScsiManXferErr); end; { else if the phase has changed, then this is not an error. } until ( (ResultCode <> ord(NoEvent)) or (psns.t_p************************************************************} Procedure MsgRejectMsg (PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); var Xfer_Code : s_byte; begin hwiGetMsgOut(PtrSessionBlock,ResultCode); if ResultCode = Ohase <> msg_in_phase) or (Buf[1] <> #1) ); XferCode := ord(Buf[1]); if (i = 1) then {standard 1 byte message} begin if (XferCode div 128) <> 0 then { Identify } ResultCode := ORD(Identify) else if XferCode > hex('0c') then RD(MsgOut) then begin xfer_code:=hex('07'); if hwiManXfer(PtrSessionBlock,xfer_code,msg_out_phase,false,false) then ResultCode := ORD(NoEvent) else begin ResultCode := ORD(ScsiErr); utlSetInternalErr(PtrSessionBlock, ScsiManXferErr); end;  Resultcode := ord(ScsiErr) else ResultCode := XlateMsgCode[XferCode]; { Wait for a possible phase change - there may be more message bytes. This is determined by the state of the REQ line. } if (psns.t_phase = msg_in_phase end; end; {************************************************************************* * MsgSetXfer ************************************************************************* * * On Input: Bus is in either CmdPhase or DataPhase. * * * Functional De     n or BufOut. * * Set XferSavedDataPointer and XferSavedDateLength equal to BufPtr and BufLen. * * On Output: NoEvent. XferBlock has been set up for a transfer. * ScsiErr. Illegal value in the XferBlock. * ************************** * * * Functional Description: * * Sets up the hardware for a transfer and controls the transfer. * If DoDMA, sets up DMA and waits for an interrupt. * * If an error occurs, this routine handles the error and waits until * the b***********************************************} Procedure MsgSetXfer (PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); var locTMOD:tmod_type; begin ResultCode := ORD(NoEvent); With PtrSessionBlock^, InternalBlock.XferBlock, Inteus is in message out phase (calls hwiGetMsgOut). * * If the xfer is stopped by the target, this is o.k., however this * routine must see that any untransmitted data that is in the chip/DMA * buffers are cleared out and that the buffer pornalBlock.pScBlock^, DeviceSynchParms[Device] do begin XferPhase := PtrScsiChip^.psns.t_phase; XferRetryCount := 0; case XferPhase of cmd_phase: begin XferBufBlock.BufPtr := CmdPtr; XferBufBlock.BufLen := CmdLen; XferBufBlockinter and length is * set to the next byte to be transferred. * * On Output: ScsiErr if an unrecoverable hardware error occurs. * MsgOut if error occured and bus successfuly moved to MsgOut phase. * NoEvent otherwise. .DoDMA := false; { Before entering data phase, the chip must see the transfer method. } if (SynchState = Synched) then locTMOD.tmod := TMODvalue.tmod else locTMOD.tmod := hex('00'); PtrScsiChip^.tmod.tmod * *************************************************************************} Procedure MsgDoXfer (PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); begin With PtrSessionBlock^, InternalBlock, XferBlock, pScBlock^, PtrScsiChip^ do := locTMOD.tmod; end; data_out_phase: XferBufBlock := BufOut; data_in_phase: XferBufBlock := BufIn; otherwise begin utlSetInternalErr(PtrSessionBlock, ScsiPhaseErr); ResultCode := ORD(ScsiErr); end; end; if (Xfe begin ResultCode := ord(NoEvent); { if not waiting for an ISR, then starting or renewing the transfer defined in the XferBlock. } if NOT ISRWaiting then begin { Is DMA Requested on this buffer block? if so, attempt to get rBufBlock.BufPtr = Nil) or (XferBufBlock.BufLen <= 0) or (XferBufBlock.BufLen > hex('00ffffff')) then begin utlSetInternalErr(PtrSessionBlock, ScsiXferParmErr); ResultCode := ORD(ScsiErr); end else if (odd(ord(XferBufBlock.BufPtr))) oa DMA channel. If one is unavailable, convert this xfer to a programmatic xfer. } if XferBlock.XferBufBlock.DoDMA then begin DMAChannel := osdGetDMAChannel(SelectCode); if DMAChannel = -1 then XferBufBlock.DoDMA:=false; er (odd(XferBufBlock.BufLen)) then XferBufBlock.DoDMA := FALSE; if ResultCode = ORD(NoEvent) then {no errors have occured so far.} begin XferSavedDataPointer := XferBufBlock.BufPtr; XferSavedDataLength := XferBufBlock.BufLen; ennd; { If a DMA channel has been acquired, then start the DMA. Otherwise, this is a programmatic transfer. } if XferBlock.XferBufBlock.DoDMA then begin DMAInProgress := TRUE; if (not hwiStartDMAXfer(PtrSessionBlock)) then d; end; end; {************************************************************************* * MsgDoXfer ************************************************************************* * * On Input: Bus is in correct phase and the XferBlock has been set up.  ResultCode := ord(ScsiErr) else ResultCode := ord(WaitForISR); end else {programmatic xfer} begin if (not hwiProgXfer(PtrSessionBlock)) then ResultCode := Ord(ScsiErr); end; end else {chip interrupt after DMA} begin      On Input: Bus is in MsgOut phase and a transmission error has been * detected during a Command or Data phase. * * Functional Description: * * Send a InitiatorDetectedError message to the target. * Do not raise the ATN line d ResultCode := Ord(NoEvent); end; {************************************************************************* * MsgSetDisc ************************************************************************* * * On Input: A disconnect message has been receiveuring the transfer. * * * On Output: NoEvent if message successfully sent. * ScsiErr otherwise. * *************************************************************************} Procedure MsgSawErrMsg (PtrSessionBlock:PtrSessionBlod. * * * Functional Description: * * wait for disconnect to happen. * turn off disconnect interrupt * Set session state to suspended. * * On Output: BusFree if disconnect occurs, ScsiErr otherwise. * * *************************if (not hwiEndDMAXfer(PtrSessionBlock, ResultCode)) then begin { DMAXfer has completed, but needs to be restarted to complete the overall transfer } DMAInProgress := TRUE; if (not hwiStartDMAXfer(PtrSessionBlock)) then RckType; Var ResultCode:S_SHORT); var xfer_code : s_byte; begin with PtrSessionBlock^.InternalBlock.XferBlock do begin XferRetryCount := XferRetryCount + 1; if XferRetryCount > XferRetryMax then begin ResultCode := ORD(ScsiErr); esultCode := ord(ScsiErr) else ResultCode := ord(WaitForISR); end else begin { DMAXfer has completed, ResultCode contains the state machine result. } osdReleaseDMAChannel(SelectCode); DMAInProgress := FALSE;  utlSetInternalErr(PtrSessionBlock, XferRetryErr); end else begin xfer_code:=hex('05'); if hwiManXfer(PtrSessionBlock,xfer_code,msg_out_phase,false,false) then ResultCode := ORD(NoEvent) else begin ResultCode := ORD(ScsiErr); end; end; if (ResultCode = ord(NoEvent)) and (psns.t_phase = XferPhase) then begin { wait for the peripheral to change to the next phase if the driver has requested the correct amount of data, but the target is expecting more da utlSetInternalErr(PtrSessionBlock, ScsiXferErr); end; end; end; end; {************************************************************************* * MsgPrepareDisc ************************************************************************* *ta (happens if user gives incorrect parms) then could wait forever and the phase will not change. But how long to wait? What if the command were a format command which can take 30 minutes or longer! The phase still wouldn't change  * On Input: A Save Data Pointers message has just been received. * This means that the target is either getting ready to * disconnect or wants to ensure that the transmission done * so far is not lost if an er until the disc has formatted. There is nothing that can be done in this case - PWS will hang. } repeat until (psns.t_phase <> XferPhase) or (ints.ints <> 0); if (psns.t_phase = XferPhase) then begin utlSetInternalErr(PtrSessionBlocror occurs latter on. * * Functional Description: * * Copy the current buffer pointer and length to the save pointer * and length. * * On Output: NoEvent * * *************************************************************************} Pk, ScsiXferErr); ResultCode := Ord(ScsiErr); end; end; end; {with} end; {************************************************************************* * MsgSawErrMsg ************************************************************************* * * rocedure MsgPrepareDisc (PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); begin With PtrSessionBlock^.InternalBlock.XferBlock do begin XferSavedDataPointer := XferBufBlock.BufPtr; XferSavedDataLength := XferBufBlock.BufLen; end;      ************************************************} Procedure MsgSetDisc (PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); label 1; begin with PtrSessionBlock^, InternalBlock.pScBlock^.PtrScsiChip^ do begin if not ints.disconnectes original h/w phase. * * * Functional Description: * * obtain the current bus phase (EventType) and compare with what is in the * Xfer block. * * * * * On Output: IsOriginalPhase if match is good, otherwise EventType bus phase. * *d then begin osdStartTimer(one_second); repeat until (ints.disconnected) or osdTimeExpired; if not ints.disconnected then begin utlSetInternalErr(PtrSessionBlock, ScsiTimeOutErr); ResultCode := ORD(ScsiErr); goto 1; end; end; *************************************************************************} Procedure MsgIsOriginalPhase (PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); begin hwiGetPhase(PtrSessionBlock, ResultCode); with PtrSessionBlock^.InternalBloc ints.ints := disconnected; { turn off disconnected interrupt } SessionState := SessionSuspended; ResultCode := ORD(BusFree); end; 1: end; {************************************************************************* * MsgPrepareRetry ************k.XferBlock, PtrSessionBlock^.InternalBlock.pScBlock^.PtrScsiChip^ do begin if (ResultCode = ORD(CmdPhase)) and (XferPhase = cmd_phase) then ResultCode := ORD(OriginalPhase) else if (ResultCode = ORD(DataPhase)) then begin if (psns.io) t************************************************************* * * On Input: A RestorePtrs messgae has just been recieved. * This means that the target is recovering from an error * or is returnning from a disconnect. If rehen begin if (XferPhase = data_in_phase) then ResultCode := ORD(OriginalPhase); end else begin if (XferPhase = data_out_phase) then ResultCode := ORD(OriginalPhase); end; end; end; end; {********************************covering from * an error, then when the next transmission occurs, the * transmission will begin from the last time the pointers * were saved (beginning of transfer or save data pointers msg). * * Functional Descr***************************************** * MsgWaitReselect ************************************************************************* * * On Input: The bus is in a bus free state. The target must reselect * this session. It is possiiption: * * Copy the save pointer and length to the buffer pointer and length. * * On Output: NoEvent * * *************************************************************************} Procedure MsgPrepareRetry (PtrSessionBlock:PtrSessionBlble that the reselect has * already occured. * * Functional Description: * * Set up for an interrupt to occur when target reselects this session. * When reselected, set the session state to running, and resets the current transockType; Var ResultCode:S_SHORT); begin With PtrSessionBlock^, InternalBlock, XferBlock, pScBlock^, PtrScsiChip^, DeviceSynchParms[Device] do begin XferBufBlock.BufPtr := XferSavedDataPointer; XferBufBlock.BufLen := XferSavedDataLength; end; fer. * * On Output: ScsiErr if timeout, otherwise NoEvent. * *************************************************************************} Procedure MsgWaitReselect (PtrSessionBlock:PtrSessionBlockType; Var ResultCode:S_SHORT); var xfer_code : s_ResultCode := Ord(NoEvent); end; {************************************************************************* * MsgIsOriginalPhase ************************************************************************* * * On Input: XferBlock in SessionBlock containbyte; locTMOD:tmod_type; begin with PtrSessionBlock^, InternalBlock, pScBlock^, PtrScsiCard^, PtrScsiChip^, DeviceSynchParms[Device] do if (not ISRWaiting) and (not ints.reselected) then begin ResultCode := ORD(WaitForISR); ISRWaiting := True     ype; Var ResultCode:S_SHORT); begin with PtrSessionBlock^, InternalBlock.pScBlock^.PtrScsiChip^ do begin if (SessionState = SessionRunning) and (ssts.init) then ResultCode := ORD(NoEvent) else if psns.bsy then ResultCode := ORD(BusBusy) else 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; { SCSIIF common precedes - do not erase this line as it is used during turn process } {--------------------- ResultCode := ORD(BusFree); end; end; {************************************************************************* * MsgAbortMsg ************************************************************************* * * On Input: bus is in message out phase. *--------------------------------------------------} {State types and constants } {-----------------------------------------------------------------------} const state_stack_size = 10; type EventType = ( ; ISRMask := Reselected; sc_reg.ie := true; end else {ISR has occured or Reselected has already happened} begin sc_reg.ie := false; ints.ints := ints.ints; ISRWaiting := false; SessionState := SessionRunning; { tmod value must be set u * * Functional Description: * * Transfer an AbortMessage to the target. * * * * * On Output: ScsiErr or NoEvent. * * *************************************************************************} Procedure MsgAbortMsg (PtrSessionBp before chip sees data in/out transfer phase. } if (SynchState = Synched) then locTMOD.tmod := TMODvalue.tmod else locTMOD.tmod := hex('00'); tmod.tmod := locTMOD.tmod; ResultCode := ord(MsgIn); if ISRError then ResultCode := ORDlock:PtrSessionBlockType; Var ResultCode:S_SHORT); var xfer_code : s_byte; begin xfer_code:=hex('06'); if hwiManXfer(PtrSessionBlock,xfer_code,msg_out_phase,false,false) then ResultCode := ORD(NoEvent) else begin ResultCode (ScsiErr) else if (psns.t_phase <> msg_in_phase) then begin osdStartTimer(one_second); repeat until ( (psns.t_phase = msg_in_phase) or (osdTimeExpired) ); if (psns.t_phase <> msg_in_phase) then begin utlSetInternalErr(PtrSessionBlock, := ORD(ScsiErr); utlSetInternalErr(PtrSessionBlock, ScsiXferErr); end; end; end; ScsiPhaseErr); ResultCode := ord(ScsiErr); end; end; end; end; {************************************************************************* * MsgIsPathActive ************************************************************************* * * On In{ SCSI definitions SCSI definitions are kept in a separate module... } module SCSI_DEFS; import STATE_PROCS; export {-----------------------------------------------------------------------} {forward pointer definitions. put: Nothing expected * * * Functional Description: * * Checks if the session is currently talking to a device. * If the session is running and the chip is connected, then the * path is active. * * If the path is not active, } {-----------------------------------------------------------------------} type PtrSessionBlockType = ^SessionBlockType; PtrSelectCodeBlockType = ^SelectCodeBlockType; {---------------------------------------------------------------------- return if the bus is busy or free. * * On Output: NoEvent if path is active, BusFree or BusBusy otherwise. * *************************************************************************} Procedure MsgIsPathActive (PtrSessionBlock:PtrSessionBlockT-} {Miscellaneous types and constants. } {-----------------------------------------------------------------------} { SCSIIF common follows - do not erase this line as it is used during turn process } type s_byte = 0 ..       { 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, Datayte; case integer of 1:(no_power : boolean;{ 1= no power to terminators } sync_rate: 0..3; { max syncronus tranfer rate } bd_state : boolean;{ 1= bus drivers messed up } parity : boolean;{ 1= parity selected } dev_addr :Phase, StatusPhase, {Message In Events} Synch, SaveDataPtr, RestorePtrs, Disconnect, CmdComplete, Reject, Identify, LCC, LCCwFlag, {Establish Path} NeedSynchParms, {Do a Transfer} OriginalPhase ); {---------------------------- 0..7); { default bus address stored as 1s compliment } 2:(pal_reset: s_byte);{ write only} end; ScsiCardType = PACKED RECORD id_reg : id_reg_type; sc_reg : sc_reg_type; wrap_reg : wrap_reg_type; { writ-------------------------------------------} {Hardware interface types and constants } {-----------------------------------------------------------------------} type {-------------------------------------------------------e only register } config_reg : config_reg_type; END; PtrScsiCardType = ^ScsiCardType; {-----------------------------------------------------------------------} {Chip Register values. } {-----------------} {Scsi Card interface definitions. } {-----------------------------------------------------------------------} id_reg_type = packed record byte0 : s_byte; case integer of 1:(idb : s_byte); ----------------------------------------------------------------------} type cmd_code = (bus_release_cmd,select_cmd,reset_atn_cmd, set_atn_cmd,transfer_cmd,transfer_pause_cmd, reset_ack_req_cmd,set_ack_req_cmd); phase_code = (data_out_phase,d 2:(rl : boolean; { remote/local } dd : boolean; { differential drivers } d16 : boolean; { 16 bit DMA only } pid : 0..31); 3:(reset : s_byte); end; sc_reg_type = packed record byte2 : s_byte; case integer of ata_in_phase,cmd_phase,status_phase, bus_free_phase,arb_sel_phase,msg_out_phase,msg_in_phase); const { sctl bit data values } reset_disable = HEX('80'); control_reset = HEX('40'); arbit_enable = HEX('10'); parity_enable = HEX('08'); reselect 1:(control : s_byte); {write} 2:(status : s_byte); {read} 3:(ie : boolean;{interupt enable} ir : boolean;{currently generating an interupt} intlevel: 0..3;{card interupt level} dma_32 : boolean;{Select 32 bit dma _enable = HEX('02'); int_enable = HEX('01'); { ints bit data values } selected = HEX('80'); reselected = HEX('40'); disconnected = HEX('20'); cmd_complete = HEX('10'); svc_required = HEX('08'); timeout = HEX('04'); spc_hard_er(default 16)} dma_dir : boolean;{software sets} d_enab_1: boolean;{dma enable channel 1} d_enab_0: boolean);{dma enable channel 0} end; wrap_reg_type = packed record { WRITE ONLY REGISTER } byte4 : s_byte; cr = HEX('02'); reset_cond = HEX('01'); { scmd values } transfer_prgx = HEX('84'); { transfer + prgx } transfer_dmax = HEX('80'); { transfer + dmax } bus_release_scmd = HEX('00'); rst_out = HEX('10'); { rst_out set all others clear } {ssts actiase integer of 1:(wraparound : s_byte); 2:(req : boolean; pad : 0..7; bsy : boolean; msg : boolean; cd : boolean; io : boolean); end; config_reg_type = packed record byte6 : s_bon values } spc_not_connected = hex('0'); spc_waiting_select = hex('2'); spc_target_idle = hex('4'); spc_target_reselect = hex('6'); spc_target_xfer = hex('7'); spc_init_idle = hex('8'); spc_init_wait_xfer      psns : s_byte); 2:(req : boolean; ack : boolean; atn : boolean; sel : boolean; bsy : boolean; msg : boolean; cd : boolean; io : boolean); 3:(sdgc : s_byte); 4:(dummy : 0..31; t_phase : phase_code)-----------------------------------------------------------------} {SCSI SessionBlock types and constants } {-----------------------------------------------------------------------} { SCSIIF common follows - do not erase th; 5:(dummy1 : 0..7; bus_free : 0..3); end; ssts_type = packed record byte44 : s_byte; case integer of 1:(ssts : s_byte); 2:(init : boolean; targ : boolean; busy : boolean; xfer : boolean; is line as it is used during turn process } type ScsiDeviceType = 0 .. 7; InternalErrType = ( NoIntErr, ScsiStackingErr, RunLevelErr, StateMachineErr, ScsiInteruptErr, ScsiAddressErr, SelectRetryErr, ScsiManXferErr, ScsiXferErr, Xfe = hex('9'); spc_init_doing_select = hex('a'); spc_init_xfer = hex('b'); {-----------------------------------------------------------------------} {Scsi Chip interface definitions. } {---------- rst : boolean; tc0 : boolean; dfull: boolean; dempty: boolean); 3:(free : 0..7); { combines init,targ & busy } 4:(action: 0..15); { combines init,targ,busy & xfer } 5:(dummy : 0..3; xfer_state : 0..3); { combines -------------------------------------------------------------} type sctl_type = packed record byte34 : s_byte; case integer of 1:(sctl : s_byte); 2:(rd : boolean; cr : boolean; dm : boolean; ae : booleanbusy & xfer } end; serr_type = packed record byte46 : s_byte; case integer of 1:(serr : s_byte); 2:(scsi_err : boolean; spc_err : boolean; pad : 0..3; tcp_err : boolean; phase_err : boo; pe : boolean; se : boolean; re : boolean; ie : boolean); end; scmd_type = packed record byte36 : s_byte; case integer of 1:(scmd : s_byte); 2:(cmd : cmd_code; rst_out : boolean; ilean; short_p : boolean; offset_err : boolean); end; pctl_type = packed record byte48 : s_byte; case integer of 1:(pctl : s_byte); 2:(bfree_ie: boolean; pad : 0..15; msg_out : boolean; cd_oux : boolean; prgx : boolean; pad : boolean; tmode : boolean); 3:(pad1 : 0..31; tm : 0..7); end; tmod_type = packed record byte38 : s_byte; case integer of 1:(tmod : s_byte); 2:(t : boolean; io_out : boolean); 3:(pad1 : 0..31; t_phase : phase_code); end; data_reg_type = packed record byte50 , mbc , byte52 , dreg , byte54 , temp , sx : boolean; maxto: 0..7; mintp: 0..3; pad : 0..3); end; ints_type = packed record byte40 : s_byte; case integer of 1:(ints : s_byte); 2:(selected : boolean; reselected : boolean; disconnbyte56 , tch , byte58 , tcm , byte60 , tcl : char; end; ScsiChipType = PACKED RECORD byte32 : char; bdid : char; sctl : sctl_type; scmd : scmd_type; ected : boolean; cmd_complete : boolean; svc_required : boolean; time_out : boolean; spc_hard_err : boolean; reset_cond : boolean); end; psns_type = packed record byte42 : s_byte; case integer of 1:( tmod : tmod_type; ints : ints_type; psns : psns_type; ssts : ssts_type; serr : serr_type; pctl : pctl_type; data_regs: data_reg_type; END; PtrScsiChipType = ^ScsiChipType; {------     rRetryErr, ScsiEscapeErr, ScsiPhaseErr, ScsiCatastrophicErr, ScsiBadMsg, ScsiTimeOutErr, ScsiXferParmErr, ScsiMiscErr ); SessionStateType = ( SessionWaiting, {Session is initialized and waiting to be started.} SessionRunni:Boolean; TracePtr:ANYPTR; TraceSize:integer; TraceStuff:ANYPTR; InternalBlock:InternalBlockType; END; { SCSIIF common precedes - do not erase this line as it is used during turn process } {---------------------------------------------ng, {Session running (State Machine is started)} SessionSuspended, {Target disconnected, bus released, awaiting reselection} SessionComplete {Session terminated, either normally or with an err} ); ScsiCallBackType = Procedu--------------------------} {Scsi Select Code Block. Common to PWS/RMB O/Ss. } {-----------------------------------------------------------------------} type SynchStateType = (NeedSynch, NoSynch, Synched); SynchParmType = RECORD re(pSB:PtrSessionBlockType); BufferBlockType = RECORD BufPtr:PtrS_byte; BufLen:integer; DoDMA:Boolean; END; const SelectRetryMax = 0; XferRetryMax = 2; type XferBlockType = RECORD XferPhase:phase_code; {The H/W phase (not event p SynchState:SynchStateType; TMODValue:tmod_type; END; ScsiIsrProcType = Procedure(Sc:s_TYPE_ISC); SelectCodeBlockType = RECORD DeviceSessionPtrs:Array[ScsiDeviceType] of PtrSessionBlockType; DeviceSynchParms:Array[ScsiDeviceType] of Synchhase)} XferRetryCount:s_byte; XferSavedDataPointer:PtrS_byte; XferSavedDataLength:integer; XferDMACount:integer; XferBufBlock:BufferBlockType; END; SysCleanUpProc = Procedure(SelectCode:s_TYPE_ISC); InternalBlockType = RECORD ParmType; PtrScsiCard:PtrScsiCardType; PtrScsiChip:PtrScsiChipType; ScsiIntLevel:s_byte; ScsiSelectCode:s_TYPE_ISC; DMAInProgress:boolean; DMA32bit:boolean; DMAChannel:integer; ScsiIsrProc:ScsiIsrProcType; END; implem NextSession:PtrSessionBlockType; pScBlock:PtrSelectCodeBlockType; CallBackLoaded:BOOLEAN; StateErrCode:s_short_signed; StateErrExt:s_short_signed; ISRWaiting:Boolean; ISRError:Boolean; ISRMask:s_byte; SelectRetryCount:s_bytent end; e; XferBlock:XferBlockType; TargetSynchReqAck:s_byte; TargetSynchPeriod:s_byte; SysCleanUp:SysCleanUpProc; StateControlRec:control_rec; END; SessionBlockType = RECORD {Caller sets before session} SelectCode:s_TYPE_ISC; * * NOTE: The following event list must match the assembler event * list defined in ST_EQU * * Standard events NoEvent equ 00 ScsiErr equ 01 WaitForISR equ 02 * Bus Phase Events, returned by hwiG Device:ScsiDeviceType; LUN:s_byte; SUN:s_byte; Overlap:Boolean; DoNotDisconnect:Boolean; CmdPtr:ANYPTR; CmdLen:s_byte; BufIn:BufferBlockType; BufOut:BufferBlockType; SessionCompleteCallBack:ScsiCallBackType; {set betPhase BusFree equ 03 BusBusy equ 04 MsgIn equ 05 MsgOut equ 06 CmdPhase equ 07 DataPhase equ 08 StatusPhase equ 09 * y 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} DoTraceMessage In Events Synch equ 10 SaveDataPtr equ 11 RestorePtrs equ 12 Disconnect equ 13 CmdComplete equ 14 Reject equ 15 Identify equ      ***************************************** *state_5 standard * MESSAGES_msgPrepareDisc * HWI_UTILS_hwiGetPhase *$event_pairs_catch * MsgIn,state_4 * state_10 **************************************************** *$end_machine ******************************************************* ******************* *state_6 standard * MESSAGES_msgPrepareRetry * HWI_UTILS_hwiGetPhase *$event_pairs_catch * MsgIn,state_4 * state_10 ******************************************************* ** match pack * nosyms sprint mname matchstr src module matchstr; src export src src type src stringarg=string[255]; src ttable =packed array[0..0] of 0..255; src src function afterstr(var s1:string; src  16 LCC equ 17 LCCwFlag equ 18 * Establish Path NeedSynchParms equ 19 * Do a Transfer OriginalPhase equ 20 state_7 standard * MESSAGES_msgSetDisc *$event_pairs * BusFree,state_9 * ScsiErr,state_exit ******************************************************* *state_8 standard * MESSAGES_msgReject INCLUDE ST_EQU *$machine_name DoTransfer *$global_recover exec_err ******************************************************* *state_1 standard * MESSAGES_msgSetXfer *$event_pairs_catch * ScsiErr,state_exit * Msg * HWI_UTILS_hwiGetPhase *$event_pairs_catch * MsgIn,state_4 * ScsiErr,state_exit * state_10 ******************************************************* *state_9 standard * MESSAGEstate_2 ******************************************************* *state_2 standard * MESSAGES_msgDoXfer * HWI_UTILS_hwiGetPhase *$event_pairs_catch * WaitForISR,state_2a * MsgIn,state_4 * S_msgWaitReselect *$event_pairs_catch * WaitForISR,state_9a * MsgIn,state_4 * ScsiErr,state_exit * state_exit ******************************************************* *state_9a suspend *  MsgOut,state_3 * state_exit ******************************************************* *state_2a suspend * state_2 ******************************************************* *state_3 standard * MESSA state_9 ******************************************************* *state_10 standard * MESSAGES_msgIsOriginalPhase *$event_pairs_catch * OriginalPhase,state_2 * state_exit ********************************GES_msgSawErrMsg * HWI_UTILS_hwiGetPhase *$event_pairs_catch * MsgIn,state_4 * state_exit ******************************************************* *state_4 standard * MESSAGES_msgGetMsg *$event_*********************** *state_12 standard * MESSAGES_msgTargetSynchParms * HWI_UTILS_hwiGetPhase *$event_pairs_catch * ScsiErr,state_exit * state_10 ********************************************pairs_catch * SaveDataPtr,state_5 * Identify,state_6 * RestorePtrs,state_6 * Disconnect,state_7 * Synch,state_12 * ScsiErr,state_exit * state_8 ************************* *exec_err standard * COMMANDS_cmdStateErr *$event_pairs_catch * state_exit ******************************************************* *state_exit mexit * 0 ***************************************       c :integer; src n :integer; src s2:stringarg):integer; src function beforestr(var s1:string; src c :integer; src n :integera.w #aargs,sp jmp (a0) * * no count with string * after2 moveq #1,d2 count 1 move.l ac(a6),d3 ble aret cursor out of range? bsr.s scan beq aret must match at least once after3 move.l d3,afunc(a6) moveq #1,d2 reset cou; src s2:stringarg):integer; src function changestr(var s1:string; src c :integer; src n :integer; src s2:stringarg; src nt bsr.s scan bne after3 bra aret * scan equ * subq.l #1,d2 pre decriment count * scan1 movem.l d0-d2/a0-a1,-(sp) save for next call bsr scanloop movem.l (sp)+,d0-d2/a0-a1 beq.s scanx dbra d2,scan1 scanx rts scanloo s3:stringarg):integer; src function breakstr(s1:stringarg; src c :integer; src s2:stringarg):integer; src function spanstr(s1:stringarg; src c :integer; src p equ * sub.l d3,d0 addq.l #1,d0 blt sfexit pos in range ? sub d1,d0 is str2 longer than blt sfexit remaining str1 ? tst.w d1 beq.s ssexit2 str2 is null so match movea.l a0,a2 save str1 ptr adda.w d3,a0 st s2:stringarg):integer; src src function utloctal(s:stringarg): integer; src src end; * * UTLOCTAL added 3/30/87 by jws -- removed dependecy on REALS library * def matchstr_matchstr matchstr_matchstr equ * rts afunc eqart source compare move.b (a1)+,d6 first character subq #2,d1 scl1 cmp.b (a0)+,d6 scl2 dbeq d0,scl1 bne.s sfexit found it ? movea.l a0,a3 temp str1 movea.l a1,a4 temp str2 move.w d1,d5 remaining str2 bytes blt.s u 26 ams1 equ 24 as1 equ 20 ac equ 16 an equ 12 as2 equ 8 aargs equ 18 def matchstr_afterstr dc.w 0 matchstr_afterstr equ * link a6,#0 clr.l afunc(a6) func:=0 movea.l as1(a6),a0 ssexit str2 is 1 char scl3 cmpm.b (a3)+,(a4)+ dbne d5,scl3 bne scl2 ssexit move.l a3,d3 sub.l a2,d3 rts ssexit2 move.l d3,d3 set condition code rts sfexit moveq #0,d3 cursor to zero rts * def matchstr_beforestr dc.w  a0:=^s1 moveq #0,d0 move.b (a0),d0 d0:=strlen(s1) move.l an(a6),d2 if n>=0 blt.s after1 then * * count * move.l ac(a6),d3 d3:=c ble.s aret check cursor<=0 movea.l as2(a6),a1 a1:=^s1 moveq #0,d1 move. 0 matchstr_beforestr equ * link a6,#0 clr.l afunc(a6) func:=0 movea.l as1(a6),a0 a0:=^s1 moveq #0,d0 move.b (a0),d0 d0:=strlen(s1) move.l an(a6),d2 if n>=0 blt.s before1 then * * count * move.l ac(a6),d3b (a1)+,d1 d1:=strlen(s2) beq.s after0 bsr.s scan agood move.l d3,afunc(a6) bra.s aret * * count but no string * after0 add.l d2,d3 c:=c+n sub.l d3,d0 addq.l #1,d0 c :: len(s1)+1 bne agood bra aret *  d3:=c ble aret check cursor<=0 movea.l as2(a6),a1 a1:=^s1 moveq #0,d1 move.b (a1)+,d1 d1:=strlen(s2) beq.s before0 bsr scan beq.s bgood sub.l d1,d3 move to front of match bgood move.l d3,afunc(a6) bra  else * no count given * after1 movea.l as2(a6),a1 moveq #0,d1 move.b (a1)+,d1 bne.s after2 * * no count no string * addq.l #1,d0 func:=d0+1 move.l d0,afunc(a6) aret unlk a6 end movea.l (sp)+,a0 add aret * * count but no string * before0 sub.l d2,d3 c:=c-n ble aret c :: 0 bra bgood * else * no count given * before1 movea.l as2(a6),a1 moveq #0,d1 move.b (a1)+,d1 bne.s before2 * * no count no       unt is zero * insert s3 at cursor nilstr dc.w 0 * make ms2 a dummy nilstring chgzcnt move.l #nilstr,ms2(a6) bsr.s chgflds move.l d4,mf(a6) bra chgret * * no count * chgncnt movea.l ms2(a6),a1 tst.b (a1) beq.s  0 length so match sub d1,d0 is old longer than blt chgbad remaining source ? move.b (a1)+,d6 first character subq #2,d1 chg1 cmp.b (a0)+,d6 chg2 dbeq d0,chg1 bne.s chgret found it ? movea.l a0,a3 temp sourc chgnil1 * no count but has s2 might have s3 * replace all occurences of s2 with s3 bsr.s chgflds move.l d4,mf(a6) beq chgret must change at least one chgncnt1 bsr.s chgflds move.l d4,mf(a6) set func value beq chgret e movea.l a1,a4 temp old move.w d1,d5 remaining old bytes blt.s chgf0 old is 1 char chg3 cmpm.b (a3)+,(a4)+ dbne d5,chg3 bne chg2 chgf0 subq.l #1,a0 chgf1 movea.l ms1(a6),a4 string s move.b d3,(a4) tst.w d0 beqstring * moveq #1,d0 func:=1 move.l d0,afunc(a6) bra aret * * no count with string * before2 moveq #1,d2 count 1 move.l ac(a6),d3 ble aret cursor out of range? bsr scan beq aret must match at least once before bra chgncnt1 * no count no s2 chgnil1 movea.l ms3(a6),a2 tst.b (a2) beq.s chgnil2 * no count only s3 * replace rest of s1 with s3 move.b d4,(a0) chop s1 to cursor subq.b #1,(a0) bra chgzcnt add s3 * * no count no s3 move.l d3,afunc(a6) sub.l d1,afunc(a6) move to front of match moveq #1,d2 reset count bsr scan bne before3 bra aret mf equ 30 ms1m equ 28 ms1 equ 24 mc equ 20 mk equ 16 ms2 equ trings * delete remainder of s1 chgnil2 move.b d4,(a0) set s1 length subq.b #1,(a0) move.l d4,mf(a6) set func value bra chgret * have count no s2 * replace count bytes with s3 chgcnil1 sub.l d5,d0 d0 is #bytes after delet 12 ms3 equ 8 mr equ 22 def matchstr_changestr dc.w 0 matchstr_changestr equ * link a6,#0 clr.l mf(a6) function result 0 move.l mc(a6),d4 cursor ble chgret movea.l ms1(a6),a0 moveq #0,d0 move.b (a0e blt chgret movea.l ms3(a6),a2 addr and size of s3 moveq #0,d2 move.b (a2)+,d2 moveq #0,d3 move.b (a0),d3 will it fit sub d5,d3 add d2,d3 final size of s1 cmp.b ms1m(a6),d3 bhi chgret move.l d5,d7 apparent size o),d0 sub.l d4,d0 addq.l #1,d0 blt chgret cursor in range ? move.l mk(a6),d5 counter beq chgzcnt ble chgncnt * have count value movea.l ms2(a6),a1 tst.b (a1) beq chgcnil1 * have count and s2 and maybe s3 f s2 adda d4,a0 cursor addr lea 0(a0,d5.w),a3 after delete bsr chgf1 do it move.l d4,mf(a6) bra chgret chgbad moveq #0,d4 cursor to zero rts * * do one change * chgflds movea.l ms1(a6),a0 source string moveq * replace the next n occurences of s2 with s3 bra.s chgl2 chgl1 movem.l d5,-(sp) save count bsr chgflds movem.l (sp)+,d5 get count move.l d4,mf(a6) set func beq chgret chgl2 dbra d5,chgl1 bra chgret * #0,d0 move.b (a0),d0 s length move.l d0,d3 final length of s sub.l d4,d0 addq.l #1,d0 blt chgbad pos in range ? movea.l ms2(a6),a1 old string moveq #0,d1 move.b (a1)+,d1 old lenght move.l d1,d7 save it for lat count but no s2 * replace next count chars with s3 moveq #0,d0 move.b (a0),d0 move.l d0,d3 final length of s1 sub.l d5,d3 movea.l ms3(a6),a2 moveq #0,d2 move.b (a2),d2 add.l d2,d3 blt chgret count is too big * coer movea.l ms3(a6),a2 new string moveq #0,d2 move.b (a2)+,d2 new length sub d1,d3 add d2,d3 cmp.b ms1m(a6),d3 will it all fit ? bhi chgbad adda.w d4,a0 start source compare tst.b d1 beq chgins !      chgcpy1 sub.w d2,d7 beq.s chgcpy1 bgt.s chgsml * new string is greater than old lea 1(a4,d3.w),a4 end s + 1 lea 0(a4,d7.w),a3 source subq.w #1,d0 count chgins1 move.b -(a3),-(a4) dbra d0,chgins1 bra.s chgcpy1 chgp0 move.b (a0)+,d2 movea.l a1,a2 copy list addr move.l d1,d3 copy list length sloop1 cmp.b (a2)+,d2 dbeq d3,sloop1 bne bsxit dbra d0,sloop0 bra bsxit ********************************************************************* * *cpy move.b (a2)+,(a0)+ chgcpy1 dbra d2,chgcpy suba.l ms1(a6),a0 move.l a0,d4 new cursor value rts chgret unlk a6 movea.l (sp)+,a0 adda.w #mr,sp jmp (a0) * * new string is smaller than old chgsml equ * movea.l a3,a4  utloctal added 3/30/87 by jws * -- removed dependecy of FILER on REALS library * ********************************************************************* * refa sysglobals def matchstr_utloctal matchstr_utloctal movea.l 4(sp),a0 address of stringsuba.w d7,a4 subq.w #1,d0 chgdel1 move.b (a3)+,(a4)+ dbra d0,chgdel1 bra chgcpy1 chgins equ * movea.l a0,a3 bra chgf1 bf equ 20 bs1 equ 16 bc equ 12 bs2 equ 8 bargs equ 12 def matchst clr.l d0 result move.b (a0)+,d2 length of string beq.s error {sb} oct@l1 clr.l d1 move.b (a0)+,d1 cmpi.b #32,d1 ord(' ') = 32 bne.s oct@l2 subq.b #1,d2 bgt.s oct@l1 bra.s error {sbr_breakstr dc.w 0 matchstr_breakstr equ * link a6,#0 clr.l bf(a6) set func to 0 move.l bc(a6),d4 cursor pos ble.s bsret movea.l bs1(a6),a0 movea.l a0,a4 save addr of s1 moveq #0,d0 move.b (a0),d0 length } oct@l5 clr.l d1 move.b (a0)+,d1 oct@l2 subi.w #48,d1 ord('0') = 48 blt.s tstblk cmpi.w #7,d1 bgt.s error move.l d0,d3 andi.l #$E0000000,d3 bne.s error asl.l #3,d0 add.l d1,d0 subq.b #1,d2 bgt.s oct@l5 oct@l4 movs1 beq.s bsret sub.l d4,d0 blt.s bsret movea.l bs2(a6),a1 list addr moveq #0,d1 move.b (a1)+,d1 list length beq.s bsret adda.l d4,a0 start scan subq.w #1,d1 bloop0 move.b (a0)+,d2 char to test movea.l a1,a2 ce.l d0,8(sp) put function result on the stack move.l (sp)+,(sp) move the return address up rts tstblk addi.w #48,d1 tstblk0 cmpi.b #32,d1 test for trailing blanks bne.s error subq.b #1,d2 ble.s oct@l4 move.b (a0)+,d1 bra.s tstblkopy list addr move.w d1,d3 copy list length bloop1 cmp.b (a2)+,d2 dbeq d3,bloop1 beq.s bsxit dbra d0,bloop0 bra.s bsret bsxit suba.l a4,a0 calc func value subq.l #1,a0 move.l a0,bf(a6) bsret unlk a6 movea.l (sp)+,a0 0 error move.w #-8,sysglobals-2(a5) trap #10 value range error end  adda.w #bargs,sp jmp (a0) def matchstr_spanstr dc.w 0 matchstr_spanstr equ * link a6,#0 clr.l bf(a6) zero function value move.l bc(a6),d4 cursor position ble.s bsret movea.l bs1(a6),a0 string addr movea.l a************************************ * SCSI Driver - Build Stream File * ************************************ * Need MAKER, which requires MATCHSTR aMATCHSTR n cMAKER n liMAKER oMAKER laiMATCHSTR alkq frMACHINE= q X MAKER ST_SD.TEXT MACHINE1.UX TABLE 0,a4 moveq #0,d0 move.b (a0),d0 string length beq.s bsret sub.l d4,d0 blt.s bsret movea.l bs2(a6),a1 list addr moveq #0,d1 move.b (a1)+,d1 list length beq.s bsret adda.l d4,a0 start scan subq.w #1,d1 slooOFF X MAKER ST_EP.TEXT MACHINE2.UX TABLE OFF X MAKER ST_XFER.TEXT MACHINE3.UX TABLE OFF X MAKER ST_TP.TEXT MACHINE4.UX TABLE OFF X MAKER ST_AP.TEXT MACHINE5.UX TABLE OFF A MACHINE1.UX. N MACHINE1.CODE A MACHINE2.UX. N MACHINE2.CODE A MACHINE3.UX. N !     G SCSIDVR AND SCSIDISC (DON'T LINK SCSILIB) ***** ************************************************************** recp; ref_list : ref_list_recp; refs_on : boolean; current_option: option_type; procedure error(n:integer); var x : integer; var es1 : string[80]; begin es1 := ''; case n of -1: es1 := 'empty file'; 0:$MODCAL$ $DEBUG ON$ PROGRAM MACHINE_MAKER(INPUT,OUTPUT); {local search{} $SEARCH 'MATCHSTR'$ {system search{{ $SEARCH 'PROGS:MATCHSTR'$ {} IMPORT SYSGLOBALS,MATCHSTR; CONST version = 'machine maker version 4.0'; max_name_size = 16; TYPE name_type =  es1 := 'unexpected EOF'; 1: es1 := 'invalid state definition'; 2: es1 := 'invalid state name'; 3: es1 := 'duplicate state definition'+current_state^.name;; 4: es1 := 'require only one exit code for state '+current_state^.name; MACHINE3.CODE A MACHINE4.UX. N MACHINE4.CODE A MACHINE5.UX. N MACHINE5.CODE a OSD_LLA n a HWIA_UTIL n c PWS_SCSI n LOSCSIDVR. LDNSCSIDVR IPWS_SCSI AIOSD_LLA AIHWIA_UTIL AIMACHINE1 AIMACHINE2 AIMACHINE3 AIMACHINE4 AIMACHINE5 ALKQ F RMACHINE1.CODE RMAstring[max_name_size]; proc_name_type = string80; pnamep = ^proc_name_type; ref_list_recp = ^ref_list_rec; ref_list_rec = record pname: pnamep; next : ref_list_recp; end; proc_recp = ^proc_reCHINE2.CODE RMACHINE3.CODE RMACHINE4.CODE RMACHINE5.CODE CMACHINE1.UX,MACHINE1.TEXT CMACHINE2.UX,MACHINE2.TEXT CMACHINE3.UX,MACHINE3.TEXT CMACHINE4.UX,MACHINE4.TEXT CMACHINE5.UX,MACHINE5.TEXT Q ***************************** * CREATE SCSILIB * c; proc_rec = record pname : proc_name_type; next : proc_recp; end; exit_class_type = (singles,singles_catch,pairs,pairs_catch); exit_recp = ^exit_rec; exit_rec = record event : name_type* Add appropriate defs to * * scsiif * ***************************** ESCSIIF FL/SCSIIF common/ SM1 FLS? I CJM1 ZQSE ESCSI_DEFS I CFL/SCSIIF common/ I CJB ZFLS? SM1 FLSFLS I CJM1 ZFLS? I CJE ZQWJUNK EESCSIIF FL/SCSIIF common/ CF; ename : name_type; next : exit_recp; end; state_class_type = (standard,mcall,mexit,suspend,done_exit); state_recp = ^state_rec; state_rec = record name : name_type; statJUNK FL/const/FLS? SM1 FL/SessionBlockType = RECORD/?I CJM1 ZFL/InternalBlock:/D HCIPACKED ARRAY [1..128] of CHAR;C JBFL/SCSIIF common/ FL/type/FLS IPtrSessionBlockType = ^SessionBlockType; cQSE FRJUNK.TEXT Q c SCSIIF n SCSILIB. ****************e_class : state_class_type; nprocs : integer; procs_list : proc_recp; exit_class : exit_class_type; nexits : integer; exit_list : exit_recp; next : state_recp; ************* * SCSI Disk TM * ***************************** c scsidisk n loSCSIDISC. lnSCSIDISC iscsidisk aiSCSILIB. alkq ***************************** * DONE WITH MAKE_SCSI * ***************************** lh1 oSCSIDVR. lnSCSIDVR x Cop end; option_type = (none,module_name, event_singles,event_singles_catch, event_pairs,event_pairs_catch, machine_name,global_recover,end_machine); VAR sname, modname : string255; sfileyright Hewlett-Packard Co.,1985,1993 All rights reserved. iSCSIDVR. alkq lh1 oSCSIDISC. lnSCSIDISC x Copyright Hewlett-Packard Co.,1985,1993 All rights reserved. iSCSIDISC. alkq ************************************************************** * DONE LINKIN, mfile : text; sline : string255; all_done : boolean; ecode : integer; {-----------------------} mod_name : string80; m_name : string80; { machine_name } g_recover : name_type; state_list, last_state, current_state : state_"      5: es1 := 'invalid state class : '+sline; 6: es1 := 'require only one state reference for state '+current_state^.name; 7: es1 := 'require only one machine reference for state '+current_state^.name; 8: es1 := 'invalid option : '+sline;  global_recover: begin i := spanstr(sline,i,' '); j := breakstr(sline,i,' '); if j = 0 then j := strlen(sline)+1; g_recover := str(sline,i,j-i); done  9: es1 := 'global recover state '+g_recover+' not defined '; 10: strwrite(es1,1,x,'invalid exit class : ',current_option, ' for state ',current_state^.name); otherwise strwrite(es1,1,x,'Error ',n:1); := true; end; end_machine: begin all_done := true; done := true; end; otherwise done := true; end; {case option} end end; { case } writeln(mfile,'->->',es1); escape(0); end; procedure upper_case(var s:string); var i : integer; begin for i := 1 to strlen(s) do if s[i] in ['a'..'z'] then s[i] := chr(ord(s[i])-ord('a')+ord('A'));  else if sline[1]<>'*' then done := true; end; end; get_sline := done; end;{ get_sline } procedure add_to_reflist(var p:proc_name_type); var temp : ref_list_recp; found: boolean; begin  end; { upper_case } function get_sline:boolean; var done : boolean; i,j : integer; begin done := false; while not done do begin current_option := none; if eof(sfile) then error(0); readln(s temp := ref_list; found := false; while (not found) and (temp<>nil) do begin if temp^.pname^=p then found := true else temp := temp^.next; end; if not found then begin new(tempfile,sline); sline := strrtrim(sline); writeln(mfile,sline); if sline<>'' then if sline[1]='*' then begin strdelete(sline,1,1); upper_case(sline); if strlen(sline)>1 then if ); with temp^ do begin pname := addr(p); next := ref_list; ref_list := temp; end; end; end; { add_to_reflist} function find_state(var n:name_type):state_recp; var found : booleansline[1]='$' then begin i := 2; try strread(sline,i,i,current_option); recover error(8); case current_option of module_name: begin ; temp : state_recp; begin temp := state_list; found := false; while (not found) and (temp<>nil) do with temp^ do begin if n=name then found := true else temp := next; end; find i := spanstr(sline,i,' '); j := breakstr(sline,i,' '); if j = 0 then j := strlen(sline)+1; mod_name := str(sline,i,j-i); end; machine_name: begin _state := temp; end; { find_state } procedure make_state(var n:name_type); begin current_state := find_state(n); if current_state<>nil then begin if current_state^.procs_list<>nil then error(3); end else  i := spanstr(sline,i,' '); j := breakstr(sline,i,' '); if j = 0 then j := strlen(sline)+1; m_name := str(sline,i,j-i); done := true; end;  begin { create a state with default values } new(current_state); with current_state^ do begin next := nil; name := n; state_class:= standard; nprocs := 0; procs_li"     last^.next := x; last := x; end; { add_state_proc } procedure get_state_procs; var scanning : boolean; last : proc_recp; begin scanning := true; last := nil; while scanning do begin if ge_option of event_singles : exit_class := singles; event_singles_catch:exit_class := singles_catch; event_pairs : exit_class := pairs; event_pairs_catch : exit_class := pairs_catch; otherwise error(10); t_sline then scanning := sline[1]=' ' else scanning := false; if scanning then add_state_proc(last,scanning); end; end; { get_state_proc } procedure add_exit_state(var last:exit_recp); var x : exit_recend; while scanning do begin if get_sline then scanning := sline[1]=' ' else scanning := false; if scanning then add_exit_state(last); end; end; { get_state_exits } procedure do_state; begist := nil; exit_class := singles; nexits := 0; exit_list := nil; end; if last_state=nil then state_list := current_state else last_state^.next := current_state; last_statep; s,e : integer; temp : state_recp; have_event : boolean; begin s := spanstr(sline,1,' '); e := breakstr(sline,s,' ,'); if e = 0 then e := strlen(sline)+1; new(x); with x^ do begin if curr := current_state; end; end; { make_state } procedure get_state_name; var sname : name_type; l : integer; begin all_done := current_option=end_machine; if not all_done then begin l := breakstr(ent_state^.exit_class in [pairs,pairs_catch] then begin event := str(sline,s,e-s); have_event := e<=strlen(sline); if have_event then have_event := sline[e]=','; if have_event then begin sline,1,' '); if l = 0 then l := strlen(sline)+1; if (l>=strlen(sline)) then error(1); if (l>max_name_size) then error(2); sname := str(sline,1,l-1); make_state(sname); try strread(sline,l,l, s := breakstr(sline,e,',')+1; s := spanstr(sline,s,' '); e := breakstr(sline,s,' '); if e = 0 then e := strlen(sline)+1; ename := str(sline,s,e-s); end else { no event field } bcurrent_state^.state_class); recover error(5); end; end; { get_state_name } procedure add_state_proc(var last:proc_recp; var scanning : boolean); var x : proc_recp; s,e : integer; beegin ename := event; event := '000'; end; end else ename := str(sline,s,e-s); next := nil; temp := find_state(ename); if temp=nil then begin temp := current_stategin s := spanstr(sline,1,' '); e := breakstr(sline,s,' '); if e = 0 then e := strlen(sline)+1; new(x); with x^ do begin pname := str(sline,s,e-s); if refs_on then begin pname := mod_name; make_state(ename); current_state := temp; end; with current_state^ do begin nexits := nexits + 1; end; end; if last=nil then current_state^.exit_list := x else la + pname; add_to_reflist(pname); end; next := nil; with current_state^ do begin nprocs := nprocs + 1; end; end; if last=nil then current_state^.procs_list := x else st^.next := x; last := x; end; { add_exit_state } procedure get_state_exits; var scanning : boolean; last : exit_recp; begin scanning := true; last := nil; with current_state^ do case current#     n get_state_name; if not all_done then with current_state^ do begin case state_class of standard: begin get_state_procs; get_state_exits; end; mith tstate^ do begin write(mfile,name,' ':15-strlen(name)); writeln(mfile,' dc.b ',state_class,',',exit_class); case state_class of standard, mcall: begin if nprocs=0 then bcall: begin get_state_procs; { only 1 machine name } if nprocs<>1 then error(7); get_state_exits; end; suspend: begin current_option := event_singles;egin writeln('No procedures for state ',name); escape(0); end; if nexits=0 then begin writeln('No exits defined for state ',name); escape(0); end;  get_state_exits; if nexits<>1 then error(6); end; mexit, done_exit: begin refs_on := false; get_state_procs; { only 1 value }  {if exit_class in [singles_catch,pairs_catch] then nexits := nexits - 1;} writeln(mfile,' ':15,' dc.b ',nexits:1,',',nprocs:1); xlist := exit_list; while xlist<>nil do with xlist^ do beg if nprocs<>1 then error(4); refs_on := true; end; otherwise writeln('un implemented state class', state_class); escape(0); end; { state_class } end; end; { do_state } procin if exit_class in [pairs,pairs_catch] then writeln(mfile,' ':15,' dc.w ',event,',',ename,'-',m_name) else writeln(mfile,' ':15,' dc.w ',ename,'-',m_name); xlist := next; edure generate_machine; var tstate : state_recp; xlist : exit_recp; plist : proc_recp; rlist : ref_list_recp; sc1 : state_class_type; sc2 : exit_class_type; option : string[80]; begin { gener end; plist := procs_list; while plist<>nil do with plist^ do begin writeln(mfile,' ':15,' dc.l ',pname); plist := plist^.next; end; end; suspeate REFA, LMODE list } if find_state(g_recover)=nil then error(9); rlist := ref_list; while rlist<>nil do with rlist^ do begin writeln(mfile,' ':15,' REFA ',pname^); writeln(mfile,' ':15,' LMODE ',pname^); nd: begin with exit_list^ do begin writeln(mfile,' ':15,' dc.w ',ename,'-',m_name); end; end; mexit, done_exit: begin with procs_list^ do  rlist := next; end; { generate state machine definition } for sc1 := standard to done_exit do begin writeln(mfile,sc1,' equ ',ord(sc1):1); end; for sc2 := singles to pairs_catch do begin writel begin writeln(mfile,' ':15,' dc.w ',pname); end; end; otherwise end; { case state_class } writeln(mfile); tstate := tstate^.next; end; writeln(mfile); readln(optin(mfile,sc2,' equ ',ord(sc2):1); end; writeln(mfile); writeln(mfile,' ':15,' DEF ',m_name); writeln(mfile,m_name,' ':15-strlen(m_name),' dc.w ',g_recover,'-',m_name); tstate := state_list; while tstate<>nil do won); option := strltrim(strrtrim(option)); writeln(mfile,'* state trace table OPTION = ',option); if option = 'TABLE ON' then begin writeln(mfile,' DEF ',m_name+'_T'); writeln(mfile,m_name+'_T equ * '); tstate :#     ); if ecode<>0 then escape(ecode); END. FSFS_FSEEK FS_FWRITECHAR FS_FWRITEINT FS_FWRITELN FS_FWRITEPAOC FS_FWRITESTRFS_FWRITESTRCHARFS_FWRITESTRINTFS_FWRITESTRWORD FS_FWRITEWORD FS_SCANTITLE FS_SUFFIXLDR_LDR LOADER_LOADERMFS_FWRITEREAL MISC_MISCSYSDEVSSYSCOMP2:M:DEVGLOBALS"sglobals; export const crevid = daterec[year:91,day:28,month:10]; crevnmY MAINBODY.TEXTT= 'Pascal'; {title} copyright1 = 'Copyright Hewlett-Packard Company, 198DEVS_SYSDATESYSDEVS_SYSDEVSSYSDEVS_SYSTIME SYSGLOBALSSYSGLOBALS_SYSGLOBALSʷ L,COPYRIGHT HEWLETT-PACKARD COMPANY 1982, 1990OPENUNIT//ENTDDAMYRRP0GLOBALSRFRRF0FP= state_list; while tstate<>nil do with tstate^ do begin writeln(mfile,' dc.w ',name,'-',m_name); writeln(mfile,' dc.b ',strlen(name):1,',''',name,' ':17-strlen(name),''''); tstate := tstate^.next; 2, 1991.'; copyr;INIT:CONVERT.CODE FULLDUMP = false; (* conditional compilation for tree dump *) allowmodcal = TRUE;  conditional comLIBS:SYSLIB2.CODEAL$ *) MC68020 = FALSE; (* conditional comp end; writeln(mfile,' dc.w 0'); { end of table } end; end; { generate_machine } BEGIN writeln(version); writeln; write('Source file name = ');readln(sname); reset(sfile,sname); write('Machine file name = ');readln(modname); ʷ L,COPYRIGHT HEWLETT-PACKARD COMPANY 1982, 1990OPENUNIT//ENTDYRRPGLOBALSRFRRSvP ALIAS ALLOW_PACKED ANSI CALLABS IF  rewrite(mfile,modname); ecode := 0; all_done := eof(sfile); mod_name := ''; state_list := nil; last_state := nil; ref_list := nil; refs_on := true; current_option := none; TRY repeat if not get_sline then escape(1); unt END CODE COPYRIGHT DEBUG DEF FLOAT_HDW HEAP_DISPOSE INCLUDE IOCHECK LINES LIST LINENUM MODCAL OVERLAY OVERLAY_SIZE OVFLCHECK PAGE PAGEWIDTH Pil current_option<>none; if current_option<>machine_name then escape(1); writeln('state machine is ',m_name); current_option := none; repeat if not get_sline then escape(2); until current_option<>none; if current_option<>global ASM_ARCTANASM_ASM ASM_ASSIGN ASM_BCD_REAL ASM_BINARYASM_CLOSEFILESASM_COSASM_DIFFERENCEASM_DIVASM_EQASM_EXP ASM_FLOATASM_GEASM_GTASM_HEX ASM_INTERSECTASM_LEASM_LNASM_LT ASM_MEMAVAILASM_MOD ASM_MOVEL ASM_MOVELEF_recover then escape(2); writeln('global recover state is ',g_recover); if get_sline then begin while not all_done do begin do_state; end; generate_machine; end else error(-1); writeln(mfile,' ENDTASM_MPYASM_NE ASM_NEQUAL ASM_NEWBYTES ASM_NEWWORDS ASM_OCTALASM_RADDASM_RDIVASM_RMULASM_RSUB ASM_SAPPENDASM_SCAN ASM_SCOPYASM_SINASM_SQRTASM_SSUBTOPSUB ASM_UNIONASM_XADELEMENTASM_XINCICI_CI CI_STREAMIN'); RECOVER begin ecode := escapecode; if ecode=1 then writeln('machine_name not found') else if ecode=2 then writeln('global_recover not found'); if ecode>0 then ecode := 0; end; close(sfile); close(mfile,'SAVE'GCONVERT_TEXT_ANY_TO_UCSDCONVERT_TEXT_CONVERT_TEXT FS_FANONFILE FS_FBLOCKIO FS_FCLOSEITFS_FEOF FS_FHPOPEN FS_FHPRESET FS_FINITB FS_FIXNAME FS_FMAKETYPEFS_FPAGEFS_FREAD FS_FREADBYTES FS_FREADCHAR FS_FREADLN FS_FREADSTRFS_$     0LRMDUNUML0v*+ UREQUEST044t+ UNITENTRY010/00DAM00101 TM11:1FSC161&g8Rm 0- HA10-m2- HA1/NN^ _TONesc <<<<Line NORMALsh-exc, error *MESSAGES=continue, <>=terminate, E=edit Error in interface text: =continueNA nCSb/-N ALIAS ALLOW_PACKED ANSI CALLABS IF END CODE COPYRIGHT DEBUG DEF FLOAT_HDW HEAP_DISPOSE INCLUDE IOCHECK LINES LIST LINENUM MOD/-Hn? NA;m0-?>>>>> Error at NA n C "n Hi0( H/NN3N^ _ NNAm B- N3pmfBmACSb`"p mfBmACSbJmg4Bn0-H/HzNJf?<NHzN8`d=|B.p%n^.Ag>A0.CCpR@ fS@SbB.BnBnB.=|=|BnRn0.Hм "tD<FŶt᪅ nmpr.=Ann=@0.r06S2.t96TgJ.g$0.r6p0@0. HЁ=@`J.g pnW2.t06WgSnpn]2.t06f|` 0.R@=@`N3n n1nN^.NuPPIFENDNAHm _-h n<xHh/N$p4mg?<NHzHN8p mn ?<`N n<xHh?<NU nHh0-R@?B'NJg m0-AtA-H n1m 1m!m  ?HnHnN@|+n, .Dg?<2NB `-n N^.NuPNA n Bp$mg?<N`jJ-g n  n m`L-m np.h l?<NB`( n"n  Hh%     !m1mHm-_ n(rf+|!m`BBJm ^-&rmWgNPRmNRmBBmNp`F?<aNU m0-Hp?-<NJf;|NJ`Hm _!nN^.NuNAJ-!g ?<]NF|!-m,ml|N*Hz2N8J.1g4`J-&f ?<XNY/N-_J] ^g?<N`Jmf ;n` ?<NڼJmgHm0-H/N`RU/N(_`Bpmf+mNS`&Y/Nt-_pPo;|P,?<NL`& o;|,?<NlHzRHnHnN@|nl+n, .Tg?<N` .<@@ N^.NuPNAJ-&f ?<XNp"mf@Y/.N n nJ] n ^g?<N~ n `<Hn/.Np.Ar:0g>ACESb`BmAtCSb`~BmAjCSb`dJ-fBmA,CSb`BJ-fBmACSb` J-fBmACSb`;|4J-f RmmB-/Nn``|/N``n0-R@Ar*0fRm??<??<?-n n0@2;N &.`*Hm.Hh ?>>>>/(0.T@?NMb` n/(0.T@?NMb`N^ _\ON..realcharset file max=scalararray recordintegerbooleanpointerelsize= (OFLO) align= signe=@ .=@ n-hp=nްnn=@ n-P0.R@h0.H/ nHhNJgHm.<1?J(8gHm.Hzf +n` nJgU/(/. /.N6Jg`x nJ gU/( /. /.NJg`PJgD-n nJg&Y/(/. /.NQJf +n` n-h`B.N^ _ NNA;m&BJmm0-ABA-H nJhgJgY/Hn?<?-Hlev= valparm refparmspecial result= relative procparm funcparmstandard __BASE + exit: boundparm entry: var string anyvarparm bitoffset=field offset= globalbase = result type: copyparm; addr= maxlength offset:NApmW-&gNN n"m"Q"Q"QJgU/NJg`( n-h` n-h`Sm` nBN^.NuNA?<eA"n$i$RGESb<HPHz>-HN n"m"Q"Q"QU n/( n h&/(B'.N,Jf`\J. g& n P"n "QpR@ f S@f``0 n-h n -h ` . W@ON^ _ NNA . f |`$J WJWg |` n"n 0)hf n 0(@2;N|Rf^RZ ./(N_ nphV n(8Ag0-&ABA-H n0(S@@2;N.U/(Hn"n/NJg/N|`,U n/(Hn"n/N(Jg/N| n-PJgfY/.Hn"n/NQ-_JfD?<eA"n"QECSb< DW". HW .DW$.HW„B`8B.`0 . `W".`WA`U n /( n/(N_` . XW".XWA`U n /( n/(N_`B.` n "n()f B.`^ n "n(")"g |`HPHz>-HN nHPN|U n/(N.n N^.Nu already definedNAB. Jg8 nphf* nJ(g n-h .PW@ N^.NuNAB. U/.NJg nh" N^.NuNAB. JgJ nJhf> nphW".T@U/. NNU/.NDg U n /( n/(Nt_`B.`,B.`$U n /( n/(B'B'N_``V n phfU n /(/.N_`. nphfU/. n/(N_`B.N^ _PONNA-n nphf"n ""n"` .VAn -.g ?<^N.N^.NuNAHn/<&N-n nB(B(0.H 1|Hh HmN n1|!mP|1| B("Hh/<N n-h"nB)"3|Hi HmN n1|!mD!|0.H!@-n N^ _TONHf n n `z .DW nJhVg"n ""n"`H n B .Pf n `( nJg n h"n"` nBN^ _ NNA n CSb/./<,N n-P nHPHnNd n!md B1|HhHmNNA o?<N.-|Y?. N n Hn <"< RlR/N-n n0"n Jg1| "n i `J n h"n3h p=i nn(=@ n h0."n2.  0.R@h n0( R@H-nn=@ n0. 0.HR n!m6 1|0.H!@1|$N^ _ NNu      NAJmf-|h n0( HV-g ?<^N. n1n -n nB!nN^ _ NNAB. JgD-n nphf0pW-g (DW"(HWA N^.NuNAJ WJWg |`RU/. N~U/.Ntg2 n"n ) n "n ")` -|N^NuNA-n YN //<N AA-H0.@2;N* n0n`" n01n` n0!nN^ _\ONNAYNP //<N AA-H-n nBh0=|Rn=|Rn n0.HЀ2.4BJAW@`B.N^ _PONNA| n "n)(g NI8 n "n0)hgNI`* nJ(f n "n)$($g NI nJV n JVg n "n )g NI nJV n JVg\ n hphf.U n/( n /(HЂ$0"pJgJnWrAn=AJ.g4"n0.2AI@tD<Fűtv᫇`2 npn2AI@tD<FŰtv᫇ nmD nm0N^ _\ONNA-n npPfD"n  p2( H-An$-@ n ."n ". '     /)/.?<N n (/?<N`,-p-Hz/.?<N/.?<N` nJh&W-g8-p-"n/)/.?<N n/(?<Nt`-p- n ( \"( _g2"n/)/.?<N n (/?<-h "npi Wr"\p"_J"Vg0J"o 1n` n ("D!@""n3n`P n"hJi f 1n`6 nph W"n$irj Vg 3n` /.N~N^.NuNABmBmB. n ph Wr0nVg n"n 3h `L n p h WN`( n/(/.?<N n/(?<N`Hn/<N n"h"$n%i"h"#n-p爁--p-0-HЭ T"n"/(?<N|`jHn/<N n"h"$n%i"h"#n-p爁--p-0-HЭ T"n"/(?<N nrh W0.H/Hzh-AN".g| n 1| 0.HЀA-00鈁-0.H/Hz(N_0.@2;Nt$tttttz t .Rh` ;|NJN^ _NNA n-hYN //<N AA-H n0(p("nJm i` n <Ш"n@ nphW"n爁))0(鈁)N^ _PONNA-n n0( @2;NP, t`N^.NuNA0.HЀA-00鈁-0.H/HzN_0.|6@2;N0j-p㈁-m?p툁m-p爁--p-`<-p㈁-m?p툁m-p爁--p-`?-NB >;|NJ`-p爁- n-0(-`-p爁- n-0(-`-p爁- n-0(-`|-p爁--p-`^-p爁- n-0(-`:=m n-0(-J(g-p爁-/(/N^ _TON $@@NABm0. HЀA -00鈁-0. H/HzN_0. Q@@2;N||||||||||v|||||^^||||||||||v|<0. Q@-N`H nJWJ"Wg-p爁-` -p爁- n/(?<N nJ"gH0.HЭ T-@ ("fHz/.?<N` n/("/.BgN`b-p爁--p- nJ("g ($Ш/?<N8`N n-h$/($<PHn/N0---n nJh f*Jl <Ш@` nh`| n/(?<N`pn f-p㈁-`HpNn f-p㈁-`,p2n f-p㈁-`-p㈁- nm?0( 툁m/.N`-p㈁-pKn fm?p툁mHЭ T-@Hn/.BgN n/(?<N`-p爁--p- nJ("g ($Ш/?<N`P n-h$/($<PHn/N.0-HЭ T-@Hn/.?<N n/(?<NZ`H-p爁- nJ(g"-p- ($Ш//N.`-p` nph S@m?툁m-p爁- n-0(-`-p㈁-p$n WrTAm?퉃m/.Nd`j-p㈁-m?p툁m-p爁- n-0(-B?<NV` p,n WrA-㉃-m?p툁m/.N`-- nJ("g ($Ш/?<N` n-h$/($<PHn/Nt0-HЭ T-@ n ( \"( _g.Hn/.?<N n (/?<Np`$Hn/.?<N n/(?<NJ`8-p爁--p- n/("?( N` np㈁-m?p툁m/.N`-?p툁-p7n D@-ց-/.N`-p㈁-m?p툁m n ("l^-爁- n ("-ׁ-`B-p㈁-m?p툁m-p爁- n-0(-`?-Npmf?-N`-h"-p爁-0-HЭ T-@"nJ)g. (Щ -@ .-@ \ _-@g-p-/.?<N` nJh&W-g0-p-Hzb/.?<N/.?<NP` n ( \"( _g>-p-"npmf /-NN^ _\ON $@@NA n-h"nm?0) 툁mpi g<0-Xm?툁m$h -0*㈁-/(NJ`" n-0(㈁-"n/) N&N^.NuNA nJhf=|=|=|=|J`=|H=|I=|J=| n(     l/NJng``-n n-0(㈁-ph WrAVAm?퉃m/. Nl`pnf-p㈁-`Hp!nf-p㈁-`,pnf-p㈁-`-p㈁- nm?0( 툁m n p h W nrh W-HN nCASb`ACESb<HPHz-HN n-?p툁-`4-?p툁-`"-?p툁-`-?p툁-/.N` n-0(or opening Error writing  file, ioresult(NAJfJ-fbHm?<HmHzNHmHzNHm`f n-0(㈁--n nJ"m h%` n <Ш"@`/NpGng`B`HmHn/<0.H/<Npg+|;|NJN^ _\ONNAJfLJ \JnVg: . m . =@ . lмr R=@ m0.Hr 2.HҀAp . R=@ . Rlмr R=@ m0.Hr 2.HҀA?-NBnRn0.AA-H npPf?(N` npPf /(N nmJ.g n 1| N^ _ N $@@ $@@NuNAB-+|;|;|N^NuNABm+nB-B B0-R@;@+|fBjBmBm;|*Bmp0.n m0.Hr 2.HҀA m0.Hr 2.HҀA`F . lмr 2-HҀ=A . =@ nl =|`=|YHmHn0.H/0.H/<N0.Hg+|;|NJ0.Ap0.R@l|r `R@=@0.BmHzB?<BgNPN^.Nu_BASENA?. N.|< HnA HP?.?<NACESb<HPHn-HN nYHm/-/<0.R@H/<Npg+|;|NJ0.R@hjp2-*SA=AFYHmHh0(H/0(H/<N n0(Hg+|;|NJ nl n1|` n1| n1nYHmHh0(H/0(H/<N n0(Hg+|;|NJ`V nphgHYHmHh/<0(R@H/<Npg+|;|-HBP1|Bh"m"Qpd "m"Q m PC$nASb0*S@5@0-S@5@Bj5mYHm/-/<B<Npg+|;|NJN^.NuNAJnW-JWgL/N>HmHzNJg ;|NJ-m n| CESb`8NJ n1|pn nh=@0.R@l|r `n=@0.R@@=@0.Hr 2.HҀCq0.Hr 2.HҀCq0. n0.Hr 2.HҀC0.Hr 2.HҀCN^ _ NNA nJhgFYHmHh0(H/0(H/<N n/-N/-/HzT?<?ZZZZZZZZZZZZZZZL nBh ` n1| ` n1| ` n $nJ*gr&n(Spg((h ,<rAj A=A` n=h n/( "nHi<?.$h ?*$n/*N `& n/( "nHiB'BgBg$n/*N n"h!Q`. n h .o/N n h .o8p".-An-@BgN1| N^ _ NNA?.?.?. nHh"NH-n0. Q@@2;N2ZZZZZZZ>ZZZZZZZZZZZZZZZL nBh ` n1| ` n1| ` n1| N^ _ NNA nJho>phl?(Nز nT` n=hp.?N nR .Rh n h!nN^.NuNA n-X=PJg nphf n-h nJhfJ.g/./N4` .TW".PWg?./N`v .Df./.N n(g Bg/NT/./N`>/.N n(g Bg/N(J.g?./N nBhBhN^.NuNA n/(N?. N n hRN^ _\ONNA n/(Nd?. N. n hTN^ _\ONNA n/(N6/. N, n hXN^ _PONNA nJhf./(N nph l"h)g Bg/N< nphnh n0(h "hD` ;|NJ` nphf2/.N n(g Bg/N nXBNj` nphfH/.NR n(g Bg/N nL H/./N/./N`PJgH-n n0S@m,|n$@2;N Jgv-h"nJgf$Q0*]@@2;3@p il6/ N n h(g Bg/.N nBh"h3h np h obJ l  nph oD-|p2( H-An-@ .Ѯ .Rh/. /.N-_ -n n hphH-@Jl/.N6 n-h`/NN^NuNA=|Rn=|RnJnW2.H/Hm-@N .f\0.2.4ҀAA-H nBPB nJPf$phf"hL H n1|N^ _TONNA=|Rn?.N nmN^NuNA n-h nph WJWJh WJ"W(@@ N^.NuNA-n n-h"n=i -Q$n$j&hLH n1n N^ _PONNA n pphW.Ag"hL H n1| nmt nm`;|+|Bm;m;|r+|tBmx;|z;|N^ _TONNA . .-1gS. -.2l+m.2-n n1| pmf1|!m"` n1|B" n!m.B(B(Bh N^hf n -h . TV". PV nAN^ _PONNA-n n-h"nJ)g=|=|`=|=| nph WJ"V0( H/Hz-AN". n(0.H^2.H]ghB(=h Bh ^ ]J" _PONNA0. 2.4ҀAA-HJn W nrhVgJo S` ;|NJ nJWrhWpPVgBPN^.NuNApnf4=|Rn0.4ADJpf`n nm` Jnf=|=|=|=|Rn0.4AAVJVg-hB`BU/.N2Jf/.<Ng.` n0(4CC-I"npigxplHBgHnN n=h ?<&"n/)HnN} n1nBB"1n `( nphf"hL H n1|Jgv n=h Bh =h -H nJPfD0(@2;N.``( n0(nl=n=h`=n nmJnm=n?.N``Jnm=n?.N``:pnf0=|Rn0.4AJpf`b nm?<AC|ESbHn/--HNP n< ] ^g 1| ` n1| =|-n?<Hn n/(N} n1n 1n nn1n N^.NunNA-n nph f?<?(Nj` nph f&?<?(NL?< n0(R@?N8`N n0( H/HmNJg2 nph f *      n0( ng6ph W"n"iri Wg /.Nl$/. ?.NN^ _ NNA n h1| pmfL/. B'Ng. n hBh ?< n/( n /(N}Bg n h?(N`?<! n /( n/(N} n/(N|N^ _ NNA/.N/. Nm@ nm,Jm gp0- H/Hm4NĄ;|@pm f4;mJmf Bm,`;|,?<*Hm Hm4N}`;|,?</Hm Hm4N}N^NuNAJm o:;|pm l?</Hm4Hm N}`?<*Hm4Hm N}Jm fNUN^NuNA/.Nd/. NdN^ nJPgp n JPgT n h1| /. Nl$?< n/( n /(N} n/(N| n /(N|`/./. /N`/. /./NN^ _ NNA-n n"h"ipif/(/(/N. n B`LB. n"h$h0Qo/(N n/(N` n/( _ NNA-n n-hJ. g"n3| ` n"h//(NĄ/.NdN^ _ NNA-n n0( m԰| n@2;N:::^/.B'/Nb n/(/(/N,`/.</N> n/(/(/N`l/.</N n/(/(/Bg?(N nJ(g?<?(NN^.NuNA . l -n `-nN^ _PONNA/. /.N . //.N-_N^ _PONNA-n n-hC-I"np_r\g$nBj |` nJ\ _g"nBi B)`p n N n/(N n/(NZ n/(NZ n"h-i"n=i =i i"h-i"n=i =i ipnf|=|!/(?..Nφ n"h-i"n=i ipnfNJ"Wr nVg |`0 np"_r"\g"n/)\ _g"n3| |`> nJ\ _g"n3| B)` n1| | n0. h oB"nJ].Ag0. R@1@ |` n1n n` n0. h f(@.g0( R@1@ |`^.@ n(g."nNl$=|`pnfB.=|! n/(?..Nφ n"h-i"n=i ipnfNJ"Wr nVg |`0 np"_r"\g"n/)Nl$=|`=|0.nW..Wg n`pnf&|png n/(Jl0( R@1@ |` nB(` nJ(f0( R@1@ |N^ _PONNAACSb|Jot/./< N =@/./< N-_p0n@ACESb nJ(g /.N`N^.NuNA/. NDd-n n-h"nJ)g /. N\ nph f/. ?.<Nφ n0( ngH0.h oJ(f?<HnNx?<0HmHnN}/. N n=h ?<*"n/)HnN}Z n"h"ipi V"hri W"hpi W"h"i)Bg?<N"h/)Nx`J.f$?. n"h/)"h/)N}`Z n"h"ipi V"hri W"hpi W"h"i)Bg?<N"h/)Nx n"h/)N| n"h/)N n/(N| n1| 1n|J-)g=n?<NHnNx`:/. Nl$ n0( nl 0( R@1@ ?<#"n/)Nx``b nph f/. Nl$` /. N, nph f R`(pnf nT`Jnf nV n1n N^ _\ONNA n -h| n  nN^ _ NNAJm fNTTBm =|Rn=|Rn0.2.4ҀAppfTRm 0.HЀ2.4BJAHЂA\tD<FŰtv㫇;n;n`@0.HЀ2.4BJAHЂA\tD<FŰtv㫇 n+     N`H/.</N n/(?<N n/(Nk n/(Nd` ;|NJNN8 n0( @2;NP^zzzzlBB4&HzNx`VHzNx`HHzVNx`:HzvNx`,HzDNx`Hz@Nx`HzNx`NN^.NuASM_XIN ASM_UNIONN$Bm`;|` ;|` nphf(=|U"n "i"i0)H/Nɸ=_B.B n-h"h$n$j fpmf"n$i *X-@` n"h )T-@?<*HnHmvN}pmf Y`U?<*HnHmvN} n"P-i?<* ASM_EQUAL ASM_NEQUAL ASM_INTERSECT ASM_INCLUSIONASM_DIFFERENCENAJ-g ?<MNwN^NuNA/.NDdBm-n n-h (hf("nX?<*/(HmvN} nY`,=| n"h0)$H-@?<*HnHmvN}/.NdN^.NuNA-nU nHnHmvN}`@=|=|U?<Nň=_ n"hpf"n$i *X-@` n"h )T-@?<*HnHnN}=|?<#HnNx?<*HnHmvN} n"hpf Y`U=|?<*HnHnN}=|?<#HnNx?<*HnHmvN} n"P-i"h/)NbJg n/(NB`L=| n"h"i/)HnHnNj;|?<*HnHmvN} n/(Nd n/(?<N n/(Nk nJg/(?<N n/(NkN^.NuNA n"n 0) h g B.` n 0( m԰|*n@2;NVVVV=|?<*HnHnN}=|?<#HnNx?<*HnHmvN}?<?.NHnN|`=| n"hpif -h `& nJ(g0( H-@` n-h n/(HnHnNj?<.HnHmvN}-n?<.HnHmvN}-n?<.HnHmvN}N^ _VVVVVVVVVVVVVVVV HzU n /( n/(NXU n /( n/(NB@`4U n /( n/(N_` n"n )W@`U n /( n/(NU n /( n/(N@` NNAJ g-n nph$W-g"n/)/( <N\ nph$f"n/)Nd` nph$Wrh$Wg"n/)Nd` nph$f"n/)N` np h$f "n /) "n"i/)/N`-n-n nphf -h ` n n"n )WU n /( n/(-@N .@`~ n"n )W n"n ")WA`L n J(g4 nJ(g n"n )W@`B.`B.`B.N^ _PONNAJ n p&h f/<Hn`NĄHnZ/<NHnV/<-h& n/(N n 2;N8^^`t n"h"iJi g /(BgN`R n"h"ipi g/(?<N`, n"h"ipi g/(?<N`` n0(H/HzNJg n-h"nJQg/(Nk`n;| n"hpil&N-nZR nRC`!I"mh$nVL?H?5i$$ nV  nR!nV1|$ B/.Z/. N/.Z/.N``HU/. /.NBJf4-n R/. NBBnUBgNň=_?<& nR/(HnN} nR/(N|=|=|U?<Nň=_hBnl?<*HnHn`N}B._J-g"h0)H/HmvNb`?<HmvNxU n/(?<N`Jf?<5 n/(Nx`&J-f n/(NZ n/(Nk np h$g "n-Q n-h `lN^ _PON NA nJf/. Nd`/. nHhNhvN^ _PONNA n -hJg n (hfH/.NDd-nN nN-hJ"nJX?</(Hn`N} nJY|_`\ nRp*h VU/(-@NNb .Ng6=|Bn n h0($H-@?<!HnHn`N}|_J._g2-|Bn?< HnNx-|?<LHnNxBnUBgNň=_/. n hL?H?`;|2L&H n/(NDd nJf/(/Nh` n"P-i/.NDd n-h nph fl"n$i$jpj f0/)/N nJ"gBg"n/)HnN}`$ n"h"i$n *"ѩ/(/N`/.Nl$ n"h"ipiN?<& n/(HnN} n/(N|=|Bn?<*Hn`HnN}?<*HnHnN}=|-|?<JHnHn`N}-|?< HnNxBg?.N?<?.hNBg?.NN^ _PONNA n hphf n/( n /(/.N-n n h S2; W"h"i)gB/(/N/.?<NBg n/(HnN}?< n?(N`| nJh f/.?<N nph W(Ag/.?<N n"h"i|"n$h$j5i$h$j5i /(/NN^ _PONNA-n /. n/N n/(NDdJ.+     N(0-鐐| m| n@2;NvR.@d?<HnNx`?<HnNx`?<HnNx`?< HnNx`v?<HnNx`d?< HnNx`R?<HnNx`@?< HnNx`.?<HnNx`?< HnNx` ;|NJ` n "nHPHQ/<=N nC!I pnf nC ` nC /.HnNf?<%HnNx|N^ _\ON_NA-n n-h"npiVriWg<$hpjn($h//(NĄ?<5 n/(Nx`\ n"h-Q.gR=|-n;|rJ.g n/(/.<Nq`P n/(HnB'Nq-nJg. nJg n-h` n"n!Q n N8N^ _NNA-nB n"hpi ff/(/.HnB'B'. /.NHn/<N n"n!Q n n/B'HnN(?<HnN ?<JHnHmN} n"h3| /(/(N nphf"h&/)"n/)<N` n/("n/)N nphl;|0(H/HmvNbN݈N8U n/(BgNJf" n/(HnNf?<%HnNxN޶` n0(| m|Hnz@2;Ng n"h"iBi n/(N n-h"n-i$nX5| ?<N/)Nx - T-@BBn?<HnNx;|?<* n/(HmvN} nY .S/ - ?N n/(N|BgHnNx?<+ n/(HnN}Bg?.N=|B.BJ.g x` n"hpi f"/(/.HnB'B'. /.NP`J. g n/(/.Nj2;|`(;| n/(Nl$ n"h/)N|Hn/<N n"n!Q n n/B'HnN(?-HnNx/.N& n"hpi fj/(/./.... /.NN8?<%HnNxJ.g Nl` B'NØN^ _ NNAJf =| `L n Sm:n02;N$Bn `=| `=| `=| N^.NuNA-nJf nHh/<(N` n!m"m+Q n"h$m""m"-hU/(NHHn/<N n"n!Q n n/B'HnN(?<HnNx` n"hpi f&/(/./.... /.N`J. g n/(/.Nj2;|`(;| n/(Nl$ n"h/)N|.@. AgFHn/<N n"n!Q nN8 n1_ B(Bh B(BBhB(B"BhC-I"nB3|N^.NuNA-nB n"hpi f$/(Hn/.B'.. /.N`P n"hpi ft/(Hn/.B'.. /.NJ.f&Hn/<N n"n!Q n n/.HnN(?< n/B'HnN(?-HnNxN8N^ _NNA n p&h f./. n /(/.N/. n /(/.N``/. NR/.NDd/.NU n /(NbJg/. Nd` ;|NJNbN8HzNxNN^ _ N ASM_SAPPENDNA n p&h f./.HnNx`J. fvJ.g n/(/.<Nq`P n/(HnB'Nq-nJg. nJg n-h` n"n!Q n `P n/(/.Nj2;|J.f&Hn/<N n"n!Q n n/.HnN(0-鐐| m| n@2;N n /(/.N/. n /(/.N`/.B'Ng. n h0(4ArpfZ nC-I"nBi 3| UBgNň n1_?<+"n/)"nHiN} n"n"i3h n h0(4AA-H nBh!|Bh/. /.NN^ _ NNAvR.@d?<HnNx`?<HnNx`?<HnNx`?< HnNx`v?<HnNx`d?< HnNx`R?<HnNx`@?< HnNx`.?<HnNx`?< HnNx` ;|NJ/.N& n"hpi f&/(/././. n/(/N/. n/(/N n h0(4AA-H n1|0BN^ _PONNAB. n (@ n (,Ag n J gB.=|0.m_.Ag: n h "m0.HCpR@ fS@f|`Rn`J.gpA... /.N6`Z n"hpi fv/(/./.... /.NJ.f&Hn/<N n"n!Q n n/.HnN(?<HnNx`J. g\ n/(/.Nj2;|J.f8J.f&Hn/<N n"n!Q n n/.Hn"n "i ECSb<HPHzT-HN n"n "Q<HPHQ-HN nCASbHn/<N-n n1|* BBB(Hh/< N n-h"n2p.3@ /<Hi /<<Hn/<0) H/N/.NDd/.NdHn/<=N,     nn8nnnnnnnnnnnnnnnnnnnnnnnnn  nnnn\nnnnnnn666666nnnnnnn0(H/HzNJg, n"h//(NĄ?<5 n/(Nx`\ n"h-Q.gR=|-n;| N ASM_BINARY ASM_SAPPEND FS_FBLOCKIO UIO_UNITBUSYNApm W n hrhW n 0( H/Hz-AN".g:Bn=| BB.B.Hn/< N-n n0p-1@ p=h nn(=@0. n2.C 0.R@h?<NHnNxBHn?<JHnHmN} n"h3| /(/(N n0(H/HzBNJg n"h/)Nd` n/("n/)NN۪N8 np(hWr)hWp"hWr#hWg:CEGSb$P<HQHR-IN"nHQN` npQhWrJhWgHzB'HnN(?<HnNx;| /. /.N n -hN8/. NM n !nBHnB'HnN(?<HnNxHnN&Bm /. NVn/. NkHnN&;| N8`j-n n-h"h-iJm W"hriWg`j n"hpiWrh WNx` n0(|E@2;N.jjjjj...jjjjjj HzNx`>ACBESb"n$Q n0( H/HzNJg n/(Nl$` n/(NDd n0( |@2;N "J6 "hpifdJm f/. NVn`J=|-|?<HnHm&N}/. n/(N˨ n"h"i$n5i `l n"h"iNN8HzNxNx`\ n"h/HnNĄBn?<HnNx=|?<5HnNx n-h=|"h S-@Bm?<*HnHmvN};|+|*?<*Hm&HmvN}B* n/(NdNdN8HzHNxNھ n-PJf n"h3| "h3| `| nJ)f/("h"i0) R@?N$?<2 n"h/)Nx/. n/(N˨ n"h"i$n5i ` n"hpQf /(NZ/. n/(N˨?<Hm n/(N};|`l n"hpifJm f/. NVn` n/(Nk;|2?<NHm&Nx-|-h"n3| 3| 3|#||B)#m6"`@ n"h3| "hB)/. BN` n"h/)?<N n"h/)Nk n"h!Q-h"n-i$Q-j$Q$R-j/.Nd/.BgNπ/.Nk/.?<Nj/.NkN:N8HzNxNٔ nBn?<HnNx-|?<HnHm&N}/. n/(N˨ n"h"i$n5i ` n"h"iJ)g~"h-i/(Nl$| nph g"n/)0( R@?NǜB.-|Bn?<HnNx?<2 n"h/)NxJ.gN^/. n/(N˨ n"h-h"n3| |3| `X n-h"n3| |3| =|-|;| ?<JHnHmN} n-h"n/)Nd n-P n/(Nd n-P n/(?<NΘ n/(Nk n-P n/(?<Nr n/(Nk=| np/hf-|`"i$n5i ` n/(NZ/. n/(N˨ n"h"i$n5i `/. n/(N˨ nBh B(`/. n/(N˨ nBh Bh XB(` n"h"ipi g*J-g/(/-P<N\ n/(BgNl/. n/(N˨ nB(`$/. n/(BBm?<*HnHmvN}NN8HzNN^`B n-h"n3| 3| |$h/*NkNֺN8 n0(|?@2;N D6(RHzNx`DHzNx`6Hz*Nx`(HzNx`HzNx` HzNxN׬` n"h/)NdN$NN˨ nB(=|-|?<Hn"n/)N}` n"hpifJm f/. NVn`t n/(Nk;|+|*?<*Hm&HmvN}?<*Hm&HmvN}B*NzN8HzNxN n1| 1| |`< n"h"iJ)g /(N n"hp*i 8 n0(| @2;N"HzNx`HzNx` HzNxNF n-h"n3| |3| ` ;|NJN^ _PON0 FS_FASM_ASM_LNASM_POSASM_SINASM_COSASM_EXPASM_HEXASM_SCANASM_SQRT ASM_SCOPY ASM_OCTAL ASM_ARCTAf/(?<<Nφ`6 n"h-i"npi W)Ag/(?<N n"h"ipi fV/(Nk;|?<*Hm&HmvN}N͘N8HzNxN n1| 1| |`Z n/(?<N| n/(Nl$?<1 n"h/)"h/)N}/. n/(,     N^ _PONNA n BPBnRn0.HA".f n 0 nmN^ _ NG1"K"4NApm f@Bn=| BB.B.Hn/< N-n n0p-1@ p=h nn(=@0. n2.C 0.R@h?<NHnNxBHnk n/(?<N2 n/(NkNN8 nph fHzPNx` HzJNxN< n-h"n3| 3| |!mD` n"h-i"npi f3| |`2 nph W"n$i$jrj Wg /)Nl$ n/(Nl$ n/(?<NL n/(B'HnN(?<HnNx;| /.NB n"h -i/( NM n"h #nBHnB'HnN(?<HnNxHnN&Bm n/( NVn n/( NkHnN&;| N8`Jm f n/( NVn` n-h "n-i/)Nk n/(NkN$N?<N< nph W-"hr*i Vg4/(Nl$=|-|?<Hn n"h/)N} n"h"i3| ?<""h/)"h/)N} n/( "n/)N˨ n-h"n3| |ph f?<K/(Nx n"hp*i W"hJ]"hp*i Vg`?<N˨ n1| ` n/(NkNN8 n0( |!@2;N"HzNx`HzNx` n1| N n1| |`Jm f/. NVn`z n/(?<NØ n/(NkNdN8 n"h"ipif/. /(N˨` HzfNx n1| 8 n0( | @2;N$2HzRNx`(HzNNx`HzJNx` HzFNxN6 n1| 1| |N^.NuASM_RADDASM_RSUBASM_RMULASM_RDIVNA n-h "npi f/)N n"h-i"npi f/(?<<Nφ`, nph N͌ n|1| `N^ _PON  @`ASM_MPYASM_RMUL ASM_ROUND ASM_TRUNC ASM_FLOATNA-n n-h/(Nk n/(NkN˒N8 n0( @2;N DR(6HzdNx`DHz^Nx`6HzXNx`(HzRNx`HzLNx` HzFNW(Ag"n/)?<N$ nph f"n/)Nk n/(N n"h"ipi f/(?<<Nφ n"h"ipi W"h"iri W"h"ipi W"h"i)Bg"h-i"npi g>pi f3| |` n/(/(?<xN̈ n1| N^ _PONASM_EQASM_NEASM_GTASM_GEASM_LTASM_LENA n h hphf/. /.N`/. HnHnN?< n /(Nx n hBh J.gX n 0( @2;N (D?<> n /(Nx;|`?<= n /(Nx;|`N n/(Nk n"h-i"npi g,pi f3| |` n/(?<N n/(NkN¸N8HzNxN n-h"n3| 3| |` n/(?<N n/(/(?<N0 n"h"ipi fH?<1"h/)"h/)N} n/( "nJ.g?<D n /(Nx;|`?<< n /(Nx;| `J.g?<F n /(Nx;|`?<: n /(Nx;| `~J.g?<E n /(Nx;|`?<9 n /(Nx;| `>J.g?<C n /(Nx;|`?<; n /(Nx;| `/)N˨ n"h/)N|`V n/(Nl$?<1 n"h/)"h/)N} n/( "n/)N˨ n"h/)N| n"h3| n!mD` n/(N2 n"hp*i f"h/)Hn"n/)NH`Bn nph WJnVg"hS/(Nl$ n/(T n 0( @2;N (D?<> n /(Nx;|`?<= n /(Nx;|`J.g?<E n /(Nx;|`?<9 n /(Nx;| `J.g?<C n /(Nx;|`?<; n /(Nx;| `~J.g?<D n /(Nx;|`?<<NDd n/("h"i?) <Nφ n/("h"i?) N?< n"h/)"h/)N} n/( "n/)N˨ n"h"i$h5i "hR` n"h-i"npi f/(?<<Nφ`, nph W(Ag"n/)?<NT nph f"n n /(Nx;| `>J.g?<F n /(Nx;|`?<: n /(Nx;| N^ _PONNA?<HnNxHn/<N nB/. HnB'Nl-|?<0HnHnN}-|Bn?<HnNx/.N&=|?<HnNx n -h n1| 1n/)Nk`L n"hp+i W"h"irW"hpQWg/(?<N n/(Nk n/(Nj n"h-i"npi f/(?<<Nφ`, nph W(Ag"n/)?<N nph W"n$i$jrj Wg/)?<NP n/(N-     N/(Nx - T-@BBn?<HnNxBg n"h/)/(N} .S/ - ?N`N n!mH"h/)N|N^.NuASM_MPYASM_DIVASM_MODNA n-h "n$iJoB./)N n"h"ipi g@"hpn/(?<NN` n/(` n/(?<<Nφ n"h-i"n=i i`zpnfppnW.ApnWg n/(?<<Nφ` n/(?<<Nφ n"h-i"n=i ipnWrnWpnW.BpnW.Ag> n/(?<N"h"i0) R@?N.`| n/(Nl$ n"h?)"h"i?)?<"h"i?) NJ.gN` n/(Nl$ n"h"iJ)g - T-@BBn?<HnNx-|p n"h")DH-AȰn=@ .-@0.HRhS=|BgHn nB n/(/(?<N n1| "n#mD`: n/(?<N n/(/(?<N n1| "n#mH/. /NU n"h/)/Nf=_U n"h/)/NN=_0. 2.HЁ2;N6L*66LL"h/)N} .S/ - ?N n"h-i"h )D?"n?)?<?) N`2 n"h-i"h )D?"n?)?<)?) N n/( "n/)N˨ n"h"i$h5i "hpi f !mD` n!mHN^.NuNAJ-gBB n"h -i66LL66 n/(Nl$/. n/(N˨ n0( HЀC?1"h/)"h/)N} n"h/)N|N`pnf n/(Nl$ np h f0/. /(N˨Bg n"h/)"h/)N}`T n"n3| U?<Nň n1_Bh n"h pi f(/( HnHn<B'<"h /)N`( n/( HnHn<B'<"h /)N/.N&/.N&N8`B n-h "n-i$i&i0+ j m/)N n/(N` n/(N n/(N n"hp h fF"n;i 2/. /(N˨?<G n"h/)Hm&N} n"h/)N|N`/. n/(N˨Jng4 n0( HЀC?1"h/)"h/)N}`6 n;h 2"n0) HЀE?2$i/*Hm&N} n"h/)N|NZ`\/. n/(N"ipi fd"h"iBi "n/) /(N˨ n0( HЀC?1"h/)"h/)N} n"h/)N|`r n/(Nl$ n"h"iBi "n/) /(N˨ n0( HЀC?1"h/)"h/)N} n"h/)N|N^.NuNA-n n0( S@@2;˨`F np h fp/. /(N˨Jnf( n;h 2Bg"n$i/*Hm&N}`Bg n"h/)"h/)N} n"h/)N|`\ np h fN/(Nl$/. n/(N˨?<G n"h/)"h/)N} n"h/)N|Nf`h n/(Nl$/. n/(NN0&&&&&:Bn`~=|`t=|`j nJ"f =|`P np"_r"\g =|`, np"_r"\g =|`=|`N^ _PONNA-n nph Wr"_p"\@N^ _PONNA-n U n"h˨ n0( HЀCD?1"h/)"h/)N} n"h/)N|N np h f?<2/(NxN` n/(Nl$/. n/(N˨ n0( HЀC?1"h/)"h/)N} n"h/)N|Nv`x np h fTpnf /(Nl$Jng?</)/NJg< n"h-i"n )"D#@"p h f 1| ` n1| np h fLU"h/)/NJJg6 n"h-i"n )"D#@"1| -h!h!nN^ _PONNA-n n-h (Lf /N`t n0( H/HzlNJg /N`N n2 n"h/)Nx` n;h 2?<2Hm&NxN/. n/(N˨`N^ _PON0NA-n nY/(/<-HNT n Ѩ (!@pWrhWg RB nJWrhW0(l^@@H WgB(N^ _ NNA-nph f /N`6 n0( H/Hz4NJg /N` n"h$h0Qo/(Nx n/(Nl` n/(N\ n/(NP n"h-i"n=i =i i"h-i"n=i =i ipnfppnW.ApnWg/(?<<Nφ n-h-n /.NDd nJV(g"n"ipi f/.B'Ng././.N˨ n/(/(N n"n )ѨJ)g<|$i 1j$i j 0) HѨ$n/*&i //.N`&/./.N˨ n/( "n/)NN^ _NNA$ n-h (-      n"hJ)g"n($i$jpj g /)Nl$ n"h -i$"n$|$n(&j&k3kB3|&h3k &h&kk &hJ+g |&h3k&h3k` n$B(` n"hJ)gt=|"h=i=|Bg"n($i/*HnN} n("h/)N"n1i` nB( n0( H/ n?(Hh/Nb n0(H//.-HN n `|-n nJ(g$0( l^@@H-@"h$n&ji /. n?(Hh/N nJ(g=| n=h n=h=| n=h=h"n0)hl =|?<#Hn| n("h"i-Q,"h"iL?H? n("h"i", n("h"ipi g /(Nl$ n"h -i$"n($i$j&n$7j7||N^.NuASM_MPYNA/.Hn n/(Nd=|=n n =PJngv n pPf=|?<#HnNxpnfBgHnHnNNx n1| n"n0)hl =|?<#HnNx n1|BgHnHnN}?< n?(N n/./.-HN n -n"n$i V)g6pf Bh `$pf n1| ` n1| N^ _PONNA-n n-h"h/HnN"hpi f"n(/)B'Ng. n/( "n(/)N˨ n(/(/(N n(/(N~ n(/(NZ n("h"iJi f/(?<N n("h"ipi W"h"i)Ag/(?<N n(/(Nl$=|XU n"h"i"Q0)H/Nɸ=_@ n"h"i"Q-i}`?.?.?<?<N n pPf N` n 0`pg=|-npnW ^g=|?<#HnNx n 0pnf ?<1HnHnN} n 0`;|?<*HnHmvN}?<*HnHmvN}0.4ADBpN2N8Hz>Nx?<* n/(HnN} n"h3| "h3| "h3nN^.NuNA/.N=| BB| n h0(H"<\El-A;|?<*HnHmvN}Y?<*HnHmvN} n/(N| n h1| N^N`N^.NuNuNA-n n (Tf>pPW"hri Vg&Bn=|-|?<Hn/(N}N^.NuNAB. n ph\". DV np*h Vgn/.NDd n-h n-h/. HmHmNj-n nJ(gNphW(Ag-|.NuNA/.N/<HnNĄ=|=| BB| n h0(R@H"<\El-A?<*HnHnN}XX?<*HnHnN}Y?<5HnNx n/(N|N^.NuNA/. N=| BB| n h0(H"<\ElY-A n1| ?<*Hn`( np(2(@HC 1S-@`f n0( @2;N&JJ(g-|` -|`. nJ(g-|` -|` -| nJ(g .DS-@`B nph W nrh W n ( W.g B.`" .]"./.N}X nX?<*Hn/.N} nY n1| n /(N|N^ _PONNA;|Jm^2-4AtpVgSm`JmoH;|;|=|Rn=|Rn0.HЀ2.4BJAHЂAtD<FŰtv㫇 nm nmp^g|N^ _ NNAU/./. .NBJg/-/Hz<+O/.N/.Nl$ -ƐNvl ;|NJ -ƐNv o ;|NJ-n n-h=|=|"npi f ;|NJ nJh f/.?<NBJf n"h=i`FU?<Nň=_?</     /<-HNT n Ѩ (!@phg=|=h=hJg&=|-hBgHnHnN} nB=|U?<Nň=_ n=h?<*HnHnN}=|-|?<HnHnN}-|?<(HnHnN}-|?<HnHnN} nJ(/(N|` nph g ;|NJN^.NuNA/. NDd-n n-h"npi f$BgHnNx?<+HmNHnN}` n0( H/HmN nph WgU/. N\Jg n=h`zJ.f /. N> n/(N|BgHnNx n=h Jh fg0(hl*=h=|?<#HnNx n1|`0 n0(hl =|?<#HnNx n1|=| n=h=hBgHnHnN}?<?.N` n|1n1hN^.NuNA n-h nphfphfpnRQ/.N>?<&"n/)HnN}`?<+ n/(HnN} n1n `;|NJBn n1| 1nBh B(BB"N^ _\ONNA n1| /. NDd-n n-h nph fzJh f@/. B'NrBn n=h?<*Hn/.N}Bg n?(N`0/. N>?<*=| np-@?<Hn"n/)N} n/(N|=|U?<Nň=_Bn?<=HnNx?<2HnNx nBh ` nphW/(Hz-@N .-A n(g*pfR nB(Bh /.N>` nphWJW-@(g n/(/.N} n /(N|` nph f.?<*"n/)/.N}?< n?(N` nph f?<*"n/)/.N}` np h Wrh&Wph W(Jh Wp h Wg/. B'Nf``X nph f4/. N>?<* n/(/.N}B(1| `z=|U?<Nň=_ n (2(HЁr\(Ag* (l^Ѩ (rЁ!@Bn`< n0(HШr\(Ag=|`=|?<* n/(HnN} n/(N| nJ(g:?(?.?<(?<N np h n/(N|`?<. n/(/.N}N^ _PONNA/. N-n n"hpi f/. /.NS` n"hpi W"(LWgR"n3| ?<*/(/.N} nX?<* n/(/.N} nY n1| `?<* n/(/.N} n/(N|N^??.?<?<N`f n0(HШr ??.?<)?<NBg np h??< HnNF=|?<HnHnN} n| n1| `=|U?<Nň=_=|?<* n/(HnN} n/(N|=| n=h?<(HnHnN}?< n?(N _PONNA/.N-n n-h"npi f/.NRv` nph g"n$ipfR;|X=|Rn n0.H們/.N>?<* n/(HmvN} nm`V n"hJgH"n;i pi WJ"Wg?<HmvNx`?<* n/(HmvN nJ(g p h??.?<?<N` np h??.?<)?<N n|1| nJ(g1| 1nBh B(BB(N^.NuNA/.NDd-n n-h"nJ)g&Y/)/<-INT"n ѩpig=|-|=| n$h=j} n/(N| n1| N^.NuNA/.N-n n-h"hpif/.NQ`` nph gR"n/)N|?<HnNx n=h ?<*"n/)HnN} n1| 1nB(N^.NuNAd-nh nh"h"iJfL0( @2;N   "n B$h=j?<)HnHnN} nJ(g=|"n$i=j$i=j0(hl$=|?<#HnNx n1|`& n0(hl=|?<#HnNxBgHnHnN}?<?.N` n|1n1h nB( nph f/.NS`2 nph `$ n /.HnlN(?<HnlNx` nh/(B'N nh/(B'N?<HnNx nh"h"iJ)"gJh Vrh VgZ?<HnNx?<0HmHnN}Bn nh"h"i3| ?<*"h/)HnN}=|?<*HnHnN}?<KHnNx?<*HnHnN}Wrh V0( H/Hm-AN".g\/.N> nJh f?<5"n/)Nx`;|?<* n/(HmvN} n/(N|` nph W"n")LWgl/<HnNĄ=|?<* n/(HnN}X?<* n/(HnN}Y?<5HnNx nBn nh"h"i3| ?<*"h/)HnN}?<HnHnN}BHnB'HnlN(?< HnlNx nh"h-id"nd3| #|B"?<*HnHnN}HnN&?<NHnNxBHnB'HnlN(?<HnlNx`X?<0HmHnN}Bn?<* nh"h/)HnN/     rJ-gBJ.f n B nph f$/.Hn/. <.B'BNJ`n/.Hn/. <.B'BNJ.f&Hn/<N n"n !Q n n /.HnN(?<HnNx/.N&N8`D/.NDd?< n"h?)N n /.HnN(|0(HШr ?"n"i?)?<(?<N n|JV(g0.@2;N0`"n"iBi BgpD??<HnNF`X n h1| Bg n|pD??<HnNF`( n h1| Bg n|?(?< HnNF?<Hn n/(N}0.@2;N n|?<HnNx`b n/(NDd n"h"ipi V-g\/(N n"h"ip i f&=|B?<!Hn"h/)N}`?<N n"h/)Nx n"h/)N| n /.HnN(?<HnNx` n/(N n"h-i"n0) H/HmNBh ` n|1| ` n|1| ?<4 n/( n/(N}?< n h?(N n /(N|`/.N۪=|U?<Nň=_=|Bg n|p h??< HnNF?<*HnHnN}=| n|=hBn?<2HnNx=| n|p hH-@BgHnHnN}?<(}=|-|=|?<HnlHnN}`0=|=| nh"h"i-Q?<*HnlHnN}-m nh"h"i3| "h-id"nd3| Bi ?< "h/)"h/)N}B nhJh f"n /.HnlN(`HnB'HnlN(?<HnlNx=|-|?<JHnJf n/(N`@ n0( @2;N ` nR` nV n/(N>?<Hm n"h/)N} n"h/)N| n /.HnN(?<HnNx`/.N n"hp i f"=|B?<!Hn/(N}`?<N n/(Nx n/(NlHnN}Hn<HnlN(?<HnlNx nhph f("n /.HnlN(?<HnlNx`Z nh"h"iJ)"gFJh g>HnN&?<KHnNxBn?<HnHnN}?<?.N nhJh g HnN& nhJh Vrh Vg"n /.HnlN( nh0(| n /.HnN(?<HnNx`L nJf( n /.HnN(?<HnNx`J.f n P `N^ _ NNAt-n n-h|/.N n|phm Bn` n|phm =|`=| n h0( nl/.?.NB/. N n|p @2;N "4F`F?< HnlNx`4?< HnlNx`"?< HnlNx`?< HnlNxBg nh"h"i?)NBg nh"h"i?)N nh"h"i?)N nh"h"i?)N?<?.NN^ _ NNAJ.f/. /<N n PB-nh f/. B'N` /. N> n|phf6phW"nr*i Wgvpn RQ=| n|p-@"nJf?<Hn"n /)N}`?<Hn n /(N} n/(N|` n|phW/(Hz|-@xN .xg n hph f /.N( n n0( @2;NXXXXXXXXX^^^^^^^^^^^^^^^^^^^^^^^"h"i=ipnWrnWgD/.NDd?<N n/(Nx n /.HnN(?<HnNx`.pnf/./. .N`/.HnHnN|pfR n-ht nt0( @2;N ` ntR` ntV n|Bh ?<*"n/)"n/)N} n/(N| n/(N|` n|phWJWg"n"ipi f /.Nh n-ht nt0( @2;N/.?<NB`` ntT n֒ n /.HnN(J.g n0( @2;N 0\?<HnNx`?<HnNx`J.g?<HnNx`?< HnNx`J.g?<HnNx`?< HnNx`VJ.g?<HnNx`?< HnNx`*J.g?<HnNx`?<|1| ?<*"n/)"n/)N} n/(N| n/(N|` n|phfv/.N޼ n|pn RQ=| n|p-@?<Hn"n /)N} n| (l^Ѩ (rЁ!@Bn`& n| (2(HЁrmd (l^Ѩ (rЁ!@ HnNx` n0( @2;N 0\?<HnNx`?<HnNx`J.g?<HnNx`?< HnNx`J.g?<HnNx`?< HnNx`VJ.g?<HnNx`?< HnNx`*J.g?<HnNx`?< HnNx`pD??(?<HnNF n|Bh ?<Hn"n/)N}Bn` n|0(HШrmPpD??(?<HnNF n|1| ?<Hn"n/)N}=|`B n|?(?(?< HnNF n|1| ?<Hn"n/)N}=|/.N6/.?.NB n0     HnHnN} n|J(g0=|U?<Nň=_=|?<*HnHnN}?<3HnNx n h1| ?<Hn n /(N}?<?.N/.N/.?<NB n h1| ?<(Hn n/(N}?< n|?(N n|J(g&?<Hn"n/)N}?<?.N4Hn n/(N}?<?.N n/(N|N^ _PONNuNA nph g nB nB" nB( nph g nB nB" nB(p oJ o . Smn2;N0::::-n nph ?<4 n/( n /(N}?< n h?(N n /(N|N^ _PONNA n hphV n hrhVg/. /.N`-n n-h/. NJ nphW/(Hz-@N .g/. /.N`X nphWrWg/. /.Ng1| BB(B"-n nph gBB(1| B" n1| ?<*/./.N}B nT nT`p fN-n nph g1| BB(B"-n nph gB1| B(B" n1| ?<*/./.N}U nX nX`0?..`. nph f/. B'N` /. N> n (2(HЁrm* (l^Ѩ (rЁ!@Bn`0 n0(HШrm=|`=|/.NF-n n-h"npi f/.B'Nb` /.N> n h"n0)h])@=| HnN-n nph g1| BB(B"-n nph g1| BB(B" n1| =|?<//.HnN}?</Hn/.N} n . Ѩ n . ѨB `zp ]. Ag =| ` . lR=@0.H】 J fN-n nphU?<Nň=_ n (2(HЁr\JnW.Bg* (l^Ѩ (rЁ!@Bn`F n0(HШr\rn\.Bg=|`=|?<* n/(HnN} n/(N| n1n 0.@2;NFphg4p g1| BB(B"-n nph g1| BB(B" n1| =|?.. HnN?<//.HnN}?</Hn/.N} n0.HѨ n0.HѨ`p. r @=A0.H】 ?.. HnN=|?<//.HnN} n1| ?</Hn/.D??(?<HnNF?<Hn n/(N}`v nphg4pD??(?<HnNF?<Hn n/(N}`2 n?(?(?< HnNF?<Hn n/(N} n0(HШ"n"i$n$j2)HҪ=A"n"i0)h]"n"i)g"n-iN} n0.HѨ n0.HѨ`p`N8 n1| n1| ?<5/.Nx?<5/.Nx;|=| . -@J.gR?<*HnHmvN}Hz*Nx n .Ѩ n .ѨN^ _N ASM_MOVELNA nJg-h"npi$oRB0)$@0.@2;N."npD=@` npD=@` n=hJnlPn`p n nH=@pnm Bn`pnm =|`=|?.?.?<(?.N n0(HШ2.H"n "iҩ"n "i0)HҀ=A?.?.?<?.N n0.2;N=| `=| `=| n"hL &H -n `@=| n . Ш-@B.phf=|-m` =|B=|?.HnNxHnN|`J f n/(Nd`  o8 n/(Nd=|-n ;|2?<HnHm&N}`h`FJno?.?.?<(?.N`$Jnl0.D@??.?<)?.N n h"n0)ho, n h=h n h0.H"(=A`| n h"n0)hl=i=i`T nphWJnWg Bn`4 nphWrnWg Bn` n=hN n/(B'Ng. n"h-i"n3| #n B)?<5$h/*Nx nB n"h/)N|N^ _ NNAhJg-nl/< nlHh NJgd nl0(Q@mN|nF@2;NL:hJ-g4?<N .X//N - T-@pBxBn?<HntNx;|=hJng0.@2;N&FpnD@??.?<HnN`8pnD@??.?<HnN`?.?.?< HnN=n?<HnHnN} n1n JnWrhWg?<*Hn"n/)N}`LpnW nrhWg?<*Hn"n/)N}`?<?<5/./NJn f nlJf4?<HmvNx=|-|?<*HnHmvN}`?<5 .м//Nj nl"hpf>=| .df-|` -|?<*HnHmvN}`&=| nl"h-Q?<*HnHmvN}Hz(Nx` ;|?<HmvNxHz0     U?<Nň=_=| n h h (T-@?<*HnHnN}=|?<#HnNx`*LH=| n h h (X-@;|?<*HnHmvN}?<?.N?<*HnHmvN}pnf?<?.NHn`N|N N8HzNxNݎ-n * n*1|-h n .Ѩ n-h n .ѨJ.gN n h1| ?<* n/( n/(N} n-h nT n-h nT`8B'NØ n-h nph W2(H/Hzp-@N . nrh V(gtBn"n"ipi W"n"iJiWg =| 1| |` n hpfb=|U?<Nň=_=| n h h (T-@?<HnNxBn?<*HnHnN}=|`*LH=| n h h (T-@?<1HnHnN}pnf?<?.N n L?H? n 1| Hn`N| nJ(`Bn?<& n/(HnN} n-h n1| BB(1nB" n-h nph W2(H/Hz-@N . nrh V(gvBn"n"ipi W"n"iriWg Bn`=|?<& n/(HnN} n-h n1| BB(1nNxJg nph$f-nh=| nh .Ш-@B.phf=|-m` =|BBgHntNx?<&HnHntN}=|-|xB.B+|;|+m6?<*HmHntN}Bn?<*HntHmN}Bg?.|NBJ-g .pS/ - p?Ng n ph gH=|U?<Nň=_=|?<*/. HnN}/. N| n L?H?=|-|BgHn/. N}-|?<)Hn/. N}N^ _ NASM_MPYNA nJg.-h nJg n-P` n n+hN^.NuNA-n n0( H/Hz` nlJg/(HnHnNj nlJg"h-Q.gR .^JWg6/<HntNĄ/.HntNhv=|~LtH`Jg n hL?H?p".-Ahhn`-@JgLHt nCt!I/./././.N .П/N-@ n2( H/Hz-@N .g np h fU/./(N_`dU/. n/(NJg |`@U/. n/(NJg"| n-h!h!n`B.`B.N^ _ N 0NA . lR-@/.N/.N nl/(?. /.NZ .Rh` nl-hJW"nJVg6/<HntNĄ/.HntNhv=|~LtH`Jg n hL?H?JgZ-nhJgLHt nCt!I/./. nh .Ш//( ?. /.N n-h`` ;|NJN^ _ n h0( H/HzN n h(g/.B'Ng. n h0( H/HzN n h(g/.B'Ng.pWrWgpf n h1| ` n h1| ?<* n/( n/(N}.g: n-h n (Ю S!@ n-h nN FS_FINITB FS_FCLOSENA*=|U?<Nň=_ n h S2;N$Bn`=|` =|`=|U n h h0(H/Nɸ=_h n h h-hdB.nBJnf=|?<HnNxBn?<*Hn`HnN} n/(Hn0Hn4Nj/-/Hz, (Ю S!@`JoBn=|Rn=|Rn0.2.4ҀAJpW2.H]gRRnJnf ?.N0.HЀ2.4BJAHЂtD<FŶtv㫇`80.HЀ2.4BJAHЂtD<FŶtv㫇 nm< nm(0.+O .04 \@/+o N,_+_pmf |/`NJL`H8 n h P-h`U n"h/)NbJg n/(/(N`ZJ-g"NA/. NU n h/(NbJg |`B. np'h f/.NB'NØJ.g8U n h/(NbJgHzbNx` HzdNx`4U n h/(NbJgHzLNx` HzNNx` ;|NJN^ _ NASM_SSUBTOSSUBASM_PSUBTOSSUBASM n/(NDd n/(NDd` n/(NDd n/(NDd n"h"ipiW"hJQWg/(N n"h"i3| U"h/)?<N`Jg ?<*HmN n"h/)N}` n/("h/)Nhv n"h-i"nX$h-j$npjl0*H/&h_SSUBTOPSUBASM_PSUBTOPSUBNA/.NDd-n n-h"nJ)g $n B`< n"hpif "n B` nJh W(A"n0) H/Hz-AN".g n B` n"hJiW"(DV"hpiW-g "n B`-n/.N n/(/+Nb`?< n"h/)Nx nY"n$i/*N|`U n"h/)NbXJg$ n/(/("h"i//.Nb` n"h"ipi f8/(N n/("h/)NS n"h/)N|` n"h"ipif/(/(/.N@`\ n"h"iN n"hp*i f$/("n"i?) "n"i)Nφ n h"n$i$j0* h o n B`( n/("n"i?) NB n"hp*i f0( H/HzNJgp n"h"iJ"gX0( | @2;N Bg"h/)"n/)N}` ?<G n"h/)pi f2/(/(Y"h"i/"h"i/N*/.N` n/(/(/.NhN^ _PON ASM_ASSIGNASM_XSETASSIGNNA n -n n/(NDd n/(NDd nph"W"h$h"*^ph"W"h$h$*]g"n B n Jgv n"h-i"n/)N}ND`r n0( |@2;N4"h"ip"f?<*"h/)"n/)N}`( n"h"iJ"f?<"n/)Nx` n/(Nl$ n0( | @2;N,NpBg"h/)"n/)N}`h?<G n"h/)"n/)N}`F?<"h"i0("H"/("n?) )Nφ n/("n?) )Nφ n/(/(/.N^-m =|-| nph"f?<Hn"h/)N}`?<JHn n"h/)N}B'NØ n/($"n/)N?<! n"h/)"h/)N}Hn<HnN( n4 n"h/)"n/)N}`$?< n"h/)"n/)N}` n0( H/HzNNJgND n"h/)N| n/(N| n N^ _N   NA=|-n ;|?<*HnHmvN}N^ _PONNA=|0. H-@;|?<*HnHmvNJ(g4"npi"f?<HnNx`?<HnNx`0 nph"f?< HnNx`?< HnNxN^ _ NNA-n n/(NDdB. n"hp*i W"hr*i Wg/. Hn/.NJ.f n"h-i/(N n"hp*i f/("n?)1     N}`?<JHn n"h/)N}Hn<HnN( nJ(f?< HnNx`?<HnNxHnN&B'NØN^ _PONNA-n nJf?<"n/)N2`Z n"hp*i V"h)A-g/(/-P<N\ n/(?<NB n/(N2;N\jjjjjjjjjjjj j CXEGSb$n$R<HQHR-ITN"nTHQNx`HzNx`B'NØ`l-n T nT/(Nd/< nT"h"i"iHi N_J.g*/<HnlNĄ=|x?<*Hm&HnlN} nT"P/)NkJ-(gHzkN^ _PONNAU n /(NbJg/. Nd`Y/< n h/N* n 1@\0(\R@H/HhlNĄ nC-I"n3| 0(\H#@"Bhx?<*HhHhlN}?<5 nHhlNx/. Nd nRp?<5HhlNx;|?<* nHhHmvN}B'NØHzBNxNNx` HzNxB'NØJ.gLlH=|v nT"hEl#J/(B'Ng. nT"h"i3| /(HnNhv=| nT"hE#JB/(B"h"i/)Bg"n/)NB'NØ`2-n T nT/(N/< nT"h"i"iHi N_J.g2/<Hn )Nφ n/(Nl$ n/(N n"hp*i f/("n?) )Nφ n"n$i$j0* h l/)?( NB n"h"ipi W"h"i)Ag/(?<NB n"h"i$h$j0* i l/("h"i?) NB n"h"ipi W"h nSp?<5HhlNx?<5 nHhlNxHzNxN^ _PON ASM_MOVEL ASM_STRRTRIMNAH-nX nXphf"n"i&/)/. B'N`b nXphfr/(/. N nXphl;|0(H/HmvNbU/.BgN`Jf/.HnlNf?<%HnlNxB'N"i)Ag/(?<NB n"h"i$h$j0* i l/("h"i?) NB n"hp*i g"h"i=i 0.@2;N./<HnNĄ`&/<HnNĄ`/<HnNĄ?<* n"h/)HnN} n"h"ipi g4"h-i"nØ` nX0(|m̰|Fn@2;NVr,hhhhdf"n -i"n "Q-i/.N/.NDdJ-g n h0($H-@^|3| B)B)Bi #n3n#n"BJ-g"U n/("h/)<NZpU n/("h/)<NZpg n"hp*i f ?<!"h/)"h/)N}`?<Hn n"h/)N}Hn/<N nB/.B'HnN( n"h"iJ)g0ph"f n (hf n-hT nTBh Bh B(X np*h f/.Bg<Nφ n hJh o/. n h?( NB/.Nl$ n hJh W n h(g-|pBnx?<HnlNx?< n/( n/(N} nB`x n hph gb=|-n^-nT n?<HnNx`?<HnNx`0 nph"f?< HnNx`?< HnNx n"h/)HnHnNj ^ n"h"iri WJWg?<N"h/)Nx n"h"i=i /("h/)<N\ n"h"i3n JW"h"iri W"hT-hP"nPpi f;i 2?<!HnlHm&N}`?<!Hnl nT/(N}`B.J.g2-|pBnx?< HnlNx-|?<LHnlNx/.N n hBh /.BgNB?<* n/( n/(N} n/(N| n/(N|` n /(Nd n -PT nT/("ipi Wg?<N"h/)Nx n/("h/)<N\ n"h"i3n -m n"hp*i f ?<!"h/)"h/)N}`?<Hn n"h/)N}HnB'HnN( n"h"iJ)g0ph"f?<HnNx`?<HnNx`0 nph"f?<NB nT/(NkHzBNB'NØ` n /(NdHz(NB'NØ`-n T nT/(Nd nT"P/)/NHzfNB'NØ`\-n T nT/(Nd nT"P/)?<NB nT"P/)Nk nT"P"Q/)?<NB nT"P"Q/)NkHzNxB'NØ?< HnNx`?< HnNxmB- n/(/(/.NznB'NØ n/($"n/)NU?<Nň=_ n"h"i0.if?<?.N n"h"i$n0* i l/("h"i?) NB n/(Nl$=|-| nph"f?<Hn"h/)` nX/(/. N nXpNh_rRh\pGhWrHhWgZ0(|G@2;N&BBBBB&BB4Hz@Nx`Hz>Nx`Hz`Nx`` nXp=hWr>hWg>CXEHGSb$n$R<HQHR-ITN"nTHQN` nX0(|F@2     lNĄ=|x?<* nT"h/)HnlN}J-(g6 nT/(Nd nT"P/)NkHzNxB'NØ`*?< nT"h/)Nx nT"h/)N|J.gD=|v nT"hEl#JB/(B"h"i/)?<"n/)N͠B'NØ` n /(NJ-(g& n /(NdHz n h h/ n/(NĄ n h1nj nT/("n/)Nj2/.Nd` nT/(Nd` nT/(NDd nP"hiJ.g*U/(N< nP"h0i V@` nP"h0.ji V.@..gN Hn/<N nT"h$nLHrNxB'NØ`.+|+m6?<*Hm n h/(N}B` n /(NJ-(g& n /(NkHzNxB'NØ`4+|;|+m6?<* n h/(HmN}B`6 n -h nXphWrhWp'hW@0(H/HzN_J.5i/.N.@.gB n h h/ n/(NĄ n h1nj n1|$ nB`6 nP"h/"n/)NĄU nP/(N< n h1_ /.Nd`..g nT/(N``J-gU nT/(/.<NZpJgT| nT/(B'Ng.NgA4CSb`ACSb n (dW nXrhWphW@J.f,CESbU"n"i/)N<=_j nXphf/.N`` /.Nd n -P nXphWrhWgX;|?<*Hm&HmvN} n/(?<NB n ;| nP"hBi ?<*/(HmvN} nP"h3| ` nT/(Nd` nT/(NdJ.gJ.g nP"h?)/.NZ..g.=| Bp nP-h/(N?<5HnlNxJ.gL nP (PfC FESb`& nP (TfC &E/(NkHzPNB'NØ n-P` nXphWrhWgz-nTU"nT/)$Q/*NJf> nT/(?<NB nT"P/)B'Ng. nT/("P"i/)Nj2 nT"P/)Nd nT"P-QJg 6-nT nT-hPB.J.f$"nP-i$ipjf $i#jSb` nP (LfC ESb`J.gA CSb`J.gA CSb`J.gA CSb`J.g@ nP"hpi fC ESb`A DCSb`: nP (HfC RESb`A C;|J.g?<*Hm&HmvN}`@J.gJ.f n-P`$ n P-P nP (Lf "n-QJg nXphVrhVg?<*Hm&HmvN}``L&H-|;|?<*HnHmvN};|-|?<*HnHmvN}?<*HnHmvN}`h nSb nXphWrhWg>CPEGSb<HQHn-ILN"nLACSb nP (LW.gRCPEGSb<HQHn-ILN"nLNLN^ _PON256 entriescase table contains more than 2most case table entries address the same statementNA n -h n0-(hW"n"i$i*8gzB3     N nHnd"n0)H/-H`NP n`/. /N`0/. /N/N`/. /N`` ;|NJ+n. n-P `.N^ _PONP_Listing abortedNA n+h n?(N` nB nph WrhVphVrh W(g0(4CrqVU"n/)-@N\ .gt n0(4CC-I"n3|2#|$n&jLH Hi /N n"n#h$n/*Hi Nhv`P n"hL-m+m.2"n;i0)R@;@pif i8`B- n"h )VD@"h )VDr;AN^.NuNAr n"h"i piWU"h/) -@vNb .vg n-hrUBgNň=_UBgNň=_U?<Nň=_ nr+h&Bn=n=|?<+HmHn?H?Hn/NH n/(HnNhv n"hL?H? n/(N|` n/(N| n/("n/)N n0(4CC-I"npif$n )f3|N^ _PONNA0-&AHJVJm^g$;|?<*HmHmvN}HzNx-N}=|=|=n nr"h pif =|`Bn=n?<*HnHnzN}J-g nr"h pif*=|"h U-@?<HnHnzN}`j nr"h i$gX=|"h 0)$H-@?<!HnHnzN}-|~Bn?< HnzNx-|?<LHnzNx nr+h5gS2J-g?<6Nw`0?<OHmNxJmo n h-hpm]rA"nHҩ$-Apif$i pjnXJVrVgBnBn=|?<+HmNHnN}=|-n l ;| `;| BgHnHmN}=|BB.BnBn=n=|?<&HmHnN}=|=n=| nr"h pif =|`Bn?<*HnzHnN}=|=n nr"h pif =|`Bn?<*HnzHnN}=| nr"h pif-|` -|=|=n nr"h pif =|`Bn3     -pJg.-n/.BB n/( Bg/.N@ n-h`/N N^.NuHPM_HESTABLISHNA/N<NØ/NBVBRBZBNBB0-,HH+@/. /NZNJV-&-'g Hm.NN^ _PONNA<x/. ?<NU/. nHhnHnHnHnF-_-n n1| 0!n"n !Q n |N^ _PONNA . DW". HW .DW$.HW„BN^ _PONNAB.-n np*h WU/.-@NbX .g nJ("g n (PWU/(-@NbX .g n (Pf-|N_J.gHm?</. HzN n!mHmHz|N nJgRpf?<N.;|NJ`. np g?<?(N$;|NJ`B.`|`B.N^ _PONPURGENARHm/<NHm/<NHm/<NHm/<N` n"h0) H-@ n0($HmV|U n/(NbJf: nHhHh/.Nd n"h|" .R"h""h2`U n/(NeLJg n h-h n (PfHhHh/.Nd|`hU n/(NbXJgR n"hpQfB"h0)?<JHnzHnN}-|~ nr"h pif =|`Bn?< HnzNxBg?.N?<?.NBg?.N` n"h"i pif>"h/) Hnz/(Npng<=|U?<Nň=_=|?<*HnzHnN}LHz=|-|BgHnHnzN}BNUHm^Hn\HnHnHnN_AC\ESb> nZC SbB-N^Nun:EXEC.CODE") ? OVERLAYADDRESSOutput file (default is "Invalid file name. File ? Jf HmB/-n n-PJ(g ?<N. np hf -h`B` ?<N. n hHh/.HnN n-h"n3|* BQ#mD|#nN^.NuDNA n-h N3pmfN3|`*B. np)hVr(hVg ?<p%h ft-h"nJgb$iU/)-JNbX$n@* n"h-A)$g""n "Qpi$W-f ?<N. n"hpif "h!i n Pph$W m,rPVg ?<N.N^ _PONDNA n0C22U@bYN-_ n N3HmNHnN8`\nN^.NuNAYN+_,-m, nBP1|* LH0-|"@2;N!mD`< n!mL`.pf n!mP`Y?-Nc0 n!_N3N^NuNAYN+_,-m, n1|* BP"n!i "nLHC-I"nJf,HnHnHz*NHnN^?<~N.` nphf/./N`-n nph$Wrh$Wph$Wg|HnHnHzNHnN^ m,p$h W-g*/< m, hHhNJg ?<N.B-Hn/N n-h n!m,pmfJf$i0mа|n@2;NNHi/<N n-h"nC-I"n$n&i4&iL H `p n-h nHh"n0<i 2< @RAlRAAH/N n"h2"n$h5i Hi $hHj 0) H/N`N3N^.NuNAYNP+_,-m,YN| n n-PpmgJg ?<~N.N^ _ NDDNA n0C22U@bpmfN3mlB-lHnHnHzNHnHnHnN@|nlJ f?<N.` n Jg*U n h/( /.NhJf ?<oN. n -hJgF-n n1|$ 0"n!i !nN3N^.NuNAYN+_,-m, n1|) 0"n!i !n0-CH!qN3N^.NuNA n-h"n3|+ 2#mD$h#j YHjN-_pmf N3` ?<N.p(mffp mfYBN n!_ n .\"._g"n"-h ` ` n-h` n"n B ` N^ _ NDNA n 0C22U@b-m,N3HnHnHzNHnN^ n-hYN-_-n n1|% "n0!n!m,Jg"npiV"nriVg`>p mfY/<N n!_`YBN n!_?<}N.N3`YBN n!_?<}N.Y n hHhN~-_pmf N3` ?<N.Y n hHhB'N-_ n"h""n""n"N^.NuNA n-h"n3|+ 2$h#j #mX?<N. nB` n"n#hU n/( i/(NhJf ?<N. n"hp*i fU/.NbJg( n0($H-@-@r-A` n/(HnHnNj n"h )]"h")^g ?<.N.+n,pmgpmf N3` YHjB'Nl n!_"h-i"nJQWJVg0$ipjf?<}N.` -R/HzHNLpmg n"hB`$N3Y n hHhN n"h"N^.NuB'ADDR' of a constant may not be supported on other implementationsNA n-h"n3|+ 2?< N.N^ _PON@NA n 0C22U@bN3Jmg,?<N.HnHnHmNHnN8` m,-hJg np hg?<N.`n n/(HnNWYN-_-n n1|( "m,0!m,!nJfB?<N.` n"n#h +n#mD$h#j YHjBgNh-_ n!npmf N3` ?<N.Y n hHh"h p/iWN n n-Ppmf N3` ?<N.Y n hHhN n n-PpmgY/ n ` N3Y n hHhN n N^.Nu5      N. n0(H/Hz NJg"Hn nHhHz NHnN^YN-_ n0(m >|6n 6@2;NnnVvvR 6 6 6 * * * * * * * * * * * * * * * * * * * * n n * * * * * * * * *-m,"nJgU/)N۾Jf ?<}p jf )RNv-@` n (SNv-@|+o N",_+_pmf?<-N.`NJ-n m,"n#hJ.gH3|* BQA-H n!n .]".^g ?</N.`6 n0"np if 1| ` n1| n!m,`/NN.-n m,"n#hB. m,p*h f nJhf3|* BQ|E-J )DfV/-/Hz.+O$n&m, +lDNv%@+o N,_+_pmf ?<-N.` n (Lf^J-lf ?<2N. nBHh/<N n"hBQ"m,"i/)/) `/N`/Nr`/N`-n n1|+ 0!mD"n!i $np$jf2?<N.J.gY nHh?<N n!_`Y nHh?<N n!_`-n n1|+ 0!mD"n!i YHiNܠ n!_B."h-i"np*i W)Ag6JWlW"hLH ` nB"nB` m,J(gz/-/HzP+O m,/(/N-_| n1|* BPC-I"n#n+o N",_+_pmf?<-N.`NJJ.f2 n0!m,"npif 1|" ` n1| `-m, nJ-i$npRf$j Hj Hn0* H/N|J.g/-/Hzz+O n0(| @2;N*HnN-_`"HnN-_`HnN-_ n1|* BP|!n+o N,_+_J-lg ?<2N.`-n n1|+ 0!mT"n!i J.V"(DV (HVg ?<}N.-n n1| 0!mP!m,"m,p*i fj"m,C-I"nJf?<}N.`F nJ] ^g?<}N.` n1|* BP"m,LH`-m, nJV"(DV (HVg ?<}N.-n ngH$np)jfYHi?<Nd n!_`Y nHh?<NF n!_`HYN2 n!_J n/(/( NLH` n/(/( NLH+o NN,_+_pmWrmWpm\tm_g?<2N.LzH`NJ n1|* BPB("h!i"hLH n"hBQ`?<}N.-n nphf"n3|# ` n1|! n0!mD!m,`T-m,-|-| nJg^-h"npil?<}N.`< nphf/(HnHnNj` n/(HnHnNjB. np*h fC-I"nJgr/-/HzH+O$nJg ?<~N.+n, m,p+h f m,-h`B m,Bh Jg6 m,"n"i0) h o n h"m,3h n-P` nphf\YN-_ m,"n" m,!nYN̖ n!_ n-h n01|$ "n!i&$m,!jN^ _PON ;STRPO5     NJg 0.H2.HҀR n!A ` 0.S@h n!n+n,N^ _PON@@NAYN+_,-m, n1|$ B0!nN^.NuNA n 0C22U@bJ-g ?<^N.Jf2HnHnHzNHnN8pmfN3`^ nphf-@N .gn n0( @2;N "0>L1| `B nBh `6 n1| `( n1| ` n1| ` n1| `YN-_-n n!mT"m,p*i g 01| !m,"h1i `BJ-lf ?<2N. nBP1|* C-I"n$m, *SlHn/.N4`@?<N.HnHnHz8NHnN8pmfN3/-.NN^ _PONNAYN+_,-m, n1|$ 0"n!i !n-n"npif?<gN.`4 nphg?<N.` nJ(-f ?<N. nphf n|D#@+n,N^ _PONNA n 0C22U@b0-H/HmNJfJ?<:N.HnHnHmNHnN80-H/HmNJf YN+_,0-H/HmNJgmJmgB-0-@2;Nd$$$$$$$$$$$$$p$$$$$$$$$$$S does not conform to HP standard, see $SWITCH_STRPOS$NA n 0C22U@bN3JW@J.gTHn/<N-n n1|BB(B( 1|B!|Hh HmNYN|-_-n n1|, 0!nB(BBBB=|/.NHnN܌`*/.Npmf ?<N.HnNd`N^ _PONNA-n nphg?<N.`" nphfJ(8g ?<N.Hn/<N m, (lм=@ n-h .lм=@ .=@0.ҰnodRnHn/<&N-n nBHhHzNJg n -n`-n-n0.ΰnf`0-np2.SA=Ann=@ n-P0.R@h=n0.Ұnf m, (=@-n nB(B( 1|Hh HmN n "n#h n phf 3|` n1|YN+_,-m, nBP1|$ !n!n N3N^ _PONNA n0C22U@bJmg?<N.`/:HnNX n0(@2;Nx^0N3pm`=|0.=nnnH=@ nHhHn nHhHnHz0.H/NNHnN0.R@h0.HЮ2.HR-@ m, .İm|`bJ.g/./< N n-P` nHh/< N n-h-n nB!n!m,|pmVfHn n/( N`DpmfHn n/( NHnN`?<N.HnN8/.N`/.NXHnNږ`/.NvHnNڂ`/.NݢHnNn` np h$W-g:YN+_,-m, n01|$ "n!i&!nN3`. np h$g ?<gN./.@J.fN3J.gpmf N3` ?< N.J.g n0` nBP nHh/<N n-h n0B Jg-nBn nJg n-PRn`0.R@HS-@ n .İo n-h .=@0. @mH=@0.H/ nHhHnNHnN`:J-g/./N`/.HnNHnN` /./Nb-m, nJg&"hpiW-Ag "h!iN^.NuNA n 0C22U@bN3Hn n/(N>-m, nJV"(TVg ?<N. npPW2( H/Hz6     $$$$$$$LLLmB-Nn`HnNd`mB-HnBNn`Hn/N0`N3HnHnHzNHnN^J,V m,rPWg m,0 m, (LW-lAg ?<N.pmf N3` ?<N.`0-H/HnNH?<-N.`NJ n1|* BP1| C-I"h$n%i"jLH n"hBQB`$ n"hp*i W.gD0( |m4|n,@2;N     "hJ)g4"hJf +h,` n"hpf+h,` n"h"iJQW/:/:"h"iJf(?<N.HnHnHmNHnN8`dN^ _PONNA n B nA-H nJg:BR .A"n")f n mN^ _ NNA-m,| n"h$h0* i 1@ "h-i"h-iJWJWg B` HnHz /)/) -@N .g n+h,`H n"h"iJQW/:^/:V"h"i/)/) -@N .g n+h,`D n"hJ)g0"hJf +h,` n"hpf+h,`` n"hp*i W.g0( |m|n@2;N P"hHnHz n0(H/N/ n0(H/NNHnHz NNJg?<N.`d n0(@2;N ""npifR"n3| U/./.NhJg$ n"n )o n!n` ?<N.`U/.NU/.Ngn .g^U/./.J)g4"hJf +h,` n"hpf+h,` n"h"iJQW/:F/:>"h"i/)/) -@N .g n+h,`H n"h"iJQW/:/:"h"i/)/) -@N .g n+h,` n"hJ)g"hpf+h,`H n"h"iNJg n1| "h#n` .DV".HV .DV$.HVg?<N. n!mD n"hp*i f"hJf?<,N.` nph W"hr*i Vg4/(Hn/NJg n1| .D"h#@`6 nph f("hJl?<YN@-_=m-n0-@2;N 4& n1| `( n1| ` n1| ` n1| m,"n#h2#m,N3HnHnHz n0(W@m||nt@2;N<hZ,hLL n0( H/HzhNJf ?<N.`. n0( H/HzBNJgv n"hJQW"hJQWgX=h 1|* BP|"h$h *fJnWrg +h,`" n"hJW"h)g+h,``l n"hp*i W.gT0( | mH|n@@2;Nz4444"hJ)g"hJf+h,`H n"h"iJQW/:/:"h"i/)/) -@N .g n+h,` n"hJ)g"hJ!A`pnW nr!A` ?<N.` n0( U@mB|n:@2;N  1| ` n1| `?<N.``>U/.NbXJf ?<N.`?<N.`?<N.` n"hp*i W"hr*i Wg"h$h)*gJ-lf ?<f+h,`H n"h"iJQW/:/:"h"i/)/) -@N .g n+h,`L n"hpW"h)g +h,`" n"hJW"h)g+h,`N^.Nu0NA n 0C22U@bB.p'mfd0-H/HzHNJgL|pm2N. n"h-i"h-i=h 1|* BP1| C-I"n0.@2;N &Db .]r#A` ._ nr!A`v .^ nr!A`X .\ nr!A`: .W nr!A` .V n7     HnHnHzNHn/Np(mf-l@-g ?<^N.YN-_-n0-Q@@2;N*8FT` n1| `P n1| `B n1| `4 n1| `& n1| ` nBh ` n1| n0!mT!m,N3Hn/N n!m,+n,pmf N3` ?<N.Y nHhNj n n-PpmgY/ nHh"nHQ$n/*N~pmf N3` ?<N.` nJg ?<~N.N^ _\ONDNAY nHhp8hWN-_ n h"h#npmf N3` ?<N. np8hf"i!iJgf"hpig?<}N. nB`B n"hJ)f?<N.`$ n"hJ)"g?<}N. nBN^ _\ONNAY n hHh. N n!_YN-_-n n1|% "n$i!j$i%n$h0B$h#jJg8$ipjg?<YHhN n `Y nHh<NR n n-Ppmf N3` ?<N. np8hfYHhN n `Y nHhN n N^.NuNAY nHhN-_ n h"h#npmf N3` ?<N.Y nHhp-hWN n n-P}N. nB` n"h$n%ipmf N3` ?<N.Hn n hHhHzNHnN n!m,"nJgfU$i/*$m,/*NhJf?<N. nB`2 n"hp*i f "hJ)f?<.N. nBN^ _\ONDNA np*hf7     }N.pmg?<N.`8N3Y nHhNb n n-P nphW@` nphWrhWg?<}N.`\ m, (dV n2(H/Hz-@N .g?<N.` m, hJf ?<}N.pmW@J.g*N3Hn nHz@NHnN`LB-Jg nBN^.Nu@ ddddNA-m,U n/(NbXJfH n (PW. r*h WgHhHh/<Nd` ?<}N.`< n"hJ)"f,"h/)HnHnNjpg ?<}HhHz2NHnN`( n0(H/Hz2NJf ?<N.`| nphWrhWg6J-n n0Hf||f ?<N.N^.Nu`@ @ ```NAY?<B'NԼ n!_N3 n-h"nHiHnHnHhHzNHnNhp mfh -R n!@J-g|N3 nHhN n!m,-m,"nJV")TVg ?<"n#n` n-h`Jn^.AgSn0.AF00H/HzNJf0.AL-p0.AFrpgRJV.Ag>-n n0Hf| |"n#n` n-h`JnW.2.AFtpWN.` ?<5N.N^.Nu NAY?< <N n!_N3 n-hHnHhHzNHnN҈ n!m,-m,"nJV")TVg ?<N.pmf N3` ?<6N.Y nHhN n!_N^.NuNAY?<<N, n!_N3 n-hg0J.f ?<N.N3N^.NuNAY?<B'N n!_N3 n"hHiHnHnHhHz4NHnN܎p mf N3` ?< N.N^.Nu@NAY?<<Nh n!_N3 n-hHnHhHzNHnN n!m,-m,"nJV")Jmg4?<N.Hn nHhHz&NHnN8B`/:HnNXYNF n!_-n-h"n3|$ $n#j 2#npj$V2*m(Vg ?<N. nJgj"hpil?<N.`N/< nHhNJg?<N.`& nHhTVg ?<N.p mf N3` ?<4N.YHn nHhHzXNHnN n!_p mf$N3Y nHhN n!_` nBN^.NuNA n h-h"nJf#n #n $n B` n -h B n-hJg, n ( HnHhHz$NHnNN3pmg0?<3N.Hn nHhHzNHnN8`N3Hn nHhHzNHnNn n!m,U"h/)"h/)NhJf?<N.`& n"hp*i f"h/)/(N0-H/HzdNJf0?<7N.Hn n8     N` /./NΒ`/N`Rm/N|Sm`xRm/NSm`f/N`\Rm/NHSm`JRm/NSm`8Rm/NSm`&Rm/NSm`Rm/NSm`0-H/Hz\NJf?<N.HnN8`Y?< B'N4-_ n!n -n N^.NuNX n-h -n n-h!nJg8Hh HnHmHn"nHi HzNHnNHnN nJVJVg"h.)@J.g\"h=i0.nr @l B.`:pnl =|`&pnl =|`pnf=|J.g n|d @NA0.n o =n`=n N^ _PONNA n 0C22U@b-m/-NJgz/-/ n PHP??Rm&0-&CBC-I"nB3|BBB B` ?<N.pnf"HnHzT nHhHhB'BN`HnHnNJf(?<N.HnHnHzNHnN8pmV@J.fN3J.gpmfN3JmfJ/:NHnHnHnN@| .DfJ_ ^g?<N.-|Hn/<&N mh"nL?H?3h$$-n n1n$Hh "nHiN .R n ` ?<N.pmf N3` ?< N9     N3Jmf n hJ(gHn/<"N`Hn/< N-n nBB 1|BB(HhHnNB.B-/:HnNX|N3JWrmWg| n|Jg "h#n n!n"h Jf "h "/.HmNd/.N\PpmNd nB B1|B(Hh"nHiN n Jf n Jg n!n-nJf-n/.N\PN3` ?<N.0-H/HzzNJf(?<N.HnHnHzlNHnN8pmV@J.fN3J.gpmf N3` ?<f N3` ?<N.Jmf/:HnNXN3`,?<N.Hn nHhHzNHnN8Jg n-h `BJgF nphm. n!n n!nJ.g/./.N` ?<nN.`,?<N.Hn nHhHzVNHnN8 n"nhN.HnHnHzNHnHnN(Jg8/.Hn/.Hn nHh HzNHnNHnNJg(-n n!n /./N n-h`pmfFN30-H/Hz|NJf(?<N.HnHnHz`NHnN8`pmf /N` nB.`HnHnHzhNHnHnHnN@|Jg nJhg?<kN.BHn/<N-n n1|Hh "nHiN nB(Jg"n "n1i!n` n 1|B n!np3mf N3` ?<N.HnHnHnN@|-nJ/./(Nxp mf N3` ?<N.B n h-h-h=h=hBHn nHhHzNHnHnHnN@| nJg*U n h/( /.NhJf ?<oN.Hn/<&N-n n!n!nB"!n1| Hh HnNp3mfvg0 n!nJV"(Vg ?<kN.` n!h n (o?<fN. n!h n/(HnHnNC n/(HnHnNC0.ڰno=n.Հ.gRnp no\ n|1n.Հ.@ ( @rnpA\"(DWJ-g ?<^N.N3Hn nHhHzNHnHnHnN@| nJg*U n h/( /.NhJf ?<oN. n!n n (o ?<fN.-n-npmV@J.fN3J.gpmf N3` ?<N.pmf N3` ?< g !mH` nB( n 0-H/HnNJf?<N.HnN8` n BN^ _ NDDNA-n nJho 0(P@S@l^@@HШ"n"` n"n" nB(pW"nriWg 1|` n1| nJN.pmf B` nBHnHmNHn nHhHzNHnHnHn nHh/(NJ-nJg0 nJ"f n"n#h""n-i```/<HnNJg ?<N. n/(Hn/(HnHnHzJNHnNHnN n h0(Wr h^(@g"n|B) 3h` nB(N^ _PONNA-n nJ fBB(`< n h"n$i (*gJJhf. (=@Jng0.H0.H1@/-/HzR+O n h"n$i 0*hNvr @lTNvhNvJhlBhl^@@HШ-@0.l^@@HЮ-@0.@2(AA]".W".^g-h=hJg. n-h n!n/. n/(N-n`pmfdN30-H/Hn nHhHzlNHnNJf,?<N.Hn nHhHz@NHnN8` `+o N2,_+_pmf ?<N. n hBBh`NJ n h"n#h|3h $i 0*hJi Wri W$i pjW$i * g0) l^@@HѩB)| n hpho1|` n hJhop/-/Hz.+O0(P@NvS@Nvl^@@HѨ?<N.pmV@J.fN3 n h!n1np mW.g n h!n1n"n#nJg nLH n-hJgt nA-H n .ʰ\".ʲ_ .ΰ\$.δ_ .ʰ]".β^g?<N.` ` n-hNv+o N.,_+_pmf?<N. n hB`NJ n hBh nB("n"iiYHi/( <?<NDf n!_"h $n$j0*il "h 5iN^ _PONNAHn/<NHnHmN-n nBB1| Hh HnN n"h"` n-h`XN^.Nu hhNA n0C22U@bB.B0-H/HzNJf(?<N.HnHnHzNHnN8Jmf8|BJmf nJ(gHn/<"N`Hn/< N-n nHPHm:     N^ _N``@p@NAHn/<N n"h"-n"nB3|B)B)"3|Hi HhNN3JmfLHn/<N-n nHPHmNd n!n !m"Bh+n"N3` ?<N.N^.NuNA/-0-& nCB!q!n/./NZ n1| Hh HnN;n&p mf N3` ?< N. n `p)mf:N3p mf N3` ?<N.HnHn/NJg< nphl?<sN.B` .Df?<N.BHn/<N/Hz*+O/. n/(N-_+o N:,_+_pmf*?<N.J g n phf n BN^ _ NNAN3pmf N3` ?< N.BHn/<&N-n n!nB"ni$B(B( 1|B(!| 1|Hh HiN-n n!n1|Hh HnN nB(B(B1|B!|oJg^/.HnHnNjJ] o^g?<N.`( n!n!npЮlмT n `dp-mf$N3Hn/<N-n nB(B(1|1| Hh HnHn nB("-nHn nHhHzNHnHn/.NJgB nphm* .Df?<N.` n!n` ?<qN.pmV@J.fN3J.gpmf N3` ?< N.p mf N3` ?<N. nHhHnN(-n n-hHzTNHnNp mfxN3Hn nHhN nJgR"hJ_"h ^g?<N.`*/< n"hHi NJg ?<N.`J-f ?<_N. nB nJf ` n"h <Б n `8pmf.--f ?<dN!nJg?<uACEB(-h"nJ)g ?<N. n0(HАS/0(H/-HN n0(H/N-_ n!n 1| n|/(HnHnNjJl .м^@` .䐼]@J.g. .䐮R-@ nJ(gph f> ?]?@Sb"n"Q +n>`D nJ(f"J.f/.HnN n|J-f n+hB/.N\P n!n nLHpmf\N30-H/HnHnHz\NHnNJ?<NDf n!_-n` YHm./.B'?<NDf n!_ nJfjJgZJV/<"nHi -@N .g20-& nCH!q0-&AH!B` n-h` .l ?<N.pmf\N30-H/HnHnHzNHnf(?<N.HnHnHz4NHnN8` ?<N.`N^ _PONNA n0C22U@bN3Jmg(?<N.HnHnHzHNHnN8;m&JmfHn/<N-n nHPHmNd nB BhHhHmN n+P NNJf(?<N.HnHnHzZNHnN8` ?<N.JmV2-H/Hm-@N .AgN^.Nu`p``LISTINGKEYBOARDNAJmf0-&ABA-H nphfX-h n/( nHhNW n-h3p(mWr mWg N3` ?<N./.N\PHnHnHzNHnHnN n!n pmf\N30-H/HnHnHz`NHnNJf(?<N.HnHnHz8NHnN8` ?<N.`;|N^.NuNA n0C22JW nJVgJf"n/HhNW` n/"nHiNW nB(Jg"hJ)(gT"hpif$phW"h)8AA`$ n"hpifp hW@ nJ(f>phW"hriWp hW"htiWg ?<N. nU@bN3BJmfHn/<,N-n nHPHmNd n!n1|B 1|$1m(HhHmNpm(f n!m ` nB J-)g n"PEpR@ f S@f`,J-*g2 n"PEpR@ fS@f``pm&f` /.N\P-nN3J(fphf,Hh/<=N n"h3|"hB)8`2 nHh/<=N n-h"n3|B8B)< n-h"nHQHmNd nB B$1|B((B()mm+B(,B(*B(-B"n1iHhHiN n/(N\P`R n"h-iJg<-n npmf--f ?<dN.N3HnHnHzZNHnHnHnN@| .ⰭPfHnHn/<Nd .ⰭDVU/.-@NbX .Ag ?<2N. n1|$ nLH& .ⰭDgpmfN3HnHnHzNHnHnHnN@| .ph$fYHm./( B'?<NDf-_ n-h`N3`?<N. n!m6pm&oRm&0-&ABA-H nJ(g:"h-iJg nJg` n-h` n ` nB nB BB1|B` ?<N. nphf-|` ;      ?<^N. n"h .Щ$-@YHn/.<?<NDf n"h#_8N3`,?<N.Hn nHhHz>NHnN8` nJ(f ?<{N.N^.Nu0NA n0C22U@b=mBr|N3-m.B.| |!HnHmNHmSb<HPHm-HN nNHn/NZ`J.g ?<N. nB("n$n%QB.@-pmf N3`"Hn nHhHz6NHnN8 n-h"nB)(|-J(g-h"nB)(|-0-&AB/0N n-hJg n/(N n-h`=m(pm(o Rm(` ?<N.-m.B.B- B-!Bm0-&ALB|lHnrm&Wg NB-pm&W.AgFJ>g>-m> n"hJ)f/HhN n"h| n+h >`B'N$B'Np1mfbJ.g ?<N.N3/N`pm&Vrm(Wg*.gS/-/./.N -.Ѯ`2J.f ?<N.p mf N3B.`(0-H/HnHnHzZNHnNJf(?<N.HnHnHz8NHnN8N^ _ NP@@@NA-n nphWrhWg B(,`2 nphW(Ag-h"npQfB) nJg /( nHhHz^NHn n/(NDpmVrmVg,?<N.Hn nHhHz NHnN80-H/HnHmHzNHnNJgp n"hB)-J(g "hB)-;n(+n.pm&f<N n/(/N0-&AT-pJgB-n nN nJg /(N~N^.NuNA n 0C22U@b|m0-H/Hz@NJf?<N.HnN80-H/Hz NJg0-|@2;N&VbnHn n(@(@(Nݶ`\HnNh`PHnN"PJV"P")\g"P"i$P%i` n-h`+n=m$N^.Nu@@@@@  NAJ g: n P P PCpR@ fS@f+n `` n -h `BN^ _PONNA n0C22U@bJ-g ?<^N.`DJ-f ?<dN.Hn<< n"hHi B'N`HnNj`0-H/HzDNJf?<N.HnN8`B-mN^ _PON@@@@NAJ gR-n nJg /(N n -h Jg/./.N n-h` n -h `N^ _-m.=m&HnHmNmmB-m-m>B>HmHzNB.Brp.mf N3` ?<N.Jmg"?<N.ACSb`p-d ?<N.0-&ABA-H nphf/(/N`F n/(/N n-hJWJVg nPONNA=m$0-&R@;@$-mpmf?<N. nHhNڲ0-H/Hz$NJg0-|@2;N8`Hn nHhHzNHn<B'N`lHn nHhHztNHnNt`JHn nHhHzVN/( /N| n-h`JW@pm&o>Rm&0-&ABA-H nBBB B1|B` ?<N.Hn/<NJ.gHn/<$NHn/<=N-n nHPHmNd nB BHhHz N n1|1||+B(B$B()B(HnN`(J-f ?<dN.<NvB'N:0-|.@2;N@v nHhB'B'0-&CTHqB'N`lN3 nHh<<0-&CTHqB'N`6N3 nHh<B'0-&CTHqB'N``HJ-f ?<dN.-|(B(,B(*|81m(-n n B|B( B BBB(B`Z m-P n-P-n nJ( g ?<N. n0-&CH#+h .| |!pm(f-m n+PJ.g n!m -n n BBB "n!i-n0-&N3 nHh0-&CP"q"QHi <N`` 0-H/Hz6NJg0-|@2;N8Xrvvvvvvvvvvvvv8vvvvvv?<N. nHh<B'N` ?<N. nHhN܌`?<N. nHhN`<N֨B'NlHnABA-H n!n"n#nJmfN3pmf N3` ?<N.pm&W.AgB'N/-NB-p/mflpm&W..Ag"|/-Nj0-]@;@NN3 n"n"Hn$nHjB'N n"n#P nB"n|<     f N3` ?< N. n"n#h#m. +n.+n>;n&HmHnNnmpm(f(+npm&W.Ag /-N| J.f n| n"n !Q n -nJg n-h Jg-n n-PJ.fV"nJ) fF?<E&Q&SIHmNHmN-/HztN0-^gBACVESbHn/HzR-/</-HN nU/<-HN n"_Nd nHhTHzNd nHhXHz.Nd nHh\HzNd nHh`HzNd nHhHzNd nHhHzNd nHhHzDNd nHhhHzNd nHhlHzxNd nHhpHzd nHhHzNd nHhHz Nd nHhHzNd nHhHzNd nHhHz@Nd nHhHzNd nHhHzNd nHhHzNd nHhHz Nd nHhHzNd nHhxHzTNd nHh|Hz~Nd nHhHzNd nHhHzNd=     1|$ n =|8Rn0.H/HzN_J.gHn/<N`Hn/<NBB0.|9@2;N:LJpJv^v/-X?</N`/-X?</N`-mT/-D?</N`/-D?</N|`x/-0-?/?<N<:?N/N/Nn`j-n/-D?</NV/-D?</NH/.?</N:`6/.?</N(/-h?</N`-n/.?</N-nt0.H ntC !n !nJ.g 1|` nt1| ntBh1n0.H/HzZNJg* ntHhHnpHmHz.NHnpN^/N/NBm(Bm&BmBm*Bm;|FBBBHBLBPBTHmHznN/N߆/NN3/Nr/N/N`;|(;|&;|\BXB^BbBfBj;|$NJmf2Hm/<N;| ;|A$mCSbJmfHm/<N;| BmB-&B`0.H/Hz@NJg* ntHhHnpHmHzNHnpN`0.H/HzNJg* ntHhHnpHmHzNHnpN`xpEnf* ntHhHnpHmHzNHnpN`FpFnf* ntHhHnpHmHzFNHnpN` ntHhHmN/.NR/-N m/-Hz?<?PROGRAMAll rights reserved.Copyright Hewlett-Pa\P nUm N^.Nu ` | NAB-BmvANCSbBB|B-B-lB-mB"B-B.| +|+| ACxSbACSb|!B-BBB|B-B-ckard Company, 1982, 1991.NA n JfD+m, n hB(Hh/<N nHh"h/)/<N`J n PLH=h$Hn/.N/. /<&NHn n //<&NN^ _PONNA nHh/. N/@-m, nJgJPg?<2N. nB`||B-|||B-B-B-|#;| B-|+BmBm|&B-"B-(BmAfC:SbA:+H6ABCSbB-,B--B-)B-*;|B-BmB-$B-B- N^.NuFLTPTHDW SYSGLOBALSNAHmfHzNHmpHzNHmHzNd np,h fV"n#hJ-lgLH`4 n"hHQHn/< NHn/N n"h#nN^ _PONNA n hHh/< N n h"h$hLH n h"hJf"h#h` n h"h" n h"hB!hN^.NuNA n h"hHmzHnHnHzHmNHnHmpNHnNHmHzNHmHnHmHzpNHnNHmHz*NHmHz"NHmHzPNN^.Nu`<=9@ \NA+|BR .SA"iHQHn/< N n+hJ. g/N@ n h-hJ. g*"nHi/< N n"h2"hB n-h"n < -@JlBpnf/.0.H/N-_`/./.N-_ .䰮oHn .䐮/Np-n԰n-@ 0".A! mN^.NuNA/N mB( |-|-r o<HmHn<0? n"n ()g n "n0) h ]@` n hN^ _ NNA n h h"h-iJf"h#h`U n /( n/( /N4Jg$ n h h"h#n "n "`^-n n-PJg8U n /( n/( /NJg  6N3 n (PW(g|U"n/)NbJg| n"h0)$H!@`FB. nJg./("nHiHiNj n (̐R!@` nB`FB. nJg./("nHiHiNj n (̐R!@` nB| nB-mHn``-n n-P` n n N^ _PONNA n hHh/<N n h"h#h "hBN3pmf N3`?<N. n h|Hn n hHhHz     @@@@_NA-m, n"nLH#hJ-lfJ)f$hAHPHn/< N n+hJ(fP0.m2|n*@2;NHh/<N-|`Hn n/(/.NN^.NuNA n!mHhN^-m, nJNNl.NWNCNNNNNNNNNN+mnN&./-/Hz+OHm     - -=--1-Eȸ-1- MPM1.-1-=!=MP=!=M1R(- -1-=M=--1-Ym-*}m(}-0-.6-`  P PJ Y- ----  1 =1 1 != ==!= ==!= = ==1==1-1  P-- e --  --    ===P!P!P!=M M-=1-=M=!1-1-!=-= -!-= -=-= -!-=1 -=1-=1-=1LB !  -=-  - - ELSEO ENDONO EXPORTO&0EXTERNALO<O.OZ7FILEOTOl-FOROhFORWARDOzOFO6FUNCTIONOO GOTOOIFOOO IMPLEMENTOO1IMPORTO/INM=11 6-1, =1&$ 0! = !  =  = ( =1T  =1 =M!==OOP(LABELPMODP"PP<&MODULEP4PN.NOTPJ%OFP\P&P ORPnP' OTHERWISEP2PACKEDPPrP* PROCEDUREPPPROGRAMP!RECORDPP`QZ,RECOVERP =!1 1- f- - )---L1Ȣ- ----  -  -    - e- - - Q9REPEATQSETQPQ6)THENQ0QH TOQDTRYQVQ"Q8TYPEQhQUNTILQ| VARQQnQWHILEQQWITHQLBDgp, `(E Tg2b.eJ$Fbe4>UGmVf&   P$P< DPP  P*P P00 P $  - "P(Ќ}X PPp   BNBGUGmVe*,f&.N>UGmVb*,f&.N(E TJg*,f`k$΄REALlt*>gGH COMPIO_ERROR.{.. h @COMPIO_INSYMBOL P$  Y--"q&}}m-  "   ! , "P P>  !  >!- ! " "P P-, htT COMPIO_ERRORptk$RAGlt$΄NEXTuENUM0k*t @NNMOHDDREPP  - -"---6  1&:  -- ---1  @.-1 --=1-= !=1m-yYm4-M1 -  - }}M--1*  - -"--- !2B"P        P      .  ?     -  -M-=-  --1$ -=-Ո -  -1  -1-=-m- - -=1  $}}m v     ,0  PP PJPP((}}Z}}@}}@}}@}}@}}@}}PTmY- - M- -  -- --E" !,و =P21=d  == == =P:1=P==11P=1=1P1fMP =1=@M--&M-- $( 46M--M--$NM--4M--M--M--&P . M-"P *  " ( M-" }} P. ===@= =!=! =! =! = =!=! = == =! = ==!====1P@PPD= ===!0= = == ">  ":P220P  $M--Y- --1-=1YYY6" mYM- (*& =M = = = =! =====! = =!= = = =*= = ==!==P$1P= M=!1P= M=!11nP1PR<11r    M- M-- M- M--B 0 M-->P4.:$   M- M-- *P&=M1P=1PH1P=1P21P1P1PM=1P1- PbPP\PXP(*P0. P P      $ P P  P P  P P B}    B$.2.2z M-- P  0(!PP, PPP*!P,}p}}P P(:-QP,P$PP8Q>PPQP(؈ j-P( .}P BP P<}P dB(LRFfr8H} }P dP<}P xlP!* !(P<>1P Z t " 6 r$8h!P  <t^-0-          * &PЎ<u>-2 .TЎ.x"^2:-PLPvP *8P}P (4fP,PdP$ ~PPLPzm m6}@  P BPBPBP@P,$D PBP"P PP>P0$!$&!$8 H P  ( $    PP PPPPPDP2 PP(PPPP,PP2PP&PPPPLPPPPPPlPnP4PnQ&P.P\P*P\PP&P*&"8 P P P  PPPPP PJP PP -P P4PPPPPPnP PP2PP P&P: PPPP&Q6!!PPP.PXP4PNPPPTPPP PP PP P PP! P!P(PP*PPP!P(PBPPPPPPPP?      26PFPP"PQ.PTP,PBP"QVP>*P>&PPN؈ :- -P --2-PP P P PP---- P PPP P&P PPPP -!"!PPPPPPP$PP(P6P2- -&}}P ---P P8PdPPPPPPP(P:PPPP0LP FP P4P*!PPP2PRPJP2PPP:(PP PPPPPPP-PP* PPP&PP P(P-PFPPPPPPP(PP(PhPPPPP&P"PP,PPP(*P&P&PPPP P(P PP PpPP.P6 PP,PPPP,PPPP6P PPPPPP&P2PDP$PPP PPP"PP*PPPPP,P0PPPPPPPP(!PPPP.,!PPPPP P P PPP P&\ P PP$!PLPPP P }P}}P} PPP*PP PP PPP P"P P PPPP PPPPPPP PP P"P PPP P$PP PP -P Pj!P(PP!P(PBPPPPPPPPP -P"PP@X!P&PPP P P!P&PP B!P&PPT P P&!P&PPP\PP -P P PfP0P"(tt`}}$!,!HP P ! PPP^P2 PPT PP P(PPP2 PPPP"V}P P(PD0}P PPPP4PP4PPPPPPPPPP0PPPPPPPPP P@P"!P(PP PPPPPPP P6PPPPP PT PPPPPP.PPPPP$PPFPVP.PpPP"PPPPfP4PPPZPPPBP P$P PP.PLP0P*PPRPPPP&PP"P&PPPPP$PPP$PP"PPPP~PjPP4PPPDPP.PPPQP P PPP PPP" PPP P P fPNP8PPP P ^ PPPP&P&* PP P P6P P,PPPPPPP P&PP0-,0!(PPPPP PPP PP P P$P>PPJP PPP\PP4P P P PPPPPPBPFPPP(PP,P"4 PP PP,P PPLP.P&PP PPP4P4PPPQ(PP*PnPPPPPPPPP.P"P(PP P"P PP PPP4P24P*PP:$P$PP PP LPP PPP P P"PHPЀPXPȜ-P6P`P:PP- ----PXPPPPPJP(PPP8P P8P2P4 PPPPP PPP P PPP P^PXPP P PP"P"P"P PP8 P& PP*PP:P$P@PPPPP&PPPlPPP6PPPPJPNP:PnPP PP*P`P2PP(P,PP2P<PPP PPP.PPP`P P0P4P*P.PtP PPP.PPP"P.P">PPPbPPP0PPPdPP8PPPPhP$$PP PPPPP,P&PPPDPPPPHPPPhPfPPPP2PPPPPP(PP PP$PVP(PPP(P*P8P6P8P6PDPPPRPPP4P!PP,PP PPP>P(PRPP,PPP,PP PPPP P(P2PP2PPPPP PX PPPPPPPP6PP PPPP PPP PRP  PPPPPPdPPP(PPP*PPPP2PPP(PPP*PPP PPPPPPPPPPPPP P P4P*P0PPPRPPPPbP$ PPPP PP2PP&P P8PP PPP*PP PPPPPPPP PPP PPPPPPPPPP PPPbPPN}P f}P PP P PPPP PPP6P P@P PP PPP PPPPJPPP PPPPP PPFBPNPP*PPPP PPBPPPPXP86P PPP>!P&PPB!PPP.!P&PPPP P.PPPPPQ:PPP8PD -PZPP!!P>P(zP$PP" P`P* P PPP P PPP8P0PPPP PPPPPlP2P PP"-PPP PBPPP6PP PP\PP P&PPP`PPPP88 PPPP$PPJPPPPPNPP  PPP&P PPPPPP0 PL PPP PPPPP<P P!P$PP$P PPP"PL!P$P,P*>P P PP,P P(PPjP6P PP PJPP*P PP P PPPPP PPP,PPJPJP PPpPP P  P PP P>,}P P  !PP PBPn Z PP PPP PP F:nPPHP2PzPʈ P P(PxP*P2 P ^P (- -(PmP ---P @- -.e8Y---- -P4u4u&h4u4u(4u&Jň P1  m -YP -P -6 ! ! ! !P,}P}} -1-=M=- -= :} =-PP-:} =-PP--1P P  LPňD@P48nPPFPPPzTP ! P: P bP (- -4---P @- -.M8q----PB!4upuR$j4u&4u&$< PňP&&P,> P <PňBP P"P2  j -- -- --E!<!** !> .\ P@$PPHPP6"PPP:PD(PPP$P(P6P&ІP* P:P FP P FP P4P(FPPPP.P Rx! h12BP PPPP"2FP`PPPHЬPP(NPPPNPPPP@P r&&&&u& P:ňP PP!!!!!!!!!!!!!- - --$ P>2 PbPPPfP&8ňPP P V"ňP .0PPP P$P4PP < P "PP(PP.P&P PP(PP :"P P P PPP $PPPP0$P P8P P (&P P8 P 0PP>P P RP   PP4PPPP(PPP 6P0P2PPP(P0PPPPJPPnPP2PP$P$P&PP".P:PP"\PňzP Pň.Pň0N!\P P:Pň P:P"P"!PP&PP&PPňPPP4FPPPnP4PP8P.8P PP&P4V*!(ň P PPň!. PPPH!. P PPP.P P P$P PPF$PPFPP&  P P   PP   PPj!n14P P$$P* PP P4PPPPhPJ P P,PP:PP(P2P P PP " P,8ň  PP P 2P& P PP"P* PP00PPP&PP2PPPfPP"PP PP(N! P"(PP8 PP PP PP P4P  P$PPJP PňTPP&PP*PP"P4P,PP(P*4P0PP2P P& 4- - ---P P !B - - 4---P , PPP( P&* "P P @*PP P $^P(P : P:P$P*- -:---P PR8FP"ň PPňPPň PPP ňPPňPP PQ PRPPPP P.P &PPPP4P 0N4@P"PP."ňPPP,ňPPPP PPPP>P*ňP*PPP &  !PPPPP PPPP @P^r- -$A9$--P l PPPP2P P0\PP(0P (- -< U  } ---- --PP\ , :P|&!>TP P* PPPBPPP PP(&P P Z!zV &,PPP RPP P PPPP\(ň PPPP,ňPPPPP4P P PPDPP$P PP P P ňPPP( PP P ňPPP(PPP.] PLP P PňP$ P ,P.PPPP2ňPP@     P"(]&! 0PPPPPP.P !$P:P >P!4 PP@P P DP P PP *(P@}P 0& P.}P    P:P :P ! P P PP PPPP.P  PPPP  P T2}} m  m  T !* !8 !( !6 !8 !, !, ! !$  !P !P PP PP PPP"! P$-P "P PP PP@P P !P PP PP ňP PP P P4 !P  &,PP P PP P PP$ PP P P$&"!P P !P  P !P P !P P !P P !P  P !P P !P P&!P  P& !PP0P !P (P !P  P  !P   PP !P6 P $PP PPPP PP P   PZ        PP Ȏ--1-M& !1-!ň2PPH,}P PP-&PP P P PP!@PPPň  Pň P PPP ň ň6"P 8P &P 8P PP: (P P PP PXP4P6PP&!.!2P (P6PPP P|*~P PP$PPPP PP$*P P,PPP P6!P !P PPPPP P !P PPP P P P P PPBP<P"PPPPPPP6  P"mP<P h PP P PP   PP !PPDP PPP P" PPP"PPP "P0PP P -P&P(-PP PP tP}P b -- -- Ym- }P - }P D-&}P &Ym"M*}P P0P P P P P PP P P PP *!!PPP  PP PPP0P P PP2(PPB `PPP2!!PR PP PP PP P PP PPhP(P P P &PP|P6P*!$}} }}P 8}}P (Ym-P *PP YEP P  P P4&!&P P$P P*P P4N8PP  !@P!P(PPP PP P$PP P(PP P P P P"!2PPPPP!"PPPPP8P(P Pp PP n- -D---P ȶ- - ---P PLH !DP !P Z!P PP  P PPP PP ވ PP   P P  PP -P   Z("ňP 2PP PP PP P"  PNP P4PPP PPP4P PP ::! &P"!!, P PNPP PPPPPP PfPP "PP>PP$P!4P PPP$PP$PPPPPPLP"  P PP PPP~ PP !!P(PBPP PP PP PPP   *P X-^&P  PPP P D,P4!!!P@:P&  0$PPPPP PPPPL!P  PPP*  6P PP ^!BP!P PP- - ---P P4PP!R$ň0P PPPPPPPD  P"mP0m0m.PP   P PP PPPPP $P PPPP PPP PД}P LP P P PPjP  P  ~.PPP P P   PNPPP*P P"P$P P R}P A      !* !2 !( !B !:P8PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP!!D! j   P PPPPPP PPPPPPPPPP PPPPPP PPPP PPPPPPPPPPPPPPPPPP PP PPPP PP PPPP PP PPPPP PPPPPPPP PP PPPPPP PPPPPPPPPP PPPPPP PPPP PPPPPPPPPPPPPPPPPP PP PPPP PP PP P `!&P@PPPPPPPPPPPPPPPPPPPPPPPPPPPP!@!!Z  ,&.Ђ       P d   This floppy contains the source for the PaWS SCSI driver, a copy of the modcal version of the PaWS Pascal compiler, and a stream file (MAKE_SCSI.TEXT) which shows how to build the SCSI driver (SCSILIB, SCSIDISC, SCSIDVR). The modcal version of the COMPIL  (ň   b( ] q]] q]m] -===P!PER (3.25M) is required for building these modules. !P!MM1-1-=1-==1-1PPPP !- ! -1-= !P>-!6!P P*,>!Ў -6!X This floppy contains the source for the PaWS SCSI driver, a copy of the modcal version of the PaWS Pascal compiler, and a stream file (MAKE_SCSI.TEXT) which shows how to build the SCSI driver (SCSILIB, SCSIDISC, SCSIDVR). The modcal version of the COMPILE$!b!PPP(P<P6P(.PP&P"PPfP