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