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