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