xref: /freebsd/sys/dev/mpt/mpt_user.c (revision fdafd315)
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/param.h>
36562894f0SBrooks Davis #ifdef __amd64__
37562894f0SBrooks Davis #include <sys/abi_compat.h>
38562894f0SBrooks Davis #endif
39ee98c4a5SJohn Baldwin #include <sys/conf.h>
40ee98c4a5SJohn Baldwin #include <sys/errno.h>
41ee98c4a5SJohn Baldwin #include <sys/ioccom.h>
42ee98c4a5SJohn Baldwin #include <sys/mpt_ioctl.h>
43ee98c4a5SJohn Baldwin 
44ee98c4a5SJohn Baldwin #include <dev/mpt/mpt.h>
45ee98c4a5SJohn Baldwin 
46ee98c4a5SJohn Baldwin struct mpt_user_raid_action_result {
47ee98c4a5SJohn Baldwin 	uint32_t	volume_status;
48ee98c4a5SJohn Baldwin 	uint32_t	action_data[4];
49ee98c4a5SJohn Baldwin 	uint16_t	action_status;
50ee98c4a5SJohn Baldwin };
51ee98c4a5SJohn Baldwin 
524124f62eSJohn Baldwin struct mpt_page_memory {
534124f62eSJohn Baldwin 	bus_dma_tag_t	tag;
544124f62eSJohn Baldwin 	bus_dmamap_t	map;
554124f62eSJohn Baldwin 	bus_addr_t	paddr;
564124f62eSJohn Baldwin 	void		*vaddr;
574124f62eSJohn Baldwin };
584124f62eSJohn Baldwin 
59ee98c4a5SJohn Baldwin static mpt_probe_handler_t	mpt_user_probe;
60ee98c4a5SJohn Baldwin static mpt_attach_handler_t	mpt_user_attach;
61ee98c4a5SJohn Baldwin static mpt_enable_handler_t	mpt_user_enable;
62ee98c4a5SJohn Baldwin static mpt_ready_handler_t	mpt_user_ready;
63ee98c4a5SJohn Baldwin static mpt_event_handler_t	mpt_user_event;
64ee98c4a5SJohn Baldwin static mpt_reset_handler_t	mpt_user_reset;
65ee98c4a5SJohn Baldwin static mpt_detach_handler_t	mpt_user_detach;
66ee98c4a5SJohn Baldwin 
67ee98c4a5SJohn Baldwin static struct mpt_personality mpt_user_personality = {
68ee98c4a5SJohn Baldwin 	.name		= "mpt_user",
69ee98c4a5SJohn Baldwin 	.probe		= mpt_user_probe,
70ee98c4a5SJohn Baldwin 	.attach		= mpt_user_attach,
71ee98c4a5SJohn Baldwin 	.enable		= mpt_user_enable,
72ee98c4a5SJohn Baldwin 	.ready		= mpt_user_ready,
73ee98c4a5SJohn Baldwin 	.event		= mpt_user_event,
74ee98c4a5SJohn Baldwin 	.reset		= mpt_user_reset,
75ee98c4a5SJohn Baldwin 	.detach		= mpt_user_detach,
76ee98c4a5SJohn Baldwin };
77ee98c4a5SJohn Baldwin 
78ee98c4a5SJohn Baldwin DECLARE_MPT_PERSONALITY(mpt_user, SI_ORDER_SECOND);
79ee98c4a5SJohn Baldwin 
80ee98c4a5SJohn Baldwin static mpt_reply_handler_t	mpt_user_reply_handler;
81ee98c4a5SJohn Baldwin 
82ee98c4a5SJohn Baldwin static d_open_t		mpt_open;
83ee98c4a5SJohn Baldwin static d_close_t	mpt_close;
84ee98c4a5SJohn Baldwin static d_ioctl_t	mpt_ioctl;
85ee98c4a5SJohn Baldwin 
86ee98c4a5SJohn Baldwin static struct cdevsw mpt_cdevsw = {
87ee98c4a5SJohn Baldwin 	.d_version =	D_VERSION,
88ee98c4a5SJohn Baldwin 	.d_flags =	0,
89ee98c4a5SJohn Baldwin 	.d_open =	mpt_open,
90ee98c4a5SJohn Baldwin 	.d_close =	mpt_close,
91ee98c4a5SJohn Baldwin 	.d_ioctl =	mpt_ioctl,
92ee98c4a5SJohn Baldwin 	.d_name =	"mpt",
93ee98c4a5SJohn Baldwin };
94ee98c4a5SJohn Baldwin 
95ee98c4a5SJohn Baldwin static MALLOC_DEFINE(M_MPTUSER, "mpt_user", "Buffers for mpt(4) ioctls");
96ee98c4a5SJohn Baldwin 
97ee98c4a5SJohn Baldwin static uint32_t user_handler_id = MPT_HANDLER_ID_NONE;
98ee98c4a5SJohn Baldwin 
9987e255acSMarius Strobl static int
mpt_user_probe(struct mpt_softc * mpt)100ee98c4a5SJohn Baldwin mpt_user_probe(struct mpt_softc *mpt)
101ee98c4a5SJohn Baldwin {
102ee98c4a5SJohn Baldwin 
103ee98c4a5SJohn Baldwin 	/* Attach to every controller. */
104ee98c4a5SJohn Baldwin 	return (0);
105ee98c4a5SJohn Baldwin }
106ee98c4a5SJohn Baldwin 
10787e255acSMarius Strobl static int
mpt_user_attach(struct mpt_softc * mpt)108ee98c4a5SJohn Baldwin mpt_user_attach(struct mpt_softc *mpt)
109ee98c4a5SJohn Baldwin {
110ee98c4a5SJohn Baldwin 	mpt_handler_t handler;
111ee98c4a5SJohn Baldwin 	int error, unit;
112ee98c4a5SJohn Baldwin 
113ee98c4a5SJohn Baldwin 	MPT_LOCK(mpt);
114ee98c4a5SJohn Baldwin 	handler.reply_handler = mpt_user_reply_handler;
115ee98c4a5SJohn Baldwin 	error = mpt_register_handler(mpt, MPT_HANDLER_REPLY, handler,
116ee98c4a5SJohn Baldwin 				     &user_handler_id);
117ee98c4a5SJohn Baldwin 	MPT_UNLOCK(mpt);
118ee98c4a5SJohn Baldwin 	if (error != 0) {
119ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "Unable to register user handler!\n");
120ee98c4a5SJohn Baldwin 		return (error);
121ee98c4a5SJohn Baldwin 	}
122ee98c4a5SJohn Baldwin 	unit = device_get_unit(mpt->dev);
123ee98c4a5SJohn Baldwin 	mpt->cdev = make_dev(&mpt_cdevsw, unit, UID_ROOT, GID_OPERATOR, 0640,
124ee98c4a5SJohn Baldwin 	    "mpt%d", unit);
125ee98c4a5SJohn Baldwin 	if (mpt->cdev == NULL) {
126ee98c4a5SJohn Baldwin 		MPT_LOCK(mpt);
127ee98c4a5SJohn Baldwin 		mpt_deregister_handler(mpt, MPT_HANDLER_REPLY, handler,
128ee98c4a5SJohn Baldwin 		    user_handler_id);
129ee98c4a5SJohn Baldwin 		MPT_UNLOCK(mpt);
130ee98c4a5SJohn Baldwin 		return (ENOMEM);
131ee98c4a5SJohn Baldwin 	}
132ee98c4a5SJohn Baldwin 	mpt->cdev->si_drv1 = mpt;
133ee98c4a5SJohn Baldwin 	return (0);
134ee98c4a5SJohn Baldwin }
135ee98c4a5SJohn Baldwin 
13687e255acSMarius Strobl static int
mpt_user_enable(struct mpt_softc * mpt)137ee98c4a5SJohn Baldwin mpt_user_enable(struct mpt_softc *mpt)
138ee98c4a5SJohn Baldwin {
139ee98c4a5SJohn Baldwin 
140ee98c4a5SJohn Baldwin 	return (0);
141ee98c4a5SJohn Baldwin }
142ee98c4a5SJohn Baldwin 
14387e255acSMarius Strobl static void
mpt_user_ready(struct mpt_softc * mpt)144ee98c4a5SJohn Baldwin mpt_user_ready(struct mpt_softc *mpt)
145ee98c4a5SJohn Baldwin {
14687e255acSMarius Strobl 
147ee98c4a5SJohn Baldwin }
148ee98c4a5SJohn Baldwin 
14987e255acSMarius Strobl static int
mpt_user_event(struct mpt_softc * mpt,request_t * req,MSG_EVENT_NOTIFY_REPLY * msg)150ee98c4a5SJohn Baldwin mpt_user_event(struct mpt_softc *mpt, request_t *req,
151ee98c4a5SJohn Baldwin     MSG_EVENT_NOTIFY_REPLY *msg)
152ee98c4a5SJohn Baldwin {
153ee98c4a5SJohn Baldwin 
154ee98c4a5SJohn Baldwin 	/* Someday we may want to let a user daemon listen for events? */
155ee98c4a5SJohn Baldwin 	return (0);
156ee98c4a5SJohn Baldwin }
157ee98c4a5SJohn Baldwin 
15887e255acSMarius Strobl static void
mpt_user_reset(struct mpt_softc * mpt,int type)159ee98c4a5SJohn Baldwin mpt_user_reset(struct mpt_softc *mpt, int type)
160ee98c4a5SJohn Baldwin {
16187e255acSMarius Strobl 
162ee98c4a5SJohn Baldwin }
163ee98c4a5SJohn Baldwin 
16487e255acSMarius Strobl static void
mpt_user_detach(struct mpt_softc * mpt)165ee98c4a5SJohn Baldwin mpt_user_detach(struct mpt_softc *mpt)
166ee98c4a5SJohn Baldwin {
167ee98c4a5SJohn Baldwin 	mpt_handler_t handler;
168ee98c4a5SJohn Baldwin 
169ee98c4a5SJohn Baldwin 	/* XXX: do a purge of pending requests? */
170ee98c4a5SJohn Baldwin 	destroy_dev(mpt->cdev);
171ee98c4a5SJohn Baldwin 
172ee98c4a5SJohn Baldwin 	MPT_LOCK(mpt);
173ee98c4a5SJohn Baldwin 	handler.reply_handler = mpt_user_reply_handler;
174ee98c4a5SJohn Baldwin 	mpt_deregister_handler(mpt, MPT_HANDLER_REPLY, handler,
175ee98c4a5SJohn Baldwin 	    user_handler_id);
176ee98c4a5SJohn Baldwin 	MPT_UNLOCK(mpt);
177ee98c4a5SJohn Baldwin }
178ee98c4a5SJohn Baldwin 
179ee98c4a5SJohn Baldwin static int
mpt_open(struct cdev * dev,int flags,int fmt,struct thread * td)18000b4e54aSWarner Losh mpt_open(struct cdev *dev, int flags, int fmt, struct thread *td)
181ee98c4a5SJohn Baldwin {
182ee98c4a5SJohn Baldwin 
183ee98c4a5SJohn Baldwin 	return (0);
184ee98c4a5SJohn Baldwin }
185ee98c4a5SJohn Baldwin 
186ee98c4a5SJohn Baldwin static int
mpt_close(struct cdev * dev,int flags,int fmt,struct thread * td)18700b4e54aSWarner Losh mpt_close(struct cdev *dev, int flags, int fmt, struct thread *td)
188ee98c4a5SJohn Baldwin {
189ee98c4a5SJohn Baldwin 
190ee98c4a5SJohn Baldwin 	return (0);
191ee98c4a5SJohn Baldwin }
192ee98c4a5SJohn Baldwin 
193ee98c4a5SJohn Baldwin static int
mpt_alloc_buffer(struct mpt_softc * mpt,struct mpt_page_memory * page_mem,size_t len)1944124f62eSJohn Baldwin mpt_alloc_buffer(struct mpt_softc *mpt, struct mpt_page_memory *page_mem,
1954124f62eSJohn Baldwin     size_t len)
1964124f62eSJohn Baldwin {
1974124f62eSJohn Baldwin 	struct mpt_map_info mi;
1984124f62eSJohn Baldwin 	int error;
1994124f62eSJohn Baldwin 
2004124f62eSJohn Baldwin 	page_mem->vaddr = NULL;
2014124f62eSJohn Baldwin 
2024124f62eSJohn Baldwin 	/* Limit requests to 16M. */
2034124f62eSJohn Baldwin 	if (len > 16 * 1024 * 1024)
2044124f62eSJohn Baldwin 		return (ENOSPC);
2054124f62eSJohn Baldwin 	error = mpt_dma_tag_create(mpt, mpt->parent_dmat, 1, 0,
2064124f62eSJohn Baldwin 	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
2074124f62eSJohn Baldwin 	    len, 1, len, 0, &page_mem->tag);
2084124f62eSJohn Baldwin 	if (error)
2094124f62eSJohn Baldwin 		return (error);
2104124f62eSJohn Baldwin 	error = bus_dmamem_alloc(page_mem->tag, &page_mem->vaddr,
2116c5276c8SMarius Strobl 	    BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &page_mem->map);
2124124f62eSJohn Baldwin 	if (error) {
2134124f62eSJohn Baldwin 		bus_dma_tag_destroy(page_mem->tag);
2144124f62eSJohn Baldwin 		return (error);
2154124f62eSJohn Baldwin 	}
2164124f62eSJohn Baldwin 	mi.mpt = mpt;
2174124f62eSJohn Baldwin 	error = bus_dmamap_load(page_mem->tag, page_mem->map, page_mem->vaddr,
2184124f62eSJohn Baldwin 	    len, mpt_map_rquest, &mi, BUS_DMA_NOWAIT);
2194124f62eSJohn Baldwin 	if (error == 0)
2204124f62eSJohn Baldwin 		error = mi.error;
2214124f62eSJohn Baldwin 	if (error) {
2224124f62eSJohn Baldwin 		bus_dmamem_free(page_mem->tag, page_mem->vaddr, page_mem->map);
2234124f62eSJohn Baldwin 		bus_dma_tag_destroy(page_mem->tag);
2244124f62eSJohn Baldwin 		page_mem->vaddr = NULL;
2254124f62eSJohn Baldwin 		return (error);
2264124f62eSJohn Baldwin 	}
2274124f62eSJohn Baldwin 	page_mem->paddr = mi.phys;
2284124f62eSJohn Baldwin 	return (0);
2294124f62eSJohn Baldwin }
2304124f62eSJohn Baldwin 
2314124f62eSJohn Baldwin static void
mpt_free_buffer(struct mpt_page_memory * page_mem)2324124f62eSJohn Baldwin mpt_free_buffer(struct mpt_page_memory *page_mem)
2334124f62eSJohn Baldwin {
2344124f62eSJohn Baldwin 
2354124f62eSJohn Baldwin 	if (page_mem->vaddr == NULL)
2364124f62eSJohn Baldwin 		return;
2374124f62eSJohn Baldwin 	bus_dmamap_unload(page_mem->tag, page_mem->map);
2384124f62eSJohn Baldwin 	bus_dmamem_free(page_mem->tag, page_mem->vaddr, page_mem->map);
2394124f62eSJohn Baldwin 	bus_dma_tag_destroy(page_mem->tag);
2404124f62eSJohn Baldwin 	page_mem->vaddr = NULL;
2414124f62eSJohn Baldwin }
2424124f62eSJohn Baldwin 
2434124f62eSJohn Baldwin static int
mpt_user_read_cfg_header(struct mpt_softc * mpt,struct mpt_cfg_page_req * page_req)244ee98c4a5SJohn Baldwin mpt_user_read_cfg_header(struct mpt_softc *mpt,
245ee98c4a5SJohn Baldwin     struct mpt_cfg_page_req *page_req)
246ee98c4a5SJohn Baldwin {
247ee98c4a5SJohn Baldwin 	request_t  *req;
248ee98c4a5SJohn Baldwin 	cfgparms_t params;
249ee98c4a5SJohn Baldwin 	MSG_CONFIG *cfgp;
250ee98c4a5SJohn Baldwin 	int	    error;
251ee98c4a5SJohn Baldwin 
252ee98c4a5SJohn Baldwin 	req = mpt_get_request(mpt, TRUE);
253ee98c4a5SJohn Baldwin 	if (req == NULL) {
254ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "mpt_user_read_cfg_header: Get request failed!\n");
255ee98c4a5SJohn Baldwin 		return (ENOMEM);
256ee98c4a5SJohn Baldwin 	}
257ee98c4a5SJohn Baldwin 
258ee98c4a5SJohn Baldwin 	params.Action = MPI_CONFIG_ACTION_PAGE_HEADER;
259ee98c4a5SJohn Baldwin 	params.PageVersion = 0;
260ee98c4a5SJohn Baldwin 	params.PageLength = 0;
261ee98c4a5SJohn Baldwin 	params.PageNumber = page_req->header.PageNumber;
262ee98c4a5SJohn Baldwin 	params.PageType = page_req->header.PageType;
2637ee37807SMarius Strobl 	params.PageAddress = le32toh(page_req->page_address);
264ee98c4a5SJohn Baldwin 	error = mpt_issue_cfg_req(mpt, req, &params, /*addr*/0, /*len*/0,
265ee98c4a5SJohn Baldwin 				  TRUE, 5000);
266ee98c4a5SJohn Baldwin 	if (error != 0) {
267ee98c4a5SJohn Baldwin 		/*
268ee98c4a5SJohn Baldwin 		 * Leave the request. Without resetting the chip, it's
269ee98c4a5SJohn Baldwin 		 * still owned by it and we'll just get into trouble
270ee98c4a5SJohn Baldwin 		 * freeing it now. Mark it as abandoned so that if it
271ee98c4a5SJohn Baldwin 		 * shows up later it can be freed.
272ee98c4a5SJohn Baldwin 		 */
273ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "read_cfg_header timed out\n");
274ee98c4a5SJohn Baldwin 		return (ETIMEDOUT);
275ee98c4a5SJohn Baldwin 	}
276ee98c4a5SJohn Baldwin 
2777ee37807SMarius Strobl 	page_req->ioc_status = htole16(req->IOCStatus);
278ee98c4a5SJohn Baldwin 	if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS) {
279ee98c4a5SJohn Baldwin 		cfgp = req->req_vbuf;
280ee98c4a5SJohn Baldwin 		bcopy(&cfgp->Header, &page_req->header,
281ee98c4a5SJohn Baldwin 		    sizeof(page_req->header));
282ee98c4a5SJohn Baldwin 	}
283ee98c4a5SJohn Baldwin 	mpt_free_request(mpt, req);
284ee98c4a5SJohn Baldwin 	return (0);
285ee98c4a5SJohn Baldwin }
286ee98c4a5SJohn Baldwin 
287ee98c4a5SJohn Baldwin static int
mpt_user_read_cfg_page(struct mpt_softc * mpt,struct mpt_cfg_page_req * page_req,struct mpt_page_memory * mpt_page)288ee98c4a5SJohn Baldwin mpt_user_read_cfg_page(struct mpt_softc *mpt, struct mpt_cfg_page_req *page_req,
2894124f62eSJohn Baldwin     struct mpt_page_memory *mpt_page)
290ee98c4a5SJohn Baldwin {
291ee98c4a5SJohn Baldwin 	CONFIG_PAGE_HEADER *hdr;
292ee98c4a5SJohn Baldwin 	request_t    *req;
293ee98c4a5SJohn Baldwin 	cfgparms_t    params;
294ee98c4a5SJohn Baldwin 	int	      error;
295ee98c4a5SJohn Baldwin 
296ee98c4a5SJohn Baldwin 	req = mpt_get_request(mpt, TRUE);
297ee98c4a5SJohn Baldwin 	if (req == NULL) {
298ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "mpt_user_read_cfg_page: Get request failed!\n");
299ee98c4a5SJohn Baldwin 		return (ENOMEM);
300ee98c4a5SJohn Baldwin 	}
301ee98c4a5SJohn Baldwin 
3024124f62eSJohn Baldwin 	hdr = mpt_page->vaddr;
303ee98c4a5SJohn Baldwin 	params.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
304ee98c4a5SJohn Baldwin 	params.PageVersion = hdr->PageVersion;
305ee98c4a5SJohn Baldwin 	params.PageLength = hdr->PageLength;
306ee98c4a5SJohn Baldwin 	params.PageNumber = hdr->PageNumber;
307ee98c4a5SJohn Baldwin 	params.PageType = hdr->PageType & MPI_CONFIG_PAGETYPE_MASK;
3087ee37807SMarius Strobl 	params.PageAddress = le32toh(page_req->page_address);
3096c5276c8SMarius Strobl 	bus_dmamap_sync(mpt_page->tag, mpt_page->map,
3106c5276c8SMarius Strobl 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
3114124f62eSJohn Baldwin 	error = mpt_issue_cfg_req(mpt, req, &params, mpt_page->paddr,
3127ee37807SMarius Strobl 	    le32toh(page_req->len), TRUE, 5000);
313ee98c4a5SJohn Baldwin 	if (error != 0) {
314ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "mpt_user_read_cfg_page timed out\n");
315ee98c4a5SJohn Baldwin 		return (ETIMEDOUT);
316ee98c4a5SJohn Baldwin 	}
317ee98c4a5SJohn Baldwin 
3187ee37807SMarius Strobl 	page_req->ioc_status = htole16(req->IOCStatus);
3194124f62eSJohn Baldwin 	if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS)
3204124f62eSJohn Baldwin 		bus_dmamap_sync(mpt_page->tag, mpt_page->map,
3216c5276c8SMarius Strobl 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
322ee98c4a5SJohn Baldwin 	mpt_free_request(mpt, req);
323ee98c4a5SJohn Baldwin 	return (0);
324ee98c4a5SJohn Baldwin }
325ee98c4a5SJohn Baldwin 
326ee98c4a5SJohn Baldwin static int
mpt_user_read_extcfg_header(struct mpt_softc * mpt,struct mpt_ext_cfg_page_req * ext_page_req)327ee98c4a5SJohn Baldwin mpt_user_read_extcfg_header(struct mpt_softc *mpt,
328ee98c4a5SJohn Baldwin     struct mpt_ext_cfg_page_req *ext_page_req)
329ee98c4a5SJohn Baldwin {
330ee98c4a5SJohn Baldwin 	request_t  *req;
331ee98c4a5SJohn Baldwin 	cfgparms_t params;
332ee98c4a5SJohn Baldwin 	MSG_CONFIG_REPLY *cfgp;
333ee98c4a5SJohn Baldwin 	int	    error;
334ee98c4a5SJohn Baldwin 
335ee98c4a5SJohn Baldwin 	req = mpt_get_request(mpt, TRUE);
336ee98c4a5SJohn Baldwin 	if (req == NULL) {
337ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "mpt_user_read_extcfg_header: Get request failed!\n");
338ee98c4a5SJohn Baldwin 		return (ENOMEM);
339ee98c4a5SJohn Baldwin 	}
340ee98c4a5SJohn Baldwin 
341ee98c4a5SJohn Baldwin 	params.Action = MPI_CONFIG_ACTION_PAGE_HEADER;
342ee98c4a5SJohn Baldwin 	params.PageVersion = ext_page_req->header.PageVersion;
343ee98c4a5SJohn Baldwin 	params.PageLength = 0;
344ee98c4a5SJohn Baldwin 	params.PageNumber = ext_page_req->header.PageNumber;
345ee98c4a5SJohn Baldwin 	params.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
3467ee37807SMarius Strobl 	params.PageAddress = le32toh(ext_page_req->page_address);
347ee98c4a5SJohn Baldwin 	params.ExtPageType = ext_page_req->header.ExtPageType;
348ee98c4a5SJohn Baldwin 	params.ExtPageLength = 0;
349ee98c4a5SJohn Baldwin 	error = mpt_issue_cfg_req(mpt, req, &params, /*addr*/0, /*len*/0,
350ee98c4a5SJohn Baldwin 				  TRUE, 5000);
351ee98c4a5SJohn Baldwin 	if (error != 0) {
352ee98c4a5SJohn Baldwin 		/*
353ee98c4a5SJohn Baldwin 		 * Leave the request. Without resetting the chip, it's
354ee98c4a5SJohn Baldwin 		 * still owned by it and we'll just get into trouble
355ee98c4a5SJohn Baldwin 		 * freeing it now. Mark it as abandoned so that if it
356ee98c4a5SJohn Baldwin 		 * shows up later it can be freed.
357ee98c4a5SJohn Baldwin 		 */
358ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "mpt_user_read_extcfg_header timed out\n");
359ee98c4a5SJohn Baldwin 		return (ETIMEDOUT);
360ee98c4a5SJohn Baldwin 	}
361ee98c4a5SJohn Baldwin 
3627ee37807SMarius Strobl 	ext_page_req->ioc_status = htole16(req->IOCStatus);
363ee98c4a5SJohn Baldwin 	if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS) {
364ee98c4a5SJohn Baldwin 		cfgp = req->req_vbuf;
365ee98c4a5SJohn Baldwin 		ext_page_req->header.PageVersion = cfgp->Header.PageVersion;
366ee98c4a5SJohn Baldwin 		ext_page_req->header.PageNumber = cfgp->Header.PageNumber;
367ee98c4a5SJohn Baldwin 		ext_page_req->header.PageType = cfgp->Header.PageType;
368ee98c4a5SJohn Baldwin 		ext_page_req->header.ExtPageLength = cfgp->ExtPageLength;
369ee98c4a5SJohn Baldwin 		ext_page_req->header.ExtPageType = cfgp->ExtPageType;
370ee98c4a5SJohn Baldwin 	}
371ee98c4a5SJohn Baldwin 	mpt_free_request(mpt, req);
372ee98c4a5SJohn Baldwin 	return (0);
373ee98c4a5SJohn Baldwin }
374ee98c4a5SJohn Baldwin 
375ee98c4a5SJohn Baldwin static int
mpt_user_read_extcfg_page(struct mpt_softc * mpt,struct mpt_ext_cfg_page_req * ext_page_req,struct mpt_page_memory * mpt_page)376ee98c4a5SJohn Baldwin mpt_user_read_extcfg_page(struct mpt_softc *mpt,
3774124f62eSJohn Baldwin     struct mpt_ext_cfg_page_req *ext_page_req, struct mpt_page_memory *mpt_page)
378ee98c4a5SJohn Baldwin {
379ee98c4a5SJohn Baldwin 	CONFIG_EXTENDED_PAGE_HEADER *hdr;
380ee98c4a5SJohn Baldwin 	request_t    *req;
381ee98c4a5SJohn Baldwin 	cfgparms_t    params;
382ee98c4a5SJohn Baldwin 	int	      error;
383ee98c4a5SJohn Baldwin 
384ee98c4a5SJohn Baldwin 	req = mpt_get_request(mpt, TRUE);
385ee98c4a5SJohn Baldwin 	if (req == NULL) {
386ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "mpt_user_read_extcfg_page: Get request failed!\n");
387ee98c4a5SJohn Baldwin 		return (ENOMEM);
388ee98c4a5SJohn Baldwin 	}
389ee98c4a5SJohn Baldwin 
3904124f62eSJohn Baldwin 	hdr = mpt_page->vaddr;
391ee98c4a5SJohn Baldwin 	params.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
392ee98c4a5SJohn Baldwin 	params.PageVersion = hdr->PageVersion;
393ee98c4a5SJohn Baldwin 	params.PageLength = 0;
394ee98c4a5SJohn Baldwin 	params.PageNumber = hdr->PageNumber;
395ee98c4a5SJohn Baldwin 	params.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
3967ee37807SMarius Strobl 	params.PageAddress = le32toh(ext_page_req->page_address);
397ee98c4a5SJohn Baldwin 	params.ExtPageType = hdr->ExtPageType;
398ee98c4a5SJohn Baldwin 	params.ExtPageLength = hdr->ExtPageLength;
3996c5276c8SMarius Strobl 	bus_dmamap_sync(mpt_page->tag, mpt_page->map,
4006c5276c8SMarius Strobl 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
4014124f62eSJohn Baldwin 	error = mpt_issue_cfg_req(mpt, req, &params, mpt_page->paddr,
4027ee37807SMarius Strobl 	    le32toh(ext_page_req->len), TRUE, 5000);
403ee98c4a5SJohn Baldwin 	if (error != 0) {
404ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "mpt_user_read_extcfg_page timed out\n");
405ee98c4a5SJohn Baldwin 		return (ETIMEDOUT);
406ee98c4a5SJohn Baldwin 	}
407ee98c4a5SJohn Baldwin 
4087ee37807SMarius Strobl 	ext_page_req->ioc_status = htole16(req->IOCStatus);
4094124f62eSJohn Baldwin 	if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS)
4104124f62eSJohn Baldwin 		bus_dmamap_sync(mpt_page->tag, mpt_page->map,
4116c5276c8SMarius Strobl 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
412ee98c4a5SJohn Baldwin 	mpt_free_request(mpt, req);
413ee98c4a5SJohn Baldwin 	return (0);
414ee98c4a5SJohn Baldwin }
415ee98c4a5SJohn Baldwin 
416ee98c4a5SJohn Baldwin static int
mpt_user_write_cfg_page(struct mpt_softc * mpt,struct mpt_cfg_page_req * page_req,struct mpt_page_memory * mpt_page)417ee98c4a5SJohn Baldwin mpt_user_write_cfg_page(struct mpt_softc *mpt,
4184124f62eSJohn Baldwin     struct mpt_cfg_page_req *page_req, struct mpt_page_memory *mpt_page)
419ee98c4a5SJohn Baldwin {
420ee98c4a5SJohn Baldwin 	CONFIG_PAGE_HEADER *hdr;
421ee98c4a5SJohn Baldwin 	request_t    *req;
422ee98c4a5SJohn Baldwin 	cfgparms_t    params;
423ee98c4a5SJohn Baldwin 	u_int	      hdr_attr;
424ee98c4a5SJohn Baldwin 	int	      error;
425ee98c4a5SJohn Baldwin 
4264124f62eSJohn Baldwin 	hdr = mpt_page->vaddr;
427ee98c4a5SJohn Baldwin 	hdr_attr = hdr->PageType & MPI_CONFIG_PAGEATTR_MASK;
428ee98c4a5SJohn Baldwin 	if (hdr_attr != MPI_CONFIG_PAGEATTR_CHANGEABLE &&
429ee98c4a5SJohn Baldwin 	    hdr_attr != MPI_CONFIG_PAGEATTR_PERSISTENT) {
430ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "page type 0x%x not changeable\n",
431ee98c4a5SJohn Baldwin 			hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
432ee98c4a5SJohn Baldwin 		return (EINVAL);
433ee98c4a5SJohn Baldwin 	}
434ee98c4a5SJohn Baldwin 
435ee98c4a5SJohn Baldwin #if	0
436ee98c4a5SJohn Baldwin 	/*
437ee98c4a5SJohn Baldwin 	 * We shouldn't mask off other bits here.
438ee98c4a5SJohn Baldwin 	 */
439ee98c4a5SJohn Baldwin 	hdr->PageType &= ~MPI_CONFIG_PAGETYPE_MASK;
440ee98c4a5SJohn Baldwin #endif
441ee98c4a5SJohn Baldwin 
442ee98c4a5SJohn Baldwin 	req = mpt_get_request(mpt, TRUE);
443ee98c4a5SJohn Baldwin 	if (req == NULL)
444ee98c4a5SJohn Baldwin 		return (ENOMEM);
445ee98c4a5SJohn Baldwin 
4466c5276c8SMarius Strobl 	bus_dmamap_sync(mpt_page->tag, mpt_page->map, BUS_DMASYNC_PREREAD |
4476c5276c8SMarius Strobl 	    BUS_DMASYNC_PREWRITE);
448ee98c4a5SJohn Baldwin 
449ee98c4a5SJohn Baldwin 	/*
450ee98c4a5SJohn Baldwin 	 * There isn't any point in restoring stripped out attributes
451ee98c4a5SJohn Baldwin 	 * if you then mask them going down to issue the request.
452ee98c4a5SJohn Baldwin 	 */
453ee98c4a5SJohn Baldwin 
454ee98c4a5SJohn Baldwin 	params.Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
455ee98c4a5SJohn Baldwin 	params.PageVersion = hdr->PageVersion;
456ee98c4a5SJohn Baldwin 	params.PageLength = hdr->PageLength;
457ee98c4a5SJohn Baldwin 	params.PageNumber = hdr->PageNumber;
4587ee37807SMarius Strobl 	params.PageAddress = le32toh(page_req->page_address);
459ee98c4a5SJohn Baldwin #if	0
460ee98c4a5SJohn Baldwin 	/* Restore stripped out attributes */
461ee98c4a5SJohn Baldwin 	hdr->PageType |= hdr_attr;
462ee98c4a5SJohn Baldwin 	params.PageType = hdr->PageType & MPI_CONFIG_PAGETYPE_MASK;
463ee98c4a5SJohn Baldwin #else
464ee98c4a5SJohn Baldwin 	params.PageType = hdr->PageType;
465ee98c4a5SJohn Baldwin #endif
4664124f62eSJohn Baldwin 	error = mpt_issue_cfg_req(mpt, req, &params, mpt_page->paddr,
4677ee37807SMarius Strobl 	    le32toh(page_req->len), TRUE, 5000);
468ee98c4a5SJohn Baldwin 	if (error != 0) {
469ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "mpt_write_cfg_page timed out\n");
470ee98c4a5SJohn Baldwin 		return (ETIMEDOUT);
471ee98c4a5SJohn Baldwin 	}
472ee98c4a5SJohn Baldwin 
4737ee37807SMarius Strobl 	page_req->ioc_status = htole16(req->IOCStatus);
4746c5276c8SMarius Strobl 	bus_dmamap_sync(mpt_page->tag, mpt_page->map, BUS_DMASYNC_POSTREAD |
4756c5276c8SMarius Strobl 	    BUS_DMASYNC_POSTWRITE);
476ee98c4a5SJohn Baldwin 	mpt_free_request(mpt, req);
477ee98c4a5SJohn Baldwin 	return (0);
478ee98c4a5SJohn Baldwin }
479ee98c4a5SJohn Baldwin 
480ee98c4a5SJohn Baldwin static int
mpt_user_reply_handler(struct mpt_softc * mpt,request_t * req,uint32_t reply_desc,MSG_DEFAULT_REPLY * reply_frame)481ee98c4a5SJohn Baldwin mpt_user_reply_handler(struct mpt_softc *mpt, request_t *req,
482ee98c4a5SJohn Baldwin     uint32_t reply_desc, MSG_DEFAULT_REPLY *reply_frame)
483ee98c4a5SJohn Baldwin {
484ee98c4a5SJohn Baldwin 	MSG_RAID_ACTION_REPLY *reply;
485ee98c4a5SJohn Baldwin 	struct mpt_user_raid_action_result *res;
486ee98c4a5SJohn Baldwin 
487ee98c4a5SJohn Baldwin 	if (req == NULL)
488ee98c4a5SJohn Baldwin 		return (TRUE);
489ee98c4a5SJohn Baldwin 
490ee98c4a5SJohn Baldwin 	if (reply_frame != NULL) {
491ee98c4a5SJohn Baldwin 		reply = (MSG_RAID_ACTION_REPLY *)reply_frame;
492ee98c4a5SJohn Baldwin 		req->IOCStatus = le16toh(reply->IOCStatus);
493ee98c4a5SJohn Baldwin 		res = (struct mpt_user_raid_action_result *)
494ee98c4a5SJohn Baldwin 		    (((uint8_t *)req->req_vbuf) + MPT_RQSL(mpt));
495ee98c4a5SJohn Baldwin 		res->action_status = reply->ActionStatus;
496ee98c4a5SJohn Baldwin 		res->volume_status = reply->VolumeStatus;
497ee98c4a5SJohn Baldwin 		bcopy(&reply->ActionData, res->action_data,
498ee98c4a5SJohn Baldwin 		    sizeof(res->action_data));
499ee98c4a5SJohn Baldwin 	}
500ee98c4a5SJohn Baldwin 
501ee98c4a5SJohn Baldwin 	req->state &= ~REQ_STATE_QUEUED;
502ee98c4a5SJohn Baldwin 	req->state |= REQ_STATE_DONE;
503ee98c4a5SJohn Baldwin 	TAILQ_REMOVE(&mpt->request_pending_list, req, links);
504ee98c4a5SJohn Baldwin 
505ee98c4a5SJohn Baldwin 	if ((req->state & REQ_STATE_NEED_WAKEUP) != 0) {
506ee98c4a5SJohn Baldwin 		wakeup(req);
507ee98c4a5SJohn Baldwin 	} else if ((req->state & REQ_STATE_TIMEDOUT) != 0) {
508ee98c4a5SJohn Baldwin 		/*
509ee98c4a5SJohn Baldwin 		 * Whew- we can free this request (late completion)
510ee98c4a5SJohn Baldwin 		 */
511ee98c4a5SJohn Baldwin 		mpt_free_request(mpt, req);
512ee98c4a5SJohn Baldwin 	}
513ee98c4a5SJohn Baldwin 
514ee98c4a5SJohn Baldwin 	return (TRUE);
515ee98c4a5SJohn Baldwin }
516ee98c4a5SJohn Baldwin 
517ee98c4a5SJohn Baldwin /*
518ee98c4a5SJohn Baldwin  * We use the first part of the request buffer after the request frame
519ee98c4a5SJohn Baldwin  * to hold the action data and action status from the RAID reply.  The
520ee98c4a5SJohn Baldwin  * rest of the request buffer is used to hold the buffer for the
521ee98c4a5SJohn Baldwin  * action SGE.
522ee98c4a5SJohn Baldwin  */
523ee98c4a5SJohn Baldwin static int
mpt_user_raid_action(struct mpt_softc * mpt,struct mpt_raid_action * raid_act,struct mpt_page_memory * mpt_page)524ee98c4a5SJohn Baldwin mpt_user_raid_action(struct mpt_softc *mpt, struct mpt_raid_action *raid_act,
5254124f62eSJohn Baldwin 	struct mpt_page_memory *mpt_page)
526ee98c4a5SJohn Baldwin {
527ee98c4a5SJohn Baldwin 	request_t *req;
528ee98c4a5SJohn Baldwin 	struct mpt_user_raid_action_result *res;
529ee98c4a5SJohn Baldwin 	MSG_RAID_ACTION_REQUEST *rap;
530ee98c4a5SJohn Baldwin 	SGE_SIMPLE32 *se;
531ee98c4a5SJohn Baldwin 	int error;
532ee98c4a5SJohn Baldwin 
533ee98c4a5SJohn Baldwin 	req = mpt_get_request(mpt, TRUE);
534ee98c4a5SJohn Baldwin 	if (req == NULL)
535ee98c4a5SJohn Baldwin 		return (ENOMEM);
536ee98c4a5SJohn Baldwin 	rap = req->req_vbuf;
537ee98c4a5SJohn Baldwin 	memset(rap, 0, sizeof *rap);
538ee98c4a5SJohn Baldwin 	rap->Action = raid_act->action;
539ee98c4a5SJohn Baldwin 	rap->ActionDataWord = raid_act->action_data_word;
540ee98c4a5SJohn Baldwin 	rap->Function = MPI_FUNCTION_RAID_ACTION;
541ee98c4a5SJohn Baldwin 	rap->VolumeID = raid_act->volume_id;
542ee98c4a5SJohn Baldwin 	rap->VolumeBus = raid_act->volume_bus;
543ee98c4a5SJohn Baldwin 	rap->PhysDiskNum = raid_act->phys_disk_num;
544ee98c4a5SJohn Baldwin 	se = (SGE_SIMPLE32 *)&rap->ActionDataSGE;
5454124f62eSJohn Baldwin 	if (mpt_page->vaddr != NULL && raid_act->len != 0) {
5464124f62eSJohn Baldwin 		bus_dmamap_sync(mpt_page->tag, mpt_page->map,
5476c5276c8SMarius Strobl 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
5487ee37807SMarius Strobl 		se->Address = htole32(mpt_page->paddr);
5497ee37807SMarius Strobl 		MPI_pSGE_SET_LENGTH(se, le32toh(raid_act->len));
550ee98c4a5SJohn Baldwin 		MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
551ee98c4a5SJohn Baldwin 		    MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
552ee98c4a5SJohn Baldwin 		    MPI_SGE_FLAGS_END_OF_LIST |
553cb5a9183SXin LI 		    (raid_act->write ? MPI_SGE_FLAGS_HOST_TO_IOC :
554cb5a9183SXin LI 		    MPI_SGE_FLAGS_IOC_TO_HOST)));
555ee98c4a5SJohn Baldwin 	}
5567ee37807SMarius Strobl 	se->FlagsLength = htole32(se->FlagsLength);
557ee98c4a5SJohn Baldwin 	rap->MsgContext = htole32(req->index | user_handler_id);
558ee98c4a5SJohn Baldwin 
559ee98c4a5SJohn Baldwin 	mpt_check_doorbell(mpt);
560ee98c4a5SJohn Baldwin 	mpt_send_cmd(mpt, req);
561ee98c4a5SJohn Baldwin 
562ee98c4a5SJohn Baldwin 	error = mpt_wait_req(mpt, req, REQ_STATE_DONE, REQ_STATE_DONE, TRUE,
563ee98c4a5SJohn Baldwin 	    2000);
564ee98c4a5SJohn Baldwin 	if (error != 0) {
565ee98c4a5SJohn Baldwin 		/*
566ee98c4a5SJohn Baldwin 		 * Leave request so it can be cleaned up later.
567ee98c4a5SJohn Baldwin 		 */
568ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "mpt_user_raid_action timed out\n");
569ee98c4a5SJohn Baldwin 		return (error);
570ee98c4a5SJohn Baldwin 	}
571ee98c4a5SJohn Baldwin 
5727ee37807SMarius Strobl 	raid_act->ioc_status = htole16(req->IOCStatus);
573ee98c4a5SJohn Baldwin 	if ((req->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
574ee98c4a5SJohn Baldwin 		mpt_free_request(mpt, req);
575ee98c4a5SJohn Baldwin 		return (0);
576ee98c4a5SJohn Baldwin 	}
577ee98c4a5SJohn Baldwin 
578ee98c4a5SJohn Baldwin 	res = (struct mpt_user_raid_action_result *)
579ee98c4a5SJohn Baldwin 	    (((uint8_t *)req->req_vbuf) + MPT_RQSL(mpt));
580ee98c4a5SJohn Baldwin 	raid_act->volume_status = res->volume_status;
581ee98c4a5SJohn Baldwin 	raid_act->action_status = res->action_status;
582ee98c4a5SJohn Baldwin 	bcopy(res->action_data, raid_act->action_data,
583ee98c4a5SJohn Baldwin 	    sizeof(res->action_data));
5844124f62eSJohn Baldwin 	if (mpt_page->vaddr != NULL)
5854124f62eSJohn Baldwin 		bus_dmamap_sync(mpt_page->tag, mpt_page->map,
5866c5276c8SMarius Strobl 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
587ee98c4a5SJohn Baldwin 	mpt_free_request(mpt, req);
588ee98c4a5SJohn Baldwin 	return (0);
589ee98c4a5SJohn Baldwin }
590ee98c4a5SJohn Baldwin 
591ee98c4a5SJohn Baldwin static int
mpt_ioctl(struct cdev * dev,u_long cmd,caddr_t arg,int flag,struct thread * td)59200b4e54aSWarner Losh mpt_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
593ee98c4a5SJohn Baldwin {
594ee98c4a5SJohn Baldwin 	struct mpt_softc *mpt;
595ee98c4a5SJohn Baldwin 	struct mpt_cfg_page_req *page_req;
596ee98c4a5SJohn Baldwin 	struct mpt_ext_cfg_page_req *ext_page_req;
597ee98c4a5SJohn Baldwin 	struct mpt_raid_action *raid_act;
5984124f62eSJohn Baldwin 	struct mpt_page_memory mpt_page;
599ee98c4a5SJohn Baldwin #ifdef __amd64__
600ee98c4a5SJohn Baldwin 	struct mpt_cfg_page_req32 *page_req32;
601ee98c4a5SJohn Baldwin 	struct mpt_cfg_page_req page_req_swab;
602ee98c4a5SJohn Baldwin 	struct mpt_ext_cfg_page_req32 *ext_page_req32;
603ee98c4a5SJohn Baldwin 	struct mpt_ext_cfg_page_req ext_page_req_swab;
604ee98c4a5SJohn Baldwin 	struct mpt_raid_action32 *raid_act32;
605ee98c4a5SJohn Baldwin 	struct mpt_raid_action raid_act_swab;
606ee98c4a5SJohn Baldwin #endif
607ee98c4a5SJohn Baldwin 	int error;
608ee98c4a5SJohn Baldwin 
609ee98c4a5SJohn Baldwin 	mpt = dev->si_drv1;
610ee98c4a5SJohn Baldwin 	page_req = (void *)arg;
611ee98c4a5SJohn Baldwin 	ext_page_req = (void *)arg;
612ee98c4a5SJohn Baldwin 	raid_act = (void *)arg;
6134124f62eSJohn Baldwin 	mpt_page.vaddr = NULL;
614ee98c4a5SJohn Baldwin 
615ee98c4a5SJohn Baldwin #ifdef __amd64__
616ee98c4a5SJohn Baldwin 	/* Convert 32-bit structs to native ones. */
617ee98c4a5SJohn Baldwin 	page_req32 = (void *)arg;
618ee98c4a5SJohn Baldwin 	ext_page_req32 = (void *)arg;
619ee98c4a5SJohn Baldwin 	raid_act32 = (void *)arg;
620ee98c4a5SJohn Baldwin 	switch (cmd) {
621ee98c4a5SJohn Baldwin 	case MPTIO_READ_CFG_HEADER32:
622ee98c4a5SJohn Baldwin 	case MPTIO_READ_CFG_PAGE32:
623ee98c4a5SJohn Baldwin 	case MPTIO_WRITE_CFG_PAGE32:
624ee98c4a5SJohn Baldwin 		page_req = &page_req_swab;
625ee98c4a5SJohn Baldwin 		page_req->header = page_req32->header;
626ee98c4a5SJohn Baldwin 		page_req->page_address = page_req32->page_address;
627ee98c4a5SJohn Baldwin 		page_req->buf = PTRIN(page_req32->buf);
628ee98c4a5SJohn Baldwin 		page_req->len = page_req32->len;
629ee98c4a5SJohn Baldwin 		page_req->ioc_status = page_req32->ioc_status;
630ee98c4a5SJohn Baldwin 		break;
631ee98c4a5SJohn Baldwin 	case MPTIO_READ_EXT_CFG_HEADER32:
632ee98c4a5SJohn Baldwin 	case MPTIO_READ_EXT_CFG_PAGE32:
633ee98c4a5SJohn Baldwin 		ext_page_req = &ext_page_req_swab;
634ee98c4a5SJohn Baldwin 		ext_page_req->header = ext_page_req32->header;
635ee98c4a5SJohn Baldwin 		ext_page_req->page_address = ext_page_req32->page_address;
636ee98c4a5SJohn Baldwin 		ext_page_req->buf = PTRIN(ext_page_req32->buf);
637ee98c4a5SJohn Baldwin 		ext_page_req->len = ext_page_req32->len;
638ee98c4a5SJohn Baldwin 		ext_page_req->ioc_status = ext_page_req32->ioc_status;
639ee98c4a5SJohn Baldwin 		break;
640ee98c4a5SJohn Baldwin 	case MPTIO_RAID_ACTION32:
641ee98c4a5SJohn Baldwin 		raid_act = &raid_act_swab;
642ee98c4a5SJohn Baldwin 		raid_act->action = raid_act32->action;
643ee98c4a5SJohn Baldwin 		raid_act->volume_bus = raid_act32->volume_bus;
644ee98c4a5SJohn Baldwin 		raid_act->volume_id = raid_act32->volume_id;
645ee98c4a5SJohn Baldwin 		raid_act->phys_disk_num = raid_act32->phys_disk_num;
646ee98c4a5SJohn Baldwin 		raid_act->action_data_word = raid_act32->action_data_word;
647ee98c4a5SJohn Baldwin 		raid_act->buf = PTRIN(raid_act32->buf);
648ee98c4a5SJohn Baldwin 		raid_act->len = raid_act32->len;
649ee98c4a5SJohn Baldwin 		raid_act->volume_status = raid_act32->volume_status;
650ee98c4a5SJohn Baldwin 		bcopy(raid_act32->action_data, raid_act->action_data,
651ee98c4a5SJohn Baldwin 		    sizeof(raid_act->action_data));
652ee98c4a5SJohn Baldwin 		raid_act->action_status = raid_act32->action_status;
653ee98c4a5SJohn Baldwin 		raid_act->ioc_status = raid_act32->ioc_status;
654ee98c4a5SJohn Baldwin 		raid_act->write = raid_act32->write;
655ee98c4a5SJohn Baldwin 		break;
656ee98c4a5SJohn Baldwin 	}
657ee98c4a5SJohn Baldwin #endif
658ee98c4a5SJohn Baldwin 
659ee98c4a5SJohn Baldwin 	switch (cmd) {
660ee98c4a5SJohn Baldwin #ifdef __amd64__
661ee98c4a5SJohn Baldwin 	case MPTIO_READ_CFG_HEADER32:
662ee98c4a5SJohn Baldwin #endif
663ee98c4a5SJohn Baldwin 	case MPTIO_READ_CFG_HEADER:
664ee98c4a5SJohn Baldwin 		MPT_LOCK(mpt);
665ee98c4a5SJohn Baldwin 		error = mpt_user_read_cfg_header(mpt, page_req);
666ee98c4a5SJohn Baldwin 		MPT_UNLOCK(mpt);
667ee98c4a5SJohn Baldwin 		break;
668ee98c4a5SJohn Baldwin #ifdef __amd64__
669ee98c4a5SJohn Baldwin 	case MPTIO_READ_CFG_PAGE32:
670ee98c4a5SJohn Baldwin #endif
671ee98c4a5SJohn Baldwin 	case MPTIO_READ_CFG_PAGE:
6728276c414SEd Maste 		if (page_req->len < (int)sizeof(CONFIG_PAGE_HEADER)) {
6738276c414SEd Maste 			error = EINVAL;
6748276c414SEd Maste 			break;
6758276c414SEd Maste 		}
6764124f62eSJohn Baldwin 		error = mpt_alloc_buffer(mpt, &mpt_page, page_req->len);
6774124f62eSJohn Baldwin 		if (error)
678ee98c4a5SJohn Baldwin 			break;
6794124f62eSJohn Baldwin 		error = copyin(page_req->buf, mpt_page.vaddr,
680ee98c4a5SJohn Baldwin 		    sizeof(CONFIG_PAGE_HEADER));
681ee98c4a5SJohn Baldwin 		if (error)
682ee98c4a5SJohn Baldwin 			break;
683ee98c4a5SJohn Baldwin 		MPT_LOCK(mpt);
6844124f62eSJohn Baldwin 		error = mpt_user_read_cfg_page(mpt, page_req, &mpt_page);
685ee98c4a5SJohn Baldwin 		MPT_UNLOCK(mpt);
686ee98c4a5SJohn Baldwin 		if (error)
687ee98c4a5SJohn Baldwin 			break;
6884124f62eSJohn Baldwin 		error = copyout(mpt_page.vaddr, page_req->buf, page_req->len);
689ee98c4a5SJohn Baldwin 		break;
690ee98c4a5SJohn Baldwin #ifdef __amd64__
691ee98c4a5SJohn Baldwin 	case MPTIO_READ_EXT_CFG_HEADER32:
692ee98c4a5SJohn Baldwin #endif
693ee98c4a5SJohn Baldwin 	case MPTIO_READ_EXT_CFG_HEADER:
694ee98c4a5SJohn Baldwin 		MPT_LOCK(mpt);
695ee98c4a5SJohn Baldwin 		error = mpt_user_read_extcfg_header(mpt, ext_page_req);
696ee98c4a5SJohn Baldwin 		MPT_UNLOCK(mpt);
697ee98c4a5SJohn Baldwin 		break;
698ee98c4a5SJohn Baldwin #ifdef __amd64__
699ee98c4a5SJohn Baldwin 	case MPTIO_READ_EXT_CFG_PAGE32:
700ee98c4a5SJohn Baldwin #endif
701ee98c4a5SJohn Baldwin 	case MPTIO_READ_EXT_CFG_PAGE:
7028276c414SEd Maste 		if (ext_page_req->len <
7038276c414SEd Maste 		    (int)sizeof(CONFIG_EXTENDED_PAGE_HEADER)) {
7048276c414SEd Maste 			error = EINVAL;
7058276c414SEd Maste 			break;
7068276c414SEd Maste 		}
7074124f62eSJohn Baldwin 		error = mpt_alloc_buffer(mpt, &mpt_page, ext_page_req->len);
7084124f62eSJohn Baldwin 		if (error)
709ee98c4a5SJohn Baldwin 			break;
7104124f62eSJohn Baldwin 		error = copyin(ext_page_req->buf, mpt_page.vaddr,
711ee98c4a5SJohn Baldwin 		    sizeof(CONFIG_EXTENDED_PAGE_HEADER));
712ee98c4a5SJohn Baldwin 		if (error)
713ee98c4a5SJohn Baldwin 			break;
714ee98c4a5SJohn Baldwin 		MPT_LOCK(mpt);
7154124f62eSJohn Baldwin 		error = mpt_user_read_extcfg_page(mpt, ext_page_req, &mpt_page);
716ee98c4a5SJohn Baldwin 		MPT_UNLOCK(mpt);
717ee98c4a5SJohn Baldwin 		if (error)
718ee98c4a5SJohn Baldwin 			break;
7194124f62eSJohn Baldwin 		error = copyout(mpt_page.vaddr, ext_page_req->buf,
7204124f62eSJohn Baldwin 		    ext_page_req->len);
721ee98c4a5SJohn Baldwin 		break;
722ee98c4a5SJohn Baldwin #ifdef __amd64__
723ee98c4a5SJohn Baldwin 	case MPTIO_WRITE_CFG_PAGE32:
724ee98c4a5SJohn Baldwin #endif
725ee98c4a5SJohn Baldwin 	case MPTIO_WRITE_CFG_PAGE:
7268276c414SEd Maste 		if (page_req->len < (int)sizeof(CONFIG_PAGE_HEADER)) {
7278276c414SEd Maste 			error = EINVAL;
7288276c414SEd Maste 			break;
7298276c414SEd Maste 		}
7304124f62eSJohn Baldwin 		error = mpt_alloc_buffer(mpt, &mpt_page, page_req->len);
7314124f62eSJohn Baldwin 		if (error)
732ee98c4a5SJohn Baldwin 			break;
7334124f62eSJohn Baldwin 		error = copyin(page_req->buf, mpt_page.vaddr, page_req->len);
734ee98c4a5SJohn Baldwin 		if (error)
735ee98c4a5SJohn Baldwin 			break;
736ee98c4a5SJohn Baldwin 		MPT_LOCK(mpt);
7374124f62eSJohn Baldwin 		error = mpt_user_write_cfg_page(mpt, page_req, &mpt_page);
738ee98c4a5SJohn Baldwin 		MPT_UNLOCK(mpt);
739ee98c4a5SJohn Baldwin 		break;
740ee98c4a5SJohn Baldwin #ifdef __amd64__
741ee98c4a5SJohn Baldwin 	case MPTIO_RAID_ACTION32:
742ee98c4a5SJohn Baldwin #endif
743ee98c4a5SJohn Baldwin 	case MPTIO_RAID_ACTION:
744ee98c4a5SJohn Baldwin 		if (raid_act->buf != NULL) {
7454124f62eSJohn Baldwin 			error = mpt_alloc_buffer(mpt, &mpt_page, raid_act->len);
7464124f62eSJohn Baldwin 			if (error)
747ee98c4a5SJohn Baldwin 				break;
7484124f62eSJohn Baldwin 			error = copyin(raid_act->buf, mpt_page.vaddr,
7494124f62eSJohn Baldwin 			    raid_act->len);
750ee98c4a5SJohn Baldwin 			if (error)
751ee98c4a5SJohn Baldwin 				break;
752ee98c4a5SJohn Baldwin 		}
753ee98c4a5SJohn Baldwin 		MPT_LOCK(mpt);
7544124f62eSJohn Baldwin 		error = mpt_user_raid_action(mpt, raid_act, &mpt_page);
755ee98c4a5SJohn Baldwin 		MPT_UNLOCK(mpt);
756ee98c4a5SJohn Baldwin 		if (error)
757ee98c4a5SJohn Baldwin 			break;
7584124f62eSJohn Baldwin 		if (raid_act->buf != NULL)
7594124f62eSJohn Baldwin 			error = copyout(mpt_page.vaddr, raid_act->buf,
7604124f62eSJohn Baldwin 			    raid_act->len);
761ee98c4a5SJohn Baldwin 		break;
762ee98c4a5SJohn Baldwin 	default:
763ee98c4a5SJohn Baldwin 		error = ENOIOCTL;
764ee98c4a5SJohn Baldwin 		break;
765ee98c4a5SJohn Baldwin 	}
766ee98c4a5SJohn Baldwin 
7674124f62eSJohn Baldwin 	mpt_free_buffer(&mpt_page);
768ee98c4a5SJohn Baldwin 
769ee98c4a5SJohn Baldwin 	if (error)
770ee98c4a5SJohn Baldwin 		return (error);
771ee98c4a5SJohn Baldwin 
772ee98c4a5SJohn Baldwin #ifdef __amd64__
773ee98c4a5SJohn Baldwin 	/* Convert native structs to 32-bit ones. */
774ee98c4a5SJohn Baldwin 	switch (cmd) {
775ee98c4a5SJohn Baldwin 	case MPTIO_READ_CFG_HEADER32:
776ee98c4a5SJohn Baldwin 	case MPTIO_READ_CFG_PAGE32:
777ee98c4a5SJohn Baldwin 	case MPTIO_WRITE_CFG_PAGE32:
778ee98c4a5SJohn Baldwin 		page_req32->header = page_req->header;
779ee98c4a5SJohn Baldwin 		page_req32->page_address = page_req->page_address;
780ee98c4a5SJohn Baldwin 		page_req32->buf = PTROUT(page_req->buf);
781ee98c4a5SJohn Baldwin 		page_req32->len = page_req->len;
782ee98c4a5SJohn Baldwin 		page_req32->ioc_status = page_req->ioc_status;
783ee98c4a5SJohn Baldwin 		break;
784ee98c4a5SJohn Baldwin 	case MPTIO_READ_EXT_CFG_HEADER32:
785ee98c4a5SJohn Baldwin 	case MPTIO_READ_EXT_CFG_PAGE32:
786ee98c4a5SJohn Baldwin 		ext_page_req32->header = ext_page_req->header;
787ee98c4a5SJohn Baldwin 		ext_page_req32->page_address = ext_page_req->page_address;
788ee98c4a5SJohn Baldwin 		ext_page_req32->buf = PTROUT(ext_page_req->buf);
789ee98c4a5SJohn Baldwin 		ext_page_req32->len = ext_page_req->len;
790ee98c4a5SJohn Baldwin 		ext_page_req32->ioc_status = ext_page_req->ioc_status;
791ee98c4a5SJohn Baldwin 		break;
792ee98c4a5SJohn Baldwin 	case MPTIO_RAID_ACTION32:
793ee98c4a5SJohn Baldwin 		raid_act32->action = raid_act->action;
794ee98c4a5SJohn Baldwin 		raid_act32->volume_bus = raid_act->volume_bus;
795ee98c4a5SJohn Baldwin 		raid_act32->volume_id = raid_act->volume_id;
796ee98c4a5SJohn Baldwin 		raid_act32->phys_disk_num = raid_act->phys_disk_num;
797ee98c4a5SJohn Baldwin 		raid_act32->action_data_word = raid_act->action_data_word;
798ee98c4a5SJohn Baldwin 		raid_act32->buf = PTROUT(raid_act->buf);
799ee98c4a5SJohn Baldwin 		raid_act32->len = raid_act->len;
800ee98c4a5SJohn Baldwin 		raid_act32->volume_status = raid_act->volume_status;
801ee98c4a5SJohn Baldwin 		bcopy(raid_act->action_data, raid_act32->action_data,
802ee98c4a5SJohn Baldwin 		    sizeof(raid_act->action_data));
803ee98c4a5SJohn Baldwin 		raid_act32->action_status = raid_act->action_status;
804ee98c4a5SJohn Baldwin 		raid_act32->ioc_status = raid_act->ioc_status;
805ee98c4a5SJohn Baldwin 		raid_act32->write = raid_act->write;
806ee98c4a5SJohn Baldwin 		break;
807ee98c4a5SJohn Baldwin 	}
808ee98c4a5SJohn Baldwin #endif
809ee98c4a5SJohn Baldwin 
810ee98c4a5SJohn Baldwin 	return (0);
811ee98c4a5SJohn Baldwin }
812