1 /*-
2 * Copyright (c) 2015 Baptiste Daroussin <[email protected]>
3 *
4 * Copyright (c) 2015 Netflix, Inc.
5 * Written by: Scott Long <[email protected]>
6 *
7 * Copyright (c) 2008 Yahoo!, Inc.
8 * All rights reserved.
9 * Written by: John Baldwin <[email protected]>
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 *
mps_ioc_status(U16 IOCStatus)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
mps_map_btdh(int fd,uint16_t * devhandle,uint16_t * bus,uint16_t * target)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
mps_read_config_page_header(int fd,U8 PageType,U8 PageNumber,U32 PageAddress,MPI2_CONFIG_PAGE_HEADER * header,U16 * IOCStatus)286 mps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
287 MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
288 {
289 MPI2_CONFIG_REQUEST req;
290 MPI2_CONFIG_REPLY reply;
291
292 bzero(&req, sizeof(req));
293 req.Function = MPI2_FUNCTION_CONFIG;
294 req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
295 req.Header.PageType = PageType;
296 req.Header.PageNumber = PageNumber;
297 req.PageAddress = PageAddress;
298
299 if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
300 NULL, 0, NULL, 0, 30))
301 return (errno);
302
303 if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
304 if (IOCStatus != NULL)
305 *IOCStatus = reply.IOCStatus;
306 return (EIO);
307 }
308 if (header == NULL)
309 return (EINVAL);
310 *header = reply.Header;
311 return (0);
312 }
313
314 int
mps_read_ext_config_page_header(int fd,U8 ExtPageType,U8 PageNumber,U32 PageAddress,MPI2_CONFIG_PAGE_HEADER * header,U16 * ExtPageLength,U16 * IOCStatus)315 mps_read_ext_config_page_header(int fd, U8 ExtPageType, U8 PageNumber, U32 PageAddress, MPI2_CONFIG_PAGE_HEADER *header, U16 *ExtPageLength, U16 *IOCStatus)
316 {
317 MPI2_CONFIG_REQUEST req;
318 MPI2_CONFIG_REPLY reply;
319
320 bzero(&req, sizeof(req));
321 req.Function = MPI2_FUNCTION_CONFIG;
322 req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
323 req.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
324 req.ExtPageType = ExtPageType;
325 req.Header.PageNumber = PageNumber;
326 req.PageAddress = PageAddress;
327
328 if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
329 NULL, 0, NULL, 0, 30))
330 return (errno);
331
332 if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
333 if (IOCStatus != NULL)
334 *IOCStatus = reply.IOCStatus;
335 return (EIO);
336 }
337 if ((header == NULL) || (ExtPageLength == NULL))
338 return (EINVAL);
339 *header = reply.Header;
340 *ExtPageLength = reply.ExtPageLength;
341 return (0);
342 }
343
344 void *
mps_read_config_page(int fd,U8 PageType,U8 PageNumber,U32 PageAddress,U16 * IOCStatus)345 mps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
346 U16 *IOCStatus)
347 {
348 MPI2_CONFIG_REQUEST req;
349 MPI2_CONFIG_PAGE_HEADER header;
350 MPI2_CONFIG_REPLY reply;
351 void *buf;
352 int error, len;
353
354 bzero(&header, sizeof(header));
355 error = mps_read_config_page_header(fd, PageType, PageNumber,
356 PageAddress, &header, IOCStatus);
357 if (error) {
358 errno = error;
359 return (NULL);
360 }
361
362 bzero(&req, sizeof(req));
363 req.Function = MPI2_FUNCTION_CONFIG;
364 req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
365 req.PageAddress = PageAddress;
366 req.Header = header;
367 if (req.Header.PageLength == 0)
368 req.Header.PageLength = 4;
369
370 len = req.Header.PageLength * 4;
371 buf = malloc(len);
372 if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
373 buf, len, NULL, 0, 30)) {
374 error = errno;
375 free(buf);
376 errno = error;
377 return (NULL);
378 }
379 if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
380 if (IOCStatus != NULL)
381 *IOCStatus = reply.IOCStatus;
382 else
383 warnx("Reading config page failed: 0x%x %s",
384 reply.IOCStatus, mps_ioc_status(reply.IOCStatus));
385 free(buf);
386 errno = EIO;
387 return (NULL);
388 }
389 return (buf);
390 }
391
392 void *
mps_read_extended_config_page(int fd,U8 ExtPageType,U8 PageVersion,U8 PageNumber,U32 PageAddress,U16 * IOCStatus)393 mps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
394 U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
395 {
396 MPI2_CONFIG_REQUEST req;
397 MPI2_CONFIG_PAGE_HEADER header;
398 MPI2_CONFIG_REPLY reply;
399 U16 pagelen;
400 void *buf;
401 int error, len;
402
403 if (IOCStatus != NULL)
404 *IOCStatus = MPI2_IOCSTATUS_SUCCESS;
405 bzero(&header, sizeof(header));
406 error = mps_read_ext_config_page_header(fd, ExtPageType, PageNumber,
407 PageAddress, &header, &pagelen, IOCStatus);
408 if (error) {
409 errno = error;
410 return (NULL);
411 }
412
413 bzero(&req, sizeof(req));
414 req.Function = MPI2_FUNCTION_CONFIG;
415 req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
416 req.PageAddress = PageAddress;
417 req.Header = header;
418 if (pagelen == 0)
419 pagelen = 4;
420 req.ExtPageLength = pagelen;
421 req.ExtPageType = ExtPageType;
422
423 len = pagelen * 4;
424 buf = malloc(len);
425 if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
426 buf, len, NULL, 0, 30)) {
427 error = errno;
428 free(buf);
429 errno = error;
430 return (NULL);
431 }
432 if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
433 if (IOCStatus != NULL)
434 *IOCStatus = reply.IOCStatus;
435 else
436 warnx("Reading extended config page failed: %s",
437 mps_ioc_status(reply.IOCStatus));
438 free(buf);
439 errno = EIO;
440 return (NULL);
441 }
442 return (buf);
443 }
444
445 int
mps_firmware_send(int fd,unsigned char * fw,uint32_t len,bool bios)446 mps_firmware_send(int fd, unsigned char *fw, uint32_t len, bool bios)
447 {
448 MPI2_FW_DOWNLOAD_REQUEST req;
449 MPI2_FW_DOWNLOAD_REPLY reply;
450
451 bzero(&req, sizeof(req));
452 bzero(&reply, sizeof(reply));
453 req.Function = MPI2_FUNCTION_FW_DOWNLOAD;
454 req.ImageType = bios ? MPI2_FW_DOWNLOAD_ITYPE_BIOS : MPI2_FW_DOWNLOAD_ITYPE_FW;
455 req.TotalImageSize = len;
456 req.MsgFlags = MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT;
457
458 if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply),
459 fw, len, 0)) {
460 return (-1);
461 }
462 return (0);
463 }
464
465 int
mps_firmware_get(int fd,unsigned char ** firmware,bool bios)466 mps_firmware_get(int fd, unsigned char **firmware, bool bios)
467 {
468 MPI2_FW_UPLOAD_REQUEST req;
469 MPI2_FW_UPLOAD_REPLY reply;
470 int size;
471
472 *firmware = NULL;
473 bzero(&req, sizeof(req));
474 bzero(&reply, sizeof(reply));
475 req.Function = MPI2_FUNCTION_FW_UPLOAD;
476 req.ImageType = bios ? MPI2_FW_DOWNLOAD_ITYPE_BIOS : MPI2_FW_DOWNLOAD_ITYPE_FW;
477
478 if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply),
479 NULL, 0, 0)) {
480 return (-1);
481 }
482 if (reply.ActualImageSize == 0) {
483 return (-1);
484 }
485
486 size = reply.ActualImageSize;
487 *firmware = calloc(size, sizeof(unsigned char));
488 if (*firmware == NULL) {
489 warn("calloc");
490 return (-1);
491 }
492 if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply),
493 *firmware, size, 0)) {
494 free(*firmware);
495 return (-1);
496 }
497
498 return (size);
499 }
500
501 #else
502
503 int
mps_read_config_page_header(int fd,U8 PageType,U8 PageNumber,U32 PageAddress,MPI2_CONFIG_PAGE_HEADER * header,U16 * IOCStatus)504 mps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
505 MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
506 {
507 struct mps_cfg_page_req req;
508
509 if (IOCStatus != NULL)
510 *IOCStatus = MPI2_IOCSTATUS_SUCCESS;
511 if (header == NULL)
512 return (EINVAL);
513 bzero(&req, sizeof(req));
514 req.header.PageType = PageType;
515 req.header.PageNumber = PageNumber;
516 req.page_address = PageAddress;
517 if (ioctl(fd, MPSIO_READ_CFG_HEADER, &req) < 0)
518 return (errno);
519 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
520 if (IOCStatus != NULL)
521 *IOCStatus = req.ioc_status;
522 return (EIO);
523 }
524 bcopy(&req.header, header, sizeof(*header));
525 return (0);
526 }
527
528 void *
mps_read_config_page(int fd,U8 PageType,U8 PageNumber,U32 PageAddress,U16 * IOCStatus)529 mps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
530 U16 *IOCStatus)
531 {
532 struct mps_cfg_page_req req;
533 void *buf;
534 int error;
535
536 error = mps_read_config_page_header(fd, PageType, PageNumber,
537 PageAddress, &req.header, IOCStatus);
538 if (error) {
539 errno = error;
540 return (NULL);
541 }
542
543 if (req.header.PageLength == 0)
544 req.header.PageLength = 4;
545 req.len = req.header.PageLength * 4;
546 buf = malloc(req.len);
547 req.buf = buf;
548 bcopy(&req.header, buf, sizeof(req.header));
549 if (ioctl(fd, MPSIO_READ_CFG_PAGE, &req) < 0) {
550 error = errno;
551 free(buf);
552 errno = error;
553 return (NULL);
554 }
555 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
556 if (IOCStatus != NULL)
557 *IOCStatus = req.ioc_status;
558 else
559 warnx("Reading config page failed: 0x%x %s",
560 req.ioc_status, mps_ioc_status(req.ioc_status));
561 free(buf);
562 errno = EIO;
563 return (NULL);
564 }
565 return (buf);
566 }
567
568 void *
mps_read_extended_config_page(int fd,U8 ExtPageType,U8 PageVersion,U8 PageNumber,U32 PageAddress,U16 * IOCStatus)569 mps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
570 U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
571 {
572 struct mps_ext_cfg_page_req req;
573 void *buf;
574 int error;
575
576 if (IOCStatus != NULL)
577 *IOCStatus = MPI2_IOCSTATUS_SUCCESS;
578 bzero(&req, sizeof(req));
579 req.header.PageVersion = PageVersion;
580 req.header.PageNumber = PageNumber;
581 req.header.ExtPageType = ExtPageType;
582 req.page_address = PageAddress;
583 if (ioctl(fd, MPSIO_READ_EXT_CFG_HEADER, &req) < 0)
584 return (NULL);
585 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
586 if (IOCStatus != NULL)
587 *IOCStatus = req.ioc_status;
588 else
589 warnx("Reading extended config page header failed: %s",
590 mps_ioc_status(req.ioc_status));
591 errno = EIO;
592 return (NULL);
593 }
594 req.len = req.header.ExtPageLength * 4;
595 buf = malloc(req.len);
596 req.buf = buf;
597 bcopy(&req.header, buf, sizeof(req.header));
598 if (ioctl(fd, MPSIO_READ_EXT_CFG_PAGE, &req) < 0) {
599 error = errno;
600 free(buf);
601 errno = error;
602 return (NULL);
603 }
604 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
605 if (IOCStatus != NULL)
606 *IOCStatus = req.ioc_status;
607 else
608 warnx("Reading extended config page failed: %s",
609 mps_ioc_status(req.ioc_status));
610 free(buf);
611 errno = EIO;
612 return (NULL);
613 }
614 return (buf);
615 }
616 #endif
617
618 int
mps_open(int unit)619 mps_open(int unit)
620 {
621 char path[MAXPATHLEN];
622
623 snprintf(path, sizeof(path), "/dev/mp%s%d", is_mps ? "s": "r", unit);
624 return (open(path, O_RDWR));
625 }
626
627 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)628 mps_user_command(int fd, void *req, uint32_t req_len, void *reply,
629 uint32_t reply_len, void *buffer, int len, uint32_t flags)
630 {
631 struct mps_usr_command cmd;
632
633 bzero(&cmd, sizeof(struct mps_usr_command));
634 cmd.req = req;
635 cmd.req_len = req_len;
636 cmd.rpl = reply;
637 cmd.rpl_len = reply_len;
638 cmd.buf = buffer;
639 cmd.len = len;
640 cmd.flags = flags;
641
642 if (ioctl(fd, is_mps ? MPSIO_MPS_COMMAND : MPRIO_MPR_COMMAND, &cmd) < 0)
643 return (errno);
644 return (0);
645 }
646
647 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)648 mps_pass_command(int fd, void *req, uint32_t req_len, void *reply,
649 uint32_t reply_len, void *data_in, uint32_t datain_len, void *data_out,
650 uint32_t dataout_len, uint32_t timeout)
651 {
652 struct mprs_pass_thru pass;
653
654 bzero(&pass, sizeof(pass));
655 pass.PtrRequest = (uint64_t)(uintptr_t)req;
656 pass.PtrReply = (uint64_t)(uintptr_t)reply;
657 pass.RequestSize = req_len;
658 pass.ReplySize = reply_len;
659 if (datain_len && dataout_len) {
660 pass.PtrData = (uint64_t)(uintptr_t)data_in;
661 pass.PtrDataOut = (uint64_t)(uintptr_t)data_out;
662 pass.DataSize = datain_len;
663 pass.DataOutSize = dataout_len;
664 if (is_mps) {
665 pass.DataDirection = MPS_PASS_THRU_DIRECTION_BOTH;
666 } else {
667 pass.DataDirection = MPR_PASS_THRU_DIRECTION_BOTH;
668 }
669 } else if (datain_len) {
670 pass.PtrData = (uint64_t)(uintptr_t)data_in;
671 pass.DataSize = datain_len;
672 if (is_mps) {
673 pass.DataDirection = MPS_PASS_THRU_DIRECTION_READ;
674 } else {
675 pass.DataDirection = MPR_PASS_THRU_DIRECTION_READ;
676 }
677 } else if (dataout_len) {
678 pass.PtrData = (uint64_t)(uintptr_t)data_out;
679 pass.DataSize = dataout_len;
680 if (is_mps) {
681 pass.DataDirection = MPS_PASS_THRU_DIRECTION_WRITE;
682 } else {
683 pass.DataDirection = MPR_PASS_THRU_DIRECTION_WRITE;
684 }
685 } else {
686 if (is_mps) {
687 pass.DataDirection = MPS_PASS_THRU_DIRECTION_NONE;
688 } else {
689 pass.DataDirection = MPR_PASS_THRU_DIRECTION_NONE;
690 }
691 }
692 pass.Timeout = timeout;
693
694 if (ioctl(fd, MPTIOCTL_PASS_THRU, &pass) < 0)
695 return (errno);
696 return (0);
697 }
698
699 MPI2_IOC_FACTS_REPLY *
mps_get_iocfacts(int fd)700 mps_get_iocfacts(int fd)
701 {
702 MPI2_IOC_FACTS_REPLY *facts;
703 MPI2_IOC_FACTS_REQUEST req;
704 int error;
705
706 facts = malloc(sizeof(MPI2_IOC_FACTS_REPLY));
707 if (facts == NULL) {
708 errno = ENOMEM;
709 return (NULL);
710 }
711
712 bzero(&req, sizeof(MPI2_IOC_FACTS_REQUEST));
713 req.Function = MPI2_FUNCTION_IOC_FACTS;
714
715 #if 1
716 error = mps_pass_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
717 facts, sizeof(MPI2_IOC_FACTS_REPLY), NULL, 0, NULL, 0, 10);
718 #else
719 error = mps_user_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
720 facts, sizeof(MPI2_IOC_FACTS_REPLY), NULL, 0, 0);
721 #endif
722 if (error) {
723 free(facts);
724 return (NULL);
725 }
726
727 if (!IOC_STATUS_SUCCESS(facts->IOCStatus)) {
728 free(facts);
729 errno = EINVAL;
730 return (NULL);
731 }
732 return (facts);
733 }
734
735