qemu/pc-bios/s390-ccw/virtio.c
<<
>>
Prefs
   1/*
   2 * Virtio driver bits
   3 *
   4 * Copyright (c) 2013 Alexander Graf <agraf@suse.de>
   5 *
   6 * This work is licensed under the terms of the GNU GPL, version 2 or (at
   7 * your option) any later version. See the COPYING file in the top-level
   8 * directory.
   9 */
  10
  11#include "s390-ccw.h"
  12#include "virtio.h"
  13#include "virtio-scsi.h"
  14
  15#define VRING_WAIT_REPLY_TIMEOUT 3
  16
  17static VRing block[VIRTIO_MAX_VQS];
  18static char ring_area[VIRTIO_RING_SIZE * VIRTIO_MAX_VQS]
  19                     __attribute__((__aligned__(PAGE_SIZE)));
  20
  21static char chsc_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
  22
  23static VDev vdev = {
  24    .nr_vqs = 1,
  25    .vrings = block,
  26    .cmd_vr_idx = 0,
  27    .ring_area = ring_area,
  28    .wait_reply_timeout = VRING_WAIT_REPLY_TIMEOUT,
  29    .schid = { .one = 1 },
  30    .scsi_block_size = VIRTIO_SCSI_BLOCK_SIZE,
  31    .blk_factor = 1,
  32};
  33
  34VDev *virtio_get_device(void)
  35{
  36    return &vdev;
  37}
  38
  39VirtioDevType virtio_get_device_type(void)
  40{
  41    return vdev.senseid.cu_model;
  42}
  43
  44/* virtio spec v1.0 para 4.3.3.2 */
  45static long kvm_hypercall(unsigned long nr, unsigned long param1,
  46                          unsigned long param2, unsigned long param3)
  47{
  48    register ulong r_nr asm("1") = nr;
  49    register ulong r_param1 asm("2") = param1;
  50    register ulong r_param2 asm("3") = param2;
  51    register ulong r_param3 asm("4") = param3;
  52    register long retval asm("2");
  53
  54    asm volatile ("diag 2,4,0x500"
  55                  : "=d" (retval)
  56                  : "d" (r_nr), "0" (r_param1), "r"(r_param2), "d"(r_param3)
  57                  : "memory", "cc");
  58
  59    return retval;
  60}
  61
  62static long virtio_notify(SubChannelId schid, int vq_idx, long cookie)
  63{
  64    return kvm_hypercall(KVM_S390_VIRTIO_CCW_NOTIFY, *(u32 *)&schid,
  65                         vq_idx, cookie);
  66}
  67
  68/***********************************************
  69 *             Virtio functions                *
  70 ***********************************************/
  71
  72static int drain_irqs(SubChannelId schid)
  73{
  74    Irb irb = {};
  75    int r = 0;
  76
  77    while (1) {
  78        /* FIXME: make use of TPI, for that enable subchannel and isc */
  79        if (tsch(schid, &irb)) {
  80            /* Might want to differentiate error codes later on. */
  81            if (irb.scsw.cstat) {
  82                r = -EIO;
  83            } else if (irb.scsw.dstat != 0xc) {
  84                r = -EIO;
  85            }
  86            return r;
  87        }
  88    }
  89}
  90
  91static int run_ccw(VDev *vdev, int cmd, void *ptr, int len)
  92{
  93    Ccw1 ccw = {};
  94    CmdOrb orb = {};
  95    Schib schib;
  96    int r;
  97
  98    /* start command processing */
  99    stsch_err(vdev->schid, &schib);
 100    schib.scsw.ctrl = SCSW_FCTL_START_FUNC;
 101    msch(vdev->schid, &schib);
 102
 103    /* start subchannel command */
 104    orb.fmt = 1;
 105    orb.cpa = (u32)(long)&ccw;
 106    orb.lpm = 0x80;
 107
 108    ccw.cmd_code = cmd;
 109    ccw.cda = (long)ptr;
 110    ccw.count = len;
 111
 112    r = ssch(vdev->schid, &orb);
 113    /*
 114     * XXX Wait until device is done processing the CCW. For now we can
 115     *     assume that a simple tsch will have finished the CCW processing,
 116     *     but the architecture allows for asynchronous operation
 117     */
 118    if (!r) {
 119        r = drain_irqs(vdev->schid);
 120    }
 121    return r;
 122}
 123
 124static void vring_init(VRing *vr, VqInfo *info)
 125{
 126    void *p = (void *) info->queue;
 127
 128    debug_print_addr("init p", p);
 129    vr->id = info->index;
 130    vr->num = info->num;
 131    vr->desc = p;
 132    vr->avail = p + info->num * sizeof(VRingDesc);
 133    vr->used = (void *)(((unsigned long)&vr->avail->ring[info->num]
 134               + info->align - 1) & ~(info->align - 1));
 135
 136    /* Zero out all relevant field */
 137    vr->avail->flags = 0;
 138    vr->avail->idx = 0;
 139
 140    /* We're running with interrupts off anyways, so don't bother */
 141    vr->used->flags = VRING_USED_F_NO_NOTIFY;
 142    vr->used->idx = 0;
 143    vr->used_idx = 0;
 144    vr->next_idx = 0;
 145    vr->cookie = 0;
 146
 147    debug_print_addr("init vr", vr);
 148}
 149
 150static bool vring_notify(VRing *vr)
 151{
 152    vr->cookie = virtio_notify(vr->schid, vr->id, vr->cookie);
 153    return vr->cookie >= 0;
 154}
 155
 156static void vring_send_buf(VRing *vr, void *p, int len, int flags)
 157{
 158    /* For follow-up chains we need to keep the first entry point */
 159    if (!(flags & VRING_HIDDEN_IS_CHAIN)) {
 160        vr->avail->ring[vr->avail->idx % vr->num] = vr->next_idx;
 161    }
 162
 163    vr->desc[vr->next_idx].addr = (ulong)p;
 164    vr->desc[vr->next_idx].len = len;
 165    vr->desc[vr->next_idx].flags = flags & ~VRING_HIDDEN_IS_CHAIN;
 166    vr->desc[vr->next_idx].next = vr->next_idx;
 167    vr->desc[vr->next_idx].next++;
 168    vr->next_idx++;
 169
 170    /* Chains only have a single ID */
 171    if (!(flags & VRING_DESC_F_NEXT)) {
 172        vr->avail->idx++;
 173    }
 174}
 175
 176static u64 get_clock(void)
 177{
 178    u64 r;
 179
 180    asm volatile("stck %0" : "=Q" (r) : : "cc");
 181    return r;
 182}
 183
 184ulong get_second(void)
 185{
 186    return (get_clock() >> 12) / 1000000;
 187}
 188
 189static int vr_poll(VRing *vr)
 190{
 191    if (vr->used->idx == vr->used_idx) {
 192        vring_notify(vr);
 193        yield();
 194        return 0;
 195    }
 196
 197    vr->used_idx = vr->used->idx;
 198    vr->next_idx = 0;
 199    vr->desc[0].len = 0;
 200    vr->desc[0].flags = 0;
 201    return 1; /* vr has been updated */
 202}
 203
 204/*
 205 * Wait for the host to reply.
 206 *
 207 * timeout is in seconds if > 0.
 208 *
 209 * Returns 0 on success, 1 on timeout.
 210 */
 211static int vring_wait_reply(void)
 212{
 213    ulong target_second = get_second() + vdev.wait_reply_timeout;
 214
 215    /* Wait for any queue to be updated by the host */
 216    do {
 217        int i, r = 0;
 218
 219        for (i = 0; i < vdev.nr_vqs; i++) {
 220            r += vr_poll(&vdev.vrings[i]);
 221        }
 222        yield();
 223        if (r) {
 224            return 0;
 225        }
 226    } while (!vdev.wait_reply_timeout || (get_second() < target_second));
 227
 228    return 1;
 229}
 230
 231int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd)
 232{
 233    VRing *vr = &vdev->vrings[vqid];
 234    int i = 0;
 235
 236    do {
 237        vring_send_buf(vr, cmd[i].data, cmd[i].size,
 238                       cmd[i].flags | (i ? VRING_HIDDEN_IS_CHAIN : 0));
 239    } while (cmd[i++].flags & VRING_DESC_F_NEXT);
 240
 241    vring_wait_reply();
 242    if (drain_irqs(vr->schid)) {
 243        return -1;
 244    }
 245    return 0;
 246}
 247
 248/***********************************************
 249 *               Virtio block                  *
 250 ***********************************************/
 251
 252static int virtio_blk_read_many(VDev *vdev,
 253                                ulong sector, void *load_addr, int sec_num)
 254{
 255    VirtioBlkOuthdr out_hdr;
 256    u8 status;
 257    VRing *vr = &vdev->vrings[vdev->cmd_vr_idx];
 258
 259    /* Tell the host we want to read */
 260    out_hdr.type = VIRTIO_BLK_T_IN;
 261    out_hdr.ioprio = 99;
 262    out_hdr.sector = virtio_sector_adjust(sector);
 263
 264    vring_send_buf(vr, &out_hdr, sizeof(out_hdr), VRING_DESC_F_NEXT);
 265
 266    /* This is where we want to receive data */
 267    vring_send_buf(vr, load_addr, virtio_get_block_size() * sec_num,
 268                   VRING_DESC_F_WRITE | VRING_HIDDEN_IS_CHAIN |
 269                   VRING_DESC_F_NEXT);
 270
 271    /* status field */
 272    vring_send_buf(vr, &status, sizeof(u8),
 273                   VRING_DESC_F_WRITE | VRING_HIDDEN_IS_CHAIN);
 274
 275    /* Now we can tell the host to read */
 276    vring_wait_reply();
 277
 278    if (drain_irqs(vr->schid)) {
 279        /* Well, whatever status is supposed to contain... */
 280        status = 1;
 281    }
 282    return status;
 283}
 284
 285int virtio_read_many(ulong sector, void *load_addr, int sec_num)
 286{
 287    switch (vdev.senseid.cu_model) {
 288    case VIRTIO_ID_BLOCK:
 289        return virtio_blk_read_many(&vdev, sector, load_addr, sec_num);
 290    case VIRTIO_ID_SCSI:
 291        return virtio_scsi_read_many(&vdev, sector, load_addr, sec_num);
 292    }
 293    panic("\n! No readable IPL device !\n");
 294    return -1;
 295}
 296
 297unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2,
 298                                 ulong subchan_id, void *load_addr)
 299{
 300    u8 status;
 301    int sec = rec_list1;
 302    int sec_num = ((rec_list2 >> 32) & 0xffff) + 1;
 303    int sec_len = rec_list2 >> 48;
 304    ulong addr = (ulong)load_addr;
 305
 306    if (sec_len != virtio_get_block_size()) {
 307        return -1;
 308    }
 309
 310    sclp_print(".");
 311    status = virtio_read_many(sec, (void *)addr, sec_num);
 312    if (status) {
 313        panic("I/O Error");
 314    }
 315    addr += sec_num * virtio_get_block_size();
 316
 317    return addr;
 318}
 319
 320int virtio_read(ulong sector, void *load_addr)
 321{
 322    return virtio_read_many(sector, load_addr, 1);
 323}
 324
 325/*
 326 * Other supported value pairs, if any, would need to be added here.
 327 * Note: head count is always 15.
 328 */
 329static inline u8 virtio_eckd_sectors_for_block_size(int size)
 330{
 331    switch (size) {
 332    case 512:
 333        return 49;
 334    case 1024:
 335        return 33;
 336    case 2048:
 337        return 21;
 338    case 4096:
 339        return 12;
 340    }
 341    return 0;
 342}
 343
 344VirtioGDN virtio_guessed_disk_nature(void)
 345{
 346    return vdev.guessed_disk_nature;
 347}
 348
 349void virtio_assume_scsi(void)
 350{
 351    switch (vdev.senseid.cu_model) {
 352    case VIRTIO_ID_BLOCK:
 353        vdev.guessed_disk_nature = VIRTIO_GDN_SCSI;
 354        vdev.config.blk.blk_size = VIRTIO_SCSI_BLOCK_SIZE;
 355        vdev.config.blk.physical_block_exp = 0;
 356        vdev.blk_factor = 1;
 357        break;
 358    case VIRTIO_ID_SCSI:
 359        vdev.scsi_block_size = VIRTIO_SCSI_BLOCK_SIZE;
 360        break;
 361    }
 362}
 363
 364void virtio_assume_iso9660(void)
 365{
 366    switch (vdev.senseid.cu_model) {
 367    case VIRTIO_ID_BLOCK:
 368        vdev.guessed_disk_nature = VIRTIO_GDN_SCSI;
 369        vdev.config.blk.blk_size = VIRTIO_ISO_BLOCK_SIZE;
 370        vdev.config.blk.physical_block_exp = 0;
 371        vdev.blk_factor = VIRTIO_ISO_BLOCK_SIZE / VIRTIO_SECTOR_SIZE;
 372        break;
 373    case VIRTIO_ID_SCSI:
 374        vdev.scsi_block_size = VIRTIO_ISO_BLOCK_SIZE;
 375        break;
 376    }
 377}
 378
 379void virtio_assume_eckd(void)
 380{
 381    vdev.guessed_disk_nature = VIRTIO_GDN_DASD;
 382    vdev.blk_factor = 1;
 383    vdev.config.blk.physical_block_exp = 0;
 384    switch (vdev.senseid.cu_model) {
 385    case VIRTIO_ID_BLOCK:
 386        vdev.config.blk.blk_size = 4096;
 387        break;
 388    case VIRTIO_ID_SCSI:
 389        vdev.config.blk.blk_size = vdev.scsi_block_size;
 390        break;
 391    }
 392    vdev.config.blk.geometry.heads = 15;
 393    vdev.config.blk.geometry.sectors =
 394        virtio_eckd_sectors_for_block_size(vdev.config.blk.blk_size);
 395}
 396
 397bool virtio_disk_is_scsi(void)
 398{
 399    if (vdev.guessed_disk_nature == VIRTIO_GDN_SCSI) {
 400        return true;
 401    }
 402    switch (vdev.senseid.cu_model) {
 403    case VIRTIO_ID_BLOCK:
 404        return (vdev.config.blk.geometry.heads == 255)
 405            && (vdev.config.blk.geometry.sectors == 63)
 406            && (virtio_get_block_size()  == VIRTIO_SCSI_BLOCK_SIZE);
 407    case VIRTIO_ID_SCSI:
 408        return true;
 409    }
 410    return false;
 411}
 412
 413bool virtio_disk_is_eckd(void)
 414{
 415    const int block_size = virtio_get_block_size();
 416
 417    if (vdev.guessed_disk_nature == VIRTIO_GDN_DASD) {
 418        return true;
 419    }
 420    switch (vdev.senseid.cu_model) {
 421    case VIRTIO_ID_BLOCK:
 422        return (vdev.config.blk.geometry.heads == 15)
 423            && (vdev.config.blk.geometry.sectors ==
 424                virtio_eckd_sectors_for_block_size(block_size));
 425    case VIRTIO_ID_SCSI:
 426        return false;
 427    }
 428    return false;
 429}
 430
 431bool virtio_ipl_disk_is_valid(void)
 432{
 433    return virtio_disk_is_scsi() || virtio_disk_is_eckd();
 434}
 435
 436int virtio_get_block_size(void)
 437{
 438    switch (vdev.senseid.cu_model) {
 439    case VIRTIO_ID_BLOCK:
 440        return vdev.config.blk.blk_size << vdev.config.blk.physical_block_exp;
 441    case VIRTIO_ID_SCSI:
 442        return vdev.scsi_block_size;
 443    }
 444    return 0;
 445}
 446
 447uint8_t virtio_get_heads(void)
 448{
 449    switch (vdev.senseid.cu_model) {
 450    case VIRTIO_ID_BLOCK:
 451        return vdev.config.blk.geometry.heads;
 452    case VIRTIO_ID_SCSI:
 453        return vdev.guessed_disk_nature == VIRTIO_GDN_DASD
 454               ? vdev.config.blk.geometry.heads : 255;
 455    }
 456    return 0;
 457}
 458
 459uint8_t virtio_get_sectors(void)
 460{
 461    switch (vdev.senseid.cu_model) {
 462    case VIRTIO_ID_BLOCK:
 463        return vdev.config.blk.geometry.sectors;
 464    case VIRTIO_ID_SCSI:
 465        return vdev.guessed_disk_nature == VIRTIO_GDN_DASD
 466               ? vdev.config.blk.geometry.sectors : 63;
 467    }
 468    return 0;
 469}
 470
 471uint64_t virtio_get_blocks(void)
 472{
 473    const uint64_t factor = virtio_get_block_size() / VIRTIO_SECTOR_SIZE;
 474    switch (vdev.senseid.cu_model) {
 475    case VIRTIO_ID_BLOCK:
 476        return vdev.config.blk.capacity / factor;
 477    case VIRTIO_ID_SCSI:
 478        return vdev.scsi_last_block / factor;
 479    }
 480    return 0;
 481}
 482
 483static void virtio_setup_ccw(VDev *vdev)
 484{
 485    int i, cfg_size = 0;
 486    unsigned char status = VIRTIO_CONFIG_S_DRIVER_OK;
 487
 488    IPL_assert(virtio_is_supported(vdev->schid), "PE");
 489    /* device ID has been established now */
 490
 491    vdev->config.blk.blk_size = 0; /* mark "illegal" - setup started... */
 492    vdev->guessed_disk_nature = VIRTIO_GDN_NONE;
 493
 494    run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0);
 495
 496    switch (vdev->senseid.cu_model) {
 497    case VIRTIO_ID_BLOCK:
 498        vdev->nr_vqs = 1;
 499        vdev->cmd_vr_idx = 0;
 500        cfg_size = sizeof(vdev->config.blk);
 501        break;
 502    case VIRTIO_ID_SCSI:
 503        vdev->nr_vqs = 3;
 504        vdev->cmd_vr_idx = VR_REQUEST;
 505        cfg_size = sizeof(vdev->config.scsi);
 506        break;
 507    default:
 508        panic("Unsupported virtio device\n");
 509    }
 510    IPL_assert(run_ccw(vdev, CCW_CMD_READ_CONF, &vdev->config, cfg_size) == 0,
 511               "Could not get block device configuration");
 512
 513    /*
 514     * Skipping CCW_CMD_READ_FEAT. We're not doing anything fancy, and
 515     * we'll just stop dead anyway if anything does not work like we
 516     * expect it.
 517     */
 518
 519    for (i = 0; i < vdev->nr_vqs; i++) {
 520        VqInfo info = {
 521            .queue = (unsigned long long) ring_area + (i * VIRTIO_RING_SIZE),
 522            .align = KVM_S390_VIRTIO_RING_ALIGN,
 523            .index = i,
 524            .num = 0,
 525        };
 526        VqConfig config = {
 527            .index = i,
 528            .num = 0,
 529        };
 530
 531        IPL_assert(
 532            run_ccw(vdev, CCW_CMD_READ_VQ_CONF, &config, sizeof(config)) == 0,
 533            "Could not get block device VQ configuration");
 534        info.num = config.num;
 535        vring_init(&vdev->vrings[i], &info);
 536        vdev->vrings[i].schid = vdev->schid;
 537        IPL_assert(run_ccw(vdev, CCW_CMD_SET_VQ, &info, sizeof(info)) == 0,
 538                   "Cannot set VQ info");
 539    }
 540    IPL_assert(
 541        run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status)) == 0,
 542        "Could not write status to host");
 543}
 544
 545void virtio_setup_device(SubChannelId schid)
 546{
 547    vdev.schid = schid;
 548    virtio_setup_ccw(&vdev);
 549
 550    switch (vdev.senseid.cu_model) {
 551    case VIRTIO_ID_BLOCK:
 552        sclp_print("Using virtio-blk.\n");
 553        if (!virtio_ipl_disk_is_valid()) {
 554            /* make sure all getters but blocksize return 0 for
 555             * invalid IPL disk
 556             */
 557            memset(&vdev.config.blk, 0, sizeof(vdev.config.blk));
 558            virtio_assume_scsi();
 559        }
 560        break;
 561    case VIRTIO_ID_SCSI:
 562        IPL_assert(vdev.config.scsi.sense_size == VIRTIO_SCSI_SENSE_SIZE,
 563            "Config: sense size mismatch");
 564        IPL_assert(vdev.config.scsi.cdb_size == VIRTIO_SCSI_CDB_SIZE,
 565            "Config: CDB size mismatch");
 566
 567        sclp_print("Using virtio-scsi.\n");
 568        virtio_scsi_setup(&vdev);
 569        break;
 570    default:
 571        panic("\n! No IPL device available !\n");
 572    }
 573}
 574
 575bool virtio_is_supported(SubChannelId schid)
 576{
 577    vdev.schid = schid;
 578    memset(&vdev.senseid, 0, sizeof(vdev.senseid));
 579    /* run sense id command */
 580    if (run_ccw(&vdev, CCW_CMD_SENSE_ID, &vdev.senseid, sizeof(vdev.senseid))) {
 581        return false;
 582    }
 583    if (vdev.senseid.cu_type == 0x3832) {
 584        switch (vdev.senseid.cu_model) {
 585        case VIRTIO_ID_BLOCK:
 586        case VIRTIO_ID_SCSI:
 587            return true;
 588        }
 589    }
 590    return false;
 591}
 592
 593int enable_mss_facility(void)
 594{
 595    int ret;
 596    ChscAreaSda *sda_area = (ChscAreaSda *) chsc_page;
 597
 598    memset(sda_area, 0, PAGE_SIZE);
 599    sda_area->request.length = 0x0400;
 600    sda_area->request.code = 0x0031;
 601    sda_area->operation_code = 0x2;
 602
 603    ret = chsc(sda_area);
 604    if ((ret == 0) && (sda_area->response.code == 0x0001)) {
 605        return 0;
 606    }
 607    return -EIO;
 608}
 609