1/******************************************************************************
2
3  Copyright (c) 2001-2017, Intel Corporation
4  All rights reserved.
5
6  Redistribution and use in source and binary forms, with or without
7  modification, are permitted provided that the following conditions are met:
8
9   1. Redistributions of source code must retain the above copyright notice,
10      this list of conditions and the following disclaimer.
11
12   2. Redistributions in binary form must reproduce the above copyright
13      notice, this list of conditions and the following disclaimer in the
14      documentation and/or other materials provided with the distribution.
15
16   3. Neither the name of the Intel Corporation nor the names of its
17      contributors may be used to endorse or promote products derived from
18      this software without specific prior written permission.
19
20  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  POSSIBILITY OF SUCH DAMAGE.
31
32******************************************************************************/
33/*$FreeBSD$*/
34
35
36#include "ixgbe.h"
37
38/************************************************************************
39 * ixgbe_bypass_mutex_enter
40 *
41 *   Mutex support for the bypass feature. Using a dual lock
42 *   to facilitate a privileged access to the watchdog update
43 *   over other threads.
44 ************************************************************************/
45static void
46ixgbe_bypass_mutex_enter(struct adapter *adapter)
47{
48	while (atomic_cmpset_int(&adapter->bypass.low, 0, 1) == 0)
49		usec_delay(3000);
50	while (atomic_cmpset_int(&adapter->bypass.high, 0, 1) == 0)
51		usec_delay(3000);
52	return;
53} /* ixgbe_bypass_mutex_enter */
54
55/************************************************************************
56 * ixgbe_bypass_mutex_clear
57 ************************************************************************/
58static void
59ixgbe_bypass_mutex_clear(struct adapter *adapter)
60{
61	while (atomic_cmpset_int(&adapter->bypass.high, 1, 0) == 0)
62		usec_delay(6000);
63	while (atomic_cmpset_int(&adapter->bypass.low, 1, 0) == 0)
64		usec_delay(6000);
65	return;
66} /* ixgbe_bypass_mutex_clear */
67
68/************************************************************************
69 * ixgbe_bypass_wd_mutex_enter
70 *
71 *   Watchdog entry is allowed to simply grab the high priority
72 ************************************************************************/
73static void
74ixgbe_bypass_wd_mutex_enter(struct adapter *adapter)
75{
76	while (atomic_cmpset_int(&adapter->bypass.high, 0, 1) == 0)
77		usec_delay(3000);
78	return;
79} /* ixgbe_bypass_wd_mutex_enter */
80
81/************************************************************************
82 * ixgbe_bypass_wd_mutex_clear
83 ************************************************************************/
84static void
85ixgbe_bypass_wd_mutex_clear(struct adapter *adapter)
86{
87	while (atomic_cmpset_int(&adapter->bypass.high, 1, 0) == 0)
88		usec_delay(6000);
89	return;
90} /* ixgbe_bypass_wd_mutex_clear */
91
92/************************************************************************
93 * ixgbe_get_bypass_time
94 ************************************************************************/
95static void
96ixgbe_get_bypass_time(u32 *year, u32 *sec)
97{
98	struct timespec current;
99
100	*year = 1970;           /* time starts at 01/01/1970 */
101	nanotime(&current);
102	*sec = current.tv_sec;
103
104	while(*sec > SEC_THIS_YEAR(*year)) {
105		*sec -= SEC_THIS_YEAR(*year);
106		(*year)++;
107	}
108} /* ixgbe_get_bypass_time */
109
110/************************************************************************
111 * ixgbe_bp_version
112 *
113 *   Display the feature version
114 ************************************************************************/
115static int
116ixgbe_bp_version(SYSCTL_HANDLER_ARGS)
117{
118	struct adapter  *adapter = (struct adapter *) arg1;
119	struct ixgbe_hw *hw = &adapter->hw;
120	int             error = 0;
121	static int      version = 0;
122	u32             cmd;
123
124	ixgbe_bypass_mutex_enter(adapter);
125	cmd = BYPASS_PAGE_CTL2 | BYPASS_WE;
126	cmd |= (BYPASS_EEPROM_VER_ADD << BYPASS_CTL2_OFFSET_SHIFT) &
127	    BYPASS_CTL2_OFFSET_M;
128	if ((error = hw->mac.ops.bypass_rw(hw, cmd, &version) != 0))
129		goto err;
130	msec_delay(100);
131	cmd &= ~BYPASS_WE;
132	if ((error = hw->mac.ops.bypass_rw(hw, cmd, &version) != 0))
133		goto err;
134	ixgbe_bypass_mutex_clear(adapter);
135	version &= BYPASS_CTL2_DATA_M;
136	error = sysctl_handle_int(oidp, &version, 0, req);
137	return (error);
138err:
139	ixgbe_bypass_mutex_clear(adapter);
140	return (error);
141
142} /* ixgbe_bp_version */
143
144/************************************************************************
145 * ixgbe_bp_set_state
146 *
147 *   Show/Set the Bypass State:
148 *	1 = NORMAL
149 *	2 = BYPASS
150 *	3 = ISOLATE
151 *
152 *	With no argument the state is displayed,
153 *	passing a value will set it.
154 ************************************************************************/
155static int
156ixgbe_bp_set_state(SYSCTL_HANDLER_ARGS)
157{
158	struct adapter  *adapter = (struct adapter *) arg1;
159	struct ixgbe_hw *hw = &adapter->hw;
160	int             error = 0;
161	static int      state = 0;
162
163	/* Get the current state */
164	ixgbe_bypass_mutex_enter(adapter);
165	error = hw->mac.ops.bypass_rw(hw,
166	    BYPASS_PAGE_CTL0, &state);
167	ixgbe_bypass_mutex_clear(adapter);
168	if (error != 0)
169		return (error);
170	state = (state >> BYPASS_STATUS_OFF_SHIFT) & 0x3;
171
172	error = sysctl_handle_int(oidp, &state, 0, req);
173	if ((error != 0) || (req->newptr == NULL))
174		return (error);
175
176	/* Sanity check new state */
177	switch (state) {
178	case BYPASS_NORM:
179	case BYPASS_BYPASS:
180	case BYPASS_ISOLATE:
181		break;
182	default:
183		return (EINVAL);
184	}
185	ixgbe_bypass_mutex_enter(adapter);
186	if ((error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
187	    BYPASS_MODE_OFF_M, state) != 0))
188		goto out;
189	/* Set AUTO back on so FW can receive events */
190	error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
191	    BYPASS_MODE_OFF_M, BYPASS_AUTO);
192out:
193	ixgbe_bypass_mutex_clear(adapter);
194	usec_delay(6000);
195	return (error);
196} /* ixgbe_bp_set_state */
197
198/************************************************************************
199 * The following routines control the operational
200 * "rules" of the feature, what behavior will occur
201 * when particular events occur.
202 * 	Values are:
203 *		0 - no change for the event (NOP)
204 *		1 - go to Normal operation
205 *		2 - go to Bypass operation
206 *		3 - go to Isolate operation
207 * Calling the entry with no argument just displays
208 * the current rule setting.
209 ************************************************************************/
210
211/************************************************************************
212 * ixgbe_bp_timeout
213 *
214 * This is to set the Rule for the watchdog,
215 * not the actual watchdog timeout value.
216 ************************************************************************/
217static int
218ixgbe_bp_timeout(SYSCTL_HANDLER_ARGS)
219{
220	struct adapter  *adapter = (struct adapter *) arg1;
221	struct ixgbe_hw *hw = &adapter->hw;
222	int             error = 0;
223	static int      timeout = 0;
224
225	/* Get the current value */
226	ixgbe_bypass_mutex_enter(adapter);
227	error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &timeout);
228	ixgbe_bypass_mutex_clear(adapter);
229	if (error)
230		return (error);
231	timeout = (timeout >> BYPASS_WDTIMEOUT_SHIFT) & 0x3;
232
233	error = sysctl_handle_int(oidp, &timeout, 0, req);
234	if ((error) || (req->newptr == NULL))
235		return (error);
236
237	/* Sanity check on the setting */
238	switch (timeout) {
239	case BYPASS_NOP:
240	case BYPASS_NORM:
241	case BYPASS_BYPASS:
242	case BYPASS_ISOLATE:
243		break;
244	default:
245		return (EINVAL);
246	}
247
248	/* Set the new state */
249	ixgbe_bypass_mutex_enter(adapter);
250	error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
251	    BYPASS_WDTIMEOUT_M, timeout << BYPASS_WDTIMEOUT_SHIFT);
252	ixgbe_bypass_mutex_clear(adapter);
253	usec_delay(6000);
254	return (error);
255} /* ixgbe_bp_timeout */
256
257/************************************************************************
258 * ixgbe_bp_main_on
259 ************************************************************************/
260static int
261ixgbe_bp_main_on(SYSCTL_HANDLER_ARGS)
262{
263	struct adapter  *adapter = (struct adapter *) arg1;
264	struct ixgbe_hw *hw = &adapter->hw;
265	int             error = 0;
266	static int      main_on = 0;
267
268	ixgbe_bypass_mutex_enter(adapter);
269	error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &main_on);
270	main_on = (main_on >> BYPASS_MAIN_ON_SHIFT) & 0x3;
271	ixgbe_bypass_mutex_clear(adapter);
272	if (error)
273		return (error);
274
275	error = sysctl_handle_int(oidp, &main_on, 0, req);
276	if ((error) || (req->newptr == NULL))
277		return (error);
278
279	/* Sanity check on the setting */
280	switch (main_on) {
281	case BYPASS_NOP:
282	case BYPASS_NORM:
283	case BYPASS_BYPASS:
284	case BYPASS_ISOLATE:
285		break;
286	default:
287		return (EINVAL);
288	}
289
290	/* Set the new state */
291	ixgbe_bypass_mutex_enter(adapter);
292	error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
293	    BYPASS_MAIN_ON_M, main_on << BYPASS_MAIN_ON_SHIFT);
294	ixgbe_bypass_mutex_clear(adapter);
295	usec_delay(6000);
296	return (error);
297} /* ixgbe_bp_main_on */
298
299/************************************************************************
300 * ixgbe_bp_main_off
301 ************************************************************************/
302static int
303ixgbe_bp_main_off(SYSCTL_HANDLER_ARGS)
304{
305	struct adapter  *adapter = (struct adapter *) arg1;
306	struct ixgbe_hw *hw = &adapter->hw;
307	int             error = 0;
308	static int      main_off = 0;
309
310	ixgbe_bypass_mutex_enter(adapter);
311	error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &main_off);
312	ixgbe_bypass_mutex_clear(adapter);
313	if (error)
314		return (error);
315	main_off = (main_off >> BYPASS_MAIN_OFF_SHIFT) & 0x3;
316
317	error = sysctl_handle_int(oidp, &main_off, 0, req);
318	if ((error) || (req->newptr == NULL))
319		return (error);
320
321	/* Sanity check on the setting */
322	switch (main_off) {
323	case BYPASS_NOP:
324	case BYPASS_NORM:
325	case BYPASS_BYPASS:
326	case BYPASS_ISOLATE:
327		break;
328	default:
329		return (EINVAL);
330	}
331
332	/* Set the new state */
333	ixgbe_bypass_mutex_enter(adapter);
334	error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
335	    BYPASS_MAIN_OFF_M, main_off << BYPASS_MAIN_OFF_SHIFT);
336	ixgbe_bypass_mutex_clear(adapter);
337	usec_delay(6000);
338	return (error);
339} /* ixgbe_bp_main_off */
340
341/************************************************************************
342 * ixgbe_bp_aux_on
343 ************************************************************************/
344static int
345ixgbe_bp_aux_on(SYSCTL_HANDLER_ARGS)
346{
347	struct adapter  *adapter = (struct adapter *) arg1;
348	struct ixgbe_hw *hw = &adapter->hw;
349	int             error = 0;
350	static int      aux_on = 0;
351
352	ixgbe_bypass_mutex_enter(adapter);
353	error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &aux_on);
354	ixgbe_bypass_mutex_clear(adapter);
355	if (error)
356		return (error);
357	aux_on = (aux_on >> BYPASS_AUX_ON_SHIFT) & 0x3;
358
359	error = sysctl_handle_int(oidp, &aux_on, 0, req);
360	if ((error) || (req->newptr == NULL))
361		return (error);
362
363	/* Sanity check on the setting */
364	switch (aux_on) {
365	case BYPASS_NOP:
366	case BYPASS_NORM:
367	case BYPASS_BYPASS:
368	case BYPASS_ISOLATE:
369		break;
370	default:
371		return (EINVAL);
372	}
373
374	/* Set the new state */
375	ixgbe_bypass_mutex_enter(adapter);
376	error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
377	    BYPASS_AUX_ON_M, aux_on << BYPASS_AUX_ON_SHIFT);
378	ixgbe_bypass_mutex_clear(adapter);
379	usec_delay(6000);
380	return (error);
381} /* ixgbe_bp_aux_on */
382
383/************************************************************************
384 * ixgbe_bp_aux_off
385 ************************************************************************/
386static int
387ixgbe_bp_aux_off(SYSCTL_HANDLER_ARGS)
388{
389	struct adapter  *adapter = (struct adapter *) arg1;
390	struct ixgbe_hw *hw = &adapter->hw;
391	int             error = 0;
392	static int      aux_off = 0;
393
394	ixgbe_bypass_mutex_enter(adapter);
395	error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &aux_off);
396	ixgbe_bypass_mutex_clear(adapter);
397	if (error)
398		return (error);
399	aux_off = (aux_off >> BYPASS_AUX_OFF_SHIFT) & 0x3;
400
401	error = sysctl_handle_int(oidp, &aux_off, 0, req);
402	if ((error) || (req->newptr == NULL))
403		return (error);
404
405	/* Sanity check on the setting */
406	switch (aux_off) {
407	case BYPASS_NOP:
408	case BYPASS_NORM:
409	case BYPASS_BYPASS:
410	case BYPASS_ISOLATE:
411		break;
412	default:
413		return (EINVAL);
414	}
415
416	/* Set the new state */
417	ixgbe_bypass_mutex_enter(adapter);
418	error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
419	    BYPASS_AUX_OFF_M, aux_off << BYPASS_AUX_OFF_SHIFT);
420	ixgbe_bypass_mutex_clear(adapter);
421	usec_delay(6000);
422	return (error);
423} /* ixgbe_bp_aux_off */
424
425/************************************************************************
426 * ixgbe_bp_wd_set - Set the Watchdog timer value
427 *
428 *   Valid settings are:
429 *	- 0 will disable the watchdog
430 *	- 1, 2, 3, 4, 8, 16, 32
431 *	- anything else is invalid and will be ignored
432 ************************************************************************/
433static int
434ixgbe_bp_wd_set(SYSCTL_HANDLER_ARGS)
435{
436	struct adapter  *adapter = (struct adapter *) arg1;
437	struct ixgbe_hw *hw = &adapter->hw;
438	int             error, tmp;
439	static int      timeout = 0;
440	u32             mask, arg;
441
442	/* Get the current hardware value */
443	ixgbe_bypass_mutex_enter(adapter);
444	error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL0, &tmp);
445	ixgbe_bypass_mutex_clear(adapter);
446	if (error)
447		return (error);
448	/*
449	 * If armed keep the displayed value,
450	 * else change the display to zero.
451	 */
452	if ((tmp & (0x1 << BYPASS_WDT_ENABLE_SHIFT)) == 0)
453		timeout = 0;
454
455	error = sysctl_handle_int(oidp, &timeout, 0, req);
456	if ((error) || (req->newptr == NULL))
457		return (error);
458
459	arg = 0x1 << BYPASS_WDT_ENABLE_SHIFT;
460	mask = BYPASS_WDT_ENABLE_M | BYPASS_WDT_VALUE_M;
461	switch (timeout) {
462	case 0: /* disables the timer */
463		arg = BYPASS_PAGE_CTL0;
464		mask = BYPASS_WDT_ENABLE_M;
465		break;
466	case 1:
467		arg |= BYPASS_WDT_1_5 << BYPASS_WDT_TIME_SHIFT;
468		break;
469	case 2:
470		arg |= BYPASS_WDT_2 << BYPASS_WDT_TIME_SHIFT;
471		break;
472	case 3:
473		arg |= BYPASS_WDT_3 << BYPASS_WDT_TIME_SHIFT;
474		break;
475	case 4:
476		arg |= BYPASS_WDT_4 << BYPASS_WDT_TIME_SHIFT;
477		break;
478	case 8:
479		arg |= BYPASS_WDT_8 << BYPASS_WDT_TIME_SHIFT;
480		break;
481	case 16:
482		arg |= BYPASS_WDT_16 << BYPASS_WDT_TIME_SHIFT;
483		break;
484	case 32:
485		arg |= BYPASS_WDT_32 << BYPASS_WDT_TIME_SHIFT;
486		break;
487	default:
488		return (EINVAL);
489	}
490
491	/* Set the new watchdog */
492	ixgbe_bypass_mutex_enter(adapter);
493	error = hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL0, mask, arg);
494	ixgbe_bypass_mutex_clear(adapter);
495
496	return (error);
497} /* ixgbe_bp_wd_set */
498
499/************************************************************************
500 * ixgbe_bp_wd_reset - Reset the Watchdog timer
501 *
502 *    To activate this it must be called with any argument.
503 ************************************************************************/
504static int
505ixgbe_bp_wd_reset(SYSCTL_HANDLER_ARGS)
506{
507	struct adapter  *adapter = (struct adapter *) arg1;
508	struct ixgbe_hw *hw = &adapter->hw;
509	u32             sec, year;
510	int             cmd, count = 0, error = 0;
511	int             reset_wd = 0;
512
513	error = sysctl_handle_int(oidp, &reset_wd, 0, req);
514	if ((error) || (req->newptr == NULL))
515		return (error);
516
517	cmd = BYPASS_PAGE_CTL1 | BYPASS_WE | BYPASS_CTL1_WDT_PET;
518
519	/* Resync the FW time while writing to CTL1 anyway */
520	ixgbe_get_bypass_time(&year, &sec);
521
522	cmd |= (sec & BYPASS_CTL1_TIME_M) | BYPASS_CTL1_VALID;
523	cmd |= BYPASS_CTL1_OFFTRST;
524
525	ixgbe_bypass_wd_mutex_enter(adapter);
526	error = hw->mac.ops.bypass_rw(hw, cmd, &reset_wd);
527
528	/* Read until it matches what we wrote, or we time out */
529	do {
530		if (count++ > 10) {
531			error = IXGBE_BYPASS_FW_WRITE_FAILURE;
532			break;
533		}
534		error = hw->mac.ops.bypass_rw(hw, BYPASS_PAGE_CTL1, &reset_wd);
535		if (error != 0) {
536			error = IXGBE_ERR_INVALID_ARGUMENT;
537			break;
538		}
539	} while (!hw->mac.ops.bypass_valid_rd(cmd, reset_wd));
540
541	reset_wd = 0;
542	ixgbe_bypass_wd_mutex_clear(adapter);
543	return (error);
544} /* ixgbe_bp_wd_reset */
545
546/************************************************************************
547 * ixgbe_bp_log - Display the bypass log
548 *
549 *   You must pass a non-zero arg to sysctl
550 ************************************************************************/
551static int
552ixgbe_bp_log(SYSCTL_HANDLER_ARGS)
553{
554	struct adapter             *adapter = (struct adapter *) arg1;
555	struct ixgbe_hw            *hw = &adapter->hw;
556	u32                        cmd, base, head;
557	u32                        log_off, count = 0;
558	static int                 status = 0;
559	u8                         data;
560	struct ixgbe_bypass_eeprom eeprom[BYPASS_MAX_LOGS];
561	int                        i, error = 0;
562
563	error = sysctl_handle_int(oidp, &status, 0, req);
564	if ((error) || (req->newptr == NULL))
565		return (error);
566
567	/* Keep the log display single-threaded */
568	while (atomic_cmpset_int(&adapter->bypass.log, 0, 1) == 0)
569		usec_delay(3000);
570
571	ixgbe_bypass_mutex_enter(adapter);
572
573	/* Find Current head of the log eeprom offset */
574	cmd = BYPASS_PAGE_CTL2 | BYPASS_WE;
575	cmd |= (0x1 << BYPASS_CTL2_OFFSET_SHIFT) & BYPASS_CTL2_OFFSET_M;
576	error = hw->mac.ops.bypass_rw(hw, cmd, &status);
577	if (error)
578		goto unlock_err;
579
580	/* wait for the write to stick */
581	msec_delay(100);
582
583	/* Now read the results */
584	cmd &= ~BYPASS_WE;
585	error = hw->mac.ops.bypass_rw(hw, cmd, &status);
586	if (error)
587		goto unlock_err;
588
589	ixgbe_bypass_mutex_clear(adapter);
590
591	base = status & BYPASS_CTL2_DATA_M;
592	head = (status & BYPASS_CTL2_HEAD_M) >> BYPASS_CTL2_HEAD_SHIFT;
593
594	/* address of the first log */
595	log_off = base + (head * 5);
596
597	/* extract all the log entries */
598	while (count < BYPASS_MAX_LOGS) {
599		eeprom[count].logs = 0;
600		eeprom[count].actions = 0;
601
602		/* Log 5 bytes store in on u32 and a u8 */
603		for (i = 0; i < 4; i++) {
604			ixgbe_bypass_mutex_enter(adapter);
605			error = hw->mac.ops.bypass_rd_eep(hw, log_off + i,
606			    &data);
607			ixgbe_bypass_mutex_clear(adapter);
608			if (error)
609				return (EINVAL);
610			eeprom[count].logs += data << (8 * i);
611		}
612
613		ixgbe_bypass_mutex_enter(adapter);
614		error = hw->mac.ops.bypass_rd_eep(hw,
615		    log_off + i, &eeprom[count].actions);
616		ixgbe_bypass_mutex_clear(adapter);
617		if (error)
618			return (EINVAL);
619
620		/* Quit if not a unread log */
621		if (!(eeprom[count].logs & BYPASS_LOG_CLEAR_M))
622			break;
623		/*
624		 * Log looks good so store the address where it's
625		 * Unread Log bit is so we can clear it after safely
626		 * pulling out all of the log data.
627		 */
628		eeprom[count].clear_off = log_off;
629
630		count++;
631		head = head ? head - 1 : BYPASS_MAX_LOGS;
632		log_off = base + (head * 5);
633	}
634
635	/* reverse order (oldest first) for output */
636	while (count--) {
637		int year;
638		u32 mon, days, hours, min, sec;
639		u32 time = eeprom[count].logs & BYPASS_LOG_TIME_M;
640		u32 event = (eeprom[count].logs & BYPASS_LOG_EVENT_M) >>
641		    BYPASS_LOG_EVENT_SHIFT;
642		u8 action =  eeprom[count].actions & BYPASS_LOG_ACTION_M;
643		u16 day_mon[2][13] = {
644		  {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
645		  {0, 31, 59, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}
646		};
647		char *event_str[] = {"unknown", "main on", "aux on",
648		    "main off", "aux off", "WDT", "user" };
649		char *action_str[] = {"ignore", "normal", "bypass", "isolate",};
650
651		/* verify vaild data  1 - 6 */
652		if (event < BYPASS_EVENT_MAIN_ON || event > BYPASS_EVENT_USR)
653			event = 0;
654
655		/*
656		 * time is in sec's this year, so convert to something
657		 * printable.
658		 */
659		ixgbe_get_bypass_time(&year, &sec);
660		days = time / SEC_PER_DAY;
661		for (i = 11; days < day_mon[LEAP_YR(year)][i]; i--)
662			continue;
663		mon = i + 1;    /* display month as 1-12 */
664		time -= (day_mon[LEAP_YR(year)][i] * SEC_PER_DAY);
665		days = (time / SEC_PER_DAY) + 1;  /* first day is 1 */
666		time %= SEC_PER_DAY;
667		hours = time / (60 * 60);
668		time %= (60 * 60);
669		min = time / 60;
670		sec = time % 60;
671		device_printf(adapter->dev,
672		    "UT %02d/%02d %02d:%02d:%02d %8.8s -> %7.7s\n",
673		    mon, days, hours, min, sec, event_str[event],
674		    action_str[action]);
675		cmd = BYPASS_PAGE_CTL2 | BYPASS_WE | BYPASS_CTL2_RW;
676		cmd |= ((eeprom[count].clear_off + 3)
677		    << BYPASS_CTL2_OFFSET_SHIFT) & BYPASS_CTL2_OFFSET_M;
678		cmd |= ((eeprom[count].logs & ~BYPASS_LOG_CLEAR_M) >> 24);
679
680		ixgbe_bypass_mutex_enter(adapter);
681
682		error = hw->mac.ops.bypass_rw(hw, cmd, &status);
683
684		/* wait for the write to stick */
685		msec_delay(100);
686
687		ixgbe_bypass_mutex_clear(adapter);
688
689		if (error)
690			return (EINVAL);
691	}
692
693	status = 0; /* reset */
694	/* Another log command can now run */
695	while (atomic_cmpset_int(&adapter->bypass.log, 1, 0) == 0)
696		usec_delay(3000);
697	return (error);
698
699unlock_err:
700	ixgbe_bypass_mutex_clear(adapter);
701	status = 0; /* reset */
702	while (atomic_cmpset_int(&adapter->bypass.log, 1, 0) == 0)
703		usec_delay(3000);
704	return (EINVAL);
705} /* ixgbe_bp_log */
706
707/************************************************************************
708 * ixgbe_bypass_init - Set up infrastructure for the bypass feature
709 *
710 *   Do time and sysctl initialization here.  This feature is
711 *   only enabled for the first port of a bypass adapter.
712 ************************************************************************/
713void
714ixgbe_bypass_init(struct adapter *adapter)
715{
716	struct ixgbe_hw        *hw = &adapter->hw;
717	device_t               dev = adapter->dev;
718	struct sysctl_oid      *bp_node;
719	struct sysctl_oid_list *bp_list;
720	u32                    mask, value, sec, year;
721
722	if (!(adapter->feat_cap & IXGBE_FEATURE_BYPASS))
723		return;
724
725	/* First set up time for the hardware */
726	ixgbe_get_bypass_time(&year, &sec);
727
728	mask = BYPASS_CTL1_TIME_M
729	     | BYPASS_CTL1_VALID_M
730	     | BYPASS_CTL1_OFFTRST_M;
731
732	value = (sec & BYPASS_CTL1_TIME_M)
733	      | BYPASS_CTL1_VALID
734	      | BYPASS_CTL1_OFFTRST;
735
736	ixgbe_bypass_mutex_enter(adapter);
737	hw->mac.ops.bypass_set(hw, BYPASS_PAGE_CTL1, mask, value);
738	ixgbe_bypass_mutex_clear(adapter);
739
740	/* Now set up the SYSCTL infrastructure */
741
742	/*
743	 * The log routine is kept separate from the other
744	 * children so a general display command like:
745	 * `sysctl dev.ix.0.bypass` will not show the log.
746	 */
747	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
748	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
749	    OID_AUTO, "bypass_log",
750	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
751	    adapter, 0, ixgbe_bp_log, "I", "Bypass Log");
752
753	/* All other setting are hung from the 'bypass' node */
754	bp_node = SYSCTL_ADD_NODE(device_get_sysctl_ctx(dev),
755	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
756	    OID_AUTO, "bypass", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Bypass");
757
758	bp_list = SYSCTL_CHILDREN(bp_node);
759
760	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
761	    OID_AUTO, "version", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
762	    adapter, 0, ixgbe_bp_version, "I", "Bypass Version");
763
764	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
765	    OID_AUTO, "state", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
766	    adapter, 0, ixgbe_bp_set_state, "I", "Bypass State");
767
768	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
769	    OID_AUTO, "timeout", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
770	    adapter, 0, ixgbe_bp_timeout, "I", "Bypass Timeout");
771
772	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
773	    OID_AUTO, "main_on", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
774	    adapter, 0, ixgbe_bp_main_on, "I", "Bypass Main On");
775
776	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
777	    OID_AUTO, "main_off", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
778	    adapter, 0, ixgbe_bp_main_off, "I", "Bypass Main Off");
779
780	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
781	    OID_AUTO, "aux_on", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
782	    adapter, 0, ixgbe_bp_aux_on, "I", "Bypass Aux On");
783
784	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
785	    OID_AUTO, "aux_off", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
786	    adapter, 0, ixgbe_bp_aux_off, "I", "Bypass Aux Off");
787
788	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
789	    OID_AUTO, "wd_set", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
790	    adapter, 0, ixgbe_bp_wd_set, "I", "Set BP Watchdog");
791
792	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), bp_list,
793	    OID_AUTO, "wd_reset", CTLTYPE_INT | CTLFLAG_WR | CTLFLAG_NEEDGIANT,
794	    adapter, 0, ixgbe_bp_wd_reset, "S", "Bypass WD Reset");
795
796	adapter->feat_en |= IXGBE_FEATURE_BYPASS;
797} /* ixgbe_bypass_init */
798
799