linux/drivers/s390/cio/chsc.c
<<
>>
Prefs
   1/*
   2 *  drivers/s390/cio/chsc.c
   3 *   S/390 common I/O routines -- channel subsystem call
   4 *
   5 *    Copyright IBM Corp. 1999,2008
   6 *    Author(s): Ingo Adlung (adlung@de.ibm.com)
   7 *               Cornelia Huck (cornelia.huck@de.ibm.com)
   8 *               Arnd Bergmann (arndb@de.ibm.com)
   9 */
  10
  11#include <linux/module.h>
  12#include <linux/slab.h>
  13#include <linux/init.h>
  14#include <linux/device.h>
  15
  16#include <asm/cio.h>
  17#include <asm/chpid.h>
  18#include <asm/chsc.h>
  19
  20#include "../s390mach.h"
  21#include "css.h"
  22#include "cio.h"
  23#include "cio_debug.h"
  24#include "ioasm.h"
  25#include "chp.h"
  26#include "chsc.h"
  27
  28static void *sei_page;
  29
  30/**
  31 * chsc_error_from_response() - convert a chsc response to an error
  32 * @response: chsc response code
  33 *
  34 * Returns an appropriate Linux error code for @response.
  35 */
  36int chsc_error_from_response(int response)
  37{
  38        switch (response) {
  39        case 0x0001:
  40                return 0;
  41        case 0x0002:
  42        case 0x0003:
  43        case 0x0006:
  44        case 0x0007:
  45        case 0x0008:
  46        case 0x000a:
  47                return -EINVAL;
  48        case 0x0004:
  49                return -EOPNOTSUPP;
  50        default:
  51                return -EIO;
  52        }
  53}
  54EXPORT_SYMBOL_GPL(chsc_error_from_response);
  55
  56struct chsc_ssd_area {
  57        struct chsc_header request;
  58        u16 :10;
  59        u16 ssid:2;
  60        u16 :4;
  61        u16 f_sch;        /* first subchannel */
  62        u16 :16;
  63        u16 l_sch;        /* last subchannel */
  64        u32 :32;
  65        struct chsc_header response;
  66        u32 :32;
  67        u8 sch_valid : 1;
  68        u8 dev_valid : 1;
  69        u8 st        : 3; /* subchannel type */
  70        u8 zeroes    : 3;
  71        u8  unit_addr;    /* unit address */
  72        u16 devno;        /* device number */
  73        u8 path_mask;
  74        u8 fla_valid_mask;
  75        u16 sch;          /* subchannel */
  76        u8 chpid[8];      /* chpids 0-7 */
  77        u16 fla[8];       /* full link addresses 0-7 */
  78} __attribute__ ((packed));
  79
  80int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd)
  81{
  82        unsigned long page;
  83        struct chsc_ssd_area *ssd_area;
  84        int ccode;
  85        int ret;
  86        int i;
  87        int mask;
  88
  89        page = get_zeroed_page(GFP_KERNEL | GFP_DMA);
  90        if (!page)
  91                return -ENOMEM;
  92        ssd_area = (struct chsc_ssd_area *) page;
  93        ssd_area->request.length = 0x0010;
  94        ssd_area->request.code = 0x0004;
  95        ssd_area->ssid = schid.ssid;
  96        ssd_area->f_sch = schid.sch_no;
  97        ssd_area->l_sch = schid.sch_no;
  98
  99        ccode = chsc(ssd_area);
 100        /* Check response. */
 101        if (ccode > 0) {
 102                ret = (ccode == 3) ? -ENODEV : -EBUSY;
 103                goto out_free;
 104        }
 105        ret = chsc_error_from_response(ssd_area->response.code);
 106        if (ret != 0) {
 107                CIO_MSG_EVENT(2, "chsc: ssd failed for 0.%x.%04x (rc=%04x)\n",
 108                              schid.ssid, schid.sch_no,
 109                              ssd_area->response.code);
 110                goto out_free;
 111        }
 112        if (!ssd_area->sch_valid) {
 113                ret = -ENODEV;
 114                goto out_free;
 115        }
 116        /* Copy data */
 117        ret = 0;
 118        memset(ssd, 0, sizeof(struct chsc_ssd_info));
 119        if ((ssd_area->st != SUBCHANNEL_TYPE_IO) &&
 120            (ssd_area->st != SUBCHANNEL_TYPE_MSG))
 121                goto out_free;
 122        ssd->path_mask = ssd_area->path_mask;
 123        ssd->fla_valid_mask = ssd_area->fla_valid_mask;
 124        for (i = 0; i < 8; i++) {
 125                mask = 0x80 >> i;
 126                if (ssd_area->path_mask & mask) {
 127                        chp_id_init(&ssd->chpid[i]);
 128                        ssd->chpid[i].id = ssd_area->chpid[i];
 129                }
 130                if (ssd_area->fla_valid_mask & mask)
 131                        ssd->fla[i] = ssd_area->fla[i];
 132        }
 133out_free:
 134        free_page(page);
 135        return ret;
 136}
 137
 138static int s390_subchannel_remove_chpid(struct subchannel *sch, void *data)
 139{
 140        spin_lock_irq(sch->lock);
 141        if (sch->driver && sch->driver->chp_event)
 142                if (sch->driver->chp_event(sch, data, CHP_OFFLINE) != 0)
 143                        goto out_unreg;
 144        spin_unlock_irq(sch->lock);
 145        return 0;
 146
 147out_unreg:
 148        sch->lpm = 0;
 149        spin_unlock_irq(sch->lock);
 150        css_schedule_eval(sch->schid);
 151        return 0;
 152}
 153
 154void chsc_chp_offline(struct chp_id chpid)
 155{
 156        char dbf_txt[15];
 157        struct chp_link link;
 158
 159        sprintf(dbf_txt, "chpr%x.%02x", chpid.cssid, chpid.id);
 160        CIO_TRACE_EVENT(2, dbf_txt);
 161
 162        if (chp_get_status(chpid) <= 0)
 163                return;
 164        memset(&link, 0, sizeof(struct chp_link));
 165        link.chpid = chpid;
 166        /* Wait until previous actions have settled. */
 167        css_wait_for_slow_path();
 168        for_each_subchannel_staged(s390_subchannel_remove_chpid, NULL, &link);
 169}
 170
 171static int s390_process_res_acc_new_sch(struct subchannel_id schid, void *data)
 172{
 173        struct schib schib;
 174        /*
 175         * We don't know the device yet, but since a path
 176         * may be available now to the device we'll have
 177         * to do recognition again.
 178         * Since we don't have any idea about which chpid
 179         * that beast may be on we'll have to do a stsch
 180         * on all devices, grr...
 181         */
 182        if (stsch_err(schid, &schib))
 183                /* We're through */
 184                return -ENXIO;
 185
 186        /* Put it on the slow path. */
 187        css_schedule_eval(schid);
 188        return 0;
 189}
 190
 191static int __s390_process_res_acc(struct subchannel *sch, void *data)
 192{
 193        spin_lock_irq(sch->lock);
 194        if (sch->driver && sch->driver->chp_event)
 195                sch->driver->chp_event(sch, data, CHP_ONLINE);
 196        spin_unlock_irq(sch->lock);
 197
 198        return 0;
 199}
 200
 201static void s390_process_res_acc(struct chp_link *link)
 202{
 203        char dbf_txt[15];
 204
 205        sprintf(dbf_txt, "accpr%x.%02x", link->chpid.cssid,
 206                link->chpid.id);
 207        CIO_TRACE_EVENT( 2, dbf_txt);
 208        if (link->fla != 0) {
 209                sprintf(dbf_txt, "fla%x", link->fla);
 210                CIO_TRACE_EVENT( 2, dbf_txt);
 211        }
 212        /* Wait until previous actions have settled. */
 213        css_wait_for_slow_path();
 214        /*
 215         * I/O resources may have become accessible.
 216         * Scan through all subchannels that may be concerned and
 217         * do a validation on those.
 218         * The more information we have (info), the less scanning
 219         * will we have to do.
 220         */
 221        for_each_subchannel_staged(__s390_process_res_acc,
 222                                   s390_process_res_acc_new_sch, link);
 223}
 224
 225static int
 226__get_chpid_from_lir(void *data)
 227{
 228        struct lir {
 229                u8  iq;
 230                u8  ic;
 231                u16 sci;
 232                /* incident-node descriptor */
 233                u32 indesc[28];
 234                /* attached-node descriptor */
 235                u32 andesc[28];
 236                /* incident-specific information */
 237                u32 isinfo[28];
 238        } __attribute__ ((packed)) *lir;
 239
 240        lir = data;
 241        if (!(lir->iq&0x80))
 242                /* NULL link incident record */
 243                return -EINVAL;
 244        if (!(lir->indesc[0]&0xc0000000))
 245                /* node descriptor not valid */
 246                return -EINVAL;
 247        if (!(lir->indesc[0]&0x10000000))
 248                /* don't handle device-type nodes - FIXME */
 249                return -EINVAL;
 250        /* Byte 3 contains the chpid. Could also be CTCA, but we don't care */
 251
 252        return (u16) (lir->indesc[0]&0x000000ff);
 253}
 254
 255struct chsc_sei_area {
 256        struct chsc_header request;
 257        u32 reserved1;
 258        u32 reserved2;
 259        u32 reserved3;
 260        struct chsc_header response;
 261        u32 reserved4;
 262        u8  flags;
 263        u8  vf;         /* validity flags */
 264        u8  rs;         /* reporting source */
 265        u8  cc;         /* content code */
 266        u16 fla;        /* full link address */
 267        u16 rsid;       /* reporting source id */
 268        u32 reserved5;
 269        u32 reserved6;
 270        u8 ccdf[4096 - 16 - 24];        /* content-code dependent field */
 271        /* ccdf has to be big enough for a link-incident record */
 272} __attribute__ ((packed));
 273
 274static void chsc_process_sei_link_incident(struct chsc_sei_area *sei_area)
 275{
 276        struct chp_id chpid;
 277        int id;
 278
 279        CIO_CRW_EVENT(4, "chsc: link incident (rs=%02x, rs_id=%04x)\n",
 280                      sei_area->rs, sei_area->rsid);
 281        if (sei_area->rs != 4)
 282                return;
 283        id = __get_chpid_from_lir(sei_area->ccdf);
 284        if (id < 0)
 285                CIO_CRW_EVENT(4, "chsc: link incident - invalid LIR\n");
 286        else {
 287                chp_id_init(&chpid);
 288                chpid.id = id;
 289                chsc_chp_offline(chpid);
 290        }
 291}
 292
 293static void chsc_process_sei_res_acc(struct chsc_sei_area *sei_area)
 294{
 295        struct chp_link link;
 296        struct chp_id chpid;
 297        int status;
 298
 299        CIO_CRW_EVENT(4, "chsc: resource accessibility event (rs=%02x, "
 300                      "rs_id=%04x)\n", sei_area->rs, sei_area->rsid);
 301        if (sei_area->rs != 4)
 302                return;
 303        chp_id_init(&chpid);
 304        chpid.id = sei_area->rsid;
 305        /* allocate a new channel path structure, if needed */
 306        status = chp_get_status(chpid);
 307        if (status < 0)
 308                chp_new(chpid);
 309        else if (!status)
 310                return;
 311        memset(&link, 0, sizeof(struct chp_link));
 312        link.chpid = chpid;
 313        if ((sei_area->vf & 0xc0) != 0) {
 314                link.fla = sei_area->fla;
 315                if ((sei_area->vf & 0xc0) == 0xc0)
 316                        /* full link address */
 317                        link.fla_mask = 0xffff;
 318                else
 319                        /* link address */
 320                        link.fla_mask = 0xff00;
 321        }
 322        s390_process_res_acc(&link);
 323}
 324
 325struct chp_config_data {
 326        u8 map[32];
 327        u8 op;
 328        u8 pc;
 329};
 330
 331static void chsc_process_sei_chp_config(struct chsc_sei_area *sei_area)
 332{
 333        struct chp_config_data *data;
 334        struct chp_id chpid;
 335        int num;
 336
 337        CIO_CRW_EVENT(4, "chsc: channel-path-configuration notification\n");
 338        if (sei_area->rs != 0)
 339                return;
 340        data = (struct chp_config_data *) &(sei_area->ccdf);
 341        chp_id_init(&chpid);
 342        for (num = 0; num <= __MAX_CHPID; num++) {
 343                if (!chp_test_bit(data->map, num))
 344                        continue;
 345                chpid.id = num;
 346                printk(KERN_WARNING "cio: processing configure event %d for "
 347                       "chpid %x.%02x\n", data->op, chpid.cssid, chpid.id);
 348                switch (data->op) {
 349                case 0:
 350                        chp_cfg_schedule(chpid, 1);
 351                        break;
 352                case 1:
 353                        chp_cfg_schedule(chpid, 0);
 354                        break;
 355                case 2:
 356                        chp_cfg_cancel_deconfigure(chpid);
 357                        break;
 358                }
 359        }
 360}
 361
 362static void chsc_process_sei(struct chsc_sei_area *sei_area)
 363{
 364        /* Check if we might have lost some information. */
 365        if (sei_area->flags & 0x40) {
 366                CIO_CRW_EVENT(2, "chsc: event overflow\n");
 367                css_schedule_eval_all();
 368        }
 369        /* which kind of information was stored? */
 370        switch (sei_area->cc) {
 371        case 1: /* link incident*/
 372                chsc_process_sei_link_incident(sei_area);
 373                break;
 374        case 2: /* i/o resource accessibiliy */
 375                chsc_process_sei_res_acc(sei_area);
 376                break;
 377        case 8: /* channel-path-configuration notification */
 378                chsc_process_sei_chp_config(sei_area);
 379                break;
 380        default: /* other stuff */
 381                CIO_CRW_EVENT(4, "chsc: unhandled sei content code %d\n",
 382                              sei_area->cc);
 383                break;
 384        }
 385}
 386
 387static void chsc_process_crw(struct crw *crw0, struct crw *crw1, int overflow)
 388{
 389        struct chsc_sei_area *sei_area;
 390
 391        if (overflow) {
 392                css_schedule_eval_all();
 393                return;
 394        }
 395        CIO_CRW_EVENT(2, "CRW reports slct=%d, oflw=%d, "
 396                      "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
 397                      crw0->slct, crw0->oflw, crw0->chn, crw0->rsc, crw0->anc,
 398                      crw0->erc, crw0->rsid);
 399        if (!sei_page)
 400                return;
 401        /* Access to sei_page is serialized through machine check handler
 402         * thread, so no need for locking. */
 403        sei_area = sei_page;
 404
 405        CIO_TRACE_EVENT(2, "prcss");
 406        do {
 407                memset(sei_area, 0, sizeof(*sei_area));
 408                sei_area->request.length = 0x0010;
 409                sei_area->request.code = 0x000e;
 410                if (chsc(sei_area))
 411                        break;
 412
 413                if (sei_area->response.code == 0x0001) {
 414                        CIO_CRW_EVENT(4, "chsc: sei successful\n");
 415                        chsc_process_sei(sei_area);
 416                } else {
 417                        CIO_CRW_EVENT(2, "chsc: sei failed (rc=%04x)\n",
 418                                      sei_area->response.code);
 419                        break;
 420                }
 421        } while (sei_area->flags & 0x80);
 422}
 423
 424void chsc_chp_online(struct chp_id chpid)
 425{
 426        char dbf_txt[15];
 427        struct chp_link link;
 428
 429        sprintf(dbf_txt, "cadd%x.%02x", chpid.cssid, chpid.id);
 430        CIO_TRACE_EVENT(2, dbf_txt);
 431
 432        if (chp_get_status(chpid) != 0) {
 433                memset(&link, 0, sizeof(struct chp_link));
 434                link.chpid = chpid;
 435                /* Wait until previous actions have settled. */
 436                css_wait_for_slow_path();
 437                for_each_subchannel_staged(__s390_process_res_acc, NULL,
 438                                           &link);
 439        }
 440}
 441
 442static void __s390_subchannel_vary_chpid(struct subchannel *sch,
 443                                         struct chp_id chpid, int on)
 444{
 445        unsigned long flags;
 446        struct chp_link link;
 447
 448        memset(&link, 0, sizeof(struct chp_link));
 449        link.chpid = chpid;
 450        spin_lock_irqsave(sch->lock, flags);
 451        if (sch->driver && sch->driver->chp_event)
 452                sch->driver->chp_event(sch, &link,
 453                                       on ? CHP_VARY_ON : CHP_VARY_OFF);
 454        spin_unlock_irqrestore(sch->lock, flags);
 455}
 456
 457static int s390_subchannel_vary_chpid_off(struct subchannel *sch, void *data)
 458{
 459        struct chp_id *chpid = data;
 460
 461        __s390_subchannel_vary_chpid(sch, *chpid, 0);
 462        return 0;
 463}
 464
 465static int s390_subchannel_vary_chpid_on(struct subchannel *sch, void *data)
 466{
 467        struct chp_id *chpid = data;
 468
 469        __s390_subchannel_vary_chpid(sch, *chpid, 1);
 470        return 0;
 471}
 472
 473static int
 474__s390_vary_chpid_on(struct subchannel_id schid, void *data)
 475{
 476        struct schib schib;
 477
 478        if (stsch_err(schid, &schib))
 479                /* We're through */
 480                return -ENXIO;
 481        /* Put it on the slow path. */
 482        css_schedule_eval(schid);
 483        return 0;
 484}
 485
 486/**
 487 * chsc_chp_vary - propagate channel-path vary operation to subchannels
 488 * @chpid: channl-path ID
 489 * @on: non-zero for vary online, zero for vary offline
 490 */
 491int chsc_chp_vary(struct chp_id chpid, int on)
 492{
 493        struct chp_link link;
 494
 495        memset(&link, 0, sizeof(struct chp_link));
 496        link.chpid = chpid;
 497        /* Wait until previous actions have settled. */
 498        css_wait_for_slow_path();
 499        /*
 500         * Redo PathVerification on the devices the chpid connects to
 501         */
 502
 503        if (on)
 504                for_each_subchannel_staged(s390_subchannel_vary_chpid_on,
 505                                           __s390_vary_chpid_on, &link);
 506        else
 507                for_each_subchannel_staged(s390_subchannel_vary_chpid_off,
 508                                           NULL, &link);
 509
 510        return 0;
 511}
 512
 513static void
 514chsc_remove_cmg_attr(struct channel_subsystem *css)
 515{
 516        int i;
 517
 518        for (i = 0; i <= __MAX_CHPID; i++) {
 519                if (!css->chps[i])
 520                        continue;
 521                chp_remove_cmg_attr(css->chps[i]);
 522        }
 523}
 524
 525static int
 526chsc_add_cmg_attr(struct channel_subsystem *css)
 527{
 528        int i, ret;
 529
 530        ret = 0;
 531        for (i = 0; i <= __MAX_CHPID; i++) {
 532                if (!css->chps[i])
 533                        continue;
 534                ret = chp_add_cmg_attr(css->chps[i]);
 535                if (ret)
 536                        goto cleanup;
 537        }
 538        return ret;
 539cleanup:
 540        for (--i; i >= 0; i--) {
 541                if (!css->chps[i])
 542                        continue;
 543                chp_remove_cmg_attr(css->chps[i]);
 544        }
 545        return ret;
 546}
 547
 548static int
 549__chsc_do_secm(struct channel_subsystem *css, int enable, void *page)
 550{
 551        struct {
 552                struct chsc_header request;
 553                u32 operation_code : 2;
 554                u32 : 30;
 555                u32 key : 4;
 556                u32 : 28;
 557                u32 zeroes1;
 558                u32 cub_addr1;
 559                u32 zeroes2;
 560                u32 cub_addr2;
 561                u32 reserved[13];
 562                struct chsc_header response;
 563                u32 status : 8;
 564                u32 : 4;
 565                u32 fmt : 4;
 566                u32 : 16;
 567        } __attribute__ ((packed)) *secm_area;
 568        int ret, ccode;
 569
 570        secm_area = page;
 571        secm_area->request.length = 0x0050;
 572        secm_area->request.code = 0x0016;
 573
 574        secm_area->key = PAGE_DEFAULT_KEY;
 575        secm_area->cub_addr1 = (u64)(unsigned long)css->cub_addr1;
 576        secm_area->cub_addr2 = (u64)(unsigned long)css->cub_addr2;
 577
 578        secm_area->operation_code = enable ? 0 : 1;
 579
 580        ccode = chsc(secm_area);
 581        if (ccode > 0)
 582                return (ccode == 3) ? -ENODEV : -EBUSY;
 583
 584        switch (secm_area->response.code) {
 585        case 0x0102:
 586        case 0x0103:
 587                ret = -EINVAL;
 588        default:
 589                ret = chsc_error_from_response(secm_area->response.code);
 590        }
 591        if (ret != 0)
 592                CIO_CRW_EVENT(2, "chsc: secm failed (rc=%04x)\n",
 593                              secm_area->response.code);
 594        return ret;
 595}
 596
 597int
 598chsc_secm(struct channel_subsystem *css, int enable)
 599{
 600        void  *secm_area;
 601        int ret;
 602
 603        secm_area = (void *)get_zeroed_page(GFP_KERNEL |  GFP_DMA);
 604        if (!secm_area)
 605                return -ENOMEM;
 606
 607        if (enable && !css->cm_enabled) {
 608                css->cub_addr1 = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
 609                css->cub_addr2 = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
 610                if (!css->cub_addr1 || !css->cub_addr2) {
 611                        free_page((unsigned long)css->cub_addr1);
 612                        free_page((unsigned long)css->cub_addr2);
 613                        free_page((unsigned long)secm_area);
 614                        return -ENOMEM;
 615                }
 616        }
 617        ret = __chsc_do_secm(css, enable, secm_area);
 618        if (!ret) {
 619                css->cm_enabled = enable;
 620                if (css->cm_enabled) {
 621                        ret = chsc_add_cmg_attr(css);
 622                        if (ret) {
 623                                memset(secm_area, 0, PAGE_SIZE);
 624                                __chsc_do_secm(css, 0, secm_area);
 625                                css->cm_enabled = 0;
 626                        }
 627                } else
 628                        chsc_remove_cmg_attr(css);
 629        }
 630        if (!css->cm_enabled) {
 631                free_page((unsigned long)css->cub_addr1);
 632                free_page((unsigned long)css->cub_addr2);
 633        }
 634        free_page((unsigned long)secm_area);
 635        return ret;
 636}
 637
 638int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt,
 639                                     int c, int m,
 640                                     struct chsc_response_struct *resp)
 641{
 642        int ccode, ret;
 643
 644        struct {
 645                struct chsc_header request;
 646                u32 : 2;
 647                u32 m : 1;
 648                u32 c : 1;
 649                u32 fmt : 4;
 650                u32 cssid : 8;
 651                u32 : 4;
 652                u32 rfmt : 4;
 653                u32 first_chpid : 8;
 654                u32 : 24;
 655                u32 last_chpid : 8;
 656                u32 zeroes1;
 657                struct chsc_header response;
 658                u8 data[PAGE_SIZE - 20];
 659        } __attribute__ ((packed)) *scpd_area;
 660
 661        if ((rfmt == 1) && !css_general_characteristics.fcs)
 662                return -EINVAL;
 663        if ((rfmt == 2) && !css_general_characteristics.cib)
 664                return -EINVAL;
 665        scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
 666        if (!scpd_area)
 667                return -ENOMEM;
 668
 669        scpd_area->request.length = 0x0010;
 670        scpd_area->request.code = 0x0002;
 671
 672        scpd_area->cssid = chpid.cssid;
 673        scpd_area->first_chpid = chpid.id;
 674        scpd_area->last_chpid = chpid.id;
 675        scpd_area->m = m;
 676        scpd_area->c = c;
 677        scpd_area->fmt = fmt;
 678        scpd_area->rfmt = rfmt;
 679
 680        ccode = chsc(scpd_area);
 681        if (ccode > 0) {
 682                ret = (ccode == 3) ? -ENODEV : -EBUSY;
 683                goto out;
 684        }
 685
 686        ret = chsc_error_from_response(scpd_area->response.code);
 687        if (ret == 0)
 688                /* Success. */
 689                memcpy(resp, &scpd_area->response, scpd_area->response.length);
 690        else
 691                CIO_CRW_EVENT(2, "chsc: scpd failed (rc=%04x)\n",
 692                              scpd_area->response.code);
 693out:
 694        free_page((unsigned long)scpd_area);
 695        return ret;
 696}
 697EXPORT_SYMBOL_GPL(chsc_determine_channel_path_desc);
 698
 699int chsc_determine_base_channel_path_desc(struct chp_id chpid,
 700                                          struct channel_path_desc *desc)
 701{
 702        struct chsc_response_struct *chsc_resp;
 703        int ret;
 704
 705        chsc_resp = kzalloc(sizeof(*chsc_resp), GFP_KERNEL);
 706        if (!chsc_resp)
 707                return -ENOMEM;
 708        ret = chsc_determine_channel_path_desc(chpid, 0, 0, 0, 0, chsc_resp);
 709        if (ret)
 710                goto out_free;
 711        memcpy(desc, &chsc_resp->data, chsc_resp->length);
 712out_free:
 713        kfree(chsc_resp);
 714        return ret;
 715}
 716
 717static void
 718chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv,
 719                          struct cmg_chars *chars)
 720{
 721        switch (chp->cmg) {
 722        case 2:
 723        case 3:
 724                chp->cmg_chars = kmalloc(sizeof(struct cmg_chars),
 725                                         GFP_KERNEL);
 726                if (chp->cmg_chars) {
 727                        int i, mask;
 728                        struct cmg_chars *cmg_chars;
 729
 730                        cmg_chars = chp->cmg_chars;
 731                        for (i = 0; i < NR_MEASUREMENT_CHARS; i++) {
 732                                mask = 0x80 >> (i + 3);
 733                                if (cmcv & mask)
 734                                        cmg_chars->values[i] = chars->values[i];
 735                                else
 736                                        cmg_chars->values[i] = 0;
 737                        }
 738                }
 739                break;
 740        default:
 741                /* No cmg-dependent data. */
 742                break;
 743        }
 744}
 745
 746int chsc_get_channel_measurement_chars(struct channel_path *chp)
 747{
 748        int ccode, ret;
 749
 750        struct {
 751                struct chsc_header request;
 752                u32 : 24;
 753                u32 first_chpid : 8;
 754                u32 : 24;
 755                u32 last_chpid : 8;
 756                u32 zeroes1;
 757                struct chsc_header response;
 758                u32 zeroes2;
 759                u32 not_valid : 1;
 760                u32 shared : 1;
 761                u32 : 22;
 762                u32 chpid : 8;
 763                u32 cmcv : 5;
 764                u32 : 11;
 765                u32 cmgq : 8;
 766                u32 cmg : 8;
 767                u32 zeroes3;
 768                u32 data[NR_MEASUREMENT_CHARS];
 769        } __attribute__ ((packed)) *scmc_area;
 770
 771        scmc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
 772        if (!scmc_area)
 773                return -ENOMEM;
 774
 775        scmc_area->request.length = 0x0010;
 776        scmc_area->request.code = 0x0022;
 777
 778        scmc_area->first_chpid = chp->chpid.id;
 779        scmc_area->last_chpid = chp->chpid.id;
 780
 781        ccode = chsc(scmc_area);
 782        if (ccode > 0) {
 783                ret = (ccode == 3) ? -ENODEV : -EBUSY;
 784                goto out;
 785        }
 786
 787        ret = chsc_error_from_response(scmc_area->response.code);
 788        if (ret == 0) {
 789                /* Success. */
 790                if (!scmc_area->not_valid) {
 791                        chp->cmg = scmc_area->cmg;
 792                        chp->shared = scmc_area->shared;
 793                        chsc_initialize_cmg_chars(chp, scmc_area->cmcv,
 794                                                  (struct cmg_chars *)
 795                                                  &scmc_area->data);
 796                } else {
 797                        chp->cmg = -1;
 798                        chp->shared = -1;
 799                }
 800        } else {
 801                CIO_CRW_EVENT(2, "chsc: scmc failed (rc=%04x)\n",
 802                              scmc_area->response.code);
 803        }
 804out:
 805        free_page((unsigned long)scmc_area);
 806        return ret;
 807}
 808
 809int __init chsc_alloc_sei_area(void)
 810{
 811        int ret;
 812
 813        sei_page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
 814        if (!sei_page) {
 815                CIO_MSG_EVENT(0, "Can't allocate page for processing of "
 816                              "chsc machine checks!\n");
 817                return -ENOMEM;
 818        }
 819        ret = s390_register_crw_handler(CRW_RSC_CSS, chsc_process_crw);
 820        if (ret)
 821                kfree(sei_page);
 822        return ret;
 823}
 824
 825void __init chsc_free_sei_area(void)
 826{
 827        s390_unregister_crw_handler(CRW_RSC_CSS);
 828        kfree(sei_page);
 829}
 830
 831int __init
 832chsc_enable_facility(int operation_code)
 833{
 834        int ret;
 835        struct {
 836                struct chsc_header request;
 837                u8 reserved1:4;
 838                u8 format:4;
 839                u8 reserved2;
 840                u16 operation_code;
 841                u32 reserved3;
 842                u32 reserved4;
 843                u32 operation_data_area[252];
 844                struct chsc_header response;
 845                u32 reserved5:4;
 846                u32 format2:4;
 847                u32 reserved6:24;
 848        } __attribute__ ((packed)) *sda_area;
 849
 850        sda_area = (void *)get_zeroed_page(GFP_KERNEL|GFP_DMA);
 851        if (!sda_area)
 852                return -ENOMEM;
 853        sda_area->request.length = 0x0400;
 854        sda_area->request.code = 0x0031;
 855        sda_area->operation_code = operation_code;
 856
 857        ret = chsc(sda_area);
 858        if (ret > 0) {
 859                ret = (ret == 3) ? -ENODEV : -EBUSY;
 860                goto out;
 861        }
 862
 863        switch (sda_area->response.code) {
 864        case 0x0101:
 865                ret = -EOPNOTSUPP;
 866                break;
 867        default:
 868                ret = chsc_error_from_response(sda_area->response.code);
 869        }
 870        if (ret != 0)
 871                CIO_CRW_EVENT(2, "chsc: sda (oc=%x) failed (rc=%04x)\n",
 872                              operation_code, sda_area->response.code);
 873 out:
 874        free_page((unsigned long)sda_area);
 875        return ret;
 876}
 877
 878struct css_general_char css_general_characteristics;
 879struct css_chsc_char css_chsc_characteristics;
 880
 881int __init
 882chsc_determine_css_characteristics(void)
 883{
 884        int result;
 885        struct {
 886                struct chsc_header request;
 887                u32 reserved1;
 888                u32 reserved2;
 889                u32 reserved3;
 890                struct chsc_header response;
 891                u32 reserved4;
 892                u32 general_char[510];
 893                u32 chsc_char[518];
 894        } __attribute__ ((packed)) *scsc_area;
 895
 896        scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
 897        if (!scsc_area)
 898                return -ENOMEM;
 899
 900        scsc_area->request.length = 0x0010;
 901        scsc_area->request.code = 0x0010;
 902
 903        result = chsc(scsc_area);
 904        if (result) {
 905                result = (result == 3) ? -ENODEV : -EBUSY;
 906                goto exit;
 907        }
 908
 909        result = chsc_error_from_response(scsc_area->response.code);
 910        if (result == 0) {
 911                memcpy(&css_general_characteristics, scsc_area->general_char,
 912                       sizeof(css_general_characteristics));
 913                memcpy(&css_chsc_characteristics, scsc_area->chsc_char,
 914                       sizeof(css_chsc_characteristics));
 915        } else
 916                CIO_CRW_EVENT(2, "chsc: scsc failed (rc=%04x)\n",
 917                              scsc_area->response.code);
 918exit:
 919        free_page ((unsigned long) scsc_area);
 920        return result;
 921}
 922
 923EXPORT_SYMBOL_GPL(css_general_characteristics);
 924EXPORT_SYMBOL_GPL(css_chsc_characteristics);
 925
 926int chsc_sstpc(void *page, unsigned int op, u16 ctrl)
 927{
 928        struct {
 929                struct chsc_header request;
 930                unsigned int rsvd0;
 931                unsigned int op : 8;
 932                unsigned int rsvd1 : 8;
 933                unsigned int ctrl : 16;
 934                unsigned int rsvd2[5];
 935                struct chsc_header response;
 936                unsigned int rsvd3[7];
 937        } __attribute__ ((packed)) *rr;
 938        int rc;
 939
 940        memset(page, 0, PAGE_SIZE);
 941        rr = page;
 942        rr->request.length = 0x0020;
 943        rr->request.code = 0x0033;
 944        rr->op = op;
 945        rr->ctrl = ctrl;
 946        rc = chsc(rr);
 947        if (rc)
 948                return -EIO;
 949        rc = (rr->response.code == 0x0001) ? 0 : -EIO;
 950        return rc;
 951}
 952
 953int chsc_sstpi(void *page, void *result, size_t size)
 954{
 955        struct {
 956                struct chsc_header request;
 957                unsigned int rsvd0[3];
 958                struct chsc_header response;
 959                char data[size];
 960        } __attribute__ ((packed)) *rr;
 961        int rc;
 962
 963        memset(page, 0, PAGE_SIZE);
 964        rr = page;
 965        rr->request.length = 0x0010;
 966        rr->request.code = 0x0038;
 967        rc = chsc(rr);
 968        if (rc)
 969                return -EIO;
 970        memcpy(result, &rr->data, size);
 971        return (rr->response.code == 0x0001) ? 0 : -EIO;
 972}
 973
 974
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.