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