Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  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 
  This page was automatically generated by the LXR engine.