Trailing-Edge
-
PDP-10 Archives
-
isi-saio_19830204
-
isi-sa10/phyc1.mac
There are 3 other files named phyc1.mac in the archive. Click here to see a list.
;<ISI-SA10>PHYC1.MAC.5111 3-Feb-83 14:35:52 Edit by ISI-SA10
;
; Copyright 1982, All Rights Reserved
; University of Southern California
;
;<5.ISI.MONITOR>PHYC1.MAC.5110 29-Nov-82 08:08:07 Edit by SMITH
;#511 Do not give CC1HRE BUGCHK unless short IORB (Paging failure)
;<5.ISI.MONITOR>PHYC1.MAC.5000 22-Oct-82 08:44:14 Edit by SMITH
;#500 Adapt to release 5
;<ISI.MONITOR>PHYC1.MAC.4620 28-Aug-82 09:02:25 Edit by SMITH
;#462 Add consistancy check on sense bytes for data checks and env. data.
;#431 <ISI.MONITOR>PHYC1.MAC.4310 16-Jun-82 11:48:46 Edit by SMITH
;#431 Generate CC1SRE BUGCHKs for ECC errors too.
;#431 Change CC1SRE,CC1SWE to every 32'd error.
;#232 BUGCHK on hard disk errors, BUGINF every ^D16 soft disk errors
;#232 Removed CC1CUE & CC1BS1 BUGINFs
;<4.ISI-MONITOR>PHYC1.MAC.250 31-Mar-81 13:07:37 Edit by SMITH
;#25 Support IBM-3330 compatable disks on SA10 channel.
;#25 Entire module supports disks on SA10
;#[T] collecting timing data
;#[P] Positioning separated from transfer
SEARCH PROLOG,SERCOD ;system parameters
TTITLE (PHYC1,,< - Device dependent code for CalComp/IBM 3330 disks>)
SUBTTL Dennis R. Smith 5-Dec-79
SEARCH PHYPAR ;parameters
ENTRY CC1DSP ;dispatch vector
;*****************************************************************************
;****** *****
;****** Notes *****
;****** *****
;*****************************************************************************
COMMENT ~
In order to use the Calcomp 3330 disks efficently, it is
necessary to block the 'sectors' of 128 words which Tops-20
uses as its logical records into larger physical records.
For various reasons, in particular, the fact that probably
99 percent of the transfers are for one 'page', a blocking
factor of 4 was chosen. This means that there are 512
words, or 1152 bytes per physical record. This allows 5
pages per track, which is the same density that is achieved
on RP06s. Since almost all I/O is for one page, the
standard command program is set up to transfer a full page
(or record) with one Device Command Word (DCW) and one Data
Chaining Word (sometimes called an IOW). In the rare case
where less than a page is read, incorrect length error is
suppressed, any quarter pages not desired are skipped with
an IOW having an address field of zero, and the desired data
is read into the user's buffer. In the case of a write of
less than one page, a command program is set up to first
read the page into a buffer, and then to write out the page,
writing out the data just read in except for that portion
supplied by the user.
~
COMMENT ~ Nomenclature used in this module
Name Abrev. Meaning
Cylinder C, CYL - Cylinder of disk or tracks thereron
Track Trk - Track of disk: data of 1 cylinder under 1 head
Head H, Hd - R/W head of disk, or any track under that head
Surface Srf - Same as Head
Record R, Rec - Hardware record (=1 page)
Sector Sec - Hardware sector (not same as 'sector', q.v.)
'Sector' - Software 'sector' = Logical record (1/4 page)
Logical
Record LRC - Logical record (referred to as 'sector' by PHYSIO)
~
SUBTTL PARAMETERS
; Retry Counts
DEVCNT==3 ;Retries on device error before recalibrate
RCLCNT==3 ;Recalibrates after DEVCNT tries
DSKNTR==^D16 ;Number of tries on unknown errors
;Status bits in LH(UDBERR)
ES.HRD==1B0 ;hard error
ES.ECC==1B1 ;ECC-corrected error
ES.DAT==1B2 ;data error
ES.DEV==1B4 ;device error
; UDB Extensions
DOPC(C1,UDBDDD) ;#500 define UDB Device Dependent Part
SC1 CC1STS,1 ;extra status bits
SC1 CC1SCP,1 ;BMX pointer to standard channel program
MSKSTR(CC1SPA,CC1SCP(P3),BMX%AD) ;address of standard channel program
SC1 CC1CCP,1 ;BMX pointer to current channel program
SC1 CC1DVL,1 ;addr of device list entry for device
SC1 CC1CYL,1 ;number of cylinders per unit
SC1 CC1SCL,1 ;'sectors' per cylinder (logical records)
SC1 CC1SSF,1 ;'sectors' per surface
SC1 CC1UHS,1 ;number of microseconds per (HW) sector
SC1 CC1USF,1 ;number of microseconds per surface
SC1 CC1IOW,1 ;IOW for current operation
SC1 CC1RMW,1 ;count of times Read/Modify/Write needed
SC1 CC1ES1,1 ;error status word 1 (copy of SSACS1)
SC1 CC1ES2,1 ;error status word 2 (copy of SSACS2)
SC1 CC1SNB,6 ;sense bytes (6 words)
SC1 CC1ESB,6 ;error sense bytes (6 words)
SC1 CC1PSF,1 ;pages per surface
SC1 CC1TIM,4 ;#[T] timing data (start, elapsed, #, average)
SC1 CC1PTM,4 ;#[P] timing data on positioning (as CC1TIM)
SC1 CC1TST,10 ;statistics gathering time storage
SC1 L.CC1,0 ;length of UDB for CC1
; CC1STS bits
C1.TNK==1B0 ;Type of drive Not Known
C1.SNS==1B1 ;sense in progress
C1.RCL==1B2 ;recalibrate in progress
C1.RBW==1B3 ;read before write (read/modify/write cycle)
C1.WAR==1B4 ;write after read - only used if the RBW
; got a CDC that broke the chaining
C1.RMW==C1.RBW!C1.WAR ;read/modify/write cycle includes both
C1.TIM==1B5 ;#[T] do timing statistics
; Pointers
DEFSTR(DP%CYL,DPOSEK,31,16) ;Cylinder. 16 bits in 1st word of seek buffer
DEFSTR(DP%SRF,DPOSEK+1,15,16) ;Surface. 16 bits in 2nd word of seek buffer
DEFSTR(DP%REC,DPOSEK+1,23,8) ;Record. 8 bits in 2nd word of seek buffer
DEFSTR(DP%LRC,DPOSEK+1,25,2) ;Logical Record within physical record (SW) - 2
; bits in 2nd word of seek buffer
DEFSTR(DP%SEC,DPOSEK+2,7,8) ;Sector. 8 bits (HW: 1/128 of track) - in
; 3rd word of seek buffer (for convenience)
MSKSTR(DP%CMD,DPOOPC,SC%CMD) ;Channel command
MSKSTR(DP%CCF,DPOOPC,SC%CCF) ;Channel command flags
MSKSTR(DP%DEV,DPOOPC,SC%DEV) ;Device address
SUBTTL DISPATCH VECTOR
CC1DSP: JRST CC1INI ;0 - Initialization
JRST CC1SIO ;1 - Start I/O
JRST CC1INT ;2 - Handle interrupt
JRST CC1ERR ;3 - Error recovery
JRST CC1HNG ;4 - Hung device
JRST CC1CNV ;5 - Convert blk # to cylinder/surf-sec
JRST CC1LTM ;6 - Latency computation
JRST CC1POS ;7 - Start positioning
JRST CC1ATN ;10- Attention interrupt
JRST CC1PRQ ;11- Skip if positioning required
JRST CC1STK ;12- Stack second transfer command
RET ;#500 13- check existance of unit (not called)
RET ;#500 14- check for halted controller (not called)
;DUMMIES
CC1HNG: RET
CC1ATN: RET ;no attention interrupts generated by drives
CC1PRQ: RET ;if asked, say no positioning required
CC1STK: RET ;say unable to stack
SUBTTL CONSTANTS
CC1FCN: ;table to translate internal to external
; functions
XWD 0,0 ;0- no such function
XWD .ICRDD,0 ;1- read
XWD 0,0 ;2- read format
XWD .ICWRD,0 ;3- write
XWD 0,0 ;4- write format
MXEXFN==.-CC1FCN-1 ;maximum external function
MXCC1F==.-CC1FCN-1 ;maximum legal function
; prototype channel program
CC1CP CC1PCP
; Table of data to copy at initial error recovery time
CC1DAT: SEBPTR 0,SBTEVC,SEC%SD ;block type (SA10 disk error)
SEBPTR MB%CNI,SBTWD,CDBCNI(P1) ;Initial CONI
SEBPTR MB%CS0,SBTWD,CDBCS0(P1) ; (Currently unused)
SEBPTR MB%CS1,SBTWD,CDBCS1(P1) ;Status word 1 (Base+1)
SEBPTR MB%CS2,SBTWD,CDBCS2(P1) ;Status word 2 (Base+2)
SEBPTR SD%IOW,SBTWD,CC1IOW(P3) ;IOW from transfer
SEBPTR SD%STS,SBTWD,CC1STS(P3) ;Device specific status
SEBPTR SD%ES1,SBTWD,CC1ES1(P3) ;Error status (Base+1)
SEBPTR SD%ES2,SBTWD,CC1ES2(P3) ;More error status (Base+2)
SEBPTR SD%SEN+0,SBTWD,CC1ESB+0(P3) ;Sense bytes (24 bytes = 6 words)
SEBPTR SD%SEN+1,SBTWD,CC1ESB+1(P3)
SEBPTR SD%SEN+2,SBTWD,CC1ESB+2(P3)
SEBPTR SD%SEN+3,SBTWD,CC1ESB+3(P3)
SEBPTR SD%SEN+4,SBTWD,CC1ESB+4(P3)
SEBPTR SD%SEN+5,SBTWD,CC1ESB+5(P3)
SEBPTR SD%CCP,SBTWD,CC1CCP(P3) ;Current Channel Program address
CC1NDA==.-CC1DAT
SUBTTL INITIALIZATION
;CC1INI - Initialize disk unit on given channel
; [Note: this differs from device "INI" routines on RH20's]
; P1/ CDB
; P3/ 0
; Q2/ unit number (0,1,...)
; CALL UDSINI(ac) ;where ac/ CC1DSP
; RETURNS +1: Always
; P3/ UDB if device found on this channel, else 0
; P1, Q1-Q4 preserved; other AC's destroyed
CC1INI: SAVEQ
MOVEI T1,CC1PGA/PGSIZ ;page used for Read/Modify/Write
CALL NOCASH ;turn off caching on that page
SETZM CC1XCP ;show RMW page not in use
; We will begin by attempting a 'Read count' command on Cylinder 800.
; What happens to this command should tell us whether the device
; is on this channel, and if so, whether it is a mod I or a mod II.
; Possible outcomes:
; (1) No response, or 'Select error' status: Device is not there
; (this will be indicated by a +1 return from SAINGO).
; (2) Unit check, with sense showing 'command reject': Unit was
; there, but had no Cyl 800 (Mod I drive).
; (3) Normal status (Channel end + Device end): Device was there and
; has a Cyl 800 (Mod II drive).
MOVE T1,SAXFRE ;get -length,,next free space
CAML T1,[XWD -DPOLEN-6,0] ;room for CP and sense buffer?
JRST CC1INF ;failed
CALL CC1MCP ;put channel program in space
JFCL ;will always skip
HRRZM T1,P6 ;save CP address
CALL CC1SRC ;set up Read Count program
SETZ Q1, ;show device type uncertain
SETZ T2, ;reset desired on channel
CALL SAINGO ;try the operation
JRST CC1INX ;unit not there
MOVE T1,CDBCS1(P1) ;get status word
TXNE T1,FLD(.S1ATN!.S1SMD!.S1CUE!.S1BSY!.S1UEX,S1%DVS) ;unusual err?
JRST CC1INE ;yes
TXNN T1,FLD(.S1UCK,S1%DVS) ;unit check?
MOVEI Q1,.UTCC2 ;no, this must be a mod II
MOVEI T1,DPOSNP(P6) ;get address of sense program
SETO T2, ;do not want reset (would clear sense)
CALL SAINGO ;do the sense
JRST CC1INX ;give up if sense fails
MOVE T1,@DPOSNP+1(P6) ;get 1st word of sense buffer
TXNE T1,SN%CRJ ;command reject?
MOVEI Q1,.UTCC1 ;yes, must be mod I
JUMPE Q1,CC1INX ;ignore if model not determined
CALL CC1IUN ;initialize unit
JRST CC1INX ;failed, P3/0
RET ;successful initialization
CC1INE: BUG(CC1UEI,<<T1,SW1>,<Q2,UNIT>,<SSASCI(P1),SUBCHN>>) ;<PHYC1 - Unusual error on 1st I/O>
JRST CC1INX ;treat as not there
CC1INF: BUG(CC1AL1) ;<PHYC1 - No space for channel program>
CC1INX: RET ;return (unsuccessful)
SUBTTL CC1IUN, CC1SUN
; CC1IUN - initialize unit ; CC1SUN - set up UDB for unit
; P1/ CDB
; P3/ UDB (If call is to CC1SUN)
; Q1/ unit type code
; Q2/ unit number
; CALL CC1IUN (CC1SUN)
; RETURNS +1: couldn't get necessary resources (UDB or uncached space)
; RETURNS +2: success
; P3/ UDB address
; T1-T4 destroyed
CC1IUN: MOVE T3,[CC1DSP,,L.CC1] ;dispatch,,length
CALL PHYUDB ;set up UDB
RETBAD ;give up if no space
CC1SUN: MOVSI T2,-NDSKUT ;search to find physical param table
CC1SU2: CAMN Q1,DSKUTP(T2) ;match?
JRST CC1SU3 ;yes
AOBJN T2,CC1SU2 ;no, loop
BUG(CC1PNF,<<Q1,TYPE>,<Q2,UNIT>,<SSASCI(P1),SUBCHN>>) ;<PHYC1 - Disk physical parameters not found>
CC1SU3: MOVE T2,DSKSIZ(T2) ;get pointer to physical parameters table
MOVEM T2,UDBSIZ(P3) ;save in UDB
MOVE T3,CYLUNT(T2) ;;get number of cylinders
MOVEM T3,CC1CYL(P3) ;save cylinders
MOVE T3,SECCYL(T2) ;get 'sectors' (records) per cylinder
MOVEM T3,CC1SCL(P3) ;save records/cyl
MOVE T3,SECSRF(T2) ;get 'sectors' (records) per surface
MOVEM T3,CC1SSF(P3) ;save records/surface
IDIV T3,SECPAG(T2) ;get pages per surface
MOVEM T3,CC1PSF(P3) ;save pages/surface
MOVE T3,SECSRF(T2) ;get back 'sectors' per surface
MOVE T1,USSECU(T2) ;get number of microseconds per "latency unit"
LSH T1,6 ;number of microseconds per RP04 'sector'
IMULI T3,(T1) ;compute number of microseconds per surface
MOVEM T3,CC1USF(P3) ;save microseconds per surface
IDIVI T3,DPKSPT ;compute microseconds per HW sector
MOVEM T3,CC1UHS(P3) ;store microseconds per HW sector
MOVX T4,US.PRQ!US.DSK ;#500 disk, positioning required
IORM T4,UDBSTS(P3) ;set status
MOVX T4,C1.TIM ;#[T] collect timing data
IORM T4,CC1STS(P3) ;#[T] .
STOR Q1,USTYP,(P3) ;store device type
CALL CC1GDL ;Get device list for channel
JRST CC1ALF ;allocation failure
ADDI T1,(Q2) ;entry for this unit
HRRZM T1,CC1DVL(P3) ;save address in UDB
CALL CC1GSB ;get a sense buffer if none yet
JRST CC1ALF ;allocation failure
SETZ T1, ;signal CC1MCP to allocate CP space
CALL CC1MCP ;make a channel program
JRST CC1ALF ;allocation failure
IORX T1,FLD(.BMXS,BMX%CM) ;block mux start program
MOVEI T2,.IDDSK(Q2) ;get device address of unit
STOR T2,BMX%DV,T1 ;store device address in Mux pointer
MOVEM T1,CC1SCP(P3) ;save for later insertion in DVL
LOAD T1,SC%ADR,DPOSNP+1(T1) ;get address of sense buffer
LOAD T1,BYTE0,1(T1) ;get sense byte 4
MOVE T2,T1 ;copy physical unit designator
ANDI T1,7 ;isolate drive index (0="A", 7="G")
LSH T2,-6 ;isolate controller bits
IMULI T2,^D100 ;multiply controller by 100
ADDI T1,(T2) ;make <controller*100+drive>
MOVEM T1,UDBDSN(P3) ;store in serial number word
MOVX T1,CS.MUX ;show this is a multiplexor channel
IORM T1,CDBSTS(P1) ; .
RETSKP ;now return UDB to caller
CC1ALF: BUG(CC1AL2) ;<PHYC1 - insufficient uncached core for new disk unit>
RETBAD ;show failure
SUBTTL CC1SRC - Set up Read Count program
;CC1SRC - set up "Read Count" program: C800, H1, R1
; T1/ channel program address
; CALL CC1SRC
; RETURNS +1: Always
; T2, T3 destroyed
CC1SRC: ;set up read count program
MOVEI T3,^D800 ;Cylinder 800.
STOR T3,DP%CYL,(T1) ;store in seek buffer
MOVEI T3,^D1 ;Surface 1
STOR T3,DP%SRF,(T1) ;store in seek buffer
STOR T3,DP%REC,(T1) ;Record 1: to seek buffer
MOVE T3,DPKSEC(T3) ;get sector for this record
STOR T3,DP%SEC,(T1) ;store in seek buffer
MOVEI T3,.ICRDC ;read count command
STOR T3,DP%CMD,(T1) ;store in command program
MOVEI T3,.SCXCT!.SCILE!.SCBYT ;eXiCuTe, Ignore Length Error, BYTe mode
STOR T3,DP%CCF,(T1) ;store flags
LOAD T2,SC%ADR,DPOSNP+1(T1) ;address of sense buffer
IORX T2,<IOW 8,.-.> ;8 byte read, no chaining
MOVEM T2,DPOADR(T1) ;store in program
MOVX T2,<HLT.H> ;halt
MOVEM T2,DPOADR+1(T1) ;end of program marker
RET
SUBTTL CC1LTM - compute best latency
;CC1LTM - Compute best latency
; P1/ CDB
; P3/ UDB
; T1/ Minimum latency in microsecseconds (0 for command stacking computation)
; CALL UDSLTM(ac) ;where ac/ CC1DSP
; RETURNS +1: no requests available (always if T1 was 0)
; destroys P4-P5, T1-T4
; RETURNS +2: request found
; T1/ Latency of closest request greater than specified minimum (uSEC)
; T2/ Predicessor of IORB corresponding to time in T1
; T3/ IORB corresponding to time in T1
;
; NOTE: This routine does not function exactly as its parallel for RP04/6's,
; because we do not separate positioning and transfers. This code
; is therefore not going to help if a seek is still needed, but only
; if we are really already on cylinder.
;
; This routine procedes as follows:
; The IORB with the smallest latency greater than the
; minimum is returned, along with its latency (same as for
; RP04's), except that the code assumes we are on cylinder.
; The positions used are HW sector numbers.
;
; AC usage:
; Q1/ current cylinder
; Q2/ minimum latency,,current position
; Q3/ best latency so far,,predecessor IORB
; P4/ current IORB
; P5/ predecessor to best IORB,,best IORB so far
CC1LTM: JUMPE T1,R ;if command stacking, quit
SAVEQ ;save Q registers
DMOVE Q1,UDBPS1(P3) ;get current cylinder, sector within
IDIV Q2,CC1PSF(P3) ;find out what page of surface we are on
HRRZ Q2,DPKSEC+1(Q3) ;get HW sector we "SET SECTOR" to
ADDI Q2,DPKSPR ;assume we are one record further
CAIL Q2,DPKSPT ;wrap around?
SUBI Q2,DPKSPT ;yes, position on next time around
HRL Q2,T1 ;minimum latency,,current pos
HRROI Q3,UDBTWQ(P3) ;initialize best latency,,predecessor
SETZB P4,P5 ;initialize current and best IORBs
CC1LT3: HRRZ P4,IRBLNK(Q3) ;set current from predecessor
JUMPE P4,CC1LT5 ;end of list?
CALL CC1CNV ;no - get address. T2/ cyl, T3/ relative LRC
MOVE T1,T3 ;copy LRC relative to cyl
IDIV T1,CC1PSF(P3) ;get T2/ page on the track
HRRZ T1,DPKSEC+1(T2) ;get HW Sector
SUBI T1,(Q2) ;compute distance to this request
IMUL T1,CC1UHS(P3) ;compute latency to this request
SKIPGE T1 ;if negative,
ADD T1,CC1USF(P3) ;get absolute distance
HLRZ T2,Q2 ;get minimum latency specified
CAMGE T1,T2 ;is this request greater?
ADD T1,CC1USF(P3) ;no - must do it one revolution later
HLRZ T2,Q3 ;compare to best latency so far
CAML T1,T2 ;less?
JRST CC1LT4 ;no - do next request
HRL Q3,T1 ;yes - save as current best LAT
MOVE P5,P4 ;copy current IORB
HRL P5,Q3 ;copy predecessor IORB
CC1LT4: HRR Q3,P4 ;current IORB becomes predecessor
JRST CC1LT3 ;look at next IORB
CC1LT5: JUMPE P5,CC1LTE ;if none found, error
HLRZ T1,Q3 ;get best latency found
HLRZ T2,P5 ;get predecessor to best IORB
HRRZ T3,P5 ;get best IORB
RETSKP
CC1LTE: BUG(CC1LTF) ;<PHYC1 - Failed to find TWQ entry at CC1LTM>
RET
SUBTTL CC1POS - Position disk
;#[P] CC1POS - Positon for transfer (Seek)
;#[P] P1/ CDB
;#[P] P3/ UDB
;#[P] P4/ IORB
;#[P] CALL UDBPOS(ac) ;where ac/ CC1DSP
;#[P] RETURNS +1: failure (never)
;#[P] RETURNS +2: success (always)
CC1POS: SAVEQ ;#[P] save ACs
CALL GETMST ;#[P] get time
MOVEM T1,CC1PTM(P3) ;#[P] store time positioning started
MOVEI Q1,0 ;#[P] indicate positioning (no command)
CALL CC1SET ;#[P] setup
RETBAD ;#[P] failure
MOVE T1,CC1SCP(P3) ;#[P] get pointer to standard program
HRRI T1,DPOPSK(T1) ;#[P] point to the seek-only program
CALL CC1GOM ;#[P] start I/O
RETSKP ;#[P] return
SUBTTL CC1SIO - Start I/O
;CC1SIO - Start I/O operation
; P1/ CDB
; P3/ UDB
; P4/ IORB
; CALL UDBSIO(ac) ;where ac/ CC1DSP
; RETURNS +1: failure
; RETURNS +2: success
CC1SIO: SAVEQ
SKIPE UDBERC(P3) ;in error recovery?
JRST [ CALL CC1GCP ;yes, get address of channel program
JRST CC1SI1] ;and restart it
CALL GETMST ;get time
MOVEM T1,CC1TIM(P3) ;store time I/O started
LDB T3,IRYFCN ;get function
CAIG T3,MXCC1F ;check maximum legal
SKIPN CC1FCN(T3) ;and one we can handle
BUG(CC1FEX,<<T3,FUNCTION>,<UDBAKA(P3),UNIT>,<SSASCI(P1),SUBCHN>>) ;<PHYC1 - Illegal function>
HLRZ Q1,CC1FCN(T3) ;translate function to hardware function
CALL CC1SET ;setup
RETBAD ;failure
CC1SI1: CALL CC1GOM ;start the I/O (Multiplexor mode)
RETSKP ;give good return
SUBTTL CC1INT - Interrupt handler
;CC1INT - handle interrupts
; P1/ CDB
; P3/ UDB
; CALL UDSINT(ac) ;where ac/ CC1DSP
; RETURNS +1: Error detected
; P4/ 0 : request PHYSIO to dismiss interrupt
; negative : Request Schedule cycle
; IORB : I/O completed on this IORB
; P1,P3 only preserved
; RETURNS +2: success
; P4/ 0 : request PHYSIO to dismiss interrupt
; negative : Request Schedule cycle
; IORB : I/O completed on this IORB
; P1,P3 only preserved
CC1INT: JUMPE P3,CC1ONL ;new device coming online
MOVX T2,US.POS ;#[P] positioning?
TDNE T2,UDBSTS(P3) ;#[P] ?
JRST CC1INP ;#[P] yes
MOVX T1,C1.TNK ;looking for device type?
MOVX T2,US.ACT ;or not active?
TDNE T2,UDBSTS(P3) ; not active?
TDNE T1,CC1STS(P3) ; looking for type?
TDZA P4,P4 ;yes, show no IORB
CALL SETIRB ;set up IORB in P4
MOVE T3,CDBCS1(P1) ;get 1st word of channel status
LOAD T4,S1%DVS,T3 ;get device status
CAIE T4,.S1CHE+.S1DVE ;check for normal case first
JRST CC1UCI ;no, unusual contdition
CC1NRM: ;normal completion (CE+DE)
MOVX T1,C1.SNS ;was this on a sense?
TDNE T1,CC1STS(P3) ; ?
JRST CC1SND ;yes, check sense info
JUMPE P4,CC1INR ;handle completion if no IORB
CALLRET CC1DUN ;finished.
CC1INP: ;#[P] interrupt when positioning
SETZ P4, ;#[P] default case is "not done"
MOVE T3,CDBCS1(P1) ;#[P] get channel status word 1
LOAD T4,S1%DVS,T3 ;#[P] get device status
CAIE T4,.S1DVE ;#[P] normal case for seek completed?
CAIN T4,.S1CHE+.S1DVE ;#[P] norm. case for seek completed immediately?
JRST CC1PDN ;#[T] yes, positioning done
CAIN T4,.S1CHE ;#[P] normal case for seek started?
RETSKP ;#[P] yes, return to PHYINT, not done
JRST CC1UCI ;#[P] unusual case, try to handle
CC1PDN: CALL PHYPDN ;#[P] say positioning done
SETO P4, ;#[P] show scheduling wanted
MOVX T2,C1.TIM ;#[T] ;#[P] timing?
TDNN T2,CC1STS(P3) ;#[T] ;#[P] ?
RETSKP ;#[T] ;#[P] no, return to PHYINT
CALL GETMST ;#[T] ;#[P] get time
SUB T1,CC1PTM(P3) ;#[T] ;#[P] subtract time positioning started
ADDB T1,CC1PTM+1(P3) ;#[T] ;#[P] add to sum
AOS T2,CC1PTM+2(P3) ;#[T] ;#[P] count times
IDIV T1,T2 ;#[T] ;#[P] compute average
MOVEM T1,CC1PTM+3(P3) ;#[T] ;#[P] store average
RETSKP ;#[P] return to PHYINT
SUBTTL CC1INT - Interrupt handler: CC1UCI - unusual condition int.
CC1UCI: ;Unusual Condition Interrupt
TRNE T4,.S1UCK ;is it a unit check?
JRST CC1XER ;yes
TRNE T4,.S1BSY ;rejected because of busy?
JRST CC1BSY ;yes
TRNE T4,.S1CUE ;control unit end?
JRST CC1CUI ;yes
TXNN T3,FLD(.S1SER!.S1BIP!.S1CSE!.S1PIF!.S1LNE,S1%CHS) ;Funny channel bits?
TRNE T4,.S1ATN!.S1UEX ; or funny device bits?
JRST CC1GBS ;funny bits, try to restart it
TRNE T4,.S1DVE ;device end alone?
JRST CC1DVE ;yes, Asynchronous, probably
;channel end or nothing at all, ignore
BUG(CC1FSB,<<T3,SW1>,<UDBAKA(P3),UNIT>,<SSASCI(P1),SUBCHN>>) ;<PHYC1 - Unusual status from disk>
CC1XND: SETZ P4, ;show not done
RETSKP ;do not indicate error
CC1GBS: BUG(CC1BSB,<<T3,SW1>,<UDBAKA(P3),UNIT>,<SSASCI(P1),SUBCHN>>) ;<PHYC1 - Bad status bits>
CC1RDV: MOVX T1,US.ACT ;see if device was active
TDNN T1,UDBSTS(P3) ;was it active?
JRST CC1XND ;no, just dismiss
CC1AGN: MOVE T1,CC1CCP(P3) ;get current program pointer for unit
CALL CC1GOM ;go restart operation
JRST CC1XND ;dismiss interrupt
CC1DVE: ;here on device end alone
MOVX T1,US.OFS ;see if it was offline
TDNN T1,UDBSTS(P3) ;offline?
BUG(CC1UDE,<<CDBCS1(P1),SW1>,<CDBCS2(P1),SW2>,<UDBAKA(P3),UNIT>,<SSASCI(P1),SUBCHN>>) ;no <PHYC1 - Unexpected Device End>
CC1DV1: ;Device end
MOVX T1,C1.TNK ;is type undetermined yet?
MOVX T2,US.ACT ;or is unit active?
TDNN T2,UDBSTS(P3) ; active?
TDNE T1,CC1STS(P3) ; type known?
JRST CC1AGN ;unit active, or type unknown, try again
CALL CC1DUP ;DE out of the blue, drive up now
CC1XER: ;exit, error detected
JUMPE P4,CC1IER ;handle differently if initialization
MOVX T1,IS.ERR ;error bit
IORM T1,IRBSTS(P4) ;set error in IORB
RETBAD ;indicate error to PHYSIO
SUBTTL CC1INT - Interrupt handler: CC1BSY - Busy status
CC1BSY: ;busy seen
MOVX T1,C1.SNS ;sense in progress?
TDNE T1,CC1STS(P3) ; ?
JRST CC1BSS ;yes, handle differently
;;#232 BUG(CC1BS1,<<CDBCS1(P1),SW1>,<CDBXFR(P1),OWNER>,<UDBAKA(P3),UNIT>,<SSASCI(P1),SUBCHN>>) ;<PHYC1 - Busy status from disk>
MOVE T1,CC1CCP(P3) ;get pointer to current Channel Program
MOVEM T1,@CC1DVL(P3) ;reset device list for whenever in mux mode
JRST CC1XND ;exit, not done yet
CC1BSS: BUG(CC1BS2,<<CDBCS1(P1),SW1>,<CDBXFR(P1),OWNER>,<UDBAKA(P3),UNIT>,<SSASCI(P1),SUBCHN>>) ;<PHYC1 - Busy status on Sense read>
LOAD T1,CC1SPA ;get standard channel program address
MOVEI T1,DPOSNP(T1) ;get address of sense program
CALL CC1GOS ;(re)start in selector mode
JRST CC1XND ;exit, not done yet
SUBTTL CC1INT - Interrupt handler: CC1CUI - Control Unit end Int
CC1CUI: ;Control Unit End seen
; Any unit that got BSY should be ready to restart the next time I/O is
; started in MUX mode. One would expect that this would be at the end of a
; sense, due to some Unit Check that caused the problem. Therefore we ignore
; the CUE. Only time will tell if this was the correct procedure. -DRS
;;#232 BUG(CC1CUE,<<CDBCS1(P1),SW1>,<UDBAKA(P3),UNIT>,<SSASCI(P1),SUBCHN>>) ;<PHYC1 - Control Unit End seen>
JRST CC1XND ;exit, not done yet
SUBTTL CC1INT - Interrupt handler: CC1INR - Initialization Normal sts.
CC1INR: MOVX T2,C1.TNK ;were we trying to find out unit type?
TDNN T2,CC1STS(P3) ; ?
JRST CC1UST ;no, that's funny
MOVEI Q1,.UTCC2 ;good status on access to C800, must be Mod II
HRRZ Q2,UDBAKA(P3) ;get unit number
CALL CC1SUN ;reset unit for correct type
RET ;just return if no core
CALLRET CC1DUP ;Device UP (online)
CC1UST: BUG(CC1UES,<<CDBCS1(P1),SW1>,<UDBAKA(P3),UNIT>,<SSASCI(P1),SUBCHN>>) ;<PHYC1 - unexpected ending status>
CALLRET CC1DUP ;force reread of home blocks
SUBTTL CC1INT - Interrupt handler: CC1IER - Initialization Error sts.
CC1IER: ;error doing read count on Cyl 800
MOVX T1,C1.SNS ;sense in progress bit
TDZN T1,CC1STS(P3) ;already in progress?
JRST CC1SEN ;no, do a sense
BUG(CC1UCO,<<CDBCS1(P1),SW1>,<UDBAKA(P3),UNIT>,<SSASCI(P1),SUBCHN>>) ;<PHYC1 - Unit check on Sense: offline device>
RET
SUBTTL CC1INT - Interrupt handler: Sense operation completed
CC1SND: ;Sense done
JUMPN P4,R ;ret if not new device, CC1ERR will handle
CC1ISN: ;Sense done for unit coming online
ANDCAM T1,CC1STS(P3) ;clear sense in progress bit
MOVE T1,@SSASBA(P1) ;get 1st word of sense buffer
TXNN T1,SN%CRJ ;command reject?
JRST CC1BPK ;no, ingore funny business
CALLRET CC1DUP ;yes, must be MOD I, like we assumed
CC1BPK: ;seems to be a bad pack
MOVX T1,CS.AC1 ;clear bit saying channel is tied up
ANDCAM T1,CDBSTS(P1) ; .
RET ;but leave US.OFS & C1.TNK
SUBTTL CC1INT - Interrupt handler: CC1DUP - Device UP subroutine
CC1DUP: ;device up
MOVX T1,C1.TNK ;Type is now known
ANDCAM T1,CC1STS(P3) ; ..
;#500 MOVX T1,US.CHB!US.PSI ;#500 need to check home blocks
;#500 SKIPL UDBSTR(P3) ;... if in a structure ...
;#500 IORM T1,UDBSTS(P3) ;check home blocks
CALLRET PHYONL ;inform PHYSIO
SUBTTL CC1ONL - Interrupt from new device coming online
;CC1ONL - Interrupt from new device coming on line
; P1/ CDB
; entered from CC1INT
; RETURNS +1: failed to initialize unit (resource problem)
; T1-T4, Q1-Q4 destroyed
; RETURNS +2: success
; P3/ UDB
; T1-T4, Q1-Q4 destroyed
CC1ONL: LOAD Q2,S1%DEV,CDBCS1(P1) ;get device code
ANDI Q2,MAXSAU-1 ;unit on SA10
MOVEI Q1,.UTCC1 ;assume MOD I for now
CALL CC1IUN ;initialize unit
JRST [ SETZ P3, ;failed, no UDB
RETBAD] ;failure return
MOVX T1,C1.TNK ;show unit's type not known
IORM T1,CC1STS(P3) ; ...
MOVX T1,US.OFS ;show unit still not online
IORM T1,UDBSTS(P3) ; ...
LOAD T1,CC1SPA ;get address of channel program for unit
CALL CC1SRC ;set up Read Count program
CALL CC1GOM ;start I/O
RETSKP ;return to SSAINT
SUBTTL CC1ERR - Error handler
;CC1ERR - handle errors
; P1/ CDB
; P3/ UDB
; P4/ IORB
; CALL UDSERR(ac) ;where ac/ CC1DSP
; RETURNS +1: not done yet
; RETURNS +2: finished (hard eror or recovered)
CC1ERR: SAVEQ ;save accumulators
MOVX T1,IS.ERR ;is error bit still on?
TDNN T1,IRBSTS(P4) ; ??
JRST [ LDB T1,IRYFCN ;no, get function
CAIN T1,IRFRED ;read?
CALL CC1ESR ;#431 ;#232 yes. count and BUGCHK if many
CAIN T1,IRFWRT ;write?
CALL CC1ESW ;#431 yes
CALLRET CC1DUN] ;show that we are done
;error bit still on.
MOVX T1,C1.SNS ;test for sense in progress
TDNN T1,CC1STS(P3) ;sense in progress?
JRST CC1SEN ;no, do a sense
ANDCAM T1,CC1STS(P3) ;clear sense in progress bit
HRLZ T1,SSASBA(P1) ;get address of sense buffer read into
HRRI T1,CC1SNB(P3) ;get address of sense buffer for device
BLT T1,CC1SNB+5(P3) ;move sense bytes
CALL CC1GO ;start it up again in multiplexor mode
AOS Q3,UDBERC(P3) ;retry count
SOJE Q3,CC1ER1 ;if this was 1st error, save info
MOVE T1,CC1ESB(P3) ;get 1st word of original sense bytes
CAIE T1,SN%EDP ;was 1st error just statistics?
JRST CC1ER2 ;no, retain info about 1st error
; ..
; ..
; here on the first error, or 2nd if 1st was "statistics"
CC1ER1: HRLZI T1,CC1SNB(P3) ;move from sense bytes
HRRI T1,CC1ESB(P3) ; to error sense bytes
BLT T1,CC1ESB+5(P3) ;move sense info
HRRZ Q1,UDBERP(P3) ;get error block
JUMPE Q1,CC1ER2 ;none, no report
MOVE T1,Q1 ;copy error block address
MOVE T2,[-CC1NDA,,CC1DAT] ;size & address of SEBCPY parms
CALL SEBCPY ;copy some things to error block
JFCL
CALL PHYBLK ;get block number
MOVEM T2,SEBDAT+MB%LOC(Q1) ;save in report
LOAD T2,CC1SPA ;get channel program address
MOVEI T2,DPORCL(T2) ;point to 1st command
HRLZI T1,0(T2) ;point to 1st command
HRRI T1,SEBDAT+SD%CP1(Q1) ;point into error block
BLT T1,SEBDAT+SD%CP2-1(Q1) ;copy program
HRLI T2,SD%CP1-SD%CP2 ;negative length
MOVEM T2,SEBDAT+SD%SCP(Q1) ;store pointer
HRLI T1,CC1XCP+DPORCL ;point to eXtra channel program
BLT T1,SEBDAT+SD%CPE-1(Q1) ;copy that program too
MOVE T2,[SD%CP2-SD%CPE,,CC1XCP+DPORCL] ;neg count, loc of XCP
MOVEM T2,SEBDAT+SD%XCP(Q1) ;store for SYSERR
; ..
; ..
CC1ER2: ;not the first entry to error routine
MOVE T1,CC1SNB(P3) ;get 1st word of sense bytes
AOJE T1,CC1HRD ;still -1, no sense info read
MOVX T1,IS.IER ;error recovery inhibited?
TDNE T1,IRBSTS(P4) ; ??
JRST CC1HRD ;yes, all errors are hard
MOVE T4,CC1SNB(P3) ;get 1st 4 sense bytes
CAMN T4,[SN%DC!SN%COR] ;correctable data check?
JRST CC1CDC ;yes
CAIN T4,SN%EDP ;statistics?
JRST CC1EDP ;#462 yes, ignore, restart operation
TXNE T4,SN%IRQ ;intervention required?
JRST CC1IRQ ;yes
TXNE T4,SN%WIN ;write inhibit?
JRST CC1WLK ;yes
TXNE T4,SN%DC ;data error?
JRST CC1DAE ;yes
MOVX T1,ES.DEV ;no, device error
IORM T1,UDBERR(P3) ;indicate device error on unit
MOVX T1,IS.DVE ;indicate device error ...
IORM T1,IRBSTS(P4) ; ... on request too
MOVE T1,Q3 ;get retry count
IDIVI T1,DEVCNT ;retry count/# of times to retry
MOVE Q3,T1 ;get dividend
JUMPN T2,CC1TRY ;Simple retry unless MOD(retry count,DEVCNT)=0
CAIG Q3,RCLCNT ;recalibrated enough?
JRST CC1RCL ;no, recalibrate and try again
;; CALLRET CC1HRD ;yes, call it a Hard Error
CC1HRD: MOVX T1,ES.HRD ;indicate hard error
IORM T1,UDBERR(P3) ; ... on unit
MOVX T1,IS.NRT!IS.DVE ;indicate hard error
IORB T1,IRBSTS(P4) ;#511 ... on request
LDB T3,IRYFCN ;#511 get the function
CAIN T3,IRFRED ;#511 read?
JRST [ AOS T2,UDBHRE(P3) ;#232 yes, one more hard read error
TXNE T1,IS.SHT ;#511 No bugchk if not a short (PAGEM) IORB
BUG(CC1HRE,<<UDBAKA(P3),UNIT>,<SSASCI(P1),SUBCHN>,<T2,NUMERR>>) ;#232 .
CALLRET CC1DUN] ;#232 .
;;;#232 CAIN T3,IRFWRT ;#511 write?
AOS T2,UDBHWE(P3) ;yes, one more hard write error
BUG(CC1HWE,<<UDBAKA(P3),UNIT>,<SSASCI(P1),SUBCHN>,<T2,NUMERR>>) ;#232 .
CALLRET CC1DUN ;return, saying we give up
HEX.60==6*^D16 ;hex 60
CC1EDP: LOAD T1,BYTE3,+CC1SNB+1(P3) ;#462 env. data: check format code
CAIE T1,HEX.60 ;#462 is it format 6?
BUG(CC1IS6,<<UDBAKA(P3),UNIT>,<SSASCI(P1),SUBCHN>>) ;#462 no, bad
CAIL Q3,DSKNTR ;#462 too many retrys?
JRST CC1HRD ;#462 yes, very strange, give up
JRST CC1TRY ;#462 retry
CC1WLK: MOVX T1,IS.WLK ;set write lock in IORB
IORM T1,IRBSTS(P4) ; .
TXCA T1,<US.WLK^!IS.WLK> ;and mark only write lock in UDB
CC1IRQ: MOVX T1,US.OFS!US.CHB ;mark offline, homeblock check needed
IORM T1,UDBSTS(P3) ;mark in status
JRST CC1HRD ;quit, indicating no more we can do
CC1DAE: MOVX T1,ES.DAT ;data errors
IORM T1,UDBERR(P3) ;mark in UDB
MOVX T1,IS.DTE ;indicate data error
IORM T1,IRBSTS(P4) ; ... on request also
HEX.40==4*^D16 ;hex 40
HEX.4F==4*^D16+^D15 ;hex 4F
LOAD T1,BYTE3,+CC1SNB+1(P3) ;#462 check format code
CAIL T1,HEX.40 ;#462 is it format 4 (ECC correctable)?
CAILE T1,HEX.4F ;#462 is it format 4 (ECC correctable)?
BUG(CC1IS4,<<UDBAKA(P3),UNIT>,<SSASCI(P1),SUBCHN>,<T1,FMT>>) ;#462 no, bad
CAIL Q3,DSKNTR ;too many retrys?
JRST CC1HRD ;yes, give up
JRST CC1TRY ;no, retry
CC1CDC: MOVX T1,ES.ECC ;correctable data check
IORM T1,UDBERR(P3) ; ... flag in UDB
HEX.50==5*^D16 ;hex 50
HEX.5F==5*^D16+^D15 ;hex 5F
LOAD T1,BYTE3,+CC1SNB+1(P3) ;#462 check format code
CAIL T1,HEX.50 ;#462 is it format 5 (ECC correctable)?
CAILE T1,HEX.5F ;#462 is it format 5 (ECC correctable)?
BUG(CC1IS5,<<UDBAKA(P3),UNIT>,<SSASCI(P1),SUBCHN>,<T1,FMT>>) ;#462 no, bad
CALL CC1ESR ;#431 count as a soft read error
MOVE T3,CC1SNB+5(P3) ;get error pattern
TXZ T3,^-<BYTE(8)-1,-1,-1> ;3 bytes only
MOVEI T4,0 ;make word pair in T3,T4
LDB T1,[POINT 16,CC1SNB+4(P3),31] ;get position from end
MOVNS T1 ;negative count
ADDI T1,NBREC ;number of bytes per record - count
IDIVI T1,^D9 ;T1/ word pairs, T2/ bytes to err
ADDI T1,(T1) ;convert # of double words to # of words
IMULI T2,-^D8 ;convert # of bytes to negative # of bits
ROTC T3,(T2) ;move the error bits around
ROT T4,4 ;odd word= bytes 5,6,7,8, last 4 bits of 4
CAML T2,[7*<0,,-^D8>] ;byte 7 or 8?
AOJA T1,[EXCH T3,T4 ;yes, 1st byte is odd, exchange patterns
JRST .+1] ;and continue
SKIPE T3 ;don't bother if no need
CALL CC1XOR ;XOR into buffer if bytes are in buffer
ADDI T1,1 ;next word
SKIPE T3,T4 ;next pattern, skip if nothing to do
CALL CC1XOR ;XOR into buffer if bytes are in buffer
MOVX T1,IS.ERR ;error bit
ANDCAM T1,IRBSTS(P4) ;turn off
MOVX T1,C1.RMW ;read/modify/write cycle?
TDNE T1,CC1STS(P3) ; ??
JRST [ XORM T1,CC1STS(P3) ;yes, change from RBW to WAR
MOVE T1,CC1SCP(P3) ;get pointer to rest of CP
CALLRET CC1GOM] ;make transfer resume
SOS UDBERC(P3) ;not a retry
CALLRET CC1DUN ;say we are done
CC1ESR: AOS T2,UDBSRE(P3) ;#431 ;#232 count soft read errors
TRNN T2,<^D32-1> ;#232 multiple of 32?
BUG(CC1SRE,<<UDBAKA(P3),UNIT>,<SSASCI(P1),SUBCHN>,<T2,NUMERR>>) ;#232 .
RET ;#431 return
CC1ESW: AOS T2,UDBSWE(P3) ;#431 count soft write errors
TRNN T2,<^D32-1> ;#431 ;#232 multiple of 32?
BUG(CC1SWE,<<UDBAKA(P3),UNIT>,<SSASCI(P1),SUBCHN>,<T2,NUMERR>>) ;#232 .
RET ;#431 return
SUBTTL CC1SEN - Do a Sense operation
;CC1SEN - Do a Sense on device
; T1/ C1.SNS
; P1/ CDB
; P3/ UDB
; CALL CC1SEN
; Returns +1: always
; T1,T2 destroyed
CC1SEN: IORM T1,CC1STS(P3) ;turn on "sense in progress" bit
DMOVE T1,CDBCS1(P1) ;get status words
DMOVEM T1,CC1ES1(P3) ;save them for later
LOAD T1,CC1SPA ;get standard channel program address
MOVEI T1,DPOSNP(T1) ;get address of sense program
HRRZ T2,1(T1) ;get address of sense buffer
SETOM 0(T2) ;set invalid sense
CALL CC1GOS ;start the I/O, selector channel mode
RET ;not done yet
SUBTTL I/O Start Routines CC1GOS,CC1GOM,CC1GO
;CC1GOS - Start I/O in selector channel mode
; T1/ address of channel program (CP)
; P1/ CDB
; P3/ UDB
; CALL CC1GOS
; RETURNS +1: always
; T1,T2 destroyed
CC1GOS: HRLI T1,(TCH) ;add transfer command to CP address
MOVX T2,CS.AC1 ;set channel active, if not already, so ...
IORM T2,CDBSTS(P1) ; ... that no other things will start on it
HRRZ T2,UDBAKA(P1) ;get unit
MOVEM T2,CDBXFR(P1) ;show who owns the channel now
JRST CC1GO1 ;store in base and start I/O
;CC1GOM - Start I/O in multiplexor channel mode
; T1/ address of channel program
; P1/ CDB
; P3/ UDB
; CALL CC1GOM
; RETURNS +1: always
; T1,T2 destroyed
CC1GOM: MOVE T2,T1 ;copy address
MOVE T1,CC1SCP(P3) ;get standard channel program
STOR T2,BMX%AD,T1 ;put in current address
MOVEM T1,@CC1DVL(P3) ;store entry for this unit
MOVEM T1,CC1CCP(P3) ;remember current entry
HRROS CDBXFR(P1) ;nobody owns channel, but recall who was last
;; CALLRET CC1GO
;CC1GO - (Re)Start I/O in multiplexor channel mode
; P1/ CDB
; P3/ UDB
; CALL CC1GO
; RETURNS +1: always
; T1,T2 destroyed
CC1GO: MOVX T1,CS.ACT ;set channel not active, so ...
ANDCAM T1,CDBSTS(P1) ; ... that other units can be started
MOVE T1,SSADVL(P1) ;get pointer to device list
CC1GO1: CALLRET SSAGO ;start the I/O
SUBTTL CC1XOR - XOR ECC bits into buffer
;CC1XOR - XOR ECC bits in T3 into user buffer at position T1
; T1/ Displacement into block of 1st byte of correction
; T3/ Correction bits
; P1/ CDB
; P3/ UDB
; CALL CC1XOR
; All AC's preserved
CC1XOR: SAVET ;save temp AC'S
LOAD T4,CC1SPA ;get channel program address
MOVX T2,C1.RMW ;test for Read-Modify-Write cycle
TDNE T2,CC1STS(P3) ;RMW in progress?
MOVEI T4,CC1XCP ;yes, use CP of the Read
CC1XO1: LOAD T2,SC%CNT,DPOADR(T4) ;get count
JUMPE T2,CC1XO3 ;zero count is end of CP
ORCMI T2,.RTJST(SC%CNT,SC%CNT) ;extend sign
ADD T1,T2 ;sub count from displacement
JUMPL T1,CC1XO2 ;jump if word was in this buffer
MOVX T2,SC%LST ;see if data chaining
TDNN T2,DPOADR(T4) ;test for data chaining
AOJA T4,CC1XO1 ;yes, process next IOW
RET ;no, done
CC1XO2: SUB T1,T2 ;compute displacement into buffer
LOAD T2,SC%ADR,DPOADR(T4) ;get buffer address
JUMPE T2,CC1XO3 ;zero address means no data transfer
ADD T1,T2 ;compute address of word to change
CALL PHYMOV ;get the word
XOR T2,T3 ;correct it
CALL PHYSTO ;put the word back
CC1XO3: RET ;return
SUBTTL CC1DUN - Finish up completed request
;CC1DUN - I/O done - finish up
; P1/ CDB
; P3/ UDB
; P4/ IORB
; CALL CC1DUN ;(actually called with CALLRET CC1DUN
; ; so a skip return, meaning DONE, is
; ; given to PHYSIO from CC1INT or CC1ERR)
; RETURNS +2: Always
; T1-T3 destroyed
CC1DUN: ;I/O done (success or failure)
LDB T3,IRYFCN ;get function code
CALL PHYCNT ;get length of transfer
LSH T1,-7 ;as blocks
MOVX T2,C1.RMW ;read/modify/write cycle?
TDNE T2,CC1STS(P3) ; ??
JRST [ ANDCAM T2,CC1STS(P3) ;yes, clear bits
SETZM CC1XCP ;clear flag saying CC1PG in use
AOS CC1RMW(P3) ;count occurrances
JRST .+1]
CAIN T3,IRFRED ;read?
ADDM T1,UDBRED(P3) ;yes, count it
CAIN T3,IRFWRT ;write?
ADDM T1,UDBWRT(P3) ;yes, count it
MOVX T2,C1.RCL ;clear bits related to this I/O
ANDCAB T2,CC1STS(P3) ; .
TXNN T2,C1.TIM ;#[T] doing timing statistics?
RETSKP ;#[T] no
CALL GETMST ;#[T] get time
SUB T1,CC1TIM(P3) ;#[T] subtract time I/O started
ADDB T1,CC1TIM+1(P3) ;#[T] add to sum
AOS T2,CC1TIM+2(P3) ;#[T] count times
IDIV T1,T2 ;#[T] compute average
MOVEM T1,CC1TIM+3(P3) ;#[T] store average
RETSKP ;I/O op done, return IORB
SUBTTL CC1SET - SETUP FOR I/O
;CC1SET - setup for I/O operation
; Q1/ Command code (IBM)
; P1/ CDB
; P3/ UDB
; P4/ IORB
; CALL CC1SET
; RETURNS +1: unable to start partial page write because CC1PG is busy
; RETURNS +2: success
; T1/ Device list entry
CC1SET: MOVX T1,US.WLK!US.OFS ;clear write locked and offline
ANDCAM T1,UDBSTS(P3) ; ...
CALL CC1CNV ;get HW address
CAME T2,UDBPS1(P3) ;same cylinder as last time?
AOS UDBSEK(P3) ;no, count it as another seek
DMOVEM T2,UDBPS1(P3) ;save cylinder, remainder
CALL CC1GHA ;get HW fmt address
LOAD Q3,CC1SPA ;get address of standard CP
DMOVEM T2,DPOSEK(Q3) ;store seek arguments
JUMPE Q1,RSKP ;#[P] quit now if just postioning
LOAD T1,DP%REC,(Q3) ;get physical record number
MOVE T1,DPKSEC(T1) ;get sector for that record
JFCL ;room to patch in modifying instruction
ANDI T1,DPKSPT-1 ;don't let it get out of range
STOR T1,DP%SEC,(Q3) ;store for set-sector command
STOR Q1,DP%CMD,(Q3) ;store command code
MOVEI T1,.SCXCT ;normal flags: eXeCuTe
STOR T1,DP%CCF,(Q3) ;store flags
CALL PHYCNT ;get word count
CAIE T1,PGSIZ ;is it one page?
JRST CC1SE1 ;no, it's a hard one
TXNN T3,DP%LRC ;make sure it is on page boundary
JRST CC1SE9 ;it is
BUG(CC1IRN,<<T3,UDBPS2>,<UDBAKA(P3),UNIT>,<SSASCI(P1),SUBCHN>>) ;<PHYC1 - Illegal record number for page I/O>
RETBAD ;fail (hope it was bad DSKOP)
CC1SE9: CALL CC1GIW ;get IOW for user data in T1
CC1SE6: MOVEM T1,DPOADR(Q3) ;store last IOW in CP
MOVX T1,<HLT.C> ;end of CP command, do not hang when done
MOVEM T1,DPOADR+1(Q3) ;terminate CP
CALL CC1GCP ;get starting address of appropriate CP
RETSKP ;setup done
CC1SE1: ;here when transfer not a page
CAIL T1,PGSIZ ;is it less than a page?
BUG(CC1ISZ,<<T1,SIZE>,<UDBAKA(P3),UNIT>,<SSASCI(P1),SUBCHN>>) ;<PHYC1 - Illegal size for disk I/O>
CAIN Q1,.ICWRD ;is it a write?
JRST CC1SE3 ;yes, that's harder still
MOVX T1,FLD(.SCILE,SC%CCF) ;ignore length error bit
IORM T1,DPOOPC(Q3) ;turn bit on (want to ignore length error)
LOAD T1,DP%LRC,(Q3) ;get logical record number (0,1,2, or 3)
JUMPE T1,CC1SE9 ;1st logical record: nothing to skip
HLLZ T1,CC1IO1-1(T1) ;Get IOW to skip 1/4, 1/2 or 3/4 pg
MOVEM T1,DPOADR(Q3) ;store in CP
AOJA Q3,CC1SE9 ;adjust CP pointer and finish CP
CC1SE3: ;partial page write.
SKIPE CC1XCP ;see if blocking page is in use
RETBAD ;yes, cannot do the write now
MOVE T4,T1 ;save count for later
MOVX T1,C1.RBW ;read/modify/write sequence needed
IORM T1,CC1STS(P3) ;remember special sequence
HRLZ T1,Q3 ;get address of CP for this device
MOVEI T2,CC1XCP ;destination CP
ADD T1,[DPORCL,,CC1XCP+DPORCL] ;from recal of dev CP to recal of xtra
BLT T1,DPOOPC-1(T2) ;move it, devadrs and all
MOVEI T1,DPOOPC-3(T2) ;address of seek
HRRM T1,DPOOPC-1(T2) ;put it in the 'TCH'
LOAD T3,DP%DEV,(Q3) ;get device address
STOR T3,DP%DEV,(T2) ;store device address for read
HRRM Q3,DPOADR+1(T2) ;store addr of normal CP in TCH in xtra prog.
MOVEI T3,.ICRDD ;want to read in the page
STOR T3,DP%CMD,(T2) ;store the read command
LOAD T3,DP%LRC,(Q3) ;get logical record to write
JUMPE T3,CC1SE5 ;first one, that is special
MOVE T2,CC1IO1-1(T3) ;get 1/4, 2/4 or 3/4 page IOW from CC1PGA
MOVEM T2,DPOADR(Q3) ;store
AOJ Q3, ;bump pointer
CC1SE5: LSH T3,^D35-POS(PGSIZ/4) ;# records times length of each
ADDB T3,T4 ;add counts together
SUBI T3,PGSIZ ;subtract page size to get neg. remainder
JUMPE T3,CC1SE9 ;no remainder, finish CP
CALL CC1GIW ;get IOW for user data in T1
TXZ T1,SC%LST ;show this is not last IOW
MOVEM T1,DPOADR(Q3) ;store in CP
MOVEI T1,CC1PGA(T4) ;address of remainder of page
STOR T3,SC%CNT,T1 ;store count, making IOW
TXO T1,SC%LST ;set as last IOW
AOJA Q3,CC1SE6 ;store IOW and terminate CP
; partial page IOW's - use full word for to/from CC1PGA, use LH,0 for skips
CC1IO1: IOW PGSIZ*1/4,CC1PGA,C ; 1/4 pg
CC1IO2: IOW PGSIZ*2/4,CC1PGA,C ; 1/2 pg
CC1IO3: IOW PGSIZ*3/4,CC1PGA,C ; 3/4 pg
SUBTTL CC1GCP - Get Channel program address
;CC1GCP - Get address of approptiate channel program
; P1/ CDB
; P2/ UDB
; P4/ IORB
; CALL CC1GCP
; Returns +1: always
; T1/ pointing to beginning of appropriate CP
CC1GCP: MOVE T1,CC1SCP(P3) ;get beginning of standard CP
MOVE T2,CC1STS(P3) ;get status
TXNE T2,C1.RBW ;is this Read Before Write?
HRRI T1,CC1XCP ;yes, start CP elsewhere
TXNE T2,C1.RCL ;recalibrate needed?
HRRI T1,DPORCL(T1) ;yes, start at recalibrate command
MOVEM T1,CC1CCP(P3) ;save current channel program pointer
RET ;return
SUBTTL CC1GDL - Get Device List for channel
;CC1GDL - Get Device List
; P1/ CDB
; P3/ UDB
; CALL CC1GDL
; Returns +1: failed - no device list yet and no space available
; Returns +2: success - device list is set up, pointed to by SSADVL(P1)
; T1/ address of device list
CC1GDL: SKIPE T1,SSADVL(P1) ;got one already?
RETSKP ;yes
MOVEI T1,MAXSAU+1 ;length needed
CALL SSAALC ;get the space
RETBAD ;failure
HRLI T1,(BMX.LP) ;set for multiplexor channel
MOVEM T1,SSADVL(P1) ;save pointer to device list for SSABAS
PUSH P,T2 ;save AC
MOVX T2,<FLD(.BMXT,BMX%CM)+FLD(.IDDSK,BMX%DV)> ;terminated cmd
HRLI T1,-MAXSAU ;put count of devices in LH for AOBJN
MOVEM T2,0(T1) ;initialize 1
AOBJN T1,.-1 ;initialize them all
SETZM 0(T1) ;end of list indicator
HRRZ T1,SSADVL(P1) ;get back pointer
POP P,T2 ;restore AC
RETSKP ;give good return
SUBTTL CC1MCP - Make Channel Program
;CC1MCP - Make Channel Program
; P1/ CDB
; T1/ Where to move channel program, or 0 to allocate space
; Q2/ Unit number
; CALL CC1MCP
; Returns +1: failure to allocate space (only if T1 was 0)
; Returns +2: success
; T1/ address of channel program
; T2,T3,T4 destroyed
CC1MCP: JUMPN T1,CC1MC1 ;jump if destination specified
MOVEI T1,DPOLEN ;how much space is needed
CALL SSAALC ;allocate space in un-cached page
RETBAD ;failure if no space
CC1MC1: PUSH P,T1 ;save address
ADDI Q2,.IDDSK ;make device address
MOVE T2,[-DPOLEN,,CC1PCP+DPORCL] ;AOBJN pointer for move
CC1MC2: MOVE T3,0(T2) ;get 1 word
LOAD T4,SC%CCF,T3 ;get channel flags
CAIN T4,.RTJST(TCH,SC%CCF) ;is it a transfer-in-channel?
JRST CC1MC4 ;yes, fixup address
CAIE T4,.RTJST(HLT.C,SC%CCF) ;is it a halt (continue)
CAIN T4,.RTJST(HLT.H,SC%CCF) ;is it a halt (hang)
JRST CC1MC5 ;halt - no fixup needed
STOR Q2,SC%DEV,T3 ;store device address in command
TXNE T4,.SCNMX ;memory transfer?
JRST CC1MC5 ;no, store and go on to next command
MOVEM T3,0(T1) ;yes, store the command
ADDI T1,1 ;point to where the IOW goes
AOBJN T2,.+1 ;point to source IOW
MOVE T3,0(T2) ;get the IOW
CC1MC4: TRNN T3,-1 ;is there an address here?
JRST CC1MC5 ;no, leave it zero
SUBI T3,0(T2) ;compute displacement from source
ADDI T3,0(T1) ;make address in destination
CC1MC5: MOVEM T3,0(T1) ;store the fixed-up cmd word
ADDI T1,1 ;next cmd stg location
AOBJN T2,CC1MC2 ;next word to move, if any more
POP P,T1 ;restore destination address
MOVEI T1,-DPORCL(T1) ;point to normal starting cmd
SKIPN T2,SSASBA(P1) ;get address of sense buffer for this channel
MOVEI T2,CC1PGA ;not set up yet, use our special page
STOR T2,SC%ADR,DPOSNP+1(T1) ;store in sense program
SUBI Q2,.IDDSK ;make unit number again
RETSKP ;return with T1/ CP
SUBTTL CC1GSB - Get a Sense Buffer for channel
;CC1GSB - Get Sense Buffer for channel
; P1/ CDB
; CALL CC1GSB
; Returns +1: failure - no space
; Returns +2: success - address of sense buffer stored in SSASBA(P1)
; T1/ Address of sense buffer
CC1GSB: SKIPE T1,SSASBA(P1) ;get address of sense buffer if exists
RETSKP ;return with Sense buffer address
MOVEI T1,6 ;need 24 bytes for sense buffer
CALL SSAALC ;allocate core
RETBAD ;no space
MOVEM T1,SSASBA(P1) ;save address for later
RETSKP ;return successfully
SUBTTL CC1GIW - get I/O word for transfer
;CC1GIW - Get I/O word for this transfer (and flush XFR page from cache)
; P1/ CDB
; P3/ UDB
; P4/ IORB
; Q1/ IBM command code (either .ICWRD or command is a "read")
; CALL CC1GIW
; RETURNS +1: always
; T1/ IOW for transfer
; T2 destroyed
CC1GIW: ;get I/O word
PUSH P,T3 ;save T3
PUSH P,T4 ;save T4
CALL PHYXFL ;get I/O list
CAIE T1,-1(T2) ;one word list?
BUG(CC1LTL,<<T1,FIRST>,<T2,LAST>,<UDBAKA(P3),UNIT>,<SSASCI(P1),SUBCHN>>) ;<PHYC1 - I/O list too long>
LOAD T1,SC%PAG,(T1) ;get page of user buf
CAIN Q1,.ICWRD ;if this is a write, ...
CALL CASHVP ;... then validate page from cache
CAIE Q1,.ICWRD ;if not a write, ...
CALL CASHIP ;... then just invalidate page
MOVE T1,-1(T2) ;get the IOW
MOVEM T1,CC1IOW(P3) ;save in case of error
POP P,T4 ;restore AC
POP P,T3 ;restore AC
RET
SUBTTL CC1CNV - CONVERT IORB TO CYLINDER, 'SECTOR'
;CC1CNV - convert to cylinder, 'sector' within cylinder, given IORB
; P3/ UDB
; P4/ IORB
; CALL UDSCNV(ac) ;where ac/ CC1DSP
; RETURNS +1: always
; T2/ Cylinder (for UDBPS1)
; T3/ 'Sector' within cylinder (for UDBPS2)
CC1CNV: CALL PHYBLK ;get unit relative block number
HRRZ T3,CC1SCL(P3) ;get 'sectors' per cylinder
IDIVI T2,(T3) ;convert
RET
;CC1GHA - get HWFMT cylinder/surface/record address
; T2/ Cylinder
; T3/ 'sector' within cylinder
; P3/ UDB
; CALL CC1GHA
; RETURNS +1: always
; T2/ HWFMT 1st word of seek: search address containing cylinder
; T3/ HWFMT 2nd word of seek: search address containing surface, record,
; quarter page within physical record
; T4 destroyed
CC1GHA: HRRZ T4,CC1SSF(P3) ;get records per surface
IDIVI T3,(T4) ;get surface, record
LSH T2,<^D35-POS(DP%CYL)> ;position cylinder for hardware
LSH T3,<^D35-POS(DP%SRF)> ;position surface
DPB T4,[POINTR(T3,DP%REC!DP%LRC)] ;insert record, logical record
ADDI T3,FLD(1,DP%REC) ;record numbers start with 1
; note that T3 will work as the 2nd word of seek/search arguments, and
; if this is not a normal 1 page transfer, byte 3 contains which quarter
; of the page to start with.
RET
SUBTTL Retry routines CC1RCL, CC1TRY
;CC1RCL, CC1TRY - retry a transfer after an error, W/ or W/O recalibrate
; P1/ CDB
; P3/ UDB
; P4/ IORB
; CALL CC1RCL / CALL CC1TRY
; RETURNS +1: transfer restarted
; P4/ 0
; Returns +2: failure, hard error recorded
CC1RCL: MOVX T1,C1.RCL ;retry with recalibrate
IORM T1,CC1STS(P3) ;set recalibrate bit
JRST CC1TR0
CC1TRY: MOVX T1,C1.RCL ;retry without recalibrate
ANDCAM T1,CC1STS(P3) ;turn off recalibrate bit
; JRST CC1TR0
CC1TR0: CALL SETIO ;clear error bits in IORB, CDBDSP to T1
CALL CDSSIO(T1) ;start I/O
JRST CC1HRD ;very strange
SETZ P4, ;tell PHYSIO to dismiss the interrupt
RET ;and wait for next one
TNXEND
END