summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--pc-bios/s390-ccw/iplb.h12
-rw-r--r--pc-bios/s390-ccw/main.c12
-rw-r--r--pc-bios/s390-ccw/virtio-scsi.c11
-rw-r--r--pc-bios/s390-ccw/virtio.h2
4 files changed, 37 insertions, 0 deletions
diff --git a/pc-bios/s390-ccw/iplb.h b/pc-bios/s390-ccw/iplb.h
index 1cf509f497..86abc56a90 100644
--- a/pc-bios/s390-ccw/iplb.h
+++ b/pc-bios/s390-ccw/iplb.h
@@ -43,6 +43,16 @@ struct IplBlockFcp {
 } __attribute__ ((packed));
 typedef struct IplBlockFcp IplBlockFcp;
 
+struct IplBlockQemuScsi {
+    uint32_t lun;
+    uint16_t target;
+    uint16_t channel;
+    uint8_t  reserved0[77];
+    uint8_t  ssid;
+    uint16_t devno;
+} __attribute__ ((packed));
+typedef struct IplBlockQemuScsi IplBlockQemuScsi;
+
 struct IplParameterBlock {
     uint32_t len;
     uint8_t  reserved0[3];
@@ -55,6 +65,7 @@ struct IplParameterBlock {
     union {
         IplBlockCcw ccw;
         IplBlockFcp fcp;
+        IplBlockQemuScsi scsi;
     };
 } __attribute__ ((packed));
 typedef struct IplParameterBlock IplParameterBlock;
@@ -63,6 +74,7 @@ extern IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
 
 #define S390_IPL_TYPE_FCP 0x00
 #define S390_IPL_TYPE_CCW 0x02
+#define S390_IPL_TYPE_QEMU_SCSI 0xff
 
 static inline bool store_iplb(IplParameterBlock *iplb)
 {
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 9446ecc235..345b848752 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -84,6 +84,18 @@ static void virtio_setup(void)
             debug_print_int("ssid ", blk_schid.ssid);
             found = find_dev(&schib, dev_no);
             break;
+        case S390_IPL_TYPE_QEMU_SCSI:
+        {
+            VDev *vdev = virtio_get_device();
+
+            vdev->scsi_device_selected = true;
+            vdev->selected_scsi_device.channel = iplb.scsi.channel;
+            vdev->selected_scsi_device.target = iplb.scsi.target;
+            vdev->selected_scsi_device.lun = iplb.scsi.lun;
+            blk_schid.ssid = iplb.scsi.ssid & 0x3;
+            found = find_dev(&schib, iplb.scsi.devno);
+            break;
+        }
         default:
             panic("List-directed IPL not supported yet!\n");
         }
diff --git a/pc-bios/s390-ccw/virtio-scsi.c b/pc-bios/s390-ccw/virtio-scsi.c
index 3bb48e917e..d850a8deed 100644
--- a/pc-bios/s390-ccw/virtio-scsi.c
+++ b/pc-bios/s390-ccw/virtio-scsi.c
@@ -204,6 +204,17 @@ static void virtio_scsi_locate_device(VDev *vdev)
     debug_print_int("config.scsi.max_target ", vdev->config.scsi.max_target);
     debug_print_int("config.scsi.max_lun    ", vdev->config.scsi.max_lun);
 
+    if (vdev->scsi_device_selected) {
+        sdev->channel = vdev->selected_scsi_device.channel;
+        sdev->target = vdev->selected_scsi_device.target;
+        sdev->lun = vdev->selected_scsi_device.lun;
+
+        IPL_check(sdev->channel == 0, "non-zero channel requested");
+        IPL_check(sdev->target <= vdev->config.scsi.max_target, "target# high");
+        IPL_check(sdev->lun <= vdev->config.scsi.max_lun, "LUN# high");
+        return;
+    }
+
     for (target = 0; target <= vdev->config.scsi.max_target; target++) {
         sdev->channel = channel;
         sdev->target = target; /* sdev->lun will be 0 here */
diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h
index 3c6e91510e..eb35ea5faf 100644
--- a/pc-bios/s390-ccw/virtio.h
+++ b/pc-bios/s390-ccw/virtio.h
@@ -274,6 +274,8 @@ struct VDev {
     uint64_t scsi_last_block;
     uint32_t scsi_dev_cyls;
     uint8_t scsi_dev_heads;
+    bool scsi_device_selected;
+    ScsiDevice selected_scsi_device;
 };
 typedef struct VDev VDev;