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 struct sdias_sccb *cbsccb; 73 74 cbsccb = (struct sdias_sccb *) request->sccb; 75 sclp_req_done = 1; 76 wake_up(&sdias_wq); /* Inform caller, that request is complete */ 77 TRACE("callback done\n"); 78 } 79 80 static int sdias_sclp_send(struct sclp_req *req) 81 { 82 int retries; 83 int rc; 84 85 for (retries = SDIAS_RETRIES; retries; retries--) { 86 sclp_req_done = 0; 87 TRACE("add request\n"); 88 rc = sclp_add_request(req); 89 if (rc) { 90 /* not initiated, wait some time and retry */ 91 set_current_state(TASK_INTERRUPTIBLE); 92 TRACE("add request failed: rc = %i\n",rc); 93 schedule_timeout(SDIAS_SLEEP_TICKS); 94 continue; 95 } 96 /* initiated, wait for completion of service call */ 97 wait_event(sdias_wq, (sclp_req_done == 1)); 98 if (req->status == SCLP_REQ_FAILED) { 99 TRACE("sclp request failed\n"); 100 rc = -EIO; 101 continue; 102 } 103 TRACE("request done\n"); 104 break; 105 } 106 return rc; 107 } 108 109 /* 110 * Get number of blocks (4K) available in the HSA 111 */ 112 int sclp_sdias_blk_count(void) 113 { 114 struct sclp_req request; 115 int rc; 116 117 mutex_lock(&sdias_mutex); 118 119 memset(&sccb, 0, sizeof(sccb)); 120 memset(&request, 0, sizeof(request)); 121 122 sccb.hdr.length = sizeof(sccb); 123 sccb.evbuf.hdr.length = sizeof(struct sdias_evbuf); 124 sccb.evbuf.hdr.type = EVTYP_SDIAS; 125 sccb.evbuf.event_qual = EQ_SIZE; 126 sccb.evbuf.data_id = DI_FCP_DUMP; 127 sccb.evbuf.event_id = 4712; 128 sccb.evbuf.dbs = 1; 129 130 request.sccb = &sccb; 131 request.command = SCLP_CMDW_WRITE_EVENT_DATA; 132 request.status = SCLP_REQ_FILLED; 133 request.callback = sdias_callback; 134 135 rc = sdias_sclp_send(&request); 136 if (rc) { 137 pr_err("sclp_send failed for get_nr_blocks\n"); 138 goto out; 139 } 140 if (sccb.hdr.response_code != 0x0020) { 141 TRACE("send failed: %x\n", sccb.hdr.response_code); 142 rc = -EIO; 143 goto out; 144 } 145 146 switch (sccb.evbuf.event_status) { 147 case 0: 148 rc = sccb.evbuf.blk_cnt; 149 break; 150 default: 151 pr_err("SCLP error: %x\n", 152 sccb.evbuf.event_status); 153 rc = -EIO; 154 goto out; 155 } 156 TRACE("%i blocks\n", rc); 157 out: 158 mutex_unlock(&sdias_mutex); 159 return rc; 160 } 161 162 /* 163 * Copy from HSA to absolute storage (not reentrant): 164 * 165 * @dest : Address of buffer where data should be copied 166 * @start_blk: Start Block (beginning with 1) 167 * @nr_blks : Number of 4K blocks to copy 168 * 169 * Return Value: 0 : Requested 'number' of blocks of data copied 170 * <0: ERROR - negative event status 171 */ 172 int sclp_sdias_copy(void *dest, int start_blk, int nr_blks) 173 { 174 struct sclp_req request; 175 int rc; 176 177 mutex_lock(&sdias_mutex); 178 179 memset(&sccb, 0, sizeof(sccb)); 180 memset(&request, 0, sizeof(request)); 181 182 sccb.hdr.length = sizeof(sccb); 183 sccb.evbuf.hdr.length = sizeof(struct sdias_evbuf); 184 sccb.evbuf.hdr.type = EVTYP_SDIAS; 185 sccb.evbuf.hdr.flags = 0; 186 sccb.evbuf.event_qual = EQ_STORE_DATA; 187 sccb.evbuf.data_id = DI_FCP_DUMP; 188 sccb.evbuf.event_id = 4712; 189 #ifdef __s390x__ 190 sccb.evbuf.asa_size = ASA_SIZE_64; 191 #else 192 sccb.evbuf.asa_size = ASA_SIZE_32; 193 #endif 194 sccb.evbuf.event_status = 0; 195 sccb.evbuf.blk_cnt = nr_blks; 196 sccb.evbuf.asa = (unsigned long)dest; 197 sccb.evbuf.fbn = start_blk; 198 sccb.evbuf.lbn = 0; 199 sccb.evbuf.dbs = 1; 200 201 request.sccb = &sccb; 202 request.command = SCLP_CMDW_WRITE_EVENT_DATA; 203 request.status = SCLP_REQ_FILLED; 204 request.callback = sdias_callback; 205 206 rc = sdias_sclp_send(&request); 207 if (rc) { 208 pr_err("sclp_send failed: %x\n", rc); 209 goto out; 210 } 211 if (sccb.hdr.response_code != 0x0020) { 212 TRACE("copy failed: %x\n", sccb.hdr.response_code); 213 rc = -EIO; 214 goto out; 215 } 216 217 switch (sccb.evbuf.event_status) { 218 case EVSTATE_ALL_STORED: 219 TRACE("all stored\n"); 220 case EVSTATE_PART_STORED: 221 TRACE("part stored: %i\n", sccb.evbuf.blk_cnt); 222 break; 223 case EVSTATE_NO_DATA: 224 TRACE("no data\n"); 225 default: 226 pr_err("Error from SCLP while copying hsa. " 227 "Event status = %x\n", 228 sccb.evbuf.event_status); 229 rc = -EIO; 230 } 231 out: 232 mutex_unlock(&sdias_mutex); 233 return rc; 234 } 235 236 int __init sclp_sdias_init(void) 237 { 238 int rc; 239 240 if (ipl_info.type != IPL_TYPE_FCP_DUMP) 241 return 0; 242 sdias_dbf = debug_register("dump_sdias", 4, 1, 4 * sizeof(long)); 243 debug_register_view(sdias_dbf, &debug_sprintf_view); 244 debug_set_level(sdias_dbf, 6); 245 rc = sclp_register(&sclp_sdias_register); 246 if (rc) 247 return rc; 248 init_waitqueue_head(&sdias_wq); 249 TRACE("init done\n"); 250 return 0; 251 } 252 253 void __exit sclp_sdias_exit(void) 254 { 255 debug_unregister(sdias_dbf); 256 sclp_unregister(&sclp_sdias_register); 257 } 258