xref: /openbmc/qemu/pc-bios/s390-ccw/cio.c (revision e17e57e862faf6e1f372385c18dcf6d3fd31158e)
1120d0410SJason J. Herne /*
2120d0410SJason J. Herne  * S390 Channel I/O
3120d0410SJason J. Herne  *
4120d0410SJason J. Herne  * Copyright (c) 2013 Alexander Graf <agraf@suse.de>
5120d0410SJason J. Herne  * Copyright (c) 2019 IBM Corp.
6120d0410SJason J. Herne  *
7120d0410SJason J. Herne  * Author(s): Jason J. Herne <jjherne@us.ibm.com>
8120d0410SJason J. Herne  *
9120d0410SJason J. Herne  * This work is licensed under the terms of the GNU GPL, version 2 or (at
10120d0410SJason J. Herne  * your option) any later version. See the COPYING file in the top-level
11120d0410SJason J. Herne  * directory.
12120d0410SJason J. Herne  */
13120d0410SJason J. Herne 
149f427883SJared Rossi #include <string.h>
159f427883SJared Rossi #include <stdio.h>
16120d0410SJason J. Herne #include "s390-ccw.h"
173083a1bbSJason J. Herne #include "s390-arch.h"
183083a1bbSJason J. Herne #include "helper.h"
19120d0410SJason J. Herne #include "cio.h"
20120d0410SJason J. Herne 
21120d0410SJason J. Herne static char chsc_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
22120d0410SJason J. Herne 
233083a1bbSJason J. Herne static int __do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt, Irb *irb);
243083a1bbSJason J. Herne 
enable_mss_facility(void)25120d0410SJason J. Herne int enable_mss_facility(void)
26120d0410SJason J. Herne {
27120d0410SJason J. Herne     int ret;
28120d0410SJason J. Herne     ChscAreaSda *sda_area = (ChscAreaSda *) chsc_page;
29120d0410SJason J. Herne 
30120d0410SJason J. Herne     memset(sda_area, 0, PAGE_SIZE);
31120d0410SJason J. Herne     sda_area->request.length = 0x0400;
32120d0410SJason J. Herne     sda_area->request.code = 0x0031;
33120d0410SJason J. Herne     sda_area->operation_code = 0x2;
34120d0410SJason J. Herne 
35120d0410SJason J. Herne     ret = chsc(sda_area);
36120d0410SJason J. Herne     if ((ret == 0) && (sda_area->response.code == 0x0001)) {
37120d0410SJason J. Herne         return 0;
38120d0410SJason J. Herne     }
39120d0410SJason J. Herne     return -EIO;
40120d0410SJason J. Herne }
41120d0410SJason J. Herne 
enable_subchannel(SubChannelId schid)42120d0410SJason J. Herne void enable_subchannel(SubChannelId schid)
43120d0410SJason J. Herne {
44120d0410SJason J. Herne     Schib schib;
45120d0410SJason J. Herne 
46120d0410SJason J. Herne     stsch_err(schid, &schib);
47120d0410SJason J. Herne     schib.pmcw.ena = 1;
48120d0410SJason J. Herne     msch(schid, &schib);
49120d0410SJason J. Herne }
503083a1bbSJason J. Herne 
cu_type(SubChannelId schid)513083a1bbSJason J. Herne uint16_t cu_type(SubChannelId schid)
523083a1bbSJason J. Herne {
533083a1bbSJason J. Herne     SenseId sense_data;
548c6cc7b9SJanosch Frank     Ccw1 sense_id_ccw = {
558c6cc7b9SJanosch Frank         .cmd_code = CCW_CMD_SENSE_ID,
568c6cc7b9SJanosch Frank         .flags = CCW_FLAG_SLI,
578c6cc7b9SJanosch Frank         .count = sizeof(sense_data),
588c6cc7b9SJanosch Frank         .cda = ptr2u32(&sense_data),
598c6cc7b9SJanosch Frank     };
603083a1bbSJason J. Herne 
613083a1bbSJason J. Herne     if (do_cio(schid, CU_TYPE_UNKNOWN, ptr2u32(&sense_id_ccw), CCW_FMT1)) {
62*0181e237SJared Rossi         puts("Failed to run SenseID CCW");
63*0181e237SJared Rossi         return CU_TYPE_UNKNOWN;
643083a1bbSJason J. Herne     }
653083a1bbSJason J. Herne 
663083a1bbSJason J. Herne     return sense_data.cu_type;
673083a1bbSJason J. Herne }
683083a1bbSJason J. Herne 
basic_sense(SubChannelId schid,uint16_t cutype,void * sense_data,uint16_t data_size)693083a1bbSJason J. Herne int basic_sense(SubChannelId schid, uint16_t cutype, void *sense_data,
703083a1bbSJason J. Herne                  uint16_t data_size)
713083a1bbSJason J. Herne {
728c6cc7b9SJanosch Frank     Ccw1 senseCcw = {
738c6cc7b9SJanosch Frank         .cmd_code = CCW_CMD_BASIC_SENSE,
748c6cc7b9SJanosch Frank         .count = data_size,
758c6cc7b9SJanosch Frank         .cda = ptr2u32(sense_data),
768c6cc7b9SJanosch Frank     };
773083a1bbSJason J. Herne     Irb irb;
783083a1bbSJason J. Herne 
793083a1bbSJason J. Herne     return __do_cio(schid, ptr2u32(&senseCcw), CCW_FMT1, &irb);
803083a1bbSJason J. Herne }
813083a1bbSJason J. Herne 
irb_error(Irb * irb)823083a1bbSJason J. Herne static bool irb_error(Irb *irb)
833083a1bbSJason J. Herne {
843083a1bbSJason J. Herne     if (irb->scsw.cstat) {
853083a1bbSJason J. Herne         return true;
863083a1bbSJason J. Herne     }
873083a1bbSJason J. Herne     return irb->scsw.dstat != (SCSW_DSTAT_DEVEND | SCSW_DSTAT_CHEND);
883083a1bbSJason J. Herne }
893083a1bbSJason J. Herne 
print_eckd_dasd_sense_data(SenseDataEckdDasd * sd)9086c58705SJason J. Herne static void print_eckd_dasd_sense_data(SenseDataEckdDasd *sd)
9186c58705SJason J. Herne {
9286c58705SJason J. Herne     char msgline[512];
9386c58705SJason J. Herne 
9486c58705SJason J. Herne     if (sd->config_info & 0x8000) {
959f427883SJared Rossi         puts("Eckd Dasd Sense Data (fmt 24-bytes):");
9686c58705SJason J. Herne     } else {
979f427883SJared Rossi         puts("Eckd Dasd Sense Data (fmt 32-bytes):");
9886c58705SJason J. Herne     }
9986c58705SJason J. Herne 
10086c58705SJason J. Herne     strcat(msgline, "    Sense Condition Flags :");
10186c58705SJason J. Herne     if (sd->common_status & SNS_STAT0_CMD_REJECT) {
10286c58705SJason J. Herne         strcat(msgline, " [Cmd-Reject]");
10386c58705SJason J. Herne     }
10486c58705SJason J. Herne     if (sd->common_status & SNS_STAT0_INTERVENTION_REQ) {
10586c58705SJason J. Herne         strcat(msgline, " [Intervention-Required]");
10686c58705SJason J. Herne     }
10786c58705SJason J. Herne     if (sd->common_status & SNS_STAT0_BUS_OUT_CHECK) {
10886c58705SJason J. Herne         strcat(msgline, " [Bus-Out-Parity-Check]");
10986c58705SJason J. Herne     }
11086c58705SJason J. Herne     if (sd->common_status & SNS_STAT0_EQUIPMENT_CHECK) {
11186c58705SJason J. Herne         strcat(msgline, " [Equipment-Check]");
11286c58705SJason J. Herne     }
11386c58705SJason J. Herne     if (sd->common_status & SNS_STAT0_DATA_CHECK) {
11486c58705SJason J. Herne         strcat(msgline, " [Data-Check]");
11586c58705SJason J. Herne     }
11686c58705SJason J. Herne     if (sd->common_status & SNS_STAT0_OVERRUN) {
11786c58705SJason J. Herne         strcat(msgline, " [Overrun]");
11886c58705SJason J. Herne     }
11986c58705SJason J. Herne     if (sd->common_status & SNS_STAT0_INCOMPL_DOMAIN) {
12086c58705SJason J. Herne         strcat(msgline, " [Incomplete-Domain]");
12186c58705SJason J. Herne     }
12286c58705SJason J. Herne 
12386c58705SJason J. Herne     if (sd->status[0] & SNS_STAT1_PERM_ERR) {
12486c58705SJason J. Herne         strcat(msgline, " [Permanent-Error]");
12586c58705SJason J. Herne     }
12686c58705SJason J. Herne     if (sd->status[0] & SNS_STAT1_INV_TRACK_FORMAT) {
12786c58705SJason J. Herne         strcat(msgline, " [Invalid-Track-Fmt]");
12886c58705SJason J. Herne     }
12986c58705SJason J. Herne     if (sd->status[0] & SNS_STAT1_EOC) {
13086c58705SJason J. Herne         strcat(msgline, " [End-of-Cyl]");
13186c58705SJason J. Herne     }
13286c58705SJason J. Herne     if (sd->status[0] & SNS_STAT1_MESSAGE_TO_OPER) {
13386c58705SJason J. Herne         strcat(msgline, " [Operator-Msg]");
13486c58705SJason J. Herne     }
13586c58705SJason J. Herne     if (sd->status[0] & SNS_STAT1_NO_REC_FOUND) {
13686c58705SJason J. Herne         strcat(msgline, " [No-Record-Found]");
13786c58705SJason J. Herne     }
13886c58705SJason J. Herne     if (sd->status[0] & SNS_STAT1_FILE_PROTECTED) {
13986c58705SJason J. Herne         strcat(msgline, " [File-Protected]");
14086c58705SJason J. Herne     }
14186c58705SJason J. Herne     if (sd->status[0] & SNS_STAT1_WRITE_INHIBITED) {
14286c58705SJason J. Herne         strcat(msgline, " [Write-Inhibited]");
14386c58705SJason J. Herne     }
14486c58705SJason J. Herne     if (sd->status[0] & SNS_STAT1_IMPRECISE_END) {
14586c58705SJason J. Herne         strcat(msgline, " [Imprecise-Ending]");
14686c58705SJason J. Herne     }
14786c58705SJason J. Herne 
14886c58705SJason J. Herne     if (sd->status[1] & SNS_STAT2_REQ_INH_WRITE) {
14986c58705SJason J. Herne         strcat(msgline, " [Req-Inhibit-Write]");
15086c58705SJason J. Herne     }
15186c58705SJason J. Herne     if (sd->status[1] & SNS_STAT2_CORRECTABLE) {
15286c58705SJason J. Herne         strcat(msgline, " [Correctable-Data-Check]");
15386c58705SJason J. Herne     }
15486c58705SJason J. Herne     if (sd->status[1] & SNS_STAT2_FIRST_LOG_ERR) {
15586c58705SJason J. Herne         strcat(msgline, " [First-Error-Log]");
15686c58705SJason J. Herne     }
15786c58705SJason J. Herne     if (sd->status[1] & SNS_STAT2_ENV_DATA_PRESENT) {
15886c58705SJason J. Herne         strcat(msgline, " [Env-Data-Present]");
15986c58705SJason J. Herne     }
16086c58705SJason J. Herne     if (sd->status[1] & SNS_STAT2_IMPRECISE_END) {
16186c58705SJason J. Herne         strcat(msgline, " [Imprecise-End]");
16286c58705SJason J. Herne     }
1639f427883SJared Rossi     puts(msgline);
16486c58705SJason J. Herne 
1659f427883SJared Rossi     printf("    Residual Count     = 0x%X\n", sd->res_count);
1669f427883SJared Rossi     printf("    Phys Drive ID      = 0x%X\n", sd->phys_drive_id);
1679f427883SJared Rossi     printf("    low cyl address    = 0x%X\n", sd->low_cyl_addr);
1689f427883SJared Rossi     printf("    head addr & hi cyl = 0x%X\n", sd->head_high_cyl_addr);
1699f427883SJared Rossi     printf("    format/message     = 0x%X\n", sd->fmt_msg);
1709f427883SJared Rossi     printf("    fmt-dependent[0-7] = 0x%llX\n", sd->fmt_dependent_info[0]);
1719f427883SJared Rossi     printf("    fmt-dependent[8-15]= 0x%llX\n", sd->fmt_dependent_info[1]);
1729f427883SJared Rossi     printf("    prog action code   = 0x%X\n", sd->program_action_code);
1739f427883SJared Rossi     printf("    Configuration info = 0x%X\n", sd->config_info);
1749f427883SJared Rossi     printf("    mcode / hi-cyl     = 0x%X\n", sd->mcode_hicyl);
1759f427883SJared Rossi     printf("    cyl & head addr [0]= 0x%X\n", sd->cyl_head_addr[0]);
1769f427883SJared Rossi     printf("    cyl & head addr [1]= 0x%X\n", sd->cyl_head_addr[1]);
1779f427883SJared Rossi     printf("    cyl & head addr [2]= 0x%X\n", sd->cyl_head_addr[2]);
17886c58705SJason J. Herne }
17986c58705SJason J. Herne 
print_irb_err(Irb * irb)18086c58705SJason J. Herne static void print_irb_err(Irb *irb)
18186c58705SJason J. Herne {
18286c58705SJason J. Herne     uint64_t this_ccw = *(uint64_t *)u32toptr(irb->scsw.cpa);
18386c58705SJason J. Herne     uint64_t prev_ccw = *(uint64_t *)u32toptr(irb->scsw.cpa - 8);
18486c58705SJason J. Herne     char msgline[256];
18586c58705SJason J. Herne 
1869f427883SJared Rossi     puts("Interrupt Response Block Data:");
18786c58705SJason J. Herne 
18886c58705SJason J. Herne     strcat(msgline, "    Function Ctrl :");
18986c58705SJason J. Herne     if (irb->scsw.ctrl & SCSW_FCTL_START_FUNC) {
19086c58705SJason J. Herne         strcat(msgline, " [Start]");
19186c58705SJason J. Herne     }
19286c58705SJason J. Herne     if (irb->scsw.ctrl & SCSW_FCTL_HALT_FUNC) {
19386c58705SJason J. Herne         strcat(msgline, " [Halt]");
19486c58705SJason J. Herne     }
19586c58705SJason J. Herne     if (irb->scsw.ctrl & SCSW_FCTL_CLEAR_FUNC) {
19686c58705SJason J. Herne         strcat(msgline, " [Clear]");
19786c58705SJason J. Herne     }
1989f427883SJared Rossi     puts(msgline);
19986c58705SJason J. Herne 
20086c58705SJason J. Herne     msgline[0] = '\0';
20186c58705SJason J. Herne     strcat(msgline, "    Activity Ctrl :");
20286c58705SJason J. Herne     if (irb->scsw.ctrl & SCSW_ACTL_RESUME_PEND) {
20386c58705SJason J. Herne         strcat(msgline, " [Resume-Pending]");
20486c58705SJason J. Herne     }
20586c58705SJason J. Herne     if (irb->scsw.ctrl & SCSW_ACTL_START_PEND) {
20686c58705SJason J. Herne         strcat(msgline, " [Start-Pending]");
20786c58705SJason J. Herne     }
20886c58705SJason J. Herne     if (irb->scsw.ctrl & SCSW_ACTL_HALT_PEND) {
20986c58705SJason J. Herne         strcat(msgline, " [Halt-Pending]");
21086c58705SJason J. Herne     }
21186c58705SJason J. Herne     if (irb->scsw.ctrl & SCSW_ACTL_CLEAR_PEND) {
21286c58705SJason J. Herne         strcat(msgline, " [Clear-Pending]");
21386c58705SJason J. Herne     }
21486c58705SJason J. Herne     if (irb->scsw.ctrl & SCSW_ACTL_CH_ACTIVE) {
21586c58705SJason J. Herne         strcat(msgline, " [Channel-Active]");
21686c58705SJason J. Herne     }
21786c58705SJason J. Herne     if (irb->scsw.ctrl & SCSW_ACTL_DEV_ACTIVE) {
21886c58705SJason J. Herne         strcat(msgline, " [Device-Active]");
21986c58705SJason J. Herne     }
22086c58705SJason J. Herne     if (irb->scsw.ctrl & SCSW_ACTL_SUSPENDED) {
22186c58705SJason J. Herne         strcat(msgline, " [Suspended]");
22286c58705SJason J. Herne     }
2239f427883SJared Rossi     puts(msgline);
22486c58705SJason J. Herne 
22586c58705SJason J. Herne     msgline[0] = '\0';
22686c58705SJason J. Herne     strcat(msgline, "    Status Ctrl :");
22786c58705SJason J. Herne     if (irb->scsw.ctrl & SCSW_SCTL_ALERT) {
22886c58705SJason J. Herne         strcat(msgline, " [Alert]");
22986c58705SJason J. Herne     }
23086c58705SJason J. Herne     if (irb->scsw.ctrl & SCSW_SCTL_INTERMED) {
23186c58705SJason J. Herne         strcat(msgline, " [Intermediate]");
23286c58705SJason J. Herne     }
23386c58705SJason J. Herne     if (irb->scsw.ctrl & SCSW_SCTL_PRIMARY) {
23486c58705SJason J. Herne         strcat(msgline, " [Primary]");
23586c58705SJason J. Herne     }
23686c58705SJason J. Herne     if (irb->scsw.ctrl & SCSW_SCTL_SECONDARY) {
23786c58705SJason J. Herne         strcat(msgline, " [Secondary]");
23886c58705SJason J. Herne     }
23986c58705SJason J. Herne     if (irb->scsw.ctrl & SCSW_SCTL_STATUS_PEND) {
24086c58705SJason J. Herne         strcat(msgline, " [Status-Pending]");
24186c58705SJason J. Herne     }
2429f427883SJared Rossi     puts(msgline);
24386c58705SJason J. Herne 
24486c58705SJason J. Herne     msgline[0] = '\0';
24586c58705SJason J. Herne     strcat(msgline, "    Device Status :");
24686c58705SJason J. Herne     if (irb->scsw.dstat & SCSW_DSTAT_ATTN) {
24786c58705SJason J. Herne         strcat(msgline, " [Attention]");
24886c58705SJason J. Herne     }
24986c58705SJason J. Herne     if (irb->scsw.dstat & SCSW_DSTAT_STATMOD) {
25086c58705SJason J. Herne         strcat(msgline, " [Status-Modifier]");
25186c58705SJason J. Herne     }
25286c58705SJason J. Herne     if (irb->scsw.dstat & SCSW_DSTAT_CUEND) {
25386c58705SJason J. Herne         strcat(msgline, " [Ctrl-Unit-End]");
25486c58705SJason J. Herne     }
25586c58705SJason J. Herne     if (irb->scsw.dstat & SCSW_DSTAT_BUSY) {
25686c58705SJason J. Herne         strcat(msgline, " [Busy]");
25786c58705SJason J. Herne     }
25886c58705SJason J. Herne     if (irb->scsw.dstat & SCSW_DSTAT_CHEND) {
25986c58705SJason J. Herne         strcat(msgline, " [Channel-End]");
26086c58705SJason J. Herne     }
26186c58705SJason J. Herne     if (irb->scsw.dstat & SCSW_DSTAT_DEVEND) {
26286c58705SJason J. Herne         strcat(msgline, " [Device-End]");
26386c58705SJason J. Herne     }
26486c58705SJason J. Herne     if (irb->scsw.dstat & SCSW_DSTAT_UCHK) {
26586c58705SJason J. Herne         strcat(msgline, " [Unit-Check]");
26686c58705SJason J. Herne     }
26786c58705SJason J. Herne     if (irb->scsw.dstat & SCSW_DSTAT_UEXCP) {
26886c58705SJason J. Herne         strcat(msgline, " [Unit-Exception]");
26986c58705SJason J. Herne     }
2709f427883SJared Rossi     puts(msgline);
27186c58705SJason J. Herne 
27286c58705SJason J. Herne     msgline[0] = '\0';
27386c58705SJason J. Herne     strcat(msgline, "    Channel Status :");
27486c58705SJason J. Herne     if (irb->scsw.cstat & SCSW_CSTAT_PCINT) {
27586c58705SJason J. Herne         strcat(msgline, " [Program-Ctrl-Interruption]");
27686c58705SJason J. Herne     }
27786c58705SJason J. Herne     if (irb->scsw.cstat & SCSW_CSTAT_BADLEN) {
27886c58705SJason J. Herne         strcat(msgline, " [Incorrect-Length]");
27986c58705SJason J. Herne     }
28086c58705SJason J. Herne     if (irb->scsw.cstat & SCSW_CSTAT_PROGCHK) {
28186c58705SJason J. Herne         strcat(msgline, " [Program-Check]");
28286c58705SJason J. Herne     }
28386c58705SJason J. Herne     if (irb->scsw.cstat & SCSW_CSTAT_PROTCHK) {
28486c58705SJason J. Herne         strcat(msgline, " [Protection-Check]");
28586c58705SJason J. Herne     }
28686c58705SJason J. Herne     if (irb->scsw.cstat & SCSW_CSTAT_CHDCHK) {
28786c58705SJason J. Herne         strcat(msgline, " [Channel-Data-Check]");
28886c58705SJason J. Herne     }
28986c58705SJason J. Herne     if (irb->scsw.cstat & SCSW_CSTAT_CHCCHK) {
29086c58705SJason J. Herne         strcat(msgline, " [Channel-Ctrl-Check]");
29186c58705SJason J. Herne     }
29286c58705SJason J. Herne     if (irb->scsw.cstat & SCSW_CSTAT_ICCHK) {
29386c58705SJason J. Herne         strcat(msgline, " [Interface-Ctrl-Check]");
29486c58705SJason J. Herne     }
29586c58705SJason J. Herne     if (irb->scsw.cstat & SCSW_CSTAT_CHAINCHK) {
29686c58705SJason J. Herne         strcat(msgline, " [Chaining-Check]");
29786c58705SJason J. Herne     }
2989f427883SJared Rossi     puts(msgline);
29986c58705SJason J. Herne 
3009f427883SJared Rossi     printf("    cpa= 0x%X\n", irb->scsw.cpa);
3019f427883SJared Rossi     printf("    prev_ccw= 0x%llX\n", prev_ccw);
3029f427883SJared Rossi     printf("    this_ccw= 0x%llX\n", this_ccw);
30386c58705SJason J. Herne }
30486c58705SJason J. Herne 
3053083a1bbSJason J. Herne /*
3063083a1bbSJason J. Herne  * Handles executing ssch, tsch and returns the irb obtained from tsch.
3073083a1bbSJason J. Herne  * Returns 0 on success, -1 if unexpected status pending and we need to retry,
3083083a1bbSJason J. Herne  * otherwise returns condition code from ssch/tsch for error cases.
3093083a1bbSJason J. Herne  */
__do_cio(SubChannelId schid,uint32_t ccw_addr,int fmt,Irb * irb)3103083a1bbSJason J. Herne static int __do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt, Irb *irb)
3113083a1bbSJason J. Herne {
3128c6cc7b9SJanosch Frank     /*
3138c6cc7b9SJanosch Frank      * QEMU's CIO implementation requires prefetch and 64-bit idaws. We
3148c6cc7b9SJanosch Frank      * allow all paths.
3158c6cc7b9SJanosch Frank      */
3168c6cc7b9SJanosch Frank     CmdOrb orb = {
3178c6cc7b9SJanosch Frank         .fmt = fmt,
3188c6cc7b9SJanosch Frank         .pfch = 1,
3198c6cc7b9SJanosch Frank         .c64 = 1,
3208c6cc7b9SJanosch Frank         .lpm = 0xFF,
3218c6cc7b9SJanosch Frank         .cpa = ccw_addr,
3228c6cc7b9SJanosch Frank     };
3233083a1bbSJason J. Herne     int rc;
3243083a1bbSJason J. Herne 
3253083a1bbSJason J. Herne     IPL_assert(fmt == 0 || fmt == 1, "Invalid ccw format");
3263083a1bbSJason J. Herne 
3273083a1bbSJason J. Herne     /* ccw_addr must be <= 24 bits and point to at least one whole ccw. */
3283083a1bbSJason J. Herne     if (fmt == 0) {
3293083a1bbSJason J. Herne         IPL_assert(ccw_addr <= 0xFFFFFF - 8, "Invalid ccw address");
3303083a1bbSJason J. Herne     }
3313083a1bbSJason J. Herne 
3323083a1bbSJason J. Herne     rc = ssch(schid, &orb);
3333083a1bbSJason J. Herne     if (rc == 1 || rc == 2) {
3343083a1bbSJason J. Herne         /* Subchannel status pending or busy. Eat status and ask for retry. */
3353083a1bbSJason J. Herne         tsch(schid, irb);
3363083a1bbSJason J. Herne         return -1;
3373083a1bbSJason J. Herne     }
3383083a1bbSJason J. Herne     if (rc) {
3399f427883SJared Rossi         printf("ssch failed with cc= 0x%x\n", rc);
3403083a1bbSJason J. Herne         return rc;
3413083a1bbSJason J. Herne     }
3423083a1bbSJason J. Herne 
3433083a1bbSJason J. Herne     consume_io_int();
3443083a1bbSJason J. Herne 
3453083a1bbSJason J. Herne     /* collect status */
3463083a1bbSJason J. Herne     rc = tsch(schid, irb);
3473083a1bbSJason J. Herne     if (rc) {
3489f427883SJared Rossi         printf("tsch failed with cc= 0x%X\n", rc);
3493083a1bbSJason J. Herne     }
3503083a1bbSJason J. Herne 
3513083a1bbSJason J. Herne     return rc;
3523083a1bbSJason J. Herne }
3533083a1bbSJason J. Herne 
3543083a1bbSJason J. Herne /*
3553083a1bbSJason J. Herne  * Executes a channel program at a given subchannel. The request to run the
3563083a1bbSJason J. Herne  * channel program is sent to the subchannel, we then wait for the interrupt
3573083a1bbSJason J. Herne  * signaling completion of the I/O operation(s) performed by the channel
3583083a1bbSJason J. Herne  * program. Lastly we verify that the i/o operation completed without error and
3593083a1bbSJason J. Herne  * that the interrupt we received was for the subchannel used to run the
3603083a1bbSJason J. Herne  * channel program.
3613083a1bbSJason J. Herne  *
3623083a1bbSJason J. Herne  * Note: This function assumes it is running in an environment where no other
3633083a1bbSJason J. Herne  * cpus are generating or receiving I/O interrupts. So either run it in a
3643083a1bbSJason J. Herne  * single-cpu environment or make sure all other cpus are not doing I/O and
3653083a1bbSJason J. Herne  * have I/O interrupts masked off. We also assume that only one device is
3663083a1bbSJason J. Herne  * active (generating i/o interrupts).
3673083a1bbSJason J. Herne  *
3683083a1bbSJason J. Herne  * Returns non-zero on error.
3693083a1bbSJason J. Herne  */
do_cio(SubChannelId schid,uint16_t cutype,uint32_t ccw_addr,int fmt)3703083a1bbSJason J. Herne int do_cio(SubChannelId schid, uint16_t cutype, uint32_t ccw_addr, int fmt)
3713083a1bbSJason J. Herne {
3723083a1bbSJason J. Herne     Irb irb = {};
3733083a1bbSJason J. Herne     SenseDataEckdDasd sd;
3743083a1bbSJason J. Herne     int rc, retries = 0;
3753083a1bbSJason J. Herne 
3763083a1bbSJason J. Herne     while (true) {
3773083a1bbSJason J. Herne         rc = __do_cio(schid, ccw_addr, fmt, &irb);
3783083a1bbSJason J. Herne 
3793083a1bbSJason J. Herne         if (rc == -1) {
3803083a1bbSJason J. Herne             retries++;
3813083a1bbSJason J. Herne             continue;
3823083a1bbSJason J. Herne         }
3833083a1bbSJason J. Herne         if (rc) {
3843083a1bbSJason J. Herne             /* ssch/tsch error. Message already reported by __do_cio */
3853083a1bbSJason J. Herne             break;
3863083a1bbSJason J. Herne         }
3873083a1bbSJason J. Herne 
3883083a1bbSJason J. Herne         if (!irb_error(&irb)) {
3893083a1bbSJason J. Herne             break;
3903083a1bbSJason J. Herne         }
3913083a1bbSJason J. Herne 
3923083a1bbSJason J. Herne         /*
3933083a1bbSJason J. Herne          * Unexpected unit check, or interface-control-check. Use sense to
3943083a1bbSJason J. Herne          * clear (unit check only) then retry.
3953083a1bbSJason J. Herne          */
3963083a1bbSJason J. Herne         if ((unit_check(&irb) || iface_ctrl_check(&irb)) && retries <= 2) {
3973083a1bbSJason J. Herne             if (unit_check(&irb)) {
3983083a1bbSJason J. Herne                 basic_sense(schid, cutype, &sd, sizeof(sd));
3993083a1bbSJason J. Herne             }
4003083a1bbSJason J. Herne             retries++;
4013083a1bbSJason J. Herne             continue;
4023083a1bbSJason J. Herne         }
4033083a1bbSJason J. Herne 
4049f427883SJared Rossi         printf("cio device error\n");
4059f427883SJared Rossi         printf("  ssid  0x%X\n", schid.ssid);
4069f427883SJared Rossi         printf("  cssid 0x%X\n", schid.cssid);
4079f427883SJared Rossi         printf("  sch_no 0x%X\n", schid.sch_no);
4089f427883SJared Rossi         printf("  ctrl-unit type 0x%X\n", cutype);
4099f427883SJared Rossi         printf("\n");
41086c58705SJason J. Herne         print_irb_err(&irb);
41186c58705SJason J. Herne         if (cutype == CU_TYPE_DASD_3990 || cutype == CU_TYPE_DASD_2107 ||
41286c58705SJason J. Herne             cutype == CU_TYPE_UNKNOWN) {
41386c58705SJason J. Herne             if (!basic_sense(schid, cutype, &sd, sizeof(sd))) {
41486c58705SJason J. Herne                 print_eckd_dasd_sense_data(&sd);
41586c58705SJason J. Herne             }
41686c58705SJason J. Herne         }
4173083a1bbSJason J. Herne         rc = -1;
4183083a1bbSJason J. Herne         break;
4193083a1bbSJason J. Herne     }
4203083a1bbSJason J. Herne 
4213083a1bbSJason J. Herne     return rc;
4223083a1bbSJason J. Herne }
423