xref: /freebsd/sys/dev/mpt/mpt_user.c (revision 4124f62e4fe38f7693568dbfa75016118fd534e4)
1ee98c4a5SJohn Baldwin /*-
2ee98c4a5SJohn Baldwin  * Copyright (c) 2008 Yahoo!, Inc.
3ee98c4a5SJohn Baldwin  * All rights reserved.
4ee98c4a5SJohn Baldwin  * Written by: John Baldwin <jhb@FreeBSD.org>
5ee98c4a5SJohn Baldwin  *
6ee98c4a5SJohn Baldwin  * Redistribution and use in source and binary forms, with or without
7ee98c4a5SJohn Baldwin  * modification, are permitted provided that the following conditions
8ee98c4a5SJohn Baldwin  * are met:
9ee98c4a5SJohn Baldwin  * 1. Redistributions of source code must retain the above copyright
10ee98c4a5SJohn Baldwin  *    notice, this list of conditions and the following disclaimer.
11ee98c4a5SJohn Baldwin  * 2. Redistributions in binary form must reproduce the above copyright
12ee98c4a5SJohn Baldwin  *    notice, this list of conditions and the following disclaimer in the
13ee98c4a5SJohn Baldwin  *    documentation and/or other materials provided with the distribution.
14ee98c4a5SJohn Baldwin  * 3. Neither the name of the author nor the names of any co-contributors
15ee98c4a5SJohn Baldwin  *    may be used to endorse or promote products derived from this software
16ee98c4a5SJohn Baldwin  *    without specific prior written permission.
17ee98c4a5SJohn Baldwin  *
18ee98c4a5SJohn Baldwin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19ee98c4a5SJohn Baldwin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20ee98c4a5SJohn Baldwin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21ee98c4a5SJohn Baldwin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22ee98c4a5SJohn Baldwin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23ee98c4a5SJohn Baldwin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24ee98c4a5SJohn Baldwin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25ee98c4a5SJohn Baldwin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26ee98c4a5SJohn Baldwin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27ee98c4a5SJohn Baldwin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28ee98c4a5SJohn Baldwin  * SUCH DAMAGE.
29ee98c4a5SJohn Baldwin  *
30ee98c4a5SJohn Baldwin  * LSI MPT-Fusion Host Adapter FreeBSD userland interface
31ee98c4a5SJohn Baldwin  */
32ee98c4a5SJohn Baldwin 
33ee98c4a5SJohn Baldwin #include <sys/cdefs.h>
34ee98c4a5SJohn Baldwin __FBSDID("$FreeBSD$");
35ee98c4a5SJohn Baldwin 
36ee98c4a5SJohn Baldwin #include <sys/param.h>
37ee98c4a5SJohn Baldwin #include <sys/conf.h>
38ee98c4a5SJohn Baldwin #include <sys/errno.h>
39ee98c4a5SJohn Baldwin #include <sys/ioccom.h>
40ee98c4a5SJohn Baldwin #include <sys/mpt_ioctl.h>
41ee98c4a5SJohn Baldwin 
42ee98c4a5SJohn Baldwin #include <dev/mpt/mpt.h>
43ee98c4a5SJohn Baldwin 
44ee98c4a5SJohn Baldwin struct mpt_user_raid_action_result {
45ee98c4a5SJohn Baldwin 	uint32_t	volume_status;
46ee98c4a5SJohn Baldwin 	uint32_t	action_data[4];
47ee98c4a5SJohn Baldwin 	uint16_t	action_status;
48ee98c4a5SJohn Baldwin };
49ee98c4a5SJohn Baldwin 
504124f62eSJohn Baldwin struct mpt_page_memory {
514124f62eSJohn Baldwin 	bus_dma_tag_t	tag;
524124f62eSJohn Baldwin 	bus_dmamap_t	map;
534124f62eSJohn Baldwin 	bus_addr_t	paddr;
544124f62eSJohn Baldwin 	void		*vaddr;
554124f62eSJohn Baldwin };
564124f62eSJohn Baldwin 
57ee98c4a5SJohn Baldwin static mpt_probe_handler_t	mpt_user_probe;
58ee98c4a5SJohn Baldwin static mpt_attach_handler_t	mpt_user_attach;
59ee98c4a5SJohn Baldwin static mpt_enable_handler_t	mpt_user_enable;
60ee98c4a5SJohn Baldwin static mpt_ready_handler_t	mpt_user_ready;
61ee98c4a5SJohn Baldwin static mpt_event_handler_t	mpt_user_event;
62ee98c4a5SJohn Baldwin static mpt_reset_handler_t	mpt_user_reset;
63ee98c4a5SJohn Baldwin static mpt_detach_handler_t	mpt_user_detach;
64ee98c4a5SJohn Baldwin 
65ee98c4a5SJohn Baldwin static struct mpt_personality mpt_user_personality = {
66ee98c4a5SJohn Baldwin 	.name		= "mpt_user",
67ee98c4a5SJohn Baldwin 	.probe		= mpt_user_probe,
68ee98c4a5SJohn Baldwin 	.attach		= mpt_user_attach,
69ee98c4a5SJohn Baldwin 	.enable		= mpt_user_enable,
70ee98c4a5SJohn Baldwin 	.ready		= mpt_user_ready,
71ee98c4a5SJohn Baldwin 	.event		= mpt_user_event,
72ee98c4a5SJohn Baldwin 	.reset		= mpt_user_reset,
73ee98c4a5SJohn Baldwin 	.detach		= mpt_user_detach,
74ee98c4a5SJohn Baldwin };
75ee98c4a5SJohn Baldwin 
76ee98c4a5SJohn Baldwin DECLARE_MPT_PERSONALITY(mpt_user, SI_ORDER_SECOND);
77ee98c4a5SJohn Baldwin 
78ee98c4a5SJohn Baldwin static mpt_reply_handler_t	mpt_user_reply_handler;
79ee98c4a5SJohn Baldwin 
80ee98c4a5SJohn Baldwin static d_open_t		mpt_open;
81ee98c4a5SJohn Baldwin static d_close_t	mpt_close;
82ee98c4a5SJohn Baldwin static d_ioctl_t	mpt_ioctl;
83ee98c4a5SJohn Baldwin 
84ee98c4a5SJohn Baldwin static struct cdevsw mpt_cdevsw = {
85ee98c4a5SJohn Baldwin 	.d_version =	D_VERSION,
86ee98c4a5SJohn Baldwin 	.d_flags =	0,
87ee98c4a5SJohn Baldwin 	.d_open =	mpt_open,
88ee98c4a5SJohn Baldwin 	.d_close =	mpt_close,
89ee98c4a5SJohn Baldwin 	.d_ioctl =	mpt_ioctl,
90ee98c4a5SJohn Baldwin 	.d_name =	"mpt",
91ee98c4a5SJohn Baldwin };
92ee98c4a5SJohn Baldwin 
93ee98c4a5SJohn Baldwin static MALLOC_DEFINE(M_MPTUSER, "mpt_user", "Buffers for mpt(4) ioctls");
94ee98c4a5SJohn Baldwin 
95ee98c4a5SJohn Baldwin static uint32_t user_handler_id = MPT_HANDLER_ID_NONE;
96ee98c4a5SJohn Baldwin 
97ee98c4a5SJohn Baldwin int
98ee98c4a5SJohn Baldwin mpt_user_probe(struct mpt_softc *mpt)
99ee98c4a5SJohn Baldwin {
100ee98c4a5SJohn Baldwin 
101ee98c4a5SJohn Baldwin 	/* Attach to every controller. */
102ee98c4a5SJohn Baldwin 	return (0);
103ee98c4a5SJohn Baldwin }
104ee98c4a5SJohn Baldwin 
105ee98c4a5SJohn Baldwin int
106ee98c4a5SJohn Baldwin mpt_user_attach(struct mpt_softc *mpt)
107ee98c4a5SJohn Baldwin {
108ee98c4a5SJohn Baldwin 	mpt_handler_t handler;
109ee98c4a5SJohn Baldwin 	int error, unit;
110ee98c4a5SJohn Baldwin 
111ee98c4a5SJohn Baldwin 	MPT_LOCK(mpt);
112ee98c4a5SJohn Baldwin 	handler.reply_handler = mpt_user_reply_handler;
113ee98c4a5SJohn Baldwin 	error = mpt_register_handler(mpt, MPT_HANDLER_REPLY, handler,
114ee98c4a5SJohn Baldwin 				     &user_handler_id);
115ee98c4a5SJohn Baldwin 	MPT_UNLOCK(mpt);
116ee98c4a5SJohn Baldwin 	if (error != 0) {
117ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "Unable to register user handler!\n");
118ee98c4a5SJohn Baldwin 		return (error);
119ee98c4a5SJohn Baldwin 	}
120ee98c4a5SJohn Baldwin 	unit = device_get_unit(mpt->dev);
121ee98c4a5SJohn Baldwin 	mpt->cdev = make_dev(&mpt_cdevsw, unit, UID_ROOT, GID_OPERATOR, 0640,
122ee98c4a5SJohn Baldwin 	    "mpt%d", unit);
123ee98c4a5SJohn Baldwin 	if (mpt->cdev == NULL) {
124ee98c4a5SJohn Baldwin 		MPT_LOCK(mpt);
125ee98c4a5SJohn Baldwin 		mpt_deregister_handler(mpt, MPT_HANDLER_REPLY, handler,
126ee98c4a5SJohn Baldwin 		    user_handler_id);
127ee98c4a5SJohn Baldwin 		MPT_UNLOCK(mpt);
128ee98c4a5SJohn Baldwin 		return (ENOMEM);
129ee98c4a5SJohn Baldwin 	}
130ee98c4a5SJohn Baldwin 	mpt->cdev->si_drv1 = mpt;
131ee98c4a5SJohn Baldwin 	return (0);
132ee98c4a5SJohn Baldwin }
133ee98c4a5SJohn Baldwin 
134ee98c4a5SJohn Baldwin int
135ee98c4a5SJohn Baldwin mpt_user_enable(struct mpt_softc *mpt)
136ee98c4a5SJohn Baldwin {
137ee98c4a5SJohn Baldwin 
138ee98c4a5SJohn Baldwin 	return (0);
139ee98c4a5SJohn Baldwin }
140ee98c4a5SJohn Baldwin 
141ee98c4a5SJohn Baldwin void
142ee98c4a5SJohn Baldwin mpt_user_ready(struct mpt_softc *mpt)
143ee98c4a5SJohn Baldwin {
144ee98c4a5SJohn Baldwin }
145ee98c4a5SJohn Baldwin 
146ee98c4a5SJohn Baldwin int
147ee98c4a5SJohn Baldwin mpt_user_event(struct mpt_softc *mpt, request_t *req,
148ee98c4a5SJohn Baldwin     MSG_EVENT_NOTIFY_REPLY *msg)
149ee98c4a5SJohn Baldwin {
150ee98c4a5SJohn Baldwin 
151ee98c4a5SJohn Baldwin 	/* Someday we may want to let a user daemon listen for events? */
152ee98c4a5SJohn Baldwin 	return (0);
153ee98c4a5SJohn Baldwin }
154ee98c4a5SJohn Baldwin 
155ee98c4a5SJohn Baldwin void
156ee98c4a5SJohn Baldwin mpt_user_reset(struct mpt_softc *mpt, int type)
157ee98c4a5SJohn Baldwin {
158ee98c4a5SJohn Baldwin }
159ee98c4a5SJohn Baldwin 
160ee98c4a5SJohn Baldwin void
161ee98c4a5SJohn Baldwin mpt_user_detach(struct mpt_softc *mpt)
162ee98c4a5SJohn Baldwin {
163ee98c4a5SJohn Baldwin 	mpt_handler_t handler;
164ee98c4a5SJohn Baldwin 
165ee98c4a5SJohn Baldwin 	/* XXX: do a purge of pending requests? */
166ee98c4a5SJohn Baldwin 	destroy_dev(mpt->cdev);
167ee98c4a5SJohn Baldwin 
168ee98c4a5SJohn Baldwin 	MPT_LOCK(mpt);
169ee98c4a5SJohn Baldwin 	handler.reply_handler = mpt_user_reply_handler;
170ee98c4a5SJohn Baldwin 	mpt_deregister_handler(mpt, MPT_HANDLER_REPLY, handler,
171ee98c4a5SJohn Baldwin 	    user_handler_id);
172ee98c4a5SJohn Baldwin 	MPT_UNLOCK(mpt);
173ee98c4a5SJohn Baldwin }
174ee98c4a5SJohn Baldwin 
175ee98c4a5SJohn Baldwin static int
176ee98c4a5SJohn Baldwin mpt_open(struct cdev *dev, int flags, int fmt, d_thread_t *td)
177ee98c4a5SJohn Baldwin {
178ee98c4a5SJohn Baldwin 
179ee98c4a5SJohn Baldwin 	return (0);
180ee98c4a5SJohn Baldwin }
181ee98c4a5SJohn Baldwin 
182ee98c4a5SJohn Baldwin static int
183ee98c4a5SJohn Baldwin mpt_close(struct cdev *dev, int flags, int fmt, d_thread_t *td)
184ee98c4a5SJohn Baldwin {
185ee98c4a5SJohn Baldwin 
186ee98c4a5SJohn Baldwin 	return (0);
187ee98c4a5SJohn Baldwin }
188ee98c4a5SJohn Baldwin 
189ee98c4a5SJohn Baldwin static int
1904124f62eSJohn Baldwin mpt_alloc_buffer(struct mpt_softc *mpt, struct mpt_page_memory *page_mem,
1914124f62eSJohn Baldwin     size_t len)
1924124f62eSJohn Baldwin {
1934124f62eSJohn Baldwin 	struct mpt_map_info mi;
1944124f62eSJohn Baldwin 	int error;
1954124f62eSJohn Baldwin 
1964124f62eSJohn Baldwin 	page_mem->vaddr = NULL;
1974124f62eSJohn Baldwin 
1984124f62eSJohn Baldwin 	/* Limit requests to 16M. */
1994124f62eSJohn Baldwin 	if (len > 16 * 1024 * 1024)
2004124f62eSJohn Baldwin 		return (ENOSPC);
2014124f62eSJohn Baldwin 	error = mpt_dma_tag_create(mpt, mpt->parent_dmat, 1, 0,
2024124f62eSJohn Baldwin 	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
2034124f62eSJohn Baldwin 	    len, 1, len, 0, &page_mem->tag);
2044124f62eSJohn Baldwin 	if (error)
2054124f62eSJohn Baldwin 		return (error);
2064124f62eSJohn Baldwin 	error = bus_dmamem_alloc(page_mem->tag, &page_mem->vaddr,
2074124f62eSJohn Baldwin 	    BUS_DMA_NOWAIT, &page_mem->map);
2084124f62eSJohn Baldwin 	if (error) {
2094124f62eSJohn Baldwin 		bus_dma_tag_destroy(page_mem->tag);
2104124f62eSJohn Baldwin 		return (error);
2114124f62eSJohn Baldwin 	}
2124124f62eSJohn Baldwin 	mi.mpt = mpt;
2134124f62eSJohn Baldwin 	error = bus_dmamap_load(page_mem->tag, page_mem->map, page_mem->vaddr,
2144124f62eSJohn Baldwin 	    len, mpt_map_rquest, &mi, BUS_DMA_NOWAIT);
2154124f62eSJohn Baldwin 	if (error == 0)
2164124f62eSJohn Baldwin 		error = mi.error;
2174124f62eSJohn Baldwin 	if (error) {
2184124f62eSJohn Baldwin 		bus_dmamem_free(page_mem->tag, page_mem->vaddr, page_mem->map);
2194124f62eSJohn Baldwin 		bus_dma_tag_destroy(page_mem->tag);
2204124f62eSJohn Baldwin 		page_mem->vaddr = NULL;
2214124f62eSJohn Baldwin 		return (error);
2224124f62eSJohn Baldwin 	}
2234124f62eSJohn Baldwin 	page_mem->paddr = mi.phys;
2244124f62eSJohn Baldwin 	return (0);
2254124f62eSJohn Baldwin }
2264124f62eSJohn Baldwin 
2274124f62eSJohn Baldwin static void
2284124f62eSJohn Baldwin mpt_free_buffer(struct mpt_page_memory *page_mem)
2294124f62eSJohn Baldwin {
2304124f62eSJohn Baldwin 
2314124f62eSJohn Baldwin 	if (page_mem->vaddr == NULL)
2324124f62eSJohn Baldwin 		return;
2334124f62eSJohn Baldwin 	bus_dmamap_unload(page_mem->tag, page_mem->map);
2344124f62eSJohn Baldwin 	bus_dmamem_free(page_mem->tag, page_mem->vaddr, page_mem->map);
2354124f62eSJohn Baldwin 	bus_dma_tag_destroy(page_mem->tag);
2364124f62eSJohn Baldwin 	page_mem->vaddr = NULL;
2374124f62eSJohn Baldwin }
2384124f62eSJohn Baldwin 
2394124f62eSJohn Baldwin static int
240ee98c4a5SJohn Baldwin mpt_user_read_cfg_header(struct mpt_softc *mpt,
241ee98c4a5SJohn Baldwin     struct mpt_cfg_page_req *page_req)
242ee98c4a5SJohn Baldwin {
243ee98c4a5SJohn Baldwin 	request_t  *req;
244ee98c4a5SJohn Baldwin 	cfgparms_t params;
245ee98c4a5SJohn Baldwin 	MSG_CONFIG *cfgp;
246ee98c4a5SJohn Baldwin 	int	    error;
247ee98c4a5SJohn Baldwin 
248ee98c4a5SJohn Baldwin 	req = mpt_get_request(mpt, TRUE);
249ee98c4a5SJohn Baldwin 	if (req == NULL) {
250ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "mpt_user_read_cfg_header: Get request failed!\n");
251ee98c4a5SJohn Baldwin 		return (ENOMEM);
252ee98c4a5SJohn Baldwin 	}
253ee98c4a5SJohn Baldwin 
254ee98c4a5SJohn Baldwin 	params.Action = MPI_CONFIG_ACTION_PAGE_HEADER;
255ee98c4a5SJohn Baldwin 	params.PageVersion = 0;
256ee98c4a5SJohn Baldwin 	params.PageLength = 0;
257ee98c4a5SJohn Baldwin 	params.PageNumber = page_req->header.PageNumber;
258ee98c4a5SJohn Baldwin 	params.PageType = page_req->header.PageType;
259ee98c4a5SJohn Baldwin 	params.PageAddress = page_req->page_address;
260ee98c4a5SJohn Baldwin 	error = mpt_issue_cfg_req(mpt, req, &params, /*addr*/0, /*len*/0,
261ee98c4a5SJohn Baldwin 				  TRUE, 5000);
262ee98c4a5SJohn Baldwin 	if (error != 0) {
263ee98c4a5SJohn Baldwin 		/*
264ee98c4a5SJohn Baldwin 		 * Leave the request. Without resetting the chip, it's
265ee98c4a5SJohn Baldwin 		 * still owned by it and we'll just get into trouble
266ee98c4a5SJohn Baldwin 		 * freeing it now. Mark it as abandoned so that if it
267ee98c4a5SJohn Baldwin 		 * shows up later it can be freed.
268ee98c4a5SJohn Baldwin 		 */
269ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "read_cfg_header timed out\n");
270ee98c4a5SJohn Baldwin 		return (ETIMEDOUT);
271ee98c4a5SJohn Baldwin 	}
272ee98c4a5SJohn Baldwin 
273ee98c4a5SJohn Baldwin 	page_req->ioc_status = req->IOCStatus;
274ee98c4a5SJohn Baldwin 	if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS) {
275ee98c4a5SJohn Baldwin 		cfgp = req->req_vbuf;
276ee98c4a5SJohn Baldwin 		bcopy(&cfgp->Header, &page_req->header,
277ee98c4a5SJohn Baldwin 		    sizeof(page_req->header));
278ee98c4a5SJohn Baldwin 	}
279ee98c4a5SJohn Baldwin 	mpt_free_request(mpt, req);
280ee98c4a5SJohn Baldwin 	return (0);
281ee98c4a5SJohn Baldwin }
282ee98c4a5SJohn Baldwin 
283ee98c4a5SJohn Baldwin static int
284ee98c4a5SJohn Baldwin mpt_user_read_cfg_page(struct mpt_softc *mpt, struct mpt_cfg_page_req *page_req,
2854124f62eSJohn Baldwin     struct mpt_page_memory *mpt_page)
286ee98c4a5SJohn Baldwin {
287ee98c4a5SJohn Baldwin 	CONFIG_PAGE_HEADER *hdr;
288ee98c4a5SJohn Baldwin 	request_t    *req;
289ee98c4a5SJohn Baldwin 	cfgparms_t    params;
290ee98c4a5SJohn Baldwin 	int	      error;
291ee98c4a5SJohn Baldwin 
292ee98c4a5SJohn Baldwin 	req = mpt_get_request(mpt, TRUE);
293ee98c4a5SJohn Baldwin 	if (req == NULL) {
294ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "mpt_user_read_cfg_page: Get request failed!\n");
295ee98c4a5SJohn Baldwin 		return (ENOMEM);
296ee98c4a5SJohn Baldwin 	}
297ee98c4a5SJohn Baldwin 
2984124f62eSJohn Baldwin 	hdr = mpt_page->vaddr;
299ee98c4a5SJohn Baldwin 	params.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
300ee98c4a5SJohn Baldwin 	params.PageVersion = hdr->PageVersion;
301ee98c4a5SJohn Baldwin 	params.PageLength = hdr->PageLength;
302ee98c4a5SJohn Baldwin 	params.PageNumber = hdr->PageNumber;
303ee98c4a5SJohn Baldwin 	params.PageType = hdr->PageType & MPI_CONFIG_PAGETYPE_MASK;
304ee98c4a5SJohn Baldwin 	params.PageAddress = page_req->page_address;
3054124f62eSJohn Baldwin 	error = mpt_issue_cfg_req(mpt, req, &params, mpt_page->paddr,
306ee98c4a5SJohn Baldwin 				  page_req->len, TRUE, 5000);
307ee98c4a5SJohn Baldwin 	if (error != 0) {
308ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "mpt_user_read_cfg_page timed out\n");
309ee98c4a5SJohn Baldwin 		return (ETIMEDOUT);
310ee98c4a5SJohn Baldwin 	}
311ee98c4a5SJohn Baldwin 
312ee98c4a5SJohn Baldwin 	page_req->ioc_status = req->IOCStatus;
3134124f62eSJohn Baldwin 	if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS)
3144124f62eSJohn Baldwin 		bus_dmamap_sync(mpt_page->tag, mpt_page->map,
315ee98c4a5SJohn Baldwin 		    BUS_DMASYNC_POSTREAD);
316ee98c4a5SJohn Baldwin 	mpt_free_request(mpt, req);
317ee98c4a5SJohn Baldwin 	return (0);
318ee98c4a5SJohn Baldwin }
319ee98c4a5SJohn Baldwin 
320ee98c4a5SJohn Baldwin static int
321ee98c4a5SJohn Baldwin mpt_user_read_extcfg_header(struct mpt_softc *mpt,
322ee98c4a5SJohn Baldwin     struct mpt_ext_cfg_page_req *ext_page_req)
323ee98c4a5SJohn Baldwin {
324ee98c4a5SJohn Baldwin 	request_t  *req;
325ee98c4a5SJohn Baldwin 	cfgparms_t params;
326ee98c4a5SJohn Baldwin 	MSG_CONFIG_REPLY *cfgp;
327ee98c4a5SJohn Baldwin 	int	    error;
328ee98c4a5SJohn Baldwin 
329ee98c4a5SJohn Baldwin 	req = mpt_get_request(mpt, TRUE);
330ee98c4a5SJohn Baldwin 	if (req == NULL) {
331ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "mpt_user_read_extcfg_header: Get request failed!\n");
332ee98c4a5SJohn Baldwin 		return (ENOMEM);
333ee98c4a5SJohn Baldwin 	}
334ee98c4a5SJohn Baldwin 
335ee98c4a5SJohn Baldwin 	params.Action = MPI_CONFIG_ACTION_PAGE_HEADER;
336ee98c4a5SJohn Baldwin 	params.PageVersion = ext_page_req->header.PageVersion;
337ee98c4a5SJohn Baldwin 	params.PageLength = 0;
338ee98c4a5SJohn Baldwin 	params.PageNumber = ext_page_req->header.PageNumber;
339ee98c4a5SJohn Baldwin 	params.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
340ee98c4a5SJohn Baldwin 	params.PageAddress = ext_page_req->page_address;
341ee98c4a5SJohn Baldwin 	params.ExtPageType = ext_page_req->header.ExtPageType;
342ee98c4a5SJohn Baldwin 	params.ExtPageLength = 0;
343ee98c4a5SJohn Baldwin 	error = mpt_issue_cfg_req(mpt, req, &params, /*addr*/0, /*len*/0,
344ee98c4a5SJohn Baldwin 				  TRUE, 5000);
345ee98c4a5SJohn Baldwin 	if (error != 0) {
346ee98c4a5SJohn Baldwin 		/*
347ee98c4a5SJohn Baldwin 		 * Leave the request. Without resetting the chip, it's
348ee98c4a5SJohn Baldwin 		 * still owned by it and we'll just get into trouble
349ee98c4a5SJohn Baldwin 		 * freeing it now. Mark it as abandoned so that if it
350ee98c4a5SJohn Baldwin 		 * shows up later it can be freed.
351ee98c4a5SJohn Baldwin 		 */
352ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "mpt_user_read_extcfg_header timed out\n");
353ee98c4a5SJohn Baldwin 		return (ETIMEDOUT);
354ee98c4a5SJohn Baldwin 	}
355ee98c4a5SJohn Baldwin 
356ee98c4a5SJohn Baldwin 	ext_page_req->ioc_status = req->IOCStatus;
357ee98c4a5SJohn Baldwin 	if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS) {
358ee98c4a5SJohn Baldwin 		cfgp = req->req_vbuf;
359ee98c4a5SJohn Baldwin 		ext_page_req->header.PageVersion = cfgp->Header.PageVersion;
360ee98c4a5SJohn Baldwin 		ext_page_req->header.PageNumber = cfgp->Header.PageNumber;
361ee98c4a5SJohn Baldwin 		ext_page_req->header.PageType = cfgp->Header.PageType;
362ee98c4a5SJohn Baldwin 		ext_page_req->header.ExtPageLength = cfgp->ExtPageLength;
363ee98c4a5SJohn Baldwin 		ext_page_req->header.ExtPageType = cfgp->ExtPageType;
364ee98c4a5SJohn Baldwin 	}
365ee98c4a5SJohn Baldwin 	mpt_free_request(mpt, req);
366ee98c4a5SJohn Baldwin 	return (0);
367ee98c4a5SJohn Baldwin }
368ee98c4a5SJohn Baldwin 
369ee98c4a5SJohn Baldwin static int
370ee98c4a5SJohn Baldwin mpt_user_read_extcfg_page(struct mpt_softc *mpt,
3714124f62eSJohn Baldwin     struct mpt_ext_cfg_page_req *ext_page_req, struct mpt_page_memory *mpt_page)
372ee98c4a5SJohn Baldwin {
373ee98c4a5SJohn Baldwin 	CONFIG_EXTENDED_PAGE_HEADER *hdr;
374ee98c4a5SJohn Baldwin 	request_t    *req;
375ee98c4a5SJohn Baldwin 	cfgparms_t    params;
376ee98c4a5SJohn Baldwin 	int	      error;
377ee98c4a5SJohn Baldwin 
378ee98c4a5SJohn Baldwin 	req = mpt_get_request(mpt, TRUE);
379ee98c4a5SJohn Baldwin 	if (req == NULL) {
380ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "mpt_user_read_extcfg_page: Get request failed!\n");
381ee98c4a5SJohn Baldwin 		return (ENOMEM);
382ee98c4a5SJohn Baldwin 	}
383ee98c4a5SJohn Baldwin 
3844124f62eSJohn Baldwin 	hdr = mpt_page->vaddr;
385ee98c4a5SJohn Baldwin 	params.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
386ee98c4a5SJohn Baldwin 	params.PageVersion = hdr->PageVersion;
387ee98c4a5SJohn Baldwin 	params.PageLength = 0;
388ee98c4a5SJohn Baldwin 	params.PageNumber = hdr->PageNumber;
389ee98c4a5SJohn Baldwin 	params.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
390ee98c4a5SJohn Baldwin 	params.PageAddress = ext_page_req->page_address;
391ee98c4a5SJohn Baldwin 	params.ExtPageType = hdr->ExtPageType;
392ee98c4a5SJohn Baldwin 	params.ExtPageLength = hdr->ExtPageLength;
3934124f62eSJohn Baldwin 	error = mpt_issue_cfg_req(mpt, req, &params, mpt_page->paddr,
394ee98c4a5SJohn Baldwin 				  ext_page_req->len, TRUE, 5000);
395ee98c4a5SJohn Baldwin 	if (error != 0) {
396ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "mpt_user_read_extcfg_page timed out\n");
397ee98c4a5SJohn Baldwin 		return (ETIMEDOUT);
398ee98c4a5SJohn Baldwin 	}
399ee98c4a5SJohn Baldwin 
400ee98c4a5SJohn Baldwin 	ext_page_req->ioc_status = req->IOCStatus;
4014124f62eSJohn Baldwin 	if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS)
4024124f62eSJohn Baldwin 		bus_dmamap_sync(mpt_page->tag, mpt_page->map,
403ee98c4a5SJohn Baldwin 		    BUS_DMASYNC_POSTREAD);
404ee98c4a5SJohn Baldwin 	mpt_free_request(mpt, req);
405ee98c4a5SJohn Baldwin 	return (0);
406ee98c4a5SJohn Baldwin }
407ee98c4a5SJohn Baldwin 
408ee98c4a5SJohn Baldwin static int
409ee98c4a5SJohn Baldwin mpt_user_write_cfg_page(struct mpt_softc *mpt,
4104124f62eSJohn Baldwin     struct mpt_cfg_page_req *page_req, struct mpt_page_memory *mpt_page)
411ee98c4a5SJohn Baldwin {
412ee98c4a5SJohn Baldwin 	CONFIG_PAGE_HEADER *hdr;
413ee98c4a5SJohn Baldwin 	request_t    *req;
414ee98c4a5SJohn Baldwin 	cfgparms_t    params;
415ee98c4a5SJohn Baldwin 	u_int	      hdr_attr;
416ee98c4a5SJohn Baldwin 	int	      error;
417ee98c4a5SJohn Baldwin 
4184124f62eSJohn Baldwin 	hdr = mpt_page->vaddr;
419ee98c4a5SJohn Baldwin 	hdr_attr = hdr->PageType & MPI_CONFIG_PAGEATTR_MASK;
420ee98c4a5SJohn Baldwin 	if (hdr_attr != MPI_CONFIG_PAGEATTR_CHANGEABLE &&
421ee98c4a5SJohn Baldwin 	    hdr_attr != MPI_CONFIG_PAGEATTR_PERSISTENT) {
422ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "page type 0x%x not changeable\n",
423ee98c4a5SJohn Baldwin 			hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
424ee98c4a5SJohn Baldwin 		return (EINVAL);
425ee98c4a5SJohn Baldwin 	}
426ee98c4a5SJohn Baldwin 
427ee98c4a5SJohn Baldwin #if	0
428ee98c4a5SJohn Baldwin 	/*
429ee98c4a5SJohn Baldwin 	 * We shouldn't mask off other bits here.
430ee98c4a5SJohn Baldwin 	 */
431ee98c4a5SJohn Baldwin 	hdr->PageType &= ~MPI_CONFIG_PAGETYPE_MASK;
432ee98c4a5SJohn Baldwin #endif
433ee98c4a5SJohn Baldwin 
434ee98c4a5SJohn Baldwin 	req = mpt_get_request(mpt, TRUE);
435ee98c4a5SJohn Baldwin 	if (req == NULL)
436ee98c4a5SJohn Baldwin 		return (ENOMEM);
437ee98c4a5SJohn Baldwin 
4384124f62eSJohn Baldwin 	bus_dmamap_sync(mpt_page->tag, mpt_page->map, BUS_DMASYNC_PREWRITE);
439ee98c4a5SJohn Baldwin 
440ee98c4a5SJohn Baldwin 	/*
441ee98c4a5SJohn Baldwin 	 * There isn't any point in restoring stripped out attributes
442ee98c4a5SJohn Baldwin 	 * if you then mask them going down to issue the request.
443ee98c4a5SJohn Baldwin 	 */
444ee98c4a5SJohn Baldwin 
445ee98c4a5SJohn Baldwin 	params.Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
446ee98c4a5SJohn Baldwin 	params.PageVersion = hdr->PageVersion;
447ee98c4a5SJohn Baldwin 	params.PageLength = hdr->PageLength;
448ee98c4a5SJohn Baldwin 	params.PageNumber = hdr->PageNumber;
449ee98c4a5SJohn Baldwin 	params.PageAddress = page_req->page_address;
450ee98c4a5SJohn Baldwin #if	0
451ee98c4a5SJohn Baldwin 	/* Restore stripped out attributes */
452ee98c4a5SJohn Baldwin 	hdr->PageType |= hdr_attr;
453ee98c4a5SJohn Baldwin 	params.PageType = hdr->PageType & MPI_CONFIG_PAGETYPE_MASK;
454ee98c4a5SJohn Baldwin #else
455ee98c4a5SJohn Baldwin 	params.PageType = hdr->PageType;
456ee98c4a5SJohn Baldwin #endif
4574124f62eSJohn Baldwin 	error = mpt_issue_cfg_req(mpt, req, &params, mpt_page->paddr,
458ee98c4a5SJohn Baldwin 				  page_req->len, TRUE, 5000);
459ee98c4a5SJohn Baldwin 	if (error != 0) {
460ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "mpt_write_cfg_page timed out\n");
461ee98c4a5SJohn Baldwin 		return (ETIMEDOUT);
462ee98c4a5SJohn Baldwin 	}
463ee98c4a5SJohn Baldwin 
464ee98c4a5SJohn Baldwin 	page_req->ioc_status = req->IOCStatus;
465ee98c4a5SJohn Baldwin 	mpt_free_request(mpt, req);
466ee98c4a5SJohn Baldwin 	return (0);
467ee98c4a5SJohn Baldwin }
468ee98c4a5SJohn Baldwin 
469ee98c4a5SJohn Baldwin static int
470ee98c4a5SJohn Baldwin mpt_user_reply_handler(struct mpt_softc *mpt, request_t *req,
471ee98c4a5SJohn Baldwin     uint32_t reply_desc, MSG_DEFAULT_REPLY *reply_frame)
472ee98c4a5SJohn Baldwin {
473ee98c4a5SJohn Baldwin 	MSG_RAID_ACTION_REPLY *reply;
474ee98c4a5SJohn Baldwin 	struct mpt_user_raid_action_result *res;
475ee98c4a5SJohn Baldwin 
476ee98c4a5SJohn Baldwin 	if (req == NULL)
477ee98c4a5SJohn Baldwin 		return (TRUE);
478ee98c4a5SJohn Baldwin 
479ee98c4a5SJohn Baldwin 	if (reply_frame != NULL) {
480ee98c4a5SJohn Baldwin 		bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap,
481ee98c4a5SJohn Baldwin 		    BUS_DMASYNC_POSTREAD);
482ee98c4a5SJohn Baldwin 		reply = (MSG_RAID_ACTION_REPLY *)reply_frame;
483ee98c4a5SJohn Baldwin 		req->IOCStatus = le16toh(reply->IOCStatus);
484ee98c4a5SJohn Baldwin 		res = (struct mpt_user_raid_action_result *)
485ee98c4a5SJohn Baldwin 		    (((uint8_t *)req->req_vbuf) + MPT_RQSL(mpt));
486ee98c4a5SJohn Baldwin 		res->action_status = reply->ActionStatus;
487ee98c4a5SJohn Baldwin 		res->volume_status = reply->VolumeStatus;
488ee98c4a5SJohn Baldwin 		bcopy(&reply->ActionData, res->action_data,
489ee98c4a5SJohn Baldwin 		    sizeof(res->action_data));
490ee98c4a5SJohn Baldwin 	}
491ee98c4a5SJohn Baldwin 
492ee98c4a5SJohn Baldwin 	req->state &= ~REQ_STATE_QUEUED;
493ee98c4a5SJohn Baldwin 	req->state |= REQ_STATE_DONE;
494ee98c4a5SJohn Baldwin 	TAILQ_REMOVE(&mpt->request_pending_list, req, links);
495ee98c4a5SJohn Baldwin 
496ee98c4a5SJohn Baldwin 	if ((req->state & REQ_STATE_NEED_WAKEUP) != 0) {
497ee98c4a5SJohn Baldwin 		wakeup(req);
498ee98c4a5SJohn Baldwin 	} else if ((req->state & REQ_STATE_TIMEDOUT) != 0) {
499ee98c4a5SJohn Baldwin 		/*
500ee98c4a5SJohn Baldwin 		 * Whew- we can free this request (late completion)
501ee98c4a5SJohn Baldwin 		 */
502ee98c4a5SJohn Baldwin 		mpt_free_request(mpt, req);
503ee98c4a5SJohn Baldwin 	}
504ee98c4a5SJohn Baldwin 
505ee98c4a5SJohn Baldwin 	return (TRUE);
506ee98c4a5SJohn Baldwin }
507ee98c4a5SJohn Baldwin 
508ee98c4a5SJohn Baldwin /*
509ee98c4a5SJohn Baldwin  * We use the first part of the request buffer after the request frame
510ee98c4a5SJohn Baldwin  * to hold the action data and action status from the RAID reply.  The
511ee98c4a5SJohn Baldwin  * rest of the request buffer is used to hold the buffer for the
512ee98c4a5SJohn Baldwin  * action SGE.
513ee98c4a5SJohn Baldwin  */
514ee98c4a5SJohn Baldwin static int
515ee98c4a5SJohn Baldwin mpt_user_raid_action(struct mpt_softc *mpt, struct mpt_raid_action *raid_act,
5164124f62eSJohn Baldwin 	struct mpt_page_memory *mpt_page)
517ee98c4a5SJohn Baldwin {
518ee98c4a5SJohn Baldwin 	request_t *req;
519ee98c4a5SJohn Baldwin 	struct mpt_user_raid_action_result *res;
520ee98c4a5SJohn Baldwin 	MSG_RAID_ACTION_REQUEST *rap;
521ee98c4a5SJohn Baldwin 	SGE_SIMPLE32 *se;
522ee98c4a5SJohn Baldwin 	int error;
523ee98c4a5SJohn Baldwin 
524ee98c4a5SJohn Baldwin 	req = mpt_get_request(mpt, TRUE);
525ee98c4a5SJohn Baldwin 	if (req == NULL)
526ee98c4a5SJohn Baldwin 		return (ENOMEM);
527ee98c4a5SJohn Baldwin 	rap = req->req_vbuf;
528ee98c4a5SJohn Baldwin 	memset(rap, 0, sizeof *rap);
529ee98c4a5SJohn Baldwin 	rap->Action = raid_act->action;
530ee98c4a5SJohn Baldwin 	rap->ActionDataWord = raid_act->action_data_word;
531ee98c4a5SJohn Baldwin 	rap->Function = MPI_FUNCTION_RAID_ACTION;
532ee98c4a5SJohn Baldwin 	rap->VolumeID = raid_act->volume_id;
533ee98c4a5SJohn Baldwin 	rap->VolumeBus = raid_act->volume_bus;
534ee98c4a5SJohn Baldwin 	rap->PhysDiskNum = raid_act->phys_disk_num;
535ee98c4a5SJohn Baldwin 	se = (SGE_SIMPLE32 *)&rap->ActionDataSGE;
5364124f62eSJohn Baldwin 	if (mpt_page->vaddr != NULL && raid_act->len != 0) {
5374124f62eSJohn Baldwin 		bus_dmamap_sync(mpt_page->tag, mpt_page->map,
5384124f62eSJohn Baldwin 		    BUS_DMASYNC_PREWRITE);
5394124f62eSJohn Baldwin 		se->Address = mpt_page->paddr;
540ee98c4a5SJohn Baldwin 		MPI_pSGE_SET_LENGTH(se, raid_act->len);
541ee98c4a5SJohn Baldwin 		MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
542ee98c4a5SJohn Baldwin 		    MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
543ee98c4a5SJohn Baldwin 		    MPI_SGE_FLAGS_END_OF_LIST |
544ee98c4a5SJohn Baldwin 		    raid_act->write ? MPI_SGE_FLAGS_HOST_TO_IOC :
545ee98c4a5SJohn Baldwin 		    MPI_SGE_FLAGS_IOC_TO_HOST));
546ee98c4a5SJohn Baldwin 	}
547ee98c4a5SJohn Baldwin 	rap->MsgContext = htole32(req->index | user_handler_id);
548ee98c4a5SJohn Baldwin 
549ee98c4a5SJohn Baldwin 	mpt_check_doorbell(mpt);
550ee98c4a5SJohn Baldwin 	mpt_send_cmd(mpt, req);
551ee98c4a5SJohn Baldwin 
552ee98c4a5SJohn Baldwin 	error = mpt_wait_req(mpt, req, REQ_STATE_DONE, REQ_STATE_DONE, TRUE,
553ee98c4a5SJohn Baldwin 	    2000);
554ee98c4a5SJohn Baldwin 	if (error != 0) {
555ee98c4a5SJohn Baldwin 		/*
556ee98c4a5SJohn Baldwin 		 * Leave request so it can be cleaned up later.
557ee98c4a5SJohn Baldwin 		 */
558ee98c4a5SJohn Baldwin 		mpt_prt(mpt, "mpt_user_raid_action timed out\n");
559ee98c4a5SJohn Baldwin 		return (error);
560ee98c4a5SJohn Baldwin 	}
561ee98c4a5SJohn Baldwin 
562ee98c4a5SJohn Baldwin 	raid_act->ioc_status = req->IOCStatus;
563ee98c4a5SJohn Baldwin 	if ((req->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
564ee98c4a5SJohn Baldwin 		mpt_free_request(mpt, req);
565ee98c4a5SJohn Baldwin 		return (0);
566ee98c4a5SJohn Baldwin 	}
567ee98c4a5SJohn Baldwin 
568ee98c4a5SJohn Baldwin 	res = (struct mpt_user_raid_action_result *)
569ee98c4a5SJohn Baldwin 	    (((uint8_t *)req->req_vbuf) + MPT_RQSL(mpt));
570ee98c4a5SJohn Baldwin 	raid_act->volume_status = res->volume_status;
571ee98c4a5SJohn Baldwin 	raid_act->action_status = res->action_status;
572ee98c4a5SJohn Baldwin 	bcopy(res->action_data, raid_act->action_data,
573ee98c4a5SJohn Baldwin 	    sizeof(res->action_data));
5744124f62eSJohn Baldwin 	if (mpt_page->vaddr != NULL)
5754124f62eSJohn Baldwin 		bus_dmamap_sync(mpt_page->tag, mpt_page->map,
5764124f62eSJohn Baldwin 		    BUS_DMASYNC_POSTREAD);
577ee98c4a5SJohn Baldwin 	mpt_free_request(mpt, req);
578ee98c4a5SJohn Baldwin 	return (0);
579ee98c4a5SJohn Baldwin }
580ee98c4a5SJohn Baldwin 
581ee98c4a5SJohn Baldwin #ifdef __amd64__
582ee98c4a5SJohn Baldwin #define	PTRIN(p)		((void *)(uintptr_t)(p))
583ee98c4a5SJohn Baldwin #define PTROUT(v)		((u_int32_t)(uintptr_t)(v))
584ee98c4a5SJohn Baldwin #endif
585ee98c4a5SJohn Baldwin 
586ee98c4a5SJohn Baldwin static int
587ee98c4a5SJohn Baldwin mpt_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
588ee98c4a5SJohn Baldwin {
589ee98c4a5SJohn Baldwin 	struct mpt_softc *mpt;
590ee98c4a5SJohn Baldwin 	struct mpt_cfg_page_req *page_req;
591ee98c4a5SJohn Baldwin 	struct mpt_ext_cfg_page_req *ext_page_req;
592ee98c4a5SJohn Baldwin 	struct mpt_raid_action *raid_act;
5934124f62eSJohn Baldwin 	struct mpt_page_memory mpt_page;
594ee98c4a5SJohn Baldwin #ifdef __amd64__
595ee98c4a5SJohn Baldwin 	struct mpt_cfg_page_req32 *page_req32;
596ee98c4a5SJohn Baldwin 	struct mpt_cfg_page_req page_req_swab;
597ee98c4a5SJohn Baldwin 	struct mpt_ext_cfg_page_req32 *ext_page_req32;
598ee98c4a5SJohn Baldwin 	struct mpt_ext_cfg_page_req ext_page_req_swab;
599ee98c4a5SJohn Baldwin 	struct mpt_raid_action32 *raid_act32;
600ee98c4a5SJohn Baldwin 	struct mpt_raid_action raid_act_swab;
601ee98c4a5SJohn Baldwin #endif
602ee98c4a5SJohn Baldwin 	int error;
603ee98c4a5SJohn Baldwin 
604ee98c4a5SJohn Baldwin 	mpt = dev->si_drv1;
605ee98c4a5SJohn Baldwin 	page_req = (void *)arg;
606ee98c4a5SJohn Baldwin 	ext_page_req = (void *)arg;
607ee98c4a5SJohn Baldwin 	raid_act = (void *)arg;
6084124f62eSJohn Baldwin 	mpt_page.vaddr = NULL;
609ee98c4a5SJohn Baldwin 
610ee98c4a5SJohn Baldwin #ifdef __amd64__
611ee98c4a5SJohn Baldwin 	/* Convert 32-bit structs to native ones. */
612ee98c4a5SJohn Baldwin 	page_req32 = (void *)arg;
613ee98c4a5SJohn Baldwin 	ext_page_req32 = (void *)arg;
614ee98c4a5SJohn Baldwin 	raid_act32 = (void *)arg;
615ee98c4a5SJohn Baldwin 	switch (cmd) {
616ee98c4a5SJohn Baldwin 	case MPTIO_READ_CFG_HEADER32:
617ee98c4a5SJohn Baldwin 	case MPTIO_READ_CFG_PAGE32:
618ee98c4a5SJohn Baldwin 	case MPTIO_WRITE_CFG_PAGE32:
619ee98c4a5SJohn Baldwin 		page_req = &page_req_swab;
620ee98c4a5SJohn Baldwin 		page_req->header = page_req32->header;
621ee98c4a5SJohn Baldwin 		page_req->page_address = page_req32->page_address;
622ee98c4a5SJohn Baldwin 		page_req->buf = PTRIN(page_req32->buf);
623ee98c4a5SJohn Baldwin 		page_req->len = page_req32->len;
624ee98c4a5SJohn Baldwin 		page_req->ioc_status = page_req32->ioc_status;
625ee98c4a5SJohn Baldwin 		break;
626ee98c4a5SJohn Baldwin 	case MPTIO_READ_EXT_CFG_HEADER32:
627ee98c4a5SJohn Baldwin 	case MPTIO_READ_EXT_CFG_PAGE32:
628ee98c4a5SJohn Baldwin 		ext_page_req = &ext_page_req_swab;
629ee98c4a5SJohn Baldwin 		ext_page_req->header = ext_page_req32->header;
630ee98c4a5SJohn Baldwin 		ext_page_req->page_address = ext_page_req32->page_address;
631ee98c4a5SJohn Baldwin 		ext_page_req->buf = PTRIN(ext_page_req32->buf);
632ee98c4a5SJohn Baldwin 		ext_page_req->len = ext_page_req32->len;
633ee98c4a5SJohn Baldwin 		ext_page_req->ioc_status = ext_page_req32->ioc_status;
634ee98c4a5SJohn Baldwin 		break;
635ee98c4a5SJohn Baldwin 	case MPTIO_RAID_ACTION32:
636ee98c4a5SJohn Baldwin 		raid_act = &raid_act_swab;
637ee98c4a5SJohn Baldwin 		raid_act->action = raid_act32->action;
638ee98c4a5SJohn Baldwin 		raid_act->volume_bus = raid_act32->volume_bus;
639ee98c4a5SJohn Baldwin 		raid_act->volume_id = raid_act32->volume_id;
640ee98c4a5SJohn Baldwin 		raid_act->phys_disk_num = raid_act32->phys_disk_num;
641ee98c4a5SJohn Baldwin 		raid_act->action_data_word = raid_act32->action_data_word;
642ee98c4a5SJohn Baldwin 		raid_act->buf = PTRIN(raid_act32->buf);
643ee98c4a5SJohn Baldwin 		raid_act->len = raid_act32->len;
644ee98c4a5SJohn Baldwin 		raid_act->volume_status = raid_act32->volume_status;
645ee98c4a5SJohn Baldwin 		bcopy(raid_act32->action_data, raid_act->action_data,
646ee98c4a5SJohn Baldwin 		    sizeof(raid_act->action_data));
647ee98c4a5SJohn Baldwin 		raid_act->action_status = raid_act32->action_status;
648ee98c4a5SJohn Baldwin 		raid_act->ioc_status = raid_act32->ioc_status;
649ee98c4a5SJohn Baldwin 		raid_act->write = raid_act32->write;
650ee98c4a5SJohn Baldwin 		break;
651ee98c4a5SJohn Baldwin 	}
652ee98c4a5SJohn Baldwin #endif
653ee98c4a5SJohn Baldwin 
654ee98c4a5SJohn Baldwin 	switch (cmd) {
655ee98c4a5SJohn Baldwin #ifdef __amd64__
656ee98c4a5SJohn Baldwin 	case MPTIO_READ_CFG_HEADER32:
657ee98c4a5SJohn Baldwin #endif
658ee98c4a5SJohn Baldwin 	case MPTIO_READ_CFG_HEADER:
659ee98c4a5SJohn Baldwin 		MPT_LOCK(mpt);
660ee98c4a5SJohn Baldwin 		error = mpt_user_read_cfg_header(mpt, page_req);
661ee98c4a5SJohn Baldwin 		MPT_UNLOCK(mpt);
662ee98c4a5SJohn Baldwin 		break;
663ee98c4a5SJohn Baldwin #ifdef __amd64__
664ee98c4a5SJohn Baldwin 	case MPTIO_READ_CFG_PAGE32:
665ee98c4a5SJohn Baldwin #endif
666ee98c4a5SJohn Baldwin 	case MPTIO_READ_CFG_PAGE:
6674124f62eSJohn Baldwin 		error = mpt_alloc_buffer(mpt, &mpt_page, page_req->len);
6684124f62eSJohn Baldwin 		if (error)
669ee98c4a5SJohn Baldwin 			break;
6704124f62eSJohn Baldwin 		error = copyin(page_req->buf, mpt_page.vaddr,
671ee98c4a5SJohn Baldwin 		    sizeof(CONFIG_PAGE_HEADER));
672ee98c4a5SJohn Baldwin 		if (error)
673ee98c4a5SJohn Baldwin 			break;
674ee98c4a5SJohn Baldwin 		MPT_LOCK(mpt);
6754124f62eSJohn Baldwin 		error = mpt_user_read_cfg_page(mpt, page_req, &mpt_page);
676ee98c4a5SJohn Baldwin 		MPT_UNLOCK(mpt);
677ee98c4a5SJohn Baldwin 		if (error)
678ee98c4a5SJohn Baldwin 			break;
6794124f62eSJohn Baldwin 		error = copyout(mpt_page.vaddr, page_req->buf, page_req->len);
680ee98c4a5SJohn Baldwin 		break;
681ee98c4a5SJohn Baldwin #ifdef __amd64__
682ee98c4a5SJohn Baldwin 	case MPTIO_READ_EXT_CFG_HEADER32:
683ee98c4a5SJohn Baldwin #endif
684ee98c4a5SJohn Baldwin 	case MPTIO_READ_EXT_CFG_HEADER:
685ee98c4a5SJohn Baldwin 		MPT_LOCK(mpt);
686ee98c4a5SJohn Baldwin 		error = mpt_user_read_extcfg_header(mpt, ext_page_req);
687ee98c4a5SJohn Baldwin 		MPT_UNLOCK(mpt);
688ee98c4a5SJohn Baldwin 		break;
689ee98c4a5SJohn Baldwin #ifdef __amd64__
690ee98c4a5SJohn Baldwin 	case MPTIO_READ_EXT_CFG_PAGE32:
691ee98c4a5SJohn Baldwin #endif
692ee98c4a5SJohn Baldwin 	case MPTIO_READ_EXT_CFG_PAGE:
6934124f62eSJohn Baldwin 		error = mpt_alloc_buffer(mpt, &mpt_page, ext_page_req->len);
6944124f62eSJohn Baldwin 		if (error)
695ee98c4a5SJohn Baldwin 			break;
6964124f62eSJohn Baldwin 		error = copyin(ext_page_req->buf, mpt_page.vaddr,
697ee98c4a5SJohn Baldwin 		    sizeof(CONFIG_EXTENDED_PAGE_HEADER));
698ee98c4a5SJohn Baldwin 		if (error)
699ee98c4a5SJohn Baldwin 			break;
700ee98c4a5SJohn Baldwin 		MPT_LOCK(mpt);
7014124f62eSJohn Baldwin 		error = mpt_user_read_extcfg_page(mpt, ext_page_req, &mpt_page);
702ee98c4a5SJohn Baldwin 		MPT_UNLOCK(mpt);
703ee98c4a5SJohn Baldwin 		if (error)
704ee98c4a5SJohn Baldwin 			break;
7054124f62eSJohn Baldwin 		error = copyout(mpt_page.vaddr, ext_page_req->buf,
7064124f62eSJohn Baldwin 		    ext_page_req->len);
707ee98c4a5SJohn Baldwin 		break;
708ee98c4a5SJohn Baldwin #ifdef __amd64__
709ee98c4a5SJohn Baldwin 	case MPTIO_WRITE_CFG_PAGE32:
710ee98c4a5SJohn Baldwin #endif
711ee98c4a5SJohn Baldwin 	case MPTIO_WRITE_CFG_PAGE:
7124124f62eSJohn Baldwin 		error = mpt_alloc_buffer(mpt, &mpt_page, page_req->len);
7134124f62eSJohn Baldwin 		if (error)
714ee98c4a5SJohn Baldwin 			break;
7154124f62eSJohn Baldwin 		error = copyin(page_req->buf, mpt_page.vaddr, page_req->len);
716ee98c4a5SJohn Baldwin 		if (error)
717ee98c4a5SJohn Baldwin 			break;
718ee98c4a5SJohn Baldwin 		MPT_LOCK(mpt);
7194124f62eSJohn Baldwin 		error = mpt_user_write_cfg_page(mpt, page_req, &mpt_page);
720ee98c4a5SJohn Baldwin 		MPT_UNLOCK(mpt);
721ee98c4a5SJohn Baldwin 		break;
722ee98c4a5SJohn Baldwin #ifdef __amd64__
723ee98c4a5SJohn Baldwin 	case MPTIO_RAID_ACTION32:
724ee98c4a5SJohn Baldwin #endif
725ee98c4a5SJohn Baldwin 	case MPTIO_RAID_ACTION:
726ee98c4a5SJohn Baldwin 		if (raid_act->buf != NULL) {
7274124f62eSJohn Baldwin 			error = mpt_alloc_buffer(mpt, &mpt_page, raid_act->len);
7284124f62eSJohn Baldwin 			if (error)
729ee98c4a5SJohn Baldwin 				break;
7304124f62eSJohn Baldwin 			error = copyin(raid_act->buf, mpt_page.vaddr,
7314124f62eSJohn Baldwin 			    raid_act->len);
732ee98c4a5SJohn Baldwin 			if (error)
733ee98c4a5SJohn Baldwin 				break;
734ee98c4a5SJohn Baldwin 		}
735ee98c4a5SJohn Baldwin 		MPT_LOCK(mpt);
7364124f62eSJohn Baldwin 		error = mpt_user_raid_action(mpt, raid_act, &mpt_page);
737ee98c4a5SJohn Baldwin 		MPT_UNLOCK(mpt);
738ee98c4a5SJohn Baldwin 		if (error)
739ee98c4a5SJohn Baldwin 			break;
7404124f62eSJohn Baldwin 		if (raid_act->buf != NULL)
7414124f62eSJohn Baldwin 			error = copyout(mpt_page.vaddr, raid_act->buf,
7424124f62eSJohn Baldwin 			    raid_act->len);
743ee98c4a5SJohn Baldwin 		break;
744ee98c4a5SJohn Baldwin 	default:
745ee98c4a5SJohn Baldwin 		error = ENOIOCTL;
746ee98c4a5SJohn Baldwin 		break;
747ee98c4a5SJohn Baldwin 	}
748ee98c4a5SJohn Baldwin 
7494124f62eSJohn Baldwin 	mpt_free_buffer(&mpt_page);
750ee98c4a5SJohn Baldwin 
751ee98c4a5SJohn Baldwin 	if (error)
752ee98c4a5SJohn Baldwin 		return (error);
753ee98c4a5SJohn Baldwin 
754ee98c4a5SJohn Baldwin #ifdef __amd64__
755ee98c4a5SJohn Baldwin 	/* Convert native structs to 32-bit ones. */
756ee98c4a5SJohn Baldwin 	switch (cmd) {
757ee98c4a5SJohn Baldwin 	case MPTIO_READ_CFG_HEADER32:
758ee98c4a5SJohn Baldwin 	case MPTIO_READ_CFG_PAGE32:
759ee98c4a5SJohn Baldwin 	case MPTIO_WRITE_CFG_PAGE32:
760ee98c4a5SJohn Baldwin 		page_req32->header = page_req->header;
761ee98c4a5SJohn Baldwin 		page_req32->page_address = page_req->page_address;
762ee98c4a5SJohn Baldwin 		page_req32->buf = PTROUT(page_req->buf);
763ee98c4a5SJohn Baldwin 		page_req32->len = page_req->len;
764ee98c4a5SJohn Baldwin 		page_req32->ioc_status = page_req->ioc_status;
765ee98c4a5SJohn Baldwin 		break;
766ee98c4a5SJohn Baldwin 	case MPTIO_READ_EXT_CFG_HEADER32:
767ee98c4a5SJohn Baldwin 	case MPTIO_READ_EXT_CFG_PAGE32:
768ee98c4a5SJohn Baldwin 		ext_page_req32->header = ext_page_req->header;
769ee98c4a5SJohn Baldwin 		ext_page_req32->page_address = ext_page_req->page_address;
770ee98c4a5SJohn Baldwin 		ext_page_req32->buf = PTROUT(ext_page_req->buf);
771ee98c4a5SJohn Baldwin 		ext_page_req32->len = ext_page_req->len;
772ee98c4a5SJohn Baldwin 		ext_page_req32->ioc_status = ext_page_req->ioc_status;
773ee98c4a5SJohn Baldwin 		break;
774ee98c4a5SJohn Baldwin 	case MPTIO_RAID_ACTION32:
775ee98c4a5SJohn Baldwin 		raid_act32->action = raid_act->action;
776ee98c4a5SJohn Baldwin 		raid_act32->volume_bus = raid_act->volume_bus;
777ee98c4a5SJohn Baldwin 		raid_act32->volume_id = raid_act->volume_id;
778ee98c4a5SJohn Baldwin 		raid_act32->phys_disk_num = raid_act->phys_disk_num;
779ee98c4a5SJohn Baldwin 		raid_act32->action_data_word = raid_act->action_data_word;
780ee98c4a5SJohn Baldwin 		raid_act32->buf = PTROUT(raid_act->buf);
781ee98c4a5SJohn Baldwin 		raid_act32->len = raid_act->len;
782ee98c4a5SJohn Baldwin 		raid_act32->volume_status = raid_act->volume_status;
783ee98c4a5SJohn Baldwin 		bcopy(raid_act->action_data, raid_act32->action_data,
784ee98c4a5SJohn Baldwin 		    sizeof(raid_act->action_data));
785ee98c4a5SJohn Baldwin 		raid_act32->action_status = raid_act->action_status;
786ee98c4a5SJohn Baldwin 		raid_act32->ioc_status = raid_act->ioc_status;
787ee98c4a5SJohn Baldwin 		raid_act32->write = raid_act->write;
788ee98c4a5SJohn Baldwin 		break;
789ee98c4a5SJohn Baldwin 	}
790ee98c4a5SJohn Baldwin #endif
791ee98c4a5SJohn Baldwin 
792ee98c4a5SJohn Baldwin 	return (0);
793ee98c4a5SJohn Baldwin }
794