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