aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/crypto/ap_bus.c
diff options
context:
space:
mode:
authorHarald Freudenberger <freude@linux.ibm.com>2021-11-17 15:38:39 +0100
committerVasily Gorbik <gor@linux.ibm.com>2022-03-08 00:33:00 +0100
commita7e701dba1234adbfbacad5ce19656c5606728da (patch)
tree245680d4d662d8bfe5470ef51b4d57d9d56588a2 /drivers/s390/crypto/ap_bus.c
parents390/zcrypt: CEX8S exploitation support (diff)
downloadlinux-dev-a7e701dba1234adbfbacad5ce19656c5606728da.tar.xz
linux-dev-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/crypto/ap_bus.c')
-rw-r--r--drivers/s390/crypto/ap_bus.c78
1 files changed, 63 insertions, 15 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);