xref: /dflybsd-src/sys/dev/raid/twa/tw_cl_io.c (revision 1e0dd9dd32a69a1d3bbe6a9e41c3a63aae59fb4d)
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