xref: /freebsd/sys/dev/mpt/mpt_user.c (revision 8276c414)
1ee98c4a5SJohn Baldwin /*-
27282444bSPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
37282444bSPedro F. Giffuni  *
4ee98c4a5SJohn Baldwin  * Copyright (c) 2008 Yahoo!, Inc.
5ee98c4a5SJohn Baldwin  * All rights reserved.
6ee98c4a5SJohn Baldwin  * Written by: John Baldwin <jhb@FreeBSD.org>
7ee98c4a5SJohn Baldwin  *
8ee98c4a5SJohn Baldwin  * Redistribution and use in source and binary forms, with or without
9ee98c4a5SJohn Baldwin  * modification, are permitted provided that the following conditions
10ee98c4a5SJohn Baldwin  * are met:
11ee98c4a5SJohn Baldwin  * 1. Redistributions of source code must retain the above copyright
12ee98c4a5SJohn Baldwin  *    notice, this list of conditions and the following disclaimer.
13ee98c4a5SJohn Baldwin  * 2. Redistributions in binary form must reproduce the above copyright
14ee98c4a5SJohn Baldwin  *    notice, this list of conditions and the following disclaimer in the
15ee98c4a5SJohn Baldwin  *    documentation and/or other materials provided with the distribution.
16ee98c4a5SJohn Baldwin  * 3. Neither the name of the author nor the names of any co-contributors
17ee98c4a5SJohn Baldwin  *    may be used to endorse or promote products derived from this software
18ee98c4a5SJohn Baldwin  *    without specific prior written permission.
19ee98c4a5SJohn Baldwin  *
20ee98c4a5SJohn Baldwin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21ee98c4a5SJohn Baldwin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22ee98c4a5SJohn Baldwin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23ee98c4a5SJohn Baldwin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24ee98c4a5SJohn Baldwin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25ee98c4a5SJohn Baldwin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26ee98c4a5SJohn Baldwin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27ee98c4a5SJohn Baldwin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28ee98c4a5SJohn Baldwin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29ee98c4a5SJohn Baldwin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30ee98c4a5SJohn Baldwin  * SUCH DAMAGE.
31ee98c4a5SJohn Baldwin  *
32ee98c4a5SJohn Baldwin  * LSI MPT-Fusion Host Adapter FreeBSD userland interface
33ee98c4a5SJohn Baldwin  */
34ee98c4a5SJohn Baldwin 
35ee98c4a5SJohn Baldwin #include <sys/cdefs.h>
36ee98c4a5SJohn Baldwin __FBSDID("$FreeBSD$");
37ee98c4a5SJohn Baldwin 
38ee98c4a5SJohn Baldwin #include <sys/param.h>
39562894f0SBrooks Davis #ifdef __amd64__
40562894f0SBrooks Davis #include <sys/abi_compat.h>
41562894f0SBrooks Davis #endif
42ee98c4a5SJohn Baldwin #include <sys/conf.h>
43ee98c4a5SJohn Baldwin #include <sys/errno.h>
44ee98c4a5SJohn Baldwin #include <sys/ioccom.h>
45ee98c4a5SJohn Baldwin #include <sys/mpt_ioctl.h>
46ee98c4a5SJohn Baldwin 
47ee98c4a5SJohn Baldwin #include <dev/mpt/mpt.h>
48ee98c4a5SJohn Baldwin 
49ee98c4a5SJohn Baldwin struct mpt_user_raid_action_result {
50ee98c4a5SJohn Baldwin 	uint32_t	volume_status;
51ee98c4a5SJohn Baldwin 	uint32_t	action_data[4];
52ee98c4a5SJohn Baldwin 	uint16_t	action_status;
53ee98c4a5SJohn Baldwin };
54ee98c4a5SJohn Baldwin 
554124f62eSJohn Baldwin struct mpt_page_memory {
564124f62eSJohn Baldwin 	bus_dma_tag_t	tag;
574124f62eSJohn Baldwin 	bus_dmamap_t	map;
584124f62eSJohn Baldwin 	bus_addr_t	paddr;
594124f62eSJohn Baldwin 	void		*vaddr;
604124f62eSJohn Baldwin };
614124f62eSJohn Baldwin 
62ee98c4a5SJohn Baldwin static mpt_probe_handler_t	mpt_user_probe;
63ee98c4a5SJohn Baldwin static mpt_attach_handler_t	mpt_user_attach;
64ee98c4a5SJohn Baldwin static mpt_enable_handler_t	mpt_user_enable;
65ee98c4a5SJohn Baldwin static mpt_ready_handler_t	mpt_user_ready;
66ee98c4a5SJohn Baldwin static mpt_event_handler_t	mpt_user_event;
67ee98c4a5SJohn Baldwin static mpt_reset_handler_t	mpt_user_reset;
68ee98c4a5SJohn Baldwin static mpt_detach_handler_t	mpt_user_detach;
69ee98c4a5SJohn Baldwin 
70ee98c4a5SJohn Baldwin static struct mpt_personality mpt_user_personality = {
71ee98c4a5SJohn Baldwin 	.name		= "mpt_user",
72ee98c4a5SJohn Baldwin 	.probe		= mpt_user_probe,
73ee98c4a5SJohn Baldwin 	.attach		= mpt_user_attach,
74ee98c4a5SJohn Baldwin 	.enable		= mpt_user_enable,
75ee98c4a5SJohn Baldwin 	.ready		= mpt_user_ready,
76ee98c4a5SJohn Baldwin 	.event		= mpt_user_event,
77ee98c4a5SJohn Baldwin 	.reset		= mpt_user_reset,
78ee98c4a5SJohn Baldwin 	.detach		= mpt_user_detach,
79ee98c4a5SJohn Baldwin };
80ee98c4a5SJohn Baldwin 
81ee98c4a5SJohn Baldwin DECLARE_MPT_PERSONALITY(mpt_user, SI_ORDER_SECOND);
82ee98c4a5SJohn Baldwin 
83ee98c4a5SJohn Baldwin static mpt_reply_handler_t	mpt_user_reply_handler;
84ee98c4a5SJohn Baldwin 
85ee98c4a5SJohn Baldwin static d_open_t		mpt_open;
86ee98c4a5SJohn Baldwin static d_close_t	mpt_close;
87ee98c4a5SJohn Baldwin static d_ioctl_t	mpt_ioctl;
88ee98c4a5SJohn Baldwin 
89ee98c4a5SJohn Baldwin static struct cdevsw mpt_cdevsw = {
90ee98c4a5SJohn Baldwin 	.d_version =	D_VERSION,
91ee98c4a5SJohn Baldwin 	.d_flags =	0,
92ee98c4a5SJohn Baldwin 	.d_open =	mpt_open,
93ee98c4a5SJohn Baldwin 	.d_close =	mpt_close,
94ee98c4a5SJohn Baldwin 	.d_ioctl =	mpt_ioctl,
95ee98c4a5SJohn Baldwin 	.d_name =	"mpt",
96ee98c4a5SJohn Baldwin };
97ee98c4a5SJohn Baldwin 
98ee98c4a5SJohn Baldwin static MALLOC_DEFINE(M_MPTUSER, "mpt_user", "Buffers for mpt(4) ioctls");
99ee98c4a5SJohn Baldwin 
100ee98c4a5SJohn Baldwin static uint32_t user_handler_id = MPT_HANDLER_ID_NONE;
101ee98c4a5SJohn Baldwin 
10287e255acSMarius Strobl static int
103ee98c4a5SJohn Baldwin mpt_user_probe(struct mpt_softc *mpt)
104ee98c4a5SJohn Baldwin {
105ee98c4a5SJohn Baldwin 
106ee98c4a5SJohn Baldwin 	/* Attach to every controller. */
107ee98c4a5SJohn Baldwin 	return (0);
108ee98c4a5SJohn Baldwin }
109ee98c4a5SJohn Baldwin 
11087e255acSMarius Strobl static int
111ee98c4a5SJohn Baldwin mpt_user_attach(struct mpt_softc *mpt)
112ee98c4a5SJohn Baldwin {
113ee98c4a5SJohn Baldwin 	mpt_handler_t handler;
114ee98c4a5SJohn Baldwin 	int error, unit;
115ee98c4a5SJohn Baldwin 
116ee98c4a5SJohn Baldwin 	MPT_LOCK(mpt);
117ee98c4a5SJohn Baldwin 	handler.reply_handler = mpt_user_reply_handler;
118ee98c4a5SJohn Baldwin 	error = mpt_register_handler(mpt, MPT_HANDLER_REPLY, handler,
119ee98c4a5SJohn Baldwin 				     &user_handler_id);
120ee98c4a5SJohn Baldwin 	MPT_UNLOCK(mpt);
121ee98c4a5SJohn Baldwin 	if (error != 0) {
122ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "Unable to register user handler!\n");
123ee98c4a5SJohn Baldwin 		return (error);
124ee98c4a5SJohn Baldwin 	}
125ee98c4a5SJohn Baldwin 	unit = device_get_unit(mpt->dev);
126ee98c4a5SJohn Baldwin 	mpt->cdev = make_dev(&mpt_cdevsw, unit, UID_ROOT, GID_OPERATOR, 0640,
127ee98c4a5SJohn Baldwin 	    "mpt%d", unit);
128ee98c4a5SJohn Baldwin 	if (mpt->cdev == NULL) {
129ee98c4a5SJohn Baldwin 		MPT_LOCK(mpt);
130ee98c4a5SJohn Baldwin 		mpt_deregister_handler(mpt, MPT_HANDLER_REPLY, handler,
131ee98c4a5SJohn Baldwin 		    user_handler_id);
132ee98c4a5SJohn Baldwin 		MPT_UNLOCK(mpt);
133ee98c4a5SJohn Baldwin 		return (ENOMEM);
134ee98c4a5SJohn Baldwin 	}
135ee98c4a5SJohn Baldwin 	mpt->cdev->si_drv1 = mpt;
136ee98c4a5SJohn Baldwin 	return (0);
137ee98c4a5SJohn Baldwin }
138ee98c4a5SJohn Baldwin 
13987e255acSMarius Strobl static int
140ee98c4a5SJohn Baldwin mpt_user_enable(struct mpt_softc *mpt)
141ee98c4a5SJohn Baldwin {
142ee98c4a5SJohn Baldwin 
143ee98c4a5SJohn Baldwin 	return (0);
144ee98c4a5SJohn Baldwin }
145ee98c4a5SJohn Baldwin 
14687e255acSMarius Strobl static void
147ee98c4a5SJohn Baldwin mpt_user_ready(struct mpt_softc *mpt)
148ee98c4a5SJohn Baldwin {
14987e255acSMarius Strobl 
150ee98c4a5SJohn Baldwin }
151ee98c4a5SJohn Baldwin 
15287e255acSMarius Strobl static int
153ee98c4a5SJohn Baldwin mpt_user_event(struct mpt_softc *mpt, request_t *req,
154ee98c4a5SJohn Baldwin     MSG_EVENT_NOTIFY_REPLY *msg)
155ee98c4a5SJohn Baldwin {
156ee98c4a5SJohn Baldwin 
157ee98c4a5SJohn Baldwin 	/* Someday we may want to let a user daemon listen for events? */
158ee98c4a5SJohn Baldwin 	return (0);
159ee98c4a5SJohn Baldwin }
160ee98c4a5SJohn Baldwin 
16187e255acSMarius Strobl static void
162ee98c4a5SJohn Baldwin mpt_user_reset(struct mpt_softc *mpt, int type)
163ee98c4a5SJohn Baldwin {
16487e255acSMarius Strobl 
165ee98c4a5SJohn Baldwin }
166ee98c4a5SJohn Baldwin 
16787e255acSMarius Strobl static void
168ee98c4a5SJohn Baldwin mpt_user_detach(struct mpt_softc *mpt)
169ee98c4a5SJohn Baldwin {
170ee98c4a5SJohn Baldwin 	mpt_handler_t handler;
171ee98c4a5SJohn Baldwin 
172ee98c4a5SJohn Baldwin 	/* XXX: do a purge of pending requests? */
173ee98c4a5SJohn Baldwin 	destroy_dev(mpt->cdev);
174ee98c4a5SJohn Baldwin 
175ee98c4a5SJohn Baldwin 	MPT_LOCK(mpt);
176ee98c4a5SJohn Baldwin 	handler.reply_handler = mpt_user_reply_handler;
177ee98c4a5SJohn Baldwin 	mpt_deregister_handler(mpt, MPT_HANDLER_REPLY, handler,
178ee98c4a5SJohn Baldwin 	    user_handler_id);
179ee98c4a5SJohn Baldwin 	MPT_UNLOCK(mpt);
180ee98c4a5SJohn Baldwin }
181ee98c4a5SJohn Baldwin 
182ee98c4a5SJohn Baldwin static int
18300b4e54aSWarner Losh mpt_open(struct cdev *dev, int flags, int fmt, struct thread *td)
184ee98c4a5SJohn Baldwin {
185ee98c4a5SJohn Baldwin 
186ee98c4a5SJohn Baldwin 	return (0);
187ee98c4a5SJohn Baldwin }
188ee98c4a5SJohn Baldwin 
189ee98c4a5SJohn Baldwin static int
19000b4e54aSWarner Losh mpt_close(struct cdev *dev, int flags, int fmt, struct thread *td)
191ee98c4a5SJohn Baldwin {
192ee98c4a5SJohn Baldwin 
193ee98c4a5SJohn Baldwin 	return (0);
194ee98c4a5SJohn Baldwin }
195ee98c4a5SJohn Baldwin 
196ee98c4a5SJohn Baldwin static int
1974124f62eSJohn Baldwin mpt_alloc_buffer(struct mpt_softc *mpt, struct mpt_page_memory *page_mem,
1984124f62eSJohn Baldwin     size_t len)
1994124f62eSJohn Baldwin {
2004124f62eSJohn Baldwin 	struct mpt_map_info mi;
2014124f62eSJohn Baldwin 	int error;
2024124f62eSJohn Baldwin 
2034124f62eSJohn Baldwin 	page_mem->vaddr = NULL;
2044124f62eSJohn Baldwin 
2054124f62eSJohn Baldwin 	/* Limit requests to 16M. */
2064124f62eSJohn Baldwin 	if (len > 16 * 1024 * 1024)
2074124f62eSJohn Baldwin 		return (ENOSPC);
2084124f62eSJohn Baldwin 	error = mpt_dma_tag_create(mpt, mpt->parent_dmat, 1, 0,
2094124f62eSJohn Baldwin 	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
2104124f62eSJohn Baldwin 	    len, 1, len, 0, &page_mem->tag);
2114124f62eSJohn Baldwin 	if (error)
2124124f62eSJohn Baldwin 		return (error);
2134124f62eSJohn Baldwin 	error = bus_dmamem_alloc(page_mem->tag, &page_mem->vaddr,
2146c5276c8SMarius Strobl 	    BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &page_mem->map);
2154124f62eSJohn Baldwin 	if (error) {
2164124f62eSJohn Baldwin 		bus_dma_tag_destroy(page_mem->tag);
2174124f62eSJohn Baldwin 		return (error);
2184124f62eSJohn Baldwin 	}
2194124f62eSJohn Baldwin 	mi.mpt = mpt;
2204124f62eSJohn Baldwin 	error = bus_dmamap_load(page_mem->tag, page_mem->map, page_mem->vaddr,
2214124f62eSJohn Baldwin 	    len, mpt_map_rquest, &mi, BUS_DMA_NOWAIT);
2224124f62eSJohn Baldwin 	if (error == 0)
2234124f62eSJohn Baldwin 		error = mi.error;
2244124f62eSJohn Baldwin 	if (error) {
2254124f62eSJohn Baldwin 		bus_dmamem_free(page_mem->tag, page_mem->vaddr, page_mem->map);
2264124f62eSJohn Baldwin 		bus_dma_tag_destroy(page_mem->tag);
2274124f62eSJohn Baldwin 		page_mem->vaddr = NULL;
2284124f62eSJohn Baldwin 		return (error);
2294124f62eSJohn Baldwin 	}
2304124f62eSJohn Baldwin 	page_mem->paddr = mi.phys;
2314124f62eSJohn Baldwin 	return (0);
2324124f62eSJohn Baldwin }
2334124f62eSJohn Baldwin 
2344124f62eSJohn Baldwin static void
2354124f62eSJohn Baldwin mpt_free_buffer(struct mpt_page_memory *page_mem)
2364124f62eSJohn Baldwin {
2374124f62eSJohn Baldwin 
2384124f62eSJohn Baldwin 	if (page_mem->vaddr == NULL)
2394124f62eSJohn Baldwin 		return;
2404124f62eSJohn Baldwin 	bus_dmamap_unload(page_mem->tag, page_mem->map);
2414124f62eSJohn Baldwin 	bus_dmamem_free(page_mem->tag, page_mem->vaddr, page_mem->map);
2424124f62eSJohn Baldwin 	bus_dma_tag_destroy(page_mem->tag);
2434124f62eSJohn Baldwin 	page_mem->vaddr = NULL;
2444124f62eSJohn Baldwin }
2454124f62eSJohn Baldwin 
2464124f62eSJohn Baldwin static int
247ee98c4a5SJohn Baldwin mpt_user_read_cfg_header(struct mpt_softc *mpt,
248ee98c4a5SJohn Baldwin     struct mpt_cfg_page_req *page_req)
249ee98c4a5SJohn Baldwin {
250ee98c4a5SJohn Baldwin 	request_t  *req;
251ee98c4a5SJohn Baldwin 	cfgparms_t params;
252ee98c4a5SJohn Baldwin 	MSG_CONFIG *cfgp;
253ee98c4a5SJohn Baldwin 	int	    error;
254ee98c4a5SJohn Baldwin 
255ee98c4a5SJohn Baldwin 	req = mpt_get_request(mpt, TRUE);
256ee98c4a5SJohn Baldwin 	if (req == NULL) {
257ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "mpt_user_read_cfg_header: Get request failed!\n");
258ee98c4a5SJohn Baldwin 		return (ENOMEM);
259ee98c4a5SJohn Baldwin 	}
260ee98c4a5SJohn Baldwin 
261ee98c4a5SJohn Baldwin 	params.Action = MPI_CONFIG_ACTION_PAGE_HEADER;
262ee98c4a5SJohn Baldwin 	params.PageVersion = 0;
263ee98c4a5SJohn Baldwin 	params.PageLength = 0;
264ee98c4a5SJohn Baldwin 	params.PageNumber = page_req->header.PageNumber;
265ee98c4a5SJohn Baldwin 	params.PageType = page_req->header.PageType;
2667ee37807SMarius Strobl 	params.PageAddress = le32toh(page_req->page_address);
267ee98c4a5SJohn Baldwin 	error = mpt_issue_cfg_req(mpt, req, &params, /*addr*/0, /*len*/0,
268ee98c4a5SJohn Baldwin 				  TRUE, 5000);
269ee98c4a5SJohn Baldwin 	if (error != 0) {
270ee98c4a5SJohn Baldwin 		/*
271ee98c4a5SJohn Baldwin 		 * Leave the request. Without resetting the chip, it's
272ee98c4a5SJohn Baldwin 		 * still owned by it and we'll just get into trouble
273ee98c4a5SJohn Baldwin 		 * freeing it now. Mark it as abandoned so that if it
274ee98c4a5SJohn Baldwin 		 * shows up later it can be freed.
275ee98c4a5SJohn Baldwin 		 */
276ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "read_cfg_header timed out\n");
277ee98c4a5SJohn Baldwin 		return (ETIMEDOUT);
278ee98c4a5SJohn Baldwin 	}
279ee98c4a5SJohn Baldwin 
2807ee37807SMarius Strobl 	page_req->ioc_status = htole16(req->IOCStatus);
281ee98c4a5SJohn Baldwin 	if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS) {
282ee98c4a5SJohn Baldwin 		cfgp = req->req_vbuf;
283ee98c4a5SJohn Baldwin 		bcopy(&cfgp->Header, &page_req->header,
284ee98c4a5SJohn Baldwin 		    sizeof(page_req->header));
285ee98c4a5SJohn Baldwin 	}
286ee98c4a5SJohn Baldwin 	mpt_free_request(mpt, req);
287ee98c4a5SJohn Baldwin 	return (0);
288ee98c4a5SJohn Baldwin }
289ee98c4a5SJohn Baldwin 
290ee98c4a5SJohn Baldwin static int
291ee98c4a5SJohn Baldwin mpt_user_read_cfg_page(struct mpt_softc *mpt, struct mpt_cfg_page_req *page_req,
2924124f62eSJohn Baldwin     struct mpt_page_memory *mpt_page)
293ee98c4a5SJohn Baldwin {
294ee98c4a5SJohn Baldwin 	CONFIG_PAGE_HEADER *hdr;
295ee98c4a5SJohn Baldwin 	request_t    *req;
296ee98c4a5SJohn Baldwin 	cfgparms_t    params;
297ee98c4a5SJohn Baldwin 	int	      error;
298ee98c4a5SJohn Baldwin 
299ee98c4a5SJohn Baldwin 	req = mpt_get_request(mpt, TRUE);
300ee98c4a5SJohn Baldwin 	if (req == NULL) {
301ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "mpt_user_read_cfg_page: Get request failed!\n");
302ee98c4a5SJohn Baldwin 		return (ENOMEM);
303ee98c4a5SJohn Baldwin 	}
304ee98c4a5SJohn Baldwin 
3054124f62eSJohn Baldwin 	hdr = mpt_page->vaddr;
306ee98c4a5SJohn Baldwin 	params.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
307ee98c4a5SJohn Baldwin 	params.PageVersion = hdr->PageVersion;
308ee98c4a5SJohn Baldwin 	params.PageLength = hdr->PageLength;
309ee98c4a5SJohn Baldwin 	params.PageNumber = hdr->PageNumber;
310ee98c4a5SJohn Baldwin 	params.PageType = hdr->PageType & MPI_CONFIG_PAGETYPE_MASK;
3117ee37807SMarius Strobl 	params.PageAddress = le32toh(page_req->page_address);
3126c5276c8SMarius Strobl 	bus_dmamap_sync(mpt_page->tag, mpt_page->map,
3136c5276c8SMarius Strobl 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
3144124f62eSJohn Baldwin 	error = mpt_issue_cfg_req(mpt, req, &params, mpt_page->paddr,
3157ee37807SMarius Strobl 	    le32toh(page_req->len), TRUE, 5000);
316ee98c4a5SJohn Baldwin 	if (error != 0) {
317ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "mpt_user_read_cfg_page timed out\n");
318ee98c4a5SJohn Baldwin 		return (ETIMEDOUT);
319ee98c4a5SJohn Baldwin 	}
320ee98c4a5SJohn Baldwin 
3217ee37807SMarius Strobl 	page_req->ioc_status = htole16(req->IOCStatus);
3224124f62eSJohn Baldwin 	if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS)
3234124f62eSJohn Baldwin 		bus_dmamap_sync(mpt_page->tag, mpt_page->map,
3246c5276c8SMarius Strobl 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
325ee98c4a5SJohn Baldwin 	mpt_free_request(mpt, req);
326ee98c4a5SJohn Baldwin 	return (0);
327ee98c4a5SJohn Baldwin }
328ee98c4a5SJohn Baldwin 
329ee98c4a5SJohn Baldwin static int
330ee98c4a5SJohn Baldwin mpt_user_read_extcfg_header(struct mpt_softc *mpt,
331ee98c4a5SJohn Baldwin     struct mpt_ext_cfg_page_req *ext_page_req)
332ee98c4a5SJohn Baldwin {
333ee98c4a5SJohn Baldwin 	request_t  *req;
334ee98c4a5SJohn Baldwin 	cfgparms_t params;
335ee98c4a5SJohn Baldwin 	MSG_CONFIG_REPLY *cfgp;
336ee98c4a5SJohn Baldwin 	int	    error;
337ee98c4a5SJohn Baldwin 
338ee98c4a5SJohn Baldwin 	req = mpt_get_request(mpt, TRUE);
339ee98c4a5SJohn Baldwin 	if (req == NULL) {
340ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "mpt_user_read_extcfg_header: Get request failed!\n");
341ee98c4a5SJohn Baldwin 		return (ENOMEM);
342ee98c4a5SJohn Baldwin 	}
343ee98c4a5SJohn Baldwin 
344ee98c4a5SJohn Baldwin 	params.Action = MPI_CONFIG_ACTION_PAGE_HEADER;
345ee98c4a5SJohn Baldwin 	params.PageVersion = ext_page_req->header.PageVersion;
346ee98c4a5SJohn Baldwin 	params.PageLength = 0;
347ee98c4a5SJohn Baldwin 	params.PageNumber = ext_page_req->header.PageNumber;
348ee98c4a5SJohn Baldwin 	params.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
3497ee37807SMarius Strobl 	params.PageAddress = le32toh(ext_page_req->page_address);
350ee98c4a5SJohn Baldwin 	params.ExtPageType = ext_page_req->header.ExtPageType;
351ee98c4a5SJohn Baldwin 	params.ExtPageLength = 0;
352ee98c4a5SJohn Baldwin 	error = mpt_issue_cfg_req(mpt, req, &params, /*addr*/0, /*len*/0,
353ee98c4a5SJohn Baldwin 				  TRUE, 5000);
354ee98c4a5SJohn Baldwin 	if (error != 0) {
355ee98c4a5SJohn Baldwin 		/*
356ee98c4a5SJohn Baldwin 		 * Leave the request. Without resetting the chip, it's
357ee98c4a5SJohn Baldwin 		 * still owned by it and we'll just get into trouble
358ee98c4a5SJohn Baldwin 		 * freeing it now. Mark it as abandoned so that if it
359ee98c4a5SJohn Baldwin 		 * shows up later it can be freed.
360ee98c4a5SJohn Baldwin 		 */
361ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "mpt_user_read_extcfg_header timed out\n");
362ee98c4a5SJohn Baldwin 		return (ETIMEDOUT);
363ee98c4a5SJohn Baldwin 	}
364ee98c4a5SJohn Baldwin 
3657ee37807SMarius Strobl 	ext_page_req->ioc_status = htole16(req->IOCStatus);
366ee98c4a5SJohn Baldwin 	if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS) {
367ee98c4a5SJohn Baldwin 		cfgp = req->req_vbuf;
368ee98c4a5SJohn Baldwin 		ext_page_req->header.PageVersion = cfgp->Header.PageVersion;
369ee98c4a5SJohn Baldwin 		ext_page_req->header.PageNumber = cfgp->Header.PageNumber;
370ee98c4a5SJohn Baldwin 		ext_page_req->header.PageType = cfgp->Header.PageType;
371ee98c4a5SJohn Baldwin 		ext_page_req->header.ExtPageLength = cfgp->ExtPageLength;
372ee98c4a5SJohn Baldwin 		ext_page_req->header.ExtPageType = cfgp->ExtPageType;
373ee98c4a5SJohn Baldwin 	}
374ee98c4a5SJohn Baldwin 	mpt_free_request(mpt, req);
375ee98c4a5SJohn Baldwin 	return (0);
376ee98c4a5SJohn Baldwin }
377ee98c4a5SJohn Baldwin 
378ee98c4a5SJohn Baldwin static int
379ee98c4a5SJohn Baldwin mpt_user_read_extcfg_page(struct mpt_softc *mpt,
3804124f62eSJohn Baldwin     struct mpt_ext_cfg_page_req *ext_page_req, struct mpt_page_memory *mpt_page)
381ee98c4a5SJohn Baldwin {
382ee98c4a5SJohn Baldwin 	CONFIG_EXTENDED_PAGE_HEADER *hdr;
383ee98c4a5SJohn Baldwin 	request_t    *req;
384ee98c4a5SJohn Baldwin 	cfgparms_t    params;
385ee98c4a5SJohn Baldwin 	int	      error;
386ee98c4a5SJohn Baldwin 
387ee98c4a5SJohn Baldwin 	req = mpt_get_request(mpt, TRUE);
388ee98c4a5SJohn Baldwin 	if (req == NULL) {
389ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "mpt_user_read_extcfg_page: Get request failed!\n");
390ee98c4a5SJohn Baldwin 		return (ENOMEM);
391ee98c4a5SJohn Baldwin 	}
392ee98c4a5SJohn Baldwin 
3934124f62eSJohn Baldwin 	hdr = mpt_page->vaddr;
394ee98c4a5SJohn Baldwin 	params.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
395ee98c4a5SJohn Baldwin 	params.PageVersion = hdr->PageVersion;
396ee98c4a5SJohn Baldwin 	params.PageLength = 0;
397ee98c4a5SJohn Baldwin 	params.PageNumber = hdr->PageNumber;
398ee98c4a5SJohn Baldwin 	params.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
3997ee37807SMarius Strobl 	params.PageAddress = le32toh(ext_page_req->page_address);
400ee98c4a5SJohn Baldwin 	params.ExtPageType = hdr->ExtPageType;
401ee98c4a5SJohn Baldwin 	params.ExtPageLength = hdr->ExtPageLength;
4026c5276c8SMarius Strobl 	bus_dmamap_sync(mpt_page->tag, mpt_page->map,
4036c5276c8SMarius Strobl 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
4044124f62eSJohn Baldwin 	error = mpt_issue_cfg_req(mpt, req, &params, mpt_page->paddr,
4057ee37807SMarius Strobl 	    le32toh(ext_page_req->len), TRUE, 5000);
406ee98c4a5SJohn Baldwin 	if (error != 0) {
407ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "mpt_user_read_extcfg_page timed out\n");
408ee98c4a5SJohn Baldwin 		return (ETIMEDOUT);
409ee98c4a5SJohn Baldwin 	}
410ee98c4a5SJohn Baldwin 
4117ee37807SMarius Strobl 	ext_page_req->ioc_status = htole16(req->IOCStatus);
4124124f62eSJohn Baldwin 	if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS)
4134124f62eSJohn Baldwin 		bus_dmamap_sync(mpt_page->tag, mpt_page->map,
4146c5276c8SMarius Strobl 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
415ee98c4a5SJohn Baldwin 	mpt_free_request(mpt, req);
416ee98c4a5SJohn Baldwin 	return (0);
417ee98c4a5SJohn Baldwin }
418ee98c4a5SJohn Baldwin 
419ee98c4a5SJohn Baldwin static int
420ee98c4a5SJohn Baldwin mpt_user_write_cfg_page(struct mpt_softc *mpt,
4214124f62eSJohn Baldwin     struct mpt_cfg_page_req *page_req, struct mpt_page_memory *mpt_page)
422ee98c4a5SJohn Baldwin {
423ee98c4a5SJohn Baldwin 	CONFIG_PAGE_HEADER *hdr;
424ee98c4a5SJohn Baldwin 	request_t    *req;
425ee98c4a5SJohn Baldwin 	cfgparms_t    params;
426ee98c4a5SJohn Baldwin 	u_int	      hdr_attr;
427ee98c4a5SJohn Baldwin 	int	      error;
428ee98c4a5SJohn Baldwin 
4294124f62eSJohn Baldwin 	hdr = mpt_page->vaddr;
430ee98c4a5SJohn Baldwin 	hdr_attr = hdr->PageType & MPI_CONFIG_PAGEATTR_MASK;
431ee98c4a5SJohn Baldwin 	if (hdr_attr != MPI_CONFIG_PAGEATTR_CHANGEABLE &&
432ee98c4a5SJohn Baldwin 	    hdr_attr != MPI_CONFIG_PAGEATTR_PERSISTENT) {
433ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "page type 0x%x not changeable\n",
434ee98c4a5SJohn Baldwin 			hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
435ee98c4a5SJohn Baldwin 		return (EINVAL);
436ee98c4a5SJohn Baldwin 	}
437ee98c4a5SJohn Baldwin 
438ee98c4a5SJohn Baldwin #if	0
439ee98c4a5SJohn Baldwin 	/*
440ee98c4a5SJohn Baldwin 	 * We shouldn't mask off other bits here.
441ee98c4a5SJohn Baldwin 	 */
442ee98c4a5SJohn Baldwin 	hdr->PageType &= ~MPI_CONFIG_PAGETYPE_MASK;
443ee98c4a5SJohn Baldwin #endif
444ee98c4a5SJohn Baldwin 
445ee98c4a5SJohn Baldwin 	req = mpt_get_request(mpt, TRUE);
446ee98c4a5SJohn Baldwin 	if (req == NULL)
447ee98c4a5SJohn Baldwin 		return (ENOMEM);
448ee98c4a5SJohn Baldwin 
4496c5276c8SMarius Strobl 	bus_dmamap_sync(mpt_page->tag, mpt_page->map, BUS_DMASYNC_PREREAD |
4506c5276c8SMarius Strobl 	    BUS_DMASYNC_PREWRITE);
451ee98c4a5SJohn Baldwin 
452ee98c4a5SJohn Baldwin 	/*
453ee98c4a5SJohn Baldwin 	 * There isn't any point in restoring stripped out attributes
454ee98c4a5SJohn Baldwin 	 * if you then mask them going down to issue the request.
455ee98c4a5SJohn Baldwin 	 */
456ee98c4a5SJohn Baldwin 
457ee98c4a5SJohn Baldwin 	params.Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
458ee98c4a5SJohn Baldwin 	params.PageVersion = hdr->PageVersion;
459ee98c4a5SJohn Baldwin 	params.PageLength = hdr->PageLength;
460ee98c4a5SJohn Baldwin 	params.PageNumber = hdr->PageNumber;
4617ee37807SMarius Strobl 	params.PageAddress = le32toh(page_req->page_address);
462ee98c4a5SJohn Baldwin #if	0
463ee98c4a5SJohn Baldwin 	/* Restore stripped out attributes */
464ee98c4a5SJohn Baldwin 	hdr->PageType |= hdr_attr;
465ee98c4a5SJohn Baldwin 	params.PageType = hdr->PageType & MPI_CONFIG_PAGETYPE_MASK;
466ee98c4a5SJohn Baldwin #else
467ee98c4a5SJohn Baldwin 	params.PageType = hdr->PageType;
468ee98c4a5SJohn Baldwin #endif
4694124f62eSJohn Baldwin 	error = mpt_issue_cfg_req(mpt, req, &params, mpt_page->paddr,
4707ee37807SMarius Strobl 	    le32toh(page_req->len), TRUE, 5000);
471ee98c4a5SJohn Baldwin 	if (error != 0) {
472ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "mpt_write_cfg_page timed out\n");
473ee98c4a5SJohn Baldwin 		return (ETIMEDOUT);
474ee98c4a5SJohn Baldwin 	}
475ee98c4a5SJohn Baldwin 
4767ee37807SMarius Strobl 	page_req->ioc_status = htole16(req->IOCStatus);
4776c5276c8SMarius Strobl 	bus_dmamap_sync(mpt_page->tag, mpt_page->map, BUS_DMASYNC_POSTREAD |
4786c5276c8SMarius Strobl 	    BUS_DMASYNC_POSTWRITE);
479ee98c4a5SJohn Baldwin 	mpt_free_request(mpt, req);
480ee98c4a5SJohn Baldwin 	return (0);
481ee98c4a5SJohn Baldwin }
482ee98c4a5SJohn Baldwin 
483ee98c4a5SJohn Baldwin static int
484ee98c4a5SJohn Baldwin mpt_user_reply_handler(struct mpt_softc *mpt, request_t *req,
485ee98c4a5SJohn Baldwin     uint32_t reply_desc, MSG_DEFAULT_REPLY *reply_frame)
486ee98c4a5SJohn Baldwin {
487ee98c4a5SJohn Baldwin 	MSG_RAID_ACTION_REPLY *reply;
488ee98c4a5SJohn Baldwin 	struct mpt_user_raid_action_result *res;
489ee98c4a5SJohn Baldwin 
490ee98c4a5SJohn Baldwin 	if (req == NULL)
491ee98c4a5SJohn Baldwin 		return (TRUE);
492ee98c4a5SJohn Baldwin 
493ee98c4a5SJohn Baldwin 	if (reply_frame != NULL) {
494ee98c4a5SJohn Baldwin 		reply = (MSG_RAID_ACTION_REPLY *)reply_frame;
495ee98c4a5SJohn Baldwin 		req->IOCStatus = le16toh(reply->IOCStatus);
496ee98c4a5SJohn Baldwin 		res = (struct mpt_user_raid_action_result *)
497ee98c4a5SJohn Baldwin 		    (((uint8_t *)req->req_vbuf) + MPT_RQSL(mpt));
498ee98c4a5SJohn Baldwin 		res->action_status = reply->ActionStatus;
499ee98c4a5SJohn Baldwin 		res->volume_status = reply->VolumeStatus;
500ee98c4a5SJohn Baldwin 		bcopy(&reply->ActionData, res->action_data,
501ee98c4a5SJohn Baldwin 		    sizeof(res->action_data));
502ee98c4a5SJohn Baldwin 	}
503ee98c4a5SJohn Baldwin 
504ee98c4a5SJohn Baldwin 	req->state &= ~REQ_STATE_QUEUED;
505ee98c4a5SJohn Baldwin 	req->state |= REQ_STATE_DONE;
506ee98c4a5SJohn Baldwin 	TAILQ_REMOVE(&mpt->request_pending_list, req, links);
507ee98c4a5SJohn Baldwin 
508ee98c4a5SJohn Baldwin 	if ((req->state & REQ_STATE_NEED_WAKEUP) != 0) {
509ee98c4a5SJohn Baldwin 		wakeup(req);
510ee98c4a5SJohn Baldwin 	} else if ((req->state & REQ_STATE_TIMEDOUT) != 0) {
511ee98c4a5SJohn Baldwin 		/*
512ee98c4a5SJohn Baldwin 		 * Whew- we can free this request (late completion)
513ee98c4a5SJohn Baldwin 		 */
514ee98c4a5SJohn Baldwin 		mpt_free_request(mpt, req);
515ee98c4a5SJohn Baldwin 	}
516ee98c4a5SJohn Baldwin 
517ee98c4a5SJohn Baldwin 	return (TRUE);
518ee98c4a5SJohn Baldwin }
519ee98c4a5SJohn Baldwin 
520ee98c4a5SJohn Baldwin /*
521ee98c4a5SJohn Baldwin  * We use the first part of the request buffer after the request frame
522ee98c4a5SJohn Baldwin  * to hold the action data and action status from the RAID reply.  The
523ee98c4a5SJohn Baldwin  * rest of the request buffer is used to hold the buffer for the
524ee98c4a5SJohn Baldwin  * action SGE.
525ee98c4a5SJohn Baldwin  */
526ee98c4a5SJohn Baldwin static int
527ee98c4a5SJohn Baldwin mpt_user_raid_action(struct mpt_softc *mpt, struct mpt_raid_action *raid_act,
5284124f62eSJohn Baldwin 	struct mpt_page_memory *mpt_page)
529ee98c4a5SJohn Baldwin {
530ee98c4a5SJohn Baldwin 	request_t *req;
531ee98c4a5SJohn Baldwin 	struct mpt_user_raid_action_result *res;
532ee98c4a5SJohn Baldwin 	MSG_RAID_ACTION_REQUEST *rap;
533ee98c4a5SJohn Baldwin 	SGE_SIMPLE32 *se;
534ee98c4a5SJohn Baldwin 	int error;
535ee98c4a5SJohn Baldwin 
536ee98c4a5SJohn Baldwin 	req = mpt_get_request(mpt, TRUE);
537ee98c4a5SJohn Baldwin 	if (req == NULL)
538ee98c4a5SJohn Baldwin 		return (ENOMEM);
539ee98c4a5SJohn Baldwin 	rap = req->req_vbuf;
540ee98c4a5SJohn Baldwin 	memset(rap, 0, sizeof *rap);
541ee98c4a5SJohn Baldwin 	rap->Action = raid_act->action;
542ee98c4a5SJohn Baldwin 	rap->ActionDataWord = raid_act->action_data_word;
543ee98c4a5SJohn Baldwin 	rap->Function = MPI_FUNCTION_RAID_ACTION;
544ee98c4a5SJohn Baldwin 	rap->VolumeID = raid_act->volume_id;
545ee98c4a5SJohn Baldwin 	rap->VolumeBus = raid_act->volume_bus;
546ee98c4a5SJohn Baldwin 	rap->PhysDiskNum = raid_act->phys_disk_num;
547ee98c4a5SJohn Baldwin 	se = (SGE_SIMPLE32 *)&rap->ActionDataSGE;
5484124f62eSJohn Baldwin 	if (mpt_page->vaddr != NULL && raid_act->len != 0) {
5494124f62eSJohn Baldwin 		bus_dmamap_sync(mpt_page->tag, mpt_page->map,
5506c5276c8SMarius Strobl 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
5517ee37807SMarius Strobl 		se->Address = htole32(mpt_page->paddr);
5527ee37807SMarius Strobl 		MPI_pSGE_SET_LENGTH(se, le32toh(raid_act->len));
553ee98c4a5SJohn Baldwin 		MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
554ee98c4a5SJohn Baldwin 		    MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
555ee98c4a5SJohn Baldwin 		    MPI_SGE_FLAGS_END_OF_LIST |
556cb5a9183SXin LI 		    (raid_act->write ? MPI_SGE_FLAGS_HOST_TO_IOC :
557cb5a9183SXin LI 		    MPI_SGE_FLAGS_IOC_TO_HOST)));
558ee98c4a5SJohn Baldwin 	}
5597ee37807SMarius Strobl 	se->FlagsLength = htole32(se->FlagsLength);
560ee98c4a5SJohn Baldwin 	rap->MsgContext = htole32(req->index | user_handler_id);
561ee98c4a5SJohn Baldwin 
562ee98c4a5SJohn Baldwin 	mpt_check_doorbell(mpt);
563ee98c4a5SJohn Baldwin 	mpt_send_cmd(mpt, req);
564ee98c4a5SJohn Baldwin 
565ee98c4a5SJohn Baldwin 	error = mpt_wait_req(mpt, req, REQ_STATE_DONE, REQ_STATE_DONE, TRUE,
566ee98c4a5SJohn Baldwin 	    2000);
567ee98c4a5SJohn Baldwin 	if (error != 0) {
568ee98c4a5SJohn Baldwin 		/*
569ee98c4a5SJohn Baldwin 		 * Leave request so it can be cleaned up later.
570ee98c4a5SJohn Baldwin 		 */
571ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "mpt_user_raid_action timed out\n");
572ee98c4a5SJohn Baldwin 		return (error);
573ee98c4a5SJohn Baldwin 	}
574ee98c4a5SJohn Baldwin 
5757ee37807SMarius Strobl 	raid_act->ioc_status = htole16(req->IOCStatus);
576ee98c4a5SJohn Baldwin 	if ((req->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
577ee98c4a5SJohn Baldwin 		mpt_free_request(mpt, req);
578ee98c4a5SJohn Baldwin 		return (0);
579ee98c4a5SJohn Baldwin 	}
580ee98c4a5SJohn Baldwin 
581ee98c4a5SJohn Baldwin 	res = (struct mpt_user_raid_action_result *)
582ee98c4a5SJohn Baldwin 	    (((uint8_t *)req->req_vbuf) + MPT_RQSL(mpt));
583ee98c4a5SJohn Baldwin 	raid_act->volume_status = res->volume_status;
584ee98c4a5SJohn Baldwin 	raid_act->action_status = res->action_status;
585ee98c4a5SJohn Baldwin 	bcopy(res->action_data, raid_act->action_data,
586ee98c4a5SJohn Baldwin 	    sizeof(res->action_data));
5874124f62eSJohn Baldwin 	if (mpt_page->vaddr != NULL)
5884124f62eSJohn Baldwin 		bus_dmamap_sync(mpt_page->tag, mpt_page->map,
5896c5276c8SMarius Strobl 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
590ee98c4a5SJohn Baldwin 	mpt_free_request(mpt, req);
591ee98c4a5SJohn Baldwin 	return (0);
592ee98c4a5SJohn Baldwin }
593ee98c4a5SJohn Baldwin 
594ee98c4a5SJohn Baldwin static int
59500b4e54aSWarner Losh mpt_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
596ee98c4a5SJohn Baldwin {
597ee98c4a5SJohn Baldwin 	struct mpt_softc *mpt;
598ee98c4a5SJohn Baldwin 	struct mpt_cfg_page_req *page_req;
599ee98c4a5SJohn Baldwin 	struct mpt_ext_cfg_page_req *ext_page_req;
600ee98c4a5SJohn Baldwin 	struct mpt_raid_action *raid_act;
6014124f62eSJohn Baldwin 	struct mpt_page_memory mpt_page;
602ee98c4a5SJohn Baldwin #ifdef __amd64__
603ee98c4a5SJohn Baldwin 	struct mpt_cfg_page_req32 *page_req32;
604ee98c4a5SJohn Baldwin 	struct mpt_cfg_page_req page_req_swab;
605ee98c4a5SJohn Baldwin 	struct mpt_ext_cfg_page_req32 *ext_page_req32;
606ee98c4a5SJohn Baldwin 	struct mpt_ext_cfg_page_req ext_page_req_swab;
607ee98c4a5SJohn Baldwin 	struct mpt_raid_action32 *raid_act32;
608ee98c4a5SJohn Baldwin 	struct mpt_raid_action raid_act_swab;
609ee98c4a5SJohn Baldwin #endif
610ee98c4a5SJohn Baldwin 	int error;
611ee98c4a5SJohn Baldwin 
612ee98c4a5SJohn Baldwin 	mpt = dev->si_drv1;
613ee98c4a5SJohn Baldwin 	page_req = (void *)arg;
614ee98c4a5SJohn Baldwin 	ext_page_req = (void *)arg;
615ee98c4a5SJohn Baldwin 	raid_act = (void *)arg;
6164124f62eSJohn Baldwin 	mpt_page.vaddr = NULL;
617ee98c4a5SJohn Baldwin 
618ee98c4a5SJohn Baldwin #ifdef __amd64__
619ee98c4a5SJohn Baldwin 	/* Convert 32-bit structs to native ones. */
620ee98c4a5SJohn Baldwin 	page_req32 = (void *)arg;
621ee98c4a5SJohn Baldwin 	ext_page_req32 = (void *)arg;
622ee98c4a5SJohn Baldwin 	raid_act32 = (void *)arg;
623ee98c4a5SJohn Baldwin 	switch (cmd) {
624ee98c4a5SJohn Baldwin 	case MPTIO_READ_CFG_HEADER32:
625ee98c4a5SJohn Baldwin 	case MPTIO_READ_CFG_PAGE32:
626ee98c4a5SJohn Baldwin 	case MPTIO_WRITE_CFG_PAGE32:
627ee98c4a5SJohn Baldwin 		page_req = &page_req_swab;
628ee98c4a5SJohn Baldwin 		page_req->header = page_req32->header;
629ee98c4a5SJohn Baldwin 		page_req->page_address = page_req32->page_address;
630ee98c4a5SJohn Baldwin 		page_req->buf = PTRIN(page_req32->buf);
631ee98c4a5SJohn Baldwin 		page_req->len = page_req32->len;
632ee98c4a5SJohn Baldwin 		page_req->ioc_status = page_req32->ioc_status;
633ee98c4a5SJohn Baldwin 		break;
634ee98c4a5SJohn Baldwin 	case MPTIO_READ_EXT_CFG_HEADER32:
635ee98c4a5SJohn Baldwin 	case MPTIO_READ_EXT_CFG_PAGE32:
636ee98c4a5SJohn Baldwin 		ext_page_req = &ext_page_req_swab;
637ee98c4a5SJohn Baldwin 		ext_page_req->header = ext_page_req32->header;
638ee98c4a5SJohn Baldwin 		ext_page_req->page_address = ext_page_req32->page_address;
639ee98c4a5SJohn Baldwin 		ext_page_req->buf = PTRIN(ext_page_req32->buf);
640ee98c4a5SJohn Baldwin 		ext_page_req->len = ext_page_req32->len;
641ee98c4a5SJohn Baldwin 		ext_page_req->ioc_status = ext_page_req32->ioc_status;
642ee98c4a5SJohn Baldwin 		break;
643ee98c4a5SJohn Baldwin 	case MPTIO_RAID_ACTION32:
644ee98c4a5SJohn Baldwin 		raid_act = &raid_act_swab;
645ee98c4a5SJohn Baldwin 		raid_act->action = raid_act32->action;
646ee98c4a5SJohn Baldwin 		raid_act->volume_bus = raid_act32->volume_bus;
647ee98c4a5SJohn Baldwin 		raid_act->volume_id = raid_act32->volume_id;
648ee98c4a5SJohn Baldwin 		raid_act->phys_disk_num = raid_act32->phys_disk_num;
649ee98c4a5SJohn Baldwin 		raid_act->action_data_word = raid_act32->action_data_word;
650ee98c4a5SJohn Baldwin 		raid_act->buf = PTRIN(raid_act32->buf);
651ee98c4a5SJohn Baldwin 		raid_act->len = raid_act32->len;
652ee98c4a5SJohn Baldwin 		raid_act->volume_status = raid_act32->volume_status;
653ee98c4a5SJohn Baldwin 		bcopy(raid_act32->action_data, raid_act->action_data,
654ee98c4a5SJohn Baldwin 		    sizeof(raid_act->action_data));
655ee98c4a5SJohn Baldwin 		raid_act->action_status = raid_act32->action_status;
656ee98c4a5SJohn Baldwin 		raid_act->ioc_status = raid_act32->ioc_status;
657ee98c4a5SJohn Baldwin 		raid_act->write = raid_act32->write;
658ee98c4a5SJohn Baldwin 		break;
659ee98c4a5SJohn Baldwin 	}
660ee98c4a5SJohn Baldwin #endif
661ee98c4a5SJohn Baldwin 
662ee98c4a5SJohn Baldwin 	switch (cmd) {
663ee98c4a5SJohn Baldwin #ifdef __amd64__
664ee98c4a5SJohn Baldwin 	case MPTIO_READ_CFG_HEADER32:
665ee98c4a5SJohn Baldwin #endif
666ee98c4a5SJohn Baldwin 	case MPTIO_READ_CFG_HEADER:
667ee98c4a5SJohn Baldwin 		MPT_LOCK(mpt);
668ee98c4a5SJohn Baldwin 		error = mpt_user_read_cfg_header(mpt, page_req);
669ee98c4a5SJohn Baldwin 		MPT_UNLOCK(mpt);
670ee98c4a5SJohn Baldwin 		break;
671ee98c4a5SJohn Baldwin #ifdef __amd64__
672ee98c4a5SJohn Baldwin 	case MPTIO_READ_CFG_PAGE32:
673ee98c4a5SJohn Baldwin #endif
674ee98c4a5SJohn Baldwin 	case MPTIO_READ_CFG_PAGE:
6758276c414SEd Maste 		if (page_req->len < (int)sizeof(CONFIG_PAGE_HEADER)) {
6768276c414SEd Maste 			error = EINVAL;
6778276c414SEd Maste 			break;
6788276c414SEd Maste 		}
6794124f62eSJohn Baldwin 		error = mpt_alloc_buffer(mpt, &mpt_page, page_req->len);
6804124f62eSJohn Baldwin 		if (error)
681ee98c4a5SJohn Baldwin 			break;
6824124f62eSJohn Baldwin 		error = copyin(page_req->buf, mpt_page.vaddr,
683ee98c4a5SJohn Baldwin 		    sizeof(CONFIG_PAGE_HEADER));
684ee98c4a5SJohn Baldwin 		if (error)
685ee98c4a5SJohn Baldwin 			break;
686ee98c4a5SJohn Baldwin 		MPT_LOCK(mpt);
6874124f62eSJohn Baldwin 		error = mpt_user_read_cfg_page(mpt, page_req, &mpt_page);
688ee98c4a5SJohn Baldwin 		MPT_UNLOCK(mpt);
689ee98c4a5SJohn Baldwin 		if (error)
690ee98c4a5SJohn Baldwin 			break;
6914124f62eSJohn Baldwin 		error = copyout(mpt_page.vaddr, page_req->buf, page_req->len);
692ee98c4a5SJohn Baldwin 		break;
693ee98c4a5SJohn Baldwin #ifdef __amd64__
694ee98c4a5SJohn Baldwin 	case MPTIO_READ_EXT_CFG_HEADER32:
695ee98c4a5SJohn Baldwin #endif
696ee98c4a5SJohn Baldwin 	case MPTIO_READ_EXT_CFG_HEADER:
697ee98c4a5SJohn Baldwin 		MPT_LOCK(mpt);
698ee98c4a5SJohn Baldwin 		error = mpt_user_read_extcfg_header(mpt, ext_page_req);
699ee98c4a5SJohn Baldwin 		MPT_UNLOCK(mpt);
700ee98c4a5SJohn Baldwin 		break;
701ee98c4a5SJohn Baldwin #ifdef __amd64__
702ee98c4a5SJohn Baldwin 	case MPTIO_READ_EXT_CFG_PAGE32:
703ee98c4a5SJohn Baldwin #endif
704ee98c4a5SJohn Baldwin 	case MPTIO_READ_EXT_CFG_PAGE:
7058276c414SEd Maste 		if (ext_page_req->len <
7068276c414SEd Maste 		    (int)sizeof(CONFIG_EXTENDED_PAGE_HEADER)) {
7078276c414SEd Maste 			error = EINVAL;
7088276c414SEd Maste 			break;
7098276c414SEd Maste 		}
7104124f62eSJohn Baldwin 		error = mpt_alloc_buffer(mpt, &mpt_page, ext_page_req->len);
7114124f62eSJohn Baldwin 		if (error)
712ee98c4a5SJohn Baldwin 			break;
7134124f62eSJohn Baldwin 		error = copyin(ext_page_req->buf, mpt_page.vaddr,
714ee98c4a5SJohn Baldwin 		    sizeof(CONFIG_EXTENDED_PAGE_HEADER));
715ee98c4a5SJohn Baldwin 		if (error)
716ee98c4a5SJohn Baldwin 			break;
717ee98c4a5SJohn Baldwin 		MPT_LOCK(mpt);
7184124f62eSJohn Baldwin 		error = mpt_user_read_extcfg_page(mpt, ext_page_req, &mpt_page);
719ee98c4a5SJohn Baldwin 		MPT_UNLOCK(mpt);
720ee98c4a5SJohn Baldwin 		if (error)
721ee98c4a5SJohn Baldwin 			break;
7224124f62eSJohn Baldwin 		error = copyout(mpt_page.vaddr, ext_page_req->buf,
7234124f62eSJohn Baldwin 		    ext_page_req->len);
724ee98c4a5SJohn Baldwin 		break;
725ee98c4a5SJohn Baldwin #ifdef __amd64__
726ee98c4a5SJohn Baldwin 	case MPTIO_WRITE_CFG_PAGE32:
727ee98c4a5SJohn Baldwin #endif
728ee98c4a5SJohn Baldwin 	case MPTIO_WRITE_CFG_PAGE:
7298276c414SEd Maste 		if (page_req->len < (int)sizeof(CONFIG_PAGE_HEADER)) {
7308276c414SEd Maste 			error = EINVAL;
7318276c414SEd Maste 			break;
7328276c414SEd Maste 		}
7334124f62eSJohn Baldwin 		error = mpt_alloc_buffer(mpt, &mpt_page, page_req->len);
7344124f62eSJohn Baldwin 		if (error)
735ee98c4a5SJohn Baldwin 			break;
7364124f62eSJohn Baldwin 		error = copyin(page_req->buf, mpt_page.vaddr, page_req->len);
737ee98c4a5SJohn Baldwin 		if (error)
738ee98c4a5SJohn Baldwin 			break;
739ee98c4a5SJohn Baldwin 		MPT_LOCK(mpt);
7404124f62eSJohn Baldwin 		error = mpt_user_write_cfg_page(mpt, page_req, &mpt_page);
741ee98c4a5SJohn Baldwin 		MPT_UNLOCK(mpt);
742ee98c4a5SJohn Baldwin 		break;
743ee98c4a5SJohn Baldwin #ifdef __amd64__
744ee98c4a5SJohn Baldwin 	case MPTIO_RAID_ACTION32:
745ee98c4a5SJohn Baldwin #endif
746ee98c4a5SJohn Baldwin 	case MPTIO_RAID_ACTION:
747ee98c4a5SJohn Baldwin 		if (raid_act->buf != NULL) {
7484124f62eSJohn Baldwin 			error = mpt_alloc_buffer(mpt, &mpt_page, raid_act->len);
7494124f62eSJohn Baldwin 			if (error)
750ee98c4a5SJohn Baldwin 				break;
7514124f62eSJohn Baldwin 			error = copyin(raid_act->buf, mpt_page.vaddr,
7524124f62eSJohn Baldwin 			    raid_act->len);
753ee98c4a5SJohn Baldwin 			if (error)
754ee98c4a5SJohn Baldwin 				break;
755ee98c4a5SJohn Baldwin 		}
756ee98c4a5SJohn Baldwin 		MPT_LOCK(mpt);
7574124f62eSJohn Baldwin 		error = mpt_user_raid_action(mpt, raid_act, &mpt_page);
758ee98c4a5SJohn Baldwin 		MPT_UNLOCK(mpt);
759ee98c4a5SJohn Baldwin 		if (error)
760ee98c4a5SJohn Baldwin 			break;
7614124f62eSJohn Baldwin 		if (raid_act->buf != NULL)
7624124f62eSJohn Baldwin 			error = copyout(mpt_page.vaddr, raid_act->buf,
7634124f62eSJohn Baldwin 			    raid_act->len);
764ee98c4a5SJohn Baldwin 		break;
765ee98c4a5SJohn Baldwin 	default:
766ee98c4a5SJohn Baldwin 		error = ENOIOCTL;
767ee98c4a5SJohn Baldwin 		break;
768ee98c4a5SJohn Baldwin 	}
769ee98c4a5SJohn Baldwin 
7704124f62eSJohn Baldwin 	mpt_free_buffer(&mpt_page);
771ee98c4a5SJohn Baldwin 
772ee98c4a5SJohn Baldwin 	if (error)
773ee98c4a5SJohn Baldwin 		return (error);
774ee98c4a5SJohn Baldwin 
775ee98c4a5SJohn Baldwin #ifdef __amd64__
776ee98c4a5SJohn Baldwin 	/* Convert native structs to 32-bit ones. */
777ee98c4a5SJohn Baldwin 	switch (cmd) {
778ee98c4a5SJohn Baldwin 	case MPTIO_READ_CFG_HEADER32:
779ee98c4a5SJohn Baldwin 	case MPTIO_READ_CFG_PAGE32:
780ee98c4a5SJohn Baldwin 	case MPTIO_WRITE_CFG_PAGE32:
781ee98c4a5SJohn Baldwin 		page_req32->header = page_req->header;
782ee98c4a5SJohn Baldwin 		page_req32->page_address = page_req->page_address;
783ee98c4a5SJohn Baldwin 		page_req32->buf = PTROUT(page_req->buf);
784ee98c4a5SJohn Baldwin 		page_req32->len = page_req->len;
785ee98c4a5SJohn Baldwin 		page_req32->ioc_status = page_req->ioc_status;
786ee98c4a5SJohn Baldwin 		break;
787ee98c4a5SJohn Baldwin 	case MPTIO_READ_EXT_CFG_HEADER32:
788ee98c4a5SJohn Baldwin 	case MPTIO_READ_EXT_CFG_PAGE32:
789ee98c4a5SJohn Baldwin 		ext_page_req32->header = ext_page_req->header;
790ee98c4a5SJohn Baldwin 		ext_page_req32->page_address = ext_page_req->page_address;
791ee98c4a5SJohn Baldwin 		ext_page_req32->buf = PTROUT(ext_page_req->buf);
792ee98c4a5SJohn Baldwin 		ext_page_req32->len = ext_page_req->len;
793ee98c4a5SJohn Baldwin 		ext_page_req32->ioc_status = ext_page_req->ioc_status;
794ee98c4a5SJohn Baldwin 		break;
795ee98c4a5SJohn Baldwin 	case MPTIO_RAID_ACTION32:
796ee98c4a5SJohn Baldwin 		raid_act32->action = raid_act->action;
797ee98c4a5SJohn Baldwin 		raid_act32->volume_bus = raid_act->volume_bus;
798ee98c4a5SJohn Baldwin 		raid_act32->volume_id = raid_act->volume_id;
799ee98c4a5SJohn Baldwin 		raid_act32->phys_disk_num = raid_act->phys_disk_num;
800ee98c4a5SJohn Baldwin 		raid_act32->action_data_word = raid_act->action_data_word;
801ee98c4a5SJohn Baldwin 		raid_act32->buf = PTROUT(raid_act->buf);
802ee98c4a5SJohn Baldwin 		raid_act32->len = raid_act->len;
803ee98c4a5SJohn Baldwin 		raid_act32->volume_status = raid_act->volume_status;
804ee98c4a5SJohn Baldwin 		bcopy(raid_act->action_data, raid_act32->action_data,
805ee98c4a5SJohn Baldwin 		    sizeof(raid_act->action_data));
806ee98c4a5SJohn Baldwin 		raid_act32->action_status = raid_act->action_status;
807ee98c4a5SJohn Baldwin 		raid_act32->ioc_status = raid_act->ioc_status;
808ee98c4a5SJohn Baldwin 		raid_act32->write = raid_act->write;
809ee98c4a5SJohn Baldwin 		break;
810ee98c4a5SJohn Baldwin 	}
811ee98c4a5SJohn Baldwin #endif
812ee98c4a5SJohn Baldwin 
813ee98c4a5SJohn Baldwin 	return (0);
814ee98c4a5SJohn Baldwin }
815