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