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 = ¶ms.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, ¶ms)) != 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 = ¶ms.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, ¶ms)) != 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 = ¶ms.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, ¶ms)) != 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 = ¶ms.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, ¶ms)) != 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 = ¶ms.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, ¶ms)) != 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