Reading your post, you left me under the impression that you are trying to access the disk hardware while still under the UEFI blanket. Is this true? If so, use the UEFI, that is what it is there for.
it looks like for many people, compiling UEFI by themselves (which is absolutely pointless) is easier, than reading the specification (which is absolutely needed when one goes - "I've switched to UEFI"). and where it's pretty clearly described how one is supposed to use it.
for the OP, you don't need to program disk controller to access your storage under UEFI. if you don't want to store your OS under ESP, that's fine, it is even good, it's not supposed to be used for that - you need to only store there your OS loader. you do access the volume, containing your OS files either using already given to you file/simple file system/load file protocols*, if it's FAT formatted and thus supported by UEFI or through disk IO/block device protocols**, and then add the code for reading your volume and its FS with any FS and overall structure you want. I suppose, you didn't invent your own block device, right?
so, UEFI already is able to read/write the block device you put your boot volume on, everything left is adding your FS reading code.
*
12.4 Simple File System Protocol
This section defines the Simple File System protocol. This protocol allows code running in the EFI boot services environment to obtain file based access to a device. EFI_SIMPLE_FILE_SYSTEM_PROTOCOL is used to open a device volume and return an EFI_FILE_PROTOCOL that provides interfaces to access files on a device volume.
12.5 EFI File Protocol
The protocol and functions described in this section support access to EFI-supported file systems.
12.1 Load File Protocol
This section defines the Load File protocol. This protocol is designed to allow code running in the boot services environment to find and load other modules of code.
**
12.7 Disk I/O Protocol
This section defines the Disk I/O protocol. This protocol is used to abstract the block accesses of the Block I/O protocol to a more general offset-length protocol. The firmware is responsible for adding this protocol to any Block I/O interface that appears in the system that does not already have a Disk I/O protocol. File systems and other disk access code utilize the Disk I/O protocol.
12.9 EFI Block I/O Protocol
This section defines the Block I/O protocol. This protocol is used to abstract mass storage devices to allow code running in the EFI boot services environment to access them without specific knowledge of the type of device or controller that manages the device. Functions are defined to read and write data at a block level from mass storage devices as well as to manage such devices in the EFI boot services environment.