1 /* 2 * PCI I/O adapter configuration related functions. 3 * 4 * Copyright IBM Corp. 2016 5 */ 6 #define KMSG_COMPONENT "sclp_cmd" 7 #define pr_fmt(fmt) KMSG_COMPONENT ": " 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 #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; 47 48 struct pci_cfg_sccb { 49 struct sccb_header header; 50 u8 atype; /* adapter type */ 51 u8 reserved1; 52 u16 reserved2; 53 u32 aid; /* adapter identifier */ 54 } __packed; 55 56 static int do_pci_configure(sclp_cmdw_t cmd, u32 fid) 57 { 58 struct pci_cfg_sccb *sccb; 59 int rc; 60 61 if (!SCLP_HAS_PCI_RECONFIG) 62 return -EOPNOTSUPP; 63 64 sccb = (struct pci_cfg_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA); 65 if (!sccb) 66 return -ENOMEM; 67 68 sccb->header.length = PAGE_SIZE; 69 sccb->atype = SCLP_ATYPE_PCI; 70 sccb->aid = fid; 71 rc = sclp_sync_request(cmd, sccb); 72 if (rc) 73 goto out; 74 switch (sccb->header.response_code) { 75 case 0x0020: 76 case 0x0120: 77 break; 78 default: 79 pr_warn("configure PCI I/O adapter failed: cmd=0x%08x response=0x%04x\n", 80 cmd, sccb->header.response_code); 81 rc = -EIO; 82 break; 83 } 84 out: 85 free_page((unsigned long) sccb); 86 return rc; 87 } 88 89 int sclp_pci_configure(u32 fid) 90 { 91 return do_pci_configure(SCLP_CMDW_CONFIGURE_PCI, fid); 92 } 93 EXPORT_SYMBOL(sclp_pci_configure); 94 95 int sclp_pci_deconfigure(u32 fid) 96 { 97 return do_pci_configure(SCLP_CMDW_DECONFIGURE_PCI, fid); 98 } 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; 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 memset(&req, 0, sizeof(req)); 151 req.callback_data = &completion; 152 req.callback = sclp_pci_callback; 153 req.command = SCLP_CMDW_WRITE_EVENT_DATA; 154 req.status = SCLP_REQ_FILLED; 155 req.sccb = sccb; 156 157 sccb->evbuf.header.length = sizeof(sccb->evbuf) + report->length; 158 sccb->evbuf.header.type = EVTYP_ERRNOTIFY; 159 sccb->header.length = sizeof(sccb->header) + sccb->evbuf.header.length; 160 161 sccb->evbuf.action = report->action; 162 sccb->evbuf.atype = SCLP_ATYPE_PCI; 163 sccb->evbuf.fh = fh; 164 sccb->evbuf.fid = fid; 165 166 memcpy(sccb->evbuf.data, report->data, report->length); 167 168 ret = sclp_add_request(&req); 169 if (ret) 170 goto out_free_req; 171 172 wait_for_completion(&completion); 173 if (req.status != SCLP_REQ_DONE) { 174 pr_warn("request failed (status=0x%02x)\n", 175 req.status); 176 ret = -EIO; 177 goto out_free_req; 178 } 179 180 if (sccb->header.response_code != 0x0020) { 181 pr_warn("request failed with response code 0x%x\n", 182 sccb->header.response_code); 183 ret = -EIO; 184 } 185 186 out_free_req: 187 free_page((unsigned long) sccb); 188 out_unregister: 189 sclp_unregister(&sclp_pci_event); 190 out_unlock: 191 mutex_unlock(&sclp_pci_mutex); 192 return ret; 193 } 194