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