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