static void chsc_process_sei_chp_avail(struct chsc_sei_nt0_area *sei_area) { struct channel_path *chp; struct chp_id chpid; u8 *data; int num; CIO_CRW_EVENT(4, "chsc: channel path availability information\n"); if (sei_area->rs != 0) return; data = sei_area->ccdf; chp_id_init(&chpid); for (num = 0; num <= __MAX_CHPID; num++) { if (!chp_test_bit(data, num)) continue; chpid.id = num; CIO_CRW_EVENT(4, "Update information for channel path " "%x.%02x\n", chpid.cssid, chpid.id); chp = chpid_to_chp(chpid); if (!chp) { chp_new(chpid); continue; } mutex_lock(&chp->lock); chsc_determine_base_channel_path_desc(chpid, &chp->desc); mutex_unlock(&chp->lock); } }
/** * chp_update_desc - update channel-path description * @chp - channel-path * * Update the channel-path description of the specified channel-path. * Return zero on success, non-zero otherwise. */ int chp_update_desc(struct channel_path *chp) { int rc; rc = chsc_determine_base_channel_path_desc(chp->chpid, &chp->desc); if (rc) return rc; rc = chsc_determine_fmt1_channel_path_desc(chp->chpid, &chp->desc_fmt1); return rc; }
/** * chp_update_desc - update channel-path description * @chp - channel-path * * Update the channel-path description of the specified channel-path * including channel measurement related information. * Return zero on success, non-zero otherwise. */ int chp_update_desc(struct channel_path *chp) { int rc; rc = chsc_determine_base_channel_path_desc(chp->chpid, &chp->desc); if (rc) return rc; /* * Fetching the following data is optional. Not all machines or * hypervisors implement the required chsc commands. */ chsc_determine_fmt1_channel_path_desc(chp->chpid, &chp->desc_fmt1); chsc_get_channel_measurement_chars(chp); return 0; }
/** * chsc_chp_vary - propagate channel-path vary operation to subchannels * @chpid: channl-path ID * @on: non-zero for vary online, zero for vary offline */ int chsc_chp_vary(struct chp_id chpid, int on) { struct channel_path *chp = chpid_to_chp(chpid); /* Wait until previous actions have settled. */ css_wait_for_slow_path(); /* * Redo PathVerification on the devices the chpid connects to */ if (on) { /* Try to update the channel path descritor. */ chsc_determine_base_channel_path_desc(chpid, &chp->desc); for_each_subchannel_staged(s390_subchannel_vary_chpid_on, __s390_vary_chpid_on, &chpid); } else for_each_subchannel_staged(s390_subchannel_vary_chpid_off, NULL, &chpid); return 0; }
/** * chp_new - register a new channel-path * @chpid - channel-path ID * * Create and register data structure representing new channel-path. Return * zero on success, non-zero otherwise. */ int chp_new(struct chp_id chpid) { struct channel_path *chp; int ret; if (chp_is_registered(chpid)) return 0; chp = kzalloc(sizeof(struct channel_path), GFP_KERNEL); if (!chp) return -ENOMEM; /* fill in status, etc. */ chp->chpid = chpid; chp->state = 1; chp->dev.parent = &channel_subsystems[chpid.cssid]->device; chp->dev.release = chp_release; dev_set_name(&chp->dev, "chp%x.%02x", chpid.cssid, chpid.id); /* Obtain channel path description and fill it in. */ ret = chsc_determine_base_channel_path_desc(chpid, &chp->desc); if (ret) goto out_free; if ((chp->desc.flags & 0x80) == 0) { ret = -ENODEV; goto out_free; } /* Get channel-measurement characteristics. */ if (css_chsc_characteristics.scmc && css_chsc_characteristics.secm) { ret = chsc_get_channel_measurement_chars(chp); if (ret) goto out_free; } else { chp->cmg = -1; } /* make it known to the system */ ret = device_register(&chp->dev); if (ret) { CIO_MSG_EVENT(0, "Could not register chp%x.%02x: %d\n", chpid.cssid, chpid.id, ret); goto out_free; } ret = sysfs_create_group(&chp->dev.kobj, &chp_attr_group); if (ret) { device_unregister(&chp->dev); goto out; } mutex_lock(&channel_subsystems[chpid.cssid]->mutex); if (channel_subsystems[chpid.cssid]->cm_enabled) { ret = chp_add_cmg_attr(chp); if (ret) { sysfs_remove_group(&chp->dev.kobj, &chp_attr_group); device_unregister(&chp->dev); mutex_unlock(&channel_subsystems[chpid.cssid]->mutex); goto out; } } channel_subsystems[chpid.cssid]->chps[chpid.id] = chp; mutex_unlock(&channel_subsystems[chpid.cssid]->mutex); goto out; out_free: kfree(chp); out: return ret; }