                  <<< DOCD$:[NOTES$LIBRARY]SCT-RAVEN.NOTE;1 >>>
                         -< The SCT Raven conference >-
================================================================================
Note 449.0      BUGFIX: MSCP Server: Return proper xfer count up      No replies
EVMS::MORONEY "{VDE SCT}"                          1515 lines   2-APR-1997 20:22
--------------------------------------------------------------------------------
The Title:			Forced Error and Served Disks
Author:				Michael J. Moroney
Component being changed:	[MSCP]MSCP.MAR
Date:				March 21, 1997
Images affected:		MSCP.EXE
Updated:			
	
1. Change Information:
   Type of change:		Bugfix

   Where is the change being made:
	OpenVMS VAX & Alpha versions - V7.2  V7.1R  V6.2R  

   Reviewed by:
	This is not filled in until after the review.

   Checkin information:
	Not filled in until the checkin is complete.

2. Symptom Description

    Inconsistant transfer count when encountering a forced error
    on a drive, a drive directly attached (or HSx served) reports
    a different transfer count from the same drive served via the
    MSCP server.

    Code that attempts to determine the LBN of a forced error block
    by looking at the byte count in the IOST/IOSB will arrive at
    different values on the same drive when directly accessed or
    MSCP served.

    Old shadow code (pre SHADOW96) looping, repeatedly "repairing"
    and rereading the same block range, producing an "unkillable"
    process waiting for an I/O that will never complete.
    EVMS-RAVEN QAR 230 describes this problem.


3. Problem Statement

    When the MSCP server encounters a forced error or parity error, it
    just issues an end message with the error.  It does not perform a
    parital data transfer for reads or a partial byte count for writes.
    This is apparently a day one bug.

4. Goals of this change

    Give correct data to software that attempts to locate the bad
    block or use partially read data. (SHADOWING)

    Make the IOSB/IOST of the same drive consistant when directly
    accessed as MSCP served.

    Close EVMS-RAVEN #230.

5. Known Restrictions / Possible Limitations / Risks

    None known.

6. Algorithms

    When encountering a forced error, parity error, or host compare mismatch,
    update the transfer count correctly for writes (IO$_WRITExBLK) and
    hostcompare (IO$_WRITECHECK) and for reads (IO$_READxBLK), send the
    partial last block with a SEND_DATA_WMSG with the error code indicating a
    forced or parity error, rather than just sending the end message of the
    error code.

7. Testing

    Code was tested by placing forced errors at known locations and
    examining the IOSBs of reads including that block range with
    directly accessed drives, MSCP served with the old and new mscp
    servers.  A wide range of transfer counts and locations of the
    bad blocks were used to locate potential problems.
    WRITECHECK I/Os were also issued as these are also affected.

8. Implementation.


============================= VAX ===================================
************
File DISK$PROD:[SHADOWING.WLG.MSCP.SRC]MSCP.MAR;29
    6   	.IDENT	'X-65'
    7   
    8   	SOFTWARE_REV == 65	; Keep software rev level equal to ident field
    9   				;  for easier remote diagnosis
******
File DISK$PROD:[SHADOWING.WLG.MSCP.SRC]MSCP.MAR;1
    6   	.IDENT	'X-64'
    7   
    8   	SOFTWARE_REV == 64	; Keep software rev level equal to ident field
    9   				;  for easier remote diagnosis
************
************
File DISK$PROD:[SHADOWING.WLG.MSCP.SRC]MSCP.MAR;29
   57   ;	X-65	MJM		Michael J. Moroney		26-Mar-1997
   58   ;               Make Forced Errors return partial transfer counts rather
   59   ;               than 0 bytes, to make it consistant with non-served disks.
   60   ;
   61   ;	X-64	RFB		Ray Boucher			 6-Aug-1996
******
File DISK$PROD:[SHADOWING.WLG.MSCP.SRC]MSCP.MAR;1
   57   ;	X-64	RFB		Ray Boucher			 6-Aug-1996
************
************
File DISK$PROD:[SHADOWING.WLG.MSCP.SRC]MSCP.MAR;29
 5415   	MOVL	CDRP$L_IOST1+2(R5),-	; Use the number of bytes retrieved
 5416   		CDRP$L_XCT_LEN(R5)	;  as the number to send to host
******
File DISK$PROD:[SHADOWING.WLG.MSCP.SRC]MSCP.MAR;1
 5411   	MOVL	HRB$L_BCNT(R3),-	; Use the number of bytes retrieved
 5412   		CDRP$L_XCT_LEN(R5)	;  as the number to send to host
************
************
File DISK$PROD:[SHADOWING.WLG.MSCP.SRC]MSCP.MAR;29
 7869   	ACTION	SS$_DATACHECK,MSCP$K_ST_COMP,ERR_DATA
 7870   	ACTION	SS$_CTRLERR,MSCP$K_ST_CNTLR,ERR_OFFLINE
 7871   	ACTION	SS$_FORMAT,MSCP$K_ST_MFMTE
 7872   	ACTION	SS$_FORCEDERROR,MSCP$K_ST_DATA,ERR_DATA
 7873   	ACTION	SS$_PARITY,<<MSCP$K_ST_DATA>!<1*MSCP$K_ST_SBCOD>>,ERR_DATA
 7874   	ACTION	SS$_IVBUFLEN,MSCP$K_ST_HSTBF
******
File DISK$PROD:[SHADOWING.WLG.MSCP.SRC]MSCP.MAR;1
 7865   	ACTION	SS$_DATACHECK,MSCP$K_ST_COMP
 7866   	ACTION	SS$_CTRLERR,MSCP$K_ST_CNTLR,ERR_OFFLINE
 7867   	ACTION	SS$_FORMAT,MSCP$K_ST_MFMTE
 7868   	ACTION	SS$_FORCEDERROR,MSCP$K_ST_DATA
 7869   	ACTION	SS$_PARITY,<<MSCP$K_ST_DATA>!<1*MSCP$K_ST_SBCOD>>
 7870   	ACTION	SS$_IVBUFLEN,MSCP$K_ST_HSTBF
************
************
File DISK$PROD:[SHADOWING.WLG.MSCP.SRC]MSCP.MAR;29
 7918   
 7919   
 7920   ERR_DATA:
 7921           MOVL    HRB$L_IRP_CDRP(R3),R5   ; Get the address of the IRP
 7922   	MOVL	IRP$L_BCNT(R5),-	; Get the number of bytes transferred
 7923   		HRB$L_BCNT(R3)		;  and save it away in the request block
 7924   	MOVAL	IRP$L_FQFL(R5),R5	; Move from the IRP to the CDRP address
 7925   	MOVL	CDRP$L_IOST1+2(R5),-	; Use the number of bytes retrieved
 7926   		CDRP$L_XCT_LEN(R5)	;  as the number to send to host
 7927   	POPL	R1			; ditch return address
 7928   60$:
 7929   ;
 7930   ; Initialize a CDRP that SCS can use to send the retrieved data to the 
 7931   ; requesting system.
 7932   ;
 7933   65$:	MOVL	HRB$L_HQB(R3),R1	; Get the HQB address 
 7934   	MOVL	HQB$L_CDT(R1),-		; Get the address of the CDT 
 7935   		CDRP$L_CDT(R5)		;  and place it in the CDRP for the call
 7936   	CLRL	CDRP$L_RWCPTR(R5)	; Clear RWAITCNT reference to avoid
 7937   					;  incorrect stalls.
 7938   	MOVL	HRB$L_MSGBUF(R3),R2	; Get the MSCP packet address back
 7939   	MOVAL	MSCP$B_BUFFER(R2),-	; Get the remote buffer handle
 7940   		CDRP$L_RBUFH_AD(R5)	;  and save it for the call
 7941   	MOVL	HRB$L_ABCNT(R3),-	; Figure out the offset into the 
 7942   		CDRP$L_RBOFF(R5)	;  remote buffer 
 7943   	MOVAL	HRB$B_LBUFF(R3),-	; Define the local buffer handle as
 7944   		CDRP$L_LBUFH_AD(R5)	;  the address of LBUFF
 7945   	CLRL	CDRP$L_LBOFF(R5)	;  in the remote and local buffers
 7946   	MOVL	HRB$L_PDT(R3),R4	; Get the PDT address for the SCS call
 7947   ;
 7948   ; This block transfer can contain all remaining bytes for the request.
 7949   ; Issue combined SEND_DATA with piggyback end message request for this final
 7950   ; transfer of the request.
 7951   
 7952   ;
 7953   ; fill in the End Packet information
 7954   ; 
 7955   	MOVW	R0,MSCP$W_STATUS(R2)	;  SEND_DATA_WMSG will complete sucessfully
 7956   					;  or SCS will not deliver the piggyback
 7957   					;  end packet!)
 7958   	ADDL2	CDRP$L_XCT_LEN(R5),-	; Add bytes transferred to
 7959   		HRB$L_ABCNT(R3)		;  ABCNT.
 7960   	MOVL	HRB$L_ABCNT(R3),-	; update the HRB, why not... 
 7961   		MSCP$L_BYTE_CNT(R2)	;  nothing short of disaster could stop
 7962   					;  the last packet now!
 7963   	MOVZBL	MSCP$B_OPCODE(R2),R1	; get opcode
 7964   	BISB2	#MSCP$K_OP_END,-	; Reset the op-code to
 7965   		MSCP$B_OPCODE(R2)	;  make an end packet
 7966   	MOVZBL	END_PKT_LEN[R1],R1	; Get the message length from the table
 7967   	MOVL	R2,CDRP$L_MSG_BUF(R5)	; Put the message buffer address into
 7968   	.IF DEFINED DEBUG$LOG
 7969   
 7970   	ASSUME DSRV$V_LOG_ENABLD  EQ  0
 7971   
 7972   	MOVL	G^SCS$GL_MSCP,R0	; Get the DSRV address.
 7973   	BLBC	DSRV$W_STATE(R0),70$	; Branch if logging is disabled.
 7974   	BSBW	LOG_END_PKT		; Otherwise, log the end packet.
 7975   70$:	.ENDC
 7976   
 7977   	CLRL	HRB$L_MSGBUF(R3)	; Message buffer belongs to SCS again
 7978   	MOVW	#HRB$K_ST_SNDAT_WAIT,-	; Set the state for this request
 7979   		HRB$W_STATE(R3)		;  before calling SCS service
 7980   	
 7981   	SEND_DATA_WMSG			; send the last SEND_DATA w/piggyback
 7982   					;  end message. NOTE: SEND_DATA_WMSG will
 7983   					;  get *all* required send credits for the
 7984   					;  block transfer, this is why RECYCL_MSG_BUF
 7985   					;  is not needed.
 7986   
 7987   	BISW	#HRB$M_STATE_INVALID,-	; The state of this request is "current"
 7988   		HRB$W_STATE(R3)		;  leave the old state for diagnosis
 7989   	BSBW	CLEANUP_HRB		; Deallocate all HRB held resources
 7990   	BRW	UNBLOCK			;  and drop the "current" counter
 7991   ;
******
File DISK$PROD:[SHADOWING.WLG.MSCP.SRC]MSCP.MAR;1
 7914   ;
************

Number of difference sections found: 5
Number of difference records found: 86

DIFFERENCES /IGNORE=()/MERGED=1/OUTPUT=DISK$PROD:[SHADOWING.WLG.MSCP.SRC]MSCP.DIF;1-
    DISK$PROD:[SHADOWING.WLG.MSCP.SRC]MSCP.MAR;29-
    DISK$PROD:[SHADOWING.WLG.MSCP.SRC]MSCP.MAR;1

;+
; Functional Description:
;
; This routine is called to process a MSCP read packet. It is called from the
; non-sequential buffer class command routine. When processing of this 
; command is complete, control is returned to the main line routine.
;
; Inputs:
;
;	R2  =  MSCP packet address
;	R3  =  HRB address
;	R4  =  UQB address
;
; Outputs:
;
;	R0  =  Read completion status
;	R2  =  MSCP packet address
;	R3  =  HRB address
;-

READ::
	.IF DEFINED DEBUG$PC_HISTORY
	BSBW	PCHIST			; Save this PC if we are keeping track
	.ENDC	   ;DEBUG$PC_HISTORY

;
; Allocate and load mapping resources to map the transfer buffer area
; in the requesting system.
;
	BSBW	ALLOCATE		; Find some memory for the transfer
;
; Now prepare the CDRP for mapping the local buffer just allocated
; for use by SCS.
;
	MOVL	HRB$L_IRP_CDRP(R3),R5	; Get the IRP base address
	MOVAL	IRP$L_FQFL(R5),R5	; Move down to the CDRP portion
	MOVAL	HRB$B_LBUFF(R3),-	; Define the local buffer handle as
		CDRP$L_LBUFH_AD(R5)	;  the address of LBUFF
	MOVL	HRB$L_HQB(R3),R4	; Get the HQB temporarily
	MOVL	HQB$L_CDT(R4),-		;  so we can put a fresh CDT address
		CDRP$L_CDT(R5)		;  in the CDRP
	MOVL	HRB$L_PDT(R3),R4	; Pick up the PDT address
	MOVW	#HRB$K_ST_MAP_WAIT,-	; Set the state of this request to 
		HRB$W_STATE(R3)		;  mapping a buffer
	MOVAL	HRB$L_SVAPTE(R3),R1	; Address of the three longword buffer
	CLRL	R2			; Access mode of transfer is kernel
	MAP				; Map the buffer
	BISW	#HRB$M_STATE_INVALID,-	; The state of this request is "current"
		HRB$W_STATE(R3)		;  leave the old state for diagnosis

;
; Since the processing of this request can be stalled while waiting for
; the local buffer to be mapped, we need to check to see if the request
; has been canceled before going on.
;
	BISW	#HRB$M_MAP,-		; Indicate that we have allocated 
		HRB$W_FLAGS(R3)		;  mapping resources for this request
	BITW	#<HRB$M_ABORT!-		; Check to see if this request has been
		HRB$M_ABORTWS>,-	;  aborted either by ^Y or by the 
		HRB$W_FLAGS(R3)		;  loss of connection to the client
	BEQL	READ_LOOP		; Request was not aborted, continue...
	BRW	ABORT_READ		; Otherwise cleanup this request

;
; Prepare the IRP for the disk transfer. 
;
READ_LOOP:
	MOVL	HRB$L_IRP_CDRP(R3),R4	; Get the address of the IRP
	MOVL	HRB$L_UQB(R3),R5	; Get the UQB address
	MOVL	UQB$L_UCB(R5),-		;  so we can pull out the UCB address
		IRP$L_UCB(R4)		;  and save it away in the IRP
	MOVL	HRB$L_SVAPTE(R3),-	; Move the local buffer
		IRP$L_SVAPTE(R4)	;  virtual page table entry,
	MOVW	HRB$W_BOFF(R3),-	;  the byte offset within the page,
		IRP$W_BOFF(R4)		;  of the start of the buffer
	MOVL	HRB$L_BCNT(R3),-	;  and the byte count to be used for
		IRP$L_BCNT(R4)		;  this (portion of the) transfer.

;
; Check for a READ RCT request. If a READ command is received by the server 
; for a LBN beyond the user visible portion of the volume, it must be a READ
; for the RCT. To verify this, make sure the byte count is exactly 512 bytes, 
; and the LBN specified is not beyond the end of the Revector Cache Tables for
; this device. If these tests are passed, set the function code to IO$_READRCT 
; and join the common code.
;
	MOVL	HRB$L_MSGBUF(R3),R2	; Get back the MSCP packet address
	MOVL	UQB$L_UCB(R5),R1	; Get the UCB address for later refrence
	CMPL	MSCP$L_LBN(R2),-	; Check to see if the LBN specified
		UCB$L_MAXBLOCK(R1)	;  for this read is beyond host range
	BLEQU	20$			; If not, continue with a normal read
	CMPL	MSCP$L_BYTE_CNT(R2),#512; If the read that is meant for the RCT
	BGTRU	10$			;  is larger than one block it's bad
	CMPL	MSCP$L_LBN(R2), -	; Then see if the read is beyond 
		UCB$L_DU_TOTSZ(R1)	;  the end of the RCT area too 
	BGTRU	10$			; If so, it is invalid
	MOVW	#IO$_READRCT,R0		; Set the I/O function code to be used
	BRB	30$			;  and continue with the main line code
10$:	MOVL	#MSCP$K_ST_ICMD,R0	; If there was an error in the read
	BRW	SEND_END		;  return an invalid command

20$:	MOVW	#IO$_READPBLK,R0	; Pass I/O function code to be used

;
; Check for any supported modifiers in the MSCP request. If they are set
; there, then we should set them in the IRP we send out also.
;
30$:	BBC	#MSCP$V_MD_COMP,-	; If the compare modifier was set in
		MSCP$W_MODIFIER(R2),40$	;  the MSCP packet,
	BISW	#IO$M_DATACHECK,R0	;  then set it in the IRP also
40$:	BBC	#MSCP$V_MD_SEREC,-	; If the  modifier was set in
		MSCP$W_MODIFIER(R2),50$	;  the MSCP packet,
	BISW	#IO$M_INHRETRY,R0	;  then set it in the IRP also
50$:	MOVW	R0,IRP$W_FUNC(R4)	; Fill in the function code

;
; Actually send off the IRP to the disk in this subroutine. If for some
; reason this request is aborted while the IRP is "out to disk", the entire
; request is cleaned up and finished off in the subroutine BACK and never
; heard from again.
;
	BSBW	DO_DISK			; Execute a disk transfer
	BLBS	R0,60$			; We got the requested bytes from disk
	BRW	XFER_ERR		; Leave now for error

;
; Send the data to the host buffer
;
60$:	MOVL	IRP$L_BCNT(R5),-	; Get the number of bytes transferred
		HRB$L_BCNT(R3)		;  and save it away in the request block
	MOVAL	IRP$L_FQFL(R5),R5	; Move from the IRP to the CDRP address

;
; Increment the HULB counter for load balancing purposes
; (note: if the transfer is segmented, the counter will be bumped for each
; segment)
;
	CLRL	R0			; Ensure that R0 has no excess baggage
	BICW3	#MSCP$M_SLUN,-		; Extract unit number for use as index,
		MSCP$W_UNIT(R2),R0	;  clearing the SLUN bit
	MOVL	HRB$L_HQB(R3),R1	; Pick up HQB
	MOVL	HQB$L_HULB_VECTOR(R1),R1; Get pointer to HQB vector
	BEQL	65$			; HULB vector has vanished...
	MOVL	(R1)[R0],R1		; Index into vector with unit number.
	BEQL	65$			; HULB has vanished...
	INCW	HULB$W_OPCOUNT(R1)	; Increment HULB counter.
;
; Initialize a CDRP that SCS can use to send the retrieved data to the 
; requesting system.
;
65$:	MOVL	HRB$L_HQB(R3),R1	; Get the HQB address 
	MOVL	HQB$L_CDT(R1),-		; Get the address of the CDT 
		CDRP$L_CDT(R5)		;  and place it in the CDRP for the call
	CLRL	CDRP$L_RWCPTR(R5)	; Clear RWAITCNT reference to avoid
					;  incorrect stalls.
	MOVL	CDRP$L_IOST1+2(R5),-	; Use the number of bytes retrieved
		CDRP$L_XCT_LEN(R5)	;  as the number to send to host
	MOVL	HRB$L_MSGBUF(R3),R2	; Get the MSCP packet address back
	MOVAL	MSCP$B_BUFFER(R2),-	; Get the remote buffer handle
		CDRP$L_RBUFH_AD(R5)	;  and save it for the call
	MOVL	HRB$L_ABCNT(R3),-	; Figure out the offset into the 
		CDRP$L_RBOFF(R5)	;  remote buffer 
	MOVAL	HRB$B_LBUFF(R3),-	; Define the local buffer handle as
		CDRP$L_LBUFH_AD(R5)	;  the address of LBUFF
	CLRL	CDRP$L_LBOFF(R5)	;  in the remote and local buffers
	MOVL	HRB$L_PDT(R3),R4	; Get the PDT address for the SCS call
;
; Check if this will be the last block tranfer for this request, that is
; bytes left to send =< size of each block transfer.
;
	SUBL3	HRB$L_ABCNT(R3),-	; Get bytes left to tranfer for this
		HRB$L_OBCNT(R3),R1	;  Request (OBCNT-ABCNT)
	CMPL	R1,HRB$L_BCNT(R3)	; (OBCNT - ABCNT) =< BCNT)?
	BGTRU	80$			; If GTR no, use plain SEND_DATA
;
; This block transfer can contain all remaining bytes for the request.
; Issue combined SEND_DATA with piggyback end message request for this final
; transfer of the request.

;
; fill in the End Packet information
; 
	ADDL3	HRB$L_ABCNT(R3),-	; bytes sent prior to this
		CDRP$L_XCT_LEN(R5),-	;  + bytes to be sent this transfer 
		MSCP$L_BYTE_CNT(R2)	;  = total bytes transfered
	ASSUME  MSCP$K_ST_SUCC EQ 0	; set status success (Note: either the 
	CLRW	MSCP$W_STATUS(R2)	;  SEND_DATA_WMSG will complete sucessfully
					;  or SCS will not deliver the piggyback
					;  end packet!)
	MOVL	MSCP$L_BYTE_CNT(R2),-	; update the HRB, why not... 
		HRB$L_ABCNT(R3)		;  nothing short of disaster could stop
					;  the last packet now!
	MOVZBL	MSCP$B_OPCODE(R2),R1	; get opcode
	BISB2	#MSCP$K_OP_END,-	; Reset the op-code to
		MSCP$B_OPCODE(R2)	;  make an end packet
	MOVZBL	END_PKT_LEN[R1],R1	; Get the message length from the table
	MOVL	R2,CDRP$L_MSG_BUF(R5)	; Put the message buffer address into
	.IF DEFINED DEBUG$LOG

	ASSUME DSRV$V_LOG_ENABLD  EQ  0

	MOVL	G^SCS$GL_MSCP,R0	; Get the DSRV address.
	BLBC	DSRV$W_STATE(R0),70$	; Branch if logging is disabled.
	BSBW	LOG_END_PKT		; Otherwise, log the end packet.
70$:	.ENDC

	CLRL	HRB$L_MSGBUF(R3)	; Message buffer belongs to SCS again
	MOVW	#HRB$K_ST_SNDAT_WAIT,-	; Set the state for this request
		HRB$W_STATE(R3)		;  before calling SCS service
	
	SEND_DATA_WMSG			; send the last SEND_DATA w/piggyback
					;  end message. NOTE: SEND_DATA_WMSG will
					;  get *all* required send credits for the
					;  block transfer, this is why RECYCL_MSG_BUF
					;  is not needed.

	BISW	#HRB$M_STATE_INVALID,-	; The state of this request is "current"
		HRB$W_STATE(R3)		;  leave the old state for diagnosis
	BSBW	CLEANUP_HRB		; Deallocate all HRB held resources
	BRW	UNBLOCK			;  and drop the "current" counter
	
;
; not the last packet, just use a regular old SEND_DATA
; 
80$:
	MOVW	#HRB$K_ST_SNDAT_WAIT,-	; Set the state of this request to
		HRB$W_STATE(R3)		;  SCS block transfer
	SEND_DATA			; Send to host buffer

;
; This thread is suspended until the block transfer completes. At that time,
; control is returned here with the following registers:
;
;		R0  =  status
; 		R3  =  Host Request Buffer address
;		R4  =  PDT address
;		R5  =  CDRP address
;
	.IF DEFINED DEBUG$PC_HISTORY
	BSBW	PCHIST			; Save this PC if we are keeping track
	.ENDC	   ;DEBUG$PC_HISTORY
	BISW	#HRB$M_STATE_INVALID,-	; The state of this request is "current"
		HRB$W_STATE(R3)		;  leave the old state for diagnosis
	BLBC	R0,ABORT_READ		; If the send was not successful 
	BITW	#<HRB$M_ABORT!-		;  or if this request has been aborted,
		HRB$M_ABORTWS>,-	;  or canceled,
		HRB$W_FLAGS(R3)		;  just clean everything up
	BNEQ	ABORT_READ

;
; Update the accumulated byte count and compare to original to
; determine if another round is needed.  
;
	.IF DEFINED DEBUG$PC_HISTORY
	BSBW	PCHIST			; Save this PC if we are keeping track
	.ENDC	   ;DEBUG$PC_HISTORY
	DECL	HRB$L_CMD_STS(R3)	; Record the progress on this request
	MOVL	CDRP$L_XCT_LEN(R5),R0	; Pick up transfered bytes
	ASHL	#-VA$S_BYTE,R0,R1	; Make it blocks
	ADDL	R0,HRB$L_ABCNT(R3)	; Calc accumulated bytes xfered
	SUBL3	HRB$L_ABCNT(R3), -	; Calc how much left to do
		HRB$L_OBCNT(R3),R2
	BLEQU	100$			; None, we are finished
	CMPL	R2,HRB$L_BCNT(R3)	; Compare the number of bytes remaining
	BGEQU	90$			;  to the number just transferred and
	MOVL	R2,HRB$L_BCNT(R3)	;  use the smaller of the two values
90$:	ADDL	R1,HRB$L_LBN(R3)	; Update LBN
	MOVL	HRB$L_UQB(R3),R0	; Record the fact that the server
	INCL	UQB$L_EXTRA_IO(R0)	;  An extra I/O has to be done
	BRW	READ_LOOP		; Loop again

100$:	BUG_CHECK MSCPSERV, FATAL	; bytes remaining =< BCNT? Should have
					;  exited through SEND_DATA_WMSG
;
; If the send data was unsuccessful, just free the allocated resources, and
; this request is finished off.
; 
ABORT_READ:
	.IF DEFINED DEBUG$PC_HISTORY
	BSBW	PCHIST			; Save this PC if we are keeping track
	.ENDC	   ;DEBUG$PC_HISTORY
	BBS	#HRB$V_ABORT,-		; If this request was aborted due to a
		HRB$W_FLAGS(R3),10$	;  disconnect, no end msg is necessary
	MOVL	HRB$L_MSGBUF(R3),R2	; Get the message buffer address 
	MOVL	#MSCP$K_ST_ABRTD,R0	; Set the status to aborted
	BRW	SEND_END		;  and send out an end message

10$:	BSBW	CLEANUP_HRB		; Deallocate the resources used
	BRW	UNBLOCK			;  and start up any eligible requests
	.PAGE
	.SBTTL	-	XFER_ERR - Translate the class driver message to a MSCP message
;+
; Functional Description:
;
; This routine is called to translate the error from a system service 
; error message to the proper MSCP error code to return to the client 
; processor.
;
; Inputs:
;
;	R0  =  system service error code 
;	R3  =  HRB address
;
; Outputs:
;
;-

XFER_ERR::
	MOVAW	ERR_TBL,R2		; Get the address of the error table

XFER_ERR_ALT:				; Entry point with R2 already loaded

10$:	MOVZWL	(R2)+,R1		; Take the VMS error code out
	BEQL	20$			; Check for the end of the table
	CMPW	R1,R0			; Compare the VMS error with that passed
	BEQL	20$			; They matched! do the translation
	ADDL	#4,R2			; Step to next entry
	BRB	10$			;  and start it all over again

20$:	MOVZWL	(R2)+,R0		; Pick up the corresponding MSCP error
	CVTWL	(R2),R1			; Get possible routine
	BEQL	30$			; None
	JSB	(R1)[R2]		; Invoke the routine
;
; Do some final cleaning up. If this is an MSCP device
;  check for the MSCP status DUDRIVER may have stored in
;  the IOSB and if present, return it in the end message.
;
30$:    MOVL    HRB$L_UQB(R3), R4       ; Get the UQB
        MOVL    UQB$L_UCB(R4), R4       ; Get the UCB
        BBC     #DEV$V_MSCP,-           ; If this is not an MSCP device,
                UCB$L_DEVCHAR2(R4),35$  ;  don't check for MSCP status.
        MOVL    HRB$L_IRP_CDRP(R3),R5   ; Get the address of the IRP
        BEQL    35$                     ; Just in case no IRP
        MOVZWL  IRP$L_IOST2+2(R5),R4    ; Get the MSCP status from
        BEQL    35$                     ;  the IOSB .. make sure its there
        MOVL    R4,R0                   ; Move the MSCP status
35$:    MOVL    HRB$L_MSGBUF(R3),R2     ; MSCP packet address from the HRB
	MOVL	HRB$L_ABCNT(R3),-	; Set the byte count in the MSCP 
		MSCP$L_BYTE_CNT(R2)	;  to return to the requestor
	BRW	SEND_END		; Send an end packet with R0 status

ERR_TBL:
	ACTION	SS$_ABORT,MSCP$K_ST_ABRTD
	ACTION	SS$_MEDOFL,MSCP$K_ST_OFFLN,ERR_OFFLINE
	ACTION	SS$_VOLINV,MSCP$K_ST_OFFLN,ERR_OFFLINE
	ACTION	SS$_DEVOFFLINE,MSCP$K_ST_OFFLN,ERR_OFFLINE
	ACTION	SS$_WRITLCK,MSCP$K_ST_WRTPR,ERR_WRITLCK
	ACTION	SS$_DATACHECK,MSCP$K_ST_COMP,ERR_DATA
	ACTION	SS$_CTRLERR,MSCP$K_ST_CNTLR,ERR_OFFLINE
	ACTION	SS$_FORMAT,MSCP$K_ST_MFMTE
	ACTION	SS$_FORCEDERROR,MSCP$K_ST_DATA,ERR_DATA
	ACTION	SS$_PARITY,<<MSCP$K_ST_DATA>!<1*MSCP$K_ST_SBCOD>>,ERR_DATA
	ACTION	SS$_IVBUFLEN,MSCP$K_ST_HSTBF
	ACTION	SS$_TIMEOUT,<MSCP$K_ST_OFFLN!MSCP$K_SC_UNKNO>,ERR_OFFLINE
	ACTION	SS$_NOENTRY,<MSCP$K_ST_ICMD>,ERR_WLG
	ACTION	0,MSCP$K_ST_DRIVE	; PATCH SPACE
	ACTION	0,MSCP$K_ST_DRIVE,ERR_OFFLINE	; End of table - default error

ERR_OFFLINE:
	MOVL	HRB$L_UQB(R3),R4	; Get the UQB address
	MOVL	UQB$L_UCB(R4),R5	;  and follow that to the UCB address
	PUSHL	R0			; Save the MSCP error to return
20$:	MOVAL	UQB$B_ONLINE(R4),R1	; R1 -> online bitmap
	SKPC	#0,#MAX_HOSTS/8,-	; If there are no other hosts online,
		(R1)
	BEQL	60$			; we are finished, continue...
	FFS	#0,#8,(R1),R0		; Find host online
	BEQL	55$			; If EQL there is something wrong with SKIPC
	BBCC	R0,(R1),30$		; Clear this hosts bit
30$:	BBC	#DEV$V_MSCP,-		; If this isn't a MSCP device, it
		UCB$L_DEVCHAR2(R5),40$	;  can't be a shadow set.
	BBS	#MSCP$V_SHADOW,-	; If this is a shadow set virtual unit
		UCB$W_MSCPUNIT(R5),50$	;  don't change the online count
40$:	DECB	UCB$B_ONLCNT(R5)	;  and note the change in online count
50$:	CMPB	#-1,UCB$B_ONLCNT(R5)	; Check for underflow in online count
	BNEQ	20$			;  and proceed if OK.

55$:	BUG_CHECK MSCPSERV, FATAL	; Online count should NEVER be negative

;
; All the bits for this unit have been cleared. Now the status of this 
; device is changed in the UQB to "offline". This status may be changed
; to "available" by the GUS command, and then eventually to "online" 
; after the successful completion of an online command.
;
60$:	POPL	R0			; Restore the MSCP error to return
	MOVW	#UQB$K_ST_OFFLINE,-	; Now set the state of this device to
		UQB$W_STATE(R4)		;   reflect the sum of individual states
	RSB				;  and return with the device offline


ERR_WRITLCK:
	MOVL	HRB$L_UQB(R3),R4	; Get the UQB address 
	BBSS	#MSCP$V_UF_WRTPH,-	; Set the write protect bit in
		UQB$W_FLAGS(R4),10$	;  the unit flag field
10$:	RSB


ERR_DATA:
        MOVL    HRB$L_IRP_CDRP(R3),R5   ; Get the address of the IRP
	MOVL	IRP$L_BCNT(R5),-	; Get the number of bytes transferred
		HRB$L_BCNT(R3)		;  and save it away in the request block
	MOVAL	IRP$L_FQFL(R5),R5	; Move from the IRP to the CDRP address
	MOVL	CDRP$L_IOST1+2(R5),-	; Use the number of bytes retrieved
		CDRP$L_XCT_LEN(R5)	;  as the number to send to host
	POPL	R1			; ditch return address
60$:
;
; Initialize a CDRP that SCS can use to send the retrieved data to the 
; requesting system.
;
65$:	MOVL	HRB$L_HQB(R3),R1	; Get the HQB address 
	MOVL	HQB$L_CDT(R1),-		; Get the address of the CDT 
		CDRP$L_CDT(R5)		;  and place it in the CDRP for the call
	CLRL	CDRP$L_RWCPTR(R5)	; Clear RWAITCNT reference to avoid
					;  incorrect stalls.
	MOVL	HRB$L_MSGBUF(R3),R2	; Get the MSCP packet address back
	MOVAL	MSCP$B_BUFFER(R2),-	; Get the remote buffer handle
		CDRP$L_RBUFH_AD(R5)	;  and save it for the call
	MOVL	HRB$L_ABCNT(R3),-	; Figure out the offset into the 
		CDRP$L_RBOFF(R5)	;  remote buffer 
	MOVAL	HRB$B_LBUFF(R3),-	; Define the local buffer handle as
		CDRP$L_LBUFH_AD(R5)	;  the address of LBUFF
	CLRL	CDRP$L_LBOFF(R5)	;  in the remote and local buffers
	MOVL	HRB$L_PDT(R3),R4	; Get the PDT address for the SCS call
;
; This block transfer can contain all remaining bytes for the request.
; Issue combined SEND_DATA with piggyback end message request for this final
; transfer of the request.

;
; fill in the End Packet information
; 
	movw	r0,MSCP$W_STATUS(R2)	;  SEND_DATA_WMSG will complete sucessfully
					;  or SCS will not deliver the piggyback
					;  end packet!)
	ADDL2	CDRP$L_XCT_LEN(R5),-	; Add bytes transferred to
		HRB$L_ABCNT(R3)		;  ABCNT.
	MOVL	HRB$L_ABCNT(R3),-	; update the HRB, why not... 
		MSCP$L_BYTE_CNT(R2)	;  nothing short of disaster could stop
					;  the last packet now!
	MOVZBL	MSCP$B_OPCODE(R2),R1	; get opcode
	BISB2	#MSCP$K_OP_END,-	; Reset the op-code to
		MSCP$B_OPCODE(R2)	;  make an end packet
	MOVZBL	END_PKT_LEN[R1],R1	; Get the message length from the table
	MOVL	R2,CDRP$L_MSG_BUF(R5)	; Put the message buffer address into
	.IF DEFINED DEBUG$LOG

	ASSUME DSRV$V_LOG_ENABLD  EQ  0

	MOVL	G^SCS$GL_MSCP,R0	; Get the DSRV address.
	BLBC	DSRV$W_STATE(R0),70$	; Branch if logging is disabled.
	BSBW	LOG_END_PKT		; Otherwise, log the end packet.
70$:	.ENDC

	CLRL	HRB$L_MSGBUF(R3)	; Message buffer belongs to SCS again
	MOVW	#HRB$K_ST_SNDAT_WAIT,-	; Set the state for this request
		HRB$W_STATE(R3)		;  before calling SCS service
	
	SEND_DATA_WMSG			; send the last SEND_DATA w/piggyback
					;  end message. NOTE: SEND_DATA_WMSG will
					;  get *all* required send credits for the
					;  block transfer, this is why RECYCL_MSG_BUF
					;  is not needed.

	BISW	#HRB$M_STATE_INVALID,-	; The state of this request is "current"
		HRB$W_STATE(R3)		;  leave the old state for diagnosis
	BSBW	CLEANUP_HRB		; Deallocate all HRB held resources
	BRW	UNBLOCK			;  and drop the "current" counter
;
; Write logging related error.
;
ERR_WLG:
	POPL	R0			; Get rid of return address of XFER_ERR
					;  Going to send_pkt directly.

	MOVL	HRB$L_MSGBUF(R3),R2	; Reload message buffer
	MOVL	#<MSCP$W_HRN@24>,R0	; Prepare for a write logging error return
	MOVB	MSCP$B_OPCODE(R2),R0
	BISL3	#<MSCP$K_ST_ICMD@16-	; The command sent was invalid
		!MSCP$K_OP_END>,-	; Identify this as an end message
		R0,MSCP$B_OPCODE(R2)	; Put all this info back in the packet
	MOVL	#MSCP$K_MXCMDLEN,R1	; Use the minimum size possible
	BRW	SEND_PKT		;  and send out the end message

============================= ALPHA ===================================

************
File WORK7:[MORONEY.MSCP.SRC]MSCP.MAR;16
    6   	.IDENT	'X-63'
    7   
    8   	SOFTWARE_REV == 63	; Keep software rev level equal to ident field
    9   				;  for easier remote diagnosis
******
File WORK7:[MORONEY.MSCP.SRC2]MSCP.MAR;1
    6   	.IDENT	'X-62'
    7   
    8   	SOFTWARE_REV == 62	; Keep software rev level equal to ident field
    9   				;  for easier remote diagnosis
************
************
File WORK7:[MORONEY.MSCP.SRC]MSCP.MAR;16
   58   ;       X-63    MJM		Michael J. Moroney		26-Mar-1997
   59   ;		Make Forced Errors return partial transfer counts rather
   60   ;		than 0 bytes, to make it consistant with non-served disks.
   61   ;
   62   ;       X-62    RFB004		Ray Boucher                      7-Aug-1996
******
File WORK7:[MORONEY.MSCP.SRC2]MSCP.MAR;1
   58   ;       X-62    RFB004		Ray Boucher                      7-Aug-1996
************
************
File WORK7:[MORONEY.MSCP.SRC]MSCP.MAR;16
 1301   FULL:	MOVL	#SS$_DEVICEFULL,R0	; There are already MAX_UNITS
 1302   	BRW	RESTOR			;  being served
******
File WORK7:[MORONEY.MSCP.SRC2]MSCP.MAR;1
 1297   FULL:	MOVL	#SS$_DEVICEFULL,R0	; There are already MSX_UNITS
 1298   	BRW	RESTOR			;  being served
************
************
File WORK7:[MORONEY.MSCP.SRC]MSCP.MAR;16
 4752   115$:	CMPL	R1,#MSCP$K_ST_DATA	; Parity or Forced Error
 4753   	BNEQ	118$			; If NEQ no
 4754   	MOVL	IRP$L_IOST1+2(R5), -	; Pick up the number of bytes
 4755   		HRB$L_ABCNT(R3)		;  transfered and update ABCNT.
 4756   	BRW	130$			; Merge
 4757   118$:	CMPL	R1,#MSCP$K_ST_ICMD	; Invalid command
 4758   	BNEQ	120$			; If NEQ no
******
File WORK7:[MORONEY.MSCP.SRC2]MSCP.MAR;1
 4748   115$:	CMPL	R1,#MSCP$K_ST_ICMD	; Invalid command
 4749   	BNEQ	120$			; If NEQ no
************
************
File WORK7:[MORONEY.MSCP.SRC]MSCP.MAR;16
 5135   	BLBS	R0,64$			; The request succeeded...
 5136   
 5137   	MOVAB	ERR_TBL,R2		; Get the address of the error table
 5138   	BSBW 	XFER_ERR		; Get the MSCP error code
 5139   	BICL3	#^cMSCP$M_ST_MASK,R0,R1	; Extract major MSCP status
 5140   	CMPL	R1,#MSCP$K_ST_DATA	; Parity or Forced Error
 5141   	BNEQ	61$			; If NEQ no
 5142   ;
 5143   ; Send the data to the host buffer
 5144   ;
 5145   	MOVL	IRP$L_IOST1+2(R5),-	; Get the number of bytes transferred
 5146   		HRB$L_BCNT(R3)		;  and save it away in the request block
 5147   	MOVAL	IRP$L_FQFL(R5),R5	; Move from the IRP to the CDRP address
 5148   
 5149   	MOVL	HRB$L_MSGBUF(R3),R2	; Get the MSCP packet address back
 5150   	MOVW	R0,MSCP$W_STATUS(R2)	; Indicate Parity or Forced Error in msg
 5151   ;
 5152   ; Increment the HULB counter for load balancing purposes
 5153   ; (note: if the transfer is segmented, the counter will be bumped for each
 5154   ; segment)
 5155   ;
 5156   	CLRL	R0			; Ensure that R0 has no excess baggage
 5157   	BICW3	#MSCP$M_SLUN,-		; Extract unit number for use as index,
 5158   		MSCP$W_UNIT(R2),R0	;  clearing the SLUN bit
 5159   	MOVL	HRB$L_HQB(R3),R1	; Pick up HQB
 5160   	MOVL	HQB$L_HULB_VECTOR(R1),R1; Get pointer to HQB vector
 5161   	BEQL	60$			; HULB vector has vanished...
 5162   	MOVL	(R1)[R0],R1		; Index into vector with unit number.
 5163   	BEQL	60$			; HULB has vanished...
 5164   	INCW	HULB$W_OPCOUNT(R1)	; Increment HULB counter.
 5165   ;
 5166   ; Initialize a CDRP that SCS can use to send the retrieved data to the 
 5167   ; requesting system.
 5168   ;
 5169   60$:	MOVL	HRB$L_HQB(R3),R1	; Get the HQB address 
 5170   	MOVL	HQB$L_CDT(R1),-		; Get the address of the CDT 
******
File WORK7:[MORONEY.MSCP.SRC2]MSCP.MAR;1
 5126   	BLBC	R0,51$			; The request failed, return the error
 5127   ;
 5128   ; Send the data to the host buffer
 5129   ;
 5130   60$:	MOVL	IRP$L_BCNT(R5),-	; Get the number of bytes transferred
 5131   		HRB$L_BCNT(R3)		;  and save it away in the request block
 5132   	MOVAL	IRP$L_FQFL(R5),R5	; Move from the IRP to the CDRP address
 5133   
 5134   ;
 5135   ; Increment the HULB counter for load balancing purposes
 5136   ; (note: if the transfer is segmented, the counter will be bumped for each
 5137   ; segment)
 5138   ;
 5139   	CLRL	R0			; Ensure that R0 has no excess baggage
 5140   	BICW3	#MSCP$M_SLUN,-		; Extract unit number for use as index,
 5141   		MSCP$W_UNIT(R2),R0	;  clearing the SLUN bit
 5142   	MOVL	HRB$L_HQB(R3),R1	; Pick up HQB
 5143   	MOVL	HQB$L_HULB_VECTOR(R1),R1; Get pointer to HQB vector
 5144   	BEQL	65$			; HULB vector has vanished...
 5145   	MOVL	(R1)[R0],R1		; Index into vector with unit number.
 5146   	BEQL	65$			; HULB has vanished...
 5147   	INCW	HULB$W_OPCOUNT(R1)	; Increment HULB counter.
 5148   ;
 5149   ; Initialize a CDRP that SCS can use to send the retrieved data to the 
 5150   ; requesting system.
 5151   ;
 5152   65$:	MOVL	HRB$L_HQB(R3),R1	; Get the HQB address 
 5153   	MOVL	HQB$L_CDT(R1),-		; Get the address of the CDT 
************
************
File WORK7:[MORONEY.MSCP.SRC]MSCP.MAR;16
 5186   ; fill in the End Packet information
 5187   ; 
 5188   	ADDL3	HRB$L_ABCNT(R3),-	; bytes sent prior to this
 5189   		CDRP$L_XCT_LEN(R5),-	;  + bytes to be sent this transfer 
 5190   		MSCP$L_BYTE_CNT(R2)	;  = total bytes transfered
 5191   	MOVL	MSCP$L_BYTE_CNT(R2),-	; update the HRB, why not... 
******
File WORK7:[MORONEY.MSCP.SRC2]MSCP.MAR;1
 5169   ; Check if this will be the last block tranfer for this request, that is
 5170   ; bytes left to send =< size of each block transfer.
 5171   ;
 5172   	SUBL3	HRB$L_ABCNT(R3),-	; Get bytes left to tranfer for this
 5173   		HRB$L_OBCNT(R3),R1	;  Request (OBCNT-ABCNT)
 5174   	CMPL	R1,HRB$L_BCNT(R3)	; (OBCNT - ABCNT) =< BCNT)?
 5175   	BGTRU	80$			; If GTR no, use plain SEND_DATA
 5176   ;
 5177   ; This block transfer can contain all remaining bytes for the request.
 5178   ; Issue combined SEND_DATA with piggyback end message request for this final
 5179   ; transfer of the request.
 5180   
 5181   ;
 5182   ; fill in the End Packet information
 5183   ; 
 5184   	ADDL3	HRB$L_ABCNT(R3),-	; bytes sent prior to this
 5185   		CDRP$L_XCT_LEN(R5),-	;  + bytes to be sent this transfer 
 5186   		MSCP$L_BYTE_CNT(R2)	;  = total bytes transfered
 5187   	ASSUME  MSCP$K_ST_SUCC EQ 0	; set status success (Note: either the 
 5188   	CLRW	MSCP$W_STATUS(R2)	;  SEND_DATA_WMSG will complete sucessfully
 5189   					;  or SCS will not deliver the piggyback
 5190   					;  end packet!)
 5191   	MOVL	MSCP$L_BYTE_CNT(R2),-	; update the HRB, why not... 
************
************
File WORK7:[MORONEY.MSCP.SRC]MSCP.MAR;16
 5226   
 5227   
 5228   
 5229   61$:	CMPL	R1,#MSCP$K_ST_OFFLN	; Was this one of the offline errors?
 5230   	BNEQ	62$			; If not test for write lock
 5231   	BSBW	ERR_OFFLINE		; Otherwise do some offline processing
 5232   	BRW	63$			;  and go to the common exit
 5233   62$:	CMPL	R1,#MSCP$K_ST_WRTPR	; Was this a write lock error?
 5234   	BNEQ	63$			; If not just return the error
 5235   	MOVL	HRB$L_UQB(R3),R4	; Get the UQB address 
 5236   	BBSS	#MSCP$V_UF_WRTPH,-	; Set the write protect bit in
 5237   		UQB$W_FLAGS(R4),53$	;  the unit flag field
 5238   63$:	MOVL	HRB$L_MSGBUF(R3),R2	; MSCP packet address from the HRB
 5239   	MOVL	HRB$L_ABCNT(R3),-	; Set the byte count in the MSCP 
 5240   		MSCP$L_BYTE_CNT(R2)	;  to return to the requestor
 5241   	BRW	SEND_END		; Send an end packet with R0 status
 5242   ;
 5243   ; Send the data to the host buffer
 5244   ;
 5245   64$:	MOVL	IRP$L_IOST1+2(R5),-	; Get the number of bytes transferred
 5246   		HRB$L_BCNT(R3)		;  and save it away in the request block
 5247   	MOVAL	IRP$L_FQFL(R5),R5	; Move from the IRP to the CDRP address
 5248   
 5249   ;
 5250   ; Increment the HULB counter for load balancing purposes
 5251   ; (note: if the transfer is segmented, the counter will be bumped for each
 5252   ; segment)
 5253   ;
 5254   	CLRL	R0			; Ensure that R0 has no excess baggage
 5255   	BICW3	#MSCP$M_SLUN,-		; Extract unit number for use as index,
 5256   		MSCP$W_UNIT(R2),R0	;  clearing the SLUN bit
 5257   	MOVL	HRB$L_HQB(R3),R1	; Pick up HQB
 5258   	MOVL	HQB$L_HULB_VECTOR(R1),R1; Get pointer to HQB vector
 5259   	BEQL	65$			; HULB vector has vanished...
 5260   	MOVL	(R1)[R0],R1		; Index into vector with unit number.
 5261   	BEQL	65$			; HULB has vanished...
 5262   	INCW	HULB$W_OPCOUNT(R1)	; Increment HULB counter.
 5263   ;
 5264   ; Initialize a CDRP that SCS can use to send the retrieved data to the 
 5265   ; requesting system.
 5266   ;
 5267   65$:	MOVL	HRB$L_HQB(R3),R1	; Get the HQB address 
 5268   	MOVL	HQB$L_CDT(R1),-		; Get the address of the CDT 
 5269   		CDRP$L_CDT(R5)		;  and place it in the CDRP for the call
 5270   	CLRL	CDRP$L_RWCPTR(R5)	; Clear RWAITCNT reference to avoid
 5271   					;  incorrect stalls.
 5272   	MOVL	HRB$L_BCNT(R3),-	; Use the number of bytes retrieved
 5273   		CDRP$L_XCT_LEN(R5)	;  as the number to send to host
 5274   	MOVL	HRB$L_MSGBUF(R3),R2	; Get the MSCP packet address back
 5275   	MOVAL	MSCP$B_BUFFER(R2),-	; Get the remote buffer handle
 5276   		CDRP$L_RBUFH_AD(R5)	;  and save it for the call
 5277   	MOVL	HRB$L_ABCNT(R3),-	; Figure out the offset into the 
 5278   		CDRP$L_RBOFF(R5)	;  remote buffer 
 5279   	MOVAL	HRB$B_LBUFF(R3),-	; Define the local buffer handle as
 5280   		CDRP$L_LBUFH_AD(R5)	;  the address of LBUFF
 5281   	CLRL	CDRP$L_LBOFF(R5)	;  in the remote and local buffers
 5282   	MOVL	HRB$L_PDT(R3),R4	; Get the PDT address for the SCS call
 5283   ;
 5284   ; Check if this will be the last block tranfer for this request, that is
 5285   ; bytes left to send =< size of each block transfer.
 5286   ;
 5287   	SUBL3	HRB$L_ABCNT(R3),-	; Get bytes left to tranfer for this
 5288   		HRB$L_OBCNT(R3),R1	;  Request (OBCNT-ABCNT)
 5289   	CMPL	R1,HRB$L_BCNT(R3)	; (OBCNT - ABCNT) =< BCNT)?
 5290   	BGTRU	80$			; If GTR no, use plain SEND_DATA
 5291   ;
 5292   ; This block transfer can contain all remaining bytes for the request.
 5293   ; Issue combined SEND_DATA with piggyback end message request for this final
 5294   ; transfer of the request.
 5295   
 5296   ;
 5297   ; fill in the End Packet information
 5298   ; 
 5299   	ADDL3	HRB$L_ABCNT(R3),-	; bytes sent prior to this
 5300   		CDRP$L_XCT_LEN(R5),-	;  + bytes to be sent this transfer 
 5301   		MSCP$L_BYTE_CNT(R2)	;  = total bytes transfered
 5302   	ASSUME  MSCP$K_ST_SUCC EQ 0	; set status success (Note: either the 
 5303   	CLRW	MSCP$W_STATUS(R2)	;  SEND_DATA_WMSG will complete sucessfully
 5304   					;  or SCS will not deliver the piggyback
 5305   					;  end packet!)
 5306   	MOVL	MSCP$L_BYTE_CNT(R2),-	; update the HRB, why not... 
 5307   		HRB$L_ABCNT(R3)		;  nothing short of disaster could stop
 5308   					;  the last packet now!
 5309   	MOVZBL	MSCP$B_OPCODE(R2),R1	; get opcode
 5310   	BISB2	#MSCP$K_OP_END,-	; Reset the op-code to
 5311   		MSCP$B_OPCODE(R2)	;  make an end packet
 5312   	MOVZBL	L^END_PKT_LEN[R1],R1	; Get the message length from the table
 5313   	MOVL	R2,CDRP$L_MSG_BUF(R5)	; Put the message buffer address into
 5314   	.IF DEFINED DEBUG$LOG
 5315   
 5316   	ASSUME DSRV$V_LOG_ENABLD  EQ  0
 5317   
 5318   	MOVL	G^SCS$GL_MSCP,R0	; Get the DSRV address.
 5319   	BLBC	DSRV$W_STATE(R0),70$	; Branch if logging is disabled.
 5320           PUSHL	R0
 5321   	MOVL	#PKT$C_MSCP_END,R0
 5322   	BSBW	LOG_PKT		; Otherwise, log the end packet.
 5323   	POPL	R0
 5324   70$:	
 5325   	.ENDC
 5326   
 5327   	CLRL	HRB$L_MSGBUF(R3)	; Message buffer belongs to SCS again
 5328   	MOVW	#HRB$K_ST_SNDAT_WAIT,-	; Set the state for this request
 5329   		HRB$W_STATE(R3)		;  before calling SCS service
 5330   	
 5331   	SEND_DATA_WMSG			; send the last SEND_DATA w/piggyback
 5332   					;  end message. NOTE: SEND_DATA_WMSG will
 5333   					;  get *all* required send credits for the
 5334   					;  block transfer, this is why RECYCL_MSG_BUF
 5335   					;  is not needed.
 5336   
 5337   	BISW	#HRB$M_STATE_INVALID,-	; The state of this request is "current"
 5338   		HRB$W_STATE(R3)		;  leave the old state for diagnosis
 5339   	BSBW	CLEANUP_HRB		; Deallocate all HRB held resources
 5340   	BRW	UNBLOCK			;  and drop the "current" counter
 5341   	
******
File WORK7:[MORONEY.MSCP.SRC2]MSCP.MAR;1
 5226   	
************
************
File WORK7:[MORONEY.MSCP.SRC]MSCP.MAR;16
 5728   	BRW	49$			;  and go to the common exit
 5729   46$:	CMPL	R1,#MSCP$K_ST_DATA	; Parity or Forced Error
 5730   	BEQL	47$			; If EQL yes
 5731   	CMPL	R1,#MSCP$K_ST_COMP	; Datacheck or Host Compare Error
 5732   	BNEQ	48$			; If NEQ no
 5733   47$:	MOVL	IRP$L_IOST1+2(R5), -	; Pick up the number of bytes
 5734   		HRB$L_ABCNT(R3)		;  transfered and update ABCNT.
 5735   	BRB	49$			; Merge
 5736   48$:	CMPL	R1,#MSCP$K_ST_WRTPR	; Was this a write lock error?
 5737   	BNEQ	49$			; If not just return the error
 5738   	MOVL	HRB$L_UQB(R3),R4	; Get the UQB address 
 5739   	BBSS	#MSCP$V_UF_WRTPH,-	; Set the write protect bit in
 5740   		UQB$W_FLAGS(R4),49$	;  the unit flag field
 5741   49$:	MOVL	HRB$L_MSGBUF(R3),R2	; MSCP packet address from the HRB
 5742   	MOVL	HRB$L_ABCNT(R3),-	; Set the byte count in the MSCP 
******
File WORK7:[MORONEY.MSCP.SRC2]MSCP.MAR;1
 5613   	BRW	47$			;  and go to the common exit
 5614   46$:	CMPL	R1,#MSCP$K_ST_WRTPR	; Was this a write lock error?
 5615   	BNEQ	47$			; If not just return the error
 5616   	MOVL	HRB$L_UQB(R3),R4	; Get the UQB address 
 5617   	BBSS	#MSCP$V_UF_WRTPH,-	; Set the write protect bit in
 5618   		UQB$W_FLAGS(R4),47$	;  the unit flag field
 5619   47$:	MOVL	HRB$L_MSGBUF(R3),R2	; MSCP packet address from the HRB
 5620   	MOVL	HRB$L_ABCNT(R3),-	; Set the byte count in the MSCP 
************

Number of difference sections found: 8
Number of difference records found: 200

DIFFERENCES /IGNORE=()/MATCH=12/MERGED=1/OUTPUT=WORK7:[MORONEY.MSCP.SRC]MSCP.DIF;1-
    WORK7:[MORONEY.MSCP.SRC]MSCP.MAR;16-
    WORK7:[MORONEY.MSCP.SRC2]MSCP.MAR;1

;+
; Resumed here when the transfer has completed
;
;   Inputs to the async completion routine:
;	R0 contains the I/O status  block
;	R1 contains the address of the UCB
;	R2 contains the message buffer address
;	R3 contains the address of the HRB
;	R4 contains the address of the UQB
;	R5 contains the address of the IRP
;
;   Outputs;
;
;	R0-R5 may be destroyed
;
;-

80$:	.JSB_ENTRY 	INPUT=<R0,R1,R2,R3,R4,R5>, -
			SCRATCH=<R0,R1,R2,R3,R4,R5>

	BLBC	R0,110$			; Branch if transfer error
	DECL	HRB$L_CMD_STS(R3)	; Report progress on this request
	MOVL	HRB$L_IRP_CDRP(R3),R5	; Get the address of the IRP back
	MOVL	IRP$L_BCNT(R5),R0	;  and find out how many bytes sent
	ASHL	#-IOC$V_BLOCK_BLKNUM,-	; Convert the number of bytes specified
		R0,R1			;  into a block count
	ADDL	R0,HRB$L_ABCNT(R3)	; Update the bytes sent so far
	SUBL3	HRB$L_ABCNT(R3),-	; Determine how many characters 
		HRB$L_OBCNT(R3),R2	;  remain to be sent
	BLEQU	100$			; Nothing left, the erase is finished
	CMPL	R2,HRB$L_BCNT(R3)	; If the number of bytes remaining
	BGEQU	90$			;  is less than that just transferred,
	MOVL	R2,HRB$L_BCNT(R3)	;  then shrink the size of the request
90$:	MOVL	HRB$L_BCNT(R3),-	; Move the size of the request we
		IRP$L_BCNT(R5)		;  finally decided on into the IRP
	ADDL	R1,HRB$L_LBN(R3)	; Move logically down the disk
	MOVL	HRB$L_UQB(R3),R4	; Record the fact that the server
	INCL	UQB$L_EXTRA_IO(R4)	;  had to split the transfer
	BBC	#IRP$V_WLE,-		; Write logging?
		IRP$L_STS2(R5),72$	;  No  - process next segment

; At this point a check is made to see if there was an allocation failure
; for the write log entry. If so, the server must still attempt to complete
; the Erase operation for all segments (per MSCP spec: 6.9.3) with write
; logging turned off. If there was no allocation failure, there is only
; one entry for the client node to do the write so the supplemental write
; log- and force-reuse flags are set. The client request might or might not
; have the reuse flag set, but it is appropriate to set it now since
; the write/erase is being fragmented.

	CMPW	#^XFFFF,IRP$L_CLN_WLE(R5); Watch out for exhaustion
	BNEQ	95$			;
	BICL	#IRP$M_WLE,-		; Stop write log.
		IRP$L_STS2(R5)		;
	BRB	72$			;
95$:
	BISB	#<IRP$M_WLE_REUSE!-	; Force the reuse bit
		  IRP$M_WLE_SUPWL>,-	;  and  the supplement bit
		IRP$B_WLG_FLAGS(R5)	;  in IRP.

	BRB	72$			; Send the next chunk of zeros

100$:	MOVL	#MSCP$K_ST_SUCC,R0	; Set the completion code to success
	BRW	130$

110$:		
	MOVAB	ERR_TBL,R2		; Get the address of the error table
	BSBW 	XFER_ERR		; Otherwise get the MSCP error code
	BICL3	#^cMSCP$M_ST_MASK, -	; Extract major MSCP status
		R0, R1			;  
	CMPL	R1,#MSCP$K_ST_OFFLN	; Was this one of the offline erroR
	BNEQ	115$			; If NEQ no
	BSBW	ERR_OFFLINE             ; Otherwise do some offline processing 
	BRW	130$			; Merge
115$:	CMPL	R1,#MSCP$K_ST_DATA	; Parity or Forced Error
	BNEQ	118$			; If NEQ no
	MOVL	IRP$L_IOST1+2(R5), -	; Pick up the number of bytes
		HRB$L_ABCNT(R3)		;  transfered and update ABCNT.
	BRW	130$			; Merge
118$:	CMPL	R1,#MSCP$K_ST_ICMD	; Invalid command
	BNEQ	120$			; If NEQ no
	BSBW	ERR_WLG			; Report WLG invalid command
	CLRL	HRB$L_ABCNT(R3)		; Zero transferred bytecount
	BRW	130$			; Merge
120$:	CMPL	R1,#MSCP$K_ST_WRTPR	; Was this a write lock error?
	BNEQ	130$			; If not just return the error
	MOVL	HRB$L_UQB(R3),R4	; Get the UQB address 
	BBSS	#MSCP$V_UF_WRTPH,-	; Set the write protect bit in
		UQB$W_FLAGS(R4),130$	;  the unit flag field

130$:	MOVL	HRB$L_MSGBUF(R3),R2	; MSCP packet address from the HRB
	BBC	#MSCP$V_MD_HISLO,-	; If not write logging, continue
		MSCP$W_MODIFIER(R2),135$;
        MOVL    IRP$L_CLN_WLE(R5),-	; Copy (entry id, entrylocator)
                MSCP$W_HRN(R2)		;
135$:	MOVL	HRB$L_ABCNT(R3),-	; Set the byte count in the MSCP 
		MSCP$L_BYTE_CNT(R2)	;  to return to the requestor
	BRW	SEND_END		; Send an end packet with R0 status



;+
; Resumed here when the transfer has completed
;
;   Inputs to the async completion routine:
;	R0 I/O status  block
;	R1 address of the UCB
;	R2 message buffer address
;	R3 address of the HRB
;	R4 address of the UQB
;	R5 address of the IRP
;
;   Outputs;
;	R0-R5 may be destroyed
;-

55$:	.JSB_ENTRY 	INPUT=<R0,R1,R2,R3,R4,R5>, -
			SCRATCH=<R0,R1,R2,R3,R4,R5>

	BLBS	R0,64$			; The request succeeded...

	MOVAB	ERR_TBL,R2		; Get the address of the error table
	BSBW 	XFER_ERR		; Get the MSCP error code
	BICL3	#^cMSCP$M_ST_MASK,R0,R1	; Extract major MSCP status
	CMPL	R1,#MSCP$K_ST_DATA	; Parity or Forced Error
	BNEQ	61$			; If NEQ no
;
; Send the data to the host buffer
;
	MOVL	IRP$L_IOST1+2(R5),-	; Get the number of bytes transferred
		HRB$L_BCNT(R3)		;  and save it away in the request block
	MOVAL	IRP$L_FQFL(R5),R5	; Move from the IRP to the CDRP address

	MOVL	HRB$L_MSGBUF(R3),R2	; Get the MSCP packet address back
	MOVW	R0,MSCP$W_STATUS(R2)	; Indicate Parity or Forced Error in msg
;
; Increment the HULB counter for load balancing purposes
; (note: if the transfer is segmented, the counter will be bumped for each
; segment)
;
	CLRL	R0			; Ensure that R0 has no excess baggage
	BICW3	#MSCP$M_SLUN,-		; Extract unit number for use as index,
		MSCP$W_UNIT(R2),R0	;  clearing the SLUN bit
	MOVL	HRB$L_HQB(R3),R1	; Pick up HQB
	MOVL	HQB$L_HULB_VECTOR(R1),R1; Get pointer to HQB vector
	BEQL	60$			; HULB vector has vanished...
	MOVL	(R1)[R0],R1		; Index into vector with unit number.
	BEQL	60$			; HULB has vanished...
	INCW	HULB$W_OPCOUNT(R1)	; Increment HULB counter.
;
; Initialize a CDRP that SCS can use to send the retrieved data to the 
; requesting system.
;
60$:	MOVL	HRB$L_HQB(R3),R1	; Get the HQB address 
	MOVL	HQB$L_CDT(R1),-		; Get the address of the CDT 
		CDRP$L_CDT(R5)		;  and place it in the CDRP for the call
	CLRL	CDRP$L_RWCPTR(R5)	; Clear RWAITCNT reference to avoid
					;  incorrect stalls.
	MOVL	HRB$L_BCNT(R3),-	; Use the number of bytes retrieved
		CDRP$L_XCT_LEN(R5)	;  as the number to send to host
	MOVL	HRB$L_MSGBUF(R3),R2	; Get the MSCP packet address back
	MOVAL	MSCP$B_BUFFER(R2),-	; Get the remote buffer handle
		CDRP$L_RBUFH_AD(R5)	;  and save it for the call
	MOVL	HRB$L_ABCNT(R3),-	; Figure out the offset into the 
		CDRP$L_RBOFF(R5)	;  remote buffer 
	MOVAL	HRB$B_LBUFF(R3),-	; Define the local buffer handle as
		CDRP$L_LBUFH_AD(R5)	;  the address of LBUFF
	CLRL	CDRP$L_LBOFF(R5)	;  in the remote and local buffers
	MOVL	HRB$L_PDT(R3),R4	; Get the PDT address for the SCS call
;
; fill in the End Packet information
; 
	ADDL3	HRB$L_ABCNT(R3),-	; bytes sent prior to this
		CDRP$L_XCT_LEN(R5),-	;  + bytes to be sent this transfer 
		MSCP$L_BYTE_CNT(R2)	;  = total bytes transfered
	MOVL	MSCP$L_BYTE_CNT(R2),-	; update the HRB, why not... 
		HRB$L_ABCNT(R3)		;  nothing short of disaster could stop
					;  the last packet now!
	MOVZBL	MSCP$B_OPCODE(R2),R1	; get opcode
	BISB2	#MSCP$K_OP_END,-	; Reset the op-code to
		MSCP$B_OPCODE(R2)	;  make an end packet
	MOVZBL	L^END_PKT_LEN[R1],R1	; Get the message length from the table
	MOVL	R2,CDRP$L_MSG_BUF(R5)	; Put the message buffer address into
	.IF DEFINED DEBUG$LOG

	ASSUME DSRV$V_LOG_ENABLD  EQ  0

	MOVL	G^SCS$GL_MSCP,R0	; Get the DSRV address.
	BLBC	DSRV$W_STATE(R0),70$	; Branch if logging is disabled.
        PUSHL	R0
	MOVL	#PKT$C_MSCP_END,R0
	BSBW	LOG_PKT		; Otherwise, log the end packet.
	POPL	R0
70$:	
	.ENDC

	CLRL	HRB$L_MSGBUF(R3)	; Message buffer belongs to SCS again
	MOVW	#HRB$K_ST_SNDAT_WAIT,-	; Set the state for this request
		HRB$W_STATE(R3)		;  before calling SCS service
	
	SEND_DATA_WMSG			; send the last SEND_DATA w/piggyback
					;  end message. NOTE: SEND_DATA_WMSG will
					;  get *all* required send credits for the
					;  block transfer, this is why RECYCL_MSG_BUF
					;  is not needed.

	BISW	#HRB$M_STATE_INVALID,-	; The state of this request is "current"
		HRB$W_STATE(R3)		;  leave the old state for diagnosis
	BSBW	CLEANUP_HRB		; Deallocate all HRB held resources
	BRW	UNBLOCK			;  and drop the "current" counter



61$:	CMPL	R1,#MSCP$K_ST_OFFLN	; Was this one of the offline errors?
	BNEQ	62$			; If not test for write lock
	BSBW	ERR_OFFLINE		; Otherwise do some offline processing
	BRW	63$			;  and go to the common exit
62$:	CMPL	R1,#MSCP$K_ST_WRTPR	; Was this a write lock error?
	BNEQ	63$			; If not just return the error
	MOVL	HRB$L_UQB(R3),R4	; Get the UQB address 
	BBSS	#MSCP$V_UF_WRTPH,-	; Set the write protect bit in
		UQB$W_FLAGS(R4),53$	;  the unit flag field
63$:	MOVL	HRB$L_MSGBUF(R3),R2	; MSCP packet address from the HRB
	MOVL	HRB$L_ABCNT(R3),-	; Set the byte count in the MSCP 
		MSCP$L_BYTE_CNT(R2)	;  to return to the requestor
	BRW	SEND_END		; Send an end packet with R0 status
;
; Send the data to the host buffer
;
64$:	MOVL	IRP$L_IOST1+2(R5),-	; Get the number of bytes transferred
		HRB$L_BCNT(R3)		;  and save it away in the request block
	MOVAL	IRP$L_FQFL(R5),R5	; Move from the IRP to the CDRP address

;
; Increment the HULB counter for load balancing purposes
; (note: if the transfer is segmented, the counter will be bumped for each
; segment)
;
	CLRL	R0			; Ensure that R0 has no excess baggage
	BICW3	#MSCP$M_SLUN,-		; Extract unit number for use as index,
		MSCP$W_UNIT(R2),R0	;  clearing the SLUN bit
	MOVL	HRB$L_HQB(R3),R1	; Pick up HQB
	MOVL	HQB$L_HULB_VECTOR(R1),R1; Get pointer to HQB vector
	BEQL	65$			; HULB vector has vanished...
	MOVL	(R1)[R0],R1		; Index into vector with unit number.
	BEQL	65$			; HULB has vanished...
	INCW	HULB$W_OPCOUNT(R1)	; Increment HULB counter.
;
; Initialize a CDRP that SCS can use to send the retrieved data to the 
; requesting system.
;
65$:	MOVL	HRB$L_HQB(R3),R1	; Get the HQB address 
	MOVL	HQB$L_CDT(R1),-		; Get the address of the CDT 
		CDRP$L_CDT(R5)		;  and place it in the CDRP for the call
	CLRL	CDRP$L_RWCPTR(R5)	; Clear RWAITCNT reference to avoid
					;  incorrect stalls.
	MOVL	HRB$L_BCNT(R3),-	; Use the number of bytes retrieved
		CDRP$L_XCT_LEN(R5)	;  as the number to send to host
	MOVL	HRB$L_MSGBUF(R3),R2	; Get the MSCP packet address back
	MOVAL	MSCP$B_BUFFER(R2),-	; Get the remote buffer handle
		CDRP$L_RBUFH_AD(R5)	;  and save it for the call
	MOVL	HRB$L_ABCNT(R3),-	; Figure out the offset into the 
		CDRP$L_RBOFF(R5)	;  remote buffer 
	MOVAL	HRB$B_LBUFF(R3),-	; Define the local buffer handle as
		CDRP$L_LBUFH_AD(R5)	;  the address of LBUFF
	CLRL	CDRP$L_LBOFF(R5)	;  in the remote and local buffers
	MOVL	HRB$L_PDT(R3),R4	; Get the PDT address for the SCS call
;
; Check if this will be the last block tranfer for this request, that is
; bytes left to send =< size of each block transfer.
;
	SUBL3	HRB$L_ABCNT(R3),-	; Get bytes left to tranfer for this
		HRB$L_OBCNT(R3),R1	;  Request (OBCNT-ABCNT)
	CMPL	R1,HRB$L_BCNT(R3)	; (OBCNT - ABCNT) =< BCNT)?
	BGTRU	80$			; If GTR no, use plain SEND_DATA
;
; This block transfer can contain all remaining bytes for the request.
; Issue combined SEND_DATA with piggyback end message request for this final
; transfer of the request.

;
; fill in the End Packet information
; 
	ADDL3	HRB$L_ABCNT(R3),-	; bytes sent prior to this
		CDRP$L_XCT_LEN(R5),-	;  + bytes to be sent this transfer 
		MSCP$L_BYTE_CNT(R2)	;  = total bytes transfered
	ASSUME  MSCP$K_ST_SUCC EQ 0	; set status success (Note: either the 
	CLRW	MSCP$W_STATUS(R2)	;  SEND_DATA_WMSG will complete sucessfully
					;  or SCS will not deliver the piggyback
					;  end packet!)
	MOVL	MSCP$L_BYTE_CNT(R2),-	; update the HRB, why not... 
		HRB$L_ABCNT(R3)		;  nothing short of disaster could stop
					;  the last packet now!
	MOVZBL	MSCP$B_OPCODE(R2),R1	; get opcode
	BISB2	#MSCP$K_OP_END,-	; Reset the op-code to
		MSCP$B_OPCODE(R2)	;  make an end packet
	MOVZBL	L^END_PKT_LEN[R1],R1	; Get the message length from the table
	MOVL	R2,CDRP$L_MSG_BUF(R5)	; Put the message buffer address into
	.IF DEFINED DEBUG$LOG

	ASSUME DSRV$V_LOG_ENABLD  EQ  0

	MOVL	G^SCS$GL_MSCP,R0	; Get the DSRV address.
	BLBC	DSRV$W_STATE(R0),70$	; Branch if logging is disabled.
        PUSHL	R0
	MOVL	#PKT$C_MSCP_END,R0
	BSBW	LOG_PKT		; Otherwise, log the end packet.
	POPL	R0
70$:	
	.ENDC

	CLRL	HRB$L_MSGBUF(R3)	; Message buffer belongs to SCS again
	MOVW	#HRB$K_ST_SNDAT_WAIT,-	; Set the state for this request
		HRB$W_STATE(R3)		;  before calling SCS service
	
	SEND_DATA_WMSG			; send the last SEND_DATA w/piggyback
					;  end message. NOTE: SEND_DATA_WMSG will
					;  get *all* required send credits for the
					;  block transfer, this is why RECYCL_MSG_BUF
					;  is not needed.

	BISW	#HRB$M_STATE_INVALID,-	; The state of this request is "current"
		HRB$W_STATE(R3)		;  leave the old state for diagnosis
	BSBW	CLEANUP_HRB		; Deallocate all HRB held resources
	BRW	UNBLOCK			;  and drop the "current" counter
	
;
; not the last packet, just use a regular old SEND_DATA
; 
80$:
	MOVW	#HRB$K_ST_SNDAT_WAIT,-	; Set the state of this request to
		HRB$W_STATE(R3)		;  SCS block transfer
	SEND_DATA			; Send to host buffer

;
; This thread is suspended until the block transfer completes. At that time,
; control is returned here with the following registers:
;
;		R0  =  status
; 		R3  =  Host Request Buffer address
;		R4  =  PDT address
;		R5  =  CDRP address
;
	.IF DEFINED DEBUG$PC_HISTORY
	BSBW	PCHIST			; Save this PC if we are keeping track
	.ENDC	   ;DEBUG$PC_HISTORY
	BISW	#HRB$M_STATE_INVALID,-	; The state of this request is "current"
		HRB$W_STATE(R3)		;  leave the old state for diagnosis
	BLBC	R0,ABORT_READ		; If the send was not successful 
	BITW	#<HRB$M_ABORT!-		;  or if this request has been aborted,
		HRB$M_ABORTWS>,-	;  or canceled,
		HRB$W_FLAGS(R3)		;  just clean everything up
	BNEQ	ABORT_READ

;
; Update the accumulated byte count and compare to original to
; determine if another round is needed.  
;
	.IF DEFINED DEBUG$PC_HISTORY
	BSBW	PCHIST			; Save this PC if we are keeping track
	.ENDC	   ;DEBUG$PC_HISTORY
	DECL	HRB$L_CMD_STS(R3)	; Record the progress on this request
	MOVL	CDRP$L_XCT_LEN(R5),R0	; Pick up transfered bytes
	ASHL	#-IOC$V_BLOCK_BLKNUM,-	; Convert the number of bytes specified
		R0,R1			;  into a block count
	ADDL	R0,HRB$L_ABCNT(R3)	; Calc accumulated bytes xfered
	SUBL3	HRB$L_ABCNT(R3), -	; Calc how much left to do
		HRB$L_OBCNT(R3),R2
	BLEQU	100$			; None, we are finished
	CMPL	R2,HRB$L_BCNT(R3)	; Compare the number of bytes remaining
	BGEQU	90$			;  to the number just transferred and
	MOVL	R2,HRB$L_BCNT(R3)	;  use the smaller of the two values
90$:	ADDL	R1,HRB$L_LBN(R3)	; Update LBN
	MOVL	HRB$L_UQB(R3),R0	; Record the fact that the server
	INCL	UQB$L_EXTRA_IO(R0)	;  An extra I/O has to be done
	BRW	READ_LOOP		; Loop again

100$:	BUG_CHECK MSCPSERV, FATAL	; bytes remaining =< BCNT? Should have
					;  exited through SEND_DATA_WMSG
;
; If the send data was unsuccessful, just free the allocated resources, and
; this request is finished off.
; 
ABORT_READ:
	.IF DEFINED DEBUG$PC_HISTORY
	BSBW	PCHIST			; Save this PC if we are keeping track
	.ENDC	   ;DEBUG$PC_HISTORY
	BBS	#HRB$V_ABORT,-		; If this request was aborted due to a
		HRB$W_FLAGS(R3),10$	;  disconnect, no end msg is necessary
	MOVL	HRB$L_MSGBUF(R3),R2	; Get the message buffer address 
	MOVL	#MSCP$K_ST_ABRTD,R0	; Set the status to aborted
	BRW	SEND_END		;  and send out an end message

10$:	BSBW	CLEANUP_HRB		; Deallocate the resources used
	BRW	UNBLOCK			;  and start up any eligible requests



;+
; Resumed here when the transfer has completed
;
;   Inputs to the async completion routine:
;	R0 contains the I/O status  block
;	R1 contains the address of the UCB
;	R2 contains the message buffer address
;	R3 contains the address of the HRB
;	R4 contains the address of the UQB
;	R5 contains the address of the IRP
;
;   Outputs;
;	R0-R5 may be destroyed
;-

30$:	.JSB_ENTRY 	INPUT=<R0,R1,R2,R3,R4,R5>, -
			SCRATCH=<R0,R1,R2,R3,R4,R5>

	BLBC	R0,45$			; Branch if error
	MOVL	IRP$L_BCNT(R5),R0	; Pick up the number of bytes transfered
	ASHL	#-IOC$V_BLOCK_BLKNUM,-	; Convert the number of bytes specified
		R0,R1			;  into a block count
	ADDL	R0,HRB$L_ABCNT(R3)	; Update bytes sent so far
	SUBL3	HRB$L_ABCNT(R3),-	; Determine how many characters
		HRB$L_OBCNT(R3),R2	;  remain to be sent
	BLEQU	50$			; Nothing left we must be done!
	CMPL	R2,HRB$L_BCNT(R3)	; If the characters remaining is smaller
	BGEQU	40$			;  than characters just transfered,
	MOVL	R2,HRB$L_BCNT(R3)	;  then shrink the size of the request
40$:	ADDL	R1,HRB$L_LBN(R3)	; Move logically down the disk
	MOVL	HRB$L_PDT(R3),R4	;  for the SCS call
	MOVL	HRB$L_UQB(R3),R0	; Record the fact that the server
	INCL	UQB$L_EXTRA_IO(R0)	; An extra I/O has to be done

	; Modify write log entry flags since we are fragmenting write.
	; We only have one entry from the client node to do the write,
	; so we need to set the supplement write log flag and force
	; the reuse flag.  The client request might or might not have
	; the reuse flag set, but it is appropriate to set it now since
	; we are fragmenting the write.

	CMPW	#^XFFFF,IRP$L_CLN_WLE(R5); Watch out for exhaustion
	BNEQ	42$			;
	BICL	#IRP$M_WLE,-		; Stop write log.
		IRP$L_STS2(R5)		;
	BRW	WRITE_LOOP		;
42$:	BISB	#<IRP$M_WLE_REUSE!-	; Force the reuse bit
		  IRP$M_WLE_SUPWL>,-	;  and  the supplement bit
		IRP$B_WLG_FLAGS(R5)	;  in IRP.
	BRW	WRITE_LOOP		; Get another chunk of data
45$:    
	MOVAB	ERR_TBL,R2		; Get the address of the error table
	BSBW    XFER_ERR                ; Otherwise get the MSCP error code
	BICL3	#^cMSCP$M_ST_MASK, -	; Extract major MSCP status
		R0, R1			;  
	CMPL	R1,#MSCP$K_ST_OFFLN	; Was this one of the offline errors?
	BNEQ	46$			; If not test for write lock
	BSBW	ERR_OFFLINE		; Otherwise do some offline processing
	BRW	49$			;  and go to the common exit
46$:	CMPL	R1,#MSCP$K_ST_DATA	; Parity or Forced Error
	BEQL	47$			; If EQL yes
	CMPL	R1,#MSCP$K_ST_COMP	; Datacheck or Host Compare Error
	BNEQ	48$			; If NEQ no
47$:	MOVL	IRP$L_IOST1+2(R5), -	; Pick up the number of bytes
		HRB$L_ABCNT(R3)		;  transfered and update ABCNT.
	BRB	49$			; Merge
48$:	CMPL	R1,#MSCP$K_ST_WRTPR	; Was this a write lock error?
	BNEQ	49$			; If not just return the error
	MOVL	HRB$L_UQB(R3),R4	; Get the UQB address 
	BBSS	#MSCP$V_UF_WRTPH,-	; Set the write protect bit in
		UQB$W_FLAGS(R4),49$	;  the unit flag field
49$:	MOVL	HRB$L_MSGBUF(R3),R2	; MSCP packet address from the HRB
	MOVL	HRB$L_ABCNT(R3),-	; Set the byte count in the MSCP 
		MSCP$L_BYTE_CNT(R2)	;  to return to the requestor
	BRW	SEND_END		; Send an end packet with R0 status
;
; Final clean up for transfer commands.  Set status, release resources.
;
50$:	MOVL	HRB$L_MSGBUF(R3),R2	; Restore packet address
	BBC	#MSCP$V_MD_HISLO,-	; If not write logging, continue
		MSCP$W_MODIFIER(R2),55$;
        MOVL    IRP$L_CLN_WLE(R5),-	; Copy (entry id, entrylocator)
                MSCP$W_HRN(R2)		;
55$:	MOVL	HRB$L_ABCNT(R3),-	; Set byte count
		MSCP$L_BYTE_CNT(R2)	; 
	MOVL	#MSCP$K_ST_SUCC,R0	; Return a successful completion
	BRW	SEND_END		; Send an end packet with R0 status

ABORT_WRITE:
	.IF DEFINED DEBUG$PC_HISTORY
	BSBW	PCHIST			; Save this PC if we are keeping track
	.ENDC	   ;DEBUG$PC_HISTORY
	BBS	#HRB$V_ABORT,-		; If this request was aborted due to a
		HRB$W_FLAGS(R3),10$	;  disconnect, no end msg is necessary
	MOVL	HRB$L_MSGBUF(R3),R2	; Get the message buffer address 
	MOVL	#MSCP$K_ST_ABRTD,R0	; Set the status to aborted
	BRW	SEND_END		;  and send out an end message

10$:	BSBW	CLEANUP_HRB		; Deallocate the resources used
	BRW	UNBLOCK			;  and restart any blocked requests,



