* [Qemu-devel] [PULL for-2.6 01/14] pc-bios/s390-ccw: add more disk layout checks
2016-03-24 8:29 [Qemu-devel] [PULL for-2.6 00/14] s390-ccw bios patches Cornelia Huck
@ 2016-03-24 8:29 ` Cornelia Huck
2016-03-24 8:29 ` [Qemu-devel] [PULL for-2.6 02/14] pc-bios/s390-ccw: virtio_panic -> panic Cornelia Huck
` (13 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Cornelia Huck @ 2016-03-24 8:29 UTC (permalink / raw)
To: peter.maydell
Cc: qemu-devel, agraf, borntraeger, jfrei, Cornelia Huck,
Eugene (jno) Dvurechenski
From: "Eugene (jno) Dvurechenski" <jno@linux.vnet.ibm.com>
Experiments showed possibility of few more "misconfigurations" in disk
layout. They are reported now.
Acked-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Reviewed-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Signed-off-by: Eugene (jno) Dvurechenski <jno@linux.vnet.ibm.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
---
pc-bios/s390-ccw/bootmap.c | 4 ++++
pc-bios/s390-ccw/bootmap.h | 9 +++++++++
2 files changed, 13 insertions(+)
diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index 4925302..ca60c33 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -415,7 +415,11 @@ static void ipl_scsi(void)
/* The 0-th block (MBR) was already read into sec[] */
sclp_print("Using SCSI scheme.\n");
+ debug_print_int("MBR Version", mbr->version_id);
+ IPL_check(mbr->version_id == 1,
+ "Unknown MBR layout version, assuming version 1");
debug_print_int("program table", mbr->blockptr.blockno);
+ IPL_assert(mbr->blockptr.blockno, "No Program Table");
/* Parse the program table */
read_block(mbr->blockptr.blockno, sec,
diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h
index f98765b..07e3b20 100644
--- a/pc-bios/s390-ccw/bootmap.h
+++ b/pc-bios/s390-ccw/bootmap.h
@@ -273,6 +273,15 @@ static inline void IPL_assert(bool term, const char *message)
}
}
+static inline void IPL_check(bool term, const char *message)
+{
+ if (!term) {
+ sclp_print("\n! WARNING: ");
+ sclp_print(message);
+ sclp_print(" !\n");
+ }
+}
+
static const unsigned char ebc2asc[256] =
/* 0123456789abcdef0123456789abcdef */
"................................" /* 1F */
--
2.7.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PULL for-2.6 02/14] pc-bios/s390-ccw: virtio_panic -> panic
2016-03-24 8:29 [Qemu-devel] [PULL for-2.6 00/14] s390-ccw bios patches Cornelia Huck
2016-03-24 8:29 ` [Qemu-devel] [PULL for-2.6 01/14] pc-bios/s390-ccw: add more disk layout checks Cornelia Huck
@ 2016-03-24 8:29 ` Cornelia Huck
2016-03-24 8:29 ` [Qemu-devel] [PULL for-2.6 03/14] pc-bios/s390-ccw: add utility functions and "export" some others Cornelia Huck
` (12 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Cornelia Huck @ 2016-03-24 8:29 UTC (permalink / raw)
To: peter.maydell
Cc: qemu-devel, agraf, borntraeger, jfrei, Cornelia Huck,
Eugene (jno) Dvurechenski
From: "Eugene (jno) Dvurechenski" <jno@linux.vnet.ibm.com>
This function has nothing to do with virtio.
Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Reviewed-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Signed-off-by: Eugene (jno) Dvurechenski <jno@linux.vnet.ibm.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
---
pc-bios/s390-ccw/bootmap.c | 8 ++++----
pc-bios/s390-ccw/bootmap.h | 2 +-
pc-bios/s390-ccw/main.c | 8 ++++----
pc-bios/s390-ccw/s390-ccw.h | 2 +-
pc-bios/s390-ccw/virtio.c | 8 ++++----
5 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index ca60c33..711a518 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -72,7 +72,7 @@ static void jump_to_IPL_code(uint64_t address)
asm volatile("lghi 1,1\n\t"
"diag 1,1,0x308\n\t"
: : : "1", "memory");
- virtio_panic("\n! IPL returns !\n");
+ panic("\n! IPL returns !\n");
}
/***********************************************************************
@@ -617,7 +617,7 @@ static IsoBcSection *find_iso_bc_entry(void)
if (!is_iso_bc_valid(e)) {
/* The validation entry is mandatory */
- virtio_panic("No valid boot catalog found!\n");
+ panic("No valid boot catalog found!\n");
return NULL;
}
@@ -633,7 +633,7 @@ static IsoBcSection *find_iso_bc_entry(void)
}
}
- virtio_panic("No suitable boot entry found on ISO-9660 media!\n");
+ panic("No suitable boot entry found on ISO-9660 media!\n");
return NULL;
}
@@ -701,5 +701,5 @@ void zipl_load(void)
*/
ipl_eckd_cdl();
- virtio_panic("\n* this can never happen *\n");
+ panic("\n* this can never happen *\n");
}
diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h
index 07e3b20..e074587 100644
--- a/pc-bios/s390-ccw/bootmap.h
+++ b/pc-bios/s390-ccw/bootmap.h
@@ -269,7 +269,7 @@ static inline void IPL_assert(bool term, const char *message)
if (!term) {
sclp_print("\n! ");
sclp_print(message);
- virtio_panic(" !\n"); /* no return */
+ panic(" !\n"); /* no return */
}
}
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index d5fe4ce..11cb803 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -31,7 +31,7 @@ void write_subsystem_identification(void)
}
-void virtio_panic(const char *string)
+void panic(const char *string)
{
sclp_print(string);
disabled_wait();
@@ -93,13 +93,13 @@ static void virtio_setup(uint64_t dev_info)
}
if (!found) {
- virtio_panic("No virtio-blk device found!\n");
+ panic("No virtio-blk device found!\n");
}
virtio_setup_block(blk_schid);
if (!virtio_ipl_disk_is_valid()) {
- virtio_panic("No valid hard disk detected.\n");
+ panic("No valid hard disk detected.\n");
}
}
@@ -111,6 +111,6 @@ int main(void)
zipl_load(); /* no return */
- virtio_panic("Failed to load OS from hard disk\n");
+ panic("Failed to load OS from hard disk\n");
return 0; /* make compiler happy */
}
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index 5484c2a..c24f720 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -50,7 +50,7 @@ void disabled_wait(void);
void consume_sclp_int(void);
/* main.c */
-void virtio_panic(const char *string);
+void panic(const char *string);
void write_subsystem_identification(void);
extern char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
extern char ring_area[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index 87aed38..2d27b1d 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -97,7 +97,7 @@ static void virtio_set_status(struct subchannel_id schid,
{
unsigned char status = dev_addr;
if (run_ccw(schid, CCW_CMD_WRITE_STATUS, &status, sizeof(status))) {
- virtio_panic("Could not write status to host!\n");
+ panic("Could not write status to host!\n");
}
}
@@ -251,7 +251,7 @@ unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2,
sclp_print(".");
status = virtio_read_many(sec, (void *)addr, sec_num);
if (status) {
- virtio_panic("I/O Error");
+ panic("I/O Error");
}
addr += sec_num * virtio_get_block_size();
@@ -381,10 +381,10 @@ void virtio_setup_block(struct subchannel_id schid)
config.index = 0;
if (run_ccw(schid, CCW_CMD_READ_VQ_CONF, &config, sizeof(config))) {
- virtio_panic("Could not get block device VQ configuration\n");
+ panic("Could not get block device VQ configuration\n");
}
if (run_ccw(schid, CCW_CMD_READ_CONF, &blk_cfg, sizeof(blk_cfg))) {
- virtio_panic("Could not get block device configuration\n");
+ panic("Could not get block device configuration\n");
}
vring_init(&block, config.num, ring_area,
KVM_S390_VIRTIO_RING_ALIGN);
--
2.7.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PULL for-2.6 03/14] pc-bios/s390-ccw: add utility functions and "export" some others
2016-03-24 8:29 [Qemu-devel] [PULL for-2.6 00/14] s390-ccw bios patches Cornelia Huck
2016-03-24 8:29 ` [Qemu-devel] [PULL for-2.6 01/14] pc-bios/s390-ccw: add more disk layout checks Cornelia Huck
2016-03-24 8:29 ` [Qemu-devel] [PULL for-2.6 02/14] pc-bios/s390-ccw: virtio_panic -> panic Cornelia Huck
@ 2016-03-24 8:29 ` Cornelia Huck
2016-03-24 8:29 ` [Qemu-devel] [PULL for-2.6 04/14] pc-bios/s390-ccw: qemuize types Cornelia Huck
` (11 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Cornelia Huck @ 2016-03-24 8:29 UTC (permalink / raw)
To: peter.maydell
Cc: qemu-devel, agraf, borntraeger, jfrei, Cornelia Huck,
Eugene (jno) Dvurechenski
From: "Eugene (jno) Dvurechenski" <jno@linux.vnet.ibm.com>
Add several utility functions, make IPL_check and IPL_assert generally
available, etc.
Acked-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Eugene (jno) Dvurechenski <jno@linux.vnet.ibm.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
---
pc-bios/s390-ccw/bootmap.h | 18 ------------------
pc-bios/s390-ccw/s390-ccw.h | 39 +++++++++++++++++++++++++++++++++++++++
pc-bios/s390-ccw/virtio.c | 2 +-
3 files changed, 40 insertions(+), 19 deletions(-)
diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h
index e074587..bea1687 100644
--- a/pc-bios/s390-ccw/bootmap.h
+++ b/pc-bios/s390-ccw/bootmap.h
@@ -264,24 +264,6 @@ typedef enum {
/* utility code below */
-static inline void IPL_assert(bool term, const char *message)
-{
- if (!term) {
- sclp_print("\n! ");
- sclp_print(message);
- panic(" !\n"); /* no return */
- }
-}
-
-static inline void IPL_check(bool term, const char *message)
-{
- if (!term) {
- sclp_print("\n! WARNING: ");
- sclp_print(message);
- sclp_print(" !\n");
- }
-}
-
static const unsigned char ebc2asc[256] =
/* 0123456789abcdef0123456789abcdef */
"................................" /* 1F */
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index c24f720..5135911 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -67,6 +67,7 @@ bool virtio_is_blk(struct subchannel_id schid);
void virtio_setup_block(struct subchannel_id schid);
int virtio_read(ulong sector, void *load_addr);
int enable_mss_facility(void);
+ulong get_second(void);
/* bootmap.c */
void zipl_load(void);
@@ -143,4 +144,42 @@ static inline void yield(void)
#define MAX_SECTOR_SIZE 4096
+static inline void sleep(unsigned int seconds)
+{
+ ulong target = get_second() + seconds;
+
+ while (get_second() < target) {
+ yield();
+ }
+}
+
+static inline void *memcpy(void *s1, const void *s2, size_t n)
+{
+ uint8_t *p1 = s1;
+ const uint8_t *p2 = s2;
+
+ while (n--) {
+ p1[n] = p2[n];
+ }
+ return s1;
+}
+
+static inline void IPL_assert(bool term, const char *message)
+{
+ if (!term) {
+ sclp_print("\n! ");
+ sclp_print(message);
+ panic(" !\n"); /* no return */
+ }
+}
+
+static inline void IPL_check(bool term, const char *message)
+{
+ if (!term) {
+ sclp_print("\n! WARNING: ");
+ sclp_print(message);
+ sclp_print(" !\n");
+ }
+}
+
#endif /* S390_CCW_H */
diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index 2d27b1d..da51fb7 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -162,7 +162,7 @@ static u64 get_clock(void)
return r;
}
-static ulong get_second(void)
+ulong get_second(void)
{
return (get_clock() >> 12) / 1000000;
}
--
2.7.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PULL for-2.6 04/14] pc-bios/s390-ccw: qemuize types
2016-03-24 8:29 [Qemu-devel] [PULL for-2.6 00/14] s390-ccw bios patches Cornelia Huck
` (2 preceding siblings ...)
2016-03-24 8:29 ` [Qemu-devel] [PULL for-2.6 03/14] pc-bios/s390-ccw: add utility functions and "export" some others Cornelia Huck
@ 2016-03-24 8:29 ` Cornelia Huck
2016-03-24 8:29 ` [Qemu-devel] [PULL for-2.6 05/14] pc-bios/s390-ccw: update virtio implementation to allow up to 3 vrings Cornelia Huck
` (10 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Cornelia Huck @ 2016-03-24 8:29 UTC (permalink / raw)
To: peter.maydell
Cc: qemu-devel, agraf, borntraeger, jfrei, Cornelia Huck,
Eugene (jno) Dvurechenski
From: "Eugene (jno) Dvurechenski" <jno@linux.vnet.ibm.com>
Turn [the most of] existing declarations from
struct type_name { ... };
into
struct TypeName { ... };
typedef struct TypeName TypeName;
and make use of them.
Also switch u{8,16,32,64} to uint{8,16,32,64}_t.
Acked-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Eugene (jno) Dvurechenski <jno@linux.vnet.ibm.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
---
pc-bios/s390-ccw/main.c | 8 +--
pc-bios/s390-ccw/s390-ccw.h | 12 +++-
pc-bios/s390-ccw/virtio.c | 46 +++++++-------
pc-bios/s390-ccw/virtio.h | 145 ++++++++++++++++++++++++--------------------
4 files changed, 116 insertions(+), 95 deletions(-)
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 11cb803..7f192f3 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -14,7 +14,7 @@
char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
char ring_area[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
uint64_t boot_value;
-static struct subchannel_id blk_schid = { .one = 1 };
+static SubChannelId blk_schid = { .one = 1 };
/*
* Priniciples of Operations (SA22-7832-09) chapter 17 requires that
@@ -23,7 +23,7 @@ static struct subchannel_id blk_schid = { .one = 1 };
*/
void write_subsystem_identification(void)
{
- struct subchannel_id *schid = (struct subchannel_id *) 184;
+ SubChannelId *schid = (SubChannelId *) 184;
uint32_t *zeroes = (uint32_t *) 188;
*schid = blk_schid;
@@ -38,7 +38,7 @@ void panic(const char *string)
while (1) { }
}
-static bool find_dev(struct schib *schib, int dev_no)
+static bool find_dev(Schib *schib, int dev_no)
{
int i, r;
@@ -64,7 +64,7 @@ static bool find_dev(struct schib *schib, int dev_no)
static void virtio_setup(uint64_t dev_info)
{
- struct schib schib;
+ Schib schib;
int ssid;
bool found = false;
uint16_t dev_no;
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index 5135911..a5c0684 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -45,6 +45,14 @@ typedef unsigned long long __u64;
#include "cio.h"
+typedef struct irb Irb;
+typedef struct ccw1 Ccw1;
+typedef struct cmd_orb CmdOrb;
+typedef struct schib Schib;
+typedef struct chsc_area_sda ChscAreaSda;
+typedef struct senseid SenseId;
+typedef struct subchannel_id SubChannelId;
+
/* start.s */
void disabled_wait(void);
void consume_sclp_int(void);
@@ -63,8 +71,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(struct subchannel_id schid);
-void virtio_setup_block(struct subchannel_id schid);
+bool virtio_is_blk(SubChannelId schid);
+void virtio_setup_block(SubChannelId schid);
int virtio_read(ulong sector, void *load_addr);
int enable_mss_facility(void);
ulong get_second(void);
diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index da51fb7..64c6e07 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -11,7 +11,7 @@
#include "s390-ccw.h"
#include "virtio.h"
-static struct vring block;
+static VRing block;
static char chsc_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
@@ -31,7 +31,7 @@ static long kvm_hypercall(unsigned long nr, unsigned long param1,
return retval;
}
-static void virtio_notify(struct subchannel_id schid)
+static void virtio_notify(SubChannelId schid)
{
kvm_hypercall(KVM_S390_VIRTIO_CCW_NOTIFY, *(u32 *)&schid, 0);
}
@@ -40,9 +40,9 @@ static void virtio_notify(struct subchannel_id schid)
* Virtio functions *
***********************************************/
-static int drain_irqs(struct subchannel_id schid)
+static int drain_irqs(SubChannelId schid)
{
- struct irb irb = {};
+ Irb irb = {};
int r = 0;
while (1) {
@@ -59,11 +59,11 @@ static int drain_irqs(struct subchannel_id schid)
}
}
-static int run_ccw(struct subchannel_id schid, int cmd, void *ptr, int len)
+static int run_ccw(SubChannelId schid, int cmd, void *ptr, int len)
{
- struct ccw1 ccw = {};
- struct cmd_orb orb = {};
- struct schib schib;
+ Ccw1 ccw = {};
+ CmdOrb orb = {};
+ Schib schib;
int r;
/* start command processing */
@@ -92,7 +92,7 @@ static int run_ccw(struct subchannel_id schid, int cmd, void *ptr, int len)
return r;
}
-static void virtio_set_status(struct subchannel_id schid,
+static void virtio_set_status(SubChannelId schid,
unsigned long dev_addr)
{
unsigned char status = dev_addr;
@@ -101,18 +101,18 @@ static void virtio_set_status(struct subchannel_id schid,
}
}
-static void virtio_reset(struct subchannel_id schid)
+static void virtio_reset(SubChannelId schid)
{
run_ccw(schid, CCW_CMD_VDEV_RESET, NULL, 0);
}
-static void vring_init(struct vring *vr, unsigned int num, void *p,
+static void vring_init(VRing *vr, unsigned int num, void *p,
unsigned long align)
{
debug_print_addr("init p", p);
vr->num = num;
vr->desc = p;
- vr->avail = p + num*sizeof(struct vring_desc);
+ vr->avail = p + num * sizeof(VRingDesc);
vr->used = (void *)(((unsigned long)&vr->avail->ring[num] + align-1)
& ~(align - 1));
@@ -129,12 +129,12 @@ static void vring_init(struct vring *vr, unsigned int num, void *p,
debug_print_addr("init vr", vr);
}
-static void vring_notify(struct subchannel_id schid)
+static void vring_notify(SubChannelId schid)
{
virtio_notify(schid);
}
-static void vring_send_buf(struct vring *vr, void *p, int len, int flags)
+static void vring_send_buf(VRing *vr, void *p, int len, int flags)
{
/* For follow-up chains we need to keep the first entry point */
if (!(flags & VRING_HIDDEN_IS_CHAIN)) {
@@ -174,10 +174,10 @@ ulong get_second(void)
*
* Returns 0 on success, 1 on timeout.
*/
-static int vring_wait_reply(struct vring *vr, int timeout)
+static int vring_wait_reply(VRing *vr, int timeout)
{
ulong target_second = get_second() + timeout;
- struct subchannel_id schid = vr->schid;
+ SubChannelId schid = vr->schid;
int r = 0;
/* Wait until the used index has moved. */
@@ -204,7 +204,7 @@ static int vring_wait_reply(struct vring *vr, int timeout)
int virtio_read_many(ulong sector, void *load_addr, int sec_num)
{
- struct virtio_blk_outhdr out_hdr;
+ VirtioBlkOuthdr out_hdr;
u8 status;
int r;
@@ -363,10 +363,10 @@ uint64_t virtio_get_blocks(void)
(virtio_get_block_size() / VIRTIO_SECTOR_SIZE);
}
-void virtio_setup_block(struct subchannel_id schid)
+void virtio_setup_block(SubChannelId schid)
{
- struct vq_info_block info;
- struct vq_config_block config = {};
+ VqInfo info;
+ VqConfig config = {};
blk_cfg.blk_size = 0; /* mark "illegal" - setup started... */
guessed_disk_nature = false;
@@ -406,10 +406,10 @@ void virtio_setup_block(struct subchannel_id schid)
}
}
-bool virtio_is_blk(struct subchannel_id schid)
+bool virtio_is_blk(SubChannelId schid)
{
int r;
- struct senseid senseid = {};
+ SenseId senseid = {};
/* run sense id command */
r = run_ccw(schid, CCW_CMD_SENSE_ID, &senseid, sizeof(senseid));
@@ -426,7 +426,7 @@ bool virtio_is_blk(struct subchannel_id schid)
int enable_mss_facility(void)
{
int ret;
- struct chsc_area_sda *sda_area = (struct chsc_area_sda *) chsc_page;
+ ChscAreaSda *sda_area = (ChscAreaSda *) chsc_page;
memset(sda_area, 0, PAGE_SIZE);
sda_area->request.length = 0x0400;
diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h
index afa01a8..af6e142 100644
--- a/pc-bios/s390-ccw/virtio.h
+++ b/pc-bios/s390-ccw/virtio.h
@@ -23,48 +23,54 @@
/* We've given up on this device. */
#define VIRTIO_CONFIG_S_FAILED 0x80
-enum virtio_dev_type {
+enum VirtioDevType {
VIRTIO_ID_NET = 1,
VIRTIO_ID_BLOCK = 2,
VIRTIO_ID_CONSOLE = 3,
VIRTIO_ID_BALLOON = 5,
};
-
-struct virtio_dev_header {
- enum virtio_dev_type type : 8;
- u8 num_vq;
- u8 feature_len;
- u8 config_len;
- u8 status;
- u8 vqconfig[];
+typedef enum VirtioDevType VirtioDevType;
+
+struct VirtioDevHeader {
+ VirtioDevType type:8;
+ uint8_t num_vq;
+ uint8_t feature_len;
+ uint8_t config_len;
+ uint8_t status;
+ uint8_t vqconfig[];
} __attribute__((packed));
+typedef struct VirtioDevHeader VirtioDevHeader;
-struct virtio_vqconfig {
- u64 token;
- u64 address;
- u16 num;
- u8 pad[6];
+struct VirtioVqConfig {
+ uint64_t token;
+ uint64_t address;
+ uint16_t num;
+ uint8_t pad[6];
} __attribute__((packed));
+typedef struct VirtioVqConfig VirtioVqConfig;
-struct vq_info_block {
- u64 queue;
- u32 align;
- u16 index;
- u16 num;
+struct VqInfo {
+ uint64_t queue;
+ uint32_t align;
+ uint16_t index;
+ uint16_t num;
} __attribute__((packed));
+typedef struct VqInfo VqInfo;
-struct vq_config_block {
- u16 index;
- u16 num;
+struct VqConfig {
+ uint16_t index;
+ uint16_t num;
} __attribute__((packed));
+typedef struct VqConfig VqConfig;
-struct virtio_dev {
- struct virtio_dev_header *header;
- struct virtio_vqconfig *vqconfig;
+struct VirtioDev {
+ VirtioDevHeader *header;
+ VirtioVqConfig *vqconfig;
char *host_features;
char *guest_features;
char *config;
};
+typedef struct VirtioDev VirtioDev;
#define KVM_S390_VIRTIO_RING_ALIGN 4096
@@ -81,46 +87,51 @@ struct virtio_dev {
#define VRING_HIDDEN_IS_CHAIN 256
/* Virtio ring descriptors: 16 bytes. These can chain together via "next". */
-struct vring_desc {
+struct VRingDesc {
/* Address (guest-physical). */
- u64 addr;
+ uint64_t addr;
/* Length. */
- u32 len;
+ uint32_t len;
/* The flags as indicated above. */
- u16 flags;
+ uint16_t flags;
/* We chain unused descriptors via this, too */
- u16 next;
+ uint16_t next;
} __attribute__((packed));
+typedef struct VRingDesc VRingDesc;
-struct vring_avail {
- u16 flags;
- u16 idx;
- u16 ring[];
+struct VRingAvail {
+ uint16_t flags;
+ uint16_t idx;
+ uint16_t ring[];
} __attribute__((packed));
+typedef struct VRingAvail VRingAvail;
-/* u32 is used here for ids for padding reasons. */
-struct vring_used_elem {
+/* uint32_t is used here for ids for padding reasons. */
+struct VRingUsedElem {
/* Index of start of used descriptor chain. */
- u32 id;
+ uint32_t id;
/* Total length of the descriptor chain which was used (written to) */
- u32 len;
+ uint32_t len;
} __attribute__((packed));
+typedef struct VRingUsedElem VRingUsedElem;
-struct vring_used {
- u16 flags;
- u16 idx;
- struct vring_used_elem ring[];
+struct VRingUsed {
+ uint16_t flags;
+ uint16_t idx;
+ VRingUsedElem ring[];
} __attribute__((packed));
+typedef struct VRingUsed VRingUsed;
-struct vring {
+struct VRing {
unsigned int num;
int next_idx;
int used_idx;
- struct vring_desc *desc;
- struct vring_avail *avail;
- struct vring_used *used;
- struct subchannel_id schid;
+ VRingDesc *desc;
+ VRingAvail *avail;
+ VRingUsed *used;
+ SubChannelId schid;
};
+typedef struct VRing VRing;
/***********************************************
@@ -152,37 +163,39 @@ struct vring {
#define VIRTIO_BLK_T_BARRIER 0x80000000
/* This is the first element of the read scatter-gather list. */
-struct virtio_blk_outhdr {
+struct VirtioBlkOuthdr {
/* VIRTIO_BLK_T* */
- u32 type;
+ uint32_t type;
/* io priority. */
- u32 ioprio;
+ uint32_t ioprio;
/* Sector (ie. 512 byte offset) */
- u64 sector;
+ uint64_t sector;
};
+typedef struct VirtioBlkOuthdr VirtioBlkOuthdr;
-typedef struct VirtioBlkConfig {
- u64 capacity; /* in 512-byte sectors */
- u32 size_max; /* max segment size (if VIRTIO_BLK_F_SIZE_MAX) */
- u32 seg_max; /* max number of segments (if VIRTIO_BLK_F_SEG_MAX) */
+struct VirtioBlkConfig {
+ uint64_t capacity; /* in 512-byte sectors */
+ uint32_t size_max; /* max segment size (if VIRTIO_BLK_F_SIZE_MAX) */
+ uint32_t seg_max; /* max number of segments (if VIRTIO_BLK_F_SEG_MAX) */
- struct virtio_blk_geometry {
- u16 cylinders;
- u8 heads;
- u8 sectors;
+ struct VirtioBlkGeometry {
+ uint16_t cylinders;
+ uint8_t heads;
+ uint8_t sectors;
} geometry; /* (if VIRTIO_BLK_F_GEOMETRY) */
- u32 blk_size; /* block size of device (if VIRTIO_BLK_F_BLK_SIZE) */
+ uint32_t blk_size; /* block size of device (if VIRTIO_BLK_F_BLK_SIZE) */
/* the next 4 entries are guarded by VIRTIO_BLK_F_TOPOLOGY */
- u8 physical_block_exp; /* exponent for physical block per logical block */
- u8 alignment_offset; /* alignment offset in logical blocks */
- u16 min_io_size; /* min I/O size without performance penalty
+ uint8_t physical_block_exp; /* exponent for physical blk per logical blk */
+ uint8_t alignment_offset; /* alignment offset in logical blocks */
+ uint16_t min_io_size; /* min I/O size without performance penalty
in logical blocks */
- u32 opt_io_size; /* optimal sustained I/O size in logical blocks */
+ uint32_t opt_io_size; /* optimal sustained I/O size in logical blks */
- u8 wce; /* writeback mode (if VIRTIO_BLK_F_CONFIG_WCE) */
-} __attribute__((packed)) VirtioBlkConfig;
+ uint8_t wce; /* writeback mode (if VIRTIO_BLK_F_CONFIG_WCE) */
+} __attribute__((packed));
+typedef struct VirtioBlkConfig VirtioBlkConfig;
bool virtio_guessed_disk_nature(void);
void virtio_assume_scsi(void);
--
2.7.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PULL for-2.6 05/14] pc-bios/s390-ccw: update virtio implementation to allow up to 3 vrings
2016-03-24 8:29 [Qemu-devel] [PULL for-2.6 00/14] s390-ccw bios patches Cornelia Huck
` (3 preceding siblings ...)
2016-03-24 8:29 ` [Qemu-devel] [PULL for-2.6 04/14] pc-bios/s390-ccw: qemuize types Cornelia Huck
@ 2016-03-24 8:29 ` Cornelia Huck
2016-03-24 8:29 ` [Qemu-devel] [PULL for-2.6 06/14] pc-bios/s390-ccw: add vdev object to store all device details Cornelia Huck
` (9 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Cornelia Huck @ 2016-03-24 8:29 UTC (permalink / raw)
To: peter.maydell
Cc: qemu-devel, agraf, borntraeger, jfrei, Cornelia Huck,
Eugene (jno) Dvurechenski
From: "Eugene (jno) Dvurechenski" <jno@linux.vnet.ibm.com>
Add ability to work with up to 3 vrings, which is required for
virtio-scsi implementation.
Implement the optional cookie to speed up processing of virtio
notifications.
Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Eugene (jno) Dvurechenski <jno@linux.vnet.ibm.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
---
pc-bios/s390-ccw/main.c | 1 -
pc-bios/s390-ccw/s390-ccw.h | 1 -
pc-bios/s390-ccw/virtio.c | 140 +++++++++++++++++++++++++++-----------------
pc-bios/s390-ccw/virtio.h | 4 ++
4 files changed, 90 insertions(+), 56 deletions(-)
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 7f192f3..6bf44a7 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -12,7 +12,6 @@
#include "virtio.h"
char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
-char ring_area[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
uint64_t boot_value;
static SubChannelId blk_schid = { .one = 1 };
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index a5c0684..3e00d42 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -61,7 +61,6 @@ void consume_sclp_int(void);
void panic(const char *string);
void write_subsystem_identification(void);
extern char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
-extern char ring_area[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
extern uint64_t boot_value;
/* sclp-ascii.c */
diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index 64c6e07..d366aa3 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -11,29 +11,35 @@
#include "s390-ccw.h"
#include "virtio.h"
-static VRing block;
+static VRing block[VIRTIO_MAX_VQS];
+static char ring_area[VIRTIO_RING_SIZE * VIRTIO_MAX_VQS]
+ __attribute__((__aligned__(PAGE_SIZE)));
+static int nr_vqs = 1;
static char chsc_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
+/* virtio spec v1.0 para 4.3.3.2 */
static long kvm_hypercall(unsigned long nr, unsigned long param1,
- unsigned long param2)
+ unsigned long param2, unsigned long param3)
{
register ulong r_nr asm("1") = nr;
register ulong r_param1 asm("2") = param1;
register ulong r_param2 asm("3") = param2;
+ register ulong r_param3 asm("4") = param3;
register long retval asm("2");
asm volatile ("diag 2,4,0x500"
: "=d" (retval)
- : "d" (r_nr), "0" (r_param1), "r"(r_param2)
+ : "d" (r_nr), "0" (r_param1), "r"(r_param2), "d"(r_param3)
: "memory", "cc");
return retval;
}
-static void virtio_notify(SubChannelId schid)
+static long virtio_notify(SubChannelId schid, int vq_idx, long cookie)
{
- kvm_hypercall(KVM_S390_VIRTIO_CCW_NOTIFY, *(u32 *)&schid, 0);
+ return kvm_hypercall(KVM_S390_VIRTIO_CCW_NOTIFY, *(u32 *)&schid,
+ vq_idx, cookie);
}
/***********************************************
@@ -106,15 +112,17 @@ static void virtio_reset(SubChannelId schid)
run_ccw(schid, CCW_CMD_VDEV_RESET, NULL, 0);
}
-static void vring_init(VRing *vr, unsigned int num, void *p,
- unsigned long align)
+static void vring_init(VRing *vr, VqInfo *info)
{
+ void *p = (void *) info->queue;
+
debug_print_addr("init p", p);
- vr->num = num;
+ vr->id = info->index;
+ vr->num = info->num;
vr->desc = p;
- vr->avail = p + num * sizeof(VRingDesc);
- vr->used = (void *)(((unsigned long)&vr->avail->ring[num] + align-1)
- & ~(align - 1));
+ vr->avail = p + info->num * sizeof(VRingDesc);
+ vr->used = (void *)(((unsigned long)&vr->avail->ring[info->num]
+ + info->align - 1) & ~(info->align - 1));
/* Zero out all relevant field */
vr->avail->flags = 0;
@@ -125,13 +133,15 @@ static void vring_init(VRing *vr, unsigned int num, void *p,
vr->used->idx = 0;
vr->used_idx = 0;
vr->next_idx = 0;
+ vr->cookie = 0;
debug_print_addr("init vr", vr);
}
-static void vring_notify(SubChannelId schid)
+static bool vring_notify(VRing *vr)
{
- virtio_notify(schid);
+ vr->cookie = virtio_notify(vr->schid, vr->id, vr->cookie);
+ return vr->cookie >= 0;
}
static void vring_send_buf(VRing *vr, void *p, int len, int flags)
@@ -167,6 +177,21 @@ ulong get_second(void)
return (get_clock() >> 12) / 1000000;
}
+static int vr_poll(VRing *vr)
+{
+ if (vr->used->idx == vr->used_idx) {
+ vring_notify(vr);
+ yield();
+ return 0;
+ }
+
+ vr->used_idx = vr->used->idx;
+ vr->next_idx = 0;
+ vr->desc[0].len = 0;
+ vr->desc[0].flags = 0;
+ return 1; /* vr has been updated */
+}
+
/*
* Wait for the host to reply.
*
@@ -174,28 +199,24 @@ ulong get_second(void)
*
* Returns 0 on success, 1 on timeout.
*/
-static int vring_wait_reply(VRing *vr, int timeout)
+static int vring_wait_reply(int timeout)
{
ulong target_second = get_second() + timeout;
- SubChannelId schid = vr->schid;
- int r = 0;
- /* Wait until the used index has moved. */
- while (vr->used->idx == vr->used_idx) {
- vring_notify(schid);
- if (timeout && (get_second() >= target_second)) {
- r = 1;
- break;
+ /* Wait for any queue to be updated by the host */
+ do {
+ int i, r = 0;
+
+ for (i = 0; i < nr_vqs; i++) {
+ r += vr_poll(&block[i]);
}
yield();
- }
-
- vr->used_idx = vr->used->idx;
- vr->next_idx = 0;
- vr->desc[0].len = 0;
- vr->desc[0].flags = 0;
+ if (r) {
+ return 0;
+ }
+ } while (!timeout || (get_second() < target_second));
- return r;
+ return 1;
}
/***********************************************
@@ -213,21 +234,21 @@ int virtio_read_many(ulong sector, void *load_addr, int sec_num)
out_hdr.ioprio = 99;
out_hdr.sector = virtio_sector_adjust(sector);
- vring_send_buf(&block, &out_hdr, sizeof(out_hdr), VRING_DESC_F_NEXT);
+ vring_send_buf(&block[0], &out_hdr, sizeof(out_hdr), VRING_DESC_F_NEXT);
/* This is where we want to receive data */
- vring_send_buf(&block, load_addr, virtio_get_block_size() * sec_num,
+ vring_send_buf(&block[0], load_addr, virtio_get_block_size() * sec_num,
VRING_DESC_F_WRITE | VRING_HIDDEN_IS_CHAIN |
VRING_DESC_F_NEXT);
/* status field */
- vring_send_buf(&block, &status, sizeof(u8), VRING_DESC_F_WRITE |
+ vring_send_buf(&block[0], &status, sizeof(u8), VRING_DESC_F_WRITE |
VRING_HIDDEN_IS_CHAIN);
/* Now we can tell the host to read */
- vring_wait_reply(&block, 0);
+ vring_wait_reply(0);
- r = drain_irqs(block.schid);
+ r = drain_irqs(block[0].schid);
if (r) {
/* Well, whatever status is supposed to contain... */
status = 1;
@@ -363,15 +384,18 @@ uint64_t virtio_get_blocks(void)
(virtio_get_block_size() / VIRTIO_SECTOR_SIZE);
}
-void virtio_setup_block(SubChannelId schid)
+static void virtio_setup_ccw(SubChannelId schid,
+ int nvr, void *cfg, int cfg_size)
{
- VqInfo info;
- VqConfig config = {};
+ int i;
blk_cfg.blk_size = 0; /* mark "illegal" - setup started... */
+ nr_vqs = nvr;
guessed_disk_nature = false;
virtio_reset(schid);
+ IPL_assert(run_ccw(schid, CCW_CMD_READ_CONF, cfg, cfg_size) == 0,
+ "Could not get block device configuration");
/*
* Skipping CCW_CMD_READ_FEAT. We're not doing anything fancy, and
@@ -379,25 +403,33 @@ void virtio_setup_block(SubChannelId schid)
* expect it.
*/
- config.index = 0;
- if (run_ccw(schid, CCW_CMD_READ_VQ_CONF, &config, sizeof(config))) {
- panic("Could not get block device VQ configuration\n");
- }
- if (run_ccw(schid, CCW_CMD_READ_CONF, &blk_cfg, sizeof(blk_cfg))) {
- panic("Could not get block device configuration\n");
+ for (i = 0; i < nr_vqs; i++) {
+ VqInfo info = {
+ .queue = (unsigned long long) ring_area + (i * VIRTIO_RING_SIZE),
+ .align = KVM_S390_VIRTIO_RING_ALIGN,
+ .index = i,
+ .num = 0,
+ };
+ VqConfig config = {
+ .index = i,
+ .num = 0,
+ };
+
+ IPL_assert(
+ run_ccw(schid, CCW_CMD_READ_VQ_CONF, &config, sizeof(config)) == 0,
+ "Could not get block device VQ configuration");
+ info.num = config.num;
+ vring_init(&block[i], &info);
+ block[i].schid = schid;
+ IPL_assert(run_ccw(schid, CCW_CMD_SET_VQ, &info, sizeof(info)) == 0,
+ "Cannot set VQ info");
}
- vring_init(&block, config.num, ring_area,
- KVM_S390_VIRTIO_RING_ALIGN);
-
- info.queue = (unsigned long long) ring_area;
- info.align = KVM_S390_VIRTIO_RING_ALIGN;
- info.index = 0;
- info.num = config.num;
- block.schid = schid;
+ virtio_set_status(schid, VIRTIO_CONFIG_S_DRIVER_OK);
+}
- if (!run_ccw(schid, CCW_CMD_SET_VQ, &info, sizeof(info))) {
- virtio_set_status(schid, VIRTIO_CONFIG_S_DRIVER_OK);
- }
+void virtio_setup_block(SubChannelId schid)
+{
+ virtio_setup_ccw(schid, 1, &blk_cfg, sizeof(blk_cfg));
if (!virtio_ipl_disk_is_valid()) {
/* make sure all getters but blocksize return 0 for invalid IPL disk */
diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h
index af6e142..d17b135 100644
--- a/pc-bios/s390-ccw/virtio.h
+++ b/pc-bios/s390-ccw/virtio.h
@@ -72,6 +72,8 @@ struct VirtioDev {
};
typedef struct VirtioDev VirtioDev;
+#define VIRTIO_RING_SIZE (PAGE_SIZE * 8)
+#define VIRTIO_MAX_VQS 3
#define KVM_S390_VIRTIO_RING_ALIGN 4096
#define VRING_USED_F_NO_NOTIFY 1
@@ -130,6 +132,8 @@ struct VRing {
VRingAvail *avail;
VRingUsed *used;
SubChannelId schid;
+ long cookie;
+ int id;
};
typedef struct VRing VRing;
--
2.7.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PULL for-2.6 06/14] pc-bios/s390-ccw: add vdev object to store all device details
2016-03-24 8:29 [Qemu-devel] [PULL for-2.6 00/14] s390-ccw bios patches Cornelia Huck
` (4 preceding siblings ...)
2016-03-24 8:29 ` [Qemu-devel] [PULL for-2.6 05/14] pc-bios/s390-ccw: update virtio implementation to allow up to 3 vrings Cornelia Huck
@ 2016-03-24 8:29 ` Cornelia Huck
2016-03-24 8:29 ` [Qemu-devel] [PULL for-2.6 07/14] pc-bios/s390-ccw: make provisions for different backends Cornelia Huck
` (8 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Cornelia Huck @ 2016-03-24 8:29 UTC (permalink / raw)
To: peter.maydell
Cc: qemu-devel, agraf, borntraeger, jfrei, Cornelia Huck,
Eugene (jno) Dvurechenski
From: "Eugene (jno) Dvurechenski" <jno@linux.vnet.ibm.com>
Add VDev "object" as a container for all device-related items.
The default object is static.
Leverage dependency on many different device-related globals.
Make them syntactically visible.
Signed-off-by: Eugene (jno) Dvurechenski <jno@linux.vnet.ibm.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
---
pc-bios/s390-ccw/virtio.c | 181 +++++++++++++++++++++++++---------------------
pc-bios/s390-ccw/virtio.h | 18 +++++
2 files changed, 116 insertions(+), 83 deletions(-)
diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index d366aa3..6bf0c38 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -11,13 +11,34 @@
#include "s390-ccw.h"
#include "virtio.h"
+#define VRING_WAIT_REPLY_TIMEOUT 3
+
static VRing block[VIRTIO_MAX_VQS];
static char ring_area[VIRTIO_RING_SIZE * VIRTIO_MAX_VQS]
__attribute__((__aligned__(PAGE_SIZE)));
-static int nr_vqs = 1;
static char chsc_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
+static VDev vdev = {
+ .nr_vqs = 1,
+ .vrings = block,
+ .cmd_vr_idx = 0,
+ .ring_area = ring_area,
+ .wait_reply_timeout = VRING_WAIT_REPLY_TIMEOUT,
+ .guessed_disk_nature = false,
+ .schid = { .one = 1 },
+};
+
+VDev *virtio_get_device(void)
+{
+ return &vdev;
+}
+
+VirtioDevType virtio_get_device_type(void)
+{
+ return vdev.senseid.cu_model;
+}
+
/* virtio spec v1.0 para 4.3.3.2 */
static long kvm_hypercall(unsigned long nr, unsigned long param1,
unsigned long param2, unsigned long param3)
@@ -65,7 +86,7 @@ static int drain_irqs(SubChannelId schid)
}
}
-static int run_ccw(SubChannelId schid, int cmd, void *ptr, int len)
+static int run_ccw(VDev *vdev, int cmd, void *ptr, int len)
{
Ccw1 ccw = {};
CmdOrb orb = {};
@@ -73,9 +94,9 @@ static int run_ccw(SubChannelId schid, int cmd, void *ptr, int len)
int r;
/* start command processing */
- stsch_err(schid, &schib);
+ stsch_err(vdev->schid, &schib);
schib.scsw.ctrl = SCSW_FCTL_START_FUNC;
- msch(schid, &schib);
+ msch(vdev->schid, &schib);
/* start subchannel command */
orb.fmt = 1;
@@ -86,32 +107,18 @@ static int run_ccw(SubChannelId schid, int cmd, void *ptr, int len)
ccw.cda = (long)ptr;
ccw.count = len;
- r = ssch(schid, &orb);
+ r = ssch(vdev->schid, &orb);
/*
* XXX Wait until device is done processing the CCW. For now we can
* assume that a simple tsch will have finished the CCW processing,
* but the architecture allows for asynchronous operation
*/
if (!r) {
- r = drain_irqs(schid);
+ r = drain_irqs(vdev->schid);
}
return r;
}
-static void virtio_set_status(SubChannelId schid,
- unsigned long dev_addr)
-{
- unsigned char status = dev_addr;
- if (run_ccw(schid, CCW_CMD_WRITE_STATUS, &status, sizeof(status))) {
- panic("Could not write status to host!\n");
- }
-}
-
-static void virtio_reset(SubChannelId schid)
-{
- run_ccw(schid, CCW_CMD_VDEV_RESET, NULL, 0);
-}
-
static void vring_init(VRing *vr, VqInfo *info)
{
void *p = (void *) info->queue;
@@ -199,22 +206,22 @@ static int vr_poll(VRing *vr)
*
* Returns 0 on success, 1 on timeout.
*/
-static int vring_wait_reply(int timeout)
+static int vring_wait_reply(void)
{
- ulong target_second = get_second() + timeout;
+ ulong target_second = get_second() + vdev.wait_reply_timeout;
/* Wait for any queue to be updated by the host */
do {
int i, r = 0;
- for (i = 0; i < nr_vqs; i++) {
- r += vr_poll(&block[i]);
+ for (i = 0; i < vdev.nr_vqs; i++) {
+ r += vr_poll(&vdev.vrings[i]);
}
yield();
if (r) {
return 0;
}
- } while (!timeout || (get_second() < target_second));
+ } while (!vdev.wait_reply_timeout || (get_second() < target_second));
return 1;
}
@@ -227,29 +234,28 @@ int virtio_read_many(ulong sector, void *load_addr, int sec_num)
{
VirtioBlkOuthdr out_hdr;
u8 status;
- int r;
+ VRing *vr = &vdev.vrings[vdev.cmd_vr_idx];
/* Tell the host we want to read */
out_hdr.type = VIRTIO_BLK_T_IN;
out_hdr.ioprio = 99;
out_hdr.sector = virtio_sector_adjust(sector);
- vring_send_buf(&block[0], &out_hdr, sizeof(out_hdr), VRING_DESC_F_NEXT);
+ vring_send_buf(vr, &out_hdr, sizeof(out_hdr), VRING_DESC_F_NEXT);
/* This is where we want to receive data */
- vring_send_buf(&block[0], load_addr, virtio_get_block_size() * sec_num,
+ vring_send_buf(vr, load_addr, virtio_get_block_size() * sec_num,
VRING_DESC_F_WRITE | VRING_HIDDEN_IS_CHAIN |
VRING_DESC_F_NEXT);
/* status field */
- vring_send_buf(&block[0], &status, sizeof(u8), VRING_DESC_F_WRITE |
- VRING_HIDDEN_IS_CHAIN);
+ vring_send_buf(vr, &status, sizeof(u8),
+ VRING_DESC_F_WRITE | VRING_HIDDEN_IS_CHAIN);
/* Now we can tell the host to read */
- vring_wait_reply(0);
+ vring_wait_reply();
- r = drain_irqs(block[0].schid);
- if (r) {
+ if (drain_irqs(vr->schid)) {
/* Well, whatever status is supposed to contain... */
status = 1;
}
@@ -284,46 +290,43 @@ int virtio_read(ulong sector, void *load_addr)
return virtio_read_many(sector, load_addr, 1);
}
-static VirtioBlkConfig blk_cfg = {};
-static bool guessed_disk_nature;
-
bool virtio_guessed_disk_nature(void)
{
- return guessed_disk_nature;
+ return vdev.guessed_disk_nature;
}
void virtio_assume_scsi(void)
{
- guessed_disk_nature = true;
- blk_cfg.blk_size = 512;
- blk_cfg.physical_block_exp = 0;
+ vdev.guessed_disk_nature = true;
+ vdev.config.blk.blk_size = 512;
+ vdev.config.blk.physical_block_exp = 0;
}
void virtio_assume_iso9660(void)
{
- guessed_disk_nature = true;
- blk_cfg.blk_size = 2048;
- blk_cfg.physical_block_exp = 0;
+ vdev.guessed_disk_nature = true;
+ vdev.config.blk.blk_size = 2048;
+ vdev.config.blk.physical_block_exp = 0;
}
void virtio_assume_eckd(void)
{
- guessed_disk_nature = true;
- blk_cfg.blk_size = 4096;
- blk_cfg.physical_block_exp = 0;
+ vdev.guessed_disk_nature = true;
+ vdev.config.blk.blk_size = 4096;
+ vdev.config.blk.physical_block_exp = 0;
/* this must be here to calculate code segment position */
- blk_cfg.geometry.heads = 15;
- blk_cfg.geometry.sectors = 12;
+ vdev.config.blk.geometry.heads = 15;
+ vdev.config.blk.geometry.sectors = 12;
}
bool virtio_disk_is_scsi(void)
{
- if (guessed_disk_nature) {
+ if (vdev.guessed_disk_nature) {
return (virtio_get_block_size() == 512);
}
- return (blk_cfg.geometry.heads == 255)
- && (blk_cfg.geometry.sectors == 63)
+ return (vdev.config.blk.geometry.heads == 255)
+ && (vdev.config.blk.geometry.sectors == 63)
&& (virtio_get_block_size() == 512);
}
@@ -350,11 +353,11 @@ bool virtio_disk_is_eckd(void)
{
const int block_size = virtio_get_block_size();
- if (guessed_disk_nature) {
+ if (vdev.guessed_disk_nature) {
return (block_size == 4096);
}
- return (blk_cfg.geometry.heads == 15)
- && (blk_cfg.geometry.sectors ==
+ return (vdev.config.blk.geometry.heads == 15)
+ && (vdev.config.blk.geometry.sectors ==
virtio_eckd_sectors_for_block_size(block_size));
}
@@ -365,36 +368,45 @@ bool virtio_ipl_disk_is_valid(void)
int virtio_get_block_size(void)
{
- return blk_cfg.blk_size << blk_cfg.physical_block_exp;
+ return vdev.config.blk.blk_size << vdev.config.blk.physical_block_exp;
}
uint8_t virtio_get_heads(void)
{
- return blk_cfg.geometry.heads;
+ return vdev.config.blk.geometry.heads;
}
uint8_t virtio_get_sectors(void)
{
- return blk_cfg.geometry.sectors;
+ return vdev.config.blk.geometry.sectors;
}
uint64_t virtio_get_blocks(void)
{
- return blk_cfg.capacity /
+ return vdev.config.blk.capacity /
(virtio_get_block_size() / VIRTIO_SECTOR_SIZE);
}
-static void virtio_setup_ccw(SubChannelId schid,
- int nvr, void *cfg, int cfg_size)
+static void virtio_setup_ccw(VDev *vdev)
{
- int i;
+ int i, cfg_size;
+ unsigned char status = VIRTIO_CONFIG_S_DRIVER_OK;
+
+ vdev->config.blk.blk_size = 0; /* mark "illegal" - setup started... */
+ vdev->guessed_disk_nature = false;
- blk_cfg.blk_size = 0; /* mark "illegal" - setup started... */
- nr_vqs = nvr;
- guessed_disk_nature = false;
+ run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0);
- virtio_reset(schid);
- IPL_assert(run_ccw(schid, CCW_CMD_READ_CONF, cfg, cfg_size) == 0,
+ switch (vdev->senseid.cu_model) {
+ case VIRTIO_ID_BLOCK:
+ vdev->nr_vqs = 1;
+ vdev->cmd_vr_idx = 0;
+ cfg_size = sizeof(vdev->config.blk);
+ break;
+ default:
+ panic("Unsupported virtio device\n");
+ }
+ IPL_assert(run_ccw(vdev, CCW_CMD_READ_CONF, &vdev->config, cfg_size) == 0,
"Could not get block device configuration");
/*
@@ -403,7 +415,7 @@ static void virtio_setup_ccw(SubChannelId schid,
* expect it.
*/
- for (i = 0; i < nr_vqs; i++) {
+ for (i = 0; i < vdev->nr_vqs; i++) {
VqInfo info = {
.queue = (unsigned long long) ring_area + (i * VIRTIO_RING_SIZE),
.align = KVM_S390_VIRTIO_RING_ALIGN,
@@ -416,43 +428,46 @@ static void virtio_setup_ccw(SubChannelId schid,
};
IPL_assert(
- run_ccw(schid, CCW_CMD_READ_VQ_CONF, &config, sizeof(config)) == 0,
+ run_ccw(vdev, CCW_CMD_READ_VQ_CONF, &config, sizeof(config)) == 0,
"Could not get block device VQ configuration");
info.num = config.num;
- vring_init(&block[i], &info);
- block[i].schid = schid;
- IPL_assert(run_ccw(schid, CCW_CMD_SET_VQ, &info, sizeof(info)) == 0,
+ vring_init(&vdev->vrings[i], &info);
+ vdev->vrings[i].schid = vdev->schid;
+ IPL_assert(run_ccw(vdev, CCW_CMD_SET_VQ, &info, sizeof(info)) == 0,
"Cannot set VQ info");
}
- virtio_set_status(schid, VIRTIO_CONFIG_S_DRIVER_OK);
+ IPL_assert(
+ run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status)) == 0,
+ "Could not write status to host");
}
void virtio_setup_block(SubChannelId schid)
{
- virtio_setup_ccw(schid, 1, &blk_cfg, sizeof(blk_cfg));
+ 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(&blk_cfg, 0, sizeof(blk_cfg));
+ memset(&vdev.config.blk, 0, sizeof(vdev.config.blk));
virtio_assume_scsi();
}
}
bool virtio_is_blk(SubChannelId schid)
{
- int r;
- SenseId senseid = {};
-
+ vdev.schid = schid;
+ memset(&vdev.senseid, 0, sizeof(vdev.senseid));
/* run sense id command */
- r = run_ccw(schid, CCW_CMD_SENSE_ID, &senseid, sizeof(senseid));
- if (r) {
+ if (run_ccw(&vdev, CCW_CMD_SENSE_ID, &vdev.senseid, sizeof(vdev.senseid))) {
return false;
}
- if ((senseid.cu_type != 0x3832) || (senseid.cu_model != VIRTIO_ID_BLOCK)) {
- return false;
+ if (vdev.senseid.cu_type == 0x3832) {
+ switch (vdev.senseid.cu_model) {
+ case VIRTIO_ID_BLOCK:
+ return true;
+ }
}
-
- return true;
+ return false;
}
int enable_mss_facility(void)
diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h
index d17b135..b0034aa 100644
--- a/pc-bios/s390-ccw/virtio.h
+++ b/pc-bios/s390-ccw/virtio.h
@@ -222,4 +222,22 @@ static inline ulong virtio_sector_adjust(ulong sector)
return sector * (virtio_get_block_size() / VIRTIO_SECTOR_SIZE);
}
+struct VDev {
+ int nr_vqs;
+ VRing *vrings;
+ int cmd_vr_idx;
+ void *ring_area;
+ long wait_reply_timeout;
+ bool guessed_disk_nature;
+ SubChannelId schid;
+ SenseId senseid;
+ union {
+ VirtioBlkConfig blk;
+ } config;
+};
+typedef struct VDev VDev;
+
+VDev *virtio_get_device(void);
+VirtioDevType virtio_get_device_type(void);
+
#endif /* VIRTIO_H */
--
2.7.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PULL for-2.6 07/14] pc-bios/s390-ccw: make provisions for different backends
2016-03-24 8:29 [Qemu-devel] [PULL for-2.6 00/14] s390-ccw bios patches Cornelia Huck
` (5 preceding siblings ...)
2016-03-24 8:29 ` [Qemu-devel] [PULL for-2.6 06/14] pc-bios/s390-ccw: add vdev object to store all device details Cornelia Huck
@ 2016-03-24 8:29 ` Cornelia Huck
2016-03-24 8:29 ` [Qemu-devel] [PULL for-2.6 08/14] pc-bios/s390-ccw: add simplified virtio call Cornelia Huck
` (7 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Cornelia Huck @ 2016-03-24 8:29 UTC (permalink / raw)
To: peter.maydell
Cc: qemu-devel, agraf, borntraeger, jfrei, Cornelia Huck,
Eugene (jno) Dvurechenski
From: "Eugene (jno) Dvurechenski" <jno@linux.vnet.ibm.com>
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>
---
pc-bios/s390-ccw/main.c | 4 +-
pc-bios/s390-ccw/s390-ccw.h | 4 +-
pc-bios/s390-ccw/virtio.c | 130 +++++++++++++++++++++++++++++++-------------
pc-bios/s390-ccw/virtio.h | 12 +++-
4 files changed, 106 insertions(+), 44 deletions(-)
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 6bf44a7..69a02fe 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -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");
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index 3e00d42..616d967 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -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);
diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index 6bf0c38..56734af 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -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;
+ }
+ 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 (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));
diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h
index b0034aa..7b227db 100644
--- a/pc-bios/s390-ccw/virtio.h
+++ b/pc-bios/s390-ccw/virtio.h
@@ -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 {
--
2.7.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PULL for-2.6 08/14] pc-bios/s390-ccw: add simplified virtio call
2016-03-24 8:29 [Qemu-devel] [PULL for-2.6 00/14] s390-ccw bios patches Cornelia Huck
` (6 preceding siblings ...)
2016-03-24 8:29 ` [Qemu-devel] [PULL for-2.6 07/14] pc-bios/s390-ccw: make provisions for different backends Cornelia Huck
@ 2016-03-24 8:29 ` Cornelia Huck
2016-03-24 8:29 ` [Qemu-devel] [PULL for-2.6 09/14] pc-bios/s390-ccw: add scsi definitions Cornelia Huck
` (6 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Cornelia Huck @ 2016-03-24 8:29 UTC (permalink / raw)
To: peter.maydell
Cc: qemu-devel, agraf, borntraeger, jfrei, Cornelia Huck,
Eugene (jno) Dvurechenski
From: "Eugene (jno) Dvurechenski" <jno@linux.vnet.ibm.com>
Add virtio_run(VirtioCmd) call to use simple declarative approach.
Signed-off-by: Eugene (jno) Dvurechenski <jno@linux.vnet.ibm.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
---
pc-bios/s390-ccw/virtio.c | 17 +++++++++++++++++
pc-bios/s390-ccw/virtio.h | 9 +++++++++
2 files changed, 26 insertions(+)
diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index 56734af..4ab4d47 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -225,6 +225,23 @@ static int vring_wait_reply(void)
return 1;
}
+int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd)
+{
+ VRing *vr = &vdev->vrings[vqid];
+ int i = 0;
+
+ do {
+ vring_send_buf(vr, cmd[i].data, cmd[i].size,
+ cmd[i].flags | (i ? VRING_HIDDEN_IS_CHAIN : 0));
+ } while (cmd[i++].flags & VRING_DESC_F_NEXT);
+
+ vring_wait_reply();
+ if (drain_irqs(vr->schid)) {
+ return -1;
+ }
+ return 0;
+}
+
/***********************************************
* Virtio block *
***********************************************/
diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h
index 7b227db..57c71a2 100644
--- a/pc-bios/s390-ccw/virtio.h
+++ b/pc-bios/s390-ccw/virtio.h
@@ -248,4 +248,13 @@ typedef struct VDev VDev;
VDev *virtio_get_device(void);
VirtioDevType virtio_get_device_type(void);
+struct VirtioCmd {
+ void *data;
+ int size;
+ int flags;
+};
+typedef struct VirtioCmd VirtioCmd;
+
+int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd);
+
#endif /* VIRTIO_H */
--
2.7.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PULL for-2.6 09/14] pc-bios/s390-ccw: add scsi definitions
2016-03-24 8:29 [Qemu-devel] [PULL for-2.6 00/14] s390-ccw bios patches Cornelia Huck
` (7 preceding siblings ...)
2016-03-24 8:29 ` [Qemu-devel] [PULL for-2.6 08/14] pc-bios/s390-ccw: add simplified virtio call Cornelia Huck
@ 2016-03-24 8:29 ` Cornelia Huck
2016-03-24 8:29 ` [Qemu-devel] [PULL for-2.6 10/14] pc-bios/s390-ccw: add virtio-scsi implementation Cornelia Huck
` (5 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Cornelia Huck @ 2016-03-24 8:29 UTC (permalink / raw)
To: peter.maydell
Cc: qemu-devel, agraf, borntraeger, jfrei, Cornelia Huck,
Eugene (jno) Dvurechenski
From: "Eugene (jno) Dvurechenski" <jno@linux.vnet.ibm.com>
Add scsi.h to provide basic definitions for SCSI.
Signed-off-by: Eugene (jno) Dvurechenski <jno@linux.vnet.ibm.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
---
pc-bios/s390-ccw/scsi.h | 184 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 184 insertions(+)
create mode 100644 pc-bios/s390-ccw/scsi.h
diff --git a/pc-bios/s390-ccw/scsi.h b/pc-bios/s390-ccw/scsi.h
new file mode 100644
index 0000000..fc830f7
--- /dev/null
+++ b/pc-bios/s390-ccw/scsi.h
@@ -0,0 +1,184 @@
+/*
+ * SCSI definitions for s390 machine loader for qemu
+ *
+ * Copyright 2015 IBM Corp.
+ * Author: Eugene "jno" Dvurechenski <jno@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#ifndef SCSI_H
+#define SCSI_H
+
+#include "s390-ccw.h"
+
+#define SCSI_DEFAULT_CDB_SIZE 32
+#define SCSI_DEFAULT_SENSE_SIZE 96
+
+#define CDB_STATUS_GOOD 0
+#define CDB_STATUS_CHECK_CONDITION 0x02U
+#define CDB_STATUS_VALID(status) (((status) & ~0x3eU) == 0)
+
+#define SCSI_SENSE_CODE_MASK 0x7fU
+#define SCSI_SENSE_KEY_MASK 0x0fU
+#define SCSI_SENSE_KEY_NO_SENSE 0
+#define SCSI_SENSE_KEY_UNIT_ATTENTION 6
+
+union ScsiLun {
+ uint64_t v64; /* numeric shortcut */
+ uint8_t v8[8]; /* generic 8 bytes representation */
+ uint16_t v16[4]; /* 4-level big-endian LUN as specified by SAM-2 */
+};
+typedef union ScsiLun ScsiLun;
+
+struct ScsiSense70 {
+ uint8_t b0; /* b0 & 7f = resp code (0x70 or 0x71) */
+ uint8_t b1, b2; /* b2 & 0f = sense key */
+ uint8_t u1[1 * 4 + 1 + 1 * 4]; /* b7 = N - 7 */
+ uint8_t additional_sense_code; /* b12 */
+ uint8_t additional_sense_code_qualifier; /* b13 */
+ uint8_t u2[1 + 3 + 0]; /* up to N (<=252) bytes */
+} __attribute__((packed));
+typedef struct ScsiSense70 ScsiSense70;
+
+/* don't confuse with virtio-scsi response/status fields! */
+
+static inline uint8_t scsi_sense_response(const void *p)
+{
+ return ((const ScsiSense70 *)p)->b0 & SCSI_SENSE_CODE_MASK;
+}
+
+static inline uint8_t scsi_sense_key(const void *p)
+{
+ return ((const ScsiSense70 *)p)->b2 & SCSI_SENSE_KEY_MASK;
+}
+
+#define SCSI_INQ_RDT_CDROM 0x05
+
+struct ScsiInquiryStd {
+ uint8_t peripheral_qdt; /* b0, use (b0 & 0x1f) to get SCSI_INQ_RDT */
+ uint8_t b1; /* Removable Media Bit = b1 & 0x80 */
+ uint8_t spc_version; /* b2 */
+ uint8_t b3; /* b3 & 0x0f == resp_data_fmt == 2, must! */
+ uint8_t u1[1 + 1 + 1 + 1 + 8]; /* b4..b15 unused, b4 = (N - 1) */
+ char prod_id[16]; /* "QEMU CD-ROM" is here */
+ uint8_t u2[4 /* b32..b35 unused, mandatory */
+ + 8 + 12 + 1 + 1 + 8 * 2 + 22 /* b36..95 unused, optional*/
+ + 0]; /* b96..bN unused, vendor specific */
+ /* byte N */
+} __attribute__((packed));
+typedef struct ScsiInquiryStd ScsiInquiryStd;
+
+struct ScsiCdbInquiry {
+ uint8_t command; /* b0, == 0x12 */
+ uint8_t b1; /* b1, |= 0x01 (evpd) */
+ uint8_t b2; /* b2; if evpd==1 */
+ uint16_t alloc_len; /* b3, b4 */
+ uint8_t control; /* b5 */
+} __attribute__((packed));
+typedef struct ScsiCdbInquiry ScsiCdbInquiry;
+
+struct ScsiCdbRead10 {
+ uint8_t command; /* =0x28 */
+ uint8_t b1;
+ uint32_t lba;
+ uint8_t b6;
+ uint16_t xfer_length;
+ uint8_t control;
+} __attribute__((packed));
+typedef struct ScsiCdbRead10 ScsiCdbRead10;
+
+struct ScsiCdbTestUnitReady {
+ uint8_t command; /* =0x00 */
+ uint8_t b1_b4[4];
+ uint8_t control;
+} __attribute__((packed));
+typedef struct ScsiCdbTestUnitReady ScsiCdbTestUnitReady;
+
+struct ScsiCdbReportLuns {
+ uint8_t command; /* =0xa0 */
+ uint8_t b1;
+ uint8_t select_report; /* =0x02, "all" */
+ uint8_t b3_b5[3];
+ uint32_t alloc_len;
+ uint8_t b10;
+ uint8_t control;
+} __attribute__((packed));
+typedef struct ScsiCdbReportLuns ScsiCdbReportLuns;
+
+struct ScsiLunReport {
+ uint32_t lun_list_len;
+ uint32_t b4_b7;
+ ScsiLun lun[1]; /* space for at least 1 lun must be allocated */
+} __attribute__((packed));
+typedef struct ScsiLunReport ScsiLunReport;
+
+struct ScsiCdbReadCapacity16 {
+ uint8_t command; /* =0x9e = "service action in 16" */
+ uint8_t service_action; /* 5 bits, =0x10 = "read capacity 16" */
+ uint64_t b2_b9;
+ uint32_t alloc_len;
+ uint8_t b14;
+ uint8_t control;
+} __attribute__((packed));
+typedef struct ScsiCdbReadCapacity16 ScsiCdbReadCapacity16;
+
+struct ScsiReadCapacity16Data {
+ uint64_t ret_lba; /* get it, 0..7 */
+ uint32_t lb_len; /* bytes, 8..11 */
+ uint8_t u1[2 + 1 * 2 + 16]; /* b12..b31, unused */
+} __attribute__((packed));
+typedef struct ScsiReadCapacity16Data ScsiReadCapacity16Data;
+
+static inline ScsiLun make_lun(uint16_t channel, uint16_t target, uint32_t lun)
+{
+ ScsiLun r = { .v64 = 0 };
+
+ /* See QEMU code to choose the way to handle LUNs.
+ *
+ * So, a valid LUN must have (always channel #0):
+ * lun[0] == 1
+ * lun[1] - target, any value
+ * lun[2] == 0 or (LUN, MSB, 0x40 set, 0x80 clear)
+ * lun[3] - LUN, LSB, any value
+ */
+ r.v8[0] = 1;
+ r.v8[1] = target & 0xffU;
+ r.v8[2] = (lun >> 8) & 0x3fU;
+ if (r.v8[2]) {
+ r.v8[2] |= 0x40;
+ }
+ r.v8[3] = lun & 0xffU;
+
+ return r;
+}
+
+static inline const char *scsi_cdb_status_msg(uint8_t status)
+{
+ static char err_msg[] = "STATUS=XX";
+ uint8_t v = status & 0x3eU;
+
+ fill_hex_val(err_msg + 7, &v, 1);
+ return err_msg;
+}
+
+static inline const char *scsi_cdb_asc_msg(const void *s)
+{
+ static char err_msg[] = "RSPN=XX KEY=XX CODE=XX QLFR=XX";
+ const ScsiSense70 *p = s;
+ uint8_t sr = scsi_sense_response(s);
+ uint8_t sk = scsi_sense_key(s);
+ uint8_t ac = p->additional_sense_code;
+ uint8_t cq = p->additional_sense_code_qualifier;
+
+ fill_hex_val(err_msg + 5, &sr, 1);
+ fill_hex_val(err_msg + 12, &sk, 1);
+ fill_hex_val(err_msg + 20, &ac, 1);
+ fill_hex_val(err_msg + 28, &cq, 1);
+
+ return err_msg;
+}
+
+#endif /* SCSI_H */
--
2.7.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PULL for-2.6 10/14] pc-bios/s390-ccw: add virtio-scsi implementation
2016-03-24 8:29 [Qemu-devel] [PULL for-2.6 00/14] s390-ccw bios patches Cornelia Huck
` (8 preceding siblings ...)
2016-03-24 8:29 ` [Qemu-devel] [PULL for-2.6 09/14] pc-bios/s390-ccw: add scsi definitions Cornelia Huck
@ 2016-03-24 8:29 ` Cornelia Huck
2016-03-24 8:30 ` [Qemu-devel] [PULL for-2.6 11/14] pc-bios/s390-ccw: enable virtio-scsi Cornelia Huck
` (4 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Cornelia Huck @ 2016-03-24 8:29 UTC (permalink / raw)
To: peter.maydell
Cc: qemu-devel, agraf, borntraeger, jfrei, Cornelia Huck,
Eugene (jno) Dvurechenski
From: "Eugene (jno) Dvurechenski" <jno@linux.vnet.ibm.com>
Add virtio-scsi.[ch] with primary implementation of virtio-scsi.
Signed-off-by: Eugene (jno) Dvurechenski <jno@linux.vnet.ibm.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
---
pc-bios/s390-ccw/virtio-scsi.c | 342 +++++++++++++++++++++++++++++++++++++++++
pc-bios/s390-ccw/virtio-scsi.h | 72 +++++++++
2 files changed, 414 insertions(+)
create mode 100644 pc-bios/s390-ccw/virtio-scsi.c
create mode 100644 pc-bios/s390-ccw/virtio-scsi.h
diff --git a/pc-bios/s390-ccw/virtio-scsi.c b/pc-bios/s390-ccw/virtio-scsi.c
new file mode 100644
index 0000000..3bb48e9
--- /dev/null
+++ b/pc-bios/s390-ccw/virtio-scsi.c
@@ -0,0 +1,342 @@
+/*
+ * Virtio-SCSI implementation for s390 machine loader for qemu
+ *
+ * Copyright 2015 IBM Corp.
+ * Author: Eugene "jno" Dvurechenski <jno@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#include "s390-ccw.h"
+#include "virtio.h"
+#include "scsi.h"
+#include "virtio-scsi.h"
+
+static ScsiDevice default_scsi_device;
+static VirtioScsiCmdReq req;
+static VirtioScsiCmdResp resp;
+
+static uint8_t scsi_inquiry_std_response[256];
+
+static inline void vs_assert(bool term, const char **msgs)
+{
+ if (!term) {
+ int i = 0;
+
+ sclp_print("\n! ");
+ while (msgs[i]) {
+ sclp_print(msgs[i++]);
+ }
+ panic(" !\n");
+ }
+}
+
+static void virtio_scsi_verify_response(VirtioScsiCmdResp *resp,
+ const char *title)
+{
+ const char *mr[] = {
+ title, ": response ", virtio_scsi_response_msg(resp), 0
+ };
+ const char *ms[] = {
+ title,
+ CDB_STATUS_VALID(resp->status) ? ": " : ": invalid ",
+ scsi_cdb_status_msg(resp->status),
+ resp->status == CDB_STATUS_CHECK_CONDITION ? " " : 0,
+ resp->sense_len ? scsi_cdb_asc_msg(resp->sense)
+ : "no sense data",
+ scsi_sense_response(resp->sense) == 0x70 ? ", sure" : "?",
+ 0
+ };
+
+ vs_assert(resp->response == VIRTIO_SCSI_S_OK, mr);
+ vs_assert(resp->status == CDB_STATUS_GOOD, ms);
+}
+
+static void prepare_request(VDev *vdev, const void *cdb, int cdb_size,
+ void *data, uint32_t data_size)
+{
+ const ScsiDevice *sdev = vdev->scsi_device;
+
+ memset(&req, 0, sizeof(req));
+ req.lun = make_lun(sdev->channel, sdev->target, sdev->lun);
+ memcpy(&req.cdb, cdb, cdb_size);
+
+ memset(&resp, 0, sizeof(resp));
+ resp.status = 0xff; /* set invalid */
+ resp.response = 0xff; /* */
+
+ if (data && data_size) {
+ memset(data, 0, data_size);
+ }
+}
+
+static inline void vs_io_assert(bool term, const char *msg)
+{
+ if (!term) {
+ virtio_scsi_verify_response(&resp, msg);
+ }
+}
+
+static void vs_run(const char *title, VirtioCmd *cmd, VDev *vdev,
+ const void *cdb, int cdb_size,
+ void *data, uint32_t data_size)
+{
+ prepare_request(vdev, cdb, cdb_size, data, data_size);
+ vs_io_assert(virtio_run(vdev, VR_REQUEST, cmd) == 0, title);
+}
+
+/* SCSI protocol implementation routines */
+
+static bool scsi_inquiry(VDev *vdev, void *data, uint32_t data_size)
+{
+ ScsiCdbInquiry cdb = {
+ .command = 0x12,
+ .alloc_len = data_size < 65535 ? data_size : 65535,
+ };
+ VirtioCmd inquiry[] = {
+ { &req, sizeof(req), VRING_DESC_F_NEXT },
+ { &resp, sizeof(resp), VRING_DESC_F_WRITE | VRING_DESC_F_NEXT },
+ { data, data_size, VRING_DESC_F_WRITE },
+ };
+
+ vs_run("inquiry", inquiry, vdev, &cdb, sizeof(cdb), data, data_size);
+
+ return virtio_scsi_response_ok(&resp);
+}
+
+static bool scsi_test_unit_ready(VDev *vdev)
+{
+ ScsiCdbTestUnitReady cdb = {
+ .command = 0x00,
+ };
+ VirtioCmd test_unit_ready[] = {
+ { &req, sizeof(req), VRING_DESC_F_NEXT },
+ { &resp, sizeof(resp), VRING_DESC_F_WRITE },
+ };
+
+ prepare_request(vdev, &cdb, sizeof(cdb), 0, 0);
+ virtio_run(vdev, VR_REQUEST, test_unit_ready); /* ignore errors here */
+
+ return virtio_scsi_response_ok(&resp);
+}
+
+static bool scsi_report_luns(VDev *vdev, void *data, uint32_t data_size)
+{
+ ScsiCdbReportLuns cdb = {
+ .command = 0xa0,
+ .select_report = 0x02, /* REPORT ALL */
+ .alloc_len = data_size,
+ };
+ VirtioCmd report_luns[] = {
+ { &req, sizeof(req), VRING_DESC_F_NEXT },
+ { &resp, sizeof(resp), VRING_DESC_F_WRITE | VRING_DESC_F_NEXT },
+ { data, data_size, VRING_DESC_F_WRITE },
+ };
+
+ vs_run("report luns", report_luns,
+ vdev, &cdb, sizeof(cdb), data, data_size);
+
+ return virtio_scsi_response_ok(&resp);
+}
+
+static bool scsi_read_10(VDev *vdev,
+ ulong sector, int sectors, void *data)
+{
+ int f = vdev->blk_factor;
+ unsigned int data_size = sectors * virtio_get_block_size() * f;
+ ScsiCdbRead10 cdb = {
+ .command = 0x28,
+ .lba = sector * f,
+ .xfer_length = sectors * f,
+ };
+ VirtioCmd read_10[] = {
+ { &req, sizeof(req), VRING_DESC_F_NEXT },
+ { &resp, sizeof(resp), VRING_DESC_F_WRITE | VRING_DESC_F_NEXT },
+ { data, data_size * f, VRING_DESC_F_WRITE },
+ };
+
+ debug_print_int("read_10 sector", sector);
+ debug_print_int("read_10 sectors", sectors);
+
+ vs_run("read(10)", read_10, vdev, &cdb, sizeof(cdb), data, data_size);
+
+ return virtio_scsi_response_ok(&resp);
+}
+
+static bool scsi_read_capacity(VDev *vdev,
+ void *data, uint32_t data_size)
+{
+ ScsiCdbReadCapacity16 cdb = {
+ .command = 0x9e, /* SERVICE_ACTION_IN_16 */
+ .service_action = 0x10, /* SA_READ_CAPACITY */
+ .alloc_len = data_size,
+ };
+ VirtioCmd read_capacity_16[] = {
+ { &req, sizeof(req), VRING_DESC_F_NEXT },
+ { &resp, sizeof(resp), VRING_DESC_F_WRITE | VRING_DESC_F_NEXT },
+ { data, data_size, VRING_DESC_F_WRITE },
+ };
+
+ vs_run("read capacity", read_capacity_16,
+ vdev, &cdb, sizeof(cdb), data, data_size);
+
+ return virtio_scsi_response_ok(&resp);
+}
+
+/* virtio-scsi routines */
+
+static void virtio_scsi_locate_device(VDev *vdev)
+{
+ const uint16_t channel = 0; /* again, it's what QEMU does */
+ uint16_t target;
+ static uint8_t data[16 + 8 * 63];
+ ScsiLunReport *r = (void *) data;
+ ScsiDevice *sdev = vdev->scsi_device;
+ int i, luns;
+
+ /* QEMU has hardcoded channel #0 in many places.
+ * If this hardcoded value is ever changed, we'll need to add code for
+ * vdev->config.scsi.max_channel != 0 here.
+ */
+ debug_print_int("config.scsi.max_channel", vdev->config.scsi.max_channel);
+ debug_print_int("config.scsi.max_target ", vdev->config.scsi.max_target);
+ debug_print_int("config.scsi.max_lun ", vdev->config.scsi.max_lun);
+
+ for (target = 0; target <= vdev->config.scsi.max_target; target++) {
+ sdev->channel = channel;
+ sdev->target = target; /* sdev->lun will be 0 here */
+ if (!scsi_report_luns(vdev, data, sizeof(data))) {
+ if (resp.response == VIRTIO_SCSI_S_BAD_TARGET) {
+ continue;
+ }
+ print_int("target", target);
+ virtio_scsi_verify_response(&resp, "SCSI cannot report LUNs");
+ }
+ if (r->lun_list_len == 0) {
+ print_int("no LUNs for target", target);
+ continue;
+ }
+ luns = r->lun_list_len / 8;
+ debug_print_int("LUNs reported", luns);
+ if (luns == 1) {
+ /* There is no ",lun=#" arg for -device or ",lun=0" given.
+ * Hence, the only LUN reported.
+ * Usually, it's 0.
+ */
+ sdev->lun = r->lun[0].v16[0]; /* it's returned this way */
+ debug_print_int("Have to use LUN", sdev->lun);
+ return; /* we have to use this device */
+ }
+ for (i = 0; i < luns; i++) {
+ if (r->lun[i].v64) {
+ /* Look for non-zero LUN - we have where to choose from */
+ sdev->lun = r->lun[i].v16[0];
+ debug_print_int("Will use LUN", sdev->lun);
+ return; /* we have found a device */
+ }
+ }
+ }
+ panic("\n! Cannot locate virtio-scsi device !\n");
+}
+
+int virtio_scsi_read_many(VDev *vdev,
+ ulong sector, void *load_addr, int sec_num)
+{
+ if (!scsi_read_10(vdev, sector, sec_num, load_addr)) {
+ virtio_scsi_verify_response(&resp, "virtio-scsi:read_many");
+ }
+
+ return 0;
+}
+
+static bool virtio_scsi_inquiry_response_is_cdrom(void *data)
+{
+ const ScsiInquiryStd *response = data;
+ const int resp_data_fmt = response->b3 & 0x0f;
+ int i;
+
+ IPL_check(resp_data_fmt == 2, "Wrong INQUIRY response format");
+ if (resp_data_fmt != 2) {
+ return false; /* cannot decode */
+ }
+
+ if ((response->peripheral_qdt & 0x1f) == SCSI_INQ_RDT_CDROM) {
+ return true;
+ }
+
+ for (i = 0; i < sizeof(response->prod_id); i++) {
+ if (response->prod_id[i] != QEMU_CDROM_SIGNATURE[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static void scsi_parse_capacity_report(void *data,
+ uint64_t *last_lba, uint32_t *lb_len)
+{
+ ScsiReadCapacity16Data *p = data;
+
+ if (last_lba) {
+ *last_lba = p->ret_lba;
+ }
+
+ if (lb_len) {
+ *lb_len = p->lb_len;
+ }
+}
+
+void virtio_scsi_setup(VDev *vdev)
+{
+ int retry_test_unit_ready = 3;
+ uint8_t data[256];
+ uint32_t data_size = sizeof(data);
+
+ vdev->scsi_device = &default_scsi_device;
+ virtio_scsi_locate_device(vdev);
+
+ /* We have to "ping" the device before it becomes readable */
+ while (!scsi_test_unit_ready(vdev)) {
+
+ if (!virtio_scsi_response_ok(&resp)) {
+ uint8_t code = resp.sense[0] & SCSI_SENSE_CODE_MASK;
+ uint8_t sense_key = resp.sense[2] & SCSI_SENSE_KEY_MASK;
+
+ IPL_assert(resp.sense_len != 0, "virtio-scsi:setup: no SENSE data");
+
+ IPL_assert(retry_test_unit_ready && code == 0x70 &&
+ sense_key == SCSI_SENSE_KEY_UNIT_ATTENTION,
+ "virtio-scsi:setup: cannot retry");
+
+ /* retry on CHECK_CONDITION/UNIT_ATTENTION as it
+ * may not designate a real error, but it may be
+ * a result of device reset, etc.
+ */
+ retry_test_unit_ready--;
+ sleep(1);
+ continue;
+ }
+
+ virtio_scsi_verify_response(&resp, "virtio-scsi:setup");
+ }
+
+ /* read and cache SCSI INQUIRY response */
+ if (!scsi_inquiry(vdev, scsi_inquiry_std_response,
+ sizeof(scsi_inquiry_std_response))) {
+ virtio_scsi_verify_response(&resp, "virtio-scsi:setup:inquiry");
+ }
+
+ if (virtio_scsi_inquiry_response_is_cdrom(scsi_inquiry_std_response)) {
+ sclp_print("SCSI CD-ROM detected.\n");
+ vdev->is_cdrom = true;
+ vdev->scsi_block_size = VIRTIO_ISO_BLOCK_SIZE;
+ }
+
+ if (!scsi_read_capacity(vdev, data, data_size)) {
+ virtio_scsi_verify_response(&resp, "virtio-scsi:setup:read_capacity");
+ }
+ scsi_parse_capacity_report(data, &vdev->scsi_last_block,
+ (uint32_t *) &vdev->scsi_block_size);
+}
diff --git a/pc-bios/s390-ccw/virtio-scsi.h b/pc-bios/s390-ccw/virtio-scsi.h
new file mode 100644
index 0000000..f50b38b
--- /dev/null
+++ b/pc-bios/s390-ccw/virtio-scsi.h
@@ -0,0 +1,72 @@
+/*
+ * Virtio-SCSI definitions for s390 machine loader for qemu
+ *
+ * Copyright 2015 IBM Corp.
+ * Author: Eugene "jno" Dvurechenski <jno@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#ifndef VIRTIO_SCSI_H
+#define VIRTIO_SCSI_H
+
+#include "s390-ccw.h"
+#include "virtio.h"
+#include "scsi.h"
+
+#define VIRTIO_SCSI_CDB_SIZE SCSI_DEFAULT_CDB_SIZE
+#define VIRTIO_SCSI_SENSE_SIZE SCSI_DEFAULT_SENSE_SIZE
+
+/* command-specific response values */
+#define VIRTIO_SCSI_S_OK 0x00
+#define VIRTIO_SCSI_S_BAD_TARGET 0x03
+
+#define QEMU_CDROM_SIGNATURE "QEMU CD-ROM "
+
+enum virtio_scsi_vq_id {
+ VR_CONTROL = 0,
+ VR_EVENT = 1,
+ VR_REQUEST = 2,
+};
+
+struct VirtioScsiCmdReq {
+ ScsiLun lun;
+ uint64_t id;
+ uint8_t task_attr; /* = 0 = VIRTIO_SCSI_S_SIMPLE */
+ uint8_t prio;
+ uint8_t crn; /* = 0 */
+ uint8_t cdb[VIRTIO_SCSI_CDB_SIZE];
+} __attribute__((packed));
+typedef struct VirtioScsiCmdReq VirtioScsiCmdReq;
+
+struct VirtioScsiCmdResp {
+ uint32_t sense_len;
+ uint32_t residual;
+ uint16_t status_qualifier;
+ uint8_t status; /* first check for .response */
+ uint8_t response; /* then for .status */
+ uint8_t sense[VIRTIO_SCSI_SENSE_SIZE];
+} __attribute__((packed));
+typedef struct VirtioScsiCmdResp VirtioScsiCmdResp;
+
+static inline const char *virtio_scsi_response_msg(const VirtioScsiCmdResp *r)
+{
+ static char err_msg[] = "VS RESP=XX";
+ uint8_t v = r->response;
+
+ fill_hex_val(err_msg + 8, &v, 1);
+ return err_msg;
+}
+
+static inline bool virtio_scsi_response_ok(const VirtioScsiCmdResp *r)
+{
+ return r->response == VIRTIO_SCSI_S_OK && r->status == CDB_STATUS_GOOD;
+}
+
+void virtio_scsi_setup(VDev *vdev);
+int virtio_scsi_read_many(VDev *vdev,
+ ulong sector, void *load_addr, int sec_num);
+
+#endif /* VIRTIO_SCSI_H */
--
2.7.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PULL for-2.6 11/14] pc-bios/s390-ccw: enable virtio-scsi
2016-03-24 8:29 [Qemu-devel] [PULL for-2.6 00/14] s390-ccw bios patches Cornelia Huck
` (9 preceding siblings ...)
2016-03-24 8:29 ` [Qemu-devel] [PULL for-2.6 10/14] pc-bios/s390-ccw: add virtio-scsi implementation Cornelia Huck
@ 2016-03-24 8:30 ` Cornelia Huck
2016-03-24 8:30 ` [Qemu-devel] [PULL for-2.6 12/14] pc-bios/s390-ccw: enhance bootmap detection Cornelia Huck
` (3 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Cornelia Huck @ 2016-03-24 8:30 UTC (permalink / raw)
To: peter.maydell
Cc: qemu-devel, agraf, borntraeger, jfrei, Cornelia Huck,
Eugene (jno) Dvurechenski
From: "Eugene (jno) Dvurechenski" <jno@linux.vnet.ibm.com>
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>
---
pc-bios/s390-ccw/Makefile | 2 +-
pc-bios/s390-ccw/main.c | 8 +---
pc-bios/s390-ccw/virtio.c | 113 +++++++++++++++++++++++++++++++++-------------
pc-bios/s390-ccw/virtio.h | 32 +++++++++++++
4 files changed, 116 insertions(+), 39 deletions(-)
diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index 11c5dd4..4208cb4 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -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
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 69a02fe..1c9e079 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -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)
diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index 4ab4d47..1d34e8c 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;
}
}
diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h
index 57c71a2..3c6e915 100644
--- a/pc-bios/s390-ccw/virtio.h
+++ b/pc-bios/s390-ccw/virtio.h
@@ -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;
--
2.7.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PULL for-2.6 12/14] pc-bios/s390-ccw: enhance bootmap detection
2016-03-24 8:29 [Qemu-devel] [PULL for-2.6 00/14] s390-ccw bios patches Cornelia Huck
` (10 preceding siblings ...)
2016-03-24 8:30 ` [Qemu-devel] [PULL for-2.6 11/14] pc-bios/s390-ccw: enable virtio-scsi Cornelia Huck
@ 2016-03-24 8:30 ` Cornelia Huck
2016-03-24 8:30 ` [Qemu-devel] [PULL for-2.6 13/14] pc-bios/s390-ccw: disambiguation of "No zIPL magic" message Cornelia Huck
` (2 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Cornelia Huck @ 2016-03-24 8:30 UTC (permalink / raw)
To: peter.maydell
Cc: qemu-devel, agraf, borntraeger, jfrei, Cornelia Huck,
Eugene (jno) Dvurechenski
From: "Eugene (jno) Dvurechenski" <jno@linux.vnet.ibm.com>
Improve the algorithm that tries to guess the disk layout:
1. Use CD-ROMs to read ISO only
2. Make explicit paths for -scsi and -blk virtio
Acked-by: Maxim Samoylov <max7255@linux.vnet.ibm.com>
Signed-off-by: Eugene (jno) Dvurechenski <jno@linux.vnet.ibm.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
---
pc-bios/s390-ccw/bootmap.c | 111 +++++++++++++++++++++++++++++++--------------
1 file changed, 76 insertions(+), 35 deletions(-)
diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index 711a518..54e0f17 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -315,6 +315,40 @@ static void print_eckd_msg(void)
sclp_print(msg);
}
+static void ipl_eckd(void)
+{
+ ScsiMbr *mbr = (void *)sec;
+ LDL_VTOC *vlbl = (void *)sec;
+
+ print_eckd_msg();
+
+ /* Grab the MBR again */
+ memset(sec, FREE_SPACE_FILLER, sizeof(sec));
+ read_block(0, mbr, "Cannot read block 0 on DASD");
+
+ if (magic_match(mbr->magic, IPL1_MAGIC)) {
+ ipl_eckd_cdl(); /* no return */
+ }
+
+ /* LDL/CMS? */
+ memset(sec, FREE_SPACE_FILLER, sizeof(sec));
+ read_block(2, vlbl, "Cannot read block 2");
+
+ if (magic_match(vlbl->magic, CMS1_MAGIC)) {
+ ipl_eckd_ldl(ECKD_CMS); /* no return */
+ }
+ if (magic_match(vlbl->magic, LNX1_MAGIC)) {
+ ipl_eckd_ldl(ECKD_LDL); /* no return */
+ }
+
+ ipl_eckd_ldl(ECKD_LDL_UNLABELED); /* it still may return */
+ /*
+ * Ok, it is not a LDL by any means.
+ * It still might be a CDL with zero record keys for IPL1 and IPL2
+ */
+ ipl_eckd_cdl();
+}
+
/***********************************************************************
* IPL a SCSI disk
*/
@@ -412,7 +446,13 @@ static void ipl_scsi(void)
const int pte_len = sizeof(ScsiBlockPtr);
ScsiBlockPtr *prog_table_entry;
- /* The 0-th block (MBR) was already read into sec[] */
+ /* Grab the MBR */
+ memset(sec, FREE_SPACE_FILLER, sizeof(sec));
+ read_block(0, mbr, "Cannot read block 0");
+
+ if (!magic_match(mbr->magic, ZIPL_MAGIC)) {
+ return;
+ }
sclp_print("Using SCSI scheme.\n");
debug_print_int("MBR Version", mbr->version_id);
@@ -649,57 +689,58 @@ static void ipl_iso_el_torito(void)
}
/***********************************************************************
- * IPL starts here
+ * Bus specific IPL sequences
*/
-void zipl_load(void)
+static void zipl_load_vblk(void)
{
- ScsiMbr *mbr = (void *)sec;
- LDL_VTOC *vlbl = (void *)sec;
-
- /* Grab the MBR */
- memset(sec, FREE_SPACE_FILLER, sizeof(sec));
- read_block(0, mbr, "Cannot read block 0");
-
- dputs("checking magic\n");
-
- if (magic_match(mbr->magic, ZIPL_MAGIC)) {
- ipl_scsi(); /* no return */
- }
-
- /* Check if we can boot as ISO media */
if (virtio_guessed_disk_nature()) {
virtio_assume_iso9660();
}
ipl_iso_el_torito();
- /* We have failed to follow the SCSI scheme, so */
if (virtio_guessed_disk_nature()) {
sclp_print("Using guessed DASD geometry.\n");
virtio_assume_eckd();
}
- print_eckd_msg();
- if (magic_match(mbr->magic, IPL1_MAGIC)) {
- ipl_eckd_cdl(); /* no return */
+ ipl_eckd();
+}
+
+static void zipl_load_vscsi(void)
+{
+ if (virtio_get_block_size() == VIRTIO_ISO_BLOCK_SIZE) {
+ /* Is it an ISO image in non-CD drive? */
+ ipl_iso_el_torito();
}
- /* LDL/CMS? */
- memset(sec, FREE_SPACE_FILLER, sizeof(sec));
- read_block(2, vlbl, "Cannot read block 2");
+ sclp_print("Using guessed DASD geometry.\n");
+ virtio_assume_eckd();
+ ipl_eckd();
+}
- if (magic_match(vlbl->magic, CMS1_MAGIC)) {
- ipl_eckd_ldl(ECKD_CMS); /* no return */
- }
- if (magic_match(vlbl->magic, LNX1_MAGIC)) {
- ipl_eckd_ldl(ECKD_LDL); /* no return */
+/***********************************************************************
+ * IPL starts here
+ */
+
+void zipl_load(void)
+{
+ if (virtio_get_device()->is_cdrom) {
+ ipl_iso_el_torito();
+ panic("\n! Cannot IPL this ISO image !\n");
}
- ipl_eckd_ldl(ECKD_LDL_UNLABELED); /* it still may return */
- /*
- * Ok, it is not a LDL by any means.
- * It still might be a CDL with zero record keys for IPL1 and IPL2
- */
- ipl_eckd_cdl();
+ ipl_scsi();
+
+ switch (virtio_get_device_type()) {
+ case VIRTIO_ID_BLOCK:
+ zipl_load_vblk();
+ break;
+ case VIRTIO_ID_SCSI:
+ zipl_load_vscsi();
+ break;
+ default:
+ panic("\n! Unknown IPL device type !\n");
+ }
panic("\n* this can never happen *\n");
}
--
2.7.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PULL for-2.6 13/14] pc-bios/s390-ccw: disambiguation of "No zIPL magic" message
2016-03-24 8:29 [Qemu-devel] [PULL for-2.6 00/14] s390-ccw bios patches Cornelia Huck
` (11 preceding siblings ...)
2016-03-24 8:30 ` [Qemu-devel] [PULL for-2.6 12/14] pc-bios/s390-ccw: enhance bootmap detection Cornelia Huck
@ 2016-03-24 8:30 ` Cornelia Huck
2016-03-24 8:30 ` [Qemu-devel] [PULL for-2.6 14/14] s390-ccw.img: rebuild image Cornelia Huck
2016-03-24 16:56 ` [Qemu-devel] [PULL for-2.6 00/14] s390-ccw bios patches Peter Maydell
14 siblings, 0 replies; 16+ messages in thread
From: Cornelia Huck @ 2016-03-24 8:30 UTC (permalink / raw)
To: peter.maydell
Cc: qemu-devel, agraf, borntraeger, jfrei, Cornelia Huck,
Eugene (jno) Dvurechenski
From: "Eugene (jno) Dvurechenski" <jno@linux.vnet.ibm.com>
Don't indicate the same error message for different conditions.
Signed-off-by: Eugene (jno) Dvurechenski <jno@linux.vnet.ibm.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
---
pc-bios/s390-ccw/bootmap.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index 54e0f17..611102e 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -84,7 +84,7 @@ static const int max_bprs_entries = sizeof(_bprs) / sizeof(ExtEckdBlockPtr);
static inline void verify_boot_info(BootInfo *bip)
{
- IPL_assert(magic_match(bip->magic, ZIPL_MAGIC), "No zIPL magic");
+ IPL_assert(magic_match(bip->magic, ZIPL_MAGIC), "No zIPL sig in BootInfo");
IPL_assert(bip->version == BOOT_INFO_VERSION, "Wrong zIPL version");
IPL_assert(bip->bp_type == BOOT_INFO_BP_TYPE_IPL, "DASD is not for IPL");
IPL_assert(bip->dev_type == BOOT_INFO_DEV_TYPE_ECKD, "DASD is not ECKD");
@@ -416,7 +416,7 @@ static void zipl_run(ScsiBlockPtr *pte)
read_block(pte->blockno, tmp_sec, "Cannot read header");
header = (ComponentHeader *)tmp_sec;
- IPL_assert(magic_match(tmp_sec, ZIPL_MAGIC), "No zIPL magic");
+ IPL_assert(magic_match(tmp_sec, ZIPL_MAGIC), "No zIPL magic in header");
IPL_assert(header->type == ZIPL_COMP_HEADER_IPL, "Bad header type");
dputs("start loading images\n");
@@ -465,7 +465,7 @@ static void ipl_scsi(void)
read_block(mbr->blockptr.blockno, sec,
"Error reading Program Table");
- IPL_assert(magic_match(sec, ZIPL_MAGIC), "No zIPL magic");
+ IPL_assert(magic_match(sec, ZIPL_MAGIC), "No zIPL magic in PT");
ns_end = sec + virtio_get_block_size();
for (ns = (sec + pte_len); (ns + pte_len) < ns_end; ns += pte_len) {
--
2.7.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PULL for-2.6 14/14] s390-ccw.img: rebuild image
2016-03-24 8:29 [Qemu-devel] [PULL for-2.6 00/14] s390-ccw bios patches Cornelia Huck
` (12 preceding siblings ...)
2016-03-24 8:30 ` [Qemu-devel] [PULL for-2.6 13/14] pc-bios/s390-ccw: disambiguation of "No zIPL magic" message Cornelia Huck
@ 2016-03-24 8:30 ` Cornelia Huck
2016-03-24 16:56 ` [Qemu-devel] [PULL for-2.6 00/14] s390-ccw bios patches Peter Maydell
14 siblings, 0 replies; 16+ messages in thread
From: Cornelia Huck @ 2016-03-24 8:30 UTC (permalink / raw)
To: peter.maydell; +Cc: Cornelia Huck, borntraeger, jfrei, qemu-devel, agraf
Contains the following changes:
pc-bios/s390-ccw: add more disk layout checks
pc-bios/s390-ccw: virtio_panic -> panic
pc-bios/s390-ccw: add utility functions and "export" some others
pc-bios/s390-ccw: qemuize types
pc-bios/s390-ccw: update virtio implementation to allow up to 3 vrings
pc-bios/s390-ccw: add vdev object to store all device details
pc-bios/s390-ccw: make provisions for different backends
pc-bios/s390-ccw: add simplified virtio call
pc-bios/s390-ccw: add scsi definitions
pc-bios/s390-ccw: add virtio-scsi implementation
pc-bios/s390-ccw: enable virtio-scsi
pc-bios/s390-ccw: enhance bootmap detection
pc-bios/s390-ccw: disambiguation of "No zIPL magic" message
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
---
pc-bios/s390-ccw.img | Bin 17760 -> 26424 bytes
1 file changed, 0 insertions(+), 0 deletions(-)
diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img
index bd8f21050fd7c396eb0e37213d284fe557caa01e..d3978ba0506cb24050f596b2e4e710dec3486fba 100644
GIT binary patch
literal 26424
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
KTT!>i)BgikNb&su
literal 17760
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
Zv+%j)j}^Z>m-6_k%|Ukxkh>N={TG%vUitt4
--
2.7.4
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Qemu-devel] [PULL for-2.6 00/14] s390-ccw bios patches
2016-03-24 8:29 [Qemu-devel] [PULL for-2.6 00/14] s390-ccw bios patches Cornelia Huck
` (13 preceding siblings ...)
2016-03-24 8:30 ` [Qemu-devel] [PULL for-2.6 14/14] s390-ccw.img: rebuild image Cornelia Huck
@ 2016-03-24 16:56 ` Peter Maydell
14 siblings, 0 replies; 16+ messages in thread
From: Peter Maydell @ 2016-03-24 16:56 UTC (permalink / raw)
To: Cornelia Huck
Cc: Christian Borntraeger, Jens Freimann, QEMU Developers,
Alexander Graf
On 24 March 2016 at 08:29, Cornelia Huck <cornelia.huck@de.ibm.com> wrote:
> The following changes since commit 2538039f2c26d66053426fb547e4f25e669baf62:
>
> Merge remote-tracking branch 'remotes/armbru/tags/pull-ivshmem-2016-03-18' into staging (2016-03-23 12:57:44 +0000)
>
> are available in the git repository at:
>
> git://github.com/cohuck/qemu tags/s390x-20160324
>
> for you to fetch changes up to ce11b0622268dc8133bb4954c1e3fae0c23b6609:
>
> s390-ccw.img: rebuild image (2016-03-23 16:13:38 +0100)
>
> ----------------------------------------------------------------
> Support for booting from virtio-scsi devices in the s390-ccw bios.
>
Applied, thanks.
-- PMM
^ permalink raw reply [flat|nested] 16+ messages in thread