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  * hermon_ioctl.c
29*9e39c5baSBill Taylor  *    Hemron 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 hermon 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/hermon/hermon.h>
44*9e39c5baSBill Taylor 
45*9e39c5baSBill Taylor /* Hemron HCA state pointer (extern) */
46*9e39c5baSBill Taylor extern void	*hermon_statep;
47*9e39c5baSBill Taylor extern int	hermon_verbose;
48*9e39c5baSBill Taylor 
49*9e39c5baSBill Taylor #define	DO_WRCONF	1
50*9e39c5baSBill Taylor static int do_bar0 = 1;
51*9e39c5baSBill Taylor 
52*9e39c5baSBill Taylor /*
53*9e39c5baSBill Taylor  * The ioctl declarations (for firmware flash burning, register read/write
54*9e39c5baSBill Taylor  * (DEBUG-only), and VTS interfaces)
55*9e39c5baSBill Taylor  */
56*9e39c5baSBill Taylor static int hermon_ioctl_flash_read(hermon_state_t *state, dev_t dev,
57*9e39c5baSBill Taylor     intptr_t arg, int mode);
58*9e39c5baSBill Taylor static int hermon_ioctl_flash_write(hermon_state_t *state, dev_t dev,
59*9e39c5baSBill Taylor     intptr_t arg, int mode);
60*9e39c5baSBill Taylor static int hermon_ioctl_flash_erase(hermon_state_t *state, dev_t dev,
61*9e39c5baSBill Taylor     intptr_t arg, int mode);
62*9e39c5baSBill Taylor static int hermon_ioctl_flash_init(hermon_state_t *state, dev_t dev,
63*9e39c5baSBill Taylor     intptr_t arg, int mode);
64*9e39c5baSBill Taylor static int hermon_ioctl_flash_fini(hermon_state_t *state, dev_t dev);
65*9e39c5baSBill Taylor static int hermon_ioctl_flash_cleanup(hermon_state_t *state);
66*9e39c5baSBill Taylor static int hermon_ioctl_flash_cleanup_nolock(hermon_state_t *state);
67*9e39c5baSBill Taylor #ifdef	DEBUG
68*9e39c5baSBill Taylor static int hermon_ioctl_reg_write(hermon_state_t *state, intptr_t arg,
69*9e39c5baSBill Taylor     int mode);
70*9e39c5baSBill Taylor static int hermon_ioctl_reg_read(hermon_state_t *state, intptr_t arg,
71*9e39c5baSBill Taylor     int mode);
72*9e39c5baSBill Taylor #endif	/* DEBUG */
73*9e39c5baSBill Taylor static int hermon_ioctl_write_boot_addr(hermon_state_t *state, dev_t dev,
74*9e39c5baSBill Taylor     intptr_t arg, int mode);
75*9e39c5baSBill Taylor static int hermon_ioctl_info(hermon_state_t *state, dev_t dev,
76*9e39c5baSBill Taylor     intptr_t arg, int mode);
77*9e39c5baSBill Taylor static int hermon_ioctl_ports(hermon_state_t *state, intptr_t arg,
78*9e39c5baSBill Taylor     int mode);
79*9e39c5baSBill Taylor static int hermon_ioctl_loopback(hermon_state_t *state, intptr_t arg,
80*9e39c5baSBill Taylor     int mode);
81*9e39c5baSBill Taylor 
82*9e39c5baSBill Taylor /* Hemron Flash Functions */
83*9e39c5baSBill Taylor static void hermon_flash_spi_exec_command(hermon_state_t *state,
84*9e39c5baSBill Taylor     ddi_acc_handle_t hdl, uint32_t cmd);
85*9e39c5baSBill Taylor static int hermon_flash_read_sector(hermon_state_t *state,
86*9e39c5baSBill Taylor     uint32_t sector_num);
87*9e39c5baSBill Taylor static int hermon_flash_read_quadlet(hermon_state_t *state, uint32_t *data,
88*9e39c5baSBill Taylor     uint32_t addr);
89*9e39c5baSBill Taylor static int hermon_flash_write_sector(hermon_state_t *state,
90*9e39c5baSBill Taylor     uint32_t sector_num);
91*9e39c5baSBill Taylor static int hermon_flash_spi_write_dword(hermon_state_t *state,
92*9e39c5baSBill Taylor     uint32_t addr, uint32_t data);
93*9e39c5baSBill Taylor static int hermon_flash_write_byte(hermon_state_t *state, uint32_t addr,
94*9e39c5baSBill Taylor     uchar_t data);
95*9e39c5baSBill Taylor static int hermon_flash_erase_sector(hermon_state_t *state,
96*9e39c5baSBill Taylor     uint32_t sector_num);
97*9e39c5baSBill Taylor static int hermon_flash_erase_chip(hermon_state_t *state);
98*9e39c5baSBill Taylor static int hermon_flash_bank(hermon_state_t *state, uint32_t addr);
99*9e39c5baSBill Taylor static uint32_t hermon_flash_read(hermon_state_t *state, uint32_t addr,
100*9e39c5baSBill Taylor     int *err);
101*9e39c5baSBill Taylor static void hermon_flash_write(hermon_state_t *state, uint32_t addr,
102*9e39c5baSBill Taylor     uchar_t data, int *err);
103*9e39c5baSBill Taylor static int hermon_flash_spi_wait_wip(hermon_state_t *state);
104*9e39c5baSBill Taylor static void hermon_flash_spi_write_enable(hermon_state_t *state);
105*9e39c5baSBill Taylor static int hermon_flash_init(hermon_state_t *state);
106*9e39c5baSBill Taylor static int hermon_flash_cfi_init(hermon_state_t *state, uint32_t *cfi_info,
107*9e39c5baSBill Taylor     int *intel_xcmd);
108*9e39c5baSBill Taylor static int hermon_flash_fini(hermon_state_t *state);
109*9e39c5baSBill Taylor static int hermon_flash_reset(hermon_state_t *state);
110*9e39c5baSBill Taylor static uint32_t hermon_flash_read_cfg(hermon_state_t *state,
111*9e39c5baSBill Taylor     ddi_acc_handle_t pci_config_hdl, uint32_t addr);
112*9e39c5baSBill Taylor #ifdef DO_WRCONF
113*9e39c5baSBill Taylor static void hermon_flash_write_cfg(hermon_state_t *state,
114*9e39c5baSBill Taylor     ddi_acc_handle_t pci_config_hdl, uint32_t addr, uint32_t data);
115*9e39c5baSBill Taylor static void hermon_flash_write_cfg_helper(hermon_state_t *state,
116*9e39c5baSBill Taylor     ddi_acc_handle_t pci_config_hdl, uint32_t addr, uint32_t data);
117*9e39c5baSBill Taylor static void hermon_flash_write_confirm(hermon_state_t *state,
118*9e39c5baSBill Taylor     ddi_acc_handle_t pci_config_hdl);
119*9e39c5baSBill Taylor #endif
120*9e39c5baSBill Taylor static void hermon_flash_cfi_byte(uint8_t *ch, uint32_t dword, int i);
121*9e39c5baSBill Taylor static void hermon_flash_cfi_dword(uint32_t *dword, uint8_t *ch, int i);
122*9e39c5baSBill Taylor 
123*9e39c5baSBill Taylor /* Hemron loopback test functions */
124*9e39c5baSBill Taylor static void hermon_loopback_free_qps(hermon_loopback_state_t *lstate);
125*9e39c5baSBill Taylor static void hermon_loopback_free_state(hermon_loopback_state_t *lstate);
126*9e39c5baSBill Taylor static int hermon_loopback_init(hermon_state_t *state,
127*9e39c5baSBill Taylor     hermon_loopback_state_t *lstate);
128*9e39c5baSBill Taylor static void hermon_loopback_init_qp_info(hermon_loopback_state_t *lstate,
129*9e39c5baSBill Taylor     hermon_loopback_comm_t *comm);
130*9e39c5baSBill Taylor static int hermon_loopback_alloc_mem(hermon_loopback_state_t *lstate,
131*9e39c5baSBill Taylor     hermon_loopback_comm_t *comm, int sz);
132*9e39c5baSBill Taylor static int hermon_loopback_alloc_qps(hermon_loopback_state_t *lstate,
133*9e39c5baSBill Taylor     hermon_loopback_comm_t *comm);
134*9e39c5baSBill Taylor static int hermon_loopback_modify_qp(hermon_loopback_state_t *lstate,
135*9e39c5baSBill Taylor     hermon_loopback_comm_t *comm, uint_t qp_num);
136*9e39c5baSBill Taylor static int hermon_loopback_copyout(hermon_loopback_ioctl_t *lb,
137*9e39c5baSBill Taylor     intptr_t arg, int mode);
138*9e39c5baSBill Taylor static int hermon_loopback_post_send(hermon_loopback_state_t *lstate,
139*9e39c5baSBill Taylor     hermon_loopback_comm_t *tx, hermon_loopback_comm_t *rx);
140*9e39c5baSBill Taylor static int hermon_loopback_poll_cq(hermon_loopback_state_t *lstate,
141*9e39c5baSBill Taylor     hermon_loopback_comm_t *comm);
142*9e39c5baSBill Taylor 
143*9e39c5baSBill Taylor /* Patchable timeout values for flash operations */
144*9e39c5baSBill Taylor int hermon_hw_flash_timeout_gpio_sema = HERMON_HW_FLASH_TIMEOUT_GPIO_SEMA;
145*9e39c5baSBill Taylor int hermon_hw_flash_timeout_config = HERMON_HW_FLASH_TIMEOUT_CONFIG;
146*9e39c5baSBill Taylor int hermon_hw_flash_timeout_write = HERMON_HW_FLASH_TIMEOUT_WRITE;
147*9e39c5baSBill Taylor int hermon_hw_flash_timeout_erase = HERMON_HW_FLASH_TIMEOUT_ERASE;
148*9e39c5baSBill Taylor 
149*9e39c5baSBill Taylor /*
150*9e39c5baSBill Taylor  * hermon_ioctl()
151*9e39c5baSBill Taylor  */
152*9e39c5baSBill Taylor /* ARGSUSED */
153*9e39c5baSBill Taylor int
154*9e39c5baSBill Taylor hermon_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
155*9e39c5baSBill Taylor     int *rvalp)
156*9e39c5baSBill Taylor {
157*9e39c5baSBill Taylor 	hermon_state_t	*state;
158*9e39c5baSBill Taylor 	minor_t		instance;
159*9e39c5baSBill Taylor 	int		status;
160*9e39c5baSBill Taylor 
161*9e39c5baSBill Taylor 	if (drv_priv(credp) != 0) {
162*9e39c5baSBill Taylor 		return (EPERM);
163*9e39c5baSBill Taylor 	}
164*9e39c5baSBill Taylor 
165*9e39c5baSBill Taylor 	instance = HERMON_DEV_INSTANCE(dev);
166*9e39c5baSBill Taylor 	if (instance == (minor_t)-1) {
167*9e39c5baSBill Taylor 		return (EBADF);
168*9e39c5baSBill Taylor 	}
169*9e39c5baSBill Taylor 
170*9e39c5baSBill Taylor 	state = ddi_get_soft_state(hermon_statep, instance);
171*9e39c5baSBill Taylor 	if (state == NULL) {
172*9e39c5baSBill Taylor 		return (EBADF);
173*9e39c5baSBill Taylor 	}
174*9e39c5baSBill Taylor 
175*9e39c5baSBill Taylor 	status = 0;
176*9e39c5baSBill Taylor 
177*9e39c5baSBill Taylor 	switch (cmd) {
178*9e39c5baSBill Taylor 	case HERMON_IOCTL_FLASH_READ:
179*9e39c5baSBill Taylor 		status = hermon_ioctl_flash_read(state, dev, arg, mode);
180*9e39c5baSBill Taylor 		break;
181*9e39c5baSBill Taylor 
182*9e39c5baSBill Taylor 	case HERMON_IOCTL_FLASH_WRITE:
183*9e39c5baSBill Taylor 		status = hermon_ioctl_flash_write(state, dev, arg, mode);
184*9e39c5baSBill Taylor 		break;
185*9e39c5baSBill Taylor 
186*9e39c5baSBill Taylor 	case HERMON_IOCTL_FLASH_ERASE:
187*9e39c5baSBill Taylor 		status = hermon_ioctl_flash_erase(state, dev, arg, mode);
188*9e39c5baSBill Taylor 		break;
189*9e39c5baSBill Taylor 
190*9e39c5baSBill Taylor 	case HERMON_IOCTL_FLASH_INIT:
191*9e39c5baSBill Taylor 		status = hermon_ioctl_flash_init(state, dev, arg, mode);
192*9e39c5baSBill Taylor 		break;
193*9e39c5baSBill Taylor 
194*9e39c5baSBill Taylor 	case HERMON_IOCTL_FLASH_FINI:
195*9e39c5baSBill Taylor 		status = hermon_ioctl_flash_fini(state, dev);
196*9e39c5baSBill Taylor 		break;
197*9e39c5baSBill Taylor 
198*9e39c5baSBill Taylor 	case HERMON_IOCTL_INFO:
199*9e39c5baSBill Taylor 		status = hermon_ioctl_info(state, dev, arg, mode);
200*9e39c5baSBill Taylor 		break;
201*9e39c5baSBill Taylor 
202*9e39c5baSBill Taylor 	case HERMON_IOCTL_PORTS:
203*9e39c5baSBill Taylor 		status = hermon_ioctl_ports(state, arg, mode);
204*9e39c5baSBill Taylor 		break;
205*9e39c5baSBill Taylor 
206*9e39c5baSBill Taylor 	case HERMON_IOCTL_LOOPBACK:
207*9e39c5baSBill Taylor 		status = hermon_ioctl_loopback(state, arg, mode);
208*9e39c5baSBill Taylor 		break;
209*9e39c5baSBill Taylor 
210*9e39c5baSBill Taylor #ifdef	DEBUG
211*9e39c5baSBill Taylor 	case HERMON_IOCTL_REG_WRITE:
212*9e39c5baSBill Taylor 		status = hermon_ioctl_reg_write(state, arg, mode);
213*9e39c5baSBill Taylor 		break;
214*9e39c5baSBill Taylor 
215*9e39c5baSBill Taylor 	case HERMON_IOCTL_REG_READ:
216*9e39c5baSBill Taylor 		status = hermon_ioctl_reg_read(state, arg, mode);
217*9e39c5baSBill Taylor 		break;
218*9e39c5baSBill Taylor #endif	/* DEBUG */
219*9e39c5baSBill Taylor 
220*9e39c5baSBill Taylor 	case HERMON_IOCTL_DDR_READ:
221*9e39c5baSBill Taylor 		/* XXX guard until the ioctl header is cleaned up */
222*9e39c5baSBill Taylor 		status = ENODEV;
223*9e39c5baSBill Taylor 		break;
224*9e39c5baSBill Taylor 
225*9e39c5baSBill Taylor 	case HERMON_IOCTL_WRITE_BOOT_ADDR:
226*9e39c5baSBill Taylor 		status = hermon_ioctl_write_boot_addr(state, dev, arg, mode);
227*9e39c5baSBill Taylor 		break;
228*9e39c5baSBill Taylor 
229*9e39c5baSBill Taylor 	default:
230*9e39c5baSBill Taylor 		status = ENOTTY;
231*9e39c5baSBill Taylor 		break;
232*9e39c5baSBill Taylor 	}
233*9e39c5baSBill Taylor 	*rvalp = status;
234*9e39c5baSBill Taylor 
235*9e39c5baSBill Taylor 	return (status);
236*9e39c5baSBill Taylor }
237*9e39c5baSBill Taylor 
238*9e39c5baSBill Taylor /*
239*9e39c5baSBill Taylor  * hermon_ioctl_flash_read()
240*9e39c5baSBill Taylor  */
241*9e39c5baSBill Taylor static int
242*9e39c5baSBill Taylor hermon_ioctl_flash_read(hermon_state_t *state, dev_t dev, intptr_t arg,
243*9e39c5baSBill Taylor     int mode)
244*9e39c5baSBill Taylor {
245*9e39c5baSBill Taylor 	hermon_flash_ioctl_t ioctl_info;
246*9e39c5baSBill Taylor 	int status = 0;
247*9e39c5baSBill Taylor 
248*9e39c5baSBill Taylor 	/*
249*9e39c5baSBill Taylor 	 * Check that flash init ioctl has been called first.  And check
250*9e39c5baSBill Taylor 	 * that the same dev_t that called init is the one calling read now.
251*9e39c5baSBill Taylor 	 */
252*9e39c5baSBill Taylor 	mutex_enter(&state->hs_fw_flashlock);
253*9e39c5baSBill Taylor 	if ((state->hs_fw_flashdev != dev) ||
254*9e39c5baSBill Taylor 	    (state->hs_fw_flashstarted == 0)) {
255*9e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
256*9e39c5baSBill Taylor 		return (EIO);
257*9e39c5baSBill Taylor 	}
258*9e39c5baSBill Taylor 
259*9e39c5baSBill Taylor 	/* copy user struct to kernel */
260*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
261*9e39c5baSBill Taylor 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
262*9e39c5baSBill Taylor 		hermon_flash_ioctl32_t info32;
263*9e39c5baSBill Taylor 
264*9e39c5baSBill Taylor 		if (ddi_copyin((void *)arg, &info32,
265*9e39c5baSBill Taylor 		    sizeof (hermon_flash_ioctl32_t), mode) != 0) {
266*9e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
267*9e39c5baSBill Taylor 			return (EFAULT);
268*9e39c5baSBill Taylor 		}
269*9e39c5baSBill Taylor 		ioctl_info.af_type = info32.af_type;
270*9e39c5baSBill Taylor 		ioctl_info.af_sector = (caddr_t)(uintptr_t)info32.af_sector;
271*9e39c5baSBill Taylor 		ioctl_info.af_sector_num = info32.af_sector_num;
272*9e39c5baSBill Taylor 		ioctl_info.af_addr = info32.af_addr;
273*9e39c5baSBill Taylor 	} else
274*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
275*9e39c5baSBill Taylor 	if (ddi_copyin((void *)arg, &ioctl_info, sizeof (hermon_flash_ioctl_t),
276*9e39c5baSBill Taylor 	    mode) != 0) {
277*9e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
278*9e39c5baSBill Taylor 		return (EFAULT);
279*9e39c5baSBill Taylor 	}
280*9e39c5baSBill Taylor 
281*9e39c5baSBill Taylor 	/*
282*9e39c5baSBill Taylor 	 * Determine type of READ ioctl
283*9e39c5baSBill Taylor 	 */
284*9e39c5baSBill Taylor 	switch (ioctl_info.af_type) {
285*9e39c5baSBill Taylor 	case HERMON_FLASH_READ_SECTOR:
286*9e39c5baSBill Taylor 		/* Check if sector num is too large for flash device */
287*9e39c5baSBill Taylor 		if (ioctl_info.af_sector_num >=
288*9e39c5baSBill Taylor 		    (state->hs_fw_device_sz >> state->hs_fw_log_sector_sz)) {
289*9e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
290*9e39c5baSBill Taylor 			return (EFAULT);
291*9e39c5baSBill Taylor 		}
292*9e39c5baSBill Taylor 
293*9e39c5baSBill Taylor 		/* Perform the Sector Read */
294*9e39c5baSBill Taylor 		if ((status = hermon_flash_reset(state)) != 0 ||
295*9e39c5baSBill Taylor 		    (status = hermon_flash_read_sector(state,
296*9e39c5baSBill Taylor 		    ioctl_info.af_sector_num)) != 0) {
297*9e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
298*9e39c5baSBill Taylor 			return (status);
299*9e39c5baSBill Taylor 		}
300*9e39c5baSBill Taylor 
301*9e39c5baSBill Taylor 		/* copyout the firmware sector image data */
302*9e39c5baSBill Taylor 		if (ddi_copyout(&state->hs_fw_sector[0],
303*9e39c5baSBill Taylor 		    &ioctl_info.af_sector[0], 1 << state->hs_fw_log_sector_sz,
304*9e39c5baSBill Taylor 		    mode) != 0) {
305*9e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
306*9e39c5baSBill Taylor 			return (EFAULT);
307*9e39c5baSBill Taylor 		}
308*9e39c5baSBill Taylor 		break;
309*9e39c5baSBill Taylor 
310*9e39c5baSBill Taylor 	case HERMON_FLASH_READ_QUADLET:
311*9e39c5baSBill Taylor 		/* Check if addr is too large for flash device */
312*9e39c5baSBill Taylor 		if (ioctl_info.af_addr >= state->hs_fw_device_sz) {
313*9e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
314*9e39c5baSBill Taylor 			return (EFAULT);
315*9e39c5baSBill Taylor 		}
316*9e39c5baSBill Taylor 
317*9e39c5baSBill Taylor 		/* Perform the Quadlet Read */
318*9e39c5baSBill Taylor 		if ((status = hermon_flash_reset(state)) != 0 ||
319*9e39c5baSBill Taylor 		    (status = hermon_flash_read_quadlet(state,
320*9e39c5baSBill Taylor 		    &ioctl_info.af_quadlet, ioctl_info.af_addr)) != 0) {
321*9e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
322*9e39c5baSBill Taylor 			return (status);
323*9e39c5baSBill Taylor 		}
324*9e39c5baSBill Taylor 		break;
325*9e39c5baSBill Taylor 
326*9e39c5baSBill Taylor 	default:
327*9e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
328*9e39c5baSBill Taylor 		return (EINVAL);
329*9e39c5baSBill Taylor 	}
330*9e39c5baSBill Taylor 
331*9e39c5baSBill Taylor 	/* copy results back to userland */
332*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
333*9e39c5baSBill Taylor 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
334*9e39c5baSBill Taylor 		hermon_flash_ioctl32_t info32;
335*9e39c5baSBill Taylor 
336*9e39c5baSBill Taylor 		info32.af_quadlet = ioctl_info.af_quadlet;
337*9e39c5baSBill Taylor 		info32.af_type = ioctl_info.af_type;
338*9e39c5baSBill Taylor 		info32.af_sector_num = ioctl_info.af_sector_num;
339*9e39c5baSBill Taylor 		info32.af_sector = (caddr32_t)(uintptr_t)ioctl_info.af_sector;
340*9e39c5baSBill Taylor 		info32.af_addr = ioctl_info.af_addr;
341*9e39c5baSBill Taylor 
342*9e39c5baSBill Taylor 		if (ddi_copyout(&info32, (void *)arg,
343*9e39c5baSBill Taylor 		    sizeof (hermon_flash_ioctl32_t), mode) != 0) {
344*9e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
345*9e39c5baSBill Taylor 			return (EFAULT);
346*9e39c5baSBill Taylor 		}
347*9e39c5baSBill Taylor 	} else
348*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
349*9e39c5baSBill Taylor 	if (ddi_copyout(&ioctl_info, (void *)arg,
350*9e39c5baSBill Taylor 	    sizeof (hermon_flash_ioctl_t), mode) != 0) {
351*9e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
352*9e39c5baSBill Taylor 		return (EFAULT);
353*9e39c5baSBill Taylor 	}
354*9e39c5baSBill Taylor 
355*9e39c5baSBill Taylor 	mutex_exit(&state->hs_fw_flashlock);
356*9e39c5baSBill Taylor 	return (status);
357*9e39c5baSBill Taylor }
358*9e39c5baSBill Taylor 
359*9e39c5baSBill Taylor /*
360*9e39c5baSBill Taylor  * hermon_ioctl_flash_write()
361*9e39c5baSBill Taylor  */
362*9e39c5baSBill Taylor static int
363*9e39c5baSBill Taylor hermon_ioctl_flash_write(hermon_state_t *state, dev_t dev, intptr_t arg,
364*9e39c5baSBill Taylor     int mode)
365*9e39c5baSBill Taylor {
366*9e39c5baSBill Taylor 	hermon_flash_ioctl_t	ioctl_info;
367*9e39c5baSBill Taylor 	int status = 0;
368*9e39c5baSBill Taylor 
369*9e39c5baSBill Taylor 	/*
370*9e39c5baSBill Taylor 	 * Check that flash init ioctl has been called first.  And check
371*9e39c5baSBill Taylor 	 * that the same dev_t that called init is the one calling write now.
372*9e39c5baSBill Taylor 	 */
373*9e39c5baSBill Taylor 	mutex_enter(&state->hs_fw_flashlock);
374*9e39c5baSBill Taylor 	if ((state->hs_fw_flashdev != dev) ||
375*9e39c5baSBill Taylor 	    (state->hs_fw_flashstarted == 0)) {
376*9e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
377*9e39c5baSBill Taylor 		return (EIO);
378*9e39c5baSBill Taylor 	}
379*9e39c5baSBill Taylor 
380*9e39c5baSBill Taylor 	/* copy user struct to kernel */
381*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
382*9e39c5baSBill Taylor 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
383*9e39c5baSBill Taylor 		hermon_flash_ioctl32_t info32;
384*9e39c5baSBill Taylor 
385*9e39c5baSBill Taylor 		if (ddi_copyin((void *)arg, &info32,
386*9e39c5baSBill Taylor 		    sizeof (hermon_flash_ioctl32_t), mode) != 0) {
387*9e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
388*9e39c5baSBill Taylor 			return (EFAULT);
389*9e39c5baSBill Taylor 		}
390*9e39c5baSBill Taylor 		ioctl_info.af_type = info32.af_type;
391*9e39c5baSBill Taylor 		ioctl_info.af_sector = (caddr_t)(uintptr_t)info32.af_sector;
392*9e39c5baSBill Taylor 		ioctl_info.af_sector_num = info32.af_sector_num;
393*9e39c5baSBill Taylor 		ioctl_info.af_addr = info32.af_addr;
394*9e39c5baSBill Taylor 		ioctl_info.af_byte = info32.af_byte;
395*9e39c5baSBill Taylor 	} else
396*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
397*9e39c5baSBill Taylor 	if (ddi_copyin((void *)arg, &ioctl_info,
398*9e39c5baSBill Taylor 	    sizeof (hermon_flash_ioctl_t), mode) != 0) {
399*9e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
400*9e39c5baSBill Taylor 		return (EFAULT);
401*9e39c5baSBill Taylor 	}
402*9e39c5baSBill Taylor 
403*9e39c5baSBill Taylor 	/*
404*9e39c5baSBill Taylor 	 * Determine type of WRITE ioctl
405*9e39c5baSBill Taylor 	 */
406*9e39c5baSBill Taylor 	switch (ioctl_info.af_type) {
407*9e39c5baSBill Taylor 	case HERMON_FLASH_WRITE_SECTOR:
408*9e39c5baSBill Taylor 		/* Check if sector num is too large for flash device */
409*9e39c5baSBill Taylor 		if (ioctl_info.af_sector_num >=
410*9e39c5baSBill Taylor 		    (state->hs_fw_device_sz >> state->hs_fw_log_sector_sz)) {
411*9e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
412*9e39c5baSBill Taylor 			return (EFAULT);
413*9e39c5baSBill Taylor 		}
414*9e39c5baSBill Taylor 
415*9e39c5baSBill Taylor 		/* copy in fw sector image data */
416*9e39c5baSBill Taylor 		if (ddi_copyin(&ioctl_info.af_sector[0],
417*9e39c5baSBill Taylor 		    &state->hs_fw_sector[0], 1 << state->hs_fw_log_sector_sz,
418*9e39c5baSBill Taylor 		    mode) != 0) {
419*9e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
420*9e39c5baSBill Taylor 			return (EFAULT);
421*9e39c5baSBill Taylor 		}
422*9e39c5baSBill Taylor 
423*9e39c5baSBill Taylor 		/* Perform Write Sector */
424*9e39c5baSBill Taylor 		status = hermon_flash_write_sector(state,
425*9e39c5baSBill Taylor 		    ioctl_info.af_sector_num);
426*9e39c5baSBill Taylor 		break;
427*9e39c5baSBill Taylor 
428*9e39c5baSBill Taylor 	case HERMON_FLASH_WRITE_BYTE:
429*9e39c5baSBill Taylor 		/* Check if addr is too large for flash device */
430*9e39c5baSBill Taylor 		if (ioctl_info.af_addr >= state->hs_fw_device_sz) {
431*9e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
432*9e39c5baSBill Taylor 			return (EFAULT);
433*9e39c5baSBill Taylor 		}
434*9e39c5baSBill Taylor 
435*9e39c5baSBill Taylor 		/* Perform Write Byte */
436*9e39c5baSBill Taylor 		/*
437*9e39c5baSBill Taylor 		 * CMJ -- is a reset really needed before and after writing
438*9e39c5baSBill Taylor 		 * each byte?  This code came from arbel, but we should look
439*9e39c5baSBill Taylor 		 * into this.  Also, for SPI, no reset is actually performed.
440*9e39c5baSBill Taylor 		 */
441*9e39c5baSBill Taylor 		if ((status = hermon_flash_bank(state,
442*9e39c5baSBill Taylor 		    ioctl_info.af_addr)) != 0 ||
443*9e39c5baSBill Taylor 		    (status = hermon_flash_reset(state)) != 0 ||
444*9e39c5baSBill Taylor 		    (status = hermon_flash_write_byte(state,
445*9e39c5baSBill Taylor 		    ioctl_info.af_addr, ioctl_info.af_byte)) != 0 ||
446*9e39c5baSBill Taylor 		    (status = hermon_flash_reset(state)) != 0) {
447*9e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
448*9e39c5baSBill Taylor 			return (status);
449*9e39c5baSBill Taylor 		}
450*9e39c5baSBill Taylor 		break;
451*9e39c5baSBill Taylor 
452*9e39c5baSBill Taylor 	default:
453*9e39c5baSBill Taylor 		status = EINVAL;
454*9e39c5baSBill Taylor 		break;
455*9e39c5baSBill Taylor 	}
456*9e39c5baSBill Taylor 
457*9e39c5baSBill Taylor 	mutex_exit(&state->hs_fw_flashlock);
458*9e39c5baSBill Taylor 	return (status);
459*9e39c5baSBill Taylor }
460*9e39c5baSBill Taylor 
461*9e39c5baSBill Taylor /*
462*9e39c5baSBill Taylor  * hermon_ioctl_flash_erase()
463*9e39c5baSBill Taylor  */
464*9e39c5baSBill Taylor static int
465*9e39c5baSBill Taylor hermon_ioctl_flash_erase(hermon_state_t *state, dev_t dev, intptr_t arg,
466*9e39c5baSBill Taylor     int mode)
467*9e39c5baSBill Taylor {
468*9e39c5baSBill Taylor 	hermon_flash_ioctl_t	ioctl_info;
469*9e39c5baSBill Taylor 	int status = 0;
470*9e39c5baSBill Taylor 
471*9e39c5baSBill Taylor 	/*
472*9e39c5baSBill Taylor 	 * Check that flash init ioctl has been called first.  And check
473*9e39c5baSBill Taylor 	 * that the same dev_t that called init is the one calling erase now.
474*9e39c5baSBill Taylor 	 */
475*9e39c5baSBill Taylor 	mutex_enter(&state->hs_fw_flashlock);
476*9e39c5baSBill Taylor 	if ((state->hs_fw_flashdev != dev) ||
477*9e39c5baSBill Taylor 	    (state->hs_fw_flashstarted == 0)) {
478*9e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
479*9e39c5baSBill Taylor 		return (EIO);
480*9e39c5baSBill Taylor 	}
481*9e39c5baSBill Taylor 
482*9e39c5baSBill Taylor 	/* copy user struct to kernel */
483*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
484*9e39c5baSBill Taylor 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
485*9e39c5baSBill Taylor 		hermon_flash_ioctl32_t info32;
486*9e39c5baSBill Taylor 
487*9e39c5baSBill Taylor 		if (ddi_copyin((void *)arg, &info32,
488*9e39c5baSBill Taylor 		    sizeof (hermon_flash_ioctl32_t), mode) != 0) {
489*9e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
490*9e39c5baSBill Taylor 			return (EFAULT);
491*9e39c5baSBill Taylor 		}
492*9e39c5baSBill Taylor 		ioctl_info.af_type = info32.af_type;
493*9e39c5baSBill Taylor 		ioctl_info.af_sector_num = info32.af_sector_num;
494*9e39c5baSBill Taylor 	} else
495*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
496*9e39c5baSBill Taylor 	if (ddi_copyin((void *)arg, &ioctl_info, sizeof (hermon_flash_ioctl_t),
497*9e39c5baSBill Taylor 	    mode) != 0) {
498*9e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
499*9e39c5baSBill Taylor 		return (EFAULT);
500*9e39c5baSBill Taylor 	}
501*9e39c5baSBill Taylor 
502*9e39c5baSBill Taylor 	/*
503*9e39c5baSBill Taylor 	 * Determine type of ERASE ioctl
504*9e39c5baSBill Taylor 	 */
505*9e39c5baSBill Taylor 	switch (ioctl_info.af_type) {
506*9e39c5baSBill Taylor 	case HERMON_FLASH_ERASE_SECTOR:
507*9e39c5baSBill Taylor 		/* Check if sector num is too large for flash device */
508*9e39c5baSBill Taylor 		if (ioctl_info.af_sector_num >=
509*9e39c5baSBill Taylor 		    (state->hs_fw_device_sz >> state->hs_fw_log_sector_sz)) {
510*9e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
511*9e39c5baSBill Taylor 			return (EFAULT);
512*9e39c5baSBill Taylor 		}
513*9e39c5baSBill Taylor 
514*9e39c5baSBill Taylor 		/* Perform Sector Erase */
515*9e39c5baSBill Taylor 		status = hermon_flash_erase_sector(state,
516*9e39c5baSBill Taylor 		    ioctl_info.af_sector_num);
517*9e39c5baSBill Taylor 		break;
518*9e39c5baSBill Taylor 
519*9e39c5baSBill Taylor 	case HERMON_FLASH_ERASE_CHIP:
520*9e39c5baSBill Taylor 		/* Perform Chip Erase */
521*9e39c5baSBill Taylor 		status = hermon_flash_erase_chip(state);
522*9e39c5baSBill Taylor 		break;
523*9e39c5baSBill Taylor 
524*9e39c5baSBill Taylor 	default:
525*9e39c5baSBill Taylor 		status = EINVAL;
526*9e39c5baSBill Taylor 		break;
527*9e39c5baSBill Taylor 	}
528*9e39c5baSBill Taylor 
529*9e39c5baSBill Taylor 	mutex_exit(&state->hs_fw_flashlock);
530*9e39c5baSBill Taylor 	return (status);
531*9e39c5baSBill Taylor }
532*9e39c5baSBill Taylor 
533*9e39c5baSBill Taylor /*
534*9e39c5baSBill Taylor  * hermon_ioctl_flash_init()
535*9e39c5baSBill Taylor  */
536*9e39c5baSBill Taylor static int
537*9e39c5baSBill Taylor hermon_ioctl_flash_init(hermon_state_t *state, dev_t dev, intptr_t arg,
538*9e39c5baSBill Taylor     int mode)
539*9e39c5baSBill Taylor {
540*9e39c5baSBill Taylor 	hermon_flash_init_ioctl_t init_info;
541*9e39c5baSBill Taylor 	int ret;
542*9e39c5baSBill Taylor 	int intel_xcmd = 0;
543*9e39c5baSBill Taylor 	ddi_acc_handle_t pci_hdl = hermon_get_pcihdl(state);
544*9e39c5baSBill Taylor 
545*9e39c5baSBill Taylor 	/* initialize the FMA retry loop */
546*9e39c5baSBill Taylor 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
547*9e39c5baSBill Taylor 
548*9e39c5baSBill Taylor 	state->hs_fw_sector = NULL;
549*9e39c5baSBill Taylor 
550*9e39c5baSBill Taylor 	/*
551*9e39c5baSBill Taylor 	 * init cannot be called more than once.  If we have already init'd the
552*9e39c5baSBill Taylor 	 * flash, return directly.
553*9e39c5baSBill Taylor 	 */
554*9e39c5baSBill Taylor 	mutex_enter(&state->hs_fw_flashlock);
555*9e39c5baSBill Taylor 	if (state->hs_fw_flashstarted == 1) {
556*9e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
557*9e39c5baSBill Taylor 		return (EINVAL);
558*9e39c5baSBill Taylor 	}
559*9e39c5baSBill Taylor 
560*9e39c5baSBill Taylor 	/* copyin the user struct to kernel */
561*9e39c5baSBill Taylor 	if (ddi_copyin((void *)arg, &init_info,
562*9e39c5baSBill Taylor 	    sizeof (hermon_flash_init_ioctl_t), mode) != 0) {
563*9e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
564*9e39c5baSBill Taylor 		return (EFAULT);
565*9e39c5baSBill Taylor 	}
566*9e39c5baSBill Taylor 
567*9e39c5baSBill Taylor 	/* Init Flash */
568*9e39c5baSBill Taylor 	if ((ret = hermon_flash_init(state)) != 0) {
569*9e39c5baSBill Taylor 		if (ret == EIO) {
570*9e39c5baSBill Taylor 			goto pio_error;
571*9e39c5baSBill Taylor 		}
572*9e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
573*9e39c5baSBill Taylor 		return (ret);
574*9e39c5baSBill Taylor 	}
575*9e39c5baSBill Taylor 
576*9e39c5baSBill Taylor 	/* Read CFI info */
577*9e39c5baSBill Taylor 	if ((ret = hermon_flash_cfi_init(state, &init_info.af_cfi_info[0],
578*9e39c5baSBill Taylor 	    &intel_xcmd)) != 0) {
579*9e39c5baSBill Taylor 		if (ret == EIO) {
580*9e39c5baSBill Taylor 			goto pio_error;
581*9e39c5baSBill Taylor 		}
582*9e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
583*9e39c5baSBill Taylor 		return (ret);
584*9e39c5baSBill Taylor 	}
585*9e39c5baSBill Taylor 
586*9e39c5baSBill Taylor 	/*
587*9e39c5baSBill Taylor 	 * Return error if the command set is unknown.
588*9e39c5baSBill Taylor 	 */
589*9e39c5baSBill Taylor 	if (state->hs_fw_cmdset == HERMON_FLASH_UNKNOWN_CMDSET) {
590*9e39c5baSBill Taylor 		if ((ret = hermon_ioctl_flash_cleanup_nolock(state)) != 0) {
591*9e39c5baSBill Taylor 			if (ret == EIO) {
592*9e39c5baSBill Taylor 				goto pio_error;
593*9e39c5baSBill Taylor 			}
594*9e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
595*9e39c5baSBill Taylor 			return (ret);
596*9e39c5baSBill Taylor 		}
597*9e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
598*9e39c5baSBill Taylor 		return (EFAULT);
599*9e39c5baSBill Taylor 	}
600*9e39c5baSBill Taylor 
601*9e39c5baSBill Taylor 	/* the FMA retry loop starts. */
602*9e39c5baSBill Taylor 	hermon_pio_start(state, pci_hdl, pio_error,
603*9e39c5baSBill Taylor 	    fm_loop_cnt, fm_status, fm_test);
604*9e39c5baSBill Taylor 
605*9e39c5baSBill Taylor 	/* Read HWREV - least significant 8 bits is revision ID */
606*9e39c5baSBill Taylor 	init_info.af_hwrev = pci_config_get32(pci_hdl,
607*9e39c5baSBill Taylor 	    HERMON_HW_FLASH_CFG_HWREV) & 0xFF;
608*9e39c5baSBill Taylor 
609*9e39c5baSBill Taylor 	/* the FMA retry loop ends. */
610*9e39c5baSBill Taylor 	hermon_pio_end(state, pci_hdl, pio_error, fm_loop_cnt,
611*9e39c5baSBill Taylor 	    fm_status, fm_test);
612*9e39c5baSBill Taylor 
613*9e39c5baSBill Taylor 	/* Fill in the firmwate revision numbers */
614*9e39c5baSBill Taylor 	init_info.af_fwrev.afi_maj	= state->hs_fw.fw_rev_major;
615*9e39c5baSBill Taylor 	init_info.af_fwrev.afi_min	= state->hs_fw.fw_rev_minor;
616*9e39c5baSBill Taylor 	init_info.af_fwrev.afi_sub	= state->hs_fw.fw_rev_subminor;
617*9e39c5baSBill Taylor 
618*9e39c5baSBill Taylor 	/* Alloc flash mem for one sector size */
619*9e39c5baSBill Taylor 	state->hs_fw_sector = (uint32_t *)kmem_zalloc(1 <<
620*9e39c5baSBill Taylor 	    state->hs_fw_log_sector_sz, KM_SLEEP);
621*9e39c5baSBill Taylor 
622*9e39c5baSBill Taylor 	/* Set HW part number and length */
623*9e39c5baSBill Taylor 	init_info.af_pn_len = state->hs_hca_pn_len;
624*9e39c5baSBill Taylor 	if (state->hs_hca_pn_len != 0) {
625*9e39c5baSBill Taylor 		(void) memcpy(init_info.af_hwpn, state->hs_hca_pn,
626*9e39c5baSBill Taylor 		    state->hs_hca_pn_len);
627*9e39c5baSBill Taylor 	}
628*9e39c5baSBill Taylor 
629*9e39c5baSBill Taylor 	/* Copy ioctl results back to userland */
630*9e39c5baSBill Taylor 	if (ddi_copyout(&init_info, (void *)arg,
631*9e39c5baSBill Taylor 	    sizeof (hermon_flash_init_ioctl_t), mode) != 0) {
632*9e39c5baSBill Taylor 		if ((ret = hermon_ioctl_flash_cleanup_nolock(state)) != 0) {
633*9e39c5baSBill Taylor 			if (ret == EIO) {
634*9e39c5baSBill Taylor 				goto pio_error;
635*9e39c5baSBill Taylor 			}
636*9e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
637*9e39c5baSBill Taylor 			return (ret);
638*9e39c5baSBill Taylor 		}
639*9e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
640*9e39c5baSBill Taylor 		return (EFAULT);
641*9e39c5baSBill Taylor 	}
642*9e39c5baSBill Taylor 
643*9e39c5baSBill Taylor 	/* Set flash state to started */
644*9e39c5baSBill Taylor 	state->hs_fw_flashstarted = 1;
645*9e39c5baSBill Taylor 	state->hs_fw_flashdev	  = dev;
646*9e39c5baSBill Taylor 
647*9e39c5baSBill Taylor 	mutex_exit(&state->hs_fw_flashlock);
648*9e39c5baSBill Taylor 
649*9e39c5baSBill Taylor 	/*
650*9e39c5baSBill Taylor 	 * If "flash init" is successful, add an "on close" callback to the
651*9e39c5baSBill Taylor 	 * current dev node to ensure that "flash fini" gets called later
652*9e39c5baSBill Taylor 	 * even if the userland process prematurely exits.
653*9e39c5baSBill Taylor 	 */
654*9e39c5baSBill Taylor 	ret = hermon_umap_db_set_onclose_cb(dev,
655*9e39c5baSBill Taylor 	    HERMON_ONCLOSE_FLASH_INPROGRESS,
656*9e39c5baSBill Taylor 	    (int (*)(void *))hermon_ioctl_flash_cleanup, state);
657*9e39c5baSBill Taylor 	if (ret != DDI_SUCCESS) {
658*9e39c5baSBill Taylor 		int status = hermon_ioctl_flash_fini(state, dev);
659*9e39c5baSBill Taylor 		if (status != 0) {
660*9e39c5baSBill Taylor 			if (status == EIO) {
661*9e39c5baSBill Taylor 				hermon_fm_ereport(state, HCA_SYS_ERR,
662*9e39c5baSBill Taylor 				    HCA_ERR_IOCTL);
663*9e39c5baSBill Taylor 				return (EIO);
664*9e39c5baSBill Taylor 			}
665*9e39c5baSBill Taylor 			return (status);
666*9e39c5baSBill Taylor 		}
667*9e39c5baSBill Taylor 	}
668*9e39c5baSBill Taylor 	return (0);
669*9e39c5baSBill Taylor 
670*9e39c5baSBill Taylor pio_error:
671*9e39c5baSBill Taylor 	mutex_exit(&state->hs_fw_flashlock);
672*9e39c5baSBill Taylor 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
673*9e39c5baSBill Taylor 	return (EIO);
674*9e39c5baSBill Taylor }
675*9e39c5baSBill Taylor 
676*9e39c5baSBill Taylor /*
677*9e39c5baSBill Taylor  * hermon_ioctl_flash_fini()
678*9e39c5baSBill Taylor  */
679*9e39c5baSBill Taylor static int
680*9e39c5baSBill Taylor hermon_ioctl_flash_fini(hermon_state_t *state, dev_t dev)
681*9e39c5baSBill Taylor {
682*9e39c5baSBill Taylor 	int ret;
683*9e39c5baSBill Taylor 
684*9e39c5baSBill Taylor 	/*
685*9e39c5baSBill Taylor 	 * Check that flash init ioctl has been called first.  And check
686*9e39c5baSBill Taylor 	 * that the same dev_t that called init is the one calling fini now.
687*9e39c5baSBill Taylor 	 */
688*9e39c5baSBill Taylor 	mutex_enter(&state->hs_fw_flashlock);
689*9e39c5baSBill Taylor 	if ((state->hs_fw_flashdev != dev) ||
690*9e39c5baSBill Taylor 	    (state->hs_fw_flashstarted == 0)) {
691*9e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
692*9e39c5baSBill Taylor 		return (EINVAL);
693*9e39c5baSBill Taylor 	}
694*9e39c5baSBill Taylor 
695*9e39c5baSBill Taylor 	if ((ret = hermon_ioctl_flash_cleanup_nolock(state)) != 0) {
696*9e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
697*9e39c5baSBill Taylor 		if (ret == EIO) {
698*9e39c5baSBill Taylor 			hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
699*9e39c5baSBill Taylor 		}
700*9e39c5baSBill Taylor 		return (ret);
701*9e39c5baSBill Taylor 	}
702*9e39c5baSBill Taylor 	mutex_exit(&state->hs_fw_flashlock);
703*9e39c5baSBill Taylor 
704*9e39c5baSBill Taylor 	/*
705*9e39c5baSBill Taylor 	 * If "flash fini" is successful, remove the "on close" callback
706*9e39c5baSBill Taylor 	 * that was setup during "flash init".
707*9e39c5baSBill Taylor 	 */
708*9e39c5baSBill Taylor 	ret = hermon_umap_db_clear_onclose_cb(dev,
709*9e39c5baSBill Taylor 	    HERMON_ONCLOSE_FLASH_INPROGRESS);
710*9e39c5baSBill Taylor 	if (ret != DDI_SUCCESS) {
711*9e39c5baSBill Taylor 		return (EFAULT);
712*9e39c5baSBill Taylor 	}
713*9e39c5baSBill Taylor 	return (0);
714*9e39c5baSBill Taylor }
715*9e39c5baSBill Taylor 
716*9e39c5baSBill Taylor 
717*9e39c5baSBill Taylor /*
718*9e39c5baSBill Taylor  * hermon_ioctl_flash_cleanup()
719*9e39c5baSBill Taylor  */
720*9e39c5baSBill Taylor static int
721*9e39c5baSBill Taylor hermon_ioctl_flash_cleanup(hermon_state_t *state)
722*9e39c5baSBill Taylor {
723*9e39c5baSBill Taylor 	int status;
724*9e39c5baSBill Taylor 
725*9e39c5baSBill Taylor 	mutex_enter(&state->hs_fw_flashlock);
726*9e39c5baSBill Taylor 	status = hermon_ioctl_flash_cleanup_nolock(state);
727*9e39c5baSBill Taylor 	mutex_exit(&state->hs_fw_flashlock);
728*9e39c5baSBill Taylor 
729*9e39c5baSBill Taylor 	return (status);
730*9e39c5baSBill Taylor }
731*9e39c5baSBill Taylor 
732*9e39c5baSBill Taylor 
733*9e39c5baSBill Taylor /*
734*9e39c5baSBill Taylor  * hermon_ioctl_flash_cleanup_nolock()
735*9e39c5baSBill Taylor  */
736*9e39c5baSBill Taylor static int
737*9e39c5baSBill Taylor hermon_ioctl_flash_cleanup_nolock(hermon_state_t *state)
738*9e39c5baSBill Taylor {
739*9e39c5baSBill Taylor 	int status;
740*9e39c5baSBill Taylor 	ASSERT(MUTEX_HELD(&state->hs_fw_flashlock));
741*9e39c5baSBill Taylor 
742*9e39c5baSBill Taylor 	/* free flash mem */
743*9e39c5baSBill Taylor 	if (state->hs_fw_sector) {
744*9e39c5baSBill Taylor 		kmem_free(state->hs_fw_sector, 1 << state->hs_fw_log_sector_sz);
745*9e39c5baSBill Taylor 	}
746*9e39c5baSBill Taylor 
747*9e39c5baSBill Taylor 	/* Fini the Flash */
748*9e39c5baSBill Taylor 	if ((status = hermon_flash_fini(state)) != 0)
749*9e39c5baSBill Taylor 		return (status);
750*9e39c5baSBill Taylor 
751*9e39c5baSBill Taylor 	/* Set flash state to fini */
752*9e39c5baSBill Taylor 	state->hs_fw_flashstarted = 0;
753*9e39c5baSBill Taylor 	state->hs_fw_flashdev	  = 0;
754*9e39c5baSBill Taylor 	return (0);
755*9e39c5baSBill Taylor }
756*9e39c5baSBill Taylor 
757*9e39c5baSBill Taylor 
758*9e39c5baSBill Taylor /*
759*9e39c5baSBill Taylor  * hermon_ioctl_info()
760*9e39c5baSBill Taylor  */
761*9e39c5baSBill Taylor static int
762*9e39c5baSBill Taylor hermon_ioctl_info(hermon_state_t *state, dev_t dev, intptr_t arg, int mode)
763*9e39c5baSBill Taylor {
764*9e39c5baSBill Taylor 	hermon_info_ioctl_t	 info;
765*9e39c5baSBill Taylor 	hermon_flash_init_ioctl_t init_info;
766*9e39c5baSBill Taylor 
767*9e39c5baSBill Taylor 	/*
768*9e39c5baSBill Taylor 	 * Access to Hemron VTS ioctls is not allowed in "maintenance mode".
769*9e39c5baSBill Taylor 	 */
770*9e39c5baSBill Taylor 	if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) {
771*9e39c5baSBill Taylor 		return (EFAULT);
772*9e39c5baSBill Taylor 	}
773*9e39c5baSBill Taylor 
774*9e39c5baSBill Taylor 	/* copyin the user struct to kernel */
775*9e39c5baSBill Taylor 	if (ddi_copyin((void *)arg, &info, sizeof (hermon_info_ioctl_t),
776*9e39c5baSBill Taylor 	    mode) != 0) {
777*9e39c5baSBill Taylor 		return (EFAULT);
778*9e39c5baSBill Taylor 	}
779*9e39c5baSBill Taylor 
780*9e39c5baSBill Taylor 	/*
781*9e39c5baSBill Taylor 	 * Check ioctl revision
782*9e39c5baSBill Taylor 	 */
783*9e39c5baSBill Taylor 	if (info.ai_revision != HERMON_VTS_IOCTL_REVISION) {
784*9e39c5baSBill Taylor 		return (EINVAL);
785*9e39c5baSBill Taylor 	}
786*9e39c5baSBill Taylor 
787*9e39c5baSBill Taylor 	/*
788*9e39c5baSBill Taylor 	 * If the 'fw_device_sz' has not been initialized yet, we initialize it
789*9e39c5baSBill Taylor 	 * here.  This is done by leveraging the
790*9e39c5baSBill Taylor 	 * hermon_ioctl_flash_init()/fini() calls.  We also hold our own mutex
791*9e39c5baSBill Taylor 	 * around this operation in case we have multiple VTS threads in
792*9e39c5baSBill Taylor 	 * process at the same time.
793*9e39c5baSBill Taylor 	 */
794*9e39c5baSBill Taylor 	mutex_enter(&state->hs_info_lock);
795*9e39c5baSBill Taylor 	if (state->hs_fw_device_sz == 0) {
796*9e39c5baSBill Taylor 		if (hermon_ioctl_flash_init(state, dev, (intptr_t)&init_info,
797*9e39c5baSBill Taylor 		    (FKIOCTL | mode)) != 0) {
798*9e39c5baSBill Taylor 			mutex_exit(&state->hs_info_lock);
799*9e39c5baSBill Taylor 			return (EFAULT);
800*9e39c5baSBill Taylor 		}
801*9e39c5baSBill Taylor 		(void) hermon_ioctl_flash_fini(state, dev);
802*9e39c5baSBill Taylor 	}
803*9e39c5baSBill Taylor 	mutex_exit(&state->hs_info_lock);
804*9e39c5baSBill Taylor 
805*9e39c5baSBill Taylor 	info.ai_hw_rev		 = state->hs_revision_id;
806*9e39c5baSBill Taylor 	info.ai_flash_sz	 = state->hs_fw_device_sz;
807*9e39c5baSBill Taylor 	info.ai_fw_rev.afi_maj	 = state->hs_fw.fw_rev_major;
808*9e39c5baSBill Taylor 	info.ai_fw_rev.afi_min	 = state->hs_fw.fw_rev_minor;
809*9e39c5baSBill Taylor 	info.ai_fw_rev.afi_sub	 = state->hs_fw.fw_rev_subminor;
810*9e39c5baSBill Taylor 
811*9e39c5baSBill Taylor 	/* Copy ioctl results back to user struct */
812*9e39c5baSBill Taylor 	if (ddi_copyout(&info, (void *)arg, sizeof (hermon_info_ioctl_t),
813*9e39c5baSBill Taylor 	    mode) != 0) {
814*9e39c5baSBill Taylor 		return (EFAULT);
815*9e39c5baSBill Taylor 	}
816*9e39c5baSBill Taylor 
817*9e39c5baSBill Taylor 	return (0);
818*9e39c5baSBill Taylor }
819*9e39c5baSBill Taylor 
820*9e39c5baSBill Taylor /*
821*9e39c5baSBill Taylor  * hermon_ioctl_ports()
822*9e39c5baSBill Taylor  */
823*9e39c5baSBill Taylor static int
824*9e39c5baSBill Taylor hermon_ioctl_ports(hermon_state_t *state, intptr_t arg, int mode)
825*9e39c5baSBill Taylor {
826*9e39c5baSBill Taylor 	hermon_ports_ioctl_t	info;
827*9e39c5baSBill Taylor 	hermon_stat_port_ioctl_t	portstat;
828*9e39c5baSBill Taylor 	ibt_hca_portinfo_t	pi;
829*9e39c5baSBill Taylor 	uint_t			tbl_size;
830*9e39c5baSBill Taylor 	ib_gid_t		*sgid_tbl;
831*9e39c5baSBill Taylor 	ib_pkey_t		*pkey_tbl;
832*9e39c5baSBill Taylor 	int			i;
833*9e39c5baSBill Taylor 
834*9e39c5baSBill Taylor 	/*
835*9e39c5baSBill Taylor 	 * Access to Hemron VTS ioctls is not allowed in "maintenance mode".
836*9e39c5baSBill Taylor 	 */
837*9e39c5baSBill Taylor 	if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) {
838*9e39c5baSBill Taylor 		return (EFAULT);
839*9e39c5baSBill Taylor 	}
840*9e39c5baSBill Taylor 
841*9e39c5baSBill Taylor 	/* copyin the user struct to kernel */
842*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
843*9e39c5baSBill Taylor 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
844*9e39c5baSBill Taylor 		hermon_ports_ioctl32_t info32;
845*9e39c5baSBill Taylor 
846*9e39c5baSBill Taylor 		if (ddi_copyin((void *)arg, &info32,
847*9e39c5baSBill Taylor 		    sizeof (hermon_ports_ioctl32_t), mode) != 0) {
848*9e39c5baSBill Taylor 			return (EFAULT);
849*9e39c5baSBill Taylor 		}
850*9e39c5baSBill Taylor 		info.ap_revision  = info32.ap_revision;
851*9e39c5baSBill Taylor 		info.ap_ports	  =
852*9e39c5baSBill Taylor 		    (hermon_stat_port_ioctl_t *)(uintptr_t)info32.ap_ports;
853*9e39c5baSBill Taylor 		info.ap_num_ports = info32.ap_num_ports;
854*9e39c5baSBill Taylor 
855*9e39c5baSBill Taylor 	} else
856*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
857*9e39c5baSBill Taylor 	if (ddi_copyin((void *)arg, &info, sizeof (hermon_ports_ioctl_t),
858*9e39c5baSBill Taylor 	    mode) != 0) {
859*9e39c5baSBill Taylor 		return (EFAULT);
860*9e39c5baSBill Taylor 	}
861*9e39c5baSBill Taylor 
862*9e39c5baSBill Taylor 	/*
863*9e39c5baSBill Taylor 	 * Check ioctl revision
864*9e39c5baSBill Taylor 	 */
865*9e39c5baSBill Taylor 	if (info.ap_revision != HERMON_VTS_IOCTL_REVISION) {
866*9e39c5baSBill Taylor 		return (EINVAL);
867*9e39c5baSBill Taylor 	}
868*9e39c5baSBill Taylor 
869*9e39c5baSBill Taylor 	/* Allocate space for temporary GID table/PKey table */
870*9e39c5baSBill Taylor 	tbl_size = (1 << state->hs_cfg_profile->cp_log_max_gidtbl);
871*9e39c5baSBill Taylor 	sgid_tbl = (ib_gid_t *)kmem_zalloc(tbl_size * sizeof (ib_gid_t),
872*9e39c5baSBill Taylor 	    KM_SLEEP);
873*9e39c5baSBill Taylor 	tbl_size = (1 << state->hs_cfg_profile->cp_log_max_pkeytbl);
874*9e39c5baSBill Taylor 	pkey_tbl = (ib_pkey_t *)kmem_zalloc(tbl_size * sizeof (ib_pkey_t),
875*9e39c5baSBill Taylor 	    KM_SLEEP);
876*9e39c5baSBill Taylor 
877*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*sgid_tbl, *pkey_tbl))
878*9e39c5baSBill Taylor 
879*9e39c5baSBill Taylor 	/*
880*9e39c5baSBill Taylor 	 * Setup the number of ports, then loop through all ports and
881*9e39c5baSBill Taylor 	 * query properties of each.
882*9e39c5baSBill Taylor 	 */
883*9e39c5baSBill Taylor 	info.ap_num_ports = (uint8_t)state->hs_cfg_profile->cp_num_ports;
884*9e39c5baSBill Taylor 	for (i = 0; i < info.ap_num_ports; i++) {
885*9e39c5baSBill Taylor 		/*
886*9e39c5baSBill Taylor 		 * Get portstate information from the device.  If
887*9e39c5baSBill Taylor 		 * hermon_port_query() fails, leave zeroes in user
888*9e39c5baSBill Taylor 		 * struct port entry and continue.
889*9e39c5baSBill Taylor 		 */
890*9e39c5baSBill Taylor 		bzero(&pi, sizeof (ibt_hca_portinfo_t));
891*9e39c5baSBill Taylor 		pi.p_sgid_tbl = sgid_tbl;
892*9e39c5baSBill Taylor 		pi.p_pkey_tbl = pkey_tbl;
893*9e39c5baSBill Taylor 		(void) hermon_port_query(state, i + 1, &pi);
894*9e39c5baSBill Taylor 
895*9e39c5baSBill Taylor 		portstat.asp_port_num	= pi.p_port_num;
896*9e39c5baSBill Taylor 		portstat.asp_state	= pi.p_linkstate;
897*9e39c5baSBill Taylor 		portstat.asp_guid	= pi.p_sgid_tbl[0].gid_guid;
898*9e39c5baSBill Taylor 
899*9e39c5baSBill Taylor 		/*
900*9e39c5baSBill Taylor 		 * Copy queried port results back to user struct.  If
901*9e39c5baSBill Taylor 		 * this fails, then break out of loop, attempt to copy
902*9e39c5baSBill Taylor 		 * out remaining info to user struct, and return (without
903*9e39c5baSBill Taylor 		 * error).
904*9e39c5baSBill Taylor 		 */
905*9e39c5baSBill Taylor 		if (ddi_copyout(&portstat,
906*9e39c5baSBill Taylor 		    &(((hermon_stat_port_ioctl_t *)info.ap_ports)[i]),
907*9e39c5baSBill Taylor 		    sizeof (hermon_stat_port_ioctl_t), mode) != 0) {
908*9e39c5baSBill Taylor 			break;
909*9e39c5baSBill Taylor 		}
910*9e39c5baSBill Taylor 	}
911*9e39c5baSBill Taylor 
912*9e39c5baSBill Taylor 	/* Free the temporary space used for GID table/PKey table */
913*9e39c5baSBill Taylor 	tbl_size = (1 << state->hs_cfg_profile->cp_log_max_gidtbl);
914*9e39c5baSBill Taylor 	kmem_free(sgid_tbl, tbl_size * sizeof (ib_gid_t));
915*9e39c5baSBill Taylor 	tbl_size = (1 << state->hs_cfg_profile->cp_log_max_pkeytbl);
916*9e39c5baSBill Taylor 	kmem_free(pkey_tbl, tbl_size * sizeof (ib_pkey_t));
917*9e39c5baSBill Taylor 
918*9e39c5baSBill Taylor 	/* Copy ioctl results back to user struct */
919*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
920*9e39c5baSBill Taylor 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
921*9e39c5baSBill Taylor 		hermon_ports_ioctl32_t info32;
922*9e39c5baSBill Taylor 
923*9e39c5baSBill Taylor 		info32.ap_revision  = info.ap_revision;
924*9e39c5baSBill Taylor 		info32.ap_ports	    = (caddr32_t)(uintptr_t)info.ap_ports;
925*9e39c5baSBill Taylor 		info32.ap_num_ports = info.ap_num_ports;
926*9e39c5baSBill Taylor 
927*9e39c5baSBill Taylor 		if (ddi_copyout(&info32, (void *)arg,
928*9e39c5baSBill Taylor 		    sizeof (hermon_ports_ioctl32_t), mode) != 0) {
929*9e39c5baSBill Taylor 			return (EFAULT);
930*9e39c5baSBill Taylor 		}
931*9e39c5baSBill Taylor 	} else
932*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
933*9e39c5baSBill Taylor 	if (ddi_copyout(&info, (void *)arg, sizeof (hermon_ports_ioctl_t),
934*9e39c5baSBill Taylor 	    mode) != 0) {
935*9e39c5baSBill Taylor 		return (EFAULT);
936*9e39c5baSBill Taylor 	}
937*9e39c5baSBill Taylor 
938*9e39c5baSBill Taylor 	return (0);
939*9e39c5baSBill Taylor }
940*9e39c5baSBill Taylor 
941*9e39c5baSBill Taylor /*
942*9e39c5baSBill Taylor  * hermon_ioctl_loopback()
943*9e39c5baSBill Taylor  */
944*9e39c5baSBill Taylor static int
945*9e39c5baSBill Taylor hermon_ioctl_loopback(hermon_state_t *state, intptr_t arg, int mode)
946*9e39c5baSBill Taylor {
947*9e39c5baSBill Taylor 	hermon_loopback_ioctl_t	lb;
948*9e39c5baSBill Taylor 	hermon_loopback_state_t	lstate;
949*9e39c5baSBill Taylor 	ibt_hca_portinfo_t 	pi;
950*9e39c5baSBill Taylor 	uint_t			tbl_size, loopmax, max_usec;
951*9e39c5baSBill Taylor 	ib_gid_t		*sgid_tbl;
952*9e39c5baSBill Taylor 	ib_pkey_t		*pkey_tbl;
953*9e39c5baSBill Taylor 	int			j, iter, ret;
954*9e39c5baSBill Taylor 
955*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(lstate))
956*9e39c5baSBill Taylor 
957*9e39c5baSBill Taylor 	/*
958*9e39c5baSBill Taylor 	 * Access to Hemron VTS ioctls is not allowed in "maintenance mode".
959*9e39c5baSBill Taylor 	 */
960*9e39c5baSBill Taylor 	if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) {
961*9e39c5baSBill Taylor 		return (EFAULT);
962*9e39c5baSBill Taylor 	}
963*9e39c5baSBill Taylor 
964*9e39c5baSBill Taylor 	/* copyin the user struct to kernel */
965*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
966*9e39c5baSBill Taylor 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
967*9e39c5baSBill Taylor 		hermon_loopback_ioctl32_t lb32;
968*9e39c5baSBill Taylor 
969*9e39c5baSBill Taylor 		if (ddi_copyin((void *)arg, &lb32,
970*9e39c5baSBill Taylor 		    sizeof (hermon_loopback_ioctl32_t), mode) != 0) {
971*9e39c5baSBill Taylor 			return (EFAULT);
972*9e39c5baSBill Taylor 		}
973*9e39c5baSBill Taylor 		lb.alb_revision	    = lb32.alb_revision;
974*9e39c5baSBill Taylor 		lb.alb_send_buf	    = (caddr_t)(uintptr_t)lb32.alb_send_buf;
975*9e39c5baSBill Taylor 		lb.alb_fail_buf	    = (caddr_t)(uintptr_t)lb32.alb_fail_buf;
976*9e39c5baSBill Taylor 		lb.alb_buf_sz	    = lb32.alb_buf_sz;
977*9e39c5baSBill Taylor 		lb.alb_num_iter	    = lb32.alb_num_iter;
978*9e39c5baSBill Taylor 		lb.alb_pass_done    = lb32.alb_pass_done;
979*9e39c5baSBill Taylor 		lb.alb_timeout	    = lb32.alb_timeout;
980*9e39c5baSBill Taylor 		lb.alb_error_type   = lb32.alb_error_type;
981*9e39c5baSBill Taylor 		lb.alb_port_num	    = lb32.alb_port_num;
982*9e39c5baSBill Taylor 		lb.alb_num_retry    = lb32.alb_num_retry;
983*9e39c5baSBill Taylor 	} else
984*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
985*9e39c5baSBill Taylor 	if (ddi_copyin((void *)arg, &lb, sizeof (hermon_loopback_ioctl_t),
986*9e39c5baSBill Taylor 	    mode) != 0) {
987*9e39c5baSBill Taylor 		return (EFAULT);
988*9e39c5baSBill Taylor 	}
989*9e39c5baSBill Taylor 
990*9e39c5baSBill Taylor 	/* Initialize the internal loopback test state structure */
991*9e39c5baSBill Taylor 	bzero(&lstate, sizeof (hermon_loopback_state_t));
992*9e39c5baSBill Taylor 
993*9e39c5baSBill Taylor 	/*
994*9e39c5baSBill Taylor 	 * Check ioctl revision
995*9e39c5baSBill Taylor 	 */
996*9e39c5baSBill Taylor 	if (lb.alb_revision != HERMON_VTS_IOCTL_REVISION) {
997*9e39c5baSBill Taylor 		lb.alb_error_type = HERMON_LOOPBACK_INVALID_REVISION;
998*9e39c5baSBill Taylor 		(void) hermon_loopback_copyout(&lb, arg, mode);
999*9e39c5baSBill Taylor 		return (EINVAL);
1000*9e39c5baSBill Taylor 	}
1001*9e39c5baSBill Taylor 
1002*9e39c5baSBill Taylor 	/* Validate that specified port number is legal */
1003*9e39c5baSBill Taylor 	if (!hermon_portnum_is_valid(state, lb.alb_port_num)) {
1004*9e39c5baSBill Taylor 		lb.alb_error_type = HERMON_LOOPBACK_INVALID_PORT;
1005*9e39c5baSBill Taylor 		(void) hermon_loopback_copyout(&lb, arg, mode);
1006*9e39c5baSBill Taylor 		return (EINVAL);
1007*9e39c5baSBill Taylor 	}
1008*9e39c5baSBill Taylor 
1009*9e39c5baSBill Taylor 	/* Allocate space for temporary GID table/PKey table */
1010*9e39c5baSBill Taylor 	tbl_size = (1 << state->hs_cfg_profile->cp_log_max_gidtbl);
1011*9e39c5baSBill Taylor 	sgid_tbl = (ib_gid_t *)kmem_zalloc(tbl_size * sizeof (ib_gid_t),
1012*9e39c5baSBill Taylor 	    KM_SLEEP);
1013*9e39c5baSBill Taylor 	tbl_size = (1 << state->hs_cfg_profile->cp_log_max_pkeytbl);
1014*9e39c5baSBill Taylor 	pkey_tbl = (ib_pkey_t *)kmem_zalloc(tbl_size * sizeof (ib_pkey_t),
1015*9e39c5baSBill Taylor 	    KM_SLEEP);
1016*9e39c5baSBill Taylor 
1017*9e39c5baSBill Taylor 	/*
1018*9e39c5baSBill Taylor 	 * Get portstate information from specific port on device
1019*9e39c5baSBill Taylor 	 */
1020*9e39c5baSBill Taylor 	bzero(&pi, sizeof (ibt_hca_portinfo_t));
1021*9e39c5baSBill Taylor 	pi.p_sgid_tbl = sgid_tbl;
1022*9e39c5baSBill Taylor 	pi.p_pkey_tbl = pkey_tbl;
1023*9e39c5baSBill Taylor 	if (hermon_port_query(state, lb.alb_port_num, &pi) != 0) {
1024*9e39c5baSBill Taylor 		/* Free the temporary space used for GID table/PKey table */
1025*9e39c5baSBill Taylor 		tbl_size = (1 << state->hs_cfg_profile->cp_log_max_gidtbl);
1026*9e39c5baSBill Taylor 		kmem_free(sgid_tbl, tbl_size * sizeof (ib_gid_t));
1027*9e39c5baSBill Taylor 		tbl_size = (1 << state->hs_cfg_profile->cp_log_max_pkeytbl);
1028*9e39c5baSBill Taylor 		kmem_free(pkey_tbl, tbl_size * sizeof (ib_pkey_t));
1029*9e39c5baSBill Taylor 
1030*9e39c5baSBill Taylor 		lb.alb_error_type = HERMON_LOOPBACK_INVALID_PORT;
1031*9e39c5baSBill Taylor 		(void) hermon_loopback_copyout(&lb, arg, mode);
1032*9e39c5baSBill Taylor 		hermon_loopback_free_state(&lstate);
1033*9e39c5baSBill Taylor 		return (EINVAL);
1034*9e39c5baSBill Taylor 	}
1035*9e39c5baSBill Taylor 
1036*9e39c5baSBill Taylor 	lstate.hls_port	   = pi.p_port_num;
1037*9e39c5baSBill Taylor 	lstate.hls_lid	   = pi.p_base_lid;
1038*9e39c5baSBill Taylor 	lstate.hls_pkey_ix = (pi.p_linkstate == HERMON_PORT_LINK_ACTIVE) ?
1039*9e39c5baSBill Taylor 	    1 : 0;	/* XXX bogus assumption of a SUN subnet manager */
1040*9e39c5baSBill Taylor 	lstate.hls_state   = state;
1041*9e39c5baSBill Taylor 	lstate.hls_retry   = lb.alb_num_retry;
1042*9e39c5baSBill Taylor 
1043*9e39c5baSBill Taylor 	/* Free the temporary space used for GID table/PKey table */
1044*9e39c5baSBill Taylor 	tbl_size = (1 << state->hs_cfg_profile->cp_log_max_gidtbl);
1045*9e39c5baSBill Taylor 	kmem_free(sgid_tbl, tbl_size * sizeof (ib_gid_t));
1046*9e39c5baSBill Taylor 	tbl_size = (1 << state->hs_cfg_profile->cp_log_max_pkeytbl);
1047*9e39c5baSBill Taylor 	kmem_free(pkey_tbl, tbl_size * sizeof (ib_pkey_t));
1048*9e39c5baSBill Taylor 
1049*9e39c5baSBill Taylor 	/*
1050*9e39c5baSBill Taylor 	 * Compute the timeout duration in usec per the formula:
1051*9e39c5baSBill Taylor 	 *    to_usec_per_retry = 4.096us * (2 ^ supplied_timeout)
1052*9e39c5baSBill Taylor 	 * (plus we add a little fudge-factor here too)
1053*9e39c5baSBill Taylor 	 */
1054*9e39c5baSBill Taylor 	lstate.hls_timeout = lb.alb_timeout;
1055*9e39c5baSBill Taylor 	max_usec = (4096 * (1 << lstate.hls_timeout)) / 1000;
1056*9e39c5baSBill Taylor 	max_usec = max_usec * (lstate.hls_retry + 1);
1057*9e39c5baSBill Taylor 	max_usec = max_usec + 10000;
1058*9e39c5baSBill Taylor 
1059*9e39c5baSBill Taylor 	/*
1060*9e39c5baSBill Taylor 	 * Determine how many times we should loop before declaring a
1061*9e39c5baSBill Taylor 	 * timeout failure.
1062*9e39c5baSBill Taylor 	 */
1063*9e39c5baSBill Taylor 	loopmax	 = max_usec/HERMON_VTS_LOOPBACK_MIN_WAIT_DUR;
1064*9e39c5baSBill Taylor 	if ((max_usec % HERMON_VTS_LOOPBACK_MIN_WAIT_DUR) != 0) {
1065*9e39c5baSBill Taylor 		loopmax++;
1066*9e39c5baSBill Taylor 	}
1067*9e39c5baSBill Taylor 
1068*9e39c5baSBill Taylor 	if (lb.alb_send_buf == NULL || lb.alb_buf_sz == 0) {
1069*9e39c5baSBill Taylor 		lb.alb_error_type = HERMON_LOOPBACK_SEND_BUF_INVALID;
1070*9e39c5baSBill Taylor 		(void) hermon_loopback_copyout(&lb, arg, mode);
1071*9e39c5baSBill Taylor 		hermon_loopback_free_state(&lstate);
1072*9e39c5baSBill Taylor 		return (EINVAL);
1073*9e39c5baSBill Taylor 	}
1074*9e39c5baSBill Taylor 
1075*9e39c5baSBill Taylor 	/* Allocate protection domain (PD) */
1076*9e39c5baSBill Taylor 	if (hermon_loopback_init(state, &lstate) != 0) {
1077*9e39c5baSBill Taylor 		lb.alb_error_type = lstate.hls_err;
1078*9e39c5baSBill Taylor 		(void) hermon_loopback_copyout(&lb, arg, mode);
1079*9e39c5baSBill Taylor 		hermon_loopback_free_state(&lstate);
1080*9e39c5baSBill Taylor 		return (EFAULT);
1081*9e39c5baSBill Taylor 	}
1082*9e39c5baSBill Taylor 
1083*9e39c5baSBill Taylor 	/* Allocate and register a TX buffer */
1084*9e39c5baSBill Taylor 	if (hermon_loopback_alloc_mem(&lstate, &lstate.hls_tx,
1085*9e39c5baSBill Taylor 	    lb.alb_buf_sz) != 0) {
1086*9e39c5baSBill Taylor 		lb.alb_error_type =
1087*9e39c5baSBill Taylor 		    HERMON_LOOPBACK_SEND_BUF_MEM_REGION_ALLOC_FAIL;
1088*9e39c5baSBill Taylor 		(void) hermon_loopback_copyout(&lb, arg, mode);
1089*9e39c5baSBill Taylor 		hermon_loopback_free_state(&lstate);
1090*9e39c5baSBill Taylor 		return (EFAULT);
1091*9e39c5baSBill Taylor 	}
1092*9e39c5baSBill Taylor 
1093*9e39c5baSBill Taylor 	/* Allocate and register an RX buffer */
1094*9e39c5baSBill Taylor 	if (hermon_loopback_alloc_mem(&lstate, &lstate.hls_rx,
1095*9e39c5baSBill Taylor 	    lb.alb_buf_sz) != 0) {
1096*9e39c5baSBill Taylor 		lb.alb_error_type =
1097*9e39c5baSBill Taylor 		    HERMON_LOOPBACK_RECV_BUF_MEM_REGION_ALLOC_FAIL;
1098*9e39c5baSBill Taylor 		(void) hermon_loopback_copyout(&lb, arg, mode);
1099*9e39c5baSBill Taylor 		hermon_loopback_free_state(&lstate);
1100*9e39c5baSBill Taylor 		return (EFAULT);
1101*9e39c5baSBill Taylor 	}
1102*9e39c5baSBill Taylor 
1103*9e39c5baSBill Taylor 	/* Copy in the transmit buffer data */
1104*9e39c5baSBill Taylor 	if (ddi_copyin((void *)lb.alb_send_buf, lstate.hls_tx.hlc_buf,
1105*9e39c5baSBill Taylor 	    lb.alb_buf_sz, mode) != 0) {
1106*9e39c5baSBill Taylor 		lb.alb_error_type = HERMON_LOOPBACK_SEND_BUF_COPY_FAIL;
1107*9e39c5baSBill Taylor 		(void) hermon_loopback_copyout(&lb, arg, mode);
1108*9e39c5baSBill Taylor 		hermon_loopback_free_state(&lstate);
1109*9e39c5baSBill Taylor 		return (EFAULT);
1110*9e39c5baSBill Taylor 	}
1111*9e39c5baSBill Taylor 
1112*9e39c5baSBill Taylor 	/* Allocate the transmit QP and CQs */
1113*9e39c5baSBill Taylor 	lstate.hls_err = HERMON_LOOPBACK_XMIT_SEND_CQ_ALLOC_FAIL;
1114*9e39c5baSBill Taylor 	if (hermon_loopback_alloc_qps(&lstate, &lstate.hls_tx) != 0) {
1115*9e39c5baSBill Taylor 		lb.alb_error_type = lstate.hls_err;
1116*9e39c5baSBill Taylor 		(void) hermon_loopback_copyout(&lb, arg, mode);
1117*9e39c5baSBill Taylor 		hermon_loopback_free_state(&lstate);
1118*9e39c5baSBill Taylor 		return (EFAULT);
1119*9e39c5baSBill Taylor 	}
1120*9e39c5baSBill Taylor 
1121*9e39c5baSBill Taylor 	/* Allocate the receive QP and CQs */
1122*9e39c5baSBill Taylor 	lstate.hls_err = HERMON_LOOPBACK_RECV_SEND_CQ_ALLOC_FAIL;
1123*9e39c5baSBill Taylor 	if (hermon_loopback_alloc_qps(&lstate, &lstate.hls_rx) != 0) {
1124*9e39c5baSBill Taylor 		lb.alb_error_type = lstate.hls_err;
1125*9e39c5baSBill Taylor 		(void) hermon_loopback_copyout(&lb, arg, mode);
1126*9e39c5baSBill Taylor 		hermon_loopback_free_state(&lstate);
1127*9e39c5baSBill Taylor 		return (EFAULT);
1128*9e39c5baSBill Taylor 	}
1129*9e39c5baSBill Taylor 
1130*9e39c5baSBill Taylor 	/* Activate the TX QP (connect to RX QP) */
1131*9e39c5baSBill Taylor 	lstate.hls_err = HERMON_LOOPBACK_XMIT_QP_INIT_FAIL;
1132*9e39c5baSBill Taylor 	if (hermon_loopback_modify_qp(&lstate, &lstate.hls_tx,
1133*9e39c5baSBill Taylor 	    lstate.hls_rx.hlc_qp_num) != 0) {
1134*9e39c5baSBill Taylor 		lb.alb_error_type = lstate.hls_err;
1135*9e39c5baSBill Taylor 		(void) hermon_loopback_copyout(&lb, arg, mode);
1136*9e39c5baSBill Taylor 		hermon_loopback_free_state(&lstate);
1137*9e39c5baSBill Taylor 		return (EFAULT);
1138*9e39c5baSBill Taylor 	}
1139*9e39c5baSBill Taylor 
1140*9e39c5baSBill Taylor 	/* Activate the RX QP (connect to TX QP) */
1141*9e39c5baSBill Taylor 	lstate.hls_err = HERMON_LOOPBACK_RECV_QP_INIT_FAIL;
1142*9e39c5baSBill Taylor 	if (hermon_loopback_modify_qp(&lstate, &lstate.hls_rx,
1143*9e39c5baSBill Taylor 	    lstate.hls_tx.hlc_qp_num) != 0) {
1144*9e39c5baSBill Taylor 		lb.alb_error_type = lstate.hls_err;
1145*9e39c5baSBill Taylor 		(void) hermon_loopback_copyout(&lb, arg, mode);
1146*9e39c5baSBill Taylor 		hermon_loopback_free_state(&lstate);
1147*9e39c5baSBill Taylor 		return (EFAULT);
1148*9e39c5baSBill Taylor 	}
1149*9e39c5baSBill Taylor 
1150*9e39c5baSBill Taylor 	/* Run the loopback test (for specified number of iterations) */
1151*9e39c5baSBill Taylor 	lb.alb_pass_done = 0;
1152*9e39c5baSBill Taylor 	for (iter = 0; iter < lb.alb_num_iter; iter++) {
1153*9e39c5baSBill Taylor 		lstate.hls_err = 0;
1154*9e39c5baSBill Taylor 		bzero(lstate.hls_rx.hlc_buf, lb.alb_buf_sz);
1155*9e39c5baSBill Taylor 
1156*9e39c5baSBill Taylor 		/* Post RDMA Write work request */
1157*9e39c5baSBill Taylor 		if (hermon_loopback_post_send(&lstate, &lstate.hls_tx,
1158*9e39c5baSBill Taylor 		    &lstate.hls_rx) != IBT_SUCCESS) {
1159*9e39c5baSBill Taylor 			lb.alb_error_type = HERMON_LOOPBACK_WQE_POST_FAIL;
1160*9e39c5baSBill Taylor 			(void) hermon_loopback_copyout(&lb, arg, mode);
1161*9e39c5baSBill Taylor 			hermon_loopback_free_state(&lstate);
1162*9e39c5baSBill Taylor 			return (EFAULT);
1163*9e39c5baSBill Taylor 		}
1164*9e39c5baSBill Taylor 
1165*9e39c5baSBill Taylor 		/* Poll the TX CQ for a completion every few ticks */
1166*9e39c5baSBill Taylor 		for (j = 0; j < loopmax; j++) {
1167*9e39c5baSBill Taylor 			delay(drv_usectohz(HERMON_VTS_LOOPBACK_MIN_WAIT_DUR));
1168*9e39c5baSBill Taylor 
1169*9e39c5baSBill Taylor 			ret = hermon_loopback_poll_cq(&lstate, &lstate.hls_tx);
1170*9e39c5baSBill Taylor 			if (((ret != IBT_SUCCESS) && (ret != IBT_CQ_EMPTY)) ||
1171*9e39c5baSBill Taylor 			    ((ret == IBT_CQ_EMPTY) && (j == loopmax - 1))) {
1172*9e39c5baSBill Taylor 				lb.alb_error_type =
1173*9e39c5baSBill Taylor 				    HERMON_LOOPBACK_CQ_POLL_FAIL;
1174*9e39c5baSBill Taylor 				if (ddi_copyout(lstate.hls_rx.hlc_buf,
1175*9e39c5baSBill Taylor 				    lb.alb_fail_buf, lstate.hls_tx.hlc_buf_sz,
1176*9e39c5baSBill Taylor 				    mode) != 0) {
1177*9e39c5baSBill Taylor 					return (EFAULT);
1178*9e39c5baSBill Taylor 				}
1179*9e39c5baSBill Taylor 				(void) hermon_loopback_copyout(&lb, arg, mode);
1180*9e39c5baSBill Taylor 				hermon_loopback_free_state(&lstate);
1181*9e39c5baSBill Taylor 				return (EFAULT);
1182*9e39c5baSBill Taylor 			} else if (ret == IBT_CQ_EMPTY) {
1183*9e39c5baSBill Taylor 				continue;
1184*9e39c5baSBill Taylor 			}
1185*9e39c5baSBill Taylor 
1186*9e39c5baSBill Taylor 			/* Compare the data buffers */
1187*9e39c5baSBill Taylor 			if (bcmp(lstate.hls_tx.hlc_buf, lstate.hls_rx.hlc_buf,
1188*9e39c5baSBill Taylor 			    lb.alb_buf_sz) == 0) {
1189*9e39c5baSBill Taylor 				break;
1190*9e39c5baSBill Taylor 			} else {
1191*9e39c5baSBill Taylor 				lb.alb_error_type =
1192*9e39c5baSBill Taylor 				    HERMON_LOOPBACK_SEND_RECV_COMPARE_FAIL;
1193*9e39c5baSBill Taylor 				if (ddi_copyout(lstate.hls_rx.hlc_buf,
1194*9e39c5baSBill Taylor 				    lb.alb_fail_buf, lstate.hls_tx.hlc_buf_sz,
1195*9e39c5baSBill Taylor 				    mode) != 0) {
1196*9e39c5baSBill Taylor 					return (EFAULT);
1197*9e39c5baSBill Taylor 				}
1198*9e39c5baSBill Taylor 				(void) hermon_loopback_copyout(&lb, arg, mode);
1199*9e39c5baSBill Taylor 				hermon_loopback_free_state(&lstate);
1200*9e39c5baSBill Taylor 				return (EFAULT);
1201*9e39c5baSBill Taylor 			}
1202*9e39c5baSBill Taylor 		}
1203*9e39c5baSBill Taylor 
1204*9e39c5baSBill Taylor 		lstate.hls_err	 = HERMON_LOOPBACK_SUCCESS;
1205*9e39c5baSBill Taylor 		lb.alb_pass_done = iter + 1;
1206*9e39c5baSBill Taylor 	}
1207*9e39c5baSBill Taylor 
1208*9e39c5baSBill Taylor 	lb.alb_error_type = HERMON_LOOPBACK_SUCCESS;
1209*9e39c5baSBill Taylor 
1210*9e39c5baSBill Taylor 	/* Copy ioctl results back to user struct */
1211*9e39c5baSBill Taylor 	ret = hermon_loopback_copyout(&lb, arg, mode);
1212*9e39c5baSBill Taylor 
1213*9e39c5baSBill Taylor 	/* Free up everything and release all consumed resources */
1214*9e39c5baSBill Taylor 	hermon_loopback_free_state(&lstate);
1215*9e39c5baSBill Taylor 
1216*9e39c5baSBill Taylor 	return (ret);
1217*9e39c5baSBill Taylor }
1218*9e39c5baSBill Taylor 
1219*9e39c5baSBill Taylor #ifdef	DEBUG
1220*9e39c5baSBill Taylor /*
1221*9e39c5baSBill Taylor  * hermon_ioctl_reg_read()
1222*9e39c5baSBill Taylor  */
1223*9e39c5baSBill Taylor static int
1224*9e39c5baSBill Taylor hermon_ioctl_reg_read(hermon_state_t *state, intptr_t arg, int mode)
1225*9e39c5baSBill Taylor {
1226*9e39c5baSBill Taylor 	hermon_reg_ioctl_t	rdreg;
1227*9e39c5baSBill Taylor 	uint32_t		*addr;
1228*9e39c5baSBill Taylor 	uintptr_t		baseaddr;
1229*9e39c5baSBill Taylor 	int			status;
1230*9e39c5baSBill Taylor 	ddi_acc_handle_t	handle;
1231*9e39c5baSBill Taylor 
1232*9e39c5baSBill Taylor 	/* initialize the FMA retry loop */
1233*9e39c5baSBill Taylor 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
1234*9e39c5baSBill Taylor 
1235*9e39c5baSBill Taylor 	/*
1236*9e39c5baSBill Taylor 	 * Access to Hemron registers is not allowed in "maintenance mode".
1237*9e39c5baSBill Taylor 	 * This is primarily because the device may not have BARs to access
1238*9e39c5baSBill Taylor 	 */
1239*9e39c5baSBill Taylor 	if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) {
1240*9e39c5baSBill Taylor 		return (EFAULT);
1241*9e39c5baSBill Taylor 	}
1242*9e39c5baSBill Taylor 
1243*9e39c5baSBill Taylor 	/* Copy in the hermon_reg_ioctl_t structure */
1244*9e39c5baSBill Taylor 	status = ddi_copyin((void *)arg, &rdreg, sizeof (hermon_reg_ioctl_t),
1245*9e39c5baSBill Taylor 	    mode);
1246*9e39c5baSBill Taylor 	if (status != 0) {
1247*9e39c5baSBill Taylor 		return (EFAULT);
1248*9e39c5baSBill Taylor 	}
1249*9e39c5baSBill Taylor 
1250*9e39c5baSBill Taylor 	/* Determine base address for requested register set */
1251*9e39c5baSBill Taylor 	switch (rdreg.arg_reg_set) {
1252*9e39c5baSBill Taylor 	case HERMON_CMD_BAR:
1253*9e39c5baSBill Taylor 		baseaddr = (uintptr_t)state->hs_reg_cmd_baseaddr;
1254*9e39c5baSBill Taylor 		handle = hermon_get_cmdhdl(state);
1255*9e39c5baSBill Taylor 		break;
1256*9e39c5baSBill Taylor 
1257*9e39c5baSBill Taylor 	case HERMON_UAR_BAR:
1258*9e39c5baSBill Taylor 		baseaddr = (uintptr_t)state->hs_reg_uar_baseaddr;
1259*9e39c5baSBill Taylor 		handle = hermon_get_uarhdl(state);
1260*9e39c5baSBill Taylor 		break;
1261*9e39c5baSBill Taylor 
1262*9e39c5baSBill Taylor 
1263*9e39c5baSBill Taylor 	default:
1264*9e39c5baSBill Taylor 		return (EINVAL);
1265*9e39c5baSBill Taylor 	}
1266*9e39c5baSBill Taylor 
1267*9e39c5baSBill Taylor 	/* Ensure that address is properly-aligned */
1268*9e39c5baSBill Taylor 	addr = (uint32_t *)((baseaddr + rdreg.arg_offset) & ~0x3);
1269*9e39c5baSBill Taylor 
1270*9e39c5baSBill Taylor 	/* the FMA retry loop starts. */
1271*9e39c5baSBill Taylor 	hermon_pio_start(state, handle, pio_error, fm_loop_cnt,
1272*9e39c5baSBill Taylor 	    fm_status, fm_test);
1273*9e39c5baSBill Taylor 
1274*9e39c5baSBill Taylor 	/* Read the register pointed to by addr */
1275*9e39c5baSBill Taylor 	rdreg.arg_data = ddi_get32(handle, addr);
1276*9e39c5baSBill Taylor 
1277*9e39c5baSBill Taylor 	/* the FMA retry loop ends. */
1278*9e39c5baSBill Taylor 	hermon_pio_end(state, handle, pio_error, fm_loop_cnt, fm_status,
1279*9e39c5baSBill Taylor 	    fm_test);
1280*9e39c5baSBill Taylor 
1281*9e39c5baSBill Taylor 	/* Copy in the result into the hermon_reg_ioctl_t structure */
1282*9e39c5baSBill Taylor 	status = ddi_copyout(&rdreg, (void *)arg, sizeof (hermon_reg_ioctl_t),
1283*9e39c5baSBill Taylor 	    mode);
1284*9e39c5baSBill Taylor 	if (status != 0) {
1285*9e39c5baSBill Taylor 		return (EFAULT);
1286*9e39c5baSBill Taylor 	}
1287*9e39c5baSBill Taylor 	return (0);
1288*9e39c5baSBill Taylor 
1289*9e39c5baSBill Taylor pio_error:
1290*9e39c5baSBill Taylor 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
1291*9e39c5baSBill Taylor 	return (EIO);
1292*9e39c5baSBill Taylor }
1293*9e39c5baSBill Taylor 
1294*9e39c5baSBill Taylor 
1295*9e39c5baSBill Taylor /*
1296*9e39c5baSBill Taylor  * hermon_ioctl_reg_write()
1297*9e39c5baSBill Taylor  */
1298*9e39c5baSBill Taylor static int
1299*9e39c5baSBill Taylor hermon_ioctl_reg_write(hermon_state_t *state, intptr_t arg, int mode)
1300*9e39c5baSBill Taylor {
1301*9e39c5baSBill Taylor 	hermon_reg_ioctl_t	wrreg;
1302*9e39c5baSBill Taylor 	uint32_t		*addr;
1303*9e39c5baSBill Taylor 	uintptr_t		baseaddr;
1304*9e39c5baSBill Taylor 	int			status;
1305*9e39c5baSBill Taylor 	ddi_acc_handle_t	handle;
1306*9e39c5baSBill Taylor 
1307*9e39c5baSBill Taylor 	/* initialize the FMA retry loop */
1308*9e39c5baSBill Taylor 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
1309*9e39c5baSBill Taylor 
1310*9e39c5baSBill Taylor 	/*
1311*9e39c5baSBill Taylor 	 * Access to Hermon registers is not allowed in "maintenance mode".
1312*9e39c5baSBill Taylor 	 * This is primarily because the device may not have BARs to access
1313*9e39c5baSBill Taylor 	 */
1314*9e39c5baSBill Taylor 	if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) {
1315*9e39c5baSBill Taylor 		return (EFAULT);
1316*9e39c5baSBill Taylor 	}
1317*9e39c5baSBill Taylor 
1318*9e39c5baSBill Taylor 	/* Copy in the hermon_reg_ioctl_t structure */
1319*9e39c5baSBill Taylor 	status = ddi_copyin((void *)arg, &wrreg, sizeof (hermon_reg_ioctl_t),
1320*9e39c5baSBill Taylor 	    mode);
1321*9e39c5baSBill Taylor 	if (status != 0) {
1322*9e39c5baSBill Taylor 		return (EFAULT);
1323*9e39c5baSBill Taylor 	}
1324*9e39c5baSBill Taylor 
1325*9e39c5baSBill Taylor 	/* Determine base address for requested register set */
1326*9e39c5baSBill Taylor 	switch (wrreg.arg_reg_set) {
1327*9e39c5baSBill Taylor 	case HERMON_CMD_BAR:
1328*9e39c5baSBill Taylor 		baseaddr = (uintptr_t)state->hs_reg_cmd_baseaddr;
1329*9e39c5baSBill Taylor 		handle = hermon_get_cmdhdl(state);
1330*9e39c5baSBill Taylor 		break;
1331*9e39c5baSBill Taylor 
1332*9e39c5baSBill Taylor 	case HERMON_UAR_BAR:
1333*9e39c5baSBill Taylor 		baseaddr = (uintptr_t)state->hs_reg_uar_baseaddr;
1334*9e39c5baSBill Taylor 		handle = hermon_get_uarhdl(state);
1335*9e39c5baSBill Taylor 		break;
1336*9e39c5baSBill Taylor 
1337*9e39c5baSBill Taylor 	default:
1338*9e39c5baSBill Taylor 		return (EINVAL);
1339*9e39c5baSBill Taylor 	}
1340*9e39c5baSBill Taylor 
1341*9e39c5baSBill Taylor 	/* Ensure that address is properly-aligned */
1342*9e39c5baSBill Taylor 	addr = (uint32_t *)((baseaddr + wrreg.arg_offset) & ~0x3);
1343*9e39c5baSBill Taylor 
1344*9e39c5baSBill Taylor 	/* the FMA retry loop starts. */
1345*9e39c5baSBill Taylor 	hermon_pio_start(state, handle, pio_error, fm_loop_cnt,
1346*9e39c5baSBill Taylor 	    fm_status, fm_test);
1347*9e39c5baSBill Taylor 
1348*9e39c5baSBill Taylor 	/* Write the data to the register pointed to by addr */
1349*9e39c5baSBill Taylor 	ddi_put32(handle, addr, wrreg.arg_data);
1350*9e39c5baSBill Taylor 
1351*9e39c5baSBill Taylor 	/* the FMA retry loop ends. */
1352*9e39c5baSBill Taylor 	hermon_pio_end(state, handle, pio_error, fm_loop_cnt, fm_status,
1353*9e39c5baSBill Taylor 	    fm_test);
1354*9e39c5baSBill Taylor 	return (0);
1355*9e39c5baSBill Taylor 
1356*9e39c5baSBill Taylor pio_error:
1357*9e39c5baSBill Taylor 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
1358*9e39c5baSBill Taylor 	return (EIO);
1359*9e39c5baSBill Taylor }
1360*9e39c5baSBill Taylor #endif	/* DEBUG */
1361*9e39c5baSBill Taylor 
1362*9e39c5baSBill Taylor static int
1363*9e39c5baSBill Taylor hermon_ioctl_write_boot_addr(hermon_state_t *state, dev_t dev, intptr_t arg,
1364*9e39c5baSBill Taylor     int mode)
1365*9e39c5baSBill Taylor {
1366*9e39c5baSBill Taylor 	hermon_flash_ioctl_t	ioctl_info;
1367*9e39c5baSBill Taylor 
1368*9e39c5baSBill Taylor 	/* initialize the FMA retry loop */
1369*9e39c5baSBill Taylor 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
1370*9e39c5baSBill Taylor 
1371*9e39c5baSBill Taylor 	/*
1372*9e39c5baSBill Taylor 	 * Check that flash init ioctl has been called first.  And check
1373*9e39c5baSBill Taylor 	 * that the same dev_t that called init is the one calling write now.
1374*9e39c5baSBill Taylor 	 */
1375*9e39c5baSBill Taylor 	mutex_enter(&state->hs_fw_flashlock);
1376*9e39c5baSBill Taylor 	if ((state->hs_fw_flashdev != dev) ||
1377*9e39c5baSBill Taylor 	    (state->hs_fw_flashstarted == 0)) {
1378*9e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
1379*9e39c5baSBill Taylor 		return (EIO);
1380*9e39c5baSBill Taylor 	}
1381*9e39c5baSBill Taylor 
1382*9e39c5baSBill Taylor 	/* copy user struct to kernel */
1383*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
1384*9e39c5baSBill Taylor 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
1385*9e39c5baSBill Taylor 		hermon_flash_ioctl32_t info32;
1386*9e39c5baSBill Taylor 
1387*9e39c5baSBill Taylor 		if (ddi_copyin((void *)arg, &info32,
1388*9e39c5baSBill Taylor 		    sizeof (hermon_flash_ioctl32_t), mode) != 0) {
1389*9e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
1390*9e39c5baSBill Taylor 			return (EFAULT);
1391*9e39c5baSBill Taylor 		}
1392*9e39c5baSBill Taylor 		ioctl_info.af_type = info32.af_type;
1393*9e39c5baSBill Taylor 		ioctl_info.af_sector = (caddr_t)(uintptr_t)info32.af_sector;
1394*9e39c5baSBill Taylor 		ioctl_info.af_sector_num = info32.af_sector_num;
1395*9e39c5baSBill Taylor 		ioctl_info.af_addr = info32.af_addr;
1396*9e39c5baSBill Taylor 		ioctl_info.af_byte = info32.af_byte;
1397*9e39c5baSBill Taylor 	} else
1398*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
1399*9e39c5baSBill Taylor 	if (ddi_copyin((void *)arg, &ioctl_info,
1400*9e39c5baSBill Taylor 	    sizeof (hermon_flash_ioctl_t), mode) != 0) {
1401*9e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
1402*9e39c5baSBill Taylor 		return (EFAULT);
1403*9e39c5baSBill Taylor 	}
1404*9e39c5baSBill Taylor 
1405*9e39c5baSBill Taylor 	switch (state->hs_fw_cmdset) {
1406*9e39c5baSBill Taylor 	case HERMON_FLASH_AMD_CMDSET:
1407*9e39c5baSBill Taylor 	case HERMON_FLASH_INTEL_CMDSET:
1408*9e39c5baSBill Taylor 		break;
1409*9e39c5baSBill Taylor 
1410*9e39c5baSBill Taylor 	case HERMON_FLASH_SPI_CMDSET:
1411*9e39c5baSBill Taylor 	{
1412*9e39c5baSBill Taylor 		ddi_acc_handle_t pci_hdl = hermon_get_pcihdl(state);
1413*9e39c5baSBill Taylor 
1414*9e39c5baSBill Taylor 		/* the FMA retry loop starts. */
1415*9e39c5baSBill Taylor 		hermon_pio_start(state, pci_hdl, pio_error,
1416*9e39c5baSBill Taylor 		    fm_loop_cnt, fm_status, fm_test);
1417*9e39c5baSBill Taylor 
1418*9e39c5baSBill Taylor 		hermon_flash_write_cfg(state, pci_hdl,
1419*9e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_BOOT_ADDR_REG,
1420*9e39c5baSBill Taylor 		    (ioctl_info.af_addr << 8) | 0x06);
1421*9e39c5baSBill Taylor 
1422*9e39c5baSBill Taylor 		/* the FMA retry loop ends. */
1423*9e39c5baSBill Taylor 		hermon_pio_end(state, pci_hdl, pio_error,
1424*9e39c5baSBill Taylor 		    fm_loop_cnt, fm_status, fm_test);
1425*9e39c5baSBill Taylor 		break;
1426*9e39c5baSBill Taylor 	}
1427*9e39c5baSBill Taylor 
1428*9e39c5baSBill Taylor 	case HERMON_FLASH_UNKNOWN_CMDSET:
1429*9e39c5baSBill Taylor 	default:
1430*9e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
1431*9e39c5baSBill Taylor 		return (EINVAL);
1432*9e39c5baSBill Taylor 	}
1433*9e39c5baSBill Taylor 	mutex_exit(&state->hs_fw_flashlock);
1434*9e39c5baSBill Taylor 	return (0);
1435*9e39c5baSBill Taylor 
1436*9e39c5baSBill Taylor pio_error:
1437*9e39c5baSBill Taylor 	mutex_exit(&state->hs_fw_flashlock);
1438*9e39c5baSBill Taylor 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
1439*9e39c5baSBill Taylor 	return (EIO);
1440*9e39c5baSBill Taylor }
1441*9e39c5baSBill Taylor 
1442*9e39c5baSBill Taylor /*
1443*9e39c5baSBill Taylor  * hermon_flash_reset()
1444*9e39c5baSBill Taylor  */
1445*9e39c5baSBill Taylor static int
1446*9e39c5baSBill Taylor hermon_flash_reset(hermon_state_t *state)
1447*9e39c5baSBill Taylor {
1448*9e39c5baSBill Taylor 	int status;
1449*9e39c5baSBill Taylor 
1450*9e39c5baSBill Taylor 	/*
1451*9e39c5baSBill Taylor 	 * Performs a reset to the flash device.  After a reset the flash will
1452*9e39c5baSBill Taylor 	 * be operating in normal mode (capable of read/write, etc.).
1453*9e39c5baSBill Taylor 	 */
1454*9e39c5baSBill Taylor 	switch (state->hs_fw_cmdset) {
1455*9e39c5baSBill Taylor 	case HERMON_FLASH_AMD_CMDSET:
1456*9e39c5baSBill Taylor 		hermon_flash_write(state, 0x555, HERMON_HW_FLASH_RESET_AMD,
1457*9e39c5baSBill Taylor 		    &status);
1458*9e39c5baSBill Taylor 		if (status != 0) {
1459*9e39c5baSBill Taylor 			return (status);
1460*9e39c5baSBill Taylor 		}
1461*9e39c5baSBill Taylor 		break;
1462*9e39c5baSBill Taylor 
1463*9e39c5baSBill Taylor 	case HERMON_FLASH_INTEL_CMDSET:
1464*9e39c5baSBill Taylor 		hermon_flash_write(state, 0x555, HERMON_HW_FLASH_RESET_INTEL,
1465*9e39c5baSBill Taylor 		    &status);
1466*9e39c5baSBill Taylor 		if (status != 0) {
1467*9e39c5baSBill Taylor 			return (status);
1468*9e39c5baSBill Taylor 		}
1469*9e39c5baSBill Taylor 		break;
1470*9e39c5baSBill Taylor 
1471*9e39c5baSBill Taylor 	/* It appears no reset is needed for SPI */
1472*9e39c5baSBill Taylor 	case HERMON_FLASH_SPI_CMDSET:
1473*9e39c5baSBill Taylor 		status = 0;
1474*9e39c5baSBill Taylor 		break;
1475*9e39c5baSBill Taylor 
1476*9e39c5baSBill Taylor 	case HERMON_FLASH_UNKNOWN_CMDSET:
1477*9e39c5baSBill Taylor 	default:
1478*9e39c5baSBill Taylor 		status = EINVAL;
1479*9e39c5baSBill Taylor 		break;
1480*9e39c5baSBill Taylor 	}
1481*9e39c5baSBill Taylor 	return (status);
1482*9e39c5baSBill Taylor }
1483*9e39c5baSBill Taylor 
1484*9e39c5baSBill Taylor /*
1485*9e39c5baSBill Taylor  * hermon_flash_read_sector()
1486*9e39c5baSBill Taylor  */
1487*9e39c5baSBill Taylor static int
1488*9e39c5baSBill Taylor hermon_flash_read_sector(hermon_state_t *state, uint32_t sector_num)
1489*9e39c5baSBill Taylor {
1490*9e39c5baSBill Taylor 	uint32_t addr;
1491*9e39c5baSBill Taylor 	uint32_t end_addr;
1492*9e39c5baSBill Taylor 	uint32_t *image;
1493*9e39c5baSBill Taylor 	int i, status;
1494*9e39c5baSBill Taylor 
1495*9e39c5baSBill Taylor 	image = (uint32_t *)&state->hs_fw_sector[0];
1496*9e39c5baSBill Taylor 
1497*9e39c5baSBill Taylor 	/*
1498*9e39c5baSBill Taylor 	 * Calculate the start and end address of the sector, based on the
1499*9e39c5baSBill Taylor 	 * sector number passed in.
1500*9e39c5baSBill Taylor 	 */
1501*9e39c5baSBill Taylor 	addr = sector_num << state->hs_fw_log_sector_sz;
1502*9e39c5baSBill Taylor 	end_addr = addr + (1 << state->hs_fw_log_sector_sz);
1503*9e39c5baSBill Taylor 
1504*9e39c5baSBill Taylor 	/* Set the flash bank correctly for the given address */
1505*9e39c5baSBill Taylor 	if ((status = hermon_flash_bank(state, addr)) != 0)
1506*9e39c5baSBill Taylor 		return (status);
1507*9e39c5baSBill Taylor 
1508*9e39c5baSBill Taylor 	/* Read the entire sector, one quadlet at a time */
1509*9e39c5baSBill Taylor 	for (i = 0; addr < end_addr; i++, addr += 4) {
1510*9e39c5baSBill Taylor 		image[i] = hermon_flash_read(state, addr, &status);
1511*9e39c5baSBill Taylor 		if (status != 0) {
1512*9e39c5baSBill Taylor 			return (status);
1513*9e39c5baSBill Taylor 		}
1514*9e39c5baSBill Taylor 	}
1515*9e39c5baSBill Taylor 	return (0);
1516*9e39c5baSBill Taylor }
1517*9e39c5baSBill Taylor 
1518*9e39c5baSBill Taylor /*
1519*9e39c5baSBill Taylor  * hermon_flash_read_quadlet()
1520*9e39c5baSBill Taylor  */
1521*9e39c5baSBill Taylor static int
1522*9e39c5baSBill Taylor hermon_flash_read_quadlet(hermon_state_t *state, uint32_t *data,
1523*9e39c5baSBill Taylor     uint32_t addr)
1524*9e39c5baSBill Taylor {
1525*9e39c5baSBill Taylor 	int status;
1526*9e39c5baSBill Taylor 
1527*9e39c5baSBill Taylor 	/* Set the flash bank correctly for the given address */
1528*9e39c5baSBill Taylor 	if ((status = hermon_flash_bank(state, addr)) != 0) {
1529*9e39c5baSBill Taylor 		return (status);
1530*9e39c5baSBill Taylor 	}
1531*9e39c5baSBill Taylor 
1532*9e39c5baSBill Taylor 	/* Read one quadlet of data */
1533*9e39c5baSBill Taylor 	*data = hermon_flash_read(state, addr, &status);
1534*9e39c5baSBill Taylor 	if (status != 0) {
1535*9e39c5baSBill Taylor 		return (EIO);
1536*9e39c5baSBill Taylor 	}
1537*9e39c5baSBill Taylor 
1538*9e39c5baSBill Taylor 	return (0);
1539*9e39c5baSBill Taylor }
1540*9e39c5baSBill Taylor 
1541*9e39c5baSBill Taylor /*
1542*9e39c5baSBill Taylor  * hermon_flash_write_sector()
1543*9e39c5baSBill Taylor  */
1544*9e39c5baSBill Taylor static int
1545*9e39c5baSBill Taylor hermon_flash_write_sector(hermon_state_t *state, uint32_t sector_num)
1546*9e39c5baSBill Taylor {
1547*9e39c5baSBill Taylor 	uint32_t	addr;
1548*9e39c5baSBill Taylor 	uint32_t	end_addr;
1549*9e39c5baSBill Taylor 	uint32_t	*databuf;
1550*9e39c5baSBill Taylor 	uchar_t		*sector;
1551*9e39c5baSBill Taylor 	int		status = 0;
1552*9e39c5baSBill Taylor 	int		i;
1553*9e39c5baSBill Taylor 
1554*9e39c5baSBill Taylor 	sector = (uchar_t *)&state->hs_fw_sector[0];
1555*9e39c5baSBill Taylor 
1556*9e39c5baSBill Taylor 	/*
1557*9e39c5baSBill Taylor 	 * Calculate the start and end address of the sector, based on the
1558*9e39c5baSBill Taylor 	 * sector number passed in.
1559*9e39c5baSBill Taylor 	 */
1560*9e39c5baSBill Taylor 	addr = sector_num << state->hs_fw_log_sector_sz;
1561*9e39c5baSBill Taylor 	end_addr = addr + (1 << state->hs_fw_log_sector_sz);
1562*9e39c5baSBill Taylor 
1563*9e39c5baSBill Taylor 	/* Set the flash bank correctly for the given address */
1564*9e39c5baSBill Taylor 	if ((status = hermon_flash_bank(state, addr)) != 0 ||
1565*9e39c5baSBill Taylor 	    (status = hermon_flash_reset(state)) != 0) {
1566*9e39c5baSBill Taylor 		return (status);
1567*9e39c5baSBill Taylor 	}
1568*9e39c5baSBill Taylor 
1569*9e39c5baSBill Taylor 	/* Erase the sector before writing */
1570*9e39c5baSBill Taylor 	status = hermon_flash_erase_sector(state, sector_num);
1571*9e39c5baSBill Taylor 	if (status != 0) {
1572*9e39c5baSBill Taylor 		return (status);
1573*9e39c5baSBill Taylor 	}
1574*9e39c5baSBill Taylor 
1575*9e39c5baSBill Taylor 	switch (state->hs_fw_cmdset) {
1576*9e39c5baSBill Taylor 	case HERMON_FLASH_SPI_CMDSET:
1577*9e39c5baSBill Taylor 		databuf = (uint32_t *)(void *)sector;
1578*9e39c5baSBill Taylor 		/* Write the sector, one dword at a time */
1579*9e39c5baSBill Taylor 		for (i = 0; addr < end_addr; i++, addr += 4) {
1580*9e39c5baSBill Taylor 			if ((status = hermon_flash_spi_write_dword(state, addr,
1581*9e39c5baSBill Taylor 			    htonl(databuf[i]))) != 0) {
1582*9e39c5baSBill Taylor 				return (status);
1583*9e39c5baSBill Taylor 			}
1584*9e39c5baSBill Taylor 		}
1585*9e39c5baSBill Taylor 		status = hermon_flash_reset(state);
1586*9e39c5baSBill Taylor 		break;
1587*9e39c5baSBill Taylor 
1588*9e39c5baSBill Taylor 	case HERMON_FLASH_INTEL_CMDSET:
1589*9e39c5baSBill Taylor 	case HERMON_FLASH_AMD_CMDSET:
1590*9e39c5baSBill Taylor 		/* Write the sector, one byte at a time */
1591*9e39c5baSBill Taylor 		for (i = 0; addr < end_addr; i++, addr++) {
1592*9e39c5baSBill Taylor 			status = hermon_flash_write_byte(state, addr,
1593*9e39c5baSBill Taylor 			    sector[i]);
1594*9e39c5baSBill Taylor 			if (status != 0) {
1595*9e39c5baSBill Taylor 				break;
1596*9e39c5baSBill Taylor 			}
1597*9e39c5baSBill Taylor 		}
1598*9e39c5baSBill Taylor 		status = hermon_flash_reset(state);
1599*9e39c5baSBill Taylor 		break;
1600*9e39c5baSBill Taylor 
1601*9e39c5baSBill Taylor 	case HERMON_FLASH_UNKNOWN_CMDSET:
1602*9e39c5baSBill Taylor 	default:
1603*9e39c5baSBill Taylor 		status = EINVAL;
1604*9e39c5baSBill Taylor 		break;
1605*9e39c5baSBill Taylor 	}
1606*9e39c5baSBill Taylor 
1607*9e39c5baSBill Taylor 	return (status);
1608*9e39c5baSBill Taylor }
1609*9e39c5baSBill Taylor 
1610*9e39c5baSBill Taylor /*
1611*9e39c5baSBill Taylor  * hermon_flash_spi_write_dword()
1612*9e39c5baSBill Taylor  *
1613*9e39c5baSBill Taylor  * NOTE: This function assumes that "data" is in network byte order.
1614*9e39c5baSBill Taylor  *
1615*9e39c5baSBill Taylor  */
1616*9e39c5baSBill Taylor static int
1617*9e39c5baSBill Taylor hermon_flash_spi_write_dword(hermon_state_t *state, uint32_t addr,
1618*9e39c5baSBill Taylor     uint32_t data)
1619*9e39c5baSBill Taylor {
1620*9e39c5baSBill Taylor 	int status;
1621*9e39c5baSBill Taylor 	ddi_acc_handle_t	hdl;
1622*9e39c5baSBill Taylor 
1623*9e39c5baSBill Taylor 	/* initialize the FMA retry loop */
1624*9e39c5baSBill Taylor 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
1625*9e39c5baSBill Taylor 
1626*9e39c5baSBill Taylor 	hdl = hermon_get_pcihdl(state);
1627*9e39c5baSBill Taylor 
1628*9e39c5baSBill Taylor 	/* the FMA retry loop starts. */
1629*9e39c5baSBill Taylor 	hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
1630*9e39c5baSBill Taylor 	    fm_test);
1631*9e39c5baSBill Taylor 
1632*9e39c5baSBill Taylor 	/* Issue Write Enable */
1633*9e39c5baSBill Taylor 	hermon_flash_spi_write_enable(state);
1634*9e39c5baSBill Taylor 
1635*9e39c5baSBill Taylor 	/* Set the Address */
1636*9e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_SPI_ADDR,
1637*9e39c5baSBill Taylor 	    addr & HERMON_HW_FLASH_SPI_ADDR_MASK);
1638*9e39c5baSBill Taylor 
1639*9e39c5baSBill Taylor 	/* Set the Data */
1640*9e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_SPI_DATA, data);
1641*9e39c5baSBill Taylor 
1642*9e39c5baSBill Taylor 	/* Set the Page Program and execute */
1643*9e39c5baSBill Taylor 	hermon_flash_spi_exec_command(state, hdl,
1644*9e39c5baSBill Taylor 	    HERMON_HW_FLASH_SPI_INSTR_PHASE_OFF |
1645*9e39c5baSBill Taylor 	    HERMON_HW_FLASH_SPI_ADDR_PHASE_OFF |
1646*9e39c5baSBill Taylor 	    HERMON_HW_FLASH_SPI_DATA_PHASE_OFF |
1647*9e39c5baSBill Taylor 	    HERMON_HW_FLASH_SPI_TRANS_SZ_4B |
1648*9e39c5baSBill Taylor 	    (HERMON_HW_FLASH_SPI_PAGE_PROGRAM <<
1649*9e39c5baSBill Taylor 	    HERMON_HW_FLASH_SPI_INSTR_SHIFT));
1650*9e39c5baSBill Taylor 
1651*9e39c5baSBill Taylor 	/* Wait for write to complete */
1652*9e39c5baSBill Taylor 	if ((status = hermon_flash_spi_wait_wip(state)) != 0) {
1653*9e39c5baSBill Taylor 		return (status);
1654*9e39c5baSBill Taylor 	}
1655*9e39c5baSBill Taylor 
1656*9e39c5baSBill Taylor 	/* the FMA retry loop ends. */
1657*9e39c5baSBill Taylor 	hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test);
1658*9e39c5baSBill Taylor 	return (0);
1659*9e39c5baSBill Taylor 
1660*9e39c5baSBill Taylor pio_error:
1661*9e39c5baSBill Taylor 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
1662*9e39c5baSBill Taylor 	return (EIO);
1663*9e39c5baSBill Taylor }
1664*9e39c5baSBill Taylor 
1665*9e39c5baSBill Taylor /*
1666*9e39c5baSBill Taylor  * hermon_flash_write_byte()
1667*9e39c5baSBill Taylor  */
1668*9e39c5baSBill Taylor static int
1669*9e39c5baSBill Taylor hermon_flash_write_byte(hermon_state_t *state, uint32_t addr, uchar_t data)
1670*9e39c5baSBill Taylor {
1671*9e39c5baSBill Taylor 	uint32_t stat;
1672*9e39c5baSBill Taylor 	int status = 0;
1673*9e39c5baSBill Taylor 	int dword_addr;
1674*9e39c5baSBill Taylor 	int byte_offset;
1675*9e39c5baSBill Taylor 	int i;
1676*9e39c5baSBill Taylor 	union {
1677*9e39c5baSBill Taylor 		uint8_t		bytes[4];
1678*9e39c5baSBill Taylor 		uint32_t	dword;
1679*9e39c5baSBill Taylor 	} dword;
1680*9e39c5baSBill Taylor 
1681*9e39c5baSBill Taylor 	switch (state->hs_fw_cmdset) {
1682*9e39c5baSBill Taylor 	case HERMON_FLASH_AMD_CMDSET:
1683*9e39c5baSBill Taylor 		/* Issue Flash Byte program command */
1684*9e39c5baSBill Taylor 		hermon_flash_write(state, addr, 0xAA, &status);
1685*9e39c5baSBill Taylor 		if (status != 0) {
1686*9e39c5baSBill Taylor 			return (status);
1687*9e39c5baSBill Taylor 		}
1688*9e39c5baSBill Taylor 
1689*9e39c5baSBill Taylor 		hermon_flash_write(state, addr, 0x55, &status);
1690*9e39c5baSBill Taylor 		if (status != 0) {
1691*9e39c5baSBill Taylor 			return (status);
1692*9e39c5baSBill Taylor 		}
1693*9e39c5baSBill Taylor 
1694*9e39c5baSBill Taylor 		hermon_flash_write(state, addr, 0xA0, &status);
1695*9e39c5baSBill Taylor 		if (status != 0) {
1696*9e39c5baSBill Taylor 			return (status);
1697*9e39c5baSBill Taylor 		}
1698*9e39c5baSBill Taylor 
1699*9e39c5baSBill Taylor 		hermon_flash_write(state, addr, data, &status);
1700*9e39c5baSBill Taylor 		if (status != 0) {
1701*9e39c5baSBill Taylor 			return (status);
1702*9e39c5baSBill Taylor 		}
1703*9e39c5baSBill Taylor 
1704*9e39c5baSBill Taylor 		/* Wait for Write Byte to Complete */
1705*9e39c5baSBill Taylor 		i = 0;
1706*9e39c5baSBill Taylor 		do {
1707*9e39c5baSBill Taylor 			drv_usecwait(1);
1708*9e39c5baSBill Taylor 			stat = hermon_flash_read(state, addr & ~3, &status);
1709*9e39c5baSBill Taylor 			if (status != 0) {
1710*9e39c5baSBill Taylor 				return (status);
1711*9e39c5baSBill Taylor 			}
1712*9e39c5baSBill Taylor 
1713*9e39c5baSBill Taylor 			if (i == hermon_hw_flash_timeout_write) {
1714*9e39c5baSBill Taylor 				cmn_err(CE_WARN,
1715*9e39c5baSBill Taylor 				    "hermon_flash_write_byte: ACS write "
1716*9e39c5baSBill Taylor 				    "timeout: addr: 0x%x, data: 0x%x\n",
1717*9e39c5baSBill Taylor 				    addr, data);
1718*9e39c5baSBill Taylor 				hermon_fm_ereport(state, HCA_SYS_ERR,
1719*9e39c5baSBill Taylor 				    HCA_ERR_IOCTL);
1720*9e39c5baSBill Taylor 				return (EIO);
1721*9e39c5baSBill Taylor 			}
1722*9e39c5baSBill Taylor 			i++;
1723*9e39c5baSBill Taylor 		} while (data != ((stat >> ((3 - (addr & 3)) << 3)) & 0xFF));
1724*9e39c5baSBill Taylor 
1725*9e39c5baSBill Taylor 		break;
1726*9e39c5baSBill Taylor 
1727*9e39c5baSBill Taylor 	case HERMON_FLASH_INTEL_CMDSET:
1728*9e39c5baSBill Taylor 		/* Issue Flash Byte program command */
1729*9e39c5baSBill Taylor 		hermon_flash_write(state, addr, HERMON_HW_FLASH_ICS_WRITE,
1730*9e39c5baSBill Taylor 		    &status);
1731*9e39c5baSBill Taylor 		if (status != 0) {
1732*9e39c5baSBill Taylor 			return (status);
1733*9e39c5baSBill Taylor 		}
1734*9e39c5baSBill Taylor 		hermon_flash_write(state, addr, data, &status);
1735*9e39c5baSBill Taylor 		if (status != 0) {
1736*9e39c5baSBill Taylor 			return (status);
1737*9e39c5baSBill Taylor 		}
1738*9e39c5baSBill Taylor 
1739*9e39c5baSBill Taylor 		/* Wait for Write Byte to Complete */
1740*9e39c5baSBill Taylor 		i = 0;
1741*9e39c5baSBill Taylor 		do {
1742*9e39c5baSBill Taylor 			drv_usecwait(1);
1743*9e39c5baSBill Taylor 			stat = hermon_flash_read(state, addr & ~3, &status);
1744*9e39c5baSBill Taylor 			if (status != 0) {
1745*9e39c5baSBill Taylor 				return (status);
1746*9e39c5baSBill Taylor 			}
1747*9e39c5baSBill Taylor 
1748*9e39c5baSBill Taylor 			if (i == hermon_hw_flash_timeout_write) {
1749*9e39c5baSBill Taylor 				cmn_err(CE_WARN,
1750*9e39c5baSBill Taylor 				    "hermon_flash_write_byte: ICS write "
1751*9e39c5baSBill Taylor 				    "timeout: addr: %x, data: %x\n",
1752*9e39c5baSBill Taylor 				    addr, data);
1753*9e39c5baSBill Taylor 				hermon_fm_ereport(state, HCA_SYS_ERR,
1754*9e39c5baSBill Taylor 				    HCA_ERR_IOCTL);
1755*9e39c5baSBill Taylor 				return (EIO);
1756*9e39c5baSBill Taylor 			}
1757*9e39c5baSBill Taylor 			i++;
1758*9e39c5baSBill Taylor 		} while ((stat & HERMON_HW_FLASH_ICS_READY) == 0);
1759*9e39c5baSBill Taylor 
1760*9e39c5baSBill Taylor 		if (stat & HERMON_HW_FLASH_ICS_ERROR) {
1761*9e39c5baSBill Taylor 			cmn_err(CE_WARN,
1762*9e39c5baSBill Taylor 			    "hermon_flash_write_byte: ICS write cmd error: "
1763*9e39c5baSBill Taylor 			    "addr: %x, data: %x\n",
1764*9e39c5baSBill Taylor 			    addr, data);
1765*9e39c5baSBill Taylor 			hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
1766*9e39c5baSBill Taylor 			return (EIO);
1767*9e39c5baSBill Taylor 		}
1768*9e39c5baSBill Taylor 		break;
1769*9e39c5baSBill Taylor 
1770*9e39c5baSBill Taylor 	case HERMON_FLASH_SPI_CMDSET:
1771*9e39c5baSBill Taylor 		/*
1772*9e39c5baSBill Taylor 		 * Our lowest write granularity on SPI is a dword.
1773*9e39c5baSBill Taylor 		 * To support this ioctl option, we can read in the
1774*9e39c5baSBill Taylor 		 * dword that contains this byte, modify this byte,
1775*9e39c5baSBill Taylor 		 * and write the dword back out.
1776*9e39c5baSBill Taylor 		 */
1777*9e39c5baSBill Taylor 
1778*9e39c5baSBill Taylor 		/* Determine dword offset and byte offset within the dword */
1779*9e39c5baSBill Taylor 		byte_offset = addr & 3;
1780*9e39c5baSBill Taylor 		dword_addr = addr - byte_offset;
1781*9e39c5baSBill Taylor #ifdef _LITTLE_ENDIAN
1782*9e39c5baSBill Taylor 		byte_offset = 3 - byte_offset;
1783*9e39c5baSBill Taylor #endif
1784*9e39c5baSBill Taylor 
1785*9e39c5baSBill Taylor 		/* Read in dword */
1786*9e39c5baSBill Taylor 		if ((status = hermon_flash_read_quadlet(state, &dword.dword,
1787*9e39c5baSBill Taylor 		    dword_addr)) != 0)
1788*9e39c5baSBill Taylor 			break;
1789*9e39c5baSBill Taylor 
1790*9e39c5baSBill Taylor 		/* Set "data" to the appopriate byte */
1791*9e39c5baSBill Taylor 		dword.bytes[byte_offset] = data;
1792*9e39c5baSBill Taylor 
1793*9e39c5baSBill Taylor 		/* Write modified dword back out */
1794*9e39c5baSBill Taylor 		status = hermon_flash_spi_write_dword(state, dword_addr,
1795*9e39c5baSBill Taylor 		    dword.dword);
1796*9e39c5baSBill Taylor 
1797*9e39c5baSBill Taylor 		break;
1798*9e39c5baSBill Taylor 
1799*9e39c5baSBill Taylor 	case HERMON_FLASH_UNKNOWN_CMDSET:
1800*9e39c5baSBill Taylor 	default:
1801*9e39c5baSBill Taylor 		cmn_err(CE_WARN,
1802*9e39c5baSBill Taylor 		    "hermon_flash_write_byte: unknown cmd set: 0x%x\n",
1803*9e39c5baSBill Taylor 		    state->hs_fw_cmdset);
1804*9e39c5baSBill Taylor 		status = EINVAL;
1805*9e39c5baSBill Taylor 		break;
1806*9e39c5baSBill Taylor 	}
1807*9e39c5baSBill Taylor 
1808*9e39c5baSBill Taylor 	return (status);
1809*9e39c5baSBill Taylor }
1810*9e39c5baSBill Taylor 
1811*9e39c5baSBill Taylor /*
1812*9e39c5baSBill Taylor  * hermon_flash_erase_sector()
1813*9e39c5baSBill Taylor  */
1814*9e39c5baSBill Taylor static int
1815*9e39c5baSBill Taylor hermon_flash_erase_sector(hermon_state_t *state, uint32_t sector_num)
1816*9e39c5baSBill Taylor {
1817*9e39c5baSBill Taylor 	ddi_acc_handle_t	hdl;
1818*9e39c5baSBill Taylor 	uint32_t addr;
1819*9e39c5baSBill Taylor 	uint32_t stat;
1820*9e39c5baSBill Taylor 	int status = 0;
1821*9e39c5baSBill Taylor 	int i;
1822*9e39c5baSBill Taylor 
1823*9e39c5baSBill Taylor 	/* initialize the FMA retry loop */
1824*9e39c5baSBill Taylor 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
1825*9e39c5baSBill Taylor 
1826*9e39c5baSBill Taylor 	/* Get address from sector num */
1827*9e39c5baSBill Taylor 	addr = sector_num << state->hs_fw_log_sector_sz;
1828*9e39c5baSBill Taylor 
1829*9e39c5baSBill Taylor 	switch (state->hs_fw_cmdset) {
1830*9e39c5baSBill Taylor 	case HERMON_FLASH_AMD_CMDSET:
1831*9e39c5baSBill Taylor 		/* Issue Flash Sector Erase Command */
1832*9e39c5baSBill Taylor 		hermon_flash_write(state, addr, 0xAA, &status);
1833*9e39c5baSBill Taylor 		if (status != 0) {
1834*9e39c5baSBill Taylor 			return (status);
1835*9e39c5baSBill Taylor 		}
1836*9e39c5baSBill Taylor 
1837*9e39c5baSBill Taylor 		hermon_flash_write(state, addr, 0x55, &status);
1838*9e39c5baSBill Taylor 		if (status != 0) {
1839*9e39c5baSBill Taylor 			return (status);
1840*9e39c5baSBill Taylor 		}
1841*9e39c5baSBill Taylor 
1842*9e39c5baSBill Taylor 		hermon_flash_write(state, addr, 0x80, &status);
1843*9e39c5baSBill Taylor 		if (status != 0) {
1844*9e39c5baSBill Taylor 			return (status);
1845*9e39c5baSBill Taylor 		}
1846*9e39c5baSBill Taylor 
1847*9e39c5baSBill Taylor 		hermon_flash_write(state, addr, 0xAA, &status);
1848*9e39c5baSBill Taylor 		if (status != 0) {
1849*9e39c5baSBill Taylor 			return (status);
1850*9e39c5baSBill Taylor 		}
1851*9e39c5baSBill Taylor 
1852*9e39c5baSBill Taylor 		hermon_flash_write(state, addr, 0x55, &status);
1853*9e39c5baSBill Taylor 		if (status != 0) {
1854*9e39c5baSBill Taylor 			return (status);
1855*9e39c5baSBill Taylor 		}
1856*9e39c5baSBill Taylor 
1857*9e39c5baSBill Taylor 		hermon_flash_write(state, addr, 0x30, &status);
1858*9e39c5baSBill Taylor 		if (status != 0) {
1859*9e39c5baSBill Taylor 			return (status);
1860*9e39c5baSBill Taylor 		}
1861*9e39c5baSBill Taylor 
1862*9e39c5baSBill Taylor 		/* Wait for Sector Erase to complete */
1863*9e39c5baSBill Taylor 		i = 0;
1864*9e39c5baSBill Taylor 		do {
1865*9e39c5baSBill Taylor 			drv_usecwait(1);
1866*9e39c5baSBill Taylor 			stat = hermon_flash_read(state, addr, &status);
1867*9e39c5baSBill Taylor 			if (status != 0) {
1868*9e39c5baSBill Taylor 				return (status);
1869*9e39c5baSBill Taylor 			}
1870*9e39c5baSBill Taylor 
1871*9e39c5baSBill Taylor 			if (i == hermon_hw_flash_timeout_erase) {
1872*9e39c5baSBill Taylor 				cmn_err(CE_WARN,
1873*9e39c5baSBill Taylor 				    "hermon_flash_erase_sector: "
1874*9e39c5baSBill Taylor 				    "ACS erase timeout\n");
1875*9e39c5baSBill Taylor 				hermon_fm_ereport(state, HCA_SYS_ERR,
1876*9e39c5baSBill Taylor 				    HCA_ERR_IOCTL);
1877*9e39c5baSBill Taylor 				return (EIO);
1878*9e39c5baSBill Taylor 			}
1879*9e39c5baSBill Taylor 			i++;
1880*9e39c5baSBill Taylor 		} while (stat != 0xFFFFFFFF);
1881*9e39c5baSBill Taylor 		break;
1882*9e39c5baSBill Taylor 
1883*9e39c5baSBill Taylor 	case HERMON_FLASH_INTEL_CMDSET:
1884*9e39c5baSBill Taylor 		/* Issue Flash Sector Erase Command */
1885*9e39c5baSBill Taylor 		hermon_flash_write(state, addr, HERMON_HW_FLASH_ICS_ERASE,
1886*9e39c5baSBill Taylor 		    &status);
1887*9e39c5baSBill Taylor 		if (status != 0) {
1888*9e39c5baSBill Taylor 			return (status);
1889*9e39c5baSBill Taylor 		}
1890*9e39c5baSBill Taylor 
1891*9e39c5baSBill Taylor 		hermon_flash_write(state, addr, HERMON_HW_FLASH_ICS_CONFIRM,
1892*9e39c5baSBill Taylor 		    &status);
1893*9e39c5baSBill Taylor 		if (status != 0) {
1894*9e39c5baSBill Taylor 			return (status);
1895*9e39c5baSBill Taylor 		}
1896*9e39c5baSBill Taylor 
1897*9e39c5baSBill Taylor 		/* Wait for Sector Erase to complete */
1898*9e39c5baSBill Taylor 		i = 0;
1899*9e39c5baSBill Taylor 		do {
1900*9e39c5baSBill Taylor 			drv_usecwait(1);
1901*9e39c5baSBill Taylor 			stat = hermon_flash_read(state, addr & ~3, &status);
1902*9e39c5baSBill Taylor 			if (status != 0) {
1903*9e39c5baSBill Taylor 				return (status);
1904*9e39c5baSBill Taylor 			}
1905*9e39c5baSBill Taylor 
1906*9e39c5baSBill Taylor 			if (i == hermon_hw_flash_timeout_erase) {
1907*9e39c5baSBill Taylor 				cmn_err(CE_WARN,
1908*9e39c5baSBill Taylor 				    "hermon_flash_erase_sector: "
1909*9e39c5baSBill Taylor 				    "ICS erase timeout\n");
1910*9e39c5baSBill Taylor 				hermon_fm_ereport(state, HCA_SYS_ERR,
1911*9e39c5baSBill Taylor 				    HCA_ERR_IOCTL);
1912*9e39c5baSBill Taylor 				return (EIO);
1913*9e39c5baSBill Taylor 			}
1914*9e39c5baSBill Taylor 			i++;
1915*9e39c5baSBill Taylor 		} while ((stat & HERMON_HW_FLASH_ICS_READY) == 0);
1916*9e39c5baSBill Taylor 
1917*9e39c5baSBill Taylor 		if (stat & HERMON_HW_FLASH_ICS_ERROR) {
1918*9e39c5baSBill Taylor 			cmn_err(CE_WARN,
1919*9e39c5baSBill Taylor 			    "hermon_flash_erase_sector: "
1920*9e39c5baSBill Taylor 			    "ICS erase cmd error\n");
1921*9e39c5baSBill Taylor 			hermon_fm_ereport(state, HCA_SYS_ERR,
1922*9e39c5baSBill Taylor 			    HCA_ERR_IOCTL);
1923*9e39c5baSBill Taylor 			return (EIO);
1924*9e39c5baSBill Taylor 		}
1925*9e39c5baSBill Taylor 		break;
1926*9e39c5baSBill Taylor 
1927*9e39c5baSBill Taylor 	case HERMON_FLASH_SPI_CMDSET:
1928*9e39c5baSBill Taylor 		hdl = hermon_get_pcihdl(state);
1929*9e39c5baSBill Taylor 
1930*9e39c5baSBill Taylor 		/* the FMA retry loop starts. */
1931*9e39c5baSBill Taylor 		hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
1932*9e39c5baSBill Taylor 		    fm_test);
1933*9e39c5baSBill Taylor 
1934*9e39c5baSBill Taylor 		/* Issue Write Enable */
1935*9e39c5baSBill Taylor 		hermon_flash_spi_write_enable(state);
1936*9e39c5baSBill Taylor 
1937*9e39c5baSBill Taylor 		/* Set the Address */
1938*9e39c5baSBill Taylor 		hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_SPI_ADDR,
1939*9e39c5baSBill Taylor 		    addr & HERMON_HW_FLASH_SPI_ADDR_MASK);
1940*9e39c5baSBill Taylor 
1941*9e39c5baSBill Taylor 		/* Issue Flash Sector Erase */
1942*9e39c5baSBill Taylor 		hermon_flash_spi_exec_command(state, hdl,
1943*9e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_INSTR_PHASE_OFF |
1944*9e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_ADDR_PHASE_OFF |
1945*9e39c5baSBill Taylor 		    ((uint32_t)(HERMON_HW_FLASH_SPI_SECTOR_ERASE) <<
1946*9e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_INSTR_SHIFT));
1947*9e39c5baSBill Taylor 
1948*9e39c5baSBill Taylor 		/* the FMA retry loop ends. */
1949*9e39c5baSBill Taylor 		hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status,
1950*9e39c5baSBill Taylor 		    fm_test);
1951*9e39c5baSBill Taylor 
1952*9e39c5baSBill Taylor 		/* Wait for Sector Erase to complete */
1953*9e39c5baSBill Taylor 		status = hermon_flash_spi_wait_wip(state);
1954*9e39c5baSBill Taylor 		break;
1955*9e39c5baSBill Taylor 
1956*9e39c5baSBill Taylor 	case HERMON_FLASH_UNKNOWN_CMDSET:
1957*9e39c5baSBill Taylor 	default:
1958*9e39c5baSBill Taylor 		cmn_err(CE_WARN,
1959*9e39c5baSBill Taylor 		    "hermon_flash_erase_sector: unknown cmd set: 0x%x\n",
1960*9e39c5baSBill Taylor 		    state->hs_fw_cmdset);
1961*9e39c5baSBill Taylor 		status = EINVAL;
1962*9e39c5baSBill Taylor 		break;
1963*9e39c5baSBill Taylor 	}
1964*9e39c5baSBill Taylor 
1965*9e39c5baSBill Taylor 	/* Reset the flash device */
1966*9e39c5baSBill Taylor 	if (status == 0) {
1967*9e39c5baSBill Taylor 		status = hermon_flash_reset(state);
1968*9e39c5baSBill Taylor 	}
1969*9e39c5baSBill Taylor 	return (status);
1970*9e39c5baSBill Taylor 
1971*9e39c5baSBill Taylor pio_error:
1972*9e39c5baSBill Taylor 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
1973*9e39c5baSBill Taylor 	return (EIO);
1974*9e39c5baSBill Taylor }
1975*9e39c5baSBill Taylor 
1976*9e39c5baSBill Taylor /*
1977*9e39c5baSBill Taylor  * hermon_flash_erase_chip()
1978*9e39c5baSBill Taylor  */
1979*9e39c5baSBill Taylor static int
1980*9e39c5baSBill Taylor hermon_flash_erase_chip(hermon_state_t *state)
1981*9e39c5baSBill Taylor {
1982*9e39c5baSBill Taylor 	uint32_t stat;
1983*9e39c5baSBill Taylor 	uint_t size;
1984*9e39c5baSBill Taylor 	int status = 0;
1985*9e39c5baSBill Taylor 	int i;
1986*9e39c5baSBill Taylor 	int num_sect;
1987*9e39c5baSBill Taylor 
1988*9e39c5baSBill Taylor 	switch (state->hs_fw_cmdset) {
1989*9e39c5baSBill Taylor 	case HERMON_FLASH_AMD_CMDSET:
1990*9e39c5baSBill Taylor 		/* Issue Flash Chip Erase Command */
1991*9e39c5baSBill Taylor 		hermon_flash_write(state, 0, 0xAA, &status);
1992*9e39c5baSBill Taylor 		if (status != 0) {
1993*9e39c5baSBill Taylor 			return (status);
1994*9e39c5baSBill Taylor 		}
1995*9e39c5baSBill Taylor 
1996*9e39c5baSBill Taylor 		hermon_flash_write(state, 0, 0x55, &status);
1997*9e39c5baSBill Taylor 		if (status != 0) {
1998*9e39c5baSBill Taylor 			return (status);
1999*9e39c5baSBill Taylor 		}
2000*9e39c5baSBill Taylor 
2001*9e39c5baSBill Taylor 		hermon_flash_write(state, 0, 0x80, &status);
2002*9e39c5baSBill Taylor 		if (status != 0) {
2003*9e39c5baSBill Taylor 			return (status);
2004*9e39c5baSBill Taylor 		}
2005*9e39c5baSBill Taylor 
2006*9e39c5baSBill Taylor 		hermon_flash_write(state, 0, 0xAA, &status);
2007*9e39c5baSBill Taylor 		if (status != 0) {
2008*9e39c5baSBill Taylor 			return (status);
2009*9e39c5baSBill Taylor 		}
2010*9e39c5baSBill Taylor 
2011*9e39c5baSBill Taylor 		hermon_flash_write(state, 0, 0x55, &status);
2012*9e39c5baSBill Taylor 		if (status != 0) {
2013*9e39c5baSBill Taylor 			return (status);
2014*9e39c5baSBill Taylor 		}
2015*9e39c5baSBill Taylor 
2016*9e39c5baSBill Taylor 		hermon_flash_write(state, 0, 0x10, &status);
2017*9e39c5baSBill Taylor 		if (status != 0) {
2018*9e39c5baSBill Taylor 			return (status);
2019*9e39c5baSBill Taylor 		}
2020*9e39c5baSBill Taylor 
2021*9e39c5baSBill Taylor 		/* Wait for Chip Erase to Complete */
2022*9e39c5baSBill Taylor 		i = 0;
2023*9e39c5baSBill Taylor 		do {
2024*9e39c5baSBill Taylor 			drv_usecwait(1);
2025*9e39c5baSBill Taylor 			stat = hermon_flash_read(state, 0, &status);
2026*9e39c5baSBill Taylor 			if (status != 0) {
2027*9e39c5baSBill Taylor 				return (status);
2028*9e39c5baSBill Taylor 			}
2029*9e39c5baSBill Taylor 
2030*9e39c5baSBill Taylor 			if (i == hermon_hw_flash_timeout_erase) {
2031*9e39c5baSBill Taylor 				cmn_err(CE_WARN,
2032*9e39c5baSBill Taylor 				    "hermon_flash_erase_chip: erase timeout\n");
2033*9e39c5baSBill Taylor 				hermon_fm_ereport(state, HCA_SYS_ERR,
2034*9e39c5baSBill Taylor 				    HCA_ERR_IOCTL);
2035*9e39c5baSBill Taylor 				return (EIO);
2036*9e39c5baSBill Taylor 			}
2037*9e39c5baSBill Taylor 			i++;
2038*9e39c5baSBill Taylor 		} while (stat != 0xFFFFFFFF);
2039*9e39c5baSBill Taylor 		break;
2040*9e39c5baSBill Taylor 
2041*9e39c5baSBill Taylor 	case HERMON_FLASH_INTEL_CMDSET:
2042*9e39c5baSBill Taylor 	case HERMON_FLASH_SPI_CMDSET:
2043*9e39c5baSBill Taylor 		/*
2044*9e39c5baSBill Taylor 		 * These chips don't have a chip erase command, so erase
2045*9e39c5baSBill Taylor 		 * all blocks one at a time.
2046*9e39c5baSBill Taylor 		 */
2047*9e39c5baSBill Taylor 		size = (0x1 << state->hs_fw_log_sector_sz);
2048*9e39c5baSBill Taylor 		num_sect = state->hs_fw_device_sz / size;
2049*9e39c5baSBill Taylor 
2050*9e39c5baSBill Taylor 		for (i = 0; i < num_sect; i++) {
2051*9e39c5baSBill Taylor 			status = hermon_flash_erase_sector(state, i);
2052*9e39c5baSBill Taylor 			if (status != 0) {
2053*9e39c5baSBill Taylor 				cmn_err(CE_WARN,
2054*9e39c5baSBill Taylor 				    "hermon_flash_erase_chip: "
2055*9e39c5baSBill Taylor 				    "sector %d erase error\n", i);
2056*9e39c5baSBill Taylor 				return (status);
2057*9e39c5baSBill Taylor 			}
2058*9e39c5baSBill Taylor 		}
2059*9e39c5baSBill Taylor 		break;
2060*9e39c5baSBill Taylor 
2061*9e39c5baSBill Taylor 	case HERMON_FLASH_UNKNOWN_CMDSET:
2062*9e39c5baSBill Taylor 	default:
2063*9e39c5baSBill Taylor 		cmn_err(CE_WARN, "hermon_flash_erase_chip: "
2064*9e39c5baSBill Taylor 		    "unknown cmd set: 0x%x\n", state->hs_fw_cmdset);
2065*9e39c5baSBill Taylor 		status = EINVAL;
2066*9e39c5baSBill Taylor 		break;
2067*9e39c5baSBill Taylor 	}
2068*9e39c5baSBill Taylor 
2069*9e39c5baSBill Taylor 	return (status);
2070*9e39c5baSBill Taylor }
2071*9e39c5baSBill Taylor 
2072*9e39c5baSBill Taylor /*
2073*9e39c5baSBill Taylor  * hermon_flash_spi_write_enable()
2074*9e39c5baSBill Taylor  */
2075*9e39c5baSBill Taylor static void
2076*9e39c5baSBill Taylor hermon_flash_spi_write_enable(hermon_state_t *state)
2077*9e39c5baSBill Taylor {
2078*9e39c5baSBill Taylor 	ddi_acc_handle_t	hdl;
2079*9e39c5baSBill Taylor 
2080*9e39c5baSBill Taylor 	hdl = hermon_get_pcihdl(state);
2081*9e39c5baSBill Taylor 
2082*9e39c5baSBill Taylor 	hermon_flash_spi_exec_command(state, hdl,
2083*9e39c5baSBill Taylor 	    HERMON_HW_FLASH_SPI_INSTR_PHASE_OFF |
2084*9e39c5baSBill Taylor 	    (HERMON_HW_FLASH_SPI_WRITE_ENABLE <<
2085*9e39c5baSBill Taylor 	    HERMON_HW_FLASH_SPI_INSTR_SHIFT));
2086*9e39c5baSBill Taylor }
2087*9e39c5baSBill Taylor 
2088*9e39c5baSBill Taylor /*
2089*9e39c5baSBill Taylor  * hermon_flash_spi_wait_wip()
2090*9e39c5baSBill Taylor  */
2091*9e39c5baSBill Taylor static int
2092*9e39c5baSBill Taylor hermon_flash_spi_wait_wip(hermon_state_t *state)
2093*9e39c5baSBill Taylor {
2094*9e39c5baSBill Taylor 	ddi_acc_handle_t	hdl;
2095*9e39c5baSBill Taylor 	uint32_t		status;
2096*9e39c5baSBill Taylor 
2097*9e39c5baSBill Taylor 	/* initialize the FMA retry loop */
2098*9e39c5baSBill Taylor 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
2099*9e39c5baSBill Taylor 
2100*9e39c5baSBill Taylor 	hdl = hermon_get_pcihdl(state);
2101*9e39c5baSBill Taylor 
2102*9e39c5baSBill Taylor 	/* the FMA retry loop starts. */
2103*9e39c5baSBill Taylor 	hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
2104*9e39c5baSBill Taylor 	    fm_test);
2105*9e39c5baSBill Taylor 
2106*9e39c5baSBill Taylor 	/* wait on the gateway to clear busy */
2107*9e39c5baSBill Taylor 	do {
2108*9e39c5baSBill Taylor 		status = hermon_flash_read_cfg(state, hdl,
2109*9e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_GW);
2110*9e39c5baSBill Taylor 	} while (status & HERMON_HW_FLASH_SPI_BUSY);
2111*9e39c5baSBill Taylor 
2112*9e39c5baSBill Taylor 	/* now, get the status and check for WIP to clear */
2113*9e39c5baSBill Taylor 	do {
2114*9e39c5baSBill Taylor 		hermon_flash_spi_exec_command(state, hdl,
2115*9e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_READ_OP |
2116*9e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_INSTR_PHASE_OFF |
2117*9e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_DATA_PHASE_OFF |
2118*9e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_TRANS_SZ_4B |
2119*9e39c5baSBill Taylor 		    (HERMON_HW_FLASH_SPI_READ_STATUS_REG <<
2120*9e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_INSTR_SHIFT));
2121*9e39c5baSBill Taylor 
2122*9e39c5baSBill Taylor 		status = hermon_flash_read_cfg(state, hdl,
2123*9e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_DATA);
2124*9e39c5baSBill Taylor 	} while (status & HERMON_HW_FLASH_SPI_WIP);
2125*9e39c5baSBill Taylor 
2126*9e39c5baSBill Taylor 	/* the FMA retry loop ends. */
2127*9e39c5baSBill Taylor 	hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test);
2128*9e39c5baSBill Taylor 	return (0);
2129*9e39c5baSBill Taylor 
2130*9e39c5baSBill Taylor pio_error:
2131*9e39c5baSBill Taylor 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
2132*9e39c5baSBill Taylor 	return (EIO);
2133*9e39c5baSBill Taylor }
2134*9e39c5baSBill Taylor 
2135*9e39c5baSBill Taylor /*
2136*9e39c5baSBill Taylor  * hermon_flash_bank()
2137*9e39c5baSBill Taylor  */
2138*9e39c5baSBill Taylor static int
2139*9e39c5baSBill Taylor hermon_flash_bank(hermon_state_t *state, uint32_t addr)
2140*9e39c5baSBill Taylor {
2141*9e39c5baSBill Taylor 	ddi_acc_handle_t	hdl;
2142*9e39c5baSBill Taylor 	uint32_t		bank;
2143*9e39c5baSBill Taylor 
2144*9e39c5baSBill Taylor 	/* initialize the FMA retry loop */
2145*9e39c5baSBill Taylor 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
2146*9e39c5baSBill Taylor 
2147*9e39c5baSBill Taylor 	/* Set handle */
2148*9e39c5baSBill Taylor 	hdl = hermon_get_pcihdl(state);
2149*9e39c5baSBill Taylor 
2150*9e39c5baSBill Taylor 	/* Determine the bank setting from the address */
2151*9e39c5baSBill Taylor 	bank = addr & HERMON_HW_FLASH_BANK_MASK;
2152*9e39c5baSBill Taylor 
2153*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(state->hs_fw_flashbank))
2154*9e39c5baSBill Taylor 
2155*9e39c5baSBill Taylor 	/*
2156*9e39c5baSBill Taylor 	 * If the bank is different from the currently set bank, we need to
2157*9e39c5baSBill Taylor 	 * change it.  Also, if an 'addr' of 0 is given, this allows the
2158*9e39c5baSBill Taylor 	 * capability to force the flash bank to 0.  This is useful at init
2159*9e39c5baSBill Taylor 	 * time to initially set the bank value
2160*9e39c5baSBill Taylor 	 */
2161*9e39c5baSBill Taylor 	if (state->hs_fw_flashbank != bank || addr == 0) {
2162*9e39c5baSBill Taylor 		switch (state->hs_fw_cmdset) {
2163*9e39c5baSBill Taylor 		case HERMON_FLASH_SPI_CMDSET:
2164*9e39c5baSBill Taylor 			/* CMJ: not needed for hermon */
2165*9e39c5baSBill Taylor 			break;
2166*9e39c5baSBill Taylor 
2167*9e39c5baSBill Taylor 		case HERMON_FLASH_INTEL_CMDSET:
2168*9e39c5baSBill Taylor 		case HERMON_FLASH_AMD_CMDSET:
2169*9e39c5baSBill Taylor 			/* the FMA retry loop starts. */
2170*9e39c5baSBill Taylor 			hermon_pio_start(state, hdl, pio_error, fm_loop_cnt,
2171*9e39c5baSBill Taylor 			    fm_status, fm_test);
2172*9e39c5baSBill Taylor 
2173*9e39c5baSBill Taylor 			hermon_flash_write_cfg(state, hdl,
2174*9e39c5baSBill Taylor 			    HERMON_HW_FLASH_GPIO_DATACLEAR, 0x70);
2175*9e39c5baSBill Taylor 			hermon_flash_write_cfg(state, hdl,
2176*9e39c5baSBill Taylor 			    HERMON_HW_FLASH_GPIO_DATASET, (bank >> 15) & 0x70);
2177*9e39c5baSBill Taylor 
2178*9e39c5baSBill Taylor 			/* the FMA retry loop ends. */
2179*9e39c5baSBill Taylor 			hermon_pio_end(state, hdl, pio_error, fm_loop_cnt,
2180*9e39c5baSBill Taylor 			    fm_status, fm_test);
2181*9e39c5baSBill Taylor 			break;
2182*9e39c5baSBill Taylor 
2183*9e39c5baSBill Taylor 		case HERMON_FLASH_UNKNOWN_CMDSET:
2184*9e39c5baSBill Taylor 		default:
2185*9e39c5baSBill Taylor 			return (EINVAL);
2186*9e39c5baSBill Taylor 		}
2187*9e39c5baSBill Taylor 
2188*9e39c5baSBill Taylor 		state->hs_fw_flashbank = bank;
2189*9e39c5baSBill Taylor 	}
2190*9e39c5baSBill Taylor 	return (0);
2191*9e39c5baSBill Taylor 
2192*9e39c5baSBill Taylor pio_error:
2193*9e39c5baSBill Taylor 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
2194*9e39c5baSBill Taylor 	return (EIO);
2195*9e39c5baSBill Taylor }
2196*9e39c5baSBill Taylor 
2197*9e39c5baSBill Taylor /*
2198*9e39c5baSBill Taylor  * hermon_flash_spi_exec_command()
2199*9e39c5baSBill Taylor  */
2200*9e39c5baSBill Taylor static void
2201*9e39c5baSBill Taylor hermon_flash_spi_exec_command(hermon_state_t *state, ddi_acc_handle_t hdl,
2202*9e39c5baSBill Taylor     uint32_t cmd)
2203*9e39c5baSBill Taylor {
2204*9e39c5baSBill Taylor 	uint32_t data;
2205*9e39c5baSBill Taylor 	int timeout = 0;
2206*9e39c5baSBill Taylor 
2207*9e39c5baSBill Taylor 	cmd |= HERMON_HW_FLASH_SPI_BUSY | HERMON_HW_FLASH_SPI_ENABLE_OFF;
2208*9e39c5baSBill Taylor 
2209*9e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_SPI_GW, cmd);
2210*9e39c5baSBill Taylor 
2211*9e39c5baSBill Taylor 	do {
2212*9e39c5baSBill Taylor 		data = hermon_flash_read_cfg(state, hdl,
2213*9e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_GW);
2214*9e39c5baSBill Taylor 		timeout++;
2215*9e39c5baSBill Taylor 	} while ((data & HERMON_HW_FLASH_SPI_BUSY) &&
2216*9e39c5baSBill Taylor 	    (timeout < hermon_hw_flash_timeout_config));
2217*9e39c5baSBill Taylor }
2218*9e39c5baSBill Taylor 
2219*9e39c5baSBill Taylor /*
2220*9e39c5baSBill Taylor  * hermon_flash_read()
2221*9e39c5baSBill Taylor  */
2222*9e39c5baSBill Taylor static uint32_t
2223*9e39c5baSBill Taylor hermon_flash_read(hermon_state_t *state, uint32_t addr, int *err)
2224*9e39c5baSBill Taylor {
2225*9e39c5baSBill Taylor 	ddi_acc_handle_t	hdl;
2226*9e39c5baSBill Taylor 	uint32_t		data = 0;
2227*9e39c5baSBill Taylor 	int			timeout, status = 0;
2228*9e39c5baSBill Taylor 
2229*9e39c5baSBill Taylor 	/* initialize the FMA retry loop */
2230*9e39c5baSBill Taylor 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
2231*9e39c5baSBill Taylor 
2232*9e39c5baSBill Taylor 	hdl = hermon_get_pcihdl(state);
2233*9e39c5baSBill Taylor 
2234*9e39c5baSBill Taylor 	/* the FMA retry loop starts. */
2235*9e39c5baSBill Taylor 	hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
2236*9e39c5baSBill Taylor 	    fm_test);
2237*9e39c5baSBill Taylor 
2238*9e39c5baSBill Taylor 	switch (state->hs_fw_cmdset) {
2239*9e39c5baSBill Taylor 	case HERMON_FLASH_SPI_CMDSET:
2240*9e39c5baSBill Taylor 		/* Set the transaction address */
2241*9e39c5baSBill Taylor 		hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_SPI_ADDR,
2242*9e39c5baSBill Taylor 		    (addr & HERMON_HW_FLASH_SPI_ADDR_MASK));
2243*9e39c5baSBill Taylor 
2244*9e39c5baSBill Taylor 		hermon_flash_spi_exec_command(state, hdl,
2245*9e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_READ_OP |
2246*9e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_INSTR_PHASE_OFF |
2247*9e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_ADDR_PHASE_OFF |
2248*9e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_DATA_PHASE_OFF |
2249*9e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_TRANS_SZ_4B |
2250*9e39c5baSBill Taylor 		    (HERMON_HW_FLASH_SPI_READ <<
2251*9e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_INSTR_SHIFT));
2252*9e39c5baSBill Taylor 
2253*9e39c5baSBill Taylor 		data = hermon_flash_read_cfg(state, hdl,
2254*9e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_DATA);
2255*9e39c5baSBill Taylor 		break;
2256*9e39c5baSBill Taylor 
2257*9e39c5baSBill Taylor 	case HERMON_FLASH_INTEL_CMDSET:
2258*9e39c5baSBill Taylor 	case HERMON_FLASH_AMD_CMDSET:
2259*9e39c5baSBill Taylor 		/*
2260*9e39c5baSBill Taylor 		 * The Read operation does the following:
2261*9e39c5baSBill Taylor 		 *   1) Write the masked address to the HERMON_FLASH_ADDR
2262*9e39c5baSBill Taylor 		 *	register. Only the least significant 19 bits are valid.
2263*9e39c5baSBill Taylor 		 *   2) Read back the register until the command has completed.
2264*9e39c5baSBill Taylor 		 *   3) Read the data retrieved from the address at the
2265*9e39c5baSBill Taylor 		 *	HERMON_FLASH_DATA register.
2266*9e39c5baSBill Taylor 		 */
2267*9e39c5baSBill Taylor 		hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_ADDR,
2268*9e39c5baSBill Taylor 		    (addr & HERMON_HW_FLASH_ADDR_MASK) | (1 << 29));
2269*9e39c5baSBill Taylor 
2270*9e39c5baSBill Taylor 		timeout = 0;
2271*9e39c5baSBill Taylor 		do {
2272*9e39c5baSBill Taylor 			data = hermon_flash_read_cfg(state, hdl,
2273*9e39c5baSBill Taylor 			    HERMON_HW_FLASH_ADDR);
2274*9e39c5baSBill Taylor 			timeout++;
2275*9e39c5baSBill Taylor 		} while ((data & HERMON_HW_FLASH_CMD_MASK) &&
2276*9e39c5baSBill Taylor 		    (timeout < hermon_hw_flash_timeout_config));
2277*9e39c5baSBill Taylor 
2278*9e39c5baSBill Taylor 		data = hermon_flash_read_cfg(state, hdl, HERMON_HW_FLASH_DATA);
2279*9e39c5baSBill Taylor 		break;
2280*9e39c5baSBill Taylor 
2281*9e39c5baSBill Taylor 	case HERMON_FLASH_UNKNOWN_CMDSET:
2282*9e39c5baSBill Taylor 	default:
2283*9e39c5baSBill Taylor 		cmn_err(CE_CONT, "hermon_flash_read: unknown cmdset: 0x%x\n",
2284*9e39c5baSBill Taylor 		    state->hs_fw_cmdset);
2285*9e39c5baSBill Taylor 		status = EINVAL;
2286*9e39c5baSBill Taylor 		break;
2287*9e39c5baSBill Taylor 	}
2288*9e39c5baSBill Taylor 
2289*9e39c5baSBill Taylor 	if (timeout == hermon_hw_flash_timeout_config) {
2290*9e39c5baSBill Taylor 		cmn_err(CE_WARN, "hermon_flash_read: command timed out.\n");
2291*9e39c5baSBill Taylor 		*err = EIO;
2292*9e39c5baSBill Taylor 		hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
2293*9e39c5baSBill Taylor 		return (data);
2294*9e39c5baSBill Taylor 	}
2295*9e39c5baSBill Taylor 
2296*9e39c5baSBill Taylor 	/* the FMA retry loop ends. */
2297*9e39c5baSBill Taylor 	hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test);
2298*9e39c5baSBill Taylor 	*err = status;
2299*9e39c5baSBill Taylor 	return (data);
2300*9e39c5baSBill Taylor 
2301*9e39c5baSBill Taylor pio_error:
2302*9e39c5baSBill Taylor 	*err = EIO;
2303*9e39c5baSBill Taylor 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
2304*9e39c5baSBill Taylor 	return (data);
2305*9e39c5baSBill Taylor }
2306*9e39c5baSBill Taylor 
2307*9e39c5baSBill Taylor /*
2308*9e39c5baSBill Taylor  * hermon_flash_write()
2309*9e39c5baSBill Taylor  */
2310*9e39c5baSBill Taylor static void
2311*9e39c5baSBill Taylor hermon_flash_write(hermon_state_t *state, uint32_t addr, uchar_t data, int *err)
2312*9e39c5baSBill Taylor {
2313*9e39c5baSBill Taylor 	ddi_acc_handle_t	hdl;
2314*9e39c5baSBill Taylor 	int			cmd;
2315*9e39c5baSBill Taylor 	int			timeout;
2316*9e39c5baSBill Taylor 
2317*9e39c5baSBill Taylor 	/* initialize the FMA retry loop */
2318*9e39c5baSBill Taylor 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
2319*9e39c5baSBill Taylor 
2320*9e39c5baSBill Taylor 	hdl = hermon_get_pcihdl(state);
2321*9e39c5baSBill Taylor 
2322*9e39c5baSBill Taylor 	/* the FMA retry loop starts. */
2323*9e39c5baSBill Taylor 	hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
2324*9e39c5baSBill Taylor 	    fm_test);
2325*9e39c5baSBill Taylor 
2326*9e39c5baSBill Taylor 	/*
2327*9e39c5baSBill Taylor 	 * The Write operation does the following:
2328*9e39c5baSBill Taylor 	 *   1) Write the data to be written to the HERMON_FLASH_DATA offset.
2329*9e39c5baSBill Taylor 	 *   2) Write the address to write the data to to the HERMON_FLASH_ADDR
2330*9e39c5baSBill Taylor 	 *	offset.
2331*9e39c5baSBill Taylor 	 *   3) Wait until the write completes.
2332*9e39c5baSBill Taylor 	 */
2333*9e39c5baSBill Taylor 
2334*9e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_DATA, data << 24);
2335*9e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_ADDR,
2336*9e39c5baSBill Taylor 	    (addr & 0x7FFFF) | (2 << 29));
2337*9e39c5baSBill Taylor 
2338*9e39c5baSBill Taylor 	timeout = 0;
2339*9e39c5baSBill Taylor 	do {
2340*9e39c5baSBill Taylor 		cmd = hermon_flash_read_cfg(state, hdl, HERMON_HW_FLASH_ADDR);
2341*9e39c5baSBill Taylor 		timeout++;
2342*9e39c5baSBill Taylor 	} while ((cmd & HERMON_HW_FLASH_CMD_MASK) &&
2343*9e39c5baSBill Taylor 	    (timeout < hermon_hw_flash_timeout_config));
2344*9e39c5baSBill Taylor 
2345*9e39c5baSBill Taylor 	if (timeout == hermon_hw_flash_timeout_config) {
2346*9e39c5baSBill Taylor 		cmn_err(CE_WARN, "hermon_flash_write: config cmd timeout.\n");
2347*9e39c5baSBill Taylor 		*err = EIO;
2348*9e39c5baSBill Taylor 		hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
2349*9e39c5baSBill Taylor 		return;
2350*9e39c5baSBill Taylor 	}
2351*9e39c5baSBill Taylor 
2352*9e39c5baSBill Taylor 	/* the FMA retry loop ends. */
2353*9e39c5baSBill Taylor 	hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test);
2354*9e39c5baSBill Taylor 	*err = 0;
2355*9e39c5baSBill Taylor 	return;
2356*9e39c5baSBill Taylor 
2357*9e39c5baSBill Taylor pio_error:
2358*9e39c5baSBill Taylor 	*err = EIO;
2359*9e39c5baSBill Taylor 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
2360*9e39c5baSBill Taylor }
2361*9e39c5baSBill Taylor 
2362*9e39c5baSBill Taylor /*
2363*9e39c5baSBill Taylor  * hermon_flash_init()
2364*9e39c5baSBill Taylor  */
2365*9e39c5baSBill Taylor static int
2366*9e39c5baSBill Taylor hermon_flash_init(hermon_state_t *state)
2367*9e39c5baSBill Taylor {
2368*9e39c5baSBill Taylor 	uint32_t		word;
2369*9e39c5baSBill Taylor 	ddi_acc_handle_t	hdl;
2370*9e39c5baSBill Taylor 	int			sema_cnt;
2371*9e39c5baSBill Taylor 	int			gpio;
2372*9e39c5baSBill Taylor 
2373*9e39c5baSBill Taylor 	/* initialize the FMA retry loop */
2374*9e39c5baSBill Taylor 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
2375*9e39c5baSBill Taylor 
2376*9e39c5baSBill Taylor 	/* Set handle */
2377*9e39c5baSBill Taylor 	hdl = hermon_get_pcihdl(state);
2378*9e39c5baSBill Taylor 
2379*9e39c5baSBill Taylor 	/* the FMA retry loop starts. */
2380*9e39c5baSBill Taylor 	hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
2381*9e39c5baSBill Taylor 	    fm_test);
2382*9e39c5baSBill Taylor 
2383*9e39c5baSBill Taylor 	/* Init the flash */
2384*9e39c5baSBill Taylor 
2385*9e39c5baSBill Taylor #ifdef DO_WRCONF
2386*9e39c5baSBill Taylor 	/*
2387*9e39c5baSBill Taylor 	 * Grab the WRCONF semaphore.
2388*9e39c5baSBill Taylor 	 */
2389*9e39c5baSBill Taylor 	word = hermon_flash_read_cfg(state, hdl, HERMON_HW_FLASH_WRCONF_SEMA);
2390*9e39c5baSBill Taylor #endif
2391*9e39c5baSBill Taylor 
2392*9e39c5baSBill Taylor 	/*
2393*9e39c5baSBill Taylor 	 * Grab the GPIO semaphore.  This allows us exclusive access to the
2394*9e39c5baSBill Taylor 	 * GPIO settings on the Hermon for the duration of the flash burning
2395*9e39c5baSBill Taylor 	 * procedure.
2396*9e39c5baSBill Taylor 	 */
2397*9e39c5baSBill Taylor 	sema_cnt = 0;
2398*9e39c5baSBill Taylor 	do {
2399*9e39c5baSBill Taylor 		word = hermon_flash_read_cfg(state, hdl,
2400*9e39c5baSBill Taylor 		    HERMON_HW_FLASH_GPIO_SEMA);
2401*9e39c5baSBill Taylor 		if (word == 0) {
2402*9e39c5baSBill Taylor 			break;
2403*9e39c5baSBill Taylor 		}
2404*9e39c5baSBill Taylor 
2405*9e39c5baSBill Taylor 		sema_cnt++;
2406*9e39c5baSBill Taylor 		drv_usecwait(1);
2407*9e39c5baSBill Taylor 
2408*9e39c5baSBill Taylor 	} while (sema_cnt < hermon_hw_flash_timeout_gpio_sema);
2409*9e39c5baSBill Taylor 
2410*9e39c5baSBill Taylor 	/*
2411*9e39c5baSBill Taylor 	 * Determine if we timed out trying to grab the GPIO semaphore
2412*9e39c5baSBill Taylor 	 */
2413*9e39c5baSBill Taylor 	if (sema_cnt == hermon_hw_flash_timeout_gpio_sema) {
2414*9e39c5baSBill Taylor 		cmn_err(CE_WARN, "hermon_flash_init: GPIO SEMA timeout\n");
2415*9e39c5baSBill Taylor 		cmn_err(CE_WARN, "GPIO_SEMA value: 0x%x\n", word);
2416*9e39c5baSBill Taylor 		hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
2417*9e39c5baSBill Taylor 		return (EIO);
2418*9e39c5baSBill Taylor 	}
2419*9e39c5baSBill Taylor 
2420*9e39c5baSBill Taylor 	/* Save away original GPIO Values */
2421*9e39c5baSBill Taylor 	state->hs_fw_gpio[0] = hermon_flash_read_cfg(state, hdl,
2422*9e39c5baSBill Taylor 	    HERMON_HW_FLASH_GPIO_DATA);
2423*9e39c5baSBill Taylor 
2424*9e39c5baSBill Taylor 	/* Set new GPIO value */
2425*9e39c5baSBill Taylor 	gpio = state->hs_fw_gpio[0] | HERMON_HW_FLASH_GPIO_PIN_ENABLE;
2426*9e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_DATA, gpio);
2427*9e39c5baSBill Taylor 
2428*9e39c5baSBill Taylor 	/* Save away original GPIO Values */
2429*9e39c5baSBill Taylor 	state->hs_fw_gpio[1] = hermon_flash_read_cfg(state, hdl,
2430*9e39c5baSBill Taylor 	    HERMON_HW_FLASH_GPIO_MOD0);
2431*9e39c5baSBill Taylor 	state->hs_fw_gpio[2] = hermon_flash_read_cfg(state, hdl,
2432*9e39c5baSBill Taylor 	    HERMON_HW_FLASH_GPIO_MOD1);
2433*9e39c5baSBill Taylor 
2434*9e39c5baSBill Taylor 	/* unlock GPIO */
2435*9e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_LOCK,
2436*9e39c5baSBill Taylor 	    HERMON_HW_FLASH_GPIO_UNLOCK_VAL);
2437*9e39c5baSBill Taylor 
2438*9e39c5baSBill Taylor 	/*
2439*9e39c5baSBill Taylor 	 * Set new GPIO values
2440*9e39c5baSBill Taylor 	 */
2441*9e39c5baSBill Taylor 	gpio = state->hs_fw_gpio[1] | HERMON_HW_FLASH_GPIO_PIN_ENABLE;
2442*9e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_MOD0, gpio);
2443*9e39c5baSBill Taylor 
2444*9e39c5baSBill Taylor 	gpio = state->hs_fw_gpio[2] & ~HERMON_HW_FLASH_GPIO_PIN_ENABLE;
2445*9e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_MOD1, gpio);
2446*9e39c5baSBill Taylor 
2447*9e39c5baSBill Taylor 	/* re-lock GPIO */
2448*9e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_LOCK, 0);
2449*9e39c5baSBill Taylor 
2450*9e39c5baSBill Taylor 	/* Set CPUMODE to enable hermon to access the flash device */
2451*9e39c5baSBill Taylor 	/* CMJ This code came from arbel.  Hermon doesn't seem to need it. */
2452*9e39c5baSBill Taylor 	/*
2453*9e39c5baSBill Taylor 	 *	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_CPUMODE,
2454*9e39c5baSBill Taylor 	 *	    1 << HERMON_HW_FLASH_CPU_SHIFT);
2455*9e39c5baSBill Taylor 	 */
2456*9e39c5baSBill Taylor 
2457*9e39c5baSBill Taylor 	/* the FMA retry loop ends. */
2458*9e39c5baSBill Taylor 	hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test);
2459*9e39c5baSBill Taylor 	return (0);
2460*9e39c5baSBill Taylor 
2461*9e39c5baSBill Taylor pio_error:
2462*9e39c5baSBill Taylor 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
2463*9e39c5baSBill Taylor 	return (EIO);
2464*9e39c5baSBill Taylor }
2465*9e39c5baSBill Taylor 
2466*9e39c5baSBill Taylor /*
2467*9e39c5baSBill Taylor  * hermon_flash_cfi_init
2468*9e39c5baSBill Taylor  *   Implements access to the CFI (Common Flash Interface) data
2469*9e39c5baSBill Taylor  */
2470*9e39c5baSBill Taylor static int
2471*9e39c5baSBill Taylor hermon_flash_cfi_init(hermon_state_t *state, uint32_t *cfi_info,
2472*9e39c5baSBill Taylor     int *intel_xcmd)
2473*9e39c5baSBill Taylor {
2474*9e39c5baSBill Taylor 	uint32_t	data;
2475*9e39c5baSBill Taylor 	uint32_t	sector_sz_bytes;
2476*9e39c5baSBill Taylor 	uint32_t	bit_count;
2477*9e39c5baSBill Taylor 	uint8_t		cfi_ch_info[HERMON_CFI_INFO_SIZE];
2478*9e39c5baSBill Taylor 	uint32_t	cfi_dw_info[HERMON_CFI_INFO_QSIZE];
2479*9e39c5baSBill Taylor 	int		i;
2480*9e39c5baSBill Taylor 	int		status;
2481*9e39c5baSBill Taylor 
2482*9e39c5baSBill Taylor 	/* Right now, all hermon cards use SPI. */
2483*9e39c5baSBill Taylor 	if (HERMON_IS_MAINTENANCE_MODE(state->hs_dip) ||
2484*9e39c5baSBill Taylor 	    HERMON_IS_HCA_MODE(state->hs_dip)) {
2485*9e39c5baSBill Taylor 		/*
2486*9e39c5baSBill Taylor 		 * Don't use CFI for SPI part. Just fill in what we need
2487*9e39c5baSBill Taylor 		 * and return.
2488*9e39c5baSBill Taylor 		 */
2489*9e39c5baSBill Taylor 		state->hs_fw_cmdset = HERMON_FLASH_SPI_CMDSET;
2490*9e39c5baSBill Taylor 		state->hs_fw_log_sector_sz = HERMON_FLASH_SPI_LOG_SECTOR_SIZE;
2491*9e39c5baSBill Taylor 		state->hs_fw_device_sz = HERMON_FLASH_SPI_DEVICE_SIZE;
2492*9e39c5baSBill Taylor 
2493*9e39c5baSBill Taylor 		/*
2494*9e39c5baSBill Taylor 		 * set this to inform caller of cmdset type.
2495*9e39c5baSBill Taylor 		 */
2496*9e39c5baSBill Taylor 		cfi_ch_info[0x13] = HERMON_FLASH_SPI_CMDSET;
2497*9e39c5baSBill Taylor 		hermon_flash_cfi_dword(&cfi_info[4], cfi_ch_info, 0x10);
2498*9e39c5baSBill Taylor 		return (0);
2499*9e39c5baSBill Taylor 	}
2500*9e39c5baSBill Taylor 
2501*9e39c5baSBill Taylor 	/*
2502*9e39c5baSBill Taylor 	 * Determine if the user command supports the Intel Extended
2503*9e39c5baSBill Taylor 	 * Command Set. The query string is contained in the fourth
2504*9e39c5baSBill Taylor 	 * quad word.
2505*9e39c5baSBill Taylor 	 */
2506*9e39c5baSBill Taylor 	hermon_flash_cfi_byte(cfi_ch_info, cfi_info[0x04], 0x10);
2507*9e39c5baSBill Taylor 	if (cfi_ch_info[0x10] == 'M' &&
2508*9e39c5baSBill Taylor 	    cfi_ch_info[0x11] == 'X' &&
2509*9e39c5baSBill Taylor 	    cfi_ch_info[0x12] == '2') {
2510*9e39c5baSBill Taylor 		*intel_xcmd = 1; /* support is there */
2511*9e39c5baSBill Taylor 		if (hermon_verbose) {
2512*9e39c5baSBill Taylor 			IBTF_DPRINTF_L2("hermon",
2513*9e39c5baSBill Taylor 			    "Support for Intel X is present\n");
2514*9e39c5baSBill Taylor 		}
2515*9e39c5baSBill Taylor 	}
2516*9e39c5baSBill Taylor 
2517*9e39c5baSBill Taylor 	/* CFI QUERY */
2518*9e39c5baSBill Taylor 	hermon_flash_write(state, 0x55, HERMON_FLASH_CFI_INIT, &status);
2519*9e39c5baSBill Taylor 	if (status != 0) {
2520*9e39c5baSBill Taylor 		return (status);
2521*9e39c5baSBill Taylor 	}
2522*9e39c5baSBill Taylor 
2523*9e39c5baSBill Taylor 	/* temporarily set the cmdset in order to do the initial read */
2524*9e39c5baSBill Taylor 	state->hs_fw_cmdset = HERMON_FLASH_INTEL_CMDSET;
2525*9e39c5baSBill Taylor 
2526*9e39c5baSBill Taylor 	/* Read in CFI data */
2527*9e39c5baSBill Taylor 	for (i = 0; i < HERMON_CFI_INFO_SIZE; i += 4) {
2528*9e39c5baSBill Taylor 		data = hermon_flash_read(state, i, &status);
2529*9e39c5baSBill Taylor 		if (status != 0) {
2530*9e39c5baSBill Taylor 			return (status);
2531*9e39c5baSBill Taylor 		}
2532*9e39c5baSBill Taylor 		cfi_dw_info[i >> 2] = data;
2533*9e39c5baSBill Taylor 		hermon_flash_cfi_byte(cfi_ch_info, data, i);
2534*9e39c5baSBill Taylor 	}
2535*9e39c5baSBill Taylor 
2536*9e39c5baSBill Taylor 	/* Determine chip set */
2537*9e39c5baSBill Taylor 	state->hs_fw_cmdset = HERMON_FLASH_UNKNOWN_CMDSET;
2538*9e39c5baSBill Taylor 	if (cfi_ch_info[0x20] == 'Q' &&
2539*9e39c5baSBill Taylor 	    cfi_ch_info[0x22] == 'R' &&
2540*9e39c5baSBill Taylor 	    cfi_ch_info[0x24] == 'Y') {
2541*9e39c5baSBill Taylor 		/*
2542*9e39c5baSBill Taylor 		 * Mode: x16 working in x8 mode (Intel).
2543*9e39c5baSBill Taylor 		 * Pack data - skip spacing bytes.
2544*9e39c5baSBill Taylor 		 */
2545*9e39c5baSBill Taylor 		if (hermon_verbose) {
2546*9e39c5baSBill Taylor 			IBTF_DPRINTF_L2("hermon",
2547*9e39c5baSBill Taylor 			    "x16 working in x8 mode (Intel)\n");
2548*9e39c5baSBill Taylor 		}
2549*9e39c5baSBill Taylor 		for (i = 0; i < HERMON_CFI_INFO_SIZE; i += 2) {
2550*9e39c5baSBill Taylor 			cfi_ch_info[i/2] = cfi_ch_info[i];
2551*9e39c5baSBill Taylor 		}
2552*9e39c5baSBill Taylor 	}
2553*9e39c5baSBill Taylor 	state->hs_fw_cmdset = cfi_ch_info[0x13];
2554*9e39c5baSBill Taylor 
2555*9e39c5baSBill Taylor 	if (state->hs_fw_cmdset != HERMON_FLASH_INTEL_CMDSET &&
2556*9e39c5baSBill Taylor 	    state->hs_fw_cmdset != HERMON_FLASH_AMD_CMDSET) {
2557*9e39c5baSBill Taylor 		cmn_err(CE_WARN,
2558*9e39c5baSBill Taylor 		    "hermon_flash_cfi_init: UNKNOWN chip cmd set 0x%04x\n",
2559*9e39c5baSBill Taylor 		    state->hs_fw_cmdset);
2560*9e39c5baSBill Taylor 		state->hs_fw_cmdset = HERMON_FLASH_UNKNOWN_CMDSET;
2561*9e39c5baSBill Taylor 		return (0);
2562*9e39c5baSBill Taylor 	}
2563*9e39c5baSBill Taylor 
2564*9e39c5baSBill Taylor 	/* Determine total bytes in one sector size */
2565*9e39c5baSBill Taylor 	sector_sz_bytes = ((cfi_ch_info[0x30] << 8) | cfi_ch_info[0x2F]) << 8;
2566*9e39c5baSBill Taylor 
2567*9e39c5baSBill Taylor 	/* Calculate equivalent of log2 (n) */
2568*9e39c5baSBill Taylor 	for (bit_count = 0; sector_sz_bytes > 1; bit_count++) {
2569*9e39c5baSBill Taylor 		sector_sz_bytes >>= 1;
2570*9e39c5baSBill Taylor 	}
2571*9e39c5baSBill Taylor 
2572*9e39c5baSBill Taylor 	/* Set sector size */
2573*9e39c5baSBill Taylor 	state->hs_fw_log_sector_sz = bit_count;
2574*9e39c5baSBill Taylor 
2575*9e39c5baSBill Taylor 	/* Set flash size */
2576*9e39c5baSBill Taylor 	state->hs_fw_device_sz = 0x1 << cfi_ch_info[0x27];
2577*9e39c5baSBill Taylor 
2578*9e39c5baSBill Taylor 	/* Reset to turn off CFI mode */
2579*9e39c5baSBill Taylor 	if ((status = hermon_flash_reset(state)) != 0)
2580*9e39c5baSBill Taylor 		goto out;
2581*9e39c5baSBill Taylor 
2582*9e39c5baSBill Taylor 	/* Pass CFI data back to user command. */
2583*9e39c5baSBill Taylor 	for (i = 0; i < HERMON_FLASH_CFI_SIZE_QUADLET; i++) {
2584*9e39c5baSBill Taylor 		hermon_flash_cfi_dword(&cfi_info[i], cfi_ch_info, i << 2);
2585*9e39c5baSBill Taylor 	}
2586*9e39c5baSBill Taylor 
2587*9e39c5baSBill Taylor 	if (*intel_xcmd == 1) {
2588*9e39c5baSBill Taylor 		/*
2589*9e39c5baSBill Taylor 		 * Inform the user cmd that this driver does support the
2590*9e39c5baSBill Taylor 		 * Intel Extended Command Set.
2591*9e39c5baSBill Taylor 		 */
2592*9e39c5baSBill Taylor 		cfi_ch_info[0x10] = 'M';
2593*9e39c5baSBill Taylor 		cfi_ch_info[0x11] = 'X';
2594*9e39c5baSBill Taylor 		cfi_ch_info[0x12] = '2';
2595*9e39c5baSBill Taylor 	} else {
2596*9e39c5baSBill Taylor 		cfi_ch_info[0x10] = 'Q';
2597*9e39c5baSBill Taylor 		cfi_ch_info[0x11] = 'R';
2598*9e39c5baSBill Taylor 		cfi_ch_info[0x12] = 'Y';
2599*9e39c5baSBill Taylor 	}
2600*9e39c5baSBill Taylor 	cfi_ch_info[0x13] = state->hs_fw_cmdset;
2601*9e39c5baSBill Taylor 	hermon_flash_cfi_dword(&cfi_info[0x4], cfi_ch_info, 0x10);
2602*9e39c5baSBill Taylor out:
2603*9e39c5baSBill Taylor 	return (status);
2604*9e39c5baSBill Taylor }
2605*9e39c5baSBill Taylor 
2606*9e39c5baSBill Taylor /*
2607*9e39c5baSBill Taylor  * hermon_flash_fini()
2608*9e39c5baSBill Taylor  */
2609*9e39c5baSBill Taylor static int
2610*9e39c5baSBill Taylor hermon_flash_fini(hermon_state_t *state)
2611*9e39c5baSBill Taylor {
2612*9e39c5baSBill Taylor 	int status;
2613*9e39c5baSBill Taylor 	ddi_acc_handle_t hdl;
2614*9e39c5baSBill Taylor 
2615*9e39c5baSBill Taylor 	/* initialize the FMA retry loop */
2616*9e39c5baSBill Taylor 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
2617*9e39c5baSBill Taylor 
2618*9e39c5baSBill Taylor 	/* Set handle */
2619*9e39c5baSBill Taylor 	hdl = hermon_get_pcihdl(state);
2620*9e39c5baSBill Taylor 
2621*9e39c5baSBill Taylor 	if ((status = hermon_flash_bank(state, 0)) != 0)
2622*9e39c5baSBill Taylor 		return (status);
2623*9e39c5baSBill Taylor 
2624*9e39c5baSBill Taylor 	/* the FMA retry loop starts. */
2625*9e39c5baSBill Taylor 	hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
2626*9e39c5baSBill Taylor 	    fm_test);
2627*9e39c5baSBill Taylor 
2628*9e39c5baSBill Taylor 	/*
2629*9e39c5baSBill Taylor 	 * Restore original GPIO Values
2630*9e39c5baSBill Taylor 	 */
2631*9e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_DATA,
2632*9e39c5baSBill Taylor 	    state->hs_fw_gpio[0]);
2633*9e39c5baSBill Taylor 
2634*9e39c5baSBill Taylor 	/* unlock GPIOs */
2635*9e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_LOCK,
2636*9e39c5baSBill Taylor 	    HERMON_HW_FLASH_GPIO_UNLOCK_VAL);
2637*9e39c5baSBill Taylor 
2638*9e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_MOD0,
2639*9e39c5baSBill Taylor 	    state->hs_fw_gpio[1]);
2640*9e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_MOD1,
2641*9e39c5baSBill Taylor 	    state->hs_fw_gpio[2]);
2642*9e39c5baSBill Taylor 
2643*9e39c5baSBill Taylor 	/* re-lock GPIOs */
2644*9e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_LOCK, 0);
2645*9e39c5baSBill Taylor 
2646*9e39c5baSBill Taylor 	/* Give up gpio semaphore */
2647*9e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_SEMA, 0);
2648*9e39c5baSBill Taylor 
2649*9e39c5baSBill Taylor 	/* the FMA retry loop ends. */
2650*9e39c5baSBill Taylor 	hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test);
2651*9e39c5baSBill Taylor 	return (0);
2652*9e39c5baSBill Taylor 
2653*9e39c5baSBill Taylor pio_error:
2654*9e39c5baSBill Taylor 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
2655*9e39c5baSBill Taylor 	return (EIO);
2656*9e39c5baSBill Taylor }
2657*9e39c5baSBill Taylor 
2658*9e39c5baSBill Taylor /*
2659*9e39c5baSBill Taylor  * hermon_flash_read_cfg
2660*9e39c5baSBill Taylor  */
2661*9e39c5baSBill Taylor static uint32_t
2662*9e39c5baSBill Taylor hermon_flash_read_cfg(hermon_state_t *state, ddi_acc_handle_t pci_config_hdl,
2663*9e39c5baSBill Taylor     uint32_t addr)
2664*9e39c5baSBill Taylor {
2665*9e39c5baSBill Taylor 	uint32_t	read;
2666*9e39c5baSBill Taylor 
2667*9e39c5baSBill Taylor 	if (do_bar0) {
2668*9e39c5baSBill Taylor 		read = ddi_get32(hermon_get_cmdhdl(state), (uint32_t *)(void *)
2669*9e39c5baSBill Taylor 		    (state->hs_reg_cmd_baseaddr + addr));
2670*9e39c5baSBill Taylor 	} else {
2671*9e39c5baSBill Taylor 		/*
2672*9e39c5baSBill Taylor 		 * Perform flash read operation:
2673*9e39c5baSBill Taylor 		 *   1) Place addr to read from on the HERMON_HW_FLASH_CFG_ADDR
2674*9e39c5baSBill Taylor 		 *	register
2675*9e39c5baSBill Taylor 		 *   2) Read data at that addr from the HERMON_HW_FLASH_CFG_DATA
2676*9e39c5baSBill Taylor 		 *	 register
2677*9e39c5baSBill Taylor 		 */
2678*9e39c5baSBill Taylor 		pci_config_put32(pci_config_hdl, HERMON_HW_FLASH_CFG_ADDR,
2679*9e39c5baSBill Taylor 		    addr);
2680*9e39c5baSBill Taylor 		read = pci_config_get32(pci_config_hdl,
2681*9e39c5baSBill Taylor 		    HERMON_HW_FLASH_CFG_DATA);
2682*9e39c5baSBill Taylor 	}
2683*9e39c5baSBill Taylor 
2684*9e39c5baSBill Taylor 	return (read);
2685*9e39c5baSBill Taylor }
2686*9e39c5baSBill Taylor 
2687*9e39c5baSBill Taylor #ifdef DO_WRCONF
2688*9e39c5baSBill Taylor static void
2689*9e39c5baSBill Taylor hermon_flash_write_cfg(hermon_state_t *state,
2690*9e39c5baSBill Taylor     ddi_acc_handle_t pci_config_hdl, uint32_t addr, uint32_t data)
2691*9e39c5baSBill Taylor {
2692*9e39c5baSBill Taylor 	hermon_flash_write_cfg_helper(state, pci_config_hdl, addr, data);
2693*9e39c5baSBill Taylor 	hermon_flash_write_confirm(state, pci_config_hdl);
2694*9e39c5baSBill Taylor }
2695*9e39c5baSBill Taylor 
2696*9e39c5baSBill Taylor static void
2697*9e39c5baSBill Taylor hermon_flash_write_confirm(hermon_state_t *state,
2698*9e39c5baSBill Taylor     ddi_acc_handle_t pci_config_hdl)
2699*9e39c5baSBill Taylor {
2700*9e39c5baSBill Taylor 	uint32_t	sem_value = 1;
2701*9e39c5baSBill Taylor 
2702*9e39c5baSBill Taylor 	hermon_flash_write_cfg_helper(state, pci_config_hdl,
2703*9e39c5baSBill Taylor 	    HERMON_HW_FLASH_WRCONF_SEMA, 0);
2704*9e39c5baSBill Taylor 	while (sem_value) {
2705*9e39c5baSBill Taylor 		sem_value = hermon_flash_read_cfg(state, pci_config_hdl,
2706*9e39c5baSBill Taylor 		    HERMON_HW_FLASH_WRCONF_SEMA);
2707*9e39c5baSBill Taylor 	}
2708*9e39c5baSBill Taylor }
2709*9e39c5baSBill Taylor #endif
2710*9e39c5baSBill Taylor 
2711*9e39c5baSBill Taylor /*
2712*9e39c5baSBill Taylor  * hermon_flash_write_cfg
2713*9e39c5baSBill Taylor  */
2714*9e39c5baSBill Taylor static void
2715*9e39c5baSBill Taylor #ifdef DO_WRCONF
2716*9e39c5baSBill Taylor hermon_flash_write_cfg_helper(hermon_state_t *state,
2717*9e39c5baSBill Taylor     ddi_acc_handle_t pci_config_hdl, uint32_t addr, uint32_t data)
2718*9e39c5baSBill Taylor #else
2719*9e39c5baSBill Taylor hermon_flash_write_cfg(hermon_state_t *state,
2720*9e39c5baSBill Taylor     ddi_acc_handle_t pci_config_hdl, uint32_t addr, uint32_t data)
2721*9e39c5baSBill Taylor #endif
2722*9e39c5baSBill Taylor {
2723*9e39c5baSBill Taylor 	if (do_bar0) {
2724*9e39c5baSBill Taylor 		ddi_put32(hermon_get_cmdhdl(state), (uint32_t *)(void *)
2725*9e39c5baSBill Taylor 		    (state->hs_reg_cmd_baseaddr + addr), data);
2726*9e39c5baSBill Taylor 
2727*9e39c5baSBill Taylor 	} else {
2728*9e39c5baSBill Taylor 
2729*9e39c5baSBill Taylor 		/*
2730*9e39c5baSBill Taylor 		 * Perform flash write operation:
2731*9e39c5baSBill Taylor 		 *   1) Place addr to write to on the HERMON_HW_FLASH_CFG_ADDR
2732*9e39c5baSBill Taylor 		 *	register
2733*9e39c5baSBill Taylor 		 *   2) Place data to write on to the HERMON_HW_FLASH_CFG_DATA
2734*9e39c5baSBill Taylor 		 *	register
2735*9e39c5baSBill Taylor 		 */
2736*9e39c5baSBill Taylor 		pci_config_put32(pci_config_hdl, HERMON_HW_FLASH_CFG_ADDR,
2737*9e39c5baSBill Taylor 		    addr);
2738*9e39c5baSBill Taylor 		pci_config_put32(pci_config_hdl, HERMON_HW_FLASH_CFG_DATA,
2739*9e39c5baSBill Taylor 		    data);
2740*9e39c5baSBill Taylor 	}
2741*9e39c5baSBill Taylor }
2742*9e39c5baSBill Taylor 
2743*9e39c5baSBill Taylor /*
2744*9e39c5baSBill Taylor  * Support routines to convert Common Flash Interface (CFI) data
2745*9e39c5baSBill Taylor  * from a 32  bit word to a char array, and from a char array to
2746*9e39c5baSBill Taylor  * a 32 bit word.
2747*9e39c5baSBill Taylor  */
2748*9e39c5baSBill Taylor static void
2749*9e39c5baSBill Taylor hermon_flash_cfi_byte(uint8_t *ch, uint32_t dword, int i)
2750*9e39c5baSBill Taylor {
2751*9e39c5baSBill Taylor 	ch[i] = (uint8_t)((dword & 0xFF000000) >> 24);
2752*9e39c5baSBill Taylor 	ch[i+1] = (uint8_t)((dword & 0x00FF0000) >> 16);
2753*9e39c5baSBill Taylor 	ch[i+2] = (uint8_t)((dword & 0x0000FF00) >> 8);
2754*9e39c5baSBill Taylor 	ch[i+3] = (uint8_t)((dword & 0x000000FF));
2755*9e39c5baSBill Taylor }
2756*9e39c5baSBill Taylor 
2757*9e39c5baSBill Taylor static void
2758*9e39c5baSBill Taylor hermon_flash_cfi_dword(uint32_t *dword, uint8_t *ch, int i)
2759*9e39c5baSBill Taylor {
2760*9e39c5baSBill Taylor 	*dword = (uint32_t)
2761*9e39c5baSBill Taylor 	    ((uint32_t)ch[i] << 24 |
2762*9e39c5baSBill Taylor 	    (uint32_t)ch[i+1] << 16 |
2763*9e39c5baSBill Taylor 	    (uint32_t)ch[i+2] << 8 |
2764*9e39c5baSBill Taylor 	    (uint32_t)ch[i+3]);
2765*9e39c5baSBill Taylor }
2766*9e39c5baSBill Taylor 
2767*9e39c5baSBill Taylor /*
2768*9e39c5baSBill Taylor  * hermon_loopback_free_qps
2769*9e39c5baSBill Taylor  */
2770*9e39c5baSBill Taylor static void
2771*9e39c5baSBill Taylor hermon_loopback_free_qps(hermon_loopback_state_t *lstate)
2772*9e39c5baSBill Taylor {
2773*9e39c5baSBill Taylor 	int i;
2774*9e39c5baSBill Taylor 
2775*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate))
2776*9e39c5baSBill Taylor 
2777*9e39c5baSBill Taylor 	if (lstate->hls_tx.hlc_qp_hdl != NULL) {
2778*9e39c5baSBill Taylor 		(void) hermon_qp_free(lstate->hls_state,
2779*9e39c5baSBill Taylor 		    &lstate->hls_tx.hlc_qp_hdl, IBC_FREE_QP_AND_QPN, NULL,
2780*9e39c5baSBill Taylor 		    HERMON_NOSLEEP);
2781*9e39c5baSBill Taylor 	}
2782*9e39c5baSBill Taylor 	if (lstate->hls_rx.hlc_qp_hdl != NULL) {
2783*9e39c5baSBill Taylor 		(void) hermon_qp_free(lstate->hls_state,
2784*9e39c5baSBill Taylor 		    &lstate->hls_rx.hlc_qp_hdl, IBC_FREE_QP_AND_QPN, NULL,
2785*9e39c5baSBill Taylor 		    HERMON_NOSLEEP);
2786*9e39c5baSBill Taylor 	}
2787*9e39c5baSBill Taylor 	lstate->hls_tx.hlc_qp_hdl = NULL;
2788*9e39c5baSBill Taylor 	lstate->hls_rx.hlc_qp_hdl = NULL;
2789*9e39c5baSBill Taylor 	for (i = 0; i < 2; i++) {
2790*9e39c5baSBill Taylor 		if (lstate->hls_tx.hlc_cqhdl[i] != NULL) {
2791*9e39c5baSBill Taylor 			(void) hermon_cq_free(lstate->hls_state,
2792*9e39c5baSBill Taylor 			    &lstate->hls_tx.hlc_cqhdl[i], HERMON_NOSLEEP);
2793*9e39c5baSBill Taylor 		}
2794*9e39c5baSBill Taylor 		if (lstate->hls_rx.hlc_cqhdl[i] != NULL) {
2795*9e39c5baSBill Taylor 			(void) hermon_cq_free(lstate->hls_state,
2796*9e39c5baSBill Taylor 			    &lstate->hls_rx.hlc_cqhdl[i], HERMON_NOSLEEP);
2797*9e39c5baSBill Taylor 		}
2798*9e39c5baSBill Taylor 		lstate->hls_tx.hlc_cqhdl[i] = NULL;
2799*9e39c5baSBill Taylor 		lstate->hls_rx.hlc_cqhdl[i] = NULL;
2800*9e39c5baSBill Taylor 	}
2801*9e39c5baSBill Taylor }
2802*9e39c5baSBill Taylor 
2803*9e39c5baSBill Taylor /*
2804*9e39c5baSBill Taylor  * hermon_loopback_free_state
2805*9e39c5baSBill Taylor  */
2806*9e39c5baSBill Taylor static void
2807*9e39c5baSBill Taylor hermon_loopback_free_state(hermon_loopback_state_t *lstate)
2808*9e39c5baSBill Taylor {
2809*9e39c5baSBill Taylor 	hermon_loopback_free_qps(lstate);
2810*9e39c5baSBill Taylor 	if (lstate->hls_tx.hlc_mrhdl != NULL) {
2811*9e39c5baSBill Taylor 		(void) hermon_mr_deregister(lstate->hls_state,
2812*9e39c5baSBill Taylor 		    &lstate->hls_tx.hlc_mrhdl, HERMON_MR_DEREG_ALL,
2813*9e39c5baSBill Taylor 		    HERMON_NOSLEEP);
2814*9e39c5baSBill Taylor 	}
2815*9e39c5baSBill Taylor 	if (lstate->hls_rx.hlc_mrhdl !=  NULL) {
2816*9e39c5baSBill Taylor 		(void) hermon_mr_deregister(lstate->hls_state,
2817*9e39c5baSBill Taylor 		    &lstate->hls_rx.hlc_mrhdl, HERMON_MR_DEREG_ALL,
2818*9e39c5baSBill Taylor 		    HERMON_NOSLEEP);
2819*9e39c5baSBill Taylor 	}
2820*9e39c5baSBill Taylor 	if (lstate->hls_pd_hdl != NULL) {
2821*9e39c5baSBill Taylor 		(void) hermon_pd_free(lstate->hls_state, &lstate->hls_pd_hdl);
2822*9e39c5baSBill Taylor 	}
2823*9e39c5baSBill Taylor 	if (lstate->hls_tx.hlc_buf != NULL) {
2824*9e39c5baSBill Taylor 		kmem_free(lstate->hls_tx.hlc_buf, lstate->hls_tx.hlc_buf_sz);
2825*9e39c5baSBill Taylor 	}
2826*9e39c5baSBill Taylor 	if (lstate->hls_rx.hlc_buf != NULL) {
2827*9e39c5baSBill Taylor 		kmem_free(lstate->hls_rx.hlc_buf, lstate->hls_rx.hlc_buf_sz);
2828*9e39c5baSBill Taylor 	}
2829*9e39c5baSBill Taylor 	bzero(lstate, sizeof (hermon_loopback_state_t));
2830*9e39c5baSBill Taylor }
2831*9e39c5baSBill Taylor 
2832*9e39c5baSBill Taylor /*
2833*9e39c5baSBill Taylor  * hermon_loopback_init
2834*9e39c5baSBill Taylor  */
2835*9e39c5baSBill Taylor static int
2836*9e39c5baSBill Taylor hermon_loopback_init(hermon_state_t *state, hermon_loopback_state_t *lstate)
2837*9e39c5baSBill Taylor {
2838*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate))
2839*9e39c5baSBill Taylor 
2840*9e39c5baSBill Taylor 	lstate->hls_hca_hdl = (ibc_hca_hdl_t)state;
2841*9e39c5baSBill Taylor 	lstate->hls_status  = hermon_pd_alloc(lstate->hls_state,
2842*9e39c5baSBill Taylor 	    &lstate->hls_pd_hdl, HERMON_NOSLEEP);
2843*9e39c5baSBill Taylor 	if (lstate->hls_status != IBT_SUCCESS) {
2844*9e39c5baSBill Taylor 		lstate->hls_err = HERMON_LOOPBACK_PROT_DOMAIN_ALLOC_FAIL;
2845*9e39c5baSBill Taylor 		return (EFAULT);
2846*9e39c5baSBill Taylor 	}
2847*9e39c5baSBill Taylor 
2848*9e39c5baSBill Taylor 	return (0);
2849*9e39c5baSBill Taylor }
2850*9e39c5baSBill Taylor 
2851*9e39c5baSBill Taylor /*
2852*9e39c5baSBill Taylor  * hermon_loopback_init_qp_info
2853*9e39c5baSBill Taylor  */
2854*9e39c5baSBill Taylor static void
2855*9e39c5baSBill Taylor hermon_loopback_init_qp_info(hermon_loopback_state_t *lstate,
2856*9e39c5baSBill Taylor     hermon_loopback_comm_t *comm)
2857*9e39c5baSBill Taylor {
2858*9e39c5baSBill Taylor 	bzero(&comm->hlc_cq_attr, sizeof (ibt_cq_attr_t));
2859*9e39c5baSBill Taylor 	bzero(&comm->hlc_qp_attr, sizeof (ibt_qp_alloc_attr_t));
2860*9e39c5baSBill Taylor 	bzero(&comm->hlc_qp_info, sizeof (ibt_qp_info_t));
2861*9e39c5baSBill Taylor 
2862*9e39c5baSBill Taylor 	comm->hlc_wrid = 1;
2863*9e39c5baSBill Taylor 	comm->hlc_cq_attr.cq_size = 128;
2864*9e39c5baSBill Taylor 	comm->hlc_qp_attr.qp_sizes.cs_sq_sgl = 3;
2865*9e39c5baSBill Taylor 	comm->hlc_qp_attr.qp_sizes.cs_rq_sgl = 3;
2866*9e39c5baSBill Taylor 	comm->hlc_qp_attr.qp_sizes.cs_sq = 16;
2867*9e39c5baSBill Taylor 	comm->hlc_qp_attr.qp_sizes.cs_rq = 16;
2868*9e39c5baSBill Taylor 	comm->hlc_qp_attr.qp_flags = IBT_WR_SIGNALED;
2869*9e39c5baSBill Taylor 
2870*9e39c5baSBill Taylor 	comm->hlc_qp_info.qp_state = IBT_STATE_RESET;
2871*9e39c5baSBill Taylor 	comm->hlc_qp_info.qp_trans = IBT_RC_SRV;
2872*9e39c5baSBill Taylor 	comm->hlc_qp_info.qp_flags = IBT_CEP_RDMA_RD | IBT_CEP_RDMA_WR;
2873*9e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_path.cep_hca_port_num =
2874*9e39c5baSBill Taylor 	    lstate->hls_port;
2875*9e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_path.cep_pkey_ix =
2876*9e39c5baSBill Taylor 	    lstate->hls_pkey_ix;
2877*9e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_path.cep_timeout =
2878*9e39c5baSBill Taylor 	    lstate->hls_timeout;
2879*9e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_srvl = 0;
2880*9e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_srate =
2881*9e39c5baSBill Taylor 	    IBT_SRATE_4X;
2882*9e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_send_grh = 0;
2883*9e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_dlid =
2884*9e39c5baSBill Taylor 	    lstate->hls_lid;
2885*9e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_retry_cnt = lstate->hls_retry;
2886*9e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_sq_psn = 0;
2887*9e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_rq_psn = 0;
2888*9e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_rdma_ra_in	 = 4;
2889*9e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_rdma_ra_out = 4;
2890*9e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_dst_qpn = 0;
2891*9e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_min_rnr_nak = IBT_RNR_NAK_655ms;
2892*9e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_path_mtu = IB_MTU_1K;
2893*9e39c5baSBill Taylor }
2894*9e39c5baSBill Taylor 
2895*9e39c5baSBill Taylor /*
2896*9e39c5baSBill Taylor  * hermon_loopback_alloc_mem
2897*9e39c5baSBill Taylor  */
2898*9e39c5baSBill Taylor static int
2899*9e39c5baSBill Taylor hermon_loopback_alloc_mem(hermon_loopback_state_t *lstate,
2900*9e39c5baSBill Taylor     hermon_loopback_comm_t *comm, int sz)
2901*9e39c5baSBill Taylor {
2902*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm))
2903*9e39c5baSBill Taylor 
2904*9e39c5baSBill Taylor 	/* Allocate buffer of specified size */
2905*9e39c5baSBill Taylor 	comm->hlc_buf_sz = sz;
2906*9e39c5baSBill Taylor 	comm->hlc_buf	 = kmem_zalloc(sz, KM_NOSLEEP);
2907*9e39c5baSBill Taylor 	if (comm->hlc_buf == NULL) {
2908*9e39c5baSBill Taylor 		return (EFAULT);
2909*9e39c5baSBill Taylor 	}
2910*9e39c5baSBill Taylor 
2911*9e39c5baSBill Taylor 	/* Register the buffer as a memory region */
2912*9e39c5baSBill Taylor 	comm->hlc_memattr.mr_vaddr = (uint64_t)(uintptr_t)comm->hlc_buf;
2913*9e39c5baSBill Taylor 	comm->hlc_memattr.mr_len   = (ib_msglen_t)sz;
2914*9e39c5baSBill Taylor 	comm->hlc_memattr.mr_as	   = NULL;
2915*9e39c5baSBill Taylor 	comm->hlc_memattr.mr_flags = IBT_MR_NOSLEEP |
2916*9e39c5baSBill Taylor 	    IBT_MR_ENABLE_REMOTE_WRITE | IBT_MR_ENABLE_LOCAL_WRITE;
2917*9e39c5baSBill Taylor 
2918*9e39c5baSBill Taylor 	comm->hlc_status = hermon_mr_register(lstate->hls_state,
2919*9e39c5baSBill Taylor 	    lstate->hls_pd_hdl, &comm->hlc_memattr, &comm->hlc_mrhdl,
2920*9e39c5baSBill Taylor 	    NULL, HERMON_MPT_DMPT);
2921*9e39c5baSBill Taylor 
2922*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm->hlc_mrhdl))
2923*9e39c5baSBill Taylor 
2924*9e39c5baSBill Taylor 	comm->hlc_mrdesc.md_vaddr  = comm->hlc_mrhdl->mr_bindinfo.bi_addr;
2925*9e39c5baSBill Taylor 	comm->hlc_mrdesc.md_lkey   = comm->hlc_mrhdl->mr_lkey;
2926*9e39c5baSBill Taylor 	comm->hlc_mrdesc.md_rkey   = comm->hlc_mrhdl->mr_rkey;
2927*9e39c5baSBill Taylor 	if (comm->hlc_status != IBT_SUCCESS) {
2928*9e39c5baSBill Taylor 		return (EFAULT);
2929*9e39c5baSBill Taylor 	}
2930*9e39c5baSBill Taylor 	return (0);
2931*9e39c5baSBill Taylor }
2932*9e39c5baSBill Taylor 
2933*9e39c5baSBill Taylor /*
2934*9e39c5baSBill Taylor  * hermon_loopback_alloc_qps
2935*9e39c5baSBill Taylor  */
2936*9e39c5baSBill Taylor static int
2937*9e39c5baSBill Taylor hermon_loopback_alloc_qps(hermon_loopback_state_t *lstate,
2938*9e39c5baSBill Taylor     hermon_loopback_comm_t *comm)
2939*9e39c5baSBill Taylor {
2940*9e39c5baSBill Taylor 	uint32_t		i, real_size;
2941*9e39c5baSBill Taylor 	hermon_qp_info_t		qpinfo;
2942*9e39c5baSBill Taylor 
2943*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm))
2944*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate))
2945*9e39c5baSBill Taylor 
2946*9e39c5baSBill Taylor 	/* Allocate send and recv CQs */
2947*9e39c5baSBill Taylor 	for (i = 0; i < 2; i++) {
2948*9e39c5baSBill Taylor 		bzero(&comm->hlc_cq_attr, sizeof (ibt_cq_attr_t));
2949*9e39c5baSBill Taylor 		comm->hlc_cq_attr.cq_size = 128;
2950*9e39c5baSBill Taylor 		comm->hlc_status = hermon_cq_alloc(lstate->hls_state,
2951*9e39c5baSBill Taylor 		    (ibt_cq_hdl_t)NULL, &comm->hlc_cq_attr, &real_size,
2952*9e39c5baSBill Taylor 		    &comm->hlc_cqhdl[i], HERMON_NOSLEEP);
2953*9e39c5baSBill Taylor 		if (comm->hlc_status != IBT_SUCCESS) {
2954*9e39c5baSBill Taylor 			lstate->hls_err += i;
2955*9e39c5baSBill Taylor 			return (EFAULT);
2956*9e39c5baSBill Taylor 		}
2957*9e39c5baSBill Taylor 	}
2958*9e39c5baSBill Taylor 
2959*9e39c5baSBill Taylor 	/* Allocate the QP */
2960*9e39c5baSBill Taylor 	hermon_loopback_init_qp_info(lstate, comm);
2961*9e39c5baSBill Taylor 	comm->hlc_qp_attr.qp_pd_hdl	 = (ibt_pd_hdl_t)lstate->hls_pd_hdl;
2962*9e39c5baSBill Taylor 	comm->hlc_qp_attr.qp_scq_hdl	 = (ibt_cq_hdl_t)comm->hlc_cqhdl[0];
2963*9e39c5baSBill Taylor 	comm->hlc_qp_attr.qp_rcq_hdl	 = (ibt_cq_hdl_t)comm->hlc_cqhdl[1];
2964*9e39c5baSBill Taylor 	comm->hlc_qp_attr.qp_ibc_scq_hdl = (ibt_opaque1_t)comm->hlc_cqhdl[0];
2965*9e39c5baSBill Taylor 	comm->hlc_qp_attr.qp_ibc_rcq_hdl = (ibt_opaque1_t)comm->hlc_cqhdl[1];
2966*9e39c5baSBill Taylor 	qpinfo.qpi_attrp	= &comm->hlc_qp_attr;
2967*9e39c5baSBill Taylor 	qpinfo.qpi_type		= IBT_RC_RQP;
2968*9e39c5baSBill Taylor 	qpinfo.qpi_ibt_qphdl	= NULL;
2969*9e39c5baSBill Taylor 	qpinfo.qpi_queueszp	= &comm->hlc_chan_sizes;
2970*9e39c5baSBill Taylor 	qpinfo.qpi_qpn		= &comm->hlc_qp_num;
2971*9e39c5baSBill Taylor 	comm->hlc_status = hermon_qp_alloc(lstate->hls_state, &qpinfo,
2972*9e39c5baSBill Taylor 	    HERMON_NOSLEEP);
2973*9e39c5baSBill Taylor 	if (comm->hlc_status == DDI_SUCCESS) {
2974*9e39c5baSBill Taylor 		comm->hlc_qp_hdl = qpinfo.qpi_qphdl;
2975*9e39c5baSBill Taylor 	}
2976*9e39c5baSBill Taylor 
2977*9e39c5baSBill Taylor 	if (comm->hlc_status != IBT_SUCCESS) {
2978*9e39c5baSBill Taylor 		lstate->hls_err += 2;
2979*9e39c5baSBill Taylor 		return (EFAULT);
2980*9e39c5baSBill Taylor 	}
2981*9e39c5baSBill Taylor 	return (0);
2982*9e39c5baSBill Taylor }
2983*9e39c5baSBill Taylor 
2984*9e39c5baSBill Taylor /*
2985*9e39c5baSBill Taylor  * hermon_loopback_modify_qp
2986*9e39c5baSBill Taylor  */
2987*9e39c5baSBill Taylor static int
2988*9e39c5baSBill Taylor hermon_loopback_modify_qp(hermon_loopback_state_t *lstate,
2989*9e39c5baSBill Taylor     hermon_loopback_comm_t *comm, uint_t qp_num)
2990*9e39c5baSBill Taylor {
2991*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm))
2992*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate))
2993*9e39c5baSBill Taylor 
2994*9e39c5baSBill Taylor 	/* Modify QP to INIT */
2995*9e39c5baSBill Taylor 	hermon_loopback_init_qp_info(lstate, comm);
2996*9e39c5baSBill Taylor 	comm->hlc_qp_info.qp_state = IBT_STATE_INIT;
2997*9e39c5baSBill Taylor 	comm->hlc_status = hermon_qp_modify(lstate->hls_state, comm->hlc_qp_hdl,
2998*9e39c5baSBill Taylor 	    IBT_CEP_SET_STATE, &comm->hlc_qp_info, &comm->hlc_queue_sizes);
2999*9e39c5baSBill Taylor 	if (comm->hlc_status != IBT_SUCCESS) {
3000*9e39c5baSBill Taylor 		return (EFAULT);
3001*9e39c5baSBill Taylor 	}
3002*9e39c5baSBill Taylor 
3003*9e39c5baSBill Taylor 	/*
3004*9e39c5baSBill Taylor 	 * Modify QP to RTR (set destination LID and QP number to local
3005*9e39c5baSBill Taylor 	 * LID and QP number)
3006*9e39c5baSBill Taylor 	 */
3007*9e39c5baSBill Taylor 	comm->hlc_qp_info.qp_state = IBT_STATE_RTR;
3008*9e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_dlid
3009*9e39c5baSBill Taylor 	    = lstate->hls_lid;
3010*9e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_dst_qpn = qp_num;
3011*9e39c5baSBill Taylor 	comm->hlc_status = hermon_qp_modify(lstate->hls_state, comm->hlc_qp_hdl,
3012*9e39c5baSBill Taylor 	    IBT_CEP_SET_STATE, &comm->hlc_qp_info, &comm->hlc_queue_sizes);
3013*9e39c5baSBill Taylor 	if (comm->hlc_status != IBT_SUCCESS) {
3014*9e39c5baSBill Taylor 		lstate->hls_err += 1;
3015*9e39c5baSBill Taylor 		return (EFAULT);
3016*9e39c5baSBill Taylor 	}
3017*9e39c5baSBill Taylor 
3018*9e39c5baSBill Taylor 	/* Modify QP to RTS */
3019*9e39c5baSBill Taylor 	comm->hlc_qp_info.qp_current_state = IBT_STATE_RTR;
3020*9e39c5baSBill Taylor 	comm->hlc_qp_info.qp_state = IBT_STATE_RTS;
3021*9e39c5baSBill Taylor 	comm->hlc_status = hermon_qp_modify(lstate->hls_state, comm->hlc_qp_hdl,
3022*9e39c5baSBill Taylor 	    IBT_CEP_SET_STATE, &comm->hlc_qp_info, &comm->hlc_queue_sizes);
3023*9e39c5baSBill Taylor 	if (comm->hlc_status != IBT_SUCCESS) {
3024*9e39c5baSBill Taylor 		lstate->hls_err += 2;
3025*9e39c5baSBill Taylor 		return (EFAULT);
3026*9e39c5baSBill Taylor 	}
3027*9e39c5baSBill Taylor 	return (0);
3028*9e39c5baSBill Taylor }
3029*9e39c5baSBill Taylor 
3030*9e39c5baSBill Taylor /*
3031*9e39c5baSBill Taylor  * hermon_loopback_copyout
3032*9e39c5baSBill Taylor  */
3033*9e39c5baSBill Taylor static int
3034*9e39c5baSBill Taylor hermon_loopback_copyout(hermon_loopback_ioctl_t *lb, intptr_t arg, int mode)
3035*9e39c5baSBill Taylor {
3036*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
3037*9e39c5baSBill Taylor 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
3038*9e39c5baSBill Taylor 		hermon_loopback_ioctl32_t lb32;
3039*9e39c5baSBill Taylor 
3040*9e39c5baSBill Taylor 		lb32.alb_revision	= lb->alb_revision;
3041*9e39c5baSBill Taylor 		lb32.alb_send_buf	=
3042*9e39c5baSBill Taylor 		    (caddr32_t)(uintptr_t)lb->alb_send_buf;
3043*9e39c5baSBill Taylor 		lb32.alb_fail_buf	=
3044*9e39c5baSBill Taylor 		    (caddr32_t)(uintptr_t)lb->alb_fail_buf;
3045*9e39c5baSBill Taylor 		lb32.alb_buf_sz		= lb->alb_buf_sz;
3046*9e39c5baSBill Taylor 		lb32.alb_num_iter	= lb->alb_num_iter;
3047*9e39c5baSBill Taylor 		lb32.alb_pass_done	= lb->alb_pass_done;
3048*9e39c5baSBill Taylor 		lb32.alb_timeout	= lb->alb_timeout;
3049*9e39c5baSBill Taylor 		lb32.alb_error_type	= lb->alb_error_type;
3050*9e39c5baSBill Taylor 		lb32.alb_port_num	= lb->alb_port_num;
3051*9e39c5baSBill Taylor 		lb32.alb_num_retry	= lb->alb_num_retry;
3052*9e39c5baSBill Taylor 
3053*9e39c5baSBill Taylor 		if (ddi_copyout(&lb32, (void *)arg,
3054*9e39c5baSBill Taylor 		    sizeof (hermon_loopback_ioctl32_t), mode) != 0) {
3055*9e39c5baSBill Taylor 			return (EFAULT);
3056*9e39c5baSBill Taylor 		}
3057*9e39c5baSBill Taylor 	} else
3058*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
3059*9e39c5baSBill Taylor 	if (ddi_copyout(lb, (void *)arg, sizeof (hermon_loopback_ioctl_t),
3060*9e39c5baSBill Taylor 	    mode) != 0) {
3061*9e39c5baSBill Taylor 		return (EFAULT);
3062*9e39c5baSBill Taylor 	}
3063*9e39c5baSBill Taylor 	return (0);
3064*9e39c5baSBill Taylor }
3065*9e39c5baSBill Taylor 
3066*9e39c5baSBill Taylor /*
3067*9e39c5baSBill Taylor  * hermon_loopback_post_send
3068*9e39c5baSBill Taylor  */
3069*9e39c5baSBill Taylor static int
3070*9e39c5baSBill Taylor hermon_loopback_post_send(hermon_loopback_state_t *lstate,
3071*9e39c5baSBill Taylor     hermon_loopback_comm_t *tx, hermon_loopback_comm_t *rx)
3072*9e39c5baSBill Taylor {
3073*9e39c5baSBill Taylor 	int	 ret;
3074*9e39c5baSBill Taylor 
3075*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*tx))
3076*9e39c5baSBill Taylor 
3077*9e39c5baSBill Taylor 	bzero(&tx->hlc_sgl, sizeof (ibt_wr_ds_t));
3078*9e39c5baSBill Taylor 	bzero(&tx->hlc_wr, sizeof (ibt_send_wr_t));
3079*9e39c5baSBill Taylor 
3080*9e39c5baSBill Taylor 	/* Initialize local address for TX buffer */
3081*9e39c5baSBill Taylor 	tx->hlc_sgl.ds_va   = tx->hlc_mrdesc.md_vaddr;
3082*9e39c5baSBill Taylor 	tx->hlc_sgl.ds_key  = tx->hlc_mrdesc.md_lkey;
3083*9e39c5baSBill Taylor 	tx->hlc_sgl.ds_len  = tx->hlc_buf_sz;
3084*9e39c5baSBill Taylor 
3085*9e39c5baSBill Taylor 	/* Initialize the remaining details of the work request */
3086*9e39c5baSBill Taylor 	tx->hlc_wr.wr_id = tx->hlc_wrid++;
3087*9e39c5baSBill Taylor 	tx->hlc_wr.wr_flags  = IBT_WR_SEND_SIGNAL;
3088*9e39c5baSBill Taylor 	tx->hlc_wr.wr_nds    = 1;
3089*9e39c5baSBill Taylor 	tx->hlc_wr.wr_sgl    = &tx->hlc_sgl;
3090*9e39c5baSBill Taylor 	tx->hlc_wr.wr_opcode = IBT_WRC_RDMAW;
3091*9e39c5baSBill Taylor 	tx->hlc_wr.wr_trans  = IBT_RC_SRV;
3092*9e39c5baSBill Taylor 
3093*9e39c5baSBill Taylor 	/* Initialize the remote address for RX buffer */
3094*9e39c5baSBill Taylor 	tx->hlc_wr.wr.rc.rcwr.rdma.rdma_raddr = rx->hlc_mrdesc.md_vaddr;
3095*9e39c5baSBill Taylor 	tx->hlc_wr.wr.rc.rcwr.rdma.rdma_rkey  = rx->hlc_mrdesc.md_rkey;
3096*9e39c5baSBill Taylor 	tx->hlc_complete = 0;
3097*9e39c5baSBill Taylor 	ret = hermon_post_send(lstate->hls_state, tx->hlc_qp_hdl, &tx->hlc_wr,
3098*9e39c5baSBill Taylor 	    1, NULL);
3099*9e39c5baSBill Taylor 	if (ret != IBT_SUCCESS) {
3100*9e39c5baSBill Taylor 		return (EFAULT);
3101*9e39c5baSBill Taylor 	}
3102*9e39c5baSBill Taylor 	return (0);
3103*9e39c5baSBill Taylor }
3104*9e39c5baSBill Taylor 
3105*9e39c5baSBill Taylor /*
3106*9e39c5baSBill Taylor  * hermon_loopback_poll_cq
3107*9e39c5baSBill Taylor  */
3108*9e39c5baSBill Taylor static int
3109*9e39c5baSBill Taylor hermon_loopback_poll_cq(hermon_loopback_state_t *lstate,
3110*9e39c5baSBill Taylor     hermon_loopback_comm_t *comm)
3111*9e39c5baSBill Taylor {
3112*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm))
3113*9e39c5baSBill Taylor 
3114*9e39c5baSBill Taylor 	comm->hlc_wc.wc_status	= 0;
3115*9e39c5baSBill Taylor 	comm->hlc_num_polled	= 0;
3116*9e39c5baSBill Taylor 	comm->hlc_status = hermon_cq_poll(lstate->hls_state,
3117*9e39c5baSBill Taylor 	    comm->hlc_cqhdl[0], &comm->hlc_wc, 1, &comm->hlc_num_polled);
3118*9e39c5baSBill Taylor 	if ((comm->hlc_status == IBT_SUCCESS) &&
3119*9e39c5baSBill Taylor 	    (comm->hlc_wc.wc_status != IBT_WC_SUCCESS)) {
3120*9e39c5baSBill Taylor 		comm->hlc_status = ibc_get_ci_failure(0);
3121*9e39c5baSBill Taylor 	}
3122*9e39c5baSBill Taylor 	return (comm->hlc_status);
3123*9e39c5baSBill Taylor }
3124