The answer comes in the units of the FAT file system. A sector is the disk's unit of transfer (512 bytes on every PC disk); a cluster is a group of sectors and the smallest piece of disk a file can get, so every file's size on disk is rounded up to whole clusters. 36h returns how big a cluster is and how many there are:

QuantityFrom the registers
bytes per clusterAX × CX
free bytesAX × CX × BX
size of the driveAX × CX × DX

The products do not fit 16 bits. Two MULs do it: the first gives the cluster size (in AX alone for clusters up to 32 KB), the second multiplies by the free clusters and leaves the free bytes in DX:AX:

MUL CX ; AX = bytes per cluster (DX = 0)
MUL BX ; DX:AX = free bytes

Errors are reported the old way, before DOS used the carry flag: AX = FFFFh means the drive does not exist, and nothing else is set. For a floppy drive without a disk, DOS calls the critical error handler first (INT 24h: Not ready reading drive A, Abort, Retry, Fail), and returns FFFFh if the user picks Fail.

The registers are 16 bits, so a drive larger than 2 GB cannot be described. DOS 7.1 caps the numbers here at just under 2 GB and offers function 7303h of INT 21h for the real ones on FAT32.

In DOSBox-X

A drive mounted from a folder on the host has no clusters: DOSBox-X makes up a geometry and reports as free space the amount MOUNT was given with -freesize. In the workbench, C: reports what is left of the box's disk allowance. Z:, DOSBox-X's virtual drive, always reports 32 sectors of 512 bytes per cluster, 32765 clusters and nothing free, so the example asks about Z: and its output is always the same:

prints: Z: 32 sectors x 512 bytes, 0 of 32765 clusters free / drive 27: AX = FFFF
MOV DX, OFFSET ZM1
MOV AH, 09h
INT 21h
MOV AH, 36h ; DOS: free space on drive DL
MOV DL, 26 ; 26 = Z: (1 = A here; 0 = the current drive)
INT 21h
CMP AX, 0FFFFh ; FFFFh: no such drive
JE NONE1
MOV BPS1, CX ; keep the answer: printing changes it
MOV FREE1, BX
MOV TOTAL1, DX
CALL PDEC ; sectors per cluster
MOV DX, OFFSET SPCM1
MOV AH, 09h
INT 21h
MOV AX, BPS1
CALL PDEC
MOV DX, OFFSET BPSM1
MOV AH, 09h
INT 21h
MOV AX, FREE1
CALL PDEC
MOV DX, OFFSET OFM1
MOV AH, 09h
INT 21h
MOV AX, TOTAL1
CALL PDEC
MOV DX, OFFSET FREEM1
MOV AH, 09h
INT 21h
NONE1:
MOV DX, OFFSET BADM1
MOV AH, 09h
INT 21h
MOV AH, 36h ; a drive that cannot exist
MOV DL, 27
INT 21h
CALL PHEX ; FFFF
MOV DX, OFFSET CRLF
MOV AH, 09h
INT 21h
ZM1 DB "Z: $"
SPCM1 DB " sectors x $"
BPSM1 DB " bytes, $"
OFM1 DB " of $"
FREEM1 DB " clusters free", 13, 10, "$"
BADM1 DB "drive 27: AX = $"
BPS1 DW 0
FREE1 DW 0
TOTAL1 DW 0
CRLF DB 13, 10, "$"
PDEC PROC NEAR ; print AX in decimal (changes AX BX CX DX)
MOV BX, 10
XOR CX, CX ; digits on the stack
PDEC1:
XOR DX, DX
DIV BX ; AX = AX / 10, DX = the last digit
PUSH DX
INC CX
OR AX, AX
JNZ PDEC1
PDEC2:
POP DX ; the digits come back first to last
ADD DL, "0"
MOV AH, 02h
INT 21h
LOOP PDEC2
RET
PDEC ENDP
PHEX PROC NEAR ; print AX as four hex digits (changes AX BX CX DX)
MOV BX, AX
MOV CX, 4
PHEX1:
PUSH CX
MOV CL, 4
ROL BX, CL ; the top digit to the bottom
POP CX
MOV DL, BL
AND DL, 0Fh
ADD DL, "0"
CMP DL, "9"
JBE PHEX2
ADD DL, 7 ; "A" to "F"
PHEX2:
MOV AH, 02h
INT 21h
LOOP PHEX1
RET
PHEX ENDP

INT 21h AH=1Ch returns the same geometry without the free count (and INT 21h AH=1Bh for the current drive), plus a pointer to the media descriptor byte.