📄 chsc.c
字号:
ret = -EIO; break; default: CIO_CRW_EVENT(2, "Unknown CHSC response %d\n", secm_area->response.code); ret = -EIO; } return ret;}intchsc_secm(struct channel_subsystem *css, int enable){ void *secm_area; int ret; secm_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!secm_area) return -ENOMEM; mutex_lock(&css->mutex); if (enable && !css->cm_enabled) { css->cub_addr1 = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); css->cub_addr2 = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!css->cub_addr1 || !css->cub_addr2) { free_page((unsigned long)css->cub_addr1); free_page((unsigned long)css->cub_addr2); free_page((unsigned long)secm_area); mutex_unlock(&css->mutex); return -ENOMEM; } } ret = __chsc_do_secm(css, enable, secm_area); if (!ret) { css->cm_enabled = enable; if (css->cm_enabled) { ret = chsc_add_cmg_attr(css); if (ret) { memset(secm_area, 0, PAGE_SIZE); __chsc_do_secm(css, 0, secm_area); css->cm_enabled = 0; } } else chsc_remove_cmg_attr(css); } if (enable && !css->cm_enabled) { free_page((unsigned long)css->cub_addr1); free_page((unsigned long)css->cub_addr2); } mutex_unlock(&css->mutex); free_page((unsigned long)secm_area); return ret;}/* * Files for the channel path entries. */static ssize_tchp_status_show(struct device *dev, struct device_attribute *attr, char *buf){ struct channel_path *chp = container_of(dev, struct channel_path, dev); if (!chp) return 0; return (get_chp_status(chp->id) ? sprintf(buf, "online\n") : sprintf(buf, "offline\n"));}static ssize_tchp_status_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ struct channel_path *cp = container_of(dev, struct channel_path, dev); char cmd[10]; int num_args; int error; num_args = sscanf(buf, "%5s", cmd); if (!num_args) return count; if (!strnicmp(cmd, "on", 2)) error = s390_vary_chpid(cp->id, 1); else if (!strnicmp(cmd, "off", 3)) error = s390_vary_chpid(cp->id, 0); else error = -EINVAL; return error < 0 ? error : count;}static DEVICE_ATTR(status, 0644, chp_status_show, chp_status_write);static ssize_tchp_type_show(struct device *dev, struct device_attribute *attr, char *buf){ struct channel_path *chp = container_of(dev, struct channel_path, dev); if (!chp) return 0; return sprintf(buf, "%x\n", chp->desc.desc);}static DEVICE_ATTR(type, 0444, chp_type_show, NULL);static ssize_tchp_cmg_show(struct device *dev, struct device_attribute *attr, char *buf){ struct channel_path *chp = to_channelpath(dev); if (!chp) return 0; if (chp->cmg == -1) /* channel measurements not available */ return sprintf(buf, "unknown\n"); return sprintf(buf, "%x\n", chp->cmg);}static DEVICE_ATTR(cmg, 0444, chp_cmg_show, NULL);static ssize_tchp_shared_show(struct device *dev, struct device_attribute *attr, char *buf){ struct channel_path *chp = to_channelpath(dev); if (!chp) return 0; if (chp->shared == -1) /* channel measurements not available */ return sprintf(buf, "unknown\n"); return sprintf(buf, "%x\n", chp->shared);}static DEVICE_ATTR(shared, 0444, chp_shared_show, NULL);static struct attribute * chp_attrs[] = { &dev_attr_status.attr, &dev_attr_type.attr, &dev_attr_cmg.attr, &dev_attr_shared.attr, NULL,};static struct attribute_group chp_attr_group = { .attrs = chp_attrs,};static voidchp_release(struct device *dev){ struct channel_path *cp; cp = container_of(dev, struct channel_path, dev); kfree(cp);}static intchsc_determine_channel_path_description(int chpid, struct channel_path_desc *desc){ int ccode, ret; struct { struct chsc_header request; u32 : 24; u32 first_chpid : 8; u32 : 24; u32 last_chpid : 8; u32 zeroes1; struct chsc_header response; u32 zeroes2; struct channel_path_desc desc; } *scpd_area; scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!scpd_area) return -ENOMEM; scpd_area->request.length = 0x0010; scpd_area->request.code = 0x0002; scpd_area->first_chpid = chpid; scpd_area->last_chpid = chpid; ccode = chsc(scpd_area); if (ccode > 0) { ret = (ccode == 3) ? -ENODEV : -EBUSY; goto out; } switch (scpd_area->response.code) { case 0x0001: /* Success. */ memcpy(desc, &scpd_area->desc, sizeof(struct channel_path_desc)); ret = 0; break; case 0x0003: /* Invalid block. */ case 0x0007: /* Invalid format. */ case 0x0008: /* Other invalid block. */ CIO_CRW_EVENT(2, "Error in chsc request block!\n"); ret = -EINVAL; break; case 0x0004: /* Command not provided in model. */ CIO_CRW_EVENT(2, "Model does not provide scpd\n"); ret = -EOPNOTSUPP; break; default: CIO_CRW_EVENT(2, "Unknown CHSC response %d\n", scpd_area->response.code); ret = -EIO; }out: free_page((unsigned long)scpd_area); return ret;}static voidchsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv, struct cmg_chars *chars){ switch (chp->cmg) { case 2: case 3: chp->cmg_chars = kmalloc(sizeof(struct cmg_chars), GFP_KERNEL); if (chp->cmg_chars) { int i, mask; struct cmg_chars *cmg_chars; cmg_chars = chp->cmg_chars; for (i = 0; i < NR_MEASUREMENT_CHARS; i++) { mask = 0x80 >> (i + 3); if (cmcv & mask) cmg_chars->values[i] = chars->values[i]; else cmg_chars->values[i] = 0; } } break; default: /* No cmg-dependent data. */ break; }}static intchsc_get_channel_measurement_chars(struct channel_path *chp){ int ccode, ret; struct { struct chsc_header request; u32 : 24; u32 first_chpid : 8; u32 : 24; u32 last_chpid : 8; u32 zeroes1; struct chsc_header response; u32 zeroes2; u32 not_valid : 1; u32 shared : 1; u32 : 22; u32 chpid : 8; u32 cmcv : 5; u32 : 11; u32 cmgq : 8; u32 cmg : 8; u32 zeroes3; u32 data[NR_MEASUREMENT_CHARS]; } *scmc_area; scmc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!scmc_area) return -ENOMEM; scmc_area->request.length = 0x0010; scmc_area->request.code = 0x0022; scmc_area->first_chpid = chp->id; scmc_area->last_chpid = chp->id; ccode = chsc(scmc_area); if (ccode > 0) { ret = (ccode == 3) ? -ENODEV : -EBUSY; goto out; } switch (scmc_area->response.code) { case 0x0001: /* Success. */ if (!scmc_area->not_valid) { chp->cmg = scmc_area->cmg; chp->shared = scmc_area->shared; chsc_initialize_cmg_chars(chp, scmc_area->cmcv, (struct cmg_chars *) &scmc_area->data); } else { chp->cmg = -1; chp->shared = -1; } ret = 0; break; case 0x0003: /* Invalid block. */ case 0x0007: /* Invalid format. */ case 0x0008: /* Invalid bit combination. */ CIO_CRW_EVENT(2, "Error in chsc request block!\n"); ret = -EINVAL; break; case 0x0004: /* Command not provided. */ CIO_CRW_EVENT(2, "Model does not provide scmc\n"); ret = -EOPNOTSUPP; break; default: CIO_CRW_EVENT(2, "Unknown CHSC response %d\n", scmc_area->response.code); ret = -EIO; }out: free_page((unsigned long)scmc_area); return ret;}/* * Entries for chpids on the system bus. * This replaces /proc/chpids. */static intnew_channel_path(int chpid){ struct channel_path *chp; int ret; chp = kzalloc(sizeof(struct channel_path), GFP_KERNEL); if (!chp) return -ENOMEM; /* fill in status, etc. */ chp->id = chpid; chp->state = 1; chp->dev = (struct device) { .parent = &css[0]->device, .release = chp_release, }; snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp0.%x", chpid); /* Obtain channel path description and fill it in. */ ret = chsc_determine_channel_path_description(chpid, &chp->desc); if (ret) 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 %02x\n", __func__, chpid); 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[0]->mutex); if (css[0]->cm_enabled) { ret = chsc_add_chp_cmg_attr(chp); if (ret) { sysfs_remove_group(&chp->dev.kobj, &chp_attr_group); device_unregister(&chp->dev); mutex_unlock(&css[0]->mutex); goto out_free; } } css[0]->chps[chpid] = chp; mutex_unlock(&css[0]->mutex); return ret;out_free: kfree(chp); return ret;}void *chsc_get_chp_desc(struct subchannel *sch, int chp_no){ struct channel_path *chp; struct channel_path_desc *desc; chp = css[0]->chps[sch->schib.pmcw.chpid[chp_no]]; 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;}static int __initchsc_alloc_sei_area(void){ sei_page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!sei_page) printk(KERN_WARNING"Can't allocate page for processing of " \ "chsc machine checks!\n"); return (sei_page ? 0 : -ENOMEM);}int __initchsc_enable_facility(int operation_code){ int ret; struct { struct chsc_header request; u8 reserved1:4; u8 format:4; u8 reserved2; u16 operation_code; u32 reserved3; u32 reserved4; u32 operation_data_area[252]; struct chsc_header response; u32 reserved5:4; u32 format2:4; u32 reserved6:24; } *sda_area; sda_area = (void *)get_zeroed_page(GFP_KERNEL|GFP_DMA); if (!sda_area) return -ENOMEM; sda_area->request.length = 0x0400; sda_area->request.code = 0x0031; sda_area->operation_code = operation_code; ret = chsc(sda_area); if (ret > 0) { ret = (ret == 3) ? -ENODEV : -EBUSY; goto out; } switch (sda_area->response.code) { case 0x0001: /* everything ok */ ret = 0; break; case 0x0003: /* invalid request block */ case 0x0007: ret = -EINVAL; break; case 0x0004: /* command not provided */ case 0x0101: /* facility not provided */ ret = -EOPNOTSUPP; break; default: /* something went wrong */ ret = -EIO; } out: free_page((unsigned long)sda_area); return ret;}subsys_initcall(chsc_alloc_sei_area);struct css_general_char css_general_characteristics;struct css_chsc_char css_chsc_characteristics;int __initchsc_determine_css_characteristics(void){ int result; struct { struct chsc_header request; u32 reserved1; u32 reserved2; u32 reserved3; struct chsc_header response; u32 reserved4; u32 general_char[510]; u32 chsc_char[518]; } *scsc_area; scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!scsc_area) { printk(KERN_WARNING"cio: Was not able to determine available" \ "CHSCs due to no memory.\n"); return -ENOMEM; } scsc_area->request.length = 0x0010; scsc_area->request.code = 0x0010; result = chsc(scsc_area); if (result) { printk(KERN_WARNING"cio: Was not able to determine " \ "available CHSCs, cc=%i.\n", result); result = -EIO; goto exit; } if (scsc_area->response.code != 1) { printk(KERN_WARNING"cio: Was not able to determine " \ "available CHSCs.\n"); result = -EIO; goto exit; } memcpy(&css_general_characteristics, scsc_area->general_char, sizeof(css_general_characteristics)); memcpy(&css_chsc_characteristics, scsc_area->chsc_char, sizeof(css_chsc_characteristics));exit: free_page ((unsigned long) scsc_area); return result;}EXPORT_SYMBOL_GPL(css_general_characteristics);EXPORT_SYMBOL_GPL(css_chsc_characteristics);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -