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