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 #include <sys/param.h> 38 #include <sys/errno.h> 39 #include <sys/ioctl.h> 40 #include <sys/sysctl.h> 41 #include <sys/uio.h> 42 #include <sys/endian.h> 43 44 #include <err.h> 45 #include <fcntl.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <string.h> 49 #include <unistd.h> 50 51 #include "mpsutil.h" 52 #include <dev/mps/mps_ioctl.h> 53 #include <dev/mpr/mpr_ioctl.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 static void adjust_iocfacts_endianness(MPI2_IOC_FACTS_REPLY *facts); 244 245 const char * 246 mps_ioc_status(U16 IOCStatus) 247 { 248 static char buffer[16]; 249 250 IOCStatus &= MPI2_IOCSTATUS_MASK; 251 if (IOCStatus < sizeof(mps_ioc_status_codes) / sizeof(char *) && 252 mps_ioc_status_codes[IOCStatus] != NULL) 253 return (mps_ioc_status_codes[IOCStatus]); 254 snprintf(buffer, sizeof(buffer), "Status: 0x%04x", IOCStatus); 255 return (buffer); 256 } 257 258 #ifdef USE_MPT_IOCTLS 259 int 260 mps_map_btdh(int fd, uint16_t *devhandle, uint16_t *bus, uint16_t *target) 261 { 262 int error; 263 struct mprs_btdh_mapping map; 264 265 map.Bus = *bus; 266 map.TargetID = *target; 267 map.DevHandle = *devhandle; 268 269 if ((error = ioctl(fd, MPTIOCTL_BTDH_MAPPING, &map)) != 0) { 270 error = errno; 271 warn("Failed to map bus/target/device"); 272 return (error); 273 } 274 275 *bus = map.Bus; 276 *target = map.TargetID; 277 *devhandle = map.DevHandle; 278 279 return (0); 280 } 281 282 int 283 mps_set_slot_status(int fd, U16 handle, U16 slot, U32 status) 284 { 285 MPI2_SEP_REQUEST req; 286 MPI2_SEP_REPLY reply; 287 288 bzero(&req, sizeof(req)); 289 req.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR; 290 req.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS; 291 req.Flags = MPI2_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS; 292 req.EnclosureHandle = handle; 293 req.Slot = slot; 294 req.SlotStatus = status; 295 296 if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply), 297 NULL, 0, NULL, 0, 30) != 0) 298 return (errno); 299 300 if (!IOC_STATUS_SUCCESS(le16toh(reply.IOCStatus))) 301 return (EIO); 302 return (0); 303 } 304 305 int 306 mps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress, 307 MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus) 308 { 309 MPI2_CONFIG_REQUEST req; 310 MPI2_CONFIG_REPLY reply; 311 312 bzero(&req, sizeof(req)); 313 req.Function = MPI2_FUNCTION_CONFIG; 314 req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; 315 req.Header.PageType = PageType; 316 req.Header.PageNumber = PageNumber; 317 req.PageAddress = PageAddress; 318 319 if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply), 320 NULL, 0, NULL, 0, 30)) 321 return (errno); 322 323 if (!IOC_STATUS_SUCCESS(le16toh(reply.IOCStatus))) { 324 if (IOCStatus != NULL) 325 *IOCStatus = reply.IOCStatus; 326 return (EIO); 327 } 328 if (header == NULL) 329 return (EINVAL); 330 *header = reply.Header; 331 return (0); 332 } 333 334 int 335 mps_read_ext_config_page_header(int fd, U8 ExtPageType, U8 PageNumber, U32 PageAddress, MPI2_CONFIG_PAGE_HEADER *header, U16 *ExtPageLength, U16 *IOCStatus) 336 { 337 MPI2_CONFIG_REQUEST req; 338 MPI2_CONFIG_REPLY reply; 339 340 bzero(&req, sizeof(req)); 341 req.Function = MPI2_FUNCTION_CONFIG; 342 req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; 343 req.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; 344 req.ExtPageType = ExtPageType; 345 req.Header.PageNumber = PageNumber; 346 req.PageAddress = htole32(PageAddress); 347 348 if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply), 349 NULL, 0, NULL, 0, 30)) 350 return (errno); 351 352 if (!IOC_STATUS_SUCCESS(le16toh(reply.IOCStatus))) { 353 if (IOCStatus != NULL) 354 *IOCStatus = le16toh(reply.IOCStatus); 355 return (EIO); 356 } 357 if ((header == NULL) || (ExtPageLength == NULL)) 358 return (EINVAL); 359 *header = reply.Header; 360 *ExtPageLength = reply.ExtPageLength; 361 return (0); 362 } 363 364 void * 365 mps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress, 366 U16 *IOCStatus) 367 { 368 MPI2_CONFIG_REQUEST req; 369 MPI2_CONFIG_PAGE_HEADER header; 370 MPI2_CONFIG_REPLY reply; 371 void *buf; 372 int error, len; 373 374 bzero(&header, sizeof(header)); 375 error = mps_read_config_page_header(fd, PageType, PageNumber, 376 PageAddress, &header, IOCStatus); 377 if (error) { 378 errno = error; 379 return (NULL); 380 } 381 382 bzero(&req, sizeof(req)); 383 req.Function = MPI2_FUNCTION_CONFIG; 384 req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; 385 req.PageAddress = htole32(PageAddress); 386 req.Header = header; 387 if (req.Header.PageLength == 0) 388 req.Header.PageLength = 4; 389 390 len = req.Header.PageLength * 4; 391 buf = malloc(len); 392 if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply), 393 buf, len, NULL, 0, 30)) { 394 error = errno; 395 free(buf); 396 errno = error; 397 return (NULL); 398 } 399 reply.IOCStatus = le16toh(reply.IOCStatus); 400 if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) { 401 if (IOCStatus != NULL) 402 *IOCStatus = reply.IOCStatus; 403 else 404 warnx("Reading config page failed: 0x%x %s", 405 reply.IOCStatus, mps_ioc_status(reply.IOCStatus)); 406 free(buf); 407 errno = EIO; 408 return (NULL); 409 } 410 return (buf); 411 } 412 413 void * 414 mps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion, 415 U8 PageNumber, U32 PageAddress, U16 *IOCStatus) 416 { 417 MPI2_CONFIG_REQUEST req; 418 MPI2_CONFIG_PAGE_HEADER header; 419 MPI2_CONFIG_REPLY reply; 420 U16 pagelen; 421 void *buf; 422 int error, len; 423 424 if (IOCStatus != NULL) 425 *IOCStatus = MPI2_IOCSTATUS_SUCCESS; 426 bzero(&header, sizeof(header)); 427 error = mps_read_ext_config_page_header(fd, ExtPageType, PageNumber, 428 PageAddress, &header, &pagelen, IOCStatus); 429 if (error) { 430 errno = error; 431 return (NULL); 432 } 433 434 bzero(&req, sizeof(req)); 435 req.Function = MPI2_FUNCTION_CONFIG; 436 req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; 437 req.PageAddress = htole32(PageAddress); 438 req.Header = header; 439 if (pagelen == 0) 440 pagelen = htole16(4); 441 req.ExtPageLength = pagelen; 442 req.ExtPageType = ExtPageType; 443 444 len = le16toh(pagelen) * 4; 445 buf = malloc(len); 446 if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply), 447 buf, len, NULL, 0, 30)) { 448 error = errno; 449 free(buf); 450 errno = error; 451 return (NULL); 452 } 453 reply.IOCStatus = le16toh(reply.IOCStatus); 454 if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) { 455 if (IOCStatus != NULL) 456 *IOCStatus = reply.IOCStatus; 457 else 458 warnx("Reading extended config page failed: %s", 459 mps_ioc_status(reply.IOCStatus)); 460 free(buf); 461 errno = EIO; 462 return (NULL); 463 } 464 return (buf); 465 } 466 467 int 468 mps_firmware_send(int fd, unsigned char *fw, uint32_t len, bool bios) 469 { 470 MPI2_FW_DOWNLOAD_REQUEST req; 471 MPI2_FW_DOWNLOAD_REPLY reply; 472 473 bzero(&req, sizeof(req)); 474 bzero(&reply, sizeof(reply)); 475 req.Function = MPI2_FUNCTION_FW_DOWNLOAD; 476 req.ImageType = bios ? MPI2_FW_DOWNLOAD_ITYPE_BIOS : MPI2_FW_DOWNLOAD_ITYPE_FW; 477 req.TotalImageSize = htole32(len); 478 req.MsgFlags = MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT; 479 480 if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply), 481 fw, len, 0)) { 482 return (-1); 483 } 484 return (0); 485 } 486 487 int 488 mps_firmware_get(int fd, unsigned char **firmware, bool bios) 489 { 490 MPI2_FW_UPLOAD_REQUEST req; 491 MPI2_FW_UPLOAD_REPLY reply; 492 int size; 493 494 *firmware = NULL; 495 bzero(&req, sizeof(req)); 496 bzero(&reply, sizeof(reply)); 497 req.Function = MPI2_FUNCTION_FW_UPLOAD; 498 req.ImageType = bios ? MPI2_FW_DOWNLOAD_ITYPE_BIOS : MPI2_FW_DOWNLOAD_ITYPE_FW; 499 500 if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply), 501 NULL, 0, 0)) { 502 return (-1); 503 } 504 if (reply.ActualImageSize == 0) { 505 return (-1); 506 } 507 508 size = le32toh(reply.ActualImageSize); 509 *firmware = calloc(size, sizeof(unsigned char)); 510 if (*firmware == NULL) { 511 warn("calloc"); 512 return (-1); 513 } 514 if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply), 515 *firmware, size, 0)) { 516 free(*firmware); 517 return (-1); 518 } 519 520 return (size); 521 } 522 523 #else 524 525 int 526 mps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress, 527 MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus) 528 { 529 struct mps_cfg_page_req req; 530 531 if (IOCStatus != NULL) 532 *IOCStatus = MPI2_IOCSTATUS_SUCCESS; 533 if (header == NULL) 534 return (EINVAL); 535 bzero(&req, sizeof(req)); 536 req.header.PageType = PageType; 537 req.header.PageNumber = PageNumber; 538 req.page_address = PageAddress; 539 if (ioctl(fd, MPSIO_READ_CFG_HEADER, &req) < 0) 540 return (errno); 541 if (!IOC_STATUS_SUCCESS(req.ioc_status)) { 542 if (IOCStatus != NULL) 543 *IOCStatus = req.ioc_status; 544 return (EIO); 545 } 546 bcopy(&req.header, header, sizeof(*header)); 547 return (0); 548 } 549 550 void * 551 mps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress, 552 U16 *IOCStatus) 553 { 554 struct mps_cfg_page_req req; 555 void *buf; 556 int error; 557 558 error = mps_read_config_page_header(fd, PageType, PageNumber, 559 PageAddress, &req.header, IOCStatus); 560 if (error) { 561 errno = error; 562 return (NULL); 563 } 564 565 if (req.header.PageLength == 0) 566 req.header.PageLength = 4; 567 req.len = req.header.PageLength * 4; 568 buf = malloc(req.len); 569 req.buf = buf; 570 bcopy(&req.header, buf, sizeof(req.header)); 571 if (ioctl(fd, MPSIO_READ_CFG_PAGE, &req) < 0) { 572 error = errno; 573 free(buf); 574 errno = error; 575 return (NULL); 576 } 577 req.ioc_status = le16toh(req.ioc_status); 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 = htole32(PageAddress); 606 if (ioctl(fd, MPSIO_READ_EXT_CFG_HEADER, &req) < 0) 607 return (NULL); 608 req.ioc_status = le16toh(req.ioc_status); 609 if (!IOC_STATUS_SUCCESS(req.ioc_status)) { 610 if (IOCStatus != NULL) 611 *IOCStatus = req.ioc_status; 612 else 613 warnx("Reading extended config page header failed: %s", 614 mps_ioc_status(req.ioc_status)); 615 errno = EIO; 616 return (NULL); 617 } 618 req.len = req.header.ExtPageLength * 4; 619 buf = malloc(req.len); 620 req.buf = buf; 621 bcopy(&req.header, buf, sizeof(req.header)); 622 if (ioctl(fd, MPSIO_READ_EXT_CFG_PAGE, &req) < 0) { 623 error = errno; 624 free(buf); 625 errno = error; 626 return (NULL); 627 } 628 req.ioc_status = le16toh(req.ioc_status); 629 if (!IOC_STATUS_SUCCESS(req.ioc_status)) { 630 if (IOCStatus != NULL) 631 *IOCStatus = req.ioc_status; 632 else 633 warnx("Reading extended config page failed: %s", 634 mps_ioc_status(req.ioc_status)); 635 free(buf); 636 errno = EIO; 637 return (NULL); 638 } 639 return (buf); 640 } 641 #endif 642 643 int 644 mps_open(int unit) 645 { 646 char path[MAXPATHLEN]; 647 648 snprintf(path, sizeof(path), "/dev/mp%s%d", is_mps ? "s": "r", unit); 649 return (open(path, O_RDWR)); 650 } 651 652 int 653 mps_user_command(int fd, void *req, uint32_t req_len, void *reply, 654 uint32_t reply_len, void *buffer, int len, uint32_t flags) 655 { 656 struct mps_usr_command cmd; 657 658 bzero(&cmd, sizeof(struct mps_usr_command)); 659 cmd.req = req; 660 cmd.req_len = req_len; 661 cmd.rpl = reply; 662 cmd.rpl_len = reply_len; 663 cmd.buf = buffer; 664 cmd.len = len; 665 cmd.flags = flags; 666 667 if (ioctl(fd, is_mps ? MPSIO_MPS_COMMAND : MPRIO_MPR_COMMAND, &cmd) < 0) 668 return (errno); 669 return (0); 670 } 671 672 int 673 mps_pass_command(int fd, void *req, uint32_t req_len, void *reply, 674 uint32_t reply_len, void *data_in, uint32_t datain_len, void *data_out, 675 uint32_t dataout_len, uint32_t timeout) 676 { 677 struct mprs_pass_thru pass; 678 679 bzero(&pass, sizeof(pass)); 680 pass.PtrRequest = (uint64_t)(uintptr_t)req; 681 pass.PtrReply = (uint64_t)(uintptr_t)reply; 682 pass.RequestSize = req_len; 683 pass.ReplySize = reply_len; 684 if (datain_len && dataout_len) { 685 pass.PtrData = (uint64_t)(uintptr_t)data_in; 686 pass.PtrDataOut = (uint64_t)(uintptr_t)data_out; 687 pass.DataSize = datain_len; 688 pass.DataOutSize = dataout_len; 689 if (is_mps) { 690 pass.DataDirection = MPS_PASS_THRU_DIRECTION_BOTH; 691 } else { 692 pass.DataDirection = MPR_PASS_THRU_DIRECTION_BOTH; 693 } 694 } else if (datain_len) { 695 pass.PtrData = (uint64_t)(uintptr_t)data_in; 696 pass.DataSize = datain_len; 697 if (is_mps) { 698 pass.DataDirection = MPS_PASS_THRU_DIRECTION_READ; 699 } else { 700 pass.DataDirection = MPR_PASS_THRU_DIRECTION_READ; 701 } 702 } else if (dataout_len) { 703 pass.PtrData = (uint64_t)(uintptr_t)data_out; 704 pass.DataSize = dataout_len; 705 if (is_mps) { 706 pass.DataDirection = MPS_PASS_THRU_DIRECTION_WRITE; 707 } else { 708 pass.DataDirection = MPR_PASS_THRU_DIRECTION_WRITE; 709 } 710 } else { 711 if (is_mps) { 712 pass.DataDirection = MPS_PASS_THRU_DIRECTION_NONE; 713 } else { 714 pass.DataDirection = MPR_PASS_THRU_DIRECTION_NONE; 715 } 716 } 717 pass.Timeout = timeout; 718 719 if (ioctl(fd, MPTIOCTL_PASS_THRU, &pass) < 0) 720 return (errno); 721 return (0); 722 } 723 724 MPI2_IOC_FACTS_REPLY * 725 mps_get_iocfacts(int fd) 726 { 727 MPI2_IOC_FACTS_REPLY *facts; 728 MPI2_IOC_FACTS_REQUEST req; 729 char msgver[8], sysctlname[128]; 730 size_t len, factslen; 731 int error; 732 733 snprintf(sysctlname, sizeof(sysctlname), "dev.%s.%d.msg_version", 734 is_mps ? "mps" : "mpr", mps_unit); 735 736 factslen = sizeof(MPI2_IOC_FACTS_REPLY); 737 len = sizeof(msgver); 738 error = sysctlbyname(sysctlname, msgver, &len, NULL, 0); 739 if (error == 0) { 740 if (strncmp(msgver, "2.6", sizeof(msgver)) == 0) 741 factslen += 4; 742 } 743 744 facts = malloc(factslen); 745 if (facts == NULL) { 746 errno = ENOMEM; 747 return (NULL); 748 } 749 750 bzero(&req, factslen); 751 req.Function = MPI2_FUNCTION_IOC_FACTS; 752 753 #if 1 754 error = mps_pass_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST), 755 facts, factslen, NULL, 0, NULL, 0, 10); 756 #else 757 error = mps_user_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST), 758 facts, factslen, NULL, 0, 0); 759 #endif 760 if (error) { 761 free(facts); 762 return (NULL); 763 } 764 765 if (!IOC_STATUS_SUCCESS(facts->IOCStatus)) { 766 free(facts); 767 errno = EINVAL; 768 return (NULL); 769 } 770 adjust_iocfacts_endianness(facts); 771 return (facts); 772 } 773 774 static void 775 adjust_iocfacts_endianness(MPI2_IOC_FACTS_REPLY *facts) 776 { 777 facts->MsgVersion = le16toh(facts->MsgVersion); 778 facts->HeaderVersion = le16toh(facts->HeaderVersion); 779 facts->Reserved1 = le16toh(facts->Reserved1); 780 facts->IOCExceptions = le16toh(facts->IOCExceptions); 781 facts->IOCStatus = le16toh(facts->IOCStatus); 782 facts->IOCLogInfo = le32toh(facts->IOCLogInfo); 783 facts->RequestCredit = le16toh(facts->RequestCredit); 784 facts->ProductID = le16toh(facts->ProductID); 785 facts->IOCCapabilities = le32toh(facts->IOCCapabilities); 786 facts->IOCRequestFrameSize = 787 le16toh(facts->IOCRequestFrameSize); 788 facts->FWVersion.Word = le32toh(facts->FWVersion.Word); 789 facts->MaxInitiators = le16toh(facts->MaxInitiators); 790 facts->MaxTargets = le16toh(facts->MaxTargets); 791 facts->MaxSasExpanders = le16toh(facts->MaxSasExpanders); 792 facts->MaxEnclosures = le16toh(facts->MaxEnclosures); 793 facts->ProtocolFlags = le16toh(facts->ProtocolFlags); 794 facts->HighPriorityCredit = le16toh(facts->HighPriorityCredit); 795 facts->MaxReplyDescriptorPostQueueDepth = 796 le16toh(facts->MaxReplyDescriptorPostQueueDepth); 797 facts->MaxDevHandle = le16toh(facts->MaxDevHandle); 798 facts->MaxPersistentEntries = 799 le16toh(facts->MaxPersistentEntries); 800 facts->MinDevHandle = le16toh(facts->MinDevHandle); 801 } 802