xref: /linux/drivers/scsi/isci/probe_roms.c (revision 88f3b62ac131e2549b6c262cacbd47e8cca42d6e)
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