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