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