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