📄 chsc.c
字号:
}void chsc_chp_online(struct chp_id chpid){ char dbf_txt[15]; sprintf(dbf_txt, "cadd%x.%02x", chpid.cssid, chpid.id); CIO_TRACE_EVENT(2, dbf_txt); if (chp_get_status(chpid) != 0) for_each_subchannel(__chp_add, &chpid);}static void __s390_subchannel_vary_chpid(struct subchannel *sch, struct chp_id chpid, int on){ int chp, old_lpm; int mask; unsigned long flags; spin_lock_irqsave(sch->lock, flags); old_lpm = sch->lpm; for (chp = 0; chp < 8; chp++) { mask = 0x80 >> chp; if (!(sch->ssd_info.path_mask & mask)) continue; if (!chp_id_is_equal(&sch->ssd_info.chpid[chp], &chpid)) continue; if (on) { sch->opm |= mask; sch->lpm |= mask; if (!old_lpm) device_trigger_reprobe(sch); else if (sch->driver && sch->driver->verify) sch->driver->verify(&sch->dev); break; } sch->opm &= ~mask; sch->lpm &= ~mask; if (check_for_io_on_path(sch, mask)) { if (device_is_online(sch)) /* Path verification is done after killing. */ device_kill_io(sch); else { /* Kill and retry internal I/O. */ terminate_internal_io(sch); /* Re-start path verification. */ if (sch->driver && sch->driver->verify) sch->driver->verify(&sch->dev); } } else if (!sch->lpm) { if (device_trigger_verify(sch) != 0) css_schedule_eval(sch->schid); } else if (sch->driver && sch->driver->verify) sch->driver->verify(&sch->dev); break; } spin_unlock_irqrestore(sch->lock, flags);}static int s390_subchannel_vary_chpid_off(struct device *dev, void *data){ struct subchannel *sch; struct chp_id *chpid; sch = to_subchannel(dev); chpid = data; __s390_subchannel_vary_chpid(sch, *chpid, 0); return 0;}static int s390_subchannel_vary_chpid_on(struct device *dev, void *data){ struct subchannel *sch; struct chp_id *chpid; sch = to_subchannel(dev); chpid = data; __s390_subchannel_vary_chpid(sch, *chpid, 1); return 0;}static int__s390_vary_chpid_on(struct subchannel_id schid, void *data){ struct schib schib; struct subchannel *sch; sch = get_subchannel_by_schid(schid); if (sch) { put_device(&sch->dev); return 0; } if (stsch_err(schid, &schib)) /* We're through */ return -ENXIO; /* Put it on the slow path. */ css_schedule_eval(schid); 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){ /* * Redo PathVerification on the devices the chpid connects to */ bus_for_each_dev(&css_bus_type, NULL, &chpid, on ? s390_subchannel_vary_chpid_on : s390_subchannel_vary_chpid_off); if (on) /* Scan for new devices on varied on path. */ for_each_subchannel(__s390_vary_chpid_on, NULL); return 0;}static voidchsc_remove_cmg_attr(struct channel_subsystem *css){ int i; for (i = 0; i <= __MAX_CHPID; i++) { if (!css->chps[i]) continue; chp_remove_cmg_attr(css->chps[i]); }}static intchsc_add_cmg_attr(struct channel_subsystem *css){ int i, ret; ret = 0; for (i = 0; i <= __MAX_CHPID; i++) { if (!css->chps[i]) continue; ret = chp_add_cmg_attr(css->chps[i]); if (ret) goto cleanup; } return ret;cleanup: for (--i; i >= 0; i--) { if (!css->chps[i]) continue; chp_remove_cmg_attr(css->chps[i]); } return ret;}static int__chsc_do_secm(struct channel_subsystem *css, int enable, void *page){ struct { struct chsc_header request; u32 operation_code : 2; u32 : 30; u32 key : 4; u32 : 28; u32 zeroes1; u32 cub_addr1; u32 zeroes2; u32 cub_addr2; u32 reserved[13]; struct chsc_header response; u32 status : 8; u32 : 4; u32 fmt : 4; u32 : 16; } __attribute__ ((packed)) *secm_area; int ret, ccode; secm_area = page; secm_area->request.length = 0x0050; secm_area->request.code = 0x0016; secm_area->key = PAGE_DEFAULT_KEY; secm_area->cub_addr1 = (u64)(unsigned long)css->cub_addr1; secm_area->cub_addr2 = (u64)(unsigned long)css->cub_addr2; secm_area->operation_code = enable ? 0 : 1; ccode = chsc(secm_area); if (ccode > 0) return (ccode == 3) ? -ENODEV : -EBUSY; switch (secm_area->response.code) { case 0x0001: /* Success. */ 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 secm\n"); ret = -EOPNOTSUPP; break; case 0x0102: /* cub adresses incorrect */ CIO_CRW_EVENT(2, "Invalid addresses in chsc request block\n"); ret = -EINVAL; break; case 0x0103: /* key error */ CIO_CRW_EVENT(2, "Access key error in secm\n"); ret = -EINVAL; break; case 0x0105: /* error while starting */ CIO_CRW_EVENT(2, "Error while starting channel measurement\n"); 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 (!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;}int chsc_determine_channel_path_description(struct chp_id 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; } __attribute__ ((packed)) *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.id; scpd_area->last_chpid = chpid.id; 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; }}int chsc_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]; } __attribute__ ((packed)) *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->chpid.id; scmc_area->last_chpid = chp->chpid.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;}int __init chsc_alloc_sei_area(void){ sei_page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!sei_page) CIO_MSG_EVENT(0, "Can't allocate page for processing of " "chsc machine checks!\n"); return (sei_page ? 0 : -ENOMEM);}void __init chsc_free_sei_area(void){ kfree(sei_page);}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; } __attribute__ ((packed)) *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;}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]; } __attribute__ ((packed)) *scsc_area; scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!scsc_area) { CIO_MSG_EVENT(0, "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) { CIO_MSG_EVENT(0, "Was not able to determine available CHSCs, " "cc=%i.\n", result); result = -EIO; goto exit; } if (scsc_area->response.code != 1) { CIO_MSG_EVENT(0, "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 + -