mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-04 17:44:14 +08:00
s390/ap: handle outband SE bind state change
This patch addresses some weird scenarios where an outband manipulation of the SE bind state of a queue assigned and maybe in use by an SE guest with AP pass-through support took place. So for example when the guest has bound and associated a queue and then this domain has been zeroed on the service element. Signed-off-by: Harald Freudenberger <freude@linux.ibm.com> Reviewed-by: Holger Dengler <dengler@linux.ibm.com> Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
This commit is contained in:
parent
d4c53ae8e4
commit
207022d39d
@ -1847,6 +1847,7 @@ static inline void ap_scan_domains(struct ap_card *ac)
|
||||
aq->card = ac;
|
||||
aq->config = !decfg;
|
||||
aq->chkstop = chkstop;
|
||||
aq->se_bstate = hwinfo.bs;
|
||||
dev = &aq->ap_dev.device;
|
||||
dev->bus = &ap_bus_type;
|
||||
dev->parent = &ac->ap_dev.device;
|
||||
@ -1876,6 +1877,8 @@ static inline void ap_scan_domains(struct ap_card *ac)
|
||||
}
|
||||
/* handle state changes on already existing queue device */
|
||||
spin_lock_bh(&aq->lock);
|
||||
/* SE bind state */
|
||||
aq->se_bstate = hwinfo.bs;
|
||||
/* checkstop state */
|
||||
if (chkstop && !aq->chkstop) {
|
||||
/* checkstop on */
|
||||
|
@ -194,7 +194,7 @@ struct ap_queue {
|
||||
bool config; /* configured state */
|
||||
bool chkstop; /* checkstop state */
|
||||
ap_qid_t qid; /* AP queue id. */
|
||||
bool se_bound; /* SE bound state */
|
||||
unsigned int se_bstate; /* SE bind state (BS) */
|
||||
unsigned int assoc_idx; /* SE association index */
|
||||
int queue_count; /* # messages currently on AP queue. */
|
||||
int pendingq_count; /* # requests on pendingq list. */
|
||||
|
@ -317,7 +317,6 @@ static enum ap_sm_wait ap_sm_reset(struct ap_queue *aq)
|
||||
case AP_RESPONSE_RESET_IN_PROGRESS:
|
||||
aq->sm_state = AP_SM_STATE_RESET_WAIT;
|
||||
aq->rapq_fbit = 0;
|
||||
aq->se_bound = false;
|
||||
return AP_SM_WAIT_LOW_TIMEOUT;
|
||||
default:
|
||||
aq->dev_state = AP_DEV_STATE_ERROR;
|
||||
@ -338,17 +337,15 @@ static enum ap_sm_wait ap_sm_reset(struct ap_queue *aq)
|
||||
static enum ap_sm_wait ap_sm_reset_wait(struct ap_queue *aq)
|
||||
{
|
||||
struct ap_queue_status status;
|
||||
struct ap_tapq_hwinfo hwinfo;
|
||||
void *lsi_ptr;
|
||||
|
||||
if (aq->queue_count > 0 && aq->reply)
|
||||
/* Try to read a completed message and get the status */
|
||||
status = ap_sm_recv(aq);
|
||||
else
|
||||
/* Get the status with TAPQ */
|
||||
status = ap_tapq(aq->qid, NULL);
|
||||
/* Get the status with TAPQ */
|
||||
status = ap_test_queue(aq->qid, 1, &hwinfo);
|
||||
|
||||
switch (status.response_code) {
|
||||
case AP_RESPONSE_NORMAL:
|
||||
aq->se_bstate = hwinfo.bs;
|
||||
lsi_ptr = ap_airq_ptr();
|
||||
if (lsi_ptr && ap_queue_enable_irq(aq, lsi_ptr) == 0)
|
||||
aq->sm_state = AP_SM_STATE_SETIRQ_WAIT;
|
||||
@ -441,6 +438,9 @@ static enum ap_sm_wait ap_sm_assoc_wait(struct ap_queue *aq)
|
||||
return AP_SM_WAIT_NONE;
|
||||
}
|
||||
|
||||
/* update queue's SE bind state */
|
||||
aq->se_bstate = hwinfo.bs;
|
||||
|
||||
/* check bs bits */
|
||||
switch (hwinfo.bs) {
|
||||
case AP_BS_Q_USABLE:
|
||||
@ -851,6 +851,12 @@ static ssize_t se_bind_show(struct device *dev,
|
||||
AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* update queue's SE bind state */
|
||||
spin_lock_bh(&aq->lock);
|
||||
aq->se_bstate = hwinfo.bs;
|
||||
spin_unlock_bh(&aq->lock);
|
||||
|
||||
switch (hwinfo.bs) {
|
||||
case AP_BS_Q_USABLE:
|
||||
case AP_BS_Q_USABLE_NO_SECURE_KEY:
|
||||
@ -866,6 +872,7 @@ static ssize_t se_bind_store(struct device *dev,
|
||||
{
|
||||
struct ap_queue *aq = to_ap_queue(dev);
|
||||
struct ap_queue_status status;
|
||||
struct ap_tapq_hwinfo hwinfo;
|
||||
bool value;
|
||||
int rc;
|
||||
|
||||
@ -877,39 +884,80 @@ static ssize_t se_bind_store(struct device *dev,
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (value) {
|
||||
/* bind, do BAPQ */
|
||||
spin_lock_bh(&aq->lock);
|
||||
if (aq->sm_state < AP_SM_STATE_IDLE) {
|
||||
spin_unlock_bh(&aq->lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
status = ap_bapq(aq->qid);
|
||||
spin_unlock_bh(&aq->lock);
|
||||
if (!status.response_code) {
|
||||
aq->se_bound = true;
|
||||
AP_DBF_INFO("%s bapq(0x%02x.%04x) success\n", __func__,
|
||||
AP_QID_CARD(aq->qid),
|
||||
AP_QID_QUEUE(aq->qid));
|
||||
} else {
|
||||
AP_DBF_WARN("%s RC 0x%02x on bapq(0x%02x.%04x)\n",
|
||||
__func__, status.response_code,
|
||||
AP_QID_CARD(aq->qid),
|
||||
AP_QID_QUEUE(aq->qid));
|
||||
return -EIO;
|
||||
}
|
||||
} else {
|
||||
/* unbind, set F bit arg and trigger RAPQ */
|
||||
if (!value) {
|
||||
/* Unbind. Set F bit arg and trigger RAPQ */
|
||||
spin_lock_bh(&aq->lock);
|
||||
__ap_flush_queue(aq);
|
||||
aq->rapq_fbit = 1;
|
||||
aq->assoc_idx = ASSOC_IDX_INVALID;
|
||||
aq->sm_state = AP_SM_STATE_RESET_START;
|
||||
ap_wait(ap_sm_event(aq, AP_SM_EVENT_POLL));
|
||||
spin_unlock_bh(&aq->lock);
|
||||
_ap_queue_init_state(aq);
|
||||
rc = count;
|
||||
goto out;
|
||||
}
|
||||
|
||||
return count;
|
||||
/* Bind. Check current SE bind state */
|
||||
status = ap_test_queue(aq->qid, 1, &hwinfo);
|
||||
if (status.response_code) {
|
||||
AP_DBF_WARN("%s RC 0x%02x on tapq(0x%02x.%04x)\n",
|
||||
__func__, status.response_code,
|
||||
AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Update BS state */
|
||||
spin_lock_bh(&aq->lock);
|
||||
aq->se_bstate = hwinfo.bs;
|
||||
if (hwinfo.bs != AP_BS_Q_AVAIL_FOR_BINDING) {
|
||||
AP_DBF_WARN("%s bind attempt with bs %d on queue 0x%02x.%04x\n",
|
||||
__func__, hwinfo.bs,
|
||||
AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid));
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Check SM state */
|
||||
if (aq->sm_state < AP_SM_STATE_IDLE) {
|
||||
rc = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* invoke BAPQ */
|
||||
status = ap_bapq(aq->qid);
|
||||
if (status.response_code) {
|
||||
AP_DBF_WARN("%s RC 0x%02x on bapq(0x%02x.%04x)\n",
|
||||
__func__, status.response_code,
|
||||
AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid));
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
aq->assoc_idx = ASSOC_IDX_INVALID;
|
||||
|
||||
/* verify SE bind state */
|
||||
status = ap_test_queue(aq->qid, 1, &hwinfo);
|
||||
if (status.response_code) {
|
||||
AP_DBF_WARN("%s RC 0x%02x on tapq(0x%02x.%04x)\n",
|
||||
__func__, status.response_code,
|
||||
AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid));
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
aq->se_bstate = hwinfo.bs;
|
||||
if (!(hwinfo.bs == AP_BS_Q_USABLE ||
|
||||
hwinfo.bs == AP_BS_Q_USABLE_NO_SECURE_KEY)) {
|
||||
AP_DBF_WARN("%s BAPQ success, but bs shows %d on queue 0x%02x.%04x\n",
|
||||
__func__, hwinfo.bs,
|
||||
AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid));
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* SE bind was successful */
|
||||
AP_DBF_INFO("%s bapq(0x%02x.%04x) success\n", __func__,
|
||||
AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid));
|
||||
rc = count;
|
||||
|
||||
out:
|
||||
spin_unlock_bh(&aq->lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(se_bind);
|
||||
@ -932,6 +980,11 @@ static ssize_t se_associate_show(struct device *dev,
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* update queue's SE bind state */
|
||||
spin_lock_bh(&aq->lock);
|
||||
aq->se_bstate = hwinfo.bs;
|
||||
spin_unlock_bh(&aq->lock);
|
||||
|
||||
switch (hwinfo.bs) {
|
||||
case AP_BS_Q_USABLE:
|
||||
if (aq->assoc_idx == ASSOC_IDX_INVALID) {
|
||||
@ -954,6 +1007,7 @@ static ssize_t se_associate_store(struct device *dev,
|
||||
{
|
||||
struct ap_queue *aq = to_ap_queue(dev);
|
||||
struct ap_queue_status status;
|
||||
struct ap_tapq_hwinfo hwinfo;
|
||||
unsigned int value;
|
||||
int rc;
|
||||
|
||||
@ -967,18 +1021,28 @@ static ssize_t se_associate_store(struct device *dev,
|
||||
if (value >= ASSOC_IDX_INVALID)
|
||||
return -EINVAL;
|
||||
|
||||
/* check current SE bind state */
|
||||
status = ap_test_queue(aq->qid, 1, &hwinfo);
|
||||
if (status.response_code) {
|
||||
AP_DBF_WARN("%s RC 0x%02x on tapq(0x%02x.%04x)\n",
|
||||
__func__, status.response_code,
|
||||
AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid));
|
||||
return -EIO;
|
||||
}
|
||||
spin_lock_bh(&aq->lock);
|
||||
|
||||
/* sm should be in idle state */
|
||||
if (aq->sm_state != AP_SM_STATE_IDLE) {
|
||||
spin_unlock_bh(&aq->lock);
|
||||
return -EBUSY;
|
||||
aq->se_bstate = hwinfo.bs;
|
||||
if (hwinfo.bs != AP_BS_Q_USABLE_NO_SECURE_KEY) {
|
||||
AP_DBF_WARN("%s association attempt with bs %d on queue 0x%02x.%04x\n",
|
||||
__func__, hwinfo.bs,
|
||||
AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid));
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* already associated or association pending ? */
|
||||
if (aq->assoc_idx != ASSOC_IDX_INVALID) {
|
||||
spin_unlock_bh(&aq->lock);
|
||||
return -EINVAL;
|
||||
/* check SM state */
|
||||
if (aq->sm_state != AP_SM_STATE_IDLE) {
|
||||
rc = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* trigger the asynchronous association request */
|
||||
@ -989,17 +1053,20 @@ static ssize_t se_associate_store(struct device *dev,
|
||||
aq->sm_state = AP_SM_STATE_ASSOC_WAIT;
|
||||
aq->assoc_idx = value;
|
||||
ap_wait(ap_sm_event(aq, AP_SM_EVENT_POLL));
|
||||
spin_unlock_bh(&aq->lock);
|
||||
break;
|
||||
default:
|
||||
spin_unlock_bh(&aq->lock);
|
||||
AP_DBF_WARN("%s RC 0x%02x on aapq(0x%02x.%04x)\n",
|
||||
__func__, status.response_code,
|
||||
AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid));
|
||||
return -EIO;
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
return count;
|
||||
rc = count;
|
||||
|
||||
out:
|
||||
spin_unlock_bh(&aq->lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(se_associate);
|
||||
@ -1122,7 +1189,9 @@ bool ap_queue_usable(struct ap_queue *aq)
|
||||
}
|
||||
|
||||
/* SE guest's queues additionally need to be bound */
|
||||
if (ap_q_needs_bind(aq) && !aq->se_bound)
|
||||
if (ap_q_needs_bind(aq) &&
|
||||
!(aq->se_bstate == AP_BS_Q_USABLE ||
|
||||
aq->se_bstate == AP_BS_Q_USABLE_NO_SECURE_KEY))
|
||||
rc = false;
|
||||
|
||||
unlock_and_out:
|
||||
|
Loading…
Reference in New Issue
Block a user