From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41714) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1X0UHq-0001kl-Tj for qemu-devel@nongnu.org; Fri, 27 Jun 2014 07:25:57 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1X0UHg-0007KQ-6P for qemu-devel@nongnu.org; Fri, 27 Jun 2014 07:25:46 -0400 Received: from e06smtp11.uk.ibm.com ([195.75.94.107]:58476) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1X0UHf-0007KD-QJ for qemu-devel@nongnu.org; Fri, 27 Jun 2014 07:25:36 -0400 Received: from /spool/local by e06smtp11.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Fri, 27 Jun 2014 12:25:35 +0100 Received: from b06cxnps4074.portsmouth.uk.ibm.com (d06relay11.portsmouth.uk.ibm.com [9.149.109.196]) by d06dlp02.portsmouth.uk.ibm.com (Postfix) with ESMTP id 475932190056 for ; Fri, 27 Jun 2014 12:25:20 +0100 (BST) Received: from d06av10.portsmouth.uk.ibm.com (d06av10.portsmouth.uk.ibm.com [9.149.37.251]) by b06cxnps4074.portsmouth.uk.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id s5RBPWEx28704790 for ; Fri, 27 Jun 2014 11:25:32 GMT Received: from d06av10.portsmouth.uk.ibm.com (localhost [127.0.0.1]) by d06av10.portsmouth.uk.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id s5RBPVJ3005866 for ; Fri, 27 Jun 2014 05:25:32 -0600 From: Cornelia Huck Date: Fri, 27 Jun 2014 13:25:19 +0200 Message-Id: <1403868326-7718-4-git-send-email-cornelia.huck@de.ibm.com> In-Reply-To: <1403868326-7718-1-git-send-email-cornelia.huck@de.ibm.com> References: <1403868326-7718-1-git-send-email-cornelia.huck@de.ibm.com> Subject: [Qemu-devel] [PULL 03/10] pc-bios/s390-ccw: handle different sector sizes List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: peter.maydell@linaro.org, agraf@suse.de, borntraeger@de.ibm.com, jfrei@linux.vnet.ibm.com, aliguori@amazon.com, Cornelia Huck , "Eugene (jno) Dvurechenski" From: "Eugene (jno) Dvurechenski" Use the virtio device's configuration to figure out the disk geometry and use a sector size based upon the layout. [CH: s/SECTOR_SIZE/MAX_SECTOR_SIZE/g] Acked-by: Christian Borntraeger Signed-off-by: Eugene (jno) Dvurechenski Signed-off-by: Jens Freimann Signed-off-by: Cornelia Huck --- pc-bios/s390-ccw/bootmap.c | 12 +++--- pc-bios/s390-ccw/s390-ccw.h | 2 +- pc-bios/s390-ccw/virtio.c | 96 ++++++++++++++++++++++++++++++++++++++++--- pc-bios/s390-ccw/virtio.h | 48 ++++++++++++++++++++++ 4 files changed, 147 insertions(+), 11 deletions(-) diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c index c216030..fa2ca26 100644 --- a/pc-bios/s390-ccw/bootmap.c +++ b/pc-bios/s390-ccw/bootmap.c @@ -10,6 +10,7 @@ #include "s390-ccw.h" #include "bootmap.h" +#include "virtio.h" /* #define DEBUG_FALLBACK */ @@ -22,7 +23,8 @@ #endif /* Scratch space */ -static uint8_t sec[SECTOR_SIZE] __attribute__((__aligned__(SECTOR_SIZE))); +static uint8_t sec[MAX_SECTOR_SIZE] +__attribute__((__aligned__(MAX_SECTOR_SIZE))); typedef struct ResetInfo { uint32_t ipl_mask; @@ -99,7 +101,7 @@ static inline bool unused_space(const void *p, unsigned int size) static int zipl_load_segment(ComponentEntry *entry) { - const int max_entries = (SECTOR_SIZE / sizeof(ScsiBlockPtr)); + const int max_entries = (MAX_SECTOR_SIZE / sizeof(ScsiBlockPtr)); ScsiBlockPtr *bprs = (void *)sec; const int bprs_size = sizeof(sec); uint64_t blockno; @@ -163,7 +165,7 @@ static int zipl_run(ScsiBlockPtr *pte) { ComponentHeader *header; ComponentEntry *entry; - uint8_t tmp_sec[SECTOR_SIZE]; + uint8_t tmp_sec[MAX_SECTOR_SIZE]; virtio_read(pte->blockno, tmp_sec); header = (ComponentHeader *)tmp_sec; @@ -187,7 +189,7 @@ static int zipl_run(ScsiBlockPtr *pte) entry++; - if ((uint8_t *)(&entry[1]) > (tmp_sec + SECTOR_SIZE)) { + if ((uint8_t *)(&entry[1]) > (tmp_sec + MAX_SECTOR_SIZE)) { goto fail; } } @@ -238,7 +240,7 @@ int zipl_load(void) goto fail; } - ns_end = sec + SECTOR_SIZE; + ns_end = sec + virtio_get_block_size(); for (ns = (sec + pte_len); (ns + pte_len) < ns_end; ns++) { prog_table_entry = (ScsiBlockPtr *)ns; if (!prog_table_entry->blockno) { diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h index fe1dd22..b6c0a5b 100644 --- a/pc-bios/s390-ccw/s390-ccw.h +++ b/pc-bios/s390-ccw/s390-ccw.h @@ -130,6 +130,6 @@ static inline void yield(void) : "memory", "cc"); } -#define SECTOR_SIZE 512 +#define MAX_SECTOR_SIZE 4096 #endif /* S390_CCW_H */ diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c index c845b14..31b23b0 100644 --- a/pc-bios/s390-ccw/virtio.c +++ b/pc-bios/s390-ccw/virtio.c @@ -202,7 +202,7 @@ static int vring_wait_reply(struct vring *vr, int timeout) * Virtio block * ***********************************************/ -static int virtio_read_many(ulong sector, void *load_addr, int sec_num) +int virtio_read_many(ulong sector, void *load_addr, int sec_num) { struct virtio_blk_outhdr out_hdr; u8 status; @@ -211,12 +211,12 @@ static int virtio_read_many(ulong sector, void *load_addr, int sec_num) /* Tell the host we want to read */ out_hdr.type = VIRTIO_BLK_T_IN; out_hdr.ioprio = 99; - out_hdr.sector = sector; + out_hdr.sector = virtio_sector_adjust(sector); vring_send_buf(&block, &out_hdr, sizeof(out_hdr), VRING_DESC_F_NEXT); /* This is where we want to receive data */ - vring_send_buf(&block, load_addr, SECTOR_SIZE * sec_num, + vring_send_buf(&block, load_addr, virtio_get_block_size() * sec_num, VRING_DESC_F_WRITE | VRING_HIDDEN_IS_CHAIN | VRING_DESC_F_NEXT); @@ -244,7 +244,7 @@ unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2, int sec_len = rec_list2 >> 48; ulong addr = (ulong)load_addr; - if (sec_len != SECTOR_SIZE) { + if (sec_len != virtio_get_block_size()) { return -1; } @@ -253,7 +253,7 @@ unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2, if (status) { virtio_panic("I/O Error"); } - addr += sec_num * SECTOR_SIZE; + addr += sec_num * virtio_get_block_size(); return addr; } @@ -263,15 +263,95 @@ 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; +} + +void virtio_assume_scsi(void) +{ + guessed_disk_nature = true; + blk_cfg.blk_size = 512; +} + +void virtio_assume_eckd(void) +{ + guessed_disk_nature = true; + blk_cfg.blk_size = 4096; + + /* this must be here to calculate code segment position */ + blk_cfg.geometry.heads = 15; + blk_cfg.geometry.sectors = 12; +} + +bool virtio_disk_is_scsi(void) +{ + if (guessed_disk_nature) { + return (blk_cfg.blk_size == 512); + } + return (blk_cfg.geometry.heads == 255) + && (blk_cfg.geometry.sectors == 63) + && (blk_cfg.blk_size == 512); +} + +bool virtio_disk_is_eckd(void) +{ + if (guessed_disk_nature) { + return (blk_cfg.blk_size == 4096); + } + return (blk_cfg.geometry.heads == 15) + && (blk_cfg.geometry.sectors == 12) + && (blk_cfg.blk_size == 4096); +} + +bool virtio_ipl_disk_is_valid(void) +{ + return blk_cfg.blk_size && (virtio_disk_is_scsi() || virtio_disk_is_eckd()); +} + +int virtio_get_block_size(void) +{ + return blk_cfg.blk_size; +} + +uint16_t virtio_get_cylinders(void) +{ + return blk_cfg.geometry.cylinders; +} + +uint8_t virtio_get_heads(void) +{ + return blk_cfg.geometry.heads; +} + +uint8_t virtio_get_sectors(void) +{ + return blk_cfg.geometry.sectors; +} + void virtio_setup_block(struct subchannel_id schid) { struct vq_info_block info; struct vq_config_block config = {}; + blk_cfg.blk_size = 0; /* mark "illegal" - setup started... */ + virtio_reset(schid); + /* + * Skipping CCW_CMD_READ_FEAT. We're not doing anything fancy, and + * we'll just stop dead anyway if anything does not work like we + * expect it. + */ + 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"); + } + if (run_ccw(schid, CCW_CMD_READ_CONF, &blk_cfg, sizeof(blk_cfg))) { virtio_panic("Could not get block device configuration\n"); } vring_init(&block, config.num, (void *)(100 * 1024 * 1024), @@ -286,6 +366,12 @@ void virtio_setup_block(struct subchannel_id schid) if (!run_ccw(schid, CCW_CMD_SET_VQ, &info, sizeof(info))) { virtio_set_status(schid, VIRTIO_CONFIG_S_DRIVER_OK); } + + 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)); + virtio_assume_scsi(); + } } bool virtio_is_blk(struct subchannel_id schid) diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h index c2990ea..f1fb1b0 100644 --- a/pc-bios/s390-ccw/virtio.h +++ b/pc-bios/s390-ccw/virtio.h @@ -161,4 +161,52 @@ struct virtio_blk_outhdr { u64 sector; }; +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 virtio_blk_geometry { + u16 cylinders; + u8 heads; + u8 sectors; + } geometry; /* (if VIRTIO_BLK_F_GEOMETRY) */ + + u32 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 + in logical blocks */ + u32 opt_io_size; /* optimal sustained I/O size in logical blocks */ + + u8 wce; /* writeback mode (if VIRTIO_BLK_F_CONFIG_WCE) */ +} __attribute__((packed)) VirtioBlkConfig; + +bool virtio_guessed_disk_nature(void); +void virtio_assume_scsi(void); +void virtio_assume_eckd(void); + +extern bool virtio_disk_is_scsi(void); +extern bool virtio_disk_is_eckd(void); +extern bool virtio_ipl_disk_is_valid(void); +extern int virtio_get_block_size(void); +extern uint16_t virtio_get_cylinders(void); +extern uint8_t virtio_get_heads(void); +extern uint8_t virtio_get_sectors(void); +extern int virtio_read_many(ulong sector, void *load_addr, int sec_num); + +#define VIRTIO_SECTOR_SIZE 512 + +static inline ulong virtio_eckd_sector_adjust(ulong sector) +{ + return sector * (virtio_get_block_size() / VIRTIO_SECTOR_SIZE); +} + +static inline ulong virtio_sector_adjust(ulong sector) +{ + return virtio_disk_is_eckd() ? virtio_eckd_sector_adjust(sector) : sector; +} + #endif /* VIRTIO_H */ -- 1.7.9.5