/* * Channel IO definitions * * Copyright (c) 2013 Alexander Graf * * Inspired by various s390 headers in Linux 3.9. * * This work is licensed under the terms of the GNU GPL, version 2 or (at * your option) any later version. See the COPYING file in the top-level * directory. */ #ifndef CIO_H #define CIO_H /* * path management control word */ struct pmcw { u32 intparm; /* interruption parameter */ u32 qf:1; /* qdio facility */ u32 w:1; u32 isc:3; /* interruption subclass */ u32 res5:3; /* reserved zeros */ u32 ena:1; /* enabled */ u32 lm:2; /* limit mode */ u32 mme:2; /* measurement-mode enable */ u32 mp:1; /* multipath mode */ u32 tf:1; /* timing facility */ u32 dnv:1; /* device number valid */ u32 dev:16; /* device number */ u8 lpm; /* logical path mask */ u8 pnom; /* path not operational mask */ u8 lpum; /* last path used mask */ u8 pim; /* path installed mask */ u16 mbi; /* measurement-block index */ u8 pom; /* path operational mask */ u8 pam; /* path available mask */ u8 chpid[8]; /* CHPID 0-7 (if available) */ u32 unused1:8; /* reserved zeros */ u32 st:3; /* subchannel type */ u32 unused2:18; /* reserved zeros */ u32 mbfc:1; /* measurement block format control */ u32 xmwme:1; /* extended measurement word mode enable */ u32 csense:1; /* concurrent sense; can be enabled ...*/ /* ... per MSCH, however, if facility */ /* ... is not installed, this results */ /* ... in an operand exception. */ } __attribute__ ((packed)); /* Target SCHIB configuration. */ struct schib_config { u64 mba; u32 intparm; u16 mbi; u32 isc:3; u32 ena:1; u32 mme:2; u32 mp:1; u32 csense:1; u32 mbfc:1; } __attribute__ ((packed)); struct scsw { u16 flags; u16 ctrl; u32 cpa; u8 dstat; u8 cstat; u16 count; } __attribute__ ((packed)); /* 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 */ typedef struct schib { struct pmcw pmcw; /* path management control word */ struct scsw scsw; /* subchannel status word */ u64 mba; /* measurement block address */ u8 mda[4]; /* model dependent area */ } __attribute__ ((packed, aligned(4))) Schib; typedef struct subchannel_id { union { struct { u16 cssid:8; u16 reserved:4; u16 m:1; u16 ssid:2; u16 one:1; }; u16 sch_id; }; u16 sch_no; } __attribute__ ((packed, aligned(4))) SubChannelId; struct chsc_header { u16 length; u16 code; } __attribute__((packed)); typedef struct chsc_area_sda { struct chsc_header request; u8 reserved1:4; u8 format:4; u8 reserved2; u16 operation_code; u32 reserved3; u32 reserved4; u32 operation_data_area[252]; struct chsc_header response; u32 reserved5:4; u32 format2:4; u32 reserved6:24; } __attribute__((packed)) ChscAreaSda; /* * TPI info structure */ struct tpi_info { struct subchannel_id schid; u32 intparm; /* interruption parameter */ u32 adapter_IO:1; u32 reserved2:1; u32 isc:3; u32 reserved3:12; u32 int_type:3; u32 reserved4:12; } __attribute__ ((packed, aligned(4))); /* 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; u16 count; 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 #define CCW_FLAG_SKIP 0x10 #define CCW_FLAG_PCI 0x08 #define CCW_FLAG_IDA 0x04 #define CCW_FLAG_SUSPEND 0x02 /* Common CCW commands */ #define CCW_CMD_READ_IPL 0x02 #define CCW_CMD_NOOP 0x03 #define CCW_CMD_BASIC_SENSE 0x04 #define CCW_CMD_TIC 0x08 #define CCW_CMD_SENSE_ID 0xe4 /* Virtio CCW commands */ #define CCW_CMD_SET_VQ 0x13 #define CCW_CMD_VDEV_RESET 0x33 #define CCW_CMD_READ_FEAT 0x12 #define CCW_CMD_WRITE_FEAT 0x11 #define CCW_CMD_READ_CONF 0x22 #define CCW_CMD_WRITE_CONF 0x21 #define CCW_CMD_WRITE_STATUS 0x31 #define CCW_CMD_SET_IND 0x43 #define CCW_CMD_SET_CONF_IND 0x53 #define CCW_CMD_READ_VQ_CONF 0x32 /* DASD CCW commands */ #define CCW_CMD_DASD_READ 0x06 #define CCW_CMD_DASD_SEEK 0x07 #define CCW_CMD_DASD_SEARCH_ID_EQ 0x31 #define CCW_CMD_DASD_READ_MT 0x86 /* * Command-mode operation request block */ typedef struct cmd_orb { u32 intparm; /* interruption parameter */ u32 key:4; /* flags, like key, suspend control, etc. */ u32 spnd:1; /* suspend control */ u32 res1:1; /* reserved */ u32 mod:1; /* modification control */ u32 sync:1; /* synchronize control */ u32 fmt:1; /* format control */ u32 pfch:1; /* prefetch control */ u32 isic:1; /* initial-status-interruption control */ u32 alcc:1; /* address-limit-checking control */ u32 ssic:1; /* suppress-suspended-interr. control */ u32 res2:1; /* reserved */ u32 c64:1; /* IDAW/QDIO 64 bit control */ u32 i2k:1; /* IDAW 2/4kB block size control */ u32 lpm:8; /* logical path mask */ u32 ils:1; /* incorrect length */ u32 zero:6; /* reserved zeros */ u32 orbx:1; /* ORB extension control */ u32 cpa; /* channel program address */ } __attribute__ ((packed, aligned(4))) CmdOrb; struct ciw { u8 type; u8 command; u16 count; }; #define CU_TYPE_UNKNOWN 0x0000 #define CU_TYPE_DASD_2107 0x2107 #define CU_TYPE_VIRTIO 0x3832 #define CU_TYPE_DASD_3990 0x3990 /* * sense-id response buffer layout */ typedef struct senseid { /* common part */ u8 reserved; /* always 0x'FF' */ u16 cu_type; /* control unit type */ u8 cu_model; /* control unit model */ u16 dev_type; /* device type */ u8 dev_model; /* device model */ u8 unused; /* padding byte */ /* extended part */ 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; u32 esw[5]; u32 ecw[8]; u32 emw[8]; } __attribute__ ((packed, aligned(4))) Irb; /* Used for SEEK ccw commands */ typedef struct CcwSeekData { uint16_t reserved; uint16_t cyl; uint16_t head; } __attribute__((packed)) CcwSeekData; /* Used for SEARCH ID ccw commands */ typedef struct CcwSearchIdData { uint16_t cyl; uint16_t head; uint8_t record; } __attribute__((packed)) CcwSearchIdData; extern SubChannelId net_schid; int enable_mss_facility(void); void enable_subchannel(SubChannelId schid); uint16_t cu_type(SubChannelId schid); int basic_sense(SubChannelId schid, uint16_t cutype, void *sense_data, uint16_t data_size); int do_cio(SubChannelId schid, uint16_t cutype, uint32_t ccw_addr, int fmt); /* * Some S390 specific IO instructions as inline */ static inline int stsch_err(struct subchannel_id schid, struct schib *addr) { register struct subchannel_id reg1 asm ("1") = schid; int ccode = -EIO; asm volatile( " stsch 0(%3)\n" "0: ipm %0\n" " srl %0,28\n" "1:\n" : "+d" (ccode), "=m" (*addr) : "d" (reg1), "a" (addr) : "cc"); return ccode; } static inline int msch(struct subchannel_id schid, struct schib *addr) { register struct subchannel_id reg1 asm ("1") = schid; int ccode; asm volatile( " msch 0(%2)\n" " ipm %0\n" " srl %0,28" : "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc"); return ccode; } static inline int msch_err(struct subchannel_id schid, struct schib *addr) { register struct subchannel_id reg1 asm ("1") = schid; int ccode = -EIO; asm volatile( " msch 0(%2)\n" "0: ipm %0\n" " srl %0,28\n" "1:\n" : "+d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc"); return ccode; } static inline int tsch(struct subchannel_id schid, struct irb *addr) { register struct subchannel_id reg1 asm ("1") = schid; int ccode; asm volatile( " tsch 0(%3)\n" " ipm %0\n" " srl %0,28" : "=d" (ccode), "=m" (*addr) : "d" (reg1), "a" (addr) : "cc"); return ccode; } static inline int ssch(struct subchannel_id schid, struct cmd_orb *addr) { register struct subchannel_id reg1 asm("1") = schid; int ccode = -EIO; asm volatile( " ssch 0(%2)\n" "0: ipm %0\n" " srl %0,28\n" "1:\n" : "+d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc", "memory"); return ccode; } static inline int csch(struct subchannel_id schid) { register struct subchannel_id reg1 asm("1") = schid; int ccode; asm volatile( " csch\n" " ipm %0\n" " srl %0,28" : "=d" (ccode) : "d" (reg1) : "cc"); return ccode; } static inline int tpi(struct tpi_info *addr) { int ccode; asm volatile( " tpi 0(%2)\n" " ipm %0\n" " srl %0,28" : "=d" (ccode), "=m" (*addr) : "a" (addr) : "cc"); return ccode; } static inline int chsc(void *chsc_area) { typedef struct { char _[4096]; } addr_type; int cc; asm volatile( " .insn rre,0xb25f0000,%2,0\n" " ipm %0\n" " srl %0,28\n" : "=d" (cc), "=m" (*(addr_type *) chsc_area) : "d" (chsc_area), "m" (*(addr_type *) chsc_area) : "cc"); return cc; } #endif /* CIO_H */