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/param.h> 37 #include <sys/errno.h> 38 #include <sys/ioctl.h> 39 #include <sys/sysctl.h> 40 #include <sys/uio.h> 41 #include <sys/endian.h> 42 43 #include <err.h> 44 #include <fcntl.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <unistd.h> 49 50 #include "mpsutil.h" 51 #include <dev/mps/mps_ioctl.h> 52 #include <dev/mpr/mpr_ioctl.h> 53 54 #ifndef USE_MPT_IOCTLS 55 #define USE_MPT_IOCTLS 56 #endif 57 58 static const char *mps_ioc_status_codes[] = { 59 "Success", /* 0x0000 */ 60 "Invalid function", 61 "Busy", 62 "Invalid scatter-gather list", 63 "Internal error", 64 "Reserved", 65 "Insufficient resources", 66 "Invalid field", 67 "Invalid state", /* 0x0008 */ 68 "Operation state not supported", 69 NULL, 70 NULL, 71 NULL, 72 NULL, 73 NULL, 74 NULL, 75 NULL, /* 0x0010 */ 76 NULL, 77 NULL, 78 NULL, 79 NULL, 80 NULL, 81 NULL, 82 NULL, 83 NULL, /* 0x0018 */ 84 NULL, 85 NULL, 86 NULL, 87 NULL, 88 NULL, 89 NULL, 90 NULL, 91 "Invalid configuration action", /* 0x0020 */ 92 "Invalid configuration type", 93 "Invalid configuration page", 94 "Invalid configuration data", 95 "No configuration defaults", 96 "Unable to commit configuration change", 97 NULL, 98 NULL, 99 NULL, /* 0x0028 */ 100 NULL, 101 NULL, 102 NULL, 103 NULL, 104 NULL, 105 NULL, 106 NULL, 107 NULL, /* 0x0030 */ 108 NULL, 109 NULL, 110 NULL, 111 NULL, 112 NULL, 113 NULL, 114 NULL, 115 NULL, /* 0x0038 */ 116 NULL, 117 NULL, 118 NULL, 119 NULL, 120 NULL, 121 NULL, 122 NULL, 123 "Recovered SCSI error", /* 0x0040 */ 124 "Invalid SCSI bus", 125 "Invalid SCSI target ID", 126 "SCSI device not there", 127 "SCSI data overrun", 128 "SCSI data underrun", 129 "SCSI I/O error", 130 "SCSI protocol error", 131 "SCSI task terminated", /* 0x0048 */ 132 "SCSI residual mismatch", 133 "SCSI task management failed", 134 "SCSI I/O controller terminated", 135 "SCSI external controller terminated", 136 "EEDP guard error", 137 "EEDP reference tag error", 138 "EEDP application tag error", 139 NULL, /* 0x0050 */ 140 NULL, 141 NULL, 142 NULL, 143 NULL, 144 NULL, 145 NULL, 146 NULL, 147 NULL, /* 0x0058 */ 148 NULL, 149 NULL, 150 NULL, 151 NULL, 152 NULL, 153 NULL, 154 NULL, 155 "SCSI target priority I/O", /* 0x0060 */ 156 "Invalid SCSI target port", 157 "Invalid SCSI target I/O index", 158 "SCSI target aborted", 159 "No connection retryable", 160 "No connection", 161 "FC aborted", 162 "Invalid FC receive ID", 163 "FC did invalid", /* 0x0068 */ 164 "FC node logged out", 165 "Transfer count mismatch", 166 "STS data not set", 167 "FC exchange canceled", 168 "Data offset error", 169 "Too much write data", 170 "IU too short", 171 "ACK NAK timeout", /* 0x0070 */ 172 "NAK received", 173 NULL, 174 NULL, 175 NULL, 176 NULL, 177 NULL, 178 NULL, 179 NULL, /* 0x0078 */ 180 NULL, 181 NULL, 182 NULL, 183 NULL, 184 NULL, 185 NULL, 186 NULL, 187 "LAN device not found", /* 0x0080 */ 188 "LAN device failure", 189 "LAN transmit error", 190 "LAN transmit aborted", 191 "LAN receive error", 192 "LAN receive aborted", 193 "LAN partial packet", 194 "LAN canceled", 195 NULL, /* 0x0088 */ 196 NULL, 197 NULL, 198 NULL, 199 NULL, 200 NULL, 201 NULL, 202 NULL, 203 "SAS SMP request failed", /* 0x0090 */ 204 "SAS SMP data overrun", 205 NULL, 206 NULL, 207 NULL, 208 NULL, 209 NULL, 210 NULL, 211 "Inband aborted", /* 0x0098 */ 212 "No inband connection", 213 NULL, 214 NULL, 215 NULL, 216 NULL, 217 NULL, 218 NULL, 219 "Diagnostic released", /* 0x00A0 */ 220 }; 221 222 struct mprs_pass_thru { 223 uint64_t PtrRequest; 224 uint64_t PtrReply; 225 uint64_t PtrData; 226 uint32_t RequestSize; 227 uint32_t ReplySize; 228 uint32_t DataSize; 229 uint32_t DataDirection; 230 uint64_t PtrDataOut; 231 uint32_t DataOutSize; 232 uint32_t Timeout; 233 }; 234 235 struct mprs_btdh_mapping { 236 uint16_t TargetID; 237 uint16_t Bus; 238 uint16_t DevHandle; 239 uint16_t Reserved; 240 }; 241 242 static void adjust_iocfacts_endianness(MPI2_IOC_FACTS_REPLY *facts); 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(le16toh(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(le16toh(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 = htole32(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(le16toh(reply.IOCStatus))) { 352 if (IOCStatus != NULL) 353 *IOCStatus = le16toh(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 = htole32(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 reply.IOCStatus = le16toh(reply.IOCStatus); 399 if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) { 400 if (IOCStatus != NULL) 401 *IOCStatus = reply.IOCStatus; 402 else 403 warnx("Reading config page failed: 0x%x %s", 404 reply.IOCStatus, mps_ioc_status(reply.IOCStatus)); 405 free(buf); 406 errno = EIO; 407 return (NULL); 408 } 409 return (buf); 410 } 411 412 void * 413 mps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion, 414 U8 PageNumber, U32 PageAddress, U16 *IOCStatus) 415 { 416 MPI2_CONFIG_REQUEST req; 417 MPI2_CONFIG_PAGE_HEADER header; 418 MPI2_CONFIG_REPLY reply; 419 U16 pagelen; 420 void *buf; 421 int error, len; 422 423 if (IOCStatus != NULL) 424 *IOCStatus = MPI2_IOCSTATUS_SUCCESS; 425 bzero(&header, sizeof(header)); 426 error = mps_read_ext_config_page_header(fd, ExtPageType, PageNumber, 427 PageAddress, &header, &pagelen, IOCStatus); 428 if (error) { 429 errno = error; 430 return (NULL); 431 } 432 433 bzero(&req, sizeof(req)); 434 req.Function = MPI2_FUNCTION_CONFIG; 435 req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; 436 req.PageAddress = htole32(PageAddress); 437 req.Header = header; 438 if (pagelen == 0) 439 pagelen = htole16(4); 440 req.ExtPageLength = pagelen; 441 req.ExtPageType = ExtPageType; 442 443 len = le16toh(pagelen) * 4; 444 buf = malloc(len); 445 if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply), 446 buf, len, NULL, 0, 30)) { 447 error = errno; 448 free(buf); 449 errno = error; 450 return (NULL); 451 } 452 reply.IOCStatus = le16toh(reply.IOCStatus); 453 if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) { 454 if (IOCStatus != NULL) 455 *IOCStatus = reply.IOCStatus; 456 else 457 warnx("Reading extended config page failed: %s", 458 mps_ioc_status(reply.IOCStatus)); 459 free(buf); 460 errno = EIO; 461 return (NULL); 462 } 463 return (buf); 464 } 465 466 int 467 mps_firmware_send(int fd, unsigned char *fw, uint32_t len, bool bios) 468 { 469 MPI2_FW_DOWNLOAD_REQUEST req; 470 MPI2_FW_DOWNLOAD_REPLY reply; 471 472 bzero(&req, sizeof(req)); 473 bzero(&reply, sizeof(reply)); 474 req.Function = MPI2_FUNCTION_FW_DOWNLOAD; 475 req.ImageType = bios ? MPI2_FW_DOWNLOAD_ITYPE_BIOS : MPI2_FW_DOWNLOAD_ITYPE_FW; 476 req.TotalImageSize = htole32(len); 477 req.MsgFlags = MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT; 478 479 if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply), 480 fw, len, 0)) { 481 return (-1); 482 } 483 return (0); 484 } 485 486 int 487 mps_firmware_get(int fd, unsigned char **firmware, bool bios) 488 { 489 MPI2_FW_UPLOAD_REQUEST req; 490 MPI2_FW_UPLOAD_REPLY reply; 491 int size; 492 493 *firmware = NULL; 494 bzero(&req, sizeof(req)); 495 bzero(&reply, sizeof(reply)); 496 req.Function = MPI2_FUNCTION_FW_UPLOAD; 497 req.ImageType = bios ? MPI2_FW_DOWNLOAD_ITYPE_BIOS : MPI2_FW_DOWNLOAD_ITYPE_FW; 498 499 if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply), 500 NULL, 0, 0)) { 501 return (-1); 502 } 503 if (reply.ActualImageSize == 0) { 504 return (-1); 505 } 506 507 size = le32toh(reply.ActualImageSize); 508 *firmware = calloc(size, sizeof(unsigned char)); 509 if (*firmware == NULL) { 510 warn("calloc"); 511 return (-1); 512 } 513 if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply), 514 *firmware, size, 0)) { 515 free(*firmware); 516 return (-1); 517 } 518 519 return (size); 520 } 521 522 #else 523 524 int 525 mps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress, 526 MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus) 527 { 528 struct mps_cfg_page_req req; 529 530 if (IOCStatus != NULL) 531 *IOCStatus = MPI2_IOCSTATUS_SUCCESS; 532 if (header == NULL) 533 return (EINVAL); 534 bzero(&req, sizeof(req)); 535 req.header.PageType = PageType; 536 req.header.PageNumber = PageNumber; 537 req.page_address = PageAddress; 538 if (ioctl(fd, MPSIO_READ_CFG_HEADER, &req) < 0) 539 return (errno); 540 if (!IOC_STATUS_SUCCESS(req.ioc_status)) { 541 if (IOCStatus != NULL) 542 *IOCStatus = req.ioc_status; 543 return (EIO); 544 } 545 bcopy(&req.header, header, sizeof(*header)); 546 return (0); 547 } 548 549 void * 550 mps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress, 551 U16 *IOCStatus) 552 { 553 struct mps_cfg_page_req req; 554 void *buf; 555 int error; 556 557 error = mps_read_config_page_header(fd, PageType, PageNumber, 558 PageAddress, &req.header, IOCStatus); 559 if (error) { 560 errno = error; 561 return (NULL); 562 } 563 564 if (req.header.PageLength == 0) 565 req.header.PageLength = 4; 566 req.len = req.header.PageLength * 4; 567 buf = malloc(req.len); 568 req.buf = buf; 569 bcopy(&req.header, buf, sizeof(req.header)); 570 if (ioctl(fd, MPSIO_READ_CFG_PAGE, &req) < 0) { 571 error = errno; 572 free(buf); 573 errno = error; 574 return (NULL); 575 } 576 req.ioc_status = le16toh(req.ioc_status); 577 if (!IOC_STATUS_SUCCESS(req.ioc_status)) { 578 if (IOCStatus != NULL) 579 *IOCStatus = req.ioc_status; 580 else 581 warnx("Reading config page failed: 0x%x %s", 582 req.ioc_status, mps_ioc_status(req.ioc_status)); 583 free(buf); 584 errno = EIO; 585 return (NULL); 586 } 587 return (buf); 588 } 589 590 void * 591 mps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion, 592 U8 PageNumber, U32 PageAddress, U16 *IOCStatus) 593 { 594 struct mps_ext_cfg_page_req req; 595 void *buf; 596 int error; 597 598 if (IOCStatus != NULL) 599 *IOCStatus = MPI2_IOCSTATUS_SUCCESS; 600 bzero(&req, sizeof(req)); 601 req.header.PageVersion = PageVersion; 602 req.header.PageNumber = PageNumber; 603 req.header.ExtPageType = ExtPageType; 604 req.page_address = htole32(PageAddress); 605 if (ioctl(fd, MPSIO_READ_EXT_CFG_HEADER, &req) < 0) 606 return (NULL); 607 req.ioc_status = le16toh(req.ioc_status); 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 req.ioc_status = le16toh(req.ioc_status); 628 if (!IOC_STATUS_SUCCESS(req.ioc_status)) { 629 if (IOCStatus != NULL) 630 *IOCStatus = req.ioc_status; 631 else 632 warnx("Reading extended config page failed: %s", 633 mps_ioc_status(req.ioc_status)); 634 free(buf); 635 errno = EIO; 636 return (NULL); 637 } 638 return (buf); 639 } 640 #endif 641 642 int 643 mps_open(int unit) 644 { 645 char path[MAXPATHLEN]; 646 647 snprintf(path, sizeof(path), "/dev/mp%s%d", is_mps ? "s": "r", unit); 648 return (open(path, O_RDWR)); 649 } 650 651 int 652 mps_user_command(int fd, void *req, uint32_t req_len, void *reply, 653 uint32_t reply_len, void *buffer, int len, uint32_t flags) 654 { 655 struct mps_usr_command cmd; 656 657 bzero(&cmd, sizeof(struct mps_usr_command)); 658 cmd.req = req; 659 cmd.req_len = req_len; 660 cmd.rpl = reply; 661 cmd.rpl_len = reply_len; 662 cmd.buf = buffer; 663 cmd.len = len; 664 cmd.flags = flags; 665 666 if (ioctl(fd, is_mps ? MPSIO_MPS_COMMAND : MPRIO_MPR_COMMAND, &cmd) < 0) 667 return (errno); 668 return (0); 669 } 670 671 int 672 mps_pass_command(int fd, void *req, uint32_t req_len, void *reply, 673 uint32_t reply_len, void *data_in, uint32_t datain_len, void *data_out, 674 uint32_t dataout_len, uint32_t timeout) 675 { 676 struct mprs_pass_thru pass; 677 678 bzero(&pass, sizeof(pass)); 679 pass.PtrRequest = (uint64_t)(uintptr_t)req; 680 pass.PtrReply = (uint64_t)(uintptr_t)reply; 681 pass.RequestSize = req_len; 682 pass.ReplySize = reply_len; 683 if (datain_len && dataout_len) { 684 pass.PtrData = (uint64_t)(uintptr_t)data_in; 685 pass.PtrDataOut = (uint64_t)(uintptr_t)data_out; 686 pass.DataSize = datain_len; 687 pass.DataOutSize = dataout_len; 688 if (is_mps) { 689 pass.DataDirection = MPS_PASS_THRU_DIRECTION_BOTH; 690 } else { 691 pass.DataDirection = MPR_PASS_THRU_DIRECTION_BOTH; 692 } 693 } else if (datain_len) { 694 pass.PtrData = (uint64_t)(uintptr_t)data_in; 695 pass.DataSize = datain_len; 696 if (is_mps) { 697 pass.DataDirection = MPS_PASS_THRU_DIRECTION_READ; 698 } else { 699 pass.DataDirection = MPR_PASS_THRU_DIRECTION_READ; 700 } 701 } else if (dataout_len) { 702 pass.PtrData = (uint64_t)(uintptr_t)data_out; 703 pass.DataSize = dataout_len; 704 if (is_mps) { 705 pass.DataDirection = MPS_PASS_THRU_DIRECTION_WRITE; 706 } else { 707 pass.DataDirection = MPR_PASS_THRU_DIRECTION_WRITE; 708 } 709 } else { 710 if (is_mps) { 711 pass.DataDirection = MPS_PASS_THRU_DIRECTION_NONE; 712 } else { 713 pass.DataDirection = MPR_PASS_THRU_DIRECTION_NONE; 714 } 715 } 716 pass.Timeout = timeout; 717 718 if (ioctl(fd, MPTIOCTL_PASS_THRU, &pass) < 0) 719 return (errno); 720 return (0); 721 } 722 723 /* Return the length in bytes of the device's MPI2_IOC_FACTS reply */ 724 static size_t 725 mps_get_ioc_factslen(int fd) 726 { 727 MPI2_IOC_FACTS_REQUEST req; 728 const size_t factslen = 4; 729 char factsbuf[4] = {0}; 730 MPI2_IOC_FACTS_REPLY *facts = (MPI2_IOC_FACTS_REPLY*)factsbuf; 731 int error; 732 733 bzero(&req, sizeof(req)); 734 req.Function = MPI2_FUNCTION_IOC_FACTS; 735 error = mps_pass_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST), 736 factsbuf, factslen, NULL, 0, NULL, 0, 10); 737 738 if (error) 739 return (0); 740 741 /* The card's response is measured in dwords */ 742 return (facts->MsgLength * 4); 743 } 744 745 MPI2_IOC_FACTS_REPLY * 746 mps_get_iocfacts(int fd) 747 { 748 MPI2_IOC_FACTS_REPLY *facts; 749 MPI2_IOC_FACTS_REQUEST req; 750 size_t factslen; 751 int error; 752 753 factslen = mps_get_ioc_factslen(fd); 754 if (factslen == 0) 755 return (NULL); 756 757 facts = malloc(factslen); 758 if (facts == NULL) { 759 errno = ENOMEM; 760 return (NULL); 761 } 762 763 bzero(&req, sizeof(req)); 764 req.Function = MPI2_FUNCTION_IOC_FACTS; 765 766 #if 1 767 error = mps_pass_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST), 768 facts, factslen, NULL, 0, NULL, 0, 10); 769 #else 770 error = mps_user_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST), 771 facts, factslen, NULL, 0, 0); 772 #endif 773 if (error) { 774 free(facts); 775 return (NULL); 776 } 777 778 if (!IOC_STATUS_SUCCESS(facts->IOCStatus)) { 779 free(facts); 780 errno = EINVAL; 781 return (NULL); 782 } 783 adjust_iocfacts_endianness(facts); 784 return (facts); 785 } 786 787 static void 788 adjust_iocfacts_endianness(MPI2_IOC_FACTS_REPLY *facts) 789 { 790 facts->MsgVersion = le16toh(facts->MsgVersion); 791 facts->HeaderVersion = le16toh(facts->HeaderVersion); 792 facts->Reserved1 = le16toh(facts->Reserved1); 793 facts->IOCExceptions = le16toh(facts->IOCExceptions); 794 facts->IOCStatus = le16toh(facts->IOCStatus); 795 facts->IOCLogInfo = le32toh(facts->IOCLogInfo); 796 facts->RequestCredit = le16toh(facts->RequestCredit); 797 facts->ProductID = le16toh(facts->ProductID); 798 facts->IOCCapabilities = le32toh(facts->IOCCapabilities); 799 facts->IOCRequestFrameSize = 800 le16toh(facts->IOCRequestFrameSize); 801 facts->FWVersion.Word = le32toh(facts->FWVersion.Word); 802 facts->MaxInitiators = le16toh(facts->MaxInitiators); 803 facts->MaxTargets = le16toh(facts->MaxTargets); 804 facts->MaxSasExpanders = le16toh(facts->MaxSasExpanders); 805 facts->MaxEnclosures = le16toh(facts->MaxEnclosures); 806 facts->ProtocolFlags = le16toh(facts->ProtocolFlags); 807 facts->HighPriorityCredit = le16toh(facts->HighPriorityCredit); 808 facts->MaxReplyDescriptorPostQueueDepth = 809 le16toh(facts->MaxReplyDescriptorPostQueueDepth); 810 facts->MaxDevHandle = le16toh(facts->MaxDevHandle); 811 facts->MaxPersistentEntries = 812 le16toh(facts->MaxPersistentEntries); 813 facts->MinDevHandle = le16toh(facts->MinDevHandle); 814 } 815