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>
38 __RCSID("$FreeBSD: head/usr.sbin/mpsutil/mps_cmd.c 321604 2017-07-27 05:31:48Z scottl $");
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 if (req
.Header
.PageLength
== 0)
369 req
.Header
.PageLength
= 4;
371 len
= req
.Header
.PageLength
* 4;
373 if (mps_pass_command(fd
, &req
, sizeof(req
), &reply
, sizeof(reply
),
374 buf
, len
, NULL
, 0, 30)) {
380 if (!IOC_STATUS_SUCCESS(reply
.IOCStatus
)) {
381 if (IOCStatus
!= NULL
)
382 *IOCStatus
= reply
.IOCStatus
;
384 warnx("Reading config page failed: 0x%x %s",
385 reply
.IOCStatus
, mps_ioc_status(reply
.IOCStatus
));
394 mps_read_extended_config_page(int fd
, U8 ExtPageType
, U8 PageVersion
,
395 U8 PageNumber
, U32 PageAddress
, U16
*IOCStatus
)
397 MPI2_CONFIG_REQUEST req
;
398 MPI2_CONFIG_PAGE_HEADER header
;
399 MPI2_CONFIG_REPLY reply
;
404 if (IOCStatus
!= NULL
)
405 *IOCStatus
= MPI2_IOCSTATUS_SUCCESS
;
406 bzero(&header
, sizeof(header
));
407 error
= mps_read_ext_config_page_header(fd
, ExtPageType
, PageNumber
,
408 PageAddress
, &header
, &pagelen
, IOCStatus
);
414 bzero(&req
, sizeof(req
));
415 req
.Function
= MPI2_FUNCTION_CONFIG
;
416 req
.Action
= MPI2_CONFIG_ACTION_PAGE_READ_CURRENT
;
417 req
.PageAddress
= PageAddress
;
421 req
.ExtPageLength
= pagelen
;
422 req
.ExtPageType
= ExtPageType
;
426 if (mps_pass_command(fd
, &req
, sizeof(req
), &reply
, sizeof(reply
),
427 buf
, len
, NULL
, 0, 30)) {
433 if (!IOC_STATUS_SUCCESS(reply
.IOCStatus
)) {
434 if (IOCStatus
!= NULL
)
435 *IOCStatus
= reply
.IOCStatus
;
437 warnx("Reading extended config page failed: %s",
438 mps_ioc_status(reply
.IOCStatus
));
447 mps_firmware_send(int fd
, unsigned char *fw
, uint32_t len
, bool bios
)
449 MPI2_FW_DOWNLOAD_REQUEST req
;
450 MPI2_FW_DOWNLOAD_REPLY reply
;
452 bzero(&req
, sizeof(req
));
453 bzero(&reply
, sizeof(reply
));
454 req
.Function
= MPI2_FUNCTION_FW_DOWNLOAD
;
455 req
.ImageType
= bios
? MPI2_FW_DOWNLOAD_ITYPE_BIOS
: MPI2_FW_DOWNLOAD_ITYPE_FW
;
456 req
.TotalImageSize
= len
;
457 req
.MsgFlags
= MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT
;
459 if (mps_user_command(fd
, &req
, sizeof(req
), &reply
, sizeof(reply
),
467 mps_firmware_get(int fd
, unsigned char **firmware
, bool bios
)
469 MPI2_FW_UPLOAD_REQUEST req
;
470 MPI2_FW_UPLOAD_REPLY reply
;
474 bzero(&req
, sizeof(req
));
475 bzero(&reply
, sizeof(reply
));
476 req
.Function
= MPI2_FUNCTION_FW_UPLOAD
;
477 req
.ImageType
= bios
? MPI2_FW_DOWNLOAD_ITYPE_BIOS
: MPI2_FW_DOWNLOAD_ITYPE_FW
;
479 if (mps_user_command(fd
, &req
, sizeof(req
), &reply
, sizeof(reply
),
483 if (reply
.ActualImageSize
== 0) {
487 size
= reply
.ActualImageSize
;
488 *firmware
= calloc(size
, sizeof(unsigned char));
489 if (*firmware
== NULL
) {
493 if (mps_user_command(fd
, &req
, sizeof(req
), &reply
, sizeof(reply
),
494 *firmware
, size
, 0)) {
505 mps_read_config_page_header(int fd
, U8 PageType
, U8 PageNumber
, U32 PageAddress
,
506 MPI2_CONFIG_PAGE_HEADER
*header
, U16
*IOCStatus
)
508 struct mps_cfg_page_req req
;
510 if (IOCStatus
!= NULL
)
511 *IOCStatus
= MPI2_IOCSTATUS_SUCCESS
;
514 bzero(&req
, sizeof(req
));
515 req
.header
.PageType
= PageType
;
516 req
.header
.PageNumber
= PageNumber
;
517 req
.page_address
= PageAddress
;
518 if (ioctl(fd
, MPSIO_READ_CFG_HEADER
, &req
) < 0)
520 if (!IOC_STATUS_SUCCESS(req
.ioc_status
)) {
521 if (IOCStatus
!= NULL
)
522 *IOCStatus
= req
.ioc_status
;
525 bcopy(&req
.header
, header
, sizeof(*header
));
530 mps_read_config_page(int fd
, U8 PageType
, U8 PageNumber
, U32 PageAddress
,
533 struct mps_cfg_page_req req
;
537 error
= mps_read_config_page_header(fd
, PageType
, PageNumber
,
538 PageAddress
, &req
.header
, IOCStatus
);
544 if (req
.header
.PageLength
== 0)
545 req
.header
.PageLength
= 4;
546 req
.len
= req
.header
.PageLength
* 4;
547 buf
= malloc(req
.len
);
549 bcopy(&req
.header
, buf
, sizeof(req
.header
));
550 if (ioctl(fd
, MPSIO_READ_CFG_PAGE
, &req
) < 0) {
556 if (!IOC_STATUS_SUCCESS(req
.ioc_status
)) {
557 if (IOCStatus
!= NULL
)
558 *IOCStatus
= req
.ioc_status
;
560 warnx("Reading config page failed: 0x%x %s",
561 req
.ioc_status
, mps_ioc_status(req
.ioc_status
));
570 mps_read_extended_config_page(int fd
, U8 ExtPageType
, U8 PageVersion
,
571 U8 PageNumber
, U32 PageAddress
, U16
*IOCStatus
)
573 struct mps_ext_cfg_page_req req
;
577 if (IOCStatus
!= NULL
)
578 *IOCStatus
= MPI2_IOCSTATUS_SUCCESS
;
579 bzero(&req
, sizeof(req
));
580 req
.header
.PageVersion
= PageVersion
;
581 req
.header
.PageNumber
= PageNumber
;
582 req
.header
.ExtPageType
= ExtPageType
;
583 req
.page_address
= PageAddress
;
584 if (ioctl(fd
, MPSIO_READ_EXT_CFG_HEADER
, &req
) < 0)
586 if (!IOC_STATUS_SUCCESS(req
.ioc_status
)) {
587 if (IOCStatus
!= NULL
)
588 *IOCStatus
= req
.ioc_status
;
590 warnx("Reading extended config page header failed: %s",
591 mps_ioc_status(req
.ioc_status
));
595 req
.len
= req
.header
.ExtPageLength
* 4;
596 buf
= malloc(req
.len
);
598 bcopy(&req
.header
, buf
, sizeof(req
.header
));
599 if (ioctl(fd
, MPSIO_READ_EXT_CFG_PAGE
, &req
) < 0) {
605 if (!IOC_STATUS_SUCCESS(req
.ioc_status
)) {
606 if (IOCStatus
!= NULL
)
607 *IOCStatus
= req
.ioc_status
;
609 warnx("Reading extended config page failed: %s",
610 mps_ioc_status(req
.ioc_status
));
622 char path
[MAXPATHLEN
];
624 snprintf(path
, sizeof(path
), "/dev/mp%s%d", is_mps
? "s": "r", unit
);
625 return (open(path
, O_RDWR
));
629 mps_user_command(int fd
, void *req
, uint32_t req_len
, void *reply
,
630 uint32_t reply_len
, void *buffer
, int len
, uint32_t flags
)
632 struct mps_usr_command cmd
;
634 bzero(&cmd
, sizeof(struct mps_usr_command
));
636 cmd
.req_len
= req_len
;
638 cmd
.rpl_len
= reply_len
;
643 if (ioctl(fd
, is_mps
? MPSIO_MPS_COMMAND
: MPRIO_MPR_COMMAND
, &cmd
) < 0)
649 mps_pass_command(int fd
, void *req
, uint32_t req_len
, void *reply
,
650 uint32_t reply_len
, void *data_in
, uint32_t datain_len
, void *data_out
,
651 uint32_t dataout_len
, uint32_t timeout
)
653 struct mprs_pass_thru pass
;
655 pass
.PtrRequest
= (uint64_t)(uintptr_t)req
;
656 pass
.PtrReply
= (uint64_t)(uintptr_t)reply
;
657 pass
.PtrData
= (uint64_t)(uintptr_t)data_in
;
658 pass
.PtrDataOut
= (uint64_t)(uintptr_t)data_out
;
659 pass
.RequestSize
= req_len
;
660 pass
.ReplySize
= reply_len
;
661 pass
.DataSize
= datain_len
;
662 pass
.DataOutSize
= dataout_len
;
663 if (datain_len
&& dataout_len
) {
665 pass
.DataDirection
= MPS_PASS_THRU_DIRECTION_BOTH
;
667 pass
.DataDirection
= MPR_PASS_THRU_DIRECTION_BOTH
;
669 } else if (datain_len
) {
671 pass
.DataDirection
= MPS_PASS_THRU_DIRECTION_READ
;
673 pass
.DataDirection
= MPR_PASS_THRU_DIRECTION_READ
;
675 } else if (dataout_len
) {
677 pass
.DataDirection
= MPS_PASS_THRU_DIRECTION_WRITE
;
679 pass
.DataDirection
= MPR_PASS_THRU_DIRECTION_WRITE
;
683 pass
.DataDirection
= MPS_PASS_THRU_DIRECTION_NONE
;
685 pass
.DataDirection
= MPR_PASS_THRU_DIRECTION_NONE
;
688 pass
.Timeout
= timeout
;
690 if (ioctl(fd
, MPTIOCTL_PASS_THRU
, &pass
) < 0)
695 MPI2_IOC_FACTS_REPLY
*
696 mps_get_iocfacts(int fd
)
698 MPI2_IOC_FACTS_REPLY
*facts
;
699 MPI2_IOC_FACTS_REQUEST req
;
702 facts
= malloc(sizeof(MPI2_IOC_FACTS_REPLY
));
708 bzero(&req
, sizeof(MPI2_IOC_FACTS_REQUEST
));
709 req
.Function
= MPI2_FUNCTION_IOC_FACTS
;
712 error
= mps_pass_command(fd
, &req
, sizeof(MPI2_IOC_FACTS_REQUEST
),
713 facts
, sizeof(MPI2_IOC_FACTS_REPLY
), NULL
, 0, NULL
, 0, 10);
715 error
= mps_user_command(fd
, &req
, sizeof(MPI2_IOC_FACTS_REQUEST
),
716 facts
, sizeof(MPI2_IOC_FACTS_REPLY
), NULL
, 0, 0);
723 if (!IOC_STATUS_SUCCESS(facts
->IOCStatus
)) {