zcrypt_pcixcc.c 8.8 KB
Newer Older
1
/*
2
 *  zcrypt 2.1.0
3
 *
4
 *  Copyright IBM Corp. 2001, 2012
5 6 7 8 9 10
 *  Author(s): Robert Burroughs
 *	       Eric Rossman (edrossma@us.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>
11
 *  MSGTYPE restruct:		  Holger Dengler <hd@linux.vnet.ibm.com>
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/delay.h>
32
#include <linux/slab.h>
A
Arun Sharma 已提交
33
#include <linux/atomic.h>
34
#include <linux/uaccess.h>
35
#include <linux/mod_devicetable.h>
36 37 38 39

#include "ap_bus.h"
#include "zcrypt_api.h"
#include "zcrypt_error.h"
40
#include "zcrypt_msgtype6.h"
41 42 43 44 45 46
#include "zcrypt_pcixcc.h"
#include "zcrypt_cca_key.h"

#define PCIXCC_MIN_MOD_SIZE	 16	/*  128 bits	*/
#define PCIXCC_MIN_MOD_SIZE_OLD	 64	/*  512 bits	*/
#define PCIXCC_MAX_MOD_SIZE	256	/* 2048 bits	*/
47
#define CEX3C_MIN_MOD_SIZE	PCIXCC_MIN_MOD_SIZE
48
#define CEX3C_MAX_MOD_SIZE	512	/* 4096 bits	*/
49 50 51 52 53 54 55 56

#define PCIXCC_MAX_ICA_MESSAGE_SIZE 0x77c  /* max size type6 v2 crt message */
#define PCIXCC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply	    */

#define PCIXCC_MAX_XCRB_MESSAGE_SIZE (12*1024)

#define PCIXCC_CLEANUP_TIME	(15*HZ)

57 58 59 60 61 62 63 64 65
#define CEIL4(x) ((((x)+3)/4)*4)

struct response_type {
	struct completion work;
	int type;
};
#define PCIXCC_RESPONSE_TYPE_ICA  0
#define PCIXCC_RESPONSE_TYPE_XCRB 1

66
MODULE_AUTHOR("IBM Corporation");
67 68
MODULE_DESCRIPTION("PCIXCC Cryptographic Coprocessor device driver, " \
		   "Copyright IBM Corp. 2001, 2012");
69 70
MODULE_LICENSE("GPL");

71 72 73 74 75 76 77 78
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 */ },
79 80
};

81
MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_card_ids);
82

83 84 85 86 87 88 89 90 91
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 */ },
};
92

93
MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_queue_ids);
94

95 96 97 98 99 100 101
/**
 * Large random number detection function. Its sends a message to a pcixcc
 * card to find out if large random numbers are supported.
 * @ap_dev: pointer to the AP device.
 *
 * Returns 1 if large random numbers are supported, 0 if not and < 0 on error.
 */
102
static int zcrypt_pcixcc_rng_supported(struct ap_queue *aq)
103 104 105
{
	struct ap_message ap_msg;
	unsigned long long psmid;
106
	unsigned int domain;
107 108 109 110 111
	struct {
		struct type86_hdr hdr;
		struct type86_fmt2_ext fmt2;
		struct CPRBX cprbx;
	} __attribute__((packed)) *reply;
112 113 114 115 116 117 118 119 120
	struct {
		struct type6_hdr hdr;
		struct CPRBX cprbx;
		char function_code[2];
		short int rule_length;
		char rule[8];
		short int verb_length;
		short int key_length;
	} __packed * msg;
121 122
	int rc, i;

123
	ap_init_message(&ap_msg);
124 125 126 127
	ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
	if (!ap_msg.message)
		return -ENOMEM;

128
	rng_type6CPRB_msgX(&ap_msg, 4, &domain);
129 130

	msg = ap_msg.message;
131
	msg->cprbx.domain = AP_QID_QUEUE(aq->qid);
132

133
	rc = ap_send(aq->qid, 0x0102030405060708ULL, ap_msg.message,
134 135 136 137 138 139 140
		     ap_msg.length);
	if (rc)
		goto out_free;

	/* Wait for the test message to complete. */
	for (i = 0; i < 2 * HZ; i++) {
		msleep(1000 / HZ);
141
		rc = ap_recv(aq->qid, &psmid, ap_msg.message, 4096);
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
		if (rc == 0 && psmid == 0x0102030405060708ULL)
			break;
	}

	if (i >= 2 * HZ) {
		/* Got no answer. */
		rc = -ENODEV;
		goto out_free;
	}

	reply = ap_msg.message;
	if (reply->cprbx.ccp_rtcode == 0 && reply->cprbx.ccp_rscode == 0)
		rc = 1;
	else
		rc = 0;
out_free:
	free_page((unsigned long) ap_msg.message);
	return rc;
}

162
/**
163 164 165 166 167
 * 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.
168
 */
169
static int zcrypt_pcixcc_card_probe(struct ap_device *ap_dev)
170
{
171 172 173 174
	/*
	 * Normalized speed ratings per crypto adapter
	 * MEX_1k, MEX_2k, MEX_4k, CRT_1k, CRT_2k, CRT_4k, RNG, SECKEY
	 */
175 176 177 178 179 180 181
	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;
182
	int rc = 0;
183

184 185
	zc = zcrypt_card_alloc();
	if (!zc)
186
		return -ENOMEM;
187 188 189
	zc->card = ac;
	ac->private = zc;
	switch (ac->ap_dev.device_type) {
190
	case AP_DEVICE_TYPE_CEX2C:
191 192 193
		zc->user_space_type = ZCRYPT_CEX2C;
		zc->type_string = "CEX2C";
		memcpy(zc->speed_rating, CEX2C_SPEED_IDX,
194
		       sizeof(CEX2C_SPEED_IDX));
195 196 197
		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;
198 199
		break;
	case AP_DEVICE_TYPE_CEX3C:
200 201 202
		zc->user_space_type = ZCRYPT_CEX3C;
		zc->type_string = "CEX3C";
		memcpy(zc->speed_rating, CEX3C_SPEED_IDX,
203
		       sizeof(CEX3C_SPEED_IDX));
204 205 206
		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;
207 208
		break;
	default:
209 210
		zcrypt_card_free(zc);
		return -ENODEV;
211
	}
212
	zc->online = 1;
213

214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
	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);
261
	if (rc < 0) {
262
		zcrypt_queue_free(zq);
263 264 265
		return rc;
	}
	if (rc)
266 267
		zq->ops = zcrypt_msgtype(MSGTYPE06_NAME,
					 MSGTYPE06_VARIANT_DEFAULT);
268
	else
269 270 271 272 273 274 275 276 277 278
		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);
	}
279 280 281 282
	return rc;
}

/**
283 284
 * This is called to remove the PCIXCC/CEX2C queue driver information
 * if an AP queue device is removed.
285
 */
286
static void zcrypt_pcixcc_queue_remove(struct ap_device *ap_dev)
287
{
288 289
	struct ap_queue *aq = to_ap_queue(&ap_dev->device);
	struct zcrypt_queue *zq = aq->private;
290

291 292 293
	ap_queue_remove(aq);
	if (zq)
		zcrypt_queue_unregister(zq);
294 295
}

296 297 298 299 300 301 302 303
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,
};

304 305
int __init zcrypt_pcixcc_init(void)
{
306 307 308 309 310 311 312 313 314 315 316 317 318
	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;
319 320 321 322
}

void zcrypt_pcixcc_exit(void)
{
323 324
	ap_driver_unregister(&zcrypt_pcixcc_queue_driver);
	ap_driver_unregister(&zcrypt_pcixcc_card_driver);
325 326 327 328
}

module_init(zcrypt_pcixcc_init);
module_exit(zcrypt_pcixcc_exit);