xref: /dragonfly/sys/dev/raid/mps/mps_user.c (revision 030b0c8c)
1c12c399aSSascha Wildner /*-
2c12c399aSSascha Wildner  * Copyright (c) 2008 Yahoo!, Inc.
3c12c399aSSascha Wildner  * All rights reserved.
4c12c399aSSascha Wildner  * Written by: John Baldwin <jhb@FreeBSD.org>
5c12c399aSSascha Wildner  *
6c12c399aSSascha Wildner  * Redistribution and use in source and binary forms, with or without
7c12c399aSSascha Wildner  * modification, are permitted provided that the following conditions
8c12c399aSSascha Wildner  * are met:
9c12c399aSSascha Wildner  * 1. Redistributions of source code must retain the above copyright
10c12c399aSSascha Wildner  *    notice, this list of conditions and the following disclaimer.
11c12c399aSSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
12c12c399aSSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
13c12c399aSSascha Wildner  *    documentation and/or other materials provided with the distribution.
14c12c399aSSascha Wildner  * 3. Neither the name of the author nor the names of any co-contributors
15c12c399aSSascha Wildner  *    may be used to endorse or promote products derived from this software
16c12c399aSSascha Wildner  *    without specific prior written permission.
17c12c399aSSascha Wildner  *
18c12c399aSSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19c12c399aSSascha Wildner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20c12c399aSSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21c12c399aSSascha Wildner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22c12c399aSSascha Wildner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23c12c399aSSascha Wildner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24c12c399aSSascha Wildner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25c12c399aSSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26c12c399aSSascha Wildner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27c12c399aSSascha Wildner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28c12c399aSSascha Wildner  * SUCH DAMAGE.
29c12c399aSSascha Wildner  *
30c12c399aSSascha Wildner  * LSI MPT-Fusion Host Adapter FreeBSD userland interface
31c12c399aSSascha Wildner  */
32c12c399aSSascha Wildner /*-
33c12c399aSSascha Wildner  * Copyright (c) 2011 LSI Corp.
34c12c399aSSascha Wildner  * All rights reserved.
35c12c399aSSascha Wildner  *
36c12c399aSSascha Wildner  * Redistribution and use in source and binary forms, with or without
37c12c399aSSascha Wildner  * modification, are permitted provided that the following conditions
38c12c399aSSascha Wildner  * are met:
39c12c399aSSascha Wildner  * 1. Redistributions of source code must retain the above copyright
40c12c399aSSascha Wildner  *    notice, this list of conditions and the following disclaimer.
41c12c399aSSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
42c12c399aSSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
43c12c399aSSascha Wildner  *    documentation and/or other materials provided with the distribution.
44c12c399aSSascha Wildner  *
45c12c399aSSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
46c12c399aSSascha Wildner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47c12c399aSSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48c12c399aSSascha Wildner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
49c12c399aSSascha Wildner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50c12c399aSSascha Wildner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51c12c399aSSascha Wildner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52c12c399aSSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53c12c399aSSascha Wildner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54c12c399aSSascha Wildner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55c12c399aSSascha Wildner  * SUCH DAMAGE.
56c12c399aSSascha Wildner  *
57c12c399aSSascha Wildner  * LSI MPT-Fusion Host Adapter FreeBSD
58c12c399aSSascha Wildner  *
59c12c399aSSascha Wildner  * $FreeBSD: src/sys/dev/mps/mps_user.c,v 1.10 2012/01/26 18:17:21 ken Exp $
60c12c399aSSascha Wildner  */
61c12c399aSSascha Wildner 
62c12c399aSSascha Wildner /* TODO Move headers to mpsvar */
63c12c399aSSascha Wildner #include <sys/types.h>
64c12c399aSSascha Wildner #include <sys/param.h>
65c12c399aSSascha Wildner #include <sys/systm.h>
66c12c399aSSascha Wildner #include <sys/kernel.h>
67c12c399aSSascha Wildner #include <sys/module.h>
68c12c399aSSascha Wildner #include <sys/bus.h>
69c12c399aSSascha Wildner #include <sys/conf.h>
70c12c399aSSascha Wildner #include <sys/eventhandler.h>
71c12c399aSSascha Wildner #include <sys/bio.h>
72c12c399aSSascha Wildner #include <sys/malloc.h>
73c12c399aSSascha Wildner #include <sys/uio.h>
74c12c399aSSascha Wildner #include <sys/sysctl.h>
75c12c399aSSascha Wildner #include <sys/endian.h>
76c12c399aSSascha Wildner #include <sys/queue.h>
77c12c399aSSascha Wildner #include <sys/kthread.h>
78c12c399aSSascha Wildner #include <sys/taskqueue.h>
79c12c399aSSascha Wildner #include <sys/proc.h>
80c12c399aSSascha Wildner #include <sys/sysent.h>
81c12c399aSSascha Wildner 
82c12c399aSSascha Wildner #include <sys/rman.h>
83c12c399aSSascha Wildner #include <sys/device.h>
84c12c399aSSascha Wildner 
85c12c399aSSascha Wildner #include <bus/cam/cam.h>
86c12c399aSSascha Wildner #include <bus/cam/scsi/scsi_all.h>
87c12c399aSSascha Wildner 
88c12c399aSSascha Wildner #include <dev/raid/mps/mpi/mpi2_type.h>
89c12c399aSSascha Wildner #include <dev/raid/mps/mpi/mpi2.h>
90c12c399aSSascha Wildner #include <dev/raid/mps/mpi/mpi2_ioc.h>
91c12c399aSSascha Wildner #include <dev/raid/mps/mpi/mpi2_cnfg.h>
92c12c399aSSascha Wildner #include <dev/raid/mps/mpi/mpi2_init.h>
93c12c399aSSascha Wildner #include <dev/raid/mps/mpi/mpi2_tool.h>
94c12c399aSSascha Wildner #include <dev/raid/mps/mps_ioctl.h>
95c12c399aSSascha Wildner #include <dev/raid/mps/mpsvar.h>
96c12c399aSSascha Wildner #include <dev/raid/mps/mps_table.h>
97c12c399aSSascha Wildner #include <dev/raid/mps/mps_sas.h>
98c12c399aSSascha Wildner #include <bus/pci/pcivar.h>
99c12c399aSSascha Wildner #include <bus/pci/pcireg.h>
100c12c399aSSascha Wildner 
101c12c399aSSascha Wildner static d_open_t		mps_open;
102c12c399aSSascha Wildner static d_close_t	mps_close;
103c12c399aSSascha Wildner static d_ioctl_t	mps_ioctl_devsw;
104c12c399aSSascha Wildner 
105c12c399aSSascha Wildner static struct dev_ops mps_ops = {
106*ce2dbe12SSascha Wildner 	{ "mps", 0, D_MPSAFE },
107c12c399aSSascha Wildner 	.d_open =	mps_open,
108c12c399aSSascha Wildner 	.d_close =	mps_close,
109c12c399aSSascha Wildner 	.d_ioctl =	mps_ioctl_devsw,
110c12c399aSSascha Wildner };
111c12c399aSSascha Wildner 
112c12c399aSSascha Wildner typedef int (mps_user_f)(struct mps_command *, struct mps_usr_command *);
113c12c399aSSascha Wildner static mps_user_f	mpi_pre_ioc_facts;
114c12c399aSSascha Wildner static mps_user_f	mpi_pre_port_facts;
115c12c399aSSascha Wildner static mps_user_f	mpi_pre_fw_download;
116c12c399aSSascha Wildner static mps_user_f	mpi_pre_fw_upload;
117c12c399aSSascha Wildner static mps_user_f	mpi_pre_sata_passthrough;
118c12c399aSSascha Wildner static mps_user_f	mpi_pre_smp_passthrough;
119c12c399aSSascha Wildner static mps_user_f	mpi_pre_config;
120c12c399aSSascha Wildner static mps_user_f	mpi_pre_sas_io_unit_control;
121c12c399aSSascha Wildner 
122c12c399aSSascha Wildner static int mps_user_read_cfg_header(struct mps_softc *,
123c12c399aSSascha Wildner 				    struct mps_cfg_page_req *);
124c12c399aSSascha Wildner static int mps_user_read_cfg_page(struct mps_softc *,
125c12c399aSSascha Wildner 				  struct mps_cfg_page_req *, void *);
126c12c399aSSascha Wildner static int mps_user_read_extcfg_header(struct mps_softc *,
127c12c399aSSascha Wildner 				     struct mps_ext_cfg_page_req *);
128c12c399aSSascha Wildner static int mps_user_read_extcfg_page(struct mps_softc *,
129c12c399aSSascha Wildner 				     struct mps_ext_cfg_page_req *, void *);
130c12c399aSSascha Wildner static int mps_user_write_cfg_page(struct mps_softc *,
131c12c399aSSascha Wildner 				   struct mps_cfg_page_req *, void *);
132c12c399aSSascha Wildner static int mps_user_setup_request(struct mps_command *,
133c12c399aSSascha Wildner 				  struct mps_usr_command *);
134c12c399aSSascha Wildner static int mps_user_command(struct mps_softc *, struct mps_usr_command *);
135c12c399aSSascha Wildner 
136c12c399aSSascha Wildner static int mps_user_pass_thru(struct mps_softc *sc, mps_pass_thru_t *data);
137c12c399aSSascha Wildner static void mps_user_get_adapter_data(struct mps_softc *sc,
138c12c399aSSascha Wildner     mps_adapter_data_t *data);
139c12c399aSSascha Wildner static void mps_user_read_pci_info(struct mps_softc *sc,
140c12c399aSSascha Wildner     mps_pci_info_t *data);
141c12c399aSSascha Wildner static uint8_t mps_get_fw_diag_buffer_number(struct mps_softc *sc,
142c12c399aSSascha Wildner     uint32_t unique_id);
143c12c399aSSascha Wildner static int mps_post_fw_diag_buffer(struct mps_softc *sc,
144c12c399aSSascha Wildner     mps_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code);
145c12c399aSSascha Wildner static int mps_release_fw_diag_buffer(struct mps_softc *sc,
146c12c399aSSascha Wildner     mps_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code,
147c12c399aSSascha Wildner     uint32_t diag_type);
148c12c399aSSascha Wildner static int mps_diag_register(struct mps_softc *sc,
149c12c399aSSascha Wildner     mps_fw_diag_register_t *diag_register, uint32_t *return_code);
150c12c399aSSascha Wildner static int mps_diag_unregister(struct mps_softc *sc,
151c12c399aSSascha Wildner     mps_fw_diag_unregister_t *diag_unregister, uint32_t *return_code);
152c12c399aSSascha Wildner static int mps_diag_query(struct mps_softc *sc, mps_fw_diag_query_t *diag_query,
153c12c399aSSascha Wildner     uint32_t *return_code);
154c12c399aSSascha Wildner static int mps_diag_read_buffer(struct mps_softc *sc,
155c12c399aSSascha Wildner     mps_diag_read_buffer_t *diag_read_buffer, uint8_t *ioctl_buf,
156c12c399aSSascha Wildner     uint32_t *return_code);
157c12c399aSSascha Wildner static int mps_diag_release(struct mps_softc *sc,
158c12c399aSSascha Wildner     mps_fw_diag_release_t *diag_release, uint32_t *return_code);
159c12c399aSSascha Wildner static int mps_do_diag_action(struct mps_softc *sc, uint32_t action,
160c12c399aSSascha Wildner     uint8_t *diag_action, uint32_t length, uint32_t *return_code);
161c12c399aSSascha Wildner static int mps_user_diag_action(struct mps_softc *sc, mps_diag_action_t *data);
162c12c399aSSascha Wildner static void mps_user_event_query(struct mps_softc *sc, mps_event_query_t *data);
163c12c399aSSascha Wildner static void mps_user_event_enable(struct mps_softc *sc,
164c12c399aSSascha Wildner     mps_event_enable_t *data);
165c12c399aSSascha Wildner static int mps_user_event_report(struct mps_softc *sc,
166c12c399aSSascha Wildner     mps_event_report_t *data);
167c12c399aSSascha Wildner static int mps_user_reg_access(struct mps_softc *sc, mps_reg_access_t *data);
168c12c399aSSascha Wildner static int mps_user_btdh(struct mps_softc *sc, mps_btdh_mapping_t *data);
169c12c399aSSascha Wildner 
170c12c399aSSascha Wildner static MALLOC_DEFINE(M_MPSUSER, "mps_user", "Buffers for mps(4) ioctls");
171c12c399aSSascha Wildner 
172c12c399aSSascha Wildner /* Macros from compat/freebsd32/freebsd32.h */
173c12c399aSSascha Wildner #define	PTRIN(v)	(void *)(uintptr_t)(v)
174c12c399aSSascha Wildner #define	PTROUT(v)	(uint32_t)(uintptr_t)(v)
175c12c399aSSascha Wildner 
176c12c399aSSascha Wildner #define	CP(src,dst,fld) do { (dst).fld = (src).fld; } while (0)
177c12c399aSSascha Wildner #define	PTRIN_CP(src,dst,fld)				\
178c12c399aSSascha Wildner 	do { (dst).fld = PTRIN((src).fld); } while (0)
179c12c399aSSascha Wildner #define	PTROUT_CP(src,dst,fld) \
180c12c399aSSascha Wildner 	do { (dst).fld = PTROUT((src).fld); } while (0)
181c12c399aSSascha Wildner 
182c12c399aSSascha Wildner int
mps_attach_user(struct mps_softc * sc)183c12c399aSSascha Wildner mps_attach_user(struct mps_softc *sc)
184c12c399aSSascha Wildner {
185c12c399aSSascha Wildner 	int unit;
186c12c399aSSascha Wildner 
187c12c399aSSascha Wildner 	unit = device_get_unit(sc->mps_dev);
188c12c399aSSascha Wildner 	sc->mps_cdev = make_dev(&mps_ops, unit, UID_ROOT, GID_OPERATOR, 0640,
189c12c399aSSascha Wildner 	    "mps%d", unit);
190c12c399aSSascha Wildner 	if (sc->mps_cdev == NULL) {
191c12c399aSSascha Wildner 		return (ENOMEM);
192c12c399aSSascha Wildner 	}
193c12c399aSSascha Wildner 	sc->mps_cdev->si_drv1 = sc;
194c12c399aSSascha Wildner 	return (0);
195c12c399aSSascha Wildner }
196c12c399aSSascha Wildner 
197c12c399aSSascha Wildner void
mps_detach_user(struct mps_softc * sc)198c12c399aSSascha Wildner mps_detach_user(struct mps_softc *sc)
199c12c399aSSascha Wildner {
200c12c399aSSascha Wildner 
201c12c399aSSascha Wildner 	/* XXX: do a purge of pending requests? */
20243f7c553SMatthew Dillon 	if (sc->mps_cdev != NULL)
203c12c399aSSascha Wildner 		destroy_dev(sc->mps_cdev);
204c12c399aSSascha Wildner }
205c12c399aSSascha Wildner 
206c12c399aSSascha Wildner static int
mps_open(struct dev_open_args * ap)207c12c399aSSascha Wildner mps_open(struct dev_open_args *ap)
208c12c399aSSascha Wildner {
209c12c399aSSascha Wildner 
210c12c399aSSascha Wildner 	return (0);
211c12c399aSSascha Wildner }
212c12c399aSSascha Wildner 
213c12c399aSSascha Wildner static int
mps_close(struct dev_close_args * ap)214c12c399aSSascha Wildner mps_close(struct dev_close_args *ap)
215c12c399aSSascha Wildner {
216c12c399aSSascha Wildner 
217c12c399aSSascha Wildner 	return (0);
218c12c399aSSascha Wildner }
219c12c399aSSascha Wildner 
220c12c399aSSascha Wildner static int
mps_user_read_cfg_header(struct mps_softc * sc,struct mps_cfg_page_req * page_req)221c12c399aSSascha Wildner mps_user_read_cfg_header(struct mps_softc *sc,
222c12c399aSSascha Wildner     struct mps_cfg_page_req *page_req)
223c12c399aSSascha Wildner {
224c12c399aSSascha Wildner 	MPI2_CONFIG_PAGE_HEADER *hdr;
225c12c399aSSascha Wildner 	struct mps_config_params params;
226c12c399aSSascha Wildner 	int	    error;
227c12c399aSSascha Wildner 
228c12c399aSSascha Wildner 	hdr = &params.hdr.Struct;
229c12c399aSSascha Wildner 	params.action = MPI2_CONFIG_ACTION_PAGE_HEADER;
230c12c399aSSascha Wildner 	params.page_address = le32toh(page_req->page_address);
231c12c399aSSascha Wildner 	hdr->PageVersion = 0;
232c12c399aSSascha Wildner 	hdr->PageLength = 0;
233c12c399aSSascha Wildner 	hdr->PageNumber = page_req->header.PageNumber;
234c12c399aSSascha Wildner 	hdr->PageType = page_req->header.PageType;
235c12c399aSSascha Wildner 	params.buffer = NULL;
236c12c399aSSascha Wildner 	params.length = 0;
237c12c399aSSascha Wildner 	params.callback = NULL;
238c12c399aSSascha Wildner 
239c12c399aSSascha Wildner 	if ((error = mps_read_config_page(sc, &params)) != 0) {
240c12c399aSSascha Wildner 		/*
241c12c399aSSascha Wildner 		 * Leave the request. Without resetting the chip, it's
242c12c399aSSascha Wildner 		 * still owned by it and we'll just get into trouble
243c12c399aSSascha Wildner 		 * freeing it now. Mark it as abandoned so that if it
244c12c399aSSascha Wildner 		 * shows up later it can be freed.
245c12c399aSSascha Wildner 		 */
246c12c399aSSascha Wildner 		mps_printf(sc, "read_cfg_header timed out\n");
247c12c399aSSascha Wildner 		return (ETIMEDOUT);
248c12c399aSSascha Wildner 	}
249c12c399aSSascha Wildner 
250c12c399aSSascha Wildner 	page_req->ioc_status = htole16(params.status);
251c12c399aSSascha Wildner 	if ((page_req->ioc_status & MPI2_IOCSTATUS_MASK) ==
252c12c399aSSascha Wildner 	    MPI2_IOCSTATUS_SUCCESS) {
253c12c399aSSascha Wildner 		bcopy(hdr, &page_req->header, sizeof(page_req->header));
254c12c399aSSascha Wildner 	}
255c12c399aSSascha Wildner 
256c12c399aSSascha Wildner 	return (0);
257c12c399aSSascha Wildner }
258c12c399aSSascha Wildner 
259c12c399aSSascha Wildner static int
mps_user_read_cfg_page(struct mps_softc * sc,struct mps_cfg_page_req * page_req,void * buf)260c12c399aSSascha Wildner mps_user_read_cfg_page(struct mps_softc *sc, struct mps_cfg_page_req *page_req,
261c12c399aSSascha Wildner     void *buf)
262c12c399aSSascha Wildner {
263c12c399aSSascha Wildner 	MPI2_CONFIG_PAGE_HEADER *reqhdr, *hdr;
264c12c399aSSascha Wildner 	struct mps_config_params params;
265c12c399aSSascha Wildner 	int	      error;
266c12c399aSSascha Wildner 
267c12c399aSSascha Wildner 	reqhdr = buf;
268c12c399aSSascha Wildner 	hdr = &params.hdr.Struct;
269c12c399aSSascha Wildner 	hdr->PageVersion = reqhdr->PageVersion;
270c12c399aSSascha Wildner 	hdr->PageLength = reqhdr->PageLength;
271c12c399aSSascha Wildner 	hdr->PageNumber = reqhdr->PageNumber;
272c12c399aSSascha Wildner 	hdr->PageType = reqhdr->PageType & MPI2_CONFIG_PAGETYPE_MASK;
273c12c399aSSascha Wildner 	params.action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
274c12c399aSSascha Wildner 	params.page_address = le32toh(page_req->page_address);
275c12c399aSSascha Wildner 	params.buffer = buf;
276c12c399aSSascha Wildner 	params.length = le32toh(page_req->len);
277c12c399aSSascha Wildner 	params.callback = NULL;
278c12c399aSSascha Wildner 
279c12c399aSSascha Wildner 	if ((error = mps_read_config_page(sc, &params)) != 0) {
280c12c399aSSascha Wildner 		mps_printf(sc, "mps_user_read_cfg_page timed out\n");
281c12c399aSSascha Wildner 		return (ETIMEDOUT);
282c12c399aSSascha Wildner 	}
283c12c399aSSascha Wildner 
284c12c399aSSascha Wildner 	page_req->ioc_status = htole16(params.status);
285c12c399aSSascha Wildner 	return (0);
286c12c399aSSascha Wildner }
287c12c399aSSascha Wildner 
288c12c399aSSascha Wildner static int
mps_user_read_extcfg_header(struct mps_softc * sc,struct mps_ext_cfg_page_req * ext_page_req)289c12c399aSSascha Wildner mps_user_read_extcfg_header(struct mps_softc *sc,
290c12c399aSSascha Wildner     struct mps_ext_cfg_page_req *ext_page_req)
291c12c399aSSascha Wildner {
292c12c399aSSascha Wildner 	MPI2_CONFIG_EXTENDED_PAGE_HEADER *hdr;
293c12c399aSSascha Wildner 	struct mps_config_params params;
294c12c399aSSascha Wildner 	int	    error;
295c12c399aSSascha Wildner 
296c12c399aSSascha Wildner 	hdr = &params.hdr.Ext;
297c12c399aSSascha Wildner 	params.action = MPI2_CONFIG_ACTION_PAGE_HEADER;
298c12c399aSSascha Wildner 	hdr->PageVersion = ext_page_req->header.PageVersion;
29943f7c553SMatthew Dillon 	hdr->PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
300c12c399aSSascha Wildner 	hdr->ExtPageLength = 0;
301c12c399aSSascha Wildner 	hdr->PageNumber = ext_page_req->header.PageNumber;
302c12c399aSSascha Wildner 	hdr->ExtPageType = ext_page_req->header.ExtPageType;
303c12c399aSSascha Wildner 	params.page_address = le32toh(ext_page_req->page_address);
304c12c399aSSascha Wildner 	if ((error = mps_read_config_page(sc, &params)) != 0) {
305c12c399aSSascha Wildner 		/*
306c12c399aSSascha Wildner 		 * Leave the request. Without resetting the chip, it's
307c12c399aSSascha Wildner 		 * still owned by it and we'll just get into trouble
308c12c399aSSascha Wildner 		 * freeing it now. Mark it as abandoned so that if it
309c12c399aSSascha Wildner 		 * shows up later it can be freed.
310c12c399aSSascha Wildner 		 */
311c12c399aSSascha Wildner 		mps_printf(sc, "mps_user_read_extcfg_header timed out\n");
312c12c399aSSascha Wildner 		return (ETIMEDOUT);
313c12c399aSSascha Wildner 	}
314c12c399aSSascha Wildner 
315c12c399aSSascha Wildner 	ext_page_req->ioc_status = htole16(params.status);
316c12c399aSSascha Wildner 	if ((ext_page_req->ioc_status & MPI2_IOCSTATUS_MASK) ==
317c12c399aSSascha Wildner 	    MPI2_IOCSTATUS_SUCCESS) {
318c12c399aSSascha Wildner 		ext_page_req->header.PageVersion = hdr->PageVersion;
319c12c399aSSascha Wildner 		ext_page_req->header.PageNumber = hdr->PageNumber;
320c12c399aSSascha Wildner 		ext_page_req->header.PageType = hdr->PageType;
321c12c399aSSascha Wildner 		ext_page_req->header.ExtPageLength = hdr->ExtPageLength;
322c12c399aSSascha Wildner 		ext_page_req->header.ExtPageType = hdr->ExtPageType;
323c12c399aSSascha Wildner 	}
324c12c399aSSascha Wildner 
325c12c399aSSascha Wildner 	return (0);
326c12c399aSSascha Wildner }
327c12c399aSSascha Wildner 
328c12c399aSSascha Wildner static int
mps_user_read_extcfg_page(struct mps_softc * sc,struct mps_ext_cfg_page_req * ext_page_req,void * buf)329c12c399aSSascha Wildner mps_user_read_extcfg_page(struct mps_softc *sc,
330c12c399aSSascha Wildner     struct mps_ext_cfg_page_req *ext_page_req, void *buf)
331c12c399aSSascha Wildner {
332c12c399aSSascha Wildner 	MPI2_CONFIG_EXTENDED_PAGE_HEADER *reqhdr, *hdr;
333c12c399aSSascha Wildner 	struct mps_config_params params;
334c12c399aSSascha Wildner 	int error;
335c12c399aSSascha Wildner 
336c12c399aSSascha Wildner 	reqhdr = buf;
337c12c399aSSascha Wildner 	hdr = &params.hdr.Ext;
338c12c399aSSascha Wildner 	params.action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
339c12c399aSSascha Wildner 	params.page_address = le32toh(ext_page_req->page_address);
340c12c399aSSascha Wildner 	hdr->PageVersion = reqhdr->PageVersion;
34143f7c553SMatthew Dillon 	hdr->PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
342c12c399aSSascha Wildner 	hdr->PageNumber = reqhdr->PageNumber;
343c12c399aSSascha Wildner 	hdr->ExtPageType = reqhdr->ExtPageType;
344c12c399aSSascha Wildner 	hdr->ExtPageLength = reqhdr->ExtPageLength;
345c12c399aSSascha Wildner 	params.buffer = buf;
346c12c399aSSascha Wildner 	params.length = le32toh(ext_page_req->len);
347c12c399aSSascha Wildner 	params.callback = NULL;
348c12c399aSSascha Wildner 
349c12c399aSSascha Wildner 	if ((error = mps_read_config_page(sc, &params)) != 0) {
350c12c399aSSascha Wildner 		mps_printf(sc, "mps_user_read_extcfg_page timed out\n");
351c12c399aSSascha Wildner 		return (ETIMEDOUT);
352c12c399aSSascha Wildner 	}
353c12c399aSSascha Wildner 
354c12c399aSSascha Wildner 	ext_page_req->ioc_status = htole16(params.status);
355c12c399aSSascha Wildner 	return (0);
356c12c399aSSascha Wildner }
357c12c399aSSascha Wildner 
358c12c399aSSascha Wildner static int
mps_user_write_cfg_page(struct mps_softc * sc,struct mps_cfg_page_req * page_req,void * buf)359c12c399aSSascha Wildner mps_user_write_cfg_page(struct mps_softc *sc,
360c12c399aSSascha Wildner     struct mps_cfg_page_req *page_req, void *buf)
361c12c399aSSascha Wildner {
362c12c399aSSascha Wildner 	MPI2_CONFIG_PAGE_HEADER *reqhdr, *hdr;
363c12c399aSSascha Wildner 	struct mps_config_params params;
364c12c399aSSascha Wildner 	u_int	      hdr_attr;
365c12c399aSSascha Wildner 	int	      error;
366c12c399aSSascha Wildner 
367c12c399aSSascha Wildner 	reqhdr = buf;
368c12c399aSSascha Wildner 	hdr = &params.hdr.Struct;
369c12c399aSSascha Wildner 	hdr_attr = reqhdr->PageType & MPI2_CONFIG_PAGEATTR_MASK;
370c12c399aSSascha Wildner 	if (hdr_attr != MPI2_CONFIG_PAGEATTR_CHANGEABLE &&
371c12c399aSSascha Wildner 	    hdr_attr != MPI2_CONFIG_PAGEATTR_PERSISTENT) {
372c12c399aSSascha Wildner 		mps_printf(sc, "page type 0x%x not changeable\n",
373c12c399aSSascha Wildner 			reqhdr->PageType & MPI2_CONFIG_PAGETYPE_MASK);
374c12c399aSSascha Wildner 		return (EINVAL);
375c12c399aSSascha Wildner 	}
376c12c399aSSascha Wildner 
377c12c399aSSascha Wildner 	/*
378c12c399aSSascha Wildner 	 * There isn't any point in restoring stripped out attributes
379c12c399aSSascha Wildner 	 * if you then mask them going down to issue the request.
380c12c399aSSascha Wildner 	 */
381c12c399aSSascha Wildner 
382c12c399aSSascha Wildner 	hdr->PageVersion = reqhdr->PageVersion;
383c12c399aSSascha Wildner 	hdr->PageLength = reqhdr->PageLength;
384c12c399aSSascha Wildner 	hdr->PageNumber = reqhdr->PageNumber;
385c12c399aSSascha Wildner 	hdr->PageType = reqhdr->PageType;
386c12c399aSSascha Wildner 	params.action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT;
387c12c399aSSascha Wildner 	params.page_address = le32toh(page_req->page_address);
388c12c399aSSascha Wildner 	params.buffer = buf;
389c12c399aSSascha Wildner 	params.length = le32toh(page_req->len);
390c12c399aSSascha Wildner 	params.callback = NULL;
391c12c399aSSascha Wildner 
392c12c399aSSascha Wildner 	if ((error = mps_write_config_page(sc, &params)) != 0) {
393c12c399aSSascha Wildner 		mps_printf(sc, "mps_write_cfg_page timed out\n");
394c12c399aSSascha Wildner 		return (ETIMEDOUT);
395c12c399aSSascha Wildner 	}
396c12c399aSSascha Wildner 
397c12c399aSSascha Wildner 	page_req->ioc_status = htole16(params.status);
398c12c399aSSascha Wildner 	return (0);
399c12c399aSSascha Wildner }
400c12c399aSSascha Wildner 
401c12c399aSSascha Wildner void
mpi_init_sge(struct mps_command * cm,void * req,void * sge)402c12c399aSSascha Wildner mpi_init_sge(struct mps_command *cm, void *req, void *sge)
403c12c399aSSascha Wildner {
404c12c399aSSascha Wildner 	int off, space;
405c12c399aSSascha Wildner 
406c12c399aSSascha Wildner 	space = (int)cm->cm_sc->facts->IOCRequestFrameSize * 4;
407c12c399aSSascha Wildner 	off = (uintptr_t)sge - (uintptr_t)req;
408c12c399aSSascha Wildner 
409c12c399aSSascha Wildner 	KASSERT(off < space, ("bad pointers %p %p, off %d, space %d",
410c12c399aSSascha Wildner             req, sge, off, space));
411c12c399aSSascha Wildner 
412c12c399aSSascha Wildner 	cm->cm_sge = sge;
413c12c399aSSascha Wildner 	cm->cm_sglsize = space - off;
414c12c399aSSascha Wildner }
415c12c399aSSascha Wildner 
416c12c399aSSascha Wildner /*
417c12c399aSSascha Wildner  * Prepare the mps_command for an IOC_FACTS request.
418c12c399aSSascha Wildner  */
419c12c399aSSascha Wildner static int
mpi_pre_ioc_facts(struct mps_command * cm,struct mps_usr_command * cmd)420c12c399aSSascha Wildner mpi_pre_ioc_facts(struct mps_command *cm, struct mps_usr_command *cmd)
421c12c399aSSascha Wildner {
422c12c399aSSascha Wildner 	MPI2_IOC_FACTS_REQUEST *req = (void *)cm->cm_req;
423c12c399aSSascha Wildner 	MPI2_IOC_FACTS_REPLY *rpl;
424c12c399aSSascha Wildner 
425c12c399aSSascha Wildner 	if (cmd->req_len != sizeof *req)
426c12c399aSSascha Wildner 		return (EINVAL);
427c12c399aSSascha Wildner 	if (cmd->rpl_len != sizeof *rpl)
428c12c399aSSascha Wildner 		return (EINVAL);
429c12c399aSSascha Wildner 
430c12c399aSSascha Wildner 	cm->cm_sge = NULL;
431c12c399aSSascha Wildner 	cm->cm_sglsize = 0;
432c12c399aSSascha Wildner 	return (0);
433c12c399aSSascha Wildner }
434c12c399aSSascha Wildner 
435c12c399aSSascha Wildner /*
436c12c399aSSascha Wildner  * Prepare the mps_command for a PORT_FACTS request.
437c12c399aSSascha Wildner  */
438c12c399aSSascha Wildner static int
mpi_pre_port_facts(struct mps_command * cm,struct mps_usr_command * cmd)439c12c399aSSascha Wildner mpi_pre_port_facts(struct mps_command *cm, struct mps_usr_command *cmd)
440c12c399aSSascha Wildner {
441c12c399aSSascha Wildner 	MPI2_PORT_FACTS_REQUEST *req = (void *)cm->cm_req;
442c12c399aSSascha Wildner 	MPI2_PORT_FACTS_REPLY *rpl;
443c12c399aSSascha Wildner 
444c12c399aSSascha Wildner 	if (cmd->req_len != sizeof *req)
445c12c399aSSascha Wildner 		return (EINVAL);
446c12c399aSSascha Wildner 	if (cmd->rpl_len != sizeof *rpl)
447c12c399aSSascha Wildner 		return (EINVAL);
448c12c399aSSascha Wildner 
449c12c399aSSascha Wildner 	cm->cm_sge = NULL;
450c12c399aSSascha Wildner 	cm->cm_sglsize = 0;
451c12c399aSSascha Wildner 	return (0);
452c12c399aSSascha Wildner }
453c12c399aSSascha Wildner 
454c12c399aSSascha Wildner /*
455c12c399aSSascha Wildner  * Prepare the mps_command for a FW_DOWNLOAD request.
456c12c399aSSascha Wildner  */
457c12c399aSSascha Wildner static int
mpi_pre_fw_download(struct mps_command * cm,struct mps_usr_command * cmd)458c12c399aSSascha Wildner mpi_pre_fw_download(struct mps_command *cm, struct mps_usr_command *cmd)
459c12c399aSSascha Wildner {
460c12c399aSSascha Wildner 	MPI2_FW_DOWNLOAD_REQUEST *req = (void *)cm->cm_req;
461c12c399aSSascha Wildner 	MPI2_FW_DOWNLOAD_REPLY *rpl;
462c12c399aSSascha Wildner 	MPI2_FW_DOWNLOAD_TCSGE tc;
463c12c399aSSascha Wildner 	int error;
464c12c399aSSascha Wildner 
465c12c399aSSascha Wildner 	/*
466c12c399aSSascha Wildner 	 * This code assumes there is room in the request's SGL for
467c12c399aSSascha Wildner 	 * the TransactionContext plus at least a SGL chain element.
468c12c399aSSascha Wildner 	 */
469c12c399aSSascha Wildner 	CTASSERT(sizeof req->SGL >= sizeof tc + MPS_SGC_SIZE);
470c12c399aSSascha Wildner 
471c12c399aSSascha Wildner 	if (cmd->req_len != sizeof *req)
472c12c399aSSascha Wildner 		return (EINVAL);
473c12c399aSSascha Wildner 	if (cmd->rpl_len != sizeof *rpl)
474c12c399aSSascha Wildner 		return (EINVAL);
475c12c399aSSascha Wildner 
476c12c399aSSascha Wildner 	if (cmd->len == 0)
477c12c399aSSascha Wildner 		return (EINVAL);
478c12c399aSSascha Wildner 
479c12c399aSSascha Wildner 	error = copyin(cmd->buf, cm->cm_data, cmd->len);
480c12c399aSSascha Wildner 	if (error != 0)
481c12c399aSSascha Wildner 		return (error);
482c12c399aSSascha Wildner 
483c12c399aSSascha Wildner 	mpi_init_sge(cm, req, &req->SGL);
484c12c399aSSascha Wildner 	bzero(&tc, sizeof tc);
485c12c399aSSascha Wildner 
486c12c399aSSascha Wildner 	/*
487c12c399aSSascha Wildner 	 * For now, the F/W image must be provided in a single request.
488c12c399aSSascha Wildner 	 */
489c12c399aSSascha Wildner 	if ((req->MsgFlags & MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT) == 0)
490c12c399aSSascha Wildner 		return (EINVAL);
491c12c399aSSascha Wildner 	if (req->TotalImageSize != cmd->len)
492c12c399aSSascha Wildner 		return (EINVAL);
493c12c399aSSascha Wildner 
494c12c399aSSascha Wildner 	/*
495c12c399aSSascha Wildner 	 * The value of the first two elements is specified in the
496c12c399aSSascha Wildner 	 * Fusion-MPT Message Passing Interface document.
497c12c399aSSascha Wildner 	 */
498c12c399aSSascha Wildner 	tc.ContextSize = 0;
499c12c399aSSascha Wildner 	tc.DetailsLength = 12;
500c12c399aSSascha Wildner 	tc.ImageOffset = 0;
501c12c399aSSascha Wildner 	tc.ImageSize = cmd->len;
502c12c399aSSascha Wildner 
503c12c399aSSascha Wildner 	cm->cm_flags |= MPS_CM_FLAGS_DATAOUT;
504c12c399aSSascha Wildner 
505c12c399aSSascha Wildner 	return (mps_push_sge(cm, &tc, sizeof tc, 0));
506c12c399aSSascha Wildner }
507c12c399aSSascha Wildner 
508c12c399aSSascha Wildner /*
509c12c399aSSascha Wildner  * Prepare the mps_command for a FW_UPLOAD request.
510c12c399aSSascha Wildner  */
511c12c399aSSascha Wildner static int
mpi_pre_fw_upload(struct mps_command * cm,struct mps_usr_command * cmd)512c12c399aSSascha Wildner mpi_pre_fw_upload(struct mps_command *cm, struct mps_usr_command *cmd)
513c12c399aSSascha Wildner {
514c12c399aSSascha Wildner 	MPI2_FW_UPLOAD_REQUEST *req = (void *)cm->cm_req;
515c12c399aSSascha Wildner 	MPI2_FW_UPLOAD_REPLY *rpl;
516c12c399aSSascha Wildner 	MPI2_FW_UPLOAD_TCSGE tc;
517c12c399aSSascha Wildner 
518c12c399aSSascha Wildner 	/*
519c12c399aSSascha Wildner 	 * This code assumes there is room in the request's SGL for
520c12c399aSSascha Wildner 	 * the TransactionContext plus at least a SGL chain element.
521c12c399aSSascha Wildner 	 */
522c12c399aSSascha Wildner 	CTASSERT(sizeof req->SGL >= sizeof tc + MPS_SGC_SIZE);
523c12c399aSSascha Wildner 
524c12c399aSSascha Wildner 	if (cmd->req_len != sizeof *req)
525c12c399aSSascha Wildner 		return (EINVAL);
526c12c399aSSascha Wildner 	if (cmd->rpl_len != sizeof *rpl)
527c12c399aSSascha Wildner 		return (EINVAL);
528c12c399aSSascha Wildner 
529c12c399aSSascha Wildner 	mpi_init_sge(cm, req, &req->SGL);
530c12c399aSSascha Wildner 	bzero(&tc, sizeof tc);
531c12c399aSSascha Wildner 
532c12c399aSSascha Wildner 	/*
533c12c399aSSascha Wildner 	 * The value of the first two elements is specified in the
534c12c399aSSascha Wildner 	 * Fusion-MPT Message Passing Interface document.
535c12c399aSSascha Wildner 	 */
536c12c399aSSascha Wildner 	tc.ContextSize = 0;
537c12c399aSSascha Wildner 	tc.DetailsLength = 12;
538c12c399aSSascha Wildner 	/*
539c12c399aSSascha Wildner 	 * XXX Is there any reason to fetch a partial image?  I.e. to
540c12c399aSSascha Wildner 	 * set ImageOffset to something other than 0?
541c12c399aSSascha Wildner 	 */
542c12c399aSSascha Wildner 	tc.ImageOffset = 0;
543c12c399aSSascha Wildner 	tc.ImageSize = cmd->len;
544c12c399aSSascha Wildner 
54543f7c553SMatthew Dillon 	cm->cm_flags |= MPS_CM_FLAGS_DATAIN;
54643f7c553SMatthew Dillon 
547c12c399aSSascha Wildner 	return (mps_push_sge(cm, &tc, sizeof tc, 0));
548c12c399aSSascha Wildner }
549c12c399aSSascha Wildner 
550c12c399aSSascha Wildner /*
551c12c399aSSascha Wildner  * Prepare the mps_command for a SATA_PASSTHROUGH request.
552c12c399aSSascha Wildner  */
553c12c399aSSascha Wildner static int
mpi_pre_sata_passthrough(struct mps_command * cm,struct mps_usr_command * cmd)554c12c399aSSascha Wildner mpi_pre_sata_passthrough(struct mps_command *cm, struct mps_usr_command *cmd)
555c12c399aSSascha Wildner {
556c12c399aSSascha Wildner 	MPI2_SATA_PASSTHROUGH_REQUEST *req = (void *)cm->cm_req;
557c12c399aSSascha Wildner 	MPI2_SATA_PASSTHROUGH_REPLY *rpl;
558c12c399aSSascha Wildner 
559c12c399aSSascha Wildner 	if (cmd->req_len != sizeof *req)
560c12c399aSSascha Wildner 		return (EINVAL);
561c12c399aSSascha Wildner 	if (cmd->rpl_len != sizeof *rpl)
562c12c399aSSascha Wildner 		return (EINVAL);
563c12c399aSSascha Wildner 
564c12c399aSSascha Wildner 	mpi_init_sge(cm, req, &req->SGL);
565c12c399aSSascha Wildner 	return (0);
566c12c399aSSascha Wildner }
567c12c399aSSascha Wildner 
568c12c399aSSascha Wildner /*
569c12c399aSSascha Wildner  * Prepare the mps_command for a SMP_PASSTHROUGH request.
570c12c399aSSascha Wildner  */
571c12c399aSSascha Wildner static int
mpi_pre_smp_passthrough(struct mps_command * cm,struct mps_usr_command * cmd)572c12c399aSSascha Wildner mpi_pre_smp_passthrough(struct mps_command *cm, struct mps_usr_command *cmd)
573c12c399aSSascha Wildner {
574c12c399aSSascha Wildner 	MPI2_SMP_PASSTHROUGH_REQUEST *req = (void *)cm->cm_req;
575c12c399aSSascha Wildner 	MPI2_SMP_PASSTHROUGH_REPLY *rpl;
576c12c399aSSascha Wildner 
577c12c399aSSascha Wildner 	if (cmd->req_len != sizeof *req)
578c12c399aSSascha Wildner 		return (EINVAL);
579c12c399aSSascha Wildner 	if (cmd->rpl_len != sizeof *rpl)
580c12c399aSSascha Wildner 		return (EINVAL);
581c12c399aSSascha Wildner 
582c12c399aSSascha Wildner 	mpi_init_sge(cm, req, &req->SGL);
583c12c399aSSascha Wildner 	return (0);
584c12c399aSSascha Wildner }
585c12c399aSSascha Wildner 
586c12c399aSSascha Wildner /*
587c12c399aSSascha Wildner  * Prepare the mps_command for a CONFIG request.
588c12c399aSSascha Wildner  */
589c12c399aSSascha Wildner static int
mpi_pre_config(struct mps_command * cm,struct mps_usr_command * cmd)590c12c399aSSascha Wildner mpi_pre_config(struct mps_command *cm, struct mps_usr_command *cmd)
591c12c399aSSascha Wildner {
592c12c399aSSascha Wildner 	MPI2_CONFIG_REQUEST *req = (void *)cm->cm_req;
593c12c399aSSascha Wildner 	MPI2_CONFIG_REPLY *rpl;
594c12c399aSSascha Wildner 
595c12c399aSSascha Wildner 	if (cmd->req_len != sizeof *req)
596c12c399aSSascha Wildner 		return (EINVAL);
597c12c399aSSascha Wildner 	if (cmd->rpl_len != sizeof *rpl)
598c12c399aSSascha Wildner 		return (EINVAL);
599c12c399aSSascha Wildner 
600c12c399aSSascha Wildner 	mpi_init_sge(cm, req, &req->PageBufferSGE);
601c12c399aSSascha Wildner 	return (0);
602c12c399aSSascha Wildner }
603c12c399aSSascha Wildner 
604c12c399aSSascha Wildner /*
605c12c399aSSascha Wildner  * Prepare the mps_command for a SAS_IO_UNIT_CONTROL request.
606c12c399aSSascha Wildner  */
607c12c399aSSascha Wildner static int
mpi_pre_sas_io_unit_control(struct mps_command * cm,struct mps_usr_command * cmd)608c12c399aSSascha Wildner mpi_pre_sas_io_unit_control(struct mps_command *cm,
609c12c399aSSascha Wildner 			     struct mps_usr_command *cmd)
610c12c399aSSascha Wildner {
611c12c399aSSascha Wildner 
612c12c399aSSascha Wildner 	cm->cm_sge = NULL;
613c12c399aSSascha Wildner 	cm->cm_sglsize = 0;
614c12c399aSSascha Wildner 	return (0);
615c12c399aSSascha Wildner }
616c12c399aSSascha Wildner 
617c12c399aSSascha Wildner /*
618c12c399aSSascha Wildner  * A set of functions to prepare an mps_command for the various
619c12c399aSSascha Wildner  * supported requests.
620c12c399aSSascha Wildner  */
621c12c399aSSascha Wildner struct mps_user_func {
622c12c399aSSascha Wildner 	U8		Function;
623c12c399aSSascha Wildner 	mps_user_f	*f_pre;
624c12c399aSSascha Wildner } mps_user_func_list[] = {
625c12c399aSSascha Wildner 	{ MPI2_FUNCTION_IOC_FACTS,		mpi_pre_ioc_facts },
626c12c399aSSascha Wildner 	{ MPI2_FUNCTION_PORT_FACTS,		mpi_pre_port_facts },
627c12c399aSSascha Wildner 	{ MPI2_FUNCTION_FW_DOWNLOAD, 		mpi_pre_fw_download },
628c12c399aSSascha Wildner 	{ MPI2_FUNCTION_FW_UPLOAD,		mpi_pre_fw_upload },
629c12c399aSSascha Wildner 	{ MPI2_FUNCTION_SATA_PASSTHROUGH,	mpi_pre_sata_passthrough },
630c12c399aSSascha Wildner 	{ MPI2_FUNCTION_SMP_PASSTHROUGH,	mpi_pre_smp_passthrough},
631c12c399aSSascha Wildner 	{ MPI2_FUNCTION_CONFIG,			mpi_pre_config},
632c12c399aSSascha Wildner 	{ MPI2_FUNCTION_SAS_IO_UNIT_CONTROL,	mpi_pre_sas_io_unit_control },
633c12c399aSSascha Wildner 	{ 0xFF,					NULL } /* list end */
634c12c399aSSascha Wildner };
635c12c399aSSascha Wildner 
636c12c399aSSascha Wildner static int
mps_user_setup_request(struct mps_command * cm,struct mps_usr_command * cmd)637c12c399aSSascha Wildner mps_user_setup_request(struct mps_command *cm, struct mps_usr_command *cmd)
638c12c399aSSascha Wildner {
639c12c399aSSascha Wildner 	MPI2_REQUEST_HEADER *hdr = (MPI2_REQUEST_HEADER *)cm->cm_req;
640c12c399aSSascha Wildner 	struct mps_user_func *f;
641c12c399aSSascha Wildner 
642c12c399aSSascha Wildner 	for (f = mps_user_func_list; f->f_pre != NULL; f++) {
643c12c399aSSascha Wildner 		if (hdr->Function == f->Function)
644c12c399aSSascha Wildner 			return (f->f_pre(cm, cmd));
645c12c399aSSascha Wildner 	}
646c12c399aSSascha Wildner 	return (EINVAL);
647c12c399aSSascha Wildner }
648c12c399aSSascha Wildner 
649c12c399aSSascha Wildner static int
mps_user_command(struct mps_softc * sc,struct mps_usr_command * cmd)650c12c399aSSascha Wildner mps_user_command(struct mps_softc *sc, struct mps_usr_command *cmd)
651c12c399aSSascha Wildner {
652c12c399aSSascha Wildner 	MPI2_REQUEST_HEADER *hdr;
653c12c399aSSascha Wildner 	MPI2_DEFAULT_REPLY *rpl;
654c12c399aSSascha Wildner 	void *buf = NULL;
655c12c399aSSascha Wildner 	struct mps_command *cm = NULL;
656c12c399aSSascha Wildner 	int err = 0;
657c12c399aSSascha Wildner 	int sz;
658c12c399aSSascha Wildner 
659c12c399aSSascha Wildner 	mps_lock(sc);
660c12c399aSSascha Wildner 	cm = mps_alloc_command(sc);
661c12c399aSSascha Wildner 
662c12c399aSSascha Wildner 	if (cm == NULL) {
663c12c399aSSascha Wildner 		mps_printf(sc, "mps_user_command: no mps requests\n");
664c12c399aSSascha Wildner 		err = ENOMEM;
665c12c399aSSascha Wildner 		goto Ret;
666c12c399aSSascha Wildner 	}
667c12c399aSSascha Wildner 	mps_unlock(sc);
668c12c399aSSascha Wildner 
669c12c399aSSascha Wildner 	hdr = (MPI2_REQUEST_HEADER *)cm->cm_req;
670c12c399aSSascha Wildner 
671c12c399aSSascha Wildner 	mps_dprint(sc, MPS_INFO, "mps_user_command: req %p %d  rpl %p %d\n",
672c12c399aSSascha Wildner 		    cmd->req, cmd->req_len, cmd->rpl, cmd->rpl_len );
673c12c399aSSascha Wildner 
674c12c399aSSascha Wildner 	if (cmd->req_len > (int)sc->facts->IOCRequestFrameSize * 4) {
675c12c399aSSascha Wildner 		err = EINVAL;
676c12c399aSSascha Wildner 		goto RetFreeUnlocked;
677c12c399aSSascha Wildner 	}
678c12c399aSSascha Wildner 	err = copyin(cmd->req, hdr, cmd->req_len);
679c12c399aSSascha Wildner 	if (err != 0)
680c12c399aSSascha Wildner 		goto RetFreeUnlocked;
681c12c399aSSascha Wildner 
682c12c399aSSascha Wildner 	mps_dprint(sc, MPS_INFO, "mps_user_command: Function %02X  "
683c12c399aSSascha Wildner 	    "MsgFlags %02X\n", hdr->Function, hdr->MsgFlags );
684c12c399aSSascha Wildner 
685c12c399aSSascha Wildner 	if (cmd->len > 0) {
686c12c399aSSascha Wildner 		buf = kmalloc(cmd->len, M_MPSUSER, M_WAITOK|M_ZERO);
687c12c399aSSascha Wildner 		cm->cm_data = buf;
688c12c399aSSascha Wildner 		cm->cm_length = cmd->len;
689c12c399aSSascha Wildner 	} else {
690c12c399aSSascha Wildner 		cm->cm_data = NULL;
691c12c399aSSascha Wildner 		cm->cm_length = 0;
692c12c399aSSascha Wildner 	}
693c12c399aSSascha Wildner 
694c12c399aSSascha Wildner 	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE;
695c12c399aSSascha Wildner 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
696c12c399aSSascha Wildner 
69743f7c553SMatthew Dillon 	err = mps_user_setup_request(cm, cmd);
69843f7c553SMatthew Dillon 	if (err != 0) {
69943f7c553SMatthew Dillon 		mps_printf(sc, "mps_user_command: unsupported function 0x%X\n",
70043f7c553SMatthew Dillon 			   hdr->Function );
70143f7c553SMatthew Dillon 		goto RetFreeUnlocked;
70243f7c553SMatthew Dillon 	}
70343f7c553SMatthew Dillon 
704c12c399aSSascha Wildner 	mps_lock(sc);
70543f7c553SMatthew Dillon 	err = mps_wait_command(sc, cm, 60);
706c12c399aSSascha Wildner 
707c12c399aSSascha Wildner 	if (err) {
708c12c399aSSascha Wildner 		mps_printf(sc, "%s: invalid request: error %d\n",
709c12c399aSSascha Wildner 		    __func__, err);
710c12c399aSSascha Wildner 		goto Ret;
711c12c399aSSascha Wildner 	}
712c12c399aSSascha Wildner 
713c12c399aSSascha Wildner 	rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply;
71443f7c553SMatthew Dillon 	if (rpl != NULL)
715c12c399aSSascha Wildner 		sz = rpl->MsgLength * 4;
71643f7c553SMatthew Dillon 	else
71743f7c553SMatthew Dillon 		sz = 0;
718c12c399aSSascha Wildner 
719c12c399aSSascha Wildner 	if (sz > cmd->rpl_len) {
720c12c399aSSascha Wildner 		mps_printf(sc,
721c12c399aSSascha Wildner 		    "mps_user_command: reply buffer too small %d required %d\n",
722c12c399aSSascha Wildner 		    cmd->rpl_len, sz );
723c12c399aSSascha Wildner 		err = EINVAL;
724c12c399aSSascha Wildner 		sz = cmd->rpl_len;
725c12c399aSSascha Wildner 	}
726c12c399aSSascha Wildner 
727c12c399aSSascha Wildner 	mps_unlock(sc);
728c12c399aSSascha Wildner 	copyout(rpl, cmd->rpl, sz);
729c12c399aSSascha Wildner 	if (buf != NULL)
730c12c399aSSascha Wildner 		copyout(buf, cmd->buf, cmd->len);
731c12c399aSSascha Wildner 	mps_dprint(sc, MPS_INFO, "mps_user_command: reply size %d\n", sz );
732c12c399aSSascha Wildner 
733c12c399aSSascha Wildner RetFreeUnlocked:
734c12c399aSSascha Wildner 	mps_lock(sc);
735c12c399aSSascha Wildner 	if (cm != NULL)
736c12c399aSSascha Wildner 		mps_free_command(sc, cm);
737c12c399aSSascha Wildner Ret:
738c12c399aSSascha Wildner 	mps_unlock(sc);
739c12c399aSSascha Wildner 	if (buf != NULL)
740c12c399aSSascha Wildner 		kfree(buf, M_MPSUSER);
741c12c399aSSascha Wildner 	return (err);
742c12c399aSSascha Wildner }
743c12c399aSSascha Wildner 
744c12c399aSSascha Wildner static int
mps_user_pass_thru(struct mps_softc * sc,mps_pass_thru_t * data)745c12c399aSSascha Wildner mps_user_pass_thru(struct mps_softc *sc, mps_pass_thru_t *data)
746c12c399aSSascha Wildner {
747c12c399aSSascha Wildner 	MPI2_REQUEST_HEADER	*hdr, tmphdr;
748c12c399aSSascha Wildner 	MPI2_DEFAULT_REPLY	*rpl;
749c12c399aSSascha Wildner 	struct mps_command	*cm = NULL;
750c12c399aSSascha Wildner 	int			err = 0, dir = 0, sz;
751c12c399aSSascha Wildner 	uint8_t			function = 0;
752c12c399aSSascha Wildner 	u_int			sense_len;
753c12c399aSSascha Wildner 
754c12c399aSSascha Wildner 	/*
755c12c399aSSascha Wildner 	 * Only allow one passthru command at a time.  Use the MPS_FLAGS_BUSY
756c12c399aSSascha Wildner 	 * bit to denote that a passthru is being processed.
757c12c399aSSascha Wildner 	 */
758c12c399aSSascha Wildner 	mps_lock(sc);
759c12c399aSSascha Wildner 	if (sc->mps_flags & MPS_FLAGS_BUSY) {
760c12c399aSSascha Wildner 		mps_dprint(sc, MPS_INFO, "%s: Only one passthru command "
761c12c399aSSascha Wildner 		    "allowed at a single time.", __func__);
762c12c399aSSascha Wildner 		mps_unlock(sc);
763c12c399aSSascha Wildner 		return (EBUSY);
764c12c399aSSascha Wildner 	}
765c12c399aSSascha Wildner 	sc->mps_flags |= MPS_FLAGS_BUSY;
766c12c399aSSascha Wildner 	mps_unlock(sc);
767c12c399aSSascha Wildner 
768c12c399aSSascha Wildner 	/*
769c12c399aSSascha Wildner 	 * Do some validation on data direction.  Valid cases are:
770c12c399aSSascha Wildner 	 *    1) DataSize is 0 and direction is NONE
771c12c399aSSascha Wildner 	 *    2) DataSize is non-zero and one of:
772c12c399aSSascha Wildner 	 *        a) direction is READ or
773c12c399aSSascha Wildner 	 *        b) direction is WRITE or
774c12c399aSSascha Wildner 	 *        c) direction is BOTH and DataOutSize is non-zero
775c12c399aSSascha Wildner 	 * If valid and the direction is BOTH, change the direction to READ.
776c12c399aSSascha Wildner 	 * if valid and the direction is not BOTH, make sure DataOutSize is 0.
777c12c399aSSascha Wildner 	 */
778c12c399aSSascha Wildner 	if (((data->DataSize == 0) &&
779c12c399aSSascha Wildner 	    (data->DataDirection == MPS_PASS_THRU_DIRECTION_NONE)) ||
780c12c399aSSascha Wildner 	    ((data->DataSize != 0) &&
781c12c399aSSascha Wildner 	    ((data->DataDirection == MPS_PASS_THRU_DIRECTION_READ) ||
782c12c399aSSascha Wildner 	    (data->DataDirection == MPS_PASS_THRU_DIRECTION_WRITE) ||
783c12c399aSSascha Wildner 	    ((data->DataDirection == MPS_PASS_THRU_DIRECTION_BOTH) &&
784c12c399aSSascha Wildner 	    (data->DataOutSize != 0))))) {
785c12c399aSSascha Wildner 		if (data->DataDirection == MPS_PASS_THRU_DIRECTION_BOTH)
786c12c399aSSascha Wildner 			data->DataDirection = MPS_PASS_THRU_DIRECTION_READ;
787c12c399aSSascha Wildner 		else
788c12c399aSSascha Wildner 			data->DataOutSize = 0;
789c12c399aSSascha Wildner 	} else
790c12c399aSSascha Wildner 		return (EINVAL);
791c12c399aSSascha Wildner 
792c12c399aSSascha Wildner 	mps_dprint(sc, MPS_INFO, "%s: req 0x%jx %d  rpl 0x%jx %d "
793c12c399aSSascha Wildner 	    "data in 0x%jx %d data out 0x%jx %d data dir %d\n", __func__,
794c12c399aSSascha Wildner 	    data->PtrRequest, data->RequestSize, data->PtrReply,
795c12c399aSSascha Wildner 	    data->ReplySize, data->PtrData, data->DataSize,
796c12c399aSSascha Wildner 	    data->PtrDataOut, data->DataOutSize, data->DataDirection);
797c12c399aSSascha Wildner 
798c12c399aSSascha Wildner 	/*
799c12c399aSSascha Wildner 	 * copy in the header so we know what we're dealing with before we
800c12c399aSSascha Wildner 	 * commit to allocating a command for it.
801c12c399aSSascha Wildner 	 */
802c12c399aSSascha Wildner 	err = copyin(PTRIN(data->PtrRequest), &tmphdr, data->RequestSize);
803c12c399aSSascha Wildner 	if (err != 0)
804c12c399aSSascha Wildner 		goto RetFreeUnlocked;
805c12c399aSSascha Wildner 
806c12c399aSSascha Wildner 	if (data->RequestSize > (int)sc->facts->IOCRequestFrameSize * 4) {
807c12c399aSSascha Wildner 		err = EINVAL;
808c12c399aSSascha Wildner 		goto RetFreeUnlocked;
809c12c399aSSascha Wildner 	}
810c12c399aSSascha Wildner 
811c12c399aSSascha Wildner 	function = tmphdr.Function;
812c12c399aSSascha Wildner 	mps_dprint(sc, MPS_INFO, "%s: Function %02X MsgFlags %02X\n", __func__,
813c12c399aSSascha Wildner 	    function, tmphdr.MsgFlags);
814c12c399aSSascha Wildner 
815c12c399aSSascha Wildner 	/*
816c12c399aSSascha Wildner 	 * Handle a passthru TM request.
817c12c399aSSascha Wildner 	 */
818c12c399aSSascha Wildner 	if (function == MPI2_FUNCTION_SCSI_TASK_MGMT) {
819c12c399aSSascha Wildner 		MPI2_SCSI_TASK_MANAGE_REQUEST	*task;
820c12c399aSSascha Wildner 
821c12c399aSSascha Wildner 		mps_lock(sc);
822c12c399aSSascha Wildner 		cm = mpssas_alloc_tm(sc);
823c12c399aSSascha Wildner 		if (cm == NULL) {
824c12c399aSSascha Wildner 			err = EINVAL;
825c12c399aSSascha Wildner 			goto Ret;
826c12c399aSSascha Wildner 		}
827c12c399aSSascha Wildner 
828c12c399aSSascha Wildner 		/* Copy the header in.  Only a small fixup is needed. */
829c12c399aSSascha Wildner 		task = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req;
830c12c399aSSascha Wildner 		bcopy(&tmphdr, task, data->RequestSize);
831c12c399aSSascha Wildner 		task->TaskMID = cm->cm_desc.Default.SMID;
832c12c399aSSascha Wildner 
833c12c399aSSascha Wildner 		cm->cm_data = NULL;
834c12c399aSSascha Wildner 		cm->cm_desc.HighPriority.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
835c12c399aSSascha Wildner 		cm->cm_complete = NULL;
836c12c399aSSascha Wildner 		cm->cm_complete_data = NULL;
837c12c399aSSascha Wildner 
83843f7c553SMatthew Dillon 		err = mps_wait_command(sc, cm, 30);
839c12c399aSSascha Wildner 
840c12c399aSSascha Wildner 		if (err != 0) {
841c12c399aSSascha Wildner 			err = EIO;
842c12c399aSSascha Wildner 			mps_dprint(sc, MPS_FAULT, "%s: task management failed",
843c12c399aSSascha Wildner 			    __func__);
844c12c399aSSascha Wildner 		}
845c12c399aSSascha Wildner 		/*
846c12c399aSSascha Wildner 		 * Copy the reply data and sense data to user space.
847c12c399aSSascha Wildner 		 */
848c12c399aSSascha Wildner 		if (cm->cm_reply != NULL) {
849c12c399aSSascha Wildner 			rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply;
850c12c399aSSascha Wildner 			sz = rpl->MsgLength * 4;
851c12c399aSSascha Wildner 
852c12c399aSSascha Wildner 			if (sz > data->ReplySize) {
853c12c399aSSascha Wildner 				mps_printf(sc, "%s: reply buffer too small: %d, "
854c12c399aSSascha Wildner 				    "required: %d\n", __func__, data->ReplySize, sz);
855c12c399aSSascha Wildner 				err = EINVAL;
856c12c399aSSascha Wildner 			} else {
857c12c399aSSascha Wildner 				mps_unlock(sc);
858c12c399aSSascha Wildner 				copyout(cm->cm_reply, PTRIN(data->PtrReply),
859c12c399aSSascha Wildner 				    data->ReplySize);
860c12c399aSSascha Wildner 				mps_lock(sc);
861c12c399aSSascha Wildner 			}
862c12c399aSSascha Wildner 		}
863c12c399aSSascha Wildner 		mpssas_free_tm(sc, cm);
864c12c399aSSascha Wildner 		goto Ret;
865c12c399aSSascha Wildner 	}
866c12c399aSSascha Wildner 
867c12c399aSSascha Wildner 	mps_lock(sc);
868c12c399aSSascha Wildner 	cm = mps_alloc_command(sc);
869c12c399aSSascha Wildner 
870c12c399aSSascha Wildner 	if (cm == NULL) {
871c12c399aSSascha Wildner 		mps_printf(sc, "%s: no mps requests\n", __func__);
872c12c399aSSascha Wildner 		err = ENOMEM;
873c12c399aSSascha Wildner 		goto Ret;
874c12c399aSSascha Wildner 	}
875c12c399aSSascha Wildner 	mps_unlock(sc);
876c12c399aSSascha Wildner 
877c12c399aSSascha Wildner 	hdr = (MPI2_REQUEST_HEADER *)cm->cm_req;
878c12c399aSSascha Wildner 	bcopy(&tmphdr, hdr, data->RequestSize);
879c12c399aSSascha Wildner 
880c12c399aSSascha Wildner 	/*
881c12c399aSSascha Wildner 	 * Do some checking to make sure the IOCTL request contains a valid
882c12c399aSSascha Wildner 	 * request.  Then set the SGL info.
883c12c399aSSascha Wildner 	 */
884c12c399aSSascha Wildner 	mpi_init_sge(cm, hdr, (void *)((uint8_t *)hdr + data->RequestSize));
885c12c399aSSascha Wildner 
886c12c399aSSascha Wildner 	/*
887c12c399aSSascha Wildner 	 * Set up for read, write or both.  From check above, DataOutSize will
888c12c399aSSascha Wildner 	 * be 0 if direction is READ or WRITE, but it will have some non-zero
889c12c399aSSascha Wildner 	 * value if the direction is BOTH.  So, just use the biggest size to get
890c12c399aSSascha Wildner 	 * the cm_data buffer size.  If direction is BOTH, 2 SGLs need to be set
891c12c399aSSascha Wildner 	 * up; the first is for the request and the second will contain the
892c12c399aSSascha Wildner 	 * response data. cm_out_len needs to be set here and this will be used
893c12c399aSSascha Wildner 	 * when the SGLs are set up.
894c12c399aSSascha Wildner 	 */
895c12c399aSSascha Wildner 	cm->cm_data = NULL;
896c12c399aSSascha Wildner 	cm->cm_length = MAX(data->DataSize, data->DataOutSize);
897c12c399aSSascha Wildner 	cm->cm_out_len = data->DataOutSize;
898c12c399aSSascha Wildner 	cm->cm_flags = 0;
899c12c399aSSascha Wildner 	if (cm->cm_length != 0) {
900c12c399aSSascha Wildner 		cm->cm_data = kmalloc(cm->cm_length, M_MPSUSER, M_WAITOK |
901c12c399aSSascha Wildner 		    M_ZERO);
902c12c399aSSascha Wildner 		if (cm->cm_data == NULL) {
903c12c399aSSascha Wildner 			mps_dprint(sc, MPS_FAULT, "%s: alloc failed for IOCTL "
904c12c399aSSascha Wildner 			    "passthru length %d\n", __func__, cm->cm_length);
905c12c399aSSascha Wildner 		} else {
906c12c399aSSascha Wildner 			cm->cm_flags = MPS_CM_FLAGS_DATAIN;
907c12c399aSSascha Wildner 			if (data->DataOutSize) {
908c12c399aSSascha Wildner 				cm->cm_flags |= MPS_CM_FLAGS_DATAOUT;
909c12c399aSSascha Wildner 				err = copyin(PTRIN(data->PtrDataOut),
910c12c399aSSascha Wildner 				    cm->cm_data, data->DataOutSize);
911c12c399aSSascha Wildner 			} else if (data->DataDirection ==
912c12c399aSSascha Wildner 			    MPS_PASS_THRU_DIRECTION_WRITE) {
913c12c399aSSascha Wildner 				cm->cm_flags = MPS_CM_FLAGS_DATAOUT;
914c12c399aSSascha Wildner 				err = copyin(PTRIN(data->PtrData),
915c12c399aSSascha Wildner 				    cm->cm_data, data->DataSize);
916c12c399aSSascha Wildner 			}
917c12c399aSSascha Wildner 			if (err != 0)
918c12c399aSSascha Wildner 				mps_dprint(sc, MPS_FAULT, "%s: failed to copy "
919c12c399aSSascha Wildner 				    "IOCTL data from user space\n", __func__);
920c12c399aSSascha Wildner 		}
921c12c399aSSascha Wildner 	}
922c12c399aSSascha Wildner 	cm->cm_flags |= MPS_CM_FLAGS_SGE_SIMPLE;
923c12c399aSSascha Wildner 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
924c12c399aSSascha Wildner 
925c12c399aSSascha Wildner 	/*
926c12c399aSSascha Wildner 	 * Set up Sense buffer and SGL offset for IO passthru.  SCSI IO request
927c12c399aSSascha Wildner 	 * uses SCSI IO descriptor.
928c12c399aSSascha Wildner 	 */
929c12c399aSSascha Wildner 	if ((function == MPI2_FUNCTION_SCSI_IO_REQUEST) ||
930c12c399aSSascha Wildner 	    (function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
931c12c399aSSascha Wildner 		MPI2_SCSI_IO_REQUEST	*scsi_io_req;
932c12c399aSSascha Wildner 
933c12c399aSSascha Wildner 		scsi_io_req = (MPI2_SCSI_IO_REQUEST *)hdr;
934c12c399aSSascha Wildner 		/*
935c12c399aSSascha Wildner 		 * Put SGE for data and data_out buffer at the end of
936c12c399aSSascha Wildner 		 * scsi_io_request message header (64 bytes in total).
937c12c399aSSascha Wildner 		 * Following above SGEs, the residual space will be used by
938c12c399aSSascha Wildner 		 * sense data.
939c12c399aSSascha Wildner 		 */
940c12c399aSSascha Wildner 		scsi_io_req->SenseBufferLength = (uint8_t)(data->RequestSize -
941c12c399aSSascha Wildner 		    64);
942c12c399aSSascha Wildner 		scsi_io_req->SenseBufferLowAddress = cm->cm_sense_busaddr;
943c12c399aSSascha Wildner 
944c12c399aSSascha Wildner 		/*
945c12c399aSSascha Wildner 		 * Set SGLOffset0 value.  This is the number of dwords that SGL
946c12c399aSSascha Wildner 		 * is offset from the beginning of MPI2_SCSI_IO_REQUEST struct.
947c12c399aSSascha Wildner 		 */
948c12c399aSSascha Wildner 		scsi_io_req->SGLOffset0 = 24;
949c12c399aSSascha Wildner 
950c12c399aSSascha Wildner 		/*
951c12c399aSSascha Wildner 		 * Setup descriptor info.  RAID passthrough must use the
952c12c399aSSascha Wildner 		 * default request descriptor which is already set, so if this
953c12c399aSSascha Wildner 		 * is a SCSI IO request, change the descriptor to SCSI IO.
954c12c399aSSascha Wildner 		 * Also, if this is a SCSI IO request, handle the reply in the
955c12c399aSSascha Wildner 		 * mpssas_scsio_complete function.
956c12c399aSSascha Wildner 		 */
957c12c399aSSascha Wildner 		if (function == MPI2_FUNCTION_SCSI_IO_REQUEST) {
958c12c399aSSascha Wildner 			cm->cm_desc.SCSIIO.RequestFlags =
959c12c399aSSascha Wildner 			    MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
960c12c399aSSascha Wildner 			cm->cm_desc.SCSIIO.DevHandle = scsi_io_req->DevHandle;
961c12c399aSSascha Wildner 
962c12c399aSSascha Wildner 			/*
963c12c399aSSascha Wildner 			 * Make sure the DevHandle is not 0 because this is a
964c12c399aSSascha Wildner 			 * likely error.
965c12c399aSSascha Wildner 			 */
966c12c399aSSascha Wildner 			if (scsi_io_req->DevHandle == 0) {
967c12c399aSSascha Wildner 				err = EINVAL;
968c12c399aSSascha Wildner 				goto RetFreeUnlocked;
969c12c399aSSascha Wildner 			}
970c12c399aSSascha Wildner 		}
971c12c399aSSascha Wildner 	}
972c12c399aSSascha Wildner 
973c12c399aSSascha Wildner 	mps_lock(sc);
974c12c399aSSascha Wildner 
97543f7c553SMatthew Dillon 	err = mps_wait_command(sc, cm, 30);
976c12c399aSSascha Wildner 
977c12c399aSSascha Wildner 	if (err) {
978c12c399aSSascha Wildner 		mps_printf(sc, "%s: invalid request: error %d\n", __func__,
979c12c399aSSascha Wildner 		    err);
980c12c399aSSascha Wildner 		mps_unlock(sc);
981c12c399aSSascha Wildner 		goto RetFreeUnlocked;
982c12c399aSSascha Wildner 	}
983c12c399aSSascha Wildner 
984c12c399aSSascha Wildner 	/*
985c12c399aSSascha Wildner 	 * Sync the DMA data, if any.  Then copy the data to user space.
986c12c399aSSascha Wildner 	 */
987c12c399aSSascha Wildner 	if (cm->cm_data != NULL) {
988c12c399aSSascha Wildner 		if (cm->cm_flags & MPS_CM_FLAGS_DATAIN)
989c12c399aSSascha Wildner 			dir = BUS_DMASYNC_POSTREAD;
990c12c399aSSascha Wildner 		else if (cm->cm_flags & MPS_CM_FLAGS_DATAOUT)
9913598cc14SSascha Wildner 			dir = BUS_DMASYNC_POSTWRITE;
992c12c399aSSascha Wildner 		bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir);
993c12c399aSSascha Wildner 		bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap);
994c12c399aSSascha Wildner 
995c12c399aSSascha Wildner 		if (cm->cm_flags & MPS_CM_FLAGS_DATAIN) {
996c12c399aSSascha Wildner 			mps_unlock(sc);
997c12c399aSSascha Wildner 			err = copyout(cm->cm_data,
998c12c399aSSascha Wildner 			    PTRIN(data->PtrData), data->DataSize);
999c12c399aSSascha Wildner 			mps_lock(sc);
1000c12c399aSSascha Wildner 			if (err != 0)
1001c12c399aSSascha Wildner 				mps_dprint(sc, MPS_FAULT, "%s: failed to copy "
1002c12c399aSSascha Wildner 				    "IOCTL data to user space\n", __func__);
1003c12c399aSSascha Wildner 		}
1004c12c399aSSascha Wildner 	}
1005c12c399aSSascha Wildner 
1006c12c399aSSascha Wildner 	/*
1007c12c399aSSascha Wildner 	 * Copy the reply data and sense data to user space.
1008c12c399aSSascha Wildner 	 */
1009c12c399aSSascha Wildner 	if (cm->cm_reply != NULL) {
1010c12c399aSSascha Wildner 		rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply;
1011c12c399aSSascha Wildner 		sz = rpl->MsgLength * 4;
1012c12c399aSSascha Wildner 
1013c12c399aSSascha Wildner 		if (sz > data->ReplySize) {
1014c12c399aSSascha Wildner 			mps_printf(sc, "%s: reply buffer too small: %d, "
1015c12c399aSSascha Wildner 			    "required: %d\n", __func__, data->ReplySize, sz);
1016c12c399aSSascha Wildner 			err = EINVAL;
1017c12c399aSSascha Wildner 		} else {
1018c12c399aSSascha Wildner 			mps_unlock(sc);
1019c12c399aSSascha Wildner 			copyout(cm->cm_reply, PTRIN(data->PtrReply),
1020c12c399aSSascha Wildner 			    data->ReplySize);
1021c12c399aSSascha Wildner 			mps_lock(sc);
1022c12c399aSSascha Wildner 		}
1023c12c399aSSascha Wildner 
1024c12c399aSSascha Wildner 		if ((function == MPI2_FUNCTION_SCSI_IO_REQUEST) ||
1025c12c399aSSascha Wildner 		    (function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
1026c12c399aSSascha Wildner 			if (((MPI2_SCSI_IO_REPLY *)rpl)->SCSIState &
1027c12c399aSSascha Wildner 			    MPI2_SCSI_STATE_AUTOSENSE_VALID) {
1028c12c399aSSascha Wildner 				sense_len =
1029c12c399aSSascha Wildner 				    MIN(((MPI2_SCSI_IO_REPLY *)rpl)->SenseCount,
1030c12c399aSSascha Wildner 				    sizeof(struct scsi_sense_data));
1031c12c399aSSascha Wildner 				mps_unlock(sc);
1032c12c399aSSascha Wildner 				copyout(cm->cm_sense, cm->cm_req + 64, sense_len);
1033c12c399aSSascha Wildner 				mps_lock(sc);
1034c12c399aSSascha Wildner 			}
1035c12c399aSSascha Wildner 		}
1036c12c399aSSascha Wildner 	}
1037c12c399aSSascha Wildner 	mps_unlock(sc);
1038c12c399aSSascha Wildner 
1039c12c399aSSascha Wildner RetFreeUnlocked:
1040c12c399aSSascha Wildner 	mps_lock(sc);
1041c12c399aSSascha Wildner 
1042c12c399aSSascha Wildner 	if (cm != NULL) {
1043c12c399aSSascha Wildner 		if (cm->cm_data)
1044c12c399aSSascha Wildner 			kfree(cm->cm_data, M_MPSUSER);
1045c12c399aSSascha Wildner 		mps_free_command(sc, cm);
1046c12c399aSSascha Wildner 	}
1047c12c399aSSascha Wildner Ret:
1048c12c399aSSascha Wildner 	sc->mps_flags &= ~MPS_FLAGS_BUSY;
1049c12c399aSSascha Wildner 	mps_unlock(sc);
1050c12c399aSSascha Wildner 
1051c12c399aSSascha Wildner 	return (err);
1052c12c399aSSascha Wildner }
1053c12c399aSSascha Wildner 
1054c12c399aSSascha Wildner static void
mps_user_get_adapter_data(struct mps_softc * sc,mps_adapter_data_t * data)1055c12c399aSSascha Wildner mps_user_get_adapter_data(struct mps_softc *sc, mps_adapter_data_t *data)
1056c12c399aSSascha Wildner {
1057c12c399aSSascha Wildner 	Mpi2ConfigReply_t	mpi_reply;
1058c12c399aSSascha Wildner 	Mpi2BiosPage3_t		config_page;
1059c12c399aSSascha Wildner 
1060c12c399aSSascha Wildner 	/*
1061c12c399aSSascha Wildner 	 * Use the PCI interface functions to get the Bus, Device, and Function
1062c12c399aSSascha Wildner 	 * information.
1063c12c399aSSascha Wildner 	 */
1064c12c399aSSascha Wildner 	data->PciInformation.u.bits.BusNumber = pci_get_bus(sc->mps_dev);
1065c12c399aSSascha Wildner 	data->PciInformation.u.bits.DeviceNumber = pci_get_slot(sc->mps_dev);
1066c12c399aSSascha Wildner 	data->PciInformation.u.bits.FunctionNumber =
1067c12c399aSSascha Wildner 	    pci_get_function(sc->mps_dev);
1068c12c399aSSascha Wildner 
1069c12c399aSSascha Wildner 	/*
1070c12c399aSSascha Wildner 	 * Get the FW version that should already be saved in IOC Facts.
1071c12c399aSSascha Wildner 	 */
1072c12c399aSSascha Wildner 	data->MpiFirmwareVersion = sc->facts->FWVersion.Word;
1073c12c399aSSascha Wildner 
1074c12c399aSSascha Wildner 	/*
1075c12c399aSSascha Wildner 	 * General device info.
1076c12c399aSSascha Wildner 	 */
1077c12c399aSSascha Wildner 	data->AdapterType = MPSIOCTL_ADAPTER_TYPE_SAS2;
1078c12c399aSSascha Wildner 	if (sc->mps_flags & MPS_FLAGS_WD_AVAILABLE)
1079c12c399aSSascha Wildner 		data->AdapterType = MPSIOCTL_ADAPTER_TYPE_SAS2_SSS6200;
1080c12c399aSSascha Wildner 	data->PCIDeviceHwId = pci_get_device(sc->mps_dev);
1081c12c399aSSascha Wildner 	data->PCIDeviceHwRev = pci_read_config(sc->mps_dev, PCIR_REVID, 1);
1082c12c399aSSascha Wildner 	data->SubSystemId = pci_get_subdevice(sc->mps_dev);
1083c12c399aSSascha Wildner 	data->SubsystemVendorId = pci_get_subvendor(sc->mps_dev);
1084c12c399aSSascha Wildner 
1085c12c399aSSascha Wildner 	/*
1086c12c399aSSascha Wildner 	 * Get the driver version.
1087c12c399aSSascha Wildner 	 */
1088c12c399aSSascha Wildner 	strcpy((char *)&data->DriverVersion[0], MPS_DRIVER_VERSION);
1089c12c399aSSascha Wildner 
1090c12c399aSSascha Wildner 	/*
1091c12c399aSSascha Wildner 	 * Need to get BIOS Config Page 3 for the BIOS Version.
1092c12c399aSSascha Wildner 	 */
1093c12c399aSSascha Wildner 	data->BiosVersion = 0;
109443f7c553SMatthew Dillon 	mps_lock(sc);
1095c12c399aSSascha Wildner 	if (mps_config_get_bios_pg3(sc, &mpi_reply, &config_page))
1096c12c399aSSascha Wildner 		kprintf("%s: Error while retrieving BIOS Version\n", __func__);
1097c12c399aSSascha Wildner 	else
1098c12c399aSSascha Wildner 		data->BiosVersion = config_page.BiosVersion;
109943f7c553SMatthew Dillon 	mps_unlock(sc);
1100c12c399aSSascha Wildner }
1101c12c399aSSascha Wildner 
1102c12c399aSSascha Wildner static void
mps_user_read_pci_info(struct mps_softc * sc,mps_pci_info_t * data)1103c12c399aSSascha Wildner mps_user_read_pci_info(struct mps_softc *sc, mps_pci_info_t *data)
1104c12c399aSSascha Wildner {
1105c12c399aSSascha Wildner 	int	i;
1106c12c399aSSascha Wildner 
1107c12c399aSSascha Wildner 	/*
1108c12c399aSSascha Wildner 	 * Use the PCI interface functions to get the Bus, Device, and Function
1109c12c399aSSascha Wildner 	 * information.
1110c12c399aSSascha Wildner 	 */
1111c12c399aSSascha Wildner 	data->BusNumber = pci_get_bus(sc->mps_dev);
1112c12c399aSSascha Wildner 	data->DeviceNumber = pci_get_slot(sc->mps_dev);
1113c12c399aSSascha Wildner 	data->FunctionNumber = pci_get_function(sc->mps_dev);
1114c12c399aSSascha Wildner 
1115c12c399aSSascha Wildner 	/*
1116c12c399aSSascha Wildner 	 * Now get the interrupt vector and the pci header.  The vector can
1117c12c399aSSascha Wildner 	 * only be 0 right now.  The header is the first 256 bytes of config
1118c12c399aSSascha Wildner 	 * space.
1119c12c399aSSascha Wildner 	 */
1120c12c399aSSascha Wildner 	data->InterruptVector = 0;
1121c12c399aSSascha Wildner 	for (i = 0; i < sizeof (data->PciHeader); i++) {
1122c12c399aSSascha Wildner 		data->PciHeader[i] = pci_read_config(sc->mps_dev, i, 1);
1123c12c399aSSascha Wildner 	}
1124c12c399aSSascha Wildner }
1125c12c399aSSascha Wildner 
1126c12c399aSSascha Wildner static uint8_t
mps_get_fw_diag_buffer_number(struct mps_softc * sc,uint32_t unique_id)1127c12c399aSSascha Wildner mps_get_fw_diag_buffer_number(struct mps_softc *sc, uint32_t unique_id)
1128c12c399aSSascha Wildner {
1129c12c399aSSascha Wildner 	uint8_t	index;
1130c12c399aSSascha Wildner 
1131c12c399aSSascha Wildner 	for (index = 0; index < MPI2_DIAG_BUF_TYPE_COUNT; index++) {
1132c12c399aSSascha Wildner 		if (sc->fw_diag_buffer_list[index].unique_id == unique_id) {
1133c12c399aSSascha Wildner 			return (index);
1134c12c399aSSascha Wildner 		}
1135c12c399aSSascha Wildner 	}
1136c12c399aSSascha Wildner 
1137c12c399aSSascha Wildner 	return (MPS_FW_DIAGNOSTIC_UID_NOT_FOUND);
1138c12c399aSSascha Wildner }
1139c12c399aSSascha Wildner 
1140c12c399aSSascha Wildner static int
mps_post_fw_diag_buffer(struct mps_softc * sc,mps_fw_diagnostic_buffer_t * pBuffer,uint32_t * return_code)1141c12c399aSSascha Wildner mps_post_fw_diag_buffer(struct mps_softc *sc,
1142c12c399aSSascha Wildner     mps_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code)
1143c12c399aSSascha Wildner {
1144c12c399aSSascha Wildner 	MPI2_DIAG_BUFFER_POST_REQUEST	*req;
1145c12c399aSSascha Wildner 	MPI2_DIAG_BUFFER_POST_REPLY	*reply;
1146c12c399aSSascha Wildner 	struct mps_command		*cm = NULL;
1147c12c399aSSascha Wildner 	int				i, status;
1148c12c399aSSascha Wildner 
1149c12c399aSSascha Wildner 	/*
1150c12c399aSSascha Wildner 	 * If buffer is not enabled, just leave.
1151c12c399aSSascha Wildner 	 */
1152c12c399aSSascha Wildner 	*return_code = MPS_FW_DIAG_ERROR_POST_FAILED;
1153c12c399aSSascha Wildner 	if (!pBuffer->enabled) {
1154c12c399aSSascha Wildner 		return (MPS_DIAG_FAILURE);
1155c12c399aSSascha Wildner 	}
1156c12c399aSSascha Wildner 
1157c12c399aSSascha Wildner 	/*
1158c12c399aSSascha Wildner 	 * Clear some flags initially.
1159c12c399aSSascha Wildner 	 */
1160c12c399aSSascha Wildner 	pBuffer->force_release = FALSE;
1161c12c399aSSascha Wildner 	pBuffer->valid_data = FALSE;
1162c12c399aSSascha Wildner 	pBuffer->owned_by_firmware = FALSE;
1163c12c399aSSascha Wildner 
1164c12c399aSSascha Wildner 	/*
1165c12c399aSSascha Wildner 	 * Get a command.
1166c12c399aSSascha Wildner 	 */
1167c12c399aSSascha Wildner 	cm = mps_alloc_command(sc);
1168c12c399aSSascha Wildner 	if (cm == NULL) {
1169c12c399aSSascha Wildner 		mps_printf(sc, "%s: no mps requests\n", __func__);
1170c12c399aSSascha Wildner 		return (MPS_DIAG_FAILURE);
1171c12c399aSSascha Wildner 	}
1172c12c399aSSascha Wildner 
1173c12c399aSSascha Wildner 	/*
1174c12c399aSSascha Wildner 	 * Build the request for releasing the FW Diag Buffer and send it.
1175c12c399aSSascha Wildner 	 */
1176c12c399aSSascha Wildner 	req = (MPI2_DIAG_BUFFER_POST_REQUEST *)cm->cm_req;
1177c12c399aSSascha Wildner 	req->Function = MPI2_FUNCTION_DIAG_BUFFER_POST;
1178c12c399aSSascha Wildner 	req->BufferType = pBuffer->buffer_type;
1179c12c399aSSascha Wildner 	req->ExtendedType = pBuffer->extended_type;
1180c12c399aSSascha Wildner 	req->BufferLength = pBuffer->size;
1181c12c399aSSascha Wildner 	for (i = 0; i < (sizeof(req->ProductSpecific) / 4); i++)
1182c12c399aSSascha Wildner 		req->ProductSpecific[i] = pBuffer->product_specific[i];
1183c12c399aSSascha Wildner 	mps_from_u64(sc->fw_diag_busaddr, &req->BufferAddress);
1184c12c399aSSascha Wildner 	cm->cm_data = NULL;
1185c12c399aSSascha Wildner 	cm->cm_length = 0;
1186c12c399aSSascha Wildner 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1187c12c399aSSascha Wildner 	cm->cm_complete_data = NULL;
1188c12c399aSSascha Wildner 
1189c12c399aSSascha Wildner 	/*
1190c12c399aSSascha Wildner 	 * Send command synchronously.
1191c12c399aSSascha Wildner 	 */
119243f7c553SMatthew Dillon 	status = mps_wait_command(sc, cm, 30);
1193c12c399aSSascha Wildner 	if (status) {
1194c12c399aSSascha Wildner 		mps_printf(sc, "%s: invalid request: error %d\n", __func__,
1195c12c399aSSascha Wildner 		    status);
1196c12c399aSSascha Wildner 		status = MPS_DIAG_FAILURE;
1197c12c399aSSascha Wildner 		goto done;
1198c12c399aSSascha Wildner 	}
1199c12c399aSSascha Wildner 
1200c12c399aSSascha Wildner 	/*
1201c12c399aSSascha Wildner 	 * Process POST reply.
1202c12c399aSSascha Wildner 	 */
1203c12c399aSSascha Wildner 	reply = (MPI2_DIAG_BUFFER_POST_REPLY *)cm->cm_reply;
1204c12c399aSSascha Wildner 	if (reply->IOCStatus != MPI2_IOCSTATUS_SUCCESS) {
1205c12c399aSSascha Wildner 		status = MPS_DIAG_FAILURE;
1206c12c399aSSascha Wildner 		mps_dprint(sc, MPS_FAULT, "%s: post of FW  Diag Buffer failed "
1207c12c399aSSascha Wildner 		    "with IOCStatus = 0x%x, IOCLogInfo = 0x%x and "
1208c12c399aSSascha Wildner 		    "TransferLength = 0x%x\n", __func__, reply->IOCStatus,
120990ff74f1SSascha Wildner 		    reply->IOCLogInfo, reply->TransferLength);
1210c12c399aSSascha Wildner 		goto done;
1211c12c399aSSascha Wildner 	}
1212c12c399aSSascha Wildner 
1213c12c399aSSascha Wildner 	/*
1214c12c399aSSascha Wildner 	 * Post was successful.
1215c12c399aSSascha Wildner 	 */
1216c12c399aSSascha Wildner 	pBuffer->valid_data = TRUE;
1217c12c399aSSascha Wildner 	pBuffer->owned_by_firmware = TRUE;
1218c12c399aSSascha Wildner 	*return_code = MPS_FW_DIAG_ERROR_SUCCESS;
1219c12c399aSSascha Wildner 	status = MPS_DIAG_SUCCESS;
1220c12c399aSSascha Wildner 
1221c12c399aSSascha Wildner done:
1222c12c399aSSascha Wildner 	mps_free_command(sc, cm);
1223c12c399aSSascha Wildner 	return (status);
1224c12c399aSSascha Wildner }
1225c12c399aSSascha Wildner 
1226c12c399aSSascha Wildner static int
mps_release_fw_diag_buffer(struct mps_softc * sc,mps_fw_diagnostic_buffer_t * pBuffer,uint32_t * return_code,uint32_t diag_type)1227c12c399aSSascha Wildner mps_release_fw_diag_buffer(struct mps_softc *sc,
1228c12c399aSSascha Wildner     mps_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code,
1229c12c399aSSascha Wildner     uint32_t diag_type)
1230c12c399aSSascha Wildner {
1231c12c399aSSascha Wildner 	MPI2_DIAG_RELEASE_REQUEST	*req;
1232c12c399aSSascha Wildner 	MPI2_DIAG_RELEASE_REPLY		*reply;
1233c12c399aSSascha Wildner 	struct mps_command		*cm = NULL;
1234c12c399aSSascha Wildner 	int				status;
1235c12c399aSSascha Wildner 
1236c12c399aSSascha Wildner 	/*
1237c12c399aSSascha Wildner 	 * If buffer is not enabled, just leave.
1238c12c399aSSascha Wildner 	 */
1239c12c399aSSascha Wildner 	*return_code = MPS_FW_DIAG_ERROR_RELEASE_FAILED;
1240c12c399aSSascha Wildner 	if (!pBuffer->enabled) {
1241c12c399aSSascha Wildner 		mps_dprint(sc, MPS_INFO, "%s: This buffer type is not supported "
1242c12c399aSSascha Wildner 		    "by the IOC", __func__);
1243c12c399aSSascha Wildner 		return (MPS_DIAG_FAILURE);
1244c12c399aSSascha Wildner 	}
1245c12c399aSSascha Wildner 
1246c12c399aSSascha Wildner 	/*
1247c12c399aSSascha Wildner 	 * Clear some flags initially.
1248c12c399aSSascha Wildner 	 */
1249c12c399aSSascha Wildner 	pBuffer->force_release = FALSE;
1250c12c399aSSascha Wildner 	pBuffer->valid_data = FALSE;
1251c12c399aSSascha Wildner 	pBuffer->owned_by_firmware = FALSE;
1252c12c399aSSascha Wildner 
1253c12c399aSSascha Wildner 	/*
1254c12c399aSSascha Wildner 	 * Get a command.
1255c12c399aSSascha Wildner 	 */
1256c12c399aSSascha Wildner 	cm = mps_alloc_command(sc);
1257c12c399aSSascha Wildner 	if (cm == NULL) {
1258c12c399aSSascha Wildner 		mps_printf(sc, "%s: no mps requests\n", __func__);
1259c12c399aSSascha Wildner 		return (MPS_DIAG_FAILURE);
1260c12c399aSSascha Wildner 	}
1261c12c399aSSascha Wildner 
1262c12c399aSSascha Wildner 	/*
1263c12c399aSSascha Wildner 	 * Build the request for releasing the FW Diag Buffer and send it.
1264c12c399aSSascha Wildner 	 */
1265c12c399aSSascha Wildner 	req = (MPI2_DIAG_RELEASE_REQUEST *)cm->cm_req;
1266c12c399aSSascha Wildner 	req->Function = MPI2_FUNCTION_DIAG_RELEASE;
1267c12c399aSSascha Wildner 	req->BufferType = pBuffer->buffer_type;
1268c12c399aSSascha Wildner 	cm->cm_data = NULL;
1269c12c399aSSascha Wildner 	cm->cm_length = 0;
1270c12c399aSSascha Wildner 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1271c12c399aSSascha Wildner 	cm->cm_complete_data = NULL;
1272c12c399aSSascha Wildner 
1273c12c399aSSascha Wildner 	/*
1274c12c399aSSascha Wildner 	 * Send command synchronously.
1275c12c399aSSascha Wildner 	 */
127643f7c553SMatthew Dillon 	status = mps_wait_command(sc, cm, 30);
1277c12c399aSSascha Wildner 	if (status) {
1278c12c399aSSascha Wildner 		mps_printf(sc, "%s: invalid request: error %d\n", __func__,
1279c12c399aSSascha Wildner 		    status);
1280c12c399aSSascha Wildner 		status = MPS_DIAG_FAILURE;
1281c12c399aSSascha Wildner 		goto done;
1282c12c399aSSascha Wildner 	}
1283c12c399aSSascha Wildner 
1284c12c399aSSascha Wildner 	/*
1285c12c399aSSascha Wildner 	 * Process RELEASE reply.
1286c12c399aSSascha Wildner 	 */
1287c12c399aSSascha Wildner 	reply = (MPI2_DIAG_RELEASE_REPLY *)cm->cm_reply;
1288c12c399aSSascha Wildner 	if ((reply->IOCStatus != MPI2_IOCSTATUS_SUCCESS) ||
1289c12c399aSSascha Wildner 	    pBuffer->owned_by_firmware) {
1290c12c399aSSascha Wildner 		status = MPS_DIAG_FAILURE;
1291c12c399aSSascha Wildner 		mps_dprint(sc, MPS_FAULT, "%s: release of FW Diag Buffer "
1292c12c399aSSascha Wildner 		    "failed with IOCStatus = 0x%x and IOCLogInfo = 0x%x\n",
129390ff74f1SSascha Wildner 		    __func__, reply->IOCStatus, reply->IOCLogInfo);
1294c12c399aSSascha Wildner 		goto done;
1295c12c399aSSascha Wildner 	}
1296c12c399aSSascha Wildner 
1297c12c399aSSascha Wildner 	/*
1298c12c399aSSascha Wildner 	 * Release was successful.
1299c12c399aSSascha Wildner 	 */
1300c12c399aSSascha Wildner 	*return_code = MPS_FW_DIAG_ERROR_SUCCESS;
1301c12c399aSSascha Wildner 	status = MPS_DIAG_SUCCESS;
1302c12c399aSSascha Wildner 
1303c12c399aSSascha Wildner 	/*
1304c12c399aSSascha Wildner 	 * If this was for an UNREGISTER diag type command, clear the unique ID.
1305c12c399aSSascha Wildner 	 */
1306c12c399aSSascha Wildner 	if (diag_type == MPS_FW_DIAG_TYPE_UNREGISTER) {
1307c12c399aSSascha Wildner 		pBuffer->unique_id = MPS_FW_DIAG_INVALID_UID;
1308c12c399aSSascha Wildner 	}
1309c12c399aSSascha Wildner 
1310c12c399aSSascha Wildner done:
1311c12c399aSSascha Wildner 	return (status);
1312c12c399aSSascha Wildner }
1313c12c399aSSascha Wildner 
1314c12c399aSSascha Wildner static int
mps_diag_register(struct mps_softc * sc,mps_fw_diag_register_t * diag_register,uint32_t * return_code)1315c12c399aSSascha Wildner mps_diag_register(struct mps_softc *sc, mps_fw_diag_register_t *diag_register,
1316c12c399aSSascha Wildner     uint32_t *return_code)
1317c12c399aSSascha Wildner {
1318c12c399aSSascha Wildner 	mps_fw_diagnostic_buffer_t	*pBuffer;
1319c12c399aSSascha Wildner 	uint8_t				extended_type, buffer_type, i;
1320c12c399aSSascha Wildner 	uint32_t			buffer_size;
1321c12c399aSSascha Wildner 	uint32_t			unique_id;
1322c12c399aSSascha Wildner 	int				status;
1323c12c399aSSascha Wildner 
1324c12c399aSSascha Wildner 	extended_type = diag_register->ExtendedType;
1325c12c399aSSascha Wildner 	buffer_type = diag_register->BufferType;
1326c12c399aSSascha Wildner 	buffer_size = diag_register->RequestedBufferSize;
1327c12c399aSSascha Wildner 	unique_id = diag_register->UniqueId;
1328c12c399aSSascha Wildner 
1329c12c399aSSascha Wildner 	/*
1330c12c399aSSascha Wildner 	 * Check for valid buffer type
1331c12c399aSSascha Wildner 	 */
1332c12c399aSSascha Wildner 	if (buffer_type >= MPI2_DIAG_BUF_TYPE_COUNT) {
1333c12c399aSSascha Wildner 		*return_code = MPS_FW_DIAG_ERROR_INVALID_PARAMETER;
1334c12c399aSSascha Wildner 		return (MPS_DIAG_FAILURE);
1335c12c399aSSascha Wildner 	}
1336c12c399aSSascha Wildner 
1337c12c399aSSascha Wildner 	/*
1338c12c399aSSascha Wildner 	 * Get the current buffer and look up the unique ID.  The unique ID
1339c12c399aSSascha Wildner 	 * should not be found.  If it is, the ID is already in use.
1340c12c399aSSascha Wildner 	 */
1341c12c399aSSascha Wildner 	i = mps_get_fw_diag_buffer_number(sc, unique_id);
1342c12c399aSSascha Wildner 	pBuffer = &sc->fw_diag_buffer_list[buffer_type];
1343c12c399aSSascha Wildner 	if (i != MPS_FW_DIAGNOSTIC_UID_NOT_FOUND) {
1344c12c399aSSascha Wildner 		*return_code = MPS_FW_DIAG_ERROR_INVALID_UID;
1345c12c399aSSascha Wildner 		return (MPS_DIAG_FAILURE);
1346c12c399aSSascha Wildner 	}
1347c12c399aSSascha Wildner 
1348c12c399aSSascha Wildner 	/*
1349c12c399aSSascha Wildner 	 * The buffer's unique ID should not be registered yet, and the given
1350c12c399aSSascha Wildner 	 * unique ID cannot be 0.
1351c12c399aSSascha Wildner 	 */
1352c12c399aSSascha Wildner 	if ((pBuffer->unique_id != MPS_FW_DIAG_INVALID_UID) ||
1353c12c399aSSascha Wildner 	    (unique_id == MPS_FW_DIAG_INVALID_UID)) {
1354c12c399aSSascha Wildner 		*return_code = MPS_FW_DIAG_ERROR_INVALID_UID;
1355c12c399aSSascha Wildner 		return (MPS_DIAG_FAILURE);
1356c12c399aSSascha Wildner 	}
1357c12c399aSSascha Wildner 
1358c12c399aSSascha Wildner 	/*
1359c12c399aSSascha Wildner 	 * If this buffer is already posted as immediate, just change owner.
1360c12c399aSSascha Wildner 	 */
1361c12c399aSSascha Wildner 	if (pBuffer->immediate && pBuffer->owned_by_firmware &&
1362c12c399aSSascha Wildner 	    (pBuffer->unique_id == MPS_FW_DIAG_INVALID_UID)) {
1363c12c399aSSascha Wildner 		pBuffer->immediate = FALSE;
1364c12c399aSSascha Wildner 		pBuffer->unique_id = unique_id;
1365c12c399aSSascha Wildner 		return (MPS_DIAG_SUCCESS);
1366c12c399aSSascha Wildner 	}
1367c12c399aSSascha Wildner 
1368c12c399aSSascha Wildner 	/*
1369c12c399aSSascha Wildner 	 * Post a new buffer after checking if it's enabled.  The DMA buffer
1370c12c399aSSascha Wildner 	 * that is allocated will be contiguous (nsegments = 1).
1371c12c399aSSascha Wildner 	 */
1372c12c399aSSascha Wildner 	if (!pBuffer->enabled) {
1373c12c399aSSascha Wildner 		*return_code = MPS_FW_DIAG_ERROR_NO_BUFFER;
1374c12c399aSSascha Wildner 		return (MPS_DIAG_FAILURE);
1375c12c399aSSascha Wildner 	}
1376c12c399aSSascha Wildner         if (bus_dma_tag_create( sc->mps_parent_dmat,    /* parent */
1377c12c399aSSascha Wildner 				1, 0,			/* algnmnt, boundary */
1378c12c399aSSascha Wildner 				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
1379c12c399aSSascha Wildner 				BUS_SPACE_MAXADDR,	/* highaddr */
1380c12c399aSSascha Wildner                                 buffer_size,		/* maxsize */
1381c12c399aSSascha Wildner                                 1,			/* nsegments */
1382c12c399aSSascha Wildner                                 buffer_size,		/* maxsegsize */
1383c12c399aSSascha Wildner                                 0,			/* flags */
1384c12c399aSSascha Wildner                                 &sc->fw_diag_dmat)) {
1385c12c399aSSascha Wildner 		device_printf(sc->mps_dev, "Cannot allocate FW diag buffer DMA "
1386c12c399aSSascha Wildner 		    "tag\n");
1387c12c399aSSascha Wildner 		return (ENOMEM);
1388c12c399aSSascha Wildner         }
1389c12c399aSSascha Wildner         if (bus_dmamem_alloc(sc->fw_diag_dmat, (void **)&sc->fw_diag_buffer,
1390c12c399aSSascha Wildner 	    BUS_DMA_NOWAIT, &sc->fw_diag_map)) {
1391c12c399aSSascha Wildner 		device_printf(sc->mps_dev, "Cannot allocate FW diag buffer "
1392c12c399aSSascha Wildner 		    "memory\n");
1393c12c399aSSascha Wildner 		return (ENOMEM);
1394c12c399aSSascha Wildner         }
1395c12c399aSSascha Wildner         bzero(sc->fw_diag_buffer, buffer_size);
1396c12c399aSSascha Wildner         bus_dmamap_load(sc->fw_diag_dmat, sc->fw_diag_map, sc->fw_diag_buffer,
1397c12c399aSSascha Wildner 	    buffer_size, mps_memaddr_cb, &sc->fw_diag_busaddr, 0);
1398c12c399aSSascha Wildner 	pBuffer->size = buffer_size;
1399c12c399aSSascha Wildner 
1400c12c399aSSascha Wildner 	/*
1401c12c399aSSascha Wildner 	 * Copy the given info to the diag buffer and post the buffer.
1402c12c399aSSascha Wildner 	 */
1403c12c399aSSascha Wildner 	pBuffer->buffer_type = buffer_type;
1404c12c399aSSascha Wildner 	pBuffer->immediate = FALSE;
1405c12c399aSSascha Wildner 	if (buffer_type == MPI2_DIAG_BUF_TYPE_TRACE) {
1406c12c399aSSascha Wildner 		for (i = 0; i < (sizeof (pBuffer->product_specific) / 4);
1407c12c399aSSascha Wildner 		    i++) {
1408c12c399aSSascha Wildner 			pBuffer->product_specific[i] =
1409c12c399aSSascha Wildner 			    diag_register->ProductSpecific[i];
1410c12c399aSSascha Wildner 		}
1411c12c399aSSascha Wildner 	}
1412c12c399aSSascha Wildner 	pBuffer->extended_type = extended_type;
1413c12c399aSSascha Wildner 	pBuffer->unique_id = unique_id;
1414c12c399aSSascha Wildner 	status = mps_post_fw_diag_buffer(sc, pBuffer, return_code);
1415c12c399aSSascha Wildner 
1416c12c399aSSascha Wildner 	/*
1417c12c399aSSascha Wildner 	 * In case there was a failure, free the DMA buffer.
1418c12c399aSSascha Wildner 	 */
1419c12c399aSSascha Wildner 	if (status == MPS_DIAG_FAILURE) {
1420c12c399aSSascha Wildner 		if (sc->fw_diag_busaddr != 0)
1421c12c399aSSascha Wildner 			bus_dmamap_unload(sc->fw_diag_dmat, sc->fw_diag_map);
1422c12c399aSSascha Wildner 		if (sc->fw_diag_buffer != NULL)
1423c12c399aSSascha Wildner 			bus_dmamem_free(sc->fw_diag_dmat, sc->fw_diag_buffer,
1424c12c399aSSascha Wildner 			    sc->fw_diag_map);
1425c12c399aSSascha Wildner 		if (sc->fw_diag_dmat != NULL)
1426c12c399aSSascha Wildner 			bus_dma_tag_destroy(sc->fw_diag_dmat);
1427c12c399aSSascha Wildner 	}
1428c12c399aSSascha Wildner 
1429c12c399aSSascha Wildner 	return (status);
1430c12c399aSSascha Wildner }
1431c12c399aSSascha Wildner 
1432c12c399aSSascha Wildner static int
mps_diag_unregister(struct mps_softc * sc,mps_fw_diag_unregister_t * diag_unregister,uint32_t * return_code)1433c12c399aSSascha Wildner mps_diag_unregister(struct mps_softc *sc,
1434c12c399aSSascha Wildner     mps_fw_diag_unregister_t *diag_unregister, uint32_t *return_code)
1435c12c399aSSascha Wildner {
1436c12c399aSSascha Wildner 	mps_fw_diagnostic_buffer_t	*pBuffer;
1437c12c399aSSascha Wildner 	uint8_t				i;
1438c12c399aSSascha Wildner 	uint32_t			unique_id;
1439c12c399aSSascha Wildner 	int				status;
1440c12c399aSSascha Wildner 
1441c12c399aSSascha Wildner 	unique_id = diag_unregister->UniqueId;
1442c12c399aSSascha Wildner 
1443c12c399aSSascha Wildner 	/*
1444c12c399aSSascha Wildner 	 * Get the current buffer and look up the unique ID.  The unique ID
1445c12c399aSSascha Wildner 	 * should be there.
1446c12c399aSSascha Wildner 	 */
1447c12c399aSSascha Wildner 	i = mps_get_fw_diag_buffer_number(sc, unique_id);
1448c12c399aSSascha Wildner 	if (i == MPS_FW_DIAGNOSTIC_UID_NOT_FOUND) {
1449c12c399aSSascha Wildner 		*return_code = MPS_FW_DIAG_ERROR_INVALID_UID;
1450c12c399aSSascha Wildner 		return (MPS_DIAG_FAILURE);
1451c12c399aSSascha Wildner 	}
1452c12c399aSSascha Wildner 
1453c12c399aSSascha Wildner 	pBuffer = &sc->fw_diag_buffer_list[i];
1454c12c399aSSascha Wildner 
1455c12c399aSSascha Wildner 	/*
1456c12c399aSSascha Wildner 	 * Try to release the buffer from FW before freeing it.  If release
1457c12c399aSSascha Wildner 	 * fails, don't free the DMA buffer in case FW tries to access it
1458c12c399aSSascha Wildner 	 * later.  If buffer is not owned by firmware, can't release it.
1459c12c399aSSascha Wildner 	 */
1460c12c399aSSascha Wildner 	if (!pBuffer->owned_by_firmware) {
1461c12c399aSSascha Wildner 		status = MPS_DIAG_SUCCESS;
1462c12c399aSSascha Wildner 	} else {
1463c12c399aSSascha Wildner 		status = mps_release_fw_diag_buffer(sc, pBuffer, return_code,
1464c12c399aSSascha Wildner 		    MPS_FW_DIAG_TYPE_UNREGISTER);
1465c12c399aSSascha Wildner 	}
1466c12c399aSSascha Wildner 
1467c12c399aSSascha Wildner 	/*
1468c12c399aSSascha Wildner 	 * At this point, return the current status no matter what happens with
1469c12c399aSSascha Wildner 	 * the DMA buffer.
1470c12c399aSSascha Wildner 	 */
1471c12c399aSSascha Wildner 	pBuffer->unique_id = MPS_FW_DIAG_INVALID_UID;
1472c12c399aSSascha Wildner 	if (status == MPS_DIAG_SUCCESS) {
1473c12c399aSSascha Wildner 		if (sc->fw_diag_busaddr != 0)
1474c12c399aSSascha Wildner 			bus_dmamap_unload(sc->fw_diag_dmat, sc->fw_diag_map);
1475c12c399aSSascha Wildner 		if (sc->fw_diag_buffer != NULL)
1476c12c399aSSascha Wildner 			bus_dmamem_free(sc->fw_diag_dmat, sc->fw_diag_buffer,
1477c12c399aSSascha Wildner 			    sc->fw_diag_map);
1478c12c399aSSascha Wildner 		if (sc->fw_diag_dmat != NULL)
1479c12c399aSSascha Wildner 			bus_dma_tag_destroy(sc->fw_diag_dmat);
1480c12c399aSSascha Wildner 	}
1481c12c399aSSascha Wildner 
1482c12c399aSSascha Wildner 	return (status);
1483c12c399aSSascha Wildner }
1484c12c399aSSascha Wildner 
1485c12c399aSSascha Wildner static int
mps_diag_query(struct mps_softc * sc,mps_fw_diag_query_t * diag_query,uint32_t * return_code)1486c12c399aSSascha Wildner mps_diag_query(struct mps_softc *sc, mps_fw_diag_query_t *diag_query,
1487c12c399aSSascha Wildner     uint32_t *return_code)
1488c12c399aSSascha Wildner {
1489c12c399aSSascha Wildner 	mps_fw_diagnostic_buffer_t	*pBuffer;
1490c12c399aSSascha Wildner 	uint8_t				i;
1491c12c399aSSascha Wildner 	uint32_t			unique_id;
1492c12c399aSSascha Wildner 
1493c12c399aSSascha Wildner 	unique_id = diag_query->UniqueId;
1494c12c399aSSascha Wildner 
1495c12c399aSSascha Wildner 	/*
1496c12c399aSSascha Wildner 	 * If ID is valid, query on ID.
1497c12c399aSSascha Wildner 	 * If ID is invalid, query on buffer type.
1498c12c399aSSascha Wildner 	 */
1499c12c399aSSascha Wildner 	if (unique_id == MPS_FW_DIAG_INVALID_UID) {
1500c12c399aSSascha Wildner 		i = diag_query->BufferType;
1501c12c399aSSascha Wildner 		if (i >= MPI2_DIAG_BUF_TYPE_COUNT) {
1502c12c399aSSascha Wildner 			*return_code = MPS_FW_DIAG_ERROR_INVALID_UID;
1503c12c399aSSascha Wildner 			return (MPS_DIAG_FAILURE);
1504c12c399aSSascha Wildner 		}
1505c12c399aSSascha Wildner 	} else {
1506c12c399aSSascha Wildner 		i = mps_get_fw_diag_buffer_number(sc, unique_id);
1507c12c399aSSascha Wildner 		if (i == MPS_FW_DIAGNOSTIC_UID_NOT_FOUND) {
1508c12c399aSSascha Wildner 			*return_code = MPS_FW_DIAG_ERROR_INVALID_UID;
1509c12c399aSSascha Wildner 			return (MPS_DIAG_FAILURE);
1510c12c399aSSascha Wildner 		}
1511c12c399aSSascha Wildner 	}
1512c12c399aSSascha Wildner 
1513c12c399aSSascha Wildner 	/*
1514c12c399aSSascha Wildner 	 * Fill query structure with the diag buffer info.
1515c12c399aSSascha Wildner 	 */
1516c12c399aSSascha Wildner 	pBuffer = &sc->fw_diag_buffer_list[i];
1517c12c399aSSascha Wildner 	diag_query->BufferType = pBuffer->buffer_type;
1518c12c399aSSascha Wildner 	diag_query->ExtendedType = pBuffer->extended_type;
1519c12c399aSSascha Wildner 	if (diag_query->BufferType == MPI2_DIAG_BUF_TYPE_TRACE) {
1520c12c399aSSascha Wildner 		for (i = 0; i < (sizeof(diag_query->ProductSpecific) / 4);
1521c12c399aSSascha Wildner 		    i++) {
1522c12c399aSSascha Wildner 			diag_query->ProductSpecific[i] =
1523c12c399aSSascha Wildner 			    pBuffer->product_specific[i];
1524c12c399aSSascha Wildner 		}
1525c12c399aSSascha Wildner 	}
1526c12c399aSSascha Wildner 	diag_query->TotalBufferSize = pBuffer->size;
1527c12c399aSSascha Wildner 	diag_query->DriverAddedBufferSize = 0;
1528c12c399aSSascha Wildner 	diag_query->UniqueId = pBuffer->unique_id;
1529c12c399aSSascha Wildner 	diag_query->ApplicationFlags = 0;
1530c12c399aSSascha Wildner 	diag_query->DiagnosticFlags = 0;
1531c12c399aSSascha Wildner 
1532c12c399aSSascha Wildner 	/*
1533c12c399aSSascha Wildner 	 * Set/Clear application flags
1534c12c399aSSascha Wildner 	 */
1535c12c399aSSascha Wildner 	if (pBuffer->immediate) {
1536c12c399aSSascha Wildner 		diag_query->ApplicationFlags &= ~MPS_FW_DIAG_FLAG_APP_OWNED;
1537c12c399aSSascha Wildner 	} else {
1538c12c399aSSascha Wildner 		diag_query->ApplicationFlags |= MPS_FW_DIAG_FLAG_APP_OWNED;
1539c12c399aSSascha Wildner 	}
1540c12c399aSSascha Wildner 	if (pBuffer->valid_data || pBuffer->owned_by_firmware) {
1541c12c399aSSascha Wildner 		diag_query->ApplicationFlags |= MPS_FW_DIAG_FLAG_BUFFER_VALID;
1542c12c399aSSascha Wildner 	} else {
1543c12c399aSSascha Wildner 		diag_query->ApplicationFlags &= ~MPS_FW_DIAG_FLAG_BUFFER_VALID;
1544c12c399aSSascha Wildner 	}
1545c12c399aSSascha Wildner 	if (pBuffer->owned_by_firmware) {
1546c12c399aSSascha Wildner 		diag_query->ApplicationFlags |=
1547c12c399aSSascha Wildner 		    MPS_FW_DIAG_FLAG_FW_BUFFER_ACCESS;
1548c12c399aSSascha Wildner 	} else {
1549c12c399aSSascha Wildner 		diag_query->ApplicationFlags &=
1550c12c399aSSascha Wildner 		    ~MPS_FW_DIAG_FLAG_FW_BUFFER_ACCESS;
1551c12c399aSSascha Wildner 	}
1552c12c399aSSascha Wildner 
1553c12c399aSSascha Wildner 	return (MPS_DIAG_SUCCESS);
1554c12c399aSSascha Wildner }
1555c12c399aSSascha Wildner 
1556c12c399aSSascha Wildner static int
mps_diag_read_buffer(struct mps_softc * sc,mps_diag_read_buffer_t * diag_read_buffer,uint8_t * ioctl_buf,uint32_t * return_code)1557c12c399aSSascha Wildner mps_diag_read_buffer(struct mps_softc *sc,
1558c12c399aSSascha Wildner     mps_diag_read_buffer_t *diag_read_buffer, uint8_t *ioctl_buf,
1559c12c399aSSascha Wildner     uint32_t *return_code)
1560c12c399aSSascha Wildner {
1561c12c399aSSascha Wildner 	mps_fw_diagnostic_buffer_t	*pBuffer;
1562c12c399aSSascha Wildner 	uint8_t				i, *pData;
1563c12c399aSSascha Wildner 	uint32_t			unique_id;
1564c12c399aSSascha Wildner 	int				status;
1565c12c399aSSascha Wildner 
1566c12c399aSSascha Wildner 	unique_id = diag_read_buffer->UniqueId;
1567c12c399aSSascha Wildner 
1568c12c399aSSascha Wildner 	/*
1569c12c399aSSascha Wildner 	 * Get the current buffer and look up the unique ID.  The unique ID
1570c12c399aSSascha Wildner 	 * should be there.
1571c12c399aSSascha Wildner 	 */
1572c12c399aSSascha Wildner 	i = mps_get_fw_diag_buffer_number(sc, unique_id);
1573c12c399aSSascha Wildner 	if (i == MPS_FW_DIAGNOSTIC_UID_NOT_FOUND) {
1574c12c399aSSascha Wildner 		*return_code = MPS_FW_DIAG_ERROR_INVALID_UID;
1575c12c399aSSascha Wildner 		return (MPS_DIAG_FAILURE);
1576c12c399aSSascha Wildner 	}
1577c12c399aSSascha Wildner 
1578c12c399aSSascha Wildner 	pBuffer = &sc->fw_diag_buffer_list[i];
1579c12c399aSSascha Wildner 
1580c12c399aSSascha Wildner 	/*
1581c12c399aSSascha Wildner 	 * Make sure requested read is within limits
1582c12c399aSSascha Wildner 	 */
1583c12c399aSSascha Wildner 	if (diag_read_buffer->StartingOffset + diag_read_buffer->BytesToRead >
1584c12c399aSSascha Wildner 	    pBuffer->size) {
1585c12c399aSSascha Wildner 		*return_code = MPS_FW_DIAG_ERROR_INVALID_PARAMETER;
1586c12c399aSSascha Wildner 		return (MPS_DIAG_FAILURE);
1587c12c399aSSascha Wildner 	}
1588c12c399aSSascha Wildner 
1589c12c399aSSascha Wildner 	/*
1590c12c399aSSascha Wildner 	 * Copy the requested data from DMA to the diag_read_buffer.  The DMA
1591c12c399aSSascha Wildner 	 * buffer that was allocated is one contiguous buffer.
1592c12c399aSSascha Wildner 	 */
1593c12c399aSSascha Wildner 	pData = (uint8_t *)(sc->fw_diag_buffer +
1594c12c399aSSascha Wildner 	    diag_read_buffer->StartingOffset);
1595c12c399aSSascha Wildner 	if (copyout(pData, ioctl_buf, diag_read_buffer->BytesToRead) != 0)
1596c12c399aSSascha Wildner 		return (MPS_DIAG_FAILURE);
1597c12c399aSSascha Wildner 	diag_read_buffer->Status = 0;
1598c12c399aSSascha Wildner 
1599c12c399aSSascha Wildner 	/*
1600c12c399aSSascha Wildner 	 * Set or clear the Force Release flag.
1601c12c399aSSascha Wildner 	 */
1602c12c399aSSascha Wildner 	if (pBuffer->force_release) {
1603c12c399aSSascha Wildner 		diag_read_buffer->Flags |= MPS_FW_DIAG_FLAG_FORCE_RELEASE;
1604c12c399aSSascha Wildner 	} else {
1605c12c399aSSascha Wildner 		diag_read_buffer->Flags &= ~MPS_FW_DIAG_FLAG_FORCE_RELEASE;
1606c12c399aSSascha Wildner 	}
1607c12c399aSSascha Wildner 
1608c12c399aSSascha Wildner 	/*
1609c12c399aSSascha Wildner 	 * If buffer is to be reregistered, make sure it's not already owned by
1610c12c399aSSascha Wildner 	 * firmware first.
1611c12c399aSSascha Wildner 	 */
1612c12c399aSSascha Wildner 	status = MPS_DIAG_SUCCESS;
1613c12c399aSSascha Wildner 	if (!pBuffer->owned_by_firmware) {
1614c12c399aSSascha Wildner 		if (diag_read_buffer->Flags & MPS_FW_DIAG_FLAG_REREGISTER) {
1615c12c399aSSascha Wildner 			status = mps_post_fw_diag_buffer(sc, pBuffer,
1616c12c399aSSascha Wildner 			    return_code);
1617c12c399aSSascha Wildner 		}
1618c12c399aSSascha Wildner 	}
1619c12c399aSSascha Wildner 
1620c12c399aSSascha Wildner 	return (status);
1621c12c399aSSascha Wildner }
1622c12c399aSSascha Wildner 
1623c12c399aSSascha Wildner static int
mps_diag_release(struct mps_softc * sc,mps_fw_diag_release_t * diag_release,uint32_t * return_code)1624c12c399aSSascha Wildner mps_diag_release(struct mps_softc *sc, mps_fw_diag_release_t *diag_release,
1625c12c399aSSascha Wildner     uint32_t *return_code)
1626c12c399aSSascha Wildner {
1627c12c399aSSascha Wildner 	mps_fw_diagnostic_buffer_t	*pBuffer;
1628c12c399aSSascha Wildner 	uint8_t				i;
1629c12c399aSSascha Wildner 	uint32_t			unique_id;
1630c12c399aSSascha Wildner 	int				status;
1631c12c399aSSascha Wildner 
1632c12c399aSSascha Wildner 	unique_id = diag_release->UniqueId;
1633c12c399aSSascha Wildner 
1634c12c399aSSascha Wildner 	/*
1635c12c399aSSascha Wildner 	 * Get the current buffer and look up the unique ID.  The unique ID
1636c12c399aSSascha Wildner 	 * should be there.
1637c12c399aSSascha Wildner 	 */
1638c12c399aSSascha Wildner 	i = mps_get_fw_diag_buffer_number(sc, unique_id);
1639c12c399aSSascha Wildner 	if (i == MPS_FW_DIAGNOSTIC_UID_NOT_FOUND) {
1640c12c399aSSascha Wildner 		*return_code = MPS_FW_DIAG_ERROR_INVALID_UID;
1641c12c399aSSascha Wildner 		return (MPS_DIAG_FAILURE);
1642c12c399aSSascha Wildner 	}
1643c12c399aSSascha Wildner 
1644c12c399aSSascha Wildner 	pBuffer = &sc->fw_diag_buffer_list[i];
1645c12c399aSSascha Wildner 
1646c12c399aSSascha Wildner 	/*
1647c12c399aSSascha Wildner 	 * If buffer is not owned by firmware, it's already been released.
1648c12c399aSSascha Wildner 	 */
1649c12c399aSSascha Wildner 	if (!pBuffer->owned_by_firmware) {
1650c12c399aSSascha Wildner 		*return_code = MPS_FW_DIAG_ERROR_ALREADY_RELEASED;
1651c12c399aSSascha Wildner 		return (MPS_DIAG_FAILURE);
1652c12c399aSSascha Wildner 	}
1653c12c399aSSascha Wildner 
1654c12c399aSSascha Wildner 	/*
1655c12c399aSSascha Wildner 	 * Release the buffer.
1656c12c399aSSascha Wildner 	 */
1657c12c399aSSascha Wildner 	status = mps_release_fw_diag_buffer(sc, pBuffer, return_code,
1658c12c399aSSascha Wildner 	    MPS_FW_DIAG_TYPE_RELEASE);
1659c12c399aSSascha Wildner 	return (status);
1660c12c399aSSascha Wildner }
1661c12c399aSSascha Wildner 
1662c12c399aSSascha Wildner static int
mps_do_diag_action(struct mps_softc * sc,uint32_t action,uint8_t * diag_action,uint32_t length,uint32_t * return_code)1663c12c399aSSascha Wildner mps_do_diag_action(struct mps_softc *sc, uint32_t action, uint8_t *diag_action,
1664c12c399aSSascha Wildner     uint32_t length, uint32_t *return_code)
1665c12c399aSSascha Wildner {
1666c12c399aSSascha Wildner 	mps_fw_diag_register_t		diag_register;
1667c12c399aSSascha Wildner 	mps_fw_diag_unregister_t	diag_unregister;
1668c12c399aSSascha Wildner 	mps_fw_diag_query_t		diag_query;
1669c12c399aSSascha Wildner 	mps_diag_read_buffer_t		diag_read_buffer;
1670c12c399aSSascha Wildner 	mps_fw_diag_release_t		diag_release;
1671c12c399aSSascha Wildner 	int				status = MPS_DIAG_SUCCESS;
1672c12c399aSSascha Wildner 	uint32_t			original_return_code;
1673c12c399aSSascha Wildner 
1674c12c399aSSascha Wildner 	original_return_code = *return_code;
1675c12c399aSSascha Wildner 	*return_code = MPS_FW_DIAG_ERROR_SUCCESS;
1676c12c399aSSascha Wildner 
1677c12c399aSSascha Wildner 	switch (action) {
1678c12c399aSSascha Wildner 		case MPS_FW_DIAG_TYPE_REGISTER:
1679c12c399aSSascha Wildner 			if (!length) {
1680c12c399aSSascha Wildner 				*return_code =
1681c12c399aSSascha Wildner 				    MPS_FW_DIAG_ERROR_INVALID_PARAMETER;
1682c12c399aSSascha Wildner 				status = MPS_DIAG_FAILURE;
1683c12c399aSSascha Wildner 				break;
1684c12c399aSSascha Wildner 			}
1685c12c399aSSascha Wildner 			if (copyin(diag_action, &diag_register,
1686c12c399aSSascha Wildner 			    sizeof(diag_register)) != 0)
1687c12c399aSSascha Wildner 				return (MPS_DIAG_FAILURE);
1688c12c399aSSascha Wildner 			status = mps_diag_register(sc, &diag_register,
1689c12c399aSSascha Wildner 			    return_code);
1690c12c399aSSascha Wildner 			break;
1691c12c399aSSascha Wildner 
1692c12c399aSSascha Wildner 		case MPS_FW_DIAG_TYPE_UNREGISTER:
1693c12c399aSSascha Wildner 			if (length < sizeof(diag_unregister)) {
1694c12c399aSSascha Wildner 				*return_code =
1695c12c399aSSascha Wildner 				    MPS_FW_DIAG_ERROR_INVALID_PARAMETER;
1696c12c399aSSascha Wildner 				status = MPS_DIAG_FAILURE;
1697c12c399aSSascha Wildner 				break;
1698c12c399aSSascha Wildner 			}
1699c12c399aSSascha Wildner 			if (copyin(diag_action, &diag_unregister,
1700c12c399aSSascha Wildner 			    sizeof(diag_unregister)) != 0)
1701c12c399aSSascha Wildner 				return (MPS_DIAG_FAILURE);
1702c12c399aSSascha Wildner 			status = mps_diag_unregister(sc, &diag_unregister,
1703c12c399aSSascha Wildner 			    return_code);
1704c12c399aSSascha Wildner 			break;
1705c12c399aSSascha Wildner 
1706c12c399aSSascha Wildner 		case MPS_FW_DIAG_TYPE_QUERY:
1707c12c399aSSascha Wildner 			if (length < sizeof (diag_query)) {
1708c12c399aSSascha Wildner 				*return_code =
1709c12c399aSSascha Wildner 				    MPS_FW_DIAG_ERROR_INVALID_PARAMETER;
1710c12c399aSSascha Wildner 				status = MPS_DIAG_FAILURE;
1711c12c399aSSascha Wildner 				break;
1712c12c399aSSascha Wildner 			}
1713c12c399aSSascha Wildner 			if (copyin(diag_action, &diag_query, sizeof(diag_query))
1714c12c399aSSascha Wildner 			    != 0)
1715c12c399aSSascha Wildner 				return (MPS_DIAG_FAILURE);
1716c12c399aSSascha Wildner 			status = mps_diag_query(sc, &diag_query, return_code);
1717c12c399aSSascha Wildner 			if (status == MPS_DIAG_SUCCESS)
1718c12c399aSSascha Wildner 				if (copyout(&diag_query, diag_action,
1719c12c399aSSascha Wildner 				    sizeof (diag_query)) != 0)
1720c12c399aSSascha Wildner 					return (MPS_DIAG_FAILURE);
1721c12c399aSSascha Wildner 			break;
1722c12c399aSSascha Wildner 
1723c12c399aSSascha Wildner 		case MPS_FW_DIAG_TYPE_READ_BUFFER:
1724c12c399aSSascha Wildner 			if (copyin(diag_action, &diag_read_buffer,
1725c12c399aSSascha Wildner 			    sizeof(diag_read_buffer)) != 0)
1726c12c399aSSascha Wildner 				return (MPS_DIAG_FAILURE);
1727c12c399aSSascha Wildner 			if (length < diag_read_buffer.BytesToRead) {
1728c12c399aSSascha Wildner 				*return_code =
1729c12c399aSSascha Wildner 				    MPS_FW_DIAG_ERROR_INVALID_PARAMETER;
1730c12c399aSSascha Wildner 				status = MPS_DIAG_FAILURE;
1731c12c399aSSascha Wildner 				break;
1732c12c399aSSascha Wildner 			}
1733c12c399aSSascha Wildner 			status = mps_diag_read_buffer(sc, &diag_read_buffer,
1734c12c399aSSascha Wildner 			    PTRIN(diag_read_buffer.PtrDataBuffer),
1735c12c399aSSascha Wildner 			    return_code);
1736c12c399aSSascha Wildner 			if (status == MPS_DIAG_SUCCESS) {
1737c12c399aSSascha Wildner 				if (copyout(&diag_read_buffer, diag_action,
1738c12c399aSSascha Wildner 				    sizeof(diag_read_buffer) -
1739c12c399aSSascha Wildner 				    sizeof(diag_read_buffer.PtrDataBuffer)) !=
1740c12c399aSSascha Wildner 				    0)
1741c12c399aSSascha Wildner 					return (MPS_DIAG_FAILURE);
1742c12c399aSSascha Wildner 			}
1743c12c399aSSascha Wildner 			break;
1744c12c399aSSascha Wildner 
1745c12c399aSSascha Wildner 		case MPS_FW_DIAG_TYPE_RELEASE:
1746c12c399aSSascha Wildner 			if (length < sizeof(diag_release)) {
1747c12c399aSSascha Wildner 				*return_code =
1748c12c399aSSascha Wildner 				    MPS_FW_DIAG_ERROR_INVALID_PARAMETER;
1749c12c399aSSascha Wildner 				status = MPS_DIAG_FAILURE;
1750c12c399aSSascha Wildner 				break;
1751c12c399aSSascha Wildner 			}
1752c12c399aSSascha Wildner 			if (copyin(diag_action, &diag_release,
1753c12c399aSSascha Wildner 			    sizeof(diag_release)) != 0)
1754c12c399aSSascha Wildner 				return (MPS_DIAG_FAILURE);
1755c12c399aSSascha Wildner 			status = mps_diag_release(sc, &diag_release,
1756c12c399aSSascha Wildner 			    return_code);
1757c12c399aSSascha Wildner 			break;
1758c12c399aSSascha Wildner 
1759c12c399aSSascha Wildner 		default:
1760c12c399aSSascha Wildner 			*return_code = MPS_FW_DIAG_ERROR_INVALID_PARAMETER;
1761c12c399aSSascha Wildner 			status = MPS_DIAG_FAILURE;
1762c12c399aSSascha Wildner 			break;
1763c12c399aSSascha Wildner 	}
1764c12c399aSSascha Wildner 
1765c12c399aSSascha Wildner 	if ((status == MPS_DIAG_FAILURE) &&
1766c12c399aSSascha Wildner 	    (original_return_code == MPS_FW_DIAG_NEW) &&
1767c12c399aSSascha Wildner 	    (*return_code != MPS_FW_DIAG_ERROR_SUCCESS))
1768c12c399aSSascha Wildner 		status = MPS_DIAG_SUCCESS;
1769c12c399aSSascha Wildner 
1770c12c399aSSascha Wildner 	return (status);
1771c12c399aSSascha Wildner }
1772c12c399aSSascha Wildner 
1773c12c399aSSascha Wildner static int
mps_user_diag_action(struct mps_softc * sc,mps_diag_action_t * data)1774c12c399aSSascha Wildner mps_user_diag_action(struct mps_softc *sc, mps_diag_action_t *data)
1775c12c399aSSascha Wildner {
1776c12c399aSSascha Wildner 	int			status;
1777c12c399aSSascha Wildner 
1778c12c399aSSascha Wildner 	/*
1779c12c399aSSascha Wildner 	 * Only allow one diag action at one time.
1780c12c399aSSascha Wildner 	 */
1781c12c399aSSascha Wildner 	if (sc->mps_flags & MPS_FLAGS_BUSY) {
1782c12c399aSSascha Wildner 		mps_dprint(sc, MPS_INFO, "%s: Only one FW diag command "
1783c12c399aSSascha Wildner 		    "allowed at a single time.", __func__);
1784c12c399aSSascha Wildner 		return (EBUSY);
1785c12c399aSSascha Wildner 	}
1786c12c399aSSascha Wildner 	sc->mps_flags |= MPS_FLAGS_BUSY;
1787c12c399aSSascha Wildner 
1788c12c399aSSascha Wildner 	/*
1789c12c399aSSascha Wildner 	 * Send diag action request
1790c12c399aSSascha Wildner 	 */
1791c12c399aSSascha Wildner 	if (data->Action == MPS_FW_DIAG_TYPE_REGISTER ||
1792c12c399aSSascha Wildner 	    data->Action == MPS_FW_DIAG_TYPE_UNREGISTER ||
1793c12c399aSSascha Wildner 	    data->Action == MPS_FW_DIAG_TYPE_QUERY ||
1794c12c399aSSascha Wildner 	    data->Action == MPS_FW_DIAG_TYPE_READ_BUFFER ||
1795c12c399aSSascha Wildner 	    data->Action == MPS_FW_DIAG_TYPE_RELEASE) {
1796c12c399aSSascha Wildner 		status = mps_do_diag_action(sc, data->Action,
1797c12c399aSSascha Wildner 		    PTRIN(data->PtrDiagAction), data->Length,
1798c12c399aSSascha Wildner 		    &data->ReturnCode);
1799c12c399aSSascha Wildner 	} else
1800c12c399aSSascha Wildner 		status = EINVAL;
1801c12c399aSSascha Wildner 
1802c12c399aSSascha Wildner 	sc->mps_flags &= ~MPS_FLAGS_BUSY;
1803c12c399aSSascha Wildner 	return (status);
1804c12c399aSSascha Wildner }
1805c12c399aSSascha Wildner 
1806c12c399aSSascha Wildner /*
1807c12c399aSSascha Wildner  * Copy the event recording mask and the event queue size out.  For
1808c12c399aSSascha Wildner  * clarification, the event recording mask (events_to_record) is not the same
1809c12c399aSSascha Wildner  * thing as the event mask (event_mask).  events_to_record has a bit set for
1810c12c399aSSascha Wildner  * every event type that is to be recorded by the driver, and event_mask has a
1811c12c399aSSascha Wildner  * bit cleared for every event that is allowed into the driver from the IOC.
1812c12c399aSSascha Wildner  * They really have nothing to do with each other.
1813c12c399aSSascha Wildner  */
1814c12c399aSSascha Wildner static void
mps_user_event_query(struct mps_softc * sc,mps_event_query_t * data)1815c12c399aSSascha Wildner mps_user_event_query(struct mps_softc *sc, mps_event_query_t *data)
1816c12c399aSSascha Wildner {
1817c12c399aSSascha Wildner 	uint8_t	i;
1818c12c399aSSascha Wildner 
1819c12c399aSSascha Wildner 	mps_lock(sc);
1820c12c399aSSascha Wildner 	data->Entries = MPS_EVENT_QUEUE_SIZE;
1821c12c399aSSascha Wildner 
1822c12c399aSSascha Wildner 	for (i = 0; i < 4; i++) {
1823c12c399aSSascha Wildner 		data->Types[i] = sc->events_to_record[i];
1824c12c399aSSascha Wildner 	}
1825c12c399aSSascha Wildner 	mps_unlock(sc);
1826c12c399aSSascha Wildner }
1827c12c399aSSascha Wildner 
1828c12c399aSSascha Wildner /*
1829c12c399aSSascha Wildner  * Set the driver's event mask according to what's been given.  See
1830c12c399aSSascha Wildner  * mps_user_event_query for explanation of the event recording mask and the IOC
1831c12c399aSSascha Wildner  * event mask.  It's the app's responsibility to enable event logging by setting
1832c12c399aSSascha Wildner  * the bits in events_to_record.  Initially, no events will be logged.
1833c12c399aSSascha Wildner  */
1834c12c399aSSascha Wildner static void
mps_user_event_enable(struct mps_softc * sc,mps_event_enable_t * data)1835c12c399aSSascha Wildner mps_user_event_enable(struct mps_softc *sc, mps_event_enable_t *data)
1836c12c399aSSascha Wildner {
1837c12c399aSSascha Wildner 	uint8_t	i;
1838c12c399aSSascha Wildner 
1839c12c399aSSascha Wildner 	mps_lock(sc);
1840c12c399aSSascha Wildner 	for (i = 0; i < 4; i++) {
1841c12c399aSSascha Wildner 		sc->events_to_record[i] = data->Types[i];
1842c12c399aSSascha Wildner 	}
1843c12c399aSSascha Wildner 	mps_unlock(sc);
1844c12c399aSSascha Wildner }
1845c12c399aSSascha Wildner 
1846c12c399aSSascha Wildner /*
1847c12c399aSSascha Wildner  * Copy out the events that have been recorded, up to the max events allowed.
1848c12c399aSSascha Wildner  */
1849c12c399aSSascha Wildner static int
mps_user_event_report(struct mps_softc * sc,mps_event_report_t * data)1850c12c399aSSascha Wildner mps_user_event_report(struct mps_softc *sc, mps_event_report_t *data)
1851c12c399aSSascha Wildner {
1852c12c399aSSascha Wildner 	int		status = 0;
1853c12c399aSSascha Wildner 	uint32_t	size;
1854c12c399aSSascha Wildner 
1855c12c399aSSascha Wildner 	mps_lock(sc);
1856c12c399aSSascha Wildner 	size = data->Size;
1857c12c399aSSascha Wildner 	if ((size >= sizeof(sc->recorded_events)) && (status == 0)) {
1858c12c399aSSascha Wildner 		mps_unlock(sc);
1859c12c399aSSascha Wildner 		if (copyout((void *)sc->recorded_events,
1860c12c399aSSascha Wildner 		    PTRIN(data->PtrEvents), size) != 0)
1861c12c399aSSascha Wildner 			status = EFAULT;
1862c12c399aSSascha Wildner 		mps_lock(sc);
1863c12c399aSSascha Wildner 	} else {
1864c12c399aSSascha Wildner 		/*
1865c12c399aSSascha Wildner 		 * data->Size value is not large enough to copy event data.
1866c12c399aSSascha Wildner 		 */
1867c12c399aSSascha Wildner 		status = EFAULT;
1868c12c399aSSascha Wildner 	}
1869c12c399aSSascha Wildner 
1870c12c399aSSascha Wildner 	/*
1871c12c399aSSascha Wildner 	 * Change size value to match the number of bytes that were copied.
1872c12c399aSSascha Wildner 	 */
1873c12c399aSSascha Wildner 	if (status == 0)
1874c12c399aSSascha Wildner 		data->Size = sizeof(sc->recorded_events);
1875c12c399aSSascha Wildner 	mps_unlock(sc);
1876c12c399aSSascha Wildner 
1877c12c399aSSascha Wildner 	return (status);
1878c12c399aSSascha Wildner }
1879c12c399aSSascha Wildner 
1880c12c399aSSascha Wildner /*
1881c12c399aSSascha Wildner  * Record events into the driver from the IOC if they are not masked.
1882c12c399aSSascha Wildner  */
1883c12c399aSSascha Wildner void
mpssas_record_event(struct mps_softc * sc,MPI2_EVENT_NOTIFICATION_REPLY * event_reply)1884c12c399aSSascha Wildner mpssas_record_event(struct mps_softc *sc,
1885c12c399aSSascha Wildner     MPI2_EVENT_NOTIFICATION_REPLY *event_reply)
1886c12c399aSSascha Wildner {
1887c12c399aSSascha Wildner 	uint32_t	event;
1888c12c399aSSascha Wildner 	int		i, j;
1889c12c399aSSascha Wildner 	uint16_t	event_data_len;
1890c12c399aSSascha Wildner 	boolean_t	sendAEN = FALSE;
1891c12c399aSSascha Wildner 
1892c12c399aSSascha Wildner 	event = event_reply->Event;
1893c12c399aSSascha Wildner 
1894c12c399aSSascha Wildner 	/*
1895c12c399aSSascha Wildner 	 * Generate a system event to let anyone who cares know that a
1896c12c399aSSascha Wildner 	 * LOG_ENTRY_ADDED event has occurred.  This is sent no matter what the
1897c12c399aSSascha Wildner 	 * event mask is set to.
1898c12c399aSSascha Wildner 	 */
1899c12c399aSSascha Wildner 	if (event == MPI2_EVENT_LOG_ENTRY_ADDED) {
1900c12c399aSSascha Wildner 		sendAEN = TRUE;
1901c12c399aSSascha Wildner 	}
1902c12c399aSSascha Wildner 
1903c12c399aSSascha Wildner 	/*
1904c12c399aSSascha Wildner 	 * Record the event only if its corresponding bit is set in
1905c12c399aSSascha Wildner 	 * events_to_record.  event_index is the index into recorded_events and
1906c12c399aSSascha Wildner 	 * event_number is the overall number of an event being recorded since
1907c12c399aSSascha Wildner 	 * start-of-day.  event_index will roll over; event_number will never
1908c12c399aSSascha Wildner 	 * roll over.
1909c12c399aSSascha Wildner 	 */
1910c12c399aSSascha Wildner 	i = (uint8_t)(event / 32);
1911c12c399aSSascha Wildner 	j = (uint8_t)(event % 32);
1912c12c399aSSascha Wildner 	if ((i < 4) && ((1 << j) & sc->events_to_record[i])) {
1913c12c399aSSascha Wildner 		i = sc->event_index;
1914c12c399aSSascha Wildner 		sc->recorded_events[i].Type = event;
1915c12c399aSSascha Wildner 		sc->recorded_events[i].Number = ++sc->event_number;
1916c12c399aSSascha Wildner 		bzero(sc->recorded_events[i].Data, MPS_MAX_EVENT_DATA_LENGTH *
1917c12c399aSSascha Wildner 		    4);
1918c12c399aSSascha Wildner 		event_data_len = event_reply->EventDataLength;
1919c12c399aSSascha Wildner 
1920c12c399aSSascha Wildner 		if (event_data_len > 0) {
1921c12c399aSSascha Wildner 			/*
1922c12c399aSSascha Wildner 			 * Limit data to size in m_event entry
1923c12c399aSSascha Wildner 			 */
1924c12c399aSSascha Wildner 			if (event_data_len > MPS_MAX_EVENT_DATA_LENGTH) {
1925c12c399aSSascha Wildner 				event_data_len = MPS_MAX_EVENT_DATA_LENGTH;
1926c12c399aSSascha Wildner 			}
1927c12c399aSSascha Wildner 			for (j = 0; j < event_data_len; j++) {
1928c12c399aSSascha Wildner 				sc->recorded_events[i].Data[j] =
1929c12c399aSSascha Wildner 				    event_reply->EventData[j];
1930c12c399aSSascha Wildner 			}
1931c12c399aSSascha Wildner 
1932c12c399aSSascha Wildner 			/*
1933c12c399aSSascha Wildner 			 * check for index wrap-around
1934c12c399aSSascha Wildner 			 */
1935c12c399aSSascha Wildner 			if (++i == MPS_EVENT_QUEUE_SIZE) {
1936c12c399aSSascha Wildner 				i = 0;
1937c12c399aSSascha Wildner 			}
1938c12c399aSSascha Wildner 			sc->event_index = (uint8_t)i;
1939c12c399aSSascha Wildner 
1940c12c399aSSascha Wildner 			/*
1941c12c399aSSascha Wildner 			 * Set flag to send the event.
1942c12c399aSSascha Wildner 			 */
1943c12c399aSSascha Wildner 			sendAEN = TRUE;
1944c12c399aSSascha Wildner 		}
1945c12c399aSSascha Wildner 	}
1946c12c399aSSascha Wildner 
1947c12c399aSSascha Wildner 	/*
1948c12c399aSSascha Wildner 	 * Generate a system event if flag is set to let anyone who cares know
1949c12c399aSSascha Wildner 	 * that an event has occurred.
1950c12c399aSSascha Wildner 	 */
1951c12c399aSSascha Wildner 	if (sendAEN) {
1952c12c399aSSascha Wildner //SLM-how to send a system event (see kqueue, kevent)
1953c12c399aSSascha Wildner //		(void) ddi_log_sysevent(mpt->m_dip, DDI_VENDOR_LSI, "MPT_SAS",
1954c12c399aSSascha Wildner //		    "SAS", NULL, NULL, DDI_NOSLEEP);
1955c12c399aSSascha Wildner 	}
1956c12c399aSSascha Wildner }
1957c12c399aSSascha Wildner 
1958c12c399aSSascha Wildner static int
mps_user_reg_access(struct mps_softc * sc,mps_reg_access_t * data)1959c12c399aSSascha Wildner mps_user_reg_access(struct mps_softc *sc, mps_reg_access_t *data)
1960c12c399aSSascha Wildner {
1961c12c399aSSascha Wildner 	int	status = 0;
1962c12c399aSSascha Wildner 
1963c12c399aSSascha Wildner 	switch (data->Command) {
1964c12c399aSSascha Wildner 		/*
1965c12c399aSSascha Wildner 		 * IO access is not supported.
1966c12c399aSSascha Wildner 		 */
1967c12c399aSSascha Wildner 		case REG_IO_READ:
1968c12c399aSSascha Wildner 		case REG_IO_WRITE:
1969c12c399aSSascha Wildner 			mps_dprint(sc, MPS_INFO, "IO access is not supported. "
1970c12c399aSSascha Wildner 			    "Use memory access.");
1971c12c399aSSascha Wildner 			status = EINVAL;
1972c12c399aSSascha Wildner 			break;
1973c12c399aSSascha Wildner 
1974c12c399aSSascha Wildner 		case REG_MEM_READ:
1975c12c399aSSascha Wildner 			data->RegData = mps_regread(sc, data->RegOffset);
1976c12c399aSSascha Wildner 			break;
1977c12c399aSSascha Wildner 
1978c12c399aSSascha Wildner 		case REG_MEM_WRITE:
1979c12c399aSSascha Wildner 			mps_regwrite(sc, data->RegOffset, data->RegData);
1980c12c399aSSascha Wildner 			break;
1981c12c399aSSascha Wildner 
1982c12c399aSSascha Wildner 		default:
1983c12c399aSSascha Wildner 			status = EINVAL;
1984c12c399aSSascha Wildner 			break;
1985c12c399aSSascha Wildner 	}
1986c12c399aSSascha Wildner 
1987c12c399aSSascha Wildner 	return (status);
1988c12c399aSSascha Wildner }
1989c12c399aSSascha Wildner 
1990c12c399aSSascha Wildner static int
mps_user_btdh(struct mps_softc * sc,mps_btdh_mapping_t * data)1991c12c399aSSascha Wildner mps_user_btdh(struct mps_softc *sc, mps_btdh_mapping_t *data)
1992c12c399aSSascha Wildner {
1993c12c399aSSascha Wildner 	uint8_t		bt2dh = FALSE;
1994c12c399aSSascha Wildner 	uint8_t		dh2bt = FALSE;
1995c12c399aSSascha Wildner 	uint16_t	dev_handle, bus, target;
1996c12c399aSSascha Wildner 
1997c12c399aSSascha Wildner 	bus = data->Bus;
1998c12c399aSSascha Wildner 	target = data->TargetID;
1999c12c399aSSascha Wildner 	dev_handle = data->DevHandle;
2000c12c399aSSascha Wildner 
2001c12c399aSSascha Wildner 	/*
2002c12c399aSSascha Wildner 	 * When DevHandle is 0xFFFF and Bus/Target are not 0xFFFF, use Bus/
2003c12c399aSSascha Wildner 	 * Target to get DevHandle.  When Bus/Target are 0xFFFF and DevHandle is
2004c12c399aSSascha Wildner 	 * not 0xFFFF, use DevHandle to get Bus/Target.  Anything else is
2005c12c399aSSascha Wildner 	 * invalid.
2006c12c399aSSascha Wildner 	 */
2007c12c399aSSascha Wildner 	if ((bus == 0xFFFF) && (target == 0xFFFF) && (dev_handle != 0xFFFF))
2008c12c399aSSascha Wildner 		dh2bt = TRUE;
2009c12c399aSSascha Wildner 	if ((dev_handle == 0xFFFF) && (bus != 0xFFFF) && (target != 0xFFFF))
2010c12c399aSSascha Wildner 		bt2dh = TRUE;
2011c12c399aSSascha Wildner 	if (!dh2bt && !bt2dh)
2012c12c399aSSascha Wildner 		return (EINVAL);
2013c12c399aSSascha Wildner 
2014c12c399aSSascha Wildner 	/*
2015c12c399aSSascha Wildner 	 * Only handle bus of 0.  Make sure target is within range.
2016c12c399aSSascha Wildner 	 */
2017c12c399aSSascha Wildner 	if (bt2dh) {
2018c12c399aSSascha Wildner 		if (bus != 0)
2019c12c399aSSascha Wildner 			return (EINVAL);
2020c12c399aSSascha Wildner 
2021c12c399aSSascha Wildner 		if (target > sc->max_devices) {
2022c12c399aSSascha Wildner 			mps_dprint(sc, MPS_FAULT, "Target ID is out of range "
2023c12c399aSSascha Wildner 			   "for Bus/Target to DevHandle mapping.");
2024c12c399aSSascha Wildner 			return (EINVAL);
2025c12c399aSSascha Wildner 		}
2026c12c399aSSascha Wildner 		dev_handle = sc->mapping_table[target].dev_handle;
2027c12c399aSSascha Wildner 		if (dev_handle)
2028c12c399aSSascha Wildner 			data->DevHandle = dev_handle;
2029c12c399aSSascha Wildner 	} else {
2030c12c399aSSascha Wildner 		bus = 0;
2031c12c399aSSascha Wildner 		target = mps_mapping_get_sas_id_from_handle(sc, dev_handle);
2032c12c399aSSascha Wildner 		data->Bus = bus;
2033c12c399aSSascha Wildner 		data->TargetID = target;
2034c12c399aSSascha Wildner 	}
2035c12c399aSSascha Wildner 
2036c12c399aSSascha Wildner 	return (0);
2037c12c399aSSascha Wildner }
2038c12c399aSSascha Wildner 
2039c12c399aSSascha Wildner static int
mps_ioctl(struct cdev * dev,u_long cmd,void * arg,int flag)2040c12c399aSSascha Wildner mps_ioctl(struct cdev *dev, u_long cmd, void *arg, int flag)
2041c12c399aSSascha Wildner {
2042c12c399aSSascha Wildner 	struct mps_softc *sc;
2043c12c399aSSascha Wildner 	struct mps_cfg_page_req *page_req;
2044c12c399aSSascha Wildner 	struct mps_ext_cfg_page_req *ext_page_req;
2045c12c399aSSascha Wildner 	void *mps_page;
2046c12c399aSSascha Wildner 	int error, reset_loop;
2047c12c399aSSascha Wildner 
2048c12c399aSSascha Wildner 	mps_page = NULL;
2049c12c399aSSascha Wildner 	sc = dev->si_drv1;
2050362298e4SSascha Wildner 	page_req = arg;
2051362298e4SSascha Wildner 	ext_page_req = arg;
2052c12c399aSSascha Wildner 
2053c12c399aSSascha Wildner 	switch (cmd) {
2054c12c399aSSascha Wildner 	case MPSIO_READ_CFG_HEADER:
2055c12c399aSSascha Wildner 		mps_lock(sc);
2056c12c399aSSascha Wildner 		error = mps_user_read_cfg_header(sc, page_req);
2057c12c399aSSascha Wildner 		mps_unlock(sc);
2058c12c399aSSascha Wildner 		break;
2059c12c399aSSascha Wildner 	case MPSIO_READ_CFG_PAGE:
2060c12c399aSSascha Wildner 		mps_page = kmalloc(page_req->len, M_MPSUSER, M_WAITOK | M_ZERO);
2061c12c399aSSascha Wildner 		error = copyin(page_req->buf, mps_page,
2062c12c399aSSascha Wildner 		    sizeof(MPI2_CONFIG_PAGE_HEADER));
2063c12c399aSSascha Wildner 		if (error)
2064c12c399aSSascha Wildner 			break;
2065c12c399aSSascha Wildner 		mps_lock(sc);
2066c12c399aSSascha Wildner 		error = mps_user_read_cfg_page(sc, page_req, mps_page);
2067c12c399aSSascha Wildner 		mps_unlock(sc);
2068c12c399aSSascha Wildner 		if (error)
2069c12c399aSSascha Wildner 			break;
2070c12c399aSSascha Wildner 		error = copyout(mps_page, page_req->buf, page_req->len);
2071c12c399aSSascha Wildner 		break;
2072c12c399aSSascha Wildner 	case MPSIO_READ_EXT_CFG_HEADER:
2073c12c399aSSascha Wildner 		mps_lock(sc);
2074c12c399aSSascha Wildner 		error = mps_user_read_extcfg_header(sc, ext_page_req);
2075c12c399aSSascha Wildner 		mps_unlock(sc);
2076c12c399aSSascha Wildner 		break;
2077c12c399aSSascha Wildner 	case MPSIO_READ_EXT_CFG_PAGE:
2078c12c399aSSascha Wildner 		mps_page = kmalloc(ext_page_req->len, M_MPSUSER, M_WAITOK|M_ZERO);
2079c12c399aSSascha Wildner 		error = copyin(ext_page_req->buf, mps_page,
2080c12c399aSSascha Wildner 		    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
2081c12c399aSSascha Wildner 		if (error)
2082c12c399aSSascha Wildner 			break;
2083c12c399aSSascha Wildner 		mps_lock(sc);
2084c12c399aSSascha Wildner 		error = mps_user_read_extcfg_page(sc, ext_page_req, mps_page);
2085c12c399aSSascha Wildner 		mps_unlock(sc);
2086c12c399aSSascha Wildner 		if (error)
2087c12c399aSSascha Wildner 			break;
2088c12c399aSSascha Wildner 		error = copyout(mps_page, ext_page_req->buf, ext_page_req->len);
2089c12c399aSSascha Wildner 		break;
2090c12c399aSSascha Wildner 	case MPSIO_WRITE_CFG_PAGE:
2091c12c399aSSascha Wildner 		mps_page = kmalloc(page_req->len, M_MPSUSER, M_WAITOK|M_ZERO);
2092c12c399aSSascha Wildner 		error = copyin(page_req->buf, mps_page, page_req->len);
2093c12c399aSSascha Wildner 		if (error)
2094c12c399aSSascha Wildner 			break;
2095c12c399aSSascha Wildner 		mps_lock(sc);
2096c12c399aSSascha Wildner 		error = mps_user_write_cfg_page(sc, page_req, mps_page);
2097c12c399aSSascha Wildner 		mps_unlock(sc);
2098c12c399aSSascha Wildner 		break;
2099c12c399aSSascha Wildner 	case MPSIO_MPS_COMMAND:
2100c12c399aSSascha Wildner 		error = mps_user_command(sc, (struct mps_usr_command *)arg);
2101c12c399aSSascha Wildner 		break;
2102c12c399aSSascha Wildner 	case MPTIOCTL_PASS_THRU:
2103c12c399aSSascha Wildner 		/*
2104c12c399aSSascha Wildner 		 * The user has requested to pass through a command to be
2105c12c399aSSascha Wildner 		 * executed by the MPT firmware.  Call our routine which does
2106c12c399aSSascha Wildner 		 * this.  Only allow one passthru IOCTL at one time.
2107c12c399aSSascha Wildner 		 */
2108c12c399aSSascha Wildner 		error = mps_user_pass_thru(sc, (mps_pass_thru_t *)arg);
2109c12c399aSSascha Wildner 		break;
2110c12c399aSSascha Wildner 	case MPTIOCTL_GET_ADAPTER_DATA:
2111c12c399aSSascha Wildner 		/*
2112c12c399aSSascha Wildner 		 * The user has requested to read adapter data.  Call our
2113c12c399aSSascha Wildner 		 * routine which does this.
2114c12c399aSSascha Wildner 		 */
2115c12c399aSSascha Wildner 		error = 0;
2116c12c399aSSascha Wildner 		mps_user_get_adapter_data(sc, (mps_adapter_data_t *)arg);
2117c12c399aSSascha Wildner 		break;
2118c12c399aSSascha Wildner 	case MPTIOCTL_GET_PCI_INFO:
2119c12c399aSSascha Wildner 		/*
2120c12c399aSSascha Wildner 		 * The user has requested to read pci info.  Call
2121c12c399aSSascha Wildner 		 * our routine which does this.
2122c12c399aSSascha Wildner 		 */
2123c12c399aSSascha Wildner 		mps_lock(sc);
2124c12c399aSSascha Wildner 		error = 0;
2125c12c399aSSascha Wildner 		mps_user_read_pci_info(sc, (mps_pci_info_t *)arg);
2126c12c399aSSascha Wildner 		mps_unlock(sc);
2127c12c399aSSascha Wildner 		break;
2128c12c399aSSascha Wildner 	case MPTIOCTL_RESET_ADAPTER:
2129c12c399aSSascha Wildner 		mps_lock(sc);
2130c12c399aSSascha Wildner 		sc->port_enable_complete = 0;
2131c12c399aSSascha Wildner 		error = mps_reinit(sc);
2132c12c399aSSascha Wildner 		mps_unlock(sc);
2133c12c399aSSascha Wildner 		/*
2134c12c399aSSascha Wildner 		 * Wait no more than 5 minutes for Port Enable to complete
2135c12c399aSSascha Wildner 		 */
2136c12c399aSSascha Wildner 		for (reset_loop = 0; (reset_loop < MPS_DIAG_RESET_TIMEOUT) &&
2137c12c399aSSascha Wildner 		    (!sc->port_enable_complete); reset_loop++) {
2138c12c399aSSascha Wildner 			DELAY(1000);
2139c12c399aSSascha Wildner 		}
2140c12c399aSSascha Wildner 		if (reset_loop == MPS_DIAG_RESET_TIMEOUT) {
2141c12c399aSSascha Wildner 			kprintf("Port Enable did not complete after Diag "
2142c12c399aSSascha Wildner 			    "Reset.\n");
2143c12c399aSSascha Wildner 		}
2144c12c399aSSascha Wildner 		break;
2145c12c399aSSascha Wildner 	case MPTIOCTL_DIAG_ACTION:
2146c12c399aSSascha Wildner 		/*
2147c12c399aSSascha Wildner 		 * The user has done a diag buffer action.  Call our routine
2148c12c399aSSascha Wildner 		 * which does this.  Only allow one diag action at one time.
2149c12c399aSSascha Wildner 		 */
2150c12c399aSSascha Wildner 		mps_lock(sc);
2151c12c399aSSascha Wildner 		error = mps_user_diag_action(sc, (mps_diag_action_t *)arg);
2152c12c399aSSascha Wildner 		mps_unlock(sc);
2153c12c399aSSascha Wildner 		break;
2154c12c399aSSascha Wildner 	case MPTIOCTL_EVENT_QUERY:
2155c12c399aSSascha Wildner 		/*
2156c12c399aSSascha Wildner 		 * The user has done an event query. Call our routine which does
2157c12c399aSSascha Wildner 		 * this.
2158c12c399aSSascha Wildner 		 */
2159c12c399aSSascha Wildner 		error = 0;
2160c12c399aSSascha Wildner 		mps_user_event_query(sc, (mps_event_query_t *)arg);
2161c12c399aSSascha Wildner 		break;
2162c12c399aSSascha Wildner 	case MPTIOCTL_EVENT_ENABLE:
2163c12c399aSSascha Wildner 		/*
2164c12c399aSSascha Wildner 		 * The user has done an event enable. Call our routine which
2165c12c399aSSascha Wildner 		 * does this.
2166c12c399aSSascha Wildner 		 */
2167c12c399aSSascha Wildner 		error = 0;
2168c12c399aSSascha Wildner 		mps_user_event_enable(sc, (mps_event_enable_t *)arg);
2169c12c399aSSascha Wildner 		break;
2170c12c399aSSascha Wildner 	case MPTIOCTL_EVENT_REPORT:
2171c12c399aSSascha Wildner 		/*
2172c12c399aSSascha Wildner 		 * The user has done an event report. Call our routine which
2173c12c399aSSascha Wildner 		 * does this.
2174c12c399aSSascha Wildner 		 */
2175c12c399aSSascha Wildner 		error = mps_user_event_report(sc, (mps_event_report_t *)arg);
2176c12c399aSSascha Wildner 		break;
2177c12c399aSSascha Wildner 	case MPTIOCTL_REG_ACCESS:
2178c12c399aSSascha Wildner 		/*
2179c12c399aSSascha Wildner 		 * The user has requested register access.  Call our routine
2180c12c399aSSascha Wildner 		 * which does this.
2181c12c399aSSascha Wildner 		 */
2182c12c399aSSascha Wildner 		mps_lock(sc);
2183c12c399aSSascha Wildner 		error = mps_user_reg_access(sc, (mps_reg_access_t *)arg);
2184c12c399aSSascha Wildner 		mps_unlock(sc);
2185c12c399aSSascha Wildner 		break;
2186c12c399aSSascha Wildner 	case MPTIOCTL_BTDH_MAPPING:
2187c12c399aSSascha Wildner 		/*
2188c12c399aSSascha Wildner 		 * The user has requested to translate a bus/target to a
2189c12c399aSSascha Wildner 		 * DevHandle or a DevHandle to a bus/target.  Call our routine
2190c12c399aSSascha Wildner 		 * which does this.
2191c12c399aSSascha Wildner 		 */
2192c12c399aSSascha Wildner 		error = mps_user_btdh(sc, (mps_btdh_mapping_t *)arg);
2193c12c399aSSascha Wildner 		break;
2194c12c399aSSascha Wildner 	default:
2195c12c399aSSascha Wildner 		error = ENOIOCTL;
2196c12c399aSSascha Wildner 		break;
2197c12c399aSSascha Wildner 	}
2198c12c399aSSascha Wildner 
2199c12c399aSSascha Wildner 	if (mps_page != NULL)
2200c12c399aSSascha Wildner 		kfree(mps_page, M_MPSUSER);
2201c12c399aSSascha Wildner 
2202c12c399aSSascha Wildner 	return (error);
2203c12c399aSSascha Wildner }
2204c12c399aSSascha Wildner 
2205c12c399aSSascha Wildner #ifdef COMPAT_FREEBSD32
2206c12c399aSSascha Wildner 
2207c12c399aSSascha Wildner struct mps_cfg_page_req32 {
2208c12c399aSSascha Wildner 	MPI2_CONFIG_PAGE_HEADER header;
2209c12c399aSSascha Wildner 	uint32_t page_address;
2210c12c399aSSascha Wildner 	uint32_t buf;
2211c12c399aSSascha Wildner 	int	len;
2212c12c399aSSascha Wildner 	uint16_t ioc_status;
2213c12c399aSSascha Wildner };
2214c12c399aSSascha Wildner 
2215c12c399aSSascha Wildner struct mps_ext_cfg_page_req32 {
2216c12c399aSSascha Wildner 	MPI2_CONFIG_EXTENDED_PAGE_HEADER header;
2217c12c399aSSascha Wildner 	uint32_t page_address;
2218c12c399aSSascha Wildner 	uint32_t buf;
2219c12c399aSSascha Wildner 	int	len;
2220c12c399aSSascha Wildner 	uint16_t ioc_status;
2221c12c399aSSascha Wildner };
2222c12c399aSSascha Wildner 
2223c12c399aSSascha Wildner struct mps_raid_action32 {
2224c12c399aSSascha Wildner 	uint8_t action;
2225c12c399aSSascha Wildner 	uint8_t volume_bus;
2226c12c399aSSascha Wildner 	uint8_t volume_id;
2227c12c399aSSascha Wildner 	uint8_t phys_disk_num;
2228c12c399aSSascha Wildner 	uint32_t action_data_word;
2229c12c399aSSascha Wildner 	uint32_t buf;
2230c12c399aSSascha Wildner 	int len;
2231c12c399aSSascha Wildner 	uint32_t volume_status;
2232c12c399aSSascha Wildner 	uint32_t action_data[4];
2233c12c399aSSascha Wildner 	uint16_t action_status;
2234c12c399aSSascha Wildner 	uint16_t ioc_status;
2235c12c399aSSascha Wildner 	uint8_t write;
2236c12c399aSSascha Wildner };
2237c12c399aSSascha Wildner 
2238c12c399aSSascha Wildner struct mps_usr_command32 {
2239c12c399aSSascha Wildner 	uint32_t req;
2240c12c399aSSascha Wildner 	uint32_t req_len;
2241c12c399aSSascha Wildner 	uint32_t rpl;
2242c12c399aSSascha Wildner 	uint32_t rpl_len;
2243c12c399aSSascha Wildner 	uint32_t buf;
2244c12c399aSSascha Wildner 	int len;
2245c12c399aSSascha Wildner 	uint32_t flags;
2246c12c399aSSascha Wildner };
2247c12c399aSSascha Wildner 
2248c12c399aSSascha Wildner #define	MPSIO_READ_CFG_HEADER32	_IOWR('M', 200, struct mps_cfg_page_req32)
2249c12c399aSSascha Wildner #define	MPSIO_READ_CFG_PAGE32	_IOWR('M', 201, struct mps_cfg_page_req32)
2250c12c399aSSascha Wildner #define	MPSIO_READ_EXT_CFG_HEADER32 _IOWR('M', 202, struct mps_ext_cfg_page_req32)
2251c12c399aSSascha Wildner #define	MPSIO_READ_EXT_CFG_PAGE32 _IOWR('M', 203, struct mps_ext_cfg_page_req32)
2252c12c399aSSascha Wildner #define	MPSIO_WRITE_CFG_PAGE32	_IOWR('M', 204, struct mps_cfg_page_req32)
2253c12c399aSSascha Wildner #define	MPSIO_RAID_ACTION32	_IOWR('M', 205, struct mps_raid_action32)
2254c12c399aSSascha Wildner #define	MPSIO_MPS_COMMAND32	_IOWR('M', 210, struct mps_usr_command32)
2255c12c399aSSascha Wildner 
2256c12c399aSSascha Wildner static int
mps_ioctl32(struct cdev * dev,u_long cmd32,void * _arg,int flag,struct thread * td)2257c12c399aSSascha Wildner mps_ioctl32(struct cdev *dev, u_long cmd32, void *_arg, int flag,
2258c12c399aSSascha Wildner     struct thread *td)
2259c12c399aSSascha Wildner {
2260c12c399aSSascha Wildner 	struct mps_cfg_page_req32 *page32 = _arg;
2261c12c399aSSascha Wildner 	struct mps_ext_cfg_page_req32 *ext32 = _arg;
2262c12c399aSSascha Wildner 	struct mps_raid_action32 *raid32 = _arg;
2263c12c399aSSascha Wildner 	struct mps_usr_command32 *user32 = _arg;
2264c12c399aSSascha Wildner 	union {
2265c12c399aSSascha Wildner 		struct mps_cfg_page_req page;
2266c12c399aSSascha Wildner 		struct mps_ext_cfg_page_req ext;
2267c12c399aSSascha Wildner 		struct mps_raid_action raid;
2268c12c399aSSascha Wildner 		struct mps_usr_command user;
2269c12c399aSSascha Wildner 	} arg;
2270c12c399aSSascha Wildner 	u_long cmd;
2271c12c399aSSascha Wildner 	int error;
2272c12c399aSSascha Wildner 
2273c12c399aSSascha Wildner 	switch (cmd32) {
2274c12c399aSSascha Wildner 	case MPSIO_READ_CFG_HEADER32:
2275c12c399aSSascha Wildner 	case MPSIO_READ_CFG_PAGE32:
2276c12c399aSSascha Wildner 	case MPSIO_WRITE_CFG_PAGE32:
2277c12c399aSSascha Wildner 		if (cmd32 == MPSIO_READ_CFG_HEADER32)
2278c12c399aSSascha Wildner 			cmd = MPSIO_READ_CFG_HEADER;
2279c12c399aSSascha Wildner 		else if (cmd32 == MPSIO_READ_CFG_PAGE32)
2280c12c399aSSascha Wildner 			cmd = MPSIO_READ_CFG_PAGE;
2281c12c399aSSascha Wildner 		else
2282c12c399aSSascha Wildner 			cmd = MPSIO_WRITE_CFG_PAGE;
2283c12c399aSSascha Wildner 		CP(*page32, arg.page, header);
2284c12c399aSSascha Wildner 		CP(*page32, arg.page, page_address);
2285c12c399aSSascha Wildner 		PTRIN_CP(*page32, arg.page, buf);
2286c12c399aSSascha Wildner 		CP(*page32, arg.page, len);
2287c12c399aSSascha Wildner 		CP(*page32, arg.page, ioc_status);
2288c12c399aSSascha Wildner 		break;
2289c12c399aSSascha Wildner 
2290c12c399aSSascha Wildner 	case MPSIO_READ_EXT_CFG_HEADER32:
2291c12c399aSSascha Wildner 	case MPSIO_READ_EXT_CFG_PAGE32:
2292c12c399aSSascha Wildner 		if (cmd32 == MPSIO_READ_EXT_CFG_HEADER32)
2293c12c399aSSascha Wildner 			cmd = MPSIO_READ_EXT_CFG_HEADER;
2294c12c399aSSascha Wildner 		else
2295c12c399aSSascha Wildner 			cmd = MPSIO_READ_EXT_CFG_PAGE;
2296c12c399aSSascha Wildner 		CP(*ext32, arg.ext, header);
2297c12c399aSSascha Wildner 		CP(*ext32, arg.ext, page_address);
2298c12c399aSSascha Wildner 		PTRIN_CP(*ext32, arg.ext, buf);
2299c12c399aSSascha Wildner 		CP(*ext32, arg.ext, len);
2300c12c399aSSascha Wildner 		CP(*ext32, arg.ext, ioc_status);
2301c12c399aSSascha Wildner 		break;
2302c12c399aSSascha Wildner 
2303c12c399aSSascha Wildner 	case MPSIO_RAID_ACTION32:
2304c12c399aSSascha Wildner 		cmd = MPSIO_RAID_ACTION;
2305c12c399aSSascha Wildner 		CP(*raid32, arg.raid, action);
2306c12c399aSSascha Wildner 		CP(*raid32, arg.raid, volume_bus);
2307c12c399aSSascha Wildner 		CP(*raid32, arg.raid, volume_id);
2308c12c399aSSascha Wildner 		CP(*raid32, arg.raid, phys_disk_num);
2309c12c399aSSascha Wildner 		CP(*raid32, arg.raid, action_data_word);
2310c12c399aSSascha Wildner 		PTRIN_CP(*raid32, arg.raid, buf);
2311c12c399aSSascha Wildner 		CP(*raid32, arg.raid, len);
2312c12c399aSSascha Wildner 		CP(*raid32, arg.raid, volume_status);
2313c12c399aSSascha Wildner 		bcopy(raid32->action_data, arg.raid.action_data,
2314c12c399aSSascha Wildner 		    sizeof arg.raid.action_data);
2315c12c399aSSascha Wildner 		CP(*raid32, arg.raid, ioc_status);
2316c12c399aSSascha Wildner 		CP(*raid32, arg.raid, write);
2317c12c399aSSascha Wildner 		break;
2318c12c399aSSascha Wildner 
2319c12c399aSSascha Wildner 	case MPSIO_MPS_COMMAND32:
2320c12c399aSSascha Wildner 		cmd = MPSIO_MPS_COMMAND;
2321c12c399aSSascha Wildner 		PTRIN_CP(*user32, arg.user, req);
2322c12c399aSSascha Wildner 		CP(*user32, arg.user, req_len);
2323c12c399aSSascha Wildner 		PTRIN_CP(*user32, arg.user, rpl);
2324c12c399aSSascha Wildner 		CP(*user32, arg.user, rpl_len);
2325c12c399aSSascha Wildner 		PTRIN_CP(*user32, arg.user, buf);
2326c12c399aSSascha Wildner 		CP(*user32, arg.user, len);
2327c12c399aSSascha Wildner 		CP(*user32, arg.user, flags);
2328c12c399aSSascha Wildner 		break;
2329c12c399aSSascha Wildner 	default:
2330c12c399aSSascha Wildner 		return (ENOIOCTL);
2331c12c399aSSascha Wildner 	}
2332c12c399aSSascha Wildner 
2333c12c399aSSascha Wildner 	error = mps_ioctl(dev, cmd, &arg, flag, td);
2334c12c399aSSascha Wildner 	if (error == 0 && (cmd32 & IOC_OUT) != 0) {
2335c12c399aSSascha Wildner 		switch (cmd32) {
2336c12c399aSSascha Wildner 		case MPSIO_READ_CFG_HEADER32:
2337c12c399aSSascha Wildner 		case MPSIO_READ_CFG_PAGE32:
2338c12c399aSSascha Wildner 		case MPSIO_WRITE_CFG_PAGE32:
2339c12c399aSSascha Wildner 			CP(arg.page, *page32, header);
2340c12c399aSSascha Wildner 			CP(arg.page, *page32, page_address);
2341c12c399aSSascha Wildner 			PTROUT_CP(arg.page, *page32, buf);
2342c12c399aSSascha Wildner 			CP(arg.page, *page32, len);
2343c12c399aSSascha Wildner 			CP(arg.page, *page32, ioc_status);
2344c12c399aSSascha Wildner 			break;
2345c12c399aSSascha Wildner 
2346c12c399aSSascha Wildner 		case MPSIO_READ_EXT_CFG_HEADER32:
2347c12c399aSSascha Wildner 		case MPSIO_READ_EXT_CFG_PAGE32:
2348c12c399aSSascha Wildner 			CP(arg.ext, *ext32, header);
2349c12c399aSSascha Wildner 			CP(arg.ext, *ext32, page_address);
2350c12c399aSSascha Wildner 			PTROUT_CP(arg.ext, *ext32, buf);
2351c12c399aSSascha Wildner 			CP(arg.ext, *ext32, len);
2352c12c399aSSascha Wildner 			CP(arg.ext, *ext32, ioc_status);
2353c12c399aSSascha Wildner 			break;
2354c12c399aSSascha Wildner 
2355c12c399aSSascha Wildner 		case MPSIO_RAID_ACTION32:
2356c12c399aSSascha Wildner 			CP(arg.raid, *raid32, action);
2357c12c399aSSascha Wildner 			CP(arg.raid, *raid32, volume_bus);
2358c12c399aSSascha Wildner 			CP(arg.raid, *raid32, volume_id);
2359c12c399aSSascha Wildner 			CP(arg.raid, *raid32, phys_disk_num);
2360c12c399aSSascha Wildner 			CP(arg.raid, *raid32, action_data_word);
2361c12c399aSSascha Wildner 			PTROUT_CP(arg.raid, *raid32, buf);
2362c12c399aSSascha Wildner 			CP(arg.raid, *raid32, len);
2363c12c399aSSascha Wildner 			CP(arg.raid, *raid32, volume_status);
2364c12c399aSSascha Wildner 			bcopy(arg.raid.action_data, raid32->action_data,
2365c12c399aSSascha Wildner 			    sizeof arg.raid.action_data);
2366c12c399aSSascha Wildner 			CP(arg.raid, *raid32, ioc_status);
2367c12c399aSSascha Wildner 			CP(arg.raid, *raid32, write);
2368c12c399aSSascha Wildner 			break;
2369c12c399aSSascha Wildner 
2370c12c399aSSascha Wildner 		case MPSIO_MPS_COMMAND32:
2371c12c399aSSascha Wildner 			PTROUT_CP(arg.user, *user32, req);
2372c12c399aSSascha Wildner 			CP(arg.user, *user32, req_len);
2373c12c399aSSascha Wildner 			PTROUT_CP(arg.user, *user32, rpl);
2374c12c399aSSascha Wildner 			CP(arg.user, *user32, rpl_len);
2375c12c399aSSascha Wildner 			PTROUT_CP(arg.user, *user32, buf);
2376c12c399aSSascha Wildner 			CP(arg.user, *user32, len);
2377c12c399aSSascha Wildner 			CP(arg.user, *user32, flags);
2378c12c399aSSascha Wildner 			break;
2379c12c399aSSascha Wildner 		}
2380c12c399aSSascha Wildner 	}
2381c12c399aSSascha Wildner 
2382c12c399aSSascha Wildner 	return (error);
2383c12c399aSSascha Wildner }
2384c12c399aSSascha Wildner #endif /* COMPAT_FREEBSD32 */
2385c12c399aSSascha Wildner 
2386c12c399aSSascha Wildner static int
mps_ioctl_devsw(struct dev_ioctl_args * ap)2387c12c399aSSascha Wildner mps_ioctl_devsw(struct dev_ioctl_args *ap)
2388c12c399aSSascha Wildner {
2389c12c399aSSascha Wildner 	cdev_t dev = ap->a_head.a_dev;
2390c12c399aSSascha Wildner 	u_long com = ap->a_cmd;
2391c12c399aSSascha Wildner 	caddr_t arg = ap->a_data;
2392c12c399aSSascha Wildner 	int flag = ap->a_fflag;
2393c12c399aSSascha Wildner 
2394c12c399aSSascha Wildner #ifdef COMPAT_FREEBSD32
2395c12c399aSSascha Wildner 	if (SV_CURPROC_FLAG(SV_ILP32))
2396c12c399aSSascha Wildner 		return (mps_ioctl32(dev, com, arg, flag, td));
2397c12c399aSSascha Wildner #endif
2398c12c399aSSascha Wildner 	return (mps_ioctl(dev, com, arg, flag));
2399c12c399aSSascha Wildner }
2400