1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source. A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*-
13  * Copyright (c) 2017 Chelsio Communications, Inc.
14  * All rights reserved.
15  *
16  * Redistribution and use in source and binary forms, with or without
17  * modification, are permitted provided that the following conditions
18  * are met:
19  * 1. Redistributions of source code must retain the above copyright
20  *    notice, this list of conditions and the following disclaimer.
21  * 2. Redistributions in binary form must reproduce the above copyright
22  *    notice, this list of conditions and the following disclaimer in the
23  *    documentation and/or other materials provided with the distribution.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  */
37 
38 #include <sys/types.h>
39 #include <sys/param.h>
40 
41 #include "common/common.h"
42 #include "common/t4_regs.h"
43 #include "cudbg.h"
44 #include "cudbg_lib_common.h"
45 
46 enum {
47 	SF_ATTEMPTS = 10,		/* max retries for SF operations */
48 
49 	/* flash command opcodes */
50 	SF_PROG_PAGE	= 2,	/* program page */
51 	SF_WR_DISABLE	= 4,	/* disable writes */
52 	SF_RD_STATUS	= 5,	/* read status register */
53 	SF_WR_ENABLE	= 6,	/* enable writes */
54 	SF_RD_DATA_FAST = 0xb,	/* read flash */
55 	SF_RD_ID	= 0x9f, /* read ID */
56 	SF_ERASE_SECTOR = 0xd8, /* erase sector */
57 };
58 
59 int write_flash(struct adapter *adap, u32 start_sec, void *data, u32 size);
60 int read_flash(struct adapter *adap, u32 start_sec , void *data, u32 size,
61 		u32 start_address);
62 
63 void
update_skip_size(struct cudbg_flash_sec_info * sec_info,u32 size)64 update_skip_size(struct cudbg_flash_sec_info *sec_info, u32 size)
65 {
66 	sec_info->skip_size += size;
67 }
68 
69 static
set_sector_availability(struct cudbg_flash_sec_info * sec_info,int sector_nu,int avail)70 void set_sector_availability(struct cudbg_flash_sec_info *sec_info,
71     int sector_nu, int avail)
72 {
73 	sector_nu -= CUDBG_START_SEC;
74 	if (avail)
75 		set_dbg_bitmap(sec_info->sec_bitmap, sector_nu);
76 	else
77 		reset_dbg_bitmap(sec_info->sec_bitmap, sector_nu);
78 }
79 
80 /* This function will return empty sector available for filling */
81 static int
find_empty_sec(struct cudbg_flash_sec_info * sec_info)82 find_empty_sec(struct cudbg_flash_sec_info *sec_info)
83 {
84 	int i, index, bit;
85 
86 	for (i = CUDBG_START_SEC; i < CUDBG_SF_MAX_SECTOR; i++) {
87 		index = (i - CUDBG_START_SEC) / 8;
88 		bit = (i - CUDBG_START_SEC) % 8;
89 		if (!(sec_info->sec_bitmap[index] & (1 << bit)))
90 			return i;
91 	}
92 
93 	return CUDBG_STATUS_FLASH_FULL;
94 }
95 
96 /* This function will get header initially. If header is already there
97  * then it will update that header */
98 static void
update_headers(void * handle,struct cudbg_buffer * dbg_buff,u64 timestamp,u32 cur_entity_hdr_offset,u32 start_offset,u32 ext_size)99 update_headers(void *handle, struct cudbg_buffer *dbg_buff,
100 	       u64 timestamp, u32 cur_entity_hdr_offset,
101 	       u32 start_offset, u32 ext_size)
102 {
103 	struct cudbg_private *priv = handle;
104 	struct cudbg_flash_sec_info *sec_info = &priv->sec_info;
105 	void *sec_hdr;
106 	struct cudbg_hdr *cudbg_hdr;
107 	struct cudbg_flash_hdr *flash_hdr;
108 	struct cudbg_entity_hdr *entity_hdr;
109 	u32 hdr_offset;
110 	u32 data_hdr_size;
111 	u32 total_hdr_size;
112 	u32 sec_hdr_start_addr;
113 
114 	data_hdr_size = CUDBG_MAX_ENTITY * sizeof(struct cudbg_entity_hdr) +
115 				sizeof(struct cudbg_hdr);
116 	total_hdr_size = data_hdr_size + sizeof(struct cudbg_flash_hdr);
117 	sec_hdr_start_addr = CUDBG_SF_SECTOR_SIZE - total_hdr_size;
118 	sec_hdr  = sec_info->sec_data + sec_hdr_start_addr;
119 
120 	flash_hdr = (struct cudbg_flash_hdr *)(sec_hdr);
121 	cudbg_hdr = (struct cudbg_hdr *)dbg_buff->data;
122 
123 	/* initially initialize flash hdr and copy all data headers and
124 	 * in next calling (else part) copy only current entity header
125 	 */
126 	if ((start_offset - sec_info->skip_size) == data_hdr_size) {
127 		flash_hdr->signature = CUDBG_FL_SIGNATURE;
128 		flash_hdr->major_ver = CUDBG_FL_MAJOR_VERSION;
129 		flash_hdr->minor_ver = CUDBG_FL_MINOR_VERSION;
130 		flash_hdr->build_ver = CUDBG_FL_BUILD_VERSION;
131 		flash_hdr->hdr_len = sizeof(struct cudbg_flash_hdr);
132 		hdr_offset =  sizeof(struct cudbg_flash_hdr);
133 
134 		memcpy((void *)((char *)sec_hdr + hdr_offset),
135 		       (void *)((char *)dbg_buff->data), data_hdr_size);
136 	} else
137 		memcpy((void *)((char *)sec_hdr +
138 			sizeof(struct cudbg_flash_hdr) +
139 			cur_entity_hdr_offset),
140 			(void *)((char *)dbg_buff->data +
141 			cur_entity_hdr_offset),
142 			sizeof(struct cudbg_entity_hdr));
143 
144 	hdr_offset = data_hdr_size + sizeof(struct cudbg_flash_hdr);
145 	flash_hdr->data_len = cudbg_hdr->data_len - sec_info->skip_size;
146 	flash_hdr->timestamp = timestamp;
147 
148 	entity_hdr = (struct cudbg_entity_hdr *)((char *)sec_hdr +
149 		      sizeof(struct cudbg_flash_hdr) +
150 		      cur_entity_hdr_offset);
151 	/* big entity like mc need to be skipped */
152 	entity_hdr->start_offset -= sec_info->skip_size;
153 
154 	cudbg_hdr = (struct cudbg_hdr *)((char *)sec_hdr +
155 			sizeof(struct cudbg_flash_hdr));
156 	cudbg_hdr->data_len = flash_hdr->data_len;
157 	flash_hdr->data_len += ext_size;
158 }
159 
160 /* Write CUDBG data into serial flash */
161 int
cudbg_write_flash(void * handle,u64 timestamp,void * data,u32 start_offset,u32 cur_entity_hdr_offset,u32 cur_entity_size,u32 ext_size)162 cudbg_write_flash(void *handle, u64 timestamp, void *data,
163 		  u32 start_offset, u32 cur_entity_hdr_offset,
164 		  u32 cur_entity_size,
165 		  u32 ext_size)
166 {
167 	struct cudbg_private *priv = handle;
168 	struct cudbg_init *cudbg_init = &priv->dbg_init;
169 	struct cudbg_flash_sec_info *sec_info = &priv->sec_info;
170 	struct adapter *adap = cudbg_init->adap;
171 	struct cudbg_flash_hdr *flash_hdr = NULL;
172 	struct cudbg_buffer *dbg_buff = (struct cudbg_buffer *)data;
173 	u32 data_hdr_size;
174 	u32 total_hdr_size;
175 	u32 tmp_size;
176 	u32 sec_data_offset;
177 	u32 sec_hdr_start_addr;
178 	u32 sec_data_size;
179 	u32 space_left;
180 	int rc = 0;
181 	int sec;
182 
183 	data_hdr_size = CUDBG_MAX_ENTITY * sizeof(struct cudbg_entity_hdr) +
184 			sizeof(struct cudbg_hdr);
185 	total_hdr_size = data_hdr_size + sizeof(struct cudbg_flash_hdr);
186 	sec_hdr_start_addr = CUDBG_SF_SECTOR_SIZE - total_hdr_size;
187 	sec_data_size = sec_hdr_start_addr;
188 
189 	cudbg_init->print(adap->dip, CE_NOTE, "\tWriting %u bytes to flash\n", cur_entity_size);
190 
191 	/* this function will get header if sec_info->sec_data does not
192 	 * have any header and
193 	 * will update the header if it has header
194 	 */
195 	update_headers(handle, dbg_buff, timestamp,
196 		       cur_entity_hdr_offset,
197 		       start_offset, ext_size);
198 
199 	if (ext_size) {
200 		cur_entity_size += sizeof(struct cudbg_entity_hdr);
201 		start_offset = dbg_buff->offset - cur_entity_size;
202 	}
203 
204 	flash_hdr = (struct cudbg_flash_hdr *)(sec_info->sec_data +
205 			sec_hdr_start_addr);
206 
207 	if (flash_hdr->data_len > CUDBG_FLASH_SIZE) {
208 		rc = CUDBG_STATUS_FLASH_FULL;
209 		goto out;
210 	}
211 
212 	space_left = CUDBG_FLASH_SIZE - flash_hdr->data_len;
213 
214 	if (cur_entity_size > space_left) {
215 		rc = CUDBG_STATUS_FLASH_FULL;
216 		goto out;
217 	}
218 
219 	while (cur_entity_size > 0) {
220 		sec = find_empty_sec(sec_info);
221 		if (sec_info->par_sec) {
222 			sec_data_offset = sec_info->par_sec_offset;
223 			set_sector_availability(sec_info, sec_info->par_sec, 0);
224 			sec_info->par_sec = 0;
225 			sec_info->par_sec_offset = 0;
226 
227 		} else {
228 			sec_info->cur_seq_no++;
229 			flash_hdr->sec_seq_no = sec_info->cur_seq_no;
230 			sec_data_offset = 0;
231 		}
232 
233 		if (cur_entity_size + sec_data_offset > sec_data_size) {
234 			tmp_size = sec_data_size - sec_data_offset;
235 		} else {
236 			tmp_size = cur_entity_size;
237 			sec_info->par_sec = sec;
238 			sec_info->par_sec_offset = cur_entity_size +
239 						  sec_data_offset;
240 		}
241 
242 		memcpy((void *)((char *)sec_info->sec_data + sec_data_offset),
243 		       (void *)((char *)dbg_buff->data + start_offset),
244 		       tmp_size);
245 
246 		rc = write_flash(adap, sec, sec_info->sec_data,
247 				CUDBG_SF_SECTOR_SIZE);
248 		if (rc)
249 			goto out;
250 
251 		cur_entity_size -= tmp_size;
252 		set_sector_availability(sec_info, sec, 1);
253 		start_offset += tmp_size;
254 	}
255 out:
256 	return rc;
257 }
258 
259 int
write_flash(struct adapter * adap,u32 start_sec,void * data,u32 size)260 write_flash(struct adapter *adap, u32 start_sec, void *data, u32 size)
261 {
262 	unsigned int addr;
263 	unsigned int i, n;
264 	unsigned int sf_sec_size;
265 	int rc = 0;
266 
267 	u8 *ptr = (u8 *)data;
268 
269 	sf_sec_size = adap->params.sf_size/adap->params.sf_nsec;
270 
271 	addr =  start_sec * CUDBG_SF_SECTOR_SIZE;
272 	i = DIV_ROUND_UP(size,/* # of sectors spanned */
273 			sf_sec_size);
274 
275 	rc = t4_flash_erase_sectors(adap, start_sec,
276 		   start_sec + i - 1);
277 	/*
278 	 * If size == 0 then we're simply erasing the FLASH sectors associated
279 	 * with the on-adapter OptionROM Configuration File.
280 	 */
281 
282 	if (rc || size == 0)
283 		goto out;
284 
285 	/* this will write to the flash up to SF_PAGE_SIZE at a time */
286 	for (i = 0; i < size; i += SF_PAGE_SIZE) {
287 		if ((size - i) <  SF_PAGE_SIZE)
288 			n = size - i;
289 		else
290 			n = SF_PAGE_SIZE;
291 		rc = t4_write_flash(adap, addr, n, ptr, 0);
292 		if (rc)
293 			goto out;
294 
295 		addr += n;
296 		ptr += n;
297 	}
298 
299 	return 0;
300 out:
301 	return rc;
302 }
303 
304 int
cudbg_read_flash_details(void * handle,struct cudbg_flash_hdr * data)305 cudbg_read_flash_details(void *handle, struct cudbg_flash_hdr *data)
306 {
307 	int rc;
308 	rc = cudbg_read_flash(handle, (void *)data,
309 			      sizeof(struct cudbg_flash_hdr), 0);
310 
311 	return rc;
312 }
313 
314 int
cudbg_read_flash_data(void * handle,void * buf,u32 buf_size)315 cudbg_read_flash_data(void *handle, void *buf, u32 buf_size)
316 {
317 	int rc;
318 	u32 total_hdr_size, data_header_size;
319 	void *payload = NULL;
320 	u32 payload_size = 0;
321 
322 	data_header_size = CUDBG_MAX_ENTITY * sizeof(struct cudbg_entity_hdr) +
323 		sizeof(struct cudbg_hdr);
324 	total_hdr_size = data_header_size + sizeof(struct cudbg_flash_hdr);
325 
326 	/* Copy flash header to buffer */
327 	rc = cudbg_read_flash(handle, buf, total_hdr_size, 0);
328 	if (rc != 0)
329 		goto out;
330 	payload = (char *)buf + total_hdr_size;
331 	payload_size  = buf_size - total_hdr_size;
332 
333 	/* Reading flash data to buf */
334 	rc = cudbg_read_flash(handle, payload, payload_size, 1);
335 	if (rc != 0)
336 		goto out;
337 
338 out:
339 	return rc;
340 }
341 
342 int
cudbg_read_flash(void * handle,void * data,u32 size,int data_flag)343 cudbg_read_flash(void *handle, void *data, u32 size, int data_flag)
344 {
345 	struct cudbg_private *priv = handle;
346 	struct cudbg_init *cudbg_init = &priv->dbg_init;
347 	struct cudbg_flash_sec_info *sec_info = &priv->sec_info;
348 	struct adapter *adap = cudbg_init->adap;
349 	struct cudbg_flash_hdr flash_hdr;
350 	u32 total_hdr_size;
351 	u32 data_hdr_size;
352 	u32 sec_hdr_start_addr;
353 	u32 tmp_size;
354 	u32 data_offset = 0;
355 	u32 i, j;
356 	int rc;
357 
358 	rc = t4_get_flash_params(adap);
359 	if (rc) {
360 		cudbg_init->print(adap->dip, CE_NOTE,"\nGet flash params failed."
361 			"Try Again...readflash\n\n");
362 		return rc;
363 	}
364 
365 	data_hdr_size = CUDBG_MAX_ENTITY * sizeof(struct cudbg_entity_hdr) +
366 			sizeof(struct cudbg_hdr);
367 	total_hdr_size = data_hdr_size + sizeof(struct cudbg_flash_hdr);
368 	sec_hdr_start_addr = CUDBG_SF_SECTOR_SIZE - total_hdr_size;
369 
370 	if (!data_flag) {
371 		/* fill header */
372 		if (!sec_info->max_timestamp) {
373 			/* finding max time stamp because it may
374 			 * have older filled sector also
375 			 */
376 			memset(&flash_hdr, 0, sizeof(struct cudbg_flash_hdr));
377 			rc = read_flash(adap, CUDBG_START_SEC, &flash_hdr,
378 				sizeof(struct cudbg_flash_hdr),
379 				sec_hdr_start_addr);
380 
381 			if (flash_hdr.signature == CUDBG_FL_SIGNATURE) {
382 				sec_info->max_timestamp = flash_hdr.timestamp;
383 			} else {
384 				rc = read_flash(adap, CUDBG_START_SEC + 1,
385 					&flash_hdr,
386 					sizeof(struct cudbg_flash_hdr),
387 					sec_hdr_start_addr);
388 
389 				if (flash_hdr.signature == CUDBG_FL_SIGNATURE)
390 					sec_info->max_timestamp =
391 							flash_hdr.timestamp;
392 				else {
393 					cudbg_init->print(adap->dip, CE_NOTE,
394 							  "\n\tNo cudbg dump "\
395 							  "found in flash\n\n");
396 					return CUDBG_STATUS_NO_SIGNATURE;
397 				}
398 
399 			}
400 
401 			/* finding max sequence number because max sequenced
402 			 * sector has updated header
403 			 */
404 			for (i = CUDBG_START_SEC; i <
405 					CUDBG_SF_MAX_SECTOR; i++) {
406 				memset(&flash_hdr, 0,
407 				       sizeof(struct cudbg_flash_hdr));
408 				rc = read_flash(adap, i, &flash_hdr,
409 						sizeof(struct cudbg_flash_hdr),
410 						sec_hdr_start_addr);
411 
412 				if (flash_hdr.signature == CUDBG_FL_SIGNATURE &&
413 				    sec_info->max_timestamp ==
414 				    flash_hdr.timestamp &&
415 				    sec_info->max_seq_no <=
416 				    flash_hdr.sec_seq_no) {
417 					if (sec_info->max_seq_no ==
418 					    flash_hdr.sec_seq_no) {
419 						if (sec_info->hdr_data_len <
420 						    flash_hdr.data_len)
421 							sec_info->max_seq_sec = i;
422 					} else {
423 						sec_info->max_seq_sec = i;
424 						sec_info->hdr_data_len =
425 							flash_hdr.data_len;
426 					}
427 					sec_info->max_seq_no = flash_hdr.sec_seq_no;
428 				}
429 			}
430 		}
431 		rc = read_flash(adap, sec_info->max_seq_sec,
432 				(struct cudbg_flash_hdr *)data,
433 				size, sec_hdr_start_addr);
434 
435 		if (rc)
436 			cudbg_init->print(adap->dip, CE_NOTE,
437 					  "Read flash header failed, rc %d\n",
438 					  rc);
439 
440 		return rc;
441 	}
442 
443 	/* finding sector sequence sorted */
444 	for (i = 1; i <= sec_info->max_seq_no; i++) {
445 		for (j = CUDBG_START_SEC; j < CUDBG_SF_MAX_SECTOR; j++) {
446 			memset(&flash_hdr, 0, sizeof(struct cudbg_flash_hdr));
447 			rc = read_flash(adap, j, &flash_hdr,
448 				sizeof(struct cudbg_flash_hdr),
449 				sec_hdr_start_addr);
450 
451 			if (flash_hdr.signature ==
452 					CUDBG_FL_SIGNATURE &&
453 					sec_info->max_timestamp ==
454 					flash_hdr.timestamp &&
455 					flash_hdr.sec_seq_no == i) {
456 				if (size + total_hdr_size >
457 						CUDBG_SF_SECTOR_SIZE)
458 					tmp_size = CUDBG_SF_SECTOR_SIZE -
459 						total_hdr_size;
460 				else
461 					tmp_size =  size;
462 
463 				if ((i != sec_info->max_seq_no) ||
464 				    (i == sec_info->max_seq_no &&
465 				    j == sec_info->max_seq_sec)){
466 					/* filling data buffer with sector data
467 					 * except sector header
468 					 */
469 					rc = read_flash(adap, j,
470 							(void *)((char *)data +
471 							data_offset),
472 							tmp_size, 0);
473 					data_offset += (tmp_size);
474 					size -= (tmp_size);
475 					break;
476 				}
477 			}
478 		}
479 	}
480 
481 	return rc;
482 }
483 
484 int
read_flash(struct adapter * adap,u32 start_sec,void * data,u32 size,u32 start_address)485 read_flash(struct adapter *adap, u32 start_sec , void *data, u32 size,
486 	   u32 start_address)
487 {
488 	unsigned int addr, i, n;
489 	int rc;
490 	u32 *ptr = (u32 *)data;
491 	addr = start_sec * CUDBG_SF_SECTOR_SIZE + start_address;
492 	size = size / 4;
493 	for (i = 0; i < size; i += SF_PAGE_SIZE) {
494 		if ((size - i) <  SF_PAGE_SIZE)
495 			n = size - i;
496 		else
497 			n = SF_PAGE_SIZE;
498 		rc = t4_read_flash(adap, addr, n, ptr, 0);
499 		if (rc)
500 			goto out;
501 
502 		addr = addr + (n*4);
503 		ptr += n;
504 	}
505 
506 	return 0;
507 out:
508 	return rc;
509 }
510