1 /* 2 * Channel subsystem base support. 3 * 4 * Copyright 2012 IBM Corp. 5 * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> 6 * 7 * This work is licensed under the terms of the GNU GPL, version 2 or (at 8 * your option) any later version. See the COPYING file in the top-level 9 * directory. 10 */ 11 12 #include <hw/qdev.h> 13 #include "qemu/bitops.h" 14 #include "exec/address-spaces.h" 15 #include "cpu.h" 16 #include "ioinst.h" 17 #include "css.h" 18 #include "trace.h" 19 20 typedef struct CrwContainer { 21 CRW crw; 22 QTAILQ_ENTRY(CrwContainer) sibling; 23 } CrwContainer; 24 25 typedef struct ChpInfo { 26 uint8_t in_use; 27 uint8_t type; 28 uint8_t is_virtual; 29 } ChpInfo; 30 31 typedef struct SubchSet { 32 SubchDev *sch[MAX_SCHID + 1]; 33 unsigned long schids_used[BITS_TO_LONGS(MAX_SCHID + 1)]; 34 unsigned long devnos_used[BITS_TO_LONGS(MAX_SCHID + 1)]; 35 } SubchSet; 36 37 typedef struct CssImage { 38 SubchSet *sch_set[MAX_SSID + 1]; 39 ChpInfo chpids[MAX_CHPID + 1]; 40 } CssImage; 41 42 typedef struct ChannelSubSys { 43 QTAILQ_HEAD(, CrwContainer) pending_crws; 44 bool do_crw_mchk; 45 bool crws_lost; 46 uint8_t max_cssid; 47 uint8_t max_ssid; 48 bool chnmon_active; 49 uint64_t chnmon_area; 50 CssImage *css[MAX_CSSID + 1]; 51 uint8_t default_cssid; 52 } ChannelSubSys; 53 54 static ChannelSubSys *channel_subsys; 55 56 int css_create_css_image(uint8_t cssid, bool default_image) 57 { 58 trace_css_new_image(cssid, default_image ? "(default)" : ""); 59 if (cssid > MAX_CSSID) { 60 return -EINVAL; 61 } 62 if (channel_subsys->css[cssid]) { 63 return -EBUSY; 64 } 65 channel_subsys->css[cssid] = g_malloc0(sizeof(CssImage)); 66 if (default_image) { 67 channel_subsys->default_cssid = cssid; 68 } 69 return 0; 70 } 71 72 uint16_t css_build_subchannel_id(SubchDev *sch) 73 { 74 if (channel_subsys->max_cssid > 0) { 75 return (sch->cssid << 8) | (1 << 3) | (sch->ssid << 1) | 1; 76 } 77 return (sch->ssid << 1) | 1; 78 } 79 80 static void css_inject_io_interrupt(SubchDev *sch) 81 { 82 S390CPU *cpu = s390_cpu_addr2state(0); 83 uint8_t isc = (sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ISC) >> 11; 84 85 trace_css_io_interrupt(sch->cssid, sch->ssid, sch->schid, 86 sch->curr_status.pmcw.intparm, isc, ""); 87 s390_io_interrupt(cpu, 88 css_build_subchannel_id(sch), 89 sch->schid, 90 sch->curr_status.pmcw.intparm, 91 isc << 27); 92 } 93 94 void css_conditional_io_interrupt(SubchDev *sch) 95 { 96 /* 97 * If the subchannel is not currently status pending, make it pending 98 * with alert status. 99 */ 100 if (!(sch->curr_status.scsw.ctrl & SCSW_STCTL_STATUS_PEND)) { 101 S390CPU *cpu = s390_cpu_addr2state(0); 102 uint8_t isc = (sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ISC) >> 11; 103 104 trace_css_io_interrupt(sch->cssid, sch->ssid, sch->schid, 105 sch->curr_status.pmcw.intparm, isc, 106 "(unsolicited)"); 107 sch->curr_status.scsw.ctrl &= ~SCSW_CTRL_MASK_STCTL; 108 sch->curr_status.scsw.ctrl |= 109 SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND; 110 /* Inject an I/O interrupt. */ 111 s390_io_interrupt(cpu, 112 css_build_subchannel_id(sch), 113 sch->schid, 114 sch->curr_status.pmcw.intparm, 115 isc << 27); 116 } 117 } 118 119 void css_adapter_interrupt(uint8_t isc) 120 { 121 S390CPU *cpu = s390_cpu_addr2state(0); 122 uint32_t io_int_word = (isc << 27) | IO_INT_WORD_AI; 123 124 trace_css_adapter_interrupt(isc); 125 s390_io_interrupt(cpu, 0, 0, 0, io_int_word); 126 } 127 128 static void sch_handle_clear_func(SubchDev *sch) 129 { 130 PMCW *p = &sch->curr_status.pmcw; 131 SCSW *s = &sch->curr_status.scsw; 132 int path; 133 134 /* Path management: In our simple css, we always choose the only path. */ 135 path = 0x80; 136 137 /* Reset values prior to 'issuing the clear signal'. */ 138 p->lpum = 0; 139 p->pom = 0xff; 140 s->flags &= ~SCSW_FLAGS_MASK_PNO; 141 142 /* We always 'attempt to issue the clear signal', and we always succeed. */ 143 sch->orb = NULL; 144 sch->channel_prog = 0x0; 145 sch->last_cmd_valid = false; 146 s->ctrl &= ~SCSW_ACTL_CLEAR_PEND; 147 s->ctrl |= SCSW_STCTL_STATUS_PEND; 148 149 s->dstat = 0; 150 s->cstat = 0; 151 p->lpum = path; 152 153 } 154 155 static void sch_handle_halt_func(SubchDev *sch) 156 { 157 158 PMCW *p = &sch->curr_status.pmcw; 159 SCSW *s = &sch->curr_status.scsw; 160 int path; 161 162 /* Path management: In our simple css, we always choose the only path. */ 163 path = 0x80; 164 165 /* We always 'attempt to issue the halt signal', and we always succeed. */ 166 sch->orb = NULL; 167 sch->channel_prog = 0x0; 168 sch->last_cmd_valid = false; 169 s->ctrl &= ~SCSW_ACTL_HALT_PEND; 170 s->ctrl |= SCSW_STCTL_STATUS_PEND; 171 172 if ((s->ctrl & (SCSW_ACTL_SUBCH_ACTIVE | SCSW_ACTL_DEVICE_ACTIVE)) || 173 !((s->ctrl & SCSW_ACTL_START_PEND) || 174 (s->ctrl & SCSW_ACTL_SUSP))) { 175 s->dstat = SCSW_DSTAT_DEVICE_END; 176 } 177 s->cstat = 0; 178 p->lpum = path; 179 180 } 181 182 static void copy_sense_id_to_guest(SenseId *dest, SenseId *src) 183 { 184 int i; 185 186 dest->reserved = src->reserved; 187 dest->cu_type = cpu_to_be16(src->cu_type); 188 dest->cu_model = src->cu_model; 189 dest->dev_type = cpu_to_be16(src->dev_type); 190 dest->dev_model = src->dev_model; 191 dest->unused = src->unused; 192 for (i = 0; i < ARRAY_SIZE(dest->ciw); i++) { 193 dest->ciw[i].type = src->ciw[i].type; 194 dest->ciw[i].command = src->ciw[i].command; 195 dest->ciw[i].count = cpu_to_be16(src->ciw[i].count); 196 } 197 } 198 199 static CCW1 copy_ccw_from_guest(hwaddr addr) 200 { 201 CCW1 tmp; 202 CCW1 ret; 203 204 cpu_physical_memory_read(addr, &tmp, sizeof(tmp)); 205 ret.cmd_code = tmp.cmd_code; 206 ret.flags = tmp.flags; 207 ret.count = be16_to_cpu(tmp.count); 208 ret.cda = be32_to_cpu(tmp.cda); 209 210 return ret; 211 } 212 213 static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr) 214 { 215 int ret; 216 bool check_len; 217 int len; 218 CCW1 ccw; 219 220 if (!ccw_addr) { 221 return -EIO; 222 } 223 224 ccw = copy_ccw_from_guest(ccw_addr); 225 226 /* Check for invalid command codes. */ 227 if ((ccw.cmd_code & 0x0f) == 0) { 228 return -EINVAL; 229 } 230 if (((ccw.cmd_code & 0x0f) == CCW_CMD_TIC) && 231 ((ccw.cmd_code & 0xf0) != 0)) { 232 return -EINVAL; 233 } 234 235 if (ccw.flags & CCW_FLAG_SUSPEND) { 236 return -EINPROGRESS; 237 } 238 239 check_len = !((ccw.flags & CCW_FLAG_SLI) && !(ccw.flags & CCW_FLAG_DC)); 240 241 /* Look at the command. */ 242 switch (ccw.cmd_code) { 243 case CCW_CMD_NOOP: 244 /* Nothing to do. */ 245 ret = 0; 246 break; 247 case CCW_CMD_BASIC_SENSE: 248 if (check_len) { 249 if (ccw.count != sizeof(sch->sense_data)) { 250 ret = -EINVAL; 251 break; 252 } 253 } 254 len = MIN(ccw.count, sizeof(sch->sense_data)); 255 cpu_physical_memory_write(ccw.cda, sch->sense_data, len); 256 sch->curr_status.scsw.count = ccw.count - len; 257 memset(sch->sense_data, 0, sizeof(sch->sense_data)); 258 ret = 0; 259 break; 260 case CCW_CMD_SENSE_ID: 261 { 262 SenseId sense_id; 263 264 copy_sense_id_to_guest(&sense_id, &sch->id); 265 /* Sense ID information is device specific. */ 266 if (check_len) { 267 if (ccw.count != sizeof(sense_id)) { 268 ret = -EINVAL; 269 break; 270 } 271 } 272 len = MIN(ccw.count, sizeof(sense_id)); 273 /* 274 * Only indicate 0xff in the first sense byte if we actually 275 * have enough place to store at least bytes 0-3. 276 */ 277 if (len >= 4) { 278 sense_id.reserved = 0xff; 279 } else { 280 sense_id.reserved = 0; 281 } 282 cpu_physical_memory_write(ccw.cda, &sense_id, len); 283 sch->curr_status.scsw.count = ccw.count - len; 284 ret = 0; 285 break; 286 } 287 case CCW_CMD_TIC: 288 if (sch->last_cmd_valid && (sch->last_cmd.cmd_code == CCW_CMD_TIC)) { 289 ret = -EINVAL; 290 break; 291 } 292 if (ccw.flags & (CCW_FLAG_CC | CCW_FLAG_DC)) { 293 ret = -EINVAL; 294 break; 295 } 296 sch->channel_prog = ccw.cda; 297 ret = -EAGAIN; 298 break; 299 default: 300 if (sch->ccw_cb) { 301 /* Handle device specific commands. */ 302 ret = sch->ccw_cb(sch, ccw); 303 } else { 304 ret = -ENOSYS; 305 } 306 break; 307 } 308 sch->last_cmd = ccw; 309 sch->last_cmd_valid = true; 310 if (ret == 0) { 311 if (ccw.flags & CCW_FLAG_CC) { 312 sch->channel_prog += 8; 313 ret = -EAGAIN; 314 } 315 } 316 317 return ret; 318 } 319 320 static void sch_handle_start_func(SubchDev *sch) 321 { 322 323 PMCW *p = &sch->curr_status.pmcw; 324 SCSW *s = &sch->curr_status.scsw; 325 ORB *orb = sch->orb; 326 int path; 327 int ret; 328 329 /* Path management: In our simple css, we always choose the only path. */ 330 path = 0x80; 331 332 if (!(s->ctrl & SCSW_ACTL_SUSP)) { 333 /* Look at the orb and try to execute the channel program. */ 334 p->intparm = orb->intparm; 335 if (!(orb->lpm & path)) { 336 /* Generate a deferred cc 3 condition. */ 337 s->flags |= SCSW_FLAGS_MASK_CC; 338 s->ctrl &= ~SCSW_CTRL_MASK_STCTL; 339 s->ctrl |= (SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND); 340 return; 341 } 342 } else { 343 s->ctrl &= ~(SCSW_ACTL_SUSP | SCSW_ACTL_RESUME_PEND); 344 } 345 sch->last_cmd_valid = false; 346 do { 347 ret = css_interpret_ccw(sch, sch->channel_prog); 348 switch (ret) { 349 case -EAGAIN: 350 /* ccw chain, continue processing */ 351 break; 352 case 0: 353 /* success */ 354 s->ctrl &= ~SCSW_ACTL_START_PEND; 355 s->ctrl &= ~SCSW_CTRL_MASK_STCTL; 356 s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY | 357 SCSW_STCTL_STATUS_PEND; 358 s->dstat = SCSW_DSTAT_CHANNEL_END | SCSW_DSTAT_DEVICE_END; 359 break; 360 case -ENOSYS: 361 /* unsupported command, generate unit check (command reject) */ 362 s->ctrl &= ~SCSW_ACTL_START_PEND; 363 s->dstat = SCSW_DSTAT_UNIT_CHECK; 364 /* Set sense bit 0 in ecw0. */ 365 sch->sense_data[0] = 0x80; 366 s->ctrl &= ~SCSW_CTRL_MASK_STCTL; 367 s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY | 368 SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND; 369 break; 370 case -EFAULT: 371 /* memory problem, generate channel data check */ 372 s->ctrl &= ~SCSW_ACTL_START_PEND; 373 s->cstat = SCSW_CSTAT_DATA_CHECK; 374 s->ctrl &= ~SCSW_CTRL_MASK_STCTL; 375 s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY | 376 SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND; 377 break; 378 case -EBUSY: 379 /* subchannel busy, generate deferred cc 1 */ 380 s->flags &= ~SCSW_FLAGS_MASK_CC; 381 s->flags |= (1 << 8); 382 s->ctrl &= ~SCSW_CTRL_MASK_STCTL; 383 s->ctrl |= SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND; 384 break; 385 case -EINPROGRESS: 386 /* channel program has been suspended */ 387 s->ctrl &= ~SCSW_ACTL_START_PEND; 388 s->ctrl |= SCSW_ACTL_SUSP; 389 break; 390 default: 391 /* error, generate channel program check */ 392 s->ctrl &= ~SCSW_ACTL_START_PEND; 393 s->cstat = SCSW_CSTAT_PROG_CHECK; 394 s->ctrl &= ~SCSW_CTRL_MASK_STCTL; 395 s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY | 396 SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND; 397 break; 398 } 399 } while (ret == -EAGAIN); 400 401 } 402 403 /* 404 * On real machines, this would run asynchronously to the main vcpus. 405 * We might want to make some parts of the ssch handling (interpreting 406 * read/writes) asynchronous later on if we start supporting more than 407 * our current very simple devices. 408 */ 409 static void do_subchannel_work(SubchDev *sch) 410 { 411 412 SCSW *s = &sch->curr_status.scsw; 413 414 if (s->ctrl & SCSW_FCTL_CLEAR_FUNC) { 415 sch_handle_clear_func(sch); 416 } else if (s->ctrl & SCSW_FCTL_HALT_FUNC) { 417 sch_handle_halt_func(sch); 418 } else if (s->ctrl & SCSW_FCTL_START_FUNC) { 419 sch_handle_start_func(sch); 420 } else { 421 /* Cannot happen. */ 422 return; 423 } 424 css_inject_io_interrupt(sch); 425 } 426 427 static void copy_pmcw_to_guest(PMCW *dest, const PMCW *src) 428 { 429 int i; 430 431 dest->intparm = cpu_to_be32(src->intparm); 432 dest->flags = cpu_to_be16(src->flags); 433 dest->devno = cpu_to_be16(src->devno); 434 dest->lpm = src->lpm; 435 dest->pnom = src->pnom; 436 dest->lpum = src->lpum; 437 dest->pim = src->pim; 438 dest->mbi = cpu_to_be16(src->mbi); 439 dest->pom = src->pom; 440 dest->pam = src->pam; 441 for (i = 0; i < ARRAY_SIZE(dest->chpid); i++) { 442 dest->chpid[i] = src->chpid[i]; 443 } 444 dest->chars = cpu_to_be32(src->chars); 445 } 446 447 static void copy_scsw_to_guest(SCSW *dest, const SCSW *src) 448 { 449 dest->flags = cpu_to_be16(src->flags); 450 dest->ctrl = cpu_to_be16(src->ctrl); 451 dest->cpa = cpu_to_be32(src->cpa); 452 dest->dstat = src->dstat; 453 dest->cstat = src->cstat; 454 dest->count = cpu_to_be16(src->count); 455 } 456 457 static void copy_schib_to_guest(SCHIB *dest, const SCHIB *src) 458 { 459 int i; 460 461 copy_pmcw_to_guest(&dest->pmcw, &src->pmcw); 462 copy_scsw_to_guest(&dest->scsw, &src->scsw); 463 dest->mba = cpu_to_be64(src->mba); 464 for (i = 0; i < ARRAY_SIZE(dest->mda); i++) { 465 dest->mda[i] = src->mda[i]; 466 } 467 } 468 469 int css_do_stsch(SubchDev *sch, SCHIB *schib) 470 { 471 /* Use current status. */ 472 copy_schib_to_guest(schib, &sch->curr_status); 473 return 0; 474 } 475 476 static void copy_pmcw_from_guest(PMCW *dest, const PMCW *src) 477 { 478 int i; 479 480 dest->intparm = be32_to_cpu(src->intparm); 481 dest->flags = be16_to_cpu(src->flags); 482 dest->devno = be16_to_cpu(src->devno); 483 dest->lpm = src->lpm; 484 dest->pnom = src->pnom; 485 dest->lpum = src->lpum; 486 dest->pim = src->pim; 487 dest->mbi = be16_to_cpu(src->mbi); 488 dest->pom = src->pom; 489 dest->pam = src->pam; 490 for (i = 0; i < ARRAY_SIZE(dest->chpid); i++) { 491 dest->chpid[i] = src->chpid[i]; 492 } 493 dest->chars = be32_to_cpu(src->chars); 494 } 495 496 static void copy_scsw_from_guest(SCSW *dest, const SCSW *src) 497 { 498 dest->flags = be16_to_cpu(src->flags); 499 dest->ctrl = be16_to_cpu(src->ctrl); 500 dest->cpa = be32_to_cpu(src->cpa); 501 dest->dstat = src->dstat; 502 dest->cstat = src->cstat; 503 dest->count = be16_to_cpu(src->count); 504 } 505 506 static void copy_schib_from_guest(SCHIB *dest, const SCHIB *src) 507 { 508 int i; 509 510 copy_pmcw_from_guest(&dest->pmcw, &src->pmcw); 511 copy_scsw_from_guest(&dest->scsw, &src->scsw); 512 dest->mba = be64_to_cpu(src->mba); 513 for (i = 0; i < ARRAY_SIZE(dest->mda); i++) { 514 dest->mda[i] = src->mda[i]; 515 } 516 } 517 518 int css_do_msch(SubchDev *sch, SCHIB *orig_schib) 519 { 520 SCSW *s = &sch->curr_status.scsw; 521 PMCW *p = &sch->curr_status.pmcw; 522 int ret; 523 SCHIB schib; 524 525 if (!(sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_DNV)) { 526 ret = 0; 527 goto out; 528 } 529 530 if (s->ctrl & SCSW_STCTL_STATUS_PEND) { 531 ret = -EINPROGRESS; 532 goto out; 533 } 534 535 if (s->ctrl & 536 (SCSW_FCTL_START_FUNC|SCSW_FCTL_HALT_FUNC|SCSW_FCTL_CLEAR_FUNC)) { 537 ret = -EBUSY; 538 goto out; 539 } 540 541 copy_schib_from_guest(&schib, orig_schib); 542 /* Only update the program-modifiable fields. */ 543 p->intparm = schib.pmcw.intparm; 544 p->flags &= ~(PMCW_FLAGS_MASK_ISC | PMCW_FLAGS_MASK_ENA | 545 PMCW_FLAGS_MASK_LM | PMCW_FLAGS_MASK_MME | 546 PMCW_FLAGS_MASK_MP); 547 p->flags |= schib.pmcw.flags & 548 (PMCW_FLAGS_MASK_ISC | PMCW_FLAGS_MASK_ENA | 549 PMCW_FLAGS_MASK_LM | PMCW_FLAGS_MASK_MME | 550 PMCW_FLAGS_MASK_MP); 551 p->lpm = schib.pmcw.lpm; 552 p->mbi = schib.pmcw.mbi; 553 p->pom = schib.pmcw.pom; 554 p->chars &= ~(PMCW_CHARS_MASK_MBFC | PMCW_CHARS_MASK_CSENSE); 555 p->chars |= schib.pmcw.chars & 556 (PMCW_CHARS_MASK_MBFC | PMCW_CHARS_MASK_CSENSE); 557 sch->curr_status.mba = schib.mba; 558 559 ret = 0; 560 561 out: 562 return ret; 563 } 564 565 int css_do_xsch(SubchDev *sch) 566 { 567 SCSW *s = &sch->curr_status.scsw; 568 PMCW *p = &sch->curr_status.pmcw; 569 int ret; 570 571 if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) { 572 ret = -ENODEV; 573 goto out; 574 } 575 576 if (!(s->ctrl & SCSW_CTRL_MASK_FCTL) || 577 ((s->ctrl & SCSW_CTRL_MASK_FCTL) != SCSW_FCTL_START_FUNC) || 578 (!(s->ctrl & 579 (SCSW_ACTL_RESUME_PEND | SCSW_ACTL_START_PEND | SCSW_ACTL_SUSP))) || 580 (s->ctrl & SCSW_ACTL_SUBCH_ACTIVE)) { 581 ret = -EINPROGRESS; 582 goto out; 583 } 584 585 if (s->ctrl & SCSW_CTRL_MASK_STCTL) { 586 ret = -EBUSY; 587 goto out; 588 } 589 590 /* Cancel the current operation. */ 591 s->ctrl &= ~(SCSW_FCTL_START_FUNC | 592 SCSW_ACTL_RESUME_PEND | 593 SCSW_ACTL_START_PEND | 594 SCSW_ACTL_SUSP); 595 sch->channel_prog = 0x0; 596 sch->last_cmd_valid = false; 597 sch->orb = NULL; 598 s->dstat = 0; 599 s->cstat = 0; 600 ret = 0; 601 602 out: 603 return ret; 604 } 605 606 int css_do_csch(SubchDev *sch) 607 { 608 SCSW *s = &sch->curr_status.scsw; 609 PMCW *p = &sch->curr_status.pmcw; 610 int ret; 611 612 if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) { 613 ret = -ENODEV; 614 goto out; 615 } 616 617 /* Trigger the clear function. */ 618 s->ctrl &= ~(SCSW_CTRL_MASK_FCTL | SCSW_CTRL_MASK_ACTL); 619 s->ctrl |= SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_CLEAR_FUNC; 620 621 do_subchannel_work(sch); 622 ret = 0; 623 624 out: 625 return ret; 626 } 627 628 int css_do_hsch(SubchDev *sch) 629 { 630 SCSW *s = &sch->curr_status.scsw; 631 PMCW *p = &sch->curr_status.pmcw; 632 int ret; 633 634 if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) { 635 ret = -ENODEV; 636 goto out; 637 } 638 639 if (((s->ctrl & SCSW_CTRL_MASK_STCTL) == SCSW_STCTL_STATUS_PEND) || 640 (s->ctrl & (SCSW_STCTL_PRIMARY | 641 SCSW_STCTL_SECONDARY | 642 SCSW_STCTL_ALERT))) { 643 ret = -EINPROGRESS; 644 goto out; 645 } 646 647 if (s->ctrl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { 648 ret = -EBUSY; 649 goto out; 650 } 651 652 /* Trigger the halt function. */ 653 s->ctrl |= SCSW_FCTL_HALT_FUNC; 654 s->ctrl &= ~SCSW_FCTL_START_FUNC; 655 if (((s->ctrl & SCSW_CTRL_MASK_ACTL) == 656 (SCSW_ACTL_SUBCH_ACTIVE | SCSW_ACTL_DEVICE_ACTIVE)) && 657 ((s->ctrl & SCSW_CTRL_MASK_STCTL) == SCSW_STCTL_INTERMEDIATE)) { 658 s->ctrl &= ~SCSW_STCTL_STATUS_PEND; 659 } 660 s->ctrl |= SCSW_ACTL_HALT_PEND; 661 662 do_subchannel_work(sch); 663 ret = 0; 664 665 out: 666 return ret; 667 } 668 669 static void css_update_chnmon(SubchDev *sch) 670 { 671 if (!(sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_MME)) { 672 /* Not active. */ 673 return; 674 } 675 /* The counter is conveniently located at the beginning of the struct. */ 676 if (sch->curr_status.pmcw.chars & PMCW_CHARS_MASK_MBFC) { 677 /* Format 1, per-subchannel area. */ 678 uint32_t count; 679 680 count = ldl_phys(&address_space_memory, sch->curr_status.mba); 681 count++; 682 stl_phys(&address_space_memory, sch->curr_status.mba, count); 683 } else { 684 /* Format 0, global area. */ 685 uint32_t offset; 686 uint16_t count; 687 688 offset = sch->curr_status.pmcw.mbi << 5; 689 count = lduw_phys(&address_space_memory, 690 channel_subsys->chnmon_area + offset); 691 count++; 692 stw_phys(&address_space_memory, 693 channel_subsys->chnmon_area + offset, count); 694 } 695 } 696 697 int css_do_ssch(SubchDev *sch, ORB *orb) 698 { 699 SCSW *s = &sch->curr_status.scsw; 700 PMCW *p = &sch->curr_status.pmcw; 701 int ret; 702 703 if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) { 704 ret = -ENODEV; 705 goto out; 706 } 707 708 if (s->ctrl & SCSW_STCTL_STATUS_PEND) { 709 ret = -EINPROGRESS; 710 goto out; 711 } 712 713 if (s->ctrl & (SCSW_FCTL_START_FUNC | 714 SCSW_FCTL_HALT_FUNC | 715 SCSW_FCTL_CLEAR_FUNC)) { 716 ret = -EBUSY; 717 goto out; 718 } 719 720 /* If monitoring is active, update counter. */ 721 if (channel_subsys->chnmon_active) { 722 css_update_chnmon(sch); 723 } 724 sch->orb = orb; 725 sch->channel_prog = orb->cpa; 726 /* Trigger the start function. */ 727 s->ctrl |= (SCSW_FCTL_START_FUNC | SCSW_ACTL_START_PEND); 728 s->flags &= ~SCSW_FLAGS_MASK_PNO; 729 730 do_subchannel_work(sch); 731 ret = 0; 732 733 out: 734 return ret; 735 } 736 737 static void copy_irb_to_guest(IRB *dest, const IRB *src) 738 { 739 int i; 740 741 copy_scsw_to_guest(&dest->scsw, &src->scsw); 742 743 for (i = 0; i < ARRAY_SIZE(dest->esw); i++) { 744 dest->esw[i] = cpu_to_be32(src->esw[i]); 745 } 746 for (i = 0; i < ARRAY_SIZE(dest->ecw); i++) { 747 dest->ecw[i] = cpu_to_be32(src->ecw[i]); 748 } 749 for (i = 0; i < ARRAY_SIZE(dest->emw); i++) { 750 dest->emw[i] = cpu_to_be32(src->emw[i]); 751 } 752 } 753 754 int css_do_tsch(SubchDev *sch, IRB *target_irb) 755 { 756 SCSW *s = &sch->curr_status.scsw; 757 PMCW *p = &sch->curr_status.pmcw; 758 uint16_t stctl; 759 uint16_t fctl; 760 uint16_t actl; 761 IRB irb; 762 int ret; 763 764 if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) { 765 ret = 3; 766 goto out; 767 } 768 769 stctl = s->ctrl & SCSW_CTRL_MASK_STCTL; 770 fctl = s->ctrl & SCSW_CTRL_MASK_FCTL; 771 actl = s->ctrl & SCSW_CTRL_MASK_ACTL; 772 773 /* Prepare the irb for the guest. */ 774 memset(&irb, 0, sizeof(IRB)); 775 776 /* Copy scsw from current status. */ 777 memcpy(&irb.scsw, s, sizeof(SCSW)); 778 if (stctl & SCSW_STCTL_STATUS_PEND) { 779 if (s->cstat & (SCSW_CSTAT_DATA_CHECK | 780 SCSW_CSTAT_CHN_CTRL_CHK | 781 SCSW_CSTAT_INTF_CTRL_CHK)) { 782 irb.scsw.flags |= SCSW_FLAGS_MASK_ESWF; 783 irb.esw[0] = 0x04804000; 784 } else { 785 irb.esw[0] = 0x00800000; 786 } 787 /* If a unit check is pending, copy sense data. */ 788 if ((s->dstat & SCSW_DSTAT_UNIT_CHECK) && 789 (p->chars & PMCW_CHARS_MASK_CSENSE)) { 790 irb.scsw.flags |= SCSW_FLAGS_MASK_ESWF | SCSW_FLAGS_MASK_ECTL; 791 memcpy(irb.ecw, sch->sense_data, sizeof(sch->sense_data)); 792 irb.esw[1] = 0x01000000 | (sizeof(sch->sense_data) << 8); 793 } 794 } 795 /* Store the irb to the guest. */ 796 copy_irb_to_guest(target_irb, &irb); 797 798 /* Clear conditions on subchannel, if applicable. */ 799 if (stctl & SCSW_STCTL_STATUS_PEND) { 800 s->ctrl &= ~SCSW_CTRL_MASK_STCTL; 801 if ((stctl != (SCSW_STCTL_INTERMEDIATE | SCSW_STCTL_STATUS_PEND)) || 802 ((fctl & SCSW_FCTL_HALT_FUNC) && 803 (actl & SCSW_ACTL_SUSP))) { 804 s->ctrl &= ~SCSW_CTRL_MASK_FCTL; 805 } 806 if (stctl != (SCSW_STCTL_INTERMEDIATE | SCSW_STCTL_STATUS_PEND)) { 807 s->flags &= ~SCSW_FLAGS_MASK_PNO; 808 s->ctrl &= ~(SCSW_ACTL_RESUME_PEND | 809 SCSW_ACTL_START_PEND | 810 SCSW_ACTL_HALT_PEND | 811 SCSW_ACTL_CLEAR_PEND | 812 SCSW_ACTL_SUSP); 813 } else { 814 if ((actl & SCSW_ACTL_SUSP) && 815 (fctl & SCSW_FCTL_START_FUNC)) { 816 s->flags &= ~SCSW_FLAGS_MASK_PNO; 817 if (fctl & SCSW_FCTL_HALT_FUNC) { 818 s->ctrl &= ~(SCSW_ACTL_RESUME_PEND | 819 SCSW_ACTL_START_PEND | 820 SCSW_ACTL_HALT_PEND | 821 SCSW_ACTL_CLEAR_PEND | 822 SCSW_ACTL_SUSP); 823 } else { 824 s->ctrl &= ~SCSW_ACTL_RESUME_PEND; 825 } 826 } 827 } 828 /* Clear pending sense data. */ 829 if (p->chars & PMCW_CHARS_MASK_CSENSE) { 830 memset(sch->sense_data, 0 , sizeof(sch->sense_data)); 831 } 832 } 833 834 ret = ((stctl & SCSW_STCTL_STATUS_PEND) == 0); 835 836 out: 837 return ret; 838 } 839 840 static void copy_crw_to_guest(CRW *dest, const CRW *src) 841 { 842 dest->flags = cpu_to_be16(src->flags); 843 dest->rsid = cpu_to_be16(src->rsid); 844 } 845 846 int css_do_stcrw(CRW *crw) 847 { 848 CrwContainer *crw_cont; 849 int ret; 850 851 crw_cont = QTAILQ_FIRST(&channel_subsys->pending_crws); 852 if (crw_cont) { 853 QTAILQ_REMOVE(&channel_subsys->pending_crws, crw_cont, sibling); 854 copy_crw_to_guest(crw, &crw_cont->crw); 855 g_free(crw_cont); 856 ret = 0; 857 } else { 858 /* List was empty, turn crw machine checks on again. */ 859 memset(crw, 0, sizeof(*crw)); 860 channel_subsys->do_crw_mchk = true; 861 ret = 1; 862 } 863 864 return ret; 865 } 866 867 int css_do_tpi(IOIntCode *int_code, int lowcore) 868 { 869 /* No pending interrupts for !KVM. */ 870 return 0; 871 } 872 873 int css_collect_chp_desc(int m, uint8_t cssid, uint8_t f_chpid, uint8_t l_chpid, 874 int rfmt, void *buf) 875 { 876 int i, desc_size; 877 uint32_t words[8]; 878 uint32_t chpid_type_word; 879 CssImage *css; 880 881 if (!m && !cssid) { 882 css = channel_subsys->css[channel_subsys->default_cssid]; 883 } else { 884 css = channel_subsys->css[cssid]; 885 } 886 if (!css) { 887 return 0; 888 } 889 desc_size = 0; 890 for (i = f_chpid; i <= l_chpid; i++) { 891 if (css->chpids[i].in_use) { 892 chpid_type_word = 0x80000000 | (css->chpids[i].type << 8) | i; 893 if (rfmt == 0) { 894 words[0] = cpu_to_be32(chpid_type_word); 895 words[1] = 0; 896 memcpy(buf + desc_size, words, 8); 897 desc_size += 8; 898 } else if (rfmt == 1) { 899 words[0] = cpu_to_be32(chpid_type_word); 900 words[1] = 0; 901 words[2] = 0; 902 words[3] = 0; 903 words[4] = 0; 904 words[5] = 0; 905 words[6] = 0; 906 words[7] = 0; 907 memcpy(buf + desc_size, words, 32); 908 desc_size += 32; 909 } 910 } 911 } 912 return desc_size; 913 } 914 915 void css_do_schm(uint8_t mbk, int update, int dct, uint64_t mbo) 916 { 917 /* dct is currently ignored (not really meaningful for our devices) */ 918 /* TODO: Don't ignore mbk. */ 919 if (update && !channel_subsys->chnmon_active) { 920 /* Enable measuring. */ 921 channel_subsys->chnmon_area = mbo; 922 channel_subsys->chnmon_active = true; 923 } 924 if (!update && channel_subsys->chnmon_active) { 925 /* Disable measuring. */ 926 channel_subsys->chnmon_area = 0; 927 channel_subsys->chnmon_active = false; 928 } 929 } 930 931 int css_do_rsch(SubchDev *sch) 932 { 933 SCSW *s = &sch->curr_status.scsw; 934 PMCW *p = &sch->curr_status.pmcw; 935 int ret; 936 937 if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) { 938 ret = -ENODEV; 939 goto out; 940 } 941 942 if (s->ctrl & SCSW_STCTL_STATUS_PEND) { 943 ret = -EINPROGRESS; 944 goto out; 945 } 946 947 if (((s->ctrl & SCSW_CTRL_MASK_FCTL) != SCSW_FCTL_START_FUNC) || 948 (s->ctrl & SCSW_ACTL_RESUME_PEND) || 949 (!(s->ctrl & SCSW_ACTL_SUSP))) { 950 ret = -EINVAL; 951 goto out; 952 } 953 954 /* If monitoring is active, update counter. */ 955 if (channel_subsys->chnmon_active) { 956 css_update_chnmon(sch); 957 } 958 959 s->ctrl |= SCSW_ACTL_RESUME_PEND; 960 do_subchannel_work(sch); 961 ret = 0; 962 963 out: 964 return ret; 965 } 966 967 int css_do_rchp(uint8_t cssid, uint8_t chpid) 968 { 969 uint8_t real_cssid; 970 971 if (cssid > channel_subsys->max_cssid) { 972 return -EINVAL; 973 } 974 if (channel_subsys->max_cssid == 0) { 975 real_cssid = channel_subsys->default_cssid; 976 } else { 977 real_cssid = cssid; 978 } 979 if (!channel_subsys->css[real_cssid]) { 980 return -EINVAL; 981 } 982 983 if (!channel_subsys->css[real_cssid]->chpids[chpid].in_use) { 984 return -ENODEV; 985 } 986 987 if (!channel_subsys->css[real_cssid]->chpids[chpid].is_virtual) { 988 fprintf(stderr, 989 "rchp unsupported for non-virtual chpid %x.%02x!\n", 990 real_cssid, chpid); 991 return -ENODEV; 992 } 993 994 /* We don't really use a channel path, so we're done here. */ 995 css_queue_crw(CRW_RSC_CHP, CRW_ERC_INIT, 996 channel_subsys->max_cssid > 0 ? 1 : 0, chpid); 997 if (channel_subsys->max_cssid > 0) { 998 css_queue_crw(CRW_RSC_CHP, CRW_ERC_INIT, 0, real_cssid << 8); 999 } 1000 return 0; 1001 } 1002 1003 bool css_schid_final(int m, uint8_t cssid, uint8_t ssid, uint16_t schid) 1004 { 1005 SubchSet *set; 1006 uint8_t real_cssid; 1007 1008 real_cssid = (!m && (cssid == 0)) ? channel_subsys->default_cssid : cssid; 1009 if (real_cssid > MAX_CSSID || ssid > MAX_SSID || 1010 !channel_subsys->css[real_cssid] || 1011 !channel_subsys->css[real_cssid]->sch_set[ssid]) { 1012 return true; 1013 } 1014 set = channel_subsys->css[real_cssid]->sch_set[ssid]; 1015 return schid > find_last_bit(set->schids_used, 1016 (MAX_SCHID + 1) / sizeof(unsigned long)); 1017 } 1018 1019 static int css_add_virtual_chpid(uint8_t cssid, uint8_t chpid, uint8_t type) 1020 { 1021 CssImage *css; 1022 1023 trace_css_chpid_add(cssid, chpid, type); 1024 if (cssid > MAX_CSSID) { 1025 return -EINVAL; 1026 } 1027 css = channel_subsys->css[cssid]; 1028 if (!css) { 1029 return -EINVAL; 1030 } 1031 if (css->chpids[chpid].in_use) { 1032 return -EEXIST; 1033 } 1034 css->chpids[chpid].in_use = 1; 1035 css->chpids[chpid].type = type; 1036 css->chpids[chpid].is_virtual = 1; 1037 1038 css_generate_chp_crws(cssid, chpid); 1039 1040 return 0; 1041 } 1042 1043 void css_sch_build_virtual_schib(SubchDev *sch, uint8_t chpid, uint8_t type) 1044 { 1045 PMCW *p = &sch->curr_status.pmcw; 1046 SCSW *s = &sch->curr_status.scsw; 1047 int i; 1048 CssImage *css = channel_subsys->css[sch->cssid]; 1049 1050 assert(css != NULL); 1051 memset(p, 0, sizeof(PMCW)); 1052 p->flags |= PMCW_FLAGS_MASK_DNV; 1053 p->devno = sch->devno; 1054 /* single path */ 1055 p->pim = 0x80; 1056 p->pom = 0xff; 1057 p->pam = 0x80; 1058 p->chpid[0] = chpid; 1059 if (!css->chpids[chpid].in_use) { 1060 css_add_virtual_chpid(sch->cssid, chpid, type); 1061 } 1062 1063 memset(s, 0, sizeof(SCSW)); 1064 sch->curr_status.mba = 0; 1065 for (i = 0; i < ARRAY_SIZE(sch->curr_status.mda); i++) { 1066 sch->curr_status.mda[i] = 0; 1067 } 1068 } 1069 1070 SubchDev *css_find_subch(uint8_t m, uint8_t cssid, uint8_t ssid, uint16_t schid) 1071 { 1072 uint8_t real_cssid; 1073 1074 real_cssid = (!m && (cssid == 0)) ? channel_subsys->default_cssid : cssid; 1075 1076 if (!channel_subsys->css[real_cssid]) { 1077 return NULL; 1078 } 1079 1080 if (!channel_subsys->css[real_cssid]->sch_set[ssid]) { 1081 return NULL; 1082 } 1083 1084 return channel_subsys->css[real_cssid]->sch_set[ssid]->sch[schid]; 1085 } 1086 1087 bool css_subch_visible(SubchDev *sch) 1088 { 1089 if (sch->ssid > channel_subsys->max_ssid) { 1090 return false; 1091 } 1092 1093 if (sch->cssid != channel_subsys->default_cssid) { 1094 return (channel_subsys->max_cssid > 0); 1095 } 1096 1097 return true; 1098 } 1099 1100 bool css_present(uint8_t cssid) 1101 { 1102 return (channel_subsys->css[cssid] != NULL); 1103 } 1104 1105 bool css_devno_used(uint8_t cssid, uint8_t ssid, uint16_t devno) 1106 { 1107 if (!channel_subsys->css[cssid]) { 1108 return false; 1109 } 1110 if (!channel_subsys->css[cssid]->sch_set[ssid]) { 1111 return false; 1112 } 1113 1114 return !!test_bit(devno, 1115 channel_subsys->css[cssid]->sch_set[ssid]->devnos_used); 1116 } 1117 1118 void css_subch_assign(uint8_t cssid, uint8_t ssid, uint16_t schid, 1119 uint16_t devno, SubchDev *sch) 1120 { 1121 CssImage *css; 1122 SubchSet *s_set; 1123 1124 trace_css_assign_subch(sch ? "assign" : "deassign", cssid, ssid, schid, 1125 devno); 1126 if (!channel_subsys->css[cssid]) { 1127 fprintf(stderr, 1128 "Suspicious call to %s (%x.%x.%04x) for non-existing css!\n", 1129 __func__, cssid, ssid, schid); 1130 return; 1131 } 1132 css = channel_subsys->css[cssid]; 1133 1134 if (!css->sch_set[ssid]) { 1135 css->sch_set[ssid] = g_malloc0(sizeof(SubchSet)); 1136 } 1137 s_set = css->sch_set[ssid]; 1138 1139 s_set->sch[schid] = sch; 1140 if (sch) { 1141 set_bit(schid, s_set->schids_used); 1142 set_bit(devno, s_set->devnos_used); 1143 } else { 1144 clear_bit(schid, s_set->schids_used); 1145 clear_bit(devno, s_set->devnos_used); 1146 } 1147 } 1148 1149 void css_queue_crw(uint8_t rsc, uint8_t erc, int chain, uint16_t rsid) 1150 { 1151 CrwContainer *crw_cont; 1152 1153 trace_css_crw(rsc, erc, rsid, chain ? "(chained)" : ""); 1154 /* TODO: Maybe use a static crw pool? */ 1155 crw_cont = g_try_malloc0(sizeof(CrwContainer)); 1156 if (!crw_cont) { 1157 channel_subsys->crws_lost = true; 1158 return; 1159 } 1160 crw_cont->crw.flags = (rsc << 8) | erc; 1161 if (chain) { 1162 crw_cont->crw.flags |= CRW_FLAGS_MASK_C; 1163 } 1164 crw_cont->crw.rsid = rsid; 1165 if (channel_subsys->crws_lost) { 1166 crw_cont->crw.flags |= CRW_FLAGS_MASK_R; 1167 channel_subsys->crws_lost = false; 1168 } 1169 1170 QTAILQ_INSERT_TAIL(&channel_subsys->pending_crws, crw_cont, sibling); 1171 1172 if (channel_subsys->do_crw_mchk) { 1173 S390CPU *cpu = s390_cpu_addr2state(0); 1174 1175 channel_subsys->do_crw_mchk = false; 1176 /* Inject crw pending machine check. */ 1177 s390_crw_mchk(cpu); 1178 } 1179 } 1180 1181 void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid, 1182 int hotplugged, int add) 1183 { 1184 uint8_t guest_cssid; 1185 bool chain_crw; 1186 1187 if (add && !hotplugged) { 1188 return; 1189 } 1190 if (channel_subsys->max_cssid == 0) { 1191 /* Default cssid shows up as 0. */ 1192 guest_cssid = (cssid == channel_subsys->default_cssid) ? 0 : cssid; 1193 } else { 1194 /* Show real cssid to the guest. */ 1195 guest_cssid = cssid; 1196 } 1197 /* 1198 * Only notify for higher subchannel sets/channel subsystems if the 1199 * guest has enabled it. 1200 */ 1201 if ((ssid > channel_subsys->max_ssid) || 1202 (guest_cssid > channel_subsys->max_cssid) || 1203 ((channel_subsys->max_cssid == 0) && 1204 (cssid != channel_subsys->default_cssid))) { 1205 return; 1206 } 1207 chain_crw = (channel_subsys->max_ssid > 0) || 1208 (channel_subsys->max_cssid > 0); 1209 css_queue_crw(CRW_RSC_SUBCH, CRW_ERC_IPI, chain_crw ? 1 : 0, schid); 1210 if (chain_crw) { 1211 css_queue_crw(CRW_RSC_SUBCH, CRW_ERC_IPI, 0, 1212 (guest_cssid << 8) | (ssid << 4)); 1213 } 1214 } 1215 1216 void css_generate_chp_crws(uint8_t cssid, uint8_t chpid) 1217 { 1218 /* TODO */ 1219 } 1220 1221 int css_enable_mcsse(void) 1222 { 1223 trace_css_enable_facility("mcsse"); 1224 channel_subsys->max_cssid = MAX_CSSID; 1225 return 0; 1226 } 1227 1228 int css_enable_mss(void) 1229 { 1230 trace_css_enable_facility("mss"); 1231 channel_subsys->max_ssid = MAX_SSID; 1232 return 0; 1233 } 1234 1235 static void css_init(void) 1236 { 1237 channel_subsys = g_malloc0(sizeof(*channel_subsys)); 1238 QTAILQ_INIT(&channel_subsys->pending_crws); 1239 channel_subsys->do_crw_mchk = true; 1240 channel_subsys->crws_lost = false; 1241 channel_subsys->chnmon_active = false; 1242 } 1243 machine_init(css_init); 1244 1245 void css_reset_sch(SubchDev *sch) 1246 { 1247 PMCW *p = &sch->curr_status.pmcw; 1248 1249 p->intparm = 0; 1250 p->flags &= ~(PMCW_FLAGS_MASK_ISC | PMCW_FLAGS_MASK_ENA | 1251 PMCW_FLAGS_MASK_LM | PMCW_FLAGS_MASK_MME | 1252 PMCW_FLAGS_MASK_MP | PMCW_FLAGS_MASK_TF); 1253 p->flags |= PMCW_FLAGS_MASK_DNV; 1254 p->devno = sch->devno; 1255 p->pim = 0x80; 1256 p->lpm = p->pim; 1257 p->pnom = 0; 1258 p->lpum = 0; 1259 p->mbi = 0; 1260 p->pom = 0xff; 1261 p->pam = 0x80; 1262 p->chars &= ~(PMCW_CHARS_MASK_MBFC | PMCW_CHARS_MASK_XMWME | 1263 PMCW_CHARS_MASK_CSENSE); 1264 1265 memset(&sch->curr_status.scsw, 0, sizeof(sch->curr_status.scsw)); 1266 sch->curr_status.mba = 0; 1267 1268 sch->channel_prog = 0x0; 1269 sch->last_cmd_valid = false; 1270 sch->orb = NULL; 1271 sch->thinint_active = false; 1272 } 1273 1274 void css_reset(void) 1275 { 1276 CrwContainer *crw_cont; 1277 1278 /* Clean up monitoring. */ 1279 channel_subsys->chnmon_active = false; 1280 channel_subsys->chnmon_area = 0; 1281 1282 /* Clear pending CRWs. */ 1283 while ((crw_cont = QTAILQ_FIRST(&channel_subsys->pending_crws))) { 1284 QTAILQ_REMOVE(&channel_subsys->pending_crws, crw_cont, sibling); 1285 g_free(crw_cont); 1286 } 1287 channel_subsys->do_crw_mchk = true; 1288 channel_subsys->crws_lost = false; 1289 1290 /* Reset maximum ids. */ 1291 channel_subsys->max_cssid = 0; 1292 channel_subsys->max_ssid = 0; 1293 } 1294