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