A subroutine is just a routine that performs a service for some other routine.
An internal subroutine is just a subroutine that is in the same program as the routine that uses it and often uses an abbreviated calling sequence. An internal subroutine is usually just a few lines of code.
An external subroutine is a subroutine that is external to the program that uses it. That means it is assembled separately from the program that uses it. It is usually much larger than an internal subroutine. It is often statically linked with the routine that uses it.
For example, I often want a program to have an optional DD statement for some reason. However, I don't want to expose the DD statement if it is not provided, so I don't want to even attempt to open it if it isn't there. In other words, no IEC130I message when the program is run. So I wrote a small subroutine to test if a DD statement is present. The input to the subroutine is the parameter list created by an OPEN macro so I can test multiple DD statements. As an internal subroutine it is coded like this -
CNOP 0,8
TESTDD BASR 15,0
SAVE (14,3),,TESTDD
LR 2,1
SR 3,3
TDD0100 L 1,0(,2)
N 1,=A(X'FFFFFF')
DEVTYPE DCBDDNAM-IHADCB(,1),64(,13)
LTR 15,15
JZ TDD0200
LHI 3,4
TDD0200 TM 0(2),X'80'
LA 2,4(,2)
JZ TDD0100
LR 15,3
RETURN (14,3),T,RC=(15)
It is called like this -
LA 1,OPENPARM
BAS 14,TESTDD
...
OPENPARM OPEN (ADCB,INPUT),MF=L
ADCB DCB DDNAME=SYSIN,...
As an external subroutine, the code for TESTDD would be a little different.
TESTDD CSECT
SAVE (14,3),,TESTDD
LR 2,1
SR 3,3
TDD0100 L 1,0(,2)
N 1,=A(X'FFFFFF')
DEVTYPE DCBDDNAM-IHADCB(,1),64(,13)
LTR 15,15
JZ TDD0200
LHI 3,4
TDD0200 TM 0(2),X'80'
LA 2,4(,2)
JZ TDD0100
LR 15,3
RETURN (14,3),T,RC=(15)
DC 0D'0'
LTORG ,
DCBD DSORG=QS,DEVD=DA
END ,
There are a number of different ways to call an external subroutine. For example, if it is statically linked, it might be called like this -
CALL TESTDD,MF=(E,OPENPARM)
...
OPENPARM OPEN (ADCB,INPUT),MF=L
ADCB DCB DDNAME=SYSIN,...
You can also call it dynamically, perhaps like this -
LINK EP=TESTDD,MF=(E,OPENPARM)
...
OPENPARM OPEN (ADCB,INPUT),MF=L
ADCB DCB DDNAME=SYSIN,...
The advantage of calling it dynamically is if you should discover a mistake, you can correct the mistake, and the revised version would be used the next time the subroutine is used. On other hand, since the system must locate and actually load TESTDD when it is used, it is much slower than using a static call.