1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * PCI I/O adapter configuration related functions. 4 * 5 * Copyright IBM Corp. 2016 6 */ 7 #define KMSG_COMPONENT "sclp_cmd" 8 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 9 10 #include <linux/completion.h> 11 #include <linux/export.h> 12 #include <linux/mutex.h> 13 #include <linux/errno.h> 14 #include <linux/slab.h> 15 #include <linux/init.h> 16 #include <linux/err.h> 17 18 #include <asm/sclp.h> 19 20 #include "sclp.h" 21 22 #define SCLP_CMDW_CONFIGURE_PCI 0x001a0001 23 #define SCLP_CMDW_DECONFIGURE_PCI 0x001b0001 24 25 #define SCLP_ATYPE_PCI 2 26 27 #define SCLP_ERRNOTIFY_AQ_REPAIR 1 28 #define SCLP_ERRNOTIFY_AQ_INFO_LOG 2 29 30 static DEFINE_MUTEX(sclp_pci_mutex); 31 static struct sclp_register sclp_pci_event = { 32 .send_mask = EVTYP_ERRNOTIFY_MASK, 33 }; 34 35 struct err_notify_evbuf { 36 struct evbuf_header header; 37 u8 action; 38 u8 atype; 39 u32 fh; 40 u32 fid; 41 u8 data[0]; 42 } __packed; 43 44 struct err_notify_sccb { 45 struct sccb_header header; 46 struct err_notify_evbuf evbuf; 47 } __packed; 48 49 struct pci_cfg_sccb { 50 struct sccb_header header; 51 u8 atype; /* adapter type */ 52 u8 reserved1; 53 u16 reserved2; 54 u32 aid; /* adapter identifier */ 55 } __packed; 56 57 static int do_pci_configure(sclp_cmdw_t cmd, u32 fid) 58 { 59 struct pci_cfg_sccb *sccb; 60 int rc; 61 62 if (!SCLP_HAS_PCI_RECONFIG) 63 return -EOPNOTSUPP; 64 65 sccb = (struct pci_cfg_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA); 66 if (!sccb) 67 return -ENOMEM; 68 69 sccb->header.length = PAGE_SIZE; 70 sccb->atype = SCLP_ATYPE_PCI; 71 sccb->aid = fid; 72 rc = sclp_sync_request(cmd, sccb); 73 if (rc) 74 goto out; 75 switch (sccb->header.response_code) { 76 case 0x0020: 77 case 0x0120: 78 break; 79 default: 80 pr_warn("configure PCI I/O adapter failed: cmd=0x%08x response=0x%04x\n", 81 cmd, sccb->header.response_code); 82 rc = -EIO; 83 break; 84 } 85 out: 86 free_page((unsigned long) sccb); 87 return rc; 88 } 89 90 int sclp_pci_configure(u32 fid) 91 { 92 return do_pci_configure(SCLP_CMDW_CONFIGURE_PCI, fid); 93 } 94 EXPORT_SYMBOL(sclp_pci_configure); 95 96 int sclp_pci_deconfigure(u32 fid) 97 { 98 return do_pci_configure(SCLP_CMDW_DECONFIGURE_PCI, fid); 99 } 100 EXPORT_SYMBOL(sclp_pci_deconfigure); 101 102 static void sclp_pci_callback(struct sclp_req *req, void *data) 103 { 104 struct completion *completion = data; 105 106 complete(completion); 107 } 108 109 static int sclp_pci_check_report(struct zpci_report_error_header *report) 110 { 111 if (report->version != 1) 112 return -EINVAL; 113 114 if (report->action != SCLP_ERRNOTIFY_AQ_REPAIR && 115 report->action != SCLP_ERRNOTIFY_AQ_INFO_LOG) 116 return -EINVAL; 117 118 if (report->length > (PAGE_SIZE - sizeof(struct err_notify_sccb))) 119 return -EINVAL; 120 121 return 0; 122 } 123 124 int sclp_pci_report(struct zpci_report_error_header *report, u32 fh, u32 fid) 125 { 126 DECLARE_COMPLETION_ONSTACK(completion); 127 struct err_notify_sccb *sccb; 128 struct sclp_req req; 129 int ret; 130 131 ret = sclp_pci_check_report(report); 132 if (ret) 133 return ret; 134 135 mutex_lock(&sclp_pci_mutex); 136 ret = sclp_register(&sclp_pci_event); 137 if (ret) 138 goto out_unlock; 139 140 if (!(sclp_pci_event.sclp_receive_mask & EVTYP_ERRNOTIFY_MASK)) { 141 ret = -EOPNOTSUPP; 142 goto out_unregister; 143 } 144 145 sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); 146 if (!sccb) { 147 ret = -ENOMEM; 148 goto out_unregister; 149 } 150 151 memset(&req, 0, sizeof(req)); 152 req.callback_data = &completion; 153 req.callback = sclp_pci_callback; 154 req.command = SCLP_CMDW_WRITE_EVENT_DATA; 155 req.status = SCLP_REQ_FILLED; 156 req.sccb = sccb; 157 158 sccb->evbuf.header.length = sizeof(sccb->evbuf) + report->length; 159 sccb->evbuf.header.type = EVTYP_ERRNOTIFY; 160 sccb->header.length = sizeof(sccb->header) + sccb->evbuf.header.length; 161 162 sccb->evbuf.action = report->action; 163 sccb->evbuf.atype = SCLP_ATYPE_PCI; 164 sccb->evbuf.fh = fh; 165 sccb->evbuf.fid = fid; 166 167 memcpy(sccb->evbuf.data, report->data, report->length); 168 169 ret = sclp_add_request(&req); 170 if (ret) 171 goto out_free_req; 172 173 wait_for_completion(&completion); 174 if (req.status != SCLP_REQ_DONE) { 175 pr_warn("request failed (status=0x%02x)\n", 176 req.status); 177 ret = -EIO; 178 goto out_free_req; 179 } 180 181 if (sccb->header.response_code != 0x0020) { 182 pr_warn("request failed with response code 0x%x\n", 183 sccb->header.response_code); 184 ret = -EIO; 185 } 186 187 out_free_req: 188 free_page((unsigned long) sccb); 189 out_unregister: 190 sclp_unregister(&sclp_pci_event); 191 out_unlock: 192 mutex_unlock(&sclp_pci_mutex); 193 return ret; 194 } 195