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