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 "scic_remote_device.h" 37 #include "sci_environment.h" 38 #include "probe_roms.h" 39 40 struct efi_variable { 41 efi_char16_t VariableName[1024/sizeof(efi_char16_t)]; 42 efi_guid_t VendorGuid; 43 unsigned long DataSize; 44 __u8 Data[1024]; 45 efi_status_t Status; 46 __u32 Attributes; 47 } __attribute__((packed)); 48 49 struct isci_orom *isci_request_oprom(struct pci_dev *pdev) 50 { 51 void __iomem *oprom = pci_map_biosrom(pdev); 52 struct isci_orom *rom = NULL; 53 size_t len, i; 54 int j; 55 char oem_sig[4]; 56 struct isci_oem_hdr oem_hdr; 57 u8 *tmp, sum; 58 59 if (!oprom) 60 return NULL; 61 62 len = pci_biosrom_size(pdev); 63 rom = devm_kzalloc(&pdev->dev, sizeof(*rom), GFP_KERNEL); 64 if (!rom) { 65 dev_warn(&pdev->dev, 66 "Unable to allocate memory for orom\n"); 67 return NULL; 68 } 69 70 for (i = 0; i < len && rom; i += ISCI_OEM_SIG_SIZE) { 71 memcpy_fromio(oem_sig, oprom + i, ISCI_OEM_SIG_SIZE); 72 73 /* we think we found the OEM table */ 74 if (memcmp(oem_sig, ISCI_OEM_SIG, ISCI_OEM_SIG_SIZE) == 0) { 75 size_t copy_len; 76 77 memcpy_fromio(&oem_hdr, oprom + i, sizeof(oem_hdr)); 78 79 copy_len = min(oem_hdr.len - sizeof(oem_hdr), 80 sizeof(*rom)); 81 82 memcpy_fromio(rom, 83 oprom + i + sizeof(oem_hdr), 84 copy_len); 85 86 /* calculate checksum */ 87 tmp = (u8 *)&oem_hdr; 88 for (j = 0, sum = 0; j < sizeof(oem_hdr); j++, tmp++) 89 sum += *tmp; 90 91 tmp = (u8 *)rom; 92 for (j = 0; j < sizeof(*rom); j++, tmp++) 93 sum += *tmp; 94 95 if (sum != 0) { 96 dev_warn(&pdev->dev, 97 "OEM table checksum failed\n"); 98 continue; 99 } 100 101 /* keep going if that's not the oem param table */ 102 if (memcmp(rom->hdr.signature, 103 ISCI_ROM_SIG, 104 ISCI_ROM_SIG_SIZE) != 0) 105 continue; 106 107 dev_info(&pdev->dev, 108 "OEM parameter table found in OROM\n"); 109 break; 110 } 111 } 112 113 if (i >= len) { 114 dev_err(&pdev->dev, "oprom parse error\n"); 115 devm_kfree(&pdev->dev, rom); 116 rom = NULL; 117 } 118 pci_unmap_biosrom(oprom); 119 120 return rom; 121 } 122 123 /** 124 * isci_parse_oem_parameters() - This method will take OEM parameters 125 * from the module init parameters and copy them to oem_params. This will 126 * only copy values that are not set to the module parameter default values 127 * @oem_parameters: This parameter specifies the controller default OEM 128 * parameters. It is expected that this has been initialized to the default 129 * parameters for the controller 130 * 131 * 132 */ 133 enum sci_status isci_parse_oem_parameters(union scic_oem_parameters *oem_params, 134 struct isci_orom *orom, int scu_index) 135 { 136 /* check for valid inputs */ 137 if (scu_index < 0 || scu_index > SCI_MAX_CONTROLLERS || 138 scu_index > orom->hdr.num_elements || !oem_params) 139 return -EINVAL; 140 141 oem_params->sds1 = orom->ctrl[scu_index]; 142 return 0; 143 } 144 145 struct isci_orom *isci_request_firmware(struct pci_dev *pdev, const struct firmware *fw) 146 { 147 struct isci_orom *orom = NULL, *data; 148 149 if (request_firmware(&fw, ISCI_FW_NAME, &pdev->dev) != 0) 150 return NULL; 151 152 if (fw->size < sizeof(*orom)) 153 goto out; 154 155 data = (struct isci_orom *)fw->data; 156 157 if (strncmp(ISCI_ROM_SIG, data->hdr.signature, 158 strlen(ISCI_ROM_SIG)) != 0) 159 goto out; 160 161 orom = devm_kzalloc(&pdev->dev, fw->size, GFP_KERNEL); 162 if (!orom) 163 goto out; 164 165 memcpy(orom, fw->data, fw->size); 166 167 out: 168 release_firmware(fw); 169 170 return orom; 171 } 172 173 static struct efi *get_efi(void) 174 { 175 #ifdef CONFIG_EFI 176 return &efi; 177 #else 178 return NULL; 179 #endif 180 } 181 182 struct isci_orom *isci_get_efi_var(struct pci_dev *pdev) 183 { 184 struct efi_variable *evar; 185 efi_status_t status; 186 struct isci_orom *rom = NULL; 187 struct isci_oem_hdr *oem_hdr; 188 u8 *tmp, sum; 189 int j; 190 size_t copy_len; 191 192 evar = devm_kzalloc(&pdev->dev, 193 sizeof(struct efi_variable), 194 GFP_KERNEL); 195 if (!evar) { 196 dev_warn(&pdev->dev, 197 "Unable to allocate memory for EFI var\n"); 198 return NULL; 199 } 200 201 rom = devm_kzalloc(&pdev->dev, sizeof(*rom), GFP_KERNEL); 202 if (!rom) { 203 dev_warn(&pdev->dev, 204 "Unable to allocate memory for orom\n"); 205 return NULL; 206 } 207 208 for (j = 0; j < strlen(ISCI_EFI_VAR_NAME) + 1; j++) 209 evar->VariableName[j] = ISCI_EFI_VAR_NAME[j]; 210 211 evar->DataSize = 1024; 212 evar->VendorGuid = ISCI_EFI_VENDOR_GUID; 213 evar->Attributes = ISCI_EFI_ATTRIBUTES; 214 215 if (get_efi()) 216 status = get_efi()->get_variable(evar->VariableName, 217 &evar->VendorGuid, 218 &evar->Attributes, 219 &evar->DataSize, 220 evar->Data); 221 else 222 status = EFI_NOT_FOUND; 223 224 if (status != EFI_SUCCESS) { 225 dev_warn(&pdev->dev, 226 "Unable to obtain EFI variable for OEM parms\n"); 227 return NULL; 228 } 229 230 oem_hdr = (struct isci_oem_hdr *)evar->Data; 231 232 if (memcmp(oem_hdr->sig, ISCI_OEM_SIG, ISCI_OEM_SIG_SIZE) != 0) { 233 dev_warn(&pdev->dev, 234 "Invalid OEM header signature\n"); 235 return NULL; 236 } 237 238 /* calculate checksum */ 239 tmp = (u8 *)oem_hdr; 240 for (j = 0, sum = 0; j < sizeof(oem_hdr); j++, tmp++) 241 sum += *tmp; 242 243 tmp = (u8 *)rom; 244 for (j = 0; j < sizeof(*rom); j++, tmp++) 245 sum += *tmp; 246 247 if (sum != 0) { 248 dev_warn(&pdev->dev, 249 "OEM table checksum failed\n"); 250 return NULL; 251 } 252 253 copy_len = min_t(u16, evar->DataSize, 254 min_t(u16, oem_hdr->len - sizeof(*oem_hdr), sizeof(*rom))); 255 256 memcpy(rom, (char *)evar->Data + sizeof(*oem_hdr), copy_len); 257 258 if (memcmp(rom->hdr.signature, 259 ISCI_ROM_SIG, 260 ISCI_ROM_SIG_SIZE) != 0) { 261 dev_warn(&pdev->dev, 262 "Invalid OEM table signature\n"); 263 return NULL; 264 } 265 266 return rom; 267 } 268