1*9e39c5baSBill Taylor /*
2*9e39c5baSBill Taylor  * CDDL HEADER START
3*9e39c5baSBill Taylor  *
4*9e39c5baSBill Taylor  * The contents of this file are subject to the terms of the
5*9e39c5baSBill Taylor  * Common Development and Distribution License (the "License").
6*9e39c5baSBill Taylor  * You may not use this file except in compliance with the License.
7*9e39c5baSBill Taylor  *
8*9e39c5baSBill Taylor  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*9e39c5baSBill Taylor  * or http://www.opensolaris.org/os/licensing.
10*9e39c5baSBill Taylor  * See the License for the specific language governing permissions
11*9e39c5baSBill Taylor  * and limitations under the License.
12*9e39c5baSBill Taylor  *
13*9e39c5baSBill Taylor  * When distributing Covered Code, include this CDDL HEADER in each
14*9e39c5baSBill Taylor  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*9e39c5baSBill Taylor  * If applicable, add the following below this CDDL HEADER, with the
16*9e39c5baSBill Taylor  * fields enclosed by brackets "[]" replaced with your own identifying
17*9e39c5baSBill Taylor  * information: Portions Copyright [yyyy] [name of copyright owner]
18*9e39c5baSBill Taylor  *
19*9e39c5baSBill Taylor  * CDDL HEADER END
20*9e39c5baSBill Taylor  */
21*9e39c5baSBill Taylor 
22*9e39c5baSBill Taylor /*
23*9e39c5baSBill Taylor  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*9e39c5baSBill Taylor  * Use is subject to license terms.
25*9e39c5baSBill Taylor  */
26*9e39c5baSBill Taylor 
27*9e39c5baSBill Taylor /*
28*9e39c5baSBill Taylor  * tavor_ioctl.c
29*9e39c5baSBill Taylor  *    Tavor IOCTL Routines
30*9e39c5baSBill Taylor  *
31*9e39c5baSBill Taylor  *    Implements all ioctl access into the driver.  This includes all routines
32*9e39c5baSBill Taylor  *    necessary for updating firmware, accessing the tavor flash device, and
33*9e39c5baSBill Taylor  *    providing interfaces for VTS.
34*9e39c5baSBill Taylor  */
35*9e39c5baSBill Taylor 
36*9e39c5baSBill Taylor #include <sys/types.h>
37*9e39c5baSBill Taylor #include <sys/conf.h>
38*9e39c5baSBill Taylor #include <sys/ddi.h>
39*9e39c5baSBill Taylor #include <sys/sunddi.h>
40*9e39c5baSBill Taylor #include <sys/modctl.h>
41*9e39c5baSBill Taylor #include <sys/file.h>
42*9e39c5baSBill Taylor 
43*9e39c5baSBill Taylor #include <sys/ib/adapters/tavor/tavor.h>
44*9e39c5baSBill Taylor 
45*9e39c5baSBill Taylor /* Tavor HCA state pointer (extern) */
46*9e39c5baSBill Taylor extern void	*tavor_statep;
47*9e39c5baSBill Taylor 
48*9e39c5baSBill Taylor /*
49*9e39c5baSBill Taylor  * The ioctl declarations (for firmware flash burning, register read/write
50*9e39c5baSBill Taylor  * (DEBUG-only), and VTS interfaces)
51*9e39c5baSBill Taylor  */
52*9e39c5baSBill Taylor static int tavor_ioctl_flash_read(tavor_state_t *state, dev_t dev,
53*9e39c5baSBill Taylor     intptr_t arg, int mode);
54*9e39c5baSBill Taylor static int tavor_ioctl_flash_write(tavor_state_t *state, dev_t dev,
55*9e39c5baSBill Taylor     intptr_t arg, int mode);
56*9e39c5baSBill Taylor static int tavor_ioctl_flash_erase(tavor_state_t *state, dev_t dev,
57*9e39c5baSBill Taylor     intptr_t arg, int mode);
58*9e39c5baSBill Taylor static int tavor_ioctl_flash_init(tavor_state_t *state, dev_t dev,
59*9e39c5baSBill Taylor     intptr_t arg, int mode);
60*9e39c5baSBill Taylor static int tavor_ioctl_flash_fini(tavor_state_t *state, dev_t dev);
61*9e39c5baSBill Taylor static void tavor_ioctl_flash_cleanup(tavor_state_t *state);
62*9e39c5baSBill Taylor static void tavor_ioctl_flash_cleanup_nolock(tavor_state_t *state);
63*9e39c5baSBill Taylor #ifdef	DEBUG
64*9e39c5baSBill Taylor static int tavor_ioctl_reg_write(tavor_state_t *state, intptr_t arg,
65*9e39c5baSBill Taylor     int mode);
66*9e39c5baSBill Taylor static int tavor_ioctl_reg_read(tavor_state_t *state, intptr_t arg,
67*9e39c5baSBill Taylor     int mode);
68*9e39c5baSBill Taylor #endif	/* DEBUG */
69*9e39c5baSBill Taylor static int tavor_ioctl_info(tavor_state_t *state, dev_t dev,
70*9e39c5baSBill Taylor     intptr_t arg, int mode);
71*9e39c5baSBill Taylor static int tavor_ioctl_ports(tavor_state_t *state, intptr_t arg,
72*9e39c5baSBill Taylor     int mode);
73*9e39c5baSBill Taylor static int tavor_ioctl_loopback(tavor_state_t *state, intptr_t arg,
74*9e39c5baSBill Taylor     int mode);
75*9e39c5baSBill Taylor static int tavor_ioctl_ddr_read(tavor_state_t *state, intptr_t arg,
76*9e39c5baSBill Taylor     int mode);
77*9e39c5baSBill Taylor 
78*9e39c5baSBill Taylor /* Tavor Flash Functions */
79*9e39c5baSBill Taylor static void tavor_flash_read_sector(tavor_state_t *state, uint32_t sector_num);
80*9e39c5baSBill Taylor static void tavor_flash_read_quadlet(tavor_state_t *state, uint32_t *data,
81*9e39c5baSBill Taylor     uint32_t addr);
82*9e39c5baSBill Taylor static int  tavor_flash_write_sector(tavor_state_t *state, uint32_t sector_num);
83*9e39c5baSBill Taylor static int  tavor_flash_write_byte(tavor_state_t *state, uint32_t addr,
84*9e39c5baSBill Taylor     uchar_t data);
85*9e39c5baSBill Taylor static int  tavor_flash_erase_sector(tavor_state_t *state, uint32_t sector_num);
86*9e39c5baSBill Taylor static int  tavor_flash_erase_chip(tavor_state_t *state);
87*9e39c5baSBill Taylor static void tavor_flash_bank(tavor_state_t *state, uint32_t addr);
88*9e39c5baSBill Taylor static uint32_t tavor_flash_read(tavor_state_t *state, uint32_t addr);
89*9e39c5baSBill Taylor static void tavor_flash_write(tavor_state_t *state, uint32_t addr,
90*9e39c5baSBill Taylor     uchar_t data);
91*9e39c5baSBill Taylor static void tavor_flash_init(tavor_state_t *state);
92*9e39c5baSBill Taylor static void tavor_flash_cfi_init(tavor_state_t *state, uint32_t *cfi_info,
93*9e39c5baSBill Taylor     int *intel_xcmd);
94*9e39c5baSBill Taylor static void tavor_flash_fini(tavor_state_t *state);
95*9e39c5baSBill Taylor static void tavor_flash_reset(tavor_state_t *state);
96*9e39c5baSBill Taylor static uint32_t tavor_flash_read_cfg(ddi_acc_handle_t pci_config_hdl,
97*9e39c5baSBill Taylor     uint32_t addr);
98*9e39c5baSBill Taylor static void tavor_flash_write_cfg(ddi_acc_handle_t pci_config_hdl,
99*9e39c5baSBill Taylor     uint32_t addr, uint32_t data);
100*9e39c5baSBill Taylor static void tavor_flash_cfi_byte(uint8_t *ch, uint32_t dword, int i);
101*9e39c5baSBill Taylor static void tavor_flash_cfi_dword(uint32_t *dword, uint8_t *ch, int i);
102*9e39c5baSBill Taylor 
103*9e39c5baSBill Taylor /* Tavor loopback test functions */
104*9e39c5baSBill Taylor static void tavor_loopback_free_qps(tavor_loopback_state_t *lstate);
105*9e39c5baSBill Taylor static void tavor_loopback_free_state(tavor_loopback_state_t *lstate);
106*9e39c5baSBill Taylor static int tavor_loopback_init(tavor_state_t *state,
107*9e39c5baSBill Taylor     tavor_loopback_state_t *lstate);
108*9e39c5baSBill Taylor static void tavor_loopback_init_qp_info(tavor_loopback_state_t *lstate,
109*9e39c5baSBill Taylor     tavor_loopback_comm_t *comm);
110*9e39c5baSBill Taylor static int tavor_loopback_alloc_mem(tavor_loopback_state_t *lstate,
111*9e39c5baSBill Taylor     tavor_loopback_comm_t *comm, int sz);
112*9e39c5baSBill Taylor static int tavor_loopback_alloc_qps(tavor_loopback_state_t *lstate,
113*9e39c5baSBill Taylor     tavor_loopback_comm_t *comm);
114*9e39c5baSBill Taylor static int tavor_loopback_modify_qp(tavor_loopback_state_t *lstate,
115*9e39c5baSBill Taylor     tavor_loopback_comm_t *comm, uint_t qp_num);
116*9e39c5baSBill Taylor static int tavor_loopback_copyout(tavor_loopback_ioctl_t *lb,
117*9e39c5baSBill Taylor     intptr_t arg, int mode);
118*9e39c5baSBill Taylor static int tavor_loopback_post_send(tavor_loopback_state_t *lstate,
119*9e39c5baSBill Taylor     tavor_loopback_comm_t *tx, tavor_loopback_comm_t *rx);
120*9e39c5baSBill Taylor static int tavor_loopback_poll_cq(tavor_loopback_state_t *lstate,
121*9e39c5baSBill Taylor     tavor_loopback_comm_t *comm);
122*9e39c5baSBill Taylor 
123*9e39c5baSBill Taylor /* Patchable timeout values for flash operations */
124*9e39c5baSBill Taylor int tavor_hw_flash_timeout_gpio_sema = TAVOR_HW_FLASH_TIMEOUT_GPIO_SEMA;
125*9e39c5baSBill Taylor int tavor_hw_flash_timeout_config = TAVOR_HW_FLASH_TIMEOUT_CONFIG;
126*9e39c5baSBill Taylor int tavor_hw_flash_timeout_write = TAVOR_HW_FLASH_TIMEOUT_WRITE;
127*9e39c5baSBill Taylor int tavor_hw_flash_timeout_erase = TAVOR_HW_FLASH_TIMEOUT_ERASE;
128*9e39c5baSBill Taylor 
129*9e39c5baSBill Taylor /*
130*9e39c5baSBill Taylor  * tavor_ioctl()
131*9e39c5baSBill Taylor  */
132*9e39c5baSBill Taylor /* ARGSUSED */
133*9e39c5baSBill Taylor int
134*9e39c5baSBill Taylor tavor_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
135*9e39c5baSBill Taylor     int *rvalp)
136*9e39c5baSBill Taylor {
137*9e39c5baSBill Taylor 	tavor_state_t	*state;
138*9e39c5baSBill Taylor 	minor_t		instance;
139*9e39c5baSBill Taylor 	int		status;
140*9e39c5baSBill Taylor 
141*9e39c5baSBill Taylor 	TAVOR_TNF_ENTER(tavor_ioctl);
142*9e39c5baSBill Taylor 
143*9e39c5baSBill Taylor 	if (drv_priv(credp) != 0) {
144*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_priv_fail, TAVOR_TNF_ERROR, "");
145*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl);
146*9e39c5baSBill Taylor 		return (EPERM);
147*9e39c5baSBill Taylor 	}
148*9e39c5baSBill Taylor 
149*9e39c5baSBill Taylor 	instance = TAVOR_DEV_INSTANCE(dev);
150*9e39c5baSBill Taylor 	if (instance == -1) {
151*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_inst_fail, TAVOR_TNF_ERROR, "");
152*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl);
153*9e39c5baSBill Taylor 		return (EBADF);
154*9e39c5baSBill Taylor 	}
155*9e39c5baSBill Taylor 
156*9e39c5baSBill Taylor 	state = ddi_get_soft_state(tavor_statep, instance);
157*9e39c5baSBill Taylor 	if (state == NULL) {
158*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_gss_fail, TAVOR_TNF_ERROR, "");
159*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl);
160*9e39c5baSBill Taylor 		return (EBADF);
161*9e39c5baSBill Taylor 	}
162*9e39c5baSBill Taylor 
163*9e39c5baSBill Taylor 	status = 0;
164*9e39c5baSBill Taylor 
165*9e39c5baSBill Taylor 	switch (cmd) {
166*9e39c5baSBill Taylor 	case TAVOR_IOCTL_FLASH_READ:
167*9e39c5baSBill Taylor 		status = tavor_ioctl_flash_read(state, dev, arg, mode);
168*9e39c5baSBill Taylor 		break;
169*9e39c5baSBill Taylor 
170*9e39c5baSBill Taylor 	case TAVOR_IOCTL_FLASH_WRITE:
171*9e39c5baSBill Taylor 		status = tavor_ioctl_flash_write(state, dev, arg, mode);
172*9e39c5baSBill Taylor 		break;
173*9e39c5baSBill Taylor 
174*9e39c5baSBill Taylor 	case TAVOR_IOCTL_FLASH_ERASE:
175*9e39c5baSBill Taylor 		status = tavor_ioctl_flash_erase(state, dev, arg, mode);
176*9e39c5baSBill Taylor 		break;
177*9e39c5baSBill Taylor 
178*9e39c5baSBill Taylor 	case TAVOR_IOCTL_FLASH_INIT:
179*9e39c5baSBill Taylor 		status = tavor_ioctl_flash_init(state, dev, arg, mode);
180*9e39c5baSBill Taylor 		break;
181*9e39c5baSBill Taylor 
182*9e39c5baSBill Taylor 	case TAVOR_IOCTL_FLASH_FINI:
183*9e39c5baSBill Taylor 		status = tavor_ioctl_flash_fini(state, dev);
184*9e39c5baSBill Taylor 		break;
185*9e39c5baSBill Taylor 
186*9e39c5baSBill Taylor 	case TAVOR_IOCTL_INFO:
187*9e39c5baSBill Taylor 		status = tavor_ioctl_info(state, dev, arg, mode);
188*9e39c5baSBill Taylor 		break;
189*9e39c5baSBill Taylor 
190*9e39c5baSBill Taylor 	case TAVOR_IOCTL_PORTS:
191*9e39c5baSBill Taylor 		status = tavor_ioctl_ports(state, arg, mode);
192*9e39c5baSBill Taylor 		break;
193*9e39c5baSBill Taylor 
194*9e39c5baSBill Taylor 	case TAVOR_IOCTL_DDR_READ:
195*9e39c5baSBill Taylor 		status = tavor_ioctl_ddr_read(state, arg, mode);
196*9e39c5baSBill Taylor 		break;
197*9e39c5baSBill Taylor 
198*9e39c5baSBill Taylor 	case TAVOR_IOCTL_LOOPBACK:
199*9e39c5baSBill Taylor 		status = tavor_ioctl_loopback(state, arg, mode);
200*9e39c5baSBill Taylor 		break;
201*9e39c5baSBill Taylor 
202*9e39c5baSBill Taylor #ifdef	DEBUG
203*9e39c5baSBill Taylor 	case TAVOR_IOCTL_REG_WRITE:
204*9e39c5baSBill Taylor 		status = tavor_ioctl_reg_write(state, arg, mode);
205*9e39c5baSBill Taylor 		break;
206*9e39c5baSBill Taylor 
207*9e39c5baSBill Taylor 	case TAVOR_IOCTL_REG_READ:
208*9e39c5baSBill Taylor 		status = tavor_ioctl_reg_read(state, arg, mode);
209*9e39c5baSBill Taylor 		break;
210*9e39c5baSBill Taylor #endif	/* DEBUG */
211*9e39c5baSBill Taylor 
212*9e39c5baSBill Taylor 	default:
213*9e39c5baSBill Taylor 		status = ENOTTY;
214*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_default_fail, TAVOR_TNF_ERROR, "");
215*9e39c5baSBill Taylor 		break;
216*9e39c5baSBill Taylor 	}
217*9e39c5baSBill Taylor 	*rvalp = status;
218*9e39c5baSBill Taylor 
219*9e39c5baSBill Taylor 	TAVOR_TNF_EXIT(tavor_ioctl);
220*9e39c5baSBill Taylor 	return (status);
221*9e39c5baSBill Taylor }
222*9e39c5baSBill Taylor 
223*9e39c5baSBill Taylor /*
224*9e39c5baSBill Taylor  * tavor_ioctl_flash_read()
225*9e39c5baSBill Taylor  */
226*9e39c5baSBill Taylor static int
227*9e39c5baSBill Taylor tavor_ioctl_flash_read(tavor_state_t *state, dev_t dev, intptr_t arg, int mode)
228*9e39c5baSBill Taylor {
229*9e39c5baSBill Taylor 	tavor_flash_ioctl_t ioctl_info;
230*9e39c5baSBill Taylor 	int status = 0;
231*9e39c5baSBill Taylor 
232*9e39c5baSBill Taylor 	TAVOR_TNF_ENTER(tavor_ioctl_flash_read);
233*9e39c5baSBill Taylor 
234*9e39c5baSBill Taylor 	/*
235*9e39c5baSBill Taylor 	 * Check that flash init ioctl has been called first.  And check
236*9e39c5baSBill Taylor 	 * that the same dev_t that called init is the one calling read now.
237*9e39c5baSBill Taylor 	 */
238*9e39c5baSBill Taylor 	mutex_enter(&state->ts_fw_flashlock);
239*9e39c5baSBill Taylor 	if ((state->ts_fw_flashdev != dev) ||
240*9e39c5baSBill Taylor 	    (state->ts_fw_flashstarted == 0)) {
241*9e39c5baSBill Taylor 		mutex_exit(&state->ts_fw_flashlock);
242*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_flash_bad_state, TAVOR_TNF_ERROR, "");
243*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_flash_read);
244*9e39c5baSBill Taylor 		return (EIO);
245*9e39c5baSBill Taylor 	}
246*9e39c5baSBill Taylor 
247*9e39c5baSBill Taylor 	/* copy user struct to kernel */
248*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
249*9e39c5baSBill Taylor 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
250*9e39c5baSBill Taylor 		tavor_flash_ioctl32_t info32;
251*9e39c5baSBill Taylor 
252*9e39c5baSBill Taylor 		if (ddi_copyin((void *)arg, &info32,
253*9e39c5baSBill Taylor 		    sizeof (tavor_flash_ioctl32_t), mode) != 0) {
254*9e39c5baSBill Taylor 			mutex_exit(&state->ts_fw_flashlock);
255*9e39c5baSBill Taylor 			TNF_PROBE_0(tavor_ioctl_flash_read_copyin_fail,
256*9e39c5baSBill Taylor 			    TAVOR_TNF_ERROR, "");
257*9e39c5baSBill Taylor 			TAVOR_TNF_EXIT(tavor_ioctl_flash_read);
258*9e39c5baSBill Taylor 			return (EFAULT);
259*9e39c5baSBill Taylor 		}
260*9e39c5baSBill Taylor 		ioctl_info.tf_type = info32.tf_type;
261*9e39c5baSBill Taylor 		ioctl_info.tf_sector = (caddr_t)(uintptr_t)info32.tf_sector;
262*9e39c5baSBill Taylor 		ioctl_info.tf_sector_num = info32.tf_sector_num;
263*9e39c5baSBill Taylor 		ioctl_info.tf_addr = info32.tf_addr;
264*9e39c5baSBill Taylor 	} else
265*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
266*9e39c5baSBill Taylor 	if (ddi_copyin((void *)arg, &ioctl_info, sizeof (tavor_flash_ioctl_t),
267*9e39c5baSBill Taylor 	    mode) != 0) {
268*9e39c5baSBill Taylor 		mutex_exit(&state->ts_fw_flashlock);
269*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_flash_read_copyin_fail,
270*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
271*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_flash_read);
272*9e39c5baSBill Taylor 		return (EFAULT);
273*9e39c5baSBill Taylor 	}
274*9e39c5baSBill Taylor 
275*9e39c5baSBill Taylor 	/*
276*9e39c5baSBill Taylor 	 * Determine type of READ ioctl
277*9e39c5baSBill Taylor 	 */
278*9e39c5baSBill Taylor 	switch (ioctl_info.tf_type) {
279*9e39c5baSBill Taylor 	case TAVOR_FLASH_READ_SECTOR:
280*9e39c5baSBill Taylor 		/* Check if sector num is too large for flash device */
281*9e39c5baSBill Taylor 		if (ioctl_info.tf_sector_num >=
282*9e39c5baSBill Taylor 		    (state->ts_fw_device_sz >> state->ts_fw_log_sector_sz)) {
283*9e39c5baSBill Taylor 			mutex_exit(&state->ts_fw_flashlock);
284*9e39c5baSBill Taylor 			TNF_PROBE_0(tavor_flash_read_sector_num_too_large,
285*9e39c5baSBill Taylor 			    TAVOR_TNF_ERROR, "");
286*9e39c5baSBill Taylor 			TAVOR_TNF_EXIT(tavor_ioctl_flash_read);
287*9e39c5baSBill Taylor 			return (EFAULT);
288*9e39c5baSBill Taylor 		}
289*9e39c5baSBill Taylor 
290*9e39c5baSBill Taylor 		/* Perform the Sector Read */
291*9e39c5baSBill Taylor 		tavor_flash_reset(state);
292*9e39c5baSBill Taylor 		tavor_flash_read_sector(state, ioctl_info.tf_sector_num);
293*9e39c5baSBill Taylor 
294*9e39c5baSBill Taylor 		/* copyout the firmware sector image data */
295*9e39c5baSBill Taylor 		if (ddi_copyout(&state->ts_fw_sector[0],
296*9e39c5baSBill Taylor 		    &ioctl_info.tf_sector[0], 1 << state->ts_fw_log_sector_sz,
297*9e39c5baSBill Taylor 		    mode) != 0) {
298*9e39c5baSBill Taylor 			mutex_exit(&state->ts_fw_flashlock);
299*9e39c5baSBill Taylor 			TNF_PROBE_0(tavor_flash_read_copyout_fail,
300*9e39c5baSBill Taylor 			    TAVOR_TNF_ERROR, "");
301*9e39c5baSBill Taylor 			TAVOR_TNF_EXIT(tavor_ioctl_flash_read);
302*9e39c5baSBill Taylor 			return (EFAULT);
303*9e39c5baSBill Taylor 		}
304*9e39c5baSBill Taylor 		break;
305*9e39c5baSBill Taylor 
306*9e39c5baSBill Taylor 	case TAVOR_FLASH_READ_QUADLET:
307*9e39c5baSBill Taylor 		/* Check if addr is too large for flash device */
308*9e39c5baSBill Taylor 		if (ioctl_info.tf_addr >= state->ts_fw_device_sz) {
309*9e39c5baSBill Taylor 			mutex_exit(&state->ts_fw_flashlock);
310*9e39c5baSBill Taylor 			TNF_PROBE_0(tavor_flash_read_quad_addr_too_large,
311*9e39c5baSBill Taylor 			    TAVOR_TNF_ERROR, "");
312*9e39c5baSBill Taylor 			TAVOR_TNF_EXIT(tavor_ioctl_flash_read);
313*9e39c5baSBill Taylor 			return (EFAULT);
314*9e39c5baSBill Taylor 		}
315*9e39c5baSBill Taylor 
316*9e39c5baSBill Taylor 		/* Perform the Quadlet Read */
317*9e39c5baSBill Taylor 		tavor_flash_reset(state);
318*9e39c5baSBill Taylor 		tavor_flash_read_quadlet(state, &ioctl_info.tf_quadlet,
319*9e39c5baSBill Taylor 		    ioctl_info.tf_addr);
320*9e39c5baSBill Taylor 		break;
321*9e39c5baSBill Taylor 
322*9e39c5baSBill Taylor 	default:
323*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_flash_read_invalid_type,
324*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
325*9e39c5baSBill Taylor 		status = EIO;
326*9e39c5baSBill Taylor 		break;
327*9e39c5baSBill Taylor 	}
328*9e39c5baSBill Taylor 
329*9e39c5baSBill Taylor 	/* copy results back to userland */
330*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
331*9e39c5baSBill Taylor 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
332*9e39c5baSBill Taylor 		tavor_flash_ioctl32_t info32;
333*9e39c5baSBill Taylor 
334*9e39c5baSBill Taylor 		info32.tf_quadlet = ioctl_info.tf_quadlet;
335*9e39c5baSBill Taylor 		info32.tf_type = ioctl_info.tf_type;
336*9e39c5baSBill Taylor 		info32.tf_sector_num = ioctl_info.tf_sector_num;
337*9e39c5baSBill Taylor 		info32.tf_sector = (caddr32_t)(uintptr_t)ioctl_info.tf_sector;
338*9e39c5baSBill Taylor 		info32.tf_addr = ioctl_info.tf_addr;
339*9e39c5baSBill Taylor 
340*9e39c5baSBill Taylor 		if (ddi_copyout(&info32, (void *)arg,
341*9e39c5baSBill Taylor 		    sizeof (tavor_flash_ioctl32_t), mode) != 0) {
342*9e39c5baSBill Taylor 			mutex_exit(&state->ts_fw_flashlock);
343*9e39c5baSBill Taylor 			TNF_PROBE_0(tavor_flash_read_copyout_fail,
344*9e39c5baSBill Taylor 			    TAVOR_TNF_ERROR, "");
345*9e39c5baSBill Taylor 			TAVOR_TNF_EXIT(tavor_ioctl_flash_read);
346*9e39c5baSBill Taylor 			return (EFAULT);
347*9e39c5baSBill Taylor 		}
348*9e39c5baSBill Taylor 	} else
349*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
350*9e39c5baSBill Taylor 	if (ddi_copyout(&ioctl_info, (void *)arg,
351*9e39c5baSBill Taylor 	    sizeof (tavor_flash_ioctl_t), mode) != 0) {
352*9e39c5baSBill Taylor 		mutex_exit(&state->ts_fw_flashlock);
353*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_flash_read_copyout_fail,
354*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
355*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_flash_read);
356*9e39c5baSBill Taylor 		return (EFAULT);
357*9e39c5baSBill Taylor 	}
358*9e39c5baSBill Taylor 
359*9e39c5baSBill Taylor 	mutex_exit(&state->ts_fw_flashlock);
360*9e39c5baSBill Taylor 	TAVOR_TNF_EXIT(tavor_ioctl_flash_read);
361*9e39c5baSBill Taylor 	return (status);
362*9e39c5baSBill Taylor }
363*9e39c5baSBill Taylor 
364*9e39c5baSBill Taylor /*
365*9e39c5baSBill Taylor  * tavor_ioctl_flash_write()
366*9e39c5baSBill Taylor  */
367*9e39c5baSBill Taylor static int
368*9e39c5baSBill Taylor tavor_ioctl_flash_write(tavor_state_t *state, dev_t dev, intptr_t arg, int mode)
369*9e39c5baSBill Taylor {
370*9e39c5baSBill Taylor 	tavor_flash_ioctl_t	ioctl_info;
371*9e39c5baSBill Taylor 	int status = 0;
372*9e39c5baSBill Taylor 
373*9e39c5baSBill Taylor 	TAVOR_TNF_ENTER(tavor_ioctl_flash_write);
374*9e39c5baSBill Taylor 
375*9e39c5baSBill Taylor 	/*
376*9e39c5baSBill Taylor 	 * Check that flash init ioctl has been called first.  And check
377*9e39c5baSBill Taylor 	 * that the same dev_t that called init is the one calling write now.
378*9e39c5baSBill Taylor 	 */
379*9e39c5baSBill Taylor 	mutex_enter(&state->ts_fw_flashlock);
380*9e39c5baSBill Taylor 	if ((state->ts_fw_flashdev != dev) ||
381*9e39c5baSBill Taylor 	    (state->ts_fw_flashstarted == 0)) {
382*9e39c5baSBill Taylor 		mutex_exit(&state->ts_fw_flashlock);
383*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_flash_bad_state, TAVOR_TNF_ERROR, "");
384*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_flash_write);
385*9e39c5baSBill Taylor 		return (EIO);
386*9e39c5baSBill Taylor 	}
387*9e39c5baSBill Taylor 
388*9e39c5baSBill Taylor 	/* copy user struct to kernel */
389*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
390*9e39c5baSBill Taylor 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
391*9e39c5baSBill Taylor 		tavor_flash_ioctl32_t info32;
392*9e39c5baSBill Taylor 
393*9e39c5baSBill Taylor 		if (ddi_copyin((void *)arg, &info32,
394*9e39c5baSBill Taylor 		    sizeof (tavor_flash_ioctl32_t), mode) != 0) {
395*9e39c5baSBill Taylor 			mutex_exit(&state->ts_fw_flashlock);
396*9e39c5baSBill Taylor 			TNF_PROBE_0(tavor_ioctl_flash_write_copyin_fail,
397*9e39c5baSBill Taylor 			    TAVOR_TNF_ERROR, "");
398*9e39c5baSBill Taylor 			TAVOR_TNF_EXIT(tavor_ioctl_flash_write);
399*9e39c5baSBill Taylor 			return (EFAULT);
400*9e39c5baSBill Taylor 		}
401*9e39c5baSBill Taylor 		ioctl_info.tf_type = info32.tf_type;
402*9e39c5baSBill Taylor 		ioctl_info.tf_sector = (caddr_t)(uintptr_t)info32.tf_sector;
403*9e39c5baSBill Taylor 		ioctl_info.tf_sector_num = info32.tf_sector_num;
404*9e39c5baSBill Taylor 		ioctl_info.tf_addr = info32.tf_addr;
405*9e39c5baSBill Taylor 		ioctl_info.tf_byte = info32.tf_byte;
406*9e39c5baSBill Taylor 	} else
407*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
408*9e39c5baSBill Taylor 	if (ddi_copyin((void *)arg, &ioctl_info,
409*9e39c5baSBill Taylor 	    sizeof (tavor_flash_ioctl_t), mode) != 0) {
410*9e39c5baSBill Taylor 		mutex_exit(&state->ts_fw_flashlock);
411*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_flash_write_ci_fail,
412*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
413*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_flash_write);
414*9e39c5baSBill Taylor 		return (EFAULT);
415*9e39c5baSBill Taylor 	}
416*9e39c5baSBill Taylor 
417*9e39c5baSBill Taylor 	/*
418*9e39c5baSBill Taylor 	 * Determine type of WRITE ioctl
419*9e39c5baSBill Taylor 	 */
420*9e39c5baSBill Taylor 	switch (ioctl_info.tf_type) {
421*9e39c5baSBill Taylor 	case TAVOR_FLASH_WRITE_SECTOR:
422*9e39c5baSBill Taylor 		/* Check if sector num is too large for flash device */
423*9e39c5baSBill Taylor 		if (ioctl_info.tf_sector_num >=
424*9e39c5baSBill Taylor 		    (state->ts_fw_device_sz >> state->ts_fw_log_sector_sz)) {
425*9e39c5baSBill Taylor 			mutex_exit(&state->ts_fw_flashlock);
426*9e39c5baSBill Taylor 			TNF_PROBE_0(tavor_flash_write_sector_num_too_large,
427*9e39c5baSBill Taylor 			    TAVOR_TNF_ERROR, "");
428*9e39c5baSBill Taylor 			TAVOR_TNF_EXIT(tavor_ioctl_flash_write);
429*9e39c5baSBill Taylor 			return (EFAULT);
430*9e39c5baSBill Taylor 		}
431*9e39c5baSBill Taylor 
432*9e39c5baSBill Taylor 		/* copy in fw sector image data */
433*9e39c5baSBill Taylor 		if (ddi_copyin(&ioctl_info.tf_sector[0],
434*9e39c5baSBill Taylor 		    &state->ts_fw_sector[0], 1 << state->ts_fw_log_sector_sz,
435*9e39c5baSBill Taylor 		    mode) != 0) {
436*9e39c5baSBill Taylor 			mutex_exit(&state->ts_fw_flashlock);
437*9e39c5baSBill Taylor 			TNF_PROBE_0(tavor_ioctl_flash_write_fw_sector_ci_fail,
438*9e39c5baSBill Taylor 			    TAVOR_TNF_ERROR, "");
439*9e39c5baSBill Taylor 			TAVOR_TNF_EXIT(tavor_ioctl_flash_write);
440*9e39c5baSBill Taylor 			return (EFAULT);
441*9e39c5baSBill Taylor 		}
442*9e39c5baSBill Taylor 
443*9e39c5baSBill Taylor 		/* Perform Write Sector */
444*9e39c5baSBill Taylor 		status = tavor_flash_write_sector(state,
445*9e39c5baSBill Taylor 		    ioctl_info.tf_sector_num);
446*9e39c5baSBill Taylor 		break;
447*9e39c5baSBill Taylor 
448*9e39c5baSBill Taylor 	case TAVOR_FLASH_WRITE_BYTE:
449*9e39c5baSBill Taylor 		/* Check if addr is too large for flash device */
450*9e39c5baSBill Taylor 		if (ioctl_info.tf_addr >= state->ts_fw_device_sz) {
451*9e39c5baSBill Taylor 			mutex_exit(&state->ts_fw_flashlock);
452*9e39c5baSBill Taylor 			TNF_PROBE_0(tavor_flash_write_byte_addr_too_large,
453*9e39c5baSBill Taylor 			    TAVOR_TNF_ERROR, "");
454*9e39c5baSBill Taylor 			TAVOR_TNF_EXIT(tavor_ioctl_flash_write);
455*9e39c5baSBill Taylor 			return (EFAULT);
456*9e39c5baSBill Taylor 		}
457*9e39c5baSBill Taylor 
458*9e39c5baSBill Taylor 		/* Perform Write Byte */
459*9e39c5baSBill Taylor 		tavor_flash_bank(state, ioctl_info.tf_addr);
460*9e39c5baSBill Taylor 		tavor_flash_reset(state);
461*9e39c5baSBill Taylor 		status = tavor_flash_write_byte(state, ioctl_info.tf_addr,
462*9e39c5baSBill Taylor 		    ioctl_info.tf_byte);
463*9e39c5baSBill Taylor 		tavor_flash_reset(state);
464*9e39c5baSBill Taylor 		break;
465*9e39c5baSBill Taylor 
466*9e39c5baSBill Taylor 	default:
467*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_flash_write_invalid_type,
468*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
469*9e39c5baSBill Taylor 		status = EIO;
470*9e39c5baSBill Taylor 		break;
471*9e39c5baSBill Taylor 	}
472*9e39c5baSBill Taylor 
473*9e39c5baSBill Taylor 	mutex_exit(&state->ts_fw_flashlock);
474*9e39c5baSBill Taylor 	TAVOR_TNF_EXIT(tavor_ioctl_flash_write);
475*9e39c5baSBill Taylor 	return (status);
476*9e39c5baSBill Taylor }
477*9e39c5baSBill Taylor 
478*9e39c5baSBill Taylor /*
479*9e39c5baSBill Taylor  * tavor_ioctl_flash_erase()
480*9e39c5baSBill Taylor  */
481*9e39c5baSBill Taylor static int
482*9e39c5baSBill Taylor tavor_ioctl_flash_erase(tavor_state_t *state, dev_t dev, intptr_t arg, int mode)
483*9e39c5baSBill Taylor {
484*9e39c5baSBill Taylor 	tavor_flash_ioctl_t	ioctl_info;
485*9e39c5baSBill Taylor 	int status = 0;
486*9e39c5baSBill Taylor 
487*9e39c5baSBill Taylor 	TAVOR_TNF_ENTER(tavor_ioctl_flash_erase);
488*9e39c5baSBill Taylor 
489*9e39c5baSBill Taylor 	/*
490*9e39c5baSBill Taylor 	 * Check that flash init ioctl has been called first.  And check
491*9e39c5baSBill Taylor 	 * that the same dev_t that called init is the one calling erase now.
492*9e39c5baSBill Taylor 	 */
493*9e39c5baSBill Taylor 	mutex_enter(&state->ts_fw_flashlock);
494*9e39c5baSBill Taylor 	if ((state->ts_fw_flashdev != dev) ||
495*9e39c5baSBill Taylor 	    (state->ts_fw_flashstarted == 0)) {
496*9e39c5baSBill Taylor 		mutex_exit(&state->ts_fw_flashlock);
497*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_flash_bad_state, TAVOR_TNF_ERROR, "");
498*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_flash_erase);
499*9e39c5baSBill Taylor 		return (EIO);
500*9e39c5baSBill Taylor 	}
501*9e39c5baSBill Taylor 
502*9e39c5baSBill Taylor 	/* copy user struct to kernel */
503*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
504*9e39c5baSBill Taylor 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
505*9e39c5baSBill Taylor 		tavor_flash_ioctl32_t info32;
506*9e39c5baSBill Taylor 
507*9e39c5baSBill Taylor 		if (ddi_copyin((void *)arg, &info32,
508*9e39c5baSBill Taylor 		    sizeof (tavor_flash_ioctl32_t), mode) != 0) {
509*9e39c5baSBill Taylor 			mutex_exit(&state->ts_fw_flashlock);
510*9e39c5baSBill Taylor 			TNF_PROBE_0(tavor_ioctl_flash_read_copyin_fail,
511*9e39c5baSBill Taylor 			    TAVOR_TNF_ERROR, "");
512*9e39c5baSBill Taylor 			TAVOR_TNF_EXIT(tavor_ioctl_flash_erase);
513*9e39c5baSBill Taylor 			return (EFAULT);
514*9e39c5baSBill Taylor 		}
515*9e39c5baSBill Taylor 		ioctl_info.tf_type = info32.tf_type;
516*9e39c5baSBill Taylor 		ioctl_info.tf_sector_num = info32.tf_sector_num;
517*9e39c5baSBill Taylor 	} else
518*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
519*9e39c5baSBill Taylor 	if (ddi_copyin((void *)arg, &ioctl_info, sizeof (tavor_flash_ioctl_t),
520*9e39c5baSBill Taylor 	    mode) != 0) {
521*9e39c5baSBill Taylor 		mutex_exit(&state->ts_fw_flashlock);
522*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_flash_erase_ci_fail,
523*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
524*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_flash_erase);
525*9e39c5baSBill Taylor 		return (EFAULT);
526*9e39c5baSBill Taylor 	}
527*9e39c5baSBill Taylor 
528*9e39c5baSBill Taylor 	/*
529*9e39c5baSBill Taylor 	 * Determine type of ERASE ioctl
530*9e39c5baSBill Taylor 	 */
531*9e39c5baSBill Taylor 	switch (ioctl_info.tf_type) {
532*9e39c5baSBill Taylor 	case TAVOR_FLASH_ERASE_SECTOR:
533*9e39c5baSBill Taylor 		/* Check if sector num is too large for flash device */
534*9e39c5baSBill Taylor 		if (ioctl_info.tf_sector_num >=
535*9e39c5baSBill Taylor 		    (state->ts_fw_device_sz >> state->ts_fw_log_sector_sz)) {
536*9e39c5baSBill Taylor 			mutex_exit(&state->ts_fw_flashlock);
537*9e39c5baSBill Taylor 			TNF_PROBE_0(tavor_flash_erase_sector_num_too_large,
538*9e39c5baSBill Taylor 			    TAVOR_TNF_ERROR, "");
539*9e39c5baSBill Taylor 			TAVOR_TNF_EXIT(tavor_ioctl_flash_write);
540*9e39c5baSBill Taylor 			return (EFAULT);
541*9e39c5baSBill Taylor 		}
542*9e39c5baSBill Taylor 
543*9e39c5baSBill Taylor 		/* Perform Sector Erase */
544*9e39c5baSBill Taylor 		status = tavor_flash_erase_sector(state,
545*9e39c5baSBill Taylor 		    ioctl_info.tf_sector_num);
546*9e39c5baSBill Taylor 		break;
547*9e39c5baSBill Taylor 
548*9e39c5baSBill Taylor 	case TAVOR_FLASH_ERASE_CHIP:
549*9e39c5baSBill Taylor 		/* Perform Chip Erase */
550*9e39c5baSBill Taylor 		status = tavor_flash_erase_chip(state);
551*9e39c5baSBill Taylor 		break;
552*9e39c5baSBill Taylor 
553*9e39c5baSBill Taylor 	default:
554*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_flash_erase_invalid_type,
555*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
556*9e39c5baSBill Taylor 		status = EIO;
557*9e39c5baSBill Taylor 		break;
558*9e39c5baSBill Taylor 	}
559*9e39c5baSBill Taylor 
560*9e39c5baSBill Taylor 	mutex_exit(&state->ts_fw_flashlock);
561*9e39c5baSBill Taylor 	TAVOR_TNF_EXIT(tavor_ioctl_flash_erase);
562*9e39c5baSBill Taylor 	return (status);
563*9e39c5baSBill Taylor }
564*9e39c5baSBill Taylor 
565*9e39c5baSBill Taylor /*
566*9e39c5baSBill Taylor  * tavor_ioctl_flash_init()
567*9e39c5baSBill Taylor  */
568*9e39c5baSBill Taylor static int
569*9e39c5baSBill Taylor tavor_ioctl_flash_init(tavor_state_t *state, dev_t dev, intptr_t arg, int mode)
570*9e39c5baSBill Taylor {
571*9e39c5baSBill Taylor 	tavor_flash_init_ioctl_t init_info;
572*9e39c5baSBill Taylor 	int ret;
573*9e39c5baSBill Taylor 	int intel_xcmd = 0;
574*9e39c5baSBill Taylor 
575*9e39c5baSBill Taylor 	TAVOR_TNF_ENTER(tavor_ioctl_flash_init);
576*9e39c5baSBill Taylor 
577*9e39c5baSBill Taylor 	/*
578*9e39c5baSBill Taylor 	 * init cannot be called more than once.  If we have already init'd the
579*9e39c5baSBill Taylor 	 * flash, return directly.
580*9e39c5baSBill Taylor 	 */
581*9e39c5baSBill Taylor 	mutex_enter(&state->ts_fw_flashlock);
582*9e39c5baSBill Taylor 	if (state->ts_fw_flashstarted == 1) {
583*9e39c5baSBill Taylor 		mutex_exit(&state->ts_fw_flashlock);
584*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_flash_init_already_started,
585*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
586*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_flash_init);
587*9e39c5baSBill Taylor 		return (EIO);
588*9e39c5baSBill Taylor 	}
589*9e39c5baSBill Taylor 
590*9e39c5baSBill Taylor 	/* copyin the user struct to kernel */
591*9e39c5baSBill Taylor 	if (ddi_copyin((void *)arg, &init_info,
592*9e39c5baSBill Taylor 	    sizeof (tavor_flash_init_ioctl_t), mode) != 0) {
593*9e39c5baSBill Taylor 		mutex_exit(&state->ts_fw_flashlock);
594*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_flash_init_ioctl_copyin_fail,
595*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
596*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_flash_init);
597*9e39c5baSBill Taylor 		return (EFAULT);
598*9e39c5baSBill Taylor 	}
599*9e39c5baSBill Taylor 
600*9e39c5baSBill Taylor 	/* Init Flash */
601*9e39c5baSBill Taylor 	tavor_flash_init(state);
602*9e39c5baSBill Taylor 
603*9e39c5baSBill Taylor 	/* Read CFI info */
604*9e39c5baSBill Taylor 	tavor_flash_cfi_init(state, &init_info.tf_cfi_info[0], &intel_xcmd);
605*9e39c5baSBill Taylor 
606*9e39c5baSBill Taylor 	/*
607*9e39c5baSBill Taylor 	 * Return error if the command set is unknown.
608*9e39c5baSBill Taylor 	 */
609*9e39c5baSBill Taylor 	if (state->ts_fw_cmdset == TAVOR_FLASH_UNKNOWN_CMDSET) {
610*9e39c5baSBill Taylor 		mutex_exit(&state->ts_fw_flashlock);
611*9e39c5baSBill Taylor 		TNF_PROBE_1(tavor_ioctl_flash_init_cmdset_fail,
612*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "", tnf_string, errmsg,
613*9e39c5baSBill Taylor 		    "UNKNOWN flash command set");
614*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_flash_init);
615*9e39c5baSBill Taylor 		return (EFAULT);
616*9e39c5baSBill Taylor 	}
617*9e39c5baSBill Taylor 
618*9e39c5baSBill Taylor 	/* Read HWREV - least significant 8 bits is revision ID */
619*9e39c5baSBill Taylor 	init_info.tf_hwrev = pci_config_get32(state->ts_pci_cfghdl,
620*9e39c5baSBill Taylor 	    TAVOR_HW_FLASH_CFG_HWREV) & 0xFF;
621*9e39c5baSBill Taylor 
622*9e39c5baSBill Taylor 	/* Fill in the firmwate revision numbers */
623*9e39c5baSBill Taylor 	init_info.tf_fwrev.tfi_maj	= state->ts_fw.fw_rev_major;
624*9e39c5baSBill Taylor 	init_info.tf_fwrev.tfi_min	= state->ts_fw.fw_rev_minor;
625*9e39c5baSBill Taylor 	init_info.tf_fwrev.tfi_sub	= state->ts_fw.fw_rev_subminor;
626*9e39c5baSBill Taylor 
627*9e39c5baSBill Taylor 	/* Alloc flash mem for one sector size */
628*9e39c5baSBill Taylor 	state->ts_fw_sector = (uint32_t *)kmem_zalloc(1 <<
629*9e39c5baSBill Taylor 	    state->ts_fw_log_sector_sz, KM_SLEEP);
630*9e39c5baSBill Taylor 
631*9e39c5baSBill Taylor 	/* Set HW part number and length */
632*9e39c5baSBill Taylor 	init_info.tf_pn_len = state->ts_hca_pn_len;
633*9e39c5baSBill Taylor 	if (state->ts_hca_pn_len != 0) {
634*9e39c5baSBill Taylor 		(void) memcpy(init_info.tf_hwpn, state->ts_hca_pn,
635*9e39c5baSBill Taylor 		    state->ts_hca_pn_len);
636*9e39c5baSBill Taylor 	}
637*9e39c5baSBill Taylor 
638*9e39c5baSBill Taylor 	/* Copy ioctl results back to userland */
639*9e39c5baSBill Taylor 	if (ddi_copyout(&init_info, (void *)arg,
640*9e39c5baSBill Taylor 	    sizeof (tavor_flash_init_ioctl_t), mode) != 0) {
641*9e39c5baSBill Taylor 
642*9e39c5baSBill Taylor 		tavor_ioctl_flash_cleanup_nolock(state);
643*9e39c5baSBill Taylor 
644*9e39c5baSBill Taylor 		mutex_exit(&state->ts_fw_flashlock);
645*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_flash_init_copyout_fail,
646*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
647*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_flash_init);
648*9e39c5baSBill Taylor 		return (EFAULT);
649*9e39c5baSBill Taylor 	}
650*9e39c5baSBill Taylor 
651*9e39c5baSBill Taylor 	/* Set flash state to started */
652*9e39c5baSBill Taylor 	state->ts_fw_flashstarted = 1;
653*9e39c5baSBill Taylor 	state->ts_fw_flashdev	  = dev;
654*9e39c5baSBill Taylor 
655*9e39c5baSBill Taylor 	mutex_exit(&state->ts_fw_flashlock);
656*9e39c5baSBill Taylor 
657*9e39c5baSBill Taylor 	/*
658*9e39c5baSBill Taylor 	 * If "flash init" is successful, add an "on close" callback to the
659*9e39c5baSBill Taylor 	 * current dev node to ensure that "flash fini" gets called later
660*9e39c5baSBill Taylor 	 * even if the userland process prematurely exits.
661*9e39c5baSBill Taylor 	 */
662*9e39c5baSBill Taylor 	ret = tavor_umap_db_set_onclose_cb(dev,
663*9e39c5baSBill Taylor 	    TAVOR_ONCLOSE_FLASH_INPROGRESS,
664*9e39c5baSBill Taylor 	    (void (*)(void *))tavor_ioctl_flash_cleanup, state);
665*9e39c5baSBill Taylor 	if (ret != DDI_SUCCESS) {
666*9e39c5baSBill Taylor 		(void) tavor_ioctl_flash_fini(state, dev);
667*9e39c5baSBill Taylor 
668*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_flash_init_set_cb_fail,
669*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
670*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_flash_init);
671*9e39c5baSBill Taylor 		return (EFAULT);
672*9e39c5baSBill Taylor 	}
673*9e39c5baSBill Taylor 
674*9e39c5baSBill Taylor 	TAVOR_TNF_EXIT(tavor_ioctl_flash_init);
675*9e39c5baSBill Taylor 	return (0);
676*9e39c5baSBill Taylor }
677*9e39c5baSBill Taylor 
678*9e39c5baSBill Taylor /*
679*9e39c5baSBill Taylor  * tavor_ioctl_flash_fini()
680*9e39c5baSBill Taylor  */
681*9e39c5baSBill Taylor static int
682*9e39c5baSBill Taylor tavor_ioctl_flash_fini(tavor_state_t *state, dev_t dev)
683*9e39c5baSBill Taylor {
684*9e39c5baSBill Taylor 	int ret;
685*9e39c5baSBill Taylor 
686*9e39c5baSBill Taylor 	TAVOR_TNF_ENTER(tavor_ioctl_flash_fini);
687*9e39c5baSBill Taylor 
688*9e39c5baSBill Taylor 	/*
689*9e39c5baSBill Taylor 	 * Check that flash init ioctl has been called first.  And check
690*9e39c5baSBill Taylor 	 * that the same dev_t that called init is the one calling fini now.
691*9e39c5baSBill Taylor 	 */
692*9e39c5baSBill Taylor 	mutex_enter(&state->ts_fw_flashlock);
693*9e39c5baSBill Taylor 	if ((state->ts_fw_flashdev != dev) ||
694*9e39c5baSBill Taylor 	    (state->ts_fw_flashstarted == 0)) {
695*9e39c5baSBill Taylor 		mutex_exit(&state->ts_fw_flashlock);
696*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_flash_bad_state, TAVOR_TNF_ERROR, "");
697*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_flash_fini);
698*9e39c5baSBill Taylor 		return (EIO);
699*9e39c5baSBill Taylor 	}
700*9e39c5baSBill Taylor 
701*9e39c5baSBill Taylor 	tavor_ioctl_flash_cleanup_nolock(state);
702*9e39c5baSBill Taylor 
703*9e39c5baSBill Taylor 	mutex_exit(&state->ts_fw_flashlock);
704*9e39c5baSBill Taylor 
705*9e39c5baSBill Taylor 	/*
706*9e39c5baSBill Taylor 	 * If "flash fini" is successful, remove the "on close" callback
707*9e39c5baSBill Taylor 	 * that was setup during "flash init".
708*9e39c5baSBill Taylor 	 */
709*9e39c5baSBill Taylor 	ret = tavor_umap_db_clear_onclose_cb(dev,
710*9e39c5baSBill Taylor 	    TAVOR_ONCLOSE_FLASH_INPROGRESS);
711*9e39c5baSBill Taylor 	if (ret != DDI_SUCCESS) {
712*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_flash_fini_clear_cb_fail, TAVOR_TNF_ERROR,
713*9e39c5baSBill Taylor 		    "");
714*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_flash_fini);
715*9e39c5baSBill Taylor 		return (EFAULT);
716*9e39c5baSBill Taylor 	}
717*9e39c5baSBill Taylor 
718*9e39c5baSBill Taylor 	TAVOR_TNF_EXIT(tavor_ioctl_flash_fini);
719*9e39c5baSBill Taylor 	return (0);
720*9e39c5baSBill Taylor }
721*9e39c5baSBill Taylor 
722*9e39c5baSBill Taylor 
723*9e39c5baSBill Taylor /*
724*9e39c5baSBill Taylor  * tavor_ioctl_flash_cleanup()
725*9e39c5baSBill Taylor  */
726*9e39c5baSBill Taylor static void
727*9e39c5baSBill Taylor tavor_ioctl_flash_cleanup(tavor_state_t *state)
728*9e39c5baSBill Taylor {
729*9e39c5baSBill Taylor 	TAVOR_TNF_ENTER(tavor_ioctl_flash_cleanup);
730*9e39c5baSBill Taylor 
731*9e39c5baSBill Taylor 	mutex_enter(&state->ts_fw_flashlock);
732*9e39c5baSBill Taylor 	tavor_ioctl_flash_cleanup_nolock(state);
733*9e39c5baSBill Taylor 	mutex_exit(&state->ts_fw_flashlock);
734*9e39c5baSBill Taylor 
735*9e39c5baSBill Taylor 	TAVOR_TNF_EXIT(tavor_ioctl_flash_cleanup);
736*9e39c5baSBill Taylor }
737*9e39c5baSBill Taylor 
738*9e39c5baSBill Taylor 
739*9e39c5baSBill Taylor /*
740*9e39c5baSBill Taylor  * tavor_ioctl_flash_cleanup_nolock()
741*9e39c5baSBill Taylor  */
742*9e39c5baSBill Taylor static void
743*9e39c5baSBill Taylor tavor_ioctl_flash_cleanup_nolock(tavor_state_t *state)
744*9e39c5baSBill Taylor {
745*9e39c5baSBill Taylor 	TAVOR_TNF_ENTER(tavor_ioctl_flash_cleanup_nolock);
746*9e39c5baSBill Taylor 
747*9e39c5baSBill Taylor 	ASSERT(MUTEX_HELD(&state->ts_fw_flashlock));
748*9e39c5baSBill Taylor 
749*9e39c5baSBill Taylor 	/* free flash mem */
750*9e39c5baSBill Taylor 	kmem_free(state->ts_fw_sector, 1 << state->ts_fw_log_sector_sz);
751*9e39c5baSBill Taylor 
752*9e39c5baSBill Taylor 	/* Fini the Flash */
753*9e39c5baSBill Taylor 	tavor_flash_fini(state);
754*9e39c5baSBill Taylor 
755*9e39c5baSBill Taylor 	/* Set flash state to fini */
756*9e39c5baSBill Taylor 	state->ts_fw_flashstarted = 0;
757*9e39c5baSBill Taylor 	state->ts_fw_flashdev	  = 0;
758*9e39c5baSBill Taylor 
759*9e39c5baSBill Taylor 	TAVOR_TNF_EXIT(tavor_ioctl_flash_cleanup_nolock);
760*9e39c5baSBill Taylor }
761*9e39c5baSBill Taylor 
762*9e39c5baSBill Taylor 
763*9e39c5baSBill Taylor /*
764*9e39c5baSBill Taylor  * tavor_ioctl_info()
765*9e39c5baSBill Taylor  */
766*9e39c5baSBill Taylor static int
767*9e39c5baSBill Taylor tavor_ioctl_info(tavor_state_t *state, dev_t dev, intptr_t arg, int mode)
768*9e39c5baSBill Taylor {
769*9e39c5baSBill Taylor 	tavor_info_ioctl_t	 info;
770*9e39c5baSBill Taylor 	tavor_flash_init_ioctl_t init_info;
771*9e39c5baSBill Taylor 
772*9e39c5baSBill Taylor 	TAVOR_TNF_ENTER(tavor_ioctl_info);
773*9e39c5baSBill Taylor 
774*9e39c5baSBill Taylor 	/*
775*9e39c5baSBill Taylor 	 * Access to Tavor VTS ioctls is not allowed in "maintenance mode".
776*9e39c5baSBill Taylor 	 */
777*9e39c5baSBill Taylor 	if (state->ts_operational_mode == TAVOR_MAINTENANCE_MODE) {
778*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_info_maintenance_mode_fail,
779*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
780*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_info);
781*9e39c5baSBill Taylor 		return (EFAULT);
782*9e39c5baSBill Taylor 	}
783*9e39c5baSBill Taylor 
784*9e39c5baSBill Taylor 	/* copyin the user struct to kernel */
785*9e39c5baSBill Taylor 	if (ddi_copyin((void *)arg, &info, sizeof (tavor_info_ioctl_t),
786*9e39c5baSBill Taylor 	    mode) != 0) {
787*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_info_copyin_fail, TAVOR_TNF_ERROR, "");
788*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_info);
789*9e39c5baSBill Taylor 		return (EFAULT);
790*9e39c5baSBill Taylor 	}
791*9e39c5baSBill Taylor 
792*9e39c5baSBill Taylor 	/*
793*9e39c5baSBill Taylor 	 * Check ioctl revision
794*9e39c5baSBill Taylor 	 */
795*9e39c5baSBill Taylor 	if (info.ti_revision != TAVOR_VTS_IOCTL_REVISION) {
796*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_info_bad_rev, TAVOR_TNF_ERROR, "");
797*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_info);
798*9e39c5baSBill Taylor 		return (EINVAL);
799*9e39c5baSBill Taylor 	}
800*9e39c5baSBill Taylor 
801*9e39c5baSBill Taylor 	/*
802*9e39c5baSBill Taylor 	 * If the 'fw_device_sz' has not been initialized yet, we initialize it
803*9e39c5baSBill Taylor 	 * here.  This is done by leveraging the
804*9e39c5baSBill Taylor 	 * tavor_ioctl_flash_init()/fini() calls.  We also hold our own mutex
805*9e39c5baSBill Taylor 	 * around this operation in case we have multiple VTS threads in
806*9e39c5baSBill Taylor 	 * process at the same time.
807*9e39c5baSBill Taylor 	 */
808*9e39c5baSBill Taylor 	mutex_enter(&state->ts_info_lock);
809*9e39c5baSBill Taylor 	if (state->ts_fw_device_sz == 0) {
810*9e39c5baSBill Taylor 		if (tavor_ioctl_flash_init(state, dev, (intptr_t)&init_info,
811*9e39c5baSBill Taylor 		    (FKIOCTL | mode)) != 0) {
812*9e39c5baSBill Taylor 			mutex_exit(&state->ts_info_lock);
813*9e39c5baSBill Taylor 			TNF_PROBE_0(tavor_ioctl_info_flash_init_fail,
814*9e39c5baSBill Taylor 			    TAVOR_TNF_ERROR, "");
815*9e39c5baSBill Taylor 			TAVOR_TNF_EXIT(tavor_ioctl_info);
816*9e39c5baSBill Taylor 			return (EFAULT);
817*9e39c5baSBill Taylor 		}
818*9e39c5baSBill Taylor 		(void) tavor_ioctl_flash_fini(state, dev);
819*9e39c5baSBill Taylor 	}
820*9e39c5baSBill Taylor 	mutex_exit(&state->ts_info_lock);
821*9e39c5baSBill Taylor 
822*9e39c5baSBill Taylor 	info.ti_hw_rev		 = state->ts_adapter.rev_id;
823*9e39c5baSBill Taylor 	info.ti_flash_sz	 = state->ts_fw_device_sz;
824*9e39c5baSBill Taylor 	info.ti_fw_rev.tfi_maj	 = state->ts_fw.fw_rev_major;
825*9e39c5baSBill Taylor 	info.ti_fw_rev.tfi_min	 = state->ts_fw.fw_rev_minor;
826*9e39c5baSBill Taylor 	info.ti_fw_rev.tfi_sub	 = state->ts_fw.fw_rev_subminor;
827*9e39c5baSBill Taylor 	info.ti_mem_start_offset = 0;
828*9e39c5baSBill Taylor 	info.ti_mem_end_offset	 = state->ts_ddr.ddr_endaddr -
829*9e39c5baSBill Taylor 	    state->ts_ddr.ddr_baseaddr;
830*9e39c5baSBill Taylor 
831*9e39c5baSBill Taylor 	/* Copy ioctl results back to user struct */
832*9e39c5baSBill Taylor 	if (ddi_copyout(&info, (void *)arg, sizeof (tavor_info_ioctl_t),
833*9e39c5baSBill Taylor 	    mode) != 0) {
834*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_info_copyout_fail, TAVOR_TNF_ERROR, "");
835*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_info);
836*9e39c5baSBill Taylor 		return (EFAULT);
837*9e39c5baSBill Taylor 	}
838*9e39c5baSBill Taylor 
839*9e39c5baSBill Taylor 	TAVOR_TNF_EXIT(tavor_ioctl_info);
840*9e39c5baSBill Taylor 	return (0);
841*9e39c5baSBill Taylor }
842*9e39c5baSBill Taylor 
843*9e39c5baSBill Taylor /*
844*9e39c5baSBill Taylor  * tavor_ioctl_ports()
845*9e39c5baSBill Taylor  */
846*9e39c5baSBill Taylor static int
847*9e39c5baSBill Taylor tavor_ioctl_ports(tavor_state_t *state, intptr_t arg, int mode)
848*9e39c5baSBill Taylor {
849*9e39c5baSBill Taylor 	tavor_ports_ioctl_t	info;
850*9e39c5baSBill Taylor 	tavor_stat_port_ioctl_t	portstat;
851*9e39c5baSBill Taylor 	ibt_hca_portinfo_t	pi;
852*9e39c5baSBill Taylor 	uint_t			tbl_size;
853*9e39c5baSBill Taylor 	ib_gid_t		*sgid_tbl;
854*9e39c5baSBill Taylor 	ib_pkey_t		*pkey_tbl;
855*9e39c5baSBill Taylor 	int			i;
856*9e39c5baSBill Taylor 
857*9e39c5baSBill Taylor 	TAVOR_TNF_ENTER(tavor_ioctl_ports);
858*9e39c5baSBill Taylor 
859*9e39c5baSBill Taylor 	/*
860*9e39c5baSBill Taylor 	 * Access to Tavor VTS ioctls is not allowed in "maintenance mode".
861*9e39c5baSBill Taylor 	 */
862*9e39c5baSBill Taylor 	if (state->ts_operational_mode == TAVOR_MAINTENANCE_MODE) {
863*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_ports_maintenance_mode_fail,
864*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
865*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_ports);
866*9e39c5baSBill Taylor 		return (EFAULT);
867*9e39c5baSBill Taylor 	}
868*9e39c5baSBill Taylor 
869*9e39c5baSBill Taylor 	/* copyin the user struct to kernel */
870*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
871*9e39c5baSBill Taylor 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
872*9e39c5baSBill Taylor 		tavor_ports_ioctl32_t info32;
873*9e39c5baSBill Taylor 
874*9e39c5baSBill Taylor 		if (ddi_copyin((void *)arg, &info32,
875*9e39c5baSBill Taylor 		    sizeof (tavor_ports_ioctl32_t), mode) != 0) {
876*9e39c5baSBill Taylor 			TNF_PROBE_0(tavor_ioctl_ports_copyin_fail,
877*9e39c5baSBill Taylor 			    TAVOR_TNF_ERROR, "");
878*9e39c5baSBill Taylor 			TAVOR_TNF_EXIT(tavor_ioctl_ports);
879*9e39c5baSBill Taylor 			return (EFAULT);
880*9e39c5baSBill Taylor 		}
881*9e39c5baSBill Taylor 		info.tp_revision  = info32.tp_revision;
882*9e39c5baSBill Taylor 		info.tp_ports	  =
883*9e39c5baSBill Taylor 		    (tavor_stat_port_ioctl_t *)(uintptr_t)info32.tp_ports;
884*9e39c5baSBill Taylor 		info.tp_num_ports = info32.tp_num_ports;
885*9e39c5baSBill Taylor 
886*9e39c5baSBill Taylor 	} else
887*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
888*9e39c5baSBill Taylor 	if (ddi_copyin((void *)arg, &info, sizeof (tavor_ports_ioctl_t),
889*9e39c5baSBill Taylor 	    mode) != 0) {
890*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_ports_copyin_fail, TAVOR_TNF_ERROR, "");
891*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_ports);
892*9e39c5baSBill Taylor 		return (EFAULT);
893*9e39c5baSBill Taylor 	}
894*9e39c5baSBill Taylor 
895*9e39c5baSBill Taylor 	/*
896*9e39c5baSBill Taylor 	 * Check ioctl revision
897*9e39c5baSBill Taylor 	 */
898*9e39c5baSBill Taylor 	if (info.tp_revision != TAVOR_VTS_IOCTL_REVISION) {
899*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_ports_bad_rev, TAVOR_TNF_ERROR, "");
900*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_ports);
901*9e39c5baSBill Taylor 		return (EINVAL);
902*9e39c5baSBill Taylor 	}
903*9e39c5baSBill Taylor 
904*9e39c5baSBill Taylor 	/* Allocate space for temporary GID table/PKey table */
905*9e39c5baSBill Taylor 	tbl_size = (1 << state->ts_cfg_profile->cp_log_max_gidtbl);
906*9e39c5baSBill Taylor 	sgid_tbl = (ib_gid_t *)kmem_zalloc(tbl_size * sizeof (ib_gid_t),
907*9e39c5baSBill Taylor 	    KM_SLEEP);
908*9e39c5baSBill Taylor 	tbl_size = (1 << state->ts_cfg_profile->cp_log_max_pkeytbl);
909*9e39c5baSBill Taylor 	pkey_tbl = (ib_pkey_t *)kmem_zalloc(tbl_size * sizeof (ib_pkey_t),
910*9e39c5baSBill Taylor 	    KM_SLEEP);
911*9e39c5baSBill Taylor 
912*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*sgid_tbl, *pkey_tbl))
913*9e39c5baSBill Taylor 
914*9e39c5baSBill Taylor 	/*
915*9e39c5baSBill Taylor 	 * Setup the number of ports, then loop through all ports and
916*9e39c5baSBill Taylor 	 * query properties of each.
917*9e39c5baSBill Taylor 	 */
918*9e39c5baSBill Taylor 	info.tp_num_ports = (uint8_t)state->ts_cfg_profile->cp_num_ports;
919*9e39c5baSBill Taylor 	for (i = 0; i < info.tp_num_ports; i++) {
920*9e39c5baSBill Taylor 		/*
921*9e39c5baSBill Taylor 		 * Get portstate information from the device.  If
922*9e39c5baSBill Taylor 		 * tavor_port_query() fails, leave zeroes in user
923*9e39c5baSBill Taylor 		 * struct port entry and continue.
924*9e39c5baSBill Taylor 		 */
925*9e39c5baSBill Taylor 		bzero(&pi, sizeof (ibt_hca_portinfo_t));
926*9e39c5baSBill Taylor 		pi.p_sgid_tbl = sgid_tbl;
927*9e39c5baSBill Taylor 		pi.p_pkey_tbl = pkey_tbl;
928*9e39c5baSBill Taylor 		if (tavor_port_query(state, i + 1, &pi) != 0) {
929*9e39c5baSBill Taylor 			TNF_PROBE_0(tavor_ioctl_ports_query_failed,
930*9e39c5baSBill Taylor 			    TAVOR_TNF_ERROR, "");
931*9e39c5baSBill Taylor 		}
932*9e39c5baSBill Taylor 
933*9e39c5baSBill Taylor 		portstat.tsp_port_num	= pi.p_port_num;
934*9e39c5baSBill Taylor 		portstat.tsp_state	= pi.p_linkstate;
935*9e39c5baSBill Taylor 		portstat.tsp_guid	= pi.p_sgid_tbl[0].gid_guid;
936*9e39c5baSBill Taylor 
937*9e39c5baSBill Taylor 		/*
938*9e39c5baSBill Taylor 		 * Copy queried port results back to user struct.  If
939*9e39c5baSBill Taylor 		 * this fails, then break out of loop, attempt to copy
940*9e39c5baSBill Taylor 		 * out remaining info to user struct, and return (without
941*9e39c5baSBill Taylor 		 * error).
942*9e39c5baSBill Taylor 		 */
943*9e39c5baSBill Taylor 		if (ddi_copyout(&portstat,
944*9e39c5baSBill Taylor 		    &(((tavor_stat_port_ioctl_t *)info.tp_ports)[i]),
945*9e39c5baSBill Taylor 		    sizeof (tavor_stat_port_ioctl_t), mode) != 0) {
946*9e39c5baSBill Taylor 			break;
947*9e39c5baSBill Taylor 		}
948*9e39c5baSBill Taylor 	}
949*9e39c5baSBill Taylor 
950*9e39c5baSBill Taylor 	/* Free the temporary space used for GID table/PKey table */
951*9e39c5baSBill Taylor 	tbl_size = (1 << state->ts_cfg_profile->cp_log_max_gidtbl);
952*9e39c5baSBill Taylor 	kmem_free(sgid_tbl, tbl_size * sizeof (ib_gid_t));
953*9e39c5baSBill Taylor 	tbl_size = (1 << state->ts_cfg_profile->cp_log_max_pkeytbl);
954*9e39c5baSBill Taylor 	kmem_free(pkey_tbl, tbl_size * sizeof (ib_pkey_t));
955*9e39c5baSBill Taylor 
956*9e39c5baSBill Taylor 	/* Copy ioctl results back to user struct */
957*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
958*9e39c5baSBill Taylor 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
959*9e39c5baSBill Taylor 		tavor_ports_ioctl32_t info32;
960*9e39c5baSBill Taylor 
961*9e39c5baSBill Taylor 		info32.tp_revision  = info.tp_revision;
962*9e39c5baSBill Taylor 		info32.tp_ports	    = (caddr32_t)(uintptr_t)info.tp_ports;
963*9e39c5baSBill Taylor 		info32.tp_num_ports = info.tp_num_ports;
964*9e39c5baSBill Taylor 
965*9e39c5baSBill Taylor 		if (ddi_copyout(&info32, (void *)arg,
966*9e39c5baSBill Taylor 		    sizeof (tavor_ports_ioctl32_t), mode) != 0) {
967*9e39c5baSBill Taylor 			TNF_PROBE_0(tavor_ioctl_ports_copyout_fail,
968*9e39c5baSBill Taylor 			    TAVOR_TNF_ERROR, "");
969*9e39c5baSBill Taylor 			TAVOR_TNF_EXIT(tavor_ioctl_ports);
970*9e39c5baSBill Taylor 			return (EFAULT);
971*9e39c5baSBill Taylor 		}
972*9e39c5baSBill Taylor 	} else
973*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
974*9e39c5baSBill Taylor 	if (ddi_copyout(&info, (void *)arg, sizeof (tavor_ports_ioctl_t),
975*9e39c5baSBill Taylor 	    mode) != 0) {
976*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_ports_copyout_fail,
977*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
978*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_ports);
979*9e39c5baSBill Taylor 		return (EFAULT);
980*9e39c5baSBill Taylor 	}
981*9e39c5baSBill Taylor 
982*9e39c5baSBill Taylor 	TAVOR_TNF_EXIT(tavor_ioctl_ports);
983*9e39c5baSBill Taylor 	return (0);
984*9e39c5baSBill Taylor }
985*9e39c5baSBill Taylor 
986*9e39c5baSBill Taylor /*
987*9e39c5baSBill Taylor  * tavor_ioctl_loopback()
988*9e39c5baSBill Taylor  */
989*9e39c5baSBill Taylor static int
990*9e39c5baSBill Taylor tavor_ioctl_loopback(tavor_state_t *state, intptr_t arg, int mode)
991*9e39c5baSBill Taylor {
992*9e39c5baSBill Taylor 	tavor_loopback_ioctl_t	lb;
993*9e39c5baSBill Taylor 	tavor_loopback_state_t	lstate;
994*9e39c5baSBill Taylor 	ibt_hca_portinfo_t 	pi;
995*9e39c5baSBill Taylor 	uint_t			tbl_size, loopmax, max_usec;
996*9e39c5baSBill Taylor 	ib_gid_t		*sgid_tbl;
997*9e39c5baSBill Taylor 	ib_pkey_t		*pkey_tbl;
998*9e39c5baSBill Taylor 	int			j, iter, ret;
999*9e39c5baSBill Taylor 
1000*9e39c5baSBill Taylor 	TAVOR_TNF_ENTER(tavor_ioctl_loopback);
1001*9e39c5baSBill Taylor 
1002*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(lstate))
1003*9e39c5baSBill Taylor 
1004*9e39c5baSBill Taylor 	/*
1005*9e39c5baSBill Taylor 	 * Access to Tavor VTS ioctls is not allowed in "maintenance mode".
1006*9e39c5baSBill Taylor 	 */
1007*9e39c5baSBill Taylor 	if (state->ts_operational_mode == TAVOR_MAINTENANCE_MODE) {
1008*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_loopback_maintenance_mode_fail,
1009*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
1010*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1011*9e39c5baSBill Taylor 		return (EFAULT);
1012*9e39c5baSBill Taylor 	}
1013*9e39c5baSBill Taylor 
1014*9e39c5baSBill Taylor 	/* copyin the user struct to kernel */
1015*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
1016*9e39c5baSBill Taylor 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
1017*9e39c5baSBill Taylor 		tavor_loopback_ioctl32_t lb32;
1018*9e39c5baSBill Taylor 
1019*9e39c5baSBill Taylor 		if (ddi_copyin((void *)arg, &lb32,
1020*9e39c5baSBill Taylor 		    sizeof (tavor_loopback_ioctl32_t), mode) != 0) {
1021*9e39c5baSBill Taylor 			TNF_PROBE_0(tavor_ioctl_loopback_copyin_fail,
1022*9e39c5baSBill Taylor 			    TAVOR_TNF_ERROR, "");
1023*9e39c5baSBill Taylor 			TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1024*9e39c5baSBill Taylor 			return (EFAULT);
1025*9e39c5baSBill Taylor 		}
1026*9e39c5baSBill Taylor 		lb.tlb_revision	    = lb32.tlb_revision;
1027*9e39c5baSBill Taylor 		lb.tlb_send_buf	    = (caddr_t)(uintptr_t)lb32.tlb_send_buf;
1028*9e39c5baSBill Taylor 		lb.tlb_fail_buf	    = (caddr_t)(uintptr_t)lb32.tlb_fail_buf;
1029*9e39c5baSBill Taylor 		lb.tlb_buf_sz	    = lb32.tlb_buf_sz;
1030*9e39c5baSBill Taylor 		lb.tlb_num_iter	    = lb32.tlb_num_iter;
1031*9e39c5baSBill Taylor 		lb.tlb_pass_done    = lb32.tlb_pass_done;
1032*9e39c5baSBill Taylor 		lb.tlb_timeout	    = lb32.tlb_timeout;
1033*9e39c5baSBill Taylor 		lb.tlb_error_type   = lb32.tlb_error_type;
1034*9e39c5baSBill Taylor 		lb.tlb_port_num	    = lb32.tlb_port_num;
1035*9e39c5baSBill Taylor 		lb.tlb_num_retry    = lb32.tlb_num_retry;
1036*9e39c5baSBill Taylor 	} else
1037*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
1038*9e39c5baSBill Taylor 	if (ddi_copyin((void *)arg, &lb, sizeof (tavor_loopback_ioctl_t),
1039*9e39c5baSBill Taylor 	    mode) != 0) {
1040*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_loopback_copyin_fail,
1041*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
1042*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1043*9e39c5baSBill Taylor 		return (EFAULT);
1044*9e39c5baSBill Taylor 	}
1045*9e39c5baSBill Taylor 
1046*9e39c5baSBill Taylor 	/* Initialize the internal loopback test state structure */
1047*9e39c5baSBill Taylor 	bzero(&lstate, sizeof (tavor_loopback_state_t));
1048*9e39c5baSBill Taylor 
1049*9e39c5baSBill Taylor 	/*
1050*9e39c5baSBill Taylor 	 * Check ioctl revision
1051*9e39c5baSBill Taylor 	 */
1052*9e39c5baSBill Taylor 	if (lb.tlb_revision != TAVOR_VTS_IOCTL_REVISION) {
1053*9e39c5baSBill Taylor 		lb.tlb_error_type = TAVOR_LOOPBACK_INVALID_REVISION;
1054*9e39c5baSBill Taylor 		(void) tavor_loopback_copyout(&lb, arg, mode);
1055*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_loopback_bad_rev,
1056*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
1057*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1058*9e39c5baSBill Taylor 		return (EINVAL);
1059*9e39c5baSBill Taylor 	}
1060*9e39c5baSBill Taylor 
1061*9e39c5baSBill Taylor 	/* Validate that specified port number is legal */
1062*9e39c5baSBill Taylor 	if (!tavor_portnum_is_valid(state, lb.tlb_port_num)) {
1063*9e39c5baSBill Taylor 		lb.tlb_error_type = TAVOR_LOOPBACK_INVALID_PORT;
1064*9e39c5baSBill Taylor 		(void) tavor_loopback_copyout(&lb, arg, mode);
1065*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_loopback_inv_port,
1066*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
1067*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1068*9e39c5baSBill Taylor 		return (EINVAL);
1069*9e39c5baSBill Taylor 	}
1070*9e39c5baSBill Taylor 
1071*9e39c5baSBill Taylor 	/* Allocate space for temporary GID table/PKey table */
1072*9e39c5baSBill Taylor 	tbl_size = (1 << state->ts_cfg_profile->cp_log_max_gidtbl);
1073*9e39c5baSBill Taylor 	sgid_tbl = (ib_gid_t *)kmem_zalloc(tbl_size * sizeof (ib_gid_t),
1074*9e39c5baSBill Taylor 	    KM_SLEEP);
1075*9e39c5baSBill Taylor 	tbl_size = (1 << state->ts_cfg_profile->cp_log_max_pkeytbl);
1076*9e39c5baSBill Taylor 	pkey_tbl = (ib_pkey_t *)kmem_zalloc(tbl_size * sizeof (ib_pkey_t),
1077*9e39c5baSBill Taylor 	    KM_SLEEP);
1078*9e39c5baSBill Taylor 
1079*9e39c5baSBill Taylor 	/*
1080*9e39c5baSBill Taylor 	 * Get portstate information from specific port on device
1081*9e39c5baSBill Taylor 	 */
1082*9e39c5baSBill Taylor 	bzero(&pi, sizeof (ibt_hca_portinfo_t));
1083*9e39c5baSBill Taylor 	pi.p_sgid_tbl = sgid_tbl;
1084*9e39c5baSBill Taylor 	pi.p_pkey_tbl = pkey_tbl;
1085*9e39c5baSBill Taylor 	if (tavor_port_query(state, lb.tlb_port_num, &pi) != 0) {
1086*9e39c5baSBill Taylor 		/* Free the temporary space used for GID table/PKey table */
1087*9e39c5baSBill Taylor 		tbl_size = (1 << state->ts_cfg_profile->cp_log_max_gidtbl);
1088*9e39c5baSBill Taylor 		kmem_free(sgid_tbl, tbl_size * sizeof (ib_gid_t));
1089*9e39c5baSBill Taylor 		tbl_size = (1 << state->ts_cfg_profile->cp_log_max_pkeytbl);
1090*9e39c5baSBill Taylor 		kmem_free(pkey_tbl, tbl_size * sizeof (ib_pkey_t));
1091*9e39c5baSBill Taylor 
1092*9e39c5baSBill Taylor 		lb.tlb_error_type = TAVOR_LOOPBACK_INVALID_PORT;
1093*9e39c5baSBill Taylor 		(void) tavor_loopback_copyout(&lb, arg, mode);
1094*9e39c5baSBill Taylor 		tavor_loopback_free_state(&lstate);
1095*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_loopback_bad_port,
1096*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
1097*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1098*9e39c5baSBill Taylor 		return (EINVAL);
1099*9e39c5baSBill Taylor 	}
1100*9e39c5baSBill Taylor 
1101*9e39c5baSBill Taylor 	lstate.tls_port	   = pi.p_port_num;
1102*9e39c5baSBill Taylor 	lstate.tls_lid	   = pi.p_base_lid;
1103*9e39c5baSBill Taylor 	lstate.tls_pkey_ix = (pi.p_linkstate == TAVOR_PORT_LINK_ACTIVE) ? 1 : 0;
1104*9e39c5baSBill Taylor 	lstate.tls_state   = state;
1105*9e39c5baSBill Taylor 	lstate.tls_retry   = lb.tlb_num_retry;
1106*9e39c5baSBill Taylor 
1107*9e39c5baSBill Taylor 	/* Free the temporary space used for GID table/PKey table */
1108*9e39c5baSBill Taylor 	tbl_size = (1 << state->ts_cfg_profile->cp_log_max_gidtbl);
1109*9e39c5baSBill Taylor 	kmem_free(sgid_tbl, tbl_size * sizeof (ib_gid_t));
1110*9e39c5baSBill Taylor 	tbl_size = (1 << state->ts_cfg_profile->cp_log_max_pkeytbl);
1111*9e39c5baSBill Taylor 	kmem_free(pkey_tbl, tbl_size * sizeof (ib_pkey_t));
1112*9e39c5baSBill Taylor 
1113*9e39c5baSBill Taylor 	/*
1114*9e39c5baSBill Taylor 	 * Compute the timeout duration in usec per the formula:
1115*9e39c5baSBill Taylor 	 *    to_usec_per_retry = 4.096us * (2 ^ supplied_timeout)
1116*9e39c5baSBill Taylor 	 * (plus we add a little fudge-factor here too)
1117*9e39c5baSBill Taylor 	 */
1118*9e39c5baSBill Taylor 	lstate.tls_timeout = lb.tlb_timeout;
1119*9e39c5baSBill Taylor 	max_usec = (4096 * (1 << lstate.tls_timeout)) / 1000;
1120*9e39c5baSBill Taylor 	max_usec = max_usec * (lstate.tls_retry + 1);
1121*9e39c5baSBill Taylor 	max_usec = max_usec + 10000;
1122*9e39c5baSBill Taylor 
1123*9e39c5baSBill Taylor 	/*
1124*9e39c5baSBill Taylor 	 * Determine how many times we should loop before declaring a
1125*9e39c5baSBill Taylor 	 * timeout failure.
1126*9e39c5baSBill Taylor 	 */
1127*9e39c5baSBill Taylor 	loopmax	 = max_usec/TAVOR_VTS_LOOPBACK_MIN_WAIT_DUR;
1128*9e39c5baSBill Taylor 	if ((max_usec % TAVOR_VTS_LOOPBACK_MIN_WAIT_DUR) != 0) {
1129*9e39c5baSBill Taylor 		loopmax++;
1130*9e39c5baSBill Taylor 	}
1131*9e39c5baSBill Taylor 
1132*9e39c5baSBill Taylor 	if (lb.tlb_send_buf == NULL || lb.tlb_buf_sz == 0) {
1133*9e39c5baSBill Taylor 		lb.tlb_error_type = TAVOR_LOOPBACK_SEND_BUF_INVALID;
1134*9e39c5baSBill Taylor 		(void) tavor_loopback_copyout(&lb, arg, mode);
1135*9e39c5baSBill Taylor 		tavor_loopback_free_state(&lstate);
1136*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_loopback_buf_null,
1137*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
1138*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1139*9e39c5baSBill Taylor 		return (EINVAL);
1140*9e39c5baSBill Taylor 	}
1141*9e39c5baSBill Taylor 
1142*9e39c5baSBill Taylor 	/* Allocate protection domain (PD) */
1143*9e39c5baSBill Taylor 	if (tavor_loopback_init(state, &lstate) != 0) {
1144*9e39c5baSBill Taylor 		lb.tlb_error_type = lstate.tls_err;
1145*9e39c5baSBill Taylor 		(void) tavor_loopback_copyout(&lb, arg, mode);
1146*9e39c5baSBill Taylor 		tavor_loopback_free_state(&lstate);
1147*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1148*9e39c5baSBill Taylor 		return (EFAULT);
1149*9e39c5baSBill Taylor 	}
1150*9e39c5baSBill Taylor 
1151*9e39c5baSBill Taylor 	/* Allocate and register a TX buffer */
1152*9e39c5baSBill Taylor 	if (tavor_loopback_alloc_mem(&lstate, &lstate.tls_tx,
1153*9e39c5baSBill Taylor 	    lb.tlb_buf_sz) != 0) {
1154*9e39c5baSBill Taylor 		lb.tlb_error_type =
1155*9e39c5baSBill Taylor 		    TAVOR_LOOPBACK_SEND_BUF_MEM_REGION_ALLOC_FAIL;
1156*9e39c5baSBill Taylor 		(void) tavor_loopback_copyout(&lb, arg, mode);
1157*9e39c5baSBill Taylor 		tavor_loopback_free_state(&lstate);
1158*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_loopback_txbuf_alloc_fail,
1159*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
1160*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1161*9e39c5baSBill Taylor 		return (EFAULT);
1162*9e39c5baSBill Taylor 	}
1163*9e39c5baSBill Taylor 
1164*9e39c5baSBill Taylor 	/* Allocate and register an RX buffer */
1165*9e39c5baSBill Taylor 	if (tavor_loopback_alloc_mem(&lstate, &lstate.tls_rx,
1166*9e39c5baSBill Taylor 	    lb.tlb_buf_sz) != 0) {
1167*9e39c5baSBill Taylor 		lb.tlb_error_type =
1168*9e39c5baSBill Taylor 		    TAVOR_LOOPBACK_RECV_BUF_MEM_REGION_ALLOC_FAIL;
1169*9e39c5baSBill Taylor 		(void) tavor_loopback_copyout(&lb, arg, mode);
1170*9e39c5baSBill Taylor 		tavor_loopback_free_state(&lstate);
1171*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_loopback_rxbuf_alloc_fail,
1172*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
1173*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1174*9e39c5baSBill Taylor 		return (EFAULT);
1175*9e39c5baSBill Taylor 	}
1176*9e39c5baSBill Taylor 
1177*9e39c5baSBill Taylor 	/* Copy in the transmit buffer data */
1178*9e39c5baSBill Taylor 	if (ddi_copyin((void *)lb.tlb_send_buf, lstate.tls_tx.tlc_buf,
1179*9e39c5baSBill Taylor 	    lb.tlb_buf_sz, mode) != 0) {
1180*9e39c5baSBill Taylor 		lb.tlb_error_type = TAVOR_LOOPBACK_SEND_BUF_COPY_FAIL;
1181*9e39c5baSBill Taylor 		(void) tavor_loopback_copyout(&lb, arg, mode);
1182*9e39c5baSBill Taylor 		tavor_loopback_free_state(&lstate);
1183*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_loopback_tx_copyin_fail,
1184*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
1185*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1186*9e39c5baSBill Taylor 		return (EFAULT);
1187*9e39c5baSBill Taylor 	}
1188*9e39c5baSBill Taylor 
1189*9e39c5baSBill Taylor 	/* Allocate the transmit QP and CQs */
1190*9e39c5baSBill Taylor 	lstate.tls_err = TAVOR_LOOPBACK_XMIT_SEND_CQ_ALLOC_FAIL;
1191*9e39c5baSBill Taylor 	if (tavor_loopback_alloc_qps(&lstate, &lstate.tls_tx) != 0) {
1192*9e39c5baSBill Taylor 		lb.tlb_error_type = lstate.tls_err;
1193*9e39c5baSBill Taylor 		(void) tavor_loopback_copyout(&lb, arg, mode);
1194*9e39c5baSBill Taylor 		tavor_loopback_free_state(&lstate);
1195*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_loopback_txqp_alloc_fail,
1196*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
1197*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1198*9e39c5baSBill Taylor 		return (EFAULT);
1199*9e39c5baSBill Taylor 	}
1200*9e39c5baSBill Taylor 
1201*9e39c5baSBill Taylor 	/* Allocate the receive QP and CQs */
1202*9e39c5baSBill Taylor 	lstate.tls_err = TAVOR_LOOPBACK_RECV_SEND_CQ_ALLOC_FAIL;
1203*9e39c5baSBill Taylor 	if (tavor_loopback_alloc_qps(&lstate, &lstate.tls_rx) != 0) {
1204*9e39c5baSBill Taylor 		lb.tlb_error_type = lstate.tls_err;
1205*9e39c5baSBill Taylor 		(void) tavor_loopback_copyout(&lb, arg, mode);
1206*9e39c5baSBill Taylor 		tavor_loopback_free_state(&lstate);
1207*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_loopback_rxqp_alloc_fail,
1208*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
1209*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1210*9e39c5baSBill Taylor 		return (EFAULT);
1211*9e39c5baSBill Taylor 	}
1212*9e39c5baSBill Taylor 
1213*9e39c5baSBill Taylor 	/* Activate the TX QP (connect to RX QP) */
1214*9e39c5baSBill Taylor 	lstate.tls_err = TAVOR_LOOPBACK_XMIT_QP_INIT_FAIL;
1215*9e39c5baSBill Taylor 	if (tavor_loopback_modify_qp(&lstate, &lstate.tls_tx,
1216*9e39c5baSBill Taylor 	    lstate.tls_rx.tlc_qp_num) != 0) {
1217*9e39c5baSBill Taylor 		lb.tlb_error_type = lstate.tls_err;
1218*9e39c5baSBill Taylor 		(void) tavor_loopback_copyout(&lb, arg, mode);
1219*9e39c5baSBill Taylor 		tavor_loopback_free_state(&lstate);
1220*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_loopback_txqp_init_fail,
1221*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
1222*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1223*9e39c5baSBill Taylor 		return (EFAULT);
1224*9e39c5baSBill Taylor 	}
1225*9e39c5baSBill Taylor 
1226*9e39c5baSBill Taylor 	/* Activate the RX QP (connect to TX QP) */
1227*9e39c5baSBill Taylor 	lstate.tls_err = TAVOR_LOOPBACK_RECV_QP_INIT_FAIL;
1228*9e39c5baSBill Taylor 	if (tavor_loopback_modify_qp(&lstate, &lstate.tls_rx,
1229*9e39c5baSBill Taylor 	    lstate.tls_tx.tlc_qp_num) != 0) {
1230*9e39c5baSBill Taylor 		lb.tlb_error_type = lstate.tls_err;
1231*9e39c5baSBill Taylor 		(void) tavor_loopback_copyout(&lb, arg, mode);
1232*9e39c5baSBill Taylor 		tavor_loopback_free_state(&lstate);
1233*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_loopback_rxqp_init_fail,
1234*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
1235*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1236*9e39c5baSBill Taylor 		return (EFAULT);
1237*9e39c5baSBill Taylor 	}
1238*9e39c5baSBill Taylor 
1239*9e39c5baSBill Taylor 	/* Run the loopback test (for specified number of iterations) */
1240*9e39c5baSBill Taylor 	lb.tlb_pass_done = 0;
1241*9e39c5baSBill Taylor 	for (iter = 0; iter < lb.tlb_num_iter; iter++) {
1242*9e39c5baSBill Taylor 		lstate.tls_err = 0;
1243*9e39c5baSBill Taylor 		bzero(lstate.tls_rx.tlc_buf, lb.tlb_buf_sz);
1244*9e39c5baSBill Taylor 
1245*9e39c5baSBill Taylor 		/* Post RDMA Write work request */
1246*9e39c5baSBill Taylor 		if (tavor_loopback_post_send(&lstate, &lstate.tls_tx,
1247*9e39c5baSBill Taylor 		    &lstate.tls_rx) != IBT_SUCCESS) {
1248*9e39c5baSBill Taylor 			lb.tlb_error_type = TAVOR_LOOPBACK_WQE_POST_FAIL;
1249*9e39c5baSBill Taylor 			(void) tavor_loopback_copyout(&lb, arg, mode);
1250*9e39c5baSBill Taylor 			tavor_loopback_free_state(&lstate);
1251*9e39c5baSBill Taylor 			TNF_PROBE_0(tavor_ioctl_loopback_wqe_post_fail,
1252*9e39c5baSBill Taylor 			    TAVOR_TNF_ERROR, "");
1253*9e39c5baSBill Taylor 			TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1254*9e39c5baSBill Taylor 			return (EFAULT);
1255*9e39c5baSBill Taylor 		}
1256*9e39c5baSBill Taylor 
1257*9e39c5baSBill Taylor 		/* Poll the TX CQ for a completion every few ticks */
1258*9e39c5baSBill Taylor 		for (j = 0; j < loopmax; j++) {
1259*9e39c5baSBill Taylor 			delay(drv_usectohz(TAVOR_VTS_LOOPBACK_MIN_WAIT_DUR));
1260*9e39c5baSBill Taylor 
1261*9e39c5baSBill Taylor 			ret = tavor_loopback_poll_cq(&lstate, &lstate.tls_tx);
1262*9e39c5baSBill Taylor 			if (((ret != IBT_SUCCESS) && (ret != IBT_CQ_EMPTY)) ||
1263*9e39c5baSBill Taylor 			    ((ret == IBT_CQ_EMPTY) && (j == loopmax - 1))) {
1264*9e39c5baSBill Taylor 				lb.tlb_error_type = TAVOR_LOOPBACK_CQ_POLL_FAIL;
1265*9e39c5baSBill Taylor 				if (ddi_copyout(lstate.tls_rx.tlc_buf,
1266*9e39c5baSBill Taylor 				    lb.tlb_fail_buf, lstate.tls_tx.tlc_buf_sz,
1267*9e39c5baSBill Taylor 				    mode) != 0) {
1268*9e39c5baSBill Taylor 					TNF_PROBE_0(
1269*9e39c5baSBill Taylor 					    tavor_ioctl_loopback_xfer_co_fail,
1270*9e39c5baSBill Taylor 					    TAVOR_TNF_ERROR, "");
1271*9e39c5baSBill Taylor 					TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1272*9e39c5baSBill Taylor 					return (EFAULT);
1273*9e39c5baSBill Taylor 				}
1274*9e39c5baSBill Taylor 				(void) tavor_loopback_copyout(&lb, arg, mode);
1275*9e39c5baSBill Taylor 				tavor_loopback_free_state(&lstate);
1276*9e39c5baSBill Taylor 				TNF_PROBE_0(tavor_ioctl_loopback_xfer_fail,
1277*9e39c5baSBill Taylor 				    TAVOR_TNF_ERROR, "");
1278*9e39c5baSBill Taylor 				TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1279*9e39c5baSBill Taylor 				return (EFAULT);
1280*9e39c5baSBill Taylor 			} else if (ret == IBT_CQ_EMPTY) {
1281*9e39c5baSBill Taylor 				continue;
1282*9e39c5baSBill Taylor 			}
1283*9e39c5baSBill Taylor 
1284*9e39c5baSBill Taylor 			/* Compare the data buffers */
1285*9e39c5baSBill Taylor 			if (bcmp(lstate.tls_tx.tlc_buf, lstate.tls_rx.tlc_buf,
1286*9e39c5baSBill Taylor 			    lb.tlb_buf_sz) == 0) {
1287*9e39c5baSBill Taylor 				break;
1288*9e39c5baSBill Taylor 			} else {
1289*9e39c5baSBill Taylor 				lb.tlb_error_type =
1290*9e39c5baSBill Taylor 				    TAVOR_LOOPBACK_SEND_RECV_COMPARE_FAIL;
1291*9e39c5baSBill Taylor 				if (ddi_copyout(lstate.tls_rx.tlc_buf,
1292*9e39c5baSBill Taylor 				    lb.tlb_fail_buf, lstate.tls_tx.tlc_buf_sz,
1293*9e39c5baSBill Taylor 				    mode) != 0) {
1294*9e39c5baSBill Taylor 					TNF_PROBE_0(
1295*9e39c5baSBill Taylor 					    tavor_ioctl_loopback_bcmp_co_fail,
1296*9e39c5baSBill Taylor 					    TAVOR_TNF_ERROR, "");
1297*9e39c5baSBill Taylor 					TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1298*9e39c5baSBill Taylor 					return (EFAULT);
1299*9e39c5baSBill Taylor 				}
1300*9e39c5baSBill Taylor 				(void) tavor_loopback_copyout(&lb, arg, mode);
1301*9e39c5baSBill Taylor 				tavor_loopback_free_state(&lstate);
1302*9e39c5baSBill Taylor 				TNF_PROBE_0(tavor_ioctl_loopback_bcmp_fail,
1303*9e39c5baSBill Taylor 				    TAVOR_TNF_ERROR, "");
1304*9e39c5baSBill Taylor 				TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1305*9e39c5baSBill Taylor 				return (EFAULT);
1306*9e39c5baSBill Taylor 			}
1307*9e39c5baSBill Taylor 		}
1308*9e39c5baSBill Taylor 
1309*9e39c5baSBill Taylor 		lstate.tls_err	 = TAVOR_LOOPBACK_SUCCESS;
1310*9e39c5baSBill Taylor 		lb.tlb_pass_done = iter + 1;
1311*9e39c5baSBill Taylor 	}
1312*9e39c5baSBill Taylor 
1313*9e39c5baSBill Taylor 	lb.tlb_error_type = TAVOR_LOOPBACK_SUCCESS;
1314*9e39c5baSBill Taylor 
1315*9e39c5baSBill Taylor 	/* Copy ioctl results back to user struct */
1316*9e39c5baSBill Taylor 	ret = tavor_loopback_copyout(&lb, arg, mode);
1317*9e39c5baSBill Taylor 
1318*9e39c5baSBill Taylor 	/* Free up everything and release all consumed resources */
1319*9e39c5baSBill Taylor 	tavor_loopback_free_state(&lstate);
1320*9e39c5baSBill Taylor 
1321*9e39c5baSBill Taylor 	TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1322*9e39c5baSBill Taylor 	return (ret);
1323*9e39c5baSBill Taylor }
1324*9e39c5baSBill Taylor 
1325*9e39c5baSBill Taylor /*
1326*9e39c5baSBill Taylor  * tavor_ioctl_ddr_read()
1327*9e39c5baSBill Taylor  */
1328*9e39c5baSBill Taylor static int
1329*9e39c5baSBill Taylor tavor_ioctl_ddr_read(tavor_state_t *state, intptr_t arg, int mode)
1330*9e39c5baSBill Taylor {
1331*9e39c5baSBill Taylor 	tavor_ddr_read_ioctl_t	rdreg;
1332*9e39c5baSBill Taylor 	uint32_t		*addr;
1333*9e39c5baSBill Taylor 	uintptr_t		baseaddr;
1334*9e39c5baSBill Taylor 	uint64_t		ddr_size;
1335*9e39c5baSBill Taylor 
1336*9e39c5baSBill Taylor 	TAVOR_TNF_ENTER(tavor_ioctl_ddr_read);
1337*9e39c5baSBill Taylor 
1338*9e39c5baSBill Taylor 	/*
1339*9e39c5baSBill Taylor 	 * Access to Tavor VTS ioctls is not allowed in "maintenance mode".
1340*9e39c5baSBill Taylor 	 */
1341*9e39c5baSBill Taylor 	if (state->ts_operational_mode == TAVOR_MAINTENANCE_MODE) {
1342*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_ddr_read_maintenance_mode_fail,
1343*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
1344*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_ddr_read);
1345*9e39c5baSBill Taylor 		return (EFAULT);
1346*9e39c5baSBill Taylor 	}
1347*9e39c5baSBill Taylor 
1348*9e39c5baSBill Taylor 	/* copyin the user struct to kernel */
1349*9e39c5baSBill Taylor 	if (ddi_copyin((void *)arg, &rdreg, sizeof (tavor_ddr_read_ioctl_t),
1350*9e39c5baSBill Taylor 	    mode) != 0) {
1351*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_ddr_read_copyin_fail,
1352*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
1353*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_ddr_read);
1354*9e39c5baSBill Taylor 		return (EFAULT);
1355*9e39c5baSBill Taylor 	}
1356*9e39c5baSBill Taylor 
1357*9e39c5baSBill Taylor 	/*
1358*9e39c5baSBill Taylor 	 * Check ioctl revision
1359*9e39c5baSBill Taylor 	 */
1360*9e39c5baSBill Taylor 	if (rdreg.tdr_revision != TAVOR_VTS_IOCTL_REVISION) {
1361*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_ddr_read_bad_rev, TAVOR_TNF_ERROR, "");
1362*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_ddr_read);
1363*9e39c5baSBill Taylor 		return (EINVAL);
1364*9e39c5baSBill Taylor 	}
1365*9e39c5baSBill Taylor 
1366*9e39c5baSBill Taylor 	/*
1367*9e39c5baSBill Taylor 	 * Check for valid offset
1368*9e39c5baSBill Taylor 	 */
1369*9e39c5baSBill Taylor 	ddr_size = (state->ts_ddr.ddr_endaddr - state->ts_ddr.ddr_baseaddr + 1);
1370*9e39c5baSBill Taylor 	if ((uint64_t)rdreg.tdr_offset >= ddr_size) {
1371*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_ddr_read_bad_offset,
1372*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
1373*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_ddr_read);
1374*9e39c5baSBill Taylor 		return (EINVAL);
1375*9e39c5baSBill Taylor 	}
1376*9e39c5baSBill Taylor 
1377*9e39c5baSBill Taylor 	/* Determine base address for requested register read */
1378*9e39c5baSBill Taylor 	baseaddr = (uintptr_t)state->ts_reg_ddr_baseaddr;
1379*9e39c5baSBill Taylor 
1380*9e39c5baSBill Taylor 	/* Ensure that address is properly-aligned */
1381*9e39c5baSBill Taylor 	addr = (uint32_t *)((baseaddr + rdreg.tdr_offset) & ~0x3);
1382*9e39c5baSBill Taylor 
1383*9e39c5baSBill Taylor 	/* Read the register pointed to by addr */
1384*9e39c5baSBill Taylor 	rdreg.tdr_data = ddi_get32(state->ts_reg_cmdhdl, addr);
1385*9e39c5baSBill Taylor 
1386*9e39c5baSBill Taylor 	/* Copy ioctl results back to user struct */
1387*9e39c5baSBill Taylor 	if (ddi_copyout(&rdreg, (void *)arg, sizeof (tavor_ddr_read_ioctl_t),
1388*9e39c5baSBill Taylor 	    mode) != 0) {
1389*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_ddr_read_copyout_fail,
1390*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
1391*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_ddr_read);
1392*9e39c5baSBill Taylor 		return (EFAULT);
1393*9e39c5baSBill Taylor 	}
1394*9e39c5baSBill Taylor 
1395*9e39c5baSBill Taylor 	TAVOR_TNF_EXIT(tavor_ioctl_ddr_read);
1396*9e39c5baSBill Taylor 	return (0);
1397*9e39c5baSBill Taylor }
1398*9e39c5baSBill Taylor 
1399*9e39c5baSBill Taylor 
1400*9e39c5baSBill Taylor #ifdef	DEBUG
1401*9e39c5baSBill Taylor /*
1402*9e39c5baSBill Taylor  * tavor_ioctl_reg_read()
1403*9e39c5baSBill Taylor  */
1404*9e39c5baSBill Taylor static int
1405*9e39c5baSBill Taylor tavor_ioctl_reg_read(tavor_state_t *state, intptr_t arg, int mode)
1406*9e39c5baSBill Taylor {
1407*9e39c5baSBill Taylor 	tavor_reg_ioctl_t	rdreg;
1408*9e39c5baSBill Taylor 	uint32_t		*addr;
1409*9e39c5baSBill Taylor 	uintptr_t		baseaddr;
1410*9e39c5baSBill Taylor 	int			status;
1411*9e39c5baSBill Taylor 
1412*9e39c5baSBill Taylor 	TAVOR_TNF_ENTER(tavor_ioctl_reg_read);
1413*9e39c5baSBill Taylor 
1414*9e39c5baSBill Taylor 	/*
1415*9e39c5baSBill Taylor 	 * Access to Tavor registers is not allowed in "maintenance mode".
1416*9e39c5baSBill Taylor 	 * This is primarily because the device may not have BARs to access
1417*9e39c5baSBill Taylor 	 */
1418*9e39c5baSBill Taylor 	if (state->ts_operational_mode == TAVOR_MAINTENANCE_MODE) {
1419*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_reg_read_maintence_mode_fail,
1420*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
1421*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_reg_read);
1422*9e39c5baSBill Taylor 		return (EFAULT);
1423*9e39c5baSBill Taylor 	}
1424*9e39c5baSBill Taylor 
1425*9e39c5baSBill Taylor 	/* Copy in the tavor_reg_ioctl_t structure */
1426*9e39c5baSBill Taylor 	status = ddi_copyin((void *)arg, &rdreg, sizeof (tavor_reg_ioctl_t),
1427*9e39c5baSBill Taylor 	    mode);
1428*9e39c5baSBill Taylor 	if (status != 0) {
1429*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_reg_read_copyin_fail,
1430*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
1431*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_reg_read);
1432*9e39c5baSBill Taylor 		return (EFAULT);
1433*9e39c5baSBill Taylor 	}
1434*9e39c5baSBill Taylor 
1435*9e39c5baSBill Taylor 	/* Determine base address for requested register set */
1436*9e39c5baSBill Taylor 	switch (rdreg.trg_reg_set) {
1437*9e39c5baSBill Taylor 	case TAVOR_CMD_BAR:
1438*9e39c5baSBill Taylor 		baseaddr = (uintptr_t)state->ts_reg_cmd_baseaddr;
1439*9e39c5baSBill Taylor 		break;
1440*9e39c5baSBill Taylor 
1441*9e39c5baSBill Taylor 	case TAVOR_UAR_BAR:
1442*9e39c5baSBill Taylor 		baseaddr = (uintptr_t)state->ts_reg_uar_baseaddr;
1443*9e39c5baSBill Taylor 		break;
1444*9e39c5baSBill Taylor 
1445*9e39c5baSBill Taylor 	case TAVOR_DDR_BAR:
1446*9e39c5baSBill Taylor 		baseaddr = (uintptr_t)state->ts_reg_ddr_baseaddr;
1447*9e39c5baSBill Taylor 		break;
1448*9e39c5baSBill Taylor 
1449*9e39c5baSBill Taylor 	default:
1450*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_reg_read_invregset_fail,
1451*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
1452*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_reg_read);
1453*9e39c5baSBill Taylor 		return (EFAULT);
1454*9e39c5baSBill Taylor 	}
1455*9e39c5baSBill Taylor 
1456*9e39c5baSBill Taylor 	/* Ensure that address is properly-aligned */
1457*9e39c5baSBill Taylor 	addr = (uint32_t *)((baseaddr + rdreg.trg_offset) & ~0x3);
1458*9e39c5baSBill Taylor 
1459*9e39c5baSBill Taylor 	/* Read the register pointed to by addr */
1460*9e39c5baSBill Taylor 	rdreg.trg_data = ddi_get32(state->ts_reg_cmdhdl, addr);
1461*9e39c5baSBill Taylor 
1462*9e39c5baSBill Taylor 	/* Copy in the result into the tavor_reg_ioctl_t structure */
1463*9e39c5baSBill Taylor 	status = ddi_copyout(&rdreg, (void *)arg, sizeof (tavor_reg_ioctl_t),
1464*9e39c5baSBill Taylor 	    mode);
1465*9e39c5baSBill Taylor 	if (status != 0) {
1466*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_reg_read_copyout_fail,
1467*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
1468*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_reg_read);
1469*9e39c5baSBill Taylor 		return (EFAULT);
1470*9e39c5baSBill Taylor 	}
1471*9e39c5baSBill Taylor 
1472*9e39c5baSBill Taylor 	TAVOR_TNF_EXIT(tavor_ioctl_reg_read);
1473*9e39c5baSBill Taylor 	return (0);
1474*9e39c5baSBill Taylor }
1475*9e39c5baSBill Taylor 
1476*9e39c5baSBill Taylor 
1477*9e39c5baSBill Taylor /*
1478*9e39c5baSBill Taylor  * tavor_ioctl_reg_write()
1479*9e39c5baSBill Taylor  */
1480*9e39c5baSBill Taylor static int
1481*9e39c5baSBill Taylor tavor_ioctl_reg_write(tavor_state_t *state, intptr_t arg, int mode)
1482*9e39c5baSBill Taylor {
1483*9e39c5baSBill Taylor 	tavor_reg_ioctl_t	wrreg;
1484*9e39c5baSBill Taylor 	uint32_t		*addr;
1485*9e39c5baSBill Taylor 	uintptr_t		baseaddr;
1486*9e39c5baSBill Taylor 	int			status;
1487*9e39c5baSBill Taylor 
1488*9e39c5baSBill Taylor 	TAVOR_TNF_ENTER(tavor_ioctl_reg_write);
1489*9e39c5baSBill Taylor 
1490*9e39c5baSBill Taylor 	/*
1491*9e39c5baSBill Taylor 	 * Access to Tavor registers is not allowed in "maintenance mode".
1492*9e39c5baSBill Taylor 	 * This is primarily because the device may not have BARs to access
1493*9e39c5baSBill Taylor 	 */
1494*9e39c5baSBill Taylor 	if (state->ts_operational_mode == TAVOR_MAINTENANCE_MODE) {
1495*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_reg_write_maintence_mode_fail,
1496*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
1497*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_reg_write);
1498*9e39c5baSBill Taylor 		return (EFAULT);
1499*9e39c5baSBill Taylor 	}
1500*9e39c5baSBill Taylor 
1501*9e39c5baSBill Taylor 	/* Copy in the tavor_reg_ioctl_t structure */
1502*9e39c5baSBill Taylor 	status = ddi_copyin((void *)arg, &wrreg, sizeof (tavor_reg_ioctl_t),
1503*9e39c5baSBill Taylor 	    mode);
1504*9e39c5baSBill Taylor 	if (status != 0) {
1505*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_reg_write_copyin_fail,
1506*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
1507*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_reg_write);
1508*9e39c5baSBill Taylor 		return (EFAULT);
1509*9e39c5baSBill Taylor 	}
1510*9e39c5baSBill Taylor 
1511*9e39c5baSBill Taylor 	/* Determine base address for requested register set */
1512*9e39c5baSBill Taylor 	switch (wrreg.trg_reg_set) {
1513*9e39c5baSBill Taylor 	case TAVOR_CMD_BAR:
1514*9e39c5baSBill Taylor 		baseaddr = (uintptr_t)state->ts_reg_cmd_baseaddr;
1515*9e39c5baSBill Taylor 		break;
1516*9e39c5baSBill Taylor 
1517*9e39c5baSBill Taylor 	case TAVOR_UAR_BAR:
1518*9e39c5baSBill Taylor 		baseaddr = (uintptr_t)state->ts_reg_uar_baseaddr;
1519*9e39c5baSBill Taylor 		break;
1520*9e39c5baSBill Taylor 
1521*9e39c5baSBill Taylor 	case TAVOR_DDR_BAR:
1522*9e39c5baSBill Taylor 		baseaddr = (uintptr_t)state->ts_reg_ddr_baseaddr;
1523*9e39c5baSBill Taylor 		break;
1524*9e39c5baSBill Taylor 
1525*9e39c5baSBill Taylor 	default:
1526*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_reg_write_invregset_fail,
1527*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
1528*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_ioctl_reg_write);
1529*9e39c5baSBill Taylor 		return (EFAULT);
1530*9e39c5baSBill Taylor 	}
1531*9e39c5baSBill Taylor 
1532*9e39c5baSBill Taylor 	/* Ensure that address is properly-aligned */
1533*9e39c5baSBill Taylor 	addr = (uint32_t *)((baseaddr + wrreg.trg_offset) & ~0x3);
1534*9e39c5baSBill Taylor 
1535*9e39c5baSBill Taylor 	/* Write the data to the register pointed to by addr */
1536*9e39c5baSBill Taylor 	ddi_put32(state->ts_reg_cmdhdl, addr, wrreg.trg_data);
1537*9e39c5baSBill Taylor 
1538*9e39c5baSBill Taylor 	TAVOR_TNF_EXIT(tavor_ioctl_reg_write);
1539*9e39c5baSBill Taylor 	return (0);
1540*9e39c5baSBill Taylor }
1541*9e39c5baSBill Taylor #endif	/* DEBUG */
1542*9e39c5baSBill Taylor 
1543*9e39c5baSBill Taylor /*
1544*9e39c5baSBill Taylor  * tavor_flash_reset()
1545*9e39c5baSBill Taylor  */
1546*9e39c5baSBill Taylor static void
1547*9e39c5baSBill Taylor tavor_flash_reset(tavor_state_t *state)
1548*9e39c5baSBill Taylor {
1549*9e39c5baSBill Taylor 	TAVOR_TNF_ENTER(tavor_flash_reset);
1550*9e39c5baSBill Taylor 
1551*9e39c5baSBill Taylor 	/*
1552*9e39c5baSBill Taylor 	 * Performs a reset to the flash device.  After a reset the flash will
1553*9e39c5baSBill Taylor 	 * be operating in normal mode (capable of read/write, etc.).
1554*9e39c5baSBill Taylor 	 */
1555*9e39c5baSBill Taylor 	switch (state->ts_fw_cmdset) {
1556*9e39c5baSBill Taylor 	case TAVOR_FLASH_AMD_CMDSET:
1557*9e39c5baSBill Taylor 		tavor_flash_write(state, 0x555, TAVOR_HW_FLASH_RESET_AMD);
1558*9e39c5baSBill Taylor 		break;
1559*9e39c5baSBill Taylor 
1560*9e39c5baSBill Taylor 	case TAVOR_FLASH_INTEL_CMDSET:
1561*9e39c5baSBill Taylor 		tavor_flash_write(state, 0x555, TAVOR_HW_FLASH_RESET_INTEL);
1562*9e39c5baSBill Taylor 		break;
1563*9e39c5baSBill Taylor 
1564*9e39c5baSBill Taylor 	default:
1565*9e39c5baSBill Taylor 		break;
1566*9e39c5baSBill Taylor 	}
1567*9e39c5baSBill Taylor 
1568*9e39c5baSBill Taylor 	TAVOR_TNF_EXIT(tavor_flash_reset);
1569*9e39c5baSBill Taylor }
1570*9e39c5baSBill Taylor 
1571*9e39c5baSBill Taylor /*
1572*9e39c5baSBill Taylor  * tavor_flash_read_sector()
1573*9e39c5baSBill Taylor  */
1574*9e39c5baSBill Taylor static void
1575*9e39c5baSBill Taylor tavor_flash_read_sector(tavor_state_t *state, uint32_t sector_num)
1576*9e39c5baSBill Taylor {
1577*9e39c5baSBill Taylor 	uint32_t addr;
1578*9e39c5baSBill Taylor 	uint32_t end_addr;
1579*9e39c5baSBill Taylor 	uint32_t *image;
1580*9e39c5baSBill Taylor 	int i;
1581*9e39c5baSBill Taylor 
1582*9e39c5baSBill Taylor 	TAVOR_TNF_ENTER(tavor_flash_read_sector);
1583*9e39c5baSBill Taylor 
1584*9e39c5baSBill Taylor 	image = (uint32_t *)&state->ts_fw_sector[0];
1585*9e39c5baSBill Taylor 
1586*9e39c5baSBill Taylor 	/*
1587*9e39c5baSBill Taylor 	 * Calculate the start and end address of the sector, based on the
1588*9e39c5baSBill Taylor 	 * sector number passed in.
1589*9e39c5baSBill Taylor 	 */
1590*9e39c5baSBill Taylor 	addr = sector_num << state->ts_fw_log_sector_sz;
1591*9e39c5baSBill Taylor 	end_addr = addr + (1 << state->ts_fw_log_sector_sz);
1592*9e39c5baSBill Taylor 
1593*9e39c5baSBill Taylor 	/* Set the flash bank correctly for the given address */
1594*9e39c5baSBill Taylor 	tavor_flash_bank(state, addr);
1595*9e39c5baSBill Taylor 
1596*9e39c5baSBill Taylor 	/* Read the entire sector, one quadlet at a time */
1597*9e39c5baSBill Taylor 	for (i = 0; addr < end_addr; i++, addr += 4) {
1598*9e39c5baSBill Taylor 		image[i] = tavor_flash_read(state, addr);
1599*9e39c5baSBill Taylor 	}
1600*9e39c5baSBill Taylor 
1601*9e39c5baSBill Taylor 	TAVOR_TNF_EXIT(tavor_flash_read_sector);
1602*9e39c5baSBill Taylor }
1603*9e39c5baSBill Taylor 
1604*9e39c5baSBill Taylor /*
1605*9e39c5baSBill Taylor  * tavor_flash_read_quadlet()
1606*9e39c5baSBill Taylor  */
1607*9e39c5baSBill Taylor static void
1608*9e39c5baSBill Taylor tavor_flash_read_quadlet(tavor_state_t *state, uint32_t *data,
1609*9e39c5baSBill Taylor     uint32_t addr)
1610*9e39c5baSBill Taylor {
1611*9e39c5baSBill Taylor 	TAVOR_TNF_ENTER(tavor_flash_read_quadlet);
1612*9e39c5baSBill Taylor 
1613*9e39c5baSBill Taylor 	/* Set the flash bank correctly for the given address */
1614*9e39c5baSBill Taylor 	tavor_flash_bank(state, addr);
1615*9e39c5baSBill Taylor 
1616*9e39c5baSBill Taylor 	/* Read one quadlet of data */
1617*9e39c5baSBill Taylor 	*data = tavor_flash_read(state, addr);
1618*9e39c5baSBill Taylor 
1619*9e39c5baSBill Taylor 	TAVOR_TNF_EXIT(tavor_flash_read_quadlet);
1620*9e39c5baSBill Taylor }
1621*9e39c5baSBill Taylor 
1622*9e39c5baSBill Taylor /*
1623*9e39c5baSBill Taylor  * tavor_flash_write_sector()
1624*9e39c5baSBill Taylor  */
1625*9e39c5baSBill Taylor static int
1626*9e39c5baSBill Taylor tavor_flash_write_sector(tavor_state_t *state, uint32_t sector_num)
1627*9e39c5baSBill Taylor {
1628*9e39c5baSBill Taylor 	uint32_t addr;
1629*9e39c5baSBill Taylor 	uint32_t end_addr;
1630*9e39c5baSBill Taylor 	uchar_t *sector;
1631*9e39c5baSBill Taylor 	int	status = 0;
1632*9e39c5baSBill Taylor 	int	i;
1633*9e39c5baSBill Taylor 
1634*9e39c5baSBill Taylor 	TAVOR_TNF_ENTER(tavor_flash_write_sector);
1635*9e39c5baSBill Taylor 
1636*9e39c5baSBill Taylor 	sector = (uchar_t *)&state->ts_fw_sector[0];
1637*9e39c5baSBill Taylor 
1638*9e39c5baSBill Taylor 	/*
1639*9e39c5baSBill Taylor 	 * Calculate the start and end address of the sector, based on the
1640*9e39c5baSBill Taylor 	 * sector number passed in.
1641*9e39c5baSBill Taylor 	 */
1642*9e39c5baSBill Taylor 	addr = sector_num << state->ts_fw_log_sector_sz;
1643*9e39c5baSBill Taylor 	end_addr = addr + (1 << state->ts_fw_log_sector_sz);
1644*9e39c5baSBill Taylor 
1645*9e39c5baSBill Taylor 	/* Set the flash bank correctly for the given address */
1646*9e39c5baSBill Taylor 	tavor_flash_bank(state, addr);
1647*9e39c5baSBill Taylor 
1648*9e39c5baSBill Taylor 	/* Erase the sector before writing */
1649*9e39c5baSBill Taylor 	tavor_flash_reset(state);
1650*9e39c5baSBill Taylor 	status = tavor_flash_erase_sector(state, sector_num);
1651*9e39c5baSBill Taylor 	if (status != 0) {
1652*9e39c5baSBill Taylor 		TAVOR_TNF_EXIT(tavor_flash_write_sector);
1653*9e39c5baSBill Taylor 		return (status);
1654*9e39c5baSBill Taylor 	}
1655*9e39c5baSBill Taylor 
1656*9e39c5baSBill Taylor 	/* Write the entire sector, one byte at a time */
1657*9e39c5baSBill Taylor 	for (i = 0; addr < end_addr; i++, addr++) {
1658*9e39c5baSBill Taylor 		status = tavor_flash_write_byte(state, addr, sector[i]);
1659*9e39c5baSBill Taylor 		if (status != 0) {
1660*9e39c5baSBill Taylor 			break;
1661*9e39c5baSBill Taylor 		}
1662*9e39c5baSBill Taylor 	}
1663*9e39c5baSBill Taylor 
1664*9e39c5baSBill Taylor 	tavor_flash_reset(state);
1665*9e39c5baSBill Taylor 	TAVOR_TNF_EXIT(tavor_flash_write_sector);
1666*9e39c5baSBill Taylor 	return (status);
1667*9e39c5baSBill Taylor }
1668*9e39c5baSBill Taylor 
1669*9e39c5baSBill Taylor /*
1670*9e39c5baSBill Taylor  * tavor_flash_write_byte()
1671*9e39c5baSBill Taylor  */
1672*9e39c5baSBill Taylor static int
1673*9e39c5baSBill Taylor tavor_flash_write_byte(tavor_state_t *state, uint32_t addr, uchar_t data)
1674*9e39c5baSBill Taylor {
1675*9e39c5baSBill Taylor 	uint32_t stat;
1676*9e39c5baSBill Taylor 	int status = 0;
1677*9e39c5baSBill Taylor 	int i;
1678*9e39c5baSBill Taylor 
1679*9e39c5baSBill Taylor 	TAVOR_TNF_ENTER(tavor_flash_write_byte);
1680*9e39c5baSBill Taylor 
1681*9e39c5baSBill Taylor 	switch (state->ts_fw_cmdset) {
1682*9e39c5baSBill Taylor 	case TAVOR_FLASH_AMD_CMDSET:
1683*9e39c5baSBill Taylor 		/* Issue Flash Byte program command */
1684*9e39c5baSBill Taylor 		tavor_flash_write(state, addr, 0xAA);
1685*9e39c5baSBill Taylor 		tavor_flash_write(state, addr, 0x55);
1686*9e39c5baSBill Taylor 		tavor_flash_write(state, addr, 0xA0);
1687*9e39c5baSBill Taylor 		tavor_flash_write(state, addr, data);
1688*9e39c5baSBill Taylor 
1689*9e39c5baSBill Taylor 		/*
1690*9e39c5baSBill Taylor 		 * Wait for Write Byte to Complete:
1691*9e39c5baSBill Taylor 		 *   1) Wait 1usec
1692*9e39c5baSBill Taylor 		 *   2) Read status of the write operation
1693*9e39c5baSBill Taylor 		 *   3) Determine if we have timed out the write operation
1694*9e39c5baSBill Taylor 		 *   4) Compare correct data value to the status value that
1695*9e39c5baSBill Taylor 		 *	was read from the same address.
1696*9e39c5baSBill Taylor 		 */
1697*9e39c5baSBill Taylor 		i = 0;
1698*9e39c5baSBill Taylor 		do {
1699*9e39c5baSBill Taylor 			drv_usecwait(1);
1700*9e39c5baSBill Taylor 			stat = tavor_flash_read(state, addr & ~3);
1701*9e39c5baSBill Taylor 
1702*9e39c5baSBill Taylor 			if (i == tavor_hw_flash_timeout_write) {
1703*9e39c5baSBill Taylor 				cmn_err(CE_WARN,
1704*9e39c5baSBill Taylor 				    "tavor_flash_write_byte: ACS write "
1705*9e39c5baSBill Taylor 				    "timeout: addr: 0x%x, data: 0x%x\n",
1706*9e39c5baSBill Taylor 				    addr, data);
1707*9e39c5baSBill Taylor 				status = EIO;
1708*9e39c5baSBill Taylor 				break;
1709*9e39c5baSBill Taylor 			}
1710*9e39c5baSBill Taylor 
1711*9e39c5baSBill Taylor 			i++;
1712*9e39c5baSBill Taylor 		} while (data != ((stat >> ((3 - (addr & 3)) << 3)) & 0xFF));
1713*9e39c5baSBill Taylor 		break;
1714*9e39c5baSBill Taylor 
1715*9e39c5baSBill Taylor 	case TAVOR_FLASH_INTEL_CMDSET:
1716*9e39c5baSBill Taylor 		/* Issue Flash Byte program command */
1717*9e39c5baSBill Taylor 		tavor_flash_write(state, addr, TAVOR_HW_FLASH_ICS_WRITE);
1718*9e39c5baSBill Taylor 		tavor_flash_write(state, addr, data);
1719*9e39c5baSBill Taylor 
1720*9e39c5baSBill Taylor 		/* wait for completion */
1721*9e39c5baSBill Taylor 		i = 0;
1722*9e39c5baSBill Taylor 		do {
1723*9e39c5baSBill Taylor 			drv_usecwait(1);
1724*9e39c5baSBill Taylor 			stat = tavor_flash_read(state, addr & ~3);
1725*9e39c5baSBill Taylor 
1726*9e39c5baSBill Taylor 			if (i == tavor_hw_flash_timeout_write) {
1727*9e39c5baSBill Taylor 				cmn_err(CE_WARN,
1728*9e39c5baSBill Taylor 				    "tavor_flash_write_byte: ICS write "
1729*9e39c5baSBill Taylor 				    "timeout: addr: %x, data: %x\n",
1730*9e39c5baSBill Taylor 				    addr, data);
1731*9e39c5baSBill Taylor 				status = EIO;
1732*9e39c5baSBill Taylor 				break;
1733*9e39c5baSBill Taylor 			}
1734*9e39c5baSBill Taylor 
1735*9e39c5baSBill Taylor 			i++;
1736*9e39c5baSBill Taylor 		} while ((stat & TAVOR_HW_FLASH_ICS_READY) == 0);
1737*9e39c5baSBill Taylor 
1738*9e39c5baSBill Taylor 		if (stat & TAVOR_HW_FLASH_ICS_ERROR) {
1739*9e39c5baSBill Taylor 			cmn_err(CE_WARN,
1740*9e39c5baSBill Taylor 			    "tavor_flash_write_byte: ICS write cmd error: "
1741*9e39c5baSBill Taylor 			    "addr: %x, data: %x\n",
1742*9e39c5baSBill Taylor 			    addr, data);
1743*9e39c5baSBill Taylor 			status = EIO;
1744*9e39c5baSBill Taylor 		}
1745*9e39c5baSBill Taylor 		break;
1746*9e39c5baSBill Taylor 
1747*9e39c5baSBill Taylor 	default:
1748*9e39c5baSBill Taylor 		cmn_err(CE_WARN,
1749*9e39c5baSBill Taylor 		    "tavor_flash_write_byte: unknown cmd set: 0x%x\n",
1750*9e39c5baSBill Taylor 		    state->ts_fw_cmdset);
1751*9e39c5baSBill Taylor 		status = EIO;
1752*9e39c5baSBill Taylor 		break;
1753*9e39c5baSBill Taylor 	}
1754*9e39c5baSBill Taylor 
1755*9e39c5baSBill Taylor 	TAVOR_TNF_EXIT(tavor_flash_write_byte);
1756*9e39c5baSBill Taylor 	return (status);
1757*9e39c5baSBill Taylor }
1758*9e39c5baSBill Taylor 
1759*9e39c5baSBill Taylor /*
1760*9e39c5baSBill Taylor  * tavor_flash_erase_sector()
1761*9e39c5baSBill Taylor  */
1762*9e39c5baSBill Taylor static int
1763*9e39c5baSBill Taylor tavor_flash_erase_sector(tavor_state_t *state, uint32_t sector_num)
1764*9e39c5baSBill Taylor {
1765*9e39c5baSBill Taylor 	uint32_t addr;
1766*9e39c5baSBill Taylor 	uint32_t stat;
1767*9e39c5baSBill Taylor 	int status = 0;
1768*9e39c5baSBill Taylor 	int i;
1769*9e39c5baSBill Taylor 
1770*9e39c5baSBill Taylor 	TAVOR_TNF_ENTER(tavor_flash_erase_sector);
1771*9e39c5baSBill Taylor 
1772*9e39c5baSBill Taylor 	/* Get address from sector num */
1773*9e39c5baSBill Taylor 	addr = sector_num << state->ts_fw_log_sector_sz;
1774*9e39c5baSBill Taylor 
1775*9e39c5baSBill Taylor 	switch (state->ts_fw_cmdset) {
1776*9e39c5baSBill Taylor 	case TAVOR_FLASH_AMD_CMDSET:
1777*9e39c5baSBill Taylor 		/* Issue Flash Sector Erase Command */
1778*9e39c5baSBill Taylor 		tavor_flash_write(state, addr, 0xAA);
1779*9e39c5baSBill Taylor 		tavor_flash_write(state, addr, 0x55);
1780*9e39c5baSBill Taylor 		tavor_flash_write(state, addr, 0x80);
1781*9e39c5baSBill Taylor 		tavor_flash_write(state, addr, 0xAA);
1782*9e39c5baSBill Taylor 		tavor_flash_write(state, addr, 0x55);
1783*9e39c5baSBill Taylor 		tavor_flash_write(state, addr, 0x30);
1784*9e39c5baSBill Taylor 
1785*9e39c5baSBill Taylor 		/*
1786*9e39c5baSBill Taylor 		 * Wait for Sector Erase to Complete
1787*9e39c5baSBill Taylor 		 *   1) Wait 1usec
1788*9e39c5baSBill Taylor 		 *   2) read the status at the base addr of the sector
1789*9e39c5baSBill Taylor 		 *   3) Determine if we have timed out
1790*9e39c5baSBill Taylor 		 *   4) Compare status of address with the value of a fully
1791*9e39c5baSBill Taylor 		 *	erased quadlet. If these are equal, the sector
1792*9e39c5baSBill Taylor 		 *	has been erased.
1793*9e39c5baSBill Taylor 		 */
1794*9e39c5baSBill Taylor 		i = 0;
1795*9e39c5baSBill Taylor 		do {
1796*9e39c5baSBill Taylor 			/* wait 1usec */
1797*9e39c5baSBill Taylor 			drv_usecwait(1);
1798*9e39c5baSBill Taylor 			stat = tavor_flash_read(state, addr);
1799*9e39c5baSBill Taylor 
1800*9e39c5baSBill Taylor 			if (i == tavor_hw_flash_timeout_erase) {
1801*9e39c5baSBill Taylor 				cmn_err(CE_WARN,
1802*9e39c5baSBill Taylor 				    "tavor_flash_erase_sector: "
1803*9e39c5baSBill Taylor 				    "ACS erase timeout\n");
1804*9e39c5baSBill Taylor 				status = EIO;
1805*9e39c5baSBill Taylor 				break;
1806*9e39c5baSBill Taylor 			}
1807*9e39c5baSBill Taylor 
1808*9e39c5baSBill Taylor 			i++;
1809*9e39c5baSBill Taylor 		} while (stat != 0xFFFFFFFF);
1810*9e39c5baSBill Taylor 		break;
1811*9e39c5baSBill Taylor 
1812*9e39c5baSBill Taylor 	case TAVOR_FLASH_INTEL_CMDSET:
1813*9e39c5baSBill Taylor 		/* Issue Erase Command */
1814*9e39c5baSBill Taylor 		tavor_flash_write(state, addr, TAVOR_HW_FLASH_ICS_ERASE);
1815*9e39c5baSBill Taylor 		tavor_flash_write(state, addr, TAVOR_HW_FLASH_ICS_CONFIRM);
1816*9e39c5baSBill Taylor 
1817*9e39c5baSBill Taylor 		/* wait for completion */
1818*9e39c5baSBill Taylor 		i = 0;
1819*9e39c5baSBill Taylor 		do {
1820*9e39c5baSBill Taylor 			drv_usecwait(1);
1821*9e39c5baSBill Taylor 			stat = tavor_flash_read(state, addr & ~3);
1822*9e39c5baSBill Taylor 
1823*9e39c5baSBill Taylor 			if (i == tavor_hw_flash_timeout_erase) {
1824*9e39c5baSBill Taylor 				cmn_err(CE_WARN,
1825*9e39c5baSBill Taylor 				    "tavor_flash_erase_sector: "
1826*9e39c5baSBill Taylor 				    "ICS erase timeout\n");
1827*9e39c5baSBill Taylor 				status = EIO;
1828*9e39c5baSBill Taylor 				break;
1829*9e39c5baSBill Taylor 			}
1830*9e39c5baSBill Taylor 
1831*9e39c5baSBill Taylor 			i++;
1832*9e39c5baSBill Taylor 		} while ((stat & TAVOR_HW_FLASH_ICS_READY) == 0);
1833*9e39c5baSBill Taylor 
1834*9e39c5baSBill Taylor 		if (stat & TAVOR_HW_FLASH_ICS_ERROR) {
1835*9e39c5baSBill Taylor 			cmn_err(CE_WARN,
1836*9e39c5baSBill Taylor 			    "tavor_flash_erase_sector: "
1837*9e39c5baSBill Taylor 			    "ICS erase cmd error\n");
1838*9e39c5baSBill Taylor 			status = EIO;
1839*9e39c5baSBill Taylor 		}
1840*9e39c5baSBill Taylor 		break;
1841*9e39c5baSBill Taylor 
1842*9e39c5baSBill Taylor 	default:
1843*9e39c5baSBill Taylor 		cmn_err(CE_WARN,
1844*9e39c5baSBill Taylor 		    "tavor_flash_erase_sector: unknown cmd set: 0x%x\n",
1845*9e39c5baSBill Taylor 		    state->ts_fw_cmdset);
1846*9e39c5baSBill Taylor 		status = EIO;
1847*9e39c5baSBill Taylor 		break;
1848*9e39c5baSBill Taylor 	}
1849*9e39c5baSBill Taylor 
1850*9e39c5baSBill Taylor 	tavor_flash_reset(state);
1851*9e39c5baSBill Taylor 
1852*9e39c5baSBill Taylor 	TAVOR_TNF_EXIT(tavor_flash_erase_sector);
1853*9e39c5baSBill Taylor 	return (status);
1854*9e39c5baSBill Taylor }
1855*9e39c5baSBill Taylor 
1856*9e39c5baSBill Taylor /*
1857*9e39c5baSBill Taylor  * tavor_flash_erase_chip()
1858*9e39c5baSBill Taylor  */
1859*9e39c5baSBill Taylor static int
1860*9e39c5baSBill Taylor tavor_flash_erase_chip(tavor_state_t *state)
1861*9e39c5baSBill Taylor {
1862*9e39c5baSBill Taylor 	uint_t size;
1863*9e39c5baSBill Taylor 	uint32_t stat;
1864*9e39c5baSBill Taylor 	int status = 0;
1865*9e39c5baSBill Taylor 	int num_sect;
1866*9e39c5baSBill Taylor 	int i;
1867*9e39c5baSBill Taylor 
1868*9e39c5baSBill Taylor 	TAVOR_TNF_ENTER(tavor_flash_erase_chip);
1869*9e39c5baSBill Taylor 
1870*9e39c5baSBill Taylor 	switch (state->ts_fw_cmdset) {
1871*9e39c5baSBill Taylor 	case TAVOR_FLASH_AMD_CMDSET:
1872*9e39c5baSBill Taylor 		/* Issue Flash Chip Erase Command */
1873*9e39c5baSBill Taylor 		tavor_flash_write(state, 0, 0xAA);
1874*9e39c5baSBill Taylor 		tavor_flash_write(state, 0, 0x55);
1875*9e39c5baSBill Taylor 		tavor_flash_write(state, 0, 0x80);
1876*9e39c5baSBill Taylor 		tavor_flash_write(state, 0, 0xAA);
1877*9e39c5baSBill Taylor 		tavor_flash_write(state, 0, 0x55);
1878*9e39c5baSBill Taylor 		tavor_flash_write(state, 0, 0x10);
1879*9e39c5baSBill Taylor 
1880*9e39c5baSBill Taylor 		/*
1881*9e39c5baSBill Taylor 		 * Wait for Chip Erase to Complete
1882*9e39c5baSBill Taylor 		 *   1) Wait 1usec
1883*9e39c5baSBill Taylor 		 *   2) read the status at the base addr of the sector
1884*9e39c5baSBill Taylor 		 *   3) Determine if we have timed out
1885*9e39c5baSBill Taylor 		 *   4) Compare status of address with the value of a
1886*9e39c5baSBill Taylor 		 *	fully erased quadlet. If these are equal, the
1887*9e39c5baSBill Taylor 		 *	chip has been erased.
1888*9e39c5baSBill Taylor 		 */
1889*9e39c5baSBill Taylor 		i = 0;
1890*9e39c5baSBill Taylor 		do {
1891*9e39c5baSBill Taylor 			/* wait 1usec */
1892*9e39c5baSBill Taylor 			drv_usecwait(1);
1893*9e39c5baSBill Taylor 			stat = tavor_flash_read(state, 0);
1894*9e39c5baSBill Taylor 
1895*9e39c5baSBill Taylor 			if (i == tavor_hw_flash_timeout_erase) {
1896*9e39c5baSBill Taylor 				cmn_err(CE_WARN,
1897*9e39c5baSBill Taylor 				    "tavor_flash_erase_chip: erase timeout\n");
1898*9e39c5baSBill Taylor 				status = EIO;
1899*9e39c5baSBill Taylor 				break;
1900*9e39c5baSBill Taylor 			}
1901*9e39c5baSBill Taylor 
1902*9e39c5baSBill Taylor 			i++;
1903*9e39c5baSBill Taylor 		} while (stat != 0xFFFFFFFF);
1904*9e39c5baSBill Taylor 		break;
1905*9e39c5baSBill Taylor 
1906*9e39c5baSBill Taylor 	case TAVOR_FLASH_INTEL_CMDSET:
1907*9e39c5baSBill Taylor 		/*
1908*9e39c5baSBill Taylor 		 * The Intel chip doesn't have a chip erase command, so erase
1909*9e39c5baSBill Taylor 		 * all blocks one at a time.
1910*9e39c5baSBill Taylor 		 */
1911*9e39c5baSBill Taylor 		size = (0x1 << state->ts_fw_log_sector_sz);
1912*9e39c5baSBill Taylor 		num_sect = state->ts_fw_device_sz / size;
1913*9e39c5baSBill Taylor 
1914*9e39c5baSBill Taylor 		for (i = 0; i < num_sect; i++) {
1915*9e39c5baSBill Taylor 			status = tavor_flash_erase_sector(state, i);
1916*9e39c5baSBill Taylor 			if (status != 0) {
1917*9e39c5baSBill Taylor 				cmn_err(CE_WARN,
1918*9e39c5baSBill Taylor 				    "tavor_flash_erase_chip: "
1919*9e39c5baSBill Taylor 				    "ICS sector %d erase error\n", i);
1920*9e39c5baSBill Taylor 				status = EIO;
1921*9e39c5baSBill Taylor 				break;
1922*9e39c5baSBill Taylor 			}
1923*9e39c5baSBill Taylor 		}
1924*9e39c5baSBill Taylor 		break;
1925*9e39c5baSBill Taylor 
1926*9e39c5baSBill Taylor 	default:
1927*9e39c5baSBill Taylor 		cmn_err(CE_WARN, "tavor_flash_erase_chip: "
1928*9e39c5baSBill Taylor 		    "unknown cmd set: 0x%x\n", state->ts_fw_cmdset);
1929*9e39c5baSBill Taylor 		status = EIO;
1930*9e39c5baSBill Taylor 		break;
1931*9e39c5baSBill Taylor 	}
1932*9e39c5baSBill Taylor 
1933*9e39c5baSBill Taylor 	TAVOR_TNF_EXIT(tavor_flash_erase_chip);
1934*9e39c5baSBill Taylor 	return (status);
1935*9e39c5baSBill Taylor }
1936*9e39c5baSBill Taylor 
1937*9e39c5baSBill Taylor /*
1938*9e39c5baSBill Taylor  * tavor_flash_bank()
1939*9e39c5baSBill Taylor  */
1940*9e39c5baSBill Taylor static void
1941*9e39c5baSBill Taylor tavor_flash_bank(tavor_state_t *state, uint32_t addr)
1942*9e39c5baSBill Taylor {
1943*9e39c5baSBill Taylor 	ddi_acc_handle_t	hdl;
1944*9e39c5baSBill Taylor 	uint32_t		bank;
1945*9e39c5baSBill Taylor 
1946*9e39c5baSBill Taylor 	TAVOR_TNF_ENTER(tavor_flash_bank);
1947*9e39c5baSBill Taylor 
1948*9e39c5baSBill Taylor 	/* Set handle */
1949*9e39c5baSBill Taylor 	hdl = state->ts_pci_cfghdl;
1950*9e39c5baSBill Taylor 
1951*9e39c5baSBill Taylor 	/* Determine the bank setting from the address */
1952*9e39c5baSBill Taylor 	bank = addr & TAVOR_HW_FLASH_BANK_MASK;
1953*9e39c5baSBill Taylor 
1954*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(state->ts_fw_flashbank))
1955*9e39c5baSBill Taylor 
1956*9e39c5baSBill Taylor 	/*
1957*9e39c5baSBill Taylor 	 * If the bank is different from the currently set bank, we need to
1958*9e39c5baSBill Taylor 	 * change it.  Also, if an 'addr' of 0 is given, this allows the
1959*9e39c5baSBill Taylor 	 * capability to force the flash bank to 0.  This is useful at init
1960*9e39c5baSBill Taylor 	 * time to initially set the bank value
1961*9e39c5baSBill Taylor 	 */
1962*9e39c5baSBill Taylor 	if (state->ts_fw_flashbank != bank || addr == 0) {
1963*9e39c5baSBill Taylor 		/* Set bank using the GPIO settings */
1964*9e39c5baSBill Taylor 		tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_DATACLEAR, 0x70);
1965*9e39c5baSBill Taylor 		tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_DATASET,
1966*9e39c5baSBill Taylor 		    (bank >> 15) & 0x70);
1967*9e39c5baSBill Taylor 
1968*9e39c5baSBill Taylor 		/* Save the bank state */
1969*9e39c5baSBill Taylor 		state->ts_fw_flashbank = bank;
1970*9e39c5baSBill Taylor 	}
1971*9e39c5baSBill Taylor 
1972*9e39c5baSBill Taylor 	TAVOR_TNF_EXIT(tavor_flash_bank);
1973*9e39c5baSBill Taylor }
1974*9e39c5baSBill Taylor 
1975*9e39c5baSBill Taylor /*
1976*9e39c5baSBill Taylor  * tavor_flash_read()
1977*9e39c5baSBill Taylor  */
1978*9e39c5baSBill Taylor static uint32_t
1979*9e39c5baSBill Taylor tavor_flash_read(tavor_state_t *state, uint32_t addr)
1980*9e39c5baSBill Taylor {
1981*9e39c5baSBill Taylor 	ddi_acc_handle_t	hdl;
1982*9e39c5baSBill Taylor 	uint32_t		data;
1983*9e39c5baSBill Taylor 	int			timeout;
1984*9e39c5baSBill Taylor 
1985*9e39c5baSBill Taylor 	TAVOR_TNF_ENTER(tavor_flash_read);
1986*9e39c5baSBill Taylor 
1987*9e39c5baSBill Taylor 	/* Set handle */
1988*9e39c5baSBill Taylor 	hdl = state->ts_pci_cfghdl;
1989*9e39c5baSBill Taylor 
1990*9e39c5baSBill Taylor 	/*
1991*9e39c5baSBill Taylor 	 * The Read operation does the following:
1992*9e39c5baSBill Taylor 	 *   1) Write the masked address to the TAVOR_FLASH_ADDR register.
1993*9e39c5baSBill Taylor 	 *	Only the least significant 19 bits are valid.
1994*9e39c5baSBill Taylor 	 *   2) Read back the register until the command has completed.
1995*9e39c5baSBill Taylor 	 *   3) Read the data retrieved from the address at the TAVOR_FLASH_DATA
1996*9e39c5baSBill Taylor 	 *	register.
1997*9e39c5baSBill Taylor 	 */
1998*9e39c5baSBill Taylor 	tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_ADDR,
1999*9e39c5baSBill Taylor 	    (addr & TAVOR_HW_FLASH_ADDR_MASK) | (1 << 29));
2000*9e39c5baSBill Taylor 
2001*9e39c5baSBill Taylor 	timeout = 0;
2002*9e39c5baSBill Taylor 	do {
2003*9e39c5baSBill Taylor 		data = tavor_flash_read_cfg(hdl, TAVOR_HW_FLASH_ADDR);
2004*9e39c5baSBill Taylor 		timeout++;
2005*9e39c5baSBill Taylor 	} while ((data & TAVOR_HW_FLASH_CMD_MASK) &&
2006*9e39c5baSBill Taylor 	    (timeout < tavor_hw_flash_timeout_config));
2007*9e39c5baSBill Taylor 
2008*9e39c5baSBill Taylor 	if (timeout == tavor_hw_flash_timeout_config) {
2009*9e39c5baSBill Taylor 		cmn_err(CE_WARN, "tavor_flash_read: config command timeout.\n");
2010*9e39c5baSBill Taylor 	}
2011*9e39c5baSBill Taylor 
2012*9e39c5baSBill Taylor 	data = tavor_flash_read_cfg(hdl, TAVOR_HW_FLASH_DATA);
2013*9e39c5baSBill Taylor 
2014*9e39c5baSBill Taylor 	TAVOR_TNF_EXIT(tavor_flash_read);
2015*9e39c5baSBill Taylor 	return (data);
2016*9e39c5baSBill Taylor }
2017*9e39c5baSBill Taylor 
2018*9e39c5baSBill Taylor /*
2019*9e39c5baSBill Taylor  * tavor_flash_write()
2020*9e39c5baSBill Taylor  */
2021*9e39c5baSBill Taylor static void
2022*9e39c5baSBill Taylor tavor_flash_write(tavor_state_t *state, uint32_t addr, uchar_t data)
2023*9e39c5baSBill Taylor {
2024*9e39c5baSBill Taylor 	ddi_acc_handle_t	hdl;
2025*9e39c5baSBill Taylor 	int			cmd;
2026*9e39c5baSBill Taylor 	int			timeout;
2027*9e39c5baSBill Taylor 
2028*9e39c5baSBill Taylor 	TAVOR_TNF_ENTER(tavor_flash_write);
2029*9e39c5baSBill Taylor 
2030*9e39c5baSBill Taylor 	/* Set handle */
2031*9e39c5baSBill Taylor 	hdl = state->ts_pci_cfghdl;
2032*9e39c5baSBill Taylor 
2033*9e39c5baSBill Taylor 	/*
2034*9e39c5baSBill Taylor 	 * The Write operation does the following:
2035*9e39c5baSBill Taylor 	 *   1) Write the data to be written to the TAVOR_FLASH_DATA offset.
2036*9e39c5baSBill Taylor 	 *   2) Write the address to write the data to to the TAVOR_FLASH_ADDR
2037*9e39c5baSBill Taylor 	 *	offset.
2038*9e39c5baSBill Taylor 	 *   3) Wait until the write completes.
2039*9e39c5baSBill Taylor 	 */
2040*9e39c5baSBill Taylor 	tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_DATA, data << 24);
2041*9e39c5baSBill Taylor 	tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_ADDR,
2042*9e39c5baSBill Taylor 	    (addr & 0x7FFFF) | (2 << 29));
2043*9e39c5baSBill Taylor 
2044*9e39c5baSBill Taylor 	timeout = 0;
2045*9e39c5baSBill Taylor 	do {
2046*9e39c5baSBill Taylor 		cmd = tavor_flash_read_cfg(hdl, TAVOR_HW_FLASH_ADDR);
2047*9e39c5baSBill Taylor 		timeout++;
2048*9e39c5baSBill Taylor 	} while ((cmd & TAVOR_HW_FLASH_CMD_MASK) &&
2049*9e39c5baSBill Taylor 	    (timeout < tavor_hw_flash_timeout_config));
2050*9e39c5baSBill Taylor 
2051*9e39c5baSBill Taylor 	if (timeout == tavor_hw_flash_timeout_config) {
2052*9e39c5baSBill Taylor 		cmn_err(CE_WARN, "tavor_flash_write: config cmd timeout.\n");
2053*9e39c5baSBill Taylor 	}
2054*9e39c5baSBill Taylor 
2055*9e39c5baSBill Taylor 	TAVOR_TNF_EXIT(tavor_flash_write);
2056*9e39c5baSBill Taylor }
2057*9e39c5baSBill Taylor 
2058*9e39c5baSBill Taylor /*
2059*9e39c5baSBill Taylor  * tavor_flash_init()
2060*9e39c5baSBill Taylor  */
2061*9e39c5baSBill Taylor static void
2062*9e39c5baSBill Taylor tavor_flash_init(tavor_state_t *state)
2063*9e39c5baSBill Taylor {
2064*9e39c5baSBill Taylor 	uint32_t		word;
2065*9e39c5baSBill Taylor 	ddi_acc_handle_t	hdl;
2066*9e39c5baSBill Taylor 	int			sema_cnt;
2067*9e39c5baSBill Taylor 	int			gpio;
2068*9e39c5baSBill Taylor 
2069*9e39c5baSBill Taylor 	TAVOR_TNF_ENTER(tavor_flash_init);
2070*9e39c5baSBill Taylor 
2071*9e39c5baSBill Taylor 	/* Set handle */
2072*9e39c5baSBill Taylor 	hdl = state->ts_pci_cfghdl;
2073*9e39c5baSBill Taylor 
2074*9e39c5baSBill Taylor 	/* Init the flash */
2075*9e39c5baSBill Taylor 
2076*9e39c5baSBill Taylor 	/*
2077*9e39c5baSBill Taylor 	 * Grab the GPIO semaphore.  This allows us exclusive access to the
2078*9e39c5baSBill Taylor 	 * GPIO settings on the Tavor for the duration of the flash burning
2079*9e39c5baSBill Taylor 	 * procedure.
2080*9e39c5baSBill Taylor 	 */
2081*9e39c5baSBill Taylor 	sema_cnt = 0;
2082*9e39c5baSBill Taylor 	do {
2083*9e39c5baSBill Taylor 		word = tavor_flash_read_cfg(hdl, TAVOR_HW_FLASH_GPIO_SEMA);
2084*9e39c5baSBill Taylor 		if (word == 0) {
2085*9e39c5baSBill Taylor 			break;
2086*9e39c5baSBill Taylor 		}
2087*9e39c5baSBill Taylor 
2088*9e39c5baSBill Taylor 		sema_cnt++;
2089*9e39c5baSBill Taylor 		drv_usecwait(1);
2090*9e39c5baSBill Taylor 	} while (sema_cnt < tavor_hw_flash_timeout_gpio_sema);
2091*9e39c5baSBill Taylor 
2092*9e39c5baSBill Taylor 	/*
2093*9e39c5baSBill Taylor 	 * Determine if we timed out trying to grab the GPIO semaphore
2094*9e39c5baSBill Taylor 	 */
2095*9e39c5baSBill Taylor 	if (sema_cnt == tavor_hw_flash_timeout_gpio_sema) {
2096*9e39c5baSBill Taylor 		cmn_err(CE_WARN, "tavor_flash_init: GPIO SEMA timeout\n");
2097*9e39c5baSBill Taylor 	}
2098*9e39c5baSBill Taylor 
2099*9e39c5baSBill Taylor 	/* Save away original GPIO Values */
2100*9e39c5baSBill Taylor 	state->ts_fw_gpio[0] = tavor_flash_read_cfg(hdl,
2101*9e39c5baSBill Taylor 	    TAVOR_HW_FLASH_GPIO_DIR);
2102*9e39c5baSBill Taylor 	state->ts_fw_gpio[1] = tavor_flash_read_cfg(hdl,
2103*9e39c5baSBill Taylor 	    TAVOR_HW_FLASH_GPIO_POL);
2104*9e39c5baSBill Taylor 	state->ts_fw_gpio[2] = tavor_flash_read_cfg(hdl,
2105*9e39c5baSBill Taylor 	    TAVOR_HW_FLASH_GPIO_MOD);
2106*9e39c5baSBill Taylor 	state->ts_fw_gpio[3] = tavor_flash_read_cfg(hdl,
2107*9e39c5baSBill Taylor 	    TAVOR_HW_FLASH_GPIO_DAT);
2108*9e39c5baSBill Taylor 
2109*9e39c5baSBill Taylor 	/* Set New GPIO Values */
2110*9e39c5baSBill Taylor 	gpio = state->ts_fw_gpio[0] | 0x70;
2111*9e39c5baSBill Taylor 	tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_DIR, gpio);
2112*9e39c5baSBill Taylor 
2113*9e39c5baSBill Taylor 	gpio = state->ts_fw_gpio[1] & ~0x70;
2114*9e39c5baSBill Taylor 	tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_POL, gpio);
2115*9e39c5baSBill Taylor 
2116*9e39c5baSBill Taylor 	gpio = state->ts_fw_gpio[2] & ~0x70;
2117*9e39c5baSBill Taylor 	tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_MOD, gpio);
2118*9e39c5baSBill Taylor 
2119*9e39c5baSBill Taylor 	/* Set CPUMODE to enable tavor to access the flash device */
2120*9e39c5baSBill Taylor 	tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_CPUMODE,
2121*9e39c5baSBill Taylor 	    1 << TAVOR_HW_FLASH_CPU_SHIFT);
2122*9e39c5baSBill Taylor 
2123*9e39c5baSBill Taylor 	/* Initialize to bank 0 */
2124*9e39c5baSBill Taylor 	tavor_flash_bank(state, 0);
2125*9e39c5baSBill Taylor 
2126*9e39c5baSBill Taylor 	TAVOR_TNF_EXIT(tavor_flash_init);
2127*9e39c5baSBill Taylor }
2128*9e39c5baSBill Taylor 
2129*9e39c5baSBill Taylor /*
2130*9e39c5baSBill Taylor  * tavor_flash_cfi_init
2131*9e39c5baSBill Taylor  *   Implements access to the CFI (Common Flash Interface) data
2132*9e39c5baSBill Taylor  */
2133*9e39c5baSBill Taylor static void
2134*9e39c5baSBill Taylor tavor_flash_cfi_init(tavor_state_t *state, uint32_t *cfi_info, int *intel_xcmd)
2135*9e39c5baSBill Taylor {
2136*9e39c5baSBill Taylor 	uint32_t	data;
2137*9e39c5baSBill Taylor 	uint32_t	sector_sz_bytes;
2138*9e39c5baSBill Taylor 	uint32_t	bit_count;
2139*9e39c5baSBill Taylor 	uint8_t		cfi_ch_info[TAVOR_CFI_INFO_SIZE];
2140*9e39c5baSBill Taylor 	uint32_t	cfi_dw_info[TAVOR_CFI_INFO_QSIZE];
2141*9e39c5baSBill Taylor 	int		i;
2142*9e39c5baSBill Taylor 
2143*9e39c5baSBill Taylor 	TAVOR_TNF_ENTER(tavor_flash_cfi_init);
2144*9e39c5baSBill Taylor 
2145*9e39c5baSBill Taylor 	/*
2146*9e39c5baSBill Taylor 	 * Determine if the user command supports the Intel Extended
2147*9e39c5baSBill Taylor 	 * Command Set. The query string is contained in the fourth
2148*9e39c5baSBill Taylor 	 * quad word.
2149*9e39c5baSBill Taylor 	 */
2150*9e39c5baSBill Taylor 	tavor_flash_cfi_byte(cfi_ch_info, cfi_info[0x04], 0x10);
2151*9e39c5baSBill Taylor 	if (cfi_ch_info[0x10] == 'M' &&
2152*9e39c5baSBill Taylor 	    cfi_ch_info[0x11] == 'X' &&
2153*9e39c5baSBill Taylor 	    cfi_ch_info[0x12] == '2') {
2154*9e39c5baSBill Taylor 		*intel_xcmd = 1; /* support is there */
2155*9e39c5baSBill Taylor 	}
2156*9e39c5baSBill Taylor 
2157*9e39c5baSBill Taylor 	/* CFI QUERY */
2158*9e39c5baSBill Taylor 	tavor_flash_write(state, 0x55, TAVOR_FLASH_CFI_INIT);
2159*9e39c5baSBill Taylor 
2160*9e39c5baSBill Taylor 	/* Read in CFI data */
2161*9e39c5baSBill Taylor 	for (i = 0; i < TAVOR_CFI_INFO_SIZE; i += 4) {
2162*9e39c5baSBill Taylor 		data = tavor_flash_read(state, i);
2163*9e39c5baSBill Taylor 		cfi_dw_info[i >> 2] = data;
2164*9e39c5baSBill Taylor 		tavor_flash_cfi_byte(cfi_ch_info, data, i);
2165*9e39c5baSBill Taylor 	}
2166*9e39c5baSBill Taylor 
2167*9e39c5baSBill Taylor 	/* Determine chip set */
2168*9e39c5baSBill Taylor 	state->ts_fw_cmdset = TAVOR_FLASH_UNKNOWN_CMDSET;
2169*9e39c5baSBill Taylor 	if (cfi_ch_info[0x20] == 'Q' &&
2170*9e39c5baSBill Taylor 	    cfi_ch_info[0x22] == 'R' &&
2171*9e39c5baSBill Taylor 	    cfi_ch_info[0x24] == 'Y') {
2172*9e39c5baSBill Taylor 		/*
2173*9e39c5baSBill Taylor 		 * Mode: x16 working in x8 mode (Intel).
2174*9e39c5baSBill Taylor 		 * Pack data - skip spacing bytes.
2175*9e39c5baSBill Taylor 		 */
2176*9e39c5baSBill Taylor 		for (i = 0; i < TAVOR_CFI_INFO_SIZE; i += 2) {
2177*9e39c5baSBill Taylor 			cfi_ch_info[i/2] = cfi_ch_info[i];
2178*9e39c5baSBill Taylor 		}
2179*9e39c5baSBill Taylor 	}
2180*9e39c5baSBill Taylor 	state->ts_fw_cmdset = cfi_ch_info[0x13];
2181*9e39c5baSBill Taylor 	if (state->ts_fw_cmdset != TAVOR_FLASH_INTEL_CMDSET &&
2182*9e39c5baSBill Taylor 	    state->ts_fw_cmdset != TAVOR_FLASH_AMD_CMDSET) {
2183*9e39c5baSBill Taylor 		cmn_err(CE_WARN,
2184*9e39c5baSBill Taylor 		    "tavor_flash_cfi_init: UNKNOWN chip cmd set\n");
2185*9e39c5baSBill Taylor 		state->ts_fw_cmdset = TAVOR_FLASH_UNKNOWN_CMDSET;
2186*9e39c5baSBill Taylor 		goto out;
2187*9e39c5baSBill Taylor 	}
2188*9e39c5baSBill Taylor 
2189*9e39c5baSBill Taylor 	/* Determine total bytes in one sector size */
2190*9e39c5baSBill Taylor 	sector_sz_bytes = ((cfi_ch_info[0x30] << 8) | cfi_ch_info[0x2F]) << 8;
2191*9e39c5baSBill Taylor 
2192*9e39c5baSBill Taylor 	/* Calculate equivalent of log2 (n) */
2193*9e39c5baSBill Taylor 	for (bit_count = 0; sector_sz_bytes > 1; bit_count++) {
2194*9e39c5baSBill Taylor 		sector_sz_bytes >>= 1;
2195*9e39c5baSBill Taylor 	}
2196*9e39c5baSBill Taylor 
2197*9e39c5baSBill Taylor 	/* Set sector size */
2198*9e39c5baSBill Taylor 	state->ts_fw_log_sector_sz = bit_count;
2199*9e39c5baSBill Taylor 
2200*9e39c5baSBill Taylor 	/* Set flash size */
2201*9e39c5baSBill Taylor 	state->ts_fw_device_sz = 0x1 << cfi_ch_info[0x27];
2202*9e39c5baSBill Taylor 
2203*9e39c5baSBill Taylor 	/* Reset to turn off CFI mode */
2204*9e39c5baSBill Taylor 	tavor_flash_reset(state);
2205*9e39c5baSBill Taylor 
2206*9e39c5baSBill Taylor 	/*
2207*9e39c5baSBill Taylor 	 * Pass CFI data back to user command.
2208*9e39c5baSBill Taylor 	 */
2209*9e39c5baSBill Taylor 	for (i = 0; i < TAVOR_FLASH_CFI_SIZE_QUADLET; i++) {
2210*9e39c5baSBill Taylor 		tavor_flash_cfi_dword(&cfi_info[i], cfi_ch_info, i << 2);
2211*9e39c5baSBill Taylor 	}
2212*9e39c5baSBill Taylor 
2213*9e39c5baSBill Taylor 	if (*intel_xcmd == 1) {
2214*9e39c5baSBill Taylor 		/*
2215*9e39c5baSBill Taylor 		 * Inform the user cmd that this driver does support the
2216*9e39c5baSBill Taylor 		 * Intel Extended Command Set.
2217*9e39c5baSBill Taylor 		 */
2218*9e39c5baSBill Taylor 		cfi_ch_info[0x10] = 'M';
2219*9e39c5baSBill Taylor 		cfi_ch_info[0x11] = 'X';
2220*9e39c5baSBill Taylor 		cfi_ch_info[0x12] = '2';
2221*9e39c5baSBill Taylor 	} else {
2222*9e39c5baSBill Taylor 		cfi_ch_info[0x10] = 'Q';
2223*9e39c5baSBill Taylor 		cfi_ch_info[0x11] = 'R';
2224*9e39c5baSBill Taylor 		cfi_ch_info[0x12] = 'Y';
2225*9e39c5baSBill Taylor 	}
2226*9e39c5baSBill Taylor 	cfi_ch_info[0x13] = state->ts_fw_cmdset;
2227*9e39c5baSBill Taylor 	tavor_flash_cfi_dword(&cfi_info[0x4], cfi_ch_info, 0x10);
2228*9e39c5baSBill Taylor out:
2229*9e39c5baSBill Taylor 	TAVOR_TNF_EXIT(tavor_flash_cfi_init);
2230*9e39c5baSBill Taylor }
2231*9e39c5baSBill Taylor 
2232*9e39c5baSBill Taylor /*
2233*9e39c5baSBill Taylor  * tavor_flash_fini()
2234*9e39c5baSBill Taylor  */
2235*9e39c5baSBill Taylor static void
2236*9e39c5baSBill Taylor tavor_flash_fini(tavor_state_t *state)
2237*9e39c5baSBill Taylor {
2238*9e39c5baSBill Taylor 	ddi_acc_handle_t hdl;
2239*9e39c5baSBill Taylor 
2240*9e39c5baSBill Taylor 	TAVOR_TNF_ENTER(tavor_flash_fini);
2241*9e39c5baSBill Taylor 
2242*9e39c5baSBill Taylor 	/* Set handle */
2243*9e39c5baSBill Taylor 	hdl = state->ts_pci_cfghdl;
2244*9e39c5baSBill Taylor 
2245*9e39c5baSBill Taylor 	/* Restore original GPIO Values */
2246*9e39c5baSBill Taylor 	tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_DIR,
2247*9e39c5baSBill Taylor 	    state->ts_fw_gpio[0]);
2248*9e39c5baSBill Taylor 	tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_POL,
2249*9e39c5baSBill Taylor 	    state->ts_fw_gpio[1]);
2250*9e39c5baSBill Taylor 	tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_MOD,
2251*9e39c5baSBill Taylor 	    state->ts_fw_gpio[2]);
2252*9e39c5baSBill Taylor 	tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_DAT,
2253*9e39c5baSBill Taylor 	    state->ts_fw_gpio[3]);
2254*9e39c5baSBill Taylor 
2255*9e39c5baSBill Taylor 	/* Give up semaphore */
2256*9e39c5baSBill Taylor 	tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_SEMA, 0);
2257*9e39c5baSBill Taylor 
2258*9e39c5baSBill Taylor 	TAVOR_TNF_EXIT(tavor_flash_fini);
2259*9e39c5baSBill Taylor }
2260*9e39c5baSBill Taylor 
2261*9e39c5baSBill Taylor /*
2262*9e39c5baSBill Taylor  * tavor_flash_read_cfg
2263*9e39c5baSBill Taylor  */
2264*9e39c5baSBill Taylor static uint32_t
2265*9e39c5baSBill Taylor tavor_flash_read_cfg(ddi_acc_handle_t pci_config_hdl, uint32_t addr)
2266*9e39c5baSBill Taylor {
2267*9e39c5baSBill Taylor 	uint32_t	read;
2268*9e39c5baSBill Taylor 
2269*9e39c5baSBill Taylor 	TAVOR_TNF_ENTER(tavor_flash_read_cfg);
2270*9e39c5baSBill Taylor 
2271*9e39c5baSBill Taylor 	/*
2272*9e39c5baSBill Taylor 	 * Perform flash read operation:
2273*9e39c5baSBill Taylor 	 *   1) Place addr to read from on the TAVOR_HW_FLASH_CFG_ADDR register
2274*9e39c5baSBill Taylor 	 *   2) Read data at that addr from the TAVOR_HW_FLASH_CFG_DATA register
2275*9e39c5baSBill Taylor 	 */
2276*9e39c5baSBill Taylor 	pci_config_put32(pci_config_hdl, TAVOR_HW_FLASH_CFG_ADDR, addr);
2277*9e39c5baSBill Taylor 	read = pci_config_get32(pci_config_hdl, TAVOR_HW_FLASH_CFG_DATA);
2278*9e39c5baSBill Taylor 
2279*9e39c5baSBill Taylor 	TAVOR_TNF_EXIT(tavor_flash_read_cfg);
2280*9e39c5baSBill Taylor 
2281*9e39c5baSBill Taylor 	return (read);
2282*9e39c5baSBill Taylor }
2283*9e39c5baSBill Taylor 
2284*9e39c5baSBill Taylor /*
2285*9e39c5baSBill Taylor  * tavor_flash_write_cfg
2286*9e39c5baSBill Taylor  */
2287*9e39c5baSBill Taylor static void
2288*9e39c5baSBill Taylor tavor_flash_write_cfg(ddi_acc_handle_t pci_config_hdl, uint32_t addr,
2289*9e39c5baSBill Taylor     uint32_t data)
2290*9e39c5baSBill Taylor {
2291*9e39c5baSBill Taylor 	TAVOR_TNF_ENTER(tavor_flash_write_cfg);
2292*9e39c5baSBill Taylor 
2293*9e39c5baSBill Taylor 	/*
2294*9e39c5baSBill Taylor 	 * Perform flash write operation:
2295*9e39c5baSBill Taylor 	 *   1) Place addr to write to on the TAVOR_HW_FLASH_CFG_ADDR register
2296*9e39c5baSBill Taylor 	 *   2) Place data to write on to the TAVOR_HW_FLASH_CFG_DATA register
2297*9e39c5baSBill Taylor 	 */
2298*9e39c5baSBill Taylor 	pci_config_put32(pci_config_hdl, TAVOR_HW_FLASH_CFG_ADDR, addr);
2299*9e39c5baSBill Taylor 	pci_config_put32(pci_config_hdl, TAVOR_HW_FLASH_CFG_DATA, data);
2300*9e39c5baSBill Taylor 
2301*9e39c5baSBill Taylor 	TAVOR_TNF_EXIT(tavor_flash_write_cfg);
2302*9e39c5baSBill Taylor }
2303*9e39c5baSBill Taylor 
2304*9e39c5baSBill Taylor /*
2305*9e39c5baSBill Taylor  * Support routines to convert Common Flash Interface (CFI) data
2306*9e39c5baSBill Taylor  * from a 32  bit word to a char array, and from a char array to
2307*9e39c5baSBill Taylor  * a 32 bit word.
2308*9e39c5baSBill Taylor  */
2309*9e39c5baSBill Taylor static void
2310*9e39c5baSBill Taylor tavor_flash_cfi_byte(uint8_t *ch, uint32_t dword, int i)
2311*9e39c5baSBill Taylor {
2312*9e39c5baSBill Taylor 	ch[i] = (uint8_t)((dword & 0xFF000000) >> 24);
2313*9e39c5baSBill Taylor 	ch[i+1] = (uint8_t)((dword & 0x00FF0000) >> 16);
2314*9e39c5baSBill Taylor 	ch[i+2] = (uint8_t)((dword & 0x0000FF00) >> 8);
2315*9e39c5baSBill Taylor 	ch[i+3] = (uint8_t)((dword & 0x000000FF));
2316*9e39c5baSBill Taylor }
2317*9e39c5baSBill Taylor 
2318*9e39c5baSBill Taylor static void
2319*9e39c5baSBill Taylor tavor_flash_cfi_dword(uint32_t *dword, uint8_t *ch, int i)
2320*9e39c5baSBill Taylor {
2321*9e39c5baSBill Taylor 	*dword = (uint32_t)
2322*9e39c5baSBill Taylor 	    ((uint32_t)ch[i] << 24 |
2323*9e39c5baSBill Taylor 	    (uint32_t)ch[i+1] << 16 |
2324*9e39c5baSBill Taylor 	    (uint32_t)ch[i+2] << 8 |
2325*9e39c5baSBill Taylor 	    (uint32_t)ch[i+3]);
2326*9e39c5baSBill Taylor }
2327*9e39c5baSBill Taylor 
2328*9e39c5baSBill Taylor /*
2329*9e39c5baSBill Taylor  * tavor_loopback_free_qps
2330*9e39c5baSBill Taylor  */
2331*9e39c5baSBill Taylor static void
2332*9e39c5baSBill Taylor tavor_loopback_free_qps(tavor_loopback_state_t *lstate)
2333*9e39c5baSBill Taylor {
2334*9e39c5baSBill Taylor 	int i;
2335*9e39c5baSBill Taylor 
2336*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate))
2337*9e39c5baSBill Taylor 
2338*9e39c5baSBill Taylor 	if (lstate->tls_tx.tlc_qp_hdl != NULL) {
2339*9e39c5baSBill Taylor 		(void) tavor_qp_free(lstate->tls_state,
2340*9e39c5baSBill Taylor 		    &lstate->tls_tx.tlc_qp_hdl, IBC_FREE_QP_AND_QPN, NULL,
2341*9e39c5baSBill Taylor 		    TAVOR_NOSLEEP);
2342*9e39c5baSBill Taylor 	}
2343*9e39c5baSBill Taylor 	if (lstate->tls_rx.tlc_qp_hdl != NULL) {
2344*9e39c5baSBill Taylor 		(void) tavor_qp_free(lstate->tls_state,
2345*9e39c5baSBill Taylor 		    &lstate->tls_rx.tlc_qp_hdl, IBC_FREE_QP_AND_QPN, NULL,
2346*9e39c5baSBill Taylor 		    TAVOR_NOSLEEP);
2347*9e39c5baSBill Taylor 	}
2348*9e39c5baSBill Taylor 	lstate->tls_tx.tlc_qp_hdl = NULL;
2349*9e39c5baSBill Taylor 	lstate->tls_rx.tlc_qp_hdl = NULL;
2350*9e39c5baSBill Taylor 	for (i = 0; i < 2; i++) {
2351*9e39c5baSBill Taylor 		if (lstate->tls_tx.tlc_cqhdl[i] != NULL) {
2352*9e39c5baSBill Taylor 			(void) tavor_cq_free(lstate->tls_state,
2353*9e39c5baSBill Taylor 			    &lstate->tls_tx.tlc_cqhdl[i], TAVOR_NOSLEEP);
2354*9e39c5baSBill Taylor 		}
2355*9e39c5baSBill Taylor 		if (lstate->tls_rx.tlc_cqhdl[i] != NULL) {
2356*9e39c5baSBill Taylor 			(void) tavor_cq_free(lstate->tls_state,
2357*9e39c5baSBill Taylor 			    &lstate->tls_rx.tlc_cqhdl[i], TAVOR_NOSLEEP);
2358*9e39c5baSBill Taylor 		}
2359*9e39c5baSBill Taylor 		lstate->tls_tx.tlc_cqhdl[i] = NULL;
2360*9e39c5baSBill Taylor 		lstate->tls_rx.tlc_cqhdl[i] = NULL;
2361*9e39c5baSBill Taylor 	}
2362*9e39c5baSBill Taylor }
2363*9e39c5baSBill Taylor 
2364*9e39c5baSBill Taylor /*
2365*9e39c5baSBill Taylor  * tavor_loopback_free_state
2366*9e39c5baSBill Taylor  */
2367*9e39c5baSBill Taylor static void
2368*9e39c5baSBill Taylor tavor_loopback_free_state(tavor_loopback_state_t *lstate)
2369*9e39c5baSBill Taylor {
2370*9e39c5baSBill Taylor 	tavor_loopback_free_qps(lstate);
2371*9e39c5baSBill Taylor 	if (lstate->tls_tx.tlc_mrhdl != NULL) {
2372*9e39c5baSBill Taylor 		(void) tavor_mr_deregister(lstate->tls_state,
2373*9e39c5baSBill Taylor 		    &lstate->tls_tx.tlc_mrhdl, TAVOR_MR_DEREG_ALL,
2374*9e39c5baSBill Taylor 		    TAVOR_NOSLEEP);
2375*9e39c5baSBill Taylor 	}
2376*9e39c5baSBill Taylor 	if (lstate->tls_rx.tlc_mrhdl !=  NULL) {
2377*9e39c5baSBill Taylor 		(void) tavor_mr_deregister(lstate->tls_state,
2378*9e39c5baSBill Taylor 		    &lstate->tls_rx.tlc_mrhdl, TAVOR_MR_DEREG_ALL,
2379*9e39c5baSBill Taylor 		    TAVOR_NOSLEEP);
2380*9e39c5baSBill Taylor 	}
2381*9e39c5baSBill Taylor 	if (lstate->tls_pd_hdl != NULL) {
2382*9e39c5baSBill Taylor 		(void) tavor_pd_free(lstate->tls_state, &lstate->tls_pd_hdl);
2383*9e39c5baSBill Taylor 	}
2384*9e39c5baSBill Taylor 	if (lstate->tls_tx.tlc_buf != NULL) {
2385*9e39c5baSBill Taylor 		kmem_free(lstate->tls_tx.tlc_buf, lstate->tls_tx.tlc_buf_sz);
2386*9e39c5baSBill Taylor 	}
2387*9e39c5baSBill Taylor 	if (lstate->tls_rx.tlc_buf != NULL) {
2388*9e39c5baSBill Taylor 		kmem_free(lstate->tls_rx.tlc_buf, lstate->tls_rx.tlc_buf_sz);
2389*9e39c5baSBill Taylor 	}
2390*9e39c5baSBill Taylor 	bzero(lstate, sizeof (tavor_loopback_state_t));
2391*9e39c5baSBill Taylor }
2392*9e39c5baSBill Taylor 
2393*9e39c5baSBill Taylor /*
2394*9e39c5baSBill Taylor  * tavor_loopback_init
2395*9e39c5baSBill Taylor  */
2396*9e39c5baSBill Taylor static int
2397*9e39c5baSBill Taylor tavor_loopback_init(tavor_state_t *state, tavor_loopback_state_t *lstate)
2398*9e39c5baSBill Taylor {
2399*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate))
2400*9e39c5baSBill Taylor 
2401*9e39c5baSBill Taylor 	lstate->tls_hca_hdl = (ibc_hca_hdl_t)state;
2402*9e39c5baSBill Taylor 	lstate->tls_status  = tavor_pd_alloc(lstate->tls_state,
2403*9e39c5baSBill Taylor 	    &lstate->tls_pd_hdl, TAVOR_NOSLEEP);
2404*9e39c5baSBill Taylor 	if (lstate->tls_status != IBT_SUCCESS) {
2405*9e39c5baSBill Taylor 		lstate->tls_err = TAVOR_LOOPBACK_PROT_DOMAIN_ALLOC_FAIL;
2406*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_loopback_alloc_pd_fail,
2407*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
2408*9e39c5baSBill Taylor 		return (EFAULT);
2409*9e39c5baSBill Taylor 	}
2410*9e39c5baSBill Taylor 
2411*9e39c5baSBill Taylor 	return (0);
2412*9e39c5baSBill Taylor }
2413*9e39c5baSBill Taylor 
2414*9e39c5baSBill Taylor /*
2415*9e39c5baSBill Taylor  * tavor_loopback_init_qp_info
2416*9e39c5baSBill Taylor  */
2417*9e39c5baSBill Taylor static void
2418*9e39c5baSBill Taylor tavor_loopback_init_qp_info(tavor_loopback_state_t *lstate,
2419*9e39c5baSBill Taylor     tavor_loopback_comm_t *comm)
2420*9e39c5baSBill Taylor {
2421*9e39c5baSBill Taylor 	bzero(&comm->tlc_cq_attr, sizeof (ibt_cq_attr_t));
2422*9e39c5baSBill Taylor 	bzero(&comm->tlc_qp_attr, sizeof (ibt_qp_alloc_attr_t));
2423*9e39c5baSBill Taylor 	bzero(&comm->tlc_qp_info, sizeof (ibt_qp_info_t));
2424*9e39c5baSBill Taylor 
2425*9e39c5baSBill Taylor 	comm->tlc_wrid = 1;
2426*9e39c5baSBill Taylor 	comm->tlc_cq_attr.cq_size = 128;
2427*9e39c5baSBill Taylor 	comm->tlc_qp_attr.qp_sizes.cs_sq_sgl = 3;
2428*9e39c5baSBill Taylor 	comm->tlc_qp_attr.qp_sizes.cs_rq_sgl = 3;
2429*9e39c5baSBill Taylor 	comm->tlc_qp_attr.qp_sizes.cs_sq = 16;
2430*9e39c5baSBill Taylor 	comm->tlc_qp_attr.qp_sizes.cs_rq = 16;
2431*9e39c5baSBill Taylor 	comm->tlc_qp_attr.qp_flags = IBT_WR_SIGNALED;
2432*9e39c5baSBill Taylor 
2433*9e39c5baSBill Taylor 	comm->tlc_qp_info.qp_state = IBT_STATE_RESET;
2434*9e39c5baSBill Taylor 	comm->tlc_qp_info.qp_trans = IBT_RC_SRV;
2435*9e39c5baSBill Taylor 	comm->tlc_qp_info.qp_flags = IBT_CEP_RDMA_RD | IBT_CEP_RDMA_WR;
2436*9e39c5baSBill Taylor 	comm->tlc_qp_info.qp_transport.rc.rc_path.cep_hca_port_num =
2437*9e39c5baSBill Taylor 	    lstate->tls_port;
2438*9e39c5baSBill Taylor 	comm->tlc_qp_info.qp_transport.rc.rc_path.cep_pkey_ix =
2439*9e39c5baSBill Taylor 	    lstate->tls_pkey_ix;
2440*9e39c5baSBill Taylor 	comm->tlc_qp_info.qp_transport.rc.rc_path.cep_timeout =
2441*9e39c5baSBill Taylor 	    lstate->tls_timeout;
2442*9e39c5baSBill Taylor 	comm->tlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_srvl = 0;
2443*9e39c5baSBill Taylor 	comm->tlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_srate =
2444*9e39c5baSBill Taylor 	    IBT_SRATE_4X;
2445*9e39c5baSBill Taylor 	comm->tlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_send_grh = 0;
2446*9e39c5baSBill Taylor 	comm->tlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_dlid =
2447*9e39c5baSBill Taylor 	    lstate->tls_lid;
2448*9e39c5baSBill Taylor 	comm->tlc_qp_info.qp_transport.rc.rc_retry_cnt = lstate->tls_retry;
2449*9e39c5baSBill Taylor 	comm->tlc_qp_info.qp_transport.rc.rc_sq_psn = 0;
2450*9e39c5baSBill Taylor 	comm->tlc_qp_info.qp_transport.rc.rc_rq_psn = 0;
2451*9e39c5baSBill Taylor 	comm->tlc_qp_info.qp_transport.rc.rc_rdma_ra_in	 = 4;
2452*9e39c5baSBill Taylor 	comm->tlc_qp_info.qp_transport.rc.rc_rdma_ra_out = 4;
2453*9e39c5baSBill Taylor 	comm->tlc_qp_info.qp_transport.rc.rc_dst_qpn = 0;
2454*9e39c5baSBill Taylor 	comm->tlc_qp_info.qp_transport.rc.rc_min_rnr_nak = IBT_RNR_NAK_655ms;
2455*9e39c5baSBill Taylor 	comm->tlc_qp_info.qp_transport.rc.rc_path_mtu = IB_MTU_1K;
2456*9e39c5baSBill Taylor }
2457*9e39c5baSBill Taylor 
2458*9e39c5baSBill Taylor /*
2459*9e39c5baSBill Taylor  * tavor_loopback_alloc_mem
2460*9e39c5baSBill Taylor  */
2461*9e39c5baSBill Taylor static int
2462*9e39c5baSBill Taylor tavor_loopback_alloc_mem(tavor_loopback_state_t *lstate,
2463*9e39c5baSBill Taylor     tavor_loopback_comm_t *comm, int sz)
2464*9e39c5baSBill Taylor {
2465*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm))
2466*9e39c5baSBill Taylor 
2467*9e39c5baSBill Taylor 	/* Allocate buffer of specified size */
2468*9e39c5baSBill Taylor 	comm->tlc_buf_sz = sz;
2469*9e39c5baSBill Taylor 	comm->tlc_buf	 = kmem_zalloc(sz, KM_NOSLEEP);
2470*9e39c5baSBill Taylor 	if (comm->tlc_buf == NULL) {
2471*9e39c5baSBill Taylor 		return (EFAULT);
2472*9e39c5baSBill Taylor 	}
2473*9e39c5baSBill Taylor 
2474*9e39c5baSBill Taylor 	/* Register the buffer as a memory region */
2475*9e39c5baSBill Taylor 	comm->tlc_memattr.mr_vaddr = (uint64_t)(uintptr_t)comm->tlc_buf;
2476*9e39c5baSBill Taylor 	comm->tlc_memattr.mr_len   = (ib_msglen_t)sz;
2477*9e39c5baSBill Taylor 	comm->tlc_memattr.mr_as	   = NULL;
2478*9e39c5baSBill Taylor 	comm->tlc_memattr.mr_flags = IBT_MR_NOSLEEP |
2479*9e39c5baSBill Taylor 	    IBT_MR_ENABLE_REMOTE_WRITE | IBT_MR_ENABLE_LOCAL_WRITE;
2480*9e39c5baSBill Taylor 
2481*9e39c5baSBill Taylor 	comm->tlc_status = tavor_mr_register(lstate->tls_state,
2482*9e39c5baSBill Taylor 	    lstate->tls_pd_hdl, &comm->tlc_memattr, &comm->tlc_mrhdl, NULL);
2483*9e39c5baSBill Taylor 
2484*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm->tlc_mrhdl))
2485*9e39c5baSBill Taylor 
2486*9e39c5baSBill Taylor 	comm->tlc_mrdesc.md_vaddr  = comm->tlc_mrhdl->mr_bindinfo.bi_addr;
2487*9e39c5baSBill Taylor 	comm->tlc_mrdesc.md_lkey   = comm->tlc_mrhdl->mr_lkey;
2488*9e39c5baSBill Taylor 	comm->tlc_mrdesc.md_rkey   = comm->tlc_mrhdl->mr_rkey;
2489*9e39c5baSBill Taylor 	if (comm->tlc_status != IBT_SUCCESS) {
2490*9e39c5baSBill Taylor 		return (EFAULT);
2491*9e39c5baSBill Taylor 	}
2492*9e39c5baSBill Taylor 	return (0);
2493*9e39c5baSBill Taylor }
2494*9e39c5baSBill Taylor 
2495*9e39c5baSBill Taylor /*
2496*9e39c5baSBill Taylor  * tavor_loopback_alloc_qps
2497*9e39c5baSBill Taylor  */
2498*9e39c5baSBill Taylor static int
2499*9e39c5baSBill Taylor tavor_loopback_alloc_qps(tavor_loopback_state_t *lstate,
2500*9e39c5baSBill Taylor     tavor_loopback_comm_t *comm)
2501*9e39c5baSBill Taylor {
2502*9e39c5baSBill Taylor 	uint32_t		i, real_size;
2503*9e39c5baSBill Taylor 	tavor_qp_info_t		qpinfo;
2504*9e39c5baSBill Taylor 
2505*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm))
2506*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate))
2507*9e39c5baSBill Taylor 
2508*9e39c5baSBill Taylor 	/* Allocate send and recv CQs */
2509*9e39c5baSBill Taylor 	for (i = 0; i < 2; i++) {
2510*9e39c5baSBill Taylor 		bzero(&comm->tlc_cq_attr, sizeof (ibt_cq_attr_t));
2511*9e39c5baSBill Taylor 		comm->tlc_cq_attr.cq_size = 128;
2512*9e39c5baSBill Taylor 		comm->tlc_status = tavor_cq_alloc(lstate->tls_state,
2513*9e39c5baSBill Taylor 		    (ibt_cq_hdl_t)NULL, &comm->tlc_cq_attr, &real_size,
2514*9e39c5baSBill Taylor 		    &comm->tlc_cqhdl[i], TAVOR_NOSLEEP);
2515*9e39c5baSBill Taylor 		if (comm->tlc_status != IBT_SUCCESS) {
2516*9e39c5baSBill Taylor 			lstate->tls_err += i;
2517*9e39c5baSBill Taylor 			return (EFAULT);
2518*9e39c5baSBill Taylor 		}
2519*9e39c5baSBill Taylor 	}
2520*9e39c5baSBill Taylor 
2521*9e39c5baSBill Taylor 	/* Allocate the QP */
2522*9e39c5baSBill Taylor 	tavor_loopback_init_qp_info(lstate, comm);
2523*9e39c5baSBill Taylor 	comm->tlc_qp_attr.qp_pd_hdl	 = (ibt_pd_hdl_t)lstate->tls_pd_hdl;
2524*9e39c5baSBill Taylor 	comm->tlc_qp_attr.qp_scq_hdl	 = (ibt_cq_hdl_t)comm->tlc_cqhdl[0];
2525*9e39c5baSBill Taylor 	comm->tlc_qp_attr.qp_rcq_hdl	 = (ibt_cq_hdl_t)comm->tlc_cqhdl[1];
2526*9e39c5baSBill Taylor 	comm->tlc_qp_attr.qp_ibc_scq_hdl = (ibt_opaque1_t)comm->tlc_cqhdl[0];
2527*9e39c5baSBill Taylor 	comm->tlc_qp_attr.qp_ibc_rcq_hdl = (ibt_opaque1_t)comm->tlc_cqhdl[1];
2528*9e39c5baSBill Taylor 	qpinfo.qpi_attrp	= &comm->tlc_qp_attr;
2529*9e39c5baSBill Taylor 	qpinfo.qpi_type		= IBT_RC_RQP;
2530*9e39c5baSBill Taylor 	qpinfo.qpi_ibt_qphdl	= NULL;
2531*9e39c5baSBill Taylor 	qpinfo.qpi_queueszp	= &comm->tlc_chan_sizes;
2532*9e39c5baSBill Taylor 	qpinfo.qpi_qpn		= &comm->tlc_qp_num;
2533*9e39c5baSBill Taylor 	comm->tlc_status = tavor_qp_alloc(lstate->tls_state, &qpinfo,
2534*9e39c5baSBill Taylor 	    TAVOR_NOSLEEP, NULL);
2535*9e39c5baSBill Taylor 	if (comm->tlc_status == DDI_SUCCESS) {
2536*9e39c5baSBill Taylor 		comm->tlc_qp_hdl = qpinfo.qpi_qphdl;
2537*9e39c5baSBill Taylor 	}
2538*9e39c5baSBill Taylor 
2539*9e39c5baSBill Taylor 	if (comm->tlc_status != IBT_SUCCESS) {
2540*9e39c5baSBill Taylor 		lstate->tls_err += 2;
2541*9e39c5baSBill Taylor 		return (EFAULT);
2542*9e39c5baSBill Taylor 	}
2543*9e39c5baSBill Taylor 	return (0);
2544*9e39c5baSBill Taylor }
2545*9e39c5baSBill Taylor 
2546*9e39c5baSBill Taylor /*
2547*9e39c5baSBill Taylor  * tavor_loopback_modify_qp
2548*9e39c5baSBill Taylor  */
2549*9e39c5baSBill Taylor static int
2550*9e39c5baSBill Taylor tavor_loopback_modify_qp(tavor_loopback_state_t *lstate,
2551*9e39c5baSBill Taylor     tavor_loopback_comm_t *comm, uint_t qp_num)
2552*9e39c5baSBill Taylor {
2553*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm))
2554*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate))
2555*9e39c5baSBill Taylor 
2556*9e39c5baSBill Taylor 	/* Modify QP to INIT */
2557*9e39c5baSBill Taylor 	tavor_loopback_init_qp_info(lstate, comm);
2558*9e39c5baSBill Taylor 	comm->tlc_qp_info.qp_state = IBT_STATE_INIT;
2559*9e39c5baSBill Taylor 	comm->tlc_status = tavor_qp_modify(lstate->tls_state, comm->tlc_qp_hdl,
2560*9e39c5baSBill Taylor 	    IBT_CEP_SET_STATE, &comm->tlc_qp_info, &comm->tlc_queue_sizes);
2561*9e39c5baSBill Taylor 	if (comm->tlc_status != IBT_SUCCESS) {
2562*9e39c5baSBill Taylor 		return (EFAULT);
2563*9e39c5baSBill Taylor 	}
2564*9e39c5baSBill Taylor 
2565*9e39c5baSBill Taylor 	/*
2566*9e39c5baSBill Taylor 	 * Modify QP to RTR (set destination LID and QP number to local
2567*9e39c5baSBill Taylor 	 * LID and QP number)
2568*9e39c5baSBill Taylor 	 */
2569*9e39c5baSBill Taylor 	comm->tlc_qp_info.qp_state = IBT_STATE_RTR;
2570*9e39c5baSBill Taylor 	comm->tlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_dlid
2571*9e39c5baSBill Taylor 	    = lstate->tls_lid;
2572*9e39c5baSBill Taylor 	comm->tlc_qp_info.qp_transport.rc.rc_dst_qpn = qp_num;
2573*9e39c5baSBill Taylor 	comm->tlc_status = tavor_qp_modify(lstate->tls_state, comm->tlc_qp_hdl,
2574*9e39c5baSBill Taylor 	    IBT_CEP_SET_STATE, &comm->tlc_qp_info, &comm->tlc_queue_sizes);
2575*9e39c5baSBill Taylor 	if (comm->tlc_status != IBT_SUCCESS) {
2576*9e39c5baSBill Taylor 		lstate->tls_err += 1;
2577*9e39c5baSBill Taylor 		return (EFAULT);
2578*9e39c5baSBill Taylor 	}
2579*9e39c5baSBill Taylor 
2580*9e39c5baSBill Taylor 	/* Modify QP to RTS */
2581*9e39c5baSBill Taylor 	comm->tlc_qp_info.qp_current_state = IBT_STATE_RTR;
2582*9e39c5baSBill Taylor 	comm->tlc_qp_info.qp_state = IBT_STATE_RTS;
2583*9e39c5baSBill Taylor 	comm->tlc_status = tavor_qp_modify(lstate->tls_state, comm->tlc_qp_hdl,
2584*9e39c5baSBill Taylor 	    IBT_CEP_SET_STATE, &comm->tlc_qp_info, &comm->tlc_queue_sizes);
2585*9e39c5baSBill Taylor 	if (comm->tlc_status != IBT_SUCCESS) {
2586*9e39c5baSBill Taylor 		lstate->tls_err += 2;
2587*9e39c5baSBill Taylor 		return (EFAULT);
2588*9e39c5baSBill Taylor 	}
2589*9e39c5baSBill Taylor 	return (0);
2590*9e39c5baSBill Taylor }
2591*9e39c5baSBill Taylor 
2592*9e39c5baSBill Taylor /*
2593*9e39c5baSBill Taylor  * tavor_loopback_copyout
2594*9e39c5baSBill Taylor  */
2595*9e39c5baSBill Taylor static int
2596*9e39c5baSBill Taylor tavor_loopback_copyout(tavor_loopback_ioctl_t *lb, intptr_t arg, int mode)
2597*9e39c5baSBill Taylor {
2598*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
2599*9e39c5baSBill Taylor 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
2600*9e39c5baSBill Taylor 		tavor_loopback_ioctl32_t lb32;
2601*9e39c5baSBill Taylor 
2602*9e39c5baSBill Taylor 		lb32.tlb_revision	= lb->tlb_revision;
2603*9e39c5baSBill Taylor 		lb32.tlb_send_buf	=
2604*9e39c5baSBill Taylor 		    (caddr32_t)(uintptr_t)lb->tlb_send_buf;
2605*9e39c5baSBill Taylor 		lb32.tlb_fail_buf	=
2606*9e39c5baSBill Taylor 		    (caddr32_t)(uintptr_t)lb->tlb_fail_buf;
2607*9e39c5baSBill Taylor 		lb32.tlb_buf_sz		= lb->tlb_buf_sz;
2608*9e39c5baSBill Taylor 		lb32.tlb_num_iter	= lb->tlb_num_iter;
2609*9e39c5baSBill Taylor 		lb32.tlb_pass_done	= lb->tlb_pass_done;
2610*9e39c5baSBill Taylor 		lb32.tlb_timeout	= lb->tlb_timeout;
2611*9e39c5baSBill Taylor 		lb32.tlb_error_type	= lb->tlb_error_type;
2612*9e39c5baSBill Taylor 		lb32.tlb_port_num	= lb->tlb_port_num;
2613*9e39c5baSBill Taylor 		lb32.tlb_num_retry	= lb->tlb_num_retry;
2614*9e39c5baSBill Taylor 
2615*9e39c5baSBill Taylor 		if (ddi_copyout(&lb32, (void *)arg,
2616*9e39c5baSBill Taylor 		    sizeof (tavor_loopback_ioctl32_t), mode) != 0) {
2617*9e39c5baSBill Taylor 			TNF_PROBE_0(tavor_ioctl_loopback_copyout_fail,
2618*9e39c5baSBill Taylor 			    TAVOR_TNF_ERROR, "");
2619*9e39c5baSBill Taylor 			return (EFAULT);
2620*9e39c5baSBill Taylor 		}
2621*9e39c5baSBill Taylor 	} else
2622*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
2623*9e39c5baSBill Taylor 	if (ddi_copyout(lb, (void *)arg, sizeof (tavor_loopback_ioctl_t),
2624*9e39c5baSBill Taylor 	    mode) != 0) {
2625*9e39c5baSBill Taylor 		TNF_PROBE_0(tavor_ioctl_loopback_copyout_fail,
2626*9e39c5baSBill Taylor 		    TAVOR_TNF_ERROR, "");
2627*9e39c5baSBill Taylor 		return (EFAULT);
2628*9e39c5baSBill Taylor 	}
2629*9e39c5baSBill Taylor 	return (0);
2630*9e39c5baSBill Taylor }
2631*9e39c5baSBill Taylor 
2632*9e39c5baSBill Taylor /*
2633*9e39c5baSBill Taylor  * tavor_loopback_post_send
2634*9e39c5baSBill Taylor  */
2635*9e39c5baSBill Taylor static int
2636*9e39c5baSBill Taylor tavor_loopback_post_send(tavor_loopback_state_t *lstate,
2637*9e39c5baSBill Taylor     tavor_loopback_comm_t *tx, tavor_loopback_comm_t *rx)
2638*9e39c5baSBill Taylor {
2639*9e39c5baSBill Taylor 	int	 ret;
2640*9e39c5baSBill Taylor 
2641*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*tx))
2642*9e39c5baSBill Taylor 
2643*9e39c5baSBill Taylor 	bzero(&tx->tlc_sgl, sizeof (ibt_wr_ds_t));
2644*9e39c5baSBill Taylor 	bzero(&tx->tlc_wr, sizeof (ibt_send_wr_t));
2645*9e39c5baSBill Taylor 
2646*9e39c5baSBill Taylor 	/* Initialize local address for TX buffer */
2647*9e39c5baSBill Taylor 	tx->tlc_sgl.ds_va   = tx->tlc_mrdesc.md_vaddr;
2648*9e39c5baSBill Taylor 	tx->tlc_sgl.ds_key  = tx->tlc_mrdesc.md_lkey;
2649*9e39c5baSBill Taylor 	tx->tlc_sgl.ds_len  = tx->tlc_buf_sz;
2650*9e39c5baSBill Taylor 
2651*9e39c5baSBill Taylor 	/* Initialize the remaining details of the work request */
2652*9e39c5baSBill Taylor 	tx->tlc_wr.wr_id = tx->tlc_wrid++;
2653*9e39c5baSBill Taylor 	tx->tlc_wr.wr_flags  = IBT_WR_SEND_SIGNAL;
2654*9e39c5baSBill Taylor 	tx->tlc_wr.wr_nds    = 1;
2655*9e39c5baSBill Taylor 	tx->tlc_wr.wr_sgl    = &tx->tlc_sgl;
2656*9e39c5baSBill Taylor 	tx->tlc_wr.wr_opcode = IBT_WRC_RDMAW;
2657*9e39c5baSBill Taylor 	tx->tlc_wr.wr_trans  = IBT_RC_SRV;
2658*9e39c5baSBill Taylor 
2659*9e39c5baSBill Taylor 	/* Initialize the remote address for RX buffer */
2660*9e39c5baSBill Taylor 	tx->tlc_wr.wr.rc.rcwr.rdma.rdma_raddr = rx->tlc_mrdesc.md_vaddr;
2661*9e39c5baSBill Taylor 	tx->tlc_wr.wr.rc.rcwr.rdma.rdma_rkey  = rx->tlc_mrdesc.md_rkey;
2662*9e39c5baSBill Taylor 	tx->tlc_complete = 0;
2663*9e39c5baSBill Taylor 	ret = tavor_post_send(lstate->tls_state, tx->tlc_qp_hdl, &tx->tlc_wr,
2664*9e39c5baSBill Taylor 	    1, NULL);
2665*9e39c5baSBill Taylor 	if (ret != IBT_SUCCESS) {
2666*9e39c5baSBill Taylor 		return (EFAULT);
2667*9e39c5baSBill Taylor 	}
2668*9e39c5baSBill Taylor 	return (0);
2669*9e39c5baSBill Taylor }
2670*9e39c5baSBill Taylor 
2671*9e39c5baSBill Taylor /*
2672*9e39c5baSBill Taylor  * tavor_loopback_poll_cq
2673*9e39c5baSBill Taylor  */
2674*9e39c5baSBill Taylor static int
2675*9e39c5baSBill Taylor tavor_loopback_poll_cq(tavor_loopback_state_t *lstate,
2676*9e39c5baSBill Taylor     tavor_loopback_comm_t *comm)
2677*9e39c5baSBill Taylor {
2678*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm))
2679*9e39c5baSBill Taylor 
2680*9e39c5baSBill Taylor 	comm->tlc_wc.wc_status	= 0;
2681*9e39c5baSBill Taylor 	comm->tlc_num_polled	= 0;
2682*9e39c5baSBill Taylor 	comm->tlc_status = tavor_cq_poll(lstate->tls_state,
2683*9e39c5baSBill Taylor 	    comm->tlc_cqhdl[0], &comm->tlc_wc, 1, &comm->tlc_num_polled);
2684*9e39c5baSBill Taylor 	if ((comm->tlc_status == IBT_SUCCESS) &&
2685*9e39c5baSBill Taylor 	    (comm->tlc_wc.wc_status != IBT_WC_SUCCESS)) {
2686*9e39c5baSBill Taylor 		comm->tlc_status = ibc_get_ci_failure(0);
2687*9e39c5baSBill Taylor 	}
2688*9e39c5baSBill Taylor 	return (comm->tlc_status);
2689*9e39c5baSBill Taylor }
2690