root/drivers/s390/char/sclp_sdias.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sclp_sdias_receiver_fn
  2. sdias_callback
  3. sdias_sclp_send
  4. sclp_sdias_blk_count
  5. sclp_sdias_copy
  6. sclp_sdias_register_check
  7. sclp_sdias_init_sync
  8. sclp_sdias_init_async
  9. sclp_sdias_init
  10. sclp_sdias_exit

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * SCLP "store data in absolute storage"
   4  *
   5  * Copyright IBM Corp. 2003, 2013
   6  * Author(s): Michael Holzheu
   7  */
   8 
   9 #define KMSG_COMPONENT "sclp_sdias"
  10 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
  11 
  12 #include <linux/completion.h>
  13 #include <linux/sched.h>
  14 #include <asm/sclp.h>
  15 #include <asm/debug.h>
  16 #include <asm/ipl.h>
  17 
  18 #include "sclp_sdias.h"
  19 #include "sclp.h"
  20 #include "sclp_rw.h"
  21 
  22 #define TRACE(x...) debug_sprintf_event(sdias_dbf, 1, x)
  23 
  24 #define SDIAS_RETRIES 300
  25 
  26 static struct debug_info *sdias_dbf;
  27 
  28 static struct sclp_register sclp_sdias_register = {
  29         .send_mask = EVTYP_SDIAS_MASK,
  30 };
  31 
  32 static struct sdias_sccb *sclp_sdias_sccb;
  33 static struct sdias_evbuf sdias_evbuf;
  34 
  35 static DECLARE_COMPLETION(evbuf_accepted);
  36 static DECLARE_COMPLETION(evbuf_done);
  37 static DEFINE_MUTEX(sdias_mutex);
  38 
  39 /*
  40  * Called by SCLP base when read event data has been completed (async mode only)
  41  */
  42 static void sclp_sdias_receiver_fn(struct evbuf_header *evbuf)
  43 {
  44         memcpy(&sdias_evbuf, evbuf,
  45                min_t(unsigned long, sizeof(sdias_evbuf), evbuf->length));
  46         complete(&evbuf_done);
  47         TRACE("sclp_sdias_receiver_fn done\n");
  48 }
  49 
  50 /*
  51  * Called by SCLP base when sdias event has been accepted
  52  */
  53 static void sdias_callback(struct sclp_req *request, void *data)
  54 {
  55         complete(&evbuf_accepted);
  56         TRACE("callback done\n");
  57 }
  58 
  59 static int sdias_sclp_send(struct sclp_req *req)
  60 {
  61         struct sdias_sccb *sccb = sclp_sdias_sccb;
  62         int retries;
  63         int rc;
  64 
  65         for (retries = SDIAS_RETRIES; retries; retries--) {
  66                 TRACE("add request\n");
  67                 rc = sclp_add_request(req);
  68                 if (rc) {
  69                         /* not initiated, wait some time and retry */
  70                         set_current_state(TASK_INTERRUPTIBLE);
  71                         TRACE("add request failed: rc = %i\n",rc);
  72                         schedule_timeout(msecs_to_jiffies(500));
  73                         continue;
  74                 }
  75                 /* initiated, wait for completion of service call */
  76                 wait_for_completion(&evbuf_accepted);
  77                 if (req->status == SCLP_REQ_FAILED) {
  78                         TRACE("sclp request failed\n");
  79                         continue;
  80                 }
  81                 /* if not accepted, retry */
  82                 if (!(sccb->evbuf.hdr.flags & 0x80)) {
  83                         TRACE("sclp request failed: flags=%x\n",
  84                               sccb->evbuf.hdr.flags);
  85                         continue;
  86                 }
  87                 /*
  88                  * for the sync interface the response is in the initial sccb
  89                  */
  90                 if (!sclp_sdias_register.receiver_fn) {
  91                         memcpy(&sdias_evbuf, &sccb->evbuf, sizeof(sdias_evbuf));
  92                         TRACE("sync request done\n");
  93                         return 0;
  94                 }
  95                 /* otherwise we wait for completion */
  96                 wait_for_completion(&evbuf_done);
  97                 TRACE("request done\n");
  98                 return 0;
  99         }
 100         return -EIO;
 101 }
 102 
 103 /*
 104  * Get number of blocks (4K) available in the HSA
 105  */
 106 int sclp_sdias_blk_count(void)
 107 {
 108         struct sdias_sccb *sccb = sclp_sdias_sccb;
 109         struct sclp_req request;
 110         int rc;
 111 
 112         mutex_lock(&sdias_mutex);
 113 
 114         memset(sccb, 0, sizeof(*sccb));
 115         memset(&request, 0, sizeof(request));
 116 
 117         sccb->hdr.length = sizeof(*sccb);
 118         sccb->evbuf.hdr.length = sizeof(struct sdias_evbuf);
 119         sccb->evbuf.hdr.type = EVTYP_SDIAS;
 120         sccb->evbuf.event_qual = SDIAS_EQ_SIZE;
 121         sccb->evbuf.data_id = SDIAS_DI_FCP_DUMP;
 122         sccb->evbuf.event_id = 4712;
 123         sccb->evbuf.dbs = 1;
 124 
 125         request.sccb = sccb;
 126         request.command = SCLP_CMDW_WRITE_EVENT_DATA;
 127         request.status = SCLP_REQ_FILLED;
 128         request.callback = sdias_callback;
 129 
 130         rc = sdias_sclp_send(&request);
 131         if (rc) {
 132                 pr_err("sclp_send failed for get_nr_blocks\n");
 133                 goto out;
 134         }
 135         if (sccb->hdr.response_code != 0x0020) {
 136                 TRACE("send failed: %x\n", sccb->hdr.response_code);
 137                 rc = -EIO;
 138                 goto out;
 139         }
 140 
 141         switch (sdias_evbuf.event_status) {
 142                 case 0:
 143                         rc = sdias_evbuf.blk_cnt;
 144                         break;
 145                 default:
 146                         pr_err("SCLP error: %x\n", sdias_evbuf.event_status);
 147                         rc = -EIO;
 148                         goto out;
 149         }
 150         TRACE("%i blocks\n", rc);
 151 out:
 152         mutex_unlock(&sdias_mutex);
 153         return rc;
 154 }
 155 
 156 /*
 157  * Copy from HSA to absolute storage (not reentrant):
 158  *
 159  * @dest     : Address of buffer where data should be copied
 160  * @start_blk: Start Block (beginning with 1)
 161  * @nr_blks  : Number of 4K blocks to copy
 162  *
 163  * Return Value: 0 : Requested 'number' of blocks of data copied
 164  *               <0: ERROR - negative event status
 165  */
 166 int sclp_sdias_copy(void *dest, int start_blk, int nr_blks)
 167 {
 168         struct sdias_sccb *sccb = sclp_sdias_sccb;
 169         struct sclp_req request;
 170         int rc;
 171 
 172         mutex_lock(&sdias_mutex);
 173 
 174         memset(sccb, 0, sizeof(*sccb));
 175         memset(&request, 0, sizeof(request));
 176 
 177         sccb->hdr.length = sizeof(*sccb);
 178         sccb->evbuf.hdr.length = sizeof(struct sdias_evbuf);
 179         sccb->evbuf.hdr.type = EVTYP_SDIAS;
 180         sccb->evbuf.hdr.flags = 0;
 181         sccb->evbuf.event_qual = SDIAS_EQ_STORE_DATA;
 182         sccb->evbuf.data_id = SDIAS_DI_FCP_DUMP;
 183         sccb->evbuf.event_id = 4712;
 184         sccb->evbuf.asa_size = SDIAS_ASA_SIZE_64;
 185         sccb->evbuf.event_status = 0;
 186         sccb->evbuf.blk_cnt = nr_blks;
 187         sccb->evbuf.asa = (unsigned long)dest;
 188         sccb->evbuf.fbn = start_blk;
 189         sccb->evbuf.lbn = 0;
 190         sccb->evbuf.dbs = 1;
 191 
 192         request.sccb     = sccb;
 193         request.command  = SCLP_CMDW_WRITE_EVENT_DATA;
 194         request.status   = SCLP_REQ_FILLED;
 195         request.callback = sdias_callback;
 196 
 197         rc = sdias_sclp_send(&request);
 198         if (rc) {
 199                 pr_err("sclp_send failed: %x\n", rc);
 200                 goto out;
 201         }
 202         if (sccb->hdr.response_code != 0x0020) {
 203                 TRACE("copy failed: %x\n", sccb->hdr.response_code);
 204                 rc = -EIO;
 205                 goto out;
 206         }
 207 
 208         switch (sdias_evbuf.event_status) {
 209         case SDIAS_EVSTATE_ALL_STORED:
 210                 TRACE("all stored\n");
 211                 break;
 212         case SDIAS_EVSTATE_PART_STORED:
 213                 TRACE("part stored: %i\n", sdias_evbuf.blk_cnt);
 214                 break;
 215         case SDIAS_EVSTATE_NO_DATA:
 216                 TRACE("no data\n");
 217                 /* fall through */
 218         default:
 219                 pr_err("Error from SCLP while copying hsa. Event status = %x\n",
 220                        sdias_evbuf.event_status);
 221                 rc = -EIO;
 222         }
 223 out:
 224         mutex_unlock(&sdias_mutex);
 225         return rc;
 226 }
 227 
 228 static int __init sclp_sdias_register_check(void)
 229 {
 230         int rc;
 231 
 232         rc = sclp_register(&sclp_sdias_register);
 233         if (rc)
 234                 return rc;
 235         if (sclp_sdias_blk_count() == 0) {
 236                 sclp_unregister(&sclp_sdias_register);
 237                 return -ENODEV;
 238         }
 239         return 0;
 240 }
 241 
 242 static int __init sclp_sdias_init_sync(void)
 243 {
 244         TRACE("Try synchronous mode\n");
 245         sclp_sdias_register.receive_mask = 0;
 246         sclp_sdias_register.receiver_fn = NULL;
 247         return sclp_sdias_register_check();
 248 }
 249 
 250 static int __init sclp_sdias_init_async(void)
 251 {
 252         TRACE("Try asynchronous mode\n");
 253         sclp_sdias_register.receive_mask = EVTYP_SDIAS_MASK;
 254         sclp_sdias_register.receiver_fn = sclp_sdias_receiver_fn;
 255         return sclp_sdias_register_check();
 256 }
 257 
 258 int __init sclp_sdias_init(void)
 259 {
 260         if (ipl_info.type != IPL_TYPE_FCP_DUMP)
 261                 return 0;
 262         sclp_sdias_sccb = (void *) __get_free_page(GFP_KERNEL | GFP_DMA);
 263         BUG_ON(!sclp_sdias_sccb);
 264         sdias_dbf = debug_register("dump_sdias", 4, 1, 4 * sizeof(long));
 265         debug_register_view(sdias_dbf, &debug_sprintf_view);
 266         debug_set_level(sdias_dbf, 6);
 267         if (sclp_sdias_init_sync() == 0)
 268                 goto out;
 269         if (sclp_sdias_init_async() == 0)
 270                 goto out;
 271         TRACE("init failed\n");
 272         free_page((unsigned long) sclp_sdias_sccb);
 273         return -ENODEV;
 274 out:
 275         TRACE("init done\n");
 276         return 0;
 277 }
 278 
 279 void __exit sclp_sdias_exit(void)
 280 {
 281         debug_unregister(sdias_dbf);
 282         sclp_unregister(&sclp_sdias_register);
 283 }

/* [<][>][^][v][top][bottom][index][help] */