xref: /dragonfly/sys/dev/raid/twa/tw_cl_misc.c (revision d26841ecab7b9e18efdfee9ce80b153c2dc3bb9a)
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: head/sys/dev/twa/tw_cl_misc.c 242827 2012-11-09 15:29:52Z rdivacky $
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
tw_cli_drain_complete_queue(struct tw_cli_ctlr_context * ctlr)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
tw_cli_drain_busy_queue(struct tw_cli_ctlr_context * ctlr)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
tw_cli_drain_pending_queue(struct tw_cli_ctlr_context * ctlr)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
tw_cli_drain_response_queue(struct tw_cli_ctlr_context * ctlr)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
tw_cli_find_response(struct tw_cli_ctlr_context * ctlr,TW_INT32 req_id)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
tw_cli_drain_aen_queue(struct tw_cli_ctlr_context * ctlr)309 tw_cli_drain_aen_queue(struct tw_cli_ctlr_context *ctlr)
310 {
311           struct tw_cli_req_context     *req;
312           TW_TIME                                 end_time;
313           TW_UINT16                     aen_code;
314           TW_INT32                      error;
315 
316           tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
317 
318           for (;;) {
319                     if ((req = tw_cli_get_request(ctlr
320                               )) == TW_CL_NULL) {
321                               error = TW_OSL_EBUSY;
322                               break;
323                     }
324 
325                     req->flags |= TW_CLI_REQ_FLAGS_INTERNAL;
326                     req->tw_cli_callback = TW_CL_NULL;
327                     if ((error = tw_cli_send_scsi_cmd(req,
328                                         0x03 /* REQUEST_SENSE */))) {
329                               tw_cli_dbg_printf(1, ctlr->ctlr_handle,
330                                         tw_osl_cur_func(),
331                                         "Cannot send command to fetch aen");
332                               break;
333                     }
334 
335                     end_time = tw_osl_get_local_time() +
336                               TW_CLI_REQUEST_TIMEOUT_PERIOD;
337                     do {
338                               if ((error = req->error_code))
339                                         /*
340                                          * This will take care of completion due to
341                                          * a reset, or a failure in
342                                          * tw_cli_submit_pending_queue.
343                                          */
344                                         goto out;
345 
346                               tw_cli_process_resp_intr(req->ctlr);
347 
348                               if ((req->state != TW_CLI_REQ_STATE_BUSY) &&
349                                         (req->state != TW_CLI_REQ_STATE_PENDING))
350                                         break;
351                     } while (tw_osl_get_local_time() <= end_time);
352 
353                     if (req->state != TW_CLI_REQ_STATE_COMPLETE) {
354                               error = TW_OSL_ETIMEDOUT;
355                               break;
356                     }
357 
358                     if ((error = req->cmd_pkt->command.cmd_pkt_9k.status)) {
359 #if       0
360                               struct tw_cl_command_header   *cmd_hdr;
361                               cmd_hdr = &req->cmd_pkt->cmd_hdr;
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
tw_cli_find_aen(struct tw_cli_ctlr_context * ctlr,TW_UINT16 aen_code)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
tw_cli_poll_status(struct tw_cli_ctlr_context * ctlr,TW_UINT32 status,TW_UINT32 timeout)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
tw_cl_create_event(struct tw_cl_ctlr_handle * ctlr_handle,TW_UINT8 queue_event,TW_UINT8 event_src,TW_UINT16 event_code,TW_UINT8 severity,TW_UINT8 * severity_str,TW_UINT8 * event_desc,TW_UINT8 * event_specific_desc,...)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 *
tw_cli_get_request(struct tw_cli_ctlr_context * ctlr)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
tw_cli_dbg_printf(TW_UINT8 dbg_level,struct tw_cl_ctlr_handle * ctlr_handle,const TW_INT8 * cur_func,TW_INT8 * fmt,...)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, "%s", 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
tw_cli_notify_ctlr_info(struct tw_cli_ctlr_context * ctlr)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
tw_cli_check_ctlr_state(struct tw_cli_ctlr_context * ctlr,TW_UINT32 status_reg)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                     {
746                               tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
747                                   TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
748                                   0x1302, 0x1, TW_CL_SEVERITY_ERROR_STRING,
749                                   "Unexpected status bit(s)",
750                                   "status reg = 0x%x Unexpected bits: %s",
751                                   status_reg & TWA_STATUS_UNEXPECTED_BITS,
752                                   tw_cli_describe_bits(status_reg &
753                                             TWA_STATUS_UNEXPECTED_BITS, desc));
754                     }
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   *
tw_cli_describe_bits(TW_UINT32 reg,TW_INT8 * str)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
tw_cl_print_ctlr_stats(struct tw_cl_ctlr_handle * ctlr_handle)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
tw_cl_reset_stats(struct tw_cl_ctlr_handle * ctlr_handle)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
tw_cl_print_req_info(struct tw_cl_req_handle * req_handle)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