aboutsummaryrefslogtreecommitdiff
path: root/pc-bios/s390-ccw/virtio.c
diff options
context:
space:
mode:
Diffstat (limited to 'pc-bios/s390-ccw/virtio.c')
-rw-r--r--pc-bios/s390-ccw/virtio.c113
1 files changed, 81 insertions, 32 deletions
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;
}
}