root/drivers/s390/cio/chsc_sch.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. CHSC_LOG_HEX
  2. chsc_subchannel_irq
  3. chsc_subchannel_probe
  4. chsc_subchannel_remove
  5. chsc_subchannel_shutdown
  6. chsc_subchannel_prepare
  7. chsc_subchannel_freeze
  8. chsc_subchannel_restore
  9. chsc_init_dbfs
  10. chsc_remove_dbfs
  11. chsc_init_sch_driver
  12. chsc_cleanup_sch_driver
  13. chsc_subchannel_match_next_free
  14. chsc_get_next_subchannel
  15. chsc_async
  16. chsc_log_command
  17. chsc_examine_irb
  18. chsc_ioctl_start
  19. chsc_ioctl_on_close_set
  20. chsc_ioctl_on_close_remove
  21. chsc_ioctl_start_sync
  22. chsc_ioctl_info_channel_path
  23. chsc_ioctl_info_cu
  24. chsc_ioctl_info_sch_cu
  25. chsc_ioctl_conf_info
  26. chsc_ioctl_conf_comp_list
  27. chsc_ioctl_chpd
  28. chsc_ioctl_dcal
  29. chsc_ioctl
  30. chsc_open
  31. chsc_release
  32. chsc_misc_init
  33. chsc_misc_cleanup
  34. chsc_sch_init
  35. chsc_sch_exit

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

/* [<][>][^][v][top][bottom][index][help] */