1 /* 2 * This file is provided under a dual BSD/GPLv2 license. When using or 3 * redistributing this file, you may do so under either license. 4 * 5 * GPL LICENSE SUMMARY 6 * 7 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of version 2 of the GNU General Public License as 11 * published by the Free Software Foundation. 12 * 13 * This program is distributed in the hope that it will be useful, but 14 * WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 21 * The full GNU General Public License is included in this distribution 22 * in the file called LICENSE.GPL. 23 */ 24 25 /* probe_roms - scan for oem parameters */ 26 27 #include <linux/kernel.h> 28 #include <linux/firmware.h> 29 #include <linux/uaccess.h> 30 #include <linux/efi.h> 31 #include <asm/probe_roms.h> 32 33 #include "isci.h" 34 #include "task.h" 35 #include "sci_controller_constants.h" 36 #include "sci_environment.h" 37 #include "probe_roms.h" 38 39 struct efi_variable { 40 efi_char16_t VariableName[1024/sizeof(efi_char16_t)]; 41 efi_guid_t VendorGuid; 42 unsigned long DataSize; 43 __u8 Data[1024]; 44 efi_status_t Status; 45 __u32 Attributes; 46 } __attribute__((packed)); 47 48 struct isci_orom *isci_request_oprom(struct pci_dev *pdev) 49 { 50 void __iomem *oprom = pci_map_biosrom(pdev); 51 struct isci_orom *rom = NULL; 52 size_t len, i; 53 int j; 54 char oem_sig[4]; 55 struct isci_oem_hdr oem_hdr; 56 u8 *tmp, sum; 57 58 if (!oprom) 59 return NULL; 60 61 len = pci_biosrom_size(pdev); 62 rom = devm_kzalloc(&pdev->dev, sizeof(*rom), GFP_KERNEL); 63 if (!rom) { 64 dev_warn(&pdev->dev, 65 "Unable to allocate memory for orom\n"); 66 return NULL; 67 } 68 69 for (i = 0; i < len && rom; i += ISCI_OEM_SIG_SIZE) { 70 memcpy_fromio(oem_sig, oprom + i, ISCI_OEM_SIG_SIZE); 71 72 /* we think we found the OEM table */ 73 if (memcmp(oem_sig, ISCI_OEM_SIG, ISCI_OEM_SIG_SIZE) == 0) { 74 size_t copy_len; 75 76 memcpy_fromio(&oem_hdr, oprom + i, sizeof(oem_hdr)); 77 78 copy_len = min(oem_hdr.len - sizeof(oem_hdr), 79 sizeof(*rom)); 80 81 memcpy_fromio(rom, 82 oprom + i + sizeof(oem_hdr), 83 copy_len); 84 85 /* calculate checksum */ 86 tmp = (u8 *)&oem_hdr; 87 for (j = 0, sum = 0; j < sizeof(oem_hdr); j++, tmp++) 88 sum += *tmp; 89 90 tmp = (u8 *)rom; 91 for (j = 0; j < sizeof(*rom); j++, tmp++) 92 sum += *tmp; 93 94 if (sum != 0) { 95 dev_warn(&pdev->dev, 96 "OEM table checksum failed\n"); 97 continue; 98 } 99 100 /* keep going if that's not the oem param table */ 101 if (memcmp(rom->hdr.signature, 102 ISCI_ROM_SIG, 103 ISCI_ROM_SIG_SIZE) != 0) 104 continue; 105 106 dev_info(&pdev->dev, 107 "OEM parameter table found in OROM\n"); 108 break; 109 } 110 } 111 112 if (i >= len) { 113 dev_err(&pdev->dev, "oprom parse error\n"); 114 devm_kfree(&pdev->dev, rom); 115 rom = NULL; 116 } 117 pci_unmap_biosrom(oprom); 118 119 return rom; 120 } 121 122 /** 123 * isci_parse_oem_parameters() - This method will take OEM parameters 124 * from the module init parameters and copy them to oem_params. This will 125 * only copy values that are not set to the module parameter default values 126 * @oem_parameters: This parameter specifies the controller default OEM 127 * parameters. It is expected that this has been initialized to the default 128 * parameters for the controller 129 * 130 * 131 */ 132 enum sci_status isci_parse_oem_parameters(union scic_oem_parameters *oem_params, 133 struct isci_orom *orom, int scu_index) 134 { 135 /* check for valid inputs */ 136 if (scu_index < 0 || scu_index > SCI_MAX_CONTROLLERS || 137 scu_index > orom->hdr.num_elements || !oem_params) 138 return -EINVAL; 139 140 oem_params->sds1 = orom->ctrl[scu_index]; 141 return 0; 142 } 143 144 struct isci_orom *isci_request_firmware(struct pci_dev *pdev, const struct firmware *fw) 145 { 146 struct isci_orom *orom = NULL, *data; 147 148 if (request_firmware(&fw, ISCI_FW_NAME, &pdev->dev) != 0) 149 return NULL; 150 151 if (fw->size < sizeof(*orom)) 152 goto out; 153 154 data = (struct isci_orom *)fw->data; 155 156 if (strncmp(ISCI_ROM_SIG, data->hdr.signature, 157 strlen(ISCI_ROM_SIG)) != 0) 158 goto out; 159 160 orom = devm_kzalloc(&pdev->dev, fw->size, GFP_KERNEL); 161 if (!orom) 162 goto out; 163 164 memcpy(orom, fw->data, fw->size); 165 166 out: 167 release_firmware(fw); 168 169 return orom; 170 } 171 172 static struct efi *get_efi(void) 173 { 174 #ifdef CONFIG_EFI 175 return &efi; 176 #else 177 return NULL; 178 #endif 179 } 180 181 struct isci_orom *isci_get_efi_var(struct pci_dev *pdev) 182 { 183 struct efi_variable *evar; 184 efi_status_t status; 185 struct isci_orom *rom = NULL; 186 struct isci_oem_hdr *oem_hdr; 187 u8 *tmp, sum; 188 int j; 189 size_t copy_len; 190 191 evar = devm_kzalloc(&pdev->dev, 192 sizeof(struct efi_variable), 193 GFP_KERNEL); 194 if (!evar) { 195 dev_warn(&pdev->dev, 196 "Unable to allocate memory for EFI var\n"); 197 return NULL; 198 } 199 200 rom = devm_kzalloc(&pdev->dev, sizeof(*rom), GFP_KERNEL); 201 if (!rom) { 202 dev_warn(&pdev->dev, 203 "Unable to allocate memory for orom\n"); 204 return NULL; 205 } 206 207 for (j = 0; j < strlen(ISCI_EFI_VAR_NAME) + 1; j++) 208 evar->VariableName[j] = ISCI_EFI_VAR_NAME[j]; 209 210 evar->DataSize = 1024; 211 evar->VendorGuid = ISCI_EFI_VENDOR_GUID; 212 evar->Attributes = ISCI_EFI_ATTRIBUTES; 213 214 if (get_efi()) 215 status = get_efi()->get_variable(evar->VariableName, 216 &evar->VendorGuid, 217 &evar->Attributes, 218 &evar->DataSize, 219 evar->Data); 220 else 221 status = EFI_NOT_FOUND; 222 223 if (status != EFI_SUCCESS) { 224 dev_warn(&pdev->dev, 225 "Unable to obtain EFI variable for OEM parms\n"); 226 return NULL; 227 } 228 229 oem_hdr = (struct isci_oem_hdr *)evar->Data; 230 231 if (memcmp(oem_hdr->sig, ISCI_OEM_SIG, ISCI_OEM_SIG_SIZE) != 0) { 232 dev_warn(&pdev->dev, 233 "Invalid OEM header signature\n"); 234 return NULL; 235 } 236 237 /* calculate checksum */ 238 tmp = (u8 *)oem_hdr; 239 for (j = 0, sum = 0; j < sizeof(oem_hdr); j++, tmp++) 240 sum += *tmp; 241 242 tmp = (u8 *)rom; 243 for (j = 0; j < sizeof(*rom); j++, tmp++) 244 sum += *tmp; 245 246 if (sum != 0) { 247 dev_warn(&pdev->dev, 248 "OEM table checksum failed\n"); 249 return NULL; 250 } 251 252 copy_len = min_t(u16, evar->DataSize, 253 min_t(u16, oem_hdr->len - sizeof(*oem_hdr), sizeof(*rom))); 254 255 memcpy(rom, (char *)evar->Data + sizeof(*oem_hdr), copy_len); 256 257 if (memcmp(rom->hdr.signature, 258 ISCI_ROM_SIG, 259 ISCI_ROM_SIG_SIZE) != 0) { 260 dev_warn(&pdev->dev, 261 "Invalid OEM table signature\n"); 262 return NULL; 263 } 264 265 return rom; 266 } 267