@@ -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)
{
@@ -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");
}
@@ -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 */
@@ -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;