2 * Copyright (c) 2015 Baptiste Daroussin <bapt@FreeBSD.org>
4 * Copyright (c) 2015 Netflix, Inc.
6 * Written by: Scott Long <scottl@freebsd.org>
8 * Copyright (c) 2008 Yahoo!, Inc.
10 * Written by: John Baldwin <jhb@FreeBSD.org>
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the author nor the names of any co-contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 #include <sys/cdefs.h>
40 #include <sys/param.h>
41 #include <sys/errno.h>
42 #include <sys/ioctl.h>
44 #include <sys/mps_ioctl.h>
46 #include "mps_ioctl.h"
47 #include "mpr_ioctl.h"
49 #include <sys/sysctl.h>
61 #ifndef USE_MPT_IOCTLS
62 #define USE_MPT_IOCTLS
65 static const char *mps_ioc_status_codes[] = {
66 "Success", /* 0x0000 */
69 "Invalid scatter-gather list",
72 "Insufficient resources",
74 "Invalid state", /* 0x0008 */
75 "Operation state not supported",
98 "Invalid configuration action", /* 0x0020 */
99 "Invalid configuration type",
100 "Invalid configuration page",
101 "Invalid configuration data",
102 "No configuration defaults",
103 "Unable to commit configuration change",
130 "Recovered SCSI error", /* 0x0040 */
132 "Invalid SCSI target ID",
133 "SCSI device not there",
135 "SCSI data underrun",
137 "SCSI protocol error",
138 "SCSI task terminated", /* 0x0048 */
139 "SCSI residual mismatch",
140 "SCSI task management failed",
141 "SCSI I/O controller terminated",
142 "SCSI external controller terminated",
144 "EEDP reference tag error",
145 "EEDP application tag error",
162 "SCSI target priority I/O", /* 0x0060 */
163 "Invalid SCSI target port",
164 "Invalid SCSI target I/O index",
165 "SCSI target aborted",
166 "No connection retryable",
169 "Invalid FC receive ID",
170 "FC did invalid", /* 0x0068 */
171 "FC node logged out",
172 "Transfer count mismatch",
174 "FC exchange canceled",
176 "Too much write data",
178 "ACK NAK timeout", /* 0x0070 */
194 "LAN device not found", /* 0x0080 */
195 "LAN device failure",
196 "LAN transmit error",
197 "LAN transmit aborted",
199 "LAN receive aborted",
200 "LAN partial packet",
210 "SAS SMP request failed", /* 0x0090 */
211 "SAS SMP data overrun",
218 "Inband aborted", /* 0x0098 */
219 "No inband connection",
226 "Diagnostic released", /* 0x00A0 */
229 struct mprs_pass_thru {
233 uint32_t RequestSize;
236 uint32_t DataDirection;
238 uint32_t DataOutSize;
242 struct mprs_btdh_mapping {
250 mps_ioc_status(U16 IOCStatus)
252 static char buffer[16];
254 IOCStatus &= MPI2_IOCSTATUS_MASK;
255 if (IOCStatus < sizeof(mps_ioc_status_codes) / sizeof(char *) &&
256 mps_ioc_status_codes[IOCStatus] != NULL)
257 return (mps_ioc_status_codes[IOCStatus]);
258 snprintf(buffer, sizeof(buffer), "Status: 0x%04x", IOCStatus);
262 #ifdef USE_MPT_IOCTLS
264 mps_map_btdh(int fd, uint16_t *devhandle, uint16_t *bus, uint16_t *target)
267 struct mprs_btdh_mapping map;
270 map.TargetID = *target;
271 map.DevHandle = *devhandle;
273 if ((error = ioctl(fd, MPTIOCTL_BTDH_MAPPING, &map)) != 0) {
275 warn("Failed to map bus/target/device");
280 *target = map.TargetID;
281 *devhandle = map.DevHandle;
287 mps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
288 MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
290 MPI2_CONFIG_REQUEST req;
291 MPI2_CONFIG_REPLY reply;
293 bzero(&req, sizeof(req));
294 req.Function = MPI2_FUNCTION_CONFIG;
295 req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
296 req.Header.PageType = PageType;
297 req.Header.PageNumber = PageNumber;
298 req.PageAddress = PageAddress;
300 if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
301 NULL, 0, NULL, 0, 30))
304 if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
305 if (IOCStatus != NULL)
306 *IOCStatus = reply.IOCStatus;
311 *header = reply.Header;
316 mps_read_ext_config_page_header(int fd, U8 ExtPageType, U8 PageNumber, U32 PageAddress, MPI2_CONFIG_PAGE_HEADER *header, U16 *ExtPageLength, U16 *IOCStatus)
318 MPI2_CONFIG_REQUEST req;
319 MPI2_CONFIG_REPLY reply;
321 bzero(&req, sizeof(req));
322 req.Function = MPI2_FUNCTION_CONFIG;
323 req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
324 req.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
325 req.ExtPageType = ExtPageType;
326 req.Header.PageNumber = PageNumber;
327 req.PageAddress = PageAddress;
329 if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
330 NULL, 0, NULL, 0, 30))
333 if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
334 if (IOCStatus != NULL)
335 *IOCStatus = reply.IOCStatus;
338 if ((header == NULL) || (ExtPageLength == NULL))
340 *header = reply.Header;
341 *ExtPageLength = reply.ExtPageLength;
346 mps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
349 MPI2_CONFIG_REQUEST req;
350 MPI2_CONFIG_PAGE_HEADER header;
351 MPI2_CONFIG_REPLY reply;
355 bzero(&header, sizeof(header));
356 error = mps_read_config_page_header(fd, PageType, PageNumber,
357 PageAddress, &header, IOCStatus);
363 bzero(&req, sizeof(req));
364 req.Function = MPI2_FUNCTION_CONFIG;
365 req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
366 req.PageAddress = PageAddress;
368 req.Header.PageLength = reply.Header.PageLength;
369 if (reply.Header.PageLength == 0)
370 req.Header.PageLength = 4;
372 len = req.Header.PageLength * 4;
374 if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
375 buf, len, NULL, 0, 30)) {
381 if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
382 if (IOCStatus != NULL)
383 *IOCStatus = reply.IOCStatus;
385 warnx("Reading config page failed: 0x%x %s",
386 reply.IOCStatus, mps_ioc_status(reply.IOCStatus));
395 mps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
396 U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
398 MPI2_CONFIG_REQUEST req;
399 MPI2_CONFIG_PAGE_HEADER header;
400 MPI2_CONFIG_REPLY reply;
405 if (IOCStatus != NULL)
406 *IOCStatus = MPI2_IOCSTATUS_SUCCESS;
407 bzero(&header, sizeof(header));
408 error = mps_read_ext_config_page_header(fd, ExtPageType, PageNumber,
409 PageAddress, &header, &pagelen, IOCStatus);
415 bzero(&req, sizeof(req));
416 req.Function = MPI2_FUNCTION_CONFIG;
417 req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
418 req.PageAddress = PageAddress;
422 req.ExtPageLength = pagelen;
423 req.ExtPageType = ExtPageType;
427 if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
428 buf, len, NULL, 0, 30)) {
434 if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
435 if (IOCStatus != NULL)
436 *IOCStatus = reply.IOCStatus;
438 warnx("Reading extended config page failed: %s",
439 mps_ioc_status(reply.IOCStatus));
448 mps_firmware_send(int fd, unsigned char *fw, uint32_t len, bool bios)
450 MPI2_FW_DOWNLOAD_REQUEST req;
451 MPI2_FW_DOWNLOAD_REPLY reply;
453 bzero(&req, sizeof(req));
454 bzero(&reply, sizeof(reply));
455 req.Function = MPI2_FUNCTION_FW_DOWNLOAD;
456 req.ImageType = bios ? MPI2_FW_DOWNLOAD_ITYPE_BIOS : MPI2_FW_DOWNLOAD_ITYPE_FW;
457 req.TotalImageSize = len;
458 req.MsgFlags = MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT;
460 if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply),
468 mps_firmware_get(int fd, unsigned char **firmware, bool bios)
470 MPI2_FW_UPLOAD_REQUEST req;
471 MPI2_FW_UPLOAD_REPLY reply;
475 bzero(&req, sizeof(req));
476 bzero(&reply, sizeof(reply));
477 req.Function = MPI2_FUNCTION_FW_UPLOAD;
478 req.ImageType = bios ? MPI2_FW_DOWNLOAD_ITYPE_BIOS : MPI2_FW_DOWNLOAD_ITYPE_FW;
480 if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply),
484 if (reply.ActualImageSize == 0) {
488 size = reply.ActualImageSize;
489 *firmware = calloc(size, sizeof(unsigned char));
490 if (*firmware == NULL) {
494 if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply),
495 *firmware, size, 0)) {
506 mps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
507 MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
509 struct mps_cfg_page_req req;
511 if (IOCStatus != NULL)
512 *IOCStatus = MPI2_IOCSTATUS_SUCCESS;
515 bzero(&req, sizeof(req));
516 req.header.PageType = PageType;
517 req.header.PageNumber = PageNumber;
518 req.page_address = PageAddress;
519 if (ioctl(fd, MPSIO_READ_CFG_HEADER, &req) < 0)
521 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
522 if (IOCStatus != NULL)
523 *IOCStatus = req.ioc_status;
526 bcopy(&req.header, header, sizeof(*header));
531 mps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
534 struct mps_cfg_page_req req;
538 error = mps_read_config_page_header(fd, PageType, PageNumber,
539 PageAddress, &req.header, IOCStatus);
545 if (req.header.PageLength == 0)
546 req.header.PageLength = 4;
547 req.len = req.header.PageLength * 4;
548 buf = malloc(req.len);
550 bcopy(&req.header, buf, sizeof(req.header));
551 if (ioctl(fd, MPSIO_READ_CFG_PAGE, &req) < 0) {
557 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
558 if (IOCStatus != NULL)
559 *IOCStatus = req.ioc_status;
561 warnx("Reading config page failed: 0x%x %s",
562 req.ioc_status, mps_ioc_status(req.ioc_status));
571 mps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
572 U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
574 struct mps_ext_cfg_page_req req;
578 if (IOCStatus != NULL)
579 *IOCStatus = MPI2_IOCSTATUS_SUCCESS;
580 bzero(&req, sizeof(req));
581 req.header.PageVersion = PageVersion;
582 req.header.PageNumber = PageNumber;
583 req.header.ExtPageType = ExtPageType;
584 req.page_address = PageAddress;
585 if (ioctl(fd, MPSIO_READ_EXT_CFG_HEADER, &req) < 0)
587 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
588 if (IOCStatus != NULL)
589 *IOCStatus = req.ioc_status;
591 warnx("Reading extended config page header failed: %s",
592 mps_ioc_status(req.ioc_status));
596 req.len = req.header.ExtPageLength * 4;
597 buf = malloc(req.len);
599 bcopy(&req.header, buf, sizeof(req.header));
600 if (ioctl(fd, MPSIO_READ_EXT_CFG_PAGE, &req) < 0) {
606 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
607 if (IOCStatus != NULL)
608 *IOCStatus = req.ioc_status;
610 warnx("Reading extended config page failed: %s",
611 mps_ioc_status(req.ioc_status));
623 char path[MAXPATHLEN];
625 snprintf(path, sizeof(path), "/dev/mp%s%d", is_mps ? "s": "r", unit);
626 return (open(path, O_RDWR));
630 mps_user_command(int fd, void *req, uint32_t req_len, void *reply,
631 uint32_t reply_len, void *buffer, int len, uint32_t flags)
633 struct mps_usr_command cmd;
635 bzero(&cmd, sizeof(struct mps_usr_command));
637 cmd.req_len = req_len;
639 cmd.rpl_len = reply_len;
644 if (ioctl(fd, is_mps ? MPSIO_MPS_COMMAND : MPRIO_MPR_COMMAND, &cmd) < 0)
650 mps_pass_command(int fd, void *req, uint32_t req_len, void *reply,
651 uint32_t reply_len, void *data_in, uint32_t datain_len, void *data_out,
652 uint32_t dataout_len, uint32_t timeout)
654 struct mprs_pass_thru pass;
656 pass.PtrRequest = (uint64_t)(uintptr_t)req;
657 pass.PtrReply = (uint64_t)(uintptr_t)reply;
658 pass.PtrData = (uint64_t)(uintptr_t)data_in;
659 pass.PtrDataOut = (uint64_t)(uintptr_t)data_out;
660 pass.RequestSize = req_len;
661 pass.ReplySize = reply_len;
662 pass.DataSize = datain_len;
663 pass.DataOutSize = dataout_len;
664 if (datain_len && dataout_len) {
666 pass.DataDirection = MPS_PASS_THRU_DIRECTION_BOTH;
668 pass.DataDirection = MPR_PASS_THRU_DIRECTION_BOTH;
670 } else if (datain_len) {
672 pass.DataDirection = MPS_PASS_THRU_DIRECTION_READ;
674 pass.DataDirection = MPR_PASS_THRU_DIRECTION_READ;
676 } else if (dataout_len) {
678 pass.DataDirection = MPS_PASS_THRU_DIRECTION_WRITE;
680 pass.DataDirection = MPR_PASS_THRU_DIRECTION_WRITE;
684 pass.DataDirection = MPS_PASS_THRU_DIRECTION_NONE;
686 pass.DataDirection = MPR_PASS_THRU_DIRECTION_NONE;
689 pass.Timeout = timeout;
691 if (ioctl(fd, MPTIOCTL_PASS_THRU, &pass) < 0)
696 MPI2_IOC_FACTS_REPLY *
697 mps_get_iocfacts(int fd)
699 MPI2_IOC_FACTS_REPLY *facts;
700 MPI2_IOC_FACTS_REQUEST req;
703 facts = malloc(sizeof(MPI2_IOC_FACTS_REPLY));
709 bzero(&req, sizeof(MPI2_IOC_FACTS_REQUEST));
710 req.Function = MPI2_FUNCTION_IOC_FACTS;
713 error = mps_pass_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
714 facts, sizeof(MPI2_IOC_FACTS_REPLY), NULL, 0, NULL, 0, 10);
716 error = mps_user_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
717 facts, sizeof(MPI2_IOC_FACTS_REPLY), NULL, 0, 0);
724 if (!IOC_STATUS_SUCCESS(facts->IOCStatus)) {