| /* SPDX-License-Identifier: GPL-2.0-only */ | |
| /* | |
| * Channel subsystem structures dumping | |
| * | |
| * Copyright (c) 2020 IBM Corp. | |
| * | |
| * Authors: | |
| * Pierre Morel <pmorel@linux.ibm.com> | |
| * | |
| * Description: | |
| * Provides the dumping functions for various structures used by subchannels: | |
| * - ORB : Operation request block, describes the I/O operation and points to | |
| * a CCW chain | |
| * - CCW : Channel Command Word, describes the command, data and flow control | |
| * - IRB : Interuption response Block, describes the result of an operation; | |
| * holds a SCSW and model-dependent data. | |
| * - SCHIB: SubCHannel Information Block composed of: | |
| * - SCSW: SubChannel Status Word, status of the channel. | |
| * - PMCW: Path Management Control Word | |
| * You need the QEMU ccw-pong device in QEMU to answer the I/O transfers. | |
| */ | |
| #include <libcflat.h> | |
| #include <stdint.h> | |
| #include <string.h> | |
| #include <css.h> | |
| /* | |
| * Try to have a more human representation of the SCSW flags: | |
| * each letter in the two strings represents the first | |
| * letter of the associated bit in the flag fields. | |
| */ | |
| static const char *scsw_str = "kkkkslccfpixuzen"; | |
| static const char *scsw_str2 = "1SHCrshcsdsAIPSs"; | |
| static char scsw_line[64] = {}; | |
| char *dump_scsw_flags(uint32_t f) | |
| { | |
| int i; | |
| for (i = 0; i < 16; i++) { | |
| if ((f << i) & 0x80000000) | |
| scsw_line[i] = scsw_str[i]; | |
| else | |
| scsw_line[i] = '_'; | |
| } | |
| scsw_line[i] = ' '; | |
| for (; i < 32; i++) { | |
| if ((f << i) & 0x80000000) | |
| scsw_line[i + 1] = scsw_str2[i - 16]; | |
| else | |
| scsw_line[i + 1] = '_'; | |
| } | |
| return scsw_line; | |
| } | |
| /* | |
| * Try to have a more human representation of the PMCW flags | |
| * each letter in the string represents the first | |
| * letter of the associated bit in the flag fields. | |
| */ | |
| static const char *pmcw_str = "11iii111ellmmdtv"; | |
| static char pcmw_line[32] = {}; | |
| char *dump_pmcw_flags(uint16_t f) | |
| { | |
| int i; | |
| for (i = 0; i < 16; i++) { | |
| if ((f << i) & 0x8000) | |
| pcmw_line[i] = pmcw_str[i]; | |
| else | |
| pcmw_line[i] = '_'; | |
| } | |
| return pcmw_line; | |
| } | |
| void dump_scsw(struct scsw *s) | |
| { | |
| dump_scsw_flags(s->ctrl); | |
| printf("scsw->flags: %s\n", scsw_line); | |
| printf("scsw->addr : %08x\n", s->ccw_addr); | |
| printf("scsw->devs : %02x\n", s->dev_stat); | |
| printf("scsw->schs : %02x\n", s->sch_stat); | |
| printf("scsw->count: %04x\n", s->count); | |
| } | |
| void dump_irb(struct irb *irbp) | |
| { | |
| int i; | |
| uint32_t *p = (uint32_t *)irbp; | |
| dump_scsw(&irbp->scsw); | |
| for (i = 0; i < sizeof(*irbp)/sizeof(*p); i++, p++) | |
| printf("irb[%02x] : %08x\n", i, *p); | |
| } | |
| void dump_pmcw(struct pmcw *p) | |
| { | |
| int i; | |
| printf("pmcw->intparm : %08x\n", p->intparm); | |
| printf("pmcw->flags : %04x\n", p->flags); | |
| dump_pmcw_flags(p->flags); | |
| printf("pmcw->devnum : %04x\n", p->devnum); | |
| printf("pmcw->lpm : %02x\n", p->lpm); | |
| printf("pmcw->pnom : %02x\n", p->pnom); | |
| printf("pmcw->lpum : %02x\n", p->lpum); | |
| printf("pmcw->pim : %02x\n", p->pim); | |
| printf("pmcw->mbi : %04x\n", p->mbi); | |
| printf("pmcw->pom : %02x\n", p->pom); | |
| printf("pmcw->pam : %02x\n", p->pam); | |
| printf("pmcw->mbi : %04x\n", p->mbi); | |
| for (i = 0; i < 8; i++) | |
| printf("pmcw->chpid[%d]: %02x\n", i, p->chpid[i]); | |
| printf("pmcw->flags2 : %08x\n", p->flags2); | |
| } | |
| void dump_schib(struct schib *sch) | |
| { | |
| struct pmcw *p = &sch->pmcw; | |
| struct scsw *s = &sch->scsw; | |
| printf("--SCHIB--\n"); | |
| dump_pmcw(p); | |
| dump_scsw(s); | |
| } | |
| struct ccw1 *dump_ccw(struct ccw1 *cp) | |
| { | |
| printf("CCW: code: %02x flags: %02x count: %04x data: %08x\n", cp->code, | |
| cp->flags, cp->count, cp->data_address); | |
| if (cp->code == CCW_C_TIC) | |
| return (struct ccw1 *)(long)cp->data_address; | |
| return (cp->flags & CCW_F_CC) ? cp + 1 : NULL; | |
| } | |
| void dump_orb(struct orb *op) | |
| { | |
| struct ccw1 *cp; | |
| printf("ORB: intparm : %08x\n", op->intparm); | |
| printf("ORB: ctrl : %08x\n", op->ctrl); | |
| printf("ORB: prio : %08x\n", op->prio); | |
| cp = (struct ccw1 *)(long) (op->cpa); | |
| while (cp) | |
| cp = dump_ccw(cp); | |
| } |