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 758