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