xref: /freebsd/sys/dev/ocs_fc/ocs_ioctl.c (revision a01ff11c)
1ef270ab1SKenneth D. Merry /*-
2ef270ab1SKenneth D. Merry  * Copyright (c) 2017 Broadcom. All rights reserved.
3ef270ab1SKenneth D. Merry  * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
4ef270ab1SKenneth D. Merry  *
5ef270ab1SKenneth D. Merry  * Redistribution and use in source and binary forms, with or without
6ef270ab1SKenneth D. Merry  * modification, are permitted provided that the following conditions are met:
7ef270ab1SKenneth D. Merry  *
8ef270ab1SKenneth D. Merry  * 1. Redistributions of source code must retain the above copyright notice,
9ef270ab1SKenneth D. Merry  *    this list of conditions and the following disclaimer.
10ef270ab1SKenneth D. Merry  *
11ef270ab1SKenneth D. Merry  * 2. Redistributions in binary form must reproduce the above copyright notice,
12ef270ab1SKenneth D. Merry  *    this list of conditions and the following disclaimer in the documentation
13ef270ab1SKenneth D. Merry  *    and/or other materials provided with the distribution.
14ef270ab1SKenneth D. Merry  *
15ef270ab1SKenneth D. Merry  * 3. Neither the name of the copyright holder nor the names of its contributors
16ef270ab1SKenneth D. Merry  *    may be used to endorse or promote products derived from this software
17ef270ab1SKenneth D. Merry  *    without specific prior written permission.
18ef270ab1SKenneth D. Merry  *
19ef270ab1SKenneth D. Merry  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20ef270ab1SKenneth D. Merry  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21ef270ab1SKenneth D. Merry  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22ef270ab1SKenneth D. Merry  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23ef270ab1SKenneth D. Merry  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24ef270ab1SKenneth D. Merry  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25ef270ab1SKenneth D. Merry  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26ef270ab1SKenneth D. Merry  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27ef270ab1SKenneth D. Merry  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28ef270ab1SKenneth D. Merry  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29ef270ab1SKenneth D. Merry  * POSSIBILITY OF SUCH DAMAGE.
30ef270ab1SKenneth D. Merry  */
31ef270ab1SKenneth D. Merry 
32ef270ab1SKenneth D. Merry #include "ocs.h"
33ef270ab1SKenneth D. Merry #include "ocs_utils.h"
34ef270ab1SKenneth D. Merry 
35ef270ab1SKenneth D. Merry #include <sys/conf.h>
36ef270ab1SKenneth D. Merry #include <sys/sysctl.h>
37ef270ab1SKenneth D. Merry #include <sys/ioccom.h>
38ef270ab1SKenneth D. Merry #include <sys/param.h>
39ef270ab1SKenneth D. Merry #include <sys/systm.h>
40ef270ab1SKenneth D. Merry #include <sys/linker.h>
41ef270ab1SKenneth D. Merry #include <sys/firmware.h>
42ef270ab1SKenneth D. Merry 
43ef270ab1SKenneth D. Merry static d_open_t		ocs_open;
44ef270ab1SKenneth D. Merry static d_close_t	ocs_close;
45ef270ab1SKenneth D. Merry static d_ioctl_t	ocs_ioctl;
46ef270ab1SKenneth D. Merry 
47ef270ab1SKenneth D. Merry static struct cdevsw ocs_cdevsw = {
48ef270ab1SKenneth D. Merry 	.d_version =	D_VERSION,
49ef270ab1SKenneth D. Merry 	.d_open =	ocs_open,
50ef270ab1SKenneth D. Merry 	.d_close =	ocs_close,
51ef270ab1SKenneth D. Merry 	.d_ioctl =	ocs_ioctl,
52ef270ab1SKenneth D. Merry 	.d_name =	"ocs_fc"
53ef270ab1SKenneth D. Merry };
54ef270ab1SKenneth D. Merry 
55ef270ab1SKenneth D. Merry int
56ef270ab1SKenneth D. Merry ocs_firmware_write(ocs_t *ocs, const uint8_t *buf, size_t buf_len, uint8_t *change_status);
57ef270ab1SKenneth D. Merry 
58ef270ab1SKenneth D. Merry static int
ocs_open(struct cdev * cdev,int flags,int fmt,struct thread * td)59ef270ab1SKenneth D. Merry ocs_open(struct cdev *cdev, int flags, int fmt, struct thread *td)
60ef270ab1SKenneth D. Merry {
61ef270ab1SKenneth D. Merry 	return 0;
62ef270ab1SKenneth D. Merry }
63ef270ab1SKenneth D. Merry 
64ef270ab1SKenneth D. Merry static int
ocs_close(struct cdev * cdev,int flag,int fmt,struct thread * td)65ef270ab1SKenneth D. Merry ocs_close(struct cdev *cdev, int flag, int fmt, struct thread *td)
66ef270ab1SKenneth D. Merry {
67ef270ab1SKenneth D. Merry 	return 0;
68ef270ab1SKenneth D. Merry }
69ef270ab1SKenneth D. Merry 
70ef270ab1SKenneth D. Merry static int32_t
__ocs_ioctl_mbox_cb(ocs_hw_t * hw,int32_t status,uint8_t * mqe,void * arg)71ef270ab1SKenneth D. Merry __ocs_ioctl_mbox_cb(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void *arg)
72ef270ab1SKenneth D. Merry {
73ef270ab1SKenneth D. Merry 	struct ocs_softc *ocs = arg;
74ef270ab1SKenneth D. Merry 
75ef270ab1SKenneth D. Merry 	/* wait for the ioctl to sleep before calling wakeup */
76ef270ab1SKenneth D. Merry 	mtx_lock(&ocs->dbg_lock);
77ef270ab1SKenneth D. Merry 
78ef270ab1SKenneth D. Merry 	mtx_unlock(&ocs->dbg_lock);
79ef270ab1SKenneth D. Merry 
80ef270ab1SKenneth D. Merry 	wakeup(arg);
81ef270ab1SKenneth D. Merry 
82ef270ab1SKenneth D. Merry 	return 0;
83ef270ab1SKenneth D. Merry }
84ef270ab1SKenneth D. Merry 
85ef270ab1SKenneth D. Merry static int
ocs_process_sli_config(ocs_t * ocs,ocs_ioctl_elxu_mbox_t * mcmd,ocs_dma_t * dma)8629e2dbd4SRam Kishore Vegesna ocs_process_sli_config (ocs_t *ocs, ocs_ioctl_elxu_mbox_t *mcmd, ocs_dma_t *dma)
8729e2dbd4SRam Kishore Vegesna {
88ef270ab1SKenneth D. Merry 	sli4_cmd_sli_config_t *sli_config = (sli4_cmd_sli_config_t *)mcmd->payload;
89a01ff11cSMark Johnston 	int error;
90ef270ab1SKenneth D. Merry 
91ef270ab1SKenneth D. Merry 	if (sli_config->emb) {
92ef270ab1SKenneth D. Merry 		sli4_req_hdr_t	*req = (sli4_req_hdr_t *)sli_config->payload.embed;
93ef270ab1SKenneth D. Merry 
94ef270ab1SKenneth D. Merry 		switch (req->opcode) {
95ef270ab1SKenneth D. Merry 		case SLI4_OPC_COMMON_READ_OBJECT:
96ef270ab1SKenneth D. Merry 			if (mcmd->out_bytes) {
97ef270ab1SKenneth D. Merry 				sli4_req_common_read_object_t *rdobj =
98ef270ab1SKenneth D. Merry 					(sli4_req_common_read_object_t *)sli_config->payload.embed;
99ef270ab1SKenneth D. Merry 
100ef270ab1SKenneth D. Merry 				if (ocs_dma_alloc(ocs, dma, mcmd->out_bytes, 4096)) {
101ef270ab1SKenneth D. Merry 					device_printf(ocs->dev, "%s: COMMON_READ_OBJECT - %lld allocation failed\n",
102ef270ab1SKenneth D. Merry 							__func__, (unsigned long long)mcmd->out_bytes);
103ef270ab1SKenneth D. Merry 					return ENXIO;
104ef270ab1SKenneth D. Merry 				}
105ef270ab1SKenneth D. Merry 
106ef270ab1SKenneth D. Merry 				memset(dma->virt, 0, mcmd->out_bytes);
107ef270ab1SKenneth D. Merry 
108ef270ab1SKenneth D. Merry 				rdobj->host_buffer_descriptor[0].bde_type = SLI4_BDE_TYPE_BDE_64;
109ef270ab1SKenneth D. Merry 				rdobj->host_buffer_descriptor[0].buffer_length = mcmd->out_bytes;
110ef270ab1SKenneth D. Merry 				rdobj->host_buffer_descriptor[0].u.data.buffer_address_low = ocs_addr32_lo(dma->phys);
111ef270ab1SKenneth D. Merry 				rdobj->host_buffer_descriptor[0].u.data.buffer_address_high = ocs_addr32_hi(dma->phys);
112ef270ab1SKenneth D. Merry 			}
113ef270ab1SKenneth D. Merry 			break;
114ef270ab1SKenneth D. Merry 		case SLI4_OPC_COMMON_WRITE_OBJECT:
115ef270ab1SKenneth D. Merry 		{
116ef270ab1SKenneth D. Merry 			sli4_req_common_write_object_t *wrobj =
117ef270ab1SKenneth D. Merry 				(sli4_req_common_write_object_t *)sli_config->payload.embed;
118ef270ab1SKenneth D. Merry 
119ef270ab1SKenneth D. Merry 			if (ocs_dma_alloc(ocs, dma, wrobj->desired_write_length, 4096)) {
120ef270ab1SKenneth D. Merry 				device_printf(ocs->dev, "%s: COMMON_WRITE_OBJECT - %d allocation failed\n",
121ef270ab1SKenneth D. Merry 						__func__, wrobj->desired_write_length);
122ef270ab1SKenneth D. Merry 				return ENXIO;
123ef270ab1SKenneth D. Merry 			}
124ef270ab1SKenneth D. Merry 			/* setup the descriptor */
125ef270ab1SKenneth D. Merry 			wrobj->host_buffer_descriptor[0].bde_type = SLI4_BDE_TYPE_BDE_64;
126ef270ab1SKenneth D. Merry 			wrobj->host_buffer_descriptor[0].buffer_length = wrobj->desired_write_length;
127ef270ab1SKenneth D. Merry 			wrobj->host_buffer_descriptor[0].u.data.buffer_address_low = ocs_addr32_lo(dma->phys);
128ef270ab1SKenneth D. Merry 			wrobj->host_buffer_descriptor[0].u.data.buffer_address_high = ocs_addr32_hi(dma->phys);
129ef270ab1SKenneth D. Merry 
130ef270ab1SKenneth D. Merry 			/* copy the data into the DMA buffer */
131a01ff11cSMark Johnston 			error = copyin((void *)(uintptr_t)mcmd->in_addr, dma->virt, mcmd->in_bytes);
132a01ff11cSMark Johnston 			if (error != 0) {
133a01ff11cSMark Johnston 				device_printf(ocs->dev, "%s: COMMON_WRITE_OBJECT - copyin failed: %d\n",
134a01ff11cSMark Johnston 						__func__, error);
135a01ff11cSMark Johnston 				ocs_dma_free(ocs, dma);
136a01ff11cSMark Johnston 				return error;
137a01ff11cSMark Johnston 			}
138ef270ab1SKenneth D. Merry 		}
139ef270ab1SKenneth D. Merry 			break;
140ef270ab1SKenneth D. Merry 		case SLI4_OPC_COMMON_DELETE_OBJECT:
141ef270ab1SKenneth D. Merry 			break;
142ef270ab1SKenneth D. Merry 		case SLI4_OPC_COMMON_READ_OBJECT_LIST:
143ef270ab1SKenneth D. Merry 			if (mcmd->out_bytes) {
144ef270ab1SKenneth D. Merry 				sli4_req_common_read_object_list_t *rdobj =
145ef270ab1SKenneth D. Merry 					(sli4_req_common_read_object_list_t *)sli_config->payload.embed;
146ef270ab1SKenneth D. Merry 
147ef270ab1SKenneth D. Merry 				if (ocs_dma_alloc(ocs, dma, mcmd->out_bytes, 4096)) {
148ef270ab1SKenneth D. Merry 					device_printf(ocs->dev, "%s: COMMON_READ_OBJECT_LIST - %lld allocation failed\n",
149ef270ab1SKenneth D. Merry 							__func__,(unsigned long long) mcmd->out_bytes);
150ef270ab1SKenneth D. Merry 					return ENXIO;
151ef270ab1SKenneth D. Merry 				}
152ef270ab1SKenneth D. Merry 
153ef270ab1SKenneth D. Merry 				memset(dma->virt, 0, mcmd->out_bytes);
154ef270ab1SKenneth D. Merry 
155ef270ab1SKenneth D. Merry 				rdobj->host_buffer_descriptor[0].bde_type = SLI4_BDE_TYPE_BDE_64;
156ef270ab1SKenneth D. Merry 				rdobj->host_buffer_descriptor[0].buffer_length = mcmd->out_bytes;
157ef270ab1SKenneth D. Merry 				rdobj->host_buffer_descriptor[0].u.data.buffer_address_low = ocs_addr32_lo(dma->phys);
158ef270ab1SKenneth D. Merry 				rdobj->host_buffer_descriptor[0].u.data.buffer_address_high = ocs_addr32_hi(dma->phys);
159ef270ab1SKenneth D. Merry 			}
160ef270ab1SKenneth D. Merry 			break;
161ef270ab1SKenneth D. Merry 		case SLI4_OPC_COMMON_READ_TRANSCEIVER_DATA:
162ef270ab1SKenneth D. Merry 			break;
163ef270ab1SKenneth D. Merry 		default:
164ef270ab1SKenneth D. Merry 			device_printf(ocs->dev, "%s: in=%p (%lld) out=%p (%lld)\n", __func__,
165bc5ea07cSDimitry Andric 					(void *)(uintptr_t)mcmd->in_addr, (unsigned long long)mcmd->in_bytes,
166bc5ea07cSDimitry Andric 					(void *)(uintptr_t)mcmd->out_addr, (unsigned long long)mcmd->out_bytes);
167ef270ab1SKenneth D. Merry 			device_printf(ocs->dev, "%s: unknown (opc=%#x)\n", __func__,
168ef270ab1SKenneth D. Merry 					req->opcode);
169ef270ab1SKenneth D. Merry 			hexdump(mcmd, mcmd->size, NULL, 0);
170ef270ab1SKenneth D. Merry 			break;
171ef270ab1SKenneth D. Merry 		}
172ef270ab1SKenneth D. Merry 	} else {
173ef270ab1SKenneth D. Merry 		uint32_t max_bytes = max(mcmd->in_bytes, mcmd->out_bytes);
174ef270ab1SKenneth D. Merry 		if (ocs_dma_alloc(ocs, dma, max_bytes, 4096)) {
175ef270ab1SKenneth D. Merry 			device_printf(ocs->dev, "%s: non-embedded - %u allocation failed\n",
176ef270ab1SKenneth D. Merry 					__func__, max_bytes);
177ef270ab1SKenneth D. Merry 			return ENXIO;
178ef270ab1SKenneth D. Merry 		}
179ef270ab1SKenneth D. Merry 
180a01ff11cSMark Johnston 		error = copyin((void *)(uintptr_t)mcmd->in_addr, dma->virt, mcmd->in_bytes);
181a01ff11cSMark Johnston 		if (error != 0) {
182a01ff11cSMark Johnston 			device_printf(ocs->dev, "%s: non-embedded - copyin failed: %d\n",
183a01ff11cSMark Johnston 					__func__, error);
184a01ff11cSMark Johnston 			ocs_dma_free(ocs, dma);
185a01ff11cSMark Johnston 			return error;
186a01ff11cSMark Johnston 		}
187ef270ab1SKenneth D. Merry 
188ef270ab1SKenneth D. Merry 		sli_config->payload.mem.address_low  = ocs_addr32_lo(dma->phys);
189ef270ab1SKenneth D. Merry 		sli_config->payload.mem.address_high = ocs_addr32_hi(dma->phys);
190ef270ab1SKenneth D. Merry 		sli_config->payload.mem.length       = max_bytes;
191ef270ab1SKenneth D. Merry 	}
192ef270ab1SKenneth D. Merry 
193ef270ab1SKenneth D. Merry 	return 0;
194ef270ab1SKenneth D. Merry }
195ef270ab1SKenneth D. Merry 
196ef270ab1SKenneth D. Merry static int
ocs_process_mbx_ioctl(ocs_t * ocs,ocs_ioctl_elxu_mbox_t * mcmd)197ef270ab1SKenneth D. Merry ocs_process_mbx_ioctl(ocs_t *ocs, ocs_ioctl_elxu_mbox_t *mcmd)
198ef270ab1SKenneth D. Merry {
199ef270ab1SKenneth D. Merry 	ocs_dma_t	dma = { 0 };
200a01ff11cSMark Johnston 	int error;
201a01ff11cSMark Johnston 
202a01ff11cSMark Johnston 	error = 0;
203ef270ab1SKenneth D. Merry 
204ef270ab1SKenneth D. Merry 	if ((ELXU_BSD_MAGIC != mcmd->magic) ||
205ef270ab1SKenneth D. Merry 			(sizeof(ocs_ioctl_elxu_mbox_t) != mcmd->size)) {
206ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "%s: malformed command m=%08x s=%08x\n",
207ef270ab1SKenneth D. Merry 				__func__, mcmd->magic, mcmd->size);
208ef270ab1SKenneth D. Merry 		return EINVAL;
209ef270ab1SKenneth D. Merry 	}
210ef270ab1SKenneth D. Merry 
211ef270ab1SKenneth D. Merry 	switch(((sli4_mbox_command_header_t *)mcmd->payload)->command) {
212ef270ab1SKenneth D. Merry 	case SLI4_MBOX_COMMAND_SLI_CONFIG:
213ef270ab1SKenneth D. Merry 		if (ENXIO == ocs_process_sli_config(ocs, mcmd, &dma))
214ef270ab1SKenneth D. Merry 			return ENXIO;
215ef270ab1SKenneth D. Merry 		break;
216ef270ab1SKenneth D. Merry 
217ef270ab1SKenneth D. Merry 	case SLI4_MBOX_COMMAND_READ_REV:
218ef270ab1SKenneth D. Merry 	case SLI4_MBOX_COMMAND_READ_STATUS:
219ef270ab1SKenneth D. Merry 	case SLI4_MBOX_COMMAND_READ_LNK_STAT:
220ef270ab1SKenneth D. Merry 		break;
221ef270ab1SKenneth D. Merry 
222ef270ab1SKenneth D. Merry 	default:
223ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "command %d\n",((sli4_mbox_command_header_t *)mcmd->payload)->command);
224ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "%s, command not support\n", __func__);
225ef270ab1SKenneth D. Merry 		goto no_support;
226ef270ab1SKenneth D. Merry 		break;
227ef270ab1SKenneth D. Merry 	}
228ef270ab1SKenneth D. Merry 
229ef270ab1SKenneth D. Merry 	/*
230ef270ab1SKenneth D. Merry 	 * The dbg_lock usage here insures the command completion code
231ef270ab1SKenneth D. Merry 	 * (__ocs_ioctl_mbox_cb), which calls wakeup(), does not run until
232ef270ab1SKenneth D. Merry 	 * after first calling msleep()
233ef270ab1SKenneth D. Merry 	 *
234ef270ab1SKenneth D. Merry 	 *  1. ioctl grabs dbg_lock
235ef270ab1SKenneth D. Merry 	 *  2. ioctl issues command
236ef270ab1SKenneth D. Merry 	 *       if the command completes before msleep(), the
237ef270ab1SKenneth D. Merry 	 *       command completion code (__ocs_ioctl_mbox_cb) will spin
238ef270ab1SKenneth D. Merry 	 *       on dbg_lock before calling wakeup()
239ef270ab1SKenneth D. Merry 	 *  3. ioctl calls msleep which releases dbg_lock before sleeping
240ef270ab1SKenneth D. Merry 	 *     and reacquires it before waking
241ef270ab1SKenneth D. Merry 	 *  4. command completion handler acquires the dbg_lock, immediately
242ef270ab1SKenneth D. Merry 	 *     releases it, and calls wakeup
243ef270ab1SKenneth D. Merry 	 *  5. msleep returns, re-acquiring the lock
244ef270ab1SKenneth D. Merry 	 *  6. ioctl code releases the lock
245ef270ab1SKenneth D. Merry 	 */
246ef270ab1SKenneth D. Merry 	mtx_lock(&ocs->dbg_lock);
2474915e5c7SRam Kishore Vegesna 	if (ocs_hw_command(&ocs->hw, mcmd->payload, OCS_CMD_NOWAIT,
2484915e5c7SRam Kishore Vegesna 			__ocs_ioctl_mbox_cb, ocs)) {
2494915e5c7SRam Kishore Vegesna 		device_printf(ocs->dev, "%s: command- %x failed\n", __func__,
2504915e5c7SRam Kishore Vegesna 			((sli4_mbox_command_header_t *)mcmd->payload)->command);
2514915e5c7SRam Kishore Vegesna 	}
252ef270ab1SKenneth D. Merry 	msleep(ocs, &ocs->dbg_lock, 0, "ocsmbx", 0);
253ef270ab1SKenneth D. Merry 	mtx_unlock(&ocs->dbg_lock);
254ef270ab1SKenneth D. Merry 
255ef270ab1SKenneth D. Merry 	if( SLI4_MBOX_COMMAND_SLI_CONFIG == ((sli4_mbox_command_header_t *)mcmd->payload)->command
256ef270ab1SKenneth D. Merry 	  		&& mcmd->out_bytes && dma.virt) {
257a01ff11cSMark Johnston 		error = copyout(dma.virt, (void *)(uintptr_t)mcmd->out_addr, mcmd->out_bytes);
258ef270ab1SKenneth D. Merry 	}
259ef270ab1SKenneth D. Merry 
260ef270ab1SKenneth D. Merry no_support:
261ef270ab1SKenneth D. Merry 	ocs_dma_free(ocs, &dma);
262ef270ab1SKenneth D. Merry 
263a01ff11cSMark Johnston 	return error;
264ef270ab1SKenneth D. Merry }
265ef270ab1SKenneth D. Merry 
266ef270ab1SKenneth D. Merry /**
267ef270ab1SKenneth D. Merry  * @brief perform requested Elx CoreDump helper function
268ef270ab1SKenneth D. Merry  *
269ef270ab1SKenneth D. Merry  * The Elx CoreDump facility used for BE3 diagnostics uses the OCS_IOCTL_CMD_ECD_HELPER
270ef270ab1SKenneth D. Merry  * ioctl function to execute requested "help" functions
271ef270ab1SKenneth D. Merry  *
272ef270ab1SKenneth D. Merry  * @param ocs pointer to ocs structure
273ef270ab1SKenneth D. Merry  * @param req pointer to helper function request
274ef270ab1SKenneth D. Merry  *
275ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
276ef270ab1SKenneth D. Merry  */
277ef270ab1SKenneth D. Merry 
278ef270ab1SKenneth D. Merry static int
ocs_process_ecd_helper(ocs_t * ocs,ocs_ioctl_ecd_helper_t * req)279ef270ab1SKenneth D. Merry ocs_process_ecd_helper (ocs_t *ocs, ocs_ioctl_ecd_helper_t *req)
280ef270ab1SKenneth D. Merry {
281ef270ab1SKenneth D. Merry 	int32_t rc = 0;
282ef270ab1SKenneth D. Merry 	uint8_t v8;
283ef270ab1SKenneth D. Merry 	uint16_t v16;
284ef270ab1SKenneth D. Merry 	uint32_t v32;
285ef270ab1SKenneth D. Merry 
286ef270ab1SKenneth D. Merry 	/* Check the BAR read/write commands for valid bar */
287ef270ab1SKenneth D. Merry 	switch(req->cmd) {
288ef270ab1SKenneth D. Merry 	case OCS_ECD_HELPER_BAR_READ8:
289ef270ab1SKenneth D. Merry 	case OCS_ECD_HELPER_BAR_READ16:
290ef270ab1SKenneth D. Merry 	case OCS_ECD_HELPER_BAR_READ32:
291ef270ab1SKenneth D. Merry 	case OCS_ECD_HELPER_BAR_WRITE8:
292ef270ab1SKenneth D. Merry 	case OCS_ECD_HELPER_BAR_WRITE16:
293ef270ab1SKenneth D. Merry 	case OCS_ECD_HELPER_BAR_WRITE32:
294ef270ab1SKenneth D. Merry 		if (req->bar >= PCI_MAX_BAR) {
295ef270ab1SKenneth D. Merry 			device_printf(ocs->dev, "Error: bar %d out of range\n", req->bar);
296ef270ab1SKenneth D. Merry 			return -EFAULT;
297ef270ab1SKenneth D. Merry 		}
298ef270ab1SKenneth D. Merry 		if (ocs->reg[req->bar].res == NULL) {
299ef270ab1SKenneth D. Merry 			device_printf(ocs->dev, "Error: bar %d not defined\n", req->bar);
300ef270ab1SKenneth D. Merry 			return -EFAULT;
301ef270ab1SKenneth D. Merry 		}
302ef270ab1SKenneth D. Merry 		break;
303ef270ab1SKenneth D. Merry 	default:
304ef270ab1SKenneth D. Merry 		break;
305ef270ab1SKenneth D. Merry 	}
306ef270ab1SKenneth D. Merry 
307ef270ab1SKenneth D. Merry 	switch(req->cmd) {
308ef270ab1SKenneth D. Merry 	case OCS_ECD_HELPER_CFG_READ8:
309ef270ab1SKenneth D. Merry 		v8 = ocs_config_read8(ocs, req->offset);
310ef270ab1SKenneth D. Merry 		req->data = v8;
311ef270ab1SKenneth D. Merry 		break;
312ef270ab1SKenneth D. Merry 	case OCS_ECD_HELPER_CFG_READ16:
313ef270ab1SKenneth D. Merry 		v16 = ocs_config_read16(ocs, req->offset);
314ef270ab1SKenneth D. Merry 		req->data = v16;
315ef270ab1SKenneth D. Merry 		break;
316ef270ab1SKenneth D. Merry 	case OCS_ECD_HELPER_CFG_READ32:
317ef270ab1SKenneth D. Merry 		v32 = ocs_config_read32(ocs, req->offset);
318ef270ab1SKenneth D. Merry 		req->data = v32;
319ef270ab1SKenneth D. Merry 		break;
320ef270ab1SKenneth D. Merry 	case OCS_ECD_HELPER_CFG_WRITE8:
321ef270ab1SKenneth D. Merry 		ocs_config_write8(ocs, req->offset, req->data);
322ef270ab1SKenneth D. Merry 		break;
323ef270ab1SKenneth D. Merry 	case OCS_ECD_HELPER_CFG_WRITE16:
324ef270ab1SKenneth D. Merry 		ocs_config_write16(ocs, req->offset, req->data);
325ef270ab1SKenneth D. Merry 		break;
326ef270ab1SKenneth D. Merry 	case OCS_ECD_HELPER_CFG_WRITE32:
327ef270ab1SKenneth D. Merry 		ocs_config_write32(ocs, req->offset, req->data);
328ef270ab1SKenneth D. Merry 		break;
329ef270ab1SKenneth D. Merry 	case OCS_ECD_HELPER_BAR_READ8:
330ef270ab1SKenneth D. Merry 		req->data = ocs_reg_read8(ocs, req->bar, req->offset);
331ef270ab1SKenneth D. Merry 		break;
332ef270ab1SKenneth D. Merry 	case OCS_ECD_HELPER_BAR_READ16:
333ef270ab1SKenneth D. Merry 		req->data = ocs_reg_read16(ocs, req->bar, req->offset);
334ef270ab1SKenneth D. Merry 		break;
335ef270ab1SKenneth D. Merry 	case OCS_ECD_HELPER_BAR_READ32:
336ef270ab1SKenneth D. Merry 		req->data = ocs_reg_read32(ocs, req->bar, req->offset);
337ef270ab1SKenneth D. Merry 		break;
338ef270ab1SKenneth D. Merry 	case OCS_ECD_HELPER_BAR_WRITE8:
339ef270ab1SKenneth D. Merry 		ocs_reg_write8(ocs, req->bar, req->offset, req->data);
340ef270ab1SKenneth D. Merry 		break;
341ef270ab1SKenneth D. Merry 	case OCS_ECD_HELPER_BAR_WRITE16:
342ef270ab1SKenneth D. Merry 		ocs_reg_write16(ocs, req->bar, req->offset, req->data);
343ef270ab1SKenneth D. Merry 		break;
344ef270ab1SKenneth D. Merry 	case OCS_ECD_HELPER_BAR_WRITE32:
345ef270ab1SKenneth D. Merry 		ocs_reg_write32(ocs, req->bar, req->offset, req->data);
346ef270ab1SKenneth D. Merry 		break;
347ef270ab1SKenneth D. Merry 	default:
348ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "Invalid helper command=%d\n", req->cmd);
349ef270ab1SKenneth D. Merry 		break;
350ef270ab1SKenneth D. Merry 	}
351ef270ab1SKenneth D. Merry 
352ef270ab1SKenneth D. Merry 	return rc;
353ef270ab1SKenneth D. Merry }
354ef270ab1SKenneth D. Merry 
355ef270ab1SKenneth D. Merry static int
ocs_ioctl(struct cdev * cdev,u_long cmd,caddr_t addr,int flag,struct thread * td)356ef270ab1SKenneth D. Merry ocs_ioctl(struct cdev *cdev, u_long cmd, caddr_t addr, int flag, struct thread *td)
357ef270ab1SKenneth D. Merry {
358ef270ab1SKenneth D. Merry 	int status = 0;
359ef270ab1SKenneth D. Merry 	struct ocs_softc *ocs = cdev->si_drv1;
360ef270ab1SKenneth D. Merry 	device_t dev = ocs->dev;
361ef270ab1SKenneth D. Merry 
362ef270ab1SKenneth D. Merry 	switch (cmd) {
363ef270ab1SKenneth D. Merry 	case OCS_IOCTL_CMD_ELXU_MBOX: {
364ef270ab1SKenneth D. Merry 		/* "copyin" done by kernel; thus, just dereference addr */
365ef270ab1SKenneth D. Merry 		ocs_ioctl_elxu_mbox_t *mcmd = (void *)addr;
366ef270ab1SKenneth D. Merry 		status = ocs_process_mbx_ioctl(ocs, mcmd);
367ef270ab1SKenneth D. Merry 		break;
368ef270ab1SKenneth D. Merry 	}
369ef270ab1SKenneth D. Merry 	case OCS_IOCTL_CMD_ECD_HELPER: {
370ef270ab1SKenneth D. Merry 		/* "copyin" done by kernel; thus, just dereference addr */
371ef270ab1SKenneth D. Merry 		ocs_ioctl_ecd_helper_t *req = (void *)addr;
372ef270ab1SKenneth D. Merry 		status = ocs_process_ecd_helper(ocs, req);
373ef270ab1SKenneth D. Merry 		break;
374ef270ab1SKenneth D. Merry 	}
375ef270ab1SKenneth D. Merry 
376ef270ab1SKenneth D. Merry 	case OCS_IOCTL_CMD_VPORT: {
377ef270ab1SKenneth D. Merry 		int32_t rc = 0;
378ef270ab1SKenneth D. Merry 		ocs_ioctl_vport_t *req = (ocs_ioctl_vport_t*) addr;
379ef270ab1SKenneth D. Merry 		ocs_domain_t *domain;
380ef270ab1SKenneth D. Merry 
381ef270ab1SKenneth D. Merry 		domain = ocs_domain_get_instance(ocs, req->domain_index);
382ef270ab1SKenneth D. Merry 		if (domain == NULL) {
383ef270ab1SKenneth D. Merry 			device_printf(ocs->dev, "domain [%d] nod found\n",
384ef270ab1SKenneth D. Merry 							req->domain_index);
385ef270ab1SKenneth D. Merry 			return -EFAULT;
386ef270ab1SKenneth D. Merry 		}
387ef270ab1SKenneth D. Merry 
388ef270ab1SKenneth D. Merry 		if (req->req_create) {
389ef270ab1SKenneth D. Merry 			rc = ocs_sport_vport_new(domain, req->wwpn, req->wwnn,
390ef270ab1SKenneth D. Merry 						UINT32_MAX, req->enable_ini,
391ef270ab1SKenneth D. Merry 					req->enable_tgt, NULL, NULL, TRUE);
392ef270ab1SKenneth D. Merry 		} else {
393ef270ab1SKenneth D. Merry 			rc = ocs_sport_vport_del(ocs, domain, req->wwpn, req->wwnn);
394ef270ab1SKenneth D. Merry 		}
395ef270ab1SKenneth D. Merry 
396ef270ab1SKenneth D. Merry 		return rc;
397ef270ab1SKenneth D. Merry 	}
398ef270ab1SKenneth D. Merry 
399ef270ab1SKenneth D. Merry 	case OCS_IOCTL_CMD_GET_DDUMP: {
400ef270ab1SKenneth D. Merry 		ocs_ioctl_ddump_t *req = (ocs_ioctl_ddump_t*) addr;
401ef270ab1SKenneth D. Merry 		ocs_textbuf_t textbuf;
402ef270ab1SKenneth D. Merry 		int x;
403ef270ab1SKenneth D. Merry 
404ef270ab1SKenneth D. Merry 		/* Build a text buffer */
405ef270ab1SKenneth D. Merry 		if (ocs_textbuf_alloc(ocs, &textbuf, req->user_buffer_len)) {
406ef270ab1SKenneth D. Merry 			device_printf(ocs->dev, "Error: ocs_textbuf_alloc failed\n");
407ef270ab1SKenneth D. Merry 			return -EFAULT;
408ef270ab1SKenneth D. Merry 		}
409ef270ab1SKenneth D. Merry 
410ef270ab1SKenneth D. Merry 		switch (req->args.action) {
411ef270ab1SKenneth D. Merry 		case OCS_IOCTL_DDUMP_GET:
412ef270ab1SKenneth D. Merry 		case OCS_IOCTL_DDUMP_GET_SAVED: {
413ef270ab1SKenneth D. Merry 			uint32_t remaining;
414ef270ab1SKenneth D. Merry 			uint32_t written;
415ef270ab1SKenneth D. Merry 			uint32_t idx;
416ef270ab1SKenneth D. Merry 			int32_t n;
417ef270ab1SKenneth D. Merry 			ocs_textbuf_t *ptbuf = NULL;
418ef270ab1SKenneth D. Merry 			uint32_t flags = 0;
419ef270ab1SKenneth D. Merry 
420ef270ab1SKenneth D. Merry 			if (req->args.action == OCS_IOCTL_DDUMP_GET_SAVED) {
421ef270ab1SKenneth D. Merry 				if (ocs_textbuf_initialized(&ocs->ddump_saved)) {
422ef270ab1SKenneth D. Merry 					ptbuf = &ocs->ddump_saved;
423ef270ab1SKenneth D. Merry 				}
424ef270ab1SKenneth D. Merry 			} else {
425ef270ab1SKenneth D. Merry 				if (ocs_textbuf_alloc(ocs, &textbuf, req->user_buffer_len)) {
426ef270ab1SKenneth D. Merry 					ocs_log_err(ocs, "Error: ocs_textbuf_alloc failed\n");
427ef270ab1SKenneth D. Merry 					return -EFAULT;
428ef270ab1SKenneth D. Merry 				}
429ef270ab1SKenneth D. Merry 
430ef270ab1SKenneth D. Merry 				/* translate IOCTL ddump flags to ddump flags */
431ef270ab1SKenneth D. Merry 				if (req->args.flags & OCS_IOCTL_DDUMP_FLAGS_WQES) {
432ef270ab1SKenneth D. Merry 					flags |= OCS_DDUMP_FLAGS_WQES;
433ef270ab1SKenneth D. Merry 				}
434ef270ab1SKenneth D. Merry 				if (req->args.flags & OCS_IOCTL_DDUMP_FLAGS_CQES) {
435ef270ab1SKenneth D. Merry 					flags |= OCS_DDUMP_FLAGS_CQES;
436ef270ab1SKenneth D. Merry 				}
437ef270ab1SKenneth D. Merry 				if (req->args.flags & OCS_IOCTL_DDUMP_FLAGS_MQES) {
438ef270ab1SKenneth D. Merry 					flags |= OCS_DDUMP_FLAGS_MQES;
439ef270ab1SKenneth D. Merry 				}
440ef270ab1SKenneth D. Merry 				if (req->args.flags & OCS_IOCTL_DDUMP_FLAGS_RQES) {
441ef270ab1SKenneth D. Merry 					flags |= OCS_DDUMP_FLAGS_RQES;
442ef270ab1SKenneth D. Merry 				}
443ef270ab1SKenneth D. Merry 				if (req->args.flags & OCS_IOCTL_DDUMP_FLAGS_EQES) {
444ef270ab1SKenneth D. Merry 					flags |= OCS_DDUMP_FLAGS_EQES;
445ef270ab1SKenneth D. Merry 				}
446ef270ab1SKenneth D. Merry 
447ef270ab1SKenneth D. Merry 				/* Try 3 times to get the dump */
448ef270ab1SKenneth D. Merry 				for(x=0; x<3; x++) {
449ef270ab1SKenneth D. Merry 					if (ocs_ddump(ocs, &textbuf, flags, req->args.q_entries) != 0) {
450ef270ab1SKenneth D. Merry 						ocs_textbuf_reset(&textbuf);
451ef270ab1SKenneth D. Merry 					} else {
452ef270ab1SKenneth D. Merry 						/* Success */
453ef270ab1SKenneth D. Merry 						x = 0;
454ef270ab1SKenneth D. Merry 						break;
455ef270ab1SKenneth D. Merry 					}
456ef270ab1SKenneth D. Merry 				}
457ef270ab1SKenneth D. Merry 				if (x != 0 ) {
458ef270ab1SKenneth D. Merry 					/* Retries failed */
459ef270ab1SKenneth D. Merry 					ocs_log_test(ocs, "ocs_ddump failed\n");
460ef270ab1SKenneth D. Merry 				} else {
461ef270ab1SKenneth D. Merry 					ptbuf = &textbuf;
462ef270ab1SKenneth D. Merry 				}
463ef270ab1SKenneth D. Merry 			}
464ef270ab1SKenneth D. Merry 			written = 0;
465ef270ab1SKenneth D. Merry 			if (ptbuf != NULL) {
466ef270ab1SKenneth D. Merry 				/* Process each textbuf segment */
467ef270ab1SKenneth D. Merry 				remaining = req->user_buffer_len;
468ef270ab1SKenneth D. Merry 				for (idx = 0; remaining; idx++) {
469ef270ab1SKenneth D. Merry 					n = ocs_textbuf_ext_get_written(ptbuf, idx);
470ef270ab1SKenneth D. Merry 					if (n < 0) {
471ef270ab1SKenneth D. Merry 						break;
472ef270ab1SKenneth D. Merry 					}
473ef270ab1SKenneth D. Merry 					if ((uint32_t)n >= remaining) {
474ef270ab1SKenneth D. Merry 						n = (int32_t)remaining;
475ef270ab1SKenneth D. Merry 					}
476ef270ab1SKenneth D. Merry 					if (ocs_copy_to_user(req->user_buffer + written,
477ef270ab1SKenneth D. Merry 						ocs_textbuf_ext_get_buffer(ptbuf, idx), n)) {
478ef270ab1SKenneth D. Merry 						ocs_log_test(ocs, "Error: (%d) ocs_copy_to_user failed\n", __LINE__);
479ef270ab1SKenneth D. Merry 					}
480ef270ab1SKenneth D. Merry 					written += n;
481ef270ab1SKenneth D. Merry 					remaining -= (uint32_t)n;
482ef270ab1SKenneth D. Merry 				}
483ef270ab1SKenneth D. Merry 			}
484ef270ab1SKenneth D. Merry 			req->bytes_written = written;
485ef270ab1SKenneth D. Merry 			if (ptbuf == &textbuf) {
486ef270ab1SKenneth D. Merry 				ocs_textbuf_free(ocs, &textbuf);
487ef270ab1SKenneth D. Merry 			}
488ef270ab1SKenneth D. Merry 
489ef270ab1SKenneth D. Merry 			break;
490ef270ab1SKenneth D. Merry 		}
491ef270ab1SKenneth D. Merry 		case OCS_IOCTL_DDUMP_CLR_SAVED:
492ef270ab1SKenneth D. Merry 			ocs_clear_saved_ddump(ocs);
493ef270ab1SKenneth D. Merry 			break;
494ef270ab1SKenneth D. Merry 		default:
495ef270ab1SKenneth D. Merry 			ocs_log_err(ocs, "Error: ocs_textbuf_alloc failed\n");
496ef270ab1SKenneth D. Merry 			break;
497ef270ab1SKenneth D. Merry 		}
498ef270ab1SKenneth D. Merry 		break;
499ef270ab1SKenneth D. Merry 	}
500ef270ab1SKenneth D. Merry 	case OCS_IOCTL_CMD_DRIVER_INFO: {
501ef270ab1SKenneth D. Merry 		ocs_ioctl_driver_info_t *req = (ocs_ioctl_driver_info_t*)addr;
502ef270ab1SKenneth D. Merry 
503ef270ab1SKenneth D. Merry 		ocs_memset(req, 0, sizeof(*req));
504ef270ab1SKenneth D. Merry 
505ef270ab1SKenneth D. Merry 		req->pci_vendor = ocs->pci_vendor;
506ef270ab1SKenneth D. Merry 		req->pci_device = ocs->pci_device;
507ef270ab1SKenneth D. Merry 		ocs_strncpy(req->businfo, ocs->businfo, sizeof(req->businfo));
508ef270ab1SKenneth D. Merry 
509ef270ab1SKenneth D. Merry 		req->sli_intf = ocs_config_read32(ocs, SLI4_INTF_REG);
510ef270ab1SKenneth D. Merry 		ocs_strncpy(req->desc, device_get_desc(dev), sizeof(req->desc));
511ef270ab1SKenneth D. Merry 		ocs_strncpy(req->fw_rev, ocs->fwrev, sizeof(req->fw_rev));
512ef270ab1SKenneth D. Merry 		if (ocs->domain && ocs->domain->sport) {
513ef270ab1SKenneth D. Merry 			*((uint64_t*)req->hw_addr.fc.wwnn) = ocs_htobe64(ocs->domain->sport->wwnn);
514ef270ab1SKenneth D. Merry 			*((uint64_t*)req->hw_addr.fc.wwpn) = ocs_htobe64(ocs->domain->sport->wwpn);
515ef270ab1SKenneth D. Merry 		}
516ef270ab1SKenneth D. Merry 		ocs_strncpy(req->serialnum, ocs->serialnum, sizeof(req->serialnum));
517ef270ab1SKenneth D. Merry 		break;
518ef270ab1SKenneth D. Merry 	}
519ef270ab1SKenneth D. Merry 
520ef270ab1SKenneth D. Merry 	case OCS_IOCTL_CMD_MGMT_LIST: {
521ef270ab1SKenneth D. Merry 		ocs_ioctl_mgmt_buffer_t* req = (ocs_ioctl_mgmt_buffer_t *)addr;
522ef270ab1SKenneth D. Merry 		ocs_textbuf_t textbuf;
523ef270ab1SKenneth D. Merry 
524ef270ab1SKenneth D. Merry 		/* Build a text buffer */
525ef270ab1SKenneth D. Merry 		if (ocs_textbuf_alloc(ocs, &textbuf, req->user_buffer_len)) {
526ef270ab1SKenneth D. Merry 			ocs_log_err(ocs, "Error: ocs_textbuf_alloc failed\n");
527ef270ab1SKenneth D. Merry 			return -EFAULT;
528ef270ab1SKenneth D. Merry 		}
529ef270ab1SKenneth D. Merry 
530ef270ab1SKenneth D. Merry 		ocs_mgmt_get_list(ocs, &textbuf);
531ef270ab1SKenneth D. Merry 
532ef270ab1SKenneth D. Merry 		if (ocs_textbuf_get_written(&textbuf)) {
533ef270ab1SKenneth D. Merry 			if (ocs_copy_to_user(req->user_buffer,
534ef270ab1SKenneth D. Merry 				ocs_textbuf_get_buffer(&textbuf),
535ef270ab1SKenneth D. Merry 				ocs_textbuf_get_written(&textbuf))) {
536ef270ab1SKenneth D. Merry 				ocs_log_test(ocs, "Error: (%d) ocs_copy_to_user failed\n", __LINE__);
537ef270ab1SKenneth D. Merry 			}
538ef270ab1SKenneth D. Merry 		}
539ef270ab1SKenneth D. Merry 		req->bytes_written = ocs_textbuf_get_written(&textbuf);
540ef270ab1SKenneth D. Merry 
541ef270ab1SKenneth D. Merry 		ocs_textbuf_free(ocs, &textbuf);
542ef270ab1SKenneth D. Merry 
543ef270ab1SKenneth D. Merry 		break;
544ef270ab1SKenneth D. Merry 	}
545ef270ab1SKenneth D. Merry 
546ef270ab1SKenneth D. Merry 	case OCS_IOCTL_CMD_MGMT_GET_ALL: {
547ef270ab1SKenneth D. Merry 		ocs_ioctl_mgmt_buffer_t* req = (ocs_ioctl_mgmt_buffer_t *)addr;
548ef270ab1SKenneth D. Merry 		ocs_textbuf_t textbuf;
549ef270ab1SKenneth D. Merry 		int32_t n;
550ef270ab1SKenneth D. Merry 		uint32_t idx;
551ef270ab1SKenneth D. Merry 		uint32_t copied = 0;
552ef270ab1SKenneth D. Merry 
553ef270ab1SKenneth D. Merry 		/* Build a text buffer */
554ef270ab1SKenneth D. Merry 		if (ocs_textbuf_alloc(ocs, &textbuf, req->user_buffer_len)) {
555ef270ab1SKenneth D. Merry 			ocs_log_err(ocs, "Error: ocs_textbuf_alloc failed\n");
556ef270ab1SKenneth D. Merry 			return -EFAULT;
557ef270ab1SKenneth D. Merry 		}
558ef270ab1SKenneth D. Merry 
559ef270ab1SKenneth D. Merry 		ocs_mgmt_get_all(ocs, &textbuf);
560ef270ab1SKenneth D. Merry 
561ef270ab1SKenneth D. Merry 		for (idx = 0; (n = ocs_textbuf_ext_get_written(&textbuf, idx)) > 0; idx++) {
562ef270ab1SKenneth D. Merry 			if(ocs_copy_to_user(req->user_buffer + copied,
563ef270ab1SKenneth D. Merry 					ocs_textbuf_ext_get_buffer(&textbuf, idx),
564ef270ab1SKenneth D. Merry 					ocs_textbuf_ext_get_written(&textbuf, idx))) {
565ef270ab1SKenneth D. Merry 					ocs_log_err(ocs, "Error: ocs_textbuf_alloc failed\n");
566ef270ab1SKenneth D. Merry 			}
567ef270ab1SKenneth D. Merry 			copied += n;
568ef270ab1SKenneth D. Merry 		}
569ef270ab1SKenneth D. Merry 		req->bytes_written = copied;
570ef270ab1SKenneth D. Merry 
571ef270ab1SKenneth D. Merry 		ocs_textbuf_free(ocs, &textbuf);
572ef270ab1SKenneth D. Merry 
573ef270ab1SKenneth D. Merry 		break;
574ef270ab1SKenneth D. Merry 	}
575ef270ab1SKenneth D. Merry 
576ef270ab1SKenneth D. Merry 	case OCS_IOCTL_CMD_MGMT_GET: {
577ef270ab1SKenneth D. Merry 		ocs_ioctl_cmd_get_t* req = (ocs_ioctl_cmd_get_t*)addr;
578ef270ab1SKenneth D. Merry 		ocs_textbuf_t textbuf;
579ef270ab1SKenneth D. Merry 		char name[OCS_MGMT_MAX_NAME];
580ef270ab1SKenneth D. Merry 
581ef270ab1SKenneth D. Merry 		/* Copy the name value in from user space */
582ef270ab1SKenneth D. Merry 		if (ocs_copy_from_user(name, req->name, OCS_MGMT_MAX_NAME)) {
583ef270ab1SKenneth D. Merry 			ocs_log_test(ocs, "ocs_copy_from_user failed\n");
584ef270ab1SKenneth D. Merry 			ocs_ioctl_free(ocs, req, sizeof(ocs_ioctl_cmd_get_t));
585ef270ab1SKenneth D. Merry 			return -EFAULT;
586ef270ab1SKenneth D. Merry 		}
587ef270ab1SKenneth D. Merry 
588ef270ab1SKenneth D. Merry 		/* Build a text buffer */
589ef270ab1SKenneth D. Merry 		if (ocs_textbuf_alloc(ocs, &textbuf, req->value_length)) {
590ef270ab1SKenneth D. Merry 			ocs_log_err(ocs, "Error: ocs_textbuf_alloc failed\n");
591ef270ab1SKenneth D. Merry 			return -EFAULT;
592ef270ab1SKenneth D. Merry 		}
593ef270ab1SKenneth D. Merry 
594ef270ab1SKenneth D. Merry 		ocs_mgmt_get(ocs, name, &textbuf);
595ef270ab1SKenneth D. Merry 
596ef270ab1SKenneth D. Merry 		if (ocs_textbuf_get_written(&textbuf)) {
597ef270ab1SKenneth D. Merry 			if (ocs_copy_to_user(req->value,
598ef270ab1SKenneth D. Merry 				ocs_textbuf_get_buffer(&textbuf),
599ef270ab1SKenneth D. Merry 				ocs_textbuf_get_written(&textbuf))) {
600ef270ab1SKenneth D. Merry 				ocs_log_test(ocs, "Error: (%d) ocs_copy_to_user failed\n", __LINE__);
601ef270ab1SKenneth D. Merry 		}
602ef270ab1SKenneth D. Merry 		}
603ef270ab1SKenneth D. Merry 		req->value_length = ocs_textbuf_get_written(&textbuf);
604ef270ab1SKenneth D. Merry 
605ef270ab1SKenneth D. Merry 		ocs_textbuf_free(ocs, &textbuf);
606ef270ab1SKenneth D. Merry 
607ef270ab1SKenneth D. Merry 		break;
608ef270ab1SKenneth D. Merry 	}
609ef270ab1SKenneth D. Merry 
610ef270ab1SKenneth D. Merry 	case OCS_IOCTL_CMD_MGMT_SET: {
611ef270ab1SKenneth D. Merry 		char name[OCS_MGMT_MAX_NAME];
612ef270ab1SKenneth D. Merry 		char value[OCS_MGMT_MAX_VALUE];
613ef270ab1SKenneth D. Merry 		ocs_ioctl_cmd_set_t* req = (ocs_ioctl_cmd_set_t*)addr;
614ef270ab1SKenneth D. Merry 
615ef270ab1SKenneth D. Merry 		// Copy the name  in from user space
616ef270ab1SKenneth D. Merry 		if (ocs_copy_from_user(name, req->name, OCS_MGMT_MAX_NAME)) {
617ef270ab1SKenneth D. Merry 			ocs_log_test(ocs, "Error: copy from user failed\n");
618ef270ab1SKenneth D. Merry 			ocs_ioctl_free(ocs, req, sizeof(*req));
619ef270ab1SKenneth D. Merry 			return -EFAULT;
620ef270ab1SKenneth D. Merry 		}
621ef270ab1SKenneth D. Merry 
622ef270ab1SKenneth D. Merry 		// Copy the  value in from user space
623ef270ab1SKenneth D. Merry 		if (ocs_copy_from_user(value, req->value, OCS_MGMT_MAX_VALUE)) {
624ef270ab1SKenneth D. Merry 			ocs_log_test(ocs, "Error: copy from user failed\n");
625ef270ab1SKenneth D. Merry 			ocs_ioctl_free(ocs, req, sizeof(*req));
626ef270ab1SKenneth D. Merry 			return -EFAULT;
627ef270ab1SKenneth D. Merry 		}
628ef270ab1SKenneth D. Merry 
629965e2154SRam Kishore Vegesna 		req->result = ocs_mgmt_set(ocs, name, value);
630ef270ab1SKenneth D. Merry 
631ef270ab1SKenneth D. Merry 		break;
632ef270ab1SKenneth D. Merry 	}
633ef270ab1SKenneth D. Merry 
634ef270ab1SKenneth D. Merry 	case OCS_IOCTL_CMD_MGMT_EXEC: {
635ef270ab1SKenneth D. Merry 		ocs_ioctl_action_t* req = (ocs_ioctl_action_t*) addr;
636ef270ab1SKenneth D. Merry 		char action_name[OCS_MGMT_MAX_NAME];
637ef270ab1SKenneth D. Merry 
638ef270ab1SKenneth D. Merry 		if (ocs_copy_from_user(action_name, req->name, sizeof(action_name))) {
639ef270ab1SKenneth D. Merry 			ocs_log_test(ocs, "Error: copy req.name from user failed\n");
640ef270ab1SKenneth D. Merry 			ocs_ioctl_free(ocs, req, sizeof(*req));
641ef270ab1SKenneth D. Merry 			return -EFAULT;
642ef270ab1SKenneth D. Merry 		}
643ef270ab1SKenneth D. Merry 
644ef270ab1SKenneth D. Merry 		req->result = ocs_mgmt_exec(ocs, action_name, req->arg_in, req->arg_in_length,
645ef270ab1SKenneth D. Merry 				req->arg_out, req->arg_out_length);
646ef270ab1SKenneth D. Merry 
647ef270ab1SKenneth D. Merry 		break;
648ef270ab1SKenneth D. Merry 	}
649ef270ab1SKenneth D. Merry 
650ef270ab1SKenneth D. Merry 	default:
651ef270ab1SKenneth D. Merry 		ocs_log_test(ocs, "Error: unknown cmd %#lx\n", cmd);
652ef270ab1SKenneth D. Merry 		status = -ENOTTY;
653ef270ab1SKenneth D. Merry 		break;
654ef270ab1SKenneth D. Merry 	}
655ef270ab1SKenneth D. Merry 	return status;
656ef270ab1SKenneth D. Merry }
657ef270ab1SKenneth D. Merry 
658ef270ab1SKenneth D. Merry static void
ocs_fw_write_cb(int32_t status,uint32_t actual_write_length,uint32_t change_status,void * arg)659ef270ab1SKenneth D. Merry ocs_fw_write_cb(int32_t status, uint32_t actual_write_length,
660ef270ab1SKenneth D. Merry 					uint32_t change_status, void *arg)
661ef270ab1SKenneth D. Merry {
662ef270ab1SKenneth D. Merry         ocs_mgmt_fw_write_result_t *result = arg;
663ef270ab1SKenneth D. Merry 
664ef270ab1SKenneth D. Merry         result->status = status;
665ef270ab1SKenneth D. Merry         result->actual_xfer = actual_write_length;
666ef270ab1SKenneth D. Merry         result->change_status = change_status;
667ef270ab1SKenneth D. Merry 
668ef270ab1SKenneth D. Merry         ocs_sem_v(&(result->semaphore));
669ef270ab1SKenneth D. Merry }
670ef270ab1SKenneth D. Merry 
671ef270ab1SKenneth D. Merry int
ocs_firmware_write(ocs_t * ocs,const uint8_t * buf,size_t buf_len,uint8_t * change_status)672ef270ab1SKenneth D. Merry ocs_firmware_write(ocs_t *ocs, const uint8_t *buf, size_t buf_len,
673ef270ab1SKenneth D. Merry 						uint8_t *change_status)
674ef270ab1SKenneth D. Merry {
675ef270ab1SKenneth D. Merry         int rc = 0;
676ef270ab1SKenneth D. Merry         uint32_t bytes_left;
677ef270ab1SKenneth D. Merry         uint32_t xfer_size;
678ef270ab1SKenneth D. Merry         uint32_t offset;
679ef270ab1SKenneth D. Merry         ocs_dma_t dma;
680ef270ab1SKenneth D. Merry         int last = 0;
681ef270ab1SKenneth D. Merry         ocs_mgmt_fw_write_result_t result;
682ef270ab1SKenneth D. Merry 
683ef270ab1SKenneth D. Merry         ocs_sem_init(&(result.semaphore), 0, "fw_write");
684ef270ab1SKenneth D. Merry 
685ef270ab1SKenneth D. Merry         bytes_left = buf_len;
686ef270ab1SKenneth D. Merry         offset = 0;
687ef270ab1SKenneth D. Merry 
688ef270ab1SKenneth D. Merry         if (ocs_dma_alloc(ocs, &dma, FW_WRITE_BUFSIZE, 4096)) {
689ef270ab1SKenneth D. Merry                 ocs_log_err(ocs, "ocs_firmware_write: malloc failed\n");
690ef270ab1SKenneth D. Merry                 return -ENOMEM;
691ef270ab1SKenneth D. Merry         }
692ef270ab1SKenneth D. Merry 
693ef270ab1SKenneth D. Merry         while (bytes_left > 0) {
694ef270ab1SKenneth D. Merry                 if (bytes_left > FW_WRITE_BUFSIZE) {
695ef270ab1SKenneth D. Merry                         xfer_size = FW_WRITE_BUFSIZE;
696ef270ab1SKenneth D. Merry                 } else {
697ef270ab1SKenneth D. Merry                         xfer_size = bytes_left;
698ef270ab1SKenneth D. Merry                 }
699ef270ab1SKenneth D. Merry 
700ef270ab1SKenneth D. Merry                 ocs_memcpy(dma.virt, buf + offset, xfer_size);
701ef270ab1SKenneth D. Merry 
702ef270ab1SKenneth D. Merry                 if (bytes_left == xfer_size) {
703ef270ab1SKenneth D. Merry                         last = 1;
704ef270ab1SKenneth D. Merry                 }
705ef270ab1SKenneth D. Merry 
706ef270ab1SKenneth D. Merry                 ocs_hw_firmware_write(&ocs->hw, &dma, xfer_size, offset,
707ef270ab1SKenneth D. Merry 						last, ocs_fw_write_cb, &result);
708ef270ab1SKenneth D. Merry 
709ef270ab1SKenneth D. Merry                 if (ocs_sem_p(&(result.semaphore), OCS_SEM_FOREVER) != 0) {
710ef270ab1SKenneth D. Merry                         rc = -ENXIO;
711ef270ab1SKenneth D. Merry                         break;
712ef270ab1SKenneth D. Merry                 }
713ef270ab1SKenneth D. Merry 
714ef270ab1SKenneth D. Merry                 if (result.actual_xfer == 0 || result.status != 0) {
715ef270ab1SKenneth D. Merry                         rc = -EFAULT;
716ef270ab1SKenneth D. Merry                         break;
717ef270ab1SKenneth D. Merry                 }
718ef270ab1SKenneth D. Merry 
719ef270ab1SKenneth D. Merry                 if (last) {
720ef270ab1SKenneth D. Merry                         *change_status = result.change_status;
721ef270ab1SKenneth D. Merry                 }
722ef270ab1SKenneth D. Merry 
723ef270ab1SKenneth D. Merry                 bytes_left -= result.actual_xfer;
724ef270ab1SKenneth D. Merry                 offset += result.actual_xfer;
725ef270ab1SKenneth D. Merry         }
726ef270ab1SKenneth D. Merry 
727ef270ab1SKenneth D. Merry         ocs_dma_free(ocs, &dma);
728ef270ab1SKenneth D. Merry         return rc;
729ef270ab1SKenneth D. Merry }
730ef270ab1SKenneth D. Merry 
731ef270ab1SKenneth D. Merry static int
ocs_sys_fwupgrade(SYSCTL_HANDLER_ARGS)732ef270ab1SKenneth D. Merry ocs_sys_fwupgrade(SYSCTL_HANDLER_ARGS)
733ef270ab1SKenneth D. Merry {
734ef270ab1SKenneth D. Merry 	char file_name[256] = {0};
735ef270ab1SKenneth D. Merry 	char fw_change_status;
736ef270ab1SKenneth D. Merry 	uint32_t rc = 1;
737ef270ab1SKenneth D. Merry         ocs_t *ocs  = (ocs_t *)arg1;
738ef270ab1SKenneth D. Merry         const struct firmware *fw;
739ef270ab1SKenneth D. Merry 	const struct ocs_hw_grp_hdr *fw_image;
740ef270ab1SKenneth D. Merry 
741ef270ab1SKenneth D. Merry         rc = sysctl_handle_string(oidp, file_name, sizeof(file_name), req);
742ef270ab1SKenneth D. Merry         if (rc || !req->newptr)
743ef270ab1SKenneth D. Merry                 return rc;
744ef270ab1SKenneth D. Merry 
745ef270ab1SKenneth D. Merry         fw = firmware_get(file_name);
746ef270ab1SKenneth D. Merry         if (fw == NULL) {
747ef270ab1SKenneth D. Merry                 device_printf(ocs->dev, "Unable to get Firmware. "
748ef270ab1SKenneth D. Merry                         "Make sure %s is copied to /boot/modules\n", file_name);
749ef270ab1SKenneth D. Merry                 return ENOENT;
750ef270ab1SKenneth D. Merry         }
751ef270ab1SKenneth D. Merry 
752ef270ab1SKenneth D. Merry 	fw_image = (const struct ocs_hw_grp_hdr *)fw->data;
753ef270ab1SKenneth D. Merry 
754ef270ab1SKenneth D. Merry         /* Check if firmware provided is compatible with this particular
755ef270ab1SKenneth D. Merry          * Adapter of not*/
756ef270ab1SKenneth D. Merry         if ((ocs_be32toh(fw_image->magic_number) != OCS_HW_OBJECT_G5) &&
757ef270ab1SKenneth D. Merry                 (ocs_be32toh(fw_image->magic_number) != OCS_HW_OBJECT_G6)) {
758ef270ab1SKenneth D. Merry                 device_printf(ocs->dev,
759ef270ab1SKenneth D. Merry                         "Invalid FW image found Magic: 0x%x Size: %zu \n",
760ef270ab1SKenneth D. Merry                         ocs_be32toh(fw_image->magic_number), fw->datasize);
761ef270ab1SKenneth D. Merry                 rc = -1;
762ef270ab1SKenneth D. Merry                 goto exit;
763ef270ab1SKenneth D. Merry         }
764ef270ab1SKenneth D. Merry 
765ef270ab1SKenneth D. Merry         if (!strncmp(ocs->fw_version, fw_image->revision,
766ef270ab1SKenneth D. Merry 					strnlen(fw_image->revision, 16))) {
767ef270ab1SKenneth D. Merry                 device_printf(ocs->dev, "No update req. "
768ef270ab1SKenneth D. Merry 				"Firmware is already up to date. \n");
769ef270ab1SKenneth D. Merry                 rc = 0;
770ef270ab1SKenneth D. Merry                 goto exit;
771ef270ab1SKenneth D. Merry         }
772ef270ab1SKenneth D. Merry 
773ef270ab1SKenneth D. Merry 	device_printf(ocs->dev, "Upgrading Firmware from %s to %s \n",
774ef270ab1SKenneth D. Merry 				ocs->fw_version, fw_image->revision);
775ef270ab1SKenneth D. Merry 
776ef270ab1SKenneth D. Merry 	rc = ocs_firmware_write(ocs, fw->data, fw->datasize, &fw_change_status);
777ef270ab1SKenneth D. Merry         if (rc) {
778ef270ab1SKenneth D. Merry                 ocs_log_err(ocs, "Firmware update failed with status = %d\n", rc);
779ef270ab1SKenneth D. Merry         } else {
780ef270ab1SKenneth D. Merry                 ocs_log_info(ocs, "Firmware updated successfully\n");
781ef270ab1SKenneth D. Merry                 switch (fw_change_status) {
782ef270ab1SKenneth D. Merry                         case 0x00:
783ef270ab1SKenneth D. Merry                                 device_printf(ocs->dev,
784ef270ab1SKenneth D. Merry 				"No reset needed, new firmware is active.\n");
785ef270ab1SKenneth D. Merry                                 break;
786ef270ab1SKenneth D. Merry                         case 0x01:
787ef270ab1SKenneth D. Merry                                 device_printf(ocs->dev,
788ef270ab1SKenneth D. Merry 				"A physical device reset (host reboot) is "
789ef270ab1SKenneth D. Merry 				"needed to activate the new firmware\n");
790ef270ab1SKenneth D. Merry                                 break;
791ef270ab1SKenneth D. Merry                         case 0x02:
792ef270ab1SKenneth D. Merry                         case 0x03:
793ef270ab1SKenneth D. Merry                                 device_printf(ocs->dev,
794ef270ab1SKenneth D. Merry 				"firmware is resetting to activate the new "
795ef270ab1SKenneth D. Merry 				"firmware, Host reboot is needed \n");
796ef270ab1SKenneth D. Merry                                 break;
797ef270ab1SKenneth D. Merry                         default:
798ef270ab1SKenneth D. Merry                                 ocs_log_warn(ocs,
799ef270ab1SKenneth D. Merry                                         "Unexected value change_status: %d\n",
800ef270ab1SKenneth D. Merry                                         fw_change_status);
801ef270ab1SKenneth D. Merry                                 break;
802ef270ab1SKenneth D. Merry                 }
803ef270ab1SKenneth D. Merry         }
804ef270ab1SKenneth D. Merry 
805ef270ab1SKenneth D. Merry exit:
806ef270ab1SKenneth D. Merry         /* Release Firmware*/
807ef270ab1SKenneth D. Merry         firmware_put(fw, FIRMWARE_UNLOAD);
808ef270ab1SKenneth D. Merry 
809ef270ab1SKenneth D. Merry         return rc;
810ef270ab1SKenneth D. Merry 
811ef270ab1SKenneth D. Merry }
812ef270ab1SKenneth D. Merry 
813ef270ab1SKenneth D. Merry static int
ocs_sysctl_wwnn(SYSCTL_HANDLER_ARGS)814ef270ab1SKenneth D. Merry ocs_sysctl_wwnn(SYSCTL_HANDLER_ARGS)
815ef270ab1SKenneth D. Merry {
816ef270ab1SKenneth D. Merry 	uint32_t rc = 1;
817ef270ab1SKenneth D. Merry 	ocs_t *ocs = oidp->oid_arg1;
818ef270ab1SKenneth D. Merry 	char old[64];
819ef270ab1SKenneth D. Merry 	char new[64];
820ef270ab1SKenneth D. Merry 	uint64_t *wwnn = NULL;
821ef270ab1SKenneth D. Merry 	ocs_xport_t *xport = ocs->xport;
822ef270ab1SKenneth D. Merry 
823ef270ab1SKenneth D. Merry 	if (xport->req_wwnn) {
824ef270ab1SKenneth D. Merry 		wwnn = &xport->req_wwnn;
825ef270ab1SKenneth D. Merry 		memset(old, 0, sizeof(old));
826ef270ab1SKenneth D. Merry 		snprintf(old, sizeof(old), "0x%llx" , (unsigned long long) *wwnn);
827ef270ab1SKenneth D. Merry 
828ef270ab1SKenneth D. Merry 	} else {
829ef270ab1SKenneth D. Merry 		wwnn = ocs_hw_get_ptr(&ocs->hw, OCS_HW_WWN_NODE);
830ef270ab1SKenneth D. Merry 
831ef270ab1SKenneth D. Merry 		memset(old, 0, sizeof(old));
832ef270ab1SKenneth D. Merry 		snprintf(old, sizeof(old), "0x%llx" , (unsigned long long) ocs_htobe64(*wwnn));
833ef270ab1SKenneth D. Merry 	}
834ef270ab1SKenneth D. Merry 
835ef270ab1SKenneth D. Merry 	/*Read wwnn*/
836ef270ab1SKenneth D. Merry 	if (!req->newptr) {
837ef270ab1SKenneth D. Merry 		return (sysctl_handle_string(oidp, old, sizeof(old), req));
838ef270ab1SKenneth D. Merry 	}
839ef270ab1SKenneth D. Merry 
840ef270ab1SKenneth D. Merry 	/*Configure port wwn*/
841ef270ab1SKenneth D. Merry 	rc = sysctl_handle_string(oidp, new, sizeof(new), req);
842ef270ab1SKenneth D. Merry 	if (rc)
843ef270ab1SKenneth D. Merry 		return (rc);
844ef270ab1SKenneth D. Merry 
845ef270ab1SKenneth D. Merry 	if (strncmp(old, new, strlen(old)) == 0) {
846ef270ab1SKenneth D. Merry 		return 0;
847ef270ab1SKenneth D. Merry 	}
848ef270ab1SKenneth D. Merry 
849ef270ab1SKenneth D. Merry 	return (set_req_wwnn(ocs, NULL, new));
850ef270ab1SKenneth D. Merry }
851ef270ab1SKenneth D. Merry 
852ef270ab1SKenneth D. Merry static int
ocs_sysctl_wwpn(SYSCTL_HANDLER_ARGS)853ef270ab1SKenneth D. Merry ocs_sysctl_wwpn(SYSCTL_HANDLER_ARGS)
854ef270ab1SKenneth D. Merry {
855ef270ab1SKenneth D. Merry 	uint32_t rc = 1;
856ef270ab1SKenneth D. Merry 	ocs_t *ocs = oidp->oid_arg1;
857ef270ab1SKenneth D. Merry 	char old[64];
858ef270ab1SKenneth D. Merry 	char new[64];
859ef270ab1SKenneth D. Merry 	uint64_t *wwpn = NULL;
860ef270ab1SKenneth D. Merry 	ocs_xport_t *xport = ocs->xport;
861ef270ab1SKenneth D. Merry 
862ef270ab1SKenneth D. Merry 	if (xport->req_wwpn) {
863ef270ab1SKenneth D. Merry 		wwpn = &xport->req_wwpn;
864ef270ab1SKenneth D. Merry 		memset(old, 0, sizeof(old));
865ef270ab1SKenneth D. Merry 		snprintf(old, sizeof(old), "0x%llx",(unsigned long long) *wwpn);
866ef270ab1SKenneth D. Merry 	} else {
867ef270ab1SKenneth D. Merry 		wwpn = ocs_hw_get_ptr(&ocs->hw, OCS_HW_WWN_PORT);
868ef270ab1SKenneth D. Merry 		memset(old, 0, sizeof(old));
869ef270ab1SKenneth D. Merry 		snprintf(old, sizeof(old), "0x%llx",(unsigned long long) ocs_htobe64(*wwpn));
870ef270ab1SKenneth D. Merry 	}
871ef270ab1SKenneth D. Merry 
872ef270ab1SKenneth D. Merry 	/*Read wwpn*/
873ef270ab1SKenneth D. Merry 	if (!req->newptr) {
874ef270ab1SKenneth D. Merry 		return (sysctl_handle_string(oidp, old, sizeof(old), req));
875ef270ab1SKenneth D. Merry 	}
876ef270ab1SKenneth D. Merry 
877ef270ab1SKenneth D. Merry 	/*Configure port wwn*/
878ef270ab1SKenneth D. Merry 	rc = sysctl_handle_string(oidp, new, sizeof(new), req);
879ef270ab1SKenneth D. Merry 	if (rc)
880ef270ab1SKenneth D. Merry 		return (rc);
881ef270ab1SKenneth D. Merry 
882ef270ab1SKenneth D. Merry 	if (strncmp(old, new, strlen(old)) == 0) {
883ef270ab1SKenneth D. Merry 		return 0;
884ef270ab1SKenneth D. Merry 	}
885ef270ab1SKenneth D. Merry 
886ef270ab1SKenneth D. Merry 	return (set_req_wwpn(ocs, NULL, new));
887ef270ab1SKenneth D. Merry }
888ef270ab1SKenneth D. Merry 
889ef270ab1SKenneth D. Merry static int
ocs_sysctl_current_topology(SYSCTL_HANDLER_ARGS)890ef270ab1SKenneth D. Merry ocs_sysctl_current_topology(SYSCTL_HANDLER_ARGS)
891ef270ab1SKenneth D. Merry {
892ef270ab1SKenneth D. Merry 	ocs_t *ocs = oidp->oid_arg1;
893ef270ab1SKenneth D. Merry 	uint32_t value;
894ef270ab1SKenneth D. Merry 
895ef270ab1SKenneth D. Merry 	ocs_hw_get(&ocs->hw, OCS_HW_TOPOLOGY, &value);
896ef270ab1SKenneth D. Merry 
897ef270ab1SKenneth D. Merry 	return (sysctl_handle_int(oidp, &value, 0, req));
898ef270ab1SKenneth D. Merry }
899ef270ab1SKenneth D. Merry 
900ef270ab1SKenneth D. Merry static int
ocs_sysctl_current_speed(SYSCTL_HANDLER_ARGS)901ef270ab1SKenneth D. Merry ocs_sysctl_current_speed(SYSCTL_HANDLER_ARGS)
902ef270ab1SKenneth D. Merry {
903ef270ab1SKenneth D. Merry 	ocs_t *ocs = oidp->oid_arg1;
904ef270ab1SKenneth D. Merry 	uint32_t value;
905ef270ab1SKenneth D. Merry 
906ef270ab1SKenneth D. Merry 	ocs_hw_get(&ocs->hw, OCS_HW_LINK_SPEED, &value);
907ef270ab1SKenneth D. Merry 
908ef270ab1SKenneth D. Merry 	return (sysctl_handle_int(oidp, &value, 0, req));
909ef270ab1SKenneth D. Merry }
910ef270ab1SKenneth D. Merry 
911ef270ab1SKenneth D. Merry static int
ocs_sysctl_config_topology(SYSCTL_HANDLER_ARGS)912ef270ab1SKenneth D. Merry ocs_sysctl_config_topology(SYSCTL_HANDLER_ARGS)
913ef270ab1SKenneth D. Merry {
914ef270ab1SKenneth D. Merry 	uint32_t rc = 1;
915ef270ab1SKenneth D. Merry 	ocs_t *ocs = oidp->oid_arg1;
916ef270ab1SKenneth D. Merry 	uint32_t old_value;
917ef270ab1SKenneth D. Merry 	uint32_t new_value;
918ef270ab1SKenneth D. Merry 	char buf[64];
919ef270ab1SKenneth D. Merry 
920ef270ab1SKenneth D. Merry 	ocs_hw_get(&ocs->hw, OCS_HW_CONFIG_TOPOLOGY, &old_value);
921ef270ab1SKenneth D. Merry 
922ef270ab1SKenneth D. Merry 	/*Read topo*/
923ef270ab1SKenneth D. Merry 	if (!req->newptr) {
924ef270ab1SKenneth D. Merry 		return (sysctl_handle_int(oidp, &old_value, 0, req));
925ef270ab1SKenneth D. Merry 	}
926ef270ab1SKenneth D. Merry 
927ef270ab1SKenneth D. Merry 	/*Configure port wwn*/
928ef270ab1SKenneth D. Merry 	rc = sysctl_handle_int(oidp, &new_value, 0, req);
929ef270ab1SKenneth D. Merry 	if (rc)
930ef270ab1SKenneth D. Merry 		return (rc);
931ef270ab1SKenneth D. Merry 
932ef270ab1SKenneth D. Merry 	if (new_value == old_value) {
933ef270ab1SKenneth D. Merry 		return 0;
934ef270ab1SKenneth D. Merry 	}
935ef270ab1SKenneth D. Merry 
936ef270ab1SKenneth D. Merry 	snprintf(buf, sizeof(buf), "%d",new_value);
937ef270ab1SKenneth D. Merry 	rc = set_configured_topology(ocs, NULL, buf);
938ef270ab1SKenneth D. Merry 	return rc;
939ef270ab1SKenneth D. Merry }
940ef270ab1SKenneth D. Merry 
941ef270ab1SKenneth D. Merry static int
ocs_sysctl_config_speed(SYSCTL_HANDLER_ARGS)942ef270ab1SKenneth D. Merry ocs_sysctl_config_speed(SYSCTL_HANDLER_ARGS)
943ef270ab1SKenneth D. Merry {
944ef270ab1SKenneth D. Merry 	uint32_t rc = 1;
945ef270ab1SKenneth D. Merry 	ocs_t *ocs = oidp->oid_arg1;
946ef270ab1SKenneth D. Merry 	uint32_t old_value;
947ef270ab1SKenneth D. Merry 	uint32_t new_value;
948ef270ab1SKenneth D. Merry 	char buf[64];
949ef270ab1SKenneth D. Merry 
950ef270ab1SKenneth D. Merry 	ocs_hw_get(&ocs->hw, OCS_HW_LINK_CONFIG_SPEED, &old_value);
951ef270ab1SKenneth D. Merry 
952ef270ab1SKenneth D. Merry 	/*Read topo*/
953ef270ab1SKenneth D. Merry 	if (!req->newptr) {
954ef270ab1SKenneth D. Merry 		return (sysctl_handle_int(oidp, &old_value, 0, req));
955ef270ab1SKenneth D. Merry 	}
956ef270ab1SKenneth D. Merry 
957ef270ab1SKenneth D. Merry 	/*Configure port wwn*/
958ef270ab1SKenneth D. Merry 	rc = sysctl_handle_int(oidp, &new_value, 0, req);
959ef270ab1SKenneth D. Merry 	if (rc)
960ef270ab1SKenneth D. Merry 		return (rc);
961ef270ab1SKenneth D. Merry 
962ef270ab1SKenneth D. Merry 	if (new_value == old_value) {
963ef270ab1SKenneth D. Merry 		return 0;
964ef270ab1SKenneth D. Merry 	}
965ef270ab1SKenneth D. Merry 
966ef270ab1SKenneth D. Merry 	snprintf(buf, sizeof(buf), "%d",new_value);
967ef270ab1SKenneth D. Merry 	rc = set_configured_speed(ocs, NULL,buf);
968ef270ab1SKenneth D. Merry 	return rc;
969ef270ab1SKenneth D. Merry }
970ef270ab1SKenneth D. Merry 
971ef270ab1SKenneth D. Merry static int
ocs_sysctl_fcid(SYSCTL_HANDLER_ARGS)972ef270ab1SKenneth D. Merry ocs_sysctl_fcid(SYSCTL_HANDLER_ARGS)
973ef270ab1SKenneth D. Merry {
974ef270ab1SKenneth D. Merry 	ocs_t *ocs = oidp->oid_arg1;
975ef270ab1SKenneth D. Merry 	char buf[64];
976ef270ab1SKenneth D. Merry 
977ef270ab1SKenneth D. Merry 	memset(buf, 0, sizeof(buf));
978ef270ab1SKenneth D. Merry 	if (ocs->domain && ocs->domain->attached) {
979ef270ab1SKenneth D. Merry 		snprintf(buf, sizeof(buf), "0x%06x",
980ef270ab1SKenneth D. Merry 			ocs->domain->sport->fc_id);
981ef270ab1SKenneth D. Merry 	}
982ef270ab1SKenneth D. Merry 
983ef270ab1SKenneth D. Merry 	return (sysctl_handle_string(oidp, buf, sizeof(buf), req));
984ef270ab1SKenneth D. Merry }
985ef270ab1SKenneth D. Merry 
986ef270ab1SKenneth D. Merry static int
ocs_sysctl_port_state(SYSCTL_HANDLER_ARGS)987ef270ab1SKenneth D. Merry ocs_sysctl_port_state(SYSCTL_HANDLER_ARGS)
988ef270ab1SKenneth D. Merry {
989ef270ab1SKenneth D. Merry 
990ef270ab1SKenneth D. Merry 	char new[256] = {0};
991ef270ab1SKenneth D. Merry 	uint32_t rc = 1;
992ef270ab1SKenneth D. Merry 	ocs_xport_stats_t old;
993ef270ab1SKenneth D. Merry 	ocs_t *ocs  = (ocs_t *)arg1;
994ef270ab1SKenneth D. Merry 
995ef270ab1SKenneth D. Merry 	ocs_xport_status(ocs->xport, OCS_XPORT_CONFIG_PORT_STATUS, &old);
996ef270ab1SKenneth D. Merry 
997ef270ab1SKenneth D. Merry 	/*Read port state */
998ef270ab1SKenneth D. Merry 	if (!req->newptr) {
999ef270ab1SKenneth D. Merry 		snprintf(new, sizeof(new), "%s",
1000ef270ab1SKenneth D. Merry 			(old.value == OCS_XPORT_PORT_OFFLINE) ?
1001ef270ab1SKenneth D. Merry 					 "offline" : "online");
1002ef270ab1SKenneth D. Merry 		return (sysctl_handle_string(oidp, new, sizeof(new), req));
1003ef270ab1SKenneth D. Merry         }
1004ef270ab1SKenneth D. Merry 
1005ef270ab1SKenneth D. Merry 	/*Configure port state*/
1006ef270ab1SKenneth D. Merry 	rc = sysctl_handle_string(oidp, new, sizeof(new), req);
1007ef270ab1SKenneth D. Merry 	if (rc)
1008ef270ab1SKenneth D. Merry 		return (rc);
1009ef270ab1SKenneth D. Merry 
1010ef270ab1SKenneth D. Merry 	if (ocs_strcasecmp(new, "offline") == 0) {
1011ef270ab1SKenneth D. Merry 		if (old.value == OCS_XPORT_PORT_OFFLINE) {
1012ef270ab1SKenneth D. Merry 			return (0);
1013ef270ab1SKenneth D. Merry 		}
1014ef270ab1SKenneth D. Merry 		ocs_log_debug(ocs, "Setting port to %s\n", new);
1015ef270ab1SKenneth D. Merry 		rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_OFFLINE);
1016ef270ab1SKenneth D. Merry 		if (rc != 0) {
1017ef270ab1SKenneth D. Merry 			ocs_log_err(ocs, "Setting port to offline failed\n");
1018ef270ab1SKenneth D. Merry 		}
1019ef270ab1SKenneth D. Merry 	} else if (ocs_strcasecmp(new, "online") == 0) {
1020ef270ab1SKenneth D. Merry 		if (old.value == OCS_XPORT_PORT_ONLINE) {
1021ef270ab1SKenneth D. Merry 			return (0);
1022ef270ab1SKenneth D. Merry 		}
1023ef270ab1SKenneth D. Merry 		ocs_log_debug(ocs, "Setting port to %s\n", new);
1024ef270ab1SKenneth D. Merry 		rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_ONLINE);
1025ef270ab1SKenneth D. Merry 		if (rc != 0) {
1026ef270ab1SKenneth D. Merry 			ocs_log_err(ocs, "Setting port to online failed\n");
1027ef270ab1SKenneth D. Merry 		}
1028ef270ab1SKenneth D. Merry 	} else {
1029ef270ab1SKenneth D. Merry 		ocs_log_err(ocs, "Unsupported link state %s\n", new);
1030ef270ab1SKenneth D. Merry 		rc = 1;
1031ef270ab1SKenneth D. Merry 	}
1032ef270ab1SKenneth D. Merry 
1033ef270ab1SKenneth D. Merry 	return (rc);
1034ef270ab1SKenneth D. Merry 
1035ef270ab1SKenneth D. Merry }
1036ef270ab1SKenneth D. Merry 
1037ef270ab1SKenneth D. Merry static int
ocs_sysctl_vport_wwpn(SYSCTL_HANDLER_ARGS)1038ef270ab1SKenneth D. Merry ocs_sysctl_vport_wwpn(SYSCTL_HANDLER_ARGS)
1039ef270ab1SKenneth D. Merry {
1040ef270ab1SKenneth D. Merry 	ocs_fcport *fcp = oidp->oid_arg1;
1041ef270ab1SKenneth D. Merry 	char str_wwpn[64];
1042ef270ab1SKenneth D. Merry 
1043ef270ab1SKenneth D. Merry 	memset(str_wwpn, 0, sizeof(str_wwpn));
1044ef270ab1SKenneth D. Merry 	snprintf(str_wwpn, sizeof(str_wwpn), "0x%llx", (unsigned long long)fcp->vport->wwpn);
1045ef270ab1SKenneth D. Merry 
1046ef270ab1SKenneth D. Merry 	return (sysctl_handle_string(oidp, str_wwpn, sizeof(str_wwpn), req));
1047ef270ab1SKenneth D. Merry }
1048ef270ab1SKenneth D. Merry 
1049ef270ab1SKenneth D. Merry static int
ocs_sysctl_vport_wwnn(SYSCTL_HANDLER_ARGS)1050ef270ab1SKenneth D. Merry ocs_sysctl_vport_wwnn(SYSCTL_HANDLER_ARGS)
1051ef270ab1SKenneth D. Merry {
1052ef270ab1SKenneth D. Merry 	ocs_fcport *fcp = oidp->oid_arg1;
1053ef270ab1SKenneth D. Merry 	char str_wwnn[64];
1054ef270ab1SKenneth D. Merry 
1055ef270ab1SKenneth D. Merry 	memset(str_wwnn, 0, sizeof(str_wwnn));
1056ef270ab1SKenneth D. Merry 	snprintf(str_wwnn, sizeof(str_wwnn), "0x%llx", (unsigned long long)fcp->vport->wwnn);
1057ef270ab1SKenneth D. Merry 
1058ef270ab1SKenneth D. Merry 	return (sysctl_handle_string(oidp, str_wwnn, sizeof(str_wwnn), req));
1059ef270ab1SKenneth D. Merry }
1060ef270ab1SKenneth D. Merry 
1061ef270ab1SKenneth D. Merry /**
1062ef270ab1SKenneth D. Merry  * @brief Initialize sysctl
1063ef270ab1SKenneth D. Merry  *
1064ef270ab1SKenneth D. Merry  * Initialize sysctl so elxsdkutil can query device information.
1065ef270ab1SKenneth D. Merry  *
1066ef270ab1SKenneth D. Merry  * @param ocs pointer to ocs
1067ef270ab1SKenneth D. Merry  * @return void
1068ef270ab1SKenneth D. Merry  */
1069ef270ab1SKenneth D. Merry static void
ocs_sysctl_init(ocs_t * ocs)1070ef270ab1SKenneth D. Merry ocs_sysctl_init(ocs_t *ocs)
1071ef270ab1SKenneth D. Merry {
1072ef270ab1SKenneth D. Merry 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(ocs->dev);
1073ef270ab1SKenneth D. Merry 	struct sysctl_oid *tree = device_get_sysctl_tree(ocs->dev);
1074ef270ab1SKenneth D. Merry 	struct sysctl_oid *vtree;
1075ef270ab1SKenneth D. Merry 	const char *str = NULL;
107684f0fb8aSMark Johnston 	char name[16];
1077ef270ab1SKenneth D. Merry 	uint32_t rev, if_type, family, i;
1078ef270ab1SKenneth D. Merry 	ocs_fcport *fcp = NULL;
1079ef270ab1SKenneth D. Merry 
1080ef270ab1SKenneth D. Merry 	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1081ef270ab1SKenneth D. Merry 			"devid", CTLFLAG_RD, NULL,
1082ef270ab1SKenneth D. Merry 			pci_get_devid(ocs->dev), "Device ID");
1083ef270ab1SKenneth D. Merry 
1084ef270ab1SKenneth D. Merry 	memset(ocs->modeldesc, 0, sizeof(ocs->modeldesc));
1085ef270ab1SKenneth D. Merry 	if (0 == pci_get_vpd_ident(ocs->dev, &str)) {
1086ef270ab1SKenneth D. Merry 		snprintf(ocs->modeldesc, sizeof(ocs->modeldesc), "%s", str);
1087ef270ab1SKenneth D. Merry 	}
1088ef270ab1SKenneth D. Merry 	SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1089ef270ab1SKenneth D. Merry 			"modeldesc", CTLFLAG_RD,
1090ef270ab1SKenneth D. Merry 			ocs->modeldesc,
1091ef270ab1SKenneth D. Merry 			0, "Model Description");
1092ef270ab1SKenneth D. Merry 
1093ef270ab1SKenneth D. Merry 	memset(ocs->serialnum, 0, sizeof(ocs->serialnum));
1094ef270ab1SKenneth D. Merry 	if (0 == pci_get_vpd_readonly(ocs->dev, "SN", &str)) {
1095ef270ab1SKenneth D. Merry 		snprintf(ocs->serialnum, sizeof(ocs->serialnum), "%s", str);
1096ef270ab1SKenneth D. Merry 	}
1097ef270ab1SKenneth D. Merry 	SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1098ef270ab1SKenneth D. Merry 			"sn", CTLFLAG_RD,
1099ef270ab1SKenneth D. Merry 			ocs->serialnum,
1100ef270ab1SKenneth D. Merry 			0, "Serial Number");
1101ef270ab1SKenneth D. Merry 
1102ef270ab1SKenneth D. Merry 	ocs_hw_get(&ocs->hw, OCS_HW_SLI_REV, &rev);
1103ef270ab1SKenneth D. Merry 	ocs_hw_get(&ocs->hw, OCS_HW_IF_TYPE, &if_type);
1104ef270ab1SKenneth D. Merry 	ocs_hw_get(&ocs->hw, OCS_HW_SLI_FAMILY, &family);
1105ef270ab1SKenneth D. Merry 
1106ef270ab1SKenneth D. Merry 	memset(ocs->fwrev, 0, sizeof(ocs->fwrev));
1107ef270ab1SKenneth D. Merry 	snprintf(ocs->fwrev, sizeof(ocs->fwrev), "%s, sli-%d:%d:%x",
1108ef270ab1SKenneth D. Merry 			(char *)ocs_hw_get_ptr(&ocs->hw, OCS_HW_FW_REV),
1109ef270ab1SKenneth D. Merry 			rev, if_type, family);
1110ef270ab1SKenneth D. Merry 	SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1111ef270ab1SKenneth D. Merry 			"fwrev", CTLFLAG_RD,
1112ef270ab1SKenneth D. Merry 			ocs->fwrev,
1113ef270ab1SKenneth D. Merry 			0, "Firmware Revision");
1114ef270ab1SKenneth D. Merry 
1115ef270ab1SKenneth D. Merry 	memset(ocs->sli_intf, 0, sizeof(ocs->sli_intf));
111684f0fb8aSMark Johnston 	snprintf(ocs->sli_intf, sizeof(ocs->sli_intf), "%08x",
1117ef270ab1SKenneth D. Merry 		 ocs_config_read32(ocs, SLI4_INTF_REG));
1118ef270ab1SKenneth D. Merry 	SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1119ef270ab1SKenneth D. Merry 			  "sli_intf", CTLFLAG_RD,
1120ef270ab1SKenneth D. Merry 			  ocs->sli_intf,
1121ef270ab1SKenneth D. Merry 			  0, "SLI Interface");
1122ef270ab1SKenneth D. Merry 
1123ef270ab1SKenneth D. Merry         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "fw_upgrade",
1124a2523baeSRam Kishore Vegesna             CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, (void *)ocs, 0,
1125ef270ab1SKenneth D. Merry 	    ocs_sys_fwupgrade, "A", "Firmware grp file");
1126ef270ab1SKenneth D. Merry 
1127ef270ab1SKenneth D. Merry 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1128a2523baeSRam Kishore Vegesna 	    "wwnn", CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE,
1129ef270ab1SKenneth D. Merry 	    ocs, 0, ocs_sysctl_wwnn, "A",
1130ef270ab1SKenneth D. Merry 	    "World Wide Node Name, wwnn should be in the format 0x<XXXXXXXXXXXXXXXX>");
1131ef270ab1SKenneth D. Merry 
1132ef270ab1SKenneth D. Merry 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1133a2523baeSRam Kishore Vegesna 	    "wwpn", CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE,
1134ef270ab1SKenneth D. Merry 	    ocs, 0, ocs_sysctl_wwpn, "A",
1135ef270ab1SKenneth D. Merry 	    "World Wide Port Name, wwpn should be in the format 0x<XXXXXXXXXXXXXXXX>");
1136ef270ab1SKenneth D. Merry 
1137ef270ab1SKenneth D. Merry 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1138a2523baeSRam Kishore Vegesna 	    "current_topology", CTLTYPE_UINT | CTLFLAG_RD | CTLFLAG_MPSAFE,
1139ef270ab1SKenneth D. Merry 	    ocs, 0, ocs_sysctl_current_topology, "IU",
1140ef270ab1SKenneth D. Merry 	    "Current Topology, 1-NPort; 2-Loop; 3-None");
1141ef270ab1SKenneth D. Merry 
1142ef270ab1SKenneth D. Merry 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1143a2523baeSRam Kishore Vegesna 	    "current_speed", CTLTYPE_UINT | CTLFLAG_RD | CTLFLAG_MPSAFE,
1144ef270ab1SKenneth D. Merry 	    ocs, 0, ocs_sysctl_current_speed, "IU",
1145ef270ab1SKenneth D. Merry 	    "Current Speed");
1146ef270ab1SKenneth D. Merry 
1147ef270ab1SKenneth D. Merry 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1148a2523baeSRam Kishore Vegesna 	    "configured_topology", CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE,
1149ef270ab1SKenneth D. Merry 	    ocs, 0, ocs_sysctl_config_topology, "IU",
1150ef270ab1SKenneth D. Merry 	    "Configured Topology, 0-Auto; 1-NPort; 2-Loop");
1151ef270ab1SKenneth D. Merry 
1152ef270ab1SKenneth D. Merry 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1153a2523baeSRam Kishore Vegesna 	    "configured_speed", CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE,
1154ef270ab1SKenneth D. Merry 	    ocs, 0, ocs_sysctl_config_speed, "IU",
1155ef270ab1SKenneth D. Merry 	    "Configured Speed, 0-Auto, 2000, 4000, 8000, 16000, 32000");
1156ef270ab1SKenneth D. Merry 
1157ef270ab1SKenneth D. Merry 	SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1158a2523baeSRam Kishore Vegesna 	    "businfo", CTLFLAG_RD, ocs->businfo, 0, "Bus Info");
1159ef270ab1SKenneth D. Merry 
1160ef270ab1SKenneth D. Merry 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1161a2523baeSRam Kishore Vegesna 	    "fcid", CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
11627029da5cSPawel Biernacki 	    ocs, 0, ocs_sysctl_fcid, "A", "Port FC ID");
1163ef270ab1SKenneth D. Merry 
1164ef270ab1SKenneth D. Merry 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1165a2523baeSRam Kishore Vegesna 	    "port_state", CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE,
11667029da5cSPawel Biernacki 	    ocs, 0, ocs_sysctl_port_state, "A", "configured port state");
1167ef270ab1SKenneth D. Merry 
1168ef270ab1SKenneth D. Merry 	for (i	= 0; i < ocs->num_vports; i++) {
1169ef270ab1SKenneth D. Merry 		fcp = FCPORT(ocs, i+1);
1170ef270ab1SKenneth D. Merry 
1171ef270ab1SKenneth D. Merry 		memset(name, 0, sizeof(name));
1172ef270ab1SKenneth D. Merry 		snprintf(name, sizeof(name), "vport%d", i);
1173ef270ab1SKenneth D. Merry 		vtree = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(tree),
11747029da5cSPawel Biernacki 		    OID_AUTO, name, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
11757029da5cSPawel Biernacki 		    "Virtual port");
1176ef270ab1SKenneth D. Merry 
1177ef270ab1SKenneth D. Merry 		SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(vtree), OID_AUTO,
1178a2523baeSRam Kishore Vegesna 		    "wwnn", CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE,
1179ef270ab1SKenneth D. Merry 		    fcp, 0, ocs_sysctl_vport_wwnn, "A",
1180ef270ab1SKenneth D. Merry 		    "World Wide Node Name");
1181ef270ab1SKenneth D. Merry 
1182ef270ab1SKenneth D. Merry 		SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(vtree), OID_AUTO,
1183a2523baeSRam Kishore Vegesna 		    "wwpn", CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE,
11847029da5cSPawel Biernacki 		    fcp, 0, ocs_sysctl_vport_wwpn, "A", "World Wide Port Name");
1185ef270ab1SKenneth D. Merry 	}
1186ef270ab1SKenneth D. Merry 
1187ef270ab1SKenneth D. Merry }
1188ef270ab1SKenneth D. Merry 
1189ef270ab1SKenneth D. Merry /**
1190ef270ab1SKenneth D. Merry  * @brief Initialize the debug module
1191ef270ab1SKenneth D. Merry  *
1192ef270ab1SKenneth D. Merry  * Parse device hints (similar to Linux module parameters) here. To use,
1193ef270ab1SKenneth D. Merry  * run the command
1194ef270ab1SKenneth D. Merry  *    kenv hint.ocs.U.P=V
1195ef270ab1SKenneth D. Merry  * from the command line replacing U with the unit # (0,1,...),
1196ef270ab1SKenneth D. Merry  * P with the parameter name (debug_mask), and V with the value
1197ef270ab1SKenneth D. Merry  */
1198ef270ab1SKenneth D. Merry void
ocs_debug_attach(void * os)1199ef270ab1SKenneth D. Merry ocs_debug_attach(void *os)
1200ef270ab1SKenneth D. Merry {
1201ef270ab1SKenneth D. Merry 	struct ocs_softc *ocs = os;
1202ef270ab1SKenneth D. Merry 	int error = 0;
1203ef270ab1SKenneth D. Merry 	char *resname = NULL;
1204ef270ab1SKenneth D. Merry 	int32_t	unit = INT32_MAX;
1205ef270ab1SKenneth D. Merry 	uint32_t ocs_debug_mask = 0;
1206ef270ab1SKenneth D. Merry 
1207ef270ab1SKenneth D. Merry 	resname = "debug_mask";
1208ef270ab1SKenneth D. Merry 	if (0 == (error = resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
1209ef270ab1SKenneth D. Merry 				resname, &ocs_debug_mask))) {
1210ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "setting %s to %010x\n", resname, ocs_debug_mask);
1211ef270ab1SKenneth D. Merry 		ocs_debug_enable(ocs_debug_mask);
1212ef270ab1SKenneth D. Merry 	}
1213ef270ab1SKenneth D. Merry 
1214ef270ab1SKenneth D. Merry 	unit = device_get_unit(ocs->dev);
1215ef270ab1SKenneth D. Merry 	ocs->cdev = make_dev(&ocs_cdevsw, unit, UID_ROOT, GID_OPERATOR, 0640,
1216ef270ab1SKenneth D. Merry 			"ocs%d", unit);
1217ef270ab1SKenneth D. Merry 	if (ocs->cdev) {
1218ef270ab1SKenneth D. Merry 		ocs->cdev->si_drv1 = ocs;
1219ef270ab1SKenneth D. Merry 	}
1220ef270ab1SKenneth D. Merry 
1221ef270ab1SKenneth D. Merry 	/* initialize sysctl interface */
1222ef270ab1SKenneth D. Merry 	ocs_sysctl_init(ocs);
1223ef270ab1SKenneth D. Merry 	mtx_init(&ocs->dbg_lock, "ocs_dbg_lock", NULL, MTX_DEF);
1224ef270ab1SKenneth D. Merry }
1225ef270ab1SKenneth D. Merry 
1226ef270ab1SKenneth D. Merry /**
1227ef270ab1SKenneth D. Merry  * @brief Free the debug module
1228ef270ab1SKenneth D. Merry  */
1229ef270ab1SKenneth D. Merry void
ocs_debug_detach(void * os)1230ef270ab1SKenneth D. Merry ocs_debug_detach(void *os)
1231ef270ab1SKenneth D. Merry {
1232ef270ab1SKenneth D. Merry 	struct ocs_softc *ocs = os;
1233ef270ab1SKenneth D. Merry 
1234ef270ab1SKenneth D. Merry 	mtx_destroy(&ocs->dbg_lock);
1235ef270ab1SKenneth D. Merry 
1236ef270ab1SKenneth D. Merry 	if (ocs->cdev) {
1237ef270ab1SKenneth D. Merry 		ocs->cdev->si_drv1 = NULL;
1238ef270ab1SKenneth D. Merry 		destroy_dev(ocs->cdev);
1239ef270ab1SKenneth D. Merry 	}
1240ef270ab1SKenneth D. Merry }
1241