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