A lot of people are moving off ESXi and migrating to Proxmox. Hosting SCO Openserver is simple on ESXi because SCO Openserver has good driver compatibility.
Proxmox will run it out of the box. OpenServer boots quite happily under QEMU/KVM. The problem is what it boots on: emulated IDE, or an emulated LSI SCSI card. Both are slow, and IDE brings its own problems on a modern hypervisor. There is no virtio support in OpenServer 5.
So I wrote two drivers: a virtio-scsi disk driver and a virtio-net network driver, for OpenServer 5.0.6 and 5.0.7.
Everything is here, MIT licensed, with the boot media you need to install onto a virtio disk:
https://github.com/tachytelic/sco-openserver-proxmox
You can install OpenServer directly onto a virtio disk, boot from it with no boot string, and run with no emulated IDE hardware in the machine at all.
%vscsi 0xE040-0xE07F 10 - type=vscsi ha=0 virtio-scsi %cd-rom - - - type=S ha=0 id=0 lun=0 bus=0 ht=vscsi %disk - - - type=S ha=0 id=0 lun=1 bus=0 ht=vscsi %Sdsk - - - cyls=1044 hds=255 secs=63 unit=0 fts=sdb
The README covers installation. What follows is the part that is more interesting: the things that went wrong, and what each of them turned out to mean. If you are debugging your own OpenServer install, one of these may be your problem.
Writing a driver for an interface that was documented in 1995
OpenServer’s host adapter interface is not in the public HDK books. SCO shipped a worked example, the `Sram` sample driver, and a 1995 specification called TLS006. Between them you can work out the shape of it, though not on the first attempt.
I built this with Claude, and I would not describe the process as effortless. Persuading a language model to write a SCSI host adapter driver against a 1995 kernel interface involves a great many firmly worded reminders that no, that function does not exist, and no, that structure is not laid out like that. It got there in the end. SCO’s own certification suite, written in 1999 by people with no opinion whatsoever about any of this, was what settled whether it had actually worked.
My favourite failure along the way was a structure packing mismatch that made the command block read back as all zeros. An all zero CDB is a perfectly valid TEST UNIT READY, so every command succeeded and the driver looked healthy, while INQUIRY and READ CAPACITY quietly did nothing at all.
error loading hd(40)/boot
The install would complete, the driver worked, and booting from CD was fine. Only the native boot from disk failed:
not a directory boot not found Stage 1 boot failure: error loading hd(40)/boot
Stage 1 reads the filesystem through BIOS geometry, before any driver exists. But the layout it is reading was written at install time using the geometry the driver reported. Mine said 128 heads and 32 sectors; SeaBIOS computes 255/63.
You can force the firmware to match with QEMU’s `lcyls`, `lheads` and `lsecs`, and it is a trap: Proxmox does not expose them, so you end up attaching the disk through an `args:` line, and Proxmox cannot snapshot or back up a volume it does not manage. The fix was to report what the firmware already computes.
The CD-ROM that thought it was a hard disk
I put the CD-ROM on the virtio-scsi controller alongside the disk, so the disk sat at LUN 0 and the CD at LUN 2. Every read failed, and OpenServer thought the drive was this:
%Srom-0 - - - Vnd=QEMU Prd=QEMU HARDDISK Rev=2.5+
QEMU’s CD-ROM calls itself QEMU DVD-ROM. QEMU HARDDISK is the hard disk.
Srom, OpenServer’s CD-ROM driver, does not handle LUNs. Whatever mscsi says, every command it issues arrives with the LUN as zero, so it was talking to whatever sat at LUN 0. The disk driver does not have this problem, which is why a second *disk* at LUN 1 works fine and lulls you into thinking LUNs are handled.
The fix is simple once you see it. Give the LUN-incapable device the slot that maps to LUN 0:
qm set 507 --scsi0 local:iso/openserver.iso,media=cdrom # CD -> LUN 0
qm set 507 --scsi1 local-lvm:8,cache=writeback # disk -> LUN 1
The payoff is a machine with no IDE controller at all, and the installer notices:
`wd`, `wdex` and `wdha` come out unconfigured on their own. Strip the USB and UDI stacks as well, which a virtio guest has no use for either, and the kernel on my test machine went from 3,221,754 bytes to 2,303,213, giving back about 6 MB of permanently resident kernel memory.
SCO’s own test suite found a real bug
SCO shipped an HBA Certification Test Suite in 1999, O5hbacert, used to certify third party SCSI drivers. It is adversarial in a way that “it boots and I copied a file” is not, and it found a defect before it had run a single test.
The interesting one was two tests that read and wrote past the end of the device and reported success:
SCSIUSERCMD2 succeeded with READTEN_CMD on block 4612271 for 400 blocks sense data is not valid... Maybe your adapter doesn't support the auto-sense mechanism.
That reads like silent data loss. It was not: the device rejected the commands correctly and nothing was written past the end of the disk. What my driver was losing was the *reason*, because it delivered the sense data to the wrong place.
Two real defects, both fixed.
Final result is 59 pass, 5 fail, 2 unsupported, and all five failures are QEMU device emulation gaps rather than driver faults.
Multiprocessor needs the right host CPU
The MPX kernel ran correctly and was unusably slow: a 50 MB write took 32 seconds against half a second on the uniprocessor kernel.
OpenServer implements `spl()`, which raises and lowers interrupt priority, as a write to the local APIC Task Priority Register, and calls it constantly. If the host CPU cannot virtualise the APIC registers, every one of those writes traps to the hypervisor and is emulated. Tracing showed 27,000 of them a second, all at guest physical address `0xfee00080`.
For usable multiprocessor performance you need a host CPU capable of APIC register virtualisation.
Check before you start:
cat /sys/module/kvm_intel/parameters/enable_apicv
If that reads `N`, no amount of tuning inside the guest will help. The capability arrived with Haswell. On a host where it reads `Y`, the same VM and workload dropped from ~32 seconds to 0.35, which is indistinguishable from the uniprocessor kernel.
Where it ended up
Both drivers work on 5.0.6 and 5.0.7 from the same binary. Network throughput, measured with 200 MB of incompressible data over plain HTTP so neither encryption nor the disk is in the way:
| direction | throughput | | host to guest | 123-131 MB/s | | guest to host | 50-53 MB/s |
That is on a Dell OptiPlex 7090 with an i5-10505, both endpoints on the same host so the traffic never touches a wire. Across a real 1 GbE LAN it gives 60-66 and 40-42 MB/s, at which point the physical link is the limit rather than the driver.
Your numbers will differ.
If you need this doing
The drivers are free and the documentation is complete enough to follow on your own. If you would rather not, migrating legacy OpenServer systems to Proxmox is something I do professionally, including P2V from real hardware and the application-level work of making sure the thing still behaves once it is running.

Leave a Reply