aboutsummaryrefslogtreecommitdiffstats
path: root/include/scsi/scsi.h
blob: 5c0e9791441c91ab712608b078ba420f0852e1d9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
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
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
/*
 * This header file contains public constants and structures used by
 * the scsi code for linux.
 *
 * For documentation on the OPCODES, MESSAGES, and SENSE values,
 * please consult the SCSI standard.
 */
#ifndef _SCSI_SCSI_H
#define _SCSI_SCSI_H

#include <linux/types.h>

/*
 *	The maximum sg list length SCSI can cope with
 *	(currently must be a power of 2 between 32 and 256)
 */
#define SCSI_MAX_PHYS_SEGMENTS	MAX_PHYS_SEGMENTS


/*
 *	SCSI command lengths
 */

extern const unsigned char scsi_command_size[8];
#define COMMAND_SIZE(opcode) scsi_command_size[((opcode) >> 5) & 7]

/*
 * Special value for scanning to specify scanning or rescanning of all
 * possible channels, (target) ids, or luns on a given shost.
 */
#define SCAN_WILD_CARD	~0

/*
 *      SCSI opcodes
 */

#define TEST_UNIT_READY       0x00
#define REZERO_UNIT           0x01
#define REQUEST_SENSE         0x03
#define FORMAT_UNIT           0x04
#define READ_BLOCK_LIMITS     0x05
#define REASSIGN_BLOCKS       0x07
#define INITIALIZE_ELEMENT_STATUS 0x07
#define READ_6                0x08
#define WRITE_6               0x0a
#define SEEK_6                0x0b
#define READ_REVERSE          0x0f
#define WRITE_FILEMARKS       0x10
#define SPACE                 0x11
#define INQUIRY               0x12
#define RECOVER_BUFFERED_DATA 0x14
#define MODE_SELECT           0x15
#define RESERVE               0x16
#define RELEASE               0x17
#define COPY                  0x18
#define ERASE                 0x19
#define MODE_SENSE            0x1a
#define START_STOP            0x1b
#define RECEIVE_DIAGNOSTIC    0x1c
#define SEND_DIAGNOSTIC       0x1d
#define ALLOW_MEDIUM_REMOVAL  0x1e

#define SET_WINDOW            0x24
#define READ_CAPACITY         0x25
#define READ_10               0x28
#define WRITE_10              0x2a
#define SEEK_10               0x2b
#define POSITION_TO_ELEMENT   0x2b
#define WRITE_VERIFY          0x2e
#define VERIFY                0x2f
#define SEARCH_HIGH           0x30
#define SEARCH_EQUAL          0x31
#define SEARCH_LOW            0x32
#define SET_LIMITS            0x33
#define PRE_FETCH             0x34
#define READ_POSITION         0x34
#define SYNCHRONIZE_CACHE     0x35
#define LOCK_UNLOCK_CACHE     0x36
#define READ_DEFECT_DATA      0x37
#define MEDIUM_SCAN           0x38
#define COMPARE               0x39
#define COPY_VERIFY           0x3a
#define WRITE_BUFFER          0x3b
#define READ_BUFFER           0x3c
#define UPDATE_BLOCK          0x3d
#define READ_LONG             0x3e
#define WRITE_LONG            0x3f
#define CHANGE_DEFINITION     0x40
#define WRITE_SAME            0x41
#define READ_TOC              0x43
#define LOG_SELECT            0x4c
#define LOG_SENSE             0x4d
#define MODE_SELECT_10        0x55
#define RESERVE_10            0x56
#define RELEASE_10            0x57
#define MODE_SENSE_10         0x5a
#define PERSISTENT_RESERVE_IN 0x5e
#define PERSISTENT_RESERVE_OUT 0x5f
#define REPORT_LUNS           0xa0
#define MAINTENANCE_IN        0xa3
#define MOVE_MEDIUM           0xa5
#define EXCHANGE_MEDIUM       0xa6
#define READ_12               0xa8
#define WRITE_12              0xaa
#define WRITE_VERIFY_12       0xae
#define SEARCH_HIGH_12        0xb0
#define SEARCH_EQUAL_12       0xb1
#define SEARCH_LOW_12         0xb2
#define READ_ELEMENT_STATUS   0xb8
#define SEND_VOLUME_TAG       0xb6
#define WRITE_LONG_2          0xea
#define READ_16               0x88
#define WRITE_16              0x8a
#define VERIFY_16	      0x8f
#define SERVICE_ACTION_IN     0x9e
/* values for service action in */
#define	SAI_READ_CAPACITY_16  0x10
/* values for maintenance in */
#define MI_REPORT_TARGET_PGS  0x0a

/* Values for T10/04-262r7 */
#define	ATA_16		      0x85	/* 16-byte pass-thru */
#define	ATA_12		      0xa1	/* 12-byte pass-thru */

/*
 *  SCSI Architecture Model (SAM) Status codes. Taken from SAM-3 draft
 *  T10/1561-D Revision 4 Draft dated 7th November 2002.
 */
#define SAM_STAT_GOOD            0x00
#define SAM_STAT_CHECK_CONDITION 0x02
#define SAM_STAT_CONDITION_MET   0x04
#define SAM_STAT_BUSY            0x08
#define SAM_STAT_INTERMEDIATE    0x10
#define SAM_STAT_INTERMEDIATE_CONDITION_MET 0x14
#define SAM_STAT_RESERVATION_CONFLICT 0x18
#define SAM_STAT_COMMAND_TERMINATED 0x22	/* obsolete in SAM-3 */
#define SAM_STAT_TASK_SET_FULL   0x28
#define SAM_STAT_ACA_ACTIVE      0x30
#define SAM_STAT_TASK_ABORTED    0x40

/** scsi_status_is_good - check the status return.
 *
 * @status: the status passed up from the driver (including host and
 *          driver components)
 *
 * This returns true for known good conditions that may be treated as
 * command completed normally
 */
static inline int scsi_status_is_good(int status)
{
	/*
	 * FIXME: bit0 is listed as reserved in SCSI-2, but is
	 * significant in SCSI-3.  For now, we follow the SCSI-2
	 * behaviour and ignore reserved bits.
	 */
	status &= 0xfe;
	return ((status == SAM_STAT_GOOD) ||
		(status == SAM_STAT_INTERMEDIATE) ||
		(status == SAM_STAT_INTERMEDIATE_CONDITION_MET) ||
		/* FIXME: this is obsolete in SAM-3 */
		(status == SAM_STAT_COMMAND_TERMINATED));
}

/*
 *  Status codes. These are deprecated as they are shifted 1 bit right
 *  from those found in the SCSI standards. This causes confusion for
 *  applications that are ported to several OSes. Prefer SAM Status codes
 *  above.
 */

#define GOOD                 0x00
#define CHECK_CONDITION      0x01
#define CONDITION_GOOD       0x02
#define BUSY                 0x04
#define INTERMEDIATE_GOOD    0x08
#define INTERMEDIATE_C_GOOD  0x0a
#define RESERVATION_CONFLICT 0x0c
#define COMMAND_TERMINATED   0x11
#define QUEUE_FULL           0x14
#define ACA_ACTIVE           0x18
#define TASK_ABORTED         0x20

#define STATUS_MASK          0xfe

/*
 *  SENSE KEYS
 */

#define NO_SENSE            0x00
#define RECOVERED_ERROR     0x01
#define NOT_READY           0x02
#define MEDIUM_ERROR        0x03
#define HARDWARE_ERROR      0x04
#define ILLEGAL_REQUEST     0x05
#define UNIT_ATTENTION      0x06
#define DATA_PROTECT        0x07
#define BLANK_CHECK         0x08
#define COPY_ABORTED        0x0a
#define ABORTED_COMMAND     0x0b
#define VOLUME_OVERFLOW     0x0d
#define MISCOMPARE          0x0e


/*
 *  DEVICE TYPES
 */

#define TYPE_DISK           0x00
#define TYPE_TAPE           0x01
#define TYPE_PRINTER        0x02
#define TYPE_PROCESSOR      0x03    /* HP scanners use this */
#define TYPE_WORM           0x04    /* Treated as ROM by our system */
#define TYPE_ROM            0x05
#define TYPE_SCANNER        0x06
#define TYPE_MOD            0x07    /* Magneto-optical disk - 
				     * - treated as TYPE_DISK */
#define TYPE_MEDIUM_CHANGER 0x08
#define TYPE_COMM           0x09    /* Communications device */
#define TYPE_RAID           0x0c
#define TYPE_ENCLOSURE      0x0d    /* Enclosure Services Device */
#define TYPE_RBC	    0x0e
#define TYPE_NO_LUN         0x7f

/* Returns a human-readable name for the device */
extern const char * scsi_device_type(unsigned type);

/*
 * standard mode-select header prepended to all mode-select commands
 */

struct ccs_modesel_head {
	__u8 _r1;			/* reserved */
	__u8 medium;		/* device-specific medium type */
	__u8 _r2;			/* reserved */
	__u8 block_desc_length;	/* block descriptor length */
	__u8 density;		/* device-specific density code */
	__u8 number_blocks_hi;	/* number of blocks in this block desc */
	__u8 number_blocks_med;
	__u8 number_blocks_lo;
	__u8 _r3;
	__u8 block_length_hi;	/* block length for blocks in this desc */
	__u8 block_length_med;
	__u8 block_length_lo;
};

/*
 * ScsiLun: 8 byte LUN.
 */
struct scsi_lun {
	__u8 scsi_lun[8];
};

/*
 *  MESSAGE CODES
 */

#define COMMAND_COMPLETE    0x00
#define EXTENDED_MESSAGE    0x01
#define     EXTENDED_MODIFY_DATA_POINTER    0x00
#define     EXTENDED_SDTR                   0x01
#define     EXTENDED_EXTENDED_IDENTIFY      0x02    /* SCSI-I only */
#define     EXTENDED_WDTR                   0x03
#define     EXTENDED_PPR                    0x04
#define     EXTENDED_MODIFY_BIDI_DATA_PTR   0x05
#define SAVE_POINTERS       0x02
#define RESTORE_POINTERS    0x03
#define DISCONNECT          0x04
#define INITIATOR_ERROR     0x05
#define ABORT_TASK_SET      0x06
#define MESSAGE_REJECT      0x07
#define NOP                 0x08
#define MSG_PARITY_ERROR    0x09
#define LINKED_CMD_COMPLETE 0x0a
#define LINKED_FLG_CMD_COMPLETE 0x0b
#define TARGET_RESET        0x0c
#define ABORT_TASK          0x0d
#define CLEAR_TASK_SET      0x0e
#define INITIATE_RECOVERY   0x0f            /* SCSI-II only */
#define RELEASE_RECOVERY    0x10            /* SCSI-II only */
#define CLEAR_ACA           0x16
#define LOGICAL_UNIT_RESET  0x17
#define SIMPLE_QUEUE_TAG    0x20
#define HEAD_OF_QUEUE_TAG   0x21
#define ORDERED_QUEUE_TAG   0x22
#define IGNORE_WIDE_RESIDUE 0x23
#define ACA                 0x24
#define QAS_REQUEST         0x55

/* Old SCSI2 names, don't use in new code */
#define BUS_DEVICE_RESET    TARGET_RESET
#define ABORT               ABORT_TASK_SET

/*
 * Host byte codes
 */

#define DID_OK          0x00	/* NO error                                */
#define DID_NO_CONNECT  0x01	/* Couldn't connect before timeout period  */
#define DID_BUS_BUSY    0x02	/* BUS stayed busy through time out period */
#define DID_TIME_OUT    0x03	/* TIMED OUT for other reason              */
#define DID_BAD_TARGET  0x04	/* BAD target.                             */
#define DID_ABORT       0x05	/* Told to abort for some other reason     */
#define DID_PARITY      0x06	/* Parity error                            */
#define DID_ERROR       0x07	/* Internal error                          */
#define DID_RESET       0x08	/* Reset by somebody.                      */
#define DID_BAD_INTR    0x09	/* Got an interrupt we weren't expecting.  */
#define DID_PASSTHROUGH 0x0a	/* Force command past mid-layer            */
#define DID_SOFT_ERROR  0x0b	/* The low level driver just wish a retry  */
#define DID_IMM_RETRY   0x0c	/* Retry without decrementing retry count  */
#define DID_REQUEUE	0x0d	/* Requeue command (no immediate retry) also
				 * without decrementing the retry count	   */
#define DRIVER_OK       0x00	/* Driver status                           */

/*
 *  These indicate the error that occurred, and what is available.
 */

#define DRIVER_BUSY         0x01
#define DRIVER_SOFT         0x02
#define DRIVER_MEDIA        0x03
#define DRIVER_ERROR        0x04

#define DRIVER_INVALID      0x05
#define DRIVER_TIMEOUT      0x06
#define DRIVER_HARD         0x07
#define DRIVER_SENSE	    0x08

#define SUGGEST_RETRY       0x10
#define SUGGEST_ABORT       0x20
#define SUGGEST_REMAP       0x30
#define SUGGEST_DIE         0x40
#define SUGGEST_SENSE       0x80
#define SUGGEST_IS_OK       0xff

#define DRIVER_MASK         0x0f
#define SUGGEST_MASK        0xf0

/*
 * Internal return values.
 */

#define NEEDS_RETRY     0x2001
#define SUCCESS         0x2002
#define FAILED          0x2003
#define QUEUED          0x2004
#define SOFT_ERROR      0x2005
#define ADD_TO_MLQUEUE  0x2006
#define TIMEOUT_ERROR   0x2007

/*
 * Midlevel queue return values.
 */
#define SCSI_MLQUEUE_HOST_BUSY   0x1055
#define SCSI_MLQUEUE_DEVICE_BUSY 0x1056
#define SCSI_MLQUEUE_EH_RETRY    0x1057

/*
 *  Use these to separate status msg and our bytes
 *
 *  These are set by:
 *
 *      status byte = set from target device
 *      msg_byte    = return status from host adapter itself.
 *      host_byte   = set by low-level driver to indicate status.
 *      driver_byte = set by mid-level.
 */
#define status_byte(result) (((result) >> 1) & 0x7f)
#define msg_byte(result)    (((result) >> 8) & 0xff)
#define host_byte(result)   (((result) >> 16) & 0xff)
#define driver_byte(result) (((result) >> 24) & 0xff)
#define suggestion(result)  (driver_byte(result) & SUGGEST_MASK)

#define sense_class(sense)  (((sense) >> 4) & 0x7)
#define sense_error(sense)  ((sense) & 0xf)
#define sense_valid(sense)  ((sense) & 0x80);

/*
 * default timeouts
*/
#define FORMAT_UNIT_TIMEOUT		(2 * 60 * 60 * HZ)
#define START_STOP_TIMEOUT		(60 * HZ)
#define MOVE_MEDIUM_TIMEOUT		(5 * 60 * HZ)
#define READ_ELEMENT_STATUS_TIMEOUT	(5 * 60 * HZ)
#define READ_DEFECT_DATA_TIMEOUT	(60 * HZ )


#define IDENTIFY_BASE       0x80
#define IDENTIFY(can_disconnect, lun)   (IDENTIFY_BASE |\
		     ((can_disconnect) ?  0x40 : 0) |\
		     ((lun) & 0x07))

/*
 *  struct scsi_device::scsi_level values. For SCSI devices other than those
 *  prior to SCSI-2 (i.e. over 12 years old) this value is (resp[2] + 1)
 *  where "resp" is a byte array of the response to an INQUIRY. The scsi_level
 *  variable is visible to the user via sysfs.
 */

#define SCSI_UNKNOWN    0
#define SCSI_1          1
#define SCSI_1_CCS      2
#define SCSI_2          3
#define SCSI_3          4        /* SPC */
#define SCSI_SPC_2      5
#define SCSI_SPC_3      6

/*
 * INQ PERIPHERAL QUALIFIERS
 */
#define SCSI_INQ_PQ_CON         0x00
#define SCSI_INQ_PQ_NOT_CON     0x01
#define SCSI_INQ_PQ_NOT_CAP     0x03


/*
 * Here are some scsi specific ioctl commands which are sometimes useful.
 *
 * Note that include/linux/cdrom.h also defines IOCTL 0x5300 - 0x5395
 */

/* Used to obtain PUN and LUN info.  Conflicts with CDROMAUDIOBUFSIZ */
#define SCSI_IOCTL_GET_IDLUN		0x5382

/* 0x5383 and 0x5384 were used for SCSI_IOCTL_TAGGED_{ENABLE,DISABLE} */

/* Used to obtain the host number of a device. */
#define SCSI_IOCTL_PROBE_HOST		0x5385

/* Used to obtain the bus number for a device */
#define SCSI_IOCTL_GET_BUS_NUMBER	0x5386

/* Used to obtain the PCI location of a device */
#define SCSI_IOCTL_GET_PCI		0x5387

/* Pull a u32 out of a SCSI message (using BE SCSI conventions) */
static inline __u32 scsi_to_u32(__u8 *ptr)
{
	return (ptr[0]<<24) + (ptr[1]<<16) + (ptr[2]<<8) + ptr[3];
}

#endif /* _SCSI_SCSI_H */
44 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531
/*
 *  linux/drivers/s390/crypto/z90hardware.c
 *
 *  z90crypt 1.3.3
 *
 *  Copyright (C)  2001, 2005 IBM Corporation
 *  Author(s): Robert Burroughs (burrough@us.ibm.com)
 *             Eric Rossman (edrossma@us.ibm.com)
 *
 *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.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.
 *
 * 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 <asm/uaccess.h>
#include <linux/compiler.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/module.h>
#include "z90crypt.h"
#include "z90common.h"

struct cca_token_hdr {
	unsigned char  token_identifier;
	unsigned char  version;
	unsigned short token_length;
	unsigned char  reserved[4];
};

#define CCA_TKN_HDR_ID_EXT 0x1E

struct cca_private_ext_ME_sec {
	unsigned char  section_identifier;
	unsigned char  version;
	unsigned short section_length;
	unsigned char  private_key_hash[20];
	unsigned char  reserved1[4];
	unsigned char  key_format;
	unsigned char  reserved2;
	unsigned char  key_name_hash[20];
	unsigned char  key_use_flags[4];
	unsigned char  reserved3[6];
	unsigned char  reserved4[24];
	unsigned char  confounder[24];
	unsigned char  exponent[128];
	unsigned char  modulus[128];
};

#define CCA_PVT_USAGE_ALL 0x80

struct cca_public_sec {
	unsigned char  section_identifier;
	unsigned char  version;
	unsigned short section_length;
	unsigned char  reserved[2];
	unsigned short exponent_len;
	unsigned short modulus_bit_len;
	unsigned short modulus_byte_len;
	unsigned char  exponent[3];
};

struct cca_private_ext_ME {
	struct cca_token_hdr	      pvtMEHdr;
	struct cca_private_ext_ME_sec pvtMESec;
	struct cca_public_sec	      pubMESec;
};

struct cca_public_key {
	struct cca_token_hdr  pubHdr;
	struct cca_public_sec pubSec;
};

struct cca_pvt_ext_CRT_sec {
	unsigned char  section_identifier;
	unsigned char  version;
	unsigned short section_length;
	unsigned char  private_key_hash[20];
	unsigned char  reserved1[4];
	unsigned char  key_format;
	unsigned char  reserved2;
	unsigned char  key_name_hash[20];
	unsigned char  key_use_flags[4];
	unsigned short p_len;
	unsigned short q_len;
	unsigned short dp_len;
	unsigned short dq_len;
	unsigned short u_len;
	unsigned short mod_len;
	unsigned char  reserved3[4];
	unsigned short pad_len;
	unsigned char  reserved4[52];
	unsigned char  confounder[8];
};

#define CCA_PVT_EXT_CRT_SEC_ID_PVT 0x08
#define CCA_PVT_EXT_CRT_SEC_FMT_CL 0x40

struct cca_private_ext_CRT {
	struct cca_token_hdr	   pvtCrtHdr;
	struct cca_pvt_ext_CRT_sec pvtCrtSec;
	struct cca_public_sec	   pubCrtSec;
};

struct ap_status_word {
	unsigned char q_stat_flags;
	unsigned char response_code;
	unsigned char reserved[2];
};

#define AP_Q_STATUS_EMPTY		0x80
#define AP_Q_STATUS_REPLIES_WAITING	0x40
#define AP_Q_STATUS_ARRAY_FULL		0x20

#define AP_RESPONSE_NORMAL		0x00
#define AP_RESPONSE_Q_NOT_AVAIL		0x01
#define AP_RESPONSE_RESET_IN_PROGRESS	0x02
#define AP_RESPONSE_DECONFIGURED	0x03
#define AP_RESPONSE_CHECKSTOPPED	0x04
#define AP_RESPONSE_BUSY		0x05
#define AP_RESPONSE_Q_FULL		0x10
#define AP_RESPONSE_NO_PENDING_REPLY	0x10
#define AP_RESPONSE_INDEX_TOO_BIG	0x11
#define AP_RESPONSE_NO_FIRST_PART	0x13
#define AP_RESPONSE_MESSAGE_TOO_BIG	0x15

#define AP_MAX_CDX_BITL		4
#define AP_RQID_RESERVED_BITL	4
#define SKIP_BITL		(AP_MAX_CDX_BITL + AP_RQID_RESERVED_BITL)

struct type4_hdr {
	unsigned char  reserved1;
	unsigned char  msg_type_code;
	unsigned short msg_len;
	unsigned char  request_code;
	unsigned char  msg_fmt;
	unsigned short reserved2;
};

#define TYPE4_TYPE_CODE 0x04
#define TYPE4_REQU_CODE 0x40

#define TYPE4_SME_LEN 0x0188
#define TYPE4_LME_LEN 0x0308
#define TYPE4_SCR_LEN 0x01E0
#define TYPE4_LCR_LEN 0x03A0

#define TYPE4_SME_FMT 0x00
#define TYPE4_LME_FMT 0x10
#define TYPE4_SCR_FMT 0x40
#define TYPE4_LCR_FMT 0x50

struct type4_sme {
	struct type4_hdr header;
	unsigned char	 message[128];
	unsigned char	 exponent[128];
	unsigned char	 modulus[128];
};

struct type4_lme {
	struct type4_hdr header;
	unsigned char	 message[256];
	unsigned char	 exponent[256];
	unsigned char	 modulus[256];
};

struct type4_scr {
	struct type4_hdr header;
	unsigned char	 message[128];
	unsigned char	 dp[72];
	unsigned char	 dq[64];
	unsigned char	 p[72];
	unsigned char	 q[64];
	unsigned char	 u[72];
};

struct type4_lcr {
	struct type4_hdr header;
	unsigned char	 message[256];
	unsigned char	 dp[136];
	unsigned char	 dq[128];
	unsigned char	 p[136];
	unsigned char	 q[128];
	unsigned char	 u[136];
};

union type4_msg {
	struct type4_sme sme;
	struct type4_lme lme;
	struct type4_scr scr;
	struct type4_lcr lcr;
};

struct type84_hdr {
	unsigned char  reserved1;
	unsigned char  code;
	unsigned short len;
	unsigned char  reserved2[4];
};

#define TYPE84_RSP_CODE 0x84

struct type6_hdr {
	unsigned char reserved1;
	unsigned char type;
	unsigned char reserved2[2];
	unsigned char right[4];
	unsigned char reserved3[2];
	unsigned char reserved4[2];
	unsigned char apfs[4];
	unsigned int  offset1;
	unsigned int  offset2;
	unsigned int  offset3;
	unsigned int  offset4;
	unsigned char agent_id[16];
	unsigned char rqid[2];
	unsigned char reserved5[2];
	unsigned char function_code[2];
	unsigned char reserved6[2];
	unsigned int  ToCardLen1;
	unsigned int  ToCardLen2;
	unsigned int  ToCardLen3;
	unsigned int  ToCardLen4;
	unsigned int  FromCardLen1;
	unsigned int  FromCardLen2;
	unsigned int  FromCardLen3;
	unsigned int  FromCardLen4;
};

struct CPRB {
	unsigned char cprb_len[2];
	unsigned char cprb_ver_id;
	unsigned char pad_000;
	unsigned char srpi_rtcode[4];
	unsigned char srpi_verb;
	unsigned char flags;
	unsigned char func_id[2];
	unsigned char checkpoint_flag;
	unsigned char resv2;
	unsigned char req_parml[2];
	unsigned char req_parmp[4];
	unsigned char req_datal[4];
	unsigned char req_datap[4];
	unsigned char rpl_parml[2];
	unsigned char pad_001[2];
	unsigned char rpl_parmp[4];
	unsigned char rpl_datal[4];
	unsigned char rpl_datap[4];
	unsigned char ccp_rscode[2];
	unsigned char ccp_rtcode[2];
	unsigned char repd_parml[2];
	unsigned char mac_data_len[2];
	unsigned char repd_datal[4];
	unsigned char req_pc[2];
	unsigned char res_origin[8];
	unsigned char mac_value[8];
	unsigned char logon_id[8];
	unsigned char usage_domain[2];
	unsigned char resv3[18];
	unsigned char svr_namel[2];
	unsigned char svr_name[8];
};

struct type6_msg {
	struct type6_hdr header;
	struct CPRB	 CPRB;
};

struct type86_hdr {
	unsigned char reserved1;
	unsigned char type;
	unsigned char format;
	unsigned char reserved2;
	unsigned char reply_code;
	unsigned char reserved3[3];
};

#define TYPE86_RSP_CODE 0x86
#define TYPE86_FMT2	0x02

struct type86_fmt2_msg {
	struct type86_hdr header;
	unsigned char	  reserved[4];
	unsigned char	  apfs[4];
	unsigned int	  count1;
	unsigned int	  offset1;
	unsigned int	  count2;
	unsigned int	  offset2;
	unsigned int	  count3;
	unsigned int	  offset3;
	unsigned int	  count4;
	unsigned int	  offset4;
};

static struct type6_hdr static_type6_hdr = {
	0x00,
	0x06,
	{0x00,0x00},
	{0x00,0x00,0x00,0x00},
	{0x00,0x00},
	{0x00,0x00},
	{0x00,0x00,0x00,0x00},
	0x00000058,
	0x00000000,
	0x00000000,
	0x00000000,
	{0x01,0x00,0x43,0x43,0x41,0x2D,0x41,0x50,
	 0x50,0x4C,0x20,0x20,0x20,0x01,0x01,0x01},
	{0x00,0x00},
	{0x00,0x00},
	{0x50,0x44},
	{0x00,0x00},
	0x00000000,
	0x00000000,
	0x00000000,
	0x00000000,
	0x00000000,
	0x00000000,
	0x00000000,
	0x00000000
};

static struct type6_hdr static_type6_hdrX = {
	0x00,
	0x06,
	{0x00,0x00},
	{0x00,0x00,0x00,0x00},
	{0x00,0x00},
	{0x00,0x00},
	{0x00,0x00,0x00,0x00},
	0x00000058,
	0x00000000,
	0x00000000,
	0x00000000,
	{0x43,0x41,0x00,0x00,0x00,0x00,0x00,0x00,
	 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
	{0x00,0x00},
	{0x00,0x00},
	{0x50,0x44},
	{0x00,0x00},
	0x00000000,
	0x00000000,
	0x00000000,
	0x00000000,
	0x00000000,
	0x00000000,
	0x00000000,
	0x00000000
};

static struct CPRB static_cprb = {
	{0x70,0x00},
	0x41,
	0x00,
	{0x00,0x00,0x00,0x00},
	0x00,
	0x00,
	{0x54,0x32},
	0x01,
	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},
	{0x08,0x00},
	{0x49,0x43,0x53,0x46,0x20,0x20,0x20,0x20}
};

struct function_and_rules_block {
	unsigned char function_code[2];
	unsigned char ulen[2];
	unsigned char only_rule[8];
};

static struct function_and_rules_block static_pkd_function_and_rules = {
	{0x50,0x44},
	{0x0A,0x00},
	{'P','K','C','S','-','1','.','2'}
};

static struct function_and_rules_block static_pke_function_and_rules = {
	{0x50,0x4B},
	{0x0A,0x00},
	{'P','K','C','S','-','1','.','2'}
};

struct T6_keyBlock_hdr {
	unsigned char blen[2];
	unsigned char ulen[2];
	unsigned char flags[2];
};

static struct T6_keyBlock_hdr static_T6_keyBlock_hdr = {
	{0x89,0x01},
	{0x87,0x01},
	{0x00}
};

static struct CPRBX static_cprbx = {
	0x00DC,
	0x02,
	{0x00,0x00,0x00},
	{0x54,0x32},
	{0x00,0x00,0x00,0x00},
	0x00000000,
	0x00000000,
	0x00000000,
	0x00000000,
	0x00000000,
	0x00000000,
	0x00000000,
	{0x00,0x00,0x00,0x00},
	0x00000000,
	{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},
	0x0000,
	0x0000,
	0x00000000,
	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
	0x00,
	0x00,
	0x0000,
	{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}
};

static struct function_and_rules_block static_pkd_function_and_rulesX_MCL2 = {
	{0x50,0x44},
	{0x00,0x0A},
	{'P','K','C','S','-','1','.','2'}
};

static struct function_and_rules_block static_pke_function_and_rulesX_MCL2 = {
	{0x50,0x4B},
	{0x00,0x0A},
	{'Z','E','R','O','-','P','A','D'}
};

static struct function_and_rules_block static_pkd_function_and_rulesX = {
	{0x50,0x44},
	{0x00,0x0A},
	{'Z','E','R','O','-','P','A','D'}
};

static struct function_and_rules_block static_pke_function_and_rulesX = {
	{0x50,0x4B},
	{0x00,0x0A},
	{'M','R','P',' ',' ',' ',' ',' '}
};

static unsigned char static_PKE_function_code[2] = {0x50, 0x4B};

struct T6_keyBlock_hdrX {
	unsigned short blen;
	unsigned short ulen;
	unsigned char flags[2];
};

static unsigned char static_pad[256] = {
0x1B,0x7B,0x5D,0xB5,0x75,0x01,0x3D,0xFD,0x8D,0xD1,0xC7,0x03,0x2D,0x09,0x23,0x57,
0x89,0x49,0xB9,0x3F,0xBB,0x99,0x41,0x5B,0x75,0x21,0x7B,0x9D,0x3B,0x6B,0x51,0x39,
0xBB,0x0D,0x35,0xB9,0x89,0x0F,0x93,0xA5,0x0B,0x47,0xF1,0xD3,0xBB,0xCB,0xF1,0x9D,
0x23,0x73,0x71,0xFF,0xF3,0xF5,0x45,0xFB,0x61,0x29,0x23,0xFD,0xF1,0x29,0x3F,0x7F,
0x17,0xB7,0x1B,0xA9,0x19,0xBD,0x57,0xA9,0xD7,0x95,0xA3,0xCB,0xED,0x1D,0xDB,0x45,
0x7D,0x11,0xD1,0x51,0x1B,0xED,0x71,0xE9,0xB1,0xD1,0xAB,0xAB,0x21,0x2B,0x1B,0x9F,
0x3B,0x9F,0xF7,0xF7,0xBD,0x63,0xEB,0xAD,0xDF,0xB3,0x6F,0x5B,0xDB,0x8D,0xA9,0x5D,
0xE3,0x7D,0x77,0x49,0x47,0xF5,0xA7,0xFD,0xAB,0x2F,0x27,0x35,0x77,0xD3,0x49,0xC9,
0x09,0xEB,0xB1,0xF9,0xBF,0x4B,0xCB,0x2B,0xEB,0xEB,0x05,0xFF,0x7D,0xC7,0x91,0x8B,
0x09,0x83,0xB9,0xB9,0x69,0x33,0x39,0x6B,0x79,0x75,0x19,0xBF,0xBB,0x07,0x1D,0xBD,
0x29,0xBF,0x39,0x95,0x93,0x1D,0x35,0xC7,0xC9,0x4D,0xE5,0x97,0x0B,0x43,0x9B,0xF1,
0x16,0x93,0x03,0x1F,0xA5,0xFB,0xDB,0xF3,0x27,0x4F,0x27,0x61,0x05,0x1F,0xB9,0x23,
0x2F,0xC3,0x81,0xA9,0x23,0x71,0x55,0x55,0xEB,0xED,0x41,0xE5,0xF3,0x11,0xF1,0x43,
0x69,0x03,0xBD,0x0B,0x37,0x0F,0x51,0x8F,0x0B,0xB5,0x89,0x5B,0x67,0xA9,0xD9,0x4F,
0x01,0xF9,0x21,0x77,0x37,0x73,0x79,0xC5,0x7F,0x51,0xC1,0xCF,0x97,0xA1,0x75,0xAD,
0x35,0x9D,0xD3,0xD3,0xA7,0x9D,0x5D,0x41,0x6F,0x65,0x1B,0xCF,0xA9,0x87,0x91,0x09
};

static struct cca_private_ext_ME static_pvt_me_key = {
	{
		0x1E,
		0x00,
		0x0183,
		{0x00,0x00,0x00,0x00}
	},

	{
		0x02,
		0x00,
		0x016C,
		{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},
		{0x80,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,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,0x00,0x00,0x00,
		 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
	},

	{
		0x04,
		0x00,
		0x000F,
		{0x00,0x00},
		0x0003,
		0x0000,
		0x0000,
		{0x01,0x00,0x01}
	}
};

static struct cca_public_key static_public_key = {
	{
		0x1E,
		0x00,
		0x0000,
		{0x00,0x00,0x00,0x00}
	},

	{
		0x04,
		0x00,
		0x0000,
		{0x00,0x00},
		0x0000,
		0x0000,
		0x0000,
		{0x01,0x00,0x01}
	}
};

#define FIXED_TYPE6_ME_LEN 0x0000025F

#define FIXED_TYPE6_ME_EN_LEN 0x000000F0

#define FIXED_TYPE6_ME_LENX 0x000002CB

#define FIXED_TYPE6_ME_EN_LENX 0x0000015C

static struct cca_public_sec static_cca_pub_sec = {
	0x04,
	0x00,
	0x000f,
	{0x00,0x00},
	0x0003,
	0x0000,
	0x0000,
	{0x01,0x00,0x01}
};

#define FIXED_TYPE6_CR_LEN 0x00000177

#define FIXED_TYPE6_CR_LENX 0x000001E3

#define MAX_RESPONSE_SIZE 0x00000710

#define MAX_RESPONSEX_SIZE 0x0000077C

#define RESPONSE_CPRB_SIZE  0x000006B8
#define RESPONSE_CPRBX_SIZE 0x00000724

struct type50_hdr {
	u8    reserved1;
	u8    msg_type_code;
	u16   msg_len;
	u8    reserved2;
	u8    ignored;
	u16   reserved3;
};

#define TYPE50_TYPE_CODE 0x50

#define TYPE50_MEB1_LEN (sizeof(struct type50_meb1_msg))
#define TYPE50_MEB2_LEN (sizeof(struct type50_meb2_msg))
#define TYPE50_CRB1_LEN (sizeof(struct type50_crb1_msg))
#define TYPE50_CRB2_LEN (sizeof(struct type50_crb2_msg))

#define TYPE50_MEB1_FMT 0x0001
#define TYPE50_MEB2_FMT 0x0002
#define TYPE50_CRB1_FMT 0x0011
#define TYPE50_CRB2_FMT 0x0012

struct type50_meb1_msg {
	struct type50_hdr	header;
	u16			keyblock_type;
	u8			reserved[6];
	u8			exponent[128];
	u8			modulus[128];
	u8			message[128];
};

struct type50_meb2_msg {
	struct type50_hdr	header;
	u16			keyblock_type;
	u8			reserved[6];
	u8			exponent[256];
	u8			modulus[256];
	u8			message[256];
};

struct type50_crb1_msg {
	struct type50_hdr	header;
	u16			keyblock_type;
	u8			reserved[6];
	u8			p[64];
	u8			q[64];
	u8			dp[64];
	u8			dq[64];
	u8			u[64];
	u8			message[128];
};

struct type50_crb2_msg {
	struct type50_hdr	header;
	u16			keyblock_type;
	u8			reserved[6];
	u8			p[128];
	u8			q[128];
	u8			dp[128];
	u8			dq[128];
	u8			u[128];
	u8			message[256];
};

union type50_msg {
	struct type50_meb1_msg meb1;
	struct type50_meb2_msg meb2;
	struct type50_crb1_msg crb1;
	struct type50_crb2_msg crb2;
};

struct type80_hdr {
	u8	reserved1;
	u8	type;
	u16	len;
	u8	code;
	u8	reserved2[3];
	u8	reserved3[8];
};

#define TYPE80_RSP_CODE 0x80

struct error_hdr {
	unsigned char reserved1;
	unsigned char type;
	unsigned char reserved2[2];
	unsigned char reply_code;
	unsigned char reserved3[3];
};

#define TYPE82_RSP_CODE 0x82
#define TYPE88_RSP_CODE 0x88

#define REP82_ERROR_MACHINE_FAILURE  0x10
#define REP82_ERROR_PREEMPT_FAILURE  0x12
#define REP82_ERROR_CHECKPT_FAILURE  0x14
#define REP82_ERROR_MESSAGE_TYPE     0x20
#define REP82_ERROR_INVALID_COMM_CD  0x21
#define REP82_ERROR_INVALID_MSG_LEN  0x23
#define REP82_ERROR_RESERVD_FIELD    0x24
#define REP82_ERROR_FORMAT_FIELD     0x29
#define REP82_ERROR_INVALID_COMMAND  0x30
#define REP82_ERROR_MALFORMED_MSG    0x40
#define REP82_ERROR_RESERVED_FIELDO  0x50
#define REP82_ERROR_WORD_ALIGNMENT   0x60
#define REP82_ERROR_MESSAGE_LENGTH   0x80
#define REP82_ERROR_OPERAND_INVALID  0x82
#define REP82_ERROR_OPERAND_SIZE     0x84
#define REP82_ERROR_EVEN_MOD_IN_OPND 0x85
#define REP82_ERROR_RESERVED_FIELD   0x88
#define REP82_ERROR_TRANSPORT_FAIL   0x90
#define REP82_ERROR_PACKET_TRUNCATED 0xA0
#define REP82_ERROR_ZERO_BUFFER_LEN  0xB0

#define REP88_ERROR_MODULE_FAILURE   0x10
#define REP88_ERROR_MODULE_TIMEOUT   0x11
#define REP88_ERROR_MODULE_NOTINIT   0x13
#define REP88_ERROR_MODULE_NOTAVAIL  0x14
#define REP88_ERROR_MODULE_DISABLED  0x15
#define REP88_ERROR_MODULE_IN_DIAGN  0x17
#define REP88_ERROR_FASTPATH_DISABLD 0x19
#define REP88_ERROR_MESSAGE_TYPE     0x20
#define REP88_ERROR_MESSAGE_MALFORMD 0x22
#define REP88_ERROR_MESSAGE_LENGTH   0x23
#define REP88_ERROR_RESERVED_FIELD   0x24
#define REP88_ERROR_KEY_TYPE         0x34
#define REP88_ERROR_INVALID_KEY      0x82
#define REP88_ERROR_OPERAND          0x84
#define REP88_ERROR_OPERAND_EVEN_MOD 0x85

#define CALLER_HEADER 12

static inline int
testq(int q_nr, int *q_depth, int *dev_type, struct ap_status_word *stat)
{
	int ccode;

	asm volatile
#ifdef CONFIG_64BIT
	("	llgfr	0,%4		\n"
	 "	slgr	1,1		\n"
	 "	lgr	2,1		\n"
	 "0:	.long	0xb2af0000	\n"
	 "1:	ipm	%0		\n"
	 "	srl	%0,28		\n"
	 "	iihh	%0,0		\n"
	 "	iihl	%0,0		\n"
	 "	lgr	%1,1		\n"
	 "	lgr	%3,2		\n"
	 "	srl	%3,24		\n"
	 "	sll	2,24		\n"
	 "	srl	2,24		\n"
	 "	lgr	%2,2		\n"
	 "2:				\n"
	 ".section .fixup,\"ax\"	\n"
	 "3:				\n"
	 "	lhi	%0,%h5		\n"
	 "	jg	2b		\n"
	 ".previous			\n"
	 ".section __ex_table,\"a\"	\n"
	 "	.align	8		\n"
	 "	.quad	0b,3b		\n"
	 "	.quad	1b,3b		\n"
	 ".previous"
	 :"=d" (ccode),"=d" (*stat),"=d" (*q_depth), "=d" (*dev_type)
	 :"d" (q_nr), "K" (DEV_TSQ_EXCEPTION)
	 :"cc","0","1","2","memory");
#else
	("	lr	0,%4		\n"
	 "	slr	1,1		\n"
	 "	lr	2,1		\n"
	 "0:	.long	0xb2af0000	\n"
	 "1:	ipm	%0		\n"
	 "	srl	%0,28		\n"
	 "	lr	%1,1		\n"
	 "	lr	%3,2		\n"
	 "	srl	%3,24		\n"
	 "	sll	2,24		\n"
	 "	srl	2,24		\n"
	 "	lr	%2,2		\n"
	 "2:				\n"
	 ".section .fixup,\"ax\"	\n"
	 "3:				\n"
	 "	lhi	%0,%h5		\n"
	 "	bras	1,4f		\n"
	 "	.long	2b		\n"
	 "4:				\n"
	 "	l	1,0(1)		\n"
	 "	br	1		\n"
	 ".previous			\n"
	 ".section __ex_table,\"a\"	\n"
	 "	.align	4		\n"
	 "	.long	0b,3b		\n"
	 "	.long	1b,3b		\n"
	 ".previous"
	 :"=d" (ccode),"=d" (*stat),"=d" (*q_depth), "=d" (*dev_type)
	 :"d" (q_nr), "K" (DEV_TSQ_EXCEPTION)
	 :"cc","0","1","2","memory");
#endif
	return ccode;
}

static inline int
resetq(int q_nr, struct ap_status_word *stat_p)
{
	int ccode;

	asm volatile
#ifdef CONFIG_64BIT
	("	llgfr	0,%2		\n"
	 "	lghi	1,1		\n"
	 "	sll	1,24		\n"
	 "	or	0,1		\n"
	 "	slgr	1,1		\n"
	 "	lgr	2,1		\n"
	 "0:	.long	0xb2af0000	\n"
	 "1:	ipm	%0		\n"
	 "	srl	%0,28		\n"
	 "	iihh	%0,0		\n"
	 "	iihl	%0,0		\n"
	 "	lgr	%1,1		\n"
	 "2:				\n"
	 ".section .fixup,\"ax\"	\n"
	 "3:				\n"
	 "	lhi	%0,%h3		\n"
	 "	jg	2b		\n"
	 ".previous			\n"
	 ".section __ex_table,\"a\"	\n"
	 "	.align	8		\n"
	 "	.quad	0b,3b		\n"
	 "	.quad	1b,3b		\n"
	 ".previous"
	 :"=d" (ccode),"=d" (*stat_p)
	 :"d" (q_nr), "K" (DEV_RSQ_EXCEPTION)
	 :"cc","0","1","2","memory");
#else
	("	lr	0,%2		\n"
	 "	lhi	1,1		\n"
	 "	sll	1,24		\n"
	 "	or	0,1		\n"
	 "	slr	1,1		\n"
	 "	lr	2,1		\n"
	 "0:	.long	0xb2af0000	\n"
	 "1:	ipm	%0		\n"
	 "	srl	%0,28		\n"
	 "	lr	%1,1		\n"
	 "2:				\n"
	 ".section .fixup,\"ax\"	\n"
	 "3:				\n"
	 "	lhi	%0,%h3		\n"
	 "	bras	1,4f		\n"
	 "	.long	2b		\n"
	 "4:				\n"
	 "	l	1,0(1)		\n"
	 "	br	1		\n"
	 ".previous			\n"
	 ".section __ex_table,\"a\"	\n"
	 "	.align	4		\n"
	 "	.long	0b,3b		\n"
	 "	.long	1b,3b		\n"
	 ".previous"
	 :"=d" (ccode),"=d" (*stat_p)
	 :"d" (q_nr), "K" (DEV_RSQ_EXCEPTION)
	 :"cc","0","1","2","memory");
#endif
	return ccode;
}

static inline int
sen(int msg_len, unsigned char *msg_ext, struct ap_status_word *stat)
{
	int ccode;

	asm volatile
#ifdef CONFIG_64BIT
	("	lgr	6,%3		\n"
	 "	llgfr	7,%2		\n"
	 "	llgt	0,0(6)		\n"
	 "	lghi	1,64		\n"
	 "	sll	1,24		\n"
	 "	or	0,1		\n"
	 "	la	6,4(6)		\n"
	 "	llgt	2,0(6)		\n"
	 "	llgt	3,4(6)		\n"
	 "	la	6,8(6)		\n"
	 "	slr	1,1		\n"
	 "0:	.long	0xb2ad0026	\n"
	 "1:	brc	2,0b		\n"
	 "	ipm	%0		\n"
	 "	srl	%0,28		\n"
	 "	iihh	%0,0		\n"
	 "	iihl	%0,0		\n"
	 "	lgr	%1,1		\n"
	 "2:				\n"
	 ".section .fixup,\"ax\"	\n"
	 "3:				\n"
	 "	lhi	%0,%h4		\n"
	 "	jg	2b		\n"
	 ".previous			\n"
	 ".section __ex_table,\"a\"	\n"
	 "	.align	8		\n"
	 "	.quad	0b,3b		\n"
	 "	.quad	1b,3b		\n"
	 ".previous"
	 :"=d" (ccode),"=d" (*stat)
	 :"d" (msg_len),"a" (msg_ext), "K" (DEV_SEN_EXCEPTION)
	 :"cc","0","1","2","3","6","7","memory");
#else
	("	lr	6,%3		\n"
	 "	lr	7,%2		\n"
	 "	l	0,0(6)		\n"
	 "	lhi	1,64		\n"
	 "	sll	1,24		\n"
	 "	or	0,1		\n"
	 "	la	6,4(6)		\n"
	 "	l	2,0(6)		\n"
	 "	l	3,4(6)		\n"
	 "	la	6,8(6)		\n"
	 "	slr	1,1		\n"
	 "0:	.long	0xb2ad0026	\n"
	 "1:	brc	2,0b		\n"
	 "	ipm	%0		\n"
	 "	srl	%0,28		\n"
	 "	lr	%1,1		\n"
	 "2:				\n"
	 ".section .fixup,\"ax\"	\n"
	 "3:				\n"
	 "	lhi	%0,%h4		\n"
	 "	bras	1,4f		\n"
	 "	.long	2b		\n"
	 "4:				\n"
	 "	l	1,0(1)		\n"
	 "	br	1		\n"
	 ".previous			\n"
	 ".section __ex_table,\"a\"	\n"
	 "	.align	4		\n"
	 "	.long	0b,3b		\n"
	 "	.long	1b,3b		\n"
	 ".previous"
	 :"=d" (ccode),"=d" (*stat)
	 :"d" (msg_len),"a" (msg_ext), "K" (DEV_SEN_EXCEPTION)
	 :"cc","0","1","2","3","6","7","memory");
#endif
	return ccode;
}

static inline int
rec(int q_nr, int buff_l, unsigned char *rsp, unsigned char *id,
    struct ap_status_word *st)
{
	int ccode;

	asm volatile
#ifdef CONFIG_64BIT
	("	llgfr	0,%2		\n"
	 "	lgr	3,%4		\n"
	 "	lgr	6,%3		\n"
	 "	llgfr	7,%5		\n"
	 "	lghi	1,128		\n"
	 "	sll	1,24		\n"
	 "	or	0,1		\n"
	 "	slgr	1,1		\n"
	 "	lgr	2,1		\n"
	 "	lgr	4,1		\n"
	 "	lgr	5,1		\n"
	 "0:	.long	0xb2ae0046	\n"
	 "1:	brc	2,0b		\n"
	 "	brc	4,0b		\n"
	 "	ipm	%0		\n"
	 "	srl	%0,28		\n"
	 "	iihh	%0,0		\n"
	 "	iihl	%0,0		\n"
	 "	lgr	%1,1		\n"
	 "	st	4,0(3)		\n"
	 "	st	5,4(3)		\n"
	 "2:				\n"
	 ".section .fixup,\"ax\"	\n"
	 "3:				\n"
	 "	lhi   %0,%h6		\n"
	 "	jg    2b		\n"
	 ".previous			\n"
	 ".section __ex_table,\"a\"	\n"
	 "   .align	8		\n"
	 "   .quad	0b,3b		\n"
	 "   .quad	1b,3b		\n"
	 ".previous"
	 :"=d"(ccode),"=d"(*st)
	 :"d" (q_nr), "d" (rsp), "d" (id), "d" (buff_l), "K" (DEV_REC_EXCEPTION)
	 :"cc","0","1","2","3","4","5","6","7","memory");
#else
	("	lr	0,%2		\n"
	 "	lr	3,%4		\n"
	 "	lr	6,%3		\n"
	 "	lr	7,%5		\n"
	 "	lhi	1,128		\n"
	 "	sll	1,24		\n"
	 "	or	0,1		\n"
	 "	slr	1,1		\n"
	 "	lr	2,1		\n"
	 "	lr	4,1		\n"
	 "	lr	5,1		\n"
	 "0:	.long	0xb2ae0046	\n"
	 "1:	brc	2,0b		\n"
	 "	brc	4,0b		\n"
	 "	ipm	%0		\n"
	 "	srl	%0,28		\n"
	 "	lr	%1,1		\n"
	 "	st	4,0(3)		\n"
	 "	st	5,4(3)		\n"
	 "2:				\n"
	 ".section .fixup,\"ax\"	\n"
	 "3:				\n"
	 "	lhi   %0,%h6		\n"
	 "	bras  1,4f		\n"
	 "	.long 2b		\n"
	 "4:				\n"
	 "	l     1,0(1)		\n"
	 "	br    1			\n"
	 ".previous			\n"
	 ".section __ex_table,\"a\"	\n"
	 "   .align	4		\n"
	 "   .long	0b,3b		\n"
	 "   .long	1b,3b		\n"
	 ".previous"
	 :"=d"(ccode),"=d"(*st)
	 :"d" (q_nr), "d" (rsp), "d" (id), "d" (buff_l), "K" (DEV_REC_EXCEPTION)
	 :"cc","0","1","2","3","4","5","6","7","memory");
#endif
	return ccode;
}

static inline void
itoLe2(int *i_p, unsigned char *lechars)
{
	*lechars       = *((unsigned char *) i_p + sizeof(int) - 1);
	*(lechars + 1) = *((unsigned char *) i_p + sizeof(int) - 2);
}

static inline void
le2toI(unsigned char *lechars, int *i_p)
{
	unsigned char *ic_p;
	*i_p = 0;
	ic_p = (unsigned char *) i_p;
	*(ic_p + 2) = *(lechars + 1);
	*(ic_p + 3) = *(lechars);
}

static inline int
is_empty(unsigned char *ptr, int len)
{
	return !memcmp(ptr, (unsigned char *) &static_pvt_me_key+60, len);
}

enum hdstat
query_online(int deviceNr, int cdx, int resetNr, int *q_depth, int *dev_type)
{
	int q_nr, i, t_depth, t_dev_type;
	enum devstat ccode;
	struct ap_status_word stat_word;
	enum hdstat stat;
	int break_out;

	q_nr = (deviceNr << SKIP_BITL) + cdx;
	stat = HD_BUSY;
	ccode = testq(q_nr, &t_depth, &t_dev_type, &stat_word);
	PDEBUG("ccode %d response_code %02X\n", ccode, stat_word.response_code);
	break_out = 0;
	for (i = 0; i < resetNr; i++) {
		if (ccode > 3) {
			PRINTKC("Exception testing device %d\n", i);
			return HD_TSQ_EXCEPTION;
		}
		switch (ccode) {
		case 0:
			PDEBUG("t_dev_type %d\n", t_dev_type);
			break_out = 1;
			stat = HD_ONLINE;
			*q_depth = t_depth + 1;
			switch (t_dev_type) {
			case PCICA_HW:
				*dev_type = PCICA;
				break;
			case PCICC_HW:
				*dev_type = PCICC;
				break;
			case PCIXCC_HW:
				*dev_type = PCIXCC_UNK;
				break;
			case CEX2C_HW:
				*dev_type = CEX2C;
				break;
			case CEX2A_HW:
				*dev_type = CEX2A;
				break;
			default:
				*dev_type = NILDEV;
				break;
			}
			PDEBUG("available device %d: Q depth = %d, dev "
			       "type = %d, stat = %02X%02X%02X%02X\n",
			       deviceNr, *q_depth, *dev_type,
			       stat_word.q_stat_flags,
			       stat_word.response_code,
			       stat_word.reserved[0],
			       stat_word.reserved[1]);
			break;
		case 3:
			switch (stat_word.response_code) {
			case AP_RESPONSE_NORMAL:
				stat = HD_ONLINE;
				break_out = 1;
				*q_depth = t_depth + 1;
				*dev_type = t_dev_type;
				PDEBUG("cc3, available device "
				       "%d: Q depth = %d, dev "
				       "type = %d, stat = "
				       "%02X%02X%02X%02X\n",
				       deviceNr, *q_depth,
				       *dev_type,
				       stat_word.q_stat_flags,
				       stat_word.response_code,
				       stat_word.reserved[0],
				       stat_word.reserved[1]);
				break;
			case AP_RESPONSE_Q_NOT_AVAIL:
				stat = HD_NOT_THERE;
				break_out = 1;
				break;
			case AP_RESPONSE_RESET_IN_PROGRESS:
				PDEBUG("device %d in reset\n",
				       deviceNr);
				break;
			case AP_RESPONSE_DECONFIGURED:
				stat = HD_DECONFIGURED;
				break_out = 1;
				break;
			case AP_RESPONSE_CHECKSTOPPED:
				stat = HD_CHECKSTOPPED;
				break_out = 1;
				break;
			case AP_RESPONSE_BUSY:
				PDEBUG("device %d busy\n",
				       deviceNr);
				break;
			default:
				break;
			}
			break;
		default:
			stat = HD_NOT_THERE;
			break_out = 1;
			break;
		}
		if (break_out)
			break;

		udelay(5);

		ccode = testq(q_nr, &t_depth, &t_dev_type, &stat_word);
	}
	return stat;
}

enum devstat
reset_device(int deviceNr, int cdx, int resetNr)
{
	int q_nr, ccode = 0, dummy_qdepth, dummy_devType, i;
	struct ap_status_word stat_word;
	enum devstat stat;
	int break_out;

	q_nr = (deviceNr << SKIP_BITL) + cdx;
	stat = DEV_GONE;
	ccode = resetq(q_nr, &stat_word);
	if (ccode > 3)
		return DEV_RSQ_EXCEPTION;

	break_out = 0;
	for (i = 0; i < resetNr; i++) {
		switch (ccode) {
		case 0:
			stat = DEV_ONLINE;
			if (stat_word.q_stat_flags & AP_Q_STATUS_EMPTY)
				break_out = 1;
			break;
		case 3:
			switch (stat_word.response_code) {
			case AP_RESPONSE_NORMAL:
				stat = DEV_ONLINE;
				if (stat_word.q_stat_flags & AP_Q_STATUS_EMPTY)
					break_out = 1;
				break;
			case AP_RESPONSE_Q_NOT_AVAIL:
			case AP_RESPONSE_DECONFIGURED:
			case AP_RESPONSE_CHECKSTOPPED:
				stat = DEV_GONE;
				break_out = 1;
				break;
			case AP_RESPONSE_RESET_IN_PROGRESS:
			case AP_RESPONSE_BUSY:
			default:
				break;
			}
			break;
		default:
			stat = DEV_GONE;
			break_out = 1;
			break;
		}
		if (break_out == 1)
			break;
		udelay(5);

		ccode = testq(q_nr, &dummy_qdepth, &dummy_devType, &stat_word);
		if (ccode > 3) {
			stat = DEV_TSQ_EXCEPTION;
			break;
		}
	}
	PDEBUG("Number of testq's needed for reset: %d\n", i);

	if (i >= resetNr) {
	  stat = DEV_GONE;
	}

	return stat;
}

#ifdef DEBUG_HYDRA_MSGS
static inline void
print_buffer(unsigned char *buffer, int bufflen)
{
	int i;
	for (i = 0; i < bufflen; i += 16) {
		PRINTK("%04X: %02X%02X%02X%02X %02X%02X%02X%02X "
		       "%02X%02X%02X%02X %02X%02X%02X%02X\n", i,
		       buffer[i+0], buffer[i+1], buffer[i+2], buffer[i+3],
		       buffer[i+4], buffer[i+5], buffer[i+6], buffer[i+7],
		       buffer[i+8], buffer[i+9], buffer[i+10], buffer[i+11],
		       buffer[i+12], buffer[i+13], buffer[i+14], buffer[i+15]);
	}
}
#endif

enum devstat
send_to_AP(int dev_nr, int cdx, int msg_len, unsigned char *msg_ext)
{
	struct ap_status_word stat_word;
	enum devstat stat;
	int ccode;
	u32 *q_nr_p = (u32 *)msg_ext;

	*q_nr_p = (dev_nr << SKIP_BITL) + cdx;
	PDEBUG("msg_len passed to sen: %d\n", msg_len);
	PDEBUG("q number passed to sen: %02x%02x%02x%02x\n",
	       msg_ext[0], msg_ext[1], msg_ext[2], msg_ext[3]);
	stat = DEV_GONE;

#ifdef DEBUG_HYDRA_MSGS
	PRINTK("Request header: %02X%02X%02X%02X %02X%02X%02X%02X "
	       "%02X%02X%02X%02X\n",
	       msg_ext[0], msg_ext[1], msg_ext[2], msg_ext[3],
	       msg_ext[4], msg_ext[5], msg_ext[6], msg_ext[7],
	       msg_ext[8], msg_ext[9], msg_ext[10], msg_ext[11]);
	print_buffer(msg_ext+CALLER_HEADER, msg_len);
#endif

	ccode = sen(msg_len, msg_ext, &stat_word);
	if (ccode > 3)
		return DEV_SEN_EXCEPTION;

	PDEBUG("nq cc: %u, st: %02x%02x%02x%02x\n",
	       ccode, stat_word.q_stat_flags, stat_word.response_code,
	       stat_word.reserved[0], stat_word.reserved[1]);
	switch (ccode) {
	case 0:
		stat = DEV_ONLINE;
		break;
	case 1:
		stat = DEV_GONE;
		break;
	case 3:
		switch (stat_word.response_code) {
		case AP_RESPONSE_NORMAL:
			stat = DEV_ONLINE;
			break;
		case AP_RESPONSE_Q_FULL:
			stat = DEV_QUEUE_FULL;
			break;
		default:
			stat = DEV_GONE;
			break;
		}
		break;
	default:
		stat = DEV_GONE;
		break;
	}

	return stat;
}

enum devstat
receive_from_AP(int dev_nr, int cdx, int resplen, unsigned char *resp,
		unsigned char *psmid)
{
	int ccode;
	struct ap_status_word stat_word;
	enum devstat stat;

	memset(resp, 0x00, 8);

	ccode = rec((dev_nr << SKIP_BITL) + cdx, resplen, resp, psmid,
		    &stat_word);
	if (ccode > 3)
		return DEV_REC_EXCEPTION;

	PDEBUG("dq cc: %u, st: %02x%02x%02x%02x\n",
	       ccode, stat_word.q_stat_flags, stat_word.response_code,
	       stat_word.reserved[0], stat_word.reserved[1]);

	stat = DEV_GONE;
	switch (ccode) {
	case 0:
		stat = DEV_ONLINE;
#ifdef DEBUG_HYDRA_MSGS
		print_buffer(resp, resplen);
#endif
		break;
	case 3:
		switch (stat_word.response_code) {
		case AP_RESPONSE_NORMAL:
			stat = DEV_ONLINE;
			break;
		case AP_RESPONSE_NO_PENDING_REPLY:
			if (stat_word.q_stat_flags & AP_Q_STATUS_EMPTY)
				stat = DEV_EMPTY;
			else
				stat = DEV_NO_WORK;
			break;
		case AP_RESPONSE_INDEX_TOO_BIG:
		case AP_RESPONSE_NO_FIRST_PART:
		case AP_RESPONSE_MESSAGE_TOO_BIG:
			stat = DEV_BAD_MESSAGE;
			break;
		default:
			break;
		}
		break;
	default:
		break;
	}

	return stat;
}

static inline int
pad_msg(unsigned char *buffer, int  totalLength, int msgLength)
{
	int pad_len;

	for (pad_len = 0; pad_len < (totalLength - msgLength); pad_len++)
		if (buffer[pad_len] != 0x00)
			break;
	pad_len -= 3;
	if (pad_len < 8)
		return SEN_PAD_ERROR;

	buffer[0] = 0x00;
	buffer[1] = 0x02;

	memcpy(buffer+2, static_pad, pad_len);

	buffer[pad_len + 2] = 0x00;

	return 0;
}

static inline int
is_common_public_key(unsigned char *key, int len)
{
	int i;

	for (i = 0; i < len; i++)
		if (key[i])
			break;
	key += i;
	len -= i;
	if (((len == 1) && (key[0] == 3)) ||
	    ((len == 3) && (key[0] == 1) && (key[1] == 0) && (key[2] == 1)))
		return 1;

	return 0;
}

static int
ICAMEX_msg_to_type4MEX_msg(struct ica_rsa_modexpo *icaMex_p, int *z90cMsg_l_p,
			   union type4_msg *z90cMsg_p)
{
	int mod_len, msg_size, mod_tgt_len, exp_tgt_len, inp_tgt_len;
	unsigned char *mod_tgt, *exp_tgt, *inp_tgt;
	union type4_msg *tmp_type4_msg;

	mod_len = icaMex_p->inputdatalength;

	msg_size = ((mod_len <= 128) ? TYPE4_SME_LEN : TYPE4_LME_LEN) +
		    CALLER_HEADER;

	memset(z90cMsg_p, 0, msg_size);

	tmp_type4_msg = (union type4_msg *)
		((unsigned char *) z90cMsg_p + CALLER_HEADER);

	tmp_type4_msg->sme.header.msg_type_code = TYPE4_TYPE_CODE;
	tmp_type4_msg->sme.header.request_code = TYPE4_REQU_CODE;

	if (mod_len <= 128) {
		tmp_type4_msg->sme.header.msg_fmt = TYPE4_SME_FMT;
		tmp_type4_msg->sme.header.msg_len = TYPE4_SME_LEN;
		mod_tgt = tmp_type4_msg->sme.modulus;
		mod_tgt_len = sizeof(tmp_type4_msg->sme.modulus);
		exp_tgt = tmp_type4_msg->sme.exponent;
		exp_tgt_len = sizeof(tmp_type4_msg->sme.exponent);
		inp_tgt = tmp_type4_msg->sme.message;
		inp_tgt_len = sizeof(tmp_type4_msg->sme.message);
	} else {
		tmp_type4_msg->lme.header.msg_fmt = TYPE4_LME_FMT;
		tmp_type4_msg->lme.header.msg_len = TYPE4_LME_LEN;
		mod_tgt = tmp_type4_msg->lme.modulus;
		mod_tgt_len = sizeof(tmp_type4_msg->lme.modulus);
		exp_tgt = tmp_type4_msg->lme.exponent;
		exp_tgt_len = sizeof(tmp_type4_msg->lme.exponent);
		inp_tgt = tmp_type4_msg->lme.message;
		inp_tgt_len = sizeof(tmp_type4_msg->lme.message);
	}

	mod_tgt += (mod_tgt_len - mod_len);
	if (copy_from_user(mod_tgt, icaMex_p->n_modulus, mod_len))
		return SEN_RELEASED;
	if (is_empty(mod_tgt, mod_len))
		return SEN_USER_ERROR;
	exp_tgt += (exp_tgt_len - mod_len);
	if (copy_from_user(exp_tgt, icaMex_p->b_key, mod_len))
		return SEN_RELEASED;
	if (is_empty(exp_tgt, mod_len))
		return SEN_USER_ERROR;
	inp_tgt += (inp_tgt_len - mod_len);
	if (copy_from_user(inp_tgt, icaMex_p->inputdata, mod_len))
		return SEN_RELEASED;
	if (is_empty(inp_tgt, mod_len))
		return SEN_USER_ERROR;

	*z90cMsg_l_p = msg_size - CALLER_HEADER;

	return 0;
}

static int
ICACRT_msg_to_type4CRT_msg(struct ica_rsa_modexpo_crt *icaMsg_p,
			   int *z90cMsg_l_p, union type4_msg *z90cMsg_p)
{
	int mod_len, short_len, long_len, tmp_size, p_tgt_len, q_tgt_len,
	    dp_tgt_len, dq_tgt_len, u_tgt_len, inp_tgt_len;
	unsigned char *p_tgt, *q_tgt, *dp_tgt, *dq_tgt, *u_tgt, *inp_tgt;
	union type4_msg *tmp_type4_msg;

	mod_len = icaMsg_p->inputdatalength;
	short_len = mod_len / 2;
	long_len = mod_len / 2 + 8;

	tmp_size = ((mod_len <= 128) ? TYPE4_SCR_LEN : TYPE4_LCR_LEN) +
		    CALLER_HEADER;

	memset(z90cMsg_p, 0, tmp_size);

	tmp_type4_msg = (union type4_msg *)
		((unsigned char *) z90cMsg_p + CALLER_HEADER);

	tmp_type4_msg->scr.header.msg_type_code = TYPE4_TYPE_CODE;
	tmp_type4_msg->scr.header.request_code = TYPE4_REQU_CODE;
	if (mod_len <= 128) {
		tmp_type4_msg->scr.header.msg_fmt = TYPE4_SCR_FMT;
		tmp_type4_msg->scr.header.msg_len = TYPE4_SCR_LEN;
		p_tgt = tmp_type4_msg->scr.p;
		p_tgt_len = sizeof(tmp_type4_msg->scr.p);
		q_tgt = tmp_type4_msg->scr.q;
		q_tgt_len = sizeof(tmp_type4_msg->scr.q);
		dp_tgt = tmp_type4_msg->scr.dp;
		dp_tgt_len = sizeof(tmp_type4_msg->scr.dp);
		dq_tgt = tmp_type4_msg->scr.dq;
		dq_tgt_len = sizeof(tmp_type4_msg->scr.dq);
		u_tgt = tmp_type4_msg->scr.u;
		u_tgt_len = sizeof(tmp_type4_msg->scr.u);
		inp_tgt = tmp_type4_msg->scr.message;
		inp_tgt_len = sizeof(tmp_type4_msg->scr.message);
	} else {
		tmp_type4_msg->lcr.header.msg_fmt = TYPE4_LCR_FMT;
		tmp_type4_msg->lcr.header.msg_len = TYPE4_LCR_LEN;
		p_tgt = tmp_type4_msg->lcr.p;
		p_tgt_len = sizeof(tmp_type4_msg->lcr.p);
		q_tgt = tmp_type4_msg->lcr.q;
		q_tgt_len = sizeof(tmp_type4_msg->lcr.q);
		dp_tgt = tmp_type4_msg->lcr.dp;
		dp_tgt_len = sizeof(tmp_type4_msg->lcr.dp);
		dq_tgt = tmp_type4_msg->lcr.dq;
		dq_tgt_len = sizeof(tmp_type4_msg->lcr.dq);
		u_tgt = tmp_type4_msg->lcr.u;
		u_tgt_len = sizeof(tmp_type4_msg->lcr.u);
		inp_tgt = tmp_type4_msg->lcr.message;
		inp_tgt_len = sizeof(tmp_type4_msg->lcr.message);
	}

	p_tgt += (p_tgt_len - long_len);
	if (copy_from_user(p_tgt, icaMsg_p->np_prime, long_len))
		return SEN_RELEASED;
	if (is_empty(p_tgt, long_len))
		return SEN_USER_ERROR;
	q_tgt += (q_tgt_len - short_len);
	if (copy_from_user(q_tgt, icaMsg_p->nq_prime, short_len))
		return SEN_RELEASED;
	if (is_empty(q_tgt, short_len))
		return SEN_USER_ERROR;
	dp_tgt += (dp_tgt_len - long_len);
	if (copy_from_user(dp_tgt, icaMsg_p->bp_key, long_len))
		return SEN_RELEASED;
	if (is_empty(dp_tgt, long_len))
		return SEN_USER_ERROR;
	dq_tgt += (dq_tgt_len - short_len);
	if (copy_from_user(dq_tgt, icaMsg_p->bq_key, short_len))
		return SEN_RELEASED;
	if (is_empty(dq_tgt, short_len))
		return SEN_USER_ERROR;
	u_tgt += (u_tgt_len - long_len);
	if (copy_from_user(u_tgt, icaMsg_p->u_mult_inv, long_len))
		return SEN_RELEASED;
	if (is_empty(u_tgt, long_len))
		return SEN_USER_ERROR;
	inp_tgt += (inp_tgt_len - mod_len);
	if (copy_from_user(inp_tgt, icaMsg_p->inputdata, mod_len))
		return SEN_RELEASED;
	if (is_empty(inp_tgt, mod_len))
		return SEN_USER_ERROR;

	*z90cMsg_l_p = tmp_size - CALLER_HEADER;

	return 0;
}

static int
ICAMEX_msg_to_type6MEX_de_msg(struct ica_rsa_modexpo *icaMsg_p, int cdx,
			      int *z90cMsg_l_p, struct type6_msg *z90cMsg_p)
{
	int mod_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l;
	unsigned char *temp;
	struct type6_hdr *tp6Hdr_p;
	struct CPRB *cprb_p;
	struct cca_private_ext_ME *key_p;
	static int deprecated_msg_count = 0;

	mod_len = icaMsg_p->inputdatalength;
	tmp_size = FIXED_TYPE6_ME_LEN + mod_len;
	total_CPRB_len = tmp_size - sizeof(struct type6_hdr);
	parmBlock_l = total_CPRB_len - sizeof(struct CPRB);
	tmp_size = 4*((tmp_size + 3)/4) + CALLER_HEADER;

	memset(z90cMsg_p, 0, tmp_size);

	temp = (unsigned char *)z90cMsg_p + CALLER_HEADER;
	memcpy(temp, &static_type6_hdr, sizeof(struct type6_hdr));
	tp6Hdr_p = (struct type6_hdr *)temp;
	tp6Hdr_p->ToCardLen1 = 4*((total_CPRB_len+3)/4);
	tp6Hdr_p->FromCardLen1 = RESPONSE_CPRB_SIZE;

	temp += sizeof(struct type6_hdr);
	memcpy(temp, &static_cprb, sizeof(struct CPRB));
	cprb_p = (struct CPRB *) temp;
	cprb_p->usage_domain[0]= (unsigned char)cdx;
	itoLe2(&parmBlock_l, cprb_p->req_parml);
	itoLe2((int *)&(tp6Hdr_p->FromCardLen1), cprb_p->rpl_parml);

	temp += sizeof(struct CPRB);
	memcpy(temp, &static_pkd_function_and_rules,
	       sizeof(struct function_and_rules_block));

	temp += sizeof(struct function_and_rules_block);
	vud_len = 2 + icaMsg_p->inputdatalength;
	itoLe2(&vud_len, temp);

	temp += 2;
	if (copy_from_user(temp, icaMsg_p->inputdata, mod_len))
		return SEN_RELEASED;
	if (is_empty(temp, mod_len))
		return SEN_USER_ERROR;

	temp += mod_len;
	memcpy(temp, &static_T6_keyBlock_hdr, sizeof(struct T6_keyBlock_hdr));

	temp += sizeof(struct T6_keyBlock_hdr);
	memcpy(temp, &static_pvt_me_key, sizeof(struct cca_private_ext_ME));
	key_p = (struct cca_private_ext_ME *)temp;
	temp = key_p->pvtMESec.exponent + sizeof(key_p->pvtMESec.exponent)
	       - mod_len;
	if (copy_from_user(temp, icaMsg_p->b_key, mod_len))
		return SEN_RELEASED;
	if (is_empty(temp, mod_len))
		return SEN_USER_ERROR;

	if (is_common_public_key(temp, mod_len)) {
		if (deprecated_msg_count < 20) {
			PRINTK("Common public key used for modex decrypt\n");
			deprecated_msg_count++;
			if (deprecated_msg_count == 20)
				PRINTK("No longer issuing messages about common"
				       " public key for modex decrypt.\n");
		}
		return SEN_NOT_AVAIL;
	}

	temp = key_p->pvtMESec.modulus + sizeof(key_p->pvtMESec.modulus)
	       - mod_len;
	if (copy_from_user(temp, icaMsg_p->n_modulus, mod_len))
		return SEN_RELEASED;
	if (is_empty(temp, mod_len))
		return SEN_USER_ERROR;

	key_p->pubMESec.modulus_bit_len = 8 * mod_len;

	*z90cMsg_l_p = tmp_size - CALLER_HEADER;

	return 0;
}

static int
ICAMEX_msg_to_type6MEX_en_msg(struct ica_rsa_modexpo *icaMsg_p, int cdx,
			      int *z90cMsg_l_p, struct type6_msg *z90cMsg_p)
{
	int mod_len, vud_len, exp_len, key_len;
	int pad_len, tmp_size, total_CPRB_len, parmBlock_l, i;
	unsigned char *temp_exp, *exp_p, *temp;
	struct type6_hdr *tp6Hdr_p;
	struct CPRB *cprb_p;
	struct cca_public_key *key_p;
	struct T6_keyBlock_hdr *keyb_p;

	temp_exp = kmalloc(256, GFP_KERNEL);
	if (!temp_exp)
		return EGETBUFF;
	mod_len = icaMsg_p->inputdatalength;
	if (copy_from_user(temp_exp, icaMsg_p->b_key, mod_len)) {
		kfree(temp_exp);
		return SEN_RELEASED;
	}
	if (is_empty(temp_exp, mod_len)) {
		kfree(temp_exp);
		return SEN_USER_ERROR;
	}

	exp_p = temp_exp;
	for (i = 0; i < mod_len; i++)
		if (exp_p[i])
			break;
	if (i >= mod_len) {
		kfree(temp_exp);
		return SEN_USER_ERROR;
	}

	exp_len = mod_len - i;
	exp_p += i;

	PDEBUG("exp_len after computation: %08x\n", exp_len);
	tmp_size = FIXED_TYPE6_ME_EN_LEN + 2 * mod_len + exp_len;
	total_CPRB_len = tmp_size - sizeof(struct type6_hdr);
	parmBlock_l = total_CPRB_len - sizeof(struct CPRB);
	tmp_size = 4*((tmp_size + 3)/4) + CALLER_HEADER;

	vud_len = 2 + mod_len;
	memset(z90cMsg_p, 0, tmp_size);

	temp = (unsigned char *)z90cMsg_p + CALLER_HEADER;
	memcpy(temp, &static_type6_hdr, sizeof(struct type6_hdr));
	tp6Hdr_p = (struct type6_hdr *)temp;
	tp6Hdr_p->ToCardLen1 = 4*((total_CPRB_len+3)/4);
	tp6Hdr_p->FromCardLen1 = RESPONSE_CPRB_SIZE;
	memcpy(tp6Hdr_p->function_code, static_PKE_function_code,
	       sizeof(static_PKE_function_code));
	temp += sizeof(struct type6_hdr);
	memcpy(temp, &static_cprb, sizeof(struct CPRB));
	cprb_p = (struct CPRB *) temp;
	cprb_p->usage_domain[0]= (unsigned char)cdx;
	itoLe2((int *)&(tp6Hdr_p->FromCardLen1), cprb_p->rpl_parml);
	temp += sizeof(struct CPRB);
	memcpy(temp, &static_pke_function_and_rules,
		 sizeof(struct function_and_rules_block));
	temp += sizeof(struct function_and_rules_block);
	temp += 2;
	if (copy_from_user(temp, icaMsg_p->inputdata, mod_len)) {
		kfree(temp_exp);
		return SEN_RELEASED;
	}
	if (is_empty(temp, mod_len)) {
		kfree(temp_exp);
		return SEN_USER_ERROR;
	}
	if ((temp[0] != 0x00) || (temp[1] != 0x02)) {
		kfree(temp_exp);
		return SEN_NOT_AVAIL;
	}
	for (i = 2; i < mod_len; i++)
		if (temp[i] == 0x00)
			break;
	if ((i < 9) || (i > (mod_len - 2))) {
		kfree(temp_exp);
		return SEN_NOT_AVAIL;
	}
	pad_len = i + 1;
	vud_len = mod_len - pad_len;
	memmove(temp, temp+pad_len, vud_len);
	temp -= 2;
	vud_len += 2;
	itoLe2(&vud_len, temp);
	temp += (vud_len);
	keyb_p = (struct T6_keyBlock_hdr *)temp;
	temp += sizeof(struct T6_keyBlock_hdr);
	memcpy(temp, &static_public_key, sizeof(static_public_key));
	key_p = (struct cca_public_key *)temp;
	temp = key_p->pubSec.exponent;
	memcpy(temp, exp_p, exp_len);
	kfree(temp_exp);
	temp += exp_len;
	if (copy_from_user(temp, icaMsg_p->n_modulus, mod_len))
		return SEN_RELEASED;
	if (is_empty(temp, mod_len))
		return SEN_USER_ERROR;
	key_p->pubSec.modulus_bit_len = 8 * mod_len;
	key_p->pubSec.modulus_byte_len = mod_len;
	key_p->pubSec.exponent_len = exp_len;
	key_p->pubSec.section_length = CALLER_HEADER + mod_len + exp_len;
	key_len = key_p->pubSec.section_length + sizeof(struct cca_token_hdr);
	key_p->pubHdr.token_length = key_len;
	key_len += 4;
	itoLe2(&key_len, keyb_p->ulen);
	key_len += 2;
	itoLe2(&key_len, keyb_p->blen);
	parmBlock_l -= pad_len;
	itoLe2(&parmBlock_l, cprb_p->req_parml);
	*z90cMsg_l_p = tmp_size - CALLER_HEADER;

	return 0;
}

static int
ICACRT_msg_to_type6CRT_msg(struct ica_rsa_modexpo_crt *icaMsg_p, int cdx,
			   int *z90cMsg_l_p, struct type6_msg *z90cMsg_p)
{
	int mod_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l, short_len;
	int long_len, pad_len, keyPartsLen, tmp_l;
	unsigned char *tgt_p, *temp;
	struct type6_hdr *tp6Hdr_p;
	struct CPRB *cprb_p;
	struct cca_token_hdr *keyHdr_p;
	struct cca_pvt_ext_CRT_sec *pvtSec_p;
	struct cca_public_sec *pubSec_p;

	mod_len = icaMsg_p->inputdatalength;
	short_len = mod_len / 2;
	long_len = 8 + short_len;
	keyPartsLen = 3 * long_len + 2 * short_len;
	pad_len = (8 - (keyPartsLen % 8)) % 8;
	keyPartsLen += pad_len + mod_len;
	tmp_size = FIXED_TYPE6_CR_LEN + keyPartsLen + mod_len;
	total_CPRB_len = tmp_size -  sizeof(struct type6_hdr);
	parmBlock_l = total_CPRB_len - sizeof(struct CPRB);
	vud_len = 2 + mod_len;
	tmp_size = 4*((tmp_size + 3)/4) + CALLER_HEADER;

	memset(z90cMsg_p, 0, tmp_size);
	tgt_p = (unsigned char *)z90cMsg_p + CALLER_HEADER;
	memcpy(tgt_p, &static_type6_hdr, sizeof(struct type6_hdr));
	tp6Hdr_p = (struct type6_hdr *)tgt_p;
	tp6Hdr_p->ToCardLen1 = 4*((total_CPRB_len+3)/4);
	tp6Hdr_p->FromCardLen1 = RESPONSE_CPRB_SIZE;
	tgt_p += sizeof(struct type6_hdr);
	cprb_p = (struct CPRB *) tgt_p;
	memcpy(tgt_p, &static_cprb, sizeof(struct CPRB));
	cprb_p->usage_domain[0]= *((unsigned char *)(&(cdx))+3);
	itoLe2(&parmBlock_l, cprb_p->req_parml);
	memcpy(cprb_p->rpl_parml, cprb_p->req_parml,
	       sizeof(cprb_p->req_parml));
	tgt_p += sizeof(struct CPRB);
	memcpy(tgt_p, &static_pkd_function_and_rules,
	       sizeof(struct function_and_rules_block));
	tgt_p += sizeof(struct function_and_rules_block);
	itoLe2(&vud_len, tgt_p);
	tgt_p += 2;
	if (copy_from_user(tgt_p, icaMsg_p->inputdata, mod_len))
		return SEN_RELEASED;
	if (is_empty(tgt_p, mod_len))
		return SEN_USER_ERROR;
	tgt_p += mod_len;
	tmp_l = sizeof(struct T6_keyBlock_hdr) + sizeof(struct cca_token_hdr) +
		sizeof(struct cca_pvt_ext_CRT_sec) + 0x0F + keyPartsLen;
	itoLe2(&tmp_l, tgt_p);
	temp = tgt_p + 2;
	tmp_l -= 2;
	itoLe2(&tmp_l, temp);
	tgt_p += sizeof(struct T6_keyBlock_hdr);
	keyHdr_p = (struct cca_token_hdr *)tgt_p;
	keyHdr_p->token_identifier = CCA_TKN_HDR_ID_EXT;
	tmp_l -= 4;
	keyHdr_p->token_length = tmp_l;
	tgt_p += sizeof(struct cca_token_hdr);
	pvtSec_p = (struct cca_pvt_ext_CRT_sec *)tgt_p;
	pvtSec_p->section_identifier = CCA_PVT_EXT_CRT_SEC_ID_PVT;
	pvtSec_p->section_length =
		sizeof(struct cca_pvt_ext_CRT_sec) + keyPartsLen;
	pvtSec_p->key_format = CCA_PVT_EXT_CRT_SEC_FMT_CL;
	pvtSec_p->key_use_flags[0] = CCA_PVT_USAGE_ALL;
	pvtSec_p->p_len = long_len;
	pvtSec_p->q_len = short_len;
	pvtSec_p->dp_len = long_len;
	pvtSec_p->dq_len = short_len;
	pvtSec_p->u_len = long_len;
	pvtSec_p->mod_len = mod_len;
	pvtSec_p->pad_len = pad_len;
	tgt_p += sizeof(struct cca_pvt_ext_CRT_sec);
	if (copy_from_user(tgt_p, icaMsg_p->np_prime, long_len))
		return SEN_RELEASED;
	if (is_empty(tgt_p, long_len))
		return SEN_USER_ERROR;
	tgt_p += long_len;
	if (copy_from_user(tgt_p, icaMsg_p->nq_prime, short_len))
		return SEN_RELEASED;
	if (is_empty(tgt_p, short_len))
		return SEN_USER_ERROR;
	tgt_p += short_len;
	if (copy_from_user(tgt_p, icaMsg_p->bp_key, long_len))
		return SEN_RELEASED;
	if (is_empty(tgt_p, long_len))
		return SEN_USER_ERROR;
	tgt_p += long_len;
	if (copy_from_user(tgt_p, icaMsg_p->bq_key, short_len))
		return SEN_RELEASED;
	if (is_empty(tgt_p, short_len))
		return SEN_USER_ERROR;
	tgt_p += short_len;
	if (copy_from_user(tgt_p, icaMsg_p->u_mult_inv, long_len))
		return SEN_RELEASED;
	if (is_empty(tgt_p, long_len))
		return SEN_USER_ERROR;
	tgt_p += long_len;
	tgt_p += pad_len;
	memset(tgt_p, 0xFF, mod_len);
	tgt_p += mod_len;
	memcpy(tgt_p, &static_cca_pub_sec, sizeof(struct cca_public_sec));
	pubSec_p = (struct cca_public_sec *) tgt_p;
	pubSec_p->modulus_bit_len = 8 * mod_len;
	*z90cMsg_l_p = tmp_size - CALLER_HEADER;

	return 0;
}

static int
ICAMEX_msg_to_type6MEX_msgX(struct ica_rsa_modexpo *icaMsg_p, int cdx,
			    int *z90cMsg_l_p, struct type6_msg *z90cMsg_p,
			    int dev_type)
{
	int mod_len, exp_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l;
	int key_len, i;
	unsigned char *temp_exp, *tgt_p, *temp, *exp_p;
	struct type6_hdr *tp6Hdr_p;
	struct CPRBX *cprbx_p;
	struct cca_public_key *key_p;
	struct T6_keyBlock_hdrX *keyb_p;

	temp_exp = kmalloc(256, GFP_KERNEL);
	if (!temp_exp)
		return EGETBUFF;
	mod_len = icaMsg_p->inputdatalength;
	if (copy_from_user(temp_exp, icaMsg_p->b_key, mod_len)) {
		kfree(temp_exp);
		return SEN_RELEASED;
	}
	if (is_empty(temp_exp, mod_len)) {
		kfree(temp_exp);
		return SEN_USER_ERROR;
	}
	exp_p = temp_exp;
	for (i = 0; i < mod_len; i++)
		if (exp_p[i])
			break;
	if (i >= mod_len) {
		kfree(temp_exp);
		return SEN_USER_ERROR;
	}
	exp_len = mod_len - i;
	exp_p += i;
	PDEBUG("exp_len after computation: %08x\n", exp_len);
	tmp_size = FIXED_TYPE6_ME_EN_LENX + 2 * mod_len + exp_len;
	total_CPRB_len = tmp_size - sizeof(struct type6_hdr);
	parmBlock_l = total_CPRB_len - sizeof(struct CPRBX);
	tmp_size = tmp_size + CALLER_HEADER;
	vud_len = 2 + mod_len;
	memset(z90cMsg_p, 0, tmp_size);
	tgt_p = (unsigned char *)z90cMsg_p + CALLER_HEADER;
	memcpy(tgt_p, &static_type6_hdrX, sizeof(struct type6_hdr));
	tp6Hdr_p = (struct type6_hdr *)tgt_p;
	tp6Hdr_p->ToCardLen1 = total_CPRB_len;
	tp6Hdr_p->FromCardLen1 = RESPONSE_CPRBX_SIZE;
	memcpy(tp6Hdr_p->function_code, static_PKE_function_code,
	       sizeof(static_PKE_function_code));
	tgt_p += sizeof(struct type6_hdr);
	memcpy(tgt_p, &static_cprbx, sizeof(struct CPRBX));
	cprbx_p = (struct CPRBX *) tgt_p;
	cprbx_p->domain = (unsigned short)cdx;
	cprbx_p->rpl_msgbl = RESPONSE_CPRBX_SIZE;
	tgt_p += sizeof(struct CPRBX);
	if (dev_type == PCIXCC_MCL2)
		memcpy(tgt_p, &static_pke_function_and_rulesX_MCL2,
		       sizeof(struct function_and_rules_block));
	else
		memcpy(tgt_p, &static_pke_function_and_rulesX,
		       sizeof(struct function_and_rules_block));
	tgt_p += sizeof(struct function_and_rules_block);

	tgt_p += 2;
	if (copy_from_user(tgt_p, icaMsg_p->inputdata, mod_len)) {
		kfree(temp_exp);
		return SEN_RELEASED;
	}
	if (is_empty(tgt_p, mod_len)) {
		kfree(temp_exp);
		return SEN_USER_ERROR;
	}
	tgt_p -= 2;
	*((short *)tgt_p) = (short) vud_len;
	tgt_p += vud_len;
	keyb_p = (struct T6_keyBlock_hdrX *)tgt_p;
	tgt_p += sizeof(struct T6_keyBlock_hdrX);
	memcpy(tgt_p, &static_public_key, sizeof(static_public_key));
	key_p = (struct cca_public_key *)tgt_p;
	temp = key_p->pubSec.exponent;
	memcpy(temp, exp_p, exp_len);
	kfree(temp_exp);
	temp += exp_len;
	if (copy_from_user(temp, icaMsg_p->n_modulus, mod_len))
		return SEN_RELEASED;
	if (is_empty(temp, mod_len))
		return SEN_USER_ERROR;
	key_p->pubSec.modulus_bit_len = 8 * mod_len;
	key_p->pubSec.modulus_byte_len = mod_len;
	key_p->pubSec.exponent_len = exp_len;
	key_p->pubSec.section_length = CALLER_HEADER + mod_len + exp_len;
	key_len = key_p->pubSec.section_length + sizeof(struct cca_token_hdr);
	key_p->pubHdr.token_length = key_len;
	key_len += 4;
	keyb_p->ulen = (unsigned short)key_len;
	key_len += 2;
	keyb_p->blen = (unsigned short)key_len;
	cprbx_p->req_parml = parmBlock_l;
	*z90cMsg_l_p = tmp_size - CALLER_HEADER;

	return 0;
}

static int
ICACRT_msg_to_type6CRT_msgX(struct ica_rsa_modexpo_crt *icaMsg_p, int cdx,
			    int *z90cMsg_l_p, struct type6_msg *z90cMsg_p,
			    int dev_type)
{
	int mod_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l, short_len;
	int long_len, pad_len, keyPartsLen, tmp_l;
	unsigned char *tgt_p, *temp;
	struct type6_hdr *tp6Hdr_p;
	struct CPRBX *cprbx_p;
	struct cca_token_hdr *keyHdr_p;
	struct cca_pvt_ext_CRT_sec *pvtSec_p;
	struct cca_public_sec *pubSec_p;

	mod_len = icaMsg_p->inputdatalength;
	short_len = mod_len / 2;
	long_len = 8 + short_len;
	keyPartsLen = 3 * long_len + 2 * short_len;
	pad_len = (8 - (keyPartsLen % 8)) % 8;
	keyPartsLen += pad_len + mod_len;
	tmp_size = FIXED_TYPE6_CR_LENX + keyPartsLen + mod_len;
	total_CPRB_len = tmp_size -  sizeof(struct type6_hdr);
	parmBlock_l = total_CPRB_len - sizeof(struct CPRBX);
	vud_len = 2 + mod_len;
	tmp_size = tmp_size + CALLER_HEADER;
	memset(z90cMsg_p, 0, tmp_size);
	tgt_p = (unsigned char *)z90cMsg_p + CALLER_HEADER;
	memcpy(tgt_p, &static_type6_hdrX, sizeof(struct type6_hdr));
	tp6Hdr_p = (struct type6_hdr *)tgt_p;
	tp6Hdr_p->ToCardLen1 = total_CPRB_len;
	tp6Hdr_p->FromCardLen1 = RESPONSE_CPRBX_SIZE;
	tgt_p += sizeof(struct type6_hdr);
	cprbx_p = (struct CPRBX *) tgt_p;
	memcpy(tgt_p, &static_cprbx, sizeof(struct CPRBX));
	cprbx_p->domain = (unsigned short)cdx;
	cprbx_p->req_parml = parmBlock_l;
	cprbx_p->rpl_msgbl = parmBlock_l;
	tgt_p += sizeof(struct CPRBX);
	if (dev_type == PCIXCC_MCL2)
		memcpy(tgt_p, &static_pkd_function_and_rulesX_MCL2,
		       sizeof(struct function_and_rules_block));
	else
		memcpy(tgt_p, &static_pkd_function_and_rulesX,
		       sizeof(struct function_and_rules_block));
	tgt_p += sizeof(struct function_and_rules_block);
	*((short *)tgt_p) = (short) vud_len;
	tgt_p += 2;
	if (copy_from_user(tgt_p, icaMsg_p->inputdata, mod_len))
		return SEN_RELEASED;
	if (is_empty(tgt_p, mod_len))
		return SEN_USER_ERROR;
	tgt_p += mod_len;
	tmp_l = sizeof(struct T6_keyBlock_hdr) + sizeof(struct cca_token_hdr) +
		sizeof(struct cca_pvt_ext_CRT_sec) + 0x0F + keyPartsLen;
	*((short *)tgt_p) = (short) tmp_l;
	temp = tgt_p + 2;
	tmp_l -= 2;
	*((short *)temp) = (short) tmp_l;
	tgt_p += sizeof(struct T6_keyBlock_hdr);
	keyHdr_p = (struct cca_token_hdr *)tgt_p;
	keyHdr_p->token_identifier = CCA_TKN_HDR_ID_EXT;
	tmp_l -= 4;
	keyHdr_p->token_length = tmp_l;
	tgt_p += sizeof(struct cca_token_hdr);
	pvtSec_p = (struct cca_pvt_ext_CRT_sec *)tgt_p;
	pvtSec_p->section_identifier = CCA_PVT_EXT_CRT_SEC_ID_PVT;
	pvtSec_p->section_length =
		sizeof(struct cca_pvt_ext_CRT_sec) + keyPartsLen;
	pvtSec_p->key_format = CCA_PVT_EXT_CRT_SEC_FMT_CL;
	pvtSec_p->key_use_flags[0] = CCA_PVT_USAGE_ALL;
	pvtSec_p->p_len = long_len;
	pvtSec_p->q_len = short_len;
	pvtSec_p->dp_len = long_len;
	pvtSec_p->dq_len = short_len;
	pvtSec_p->u_len = long_len;
	pvtSec_p->mod_len = mod_len;
	pvtSec_p->pad_len = pad_len;
	tgt_p += sizeof(struct cca_pvt_ext_CRT_sec);
	if (copy_from_user(tgt_p, icaMsg_p->np_prime, long_len))
		return SEN_RELEASED;
	if (is_empty(tgt_p, long_len))
		return SEN_USER_ERROR;
	tgt_p += long_len;
	if (copy_from_user(tgt_p, icaMsg_p->nq_prime, short_len))
		return SEN_RELEASED;
	if (is_empty(tgt_p, short_len))
		return SEN_USER_ERROR;
	tgt_p += short_len;
	if (copy_from_user(tgt_p, icaMsg_p->bp_key, long_len))
		return SEN_RELEASED;
	if (is_empty(tgt_p, long_len))
		return SEN_USER_ERROR;
	tgt_p += long_len;
	if (copy_from_user(tgt_p, icaMsg_p->bq_key, short_len))
		return SEN_RELEASED;
	if (is_empty(tgt_p, short_len))
		return SEN_USER_ERROR;
	tgt_p += short_len;
	if (copy_from_user(tgt_p, icaMsg_p->u_mult_inv, long_len))
		return SEN_RELEASED;
	if (is_empty(tgt_p, long_len))
		return SEN_USER_ERROR;
	tgt_p += long_len;
	tgt_p += pad_len;
	memset(tgt_p, 0xFF, mod_len);
	tgt_p += mod_len;