The device suspend call triggers all ap devices to fetch potentially
available response messages from the queues. Therefore the
corresponding zcrypt device, that is allocated asynchronously after
ap device probing, needs to be fully prepared. This race condition
could lead to uninitialized response buffers while trying to read
from the queues.
Introduce a new callback within the ap layer to get noticed when a
zcrypt device is fully prepared. Additional checks prevent reading
from devices that are not fully prepared.
Signed-off-by: Ingo Tuchscherer <ingo.tuchscherer@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
{
struct ap_queue_status status;
{
struct ap_queue_status status;
+ if (msg == NULL)
+ return -EINVAL;
status = __ap_recv(qid, psmid, msg, length);
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
status = __ap_recv(qid, psmid, msg, length);
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
{
struct ap_queue_status status;
{
struct ap_queue_status status;
+ if (!ap_dev->reply)
+ return AP_WAIT_NONE;
status = ap_sm_recv(ap_dev);
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
status = ap_sm_recv(ap_dev);
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
+/**
+ * ap_sm_suspend_read(): Receive pending reply messages from an AP device
+ * without changing the device state in between. In suspend mode we don't
+ * allow sending new requests, therefore just fetch pending replies.
+ * @ap_dev: pointer to the AP device
+ *
+ * Returns AP_WAIT_NONE or AP_WAIT_AGAIN
+ */
+static enum ap_wait ap_sm_suspend_read(struct ap_device *ap_dev)
+{
+ struct ap_queue_status status;
+
+ if (!ap_dev->reply)
+ return AP_WAIT_NONE;
+ status = ap_sm_recv(ap_dev);
+ switch (status.response_code) {
+ case AP_RESPONSE_NORMAL:
+ if (ap_dev->queue_count > 0)
+ return AP_WAIT_AGAIN;
+ /* fall through */
+ default:
+ return AP_WAIT_NONE;
+ }
+}
+
/**
* ap_sm_write(): Send messages from the request queue to an AP device.
* @ap_dev: pointer to the AP device
/**
* ap_sm_write(): Send messages from the request queue to an AP device.
* @ap_dev: pointer to the AP device
struct ap_queue_status status;
unsigned long info;
struct ap_queue_status status;
unsigned long info;
- if (ap_dev->queue_count > 0)
+ if (ap_dev->queue_count > 0 && ap_dev->reply)
/* Try to read a completed message and get the status */
status = ap_sm_recv(ap_dev);
else
/* Try to read a completed message and get the status */
status = ap_sm_recv(ap_dev);
else
struct ap_queue_status status;
unsigned long info;
struct ap_queue_status status;
unsigned long info;
- if (ap_dev->queue_count > 0)
+ if (ap_dev->queue_count > 0 && ap_dev->reply)
/* Try to read a completed message and get the status */
status = ap_sm_recv(ap_dev);
else
/* Try to read a completed message and get the status */
status = ap_sm_recv(ap_dev);
else
[AP_EVENT_TIMEOUT] = ap_sm_reset,
},
[AP_STATE_SUSPEND_WAIT] = {
[AP_EVENT_TIMEOUT] = ap_sm_reset,
},
[AP_STATE_SUSPEND_WAIT] = {
- [AP_EVENT_POLL] = ap_sm_read,
+ [AP_EVENT_POLL] = ap_sm_suspend_read,
[AP_EVENT_TIMEOUT] = ap_sm_nop,
},
[AP_STATE_BORKED] = {
[AP_EVENT_TIMEOUT] = ap_sm_nop,
},
[AP_STATE_BORKED] = {
.resume = ap_dev_resume,
};
.resume = ap_dev_resume,
};
+void ap_device_init_reply(struct ap_device *ap_dev,
+ struct ap_message *reply)
+{
+ ap_dev->reply = reply;
+
+ spin_lock_bh(&ap_dev->lock);
+ ap_sm_wait(ap_sm_event(ap_dev, AP_EVENT_POLL));
+ spin_unlock_bh(&ap_dev->lock);
+}
+EXPORT_SYMBOL(ap_device_init_reply);
+
static int ap_device_probe(struct device *dev)
{
struct ap_device *ap_dev = to_ap_dev(dev);
static int ap_device_probe(struct device *dev)
{
struct ap_device *ap_dev = to_ap_dev(dev);
void ap_cancel_message(struct ap_device *ap_dev, struct ap_message *ap_msg);
void ap_flush_queue(struct ap_device *ap_dev);
void ap_bus_force_rescan(void);
void ap_cancel_message(struct ap_device *ap_dev, struct ap_message *ap_msg);
void ap_flush_queue(struct ap_device *ap_dev);
void ap_bus_force_rescan(void);
+void ap_device_init_reply(struct ap_device *ap_dev, struct ap_message *ap_msg);
int ap_module_init(void);
void ap_module_exit(void);
int ap_module_init(void);
void ap_module_exit(void);
MSGTYPE50_VARIANT_DEFAULT);
zdev->ap_dev = ap_dev;
zdev->online = 1;
MSGTYPE50_VARIANT_DEFAULT);
zdev->ap_dev = ap_dev;
zdev->online = 1;
- ap_dev->reply = &zdev->reply;
+ ap_device_init_reply(ap_dev, &zdev->reply);
ap_dev->private = zdev;
rc = zcrypt_device_register(zdev);
if (rc) {
ap_dev->private = zdev;
rc = zcrypt_device_register(zdev);
if (rc) {
return -ENODEV;
zdev->ap_dev = ap_dev;
zdev->online = 1;
return -ENODEV;
zdev->ap_dev = ap_dev;
zdev->online = 1;
- ap_dev->reply = &zdev->reply;
+ ap_device_init_reply(ap_dev, &zdev->reply);
ap_dev->private = zdev;
rc = zcrypt_device_register(zdev);
if (rc) {
ap_dev->private = zdev;
rc = zcrypt_device_register(zdev);
if (rc) {
else
zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME,
MSGTYPE06_VARIANT_NORNG);
else
zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME,
MSGTYPE06_VARIANT_NORNG);
- ap_dev->reply = &zdev->reply;
+ ap_device_init_reply(ap_dev, &zdev->reply);
ap_dev->private = zdev;
rc = zcrypt_device_register(zdev);
if (rc)
ap_dev->private = zdev;
rc = zcrypt_device_register(zdev);
if (rc)