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