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_get_chp_desc - return newly allocated channel-path description * @chpid: channel-path ID * * On success return a newly allocated copy of the channel-path description * data associated with the given channel-path ID. Return %NULL on error. */ void *chp_get_chp_desc(struct chp_id chpid) { struct channel_path *chp; struct channel_path_desc *desc; chp = chpid_to_chp(chpid); if (!chp) return NULL; desc = kmalloc(sizeof(struct channel_path_desc), GFP_KERNEL); if (!desc) return NULL; memcpy(desc, &chp->desc, sizeof(struct channel_path_desc)); return desc; }
/** * 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; }
/** * 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 description. */ chp_update_desc(chp); for_each_subchannel_staged(s390_subchannel_vary_chpid_on, NULL, &chpid); css_schedule_reprobe(); } else for_each_subchannel_staged(s390_subchannel_vary_chpid_off, NULL, &chpid); return 0; }
void chsc_chp_offline(struct chp_id chpid) { struct channel_path *chp = chpid_to_chp(chpid); struct chp_link link; char dbf_txt[15]; sprintf(dbf_txt, "chpr%x.%02x", chpid.cssid, chpid.id); CIO_TRACE_EVENT(2, dbf_txt); if (chp_get_status(chpid) <= 0) return; memset(&link, 0, sizeof(struct chp_link)); link.chpid = chpid; /* Wait until previous actions have settled. */ css_wait_for_slow_path(); mutex_lock(&chp->lock); chp_update_desc(chp); mutex_unlock(&chp->lock); for_each_subchannel_staged(s390_subchannel_remove_chpid, NULL, &link); }
/* On success return 0 if channel-path is varied offline, 1 if it is varied * online. Return -ENODEV if channel-path is not registered. */ int chp_get_status(struct chp_id chpid) { return (chpid_to_chp(chpid) ? chpid_to_chp(chpid)->state : -ENODEV); }
/* Set vary state for given chpid. */ static void set_chp_logically_online(struct chp_id chpid, int onoff) { chpid_to_chp(chpid)->state = onoff; }
/** * chp_is_registered - check if a channel-path is registered * @chpid: channel-path ID * * Return non-zero if a channel-path with the given chpid is registered, * zero otherwise. */ int chp_is_registered(struct chp_id chpid) { return chpid_to_chp(chpid) != NULL; }