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>
This commit is contained in:
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) { if (!schib->pmcw.dnv) {
continue; continue;
} }
if (!virtio_is_blk(blk_schid)) { if (!virtio_is_supported(blk_schid)) {
continue; continue;
} }
if ((dev_no < 0) || (schib->pmcw.dev == dev_no)) { 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"); panic("No virtio-blk device found!\n");
} }
virtio_setup_block(blk_schid); virtio_setup_device(blk_schid);
if (!virtio_ipl_disk_is_valid()) { if (!virtio_ipl_disk_is_valid()) {
panic("No valid hard disk detected.\n"); panic("No valid hard disk detected.\n");

View file

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

View file

@ -25,7 +25,6 @@ static VDev vdev = {
.cmd_vr_idx = 0, .cmd_vr_idx = 0,
.ring_area = ring_area, .ring_area = ring_area,
.wait_reply_timeout = VRING_WAIT_REPLY_TIMEOUT, .wait_reply_timeout = VRING_WAIT_REPLY_TIMEOUT,
.guessed_disk_nature = false,
.schid = { .one = 1 }, .schid = { .one = 1 },
}; };
@ -230,11 +229,12 @@ static int vring_wait_reply(void)
* Virtio block * * 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; VirtioBlkOuthdr out_hdr;
u8 status; 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 */ /* Tell the host we want to read */
out_hdr.type = VIRTIO_BLK_T_IN; 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; 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, unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2,
ulong subchan_id, void *load_addr) 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); 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; return vdev.guessed_disk_nature;
} }
void virtio_assume_scsi(void) void virtio_assume_scsi(void)
{ {
vdev.guessed_disk_nature = true; vdev.guessed_disk_nature = VIRTIO_GDN_SCSI;
vdev.config.blk.blk_size = 512; switch (vdev.senseid.cu_model) {
vdev.config.blk.physical_block_exp = 0; case VIRTIO_ID_BLOCK:
vdev.config.blk.blk_size = 512;
vdev.config.blk.physical_block_exp = 0;
break;
}
} }
void virtio_assume_iso9660(void) void virtio_assume_iso9660(void)
{ {
vdev.guessed_disk_nature = true; vdev.guessed_disk_nature = VIRTIO_GDN_CDROM;
vdev.config.blk.blk_size = 2048; switch (vdev.senseid.cu_model) {
vdev.config.blk.physical_block_exp = 0; case VIRTIO_ID_BLOCK:
vdev.config.blk.blk_size = 2048;
vdev.config.blk.physical_block_exp = 0;
break;
}
} }
void virtio_assume_eckd(void) void virtio_assume_eckd(void)
{ {
vdev.guessed_disk_nature = true; vdev.guessed_disk_nature = VIRTIO_GDN_DASD;
vdev.config.blk.blk_size = 4096; switch (vdev.senseid.cu_model) {
vdev.config.blk.physical_block_exp = 0; 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 */ /* this must be here to calculate code segment position */
vdev.config.blk.geometry.heads = 15; vdev.config.blk.geometry.heads = 15;
vdev.config.blk.geometry.sectors = 12; vdev.config.blk.geometry.sectors = 12;
break;
}
} }
bool virtio_disk_is_scsi(void) bool virtio_disk_is_scsi(void)
{ {
if (vdev.guessed_disk_nature) { if (vdev.guessed_disk_nature == VIRTIO_GDN_SCSI) {
return (virtio_get_block_size() == 512); return true;
} }
return (vdev.config.blk.geometry.heads == 255) switch (vdev.senseid.cu_model) {
&& (vdev.config.blk.geometry.sectors == 63) case VIRTIO_ID_BLOCK:
&& (virtio_get_block_size() == 512); 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(); const int block_size = virtio_get_block_size();
if (vdev.guessed_disk_nature) { if (vdev.guessed_disk_nature == VIRTIO_GDN_DASD) {
return (block_size == 4096); return true;
} }
return (vdev.config.blk.geometry.heads == 15) switch (vdev.senseid.cu_model) {
&& (vdev.config.blk.geometry.sectors == case VIRTIO_ID_BLOCK:
virtio_eckd_sectors_for_block_size(block_size)); 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) bool virtio_ipl_disk_is_valid(void)
@ -368,23 +398,39 @@ bool virtio_ipl_disk_is_valid(void)
int virtio_get_block_size(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) 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) 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) uint64_t virtio_get_blocks(void)
{ {
return vdev.config.blk.capacity / switch (vdev.senseid.cu_model) {
(virtio_get_block_size() / VIRTIO_SECTOR_SIZE); 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) 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; unsigned char status = VIRTIO_CONFIG_S_DRIVER_OK;
vdev->config.blk.blk_size = 0; /* mark "illegal" - setup started... */ 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); 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"); "Could not write status to host");
} }
void virtio_setup_block(SubChannelId schid) void virtio_setup_device(SubChannelId schid)
{ {
vdev.schid = schid; vdev.schid = schid;
virtio_setup_ccw(&vdev); virtio_setup_ccw(&vdev);
if (!virtio_ipl_disk_is_valid()) { switch (vdev.senseid.cu_model) {
/* make sure all getters but blocksize return 0 for invalid IPL disk */ case VIRTIO_ID_BLOCK:
memset(&vdev.config.blk, 0, sizeof(vdev.config.blk)); if (!virtio_ipl_disk_is_valid()) {
virtio_assume_scsi(); /* 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; vdev.schid = schid;
memset(&vdev.senseid, 0, sizeof(vdev.senseid)); memset(&vdev.senseid, 0, sizeof(vdev.senseid));

View file

@ -201,7 +201,15 @@ struct VirtioBlkConfig {
} __attribute__((packed)); } __attribute__((packed));
typedef struct VirtioBlkConfig VirtioBlkConfig; 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_scsi(void);
void virtio_assume_eckd(void); void virtio_assume_eckd(void);
void virtio_assume_iso9660(void); void virtio_assume_iso9660(void);
@ -228,7 +236,7 @@ struct VDev {
int cmd_vr_idx; int cmd_vr_idx;
void *ring_area; void *ring_area;
long wait_reply_timeout; long wait_reply_timeout;
bool guessed_disk_nature; VirtioGDN guessed_disk_nature;
SubChannelId schid; SubChannelId schid;
SenseId senseid; SenseId senseid;
union { union {