1 /* 2 * arch/s390/kernel/cpcmd.c 3 * 4 * S390 version 5 * Copyright (C) 1999,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation 6 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), 7 * Christian Borntraeger (cborntra@de.ibm.com), 8 */ 9 10 #include <linux/kernel.h> 11 #include <linux/module.h> 12 #include <linux/slab.h> 13 #include <linux/spinlock.h> 14 #include <linux/stddef.h> 15 #include <linux/string.h> 16 #include <asm/ebcdic.h> 17 #include <asm/cpcmd.h> 18 #include <asm/system.h> 19 20 static DEFINE_SPINLOCK(cpcmd_lock); 21 static char cpcmd_buf[241]; 22 23 /* 24 * the caller of __cpcmd has to ensure that the response buffer is below 2 GB 25 */ 26 int __cpcmd(const char *cmd, char *response, int rlen, int *response_code) 27 { 28 const int mask = 0x40000000L; 29 unsigned long flags; 30 int return_code; 31 int return_len; 32 int cmdlen; 33 34 spin_lock_irqsave(&cpcmd_lock, flags); 35 cmdlen = strlen(cmd); 36 BUG_ON(cmdlen > 240); 37 memcpy(cpcmd_buf, cmd, cmdlen); 38 ASCEBC(cpcmd_buf, cmdlen); 39 40 if (response != NULL && rlen > 0) { 41 memset(response, 0, rlen); 42 #ifndef CONFIG_64BIT 43 asm volatile ( "lra 2,0(%2)\n" 44 "lr 4,%3\n" 45 "o 4,%6\n" 46 "lra 3,0(%4)\n" 47 "lr 5,%5\n" 48 "diag 2,4,0x8\n" 49 "brc 8, 1f\n" 50 "ar 5, %5\n" 51 "1: \n" 52 "lr %0,4\n" 53 "lr %1,5\n" 54 : "=d" (return_code), "=d" (return_len) 55 : "a" (cpcmd_buf), "d" (cmdlen), 56 "a" (response), "d" (rlen), "m" (mask) 57 : "cc", "2", "3", "4", "5" ); 58 #else /* CONFIG_64BIT */ 59 asm volatile ( "lrag 2,0(%2)\n" 60 "lgr 4,%3\n" 61 "o 4,%6\n" 62 "lrag 3,0(%4)\n" 63 "lgr 5,%5\n" 64 "sam31\n" 65 "diag 2,4,0x8\n" 66 "sam64\n" 67 "brc 8, 1f\n" 68 "agr 5, %5\n" 69 "1: \n" 70 "lgr %0,4\n" 71 "lgr %1,5\n" 72 : "=d" (return_code), "=d" (return_len) 73 : "a" (cpcmd_buf), "d" (cmdlen), 74 "a" (response), "d" (rlen), "m" (mask) 75 : "cc", "2", "3", "4", "5" ); 76 #endif /* CONFIG_64BIT */ 77 EBCASC(response, rlen); 78 } else { 79 return_len = 0; 80 #ifndef CONFIG_64BIT 81 asm volatile ( "lra 2,0(%1)\n" 82 "lr 3,%2\n" 83 "diag 2,3,0x8\n" 84 "lr %0,3\n" 85 : "=d" (return_code) 86 : "a" (cpcmd_buf), "d" (cmdlen) 87 : "2", "3" ); 88 #else /* CONFIG_64BIT */ 89 asm volatile ( "lrag 2,0(%1)\n" 90 "lgr 3,%2\n" 91 "sam31\n" 92 "diag 2,3,0x8\n" 93 "sam64\n" 94 "lgr %0,3\n" 95 : "=d" (return_code) 96 : "a" (cpcmd_buf), "d" (cmdlen) 97 : "2", "3" ); 98 #endif /* CONFIG_64BIT */ 99 } 100 spin_unlock_irqrestore(&cpcmd_lock, flags); 101 if (response_code != NULL) 102 *response_code = return_code; 103 return return_len; 104 } 105 106 EXPORT_SYMBOL(__cpcmd); 107 108 #ifdef CONFIG_64BIT 109 int cpcmd(const char *cmd, char *response, int rlen, int *response_code) 110 { 111 char *lowbuf; 112 int len; 113 114 if ((rlen == 0) || (response == NULL) 115 || !((unsigned long)response >> 31)) 116 len = __cpcmd(cmd, response, rlen, response_code); 117 else { 118 lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA); 119 if (!lowbuf) { 120 printk(KERN_WARNING 121 "cpcmd: could not allocate response buffer\n"); 122 return -ENOMEM; 123 } 124 len = __cpcmd(cmd, lowbuf, rlen, response_code); 125 memcpy(response, lowbuf, rlen); 126 kfree(lowbuf); 127 } 128 return len; 129 } 130 131 EXPORT_SYMBOL(cpcmd); 132 #endif /* CONFIG_64BIT */ 133