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