diff options
author | 2021-11-17 15:38:39 +0100 | |
---|---|---|
committer | 2022-03-08 00:33:00 +0100 | |
commit | a7e701dba1234adbfbacad5ce19656c5606728da (patch) | |
tree | 245680d4d662d8bfe5470ef51b4d57d9d56588a2 /drivers/s390 | |
parent | s390/zcrypt: CEX8S exploitation support (diff) | |
download | linux-a7e701dba1234adbfbacad5ce19656c5606728da.tar.gz linux-a7e701dba1234adbfbacad5ce19656c5606728da.tar.bz2 linux-a7e701dba1234adbfbacad5ce19656c5606728da.zip |
s390/zcrypt: handle checkstopped cards with new state
A crypto card may be in checkstopped state. With this
patch this is handled as a new state in the ap card and
ap queue structs. There is also a new card sysfs attribute
/sys/devices/ap/cardxx/chkstop
and a new queue sysfs attribute
/sys/devices/ap/cardxx/xx.yyyy/chkstop
displaying the checkstop state of the card or queue. Please
note that the queue's checkstop state is only a copy of the
card's checkstop state but makes maintenance much easier.
The checkstop state expressed here is the result of an
RC 0x04 (CHECKSTOP) during an AP command, mostly the
PQAP(TAPQ) command which is 'testing' the queue.
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Jürgen Christ <jchrist@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/crypto/ap_bus.c | 78 | ||||
-rw-r--r-- | drivers/s390/crypto/ap_bus.h | 2 | ||||
-rw-r--r-- | drivers/s390/crypto/ap_card.c | 11 | ||||
-rw-r--r-- | drivers/s390/crypto/ap_queue.c | 18 | ||||
-rw-r--r-- | drivers/s390/crypto/zcrypt_api.c | 26 |
5 files changed, 105 insertions, 30 deletions
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 0f8f4230dbc2..fdf16cb70881 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -323,7 +323,7 @@ EXPORT_SYMBOL(ap_test_config_ctrl_domain); * false otherwise. */ static bool ap_queue_info(ap_qid_t qid, int *q_type, unsigned int *q_fac, - int *q_depth, int *q_ml, bool *q_decfg) + int *q_depth, int *q_ml, bool *q_decfg, bool *q_cstop) { struct ap_queue_status status; union { @@ -366,6 +366,7 @@ static bool ap_queue_info(ap_qid_t qid, int *q_type, unsigned int *q_fac, *q_depth = tapq_info.tapq_gr2.qd; *q_ml = tapq_info.tapq_gr2.ml; *q_decfg = status.response_code == AP_RESPONSE_DECONFIGURED; + *q_cstop = status.response_code == AP_RESPONSE_CHECKSTOPPED; switch (*q_type) { /* For CEX2 and CEX3 the available functions * are not reflected by the facilities bits. @@ -1710,7 +1711,7 @@ static inline void ap_scan_rm_card_dev_and_queue_devs(struct ap_card *ac) */ static inline void ap_scan_domains(struct ap_card *ac) { - bool decfg; + bool decfg, chkstop; ap_qid_t qid; unsigned int func; struct device *dev; @@ -1739,7 +1740,8 @@ static inline void ap_scan_domains(struct ap_card *ac) continue; } /* domain is valid, get info from this APQN */ - if (!ap_queue_info(qid, &type, &func, &depth, &ml, &decfg)) { + if (!ap_queue_info(qid, &type, &func, &depth, + &ml, &decfg, &chkstop)) { if (aq) { AP_DBF_INFO("%s(%d,%d) queue_info() failed, rm queue dev\n", __func__, ac->id, dom); @@ -1758,6 +1760,7 @@ static inline void ap_scan_domains(struct ap_card *ac) } aq->card = ac; aq->config = !decfg; + aq->chkstop = chkstop; dev = &aq->ap_dev.device; dev->bus = &ap_bus_type; dev->parent = &ac->ap_dev.device; @@ -1774,13 +1777,43 @@ static inline void ap_scan_domains(struct ap_card *ac) if (decfg) AP_DBF_INFO("%s(%d,%d) new (decfg) queue dev created\n", __func__, ac->id, dom); + else if (chkstop) + AP_DBF_INFO("%s(%d,%d) new (chkstop) queue dev created\n", + __func__, ac->id, dom); else AP_DBF_INFO("%s(%d,%d) new queue dev created\n", __func__, ac->id, dom); goto put_dev_and_continue; } - /* Check config state on the already existing queue device */ + /* handle state changes on already existing queue device */ spin_lock_bh(&aq->lock); + /* checkstop state */ + if (chkstop && !aq->chkstop) { + /* checkstop on */ + aq->chkstop = true; + if (aq->dev_state > AP_DEV_STATE_UNINITIATED) { + aq->dev_state = AP_DEV_STATE_ERROR; + aq->last_err_rc = AP_RESPONSE_CHECKSTOPPED; + } + spin_unlock_bh(&aq->lock); + AP_DBF_DBG("%s(%d,%d) queue dev checkstop on\n", + __func__, ac->id, dom); + /* 'receive' pending messages with -EAGAIN */ + ap_flush_queue(aq); + goto put_dev_and_continue; + } else if (!chkstop && aq->chkstop) { + /* checkstop off */ + aq->chkstop = false; + if (aq->dev_state > AP_DEV_STATE_UNINITIATED) { + aq->dev_state = AP_DEV_STATE_OPERATING; + aq->sm_state = AP_SM_STATE_RESET_START; + } + spin_unlock_bh(&aq->lock); + AP_DBF_DBG("%s(%d,%d) queue dev checkstop off\n", + __func__, ac->id, dom); + goto put_dev_and_continue; + } + /* config state change */ if (decfg && aq->config) { /* config off this queue device */ aq->config = false; @@ -1789,14 +1822,13 @@ static inline void ap_scan_domains(struct ap_card *ac) aq->last_err_rc = AP_RESPONSE_DECONFIGURED; } spin_unlock_bh(&aq->lock); - AP_DBF_INFO("%s(%d,%d) queue dev config off\n", - __func__, ac->id, dom); + AP_DBF_DBG("%s(%d,%d) queue dev config off\n", + __func__, ac->id, dom); ap_send_config_uevent(&aq->ap_dev, aq->config); /* 'receive' pending messages with -EAGAIN */ ap_flush_queue(aq); goto put_dev_and_continue; - } - if (!decfg && !aq->config) { + } else if (!decfg && !aq->config) { /* config on this queue device */ aq->config = true; if (aq->dev_state > AP_DEV_STATE_UNINITIATED) { @@ -1804,8 +1836,8 @@ static inline void ap_scan_domains(struct ap_card *ac) aq->sm_state = AP_SM_STATE_RESET_START; } spin_unlock_bh(&aq->lock); - AP_DBF_INFO("%s(%d,%d) queue dev config on\n", - __func__, ac->id, dom); + AP_DBF_DBG("%s(%d,%d) queue dev config on\n", + __func__, ac->id, dom); ap_send_config_uevent(&aq->ap_dev, aq->config); goto put_dev_and_continue; } @@ -1832,7 +1864,7 @@ put_dev_and_continue: */ static inline void ap_scan_adapter(int ap) { - bool decfg; + bool decfg, chkstop; ap_qid_t qid; unsigned int func; struct device *dev; @@ -1866,8 +1898,8 @@ static inline void ap_scan_adapter(int ap) for (dom = 0; dom <= ap_max_domain_id; dom++) if (ap_test_config_usage_domain(dom)) { qid = AP_MKQID(ap, dom); - if (ap_queue_info(qid, &type, &func, - &depth, &ml, &decfg)) + if (ap_queue_info(qid, &type, &func, &depth, + &ml, &decfg, &chkstop)) break; } if (dom > ap_max_domain_id) { @@ -1912,13 +1944,25 @@ static inline void ap_scan_adapter(int ap) put_device(dev); ac = NULL; } else { + /* handle checkstop state change */ + if (chkstop && !ac->chkstop) { + /* checkstop on */ + ac->chkstop = true; + AP_DBF_INFO("%s(%d) card dev checkstop on\n", + __func__, ap); + } else if (!chkstop && ac->chkstop) { + /* checkstop off */ + ac->chkstop = false; + AP_DBF_INFO("%s(%d) card dev checkstop off\n", + __func__, ap); + } + /* handle config state change */ if (decfg && ac->config) { ac->config = false; AP_DBF_INFO("%s(%d) card dev config off\n", __func__, ap); ap_send_config_uevent(&ac->ap_dev, ac->config); - } - if (!decfg && !ac->config) { + } else if (!decfg && !ac->config) { ac->config = true; AP_DBF_INFO("%s(%d) card dev config on\n", __func__, ap); @@ -1942,6 +1986,7 @@ static inline void ap_scan_adapter(int ap) return; } ac->config = !decfg; + ac->chkstop = chkstop; dev = &ac->ap_dev.device; dev->bus = &ap_bus_type; dev->parent = ap_root_device; @@ -1966,6 +2011,9 @@ static inline void ap_scan_adapter(int ap) if (decfg) AP_DBF_INFO("%s(%d) new (decfg) card dev type=%d func=0x%08x created\n", __func__, ap, type, func); + else if (chkstop) + AP_DBF_INFO("%s(%d) new (chkstop) card dev type=%d func=0x%08x created\n", + __func__, ap, type, func); else AP_DBF_INFO("%s(%d) new card dev type=%d func=0x%08x created\n", __func__, ap, type, func); diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index 5700d4024681..703d6782ce65 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h @@ -179,6 +179,7 @@ struct ap_card { int id; /* AP card number. */ unsigned int maxmsgsize; /* AP msg limit for this card */ bool config; /* configured state */ + bool chkstop; /* checkstop state */ atomic64_t total_request_count; /* # requests ever for this AP device.*/ }; @@ -191,6 +192,7 @@ struct ap_queue { spinlock_t lock; /* Per device lock. */ enum ap_dev_state dev_state; /* queue device state */ bool config; /* configured state */ + bool chkstop; /* checkstop state */ ap_qid_t qid; /* AP queue id. */ bool interrupt; /* indicate if interrupts are enabled */ int queue_count; /* # messages currently on AP queue. */ diff --git a/drivers/s390/crypto/ap_card.c b/drivers/s390/crypto/ap_card.c index 196325a66662..6b2170cf186e 100644 --- a/drivers/s390/crypto/ap_card.c +++ b/drivers/s390/crypto/ap_card.c @@ -174,6 +174,16 @@ static ssize_t config_store(struct device *dev, static DEVICE_ATTR_RW(config); +static ssize_t chkstop_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ap_card *ac = to_ap_card(dev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", ac->chkstop ? 1 : 0); +} + +static DEVICE_ATTR_RO(chkstop); + static ssize_t max_msg_size_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -194,6 +204,7 @@ static struct attribute *ap_card_dev_attrs[] = { &dev_attr_pendingq_count.attr, &dev_attr_modalias.attr, &dev_attr_config.attr, + &dev_attr_chkstop.attr, &dev_attr_max_msg_size.attr, NULL }; diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c index 921a82a41e66..205045cd998d 100644 --- a/drivers/s390/crypto/ap_queue.c +++ b/drivers/s390/crypto/ap_queue.c @@ -455,7 +455,8 @@ static ap_func_t *ap_jumptable[NR_AP_SM_STATES][NR_AP_SM_EVENTS] = { enum ap_sm_wait ap_sm_event(struct ap_queue *aq, enum ap_sm_event event) { - if (aq->config && aq->dev_state > AP_DEV_STATE_UNINITIATED) + if (aq->config && !aq->chkstop && + aq->dev_state > AP_DEV_STATE_UNINITIATED) return ap_jumptable[aq->sm_state][event](aq); else return AP_SM_WAIT_NONE; @@ -615,6 +616,20 @@ static ssize_t config_show(struct device *dev, static DEVICE_ATTR_RO(config); +static ssize_t chkstop_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ap_queue *aq = to_ap_queue(dev); + int rc; + + spin_lock_bh(&aq->lock); + rc = scnprintf(buf, PAGE_SIZE, "%d\n", aq->chkstop ? 1 : 0); + spin_unlock_bh(&aq->lock); + return rc; +} + +static DEVICE_ATTR_RO(chkstop); + #ifdef CONFIG_ZCRYPT_DEBUG static ssize_t states_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -729,6 +744,7 @@ static struct attribute *ap_queue_dev_attrs[] = { &dev_attr_reset.attr, &dev_attr_interrupt.attr, &dev_attr_config.attr, + &dev_attr_chkstop.attr, #ifdef CONFIG_ZCRYPT_DEBUG &dev_attr_states.attr, &dev_attr_last_err_rc.attr, diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 00f6859c4e72..8b81e6385d55 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -671,7 +671,7 @@ static long zcrypt_rsa_modexpo(struct ap_perms *perms, spin_lock(&zcrypt_list_lock); for_each_zcrypt_card(zc) { /* Check for useable accelarator or CCA card */ - if (!zc->online || !zc->card->config || + if (!zc->online || !zc->card->config || zc->card->chkstop || !(zc->card->functions & 0x18000000)) continue; /* Check for size limits */ @@ -692,7 +692,7 @@ static long zcrypt_rsa_modexpo(struct ap_perms *perms, for_each_zcrypt_queue(zq, zc) { /* check if device is useable and eligible */ if (!zq->online || !zq->ops->rsa_modexpo || - !zq->queue->config) + !zq->queue->config || zq->queue->chkstop) continue; /* check if device node has admission for this queue */ if (!zcrypt_check_queue(perms, @@ -781,7 +781,7 @@ static long zcrypt_rsa_crt(struct ap_perms *perms, spin_lock(&zcrypt_list_lock); for_each_zcrypt_card(zc) { /* Check for useable accelarator or CCA card */ - if (!zc->online || !zc->card->config || + if (!zc->online || !zc->card->config || zc->card->chkstop || !(zc->card->functions & 0x18000000)) continue; /* Check for size limits */ @@ -802,7 +802,7 @@ static long zcrypt_rsa_crt(struct ap_perms *perms, for_each_zcrypt_queue(zq, zc) { /* check if device is useable and eligible */ if (!zq->online || !zq->ops->rsa_modexpo_crt || - !zq->queue->config) + !zq->queue->config || zq->queue->chkstop) continue; /* check if device node has admission for this queue */ if (!zcrypt_check_queue(perms, @@ -895,7 +895,7 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms, spin_lock(&zcrypt_list_lock); for_each_zcrypt_card(zc) { /* Check for useable CCA card */ - if (!zc->online || !zc->card->config || + if (!zc->online || !zc->card->config || zc->card->chkstop || !(zc->card->functions & 0x10000000)) continue; /* Check for user selected CCA card */ @@ -918,9 +918,8 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms, continue; for_each_zcrypt_queue(zq, zc) { /* check for device useable and eligible */ - if (!zq->online || - !zq->ops->send_cprb || - !zq->queue->config || + if (!zq->online || !zq->ops->send_cprb || + !zq->queue->config || zq->queue->chkstop || (tdom != AUTOSEL_DOM && tdom != AP_QID_QUEUE(zq->queue->qid))) continue; @@ -1068,7 +1067,7 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms, spin_lock(&zcrypt_list_lock); for_each_zcrypt_card(zc) { /* Check for useable EP11 card */ - if (!zc->online || !zc->card->config || + if (!zc->online || !zc->card->config || zc->card->chkstop || !(zc->card->functions & 0x04000000)) continue; /* Check for user selected EP11 card */ @@ -1091,9 +1090,8 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms, continue; for_each_zcrypt_queue(zq, zc) { /* check if device is useable and eligible */ - if (!zq->online || - !zq->ops->send_ep11_cprb || - !zq->queue->config || + if (!zq->online || !zq->ops->send_ep11_cprb || + !zq->queue->config || zq->queue->chkstop || (targets && !is_desired_ep11_queue(zq->queue->qid, target_num, targets))) @@ -1182,7 +1180,7 @@ static long zcrypt_rng(char *buffer) spin_lock(&zcrypt_list_lock); for_each_zcrypt_card(zc) { /* Check for useable CCA card */ - if (!zc->online || !zc->card->config || + if (!zc->online || !zc->card->config || zc->card->chkstop || !(zc->card->functions & 0x10000000)) continue; /* get weight index of the card device */ @@ -1192,7 +1190,7 @@ static long zcrypt_rng(char *buffer) for_each_zcrypt_queue(zq, zc) { /* check if device is useable and eligible */ if (!zq->online || !zq->ops->rng || - !zq->queue->config) + !zq->queue->config || zq->queue->chkstop) continue; if (!zcrypt_queue_compare(zq, pref_zq, wgt, pref_wgt)) continue; |