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