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