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#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
  30static struct debug_info *sdias_dbf;
  31
  32static struct sclp_register sclp_sdias_register = {
  33        .send_mask = EVTYP_SDIAS_MASK,
  34};
  35
  36struct 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
  56struct sdias_sccb {
  57        struct sccb_header  hdr;
  58        struct sdias_evbuf  evbuf;
  59} __attribute__((packed));
  60
  61static struct sdias_sccb sccb __attribute__((aligned(4096)));
  62
  63static int sclp_req_done;
  64static wait_queue_head_t sdias_wq;
  65static DEFINE_MUTEX(sdias_mutex);
  66
  67static 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
  77static 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 */
 109int 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);
 153out:
 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 */
 168int 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        }
 227out:
 228        mutex_unlock(&sdias_mutex);
 229        return rc;
 230}
 231
 232int __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
 249void __exit sclp_sdias_exit(void)
 250{
 251        debug_unregister(sdias_dbf);
 252        sclp_unregister(&sclp_sdias_register);
 253}
 254
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.