diff mbox series

[10/15] s390-bios: Support for running format-0/1 channel programs

Message ID 1544623878-11248-11-git-send-email-jjherne@linux.ibm.com (mailing list archive)
State New, archived
Headers show
Series s390: vfio-ccw dasd ipl support | expand

Commit Message

Jason J. Herne Dec. 12, 2018, 2:11 p.m. UTC
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      | 108 ++++++++++++++++++++++++++++++++++++++
 pc-bios/s390-ccw/cio.h      | 124 ++++++++++++++++++++++++++++++++++++++++++--
 pc-bios/s390-ccw/s390-ccw.h |   1 +
 pc-bios/s390-ccw/start.S    |  33 +++++++++++-
 4 files changed, 261 insertions(+), 5 deletions(-)

Comments

Farhan Ali Dec. 13, 2018, 4:54 p.m. UTC | #1
On 12/12/2018 09:11 AM, 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>
> ---
>   pc-bios/s390-ccw/cio.c      | 108 ++++++++++++++++++++++++++++++++++++++
>   pc-bios/s390-ccw/cio.h      | 124 ++++++++++++++++++++++++++++++++++++++++++--
>   pc-bios/s390-ccw/s390-ccw.h |   1 +
>   pc-bios/s390-ccw/start.S    |  33 +++++++++++-
>   4 files changed, 261 insertions(+), 5 deletions(-)
> 
> diff --git a/pc-bios/s390-ccw/cio.c b/pc-bios/s390-ccw/cio.c
> index 095f79b..9019250 100644
> --- a/pc-bios/s390-ccw/cio.c
> +++ b/pc-bios/s390-ccw/cio.c
> @@ -10,6 +10,7 @@
> 
>   #include "libc.h"
>   #include "s390-ccw.h"
> +#include "s390-arch.h"
>   #include "cio.h"
> 
>   static char chsc_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
> @@ -39,3 +40,110 @@ 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);
> +
> +    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, SenseData *sd)
> +{
> +    Ccw1 senseCcw;
> +
> +    senseCcw.cmd_code = CCW_CMD_BASIC_SENSE;
> +    senseCcw.cda = ptr2u32(sd);
> +    senseCcw.count = sizeof(*sd);
> +
> +    if (do_cio(schid, ptr2u32(&senseCcw), CCW_FMT1)) {
> +        panic("Failed to run Basic Sense CCW\n");
> +    }
> +}
> +
> +static bool irb_error(Irb *irb)
> +{
> +    /* We have to ignore Incorrect Length (cstat == 0x40) indicators because
> +     * real devices expect a 24 byte SenseID  buffer, and virtio devices expect
> +     * a much larger buffer. Neither device type can tolerate a buffer size
> +     * different from what they expect so they set this indicator.
> +     */
> +    if (irb->scsw.cstat != 0x00 && irb->scsw.cstat != 0x40) {
> +        return true;
> +    }
> +    return irb->scsw.dstat != 0xc;
> +}
> +
> +/* 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
> + * singaling completion of the I/O operation(s) perfomed 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.
> + */
> +int do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt)
> +{
> +    CmdOrb orb = {};
> +    Irb irb = {};
> +    SenseData sd;
> +    int rc, retries = 0;
> +
> +    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;
> +
> +    while (true) {
> +        rc = ssch(schid, &orb);
> +        if (rc) {
> +            print_int("ssch failed with rc=", rc);
> +            break;
> +        }
> +
> +        consume_io_int();
> +
> +        /* Clear read */
> +        rc = tsch(schid, &irb);
> +        if (rc) {
> +            print_int("tsch failed with rc=", rc);
> +            break;
> +        }
> +
> +        if (!irb_error(&irb)) {
> +            break;
> +        }

Now that we enable i/o interrupts, do we still need drain_irqs function 
anymore? Maybe we could refactor that.

My question is more out of curiosity and I know it's out of the score 
for this patch series.

> +
> +        /* Unexpected unit check. Use sense to clear unit check then retry. */
> +        if (unit_check(&irb) && retries <= 2) {
> +            basic_sense(schid, &sd);
> +            retries++;
> +            continue;
> +        }
> +
> +        break;
> +    }
> +
> +    return rc;
> +}
> diff --git a/pc-bios/s390-ccw/cio.h b/pc-bios/s390-ccw/cio.h
> index 7b07d75..5c16635 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            0x3990
> +
>   /*
>    * sense-id response buffer layout
>    */
> @@ -205,6 +265,61 @@ typedef struct senseid {
>       struct ciw ciw[62];
>   }  __attribute__ ((packed, aligned(4))) SenseId;
> 
> +/* architected values for first sense byte */
> +#define SNS0_CMD_REJECT         0x80
> +#define SNS0_INTERVENTION_REQ   0x40
> +#define SNS0_BUS_OUT_CHECK      0x20
> +#define SNS0_EQUIPMENT_CHECK    0x10
> +#define SNS0_DATA_CHECK         0x08
> +#define SNS0_OVERRUN            0x04
> +#define SNS0_INCOMPL_DOMAIN     0x01
> +
> +/* architectured values for second sense byte */
> +#define SNS1_PERM_ERR           0x80
> +#define SNS1_INV_TRACK_FORMAT   0x40
> +#define SNS1_EOC                0x20
> +#define SNS1_MESSAGE_TO_OPER    0x10
> +#define SNS1_NO_REC_FOUND       0x08
> +#define SNS1_FILE_PROTECTED     0x04
> +#define SNS1_WRITE_INHIBITED    0x02
> +#define SNS1_INPRECISE_END      0x01
> +
> +/* architectured values for third sense byte */
> +#define SNS2_REQ_INH_WRITE      0x80
> +#define SNS2_CORRECTABLE        0x40
> +#define SNS2_FIRST_LOG_ERR      0x20
> +#define SNS2_ENV_DATA_PRESENT   0x10
> +#define SNS2_INPRECISE_END      0x04
> +
> +/* 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
> +
> +#define SENSE24_FMT0_MSG_RESET_NOTIFICATION 0x16
> +
> +/* basic sense response buffer layout */
> +typedef struct senseData {
> +    uint8_t status[3];
> +    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))) SenseData;
> +
> +#define SENSE24_GET_FMT(sd)     (sd->fmt_msg & 0xF0 >> 4)
> +#define SENSE24_GET_MSG(sd)     (sd->fmt_msg & 0x0F)
> +
> +#define unit_check(irb)     ((irb)->scsw.dstat & SCSW_DSTAT_UCHK)
> +
>   /* interruption response block */
>   typedef struct irb {
>       struct scsw scsw;
> @@ -215,6 +330,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, SenseData *sd);
> +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 eb8d024..a48c38f 100644
> --- a/pc-bios/s390-ccw/start.S
> +++ b/pc-bios/s390-ccw/start.S
> @@ -65,12 +65,32 @@ consume_sclp_int:
>           /* prepare external call handler */
>           larl %r1, external_new_code
>           stg %r1, 0x1b8
> -        larl %r1, external_new_mask
> +        larl %r1, int_new_mask
>           mvc 0x1b0(8),0(%r1)
>           /* load enabled wait PSW */
>           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 cr0 */
> +        stctg 6,6,0(15)
> +        oi 4(15), 0xff
> +        lctlg 6,6,0(15)
> +        /* prepare external call handler */

shouldn't this be i/o call handler?

> +        larl %r1, io_new_code
> +        stg %r1, 0x1f8
> +        larl %r1, int_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 0,0,0(15)
> @@ -78,10 +98,19 @@ external_new_code:
>           lctlg 0,0,0(15)
>           br 14
> 
> +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
>   enabled_wait_psw:
>           .quad   0x0302000180000000,0x0000000000000000
> -external_new_mask:
> +int_new_mask:
>           .quad   0x0000000180000000
>
Cornelia Huck Dec. 13, 2018, 5:21 p.m. UTC | #2
On Wed, 12 Dec 2018 09:11:13 -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.
> 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      | 108 ++++++++++++++++++++++++++++++++++++++
>  pc-bios/s390-ccw/cio.h      | 124 ++++++++++++++++++++++++++++++++++++++++++--
>  pc-bios/s390-ccw/s390-ccw.h |   1 +
>  pc-bios/s390-ccw/start.S    |  33 +++++++++++-
>  4 files changed, 261 insertions(+), 5 deletions(-)
> 

(...)

> +static bool irb_error(Irb *irb)
> +{
> +    /* We have to ignore Incorrect Length (cstat == 0x40) indicators because
> +     * real devices expect a 24 byte SenseID  buffer, and virtio devices expect
> +     * a much larger buffer. Neither device type can tolerate a buffer size
> +     * different from what they expect so they set this indicator.

Hm, can't you specify SLI for SenseID?

> +     */
> +    if (irb->scsw.cstat != 0x00 && irb->scsw.cstat != 0x40) {
> +        return true;
> +    }
> +    return irb->scsw.dstat != 0xc;

Also, shouldn't you actually use the #defines you introduce further
down?

> +}
> +
> +/* 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
> + * singaling completion of the I/O operation(s) perfomed 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.

Anything about iscs here (cr6)?

> + */
> +int do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt)
> +{
> +    CmdOrb orb = {};
> +    Irb irb = {};
> +    SenseData sd;
> +    int rc, retries = 0;
> +
> +    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;
> +
> +    while (true) {
> +        rc = ssch(schid, &orb);

I think we can get here:
- cc 0 -> all ok
- cc 1 -> status pending; could that be an unsolicited interrupt from
  the device? or would we always get a deferred cc 1 in that case?
- cc 2 -> another function pending; Should Not Happen
- cc 3 -> it's dead, Jim

So I'm wondering whether we should consume the status and retry for cc
1. The handling of the others is fine.

> +        if (rc) {
> +            print_int("ssch failed with rc=", rc);
> +            break;
> +        }
> +
> +        consume_io_int();
> +
> +        /* Clear read */

I find that comment confusing. /* collect status */ maybe?

> +        rc = tsch(schid, &irb);

Here we can get:
- cc 0 -> status pending, all ok
- cc 1 -> no status pending, Should Not Happen
- cc 3 -> it's dead, Jim

So this looks fine.

> +        if (rc) {
> +            print_int("tsch failed with rc=", rc);
> +            break;
> +        }
> +
> +        if (!irb_error(&irb)) {
> +            break;
> +        }
> +
> +        /* Unexpected unit check. Use sense to clear unit check then retry. */

The dasds still don't support concurrent sense, do they? Might also be
worth investigating whether some unit checks are more "recoverable"
than others.

I expect we simply want to ignore IFCCs? IIRC, the strategy for those
is "retry, in case it is transient"; but that may take some time. Or
was there some path handling to be considered? (i.e., retrying may
select another path, which may be fine.)

> +        if (unit_check(&irb) && retries <= 2) {
> +            basic_sense(schid, &sd);
> +            retries++;
> +            continue;
> +        }
> +
> +        break;
> +    }
> +
> +    return rc;
> +}

(...)

> @@ -190,6 +247,9 @@ struct ciw {
>      __u16 count;
>  };
>  
> +#define CU_TYPE_VIRTIO          0x3832
> +#define CU_TYPE_DASD            0x3990

No other dasd types we want to support? :) (Not sure if others are out
in the wild. Maybe FBA?)

> +
>  /*
>   * sense-id response buffer layout
>   */
> @@ -205,6 +265,61 @@ typedef struct senseid {
>      struct ciw ciw[62];
>  }  __attribute__ ((packed, aligned(4))) SenseId;
>  
> +/* architected values for first sense byte */
> +#define SNS0_CMD_REJECT         0x80
> +#define SNS0_INTERVENTION_REQ   0x40
> +#define SNS0_BUS_OUT_CHECK      0x20
> +#define SNS0_EQUIPMENT_CHECK    0x10
> +#define SNS0_DATA_CHECK         0x08
> +#define SNS0_OVERRUN            0x04
> +#define SNS0_INCOMPL_DOMAIN     0x01

IIRC, only byte 0 is device independent, and the others below are
(ECKD) dasd specific?

> +
> +/* architectured values for second sense byte */
> +#define SNS1_PERM_ERR           0x80
> +#define SNS1_INV_TRACK_FORMAT   0x40
> +#define SNS1_EOC                0x20
> +#define SNS1_MESSAGE_TO_OPER    0x10
> +#define SNS1_NO_REC_FOUND       0x08
> +#define SNS1_FILE_PROTECTED     0x04
> +#define SNS1_WRITE_INHIBITED    0x02
> +#define SNS1_INPRECISE_END      0x01
> +
> +/* architectured values for third sense byte */
> +#define SNS2_REQ_INH_WRITE      0x80
> +#define SNS2_CORRECTABLE        0x40
> +#define SNS2_FIRST_LOG_ERR      0x20
> +#define SNS2_ENV_DATA_PRESENT   0x10
> +#define SNS2_INPRECISE_END      0x04
> +
> +/* 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
> +
> +#define SENSE24_FMT0_MSG_RESET_NOTIFICATION 0x16
> +
> +/* basic sense response buffer layout */
> +typedef struct senseData {
> +    uint8_t status[3];
> +    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))) SenseData;

And this looks _really_ dasd specific.

> +
> +#define SENSE24_GET_FMT(sd)     (sd->fmt_msg & 0xF0 >> 4)
> +#define SENSE24_GET_MSG(sd)     (sd->fmt_msg & 0x0F)
> +
> +#define unit_check(irb)     ((irb)->scsw.dstat & SCSW_DSTAT_UCHK)
> +
>  /* interruption response block */
>  typedef struct irb {
>      struct scsw scsw;

(...)

> diff --git a/pc-bios/s390-ccw/start.S b/pc-bios/s390-ccw/start.S
> index eb8d024..a48c38f 100644
> --- a/pc-bios/s390-ccw/start.S
> +++ b/pc-bios/s390-ccw/start.S
> @@ -65,12 +65,32 @@ consume_sclp_int:
>          /* prepare external call handler */
>          larl %r1, external_new_code
>          stg %r1, 0x1b8
> -        larl %r1, external_new_mask
> +        larl %r1, int_new_mask
>          mvc 0x1b0(8),0(%r1)
>          /* load enabled wait PSW */
>          larl %r1, enabled_wait_psw
>          lpswe 0(%r1)
>  
> +/*
> + * void consume_io_int(void)
> + *
> + * eats one I/O interrupt

*nomnom*

> + */
> +        .globl consume_io_int
> +consume_io_int:
> +        /* enable I/O interrupts in cr0 */

cr6?

> +        stctg 6,6,0(15)
> +        oi 4(15), 0xff
> +        lctlg 6,6,0(15)
> +        /* prepare external call handler */

I/O call handler?

> +        larl %r1, io_new_code
> +        stg %r1, 0x1f8
> +        larl %r1, int_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 0,0,0(15)
> @@ -78,10 +98,19 @@ external_new_code:
>          lctlg 0,0,0(15)
>          br 14
>  
> +io_new_code:
> +        /* disable I/O interrupts in cr6 */
> +        stctg 6,6,0(15)

I'm wondering why you are changing cr6 every time you wait for an I/O
interrupt. Just enable the isc(s) you want once, and disable them again
after you're done with all I/O? Simply disabling the I/O interrupts
should be enough to prevent further interrupts popping up. You maybe
want two enabled wait PSWs, one with I/O + external and one with
external only?

> +        ni 4(15), 0x00
> +        lctlg 6,6,0(15)
> +        br 14
> +
> +
> +
>          .align  8
>  disabled_wait_psw:
>          .quad   0x0002000180000000,0x0000000000000000
>  enabled_wait_psw:
>          .quad   0x0302000180000000,0x0000000000000000
> -external_new_mask:
> +int_new_mask:
>          .quad   0x0000000180000000
Jason J. Herne Jan. 7, 2019, 7:02 p.m. UTC | #3
On 12/13/18 12:21 PM, Cornelia Huck wrote:
> On Wed, 12 Dec 2018 09:11:13 -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.
>> 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      | 108 ++++++++++++++++++++++++++++++++++++++
>>   pc-bios/s390-ccw/cio.h      | 124 ++++++++++++++++++++++++++++++++++++++++++--
>>   pc-bios/s390-ccw/s390-ccw.h |   1 +
>>   pc-bios/s390-ccw/start.S    |  33 +++++++++++-
>>   4 files changed, 261 insertions(+), 5 deletions(-)
>>
> 
> (...)
> 
>> +static bool irb_error(Irb *irb)
>> +{
>> +    /* We have to ignore Incorrect Length (cstat == 0x40) indicators because
>> +     * real devices expect a 24 byte SenseID  buffer, and virtio devices expect
>> +     * a much larger buffer. Neither device type can tolerate a buffer size
>> +     * different from what they expect so they set this indicator.
> 
> Hm, can't you specify SLI for SenseID?
> 

Yes, but this requires modifying run_ccw() in virtio.c to always specify the SLI flag. I'm 
not sure that is the best choice? I suppose I could add an sli argument to run_ccw if 
you'd prefer that.

>> +     */
>> +    if (irb->scsw.cstat != 0x00 && irb->scsw.cstat != 0x40) {
>> +        return true;
>> +    }
>> +    return irb->scsw.dstat != 0xc;
> 
> Also, shouldn't you actually use the #defines you introduce further
> down?
> 

Yep, I added the defines after I wrote this code. I'll fix that.

>> +}
>> +
>> +/* 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
>> + * singaling completion of the I/O operation(s) perfomed 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.
> 
> Anything about iscs here (cr6)?
> 

Those details are handled in the assembler code. Do you think I should mention something 
about cr6 here?

>> + */
>> +int do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt)
>> +{
>> +    CmdOrb orb = {};
>> +    Irb irb = {};
>> +    SenseData sd;
>> +    int rc, retries = 0;
>> +
>> +    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;
>> +
>> +    while (true) {
>> +        rc = ssch(schid, &orb);
> 
> I think we can get here:
> - cc 0 -> all ok
> - cc 1 -> status pending; could that be an unsolicited interrupt from
>    the device? or would we always get a deferred cc 1 in that case?
> - cc 2 -> another function pending; Should Not Happen
> - cc 3 -> it's dead, Jim
> 
> So I'm wondering whether we should consume the status and retry for cc
> 1. The handling of the others is fine.
> 

I took a look at css_do_ssch() in hw/s390x/css.c and it appears as though CC1 is a 
possibility here. I'm not against taking action, but I suspect we would have to clear the 
status with a basic sense (or something) before simply retrying... right?

Is it safe for us to just assume we can clear it and move on? It seems like an edge case 
that we'd be better off failing on. Perhaps let the user try again which will redrive the 
process?


>> +        if (rc) {
>> +            print_int("ssch failed with rc=", rc);
>> +            break;
>> +        }
>> +
>> +        consume_io_int();
>> +
>> +        /* Clear read */
> 
> I find that comment confusing. /* collect status */ maybe?
> 
>> +        rc = tsch(schid, &irb);
> 
> Here we can get:
> - cc 0 -> status pending, all ok
> - cc 1 -> no status pending, Should Not Happen
> - cc 3 -> it's dead, Jim
> 
> So this looks fine.
> 
>> +        if (rc) {
>> +            print_int("tsch failed with rc=", rc);
>> +            break;
>> +        }
>> +
>> +        if (!irb_error(&irb)) {
>> +            break;
>> +        }
>> +
>> +        /* Unexpected unit check. Use sense to clear unit check then retry. */
> 
> The dasds still don't support concurrent sense, do they? Might also be
> worth investigating whether some unit checks are more "recoverable"
> than others.
> 

I wasn't sure on concurrent sense. I'd bet there are situations or environments where it 
won't be supported so it seems safest to assume we don't have it.

We already recover from the one unit check scenario I've discovered in practice (initial 
reset). And the algorithm I chose is to simply retry a few times whenever we're presented 
with unexpected unit check status. This is what the kernel does. It seems fairly robust.


> I expect we simply want to ignore IFCCs? IIRC, the strategy for those
> is "retry, in case it is transient"; but that may take some time. Or
> was there some path handling to be considered? (i.e., retrying may
> select another path, which may be fine.)
> 

Currently we'll give up on IFCC. I think this is the right thing to do. A user can always 
retry if they want. But in reality an IFCC very likely means faulty hardware IIUC.

I've not thought about path management much. I suspect paths changing isn't something we 
should realistically see in the bios. Even still, a retry is really all we can do, so 
assuming path changes result in a unit check then we should be okay there.


>> +        if (unit_check(&irb) && retries <= 2) {
>> +            basic_sense(schid, &sd);
>> +            retries++;
>> +            continue;
>> +        }
>> +
>> +        break;
>> +    }
>> +
>> +    return rc;
>> +}
> 
> (...)
> 
>> @@ -190,6 +247,9 @@ struct ciw {
>>       __u16 count;
>>   };
>>   
>> +#define CU_TYPE_VIRTIO          0x3832
>> +#define CU_TYPE_DASD            0x3990
> 
> No other dasd types we want to support? :) (Not sure if others are out
> in the wild. Maybe FBA?)
>

I have no idea. I assumed 3390 was the only thing we supported. Perhaps 3380? I'd need to 
find a test device, which I could probably do ... I'll look more into this.


>> +
>>   /*
>>    * sense-id response buffer layout
>>    */
>> @@ -205,6 +265,61 @@ typedef struct senseid {
>>       struct ciw ciw[62];
>>   }  __attribute__ ((packed, aligned(4))) SenseId;
>>   
>> +/* architected values for first sense byte */
>> +#define SNS0_CMD_REJECT         0x80
>> +#define SNS0_INTERVENTION_REQ   0x40
>> +#define SNS0_BUS_OUT_CHECK      0x20
>> +#define SNS0_EQUIPMENT_CHECK    0x10
>> +#define SNS0_DATA_CHECK         0x08
>> +#define SNS0_OVERRUN            0x04
>> +#define SNS0_INCOMPL_DOMAIN     0x01
> 
> IIRC, only byte 0 is device independent, and the others below are
> (ECKD) dasd specific?
> 
>> +
>> +/* architectured values for second sense byte */
>> +#define SNS1_PERM_ERR           0x80
>> +#define SNS1_INV_TRACK_FORMAT   0x40
>> +#define SNS1_EOC                0x20
>> +#define SNS1_MESSAGE_TO_OPER    0x10
>> +#define SNS1_NO_REC_FOUND       0x08
>> +#define SNS1_FILE_PROTECTED     0x04
>> +#define SNS1_WRITE_INHIBITED    0x02
>> +#define SNS1_INPRECISE_END      0x01
>> +
>> +/* architectured values for third sense byte */
>> +#define SNS2_REQ_INH_WRITE      0x80
>> +#define SNS2_CORRECTABLE        0x40
>> +#define SNS2_FIRST_LOG_ERR      0x20
>> +#define SNS2_ENV_DATA_PRESENT   0x10
>> +#define SNS2_INPRECISE_END      0x04
>> +
>> +/* 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
>> +
>> +#define SENSE24_FMT0_MSG_RESET_NOTIFICATION 0x16
>> +
>> +/* basic sense response buffer layout */
>> +typedef struct senseData {
>> +    uint8_t status[3];
>> +    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))) SenseData;
> 
> And this looks _really_ dasd specific.
> 

Yep, I glossed over those details while I was furiously tracking down the reset bug. I'll 
take a look at redesigning this.

>> +
>> +#define SENSE24_GET_FMT(sd)     (sd->fmt_msg & 0xF0 >> 4)
>> +#define SENSE24_GET_MSG(sd)     (sd->fmt_msg & 0x0F)
>> +
>> +#define unit_check(irb)     ((irb)->scsw.dstat & SCSW_DSTAT_UCHK)
>> +
>>   /* interruption response block */
>>   typedef struct irb {
>>       struct scsw scsw;
> 
> (...)
> 
>> diff --git a/pc-bios/s390-ccw/start.S b/pc-bios/s390-ccw/start.S
>> index eb8d024..a48c38f 100644
>> --- a/pc-bios/s390-ccw/start.S
>> +++ b/pc-bios/s390-ccw/start.S
>> @@ -65,12 +65,32 @@ consume_sclp_int:
>>           /* prepare external call handler */
>>           larl %r1, external_new_code
>>           stg %r1, 0x1b8
>> -        larl %r1, external_new_mask
>> +        larl %r1, int_new_mask
>>           mvc 0x1b0(8),0(%r1)
>>           /* load enabled wait PSW */
>>           larl %r1, enabled_wait_psw
>>           lpswe 0(%r1)
>>   
>> +/*
>> + * void consume_io_int(void)
>> + *
>> + * eats one I/O interrupt
> 
> *nomnom*
> 
>> + */
>> +        .globl consume_io_int
>> +consume_io_int:
>> +        /* enable I/O interrupts in cr0 */
> 
> cr6?
> 
>> +        stctg 6,6,0(15)
>> +        oi 4(15), 0xff
>> +        lctlg 6,6,0(15)
>> +        /* prepare external call handler */
> 
> I/O call handler?
> 

Both copy/paste errors. Thanks for catching these. :)

>> +        larl %r1, io_new_code
>> +        stg %r1, 0x1f8
>> +        larl %r1, int_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 0,0,0(15)
>> @@ -78,10 +98,19 @@ external_new_code:
>>           lctlg 0,0,0(15)
>>           br 14
>>   
>> +io_new_code:
>> +        /* disable I/O interrupts in cr6 */
>> +        stctg 6,6,0(15)
> 
> I'm wondering why you are changing cr6 every time you wait for an I/O
> interrupt. Just enable the isc(s) you want once, and disable them again
> after you're done with all I/O? Simply disabling the I/O interrupts
> should be enough to prevent further interrupts popping up. You maybe
> want two enabled wait PSWs, one with I/O + external and one with
> external only?
> 

No real reason. We only come through here a hand full of times so performance is not a 
consideration. I guess my thought process was probably to keep the system is as close to 
initial state as possible through the ipl process. Eventually when we hand control to the 
guest OS we want the system as close to undisturbed as possible. If you think I should 
only be setting cr-6 once, it sounds reasonable.


>> +        ni 4(15), 0x00
>> +        lctlg 6,6,0(15)
>> +        br 14
>> +
>> +
>> +
>>           .align  8
>>   disabled_wait_psw:
>>           .quad   0x0002000180000000,0x0000000000000000
>>   enabled_wait_psw:
>>           .quad   0x0302000180000000,0x0000000000000000
>> -external_new_mask:
>> +int_new_mask:
>>           .quad   0x0000000180000000
> 
>
Cornelia Huck Jan. 8, 2019, 11:07 a.m. UTC | #4
On Mon, 7 Jan 2019 14:02:45 -0500
"Jason J. Herne" <jjherne@linux.ibm.com> wrote:

> On 12/13/18 12:21 PM, Cornelia Huck wrote:
> > On Wed, 12 Dec 2018 09:11:13 -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.
> >> 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      | 108 ++++++++++++++++++++++++++++++++++++++
> >>   pc-bios/s390-ccw/cio.h      | 124 ++++++++++++++++++++++++++++++++++++++++++--
> >>   pc-bios/s390-ccw/s390-ccw.h |   1 +
> >>   pc-bios/s390-ccw/start.S    |  33 +++++++++++-
> >>   4 files changed, 261 insertions(+), 5 deletions(-)
> >>  
> > 
> > (...)
> >   
> >> +static bool irb_error(Irb *irb)
> >> +{
> >> +    /* We have to ignore Incorrect Length (cstat == 0x40) indicators because
> >> +     * real devices expect a 24 byte SenseID  buffer, and virtio devices expect
> >> +     * a much larger buffer. Neither device type can tolerate a buffer size
> >> +     * different from what they expect so they set this indicator.  
> > 
> > Hm, can't you specify SLI for SenseID?
> >   
> 
> Yes, but this requires modifying run_ccw() in virtio.c to always specify the SLI flag. I'm 
> not sure that is the best choice? I suppose I could add an sli argument to run_ccw if 
> you'd prefer that.

Ignoring an error feels wrong :) Telling the function "hey, I don't
know what buffer size you expect, just give me what you have" feels
better. If I read SA22-7204-01 correctly, there's always just a minimum
of sense id data, and how much we get is device dependent. (FWIW, the
Linux kernel does sense id with SLI as well.)

So yes, +1 to adding a sli parameter to run_ccw().

> 
> >> +     */
> >> +    if (irb->scsw.cstat != 0x00 && irb->scsw.cstat != 0x40) {
> >> +        return true;
> >> +    }
> >> +    return irb->scsw.dstat != 0xc;  
> > 
> > Also, shouldn't you actually use the #defines you introduce further
> > down?
> >   
> 
> Yep, I added the defines after I wrote this code. I'll fix that.
> 
> >> +}
> >> +
> >> +/* 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
> >> + * singaling completion of the I/O operation(s) perfomed by the channel

s/perfomed/performed/

> >> + * 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.  
> > 
> > Anything about iscs here (cr6)?
> >   
> 
> Those details are handled in the assembler code. Do you think I should mention something 
> about cr6 here?

We can probably do without.

> 
> >> + */
> >> +int do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt)
> >> +{
> >> +    CmdOrb orb = {};
> >> +    Irb irb = {};
> >> +    SenseData sd;
> >> +    int rc, retries = 0;
> >> +
> >> +    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;
> >> +
> >> +    while (true) {
> >> +        rc = ssch(schid, &orb);  
> > 
> > I think we can get here:
> > - cc 0 -> all ok
> > - cc 1 -> status pending; could that be an unsolicited interrupt from
> >    the device? or would we always get a deferred cc 1 in that case?
> > - cc 2 -> another function pending; Should Not Happen
> > - cc 3 -> it's dead, Jim
> > 
> > So I'm wondering whether we should consume the status and retry for cc
> > 1. The handling of the others is fine.
> >   
> 
> I took a look at css_do_ssch() in hw/s390x/css.c and it appears as though CC1 is a 
> possibility here. I'm not against taking action, but I suspect we would have to clear the 
> status with a basic sense (or something) before simply retrying... right?

It depends on the status. If you get an unit check, you'll probably
need the basic sense; in other cases, you'll probably want to simply
retry.

> 
> Is it safe for us to just assume we can clear it and move on? It seems like an edge case 
> that we'd be better off failing on. Perhaps let the user try again which will redrive the 
> process?

A very low amount of retries (2?) sounds reasonable: this would keep us
going if there's a state from the device that will be ignored anyway,
and won't get us stuck in a pointless retry loop if something more
involved is going on.

> 
> 
> >> +        if (rc) {
> >> +            print_int("ssch failed with rc=", rc);
> >> +            break;
> >> +        }
> >> +
> >> +        consume_io_int();
> >> +
> >> +        /* Clear read */  
> > 
> > I find that comment confusing. /* collect status */ maybe?
> >   
> >> +        rc = tsch(schid, &irb);  
> > 
> > Here we can get:
> > - cc 0 -> status pending, all ok
> > - cc 1 -> no status pending, Should Not Happen
> > - cc 3 -> it's dead, Jim
> > 
> > So this looks fine.
> >   
> >> +        if (rc) {
> >> +            print_int("tsch failed with rc=", rc);
> >> +            break;
> >> +        }
> >> +
> >> +        if (!irb_error(&irb)) {
> >> +            break;
> >> +        }
> >> +
> >> +        /* Unexpected unit check. Use sense to clear unit check then retry. */  
> > 
> > The dasds still don't support concurrent sense, do they? Might also be
> > worth investigating whether some unit checks are more "recoverable"
> > than others.
> >   
> 
> I wasn't sure on concurrent sense. I'd bet there are situations or environments where it 
> won't be supported so it seems safest to assume we don't have it.

Ok.

> 
> We already recover from the one unit check scenario I've discovered in practice (initial 
> reset). And the algorithm I chose is to simply retry a few times whenever we're presented 
> with unexpected unit check status. This is what the kernel does. It seems fairly robust.

Nod.

> > I expect we simply want to ignore IFCCs? IIRC, the strategy for those
> > is "retry, in case it is transient"; but that may take some time. Or
> > was there some path handling to be considered? (i.e., retrying may
> > select another path, which may be fine.)
> >   
> 
> Currently we'll give up on IFCC. I think this is the right thing to do. A user can always 
> retry if they want. But in reality an IFCC very likely means faulty hardware IIUC.

It could also be a transient link issue. Maybe retry twice, just to
avoid the very tiny blips?

> I've not thought about path management much. I suspect paths changing isn't something we 
> should realistically see in the bios. Even still, a retry is really all we can do, so 
> assuming path changes result in a unit check then we should be okay there.

If you use a full path mask, the channel subsystem might try a
different path (that is working correctly) the next time. I don't think
you want to implement path grouping stuff in the bios, which would mean
a lot of pain for very little gain :)

Thinking about path groups: One scenario we might have is that another
LPAR did a reserve on a dasd and then died. The dasd is then
unaccessible by our LPAR until we do a steal lock. If the device is
bound to the vfio-ccw subchannel driver, we don't have an interface for
that, though (we would need to re-bind to the I/O subchannel driver and
the dasd driver so we can invoke tunedasd). We could add an option to
break the lock from the bios, although that's probably overkill for a
real edge case. Just wanted to mention it :)

> 
> 
> >> +        if (unit_check(&irb) && retries <= 2) {
> >> +            basic_sense(schid, &sd);
> >> +            retries++;
> >> +            continue;
> >> +        }
> >> +
> >> +        break;
> >> +    }
> >> +
> >> +    return rc;
> >> +}  
> > 
> > (...)
> >   
> >> @@ -190,6 +247,9 @@ struct ciw {
> >>       __u16 count;
> >>   };
> >>   
> >> +#define CU_TYPE_VIRTIO          0x3832
> >> +#define CU_TYPE_DASD            0x3990  
> > 
> > No other dasd types we want to support? :) (Not sure if others are out
> > in the wild. Maybe FBA?)
> >  
> 
> I have no idea. I assumed 3390 was the only thing we supported. Perhaps 3380? I'd need to 
> find a test device, which I could probably do ... I'll look more into this.

IIRC, z/VM can hand out FBA devices. I'm not sure if current storage
systems can emulate them.

> 
> 
> >> +
> >>   /*
> >>    * sense-id response buffer layout
> >>    */
> >> @@ -205,6 +265,61 @@ typedef struct senseid {
> >>       struct ciw ciw[62];
> >>   }  __attribute__ ((packed, aligned(4))) SenseId;
> >>   
> >> +/* architected values for first sense byte */
> >> +#define SNS0_CMD_REJECT         0x80
> >> +#define SNS0_INTERVENTION_REQ   0x40
> >> +#define SNS0_BUS_OUT_CHECK      0x20
> >> +#define SNS0_EQUIPMENT_CHECK    0x10
> >> +#define SNS0_DATA_CHECK         0x08
> >> +#define SNS0_OVERRUN            0x04
> >> +#define SNS0_INCOMPL_DOMAIN     0x01  
> > 
> > IIRC, only byte 0 is device independent, and the others below are
> > (ECKD) dasd specific?
> >   
> >> +
> >> +/* architectured values for second sense byte */
> >> +#define SNS1_PERM_ERR           0x80
> >> +#define SNS1_INV_TRACK_FORMAT   0x40
> >> +#define SNS1_EOC                0x20
> >> +#define SNS1_MESSAGE_TO_OPER    0x10
> >> +#define SNS1_NO_REC_FOUND       0x08
> >> +#define SNS1_FILE_PROTECTED     0x04
> >> +#define SNS1_WRITE_INHIBITED    0x02
> >> +#define SNS1_INPRECISE_END      0x01
> >> +
> >> +/* architectured values for third sense byte */
> >> +#define SNS2_REQ_INH_WRITE      0x80
> >> +#define SNS2_CORRECTABLE        0x40
> >> +#define SNS2_FIRST_LOG_ERR      0x20
> >> +#define SNS2_ENV_DATA_PRESENT   0x10
> >> +#define SNS2_INPRECISE_END      0x04
> >> +
> >> +/* 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
> >> +
> >> +#define SENSE24_FMT0_MSG_RESET_NOTIFICATION 0x16
> >> +
> >> +/* basic sense response buffer layout */
> >> +typedef struct senseData {
> >> +    uint8_t status[3];
> >> +    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))) SenseData;  
> > 
> > And this looks _really_ dasd specific.
> >   
> 
> Yep, I glossed over those details while I was furiously tracking down the reset bug. I'll 
> take a look at redesigning this.

Ok.

> 
> >> +
> >> +#define SENSE24_GET_FMT(sd)     (sd->fmt_msg & 0xF0 >> 4)
> >> +#define SENSE24_GET_MSG(sd)     (sd->fmt_msg & 0x0F)
> >> +
> >> +#define unit_check(irb)     ((irb)->scsw.dstat & SCSW_DSTAT_UCHK)
> >> +
> >>   /* interruption response block */
> >>   typedef struct irb {
> >>       struct scsw scsw;  
> > 
> > (...)
> >   
> >> diff --git a/pc-bios/s390-ccw/start.S b/pc-bios/s390-ccw/start.S
> >> index eb8d024..a48c38f 100644
> >> --- a/pc-bios/s390-ccw/start.S
> >> +++ b/pc-bios/s390-ccw/start.S
> >> @@ -65,12 +65,32 @@ consume_sclp_int:
> >>           /* prepare external call handler */
> >>           larl %r1, external_new_code
> >>           stg %r1, 0x1b8
> >> -        larl %r1, external_new_mask
> >> +        larl %r1, int_new_mask
> >>           mvc 0x1b0(8),0(%r1)
> >>           /* load enabled wait PSW */
> >>           larl %r1, enabled_wait_psw
> >>           lpswe 0(%r1)
> >>   
> >> +/*
> >> + * void consume_io_int(void)
> >> + *
> >> + * eats one I/O interrupt  
> > 
> > *nomnom*
> >   
> >> + */
> >> +        .globl consume_io_int
> >> +consume_io_int:
> >> +        /* enable I/O interrupts in cr0 */  
> > 
> > cr6?
> >   
> >> +        stctg 6,6,0(15)
> >> +        oi 4(15), 0xff
> >> +        lctlg 6,6,0(15)
> >> +        /* prepare external call handler */  
> > 
> > I/O call handler?
> >   
> 
> Both copy/paste errors. Thanks for catching these. :)
> 
> >> +        larl %r1, io_new_code
> >> +        stg %r1, 0x1f8
> >> +        larl %r1, int_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 0,0,0(15)
> >> @@ -78,10 +98,19 @@ external_new_code:
> >>           lctlg 0,0,0(15)
> >>           br 14
> >>   
> >> +io_new_code:
> >> +        /* disable I/O interrupts in cr6 */
> >> +        stctg 6,6,0(15)  
> > 
> > I'm wondering why you are changing cr6 every time you wait for an I/O
> > interrupt. Just enable the isc(s) you want once, and disable them again
> > after you're done with all I/O? Simply disabling the I/O interrupts
> > should be enough to prevent further interrupts popping up. You maybe
> > want two enabled wait PSWs, one with I/O + external and one with
> > external only?
> >   
> 
> No real reason. We only come through here a hand full of times so performance is not a 
> consideration. I guess my thought process was probably to keep the system is as close to 
> initial state as possible through the ipl process. Eventually when we hand control to the 
> guest OS we want the system as close to undisturbed as possible. If you think I should 
> only be setting cr-6 once, it sounds reasonable.

It just looked a bit odd to me. But I agree that this isn't
performance-sensitive.

> 
> 
> >> +        ni 4(15), 0x00
> >> +        lctlg 6,6,0(15)
> >> +        br 14
> >> +
> >> +
> >> +
> >>           .align  8
> >>   disabled_wait_psw:
> >>           .quad   0x0002000180000000,0x0000000000000000
> >>   enabled_wait_psw:
> >>           .quad   0x0302000180000000,0x0000000000000000
> >> -external_new_mask:
> >> +int_new_mask:
> >>           .quad   0x0000000180000000  
> > 
> >   
> 
>
Jason J. Herne Jan. 9, 2019, 6:10 p.m. UTC | #5
On 1/7/19 2:02 PM, Jason J. Herne wrote:
>>> +
>>>   /*
>>>    * sense-id response buffer layout
>>>    */
>>> @@ -205,6 +265,61 @@ typedef struct senseid {
>>>       struct ciw ciw[62];
>>>   }  __attribute__ ((packed, aligned(4))) SenseId;
>>> +/* architected values for first sense byte */
>>> +#define SNS0_CMD_REJECT         0x80
>>> +#define SNS0_INTERVENTION_REQ   0x40
>>> +#define SNS0_BUS_OUT_CHECK      0x20
>>> +#define SNS0_EQUIPMENT_CHECK    0x10
>>> +#define SNS0_DATA_CHECK         0x08
>>> +#define SNS0_OVERRUN            0x04
>>> +#define SNS0_INCOMPL_DOMAIN     0x01
>>
>> IIRC, only byte 0 is device independent, and the others below are
>> (ECKD) dasd specific?
>>
>>> +
>>> +/* architectured values for second sense byte */
>>> +#define SNS1_PERM_ERR           0x80
>>> +#define SNS1_INV_TRACK_FORMAT   0x40
>>> +#define SNS1_EOC                0x20
>>> +#define SNS1_MESSAGE_TO_OPER    0x10
>>> +#define SNS1_NO_REC_FOUND       0x08
>>> +#define SNS1_FILE_PROTECTED     0x04
>>> +#define SNS1_WRITE_INHIBITED    0x02
>>> +#define SNS1_INPRECISE_END      0x01
>>> +
>>> +/* architectured values for third sense byte */
>>> +#define SNS2_REQ_INH_WRITE      0x80
>>> +#define SNS2_CORRECTABLE        0x40
>>> +#define SNS2_FIRST_LOG_ERR      0x20
>>> +#define SNS2_ENV_DATA_PRESENT   0x10
>>> +#define SNS2_INPRECISE_END      0x04
>>> +
>>> +/* 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
>>> +
>>> +#define SENSE24_FMT0_MSG_RESET_NOTIFICATION 0x16
>>> +
>>> +/* basic sense response buffer layout */
>>> +typedef struct senseData {
>>> +    uint8_t status[3];
>>> +    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))) SenseData;
>>
>> And this looks _really_ dasd specific.
>>
> 
> Yep, I glossed over those details while I was furiously tracking down the reset bug. I'll 
> take a look at redesigning this.

All of my information for creating these data structures came from an internal ECKD DASD 
reference. There are probably some things that could stand a bit of cleanup or renaming. 
Aside from that, considering this is in a DASD only (ECKD DASD only at the moment) code 
path are you okay with my renaming the struct to senseDataECKD or something similar?
I'm not sure what value there is in abstracting sense at the moment. I'm not even sure 
what other device's sense data looks like. Since my description of the SENSE CCW comes 
from an ECKD reference I have not been able to verify any areas of the data that are 
common across device types. Thoughts?
Cornelia Huck Jan. 9, 2019, 6:34 p.m. UTC | #6
On Wed, 9 Jan 2019 13:10:26 -0500
"Jason J. Herne" <jjherne@linux.ibm.com> wrote:

> On 1/7/19 2:02 PM, Jason J. Herne wrote:
> >>> +
> >>>   /*
> >>>    * sense-id response buffer layout
> >>>    */
> >>> @@ -205,6 +265,61 @@ typedef struct senseid {
> >>>       struct ciw ciw[62];
> >>>   }  __attribute__ ((packed, aligned(4))) SenseId;
> >>> +/* architected values for first sense byte */
> >>> +#define SNS0_CMD_REJECT         0x80
> >>> +#define SNS0_INTERVENTION_REQ   0x40
> >>> +#define SNS0_BUS_OUT_CHECK      0x20
> >>> +#define SNS0_EQUIPMENT_CHECK    0x10
> >>> +#define SNS0_DATA_CHECK         0x08
> >>> +#define SNS0_OVERRUN            0x04
> >>> +#define SNS0_INCOMPL_DOMAIN     0x01  
> >>
> >> IIRC, only byte 0 is device independent, and the others below are
> >> (ECKD) dasd specific?
> >>  
> >>> +
> >>> +/* architectured values for second sense byte */
> >>> +#define SNS1_PERM_ERR           0x80
> >>> +#define SNS1_INV_TRACK_FORMAT   0x40
> >>> +#define SNS1_EOC                0x20
> >>> +#define SNS1_MESSAGE_TO_OPER    0x10
> >>> +#define SNS1_NO_REC_FOUND       0x08
> >>> +#define SNS1_FILE_PROTECTED     0x04
> >>> +#define SNS1_WRITE_INHIBITED    0x02
> >>> +#define SNS1_INPRECISE_END      0x01
> >>> +
> >>> +/* architectured values for third sense byte */
> >>> +#define SNS2_REQ_INH_WRITE      0x80
> >>> +#define SNS2_CORRECTABLE        0x40
> >>> +#define SNS2_FIRST_LOG_ERR      0x20
> >>> +#define SNS2_ENV_DATA_PRESENT   0x10
> >>> +#define SNS2_INPRECISE_END      0x04
> >>> +
> >>> +/* 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
> >>> +
> >>> +#define SENSE24_FMT0_MSG_RESET_NOTIFICATION 0x16
> >>> +
> >>> +/* basic sense response buffer layout */
> >>> +typedef struct senseData {
> >>> +    uint8_t status[3];
> >>> +    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))) SenseData;  
> >>
> >> And this looks _really_ dasd specific.
> >>  
> > 
> > Yep, I glossed over those details while I was furiously tracking down the reset bug. I'll 
> > take a look at redesigning this.  
> 
> All of my information for creating these data structures came from an internal ECKD DASD 
> reference. There are probably some things that could stand a bit of cleanup or renaming. 
> Aside from that, considering this is in a DASD only (ECKD DASD only at the moment) code 
> path are you okay with my renaming the struct to senseDataECKD or something similar?

Renaming this makes sense.

> I'm not sure what value there is in abstracting sense at the moment. I'm not even sure 
> what other device's sense data looks like. Since my description of the SENSE CCW comes 
> from an ECKD reference I have not been able to verify any areas of the data that are 
> common across device types. Thoughts?

There's SA22-7204-01 ("Common I/O Device Commands"), which is from 1992
(this is what I have on my disk -- is there anything newer?). It
specifies what bits 0-5 of byte 0 mean and states that bytes 1-31 are
optional and device-specific.

Maybe some other bits have been specified after 1992, but I have not
come across documentation for them.
Jason J. Herne Jan. 9, 2019, 8:01 p.m. UTC | #7
On 1/9/19 1:34 PM, Cornelia Huck wrote:
> On Wed, 9 Jan 2019 13:10:26 -0500
> "Jason J. Herne" <jjherne@linux.ibm.com> wrote:
> 
>> On 1/7/19 2:02 PM, Jason J. Herne wrote:
>>>>> +
>>>>>    /*
>>>>>     * sense-id response buffer layout
>>>>>     */
>>>>> @@ -205,6 +265,61 @@ typedef struct senseid {
>>>>>        struct ciw ciw[62];
>>>>>    }  __attribute__ ((packed, aligned(4))) SenseId;
>>>>> +/* architected values for first sense byte */
>>>>> +#define SNS0_CMD_REJECT         0x80
>>>>> +#define SNS0_INTERVENTION_REQ   0x40
>>>>> +#define SNS0_BUS_OUT_CHECK      0x20
>>>>> +#define SNS0_EQUIPMENT_CHECK    0x10
>>>>> +#define SNS0_DATA_CHECK         0x08
>>>>> +#define SNS0_OVERRUN            0x04
>>>>> +#define SNS0_INCOMPL_DOMAIN     0x01
>>>>
>>>> IIRC, only byte 0 is device independent, and the others below are
>>>> (ECKD) dasd specific?
>>>>   
>>>>> +
>>>>> +/* architectured values for second sense byte */
>>>>> +#define SNS1_PERM_ERR           0x80
>>>>> +#define SNS1_INV_TRACK_FORMAT   0x40
>>>>> +#define SNS1_EOC                0x20
>>>>> +#define SNS1_MESSAGE_TO_OPER    0x10
>>>>> +#define SNS1_NO_REC_FOUND       0x08
>>>>> +#define SNS1_FILE_PROTECTED     0x04
>>>>> +#define SNS1_WRITE_INHIBITED    0x02
>>>>> +#define SNS1_INPRECISE_END      0x01
>>>>> +
>>>>> +/* architectured values for third sense byte */
>>>>> +#define SNS2_REQ_INH_WRITE      0x80
>>>>> +#define SNS2_CORRECTABLE        0x40
>>>>> +#define SNS2_FIRST_LOG_ERR      0x20
>>>>> +#define SNS2_ENV_DATA_PRESENT   0x10
>>>>> +#define SNS2_INPRECISE_END      0x04
>>>>> +
>>>>> +/* 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
>>>>> +
>>>>> +#define SENSE24_FMT0_MSG_RESET_NOTIFICATION 0x16
>>>>> +
>>>>> +/* basic sense response buffer layout */
>>>>> +typedef struct senseData {
>>>>> +    uint8_t status[3];
>>>>> +    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))) SenseData;
>>>>
>>>> And this looks _really_ dasd specific.
>>>>   
>>>
>>> Yep, I glossed over those details while I was furiously tracking down the reset bug. I'll
>>> take a look at redesigning this.
>>
>> All of my information for creating these data structures came from an internal ECKD DASD
>> reference. There are probably some things that could stand a bit of cleanup or renaming.
>> Aside from that, considering this is in a DASD only (ECKD DASD only at the moment) code
>> path are you okay with my renaming the struct to senseDataECKD or something similar?
> 
> Renaming this makes sense.
> 
>> I'm not sure what value there is in abstracting sense at the moment. I'm not even sure
>> what other device's sense data looks like. Since my description of the SENSE CCW comes
>> from an ECKD reference I have not been able to verify any areas of the data that are
>> common across device types. Thoughts?
> 
> There's SA22-7204-01 ("Common I/O Device Commands"), which is from 1992
> (this is what I have on my disk -- is there anything newer?). It
> specifies what bits 0-5 of byte 0 mean and states that bytes 1-31 are
> optional and device-specific.
> 
> Maybe some other bits have been specified after 1992, but I have not
> come across documentation for them.

That publication is no longer available. According to my quick research it has been 
replaced by an internal only publication. I'll see what I can find.
Cornelia Huck Jan. 10, 2019, 12:15 p.m. UTC | #8
On Wed, 9 Jan 2019 15:01:19 -0500
"Jason J. Herne" <jjherne@linux.ibm.com> wrote:

> On 1/9/19 1:34 PM, Cornelia Huck wrote:
> > On Wed, 9 Jan 2019 13:10:26 -0500
> > "Jason J. Herne" <jjherne@linux.ibm.com> wrote:

> >> I'm not sure what value there is in abstracting sense at the moment. I'm not even sure
> >> what other device's sense data looks like. Since my description of the SENSE CCW comes
> >> from an ECKD reference I have not been able to verify any areas of the data that are
> >> common across device types. Thoughts?  
> > 
> > There's SA22-7204-01 ("Common I/O Device Commands"), which is from 1992
> > (this is what I have on my disk -- is there anything newer?). It
> > specifies what bits 0-5 of byte 0 mean and states that bytes 1-31 are
> > optional and device-specific.
> > 
> > Maybe some other bits have been specified after 1992, but I have not
> > come across documentation for them.  
> 
> That publication is no longer available. According to my quick research it has been 
> replaced by an internal only publication. I'll see what I can find.

The publication no longer being available is not good, as it is a
normative reference pointed to by the virtio standard (see
http://docs.oasis-open.org/virtio/virtio/v1.0/cs04/virtio-v1.0-cs04.html#x1-30001)
:(

Is there any chance that at least that old version can be made
available again?
Jason J. Herne Jan. 10, 2019, 3:02 p.m. UTC | #9
On 1/10/19 7:15 AM, Cornelia Huck wrote:
> On Wed, 9 Jan 2019 15:01:19 -0500
> "Jason J. Herne" <jjherne@linux.ibm.com> wrote:
> 
>> On 1/9/19 1:34 PM, Cornelia Huck wrote:
>>> On Wed, 9 Jan 2019 13:10:26 -0500
>>> "Jason J. Herne" <jjherne@linux.ibm.com> wrote:
> 
>>>> I'm not sure what value there is in abstracting sense at the moment. I'm not even sure
>>>> what other device's sense data looks like. Since my description of the SENSE CCW comes
>>>> from an ECKD reference I have not been able to verify any areas of the data that are
>>>> common across device types. Thoughts?
>>>
>>> There's SA22-7204-01 ("Common I/O Device Commands"), which is from 1992
>>> (this is what I have on my disk -- is there anything newer?). It
>>> specifies what bits 0-5 of byte 0 mean and states that bytes 1-31 are
>>> optional and device-specific.
>>>
>>> Maybe some other bits have been specified after 1992, but I have not
>>> come across documentation for them.
>>
>> That publication is no longer available. According to my quick research it has been
>> replaced by an internal only publication. I'll see what I can find.
> 
> The publication no longer being available is not good, as it is a
> normative reference pointed to by the virtio standard (see
> http://docs.oasis-open.org/virtio/virtio/v1.0/cs04/virtio-v1.0-cs04.html#x1-30001)
> :(
> 
> Is there any chance that at least that old version can be made
> available again?

A quick web search turns up the following link:
http://publibz.boulder.ibm.com/support/libraryserver/FRAMESET/DZ9AR501/CCONTENTS?D

So I guess it is available, even if the document has been superseded internally.
Cornelia Huck Jan. 10, 2019, 3:21 p.m. UTC | #10
On Thu, 10 Jan 2019 10:02:48 -0500
"Jason J. Herne" <jjherne@linux.ibm.com> wrote:

> On 1/10/19 7:15 AM, Cornelia Huck wrote:
> > On Wed, 9 Jan 2019 15:01:19 -0500
> > "Jason J. Herne" <jjherne@linux.ibm.com> wrote:
> >   
> >> On 1/9/19 1:34 PM, Cornelia Huck wrote:  
> >>> On Wed, 9 Jan 2019 13:10:26 -0500
> >>> "Jason J. Herne" <jjherne@linux.ibm.com> wrote:  
> >   
> >>>> I'm not sure what value there is in abstracting sense at the moment. I'm not even sure
> >>>> what other device's sense data looks like. Since my description of the SENSE CCW comes
> >>>> from an ECKD reference I have not been able to verify any areas of the data that are
> >>>> common across device types. Thoughts?  
> >>>
> >>> There's SA22-7204-01 ("Common I/O Device Commands"), which is from 1992
> >>> (this is what I have on my disk -- is there anything newer?). It
> >>> specifies what bits 0-5 of byte 0 mean and states that bytes 1-31 are
> >>> optional and device-specific.
> >>>
> >>> Maybe some other bits have been specified after 1992, but I have not
> >>> come across documentation for them.  
> >>
> >> That publication is no longer available. According to my quick research it has been
> >> replaced by an internal only publication. I'll see what I can find.  
> > 
> > The publication no longer being available is not good, as it is a
> > normative reference pointed to by the virtio standard (see
> > http://docs.oasis-open.org/virtio/virtio/v1.0/cs04/virtio-v1.0-cs04.html#x1-30001)
> > :(
> > 
> > Is there any chance that at least that old version can be made
> > available again?  
> 
> A quick web search turns up the following link:
> http://publibz.boulder.ibm.com/support/libraryserver/FRAMESET/DZ9AR501/CCONTENTS?D
> 
> So I guess it is available, even if the document has been superseded internally.

Cool, thanks for checking!
Jason J. Herne Jan. 14, 2019, 6:44 p.m. UTC | #11
On 1/7/19 2:02 PM, Jason J. Herne wrote:
>>> @@ -190,6 +247,9 @@ struct ciw {
>>>       __u16 count;
>>>   };
>>> +#define CU_TYPE_VIRTIO          0x3832
>>> +#define CU_TYPE_DASD            0x3990
>>
>> No other dasd types we want to support? :) (Not sure if others are out
>> in the wild. Maybe FBA?)
>>
> 
> I have no idea. I assumed 3390 was the only thing we supported. Perhaps 3380? I'd need to 
> find a test device, which I could probably do ... I'll look more into this.

After a few discussions with folks in the lab we've decided that we don't see a ton of 
value in supporting anything other than 3990 at the moment. Anything else would be older 
(3380) and/or rare to see in the wild (and very difficult to test). As for emulated setups 
like z/VM, a user can just use 3390 instead of FBA. So I recommend we move forward with 
3390/3990 support for now. We can always add in others types if/when we need them.
Cornelia Huck Jan. 15, 2019, 8:54 a.m. UTC | #12
On Mon, 14 Jan 2019 13:44:12 -0500
"Jason J. Herne" <jjherne@linux.ibm.com> wrote:

> On 1/7/19 2:02 PM, Jason J. Herne wrote:
> >>> @@ -190,6 +247,9 @@ struct ciw {
> >>>       __u16 count;
> >>>   };
> >>> +#define CU_TYPE_VIRTIO          0x3832
> >>> +#define CU_TYPE_DASD            0x3990  
> >>
> >> No other dasd types we want to support? :) (Not sure if others are out
> >> in the wild. Maybe FBA?)
> >>  
> > 
> > I have no idea. I assumed 3390 was the only thing we supported. Perhaps 3380? I'd need to 
> > find a test device, which I could probably do ... I'll look more into this.  
> 
> After a few discussions with folks in the lab we've decided that we don't see a ton of 
> value in supporting anything other than 3990 at the moment. Anything else would be older 
> (3380) and/or rare to see in the wild (and very difficult to test). As for emulated setups 
> like z/VM, a user can just use 3390 instead of FBA. So I recommend we move forward with 
> 3390/3990 support for now. We can always add in others types if/when we need them.

Sounds reasonable.

What about calling the #define above CU_TYPE_DASD_3990 instead? Just to
make clear that there are other dasd types out there, but we only
support that particular one (at least at the moment).
Jason J. Herne Jan. 16, 2019, 3:19 p.m. UTC | #13
On 1/9/19 1:34 PM, Cornelia Huck wrote:
> On Wed, 9 Jan 2019 13:10:26 -0500
> "Jason J. Herne" <jjherne@linux.ibm.com> wrote:
> 
>> On 1/7/19 2:02 PM, Jason J. Herne wrote:
>>>>> +
>>>>>    /*
>>>>>     * sense-id response buffer layout
>>>>>     */
>>>>> @@ -205,6 +265,61 @@ typedef struct senseid {
>>>>>        struct ciw ciw[62];
>>>>>    }  __attribute__ ((packed, aligned(4))) SenseId;
>>>>> +/* architected values for first sense byte */
>>>>> +#define SNS0_CMD_REJECT         0x80
>>>>> +#define SNS0_INTERVENTION_REQ   0x40
>>>>> +#define SNS0_BUS_OUT_CHECK      0x20
>>>>> +#define SNS0_EQUIPMENT_CHECK    0x10
>>>>> +#define SNS0_DATA_CHECK         0x08
>>>>> +#define SNS0_OVERRUN            0x04
>>>>> +#define SNS0_INCOMPL_DOMAIN     0x01
>>>>
>>>> IIRC, only byte 0 is device independent, and the others below are
>>>> (ECKD) dasd specific?
>>>>   
>>>>> +
>>>>> +/* architectured values for second sense byte */
>>>>> +#define SNS1_PERM_ERR           0x80
>>>>> +#define SNS1_INV_TRACK_FORMAT   0x40
>>>>> +#define SNS1_EOC                0x20
>>>>> +#define SNS1_MESSAGE_TO_OPER    0x10
>>>>> +#define SNS1_NO_REC_FOUND       0x08
>>>>> +#define SNS1_FILE_PROTECTED     0x04
>>>>> +#define SNS1_WRITE_INHIBITED    0x02
>>>>> +#define SNS1_INPRECISE_END      0x01
>>>>> +
>>>>> +/* architectured values for third sense byte */
>>>>> +#define SNS2_REQ_INH_WRITE      0x80
>>>>> +#define SNS2_CORRECTABLE        0x40
>>>>> +#define SNS2_FIRST_LOG_ERR      0x20
>>>>> +#define SNS2_ENV_DATA_PRESENT   0x10
>>>>> +#define SNS2_INPRECISE_END      0x04
>>>>> +
>>>>> +/* 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
>>>>> +
>>>>> +#define SENSE24_FMT0_MSG_RESET_NOTIFICATION 0x16
>>>>> +
>>>>> +/* basic sense response buffer layout */
>>>>> +typedef struct senseData {
>>>>> +    uint8_t status[3];
>>>>> +    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))) SenseData;
>>>>
>>>> And this looks _really_ dasd specific.
>>>>   
>>>
>>> Yep, I glossed over those details while I was furiously tracking down the reset bug. I'll
>>> take a look at redesigning this.
>>
>> All of my information for creating these data structures came from an internal ECKD DASD
>> reference. There are probably some things that could stand a bit of cleanup or renaming.
>> Aside from that, considering this is in a DASD only (ECKD DASD only at the moment) code
>> path are you okay with my renaming the struct to senseDataECKD or something similar?
> 
> Renaming this makes sense.
> 
>> I'm not sure what value there is in abstracting sense at the moment. I'm not even sure
>> what other device's sense data looks like. Since my description of the SENSE CCW comes
>> from an ECKD reference I have not been able to verify any areas of the data that are
>> common across device types. Thoughts?
> 
> There's SA22-7204-01 ("Common I/O Device Commands"), which is from 1992
> (this is what I have on my disk -- is there anything newer?). It
> specifies what bits 0-5 of byte 0 mean and states that bytes 1-31 are
> optional and device-specific.
> 
> Maybe some other bits have been specified after 1992, but I have not
> come across documentation for them.
> 

So everything I'm finding (including SA22-7204-01) only speaks of the first 6 bits being 
device agnostic. It is odd that the entire first byte would not have been reserved. 
Perhaps it is and I'm just not looking at the right documentation. My thought process is 
to have the basic_Sense function change to this:

- void basic_sense(SubChannelId schid, SenseData *sd);
+ void basic_sense(SubChannelId schid, void *sense_data);

The caller is free to map it however they see fit depending on the device type they are 
sensing. I'll rename struct senseData to struct senseDataEckdDasd, break out the first 
status byte and define common constants for the first 6 bits of that byte. This should 
clear up the confusion. I'll add a small comment to explain. Does this sound good?
diff mbox series

Patch

diff --git a/pc-bios/s390-ccw/cio.c b/pc-bios/s390-ccw/cio.c
index 095f79b..9019250 100644
--- a/pc-bios/s390-ccw/cio.c
+++ b/pc-bios/s390-ccw/cio.c
@@ -10,6 +10,7 @@ 
 
 #include "libc.h"
 #include "s390-ccw.h"
+#include "s390-arch.h"
 #include "cio.h"
 
 static char chsc_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
@@ -39,3 +40,110 @@  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);
+
+    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, SenseData *sd)
+{
+    Ccw1 senseCcw;
+
+    senseCcw.cmd_code = CCW_CMD_BASIC_SENSE;
+    senseCcw.cda = ptr2u32(sd);
+    senseCcw.count = sizeof(*sd);
+
+    if (do_cio(schid, ptr2u32(&senseCcw), CCW_FMT1)) {
+        panic("Failed to run Basic Sense CCW\n");
+    }
+}
+
+static bool irb_error(Irb *irb)
+{
+    /* We have to ignore Incorrect Length (cstat == 0x40) indicators because
+     * real devices expect a 24 byte SenseID  buffer, and virtio devices expect
+     * a much larger buffer. Neither device type can tolerate a buffer size
+     * different from what they expect so they set this indicator.
+     */
+    if (irb->scsw.cstat != 0x00 && irb->scsw.cstat != 0x40) {
+        return true;
+    }
+    return irb->scsw.dstat != 0xc;
+}
+
+/* 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
+ * singaling completion of the I/O operation(s) perfomed 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.
+ */
+int do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt)
+{
+    CmdOrb orb = {};
+    Irb irb = {};
+    SenseData sd;
+    int rc, retries = 0;
+
+    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;
+
+    while (true) {
+        rc = ssch(schid, &orb);
+        if (rc) {
+            print_int("ssch failed with rc=", rc);
+            break;
+        }
+
+        consume_io_int();
+
+        /* Clear read */
+        rc = tsch(schid, &irb);
+        if (rc) {
+            print_int("tsch failed with rc=", rc);
+            break;
+        }
+
+        if (!irb_error(&irb)) {
+            break;
+        }
+
+        /* Unexpected unit check. Use sense to clear unit check then retry. */
+        if (unit_check(&irb) && retries <= 2) {
+            basic_sense(schid, &sd);
+            retries++;
+            continue;
+        }
+
+        break;
+    }
+
+    return rc;
+}
diff --git a/pc-bios/s390-ccw/cio.h b/pc-bios/s390-ccw/cio.h
index 7b07d75..5c16635 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            0x3990
+
 /*
  * sense-id response buffer layout
  */
@@ -205,6 +265,61 @@  typedef struct senseid {
     struct ciw ciw[62];
 }  __attribute__ ((packed, aligned(4))) SenseId;
 
+/* architected values for first sense byte */
+#define SNS0_CMD_REJECT         0x80
+#define SNS0_INTERVENTION_REQ   0x40
+#define SNS0_BUS_OUT_CHECK      0x20
+#define SNS0_EQUIPMENT_CHECK    0x10
+#define SNS0_DATA_CHECK         0x08
+#define SNS0_OVERRUN            0x04
+#define SNS0_INCOMPL_DOMAIN     0x01
+
+/* architectured values for second sense byte */
+#define SNS1_PERM_ERR           0x80
+#define SNS1_INV_TRACK_FORMAT   0x40
+#define SNS1_EOC                0x20
+#define SNS1_MESSAGE_TO_OPER    0x10
+#define SNS1_NO_REC_FOUND       0x08
+#define SNS1_FILE_PROTECTED     0x04
+#define SNS1_WRITE_INHIBITED    0x02
+#define SNS1_INPRECISE_END      0x01
+
+/* architectured values for third sense byte */
+#define SNS2_REQ_INH_WRITE      0x80
+#define SNS2_CORRECTABLE        0x40
+#define SNS2_FIRST_LOG_ERR      0x20
+#define SNS2_ENV_DATA_PRESENT   0x10
+#define SNS2_INPRECISE_END      0x04
+
+/* 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
+
+#define SENSE24_FMT0_MSG_RESET_NOTIFICATION 0x16
+
+/* basic sense response buffer layout */
+typedef struct senseData {
+    uint8_t status[3];
+    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))) SenseData;
+
+#define SENSE24_GET_FMT(sd)     (sd->fmt_msg & 0xF0 >> 4)
+#define SENSE24_GET_MSG(sd)     (sd->fmt_msg & 0x0F)
+
+#define unit_check(irb)     ((irb)->scsw.dstat & SCSW_DSTAT_UCHK)
+
 /* interruption response block */
 typedef struct irb {
     struct scsw scsw;
@@ -215,6 +330,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, SenseData *sd);
+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 eb8d024..a48c38f 100644
--- a/pc-bios/s390-ccw/start.S
+++ b/pc-bios/s390-ccw/start.S
@@ -65,12 +65,32 @@  consume_sclp_int:
         /* prepare external call handler */
         larl %r1, external_new_code
         stg %r1, 0x1b8
-        larl %r1, external_new_mask
+        larl %r1, int_new_mask
         mvc 0x1b0(8),0(%r1)
         /* load enabled wait PSW */
         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 cr0 */
+        stctg 6,6,0(15)
+        oi 4(15), 0xff
+        lctlg 6,6,0(15)
+        /* prepare external call handler */
+        larl %r1, io_new_code
+        stg %r1, 0x1f8
+        larl %r1, int_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 0,0,0(15)
@@ -78,10 +98,19 @@  external_new_code:
         lctlg 0,0,0(15)
         br 14
 
+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
 enabled_wait_psw:
         .quad   0x0302000180000000,0x0000000000000000
-external_new_mask:
+int_new_mask:
         .quad   0x0000000180000000