pc-bios/s390-ccw: Pass selected SCSI device to IPL
authorEugene (jno) Dvurechenski <jno@linux.vnet.ibm.com>
Wed, 1 Jun 2016 13:25:51 +0000 (15:25 +0200)
committerCornelia Huck <cornelia.huck@de.ibm.com>
Mon, 11 Jul 2016 07:48:05 +0000 (09:48 +0200)
There is ,bootindex=%d argument to specify the lookup order of
boot devices.

If a bootindex assigned to the device, then IPL Parameter Info Block
is created for that device when it is IPLed from.

If it is a mere SCSI device (not FCP), then IPIB is created with a
special SCSI type and its fields are used to store SCSI address of the
device. This new ipl block is private to qemu for now.

If the device to IPL from is specified this way, then SCSI bus lookup
is bypassed and prescribed devices uses the address specified.

Signed-off-by: Eugene (jno) Dvurechenski <jno@linux.vnet.ibm.com>
Signed-off-by: Alexander Yarygin <yarygin@linux.vnet.ibm.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
pc-bios/s390-ccw/iplb.h
pc-bios/s390-ccw/main.c
pc-bios/s390-ccw/virtio-scsi.c
pc-bios/s390-ccw/virtio.h

index 1cf509f49746bb61778eb37b4f65f36b08b916a1..86abc56a90e86a8e28646f40af72f53f38cda312 100644 (file)
@@ -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)
 {
index 9446ecc235a65fb9dd6b8574b8d0eda6f1428fd7..345b84875278b12a918b2b32fc3e9c1b51e1a312 100644 (file)
@@ -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");
         }
index 3bb48e917ea595c10748d1b8896499f5862a1ccf..d850a8deed5b22dc653bab1b2d630939c442dc25 100644 (file)
@@ -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 */
index 3c6e91510ef667276dddf9d6dd7a8223a869495a..eb35ea5faf64adc19ca0ecb8bda76dc315f8e666 100644 (file)
@@ -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;