xref: /freebsd/sys/dev/mps/mps_user.c (revision e658ccea60873c1e9e6df3ea9fc34931c47339c7)
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 
82d95f15e7SMatthew D Fleming typedef int (mps_user_f)(struct mps_command *, struct mps_usr_command *);
83d95f15e7SMatthew D Fleming static mps_user_f	mpi_pre_ioc_facts;
84d95f15e7SMatthew D Fleming static mps_user_f	mpi_pre_port_facts;
85d95f15e7SMatthew D Fleming static mps_user_f	mpi_pre_fw_download;
86d95f15e7SMatthew D Fleming static mps_user_f	mpi_pre_fw_upload;
87d95f15e7SMatthew D Fleming static mps_user_f	mpi_pre_sata_passthrough;
88d95f15e7SMatthew D Fleming static mps_user_f	mpi_pre_smp_passthrough;
89d95f15e7SMatthew D Fleming static mps_user_f	mpi_pre_config;
90d95f15e7SMatthew D Fleming static mps_user_f	mpi_pre_sas_io_unit_control;
91d95f15e7SMatthew D Fleming 
92452909d7SMatthew D Fleming static int mps_user_read_cfg_header(struct mps_softc *,
93452909d7SMatthew D Fleming 				    struct mps_cfg_page_req *);
94452909d7SMatthew D Fleming static int mps_user_read_cfg_page(struct mps_softc *,
95452909d7SMatthew D Fleming 				  struct mps_cfg_page_req *, void *);
96452909d7SMatthew D Fleming static int mps_user_read_extcfg_header(struct mps_softc *,
97452909d7SMatthew D Fleming 				     struct mps_ext_cfg_page_req *);
98452909d7SMatthew D Fleming static int mps_user_read_extcfg_page(struct mps_softc *,
99452909d7SMatthew D Fleming 				     struct mps_ext_cfg_page_req *, void *);
100452909d7SMatthew D Fleming static int mps_user_write_cfg_page(struct mps_softc *,
101452909d7SMatthew D Fleming 				   struct mps_cfg_page_req *, void *);
102d95f15e7SMatthew D Fleming static int mps_user_setup_request(struct mps_command *,
103d95f15e7SMatthew D Fleming 				  struct mps_usr_command *);
104452909d7SMatthew D Fleming static int mps_user_command(struct mps_softc *, struct mps_usr_command *);
105452909d7SMatthew D Fleming 
106d3c7b9a0SKenneth D. Merry static MALLOC_DEFINE(M_MPSUSER, "mps_user", "Buffers for mps(4) ioctls");
107d3c7b9a0SKenneth D. Merry 
108d3c7b9a0SKenneth D. Merry int
109d3c7b9a0SKenneth D. Merry mps_attach_user(struct mps_softc *sc)
110d3c7b9a0SKenneth D. Merry {
111d3c7b9a0SKenneth D. Merry 	int unit;
112d3c7b9a0SKenneth D. Merry 
113d3c7b9a0SKenneth D. Merry 	unit = device_get_unit(sc->mps_dev);
114d3c7b9a0SKenneth D. Merry 	sc->mps_cdev = make_dev(&mps_cdevsw, unit, UID_ROOT, GID_OPERATOR, 0640,
115d3c7b9a0SKenneth D. Merry 	    "mps%d", unit);
116d3c7b9a0SKenneth D. Merry 	if (sc->mps_cdev == NULL) {
117d3c7b9a0SKenneth D. Merry 		return (ENOMEM);
118d3c7b9a0SKenneth D. Merry 	}
119d3c7b9a0SKenneth D. Merry 	sc->mps_cdev->si_drv1 = sc;
120d3c7b9a0SKenneth D. Merry 	return (0);
121d3c7b9a0SKenneth D. Merry }
122d3c7b9a0SKenneth D. Merry 
123d3c7b9a0SKenneth D. Merry void
124d3c7b9a0SKenneth D. Merry mps_detach_user(struct mps_softc *sc)
125d3c7b9a0SKenneth D. Merry {
126d3c7b9a0SKenneth D. Merry 
127d3c7b9a0SKenneth D. Merry 	/* XXX: do a purge of pending requests? */
128d3c7b9a0SKenneth D. Merry 	destroy_dev(sc->mps_cdev);
129d3c7b9a0SKenneth D. Merry 
130d3c7b9a0SKenneth D. Merry }
131d3c7b9a0SKenneth D. Merry 
132d3c7b9a0SKenneth D. Merry static int
133d3c7b9a0SKenneth D. Merry mps_open(struct cdev *dev, int flags, int fmt, struct thread *td)
134d3c7b9a0SKenneth D. Merry {
135d3c7b9a0SKenneth D. Merry 
136d3c7b9a0SKenneth D. Merry 	return (0);
137d3c7b9a0SKenneth D. Merry }
138d3c7b9a0SKenneth D. Merry 
139d3c7b9a0SKenneth D. Merry static int
140d3c7b9a0SKenneth D. Merry mps_close(struct cdev *dev, int flags, int fmt, struct thread *td)
141d3c7b9a0SKenneth D. Merry {
142d3c7b9a0SKenneth D. Merry 
143d3c7b9a0SKenneth D. Merry 	return (0);
144d3c7b9a0SKenneth D. Merry }
145d3c7b9a0SKenneth D. Merry 
146d3c7b9a0SKenneth D. Merry static int
147d3c7b9a0SKenneth D. Merry mps_user_read_cfg_header(struct mps_softc *sc,
148d3c7b9a0SKenneth D. Merry     struct mps_cfg_page_req *page_req)
149d3c7b9a0SKenneth D. Merry {
150d3c7b9a0SKenneth D. Merry 	MPI2_CONFIG_PAGE_HEADER *hdr;
151d3c7b9a0SKenneth D. Merry 	struct mps_config_params params;
152d3c7b9a0SKenneth D. Merry 	int	    error;
153d3c7b9a0SKenneth D. Merry 
154d3c7b9a0SKenneth D. Merry 	hdr = &params.hdr.Struct;
155d3c7b9a0SKenneth D. Merry 	params.action = MPI2_CONFIG_ACTION_PAGE_HEADER;
156d3c7b9a0SKenneth D. Merry 	params.page_address = le32toh(page_req->page_address);
157d3c7b9a0SKenneth D. Merry 	hdr->PageVersion = 0;
158d3c7b9a0SKenneth D. Merry 	hdr->PageLength = 0;
159d3c7b9a0SKenneth D. Merry 	hdr->PageNumber = page_req->header.PageNumber;
160d3c7b9a0SKenneth D. Merry 	hdr->PageType = page_req->header.PageType;
161d3c7b9a0SKenneth D. Merry 	params.buffer = NULL;
162d3c7b9a0SKenneth D. Merry 	params.length = 0;
163d3c7b9a0SKenneth D. Merry 	params.callback = NULL;
164d3c7b9a0SKenneth D. Merry 
165d3c7b9a0SKenneth D. Merry 	if ((error = mps_read_config_page(sc, &params)) != 0) {
166d3c7b9a0SKenneth D. Merry 		/*
167d3c7b9a0SKenneth D. Merry 		 * Leave the request. Without resetting the chip, it's
168d3c7b9a0SKenneth D. Merry 		 * still owned by it and we'll just get into trouble
169d3c7b9a0SKenneth D. Merry 		 * freeing it now. Mark it as abandoned so that if it
170d3c7b9a0SKenneth D. Merry 		 * shows up later it can be freed.
171d3c7b9a0SKenneth D. Merry 		 */
172d3c7b9a0SKenneth D. Merry 		mps_printf(sc, "read_cfg_header timed out\n");
173d3c7b9a0SKenneth D. Merry 		return (ETIMEDOUT);
174d3c7b9a0SKenneth D. Merry 	}
175d3c7b9a0SKenneth D. Merry 
176d3c7b9a0SKenneth D. Merry 	page_req->ioc_status = htole16(params.status);
177d3c7b9a0SKenneth D. Merry 	if ((page_req->ioc_status & MPI2_IOCSTATUS_MASK) ==
178d3c7b9a0SKenneth D. Merry 	    MPI2_IOCSTATUS_SUCCESS) {
179d3c7b9a0SKenneth D. Merry 		bcopy(hdr, &page_req->header, sizeof(page_req->header));
180d3c7b9a0SKenneth D. Merry 	}
181d3c7b9a0SKenneth D. Merry 
182d3c7b9a0SKenneth D. Merry 	return (0);
183d3c7b9a0SKenneth D. Merry }
184d3c7b9a0SKenneth D. Merry 
185d3c7b9a0SKenneth D. Merry static int
186d3c7b9a0SKenneth D. Merry mps_user_read_cfg_page(struct mps_softc *sc, struct mps_cfg_page_req *page_req,
187d3c7b9a0SKenneth D. Merry     void *buf)
188d3c7b9a0SKenneth D. Merry {
189d3c7b9a0SKenneth D. Merry 	MPI2_CONFIG_PAGE_HEADER *reqhdr, *hdr;
190d3c7b9a0SKenneth D. Merry 	struct mps_config_params params;
191d3c7b9a0SKenneth D. Merry 	int	      error;
192d3c7b9a0SKenneth D. Merry 
193d3c7b9a0SKenneth D. Merry 	reqhdr = buf;
194d3c7b9a0SKenneth D. Merry 	hdr = &params.hdr.Struct;
195d3c7b9a0SKenneth D. Merry 	hdr->PageVersion = reqhdr->PageVersion;
196d3c7b9a0SKenneth D. Merry 	hdr->PageLength = reqhdr->PageLength;
197d3c7b9a0SKenneth D. Merry 	hdr->PageNumber = reqhdr->PageNumber;
198d3c7b9a0SKenneth D. Merry 	hdr->PageType = reqhdr->PageType & MPI2_CONFIG_PAGETYPE_MASK;
199d3c7b9a0SKenneth D. Merry 	params.action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
200d3c7b9a0SKenneth D. Merry 	params.page_address = le32toh(page_req->page_address);
201d3c7b9a0SKenneth D. Merry 	params.buffer = buf;
202d3c7b9a0SKenneth D. Merry 	params.length = le32toh(page_req->len);
203d3c7b9a0SKenneth D. Merry 	params.callback = NULL;
204d3c7b9a0SKenneth D. Merry 
205d3c7b9a0SKenneth D. Merry 	if ((error = mps_read_config_page(sc, &params)) != 0) {
206d3c7b9a0SKenneth D. Merry 		mps_printf(sc, "mps_user_read_cfg_page timed out\n");
207d3c7b9a0SKenneth D. Merry 		return (ETIMEDOUT);
208d3c7b9a0SKenneth D. Merry 	}
209d3c7b9a0SKenneth D. Merry 
210d3c7b9a0SKenneth D. Merry 	page_req->ioc_status = htole16(params.status);
211d3c7b9a0SKenneth D. Merry 	return (0);
212d3c7b9a0SKenneth D. Merry }
213d3c7b9a0SKenneth D. Merry 
214d3c7b9a0SKenneth D. Merry static int
215d3c7b9a0SKenneth D. Merry mps_user_read_extcfg_header(struct mps_softc *sc,
216d3c7b9a0SKenneth D. Merry     struct mps_ext_cfg_page_req *ext_page_req)
217d3c7b9a0SKenneth D. Merry {
218d3c7b9a0SKenneth D. Merry 	MPI2_CONFIG_EXTENDED_PAGE_HEADER *hdr;
219d3c7b9a0SKenneth D. Merry 	struct mps_config_params params;
220d3c7b9a0SKenneth D. Merry 	int	    error;
221d3c7b9a0SKenneth D. Merry 
222d3c7b9a0SKenneth D. Merry 	hdr = &params.hdr.Ext;
223d3c7b9a0SKenneth D. Merry 	params.action = MPI2_CONFIG_ACTION_PAGE_HEADER;
224d3c7b9a0SKenneth D. Merry 	hdr->PageVersion = ext_page_req->header.PageVersion;
225d3c7b9a0SKenneth D. Merry 	hdr->ExtPageLength = 0;
226d3c7b9a0SKenneth D. Merry 	hdr->PageNumber = ext_page_req->header.PageNumber;
227d3c7b9a0SKenneth D. Merry 	hdr->ExtPageType = ext_page_req->header.ExtPageType;
228d3c7b9a0SKenneth D. Merry 	params.page_address = le32toh(ext_page_req->page_address);
229d3c7b9a0SKenneth D. Merry 	if ((error = mps_read_config_page(sc, &params)) != 0) {
230d3c7b9a0SKenneth D. Merry 		/*
231d3c7b9a0SKenneth D. Merry 		 * Leave the request. Without resetting the chip, it's
232d3c7b9a0SKenneth D. Merry 		 * still owned by it and we'll just get into trouble
233d3c7b9a0SKenneth D. Merry 		 * freeing it now. Mark it as abandoned so that if it
234d3c7b9a0SKenneth D. Merry 		 * shows up later it can be freed.
235d3c7b9a0SKenneth D. Merry 		 */
236d3c7b9a0SKenneth D. Merry 		mps_printf(sc, "mps_user_read_extcfg_header timed out\n");
237d3c7b9a0SKenneth D. Merry 		return (ETIMEDOUT);
238d3c7b9a0SKenneth D. Merry 	}
239d3c7b9a0SKenneth D. Merry 
240d3c7b9a0SKenneth D. Merry 	ext_page_req->ioc_status = htole16(params.status);
241d3c7b9a0SKenneth D. Merry 	if ((ext_page_req->ioc_status & MPI2_IOCSTATUS_MASK) ==
242d3c7b9a0SKenneth D. Merry 	    MPI2_IOCSTATUS_SUCCESS) {
243d3c7b9a0SKenneth D. Merry 		ext_page_req->header.PageVersion = hdr->PageVersion;
244d3c7b9a0SKenneth D. Merry 		ext_page_req->header.PageNumber = hdr->PageNumber;
245d3c7b9a0SKenneth D. Merry 		ext_page_req->header.PageType = hdr->PageType;
246d3c7b9a0SKenneth D. Merry 		ext_page_req->header.ExtPageLength = hdr->ExtPageLength;
247d3c7b9a0SKenneth D. Merry 		ext_page_req->header.ExtPageType = hdr->ExtPageType;
248d3c7b9a0SKenneth D. Merry 	}
249d3c7b9a0SKenneth D. Merry 
250d3c7b9a0SKenneth D. Merry 	return (0);
251d3c7b9a0SKenneth D. Merry }
252d3c7b9a0SKenneth D. Merry 
253d3c7b9a0SKenneth D. Merry static int
254d3c7b9a0SKenneth D. Merry mps_user_read_extcfg_page(struct mps_softc *sc,
255d3c7b9a0SKenneth D. Merry     struct mps_ext_cfg_page_req *ext_page_req, void *buf)
256d3c7b9a0SKenneth D. Merry {
257d3c7b9a0SKenneth D. Merry 	MPI2_CONFIG_EXTENDED_PAGE_HEADER *reqhdr, *hdr;
258d3c7b9a0SKenneth D. Merry 	struct mps_config_params params;
259d3c7b9a0SKenneth D. Merry 	int error;
260d3c7b9a0SKenneth D. Merry 
261d3c7b9a0SKenneth D. Merry 	reqhdr = buf;
262d3c7b9a0SKenneth D. Merry 	hdr = &params.hdr.Ext;
263d3c7b9a0SKenneth D. Merry 	params.action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
264d3c7b9a0SKenneth D. Merry 	params.page_address = le32toh(ext_page_req->page_address);
265d3c7b9a0SKenneth D. Merry 	hdr->PageVersion = reqhdr->PageVersion;
266d3c7b9a0SKenneth D. Merry 	hdr->PageNumber = reqhdr->PageNumber;
267d3c7b9a0SKenneth D. Merry 	hdr->ExtPageType = reqhdr->ExtPageType;
268d3c7b9a0SKenneth D. Merry 	hdr->ExtPageLength = reqhdr->ExtPageLength;
269d3c7b9a0SKenneth D. Merry 	params.buffer = buf;
270d3c7b9a0SKenneth D. Merry 	params.length = le32toh(ext_page_req->len);
271d3c7b9a0SKenneth D. Merry 	params.callback = NULL;
272d3c7b9a0SKenneth D. Merry 
273d3c7b9a0SKenneth D. Merry 	if ((error = mps_read_config_page(sc, &params)) != 0) {
274d3c7b9a0SKenneth D. Merry 		mps_printf(sc, "mps_user_read_extcfg_page timed out\n");
275d3c7b9a0SKenneth D. Merry 		return (ETIMEDOUT);
276d3c7b9a0SKenneth D. Merry 	}
277d3c7b9a0SKenneth D. Merry 
278d3c7b9a0SKenneth D. Merry 	ext_page_req->ioc_status = htole16(params.status);
279d3c7b9a0SKenneth D. Merry 	return (0);
280d3c7b9a0SKenneth D. Merry }
281d3c7b9a0SKenneth D. Merry 
282d3c7b9a0SKenneth D. Merry static int
283d3c7b9a0SKenneth D. Merry mps_user_write_cfg_page(struct mps_softc *sc,
284d3c7b9a0SKenneth D. Merry     struct mps_cfg_page_req *page_req, void *buf)
285d3c7b9a0SKenneth D. Merry {
286d3c7b9a0SKenneth D. Merry 	MPI2_CONFIG_PAGE_HEADER *reqhdr, *hdr;
287d3c7b9a0SKenneth D. Merry 	struct mps_config_params params;
288d3c7b9a0SKenneth D. Merry 	u_int	      hdr_attr;
289d3c7b9a0SKenneth D. Merry 	int	      error;
290d3c7b9a0SKenneth D. Merry 
291d3c7b9a0SKenneth D. Merry 	reqhdr = buf;
292d3c7b9a0SKenneth D. Merry 	hdr = &params.hdr.Struct;
293d3c7b9a0SKenneth D. Merry 	hdr_attr = reqhdr->PageType & MPI2_CONFIG_PAGEATTR_MASK;
294d3c7b9a0SKenneth D. Merry 	if (hdr_attr != MPI2_CONFIG_PAGEATTR_CHANGEABLE &&
295d3c7b9a0SKenneth D. Merry 	    hdr_attr != MPI2_CONFIG_PAGEATTR_PERSISTENT) {
296d3c7b9a0SKenneth D. Merry 		mps_printf(sc, "page type 0x%x not changeable\n",
297d3c7b9a0SKenneth D. Merry 			reqhdr->PageType & MPI2_CONFIG_PAGETYPE_MASK);
298d3c7b9a0SKenneth D. Merry 		return (EINVAL);
299d3c7b9a0SKenneth D. Merry 	}
300d3c7b9a0SKenneth D. Merry 
301d3c7b9a0SKenneth D. Merry 	/*
302d3c7b9a0SKenneth D. Merry 	 * There isn't any point in restoring stripped out attributes
303d3c7b9a0SKenneth D. Merry 	 * if you then mask them going down to issue the request.
304d3c7b9a0SKenneth D. Merry 	 */
305d3c7b9a0SKenneth D. Merry 
306d3c7b9a0SKenneth D. Merry 	hdr->PageVersion = reqhdr->PageVersion;
307d3c7b9a0SKenneth D. Merry 	hdr->PageLength = reqhdr->PageLength;
308d3c7b9a0SKenneth D. Merry 	hdr->PageNumber = reqhdr->PageNumber;
309d3c7b9a0SKenneth D. Merry 	hdr->PageType = reqhdr->PageType;
310d3c7b9a0SKenneth D. Merry 	params.action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT;
311d3c7b9a0SKenneth D. Merry 	params.page_address = le32toh(page_req->page_address);
312d3c7b9a0SKenneth D. Merry 	params.buffer = buf;
313d3c7b9a0SKenneth D. Merry 	params.length = le32toh(page_req->len);
314d3c7b9a0SKenneth D. Merry 	params.callback = NULL;
315d3c7b9a0SKenneth D. Merry 
316d3c7b9a0SKenneth D. Merry 	if ((error = mps_write_config_page(sc, &params)) != 0) {
317d3c7b9a0SKenneth D. Merry 		mps_printf(sc, "mps_write_cfg_page timed out\n");
318d3c7b9a0SKenneth D. Merry 		return (ETIMEDOUT);
319d3c7b9a0SKenneth D. Merry 	}
320d3c7b9a0SKenneth D. Merry 
321d3c7b9a0SKenneth D. Merry 	page_req->ioc_status = htole16(params.status);
322d3c7b9a0SKenneth D. Merry 	return (0);
323d3c7b9a0SKenneth D. Merry }
324d3c7b9a0SKenneth D. Merry 
32513ac67a7SMatthew D Fleming static void
32613ac67a7SMatthew D Fleming mpi_init_sge(struct mps_command *cm, void *req, void *sge)
32713ac67a7SMatthew D Fleming {
32813ac67a7SMatthew D Fleming 	int off, space;
32913ac67a7SMatthew D Fleming 
33013ac67a7SMatthew D Fleming 	space = (int)cm->cm_sc->facts->IOCRequestFrameSize * 4;
33113ac67a7SMatthew D Fleming 	off = (uintptr_t)sge - (uintptr_t)req;
33213ac67a7SMatthew D Fleming 
33313ac67a7SMatthew D Fleming 	KASSERT(off < space, ("bad pointers %p %p, off %d, space %d",
33413ac67a7SMatthew D Fleming             req, sge, off, space));
33513ac67a7SMatthew D Fleming 
33613ac67a7SMatthew D Fleming 	cm->cm_sge = sge;
33713ac67a7SMatthew D Fleming 	cm->cm_sglsize = space - off;
33813ac67a7SMatthew D Fleming }
33913ac67a7SMatthew D Fleming 
340d95f15e7SMatthew D Fleming /*
341d95f15e7SMatthew D Fleming  * Prepare the mps_command for an IOC_FACTS request.
342d95f15e7SMatthew D Fleming  */
343d95f15e7SMatthew D Fleming static int
344d95f15e7SMatthew D Fleming mpi_pre_ioc_facts(struct mps_command *cm, struct mps_usr_command *cmd)
345d95f15e7SMatthew D Fleming {
346d95f15e7SMatthew D Fleming 	MPI2_IOC_FACTS_REQUEST *req = (void *)cm->cm_req;
347d95f15e7SMatthew D Fleming 	MPI2_IOC_FACTS_REPLY *rpl;
348d95f15e7SMatthew D Fleming 
349d95f15e7SMatthew D Fleming 	if (cmd->req_len != sizeof *req)
350d95f15e7SMatthew D Fleming 		return (EINVAL);
351d95f15e7SMatthew D Fleming 	if (cmd->rpl_len != sizeof *rpl)
352d95f15e7SMatthew D Fleming 		return (EINVAL);
353d95f15e7SMatthew D Fleming 
354d95f15e7SMatthew D Fleming 	cm->cm_sge = NULL;
355d95f15e7SMatthew D Fleming 	cm->cm_sglsize = 0;
356d95f15e7SMatthew D Fleming 	return (0);
357d95f15e7SMatthew D Fleming }
358d95f15e7SMatthew D Fleming 
359d95f15e7SMatthew D Fleming /*
360d95f15e7SMatthew D Fleming  * Prepare the mps_command for a PORT_FACTS request.
361d95f15e7SMatthew D Fleming  */
362d95f15e7SMatthew D Fleming static int
363d95f15e7SMatthew D Fleming mpi_pre_port_facts(struct mps_command *cm, struct mps_usr_command *cmd)
364d95f15e7SMatthew D Fleming {
365d95f15e7SMatthew D Fleming 	MPI2_PORT_FACTS_REQUEST *req = (void *)cm->cm_req;
366d95f15e7SMatthew D Fleming 	MPI2_PORT_FACTS_REPLY *rpl;
367d95f15e7SMatthew D Fleming 
368d95f15e7SMatthew D Fleming 	if (cmd->req_len != sizeof *req)
369d95f15e7SMatthew D Fleming 		return (EINVAL);
370d95f15e7SMatthew D Fleming 	if (cmd->rpl_len != sizeof *rpl)
371d95f15e7SMatthew D Fleming 		return (EINVAL);
372d95f15e7SMatthew D Fleming 
373d95f15e7SMatthew D Fleming 	cm->cm_sge = NULL;
374d95f15e7SMatthew D Fleming 	cm->cm_sglsize = 0;
375d95f15e7SMatthew D Fleming 	return (0);
376d95f15e7SMatthew D Fleming }
377d95f15e7SMatthew D Fleming 
378d95f15e7SMatthew D Fleming /*
379d95f15e7SMatthew D Fleming  * Prepare the mps_command for a FW_DOWNLOAD request.
380d95f15e7SMatthew D Fleming  */
381d95f15e7SMatthew D Fleming static int
382d95f15e7SMatthew D Fleming mpi_pre_fw_download(struct mps_command *cm, struct mps_usr_command *cmd)
383d95f15e7SMatthew D Fleming {
384d95f15e7SMatthew D Fleming 	MPI2_FW_DOWNLOAD_REQUEST *req = (void *)cm->cm_req;
385d95f15e7SMatthew D Fleming 	MPI2_FW_DOWNLOAD_REPLY *rpl;
3863f237b0bSMatthew D Fleming 	MPI2_FW_DOWNLOAD_TCSGE tc;
3873f237b0bSMatthew D Fleming 	int error;
3883f237b0bSMatthew D Fleming 
3893f237b0bSMatthew D Fleming 	/*
3903f237b0bSMatthew D Fleming 	 * This code assumes there is room in the request's SGL for
3913f237b0bSMatthew D Fleming 	 * the TransactionContext plus at least a SGL chain element.
3923f237b0bSMatthew D Fleming 	 */
3933f237b0bSMatthew D Fleming 	CTASSERT(sizeof req->SGL >= sizeof tc + MPS_SGC_SIZE);
394d95f15e7SMatthew D Fleming 
395d95f15e7SMatthew D Fleming 	if (cmd->req_len != sizeof *req)
396d95f15e7SMatthew D Fleming 		return (EINVAL);
397d95f15e7SMatthew D Fleming 	if (cmd->rpl_len != sizeof *rpl)
398d95f15e7SMatthew D Fleming 		return (EINVAL);
399d95f15e7SMatthew D Fleming 
4003f237b0bSMatthew D Fleming 	if (cmd->len == 0)
4013f237b0bSMatthew D Fleming 		return (EINVAL);
4023f237b0bSMatthew D Fleming 
4033f237b0bSMatthew D Fleming 	error = copyin(cmd->buf, cm->cm_data, cmd->len);
4043f237b0bSMatthew D Fleming 	if (error != 0)
4053f237b0bSMatthew D Fleming 		return (error);
4063f237b0bSMatthew D Fleming 
40713ac67a7SMatthew D Fleming 	mpi_init_sge(cm, req, &req->SGL);
4083f237b0bSMatthew D Fleming 	bzero(&tc, sizeof tc);
4093f237b0bSMatthew D Fleming 
4103f237b0bSMatthew D Fleming 	/*
4113f237b0bSMatthew D Fleming 	 * For now, the F/W image must be provided in a single request.
4123f237b0bSMatthew D Fleming 	 */
4133f237b0bSMatthew D Fleming 	if ((req->MsgFlags & MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT) == 0)
4143f237b0bSMatthew D Fleming 		return (EINVAL);
4153f237b0bSMatthew D Fleming 	if (req->TotalImageSize != cmd->len)
4163f237b0bSMatthew D Fleming 		return (EINVAL);
4173f237b0bSMatthew D Fleming 
4183f237b0bSMatthew D Fleming 	/*
4193f237b0bSMatthew D Fleming 	 * The value of the first two elements is specified in the
4203f237b0bSMatthew D Fleming 	 * Fusion-MPT Message Passing Interface document.
4213f237b0bSMatthew D Fleming 	 */
4223f237b0bSMatthew D Fleming 	tc.ContextSize = 0;
4233f237b0bSMatthew D Fleming 	tc.DetailsLength = 12;
4243f237b0bSMatthew D Fleming 	tc.ImageOffset = 0;
4253f237b0bSMatthew D Fleming 	tc.ImageSize = cmd->len;
4263f237b0bSMatthew D Fleming 
4273f237b0bSMatthew D Fleming 	cm->cm_flags |= MPS_CM_FLAGS_DATAOUT;
4283f237b0bSMatthew D Fleming 
4293f237b0bSMatthew D Fleming 	return (mps_push_sge(cm, &tc, sizeof tc, 0));
430d95f15e7SMatthew D Fleming }
431d95f15e7SMatthew D Fleming 
432d95f15e7SMatthew D Fleming /*
433d95f15e7SMatthew D Fleming  * Prepare the mps_command for a FW_UPLOAD request.
434d95f15e7SMatthew D Fleming  */
435d95f15e7SMatthew D Fleming static int
436d95f15e7SMatthew D Fleming mpi_pre_fw_upload(struct mps_command *cm, struct mps_usr_command *cmd)
437d95f15e7SMatthew D Fleming {
438d95f15e7SMatthew D Fleming 	MPI2_FW_UPLOAD_REQUEST *req = (void *)cm->cm_req;
439d95f15e7SMatthew D Fleming 	MPI2_FW_UPLOAD_REPLY *rpl;
44013ac67a7SMatthew D Fleming 	MPI2_FW_UPLOAD_TCSGE tc;
441d95f15e7SMatthew D Fleming 
442d95f15e7SMatthew D Fleming 	/*
443d95f15e7SMatthew D Fleming 	 * This code assumes there is room in the request's SGL for
444d95f15e7SMatthew D Fleming 	 * the TransactionContext plus at least a SGL chain element.
445d95f15e7SMatthew D Fleming 	 */
44613ac67a7SMatthew D Fleming 	CTASSERT(sizeof req->SGL >= sizeof tc + MPS_SGC_SIZE);
447d95f15e7SMatthew D Fleming 
448d95f15e7SMatthew D Fleming 	if (cmd->req_len != sizeof *req)
449d95f15e7SMatthew D Fleming 		return (EINVAL);
450d95f15e7SMatthew D Fleming 	if (cmd->rpl_len != sizeof *rpl)
451d95f15e7SMatthew D Fleming 		return (EINVAL);
452d95f15e7SMatthew D Fleming 
45313ac67a7SMatthew D Fleming 	mpi_init_sge(cm, req, &req->SGL);
454d95f15e7SMatthew D Fleming 	if (cmd->len == 0) {
455d95f15e7SMatthew D Fleming 		/* Perhaps just asking what the size of the fw is? */
456d95f15e7SMatthew D Fleming 		return (0);
457d95f15e7SMatthew D Fleming 	}
458d95f15e7SMatthew D Fleming 
45913ac67a7SMatthew D Fleming 	bzero(&tc, sizeof tc);
460d95f15e7SMatthew D Fleming 
461d95f15e7SMatthew D Fleming 	/*
462d95f15e7SMatthew D Fleming 	 * The value of the first two elements is specified in the
463d95f15e7SMatthew D Fleming 	 * Fusion-MPT Message Passing Interface document.
464d95f15e7SMatthew D Fleming 	 */
46513ac67a7SMatthew D Fleming 	tc.ContextSize = 0;
46613ac67a7SMatthew D Fleming 	tc.DetailsLength = 12;
467d95f15e7SMatthew D Fleming 	/*
468d95f15e7SMatthew D Fleming 	 * XXX Is there any reason to fetch a partial image?  I.e. to
469d95f15e7SMatthew D Fleming 	 * set ImageOffset to something other than 0?
470d95f15e7SMatthew D Fleming 	 */
47113ac67a7SMatthew D Fleming 	tc.ImageOffset = 0;
47213ac67a7SMatthew D Fleming 	tc.ImageSize = cmd->len;
473d95f15e7SMatthew D Fleming 
47413ac67a7SMatthew D Fleming 	return (mps_push_sge(cm, &tc, sizeof tc, 0));
475d95f15e7SMatthew D Fleming }
476d95f15e7SMatthew D Fleming 
477d95f15e7SMatthew D Fleming /*
478d95f15e7SMatthew D Fleming  * Prepare the mps_command for a SATA_PASSTHROUGH request.
479d95f15e7SMatthew D Fleming  */
480d95f15e7SMatthew D Fleming static int
481d95f15e7SMatthew D Fleming mpi_pre_sata_passthrough(struct mps_command *cm, struct mps_usr_command *cmd)
482d95f15e7SMatthew D Fleming {
483d95f15e7SMatthew D Fleming 	MPI2_SATA_PASSTHROUGH_REQUEST *req = (void *)cm->cm_req;
484d95f15e7SMatthew D Fleming 	MPI2_SATA_PASSTHROUGH_REPLY *rpl;
485d95f15e7SMatthew D Fleming 
486d95f15e7SMatthew D Fleming 	if (cmd->req_len != sizeof *req)
487d95f15e7SMatthew D Fleming 		return (EINVAL);
488d95f15e7SMatthew D Fleming 	if (cmd->rpl_len != sizeof *rpl)
489d95f15e7SMatthew D Fleming 		return (EINVAL);
490d95f15e7SMatthew D Fleming 
49113ac67a7SMatthew D Fleming 	mpi_init_sge(cm, req, &req->SGL);
492d95f15e7SMatthew D Fleming 	return (0);
493d95f15e7SMatthew D Fleming }
494d95f15e7SMatthew D Fleming 
495d95f15e7SMatthew D Fleming /*
496d95f15e7SMatthew D Fleming  * Prepare the mps_command for a SMP_PASSTHROUGH request.
497d95f15e7SMatthew D Fleming  */
498d95f15e7SMatthew D Fleming static int
499d95f15e7SMatthew D Fleming mpi_pre_smp_passthrough(struct mps_command *cm, struct mps_usr_command *cmd)
500d95f15e7SMatthew D Fleming {
501d95f15e7SMatthew D Fleming 	MPI2_SMP_PASSTHROUGH_REQUEST *req = (void *)cm->cm_req;
502d95f15e7SMatthew D Fleming 	MPI2_SMP_PASSTHROUGH_REPLY *rpl;
503d95f15e7SMatthew D Fleming 
504d95f15e7SMatthew D Fleming 	if (cmd->req_len != sizeof *req)
505d95f15e7SMatthew D Fleming 		return (EINVAL);
506d95f15e7SMatthew D Fleming 	if (cmd->rpl_len != sizeof *rpl)
507d95f15e7SMatthew D Fleming 		return (EINVAL);
508d95f15e7SMatthew D Fleming 
50913ac67a7SMatthew D Fleming 	mpi_init_sge(cm, req, &req->SGL);
510d95f15e7SMatthew D Fleming 	return (0);
511d95f15e7SMatthew D Fleming }
512d95f15e7SMatthew D Fleming 
513d95f15e7SMatthew D Fleming /*
514d95f15e7SMatthew D Fleming  * Prepare the mps_command for a CONFIG request.
515d95f15e7SMatthew D Fleming  */
516d95f15e7SMatthew D Fleming static int
517d95f15e7SMatthew D Fleming mpi_pre_config(struct mps_command *cm, struct mps_usr_command *cmd)
518d95f15e7SMatthew D Fleming {
519d95f15e7SMatthew D Fleming 	MPI2_CONFIG_REQUEST *req = (void *)cm->cm_req;
520d95f15e7SMatthew D Fleming 	MPI2_CONFIG_REPLY *rpl;
521d95f15e7SMatthew D Fleming 
522d95f15e7SMatthew D Fleming 	if (cmd->req_len != sizeof *req)
523d95f15e7SMatthew D Fleming 		return (EINVAL);
524d95f15e7SMatthew D Fleming 	if (cmd->rpl_len != sizeof *rpl)
525d95f15e7SMatthew D Fleming 		return (EINVAL);
526d95f15e7SMatthew D Fleming 
52713ac67a7SMatthew D Fleming 	mpi_init_sge(cm, req, &req->PageBufferSGE);
528d95f15e7SMatthew D Fleming 	return (0);
529d95f15e7SMatthew D Fleming }
530d95f15e7SMatthew D Fleming 
531d95f15e7SMatthew D Fleming /*
532d95f15e7SMatthew D Fleming  * Prepare the mps_command for a SAS_IO_UNIT_CONTROL request.
533d95f15e7SMatthew D Fleming  */
534d95f15e7SMatthew D Fleming static int
535d95f15e7SMatthew D Fleming mpi_pre_sas_io_unit_control(struct mps_command *cm,
536d95f15e7SMatthew D Fleming 			     struct mps_usr_command *cmd)
537d95f15e7SMatthew D Fleming {
538d95f15e7SMatthew D Fleming 
539d95f15e7SMatthew D Fleming 	cm->cm_sge = NULL;
540d95f15e7SMatthew D Fleming 	cm->cm_sglsize = 0;
541d95f15e7SMatthew D Fleming 	return (0);
542d95f15e7SMatthew D Fleming }
543d95f15e7SMatthew D Fleming 
544d95f15e7SMatthew D Fleming /*
545d95f15e7SMatthew D Fleming  * A set of functions to prepare an mps_command for the various
546d95f15e7SMatthew D Fleming  * supported requests.
547d95f15e7SMatthew D Fleming  */
548d3c7b9a0SKenneth D. Merry struct mps_user_func {
549d95f15e7SMatthew D Fleming 	U8		Function;
550d95f15e7SMatthew D Fleming 	mps_user_f	*f_pre;
551d3c7b9a0SKenneth D. Merry } mps_user_func_list[] = {
552d95f15e7SMatthew D Fleming 	{ MPI2_FUNCTION_IOC_FACTS,		mpi_pre_ioc_facts },
553d95f15e7SMatthew D Fleming 	{ MPI2_FUNCTION_PORT_FACTS,		mpi_pre_port_facts },
554d95f15e7SMatthew D Fleming 	{ MPI2_FUNCTION_FW_DOWNLOAD, 		mpi_pre_fw_download },
555d95f15e7SMatthew D Fleming 	{ MPI2_FUNCTION_FW_UPLOAD,		mpi_pre_fw_upload },
556d95f15e7SMatthew D Fleming 	{ MPI2_FUNCTION_SATA_PASSTHROUGH,	mpi_pre_sata_passthrough },
557d95f15e7SMatthew D Fleming 	{ MPI2_FUNCTION_SMP_PASSTHROUGH,	mpi_pre_smp_passthrough},
558d95f15e7SMatthew D Fleming 	{ MPI2_FUNCTION_CONFIG,			mpi_pre_config},
559d95f15e7SMatthew D Fleming 	{ MPI2_FUNCTION_SAS_IO_UNIT_CONTROL,	mpi_pre_sas_io_unit_control },
560d95f15e7SMatthew D Fleming 	{ 0xFF,					NULL } /* list end */
561d3c7b9a0SKenneth D. Merry };
562d3c7b9a0SKenneth D. Merry 
563d3c7b9a0SKenneth D. Merry static int
564d95f15e7SMatthew D Fleming mps_user_setup_request(struct mps_command *cm, struct mps_usr_command *cmd)
565d3c7b9a0SKenneth D. Merry {
566d95f15e7SMatthew D Fleming 	MPI2_REQUEST_HEADER *hdr = (MPI2_REQUEST_HEADER *)cm->cm_req;
567d95f15e7SMatthew D Fleming 	struct mps_user_func *f;
568d3c7b9a0SKenneth D. Merry 
569d95f15e7SMatthew D Fleming 	for (f = mps_user_func_list; f->f_pre != NULL; f++) {
570d95f15e7SMatthew D Fleming 		if (hdr->Function == f->Function)
571d95f15e7SMatthew D Fleming 			return (f->f_pre(cm, cmd));
572d3c7b9a0SKenneth D. Merry 	}
573d95f15e7SMatthew D Fleming 	return (EINVAL);
574d3c7b9a0SKenneth D. Merry }
575d3c7b9a0SKenneth D. Merry 
576d3c7b9a0SKenneth D. Merry static int
577d3c7b9a0SKenneth D. Merry mps_user_command(struct mps_softc *sc, struct mps_usr_command *cmd)
578d3c7b9a0SKenneth D. Merry {
579d3c7b9a0SKenneth D. Merry 	MPI2_REQUEST_HEADER *hdr;
580d3c7b9a0SKenneth D. Merry 	MPI2_DEFAULT_REPLY *rpl;
58101095e3bSMatthew D Fleming 	void *buf = NULL;
582*e658cceaSMatthew D Fleming 	struct mps_command *cm = NULL;
583d3c7b9a0SKenneth D. Merry 	int err = 0;
584d3c7b9a0SKenneth D. Merry 	int sz;
585d3c7b9a0SKenneth D. Merry 
586d3c7b9a0SKenneth D. Merry 	mps_lock(sc);
587d3c7b9a0SKenneth D. Merry 	cm = mps_alloc_command(sc);
588d3c7b9a0SKenneth D. Merry 
589d3c7b9a0SKenneth D. Merry 	if (cm == NULL) {
590d3c7b9a0SKenneth D. Merry 		mps_printf(sc, "mps_user_command: no mps requests\n");
591d3c7b9a0SKenneth D. Merry 		err = ENOMEM;
592d3c7b9a0SKenneth D. Merry 		goto Ret;
593d3c7b9a0SKenneth D. Merry 	}
594d3c7b9a0SKenneth D. Merry 	mps_unlock(sc);
595d3c7b9a0SKenneth D. Merry 
596d3c7b9a0SKenneth D. Merry 	hdr = (MPI2_REQUEST_HEADER *)cm->cm_req;
597d3c7b9a0SKenneth D. Merry 
598d3c7b9a0SKenneth D. Merry 	mps_dprint(sc, MPS_INFO, "mps_user_command: req %p %d  rpl %p %d\n",
599d3c7b9a0SKenneth D. Merry 		    cmd->req, cmd->req_len, cmd->rpl, cmd->rpl_len );
600d3c7b9a0SKenneth D. Merry 
60101095e3bSMatthew D Fleming 	if (cmd->req_len > (int)sc->facts->IOCRequestFrameSize * 4) {
60201095e3bSMatthew D Fleming 		err = EINVAL;
60301095e3bSMatthew D Fleming 		goto RetFreeUnlocked;
60401095e3bSMatthew D Fleming 	}
60501095e3bSMatthew D Fleming 	err = copyin(cmd->req, hdr, cmd->req_len);
60601095e3bSMatthew D Fleming 	if (err != 0)
60701095e3bSMatthew D Fleming 		goto RetFreeUnlocked;
608d3c7b9a0SKenneth D. Merry 
609d3c7b9a0SKenneth D. Merry 	mps_dprint(sc, MPS_INFO, "mps_user_command: Function %02X  "
610d3c7b9a0SKenneth D. Merry 	    "MsgFlags %02X\n", hdr->Function, hdr->MsgFlags );
611d3c7b9a0SKenneth D. Merry 
612d95f15e7SMatthew D Fleming 	err = mps_user_setup_request(cm, cmd);
613d3c7b9a0SKenneth D. Merry 	if (err != 0) {
614d3c7b9a0SKenneth D. Merry 		mps_printf(sc, "mps_user_command: unsupported function 0x%X\n",
615d3c7b9a0SKenneth D. Merry 		    hdr->Function );
61601095e3bSMatthew D Fleming 		goto RetFreeUnlocked;
617d3c7b9a0SKenneth D. Merry 	}
618d3c7b9a0SKenneth D. Merry 
619d3c7b9a0SKenneth D. Merry 	if (cmd->len > 0) {
620d3c7b9a0SKenneth D. Merry 		buf = malloc(cmd->len, M_MPSUSER, M_WAITOK|M_ZERO);
621d3c7b9a0SKenneth D. Merry 		cm->cm_data = buf;
622d3c7b9a0SKenneth D. Merry 		cm->cm_length = cmd->len;
623d3c7b9a0SKenneth D. Merry 	} else {
624d3c7b9a0SKenneth D. Merry 		cm->cm_data = NULL;
625d3c7b9a0SKenneth D. Merry 		cm->cm_length = 0;
626d3c7b9a0SKenneth D. Merry 	}
627d3c7b9a0SKenneth D. Merry 
628d3c7b9a0SKenneth D. Merry 	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_WAKEUP;
629d3c7b9a0SKenneth D. Merry 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
630d3c7b9a0SKenneth D. Merry 
631d3c7b9a0SKenneth D. Merry 	mps_lock(sc);
632d3c7b9a0SKenneth D. Merry 	err = mps_map_command(sc, cm);
633d3c7b9a0SKenneth D. Merry 
634*e658cceaSMatthew D Fleming 	if (err != 0 && err != EINPROGRESS) {
635*e658cceaSMatthew D Fleming 		mps_printf(sc, "%s: invalid request: error %d\n",
636*e658cceaSMatthew D Fleming 		    __func__, err);
637d3c7b9a0SKenneth D. Merry 		goto Ret;
638d3c7b9a0SKenneth D. Merry 	}
639*e658cceaSMatthew D Fleming 	msleep(cm, &sc->mps_mtx, 0, "mpsuser", 0);
640d3c7b9a0SKenneth D. Merry 
641d3c7b9a0SKenneth D. Merry 	rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply;
642d3c7b9a0SKenneth D. Merry 	sz = rpl->MsgLength * 4;
643d3c7b9a0SKenneth D. Merry 
644d3c7b9a0SKenneth D. Merry 	if (sz > cmd->rpl_len) {
645d3c7b9a0SKenneth D. Merry 		mps_printf(sc,
646d3c7b9a0SKenneth D. Merry 		    "mps_user_command: reply buffer too small %d required %d\n",
647d3c7b9a0SKenneth D. Merry 		    cmd->rpl_len, sz );
648d3c7b9a0SKenneth D. Merry 		err = EINVAL;
649d3c7b9a0SKenneth D. Merry 		sz = cmd->rpl_len;
650d3c7b9a0SKenneth D. Merry 	}
651d3c7b9a0SKenneth D. Merry 
652d3c7b9a0SKenneth D. Merry 	mps_unlock(sc);
653d3c7b9a0SKenneth D. Merry 	copyout(rpl, cmd->rpl, sz);
65401095e3bSMatthew D Fleming 	if (buf != NULL)
655d3c7b9a0SKenneth D. Merry 		copyout(buf, cmd->buf, cmd->len);
656d3c7b9a0SKenneth D. Merry 	mps_dprint(sc, MPS_INFO, "mps_user_command: reply size %d\n", sz );
657d3c7b9a0SKenneth D. Merry 
65801095e3bSMatthew D Fleming RetFreeUnlocked:
65901095e3bSMatthew D Fleming 	mps_lock(sc);
660*e658cceaSMatthew D Fleming 	if (cm != NULL)
66101095e3bSMatthew D Fleming 		mps_free_command(sc, cm);
662*e658cceaSMatthew D Fleming Ret:
66301095e3bSMatthew D Fleming 	mps_unlock(sc);
66401095e3bSMatthew D Fleming 	if (buf != NULL)
66501095e3bSMatthew D Fleming 		free(buf, M_MPSUSER);
66601095e3bSMatthew D Fleming 	return (err);
667d3c7b9a0SKenneth D. Merry }
668d3c7b9a0SKenneth D. Merry 
669d3c7b9a0SKenneth D. Merry static int
6705ef98042SMatthew D Fleming mps_ioctl(struct cdev *dev, u_long cmd, void *arg, int flag,
671d3c7b9a0SKenneth D. Merry     struct thread *td)
672d3c7b9a0SKenneth D. Merry {
673d3c7b9a0SKenneth D. Merry 	struct mps_softc *sc;
674d3c7b9a0SKenneth D. Merry 	struct mps_cfg_page_req *page_req;
675d3c7b9a0SKenneth D. Merry 	struct mps_ext_cfg_page_req *ext_page_req;
676d3c7b9a0SKenneth D. Merry 	void *mps_page;
677d3c7b9a0SKenneth D. Merry 	int error;
678d3c7b9a0SKenneth D. Merry 
679d3c7b9a0SKenneth D. Merry 	mps_page = NULL;
680d3c7b9a0SKenneth D. Merry 	sc = dev->si_drv1;
681d3c7b9a0SKenneth D. Merry 	page_req = (void *)arg;
682d3c7b9a0SKenneth D. Merry 	ext_page_req = (void *)arg;
683d3c7b9a0SKenneth D. Merry 
684d3c7b9a0SKenneth D. Merry 	switch (cmd) {
685d3c7b9a0SKenneth D. Merry 	case MPSIO_READ_CFG_HEADER:
686d3c7b9a0SKenneth D. Merry 		mps_lock(sc);
687d3c7b9a0SKenneth D. Merry 		error = mps_user_read_cfg_header(sc, page_req);
688d3c7b9a0SKenneth D. Merry 		mps_unlock(sc);
689d3c7b9a0SKenneth D. Merry 		break;
690d3c7b9a0SKenneth D. Merry 	case MPSIO_READ_CFG_PAGE:
691d3c7b9a0SKenneth D. Merry 		mps_page = malloc(page_req->len, M_MPSUSER, M_WAITOK | M_ZERO);
692d3c7b9a0SKenneth D. Merry 		error = copyin(page_req->buf, mps_page,
693d3c7b9a0SKenneth D. Merry 		    sizeof(MPI2_CONFIG_PAGE_HEADER));
694d3c7b9a0SKenneth D. Merry 		if (error)
695d3c7b9a0SKenneth D. Merry 			break;
696d3c7b9a0SKenneth D. Merry 		mps_lock(sc);
697d3c7b9a0SKenneth D. Merry 		error = mps_user_read_cfg_page(sc, page_req, mps_page);
698d3c7b9a0SKenneth D. Merry 		mps_unlock(sc);
699d3c7b9a0SKenneth D. Merry 		if (error)
700d3c7b9a0SKenneth D. Merry 			break;
701d3c7b9a0SKenneth D. Merry 		error = copyout(mps_page, page_req->buf, page_req->len);
702d3c7b9a0SKenneth D. Merry 		break;
703d3c7b9a0SKenneth D. Merry 	case MPSIO_READ_EXT_CFG_HEADER:
704d3c7b9a0SKenneth D. Merry 		mps_lock(sc);
705d3c7b9a0SKenneth D. Merry 		error = mps_user_read_extcfg_header(sc, ext_page_req);
706d3c7b9a0SKenneth D. Merry 		mps_unlock(sc);
707d3c7b9a0SKenneth D. Merry 		break;
708d3c7b9a0SKenneth D. Merry 	case MPSIO_READ_EXT_CFG_PAGE:
709d3c7b9a0SKenneth D. Merry 		mps_page = malloc(ext_page_req->len, M_MPSUSER, M_WAITOK|M_ZERO);
710d3c7b9a0SKenneth D. Merry 		error = copyin(ext_page_req->buf, mps_page,
711d3c7b9a0SKenneth D. Merry 		    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
712d3c7b9a0SKenneth D. Merry 		if (error)
713d3c7b9a0SKenneth D. Merry 			break;
714d3c7b9a0SKenneth D. Merry 		mps_lock(sc);
715d3c7b9a0SKenneth D. Merry 		error = mps_user_read_extcfg_page(sc, ext_page_req, mps_page);
716d3c7b9a0SKenneth D. Merry 		mps_unlock(sc);
717d3c7b9a0SKenneth D. Merry 		if (error)
718d3c7b9a0SKenneth D. Merry 			break;
719d3c7b9a0SKenneth D. Merry 		error = copyout(mps_page, ext_page_req->buf, ext_page_req->len);
720d3c7b9a0SKenneth D. Merry 		break;
721d3c7b9a0SKenneth D. Merry 	case MPSIO_WRITE_CFG_PAGE:
722d3c7b9a0SKenneth D. Merry 		mps_page = malloc(page_req->len, M_MPSUSER, M_WAITOK|M_ZERO);
723d3c7b9a0SKenneth D. Merry 		error = copyin(page_req->buf, mps_page, page_req->len);
724d3c7b9a0SKenneth D. Merry 		if (error)
725d3c7b9a0SKenneth D. Merry 			break;
726d3c7b9a0SKenneth D. Merry 		mps_lock(sc);
727d3c7b9a0SKenneth D. Merry 		error = mps_user_write_cfg_page(sc, page_req, mps_page);
728d3c7b9a0SKenneth D. Merry 		mps_unlock(sc);
729d3c7b9a0SKenneth D. Merry 		break;
730d3c7b9a0SKenneth D. Merry 	case MPSIO_MPS_COMMAND:
731d3c7b9a0SKenneth D. Merry 		error = mps_user_command(sc, (struct mps_usr_command *)arg);
732d3c7b9a0SKenneth D. Merry 		break;
733d3c7b9a0SKenneth D. Merry 	default:
734d3c7b9a0SKenneth D. Merry 		error = ENOIOCTL;
735d3c7b9a0SKenneth D. Merry 		break;
736d3c7b9a0SKenneth D. Merry 	}
737d3c7b9a0SKenneth D. Merry 
738d3c7b9a0SKenneth D. Merry 	if (mps_page != NULL)
739d3c7b9a0SKenneth D. Merry 		free(mps_page, M_MPSUSER);
740d3c7b9a0SKenneth D. Merry 
741d3c7b9a0SKenneth D. Merry 	return (error);
7425ef98042SMatthew D Fleming }
743d3c7b9a0SKenneth D. Merry 
7445ef98042SMatthew D Fleming #ifdef COMPAT_FREEBSD32
7455ef98042SMatthew D Fleming 
7465ef98042SMatthew D Fleming /* Macros from compat/freebsd32/freebsd32.h */
7475ef98042SMatthew D Fleming #define	PTRIN(v)	(void *)(uintptr_t)(v)
7485ef98042SMatthew D Fleming #define	PTROUT(v)	(uint32_t)(uintptr_t)(v)
7495ef98042SMatthew D Fleming 
7505ef98042SMatthew D Fleming #define	CP(src,dst,fld) do { (dst).fld = (src).fld; } while (0)
7515ef98042SMatthew D Fleming #define	PTRIN_CP(src,dst,fld)				\
7525ef98042SMatthew D Fleming 	do { (dst).fld = PTRIN((src).fld); } while (0)
7535ef98042SMatthew D Fleming #define	PTROUT_CP(src,dst,fld) \
7545ef98042SMatthew D Fleming 	do { (dst).fld = PTROUT((src).fld); } while (0)
7555ef98042SMatthew D Fleming 
7565ef98042SMatthew D Fleming struct mps_cfg_page_req32 {
7575ef98042SMatthew D Fleming 	MPI2_CONFIG_PAGE_HEADER header;
7585ef98042SMatthew D Fleming 	uint32_t page_address;
7595ef98042SMatthew D Fleming 	uint32_t buf;
7605ef98042SMatthew D Fleming 	int	len;
7615ef98042SMatthew D Fleming 	uint16_t ioc_status;
7625ef98042SMatthew D Fleming };
7635ef98042SMatthew D Fleming 
7645ef98042SMatthew D Fleming struct mps_ext_cfg_page_req32 {
7655ef98042SMatthew D Fleming 	MPI2_CONFIG_EXTENDED_PAGE_HEADER header;
7665ef98042SMatthew D Fleming 	uint32_t page_address;
7675ef98042SMatthew D Fleming 	uint32_t buf;
7685ef98042SMatthew D Fleming 	int	len;
7695ef98042SMatthew D Fleming 	uint16_t ioc_status;
7705ef98042SMatthew D Fleming };
7715ef98042SMatthew D Fleming 
7725ef98042SMatthew D Fleming struct mps_raid_action32 {
7735ef98042SMatthew D Fleming 	uint8_t action;
7745ef98042SMatthew D Fleming 	uint8_t volume_bus;
7755ef98042SMatthew D Fleming 	uint8_t volume_id;
7765ef98042SMatthew D Fleming 	uint8_t phys_disk_num;
7775ef98042SMatthew D Fleming 	uint32_t action_data_word;
7785ef98042SMatthew D Fleming 	uint32_t buf;
7795ef98042SMatthew D Fleming 	int len;
7805ef98042SMatthew D Fleming 	uint32_t volume_status;
7815ef98042SMatthew D Fleming 	uint32_t action_data[4];
7825ef98042SMatthew D Fleming 	uint16_t action_status;
7835ef98042SMatthew D Fleming 	uint16_t ioc_status;
7845ef98042SMatthew D Fleming 	uint8_t write;
7855ef98042SMatthew D Fleming };
7865ef98042SMatthew D Fleming 
7875ef98042SMatthew D Fleming struct mps_usr_command32 {
7885ef98042SMatthew D Fleming 	uint32_t req;
7895ef98042SMatthew D Fleming 	uint32_t req_len;
7905ef98042SMatthew D Fleming 	uint32_t rpl;
7915ef98042SMatthew D Fleming 	uint32_t rpl_len;
7925ef98042SMatthew D Fleming 	uint32_t buf;
7935ef98042SMatthew D Fleming 	int len;
7945ef98042SMatthew D Fleming 	uint32_t flags;
7955ef98042SMatthew D Fleming };
7965ef98042SMatthew D Fleming 
7975ef98042SMatthew D Fleming #define	MPSIO_READ_CFG_HEADER32	_IOWR('M', 200, struct mps_cfg_page_req32)
7985ef98042SMatthew D Fleming #define	MPSIO_READ_CFG_PAGE32	_IOWR('M', 201, struct mps_cfg_page_req32)
7995ef98042SMatthew D Fleming #define	MPSIO_READ_EXT_CFG_HEADER32 _IOWR('M', 202, struct mps_ext_cfg_page_req32)
8005ef98042SMatthew D Fleming #define	MPSIO_READ_EXT_CFG_PAGE32 _IOWR('M', 203, struct mps_ext_cfg_page_req32)
8015ef98042SMatthew D Fleming #define	MPSIO_WRITE_CFG_PAGE32	_IOWR('M', 204, struct mps_cfg_page_req32)
8025ef98042SMatthew D Fleming #define	MPSIO_RAID_ACTION32	_IOWR('M', 205, struct mps_raid_action32)
8035ef98042SMatthew D Fleming #define	MPSIO_MPS_COMMAND32	_IOWR('M', 210, struct mps_usr_command32)
8045ef98042SMatthew D Fleming 
8055ef98042SMatthew D Fleming static int
8065ef98042SMatthew D Fleming mps_ioctl32(struct cdev *dev, u_long cmd32, void *_arg, int flag,
8075ef98042SMatthew D Fleming     struct thread *td)
8085ef98042SMatthew D Fleming {
8095ef98042SMatthew D Fleming 	struct mps_cfg_page_req32 *page32 = _arg;
8105ef98042SMatthew D Fleming 	struct mps_ext_cfg_page_req32 *ext32 = _arg;
8115ef98042SMatthew D Fleming 	struct mps_raid_action32 *raid32 = _arg;
8125ef98042SMatthew D Fleming 	struct mps_usr_command32 *user32 = _arg;
8135ef98042SMatthew D Fleming 	union {
8145ef98042SMatthew D Fleming 		struct mps_cfg_page_req page;
8155ef98042SMatthew D Fleming 		struct mps_ext_cfg_page_req ext;
8165ef98042SMatthew D Fleming 		struct mps_raid_action raid;
8175ef98042SMatthew D Fleming 		struct mps_usr_command user;
8185ef98042SMatthew D Fleming 	} arg;
8195ef98042SMatthew D Fleming 	u_long cmd;
8205ef98042SMatthew D Fleming 	int error;
8215ef98042SMatthew D Fleming 
8225ef98042SMatthew D Fleming 	switch (cmd32) {
823d3c7b9a0SKenneth D. Merry 	case MPSIO_READ_CFG_HEADER32:
824d3c7b9a0SKenneth D. Merry 	case MPSIO_READ_CFG_PAGE32:
825d3c7b9a0SKenneth D. Merry 	case MPSIO_WRITE_CFG_PAGE32:
8265ef98042SMatthew D Fleming 		if (cmd32 == MPSIO_READ_CFG_HEADER32)
8275ef98042SMatthew D Fleming 			cmd = MPSIO_READ_CFG_HEADER;
8285ef98042SMatthew D Fleming 		else if (cmd32 == MPSIO_READ_CFG_PAGE32)
8295ef98042SMatthew D Fleming 			cmd = MPSIO_READ_CFG_PAGE;
8305ef98042SMatthew D Fleming 		else
8315ef98042SMatthew D Fleming 			cmd = MPSIO_WRITE_CFG_PAGE;
8325ef98042SMatthew D Fleming 		CP(*page32, arg.page, header);
8335ef98042SMatthew D Fleming 		CP(*page32, arg.page, page_address);
8345ef98042SMatthew D Fleming 		PTRIN_CP(*page32, arg.page, buf);
8355ef98042SMatthew D Fleming 		CP(*page32, arg.page, len);
8365ef98042SMatthew D Fleming 		CP(*page32, arg.page, ioc_status);
837d3c7b9a0SKenneth D. Merry 		break;
8385ef98042SMatthew D Fleming 
839d3c7b9a0SKenneth D. Merry 	case MPSIO_READ_EXT_CFG_HEADER32:
840d3c7b9a0SKenneth D. Merry 	case MPSIO_READ_EXT_CFG_PAGE32:
8415ef98042SMatthew D Fleming 		if (cmd32 == MPSIO_READ_EXT_CFG_HEADER32)
8425ef98042SMatthew D Fleming 			cmd = MPSIO_READ_EXT_CFG_HEADER;
8435ef98042SMatthew D Fleming 		else
8445ef98042SMatthew D Fleming 			cmd = MPSIO_READ_EXT_CFG_PAGE;
8455ef98042SMatthew D Fleming 		CP(*ext32, arg.ext, header);
8465ef98042SMatthew D Fleming 		CP(*ext32, arg.ext, page_address);
8475ef98042SMatthew D Fleming 		PTRIN_CP(*ext32, arg.ext, buf);
8485ef98042SMatthew D Fleming 		CP(*ext32, arg.ext, len);
8495ef98042SMatthew D Fleming 		CP(*ext32, arg.ext, ioc_status);
8505ef98042SMatthew D Fleming 		break;
8515ef98042SMatthew D Fleming 
8525ef98042SMatthew D Fleming 	case MPSIO_RAID_ACTION32:
8535ef98042SMatthew D Fleming 		cmd = MPSIO_RAID_ACTION;
8545ef98042SMatthew D Fleming 		CP(*raid32, arg.raid, action);
8555ef98042SMatthew D Fleming 		CP(*raid32, arg.raid, volume_bus);
8565ef98042SMatthew D Fleming 		CP(*raid32, arg.raid, volume_id);
8575ef98042SMatthew D Fleming 		CP(*raid32, arg.raid, phys_disk_num);
8585ef98042SMatthew D Fleming 		CP(*raid32, arg.raid, action_data_word);
8595ef98042SMatthew D Fleming 		PTRIN_CP(*raid32, arg.raid, buf);
8605ef98042SMatthew D Fleming 		CP(*raid32, arg.raid, len);
8615ef98042SMatthew D Fleming 		CP(*raid32, arg.raid, volume_status);
8625ef98042SMatthew D Fleming 		bcopy(raid32->action_data, arg.raid.action_data,
8635ef98042SMatthew D Fleming 		    sizeof arg.raid.action_data);
8645ef98042SMatthew D Fleming 		CP(*raid32, arg.raid, ioc_status);
8655ef98042SMatthew D Fleming 		CP(*raid32, arg.raid, write);
8665ef98042SMatthew D Fleming 		break;
8675ef98042SMatthew D Fleming 
8685ef98042SMatthew D Fleming 	case MPSIO_MPS_COMMAND32:
8695ef98042SMatthew D Fleming 		cmd = MPSIO_MPS_COMMAND;
8705ef98042SMatthew D Fleming 		PTRIN_CP(*user32, arg.user, req);
8715ef98042SMatthew D Fleming 		CP(*user32, arg.user, req_len);
8725ef98042SMatthew D Fleming 		PTRIN_CP(*user32, arg.user, rpl);
8735ef98042SMatthew D Fleming 		CP(*user32, arg.user, rpl_len);
8745ef98042SMatthew D Fleming 		PTRIN_CP(*user32, arg.user, buf);
8755ef98042SMatthew D Fleming 		CP(*user32, arg.user, len);
8765ef98042SMatthew D Fleming 		CP(*user32, arg.user, flags);
877d3c7b9a0SKenneth D. Merry 		break;
878d3c7b9a0SKenneth D. Merry 	default:
879d3c7b9a0SKenneth D. Merry 		return (ENOIOCTL);
880d3c7b9a0SKenneth D. Merry 	}
881d3c7b9a0SKenneth D. Merry 
8825ef98042SMatthew D Fleming 	error = mps_ioctl(dev, cmd, &arg, flag, td);
8835ef98042SMatthew D Fleming 	if (error == 0 && (cmd32 & IOC_OUT) != 0) {
8845ef98042SMatthew D Fleming 		switch (cmd32) {
8855ef98042SMatthew D Fleming 		case MPSIO_READ_CFG_HEADER32:
8865ef98042SMatthew D Fleming 		case MPSIO_READ_CFG_PAGE32:
8875ef98042SMatthew D Fleming 		case MPSIO_WRITE_CFG_PAGE32:
8885ef98042SMatthew D Fleming 			CP(arg.page, *page32, header);
8895ef98042SMatthew D Fleming 			CP(arg.page, *page32, page_address);
8905ef98042SMatthew D Fleming 			PTROUT_CP(arg.page, *page32, buf);
8915ef98042SMatthew D Fleming 			CP(arg.page, *page32, len);
8925ef98042SMatthew D Fleming 			CP(arg.page, *page32, ioc_status);
8935ef98042SMatthew D Fleming 			break;
8945ef98042SMatthew D Fleming 
8955ef98042SMatthew D Fleming 		case MPSIO_READ_EXT_CFG_HEADER32:
8965ef98042SMatthew D Fleming 		case MPSIO_READ_EXT_CFG_PAGE32:
8975ef98042SMatthew D Fleming 			CP(arg.ext, *ext32, header);
8985ef98042SMatthew D Fleming 			CP(arg.ext, *ext32, page_address);
8995ef98042SMatthew D Fleming 			PTROUT_CP(arg.ext, *ext32, buf);
9005ef98042SMatthew D Fleming 			CP(arg.ext, *ext32, len);
9015ef98042SMatthew D Fleming 			CP(arg.ext, *ext32, ioc_status);
9025ef98042SMatthew D Fleming 			break;
9035ef98042SMatthew D Fleming 
9045ef98042SMatthew D Fleming 		case MPSIO_RAID_ACTION32:
9055ef98042SMatthew D Fleming 			CP(arg.raid, *raid32, action);
9065ef98042SMatthew D Fleming 			CP(arg.raid, *raid32, volume_bus);
9075ef98042SMatthew D Fleming 			CP(arg.raid, *raid32, volume_id);
9085ef98042SMatthew D Fleming 			CP(arg.raid, *raid32, phys_disk_num);
9095ef98042SMatthew D Fleming 			CP(arg.raid, *raid32, action_data_word);
9105ef98042SMatthew D Fleming 			PTROUT_CP(arg.raid, *raid32, buf);
9115ef98042SMatthew D Fleming 			CP(arg.raid, *raid32, len);
9125ef98042SMatthew D Fleming 			CP(arg.raid, *raid32, volume_status);
9135ef98042SMatthew D Fleming 			bcopy(arg.raid.action_data, raid32->action_data,
9145ef98042SMatthew D Fleming 			    sizeof arg.raid.action_data);
9155ef98042SMatthew D Fleming 			CP(arg.raid, *raid32, ioc_status);
9165ef98042SMatthew D Fleming 			CP(arg.raid, *raid32, write);
9175ef98042SMatthew D Fleming 			break;
9185ef98042SMatthew D Fleming 
9195ef98042SMatthew D Fleming 		case MPSIO_MPS_COMMAND32:
9205ef98042SMatthew D Fleming 			PTROUT_CP(arg.user, *user32, req);
9215ef98042SMatthew D Fleming 			CP(arg.user, *user32, req_len);
9225ef98042SMatthew D Fleming 			PTROUT_CP(arg.user, *user32, rpl);
9235ef98042SMatthew D Fleming 			CP(arg.user, *user32, rpl_len);
9245ef98042SMatthew D Fleming 			PTROUT_CP(arg.user, *user32, buf);
9255ef98042SMatthew D Fleming 			CP(arg.user, *user32, len);
9265ef98042SMatthew D Fleming 			CP(arg.user, *user32, flags);
9275ef98042SMatthew D Fleming 			break;
9285ef98042SMatthew D Fleming 		}
9295ef98042SMatthew D Fleming 	}
9305ef98042SMatthew D Fleming 
9315ef98042SMatthew D Fleming 	return (error);
9325ef98042SMatthew D Fleming }
9335ef98042SMatthew D Fleming #endif /* COMPAT_FREEBSD32 */
9345ef98042SMatthew D Fleming 
9355ef98042SMatthew D Fleming static int
9365ef98042SMatthew D Fleming mps_ioctl_devsw(struct cdev *dev, u_long com, caddr_t arg, int flag,
9375ef98042SMatthew D Fleming     struct thread *td)
9385ef98042SMatthew D Fleming {
9395ef98042SMatthew D Fleming #ifdef COMPAT_FREEBSD32
9405ef98042SMatthew D Fleming 	if (SV_CURPROC_FLAG(SV_ILP32))
9415ef98042SMatthew D Fleming 		return (mps_ioctl32(dev, com, arg, flag, td));
9425ef98042SMatthew D Fleming #endif
9435ef98042SMatthew D Fleming 	return (mps_ioctl(dev, com, arg, flag, td));
944d3c7b9a0SKenneth D. Merry }
945