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