diff options
Diffstat (limited to 'drivers/s390/char/sclp_cmd.c')
-rw-r--r-- | drivers/s390/char/sclp_cmd.c | 123 |
1 files changed, 122 insertions, 1 deletions
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index ba004fd43c05..d7e6f4d65b78 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c | |||
@@ -2,7 +2,8 @@ | |||
2 | * drivers/s390/char/sclp_cmd.c | 2 | * drivers/s390/char/sclp_cmd.c |
3 | * | 3 | * |
4 | * Copyright IBM Corp. 2007 | 4 | * Copyright IBM Corp. 2007 |
5 | * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> | 5 | * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>, |
6 | * Peter Oberparleiter <peter.oberparleiter@de.ibm.com> | ||
6 | */ | 7 | */ |
7 | 8 | ||
8 | #include <linux/completion.h> | 9 | #include <linux/completion.h> |
@@ -10,6 +11,7 @@ | |||
10 | #include <linux/errno.h> | 11 | #include <linux/errno.h> |
11 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
12 | #include <linux/string.h> | 13 | #include <linux/string.h> |
14 | #include <asm/chpid.h> | ||
13 | #include <asm/sclp.h> | 15 | #include <asm/sclp.h> |
14 | #include "sclp.h" | 16 | #include "sclp.h" |
15 | 17 | ||
@@ -317,3 +319,122 @@ int sclp_cpu_deconfigure(u8 cpu) | |||
317 | { | 319 | { |
318 | return do_cpu_configure(SCLP_CMDW_DECONFIGURE_CPU | cpu << 8); | 320 | return do_cpu_configure(SCLP_CMDW_DECONFIGURE_CPU | cpu << 8); |
319 | } | 321 | } |
322 | |||
323 | /* | ||
324 | * Channel path configuration related functions. | ||
325 | */ | ||
326 | |||
327 | #define SCLP_CMDW_CONFIGURE_CHPATH 0x000f0001 | ||
328 | #define SCLP_CMDW_DECONFIGURE_CHPATH 0x000e0001 | ||
329 | #define SCLP_CMDW_READ_CHPATH_INFORMATION 0x00030001 | ||
330 | |||
331 | struct chp_cfg_sccb { | ||
332 | struct sccb_header header; | ||
333 | u8 ccm; | ||
334 | u8 reserved[6]; | ||
335 | u8 cssid; | ||
336 | } __attribute__((packed)); | ||
337 | |||
338 | static int do_chp_configure(sclp_cmdw_t cmd) | ||
339 | { | ||
340 | struct chp_cfg_sccb *sccb; | ||
341 | int rc; | ||
342 | |||
343 | if (!SCLP_HAS_CHP_RECONFIG) | ||
344 | return -EOPNOTSUPP; | ||
345 | /* Prepare sccb. */ | ||
346 | sccb = (struct chp_cfg_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA); | ||
347 | if (!sccb) | ||
348 | return -ENOMEM; | ||
349 | sccb->header.length = sizeof(*sccb); | ||
350 | rc = do_sync_request(cmd, sccb); | ||
351 | if (rc) | ||
352 | goto out; | ||
353 | switch (sccb->header.response_code) { | ||
354 | case 0x0020: | ||
355 | case 0x0120: | ||
356 | case 0x0440: | ||
357 | case 0x0450: | ||
358 | break; | ||
359 | default: | ||
360 | printk(KERN_WARNING TAG "configure channel-path failed " | ||
361 | "(cmd=0x%08x, response=0x%04x)\n", cmd, | ||
362 | sccb->header.response_code); | ||
363 | rc = -EIO; | ||
364 | break; | ||
365 | } | ||
366 | out: | ||
367 | free_page((unsigned long) sccb); | ||
368 | return rc; | ||
369 | } | ||
370 | |||
371 | /** | ||
372 | * sclp_chp_configure - perform configure channel-path sclp command | ||
373 | * @chpid: channel-path ID | ||
374 | * | ||
375 | * Perform configure channel-path command sclp command for specified chpid. | ||
376 | * Return 0 after command successfully finished, non-zero otherwise. | ||
377 | */ | ||
378 | int sclp_chp_configure(struct chp_id chpid) | ||
379 | { | ||
380 | return do_chp_configure(SCLP_CMDW_CONFIGURE_CHPATH | chpid.id << 8); | ||
381 | } | ||
382 | |||
383 | /** | ||
384 | * sclp_chp_deconfigure - perform deconfigure channel-path sclp command | ||
385 | * @chpid: channel-path ID | ||
386 | * | ||
387 | * Perform deconfigure channel-path command sclp command for specified chpid | ||
388 | * and wait for completion. On success return 0. Return non-zero otherwise. | ||
389 | */ | ||
390 | int sclp_chp_deconfigure(struct chp_id chpid) | ||
391 | { | ||
392 | return do_chp_configure(SCLP_CMDW_DECONFIGURE_CHPATH | chpid.id << 8); | ||
393 | } | ||
394 | |||
395 | struct chp_info_sccb { | ||
396 | struct sccb_header header; | ||
397 | u8 recognized[SCLP_CHP_INFO_MASK_SIZE]; | ||
398 | u8 standby[SCLP_CHP_INFO_MASK_SIZE]; | ||
399 | u8 configured[SCLP_CHP_INFO_MASK_SIZE]; | ||
400 | u8 ccm; | ||
401 | u8 reserved[6]; | ||
402 | u8 cssid; | ||
403 | } __attribute__((packed)); | ||
404 | |||
405 | /** | ||
406 | * sclp_chp_read_info - perform read channel-path information sclp command | ||
407 | * @info: resulting channel-path information data | ||
408 | * | ||
409 | * Perform read channel-path information sclp command and wait for completion. | ||
410 | * On success, store channel-path information in @info and return 0. Return | ||
411 | * non-zero otherwise. | ||
412 | */ | ||
413 | int sclp_chp_read_info(struct sclp_chp_info *info) | ||
414 | { | ||
415 | struct chp_info_sccb *sccb; | ||
416 | int rc; | ||
417 | |||
418 | if (!SCLP_HAS_CHP_INFO) | ||
419 | return -EOPNOTSUPP; | ||
420 | /* Prepare sccb. */ | ||
421 | sccb = (struct chp_info_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA); | ||
422 | if (!sccb) | ||
423 | return -ENOMEM; | ||
424 | sccb->header.length = sizeof(*sccb); | ||
425 | rc = do_sync_request(SCLP_CMDW_READ_CHPATH_INFORMATION, sccb); | ||
426 | if (rc) | ||
427 | goto out; | ||
428 | if (sccb->header.response_code != 0x0010) { | ||
429 | printk(KERN_WARNING TAG "read channel-path info failed " | ||
430 | "(response=0x%04x)\n", sccb->header.response_code); | ||
431 | rc = -EIO; | ||
432 | goto out; | ||
433 | } | ||
434 | memcpy(info->recognized, sccb->recognized, SCLP_CHP_INFO_MASK_SIZE); | ||
435 | memcpy(info->standby, sccb->standby, SCLP_CHP_INFO_MASK_SIZE); | ||
436 | memcpy(info->configured, sccb->configured, SCLP_CHP_INFO_MASK_SIZE); | ||
437 | out: | ||
438 | free_page((unsigned long) sccb); | ||
439 | return rc; | ||
440 | } | ||