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