linux/drivers/s390/cio/chsc_sch.c
<<
>>
Prefs
   1/*
   2 * Driver for s390 chsc subchannels
   3 *
   4 * Copyright IBM Corp. 2008, 2011
   5 *
   6 * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
   7 *
   8 */
   9
  10#include <linux/slab.h>
  11#include <linux/compat.h>
  12#include <linux/device.h>
  13#include <linux/module.h>
  14#include <linux/uaccess.h>
  15#include <linux/miscdevice.h>
  16#include <linux/kernel_stat.h>
  17
  18#include <asm/compat.h>
  19#include <asm/cio.h>
  20#include <asm/chsc.h>
  21#include <asm/isc.h>
  22
  23#include "cio.h"
  24#include "cio_debug.h"
  25#include "css.h"
  26#include "chsc_sch.h"
  27#include "ioasm.h"
  28
  29static debug_info_t *chsc_debug_msg_id;
  30static debug_info_t *chsc_debug_log_id;
  31
  32static struct chsc_request *on_close_request;
  33static struct chsc_async_area *on_close_chsc_area;
  34static DEFINE_MUTEX(on_close_mutex);
  35
  36#define CHSC_MSG(imp, args...) do {                                     \
  37                debug_sprintf_event(chsc_debug_msg_id, imp , ##args);   \
  38        } while (0)
  39
  40#define CHSC_LOG(imp, txt) do {                                 \
  41                debug_text_event(chsc_debug_log_id, imp , txt); \
  42        } while (0)
  43
  44static void CHSC_LOG_HEX(int level, void *data, int length)
  45{
  46        while (length > 0) {
  47                debug_event(chsc_debug_log_id, level, data, length);
  48                length -= chsc_debug_log_id->buf_size;
  49                data += chsc_debug_log_id->buf_size;
  50        }
  51}
  52
  53MODULE_AUTHOR("IBM Corporation");
  54MODULE_DESCRIPTION("driver for s390 chsc subchannels");
  55MODULE_LICENSE("GPL");
  56
  57static void chsc_subchannel_irq(struct subchannel *sch)
  58{
  59        struct chsc_private *private = dev_get_drvdata(&sch->dev);
  60        struct chsc_request *request = private->request;
  61        struct irb *irb = (struct irb *)&S390_lowcore.irb;
  62
  63        CHSC_LOG(4, "irb");
  64        CHSC_LOG_HEX(4, irb, sizeof(*irb));
  65        inc_irq_stat(IRQIO_CSC);
  66
  67        /* Copy irb to provided request and set done. */
  68        if (!request) {
  69                CHSC_MSG(0, "Interrupt on sch 0.%x.%04x with no request\n",
  70                         sch->schid.ssid, sch->schid.sch_no);
  71                return;
  72        }
  73        private->request = NULL;
  74        memcpy(&request->irb, irb, sizeof(*irb));
  75        cio_update_schib(sch);
  76        complete(&request->completion);
  77        put_device(&sch->dev);
  78}
  79
  80static int chsc_subchannel_probe(struct subchannel *sch)
  81{
  82        struct chsc_private *private;
  83        int ret;
  84
  85        CHSC_MSG(6, "Detected chsc subchannel 0.%x.%04x\n",
  86                 sch->schid.ssid, sch->schid.sch_no);
  87        sch->isc = CHSC_SCH_ISC;
  88        private = kzalloc(sizeof(*private), GFP_KERNEL);
  89        if (!private)
  90                return -ENOMEM;
  91        dev_set_drvdata(&sch->dev, private);
  92        ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch);
  93        if (ret) {
  94                CHSC_MSG(0, "Failed to enable 0.%x.%04x: %d\n",
  95                         sch->schid.ssid, sch->schid.sch_no, ret);
  96                dev_set_drvdata(&sch->dev, NULL);
  97                kfree(private);
  98        } else {
  99                if (dev_get_uevent_suppress(&sch->dev)) {
 100                        dev_set_uevent_suppress(&sch->dev, 0);
 101                        kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
 102                }
 103        }
 104        return ret;
 105}
 106
 107static int chsc_subchannel_remove(struct subchannel *sch)
 108{
 109        struct chsc_private *private;
 110
 111        cio_disable_subchannel(sch);
 112        private = dev_get_drvdata(&sch->dev);
 113        dev_set_drvdata(&sch->dev, NULL);
 114        if (private->request) {
 115                complete(&private->request->completion);
 116                put_device(&sch->dev);
 117        }
 118        kfree(private);
 119        return 0;
 120}
 121
 122static void chsc_subchannel_shutdown(struct subchannel *sch)
 123{
 124        cio_disable_subchannel(sch);
 125}
 126
 127static int chsc_subchannel_prepare(struct subchannel *sch)
 128{
 129        int cc;
 130        struct schib schib;
 131        /*
 132         * Don't allow suspend while the subchannel is not idle
 133         * since we don't have a way to clear the subchannel and
 134         * cannot disable it with a request running.
 135         */
 136        cc = stsch_err(sch->schid, &schib);
 137        if (!cc && scsw_stctl(&schib.scsw))
 138                return -EAGAIN;
 139        return 0;
 140}
 141
 142static int chsc_subchannel_freeze(struct subchannel *sch)
 143{
 144        return cio_disable_subchannel(sch);
 145}
 146
 147static int chsc_subchannel_restore(struct subchannel *sch)
 148{
 149        return cio_enable_subchannel(sch, (u32)(unsigned long)sch);
 150}
 151
 152static struct css_device_id chsc_subchannel_ids[] = {
 153        { .match_flags = 0x1, .type =SUBCHANNEL_TYPE_CHSC, },
 154        { /* end of list */ },
 155};
 156MODULE_DEVICE_TABLE(css, chsc_subchannel_ids);
 157
 158static struct css_driver chsc_subchannel_driver = {
 159        .drv = {
 160                .owner = THIS_MODULE,
 161                .name = "chsc_subchannel",
 162        },
 163        .subchannel_type = chsc_subchannel_ids,
 164        .irq = chsc_subchannel_irq,
 165        .probe = chsc_subchannel_probe,
 166        .remove = chsc_subchannel_remove,
 167        .shutdown = chsc_subchannel_shutdown,
 168        .prepare = chsc_subchannel_prepare,
 169        .freeze = chsc_subchannel_freeze,
 170        .thaw = chsc_subchannel_restore,
 171        .restore = chsc_subchannel_restore,
 172};
 173
 174static int __init chsc_init_dbfs(void)
 175{
 176        chsc_debug_msg_id = debug_register("chsc_msg", 16, 1,
 177                                           16 * sizeof(long));
 178        if (!chsc_debug_msg_id)
 179                goto out;
 180        debug_register_view(chsc_debug_msg_id, &debug_sprintf_view);
 181        debug_set_level(chsc_debug_msg_id, 2);
 182        chsc_debug_log_id = debug_register("chsc_log", 16, 1, 16);
 183        if (!chsc_debug_log_id)
 184                goto out;
 185        debug_register_view(chsc_debug_log_id, &debug_hex_ascii_view);
 186        debug_set_level(chsc_debug_log_id, 2);
 187        return 0;
 188out:
 189        if (chsc_debug_msg_id)
 190                debug_unregister(chsc_debug_msg_id);
 191        return -ENOMEM;
 192}
 193
 194static void chsc_remove_dbfs(void)
 195{
 196        debug_unregister(chsc_debug_log_id);
 197        debug_unregister(chsc_debug_msg_id);
 198}
 199
 200static int __init chsc_init_sch_driver(void)
 201{
 202        return css_driver_register(&chsc_subchannel_driver);
 203}
 204
 205static void chsc_cleanup_sch_driver(void)
 206{
 207        css_driver_unregister(&chsc_subchannel_driver);
 208}
 209
 210static DEFINE_SPINLOCK(chsc_lock);
 211
 212static int chsc_subchannel_match_next_free(struct device *dev, void *data)
 213{
 214        struct subchannel *sch = to_subchannel(dev);
 215
 216        return sch->schib.pmcw.ena && !scsw_fctl(&sch->schib.scsw);
 217}
 218
 219static struct subchannel *chsc_get_next_subchannel(struct subchannel *sch)
 220{
 221        struct device *dev;
 222
 223        dev = driver_find_device(&chsc_subchannel_driver.drv,
 224                                 sch ? &sch->dev : NULL, NULL,
 225                                 chsc_subchannel_match_next_free);
 226        return dev ? to_subchannel(dev) : NULL;
 227}
 228
 229/**
 230 * chsc_async() - try to start a chsc request asynchronously
 231 * @chsc_area: request to be started
 232 * @request: request structure to associate
 233 *
 234 * Tries to start a chsc request on one of the existing chsc subchannels.
 235 * Returns:
 236 *  %0 if the request was performed synchronously
 237 *  %-EINPROGRESS if the request was successfully started
 238 *  %-EBUSY if all chsc subchannels are busy
 239 *  %-ENODEV if no chsc subchannels are available
 240 * Context:
 241 *  interrupts disabled, chsc_lock held
 242 */
 243static int chsc_async(struct chsc_async_area *chsc_area,
 244                      struct chsc_request *request)
 245{
 246        int cc;
 247        struct chsc_private *private;
 248        struct subchannel *sch = NULL;
 249        int ret = -ENODEV;
 250        char dbf[10];
 251
 252        chsc_area->header.key = PAGE_DEFAULT_KEY >> 4;
 253        while ((sch = chsc_get_next_subchannel(sch))) {
 254                spin_lock(sch->lock);
 255                private = dev_get_drvdata(&sch->dev);
 256                if (private->request) {
 257                        spin_unlock(sch->lock);
 258                        ret = -EBUSY;
 259                        continue;
 260                }
 261                chsc_area->header.sid = sch->schid;
 262                CHSC_LOG(2, "schid");
 263                CHSC_LOG_HEX(2, &sch->schid, sizeof(sch->schid));
 264                cc = chsc(chsc_area);
 265                sprintf(dbf, "cc:%d", cc);
 266                CHSC_LOG(2, dbf);
 267                switch (cc) {
 268                case 0:
 269                        ret = 0;
 270                        break;
 271                case 1:
 272                        sch->schib.scsw.cmd.fctl |= SCSW_FCTL_START_FUNC;
 273                        ret = -EINPROGRESS;
 274                        private->request = request;
 275                        break;
 276                case 2:
 277                        ret = -EBUSY;
 278                        break;
 279                default:
 280                        ret = -ENODEV;
 281                }
 282                spin_unlock(sch->lock);
 283                CHSC_MSG(2, "chsc on 0.%x.%04x returned cc=%d\n",
 284                         sch->schid.ssid, sch->schid.sch_no, cc);
 285                if (ret == -EINPROGRESS)
 286                        return -EINPROGRESS;
 287                put_device(&sch->dev);
 288                if (ret == 0)
 289                        return 0;
 290        }
 291        return ret;
 292}
 293
 294static void chsc_log_command(void *chsc_area)
 295{
 296        char dbf[10];
 297
 298        sprintf(dbf, "CHSC:%x", ((uint16_t *)chsc_area)[1]);
 299        CHSC_LOG(0, dbf);
 300        CHSC_LOG_HEX(0, chsc_area, 32);
 301}
 302
 303static int chsc_examine_irb(struct chsc_request *request)
 304{
 305        int backed_up;
 306
 307        if (!(scsw_stctl(&request->irb.scsw) & SCSW_STCTL_STATUS_PEND))
 308                return -EIO;
 309        backed_up = scsw_cstat(&request->irb.scsw) & SCHN_STAT_CHAIN_CHECK;
 310        request->irb.scsw.cmd.cstat &= ~SCHN_STAT_CHAIN_CHECK;
 311        if (scsw_cstat(&request->irb.scsw) == 0)
 312                return 0;
 313        if (!backed_up)
 314                return 0;
 315        if (scsw_cstat(&request->irb.scsw) & SCHN_STAT_PROG_CHECK)
 316                return -EIO;
 317        if (scsw_cstat(&request->irb.scsw) & SCHN_STAT_PROT_CHECK)
 318                return -EPERM;
 319        if (scsw_cstat(&request->irb.scsw) & SCHN_STAT_CHN_DATA_CHK)
 320                return -EAGAIN;
 321        if (scsw_cstat(&request->irb.scsw) & SCHN_STAT_CHN_CTRL_CHK)
 322                return -EAGAIN;
 323        return -EIO;
 324}
 325
 326static int chsc_ioctl_start(void __user *user_area)
 327{
 328        struct chsc_request *request;
 329        struct chsc_async_area *chsc_area;
 330        int ret;
 331        char dbf[10];
 332
 333        if (!css_general_characteristics.dynio)
 334                /* It makes no sense to try. */
 335                return -EOPNOTSUPP;
 336        chsc_area = (void *)get_zeroed_page(GFP_DMA | GFP_KERNEL);
 337        if (!chsc_area)
 338                return -ENOMEM;
 339        request = kzalloc(sizeof(*request), GFP_KERNEL);
 340        if (!request) {
 341                ret = -ENOMEM;
 342                goto out_free;
 343        }
 344        init_completion(&request->completion);
 345        if (copy_from_user(chsc_area, user_area, PAGE_SIZE)) {
 346                ret = -EFAULT;
 347                goto out_free;
 348        }
 349        chsc_log_command(chsc_area);
 350        spin_lock_irq(&chsc_lock);
 351        ret = chsc_async(chsc_area, request);
 352        spin_unlock_irq(&chsc_lock);
 353        if (ret == -EINPROGRESS) {
 354                wait_for_completion(&request->completion);
 355                ret = chsc_examine_irb(request);
 356        }
 357        /* copy area back to user */
 358        if (!ret)
 359                if (copy_to_user(user_area, chsc_area, PAGE_SIZE))
 360                        ret = -EFAULT;
 361out_free:
 362        sprintf(dbf, "ret:%d", ret);
 363        CHSC_LOG(0, dbf);
 364        kfree(request);
 365        free_page((unsigned long)chsc_area);
 366        return ret;
 367}
 368
 369static int chsc_ioctl_on_close_set(void __user *user_area)
 370{
 371        char dbf[13];
 372        int ret;
 373
 374        mutex_lock(&on_close_mutex);
 375        if (on_close_chsc_area) {
 376                ret = -EBUSY;
 377                goto out_unlock;
 378        }
 379        on_close_request = kzalloc(sizeof(*on_close_request), GFP_KERNEL);
 380        if (!on_close_request) {
 381                ret = -ENOMEM;
 382                goto out_unlock;
 383        }
 384        on_close_chsc_area = (void *)get_zeroed_page(GFP_DMA | GFP_KERNEL);
 385        if (!on_close_chsc_area) {
 386                ret = -ENOMEM;
 387                goto out_free_request;
 388        }
 389        if (copy_from_user(on_close_chsc_area, user_area, PAGE_SIZE)) {
 390                ret = -EFAULT;
 391                goto out_free_chsc;
 392        }
 393        ret = 0;
 394        goto out_unlock;
 395
 396out_free_chsc:
 397        free_page((unsigned long)on_close_chsc_area);
 398        on_close_chsc_area = NULL;
 399out_free_request:
 400        kfree(on_close_request);
 401        on_close_request = NULL;
 402out_unlock:
 403        mutex_unlock(&on_close_mutex);
 404        sprintf(dbf, "ocsret:%d", ret);
 405        CHSC_LOG(0, dbf);
 406        return ret;
 407}
 408
 409static int chsc_ioctl_on_close_remove(void)
 410{
 411        char dbf[13];
 412        int ret;
 413
 414        mutex_lock(&on_close_mutex);
 415        if (!on_close_chsc_area) {
 416                ret = -ENOENT;
 417                goto out_unlock;
 418        }
 419        free_page((unsigned long)on_close_chsc_area);
 420        on_close_chsc_area = NULL;
 421        kfree(on_close_request);
 422        on_close_request = NULL;
 423        ret = 0;
 424out_unlock:
 425        mutex_unlock(&on_close_mutex);
 426        sprintf(dbf, "ocrret:%d", ret);
 427        CHSC_LOG(0, dbf);
 428        return ret;
 429}
 430
 431static int chsc_ioctl_start_sync(void __user *user_area)
 432{
 433        struct chsc_sync_area *chsc_area;
 434        int ret, ccode;
 435
 436        chsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
 437        if (!chsc_area)
 438                return -ENOMEM;
 439        if (copy_from_user(chsc_area, user_area, PAGE_SIZE)) {
 440                ret = -EFAULT;
 441                goto out_free;
 442        }
 443        if (chsc_area->header.code & 0x4000) {
 444                ret = -EINVAL;
 445                goto out_free;
 446        }
 447        chsc_log_command(chsc_area);
 448        ccode = chsc(chsc_area);
 449        if (ccode != 0) {
 450                ret = -EIO;
 451                goto out_free;
 452        }
 453        if (copy_to_user(user_area, chsc_area, PAGE_SIZE))
 454                ret = -EFAULT;
 455        else
 456                ret = 0;
 457out_free:
 458        free_page((unsigned long)chsc_area);
 459        return ret;
 460}
 461
 462static int chsc_ioctl_info_channel_path(void __user *user_cd)
 463{
 464        struct chsc_chp_cd *cd;
 465        int ret, ccode;
 466        struct {
 467                struct chsc_header request;
 468                u32 : 2;
 469                u32 m : 1;
 470                u32 : 1;
 471                u32 fmt1 : 4;
 472                u32 cssid : 8;
 473                u32 : 8;
 474                u32 first_chpid : 8;
 475                u32 : 24;
 476                u32 last_chpid : 8;
 477                u32 : 32;
 478                struct chsc_header response;
 479                u8 data[PAGE_SIZE - 20];
 480        } __attribute__ ((packed)) *scpcd_area;
 481
 482        scpcd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
 483        if (!scpcd_area)
 484                return -ENOMEM;
 485        cd = kzalloc(sizeof(*cd), GFP_KERNEL);
 486        if (!cd) {
 487                ret = -ENOMEM;
 488                goto out_free;
 489        }
 490        if (copy_from_user(cd, user_cd, sizeof(*cd))) {
 491                ret = -EFAULT;
 492                goto out_free;
 493        }
 494        scpcd_area->request.length = 0x0010;
 495        scpcd_area->request.code = 0x0028;
 496        scpcd_area->m = cd->m;
 497        scpcd_area->fmt1 = cd->fmt;
 498        scpcd_area->cssid = cd->chpid.cssid;
 499        scpcd_area->first_chpid = cd->chpid.id;
 500        scpcd_area->last_chpid = cd->chpid.id;
 501
 502        ccode = chsc(scpcd_area);
 503        if (ccode != 0) {
 504                ret = -EIO;
 505                goto out_free;
 506        }
 507        if (scpcd_area->response.code != 0x0001) {
 508                ret = -EIO;
 509                CHSC_MSG(0, "scpcd: response code=%x\n",
 510                         scpcd_area->response.code);
 511                goto out_free;
 512        }
 513        memcpy(&cd->cpcb, &scpcd_area->response, scpcd_area->response.length);
 514        if (copy_to_user(user_cd, cd, sizeof(*cd)))
 515                ret = -EFAULT;
 516        else
 517                ret = 0;
 518out_free:
 519        kfree(cd);
 520        free_page((unsigned long)scpcd_area);
 521        return ret;
 522}
 523
 524static int chsc_ioctl_info_cu(void __user *user_cd)
 525{
 526        struct chsc_cu_cd *cd;
 527        int ret, ccode;
 528        struct {
 529                struct chsc_header request;
 530                u32 : 2;
 531                u32 m : 1;
 532                u32 : 1;
 533                u32 fmt1 : 4;
 534                u32 cssid : 8;
 535                u32 : 8;
 536                u32 first_cun : 8;
 537                u32 : 24;
 538                u32 last_cun : 8;
 539                u32 : 32;
 540                struct chsc_header response;
 541                u8 data[PAGE_SIZE - 20];
 542        } __attribute__ ((packed)) *scucd_area;
 543
 544        scucd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
 545        if (!scucd_area)
 546                return -ENOMEM;
 547        cd = kzalloc(sizeof(*cd), GFP_KERNEL);
 548        if (!cd) {
 549                ret = -ENOMEM;
 550                goto out_free;
 551        }
 552        if (copy_from_user(cd, user_cd, sizeof(*cd))) {
 553                ret = -EFAULT;
 554                goto out_free;
 555        }
 556        scucd_area->request.length = 0x0010;
 557        scucd_area->request.code = 0x0028;
 558        scucd_area->m = cd->m;
 559        scucd_area->fmt1 = cd->fmt;
 560        scucd_area->cssid = cd->cssid;
 561        scucd_area->first_cun = cd->cun;
 562        scucd_area->last_cun = cd->cun;
 563
 564        ccode = chsc(scucd_area);
 565        if (ccode != 0) {
 566                ret = -EIO;
 567                goto out_free;
 568        }
 569        if (scucd_area->response.code != 0x0001) {
 570                ret = -EIO;
 571                CHSC_MSG(0, "scucd: response code=%x\n",
 572                         scucd_area->response.code);
 573                goto out_free;
 574        }
 575        memcpy(&cd->cucb, &scucd_area->response, scucd_area->response.length);
 576        if (copy_to_user(user_cd, cd, sizeof(*cd)))
 577                ret = -EFAULT;
 578        else
 579                ret = 0;
 580out_free:
 581        kfree(cd);
 582        free_page((unsigned long)scucd_area);
 583        return ret;
 584}
 585
 586static int chsc_ioctl_info_sch_cu(void __user *user_cud)
 587{
 588        struct chsc_sch_cud *cud;
 589        int ret, ccode;
 590        struct {
 591                struct chsc_header request;
 592                u32 : 2;
 593                u32 m : 1;
 594                u32 : 5;
 595                u32 fmt1 : 4;
 596                u32 : 2;
 597                u32 ssid : 2;
 598                u32 first_sch : 16;
 599                u32 : 8;
 600                u32 cssid : 8;
 601                u32 last_sch : 16;
 602                u32 : 32;
 603                struct chsc_header response;
 604                u8 data[PAGE_SIZE - 20];
 605        } __attribute__ ((packed)) *sscud_area;
 606
 607        sscud_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
 608        if (!sscud_area)
 609                return -ENOMEM;
 610        cud = kzalloc(sizeof(*cud), GFP_KERNEL);
 611        if (!cud) {
 612                ret = -ENOMEM;
 613                goto out_free;
 614        }
 615        if (copy_from_user(cud, user_cud, sizeof(*cud))) {
 616                ret = -EFAULT;
 617                goto out_free;
 618        }
 619        sscud_area->request.length = 0x0010;
 620        sscud_area->request.code = 0x0006;
 621        sscud_area->m = cud->schid.m;
 622        sscud_area->fmt1 = cud->fmt;
 623        sscud_area->ssid = cud->schid.ssid;
 624        sscud_area->first_sch = cud->schid.sch_no;
 625        sscud_area->cssid = cud->schid.cssid;
 626        sscud_area->last_sch = cud->schid.sch_no;
 627
 628        ccode = chsc(sscud_area);
 629        if (ccode != 0) {
 630                ret = -EIO;
 631                goto out_free;
 632        }
 633        if (sscud_area->response.code != 0x0001) {
 634                ret = -EIO;
 635                CHSC_MSG(0, "sscud: response code=%x\n",
 636                         sscud_area->response.code);
 637                goto out_free;
 638        }
 639        memcpy(&cud->scub, &sscud_area->response, sscud_area->response.length);
 640        if (copy_to_user(user_cud, cud, sizeof(*cud)))
 641                ret = -EFAULT;
 642        else
 643                ret = 0;
 644out_free:
 645        kfree(cud);
 646        free_page((unsigned long)sscud_area);
 647        return ret;
 648}
 649
 650static int chsc_ioctl_conf_info(void __user *user_ci)
 651{
 652        struct chsc_conf_info *ci;
 653        int ret, ccode;
 654        struct {
 655                struct chsc_header request;
 656                u32 : 2;
 657                u32 m : 1;
 658                u32 : 1;
 659                u32 fmt1 : 4;
 660                u32 cssid : 8;
 661                u32 : 6;
 662                u32 ssid : 2;
 663                u32 : 8;
 664                u64 : 64;
 665                struct chsc_header response;
 666                u8 data[PAGE_SIZE - 20];
 667        } __attribute__ ((packed)) *sci_area;
 668
 669        sci_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
 670        if (!sci_area)
 671                return -ENOMEM;
 672        ci = kzalloc(sizeof(*ci), GFP_KERNEL);
 673        if (!ci) {
 674                ret = -ENOMEM;
 675                goto out_free;
 676        }
 677        if (copy_from_user(ci, user_ci, sizeof(*ci))) {
 678                ret = -EFAULT;
 679                goto out_free;
 680        }
 681        sci_area->request.length = 0x0010;
 682        sci_area->request.code = 0x0012;
 683        sci_area->m = ci->id.m;
 684        sci_area->fmt1 = ci->fmt;
 685        sci_area->cssid = ci->id.cssid;
 686        sci_area->ssid = ci->id.ssid;
 687
 688        ccode = chsc(sci_area);
 689        if (ccode != 0) {
 690                ret = -EIO;
 691                goto out_free;
 692        }
 693        if (sci_area->response.code != 0x0001) {
 694                ret = -EIO;
 695                CHSC_MSG(0, "sci: response code=%x\n",
 696                         sci_area->response.code);
 697                goto out_free;
 698        }
 699        memcpy(&ci->scid, &sci_area->response, sci_area->response.length);
 700        if (copy_to_user(user_ci, ci, sizeof(*ci)))
 701                ret = -EFAULT;
 702        else
 703                ret = 0;
 704out_free:
 705        kfree(ci);
 706        free_page((unsigned long)sci_area);
 707        return ret;
 708}
 709
 710static int chsc_ioctl_conf_comp_list(void __user *user_ccl)
 711{
 712        struct chsc_comp_list *ccl;
 713        int ret, ccode;
 714        struct {
 715                struct chsc_header request;
 716                u32 ctype : 8;
 717                u32 : 4;
 718                u32 fmt : 4;
 719                u32 : 16;
 720                u64 : 64;
 721                u32 list_parm[2];
 722                u64 : 64;
 723                struct chsc_header response;
 724                u8 data[PAGE_SIZE - 36];
 725        } __attribute__ ((packed)) *sccl_area;
 726        struct {
 727                u32 m : 1;
 728                u32 : 31;
 729                u32 cssid : 8;
 730                u32 : 16;
 731                u32 chpid : 8;
 732        } __attribute__ ((packed)) *chpid_parm;
 733        struct {
 734                u32 f_cssid : 8;
 735                u32 l_cssid : 8;
 736                u32 : 16;
 737                u32 res;
 738        } __attribute__ ((packed)) *cssids_parm;
 739
 740        sccl_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
 741        if (!sccl_area)
 742                return -ENOMEM;
 743        ccl = kzalloc(sizeof(*ccl), GFP_KERNEL);
 744        if (!ccl) {
 745                ret = -ENOMEM;
 746                goto out_free;
 747        }
 748        if (copy_from_user(ccl, user_ccl, sizeof(*ccl))) {
 749                ret = -EFAULT;
 750                goto out_free;
 751        }
 752        sccl_area->request.length = 0x0020;
 753        sccl_area->request.code = 0x0030;
 754        sccl_area->fmt = ccl->req.fmt;
 755        sccl_area->ctype = ccl->req.ctype;
 756        switch (sccl_area->ctype) {
 757        case CCL_CU_ON_CHP:
 758        case CCL_IOP_CHP:
 759                chpid_parm = (void *)&sccl_area->list_parm;
 760                chpid_parm->m = ccl->req.chpid.m;
 761                chpid_parm->cssid = ccl->req.chpid.chp.cssid;
 762                chpid_parm->chpid = ccl->req.chpid.chp.id;
 763                break;
 764        case CCL_CSS_IMG:
 765        case CCL_CSS_IMG_CONF_CHAR:
 766                cssids_parm = (void *)&sccl_area->list_parm;
 767                cssids_parm->f_cssid = ccl->req.cssids.f_cssid;
 768                cssids_parm->l_cssid = ccl->req.cssids.l_cssid;
 769                break;
 770        }
 771        ccode = chsc(sccl_area);
 772        if (ccode != 0) {
 773                ret = -EIO;
 774                goto out_free;
 775        }
 776        if (sccl_area->response.code != 0x0001) {
 777                ret = -EIO;
 778                CHSC_MSG(0, "sccl: response code=%x\n",
 779                         sccl_area->response.code);
 780                goto out_free;
 781        }
 782        memcpy(&ccl->sccl, &sccl_area->response, sccl_area->response.length);
 783        if (copy_to_user(user_ccl, ccl, sizeof(*ccl)))
 784                ret = -EFAULT;
 785        else
 786                ret = 0;
 787out_free:
 788        kfree(ccl);
 789        free_page((unsigned long)sccl_area);
 790        return ret;
 791}
 792
 793static int chsc_ioctl_chpd(void __user *user_chpd)
 794{
 795        struct chsc_scpd *scpd_area;
 796        struct chsc_cpd_info *chpd;
 797        int ret;
 798
 799        chpd = kzalloc(sizeof(*chpd), GFP_KERNEL);
 800        scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
 801        if (!scpd_area || !chpd) {
 802                ret = -ENOMEM;
 803                goto out_free;
 804        }
 805        if (copy_from_user(chpd, user_chpd, sizeof(*chpd))) {
 806                ret = -EFAULT;
 807                goto out_free;
 808        }
 809        ret = chsc_determine_channel_path_desc(chpd->chpid, chpd->fmt,
 810                                               chpd->rfmt, chpd->c, chpd->m,
 811                                               scpd_area);
 812        if (ret)
 813                goto out_free;
 814        memcpy(&chpd->chpdb, &scpd_area->response, scpd_area->response.length);
 815        if (copy_to_user(user_chpd, chpd, sizeof(*chpd)))
 816                ret = -EFAULT;
 817out_free:
 818        kfree(chpd);
 819        free_page((unsigned long)scpd_area);
 820        return ret;
 821}
 822
 823static int chsc_ioctl_dcal(void __user *user_dcal)
 824{
 825        struct chsc_dcal *dcal;
 826        int ret, ccode;
 827        struct {
 828                struct chsc_header request;
 829                u32 atype : 8;
 830                u32 : 4;
 831                u32 fmt : 4;
 832                u32 : 16;
 833                u32 res0[2];
 834                u32 list_parm[2];
 835                u32 res1[2];
 836                struct chsc_header response;
 837                u8 data[PAGE_SIZE - 36];
 838        } __attribute__ ((packed)) *sdcal_area;
 839
 840        sdcal_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
 841        if (!sdcal_area)
 842                return -ENOMEM;
 843        dcal = kzalloc(sizeof(*dcal), GFP_KERNEL);
 844        if (!dcal) {
 845                ret = -ENOMEM;
 846                goto out_free;
 847        }
 848        if (copy_from_user(dcal, user_dcal, sizeof(*dcal))) {
 849                ret = -EFAULT;
 850                goto out_free;
 851        }
 852        sdcal_area->request.length = 0x0020;
 853        sdcal_area->request.code = 0x0034;
 854        sdcal_area->atype = dcal->req.atype;
 855        sdcal_area->fmt = dcal->req.fmt;
 856        memcpy(&sdcal_area->list_parm, &dcal->req.list_parm,
 857               sizeof(sdcal_area->list_parm));
 858
 859        ccode = chsc(sdcal_area);
 860        if (ccode != 0) {
 861                ret = -EIO;
 862                goto out_free;
 863        }
 864        if (sdcal_area->response.code != 0x0001) {
 865                ret = -EIO;
 866                CHSC_MSG(0, "sdcal: response code=%x\n",
 867                         sdcal_area->response.code);
 868                goto out_free;
 869        }
 870        memcpy(&dcal->sdcal, &sdcal_area->response,
 871               sdcal_area->response.length);
 872        if (copy_to_user(user_dcal, dcal, sizeof(*dcal)))
 873                ret = -EFAULT;
 874        else
 875                ret = 0;
 876out_free:
 877        kfree(dcal);
 878        free_page((unsigned long)sdcal_area);
 879        return ret;
 880}
 881
 882static long chsc_ioctl(struct file *filp, unsigned int cmd,
 883                       unsigned long arg)
 884{
 885        void __user *argp;
 886
 887        CHSC_MSG(2, "chsc_ioctl called, cmd=%x\n", cmd);
 888        if (is_compat_task())
 889                argp = compat_ptr(arg);
 890        else
 891                argp = (void __user *)arg;
 892        switch (cmd) {
 893        case CHSC_START:
 894                return chsc_ioctl_start(argp);
 895        case CHSC_START_SYNC:
 896                return chsc_ioctl_start_sync(argp);
 897        case CHSC_INFO_CHANNEL_PATH:
 898                return chsc_ioctl_info_channel_path(argp);
 899        case CHSC_INFO_CU:
 900                return chsc_ioctl_info_cu(argp);
 901        case CHSC_INFO_SCH_CU:
 902                return chsc_ioctl_info_sch_cu(argp);
 903        case CHSC_INFO_CI:
 904                return chsc_ioctl_conf_info(argp);
 905        case CHSC_INFO_CCL:
 906                return chsc_ioctl_conf_comp_list(argp);
 907        case CHSC_INFO_CPD:
 908                return chsc_ioctl_chpd(argp);
 909        case CHSC_INFO_DCAL:
 910                return chsc_ioctl_dcal(argp);
 911        case CHSC_ON_CLOSE_SET:
 912                return chsc_ioctl_on_close_set(argp);
 913        case CHSC_ON_CLOSE_REMOVE:
 914                return chsc_ioctl_on_close_remove();
 915        default: /* unknown ioctl number */
 916                return -ENOIOCTLCMD;
 917        }
 918}
 919
 920static atomic_t chsc_ready_for_use = ATOMIC_INIT(1);
 921
 922static int chsc_open(struct inode *inode, struct file *file)
 923{
 924        if (!atomic_dec_and_test(&chsc_ready_for_use)) {
 925                atomic_inc(&chsc_ready_for_use);
 926                return -EBUSY;
 927        }
 928        return nonseekable_open(inode, file);
 929}
 930
 931static int chsc_release(struct inode *inode, struct file *filp)
 932{
 933        char dbf[13];
 934        int ret;
 935
 936        mutex_lock(&on_close_mutex);
 937        if (!on_close_chsc_area)
 938                goto out_unlock;
 939        init_completion(&on_close_request->completion);
 940        CHSC_LOG(0, "on_close");
 941        chsc_log_command(on_close_chsc_area);
 942        spin_lock_irq(&chsc_lock);
 943        ret = chsc_async(on_close_chsc_area, on_close_request);
 944        spin_unlock_irq(&chsc_lock);
 945        if (ret == -EINPROGRESS) {
 946                wait_for_completion(&on_close_request->completion);
 947                ret = chsc_examine_irb(on_close_request);
 948        }
 949        sprintf(dbf, "relret:%d", ret);
 950        CHSC_LOG(0, dbf);
 951        free_page((unsigned long)on_close_chsc_area);
 952        on_close_chsc_area = NULL;
 953        kfree(on_close_request);
 954        on_close_request = NULL;
 955out_unlock:
 956        mutex_unlock(&on_close_mutex);
 957        atomic_inc(&chsc_ready_for_use);
 958        return 0;
 959}
 960
 961static const struct file_operations chsc_fops = {
 962        .owner = THIS_MODULE,
 963        .open = chsc_open,
 964        .release = chsc_release,
 965        .unlocked_ioctl = chsc_ioctl,
 966        .compat_ioctl = chsc_ioctl,
 967        .llseek = no_llseek,
 968};
 969
 970static struct miscdevice chsc_misc_device = {
 971        .minor = MISC_DYNAMIC_MINOR,
 972        .name = "chsc",
 973        .fops = &chsc_fops,
 974};
 975
 976static int __init chsc_misc_init(void)
 977{
 978        return misc_register(&chsc_misc_device);
 979}
 980
 981static void chsc_misc_cleanup(void)
 982{
 983        misc_deregister(&chsc_misc_device);
 984}
 985
 986static int __init chsc_sch_init(void)
 987{
 988        int ret;
 989
 990        ret = chsc_init_dbfs();
 991        if (ret)
 992                return ret;
 993        isc_register(CHSC_SCH_ISC);
 994        ret = chsc_init_sch_driver();
 995        if (ret)
 996                goto out_dbf;
 997        ret = chsc_misc_init();
 998        if (ret)
 999                goto out_driver;
1000        return ret;
1001out_driver:
1002        chsc_cleanup_sch_driver();
1003out_dbf:
1004        isc_unregister(CHSC_SCH_ISC);
1005        chsc_remove_dbfs();
1006        return ret;
1007}
1008
1009static void __exit chsc_sch_exit(void)
1010{
1011        chsc_misc_cleanup();
1012        chsc_cleanup_sch_driver();
1013        isc_unregister(CHSC_SCH_ISC);
1014        chsc_remove_dbfs();
1015}
1016
1017module_init(chsc_sch_init);
1018module_exit(chsc_sch_exit);
1019