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