twa(4): Sync with FreeBSD's current code.
[dragonfly.git] / sys / dev / raid / twa / tw_cl_io.c
1 /*
2  * Copyright (c) 2004-07 Applied Micro Circuits Corporation.
3  * Copyright (c) 2004-05 Vinod Kashyap
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  *      $FreeBSD: src/sys/dev/twa/tw_cl_io.c,v 1.6 2010/06/09 21:40:38 delphij Exp $
28  */
29
30 /*
31  * AMCC'S 3ware driver for 9000 series storage controllers.
32  *
33  * Author: Vinod Kashyap
34  * Modifications by: Adam Radford
35  * Modifications by: Manjunath Ranganathaiah
36  */
37
38
39 /*
40  * Common Layer I/O 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 #include <bus/cam/cam.h>
53 #include <bus/cam/cam_ccb.h>
54 #include <bus/cam/cam_xpt_sim.h>
55
56
57
58 /*
59  * Function name:       tw_cl_start_io
60  * Description:         Interface to OS Layer for accepting SCSI requests.
61  *
62  * Input:               ctlr_handle     -- controller handle
63  *                      req_pkt         -- OSL built request packet
64  *                      req_handle      -- request handle
65  * Output:              None
66  * Return value:        0       -- success
67  *                      non-zero-- failure
68  */
69 TW_INT32
70 tw_cl_start_io(struct tw_cl_ctlr_handle *ctlr_handle,
71         struct tw_cl_req_packet *req_pkt, struct tw_cl_req_handle *req_handle)
72 {
73         struct tw_cli_ctlr_context              *ctlr;
74         struct tw_cli_req_context               *req;
75         struct tw_cl_command_9k                 *cmd;
76         struct tw_cl_scsi_req_packet            *scsi_req;
77         TW_INT32                                error;
78
79         tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), "entered");
80
81         ctlr = (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt);
82
83         if (ctlr->reset_in_progress) {
84                 tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(),
85                         "I/O during reset: returning busy.");
86                 return(TW_OSL_EBUSY);
87         }
88
89         /*
90          * If working with a firmware version that does not support multiple
91          * luns, and this request is directed at a non-zero lun, error it
92          * back right away.
93          */
94         if ((req_pkt->gen_req_pkt.scsi_req.lun) &&
95                 (ctlr->working_srl < TWA_MULTI_LUN_FW_SRL)) {
96                 req_pkt->status |= (TW_CL_ERR_REQ_INVALID_LUN |
97                         TW_CL_ERR_REQ_SCSI_ERROR);
98                 req_pkt->tw_osl_callback(req_handle);
99                 return(TW_CL_ERR_REQ_SUCCESS);
100         }
101
102         if ((req = tw_cli_get_request(ctlr
103                 )) == TW_CL_NULL) {
104                 tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(),
105                         "Out of request context packets: returning busy");
106                 return(TW_OSL_EBUSY);
107         }
108
109         req_handle->cl_req_ctxt = req;
110         req->req_handle = req_handle;
111         req->orig_req = req_pkt;
112         req->tw_cli_callback = tw_cli_complete_io;
113
114         req->flags |= TW_CLI_REQ_FLAGS_EXTERNAL;
115         req->flags |= TW_CLI_REQ_FLAGS_9K;
116
117         scsi_req = &(req_pkt->gen_req_pkt.scsi_req);
118
119         /* Build the cmd pkt. */
120         cmd = &(req->cmd_pkt->command.cmd_pkt_9k);
121
122         req->cmd_pkt->cmd_hdr.header_desc.size_header = 128;
123
124         cmd->res__opcode = BUILD_RES__OPCODE(0, TWA_FW_CMD_EXECUTE_SCSI);
125         cmd->unit = (TW_UINT8)(scsi_req->unit);
126         cmd->lun_l4__req_id = TW_CL_SWAP16(
127                 BUILD_LUN_L4__REQ_ID(scsi_req->lun, req->request_id));
128         cmd->status = 0;
129         cmd->sgl_offset = 16; /* offset from end of hdr = max cdb len */
130         tw_osl_memcpy(cmd->cdb, scsi_req->cdb, scsi_req->cdb_len);
131
132         if (req_pkt->flags & TW_CL_REQ_CALLBACK_FOR_SGLIST) {
133                 TW_UINT32       num_sgl_entries;
134
135                 req_pkt->tw_osl_sgl_callback(req_handle, cmd->sg_list,
136                         &num_sgl_entries);
137                 cmd->lun_h4__sgl_entries =
138                         TW_CL_SWAP16(BUILD_LUN_H4__SGL_ENTRIES(scsi_req->lun,
139                                 num_sgl_entries));
140         } else {
141                 cmd->lun_h4__sgl_entries =
142                         TW_CL_SWAP16(BUILD_LUN_H4__SGL_ENTRIES(scsi_req->lun,
143                                 scsi_req->sgl_entries));
144                 tw_cli_fill_sg_list(ctlr, scsi_req->sg_list,
145                         cmd->sg_list, scsi_req->sgl_entries);
146         }
147
148         if ((error = tw_cli_submit_cmd(req))) {
149                 tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(),
150                         "Could not start request. request = %p, error = %d",
151                         req, error);
152                 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
153         }
154         return(error);
155 }
156
157
158
159 /*
160  * Function name:       tw_cli_submit_cmd
161  * Description:         Submits a cmd to firmware.
162  *
163  * Input:               req     -- ptr to CL internal request context
164  * Output:              None
165  * Return value:        0       -- success
166  *                      non-zero-- failure
167  */
168 TW_INT32
169 tw_cli_submit_cmd(struct tw_cli_req_context *req)
170 {
171         struct tw_cli_ctlr_context      *ctlr = req->ctlr;
172         struct tw_cl_ctlr_handle        *ctlr_handle = ctlr->ctlr_handle;
173         TW_UINT32                       status_reg;
174         TW_INT32                        error;
175
176         tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), "entered");
177
178         /* Serialize access to the controller cmd queue. */
179         tw_osl_get_lock(ctlr_handle, ctlr->io_lock);
180
181         /* For 9650SE first write low 4 bytes */
182         if ((ctlr->device_id == TW_CL_DEVICE_ID_9K_E) ||
183             (ctlr->device_id == TW_CL_DEVICE_ID_9K_SA))
184                 tw_osl_write_reg(ctlr_handle,
185                                  TWA_COMMAND_QUEUE_OFFSET_LOW,
186                                  (TW_UINT32)(req->cmd_pkt_phys + sizeof(struct tw_cl_command_header)), 4);
187
188         /* Check to see if we can post a command. */
189         status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr_handle);
190         if ((error = tw_cli_check_ctlr_state(ctlr, status_reg)))
191                 goto out;
192
193         if (status_reg & TWA_STATUS_COMMAND_QUEUE_FULL) {
194                 struct tw_cl_req_packet *req_pkt =
195                         (struct tw_cl_req_packet *)(req->orig_req);
196
197                 tw_cli_dbg_printf(7, ctlr_handle, tw_osl_cur_func(),
198                         "Cmd queue full");
199
200                 if ((req->flags & TW_CLI_REQ_FLAGS_INTERNAL)
201                         || ((req_pkt) &&
202                         (req_pkt->flags & TW_CL_REQ_RETRY_ON_BUSY))
203                         ) {
204                         if (req->state != TW_CLI_REQ_STATE_PENDING) {
205                                 tw_cli_dbg_printf(2, ctlr_handle,
206                                         tw_osl_cur_func(),
207                                         "pending internal/ioctl request");
208                                 req->state = TW_CLI_REQ_STATE_PENDING;
209                                 tw_cli_req_q_insert_tail(req, TW_CLI_PENDING_Q);
210                                 error = 0;
211                                 /* Unmask command interrupt. */
212                                 TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle,
213                                         TWA_CONTROL_UNMASK_COMMAND_INTERRUPT);
214                         } else
215                                 error = TW_OSL_EBUSY;
216                 } else {
217                         tw_osl_ctlr_busy(ctlr_handle, req->req_handle);
218                         error = TW_OSL_EBUSY;
219                 }
220         } else {
221                 tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(),
222                         "Submitting command");
223
224                 /* Insert command into busy queue */
225                 req->state = TW_CLI_REQ_STATE_BUSY;
226                 tw_cli_req_q_insert_tail(req, TW_CLI_BUSY_Q);
227
228                 if ((ctlr->device_id == TW_CL_DEVICE_ID_9K_E) ||
229                     (ctlr->device_id == TW_CL_DEVICE_ID_9K_SA)) {
230                         /* Now write the high 4 bytes */
231                         tw_osl_write_reg(ctlr_handle,
232                                          TWA_COMMAND_QUEUE_OFFSET_HIGH,
233                                          (TW_UINT32)(((TW_UINT64)(req->cmd_pkt_phys + sizeof(struct tw_cl_command_header)))>>32), 4);
234                 } else {
235                         if (ctlr->flags & TW_CL_64BIT_ADDRESSES) {
236                                 /* First write the low 4 bytes, then the high 4. */
237                                 tw_osl_write_reg(ctlr_handle,
238                                                  TWA_COMMAND_QUEUE_OFFSET_LOW,
239                                                  (TW_UINT32)(req->cmd_pkt_phys + sizeof(struct tw_cl_command_header)), 4);
240                                 tw_osl_write_reg(ctlr_handle,
241                                                  TWA_COMMAND_QUEUE_OFFSET_HIGH,
242                                                  (TW_UINT32)(((TW_UINT64)(req->cmd_pkt_phys + sizeof(struct tw_cl_command_header)))>>32), 4);
243                         } else
244                                 tw_osl_write_reg(ctlr_handle,
245                                                  TWA_COMMAND_QUEUE_OFFSET,
246                                                  (TW_UINT32)(req->cmd_pkt_phys + sizeof(struct tw_cl_command_header)), 4);
247                 }
248         }
249 out:
250         tw_osl_free_lock(ctlr_handle, ctlr->io_lock);
251
252         return(error);
253 }
254
255
256
257 /*
258  * Function name:       tw_cl_fw_passthru
259  * Description:         Interface to OS Layer for accepting firmware
260  *                      passthru requests.
261  * Input:               ctlr_handle     -- controller handle
262  *                      req_pkt         -- OSL built request packet
263  *                      req_handle      -- request handle
264  * Output:              None
265  * Return value:        0       -- success
266  *                      non-zero-- failure
267  */
268 TW_INT32
269 tw_cl_fw_passthru(struct tw_cl_ctlr_handle *ctlr_handle,
270         struct tw_cl_req_packet *req_pkt, struct tw_cl_req_handle *req_handle)
271 {
272         struct tw_cli_ctlr_context              *ctlr;
273         struct tw_cli_req_context               *req;
274         union tw_cl_command_7k                  *cmd_7k;
275         struct tw_cl_command_9k                 *cmd_9k;
276         struct tw_cl_passthru_req_packet        *pt_req;
277         TW_UINT8                                opcode;
278         TW_UINT8                                sgl_offset;
279         TW_VOID                                 *sgl = TW_CL_NULL;
280         TW_INT32                                error;
281
282         tw_cli_dbg_printf(5, ctlr_handle, tw_osl_cur_func(), "entered");
283
284         ctlr = (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt);
285
286         if (ctlr->reset_in_progress) {
287                 tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(),
288                         "Passthru request during reset: returning busy.");
289                 return(TW_OSL_EBUSY);
290         }
291
292         if ((req = tw_cli_get_request(ctlr
293                 )) == TW_CL_NULL) {
294                 tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(),
295                         "Out of request context packets: returning busy");
296                 return(TW_OSL_EBUSY);
297         }
298
299         req_handle->cl_req_ctxt = req;
300         req->req_handle = req_handle;
301         req->orig_req = req_pkt;
302         req->tw_cli_callback = tw_cli_complete_io;
303
304         req->flags |= (TW_CLI_REQ_FLAGS_EXTERNAL | TW_CLI_REQ_FLAGS_PASSTHRU);
305
306         pt_req = &(req_pkt->gen_req_pkt.pt_req);
307
308         tw_osl_memcpy(req->cmd_pkt, pt_req->cmd_pkt,
309                 pt_req->cmd_pkt_length);
310         /* Build the cmd pkt. */
311         if ((opcode = GET_OPCODE(((TW_UINT8 *)
312                 (pt_req->cmd_pkt))[sizeof(struct tw_cl_command_header)]))
313                         == TWA_FW_CMD_EXECUTE_SCSI) {
314                 TW_UINT16       lun_l4, lun_h4;
315
316                 tw_cli_dbg_printf(5, ctlr_handle, tw_osl_cur_func(),
317                         "passthru: 9k cmd pkt");
318                 req->flags |= TW_CLI_REQ_FLAGS_9K;
319                 cmd_9k = &(req->cmd_pkt->command.cmd_pkt_9k);
320                 lun_l4 = GET_LUN_L4(cmd_9k->lun_l4__req_id);
321                 lun_h4 = GET_LUN_H4(cmd_9k->lun_h4__sgl_entries);
322                 cmd_9k->lun_l4__req_id = TW_CL_SWAP16(
323                         BUILD_LUN_L4__REQ_ID(lun_l4, req->request_id));
324                 if (pt_req->sgl_entries) {
325                         cmd_9k->lun_h4__sgl_entries =
326                                 TW_CL_SWAP16(BUILD_LUN_H4__SGL_ENTRIES(lun_h4,
327                                         pt_req->sgl_entries));
328                         sgl = (TW_VOID *)(cmd_9k->sg_list);
329                 }
330         } else {
331                 tw_cli_dbg_printf(5, ctlr_handle, tw_osl_cur_func(),
332                         "passthru: 7k cmd pkt");
333                 cmd_7k = &(req->cmd_pkt->command.cmd_pkt_7k);
334                 cmd_7k->generic.request_id =
335                         (TW_UINT8)(TW_CL_SWAP16(req->request_id));
336                 if ((sgl_offset =
337                         GET_SGL_OFF(cmd_7k->generic.sgl_off__opcode))) {
338                         if (ctlr->device_id == TW_CL_DEVICE_ID_9K_SA)
339                                 sgl = (((TW_UINT32 *)cmd_7k) + cmd_7k->generic.size);
340                         else
341                                 sgl = (((TW_UINT32 *)cmd_7k) + sgl_offset);
342                         cmd_7k->generic.size += pt_req->sgl_entries *
343                                 ((ctlr->flags & TW_CL_64BIT_ADDRESSES) ? 3 : 2);
344                 }
345         }
346
347         if (sgl)
348                 tw_cli_fill_sg_list(ctlr, pt_req->sg_list,
349                         sgl, pt_req->sgl_entries);
350
351         if ((error = tw_cli_submit_cmd(req))) {
352                 tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
353                         TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
354                         0x1100, 0x1, TW_CL_SEVERITY_ERROR_STRING,
355                         "Failed to start passthru command",
356                         "error = %d", error);
357                 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
358         }
359         return(error);
360 }
361
362
363
364 /*
365  * Function name:       tw_cl_ioctl
366  * Description:         Handler of CL supported ioctl cmds.
367  *
368  * Input:               ctlr    -- ptr to per ctlr structure
369  *                      cmd     -- ioctl cmd
370  *                      buf     -- ptr to buffer in kernel memory, which is
371  *                                 a copy of the input buffer in user-space
372  * Output:              buf     -- ptr to buffer in kernel memory, which will
373  *                                 need to be copied to the output buffer in
374  *                                 user-space
375  * Return value:        0       -- success
376  *                      non-zero-- failure
377  */
378 TW_INT32
379 tw_cl_ioctl(struct tw_cl_ctlr_handle *ctlr_handle, u_long cmd, TW_VOID *buf)
380 {
381         struct tw_cli_ctlr_context      *ctlr =
382                 (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt);
383         struct tw_cl_ioctl_packet       *user_buf =
384                 (struct tw_cl_ioctl_packet *)buf;
385         struct tw_cl_event_packet       event_buf;
386         TW_INT32                        event_index;
387         TW_INT32                        start_index;
388         TW_INT32                        error = TW_OSL_ESUCCESS;
389
390         tw_cli_dbg_printf(5, ctlr_handle, tw_osl_cur_func(), "entered");
391
392         /* Serialize access to the AEN queue and the ioctl lock. */
393         tw_osl_get_lock(ctlr_handle, ctlr->gen_lock);
394
395         switch (cmd) {
396         case TW_CL_IOCTL_GET_FIRST_EVENT:
397                 tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(),
398                         "Get First Event");
399
400                 if (ctlr->aen_q_wrapped) {
401                         if (ctlr->aen_q_overflow) {
402                                 /*
403                                  * The aen queue has wrapped, even before some
404                                  * events have been retrieved.  Let the caller
405                                  * know that he missed out on some AEN's.
406                                  */
407                                 user_buf->driver_pkt.status =
408                                         TW_CL_ERROR_AEN_OVERFLOW;
409                                 ctlr->aen_q_overflow = TW_CL_FALSE;
410                         } else
411                                 user_buf->driver_pkt.status = 0;
412                         event_index = ctlr->aen_head;
413                 } else {
414                         if (ctlr->aen_head == ctlr->aen_tail) {
415                                 user_buf->driver_pkt.status =
416                                         TW_CL_ERROR_AEN_NO_EVENTS;
417                                 break;
418                         }
419                         user_buf->driver_pkt.status = 0;
420                         event_index = ctlr->aen_tail;   /* = 0 */
421                 }
422                 tw_osl_memcpy(user_buf->data_buf,
423                         &(ctlr->aen_queue[event_index]),
424                         sizeof(struct tw_cl_event_packet));
425
426                 ctlr->aen_queue[event_index].retrieved = TW_CL_AEN_RETRIEVED;
427
428                 break;
429
430
431         case TW_CL_IOCTL_GET_LAST_EVENT:
432                 tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(),
433                         "Get Last Event");
434
435                 if (ctlr->aen_q_wrapped) {
436                         if (ctlr->aen_q_overflow) {
437                                 /*
438                                  * The aen queue has wrapped, even before some
439                                  * events have been retrieved.  Let the caller
440                                  * know that he missed out on some AEN's.
441                                  */
442                                 user_buf->driver_pkt.status =
443                                         TW_CL_ERROR_AEN_OVERFLOW;
444                                 ctlr->aen_q_overflow = TW_CL_FALSE;
445                         } else
446                                 user_buf->driver_pkt.status = 0;
447                 } else {
448                         if (ctlr->aen_head == ctlr->aen_tail) {
449                                 user_buf->driver_pkt.status =
450                                         TW_CL_ERROR_AEN_NO_EVENTS;
451                                 break;
452                         }
453                         user_buf->driver_pkt.status = 0;
454                 }
455                 event_index = (ctlr->aen_head - 1 + ctlr->max_aens_supported) %
456                         ctlr->max_aens_supported;
457
458                 tw_osl_memcpy(user_buf->data_buf,
459                         &(ctlr->aen_queue[event_index]),
460                         sizeof(struct tw_cl_event_packet));
461
462                 ctlr->aen_queue[event_index].retrieved = TW_CL_AEN_RETRIEVED;
463
464                 break;
465
466
467         case TW_CL_IOCTL_GET_NEXT_EVENT:
468                 tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(),
469                         "Get Next Event");
470
471                 user_buf->driver_pkt.status = 0;
472                 if (ctlr->aen_q_wrapped) {
473                         tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(),
474                                 "Get Next Event: wrapped");
475                         if (ctlr->aen_q_overflow) {
476                                 /*
477                                  * The aen queue has wrapped, even before some
478                                  * events have been retrieved.  Let the caller
479                                  * know that he missed out on some AEN's.
480                                  */
481                                 tw_cli_dbg_printf(2, ctlr_handle,
482                                         tw_osl_cur_func(),
483                                         "Get Next Event: overflow");
484                                 user_buf->driver_pkt.status =
485                                         TW_CL_ERROR_AEN_OVERFLOW;
486                                 ctlr->aen_q_overflow = TW_CL_FALSE;
487                         }
488                         start_index = ctlr->aen_head;
489                 } else {
490                         if (ctlr->aen_head == ctlr->aen_tail) {
491                                 tw_cli_dbg_printf(3, ctlr_handle,
492                                         tw_osl_cur_func(),
493                                         "Get Next Event: empty queue");
494                                 user_buf->driver_pkt.status =
495                                         TW_CL_ERROR_AEN_NO_EVENTS;
496                                 break;
497                         }
498                         start_index = ctlr->aen_tail;   /* = 0 */
499                 }
500                 tw_osl_memcpy(&event_buf, user_buf->data_buf,
501                         sizeof(struct tw_cl_event_packet));
502
503                 event_index = (start_index + event_buf.sequence_id -
504                         ctlr->aen_queue[start_index].sequence_id + 1) %
505                         ctlr->max_aens_supported;
506
507                 tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(),
508                         "Get Next Event: si = %x, ei = %x, ebsi = %x, "
509                         "sisi = %x, eisi = %x",
510                         start_index, event_index, event_buf.sequence_id,
511                         ctlr->aen_queue[start_index].sequence_id,
512                         ctlr->aen_queue[event_index].sequence_id);
513
514                 if (! (ctlr->aen_queue[event_index].sequence_id >
515                         event_buf.sequence_id)) {
516                         /*
517                          * We don't have any event matching the criterion.  So,
518                          * we have to report TW_CL_ERROR_NO_EVENTS.  If we also
519                          * encountered an overflow condition above, we cannot
520                          * report both conditions during this call.  We choose
521                          * to report NO_EVENTS this time, and an overflow the
522                          * next time we are called.
523                          */
524                         if (user_buf->driver_pkt.status ==
525                                 TW_CL_ERROR_AEN_OVERFLOW) {
526                                 /*
527                                  * Make a note so we report the overflow
528                                  * next time.
529                                  */
530                                 ctlr->aen_q_overflow = TW_CL_TRUE;
531                         }
532                         user_buf->driver_pkt.status = TW_CL_ERROR_AEN_NO_EVENTS;
533                         break;
534                 }
535                 /* Copy the event -- even if there has been an overflow. */
536                 tw_osl_memcpy(user_buf->data_buf,
537                         &(ctlr->aen_queue[event_index]),
538                         sizeof(struct tw_cl_event_packet));
539
540                 ctlr->aen_queue[event_index].retrieved = TW_CL_AEN_RETRIEVED;
541
542                 break;
543
544
545         case TW_CL_IOCTL_GET_PREVIOUS_EVENT:
546                 tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(),
547                         "Get Previous Event");
548
549                 user_buf->driver_pkt.status = 0;
550                 if (ctlr->aen_q_wrapped) {
551                         if (ctlr->aen_q_overflow) {
552                                 /*
553                                  * The aen queue has wrapped, even before some
554                                  * events have been retrieved.  Let the caller
555                                  * know that he missed out on some AEN's.
556                                  */
557                                 user_buf->driver_pkt.status =
558                                         TW_CL_ERROR_AEN_OVERFLOW;
559                                 ctlr->aen_q_overflow = TW_CL_FALSE;
560                         }
561                         start_index = ctlr->aen_head;
562                 } else {
563                         if (ctlr->aen_head == ctlr->aen_tail) {
564                                 user_buf->driver_pkt.status =
565                                         TW_CL_ERROR_AEN_NO_EVENTS;
566                                 break;
567                         }
568                         start_index = ctlr->aen_tail;   /* = 0 */
569                 }
570                 tw_osl_memcpy(&event_buf, user_buf->data_buf,
571                         sizeof(struct tw_cl_event_packet));
572
573                 event_index = (start_index + event_buf.sequence_id -
574                         ctlr->aen_queue[start_index].sequence_id - 1) %
575                         ctlr->max_aens_supported;
576
577                 if (! (ctlr->aen_queue[event_index].sequence_id <
578                         event_buf.sequence_id)) {
579                         /*
580                          * We don't have any event matching the criterion.  So,
581                          * we have to report TW_CL_ERROR_NO_EVENTS.  If we also
582                          * encountered an overflow condition above, we cannot
583                          * report both conditions during this call.  We choose
584                          * to report NO_EVENTS this time, and an overflow the
585                          * next time we are called.
586                          */
587                         if (user_buf->driver_pkt.status ==
588                                 TW_CL_ERROR_AEN_OVERFLOW) {
589                                 /*
590                                  * Make a note so we report the overflow
591                                  * next time.
592                                  */
593                                 ctlr->aen_q_overflow = TW_CL_TRUE;
594                         }
595                         user_buf->driver_pkt.status = TW_CL_ERROR_AEN_NO_EVENTS;
596                         break;
597                 }
598                 /* Copy the event -- even if there has been an overflow. */
599                 tw_osl_memcpy(user_buf->data_buf,
600                         &(ctlr->aen_queue[event_index]),
601                         sizeof(struct tw_cl_event_packet));
602
603                 ctlr->aen_queue[event_index].retrieved = TW_CL_AEN_RETRIEVED;
604
605                 break;
606
607
608         case TW_CL_IOCTL_GET_LOCK:
609         {
610                 struct tw_cl_lock_packet        lock_pkt;
611                 TW_TIME                         cur_time;
612
613                 tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(),
614                         "Get ioctl lock");
615
616                 cur_time = tw_osl_get_local_time();
617                 tw_osl_memcpy(&lock_pkt, user_buf->data_buf,
618                         sizeof(struct tw_cl_lock_packet));
619
620                 if ((ctlr->ioctl_lock.lock == TW_CLI_LOCK_FREE) ||
621                         (lock_pkt.force_flag) ||
622                         (cur_time >= ctlr->ioctl_lock.timeout)) {
623                         tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(),
624                                 "GET_LOCK: Getting lock!");
625                         ctlr->ioctl_lock.lock = TW_CLI_LOCK_HELD;
626                         ctlr->ioctl_lock.timeout =
627                                 cur_time + (lock_pkt.timeout_msec / 1000);
628                         lock_pkt.time_remaining_msec = lock_pkt.timeout_msec;
629                         user_buf->driver_pkt.status = 0;
630                 } else {
631                         tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(),
632                                 "GET_LOCK: Lock already held!");
633                         lock_pkt.time_remaining_msec = (TW_UINT32)(
634                                 (ctlr->ioctl_lock.timeout - cur_time) * 1000);
635                         user_buf->driver_pkt.status =
636                                 TW_CL_ERROR_IOCTL_LOCK_ALREADY_HELD;
637                 }
638                 tw_osl_memcpy(user_buf->data_buf, &lock_pkt,
639                         sizeof(struct tw_cl_lock_packet));
640                 break;
641         }
642
643
644         case TW_CL_IOCTL_RELEASE_LOCK:
645                 tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(),
646                         "Release ioctl lock");
647
648                 if (ctlr->ioctl_lock.lock == TW_CLI_LOCK_FREE) {
649                         tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(),
650                                 "twa_ioctl: RELEASE_LOCK: Lock not held!");
651                         user_buf->driver_pkt.status =
652                                 TW_CL_ERROR_IOCTL_LOCK_NOT_HELD;
653                 } else {
654                         tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(),
655                                 "RELEASE_LOCK: Releasing lock!");
656                         ctlr->ioctl_lock.lock = TW_CLI_LOCK_FREE;
657                         user_buf->driver_pkt.status = 0;
658                 }
659                 break;
660
661
662         case TW_CL_IOCTL_GET_COMPATIBILITY_INFO:
663         {
664                 struct tw_cl_compatibility_packet       comp_pkt;
665
666                 tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(),
667                         "Get compatibility info");
668
669                 tw_osl_memcpy(comp_pkt.driver_version,
670                         TW_OSL_DRIVER_VERSION_STRING,
671                         sizeof(TW_OSL_DRIVER_VERSION_STRING));
672                 comp_pkt.working_srl = ctlr->working_srl;
673                 comp_pkt.working_branch = ctlr->working_branch;
674                 comp_pkt.working_build = ctlr->working_build;
675                 comp_pkt.driver_srl_high = TWA_CURRENT_FW_SRL;
676                 comp_pkt.driver_branch_high =
677                         TWA_CURRENT_FW_BRANCH(ctlr->arch_id);
678                 comp_pkt.driver_build_high =
679                         TWA_CURRENT_FW_BUILD(ctlr->arch_id);
680                 comp_pkt.driver_srl_low = TWA_BASE_FW_SRL;
681                 comp_pkt.driver_branch_low = TWA_BASE_FW_BRANCH;
682                 comp_pkt.driver_build_low = TWA_BASE_FW_BUILD;
683                 comp_pkt.fw_on_ctlr_srl = ctlr->fw_on_ctlr_srl;
684                 comp_pkt.fw_on_ctlr_branch = ctlr->fw_on_ctlr_branch;
685                 comp_pkt.fw_on_ctlr_build = ctlr->fw_on_ctlr_build;
686                 user_buf->driver_pkt.status = 0;
687
688                 /* Copy compatibility information to user space. */
689                 tw_osl_memcpy(user_buf->data_buf, &comp_pkt,
690                         (sizeof(struct tw_cl_compatibility_packet) <
691                         user_buf->driver_pkt.buffer_length) ?
692                         sizeof(struct tw_cl_compatibility_packet) :
693                         user_buf->driver_pkt.buffer_length);
694                 break;
695         }
696
697         default:
698                 /* Unknown opcode. */
699                 tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(),
700                         "Unknown ioctl cmd 0x%x", cmd);
701                 error = TW_OSL_ENOTTY;
702         }
703
704         tw_osl_free_lock(ctlr_handle, ctlr->gen_lock);
705         return(error);
706 }
707
708
709
710 /*
711  * Function name:       tw_cli_get_param
712  * Description:         Get a firmware parameter.
713  *
714  * Input:               ctlr            -- ptr to per ctlr structure
715  *                      table_id        -- parameter table #
716  *                      param_id        -- index of the parameter in the table
717  *                      param_size      -- size of the parameter in bytes
718  *                      callback        -- ptr to function, if any, to be called
719  *                                      back on completion; TW_CL_NULL if no callback.
720  * Output:              param_data      -- param value
721  * Return value:        0       -- success
722  *                      non-zero-- failure
723  */
724 TW_INT32
725 tw_cli_get_param(struct tw_cli_ctlr_context *ctlr, TW_INT32 table_id,
726         TW_INT32 param_id, TW_VOID *param_data, TW_INT32 param_size,
727         TW_VOID (* callback)(struct tw_cli_req_context *req))
728 {
729         struct tw_cli_req_context       *req;
730         union tw_cl_command_7k          *cmd;
731         struct tw_cl_param_9k           *param = TW_CL_NULL;
732         TW_INT32                        error = TW_OSL_EBUSY;
733
734         tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
735
736         /* Get a request packet. */
737         if ((req = tw_cli_get_request(ctlr
738                 )) == TW_CL_NULL)
739                 goto out;
740
741         /* Make sure this is the only CL internal request at this time. */
742         if (ctlr->internal_req_busy) {
743                 error = TW_OSL_EBUSY;
744                 goto out;
745         }
746         ctlr->internal_req_busy = TW_CL_TRUE;
747         req->data = ctlr->internal_req_data;
748         req->data_phys = ctlr->internal_req_data_phys;
749         req->length = TW_CLI_SECTOR_SIZE;
750         req->flags |= TW_CLI_REQ_FLAGS_INTERNAL;
751
752         /* Initialize memory to read data into. */
753         param = (struct tw_cl_param_9k *)(req->data);
754         tw_osl_memzero(param, sizeof(struct tw_cl_param_9k) - 1 + param_size);
755
756         /* Build the cmd pkt. */
757         cmd = &(req->cmd_pkt->command.cmd_pkt_7k);
758
759         req->cmd_pkt->cmd_hdr.header_desc.size_header = 128;
760
761         cmd->param.sgl_off__opcode =
762                 BUILD_SGL_OFF__OPCODE(2, TWA_FW_CMD_GET_PARAM);
763         cmd->param.request_id =
764                 (TW_UINT8)(TW_CL_SWAP16(req->request_id));
765         cmd->param.host_id__unit = BUILD_HOST_ID__UNIT(0, 0);
766         cmd->param.param_count = TW_CL_SWAP16(1);
767
768         if (ctlr->flags & TW_CL_64BIT_ADDRESSES) {
769                 ((struct tw_cl_sg_desc64 *)(cmd->param.sgl))[0].address =
770                         TW_CL_SWAP64(req->data_phys);
771                 ((struct tw_cl_sg_desc64 *)(cmd->param.sgl))[0].length =
772                         TW_CL_SWAP32(req->length);
773                 cmd->param.size = 2 + 3;
774         } else {
775                 ((struct tw_cl_sg_desc32 *)(cmd->param.sgl))[0].address =
776                         TW_CL_SWAP32(req->data_phys);
777                 ((struct tw_cl_sg_desc32 *)(cmd->param.sgl))[0].length =
778                         TW_CL_SWAP32(req->length);
779                 cmd->param.size = 2 + 2;
780         }
781
782         /* Specify which parameter we need. */
783         param->table_id = TW_CL_SWAP16(table_id | TWA_9K_PARAM_DESCRIPTOR);
784         param->parameter_id = (TW_UINT8)(param_id);
785         param->parameter_size_bytes = TW_CL_SWAP16(param_size);
786
787         /* Submit the command. */
788         if (callback == TW_CL_NULL) {
789                 /* There's no call back; wait till the command completes. */
790                 error = tw_cli_submit_and_poll_request(req,
791                                 TW_CLI_REQUEST_TIMEOUT_PERIOD);
792                 if (error == TW_OSL_ETIMEDOUT)
793                         /* Clean-up done by tw_cli_submit_and_poll_request. */
794                         return(error);
795                 if (error)
796                         goto out;
797                 if ((error = cmd->param.status)) {
798                         tw_cli_create_ctlr_event(ctlr,
799                                 TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
800                                 &(req->cmd_pkt->cmd_hdr));
801                         goto out;
802                 }
803                 tw_osl_memcpy(param_data, param->data, param_size);
804                 ctlr->internal_req_busy = TW_CL_FALSE;
805                 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
806         } else {
807                 /* There's a call back.  Simply submit the command. */
808                 req->tw_cli_callback = callback;
809                 if ((error = tw_cli_submit_cmd(req)))
810                         goto out;
811         }
812         return(0);
813
814 out:
815         tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
816                 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
817                 0x1101, 0x1, TW_CL_SEVERITY_ERROR_STRING,
818                 "get_param failed",
819                 "error = %d", error);
820         if (param)
821                 ctlr->internal_req_busy = TW_CL_FALSE;
822         if (req)
823                 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
824         return(1);
825 }
826
827
828
829 /*
830  * Function name:       tw_cli_set_param
831  * Description:         Set a firmware parameter.
832  *
833  * Input:               ctlr            -- ptr to per ctlr structure
834  *                      table_id        -- parameter table #
835  *                      param_id        -- index of the parameter in the table
836  *                      param_size      -- size of the parameter in bytes
837  *                      callback        -- ptr to function, if any, to be called
838  *                                      back on completion; TW_CL_NULL if no callback.
839  * Output:              None
840  * Return value:        0       -- success
841  *                      non-zero-- failure
842  */
843 TW_INT32
844 tw_cli_set_param(struct tw_cli_ctlr_context *ctlr, TW_INT32 table_id,
845         TW_INT32 param_id, TW_INT32 param_size, TW_VOID *data,
846         TW_VOID (* callback)(struct tw_cli_req_context *req))
847 {
848         struct tw_cli_req_context       *req;
849         union tw_cl_command_7k          *cmd;
850         struct tw_cl_param_9k           *param = TW_CL_NULL;
851         TW_INT32                        error = TW_OSL_EBUSY;
852
853         tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
854
855         /* Get a request packet. */
856         if ((req = tw_cli_get_request(ctlr
857                 )) == TW_CL_NULL)
858                 goto out;
859
860         /* Make sure this is the only CL internal request at this time. */
861         if (ctlr->internal_req_busy) {
862                 error = TW_OSL_EBUSY;
863                 goto out;
864         }
865         ctlr->internal_req_busy = TW_CL_TRUE;
866         req->data = ctlr->internal_req_data;
867         req->data_phys = ctlr->internal_req_data_phys;
868         req->length = TW_CLI_SECTOR_SIZE;
869         req->flags |= TW_CLI_REQ_FLAGS_INTERNAL;
870
871         /* Initialize memory to send data using. */
872         param = (struct tw_cl_param_9k *)(req->data);
873         tw_osl_memzero(param, sizeof(struct tw_cl_param_9k) - 1 + param_size);
874
875         /* Build the cmd pkt. */
876         cmd = &(req->cmd_pkt->command.cmd_pkt_7k);
877
878         req->cmd_pkt->cmd_hdr.header_desc.size_header = 128;
879
880         cmd->param.sgl_off__opcode =
881                 BUILD_SGL_OFF__OPCODE(2, TWA_FW_CMD_SET_PARAM);
882         cmd->param.request_id = (TW_UINT8)(TW_CL_SWAP16(req->request_id));
883         cmd->param.host_id__unit = BUILD_HOST_ID__UNIT(0, 0);
884         cmd->param.param_count = TW_CL_SWAP16(1);
885
886         if (ctlr->flags & TW_CL_64BIT_ADDRESSES) {
887                 ((struct tw_cl_sg_desc64 *)(cmd->param.sgl))[0].address =
888                         TW_CL_SWAP64(req->data_phys);
889                 ((struct tw_cl_sg_desc64 *)(cmd->param.sgl))[0].length =
890                         TW_CL_SWAP32(req->length);
891                 cmd->param.size = 2 + 3;
892         } else {
893                 ((struct tw_cl_sg_desc32 *)(cmd->param.sgl))[0].address =
894                         TW_CL_SWAP32(req->data_phys);
895                 ((struct tw_cl_sg_desc32 *)(cmd->param.sgl))[0].length =
896                         TW_CL_SWAP32(req->length);
897                 cmd->param.size = 2 + 2;
898         }
899
900         /* Specify which parameter we want to set. */
901         param->table_id = TW_CL_SWAP16(table_id | TWA_9K_PARAM_DESCRIPTOR);
902         param->parameter_id = (TW_UINT8)(param_id);
903         param->parameter_size_bytes = TW_CL_SWAP16(param_size);
904         tw_osl_memcpy(param->data, data, param_size);
905
906         /* Submit the command. */
907         if (callback == TW_CL_NULL) {
908                 /* There's no call back;  wait till the command completes. */
909                 error = tw_cli_submit_and_poll_request(req,
910                         TW_CLI_REQUEST_TIMEOUT_PERIOD);
911                 if (error == TW_OSL_ETIMEDOUT)
912                         /* Clean-up done by tw_cli_submit_and_poll_request. */
913                         return(error);
914                 if (error)
915                         goto out;
916                 if ((error = cmd->param.status)) {
917                         tw_cli_create_ctlr_event(ctlr,
918                                 TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
919                                 &(req->cmd_pkt->cmd_hdr));
920                         goto out;
921                 }
922                 ctlr->internal_req_busy = TW_CL_FALSE;
923                 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
924         } else {
925                 /* There's a call back.  Simply submit the command. */
926                 req->tw_cli_callback = callback;
927                 if ((error = tw_cli_submit_cmd(req)))
928                         goto out;
929         }
930         return(error);
931
932 out:
933         tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
934                 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
935                 0x1102, 0x1, TW_CL_SEVERITY_ERROR_STRING,
936                 "set_param failed",
937                 "error = %d", error);
938         if (param)
939                 ctlr->internal_req_busy = TW_CL_FALSE;
940         if (req)
941                 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
942         return(error);
943 }
944
945
946
947 /*
948  * Function name:       tw_cli_submit_and_poll_request
949  * Description:         Sends down a firmware cmd, and waits for the completion
950  *                      in a tight loop.
951  *
952  * Input:               req     -- ptr to request pkt
953  *                      timeout -- max # of seconds to wait before giving up
954  * Output:              None
955  * Return value:        0       -- success
956  *                      non-zero-- failure
957  */
958 TW_INT32
959 tw_cli_submit_and_poll_request(struct tw_cli_req_context *req,
960         TW_UINT32 timeout)
961 {
962         struct tw_cli_ctlr_context      *ctlr = req->ctlr;
963         TW_TIME                         end_time;
964         TW_INT32                        error;
965
966         tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
967
968         /*
969          * If the cmd queue is full, tw_cli_submit_cmd will queue this
970          * request in the pending queue, since this is an internal request.
971          */
972         if ((error = tw_cli_submit_cmd(req))) {
973                 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
974                         TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
975                         0x1103, 0x1, TW_CL_SEVERITY_ERROR_STRING,
976                         "Failed to start internal request",
977                         "error = %d", error);
978                 return(error);
979         }
980
981         /*
982          * Poll for the response until the command gets completed, or there's
983          * a timeout.
984          */
985         end_time = tw_osl_get_local_time() + timeout;
986         do {
987                 if ((error = req->error_code))
988                         /*
989                          * This will take care of completion due to a reset,
990                          * or a failure in tw_cli_submit_pending_queue.
991                          * The caller should do the clean-up.
992                          */
993                         return(error);
994
995                 /* See if the command completed. */
996                 tw_cli_process_resp_intr(ctlr);
997
998                 if ((req->state != TW_CLI_REQ_STATE_BUSY) &&
999                         (req->state != TW_CLI_REQ_STATE_PENDING))
1000                         return(req->state != TW_CLI_REQ_STATE_COMPLETE);
1001         } while (tw_osl_get_local_time() <= end_time);
1002
1003         /* Time out! */
1004         tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
1005                 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
1006                 0x1104, 0x1, TW_CL_SEVERITY_ERROR_STRING,
1007                 "Internal request timed out",
1008                 "request = %p", req);
1009
1010         /*
1011          * We will reset the controller only if the request has already been
1012          * submitted, so as to not lose the request packet.  If a busy request
1013          * timed out, the reset will take care of freeing resources.  If a
1014          * pending request timed out, we will free resources for that request,
1015          * right here, thereby avoiding a reset.  So, the caller is expected
1016          * to NOT cleanup when TW_OSL_ETIMEDOUT is returned.
1017          */
1018
1019         /*
1020          * We have to make sure that this timed out request, if it were in the
1021          * pending queue, doesn't get submitted while we are here, from
1022          * tw_cli_submit_pending_queue.  There could be a race in that case.
1023          * Need to revisit.
1024          */
1025         if (req->state != TW_CLI_REQ_STATE_PENDING)
1026                 tw_cl_reset_ctlr(ctlr->ctlr_handle);
1027         else {
1028                 tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(),
1029                         "Removing request from pending queue");
1030                 /*
1031                  * Request was never submitted.  Clean up.  Note that we did
1032                  * not do a reset.  So, we have to remove the request ourselves
1033                  * from the pending queue (as against tw_cli_drain_pendinq_queue
1034                  * taking care of it).
1035                  */
1036                 tw_cli_req_q_remove_item(req, TW_CLI_PENDING_Q);
1037                 if ((TW_CL_Q_FIRST_ITEM(&(ctlr->req_q_head[TW_CLI_PENDING_Q]))) == TW_CL_NULL)
1038                         TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle,
1039                                 TWA_CONTROL_MASK_COMMAND_INTERRUPT);
1040                 if (req->data)
1041                         ctlr->internal_req_busy = TW_CL_FALSE;
1042                 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
1043         }
1044
1045         return(TW_OSL_ETIMEDOUT);
1046 }
1047
1048
1049
1050 /*
1051  * Function name:       tw_cl_reset_ctlr
1052  * Description:         Soft resets and then initializes the controller;
1053  *                      drains any incomplete requests.
1054  *
1055  * Input:               ctlr    -- ptr to per ctlr structure
1056  * Output:              None
1057  * Return value:        0       -- success
1058  *                      non-zero-- failure
1059  */
1060 TW_INT32
1061 tw_cl_reset_ctlr(struct tw_cl_ctlr_handle *ctlr_handle)
1062 {
1063         struct tw_cli_ctlr_context      *ctlr =
1064                 (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt);
1065         struct twa_softc                *sc = ctlr_handle->osl_ctlr_ctxt;
1066         TW_INT32                        reset_attempt = 1;
1067         TW_INT32                        error;
1068
1069         tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), "entered");
1070
1071         ctlr->reset_in_progress = TW_CL_TRUE;
1072         xpt_freeze_simq(sc->sim, 1);
1073
1074         tw_cli_disable_interrupts(ctlr);
1075
1076         /*
1077          * Error back all requests in the complete, busy, and pending queues.
1078          * If any request is already on its way to getting submitted, it's in
1079          * none of these queues and so, will not be completed.  That request
1080          * will continue its course and get submitted to the controller after
1081          * the reset is done (and io_lock is released).
1082          */
1083         tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(),
1084                 "Draining all queues following reset");
1085         tw_cli_drain_complete_queue(ctlr);
1086         tw_cli_drain_busy_queue(ctlr);
1087         tw_cli_drain_pending_queue(ctlr);
1088         ctlr->internal_req_busy = TW_CL_FALSE;
1089         ctlr->get_more_aens     = TW_CL_FALSE;
1090
1091         /* Soft reset the controller. */
1092 try_reset:
1093         if ((error = tw_cli_soft_reset(ctlr))) {
1094                 tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
1095                         TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
1096                         0x1105, 0x1, TW_CL_SEVERITY_ERROR_STRING,
1097                         "Controller reset failed",
1098                         "error = %d; attempt %d", error, reset_attempt++);
1099                 if (reset_attempt <= TW_CLI_MAX_RESET_ATTEMPTS)
1100                         goto try_reset;
1101                 else
1102                         goto out;
1103         }
1104
1105         /* Re-establish logical connection with the controller. */
1106         if ((error = tw_cli_init_connection(ctlr,
1107                         (TW_UINT16)(ctlr->max_simult_reqs),
1108                         0, 0, 0, 0, 0, TW_CL_NULL, TW_CL_NULL, TW_CL_NULL,
1109                         TW_CL_NULL, TW_CL_NULL))) {
1110                 tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
1111                         TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
1112                         0x1106, 0x1, TW_CL_SEVERITY_ERROR_STRING,
1113                         "Can't initialize connection after reset",
1114                         "error = %d", error);
1115                 goto out;
1116         }
1117
1118         tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
1119                 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
1120                 0x1107, 0x3, TW_CL_SEVERITY_INFO_STRING,
1121                 "Controller reset done!",
1122                 " ");
1123
1124 out:
1125         ctlr->reset_in_progress = TW_CL_FALSE;
1126         xpt_release_simq(sc->sim, 1);
1127
1128         /*
1129          * Enable interrupts, and also clear attention and response interrupts.
1130          */
1131         tw_cli_enable_interrupts(ctlr);
1132
1133         /* Request for a bus re-scan. */
1134         if (!error)
1135                 tw_osl_scan_bus(ctlr_handle);
1136         return(error);
1137 }
1138
1139
1140
1141 /*
1142  * Function name:       tw_cli_soft_reset
1143  * Description:         Does the actual soft reset.
1144  *
1145  * Input:               ctlr    -- ptr to per ctlr structure
1146  * Output:              None
1147  * Return value:        0       -- success
1148  *                      non-zero-- failure
1149  */
1150 TW_INT32
1151 tw_cli_soft_reset(struct tw_cli_ctlr_context *ctlr)
1152 {
1153         struct tw_cl_ctlr_handle        *ctlr_handle = ctlr->ctlr_handle;
1154         TW_UINT32                       status_reg;
1155         int                             found;
1156         int                             loop_count;
1157         TW_UINT32                       error;
1158
1159         tw_cli_dbg_printf(1, ctlr_handle, tw_osl_cur_func(), "entered");
1160
1161         tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
1162                 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
1163                 0x1108, 0x3, TW_CL_SEVERITY_INFO_STRING,
1164                 "Resetting controller...",
1165                 " ");
1166
1167         /* Don't let any new commands get submitted to the controller. */
1168         tw_osl_get_lock(ctlr_handle, ctlr->io_lock);
1169
1170         TW_CLI_SOFT_RESET(ctlr_handle);
1171
1172         if ((ctlr->device_id == TW_CL_DEVICE_ID_9K_X) ||
1173             (ctlr->device_id == TW_CL_DEVICE_ID_9K_E) ||
1174             (ctlr->device_id == TW_CL_DEVICE_ID_9K_SA)) {
1175                 /*
1176                  * There's a hardware bug in the G133 ASIC, which can lead to
1177                  * PCI parity errors and hangs, if the host accesses any
1178                  * registers when the firmware is resetting the hardware, as
1179                  * part of a hard/soft reset.  The window of time when the
1180                  * problem can occur is about 10 ms.  Here, we will handshake
1181                  * with the firmware to find out when the firmware is pulling
1182                  * down the hardware reset pin, and wait for about 500 ms to
1183                  * make sure we don't access any hardware registers (for
1184                  * polling) during that window.
1185                  */
1186                 ctlr->reset_phase1_in_progress = TW_CL_TRUE;
1187                 loop_count = 0;
1188                 do {
1189                         found = (tw_cli_find_response(ctlr, TWA_RESET_PHASE1_NOTIFICATION_RESPONSE) == TW_OSL_ESUCCESS);
1190                         tw_osl_delay(10);
1191                         loop_count++;
1192                         error = 0x7888;
1193                 } while (!found && (loop_count < 6000000)); /* Loop for no more than 60 seconds */
1194
1195                 if (!found) {
1196                         tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
1197                                 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
1198                                 0x1109, 0x1, TW_CL_SEVERITY_ERROR_STRING,
1199                                 "Missed firmware handshake after soft-reset",
1200                                 "error = %d", error);
1201                         tw_osl_free_lock(ctlr_handle, ctlr->io_lock);
1202                         return(error);
1203                 }
1204
1205                 tw_osl_delay(TWA_RESET_PHASE1_WAIT_TIME_MS * 1000);
1206                 ctlr->reset_phase1_in_progress = TW_CL_FALSE;
1207         }
1208
1209         if ((error = tw_cli_poll_status(ctlr,
1210                         TWA_STATUS_MICROCONTROLLER_READY |
1211                         TWA_STATUS_ATTENTION_INTERRUPT,
1212                         TW_CLI_RESET_TIMEOUT_PERIOD))) {
1213                 tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
1214                         TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
1215                         0x1109, 0x1, TW_CL_SEVERITY_ERROR_STRING,
1216                         "Micro-ctlr not ready/No attn intr after reset",
1217                         "error = %d", error);
1218                 tw_osl_free_lock(ctlr_handle, ctlr->io_lock);
1219                 return(error);
1220         }
1221
1222         TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle,
1223                 TWA_CONTROL_CLEAR_ATTENTION_INTERRUPT);
1224
1225         if ((error = tw_cli_drain_response_queue(ctlr))) {
1226                 tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
1227                         TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
1228                         0x110A, 0x1, TW_CL_SEVERITY_ERROR_STRING,
1229                         "Can't drain response queue after reset",
1230                         "error = %d", error);
1231                 tw_osl_free_lock(ctlr_handle, ctlr->io_lock);
1232                 return(error);
1233         }
1234
1235         tw_osl_free_lock(ctlr_handle, ctlr->io_lock);
1236
1237         if ((error = tw_cli_drain_aen_queue(ctlr))) {
1238                 tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
1239                         TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
1240                         0x110B, 0x1, TW_CL_SEVERITY_ERROR_STRING,
1241                         "Can't drain AEN queue after reset",
1242                         "error = %d", error);
1243                 return(error);
1244         }
1245
1246         if ((error = tw_cli_find_aen(ctlr, TWA_AEN_SOFT_RESET))) {
1247                 tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
1248                         TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
1249                         0x110C, 0x1, TW_CL_SEVERITY_ERROR_STRING,
1250                         "Reset not reported by controller",
1251                         "error = %d", error);
1252                 return(error);
1253         }
1254
1255         status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr_handle);
1256
1257         if ((error = TW_CLI_STATUS_ERRORS(status_reg)) ||
1258                         (error = tw_cli_check_ctlr_state(ctlr, status_reg))) {
1259                 tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
1260                         TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
1261                         0x110D, 0x1, TW_CL_SEVERITY_ERROR_STRING,
1262                         "Controller errors detected after reset",
1263                         "error = %d", error);
1264                 return(error);
1265         }
1266
1267         return(TW_OSL_ESUCCESS);
1268 }
1269
1270
1271
1272 /*
1273  * Function name:       tw_cli_send_scsi_cmd
1274  * Description:         Sends down a scsi cmd to fw.
1275  *
1276  * Input:               req     -- ptr to request pkt
1277  *                      cmd     -- opcode of scsi cmd to send
1278  * Output:              None
1279  * Return value:        0       -- success
1280  *                      non-zero-- failure
1281  */
1282 TW_INT32
1283 tw_cli_send_scsi_cmd(struct tw_cli_req_context *req, TW_INT32 cmd)
1284 {
1285         struct tw_cl_command_packet     *cmdpkt;
1286         struct tw_cl_command_9k         *cmd9k;
1287         struct tw_cli_ctlr_context      *ctlr;
1288         TW_INT32                        error;
1289
1290         ctlr = req->ctlr;
1291         tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
1292
1293         /* Make sure this is the only CL internal request at this time. */
1294         if (ctlr->internal_req_busy)
1295                 return(TW_OSL_EBUSY);
1296         ctlr->internal_req_busy = TW_CL_TRUE;
1297         req->data = ctlr->internal_req_data;
1298         req->data_phys = ctlr->internal_req_data_phys;
1299         tw_osl_memzero(req->data, TW_CLI_SECTOR_SIZE);
1300         req->length = TW_CLI_SECTOR_SIZE;
1301
1302         /* Build the cmd pkt. */
1303         cmdpkt = req->cmd_pkt;
1304
1305         cmdpkt->cmd_hdr.header_desc.size_header = 128;
1306
1307         cmd9k = &(cmdpkt->command.cmd_pkt_9k);
1308
1309         cmd9k->res__opcode =
1310                 BUILD_RES__OPCODE(0, TWA_FW_CMD_EXECUTE_SCSI);
1311         cmd9k->unit = 0;
1312         cmd9k->lun_l4__req_id = TW_CL_SWAP16(req->request_id);
1313         cmd9k->status = 0;
1314         cmd9k->sgl_offset = 16; /* offset from end of hdr = max cdb len */
1315         cmd9k->lun_h4__sgl_entries = TW_CL_SWAP16(1);
1316
1317         if (req->ctlr->flags & TW_CL_64BIT_ADDRESSES) {
1318                 ((struct tw_cl_sg_desc64 *)(cmd9k->sg_list))[0].address =
1319                         TW_CL_SWAP64(req->data_phys);
1320                 ((struct tw_cl_sg_desc64 *)(cmd9k->sg_list))[0].length =
1321                         TW_CL_SWAP32(req->length);
1322         } else {
1323                 ((struct tw_cl_sg_desc32 *)(cmd9k->sg_list))[0].address =
1324                         TW_CL_SWAP32(req->data_phys);
1325                 ((struct tw_cl_sg_desc32 *)(cmd9k->sg_list))[0].length =
1326                         TW_CL_SWAP32(req->length);
1327         }
1328
1329         cmd9k->cdb[0] = (TW_UINT8)cmd;
1330         cmd9k->cdb[4] = 128;
1331
1332         if ((error = tw_cli_submit_cmd(req)))
1333                 if (error != TW_OSL_EBUSY) {
1334                         tw_cli_dbg_printf(1, ctlr->ctlr_handle,
1335                                 tw_osl_cur_func(),
1336                                 "Failed to start SCSI command",
1337                                 "request = %p, error = %d", req, error);
1338                         return(TW_OSL_EIO);
1339                 }
1340         return(TW_OSL_ESUCCESS);
1341 }
1342
1343
1344
1345 /*
1346  * Function name:       tw_cli_get_aen
1347  * Description:         Sends down a Request Sense cmd to fw to fetch an AEN.
1348  *
1349  * Input:               ctlr    -- ptr to per ctlr structure
1350  * Output:              None
1351  * Return value:        0       -- success
1352  *                      non-zero-- failure
1353  */
1354 TW_INT32
1355 tw_cli_get_aen(struct tw_cli_ctlr_context *ctlr)
1356 {
1357         struct tw_cli_req_context       *req;
1358         TW_INT32                        error;
1359
1360         tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
1361
1362         if ((req = tw_cli_get_request(ctlr
1363                 )) == TW_CL_NULL)
1364                 return(TW_OSL_EBUSY);
1365
1366         req->flags |= TW_CLI_REQ_FLAGS_INTERNAL;
1367         req->flags |= TW_CLI_REQ_FLAGS_9K;
1368         req->tw_cli_callback = tw_cli_aen_callback;
1369         if ((error = tw_cli_send_scsi_cmd(req, 0x03 /* REQUEST_SENSE */))) {
1370                 tw_cli_dbg_printf(1, ctlr->ctlr_handle, tw_osl_cur_func(),
1371                         "Could not send SCSI command",
1372                         "request = %p, error = %d", req, error);
1373                 if (req->data)
1374                         ctlr->internal_req_busy = TW_CL_FALSE;
1375                 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
1376         }
1377         return(error);
1378 }
1379
1380
1381
1382 /*
1383  * Function name:       tw_cli_fill_sg_list
1384  * Description:         Fills in the scatter/gather list.
1385  *
1386  * Input:               ctlr    -- ptr to per ctlr structure
1387  *                      sgl_src -- ptr to fill the sg list from
1388  *                      sgl_dest-- ptr to sg list
1389  *                      nsegments--# of segments
1390  * Output:              None
1391  * Return value:        None
1392  */
1393 TW_VOID
1394 tw_cli_fill_sg_list(struct tw_cli_ctlr_context *ctlr, TW_VOID *sgl_src,
1395         TW_VOID *sgl_dest, TW_INT32 num_sgl_entries)
1396 {
1397         TW_INT32        i;
1398
1399         tw_cli_dbg_printf(10, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
1400
1401         if (ctlr->flags & TW_CL_64BIT_ADDRESSES) {
1402                 struct tw_cl_sg_desc64 *sgl_s =
1403                         (struct tw_cl_sg_desc64 *)sgl_src;
1404                 struct tw_cl_sg_desc64 *sgl_d =
1405                         (struct tw_cl_sg_desc64 *)sgl_dest;
1406
1407                 tw_cli_dbg_printf(10, ctlr->ctlr_handle, tw_osl_cur_func(),
1408                         "64 bit addresses");
1409                 for (i = 0; i < num_sgl_entries; i++) {
1410                         sgl_d[i].address = TW_CL_SWAP64(sgl_s->address);
1411                         sgl_d[i].length = TW_CL_SWAP32(sgl_s->length);
1412                         sgl_s++;
1413                         if (ctlr->flags & TW_CL_64BIT_SG_LENGTH)
1414                                 sgl_s = (struct tw_cl_sg_desc64 *)
1415                                         (((TW_INT8 *)(sgl_s)) + 4);
1416                 }
1417         } else {
1418                 struct tw_cl_sg_desc32 *sgl_s =
1419                         (struct tw_cl_sg_desc32 *)sgl_src;
1420                 struct tw_cl_sg_desc32 *sgl_d =
1421                         (struct tw_cl_sg_desc32 *)sgl_dest;
1422
1423                 tw_cli_dbg_printf(10, ctlr->ctlr_handle, tw_osl_cur_func(),
1424                         "32 bit addresses");
1425                 for (i = 0; i < num_sgl_entries; i++) {
1426                         sgl_d[i].address = TW_CL_SWAP32(sgl_s[i].address);
1427                         sgl_d[i].length = TW_CL_SWAP32(sgl_s[i].length);
1428                 }
1429         }
1430 }