1 /* 2 * Sclp "store data in absolut storage" 3 * 4 * Copyright IBM Corp. 2003,2007 5 * Author(s): Michael Holzheu 6 */ 7 8 #define KMSG_COMPONENT "sclp_sdias" 9 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 10 11 #include <linux/sched.h> 12 #include <asm/sclp.h> 13 #include <asm/debug.h> 14 #include <asm/ipl.h> 15 16 #include "sclp.h" 17 #include "sclp_rw.h" 18 19 #define TRACE(x...) debug_sprintf_event(sdias_dbf, 1, x) 20 21 #define SDIAS_RETRIES 300 22 #define SDIAS_SLEEP_TICKS 50 23 24 #define EQ_STORE_DATA 0x0 25 #define EQ_SIZE 0x1 26 #define DI_FCP_DUMP 0x0 27 #define ASA_SIZE_32 0x0 28 #define ASA_SIZE_64 0x1 29 #define EVSTATE_ALL_STORED 0x0 30 #define EVSTATE_NO_DATA 0x3 31 #define EVSTATE_PART_STORED 0x10 32 33 static struct debug_info *sdias_dbf; 34 35 static struct sclp_register sclp_sdias_register = { 36 .send_mask = EVTYP_SDIAS_MASK, 37 }; 38 39 struct sdias_evbuf { 40 struct evbuf_header hdr; 41 u8 event_qual; 42 u8 data_id; 43 u64 reserved2; 44 u32 event_id; 45 u16 reserved3; 46 u8 asa_size; 47 u8 event_status; 48 u32 reserved4; 49 u32 blk_cnt; 50 u64 asa; 51 u32 reserved5; 52 u32 fbn; 53 u32 reserved6; 54 u32 lbn; 55 u16 reserved7; 56 u16 dbs; 57 } __attribute__((packed)); 58 59 struct sdias_sccb { 60 struct sccb_header hdr; 61 struct sdias_evbuf evbuf; 62 } __attribute__((packed)); 63 64 static struct sdias_sccb sccb __attribute__((aligned(4096))); 65 66 static int sclp_req_done; 67 static wait_queue_head_t sdias_wq; 68 static DEFINE_MUTEX(sdias_mutex); 69 70 static void sdias_callback(struct sclp_req *request, void *data) 71 { 72 sclp_req_done = 1; 73 wake_up(&sdias_wq); /* Inform caller, that request is complete */ 74 TRACE("callback done\n"); 75 } 76 77 static int sdias_sclp_send(struct sclp_req *req) 78 { 79 int retries; 80 int rc; 81 82 for (retries = SDIAS_RETRIES; retries; retries--) { 83 sclp_req_done = 0; 84 TRACE("add request\n"); 85 rc = sclp_add_request(req); 86 if (rc) { 87 /* not initiated, wait some time and retry */ 88 set_current_state(TASK_INTERRUPTIBLE); 89 TRACE("add request failed: rc = %i\n",rc); 90 schedule_timeout(SDIAS_SLEEP_TICKS); 91 continue; 92 } 93 /* initiated, wait for completion of service call */ 94 wait_event(sdias_wq, (sclp_req_done == 1)); 95 if (req->status == SCLP_REQ_FAILED) { 96 TRACE("sclp request failed\n"); 97 rc = -EIO; 98 continue; 99 } 100 TRACE("request done\n"); 101 break; 102 } 103 return rc; 104 } 105 106 /* 107 * Get number of blocks (4K) available in the HSA 108 */ 109 int sclp_sdias_blk_count(void) 110 { 111 struct sclp_req request; 112 int rc; 113 114 mutex_lock(&sdias_mutex); 115 116 memset(&sccb, 0, sizeof(sccb)); 117 memset(&request, 0, sizeof(request)); 118 119 sccb.hdr.length = sizeof(sccb); 120 sccb.evbuf.hdr.length = sizeof(struct sdias_evbuf); 121 sccb.evbuf.hdr.type = EVTYP_SDIAS; 122 sccb.evbuf.event_qual = EQ_SIZE; 123 sccb.evbuf.data_id = DI_FCP_DUMP; 124 sccb.evbuf.event_id = 4712; 125 sccb.evbuf.dbs = 1; 126 127 request.sccb = &sccb; 128 request.command = SCLP_CMDW_WRITE_EVENT_DATA; 129 request.status = SCLP_REQ_FILLED; 130 request.callback = sdias_callback; 131 132 rc = sdias_sclp_send(&request); 133 if (rc) { 134 pr_err("sclp_send failed for get_nr_blocks\n"); 135 goto out; 136 } 137 if (sccb.hdr.response_code != 0x0020) { 138 TRACE("send failed: %x\n", sccb.hdr.response_code); 139 rc = -EIO; 140 goto out; 141 } 142 143 switch (sccb.evbuf.event_status) { 144 case 0: 145 rc = sccb.evbuf.blk_cnt; 146 break; 147 default: 148 pr_err("SCLP error: %x\n", 149 sccb.evbuf.event_status); 150 rc = -EIO; 151 goto out; 152 } 153 TRACE("%i blocks\n", rc); 154 out: 155 mutex_unlock(&sdias_mutex); 156 return rc; 157 } 158 159 /* 160 * Copy from HSA to absolute storage (not reentrant): 161 * 162 * @dest : Address of buffer where data should be copied 163 * @start_blk: Start Block (beginning with 1) 164 * @nr_blks : Number of 4K blocks to copy 165 * 166 * Return Value: 0 : Requested 'number' of blocks of data copied 167 * <0: ERROR - negative event status 168 */ 169 int sclp_sdias_copy(void *dest, int start_blk, int nr_blks) 170 { 171 struct sclp_req request; 172 int rc; 173 174 mutex_lock(&sdias_mutex); 175 176 memset(&sccb, 0, sizeof(sccb)); 177 memset(&request, 0, sizeof(request)); 178 179 sccb.hdr.length = sizeof(sccb); 180 sccb.evbuf.hdr.length = sizeof(struct sdias_evbuf); 181 sccb.evbuf.hdr.type = EVTYP_SDIAS; 182 sccb.evbuf.hdr.flags = 0; 183 sccb.evbuf.event_qual = EQ_STORE_DATA; 184 sccb.evbuf.data_id = DI_FCP_DUMP; 185 sccb.evbuf.event_id = 4712; 186 #ifdef __s390x__ 187 sccb.evbuf.asa_size = ASA_SIZE_64; 188 #else 189 sccb.evbuf.asa_size = ASA_SIZE_32; 190 #endif 191 sccb.evbuf.event_status = 0; 192 sccb.evbuf.blk_cnt = nr_blks; 193 sccb.evbuf.asa = (unsigned long)dest; 194 sccb.evbuf.fbn = start_blk; 195 sccb.evbuf.lbn = 0; 196 sccb.evbuf.dbs = 1; 197 198 request.sccb = &sccb; 199 request.command = SCLP_CMDW_WRITE_EVENT_DATA; 200 request.status = SCLP_REQ_FILLED; 201 request.callback = sdias_callback; 202 203 rc = sdias_sclp_send(&request); 204 if (rc) { 205 pr_err("sclp_send failed: %x\n", rc); 206 goto out; 207 } 208 if (sccb.hdr.response_code != 0x0020) { 209 TRACE("copy failed: %x\n", sccb.hdr.response_code); 210 rc = -EIO; 211 goto out; 212 } 213 214 switch (sccb.evbuf.event_status) { 215 case EVSTATE_ALL_STORED: 216 TRACE("all stored\n"); 217 case EVSTATE_PART_STORED: 218 TRACE("part stored: %i\n", sccb.evbuf.blk_cnt); 219 break; 220 case EVSTATE_NO_DATA: 221 TRACE("no data\n"); 222 default: 223 pr_err("Error from SCLP while copying hsa. " 224 "Event status = %x\n", 225 sccb.evbuf.event_status); 226 rc = -EIO; 227 } 228 out: 229 mutex_unlock(&sdias_mutex); 230 return rc; 231 } 232 233 int __init sclp_sdias_init(void) 234 { 235 int rc; 236 237 if (ipl_info.type != IPL_TYPE_FCP_DUMP) 238 return 0; 239 sdias_dbf = debug_register("dump_sdias", 4, 1, 4 * sizeof(long)); 240 debug_register_view(sdias_dbf, &debug_sprintf_view); 241 debug_set_level(sdias_dbf, 6); 242 rc = sclp_register(&sclp_sdias_register); 243 if (rc) 244 return rc; 245 init_waitqueue_head(&sdias_wq); 246 TRACE("init done\n"); 247 return 0; 248 } 249 250 void __exit sclp_sdias_exit(void) 251 { 252 debug_unregister(sdias_dbf); 253 sclp_unregister(&sclp_sdias_register); 254 } 255