1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2004-07 Applied Micro Circuits Corporation.
5 * Copyright (c) 2004-05 Vinod Kashyap
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 *	$FreeBSD$
30 */
31
32/*
33 * AMCC'S 3ware driver for 9000 series storage controllers.
34 *
35 * Author: Vinod Kashyap
36 * Modifications by: Adam Radford
37 * Modifications by: Manjunath Ranganathaiah
38 */
39
40
41/*
42 * Common Layer miscellaneous functions.
43 */
44
45
46#include "tw_osl_share.h"
47#include "tw_cl_share.h"
48#include "tw_cl_fwif.h"
49#include "tw_cl_ioctl.h"
50#include "tw_cl.h"
51#include "tw_cl_externs.h"
52#include "tw_osl_ioctl.h"
53
54
55
56/* AEN severity table. */
57TW_INT8	*tw_cli_severity_string_table[] = {
58	"None",
59	TW_CL_SEVERITY_ERROR_STRING,
60	TW_CL_SEVERITY_WARNING_STRING,
61	TW_CL_SEVERITY_INFO_STRING,
62	TW_CL_SEVERITY_DEBUG_STRING,
63	""
64};
65
66
67
68/*
69 * Function name:	tw_cli_drain_complete_queue
70 * Description:		This function gets called during a controller reset.
71 *			It errors back to the OS Layer, all those requests that
72 *			are in the complete queue, at the time of the reset.
73 *			Any CL internal requests will be simply freed.
74 *
75 * Input:		ctlr	-- ptr to CL internal ctlr context
76 * Output:		None
77 * Return value:	None
78 */
79TW_VOID
80tw_cli_drain_complete_queue(struct tw_cli_ctlr_context *ctlr)
81{
82	struct tw_cli_req_context	*req;
83	struct tw_cl_req_packet		*req_pkt;
84
85	tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
86
87	/* Walk the busy queue. */
88	while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_COMPLETE_Q)) !=
89		TW_CL_NULL) {
90		if (req->flags & TW_CLI_REQ_FLAGS_INTERNAL) {
91			/*
92			 * It's an internal request.  Set the appropriate
93			 * error and call the CL internal callback if there's
94			 * one.  If the request originator is polling for
95			 * completion, he should be checking req->error to
96			 * determine that the request did not go through.
97			 * The request originators are responsible for the
98			 * clean-up.
99			 */
100			req->error_code = TW_CL_ERR_REQ_BUS_RESET;
101			if (req->tw_cli_callback)
102				req->tw_cli_callback(req);
103		} else if (req->flags & TW_CLI_REQ_FLAGS_PASSTHRU) {
104			/* It's a passthru request.  Complete it. */
105			if ((req_pkt = req->orig_req) != TW_CL_NULL) {
106				req_pkt->status = TW_CL_ERR_REQ_BUS_RESET;
107
108				if (req_pkt->tw_osl_callback)
109					req_pkt->tw_osl_callback(req->req_handle);
110			}
111			tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
112		} else {
113			/* It's an external (SCSI) request.  Add it to the reset queue. */
114			tw_osl_untimeout(req->req_handle);
115			tw_cli_req_q_insert_tail(req, TW_CLI_RESET_Q);
116		}
117	} /* End of while loop */
118}
119
120
121
122/*
123 * Function name:	tw_cli_drain_busy_queue
124 * Description:		This function gets called during a controller reset.
125 *			It errors back to the OS Layer, all those requests that
126 *			were pending with the firmware, at the time of the
127 *			reset.
128 *
129 * Input:		ctlr	-- ptr to CL internal ctlr context
130 * Output:		None
131 * Return value:	None
132 */
133TW_VOID
134tw_cli_drain_busy_queue(struct tw_cli_ctlr_context *ctlr)
135{
136	struct tw_cli_req_context	*req;
137	struct tw_cl_req_packet		*req_pkt;
138
139	tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
140
141	/* Walk the busy queue. */
142	while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_BUSY_Q)) !=
143		TW_CL_NULL) {
144		if (req->flags & TW_CLI_REQ_FLAGS_INTERNAL) {
145			/*
146			 * It's an internal request.  Set the appropriate
147			 * error and call the CL internal callback if there's
148			 * one.  If the request originator is polling for
149			 * completion, he should be checking req->error to
150			 * determine that the request did not go through.
151			 * The request originators are responsible for the
152			 * clean-up.
153			 */
154			req->error_code = TW_CL_ERR_REQ_BUS_RESET;
155			if (req->tw_cli_callback)
156				req->tw_cli_callback(req);
157		} else if (req->flags & TW_CLI_REQ_FLAGS_PASSTHRU) {
158			/* It's a passthru request.  Complete it. */
159			if ((req_pkt = req->orig_req) != TW_CL_NULL) {
160				req_pkt->status = TW_CL_ERR_REQ_BUS_RESET;
161
162				if (req_pkt->tw_osl_callback)
163					req_pkt->tw_osl_callback(req->req_handle);
164			}
165			tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
166		} else {
167			/* It's an external (SCSI) request.  Add it to the reset queue. */
168			tw_osl_untimeout(req->req_handle);
169			tw_cli_req_q_insert_tail(req, TW_CLI_RESET_Q);
170		}
171	} /* End of while loop */
172}
173
174
175
176/*
177 * Function name:	tw_cli_drain_pending_queue
178 * Description:		This function gets called during a controller reset.
179 *			It errors back to the OS Layer, all those requests that
180 *			were in the pending queue, at the time of the reset.
181 *
182 * Input:		ctlr	-- ptr to CL internal ctlr context
183 * Output:		None
184 * Return value:	None
185 */
186
187TW_VOID
188tw_cli_drain_pending_queue(struct tw_cli_ctlr_context *ctlr)
189{
190	struct tw_cli_req_context	*req;
191	struct tw_cl_req_packet		*req_pkt;
192
193	tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
194
195	/*
196	 * Pull requests off the pending queue, and complete them.
197	 */
198	while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_PENDING_Q)) !=
199		TW_CL_NULL) {
200		if (req->flags & TW_CLI_REQ_FLAGS_INTERNAL) {
201			/*
202			 * It's an internal request.  Set the appropriate
203			 * error and call the CL internal callback if there's
204			 * one.  If the request originator is polling for
205			 * completion, he should be checking req->error to
206			 * determine that the request did not go through.
207			 * The request originators are responsible for the
208			 * clean-up.
209			 */
210			req->error_code = TW_CL_ERR_REQ_BUS_RESET;
211			if (req->tw_cli_callback)
212				req->tw_cli_callback(req);
213		} else if (req->flags & TW_CLI_REQ_FLAGS_PASSTHRU) {
214			/* It's a passthru request.  Complete it. */
215			if ((req_pkt = req->orig_req) != TW_CL_NULL) {
216				req_pkt->status = TW_CL_ERR_REQ_BUS_RESET;
217
218				if (req_pkt->tw_osl_callback)
219					req_pkt->tw_osl_callback(req->req_handle);
220			}
221			tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
222		} else {
223			/* It's an external (SCSI) request.  Add it to the reset queue. */
224			tw_osl_untimeout(req->req_handle);
225			tw_cli_req_q_insert_tail(req, TW_CLI_RESET_Q);
226		}
227	} /* End of while loop */
228}
229
230
231
232/*
233 * Function name:	tw_cli_drain_response_queue
234 * Description:		Drain the controller response queue.
235 *
236 * Input:		ctlr	-- ptr to per ctlr structure
237 * Output:		None
238 * Return value:	0	-- success
239 *			non-zero-- failure
240 */
241TW_INT32
242tw_cli_drain_response_queue(struct tw_cli_ctlr_context *ctlr)
243{
244	TW_UINT32	resp;
245	TW_UINT32	status_reg;
246
247	tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
248
249	for (;;) {
250		status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr->ctlr_handle);
251
252		if (status_reg & TWA_STATUS_RESPONSE_QUEUE_EMPTY)
253			return(TW_OSL_ESUCCESS); /* no more response queue entries */
254
255		resp = TW_CLI_READ_RESPONSE_QUEUE(ctlr->ctlr_handle);
256	}
257}
258
259
260
261/*
262 * Function name:	tw_cli_find_response
263 * Description:		Find a particular response in the ctlr response queue.
264 *
265 * Input:		ctlr	-- ptr to per ctlr structure
266 *			req_id	-- request id of the response to look for
267 * Output:		None
268 * Return value:	0	-- success
269 *			non-zero-- failure
270 */
271TW_INT32
272tw_cli_find_response(struct tw_cli_ctlr_context *ctlr, TW_INT32 req_id)
273{
274	TW_UINT32	resp;
275	TW_INT32	resp_id;
276	TW_UINT32	status_reg;
277
278	tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
279
280	for (;;) {
281		status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr->ctlr_handle);
282
283		if (status_reg & TWA_STATUS_RESPONSE_QUEUE_EMPTY)
284			return(TW_OSL_ENOTTY); /* no more response queue entries */
285
286		if (ctlr->device_id == TW_CL_DEVICE_ID_9K) {
287			resp = TW_CLI_READ_RESPONSE_QUEUE(ctlr->ctlr_handle);
288			resp_id = GET_RESP_ID(resp);
289		} else {
290			resp = TW_CLI_READ_LARGE_RESPONSE_QUEUE(
291				ctlr->ctlr_handle);
292			resp_id = GET_LARGE_RESP_ID(resp);
293		}
294		if (resp_id == req_id)
295			return(TW_OSL_ESUCCESS); /* found the req_id */
296	}
297}
298
299
300
301/*
302 * Function name:	tw_cli_drain_aen_queue
303 * Description:		Fetches all un-retrieved AEN's posted by fw.
304 *
305 * Input:		ctlr	-- ptr to CL internal ctlr context
306 * Output:		None
307 * Return value:	0	-- success
308 *			non-zero-- failure
309 */
310TW_INT32
311tw_cli_drain_aen_queue(struct tw_cli_ctlr_context *ctlr)
312{
313	struct tw_cli_req_context	*req;
314	struct tw_cl_command_header	*cmd_hdr;
315	TW_TIME				end_time;
316	TW_UINT16			aen_code;
317	TW_INT32			error;
318
319	tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
320
321	for (;;) {
322		if ((req = tw_cli_get_request(ctlr
323			)) == TW_CL_NULL) {
324			error = TW_OSL_EBUSY;
325			break;
326		}
327
328		req->flags |= TW_CLI_REQ_FLAGS_INTERNAL;
329		req->tw_cli_callback = TW_CL_NULL;
330		if ((error = tw_cli_send_scsi_cmd(req,
331				0x03 /* REQUEST_SENSE */))) {
332			tw_cli_dbg_printf(1, ctlr->ctlr_handle,
333				tw_osl_cur_func(),
334				"Cannot send command to fetch aen");
335			break;
336		}
337
338		end_time = tw_osl_get_local_time() +
339			TW_CLI_REQUEST_TIMEOUT_PERIOD;
340		do {
341			if ((error = req->error_code))
342				/*
343				 * This will take care of completion due to
344				 * a reset, or a failure in
345				 * tw_cli_submit_pending_queue.
346				 */
347				goto out;
348
349			tw_cli_process_resp_intr(req->ctlr);
350
351			if ((req->state != TW_CLI_REQ_STATE_BUSY) &&
352				(req->state != TW_CLI_REQ_STATE_PENDING))
353				break;
354		} while (tw_osl_get_local_time() <= end_time);
355
356		if (req->state != TW_CLI_REQ_STATE_COMPLETE) {
357			error = TW_OSL_ETIMEDOUT;
358			break;
359		}
360
361		if ((error = req->cmd_pkt->command.cmd_pkt_9k.status)) {
362			cmd_hdr = &req->cmd_pkt->cmd_hdr;
363#if       0
364			tw_cli_create_ctlr_event(ctlr,
365				TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
366				cmd_hdr);
367#endif // 0
368			break;
369		}
370
371		aen_code = tw_cli_manage_aen(ctlr, req);
372		if (aen_code == TWA_AEN_QUEUE_EMPTY)
373			break;
374		if (aen_code == TWA_AEN_SYNC_TIME_WITH_HOST)
375			continue;
376
377		ctlr->internal_req_busy = TW_CL_FALSE;
378		tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
379	}
380
381out:
382	if (req) {
383		if (req->data)
384			ctlr->internal_req_busy = TW_CL_FALSE;
385		tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
386	}
387	return(error);
388}
389
390
391
392/*
393 * Function name:	tw_cli_find_aen
394 * Description:		Reports whether a given AEN ever occurred.
395 *
396 * Input:		ctlr	-- ptr to CL internal ctlr context
397 *			aen_code-- AEN to look for
398 * Output:		None
399 * Return value:	0	-- success
400 *			non-zero-- failure
401 */
402TW_INT32
403tw_cli_find_aen(struct tw_cli_ctlr_context *ctlr, TW_UINT16 aen_code)
404{
405	TW_UINT32	last_index;
406	TW_INT32	i;
407
408	tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
409
410	if (ctlr->aen_q_wrapped)
411		last_index = ctlr->aen_head;
412	else
413		last_index = 0;
414
415	i = ctlr->aen_head;
416	do {
417		i = (i + ctlr->max_aens_supported - 1) %
418			ctlr->max_aens_supported;
419		if (ctlr->aen_queue[i].aen_code == aen_code)
420			return(TW_OSL_ESUCCESS);
421	} while (i != last_index);
422
423	return(TW_OSL_EGENFAILURE);
424}
425
426
427
428/*
429 * Function name:	tw_cli_poll_status
430 * Description:		Poll for a given status to show up in the firmware
431 *			status register.
432 *
433 * Input:		ctlr	-- ptr to CL internal ctlr context
434 *			status	-- status to look for
435 *			timeout -- max # of seconds to wait before giving up
436 * Output:		None
437 * Return value:	0	-- success
438 *			non-zero-- failure
439 */
440TW_INT32
441tw_cli_poll_status(struct tw_cli_ctlr_context *ctlr, TW_UINT32 status,
442	TW_UINT32 timeout)
443{
444	TW_TIME		end_time;
445	TW_UINT32	status_reg;
446
447	tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
448
449	end_time = tw_osl_get_local_time() + timeout;
450	do {
451		status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr->ctlr_handle);
452		if ((status_reg & status) == status)
453			/* got the required bit(s) */
454			return(TW_OSL_ESUCCESS);
455
456		tw_osl_delay(1000);
457	} while (tw_osl_get_local_time() <= end_time);
458
459	return(TW_OSL_ETIMEDOUT);
460}
461
462
463
464/*
465 * Function name:	tw_cl_create_event
466 * Description:		Creates and queues ctlr/CL/OSL AEN's to be
467 *			supplied to user-space tools on request.
468 *			Also notifies OS Layer.
469 * Input:		ctlr	-- ptr to CL internal ctlr context
470 *			queue_event-- TW_CL_TRUE --> queue event;
471 *				      TW_CL_FALSE--> don't queue event
472 *							(simply notify OSL)
473 *			event_src  -- source of event
474 *			event_code -- AEN/error code
475 *			severity -- severity of event
476 *			severity_str--Text description of severity
477 *			event_desc -- standard string related to the event/error
478 *			event_specific_desc -- format string for additional
479 *						info about the event
480 *			... -- additional arguments conforming to the format
481 *				specified by event_specific_desc
482 * Output:		None
483 * Return value:	None
484 */
485TW_VOID
486tw_cl_create_event(struct tw_cl_ctlr_handle *ctlr_handle,
487	TW_UINT8 queue_event, TW_UINT8 event_src, TW_UINT16 event_code,
488	TW_UINT8 severity, TW_UINT8 *severity_str, TW_UINT8 *event_desc,
489	TW_UINT8 *event_specific_desc, ...)
490{
491	struct tw_cli_ctlr_context	*ctlr = ctlr_handle->cl_ctlr_ctxt;
492	struct tw_cl_event_packet	event_pkt;
493	struct tw_cl_event_packet	*event;
494	TW_UINT32			aen_head;
495	va_list				ap;
496
497	tw_cli_dbg_printf(8, ctlr_handle, tw_osl_cur_func(), "entered");
498
499	if ((ctlr) && (queue_event)) {
500		/* Protect access to ctlr->aen_head. */
501		tw_osl_get_lock(ctlr_handle, ctlr->gen_lock);
502
503		aen_head = ctlr->aen_head;
504		ctlr->aen_head = (aen_head + 1) % ctlr->max_aens_supported;
505
506		/* Queue the event. */
507		event = &(ctlr->aen_queue[aen_head]);
508		tw_osl_memzero(event->parameter_data,
509			sizeof(event->parameter_data));
510
511		if (event->retrieved == TW_CL_AEN_NOT_RETRIEVED)
512			ctlr->aen_q_overflow = TW_CL_TRUE;
513		event->sequence_id = ++(ctlr->aen_cur_seq_id);
514		if ((aen_head + 1) == ctlr->max_aens_supported) {
515			tw_cli_dbg_printf(4, ctlr->ctlr_handle,
516				tw_osl_cur_func(), "AEN queue wrapped");
517			ctlr->aen_q_wrapped = TW_CL_TRUE;
518		}
519
520		/* Free access to ctlr->aen_head. */
521		tw_osl_free_lock(ctlr_handle, ctlr->gen_lock);
522	} else {
523		event = &event_pkt;
524		tw_osl_memzero(event, sizeof(struct tw_cl_event_packet));
525	}
526
527	event->event_src = event_src;
528	event->time_stamp_sec = (TW_UINT32)tw_osl_get_local_time();
529	event->aen_code = event_code;
530	event->severity = severity;
531	tw_osl_strcpy(event->severity_str, severity_str);
532	event->retrieved = TW_CL_AEN_NOT_RETRIEVED;
533
534	va_start(ap, event_specific_desc);
535	tw_osl_vsprintf(event->parameter_data, event_specific_desc, ap);
536	va_end(ap);
537
538	event->parameter_len =
539		(TW_UINT8)(tw_osl_strlen(event->parameter_data));
540	tw_osl_strcpy(event->parameter_data + event->parameter_len + 1,
541		event_desc);
542	event->parameter_len += (1 + tw_osl_strlen(event_desc));
543
544	tw_cli_dbg_printf(4, ctlr_handle, tw_osl_cur_func(),
545		"event = %x %x %x %x %x %x %x\n %s",
546		event->sequence_id,
547		event->time_stamp_sec,
548		event->aen_code,
549		event->severity,
550		event->retrieved,
551		event->repeat_count,
552		event->parameter_len,
553		event->parameter_data);
554
555	tw_osl_notify_event(ctlr_handle, event);
556}
557
558
559
560/*
561 * Function name:	tw_cli_get_request
562 * Description:		Gets a request pkt from the free queue.
563 *
564 * Input:		ctlr	-- ptr to CL internal ctlr context
565 *			req_pkt -- ptr to OSL built req_pkt, if there's one
566 * Output:		None
567 * Return value:	ptr to request pkt	-- success
568 *			TW_CL_NULL		-- failure
569 */
570struct tw_cli_req_context *
571tw_cli_get_request(struct tw_cli_ctlr_context *ctlr
572	)
573{
574	struct tw_cli_req_context	*req;
575
576	tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
577
578	{
579		/* Get a free request packet. */
580		req = tw_cli_req_q_remove_head(ctlr, TW_CLI_FREE_Q);
581	}
582
583	/* Initialize some fields to their defaults. */
584	if (req) {
585		req->req_handle = TW_CL_NULL;
586		req->data = TW_CL_NULL;
587		req->length = 0;
588		req->data_phys = 0;
589		req->state = TW_CLI_REQ_STATE_INIT; /* req being initialized */
590		req->flags = 0;
591		req->error_code = 0;
592		req->orig_req = TW_CL_NULL;
593		req->tw_cli_callback = TW_CL_NULL;
594
595		/*
596		 * Look at the status field in the command packet to see how
597		 * it completed the last time it was used, and zero out only
598		 * the portions that might have changed.  Note that we don't
599		 * care to zero out the sglist.
600		 */
601		if (req->cmd_pkt->command.cmd_pkt_9k.status)
602			tw_osl_memzero(req->cmd_pkt,
603				sizeof(struct tw_cl_command_header) +
604				28 /* max bytes before sglist */);
605		else
606			tw_osl_memzero(&(req->cmd_pkt->command),
607				28 /* max bytes before sglist */);
608
609	}
610	return(req);
611}
612
613
614
615/*
616 * Function name:	tw_cli_dbg_printf
617 * Description:		Calls OSL print function if dbg_level is appropriate
618 *
619 * Input:		dbg_level -- Determines whether or not to print
620 *			ctlr_handle -- controller handle
621 *			cur_func -- text name of calling function
622 *			fmt -- format string for the arguments to follow
623 *			... -- variable number of arguments, to be printed
624 *				based on the fmt string
625 * Output:		None
626 * Return value:	None
627 */
628TW_VOID
629tw_cli_dbg_printf(TW_UINT8 dbg_level,
630	struct tw_cl_ctlr_handle *ctlr_handle, const TW_INT8 *cur_func,
631	TW_INT8 *fmt, ...)
632{
633#ifdef TW_OSL_DEBUG
634	TW_INT8	print_str[256];
635	va_list	ap;
636
637	tw_osl_memzero(print_str, 256);
638	if (dbg_level <= TW_OSL_DEBUG_LEVEL_FOR_CL) {
639		tw_osl_sprintf(print_str, "%s: ", cur_func);
640
641		va_start(ap, fmt);
642		tw_osl_vsprintf(print_str + tw_osl_strlen(print_str), fmt, ap);
643		va_end(ap);
644
645		tw_osl_strcpy(print_str + tw_osl_strlen(print_str), "\n");
646		tw_osl_dbg_printf(ctlr_handle, "%s", print_str);
647	}
648#endif /* TW_OSL_DEBUG */
649}
650
651
652
653/*
654 * Function name:	tw_cli_notify_ctlr_info
655 * Description:		Notify OSL of controller info (fw/BIOS versions, etc.).
656 *
657 * Input:		ctlr	-- ptr to CL internal ctlr context
658 * Output:		None
659 * Return value:	None
660 */
661TW_VOID
662tw_cli_notify_ctlr_info(struct tw_cli_ctlr_context *ctlr)
663{
664	TW_INT8		fw_ver[16];
665	TW_INT8		bios_ver[16];
666	TW_INT8		ctlr_model[16];
667	TW_INT32	error[3];
668	TW_UINT8	num_ports = 0;
669
670	tw_cli_dbg_printf(5, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
671
672	/* Get the port count. */
673	error[0] = tw_cli_get_param(ctlr, TWA_PARAM_CONTROLLER_TABLE,
674			TWA_PARAM_CONTROLLER_PORT_COUNT, &num_ports,
675			1, TW_CL_NULL);
676
677	/* Get the firmware and BIOS versions. */
678	error[0] = tw_cli_get_param(ctlr, TWA_PARAM_VERSION_TABLE,
679			TWA_PARAM_VERSION_FW, fw_ver, 16, TW_CL_NULL);
680	error[1] = tw_cli_get_param(ctlr, TWA_PARAM_VERSION_TABLE,
681			TWA_PARAM_VERSION_BIOS, bios_ver, 16, TW_CL_NULL);
682	error[2] = tw_cli_get_param(ctlr, TWA_PARAM_VERSION_TABLE,
683			TWA_PARAM_CTLR_MODEL, ctlr_model, 16, TW_CL_NULL);
684
685	tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
686		TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
687		0x1300, 0x3, TW_CL_SEVERITY_INFO_STRING,
688		"Controller details:",
689		"Model %.16s, %d ports, Firmware %.16s, BIOS %.16s",
690		error[2]?(TW_INT8 *)TW_CL_NULL:ctlr_model,
691		num_ports,
692		error[0]?(TW_INT8 *)TW_CL_NULL:fw_ver,
693		error[1]?(TW_INT8 *)TW_CL_NULL:bios_ver);
694}
695
696
697
698/*
699 * Function name:	tw_cli_check_ctlr_state
700 * Description:		Makes sure that the fw status register reports a
701 *			proper status.
702 *
703 * Input:		ctlr	-- ptr to CL internal ctlr context
704 *			status_reg-- value in the status register
705 * Output:		None
706 * Return value:	0	-- no errors
707 *			non-zero-- errors
708 */
709TW_INT32
710tw_cli_check_ctlr_state(struct tw_cli_ctlr_context *ctlr, TW_UINT32 status_reg)
711{
712	struct tw_cl_ctlr_handle	*ctlr_handle = ctlr->ctlr_handle;
713	TW_INT32			error = TW_OSL_ESUCCESS;
714
715	tw_cli_dbg_printf(8, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
716
717	/* Check if the 'micro-controller ready' bit is not set. */
718	if (!(status_reg & TWA_STATUS_MICROCONTROLLER_READY)) {
719		TW_INT8	desc[200];
720
721		tw_osl_memzero(desc, 200);
722		if (!(ctlr->reset_phase1_in_progress)) {
723			tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
724				TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
725				0x1301, 0x1, TW_CL_SEVERITY_ERROR_STRING,
726				"Missing expected status bit(s)",
727				"status reg = 0x%x; Missing bits: %s",
728				status_reg,
729				tw_cli_describe_bits(
730					TWA_STATUS_MICROCONTROLLER_READY,
731					desc));
732			error = TW_OSL_EGENFAILURE;
733		}
734	}
735
736	/* Check if any error bits are set. */
737	if ((status_reg & TWA_STATUS_UNEXPECTED_BITS) != 0) {
738		TW_INT8	desc[200];
739
740		tw_osl_memzero(desc, 200);
741
742		/* Skip queue error msgs during 9650SE/9690SA reset */
743		if (((ctlr->device_id != TW_CL_DEVICE_ID_9K_E) &&
744		     (ctlr->device_id != TW_CL_DEVICE_ID_9K_SA)) ||
745		    (!(ctlr->reset_in_progress)) ||
746		    ((status_reg & TWA_STATUS_QUEUE_ERROR_INTERRUPT) == 0))
747		tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
748			TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
749			0x1302, 0x1, TW_CL_SEVERITY_ERROR_STRING,
750			"Unexpected status bit(s)",
751			"status reg = 0x%x Unexpected bits: %s",
752			status_reg & TWA_STATUS_UNEXPECTED_BITS,
753			tw_cli_describe_bits(status_reg &
754				TWA_STATUS_UNEXPECTED_BITS, desc));
755
756		if (status_reg & TWA_STATUS_PCI_PARITY_ERROR_INTERRUPT) {
757			tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
758				TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
759				0x1303, 0x1, TW_CL_SEVERITY_ERROR_STRING,
760				"PCI parity error: clearing... "
761				"Re-seat/move/replace card",
762				"status reg = 0x%x %s",
763				status_reg,
764				tw_cli_describe_bits(status_reg, desc));
765			TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle,
766				TWA_CONTROL_CLEAR_PARITY_ERROR);
767
768#ifdef TW_OSL_PCI_CONFIG_ACCESSIBLE
769			tw_osl_write_pci_config(ctlr->ctlr_handle,
770				TW_CLI_PCI_CONFIG_STATUS_OFFSET,
771				TWA_PCI_CONFIG_CLEAR_PARITY_ERROR, 2);
772#endif /* TW_OSL_PCI_CONFIG_ACCESSIBLE */
773
774		}
775
776		if (status_reg & TWA_STATUS_PCI_ABORT_INTERRUPT) {
777			tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
778				TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
779				0x1304, 0x1, TW_CL_SEVERITY_ERROR_STRING,
780				"PCI abort: clearing... ",
781				"status reg = 0x%x %s",
782				status_reg,
783				tw_cli_describe_bits(status_reg, desc));
784			TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle,
785				TWA_CONTROL_CLEAR_PCI_ABORT);
786
787#ifdef TW_OSL_PCI_CONFIG_ACCESSIBLE
788			tw_osl_write_pci_config(ctlr->ctlr_handle,
789				TW_CLI_PCI_CONFIG_STATUS_OFFSET,
790				TWA_PCI_CONFIG_CLEAR_PCI_ABORT, 2);
791#endif /* TW_OSL_PCI_CONFIG_ACCESSIBLE */
792
793		}
794
795		if (status_reg & TWA_STATUS_QUEUE_ERROR_INTERRUPT) {
796			/* Skip queue error msgs during 9650SE/9690SA reset */
797			if (((ctlr->device_id != TW_CL_DEVICE_ID_9K_E) &&
798			     (ctlr->device_id != TW_CL_DEVICE_ID_9K_SA)) ||
799			    (!(ctlr->reset_in_progress)))
800				tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
801						   TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
802						   0x1305, 0x1, TW_CL_SEVERITY_ERROR_STRING,
803						   "Controller queue error: clearing... ",
804						   "status reg = 0x%x %s",
805						   status_reg,
806						   tw_cli_describe_bits(status_reg, desc));
807			TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle,
808				TWA_CONTROL_CLEAR_QUEUE_ERROR);
809		}
810	}
811	return(error);
812}
813
814
815
816/*
817 * Function name:	tw_cli_describe_bits
818 * Description:		Given the value of the status register, returns a
819 *			string describing the meaning of each set bit.
820 *
821 * Input:		reg -- status register value
822 * Output:		Pointer to a string describing each set bit
823 * Return value:	Pointer to the string describing each set bit
824 */
825TW_INT8	*
826tw_cli_describe_bits(TW_UINT32 reg, TW_INT8 *str)
827{
828	tw_osl_strcpy(str, "[");
829
830	if (reg & TWA_STATUS_COMMAND_QUEUE_EMPTY)
831		tw_osl_strcpy(&str[tw_osl_strlen(str)], "CMD_Q_EMPTY,");
832	if (reg & TWA_STATUS_MICROCONTROLLER_READY)
833		tw_osl_strcpy(&str[tw_osl_strlen(str)], "MC_RDY,");
834	if (reg & TWA_STATUS_RESPONSE_QUEUE_EMPTY)
835		tw_osl_strcpy(&str[tw_osl_strlen(str)], "RESP_Q_EMPTY,");
836	if (reg & TWA_STATUS_COMMAND_QUEUE_FULL)
837		tw_osl_strcpy(&str[tw_osl_strlen(str)], "CMD_Q_FULL,");
838	if (reg & TWA_STATUS_RESPONSE_INTERRUPT)
839		tw_osl_strcpy(&str[tw_osl_strlen(str)], "RESP_INTR,");
840	if (reg & TWA_STATUS_COMMAND_INTERRUPT)
841		tw_osl_strcpy(&str[tw_osl_strlen(str)], "CMD_INTR,");
842	if (reg & TWA_STATUS_ATTENTION_INTERRUPT)
843		tw_osl_strcpy(&str[tw_osl_strlen(str)], "ATTN_INTR,");
844	if (reg & TWA_STATUS_HOST_INTERRUPT)
845		tw_osl_strcpy(&str[tw_osl_strlen(str)], "HOST_INTR,");
846	if (reg & TWA_STATUS_PCI_ABORT_INTERRUPT)
847		tw_osl_strcpy(&str[tw_osl_strlen(str)], "PCI_ABRT,");
848	if (reg & TWA_STATUS_QUEUE_ERROR_INTERRUPT)
849		tw_osl_strcpy(&str[tw_osl_strlen(str)], "Q_ERR,");
850	if (reg & TWA_STATUS_PCI_PARITY_ERROR_INTERRUPT)
851		tw_osl_strcpy(&str[tw_osl_strlen(str)], "PCI_PERR");
852
853	tw_osl_strcpy(&str[tw_osl_strlen(str)], "]");
854	return(str);
855}
856
857
858
859#ifdef TW_OSL_DEBUG
860
861/*
862 * Function name:	tw_cl_print_ctlr_stats
863 * Description:		Prints the current status of the controller.
864 *
865 * Input:		ctlr_handle-- controller handle
866 * Output:		None
867 * Return value:	None
868 */
869TW_VOID
870tw_cl_print_ctlr_stats(struct tw_cl_ctlr_handle *ctlr_handle)
871{
872	struct tw_cli_ctlr_context	*ctlr =
873		(struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt);
874	TW_UINT32			status_reg;
875	TW_INT8				desc[200];
876
877	tw_cli_dbg_printf(7, ctlr->ctlr_handle, "", "entered");
878
879	/* Print current controller details. */
880	tw_cli_dbg_printf(0, ctlr_handle, "", "cl_ctlr_ctxt = %p", ctlr);
881
882	tw_osl_memzero(desc, 200);
883	status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr_handle);
884	tw_cli_dbg_printf(0, ctlr_handle, "", "status reg = 0x%x %s",
885		status_reg, tw_cli_describe_bits(status_reg, desc));
886
887	tw_cli_dbg_printf(0, ctlr_handle, "", "CLq type  current  max");
888	tw_cli_dbg_printf(0, ctlr_handle, "", "free      %04d     %04d",
889		ctlr->q_stats[TW_CLI_FREE_Q].cur_len,
890		ctlr->q_stats[TW_CLI_FREE_Q].max_len);
891	tw_cli_dbg_printf(0, ctlr_handle, "", "busy      %04d     %04d",
892		ctlr->q_stats[TW_CLI_BUSY_Q].cur_len,
893		ctlr->q_stats[TW_CLI_BUSY_Q].max_len);
894	tw_cli_dbg_printf(0, ctlr_handle, "", "pending   %04d     %04d",
895		ctlr->q_stats[TW_CLI_PENDING_Q].cur_len,
896		ctlr->q_stats[TW_CLI_PENDING_Q].max_len);
897	tw_cli_dbg_printf(0, ctlr_handle, "", "complete  %04d     %04d",
898		ctlr->q_stats[TW_CLI_COMPLETE_Q].cur_len,
899		ctlr->q_stats[TW_CLI_COMPLETE_Q].max_len);
900	tw_cli_dbg_printf(0, ctlr_handle, "", "AEN queue head %d  tail %d",
901			ctlr->aen_head, ctlr->aen_tail);
902}
903
904
905
906/*
907 * Function name:	tw_cl_reset_stats
908 * Description:		Resets CL maintained statistics for the controller.
909 *
910 * Input:		ctlr_handle-- controller handle
911 * Output:		None
912 * Return value:	None
913 */
914TW_VOID
915tw_cl_reset_stats(struct tw_cl_ctlr_handle *ctlr_handle)
916{
917	struct tw_cli_ctlr_context	*ctlr =
918		(struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt);
919
920	tw_cli_dbg_printf(7, ctlr_handle, tw_osl_cur_func(), "entered");
921	ctlr->q_stats[TW_CLI_FREE_Q].max_len = 0;
922	ctlr->q_stats[TW_CLI_BUSY_Q].max_len = 0;
923	ctlr->q_stats[TW_CLI_PENDING_Q].max_len = 0;
924	ctlr->q_stats[TW_CLI_COMPLETE_Q].max_len = 0;
925}
926
927
928
929/*
930 * Function name:	tw_cli_print_req_info
931 * Description:		Prints CL internal details of a given request.
932 *
933 * Input:		req	-- ptr to CL internal request context
934 * Output:		None
935 * Return value:	None
936 */
937TW_VOID
938tw_cl_print_req_info(struct tw_cl_req_handle *req_handle)
939{
940	struct tw_cli_req_context	*req = req_handle->cl_req_ctxt;
941	struct tw_cli_ctlr_context	*ctlr = req->ctlr;
942	struct tw_cl_ctlr_handle	*ctlr_handle = ctlr->ctlr_handle;
943	struct tw_cl_command_packet	*cmd_pkt = req->cmd_pkt;
944	struct tw_cl_command_9k		*cmd9k;
945	union tw_cl_command_7k		*cmd7k;
946	TW_UINT8			*cdb;
947	TW_VOID				*sgl;
948	TW_UINT32			sgl_entries;
949	TW_UINT32			i;
950
951	tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(),
952		"CL details for request:");
953	tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(),
954		"req_handle = %p, ctlr = %p,\n"
955		"cmd_pkt = %p, cmd_pkt_phys = 0x%llx,\n"
956		"data = %p, length = 0x%x, data_phys = 0x%llx,\n"
957		"state = 0x%x, flags = 0x%x, error = 0x%x,\n"
958		"orig_req = %p, callback = %p, req_id = 0x%x,\n"
959		"next_req = %p, prev_req = %p",
960		req_handle, ctlr,
961		cmd_pkt, req->cmd_pkt_phys,
962		req->data, req->length, req->data_phys,
963		req->state, req->flags, req->error_code,
964		req->orig_req, req->tw_cli_callback, req->request_id,
965		req->link.next, req->link.prev);
966
967	if (req->flags & TW_CLI_REQ_FLAGS_9K) {
968		cmd9k = &(cmd_pkt->command.cmd_pkt_9k);
969		sgl = cmd9k->sg_list;
970		sgl_entries = TW_CL_SWAP16(
971			GET_SGL_ENTRIES(cmd9k->lun_h4__sgl_entries));
972		tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(),
973			"9K cmd: opcode = 0x%x, unit = 0x%x, req_id = 0x%x,\n"
974			"status = 0x%x, sgl_offset = 0x%x, sgl_entries = 0x%x",
975			GET_OPCODE(cmd9k->res__opcode),
976			cmd9k->unit,
977			TW_CL_SWAP16(GET_REQ_ID(cmd9k->lun_l4__req_id)),
978			cmd9k->status,
979			cmd9k->sgl_offset,
980			sgl_entries);
981
982		cdb = (TW_UINT8 *)(cmd9k->cdb);
983		tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(),
984			"CDB: %x %x %x %x %x %x %x %x"
985			"%x %x %x %x %x %x %x %x",
986			cdb[0], cdb[1], cdb[2], cdb[3],
987			cdb[4], cdb[5], cdb[6], cdb[7],
988			cdb[8], cdb[9], cdb[10], cdb[11],
989			cdb[12], cdb[13], cdb[14], cdb[15]);
990	} else {
991		cmd7k = &(cmd_pkt->command.cmd_pkt_7k);
992		sgl = cmd7k->param.sgl;
993		sgl_entries = (cmd7k->generic.size -
994			GET_SGL_OFF(cmd7k->generic.sgl_off__opcode)) /
995			((ctlr->flags & TW_CL_64BIT_ADDRESSES) ? 3 : 2);
996		tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(),
997			"7K cmd: opcode = 0x%x, sgl_offset = 0x%x,\n"
998			"size = 0x%x, req_id = 0x%x, unit = 0x%x,\n"
999			"status = 0x%x, flags = 0x%x, count = 0x%x",
1000			GET_OPCODE(cmd7k->generic.sgl_off__opcode),
1001			GET_SGL_OFF(cmd7k->generic.sgl_off__opcode),
1002			cmd7k->generic.size,
1003			TW_CL_SWAP16(cmd7k->generic.request_id),
1004			GET_UNIT(cmd7k->generic.host_id__unit),
1005			cmd7k->generic.status,
1006			cmd7k->generic.flags,
1007			TW_CL_SWAP16(cmd7k->generic.count));
1008	}
1009
1010	tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(), "SG entries:");
1011
1012	if (ctlr->flags & TW_CL_64BIT_ADDRESSES) {
1013		struct tw_cl_sg_desc64 *sgl64 = (struct tw_cl_sg_desc64 *)sgl;
1014
1015		for (i = 0; i < sgl_entries; i++) {
1016			tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(),
1017				"0x%llx  0x%x",
1018				sgl64[i].address, sgl64[i].length);
1019		}
1020	} else {
1021		struct tw_cl_sg_desc32 *sgl32 = (struct tw_cl_sg_desc32 *)sgl;
1022
1023		for (i = 0; i < sgl_entries; i++) {
1024			tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(),
1025				"0x%x  0x%x",
1026				sgl32[i].address, sgl32[i].length);
1027		}
1028	}
1029}
1030
1031#endif /* TW_OSL_DEBUG */
1032
1033