#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
-#include "hw/qdev.h"
-#include "qemu/error-report.h"
#include "qemu/bitops.h"
#include "qemu/error-report.h"
#include "exec/address-spaces.h"
#include "cpu.h"
#include "hw/s390x/ioinst.h"
+#include "hw/qdev-properties.h"
#include "hw/s390x/css.h"
#include "trace.h"
#include "hw/s390x/s390_flic.h"
#include "hw/s390x/s390-virtio-ccw.h"
+#include "hw/s390x/s390-ccw.h"
typedef struct CrwContainer {
CRW crw;
bool do_map)
{
S390FLICState *fs = s390_get_flic();
- S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
+ S390FLICStateClass *fsc = s390_get_flic_class(fs);
return fsc->io_adapter_map(fs, adapter->adapter_id, map_addr, do_map);
}
if (channel_subsys.css[cssid]) {
return -EBUSY;
}
- channel_subsys.css[cssid] = g_malloc0(sizeof(CssImage));
+ channel_subsys.css[cssid] = g_new0(CssImage, 1);
if (default_image) {
channel_subsys.default_cssid = cssid;
}
int ret, isc;
IoAdapter *adapter;
S390FLICState *fs = s390_get_flic();
- S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
+ S390FLICStateClass *fsc = s390_get_flic_class(fs);
/*
* Disallow multiple registrations for the same device type.
Error *err = NULL;
static bool no_clear_irq;
S390FLICState *fs = s390_get_flic();
- S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
+ S390FLICStateClass *fsc = s390_get_flic_class(fs);
int r;
if (unlikely(no_clear_irq)) {
void css_conditional_io_interrupt(SubchDev *sch)
{
+ /*
+ * If the subchannel is not enabled, it is not made status pending
+ * (see PoP p. 16-17, "Status Control").
+ */
+ if (!(sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ENA)) {
+ return;
+ }
+
/*
* If the subchannel is not currently status pending, make it pending
* with alert status.
int css_do_sic(CPUS390XState *env, uint8_t isc, uint16_t mode)
{
S390FLICState *fs = s390_get_flic();
- S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
+ S390FLICStateClass *fsc = s390_get_flic_class(fs);
int r;
if (env->psw.mask & PSW_MASK_PSTATE) {
void css_adapter_interrupt(CssIoAdapterType type, uint8_t isc)
{
S390FLICState *fs = s390_get_flic();
- S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
+ S390FLICStateClass *fsc = s390_get_flic_class(fs);
uint32_t io_int_word = (isc << 27) | IO_INT_WORD_AI;
IoAdapter *adapter = channel_subsys.io_adapters[type][isc];
static void sch_handle_clear_func(SubchDev *sch)
{
- PMCW *p = &sch->curr_status.pmcw;
- SCSW *s = &sch->curr_status.scsw;
+ SCHIB *schib = &sch->curr_status;
int path;
/* Path management: In our simple css, we always choose the only path. */
path = 0x80;
/* Reset values prior to 'issuing the clear signal'. */
- p->lpum = 0;
- p->pom = 0xff;
- s->flags &= ~SCSW_FLAGS_MASK_PNO;
+ schib->pmcw.lpum = 0;
+ schib->pmcw.pom = 0xff;
+ schib->scsw.flags &= ~SCSW_FLAGS_MASK_PNO;
/* We always 'attempt to issue the clear signal', and we always succeed. */
sch->channel_prog = 0x0;
sch->last_cmd_valid = false;
- s->ctrl &= ~SCSW_ACTL_CLEAR_PEND;
- s->ctrl |= SCSW_STCTL_STATUS_PEND;
+ schib->scsw.ctrl &= ~SCSW_ACTL_CLEAR_PEND;
+ schib->scsw.ctrl |= SCSW_STCTL_STATUS_PEND;
- s->dstat = 0;
- s->cstat = 0;
- p->lpum = path;
+ schib->scsw.dstat = 0;
+ schib->scsw.cstat = 0;
+ schib->pmcw.lpum = path;
}
static void sch_handle_halt_func(SubchDev *sch)
{
-
- PMCW *p = &sch->curr_status.pmcw;
- SCSW *s = &sch->curr_status.scsw;
+ SCHIB *schib = &sch->curr_status;
hwaddr curr_ccw = sch->channel_prog;
int path;
/* We always 'attempt to issue the halt signal', and we always succeed. */
sch->channel_prog = 0x0;
sch->last_cmd_valid = false;
- s->ctrl &= ~SCSW_ACTL_HALT_PEND;
- s->ctrl |= SCSW_STCTL_STATUS_PEND;
+ schib->scsw.ctrl &= ~SCSW_ACTL_HALT_PEND;
+ schib->scsw.ctrl |= SCSW_STCTL_STATUS_PEND;
- if ((s->ctrl & (SCSW_ACTL_SUBCH_ACTIVE | SCSW_ACTL_DEVICE_ACTIVE)) ||
- !((s->ctrl & SCSW_ACTL_START_PEND) ||
- (s->ctrl & SCSW_ACTL_SUSP))) {
- s->dstat = SCSW_DSTAT_DEVICE_END;
+ if ((schib->scsw.ctrl & (SCSW_ACTL_SUBCH_ACTIVE |
+ SCSW_ACTL_DEVICE_ACTIVE)) ||
+ !((schib->scsw.ctrl & SCSW_ACTL_START_PEND) ||
+ (schib->scsw.ctrl & SCSW_ACTL_SUSP))) {
+ schib->scsw.dstat = SCSW_DSTAT_DEVICE_END;
}
- if ((s->ctrl & (SCSW_ACTL_SUBCH_ACTIVE | SCSW_ACTL_DEVICE_ACTIVE)) ||
- (s->ctrl & SCSW_ACTL_SUSP)) {
- s->cpa = curr_ccw + 8;
+ if ((schib->scsw.ctrl & (SCSW_ACTL_SUBCH_ACTIVE |
+ SCSW_ACTL_DEVICE_ACTIVE)) ||
+ (schib->scsw.ctrl & SCSW_ACTL_SUSP)) {
+ schib->scsw.cpa = curr_ccw + 8;
}
- s->cstat = 0;
- p->lpum = path;
+ schib->scsw.cstat = 0;
+ schib->pmcw.lpum = path;
}
-static void copy_sense_id_to_guest(SenseId *dest, SenseId *src)
+/*
+ * As the SenseId struct cannot be packed (would cause unaligned accesses), we
+ * have to copy the individual fields to an unstructured area using the correct
+ * layout (see SA22-7204-01 "Common I/O-Device Commands").
+ */
+static void copy_sense_id_to_guest(uint8_t *dest, SenseId *src)
{
int i;
- dest->reserved = src->reserved;
- dest->cu_type = cpu_to_be16(src->cu_type);
- dest->cu_model = src->cu_model;
- dest->dev_type = cpu_to_be16(src->dev_type);
- dest->dev_model = src->dev_model;
- dest->unused = src->unused;
- for (i = 0; i < ARRAY_SIZE(dest->ciw); i++) {
- dest->ciw[i].type = src->ciw[i].type;
- dest->ciw[i].command = src->ciw[i].command;
- dest->ciw[i].count = cpu_to_be16(src->ciw[i].count);
+ dest[0] = src->reserved;
+ stw_be_p(dest + 1, src->cu_type);
+ dest[3] = src->cu_model;
+ stw_be_p(dest + 4, src->dev_type);
+ dest[6] = src->dev_model;
+ dest[7] = src->unused;
+ for (i = 0; i < ARRAY_SIZE(src->ciw); i++) {
+ dest[8 + i * 4] = src->ciw[i].type;
+ dest[9 + i * 4] = src->ciw[i].command;
+ stw_be_p(dest + 10 + i * 4, src->ciw[i].count);
}
}
if (op == CDS_OP_A) {
goto incr;
}
- ret = address_space_rw(&address_space_memory, cds->cda,
- MEMTXATTRS_UNSPECIFIED, buff, len, op);
+ if (!cds->do_skip) {
+ ret = address_space_rw(&address_space_memory, cds->cda,
+ MEMTXATTRS_UNSPECIFIED, buff, len, op);
+ } else {
+ ret = MEMTX_OK;
+ }
if (ret != MEMTX_OK) {
cds->flags |= CDS_F_STREAM_BROKEN;
return -EINVAL;
return 0;
}
+/* returns values between 1 and bsz, where bsz is a power of 2 */
+static inline uint16_t ida_continuous_left(hwaddr cda, uint64_t bsz)
+{
+ return bsz - (cda & (bsz - 1));
+}
+
+static inline uint64_t ccw_ida_block_size(uint8_t flags)
+{
+ if ((flags & CDS_F_C64) && !(flags & CDS_F_I2K)) {
+ return 1ULL << 12;
+ }
+ return 1ULL << 11;
+}
+
+static inline int ida_read_next_idaw(CcwDataStream *cds)
+{
+ union {uint64_t fmt2; uint32_t fmt1; } idaw;
+ int ret;
+ hwaddr idaw_addr;
+ bool idaw_fmt2 = cds->flags & CDS_F_C64;
+ bool ccw_fmt1 = cds->flags & CDS_F_FMT;
+
+ if (idaw_fmt2) {
+ idaw_addr = cds->cda_orig + sizeof(idaw.fmt2) * cds->at_idaw;
+ if (idaw_addr & 0x07 || !cds_ccw_addrs_ok(idaw_addr, 0, ccw_fmt1)) {
+ return -EINVAL; /* channel program check */
+ }
+ ret = address_space_read(&address_space_memory, idaw_addr,
+ MEMTXATTRS_UNSPECIFIED, &idaw.fmt2,
+ sizeof(idaw.fmt2));
+ cds->cda = be64_to_cpu(idaw.fmt2);
+ } else {
+ idaw_addr = cds->cda_orig + sizeof(idaw.fmt1) * cds->at_idaw;
+ if (idaw_addr & 0x03 || !cds_ccw_addrs_ok(idaw_addr, 0, ccw_fmt1)) {
+ return -EINVAL; /* channel program check */
+ }
+ ret = address_space_read(&address_space_memory, idaw_addr,
+ MEMTXATTRS_UNSPECIFIED, &idaw.fmt1,
+ sizeof(idaw.fmt1));
+ cds->cda = be64_to_cpu(idaw.fmt1);
+ if (cds->cda & 0x80000000) {
+ return -EINVAL; /* channel program check */
+ }
+ }
+ ++(cds->at_idaw);
+ if (ret != MEMTX_OK) {
+ /* assume inaccessible address */
+ return -EINVAL; /* channel program check */
+ }
+ return 0;
+}
+
+static int ccw_dstream_rw_ida(CcwDataStream *cds, void *buff, int len,
+ CcwDataStreamOp op)
+{
+ uint64_t bsz = ccw_ida_block_size(cds->flags);
+ int ret = 0;
+ uint16_t cont_left, iter_len;
+
+ ret = cds_check_len(cds, len);
+ if (ret <= 0) {
+ return ret;
+ }
+ if (!cds->at_idaw) {
+ /* read first idaw */
+ ret = ida_read_next_idaw(cds);
+ if (ret) {
+ goto err;
+ }
+ cont_left = ida_continuous_left(cds->cda, bsz);
+ } else {
+ cont_left = ida_continuous_left(cds->cda, bsz);
+ if (cont_left == bsz) {
+ ret = ida_read_next_idaw(cds);
+ if (ret) {
+ goto err;
+ }
+ if (cds->cda & (bsz - 1)) {
+ ret = -EINVAL; /* channel program check */
+ goto err;
+ }
+ }
+ }
+ do {
+ iter_len = MIN(len, cont_left);
+ if (op != CDS_OP_A) {
+ if (!cds->do_skip) {
+ ret = address_space_rw(&address_space_memory, cds->cda,
+ MEMTXATTRS_UNSPECIFIED, buff, iter_len,
+ op);
+ } else {
+ ret = MEMTX_OK;
+ }
+ if (ret != MEMTX_OK) {
+ /* assume inaccessible address */
+ ret = -EINVAL; /* channel program check */
+ goto err;
+ }
+ }
+ cds->at_byte += iter_len;
+ cds->cda += iter_len;
+ len -= iter_len;
+ if (!len) {
+ break;
+ }
+ ret = ida_read_next_idaw(cds);
+ if (ret) {
+ goto err;
+ }
+ cont_left = bsz;
+ } while (true);
+ return ret;
+err:
+ cds->flags |= CDS_F_STREAM_BROKEN;
+ return ret;
+}
+
void ccw_dstream_init(CcwDataStream *cds, CCW1 const *ccw, ORB const *orb)
{
/*
cds->count = ccw->count;
cds->cda_orig = ccw->cda;
+ /* skip is only effective for read, read backwards, or sense commands */
+ cds->do_skip = (ccw->flags & CCW_FLAG_SKIP) &&
+ ((ccw->cmd_code & 0x0f) == CCW_CMD_BASIC_SENSE ||
+ (ccw->cmd_code & 0x03) == 0x02 /* read */ ||
+ (ccw->cmd_code & 0x0f) == 0x0c /* read backwards */);
ccw_dstream_rewind(cds);
if (!(cds->flags & CDS_F_IDA)) {
cds->op_handler = ccw_dstream_rw_noflags;
} else {
- assert(false);
+ cds->op_handler = ccw_dstream_rw_ida;
}
}
break;
case CCW_CMD_SENSE_ID:
{
- SenseId sense_id;
+ /* According to SA22-7204-01, Sense-ID can store up to 256 bytes */
+ uint8_t sense_id[256];
- copy_sense_id_to_guest(&sense_id, &sch->id);
+ copy_sense_id_to_guest(sense_id, &sch->id);
/* Sense ID information is device specific. */
if (check_len) {
if (ccw.count != sizeof(sense_id)) {
* have enough place to store at least bytes 0-3.
*/
if (len >= 4) {
- sense_id.reserved = 0xff;
+ sense_id[0] = 0xff;
} else {
- sense_id.reserved = 0;
+ sense_id[0] = 0;
}
- ccw_dstream_write_buf(&sch->cds, &sense_id, len);
+ ccw_dstream_write_buf(&sch->cds, sense_id, len);
sch->curr_status.scsw.count = ccw_dstream_residual_count(&sch->cds);
ret = 0;
break;
static void sch_handle_start_func_virtual(SubchDev *sch)
{
-
- PMCW *p = &sch->curr_status.pmcw;
- SCSW *s = &sch->curr_status.scsw;
+ SCHIB *schib = &sch->curr_status;
int path;
int ret;
bool suspend_allowed;
/* Path management: In our simple css, we always choose the only path. */
path = 0x80;
- if (!(s->ctrl & SCSW_ACTL_SUSP)) {
+ if (!(schib->scsw.ctrl & SCSW_ACTL_SUSP)) {
/* Start Function triggered via ssch, i.e. we have an ORB */
ORB *orb = &sch->orb;
- s->cstat = 0;
- s->dstat = 0;
+ schib->scsw.cstat = 0;
+ schib->scsw.dstat = 0;
/* Look at the orb and try to execute the channel program. */
- p->intparm = orb->intparm;
+ schib->pmcw.intparm = orb->intparm;
if (!(orb->lpm & path)) {
/* Generate a deferred cc 3 condition. */
- s->flags |= SCSW_FLAGS_MASK_CC;
- s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
- s->ctrl |= (SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND);
+ schib->scsw.flags |= SCSW_FLAGS_MASK_CC;
+ schib->scsw.ctrl &= ~SCSW_CTRL_MASK_STCTL;
+ schib->scsw.ctrl |= (SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND);
return;
}
sch->ccw_fmt_1 = !!(orb->ctrl0 & ORB_CTRL0_MASK_FMT);
- s->flags |= (sch->ccw_fmt_1) ? SCSW_FLAGS_MASK_FMT : 0;
+ schib->scsw.flags |= (sch->ccw_fmt_1) ? SCSW_FLAGS_MASK_FMT : 0;
sch->ccw_no_data_cnt = 0;
suspend_allowed = !!(orb->ctrl0 & ORB_CTRL0_MASK_SPND);
} else {
/* Start Function resumed via rsch */
- s->ctrl &= ~(SCSW_ACTL_SUSP | SCSW_ACTL_RESUME_PEND);
+ schib->scsw.ctrl &= ~(SCSW_ACTL_SUSP | SCSW_ACTL_RESUME_PEND);
/* The channel program had been suspended before. */
suspend_allowed = true;
}
break;
case 0:
/* success */
- s->ctrl &= ~SCSW_ACTL_START_PEND;
- s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
- s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY |
+ schib->scsw.ctrl &= ~SCSW_ACTL_START_PEND;
+ schib->scsw.ctrl &= ~SCSW_CTRL_MASK_STCTL;
+ schib->scsw.ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY |
SCSW_STCTL_STATUS_PEND;
- s->dstat = SCSW_DSTAT_CHANNEL_END | SCSW_DSTAT_DEVICE_END;
- s->cpa = sch->channel_prog + 8;
+ schib->scsw.dstat = SCSW_DSTAT_CHANNEL_END | SCSW_DSTAT_DEVICE_END;
+ schib->scsw.cpa = sch->channel_prog + 8;
break;
case -EIO:
/* I/O errors, status depends on specific devices */
break;
case -ENOSYS:
/* unsupported command, generate unit check (command reject) */
- s->ctrl &= ~SCSW_ACTL_START_PEND;
- s->dstat = SCSW_DSTAT_UNIT_CHECK;
+ schib->scsw.ctrl &= ~SCSW_ACTL_START_PEND;
+ schib->scsw.dstat = SCSW_DSTAT_UNIT_CHECK;
/* Set sense bit 0 in ecw0. */
sch->sense_data[0] = 0x80;
- s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
- s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY |
+ schib->scsw.ctrl &= ~SCSW_CTRL_MASK_STCTL;
+ schib->scsw.ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY |
SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND;
- s->cpa = sch->channel_prog + 8;
+ schib->scsw.cpa = sch->channel_prog + 8;
break;
case -EINPROGRESS:
/* channel program has been suspended */
- s->ctrl &= ~SCSW_ACTL_START_PEND;
- s->ctrl |= SCSW_ACTL_SUSP;
+ schib->scsw.ctrl &= ~SCSW_ACTL_START_PEND;
+ schib->scsw.ctrl |= SCSW_ACTL_SUSP;
break;
default:
/* error, generate channel program check */
- s->ctrl &= ~SCSW_ACTL_START_PEND;
- s->cstat = SCSW_CSTAT_PROG_CHECK;
- s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
- s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY |
+ schib->scsw.ctrl &= ~SCSW_ACTL_START_PEND;
+ schib->scsw.cstat = SCSW_CSTAT_PROG_CHECK;
+ schib->scsw.ctrl &= ~SCSW_CTRL_MASK_STCTL;
+ schib->scsw.ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY |
SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND;
- s->cpa = sch->channel_prog + 8;
+ schib->scsw.cpa = sch->channel_prog + 8;
break;
}
} while (ret == -EAGAIN);
}
-static int sch_handle_start_func_passthrough(SubchDev *sch)
+static void sch_handle_halt_func_passthrough(SubchDev *sch)
{
-
- PMCW *p = &sch->curr_status.pmcw;
- SCSW *s = &sch->curr_status.scsw;
int ret;
- ORB *orb = &sch->orb;
- if (!(s->ctrl & SCSW_ACTL_SUSP)) {
- assert(orb != NULL);
- p->intparm = orb->intparm;
+ ret = s390_ccw_halt(sch);
+ if (ret == -ENOSYS) {
+ sch_handle_halt_func(sch);
}
+}
- /*
- * Only support prefetch enable mode.
- * Only support 64bit addressing idal.
- */
- if (!(orb->ctrl0 & ORB_CTRL0_MASK_PFCH) ||
- !(orb->ctrl0 & ORB_CTRL0_MASK_C64)) {
- return -EINVAL;
- }
+static void sch_handle_clear_func_passthrough(SubchDev *sch)
+{
+ int ret;
- ret = s390_ccw_cmd_request(orb, s, sch->driver_data);
- switch (ret) {
- /* Currently we don't update control block and just return the cc code. */
- case 0:
- break;
- case -EBUSY:
- break;
- case -ENODEV:
- break;
- case -EACCES:
- /* Let's reflect an inaccessible host device by cc 3. */
- ret = -ENODEV;
- break;
- default:
- /*
- * All other return codes will trigger a program check,
- * or set cc to 1.
- */
- break;
- };
+ ret = s390_ccw_clear(sch);
+ if (ret == -ENOSYS) {
+ sch_handle_clear_func(sch);
+ }
+}
- return ret;
+static IOInstEnding sch_handle_start_func_passthrough(SubchDev *sch)
+{
+ SCHIB *schib = &sch->curr_status;
+ ORB *orb = &sch->orb;
+ if (!(schib->scsw.ctrl & SCSW_ACTL_SUSP)) {
+ assert(orb != NULL);
+ schib->pmcw.intparm = orb->intparm;
+ }
+ return s390_ccw_cmd_request(sch);
}
/*
* read/writes) asynchronous later on if we start supporting more than
* our current very simple devices.
*/
-int do_subchannel_work_virtual(SubchDev *sch)
+IOInstEnding do_subchannel_work_virtual(SubchDev *sch)
{
+ SCHIB *schib = &sch->curr_status;
- SCSW *s = &sch->curr_status.scsw;
-
- if (s->ctrl & SCSW_FCTL_CLEAR_FUNC) {
+ if (schib->scsw.ctrl & SCSW_FCTL_CLEAR_FUNC) {
sch_handle_clear_func(sch);
- } else if (s->ctrl & SCSW_FCTL_HALT_FUNC) {
+ } else if (schib->scsw.ctrl & SCSW_FCTL_HALT_FUNC) {
sch_handle_halt_func(sch);
- } else if (s->ctrl & SCSW_FCTL_START_FUNC) {
+ } else if (schib->scsw.ctrl & SCSW_FCTL_START_FUNC) {
/* Triggered by both ssch and rsch. */
sch_handle_start_func_virtual(sch);
- } else {
- /* Cannot happen. */
- return 0;
}
css_inject_io_interrupt(sch);
- return 0;
+ /* inst must succeed if this func is called */
+ return IOINST_CC_EXPECTED;
}
-int do_subchannel_work_passthrough(SubchDev *sch)
+IOInstEnding do_subchannel_work_passthrough(SubchDev *sch)
{
- int ret;
- SCSW *s = &sch->curr_status.scsw;
+ SCHIB *schib = &sch->curr_status;
- if (s->ctrl & SCSW_FCTL_CLEAR_FUNC) {
- /* TODO: Clear handling */
- sch_handle_clear_func(sch);
- ret = 0;
- } else if (s->ctrl & SCSW_FCTL_HALT_FUNC) {
- /* TODO: Halt handling */
- sch_handle_halt_func(sch);
- ret = 0;
- } else if (s->ctrl & SCSW_FCTL_START_FUNC) {
- ret = sch_handle_start_func_passthrough(sch);
- } else {
- /* Cannot happen. */
- return -ENODEV;
+ if (schib->scsw.ctrl & SCSW_FCTL_CLEAR_FUNC) {
+ sch_handle_clear_func_passthrough(sch);
+ } else if (schib->scsw.ctrl & SCSW_FCTL_HALT_FUNC) {
+ sch_handle_halt_func_passthrough(sch);
+ } else if (schib->scsw.ctrl & SCSW_FCTL_START_FUNC) {
+ return sch_handle_start_func_passthrough(sch);
}
-
- return ret;
+ return IOINST_CC_EXPECTED;
}
-static int do_subchannel_work(SubchDev *sch)
+static IOInstEnding do_subchannel_work(SubchDev *sch)
{
- if (sch->do_subchannel_work) {
- return sch->do_subchannel_work(sch);
- } else {
- return -EINVAL;
+ if (!sch->do_subchannel_work) {
+ return IOINST_CC_STATUS_PRESENT;
}
+ g_assert(sch->curr_status.scsw.ctrl & SCSW_CTRL_MASK_FCTL);
+ return sch->do_subchannel_work(sch);
}
static void copy_pmcw_to_guest(PMCW *dest, const PMCW *src)
static void copy_schib_to_guest(SCHIB *dest, const SCHIB *src)
{
int i;
-
- copy_pmcw_to_guest(&dest->pmcw, &src->pmcw);
- copy_scsw_to_guest(&dest->scsw, &src->scsw);
+ /*
+ * We copy the PMCW and SCSW in and out of local variables to
+ * avoid taking the address of members of a packed struct.
+ */
+ PMCW src_pmcw, dest_pmcw;
+ SCSW src_scsw, dest_scsw;
+
+ src_pmcw = src->pmcw;
+ copy_pmcw_to_guest(&dest_pmcw, &src_pmcw);
+ dest->pmcw = dest_pmcw;
+ src_scsw = src->scsw;
+ copy_scsw_to_guest(&dest_scsw, &src_scsw);
+ dest->scsw = dest_scsw;
dest->mba = cpu_to_be64(src->mba);
for (i = 0; i < ARRAY_SIZE(dest->mda); i++) {
dest->mda[i] = src->mda[i];
static void copy_schib_from_guest(SCHIB *dest, const SCHIB *src)
{
int i;
-
- copy_pmcw_from_guest(&dest->pmcw, &src->pmcw);
- copy_scsw_from_guest(&dest->scsw, &src->scsw);
+ /*
+ * We copy the PMCW and SCSW in and out of local variables to
+ * avoid taking the address of members of a packed struct.
+ */
+ PMCW src_pmcw, dest_pmcw;
+ SCSW src_scsw, dest_scsw;
+
+ src_pmcw = src->pmcw;
+ copy_pmcw_from_guest(&dest_pmcw, &src_pmcw);
+ dest->pmcw = dest_pmcw;
+ src_scsw = src->scsw;
+ copy_scsw_from_guest(&dest_scsw, &src_scsw);
+ dest->scsw = dest_scsw;
dest->mba = be64_to_cpu(src->mba);
for (i = 0; i < ARRAY_SIZE(dest->mda); i++) {
dest->mda[i] = src->mda[i];
}
}
-int css_do_msch(SubchDev *sch, const SCHIB *orig_schib)
+IOInstEnding css_do_msch(SubchDev *sch, const SCHIB *orig_schib)
{
- SCSW *s = &sch->curr_status.scsw;
- PMCW *p = &sch->curr_status.pmcw;
+ SCHIB *schib = &sch->curr_status;
uint16_t oldflags;
- int ret;
- SCHIB schib;
+ SCHIB schib_copy;
- if (!(sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_DNV)) {
- ret = 0;
- goto out;
+ if (!(schib->pmcw.flags & PMCW_FLAGS_MASK_DNV)) {
+ return IOINST_CC_EXPECTED;
}
- if (s->ctrl & SCSW_STCTL_STATUS_PEND) {
- ret = -EINPROGRESS;
- goto out;
+ if (schib->scsw.ctrl & SCSW_STCTL_STATUS_PEND) {
+ return IOINST_CC_STATUS_PRESENT;
}
- if (s->ctrl &
+ if (schib->scsw.ctrl &
(SCSW_FCTL_START_FUNC|SCSW_FCTL_HALT_FUNC|SCSW_FCTL_CLEAR_FUNC)) {
- ret = -EBUSY;
- goto out;
+ return IOINST_CC_BUSY;
}
- copy_schib_from_guest(&schib, orig_schib);
+ copy_schib_from_guest(&schib_copy, orig_schib);
/* Only update the program-modifiable fields. */
- p->intparm = schib.pmcw.intparm;
- oldflags = p->flags;
- p->flags &= ~(PMCW_FLAGS_MASK_ISC | PMCW_FLAGS_MASK_ENA |
+ schib->pmcw.intparm = schib_copy.pmcw.intparm;
+ oldflags = schib->pmcw.flags;
+ schib->pmcw.flags &= ~(PMCW_FLAGS_MASK_ISC | PMCW_FLAGS_MASK_ENA |
PMCW_FLAGS_MASK_LM | PMCW_FLAGS_MASK_MME |
PMCW_FLAGS_MASK_MP);
- p->flags |= schib.pmcw.flags &
+ schib->pmcw.flags |= schib_copy.pmcw.flags &
(PMCW_FLAGS_MASK_ISC | PMCW_FLAGS_MASK_ENA |
PMCW_FLAGS_MASK_LM | PMCW_FLAGS_MASK_MME |
PMCW_FLAGS_MASK_MP);
- p->lpm = schib.pmcw.lpm;
- p->mbi = schib.pmcw.mbi;
- p->pom = schib.pmcw.pom;
- p->chars &= ~(PMCW_CHARS_MASK_MBFC | PMCW_CHARS_MASK_CSENSE);
- p->chars |= schib.pmcw.chars &
+ schib->pmcw.lpm = schib_copy.pmcw.lpm;
+ schib->pmcw.mbi = schib_copy.pmcw.mbi;
+ schib->pmcw.pom = schib_copy.pmcw.pom;
+ schib->pmcw.chars &= ~(PMCW_CHARS_MASK_MBFC | PMCW_CHARS_MASK_CSENSE);
+ schib->pmcw.chars |= schib_copy.pmcw.chars &
(PMCW_CHARS_MASK_MBFC | PMCW_CHARS_MASK_CSENSE);
- sch->curr_status.mba = schib.mba;
+ schib->mba = schib_copy.mba;
/* Has the channel been disabled? */
if (sch->disable_cb && (oldflags & PMCW_FLAGS_MASK_ENA) != 0
- && (p->flags & PMCW_FLAGS_MASK_ENA) == 0) {
+ && (schib->pmcw.flags & PMCW_FLAGS_MASK_ENA) == 0) {
sch->disable_cb(sch);
}
-
- ret = 0;
-
-out:
- return ret;
+ return IOINST_CC_EXPECTED;
}
-int css_do_xsch(SubchDev *sch)
+IOInstEnding css_do_xsch(SubchDev *sch)
{
- SCSW *s = &sch->curr_status.scsw;
- PMCW *p = &sch->curr_status.pmcw;
- int ret;
+ SCHIB *schib = &sch->curr_status;
- if (~(p->flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) {
- ret = -ENODEV;
- goto out;
+ if (~(schib->pmcw.flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) {
+ return IOINST_CC_NOT_OPERATIONAL;
}
- if (s->ctrl & SCSW_CTRL_MASK_STCTL) {
- ret = -EINPROGRESS;
- goto out;
+ if (schib->scsw.ctrl & SCSW_CTRL_MASK_STCTL) {
+ return IOINST_CC_STATUS_PRESENT;
}
- if (!(s->ctrl & SCSW_CTRL_MASK_FCTL) ||
- ((s->ctrl & SCSW_CTRL_MASK_FCTL) != SCSW_FCTL_START_FUNC) ||
- (!(s->ctrl &
+ if (!(schib->scsw.ctrl & SCSW_CTRL_MASK_FCTL) ||
+ ((schib->scsw.ctrl & SCSW_CTRL_MASK_FCTL) != SCSW_FCTL_START_FUNC) ||
+ (!(schib->scsw.ctrl &
(SCSW_ACTL_RESUME_PEND | SCSW_ACTL_START_PEND | SCSW_ACTL_SUSP))) ||
- (s->ctrl & SCSW_ACTL_SUBCH_ACTIVE)) {
- ret = -EBUSY;
- goto out;
+ (schib->scsw.ctrl & SCSW_ACTL_SUBCH_ACTIVE)) {
+ return IOINST_CC_BUSY;
}
/* Cancel the current operation. */
- s->ctrl &= ~(SCSW_FCTL_START_FUNC |
+ schib->scsw.ctrl &= ~(SCSW_FCTL_START_FUNC |
SCSW_ACTL_RESUME_PEND |
SCSW_ACTL_START_PEND |
SCSW_ACTL_SUSP);
sch->channel_prog = 0x0;
sch->last_cmd_valid = false;
- s->dstat = 0;
- s->cstat = 0;
- ret = 0;
-
-out:
- return ret;
+ schib->scsw.dstat = 0;
+ schib->scsw.cstat = 0;
+ return IOINST_CC_EXPECTED;
}
-int css_do_csch(SubchDev *sch)
+IOInstEnding css_do_csch(SubchDev *sch)
{
- SCSW *s = &sch->curr_status.scsw;
- PMCW *p = &sch->curr_status.pmcw;
- int ret;
+ SCHIB *schib = &sch->curr_status;
- if (~(p->flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) {
- ret = -ENODEV;
- goto out;
+ if (~(schib->pmcw.flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) {
+ return IOINST_CC_NOT_OPERATIONAL;
}
/* Trigger the clear function. */
- s->ctrl &= ~(SCSW_CTRL_MASK_FCTL | SCSW_CTRL_MASK_ACTL);
- s->ctrl |= SCSW_FCTL_CLEAR_FUNC | SCSW_ACTL_CLEAR_PEND;
-
- do_subchannel_work(sch);
- ret = 0;
+ schib->scsw.ctrl &= ~(SCSW_CTRL_MASK_FCTL | SCSW_CTRL_MASK_ACTL);
+ schib->scsw.ctrl |= SCSW_FCTL_CLEAR_FUNC | SCSW_ACTL_CLEAR_PEND;
-out:
- return ret;
+ return do_subchannel_work(sch);
}
-int css_do_hsch(SubchDev *sch)
+IOInstEnding css_do_hsch(SubchDev *sch)
{
- SCSW *s = &sch->curr_status.scsw;
- PMCW *p = &sch->curr_status.pmcw;
- int ret;
+ SCHIB *schib = &sch->curr_status;
- if (~(p->flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) {
- ret = -ENODEV;
- goto out;
+ if (~(schib->pmcw.flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) {
+ return IOINST_CC_NOT_OPERATIONAL;
}
- if (((s->ctrl & SCSW_CTRL_MASK_STCTL) == SCSW_STCTL_STATUS_PEND) ||
- (s->ctrl & (SCSW_STCTL_PRIMARY |
+ if (((schib->scsw.ctrl & SCSW_CTRL_MASK_STCTL) == SCSW_STCTL_STATUS_PEND) ||
+ (schib->scsw.ctrl & (SCSW_STCTL_PRIMARY |
SCSW_STCTL_SECONDARY |
SCSW_STCTL_ALERT))) {
- ret = -EINPROGRESS;
- goto out;
+ return IOINST_CC_STATUS_PRESENT;
}
- if (s->ctrl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) {
- ret = -EBUSY;
- goto out;
+ if (schib->scsw.ctrl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) {
+ return IOINST_CC_BUSY;
}
/* Trigger the halt function. */
- s->ctrl |= SCSW_FCTL_HALT_FUNC;
- s->ctrl &= ~SCSW_FCTL_START_FUNC;
- if (((s->ctrl & SCSW_CTRL_MASK_ACTL) ==
+ schib->scsw.ctrl |= SCSW_FCTL_HALT_FUNC;
+ schib->scsw.ctrl &= ~SCSW_FCTL_START_FUNC;
+ if (((schib->scsw.ctrl & SCSW_CTRL_MASK_ACTL) ==
(SCSW_ACTL_SUBCH_ACTIVE | SCSW_ACTL_DEVICE_ACTIVE)) &&
- ((s->ctrl & SCSW_CTRL_MASK_STCTL) == SCSW_STCTL_INTERMEDIATE)) {
- s->ctrl &= ~SCSW_STCTL_STATUS_PEND;
+ ((schib->scsw.ctrl & SCSW_CTRL_MASK_STCTL) ==
+ SCSW_STCTL_INTERMEDIATE)) {
+ schib->scsw.ctrl &= ~SCSW_STCTL_STATUS_PEND;
}
- s->ctrl |= SCSW_ACTL_HALT_PEND;
-
- do_subchannel_work(sch);
- ret = 0;
+ schib->scsw.ctrl |= SCSW_ACTL_HALT_PEND;
-out:
- return ret;
+ return do_subchannel_work(sch);
}
static void css_update_chnmon(SubchDev *sch)
}
}
-int css_do_ssch(SubchDev *sch, ORB *orb)
+IOInstEnding css_do_ssch(SubchDev *sch, ORB *orb)
{
- SCSW *s = &sch->curr_status.scsw;
- PMCW *p = &sch->curr_status.pmcw;
- int ret;
+ SCHIB *schib = &sch->curr_status;
- if (~(p->flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) {
- ret = -ENODEV;
- goto out;
+ if (~(schib->pmcw.flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) {
+ return IOINST_CC_NOT_OPERATIONAL;
}
- if (s->ctrl & SCSW_STCTL_STATUS_PEND) {
- ret = -EINPROGRESS;
- goto out;
+ if (schib->scsw.ctrl & SCSW_STCTL_STATUS_PEND) {
+ return IOINST_CC_STATUS_PRESENT;
}
- if (s->ctrl & (SCSW_FCTL_START_FUNC |
+ if (schib->scsw.ctrl & (SCSW_FCTL_START_FUNC |
SCSW_FCTL_HALT_FUNC |
SCSW_FCTL_CLEAR_FUNC)) {
- ret = -EBUSY;
- goto out;
+ return IOINST_CC_BUSY;
}
/* If monitoring is active, update counter. */
sch->orb = *orb;
sch->channel_prog = orb->cpa;
/* Trigger the start function. */
- s->ctrl |= (SCSW_FCTL_START_FUNC | SCSW_ACTL_START_PEND);
- s->flags &= ~SCSW_FLAGS_MASK_PNO;
-
- ret = do_subchannel_work(sch);
+ schib->scsw.ctrl |= (SCSW_FCTL_START_FUNC | SCSW_ACTL_START_PEND);
+ schib->scsw.flags &= ~SCSW_FLAGS_MASK_PNO;
-out:
- return ret;
+ return do_subchannel_work(sch);
}
-static void copy_irb_to_guest(IRB *dest, const IRB *src, PMCW *pmcw,
+static void copy_irb_to_guest(IRB *dest, const IRB *src, const PMCW *pmcw,
int *irb_len)
{
int i;
int css_do_tsch_get_irb(SubchDev *sch, IRB *target_irb, int *irb_len)
{
- SCSW *s = &sch->curr_status.scsw;
- PMCW *p = &sch->curr_status.pmcw;
+ SCHIB *schib = &sch->curr_status;
+ PMCW p;
uint16_t stctl;
IRB irb;
- if (~(p->flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) {
+ if (~(schib->pmcw.flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) {
return 3;
}
- stctl = s->ctrl & SCSW_CTRL_MASK_STCTL;
+ stctl = schib->scsw.ctrl & SCSW_CTRL_MASK_STCTL;
/* Prepare the irb for the guest. */
memset(&irb, 0, sizeof(IRB));
/* Copy scsw from current status. */
- memcpy(&irb.scsw, s, sizeof(SCSW));
+ irb.scsw = schib->scsw;
if (stctl & SCSW_STCTL_STATUS_PEND) {
- if (s->cstat & (SCSW_CSTAT_DATA_CHECK |
+ if (schib->scsw.cstat & (SCSW_CSTAT_DATA_CHECK |
SCSW_CSTAT_CHN_CTRL_CHK |
SCSW_CSTAT_INTF_CTRL_CHK)) {
irb.scsw.flags |= SCSW_FLAGS_MASK_ESWF;
irb.esw[0] = 0x00800000;
}
/* If a unit check is pending, copy sense data. */
- if ((s->dstat & SCSW_DSTAT_UNIT_CHECK) &&
- (p->chars & PMCW_CHARS_MASK_CSENSE)) {
+ if ((schib->scsw.dstat & SCSW_DSTAT_UNIT_CHECK) &&
+ (schib->pmcw.chars & PMCW_CHARS_MASK_CSENSE)) {
int i;
irb.scsw.flags |= SCSW_FLAGS_MASK_ESWF | SCSW_FLAGS_MASK_ECTL;
}
}
/* Store the irb to the guest. */
- copy_irb_to_guest(target_irb, &irb, p, irb_len);
+ p = schib->pmcw;
+ copy_irb_to_guest(target_irb, &irb, &p, irb_len);
return ((stctl & SCSW_STCTL_STATUS_PEND) == 0);
}
void css_do_tsch_update_subch(SubchDev *sch)
{
- SCSW *s = &sch->curr_status.scsw;
- PMCW *p = &sch->curr_status.pmcw;
+ SCHIB *schib = &sch->curr_status;
uint16_t stctl;
uint16_t fctl;
uint16_t actl;
- stctl = s->ctrl & SCSW_CTRL_MASK_STCTL;
- fctl = s->ctrl & SCSW_CTRL_MASK_FCTL;
- actl = s->ctrl & SCSW_CTRL_MASK_ACTL;
+ stctl = schib->scsw.ctrl & SCSW_CTRL_MASK_STCTL;
+ fctl = schib->scsw.ctrl & SCSW_CTRL_MASK_FCTL;
+ actl = schib->scsw.ctrl & SCSW_CTRL_MASK_ACTL;
/* Clear conditions on subchannel, if applicable. */
if (stctl & SCSW_STCTL_STATUS_PEND) {
- s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
+ schib->scsw.ctrl &= ~SCSW_CTRL_MASK_STCTL;
if ((stctl != (SCSW_STCTL_INTERMEDIATE | SCSW_STCTL_STATUS_PEND)) ||
((fctl & SCSW_FCTL_HALT_FUNC) &&
(actl & SCSW_ACTL_SUSP))) {
- s->ctrl &= ~SCSW_CTRL_MASK_FCTL;
+ schib->scsw.ctrl &= ~SCSW_CTRL_MASK_FCTL;
}
if (stctl != (SCSW_STCTL_INTERMEDIATE | SCSW_STCTL_STATUS_PEND)) {
- s->flags &= ~SCSW_FLAGS_MASK_PNO;
- s->ctrl &= ~(SCSW_ACTL_RESUME_PEND |
+ schib->scsw.flags &= ~SCSW_FLAGS_MASK_PNO;
+ schib->scsw.ctrl &= ~(SCSW_ACTL_RESUME_PEND |
SCSW_ACTL_START_PEND |
SCSW_ACTL_HALT_PEND |
SCSW_ACTL_CLEAR_PEND |
} else {
if ((actl & SCSW_ACTL_SUSP) &&
(fctl & SCSW_FCTL_START_FUNC)) {
- s->flags &= ~SCSW_FLAGS_MASK_PNO;
+ schib->scsw.flags &= ~SCSW_FLAGS_MASK_PNO;
if (fctl & SCSW_FCTL_HALT_FUNC) {
- s->ctrl &= ~(SCSW_ACTL_RESUME_PEND |
+ schib->scsw.ctrl &= ~(SCSW_ACTL_RESUME_PEND |
SCSW_ACTL_START_PEND |
SCSW_ACTL_HALT_PEND |
SCSW_ACTL_CLEAR_PEND |
SCSW_ACTL_SUSP);
} else {
- s->ctrl &= ~SCSW_ACTL_RESUME_PEND;
+ schib->scsw.ctrl &= ~SCSW_ACTL_RESUME_PEND;
}
}
}
/* Clear pending sense data. */
- if (p->chars & PMCW_CHARS_MASK_CSENSE) {
+ if (schib->pmcw.chars & PMCW_CHARS_MASK_CSENSE) {
memset(sch->sense_data, 0 , sizeof(sch->sense_data));
}
}
{
CrwContainer *crw_cont;
- crw_cont = g_try_malloc0(sizeof(CrwContainer));
+ crw_cont = g_try_new0(CrwContainer, 1);
if (!crw_cont) {
channel_subsys.crws_lost = true;
return;
QTAILQ_INSERT_HEAD(&channel_subsys.pending_crws, crw_cont, sibling);
}
-int css_do_tpi(IOIntCode *int_code, int lowcore)
-{
- /* No pending interrupts for !KVM. */
- return 0;
- }
-
int css_collect_chp_desc(int m, uint8_t cssid, uint8_t f_chpid, uint8_t l_chpid,
int rfmt, void *buf)
{
}
}
-int css_do_rsch(SubchDev *sch)
+IOInstEnding css_do_rsch(SubchDev *sch)
{
- SCSW *s = &sch->curr_status.scsw;
- PMCW *p = &sch->curr_status.pmcw;
- int ret;
+ SCHIB *schib = &sch->curr_status;
- if (~(p->flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) {
- ret = -ENODEV;
- goto out;
+ if (~(schib->pmcw.flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) {
+ return IOINST_CC_NOT_OPERATIONAL;
}
- if (s->ctrl & SCSW_STCTL_STATUS_PEND) {
- ret = -EINPROGRESS;
- goto out;
+ if (schib->scsw.ctrl & SCSW_STCTL_STATUS_PEND) {
+ return IOINST_CC_STATUS_PRESENT;
}
- if (((s->ctrl & SCSW_CTRL_MASK_FCTL) != SCSW_FCTL_START_FUNC) ||
- (s->ctrl & SCSW_ACTL_RESUME_PEND) ||
- (!(s->ctrl & SCSW_ACTL_SUSP))) {
- ret = -EINVAL;
- goto out;
+ if (((schib->scsw.ctrl & SCSW_CTRL_MASK_FCTL) != SCSW_FCTL_START_FUNC) ||
+ (schib->scsw.ctrl & SCSW_ACTL_RESUME_PEND) ||
+ (!(schib->scsw.ctrl & SCSW_ACTL_SUSP))) {
+ return IOINST_CC_BUSY;
}
/* If monitoring is active, update counter. */
css_update_chnmon(sch);
}
- s->ctrl |= SCSW_ACTL_RESUME_PEND;
- do_subchannel_work(sch);
- ret = 0;
-
-out:
- return ret;
+ schib->scsw.ctrl |= SCSW_ACTL_RESUME_PEND;
+ return do_subchannel_work(sch);
}
int css_do_rchp(uint8_t cssid, uint8_t chpid)
void css_sch_build_virtual_schib(SubchDev *sch, uint8_t chpid, uint8_t type)
{
- PMCW *p = &sch->curr_status.pmcw;
- SCSW *s = &sch->curr_status.scsw;
+ SCHIB *schib = &sch->curr_status;
int i;
CssImage *css = channel_subsys.css[sch->cssid];
assert(css != NULL);
- memset(p, 0, sizeof(PMCW));
- p->flags |= PMCW_FLAGS_MASK_DNV;
- p->devno = sch->devno;
+ memset(&schib->pmcw, 0, sizeof(PMCW));
+ schib->pmcw.flags |= PMCW_FLAGS_MASK_DNV;
+ schib->pmcw.devno = sch->devno;
/* single path */
- p->pim = 0x80;
- p->pom = 0xff;
- p->pam = 0x80;
- p->chpid[0] = chpid;
+ schib->pmcw.pim = 0x80;
+ schib->pmcw.pom = 0xff;
+ schib->pmcw.pam = 0x80;
+ schib->pmcw.chpid[0] = chpid;
if (!css->chpids[chpid].in_use) {
css_add_chpid(sch->cssid, chpid, type, true);
}
- memset(s, 0, sizeof(SCSW));
- sch->curr_status.mba = 0;
- for (i = 0; i < ARRAY_SIZE(sch->curr_status.mda); i++) {
- sch->curr_status.mda[i] = 0;
+ memset(&schib->scsw, 0, sizeof(SCSW));
+ schib->mba = 0;
+ for (i = 0; i < ARRAY_SIZE(schib->mda); i++) {
+ schib->mda[i] = 0;
}
}
css = channel_subsys.css[cssid];
if (!css->sch_set[ssid]) {
- css->sch_set[ssid] = g_malloc0(sizeof(SubchSet));
+ css->sch_set[ssid] = g_new0(SubchSet, 1);
}
s_set = css->sch_set[ssid];
trace_css_crw(rsc, erc, rsid, chain ? "(chained)" : "");
/* TODO: Maybe use a static crw pool? */
- crw_cont = g_try_malloc0(sizeof(CrwContainer));
+ crw_cont = g_try_new0(CrwContainer, 1);
if (!crw_cont) {
channel_subsys.crws_lost = true;
return;
void css_reset_sch(SubchDev *sch)
{
- PMCW *p = &sch->curr_status.pmcw;
+ SCHIB *schib = &sch->curr_status;
- if ((p->flags & PMCW_FLAGS_MASK_ENA) != 0 && sch->disable_cb) {
+ if ((schib->pmcw.flags & PMCW_FLAGS_MASK_ENA) != 0 && sch->disable_cb) {
sch->disable_cb(sch);
}
- p->intparm = 0;
- p->flags &= ~(PMCW_FLAGS_MASK_ISC | PMCW_FLAGS_MASK_ENA |
+ schib->pmcw.intparm = 0;
+ schib->pmcw.flags &= ~(PMCW_FLAGS_MASK_ISC | PMCW_FLAGS_MASK_ENA |
PMCW_FLAGS_MASK_LM | PMCW_FLAGS_MASK_MME |
PMCW_FLAGS_MASK_MP | PMCW_FLAGS_MASK_TF);
- p->flags |= PMCW_FLAGS_MASK_DNV;
- p->devno = sch->devno;
- p->pim = 0x80;
- p->lpm = p->pim;
- p->pnom = 0;
- p->lpum = 0;
- p->mbi = 0;
- p->pom = 0xff;
- p->pam = 0x80;
- p->chars &= ~(PMCW_CHARS_MASK_MBFC | PMCW_CHARS_MASK_XMWME |
+ schib->pmcw.flags |= PMCW_FLAGS_MASK_DNV;
+ schib->pmcw.devno = sch->devno;
+ schib->pmcw.pim = 0x80;
+ schib->pmcw.lpm = schib->pmcw.pim;
+ schib->pmcw.pnom = 0;
+ schib->pmcw.lpum = 0;
+ schib->pmcw.mbi = 0;
+ schib->pmcw.pom = 0xff;
+ schib->pmcw.pam = 0x80;
+ schib->pmcw.chars &= ~(PMCW_CHARS_MASK_MBFC | PMCW_CHARS_MASK_XMWME |
PMCW_CHARS_MASK_CSENSE);
- memset(&sch->curr_status.scsw, 0, sizeof(sch->curr_status.scsw));
- sch->curr_status.mba = 0;
+ memset(&schib->scsw, 0, sizeof(schib->scsw));
+ schib->mba = 0;
sch->channel_prog = 0x0;
sch->last_cmd_valid = false;
.get = get_css_devid,
};
-SubchDev *css_create_sch(CssDevId bus_id, bool is_virtual, bool squash_mcss,
- Error **errp)
+SubchDev *css_create_sch(CssDevId bus_id, Error **errp)
{
uint16_t schid = 0;
SubchDev *sch;
if (bus_id.valid) {
- if (is_virtual != (bus_id.cssid == VIRTUAL_CSSID)) {
- error_setg(errp, "cssid %hhx not valid for %s devices",
- bus_id.cssid,
- (is_virtual ? "virtual" : "non-virtual"));
- return NULL;
- }
- }
-
- if (bus_id.valid) {
- if (squash_mcss) {
- bus_id.cssid = channel_subsys.default_cssid;
- } else if (!channel_subsys.css[bus_id.cssid]) {
+ if (!channel_subsys.css[bus_id.cssid]) {
css_create_css_image(bus_id.cssid, false);
}
bus_id.devid, &schid, errp)) {
return NULL;
}
- } else if (squash_mcss || is_virtual) {
- bus_id.cssid = channel_subsys.default_cssid;
-
- if (!css_find_free_subch_and_devno(bus_id.cssid, &bus_id.ssid,
- &bus_id.devid, &schid, errp)) {
- return NULL;
- }
} else {
- for (bus_id.cssid = 0; bus_id.cssid < MAX_CSSID; ++bus_id.cssid) {
- if (bus_id.cssid == VIRTUAL_CSSID) {
- continue;
- }
-
+ for (bus_id.cssid = channel_subsys.default_cssid;;) {
if (!channel_subsys.css[bus_id.cssid]) {
css_create_css_image(bus_id.cssid, false);
}
NULL)) {
break;
}
- if (bus_id.cssid == MAX_CSSID) {
+ bus_id.cssid = (bus_id.cssid + 1) % MAX_CSSID;
+ if (bus_id.cssid == channel_subsys.default_cssid) {
error_setg(errp, "Virtual channel subsystem is full!");
return NULL;
}
}
}
- sch = g_malloc0(sizeof(*sch));
+ sch = g_new0(SubchDev, 1);
sch->cssid = bus_id.cssid;
sch->ssid = bus_id.ssid;
sch->devno = bus_id.devid;
FILE *fd;
uint32_t chpid[8];
int i;
- PMCW *p = &sch->curr_status.pmcw;
+ SCHIB *schib = &sch->curr_status;
fid_path = g_strdup_printf("/sys/bus/css/devices/%x.%x.%04x/chpids",
dev_id->cssid, dev_id->ssid, dev_id->devid);
return -EINVAL;
}
- for (i = 0; i < ARRAY_SIZE(p->chpid); i++) {
- p->chpid[i] = chpid[i];
+ for (i = 0; i < ARRAY_SIZE(schib->pmcw.chpid); i++) {
+ schib->pmcw.chpid[i] = chpid[i];
}
fclose(fd);
char *fid_path;
FILE *fd;
uint32_t pim, pam, pom;
- PMCW *p = &sch->curr_status.pmcw;
+ SCHIB *schib = &sch->curr_status;
fid_path = g_strdup_printf("/sys/bus/css/devices/%x.%x.%04x/pimpampom",
dev_id->cssid, dev_id->ssid, dev_id->devid);
return -EINVAL;
}
- p->pim = pim;
- p->pam = pam;
- p->pom = pom;
+ schib->pmcw.pim = pim;
+ schib->pmcw.pam = pam;
+ schib->pmcw.pom = pom;
fclose(fd);
g_free(fid_path);
int css_sch_build_schib(SubchDev *sch, CssDevId *dev_id)
{
CssImage *css = channel_subsys.css[sch->cssid];
- PMCW *p = &sch->curr_status.pmcw;
- SCSW *s = &sch->curr_status.scsw;
+ SCHIB *schib = &sch->curr_status;
uint32_t type;
int i, ret;
assert(css != NULL);
- memset(p, 0, sizeof(PMCW));
- p->flags |= PMCW_FLAGS_MASK_DNV;
+ memset(&schib->pmcw, 0, sizeof(PMCW));
+ schib->pmcw.flags |= PMCW_FLAGS_MASK_DNV;
/* We are dealing with I/O subchannels only. */
- p->devno = sch->devno;
+ schib->pmcw.devno = sch->devno;
/* Grab path mask from sysfs. */
ret = css_sch_get_path_masks(sch, dev_id);
}
/* Build chpid type. */
- for (i = 0; i < ARRAY_SIZE(p->chpid); i++) {
- if (p->chpid[i] && !css->chpids[p->chpid[i]].in_use) {
- ret = css_sch_get_chpid_type(p->chpid[i], &type, dev_id);
+ for (i = 0; i < ARRAY_SIZE(schib->pmcw.chpid); i++) {
+ if (schib->pmcw.chpid[i] && !css->chpids[schib->pmcw.chpid[i]].in_use) {
+ ret = css_sch_get_chpid_type(schib->pmcw.chpid[i], &type, dev_id);
if (ret) {
return ret;
}
- css_add_chpid(sch->cssid, p->chpid[i], type, false);
+ css_add_chpid(sch->cssid, schib->pmcw.chpid[i], type, false);
}
}
- memset(s, 0, sizeof(SCSW));
- sch->curr_status.mba = 0;
- for (i = 0; i < ARRAY_SIZE(sch->curr_status.mda); i++) {
- sch->curr_status.mda[i] = 0;
+ memset(&schib->scsw, 0, sizeof(SCSW));
+ schib->mba = 0;
+ for (i = 0; i < ARRAY_SIZE(schib->mda); i++) {
+ schib->mda[i] = 0;
}
return 0;