2 * Copyright (c) 2008 Yahoo!, Inc.
4 * Written by: John Baldwin <jhb@FreeBSD.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the author nor the names of any co-contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #include <sys/cdefs.h>
34 #include <sys/param.h>
35 #include <sys/errno.h>
36 #include <sys/ioctl.h>
38 #include <sys/mps_ioctl.h>
40 #include "mps_ioctl.h"
41 #include "mpr_ioctl.h"
43 #include <sys/sysctl.h>
55 #ifndef USE_MPT_IOCTLS
56 #define USE_MPT_IOCTLS
59 static const char *mps_ioc_status_codes[] = {
60 "Success", /* 0x0000 */
63 "Invalid scatter-gather list",
66 "Insufficient resources",
68 "Invalid state", /* 0x0008 */
69 "Operation state not supported",
92 "Invalid configuration action", /* 0x0020 */
93 "Invalid configuration type",
94 "Invalid configuration page",
95 "Invalid configuration data",
96 "No configuration defaults",
97 "Unable to commit configuration change",
124 "Recovered SCSI error", /* 0x0040 */
126 "Invalid SCSI target ID",
127 "SCSI device not there",
129 "SCSI data underrun",
131 "SCSI protocol error",
132 "SCSI task terminated", /* 0x0048 */
133 "SCSI residual mismatch",
134 "SCSI task management failed",
135 "SCSI I/O controller terminated",
136 "SCSI external controller terminated",
138 "EEDP reference tag error",
139 "EEDP application tag error",
156 "SCSI target priority I/O", /* 0x0060 */
157 "Invalid SCSI target port",
158 "Invalid SCSI target I/O index",
159 "SCSI target aborted",
160 "No connection retryable",
163 "Invalid FC receive ID",
164 "FC did invalid", /* 0x0068 */
165 "FC node logged out",
166 "Transfer count mismatch",
168 "FC exchange canceled",
170 "Too much write data",
172 "ACK NAK timeout", /* 0x0070 */
188 "LAN device not found", /* 0x0080 */
189 "LAN device failure",
190 "LAN transmit error",
191 "LAN transmit aborted",
193 "LAN receive aborted",
194 "LAN partial packet",
204 "SAS SMP request failed", /* 0x0090 */
205 "SAS SMP data overrun",
212 "Inband aborted", /* 0x0098 */
213 "No inband connection",
220 "Diagnostic released", /* 0x00A0 */
223 struct mprs_pass_thru {
227 uint32_t RequestSize;
230 uint32_t DataDirection;
232 uint32_t DataOutSize;
236 struct mprs_btdh_mapping {
244 mps_ioc_status(U16 IOCStatus)
246 static char buffer[16];
248 IOCStatus &= MPI2_IOCSTATUS_MASK;
249 if (IOCStatus < sizeof(mps_ioc_status_codes) / sizeof(char *) &&
250 mps_ioc_status_codes[IOCStatus] != NULL)
251 return (mps_ioc_status_codes[IOCStatus]);
252 snprintf(buffer, sizeof(buffer), "Status: 0x%04x", IOCStatus);
256 #ifdef USE_MPT_IOCTLS
258 mps_map_btdh(int fd, uint16_t *devhandle, uint16_t *bus, uint16_t *target)
261 struct mprs_btdh_mapping map;
264 map.TargetID = *target;
265 map.DevHandle = *devhandle;
267 if ((error = ioctl(fd, MPTIOCTL_BTDH_MAPPING, &map)) != 0) {
269 warn("Failed to map bus/target/device");
274 *target = map.TargetID;
275 *devhandle = map.DevHandle;
281 mps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
282 MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
284 MPI2_CONFIG_REQUEST req;
285 MPI2_CONFIG_REPLY reply;
287 bzero(&req, sizeof(req));
288 req.Function = MPI2_FUNCTION_CONFIG;
289 req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
290 req.Header.PageType = PageType;
291 req.Header.PageNumber = PageNumber;
292 req.PageAddress = PageAddress;
294 if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
295 NULL, 0, NULL, 0, 30))
298 if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
299 if (IOCStatus != NULL)
300 *IOCStatus = reply.IOCStatus;
305 *header = reply.Header;
310 mps_read_ext_config_page_header(int fd, U8 ExtPageType, U8 PageNumber, U32 PageAddress, MPI2_CONFIG_PAGE_HEADER *header, U16 *ExtPageLength, U16 *IOCStatus)
312 MPI2_CONFIG_REQUEST req;
313 MPI2_CONFIG_REPLY reply;
315 bzero(&req, sizeof(req));
316 req.Function = MPI2_FUNCTION_CONFIG;
317 req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
318 req.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
319 req.ExtPageType = ExtPageType;
320 req.Header.PageNumber = PageNumber;
321 req.PageAddress = PageAddress;
323 if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
324 NULL, 0, NULL, 0, 30))
327 if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
328 if (IOCStatus != NULL)
329 *IOCStatus = reply.IOCStatus;
332 if ((header == NULL) || (ExtPageLength == NULL))
334 *header = reply.Header;
335 *ExtPageLength = reply.ExtPageLength;
340 mps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
343 MPI2_CONFIG_REQUEST req;
344 MPI2_CONFIG_PAGE_HEADER header;
345 MPI2_CONFIG_REPLY reply;
349 bzero(&header, sizeof(header));
350 error = mps_read_config_page_header(fd, PageType, PageNumber,
351 PageAddress, &header, IOCStatus);
357 bzero(&req, sizeof(req));
358 req.Function = MPI2_FUNCTION_CONFIG;
359 req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
360 req.PageAddress = PageAddress;
362 req.Header.PageLength = reply.Header.PageLength;
363 if (reply.Header.PageLength == 0)
364 req.Header.PageLength = 4;
366 len = req.Header.PageLength * 4;
368 if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
369 buf, len, NULL, 0, 30)) {
375 if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
376 if (IOCStatus != NULL)
377 *IOCStatus = reply.IOCStatus;
379 warnx("Reading config page failed: 0x%x %s",
380 reply.IOCStatus, mps_ioc_status(reply.IOCStatus));
389 mps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
390 U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
392 MPI2_CONFIG_REQUEST req;
393 MPI2_CONFIG_PAGE_HEADER header;
394 MPI2_CONFIG_REPLY reply;
399 if (IOCStatus != NULL)
400 *IOCStatus = MPI2_IOCSTATUS_SUCCESS;
401 bzero(&header, sizeof(header));
402 error = mps_read_ext_config_page_header(fd, ExtPageType, PageNumber,
403 PageAddress, &header, &pagelen, IOCStatus);
409 bzero(&req, sizeof(req));
410 req.Function = MPI2_FUNCTION_CONFIG;
411 req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
412 req.PageAddress = PageAddress;
416 req.ExtPageLength = pagelen;
417 req.ExtPageType = ExtPageType;
421 if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
422 buf, len, NULL, 0, 30)) {
428 if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
429 if (IOCStatus != NULL)
430 *IOCStatus = reply.IOCStatus;
432 warnx("Reading extended config page failed: %s",
433 mps_ioc_status(reply.IOCStatus));
444 mps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
445 MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
447 struct mps_cfg_page_req req;
449 if (IOCStatus != NULL)
450 *IOCStatus = MPI2_IOCSTATUS_SUCCESS;
453 bzero(&req, sizeof(req));
454 req.header.PageType = PageType;
455 req.header.PageNumber = PageNumber;
456 req.page_address = PageAddress;
457 if (ioctl(fd, MPSIO_READ_CFG_HEADER, &req) < 0)
459 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
460 if (IOCStatus != NULL)
461 *IOCStatus = req.ioc_status;
464 bcopy(&req.header, header, sizeof(*header));
469 mps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
472 struct mps_cfg_page_req req;
476 error = mps_read_config_page_header(fd, PageType, PageNumber,
477 PageAddress, &req.header, IOCStatus);
483 if (req.header.PageLength == 0)
484 req.header.PageLength = 4;
485 req.len = req.header.PageLength * 4;
486 buf = malloc(req.len);
488 bcopy(&req.header, buf, sizeof(req.header));
489 if (ioctl(fd, MPSIO_READ_CFG_PAGE, &req) < 0) {
495 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
496 if (IOCStatus != NULL)
497 *IOCStatus = req.ioc_status;
499 warnx("Reading config page failed: 0x%x %s",
500 req.ioc_status, mps_ioc_status(req.ioc_status));
509 mps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
510 U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
512 struct mps_ext_cfg_page_req req;
516 if (IOCStatus != NULL)
517 *IOCStatus = MPI2_IOCSTATUS_SUCCESS;
518 bzero(&req, sizeof(req));
519 req.header.PageVersion = PageVersion;
520 req.header.PageNumber = PageNumber;
521 req.header.ExtPageType = ExtPageType;
522 req.page_address = PageAddress;
523 if (ioctl(fd, MPSIO_READ_EXT_CFG_HEADER, &req) < 0)
525 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
526 if (IOCStatus != NULL)
527 *IOCStatus = req.ioc_status;
529 warnx("Reading extended config page header failed: %s",
530 mps_ioc_status(req.ioc_status));
534 req.len = req.header.ExtPageLength * 4;
535 buf = malloc(req.len);
537 bcopy(&req.header, buf, sizeof(req.header));
538 if (ioctl(fd, MPSIO_READ_EXT_CFG_PAGE, &req) < 0) {
544 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
545 if (IOCStatus != NULL)
546 *IOCStatus = req.ioc_status;
548 warnx("Reading extended config page failed: %s",
549 mps_ioc_status(req.ioc_status));
560 mpt_write_config_page(int fd, void *buf, U16 *IOCStatus)
562 CONFIG_PAGE_HEADER *hdr;
563 struct mpt_cfg_page_req req;
565 if (IOCStatus != NULL)
566 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
567 bzero(&req, sizeof(req));
570 req.len = hdr->PageLength * 4;
571 if (ioctl(fd, MPTIO_WRITE_CFG_PAGE, &req) < 0)
573 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
574 if (IOCStatus != NULL) {
575 *IOCStatus = req.ioc_status;
578 warnx("Writing config page failed: %s",
579 mpt_ioc_status(req.ioc_status));
586 mpt_raid_action(int fd, U8 Action, U8 VolumeBus, U8 VolumeID, U8 PhysDiskNum,
587 U32 ActionDataWord, void *buf, int len, RAID_VOL0_STATUS *VolumeStatus,
588 U32 *ActionData, int datalen, U16 *IOCStatus, U16 *ActionStatus, int write)
590 struct mpt_raid_action raid_act;
592 if (IOCStatus != NULL)
593 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
594 if (datalen < 0 || (unsigned)datalen > sizeof(raid_act.action_data))
596 bzero(&raid_act, sizeof(raid_act));
597 raid_act.action = Action;
598 raid_act.volume_bus = VolumeBus;
599 raid_act.volume_id = VolumeID;
600 raid_act.phys_disk_num = PhysDiskNum;
601 raid_act.action_data_word = ActionDataWord;
602 if (buf != NULL && len != 0) {
605 raid_act.write = write;
608 if (ioctl(fd, MPTIO_RAID_ACTION, &raid_act) < 0)
611 if (!IOC_STATUS_SUCCESS(raid_act.ioc_status)) {
612 if (IOCStatus != NULL) {
613 *IOCStatus = raid_act.ioc_status;
616 warnx("RAID action failed: %s",
617 mpt_ioc_status(raid_act.ioc_status));
621 if (ActionStatus != NULL)
622 *ActionStatus = raid_act.action_status;
623 if (raid_act.action_status != MPI_RAID_ACTION_ASTATUS_SUCCESS) {
624 if (ActionStatus != NULL)
626 warnx("RAID action failed: %s",
627 mpt_raid_status(raid_act.action_status));
631 if (VolumeStatus != NULL)
632 *((U32 *)VolumeStatus) = raid_act.volume_status;
633 if (ActionData != NULL)
634 bcopy(raid_act.action_data, ActionData, datalen);
642 char path[MAXPATHLEN];
644 snprintf(path, sizeof(path), "/dev/mp%s%d", is_mps ? "s": "r", unit);
645 return (open(path, O_RDWR));
649 mps_user_command(int fd, void *req, uint32_t req_len, void *reply,
650 uint32_t reply_len, void *buffer, int len, uint32_t flags)
652 struct mps_usr_command cmd;
654 bzero(&cmd, sizeof(struct mps_usr_command));
656 cmd.req_len = req_len;
658 cmd.rpl_len = reply_len;
663 if (ioctl(fd, is_mps ? MPSIO_MPS_COMMAND : MPRIO_MPR_COMMAND, &cmd) < 0)
669 mps_pass_command(int fd, void *req, uint32_t req_len, void *reply,
670 uint32_t reply_len, void *data_in, uint32_t datain_len, void *data_out,
671 uint32_t dataout_len, uint32_t timeout)
673 struct mprs_pass_thru pass;
675 pass.PtrRequest = (uint64_t)(uintptr_t)req;
676 pass.PtrReply = (uint64_t)(uintptr_t)reply;
677 pass.PtrData = (uint64_t)(uintptr_t)data_in;
678 pass.PtrDataOut = (uint64_t)(uintptr_t)data_out;
679 pass.RequestSize = req_len;
680 pass.ReplySize = reply_len;
681 pass.DataSize = datain_len;
682 pass.DataOutSize = dataout_len;
683 if (datain_len && dataout_len) {
685 pass.DataDirection = MPS_PASS_THRU_DIRECTION_BOTH;
687 pass.DataDirection = MPR_PASS_THRU_DIRECTION_BOTH;
689 } else if (datain_len) {
691 pass.DataDirection = MPS_PASS_THRU_DIRECTION_READ;
693 pass.DataDirection = MPR_PASS_THRU_DIRECTION_READ;
695 } else if (dataout_len) {
697 pass.DataDirection = MPS_PASS_THRU_DIRECTION_WRITE;
699 pass.DataDirection = MPR_PASS_THRU_DIRECTION_WRITE;
703 pass.DataDirection = MPS_PASS_THRU_DIRECTION_NONE;
705 pass.DataDirection = MPR_PASS_THRU_DIRECTION_NONE;
708 pass.Timeout = timeout;
710 if (ioctl(fd, MPTIOCTL_PASS_THRU, &pass) < 0)
715 MPI2_IOC_FACTS_REPLY *
716 mps_get_iocfacts(int fd)
718 MPI2_IOC_FACTS_REPLY *facts;
719 MPI2_IOC_FACTS_REQUEST req;
722 facts = malloc(sizeof(MPI2_IOC_FACTS_REPLY));
728 bzero(&req, sizeof(MPI2_IOC_FACTS_REQUEST));
729 req.Function = MPI2_FUNCTION_IOC_FACTS;
732 error = mps_pass_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
733 facts, sizeof(MPI2_IOC_FACTS_REPLY), NULL, 0, NULL, 0, 10);
735 error = mps_user_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
736 facts, sizeof(MPI2_IOC_FACTS_REPLY), NULL, 0, 0);
743 if (!IOC_STATUS_SUCCESS(facts->IOCStatus)) {