qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

cio.c (12733B)


      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 
     20 static char chsc_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
     21 
     22 static int __do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt, Irb *irb);
     23 
     24 int 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 
     41 void 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 
     50 uint16_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 
     67 int 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 
     80 static 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 
     88 static 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 
    179 static 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  */
    315 static 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  */
    375 int 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 }