mirror of
https://github.com/qemu/qemu.git
synced 2024-11-24 19:33:39 +08:00
pc-bios/s390-ccw: enable virtio-scsi
Make the code added before to work. Signed-off-by: Eugene (jno) Dvurechenski <jno@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
This commit is contained in:
parent
86aec22d48
commit
80ba3e249b
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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,62 +322,6 @@ int virtio_read(ulong sector, void *load_addr)
|
||||
return virtio_read_many(sector, load_addr, 1);
|
||||
}
|
||||
|
||||
VirtioGDN virtio_guessed_disk_nature(void)
|
||||
{
|
||||
return vdev.guessed_disk_nature;
|
||||
}
|
||||
|
||||
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.config.blk.physical_block_exp = 0;
|
||||
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.config.blk.physical_block_exp = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void virtio_assume_eckd(void)
|
||||
{
|
||||
vdev.guessed_disk_nature = VIRTIO_GDN_DASD;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
bool virtio_disk_is_scsi(void)
|
||||
{
|
||||
if (vdev.guessed_disk_nature == VIRTIO_GDN_SCSI) {
|
||||
return true;
|
||||
}
|
||||
switch (vdev.senseid.cu_model) {
|
||||
case VIRTIO_ID_BLOCK:
|
||||
return (vdev.config.blk.geometry.heads == 255)
|
||||
&& (vdev.config.blk.geometry.sectors == 63)
|
||||
&& (virtio_get_block_size() == 512);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Other supported value pairs, if any, would need to be added here.
|
||||
* Note: head count is always 15.
|
||||
@ -392,6 +341,75 @@ static inline u8 virtio_eckd_sectors_for_block_size(int size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
VirtioGDN virtio_guessed_disk_nature(void)
|
||||
{
|
||||
return vdev.guessed_disk_nature;
|
||||
}
|
||||
|
||||
void virtio_assume_scsi(void)
|
||||
{
|
||||
switch (vdev.senseid.cu_model) {
|
||||
case VIRTIO_ID_BLOCK:
|
||||
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)
|
||||
{
|
||||
switch (vdev.senseid.cu_model) {
|
||||
case VIRTIO_ID_BLOCK:
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
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)
|
||||
{
|
||||
if (vdev.guessed_disk_nature == VIRTIO_GDN_SCSI) {
|
||||
return true;
|
||||
}
|
||||
switch (vdev.senseid.cu_model) {
|
||||
case VIRTIO_ID_BLOCK:
|
||||
return (vdev.config.blk.geometry.heads == 255)
|
||||
&& (vdev.config.blk.geometry.sectors == 63)
|
||||
&& (virtio_get_block_size() == VIRTIO_SCSI_BLOCK_SIZE);
|
||||
case VIRTIO_ID_SCSI:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user