]> git.karo-electronics.de Git - linux-beck.git/commitdiff
s390/zcrypt: add multi domain support
authorIngo Tuchscherer <ingo.tuchscherer@linux.vnet.ibm.com>
Thu, 25 Aug 2016 09:16:03 +0000 (11:16 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Wed, 14 Dec 2016 15:33:38 +0000 (16:33 +0100)
Currently the ap infrastructure only supports one domain at a time.
This feature extends the generic cryptographic device driver to
support multiple cryptographic domains simultaneously.

There are now card and queue devices on the AP bus with independent
card and queue drivers. The new /sys layout is as follows:

/sys/bus/ap
    devices
        <xx>.<yyyy> -> ../../../devices/ap/card<xx>/<xx>.<yyyy>
        ...
        card<xx> -> ../../../devices/ap/card<xx>
        ...
    drivers
        <drv>card
            card<xx> -> ../../../../devices/ap/card<xx>
        <drv>queue
            <xx>.<yyyy> -> ../../../../devices/ap/card<xx>/<xx>.<yyyy>
            ...

/sys/devices/ap
    card<xx>
        <xx>.<yyyy>
            driver -> ../../../../bus/ap/drivers/<zzz>queue
            ...
        driver -> ../../../bus/ap/drivers/<drv>card
        ...

The two digit <xx> field is the card number, the four digit <yyyy>
field is the queue number and <drv> is the name of the device driver,
e.g. "cex4".

For compatability /sys/bus/ap/card<xx> for the old layout has to exist,
including the attributes that used to reside there.

With additional contributions from Harald Freudenberger and
Martin Schwidefsky.

Signed-off-by: Ingo Tuchscherer <ingo.tuchscherer@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
17 files changed:
drivers/s390/crypto/Makefile
drivers/s390/crypto/ap_bus.c
drivers/s390/crypto/ap_bus.h
drivers/s390/crypto/ap_card.c [new file with mode: 0644]
drivers/s390/crypto/ap_queue.c [new file with mode: 0644]
drivers/s390/crypto/zcrypt_api.c
drivers/s390/crypto/zcrypt_api.h
drivers/s390/crypto/zcrypt_card.c [new file with mode: 0644]
drivers/s390/crypto/zcrypt_cex2a.c
drivers/s390/crypto/zcrypt_cex4.c
drivers/s390/crypto/zcrypt_error.h
drivers/s390/crypto/zcrypt_msgtype50.c
drivers/s390/crypto/zcrypt_msgtype6.c
drivers/s390/crypto/zcrypt_msgtype6.h
drivers/s390/crypto/zcrypt_pcixcc.c
drivers/s390/crypto/zcrypt_queue.c [new file with mode: 0644]
include/linux/mod_devicetable.h

index d0549fc8724786296874063b689db9dca5f7b3d0..0a7fb83f35e5b364381c22594cd31f89552ce676 100644 (file)
@@ -2,10 +2,11 @@
 # S/390 crypto devices
 #
 
-ap-objs := ap_bus.o
+ap-objs := ap_bus.o ap_card.o ap_queue.o
 obj-$(subst m,y,$(CONFIG_ZCRYPT)) += ap.o
 # zcrypt_api.o and zcrypt_msgtype*.o depend on ap.o
-zcrypt-objs := zcrypt_api.o zcrypt_msgtype6.o zcrypt_msgtype50.o
+zcrypt-objs := zcrypt_api.o zcrypt_card.o zcrypt_queue.o
+zcrypt-objs += zcrypt_msgtype6.o zcrypt_msgtype50.o
 obj-$(CONFIG_ZCRYPT) += zcrypt.o
 # adapter drivers depend on ap.o and zcrypt.o
 obj-$(CONFIG_ZCRYPT) += zcrypt_pcixcc.o zcrypt_cex2a.o zcrypt_cex4.o
index fe1cfa4b22c9469e8542130f62d71966df2fc5e1..ac6c258300cfbd92e8463c0066017b0c7c19d24a 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/ktime.h>
 #include <asm/facility.h>
 #include <linux/crypto.h>
+#include <linux/mod_devicetable.h>
 
 #include "ap_bus.h"
 #include "ap_asm.h"
@@ -72,10 +73,12 @@ static int ap_thread_flag = 0;
 module_param_named(poll_thread, ap_thread_flag, int, S_IRUSR|S_IRGRP);
 MODULE_PARM_DESC(poll_thread, "Turn on/off poll thread, default is 0 (off).");
 
-static struct device *ap_root_device = NULL;
+static struct device *ap_root_device;
+
+DEFINE_SPINLOCK(ap_list_lock);
+LIST_HEAD(ap_card_list);
+
 static struct ap_config_info *ap_configuration;
-static DEFINE_SPINLOCK(ap_device_list_lock);
-static LIST_HEAD(ap_device_list);
 static bool initialised;
 
 /*
@@ -129,6 +132,20 @@ static inline int ap_using_interrupts(void)
        return ap_airq_flag;
 }
 
+/**
+ * ap_airq_ptr() - Get the address of the adapter interrupt indicator
+ *
+ * Returns the address of the local-summary-indicator of the adapter
+ * interrupt handler for AP, or NULL if adapter interrupts are not
+ * available.
+ */
+void *ap_airq_ptr(void)
+{
+       if (ap_using_interrupts())
+               return ap_airq.lsi_ptr;
+       return NULL;
+}
+
 /**
  * ap_interrupts_available(): Test if AP interrupts are available.
  *
@@ -229,101 +246,6 @@ static inline int ap_test_config_domain(unsigned int domain)
        return ap_test_config(ap_configuration->aqm, domain);
 }
 
-/**
- * ap_queue_enable_interruption(): Enable interruption on an AP.
- * @qid: The AP queue number
- * @ind: the notification indicator byte
- *
- * Enables interruption on AP queue via ap_aqic(). Based on the return
- * value it waits a while and tests the AP queue if interrupts
- * have been switched on using ap_test_queue().
- */
-static int ap_queue_enable_interruption(struct ap_device *ap_dev, void *ind)
-{
-       struct ap_queue_status status;
-
-       status = ap_aqic(ap_dev->qid, ind);
-       switch (status.response_code) {
-       case AP_RESPONSE_NORMAL:
-       case AP_RESPONSE_OTHERWISE_CHANGED:
-               return 0;
-       case AP_RESPONSE_Q_NOT_AVAIL:
-       case AP_RESPONSE_DECONFIGURED:
-       case AP_RESPONSE_CHECKSTOPPED:
-       case AP_RESPONSE_INVALID_ADDRESS:
-               pr_err("Registering adapter interrupts for AP %d failed\n",
-                      AP_QID_DEVICE(ap_dev->qid));
-               return -EOPNOTSUPP;
-       case AP_RESPONSE_RESET_IN_PROGRESS:
-       case AP_RESPONSE_BUSY:
-       default:
-               return -EBUSY;
-       }
-}
-
-/**
- * __ap_send(): Send message to adjunct processor queue.
- * @qid: The AP queue number
- * @psmid: The program supplied message identifier
- * @msg: The message text
- * @length: The message length
- * @special: Special Bit
- *
- * Returns AP queue status structure.
- * Condition code 1 on NQAP can't happen because the L bit is 1.
- * Condition code 2 on NQAP also means the send is incomplete,
- * because a segment boundary was reached. The NQAP is repeated.
- */
-static inline struct ap_queue_status
-__ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length,
-         unsigned int special)
-{
-       if (special == 1)
-               qid |= 0x400000UL;
-       return ap_nqap(qid, psmid, msg, length);
-}
-
-int ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length)
-{
-       struct ap_queue_status status;
-
-       status = __ap_send(qid, psmid, msg, length, 0);
-       switch (status.response_code) {
-       case AP_RESPONSE_NORMAL:
-               return 0;
-       case AP_RESPONSE_Q_FULL:
-       case AP_RESPONSE_RESET_IN_PROGRESS:
-               return -EBUSY;
-       case AP_RESPONSE_REQ_FAC_NOT_INST:
-               return -EINVAL;
-       default:        /* Device is gone. */
-               return -ENODEV;
-       }
-}
-EXPORT_SYMBOL(ap_send);
-
-int ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length)
-{
-       struct ap_queue_status status;
-
-       if (msg == NULL)
-               return -EINVAL;
-       status = ap_dqap(qid, psmid, msg, length);
-       switch (status.response_code) {
-       case AP_RESPONSE_NORMAL:
-               return 0;
-       case AP_RESPONSE_NO_PENDING_REPLY:
-               if (status.queue_empty)
-                       return -ENOENT;
-               return -EBUSY;
-       case AP_RESPONSE_RESET_IN_PROGRESS:
-               return -EBUSY;
-       default:
-               return -ENODEV;
-       }
-}
-EXPORT_SYMBOL(ap_recv);
-
 /**
  * ap_query_queue(): Check if an AP queue is available.
  * @qid: The AP queue number
@@ -338,7 +260,7 @@ static int ap_query_queue(ap_qid_t qid, int *queue_depth, int *device_type,
        unsigned long info;
        int nd;
 
-       if (!ap_test_config_card_id(AP_QID_DEVICE(qid)))
+       if (!ap_test_config_card_id(AP_QID_CARD(qid)))
                return -ENODEV;
 
        status = ap_test_queue(qid, &info);
@@ -366,9 +288,7 @@ static int ap_query_queue(ap_qid_t qid, int *queue_depth, int *device_type,
        }
 }
 
-/* State machine definitions and helpers */
-
-static void ap_sm_wait(enum ap_wait wait)
+void ap_wait(enum ap_wait wait)
 {
        ktime_t hr_time;
 
@@ -397,347 +317,21 @@ static void ap_sm_wait(enum ap_wait wait)
        }
 }
 
-static enum ap_wait ap_sm_nop(struct ap_device *ap_dev)
-{
-       return AP_WAIT_NONE;
-}
-
-/**
- * ap_sm_recv(): Receive pending reply messages from an AP device but do
- *     not change the state of the device.
- * @ap_dev: pointer to the AP device
- *
- * Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT
- */
-static struct ap_queue_status ap_sm_recv(struct ap_device *ap_dev)
-{
-       struct ap_queue_status status;
-       struct ap_message *ap_msg;
-
-       status = ap_dqap(ap_dev->qid, &ap_dev->reply->psmid,
-                        ap_dev->reply->message, ap_dev->reply->length);
-       switch (status.response_code) {
-       case AP_RESPONSE_NORMAL:
-               ap_dev->queue_count--;
-               if (ap_dev->queue_count > 0)
-                       mod_timer(&ap_dev->timeout,
-                                 jiffies + ap_dev->drv->request_timeout);
-               list_for_each_entry(ap_msg, &ap_dev->pendingq, list) {
-                       if (ap_msg->psmid != ap_dev->reply->psmid)
-                               continue;
-                       list_del_init(&ap_msg->list);
-                       ap_dev->pendingq_count--;
-                       ap_msg->receive(ap_dev, ap_msg, ap_dev->reply);
-                       break;
-               }
-       case AP_RESPONSE_NO_PENDING_REPLY:
-               if (!status.queue_empty || ap_dev->queue_count <= 0)
-                       break;
-               /* The card shouldn't forget requests but who knows. */
-               ap_dev->queue_count = 0;
-               list_splice_init(&ap_dev->pendingq, &ap_dev->requestq);
-               ap_dev->requestq_count += ap_dev->pendingq_count;
-               ap_dev->pendingq_count = 0;
-               break;
-       default:
-               break;
-       }
-       return status;
-}
-
-/**
- * ap_sm_read(): Receive pending reply messages from an AP device.
- * @ap_dev: pointer to the AP device
- *
- * Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT
- */
-static enum ap_wait ap_sm_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) {
-                       ap_dev->state = AP_STATE_WORKING;
-                       return AP_WAIT_AGAIN;
-               }
-               ap_dev->state = AP_STATE_IDLE;
-               return AP_WAIT_NONE;
-       case AP_RESPONSE_NO_PENDING_REPLY:
-               if (ap_dev->queue_count > 0)
-                       return AP_WAIT_INTERRUPT;
-               ap_dev->state = AP_STATE_IDLE;
-               return AP_WAIT_NONE;
-       default:
-               ap_dev->state = AP_STATE_BORKED;
-               return AP_WAIT_NONE;
-       }
-}
-
-/**
- * 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
- *
- * Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT
- */
-static enum ap_wait ap_sm_write(struct ap_device *ap_dev)
-{
-       struct ap_queue_status status;
-       struct ap_message *ap_msg;
-
-       if (ap_dev->requestq_count <= 0)
-               return AP_WAIT_NONE;
-       /* Start the next request on the queue. */
-       ap_msg = list_entry(ap_dev->requestq.next, struct ap_message, list);
-       status = __ap_send(ap_dev->qid, ap_msg->psmid,
-                          ap_msg->message, ap_msg->length, ap_msg->special);
-       switch (status.response_code) {
-       case AP_RESPONSE_NORMAL:
-               ap_dev->queue_count++;
-               if (ap_dev->queue_count == 1)
-                       mod_timer(&ap_dev->timeout,
-                                 jiffies + ap_dev->drv->request_timeout);
-               list_move_tail(&ap_msg->list, &ap_dev->pendingq);
-               ap_dev->requestq_count--;
-               ap_dev->pendingq_count++;
-               if (ap_dev->queue_count < ap_dev->queue_depth) {
-                       ap_dev->state = AP_STATE_WORKING;
-                       return AP_WAIT_AGAIN;
-               }
-               /* fall through */
-       case AP_RESPONSE_Q_FULL:
-               ap_dev->state = AP_STATE_QUEUE_FULL;
-               return AP_WAIT_INTERRUPT;
-       case AP_RESPONSE_RESET_IN_PROGRESS:
-               ap_dev->state = AP_STATE_RESET_WAIT;
-               return AP_WAIT_TIMEOUT;
-       case AP_RESPONSE_MESSAGE_TOO_BIG:
-       case AP_RESPONSE_REQ_FAC_NOT_INST:
-               list_del_init(&ap_msg->list);
-               ap_dev->requestq_count--;
-               ap_msg->rc = -EINVAL;
-               ap_msg->receive(ap_dev, ap_msg, NULL);
-               return AP_WAIT_AGAIN;
-       default:
-               ap_dev->state = AP_STATE_BORKED;
-               return AP_WAIT_NONE;
-       }
-}
-
-/**
- * ap_sm_read_write(): Send and receive messages to/from an AP device.
- * @ap_dev: pointer to the AP device
- *
- * Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT
- */
-static enum ap_wait ap_sm_read_write(struct ap_device *ap_dev)
-{
-       return min(ap_sm_read(ap_dev), ap_sm_write(ap_dev));
-}
-
-/**
- * ap_sm_reset(): Reset an AP queue.
- * @qid: The AP queue number
- *
- * Submit the Reset command to an AP queue.
- */
-static enum ap_wait ap_sm_reset(struct ap_device *ap_dev)
-{
-       struct ap_queue_status status;
-
-       status = ap_rapq(ap_dev->qid);
-       switch (status.response_code) {
-       case AP_RESPONSE_NORMAL:
-       case AP_RESPONSE_RESET_IN_PROGRESS:
-               ap_dev->state = AP_STATE_RESET_WAIT;
-               ap_dev->interrupt = AP_INTR_DISABLED;
-               return AP_WAIT_TIMEOUT;
-       case AP_RESPONSE_BUSY:
-               return AP_WAIT_TIMEOUT;
-       case AP_RESPONSE_Q_NOT_AVAIL:
-       case AP_RESPONSE_DECONFIGURED:
-       case AP_RESPONSE_CHECKSTOPPED:
-       default:
-               ap_dev->state = AP_STATE_BORKED;
-               return AP_WAIT_NONE;
-       }
-}
-
-/**
- * ap_sm_reset_wait(): Test queue for completion of the reset operation
- * @ap_dev: pointer to the AP device
- *
- * Returns AP_POLL_IMMEDIATELY, AP_POLL_AFTER_TIMEROUT or 0.
- */
-static enum ap_wait ap_sm_reset_wait(struct ap_device *ap_dev)
-{
-       struct ap_queue_status status;
-       unsigned long info;
-
-       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
-               /* Get the status with TAPQ */
-               status = ap_test_queue(ap_dev->qid, &info);
-
-       switch (status.response_code) {
-       case AP_RESPONSE_NORMAL:
-               if (ap_using_interrupts() &&
-                   ap_queue_enable_interruption(ap_dev,
-                                                ap_airq.lsi_ptr) == 0)
-                       ap_dev->state = AP_STATE_SETIRQ_WAIT;
-               else
-                       ap_dev->state = (ap_dev->queue_count > 0) ?
-                               AP_STATE_WORKING : AP_STATE_IDLE;
-               return AP_WAIT_AGAIN;
-       case AP_RESPONSE_BUSY:
-       case AP_RESPONSE_RESET_IN_PROGRESS:
-               return AP_WAIT_TIMEOUT;
-       case AP_RESPONSE_Q_NOT_AVAIL:
-       case AP_RESPONSE_DECONFIGURED:
-       case AP_RESPONSE_CHECKSTOPPED:
-       default:
-               ap_dev->state = AP_STATE_BORKED;
-               return AP_WAIT_NONE;
-       }
-}
-
-/**
- * ap_sm_setirq_wait(): Test queue for completion of the irq enablement
- * @ap_dev: pointer to the AP device
- *
- * Returns AP_POLL_IMMEDIATELY, AP_POLL_AFTER_TIMEROUT or 0.
- */
-static enum ap_wait ap_sm_setirq_wait(struct ap_device *ap_dev)
-{
-       struct ap_queue_status status;
-       unsigned long info;
-
-       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
-               /* Get the status with TAPQ */
-               status = ap_test_queue(ap_dev->qid, &info);
-
-       if (status.int_enabled == 1) {
-               /* Irqs are now enabled */
-               ap_dev->interrupt = AP_INTR_ENABLED;
-               ap_dev->state = (ap_dev->queue_count > 0) ?
-                       AP_STATE_WORKING : AP_STATE_IDLE;
-       }
-
-       switch (status.response_code) {
-       case AP_RESPONSE_NORMAL:
-               if (ap_dev->queue_count > 0)
-                       return AP_WAIT_AGAIN;
-               /* fallthrough */
-       case AP_RESPONSE_NO_PENDING_REPLY:
-               return AP_WAIT_TIMEOUT;
-       default:
-               ap_dev->state = AP_STATE_BORKED;
-               return AP_WAIT_NONE;
-       }
-}
-
-/*
- * AP state machine jump table
- */
-static ap_func_t *ap_jumptable[NR_AP_STATES][NR_AP_EVENTS] = {
-       [AP_STATE_RESET_START] = {
-               [AP_EVENT_POLL] = ap_sm_reset,
-               [AP_EVENT_TIMEOUT] = ap_sm_nop,
-       },
-       [AP_STATE_RESET_WAIT] = {
-               [AP_EVENT_POLL] = ap_sm_reset_wait,
-               [AP_EVENT_TIMEOUT] = ap_sm_nop,
-       },
-       [AP_STATE_SETIRQ_WAIT] = {
-               [AP_EVENT_POLL] = ap_sm_setirq_wait,
-               [AP_EVENT_TIMEOUT] = ap_sm_nop,
-       },
-       [AP_STATE_IDLE] = {
-               [AP_EVENT_POLL] = ap_sm_write,
-               [AP_EVENT_TIMEOUT] = ap_sm_nop,
-       },
-       [AP_STATE_WORKING] = {
-               [AP_EVENT_POLL] = ap_sm_read_write,
-               [AP_EVENT_TIMEOUT] = ap_sm_reset,
-       },
-       [AP_STATE_QUEUE_FULL] = {
-               [AP_EVENT_POLL] = ap_sm_read,
-               [AP_EVENT_TIMEOUT] = ap_sm_reset,
-       },
-       [AP_STATE_SUSPEND_WAIT] = {
-               [AP_EVENT_POLL] = ap_sm_suspend_read,
-               [AP_EVENT_TIMEOUT] = ap_sm_nop,
-       },
-       [AP_STATE_BORKED] = {
-               [AP_EVENT_POLL] = ap_sm_nop,
-               [AP_EVENT_TIMEOUT] = ap_sm_nop,
-       },
-};
-
-static inline enum ap_wait ap_sm_event(struct ap_device *ap_dev,
-                                      enum ap_event event)
-{
-       return ap_jumptable[ap_dev->state][event](ap_dev);
-}
-
-static inline enum ap_wait ap_sm_event_loop(struct ap_device *ap_dev,
-                                           enum ap_event event)
-{
-       enum ap_wait wait;
-
-       while ((wait = ap_sm_event(ap_dev, event)) == AP_WAIT_AGAIN)
-               ;
-       return wait;
-}
-
 /**
  * ap_request_timeout(): Handling of request timeouts
  * @data: Holds the AP device.
  *
  * Handles request timeouts.
  */
-static void ap_request_timeout(unsigned long data)
+void ap_request_timeout(unsigned long data)
 {
-       struct ap_device *ap_dev = (struct ap_device *) data;
+       struct ap_queue *aq = (struct ap_queue *) data;
 
        if (ap_suspend_flag)
                return;
-       spin_lock_bh(&ap_dev->lock);
-       ap_sm_wait(ap_sm_event(ap_dev, AP_EVENT_TIMEOUT));
-       spin_unlock_bh(&ap_dev->lock);
+       spin_lock_bh(&aq->lock);
+       ap_wait(ap_sm_event(aq, AP_EVENT_TIMEOUT));
+       spin_unlock_bh(&aq->lock);
 }
 
 /**
@@ -772,7 +366,8 @@ static void ap_interrupt_handler(struct airq_struct *airq)
  */
 static void ap_tasklet_fn(unsigned long dummy)
 {
-       struct ap_device *ap_dev;
+       struct ap_card *ac;
+       struct ap_queue *aq;
        enum ap_wait wait = AP_WAIT_NONE;
 
        /* Reset the indicator if interrupts are used. Thus new interrupts can
@@ -782,35 +377,35 @@ static void ap_tasklet_fn(unsigned long dummy)
        if (ap_using_interrupts())
                xchg(ap_airq.lsi_ptr, 0);
 
-       spin_lock(&ap_device_list_lock);
-       list_for_each_entry(ap_dev, &ap_device_list, list) {
-               spin_lock_bh(&ap_dev->lock);
-               wait = min(wait, ap_sm_event_loop(ap_dev, AP_EVENT_POLL));
-               spin_unlock_bh(&ap_dev->lock);
+       spin_lock_bh(&ap_list_lock);
+       for_each_ap_card(ac) {
+               for_each_ap_queue(aq, ac) {
+                       spin_lock_bh(&aq->lock);
+                       wait = min(wait, ap_sm_event_loop(aq, AP_EVENT_POLL));
+                       spin_unlock_bh(&aq->lock);
+               }
        }
-       spin_unlock(&ap_device_list_lock);
-       ap_sm_wait(wait);
+       spin_unlock_bh(&ap_list_lock);
+
+       ap_wait(wait);
 }
 
 static int ap_pending_requests(void)
 {
-       struct ap_device *ap_dev;
-       int id, pending = 0;
-
-       for (id = 0; pending == 0 && id < AP_DEVICES; id++) {
-               spin_lock_bh(&ap_device_list_lock);
-               list_for_each_entry(ap_dev, &ap_device_list, list) {
-                       spin_lock_bh(&ap_dev->lock);
-                       if (ap_dev->queue_count)
-                               pending = 1;
-                       spin_unlock_bh(&ap_dev->lock);
-                       if (pending)
-                               break;
+       struct ap_card *ac;
+       struct ap_queue *aq;
+
+       spin_lock_bh(&ap_list_lock);
+       for_each_ap_card(ac) {
+               for_each_ap_queue(aq, ac) {
+                       if (aq->queue_count == 0)
+                               continue;
+                       spin_unlock_bh(&ap_list_lock);
+                       return 1;
                }
-               spin_unlock_bh(&ap_device_list_lock);
        }
-
-       return pending;
+       spin_unlock_bh(&ap_list_lock);
+       return 0;
 }
 
 /**
@@ -874,207 +469,8 @@ static void ap_poll_thread_stop(void)
        mutex_unlock(&ap_poll_thread_mutex);
 }
 
-/**
- * ap_queue_message(): Queue a request to an AP device.
- * @ap_dev: The AP device to queue the message to
- * @ap_msg: The message that is to be added
- */
-void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg)
-{
-       /* For asynchronous message handling a valid receive-callback
-        * is required. */
-       BUG_ON(!ap_msg->receive);
-
-       spin_lock_bh(&ap_dev->lock);
-       /* Queue the message. */
-       list_add_tail(&ap_msg->list, &ap_dev->requestq);
-       ap_dev->requestq_count++;
-       ap_dev->total_request_count++;
-       /* Send/receive as many request from the queue as possible. */
-       ap_sm_wait(ap_sm_event_loop(ap_dev, AP_EVENT_POLL));
-       spin_unlock_bh(&ap_dev->lock);
-}
-EXPORT_SYMBOL(ap_queue_message);
-
-/**
- * ap_cancel_message(): Cancel a crypto request.
- * @ap_dev: The AP device that has the message queued
- * @ap_msg: The message that is to be removed
- *
- * Cancel a crypto request. This is done by removing the request
- * from the device pending or request queue. Note that the
- * request stays on the AP queue. When it finishes the message
- * reply will be discarded because the psmid can't be found.
- */
-void ap_cancel_message(struct ap_device *ap_dev, struct ap_message *ap_msg)
-{
-       struct ap_message *tmp;
-
-       spin_lock_bh(&ap_dev->lock);
-       if (!list_empty(&ap_msg->list)) {
-               list_for_each_entry(tmp, &ap_dev->pendingq, list)
-                       if (tmp->psmid == ap_msg->psmid) {
-                               ap_dev->pendingq_count--;
-                               goto found;
-                       }
-               ap_dev->requestq_count--;
-found:
-               list_del_init(&ap_msg->list);
-       }
-       spin_unlock_bh(&ap_dev->lock);
-}
-EXPORT_SYMBOL(ap_cancel_message);
-
-/*
- * AP device related attributes.
- */
-static ssize_t ap_hwtype_show(struct device *dev,
-                             struct device_attribute *attr, char *buf)
-{
-       struct ap_device *ap_dev = to_ap_dev(dev);
-       return snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->device_type);
-}
-
-static DEVICE_ATTR(hwtype, 0444, ap_hwtype_show, NULL);
-
-static ssize_t ap_raw_hwtype_show(struct device *dev,
-                             struct device_attribute *attr, char *buf)
-{
-       struct ap_device *ap_dev = to_ap_dev(dev);
-
-       return snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->raw_hwtype);
-}
-
-static DEVICE_ATTR(raw_hwtype, 0444, ap_raw_hwtype_show, NULL);
-
-static ssize_t ap_depth_show(struct device *dev, struct device_attribute *attr,
-                            char *buf)
-{
-       struct ap_device *ap_dev = to_ap_dev(dev);
-       return snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->queue_depth);
-}
-
-static DEVICE_ATTR(depth, 0444, ap_depth_show, NULL);
-static ssize_t ap_request_count_show(struct device *dev,
-                                    struct device_attribute *attr,
-                                    char *buf)
-{
-       struct ap_device *ap_dev = to_ap_dev(dev);
-       int rc;
-
-       spin_lock_bh(&ap_dev->lock);
-       rc = snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->total_request_count);
-       spin_unlock_bh(&ap_dev->lock);
-       return rc;
-}
-
-static DEVICE_ATTR(request_count, 0444, ap_request_count_show, NULL);
-
-static ssize_t ap_requestq_count_show(struct device *dev,
-                                     struct device_attribute *attr, char *buf)
-{
-       struct ap_device *ap_dev = to_ap_dev(dev);
-       int rc;
-
-       spin_lock_bh(&ap_dev->lock);
-       rc = snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->requestq_count);
-       spin_unlock_bh(&ap_dev->lock);
-       return rc;
-}
-
-static DEVICE_ATTR(requestq_count, 0444, ap_requestq_count_show, NULL);
-
-static ssize_t ap_pendingq_count_show(struct device *dev,
-                                     struct device_attribute *attr, char *buf)
-{
-       struct ap_device *ap_dev = to_ap_dev(dev);
-       int rc;
-
-       spin_lock_bh(&ap_dev->lock);
-       rc = snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->pendingq_count);
-       spin_unlock_bh(&ap_dev->lock);
-       return rc;
-}
-
-static DEVICE_ATTR(pendingq_count, 0444, ap_pendingq_count_show, NULL);
-
-static ssize_t ap_reset_show(struct device *dev,
-                                     struct device_attribute *attr, char *buf)
-{
-       struct ap_device *ap_dev = to_ap_dev(dev);
-       int rc = 0;
-
-       spin_lock_bh(&ap_dev->lock);
-       switch (ap_dev->state) {
-       case AP_STATE_RESET_START:
-       case AP_STATE_RESET_WAIT:
-               rc = snprintf(buf, PAGE_SIZE, "Reset in progress.\n");
-               break;
-       case AP_STATE_WORKING:
-       case AP_STATE_QUEUE_FULL:
-               rc = snprintf(buf, PAGE_SIZE, "Reset Timer armed.\n");
-               break;
-       default:
-               rc = snprintf(buf, PAGE_SIZE, "No Reset Timer set.\n");
-       }
-       spin_unlock_bh(&ap_dev->lock);
-       return rc;
-}
-
-static DEVICE_ATTR(reset, 0444, ap_reset_show, NULL);
-
-static ssize_t ap_interrupt_show(struct device *dev,
-                                     struct device_attribute *attr, char *buf)
-{
-       struct ap_device *ap_dev = to_ap_dev(dev);
-       int rc = 0;
-
-       spin_lock_bh(&ap_dev->lock);
-       if (ap_dev->state == AP_STATE_SETIRQ_WAIT)
-               rc = snprintf(buf, PAGE_SIZE, "Enable Interrupt pending.\n");
-       else if (ap_dev->interrupt == AP_INTR_ENABLED)
-               rc = snprintf(buf, PAGE_SIZE, "Interrupts enabled.\n");
-       else
-               rc = snprintf(buf, PAGE_SIZE, "Interrupts disabled.\n");
-       spin_unlock_bh(&ap_dev->lock);
-       return rc;
-}
-
-static DEVICE_ATTR(interrupt, 0444, ap_interrupt_show, NULL);
-
-static ssize_t ap_modalias_show(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       return sprintf(buf, "ap:t%02X\n", to_ap_dev(dev)->device_type);
-}
-
-static DEVICE_ATTR(modalias, 0444, ap_modalias_show, NULL);
-
-static ssize_t ap_functions_show(struct device *dev,
-                                struct device_attribute *attr, char *buf)
-{
-       struct ap_device *ap_dev = to_ap_dev(dev);
-       return snprintf(buf, PAGE_SIZE, "0x%08X\n", ap_dev->functions);
-}
-
-static DEVICE_ATTR(ap_functions, 0444, ap_functions_show, NULL);
-
-static struct attribute *ap_dev_attrs[] = {
-       &dev_attr_hwtype.attr,
-       &dev_attr_raw_hwtype.attr,
-       &dev_attr_depth.attr,
-       &dev_attr_request_count.attr,
-       &dev_attr_requestq_count.attr,
-       &dev_attr_pendingq_count.attr,
-       &dev_attr_reset.attr,
-       &dev_attr_interrupt.attr,
-       &dev_attr_modalias.attr,
-       &dev_attr_ap_functions.attr,
-       NULL
-};
-static struct attribute_group ap_dev_attr_group = {
-       .attrs = ap_dev_attrs
-};
+#define is_card_dev(x) ((x)->parent == ap_root_device)
+#define is_queue_dev(x) ((x)->parent != ap_root_device)
 
 /**
  * ap_bus_match()
@@ -1085,7 +481,6 @@ static struct attribute_group ap_dev_attr_group = {
  */
 static int ap_bus_match(struct device *dev, struct device_driver *drv)
 {
-       struct ap_device *ap_dev = to_ap_dev(dev);
        struct ap_driver *ap_drv = to_ap_drv(drv);
        struct ap_device_id *id;
 
@@ -1094,10 +489,14 @@ static int ap_bus_match(struct device *dev, struct device_driver *drv)
         * supported types of the device_driver.
         */
        for (id = ap_drv->ids; id->match_flags; id++) {
-               if ((id->match_flags & AP_DEVICE_ID_MATCH_DEVICE_TYPE) &&
-                   (id->dev_type != ap_dev->device_type))
-                       continue;
-               return 1;
+               if (is_card_dev(dev) &&
+                   id->match_flags & AP_DEVICE_ID_MATCH_CARD_TYPE &&
+                   id->dev_type == to_ap_dev(dev)->device_type)
+                       return 1;
+               if (is_queue_dev(dev) &&
+                   id->match_flags & AP_DEVICE_ID_MATCH_QUEUE_TYPE &&
+                   id->dev_type == to_ap_dev(dev)->device_type)
+                       return 1;
        }
        return 0;
 }
@@ -1133,13 +532,17 @@ static int ap_dev_suspend(struct device *dev)
 {
        struct ap_device *ap_dev = to_ap_dev(dev);
 
-       /* Poll on the device until all requests are finished. */
-       spin_lock_bh(&ap_dev->lock);
-       ap_dev->state = AP_STATE_SUSPEND_WAIT;
-       while (ap_sm_event(ap_dev, AP_EVENT_POLL) != AP_WAIT_NONE)
-               ;
-       ap_dev->state = AP_STATE_BORKED;
-       spin_unlock_bh(&ap_dev->lock);
+       if (ap_dev->drv && ap_dev->drv->suspend)
+               ap_dev->drv->suspend(ap_dev);
+       return 0;
+}
+
+static int ap_dev_resume(struct device *dev)
+{
+       struct ap_device *ap_dev = to_ap_dev(dev);
+
+       if (ap_dev->drv && ap_dev->drv->resume)
+               ap_dev->drv->resume(ap_dev);
        return 0;
 }
 
@@ -1154,9 +557,25 @@ static void ap_bus_suspend(void)
        tasklet_disable(&ap_tasklet);
 }
 
-static int __ap_devices_unregister(struct device *dev, void *dummy)
+static int __ap_card_devices_unregister(struct device *dev, void *dummy)
+{
+       if (is_card_dev(dev))
+               device_unregister(dev);
+       return 0;
+}
+
+static int __ap_queue_devices_unregister(struct device *dev, void *dummy)
+{
+       if (is_queue_dev(dev))
+               device_unregister(dev);
+       return 0;
+}
+
+static int __ap_queue_devices_with_id_unregister(struct device *dev, void *data)
 {
-       device_unregister(dev);
+       if (is_queue_dev(dev) &&
+           AP_QID_CARD(to_ap_queue(dev)->qid) == (int)(long) data)
+               device_unregister(dev);
        return 0;
 }
 
@@ -1164,8 +583,13 @@ static void ap_bus_resume(void)
 {
        int rc;
 
-       /* Unconditionally remove all AP devices */
-       bus_for_each_dev(&ap_bus_type, NULL, NULL, __ap_devices_unregister);
+       /* remove all queue devices */
+       bus_for_each_dev(&ap_bus_type, NULL, NULL,
+                        __ap_queue_devices_unregister);
+       /* remove all card devices */
+       bus_for_each_dev(&ap_bus_type, NULL, NULL,
+                        __ap_card_devices_unregister);
+
        /* Reset thin interrupt setting */
        if (ap_interrupts_available() && !ap_using_interrupts()) {
                rc = register_adapter_interrupt(&ap_airq);
@@ -1207,7 +631,7 @@ static struct notifier_block ap_power_notifier = {
        .notifier_call = ap_power_event,
 };
 
-static SIMPLE_DEV_PM_OPS(ap_bus_pm_ops, ap_dev_suspend, NULL);
+static SIMPLE_DEV_PM_OPS(ap_bus_pm_ops, ap_dev_suspend, ap_dev_resume);
 
 static struct bus_type ap_bus_type = {
        .name = "ap",
@@ -1216,17 +640,6 @@ static struct bus_type ap_bus_type = {
        .pm = &ap_bus_pm_ops,
 };
 
-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);
@@ -1240,58 +653,22 @@ static int ap_device_probe(struct device *dev)
        return rc;
 }
 
-/**
- * __ap_flush_queue(): Flush requests.
- * @ap_dev: Pointer to the AP device
- *
- * Flush all requests from the request/pending queue of an AP device.
- */
-static void __ap_flush_queue(struct ap_device *ap_dev)
-{
-       struct ap_message *ap_msg, *next;
-
-       list_for_each_entry_safe(ap_msg, next, &ap_dev->pendingq, list) {
-               list_del_init(&ap_msg->list);
-               ap_dev->pendingq_count--;
-               ap_msg->rc = -EAGAIN;
-               ap_msg->receive(ap_dev, ap_msg, NULL);
-       }
-       list_for_each_entry_safe(ap_msg, next, &ap_dev->requestq, list) {
-               list_del_init(&ap_msg->list);
-               ap_dev->requestq_count--;
-               ap_msg->rc = -EAGAIN;
-               ap_msg->receive(ap_dev, ap_msg, NULL);
-       }
-}
-
-void ap_flush_queue(struct ap_device *ap_dev)
-{
-       spin_lock_bh(&ap_dev->lock);
-       __ap_flush_queue(ap_dev);
-       spin_unlock_bh(&ap_dev->lock);
-}
-EXPORT_SYMBOL(ap_flush_queue);
-
 static int ap_device_remove(struct device *dev)
 {
        struct ap_device *ap_dev = to_ap_dev(dev);
        struct ap_driver *ap_drv = ap_dev->drv;
 
-       ap_flush_queue(ap_dev);
-       del_timer_sync(&ap_dev->timeout);
-       spin_lock_bh(&ap_device_list_lock);
-       list_del_init(&ap_dev->list);
-       spin_unlock_bh(&ap_device_list_lock);
+       spin_lock_bh(&ap_list_lock);
+       if (is_card_dev(dev))
+               list_del_init(&to_ap_card(dev)->list);
+       else
+               list_del_init(&to_ap_queue(dev)->list);
+       spin_unlock_bh(&ap_list_lock);
        if (ap_drv->remove)
                ap_drv->remove(ap_dev);
        return 0;
 }
 
-static void ap_device_release(struct device *dev)
-{
-       kfree(to_ap_dev(dev));
-}
-
 int ap_driver_register(struct ap_driver *ap_drv, struct module *owner,
                       char *name)
 {
@@ -1354,12 +731,7 @@ static ssize_t ap_control_domain_mask_show(struct bus_type *bus, char *buf)
 {
        if (!ap_configuration)  /* QCI not supported */
                return snprintf(buf, PAGE_SIZE, "not supported\n");
-       if (!test_facility(76))
-               /* format 0 - 16 bit domain field */
-               return snprintf(buf, PAGE_SIZE, "%08x%08x\n",
-                               ap_configuration->adm[0],
-                               ap_configuration->adm[1]);
-       /* format 1 - 256 bit domain field */
+
        return snprintf(buf, PAGE_SIZE,
                        "0x%08x%08x%08x%08x%08x%08x%08x%08x\n",
                        ap_configuration->adm[0], ap_configuration->adm[1],
@@ -1371,6 +743,22 @@ static ssize_t ap_control_domain_mask_show(struct bus_type *bus, char *buf)
 static BUS_ATTR(ap_control_domain_mask, 0444,
                ap_control_domain_mask_show, NULL);
 
+static ssize_t ap_usage_domain_mask_show(struct bus_type *bus, char *buf)
+{
+       if (!ap_configuration)  /* QCI not supported */
+               return snprintf(buf, PAGE_SIZE, "not supported\n");
+
+       return snprintf(buf, PAGE_SIZE,
+                       "0x%08x%08x%08x%08x%08x%08x%08x%08x\n",
+                       ap_configuration->aqm[0], ap_configuration->aqm[1],
+                       ap_configuration->aqm[2], ap_configuration->aqm[3],
+                       ap_configuration->aqm[4], ap_configuration->aqm[5],
+                       ap_configuration->aqm[6], ap_configuration->aqm[7]);
+}
+
+static BUS_ATTR(ap_usage_domain_mask, 0444,
+               ap_usage_domain_mask_show, NULL);
+
 static ssize_t ap_config_time_show(struct bus_type *bus, char *buf)
 {
        return snprintf(buf, PAGE_SIZE, "%d\n", ap_config_time);
@@ -1466,6 +854,7 @@ static BUS_ATTR(ap_max_domain_id, 0444, ap_max_domain_id_show, NULL);
 static struct bus_attribute *const ap_bus_attrs[] = {
        &bus_attr_ap_domain,
        &bus_attr_ap_control_domain_mask,
+       &bus_attr_ap_usage_domain_mask,
        &bus_attr_config_time,
        &bus_attr_poll_thread,
        &bus_attr_ap_interrupts,
@@ -1524,110 +913,162 @@ static int ap_select_domain(void)
        return -ENODEV;
 }
 
-/**
- * __ap_scan_bus(): Scan the AP bus.
- * @dev: Pointer to device
- * @data: Pointer to data
- *
- * Scan the AP bus for new devices.
+/*
+ * helper function to be used with bus_find_dev
+ * matches for the card device with the given id
  */
-static int __ap_scan_bus(struct device *dev, void *data)
+static int __match_card_device_with_id(struct device *dev, void *data)
 {
-       return to_ap_dev(dev)->qid == (ap_qid_t)(unsigned long) data;
+       return is_card_dev(dev) && to_ap_card(dev)->id == (int)(long) data;
 }
 
+/* helper function to be used with bus_find_dev
+ * matches for the queue device with a given qid
+ */
+static int __match_queue_device_with_qid(struct device *dev, void *data)
+{
+       return is_queue_dev(dev) && to_ap_queue(dev)->qid == (int)(long) data;
+}
+
+/**
+ * ap_scan_bus(): Scan the AP bus for new devices
+ * Runs periodically, workqueue timer (ap_config_time)
+ */
 static void ap_scan_bus(struct work_struct *unused)
 {
-       struct ap_device *ap_dev;
+       struct ap_queue *aq;
+       struct ap_card *ac;
        struct device *dev;
        ap_qid_t qid;
-       int queue_depth = 0, device_type = 0;
-       unsigned int device_functions = 0;
-       int rc, i, borked;
+       int depth = 0, type = 0;
+       unsigned int functions = 0;
+       int rc, id, dom, borked, domains;
 
        ap_query_configuration();
        if (ap_select_domain() != 0)
                goto out;
 
-
-       spin_lock_bh(&ap_domain_lock);
-       for (i = 0; i < AP_DEVICES; i++) {
-               qid = AP_MKQID(i, ap_domain_index);
+       for (id = 0; id < AP_DEVICES; id++) {
+               /* check if device is registered */
                dev = bus_find_device(&ap_bus_type, NULL,
-                                     (void *)(unsigned long)qid,
-                                     __ap_scan_bus);
-               rc = ap_query_queue(qid, &queue_depth, &device_type,
-                                   &device_functions);
-               if (dev) {
-                       ap_dev = to_ap_dev(dev);
-                       spin_lock_bh(&ap_dev->lock);
-                       if (rc == -ENODEV)
-                               ap_dev->state = AP_STATE_BORKED;
-                       borked = ap_dev->state == AP_STATE_BORKED;
-                       spin_unlock_bh(&ap_dev->lock);
-                       if (borked)     /* Remove broken device */
+                                     (void *)(long) id,
+                                     __match_card_device_with_id);
+               ac = dev ? to_ap_card(dev) : NULL;
+               if (!ap_test_config_card_id(id)) {
+                       if (dev) {
+                               /* Card device has been removed from
+                                * configuration, remove the belonging
+                                * queue devices.
+                                */
+                               bus_for_each_dev(&ap_bus_type, NULL,
+                                       (void *)(long) id,
+                                       __ap_queue_devices_with_id_unregister);
+                               /* now remove the card device */
                                device_unregister(dev);
-                       put_device(dev);
-                       if (!borked)
-                               continue;
-               }
-               if (rc)
-                       continue;
-               ap_dev = kzalloc(sizeof(*ap_dev), GFP_KERNEL);
-               if (!ap_dev)
-                       break;
-               ap_dev->qid = qid;
-               ap_dev->state = AP_STATE_RESET_START;
-               ap_dev->interrupt = AP_INTR_DISABLED;
-               ap_dev->queue_depth = queue_depth;
-               ap_dev->raw_hwtype = device_type;
-               ap_dev->device_type = device_type;
-               /* CEX6 toleration: map to CEX5 */
-               if (device_type == AP_DEVICE_TYPE_CEX6)
-                       ap_dev->device_type = AP_DEVICE_TYPE_CEX5;
-               ap_dev->functions = device_functions;
-               spin_lock_init(&ap_dev->lock);
-               INIT_LIST_HEAD(&ap_dev->pendingq);
-               INIT_LIST_HEAD(&ap_dev->requestq);
-               INIT_LIST_HEAD(&ap_dev->list);
-               setup_timer(&ap_dev->timeout, ap_request_timeout,
-                           (unsigned long) ap_dev);
-
-               ap_dev->device.bus = &ap_bus_type;
-               ap_dev->device.parent = ap_root_device;
-               rc = dev_set_name(&ap_dev->device, "card%02x",
-                                 AP_QID_DEVICE(ap_dev->qid));
-               if (rc) {
-                       kfree(ap_dev);
-                       continue;
-               }
-               /* Add to list of devices */
-               spin_lock_bh(&ap_device_list_lock);
-               list_add(&ap_dev->list, &ap_device_list);
-               spin_unlock_bh(&ap_device_list_lock);
-               /* Start with a device reset */
-               spin_lock_bh(&ap_dev->lock);
-               ap_sm_wait(ap_sm_event(ap_dev, AP_EVENT_POLL));
-               spin_unlock_bh(&ap_dev->lock);
-               /* Register device */
-               ap_dev->device.release = ap_device_release;
-               rc = device_register(&ap_dev->device);
-               if (rc) {
-                       spin_lock_bh(&ap_dev->lock);
-                       list_del_init(&ap_dev->list);
-                       spin_unlock_bh(&ap_dev->lock);
-                       put_device(&ap_dev->device);
+                               put_device(dev);
+                       }
                        continue;
                }
-               /* Add device attributes. */
-               rc = sysfs_create_group(&ap_dev->device.kobj,
-                                       &ap_dev_attr_group);
-               if (rc) {
-                       device_unregister(&ap_dev->device);
-                       continue;
+               /* According to the configuration there should be a card
+                * device, so check if there is at least one valid queue
+                * and maybe create queue devices and the card device.
+                */
+               domains = 0;
+               for (dom = 0; dom < AP_DOMAINS; dom++) {
+                       qid = AP_MKQID(id, dom);
+                       dev = bus_find_device(&ap_bus_type, NULL,
+                                             (void *)(long) qid,
+                                             __match_queue_device_with_qid);
+                       aq = dev ? to_ap_queue(dev) : NULL;
+                       if (!ap_test_config_domain(dom)) {
+                               if (dev) {
+                                       /* Queue device exists but has been
+                                        * removed from configuration.
+                                        */
+                                       device_unregister(dev);
+                                       put_device(dev);
+                               }
+                               continue;
+                       }
+                       rc = ap_query_queue(qid, &depth, &type, &functions);
+                       if (dev) {
+                               spin_lock_bh(&aq->lock);
+                               if (rc == -ENODEV ||
+                                   /* adapter reconfiguration */
+                                   (ac && ac->functions != functions))
+                                       aq->state = AP_STATE_BORKED;
+                               borked = aq->state == AP_STATE_BORKED;
+                               spin_unlock_bh(&aq->lock);
+                               if (borked)     /* Remove broken device */
+                                       device_unregister(dev);
+                               put_device(dev);
+                               if (!borked) {
+                                       domains++;
+                                       continue;
+                               }
+                       }
+                       if (rc)
+                               continue;
+                       /* new queue device needed */
+                       if (!ac) {
+                               /* but first create the card device */
+                               ac = ap_card_create(id, depth,
+                                                   type, functions);
+                               if (!ac)
+                                       continue;
+                               ac->ap_dev.device.bus = &ap_bus_type;
+                               ac->ap_dev.device.parent = ap_root_device;
+                               dev_set_name(&ac->ap_dev.device,
+                                            "card%02x", id);
+                               /* Register card with AP bus */
+                               rc = device_register(&ac->ap_dev.device);
+                               if (rc) {
+                                       put_device(&ac->ap_dev.device);
+                                       ac = NULL;
+                                       break;
+                               }
+                               /* get it and thus adjust reference counter */
+                               get_device(&ac->ap_dev.device);
+                               /* Add card device to card list */
+                               spin_lock_bh(&ap_list_lock);
+                               list_add(&ac->list, &ap_card_list);
+                               spin_unlock_bh(&ap_list_lock);
+                       }
+                       /* now create the new queue device */
+                       aq = ap_queue_create(qid, type);
+                       if (!aq)
+                               continue;
+                       aq->card = ac;
+                       aq->ap_dev.device.bus = &ap_bus_type;
+                       aq->ap_dev.device.parent = &ac->ap_dev.device;
+                       dev_set_name(&aq->ap_dev.device,
+                                    "%02x.%04x", id, dom);
+                       /* Add queue device to card queue list */
+                       spin_lock_bh(&ap_list_lock);
+                       list_add(&aq->list, &ac->queues);
+                       spin_unlock_bh(&ap_list_lock);
+                       /* Start with a device reset */
+                       spin_lock_bh(&aq->lock);
+                       ap_wait(ap_sm_event(aq, AP_EVENT_POLL));
+                       spin_unlock_bh(&aq->lock);
+                       /* Register device */
+                       rc = device_register(&aq->ap_dev.device);
+                       if (rc) {
+                               spin_lock_bh(&ap_list_lock);
+                               list_del_init(&aq->list);
+                               spin_unlock_bh(&ap_list_lock);
+                               put_device(&aq->ap_dev.device);
+                               continue;
+                       }
+                       domains++;
+               } /* end domain loop */
+               if (ac) {
+                       /* remove card dev if there are no queue devices */
+                       if (!domains)
+                               device_unregister(&ac->ap_dev.device);
+                       put_device(&ac->ap_dev.device);
                }
-       }
-       spin_unlock_bh(&ap_domain_lock);
+       } /* end device loop */
 out:
        mod_timer(&ap_config_timer, jiffies + ap_config_time * HZ);
 }
@@ -1787,7 +1228,15 @@ void ap_module_exit(void)
        del_timer_sync(&ap_config_timer);
        hrtimer_cancel(&ap_poll_timer);
        tasklet_kill(&ap_tasklet);
-       bus_for_each_dev(&ap_bus_type, NULL, NULL, __ap_devices_unregister);
+
+       /* first remove queue devices */
+       bus_for_each_dev(&ap_bus_type, NULL, NULL,
+                        __ap_queue_devices_unregister);
+       /* now remove the card devices */
+       bus_for_each_dev(&ap_bus_type, NULL, NULL,
+                        __ap_card_devices_unregister);
+
+       /* remove bus attributes */
        for (i = 0; ap_bus_attrs[i]; i++)
                bus_remove_file(&ap_bus_type, ap_bus_attrs[i]);
        unregister_pm_notifier(&ap_power_notifier);
index fd66d2c450d5506dd46bbc93471cf8bcefe6385a..54b17e1427928b87ef5109e312933cf6a1101e7d 100644 (file)
@@ -27,7 +27,6 @@
 #define _AP_BUS_H_
 
 #include <linux/device.h>
-#include <linux/mod_devicetable.h>
 #include <linux/types.h>
 
 #define AP_DEVICES 64          /* Number of AP devices. */
 
 extern int ap_domain_index;
 
+extern spinlock_t ap_list_lock;
+extern struct list_head ap_card_list;
+
 /**
  * The ap_qid_t identifier of an ap queue. It contains a
- * 6 bit device index and a 4 bit queue index (domain).
+ * 6 bit card index and a 4 bit queue index (domain).
  */
 typedef unsigned int ap_qid_t;
 
-#define AP_MKQID(_device, _queue) (((_device) & 63) << 8 | ((_queue) & 255))
-#define AP_QID_DEVICE(_qid) (((_qid) >> 8) & 63)
+#define AP_MKQID(_card, _queue) (((_card) & 63) << 8 | ((_queue) & 255))
+#define AP_QID_CARD(_qid) (((_qid) >> 8) & 63)
 #define AP_QID_QUEUE(_qid) ((_qid) & 255)
 
 /**
@@ -55,7 +57,7 @@ typedef unsigned int ap_qid_t;
  * @queue_full: Is 1 if the queue is full
  * @pad: A 4 bit pad
  * @int_enabled: Shows if interrupts are enabled for the AP
- * @response_conde: Holds the 8 bit response code
+ * @response_code: Holds the 8 bit response code
  * @pad2: A 16 bit pad
  *
  * The ap queue status word is returned by all three AP functions
@@ -167,7 +169,8 @@ struct ap_driver {
 
        int (*probe)(struct ap_device *);
        void (*remove)(struct ap_device *);
-       int request_timeout;            /* request timeout in jiffies */
+       void (*suspend)(struct ap_device *);
+       void (*resume)(struct ap_device *);
 };
 
 #define to_ap_drv(x) container_of((x), struct ap_driver, driver)
@@ -175,38 +178,50 @@ struct ap_driver {
 int ap_driver_register(struct ap_driver *, struct module *, char *);
 void ap_driver_unregister(struct ap_driver *);
 
-typedef enum ap_wait (ap_func_t)(struct ap_device *ap_dev);
-
 struct ap_device {
        struct device device;
        struct ap_driver *drv;          /* Pointer to AP device driver. */
-       spinlock_t lock;                /* Per device lock. */
-       struct list_head list;          /* private list of all AP devices. */
+       int device_type;                /* AP device type. */
+};
 
-       enum ap_state state;            /* State of the AP device. */
+#define to_ap_dev(x) container_of((x), struct ap_device, device)
 
-       ap_qid_t qid;                   /* AP queue id. */
-       int queue_depth;                /* AP queue depth.*/
-       int device_type;                /* AP device type. */
+struct ap_card {
+       struct ap_device ap_dev;
+       struct list_head list;          /* Private list of AP cards. */
+       struct list_head queues;        /* List of assoc. AP queues */
+       void *private;                  /* ap driver private pointer. */
        int raw_hwtype;                 /* AP raw hardware type. */
        unsigned int functions;         /* AP device function bitfield. */
-       struct timer_list timeout;      /* Timer for request timeouts. */
+       int queue_depth;                /* AP queue depth.*/
+       int id;                         /* AP card number. */
+};
+
+#define to_ap_card(x) container_of((x), struct ap_card, ap_dev.device)
 
+struct ap_queue {
+       struct ap_device ap_dev;
+       struct list_head list;          /* Private list of AP queues. */
+       struct ap_card *card;           /* Ptr to assoc. AP card. */
+       spinlock_t lock;                /* Per device lock. */
+       void *private;                  /* ap driver private pointer. */
+       ap_qid_t qid;                   /* AP queue id. */
        int interrupt;                  /* indicate if interrupts are enabled */
        int queue_count;                /* # messages currently on AP queue. */
-
-       struct list_head pendingq;      /* List of message sent to AP queue. */
+       enum ap_state state;            /* State of the AP device. */
        int pendingq_count;             /* # requests on pendingq list. */
-       struct list_head requestq;      /* List of message yet to be sent. */
        int requestq_count;             /* # requests on requestq list. */
        int total_request_count;        /* # requests ever for this AP device. */
-
+       int request_timeout;            /* Request timout in jiffies. */
+       struct timer_list timeout;      /* Timer for request timeouts. */
+       struct list_head pendingq;      /* List of message sent to AP queue. */
+       struct list_head requestq;      /* List of message yet to be sent. */
        struct ap_message *reply;       /* Per device reply message. */
-
-       void *private;                  /* ap driver private pointer. */
 };
 
-#define to_ap_dev(x) container_of((x), struct ap_device, device)
+#define to_ap_queue(x) container_of((x), struct ap_queue, ap_dev.device)
+
+typedef enum ap_wait (ap_func_t)(struct ap_queue *queue);
 
 struct ap_message {
        struct list_head list;          /* Request queueing. */
@@ -218,7 +233,7 @@ struct ap_message {
        void *private;                  /* ap driver private pointer. */
        unsigned int special:1;         /* Used for special commands. */
        /* receive is called from tasklet context */
-       void (*receive)(struct ap_device *, struct ap_message *,
+       void (*receive)(struct ap_queue *, struct ap_message *,
                        struct ap_message *);
 };
 
@@ -233,10 +248,6 @@ struct ap_config_info {
        unsigned char reserved4[16];
 } __packed;
 
-#define AP_DEVICE(dt)                                  \
-       .dev_type=(dt),                                 \
-       .match_flags=AP_DEVICE_ID_MATCH_DEVICE_TYPE,
-
 /**
  * ap_init_message() - Initialize ap_message.
  * Initialize a message before using. Otherwise this might result in
@@ -251,6 +262,12 @@ static inline void ap_init_message(struct ap_message *ap_msg)
        ap_msg->receive = NULL;
 }
 
+#define for_each_ap_card(_ac) \
+       list_for_each_entry(_ac, &ap_card_list, list)
+
+#define for_each_ap_queue(_aq, _ac) \
+       list_for_each_entry(_aq, &(_ac)->queues, list)
+
 /*
  * Note: don't use ap_send/ap_recv after using ap_queue_message
  * for the first time. Otherwise the ap message queue will get
@@ -259,11 +276,26 @@ static inline void ap_init_message(struct ap_message *ap_msg)
 int ap_send(ap_qid_t, unsigned long long, void *, size_t);
 int ap_recv(ap_qid_t, unsigned long long *, void *, size_t);
 
-void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg);
-void ap_cancel_message(struct ap_device *ap_dev, struct ap_message *ap_msg);
-void ap_flush_queue(struct ap_device *ap_dev);
+enum ap_wait ap_sm_event(struct ap_queue *aq, enum ap_event event);
+enum ap_wait ap_sm_event_loop(struct ap_queue *aq, enum ap_event event);
+
+void ap_queue_message(struct ap_queue *aq, struct ap_message *ap_msg);
+void ap_cancel_message(struct ap_queue *aq, struct ap_message *ap_msg);
+void ap_flush_queue(struct ap_queue *aq);
+
+void *ap_airq_ptr(void);
+void ap_wait(enum ap_wait wait);
+void ap_request_timeout(unsigned long data);
 void ap_bus_force_rescan(void);
-void ap_device_init_reply(struct ap_device *ap_dev, struct ap_message *ap_msg);
+
+void ap_queue_init_reply(struct ap_queue *aq, struct ap_message *ap_msg);
+struct ap_queue *ap_queue_create(ap_qid_t qid, int device_type);
+void ap_queue_remove(struct ap_queue *aq);
+void ap_queue_suspend(struct ap_device *ap_dev);
+void ap_queue_resume(struct ap_device *ap_dev);
+
+struct ap_card *ap_card_create(int id, int queue_depth, int device_type,
+                              unsigned int device_functions);
 
 int ap_module_init(void);
 void ap_module_exit(void);
diff --git a/drivers/s390/crypto/ap_card.c b/drivers/s390/crypto/ap_card.c
new file mode 100644 (file)
index 0000000..731dc0d
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright IBM Corp. 2016
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *
+ * Adjunct processor bus, card related code.
+ */
+
+#define KMSG_COMPONENT "ap"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <asm/facility.h>
+
+#include "ap_bus.h"
+#include "ap_asm.h"
+
+/*
+ * AP card related attributes.
+ */
+static ssize_t ap_hwtype_show(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+       struct ap_card *ac = to_ap_card(dev);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", ac->ap_dev.device_type);
+}
+
+static DEVICE_ATTR(hwtype, 0444, ap_hwtype_show, NULL);
+
+static ssize_t ap_raw_hwtype_show(struct device *dev,
+                                 struct device_attribute *attr, char *buf)
+{
+       struct ap_card *ac = to_ap_card(dev);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", ac->raw_hwtype);
+}
+
+static DEVICE_ATTR(raw_hwtype, 0444, ap_raw_hwtype_show, NULL);
+
+static ssize_t ap_depth_show(struct device *dev, struct device_attribute *attr,
+                            char *buf)
+{
+       struct ap_card *ac = to_ap_card(dev);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", ac->queue_depth);
+}
+
+static DEVICE_ATTR(depth, 0444, ap_depth_show, NULL);
+
+static ssize_t ap_functions_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct ap_card *ac = to_ap_card(dev);
+
+       return snprintf(buf, PAGE_SIZE, "0x%08X\n", ac->functions);
+}
+
+static DEVICE_ATTR(ap_functions, 0444, ap_functions_show, NULL);
+
+static ssize_t ap_request_count_show(struct device *dev,
+                                    struct device_attribute *attr,
+                                    char *buf)
+{
+       struct ap_card *ac = to_ap_card(dev);
+       struct ap_queue *aq;
+       unsigned int req_cnt;
+
+       req_cnt = 0;
+       spin_lock_bh(&ap_list_lock);
+       for_each_ap_queue(aq, ac)
+               req_cnt += aq->total_request_count;
+       spin_unlock_bh(&ap_list_lock);
+       return snprintf(buf, PAGE_SIZE, "%d\n", req_cnt);
+}
+
+static DEVICE_ATTR(request_count, 0444, ap_request_count_show, NULL);
+
+static ssize_t ap_requestq_count_show(struct device *dev,
+                                     struct device_attribute *attr, char *buf)
+{
+       struct ap_card *ac = to_ap_card(dev);
+       struct ap_queue *aq;
+       unsigned int reqq_cnt;
+
+       reqq_cnt = 0;
+       spin_lock_bh(&ap_list_lock);
+       for_each_ap_queue(aq, ac)
+               reqq_cnt += aq->requestq_count;
+       spin_unlock_bh(&ap_list_lock);
+       return snprintf(buf, PAGE_SIZE, "%d\n", reqq_cnt);
+}
+
+static DEVICE_ATTR(requestq_count, 0444, ap_requestq_count_show, NULL);
+
+static ssize_t ap_pendingq_count_show(struct device *dev,
+                                     struct device_attribute *attr, char *buf)
+{
+       struct ap_card *ac = to_ap_card(dev);
+       struct ap_queue *aq;
+       unsigned int penq_cnt;
+
+       penq_cnt = 0;
+       spin_lock_bh(&ap_list_lock);
+       for_each_ap_queue(aq, ac)
+               penq_cnt += aq->pendingq_count;
+       spin_unlock_bh(&ap_list_lock);
+       return snprintf(buf, PAGE_SIZE, "%d\n", penq_cnt);
+}
+
+static DEVICE_ATTR(pendingq_count, 0444, ap_pendingq_count_show, NULL);
+
+static ssize_t ap_modalias_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "ap:t%02X\n", to_ap_dev(dev)->device_type);
+}
+
+static DEVICE_ATTR(modalias, 0444, ap_modalias_show, NULL);
+
+static struct attribute *ap_card_dev_attrs[] = {
+       &dev_attr_hwtype.attr,
+       &dev_attr_raw_hwtype.attr,
+       &dev_attr_depth.attr,
+       &dev_attr_ap_functions.attr,
+       &dev_attr_request_count.attr,
+       &dev_attr_requestq_count.attr,
+       &dev_attr_pendingq_count.attr,
+       &dev_attr_modalias.attr,
+       NULL
+};
+
+static struct attribute_group ap_card_dev_attr_group = {
+       .attrs = ap_card_dev_attrs
+};
+
+static const struct attribute_group *ap_card_dev_attr_groups[] = {
+       &ap_card_dev_attr_group,
+       NULL
+};
+
+struct device_type ap_card_type = {
+       .name = "ap_card",
+       .groups = ap_card_dev_attr_groups,
+};
+
+static void ap_card_device_release(struct device *dev)
+{
+       kfree(to_ap_card(dev));
+}
+
+struct ap_card *ap_card_create(int id, int queue_depth, int device_type,
+                              unsigned int functions)
+{
+       struct ap_card *ac;
+
+       ac = kzalloc(sizeof(*ac), GFP_KERNEL);
+       if (!ac)
+               return NULL;
+       INIT_LIST_HEAD(&ac->queues);
+       ac->ap_dev.device.release = ap_card_device_release;
+       ac->ap_dev.device.type = &ap_card_type;
+       ac->ap_dev.device_type = device_type;
+       /* CEX6 toleration: map to CEX5 */
+       if (device_type == AP_DEVICE_TYPE_CEX6)
+               ac->ap_dev.device_type = AP_DEVICE_TYPE_CEX5;
+       ac->raw_hwtype = device_type;
+       ac->queue_depth = queue_depth;
+       ac->functions = functions;
+       ac->id = id;
+       return ac;
+}
diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c
new file mode 100644 (file)
index 0000000..8f95a07
--- /dev/null
@@ -0,0 +1,700 @@
+/*
+ * Copyright IBM Corp. 2016
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *
+ * Adjunct processor bus, queue related code.
+ */
+
+#define KMSG_COMPONENT "ap"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <asm/facility.h>
+
+#include "ap_bus.h"
+#include "ap_asm.h"
+
+/**
+ * ap_queue_enable_interruption(): Enable interruption on an AP queue.
+ * @qid: The AP queue number
+ * @ind: the notification indicator byte
+ *
+ * Enables interruption on AP queue via ap_aqic(). Based on the return
+ * value it waits a while and tests the AP queue if interrupts
+ * have been switched on using ap_test_queue().
+ */
+static int ap_queue_enable_interruption(struct ap_queue *aq, void *ind)
+{
+       struct ap_queue_status status;
+
+       status = ap_aqic(aq->qid, ind);
+       switch (status.response_code) {
+       case AP_RESPONSE_NORMAL:
+       case AP_RESPONSE_OTHERWISE_CHANGED:
+               return 0;
+       case AP_RESPONSE_Q_NOT_AVAIL:
+       case AP_RESPONSE_DECONFIGURED:
+       case AP_RESPONSE_CHECKSTOPPED:
+       case AP_RESPONSE_INVALID_ADDRESS:
+               pr_err("Registering adapter interrupts for AP device %02x.%04x failed\n",
+                      AP_QID_CARD(aq->qid),
+                      AP_QID_QUEUE(aq->qid));
+               return -EOPNOTSUPP;
+       case AP_RESPONSE_RESET_IN_PROGRESS:
+       case AP_RESPONSE_BUSY:
+       default:
+               return -EBUSY;
+       }
+}
+
+/**
+ * __ap_send(): Send message to adjunct processor queue.
+ * @qid: The AP queue number
+ * @psmid: The program supplied message identifier
+ * @msg: The message text
+ * @length: The message length
+ * @special: Special Bit
+ *
+ * Returns AP queue status structure.
+ * Condition code 1 on NQAP can't happen because the L bit is 1.
+ * Condition code 2 on NQAP also means the send is incomplete,
+ * because a segment boundary was reached. The NQAP is repeated.
+ */
+static inline struct ap_queue_status
+__ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length,
+         unsigned int special)
+{
+       if (special == 1)
+               qid |= 0x400000UL;
+       return ap_nqap(qid, psmid, msg, length);
+}
+
+int ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length)
+{
+       struct ap_queue_status status;
+
+       status = __ap_send(qid, psmid, msg, length, 0);
+       switch (status.response_code) {
+       case AP_RESPONSE_NORMAL:
+               return 0;
+       case AP_RESPONSE_Q_FULL:
+       case AP_RESPONSE_RESET_IN_PROGRESS:
+               return -EBUSY;
+       case AP_RESPONSE_REQ_FAC_NOT_INST:
+               return -EINVAL;
+       default:        /* Device is gone. */
+               return -ENODEV;
+       }
+}
+EXPORT_SYMBOL(ap_send);
+
+int ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length)
+{
+       struct ap_queue_status status;
+
+       if (msg == NULL)
+               return -EINVAL;
+       status = ap_dqap(qid, psmid, msg, length);
+       switch (status.response_code) {
+       case AP_RESPONSE_NORMAL:
+               return 0;
+       case AP_RESPONSE_NO_PENDING_REPLY:
+               if (status.queue_empty)
+                       return -ENOENT;
+               return -EBUSY;
+       case AP_RESPONSE_RESET_IN_PROGRESS:
+               return -EBUSY;
+       default:
+               return -ENODEV;
+       }
+}
+EXPORT_SYMBOL(ap_recv);
+
+/* State machine definitions and helpers */
+
+static enum ap_wait ap_sm_nop(struct ap_queue *aq)
+{
+       return AP_WAIT_NONE;
+}
+
+/**
+ * ap_sm_recv(): Receive pending reply messages from an AP queue but do
+ *     not change the state of the device.
+ * @aq: pointer to the AP queue
+ *
+ * Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT
+ */
+static struct ap_queue_status ap_sm_recv(struct ap_queue *aq)
+{
+       struct ap_queue_status status;
+       struct ap_message *ap_msg;
+
+       status = ap_dqap(aq->qid, &aq->reply->psmid,
+                        aq->reply->message, aq->reply->length);
+       switch (status.response_code) {
+       case AP_RESPONSE_NORMAL:
+               aq->queue_count--;
+               if (aq->queue_count > 0)
+                       mod_timer(&aq->timeout,
+                                 jiffies + aq->request_timeout);
+               list_for_each_entry(ap_msg, &aq->pendingq, list) {
+                       if (ap_msg->psmid != aq->reply->psmid)
+                               continue;
+                       list_del_init(&ap_msg->list);
+                       aq->pendingq_count--;
+                       ap_msg->receive(aq, ap_msg, aq->reply);
+                       break;
+               }
+       case AP_RESPONSE_NO_PENDING_REPLY:
+               if (!status.queue_empty || aq->queue_count <= 0)
+                       break;
+               /* The card shouldn't forget requests but who knows. */
+               aq->queue_count = 0;
+               list_splice_init(&aq->pendingq, &aq->requestq);
+               aq->requestq_count += aq->pendingq_count;
+               aq->pendingq_count = 0;
+               break;
+       default:
+               break;
+       }
+       return status;
+}
+
+/**
+ * ap_sm_read(): Receive pending reply messages from an AP queue.
+ * @aq: pointer to the AP queue
+ *
+ * Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT
+ */
+static enum ap_wait ap_sm_read(struct ap_queue *aq)
+{
+       struct ap_queue_status status;
+
+       if (!aq->reply)
+               return AP_WAIT_NONE;
+       status = ap_sm_recv(aq);
+       switch (status.response_code) {
+       case AP_RESPONSE_NORMAL:
+               if (aq->queue_count > 0) {
+                       aq->state = AP_STATE_WORKING;
+                       return AP_WAIT_AGAIN;
+               }
+               aq->state = AP_STATE_IDLE;
+               return AP_WAIT_NONE;
+       case AP_RESPONSE_NO_PENDING_REPLY:
+               if (aq->queue_count > 0)
+                       return AP_WAIT_INTERRUPT;
+               aq->state = AP_STATE_IDLE;
+               return AP_WAIT_NONE;
+       default:
+               aq->state = AP_STATE_BORKED;
+               return AP_WAIT_NONE;
+       }
+}
+
+/**
+ * ap_sm_suspend_read(): Receive pending reply messages from an AP queue
+ * without changing the device state in between. In suspend mode we don't
+ * allow sending new requests, therefore just fetch pending replies.
+ * @aq: pointer to the AP queue
+ *
+ * Returns AP_WAIT_NONE or AP_WAIT_AGAIN
+ */
+static enum ap_wait ap_sm_suspend_read(struct ap_queue *aq)
+{
+       struct ap_queue_status status;
+
+       if (!aq->reply)
+               return AP_WAIT_NONE;
+       status = ap_sm_recv(aq);
+       switch (status.response_code) {
+       case AP_RESPONSE_NORMAL:
+               if (aq->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 queue.
+ * @aq: pointer to the AP queue
+ *
+ * Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT
+ */
+static enum ap_wait ap_sm_write(struct ap_queue *aq)
+{
+       struct ap_queue_status status;
+       struct ap_message *ap_msg;
+
+       if (aq->requestq_count <= 0)
+               return AP_WAIT_NONE;
+       /* Start the next request on the queue. */
+       ap_msg = list_entry(aq->requestq.next, struct ap_message, list);
+       status = __ap_send(aq->qid, ap_msg->psmid,
+                          ap_msg->message, ap_msg->length, ap_msg->special);
+       switch (status.response_code) {
+       case AP_RESPONSE_NORMAL:
+               aq->queue_count++;
+               if (aq->queue_count == 1)
+                       mod_timer(&aq->timeout, jiffies + aq->request_timeout);
+               list_move_tail(&ap_msg->list, &aq->pendingq);
+               aq->requestq_count--;
+               aq->pendingq_count++;
+               if (aq->queue_count < aq->card->queue_depth) {
+                       aq->state = AP_STATE_WORKING;
+                       return AP_WAIT_AGAIN;
+               }
+               /* fall through */
+       case AP_RESPONSE_Q_FULL:
+               aq->state = AP_STATE_QUEUE_FULL;
+               return AP_WAIT_INTERRUPT;
+       case AP_RESPONSE_RESET_IN_PROGRESS:
+               aq->state = AP_STATE_RESET_WAIT;
+               return AP_WAIT_TIMEOUT;
+       case AP_RESPONSE_MESSAGE_TOO_BIG:
+       case AP_RESPONSE_REQ_FAC_NOT_INST:
+               list_del_init(&ap_msg->list);
+               aq->requestq_count--;
+               ap_msg->rc = -EINVAL;
+               ap_msg->receive(aq, ap_msg, NULL);
+               return AP_WAIT_AGAIN;
+       default:
+               aq->state = AP_STATE_BORKED;
+               return AP_WAIT_NONE;
+       }
+}
+
+/**
+ * ap_sm_read_write(): Send and receive messages to/from an AP queue.
+ * @aq: pointer to the AP queue
+ *
+ * Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT
+ */
+static enum ap_wait ap_sm_read_write(struct ap_queue *aq)
+{
+       return min(ap_sm_read(aq), ap_sm_write(aq));
+}
+
+/**
+ * ap_sm_reset(): Reset an AP queue.
+ * @qid: The AP queue number
+ *
+ * Submit the Reset command to an AP queue.
+ */
+static enum ap_wait ap_sm_reset(struct ap_queue *aq)
+{
+       struct ap_queue_status status;
+
+       status = ap_rapq(aq->qid);
+       switch (status.response_code) {
+       case AP_RESPONSE_NORMAL:
+       case AP_RESPONSE_RESET_IN_PROGRESS:
+               aq->state = AP_STATE_RESET_WAIT;
+               aq->interrupt = AP_INTR_DISABLED;
+               return AP_WAIT_TIMEOUT;
+       case AP_RESPONSE_BUSY:
+               return AP_WAIT_TIMEOUT;
+       case AP_RESPONSE_Q_NOT_AVAIL:
+       case AP_RESPONSE_DECONFIGURED:
+       case AP_RESPONSE_CHECKSTOPPED:
+       default:
+               aq->state = AP_STATE_BORKED;
+               return AP_WAIT_NONE;
+       }
+}
+
+/**
+ * ap_sm_reset_wait(): Test queue for completion of the reset operation
+ * @aq: pointer to the AP queue
+ *
+ * Returns AP_POLL_IMMEDIATELY, AP_POLL_AFTER_TIMEROUT or 0.
+ */
+static enum ap_wait ap_sm_reset_wait(struct ap_queue *aq)
+{
+       struct ap_queue_status status;
+       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);
+
+       switch (status.response_code) {
+       case AP_RESPONSE_NORMAL:
+               lsi_ptr = ap_airq_ptr();
+               if (lsi_ptr && ap_queue_enable_interruption(aq, lsi_ptr) == 0)
+                       aq->state = AP_STATE_SETIRQ_WAIT;
+               else
+                       aq->state = (aq->queue_count > 0) ?
+                               AP_STATE_WORKING : AP_STATE_IDLE;
+               return AP_WAIT_AGAIN;
+       case AP_RESPONSE_BUSY:
+       case AP_RESPONSE_RESET_IN_PROGRESS:
+               return AP_WAIT_TIMEOUT;
+       case AP_RESPONSE_Q_NOT_AVAIL:
+       case AP_RESPONSE_DECONFIGURED:
+       case AP_RESPONSE_CHECKSTOPPED:
+       default:
+               aq->state = AP_STATE_BORKED;
+               return AP_WAIT_NONE;
+       }
+}
+
+/**
+ * ap_sm_setirq_wait(): Test queue for completion of the irq enablement
+ * @aq: pointer to the AP queue
+ *
+ * Returns AP_POLL_IMMEDIATELY, AP_POLL_AFTER_TIMEROUT or 0.
+ */
+static enum ap_wait ap_sm_setirq_wait(struct ap_queue *aq)
+{
+       struct ap_queue_status status;
+
+       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);
+
+       if (status.int_enabled == 1) {
+               /* Irqs are now enabled */
+               aq->interrupt = AP_INTR_ENABLED;
+               aq->state = (aq->queue_count > 0) ?
+                       AP_STATE_WORKING : AP_STATE_IDLE;
+       }
+
+       switch (status.response_code) {
+       case AP_RESPONSE_NORMAL:
+               if (aq->queue_count > 0)
+                       return AP_WAIT_AGAIN;
+               /* fallthrough */
+       case AP_RESPONSE_NO_PENDING_REPLY:
+               return AP_WAIT_TIMEOUT;
+       default:
+               aq->state = AP_STATE_BORKED;
+               return AP_WAIT_NONE;
+       }
+}
+
+/*
+ * AP state machine jump table
+ */
+static ap_func_t *ap_jumptable[NR_AP_STATES][NR_AP_EVENTS] = {
+       [AP_STATE_RESET_START] = {
+               [AP_EVENT_POLL] = ap_sm_reset,
+               [AP_EVENT_TIMEOUT] = ap_sm_nop,
+       },
+       [AP_STATE_RESET_WAIT] = {
+               [AP_EVENT_POLL] = ap_sm_reset_wait,
+               [AP_EVENT_TIMEOUT] = ap_sm_nop,
+       },
+       [AP_STATE_SETIRQ_WAIT] = {
+               [AP_EVENT_POLL] = ap_sm_setirq_wait,
+               [AP_EVENT_TIMEOUT] = ap_sm_nop,
+       },
+       [AP_STATE_IDLE] = {
+               [AP_EVENT_POLL] = ap_sm_write,
+               [AP_EVENT_TIMEOUT] = ap_sm_nop,
+       },
+       [AP_STATE_WORKING] = {
+               [AP_EVENT_POLL] = ap_sm_read_write,
+               [AP_EVENT_TIMEOUT] = ap_sm_reset,
+       },
+       [AP_STATE_QUEUE_FULL] = {
+               [AP_EVENT_POLL] = ap_sm_read,
+               [AP_EVENT_TIMEOUT] = ap_sm_reset,
+       },
+       [AP_STATE_SUSPEND_WAIT] = {
+               [AP_EVENT_POLL] = ap_sm_suspend_read,
+               [AP_EVENT_TIMEOUT] = ap_sm_nop,
+       },
+       [AP_STATE_BORKED] = {
+               [AP_EVENT_POLL] = ap_sm_nop,
+               [AP_EVENT_TIMEOUT] = ap_sm_nop,
+       },
+};
+
+enum ap_wait ap_sm_event(struct ap_queue *aq, enum ap_event event)
+{
+       return ap_jumptable[aq->state][event](aq);
+}
+
+enum ap_wait ap_sm_event_loop(struct ap_queue *aq, enum ap_event event)
+{
+       enum ap_wait wait;
+
+       while ((wait = ap_sm_event(aq, event)) == AP_WAIT_AGAIN)
+               ;
+       return wait;
+}
+
+/*
+ * Power management for queue devices
+ */
+void ap_queue_suspend(struct ap_device *ap_dev)
+{
+       struct ap_queue *aq = to_ap_queue(&ap_dev->device);
+
+       /* Poll on the device until all requests are finished. */
+       spin_lock_bh(&aq->lock);
+       aq->state = AP_STATE_SUSPEND_WAIT;
+       while (ap_sm_event(aq, AP_EVENT_POLL) != AP_WAIT_NONE)
+               ;
+       aq->state = AP_STATE_BORKED;
+       spin_unlock_bh(&aq->lock);
+}
+EXPORT_SYMBOL(ap_queue_suspend);
+
+void ap_queue_resume(struct ap_device *ap_dev)
+{
+}
+EXPORT_SYMBOL(ap_queue_resume);
+
+/*
+ * AP queue related attributes.
+ */
+static ssize_t ap_request_count_show(struct device *dev,
+                                    struct device_attribute *attr,
+                                    char *buf)
+{
+       struct ap_queue *aq = to_ap_queue(dev);
+       unsigned int req_cnt;
+
+       spin_lock_bh(&aq->lock);
+       req_cnt = aq->total_request_count;
+       spin_unlock_bh(&aq->lock);
+       return snprintf(buf, PAGE_SIZE, "%d\n", req_cnt);
+}
+
+static DEVICE_ATTR(request_count, 0444, ap_request_count_show, NULL);
+
+static ssize_t ap_requestq_count_show(struct device *dev,
+                                     struct device_attribute *attr, char *buf)
+{
+       struct ap_queue *aq = to_ap_queue(dev);
+       unsigned int reqq_cnt = 0;
+
+       spin_lock_bh(&aq->lock);
+       reqq_cnt = aq->requestq_count;
+       spin_unlock_bh(&aq->lock);
+       return snprintf(buf, PAGE_SIZE, "%d\n", reqq_cnt);
+}
+
+static DEVICE_ATTR(requestq_count, 0444, ap_requestq_count_show, NULL);
+
+static ssize_t ap_pendingq_count_show(struct device *dev,
+                                     struct device_attribute *attr, char *buf)
+{
+       struct ap_queue *aq = to_ap_queue(dev);
+       unsigned int penq_cnt = 0;
+
+       spin_lock_bh(&aq->lock);
+       penq_cnt = aq->pendingq_count;
+       spin_unlock_bh(&aq->lock);
+       return snprintf(buf, PAGE_SIZE, "%d\n", penq_cnt);
+}
+
+static DEVICE_ATTR(pendingq_count, 0444, ap_pendingq_count_show, NULL);
+
+static ssize_t ap_reset_show(struct device *dev,
+                                     struct device_attribute *attr, char *buf)
+{
+       struct ap_queue *aq = to_ap_queue(dev);
+       int rc = 0;
+
+       spin_lock_bh(&aq->lock);
+       switch (aq->state) {
+       case AP_STATE_RESET_START:
+       case AP_STATE_RESET_WAIT:
+               rc = snprintf(buf, PAGE_SIZE, "Reset in progress.\n");
+               break;
+       case AP_STATE_WORKING:
+       case AP_STATE_QUEUE_FULL:
+               rc = snprintf(buf, PAGE_SIZE, "Reset Timer armed.\n");
+               break;
+       default:
+               rc = snprintf(buf, PAGE_SIZE, "No Reset Timer set.\n");
+       }
+       spin_unlock_bh(&aq->lock);
+       return rc;
+}
+
+static DEVICE_ATTR(reset, 0444, ap_reset_show, NULL);
+
+static ssize_t ap_interrupt_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct ap_queue *aq = to_ap_queue(dev);
+       int rc = 0;
+
+       spin_lock_bh(&aq->lock);
+       if (aq->state == AP_STATE_SETIRQ_WAIT)
+               rc = snprintf(buf, PAGE_SIZE, "Enable Interrupt pending.\n");
+       else if (aq->interrupt == AP_INTR_ENABLED)
+               rc = snprintf(buf, PAGE_SIZE, "Interrupts enabled.\n");
+       else
+               rc = snprintf(buf, PAGE_SIZE, "Interrupts disabled.\n");
+       spin_unlock_bh(&aq->lock);
+       return rc;
+}
+
+static DEVICE_ATTR(interrupt, 0444, ap_interrupt_show, NULL);
+
+static struct attribute *ap_queue_dev_attrs[] = {
+       &dev_attr_request_count.attr,
+       &dev_attr_requestq_count.attr,
+       &dev_attr_pendingq_count.attr,
+       &dev_attr_reset.attr,
+       &dev_attr_interrupt.attr,
+       NULL
+};
+
+static struct attribute_group ap_queue_dev_attr_group = {
+       .attrs = ap_queue_dev_attrs
+};
+
+static const struct attribute_group *ap_queue_dev_attr_groups[] = {
+       &ap_queue_dev_attr_group,
+       NULL
+};
+
+struct device_type ap_queue_type = {
+       .name = "ap_queue",
+       .groups = ap_queue_dev_attr_groups,
+};
+
+static void ap_queue_device_release(struct device *dev)
+{
+       kfree(to_ap_queue(dev));
+}
+
+struct ap_queue *ap_queue_create(ap_qid_t qid, int device_type)
+{
+       struct ap_queue *aq;
+
+       aq = kzalloc(sizeof(*aq), GFP_KERNEL);
+       if (!aq)
+               return NULL;
+       aq->ap_dev.device.release = ap_queue_device_release;
+       aq->ap_dev.device.type = &ap_queue_type;
+       aq->ap_dev.device_type = device_type;
+       /* CEX6 toleration: map to CEX5 */
+       if (device_type == AP_DEVICE_TYPE_CEX6)
+               aq->ap_dev.device_type = AP_DEVICE_TYPE_CEX5;
+       aq->qid = qid;
+       aq->state = AP_STATE_RESET_START;
+       aq->interrupt = AP_INTR_DISABLED;
+       spin_lock_init(&aq->lock);
+       INIT_LIST_HEAD(&aq->pendingq);
+       INIT_LIST_HEAD(&aq->requestq);
+       setup_timer(&aq->timeout, ap_request_timeout, (unsigned long) aq);
+
+       return aq;
+}
+
+void ap_queue_init_reply(struct ap_queue *aq, struct ap_message *reply)
+{
+       aq->reply = reply;
+
+       spin_lock_bh(&aq->lock);
+       ap_wait(ap_sm_event(aq, AP_EVENT_POLL));
+       spin_unlock_bh(&aq->lock);
+}
+EXPORT_SYMBOL(ap_queue_init_reply);
+
+/**
+ * ap_queue_message(): Queue a request to an AP device.
+ * @aq: The AP device to queue the message to
+ * @ap_msg: The message that is to be added
+ */
+void ap_queue_message(struct ap_queue *aq, struct ap_message *ap_msg)
+{
+       /* For asynchronous message handling a valid receive-callback
+        * is required.
+        */
+       BUG_ON(!ap_msg->receive);
+
+       spin_lock_bh(&aq->lock);
+       /* Queue the message. */
+       list_add_tail(&ap_msg->list, &aq->requestq);
+       aq->requestq_count++;
+       aq->total_request_count++;
+       /* Send/receive as many request from the queue as possible. */
+       ap_wait(ap_sm_event_loop(aq, AP_EVENT_POLL));
+       spin_unlock_bh(&aq->lock);
+}
+EXPORT_SYMBOL(ap_queue_message);
+
+/**
+ * ap_cancel_message(): Cancel a crypto request.
+ * @aq: The AP device that has the message queued
+ * @ap_msg: The message that is to be removed
+ *
+ * Cancel a crypto request. This is done by removing the request
+ * from the device pending or request queue. Note that the
+ * request stays on the AP queue. When it finishes the message
+ * reply will be discarded because the psmid can't be found.
+ */
+void ap_cancel_message(struct ap_queue *aq, struct ap_message *ap_msg)
+{
+       struct ap_message *tmp;
+
+       spin_lock_bh(&aq->lock);
+       if (!list_empty(&ap_msg->list)) {
+               list_for_each_entry(tmp, &aq->pendingq, list)
+                       if (tmp->psmid == ap_msg->psmid) {
+                               aq->pendingq_count--;
+                               goto found;
+                       }
+               aq->requestq_count--;
+found:
+               list_del_init(&ap_msg->list);
+       }
+       spin_unlock_bh(&aq->lock);
+}
+EXPORT_SYMBOL(ap_cancel_message);
+
+/**
+ * __ap_flush_queue(): Flush requests.
+ * @aq: Pointer to the AP queue
+ *
+ * Flush all requests from the request/pending queue of an AP device.
+ */
+static void __ap_flush_queue(struct ap_queue *aq)
+{
+       struct ap_message *ap_msg, *next;
+
+       list_for_each_entry_safe(ap_msg, next, &aq->pendingq, list) {
+               list_del_init(&ap_msg->list);
+               aq->pendingq_count--;
+               ap_msg->rc = -EAGAIN;
+               ap_msg->receive(aq, ap_msg, NULL);
+       }
+       list_for_each_entry_safe(ap_msg, next, &aq->requestq, list) {
+               list_del_init(&ap_msg->list);
+               aq->requestq_count--;
+               ap_msg->rc = -EAGAIN;
+               ap_msg->receive(aq, ap_msg, NULL);
+       }
+}
+
+void ap_flush_queue(struct ap_queue *aq)
+{
+       spin_lock_bh(&aq->lock);
+       __ap_flush_queue(aq);
+       spin_unlock_bh(&aq->lock);
+}
+EXPORT_SYMBOL(ap_flush_queue);
+
+void ap_queue_remove(struct ap_queue *aq)
+{
+       ap_flush_queue(aq);
+       del_timer_sync(&aq->timeout);
+}
+EXPORT_SYMBOL(ap_queue_remove);
index 28913e5400960f03658ede4b06824871ada4b11f..fd0ae8cd2beecdac35280a5210874a0a25d4f4b0 100644 (file)
@@ -59,71 +59,22 @@ static int zcrypt_hwrng_seed = 1;
 module_param_named(hwrng_seed, zcrypt_hwrng_seed, int, S_IRUSR|S_IRGRP);
 MODULE_PARM_DESC(hwrng_seed, "Turn on/off hwrng auto seed, default is 1 (on).");
 
-static DEFINE_SPINLOCK(zcrypt_device_lock);
-static LIST_HEAD(zcrypt_device_list);
-static int zcrypt_device_count = 0;
+DEFINE_SPINLOCK(zcrypt_list_lock);
+LIST_HEAD(zcrypt_card_list);
+int zcrypt_device_count;
+
 static atomic_t zcrypt_open_count = ATOMIC_INIT(0);
 static atomic_t zcrypt_rescan_count = ATOMIC_INIT(0);
 
 atomic_t zcrypt_rescan_req = ATOMIC_INIT(0);
 EXPORT_SYMBOL(zcrypt_rescan_req);
 
-static int zcrypt_rng_device_add(void);
-static void zcrypt_rng_device_remove(void);
-
 static LIST_HEAD(zcrypt_ops_list);
 
-static debug_info_t *zcrypt_dbf_common;
-static debug_info_t *zcrypt_dbf_devices;
 static struct dentry *debugfs_root;
-
-/*
- * Device attributes common for all crypto devices.
- */
-static ssize_t zcrypt_type_show(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       struct zcrypt_device *zdev = to_ap_dev(dev)->private;
-       return snprintf(buf, PAGE_SIZE, "%s\n", zdev->type_string);
-}
-
-static DEVICE_ATTR(type, 0444, zcrypt_type_show, NULL);
-
-static ssize_t zcrypt_online_show(struct device *dev,
-                                 struct device_attribute *attr, char *buf)
-{
-       struct zcrypt_device *zdev = to_ap_dev(dev)->private;
-       return snprintf(buf, PAGE_SIZE, "%d\n", zdev->online);
-}
-
-static ssize_t zcrypt_online_store(struct device *dev,
-                                  struct device_attribute *attr,
-                                  const char *buf, size_t count)
-{
-       struct zcrypt_device *zdev = to_ap_dev(dev)->private;
-       int online;
-
-       if (sscanf(buf, "%d\n", &online) != 1 || online < 0 || online > 1)
-               return -EINVAL;
-       zdev->online = online;
-       ZCRYPT_DBF_DEV(DBF_INFO, zdev, "dev%04xo%dman", zdev->ap_dev->qid,
-                      zdev->online);
-       if (!online)
-               ap_flush_queue(zdev->ap_dev);
-       return count;
-}
-
-static DEVICE_ATTR(online, 0644, zcrypt_online_show, zcrypt_online_store);
-
-static struct attribute * zcrypt_device_attrs[] = {
-       &dev_attr_type.attr,
-       &dev_attr_online.attr,
-       NULL,
-};
-
-static struct attribute_group zcrypt_device_attr_group = {
-       .attrs = zcrypt_device_attrs,
-};
+debug_info_t *zcrypt_dbf_common;
+debug_info_t *zcrypt_dbf_devices;
+debug_info_t *zcrypt_dbf_cards;
 
 /**
  * Process a rescan of the transport layer.
@@ -143,174 +94,6 @@ static inline int zcrypt_process_rescan(void)
        return 0;
 }
 
-/**
- * __zcrypt_increase_preference(): Increase preference of a crypto device.
- * @zdev: Pointer the crypto device
- *
- * Move the device towards the head of the device list.
- * Need to be called while holding the zcrypt device list lock.
- * Note: cards with speed_rating of 0 are kept at the end of the list.
- */
-static void __zcrypt_increase_preference(struct zcrypt_device *zdev,
-                                 unsigned int weight)
-{
-       struct zcrypt_device *tmp;
-       struct list_head *l;
-
-       zdev->load -= weight;
-       for (l = zdev->list.prev; l != &zcrypt_device_list; l = l->prev) {
-               tmp = list_entry(l, struct zcrypt_device, list);
-               if (tmp->load <= zdev->load)
-                       break;
-       }
-       if (l == zdev->list.prev)
-               return;
-       /* Move zdev behind l */
-       list_move(&zdev->list, l);
-}
-
-/**
- * __zcrypt_decrease_preference(): Decrease preference of a crypto device.
- * @zdev: Pointer to a crypto device.
- *
- * Move the device towards the tail of the device list.
- * Need to be called while holding the zcrypt device list lock.
- * Note: cards with speed_rating of 0 are kept at the end of the list.
- */
-static void __zcrypt_decrease_preference(struct zcrypt_device *zdev,
-                                 unsigned int weight)
-{
-       struct zcrypt_device *tmp;
-       struct list_head *l;
-
-       zdev->load += weight;
-       for (l = zdev->list.next; l != &zcrypt_device_list; l = l->next) {
-               tmp = list_entry(l, struct zcrypt_device, list);
-               if (tmp->load > zdev->load)
-                       break;
-       }
-       if (l == zdev->list.next)
-               return;
-       /* Move zdev before l */
-       list_move_tail(&zdev->list, l);
-}
-
-static void zcrypt_device_release(struct kref *kref)
-{
-       struct zcrypt_device *zdev =
-               container_of(kref, struct zcrypt_device, refcount);
-       zcrypt_device_free(zdev);
-}
-
-void zcrypt_device_get(struct zcrypt_device *zdev)
-{
-       kref_get(&zdev->refcount);
-}
-EXPORT_SYMBOL(zcrypt_device_get);
-
-int zcrypt_device_put(struct zcrypt_device *zdev)
-{
-       return kref_put(&zdev->refcount, zcrypt_device_release);
-}
-EXPORT_SYMBOL(zcrypt_device_put);
-
-struct zcrypt_device *zcrypt_device_alloc(size_t max_response_size)
-{
-       struct zcrypt_device *zdev;
-
-       zdev = kzalloc(sizeof(struct zcrypt_device), GFP_KERNEL);
-       if (!zdev)
-               return NULL;
-       zdev->reply.message = kmalloc(max_response_size, GFP_KERNEL);
-       if (!zdev->reply.message)
-               goto out_free;
-       zdev->reply.length = max_response_size;
-       spin_lock_init(&zdev->lock);
-       INIT_LIST_HEAD(&zdev->list);
-       zdev->dbf_area = zcrypt_dbf_devices;
-       return zdev;
-
-out_free:
-       kfree(zdev);
-       return NULL;
-}
-EXPORT_SYMBOL(zcrypt_device_alloc);
-
-void zcrypt_device_free(struct zcrypt_device *zdev)
-{
-       kfree(zdev->reply.message);
-       kfree(zdev);
-}
-EXPORT_SYMBOL(zcrypt_device_free);
-
-/**
- * zcrypt_device_register() - Register a crypto device.
- * @zdev: Pointer to a crypto device
- *
- * Register a crypto device. Returns 0 if successful.
- */
-int zcrypt_device_register(struct zcrypt_device *zdev)
-{
-       int rc;
-
-       if (!zdev->ops)
-               return -ENODEV;
-       rc = sysfs_create_group(&zdev->ap_dev->device.kobj,
-                               &zcrypt_device_attr_group);
-       if (rc)
-               goto out;
-       get_device(&zdev->ap_dev->device);
-       kref_init(&zdev->refcount);
-       spin_lock_bh(&zcrypt_device_lock);
-       zdev->online = 1;       /* New devices are online by default. */
-       ZCRYPT_DBF_DEV(DBF_INFO, zdev, "dev%04xo%dreg", zdev->ap_dev->qid,
-                      zdev->online);
-       list_add_tail(&zdev->list, &zcrypt_device_list);
-       __zcrypt_increase_preference(zdev, 0); /* sort devices acc. weight */
-       zcrypt_device_count++;
-       spin_unlock_bh(&zcrypt_device_lock);
-       if (zdev->ops->rng) {
-               rc = zcrypt_rng_device_add();
-               if (rc)
-                       goto out_unregister;
-       }
-       return 0;
-
-out_unregister:
-       spin_lock_bh(&zcrypt_device_lock);
-       zcrypt_device_count--;
-       list_del_init(&zdev->list);
-       spin_unlock_bh(&zcrypt_device_lock);
-       sysfs_remove_group(&zdev->ap_dev->device.kobj,
-                          &zcrypt_device_attr_group);
-       put_device(&zdev->ap_dev->device);
-       zcrypt_device_put(zdev);
-out:
-       return rc;
-}
-EXPORT_SYMBOL(zcrypt_device_register);
-
-/**
- * zcrypt_device_unregister(): Unregister a crypto device.
- * @zdev: Pointer to crypto device
- *
- * Unregister a crypto device.
- */
-void zcrypt_device_unregister(struct zcrypt_device *zdev)
-{
-       if (zdev->ops->rng)
-               zcrypt_rng_device_remove();
-       spin_lock_bh(&zcrypt_device_lock);
-       zcrypt_device_count--;
-       list_del_init(&zdev->list);
-       spin_unlock_bh(&zcrypt_device_lock);
-       sysfs_remove_group(&zdev->ap_dev->device.kobj,
-                          &zcrypt_device_attr_group);
-       put_device(&zdev->ap_dev->device);
-       zcrypt_device_put(zdev);
-}
-EXPORT_SYMBOL(zcrypt_device_unregister);
-
 void zcrypt_msgtype_register(struct zcrypt_ops *zops)
 {
        list_add_tail(&zops->list, &zcrypt_ops_list);
@@ -377,14 +160,44 @@ static int zcrypt_release(struct inode *inode, struct file *filp)
        return 0;
 }
 
+static inline struct zcrypt_queue *zcrypt_pick_queue(struct zcrypt_card *zc,
+                                                    struct zcrypt_queue *zq,
+                                                    unsigned int weight)
+{
+       if (!zq || !try_module_get(zq->queue->ap_dev.drv->driver.owner))
+               return NULL;
+       zcrypt_queue_get(zq);
+       get_device(&zq->queue->ap_dev.device);
+       atomic_add(weight, &zc->load);
+       atomic_add(weight, &zq->load);
+       zq->request_count++;
+       return zq;
+}
+
+static inline void zcrypt_drop_queue(struct zcrypt_card *zc,
+                                    struct zcrypt_queue *zq,
+                                    unsigned int weight)
+{
+       struct module *mod = zq->queue->ap_dev.drv->driver.owner;
+
+       zq->request_count--;
+       atomic_sub(weight, &zc->load);
+       atomic_sub(weight, &zq->load);
+       put_device(&zq->queue->ap_dev.device);
+       zcrypt_queue_put(zq);
+       module_put(mod);
+}
+
 /*
  * zcrypt ioctls.
  */
 static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex)
 {
-       struct zcrypt_device *zdev, *pref_zdev = NULL;
+       struct zcrypt_card *zc, *pref_zc;
+       struct zcrypt_queue *zq, *pref_zq;
+       unsigned int weight, pref_weight;
+       unsigned int func_code;
        int rc;
-       unsigned int weight, func_code, pref_weight = 0;
 
        if (mex->outputdatalength < mex->inputdatalength)
                return -EINVAL;
@@ -399,59 +212,56 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex)
        if (rc)
                return rc;
 
-       spin_lock_bh(&zcrypt_device_lock);
-       list_for_each_entry(zdev, &zcrypt_device_list, list) {
-               if (!zdev->online ||
-                   !zdev->ops->rsa_modexpo ||
-                   zdev->min_mod_size > mex->inputdatalength ||
-                   zdev->max_mod_size < mex->inputdatalength)
+       pref_zc = NULL;
+       pref_zq = NULL;
+       spin_lock(&zcrypt_list_lock);
+       for_each_zcrypt_card(zc) {
+               /* Check for online accelarator and CCA cards */
+               if (!zc->online || !(zc->card->functions & 0x18000000))
                        continue;
-               weight = zdev->speed_rating[func_code];
-               if (!pref_zdev) {
-                       pref_zdev = zdev;
-                       pref_weight = weight;
+               /* Check for size limits */
+               if (zc->min_mod_size > mex->inputdatalength ||
+                   zc->max_mod_size < mex->inputdatalength)
                        continue;
-               }
-               if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) {
-                       pref_zdev = zdev;
-                       pref_weight = weight;
+               /* get weight index of the card device  */
+               weight = zc->speed_rating[func_code];
+               if (pref_zc && atomic_read(&zc->load) + weight >=
+                   atomic_read(&pref_zc->load) + pref_weight)
                        continue;
+               for_each_zcrypt_queue(zq, zc) {
+                       /* check if device is online and eligible */
+                       if (!zq->online)
+                               continue;
+                       if (pref_zq && atomic_read(&zq->load) + weight >=
+                           atomic_read(&pref_zq->load) + pref_weight)
+                               continue;
+                       pref_zc = zc;
+                       pref_zq = zq;
+                       pref_weight = weight;
                }
-               if ((pref_zdev->load + pref_weight) <= zdev->load)
-                       break; /* Load on remaining devices too high - abort */
        }
+       pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, weight);
+       spin_unlock(&zcrypt_list_lock);
 
-       if (!pref_zdev) {
-               spin_unlock_bh(&zcrypt_device_lock);
+       if (!pref_zq)
                return -ENODEV;
-       }
-       __zcrypt_decrease_preference(pref_zdev, pref_weight);
-       zcrypt_device_get(pref_zdev);
-       get_device(&pref_zdev->ap_dev->device);
-       pref_zdev->request_count++;
-       if (try_module_get(pref_zdev->ap_dev->drv->driver.owner)) {
-               spin_unlock_bh(&zcrypt_device_lock);
-               rc = -ENODEV;
-               rc = pref_zdev->ops->rsa_modexpo(pref_zdev, mex);
-               spin_lock_bh(&zcrypt_device_lock);
-               module_put(pref_zdev->ap_dev->drv->driver.owner);
-       } else
-               rc = -EAGAIN;
 
-       pref_zdev->request_count--;
-       __zcrypt_increase_preference(pref_zdev, pref_weight);
-       put_device(&pref_zdev->ap_dev->device);
-       zcrypt_device_put(pref_zdev);
-       spin_unlock_bh(&zcrypt_device_lock);
+       rc = pref_zq->ops->rsa_modexpo(pref_zq, mex);
+
+       spin_lock(&zcrypt_list_lock);
+       zcrypt_drop_queue(pref_zc, pref_zq, weight);
+       spin_unlock(&zcrypt_list_lock);
+
        return rc;
 }
 
 static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt)
 {
-       struct zcrypt_device *zdev, *pref_zdev = NULL;
-       unsigned long long z1, z2, z3;
-       int rc, copied;
-       unsigned int weight, func_code, pref_weight = 0;
+       struct zcrypt_card *zc, *pref_zc;
+       struct zcrypt_queue *zq, *pref_zq;
+       unsigned int weight, pref_weight;
+       unsigned int func_code;
+       int rc;
 
        if (crt->outputdatalength < crt->inputdatalength)
                return -EINVAL;
@@ -466,385 +276,388 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt)
        if (rc)
                return rc;
 
-       copied = 0;
- restart:
-       spin_lock_bh(&zcrypt_device_lock);
-       list_for_each_entry(zdev, &zcrypt_device_list, list) {
-               if (!zdev->online ||
-                   !zdev->ops->rsa_modexpo_crt ||
-                   zdev->min_mod_size > crt->inputdatalength ||
-                   zdev->max_mod_size < crt->inputdatalength)
+       pref_zc = NULL;
+       pref_zq = NULL;
+       spin_lock(&zcrypt_list_lock);
+       for_each_zcrypt_card(zc) {
+               /* Check for online accelarator and CCA cards */
+               if (!zc->online || !(zc->card->functions & 0x18000000))
                        continue;
-               if (zdev->short_crt && crt->inputdatalength > 240) {
-                       /*
-                        * Check inputdata for leading zeros for cards
-                        * that can't handle np_prime, bp_key, or
-                        * u_mult_inv > 128 bytes.
-                        */
-                       if (copied == 0) {
-                               unsigned int len;
-                               spin_unlock_bh(&zcrypt_device_lock);
-                               /* len is max 256 / 2 - 120 = 8
-                                * For bigger device just assume len of leading
-                                * 0s is 8 as stated in the requirements for
-                                * ica_rsa_modexpo_crt struct in zcrypt.h.
-                                */
-                               if (crt->inputdatalength <= 256)
-                                       len = crt->inputdatalength / 2 - 120;
-                               else
-                                       len = 8;
-                               if (len > sizeof(z1))
-                                       return -EFAULT;
-                               z1 = z2 = z3 = 0;
-                               if (copy_from_user(&z1, crt->np_prime, len) ||
-                                   copy_from_user(&z2, crt->bp_key, len) ||
-                                   copy_from_user(&z3, crt->u_mult_inv, len))
-                                       return -EFAULT;
-                               z1 = z2 = z3 = 0;
-                               copied = 1;
-                               /*
-                                * We have to restart device lookup -
-                                * the device list may have changed by now.
-                                */
-                               goto restart;
-                       }
-                       if (z1 != 0ULL || z2 != 0ULL || z3 != 0ULL)
-                               /* The device can't handle this request. */
-                               continue;
-               }
-
-               weight = zdev->speed_rating[func_code];
-               if (!pref_zdev) {
-                       pref_zdev = zdev;
-                       pref_weight = weight;
+               /* Check for size limits */
+               if (zc->min_mod_size > crt->inputdatalength ||
+                   zc->max_mod_size < crt->inputdatalength)
                        continue;
-               }
-               if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) {
-                       pref_zdev = zdev;
-                       pref_weight = weight;
+               /* get weight index of the card device  */
+               weight = zc->speed_rating[func_code];
+               if (pref_zc && atomic_read(&zc->load) + weight >=
+                   atomic_read(&pref_zc->load) + pref_weight)
                        continue;
+               for_each_zcrypt_queue(zq, zc) {
+                       /* check if device is online and eligible */
+                       if (!zq->online)
+                               continue;
+                       if (pref_zq && atomic_read(&zq->load) + weight >=
+                           atomic_read(&pref_zq->load) + pref_weight)
+                               continue;
+                       pref_zc = zc;
+                       pref_zq = zq;
+                       pref_weight = weight;
                }
-               if ((pref_zdev->load + pref_weight) <= zdev->load)
-                       break; /* Load on remaining devices too high - abort */
        }
-       if (!pref_zdev) {
-               spin_unlock_bh(&zcrypt_device_lock);
+       pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, weight);
+       spin_unlock(&zcrypt_list_lock);
+
+       if (!pref_zq)
                return -ENODEV;
-       }
-       __zcrypt_decrease_preference(pref_zdev, pref_weight);
-       zcrypt_device_get(pref_zdev);
-       get_device(&pref_zdev->ap_dev->device);
-       pref_zdev->request_count++;
-       if (try_module_get(pref_zdev->ap_dev->drv->driver.owner)) {
-               spin_unlock_bh(&zcrypt_device_lock);
-               rc = pref_zdev->ops->rsa_modexpo_crt(pref_zdev, crt);
-               spin_lock_bh(&zcrypt_device_lock);
-               module_put(pref_zdev->ap_dev->drv->driver.owner);
-       } else
-               rc = -EAGAIN;
-       pref_zdev->request_count--;
-       __zcrypt_increase_preference(pref_zdev, pref_weight);
-       put_device(&pref_zdev->ap_dev->device);
-       zcrypt_device_put(pref_zdev);
-       spin_unlock_bh(&zcrypt_device_lock);
+
+       rc = pref_zq->ops->rsa_modexpo_crt(pref_zq, crt);
+
+       spin_lock(&zcrypt_list_lock);
+       zcrypt_drop_queue(pref_zc, pref_zq, weight);
+       spin_unlock(&zcrypt_list_lock);
+
        return rc;
 }
 
 static long zcrypt_send_cprb(struct ica_xcRB *xcRB)
 {
-       struct zcrypt_device *zdev, *pref_zdev = NULL;
-       unsigned int weight = 0, func_code = 0, pref_weight = 0;
-       int rc;
+       struct zcrypt_card *zc, *pref_zc;
+       struct zcrypt_queue *zq, *pref_zq;
        struct ap_message ap_msg;
+       unsigned int weight, pref_weight;
+       unsigned int func_code;
+       unsigned short *domain;
+       int rc;
 
-       rc = get_cprb_fc(xcRB, &ap_msg, &func_code);
+       rc = get_cprb_fc(xcRB, &ap_msg, &func_code, &domain);
        if (rc)
                return rc;
 
-       spin_lock_bh(&zcrypt_device_lock);
-       list_for_each_entry(zdev, &zcrypt_device_list, list) {
-               if (!zdev->online || !zdev->ops->send_cprb ||
-                  (zdev->ops->variant == MSGTYPE06_VARIANT_EP11) ||
-                  (xcRB->user_defined != AUTOSELECT &&
-                   AP_QID_DEVICE(zdev->ap_dev->qid) != xcRB->user_defined))
+       pref_zc = NULL;
+       pref_zq = NULL;
+       spin_lock(&zcrypt_list_lock);
+       for_each_zcrypt_card(zc) {
+               /* Check for online CCA cards */
+               if (!zc->online || !(zc->card->functions & 0x10000000))
                        continue;
-
-               weight = speed_idx_cca(func_code) * zdev->speed_rating[SECKEY];
-               if (!pref_zdev) {
-                       pref_zdev = zdev;
-                       pref_weight = weight;
+               /* Check for user selected CCA card */
+               if (xcRB->user_defined != AUTOSELECT &&
+                   xcRB->user_defined != zc->card->id)
                        continue;
-               }
-               if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) {
-                       pref_zdev = zdev;
-                       pref_weight = weight;
+               /* get weight index of the card device  */
+               weight = speed_idx_cca(func_code) * zc->speed_rating[SECKEY];
+               if (pref_zc && atomic_read(&zc->load) + weight >=
+                   atomic_read(&pref_zc->load) + pref_weight)
                        continue;
+               for_each_zcrypt_queue(zq, zc) {
+                       /* check if device is online and eligible */
+                       if (!zq->online ||
+                           ((*domain != (unsigned short) AUTOSELECT) &&
+                            (*domain != AP_QID_QUEUE(zq->queue->qid))))
+                               continue;
+                       if (pref_zq && atomic_read(&zq->load) + weight >=
+                           atomic_read(&pref_zq->load) + pref_weight)
+                               continue;
+                       pref_zc = zc;
+                       pref_zq = zq;
+                       pref_weight = weight;
                }
-               if ((pref_zdev->load + pref_weight) <= zdev->load)
-                       break; /* Load on remaining devices too high - abort */
        }
-       if (!pref_zdev) {
-               spin_unlock_bh(&zcrypt_device_lock);
+       pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, weight);
+       spin_unlock(&zcrypt_list_lock);
+
+       if (!pref_zq)
                return -ENODEV;
-       }
-       __zcrypt_decrease_preference(pref_zdev, pref_weight);
-       zcrypt_device_get(pref_zdev);
-       get_device(&pref_zdev->ap_dev->device);
-       pref_zdev->request_count++;
-       if (try_module_get(pref_zdev->ap_dev->drv->driver.owner)) {
-               spin_unlock_bh(&zcrypt_device_lock);
-               rc = pref_zdev->ops->send_cprb(pref_zdev, xcRB, &ap_msg);
-               spin_lock_bh(&zcrypt_device_lock);
-               module_put(pref_zdev->ap_dev->drv->driver.owner);
-       } else
-               rc = -EAGAIN;
-       pref_zdev->request_count--;
-       __zcrypt_increase_preference(pref_zdev, pref_weight);
-       put_device(&pref_zdev->ap_dev->device);
-       zcrypt_device_put(pref_zdev);
-       spin_unlock_bh(&zcrypt_device_lock);
+
+       /* in case of auto select, provide the correct domain */
+       if (*domain == (unsigned short) AUTOSELECT)
+               *domain = AP_QID_QUEUE(pref_zq->queue->qid);
+
+       rc = pref_zq->ops->send_cprb(pref_zq, xcRB, &ap_msg);
+
+       spin_lock(&zcrypt_list_lock);
+       zcrypt_drop_queue(pref_zc, pref_zq, weight);
+       spin_unlock(&zcrypt_list_lock);
        return rc;
 }
 
-struct ep11_target_dev_list {
-       unsigned short          targets_num;
-       struct ep11_target_dev  *targets;
-};
-
-static bool is_desired_ep11dev(unsigned int dev_qid,
-                              struct ep11_target_dev_list dev_list)
+static bool is_desired_ep11_card(unsigned int dev_id,
+                                unsigned short target_num,
+                                struct ep11_target_dev *targets)
 {
-       int n;
+       while (target_num-- > 0) {
+               if (dev_id == targets->ap_id)
+                       return true;
+               targets++;
+       }
+       return false;
+}
 
-       for (n = 0; n < dev_list.targets_num; n++, dev_list.targets++) {
-               if ((AP_QID_DEVICE(dev_qid) == dev_list.targets->ap_id) &&
-                   (AP_QID_QUEUE(dev_qid) == dev_list.targets->dom_id)) {
+static bool is_desired_ep11_queue(unsigned int dev_qid,
+                                 unsigned short target_num,
+                                 struct ep11_target_dev *targets)
+{
+       while (target_num-- > 0) {
+               if (AP_MKQID(targets->ap_id, targets->dom_id) == dev_qid)
                        return true;
-               }
+               targets++;
        }
        return false;
 }
 
 static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb)
 {
-       struct zcrypt_device *zdev, *pref_zdev = NULL;
+       struct zcrypt_card *zc, *pref_zc;
+       struct zcrypt_queue *zq, *pref_zq;
+       struct ep11_target_dev *targets;
+       unsigned short target_num;
+       unsigned int weight, pref_weight;
+       unsigned int func_code;
        struct ap_message ap_msg;
-       unsigned int weight = 0, func_code = 0, pref_weight = 0;
-       bool autoselect = false;
        int rc;
-       struct ep11_target_dev_list ep11_dev_list = {
-               .targets_num    =  0x00,
-               .targets        =  NULL,
-       };
 
-       ep11_dev_list.targets_num = (unsigned short) xcrb->targets_num;
+       target_num = (unsigned short) xcrb->targets_num;
 
        /* empty list indicates autoselect (all available targets) */
-       if (ep11_dev_list.targets_num == 0)
-               autoselect = true;
-       else {
-               ep11_dev_list.targets = kcalloc((unsigned short)
-                                               xcrb->targets_num,
-                                               sizeof(struct ep11_target_dev),
-                                               GFP_KERNEL);
-               if (!ep11_dev_list.targets)
+       targets = NULL;
+       if (target_num != 0) {
+               struct ep11_target_dev __user *uptr;
+
+               targets = kcalloc(target_num, sizeof(*targets), GFP_KERNEL);
+               if (!targets)
                        return -ENOMEM;
 
-               if (copy_from_user(ep11_dev_list.targets,
-                                  (struct ep11_target_dev __force __user *)
-                                  xcrb->targets, xcrb->targets_num *
-                                  sizeof(struct ep11_target_dev)))
+               uptr = (struct ep11_target_dev __force __user *) xcrb->targets;
+               if (copy_from_user(targets, uptr,
+                                  target_num * sizeof(*targets)))
                        return -EFAULT;
        }
 
        rc = get_ep11cprb_fc(xcrb, &ap_msg, &func_code);
        if (rc)
-               return rc;
+               goto out_free;
 
-       spin_lock_bh(&zcrypt_device_lock);
-       list_for_each_entry(zdev, &zcrypt_device_list, list) {
-               /* check if device is eligible */
-               if (!zdev->online ||
-                   zdev->ops->variant != MSGTYPE06_VARIANT_EP11)
+       pref_zc = NULL;
+       pref_zq = NULL;
+       spin_lock(&zcrypt_list_lock);
+       for_each_zcrypt_card(zc) {
+               /* Check for online EP11 cards */
+               if (!zc->online || !(zc->card->functions & 0x04000000))
                        continue;
-
-               /* check if device is selected as valid target */
-               if (!is_desired_ep11dev(zdev->ap_dev->qid, ep11_dev_list) &&
-                   !autoselect)
+               /* Check for user selected EP11 card */
+               if (targets &&
+                   !is_desired_ep11_card(zc->card->id, target_num, targets))
                        continue;
-
-               weight = speed_idx_ep11(func_code) * zdev->speed_rating[SECKEY];
-               if (!pref_zdev) {
-                       pref_zdev = zdev;
-                       pref_weight = weight;
+               /* get weight index of the card device  */
+               weight = speed_idx_ep11(func_code) * zc->speed_rating[SECKEY];
+               if (pref_zc && atomic_read(&zc->load) + weight >=
+                   atomic_read(&pref_zc->load) + pref_weight)
                        continue;
-               }
-               if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) {
-                       pref_zdev = zdev;
+               for_each_zcrypt_queue(zq, zc) {
+                       /* check if device is online and eligible */
+                       if (!zq->online ||
+                           (targets &&
+                            !is_desired_ep11_queue(zq->queue->qid,
+                                                   target_num, targets)))
+                               continue;
+                       if (pref_zq && atomic_read(&zq->load) + weight >=
+                           atomic_read(&pref_zq->load) + pref_weight)
+                               continue;
+                       pref_zc = zc;
+                       pref_zq = zq;
                        pref_weight = weight;
-                       continue;
                }
-               if ((pref_zdev->load + pref_weight) <= zdev->load)
-                       break; /* Load on remaining devices too high - abort */
-       }
-       if (!pref_zdev) {
-               spin_unlock_bh(&zcrypt_device_lock);
-               return -ENODEV;
        }
+       pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, weight);
+       spin_unlock(&zcrypt_list_lock);
 
-       zcrypt_device_get(pref_zdev);
-       get_device(&pref_zdev->ap_dev->device);
-       pref_zdev->request_count++;
-       if (try_module_get(pref_zdev->ap_dev->drv->driver.owner)) {
-               spin_unlock_bh(&zcrypt_device_lock);
-               rc = pref_zdev->ops->send_ep11_cprb(pref_zdev, xcrb, &ap_msg);
-               spin_lock_bh(&zcrypt_device_lock);
-               module_put(pref_zdev->ap_dev->drv->driver.owner);
-       } else {
-               rc = -EAGAIN;
+       if (!pref_zq) {
+               rc = -ENODEV;
+               goto out_free;
        }
-       pref_zdev->request_count--;
-       put_device(&pref_zdev->ap_dev->device);
-       zcrypt_device_put(pref_zdev);
-       spin_unlock_bh(&zcrypt_device_lock);
+
+       rc = pref_zq->ops->send_ep11_cprb(pref_zq, xcrb, &ap_msg);
+
+       spin_lock(&zcrypt_list_lock);
+       zcrypt_drop_queue(pref_zc, pref_zq, weight);
+       spin_unlock(&zcrypt_list_lock);
+
+out_free:
+       kfree(targets);
        return rc;
 }
 
 static long zcrypt_rng(char *buffer)
 {
-       struct zcrypt_device *zdev, *pref_zdev = NULL;
+       struct zcrypt_card *zc, *pref_zc;
+       struct zcrypt_queue *zq, *pref_zq;
+       unsigned int weight, pref_weight;
+       unsigned int func_code;
        struct ap_message ap_msg;
-       unsigned int weight = 0, func_code = 0, pref_weight = 0;
+       unsigned int domain;
        int rc;
 
-       rc = get_rng_fc(&ap_msg, &func_code);
+       rc = get_rng_fc(&ap_msg, &func_code, &domain);
        if (rc)
                return rc;
 
-       spin_lock_bh(&zcrypt_device_lock);
-       list_for_each_entry(zdev, &zcrypt_device_list, list) {
-               if (!zdev->online || !zdev->ops->rng)
+       pref_zc = NULL;
+       pref_zq = NULL;
+       spin_lock(&zcrypt_list_lock);
+       for_each_zcrypt_card(zc) {
+               /* Check for online CCA cards */
+               if (!zc->online || !(zc->card->functions & 0x10000000))
                        continue;
-
-               weight = zdev->speed_rating[func_code];
-               if (!pref_zdev) {
-                       pref_zdev = zdev;
-                       pref_weight = weight;
+               /* get weight index of the card device  */
+               weight = zc->speed_rating[func_code];
+               if (pref_zc && atomic_read(&zc->load) + weight >=
+                   atomic_read(&pref_zc->load) + pref_weight)
                        continue;
-               }
-               if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) {
-                       pref_zdev = zdev;
+               for_each_zcrypt_queue(zq, zc) {
+                       /* check if device is online and eligible */
+                       if (!zq->online)
+                               continue;
+                       if (pref_zq && atomic_read(&zq->load) + weight >=
+                           atomic_read(&pref_zq->load) + pref_weight)
+                               continue;
+                       pref_zc = zc;
+                       pref_zq = zq;
                        pref_weight = weight;
-                       continue;
                }
-               if ((pref_zdev->load + pref_weight) <= zdev->load)
-                       break; /* Load on remaining devices too high - abort */
        }
-       if (!pref_zdev) {
-               spin_unlock_bh(&zcrypt_device_lock);
+       pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, weight);
+       spin_unlock(&zcrypt_list_lock);
+
+       if (!pref_zq)
                return -ENODEV;
-       }
 
-       zcrypt_device_get(pref_zdev);
-       get_device(&pref_zdev->ap_dev->device);
-       pref_zdev->request_count++;
-       if (try_module_get(pref_zdev->ap_dev->drv->driver.owner)) {
-               spin_unlock_bh(&zcrypt_device_lock);
-               rc = pref_zdev->ops->rng(pref_zdev, buffer, &ap_msg);
-               spin_lock_bh(&zcrypt_device_lock);
-               module_put(pref_zdev->ap_dev->drv->driver.owner);
-       } else
-               rc = -EAGAIN;
-       pref_zdev->request_count--;
-       put_device(&pref_zdev->ap_dev->device);
-       zcrypt_device_put(pref_zdev);
-       spin_unlock_bh(&zcrypt_device_lock);
+       rc = pref_zq->ops->rng(pref_zq, buffer, &ap_msg);
+
+       spin_lock(&zcrypt_list_lock);
+       zcrypt_drop_queue(pref_zc, pref_zq, weight);
+       spin_unlock(&zcrypt_list_lock);
        return rc;
 }
 
 static void zcrypt_status_mask(char status[AP_DEVICES])
 {
-       struct zcrypt_device *zdev;
+       struct zcrypt_card *zc;
+       struct zcrypt_queue *zq;
 
        memset(status, 0, sizeof(char) * AP_DEVICES);
-       spin_lock_bh(&zcrypt_device_lock);
-       list_for_each_entry(zdev, &zcrypt_device_list, list)
-               status[AP_QID_DEVICE(zdev->ap_dev->qid)] =
-                       zdev->online ? zdev->user_space_type : 0x0d;
-       spin_unlock_bh(&zcrypt_device_lock);
+       spin_lock(&zcrypt_list_lock);
+       for_each_zcrypt_card(zc) {
+               for_each_zcrypt_queue(zq, zc) {
+                       if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index)
+                               continue;
+                       status[AP_QID_CARD(zq->queue->qid)] =
+                               zc->online ? zc->user_space_type : 0x0d;
+               }
+       }
+       spin_unlock(&zcrypt_list_lock);
 }
 
 static void zcrypt_qdepth_mask(char qdepth[AP_DEVICES])
 {
-       struct zcrypt_device *zdev;
+       struct zcrypt_card *zc;
+       struct zcrypt_queue *zq;
 
        memset(qdepth, 0, sizeof(char)  * AP_DEVICES);
-       spin_lock_bh(&zcrypt_device_lock);
-       list_for_each_entry(zdev, &zcrypt_device_list, list) {
-               spin_lock(&zdev->ap_dev->lock);
-               qdepth[AP_QID_DEVICE(zdev->ap_dev->qid)] =
-                       zdev->ap_dev->pendingq_count +
-                       zdev->ap_dev->requestq_count;
-               spin_unlock(&zdev->ap_dev->lock);
+       spin_lock(&zcrypt_list_lock);
+       for_each_zcrypt_card(zc) {
+               for_each_zcrypt_queue(zq, zc) {
+                       if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index)
+                               continue;
+                       spin_lock(&zq->queue->lock);
+                       qdepth[AP_QID_CARD(zq->queue->qid)] =
+                               zq->queue->pendingq_count +
+                               zq->queue->requestq_count;
+                       spin_unlock(&zq->queue->lock);
+               }
        }
-       spin_unlock_bh(&zcrypt_device_lock);
+       spin_unlock(&zcrypt_list_lock);
 }
 
 static void zcrypt_perdev_reqcnt(int reqcnt[AP_DEVICES])
 {
-       struct zcrypt_device *zdev;
+       struct zcrypt_card *zc;
+       struct zcrypt_queue *zq;
 
        memset(reqcnt, 0, sizeof(int) * AP_DEVICES);
-       spin_lock_bh(&zcrypt_device_lock);
-       list_for_each_entry(zdev, &zcrypt_device_list, list) {
-               spin_lock(&zdev->ap_dev->lock);
-               reqcnt[AP_QID_DEVICE(zdev->ap_dev->qid)] =
-                       zdev->ap_dev->total_request_count;
-               spin_unlock(&zdev->ap_dev->lock);
+       spin_lock(&zcrypt_list_lock);
+       for_each_zcrypt_card(zc) {
+               for_each_zcrypt_queue(zq, zc) {
+                       if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index)
+                               continue;
+                       spin_lock(&zq->queue->lock);
+                       reqcnt[AP_QID_CARD(zq->queue->qid)] =
+                               zq->queue->total_request_count;
+                       spin_unlock(&zq->queue->lock);
+               }
        }
-       spin_unlock_bh(&zcrypt_device_lock);
+       spin_unlock(&zcrypt_list_lock);
 }
 
 static int zcrypt_pendingq_count(void)
 {
-       struct zcrypt_device *zdev;
-       int pendingq_count = 0;
-
-       spin_lock_bh(&zcrypt_device_lock);
-       list_for_each_entry(zdev, &zcrypt_device_list, list) {
-               spin_lock(&zdev->ap_dev->lock);
-               pendingq_count += zdev->ap_dev->pendingq_count;
-               spin_unlock(&zdev->ap_dev->lock);
+       struct zcrypt_card *zc;
+       struct zcrypt_queue *zq;
+       int pendingq_count;
+
+       pendingq_count = 0;
+       spin_lock(&zcrypt_list_lock);
+       for_each_zcrypt_card(zc) {
+               for_each_zcrypt_queue(zq, zc) {
+                       if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index)
+                               continue;
+                       spin_lock(&zq->queue->lock);
+                       pendingq_count += zq->queue->pendingq_count;
+                       spin_unlock(&zq->queue->lock);
+               }
        }
-       spin_unlock_bh(&zcrypt_device_lock);
+       spin_unlock(&zcrypt_list_lock);
        return pendingq_count;
 }
 
 static int zcrypt_requestq_count(void)
 {
-       struct zcrypt_device *zdev;
-       int requestq_count = 0;
-
-       spin_lock_bh(&zcrypt_device_lock);
-       list_for_each_entry(zdev, &zcrypt_device_list, list) {
-               spin_lock(&zdev->ap_dev->lock);
-               requestq_count += zdev->ap_dev->requestq_count;
-               spin_unlock(&zdev->ap_dev->lock);
+       struct zcrypt_card *zc;
+       struct zcrypt_queue *zq;
+       int requestq_count;
+
+       requestq_count = 0;
+       spin_lock(&zcrypt_list_lock);
+       for_each_zcrypt_card(zc) {
+               for_each_zcrypt_queue(zq, zc) {
+                       if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index)
+                               continue;
+                       spin_lock(&zq->queue->lock);
+                       requestq_count += zq->queue->requestq_count;
+                       spin_unlock(&zq->queue->lock);
+               }
        }
-       spin_unlock_bh(&zcrypt_device_lock);
+       spin_unlock(&zcrypt_list_lock);
        return requestq_count;
 }
 
 static int zcrypt_count_type(int type)
 {
-       struct zcrypt_device *zdev;
-       int device_count = 0;
-
-       spin_lock_bh(&zcrypt_device_lock);
-       list_for_each_entry(zdev, &zcrypt_device_list, list)
-               if (zdev->user_space_type == type)
+       struct zcrypt_card *zc;
+       struct zcrypt_queue *zq;
+       int device_count;
+
+       device_count = 0;
+       spin_lock(&zcrypt_list_lock);
+       for_each_zcrypt_card(zc) {
+               if (zc->card->id != type)
+                       continue;
+               for_each_zcrypt_queue(zq, zc) {
+                       if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index)
+                               continue;
                        device_count++;
-       spin_unlock_bh(&zcrypt_device_lock);
+               }
+       }
+       spin_unlock(&zcrypt_list_lock);
        return device_count;
 }
 
@@ -1313,29 +1126,36 @@ static int zcrypt_proc_open(struct inode *inode, struct file *file)
 
 static void zcrypt_disable_card(int index)
 {
-       struct zcrypt_device *zdev;
+       struct zcrypt_card *zc;
+       struct zcrypt_queue *zq;
 
-       spin_lock_bh(&zcrypt_device_lock);
-       list_for_each_entry(zdev, &zcrypt_device_list, list)
-               if (AP_QID_DEVICE(zdev->ap_dev->qid) == index) {
-                       zdev->online = 0;
-                       ap_flush_queue(zdev->ap_dev);
-                       break;
+       spin_lock(&zcrypt_list_lock);
+       for_each_zcrypt_card(zc) {
+               for_each_zcrypt_queue(zq, zc) {
+                       if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index)
+                               continue;
+                       zq->online = 0;
+                       ap_flush_queue(zq->queue);
                }
-       spin_unlock_bh(&zcrypt_device_lock);
+       }
+       spin_unlock(&zcrypt_list_lock);
 }
 
 static void zcrypt_enable_card(int index)
 {
-       struct zcrypt_device *zdev;
+       struct zcrypt_card *zc;
+       struct zcrypt_queue *zq;
 
-       spin_lock_bh(&zcrypt_device_lock);
-       list_for_each_entry(zdev, &zcrypt_device_list, list)
-               if (AP_QID_DEVICE(zdev->ap_dev->qid) == index) {
-                       zdev->online = 1;
-                       break;
+       spin_lock(&zcrypt_list_lock);
+       for_each_zcrypt_card(zc) {
+               for_each_zcrypt_queue(zq, zc) {
+                       if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index)
+                               continue;
+                       zq->online = 1;
+                       ap_flush_queue(zq->queue);
                }
-       spin_unlock_bh(&zcrypt_device_lock);
+       }
+       spin_unlock(&zcrypt_list_lock);
 }
 
 static ssize_t zcrypt_proc_write(struct file *file, const char __user *buffer,
@@ -1433,7 +1253,7 @@ static struct hwrng zcrypt_rng_dev = {
        .quality        = 990,
 };
 
-static int zcrypt_rng_device_add(void)
+int zcrypt_rng_device_add(void)
 {
        int rc = 0;
 
@@ -1463,7 +1283,7 @@ out:
        return rc;
 }
 
-static void zcrypt_rng_device_remove(void)
+void zcrypt_rng_device_remove(void)
 {
        mutex_lock(&zcrypt_rng_mutex);
        zcrypt_rng_device_count--;
@@ -1486,6 +1306,10 @@ int __init zcrypt_debug_init(void)
        debug_register_view(zcrypt_dbf_devices, &debug_hex_ascii_view);
        debug_set_level(zcrypt_dbf_devices, DBF_ERR);
 
+       zcrypt_dbf_cards = debug_register("zcrypt_cards", 1, 1, 16);
+       debug_register_view(zcrypt_dbf_cards, &debug_hex_ascii_view);
+       debug_set_level(zcrypt_dbf_cards, DBF_ERR);
+
        return 0;
 }
 
@@ -1517,7 +1341,8 @@ int __init zcrypt_api_init(void)
                goto out;
 
        /* Set up the proc file system */
-       zcrypt_entry = proc_create("driver/z90crypt", 0644, NULL, &zcrypt_proc_fops);
+       zcrypt_entry = proc_create("driver/z90crypt", 0644, NULL,
+                                  &zcrypt_proc_fops);
        if (!zcrypt_entry) {
                rc = -ENOMEM;
                goto out_misc;
index 3d0d1e25d751d1931e568cb140d5982d2c3aa0db..4fb892b99f41ccfb26796e43ac67a22835f66e6d 100644 (file)
@@ -88,7 +88,7 @@ struct ica_z90_status {
  * Identifier for Crypto Request Performance Index
  */
 enum crypto_ops {
-       MEX_1K = 0,
+       MEX_1K,
        MEX_2K,
        MEX_4K,
        CRT_1K,
@@ -99,43 +99,56 @@ enum crypto_ops {
        NUM_OPS
 };
 
-struct zcrypt_device;
+struct zcrypt_queue;
 
 struct zcrypt_ops {
-       long (*rsa_modexpo)(struct zcrypt_device *, struct ica_rsa_modexpo *);
-       long (*rsa_modexpo_crt)(struct zcrypt_device *,
+       long (*rsa_modexpo)(struct zcrypt_queue *, struct ica_rsa_modexpo *);
+       long (*rsa_modexpo_crt)(struct zcrypt_queue *,
                                struct ica_rsa_modexpo_crt *);
-       long (*send_cprb)(struct zcrypt_device *, struct ica_xcRB *,
+       long (*send_cprb)(struct zcrypt_queue *, struct ica_xcRB *,
                          struct ap_message *);
-       long (*send_ep11_cprb)(struct zcrypt_device *, struct ep11_urb *,
+       long (*send_ep11_cprb)(struct zcrypt_queue *, struct ep11_urb *,
                               struct ap_message *);
-       long (*rng)(struct zcrypt_device *, char *, struct ap_message *);
+       long (*rng)(struct zcrypt_queue *, char *, struct ap_message *);
        struct list_head list;          /* zcrypt ops list. */
        struct module *owner;
        int variant;
        char name[128];
 };
 
-struct zcrypt_device {
+struct zcrypt_card {
        struct list_head list;          /* Device list. */
-       spinlock_t lock;                /* Per device lock. */
+       struct list_head zqueues;       /* List of zcrypt queues */
        struct kref refcount;           /* device refcounting */
-       struct ap_device *ap_dev;       /* The "real" ap device. */
-       struct zcrypt_ops *ops;         /* Crypto operations. */
+       struct ap_card *card;           /* The "real" ap card device. */
        int online;                     /* User online/offline */
 
        int user_space_type;            /* User space device id. */
        char *type_string;              /* User space device name. */
        int min_mod_size;               /* Min number of bits. */
        int max_mod_size;               /* Max number of bits. */
-       int short_crt;                  /* Card has crt length restriction. */
+       int max_exp_bit_length;
        int speed_rating[NUM_OPS];      /* Speed idx of crypto ops. */
-       int load;                       /* Utilization of the crypto device */
+       atomic_t load;                  /* Utilization of the crypto device */
+
+       int request_count;              /* # current requests. */
+
+       debug_info_t *dbf_area;         /* debugging */
+};
+
+struct zcrypt_queue {
+       struct list_head list;          /* Device list. */
+       struct kref refcount;           /* device refcounting */
+       struct zcrypt_card *zcard;
+       struct zcrypt_ops *ops;         /* Crypto operations. */
+       struct ap_queue *queue;         /* The "real" ap queue device. */
+       int online;                     /* User online/offline */
+
+       atomic_t load;                  /* Utilization of the crypto device */
 
        int request_count;              /* # current requests. */
 
        struct ap_message reply;        /* Per-device reply structure. */
-       int max_exp_bit_length;
 
        debug_info_t *dbf_area;         /* debugging */
 };
@@ -143,12 +156,43 @@ struct zcrypt_device {
 /* transport layer rescanning */
 extern atomic_t zcrypt_rescan_req;
 
-struct zcrypt_device *zcrypt_device_alloc(size_t);
-void zcrypt_device_free(struct zcrypt_device *);
-void zcrypt_device_get(struct zcrypt_device *);
-int zcrypt_device_put(struct zcrypt_device *);
-int zcrypt_device_register(struct zcrypt_device *);
-void zcrypt_device_unregister(struct zcrypt_device *);
+extern spinlock_t zcrypt_list_lock;
+extern int zcrypt_device_count;
+extern struct list_head zcrypt_card_list;
+
+extern debug_info_t *zcrypt_dbf_common;
+extern debug_info_t *zcrypt_dbf_devices;
+extern debug_info_t *zcrypt_dbf_cards;
+
+#define for_each_zcrypt_card(_zc) \
+       list_for_each_entry(_zc, &zcrypt_card_list, list)
+
+#define for_each_zcrypt_queue(_zq, _zc) \
+       list_for_each_entry(_zq, &(_zc)->zqueues, list)
+
+struct zcrypt_card *zcrypt_card_alloc(void);
+void zcrypt_card_free(struct zcrypt_card *);
+void zcrypt_card_get(struct zcrypt_card *);
+int zcrypt_card_put(struct zcrypt_card *);
+int zcrypt_card_register(struct zcrypt_card *);
+void zcrypt_card_unregister(struct zcrypt_card *);
+struct zcrypt_card *zcrypt_card_get_best(unsigned int *,
+                                        unsigned int, unsigned int);
+void zcrypt_card_put_best(struct zcrypt_card *, unsigned int);
+
+struct zcrypt_queue *zcrypt_queue_alloc(size_t);
+void zcrypt_queue_free(struct zcrypt_queue *);
+void zcrypt_queue_get(struct zcrypt_queue *);
+int zcrypt_queue_put(struct zcrypt_queue *);
+int zcrypt_queue_register(struct zcrypt_queue *);
+void zcrypt_queue_unregister(struct zcrypt_queue *);
+void zcrypt_queue_force_online(struct zcrypt_queue *, int);
+struct zcrypt_queue *zcrypt_queue_get_best(unsigned int, unsigned int);
+void  zcrypt_queue_put_best(struct zcrypt_queue *, unsigned int);
+
+int zcrypt_rng_device_add(void);
+void zcrypt_rng_device_remove(void);
+
 void zcrypt_msgtype_register(struct zcrypt_ops *);
 void zcrypt_msgtype_unregister(struct zcrypt_ops *);
 struct zcrypt_ops *zcrypt_msgtype(unsigned char *, int);
diff --git a/drivers/s390/crypto/zcrypt_card.c b/drivers/s390/crypto/zcrypt_card.c
new file mode 100644 (file)
index 0000000..57873d7
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ *  zcrypt 2.1.0
+ *
+ *  Copyright IBM Corp. 2001, 2012
+ *  Author(s): Robert Burroughs
+ *            Eric Rossman (edrossma@us.ibm.com)
+ *            Cornelia Huck <cornelia.huck@de.ibm.com>
+ *
+ *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ *  Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *                               Ralph Wuerthner <rwuerthn@de.ibm.com>
+ *  MSGTYPE restruct:            Holger Dengler <hd@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/compat.h>
+#include <linux/slab.h>
+#include <linux/atomic.h>
+#include <linux/uaccess.h>
+#include <linux/hw_random.h>
+#include <linux/debugfs.h>
+#include <asm/debug.h>
+
+#include "zcrypt_debug.h"
+#include "zcrypt_api.h"
+
+#include "zcrypt_msgtype6.h"
+#include "zcrypt_msgtype50.h"
+
+/*
+ * Device attributes common for all crypto card devices.
+ */
+
+static ssize_t zcrypt_card_type_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       struct zcrypt_card *zc = to_ap_card(dev)->private;
+
+       return snprintf(buf, PAGE_SIZE, "%s\n", zc->type_string);
+}
+
+static DEVICE_ATTR(type, 0444, zcrypt_card_type_show, NULL);
+
+static ssize_t zcrypt_card_online_show(struct device *dev,
+                                      struct device_attribute *attr,
+                                      char *buf)
+{
+       struct zcrypt_card *zc = to_ap_card(dev)->private;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", zc->online);
+}
+
+static ssize_t zcrypt_card_online_store(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       struct zcrypt_card *zc = to_ap_card(dev)->private;
+       struct zcrypt_queue *zq;
+       int online, id;
+
+       if (sscanf(buf, "%d\n", &online) != 1 || online < 0 || online > 1)
+               return -EINVAL;
+
+       zc->online = online;
+       id = zc->card->id;
+       ZCRYPT_DBF_DEV(DBF_INFO, zc, "card%02xo%dman", id, online);
+       spin_lock(&zcrypt_list_lock);
+       list_for_each_entry(zq, &zc->zqueues, list)
+               zcrypt_queue_force_online(zq, online);
+       spin_unlock(&zcrypt_list_lock);
+       return count;
+}
+
+static DEVICE_ATTR(online, 0644, zcrypt_card_online_show,
+                  zcrypt_card_online_store);
+
+static struct attribute *zcrypt_card_attrs[] = {
+       &dev_attr_type.attr,
+       &dev_attr_online.attr,
+       NULL,
+};
+
+static struct attribute_group zcrypt_card_attr_group = {
+       .attrs = zcrypt_card_attrs,
+};
+
+struct zcrypt_card *zcrypt_card_alloc(void)
+{
+       struct zcrypt_card *zc;
+
+       zc = kzalloc(sizeof(struct zcrypt_card), GFP_KERNEL);
+       if (!zc)
+               return NULL;
+       INIT_LIST_HEAD(&zc->list);
+       INIT_LIST_HEAD(&zc->zqueues);
+       zc->dbf_area = zcrypt_dbf_cards;
+       kref_init(&zc->refcount);
+       return zc;
+}
+EXPORT_SYMBOL(zcrypt_card_alloc);
+
+void zcrypt_card_free(struct zcrypt_card *zc)
+{
+       kfree(zc);
+}
+EXPORT_SYMBOL(zcrypt_card_free);
+
+static void zcrypt_card_release(struct kref *kref)
+{
+       struct zcrypt_card *zdev =
+               container_of(kref, struct zcrypt_card, refcount);
+       zcrypt_card_free(zdev);
+}
+
+void zcrypt_card_get(struct zcrypt_card *zc)
+{
+       kref_get(&zc->refcount);
+}
+EXPORT_SYMBOL(zcrypt_card_get);
+
+int zcrypt_card_put(struct zcrypt_card *zc)
+{
+       return kref_put(&zc->refcount, zcrypt_card_release);
+}
+EXPORT_SYMBOL(zcrypt_card_put);
+
+/**
+ * zcrypt_card_register() - Register a crypto card device.
+ * @zc: Pointer to a crypto card device
+ *
+ * Register a crypto card device. Returns 0 if successful.
+ */
+int zcrypt_card_register(struct zcrypt_card *zc)
+{
+       int rc;
+
+       rc = sysfs_create_group(&zc->card->ap_dev.device.kobj,
+                               &zcrypt_card_attr_group);
+       if (rc)
+               return rc;
+
+       spin_lock(&zcrypt_list_lock);
+       list_add_tail(&zc->list, &zcrypt_card_list);
+       spin_unlock(&zcrypt_list_lock);
+
+       zc->online = 1;
+       return rc;
+}
+EXPORT_SYMBOL(zcrypt_card_register);
+
+/**
+ * zcrypt_card_unregister(): Unregister a crypto card device.
+ * @zc: Pointer to crypto card device
+ *
+ * Unregister a crypto card device.
+ */
+void zcrypt_card_unregister(struct zcrypt_card *zc)
+{
+       spin_lock(&zcrypt_list_lock);
+       list_del_init(&zc->list);
+       spin_unlock(&zcrypt_list_lock);
+       sysfs_remove_group(&zc->card->ap_dev.device.kobj,
+                          &zcrypt_card_attr_group);
+}
+EXPORT_SYMBOL(zcrypt_card_unregister);
index 4bb13eadd0f18f3c03ef0a5a983005e3d1b29197..c7d48a18199e5171cc40ab426a4734852aaf7c0a 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/err.h>
 #include <linux/atomic.h>
 #include <asm/uaccess.h>
+#include <linux/mod_devicetable.h>
 
 #include "ap_bus.h"
 #include "zcrypt_api.h"
 #define CEX2A_CLEANUP_TIME     (15*HZ)
 #define CEX3A_CLEANUP_TIME     CEX2A_CLEANUP_TIME
 
-static struct ap_device_id zcrypt_cex2a_ids[] = {
-       { AP_DEVICE(AP_DEVICE_TYPE_CEX2A) },
-       { AP_DEVICE(AP_DEVICE_TYPE_CEX3A) },
-       { /* end of list */ },
-};
-
-MODULE_DEVICE_TABLE(ap, zcrypt_cex2a_ids);
 MODULE_AUTHOR("IBM Corporation");
 MODULE_DESCRIPTION("CEX2A Cryptographic Coprocessor device driver, " \
                   "Copyright IBM Corp. 2001, 2012");
 MODULE_LICENSE("GPL");
 
-static int zcrypt_cex2a_probe(struct ap_device *ap_dev);
-static void zcrypt_cex2a_remove(struct ap_device *ap_dev);
+static struct ap_device_id zcrypt_cex2a_card_ids[] = {
+       { .dev_type = AP_DEVICE_TYPE_CEX2A,
+         .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE },
+       { .dev_type = AP_DEVICE_TYPE_CEX3A,
+         .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE },
+       { /* end of list */ },
+};
+
+MODULE_DEVICE_TABLE(ap, zcrypt_cex2a_card_ids);
 
-static struct ap_driver zcrypt_cex2a_driver = {
-       .probe = zcrypt_cex2a_probe,
-       .remove = zcrypt_cex2a_remove,
-       .ids = zcrypt_cex2a_ids,
-       .request_timeout = CEX2A_CLEANUP_TIME,
+static struct ap_device_id zcrypt_cex2a_queue_ids[] = {
+       { .dev_type = AP_DEVICE_TYPE_CEX2A,
+         .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
+       { .dev_type = AP_DEVICE_TYPE_CEX3A,
+         .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
+       { /* end of list */ },
 };
 
+MODULE_DEVICE_TABLE(ap, zcrypt_cex2a_queue_ids);
+
 /**
- * Probe function for CEX2A cards. It always accepts the AP device
- * since the bus_match already checked the hardware type.
+ * Probe function for CEX2A card devices. It always accepts the AP device
+ * since the bus_match already checked the card type.
  * @ap_dev: pointer to the AP device.
  */
-static int zcrypt_cex2a_probe(struct ap_device *ap_dev)
+static int zcrypt_cex2a_card_probe(struct ap_device *ap_dev)
 {
-       struct zcrypt_device *zdev = NULL;
-       int CEX2A_SPEED_IDX[] = { 800, 1000, 2000,  900, 1200, 2400, 0};
-       int CEX3A_SPEED_IDX[] = { 400,  500, 1000,  450,  550, 1200, 0};
+       /*
+        * Normalized speed ratings per crypto adapter
+        * MEX_1k, MEX_2k, MEX_4k, CRT_1k, CRT_2k, CRT_4k, RNG, SECKEY
+        */
+       static const int CEX2A_SPEED_IDX[] = {
+               800, 1000, 2000,  900, 1200, 2400, 0, 0};
+       static const int CEX3A_SPEED_IDX[] = {
+               400,  500, 1000,  450,  550, 1200, 0, 0};
+
+       struct ap_card *ac = to_ap_card(&ap_dev->device);
+       struct zcrypt_card *zc;
        int rc = 0;
 
+       zc = zcrypt_card_alloc();
+       if (!zc)
+               return -ENOMEM;
+       zc->card = ac;
+       ac->private = zc;
+
+       if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX2A) {
+               zc->min_mod_size = CEX2A_MIN_MOD_SIZE;
+               zc->max_mod_size = CEX2A_MAX_MOD_SIZE;
+               memcpy(zc->speed_rating, CEX2A_SPEED_IDX,
+                      sizeof(CEX2A_SPEED_IDX));
+               zc->max_exp_bit_length = CEX2A_MAX_MOD_SIZE;
+               zc->type_string = "CEX2A";
+               zc->user_space_type = ZCRYPT_CEX2A;
+       } else if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX3A) {
+               zc->min_mod_size = CEX2A_MIN_MOD_SIZE;
+               zc->max_mod_size = CEX2A_MAX_MOD_SIZE;
+               zc->max_exp_bit_length = CEX2A_MAX_MOD_SIZE;
+               if (ap_test_bit(&ac->functions, AP_FUNC_MEX4K) &&
+                   ap_test_bit(&ac->functions, AP_FUNC_CRT4K)) {
+                       zc->max_mod_size = CEX3A_MAX_MOD_SIZE;
+                       zc->max_exp_bit_length = CEX3A_MAX_MOD_SIZE;
+               }
+               memcpy(zc->speed_rating, CEX3A_SPEED_IDX,
+                      sizeof(CEX3A_SPEED_IDX));
+               zc->type_string = "CEX3A";
+               zc->user_space_type = ZCRYPT_CEX3A;
+       } else {
+               zcrypt_card_free(zc);
+               return -ENODEV;
+       }
+       zc->online = 1;
+
+       rc = zcrypt_card_register(zc);
+       if (rc) {
+               ac->private = NULL;
+               zcrypt_card_free(zc);
+       }
+
+       return rc;
+}
+
+/**
+ * This is called to remove the CEX2A card driver information
+ * if an AP card device is removed.
+ */
+static void zcrypt_cex2a_card_remove(struct ap_device *ap_dev)
+{
+       struct zcrypt_card *zc = to_ap_card(&ap_dev->device)->private;
+
+       if (zc)
+               zcrypt_card_unregister(zc);
+}
+
+static struct ap_driver zcrypt_cex2a_card_driver = {
+       .probe = zcrypt_cex2a_card_probe,
+       .remove = zcrypt_cex2a_card_remove,
+       .ids = zcrypt_cex2a_card_ids,
+};
+
+/**
+ * Probe function for CEX2A queue devices. It always accepts the AP device
+ * since the bus_match already checked the queue type.
+ * @ap_dev: pointer to the AP device.
+ */
+static int zcrypt_cex2a_queue_probe(struct ap_device *ap_dev)
+{
+       struct ap_queue *aq = to_ap_queue(&ap_dev->device);
+       struct zcrypt_queue *zq = NULL;
+       int rc;
+
        switch (ap_dev->device_type) {
        case AP_DEVICE_TYPE_CEX2A:
-               zdev = zcrypt_device_alloc(CEX2A_MAX_RESPONSE_SIZE);
-               if (!zdev)
+               zq = zcrypt_queue_alloc(CEX2A_MAX_RESPONSE_SIZE);
+               if (!zq)
                        return -ENOMEM;
-               zdev->user_space_type = ZCRYPT_CEX2A;
-               zdev->type_string = "CEX2A";
-               zdev->min_mod_size = CEX2A_MIN_MOD_SIZE;
-               zdev->max_mod_size = CEX2A_MAX_MOD_SIZE;
-               zdev->short_crt = 1;
-               memcpy(zdev->speed_rating, CEX2A_SPEED_IDX,
-                      sizeof(CEX2A_SPEED_IDX));
-               zdev->max_exp_bit_length = CEX2A_MAX_MOD_SIZE;
                break;
        case AP_DEVICE_TYPE_CEX3A:
-               zdev = zcrypt_device_alloc(CEX3A_MAX_RESPONSE_SIZE);
-               if (!zdev)
+               zq = zcrypt_queue_alloc(CEX3A_MAX_RESPONSE_SIZE);
+               if (!zq)
                        return -ENOMEM;
-               zdev->user_space_type = ZCRYPT_CEX3A;
-               zdev->type_string = "CEX3A";
-               zdev->min_mod_size = CEX2A_MIN_MOD_SIZE;
-               zdev->max_mod_size = CEX2A_MAX_MOD_SIZE;
-               zdev->max_exp_bit_length = CEX2A_MAX_MOD_SIZE;
-               if (ap_test_bit(&ap_dev->functions, AP_FUNC_MEX4K) &&
-                   ap_test_bit(&ap_dev->functions, AP_FUNC_CRT4K)) {
-                       zdev->max_mod_size = CEX3A_MAX_MOD_SIZE;
-                       zdev->max_exp_bit_length = CEX3A_MAX_MOD_SIZE;
-               }
-               zdev->short_crt = 1;
-               memcpy(zdev->speed_rating, CEX3A_SPEED_IDX,
-                      sizeof(CEX3A_SPEED_IDX));
                break;
        }
-       if (!zdev)
+       if (!zq)
                return -ENODEV;
-       zdev->ops = zcrypt_msgtype(MSGTYPE50_NAME, MSGTYPE50_VARIANT_DEFAULT);
-       zdev->ap_dev = ap_dev;
-       zdev->online = 1;
-       zdev->load = zdev->speed_rating[0];
-       ap_device_init_reply(ap_dev, &zdev->reply);
-       ap_dev->private = zdev;
-       rc = zcrypt_device_register(zdev);
+       zq->ops = zcrypt_msgtype(MSGTYPE50_NAME, MSGTYPE50_VARIANT_DEFAULT);
+       zq->queue = aq;
+       zq->online = 1;
+       atomic_set(&zq->load, 0);
+       ap_queue_init_reply(aq, &zq->reply);
+       aq->request_timeout = CEX2A_CLEANUP_TIME,
+       aq->private = zq;
+       rc = zcrypt_queue_register(zq);
        if (rc) {
-               ap_dev->private = NULL;
-               zcrypt_device_free(zdev);
+               aq->private = NULL;
+               zcrypt_queue_free(zq);
        }
+
        return rc;
 }
 
 /**
- * This is called to remove the extended CEX2A driver information
- * if an AP device is removed.
+ * This is called to remove the CEX2A queue driver information
+ * if an AP queue device is removed.
  */
-static void zcrypt_cex2a_remove(struct ap_device *ap_dev)
+static void zcrypt_cex2a_queue_remove(struct ap_device *ap_dev)
 {
-       struct zcrypt_device *zdev = ap_dev->private;
+       struct ap_queue *aq = to_ap_queue(&ap_dev->device);
+       struct zcrypt_queue *zq = aq->private;
 
-       zcrypt_device_unregister(zdev);
+       ap_queue_remove(aq);
+       if (zq)
+               zcrypt_queue_unregister(zq);
 }
 
+static struct ap_driver zcrypt_cex2a_queue_driver = {
+       .probe = zcrypt_cex2a_queue_probe,
+       .remove = zcrypt_cex2a_queue_remove,
+       .suspend = ap_queue_suspend,
+       .resume = ap_queue_resume,
+       .ids = zcrypt_cex2a_queue_ids,
+};
+
 int __init zcrypt_cex2a_init(void)
 {
-       return ap_driver_register(&zcrypt_cex2a_driver, THIS_MODULE, "cex2a");
+       int rc;
+
+       rc = ap_driver_register(&zcrypt_cex2a_card_driver,
+                               THIS_MODULE, "cex2acard");
+       if (rc)
+               return rc;
+
+       rc = ap_driver_register(&zcrypt_cex2a_queue_driver,
+                               THIS_MODULE, "cex2aqueue");
+       if (rc)
+               ap_driver_unregister(&zcrypt_cex2a_card_driver);
+
+       return rc;
 }
 
 void __exit zcrypt_cex2a_exit(void)
 {
-       ap_driver_unregister(&zcrypt_cex2a_driver);
+       ap_driver_unregister(&zcrypt_cex2a_queue_driver);
+       ap_driver_unregister(&zcrypt_cex2a_card_driver);
 }
 
 module_init(zcrypt_cex2a_init);
index ff28ad543c3047df156b22d9da52dc16ed5c6670..4e91163d70a6eb1341bb2306ca9a6b1137aa159a 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/err.h>
 #include <linux/atomic.h>
 #include <linux/uaccess.h>
+#include <linux/mod_devicetable.h>
 
 #include "ap_bus.h"
 #include "zcrypt_api.h"
  */
 #define CEX4_CLEANUP_TIME      (900*HZ)
 
-static struct ap_device_id zcrypt_cex4_ids[] = {
-       { AP_DEVICE(AP_DEVICE_TYPE_CEX4)  },
-       { AP_DEVICE(AP_DEVICE_TYPE_CEX5)  },
-       { /* end of list */ },
-};
-
-MODULE_DEVICE_TABLE(ap, zcrypt_cex4_ids);
 MODULE_AUTHOR("IBM Corporation");
 MODULE_DESCRIPTION("CEX4 Cryptographic Card device driver, " \
                   "Copyright IBM Corp. 2012");
 MODULE_LICENSE("GPL");
 
-static int zcrypt_cex4_probe(struct ap_device *ap_dev);
-static void zcrypt_cex4_remove(struct ap_device *ap_dev);
+static struct ap_device_id zcrypt_cex4_card_ids[] = {
+       { .dev_type = AP_DEVICE_TYPE_CEX4,
+         .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE },
+       { .dev_type = AP_DEVICE_TYPE_CEX5,
+         .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE },
+       { /* end of list */ },
+};
+
+MODULE_DEVICE_TABLE(ap, zcrypt_cex4_card_ids);
 
-static struct ap_driver zcrypt_cex4_driver = {
-       .probe = zcrypt_cex4_probe,
-       .remove = zcrypt_cex4_remove,
-       .ids = zcrypt_cex4_ids,
-       .request_timeout = CEX4_CLEANUP_TIME,
+static struct ap_device_id zcrypt_cex4_queue_ids[] = {
+       { .dev_type = AP_DEVICE_TYPE_CEX4,
+         .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
+       { .dev_type = AP_DEVICE_TYPE_CEX5,
+         .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
+       { /* end of list */ },
 };
 
+MODULE_DEVICE_TABLE(ap, zcrypt_cex4_queue_ids);
+
 /**
- * Probe function for CEX4 cards. It always accepts the AP device
+ * Probe function for CEX4 card device. It always accepts the AP device
  * since the bus_match already checked the hardware type.
  * @ap_dev: pointer to the AP device.
  */
-static int zcrypt_cex4_probe(struct ap_device *ap_dev)
+static int zcrypt_cex4_card_probe(struct ap_device *ap_dev)
 {
-       struct zcrypt_device *zdev = NULL;
        /*
         * Normalized speed ratings per crypto adapter
         * MEX_1k, MEX_2k, MEX_4k, CRT_1k, CRT_2k, CRT_4k, RNG, SECKEY
         */
-       int CEX4A_SPEED_IDX[] = {  5,  6,    59,  20, 115,  581,  0,  0};
-       int CEX5A_SPEED_IDX[] = {  3,  3,     6,   8,  32,  218,  0,  0};
-       int CEX4C_SPEED_IDX[] = { 24,  25,   82,  41, 138, 1111, 79,  8};
-       int CEX5C_SPEED_IDX[] = { 10,  14,   23,  17,  45,  242, 63,  4};
-       int CEX4P_SPEED_IDX[] = {142, 198, 1852, 203, 331, 1563,  0,  8};
-       int CEX5P_SPEED_IDX[] = { 49,  67,  131,  52,  85,  287,  0,  4};
+       static const int CEX4A_SPEED_IDX[] = {
+               5,  6,    59,  20, 115,  581,  0,  0};
+       static const int CEX5A_SPEED_IDX[] = {
+               3,  3,     6,   8,  32,  218,  0,  0};
+       static const int CEX4C_SPEED_IDX[] = {
+               24,  25,   82,  41, 138, 1111, 79,  8};
+       static const int CEX5C_SPEED_IDX[] = {
+               10,  14,   23,  17,  45,  242, 63,  4};
+       static const int CEX4P_SPEED_IDX[] = {
+               142, 198, 1852, 203, 331, 1563,  0,  8};
+       static const int CEX5P_SPEED_IDX[] = {
+               49,  67,  131,  52,  85,  287,  0,  4};
+
+       struct ap_card *ac = to_ap_card(&ap_dev->device);
+       struct zcrypt_card *zc;
        int rc = 0;
 
-       switch (ap_dev->device_type) {
-       case AP_DEVICE_TYPE_CEX4:
-       case AP_DEVICE_TYPE_CEX5:
-               if (ap_test_bit(&ap_dev->functions, AP_FUNC_ACCEL)) {
-                       zdev = zcrypt_device_alloc(CEX4A_MAX_MESSAGE_SIZE);
-                       if (!zdev)
-                               return -ENOMEM;
-                       if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) {
-                               zdev->type_string = "CEX4A";
-                               memcpy(zdev->speed_rating, CEX4A_SPEED_IDX,
-                                      sizeof(CEX4A_SPEED_IDX));
-                       } else {
-                               zdev->type_string = "CEX5A";
-                               memcpy(zdev->speed_rating, CEX5A_SPEED_IDX,
-                                      sizeof(CEX5A_SPEED_IDX));
-                       }
-                       zdev->user_space_type = ZCRYPT_CEX3A;
-                       zdev->min_mod_size = CEX4A_MIN_MOD_SIZE;
-                       if (ap_test_bit(&ap_dev->functions, AP_FUNC_MEX4K) &&
-                           ap_test_bit(&ap_dev->functions, AP_FUNC_CRT4K)) {
-                               zdev->max_mod_size =
-                                       CEX4A_MAX_MOD_SIZE_4K;
-                               zdev->max_exp_bit_length =
-                                       CEX4A_MAX_MOD_SIZE_4K;
-                       } else {
-                               zdev->max_mod_size =
-                                       CEX4A_MAX_MOD_SIZE_2K;
-                               zdev->max_exp_bit_length =
-                                       CEX4A_MAX_MOD_SIZE_2K;
-                       }
-                       zdev->short_crt = 1;
-                       zdev->ops = zcrypt_msgtype(MSGTYPE50_NAME,
-                                                  MSGTYPE50_VARIANT_DEFAULT);
-               } else if (ap_test_bit(&ap_dev->functions, AP_FUNC_COPRO)) {
-                       zdev = zcrypt_device_alloc(CEX4C_MAX_MESSAGE_SIZE);
-                       if (!zdev)
-                               return -ENOMEM;
-                       if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) {
-                               zdev->type_string = "CEX4C";
-                               memcpy(zdev->speed_rating, CEX4C_SPEED_IDX,
-                                      sizeof(CEX4C_SPEED_IDX));
-                       } else {
-                               zdev->type_string = "CEX5C";
-                               memcpy(zdev->speed_rating, CEX5C_SPEED_IDX,
-                                      sizeof(CEX5C_SPEED_IDX));
-                       }
-                       zdev->user_space_type = ZCRYPT_CEX3C;
-                       zdev->min_mod_size = CEX4C_MIN_MOD_SIZE;
-                       zdev->max_mod_size = CEX4C_MAX_MOD_SIZE;
-                       zdev->max_exp_bit_length = CEX4C_MAX_MOD_SIZE;
-                       zdev->short_crt = 0;
-                       zdev->ops = zcrypt_msgtype(MSGTYPE06_NAME,
-                                                  MSGTYPE06_VARIANT_DEFAULT);
-               } else if (ap_test_bit(&ap_dev->functions, AP_FUNC_EP11)) {
-                       zdev = zcrypt_device_alloc(CEX4C_MAX_MESSAGE_SIZE);
-                       if (!zdev)
-                               return -ENOMEM;
-                       if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) {
-                               zdev->type_string = "CEX4P";
-                               memcpy(zdev->speed_rating, CEX4P_SPEED_IDX,
-                                      sizeof(CEX4P_SPEED_IDX));
-                       } else {
-                               zdev->type_string = "CEX5P";
-                               memcpy(zdev->speed_rating, CEX5P_SPEED_IDX,
-                                      sizeof(CEX5P_SPEED_IDX));
-                       }
-                       zdev->user_space_type = ZCRYPT_CEX4;
-                       zdev->min_mod_size = CEX4C_MIN_MOD_SIZE;
-                       zdev->max_mod_size = CEX4C_MAX_MOD_SIZE;
-                       zdev->max_exp_bit_length = CEX4C_MAX_MOD_SIZE;
-                       zdev->short_crt = 0;
-                       zdev->ops = zcrypt_msgtype(MSGTYPE06_NAME,
-                                                  MSGTYPE06_VARIANT_EP11);
+       zc = zcrypt_card_alloc();
+       if (!zc)
+               return -ENOMEM;
+       zc->card = ac;
+       ac->private = zc;
+       if (ap_test_bit(&ac->functions, AP_FUNC_ACCEL)) {
+               if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX4) {
+                       zc->type_string = "CEX4A";
+                       zc->user_space_type = ZCRYPT_CEX4;
+                       memcpy(zc->speed_rating, CEX4A_SPEED_IDX,
+                              sizeof(CEX4A_SPEED_IDX));
+               } else {
+                       zc->type_string = "CEX5A";
+                       zc->user_space_type = ZCRYPT_CEX5;
+                       memcpy(zc->speed_rating, CEX5A_SPEED_IDX,
+                              sizeof(CEX5A_SPEED_IDX));
                }
-               break;
-       }
-       if (!zdev)
+               zc->min_mod_size = CEX4A_MIN_MOD_SIZE;
+               if (ap_test_bit(&ac->functions, AP_FUNC_MEX4K) &&
+                   ap_test_bit(&ac->functions, AP_FUNC_CRT4K)) {
+                       zc->max_mod_size = CEX4A_MAX_MOD_SIZE_4K;
+                       zc->max_exp_bit_length =
+                               CEX4A_MAX_MOD_SIZE_4K;
+               } else {
+                       zc->max_mod_size = CEX4A_MAX_MOD_SIZE_2K;
+                       zc->max_exp_bit_length =
+                               CEX4A_MAX_MOD_SIZE_2K;
+               }
+       } else if (ap_test_bit(&ac->functions, AP_FUNC_COPRO)) {
+               if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX4) {
+                       zc->type_string = "CEX4C";
+                       /* wrong user space type, must be CEX4
+                        * just keep it for cca compatibility
+                        */
+                       zc->user_space_type = ZCRYPT_CEX3C;
+                       memcpy(zc->speed_rating, CEX4C_SPEED_IDX,
+                              sizeof(CEX4C_SPEED_IDX));
+               } else {
+                       zc->type_string = "CEX5C";
+                       /* wrong user space type, must be CEX5
+                        * just keep it for cca compatibility
+                        */
+                       zc->user_space_type = ZCRYPT_CEX3C;
+                       memcpy(zc->speed_rating, CEX5C_SPEED_IDX,
+                              sizeof(CEX5C_SPEED_IDX));
+               }
+               zc->min_mod_size = CEX4C_MIN_MOD_SIZE;
+               zc->max_mod_size = CEX4C_MAX_MOD_SIZE;
+               zc->max_exp_bit_length = CEX4C_MAX_MOD_SIZE;
+       } else if (ap_test_bit(&ac->functions, AP_FUNC_EP11)) {
+               if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX4) {
+                       zc->type_string = "CEX4P";
+                       zc->user_space_type = ZCRYPT_CEX4;
+                       memcpy(zc->speed_rating, CEX4P_SPEED_IDX,
+                              sizeof(CEX4P_SPEED_IDX));
+               } else {
+                       zc->type_string = "CEX5P";
+                       zc->user_space_type = ZCRYPT_CEX5;
+                       memcpy(zc->speed_rating, CEX5P_SPEED_IDX,
+                              sizeof(CEX5P_SPEED_IDX));
+               }
+               zc->min_mod_size = CEX4C_MIN_MOD_SIZE;
+               zc->max_mod_size = CEX4C_MAX_MOD_SIZE;
+               zc->max_exp_bit_length = CEX4C_MAX_MOD_SIZE;
+       } else {
+               zcrypt_card_free(zc);
                return -ENODEV;
-       zdev->ap_dev = ap_dev;
-       zdev->online = 1;
-       zdev->load = zdev->speed_rating[0];
-       ap_device_init_reply(ap_dev, &zdev->reply);
-       ap_dev->private = zdev;
-       rc = zcrypt_device_register(zdev);
+       }
+       zc->online = 1;
+
+       rc = zcrypt_card_register(zc);
        if (rc) {
-               ap_dev->private = NULL;
-               zcrypt_device_free(zdev);
+               ac->private = NULL;
+               zcrypt_card_free(zc);
        }
+
        return rc;
 }
 
 /**
- * This is called to remove the extended CEX4 driver information
- * if an AP device is removed.
+ * This is called to remove the CEX4 card driver information
+ * if an AP card device is removed.
  */
-static void zcrypt_cex4_remove(struct ap_device *ap_dev)
+static void zcrypt_cex4_card_remove(struct ap_device *ap_dev)
 {
-       struct zcrypt_device *zdev = ap_dev->private;
+       struct zcrypt_card *zc = to_ap_card(&ap_dev->device)->private;
 
-       if (zdev) {
-               zcrypt_device_unregister(zdev);
+       if (zc)
+               zcrypt_card_unregister(zc);
+}
+
+static struct ap_driver zcrypt_cex4_card_driver = {
+       .probe = zcrypt_cex4_card_probe,
+       .remove = zcrypt_cex4_card_remove,
+       .ids = zcrypt_cex4_card_ids,
+};
+
+/**
+ * Probe function for CEX4 queue device. It always accepts the AP device
+ * since the bus_match already checked the hardware type.
+ * @ap_dev: pointer to the AP device.
+ */
+static int zcrypt_cex4_queue_probe(struct ap_device *ap_dev)
+{
+       struct ap_queue *aq = to_ap_queue(&ap_dev->device);
+       struct zcrypt_queue *zq;
+       int rc;
+
+       if (ap_test_bit(&aq->card->functions, AP_FUNC_ACCEL)) {
+               zq = zcrypt_queue_alloc(CEX4A_MAX_MESSAGE_SIZE);
+               if (!zq)
+                       return -ENOMEM;
+               zq->ops = zcrypt_msgtype(MSGTYPE50_NAME,
+                                        MSGTYPE50_VARIANT_DEFAULT);
+       } else if (ap_test_bit(&aq->card->functions, AP_FUNC_COPRO)) {
+               zq = zcrypt_queue_alloc(CEX4C_MAX_MESSAGE_SIZE);
+               if (!zq)
+                       return -ENOMEM;
+               zq->ops = zcrypt_msgtype(MSGTYPE06_NAME,
+                                        MSGTYPE06_VARIANT_DEFAULT);
+       } else if (ap_test_bit(&aq->card->functions, AP_FUNC_EP11)) {
+               zq = zcrypt_queue_alloc(CEX4C_MAX_MESSAGE_SIZE);
+               if (!zq)
+                       return -ENOMEM;
+               zq->ops = zcrypt_msgtype(MSGTYPE06_NAME,
+                                        MSGTYPE06_VARIANT_EP11);
+       } else {
+               return -ENODEV;
        }
+       zq->queue = aq;
+       zq->online = 1;
+       atomic_set(&zq->load, 0);
+       ap_queue_init_reply(aq, &zq->reply);
+       aq->request_timeout = CEX4_CLEANUP_TIME,
+       aq->private = zq;
+       rc = zcrypt_queue_register(zq);
+       if (rc) {
+               aq->private = NULL;
+               zcrypt_queue_free(zq);
+       }
+
+       return rc;
 }
 
+/**
+ * This is called to remove the CEX4 queue driver information
+ * if an AP queue device is removed.
+ */
+static void zcrypt_cex4_queue_remove(struct ap_device *ap_dev)
+{
+       struct ap_queue *aq = to_ap_queue(&ap_dev->device);
+       struct zcrypt_queue *zq = aq->private;
+
+       ap_queue_remove(aq);
+       if (zq)
+               zcrypt_queue_unregister(zq);
+}
+
+static struct ap_driver zcrypt_cex4_queue_driver = {
+       .probe = zcrypt_cex4_queue_probe,
+       .remove = zcrypt_cex4_queue_remove,
+       .suspend = ap_queue_suspend,
+       .resume = ap_queue_resume,
+       .ids = zcrypt_cex4_queue_ids,
+};
+
 int __init zcrypt_cex4_init(void)
 {
-       return ap_driver_register(&zcrypt_cex4_driver, THIS_MODULE, "cex4");
+       int rc;
+
+       rc = ap_driver_register(&zcrypt_cex4_card_driver,
+                               THIS_MODULE, "cex4card");
+       if (rc)
+               return rc;
+
+       rc = ap_driver_register(&zcrypt_cex4_queue_driver,
+                               THIS_MODULE, "cex4queue");
+       if (rc)
+               ap_driver_unregister(&zcrypt_cex4_card_driver);
+
+       return rc;
 }
 
 void __exit zcrypt_cex4_exit(void)
 {
-       ap_driver_unregister(&zcrypt_cex4_driver);
+       ap_driver_unregister(&zcrypt_cex4_queue_driver);
+       ap_driver_unregister(&zcrypt_cex4_card_driver);
 }
 
 module_init(zcrypt_cex4_init);
index de1b6c1d172c8c0866dc0fd8fb709d032bdef820..09247331e9fb5ced7d9d23e7657597347ce737b3 100644 (file)
@@ -87,7 +87,7 @@ struct error_hdr {
 #define REP88_ERROR_OPERAND         0x84       /* CEX2A        */
 #define REP88_ERROR_OPERAND_EVEN_MOD 0x85      /* CEX2A        */
 
-static inline int convert_error(struct zcrypt_device *zdev,
+static inline int convert_error(struct zcrypt_queue *zq,
                                struct ap_message *reply)
 {
        struct error_hdr *ehdr = reply->message;
@@ -110,11 +110,13 @@ static inline int convert_error(struct zcrypt_device *zdev,
                 * and then repeat the request.
                 */
                atomic_set(&zcrypt_rescan_req, 1);
-               zdev->online = 0;
-               pr_err("Cryptographic device %x failed and was set offline\n",
-                      AP_QID_DEVICE(zdev->ap_dev->qid));
-               ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d",
-                       AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online,
+               zq->online = 0;
+               pr_err("Cryptographic device %02x.%04x failed and was set offline\n",
+                      AP_QID_CARD(zq->queue->qid),
+                      AP_QID_QUEUE(zq->queue->qid));
+               ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%drc%d",
+                       AP_QID_CARD(zq->queue->qid),
+                       AP_QID_QUEUE(zq->queue->qid), zq->online,
                        ehdr->reply_code);
                return -EAGAIN;
        case REP82_ERROR_TRANSPORT_FAIL:
@@ -122,19 +124,23 @@ static inline int convert_error(struct zcrypt_device *zdev,
        //   REP88_ERROR_MODULE_FAILURE         // '10' CEX2A
                /* If a card fails disable it and repeat the request. */
                atomic_set(&zcrypt_rescan_req, 1);
-               zdev->online = 0;
-               pr_err("Cryptographic device %x failed and was set offline\n",
-                      AP_QID_DEVICE(zdev->ap_dev->qid));
-               ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d",
-                       AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online,
+               zq->online = 0;
+               pr_err("Cryptographic device %02x.%04x failed and was set offline\n",
+                      AP_QID_CARD(zq->queue->qid),
+                      AP_QID_QUEUE(zq->queue->qid));
+               ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%drc%d",
+                       AP_QID_CARD(zq->queue->qid),
+                       AP_QID_QUEUE(zq->queue->qid), zq->online,
                        ehdr->reply_code);
                return -EAGAIN;
        default:
-               zdev->online = 0;
-               pr_err("Cryptographic device %x failed and was set offline\n",
-                      AP_QID_DEVICE(zdev->ap_dev->qid));
-               ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d",
-                       AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online,
+               zq->online = 0;
+               pr_err("Cryptographic device %02x.%04x failed and was set offline\n",
+                      AP_QID_CARD(zq->queue->qid),
+                      AP_QID_QUEUE(zq->queue->qid));
+               ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%drc%d",
+                       AP_QID_CARD(zq->queue->qid),
+                       AP_QID_QUEUE(zq->queue->qid), zq->online,
                        ehdr->reply_code);
                return -EAGAIN; /* repeat the request on a different device. */
        }
index fb97479af3f86f5b4f29993206a4ddeca9b5d1ac..a9873b43611568d46bee7eceed3be87631e0e3c7 100644 (file)
@@ -53,9 +53,6 @@ MODULE_DESCRIPTION("Cryptographic Accelerator (message type 50), " \
                   "Copyright IBM Corp. 2001, 2012");
 MODULE_LICENSE("GPL");
 
-static void zcrypt_cex2a_receive(struct ap_device *, struct ap_message *,
-                                struct ap_message *);
-
 /**
  * The type 50 message family is associated with a CEX2A card.
  *
@@ -208,13 +205,13 @@ unsigned int get_rsa_crt_fc(struct ica_rsa_modexpo_crt *crt, int *fcode)
 /**
  * Convert a ICAMEX message to a type50 MEX message.
  *
- * @zdev: crypto device pointer
- * @zreq: crypto request pointer
+ * @zq: crypto queue pointer
+ * @ap_msg: crypto request pointer
  * @mex: pointer to user input data
  *
  * Returns 0 on success or -EFAULT.
  */
-static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_device *zdev,
+static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_queue *zq,
                                       struct ap_message *ap_msg,
                                       struct ica_rsa_modexpo *mex)
 {
@@ -266,13 +263,13 @@ static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_device *zdev,
 /**
  * Convert a ICACRT message to a type50 CRT message.
  *
- * @zdev: crypto device pointer
- * @zreq: crypto request pointer
+ * @zq: crypto queue pointer
+ * @ap_msg: crypto request pointer
  * @crt: pointer to user input data
  *
  * Returns 0 on success or -EFAULT.
  */
-static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_device *zdev,
+static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_queue *zq,
                                       struct ap_message *ap_msg,
                                       struct ica_rsa_modexpo_crt *crt)
 {
@@ -315,7 +312,7 @@ static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_device *zdev,
                u = crb2->u + sizeof(crb2->u) - short_len;
                inp = crb2->message + sizeof(crb2->message) - mod_len;
        } else if ((mod_len <= 512) &&  /* up to 4096 bit key size */
-                  (zdev->max_mod_size == CEX3A_MAX_MOD_SIZE)) { /* >= CEX3A */
+                  (zq->zcard->max_mod_size == CEX3A_MAX_MOD_SIZE)) {
                struct type50_crb3_msg *crb3 = ap_msg->message;
                memset(crb3, 0, sizeof(*crb3));
                ap_msg->length = sizeof(*crb3);
@@ -349,14 +346,14 @@ static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_device *zdev,
 /**
  * Copy results from a type 80 reply message back to user space.
  *
- * @zdev: crypto device pointer
+ * @zq: crypto device pointer
  * @reply: reply AP message.
  * @data: pointer to user output data
  * @length: size of user output data
  *
  * Returns 0 on success or -EFAULT.
  */
-static int convert_type80(struct zcrypt_device *zdev,
+static int convert_type80(struct zcrypt_queue *zq,
                          struct ap_message *reply,
                          char __user *outputdata,
                          unsigned int outputdatalength)
@@ -366,16 +363,18 @@ static int convert_type80(struct zcrypt_device *zdev,
 
        if (t80h->len < sizeof(*t80h) + outputdatalength) {
                /* The result is too short, the CEX2A card may not do that.. */
-               zdev->online = 0;
-               pr_err("Cryptographic device %x failed and was set offline\n",
-                      AP_QID_DEVICE(zdev->ap_dev->qid));
-               ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d",
-                              AP_QID_DEVICE(zdev->ap_dev->qid),
-                              zdev->online, t80h->code);
+               zq->online = 0;
+               pr_err("Cryptographic device %02x.%04x failed and was set offline\n",
+                      AP_QID_CARD(zq->queue->qid),
+                      AP_QID_QUEUE(zq->queue->qid));
+               ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%drc%d",
+                              AP_QID_CARD(zq->queue->qid),
+                              AP_QID_QUEUE(zq->queue->qid),
+                              zq->online, t80h->code);
 
                return -EAGAIN; /* repeat the request on a different device. */
        }
-       if (zdev->user_space_type == ZCRYPT_CEX2A)
+       if (zq->zcard->user_space_type == ZCRYPT_CEX2A)
                BUG_ON(t80h->len > CEX2A_MAX_RESPONSE_SIZE);
        else
                BUG_ON(t80h->len > CEX3A_MAX_RESPONSE_SIZE);
@@ -385,7 +384,7 @@ static int convert_type80(struct zcrypt_device *zdev,
        return 0;
 }
 
-static int convert_response(struct zcrypt_device *zdev,
+static int convert_response(struct zcrypt_queue *zq,
                            struct ap_message *reply,
                            char __user *outputdata,
                            unsigned int outputdatalength)
@@ -394,16 +393,19 @@ static int convert_response(struct zcrypt_device *zdev,
        switch (((unsigned char *) reply->message)[1]) {
        case TYPE82_RSP_CODE:
        case TYPE88_RSP_CODE:
-               return convert_error(zdev, reply);
+               return convert_error(zq, reply);
        case TYPE80_RSP_CODE:
-               return convert_type80(zdev, reply,
+               return convert_type80(zq, reply,
                                      outputdata, outputdatalength);
        default: /* Unknown response type, this should NEVER EVER happen */
-               zdev->online = 0;
-               pr_err("Cryptographic device %x failed and was set offline\n",
-                      AP_QID_DEVICE(zdev->ap_dev->qid));
-               ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%dfail",
-                              AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online);
+               zq->online = 0;
+               pr_err("Cryptographic device %02x.%04x failed and was set offline\n",
+                      AP_QID_CARD(zq->queue->qid),
+                      AP_QID_QUEUE(zq->queue->qid));
+               ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%dfail",
+                              AP_QID_CARD(zq->queue->qid),
+                              AP_QID_QUEUE(zq->queue->qid),
+                              zq->online);
                return -EAGAIN; /* repeat the request on a different device. */
        }
 }
@@ -412,11 +414,11 @@ static int convert_response(struct zcrypt_device *zdev,
  * This function is called from the AP bus code after a crypto request
  * "msg" has finished with the reply message "reply".
  * It is called from tasklet context.
- * @ap_dev: pointer to the AP device
+ * @aq: pointer to the AP device
  * @msg: pointer to the AP message
  * @reply: pointer to the AP reply message
  */
-static void zcrypt_cex2a_receive(struct ap_device *ap_dev,
+static void zcrypt_cex2a_receive(struct ap_queue *aq,
                                 struct ap_message *msg,
                                 struct ap_message *reply)
 {
@@ -432,7 +434,7 @@ static void zcrypt_cex2a_receive(struct ap_device *ap_dev,
                goto out;       /* ap_msg->rc indicates the error */
        t80h = reply->message;
        if (t80h->type == TYPE80_RSP_CODE) {
-               if (ap_dev->device_type == AP_DEVICE_TYPE_CEX2A)
+               if (aq->ap_dev.device_type == AP_DEVICE_TYPE_CEX2A)
                        length = min_t(int,
                                       CEX2A_MAX_RESPONSE_SIZE, t80h->len);
                else
@@ -450,11 +452,11 @@ static atomic_t zcrypt_step = ATOMIC_INIT(0);
 /**
  * The request distributor calls this function if it picked the CEX2A
  * device to handle a modexpo request.
- * @zdev: pointer to zcrypt_device structure that identifies the
+ * @zq: pointer to zcrypt_queue structure that identifies the
  *       CEX2A device to the request distributor
  * @mex: pointer to the modexpo request buffer
  */
-static long zcrypt_cex2a_modexpo(struct zcrypt_device *zdev,
+static long zcrypt_cex2a_modexpo(struct zcrypt_queue *zq,
                                 struct ica_rsa_modexpo *mex)
 {
        struct ap_message ap_msg;
@@ -462,7 +464,7 @@ static long zcrypt_cex2a_modexpo(struct zcrypt_device *zdev,
        int rc;
 
        ap_init_message(&ap_msg);
-       if (zdev->user_space_type == ZCRYPT_CEX2A)
+       if (zq->zcard->user_space_type == ZCRYPT_CEX2A)
                ap_msg.message = kmalloc(MSGTYPE50_CRB2_MAX_MSG_SIZE,
                                         GFP_KERNEL);
        else
@@ -474,20 +476,20 @@ static long zcrypt_cex2a_modexpo(struct zcrypt_device *zdev,
        ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
                                atomic_inc_return(&zcrypt_step);
        ap_msg.private = &work;
-       rc = ICAMEX_msg_to_type50MEX_msg(zdev, &ap_msg, mex);
+       rc = ICAMEX_msg_to_type50MEX_msg(zq, &ap_msg, mex);
        if (rc)
                goto out_free;
        init_completion(&work);
-       ap_queue_message(zdev->ap_dev, &ap_msg);
+       ap_queue_message(zq->queue, &ap_msg);
        rc = wait_for_completion_interruptible(&work);
        if (rc == 0) {
                rc = ap_msg.rc;
                if (rc == 0)
-                       rc = convert_response(zdev, &ap_msg, mex->outputdata,
+                       rc = convert_response(zq, &ap_msg, mex->outputdata,
                                              mex->outputdatalength);
        } else
                /* Signal pending. */
-               ap_cancel_message(zdev->ap_dev, &ap_msg);
+               ap_cancel_message(zq->queue, &ap_msg);
 out_free:
        kfree(ap_msg.message);
        return rc;
@@ -496,11 +498,11 @@ out_free:
 /**
  * The request distributor calls this function if it picked the CEX2A
  * device to handle a modexpo_crt request.
- * @zdev: pointer to zcrypt_device structure that identifies the
+ * @zq: pointer to zcrypt_queue structure that identifies the
  *       CEX2A device to the request distributor
  * @crt: pointer to the modexpoc_crt request buffer
  */
-static long zcrypt_cex2a_modexpo_crt(struct zcrypt_device *zdev,
+static long zcrypt_cex2a_modexpo_crt(struct zcrypt_queue *zq,
                                     struct ica_rsa_modexpo_crt *crt)
 {
        struct ap_message ap_msg;
@@ -508,7 +510,7 @@ static long zcrypt_cex2a_modexpo_crt(struct zcrypt_device *zdev,
        int rc;
 
        ap_init_message(&ap_msg);
-       if (zdev->user_space_type == ZCRYPT_CEX2A)
+       if (zq->zcard->user_space_type == ZCRYPT_CEX2A)
                ap_msg.message = kmalloc(MSGTYPE50_CRB2_MAX_MSG_SIZE,
                                         GFP_KERNEL);
        else
@@ -520,20 +522,20 @@ static long zcrypt_cex2a_modexpo_crt(struct zcrypt_device *zdev,
        ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
                                atomic_inc_return(&zcrypt_step);
        ap_msg.private = &work;
-       rc = ICACRT_msg_to_type50CRT_msg(zdev, &ap_msg, crt);
+       rc = ICACRT_msg_to_type50CRT_msg(zq, &ap_msg, crt);
        if (rc)
                goto out_free;
        init_completion(&work);
-       ap_queue_message(zdev->ap_dev, &ap_msg);
+       ap_queue_message(zq->queue, &ap_msg);
        rc = wait_for_completion_interruptible(&work);
        if (rc == 0) {
                rc = ap_msg.rc;
                if (rc == 0)
-                       rc = convert_response(zdev, &ap_msg, crt->outputdata,
+                       rc = convert_response(zq, &ap_msg, crt->outputdata,
                                              crt->outputdatalength);
        } else
                /* Signal pending. */
-               ap_cancel_message(zdev->ap_dev, &ap_msg);
+               ap_cancel_message(zq->queue, &ap_msg);
 out_free:
        kfree(ap_msg.message);
        return rc;
index 957a88d5768ba0d6e162ca9d7bbfe4003774def3..c6cfb9acec19aa0c50aa8ff33ab45bd7532a31d4 100644 (file)
@@ -60,9 +60,6 @@ MODULE_DESCRIPTION("Cryptographic Coprocessor (message type 6), " \
                   "Copyright IBM Corp. 2001, 2012");
 MODULE_LICENSE("GPL");
 
-static void zcrypt_msgtype6_receive(struct ap_device *, struct ap_message *,
-                                struct ap_message *);
-
 /**
  * CPRB
  *       Note that all shorts, ints and longs are little-endian.
@@ -258,13 +255,13 @@ int speed_idx_ep11(int req_type)
 /**
  * Convert a ICAMEX message to a type6 MEX message.
  *
- * @zdev: crypto device pointer
+ * @zq: crypto device pointer
  * @ap_msg: pointer to AP message
  * @mex: pointer to user input data
  *
  * Returns 0 on success or -EFAULT.
  */
-static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_device *zdev,
+static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_queue *zq,
                                       struct ap_message *ap_msg,
                                       struct ica_rsa_modexpo *mex)
 {
@@ -279,11 +276,6 @@ static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_device *zdev,
                .ulen           = 10,
                .only_rule      = {'M', 'R', 'P', ' ', ' ', ' ', ' ', ' '}
        };
-       static struct function_and_rules_block static_pke_fnr_MCL2 = {
-               .function_code  = {'P', 'K'},
-               .ulen           = 10,
-               .only_rule      = {'Z', 'E', 'R', 'O', '-', 'P', 'A', 'D'}
-       };
        struct {
                struct type6_hdr hdr;
                struct CPRBX cprbx;
@@ -310,11 +302,10 @@ static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_device *zdev,
        msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
 
        msg->cprbx = static_cprbx;
-       msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid);
+       msg->cprbx.domain = AP_QID_QUEUE(zq->queue->qid);
        msg->cprbx.rpl_msgbl = msg->hdr.FromCardLen1;
 
-       msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ?
-               static_pke_fnr_MCL2 : static_pke_fnr;
+       msg->fr = static_pke_fnr;
 
        msg->cprbx.req_parml = size - sizeof(msg->hdr) - sizeof(msg->cprbx);
 
@@ -325,13 +316,13 @@ static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_device *zdev,
 /**
  * Convert a ICACRT message to a type6 CRT message.
  *
- * @zdev: crypto device pointer
+ * @zq: crypto device pointer
  * @ap_msg: pointer to AP message
  * @crt: pointer to user input data
  *
  * Returns 0 on success or -EFAULT.
  */
-static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev,
+static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_queue *zq,
                                       struct ap_message *ap_msg,
                                       struct ica_rsa_modexpo_crt *crt)
 {
@@ -347,11 +338,6 @@ static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev,
                .only_rule      = {'Z', 'E', 'R', 'O', '-', 'P', 'A', 'D'}
        };
 
-       static struct function_and_rules_block static_pkd_fnr_MCL2 = {
-               .function_code  = {'P', 'D'},
-               .ulen           = 10,
-               .only_rule      = {'P', 'K', 'C', 'S', '-', '1', '.', '2'}
-       };
        struct {
                struct type6_hdr hdr;
                struct CPRBX cprbx;
@@ -378,12 +364,11 @@ static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev,
        msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
 
        msg->cprbx = static_cprbx;
-       msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid);
+       msg->cprbx.domain = AP_QID_QUEUE(zq->queue->qid);
        msg->cprbx.req_parml = msg->cprbx.rpl_msgbl =
                size - sizeof(msg->hdr) - sizeof(msg->cprbx);
 
-       msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ?
-               static_pkd_fnr_MCL2 : static_pkd_fnr;
+       msg->fr = static_pkd_fnr;
 
        ap_msg->length = size;
        return 0;
@@ -392,7 +377,7 @@ static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev,
 /**
  * Convert a XCRB message to a type6 CPRB message.
  *
- * @zdev: crypto device pointer
+ * @zq: crypto device pointer
  * @ap_msg: pointer to AP message
  * @xcRB: pointer to user input data
  *
@@ -405,7 +390,8 @@ struct type86_fmt2_msg {
 
 static int XCRB_msg_to_type6CPRB_msgX(struct ap_message *ap_msg,
                                      struct ica_xcRB *xcRB,
-                                     unsigned int *fcode)
+                                     unsigned int *fcode,
+                                     unsigned short **dom)
 {
        static struct type6_hdr static_type6_hdrX = {
                .type           =  0x06,
@@ -486,6 +472,7 @@ static int XCRB_msg_to_type6CPRB_msgX(struct ap_message *ap_msg,
               sizeof(msg->hdr.function_code));
 
        *fcode = (msg->hdr.function_code[0] << 8) | msg->hdr.function_code[1];
+       *dom = (unsigned short *)&msg->cprbx.domain;
 
        if (memcmp(function_code, "US", 2) == 0)
                ap_msg->special = 1;
@@ -497,6 +484,7 @@ static int XCRB_msg_to_type6CPRB_msgX(struct ap_message *ap_msg,
            copy_from_user(req_data, xcRB->request_data_address,
                xcRB->request_data_length))
                return -EFAULT;
+
        return 0;
 }
 
@@ -504,6 +492,7 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(struct ap_message *ap_msg,
                                       struct ep11_urb *xcRB,
                                       unsigned int *fcode)
 {
+       unsigned int lfmt;
        static struct type6_hdr static_type6_ep11_hdr = {
                .type           =  0x06,
                .rqid           = {0x00, 0x01},
@@ -556,14 +545,30 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(struct ap_message *ap_msg,
                return -EFAULT;
        }
 
-       *fcode = speed_idx_ep11(payload_hdr->func_val & 0xFFFF);
+       if ((msg->pld_lenfmt & 0x80) == 0x80) { /*ext.len.fmt 2 or 3*/
+               switch (msg->pld_lenfmt & 0x03) {
+               case 1:
+                       lfmt = 2;
+                       break;
+               case 2:
+                       lfmt = 3;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       } else {
+               lfmt = 1; /* length format #1 */
+       }
+       payload_hdr = (struct pld_hdr *)((&(msg->pld_lenfmt))+lfmt);
+       *fcode = payload_hdr->func_val & 0xFFFF;
+
        return 0;
 }
 
 /**
  * Copy results from a type 86 ICA reply message back to user space.
  *
- * @zdev: crypto device pointer
+ * @zq: crypto device pointer
  * @reply: reply AP message.
  * @data: pointer to user output data
  * @length: size of user output data
@@ -585,7 +590,7 @@ struct type86_ep11_reply {
        struct ep11_cprb cprbx;
 } __packed;
 
-static int convert_type86_ica(struct zcrypt_device *zdev,
+static int convert_type86_ica(struct zcrypt_queue *zq,
                          struct ap_message *reply,
                          char __user *outputdata,
                          unsigned int outputdatalength)
@@ -640,18 +645,22 @@ static int convert_type86_ica(struct zcrypt_device *zdev,
                if (service_rc == 8 && service_rs == 770)
                        return -EINVAL;
                if (service_rc == 8 && service_rs == 783) {
-                       zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
+                       zq->zcard->min_mod_size =
+                               PCIXCC_MIN_MOD_SIZE_OLD;
                        return -EAGAIN;
                }
                if (service_rc == 12 && service_rs == 769)
                        return -EINVAL;
                if (service_rc == 8 && service_rs == 72)
                        return -EINVAL;
-               zdev->online = 0;
-               pr_err("Cryptographic device %x failed and was set offline\n",
-                      AP_QID_DEVICE(zdev->ap_dev->qid));
-               ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d",
-                              AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online,
+               zq->online = 0;
+               pr_err("Cryptographic device %02x.%04x failed and was set offline\n",
+                      AP_QID_CARD(zq->queue->qid),
+                      AP_QID_QUEUE(zq->queue->qid));
+               ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%drc%d",
+                              AP_QID_CARD(zq->queue->qid),
+                              AP_QID_QUEUE(zq->queue->qid),
+                              zq->online,
                               msg->hdr.reply_code);
                return -EAGAIN; /* repeat the request on a different device. */
        }
@@ -688,13 +697,13 @@ static int convert_type86_ica(struct zcrypt_device *zdev,
 /**
  * Copy results from a type 86 XCRB reply message back to user space.
  *
- * @zdev: crypto device pointer
+ * @zq: crypto device pointer
  * @reply: reply AP message.
  * @xcRB: pointer to XCRB
  *
  * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error.
  */
-static int convert_type86_xcrb(struct zcrypt_device *zdev,
+static int convert_type86_xcrb(struct zcrypt_queue *zq,
                               struct ap_message *reply,
                               struct ica_xcRB *xcRB)
 {
@@ -719,13 +728,13 @@ static int convert_type86_xcrb(struct zcrypt_device *zdev,
 /**
  * Copy results from a type 86 EP11 XCRB reply message back to user space.
  *
- * @zdev: crypto device pointer
+ * @zq: crypto device pointer
  * @reply: reply AP message.
  * @xcRB: pointer to EP11 user request block
  *
  * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error.
  */
-static int convert_type86_ep11_xcrb(struct zcrypt_device *zdev,
+static int convert_type86_ep11_xcrb(struct zcrypt_queue *zq,
                                    struct ap_message *reply,
                                    struct ep11_urb *xcRB)
 {
@@ -743,7 +752,7 @@ static int convert_type86_ep11_xcrb(struct zcrypt_device *zdev,
        return 0;
 }
 
-static int convert_type86_rng(struct zcrypt_device *zdev,
+static int convert_type86_rng(struct zcrypt_queue *zq,
                          struct ap_message *reply,
                          char *buffer)
 {
@@ -760,7 +769,7 @@ static int convert_type86_rng(struct zcrypt_device *zdev,
        return msg->fmt2.count2;
 }
 
-static int convert_response_ica(struct zcrypt_device *zdev,
+static int convert_response_ica(struct zcrypt_queue *zq,
                            struct ap_message *reply,
                            char __user *outputdata,
                            unsigned int outputdatalength)
@@ -771,35 +780,38 @@ static int convert_response_ica(struct zcrypt_device *zdev,
        switch (((unsigned char *) reply->message)[1]) {
        case TYPE82_RSP_CODE:
        case TYPE88_RSP_CODE:
-               return convert_error(zdev, reply);
+               return convert_error(zq, reply);
        case TYPE86_RSP_CODE:
                if (msg->cprbx.ccp_rtcode &&
                   (msg->cprbx.ccp_rscode == 0x14f) &&
                   (outputdatalength > 256)) {
-                       if (zdev->max_exp_bit_length <= 17) {
-                               zdev->max_exp_bit_length = 17;
+                       if (zq->zcard->max_exp_bit_length <= 17) {
+                               zq->zcard->max_exp_bit_length = 17;
                                return -EAGAIN;
                        } else
                                return -EINVAL;
                }
                if (msg->hdr.reply_code)
-                       return convert_error(zdev, reply);
+                       return convert_error(zq, reply);
                if (msg->cprbx.cprb_ver_id == 0x02)
-                       return convert_type86_ica(zdev, reply,
+                       return convert_type86_ica(zq, reply,
                                                  outputdata, outputdatalength);
                /* Fall through, no break, incorrect cprb version is an unknown
                 * response */
        default: /* Unknown response type, this should NEVER EVER happen */
-               zdev->online = 0;
-               pr_err("Cryptographic device %x failed and was set offline\n",
-                      AP_QID_DEVICE(zdev->ap_dev->qid));
-               ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%dfail",
-                              AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online);
+               zq->online = 0;
+               pr_err("Cryptographic device %02x.%04x failed and was set offline\n",
+                      AP_QID_CARD(zq->queue->qid),
+                      AP_QID_QUEUE(zq->queue->qid));
+               ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%dfail",
+                              AP_QID_CARD(zq->queue->qid),
+                              AP_QID_QUEUE(zq->queue->qid),
+                              zq->online);
                return -EAGAIN; /* repeat the request on a different device. */
        }
 }
 
-static int convert_response_xcrb(struct zcrypt_device *zdev,
+static int convert_response_xcrb(struct zcrypt_queue *zq,
                            struct ap_message *reply,
                            struct ica_xcRB *xcRB)
 {
@@ -810,28 +822,31 @@ static int convert_response_xcrb(struct zcrypt_device *zdev,
        case TYPE82_RSP_CODE:
        case TYPE88_RSP_CODE:
                xcRB->status = 0x0008044DL; /* HDD_InvalidParm */
-               return convert_error(zdev, reply);
+               return convert_error(zq, reply);
        case TYPE86_RSP_CODE:
                if (msg->hdr.reply_code) {
                        memcpy(&(xcRB->status), msg->fmt2.apfs, sizeof(u32));
-                       return convert_error(zdev, reply);
+                       return convert_error(zq, reply);
                }
                if (msg->cprbx.cprb_ver_id == 0x02)
-                       return convert_type86_xcrb(zdev, reply, xcRB);
+                       return convert_type86_xcrb(zq, reply, xcRB);
                /* Fall through, no break, incorrect cprb version is an unknown
                 * response */
        default: /* Unknown response type, this should NEVER EVER happen */
                xcRB->status = 0x0008044DL; /* HDD_InvalidParm */
-               zdev->online = 0;
-               pr_err("Cryptographic device %x failed and was set offline\n",
-                      AP_QID_DEVICE(zdev->ap_dev->qid));
-               ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%dfail",
-                              AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online);
+               zq->online = 0;
+               pr_err("Cryptographic device %02x.%04x failed and was set offline\n",
+                      AP_QID_CARD(zq->queue->qid),
+                      AP_QID_QUEUE(zq->queue->qid));
+               ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%dfail",
+                      AP_QID_CARD(zq->queue->qid),
+                      AP_QID_QUEUE(zq->queue->qid),
+                              zq->online);
                return -EAGAIN; /* repeat the request on a different device. */
        }
 }
 
-static int convert_response_ep11_xcrb(struct zcrypt_device *zdev,
+static int convert_response_ep11_xcrb(struct zcrypt_queue *zq,
        struct ap_message *reply, struct ep11_urb *xcRB)
 {
        struct type86_ep11_reply *msg = reply->message;
@@ -840,24 +855,27 @@ static int convert_response_ep11_xcrb(struct zcrypt_device *zdev,
        switch (((unsigned char *)reply->message)[1]) {
        case TYPE82_RSP_CODE:
        case TYPE87_RSP_CODE:
-               return convert_error(zdev, reply);
+               return convert_error(zq, reply);
        case TYPE86_RSP_CODE:
                if (msg->hdr.reply_code)
-                       return convert_error(zdev, reply);
+                       return convert_error(zq, reply);
                if (msg->cprbx.cprb_ver_id == 0x04)
-                       return convert_type86_ep11_xcrb(zdev, reply, xcRB);
+                       return convert_type86_ep11_xcrb(zq, reply, xcRB);
        /* Fall through, no break, incorrect cprb version is an unknown resp.*/
        default: /* Unknown response type, this should NEVER EVER happen */
-               zdev->online = 0;
-               pr_err("Cryptographic device %x failed and was set offline\n",
-                      AP_QID_DEVICE(zdev->ap_dev->qid));
-               ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%dfail",
-                              AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online);
+               zq->online = 0;
+               pr_err("Cryptographic device %02x.%04x failed and was set offline\n",
+                      AP_QID_CARD(zq->queue->qid),
+                      AP_QID_QUEUE(zq->queue->qid));
+               ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%dfail",
+                              AP_QID_CARD(zq->queue->qid),
+                              AP_QID_QUEUE(zq->queue->qid),
+                              zq->online);
                return -EAGAIN; /* repeat the request on a different device. */
        }
 }
 
-static int convert_response_rng(struct zcrypt_device *zdev,
+static int convert_response_rng(struct zcrypt_queue *zq,
                                 struct ap_message *reply,
                                 char *data)
 {
@@ -871,15 +889,18 @@ static int convert_response_rng(struct zcrypt_device *zdev,
                if (msg->hdr.reply_code)
                        return -EINVAL;
                if (msg->cprbx.cprb_ver_id == 0x02)
-                       return convert_type86_rng(zdev, reply, data);
+                       return convert_type86_rng(zq, reply, data);
                /* Fall through, no break, incorrect cprb version is an unknown
                 * response */
        default: /* Unknown response type, this should NEVER EVER happen */
-               zdev->online = 0;
-               pr_err("Cryptographic device %x failed and was set offline\n",
-                      AP_QID_DEVICE(zdev->ap_dev->qid));
-               ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%dfail",
-                              AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online);
+               zq->online = 0;
+               pr_err("Cryptographic device %02x.%04x failed and was set offline\n",
+                      AP_QID_CARD(zq->queue->qid),
+                      AP_QID_QUEUE(zq->queue->qid));
+               ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%dfail",
+                              AP_QID_CARD(zq->queue->qid),
+                              AP_QID_QUEUE(zq->queue->qid),
+                              zq->online);
                return -EAGAIN; /* repeat the request on a different device. */
        }
 }
@@ -888,11 +909,11 @@ static int convert_response_rng(struct zcrypt_device *zdev,
  * This function is called from the AP bus code after a crypto request
  * "msg" has finished with the reply message "reply".
  * It is called from tasklet context.
- * @ap_dev: pointer to the AP device
+ * @aq: pointer to the AP queue
  * @msg: pointer to the AP message
  * @reply: pointer to the AP reply message
  */
-static void zcrypt_msgtype6_receive(struct ap_device *ap_dev,
+static void zcrypt_msgtype6_receive(struct ap_queue *aq,
                                  struct ap_message *msg,
                                  struct ap_message *reply)
 {
@@ -937,11 +958,11 @@ out:
  * This function is called from the AP bus code after a crypto request
  * "msg" has finished with the reply message "reply".
  * It is called from tasklet context.
- * @ap_dev: pointer to the AP device
+ * @aq: pointer to the AP queue
  * @msg: pointer to the AP message
  * @reply: pointer to the AP reply message
  */
-static void zcrypt_msgtype6_receive_ep11(struct ap_device *ap_dev,
+static void zcrypt_msgtype6_receive_ep11(struct ap_queue *aq,
                                         struct ap_message *msg,
                                         struct ap_message *reply)
 {
@@ -981,11 +1002,11 @@ static atomic_t zcrypt_step = ATOMIC_INIT(0);
 /**
  * The request distributor calls this function if it picked the PCIXCC/CEX2C
  * device to handle a modexpo request.
- * @zdev: pointer to zcrypt_device structure that identifies the
+ * @zq: pointer to zcrypt_queue structure that identifies the
  *       PCIXCC/CEX2C device to the request distributor
  * @mex: pointer to the modexpo request buffer
  */
-static long zcrypt_msgtype6_modexpo(struct zcrypt_device *zdev,
+static long zcrypt_msgtype6_modexpo(struct zcrypt_queue *zq,
                                  struct ica_rsa_modexpo *mex)
 {
        struct ap_message ap_msg;
@@ -1002,21 +1023,21 @@ static long zcrypt_msgtype6_modexpo(struct zcrypt_device *zdev,
        ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
                                atomic_inc_return(&zcrypt_step);
        ap_msg.private = &resp_type;
-       rc = ICAMEX_msg_to_type6MEX_msgX(zdev, &ap_msg, mex);
+       rc = ICAMEX_msg_to_type6MEX_msgX(zq, &ap_msg, mex);
        if (rc)
                goto out_free;
        init_completion(&resp_type.work);
-       ap_queue_message(zdev->ap_dev, &ap_msg);
+       ap_queue_message(zq->queue, &ap_msg);
        rc = wait_for_completion_interruptible(&resp_type.work);
        if (rc == 0) {
                rc = ap_msg.rc;
                if (rc == 0)
-                       rc = convert_response_ica(zdev, &ap_msg,
+                       rc = convert_response_ica(zq, &ap_msg,
                                                  mex->outputdata,
                                                  mex->outputdatalength);
        } else
                /* Signal pending. */
-               ap_cancel_message(zdev->ap_dev, &ap_msg);
+               ap_cancel_message(zq->queue, &ap_msg);
 out_free:
        free_page((unsigned long) ap_msg.message);
        return rc;
@@ -1025,11 +1046,11 @@ out_free:
 /**
  * The request distributor calls this function if it picked the PCIXCC/CEX2C
  * device to handle a modexpo_crt request.
- * @zdev: pointer to zcrypt_device structure that identifies the
+ * @zq: pointer to zcrypt_queue structure that identifies the
  *       PCIXCC/CEX2C device to the request distributor
  * @crt: pointer to the modexpoc_crt request buffer
  */
-static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_device *zdev,
+static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq,
                                      struct ica_rsa_modexpo_crt *crt)
 {
        struct ap_message ap_msg;
@@ -1046,21 +1067,22 @@ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_device *zdev,
        ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
                                atomic_inc_return(&zcrypt_step);
        ap_msg.private = &resp_type;
-       rc = ICACRT_msg_to_type6CRT_msgX(zdev, &ap_msg, crt);
+       rc = ICACRT_msg_to_type6CRT_msgX(zq, &ap_msg, crt);
        if (rc)
                goto out_free;
        init_completion(&resp_type.work);
-       ap_queue_message(zdev->ap_dev, &ap_msg);
+       ap_queue_message(zq->queue, &ap_msg);
        rc = wait_for_completion_interruptible(&resp_type.work);
        if (rc == 0) {
                rc = ap_msg.rc;
                if (rc == 0)
-                       rc = convert_response_ica(zdev, &ap_msg,
+                       rc = convert_response_ica(zq, &ap_msg,
                                                  crt->outputdata,
                                                  crt->outputdatalength);
-       } else
+       } else {
                /* Signal pending. */
-               ap_cancel_message(zdev->ap_dev, &ap_msg);
+               ap_cancel_message(zq->queue, &ap_msg);
+       }
 out_free:
        free_page((unsigned long) ap_msg.message);
        return rc;
@@ -1068,7 +1090,7 @@ out_free:
 
 unsigned int get_cprb_fc(struct ica_xcRB *xcRB,
                                struct ap_message *ap_msg,
-                               int *func_code)
+                               unsigned int *func_code, unsigned short **dom)
 {
        struct response_type resp_type = {
                .type = PCIXCC_RESPONSE_TYPE_XCRB,
@@ -1088,7 +1110,7 @@ unsigned int get_cprb_fc(struct ica_xcRB *xcRB,
                return -ENOMEM;
        }
        memcpy(ap_msg->private, &resp_type, sizeof(resp_type));
-       rc = XCRB_msg_to_type6CPRB_msgX(ap_msg, xcRB, func_code);
+       rc = XCRB_msg_to_type6CPRB_msgX(ap_msg, xcRB, func_code, dom);
        if (rc) {
                kzfree(ap_msg->message);
                kzfree(ap_msg->private);
@@ -1099,11 +1121,11 @@ unsigned int get_cprb_fc(struct ica_xcRB *xcRB,
 /**
  * The request distributor calls this function if it picked the PCIXCC/CEX2C
  * device to handle a send_cprb request.
- * @zdev: pointer to zcrypt_device structure that identifies the
+ * @zq: pointer to zcrypt_queue structure that identifies the
  *       PCIXCC/CEX2C device to the request distributor
  * @xcRB: pointer to the send_cprb request buffer
  */
-static long zcrypt_msgtype6_send_cprb(struct zcrypt_device *zdev,
+static long zcrypt_msgtype6_send_cprb(struct zcrypt_queue *zq,
                                    struct ica_xcRB *xcRB,
                                    struct ap_message *ap_msg)
 {
@@ -1111,15 +1133,15 @@ static long zcrypt_msgtype6_send_cprb(struct zcrypt_device *zdev,
        struct response_type *rtype = (struct response_type *)(ap_msg->private);
 
        init_completion(&rtype->work);
-       ap_queue_message(zdev->ap_dev, ap_msg);
+       ap_queue_message(zq->queue, ap_msg);
        rc = wait_for_completion_interruptible(&rtype->work);
        if (rc == 0) {
                rc = ap_msg->rc;
                if (rc == 0)
-                       rc = convert_response_xcrb(zdev, ap_msg, xcRB);
+                       rc = convert_response_xcrb(zq, ap_msg, xcRB);
        } else
                /* Signal pending. */
-               ap_cancel_message(zdev->ap_dev, ap_msg);
+               ap_cancel_message(zq->queue, ap_msg);
 
        kzfree(ap_msg->message);
        kzfree(ap_msg->private);
@@ -1128,7 +1150,7 @@ static long zcrypt_msgtype6_send_cprb(struct zcrypt_device *zdev,
 
 unsigned int get_ep11cprb_fc(struct ep11_urb *xcrb,
                                    struct ap_message *ap_msg,
-                                   int *func_code)
+                                   unsigned int *func_code)
 {
        struct response_type resp_type = {
                .type = PCIXCC_RESPONSE_TYPE_EP11,
@@ -1159,11 +1181,11 @@ unsigned int get_ep11cprb_fc(struct ep11_urb *xcrb,
 /**
  * The request distributor calls this function if it picked the CEX4P
  * device to handle a send_ep11_cprb request.
- * @zdev: pointer to zcrypt_device structure that identifies the
+ * @zq: pointer to zcrypt_queue structure that identifies the
  *       CEX4P device to the request distributor
  * @xcRB: pointer to the ep11 user request block
  */
-static long zcrypt_msgtype6_send_ep11_cprb(struct zcrypt_device *zdev,
+static long zcrypt_msgtype6_send_ep11_cprb(struct zcrypt_queue *zq,
                                           struct ep11_urb *xcrb,
                                           struct ap_message *ap_msg)
 {
@@ -1196,7 +1218,7 @@ static long zcrypt_msgtype6_send_ep11_cprb(struct zcrypt_device *zdev,
         */
        if (!((msg->cprbx.flags & 0x80) == 0x80)) {
                msg->cprbx.target_id = (unsigned int)
-                                       AP_QID_QUEUE(zdev->ap_dev->qid);
+                                       AP_QID_QUEUE(zq->queue->qid);
 
                if ((msg->pld_lenfmt & 0x80) == 0x80) { /*ext.len.fmt 2 or 3*/
                        switch (msg->pld_lenfmt & 0x03) {
@@ -1214,26 +1236,27 @@ static long zcrypt_msgtype6_send_ep11_cprb(struct zcrypt_device *zdev,
                }
                payload_hdr = (struct pld_hdr *)((&(msg->pld_lenfmt))+lfmt);
                payload_hdr->dom_val = (unsigned int)
-                                       AP_QID_QUEUE(zdev->ap_dev->qid);
+                                       AP_QID_QUEUE(zq->queue->qid);
        }
 
        init_completion(&rtype->work);
-       ap_queue_message(zdev->ap_dev, ap_msg);
+       ap_queue_message(zq->queue, ap_msg);
        rc = wait_for_completion_interruptible(&rtype->work);
        if (rc == 0) {
                rc = ap_msg->rc;
                if (rc == 0)
-                       rc = convert_response_ep11_xcrb(zdev, ap_msg, xcrb);
+                       rc = convert_response_ep11_xcrb(zq, ap_msg, xcrb);
        } else
                /* Signal pending. */
-               ap_cancel_message(zdev->ap_dev, ap_msg);
+               ap_cancel_message(zq->queue, ap_msg);
 
        kzfree(ap_msg->message);
        kzfree(ap_msg->private);
        return rc;
 }
 
-unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code)
+unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code,
+                                                  unsigned int *domain)
 {
        struct response_type resp_type = {
                .type = PCIXCC_RESPONSE_TYPE_XCRB,
@@ -1253,7 +1276,7 @@ unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code)
        }
        memcpy(ap_msg->private, &resp_type, sizeof(resp_type));
 
-       rng_type6CPRB_msgX(ap_msg, ZCRYPT_RNG_BUFFER_SIZE);
+       rng_type6CPRB_msgX(ap_msg, ZCRYPT_RNG_BUFFER_SIZE, domain);
 
        *func_code = HWRNG;
        return 0;
@@ -1262,11 +1285,11 @@ unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code)
 /**
  * The request distributor calls this function if it picked the PCIXCC/CEX2C
  * device to generate random data.
- * @zdev: pointer to zcrypt_device structure that identifies the
+ * @zq: pointer to zcrypt_queue structure that identifies the
  *       PCIXCC/CEX2C device to the request distributor
  * @buffer: pointer to a memory page to return random data
  */
-static long zcrypt_msgtype6_rng(struct zcrypt_device *zdev,
+static long zcrypt_msgtype6_rng(struct zcrypt_queue *zq,
                                char *buffer, struct ap_message *ap_msg)
 {
        struct {
@@ -1281,18 +1304,18 @@ static long zcrypt_msgtype6_rng(struct zcrypt_device *zdev,
        struct response_type *rtype = (struct response_type *)(ap_msg->private);
        int rc;
 
-       msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid);
+       msg->cprbx.domain = AP_QID_QUEUE(zq->queue->qid);
 
        init_completion(&rtype->work);
-       ap_queue_message(zdev->ap_dev, ap_msg);
+       ap_queue_message(zq->queue, ap_msg);
        rc = wait_for_completion_interruptible(&rtype->work);
        if (rc == 0) {
                rc = ap_msg->rc;
                if (rc == 0)
-                       rc = convert_response_rng(zdev, ap_msg, buffer);
+                       rc = convert_response_rng(zq, ap_msg, buffer);
        } else
                /* Signal pending. */
-               ap_cancel_message(zdev->ap_dev, ap_msg);
+               ap_cancel_message(zq->queue, ap_msg);
 
        kzfree(ap_msg->message);
        kzfree(ap_msg->private);
index a360dbe3c7d2aad799907822b0cec693d1c19d2e..7a0d5b57821f07868c9af78da9873c1eca997c2e 100644 (file)
@@ -116,9 +116,11 @@ struct type86_fmt2_ext {
        unsigned int      offset4;      /* 0x00000000                   */
 } __packed;
 
-unsigned int get_cprb_fc(struct ica_xcRB *, struct ap_message *, int *);
-unsigned int get_ep11cprb_fc(struct ep11_urb *, struct ap_message *, int *);
-unsigned int get_rng_fc(struct ap_message *, int *);
+unsigned int get_cprb_fc(struct ica_xcRB *, struct ap_message *,
+                        unsigned int *, unsigned short **);
+unsigned int get_ep11cprb_fc(struct ep11_urb *, struct ap_message *,
+                            unsigned int *);
+unsigned int get_rng_fc(struct ap_message *, int *, unsigned int *);
 
 #define LOW    10
 #define MEDIUM 100
@@ -134,7 +136,8 @@ int speed_idx_ep11(int);
  * @ap_msg: pointer to AP message
  */
 static inline void rng_type6CPRB_msgX(struct ap_message *ap_msg,
-                                     unsigned int random_number_length)
+                                     unsigned int random_number_length,
+                                     unsigned int *domain)
 {
        struct {
                struct type6_hdr hdr;
@@ -172,6 +175,7 @@ static inline void rng_type6CPRB_msgX(struct ap_message *ap_msg,
        msg->verb_length = 0x02;
        msg->key_length = 0x02;
        ap_msg->length = sizeof(*msg);
+       *domain = (unsigned short)msg->cprbx.domain;
 }
 
 void zcrypt_msgtype6_init(void);
index 43de39c74944a5f6eaec03adbf123299f0950501..26ceaa6967650b683b24ebee498d09c0feb8b4fd 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/slab.h>
 #include <linux/atomic.h>
 #include <asm/uaccess.h>
+#include <linux/mod_devicetable.h>
 
 #include "ap_bus.h"
 #include "zcrypt_api.h"
@@ -62,142 +63,34 @@ struct response_type {
 #define PCIXCC_RESPONSE_TYPE_ICA  0
 #define PCIXCC_RESPONSE_TYPE_XCRB 1
 
-static struct ap_device_id zcrypt_pcixcc_ids[] = {
-       { AP_DEVICE(AP_DEVICE_TYPE_PCIXCC) },
-       { AP_DEVICE(AP_DEVICE_TYPE_CEX2C) },
-       { AP_DEVICE(AP_DEVICE_TYPE_CEX3C) },
-       { /* end of list */ },
-};
-
-MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_ids);
 MODULE_AUTHOR("IBM Corporation");
 MODULE_DESCRIPTION("PCIXCC Cryptographic Coprocessor device driver, " \
                   "Copyright IBM Corp. 2001, 2012");
 MODULE_LICENSE("GPL");
 
-static int zcrypt_pcixcc_probe(struct ap_device *ap_dev);
-static void zcrypt_pcixcc_remove(struct ap_device *ap_dev);
-
-static struct ap_driver zcrypt_pcixcc_driver = {
-       .probe = zcrypt_pcixcc_probe,
-       .remove = zcrypt_pcixcc_remove,
-       .ids = zcrypt_pcixcc_ids,
-       .request_timeout = PCIXCC_CLEANUP_TIME,
+static struct ap_device_id zcrypt_pcixcc_card_ids[] = {
+       { .dev_type = AP_DEVICE_TYPE_PCIXCC,
+         .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE },
+       { .dev_type = AP_DEVICE_TYPE_CEX2C,
+         .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE },
+       { .dev_type = AP_DEVICE_TYPE_CEX3C,
+         .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE },
+       { /* end of list */ },
 };
 
-/**
- * Micro-code detection function. Its sends a message to a pcixcc card
- * to find out the microcode level.
- * @ap_dev: pointer to the AP device.
- */
-static int zcrypt_pcixcc_mcl(struct ap_device *ap_dev)
-{
-       static unsigned char msg[] = {
-               0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x43,0x41,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x00,
-               0x00,0x00,0x01,0xC4,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x07,0x24,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x00,0xDC,0x02,0x00,0x00,0x00,0x54,0x32,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE8,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x24,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x0A,
-               0x4D,0x52,0x50,0x20,0x20,0x20,0x20,0x20,
-               0x00,0x42,0x00,0x01,0x02,0x03,0x04,0x05,
-               0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
-               0x0E,0x0F,0x00,0x11,0x22,0x33,0x44,0x55,
-               0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,
-               0xEE,0xFF,0xFF,0xEE,0xDD,0xCC,0xBB,0xAA,
-               0x99,0x88,0x77,0x66,0x55,0x44,0x33,0x22,
-               0x11,0x00,0x01,0x23,0x45,0x67,0x89,0xAB,
-               0xCD,0xEF,0xFE,0xDC,0xBA,0x98,0x76,0x54,
-               0x32,0x10,0x00,0x9A,0x00,0x98,0x00,0x00,
-               0x1E,0x00,0x00,0x94,0x00,0x00,0x00,0x00,
-               0x04,0x00,0x00,0x8C,0x00,0x00,0x00,0x40,
-               0x02,0x00,0x00,0x40,0xBA,0xE8,0x23,0x3C,
-               0x75,0xF3,0x91,0x61,0xD6,0x73,0x39,0xCF,
-               0x7B,0x6D,0x8E,0x61,0x97,0x63,0x9E,0xD9,
-               0x60,0x55,0xD6,0xC7,0xEF,0xF8,0x1E,0x63,
-               0x95,0x17,0xCC,0x28,0x45,0x60,0x11,0xC5,
-               0xC4,0x4E,0x66,0xC6,0xE6,0xC3,0xDE,0x8A,
-               0x19,0x30,0xCF,0x0E,0xD7,0xAA,0xDB,0x01,
-               0xD8,0x00,0xBB,0x8F,0x39,0x9F,0x64,0x28,
-               0xF5,0x7A,0x77,0x49,0xCC,0x6B,0xA3,0x91,
-               0x97,0x70,0xE7,0x60,0x1E,0x39,0xE1,0xE5,
-               0x33,0xE1,0x15,0x63,0x69,0x08,0x80,0x4C,
-               0x67,0xC4,0x41,0x8F,0x48,0xDF,0x26,0x98,
-               0xF1,0xD5,0x8D,0x88,0xD9,0x6A,0xA4,0x96,
-               0xC5,0x84,0xD9,0x30,0x49,0x67,0x7D,0x19,
-               0xB1,0xB3,0x45,0x4D,0xB2,0x53,0x9A,0x47,
-               0x3C,0x7C,0x55,0xBF,0xCC,0x85,0x00,0x36,
-               0xF1,0x3D,0x93,0x53
-       };
-       unsigned long long psmid;
-       struct CPRBX *cprbx;
-       char *reply;
-       int rc, i;
-
-       reply = (void *) get_zeroed_page(GFP_KERNEL);
-       if (!reply)
-               return -ENOMEM;
+MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_card_ids);
 
-       rc = ap_send(ap_dev->qid, 0x0102030405060708ULL, msg, sizeof(msg));
-       if (rc)
-               goto out_free;
-
-       /* Wait for the test message to complete. */
-       for (i = 0; i < 6; i++) {
-               msleep(300);
-               rc = ap_recv(ap_dev->qid, &psmid, reply, 4096);
-               if (rc == 0 && psmid == 0x0102030405060708ULL)
-                       break;
-       }
-
-       if (i >= 6) {
-               /* Got no answer. */
-               rc = -ENODEV;
-               goto out_free;
-       }
+static struct ap_device_id zcrypt_pcixcc_queue_ids[] = {
+       { .dev_type = AP_DEVICE_TYPE_PCIXCC,
+         .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
+       { .dev_type = AP_DEVICE_TYPE_CEX2C,
+         .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
+       { .dev_type = AP_DEVICE_TYPE_CEX3C,
+         .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
+       { /* end of list */ },
+};
 
-       cprbx = (struct CPRBX *) (reply + 48);
-       if (cprbx->ccp_rtcode == 8 && cprbx->ccp_rscode == 33)
-               rc = ZCRYPT_PCIXCC_MCL2;
-       else
-               rc = ZCRYPT_PCIXCC_MCL3;
-out_free:
-       free_page((unsigned long) reply);
-       return rc;
-}
+MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_queue_ids);
 
 /**
  * Large random number detection function. Its sends a message to a pcixcc
@@ -206,10 +99,11 @@ out_free:
  *
  * Returns 1 if large random numbers are supported, 0 if not and < 0 on error.
  */
-static int zcrypt_pcixcc_rng_supported(struct ap_device *ap_dev)
+static int zcrypt_pcixcc_rng_supported(struct ap_queue *aq)
 {
        struct ap_message ap_msg;
        unsigned long long psmid;
+       unsigned int domain;
        struct {
                struct type86_hdr hdr;
                struct type86_fmt2_ext fmt2;
@@ -231,12 +125,12 @@ static int zcrypt_pcixcc_rng_supported(struct ap_device *ap_dev)
        if (!ap_msg.message)
                return -ENOMEM;
 
-       rng_type6CPRB_msgX(&ap_msg, 4);
+       rng_type6CPRB_msgX(&ap_msg, 4, &domain);
 
        msg = ap_msg.message;
-       msg->cprbx.domain = AP_QID_QUEUE(ap_dev->qid);
+       msg->cprbx.domain = AP_QID_QUEUE(aq->qid);
 
-       rc = ap_send(ap_dev->qid, 0x0102030405060708ULL, ap_msg.message,
+       rc = ap_send(aq->qid, 0x0102030405060708ULL, ap_msg.message,
                     ap_msg.length);
        if (rc)
                goto out_free;
@@ -244,7 +138,7 @@ static int zcrypt_pcixcc_rng_supported(struct ap_device *ap_dev)
        /* Wait for the test message to complete. */
        for (i = 0; i < 2 * HZ; i++) {
                msleep(1000 / HZ);
-               rc = ap_recv(ap_dev->qid, &psmid, ap_msg.message, 4096);
+               rc = ap_recv(aq->qid, &psmid, ap_msg.message, 4096);
                if (rc == 0 && psmid == 0x0102030405060708ULL)
                        break;
        }
@@ -266,120 +160,168 @@ out_free:
 }
 
 /**
- * Probe function for PCIXCC/CEX2C cards. It always accepts the AP device
- * since the bus_match already checked the hardware type. The PCIXCC
- * cards come in two flavours: micro code level 2 and micro code level 3.
- * This is checked by sending a test message to the device.
- * @ap_dev: pointer to the AP device.
+ * Probe function for PCIXCC/CEX2C card devices. It always accepts the
+ * AP device since the bus_match already checked the hardware type. The
+ * PCIXCC cards come in two flavours: micro code level 2 and micro code
+ * level 3. This is checked by sending a test message to the device.
+ * @ap_dev: pointer to the AP card device.
  */
-static int zcrypt_pcixcc_probe(struct ap_device *ap_dev)
+static int zcrypt_pcixcc_card_probe(struct ap_device *ap_dev)
 {
-       struct zcrypt_device *zdev;
        /*
         * Normalized speed ratings per crypto adapter
         * MEX_1k, MEX_2k, MEX_4k, CRT_1k, CRT_2k, CRT_4k, RNG, SECKEY
         */
-       int PCIXCC_MCL2_SPEED_IDX[] = {10, 10, 10, 10, 10, 10, 10, 10};
-       int PCIXCC_MCL3_SPEED_IDX[] = { 8,  8,  8,  8,  8,  8,  8,  8};
-       int CEX2C_SPEED_IDX[] = {1000, 1400, 2400, 1100, 1500, 2600, 100, 12};
-       int CEX3C_SPEED_IDX[] = { 500,  700, 1400,  550,  800, 1500,  80, 10};
+       static const int CEX2C_SPEED_IDX[] = {
+               1000, 1400, 2400, 1100, 1500, 2600, 100, 12};
+       static const int CEX3C_SPEED_IDX[] = {
+               500,  700, 1400,  550,  800, 1500,  80, 10};
+
+       struct ap_card *ac = to_ap_card(&ap_dev->device);
+       struct zcrypt_card *zc;
        int rc = 0;
 
-       zdev = zcrypt_device_alloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE);
-       if (!zdev)
+       zc = zcrypt_card_alloc();
+       if (!zc)
                return -ENOMEM;
-       zdev->ap_dev = ap_dev;
-       zdev->online = 1;
-       switch (ap_dev->device_type) {
-       case AP_DEVICE_TYPE_PCIXCC:
-               rc = zcrypt_pcixcc_mcl(ap_dev);
-               if (rc < 0) {
-                       zcrypt_device_free(zdev);
-                       return rc;
-               }
-               zdev->user_space_type = rc;
-               if (rc == ZCRYPT_PCIXCC_MCL2) {
-                       zdev->type_string = "PCIXCC_MCL2";
-                       memcpy(zdev->speed_rating, PCIXCC_MCL2_SPEED_IDX,
-                              sizeof(PCIXCC_MCL2_SPEED_IDX));
-                       zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
-                       zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
-                       zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE;
-               } else {
-                       zdev->type_string = "PCIXCC_MCL3";
-                       memcpy(zdev->speed_rating, PCIXCC_MCL3_SPEED_IDX,
-                              sizeof(PCIXCC_MCL3_SPEED_IDX));
-                       zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE;
-                       zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
-                       zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE;
-               }
-               break;
+       zc->card = ac;
+       ac->private = zc;
+       switch (ac->ap_dev.device_type) {
        case AP_DEVICE_TYPE_CEX2C:
-               zdev->user_space_type = ZCRYPT_CEX2C;
-               zdev->type_string = "CEX2C";
-               memcpy(zdev->speed_rating, CEX2C_SPEED_IDX,
+               zc->user_space_type = ZCRYPT_CEX2C;
+               zc->type_string = "CEX2C";
+               memcpy(zc->speed_rating, CEX2C_SPEED_IDX,
                       sizeof(CEX2C_SPEED_IDX));
-               zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE;
-               zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
-               zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE;
+               zc->min_mod_size = PCIXCC_MIN_MOD_SIZE;
+               zc->max_mod_size = PCIXCC_MAX_MOD_SIZE;
+               zc->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE;
                break;
        case AP_DEVICE_TYPE_CEX3C:
-               zdev->user_space_type = ZCRYPT_CEX3C;
-               zdev->type_string = "CEX3C";
-               memcpy(zdev->speed_rating, CEX3C_SPEED_IDX,
+               zc->user_space_type = ZCRYPT_CEX3C;
+               zc->type_string = "CEX3C";
+               memcpy(zc->speed_rating, CEX3C_SPEED_IDX,
                       sizeof(CEX3C_SPEED_IDX));
-               zdev->min_mod_size = CEX3C_MIN_MOD_SIZE;
-               zdev->max_mod_size = CEX3C_MAX_MOD_SIZE;
-               zdev->max_exp_bit_length = CEX3C_MAX_MOD_SIZE;
+               zc->min_mod_size = CEX3C_MIN_MOD_SIZE;
+               zc->max_mod_size = CEX3C_MAX_MOD_SIZE;
+               zc->max_exp_bit_length = CEX3C_MAX_MOD_SIZE;
                break;
        default:
-               goto out_free;
+               zcrypt_card_free(zc);
+               return -ENODEV;
        }
-       zdev->load = zdev->speed_rating[0];
+       zc->online = 1;
 
-       rc = zcrypt_pcixcc_rng_supported(ap_dev);
+       rc = zcrypt_card_register(zc);
+       if (rc) {
+               ac->private = NULL;
+               zcrypt_card_free(zc);
+       }
+
+       return rc;
+}
+
+/**
+ * This is called to remove the PCIXCC/CEX2C card driver information
+ * if an AP card device is removed.
+ */
+static void zcrypt_pcixcc_card_remove(struct ap_device *ap_dev)
+{
+       struct zcrypt_card *zc = to_ap_card(&ap_dev->device)->private;
+
+       if (zc)
+               zcrypt_card_unregister(zc);
+}
+
+static struct ap_driver zcrypt_pcixcc_card_driver = {
+       .probe = zcrypt_pcixcc_card_probe,
+       .remove = zcrypt_pcixcc_card_remove,
+       .ids = zcrypt_pcixcc_card_ids,
+};
+
+/**
+ * Probe function for PCIXCC/CEX2C queue devices. It always accepts the
+ * AP device since the bus_match already checked the hardware type. The
+ * PCIXCC cards come in two flavours: micro code level 2 and micro code
+ * level 3. This is checked by sending a test message to the device.
+ * @ap_dev: pointer to the AP card device.
+ */
+static int zcrypt_pcixcc_queue_probe(struct ap_device *ap_dev)
+{
+       struct ap_queue *aq = to_ap_queue(&ap_dev->device);
+       struct zcrypt_queue *zq;
+       int rc;
+
+       zq = zcrypt_queue_alloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE);
+       if (!zq)
+               return -ENOMEM;
+       zq->queue = aq;
+       zq->online = 1;
+       atomic_set(&zq->load, 0);
+       rc = zcrypt_pcixcc_rng_supported(aq);
        if (rc < 0) {
-               zcrypt_device_free(zdev);
+               zcrypt_queue_free(zq);
                return rc;
        }
        if (rc)
-               zdev->ops = zcrypt_msgtype(MSGTYPE06_NAME,
-                                          MSGTYPE06_VARIANT_DEFAULT);
+               zq->ops = zcrypt_msgtype(MSGTYPE06_NAME,
+                                        MSGTYPE06_VARIANT_DEFAULT);
        else
-               zdev->ops = zcrypt_msgtype(MSGTYPE06_NAME,
-                                          MSGTYPE06_VARIANT_NORNG);
-       ap_device_init_reply(ap_dev, &zdev->reply);
-       ap_dev->private = zdev;
-       rc = zcrypt_device_register(zdev);
-       if (rc)
-               goto out_free;
-       return 0;
-
- out_free:
-       ap_dev->private = NULL;
-       zcrypt_device_free(zdev);
+               zq->ops = zcrypt_msgtype(MSGTYPE06_NAME,
+                                        MSGTYPE06_VARIANT_NORNG);
+       ap_queue_init_reply(aq, &zq->reply);
+       aq->request_timeout = PCIXCC_CLEANUP_TIME,
+       aq->private = zq;
+       rc = zcrypt_queue_register(zq);
+       if (rc) {
+               aq->private = NULL;
+               zcrypt_queue_free(zq);
+       }
        return rc;
 }
 
 /**
- * This is called to remove the extended PCIXCC/CEX2C driver information
- * if an AP device is removed.
+ * This is called to remove the PCIXCC/CEX2C queue driver information
+ * if an AP queue device is removed.
  */
-static void zcrypt_pcixcc_remove(struct ap_device *ap_dev)
+static void zcrypt_pcixcc_queue_remove(struct ap_device *ap_dev)
 {
-       struct zcrypt_device *zdev = ap_dev->private;
+       struct ap_queue *aq = to_ap_queue(&ap_dev->device);
+       struct zcrypt_queue *zq = aq->private;
 
-       zcrypt_device_unregister(zdev);
+       ap_queue_remove(aq);
+       if (zq)
+               zcrypt_queue_unregister(zq);
 }
 
+static struct ap_driver zcrypt_pcixcc_queue_driver = {
+       .probe = zcrypt_pcixcc_queue_probe,
+       .remove = zcrypt_pcixcc_queue_remove,
+       .suspend = ap_queue_suspend,
+       .resume = ap_queue_resume,
+       .ids = zcrypt_pcixcc_queue_ids,
+};
+
 int __init zcrypt_pcixcc_init(void)
 {
-       return ap_driver_register(&zcrypt_pcixcc_driver, THIS_MODULE, "pcixcc");
+       int rc;
+
+       rc = ap_driver_register(&zcrypt_pcixcc_card_driver,
+                               THIS_MODULE, "pcixcccard");
+       if (rc)
+               return rc;
+
+       rc = ap_driver_register(&zcrypt_pcixcc_queue_driver,
+                               THIS_MODULE, "pcixccqueue");
+       if (rc)
+               ap_driver_unregister(&zcrypt_pcixcc_card_driver);
+
+       return rc;
 }
 
 void zcrypt_pcixcc_exit(void)
 {
-       ap_driver_unregister(&zcrypt_pcixcc_driver);
+       ap_driver_unregister(&zcrypt_pcixcc_queue_driver);
+       ap_driver_unregister(&zcrypt_pcixcc_card_driver);
 }
 
 module_init(zcrypt_pcixcc_init);
diff --git a/drivers/s390/crypto/zcrypt_queue.c b/drivers/s390/crypto/zcrypt_queue.c
new file mode 100644 (file)
index 0000000..c70b252
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ *  zcrypt 2.1.0
+ *
+ *  Copyright IBM Corp. 2001, 2012
+ *  Author(s): Robert Burroughs
+ *            Eric Rossman (edrossma@us.ibm.com)
+ *            Cornelia Huck <cornelia.huck@de.ibm.com>
+ *
+ *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ *  Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *                               Ralph Wuerthner <rwuerthn@de.ibm.com>
+ *  MSGTYPE restruct:            Holger Dengler <hd@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/compat.h>
+#include <linux/slab.h>
+#include <linux/atomic.h>
+#include <linux/uaccess.h>
+#include <linux/hw_random.h>
+#include <linux/debugfs.h>
+#include <asm/debug.h>
+
+#include "zcrypt_debug.h"
+#include "zcrypt_api.h"
+
+#include "zcrypt_msgtype6.h"
+#include "zcrypt_msgtype50.h"
+
+/*
+ * Device attributes common for all crypto queue devices.
+ */
+
+static ssize_t zcrypt_queue_online_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct zcrypt_queue *zq = to_ap_queue(dev)->private;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", zq->online);
+}
+
+static ssize_t zcrypt_queue_online_store(struct device *dev,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t count)
+{
+       struct zcrypt_queue *zq = to_ap_queue(dev)->private;
+       struct zcrypt_card *zc = zq->zcard;
+       int online;
+
+       if (sscanf(buf, "%d\n", &online) != 1 || online < 0 || online > 1)
+               return -EINVAL;
+
+       if (online && !zc->online)
+               return -EINVAL;
+       zq->online = online;
+       ZCRYPT_DBF_DEV(DBF_INFO, zq, "dev%02x%04xo%dman",
+                      AP_QID_CARD(zq->queue->qid),
+                      AP_QID_QUEUE(zq->queue->qid), online);
+       if (!online)
+               ap_flush_queue(zq->queue);
+       return count;
+}
+
+static DEVICE_ATTR(online, 0644, zcrypt_queue_online_show,
+                  zcrypt_queue_online_store);
+
+static struct attribute *zcrypt_queue_attrs[] = {
+       &dev_attr_online.attr,
+       NULL,
+};
+
+static struct attribute_group zcrypt_queue_attr_group = {
+       .attrs = zcrypt_queue_attrs,
+};
+
+void zcrypt_queue_force_online(struct zcrypt_queue *zq, int online)
+{
+       zq->online = online;
+       if (!online)
+               ap_flush_queue(zq->queue);
+}
+
+struct zcrypt_queue *zcrypt_queue_alloc(size_t max_response_size)
+{
+       struct zcrypt_queue *zq;
+
+       zq = kzalloc(sizeof(struct zcrypt_queue), GFP_KERNEL);
+       if (!zq)
+               return NULL;
+       zq->reply.message = kmalloc(max_response_size, GFP_KERNEL);
+       if (!zq->reply.message)
+               goto out_free;
+       zq->reply.length = max_response_size;
+       INIT_LIST_HEAD(&zq->list);
+       zq->dbf_area = zcrypt_dbf_devices;
+       kref_init(&zq->refcount);
+       return zq;
+
+out_free:
+       kfree(zq);
+       return NULL;
+}
+EXPORT_SYMBOL(zcrypt_queue_alloc);
+
+void zcrypt_queue_free(struct zcrypt_queue *zq)
+{
+       kfree(zq->reply.message);
+       kfree(zq);
+}
+EXPORT_SYMBOL(zcrypt_queue_free);
+
+static void zcrypt_queue_release(struct kref *kref)
+{
+       struct zcrypt_queue *zq =
+               container_of(kref, struct zcrypt_queue, refcount);
+       zcrypt_queue_free(zq);
+}
+
+void zcrypt_queue_get(struct zcrypt_queue *zq)
+{
+       kref_get(&zq->refcount);
+}
+EXPORT_SYMBOL(zcrypt_queue_get);
+
+int zcrypt_queue_put(struct zcrypt_queue *zq)
+{
+       return kref_put(&zq->refcount, zcrypt_queue_release);
+}
+EXPORT_SYMBOL(zcrypt_queue_put);
+
+/**
+ * zcrypt_queue_register() - Register a crypto queue device.
+ * @zq: Pointer to a crypto queue device
+ *
+ * Register a crypto queue device. Returns 0 if successful.
+ */
+int zcrypt_queue_register(struct zcrypt_queue *zq)
+{
+       struct zcrypt_card *zc;
+       int rc;
+
+       spin_lock(&zcrypt_list_lock);
+       zc = zq->queue->card->private;
+       zcrypt_card_get(zc);
+       zq->zcard = zc;
+       zq->online = 1; /* New devices are online by default. */
+       ZCRYPT_DBF_DEV(DBF_INFO, zq, "dev%02x%04xo%dreg",
+                      AP_QID_CARD(zq->queue->qid),
+                      AP_QID_QUEUE(zq->queue->qid),
+                      zq->online);
+       list_add_tail(&zq->list, &zc->zqueues);
+       zcrypt_device_count++;
+       spin_unlock(&zcrypt_list_lock);
+
+       rc = sysfs_create_group(&zq->queue->ap_dev.device.kobj,
+                               &zcrypt_queue_attr_group);
+       if (rc)
+               goto out;
+       get_device(&zq->queue->ap_dev.device);
+
+       if (zq->ops->rng) {
+               rc = zcrypt_rng_device_add();
+               if (rc)
+                       goto out_unregister;
+       }
+       return 0;
+
+out_unregister:
+       sysfs_remove_group(&zq->queue->ap_dev.device.kobj,
+                          &zcrypt_queue_attr_group);
+       put_device(&zq->queue->ap_dev.device);
+out:
+       spin_lock(&zcrypt_list_lock);
+       list_del_init(&zq->list);
+       spin_unlock(&zcrypt_list_lock);
+       zcrypt_card_put(zc);
+       return rc;
+}
+EXPORT_SYMBOL(zcrypt_queue_register);
+
+/**
+ * zcrypt_queue_unregister(): Unregister a crypto queue device.
+ * @zq: Pointer to crypto queue device
+ *
+ * Unregister a crypto queue device.
+ */
+void zcrypt_queue_unregister(struct zcrypt_queue *zq)
+{
+       struct zcrypt_card *zc;
+
+       zc = zq->zcard;
+       spin_lock(&zcrypt_list_lock);
+       list_del_init(&zq->list);
+       zcrypt_device_count--;
+       spin_unlock(&zcrypt_list_lock);
+       zcrypt_card_put(zc);
+       if (zq->ops->rng)
+               zcrypt_rng_device_remove();
+       sysfs_remove_group(&zq->queue->ap_dev.device.kobj,
+                          &zcrypt_queue_attr_group);
+       put_device(&zq->queue->ap_dev.device);
+       zcrypt_queue_put(zq);
+}
+EXPORT_SYMBOL(zcrypt_queue_unregister);
index ed84c07f6a510f48e24d53e0d54afaeb50a182f3..8a57f0b1242d741ef0ebab33cab628773a3e289f 100644 (file)
@@ -175,7 +175,8 @@ struct ap_device_id {
        kernel_ulong_t driver_info;
 };
 
-#define AP_DEVICE_ID_MATCH_DEVICE_TYPE         0x01
+#define AP_DEVICE_ID_MATCH_CARD_TYPE           0x01
+#define AP_DEVICE_ID_MATCH_QUEUE_TYPE          0x02
 
 /* s390 css bus devices (subchannels) */
 struct css_device_id {