All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PULL for-2.6 00/14] s390-ccw bios patches
@ 2016-03-24  8:29 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
                   ` (14 more replies)
  0 siblings, 15 replies; 16+ messages in thread
From: Cornelia Huck @ 2016-03-24  8:29 UTC (permalink / raw)
  To: peter.maydell; +Cc: Cornelia Huck, borntraeger, jfrei, qemu-devel, agraf

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.

----------------------------------------------------------------

Cornelia Huck (1):
  s390-ccw.img: rebuild image

Eugene (jno) Dvurechenski (13):
  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

 pc-bios/s390-ccw.img           | Bin 17760 -> 26424 bytes
 pc-bios/s390-ccw/Makefile      |   2 +-
 pc-bios/s390-ccw/bootmap.c     | 129 +++++++----
 pc-bios/s390-ccw/bootmap.h     |   9 -
 pc-bios/s390-ccw/main.c        |  25 +--
 pc-bios/s390-ccw/s390-ccw.h    |  54 ++++-
 pc-bios/s390-ccw/scsi.h        | 184 ++++++++++++++++
 pc-bios/s390-ccw/virtio-scsi.c | 342 +++++++++++++++++++++++++++++
 pc-bios/s390-ccw/virtio-scsi.h |  72 +++++++
 pc-bios/s390-ccw/virtio.c      | 479 +++++++++++++++++++++++++++--------------
 pc-bios/s390-ccw/virtio.h      | 218 +++++++++++++------
 11 files changed, 1220 insertions(+), 294 deletions(-)
 create mode 100644 pc-bios/s390-ccw/scsi.h
 create mode 100644 pc-bios/s390-ccw/virtio-scsi.c
 create mode 100644 pc-bios/s390-ccw/virtio-scsi.h

-- 
2.7.4

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [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
zcmeHwdw5jkwfCA!k|7CUCxkEw2s<%qK#UVWjHq=c7Yr9+LxK)%Pf17uNe#)E3>2-^
zsMMmTwIK!Ttu<9)Q>=EN)&p83{YqPJ)rg{aT9J0N<uvwlQlp|m_V-(B?>(7>cut?^
zJAXRQGxNUteb>A0YrVHkxVdu40;khK@sEpgP`4VA?y=haX1Qjclzu9uapb2g%EWUr
zzDZ_3+RV?W(s9ykwoCHh*@ds$Y<HH9UD5=zJzg?j{I%&>-J^@@qh^a;D*VXfm{)vO
zn+3IvDqYMMk@HZ*?2vIz)c=QZmbz@Uk;uog+45DH_?)9kDm2^UrMn^gt~NYw;V!d(
zbm_R!Y`06|am&$`Vz&RwzY4~!0JO#D=jr7P`5YIvG_Sd^rD5LO;*PfB5~0U9vhj6Y
zxpXD%&I+AV`BF|z->LPh9t>=G{H;4KzC)nQAGSSzY<}%$i;w@wzUE;3T6Q6}k^Ny@
z{4DnNI21}!{ol3P*l&_6#z*dZ??`3Yjos0wrv|TkQ&C?qB|zs`A0RaSg505m{#<y6
z)t+R=h1m&;lwnret$umRM!V_Ht~rqeJf3(vjewt-6~~`!#Si7t>c)n;a2>5)y{4mM
zbw{|aJ&dN-2C8ps?bxusadk(1OK5d-YnVcHt<CionUL42q?@J9Z%7^4Zqo^sj%at;
zV4<oJ?T#Mn@j6=`6TfRt*zCBj*8;HHJ^c^Hs;IEHk7(+3`e#N_@4H0fxAj5=mmi2m
zP`J5e(#QHi!_YU=-2U@Pp>*%1HEJL2m`BtLN*Dd=4wW*4N`!Xg7@y>1X{hbbra1vM
z_6U!rpJf$b?4?09Li{}O0shUpMOw?ao<6Zx1qWvd^lAMb3vXATC-w;A)l136xU(<0
z!$+Ap6NQ4CX6lz1hK%_paD|Om^!vzB)73}%R&wd@81FFFDMuJ${0gbRBK0L)pY|6S
z`8#R<jkNov{({u!3rwHDJdu*p8zcJm+}>K~r6d|cQK%0Z^{gkFv3IXR{RDt>?smqK
zrFNn8WJVRoK4_Pr&OMysfIg+}9Uigmv^^qaC<PxxilY<Y_Qy5q8ST>Fe{-x9JbY%<
z?swB+d^_}g&{`MK+z<6FhOy&ua(Jigz}yj3yU1I$<2<6Ae2wc_d*}Ai-U9M(@zYd&
zDKxd2GW4Zl-_)&+z9c<Nnfg=Y(03Zg^&+CEe?TEOELs4nN6DQs$Xdx-&-OF^k@XF|
zf;>^BFPXOHPKFiU!5GJxV^})q5xSWBNKjQsM+|5x?b8(cRmxER`>~KI593b%X79U(
zVN~mbNJ;XEDv0eIw#l}i98M!rDP@2=`rnQ<CFo%?y(J@GW;)xxdpM0%->U%EUwG_U
z|E2Yj2NcDt)2sAca@>~b@(5Qe86xkWQ3Ye%{cjI=An8E=&tsYyAJbMr%MY=}nZwMD
zc-kwq%d4oz*<XM;czo2~L$tL&3-$CJtBqK;c85mkd6oO8Qg;8P0zrL5o&9qdBC7Vd
zsms!ohm`&4G*Lg_FhDZ~eS0WBWw5_3=CkOZrGNH+Pxf{a-5(4120T%<(~@JtarS=4
z_gIR&9Y<UP$Y8K(w#aie^O*Lk)bEq}A4C)NqNgjj(?B}LekGv9K8`A}2o(k>)*GeR
zE@*WIy%{KoQB;k=i}hwlQD7~el-kMErB5R##<_*&gHg2>I*UeXz2rVz9D5Uf9s)0q
zVq`D4_kriT^;|!7@Ai>?DLiYkaVp@C^)glc67n2YV$X&ss`-h!`gdUVOOL`()LFhe
z_H0>?LgnwGJgzwO#TYvUlrJ_;2-a&^q6xK<NhF8l9upbAg52|_)UIY}r@qJ14)sB2
z%%^a*-$|U6?&>`b?w0BI!e@`idcduQ=PUGuMEXz3I2hGZ5f24IIhUxv0^E%U&q|=8
zlc1*_atHqGr|r9s6X4RoodevR6dG>ih}#6FFzVCbPmC3Q^A+KGJbRFSp~T%x=pLA&
zsxr)<o0eNVUS{?Jw<5Jd_FMQzuC7x`oYGR@TZr#gP~FK==LVTh>Jh0&r2evKqfxZ6
z@V}uMHl76yzdj?=6UeM3_JaNSl#fXF1!`;61RvOJ5PZR5`&;fbp>w~`{I1lu3(fO|
z<^*^Od_?N!=$~bJqJG4^TfCg}3b^*3W(qQLlVFi}OKle{9v*r6JxJIquzwS{27$X+
z>R;pf6l5sC9n}Yigu3@t>C*%*RqBfb?zq4m0$jbBXNKc#YBOTJ6fvN%r`<OXwsY{v
z@!#TTqaybF`_4zMLzd@g>Ft4^-N5?iIdSSH)UJaL3BHn4zPyJ5fso_CazA@Xs^ujg
zZFh7fLv!Ph14=~;Cka}JDqV<!l}cZ_UT6$vWnx5`g-I=UL@2O4lybnKQLmrq-oK-F
zj)m`oXoxw9s{Si!nq=oA`*Wy(`M>w|IR9q}{{i^TE?5Fm-23cyhsqhFnx9Hu5iRvt
zd9W?UJPqhu$dPxeVA{htZEWcu3AQ9}5o~fNkMzncKJGrL|AI9(Zky<Orsz6DAU8-a
ztcl)lOMQ>jZx+Z&40-C41P;F;9EOcO+nvY)g~nssS1Qvm*Zg$*Ze=>k9S7$q$VbLc
zSoimaSohJ0Sf!TeN5Md+n$L6NkFG&XUxD7e@H<Gq9aA9W&J_!~p+$H$kJ5ExKy<NK
zc>DH9U0{6n{&6%}pJBWc$m~RPD72lR!Lacb+TP{ogVn52<A^@R_#12OM>!JP(^zj}
z6G)yOWE+`zdh)F-zsC@IUy}MKT+jQy=%Rz|&v>R>29NZXFZaQpy2$h=;~}yCdB#WJ
zY>LS3Hsz>NBhD&cBw0ho(|oZ*(MZHY)3iwJ3EQvlc|LB*%mi*O6%O_ZH`ArQSGcJX
zZf5Z;)cKgHL)L5Oe{jC<JQVc%AJT(l&h7pXX<8>~@Me7%RuP>%i$uFvzu@!9{du$p
zzP*{&N7V@YU8p~#PxG)vejL>zPI9l(!0Bd3J=PwJKn>YBFAEviN#nKbE(*@=q$#sC
z{BCtdaxv-w{c%bG{Fks^Bz-qBy7)Lor(*OzM3};3&5W!q2Y)3hzJ9E5fZN^w1osA~
zbP;0DqaQLJXPI+;De}+e`sANUeHPbq{}1cpvz<|mJt;Uv<IHYL6*hjzR1@j3^&XhW
z+K%RjfR-_(T{EonoLjghWk~4UDfN>==Pses4q2GTEa9=Fld|SO;>T>=1v8=Lu(1YI
zzubS0z|0PjJ|CIcL!_Y&KB2$hY*@qz*!d?ZuSCNW@Pv(9^xcLbV<(A*1eQ6z|EZB2
zrw%1>EW3r29l~*maQvWfe35XRt3QspEo@W=mDnL(iF!-6U=@cIyeCKI>dA||dv-iY
zv?W4L8QlrU-qDbd`w7bFFCia|2ZxKXcJfg=!>8^W=4Fzs=2KP+FLMRkDz1CqXI?&i
zHHtdsS6+R&_jh6iv6)i#PeyL!-s3xp$$`v|OxHVz=c7?y1Rfbggh9Wl<jyOfayG0x
z4?a6L>VsOkxJBcB@hdIgPnbiFF~yvxg?b+J4UY@@w5iC9%Mf|Mll3%m!VUUUDH7*7
zPebxFfp!7rHd)Wc*L%4ooPqBC6tj>Yv`ehaG-?&aHoE(SXydH}ZO95E`Ka*oJohFa
z7Hu?%yt4nf8~Y;2+ASD<uaAZISAus>0^SP+*Utp+PN~aE!+V+FQlmbOg{bPgn7X`K
z`h~Ja4DpKU?w!2e7o8Mp3Zi;H@>z)Jrl-s?{ZHeJVLWUNoki;-rLY8ZR}RS^Vrn<-
z)N@s=ACXnhhfibuh@P3u`%U)>mtO;yVcN;NAb83B{r3{qX@OO?-vjy_!I;Mw%~hAf
zr9b1quGV-3x<zb7JC!8N-q6;#b-A~~Lu3V=E%Bc$@t;#JGE4kVmiYf<C-}$Ms!pFX
z+S!LB$Pj6B%>97;rti<ETd{Kbca|d?(F|*(i3XQRJ&Eg+?`Q5lx!J@P_4`t&3#-2h
z$fN}>2`MuF&md0#nSc9kjaLyBR@Rp+aZ}Fc>Sr8N8TS%f(P$SQmT*hbb6lVFuGD`c
zJggEPE{89EP2ftU@0S91K<YmixJrSW0k}nMg@E7hKsk>gJpWhhP-bbgM}ZuiiFrRM
z{ZH*(K{NMzX$?kSAUO$o*RT)b-qaW1B}R7EB(Gj!eBH#cofJ1X$9@Ib@dL(gw3)e3
zxR?#fx60T*n|d~Cfmu9!;!$o-S}FXCU6Ph@JqI!y#>wXZ_ju43d%}!V&Xt%WpU}U8
zRRG6sA^hkU{Zqs*O}{={8TRYVLp!iLb+aEI$i!@6dCSBf3(YA)bA{9=3C%}^=Jzc>
zmpLPP4*NOs4t9H-cTPTl{jBUa5%U`4+N&4K?tESM6|qOUi(@;wQ)4^3DW;<xD{e=g
zP$}(&+im+R({jHpEs~4fZ${O=WzfE86l-)pMiis`CwTn?trLKCM|ReZDda0tVvk@&
z@CdK-aptm1aP5~hhX&s~m$7d953FR9qXAUA$}2P~3-pk9;Kjzr;7R7n>`!Fm1MC%2
z`yr3a{y^&3mr#=M+Qo6Z?R%qh4mglC&Ni`?X9Ihz8G~6ShLB);Nw9sL>p8?){rDaI
z8PU^?oG~XB2C;)*rSyg3qhFH|%VqQnQeVvVNq?5nzuoTW3&&xfk^V~s_SaIsNMJDz
zlzzUQ`Zgf;Hlo~!@@p9TjriCefj>*e_DX%SjD1YTZjJW!eap-*DHrD+j*t4bKssgA
z<6L*0l2P3<Y9rUT&5=6tG1kQc*e$5=o1YKB;Mg-oa2B)sh^sFY;T6CKf=3fPN9F8n
z(D-KeY}j|uP^51fW~vih%c>Hn-%9IhsUPI}q?JPL5{&2;IGImfdju{ZaE}Tc>d?tK
zfV-i)geeTYZJn0@OLiT+IM~}m^n-h3%vSaa)8@lj95#2bH~ipshDqUbJj>>p;!7@(
zKU-GBF0uclWTyJj-`Un##YbE{UsZU;D7iZGZK3p4;Z*XGOZNZS@5z|HXkSmWX@TU8
z!xqRqB%=Z{>U^o2_J2i2{c=0?tbwiX<^CTuNZZH4^DK$cQ8Onba!Rl4gHo~*B$6EG
z8ZUGtK3pkM|B>Llg(b@N1^eK=eTXevrVY%I^Pd7)DE0TGj;segtOYFcqb0vs(fKFo
zR|WQUskaEM#t|Lpi}mn~JV|8iera@6_a#QP%<dC21k)Z!dx6ws{-5ZP`cAY$XIKgE
zfM0sqFJ;Fld-=@C0wepsiFZr=E?W-p?t$lAW9_@+=g`>)B#H-k_kH->*iUel1o@MG
z>~-oh4P&K>Tw6%XA<1u|IO)adOD4`HvgKUG*B_xPD0TnsGz0rCBih6LSnWLu9?P&}
zn~Cot%*jry%y}1)is!}sbIC#D@$AC-(nE96=F(G<6G?HPetuQ~D2I(c*!7@w4w8l0
zT)_#`Gr+qCFnd`C-75SLRQ2<WQ-J*m!?O2x=Zf4}fEmmCCF6Cch>WL(eMPx}TO1#=
zwk9r;`he8G!@B<PTG7!Gct45vOE%p4&KS`pzPR-b!T(|ceiP^K1*iDD<JVHZM(|%M
z_-Al#*}6YYrC3hz6>v0t6-&Dr=fpF}#UoB(HHZ^7mvxfy-~i4hQwAj#xc7%~ILT_K
z-#-J+Ay{r>3h;`T`RVkZP}@G*KPLVXo>9y4xWWgg=hq@Kzr%abt&J=_v^*nml?b|`
z;jLGT1{M!%V8U~v)dehd)-kEe`G3~yOndODV5Cb<>nEIID{h^)Dk2hpRVZJI8Q2N=
zFG1-62iQlz)t2bRvU`0~G?^tha|9meRM1WrYjsAx^yXV<3J=CkKvSk|5mBK0ErH4q
zsEkoiEcJDeA&gZqU_W|Pus5+(@X$fyx6;}pGD)Tyyc(^t>dV^5u=EmU3J)?yn675I
zx}HBcy(=4%)Z;Xo&y#&<Gv}^fCg=+D55`6W?`Em*mbza!E?fm&**R!}<UNw}pR5}N
zR^mSk84uD)E^++_%h>fmpa42%ir>N7Enh!Gfg>q><Wqo4b`*oRf%}C*DPJ(PNnNx}
z&0Nnkq`e++LNP-ui4#`zWt}U1vi{5LXX+okY)T2}?{S~=W7Pglbe4>otaCCB$f)@V
z80HG4=LN&#faCih4N))^=L}O>lE`^}AG`yrxuB{M>Zz#vHJ{?eHyz(>e3iW_<>TJP
zx5a0UD)O4v<(rIXAKzo}>L}|&IZN710r+xOKv5jtk}0#X3g+4UQ@sjzHC{^2E6<zA
zJpBCce!oWD*wc6CX{jjF{EFtmp8gO`koB7%FmIPTR4Q}$&CEW}_%x{C21unz;6~k|
zn%tcCitvDwBM8JE$=II;tqhzXBm=8Z@ssAUDM1r&MPso|=9zicj}Vvi#_Cv4tS5jy
z5$>5T^6@>Bf?fYqKIt(|Zl~B!;dv8fFWVIbPP%o!i!%H3C2!+~DH<Et1nNV25i;qZ
zakBqWzJJk|J9x+AjYd?=Fwq_uHz%s#glMZi4w?Tu$mBR*z-bFIc@?S2en$jysPJcu
zaO3XfX~J$WdMPBsNj$fhy*NuiyH>7vyp@UVJFXlu%szj)k{(o4H+q2$^Gv|J0q|%0
z5SxNKQ*bjiPnA!};C%!<AcIHgdDv5Mxttu}KP{><|5b|W<Q_jtkq`2k_jzpp%+tJX
z+M5)^32dJS5}4;c1(Z(d@Q4*0wdbYCKKFJC@aaxa>EXP0ANHSsN3F2Gow9I;5`v;U
zxem-$6K^A`!0AJnS~<dcRMh4L6+|t@1L6^50J3TQD=8Uz(t13&(Nl3d2kI)cyh_!0
zhf}I?S%mW>Rde$h8(^Rn&8K?cmxMbGJn`+H-|tJ$+lyJ$0UQ2WWEmv|=IAP>E!-9`
zx5xnP@Y)%|6>c!#y)NJ{f~9?0DJ+I~BKK{DNlX=YVk{B!V!=Ppb#ny*N%*GnIQ(dk
zxjC~nzR!a9K-*sPL{Q&l7_b_>krvw(+l8Io6W-Lo(=pmRH^P2QTX3wed;H|5*x|ji
zr7eOJoT+8-cFiAq1YUolyEFE<KHu2q*J2N0HyOFRGxnHwKF-i~1uB4Pj-N3}2H<ly
z@&r{C>l@4sU-Qle-)Do@psejnnS10Jxca#YP6gq*=i<gtnL}NCQ*7RQvcD+*Nbna#
z?r49(O(uITd}UbI@Hg3K_CL(_4k~_6)aS?8pyp54-^5L%o1O@~g?xdT7SRT8VEbbK
zHUT{cqCSvyBZqi`8ty2n5SxD_C8q{`Ga<uDd}U`aRJhd<nSiWi&VE~iYEKc%diq3W
z0ptW%cd9fUoWvxu3PfJWdConM6Lx1gS?+VXOu4N&H_e)Jll3AeJTbF@vjw>{jNz7U
z%B(^w`-TH$lX<T$cv?OWkLL_Lo<uzEQFyADhKXM(;=U1hFB1MX)1>YRnPoxdq}a`~
z<7BK`^YmgTXR>J+T~elImZuC^Pz}N}Lxzoipf}&_wN?~4dNK0<X52i&%dMUwg?Oxt
zE24C}l_r@rbKS&p7sf{Lr&#=@FfNXjlp%20VAi6(%qpCGg6lg}pVceplCnOBKU4|E
z-^143QDSdI?O}YM&@*I3Gz%r?3OV7O@G9Fomd)857B4dG-2b4tbHyk=KjIS{nXd~U
z;F&ii_e@CU6n7ZAqJ5a0fQ{<=-(t^2+t1Jj|71GGcd=IIwfTxW6&i;-_pOM?U5GtJ
zUxiy2>|SvDfE#XxJteC=qr+Q<^Qgt>o6r6FDu)Yts1S(XVzkbu-)MDmue3hJzo*X+
zs(s?ir*4&165ECI%qR&Fi@MzKk80Pw4kIrMx$!Z^&u2fz3TvHfpa0Z?;;Z;RgfC7Y
z0dZFURfLmoJ=ZXD3!&jO^yHgyWX4d+AZLs8=b#%E?;pI5i2YAKb;I85RY=9Lc@@Us
zZU@-%^nAkUJdNk4q4%MM3(z+OCv(i#Ym8}vtnA;v2+!{i=bMcEoE6v$&OU^-WHzD>
zemTO!GOP%l#9Cp$vfic`iYl3YWGJ53I`K=SVr(i~*MwkL<T~bP=QS#fUBG)jtWc(d
zhquHJ<$Vv%dl|O~9}Fw&>a)MaD_h~_BHR*kc1_-n_!x@<_$bH8m>HMzFzXaqai&U~
z;dU21A=`pXr^VT=SfBE{83kCWq?>%QbcuZ9c@p^is}<wOPgH{EV<>q~^Ped5QNAv6
zB)sneYgEIF!i2Rk>RU4l`rqg5$Z{u8k~Z_%Tz_WBdn;$-mW$&MI_Dk9S(fgVBQA|Z
z8yqjpH{MT?-*m~BG_s{!%`6+)V)`Sm0>>X^YZv_CU!ZfvNE|Hr$QIBkAK7C0{Rn-W
z))C2Nh~&9<`e~d{zYCIAjNl;G%3~hh<Cz*u8AARFVGR;*!P<~-8_$*=-`G8v!Hm2z
zSmp)Hs|RC2a~(duj(5KWE7;34H8M-MsMlvWFf$+*^LrlH>2sVET#Yl7clb8Gpc=VC
z=JU@Ei$zn9I3gu|vX3mdfa8QU!Zx(x_MmxIf;Bf=kl(4<Ovxy*r!?LJEU%ybF8&g~
z7aE_-S-9IBdsz5$3UBN;J2(?LKEsL~cdmOX@Qz%OaF+t^<{-}yvY^S^W~`k-k9+g~
zVp4UyDpWU<oE?pqtniOgzRLx-vV+Qx0#AWRS<8O<S)E9D?BKEp>4zL?ya(U^Fz(k$
zZ^9{42<xFvWZyx$8Fys6c-0%*=~rS;dP{c9<CP<B^|pc!4^D9M6vF-pt2bo#Ld@f(
zxCMC<?@`I>Jb*P*6gw&0UHW5@DmC`x#2R=IR{Drf<dHyu&y9PzLhJx4IYM#XQwTp%
zv1_Oz!b%jhFxu_+t4?X>l`B^0Dz~d<J8K8jv8rVIfCCS{?w~(1%j8g7q=+u_>!5>)
z@TV&1QeiE8dQ7y?CTCF|{ZX8<f1MnwYN3-y=oZGNdlmA7YkYT_x8MHS*c13Zf_pI8
zQRmMCR-Of~1Xj0T{RP|7Xk-he;QSAF19JYC-XL{3|4WtgzxUR{LzctlE=c9XUIUs`
z71*s%tUHdaXWK1*v*7-=;Fi5^%9Voe5W}WphYdQ<a6Pq#>+h8Ucb4!l$CgZB<oquk
zr^0~WDe$see@`{FAktSDw{eg9EU1?R{IQ354(1V`Rx*9_yb^hgacpMDbexo+ev{zK
z=6e6hVLw&xvZABLj1DU2xhKEE#+3XQ8NFICrAb}xf5*xFZ~v=+R`yiIp<fV)DuH%N
zy^QPQaAO3zzmj&D{Z7u~x+*tyt}1he$BoSiUY&DK+NUz&;W2ui5xgSR=`{8d^BqL>
z*Vx(Qcas{w$;2HqM<a5qI>pN3v&<}RJZG<QVTs?c-?C4`!le1d%9u}vN|=x2HB9Z}
zw}q!!QkPSxac#mM-lRPJA-oY@g7s$=uZ*#B^<`GbYT2LJ1pGhXJj3}ub+Ffmz5f9{
zSK<BH*@?XBUN>=|z~f3#I+@<jcj3v2r{uk>$(OL>5A*wKh1friwbPI9@jsLN_89N;
zd0tPe!w%PRODVK82h^YHCdAUykQ{fuQBqxaLy)iz8o$Hiz}`=Fd-Jzomy7q2Jy_9P
zfmw9XjwH-?`8?n8S_!$riy7O4cXn<eXOw!dAeNg|tUSu|eN>j;Gf~cMuQWb|+>XxQ
zf^y4fxw{QtD!yqLxstsI<yw>q&orp#pq|G&;<DMAZP!oxStji5cbrdtYb{YgML1;!
zAJBIMbQ~!ED)P(wyexm}f3YW|dG*hRux{sjNSv1R$}IMfSXyS2>HT<T@~F!1UpqQm
z_!I>1ETmzri8m=Rf?|C*1*pc!L^^WYgz|64j+S*Q9^}UI@`~8eXb;}wEiCgZ;}Bt~
zn0Yek*N|W}XZO_Skgtzp^l~1J_b?Ue1T7u3&^vuM-jvJ$o~?j7L51Z>F};lZDdnqB
zYJQJCUFNWpW=6%%uJGXZBRta4nG4(89wmP|e4Xjs4-6-%u!j1)@Ju5cYcJwEyCW=R
z>JOvp04&9GR#d~gxNI|C(_Ic;dEJ_Ui0i~o`R0Kt=y;GZda|L-hk3O7kL>jy1u<qf
zFy>${e;gK_$-8;@lI#{fS_tnr8O@IX9B>?;gRJ>!%Naw;tL8bFg<sBR-4VfhK^*J7
z)GJu;1=jm5tkX=aU5Qv3-=jSCzrJ4%eS^yfO^rsoSQ|J8xjB0rawlf9eym<7z5I@t
z9u4(j^;!PIn9ead?O0i-mTZnH>(Y{<A%6y}9pW+N--+pmNlVAC*a>}JM9B{s6Gn}<
zpn#LHVe}*m&hO8qE<j}WZxdVl1zQDR{MuRNGf=A9R7hB9S}MUxVdFy9(zss8aslh!
zeKu<2uzr$t3a^<k?lpXWf$su*FT(dBSkliY6tCcnBU(GKgd{r-@tGCxJ{DuHkZk-h
z&wpWgFH(Vx+u+TxF(77|b>1-zHA~#s^ps#<eiI-b!FM~px8b`NyPEIm&6LWzKlv?q
zeGe7BF)sFG>`C;@K-QXr@<*75pG6;hUh9nQ<DF1<5$5Zz*a6^Jj9p-FK$8)NvBt<k
zgzbV~dii88_9Ds_lt)pzQ2q%eX5rX-T3_r0yvcFXYi9H!vK=?wgA-Q7rD(30c`~lW
zE(r05+vGIJn+(t5H{v`3QNR$VKjI7nU$13745+M!VYxY9c>XMOdi2juKWouK{=D%R
zzax$e6O;Qf=mKxsIBwFhvf_*q$`9gAZ!LxymgUB(_A<zt$9Gn+!3n(WNr5?d7ocmP
z6z@WSXJjJID?ZK}oS$!+jgb*5^mm4wfQZ1JnrJs|zyrEi_xRNiPQ;xa*c`Mp-vG`_
zk;kz6!@I79SfR|(;0>l82l%w6MN<c~?w$cpw{svh+Jm@eEkm0F4alr6V5rf9P7g-a
z>N9{B=K+!xFJWzY9u!+4Q^4Nothu2BQKbhNF)I^i{+#2&&N7Mf&A9XP@(j|SiQjZ^
zbpkRe@aFNb^$CtP*V4n221*rz?mYoz;4<V>NO)Ko@My4w4;L2w4G9smcED3si?`G(
zQ2OzHD!<{*Z>gVWoRE=XanD-jYA^$Q&XC$T;d`N2*#*sl0$Ln5Iu1_v;jG8;3C_)3
zSnc3V4`-viDe2|2TNQf)C+8@~HwSsfF}07kqC9-^tmn{FX%P?2^G4M@OKGe37JjR4
zQWoB6oB>aV-GsKR`2JRjHTqP2p>Yy(WEoTNgSzpi2?uU>U=2BkWx{$KccjsYJ-80j
zl#m;5b-MT+uBn}GB(c>GPai0S%{gPMdl2E`feW#pX(qxOqmFNRS=Lkh-uw9+=_p0|
z4}WEOkfKQ}Xo<1#CD@t0t5Zd$jMl2idIzt-+G(@n$}G<9o|;a~A9wN0;Rv!+j<=Y~
z2VdrTO25==xbFTt*Z=yGeh0LKw;lQE!_|=aR;hh?Kfk4Q$ap}`l?RQFO_^{~L-5Tx
zy!HZ@?7tfOuU{ERgTMOWl@;*i7I>w`IY2LRVD~jpgT7jfaq@l;Fbx<BZ|%;)zuV|!
z&*m7qQGu5uHq5*PZHOnQ>_%;I!1QE!*Wq+9s&tBGIukV`St8|5=KixNd>tzz$m#gz
zyERH*wyc)Jjv2V4fVZMWK}!<!HGTVXtQ^D0e!1A2lu~72c~9nn5>00J<PYHS6HIT%
zzwSsfce(V*uotJ`4FkjY=c63AdJ)b|l|9%U?`hyH1)Eyl2pxGjdZ9a0H!4aebTrqL
zEp`$<q4b~4^FOrZg!i*%k+Coe+J^QN);Khm9Z->j)PW+&LCD{t<x<fyXBD69$bXDX
zCi$RSiG9L;#}-eP_q<N+H)AWR_(X@kGj(X5kp=WzM}vNFs4I{efq&r!ge?tw?+MB3
zgEMn-P=U>rJq=O+Ke4CnZ~JEx@#+KA=qI9?X+n96)V*AHJ<j!ayRlOLDQtj$Z8bC(
ztMT5NT3D$S(GecniM}UC<)oOIlahafoP?LR;n(i}{hX96^Y6eRSVeNuz(H{KZh48{
zVS5F*HB9ScexD%ne3j)Hko(`{bEN)=w9l9Nk0HxvGB=nvM3QZQ|0lrw7QE4em7}yt
z1{pm4HqT}$DXIA?Ep1abHn)eH+th}}jm`Cq>e{vq_?MK@Uf0sxpf1#w*j){c;l}!K
zBYGFqHMcZ2sNpuXrLC?(T~@8GZEstzHr2H^s13~>*QUZW@^SGm=rES{#_)#r)($m4
zmCEZ{Tie2D!QdwRG`17n02ram6?J{xy5@Sdxz+A2i$kj6>qCtKZ4&QjT(`clHLR``
zo`|k#Z);trqNV+Mbz@!2hDMg9GFVw|wwWVMU=~1lDAQI{t94=3x9Q8HKG^n@%$_s%
zqInmWUQ)NFzM*k#qVzI&Vf8X~V_OUU;VBf=QQzJi3b#R?VI2unWs6$V*4_+?YuX@s
zJ^le}OWV59P|c9LQSE@5+uBthbKbF`Ib64<rO_N_iX}Eu+geqSzTlF1^L*<1#)jrP
zD0VbH<}K6?tWZV*a}~|)LgIQg+};R!;r0#nFis<Up{=D3-q1QGrUrW$QJiwT4fsRh
zCbgw`eREiC+*IG#*wEMjj+g}z*^;gK29RlNZ(iHX-DCCEw{2)?P}xD&B!Z5XZ5U~O
zg1;te*L3Dl{&rQ_iV^--#^$)HE~HkA=}3G*OlEu38u(s)(}vb-)io_`_1CH$5COYR
z_8I((<8X8922q*mO4gwIwuVM)&<I>BTd!?x`$ns3`ibSH;?cuYD$5sFsC5ku?NokM
zH7%)FLaeY3SVg6)mo2HTTygnVi2e<_O^hRxHy``-y7sy?md;z(wiOd?Xl<!m)5swU
zY{jYUR}y6%&FeVESOp6KX~m9oSrl>M8>p^On>)lFYvGj~ripFLE$bf<h~97$K<nD;
zn}{QJSYJ%WBnii3N!r!|woxtV;51O**4|KzwcL_XGJ)1?tDD2qL{~DLB{)zR8IUJ{
z7XJ&hM}UL-)(b@IRuW``jK%TDQHk2W+DrgTSk1$%&Zc)?e-&Hmg{{a$NTz01gXmVi
z5UZGCjS17y*lzVE(y}cL!PyY>+#5{eOo-X^o7et=o>!0j4ZkZpnvoYp%8vS`Mr5m^
z1oO<~&x~2BWNQl*q&4lyL25?ts93T%v2a(HS1*KPGj8}8vi>!J6-yT`y>dRV+J2Ad
zQ(Nk;Z`%;IeR`H!*MWbv&&=6gUPA1lT6-HDdA(Z0>5r(gy&e9=!Ni~=J8gfC&l*|{
zRjv<(uO9_x>R{c5#*Plef_U+|#<um1m@7<<Z8ll-L|=g1sWVMw)YrADt&Lz6(_JXk
z*s9Ki(<Xir|6YfqQ+ho7D{~>r2@Yu^T5EpRk>mCsTTOQ1aN?iQ)Z*9?WfPZv>jOJi
z_<SW)xkRm5wqjw;GPPQ(EMK@_VR@it;j*Rn_;^|T|M^i9#$Q%+{*C9xpYsc6&bYMr
zf(zpfv(8!lr7Pl3we!#RpLcmdu{mk3YihQ7zJ6`X`qsA4b?r7}M|i`=Z*02$2K#wb
z87M2Ss9bPm)k3R%(c&dnEnTK9Utz;l*Q~tyn&7H0o6p0uwfQWH*hEQEZnR2MJJ#QU
zfJUbryY-DH=l;<yiHs{u5W_G_SYg<Hm!oc*a70-;+k`fMJI%sj456apTZ=D$9Ec1!
zEPJv{><PZcGx)*_m#O0Gq*Zd<bZiKP+S;+~8o5y8Oc|di*EQP7(Q;bMOKY3gZD_aV
z^8W_%>g7C%B>-E&-vN~9YvySofzmgygy984U3fzWPc=<#9br4Sm<!1Z*0fxUV8R&2
zIv<Of)((u|X@7ll$NIW3<_5d3yrOJWj~SsBrjGiKW-~6KuLL#KZNyqnbjJ#_KR2Ud
z*-e`4zpG-$BgY@ZjQ(){bbPs#{`rvF%-2M%Sb>QE@)t*DVL8^0TyzD^hy6N2_<JLb
zDzPPtN_^OjCGb6;TUW2IYrUS9S6;PJEw8v>#j>kZ{t!m6N!6AOtsNv;6G_Ef5KH@#
zl}kIAGMDD8TGtK}C+21>MCxFO1cG+HVwEH`&xav5gyv)VR;w$QR#&Pbh&9tMT)KSa
z!WFBAWx*5<3yDNnqK4|~o5R<Sg)Po6GUpim&8^pMXhx67W=U@E9@sa|<WIB}r#K%g
zaVtB<3%uAi#dRsdhyU(Rv0*&*EZ!yc8pf|W(RPnv9KgAZ<2Xv*x1B_ZQxc~iCC=5H
zL6j#@b{fVrO(-LV@#~`~V}|i;5TV^<7%y^(x6xkqq6D5-fX5B|uL6&|)-YZNSvUG$
z=k{L1c*BDdaBl!#lE*NPqCKg|Fy8D%88VFj<n|tv7@xEcWhcr$l-v*g{s?->fd3=l
zlKm(nD8c6+Pol*5KkY)f1!W8+@Eohc*$Sb=xD@bp4DBgZhVk|$l$#9WxF6*{l%SJx
z0_6#u&;kC>8cM+b`6x;af0QGHvJ<B={0x5n#{GalfpVOJyBjacT9jK*MsOnueB)wd
ze(=sew0pw}a%{?QOi7>6V<kYW0BI_0avbGeTJW9mThi}HyEFCQ$9>oHy_CC>zn@f*
z(d%@!r@s8sA6|Un`RAVfeMXO?EUo?b&p!A33oriRrI+!Dk@%+=_%;~E)8GX+NW-70
zsNQI`=g|TiV;rCmwFeAi-!5=>E-e^Idr`(oN#KBC{D*+2$f~1|50C$o)m}>r5_qlw
z%QkmJvw+_XxLUw>(t<<@m$HOwO#$NrE(82rz(?RyU#A7PXPl{-MH#!!b~*b}F=k0z
zJ-;hU6TT4hjxc=oIDFv7&l`VYgl2ySL}h8t?qOY<EiOmu8BMM~jci(AQYB)(-!qIu
zC&2g6*mSjw<4%|BFT*Uyg$Czy5nHnmTd;?-cch*wGWwh@=eZVPVOB(yA07w$zu-eT
zo0cT%w<6<Nr^|72>~R%<hyDM+<KQ17?XP8=z{qE8QHA8%)M3xFbj=Jfo_CM~JSguP
zjb{;C_@xm88%7`<mIHp~g8ZCAC~;8+KXz51eGA(6v7b3Nr~aYJ);duk`XT>e75%le
zgyW{i<y?@;0g}KbF`n-NE(o|2rhc8rUw9r*<_B`Peumto!j7$D#p5E;CJ>JZ$ePgs
z34eFt-siO{pxsG}M%rVG%X#-Ge}~-eLcsR|9y*MFxcxG;BMvAd-YW9CYtX(6ZGJoM
zn73LWPH-sj;l9zrd-q6xY8Wf-m>%RmQZ$Mlw;w{gigxHI{^54S{}Hy==yu3|q!aDC
z<Is{vlF~63aE?lZ|0;4j<bNIdas)^FPesO2r?bjdxmdJmgf}^#9PxPdh$o>AK9e?M
z&hg_3^Jx47{UpKv-zY`PJtOtQnb%IdaW7){7XjY`_|3z5?{$WmJprptHS@CM1muIH
zQ-D7S_(O^CAq##%TDt{bleQ>vBnIFEddZhzj_gGJOT+p5%NPw}i_#ViPXP?hc{;fT
z@Li~{krwlZ+adqa<D=T=q8;+T=|lVN!}xDB@t37(sX}1UaK*&Oe7%Noop{_v3x?+_
zjlJq?EZmDP#I;7W1aqq!@F(Ce4P)oUMX<8Vb*nj)r#dtJ22+2R7+h8`L!K1)|1st!
z%s<wr5bcovSS_AU4cpWCS}M<<!<m5j*@iU$?C$*CSaGgpL|iUM(J(h6j4fGwCbsD^
zzIU)z;5cm=TRxe|wPA#&c#F(LV2Nv^<9Wn07x?<nGWdD;x?Ii^V-J_{VXRrUz)sJP
zJzmQ=n&e8_IGUk23tv>e(7+cO_(B6;Xy6MCe4&9aH1LH6zR<uI8W=+ZZnMo9;<C*c
z`p|mjwL5>zI}~#9-he;JW?}uk_~HGi&ul0ARD<`({F!7H@n7qF-gVq+@mOV-RgSYt
z8Q+FK)MY(ebgifVwF1{1V}6qMna#;3<F`K8+{Zy(YP>2HN00q%-uDed+U;MI|B?pe
z$oBKKXa0TlIY4E?xaP3`wBYMpQLQb#JQ!3LSFYlsd|5>$m&=zdSb>tLx+YMwvYM+`
zSF0;3t2JpQy0W}{zFJhh5|<=P@KVR78S32P(&CG7+tAU3S7h)S4i)3C$~U%$s2I03
zjm7I)Hx#eg(A?5+L30DiQ&U|>6BRdH-`a8gdb13-Q*nD^OC2{-akz0)7|(5T2~*tI
zw0bRWxEohD;a!jTlZ>ldk3U>rysiz<CM^EcJr&ott><^0{w4kWOF$f>wvI*NP+zGz
z(k`vP*FTKThUb=v_}ceu_V_9j)M=G`ra9tc<r!(4iC-(PkUc(RLYsLA_1Xj&?y~a)
zm**lce8i3T*yH=GN2|oYNg1ZWUG{jc`|!2%lr`SYXLd=u0K+-Q>W`22qK$EzaUSot
z^P^n~4S>ZziTd-S)z*hi|F{Y1vP$a0v#lfUviWEFi}1DaS$WYNVj!Tk%F-?7bNtsH
z&kY*B_IQi_WhYHYyG)Om&+*^H@xe34f8PJo5g%{M%MEMK9KX28gtSY~e@CBXwC4lM
z4t5@2ZK5&7vthW+=3hbmdVFp9t?`VKKeh6UAB!LRF+QI0+=TDw@fLioRXUExN17EL
zXMZ-MVn18-JFUJoX1ntjqvU6{<DWZFv+4Wdtx~bZkGx0Y9vhxZ{#taoEAg{NwVt{Y
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

end of thread, other threads:[~2016-03-24 16:56 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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 ` [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 ` [Qemu-devel] [PULL for-2.6 04/14] pc-bios/s390-ccw: qemuize types 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
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 ` [Qemu-devel] [PULL for-2.6 07/14] pc-bios/s390-ccw: make provisions for different backends 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
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 ` [Qemu-devel] [PULL for-2.6 10/14] pc-bios/s390-ccw: add virtio-scsi implementation Cornelia Huck
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 ` [Qemu-devel] [PULL for-2.6 12/14] pc-bios/s390-ccw: enhance bootmap detection 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
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

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.