}
}
-int css_do_msch(SubchDev *sch, SCHIB *orig_schib)
+int css_do_msch(SubchDev *sch, const SCHIB *orig_schib)
{
SCSW *s = &sch->curr_status.scsw;
PMCW *p = &sch->curr_status.pmcw;
+ uint16_t oldflags;
int ret;
SCHIB schib;
copy_schib_from_guest(&schib, 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 |
PMCW_FLAGS_MASK_LM | PMCW_FLAGS_MASK_MME |
PMCW_FLAGS_MASK_MP);
(PMCW_CHARS_MASK_MBFC | PMCW_CHARS_MASK_CSENSE);
sch->curr_status.mba = schib.mba;
+ /* Has the channel been disabled? */
+ if (sch->disable_cb && (oldflags & PMCW_FLAGS_MASK_ENA) != 0
+ && (p->flags & PMCW_FLAGS_MASK_ENA) == 0) {
+ sch->disable_cb(sch);
+ }
+
ret = 0;
out:
/* Format 1, per-subchannel area. */
uint32_t count;
- count = ldl_phys(&address_space_memory, sch->curr_status.mba);
+ count = address_space_ldl(&address_space_memory,
+ sch->curr_status.mba,
+ MEMTXATTRS_UNSPECIFIED,
+ NULL);
count++;
- stl_phys(&address_space_memory, sch->curr_status.mba, count);
+ address_space_stl(&address_space_memory, sch->curr_status.mba, count,
+ MEMTXATTRS_UNSPECIFIED, NULL);
} else {
/* Format 0, global area. */
uint32_t offset;
uint16_t count;
offset = sch->curr_status.pmcw.mbi << 5;
- count = lduw_phys(&address_space_memory,
- channel_subsys->chnmon_area + offset);
+ count = address_space_lduw(&address_space_memory,
+ channel_subsys->chnmon_area + offset,
+ MEMTXATTRS_UNSPECIFIED,
+ NULL);
count++;
- stw_phys(&address_space_memory,
- channel_subsys->chnmon_area + offset, count);
+ address_space_stw(&address_space_memory,
+ channel_subsys->chnmon_area + offset, count,
+ MEMTXATTRS_UNSPECIFIED, NULL);
}
}
return ret;
}
-static void copy_irb_to_guest(IRB *dest, const IRB *src, PMCW *pmcw)
+static void copy_irb_to_guest(IRB *dest, const IRB *src, PMCW *pmcw,
+ int *irb_len)
{
int i;
uint16_t stctl = src->scsw.ctrl & SCSW_CTRL_MASK_STCTL;
for (i = 0; i < ARRAY_SIZE(dest->ecw); i++) {
dest->ecw[i] = cpu_to_be32(src->ecw[i]);
}
+ *irb_len = sizeof(*dest) - sizeof(dest->emw);
+
/* extended measurements enabled? */
if ((src->scsw.flags & SCSW_FLAGS_MASK_ESWF) ||
!(pmcw->flags & PMCW_FLAGS_MASK_TF) ||
dest->emw[i] = cpu_to_be32(src->emw[i]);
}
}
+ *irb_len = sizeof(*dest);
}
-int css_do_tsch(SubchDev *sch, IRB *target_irb)
+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;
uint16_t stctl;
- uint16_t fctl;
- uint16_t actl;
IRB irb;
- int ret;
if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) {
- ret = 3;
- goto out;
+ return 3;
}
stctl = s->ctrl & SCSW_CTRL_MASK_STCTL;
- fctl = s->ctrl & SCSW_CTRL_MASK_FCTL;
- actl = s->ctrl & SCSW_CTRL_MASK_ACTL;
/* Prepare the irb for the guest. */
memset(&irb, 0, sizeof(IRB));
}
}
/* Store the irb to the guest. */
- copy_irb_to_guest(target_irb, &irb, p);
+ 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;
+ 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;
/* Clear conditions on subchannel, if applicable. */
if (stctl & SCSW_STCTL_STATUS_PEND) {
memset(sch->sense_data, 0 , sizeof(sch->sense_data));
}
}
-
- ret = ((stctl & SCSW_STCTL_STATUS_PEND) == 0);
-
-out:
- return ret;
}
static void copy_crw_to_guest(CRW *dest, const CRW *src)
return ret;
}
+static void copy_crw_from_guest(CRW *dest, const CRW *src)
+{
+ dest->flags = be16_to_cpu(src->flags);
+ dest->rsid = be16_to_cpu(src->rsid);
+}
+
+void css_undo_stcrw(CRW *crw)
+{
+ CrwContainer *crw_cont;
+
+ crw_cont = g_try_malloc0(sizeof(CrwContainer));
+ if (!crw_cont) {
+ channel_subsys->crws_lost = true;
+ return;
+ }
+ copy_crw_from_guest(&crw_cont->crw, crw);
+
+ QTAILQ_INSERT_HEAD(&channel_subsys->pending_crws, crw_cont, sibling);
+}
+
int css_do_tpi(IOIntCode *int_code, int lowcore)
{
/* No pending interrupts for !KVM. */
}
s->ccw_fmt_1 = qemu_get_byte(f);
s->ccw_no_data_cnt = qemu_get_byte(f);
+ /*
+ * Hack alert. We don't migrate the channel subsystem status (no
+ * device!), but we need to find out if the guest enabled mss/mcss-e.
+ * If the subchannel is enabled, it certainly was able to access it,
+ * so adjust the max_ssid/max_cssid values for relevant ssid/cssid
+ * values. This is not watertight, but better than nothing.
+ */
+ if (s->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ENA) {
+ if (s->ssid) {
+ channel_subsys->max_ssid = MAX_SSID;
+ }
+ if (s->cssid != channel_subsys->default_cssid) {
+ channel_subsys->max_cssid = MAX_CSSID;
+ }
+ }
return 0;
}
{
PMCW *p = &sch->curr_status.pmcw;
+ if ((p->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 |
PMCW_FLAGS_MASK_LM | PMCW_FLAGS_MASK_MME |