2 * Copyright (c) 2015 Baptiste Daroussin <bapt@FreeBSD.org>
4 * Copyright (c) 2015 Netflix, Inc.
5 * Written by: Scott Long <scottl@freebsd.org>
7 * Copyright (c) 2008 Yahoo!, Inc.
9 * Written by: John Baldwin <jhb@FreeBSD.org>
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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
36 #include <sys/cdefs.h>
39 #include <sys/param.h>
40 #include <sys/errno.h>
41 #include <sys/ioctl.h>
43 #include <sys/mps_ioctl.h>
45 #include "mps_ioctl.h"
46 #include "mpr_ioctl.h"
48 #include <sys/sysctl.h>
60 #ifndef USE_MPT_IOCTLS
61 #define USE_MPT_IOCTLS
64 static const char *mps_ioc_status_codes[] = {
65 "Success", /* 0x0000 */
68 "Invalid scatter-gather list",
71 "Insufficient resources",
73 "Invalid state", /* 0x0008 */
74 "Operation state not supported",
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",
129 "Recovered SCSI error", /* 0x0040 */
131 "Invalid SCSI target ID",
132 "SCSI device not there",
134 "SCSI data underrun",
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",
143 "EEDP reference tag error",
144 "EEDP application tag error",
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",
168 "Invalid FC receive ID",
169 "FC did invalid", /* 0x0068 */
170 "FC node logged out",
171 "Transfer count mismatch",
173 "FC exchange canceled",
175 "Too much write data",
177 "ACK NAK timeout", /* 0x0070 */
193 "LAN device not found", /* 0x0080 */
194 "LAN device failure",
195 "LAN transmit error",
196 "LAN transmit aborted",
198 "LAN receive aborted",
199 "LAN partial packet",
209 "SAS SMP request failed", /* 0x0090 */
210 "SAS SMP data overrun",
217 "Inband aborted", /* 0x0098 */
218 "No inband connection",
225 "Diagnostic released", /* 0x00A0 */
228 struct mprs_pass_thru {
232 uint32_t RequestSize;
235 uint32_t DataDirection;
237 uint32_t DataOutSize;
241 struct mprs_btdh_mapping {
249 mps_ioc_status(U16 IOCStatus)
251 static char buffer[16];
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);
261 #ifdef USE_MPT_IOCTLS
263 mps_map_btdh(int fd, uint16_t *devhandle, uint16_t *bus, uint16_t *target)
266 struct mprs_btdh_mapping map;
269 map.TargetID = *target;
270 map.DevHandle = *devhandle;
272 if ((error = ioctl(fd, MPTIOCTL_BTDH_MAPPING, &map)) != 0) {
274 warn("Failed to map bus/target/device");
279 *target = map.TargetID;
280 *devhandle = map.DevHandle;
286 mps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
287 MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
289 MPI2_CONFIG_REQUEST req;
290 MPI2_CONFIG_REPLY reply;
292 bzero(&req, sizeof(req));
293 req.Function = MPI2_FUNCTION_CONFIG;
294 req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
295 req.Header.PageType = PageType;
296 req.Header.PageNumber = PageNumber;
297 req.PageAddress = PageAddress;
299 if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
300 NULL, 0, NULL, 0, 30))
303 if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
304 if (IOCStatus != NULL)
305 *IOCStatus = reply.IOCStatus;
310 *header = reply.Header;
315 mps_read_ext_config_page_header(int fd, U8 ExtPageType, U8 PageNumber, U32 PageAddress, MPI2_CONFIG_PAGE_HEADER *header, U16 *ExtPageLength, U16 *IOCStatus)
317 MPI2_CONFIG_REQUEST req;
318 MPI2_CONFIG_REPLY reply;
320 bzero(&req, sizeof(req));
321 req.Function = MPI2_FUNCTION_CONFIG;
322 req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
323 req.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
324 req.ExtPageType = ExtPageType;
325 req.Header.PageNumber = PageNumber;
326 req.PageAddress = PageAddress;
328 if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
329 NULL, 0, NULL, 0, 30))
332 if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
333 if (IOCStatus != NULL)
334 *IOCStatus = reply.IOCStatus;
337 if ((header == NULL) || (ExtPageLength == NULL))
339 *header = reply.Header;
340 *ExtPageLength = reply.ExtPageLength;
345 mps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
348 MPI2_CONFIG_REQUEST req;
349 MPI2_CONFIG_PAGE_HEADER header;
350 MPI2_CONFIG_REPLY reply;
354 bzero(&header, sizeof(header));
355 error = mps_read_config_page_header(fd, PageType, PageNumber,
356 PageAddress, &header, IOCStatus);
362 bzero(&req, sizeof(req));
363 req.Function = MPI2_FUNCTION_CONFIG;
364 req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
365 req.PageAddress = PageAddress;
367 if (req.Header.PageLength == 0)
368 req.Header.PageLength = 4;
370 len = req.Header.PageLength * 4;
372 if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
373 buf, len, NULL, 0, 30)) {
379 if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
380 if (IOCStatus != NULL)
381 *IOCStatus = reply.IOCStatus;
383 warnx("Reading config page failed: 0x%x %s",
384 reply.IOCStatus, mps_ioc_status(reply.IOCStatus));
393 mps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
394 U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
396 MPI2_CONFIG_REQUEST req;
397 MPI2_CONFIG_PAGE_HEADER header;
398 MPI2_CONFIG_REPLY reply;
403 if (IOCStatus != NULL)
404 *IOCStatus = MPI2_IOCSTATUS_SUCCESS;
405 bzero(&header, sizeof(header));
406 error = mps_read_ext_config_page_header(fd, ExtPageType, PageNumber,
407 PageAddress, &header, &pagelen, IOCStatus);
413 bzero(&req, sizeof(req));
414 req.Function = MPI2_FUNCTION_CONFIG;
415 req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
416 req.PageAddress = PageAddress;
420 req.ExtPageLength = pagelen;
421 req.ExtPageType = ExtPageType;
425 if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
426 buf, len, NULL, 0, 30)) {
432 if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
433 if (IOCStatus != NULL)
434 *IOCStatus = reply.IOCStatus;
436 warnx("Reading extended config page failed: %s",
437 mps_ioc_status(reply.IOCStatus));
446 mps_firmware_send(int fd, unsigned char *fw, uint32_t len, bool bios)
448 MPI2_FW_DOWNLOAD_REQUEST req;
449 MPI2_FW_DOWNLOAD_REPLY reply;
451 bzero(&req, sizeof(req));
452 bzero(&reply, sizeof(reply));
453 req.Function = MPI2_FUNCTION_FW_DOWNLOAD;
454 req.ImageType = bios ? MPI2_FW_DOWNLOAD_ITYPE_BIOS : MPI2_FW_DOWNLOAD_ITYPE_FW;
455 req.TotalImageSize = len;
456 req.MsgFlags = MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT;
458 if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply),
466 mps_firmware_get(int fd, unsigned char **firmware, bool bios)
468 MPI2_FW_UPLOAD_REQUEST req;
469 MPI2_FW_UPLOAD_REPLY reply;
473 bzero(&req, sizeof(req));
474 bzero(&reply, sizeof(reply));
475 req.Function = MPI2_FUNCTION_FW_UPLOAD;
476 req.ImageType = bios ? MPI2_FW_DOWNLOAD_ITYPE_BIOS : MPI2_FW_DOWNLOAD_ITYPE_FW;
478 if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply),
482 if (reply.ActualImageSize == 0) {
486 size = reply.ActualImageSize;
487 *firmware = calloc(size, sizeof(unsigned char));
488 if (*firmware == NULL) {
492 if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply),
493 *firmware, size, 0)) {
504 mps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
505 MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
507 struct mps_cfg_page_req req;
509 if (IOCStatus != NULL)
510 *IOCStatus = MPI2_IOCSTATUS_SUCCESS;
513 bzero(&req, sizeof(req));
514 req.header.PageType = PageType;
515 req.header.PageNumber = PageNumber;
516 req.page_address = PageAddress;
517 if (ioctl(fd, MPSIO_READ_CFG_HEADER, &req) < 0)
519 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
520 if (IOCStatus != NULL)
521 *IOCStatus = req.ioc_status;
524 bcopy(&req.header, header, sizeof(*header));
529 mps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
532 struct mps_cfg_page_req req;
536 error = mps_read_config_page_header(fd, PageType, PageNumber,
537 PageAddress, &req.header, IOCStatus);
543 if (req.header.PageLength == 0)
544 req.header.PageLength = 4;
545 req.len = req.header.PageLength * 4;
546 buf = malloc(req.len);
548 bcopy(&req.header, buf, sizeof(req.header));
549 if (ioctl(fd, MPSIO_READ_CFG_PAGE, &req) < 0) {
555 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
556 if (IOCStatus != NULL)
557 *IOCStatus = req.ioc_status;
559 warnx("Reading config page failed: 0x%x %s",
560 req.ioc_status, mps_ioc_status(req.ioc_status));
569 mps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
570 U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
572 struct mps_ext_cfg_page_req req;
576 if (IOCStatus != NULL)
577 *IOCStatus = MPI2_IOCSTATUS_SUCCESS;
578 bzero(&req, sizeof(req));
579 req.header.PageVersion = PageVersion;
580 req.header.PageNumber = PageNumber;
581 req.header.ExtPageType = ExtPageType;
582 req.page_address = PageAddress;
583 if (ioctl(fd, MPSIO_READ_EXT_CFG_HEADER, &req) < 0)
585 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
586 if (IOCStatus != NULL)
587 *IOCStatus = req.ioc_status;
589 warnx("Reading extended config page header failed: %s",
590 mps_ioc_status(req.ioc_status));
594 req.len = req.header.ExtPageLength * 4;
595 buf = malloc(req.len);
597 bcopy(&req.header, buf, sizeof(req.header));
598 if (ioctl(fd, MPSIO_READ_EXT_CFG_PAGE, &req) < 0) {
604 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
605 if (IOCStatus != NULL)
606 *IOCStatus = req.ioc_status;
608 warnx("Reading extended config page failed: %s",
609 mps_ioc_status(req.ioc_status));
621 char path[MAXPATHLEN];
623 snprintf(path, sizeof(path), "/dev/mp%s%d", is_mps ? "s": "r", unit);
624 return (open(path, O_RDWR));
628 mps_user_command(int fd, void *req, uint32_t req_len, void *reply,
629 uint32_t reply_len, void *buffer, int len, uint32_t flags)
631 struct mps_usr_command cmd;
633 bzero(&cmd, sizeof(struct mps_usr_command));
635 cmd.req_len = req_len;
637 cmd.rpl_len = reply_len;
642 if (ioctl(fd, is_mps ? MPSIO_MPS_COMMAND : MPRIO_MPR_COMMAND, &cmd) < 0)
648 mps_pass_command(int fd, void *req, uint32_t req_len, void *reply,
649 uint32_t reply_len, void *data_in, uint32_t datain_len, void *data_out,
650 uint32_t dataout_len, uint32_t timeout)
652 struct mprs_pass_thru pass;
654 bzero(&pass, sizeof(pass));
655 pass.PtrRequest = (uint64_t)(uintptr_t)req;
656 pass.PtrReply = (uint64_t)(uintptr_t)reply;
657 pass.RequestSize = req_len;
658 pass.ReplySize = reply_len;
659 if (datain_len && dataout_len) {
660 pass.PtrData = (uint64_t)(uintptr_t)data_in;
661 pass.PtrDataOut = (uint64_t)(uintptr_t)data_out;
662 pass.DataSize = datain_len;
663 pass.DataOutSize = dataout_len;
665 pass.DataDirection = MPS_PASS_THRU_DIRECTION_BOTH;
667 pass.DataDirection = MPR_PASS_THRU_DIRECTION_BOTH;
669 } else if (datain_len) {
670 pass.PtrData = (uint64_t)(uintptr_t)data_in;
671 pass.DataSize = datain_len;
673 pass.DataDirection = MPS_PASS_THRU_DIRECTION_READ;
675 pass.DataDirection = MPR_PASS_THRU_DIRECTION_READ;
677 } else if (dataout_len) {
678 pass.PtrData = (uint64_t)(uintptr_t)data_out;
679 pass.DataSize = dataout_len;
681 pass.DataDirection = MPS_PASS_THRU_DIRECTION_WRITE;
683 pass.DataDirection = MPR_PASS_THRU_DIRECTION_WRITE;
687 pass.DataDirection = MPS_PASS_THRU_DIRECTION_NONE;
689 pass.DataDirection = MPR_PASS_THRU_DIRECTION_NONE;
692 pass.Timeout = timeout;
694 if (ioctl(fd, MPTIOCTL_PASS_THRU, &pass) < 0)
699 MPI2_IOC_FACTS_REPLY *
700 mps_get_iocfacts(int fd)
702 MPI2_IOC_FACTS_REPLY *facts;
703 MPI2_IOC_FACTS_REQUEST req;
706 facts = malloc(sizeof(MPI2_IOC_FACTS_REPLY));
712 bzero(&req, sizeof(MPI2_IOC_FACTS_REQUEST));
713 req.Function = MPI2_FUNCTION_IOC_FACTS;
716 error = mps_pass_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
717 facts, sizeof(MPI2_IOC_FACTS_REPLY), NULL, 0, NULL, 0, 10);
719 error = mps_user_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
720 facts, sizeof(MPI2_IOC_FACTS_REPLY), NULL, 0, 0);
727 if (!IOC_STATUS_SUCCESS(facts->IOCStatus)) {