]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/mpsutil/mps_cmd.c
Import DTS files from Linux 5.3
[FreeBSD/FreeBSD.git] / usr.sbin / mpsutil / mps_cmd.c
1 /*-
2  * Copyright (c) 2015 Baptiste Daroussin <bapt@FreeBSD.org>
3  *
4  * Copyright (c) 2015 Netflix, Inc.
5  * Written by: Scott Long <scottl@freebsd.org>
6  *
7  * Copyright (c) 2008 Yahoo!, Inc.
8  * All rights reserved.
9  * Written by: John Baldwin <jhb@FreeBSD.org>
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of the author nor the names of any co-contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35
36 #include <sys/cdefs.h>
37 __RCSID("$FreeBSD$");
38
39 #include <sys/param.h>
40 #include <sys/errno.h>
41 #include <sys/ioctl.h>
42 #if 0
43 #include <sys/mps_ioctl.h>
44 #else
45 #include "mps_ioctl.h"
46 #include "mpr_ioctl.h"
47 #endif
48 #include <sys/sysctl.h>
49 #include <sys/uio.h>
50
51 #include <err.h>
52 #include <fcntl.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <unistd.h>
57
58 #include "mpsutil.h"
59
60 #ifndef USE_MPT_IOCTLS
61 #define USE_MPT_IOCTLS
62 #endif
63
64 static const char *mps_ioc_status_codes[] = {
65         "Success",                              /* 0x0000 */
66         "Invalid function",
67         "Busy",
68         "Invalid scatter-gather list",
69         "Internal error",
70         "Reserved",
71         "Insufficient resources",
72         "Invalid field",
73         "Invalid state",                        /* 0x0008 */
74         "Operation state not supported",
75         NULL,
76         NULL,
77         NULL,
78         NULL,
79         NULL,
80         NULL,
81         NULL,                                   /* 0x0010 */
82         NULL,
83         NULL,
84         NULL,
85         NULL,
86         NULL,
87         NULL,
88         NULL,
89         NULL,                                   /* 0x0018 */
90         NULL,
91         NULL,
92         NULL,
93         NULL,
94         NULL,
95         NULL,
96         NULL,
97         "Invalid configuration action",         /* 0x0020 */
98         "Invalid configuration type",
99         "Invalid configuration page",
100         "Invalid configuration data",
101         "No configuration defaults",
102         "Unable to commit configuration change",
103         NULL,
104         NULL,
105         NULL,                                   /* 0x0028 */
106         NULL,
107         NULL,
108         NULL,
109         NULL,
110         NULL,
111         NULL,
112         NULL,
113         NULL,                                   /* 0x0030 */
114         NULL,
115         NULL,
116         NULL,
117         NULL,
118         NULL,
119         NULL,
120         NULL,
121         NULL,                                   /* 0x0038 */
122         NULL,
123         NULL,
124         NULL,
125         NULL,
126         NULL,
127         NULL,
128         NULL,
129         "Recovered SCSI error",                 /* 0x0040 */
130         "Invalid SCSI bus",
131         "Invalid SCSI target ID",
132         "SCSI device not there",
133         "SCSI data overrun",
134         "SCSI data underrun",
135         "SCSI I/O error",
136         "SCSI protocol error",
137         "SCSI task terminated",                 /* 0x0048 */
138         "SCSI residual mismatch",
139         "SCSI task management failed",
140         "SCSI I/O controller terminated",
141         "SCSI external controller terminated",
142         "EEDP guard error",
143         "EEDP reference tag error",
144         "EEDP application tag error",
145         NULL,                                   /* 0x0050 */
146         NULL,
147         NULL,
148         NULL,
149         NULL,
150         NULL,
151         NULL,
152         NULL,
153         NULL,                                   /* 0x0058 */
154         NULL,
155         NULL,
156         NULL,
157         NULL,
158         NULL,
159         NULL,
160         NULL,
161         "SCSI target priority I/O",             /* 0x0060 */
162         "Invalid SCSI target port",
163         "Invalid SCSI target I/O index",
164         "SCSI target aborted",
165         "No connection retryable",
166         "No connection",
167         "FC aborted",
168         "Invalid FC receive ID",
169         "FC did invalid",                       /* 0x0068 */
170         "FC node logged out",
171         "Transfer count mismatch",
172         "STS data not set",
173         "FC exchange canceled",
174         "Data offset error",
175         "Too much write data",
176         "IU too short",
177         "ACK NAK timeout",                      /* 0x0070 */
178         "NAK received",
179         NULL,
180         NULL,
181         NULL,
182         NULL,
183         NULL,
184         NULL,
185         NULL,                                   /* 0x0078 */
186         NULL,
187         NULL,
188         NULL,
189         NULL,
190         NULL,
191         NULL,
192         NULL,
193         "LAN device not found",                 /* 0x0080 */
194         "LAN device failure",
195         "LAN transmit error",
196         "LAN transmit aborted",
197         "LAN receive error",
198         "LAN receive aborted",
199         "LAN partial packet",
200         "LAN canceled",
201         NULL,                                   /* 0x0088 */
202         NULL,
203         NULL,
204         NULL,
205         NULL,
206         NULL,
207         NULL,
208         NULL,
209         "SAS SMP request failed",               /* 0x0090 */
210         "SAS SMP data overrun",
211         NULL,
212         NULL,
213         NULL,
214         NULL,
215         NULL,
216         NULL,
217         "Inband aborted",                       /* 0x0098 */
218         "No inband connection",
219         NULL,
220         NULL,
221         NULL,
222         NULL,
223         NULL,
224         NULL,
225         "Diagnostic released",                  /* 0x00A0 */
226 };
227
228 struct mprs_pass_thru {
229         uint64_t        PtrRequest;
230         uint64_t        PtrReply;
231         uint64_t        PtrData;
232         uint32_t        RequestSize;
233         uint32_t        ReplySize;
234         uint32_t        DataSize;
235         uint32_t        DataDirection;
236         uint64_t        PtrDataOut;
237         uint32_t        DataOutSize;
238         uint32_t        Timeout;
239 };
240
241 struct mprs_btdh_mapping {
242         uint16_t        TargetID;
243         uint16_t        Bus;
244         uint16_t        DevHandle;
245         uint16_t        Reserved;
246 };
247
248 const char *
249 mps_ioc_status(U16 IOCStatus)
250 {
251         static char buffer[16];
252
253         IOCStatus &= MPI2_IOCSTATUS_MASK;
254         if (IOCStatus < sizeof(mps_ioc_status_codes) / sizeof(char *) &&
255             mps_ioc_status_codes[IOCStatus] != NULL)
256                 return (mps_ioc_status_codes[IOCStatus]);
257         snprintf(buffer, sizeof(buffer), "Status: 0x%04x", IOCStatus);
258         return (buffer);
259 }
260
261 #ifdef USE_MPT_IOCTLS
262 int
263 mps_map_btdh(int fd, uint16_t *devhandle, uint16_t *bus, uint16_t *target)
264 {
265         int error;
266         struct mprs_btdh_mapping map;
267
268         map.Bus = *bus;
269         map.TargetID = *target;
270         map.DevHandle = *devhandle;
271
272         if ((error = ioctl(fd, MPTIOCTL_BTDH_MAPPING, &map)) != 0) {
273                 error = errno;
274                 warn("Failed to map bus/target/device");
275                 return (error);
276         }
277
278         *bus = map.Bus;
279         *target = map.TargetID;
280         *devhandle = map.DevHandle;
281
282         return (0);
283 }
284
285 int
286 mps_set_slot_status(int fd, U16 handle, U16 slot, U32 status)
287 {
288         MPI2_SEP_REQUEST req;
289         MPI2_SEP_REPLY reply;
290
291         bzero(&req, sizeof(req));
292         req.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
293         req.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS;
294         req.Flags = MPI2_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS;
295         req.EnclosureHandle = handle;
296         req.Slot = slot;
297         req.SlotStatus = status;
298
299         if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
300             NULL, 0, NULL, 0, 30) != 0)
301                 return (errno);
302
303         if (!IOC_STATUS_SUCCESS(reply.IOCStatus))
304                 return (EIO);
305         return (0);
306 }
307
308 int
309 mps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
310     MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
311 {
312         MPI2_CONFIG_REQUEST req;
313         MPI2_CONFIG_REPLY reply;
314
315         bzero(&req, sizeof(req));
316         req.Function = MPI2_FUNCTION_CONFIG;
317         req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
318         req.Header.PageType = PageType;
319         req.Header.PageNumber = PageNumber;
320         req.PageAddress = PageAddress;
321
322         if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
323             NULL, 0, NULL, 0, 30))
324                 return (errno);
325
326         if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
327                 if (IOCStatus != NULL)
328                         *IOCStatus = reply.IOCStatus;
329                 return (EIO);
330         }
331         if (header == NULL)
332                 return (EINVAL);
333         *header = reply.Header;
334         return (0);
335 }
336
337 int
338 mps_read_ext_config_page_header(int fd, U8 ExtPageType, U8 PageNumber, U32 PageAddress, MPI2_CONFIG_PAGE_HEADER *header, U16 *ExtPageLength, U16 *IOCStatus)
339 {
340         MPI2_CONFIG_REQUEST req;
341         MPI2_CONFIG_REPLY reply;
342
343         bzero(&req, sizeof(req));
344         req.Function = MPI2_FUNCTION_CONFIG;
345         req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
346         req.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
347         req.ExtPageType = ExtPageType;
348         req.Header.PageNumber = PageNumber;
349         req.PageAddress = PageAddress;
350
351         if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
352             NULL, 0, NULL, 0, 30))
353                 return (errno);
354
355         if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
356                 if (IOCStatus != NULL)
357                         *IOCStatus = reply.IOCStatus;
358                 return (EIO);
359         }
360         if ((header == NULL) || (ExtPageLength == NULL))
361                 return (EINVAL);
362         *header = reply.Header;
363         *ExtPageLength = reply.ExtPageLength;
364         return (0);
365 }
366
367 void *
368 mps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
369     U16 *IOCStatus)
370 {
371         MPI2_CONFIG_REQUEST req;
372         MPI2_CONFIG_PAGE_HEADER header;
373         MPI2_CONFIG_REPLY reply;
374         void *buf;
375         int error, len;
376
377         bzero(&header, sizeof(header));
378         error = mps_read_config_page_header(fd, PageType, PageNumber,
379             PageAddress, &header, IOCStatus);
380         if (error) {
381                 errno = error;
382                 return (NULL);
383         }
384
385         bzero(&req, sizeof(req));
386         req.Function = MPI2_FUNCTION_CONFIG;
387         req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
388         req.PageAddress = PageAddress;
389         req.Header = header;
390         if (req.Header.PageLength == 0)
391                 req.Header.PageLength = 4;
392
393         len = req.Header.PageLength * 4;
394         buf = malloc(len);
395         if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
396             buf, len, NULL, 0, 30)) {
397                 error = errno;
398                 free(buf);
399                 errno = error;
400                 return (NULL);
401         }
402         if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
403                 if (IOCStatus != NULL)
404                         *IOCStatus = reply.IOCStatus;
405                 else
406                         warnx("Reading config page failed: 0x%x %s",
407                             reply.IOCStatus, mps_ioc_status(reply.IOCStatus));
408                 free(buf);
409                 errno = EIO;
410                 return (NULL);
411         }
412         return (buf);
413 }
414
415 void *
416 mps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
417     U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
418 {
419         MPI2_CONFIG_REQUEST req;
420         MPI2_CONFIG_PAGE_HEADER header;
421         MPI2_CONFIG_REPLY reply;
422         U16 pagelen;
423         void *buf;
424         int error, len;
425
426         if (IOCStatus != NULL)
427                 *IOCStatus = MPI2_IOCSTATUS_SUCCESS;
428         bzero(&header, sizeof(header));
429         error = mps_read_ext_config_page_header(fd, ExtPageType, PageNumber,
430             PageAddress, &header, &pagelen, IOCStatus);
431         if (error) {
432                 errno = error;
433                 return (NULL);
434         }
435
436         bzero(&req, sizeof(req));
437         req.Function = MPI2_FUNCTION_CONFIG;
438         req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
439         req.PageAddress = PageAddress;
440         req.Header = header;
441         if (pagelen == 0)
442                 pagelen = 4;
443         req.ExtPageLength = pagelen;
444         req.ExtPageType = ExtPageType;
445
446         len = pagelen * 4;
447         buf = malloc(len);
448         if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
449             buf, len, NULL, 0, 30)) {
450                 error = errno;
451                 free(buf);
452                 errno = error;
453                 return (NULL);
454         }
455         if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
456                 if (IOCStatus != NULL)
457                         *IOCStatus = reply.IOCStatus;
458                 else
459                         warnx("Reading extended config page failed: %s",
460                             mps_ioc_status(reply.IOCStatus));
461                 free(buf);
462                 errno = EIO;
463                 return (NULL);
464         }
465         return (buf);
466 }
467
468 int
469 mps_firmware_send(int fd, unsigned char *fw, uint32_t len, bool bios)
470 {
471         MPI2_FW_DOWNLOAD_REQUEST req;
472         MPI2_FW_DOWNLOAD_REPLY reply;
473
474         bzero(&req, sizeof(req));
475         bzero(&reply, sizeof(reply));
476         req.Function = MPI2_FUNCTION_FW_DOWNLOAD;
477         req.ImageType = bios ? MPI2_FW_DOWNLOAD_ITYPE_BIOS : MPI2_FW_DOWNLOAD_ITYPE_FW;
478         req.TotalImageSize = len;
479         req.MsgFlags = MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT;
480
481         if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply),
482             fw, len, 0)) {
483                 return (-1);
484         }
485         return (0);
486 }
487
488 int
489 mps_firmware_get(int fd, unsigned char **firmware, bool bios)
490 {
491         MPI2_FW_UPLOAD_REQUEST req;
492         MPI2_FW_UPLOAD_REPLY reply;
493         int size;
494
495         *firmware = NULL;
496         bzero(&req, sizeof(req));
497         bzero(&reply, sizeof(reply));
498         req.Function = MPI2_FUNCTION_FW_UPLOAD;
499         req.ImageType = bios ? MPI2_FW_DOWNLOAD_ITYPE_BIOS : MPI2_FW_DOWNLOAD_ITYPE_FW;
500
501         if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply),
502             NULL, 0, 0)) {
503                 return (-1);
504         }
505         if (reply.ActualImageSize == 0) {
506                 return (-1);
507         }
508
509         size = reply.ActualImageSize;
510         *firmware = calloc(size, sizeof(unsigned char));
511         if (*firmware == NULL) {
512                 warn("calloc");
513                 return (-1);
514         }
515         if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply),
516             *firmware, size, 0)) {
517                 free(*firmware);
518                 return (-1);
519         }
520
521         return (size);
522 }
523
524 #else
525
526 int
527 mps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
528     MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
529 {
530         struct mps_cfg_page_req req;
531
532         if (IOCStatus != NULL)
533                 *IOCStatus = MPI2_IOCSTATUS_SUCCESS;
534         if (header == NULL)
535                 return (EINVAL);
536         bzero(&req, sizeof(req));
537         req.header.PageType = PageType;
538         req.header.PageNumber = PageNumber;
539         req.page_address = PageAddress;
540         if (ioctl(fd, MPSIO_READ_CFG_HEADER, &req) < 0)
541                 return (errno);
542         if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
543                 if (IOCStatus != NULL)
544                         *IOCStatus = req.ioc_status;
545                 return (EIO);
546         }
547         bcopy(&req.header, header, sizeof(*header));
548         return (0);
549 }
550
551 void *
552 mps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
553     U16 *IOCStatus)
554 {
555         struct mps_cfg_page_req req;
556         void *buf;
557         int error;
558
559         error = mps_read_config_page_header(fd, PageType, PageNumber,
560             PageAddress, &req.header, IOCStatus);
561         if (error) {
562                 errno = error;
563                 return (NULL);
564         }
565
566         if (req.header.PageLength == 0)
567                 req.header.PageLength = 4;
568         req.len = req.header.PageLength * 4;
569         buf = malloc(req.len);
570         req.buf = buf;
571         bcopy(&req.header, buf, sizeof(req.header));
572         if (ioctl(fd, MPSIO_READ_CFG_PAGE, &req) < 0) {
573                 error = errno;
574                 free(buf);
575                 errno = error;
576                 return (NULL);
577         }
578         if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
579                 if (IOCStatus != NULL)
580                         *IOCStatus = req.ioc_status;
581                 else
582                         warnx("Reading config page failed: 0x%x %s",
583                             req.ioc_status, mps_ioc_status(req.ioc_status));
584                 free(buf);
585                 errno = EIO;
586                 return (NULL);
587         }
588         return (buf);
589 }
590
591 void *
592 mps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
593     U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
594 {
595         struct mps_ext_cfg_page_req req;
596         void *buf;
597         int error;
598
599         if (IOCStatus != NULL)
600                 *IOCStatus = MPI2_IOCSTATUS_SUCCESS;
601         bzero(&req, sizeof(req));
602         req.header.PageVersion = PageVersion;
603         req.header.PageNumber = PageNumber;
604         req.header.ExtPageType = ExtPageType;
605         req.page_address = PageAddress;
606         if (ioctl(fd, MPSIO_READ_EXT_CFG_HEADER, &req) < 0)
607                 return (NULL);
608         if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
609                 if (IOCStatus != NULL)
610                         *IOCStatus = req.ioc_status;
611                 else
612                         warnx("Reading extended config page header failed: %s",
613                             mps_ioc_status(req.ioc_status));
614                 errno = EIO;
615                 return (NULL);
616         }
617         req.len = req.header.ExtPageLength * 4;
618         buf = malloc(req.len);
619         req.buf = buf;
620         bcopy(&req.header, buf, sizeof(req.header));
621         if (ioctl(fd, MPSIO_READ_EXT_CFG_PAGE, &req) < 0) {
622                 error = errno;
623                 free(buf);
624                 errno = error;
625                 return (NULL);
626         }
627         if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
628                 if (IOCStatus != NULL)
629                         *IOCStatus = req.ioc_status;
630                 else
631                         warnx("Reading extended config page failed: %s",
632                             mps_ioc_status(req.ioc_status));
633                 free(buf);
634                 errno = EIO;
635                 return (NULL);
636         }
637         return (buf);
638 }
639 #endif
640
641 int
642 mps_open(int unit)
643 {
644         char path[MAXPATHLEN];
645
646         snprintf(path, sizeof(path), "/dev/mp%s%d", is_mps ? "s": "r", unit);
647         return (open(path, O_RDWR));
648 }
649
650 int
651 mps_user_command(int fd, void *req, uint32_t req_len, void *reply,
652         uint32_t reply_len, void *buffer, int len, uint32_t flags)
653 {
654         struct mps_usr_command cmd;
655
656         bzero(&cmd, sizeof(struct mps_usr_command));
657         cmd.req = req;
658         cmd.req_len = req_len;
659         cmd.rpl = reply;
660         cmd.rpl_len = reply_len;
661         cmd.buf = buffer;
662         cmd.len = len;
663         cmd.flags = flags;
664
665         if (ioctl(fd, is_mps ? MPSIO_MPS_COMMAND : MPRIO_MPR_COMMAND, &cmd) < 0)
666                 return (errno);
667         return (0);
668 }
669
670 int
671 mps_pass_command(int fd, void *req, uint32_t req_len, void *reply,
672         uint32_t reply_len, void *data_in, uint32_t datain_len, void *data_out,
673         uint32_t dataout_len, uint32_t timeout)
674 {
675         struct mprs_pass_thru pass;
676
677         bzero(&pass, sizeof(pass));
678         pass.PtrRequest = (uint64_t)(uintptr_t)req;
679         pass.PtrReply = (uint64_t)(uintptr_t)reply;
680         pass.RequestSize = req_len;
681         pass.ReplySize = reply_len;
682         if (datain_len && dataout_len) {
683                 pass.PtrData = (uint64_t)(uintptr_t)data_in;
684                 pass.PtrDataOut = (uint64_t)(uintptr_t)data_out;
685                 pass.DataSize = datain_len;
686                 pass.DataOutSize = dataout_len;
687                 if (is_mps) {
688                         pass.DataDirection = MPS_PASS_THRU_DIRECTION_BOTH;
689                 } else {
690                         pass.DataDirection = MPR_PASS_THRU_DIRECTION_BOTH;
691                 }
692         } else if (datain_len) {
693                 pass.PtrData = (uint64_t)(uintptr_t)data_in;
694                 pass.DataSize = datain_len;
695                 if (is_mps) {
696                         pass.DataDirection = MPS_PASS_THRU_DIRECTION_READ;
697                 } else {
698                         pass.DataDirection = MPR_PASS_THRU_DIRECTION_READ;
699                 }
700         } else if (dataout_len) {
701                 pass.PtrData = (uint64_t)(uintptr_t)data_out;
702                 pass.DataSize = dataout_len;
703                 if (is_mps) {
704                         pass.DataDirection = MPS_PASS_THRU_DIRECTION_WRITE;
705                 } else {
706                         pass.DataDirection = MPR_PASS_THRU_DIRECTION_WRITE;
707                 }
708         } else {
709                 if (is_mps) {
710                         pass.DataDirection = MPS_PASS_THRU_DIRECTION_NONE;
711                 } else {
712                         pass.DataDirection = MPR_PASS_THRU_DIRECTION_NONE;
713                 }
714         }
715         pass.Timeout = timeout;
716
717         if (ioctl(fd, MPTIOCTL_PASS_THRU, &pass) < 0)
718                 return (errno);
719         return (0);
720 }
721
722 MPI2_IOC_FACTS_REPLY *
723 mps_get_iocfacts(int fd)
724 {
725         MPI2_IOC_FACTS_REPLY *facts;
726         MPI2_IOC_FACTS_REQUEST req;
727         int error;
728
729         facts = malloc(sizeof(MPI2_IOC_FACTS_REPLY));
730         if (facts == NULL) {
731                 errno = ENOMEM;
732                 return (NULL);
733         }
734
735         bzero(&req, sizeof(MPI2_IOC_FACTS_REQUEST));
736         req.Function = MPI2_FUNCTION_IOC_FACTS;
737
738 #if 1
739         error = mps_pass_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
740             facts, sizeof(MPI2_IOC_FACTS_REPLY), NULL, 0, NULL, 0, 10);
741 #else
742         error = mps_user_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
743             facts, sizeof(MPI2_IOC_FACTS_REPLY), NULL, 0, 0);
744 #endif
745         if (error) {
746                 free(facts);
747                 return (NULL);
748         }
749
750         if (!IOC_STATUS_SUCCESS(facts->IOCStatus)) {
751                 free(facts);
752                 errno = EINVAL;
753                 return (NULL);
754         }
755         return (facts);
756 }
757