]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/mpsutil/mps_cmd.c
Add generic storage structure for both mpr and mps to simplify code
[FreeBSD/FreeBSD.git] / usr.sbin / mpsutil / mps_cmd.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
31 #include <sys/cdefs.h>
32 __RCSID("$FreeBSD$");
33
34 #include <sys/param.h>
35 #include <sys/errno.h>
36 #include <sys/ioctl.h>
37 #if 0
38 #include <sys/mps_ioctl.h>
39 #else
40 #include "mps_ioctl.h"
41 #include "mpr_ioctl.h"
42 #endif
43 #include <sys/sysctl.h>
44 #include <sys/uio.h>
45
46 #include <err.h>
47 #include <fcntl.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <unistd.h>
52
53 #include "mpsutil.h"
54
55 #ifndef USE_MPT_IOCTLS
56 #define USE_MPT_IOCTLS
57 #endif
58
59 static const char *mps_ioc_status_codes[] = {
60         "Success",                              /* 0x0000 */
61         "Invalid function",
62         "Busy",
63         "Invalid scatter-gather list",
64         "Internal error",
65         "Reserved",
66         "Insufficient resources",
67         "Invalid field",
68         "Invalid state",                        /* 0x0008 */
69         "Operation state not supported",
70         NULL,
71         NULL,
72         NULL,
73         NULL,
74         NULL,
75         NULL,
76         NULL,                                   /* 0x0010 */
77         NULL,
78         NULL,
79         NULL,
80         NULL,
81         NULL,
82         NULL,
83         NULL,
84         NULL,                                   /* 0x0018 */
85         NULL,
86         NULL,
87         NULL,
88         NULL,
89         NULL,
90         NULL,
91         NULL,
92         "Invalid configuration action",         /* 0x0020 */
93         "Invalid configuration type",
94         "Invalid configuration page",
95         "Invalid configuration data",
96         "No configuration defaults",
97         "Unable to commit configuration change",
98         NULL,
99         NULL,
100         NULL,                                   /* 0x0028 */
101         NULL,
102         NULL,
103         NULL,
104         NULL,
105         NULL,
106         NULL,
107         NULL,
108         NULL,                                   /* 0x0030 */
109         NULL,
110         NULL,
111         NULL,
112         NULL,
113         NULL,
114         NULL,
115         NULL,
116         NULL,                                   /* 0x0038 */
117         NULL,
118         NULL,
119         NULL,
120         NULL,
121         NULL,
122         NULL,
123         NULL,
124         "Recovered SCSI error",                 /* 0x0040 */
125         "Invalid SCSI bus",
126         "Invalid SCSI target ID",
127         "SCSI device not there",
128         "SCSI data overrun",
129         "SCSI data underrun",
130         "SCSI I/O error",
131         "SCSI protocol error",
132         "SCSI task terminated",                 /* 0x0048 */
133         "SCSI residual mismatch",
134         "SCSI task management failed",
135         "SCSI I/O controller terminated",
136         "SCSI external controller terminated",
137         "EEDP guard error",
138         "EEDP reference tag error",
139         "EEDP application tag error",
140         NULL,                                   /* 0x0050 */
141         NULL,
142         NULL,
143         NULL,
144         NULL,
145         NULL,
146         NULL,
147         NULL,
148         NULL,                                   /* 0x0058 */
149         NULL,
150         NULL,
151         NULL,
152         NULL,
153         NULL,
154         NULL,
155         NULL,
156         "SCSI target priority I/O",             /* 0x0060 */
157         "Invalid SCSI target port",
158         "Invalid SCSI target I/O index",
159         "SCSI target aborted",
160         "No connection retryable",
161         "No connection",
162         "FC aborted",
163         "Invalid FC receive ID",
164         "FC did invalid",                       /* 0x0068 */
165         "FC node logged out",
166         "Transfer count mismatch",
167         "STS data not set",
168         "FC exchange canceled",
169         "Data offset error",
170         "Too much write data",
171         "IU too short",
172         "ACK NAK timeout",                      /* 0x0070 */
173         "NAK received",
174         NULL,
175         NULL,
176         NULL,
177         NULL,
178         NULL,
179         NULL,
180         NULL,                                   /* 0x0078 */
181         NULL,
182         NULL,
183         NULL,
184         NULL,
185         NULL,
186         NULL,
187         NULL,
188         "LAN device not found",                 /* 0x0080 */
189         "LAN device failure",
190         "LAN transmit error",
191         "LAN transmit aborted",
192         "LAN receive error",
193         "LAN receive aborted",
194         "LAN partial packet",
195         "LAN canceled",
196         NULL,                                   /* 0x0088 */
197         NULL,
198         NULL,
199         NULL,
200         NULL,
201         NULL,
202         NULL,
203         NULL,
204         "SAS SMP request failed",               /* 0x0090 */
205         "SAS SMP data overrun",
206         NULL,
207         NULL,
208         NULL,
209         NULL,
210         NULL,
211         NULL,
212         "Inband aborted",                       /* 0x0098 */
213         "No inband connection",
214         NULL,
215         NULL,
216         NULL,
217         NULL,
218         NULL,
219         NULL,
220         "Diagnostic released",                  /* 0x00A0 */
221 };
222
223 struct mprs_pass_thru {
224         uint64_t        PtrRequest;
225         uint64_t        PtrReply;
226         uint64_t        PtrData;
227         uint32_t        RequestSize;
228         uint32_t        ReplySize;
229         uint32_t        DataSize;
230         uint32_t        DataDirection;
231         uint64_t        PtrDataOut;
232         uint32_t        DataOutSize;
233         uint32_t        Timeout;
234 };
235
236 struct mprs_btdh_mapping {
237         uint16_t        TargetID;
238         uint16_t        Bus;
239         uint16_t        DevHandle;
240         uint16_t        Reserved;
241 };
242
243 const char *
244 mps_ioc_status(U16 IOCStatus)
245 {
246         static char buffer[16];
247
248         IOCStatus &= MPI2_IOCSTATUS_MASK;
249         if (IOCStatus < sizeof(mps_ioc_status_codes) / sizeof(char *) &&
250             mps_ioc_status_codes[IOCStatus] != NULL)
251                 return (mps_ioc_status_codes[IOCStatus]);
252         snprintf(buffer, sizeof(buffer), "Status: 0x%04x", IOCStatus);
253         return (buffer);
254 }
255
256 #ifdef USE_MPT_IOCTLS
257 int
258 mps_map_btdh(int fd, uint16_t *devhandle, uint16_t *bus, uint16_t *target)
259 {
260         int error;
261         struct mprs_btdh_mapping map;
262
263         map.Bus = *bus;
264         map.TargetID = *target;
265         map.DevHandle = *devhandle;
266
267         if ((error = ioctl(fd, MPTIOCTL_BTDH_MAPPING, &map)) != 0) {
268                 error = errno;
269                 warn("Failed to map bus/target/device");
270                 return (error);
271         }
272
273         *bus = map.Bus;
274         *target = map.TargetID;
275         *devhandle = map.DevHandle;
276
277         return (0);
278 }
279
280 int
281 mps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
282     MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
283 {
284         MPI2_CONFIG_REQUEST req;
285         MPI2_CONFIG_REPLY reply;
286
287         bzero(&req, sizeof(req));
288         req.Function = MPI2_FUNCTION_CONFIG;
289         req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
290         req.Header.PageType = PageType;
291         req.Header.PageNumber = PageNumber;
292         req.PageAddress = PageAddress;
293
294         if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
295             NULL, 0, NULL, 0, 30))
296                 return (errno);
297
298         if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
299                 if (IOCStatus != NULL)
300                         *IOCStatus = reply.IOCStatus;
301                 return (EIO);
302         }
303         if (header == NULL)
304                 return (EINVAL);
305         *header = reply.Header;
306         return (0);
307 }
308
309 int
310 mps_read_ext_config_page_header(int fd, U8 ExtPageType, U8 PageNumber, U32 PageAddress, MPI2_CONFIG_PAGE_HEADER *header, U16 *ExtPageLength, 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 = MPI2_CONFIG_PAGETYPE_EXTENDED;
319         req.ExtPageType = ExtPageType;
320         req.Header.PageNumber = PageNumber;
321         req.PageAddress = PageAddress;
322
323         if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
324             NULL, 0, NULL, 0, 30))
325                 return (errno);
326
327         if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
328                 if (IOCStatus != NULL)
329                         *IOCStatus = reply.IOCStatus;
330                 return (EIO);
331         }
332         if ((header == NULL) || (ExtPageLength == NULL))
333                 return (EINVAL);
334         *header = reply.Header;
335         *ExtPageLength = reply.ExtPageLength;
336         return (0);
337 }
338
339 void *
340 mps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
341     U16 *IOCStatus)
342 {
343         MPI2_CONFIG_REQUEST req;
344         MPI2_CONFIG_PAGE_HEADER header;
345         MPI2_CONFIG_REPLY reply;
346         void *buf;
347         int error, len;
348
349         bzero(&header, sizeof(header));
350         error = mps_read_config_page_header(fd, PageType, PageNumber,
351             PageAddress, &header, IOCStatus);
352         if (error) {
353                 errno = error;
354                 return (NULL);
355         }
356
357         bzero(&req, sizeof(req));
358         req.Function = MPI2_FUNCTION_CONFIG;
359         req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
360         req.PageAddress = PageAddress;
361         req.Header = header;
362         req.Header.PageLength = reply.Header.PageLength;
363         if (reply.Header.PageLength == 0)
364                 req.Header.PageLength = 4;
365
366         len = req.Header.PageLength * 4;
367         buf = malloc(len);
368         if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
369             buf, len, NULL, 0, 30)) {
370                 error = errno;
371                 free(buf);
372                 errno = error;
373                 return (NULL);
374         }
375         if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
376                 if (IOCStatus != NULL)
377                         *IOCStatus = reply.IOCStatus;
378                 else
379                         warnx("Reading config page failed: 0x%x %s",
380                             reply.IOCStatus, mps_ioc_status(reply.IOCStatus));
381                 free(buf);
382                 errno = EIO;
383                 return (NULL);
384         }
385         return (buf);
386 }
387
388 void *
389 mps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
390     U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
391 {
392         MPI2_CONFIG_REQUEST req;
393         MPI2_CONFIG_PAGE_HEADER header;
394         MPI2_CONFIG_REPLY reply;
395         U16 pagelen;
396         void *buf;
397         int error, len;
398
399         if (IOCStatus != NULL)
400                 *IOCStatus = MPI2_IOCSTATUS_SUCCESS;
401         bzero(&header, sizeof(header));
402         error = mps_read_ext_config_page_header(fd, ExtPageType, PageNumber,
403             PageAddress, &header, &pagelen, IOCStatus);
404         if (error) {
405                 errno = error;
406                 return (NULL);
407         }
408
409         bzero(&req, sizeof(req));
410         req.Function = MPI2_FUNCTION_CONFIG;
411         req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
412         req.PageAddress = PageAddress;
413         req.Header = header;
414         if (pagelen == 0)
415                 pagelen = 4;
416         req.ExtPageLength = pagelen;
417         req.ExtPageType = ExtPageType;
418
419         len = pagelen * 4;
420         buf = malloc(len);
421         if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
422             buf, len, NULL, 0, 30)) {
423                 error = errno;
424                 free(buf);
425                 errno = error;
426                 return (NULL);
427         }
428         if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
429                 if (IOCStatus != NULL)
430                         *IOCStatus = reply.IOCStatus;
431                 else
432                         warnx("Reading extended config page failed: %s",
433                             mps_ioc_status(reply.IOCStatus));
434                 free(buf);
435                 errno = EIO;
436                 return (NULL);
437         }
438         return (buf);
439 }
440
441 #else
442
443 int
444 mps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
445     MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
446 {
447         struct mps_cfg_page_req req;
448
449         if (IOCStatus != NULL)
450                 *IOCStatus = MPI2_IOCSTATUS_SUCCESS;
451         if (header == NULL)
452                 return (EINVAL);
453         bzero(&req, sizeof(req));
454         req.header.PageType = PageType;
455         req.header.PageNumber = PageNumber;
456         req.page_address = PageAddress;
457         if (ioctl(fd, MPSIO_READ_CFG_HEADER, &req) < 0)
458                 return (errno);
459         if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
460                 if (IOCStatus != NULL)
461                         *IOCStatus = req.ioc_status;
462                 return (EIO);
463         }
464         bcopy(&req.header, header, sizeof(*header));
465         return (0);
466 }
467
468 void *
469 mps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
470     U16 *IOCStatus)
471 {
472         struct mps_cfg_page_req req;
473         void *buf;
474         int error;
475
476         error = mps_read_config_page_header(fd, PageType, PageNumber,
477             PageAddress, &req.header, IOCStatus);
478         if (error) {
479                 errno = error;
480                 return (NULL);
481         }
482
483         if (req.header.PageLength == 0)
484                 req.header.PageLength = 4;
485         req.len = req.header.PageLength * 4;
486         buf = malloc(req.len);
487         req.buf = buf;
488         bcopy(&req.header, buf, sizeof(req.header));
489         if (ioctl(fd, MPSIO_READ_CFG_PAGE, &req) < 0) {
490                 error = errno;
491                 free(buf);
492                 errno = error;
493                 return (NULL);
494         }
495         if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
496                 if (IOCStatus != NULL)
497                         *IOCStatus = req.ioc_status;
498                 else
499                         warnx("Reading config page failed: 0x%x %s",
500                             req.ioc_status, mps_ioc_status(req.ioc_status));
501                 free(buf);
502                 errno = EIO;
503                 return (NULL);
504         }
505         return (buf);
506 }
507
508 void *
509 mps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
510     U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
511 {
512         struct mps_ext_cfg_page_req req;
513         void *buf;
514         int error;
515
516         if (IOCStatus != NULL)
517                 *IOCStatus = MPI2_IOCSTATUS_SUCCESS;
518         bzero(&req, sizeof(req));
519         req.header.PageVersion = PageVersion;
520         req.header.PageNumber = PageNumber;
521         req.header.ExtPageType = ExtPageType;
522         req.page_address = PageAddress;
523         if (ioctl(fd, MPSIO_READ_EXT_CFG_HEADER, &req) < 0)
524                 return (NULL);
525         if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
526                 if (IOCStatus != NULL)
527                         *IOCStatus = req.ioc_status;
528                 else
529                         warnx("Reading extended config page header failed: %s",
530                             mps_ioc_status(req.ioc_status));
531                 errno = EIO;
532                 return (NULL);
533         }
534         req.len = req.header.ExtPageLength * 4;
535         buf = malloc(req.len);
536         req.buf = buf;
537         bcopy(&req.header, buf, sizeof(req.header));
538         if (ioctl(fd, MPSIO_READ_EXT_CFG_PAGE, &req) < 0) {
539                 error = errno;
540                 free(buf);
541                 errno = error;
542                 return (NULL);
543         }
544         if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
545                 if (IOCStatus != NULL)
546                         *IOCStatus = req.ioc_status;
547                 else
548                         warnx("Reading extended config page failed: %s",
549                             mps_ioc_status(req.ioc_status));
550                 free(buf);
551                 errno = EIO;
552                 return (NULL);
553         }
554         return (buf);
555 }
556 #endif
557
558 #if 0
559 int
560 mpt_write_config_page(int fd, void *buf, U16 *IOCStatus)
561 {
562         CONFIG_PAGE_HEADER *hdr;
563         struct mpt_cfg_page_req req;
564
565         if (IOCStatus != NULL)
566                 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
567         bzero(&req, sizeof(req));
568         req.buf = buf;
569         hdr = buf;
570         req.len = hdr->PageLength * 4;
571         if (ioctl(fd, MPTIO_WRITE_CFG_PAGE, &req) < 0)
572                 return (errno);
573         if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
574                 if (IOCStatus != NULL) {
575                         *IOCStatus = req.ioc_status;
576                         return (0);
577                 }
578                 warnx("Writing config page failed: %s",
579                     mpt_ioc_status(req.ioc_status));
580                 return (EIO);
581         }
582         return (0);
583 }
584
585 int
586 mpt_raid_action(int fd, U8 Action, U8 VolumeBus, U8 VolumeID, U8 PhysDiskNum,
587     U32 ActionDataWord, void *buf, int len, RAID_VOL0_STATUS *VolumeStatus,
588     U32 *ActionData, int datalen, U16 *IOCStatus, U16 *ActionStatus, int write)
589 {
590         struct mpt_raid_action raid_act;
591
592         if (IOCStatus != NULL)
593                 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
594         if (datalen < 0 || (unsigned)datalen > sizeof(raid_act.action_data))
595                 return (EINVAL);
596         bzero(&raid_act, sizeof(raid_act));
597         raid_act.action = Action;
598         raid_act.volume_bus = VolumeBus;
599         raid_act.volume_id = VolumeID;
600         raid_act.phys_disk_num = PhysDiskNum;
601         raid_act.action_data_word = ActionDataWord;
602         if (buf != NULL && len != 0) {
603                 raid_act.buf = buf;
604                 raid_act.len = len;
605                 raid_act.write = write;
606         }
607
608         if (ioctl(fd, MPTIO_RAID_ACTION, &raid_act) < 0)
609                 return (errno);
610
611         if (!IOC_STATUS_SUCCESS(raid_act.ioc_status)) {
612                 if (IOCStatus != NULL) {
613                         *IOCStatus = raid_act.ioc_status;
614                         return (0);
615                 }
616                 warnx("RAID action failed: %s",
617                     mpt_ioc_status(raid_act.ioc_status));
618                 return (EIO);
619         }
620
621         if (ActionStatus != NULL)
622                 *ActionStatus = raid_act.action_status;
623         if (raid_act.action_status != MPI_RAID_ACTION_ASTATUS_SUCCESS) {
624                 if (ActionStatus != NULL)
625                         return (0);
626                 warnx("RAID action failed: %s",
627                     mpt_raid_status(raid_act.action_status));
628                 return (EIO);
629         }
630
631         if (VolumeStatus != NULL)
632                 *((U32 *)VolumeStatus) = raid_act.volume_status;
633         if (ActionData != NULL)
634                 bcopy(raid_act.action_data, ActionData, datalen);
635         return (0);
636 }
637 #endif
638
639 int
640 mps_open(int unit)
641 {
642         char path[MAXPATHLEN];
643
644         snprintf(path, sizeof(path), "/dev/mp%s%d", is_mps ? "s": "r", unit);
645         return (open(path, O_RDWR));
646 }
647
648 int
649 mps_user_command(int fd, void *req, uint32_t req_len, void *reply,
650         uint32_t reply_len, void *buffer, int len, uint32_t flags)
651 {
652         struct mps_usr_command cmd;
653
654         bzero(&cmd, sizeof(struct mps_usr_command));
655         cmd.req = req;
656         cmd.req_len = req_len;
657         cmd.rpl = reply;
658         cmd.rpl_len = reply_len;
659         cmd.buf = buffer;
660         cmd.len = len;
661         cmd.flags = flags;
662
663         if (ioctl(fd, is_mps ? MPSIO_MPS_COMMAND : MPRIO_MPR_COMMAND, &cmd) < 0)
664                 return (errno);
665         return (0);
666 }
667
668 int
669 mps_pass_command(int fd, void *req, uint32_t req_len, void *reply,
670         uint32_t reply_len, void *data_in, uint32_t datain_len, void *data_out,
671         uint32_t dataout_len, uint32_t timeout)
672 {
673         struct mprs_pass_thru pass;
674
675         pass.PtrRequest = (uint64_t)(uintptr_t)req;
676         pass.PtrReply = (uint64_t)(uintptr_t)reply;
677         pass.PtrData = (uint64_t)(uintptr_t)data_in;
678         pass.PtrDataOut = (uint64_t)(uintptr_t)data_out;
679         pass.RequestSize = req_len;
680         pass.ReplySize = reply_len;
681         pass.DataSize = datain_len;
682         pass.DataOutSize = dataout_len;
683         if (datain_len && dataout_len) {
684                 if (is_mps) {
685                         pass.DataDirection = MPS_PASS_THRU_DIRECTION_BOTH;
686                 } else {
687                         pass.DataDirection = MPR_PASS_THRU_DIRECTION_BOTH;
688                 }
689         } else if (datain_len) {
690                 if (is_mps) {
691                         pass.DataDirection = MPS_PASS_THRU_DIRECTION_READ;
692                 } else {
693                         pass.DataDirection = MPR_PASS_THRU_DIRECTION_READ;
694                 }
695         } else if (dataout_len) {
696                 if (is_mps) {
697                         pass.DataDirection = MPS_PASS_THRU_DIRECTION_WRITE;
698                 } else {
699                         pass.DataDirection = MPR_PASS_THRU_DIRECTION_WRITE;
700                 }
701         } else {
702                 if (is_mps) {
703                         pass.DataDirection = MPS_PASS_THRU_DIRECTION_NONE;
704                 } else {
705                         pass.DataDirection = MPR_PASS_THRU_DIRECTION_NONE;
706                 }
707         }
708         pass.Timeout = timeout;
709
710         if (ioctl(fd, MPTIOCTL_PASS_THRU, &pass) < 0)
711                 return (errno);
712         return (0);
713 }
714
715 MPI2_IOC_FACTS_REPLY *
716 mps_get_iocfacts(int fd)
717 {
718         MPI2_IOC_FACTS_REPLY *facts;
719         MPI2_IOC_FACTS_REQUEST req;
720         int error;
721
722         facts = malloc(sizeof(MPI2_IOC_FACTS_REPLY));
723         if (facts == NULL) {
724                 errno = ENOMEM;
725                 return (NULL);
726         }
727
728         bzero(&req, sizeof(MPI2_IOC_FACTS_REQUEST));
729         req.Function = MPI2_FUNCTION_IOC_FACTS;
730
731 #if 1
732         error = mps_pass_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
733             facts, sizeof(MPI2_IOC_FACTS_REPLY), NULL, 0, NULL, 0, 10);
734 #else
735         error = mps_user_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
736             facts, sizeof(MPI2_IOC_FACTS_REPLY), NULL, 0, 0);
737 #endif
738         if (error) {
739                 free(facts);
740                 return (NULL);
741         }
742
743         if (!IOC_STATUS_SUCCESS(facts->IOCStatus)) {
744                 free(facts);
745                 errno = EINVAL;
746                 return (NULL);
747         }
748         return (facts);
749 }
750