qemu/pc-bios/s390-ccw/cio.c
<<
>>
Prefs
   1/*
   2 * S390 Channel I/O
   3 *
   4 * Copyright (c) 2013 Alexander Graf <agraf@suse.de>
   5 * Copyright (c) 2019 IBM Corp.
   6 *
   7 * Author(s): Jason J. Herne <jjherne@us.ibm.com>
   8 *
   9 * This work is licensed under the terms of the GNU GPL, version 2 or (at
  10 * your option) any later version. See the COPYING file in the top-level
  11 * directory.
  12 */
  13
  14#include "libc.h"
  15#include "s390-ccw.h"
  16#include "s390-arch.h"
  17#include "helper.h"
  18#include "cio.h"
  19
  20static char chsc_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
  21
  22static int __do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt, Irb *irb);
  23
  24int enable_mss_facility(void)
  25{
  26    int ret;
  27    ChscAreaSda *sda_area = (ChscAreaSda *) chsc_page;
  28
  29    memset(sda_area, 0, PAGE_SIZE);
  30    sda_area->request.length = 0x0400;
  31    sda_area->request.code = 0x0031;
  32    sda_area->operation_code = 0x2;
  33
  34    ret = chsc(sda_area);
  35    if ((ret == 0) && (sda_area->response.code == 0x0001)) {
  36        return 0;
  37    }
  38    return -EIO;
  39}
  40
  41void enable_subchannel(SubChannelId schid)
  42{
  43    Schib schib;
  44
  45    stsch_err(schid, &schib);
  46    schib.pmcw.ena = 1;
  47    msch(schid, &schib);
  48}
  49
  50uint16_t cu_type(SubChannelId schid)
  51{
  52    SenseId sense_data;
  53    Ccw1 sense_id_ccw = {
  54        .cmd_code = CCW_CMD_SENSE_ID,
  55        .flags = CCW_FLAG_SLI,
  56        .count = sizeof(sense_data),
  57        .cda = ptr2u32(&sense_data),
  58    };
  59
  60    if (do_cio(schid, CU_TYPE_UNKNOWN, ptr2u32(&sense_id_ccw), CCW_FMT1)) {
  61        panic("Failed to run SenseID CCw\n");
  62    }
  63
  64    return sense_data.cu_type;
  65}
  66
  67int basic_sense(SubChannelId schid, uint16_t cutype, void *sense_data,
  68                 uint16_t data_size)
  69{
  70    Ccw1 senseCcw = {
  71        .cmd_code = CCW_CMD_BASIC_SENSE,
  72        .count = data_size,
  73        .cda = ptr2u32(sense_data),
  74    };
  75    Irb irb;
  76
  77    return __do_cio(schid, ptr2u32(&senseCcw), CCW_FMT1, &irb);
  78}
  79
  80static bool irb_error(Irb *irb)
  81{
  82    if (irb->scsw.cstat) {
  83        return true;
  84    }
  85    return irb->scsw.dstat != (SCSW_DSTAT_DEVEND | SCSW_DSTAT_CHEND);
  86}
  87
  88static void print_eckd_dasd_sense_data(SenseDataEckdDasd *sd)
  89{
  90    char msgline[512];
  91
  92    if (sd->config_info & 0x8000) {
  93        sclp_print("Eckd Dasd Sense Data (fmt 24-bytes):\n");
  94    } else {
  95        sclp_print("Eckd Dasd Sense Data (fmt 32-bytes):\n");
  96    }
  97
  98    strcat(msgline, "    Sense Condition Flags :");
  99    if (sd->common_status & SNS_STAT0_CMD_REJECT) {
 100        strcat(msgline, " [Cmd-Reject]");
 101    }
 102    if (sd->common_status & SNS_STAT0_INTERVENTION_REQ) {
 103        strcat(msgline, " [Intervention-Required]");
 104    }
 105    if (sd->common_status & SNS_STAT0_BUS_OUT_CHECK) {
 106        strcat(msgline, " [Bus-Out-Parity-Check]");
 107    }
 108    if (sd->common_status & SNS_STAT0_EQUIPMENT_CHECK) {
 109        strcat(msgline, " [Equipment-Check]");
 110    }
 111    if (sd->common_status & SNS_STAT0_DATA_CHECK) {
 112        strcat(msgline, " [Data-Check]");
 113    }
 114    if (sd->common_status & SNS_STAT0_OVERRUN) {
 115        strcat(msgline, " [Overrun]");
 116    }
 117    if (sd->common_status & SNS_STAT0_INCOMPL_DOMAIN) {
 118        strcat(msgline, " [Incomplete-Domain]");
 119    }
 120
 121    if (sd->status[0] & SNS_STAT1_PERM_ERR) {
 122        strcat(msgline, " [Permanent-Error]");
 123    }
 124    if (sd->status[0] & SNS_STAT1_INV_TRACK_FORMAT) {
 125        strcat(msgline, " [Invalid-Track-Fmt]");
 126    }
 127    if (sd->status[0] & SNS_STAT1_EOC) {
 128        strcat(msgline, " [End-of-Cyl]");
 129    }
 130    if (sd->status[0] & SNS_STAT1_MESSAGE_TO_OPER) {
 131        strcat(msgline, " [Operator-Msg]");
 132    }
 133    if (sd->status[0] & SNS_STAT1_NO_REC_FOUND) {
 134        strcat(msgline, " [No-Record-Found]");
 135    }
 136    if (sd->status[0] & SNS_STAT1_FILE_PROTECTED) {
 137        strcat(msgline, " [File-Protected]");
 138    }
 139    if (sd->status[0] & SNS_STAT1_WRITE_INHIBITED) {
 140        strcat(msgline, " [Write-Inhibited]");
 141    }
 142    if (sd->status[0] & SNS_STAT1_IMPRECISE_END) {
 143        strcat(msgline, " [Imprecise-Ending]");
 144    }
 145
 146    if (sd->status[1] & SNS_STAT2_REQ_INH_WRITE) {
 147        strcat(msgline, " [Req-Inhibit-Write]");
 148    }
 149    if (sd->status[1] & SNS_STAT2_CORRECTABLE) {
 150        strcat(msgline, " [Correctable-Data-Check]");
 151    }
 152    if (sd->status[1] & SNS_STAT2_FIRST_LOG_ERR) {
 153        strcat(msgline, " [First-Error-Log]");
 154    }
 155    if (sd->status[1] & SNS_STAT2_ENV_DATA_PRESENT) {
 156        strcat(msgline, " [Env-Data-Present]");
 157    }
 158    if (sd->status[1] & SNS_STAT2_IMPRECISE_END) {
 159        strcat(msgline, " [Imprecise-End]");
 160    }
 161    strcat(msgline, "\n");
 162    sclp_print(msgline);
 163
 164    print_int("    Residual Count     =", sd->res_count);
 165    print_int("    Phys Drive ID      =", sd->phys_drive_id);
 166    print_int("    low cyl address    =", sd->low_cyl_addr);
 167    print_int("    head addr & hi cyl =", sd->head_high_cyl_addr);
 168    print_int("    format/message     =", sd->fmt_msg);
 169    print_int("    fmt-dependent[0-7] =", sd->fmt_dependent_info[0]);
 170    print_int("    fmt-dependent[8-15]=", sd->fmt_dependent_info[1]);
 171    print_int("    prog action code   =", sd->program_action_code);
 172    print_int("    Configuration info =", sd->config_info);
 173    print_int("    mcode / hi-cyl     =", sd->mcode_hicyl);
 174    print_int("    cyl & head addr [0]=", sd->cyl_head_addr[0]);
 175    print_int("    cyl & head addr [1]=", sd->cyl_head_addr[1]);
 176    print_int("    cyl & head addr [2]=", sd->cyl_head_addr[2]);
 177}
 178
 179static void print_irb_err(Irb *irb)
 180{
 181    uint64_t this_ccw = *(uint64_t *)u32toptr(irb->scsw.cpa);
 182    uint64_t prev_ccw = *(uint64_t *)u32toptr(irb->scsw.cpa - 8);
 183    char msgline[256];
 184
 185    sclp_print("Interrupt Response Block Data:\n");
 186
 187    strcat(msgline, "    Function Ctrl :");
 188    if (irb->scsw.ctrl & SCSW_FCTL_START_FUNC) {
 189        strcat(msgline, " [Start]");
 190    }
 191    if (irb->scsw.ctrl & SCSW_FCTL_HALT_FUNC) {
 192        strcat(msgline, " [Halt]");
 193    }
 194    if (irb->scsw.ctrl & SCSW_FCTL_CLEAR_FUNC) {
 195        strcat(msgline, " [Clear]");
 196    }
 197    strcat(msgline, "\n");
 198    sclp_print(msgline);
 199
 200    msgline[0] = '\0';
 201    strcat(msgline, "    Activity Ctrl :");
 202    if (irb->scsw.ctrl & SCSW_ACTL_RESUME_PEND) {
 203        strcat(msgline, " [Resume-Pending]");
 204    }
 205    if (irb->scsw.ctrl & SCSW_ACTL_START_PEND) {
 206        strcat(msgline, " [Start-Pending]");
 207    }
 208    if (irb->scsw.ctrl & SCSW_ACTL_HALT_PEND) {
 209        strcat(msgline, " [Halt-Pending]");
 210    }
 211    if (irb->scsw.ctrl & SCSW_ACTL_CLEAR_PEND) {
 212        strcat(msgline, " [Clear-Pending]");
 213    }
 214    if (irb->scsw.ctrl & SCSW_ACTL_CH_ACTIVE) {
 215        strcat(msgline, " [Channel-Active]");
 216    }
 217    if (irb->scsw.ctrl & SCSW_ACTL_DEV_ACTIVE) {
 218        strcat(msgline, " [Device-Active]");
 219    }
 220    if (irb->scsw.ctrl & SCSW_ACTL_SUSPENDED) {
 221        strcat(msgline, " [Suspended]");
 222    }
 223    strcat(msgline, "\n");
 224    sclp_print(msgline);
 225
 226    msgline[0] = '\0';
 227    strcat(msgline, "    Status Ctrl :");
 228    if (irb->scsw.ctrl & SCSW_SCTL_ALERT) {
 229        strcat(msgline, " [Alert]");
 230    }
 231    if (irb->scsw.ctrl & SCSW_SCTL_INTERMED) {
 232        strcat(msgline, " [Intermediate]");
 233    }
 234    if (irb->scsw.ctrl & SCSW_SCTL_PRIMARY) {
 235        strcat(msgline, " [Primary]");
 236    }
 237    if (irb->scsw.ctrl & SCSW_SCTL_SECONDARY) {
 238        strcat(msgline, " [Secondary]");
 239    }
 240    if (irb->scsw.ctrl & SCSW_SCTL_STATUS_PEND) {
 241        strcat(msgline, " [Status-Pending]");
 242    }
 243
 244    strcat(msgline, "\n");
 245    sclp_print(msgline);
 246
 247    msgline[0] = '\0';
 248    strcat(msgline, "    Device Status :");
 249    if (irb->scsw.dstat & SCSW_DSTAT_ATTN) {
 250        strcat(msgline, " [Attention]");
 251    }
 252    if (irb->scsw.dstat & SCSW_DSTAT_STATMOD) {
 253        strcat(msgline, " [Status-Modifier]");
 254    }
 255    if (irb->scsw.dstat & SCSW_DSTAT_CUEND) {
 256        strcat(msgline, " [Ctrl-Unit-End]");
 257    }
 258    if (irb->scsw.dstat & SCSW_DSTAT_BUSY) {
 259        strcat(msgline, " [Busy]");
 260    }
 261    if (irb->scsw.dstat & SCSW_DSTAT_CHEND) {
 262        strcat(msgline, " [Channel-End]");
 263    }
 264    if (irb->scsw.dstat & SCSW_DSTAT_DEVEND) {
 265        strcat(msgline, " [Device-End]");
 266    }
 267    if (irb->scsw.dstat & SCSW_DSTAT_UCHK) {
 268        strcat(msgline, " [Unit-Check]");
 269    }
 270    if (irb->scsw.dstat & SCSW_DSTAT_UEXCP) {
 271        strcat(msgline, " [Unit-Exception]");
 272    }
 273    strcat(msgline, "\n");
 274    sclp_print(msgline);
 275
 276    msgline[0] = '\0';
 277    strcat(msgline, "    Channel Status :");
 278    if (irb->scsw.cstat & SCSW_CSTAT_PCINT) {
 279        strcat(msgline, " [Program-Ctrl-Interruption]");
 280    }
 281    if (irb->scsw.cstat & SCSW_CSTAT_BADLEN) {
 282        strcat(msgline, " [Incorrect-Length]");
 283    }
 284    if (irb->scsw.cstat & SCSW_CSTAT_PROGCHK) {
 285        strcat(msgline, " [Program-Check]");
 286    }
 287    if (irb->scsw.cstat & SCSW_CSTAT_PROTCHK) {
 288        strcat(msgline, " [Protection-Check]");
 289    }
 290    if (irb->scsw.cstat & SCSW_CSTAT_CHDCHK) {
 291        strcat(msgline, " [Channel-Data-Check]");
 292    }
 293    if (irb->scsw.cstat & SCSW_CSTAT_CHCCHK) {
 294        strcat(msgline, " [Channel-Ctrl-Check]");
 295    }
 296    if (irb->scsw.cstat & SCSW_CSTAT_ICCHK) {
 297        strcat(msgline, " [Interface-Ctrl-Check]");
 298    }
 299    if (irb->scsw.cstat & SCSW_CSTAT_CHAINCHK) {
 300        strcat(msgline, " [Chaining-Check]");
 301    }
 302    strcat(msgline, "\n");
 303    sclp_print(msgline);
 304
 305    print_int("    cpa=", irb->scsw.cpa);
 306    print_int("    prev_ccw=", prev_ccw);
 307    print_int("    this_ccw=", this_ccw);
 308}
 309
 310/*
 311 * Handles executing ssch, tsch and returns the irb obtained from tsch.
 312 * Returns 0 on success, -1 if unexpected status pending and we need to retry,
 313 * otherwise returns condition code from ssch/tsch for error cases.
 314 */
 315static int __do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt, Irb *irb)
 316{
 317    /*
 318     * QEMU's CIO implementation requires prefetch and 64-bit idaws. We
 319     * allow all paths.
 320     */
 321    CmdOrb orb = {
 322        .fmt = fmt,
 323        .pfch = 1,
 324        .c64 = 1,
 325        .lpm = 0xFF,
 326        .cpa = ccw_addr,
 327    };
 328    int rc;
 329
 330    IPL_assert(fmt == 0 || fmt == 1, "Invalid ccw format");
 331
 332    /* ccw_addr must be <= 24 bits and point to at least one whole ccw. */
 333    if (fmt == 0) {
 334        IPL_assert(ccw_addr <= 0xFFFFFF - 8, "Invalid ccw address");
 335    }
 336
 337    rc = ssch(schid, &orb);
 338    if (rc == 1 || rc == 2) {
 339        /* Subchannel status pending or busy. Eat status and ask for retry. */
 340        tsch(schid, irb);
 341        return -1;
 342    }
 343    if (rc) {
 344        print_int("ssch failed with cc=", rc);
 345        return rc;
 346    }
 347
 348    consume_io_int();
 349
 350    /* collect status */
 351    rc = tsch(schid, irb);
 352    if (rc) {
 353        print_int("tsch failed with cc=", rc);
 354    }
 355
 356    return rc;
 357}
 358
 359/*
 360 * Executes a channel program at a given subchannel. The request to run the
 361 * channel program is sent to the subchannel, we then wait for the interrupt
 362 * signaling completion of the I/O operation(s) performed by the channel
 363 * program. Lastly we verify that the i/o operation completed without error and
 364 * that the interrupt we received was for the subchannel used to run the
 365 * channel program.
 366 *
 367 * Note: This function assumes it is running in an environment where no other
 368 * cpus are generating or receiving I/O interrupts. So either run it in a
 369 * single-cpu environment or make sure all other cpus are not doing I/O and
 370 * have I/O interrupts masked off. We also assume that only one device is
 371 * active (generating i/o interrupts).
 372 *
 373 * Returns non-zero on error.
 374 */
 375int do_cio(SubChannelId schid, uint16_t cutype, uint32_t ccw_addr, int fmt)
 376{
 377    Irb irb = {};
 378    SenseDataEckdDasd sd;
 379    int rc, retries = 0;
 380
 381    while (true) {
 382        rc = __do_cio(schid, ccw_addr, fmt, &irb);
 383
 384        if (rc == -1) {
 385            retries++;
 386            continue;
 387        }
 388        if (rc) {
 389            /* ssch/tsch error. Message already reported by __do_cio */
 390            break;
 391        }
 392
 393        if (!irb_error(&irb)) {
 394            break;
 395        }
 396
 397        /*
 398         * Unexpected unit check, or interface-control-check. Use sense to
 399         * clear (unit check only) then retry.
 400         */
 401        if ((unit_check(&irb) || iface_ctrl_check(&irb)) && retries <= 2) {
 402            if (unit_check(&irb)) {
 403                basic_sense(schid, cutype, &sd, sizeof(sd));
 404            }
 405            retries++;
 406            continue;
 407        }
 408
 409        sclp_print("cio device error\n");
 410        print_int("  ssid  ", schid.ssid);
 411        print_int("  cssid ", schid.cssid);
 412        print_int("  sch_no", schid.sch_no);
 413        print_int("  ctrl-unit type", cutype);
 414        sclp_print("\n");
 415        print_irb_err(&irb);
 416        if (cutype == CU_TYPE_DASD_3990 || cutype == CU_TYPE_DASD_2107 ||
 417            cutype == CU_TYPE_UNKNOWN) {
 418            if (!basic_sense(schid, cutype, &sd, sizeof(sd))) {
 419                print_eckd_dasd_sense_data(&sd);
 420            }
 421        }
 422        rc = -1;
 423        break;
 424    }
 425
 426    return rc;
 427}
 428