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