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