diff options
Diffstat (limited to 'pc-bios/s390-ccw/virtio.c')
-rw-r--r-- | pc-bios/s390-ccw/virtio.c | 113 |
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; } } |