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