Passing Multiple Physical Optical Drives to a Windows VM Using SCSI (libvirt / KVM)This guide explains: How the original XML configuration worked with 2 optical drives How it was extended to support 4 physical optical drives Why each part of the configuration matters The setup uses SCSI passthrough and virtio-scsi controllers. 1. Adding SCSI Controllers to the VMFirst, the VM needs SCSI controllers to attach devices to. In this configuration, two virtio-scsi controllers are used: <controller type='scsi' index='0' model='virtio-scsi'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x0b' function='0x0'/>
</controller>
<controller type='scsi' index='1' model='virtio-scsi'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x0c' function='0x0'/>
</controller>
What this does: Creates two independent SCSI controllers inside the guest Uses virtio-scsi for good performance and flexibility Pins each controller to a fixed PCI slot so device ordering remains stable At this point, Windows sees two empty SCSI controllers. 2. How a Physical Optical Drive Is Passed ThroughEach physical drive is passed using a <hostdev> block with type='scsi'. Example of a single optical drive: <hostdev mode='subsystem' type='scsi' managed='no'>
<source>
<adapter name='scsi_host6'/>
<address bus='0' target='0' unit='0'/>
</source>
<readonly/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
</hostdev>
This block has two important parts. 2.1 Host-side device selection<source>
<adapter name='scsi_host6'/>
<address bus='0' target='0' unit='0'/>
</source>
Meaning: scsi_host6 identifies the SCSI controller on the Linux host bus / target / unit identifies the exact physical device attached to it This tells libvirt which real optical drive to use. 2.2 Guest-side placement<address type='drive' controller='0' bus='0' target='0' unit='0'/>
Meaning: Attaches the drive to SCSI controller 0 inside the VM Assigns a unique SCSI address in the guest Every drive inside the VM must have a unique (controller, bus, target, unit) combination. 2.3 Read-only flag<readonly/>
This marks the device as read-only in the guest, which matches optical drive behavior and prevents accidental writes. 3. Why the Original Setup Worked for 2 DrivesTwo virtio-scsi controllers existed Each optical drive: Used a different host SCSI adapter Was attached to a different guest controller No guest SCSI address conflicts existed 4. Identifying Additional Optical Drives on the HostTo add more drives, first list them on the Linux host: lsscsi
Example output: [12:0:1:0] cd/dvd /dev/sr0
[12:0:4:0] cd/dvd /dev/sr1
[12:0:5:0] cd/dvd /dev/sr2
[12:0:6:0] cd/dvd /dev/sr3
Format: [host : channel : target : lun]
From this output: Host adapter = 12 → scsi_host12 Channel = 0 Targets = 1, 4, 5, 6 LUN = 0 5. Scaling from 2 Drives to 4 DrivesInstead of adding more controllers, we reused the existing two and placed two drives on each controller. Guest-side layout:Controller 0: unit 0 unit 1 Controller 1: unit 0 unit 1 This avoids address collisions and keeps the configuration clean. 6. Final Working Configuration (4 Drives)<controller type='scsi' index='0' model='virtio-scsi'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x0b' function='0x0'/>
</controller>
<controller type='scsi' index='1' model='virtio-scsi'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x0c' function='0x0'/>
</controller>
<hostdev mode='subsystem' type='scsi' managed='no'>
<source>
<adapter name='scsi_host12'/>
<address bus='0' target='1' unit='0'/>
</source>
<readonly/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
</hostdev>
<hostdev mode='subsystem' type='scsi' managed='no'>
<source>
<adapter name='scsi_host12'/>
<address bus='0' target='4' unit='0'/>
</source>
<readonly/>
<address type='drive' controller='0' bus='0' target='0' unit='1'/>
</hostdev>
<hostdev mode='subsystem' type='scsi' managed='no'>
<source>
<adapter name='scsi_host12'/>
<address bus='0' target='5' unit='0'/>
</source>
<readonly/>
<address type='drive' controller='1' bus='0' target='0' unit='0'/>
</hostdev>
<hostdev mode='subsystem' type='scsi' managed='no'>
<source>
<adapter name='scsi_host12'/>
<address bus='0' target='6' unit='0'/>
</source>
<readonly/>
<address type='drive' controller='1' bus='0' target='0' unit='1'/>
</hostdev>
7. Key TakeawaysEach physical drive requires its own <hostdev> block Host SCSI addresses must match lsscsi output exactly Guest SCSI addresses must be unique Reusing controllers with different unit values scales cleanly This approach works reliably for multiple optical drives in Windows VMs