xref: /freebsd/sys/dev/mps/mps_user.c (revision 01095e3bf1cacb583eb14f82000f26e423c60596)
1d3c7b9a0SKenneth D. Merry /*-
2d3c7b9a0SKenneth D. Merry  * Copyright (c) 2008 Yahoo!, Inc.
3d3c7b9a0SKenneth D. Merry  * All rights reserved.
4d3c7b9a0SKenneth D. Merry  * Written by: John Baldwin <jhb@FreeBSD.org>
5d3c7b9a0SKenneth D. Merry  *
6d3c7b9a0SKenneth D. Merry  * Redistribution and use in source and binary forms, with or without
7d3c7b9a0SKenneth D. Merry  * modification, are permitted provided that the following conditions
8d3c7b9a0SKenneth D. Merry  * are met:
9d3c7b9a0SKenneth D. Merry  * 1. Redistributions of source code must retain the above copyright
10d3c7b9a0SKenneth D. Merry  *    notice, this list of conditions and the following disclaimer.
11d3c7b9a0SKenneth D. Merry  * 2. Redistributions in binary form must reproduce the above copyright
12d3c7b9a0SKenneth D. Merry  *    notice, this list of conditions and the following disclaimer in the
13d3c7b9a0SKenneth D. Merry  *    documentation and/or other materials provided with the distribution.
14d3c7b9a0SKenneth D. Merry  * 3. Neither the name of the author nor the names of any co-contributors
15d3c7b9a0SKenneth D. Merry  *    may be used to endorse or promote products derived from this software
16d3c7b9a0SKenneth D. Merry  *    without specific prior written permission.
17d3c7b9a0SKenneth D. Merry  *
18d3c7b9a0SKenneth D. Merry  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19d3c7b9a0SKenneth D. Merry  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20d3c7b9a0SKenneth D. Merry  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21d3c7b9a0SKenneth D. Merry  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22d3c7b9a0SKenneth D. Merry  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23d3c7b9a0SKenneth D. Merry  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24d3c7b9a0SKenneth D. Merry  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25d3c7b9a0SKenneth D. Merry  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26d3c7b9a0SKenneth D. Merry  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27d3c7b9a0SKenneth D. Merry  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28d3c7b9a0SKenneth D. Merry  * SUCH DAMAGE.
29d3c7b9a0SKenneth D. Merry  *
30d3c7b9a0SKenneth D. Merry  * LSI MPS-Fusion Host Adapter FreeBSD userland interface
31d3c7b9a0SKenneth D. Merry  */
32d3c7b9a0SKenneth D. Merry 
33d3c7b9a0SKenneth D. Merry #include <sys/cdefs.h>
34d3c7b9a0SKenneth D. Merry __FBSDID("$FreeBSD$");
35d3c7b9a0SKenneth D. Merry 
365ef98042SMatthew D Fleming #include "opt_compat.h"
375ef98042SMatthew D Fleming 
38d3c7b9a0SKenneth D. Merry #include <sys/types.h>
39d3c7b9a0SKenneth D. Merry #include <sys/param.h>
40d3c7b9a0SKenneth D. Merry #include <sys/systm.h>
41d3c7b9a0SKenneth D. Merry #include <sys/kernel.h>
42d3c7b9a0SKenneth D. Merry #include <sys/selinfo.h>
43d3c7b9a0SKenneth D. Merry #include <sys/module.h>
44d3c7b9a0SKenneth D. Merry #include <sys/bus.h>
45d3c7b9a0SKenneth D. Merry #include <sys/conf.h>
46d3c7b9a0SKenneth D. Merry #include <sys/bio.h>
47d3c7b9a0SKenneth D. Merry #include <sys/malloc.h>
48d3c7b9a0SKenneth D. Merry #include <sys/uio.h>
49d3c7b9a0SKenneth D. Merry #include <sys/sysctl.h>
50d3c7b9a0SKenneth D. Merry #include <sys/ioccom.h>
51d3c7b9a0SKenneth D. Merry #include <sys/endian.h>
525ef98042SMatthew D Fleming #include <sys/proc.h>
535ef98042SMatthew D Fleming #include <sys/sysent.h>
54d3c7b9a0SKenneth D. Merry 
55d3c7b9a0SKenneth D. Merry #include <machine/bus.h>
56d3c7b9a0SKenneth D. Merry #include <machine/resource.h>
57d3c7b9a0SKenneth D. Merry #include <sys/rman.h>
58d3c7b9a0SKenneth D. Merry 
59d3c7b9a0SKenneth D. Merry #include <cam/scsi/scsi_all.h>
60d3c7b9a0SKenneth D. Merry 
61d3c7b9a0SKenneth D. Merry #include <dev/mps/mpi/mpi2_type.h>
62d3c7b9a0SKenneth D. Merry #include <dev/mps/mpi/mpi2.h>
63d3c7b9a0SKenneth D. Merry #include <dev/mps/mpi/mpi2_ioc.h>
64d3c7b9a0SKenneth D. Merry #include <dev/mps/mpi/mpi2_cnfg.h>
65d3c7b9a0SKenneth D. Merry #include <dev/mps/mpsvar.h>
66d3c7b9a0SKenneth D. Merry #include <dev/mps/mps_table.h>
67d3c7b9a0SKenneth D. Merry #include <dev/mps/mps_ioctl.h>
68d3c7b9a0SKenneth D. Merry 
69d3c7b9a0SKenneth D. Merry static d_open_t		mps_open;
70d3c7b9a0SKenneth D. Merry static d_close_t	mps_close;
715ef98042SMatthew D Fleming static d_ioctl_t	mps_ioctl_devsw;
72d3c7b9a0SKenneth D. Merry 
73d3c7b9a0SKenneth D. Merry static struct cdevsw mps_cdevsw = {
74d3c7b9a0SKenneth D. Merry 	.d_version =	D_VERSION,
75d3c7b9a0SKenneth D. Merry 	.d_flags =	0,
76d3c7b9a0SKenneth D. Merry 	.d_open =	mps_open,
77d3c7b9a0SKenneth D. Merry 	.d_close =	mps_close,
785ef98042SMatthew D Fleming 	.d_ioctl =	mps_ioctl_devsw,
79d3c7b9a0SKenneth D. Merry 	.d_name =	"mps",
80d3c7b9a0SKenneth D. Merry };
81d3c7b9a0SKenneth D. Merry 
82d3c7b9a0SKenneth D. Merry static MALLOC_DEFINE(M_MPSUSER, "mps_user", "Buffers for mps(4) ioctls");
83d3c7b9a0SKenneth D. Merry 
84d3c7b9a0SKenneth D. Merry int
85d3c7b9a0SKenneth D. Merry mps_attach_user(struct mps_softc *sc)
86d3c7b9a0SKenneth D. Merry {
87d3c7b9a0SKenneth D. Merry 	int unit;
88d3c7b9a0SKenneth D. Merry 
89d3c7b9a0SKenneth D. Merry 	unit = device_get_unit(sc->mps_dev);
90d3c7b9a0SKenneth D. Merry 	sc->mps_cdev = make_dev(&mps_cdevsw, unit, UID_ROOT, GID_OPERATOR, 0640,
91d3c7b9a0SKenneth D. Merry 	    "mps%d", unit);
92d3c7b9a0SKenneth D. Merry 	if (sc->mps_cdev == NULL) {
93d3c7b9a0SKenneth D. Merry 		return (ENOMEM);
94d3c7b9a0SKenneth D. Merry 	}
95d3c7b9a0SKenneth D. Merry 	sc->mps_cdev->si_drv1 = sc;
96d3c7b9a0SKenneth D. Merry 	return (0);
97d3c7b9a0SKenneth D. Merry }
98d3c7b9a0SKenneth D. Merry 
99d3c7b9a0SKenneth D. Merry void
100d3c7b9a0SKenneth D. Merry mps_detach_user(struct mps_softc *sc)
101d3c7b9a0SKenneth D. Merry {
102d3c7b9a0SKenneth D. Merry 
103d3c7b9a0SKenneth D. Merry 	/* XXX: do a purge of pending requests? */
104d3c7b9a0SKenneth D. Merry 	destroy_dev(sc->mps_cdev);
105d3c7b9a0SKenneth D. Merry 
106d3c7b9a0SKenneth D. Merry }
107d3c7b9a0SKenneth D. Merry 
108d3c7b9a0SKenneth D. Merry static int
109d3c7b9a0SKenneth D. Merry mps_open(struct cdev *dev, int flags, int fmt, struct thread *td)
110d3c7b9a0SKenneth D. Merry {
111d3c7b9a0SKenneth D. Merry 
112d3c7b9a0SKenneth D. Merry 	return (0);
113d3c7b9a0SKenneth D. Merry }
114d3c7b9a0SKenneth D. Merry 
115d3c7b9a0SKenneth D. Merry static int
116d3c7b9a0SKenneth D. Merry mps_close(struct cdev *dev, int flags, int fmt, struct thread *td)
117d3c7b9a0SKenneth D. Merry {
118d3c7b9a0SKenneth D. Merry 
119d3c7b9a0SKenneth D. Merry 	return (0);
120d3c7b9a0SKenneth D. Merry }
121d3c7b9a0SKenneth D. Merry 
122d3c7b9a0SKenneth D. Merry static int
123d3c7b9a0SKenneth D. Merry mps_user_read_cfg_header(struct mps_softc *sc,
124d3c7b9a0SKenneth D. Merry     struct mps_cfg_page_req *page_req)
125d3c7b9a0SKenneth D. Merry {
126d3c7b9a0SKenneth D. Merry 	MPI2_CONFIG_PAGE_HEADER *hdr;
127d3c7b9a0SKenneth D. Merry 	struct mps_config_params params;
128d3c7b9a0SKenneth D. Merry 	int	    error;
129d3c7b9a0SKenneth D. Merry 
130d3c7b9a0SKenneth D. Merry 	hdr = &params.hdr.Struct;
131d3c7b9a0SKenneth D. Merry 	params.action = MPI2_CONFIG_ACTION_PAGE_HEADER;
132d3c7b9a0SKenneth D. Merry 	params.page_address = le32toh(page_req->page_address);
133d3c7b9a0SKenneth D. Merry 	hdr->PageVersion = 0;
134d3c7b9a0SKenneth D. Merry 	hdr->PageLength = 0;
135d3c7b9a0SKenneth D. Merry 	hdr->PageNumber = page_req->header.PageNumber;
136d3c7b9a0SKenneth D. Merry 	hdr->PageType = page_req->header.PageType;
137d3c7b9a0SKenneth D. Merry 	params.buffer = NULL;
138d3c7b9a0SKenneth D. Merry 	params.length = 0;
139d3c7b9a0SKenneth D. Merry 	params.callback = NULL;
140d3c7b9a0SKenneth D. Merry 
141d3c7b9a0SKenneth D. Merry 	if ((error = mps_read_config_page(sc, &params)) != 0) {
142d3c7b9a0SKenneth D. Merry 		/*
143d3c7b9a0SKenneth D. Merry 		 * Leave the request. Without resetting the chip, it's
144d3c7b9a0SKenneth D. Merry 		 * still owned by it and we'll just get into trouble
145d3c7b9a0SKenneth D. Merry 		 * freeing it now. Mark it as abandoned so that if it
146d3c7b9a0SKenneth D. Merry 		 * shows up later it can be freed.
147d3c7b9a0SKenneth D. Merry 		 */
148d3c7b9a0SKenneth D. Merry 		mps_printf(sc, "read_cfg_header timed out\n");
149d3c7b9a0SKenneth D. Merry 		return (ETIMEDOUT);
150d3c7b9a0SKenneth D. Merry 	}
151d3c7b9a0SKenneth D. Merry 
152d3c7b9a0SKenneth D. Merry 	page_req->ioc_status = htole16(params.status);
153d3c7b9a0SKenneth D. Merry 	if ((page_req->ioc_status & MPI2_IOCSTATUS_MASK) ==
154d3c7b9a0SKenneth D. Merry 	    MPI2_IOCSTATUS_SUCCESS) {
155d3c7b9a0SKenneth D. Merry 		bcopy(hdr, &page_req->header, sizeof(page_req->header));
156d3c7b9a0SKenneth D. Merry 	}
157d3c7b9a0SKenneth D. Merry 
158d3c7b9a0SKenneth D. Merry 	return (0);
159d3c7b9a0SKenneth D. Merry }
160d3c7b9a0SKenneth D. Merry 
161d3c7b9a0SKenneth D. Merry static int
162d3c7b9a0SKenneth D. Merry mps_user_read_cfg_page(struct mps_softc *sc, struct mps_cfg_page_req *page_req,
163d3c7b9a0SKenneth D. Merry     void *buf)
164d3c7b9a0SKenneth D. Merry {
165d3c7b9a0SKenneth D. Merry 	MPI2_CONFIG_PAGE_HEADER *reqhdr, *hdr;
166d3c7b9a0SKenneth D. Merry 	struct mps_config_params params;
167d3c7b9a0SKenneth D. Merry 	int	      error;
168d3c7b9a0SKenneth D. Merry 
169d3c7b9a0SKenneth D. Merry 	reqhdr = buf;
170d3c7b9a0SKenneth D. Merry 	hdr = &params.hdr.Struct;
171d3c7b9a0SKenneth D. Merry 	hdr->PageVersion = reqhdr->PageVersion;
172d3c7b9a0SKenneth D. Merry 	hdr->PageLength = reqhdr->PageLength;
173d3c7b9a0SKenneth D. Merry 	hdr->PageNumber = reqhdr->PageNumber;
174d3c7b9a0SKenneth D. Merry 	hdr->PageType = reqhdr->PageType & MPI2_CONFIG_PAGETYPE_MASK;
175d3c7b9a0SKenneth D. Merry 	params.action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
176d3c7b9a0SKenneth D. Merry 	params.page_address = le32toh(page_req->page_address);
177d3c7b9a0SKenneth D. Merry 	params.buffer = buf;
178d3c7b9a0SKenneth D. Merry 	params.length = le32toh(page_req->len);
179d3c7b9a0SKenneth D. Merry 	params.callback = NULL;
180d3c7b9a0SKenneth D. Merry 
181d3c7b9a0SKenneth D. Merry 	if ((error = mps_read_config_page(sc, &params)) != 0) {
182d3c7b9a0SKenneth D. Merry 		mps_printf(sc, "mps_user_read_cfg_page timed out\n");
183d3c7b9a0SKenneth D. Merry 		return (ETIMEDOUT);
184d3c7b9a0SKenneth D. Merry 	}
185d3c7b9a0SKenneth D. Merry 
186d3c7b9a0SKenneth D. Merry 	page_req->ioc_status = htole16(params.status);
187d3c7b9a0SKenneth D. Merry 	return (0);
188d3c7b9a0SKenneth D. Merry }
189d3c7b9a0SKenneth D. Merry 
190d3c7b9a0SKenneth D. Merry static int
191d3c7b9a0SKenneth D. Merry mps_user_read_extcfg_header(struct mps_softc *sc,
192d3c7b9a0SKenneth D. Merry     struct mps_ext_cfg_page_req *ext_page_req)
193d3c7b9a0SKenneth D. Merry {
194d3c7b9a0SKenneth D. Merry 	MPI2_CONFIG_EXTENDED_PAGE_HEADER *hdr;
195d3c7b9a0SKenneth D. Merry 	struct mps_config_params params;
196d3c7b9a0SKenneth D. Merry 	int	    error;
197d3c7b9a0SKenneth D. Merry 
198d3c7b9a0SKenneth D. Merry 	hdr = &params.hdr.Ext;
199d3c7b9a0SKenneth D. Merry 	params.action = MPI2_CONFIG_ACTION_PAGE_HEADER;
200d3c7b9a0SKenneth D. Merry 	hdr->PageVersion = ext_page_req->header.PageVersion;
201d3c7b9a0SKenneth D. Merry 	hdr->ExtPageLength = 0;
202d3c7b9a0SKenneth D. Merry 	hdr->PageNumber = ext_page_req->header.PageNumber;
203d3c7b9a0SKenneth D. Merry 	hdr->ExtPageType = ext_page_req->header.ExtPageType;
204d3c7b9a0SKenneth D. Merry 	params.page_address = le32toh(ext_page_req->page_address);
205d3c7b9a0SKenneth D. Merry 	if ((error = mps_read_config_page(sc, &params)) != 0) {
206d3c7b9a0SKenneth D. Merry 		/*
207d3c7b9a0SKenneth D. Merry 		 * Leave the request. Without resetting the chip, it's
208d3c7b9a0SKenneth D. Merry 		 * still owned by it and we'll just get into trouble
209d3c7b9a0SKenneth D. Merry 		 * freeing it now. Mark it as abandoned so that if it
210d3c7b9a0SKenneth D. Merry 		 * shows up later it can be freed.
211d3c7b9a0SKenneth D. Merry 		 */
212d3c7b9a0SKenneth D. Merry 		mps_printf(sc, "mps_user_read_extcfg_header timed out\n");
213d3c7b9a0SKenneth D. Merry 		return (ETIMEDOUT);
214d3c7b9a0SKenneth D. Merry 	}
215d3c7b9a0SKenneth D. Merry 
216d3c7b9a0SKenneth D. Merry 	ext_page_req->ioc_status = htole16(params.status);
217d3c7b9a0SKenneth D. Merry 	if ((ext_page_req->ioc_status & MPI2_IOCSTATUS_MASK) ==
218d3c7b9a0SKenneth D. Merry 	    MPI2_IOCSTATUS_SUCCESS) {
219d3c7b9a0SKenneth D. Merry 		ext_page_req->header.PageVersion = hdr->PageVersion;
220d3c7b9a0SKenneth D. Merry 		ext_page_req->header.PageNumber = hdr->PageNumber;
221d3c7b9a0SKenneth D. Merry 		ext_page_req->header.PageType = hdr->PageType;
222d3c7b9a0SKenneth D. Merry 		ext_page_req->header.ExtPageLength = hdr->ExtPageLength;
223d3c7b9a0SKenneth D. Merry 		ext_page_req->header.ExtPageType = hdr->ExtPageType;
224d3c7b9a0SKenneth D. Merry 	}
225d3c7b9a0SKenneth D. Merry 
226d3c7b9a0SKenneth D. Merry 	return (0);
227d3c7b9a0SKenneth D. Merry }
228d3c7b9a0SKenneth D. Merry 
229d3c7b9a0SKenneth D. Merry static int
230d3c7b9a0SKenneth D. Merry mps_user_read_extcfg_page(struct mps_softc *sc,
231d3c7b9a0SKenneth D. Merry     struct mps_ext_cfg_page_req *ext_page_req, void *buf)
232d3c7b9a0SKenneth D. Merry {
233d3c7b9a0SKenneth D. Merry 	MPI2_CONFIG_EXTENDED_PAGE_HEADER *reqhdr, *hdr;
234d3c7b9a0SKenneth D. Merry 	struct mps_config_params params;
235d3c7b9a0SKenneth D. Merry 	int error;
236d3c7b9a0SKenneth D. Merry 
237d3c7b9a0SKenneth D. Merry 	reqhdr = buf;
238d3c7b9a0SKenneth D. Merry 	hdr = &params.hdr.Ext;
239d3c7b9a0SKenneth D. Merry 	params.action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
240d3c7b9a0SKenneth D. Merry 	params.page_address = le32toh(ext_page_req->page_address);
241d3c7b9a0SKenneth D. Merry 	hdr->PageVersion = reqhdr->PageVersion;
242d3c7b9a0SKenneth D. Merry 	hdr->PageNumber = reqhdr->PageNumber;
243d3c7b9a0SKenneth D. Merry 	hdr->ExtPageType = reqhdr->ExtPageType;
244d3c7b9a0SKenneth D. Merry 	hdr->ExtPageLength = reqhdr->ExtPageLength;
245d3c7b9a0SKenneth D. Merry 	params.buffer = buf;
246d3c7b9a0SKenneth D. Merry 	params.length = le32toh(ext_page_req->len);
247d3c7b9a0SKenneth D. Merry 	params.callback = NULL;
248d3c7b9a0SKenneth D. Merry 
249d3c7b9a0SKenneth D. Merry 	if ((error = mps_read_config_page(sc, &params)) != 0) {
250d3c7b9a0SKenneth D. Merry 		mps_printf(sc, "mps_user_read_extcfg_page timed out\n");
251d3c7b9a0SKenneth D. Merry 		return (ETIMEDOUT);
252d3c7b9a0SKenneth D. Merry 	}
253d3c7b9a0SKenneth D. Merry 
254d3c7b9a0SKenneth D. Merry 	ext_page_req->ioc_status = htole16(params.status);
255d3c7b9a0SKenneth D. Merry 	return (0);
256d3c7b9a0SKenneth D. Merry }
257d3c7b9a0SKenneth D. Merry 
258d3c7b9a0SKenneth D. Merry static int
259d3c7b9a0SKenneth D. Merry mps_user_write_cfg_page(struct mps_softc *sc,
260d3c7b9a0SKenneth D. Merry     struct mps_cfg_page_req *page_req, void *buf)
261d3c7b9a0SKenneth D. Merry {
262d3c7b9a0SKenneth D. Merry 	MPI2_CONFIG_PAGE_HEADER *reqhdr, *hdr;
263d3c7b9a0SKenneth D. Merry 	struct mps_config_params params;
264d3c7b9a0SKenneth D. Merry 	u_int	      hdr_attr;
265d3c7b9a0SKenneth D. Merry 	int	      error;
266d3c7b9a0SKenneth D. Merry 
267d3c7b9a0SKenneth D. Merry 	reqhdr = buf;
268d3c7b9a0SKenneth D. Merry 	hdr = &params.hdr.Struct;
269d3c7b9a0SKenneth D. Merry 	hdr_attr = reqhdr->PageType & MPI2_CONFIG_PAGEATTR_MASK;
270d3c7b9a0SKenneth D. Merry 	if (hdr_attr != MPI2_CONFIG_PAGEATTR_CHANGEABLE &&
271d3c7b9a0SKenneth D. Merry 	    hdr_attr != MPI2_CONFIG_PAGEATTR_PERSISTENT) {
272d3c7b9a0SKenneth D. Merry 		mps_printf(sc, "page type 0x%x not changeable\n",
273d3c7b9a0SKenneth D. Merry 			reqhdr->PageType & MPI2_CONFIG_PAGETYPE_MASK);
274d3c7b9a0SKenneth D. Merry 		return (EINVAL);
275d3c7b9a0SKenneth D. Merry 	}
276d3c7b9a0SKenneth D. Merry 
277d3c7b9a0SKenneth D. Merry 	/*
278d3c7b9a0SKenneth D. Merry 	 * There isn't any point in restoring stripped out attributes
279d3c7b9a0SKenneth D. Merry 	 * if you then mask them going down to issue the request.
280d3c7b9a0SKenneth D. Merry 	 */
281d3c7b9a0SKenneth D. Merry 
282d3c7b9a0SKenneth D. Merry 	hdr->PageVersion = reqhdr->PageVersion;
283d3c7b9a0SKenneth D. Merry 	hdr->PageLength = reqhdr->PageLength;
284d3c7b9a0SKenneth D. Merry 	hdr->PageNumber = reqhdr->PageNumber;
285d3c7b9a0SKenneth D. Merry 	hdr->PageType = reqhdr->PageType;
286d3c7b9a0SKenneth D. Merry 	params.action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT;
287d3c7b9a0SKenneth D. Merry 	params.page_address = le32toh(page_req->page_address);
288d3c7b9a0SKenneth D. Merry 	params.buffer = buf;
289d3c7b9a0SKenneth D. Merry 	params.length = le32toh(page_req->len);
290d3c7b9a0SKenneth D. Merry 	params.callback = NULL;
291d3c7b9a0SKenneth D. Merry 
292d3c7b9a0SKenneth D. Merry 	if ((error = mps_write_config_page(sc, &params)) != 0) {
293d3c7b9a0SKenneth D. Merry 		mps_printf(sc, "mps_write_cfg_page timed out\n");
294d3c7b9a0SKenneth D. Merry 		return (ETIMEDOUT);
295d3c7b9a0SKenneth D. Merry 	}
296d3c7b9a0SKenneth D. Merry 
297d3c7b9a0SKenneth D. Merry 	page_req->ioc_status = htole16(params.status);
298d3c7b9a0SKenneth D. Merry 	return (0);
299d3c7b9a0SKenneth D. Merry }
300d3c7b9a0SKenneth D. Merry 
301d3c7b9a0SKenneth D. Merry struct mps_user_func {
302d3c7b9a0SKenneth D. Merry 	U8 Func;
303d3c7b9a0SKenneth D. Merry 	U8 SgOff;
304d3c7b9a0SKenneth D. Merry } mps_user_func_list[] = {
305d3c7b9a0SKenneth D. Merry 	{ MPI2_FUNCTION_IOC_FACTS,	0 },
306d3c7b9a0SKenneth D. Merry 	{ MPI2_FUNCTION_PORT_FACTS,	0 },
307d3c7b9a0SKenneth D. Merry 	{ MPI2_FUNCTION_FW_DOWNLOAD, 	offsetof(Mpi2FWDownloadRequest,SGL)},
308d3c7b9a0SKenneth D. Merry 	{ MPI2_FUNCTION_FW_UPLOAD,	offsetof(Mpi2FWUploadRequest_t,SGL)},
309d3c7b9a0SKenneth D. Merry 	{ MPI2_FUNCTION_SATA_PASSTHROUGH,offsetof(Mpi2SataPassthroughRequest_t,SGL)},
310d3c7b9a0SKenneth D. Merry 	{ MPI2_FUNCTION_SMP_PASSTHROUGH, offsetof(Mpi2SmpPassthroughRequest_t,SGL)},
311d3c7b9a0SKenneth D. Merry 	{ MPI2_FUNCTION_CONFIG,		offsetof(Mpi2ConfigRequest_t,PageBufferSGE)},
312d3c7b9a0SKenneth D. Merry 	{ MPI2_FUNCTION_SAS_IO_UNIT_CONTROL,	0 },
313d3c7b9a0SKenneth D. Merry };
314d3c7b9a0SKenneth D. Merry 
315d3c7b9a0SKenneth D. Merry static int
316d3c7b9a0SKenneth D. Merry mps_user_verify_request(MPI2_REQUEST_HEADER *hdr, MPI2_SGE_IO_UNION **psgl)
317d3c7b9a0SKenneth D. Merry {
318d3c7b9a0SKenneth D. Merry 	int i, err = EINVAL;
319d3c7b9a0SKenneth D. Merry 
320d3c7b9a0SKenneth D. Merry 	for (i = 0; i < sizeof(mps_user_func_list) /
321d3c7b9a0SKenneth D. Merry 	    sizeof(mps_user_func_list[0]); i++ ) {
322d3c7b9a0SKenneth D. Merry 		struct mps_user_func *func = &mps_user_func_list[i];
323d3c7b9a0SKenneth D. Merry 
324d3c7b9a0SKenneth D. Merry 		if (hdr->Function == func->Func) {
325d3c7b9a0SKenneth D. Merry 			if (psgl != NULL) {
326d3c7b9a0SKenneth D. Merry 				if (func->SgOff != 0)
327d3c7b9a0SKenneth D. Merry 					*psgl = (PTR_MPI2_SGE_IO_UNION)
328d3c7b9a0SKenneth D. Merry 					    ((char*)hdr + func->SgOff);
329d3c7b9a0SKenneth D. Merry 				else
330d3c7b9a0SKenneth D. Merry 					*psgl = NULL;
331d3c7b9a0SKenneth D. Merry 				err = 0;
332d3c7b9a0SKenneth D. Merry 				break;
333d3c7b9a0SKenneth D. Merry 			}
334d3c7b9a0SKenneth D. Merry 		}
335d3c7b9a0SKenneth D. Merry 	}
336d3c7b9a0SKenneth D. Merry 
337d3c7b9a0SKenneth D. Merry 	return err;
338d3c7b9a0SKenneth D. Merry }
339d3c7b9a0SKenneth D. Merry 
340d3c7b9a0SKenneth D. Merry static int
341d3c7b9a0SKenneth D. Merry mps_user_command(struct mps_softc *sc, struct mps_usr_command *cmd)
342d3c7b9a0SKenneth D. Merry {
343d3c7b9a0SKenneth D. Merry 	MPI2_REQUEST_HEADER *hdr;
344d3c7b9a0SKenneth D. Merry 	MPI2_DEFAULT_REPLY *rpl;
345d3c7b9a0SKenneth D. Merry 	MPI2_SGE_IO_UNION *sgl;
346*01095e3bSMatthew D Fleming 	void *buf = NULL;
347d3c7b9a0SKenneth D. Merry 	struct mps_command *cm;
348d3c7b9a0SKenneth D. Merry 	int err = 0;
349d3c7b9a0SKenneth D. Merry 	int sz;
350d3c7b9a0SKenneth D. Merry 
351d3c7b9a0SKenneth D. Merry 	mps_lock(sc);
352d3c7b9a0SKenneth D. Merry 	cm = mps_alloc_command(sc);
353d3c7b9a0SKenneth D. Merry 
354d3c7b9a0SKenneth D. Merry 	if (cm == NULL) {
355d3c7b9a0SKenneth D. Merry 		mps_printf(sc, "mps_user_command: no mps requests\n");
356d3c7b9a0SKenneth D. Merry 		err = ENOMEM;
357d3c7b9a0SKenneth D. Merry 		goto Ret;
358d3c7b9a0SKenneth D. Merry 	}
359d3c7b9a0SKenneth D. Merry 	mps_unlock(sc);
360d3c7b9a0SKenneth D. Merry 
361d3c7b9a0SKenneth D. Merry 	hdr = (MPI2_REQUEST_HEADER *)cm->cm_req;
362d3c7b9a0SKenneth D. Merry 
363d3c7b9a0SKenneth D. Merry 	mps_dprint(sc, MPS_INFO, "mps_user_command: req %p %d  rpl %p %d\n",
364d3c7b9a0SKenneth D. Merry 		    cmd->req, cmd->req_len, cmd->rpl, cmd->rpl_len );
365d3c7b9a0SKenneth D. Merry 
366*01095e3bSMatthew D Fleming 	if (cmd->req_len > (int)sc->facts->IOCRequestFrameSize * 4) {
367*01095e3bSMatthew D Fleming 		err = EINVAL;
368*01095e3bSMatthew D Fleming 		goto RetFreeUnlocked;
369*01095e3bSMatthew D Fleming 	}
370*01095e3bSMatthew D Fleming 	err = copyin(cmd->req, hdr, cmd->req_len);
371*01095e3bSMatthew D Fleming 	if (err != 0)
372*01095e3bSMatthew D Fleming 		goto RetFreeUnlocked;
373d3c7b9a0SKenneth D. Merry 
374d3c7b9a0SKenneth D. Merry 	mps_dprint(sc, MPS_INFO, "mps_user_command: Function %02X  "
375d3c7b9a0SKenneth D. Merry 	    "MsgFlags %02X\n", hdr->Function, hdr->MsgFlags );
376d3c7b9a0SKenneth D. Merry 
377d3c7b9a0SKenneth D. Merry 	err = mps_user_verify_request(hdr, &sgl);
378d3c7b9a0SKenneth D. Merry 	if (err != 0) {
379d3c7b9a0SKenneth D. Merry 		mps_printf(sc, "mps_user_command: unsupported function 0x%X\n",
380d3c7b9a0SKenneth D. Merry 		    hdr->Function );
381*01095e3bSMatthew D Fleming 		goto RetFreeUnlocked;
382d3c7b9a0SKenneth D. Merry 	}
383d3c7b9a0SKenneth D. Merry 
384d3c7b9a0SKenneth D. Merry 	if (cmd->len > 0) {
385d3c7b9a0SKenneth D. Merry 		buf = malloc(cmd->len, M_MPSUSER, M_WAITOK|M_ZERO);
386d3c7b9a0SKenneth D. Merry 		cm->cm_data = buf;
387d3c7b9a0SKenneth D. Merry 		cm->cm_length = cmd->len;
388d3c7b9a0SKenneth D. Merry 	} else {
389d3c7b9a0SKenneth D. Merry 		cm->cm_data = NULL;
390d3c7b9a0SKenneth D. Merry 		cm->cm_length = 0;
391d3c7b9a0SKenneth D. Merry 	}
392d3c7b9a0SKenneth D. Merry 
393d3c7b9a0SKenneth D. Merry 	cm->cm_sge = sgl;
394d3c7b9a0SKenneth D. Merry 	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
395d3c7b9a0SKenneth D. Merry 	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_WAKEUP;
396d3c7b9a0SKenneth D. Merry 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
397d3c7b9a0SKenneth D. Merry 
398d3c7b9a0SKenneth D. Merry 	mps_lock(sc);
399d3c7b9a0SKenneth D. Merry 	err = mps_map_command(sc, cm);
400d3c7b9a0SKenneth D. Merry 
401d3c7b9a0SKenneth D. Merry 	if (err != 0) {
402d3c7b9a0SKenneth D. Merry 		mps_printf(sc, "mps_user_command: request timed out\n");
403d3c7b9a0SKenneth D. Merry 		goto Ret;
404d3c7b9a0SKenneth D. Merry 	}
405d3c7b9a0SKenneth D. Merry 	msleep(cm, &sc->mps_mtx, 0, "mpsuser", 0); /* 30 seconds */
406d3c7b9a0SKenneth D. Merry 
407d3c7b9a0SKenneth D. Merry 	rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply;
408d3c7b9a0SKenneth D. Merry 	sz = rpl->MsgLength * 4;
409d3c7b9a0SKenneth D. Merry 
410d3c7b9a0SKenneth D. Merry 	if (sz > cmd->rpl_len) {
411d3c7b9a0SKenneth D. Merry 		mps_printf(sc,
412d3c7b9a0SKenneth D. Merry 		    "mps_user_command: reply buffer too small %d required %d\n",
413d3c7b9a0SKenneth D. Merry 		    cmd->rpl_len, sz );
414d3c7b9a0SKenneth D. Merry 		err = EINVAL;
415d3c7b9a0SKenneth D. Merry 		sz = cmd->rpl_len;
416d3c7b9a0SKenneth D. Merry 	}
417d3c7b9a0SKenneth D. Merry 
418d3c7b9a0SKenneth D. Merry 	mps_unlock(sc);
419d3c7b9a0SKenneth D. Merry 	copyout(rpl, cmd->rpl, sz);
420*01095e3bSMatthew D Fleming 	if (buf != NULL)
421d3c7b9a0SKenneth D. Merry 		copyout(buf, cmd->buf, cmd->len);
422d3c7b9a0SKenneth D. Merry 	mps_lock(sc);
423d3c7b9a0SKenneth D. Merry 
424d3c7b9a0SKenneth D. Merry 	mps_dprint(sc, MPS_INFO, "mps_user_command: reply size %d\n", sz );
425d3c7b9a0SKenneth D. Merry 
426d3c7b9a0SKenneth D. Merry 	mps_free_command(sc, cm);
427d3c7b9a0SKenneth D. Merry Ret:
428d3c7b9a0SKenneth D. Merry 	mps_unlock(sc);
429*01095e3bSMatthew D Fleming 	if (buf != NULL)
430*01095e3bSMatthew D Fleming 		free(buf, M_MPSUSER);
431*01095e3bSMatthew D Fleming 	return (err);
432*01095e3bSMatthew D Fleming 
433*01095e3bSMatthew D Fleming RetFreeUnlocked:
434*01095e3bSMatthew D Fleming 	mps_lock(sc);
435*01095e3bSMatthew D Fleming 	mps_free_command(sc, cm);
436*01095e3bSMatthew D Fleming 	mps_unlock(sc);
437*01095e3bSMatthew D Fleming 
438*01095e3bSMatthew D Fleming 	if (buf != NULL)
439*01095e3bSMatthew D Fleming 		free(buf, M_MPSUSER);
440*01095e3bSMatthew D Fleming 	return (err);
441d3c7b9a0SKenneth D. Merry }
442d3c7b9a0SKenneth D. Merry 
443d3c7b9a0SKenneth D. Merry static int
4445ef98042SMatthew D Fleming mps_ioctl(struct cdev *dev, u_long cmd, void *arg, int flag,
445d3c7b9a0SKenneth D. Merry     struct thread *td)
446d3c7b9a0SKenneth D. Merry {
447d3c7b9a0SKenneth D. Merry 	struct mps_softc *sc;
448d3c7b9a0SKenneth D. Merry 	struct mps_cfg_page_req *page_req;
449d3c7b9a0SKenneth D. Merry 	struct mps_ext_cfg_page_req *ext_page_req;
450d3c7b9a0SKenneth D. Merry 	void *mps_page;
451d3c7b9a0SKenneth D. Merry 	int error;
452d3c7b9a0SKenneth D. Merry 
453d3c7b9a0SKenneth D. Merry 	mps_page = NULL;
454d3c7b9a0SKenneth D. Merry 	sc = dev->si_drv1;
455d3c7b9a0SKenneth D. Merry 	page_req = (void *)arg;
456d3c7b9a0SKenneth D. Merry 	ext_page_req = (void *)arg;
457d3c7b9a0SKenneth D. Merry 
458d3c7b9a0SKenneth D. Merry 	switch (cmd) {
459d3c7b9a0SKenneth D. Merry 	case MPSIO_READ_CFG_HEADER:
460d3c7b9a0SKenneth D. Merry 		mps_lock(sc);
461d3c7b9a0SKenneth D. Merry 		error = mps_user_read_cfg_header(sc, page_req);
462d3c7b9a0SKenneth D. Merry 		mps_unlock(sc);
463d3c7b9a0SKenneth D. Merry 		break;
464d3c7b9a0SKenneth D. Merry 	case MPSIO_READ_CFG_PAGE:
465d3c7b9a0SKenneth D. Merry 		mps_page = malloc(page_req->len, M_MPSUSER, M_WAITOK | M_ZERO);
466d3c7b9a0SKenneth D. Merry 		error = copyin(page_req->buf, mps_page,
467d3c7b9a0SKenneth D. Merry 		    sizeof(MPI2_CONFIG_PAGE_HEADER));
468d3c7b9a0SKenneth D. Merry 		if (error)
469d3c7b9a0SKenneth D. Merry 			break;
470d3c7b9a0SKenneth D. Merry 		mps_lock(sc);
471d3c7b9a0SKenneth D. Merry 		error = mps_user_read_cfg_page(sc, page_req, mps_page);
472d3c7b9a0SKenneth D. Merry 		mps_unlock(sc);
473d3c7b9a0SKenneth D. Merry 		if (error)
474d3c7b9a0SKenneth D. Merry 			break;
475d3c7b9a0SKenneth D. Merry 		error = copyout(mps_page, page_req->buf, page_req->len);
476d3c7b9a0SKenneth D. Merry 		break;
477d3c7b9a0SKenneth D. Merry 	case MPSIO_READ_EXT_CFG_HEADER:
478d3c7b9a0SKenneth D. Merry 		mps_lock(sc);
479d3c7b9a0SKenneth D. Merry 		error = mps_user_read_extcfg_header(sc, ext_page_req);
480d3c7b9a0SKenneth D. Merry 		mps_unlock(sc);
481d3c7b9a0SKenneth D. Merry 		break;
482d3c7b9a0SKenneth D. Merry 	case MPSIO_READ_EXT_CFG_PAGE:
483d3c7b9a0SKenneth D. Merry 		mps_page = malloc(ext_page_req->len, M_MPSUSER, M_WAITOK|M_ZERO);
484d3c7b9a0SKenneth D. Merry 		error = copyin(ext_page_req->buf, mps_page,
485d3c7b9a0SKenneth D. Merry 		    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
486d3c7b9a0SKenneth D. Merry 		if (error)
487d3c7b9a0SKenneth D. Merry 			break;
488d3c7b9a0SKenneth D. Merry 		mps_lock(sc);
489d3c7b9a0SKenneth D. Merry 		error = mps_user_read_extcfg_page(sc, ext_page_req, mps_page);
490d3c7b9a0SKenneth D. Merry 		mps_unlock(sc);
491d3c7b9a0SKenneth D. Merry 		if (error)
492d3c7b9a0SKenneth D. Merry 			break;
493d3c7b9a0SKenneth D. Merry 		error = copyout(mps_page, ext_page_req->buf, ext_page_req->len);
494d3c7b9a0SKenneth D. Merry 		break;
495d3c7b9a0SKenneth D. Merry 	case MPSIO_WRITE_CFG_PAGE:
496d3c7b9a0SKenneth D. Merry 		mps_page = malloc(page_req->len, M_MPSUSER, M_WAITOK|M_ZERO);
497d3c7b9a0SKenneth D. Merry 		error = copyin(page_req->buf, mps_page, page_req->len);
498d3c7b9a0SKenneth D. Merry 		if (error)
499d3c7b9a0SKenneth D. Merry 			break;
500d3c7b9a0SKenneth D. Merry 		mps_lock(sc);
501d3c7b9a0SKenneth D. Merry 		error = mps_user_write_cfg_page(sc, page_req, mps_page);
502d3c7b9a0SKenneth D. Merry 		mps_unlock(sc);
503d3c7b9a0SKenneth D. Merry 		break;
504d3c7b9a0SKenneth D. Merry 	case MPSIO_MPS_COMMAND:
505d3c7b9a0SKenneth D. Merry 		error = mps_user_command(sc, (struct mps_usr_command *)arg);
506d3c7b9a0SKenneth D. Merry 		break;
507d3c7b9a0SKenneth D. Merry 	default:
508d3c7b9a0SKenneth D. Merry 		error = ENOIOCTL;
509d3c7b9a0SKenneth D. Merry 		break;
510d3c7b9a0SKenneth D. Merry 	}
511d3c7b9a0SKenneth D. Merry 
512d3c7b9a0SKenneth D. Merry 	if (mps_page != NULL)
513d3c7b9a0SKenneth D. Merry 		free(mps_page, M_MPSUSER);
514d3c7b9a0SKenneth D. Merry 
515d3c7b9a0SKenneth D. Merry 	return (error);
5165ef98042SMatthew D Fleming }
517d3c7b9a0SKenneth D. Merry 
5185ef98042SMatthew D Fleming #ifdef COMPAT_FREEBSD32
5195ef98042SMatthew D Fleming 
5205ef98042SMatthew D Fleming /* Macros from compat/freebsd32/freebsd32.h */
5215ef98042SMatthew D Fleming #define	PTRIN(v)	(void *)(uintptr_t)(v)
5225ef98042SMatthew D Fleming #define	PTROUT(v)	(uint32_t)(uintptr_t)(v)
5235ef98042SMatthew D Fleming 
5245ef98042SMatthew D Fleming #define	CP(src,dst,fld) do { (dst).fld = (src).fld; } while (0)
5255ef98042SMatthew D Fleming #define	PTRIN_CP(src,dst,fld)				\
5265ef98042SMatthew D Fleming 	do { (dst).fld = PTRIN((src).fld); } while (0)
5275ef98042SMatthew D Fleming #define	PTROUT_CP(src,dst,fld) \
5285ef98042SMatthew D Fleming 	do { (dst).fld = PTROUT((src).fld); } while (0)
5295ef98042SMatthew D Fleming 
5305ef98042SMatthew D Fleming struct mps_cfg_page_req32 {
5315ef98042SMatthew D Fleming 	MPI2_CONFIG_PAGE_HEADER header;
5325ef98042SMatthew D Fleming 	uint32_t page_address;
5335ef98042SMatthew D Fleming 	uint32_t buf;
5345ef98042SMatthew D Fleming 	int	len;
5355ef98042SMatthew D Fleming 	uint16_t ioc_status;
5365ef98042SMatthew D Fleming };
5375ef98042SMatthew D Fleming 
5385ef98042SMatthew D Fleming struct mps_ext_cfg_page_req32 {
5395ef98042SMatthew D Fleming 	MPI2_CONFIG_EXTENDED_PAGE_HEADER header;
5405ef98042SMatthew D Fleming 	uint32_t page_address;
5415ef98042SMatthew D Fleming 	uint32_t buf;
5425ef98042SMatthew D Fleming 	int	len;
5435ef98042SMatthew D Fleming 	uint16_t ioc_status;
5445ef98042SMatthew D Fleming };
5455ef98042SMatthew D Fleming 
5465ef98042SMatthew D Fleming struct mps_raid_action32 {
5475ef98042SMatthew D Fleming 	uint8_t action;
5485ef98042SMatthew D Fleming 	uint8_t volume_bus;
5495ef98042SMatthew D Fleming 	uint8_t volume_id;
5505ef98042SMatthew D Fleming 	uint8_t phys_disk_num;
5515ef98042SMatthew D Fleming 	uint32_t action_data_word;
5525ef98042SMatthew D Fleming 	uint32_t buf;
5535ef98042SMatthew D Fleming 	int len;
5545ef98042SMatthew D Fleming 	uint32_t volume_status;
5555ef98042SMatthew D Fleming 	uint32_t action_data[4];
5565ef98042SMatthew D Fleming 	uint16_t action_status;
5575ef98042SMatthew D Fleming 	uint16_t ioc_status;
5585ef98042SMatthew D Fleming 	uint8_t write;
5595ef98042SMatthew D Fleming };
5605ef98042SMatthew D Fleming 
5615ef98042SMatthew D Fleming struct mps_usr_command32 {
5625ef98042SMatthew D Fleming 	uint32_t req;
5635ef98042SMatthew D Fleming 	uint32_t req_len;
5645ef98042SMatthew D Fleming 	uint32_t rpl;
5655ef98042SMatthew D Fleming 	uint32_t rpl_len;
5665ef98042SMatthew D Fleming 	uint32_t buf;
5675ef98042SMatthew D Fleming 	int len;
5685ef98042SMatthew D Fleming 	uint32_t flags;
5695ef98042SMatthew D Fleming };
5705ef98042SMatthew D Fleming 
5715ef98042SMatthew D Fleming #define	MPSIO_READ_CFG_HEADER32	_IOWR('M', 200, struct mps_cfg_page_req32)
5725ef98042SMatthew D Fleming #define	MPSIO_READ_CFG_PAGE32	_IOWR('M', 201, struct mps_cfg_page_req32)
5735ef98042SMatthew D Fleming #define	MPSIO_READ_EXT_CFG_HEADER32 _IOWR('M', 202, struct mps_ext_cfg_page_req32)
5745ef98042SMatthew D Fleming #define	MPSIO_READ_EXT_CFG_PAGE32 _IOWR('M', 203, struct mps_ext_cfg_page_req32)
5755ef98042SMatthew D Fleming #define	MPSIO_WRITE_CFG_PAGE32	_IOWR('M', 204, struct mps_cfg_page_req32)
5765ef98042SMatthew D Fleming #define	MPSIO_RAID_ACTION32	_IOWR('M', 205, struct mps_raid_action32)
5775ef98042SMatthew D Fleming #define	MPSIO_MPS_COMMAND32	_IOWR('M', 210, struct mps_usr_command32)
5785ef98042SMatthew D Fleming 
5795ef98042SMatthew D Fleming static int
5805ef98042SMatthew D Fleming mps_ioctl32(struct cdev *dev, u_long cmd32, void *_arg, int flag,
5815ef98042SMatthew D Fleming     struct thread *td)
5825ef98042SMatthew D Fleming {
5835ef98042SMatthew D Fleming 	struct mps_cfg_page_req32 *page32 = _arg;
5845ef98042SMatthew D Fleming 	struct mps_ext_cfg_page_req32 *ext32 = _arg;
5855ef98042SMatthew D Fleming 	struct mps_raid_action32 *raid32 = _arg;
5865ef98042SMatthew D Fleming 	struct mps_usr_command32 *user32 = _arg;
5875ef98042SMatthew D Fleming 	union {
5885ef98042SMatthew D Fleming 		struct mps_cfg_page_req page;
5895ef98042SMatthew D Fleming 		struct mps_ext_cfg_page_req ext;
5905ef98042SMatthew D Fleming 		struct mps_raid_action raid;
5915ef98042SMatthew D Fleming 		struct mps_usr_command user;
5925ef98042SMatthew D Fleming 	} arg;
5935ef98042SMatthew D Fleming 	u_long cmd;
5945ef98042SMatthew D Fleming 	int error;
5955ef98042SMatthew D Fleming 
5965ef98042SMatthew D Fleming 	switch (cmd32) {
597d3c7b9a0SKenneth D. Merry 	case MPSIO_READ_CFG_HEADER32:
598d3c7b9a0SKenneth D. Merry 	case MPSIO_READ_CFG_PAGE32:
599d3c7b9a0SKenneth D. Merry 	case MPSIO_WRITE_CFG_PAGE32:
6005ef98042SMatthew D Fleming 		if (cmd32 == MPSIO_READ_CFG_HEADER32)
6015ef98042SMatthew D Fleming 			cmd = MPSIO_READ_CFG_HEADER;
6025ef98042SMatthew D Fleming 		else if (cmd32 == MPSIO_READ_CFG_PAGE32)
6035ef98042SMatthew D Fleming 			cmd = MPSIO_READ_CFG_PAGE;
6045ef98042SMatthew D Fleming 		else
6055ef98042SMatthew D Fleming 			cmd = MPSIO_WRITE_CFG_PAGE;
6065ef98042SMatthew D Fleming 		CP(*page32, arg.page, header);
6075ef98042SMatthew D Fleming 		CP(*page32, arg.page, page_address);
6085ef98042SMatthew D Fleming 		PTRIN_CP(*page32, arg.page, buf);
6095ef98042SMatthew D Fleming 		CP(*page32, arg.page, len);
6105ef98042SMatthew D Fleming 		CP(*page32, arg.page, ioc_status);
611d3c7b9a0SKenneth D. Merry 		break;
6125ef98042SMatthew D Fleming 
613d3c7b9a0SKenneth D. Merry 	case MPSIO_READ_EXT_CFG_HEADER32:
614d3c7b9a0SKenneth D. Merry 	case MPSIO_READ_EXT_CFG_PAGE32:
6155ef98042SMatthew D Fleming 		if (cmd32 == MPSIO_READ_EXT_CFG_HEADER32)
6165ef98042SMatthew D Fleming 			cmd = MPSIO_READ_EXT_CFG_HEADER;
6175ef98042SMatthew D Fleming 		else
6185ef98042SMatthew D Fleming 			cmd = MPSIO_READ_EXT_CFG_PAGE;
6195ef98042SMatthew D Fleming 		CP(*ext32, arg.ext, header);
6205ef98042SMatthew D Fleming 		CP(*ext32, arg.ext, page_address);
6215ef98042SMatthew D Fleming 		PTRIN_CP(*ext32, arg.ext, buf);
6225ef98042SMatthew D Fleming 		CP(*ext32, arg.ext, len);
6235ef98042SMatthew D Fleming 		CP(*ext32, arg.ext, ioc_status);
6245ef98042SMatthew D Fleming 		break;
6255ef98042SMatthew D Fleming 
6265ef98042SMatthew D Fleming 	case MPSIO_RAID_ACTION32:
6275ef98042SMatthew D Fleming 		cmd = MPSIO_RAID_ACTION;
6285ef98042SMatthew D Fleming 		CP(*raid32, arg.raid, action);
6295ef98042SMatthew D Fleming 		CP(*raid32, arg.raid, volume_bus);
6305ef98042SMatthew D Fleming 		CP(*raid32, arg.raid, volume_id);
6315ef98042SMatthew D Fleming 		CP(*raid32, arg.raid, phys_disk_num);
6325ef98042SMatthew D Fleming 		CP(*raid32, arg.raid, action_data_word);
6335ef98042SMatthew D Fleming 		PTRIN_CP(*raid32, arg.raid, buf);
6345ef98042SMatthew D Fleming 		CP(*raid32, arg.raid, len);
6355ef98042SMatthew D Fleming 		CP(*raid32, arg.raid, volume_status);
6365ef98042SMatthew D Fleming 		bcopy(raid32->action_data, arg.raid.action_data,
6375ef98042SMatthew D Fleming 		    sizeof arg.raid.action_data);
6385ef98042SMatthew D Fleming 		CP(*raid32, arg.raid, ioc_status);
6395ef98042SMatthew D Fleming 		CP(*raid32, arg.raid, write);
6405ef98042SMatthew D Fleming 		break;
6415ef98042SMatthew D Fleming 
6425ef98042SMatthew D Fleming 	case MPSIO_MPS_COMMAND32:
6435ef98042SMatthew D Fleming 		cmd = MPSIO_MPS_COMMAND;
6445ef98042SMatthew D Fleming 		PTRIN_CP(*user32, arg.user, req);
6455ef98042SMatthew D Fleming 		CP(*user32, arg.user, req_len);
6465ef98042SMatthew D Fleming 		PTRIN_CP(*user32, arg.user, rpl);
6475ef98042SMatthew D Fleming 		CP(*user32, arg.user, rpl_len);
6485ef98042SMatthew D Fleming 		PTRIN_CP(*user32, arg.user, buf);
6495ef98042SMatthew D Fleming 		CP(*user32, arg.user, len);
6505ef98042SMatthew D Fleming 		CP(*user32, arg.user, flags);
651d3c7b9a0SKenneth D. Merry 		break;
652d3c7b9a0SKenneth D. Merry 	default:
653d3c7b9a0SKenneth D. Merry 		return (ENOIOCTL);
654d3c7b9a0SKenneth D. Merry 	}
655d3c7b9a0SKenneth D. Merry 
6565ef98042SMatthew D Fleming 	error = mps_ioctl(dev, cmd, &arg, flag, td);
6575ef98042SMatthew D Fleming 	if (error == 0 && (cmd32 & IOC_OUT) != 0) {
6585ef98042SMatthew D Fleming 		switch (cmd32) {
6595ef98042SMatthew D Fleming 		case MPSIO_READ_CFG_HEADER32:
6605ef98042SMatthew D Fleming 		case MPSIO_READ_CFG_PAGE32:
6615ef98042SMatthew D Fleming 		case MPSIO_WRITE_CFG_PAGE32:
6625ef98042SMatthew D Fleming 			CP(arg.page, *page32, header);
6635ef98042SMatthew D Fleming 			CP(arg.page, *page32, page_address);
6645ef98042SMatthew D Fleming 			PTROUT_CP(arg.page, *page32, buf);
6655ef98042SMatthew D Fleming 			CP(arg.page, *page32, len);
6665ef98042SMatthew D Fleming 			CP(arg.page, *page32, ioc_status);
6675ef98042SMatthew D Fleming 			break;
6685ef98042SMatthew D Fleming 
6695ef98042SMatthew D Fleming 		case MPSIO_READ_EXT_CFG_HEADER32:
6705ef98042SMatthew D Fleming 		case MPSIO_READ_EXT_CFG_PAGE32:
6715ef98042SMatthew D Fleming 			CP(arg.ext, *ext32, header);
6725ef98042SMatthew D Fleming 			CP(arg.ext, *ext32, page_address);
6735ef98042SMatthew D Fleming 			PTROUT_CP(arg.ext, *ext32, buf);
6745ef98042SMatthew D Fleming 			CP(arg.ext, *ext32, len);
6755ef98042SMatthew D Fleming 			CP(arg.ext, *ext32, ioc_status);
6765ef98042SMatthew D Fleming 			break;
6775ef98042SMatthew D Fleming 
6785ef98042SMatthew D Fleming 		case MPSIO_RAID_ACTION32:
6795ef98042SMatthew D Fleming 			CP(arg.raid, *raid32, action);
6805ef98042SMatthew D Fleming 			CP(arg.raid, *raid32, volume_bus);
6815ef98042SMatthew D Fleming 			CP(arg.raid, *raid32, volume_id);
6825ef98042SMatthew D Fleming 			CP(arg.raid, *raid32, phys_disk_num);
6835ef98042SMatthew D Fleming 			CP(arg.raid, *raid32, action_data_word);
6845ef98042SMatthew D Fleming 			PTROUT_CP(arg.raid, *raid32, buf);
6855ef98042SMatthew D Fleming 			CP(arg.raid, *raid32, len);
6865ef98042SMatthew D Fleming 			CP(arg.raid, *raid32, volume_status);
6875ef98042SMatthew D Fleming 			bcopy(arg.raid.action_data, raid32->action_data,
6885ef98042SMatthew D Fleming 			    sizeof arg.raid.action_data);
6895ef98042SMatthew D Fleming 			CP(arg.raid, *raid32, ioc_status);
6905ef98042SMatthew D Fleming 			CP(arg.raid, *raid32, write);
6915ef98042SMatthew D Fleming 			break;
6925ef98042SMatthew D Fleming 
6935ef98042SMatthew D Fleming 		case MPSIO_MPS_COMMAND32:
6945ef98042SMatthew D Fleming 			PTROUT_CP(arg.user, *user32, req);
6955ef98042SMatthew D Fleming 			CP(arg.user, *user32, req_len);
6965ef98042SMatthew D Fleming 			PTROUT_CP(arg.user, *user32, rpl);
6975ef98042SMatthew D Fleming 			CP(arg.user, *user32, rpl_len);
6985ef98042SMatthew D Fleming 			PTROUT_CP(arg.user, *user32, buf);
6995ef98042SMatthew D Fleming 			CP(arg.user, *user32, len);
7005ef98042SMatthew D Fleming 			CP(arg.user, *user32, flags);
7015ef98042SMatthew D Fleming 			break;
7025ef98042SMatthew D Fleming 		}
7035ef98042SMatthew D Fleming 	}
7045ef98042SMatthew D Fleming 
7055ef98042SMatthew D Fleming 	return (error);
7065ef98042SMatthew D Fleming }
7075ef98042SMatthew D Fleming #endif /* COMPAT_FREEBSD32 */
7085ef98042SMatthew D Fleming 
7095ef98042SMatthew D Fleming static int
7105ef98042SMatthew D Fleming mps_ioctl_devsw(struct cdev *dev, u_long com, caddr_t arg, int flag,
7115ef98042SMatthew D Fleming     struct thread *td)
7125ef98042SMatthew D Fleming {
7135ef98042SMatthew D Fleming #ifdef COMPAT_FREEBSD32
7145ef98042SMatthew D Fleming 	if (SV_CURPROC_FLAG(SV_ILP32))
7155ef98042SMatthew D Fleming 		return (mps_ioctl32(dev, com, arg, flag, td));
7165ef98042SMatthew D Fleming #endif
7175ef98042SMatthew D Fleming 	return (mps_ioctl(dev, com, arg, flag, td));
718d3c7b9a0SKenneth D. Merry }
719