qemu-devel.nongnu.org archive mirror
 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
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
KTT!>i)BgikNb&su

literal 17760
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
Zv+%j)j}^Z>m-6_k%|Ukxkh>N={TG%vUitt4

-- 
2.7.4

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

* Re: [Qemu-devel] [PULL for-2.6 00/14] s390-ccw bios patches
  2016-03-24  8:29 [Qemu-devel] [PULL for-2.6 00/14] s390-ccw bios patches Cornelia Huck
                   ` (13 preceding siblings ...)
  2016-03-24  8:30 ` [Qemu-devel] [PULL for-2.6 14/14] s390-ccw.img: rebuild image Cornelia Huck
@ 2016-03-24 16:56 ` Peter Maydell
  14 siblings, 0 replies; 16+ messages in thread
From: Peter Maydell @ 2016-03-24 16:56 UTC (permalink / raw)
  To: Cornelia Huck
  Cc: Christian Borntraeger, Jens Freimann, QEMU Developers,
	Alexander Graf

On 24 March 2016 at 08:29, Cornelia Huck <cornelia.huck@de.ibm.com> wrote:
> The following changes since commit 2538039f2c26d66053426fb547e4f25e669baf62:
>
>   Merge remote-tracking branch 'remotes/armbru/tags/pull-ivshmem-2016-03-18' into staging (2016-03-23 12:57:44 +0000)
>
> are available in the git repository at:
>
>   git://github.com/cohuck/qemu tags/s390x-20160324
>
> for you to fetch changes up to ce11b0622268dc8133bb4954c1e3fae0c23b6609:
>
>   s390-ccw.img: rebuild image (2016-03-23 16:13:38 +0100)
>
> ----------------------------------------------------------------
> Support for booting from virtio-scsi devices in the s390-ccw bios.
>

Applied, thanks.

-- PMM

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

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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).