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