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