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: releng/12.0/sys/dev/twa/tw_cl_misc.c 326255 2017-11-27 14:52:40Z pfg $
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
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
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
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
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
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
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
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
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
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 *
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
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
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
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 *
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
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
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
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
Cache object: ec2ffdb9c441cd460014d597e3547631
|