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