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