tw_cl_misc.c revision 144966
1272343Sngie/*
2272343Sngie * Copyright (c) 2004-05 Applied Micro Circuits Corporation.
3272343Sngie * Copyright (c) 2004-05 Vinod Kashyap
4272343Sngie * All rights reserved.
5272343Sngie *
6272343Sngie * Redistribution and use in source and binary forms, with or without
7272343Sngie * modification, are permitted provided that the following conditions
8272343Sngie * are met:
9272343Sngie * 1. Redistributions of source code must retain the above copyright
10272343Sngie *    notice, this list of conditions and the following disclaimer.
11272343Sngie * 2. Redistributions in binary form must reproduce the above copyright
12272343Sngie *    notice, this list of conditions and the following disclaimer in the
13272343Sngie *    documentation and/or other materials provided with the distribution.
14272343Sngie *
15272343Sngie * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16272343Sngie * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17272343Sngie * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18272343Sngie * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19272343Sngie * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20272343Sngie * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21272343Sngie * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22272343Sngie * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23272343Sngie * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24272343Sngie * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25272343Sngie * SUCH DAMAGE.
26272343Sngie *
27272343Sngie *	$FreeBSD: head/sys/dev/twa/tw_cl_misc.c 144966 2005-04-12 22:07:11Z vkashyap $
28272343Sngie */
29272343Sngie
30272343Sngie/*
31272343Sngie * AMCC'S 3ware driver for 9000 series storage controllers.
32272343Sngie *
33272343Sngie * Author: Vinod Kashyap
34272343Sngie */
35272343Sngie
36272343Sngie
37272343Sngie/*
38272343Sngie * Common Layer miscellaneous functions.
39272343Sngie */
40272343Sngie
41272343Sngie
42272343Sngie#include "tw_osl_share.h"
43272343Sngie#include "tw_cl_share.h"
44272343Sngie#include "tw_cl_fwif.h"
45272343Sngie#include "tw_cl_ioctl.h"
46272343Sngie#include "tw_cl.h"
47272343Sngie#include "tw_cl_externs.h"
48272343Sngie#include "tw_osl_ioctl.h"
49272343Sngie
50272343Sngie
51272343Sngie
52272343Sngie/* AEN severity table. */
53272343SngieTW_INT8	*tw_cli_severity_string_table[] = {
54272343Sngie	"None",
55272343Sngie	TW_CL_SEVERITY_ERROR_STRING,
56272343Sngie	TW_CL_SEVERITY_WARNING_STRING,
57272343Sngie	TW_CL_SEVERITY_INFO_STRING,
58272343Sngie	TW_CL_SEVERITY_DEBUG_STRING,
59272343Sngie	""
60272343Sngie};
61272343Sngie
62272343Sngie
63272343Sngie
64272343Sngie/*
65272343Sngie * Function name:	tw_cli_drain_complete_queue
66272343Sngie * Description:		This function gets called during a controller reset.
67272343Sngie *			It errors back to CAM, all those requests that are
68272343Sngie *			in the complete queue, at the time of the reset.  Any
69272343Sngie *			CL internal requests will be simply freed.
70272343Sngie *
71272343Sngie * Input:		ctlr	-- ptr to CL internal ctlr context
72272343Sngie * Output:		None
73272343Sngie * Return value:	None
74272343Sngie */
75272343SngieTW_VOID
76272343Sngietw_cli_drain_complete_queue(struct tw_cli_ctlr_context *ctlr)
77272343Sngie{
78272343Sngie	struct tw_cli_req_context	*req;
79272343Sngie	struct tw_cl_req_packet		*req_pkt;
80272343Sngie
81272343Sngie	tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
82272343Sngie
83272343Sngie	/* Walk the busy queue. */
84272343Sngie	while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_COMPLETE_Q))) {
85272343Sngie		if (req->flags & TW_CLI_REQ_FLAGS_INTERNAL) {
86272343Sngie			/*
87272343Sngie			 * It's an internal request.  Set the appropriate
88272343Sngie			 * error and call the CL internal callback if there's
89272343Sngie			 * one.  If the request originator is polling for
90272343Sngie			 * completion, he should be checking req->error to
91272343Sngie			 * determine that the request did not go through.
92272343Sngie			 * The request originators are responsible for the
93272343Sngie			 * clean-up.
94272343Sngie			 */
95272343Sngie			req->error_code = TW_CL_ERR_REQ_BUS_RESET;
96272343Sngie			if (req->tw_cli_callback)
97272343Sngie				req->tw_cli_callback(req);
98272343Sngie		} else {
99272343Sngie			if ((req_pkt = req->orig_req)) {
100				/* It's a SCSI request.  Complete it. */
101				tw_cli_dbg_printf(2, ctlr->ctlr_handle,
102					tw_osl_cur_func(),
103					"Completing complete request %p "
104					"on reset",
105					req);
106				req_pkt->status = TW_CL_ERR_REQ_BUS_RESET;
107				req_pkt->tw_osl_callback(req->req_handle);
108			}
109			tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
110		}
111	}
112}
113
114
115
116/*
117 * Function name:	tw_cli_drain_busy_queue
118 * Description:		This function gets called during a controller reset.
119 *			It errors back to CAM, all those requests that were
120 *			pending with the firmware, at the time of the reset.
121 *
122 * Input:		ctlr	-- ptr to CL internal ctlr context
123 * Output:		None
124 * Return value:	None
125 */
126TW_VOID
127tw_cli_drain_busy_queue(struct tw_cli_ctlr_context *ctlr)
128{
129	struct tw_cli_req_context	*req;
130	struct tw_cl_req_packet		*req_pkt;
131
132	tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
133
134	/* Walk the busy queue. */
135	while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_BUSY_Q))) {
136		if (req->flags & TW_CLI_REQ_FLAGS_INTERNAL) {
137			/*
138			 * It's an internal request.  Set the appropriate
139			 * error and call the CL internal callback if there's
140			 * one.  If the request originator is polling for
141			 * completion, he should be checking req->error to
142			 * determine that the request did not go through.
143			 * The request originators are responsible for the
144			 * clean-up.
145			 */
146			req->error_code = TW_CL_ERR_REQ_BUS_RESET;
147			if (req->tw_cli_callback)
148				req->tw_cli_callback(req);
149		} else {
150			if ((req_pkt = req->orig_req)) {
151				/* It's a SCSI request.  Complete it. */
152				tw_cli_dbg_printf(2, ctlr->ctlr_handle,
153					tw_osl_cur_func(),
154					"Completing busy request %p on reset",
155					req);
156				req_pkt->status = TW_CL_ERR_REQ_BUS_RESET;
157				req_pkt->tw_osl_callback(req->req_handle);
158			}
159			tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
160		}
161	}
162}
163
164
165
166/*
167 * Function name:	tw_cli_drain_pending_queue
168 * Description:		This function gets called during a controller reset.
169 *			It errors back to CAM, all those requests that were
170 *			in the pending queue, at the time of the reset.
171 *
172 * Input:		ctlr	-- ptr to CL internal ctlr context
173 * Output:		None
174 * Return value:	None
175 */
176
177TW_VOID
178tw_cli_drain_pending_queue(struct tw_cli_ctlr_context *ctlr)
179{
180	struct tw_cli_req_context	*req;
181	struct tw_cl_req_packet		*req_pkt;
182
183	tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
184
185	/*
186	 * Pull requests off the pending queue, and complete them.
187	 */
188	while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_PENDING_Q))) {
189		if (req->flags & TW_CLI_REQ_FLAGS_INTERNAL) {
190			/*
191			 * It's an internal request.  Set the appropriate
192			 * error and call the CL internal callback if there's
193			 * one.  If the request originator is polling for
194			 * completion, he should be checking req->error to
195			 * determine that the request did not go through.
196			 * The request originators are responsible for the
197			 * clean-up.
198			 */
199			req->error_code = TW_CL_ERR_REQ_BUS_RESET;
200			if (req->tw_cli_callback)
201				req->tw_cli_callback(req);
202		} else {
203			if ((req_pkt = req->orig_req)) {
204				/* It's an external request.  Complete it. */
205				tw_cli_dbg_printf(2, ctlr->ctlr_handle,
206					tw_osl_cur_func(),
207					"Completing pending request %p "
208					"on reset", req);
209				req_pkt->status = TW_CL_ERR_REQ_BUS_RESET;
210				req_pkt->tw_osl_callback(req->req_handle);
211			}
212			tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
213		}
214	}
215}
216
217
218
219/*
220 * Function name:	tw_cli_drain_response_queue
221 * Description:		Drain the controller response queue.
222 *
223 * Input:		ctlr	-- ptr to per ctlr structure
224 * Output:		None
225 * Return value:	0	-- success
226 *			non-zero-- failure
227 */
228TW_INT32
229tw_cli_drain_response_queue(struct tw_cli_ctlr_context *ctlr)
230{
231	TW_UINT32	resp;
232	TW_UINT32	status_reg;
233
234	tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
235
236	for (;;) {
237		status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr->ctlr_handle);
238
239		if (tw_cli_check_ctlr_state(ctlr, status_reg))
240			return(TW_OSL_EGENFAILURE);
241
242		if (status_reg & TWA_STATUS_RESPONSE_QUEUE_EMPTY)
243			return(TW_OSL_ESUCCESS); /* no more response queue entries */
244
245		resp = TW_CLI_READ_RESPONSE_QUEUE(ctlr->ctlr_handle);
246	}
247}
248
249
250
251/*
252 * Function name:	tw_cli_drain_aen_queue
253 * Description:		Fetches all un-retrieved AEN's posted by fw.
254 *
255 * Input:		ctlr	-- ptr to CL internal ctlr context
256 * Output:		None
257 * Return value:	0	-- success
258 *			non-zero-- failure
259 */
260TW_INT32
261tw_cli_drain_aen_queue(struct tw_cli_ctlr_context *ctlr)
262{
263	struct tw_cli_req_context	*req;
264	struct tw_cl_command_header	*cmd_hdr;
265	TW_TIME				end_time;
266	TW_UINT16			aen_code;
267	TW_INT32			error;
268
269	tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
270
271	for (;;) {
272		if ((req = tw_cli_get_request(ctlr
273#ifdef TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST
274			, TW_CL_NULL
275#endif /* TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST */
276			)) == TW_CL_NULL) {
277			error = TW_OSL_EBUSY;
278			break;
279		}
280
281#ifdef TW_OSL_DMA_MEM_ALLOC_PER_REQUEST
282
283		req->cmd_pkt = ctlr->cmd_pkt_buf;
284		req->cmd_pkt_phys = ctlr->cmd_pkt_phys;
285		tw_osl_memzero(req->cmd_pkt,
286			sizeof(struct tw_cl_command_header) +
287			28 /* max bytes before sglist */);
288
289#endif /* TW_OSL_DMA_MEM_ALLOC_PER_REQUEST */
290
291		req->flags |= TW_CLI_REQ_FLAGS_INTERNAL;
292		req->tw_cli_callback = TW_CL_NULL;
293		if ((error = tw_cli_send_scsi_cmd(req,
294				0x03 /* REQUEST_SENSE */))) {
295			tw_cli_dbg_printf(1, ctlr->ctlr_handle,
296				tw_osl_cur_func(),
297				"Cannot send command to fetch aen");
298			break;
299		}
300
301		end_time = tw_osl_get_local_time() +
302			TW_CLI_REQUEST_TIMEOUT_PERIOD;
303		do {
304			if ((error = req->error_code))
305				/*
306				 * This will take care of completion due to
307				 * a reset, or a failure in
308				 * tw_cli_submit_pending_queue.
309				 */
310				goto out;
311
312			tw_cli_process_resp_intr(req->ctlr);
313
314			if ((req->state != TW_CLI_REQ_STATE_BUSY) &&
315				(req->state != TW_CLI_REQ_STATE_PENDING))
316				break;
317		} while (tw_osl_get_local_time() <= end_time);
318
319		if (req->state != TW_CLI_REQ_STATE_COMPLETE) {
320			error = TW_OSL_ETIMEDOUT;
321			break;
322		}
323
324		if ((error = req->cmd_pkt->command.cmd_pkt_9k.status)) {
325			cmd_hdr = &req->cmd_pkt->cmd_hdr;
326			tw_cli_create_ctlr_event(ctlr,
327				TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
328				cmd_hdr);
329			break;
330		}
331
332		aen_code = tw_cli_manage_aen(ctlr, req);
333		if (aen_code == TWA_AEN_QUEUE_EMPTY)
334			break;
335		if (aen_code == TWA_AEN_SYNC_TIME_WITH_HOST)
336			continue;
337
338		ctlr->state &= ~TW_CLI_CTLR_STATE_INTERNAL_REQ_BUSY;
339		tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
340	}
341
342out:
343	if (req) {
344		if (req->data)
345			ctlr->state &= ~TW_CLI_CTLR_STATE_INTERNAL_REQ_BUSY;
346		tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
347	}
348	return(error);
349}
350
351
352
353/*
354 * Function name:	tw_cli_find_aen
355 * Description:		Reports whether a given AEN ever occurred.
356 *
357 * Input:		ctlr	-- ptr to CL internal ctlr context
358 *			aen_code-- AEN to look for
359 * Output:		None
360 * Return value:	0	-- success
361 *			non-zero-- failure
362 */
363TW_INT32
364tw_cli_find_aen(struct tw_cli_ctlr_context *ctlr, TW_UINT16 aen_code)
365{
366	TW_UINT32	last_index;
367	TW_INT32	i;
368
369	tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
370
371	if (ctlr->aen_q_wrapped)
372		last_index = ctlr->aen_head;
373	else
374		last_index = 0;
375
376	i = ctlr->aen_head;
377	do {
378		i = (i + ctlr->max_aens_supported - 1) %
379			ctlr->max_aens_supported;
380		if (ctlr->aen_queue[i].aen_code == aen_code)
381			return(TW_OSL_ESUCCESS);
382	} while (i != last_index);
383
384	return(TW_OSL_EGENFAILURE);
385}
386
387
388
389/*
390 * Function name:	tw_cli_poll_status
391 * Description:		Poll for a given status to show up in the firmware
392 *			status register.
393 *
394 * Input:		ctlr	-- ptr to CL internal ctlr context
395 *			status	-- status to look for
396 *			timeout -- max # of seconds to wait before giving up
397 * Output:		None
398 * Return value:	0	-- success
399 *			non-zero-- failure
400 */
401TW_INT32
402tw_cli_poll_status(struct tw_cli_ctlr_context *ctlr, TW_UINT32 status,
403	TW_UINT32 timeout)
404{
405	TW_TIME		end_time;
406	TW_UINT32	status_reg;
407
408	tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
409
410	end_time = tw_osl_get_local_time() + timeout;
411	do {
412		status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr->ctlr_handle);
413		if ((status_reg & status) == status)
414			/* got the required bit(s) */
415			return(TW_OSL_ESUCCESS);
416
417		/*
418		 * The OSL should not define TW_OSL_CAN_SLEEP if it calls
419		 * tw_cl_deferred_interrupt from within the ISR and not a
420		 * lower interrupt level, since, in that case, we might end
421		 * up here, and try to sleep (within an ISR).
422		 */
423#ifndef TW_OSL_CAN_SLEEP
424		/* OSL doesn't support sleeping; will spin. */
425		tw_osl_delay(1000);
426#else /* TW_OSL_CAN_SLEEP */
427#if 0
428		/* Will spin if initializing, sleep otherwise. */
429		if (!(ctlr->state & TW_CLI_CTLR_STATE_ACTIVE))
430			tw_osl_delay(1000);
431		else
432			tw_osl_sleep(ctlr->ctlr_handle,
433				&(ctlr->sleep_handle), 1 /* ms */);
434#else /* #if 0 */
435		/*
436		 * Will always spin for now (since reset holds a spin lock).
437		 * We could free io_lock after the call to TW_CLI_SOFT_RESET,
438		 * so we could sleep here.  To block new requests (since
439		 * the lock will have been released) we could use the
440		 * ...RESET_IN_PROGRESS flag.  Need to revisit.
441		 */
442		tw_osl_delay(1000);
443#endif /* #if 0 */
444#endif /* TW_OSL_CAN_SLEEP */
445	} while (tw_osl_get_local_time() <= end_time);
446
447	return(TW_OSL_ETIMEDOUT);
448}
449
450
451
452/*
453 * Function name:	tw_cl_create_event
454 * Description:		Creates and queues ctlr/CL/OSL AEN's to be
455 *			supplied to user-space tools on request.
456 *			Also notifies OS Layer.
457 * Input:		ctlr	-- ptr to CL internal ctlr context
458 *			queue_event-- TW_CL_TRUE --> queue event;
459 *				      TW_CL_FALSE--> don't queue event
460 *							(simply notify OSL)
461 *			event_src  -- source of event
462 *			event_code -- AEN/error code
463 *			severity -- severity of event
464 *			severity_str--Text description of severity
465 *			event_desc -- standard string related to the event/error
466 *			event_specific_desc -- format string for additional
467 *						info about the event
468 *			... -- additional arguments conforming to the format
469 *				specified by event_specific_desc
470 * Output:		None
471 * Return value:	None
472 */
473TW_VOID
474tw_cl_create_event(struct tw_cl_ctlr_handle *ctlr_handle,
475	TW_UINT8 queue_event, TW_UINT8 event_src, TW_UINT16 event_code,
476	TW_UINT8 severity, TW_UINT8 *severity_str, TW_UINT8 *event_desc,
477	TW_UINT8 *event_specific_desc, ...)
478{
479	struct tw_cli_ctlr_context	*ctlr = ctlr_handle->cl_ctlr_ctxt;
480	struct tw_cl_event_packet	event_pkt;
481	struct tw_cl_event_packet	*event;
482	va_list				ap;
483
484	tw_cli_dbg_printf(8, ctlr_handle, tw_osl_cur_func(), "entered");
485
486	if ((ctlr) && (queue_event)) {
487		/* Protect access to ctlr->aen_head. */
488		tw_osl_get_lock(ctlr_handle, ctlr->gen_lock);
489
490		/* Queue the event. */
491		event = &(ctlr->aen_queue[ctlr->aen_head]);
492		tw_osl_memzero(event->parameter_data,
493			sizeof(event->parameter_data));
494
495		if (event->retrieved == TW_CL_AEN_NOT_RETRIEVED)
496			ctlr->aen_q_overflow = TW_CL_TRUE;
497		event->sequence_id = ++(ctlr->aen_cur_seq_id);
498		if ((ctlr->aen_head + 1) == ctlr->max_aens_supported) {
499			tw_cli_dbg_printf(4, ctlr->ctlr_handle,
500				tw_osl_cur_func(), "AEN queue wrapped");
501			ctlr->aen_q_wrapped = TW_CL_TRUE;
502		}
503	} else {
504		event = &event_pkt;
505		tw_osl_memzero(event, sizeof(struct tw_cl_event_packet));
506	}
507
508	event->event_src = event_src;
509	event->time_stamp_sec = (TW_UINT32)tw_osl_get_local_time();
510	event->aen_code = event_code;
511	event->severity = severity;
512	tw_osl_strcpy(event->severity_str, severity_str);
513	event->retrieved = TW_CL_AEN_NOT_RETRIEVED;
514
515	va_start(ap, event_specific_desc);
516	tw_osl_vsprintf(event->parameter_data, event_specific_desc, ap);
517	va_end(ap);
518
519	event->parameter_len =
520		(TW_UINT8)(tw_osl_strlen(event->parameter_data));
521	tw_osl_strcpy(event->parameter_data + event->parameter_len + 1,
522		event_desc);
523	event->parameter_len += (1 + tw_osl_strlen(event_desc));
524
525	tw_cli_dbg_printf(4, ctlr_handle, tw_osl_cur_func(),
526		"event = %x %x %x %x %x %x %x\n %s",
527		event->sequence_id,
528		event->time_stamp_sec,
529		event->aen_code,
530		event->severity,
531		event->retrieved,
532		event->repeat_count,
533		event->parameter_len,
534		event->parameter_data);
535
536	if ((ctlr) && (queue_event)) {
537		ctlr->aen_head =
538			(ctlr->aen_head + 1) % ctlr->max_aens_supported;
539		/* Free access to ctlr->aen_head. */
540		tw_osl_free_lock(ctlr_handle, ctlr->gen_lock);
541	}
542	tw_osl_notify_event(ctlr_handle, event);
543}
544
545
546
547/*
548 * Function name:	tw_cli_get_request
549 * Description:		Gets a request pkt from the free queue.
550 *
551 * Input:		ctlr	-- ptr to CL internal ctlr context
552 *			req_pkt -- ptr to OSL built req_pkt, if there's one
553 * Output:		None
554 * Return value:	ptr to request pkt	-- success
555 *			TW_CL_NULL		-- failure
556 */
557struct tw_cli_req_context *
558tw_cli_get_request(struct tw_cli_ctlr_context *ctlr
559#ifdef TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST
560	, struct tw_cl_req_packet *req_pkt
561#endif /* TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST */
562	)
563{
564	struct tw_cli_req_context	*req;
565
566	tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
567
568#ifdef TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST
569
570	if (req_pkt) {
571		if (ctlr->num_free_req_ids == 0) {
572			DbgPrint("Out of req_ids!!\n");
573			return(TW_CL_NULL);
574		}
575		ctlr->num_free_req_ids--;
576		req = (struct tw_cli_req_context *)(req_pkt->non_dma_mem);
577		req->ctlr = ctlr;
578		req->request_id = ctlr->free_req_ids[ctlr->free_req_head];
579		ctlr->busy_reqs[req->request_id] = req;
580		ctlr->free_req_head = (ctlr->free_req_head + 1) %
581			(ctlr->max_simult_reqs - 1);
582	} else
583
584#endif /* TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST */
585	{
586		/* Get a free request packet. */
587		req = tw_cli_req_q_remove_head(ctlr, TW_CLI_FREE_Q);
588	}
589
590	/* Initialize some fields to their defaults. */
591	if (req) {
592		req->req_handle = TW_CL_NULL;
593		req->data = TW_CL_NULL;
594		req->length = 0;
595		req->data_phys = 0;
596		req->state = TW_CLI_REQ_STATE_INIT; /* req being initialized */
597		req->flags = 0;
598		req->error_code = 0;
599		req->orig_req = TW_CL_NULL;
600		req->tw_cli_callback = TW_CL_NULL;
601
602#ifndef TW_OSL_DMA_MEM_ALLOC_PER_REQUEST
603
604		/*
605		 * Look at the status field in the command packet to see how
606		 * it completed the last time it was used, and zero out only
607		 * the portions that might have changed.  Note that we don't
608		 * care to zero out the sglist.
609		 */
610		if (req->cmd_pkt->command.cmd_pkt_9k.status)
611			tw_osl_memzero(req->cmd_pkt,
612				sizeof(struct tw_cl_command_header) +
613				28 /* max bytes before sglist */);
614		else
615			tw_osl_memzero(&(req->cmd_pkt->command),
616				28 /* max bytes before sglist */);
617
618#endif /* TW_OSL_DMA_MEM_ALLOC_PER_REQUEST */
619	}
620	return(req);
621}
622
623
624
625/*
626 * Function name:	tw_cli_dbg_printf
627 * Description:		Calls OSL print function if dbg_level is appropriate
628 *
629 * Input:		dbg_level -- Determines whether or not to print
630 *			ctlr_handle -- controller handle
631 *			cur_func -- text name of calling function
632 *			fmt -- format string for the arguments to follow
633 *			... -- variable number of arguments, to be printed
634 *				based on the fmt string
635 * Output:		None
636 * Return value:	None
637 */
638TW_VOID
639tw_cli_dbg_printf(TW_UINT8 dbg_level,
640	struct tw_cl_ctlr_handle *ctlr_handle, const TW_INT8 *cur_func,
641	TW_INT8 *fmt, ...)
642{
643#ifdef TW_OSL_DEBUG
644	TW_INT8	print_str[256];
645	va_list	ap;
646
647	tw_osl_memzero(print_str, 256);
648	if (dbg_level <= TW_OSL_DEBUG_LEVEL_FOR_CL) {
649		tw_osl_sprintf(print_str, "%s: ", cur_func);
650
651		va_start(ap, fmt);
652		tw_osl_vsprintf(print_str + tw_osl_strlen(print_str), fmt, ap);
653		va_end(ap);
654
655		tw_osl_strcpy(print_str + tw_osl_strlen(print_str), "\n");
656		tw_osl_dbg_printf(ctlr_handle, print_str);
657	}
658#endif /* TW_OSL_DEBUG */
659}
660
661
662
663/*
664 * Function name:	tw_cli_notify_ctlr_info
665 * Description:		Notify OSL of controller info (fw/BIOS versions, etc.).
666 *
667 * Input:		ctlr	-- ptr to CL internal ctlr context
668 * Output:		None
669 * Return value:	None
670 */
671TW_VOID
672tw_cli_notify_ctlr_info(struct tw_cli_ctlr_context *ctlr)
673{
674	TW_INT8		fw_ver[16];
675	TW_INT8		bios_ver[16];
676	TW_INT32	error[2];
677	TW_UINT8	num_ports = 0;
678
679	tw_cli_dbg_printf(5, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
680
681	/* Get the port count. */
682	error[0] = tw_cli_get_param(ctlr, TWA_PARAM_CONTROLLER_TABLE,
683			TWA_PARAM_CONTROLLER_PORT_COUNT, &num_ports,
684			1, TW_CL_NULL);
685
686	/* Get the firmware and BIOS versions. */
687	error[0] = tw_cli_get_param(ctlr, TWA_PARAM_VERSION_TABLE,
688			TWA_PARAM_VERSION_FW, fw_ver, 16, TW_CL_NULL);
689	error[1] = tw_cli_get_param(ctlr, TWA_PARAM_VERSION_TABLE,
690			TWA_PARAM_VERSION_BIOS, bios_ver, 16, TW_CL_NULL);
691
692	tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
693		TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
694		0x1300, 0x3, TW_CL_SEVERITY_INFO_STRING,
695		"Controller details:",
696		"%d ports, Firmware %.16s, BIOS %.16s",
697		num_ports,
698		error[0]?(TW_INT8 *)TW_CL_NULL:fw_ver,
699		error[1]?(TW_INT8 *)TW_CL_NULL:bios_ver);
700}
701
702
703
704/*
705 * Function name:	tw_cli_check_ctlr_state
706 * Description:		Makes sure that the fw status register reports a
707 *			proper status.
708 *
709 * Input:		ctlr	-- ptr to CL internal ctlr context
710 *			status_reg-- value in the status register
711 * Output:		None
712 * Return value:	0	-- no errors
713 *			non-zero-- errors
714 */
715TW_INT32
716tw_cli_check_ctlr_state(struct tw_cli_ctlr_context *ctlr, TW_UINT32 status_reg)
717{
718	struct tw_cl_ctlr_handle	*ctlr_handle = ctlr->ctlr_handle;
719	TW_INT32			error = TW_OSL_ESUCCESS;
720
721	tw_cli_dbg_printf(8, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
722
723	/* Check if the 'micro-controller ready' bit is not set. */
724	if ((status_reg & TWA_STATUS_EXPECTED_BITS) !=
725				TWA_STATUS_EXPECTED_BITS) {
726		TW_INT8	desc[200];
727
728		tw_osl_memzero(desc, 200);
729		tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
730			TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
731			0x1301, 0x1, TW_CL_SEVERITY_ERROR_STRING,
732			"Missing expected status bit(s)",
733			"status reg = 0x%x; Missing bits: %s",
734			status_reg,
735			tw_cli_describe_bits (~status_reg &
736				TWA_STATUS_EXPECTED_BITS, desc));
737		error = TW_OSL_EGENFAILURE;
738	}
739
740	/* Check if any error bits are set. */
741	if ((status_reg & TWA_STATUS_UNEXPECTED_BITS) != 0) {
742		TW_INT8	desc[200];
743
744		tw_osl_memzero(desc, 200);
745		tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
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_TRUE,
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_TRUE,
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			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_SBUF_WRITE_ERROR) {
806			tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
807				TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
808				0x1306, 0x1, TW_CL_SEVERITY_ERROR_STRING,
809				"SBUF write error: clearing... ",
810				"status reg = 0x%x %s",
811				status_reg,
812				tw_cli_describe_bits(status_reg, desc));
813			TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle,
814				TWA_CONTROL_CLEAR_SBUF_WRITE_ERROR);
815		}
816
817		if (status_reg & TWA_STATUS_MICROCONTROLLER_ERROR) {
818			tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
819				TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
820				0x1307, 0x1, TW_CL_SEVERITY_ERROR_STRING,
821				"Micro-controller error! ",
822				"status reg = 0x%x %s",
823				status_reg,
824				tw_cli_describe_bits(status_reg, desc));
825			error = TW_OSL_EGENFAILURE;
826		}
827	}
828	return(error);
829}
830
831
832
833/*
834 * Function name:	tw_cli_describe_bits
835 * Description:		Given the value of the status register, returns a
836 *			string describing the meaning of each set bit.
837 *
838 * Input:		reg -- status register value
839 * Output:		Pointer to a string describing each set bit
840 * Return value:	Pointer to the string describing each set bit
841 */
842TW_INT8	*
843tw_cli_describe_bits(TW_UINT32 reg, TW_INT8 *str)
844{
845	tw_osl_strcpy(str, "[");
846
847	if (reg	& TWA_STATUS_SBUF_WRITE_ERROR)
848		tw_osl_strcpy(str, "SBUF_WR_ERR,");
849	if (reg & TWA_STATUS_COMMAND_QUEUE_EMPTY)
850		tw_osl_strcpy(&str[tw_osl_strlen(str)], "CMD_Q_EMPTY,");
851	if (reg & TWA_STATUS_MICROCONTROLLER_READY)
852		tw_osl_strcpy(&str[tw_osl_strlen(str)], "MC_RDY,");
853	if (reg & TWA_STATUS_RESPONSE_QUEUE_EMPTY)
854		tw_osl_strcpy(&str[tw_osl_strlen(str)], "RESP_Q_EMPTY,");
855	if (reg & TWA_STATUS_COMMAND_QUEUE_FULL)
856		tw_osl_strcpy(&str[tw_osl_strlen(str)], "CMD_Q_FULL,");
857	if (reg & TWA_STATUS_RESPONSE_INTERRUPT)
858		tw_osl_strcpy(&str[tw_osl_strlen(str)], "RESP_INTR,");
859	if (reg & TWA_STATUS_COMMAND_INTERRUPT)
860		tw_osl_strcpy(&str[tw_osl_strlen(str)], "CMD_INTR,");
861	if (reg & TWA_STATUS_ATTENTION_INTERRUPT)
862		tw_osl_strcpy(&str[tw_osl_strlen(str)], "ATTN_INTR,");
863	if (reg & TWA_STATUS_HOST_INTERRUPT)
864		tw_osl_strcpy(&str[tw_osl_strlen(str)], "HOST_INTR,");
865	if (reg & TWA_STATUS_PCI_ABORT_INTERRUPT)
866		tw_osl_strcpy(&str[tw_osl_strlen(str)], "PCI_ABRT,");
867	if (reg & TWA_STATUS_MICROCONTROLLER_ERROR)
868		tw_osl_strcpy(&str[tw_osl_strlen(str)], "MC_ERR,");
869	if (reg & TWA_STATUS_QUEUE_ERROR_INTERRUPT)
870		tw_osl_strcpy(&str[tw_osl_strlen(str)], "Q_ERR,");
871	if (reg & TWA_STATUS_PCI_PARITY_ERROR_INTERRUPT)
872		tw_osl_strcpy(&str[tw_osl_strlen(str)], "PCI_PERR");
873
874	tw_osl_strcpy(&str[tw_osl_strlen(str)], "]");
875	return(str);
876}
877
878
879
880#ifdef TW_OSL_DEBUG
881
882/*
883 * Function name:	tw_cl_print_ctlr_stats
884 * Description:		Prints the current status of the controller.
885 *
886 * Input:		ctlr_handle-- controller handle
887 * Output:		None
888 * Return value:	None
889 */
890TW_VOID
891tw_cl_print_ctlr_stats(struct tw_cl_ctlr_handle *ctlr_handle)
892{
893	struct tw_cli_ctlr_context	*ctlr =
894		(struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt);
895	TW_UINT32			status_reg;
896	TW_INT8				desc[200];
897
898	tw_cli_dbg_printf(7, ctlr->ctlr_handle, "", "entered");
899
900	/* Print current controller details. */
901	tw_cli_dbg_printf(0, ctlr_handle, "", "cl_ctlr_ctxt = %p", ctlr);
902
903	tw_osl_memzero(desc, 200);
904	status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr_handle);
905	tw_cli_dbg_printf(0, ctlr_handle, "", "status reg = 0x%x %s",
906		status_reg, tw_cli_describe_bits(status_reg, desc));
907
908	tw_cli_dbg_printf(0, ctlr_handle, "", "CLq type  current  max");
909	tw_cli_dbg_printf(0, ctlr_handle, "", "free      %04d     %04d",
910		ctlr->q_stats[TW_CLI_FREE_Q].cur_len,
911		ctlr->q_stats[TW_CLI_FREE_Q].max_len);
912	tw_cli_dbg_printf(0, ctlr_handle, "", "busy      %04d     %04d",
913		ctlr->q_stats[TW_CLI_BUSY_Q].cur_len,
914		ctlr->q_stats[TW_CLI_BUSY_Q].max_len);
915	tw_cli_dbg_printf(0, ctlr_handle, "", "pending   %04d     %04d",
916		ctlr->q_stats[TW_CLI_PENDING_Q].cur_len,
917		ctlr->q_stats[TW_CLI_PENDING_Q].max_len);
918	tw_cli_dbg_printf(0, ctlr_handle, "", "complete  %04d     %04d",
919		ctlr->q_stats[TW_CLI_COMPLETE_Q].cur_len,
920		ctlr->q_stats[TW_CLI_COMPLETE_Q].max_len);
921	tw_cli_dbg_printf(0, ctlr_handle, "", "AEN queue head %d  tail %d",
922			ctlr->aen_head, ctlr->aen_tail);
923}
924
925
926
927/*
928 * Function name:	tw_cl_reset_stats
929 * Description:		Resets CL maintained statistics for the controller.
930 *
931 * Input:		ctlr_handle-- controller handle
932 * Output:		None
933 * Return value:	None
934 */
935TW_VOID
936tw_cl_reset_stats(struct tw_cl_ctlr_handle *ctlr_handle)
937{
938	struct tw_cli_ctlr_context	*ctlr =
939		(struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt);
940
941	tw_cli_dbg_printf(7, ctlr_handle, tw_osl_cur_func(), "entered");
942	ctlr->q_stats[TW_CLI_FREE_Q].max_len = 0;
943	ctlr->q_stats[TW_CLI_BUSY_Q].max_len = 0;
944	ctlr->q_stats[TW_CLI_PENDING_Q].max_len = 0;
945	ctlr->q_stats[TW_CLI_COMPLETE_Q].max_len = 0;
946}
947
948
949
950/*
951 * Function name:	tw_cli_print_req_info
952 * Description:		Prints CL internal details of a given request.
953 *
954 * Input:		req	-- ptr to CL internal request context
955 * Output:		None
956 * Return value:	None
957 */
958TW_VOID
959tw_cl_print_req_info(struct tw_cl_req_handle *req_handle)
960{
961	struct tw_cli_req_context	*req = req_handle->cl_req_ctxt;
962	struct tw_cli_ctlr_context	*ctlr = req->ctlr;
963	struct tw_cl_ctlr_handle	*ctlr_handle = ctlr->ctlr_handle;
964	struct tw_cl_command_packet	*cmd_pkt = req->cmd_pkt;
965	struct tw_cl_command_9k		*cmd9k;
966	union tw_cl_command_7k		*cmd7k;
967	TW_UINT8			*cdb;
968	TW_VOID				*sgl;
969	TW_UINT32			sgl_entries;
970	TW_UINT32			i;
971
972	tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(),
973		"CL details for request:");
974	tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(),
975		"req_handle = %p, ctlr = %p,\n"
976		"cmd_pkt = %p, cmd_pkt_phys = 0x%llx,\n"
977		"data = %p, length = 0x%x, data_phys = 0x%llx,\n"
978		"state = 0x%x, flags = 0x%x, error = 0x%x,\n"
979		"orig_req = %p, callback = %p, req_id = 0x%x,\n"
980		"next_req = %p, prev_req = %p",
981		req_handle, ctlr,
982		cmd_pkt, req->cmd_pkt_phys,
983		req->data, req->length, req->data_phys,
984		req->state, req->flags, req->error_code,
985		req->orig_req, req->tw_cli_callback, req->request_id,
986		req->link.next, req->link.prev);
987
988	if (req->flags & TW_CLI_REQ_FLAGS_9K) {
989		cmd9k = &(cmd_pkt->command.cmd_pkt_9k);
990		sgl = cmd9k->sg_list;
991		sgl_entries = TW_CL_SWAP16(
992			GET_SGL_ENTRIES(cmd9k->lun_h4__sgl_entries));
993		tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(),
994			"9K cmd: opcode = 0x%x, unit = 0x%x, req_id = 0x%x,\n"
995			"status = 0x%x, sgl_offset = 0x%x, sgl_entries = 0x%x",
996			GET_OPCODE(cmd9k->res__opcode),
997			cmd9k->unit,
998			TW_CL_SWAP16(GET_REQ_ID(cmd9k->lun_l4__req_id)),
999			cmd9k->status,
1000			cmd9k->sgl_offset,
1001			sgl_entries);
1002
1003		cdb = (TW_UINT8 *)(cmd9k->cdb);
1004		tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(),
1005			"CDB: %x %x %x %x %x %x %x %x"
1006			"%x %x %x %x %x %x %x %x",
1007			cdb[0], cdb[1], cdb[2], cdb[3],
1008			cdb[4], cdb[5], cdb[6], cdb[7],
1009			cdb[8], cdb[9], cdb[10], cdb[11],
1010			cdb[12], cdb[13], cdb[14], cdb[15]);
1011	} else {
1012		cmd7k = &(cmd_pkt->command.cmd_pkt_7k);
1013		sgl = cmd7k->param.sgl;
1014		sgl_entries = (cmd7k->generic.size -
1015			GET_SGL_OFF(cmd7k->generic.sgl_off__opcode)) /
1016			((ctlr->flags & TW_CL_64BIT_ADDRESSES) ? 3 : 2);
1017		tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(),
1018			"7K cmd: opcode = 0x%x, sgl_offset = 0x%x,\n"
1019			"size = 0x%x, req_id = 0x%x, unit = 0x%x,\n"
1020			"status = 0x%x, flags = 0x%x, count = 0x%x",
1021			GET_OPCODE(cmd7k->generic.sgl_off__opcode),
1022			GET_SGL_OFF(cmd7k->generic.sgl_off__opcode),
1023			cmd7k->generic.size,
1024			TW_CL_SWAP16(cmd7k->generic.request_id),
1025			GET_UNIT(cmd7k->generic.host_id__unit),
1026			cmd7k->generic.status,
1027			cmd7k->generic.flags,
1028			TW_CL_SWAP16(cmd7k->generic.count));
1029	}
1030
1031	tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(), "SG entries:");
1032
1033	if (ctlr->flags & TW_CL_64BIT_ADDRESSES) {
1034		struct tw_cl_sg_desc64 *sgl64 = (struct tw_cl_sg_desc64 *)sgl;
1035
1036		for (i = 0; i < sgl_entries; i++) {
1037			tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(),
1038				"0x%llx  0x%x",
1039				sgl64[i].address, sgl64[i].length);
1040		}
1041	} else {
1042		struct tw_cl_sg_desc32 *sgl32 = (struct tw_cl_sg_desc32 *)sgl;
1043
1044		for (i = 0; i < sgl_entries; i++) {
1045			tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(),
1046				"0x%x  0x%x",
1047				sgl32[i].address, sgl32[i].length);
1048		}
1049	}
1050}
1051
1052#endif /* TW_OSL_DEBUG */
1053
1054