/** * 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.groups = chp_attr_groups; chp->dev.release = chp_release; mutex_init(&chp->lock); /* Obtain channel path description and fill it in. */ ret = chp_update_desc(chp); if (ret) goto out_free; if ((chp->desc.flags & 0x80) == 0) { ret = -ENODEV; goto out_free; } dev_set_name(&chp->dev, "chp%x.%02x", chpid.cssid, chpid.id); /* 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); put_device(&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) { 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; }
static void ssd_register_chpids(struct chsc_ssd_info *ssd) { int i; int mask; for (i = 0; i < 8; i++) { mask = 0x80 >> i; if (ssd->path_mask & mask) if (!chp_is_registered(ssd->chpid[i])) chp_new(ssd->chpid[i]); } }
/** * chp_process_crw - process channel-path status change * @id: channel-path ID number * @status: non-zero if channel-path has become available, zero otherwise * * Handle channel-report-words indicating that the status of a channel-path * has changed. */ void chp_process_crw(int id, int status) { struct chp_id chpid; chp_id_init(&chpid); chpid.id = id; if (status) { if (!chp_is_registered(chpid)) chp_new(chpid); chsc_chp_online(chpid); } else chsc_chp_offline(chpid); }
/** * chp_process_crw - process channel-path status change * @crw0: channel report-word to handler * @crw1: second channel-report word (always NULL) * @overflow: crw overflow indication * * Handle channel-report-words indicating that the status of a channel-path * has changed. */ static void chp_process_crw(struct crw *crw0, struct crw *crw1, int overflow) { struct chp_id chpid; if (overflow) { css_schedule_eval_all(); return; } CIO_CRW_EVENT(2, "CRW reports slct=%d, oflw=%d, " "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", crw0->slct, crw0->oflw, crw0->chn, crw0->rsc, crw0->anc, crw0->erc, crw0->rsid); /* * Check for solicited machine checks. These are * created by reset channel path and need not be * handled here. */ if (crw0->slct) { CIO_CRW_EVENT(2, "solicited machine check for " "channel path %02X\n", crw0->rsid); return; } chp_id_init(&chpid); chpid.id = crw0->rsid; switch (crw0->erc) { case CRW_ERC_IPARM: /* Path has come. */ if (!chp_is_registered(chpid)) chp_new(chpid); chsc_chp_online(chpid); break; case CRW_ERC_PERRI: /* Path has gone. */ case CRW_ERC_PERRN: chsc_chp_offline(chpid); break; default: CIO_CRW_EVENT(2, "Don't know how to handle erc=%x\n", crw0->erc); } }
/** * 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; }
/** * 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 = &css[chpid.cssid]->device; chp->dev.release = chp_release; snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp%x.%02x", chpid.cssid, chpid.id); /* Obtain channel path description and fill it in. */ ret = chsc_determine_channel_path_description(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_characteristics_avail && css_chsc_characteristics.scmc && css_chsc_characteristics.secm) { ret = chsc_get_channel_measurement_chars(chp); if (ret) goto out_free; } else { static int msg_done; if (!msg_done) { printk(KERN_WARNING "cio: Channel measurements not " "available, continuing.\n"); msg_done = 1; } chp->cmg = -1; } /* make it known to the system */ ret = device_register(&chp->dev); if (ret) { printk(KERN_WARNING "%s: could not register %x.%02x\n", __func__, chpid.cssid, chpid.id); goto out_free; } ret = sysfs_create_group(&chp->dev.kobj, &chp_attr_group); if (ret) { device_unregister(&chp->dev); goto out_free; } mutex_lock(&css[chpid.cssid]->mutex); if (css[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(&css[chpid.cssid]->mutex); goto out_free; } } css[chpid.cssid]->chps[chpid.id] = chp; mutex_unlock(&css[chpid.cssid]->mutex); return ret; out_free: kfree(chp); return ret; }