2 * Copyright (c) 2004-07 Applied Micro Circuits Corporation.
3 * Copyright (c) 2004-05 Vinod Kashyap
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * $FreeBSD: head/sys/dev/twa/tw_cl_misc.c 242827 2012-11-09 15:29:52Z rdivacky $
31 * AMCC'S 3ware driver for 9000 series storage controllers.
33 * Author: Vinod Kashyap
34 * Modifications by: Adam Radford
35 * Modifications by: Manjunath Ranganathaiah
40 * Common Layer miscellaneous functions.
44 #include "tw_osl_share.h"
45 #include "tw_cl_share.h"
46 #include "tw_cl_fwif.h"
47 #include "tw_cl_ioctl.h"
49 #include "tw_cl_externs.h"
50 #include "tw_osl_ioctl.h"
54 /* AEN severity table. */
55 TW_INT8
*tw_cli_severity_string_table
[] = {
57 TW_CL_SEVERITY_ERROR_STRING
,
58 TW_CL_SEVERITY_WARNING_STRING
,
59 TW_CL_SEVERITY_INFO_STRING
,
60 TW_CL_SEVERITY_DEBUG_STRING
,
67 * Function name: tw_cli_drain_complete_queue
68 * Description: This function gets called during a controller reset.
69 * It errors back to the OS Layer, all those requests that
70 * are in the complete queue, at the time of the reset.
71 * Any CL internal requests will be simply freed.
73 * Input: ctlr -- ptr to CL internal ctlr context
78 tw_cli_drain_complete_queue(struct tw_cli_ctlr_context
*ctlr
)
80 struct tw_cli_req_context
*req
;
81 struct tw_cl_req_packet
*req_pkt
;
83 tw_cli_dbg_printf(3, ctlr
->ctlr_handle
, tw_osl_cur_func(), "entered");
85 /* Walk the busy queue. */
86 while ((req
= tw_cli_req_q_remove_head(ctlr
, TW_CLI_COMPLETE_Q
)) !=
88 if (req
->flags
& TW_CLI_REQ_FLAGS_INTERNAL
) {
90 * It's an internal request. Set the appropriate
91 * error and call the CL internal callback if there's
92 * one. If the request originator is polling for
93 * completion, he should be checking req->error to
94 * determine that the request did not go through.
95 * The request originators are responsible for the
98 req
->error_code
= TW_CL_ERR_REQ_BUS_RESET
;
99 if (req
->tw_cli_callback
)
100 req
->tw_cli_callback(req
);
101 } else if (req
->flags
& TW_CLI_REQ_FLAGS_PASSTHRU
) {
102 /* It's a passthru request. Complete it. */
103 if ((req_pkt
= req
->orig_req
) != TW_CL_NULL
) {
104 req_pkt
->status
= TW_CL_ERR_REQ_BUS_RESET
;
106 if (req_pkt
->tw_osl_callback
)
107 req_pkt
->tw_osl_callback(req
->req_handle
);
109 tw_cli_req_q_insert_tail(req
, TW_CLI_FREE_Q
);
111 /* It's an external (SCSI) request. Add it to the reset queue. */
112 tw_osl_untimeout(req
->req_handle
);
113 tw_cli_req_q_insert_tail(req
, TW_CLI_RESET_Q
);
115 } /* End of while loop */
121 * Function name: tw_cli_drain_busy_queue
122 * Description: This function gets called during a controller reset.
123 * It errors back to the OS Layer, all those requests that
124 * were pending with the firmware, at the time of the
127 * Input: ctlr -- ptr to CL internal ctlr context
132 tw_cli_drain_busy_queue(struct tw_cli_ctlr_context
*ctlr
)
134 struct tw_cli_req_context
*req
;
135 struct tw_cl_req_packet
*req_pkt
;
137 tw_cli_dbg_printf(3, ctlr
->ctlr_handle
, tw_osl_cur_func(), "entered");
139 /* Walk the busy queue. */
140 while ((req
= tw_cli_req_q_remove_head(ctlr
, TW_CLI_BUSY_Q
)) !=
142 if (req
->flags
& TW_CLI_REQ_FLAGS_INTERNAL
) {
144 * It's an internal request. Set the appropriate
145 * error and call the CL internal callback if there's
146 * one. If the request originator is polling for
147 * completion, he should be checking req->error to
148 * determine that the request did not go through.
149 * The request originators are responsible for the
152 req
->error_code
= TW_CL_ERR_REQ_BUS_RESET
;
153 if (req
->tw_cli_callback
)
154 req
->tw_cli_callback(req
);
155 } else if (req
->flags
& TW_CLI_REQ_FLAGS_PASSTHRU
) {
156 /* It's a passthru request. Complete it. */
157 if ((req_pkt
= req
->orig_req
) != TW_CL_NULL
) {
158 req_pkt
->status
= TW_CL_ERR_REQ_BUS_RESET
;
160 if (req_pkt
->tw_osl_callback
)
161 req_pkt
->tw_osl_callback(req
->req_handle
);
163 tw_cli_req_q_insert_tail(req
, TW_CLI_FREE_Q
);
165 /* It's an external (SCSI) request. Add it to the reset queue. */
166 tw_osl_untimeout(req
->req_handle
);
167 tw_cli_req_q_insert_tail(req
, TW_CLI_RESET_Q
);
169 } /* End of while loop */
175 * Function name: tw_cli_drain_pending_queue
176 * Description: This function gets called during a controller reset.
177 * It errors back to the OS Layer, all those requests that
178 * were in the pending queue, at the time of the reset.
180 * Input: ctlr -- ptr to CL internal ctlr context
186 tw_cli_drain_pending_queue(struct tw_cli_ctlr_context
*ctlr
)
188 struct tw_cli_req_context
*req
;
189 struct tw_cl_req_packet
*req_pkt
;
191 tw_cli_dbg_printf(3, ctlr
->ctlr_handle
, tw_osl_cur_func(), "entered");
194 * Pull requests off the pending queue, and complete them.
196 while ((req
= tw_cli_req_q_remove_head(ctlr
, TW_CLI_PENDING_Q
)) !=
198 if (req
->flags
& TW_CLI_REQ_FLAGS_INTERNAL
) {
200 * It's an internal request. Set the appropriate
201 * error and call the CL internal callback if there's
202 * one. If the request originator is polling for
203 * completion, he should be checking req->error to
204 * determine that the request did not go through.
205 * The request originators are responsible for the
208 req
->error_code
= TW_CL_ERR_REQ_BUS_RESET
;
209 if (req
->tw_cli_callback
)
210 req
->tw_cli_callback(req
);
211 } else if (req
->flags
& TW_CLI_REQ_FLAGS_PASSTHRU
) {
212 /* It's a passthru request. Complete it. */
213 if ((req_pkt
= req
->orig_req
) != TW_CL_NULL
) {
214 req_pkt
->status
= TW_CL_ERR_REQ_BUS_RESET
;
216 if (req_pkt
->tw_osl_callback
)
217 req_pkt
->tw_osl_callback(req
->req_handle
);
219 tw_cli_req_q_insert_tail(req
, TW_CLI_FREE_Q
);
221 /* It's an external (SCSI) request. Add it to the reset queue. */
222 tw_osl_untimeout(req
->req_handle
);
223 tw_cli_req_q_insert_tail(req
, TW_CLI_RESET_Q
);
225 } /* End of while loop */
231 * Function name: tw_cli_drain_response_queue
232 * Description: Drain the controller response queue.
234 * Input: ctlr -- ptr to per ctlr structure
236 * Return value: 0 -- success
240 tw_cli_drain_response_queue(struct tw_cli_ctlr_context
*ctlr
)
243 TW_UINT32 status_reg
;
245 tw_cli_dbg_printf(4, ctlr
->ctlr_handle
, tw_osl_cur_func(), "entered");
248 status_reg
= TW_CLI_READ_STATUS_REGISTER(ctlr
->ctlr_handle
);
250 if (status_reg
& TWA_STATUS_RESPONSE_QUEUE_EMPTY
)
251 return(TW_OSL_ESUCCESS
); /* no more response queue entries */
253 resp
= TW_CLI_READ_RESPONSE_QUEUE(ctlr
->ctlr_handle
);
260 * Function name: tw_cli_find_response
261 * Description: Find a particular response in the ctlr response queue.
263 * Input: ctlr -- ptr to per ctlr structure
264 * req_id -- request id of the response to look for
266 * Return value: 0 -- success
270 tw_cli_find_response(struct tw_cli_ctlr_context
*ctlr
, TW_INT32 req_id
)
274 TW_UINT32 status_reg
;
276 tw_cli_dbg_printf(4, ctlr
->ctlr_handle
, tw_osl_cur_func(), "entered");
279 status_reg
= TW_CLI_READ_STATUS_REGISTER(ctlr
->ctlr_handle
);
281 if (status_reg
& TWA_STATUS_RESPONSE_QUEUE_EMPTY
)
282 return(TW_OSL_ENOTTY
); /* no more response queue entries */
284 if (ctlr
->device_id
== TW_CL_DEVICE_ID_9K
) {
285 resp
= TW_CLI_READ_RESPONSE_QUEUE(ctlr
->ctlr_handle
);
286 resp_id
= GET_RESP_ID(resp
);
288 resp
= TW_CLI_READ_LARGE_RESPONSE_QUEUE(
290 resp_id
= GET_LARGE_RESP_ID(resp
);
292 if (resp_id
== req_id
)
293 return(TW_OSL_ESUCCESS
); /* found the req_id */
300 * Function name: tw_cli_drain_aen_queue
301 * Description: Fetches all un-retrieved AEN's posted by fw.
303 * Input: ctlr -- ptr to CL internal ctlr context
305 * Return value: 0 -- success
309 tw_cli_drain_aen_queue(struct tw_cli_ctlr_context
*ctlr
)
311 struct tw_cli_req_context
*req
;
316 tw_cli_dbg_printf(4, ctlr
->ctlr_handle
, tw_osl_cur_func(), "entered");
319 if ((req
= tw_cli_get_request(ctlr
321 error
= TW_OSL_EBUSY
;
325 req
->flags
|= TW_CLI_REQ_FLAGS_INTERNAL
;
326 req
->tw_cli_callback
= TW_CL_NULL
;
327 if ((error
= tw_cli_send_scsi_cmd(req
,
328 0x03 /* REQUEST_SENSE */))) {
329 tw_cli_dbg_printf(1, ctlr
->ctlr_handle
,
331 "Cannot send command to fetch aen");
335 end_time
= tw_osl_get_local_time() +
336 TW_CLI_REQUEST_TIMEOUT_PERIOD
;
338 if ((error
= req
->error_code
))
340 * This will take care of completion due to
341 * a reset, or a failure in
342 * tw_cli_submit_pending_queue.
346 tw_cli_process_resp_intr(req
->ctlr
);
348 if ((req
->state
!= TW_CLI_REQ_STATE_BUSY
) &&
349 (req
->state
!= TW_CLI_REQ_STATE_PENDING
))
351 } while (tw_osl_get_local_time() <= end_time
);
353 if (req
->state
!= TW_CLI_REQ_STATE_COMPLETE
) {
354 error
= TW_OSL_ETIMEDOUT
;
358 if ((error
= req
->cmd_pkt
->command
.cmd_pkt_9k
.status
)) {
360 struct tw_cl_command_header
*cmd_hdr
;
361 cmd_hdr
= &req
->cmd_pkt
->cmd_hdr
;
362 tw_cli_create_ctlr_event(ctlr
,
363 TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR
,
369 aen_code
= tw_cli_manage_aen(ctlr
, req
);
370 if (aen_code
== TWA_AEN_QUEUE_EMPTY
)
372 if (aen_code
== TWA_AEN_SYNC_TIME_WITH_HOST
)
375 ctlr
->internal_req_busy
= TW_CL_FALSE
;
376 tw_cli_req_q_insert_tail(req
, TW_CLI_FREE_Q
);
382 ctlr
->internal_req_busy
= TW_CL_FALSE
;
383 tw_cli_req_q_insert_tail(req
, TW_CLI_FREE_Q
);
391 * Function name: tw_cli_find_aen
392 * Description: Reports whether a given AEN ever occurred.
394 * Input: ctlr -- ptr to CL internal ctlr context
395 * aen_code-- AEN to look for
397 * Return value: 0 -- success
401 tw_cli_find_aen(struct tw_cli_ctlr_context
*ctlr
, TW_UINT16 aen_code
)
403 TW_UINT32 last_index
;
406 tw_cli_dbg_printf(4, ctlr
->ctlr_handle
, tw_osl_cur_func(), "entered");
408 if (ctlr
->aen_q_wrapped
)
409 last_index
= ctlr
->aen_head
;
415 i
= (i
+ ctlr
->max_aens_supported
- 1) %
416 ctlr
->max_aens_supported
;
417 if (ctlr
->aen_queue
[i
].aen_code
== aen_code
)
418 return(TW_OSL_ESUCCESS
);
419 } while (i
!= last_index
);
421 return(TW_OSL_EGENFAILURE
);
427 * Function name: tw_cli_poll_status
428 * Description: Poll for a given status to show up in the firmware
431 * Input: ctlr -- ptr to CL internal ctlr context
432 * status -- status to look for
433 * timeout -- max # of seconds to wait before giving up
435 * Return value: 0 -- success
439 tw_cli_poll_status(struct tw_cli_ctlr_context
*ctlr
, TW_UINT32 status
,
443 TW_UINT32 status_reg
;
445 tw_cli_dbg_printf(4, ctlr
->ctlr_handle
, tw_osl_cur_func(), "entered");
447 end_time
= tw_osl_get_local_time() + timeout
;
449 status_reg
= TW_CLI_READ_STATUS_REGISTER(ctlr
->ctlr_handle
);
450 if ((status_reg
& status
) == status
)
451 /* got the required bit(s) */
452 return(TW_OSL_ESUCCESS
);
455 } while (tw_osl_get_local_time() <= end_time
);
457 return(TW_OSL_ETIMEDOUT
);
463 * Function name: tw_cl_create_event
464 * Description: Creates and queues ctlr/CL/OSL AEN's to be
465 * supplied to user-space tools on request.
466 * Also notifies OS Layer.
467 * Input: ctlr -- ptr to CL internal ctlr context
468 * queue_event-- TW_CL_TRUE --> queue event;
469 * TW_CL_FALSE--> don't queue event
470 * (simply notify OSL)
471 * event_src -- source of event
472 * event_code -- AEN/error code
473 * severity -- severity of event
474 * severity_str--Text description of severity
475 * event_desc -- standard string related to the event/error
476 * event_specific_desc -- format string for additional
477 * info about the event
478 * ... -- additional arguments conforming to the format
479 * specified by event_specific_desc
484 tw_cl_create_event(struct tw_cl_ctlr_handle
*ctlr_handle
,
485 TW_UINT8 queue_event
, TW_UINT8 event_src
, TW_UINT16 event_code
,
486 TW_UINT8 severity
, TW_UINT8
*severity_str
, TW_UINT8
*event_desc
,
487 TW_UINT8
*event_specific_desc
, ...)
489 struct tw_cli_ctlr_context
*ctlr
= ctlr_handle
->cl_ctlr_ctxt
;
490 struct tw_cl_event_packet event_pkt
;
491 struct tw_cl_event_packet
*event
;
495 tw_cli_dbg_printf(8, ctlr_handle
, tw_osl_cur_func(), "entered");
497 if ((ctlr
) && (queue_event
)) {
498 /* Protect access to ctlr->aen_head. */
499 tw_osl_get_lock(ctlr_handle
, ctlr
->gen_lock
);
501 aen_head
= ctlr
->aen_head
;
502 ctlr
->aen_head
= (aen_head
+ 1) % ctlr
->max_aens_supported
;
504 /* Queue the event. */
505 event
= &(ctlr
->aen_queue
[aen_head
]);
506 tw_osl_memzero(event
->parameter_data
,
507 sizeof(event
->parameter_data
));
509 if (event
->retrieved
== TW_CL_AEN_NOT_RETRIEVED
)
510 ctlr
->aen_q_overflow
= TW_CL_TRUE
;
511 event
->sequence_id
= ++(ctlr
->aen_cur_seq_id
);
512 if ((aen_head
+ 1) == ctlr
->max_aens_supported
) {
513 tw_cli_dbg_printf(4, ctlr
->ctlr_handle
,
514 tw_osl_cur_func(), "AEN queue wrapped");
515 ctlr
->aen_q_wrapped
= TW_CL_TRUE
;
518 /* Free access to ctlr->aen_head. */
519 tw_osl_free_lock(ctlr_handle
, ctlr
->gen_lock
);
522 tw_osl_memzero(event
, sizeof(struct tw_cl_event_packet
));
525 event
->event_src
= event_src
;
526 event
->time_stamp_sec
= (TW_UINT32
)tw_osl_get_local_time();
527 event
->aen_code
= event_code
;
528 event
->severity
= severity
;
529 tw_osl_strcpy(event
->severity_str
, severity_str
);
530 event
->retrieved
= TW_CL_AEN_NOT_RETRIEVED
;
532 __va_start(ap
, event_specific_desc
);
533 tw_osl_vsprintf(event
->parameter_data
, event_specific_desc
, ap
);
536 event
->parameter_len
=
537 (TW_UINT8
)(tw_osl_strlen(event
->parameter_data
));
538 tw_osl_strcpy(event
->parameter_data
+ event
->parameter_len
+ 1,
540 event
->parameter_len
+= (1 + tw_osl_strlen(event_desc
));
542 tw_cli_dbg_printf(4, ctlr_handle
, tw_osl_cur_func(),
543 "event = %x %x %x %x %x %x %x\n %s",
545 event
->time_stamp_sec
,
550 event
->parameter_len
,
551 event
->parameter_data
);
553 tw_osl_notify_event(ctlr_handle
, event
);
559 * Function name: tw_cli_get_request
560 * Description: Gets a request pkt from the free queue.
562 * Input: ctlr -- ptr to CL internal ctlr context
563 * req_pkt -- ptr to OSL built req_pkt, if there's one
565 * Return value: ptr to request pkt -- success
566 * TW_CL_NULL -- failure
568 struct tw_cli_req_context
*
569 tw_cli_get_request(struct tw_cli_ctlr_context
*ctlr
572 struct tw_cli_req_context
*req
;
574 tw_cli_dbg_printf(4, ctlr
->ctlr_handle
, tw_osl_cur_func(), "entered");
577 /* Get a free request packet. */
578 req
= tw_cli_req_q_remove_head(ctlr
, TW_CLI_FREE_Q
);
581 /* Initialize some fields to their defaults. */
583 req
->req_handle
= TW_CL_NULL
;
584 req
->data
= TW_CL_NULL
;
587 req
->state
= TW_CLI_REQ_STATE_INIT
; /* req being initialized */
590 req
->orig_req
= TW_CL_NULL
;
591 req
->tw_cli_callback
= TW_CL_NULL
;
594 * Look at the status field in the command packet to see how
595 * it completed the last time it was used, and zero out only
596 * the portions that might have changed. Note that we don't
597 * care to zero out the sglist.
599 if (req
->cmd_pkt
->command
.cmd_pkt_9k
.status
)
600 tw_osl_memzero(req
->cmd_pkt
,
601 sizeof(struct tw_cl_command_header
) +
602 28 /* max bytes before sglist */);
604 tw_osl_memzero(&(req
->cmd_pkt
->command
),
605 28 /* max bytes before sglist */);
614 * Function name: tw_cli_dbg_printf
615 * Description: Calls OSL print function if dbg_level is appropriate
617 * Input: dbg_level -- Determines whether or not to print
618 * ctlr_handle -- controller handle
619 * cur_func -- text name of calling function
620 * fmt -- format string for the arguments to follow
621 * ... -- variable number of arguments, to be printed
622 * based on the fmt string
627 tw_cli_dbg_printf(TW_UINT8 dbg_level
,
628 struct tw_cl_ctlr_handle
*ctlr_handle
, const TW_INT8
*cur_func
,
632 TW_INT8 print_str
[256];
635 tw_osl_memzero(print_str
, 256);
636 if (dbg_level
<= TW_OSL_DEBUG_LEVEL_FOR_CL
) {
637 tw_osl_sprintf(print_str
, "%s: ", cur_func
);
640 tw_osl_vsprintf(print_str
+ tw_osl_strlen(print_str
), fmt
, ap
);
643 tw_osl_strcpy(print_str
+ tw_osl_strlen(print_str
), "\n");
644 tw_osl_dbg_printf(ctlr_handle
, "%s", print_str
);
646 #endif /* TW_OSL_DEBUG */
652 * Function name: tw_cli_notify_ctlr_info
653 * Description: Notify OSL of controller info (fw/BIOS versions, etc.).
655 * Input: ctlr -- ptr to CL internal ctlr context
660 tw_cli_notify_ctlr_info(struct tw_cli_ctlr_context
*ctlr
)
663 TW_INT8 bios_ver
[16];
664 TW_INT8 ctlr_model
[16];
666 TW_UINT8 num_ports
= 0;
668 tw_cli_dbg_printf(5, ctlr
->ctlr_handle
, tw_osl_cur_func(), "entered");
670 /* Get the port count. */
671 error
[0] = tw_cli_get_param(ctlr
, TWA_PARAM_CONTROLLER_TABLE
,
672 TWA_PARAM_CONTROLLER_PORT_COUNT
, &num_ports
,
675 /* Get the firmware and BIOS versions. */
676 error
[0] = tw_cli_get_param(ctlr
, TWA_PARAM_VERSION_TABLE
,
677 TWA_PARAM_VERSION_FW
, fw_ver
, 16, TW_CL_NULL
);
678 error
[1] = tw_cli_get_param(ctlr
, TWA_PARAM_VERSION_TABLE
,
679 TWA_PARAM_VERSION_BIOS
, bios_ver
, 16, TW_CL_NULL
);
680 error
[2] = tw_cli_get_param(ctlr
, TWA_PARAM_VERSION_TABLE
,
681 TWA_PARAM_CTLR_MODEL
, ctlr_model
, 16, TW_CL_NULL
);
683 tw_cl_create_event(ctlr
->ctlr_handle
, TW_CL_FALSE
,
684 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR
,
685 0x1300, 0x3, TW_CL_SEVERITY_INFO_STRING
,
686 "Controller details",
687 "Model %.16s, %d ports, Firmware %.16s, BIOS %.16s",
688 error
[2]?(TW_INT8
*)TW_CL_NULL
:ctlr_model
,
690 error
[0]?(TW_INT8
*)TW_CL_NULL
:fw_ver
,
691 error
[1]?(TW_INT8
*)TW_CL_NULL
:bios_ver
);
697 * Function name: tw_cli_check_ctlr_state
698 * Description: Makes sure that the fw status register reports a
701 * Input: ctlr -- ptr to CL internal ctlr context
702 * status_reg-- value in the status register
704 * Return value: 0 -- no errors
708 tw_cli_check_ctlr_state(struct tw_cli_ctlr_context
*ctlr
, TW_UINT32 status_reg
)
710 struct tw_cl_ctlr_handle
*ctlr_handle
= ctlr
->ctlr_handle
;
711 TW_INT32 error
= TW_OSL_ESUCCESS
;
713 tw_cli_dbg_printf(8, ctlr
->ctlr_handle
, tw_osl_cur_func(), "entered");
715 /* Check if the 'micro-controller ready' bit is not set. */
716 if (!(status_reg
& TWA_STATUS_MICROCONTROLLER_READY
)) {
719 tw_osl_memzero(desc
, 200);
720 if (!(ctlr
->reset_phase1_in_progress
)) {
721 tw_cl_create_event(ctlr_handle
, TW_CL_FALSE
,
722 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT
,
723 0x1301, 0x1, TW_CL_SEVERITY_ERROR_STRING
,
724 "Missing expected status bit(s)",
725 "status reg = 0x%x; Missing bits: %s",
727 tw_cli_describe_bits(
728 TWA_STATUS_MICROCONTROLLER_READY
,
730 error
= TW_OSL_EGENFAILURE
;
734 /* Check if any error bits are set. */
735 if ((status_reg
& TWA_STATUS_UNEXPECTED_BITS
) != 0) {
738 tw_osl_memzero(desc
, 200);
740 /* Skip queue error msgs during 9650SE/9690SA reset */
741 if (((ctlr
->device_id
!= TW_CL_DEVICE_ID_9K_E
) &&
742 (ctlr
->device_id
!= TW_CL_DEVICE_ID_9K_SA
)) ||
743 (!(ctlr
->reset_in_progress
)) ||
744 ((status_reg
& TWA_STATUS_QUEUE_ERROR_INTERRUPT
) == 0))
746 tw_cl_create_event(ctlr_handle
, TW_CL_FALSE
,
747 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT
,
748 0x1302, 0x1, TW_CL_SEVERITY_ERROR_STRING
,
749 "Unexpected status bit(s)",
750 "status reg = 0x%x Unexpected bits: %s",
751 status_reg
& TWA_STATUS_UNEXPECTED_BITS
,
752 tw_cli_describe_bits(status_reg
&
753 TWA_STATUS_UNEXPECTED_BITS
, desc
));
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",
764 tw_cli_describe_bits(status_reg
, desc
));
765 TW_CLI_WRITE_CONTROL_REGISTER(ctlr
->ctlr_handle
,
766 TWA_CONTROL_CLEAR_PARITY_ERROR
);
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 */
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",
783 tw_cli_describe_bits(status_reg
, desc
));
784 TW_CLI_WRITE_CONTROL_REGISTER(ctlr
->ctlr_handle
,
785 TWA_CONTROL_CLEAR_PCI_ABORT
);
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 */
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",
806 tw_cli_describe_bits(status_reg
, desc
));
807 TW_CLI_WRITE_CONTROL_REGISTER(ctlr
->ctlr_handle
,
808 TWA_CONTROL_CLEAR_QUEUE_ERROR
);
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.
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
826 tw_cli_describe_bits(TW_UINT32 reg
, TW_INT8
*str
)
828 tw_osl_strcpy(str
, "[");
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");
853 tw_osl_strcpy(&str
[tw_osl_strlen(str
)], "]");
862 * Function name: tw_cl_print_ctlr_stats
863 * Description: Prints the current status of the controller.
865 * Input: ctlr_handle-- controller handle
870 tw_cl_print_ctlr_stats(struct tw_cl_ctlr_handle
*ctlr_handle
)
872 struct tw_cli_ctlr_context
*ctlr
=
873 (struct tw_cli_ctlr_context
*)(ctlr_handle
->cl_ctlr_ctxt
);
874 TW_UINT32 status_reg
;
877 tw_cli_dbg_printf(7, ctlr
->ctlr_handle
, "", "entered");
879 /* Print current controller details. */
880 tw_cli_dbg_printf(0, ctlr_handle
, "", "cl_ctlr_ctxt = %p", ctlr
);
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
));
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
);
907 * Function name: tw_cl_reset_stats
908 * Description: Resets CL maintained statistics for the controller.
910 * Input: ctlr_handle-- controller handle
915 tw_cl_reset_stats(struct tw_cl_ctlr_handle
*ctlr_handle
)
917 struct tw_cli_ctlr_context
*ctlr
=
918 (struct tw_cli_ctlr_context
*)(ctlr_handle
->cl_ctlr_ctxt
);
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;
930 * Function name: tw_cli_print_req_info
931 * Description: Prints CL internal details of a given request.
933 * Input: req -- ptr to CL internal request context
938 tw_cl_print_req_info(struct tw_cl_req_handle
*req_handle
)
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
;
948 TW_UINT32 sgl_entries
;
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",
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
);
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
),
977 TW_CL_SWAP16(GET_REQ_ID(cmd9k
->lun_l4__req_id
)),
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]);
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
));
1010 tw_cli_dbg_printf(0, ctlr_handle
, tw_osl_cur_func(), "SG entries:");
1012 if (ctlr
->flags
& TW_CL_64BIT_ADDRESSES
) {
1013 struct tw_cl_sg_desc64
*sgl64
= (struct tw_cl_sg_desc64
*)sgl
;
1015 for (i
= 0; i
< sgl_entries
; i
++) {
1016 tw_cli_dbg_printf(0, ctlr_handle
, tw_osl_cur_func(),
1018 sgl64
[i
].address
, sgl64
[i
].length
);
1021 struct tw_cl_sg_desc32
*sgl32
= (struct tw_cl_sg_desc32
*)sgl
;
1023 for (i
= 0; i
< sgl_entries
; i
++) {
1024 tw_cli_dbg_printf(0, ctlr_handle
, tw_osl_cur_func(),
1026 sgl32
[i
].address
, sgl32
[i
].length
);
1031 #endif /* TW_OSL_DEBUG */