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