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