aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio/chp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/cio/chp.c')
-rw-r--r--drivers/s390/cio/chp.c116
1 files changed, 86 insertions, 30 deletions
diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c
index 297cdceb0ca4..db00b0591733 100644
--- a/drivers/s390/cio/chp.c
+++ b/drivers/s390/cio/chp.c
@@ -18,6 +18,7 @@
18#include <asm/chpid.h> 18#include <asm/chpid.h>
19#include <asm/sclp.h> 19#include <asm/sclp.h>
20 20
21#include "../s390mach.h"
21#include "cio.h" 22#include "cio.h"
22#include "css.h" 23#include "css.h"
23#include "ioasm.h" 24#include "ioasm.h"
@@ -94,6 +95,7 @@ u8 chp_get_sch_opm(struct subchannel *sch)
94 } 95 }
95 return opm; 96 return opm;
96} 97}
98EXPORT_SYMBOL_GPL(chp_get_sch_opm);
97 99
98/** 100/**
99 * chp_is_registered - check if a channel-path is registered 101 * chp_is_registered - check if a channel-path is registered
@@ -121,11 +123,8 @@ static int s390_vary_chpid(struct chp_id chpid, int on)
121 CIO_TRACE_EVENT(2, dbf_text); 123 CIO_TRACE_EVENT(2, dbf_text);
122 124
123 status = chp_get_status(chpid); 125 status = chp_get_status(chpid);
124 if (!on && !status) { 126 if (!on && !status)
125 printk(KERN_ERR "cio: chpid %x.%02x is already offline\n", 127 return 0;
126 chpid.cssid, chpid.id);
127 return -EINVAL;
128 }
129 128
130 set_chp_logically_online(chpid, on); 129 set_chp_logically_online(chpid, on);
131 chsc_chp_vary(chpid, on); 130 chsc_chp_vary(chpid, on);
@@ -141,21 +140,14 @@ static ssize_t chp_measurement_chars_read(struct kobject *kobj,
141{ 140{
142 struct channel_path *chp; 141 struct channel_path *chp;
143 struct device *device; 142 struct device *device;
144 unsigned int size;
145 143
146 device = container_of(kobj, struct device, kobj); 144 device = container_of(kobj, struct device, kobj);
147 chp = to_channelpath(device); 145 chp = to_channelpath(device);
148 if (!chp->cmg_chars) 146 if (!chp->cmg_chars)
149 return 0; 147 return 0;
150 148
151 size = sizeof(struct cmg_chars); 149 return memory_read_from_buffer(buf, count, &off,
152 150 chp->cmg_chars, sizeof(struct cmg_chars));
153 if (off > size)
154 return 0;
155 if (off + count > size)
156 count = size - off;
157 memcpy(buf, chp->cmg_chars + off, count);
158 return count;
159} 151}
160 152
161static struct bin_attribute chp_measurement_chars_attr = { 153static struct bin_attribute chp_measurement_chars_attr = {
@@ -405,7 +397,7 @@ int chp_new(struct chp_id chpid)
405 chpid.id); 397 chpid.id);
406 398
407 /* Obtain channel path description and fill it in. */ 399 /* Obtain channel path description and fill it in. */
408 ret = chsc_determine_channel_path_description(chpid, &chp->desc); 400 ret = chsc_determine_base_channel_path_desc(chpid, &chp->desc);
409 if (ret) 401 if (ret)
410 goto out_free; 402 goto out_free;
411 if ((chp->desc.flags & 0x80) == 0) { 403 if ((chp->desc.flags & 0x80) == 0) {
@@ -413,8 +405,7 @@ int chp_new(struct chp_id chpid)
413 goto out_free; 405 goto out_free;
414 } 406 }
415 /* Get channel-measurement characteristics. */ 407 /* Get channel-measurement characteristics. */
416 if (css_characteristics_avail && css_chsc_characteristics.scmc 408 if (css_chsc_characteristics.scmc && css_chsc_characteristics.secm) {
417 && css_chsc_characteristics.secm) {
418 ret = chsc_get_channel_measurement_chars(chp); 409 ret = chsc_get_channel_measurement_chars(chp);
419 if (ret) 410 if (ret)
420 goto out_free; 411 goto out_free;
@@ -476,26 +467,74 @@ void *chp_get_chp_desc(struct chp_id chpid)
476 467
477/** 468/**
478 * chp_process_crw - process channel-path status change 469 * chp_process_crw - process channel-path status change
479 * @id: channel-path ID number 470 * @crw0: channel report-word to handler
480 * @status: non-zero if channel-path has become available, zero otherwise 471 * @crw1: second channel-report word (always NULL)
472 * @overflow: crw overflow indication
481 * 473 *
482 * Handle channel-report-words indicating that the status of a channel-path 474 * Handle channel-report-words indicating that the status of a channel-path
483 * has changed. 475 * has changed.
484 */ 476 */
485void chp_process_crw(int id, int status) 477static void chp_process_crw(struct crw *crw0, struct crw *crw1,
478 int overflow)
486{ 479{
487 struct chp_id chpid; 480 struct chp_id chpid;
488 481
482 if (overflow) {
483 css_schedule_eval_all();
484 return;
485 }
486 CIO_CRW_EVENT(2, "CRW reports slct=%d, oflw=%d, "
487 "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
488 crw0->slct, crw0->oflw, crw0->chn, crw0->rsc, crw0->anc,
489 crw0->erc, crw0->rsid);
490 /*
491 * Check for solicited machine checks. These are
492 * created by reset channel path and need not be
493 * handled here.
494 */
495 if (crw0->slct) {
496 CIO_CRW_EVENT(2, "solicited machine check for "
497 "channel path %02X\n", crw0->rsid);
498 return;
499 }
489 chp_id_init(&chpid); 500 chp_id_init(&chpid);
490 chpid.id = id; 501 chpid.id = crw0->rsid;
491 if (status) { 502 switch (crw0->erc) {
503 case CRW_ERC_IPARM: /* Path has come. */
492 if (!chp_is_registered(chpid)) 504 if (!chp_is_registered(chpid))
493 chp_new(chpid); 505 chp_new(chpid);
494 chsc_chp_online(chpid); 506 chsc_chp_online(chpid);
495 } else 507 break;
508 case CRW_ERC_PERRI: /* Path has gone. */
509 case CRW_ERC_PERRN:
496 chsc_chp_offline(chpid); 510 chsc_chp_offline(chpid);
511 break;
512 default:
513 CIO_CRW_EVENT(2, "Don't know how to handle erc=%x\n",
514 crw0->erc);
515 }
497} 516}
498 517
518int chp_ssd_get_mask(struct chsc_ssd_info *ssd, struct chp_link *link)
519{
520 int i;
521 int mask;
522
523 for (i = 0; i < 8; i++) {
524 mask = 0x80 >> i;
525 if (!(ssd->path_mask & mask))
526 continue;
527 if (!chp_id_is_equal(&ssd->chpid[i], &link->chpid))
528 continue;
529 if ((ssd->fla_valid_mask & mask) &&
530 ((ssd->fla[i] & link->fla_mask) != link->fla))
531 continue;
532 return mask;
533 }
534 return 0;
535}
536EXPORT_SYMBOL_GPL(chp_ssd_get_mask);
537
499static inline int info_bit_num(struct chp_id id) 538static inline int info_bit_num(struct chp_id id)
500{ 539{
501 return id.id + id.cssid * (__MAX_CHPID + 1); 540 return id.id + id.cssid * (__MAX_CHPID + 1);
@@ -575,6 +614,7 @@ static void cfg_func(struct work_struct *work)
575{ 614{
576 struct chp_id chpid; 615 struct chp_id chpid;
577 enum cfg_task_t t; 616 enum cfg_task_t t;
617 int rc;
578 618
579 mutex_lock(&cfg_lock); 619 mutex_lock(&cfg_lock);
580 t = cfg_none; 620 t = cfg_none;
@@ -589,14 +629,24 @@ static void cfg_func(struct work_struct *work)
589 629
590 switch (t) { 630 switch (t) {
591 case cfg_configure: 631 case cfg_configure:
592 sclp_chp_configure(chpid); 632 rc = sclp_chp_configure(chpid);
593 info_expire(); 633 if (rc)
594 chsc_chp_online(chpid); 634 CIO_MSG_EVENT(2, "chp: sclp_chp_configure(%x.%02x)="
635 "%d\n", chpid.cssid, chpid.id, rc);
636 else {
637 info_expire();
638 chsc_chp_online(chpid);
639 }
595 break; 640 break;
596 case cfg_deconfigure: 641 case cfg_deconfigure:
597 sclp_chp_deconfigure(chpid); 642 rc = sclp_chp_deconfigure(chpid);
598 info_expire(); 643 if (rc)
599 chsc_chp_offline(chpid); 644 CIO_MSG_EVENT(2, "chp: sclp_chp_deconfigure(%x.%02x)="
645 "%d\n", chpid.cssid, chpid.id, rc);
646 else {
647 info_expire();
648 chsc_chp_offline(chpid);
649 }
600 break; 650 break;
601 case cfg_none: 651 case cfg_none:
602 /* Get updated information after last change. */ 652 /* Get updated information after last change. */
@@ -654,10 +704,16 @@ static int cfg_wait_idle(void)
654static int __init chp_init(void) 704static int __init chp_init(void)
655{ 705{
656 struct chp_id chpid; 706 struct chp_id chpid;
707 int ret;
657 708
709 ret = s390_register_crw_handler(CRW_RSC_CPATH, chp_process_crw);
710 if (ret)
711 return ret;
658 chp_wq = create_singlethread_workqueue("cio_chp"); 712 chp_wq = create_singlethread_workqueue("cio_chp");
659 if (!chp_wq) 713 if (!chp_wq) {
714 s390_unregister_crw_handler(CRW_RSC_CPATH);
660 return -ENOMEM; 715 return -ENOMEM;
716 }
661 INIT_WORK(&cfg_work, cfg_func); 717 INIT_WORK(&cfg_work, cfg_func);
662 init_waitqueue_head(&cfg_wait_queue); 718 init_waitqueue_head(&cfg_wait_queue);
663 if (info_update()) 719 if (info_update())