sclp_chp.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. /*
  2. * drivers/s390/char/sclp_chp.c
  3. *
  4. * Copyright IBM Corp. 2007
  5. * Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
  6. */
  7. #include <linux/types.h>
  8. #include <linux/gfp.h>
  9. #include <linux/errno.h>
  10. #include <linux/completion.h>
  11. #include <asm/sclp.h>
  12. #include <asm/chpid.h>
  13. #include "sclp.h"
  14. #define TAG "sclp_chp: "
  15. #define SCLP_CMDW_CONFIGURE_CHANNEL_PATH 0x000f0001
  16. #define SCLP_CMDW_DECONFIGURE_CHANNEL_PATH 0x000e0001
  17. #define SCLP_CMDW_READ_CHANNEL_PATH_INFORMATION 0x00030001
  18. static inline sclp_cmdw_t get_configure_cmdw(struct chp_id chpid)
  19. {
  20. return SCLP_CMDW_CONFIGURE_CHANNEL_PATH | chpid.id << 8;
  21. }
  22. static inline sclp_cmdw_t get_deconfigure_cmdw(struct chp_id chpid)
  23. {
  24. return SCLP_CMDW_DECONFIGURE_CHANNEL_PATH | chpid.id << 8;
  25. }
  26. static void chp_callback(struct sclp_req *req, void *data)
  27. {
  28. struct completion *completion = data;
  29. complete(completion);
  30. }
  31. struct chp_cfg_sccb {
  32. struct sccb_header header;
  33. u8 ccm;
  34. u8 reserved[6];
  35. u8 cssid;
  36. } __attribute__((packed));
  37. struct chp_cfg_data {
  38. struct chp_cfg_sccb sccb;
  39. struct sclp_req req;
  40. struct completion completion;
  41. } __attribute__((packed));
  42. static int do_configure(sclp_cmdw_t cmd)
  43. {
  44. struct chp_cfg_data *data;
  45. int rc;
  46. if (!SCLP_HAS_CHP_RECONFIG)
  47. return -EOPNOTSUPP;
  48. /* Prepare sccb. */
  49. data = (struct chp_cfg_data *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
  50. if (!data)
  51. return -ENOMEM;
  52. data->sccb.header.length = sizeof(struct chp_cfg_sccb);
  53. data->req.command = cmd;
  54. data->req.sccb = &(data->sccb);
  55. data->req.status = SCLP_REQ_FILLED;
  56. data->req.callback = chp_callback;
  57. data->req.callback_data = &(data->completion);
  58. init_completion(&data->completion);
  59. /* Perform sclp request. */
  60. rc = sclp_add_request(&(data->req));
  61. if (rc)
  62. goto out;
  63. wait_for_completion(&data->completion);
  64. /* Check response .*/
  65. if (data->req.status != SCLP_REQ_DONE) {
  66. printk(KERN_WARNING TAG "configure channel-path request failed "
  67. "(status=0x%02x)\n", data->req.status);
  68. rc = -EIO;
  69. goto out;
  70. }
  71. switch (data->sccb.header.response_code) {
  72. case 0x0020:
  73. case 0x0120:
  74. case 0x0440:
  75. case 0x0450:
  76. break;
  77. default:
  78. printk(KERN_WARNING TAG "configure channel-path failed "
  79. "(cmd=0x%08x, response=0x%04x)\n", cmd,
  80. data->sccb.header.response_code);
  81. rc = -EIO;
  82. break;
  83. }
  84. out:
  85. free_page((unsigned long) data);
  86. return rc;
  87. }
  88. /**
  89. * sclp_chp_configure - perform configure channel-path sclp command
  90. * @chpid: channel-path ID
  91. *
  92. * Perform configure channel-path command sclp command for specified chpid.
  93. * Return 0 after command successfully finished, non-zero otherwise.
  94. */
  95. int sclp_chp_configure(struct chp_id chpid)
  96. {
  97. return do_configure(get_configure_cmdw(chpid));
  98. }
  99. /**
  100. * sclp_chp_deconfigure - perform deconfigure channel-path sclp command
  101. * @chpid: channel-path ID
  102. *
  103. * Perform deconfigure channel-path command sclp command for specified chpid
  104. * and wait for completion. On success return 0. Return non-zero otherwise.
  105. */
  106. int sclp_chp_deconfigure(struct chp_id chpid)
  107. {
  108. return do_configure(get_deconfigure_cmdw(chpid));
  109. }
  110. struct chp_info_sccb {
  111. struct sccb_header header;
  112. u8 recognized[SCLP_CHP_INFO_MASK_SIZE];
  113. u8 standby[SCLP_CHP_INFO_MASK_SIZE];
  114. u8 configured[SCLP_CHP_INFO_MASK_SIZE];
  115. u8 ccm;
  116. u8 reserved[6];
  117. u8 cssid;
  118. } __attribute__((packed));
  119. struct chp_info_data {
  120. struct chp_info_sccb sccb;
  121. struct sclp_req req;
  122. struct completion completion;
  123. } __attribute__((packed));
  124. /**
  125. * sclp_chp_read_info - perform read channel-path information sclp command
  126. * @info: resulting channel-path information data
  127. *
  128. * Perform read channel-path information sclp command and wait for completion.
  129. * On success, store channel-path information in @info and return 0. Return
  130. * non-zero otherwise.
  131. */
  132. int sclp_chp_read_info(struct sclp_chp_info *info)
  133. {
  134. struct chp_info_data *data;
  135. int rc;
  136. if (!SCLP_HAS_CHP_INFO)
  137. return -EOPNOTSUPP;
  138. /* Prepare sccb. */
  139. data = (struct chp_info_data *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
  140. if (!data)
  141. return -ENOMEM;
  142. data->sccb.header.length = sizeof(struct chp_info_sccb);
  143. data->req.command = SCLP_CMDW_READ_CHANNEL_PATH_INFORMATION;
  144. data->req.sccb = &(data->sccb);
  145. data->req.status = SCLP_REQ_FILLED;
  146. data->req.callback = chp_callback;
  147. data->req.callback_data = &(data->completion);
  148. init_completion(&data->completion);
  149. /* Perform sclp request. */
  150. rc = sclp_add_request(&(data->req));
  151. if (rc)
  152. goto out;
  153. wait_for_completion(&data->completion);
  154. /* Check response .*/
  155. if (data->req.status != SCLP_REQ_DONE) {
  156. printk(KERN_WARNING TAG "read channel-path info request failed "
  157. "(status=0x%02x)\n", data->req.status);
  158. rc = -EIO;
  159. goto out;
  160. }
  161. if (data->sccb.header.response_code != 0x0010) {
  162. printk(KERN_WARNING TAG "read channel-path info failed "
  163. "(response=0x%04x)\n", data->sccb.header.response_code);
  164. rc = -EIO;
  165. goto out;
  166. }
  167. memcpy(info->recognized, data->sccb.recognized,
  168. SCLP_CHP_INFO_MASK_SIZE);
  169. memcpy(info->standby, data->sccb.standby,
  170. SCLP_CHP_INFO_MASK_SIZE);
  171. memcpy(info->configured, data->sccb.configured,
  172. SCLP_CHP_INFO_MASK_SIZE);
  173. out:
  174. free_page((unsigned long) data);
  175. return rc;
  176. }