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