Add struct for format-0 ccws. Support executing format-0 channel
programs and waiting for their completion before continuing execution.
This will be used for real dasd ipl.
Add cu_type() to channel io library. This will be used to query control
unit type which is used to determine if we are booting a virtio device or a
real dasd device.
Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
---
pc-bios/s390-ccw/cio.c | 141 ++++++++++++++++++++++++++++++++++++++++++++
pc-bios/s390-ccw/cio.h | 127 ++++++++++++++++++++++++++++++++++++++-
pc-bios/s390-ccw/s390-ccw.h | 1 +
pc-bios/s390-ccw/start.S | 31 ++++++++++
4 files changed, 297 insertions(+), 3 deletions(-)
diff --git a/pc-bios/s390-ccw/cio.c b/pc-bios/s390-ccw/cio.c
index 605f6f0..e61cfd3 100644
--- a/pc-bios/s390-ccw/cio.c
+++ b/pc-bios/s390-ccw/cio.c
@@ -12,6 +12,8 @@
#include "libc.h"
#include "s390-ccw.h"
+#include "s390-arch.h"
+#include "helper.h"
#include "cio.h"
static char chsc_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
@@ -41,3 +43,142 @@ void enable_subchannel(SubChannelId schid)
schib.pmcw.ena = 1;
msch(schid, &schib);
}
+
+uint16_t cu_type(SubChannelId schid)
+{
+ Ccw1 sense_id_ccw;
+ SenseId sense_data;
+
+ sense_id_ccw.cmd_code = CCW_CMD_SENSE_ID;
+ sense_id_ccw.cda = ptr2u32(&sense_data);
+ sense_id_ccw.count = sizeof(sense_data);
+ sense_id_ccw.flags |= CCW_FLAG_SLI;
+
+ if (do_cio(schid, ptr2u32(&sense_id_ccw), CCW_FMT1)) {
+ panic("Failed to run SenseID CCw\n");
+ }
+
+ return sense_data.cu_type;
+}
+
+void basic_sense(SubChannelId schid, void *sense_data, uint16_t data_size)
+{
+ Ccw1 senseCcw;
+
+ senseCcw.cmd_code = CCW_CMD_BASIC_SENSE;
+ senseCcw.cda = ptr2u32(sense_data);
+ senseCcw.count = data_size;
+
+ if (do_cio(schid, ptr2u32(&senseCcw), CCW_FMT1)) {
+ panic("Failed to run Basic Sense CCW\n");
+ }
+}
+
+static bool irb_error(Irb *irb)
+{
+ if (irb->scsw.cstat) {
+ return true;
+ }
+ return irb->scsw.dstat != (SCSW_DSTAT_DEVEND | SCSW_DSTAT_CHEND);
+}
+
+/*
+ * Handles executing ssch, tsch and returns the irb obtained from tsch.
+ * Returns 0 on success, -1 if unexpected status pending and we need to retry,
+ * otherwse returns condition code from ssch/tsch for error cases.
+ */
+static int __do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt, Irb *irb)
+{
+ CmdOrb orb = {};
+ int rc;
+
+ IPL_assert(fmt == 0 || fmt == 1, "Invalid ccw format");
+
+ /* ccw_addr must be <= 24 bits and point to at least one whole ccw. */
+ if (fmt == 0) {
+ IPL_assert(ccw_addr <= 0xFFFFFF - 8, "Invalid ccw address");
+ }
+
+ orb.fmt = fmt ;
+ orb.pfch = 1; /* QEMU's cio implementation requires prefetch */
+ orb.c64 = 1; /* QEMU's cio implementation requires 64-bit idaws */
+ orb.lpm = 0xFF; /* All paths allowed */
+ orb.cpa = ccw_addr;
+
+ rc = ssch(schid, &orb);
+ if (rc == 1) {
+ /* Status pending, not sure why. Eat status and ask for retry. */
+ tsch(schid, irb);
+ return -1;
+ }
+ if (rc) {
+ print_int("ssch failed with rc=", rc);
+ return rc;
+ }
+
+ consume_io_int();
+
+ /* collect status */
+ rc = tsch(schid, irb);
+ if (rc) {
+ print_int("tsch failed with rc=", rc);
+ }
+
+ return rc;
+}
+
+/*
+ * Executes a channel program at a given subchannel. The request to run the
+ * channel program is sent to the subchannel, we then wait for the interrupt
+ * signaling completion of the I/O operation(s) performed by the channel
+ * program. Lastly we verify that the i/o operation completed without error and
+ * that the interrupt we received was for the subchannel used to run the
+ * channel program.
+ *
+ * Note: This function assumes it is running in an environment where no other
+ * cpus are generating or receiving I/O interrupts. So either run it in a
+ * single-cpu environment or make sure all other cpus are not doing I/O and
+ * have I/O interrupts masked off.
+ *
+ * Returns non-zero on error.
+ */
+int do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt)
+{
+ Irb irb = {};
+ SenseDataEckdDasd sd;
+ int rc, retries = 0;
+
+ while (true) {
+ rc = __do_cio(schid, ccw_addr, fmt, &irb);
+
+ if (rc == -1) {
+ retries++;
+ continue;
+ }
+ if (rc) {
+ /* ssch/tsch error. Message already reported by __do_cio */
+ break;
+ }
+
+ if (!irb_error(&irb)) {
+ break;
+ }
+
+ /*
+ * Unexpected unit check, or interface-control-check. Use sense to
+ * clear (unit check only) then retry.
+ */
+ if ((unit_check(&irb) || iface_ctrl_check(&irb)) && retries <= 2) {
+ if (unit_check(&irb)) {
+ basic_sense(schid, &sd, sizeof(sd));
+ }
+ retries++;
+ continue;
+ }
+
+ rc = -1;
+ break;
+ }
+
+ return rc;
+}
diff --git a/pc-bios/s390-ccw/cio.h b/pc-bios/s390-ccw/cio.h
index d454050..9de67ec 100644
--- a/pc-bios/s390-ccw/cio.h
+++ b/pc-bios/s390-ccw/cio.h
@@ -70,9 +70,46 @@ struct scsw {
__u16 count;
} __attribute__ ((packed));
-#define SCSW_FCTL_CLEAR_FUNC 0x1000
-#define SCSW_FCTL_HALT_FUNC 0x2000
+/* Function Control */
#define SCSW_FCTL_START_FUNC 0x4000
+#define SCSW_FCTL_HALT_FUNC 0x2000
+#define SCSW_FCTL_CLEAR_FUNC 0x1000
+
+/* Activity Control */
+#define SCSW_ACTL_RESUME_PEND 0x0800
+#define SCSW_ACTL_START_PEND 0x0400
+#define SCSW_ACTL_HALT_PEND 0x0200
+#define SCSW_ACTL_CLEAR_PEND 0x0100
+#define SCSW_ACTL_CH_ACTIVE 0x0080
+#define SCSW_ACTL_DEV_ACTIVE 0x0040
+#define SCSW_ACTL_SUSPENDED 0x0020
+
+/* Status Control */
+#define SCSW_SCTL_ALERT 0x0010
+#define SCSW_SCTL_INTERMED 0x0008
+#define SCSW_SCTL_PRIMARY 0x0004
+#define SCSW_SCTL_SECONDARY 0x0002
+#define SCSW_SCTL_STATUS_PEND 0x0001
+
+/* SCSW Device Status Flags */
+#define SCSW_DSTAT_ATTN 0x80
+#define SCSW_DSTAT_STATMOD 0x40
+#define SCSW_DSTAT_CUEND 0x20
+#define SCSW_DSTAT_BUSY 0x10
+#define SCSW_DSTAT_CHEND 0x08
+#define SCSW_DSTAT_DEVEND 0x04
+#define SCSW_DSTAT_UCHK 0x02
+#define SCSW_DSTAT_UEXCP 0x01
+
+/* SCSW Subchannel Status Flags */
+#define SCSW_CSTAT_PCINT 0x80
+#define SCSW_CSTAT_BADLEN 0x40
+#define SCSW_CSTAT_PROGCHK 0x20
+#define SCSW_CSTAT_PROTCHK 0x10
+#define SCSW_CSTAT_CHDCHK 0x08
+#define SCSW_CSTAT_CHCCHK 0x04
+#define SCSW_CSTAT_ICCHK 0x02
+#define SCSW_CSTAT_CHAINCHK 0x01
/*
* subchannel information block
@@ -127,7 +164,23 @@ struct tpi_info {
__u32 reserved4:12;
} __attribute__ ((packed, aligned(4)));
-/* channel command word (type 1) */
+/* channel command word (format 0) */
+typedef struct ccw0 {
+ __u8 cmd_code;
+ __u32 cda:24;
+ __u32 chainData:1;
+ __u32 chain:1;
+ __u32 sli:1;
+ __u32 skip:1;
+ __u32 pci:1;
+ __u32 ida:1;
+ __u32 suspend:1;
+ __u32 mida:1;
+ __u8 reserved;
+ __u16 count;
+} __attribute__ ((packed, aligned(8))) Ccw0;
+
+/* channel command word (format 1) */
typedef struct ccw1 {
__u8 cmd_code;
__u8 flags;
@@ -135,6 +188,10 @@ typedef struct ccw1 {
__u32 cda;
} __attribute__ ((packed, aligned(8))) Ccw1;
+/* do_cio() CCW formats */
+#define CCW_FMT0 0x00
+#define CCW_FMT1 0x01
+
#define CCW_FLAG_DC 0x80
#define CCW_FLAG_CC 0x40
#define CCW_FLAG_SLI 0x20
@@ -190,6 +247,9 @@ struct ciw {
__u16 count;
};
+#define CU_TYPE_VIRTIO 0x3832
+#define CU_TYPE_DASD_3990 0x3990
+
/*
* sense-id response buffer layout
*/
@@ -205,6 +265,64 @@ typedef struct senseid {
struct ciw ciw[62];
} __attribute__ ((packed, aligned(4))) SenseId;
+/*
+ * architected values for first sense byte - common_status. Bits 0-5 of this
+ * field are common to all device types.
+ */
+#define SNS_STAT0_CMD_REJECT 0x80
+#define SNS_STAT0_INTERVENTION_REQ 0x40
+#define SNS_STAT0_BUS_OUT_CHECK 0x20
+#define SNS_STAT0_EQUIPMENT_CHECK 0x10
+#define SNS_STAT0_DATA_CHECK 0x08
+#define SNS_STAT0_OVERRUN 0x04
+#define SNS_STAT0_INCOMPL_DOMAIN 0x01
+
+/* ECKD DASD status[0] byte */
+#define SNS_STAT1_PERM_ERR 0x80
+#define SNS_STAT1_INV_TRACK_FORMAT 0x40
+#define SNS_STAT1_EOC 0x20
+#define SNS_STAT1_MESSAGE_TO_OPER 0x10
+#define SNS_STAT1_NO_REC_FOUND 0x08
+#define SNS_STAT1_FILE_PROTECTED 0x04
+#define SNS_STAT1_WRITE_INHIBITED 0x02
+#define SNS_STAT1_IMPRECISE_END 0x01
+
+/* ECKD DASD status[1] byte */
+#define SNS_STAT2_REQ_INH_WRITE 0x80
+#define SNS_STAT2_CORRECTABLE 0x40
+#define SNS_STAT2_FIRST_LOG_ERR 0x20
+#define SNS_STAT2_ENV_DATA_PRESENT 0x10
+#define SNS_STAT2_IMPRECISE_END 0x04
+
+/* ECKD DASD 24-byte Sense fmt_msg codes */
+#define SENSE24_FMT_PROG_SYS 0x0
+#define SENSE24_FMT_EQUIPMENT 0x2
+#define SENSE24_FMT_CONTROLLER 0x3
+#define SENSE24_FMT_MISC 0xF
+
+/* basic sense response buffer layout */
+typedef struct SenseDataEckdDasd {
+ uint8_t common_status;
+ uint8_t status[2];
+ uint8_t res_count;
+ uint8_t phys_drive_id;
+ uint8_t low_cyl_addr;
+ uint8_t head_high_cyl_addr;
+ uint8_t fmt_msg;
+ uint64_t fmt_dependent_info[2];
+ uint8_t reserved;
+ uint8_t program_action_code;
+ uint16_t config_info;
+ uint8_t mcode_hicyl;
+ uint8_t cyl_head_addr[3];
+} __attribute__ ((packed, aligned(4))) SenseDataEckdDasd;
+
+#define ECKD_SENSE24_GET_FMT(sd) (sd->fmt_msg & 0xF0 >> 4)
+#define ECKD_SENSE24_GET_MSG(sd) (sd->fmt_msg & 0x0F)
+
+#define unit_check(irb) ((irb)->scsw.dstat & SCSW_DSTAT_UCHK)
+#define iface_ctrl_check(irb) ((irb)->scsw.cstat & SCSW_CSTAT_ICCHK)
+
/* interruption response block */
typedef struct irb {
struct scsw scsw;
@@ -215,6 +333,9 @@ typedef struct irb {
int enable_mss_facility(void);
void enable_subchannel(SubChannelId schid);
+uint16_t cu_type(SubChannelId schid);
+void basic_sense(SubChannelId schid, void *sense_data, uint16_t data_size);
+int do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt);
/*
* Some S390 specific IO instructions as inline
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index b39ee5d..11bce7d 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -52,6 +52,7 @@ typedef unsigned long long __u64;
/* start.s */
void disabled_wait(void);
void consume_sclp_int(void);
+void consume_io_int(void);
/* main.c */
void panic(const char *string);
diff --git a/pc-bios/s390-ccw/start.S b/pc-bios/s390-ccw/start.S
index 5c22cb0..2b4ea4c 100644
--- a/pc-bios/s390-ccw/start.S
+++ b/pc-bios/s390-ccw/start.S
@@ -71,6 +71,26 @@ consume_sclp_int:
larl %r1, enabled_wait_psw
lpswe 0(%r1)
+/*
+ * void consume_io_int(void)
+ *
+ * eats one I/O interrupt
+ */
+ .globl consume_io_int
+consume_io_int:
+ /* enable I/O interrupts in cr6 */
+ stctg 6,6,0(15)
+ oi 4(15), 0xff
+ lctlg 6,6,0(15)
+ /* prepare i/o call handler */
+ larl %r1, io_new_code
+ stg %r1, 0x1f8
+ larl %r1, io_new_mask
+ mvc 0x1f0(8),0(%r1)
+ /* load enabled wait PSW */
+ larl %r1, enabled_wait_psw
+ lpswe 0(%r1)
+
external_new_code:
/* disable service interrupts in cr0 */
stctg %c0,%c0,0(%r15)
@@ -78,6 +98,15 @@ external_new_code:
lctlg %c0,%c0,0(%r15)
br %r14
+io_new_code:
+ /* disable I/O interrupts in cr6 */
+ stctg 6,6,0(15)
+ ni 4(15), 0x00
+ lctlg 6,6,0(15)
+ br 14
+
+
+
.align 8
disabled_wait_psw:
.quad 0x0002000180000000,0x0000000000000000
@@ -85,3 +114,5 @@ enabled_wait_psw:
.quad 0x0302000180000000,0x0000000000000000
external_new_mask:
.quad 0x0000000180000000
+io_new_mask:
+ .quad 0x0000000180000000
--
2.7.4
On Fri, 1 Mar 2019 13:59:30 -0500
"Jason J. Herne" <jjherne@linux.ibm.com> wrote:
> Add struct for format-0 ccws. Support executing format-0 channel
> programs and waiting for their completion before continuing execution.
That sentence is a bit confusing. What about:
"Introduce a library function for executing format-0 and format-1
channel programs..."
> This will be used for real dasd ipl.
But also for virtio in the follow-on patches, won't it?
>
> Add cu_type() to channel io library. This will be used to query control
> unit type which is used to determine if we are booting a virtio device or a
> real dasd device.
>
> Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
> ---
> pc-bios/s390-ccw/cio.c | 141 ++++++++++++++++++++++++++++++++++++++++++++
> pc-bios/s390-ccw/cio.h | 127 ++++++++++++++++++++++++++++++++++++++-
> pc-bios/s390-ccw/s390-ccw.h | 1 +
> pc-bios/s390-ccw/start.S | 31 ++++++++++
> 4 files changed, 297 insertions(+), 3 deletions(-)
>
(...)
> +/*
> + * Handles executing ssch, tsch and returns the irb obtained from tsch.
> + * Returns 0 on success, -1 if unexpected status pending and we need to retry,
> + * otherwse returns condition code from ssch/tsch for error cases.
s/otherwse/otherwise/
> + */
> +static int __do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt, Irb *irb)
> +{
> + CmdOrb orb = {};
> + int rc;
> +
> + IPL_assert(fmt == 0 || fmt == 1, "Invalid ccw format");
> +
> + /* ccw_addr must be <= 24 bits and point to at least one whole ccw. */
> + if (fmt == 0) {
> + IPL_assert(ccw_addr <= 0xFFFFFF - 8, "Invalid ccw address");
> + }
> +
> + orb.fmt = fmt ;
extra ' ' before ';'
> + orb.pfch = 1; /* QEMU's cio implementation requires prefetch */
> + orb.c64 = 1; /* QEMU's cio implementation requires 64-bit idaws */
> + orb.lpm = 0xFF; /* All paths allowed */
> + orb.cpa = ccw_addr;
> +
> + rc = ssch(schid, &orb);
> + if (rc == 1) {
> + /* Status pending, not sure why. Eat status and ask for retry. */
> + tsch(schid, irb);
> + return -1;
> + }
> + if (rc) {
> + print_int("ssch failed with rc=", rc);
Better 'cc' than 'rc' in the message?
> + return rc;
> + }
> +
> + consume_io_int();
> +
> + /* collect status */
> + rc = tsch(schid, irb);
> + if (rc) {
> + print_int("tsch failed with rc=", rc);
> + }
Hm. The whole code flow relies on the fact that not only no more than
one cpu is enabled for I/O interrupts, but also only one subchannel.
Otherwise, you could get an interrupt for another subchannel, which
would be the only way you'd get cc 1 on the tsch for this subchannel
here (no status pending). Maybe peek at the interruption information
stored into the lowcore first?
Won't be a problem with the code as it is now, though, AFAICS.
> +
> + return rc;
> +}
> +
> +/*
> + * Executes a channel program at a given subchannel. The request to run the
> + * channel program is sent to the subchannel, we then wait for the interrupt
> + * signaling completion of the I/O operation(s) performed by the channel
> + * program. Lastly we verify that the i/o operation completed without error and
> + * that the interrupt we received was for the subchannel used to run the
> + * channel program.
> + *
> + * Note: This function assumes it is running in an environment where no other
> + * cpus are generating or receiving I/O interrupts. So either run it in a
> + * single-cpu environment or make sure all other cpus are not doing I/O and
> + * have I/O interrupts masked off.
> + *
> + * Returns non-zero on error.
> + */
> +int do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt)
> +{
> + Irb irb = {};
> + SenseDataEckdDasd sd;
> + int rc, retries = 0;
> +
> + while (true) {
> + rc = __do_cio(schid, ccw_addr, fmt, &irb);
> +
> + if (rc == -1) {
> + retries++;
> + continue;
> + }
> + if (rc) {
> + /* ssch/tsch error. Message already reported by __do_cio */
You might also want to consider retrying on cc 2. Not very likely,
though.
> + break;
> + }
> +
> + if (!irb_error(&irb)) {
> + break;
> + }
> +
> + /*
> + * Unexpected unit check, or interface-control-check. Use sense to
> + * clear (unit check only) then retry.
> + */
> + if ((unit_check(&irb) || iface_ctrl_check(&irb)) && retries <= 2) {
> + if (unit_check(&irb)) {
> + basic_sense(schid, &sd, sizeof(sd));
Unless I'm confused: I think you can still descend into the unit check
rabbit hole here. basic_sense() calls do_cio(), which calls
basic_sense(),... and we don't even get to the retries check.
Maybe call __do_cio() from basic_sense() instead and make that return
an error instead of panicking? Then you could just bump retries here
and give up after some retries...
> + }
> + retries++;
> + continue;
> + }
> +
> + rc = -1;
> + break;
> + }
> +
> + return rc;
> +}
On 3/4/19 1:25 PM, Cornelia Huck wrote:
> On Fri, 1 Mar 2019 13:59:30 -0500
> "Jason J. Herne" <jjherne@linux.ibm.com> wrote:
>
>> Add struct for format-0 ccws. Support executing format-0 channel
>> programs and waiting for their completion before continuing execution.
>
> That sentence is a bit confusing. What about:
>
> "Introduce a library function for executing format-0 and format-1
> channel programs..."
>
Agreed. Fixed.
>> This will be used for real dasd ipl.
>
> But also for virtio in the follow-on patches, won't it?
>
True. I removed that line. It is obvious and not really useful anyway.
...
>> + orb.fmt = fmt ;
>
> extra ' ' before ';'
>
Fixed.
>> + orb.pfch = 1; /* QEMU's cio implementation requires prefetch */
>> + orb.c64 = 1; /* QEMU's cio implementation requires 64-bit idaws */
>> + orb.lpm = 0xFF; /* All paths allowed */
>> + orb.cpa = ccw_addr;
>> +
>> + rc = ssch(schid, &orb);
>> + if (rc == 1) {
>> + /* Status pending, not sure why. Eat status and ask for retry. */
>> + tsch(schid, irb);
>> + return -1;
>> + }
>> + if (rc) {
>> + print_int("ssch failed with rc=", rc);
>
> Better 'cc' than 'rc' in the message?
>
Fixed here and for tsch as well.
>> + return rc;
>> + }
>> +
>> + consume_io_int();
>> +
>> + /* collect status */
>> + rc = tsch(schid, irb);
>> + if (rc) {
>> + print_int("tsch failed with rc=", rc);
>> + }
>
> Hm. The whole code flow relies on the fact that not only no more than
> one cpu is enabled for I/O interrupts, but also only one subchannel.
> Otherwise, you could get an interrupt for another subchannel, which
> would be the only way you'd get cc 1 on the tsch for this subchannel
> here (no status pending). Maybe peek at the interruption information
> stored into the lowcore first?
>
> Won't be a problem with the code as it is now, though, AFAICS.
>
Agreed, voting to leave as is. Perhaps a comment to explain that we rely on only one
"Active" i/o device?
>> +
>> + return rc;
>> +}
>> +
>> +/*
>> + * Executes a channel program at a given subchannel. The request to run the
>> + * channel program is sent to the subchannel, we then wait for the interrupt
>> + * signaling completion of the I/O operation(s) performed by the channel
>> + * program. Lastly we verify that the i/o operation completed without error and
>> + * that the interrupt we received was for the subchannel used to run the
>> + * channel program.
>> + *
>> + * Note: This function assumes it is running in an environment where no other
>> + * cpus are generating or receiving I/O interrupts. So either run it in a
>> + * single-cpu environment or make sure all other cpus are not doing I/O and
>> + * have I/O interrupts masked off.
>> + *
>> + * Returns non-zero on error.
>> + */
>> +int do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt)
>> +{
>> + Irb irb = {};
>> + SenseDataEckdDasd sd;
>> + int rc, retries = 0;
>> +
>> + while (true) {
>> + rc = __do_cio(schid, ccw_addr, fmt, &irb);
>> +
>> + if (rc == -1) {
>> + retries++;
>> + continue;
>> + }
>> + if (rc) {
>> + /* ssch/tsch error. Message already reported by __do_cio */
>
> You might also want to consider retrying on cc 2. Not very likely,
> though.
>
It is easy to retry on cc=2, fixed.
>> + break;
>> + }
>> +
>> + if (!irb_error(&irb)) {
>> + break;
>> + }
>> +
>> + /*
>> + * Unexpected unit check, or interface-control-check. Use sense to
>> + * clear (unit check only) then retry.
>> + */
>> + if ((unit_check(&irb) || iface_ctrl_check(&irb)) && retries <= 2) {
>> + if (unit_check(&irb)) {
>> + basic_sense(schid, &sd, sizeof(sd));
>
> Unless I'm confused: I think you can still descend into the unit check
> rabbit hole here. basic_sense() calls do_cio(), which calls
> basic_sense(),... and we don't even get to the retries check.
>
> Maybe call __do_cio() from basic_sense() instead and make that return
> an error instead of panicking? Then you could just bump retries here
> and give up after some retries...
>
Yes, good point. This is now fixed.
--
-- Jason J. Herne (jjherne@linux.ibm.com)
On Thu, 7 Mar 2019 14:25:00 -0500
"Jason J. Herne" <jjherne@linux.ibm.com> wrote:
> On 3/4/19 1:25 PM, Cornelia Huck wrote:
> > On Fri, 1 Mar 2019 13:59:30 -0500
> > "Jason J. Herne" <jjherne@linux.ibm.com> wrote:
> >> + consume_io_int();
> >> +
> >> + /* collect status */
> >> + rc = tsch(schid, irb);
> >> + if (rc) {
> >> + print_int("tsch failed with rc=", rc);
> >> + }
> >
> > Hm. The whole code flow relies on the fact that not only no more than
> > one cpu is enabled for I/O interrupts, but also only one subchannel.
> > Otherwise, you could get an interrupt for another subchannel, which
> > would be the only way you'd get cc 1 on the tsch for this subchannel
> > here (no status pending). Maybe peek at the interruption information
> > stored into the lowcore first?
> >
> > Won't be a problem with the code as it is now, though, AFAICS.
> >
> Agreed, voting to leave as is. Perhaps a comment to explain that we rely on only one
> "Active" i/o device?
Yes, sounds good.
On 01/03/2019 19.59, Jason J. Herne wrote:
> Add struct for format-0 ccws. Support executing format-0 channel
> programs and waiting for their completion before continuing execution.
> This will be used for real dasd ipl.
>
> Add cu_type() to channel io library. This will be used to query control
> unit type which is used to determine if we are booting a virtio device or a
> real dasd device.
>
> Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
> ---
[...]
> diff --git a/pc-bios/s390-ccw/start.S b/pc-bios/s390-ccw/start.S
> index 5c22cb0..2b4ea4c 100644
> --- a/pc-bios/s390-ccw/start.S
> +++ b/pc-bios/s390-ccw/start.S
> @@ -71,6 +71,26 @@ consume_sclp_int:
> larl %r1, enabled_wait_psw
> lpswe 0(%r1)
>
> +/*
> + * void consume_io_int(void)
> + *
> + * eats one I/O interrupt
> + */
> + .globl consume_io_int
> +consume_io_int:
> + /* enable I/O interrupts in cr6 */
> + stctg 6,6,0(15)
> + oi 4(15), 0xff
> + lctlg 6,6,0(15)
Could you please use %-register names? If we ever want to compile the
code with Clang again, this will likely be required (see commit
0d3a76139827f7d08f1b for example). I.e.:
stctg %c6,%c6,0(%r15)
oi 4(%r15),0xff
lctlg %c6,%c6,0(%r15)
(indenting the parameters of the instruction would also be nice)
> + /* prepare i/o call handler */
> + larl %r1, io_new_code
> + stg %r1, 0x1f8
> + larl %r1, io_new_mask
> + mvc 0x1f0(8),0(%r1)
> + /* load enabled wait PSW */
> + larl %r1, enabled_wait_psw
> + lpswe 0(%r1)
> +
> external_new_code:
> /* disable service interrupts in cr0 */
> stctg %c0,%c0,0(%r15)
> @@ -78,6 +98,15 @@ external_new_code:
> lctlg %c0,%c0,0(%r15)
> br %r14
>
> +io_new_code:
> + /* disable I/O interrupts in cr6 */
> + stctg 6,6,0(15)
> + ni 4(15), 0x00
> + lctlg 6,6,0(15)
dito
Thanks,
Thomas
© 2016 - 2026 Red Hat, Inc.