pc-bios/s390-ccw: make provisions for different backends

Add dispatching code to make room for non virtio-blk boot devices.

Signed-off-by: Eugene (jno) Dvurechenski <jno@linux.vnet.ibm.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
master
Eugene (jno) Dvurechenski 2015-10-26 16:55:16 +01:00 committed by Cornelia Huck
parent 69429682c6
commit a1102cebbf
4 changed files with 106 additions and 44 deletions

View File

@ -50,7 +50,7 @@ static bool find_dev(Schib *schib, int dev_no)
if (!schib->pmcw.dnv) {
continue;
}
if (!virtio_is_blk(blk_schid)) {
if (!virtio_is_supported(blk_schid)) {
continue;
}
if ((dev_no < 0) || (schib->pmcw.dev == dev_no)) {
@ -95,7 +95,7 @@ static void virtio_setup(uint64_t dev_info)
panic("No virtio-blk device found!\n");
}
virtio_setup_block(blk_schid);
virtio_setup_device(blk_schid);
if (!virtio_ipl_disk_is_valid()) {
panic("No valid hard disk detected.\n");

View File

@ -70,8 +70,8 @@ void sclp_setup(void);
/* virtio.c */
unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2,
ulong subchan_id, void *load_addr);
bool virtio_is_blk(SubChannelId schid);
void virtio_setup_block(SubChannelId schid);
bool virtio_is_supported(SubChannelId schid);
void virtio_setup_device(SubChannelId schid);
int virtio_read(ulong sector, void *load_addr);
int enable_mss_facility(void);
ulong get_second(void);

View File

@ -25,7 +25,6 @@ static VDev vdev = {
.cmd_vr_idx = 0,
.ring_area = ring_area,
.wait_reply_timeout = VRING_WAIT_REPLY_TIMEOUT,
.guessed_disk_nature = false,
.schid = { .one = 1 },
};
@ -230,11 +229,12 @@ static int vring_wait_reply(void)
* Virtio block *
***********************************************/
int virtio_read_many(ulong sector, void *load_addr, int sec_num)
static int virtio_blk_read_many(VDev *vdev,
ulong sector, void *load_addr, int sec_num)
{
VirtioBlkOuthdr out_hdr;
u8 status;
VRing *vr = &vdev.vrings[vdev.cmd_vr_idx];
VRing *vr = &vdev->vrings[vdev->cmd_vr_idx];
/* Tell the host we want to read */
out_hdr.type = VIRTIO_BLK_T_IN;
@ -262,6 +262,16 @@ int virtio_read_many(ulong sector, void *load_addr, int sec_num)
return status;
}
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);
}
panic("\n! No readable IPL device !\n");
return -1;
}
unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2,
ulong subchan_id, void *load_addr)
{
@ -290,44 +300,60 @@ int virtio_read(ulong sector, void *load_addr)
return virtio_read_many(sector, load_addr, 1);
}
bool virtio_guessed_disk_nature(void)
VirtioGDN virtio_guessed_disk_nature(void)
{
return vdev.guessed_disk_nature;
}
void virtio_assume_scsi(void)
{
vdev.guessed_disk_nature = true;
vdev.config.blk.blk_size = 512;
vdev.config.blk.physical_block_exp = 0;
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 = true;
vdev.config.blk.blk_size = 2048;
vdev.config.blk.physical_block_exp = 0;
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 = true;
vdev.config.blk.blk_size = 4096;
vdev.config.blk.physical_block_exp = 0;
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;
/* 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) {
return (virtio_get_block_size() == 512);
if (vdev.guessed_disk_nature == VIRTIO_GDN_SCSI) {
return true;
}
return (vdev.config.blk.geometry.heads == 255)
&& (vdev.config.blk.geometry.sectors == 63)
&& (virtio_get_block_size() == 512);
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;
}
/*
@ -353,12 +379,16 @@ bool virtio_disk_is_eckd(void)
{
const int block_size = virtio_get_block_size();
if (vdev.guessed_disk_nature) {
return (block_size == 4096);
if (vdev.guessed_disk_nature == VIRTIO_GDN_DASD) {
return true;
}
return (vdev.config.blk.geometry.heads == 15)
&& (vdev.config.blk.geometry.sectors ==
virtio_eckd_sectors_for_block_size(block_size));
switch (vdev.senseid.cu_model) {
case VIRTIO_ID_BLOCK:
return (vdev.config.blk.geometry.heads == 15)
&& (vdev.config.blk.geometry.sectors ==
virtio_eckd_sectors_for_block_size(block_size));
}
return false;
}
bool virtio_ipl_disk_is_valid(void)
@ -368,23 +398,39 @@ bool virtio_ipl_disk_is_valid(void)
int virtio_get_block_size(void)
{
return vdev.config.blk.blk_size << vdev.config.blk.physical_block_exp;
switch (vdev.senseid.cu_model) {
case VIRTIO_ID_BLOCK:
return vdev.config.blk.blk_size << vdev.config.blk.physical_block_exp;
}
return 0;
}
uint8_t virtio_get_heads(void)
{
return vdev.config.blk.geometry.heads;
switch (vdev.senseid.cu_model) {
case VIRTIO_ID_BLOCK:
return vdev.config.blk.geometry.heads;
}
return 0;
}
uint8_t virtio_get_sectors(void)
{
return vdev.config.blk.geometry.sectors;
switch (vdev.senseid.cu_model) {
case VIRTIO_ID_BLOCK:
return vdev.config.blk.geometry.sectors;
}
return 0;
}
uint64_t virtio_get_blocks(void)
{
return vdev.config.blk.capacity /
(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 0;
}
static void virtio_setup_ccw(VDev *vdev)
@ -393,7 +439,7 @@ static void virtio_setup_ccw(VDev *vdev)
unsigned char status = VIRTIO_CONFIG_S_DRIVER_OK;
vdev->config.blk.blk_size = 0; /* mark "illegal" - setup started... */
vdev->guessed_disk_nature = false;
vdev->guessed_disk_nature = VIRTIO_GDN_NONE;
run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0);
@ -441,19 +487,27 @@ static void virtio_setup_ccw(VDev *vdev)
"Could not write status to host");
}
void virtio_setup_block(SubChannelId schid)
void virtio_setup_device(SubChannelId schid)
{
vdev.schid = schid;
virtio_setup_ccw(&vdev);
if (!virtio_ipl_disk_is_valid()) {
/* make sure all getters but blocksize return 0 for invalid IPL disk */
memset(&vdev.config.blk, 0, sizeof(vdev.config.blk));
virtio_assume_scsi();
switch (vdev.senseid.cu_model) {
case VIRTIO_ID_BLOCK:
if (!virtio_ipl_disk_is_valid()) {
/* make sure all getters but blocksize return 0 for
* invalid IPL disk
*/
memset(&vdev.config.blk, 0, sizeof(vdev.config.blk));
virtio_assume_scsi();
}
break;
default:
panic("\n! No IPL device available !\n");
}
}
bool virtio_is_blk(SubChannelId schid)
bool virtio_is_supported(SubChannelId schid)
{
vdev.schid = schid;
memset(&vdev.senseid, 0, sizeof(vdev.senseid));

View File

@ -201,7 +201,15 @@ struct VirtioBlkConfig {
} __attribute__((packed));
typedef struct VirtioBlkConfig VirtioBlkConfig;
bool virtio_guessed_disk_nature(void);
enum guessed_disk_nature_type {
VIRTIO_GDN_NONE = 0,
VIRTIO_GDN_DASD = 1,
VIRTIO_GDN_CDROM = 2,
VIRTIO_GDN_SCSI = 3,
};
typedef enum guessed_disk_nature_type VirtioGDN;
VirtioGDN virtio_guessed_disk_nature(void);
void virtio_assume_scsi(void);
void virtio_assume_eckd(void);
void virtio_assume_iso9660(void);
@ -228,7 +236,7 @@ struct VDev {
int cmd_vr_idx;
void *ring_area;
long wait_reply_timeout;
bool guessed_disk_nature;
VirtioGDN guessed_disk_nature;
SubChannelId schid;
SenseId senseid;
union {