aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio/chsc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/cio/chsc.c')
-rw-r--r--drivers/s390/cio/chsc.c156
1 files changed, 112 insertions, 44 deletions
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index 4d51a7c4eb8b..68e80e2734a4 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * S/390 common I/O routines -- channel subsystem call 2 * S/390 common I/O routines -- channel subsystem call
3 * 3 *
4 * Copyright IBM Corp. 1999, 2010 4 * Copyright IBM Corp. 1999,2012
5 * Author(s): Ingo Adlung (adlung@de.ibm.com) 5 * Author(s): Ingo Adlung (adlung@de.ibm.com)
6 * Cornelia Huck (cornelia.huck@de.ibm.com) 6 * Cornelia Huck (cornelia.huck@de.ibm.com)
7 * Arnd Bergmann (arndb@de.ibm.com) 7 * Arnd Bergmann (arndb@de.ibm.com)
@@ -14,6 +14,7 @@
14#include <linux/slab.h> 14#include <linux/slab.h>
15#include <linux/init.h> 15#include <linux/init.h>
16#include <linux/device.h> 16#include <linux/device.h>
17#include <linux/pci.h>
17 18
18#include <asm/cio.h> 19#include <asm/cio.h>
19#include <asm/chpid.h> 20#include <asm/chpid.h>
@@ -260,26 +261,45 @@ __get_chpid_from_lir(void *data)
260 return (u16) (lir->indesc[0]&0x000000ff); 261 return (u16) (lir->indesc[0]&0x000000ff);
261} 262}
262 263
263struct chsc_sei_area { 264struct chsc_sei_nt0_area {
264 struct chsc_header request; 265 u8 flags;
266 u8 vf; /* validity flags */
267 u8 rs; /* reporting source */
268 u8 cc; /* content code */
269 u16 fla; /* full link address */
270 u16 rsid; /* reporting source id */
265 u32 reserved1; 271 u32 reserved1;
266 u32 reserved2; 272 u32 reserved2;
267 u32 reserved3;
268 struct chsc_header response;
269 u32 reserved4;
270 u8 flags;
271 u8 vf; /* validity flags */
272 u8 rs; /* reporting source */
273 u8 cc; /* content code */
274 u16 fla; /* full link address */
275 u16 rsid; /* reporting source id */
276 u32 reserved5;
277 u32 reserved6;
278 u8 ccdf[4096 - 16 - 24]; /* content-code dependent field */
279 /* ccdf has to be big enough for a link-incident record */ 273 /* ccdf has to be big enough for a link-incident record */
280} __attribute__ ((packed)); 274 u8 ccdf[PAGE_SIZE - 24 - 16]; /* content-code dependent field */
281 275} __packed;
282static void chsc_process_sei_link_incident(struct chsc_sei_area *sei_area) 276
277struct chsc_sei_nt2_area {
278 u8 flags; /* p and v bit */
279 u8 reserved1;
280 u8 reserved2;
281 u8 cc; /* content code */
282 u32 reserved3[13];
283 u8 ccdf[PAGE_SIZE - 24 - 56]; /* content-code dependent field */
284} __packed;
285
286#define CHSC_SEI_NT0 0ULL
287#define CHSC_SEI_NT2 (1ULL << 61)
288
289struct chsc_sei {
290 struct chsc_header request;
291 u32 reserved1;
292 u64 ntsm; /* notification type mask */
293 struct chsc_header response;
294 u32 reserved2;
295 union {
296 struct chsc_sei_nt0_area nt0_area;
297 struct chsc_sei_nt2_area nt2_area;
298 u8 nt_area[PAGE_SIZE - 24];
299 } u;
300} __packed;
301
302static void chsc_process_sei_link_incident(struct chsc_sei_nt0_area *sei_area)
283{ 303{
284 struct chp_id chpid; 304 struct chp_id chpid;
285 int id; 305 int id;
@@ -298,7 +318,7 @@ static void chsc_process_sei_link_incident(struct chsc_sei_area *sei_area)
298 } 318 }
299} 319}
300 320
301static void chsc_process_sei_res_acc(struct chsc_sei_area *sei_area) 321static void chsc_process_sei_res_acc(struct chsc_sei_nt0_area *sei_area)
302{ 322{
303 struct chp_link link; 323 struct chp_link link;
304 struct chp_id chpid; 324 struct chp_id chpid;
@@ -330,7 +350,7 @@ static void chsc_process_sei_res_acc(struct chsc_sei_area *sei_area)
330 s390_process_res_acc(&link); 350 s390_process_res_acc(&link);
331} 351}
332 352
333static void chsc_process_sei_chp_avail(struct chsc_sei_area *sei_area) 353static void chsc_process_sei_chp_avail(struct chsc_sei_nt0_area *sei_area)
334{ 354{
335 struct channel_path *chp; 355 struct channel_path *chp;
336 struct chp_id chpid; 356 struct chp_id chpid;
@@ -366,7 +386,7 @@ struct chp_config_data {
366 u8 pc; 386 u8 pc;
367}; 387};
368 388
369static void chsc_process_sei_chp_config(struct chsc_sei_area *sei_area) 389static void chsc_process_sei_chp_config(struct chsc_sei_nt0_area *sei_area)
370{ 390{
371 struct chp_config_data *data; 391 struct chp_config_data *data;
372 struct chp_id chpid; 392 struct chp_id chpid;
@@ -398,7 +418,7 @@ static void chsc_process_sei_chp_config(struct chsc_sei_area *sei_area)
398 } 418 }
399} 419}
400 420
401static void chsc_process_sei_scm_change(struct chsc_sei_area *sei_area) 421static void chsc_process_sei_scm_change(struct chsc_sei_nt0_area *sei_area)
402{ 422{
403 int ret; 423 int ret;
404 424
@@ -412,13 +432,26 @@ static void chsc_process_sei_scm_change(struct chsc_sei_area *sei_area)
412 " failed (rc=%d).\n", ret); 432 " failed (rc=%d).\n", ret);
413} 433}
414 434
415static void chsc_process_sei(struct chsc_sei_area *sei_area) 435static void chsc_process_sei_nt2(struct chsc_sei_nt2_area *sei_area)
416{ 436{
417 /* Check if we might have lost some information. */ 437#ifdef CONFIG_PCI
418 if (sei_area->flags & 0x40) { 438 switch (sei_area->cc) {
419 CIO_CRW_EVENT(2, "chsc: event overflow\n"); 439 case 1:
420 css_schedule_eval_all(); 440 zpci_event_error(sei_area->ccdf);
441 break;
442 case 2:
443 zpci_event_availability(sei_area->ccdf);
444 break;
445 default:
446 CIO_CRW_EVENT(2, "chsc: unhandled sei content code %d\n",
447 sei_area->cc);
448 break;
421 } 449 }
450#endif
451}
452
453static void chsc_process_sei_nt0(struct chsc_sei_nt0_area *sei_area)
454{
422 /* which kind of information was stored? */ 455 /* which kind of information was stored? */
423 switch (sei_area->cc) { 456 switch (sei_area->cc) {
424 case 1: /* link incident*/ 457 case 1: /* link incident*/
@@ -443,9 +476,51 @@ static void chsc_process_sei(struct chsc_sei_area *sei_area)
443 } 476 }
444} 477}
445 478
479static int __chsc_process_crw(struct chsc_sei *sei, u64 ntsm)
480{
481 do {
482 memset(sei, 0, sizeof(*sei));
483 sei->request.length = 0x0010;
484 sei->request.code = 0x000e;
485 sei->ntsm = ntsm;
486
487 if (chsc(sei))
488 break;
489
490 if (sei->response.code == 0x0001) {
491 CIO_CRW_EVENT(2, "chsc: sei successful\n");
492
493 /* Check if we might have lost some information. */
494 if (sei->u.nt0_area.flags & 0x40) {
495 CIO_CRW_EVENT(2, "chsc: event overflow\n");
496 css_schedule_eval_all();
497 }
498
499 switch (sei->ntsm) {
500 case CHSC_SEI_NT0:
501 chsc_process_sei_nt0(&sei->u.nt0_area);
502 return 1;
503 case CHSC_SEI_NT2:
504 chsc_process_sei_nt2(&sei->u.nt2_area);
505 return 1;
506 default:
507 CIO_CRW_EVENT(2, "chsc: unhandled nt (nt=%08Lx)\n",
508 sei->ntsm);
509 return 0;
510 }
511 } else {
512 CIO_CRW_EVENT(2, "chsc: sei failed (rc=%04x)\n",
513 sei->response.code);
514 break;
515 }
516 } while (sei->u.nt0_area.flags & 0x80);
517
518 return 0;
519}
520
446static void chsc_process_crw(struct crw *crw0, struct crw *crw1, int overflow) 521static void chsc_process_crw(struct crw *crw0, struct crw *crw1, int overflow)
447{ 522{
448 struct chsc_sei_area *sei_area; 523 struct chsc_sei *sei;
449 524
450 if (overflow) { 525 if (overflow) {
451 css_schedule_eval_all(); 526 css_schedule_eval_all();
@@ -459,25 +534,18 @@ static void chsc_process_crw(struct crw *crw0, struct crw *crw1, int overflow)
459 return; 534 return;
460 /* Access to sei_page is serialized through machine check handler 535 /* Access to sei_page is serialized through machine check handler
461 * thread, so no need for locking. */ 536 * thread, so no need for locking. */
462 sei_area = sei_page; 537 sei = sei_page;
463 538
464 CIO_TRACE_EVENT(2, "prcss"); 539 CIO_TRACE_EVENT(2, "prcss");
465 do {
466 memset(sei_area, 0, sizeof(*sei_area));
467 sei_area->request.length = 0x0010;
468 sei_area->request.code = 0x000e;
469 if (chsc(sei_area))
470 break;
471 540
472 if (sei_area->response.code == 0x0001) { 541 /*
473 CIO_CRW_EVENT(4, "chsc: sei successful\n"); 542 * The ntsm does not allow to select NT0 and NT2 together. We need to
474 chsc_process_sei(sei_area); 543 * first check for NT2, than additionally for NT0...
475 } else { 544 */
476 CIO_CRW_EVENT(2, "chsc: sei failed (rc=%04x)\n", 545#ifdef CONFIG_PCI
477 sei_area->response.code); 546 if (!__chsc_process_crw(sei, CHSC_SEI_NT2))
478 break; 547#endif
479 } 548 __chsc_process_crw(sei, CHSC_SEI_NT0);
480 } while (sei_area->flags & 0x80);
481} 549}
482 550
483void chsc_chp_online(struct chp_id chpid) 551void chsc_chp_online(struct chp_id chpid)