1 /* 2 * Sclp "store data in absolut storage" 3 * 4 * Copyright IBM Corp. 2003,2007 5 * Author(s): Michael Holzheu 6 */ 7 8 #include <linux/sched.h> 9 #include <asm/sclp.h> 10 #include <asm/debug.h> 11 #include <asm/ipl.h> 12 #include "sclp.h" 13 #include "sclp_rw.h" 14 15 #define TRACE(x...) debug_sprintf_event(sdias_dbf, 1, x) 16 #define ERROR_MSG(x...) printk ( KERN_ALERT "SDIAS: " x ) 17 18 #define SDIAS_RETRIES 300 19 #define SDIAS_SLEEP_TICKS 50 20 21 #define EQ_STORE_DATA 0x0 22 #define EQ_SIZE 0x1 23 #define DI_FCP_DUMP 0x0 24 #define ASA_SIZE_32 0x0 25 #define ASA_SIZE_64 0x1 26 #define EVSTATE_ALL_STORED 0x0 27 #define EVSTATE_NO_DATA 0x3 28 #define EVSTATE_PART_STORED 0x10 29 30 static struct debug_info *sdias_dbf; 31 32 static struct sclp_register sclp_sdias_register = { 33 .send_mask = EVTYP_SDIAS_MASK, 34 }; 35 36 struct sdias_evbuf { 37 struct evbuf_header hdr; 38 u8 event_qual; 39 u8 data_id; 40 u64 reserved2; 41 u32 event_id; 42 u16 reserved3; 43 u8 asa_size; 44 u8 event_status; 45 u32 reserved4; 46 u32 blk_cnt; 47 u64 asa; 48 u32 reserved5; 49 u32 fbn; 50 u32 reserved6; 51 u32 lbn; 52 u16 reserved7; 53 u16 dbs; 54 } __attribute__((packed)); 55 56 struct sdias_sccb { 57 struct sccb_header hdr; 58 struct sdias_evbuf evbuf; 59 } __attribute__((packed)); 60 61 static struct sdias_sccb sccb __attribute__((aligned(4096))); 62 63 static int sclp_req_done; 64 static wait_queue_head_t sdias_wq; 65 static DEFINE_MUTEX(sdias_mutex); 66 67 static void sdias_callback(struct sclp_req *request, void *data) 68 { 69 struct sdias_sccb *cbsccb; 70 71 cbsccb = (struct sdias_sccb *) request->sccb; 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 ERROR_MSG("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 ERROR_MSG("SCLP error: %x\n", sccb.evbuf.event_status); 149 rc = -EIO; 150 goto out; 151 } 152 TRACE("%i blocks\n", rc); 153 out: 154 mutex_unlock(&sdias_mutex); 155 return rc; 156 } 157 158 /* 159 * Copy from HSA to absolute storage (not reentrant): 160 * 161 * @dest : Address of buffer where data should be copied 162 * @start_blk: Start Block (beginning with 1) 163 * @nr_blks : Number of 4K blocks to copy 164 * 165 * Return Value: 0 : Requested 'number' of blocks of data copied 166 * <0: ERROR - negative event status 167 */ 168 int sclp_sdias_copy(void *dest, int start_blk, int nr_blks) 169 { 170 struct sclp_req request; 171 int rc; 172 173 mutex_lock(&sdias_mutex); 174 175 memset(&sccb, 0, sizeof(sccb)); 176 memset(&request, 0, sizeof(request)); 177 178 sccb.hdr.length = sizeof(sccb); 179 sccb.evbuf.hdr.length = sizeof(struct sdias_evbuf); 180 sccb.evbuf.hdr.type = EVTYP_SDIAS; 181 sccb.evbuf.hdr.flags = 0; 182 sccb.evbuf.event_qual = EQ_STORE_DATA; 183 sccb.evbuf.data_id = DI_FCP_DUMP; 184 sccb.evbuf.event_id = 4712; 185 #ifdef __s390x__ 186 sccb.evbuf.asa_size = ASA_SIZE_64; 187 #else 188 sccb.evbuf.asa_size = ASA_SIZE_32; 189 #endif 190 sccb.evbuf.event_status = 0; 191 sccb.evbuf.blk_cnt = nr_blks; 192 sccb.evbuf.asa = (unsigned long)dest; 193 sccb.evbuf.fbn = start_blk; 194 sccb.evbuf.lbn = 0; 195 sccb.evbuf.dbs = 1; 196 197 request.sccb = &sccb; 198 request.command = SCLP_CMDW_WRITE_EVENT_DATA; 199 request.status = SCLP_REQ_FILLED; 200 request.callback = sdias_callback; 201 202 rc = sdias_sclp_send(&request); 203 if (rc) { 204 ERROR_MSG("sclp_send failed: %x\n", rc); 205 goto out; 206 } 207 if (sccb.hdr.response_code != 0x0020) { 208 TRACE("copy failed: %x\n", sccb.hdr.response_code); 209 rc = -EIO; 210 goto out; 211 } 212 213 switch (sccb.evbuf.event_status) { 214 case EVSTATE_ALL_STORED: 215 TRACE("all stored\n"); 216 case EVSTATE_PART_STORED: 217 TRACE("part stored: %i\n", sccb.evbuf.blk_cnt); 218 break; 219 case EVSTATE_NO_DATA: 220 TRACE("no data\n"); 221 default: 222 ERROR_MSG("Error from SCLP while copying hsa. " 223 "Event status = %x\n", 224 sccb.evbuf.event_status); 225 rc = -EIO; 226 } 227 out: 228 mutex_unlock(&sdias_mutex); 229 return rc; 230 } 231 232 int __init sclp_sdias_init(void) 233 { 234 int rc; 235 236 if (ipl_info.type != IPL_TYPE_FCP_DUMP) 237 return 0; 238 sdias_dbf = debug_register("dump_sdias", 4, 1, 4 * sizeof(long)); 239 debug_register_view(sdias_dbf, &debug_sprintf_view); 240 debug_set_level(sdias_dbf, 6); 241 rc = sclp_register(&sclp_sdias_register); 242 if (rc) 243 return rc; 244 init_waitqueue_head(&sdias_wq); 245 TRACE("init done\n"); 246 return 0; 247 } 248 249 void __exit sclp_sdias_exit(void) 250 { 251 debug_unregister(sdias_dbf); 252 sclp_unregister(&sclp_sdias_register); 253 } 254