aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pc-bios/s390-ccw/Makefile2
-rw-r--r--pc-bios/s390-ccw/main.c8
-rw-r--r--pc-bios/s390-ccw/virtio.c113
-rw-r--r--pc-bios/s390-ccw/virtio.h32
4 files changed, 116 insertions, 39 deletions
diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index 11c5dd4799..4208cb4295 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -9,7 +9,7 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw)
.PHONY : all clean build-all
-OBJECTS = start.o main.o bootmap.o sclp-ascii.o virtio.o
+OBJECTS = start.o main.o bootmap.o sclp-ascii.o virtio.o virtio-scsi.o
CFLAGS += -fPIE -fno-stack-protector -ffreestanding -march=z900
CFLAGS += -fno-delete-null-pointer-checks -msoft-float
LDFLAGS += -Wl,-pie -nostdlib
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 69a02feb87..1c9e0791ab 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -91,15 +91,11 @@ static void virtio_setup(uint64_t dev_info)
}
}
- if (!found) {
- panic("No virtio-blk device found!\n");
- }
+ IPL_assert(found, "No virtio device found");
virtio_setup_device(blk_schid);
- if (!virtio_ipl_disk_is_valid()) {
- panic("No valid hard disk detected.\n");
- }
+ IPL_assert(virtio_ipl_disk_is_valid(), "No valid IPL device detected");
}
int main(void)
diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index 4ab4d475c0..1d34e8c1aa 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -10,6 +10,7 @@
#include "s390-ccw.h"
#include "virtio.h"
+#include "virtio-scsi.h"
#define VRING_WAIT_REPLY_TIMEOUT 3
@@ -26,6 +27,8 @@ static VDev vdev = {
.ring_area = ring_area,
.wait_reply_timeout = VRING_WAIT_REPLY_TIMEOUT,
.schid = { .one = 1 },
+ .scsi_block_size = VIRTIO_SCSI_BLOCK_SIZE,
+ .blk_factor = 1,
};
VDev *virtio_get_device(void)
@@ -284,6 +287,8 @@ int virtio_read_many(ulong sector, void *load_addr, int sec_num)
switch (vdev.senseid.cu_model) {
case VIRTIO_ID_BLOCK:
return virtio_blk_read_many(&vdev, sector, load_addr, sec_num);
+ case VIRTIO_ID_SCSI:
+ return virtio_scsi_read_many(&vdev, sector, load_addr, sec_num);
}
panic("\n! No readable IPL device !\n");
return -1;
@@ -317,6 +322,25 @@ int virtio_read(ulong sector, void *load_addr)
return virtio_read_many(sector, load_addr, 1);
}
+/*
+ * Other supported value pairs, if any, would need to be added here.
+ * Note: head count is always 15.
+ */
+static inline u8 virtio_eckd_sectors_for_block_size(int size)
+{
+ switch (size) {
+ case 512:
+ return 49;
+ case 1024:
+ return 33;
+ case 2048:
+ return 21;
+ case 4096:
+ return 12;
+ }
+ return 0;
+}
+
VirtioGDN virtio_guessed_disk_nature(void)
{
return vdev.guessed_disk_nature;
@@ -324,22 +348,30 @@ VirtioGDN virtio_guessed_disk_nature(void)
void virtio_assume_scsi(void)
{
- vdev.guessed_disk_nature = VIRTIO_GDN_SCSI;
switch (vdev.senseid.cu_model) {
case VIRTIO_ID_BLOCK:
- vdev.config.blk.blk_size = 512;
+ vdev.guessed_disk_nature = VIRTIO_GDN_SCSI;
+ vdev.config.blk.blk_size = VIRTIO_SCSI_BLOCK_SIZE;
vdev.config.blk.physical_block_exp = 0;
+ vdev.blk_factor = 1;
+ break;
+ case VIRTIO_ID_SCSI:
+ vdev.scsi_block_size = VIRTIO_SCSI_BLOCK_SIZE;
break;
}
}
void virtio_assume_iso9660(void)
{
- vdev.guessed_disk_nature = VIRTIO_GDN_CDROM;
switch (vdev.senseid.cu_model) {
case VIRTIO_ID_BLOCK:
- vdev.config.blk.blk_size = 2048;
+ vdev.guessed_disk_nature = VIRTIO_GDN_SCSI;
+ vdev.config.blk.blk_size = VIRTIO_ISO_BLOCK_SIZE;
vdev.config.blk.physical_block_exp = 0;
+ vdev.blk_factor = VIRTIO_ISO_BLOCK_SIZE / VIRTIO_SECTOR_SIZE;
+ break;
+ case VIRTIO_ID_SCSI:
+ vdev.scsi_block_size = VIRTIO_ISO_BLOCK_SIZE;
break;
}
}
@@ -347,16 +379,19 @@ void virtio_assume_iso9660(void)
void virtio_assume_eckd(void)
{
vdev.guessed_disk_nature = VIRTIO_GDN_DASD;
+ vdev.blk_factor = 1;
+ vdev.config.blk.physical_block_exp = 0;
switch (vdev.senseid.cu_model) {
case VIRTIO_ID_BLOCK:
vdev.config.blk.blk_size = 4096;
- vdev.config.blk.physical_block_exp = 0;
-
- /* this must be here to calculate code segment position */
- vdev.config.blk.geometry.heads = 15;
- vdev.config.blk.geometry.sectors = 12;
+ break;
+ case VIRTIO_ID_SCSI:
+ vdev.config.blk.blk_size = vdev.scsi_block_size;
break;
}
+ vdev.config.blk.geometry.heads = 15;
+ vdev.config.blk.geometry.sectors =
+ virtio_eckd_sectors_for_block_size(vdev.config.blk.blk_size);
}
bool virtio_disk_is_scsi(void)
@@ -368,30 +403,13 @@ bool virtio_disk_is_scsi(void)
case VIRTIO_ID_BLOCK:
return (vdev.config.blk.geometry.heads == 255)
&& (vdev.config.blk.geometry.sectors == 63)
- && (virtio_get_block_size() == 512);
+ && (virtio_get_block_size() == VIRTIO_SCSI_BLOCK_SIZE);
+ case VIRTIO_ID_SCSI:
+ return true;
}
return false;
}
-/*
- * Other supported value pairs, if any, would need to be added here.
- * Note: head count is always 15.
- */
-static inline u8 virtio_eckd_sectors_for_block_size(int size)
-{
- switch (size) {
- case 512:
- return 49;
- case 1024:
- return 33;
- case 2048:
- return 21;
- case 4096:
- return 12;
- }
- return 0;
-}
-
bool virtio_disk_is_eckd(void)
{
const int block_size = virtio_get_block_size();
@@ -404,6 +422,8 @@ bool virtio_disk_is_eckd(void)
return (vdev.config.blk.geometry.heads == 15)
&& (vdev.config.blk.geometry.sectors ==
virtio_eckd_sectors_for_block_size(block_size));
+ case VIRTIO_ID_SCSI:
+ return false;
}
return false;
}
@@ -418,6 +438,8 @@ int virtio_get_block_size(void)
switch (vdev.senseid.cu_model) {
case VIRTIO_ID_BLOCK:
return vdev.config.blk.blk_size << vdev.config.blk.physical_block_exp;
+ case VIRTIO_ID_SCSI:
+ return vdev.scsi_block_size;
}
return 0;
}
@@ -427,6 +449,9 @@ uint8_t virtio_get_heads(void)
switch (vdev.senseid.cu_model) {
case VIRTIO_ID_BLOCK:
return vdev.config.blk.geometry.heads;
+ case VIRTIO_ID_SCSI:
+ return vdev.guessed_disk_nature == VIRTIO_GDN_DASD
+ ? vdev.config.blk.geometry.heads : 255;
}
return 0;
}
@@ -436,25 +461,33 @@ uint8_t virtio_get_sectors(void)
switch (vdev.senseid.cu_model) {
case VIRTIO_ID_BLOCK:
return vdev.config.blk.geometry.sectors;
+ case VIRTIO_ID_SCSI:
+ return vdev.guessed_disk_nature == VIRTIO_GDN_DASD
+ ? vdev.config.blk.geometry.sectors : 63;
}
return 0;
}
uint64_t virtio_get_blocks(void)
{
+ const uint64_t factor = virtio_get_block_size() / VIRTIO_SECTOR_SIZE;
switch (vdev.senseid.cu_model) {
case VIRTIO_ID_BLOCK:
- return vdev.config.blk.capacity /
- (virtio_get_block_size() / VIRTIO_SECTOR_SIZE);
+ return vdev.config.blk.capacity / factor;
+ case VIRTIO_ID_SCSI:
+ return vdev.scsi_last_block / factor;
}
return 0;
}
static void virtio_setup_ccw(VDev *vdev)
{
- int i, cfg_size;
+ int i, cfg_size = 0;
unsigned char status = VIRTIO_CONFIG_S_DRIVER_OK;
+ IPL_assert(virtio_is_supported(vdev->schid), "PE");
+ /* device ID has been established now */
+
vdev->config.blk.blk_size = 0; /* mark "illegal" - setup started... */
vdev->guessed_disk_nature = VIRTIO_GDN_NONE;
@@ -466,6 +499,11 @@ static void virtio_setup_ccw(VDev *vdev)
vdev->cmd_vr_idx = 0;
cfg_size = sizeof(vdev->config.blk);
break;
+ case VIRTIO_ID_SCSI:
+ vdev->nr_vqs = 3;
+ vdev->cmd_vr_idx = VR_REQUEST;
+ cfg_size = sizeof(vdev->config.scsi);
+ break;
default:
panic("Unsupported virtio device\n");
}
@@ -511,6 +549,7 @@ void virtio_setup_device(SubChannelId schid)
switch (vdev.senseid.cu_model) {
case VIRTIO_ID_BLOCK:
+ sclp_print("Using virtio-blk.\n");
if (!virtio_ipl_disk_is_valid()) {
/* make sure all getters but blocksize return 0 for
* invalid IPL disk
@@ -519,6 +558,15 @@ void virtio_setup_device(SubChannelId schid)
virtio_assume_scsi();
}
break;
+ case VIRTIO_ID_SCSI:
+ IPL_assert(vdev.config.scsi.sense_size == VIRTIO_SCSI_SENSE_SIZE,
+ "Config: sense size mismatch");
+ IPL_assert(vdev.config.scsi.cdb_size == VIRTIO_SCSI_CDB_SIZE,
+ "Config: CDB size mismatch");
+
+ sclp_print("Using virtio-scsi.\n");
+ virtio_scsi_setup(&vdev);
+ break;
default:
panic("\n! No IPL device available !\n");
}
@@ -535,6 +583,7 @@ bool virtio_is_supported(SubChannelId schid)
if (vdev.senseid.cu_type == 0x3832) {
switch (vdev.senseid.cu_model) {
case VIRTIO_ID_BLOCK:
+ case VIRTIO_ID_SCSI:
return true;
}
}
diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h
index 57c71a2c93..3c6e91510e 100644
--- a/pc-bios/s390-ccw/virtio.h
+++ b/pc-bios/s390-ccw/virtio.h
@@ -28,6 +28,7 @@ enum VirtioDevType {
VIRTIO_ID_BLOCK = 2,
VIRTIO_ID_CONSOLE = 3,
VIRTIO_ID_BALLOON = 5,
+ VIRTIO_ID_SCSI = 8,
};
typedef enum VirtioDevType VirtioDevType;
@@ -224,12 +225,35 @@ extern uint64_t virtio_get_blocks(void);
extern int virtio_read_many(ulong sector, void *load_addr, int sec_num);
#define VIRTIO_SECTOR_SIZE 512
+#define VIRTIO_ISO_BLOCK_SIZE 2048
+#define VIRTIO_SCSI_BLOCK_SIZE 512
static inline ulong virtio_sector_adjust(ulong sector)
{
return sector * (virtio_get_block_size() / VIRTIO_SECTOR_SIZE);
}
+struct VirtioScsiConfig {
+ uint32_t num_queues;
+ uint32_t seg_max;
+ uint32_t max_sectors;
+ uint32_t cmd_per_lun;
+ uint32_t event_info_size;
+ uint32_t sense_size;
+ uint32_t cdb_size;
+ uint16_t max_channel;
+ uint16_t max_target;
+ uint32_t max_lun;
+} __attribute__((packed));
+typedef struct VirtioScsiConfig VirtioScsiConfig;
+
+struct ScsiDevice {
+ uint16_t channel; /* Always 0 in QEMU */
+ uint16_t target; /* will be scanned over */
+ uint32_t lun; /* will be reported */
+};
+typedef struct ScsiDevice ScsiDevice;
+
struct VDev {
int nr_vqs;
VRing *vrings;
@@ -241,7 +265,15 @@ struct VDev {
SenseId senseid;
union {
VirtioBlkConfig blk;
+ VirtioScsiConfig scsi;
} config;
+ ScsiDevice *scsi_device;
+ bool is_cdrom;
+ int scsi_block_size;
+ int blk_factor;
+ uint64_t scsi_last_block;
+ uint32_t scsi_dev_cyls;
+ uint8_t scsi_dev_heads;
};
typedef struct VDev VDev;