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