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>
This commit is contained in:
Harald Freudenberger 2021-11-17 15:38:39 +01:00 committed by Vasily Gorbik
parent 985214af93
commit a7e701dba1
5 changed files with 105 additions and 30 deletions

View file

@ -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 @@ static inline void ap_scan_domains(struct ap_card *ac)
*/
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);

View file

@ -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. */

View file

@ -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
};

View file

@ -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,

View file

@ -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;