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