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