Let's look again at the example configuration from the last post:
Device Subchan. DevType CU Type Use PIM PAM POM CHPIDsThe second device is the virtio-blk device 0.0.0042 on subchannel 0.0.0001, having channel path 0. Being virtio, this is a very simplified variation of what you'd see on real hardware (although this also can be a benefit in some way). Think of it as the following:
0.0.0000 0.0.0000 0000/00 3832/01 yes 80 80 ff 00000000 00000000
0.0.0042 0.0.0001 0000/00 3832/02 yes 80 80 ff 00000000 00000000
Device 0.0.0042 is accessed via channel path 0, and subchannel 0.0.0001 is used as a means to address it.
The access (channel path) is configured in the hypervisor (or in the hardware definitions). The subchannel is what the OS will use as a target for I/O instructions and how it can associate I/O interrupts with the device they are for.
I/O instructions? There's a whole zoo of them, but they share some characteristics:
- They take a subchannel identifier as parameter.
- They are privileged: I.e., on a Linux system, they can only be issued by the kernel and not from user space.
- START SUBCHANNEL (SSCH) - start a channel program
- TEST SUBCHANNEL (TSCH) - retrieve subchannel status
ccws consist of three parts:
- The command. This falls into the categories of read (read data from the device), write (write data to the device) or control (for example, rewinding a tape). An 8-bit value.
- The flags, which control error handling or program flow. I'll ignore them for simplicity here.
- The data address. This is an address in memory where data is written to (read) or read from (write).
The operating system will assemble a ccw: The command code will be 0xe4 for SENSE ID, and the data address will point to a location wherethe OS wants to have the obtained information. The OS will also assemble a so-called ORB (operation request block), which, amongst other things, points to the assembled ccw (respectively the first one in a chain). This ORB and the subchannel id are the two parameters for the SSCH instruction. If all goes well, the OS will receive a condition code 0 and knows that it will be signalled asynchronously once the channel program has been processed (successfully or with errors)1.
Processing of the actual channel command is done asynchronously by real hardware (QEMU does it synchronously for simplicity reasons). The result is that the wanted data is put into the memory area refered to by the ccw2. Subsequently, the subchannel is made status pending: Information is ready for retrieval by the OS.
Usually, the OS wants to have a notification that the subchannel became status pending; this is done via an I/O interrupt. I/O interrupts on s390 carry extra status which is written to the low memory area of the cpu receiving the interrupt; amongst other things, this status contains the subchannel id.
Next, the OS needs to actually retreive the status information: This is done via the TSCH instruction, which in turn makes the subchannel no longer status pending and ready for the next I/O request via SSCH. The status contains enough information for the OS to determine whether the request was successful (and the sense id information has been stored), or whether there was an error.3
Of course, this is all only scratching at the surface of channel programs; interested readers can peek at the Linux kernel and QEMU to get a feel for both parts or at the Principles of Operation for the whole story.4
1. In the Linux source code, you'll find this under drivers/s390/cio/↩
2. In the QEMU source code, you'll find channel command interpretation under hw/s390x/css.c↩
3. Again, you'll find this under drivers/s390/cio/ in the Linux source code↩
4. Command chaining, channel path management, I/O instructions to terminate a channel program are just some of the interesting topics.↩