diff options
author | Sebastian Ott <sebott@linux.vnet.ibm.com> | 2015-11-27 05:18:02 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2016-04-15 12:16:38 -0400 |
commit | 12283a4035691697977083a5ac1e00ad5cfa6a3d (patch) | |
tree | 1e1fd34032cda6850e378cfa019e0ddfcf04b929 | |
parent | 68dd13d6d58c145bbf6d295b8c430b4d38c943d9 (diff) |
s390/sclp: add error notification command
Add SCLP event 24 "Adapter-error notification".
Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r-- | arch/s390/include/asm/sclp.h | 13 | ||||
-rw-r--r-- | drivers/s390/char/sclp.h | 2 | ||||
-rw-r--r-- | drivers/s390/char/sclp_pci.c | 120 |
3 files changed, 133 insertions, 2 deletions
diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h index bab456be9a4f..bd7893d274fa 100644 --- a/arch/s390/include/asm/sclp.h +++ b/arch/s390/include/asm/sclp.h | |||
@@ -72,6 +72,18 @@ struct sclp_info { | |||
72 | }; | 72 | }; |
73 | extern struct sclp_info sclp; | 73 | extern struct sclp_info sclp; |
74 | 74 | ||
75 | struct zpci_report_error_header { | ||
76 | u8 version; /* Interface version byte */ | ||
77 | u8 action; /* Action qualifier byte | ||
78 | * 1: Deconfigure and repair action requested | ||
79 | * (OpenCrypto Problem Call Home) | ||
80 | * 2: Informational Report | ||
81 | * (OpenCrypto Successful Diagnostics Execution) | ||
82 | */ | ||
83 | u16 length; /* Length of Subsequent Data (up to 4K – SCLP header */ | ||
84 | u8 data[0]; /* Subsequent Data passed verbatim to SCLP ET 24 */ | ||
85 | } __packed; | ||
86 | |||
75 | int sclp_get_core_info(struct sclp_core_info *info); | 87 | int sclp_get_core_info(struct sclp_core_info *info); |
76 | int sclp_core_configure(u8 core); | 88 | int sclp_core_configure(u8 core); |
77 | int sclp_core_deconfigure(u8 core); | 89 | int sclp_core_deconfigure(u8 core); |
@@ -83,6 +95,7 @@ int sclp_chp_read_info(struct sclp_chp_info *info); | |||
83 | void sclp_get_ipl_info(struct sclp_ipl_info *info); | 95 | void sclp_get_ipl_info(struct sclp_ipl_info *info); |
84 | int sclp_pci_configure(u32 fid); | 96 | int sclp_pci_configure(u32 fid); |
85 | int sclp_pci_deconfigure(u32 fid); | 97 | int sclp_pci_deconfigure(u32 fid); |
98 | int sclp_pci_report(struct zpci_report_error_header *report, u32 fh, u32 fid); | ||
86 | int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count); | 99 | int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count); |
87 | int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count); | 100 | int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count); |
88 | void sclp_early_detect(void); | 101 | void sclp_early_detect(void); |
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index 026e38990952..6079efa95eaa 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h | |||
@@ -22,6 +22,7 @@ | |||
22 | #define EVTYP_DIAG_TEST 0x07 | 22 | #define EVTYP_DIAG_TEST 0x07 |
23 | #define EVTYP_STATECHANGE 0x08 | 23 | #define EVTYP_STATECHANGE 0x08 |
24 | #define EVTYP_PMSGCMD 0x09 | 24 | #define EVTYP_PMSGCMD 0x09 |
25 | #define EVTYP_ERRNOTIFY 0x18 | ||
25 | #define EVTYP_CNTLPROGOPCMD 0x20 | 26 | #define EVTYP_CNTLPROGOPCMD 0x20 |
26 | #define EVTYP_CNTLPROGIDENT 0x0B | 27 | #define EVTYP_CNTLPROGIDENT 0x0B |
27 | #define EVTYP_SIGQUIESCE 0x1D | 28 | #define EVTYP_SIGQUIESCE 0x1D |
@@ -36,6 +37,7 @@ | |||
36 | #define EVTYP_DIAG_TEST_MASK 0x02000000 | 37 | #define EVTYP_DIAG_TEST_MASK 0x02000000 |
37 | #define EVTYP_STATECHANGE_MASK 0x01000000 | 38 | #define EVTYP_STATECHANGE_MASK 0x01000000 |
38 | #define EVTYP_PMSGCMD_MASK 0x00800000 | 39 | #define EVTYP_PMSGCMD_MASK 0x00800000 |
40 | #define EVTYP_ERRNOTIFY_MASK 0x00000100 | ||
39 | #define EVTYP_CTLPROGOPCMD_MASK 0x00000001 | 41 | #define EVTYP_CTLPROGOPCMD_MASK 0x00000001 |
40 | #define EVTYP_CTLPROGIDENT_MASK 0x00200000 | 42 | #define EVTYP_CTLPROGIDENT_MASK 0x00200000 |
41 | #define EVTYP_SIGQUIESCE_MASK 0x00000008 | 43 | #define EVTYP_SIGQUIESCE_MASK 0x00000008 |
diff --git a/drivers/s390/char/sclp_pci.c b/drivers/s390/char/sclp_pci.c index 943e92539e65..0c8973c45b48 100644 --- a/drivers/s390/char/sclp_pci.c +++ b/drivers/s390/char/sclp_pci.c | |||
@@ -8,6 +8,7 @@ | |||
8 | 8 | ||
9 | #include <linux/completion.h> | 9 | #include <linux/completion.h> |
10 | #include <linux/export.h> | 10 | #include <linux/export.h> |
11 | #include <linux/mutex.h> | ||
11 | #include <linux/errno.h> | 12 | #include <linux/errno.h> |
12 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
13 | #include <linux/init.h> | 14 | #include <linux/init.h> |
@@ -20,7 +21,29 @@ | |||
20 | #define SCLP_CMDW_CONFIGURE_PCI 0x001a0001 | 21 | #define SCLP_CMDW_CONFIGURE_PCI 0x001a0001 |
21 | #define SCLP_CMDW_DECONFIGURE_PCI 0x001b0001 | 22 | #define SCLP_CMDW_DECONFIGURE_PCI 0x001b0001 |
22 | 23 | ||
23 | #define SCLP_RECONFIG_PCI_ATPYE 2 | 24 | #define SCLP_ATYPE_PCI 2 |
25 | |||
26 | #define SCLP_ERRNOTIFY_AQ_REPAIR 1 | ||
27 | #define SCLP_ERRNOTIFY_AQ_INFO_LOG 2 | ||
28 | |||
29 | static DEFINE_MUTEX(sclp_pci_mutex); | ||
30 | static struct sclp_register sclp_pci_event = { | ||
31 | .send_mask = EVTYP_ERRNOTIFY_MASK, | ||
32 | }; | ||
33 | |||
34 | struct err_notify_evbuf { | ||
35 | struct evbuf_header header; | ||
36 | u8 action; | ||
37 | u8 atype; | ||
38 | u32 fh; | ||
39 | u32 fid; | ||
40 | u8 data[0]; | ||
41 | } __packed; | ||
42 | |||
43 | struct err_notify_sccb { | ||
44 | struct sccb_header header; | ||
45 | struct err_notify_evbuf evbuf; | ||
46 | } __packed; | ||
24 | 47 | ||
25 | struct pci_cfg_sccb { | 48 | struct pci_cfg_sccb { |
26 | struct sccb_header header; | 49 | struct sccb_header header; |
@@ -43,7 +66,7 @@ static int do_pci_configure(sclp_cmdw_t cmd, u32 fid) | |||
43 | return -ENOMEM; | 66 | return -ENOMEM; |
44 | 67 | ||
45 | sccb->header.length = PAGE_SIZE; | 68 | sccb->header.length = PAGE_SIZE; |
46 | sccb->atype = SCLP_RECONFIG_PCI_ATPYE; | 69 | sccb->atype = SCLP_ATYPE_PCI; |
47 | sccb->aid = fid; | 70 | sccb->aid = fid; |
48 | rc = sclp_sync_request(cmd, sccb); | 71 | rc = sclp_sync_request(cmd, sccb); |
49 | if (rc) | 72 | if (rc) |
@@ -74,3 +97,96 @@ int sclp_pci_deconfigure(u32 fid) | |||
74 | return do_pci_configure(SCLP_CMDW_DECONFIGURE_PCI, fid); | 97 | return do_pci_configure(SCLP_CMDW_DECONFIGURE_PCI, fid); |
75 | } | 98 | } |
76 | EXPORT_SYMBOL(sclp_pci_deconfigure); | 99 | EXPORT_SYMBOL(sclp_pci_deconfigure); |
100 | |||
101 | static void sclp_pci_callback(struct sclp_req *req, void *data) | ||
102 | { | ||
103 | struct completion *completion = data; | ||
104 | |||
105 | complete(completion); | ||
106 | } | ||
107 | |||
108 | static int sclp_pci_check_report(struct zpci_report_error_header *report) | ||
109 | { | ||
110 | if (report->version != 1) | ||
111 | return -EINVAL; | ||
112 | |||
113 | if (report->action != SCLP_ERRNOTIFY_AQ_REPAIR && | ||
114 | report->action != SCLP_ERRNOTIFY_AQ_INFO_LOG) | ||
115 | return -EINVAL; | ||
116 | |||
117 | if (report->length > (PAGE_SIZE - sizeof(struct err_notify_sccb))) | ||
118 | return -EINVAL; | ||
119 | |||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | int sclp_pci_report(struct zpci_report_error_header *report, u32 fh, u32 fid) | ||
124 | { | ||
125 | DECLARE_COMPLETION_ONSTACK(completion); | ||
126 | struct err_notify_sccb *sccb; | ||
127 | struct sclp_req req = {0}; | ||
128 | int ret; | ||
129 | |||
130 | ret = sclp_pci_check_report(report); | ||
131 | if (ret) | ||
132 | return ret; | ||
133 | |||
134 | mutex_lock(&sclp_pci_mutex); | ||
135 | ret = sclp_register(&sclp_pci_event); | ||
136 | if (ret) | ||
137 | goto out_unlock; | ||
138 | |||
139 | if (!(sclp_pci_event.sclp_receive_mask & EVTYP_ERRNOTIFY_MASK)) { | ||
140 | ret = -EOPNOTSUPP; | ||
141 | goto out_unregister; | ||
142 | } | ||
143 | |||
144 | sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); | ||
145 | if (!sccb) { | ||
146 | ret = -ENOMEM; | ||
147 | goto out_unregister; | ||
148 | } | ||
149 | |||
150 | req.callback_data = &completion; | ||
151 | req.callback = sclp_pci_callback; | ||
152 | req.command = SCLP_CMDW_WRITE_EVENT_DATA; | ||
153 | req.status = SCLP_REQ_FILLED; | ||
154 | req.sccb = sccb; | ||
155 | |||
156 | sccb->evbuf.header.length = sizeof(sccb->evbuf) + report->length; | ||
157 | sccb->evbuf.header.type = EVTYP_ERRNOTIFY; | ||
158 | sccb->header.length = sizeof(sccb->header) + sccb->evbuf.header.length; | ||
159 | |||
160 | sccb->evbuf.action = report->action; | ||
161 | sccb->evbuf.atype = SCLP_ATYPE_PCI; | ||
162 | sccb->evbuf.fh = fh; | ||
163 | sccb->evbuf.fid = fid; | ||
164 | |||
165 | memcpy(sccb->evbuf.data, report->data, report->length); | ||
166 | |||
167 | ret = sclp_add_request(&req); | ||
168 | if (ret) | ||
169 | goto out_free_req; | ||
170 | |||
171 | wait_for_completion(&completion); | ||
172 | if (req.status != SCLP_REQ_DONE) { | ||
173 | pr_warn("request failed (status=0x%02x)\n", | ||
174 | req.status); | ||
175 | ret = -EIO; | ||
176 | goto out_free_req; | ||
177 | } | ||
178 | |||
179 | if (sccb->header.response_code != 0x0020) { | ||
180 | pr_warn("request failed with response code 0x%x\n", | ||
181 | sccb->header.response_code); | ||
182 | ret = -EIO; | ||
183 | } | ||
184 | |||
185 | out_free_req: | ||
186 | free_page((unsigned long) sccb); | ||
187 | out_unregister: | ||
188 | sclp_unregister(&sclp_pci_event); | ||
189 | out_unlock: | ||
190 | mutex_unlock(&sclp_pci_mutex); | ||
191 | return ret; | ||
192 | } | ||