linux/drivers/s390/char/sclp_sdias.c
<<
>>
Prefs
   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
  33static struct debug_info *sdias_dbf;
  34
  35static struct sclp_register sclp_sdias_register = {
  36        .send_mask = EVTYP_SDIAS_MASK,
  37};
  38
  39struct 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
  59struct sdias_sccb {
  60        struct sccb_header  hdr;
  61        struct sdias_evbuf  evbuf;
  62} __attribute__((packed));
  63
  64static struct sdias_sccb sccb __attribute__((aligned(4096)));
  65
  66static int sclp_req_done;
  67static wait_queue_head_t sdias_wq;
  68static DEFINE_MUTEX(sdias_mutex);
  69
  70static 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
  80static 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 */
 112int 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);
 157out:
 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 */
 172int 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        }
 231out:
 232        mutex_unlock(&sdias_mutex);
 233        return rc;
 234}
 235
 236int __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
 253void __exit sclp_sdias_exit(void)
 254{
 255        debug_unregister(sdias_dbf);
 256        sclp_unregister(&sclp_sdias_register);
 257}
 258