Index: projects/mpsutil/usr.sbin/mpsutil/Makefile
===================================================================
--- projects/mpsutil/usr.sbin/mpsutil/Makefile	(revision 289363)
+++ projects/mpsutil/usr.sbin/mpsutil/Makefile	(revision 289364)
@@ -1,20 +1,21 @@
 # $FreeBSD$
 
 PROG=	mpsutil
 SRCS=	mpsutil.c mps_cmd.c mps_show.c
 #	mpt_flash.c
 MAN=	mpsutil.8
 
 WARNS?= 3
 
 LIBADD=	cam util
+LINKS=	${BINDIR}/mpsutil ${BINDIR}/mprutil
 
 CFLAGS+= -I${.CURDIR}/../../sys -I. -DUSE_MPT_IOCTLS -g
 
 
 # Here be dragons
 .ifdef DEBUG
 CFLAGS+= -DDEBUG
 .endif
 
 .include <bsd.prog.mk>
Index: projects/mpsutil/usr.sbin/mpsutil/mps_cmd.c
===================================================================
--- projects/mpsutil/usr.sbin/mpsutil/mps_cmd.c	(revision 289363)
+++ projects/mpsutil/usr.sbin/mpsutil/mps_cmd.c	(revision 289364)
@@ -1,713 +1,713 @@
 /*-
  * Copyright (c) 2008 Yahoo!, Inc.
  * All rights reserved.
  * Written by: John Baldwin <jhb@FreeBSD.org>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  * 3. Neither the name of the author nor the names of any co-contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
 
 #include <sys/cdefs.h>
 __RCSID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/errno.h>
 #include <sys/ioctl.h>
 #if 0
 #include <sys/mps_ioctl.h>
 #else
 #include "mps_ioctl.h"
 #endif
 #include <sys/sysctl.h>
 #include <sys/uio.h>
 
 #include <err.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
 #include "mpsutil.h"
 
 #ifndef USE_MPT_IOCTLS
 #define USE_MPT_IOCTLS
 #endif
 
 static const char *mps_ioc_status_codes[] = {
 	"Success",				/* 0x0000 */
 	"Invalid function",
 	"Busy",
 	"Invalid scatter-gather list",
 	"Internal error",
 	"Reserved",
 	"Insufficient resources",
 	"Invalid field",
 	"Invalid state",			/* 0x0008 */
 	"Operation state not supported",
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,					/* 0x0010 */
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,					/* 0x0018 */
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	"Invalid configuration action",		/* 0x0020 */
 	"Invalid configuration type",
 	"Invalid configuration page",
 	"Invalid configuration data",
 	"No configuration defaults",
 	"Unable to commit configuration change",
 	NULL,
 	NULL,
 	NULL,					/* 0x0028 */
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,					/* 0x0030 */
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,					/* 0x0038 */
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	"Recovered SCSI error",			/* 0x0040 */
 	"Invalid SCSI bus",
 	"Invalid SCSI target ID",
 	"SCSI device not there",
 	"SCSI data overrun",
 	"SCSI data underrun",
 	"SCSI I/O error",
 	"SCSI protocol error",
 	"SCSI task terminated",			/* 0x0048 */
 	"SCSI residual mismatch",
 	"SCSI task management failed",
 	"SCSI I/O controller terminated",
 	"SCSI external controller terminated",
 	"EEDP guard error",
 	"EEDP reference tag error",
 	"EEDP application tag error",
 	NULL,					/* 0x0050 */
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,					/* 0x0058 */
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	"SCSI target priority I/O",		/* 0x0060 */
 	"Invalid SCSI target port",
 	"Invalid SCSI target I/O index",
 	"SCSI target aborted",
 	"No connection retryable",
 	"No connection",
 	"FC aborted",
 	"Invalid FC receive ID",
 	"FC did invalid",			/* 0x0068 */
 	"FC node logged out",
 	"Transfer count mismatch",
 	"STS data not set",
 	"FC exchange canceled",
 	"Data offset error",
 	"Too much write data",
 	"IU too short",
 	"ACK NAK timeout",			/* 0x0070 */
 	"NAK received",
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,					/* 0x0078 */
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	"LAN device not found",			/* 0x0080 */
 	"LAN device failure",
 	"LAN transmit error",
 	"LAN transmit aborted",
 	"LAN receive error",
 	"LAN receive aborted",
 	"LAN partial packet",
 	"LAN canceled",
 	NULL,					/* 0x0088 */
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	"SAS SMP request failed",		/* 0x0090 */
 	"SAS SMP data overrun",
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	"Inband aborted",			/* 0x0098 */
 	"No inband connection",
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	"Diagnostic released",			/* 0x00A0 */
 };
 
 const char *
 mps_ioc_status(U16 IOCStatus)
 {
 	static char buffer[16];
 
 	IOCStatus &= MPI2_IOCSTATUS_MASK;
 	if (IOCStatus < sizeof(mps_ioc_status_codes) / sizeof(char *) &&
 	    mps_ioc_status_codes[IOCStatus] != NULL)
 		return (mps_ioc_status_codes[IOCStatus]);
 	snprintf(buffer, sizeof(buffer), "Status: 0x%04x", IOCStatus);
 	return (buffer);
 }
 
 #ifdef USE_MPT_IOCTLS
 int
 mps_map_btdh(int fd, uint16_t *devhandle, uint16_t *bus, uint16_t *target)
 {
 	int error;
 	struct mps_btdh_mapping map;
 
 	bzero(&map, sizeof(map));
 	map.Bus = *bus;
 	map.TargetID = *target;
 	map.DevHandle = *devhandle;
 
 	if ((error = ioctl(fd, MPTIOCTL_BTDH_MAPPING, &map)) != 0) {
 		error = errno;
 		warn("Failed to map bus/target/device");
 		return (error);
 	}
 
 	*bus = map.Bus;
 	*target = map.TargetID;
 	*devhandle = map.DevHandle;
 
 	return (0);
 }
 
 int
 mps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
     MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
 {
 	MPI2_CONFIG_REQUEST req;
 	MPI2_CONFIG_REPLY reply;
 
 	bzero(&req, sizeof(req));
 	req.Function = MPI2_FUNCTION_CONFIG;
 	req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
 	req.Header.PageType = PageType;
 	req.Header.PageNumber = PageNumber;
 	req.PageAddress = PageAddress;
 
 	if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
 	    NULL, 0, NULL, 0, 30))
 		return (errno);
 
 	if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
 		if (IOCStatus != NULL)
 			*IOCStatus = reply.IOCStatus;
 		return (EIO);
 	}
 	if (header == NULL)
 		return (EINVAL);
 	*header = reply.Header;
 	return (0);
 }
 
 int
 mps_read_ext_config_page_header(int fd, U8 ExtPageType, U8 PageNumber, U32 PageAddress, MPI2_CONFIG_PAGE_HEADER *header, U16 *ExtPageLength, U16 *IOCStatus)
 {
 	MPI2_CONFIG_REQUEST req;
 	MPI2_CONFIG_REPLY reply;
 
 	bzero(&req, sizeof(req));
 	req.Function = MPI2_FUNCTION_CONFIG;
 	req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
 	req.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
 	req.ExtPageType = ExtPageType;
 	req.Header.PageNumber = PageNumber;
 	req.PageAddress = PageAddress;
 
 	if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
 	    NULL, 0, NULL, 0, 30))
 		return (errno);
 
 	if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
 		if (IOCStatus != NULL)
 			*IOCStatus = reply.IOCStatus;
 		return (EIO);
 	}
 	if ((header == NULL) || (ExtPageLength == NULL))
 		return (EINVAL);
 	*header = reply.Header;
 	*ExtPageLength = reply.ExtPageLength;
 	return (0);
 }
 
 void *
 mps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
     U16 *IOCStatus)
 {
 	MPI2_CONFIG_REQUEST req;
 	MPI2_CONFIG_PAGE_HEADER header;
 	MPI2_CONFIG_REPLY reply;
 	void *buf;
 	int error, len;
 
 	bzero(&header, sizeof(header));
 	error = mps_read_config_page_header(fd, PageType, PageNumber,
 	    PageAddress, &header, IOCStatus);
 	if (error) {
 		errno = error;
 		return (NULL);
 	}
 
 	bzero(&req, sizeof(req));
 	req.Function = MPI2_FUNCTION_CONFIG;
 	req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
 	req.PageAddress = PageAddress;
 	req.Header = header;
 	req.Header.PageLength = reply.Header.PageLength;
 	if (reply.Header.PageLength == 0)
 		req.Header.PageLength = 4;
 
 	len = req.Header.PageLength * 4;
 	buf = malloc(len);
 	if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
 	    buf, len, NULL, 0, 30)) {
 		error = errno;
 		free(buf);
 		errno = error;
 		return (NULL);
 	}
 	if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
 		if (IOCStatus != NULL)
 			*IOCStatus = reply.IOCStatus;
 		else
 			warnx("Reading config page failed: 0x%x %s",
 			    reply.IOCStatus, mps_ioc_status(reply.IOCStatus));
 		free(buf);
 		errno = EIO;
 		return (NULL);
 	}
 	return (buf);
 }
 
 void *
 mps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
     U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
 {
 	MPI2_CONFIG_REQUEST req;
 	MPI2_CONFIG_PAGE_HEADER header;
 	MPI2_CONFIG_REPLY reply;
 	U16 pagelen;
 	void *buf;
 	int error, len;
 
 	if (IOCStatus != NULL)
 		*IOCStatus = MPI2_IOCSTATUS_SUCCESS;
 	bzero(&header, sizeof(header));
 	error = mps_read_ext_config_page_header(fd, ExtPageType, PageNumber,
 	    PageAddress, &header, &pagelen, IOCStatus);
 	if (error) {
 		errno = error;
 		return (NULL);
 	}
 
 	bzero(&req, sizeof(req));
 	req.Function = MPI2_FUNCTION_CONFIG;
 	req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
 	req.PageAddress = PageAddress;
 	req.Header = header;
 	if (pagelen == 0)
 		pagelen = 4;
 	req.ExtPageLength = pagelen;
 	req.ExtPageType = ExtPageType;
 
 	len = pagelen * 4;
 	buf = malloc(len);
 	if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
 	    buf, len, NULL, 0, 30)) {
 		error = errno;
 		free(buf);
 		errno = error;
 		return (NULL);
 	}
 	if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
 		if (IOCStatus != NULL)
 			*IOCStatus = reply.IOCStatus;
 		else
 			warnx("Reading extended config page failed: %s",
 			    mps_ioc_status(reply.IOCStatus));
 		free(buf);
 		errno = EIO;
 		return (NULL);
 	}
 	return (buf);
 }
 
 #else
 
 int
 mps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
     MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
 {
 	struct mps_cfg_page_req req;
 
 	if (IOCStatus != NULL)
 		*IOCStatus = MPI2_IOCSTATUS_SUCCESS;
 	if (header == NULL)
 		return (EINVAL);
 	bzero(&req, sizeof(req));
 	req.header.PageType = PageType;
 	req.header.PageNumber = PageNumber;
 	req.page_address = PageAddress;
 	if (ioctl(fd, MPSIO_READ_CFG_HEADER, &req) < 0)
 		return (errno);
 	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
 		if (IOCStatus != NULL)
 			*IOCStatus = req.ioc_status;
 		return (EIO);
 	}
 	bcopy(&req.header, header, sizeof(*header));
 	return (0);
 }
 
 void *
 mps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
     U16 *IOCStatus)
 {
 	struct mps_cfg_page_req req;
 	void *buf;
 	int error;
 
 	error = mps_read_config_page_header(fd, PageType, PageNumber,
 	    PageAddress, &req.header, IOCStatus);
 	if (error) {
 		errno = error;
 		return (NULL);
 	}
 
 	if (req.header.PageLength == 0)
 		req.header.PageLength = 4;
 	req.len = req.header.PageLength * 4;
 	buf = malloc(req.len);
 	req.buf = buf;
 	bcopy(&req.header, buf, sizeof(req.header));
 	if (ioctl(fd, MPSIO_READ_CFG_PAGE, &req) < 0) {
 		error = errno;
 		free(buf);
 		errno = error;
 		return (NULL);
 	}
 	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
 		if (IOCStatus != NULL)
 			*IOCStatus = req.ioc_status;
 		else
 			warnx("Reading config page failed: 0x%x %s",
 			    req.ioc_status, mps_ioc_status(req.ioc_status));
 		free(buf);
 		errno = EIO;
 		return (NULL);
 	}
 	return (buf);
 }
 
 void *
 mps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
     U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
 {
 	struct mps_ext_cfg_page_req req;
 	void *buf;
 	int error;
 
 	if (IOCStatus != NULL)
 		*IOCStatus = MPI2_IOCSTATUS_SUCCESS;
 	bzero(&req, sizeof(req));
 	req.header.PageVersion = PageVersion;
 	req.header.PageNumber = PageNumber;
 	req.header.ExtPageType = ExtPageType;
 	req.page_address = PageAddress;
 	if (ioctl(fd, MPSIO_READ_EXT_CFG_HEADER, &req) < 0)
 		return (NULL);
 	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
 		if (IOCStatus != NULL)
 			*IOCStatus = req.ioc_status;
 		else
 			warnx("Reading extended config page header failed: %s",
 			    mps_ioc_status(req.ioc_status));
 		errno = EIO;
 		return (NULL);
 	}
 	req.len = req.header.ExtPageLength * 4;
 	buf = malloc(req.len);
 	req.buf = buf;
 	bcopy(&req.header, buf, sizeof(req.header));
 	if (ioctl(fd, MPSIO_READ_EXT_CFG_PAGE, &req) < 0) {
 		error = errno;
 		free(buf);
 		errno = error;
 		return (NULL);
 	}
 	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
 		if (IOCStatus != NULL)
 			*IOCStatus = req.ioc_status;
 		else
 			warnx("Reading extended config page failed: %s",
 			    mps_ioc_status(req.ioc_status));
 		free(buf);
 		errno = EIO;
 		return (NULL);
 	}
 	return (buf);
 }
 #endif
 
 #if 0
 int
 mpt_write_config_page(int fd, void *buf, U16 *IOCStatus)
 {
 	CONFIG_PAGE_HEADER *hdr;
 	struct mpt_cfg_page_req req;
 
 	if (IOCStatus != NULL)
 		*IOCStatus = MPI_IOCSTATUS_SUCCESS;
 	bzero(&req, sizeof(req));
 	req.buf = buf;
 	hdr = buf;
 	req.len = hdr->PageLength * 4;
 	if (ioctl(fd, MPTIO_WRITE_CFG_PAGE, &req) < 0)
 		return (errno);
 	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
 		if (IOCStatus != NULL) {
 			*IOCStatus = req.ioc_status;
 			return (0);
 		}
 		warnx("Writing config page failed: %s",
 		    mpt_ioc_status(req.ioc_status));
 		return (EIO);
 	}
 	return (0);
 }
 
 int
 mpt_raid_action(int fd, U8 Action, U8 VolumeBus, U8 VolumeID, U8 PhysDiskNum,
     U32 ActionDataWord, void *buf, int len, RAID_VOL0_STATUS *VolumeStatus,
     U32 *ActionData, int datalen, U16 *IOCStatus, U16 *ActionStatus, int write)
 {
 	struct mpt_raid_action raid_act;
 
 	if (IOCStatus != NULL)
 		*IOCStatus = MPI_IOCSTATUS_SUCCESS;
 	if (datalen < 0 || (unsigned)datalen > sizeof(raid_act.action_data))
 		return (EINVAL);
 	bzero(&raid_act, sizeof(raid_act));
 	raid_act.action = Action;
 	raid_act.volume_bus = VolumeBus;
 	raid_act.volume_id = VolumeID;
 	raid_act.phys_disk_num = PhysDiskNum;
 	raid_act.action_data_word = ActionDataWord;
 	if (buf != NULL && len != 0) {
 		raid_act.buf = buf;
 		raid_act.len = len;
 		raid_act.write = write;
 	}
 
 	if (ioctl(fd, MPTIO_RAID_ACTION, &raid_act) < 0)
 		return (errno);
 
 	if (!IOC_STATUS_SUCCESS(raid_act.ioc_status)) {
 		if (IOCStatus != NULL) {
 			*IOCStatus = raid_act.ioc_status;
 			return (0);
 		}
 		warnx("RAID action failed: %s",
 		    mpt_ioc_status(raid_act.ioc_status));
 		return (EIO);
 	}
 
 	if (ActionStatus != NULL)
 		*ActionStatus = raid_act.action_status;
 	if (raid_act.action_status != MPI_RAID_ACTION_ASTATUS_SUCCESS) {
 		if (ActionStatus != NULL)
 			return (0);
 		warnx("RAID action failed: %s",
 		    mpt_raid_status(raid_act.action_status));
 		return (EIO);
 	}
 
 	if (VolumeStatus != NULL)
 		*((U32 *)VolumeStatus) = raid_act.volume_status;
 	if (ActionData != NULL)
 		bcopy(raid_act.action_data, ActionData, datalen);
 	return (0);
 }
 #endif
 
 int
 mps_open(int unit)
 {
 	char path[MAXPATHLEN];
 
-	snprintf(path, sizeof(path), "/dev/mps%d", unit);
+	snprintf(path, sizeof(path), "/dev/mp%s%d", is_mps ? "s": "r", unit);
 	return (open(path, O_RDWR));
 }
 
 int
 mps_user_command(int fd, void *req, uint32_t req_len, void *reply,
         uint32_t reply_len, void *buffer, int len, uint32_t flags)
 {
 	struct mps_usr_command cmd;
 
 	bzero(&cmd, sizeof(struct mps_usr_command));
 	cmd.req = req;
 	cmd.req_len = req_len;
 	cmd.rpl = reply;
 	cmd.rpl_len = reply_len;
 	cmd.buf = buffer;
 	cmd.len = len;
 	cmd.flags = flags;
 
 	if (ioctl(fd, MPSIO_MPS_COMMAND, &cmd) < 0)
 		return (errno);
 	return (0);
 }
 
 int
 mps_pass_command(int fd, void *req, uint32_t req_len, void *reply,
 	uint32_t reply_len, void *data_in, uint32_t datain_len, void *data_out,
 	uint32_t dataout_len, uint32_t timeout)
 {
 	struct mps_pass_thru pass;
 
 	pass.PtrRequest = (uint64_t)(uintptr_t)req;
 	pass.PtrReply = (uint64_t)(uintptr_t)reply;
 	pass.PtrData = (uint64_t)(uintptr_t)data_in;
 	pass.PtrDataOut = (uint64_t)(uintptr_t)data_out;
 	pass.RequestSize = req_len;
 	pass.ReplySize = reply_len;
 	pass.DataSize = datain_len;
 	pass.DataOutSize = dataout_len;
 	if (datain_len && dataout_len)
 		pass.DataDirection = MPS_PASS_THRU_DIRECTION_BOTH;
 	else if (datain_len)
 		pass.DataDirection = MPS_PASS_THRU_DIRECTION_READ;
 	else if (dataout_len)
 		pass.DataDirection = MPS_PASS_THRU_DIRECTION_WRITE;
 	else
 		pass.DataDirection = MPS_PASS_THRU_DIRECTION_NONE;
 	pass.Timeout = timeout;
 
 	if (ioctl(fd, MPTIOCTL_PASS_THRU, &pass) < 0)
 		return (errno);
 	return (0);
 }
 
 MPI2_IOC_FACTS_REPLY *
 mps_get_iocfacts(int fd)
 {
 	MPI2_IOC_FACTS_REPLY *facts;
 	MPI2_IOC_FACTS_REQUEST req;
 	int error;
 
 	facts = malloc(sizeof(MPI2_IOC_FACTS_REPLY));
 	if (facts == NULL) {
 		errno = ENOMEM;
 		return (NULL);
 	}
 
 	bzero(&req, sizeof(MPI2_IOC_FACTS_REQUEST));
 	req.Function = MPI2_FUNCTION_IOC_FACTS;
 
 #if 1
 	error = mps_pass_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
 	    facts, sizeof(MPI2_IOC_FACTS_REPLY), NULL, 0, NULL, 0, 10);
 #else
 	error = mps_user_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
 	    facts, sizeof(MPI2_IOC_FACTS_REPLY), NULL, 0, 0);
 #endif
 	if (error) {
 		free(facts);
 		return (NULL);
 	}
 
 	if (!IOC_STATUS_SUCCESS(facts->IOCStatus)) {
 		free(facts);
 		errno = EINVAL;
 		return (NULL);
 	}
 	return (facts);
 }
 
Index: projects/mpsutil/usr.sbin/mpsutil/mps_show.c
===================================================================
--- projects/mpsutil/usr.sbin/mpsutil/mps_show.c	(revision 289363)
+++ projects/mpsutil/usr.sbin/mpsutil/mps_show.c	(revision 289364)
@@ -1,758 +1,759 @@
 /*-
  * Copyright (c) 2008 Yahoo!, Inc.
  * All rights reserved.
  * Written by: John Baldwin <jhb@FreeBSD.org>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  * 3. Neither the name of the author nor the names of any co-contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
 
 #include <sys/cdefs.h>
 __RCSID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/errno.h>
 #include <err.h>
 #include <libutil.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include "mpsutil.h"
 
 static char * get_device_speed(uint8_t rate);
 static char * get_device_type(uint32_t di);
 static int show_all(int ac, char **av);
 static int show_devices(int ac, char **av);
 static int show_enclosures(int ac, char **av);
 static int show_expanders(int ac, char **av);
 
 MPS_TABLE(top, show);
 
 #define	STANDALONE_STATE	"ONLINE"
 
 static int
 show_adapter(int ac, char **av)
 {
 	MPI2_CONFIG_PAGE_SASIOUNIT_0	*sas0;
 	MPI2_CONFIG_PAGE_SASIOUNIT_1	*sas1;
 	MPI2_SAS_IO_UNIT0_PHY_DATA	*phy0;
 	MPI2_SAS_IO_UNIT1_PHY_DATA	*phy1;
 	MPI2_CONFIG_PAGE_MAN_0 *man0;
 	MPI2_CONFIG_PAGE_BIOS_3 *bios3;
 	MPI2_IOC_FACTS_REPLY *facts;
 	U16 IOCStatus;
 	char *speed, *minspeed, *maxspeed, *isdisabled, *type;
 	char devhandle[5], ctrlhandle[5];
 	int error, fd, v, i;
 
 	if (ac != 1) {
 		warnx("show adapter: extra arguments");
 		return (EINVAL);
 	}
 
 	fd = mps_open(mps_unit);
 	if (fd < 0) {
 		error = errno;
 		warn("mps_open");
 		return (error);
 	}
 
 	man0 = mps_read_man_page(fd, 0, NULL);
 	if (man0 == NULL) {
 		error = errno;
 		warn("Failed to get controller info");
 		return (error);
 	}
 	if (man0->Header.PageLength < sizeof(*man0) / 4) {
 		warnx("Invalid controller info");
 		return (EINVAL);
 	}
 	printf("mps%d Adapter:\n", mps_unit);
 	printf("       Board Name: %.16s\n", man0->BoardName);
 	printf("   Board Assembly: %.16s\n", man0->BoardAssembly);
 	printf("        Chip Name: %.16s\n", man0->ChipName);
 	printf("    Chip Revision: %.16s\n", man0->ChipRevision);
 	free(man0);
 
 	bios3 = mps_read_config_page(fd, MPI2_CONFIG_PAGETYPE_BIOS, 3, 0, NULL);
 	if (bios3 == NULL) {
 		error = errno;
 		warn("Failed to get BIOS page 3 info");
 		return (error);
 	}
 	v = bios3->BiosVersion;
 	printf("    BIOS Revision: %d.%02d.%02d.%02d\n",
 	    ((v & 0xff000000) >> 24), ((v &0xff0000) >> 16),
 	    ((v & 0xff00) >> 8), (v & 0xff));
 	free(bios3);
 
 	if ((facts = mps_get_iocfacts(fd)) == NULL) {
 		printf("could not get controller IOCFacts\n");
 		close(fd);
 		return (errno);
 	}
 	v = facts->FWVersion.Word;
 	printf("Firmware Revision: %d.%02d.%02d.%02d\n",
 	    ((v & 0xff000000) >> 24), ((v &0xff0000) >> 16),
 	    ((v & 0xff00) >> 8), (v & 0xff));
 	printf("  Integrated RAID: %s\n",
 	    (facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID)
 	    ? "yes" : "no");
 	free(facts);
 
 	fd = mps_open(mps_unit);
 	if (fd < 0) {
 		error = errno;
 		warn("mps_open");
 		return (error);
 	}
 
 	sas0 = mps_read_extended_config_page(fd,
 	    MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
 	    MPI2_SASIOUNITPAGE0_PAGEVERSION, 0, 0, &IOCStatus);
 	if (sas0 == NULL) {
 		error = errno;
 		warn("Error retrieving SAS IO Unit page %d", IOCStatus);
 		return (error);
 	}
 
 	sas1 = mps_read_extended_config_page(fd,
 	    MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
 	    MPI2_SASIOUNITPAGE1_PAGEVERSION, 1, 0, &IOCStatus);
 	if (sas0 == NULL) {
 		error = errno;
 		warn("Error retrieving SAS IO Unit page %d", IOCStatus);
 		return (error);
 	}
 	printf("\n");
 
 	printf("PhyNum  CtlrHandle  DevHandle  Disabled  Speed   Min    Max      Device\n");
 	for (i = 0; i < sas0->NumPhys; i++) {
 		phy0 = &sas0->PhyData[i];
 		phy1 = &sas1->PhyData[i];
 		printf("  %d  ", i);
 		if (phy0->PortFlags &
 		     MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS) {
 			printf("Discovery still in progress\n");
 			continue;
 		}
 		if (phy0->PhyFlags & MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED)
 			isdisabled = "Y";
 		else
 			isdisabled = "N";
 
 		minspeed = get_device_speed(phy1->MaxMinLinkRate);
 		maxspeed = get_device_speed(phy1->MaxMinLinkRate >> 4);
 		type = get_device_type(phy0->ControllerPhyDeviceInfo);
 
 		if (phy0->AttachedDevHandle != 0) {
 			snprintf(devhandle, 5, "%04x", phy0->AttachedDevHandle);
 			snprintf(ctrlhandle, 5, "%04x",
 			    phy0->ControllerDevHandle);
 			speed = get_device_speed(phy0->NegotiatedLinkRate);
 		} else {
 			snprintf(devhandle, 5, "    ");
 			snprintf(ctrlhandle, 5, "    ");
 			speed = "     ";
 		}
 		printf("      %s       %s        %s      %s  %s  %s  %s\n",
 		    ctrlhandle, devhandle, isdisabled, speed, minspeed,
 		    maxspeed, type);
 	}
 	free(sas0);
 	free(sas1);
 	printf("\n");
 	close(fd);
 	return (0);
 }
 
 MPS_COMMAND(show, adapter, show_adapter, "", "display controller information")
 
 static int
 show_iocfacts(int ac, char **av)
 {
 	MPI2_IOC_FACTS_REPLY *facts;
 	int error, fd;
 
 	fd = mps_open(mps_unit);
 	if (fd < 0) {
 		error = errno;
 		warn("mps_open");
 		return (error);
 	}
 
 	if ((facts = mps_get_iocfacts(fd)) == NULL) {
 		printf("could not get controller IOCFacts\n");
 		close(fd);
 		return (errno);
 	}
 
 	printf("       MaxChainDepth: %d\n", facts->MaxChainDepth);
 	printf("             WhoInit: 0x%x\n", facts->WhoInit);
 	printf("       NumberOfPorts: %d\n", facts->NumberOfPorts);
 	printf("      MaxMSIxVectors: %d\n", facts->MaxMSIxVectors);
 	printf("       RequestCredit: %d\n", facts->RequestCredit);
 	printf("           ProductID: 0x%x\n", facts->ProductID);
 	printf("     IOCCapabilities: 0x%x\n", facts->IOCCapabilities);
 	printf("           FWVersion: 0x%08x\n", facts->FWVersion.Word);
 	printf(" IOCRequestFrameSize: %d\n", facts->IOCRequestFrameSize);
 	printf("       MaxInitiators: %d\n", facts->MaxInitiators);
 	printf("          MaxTargets: %d\n", facts->MaxTargets);
 	printf("     MaxSasExpanders: %d\n", facts->MaxSasExpanders);
 	printf("       MaxEnclosures: %d\n", facts->MaxEnclosures);
 	printf("       ProtocolFlags: 0x%x\n", facts->ProtocolFlags);
 	printf("  HighPriorityCredit: %d\n", facts->HighPriorityCredit);
 	printf("MaxRepDescPostQDepth: %d\n",
 	    facts->MaxReplyDescriptorPostQueueDepth);
 	printf("      ReplyFrameSize: %d\n", facts->ReplyFrameSize);
 	printf("          MaxVolumes: %d\n", facts->MaxVolumes);
 	printf("        MaxDevHandle: %d\n", facts->MaxDevHandle);
 	printf("MaxPersistentEntries: %d\n", facts->MaxPersistentEntries);
 	printf("        MinDevHandle: %d\n", facts->MinDevHandle);
 
 	free(facts);
 	return (0);
 }
 
 MPS_COMMAND(show, iocfacts, show_iocfacts, "", "Show IOC Facts Message");
 
 static int
 show_adapters(int ac, char **av)
 {
 	MPI2_CONFIG_PAGE_MAN_0 *man0;
 	MPI2_IOC_FACTS_REPLY *facts;
 	int unit, fd, error;
 
 	printf("Device Name\t      Chip Name        Board Name        Firmware\n");
 	for (unit = 0; unit < MPS_MAX_UNIT; unit++) {
 		fd = mps_open(unit);
 		if (fd < 0)
 			continue;
 		facts = mps_get_iocfacts(fd);
 		if (facts == NULL) {
 			error = errno;
 			warn("Faled to get controller iocfacts");
 			close(fd);
 			return (error);
 		}
 		man0 = mps_read_man_page(fd, 0, NULL);
 		if (man0 == NULL) {
 			error = errno;
 			warn("Failed to get controller info");
 			close(fd);
 			return (error);
 		}
 		if (man0->Header.PageLength < sizeof(*man0) / 4) {
 			warnx("Invalid controller info");
 			close(fd);
 			free(man0);
 			return (EINVAL);
 		}
-		printf("/dev/mps%d\t%16s %16s        %08x\n", unit,
+		printf("/dev/mp%s%d\t%16s %16s        %08x\n",
+		    is_mps ? "s": "r", unit,
 		    man0->ChipName, man0->BoardName, facts->FWVersion.Word);
 		free(man0);
 		free(facts);
 		close(fd);
 	}
 	return (0);
 }
 MPS_COMMAND(show, adapters, show_adapters, "", "Show a summary of all adapters");
 
 static char *
 get_device_type(uint32_t di)
 {
 
 	if (di & 0x4000)
 		return ("SEP Target    ");
 	if (di & 0x2000)
 		return ("ATAPI Target  ");
 	if (di & 0x400)
 		return ("SAS Target    ");
 	if (di & 0x200)
 		return ("STP Target    ");
 	if (di & 0x100)
 		return ("SMP Target    ");
 	if (di & 0x80)
 		return ("SATA Target   ");
 	if (di & 0x70)
 		return ("SAS Initiator ");
 	if (di & 0x8)
 		return ("SATA Initiator");
 	if ((di & 0x7) == 0)
 		return ("No Device     ");
 	return ("Unknown Device");
 }
 
 static char *
 get_enc_type(uint32_t flags, int *issep)
 {
 	char *type;
 
 	*issep = 0;
 	switch (flags & 0xf) {
 	case 0x01:
 		type = "Direct Attached SES-2";
 		*issep = 1;
 		break;
 	case 0x02:
 		type = "Direct Attached SGPIO";
 		break;
 	case 0x03:
 		type = "Expander SGPIO";
 		break;
 	case 0x04:
 		type = "External SES-2";
 		*issep = 1;
 		break;
 	case 0x05:
 		type = "Direct Attached GPIO";
 		break;
 	case 0x0:
 	default:
 		return ("Unknown");
 	}
 
 	return (type);
 }
 
 static char *
 mps_device_speed[] = {
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	"1.5",
 	"3.0",
 	"6.0",
 	"12 "
 };
 
 static char *
 get_device_speed(uint8_t rate)
 {
 	char *speed;
 
 	rate &= 0xf;
 	if (rate >= sizeof(mps_device_speed))
 		return ("Unk");
 
 	if ((speed = mps_device_speed[rate]) == NULL)
 		return ("???");
 	return (speed);
 }
 
 static char *
 mps_page_name[] = {
 	"IO Unit",
 	"IOC",
 	"BIOS",
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	"RAID Volume",
 	"Manufacturing",
 	"RAID Physical Disk",
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	NULL,
 	"SAS IO Unit",
 	"SAS Expander",
 	"SAS Device",
 	"SAS PHY",
 	"Log",
 	"Enclosure",
 	"RAID Configuration",
 	"Driver Persistent Mapping",
 	"SAS Port",
 	"Ethernet Port",
 	"Extended Manufacturing"
 };
 
 static char *
 get_page_name(u_int page)
 {
 	char *name;
 
 	if (page >= sizeof(mps_page_name))
 		return ("Unknown");
 	if ((name = mps_page_name[page]) == NULL)
 		return ("Unknown");
 	return (name);
 }
 
 static int
 show_all(int ac, char **av)
 {
 	int error;
 
 	printf("Adapter:\n");
 	error = show_adapter(ac, av);
 	printf("Devices:\n");
 	error = show_devices(ac, av);
 	printf("Enclosures:\n");
 	error = show_enclosures(ac, av);
 	printf("Expanders:\n");
 	error = show_expanders(ac, av);
 	return (error);
 }
 MPS_COMMAND(show, all, show_all, "", "Show all devices");
 
 static int
 show_devices(int ac, char **av)
 {
 	MPI2_CONFIG_PAGE_SASIOUNIT_0	*sas0;
 	MPI2_SAS_IO_UNIT0_PHY_DATA	*phydata;
 	MPI2_CONFIG_PAGE_SAS_DEV_0	*device;
 	MPI2_CONFIG_PAGE_EXPANDER_1	*exp1;
 	uint16_t IOCStatus, handle, bus, target;
 	char *type, *speed, enchandle[5], slot[3], bt[7];
 	int fd, error, nphys;
 
 	fd = mps_open(mps_unit);
 	if (fd < 0) {
 		error = errno;
 		warn("mps_open");
 		return (error);
 	}
 
 	sas0 = mps_read_extended_config_page(fd,
 	    MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
 	    MPI2_SASIOUNITPAGE0_PAGEVERSION, 0, 0, &IOCStatus);
 	if (sas0 == NULL) {
 		error = errno;
 		warn("Error retrieving SAS IO Unit page %d", IOCStatus);
 		return (error);
 	}
 	nphys = sas0->NumPhys;
 
 	printf("B____T    SAS Address     Handle  Parent    Device       Speed Enc  Slot  Wdt\n");
 	handle = 0xffff;
 	while (1) {
 		device = mps_read_extended_config_page(fd,
 		    MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE,
 		    MPI2_SASDEVICE0_PAGEVERSION, 0,
 		    MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE | handle,
 		    &IOCStatus);
 		if (device == NULL) {
 			if (IOCStatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
 				break;
 			error = errno;
 			warn("Error retrieving device page");
 			return (error);
 		}
 		handle = device->DevHandle;
 
 		if (device->ParentDevHandle == 0x0) {
 			free(device);
 			continue;
 		}
 
 		bus = 0xffff;
 		target = 0xffff;
 		error = mps_map_btdh(fd, &handle, &bus, &target);
 		if (error) {
 			free(device);
 			continue;
 		}
 		if ((bus == 0xffff) || (target == 0xffff))
 			snprintf(bt, 7, "      ");
 		else
 			snprintf(bt, 7, "%02d  %02d", bus, target);
 
 		type = get_device_type(device->DeviceInfo);
 
 		if (device->PhyNum < nphys) {
 			phydata = &sas0->PhyData[device->PhyNum];
 			speed = get_device_speed(phydata->NegotiatedLinkRate);
 		} else if (device->ParentDevHandle > 0) {
 			exp1 = mps_read_extended_config_page(fd,
 			    MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER,
 			    MPI2_SASEXPANDER1_PAGEVERSION, 1,
 			    MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM |
 			    (device->PhyNum <<
 			    MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT) |
 			    device->ParentDevHandle, &IOCStatus);
 			if (exp1 == NULL) {
 				if (IOCStatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
 					error = errno;
 					warn("Error retrieving expander page 1: 0x%x",
 					    IOCStatus);
 					return (error);
 				}
 				speed = " ";
 			} else {
 				speed = get_device_speed(exp1->NegotiatedLinkRate);
 				free(exp1);
 			}
 		} else
 			speed = " ";
 
 		if (device->EnclosureHandle != 0) {
 			snprintf(enchandle, 5, "%04x", device->EnclosureHandle);
 			snprintf(slot, 3, "%02d", device->Slot);
 		} else {
 			snprintf(enchandle, 5, "    ");
 			snprintf(slot, 3, "  ");
 		}
 		printf("%s    %08x%08x   %04x    %04x   %s  %s  %s  %s    %d\n",
 		    bt, device->SASAddress.High, device->SASAddress.Low,
 		    device->DevHandle, device->ParentDevHandle, type, speed,
 		    enchandle, slot, device->MaxPortConnections);
 		free(device);
 	}
 	printf("\n");
 	free(sas0);
 	close(fd);
 	return (0);
 }
 MPS_COMMAND(show, devices, show_devices, "", "Show attached devices");
 
 static int
 show_enclosures(int ac, char **av)
 {
 	MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0 *enc;
 	char *type, sepstr[5];
 	uint16_t IOCStatus, handle;
 	int fd, error, issep;
 
 	fd = mps_open(mps_unit);
 	if (fd < 0) {
 		error = errno;
 		warn("mps_open");
 		return (error);
 	}
 
 	printf("Slots      Logical ID     SEPHandle  EncHandle    Type\n");
 	handle = 0xffff;
 	while (1) {
 		enc = mps_read_extended_config_page(fd,
 		    MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE,
 		    MPI2_SASENCLOSURE0_PAGEVERSION, 0,
 		    MPI2_SAS_ENCLOS_PGAD_FORM_GET_NEXT_HANDLE | handle,
 		    &IOCStatus);
 		if (enc == NULL) {
 			if (IOCStatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
 				break;
 			error = errno;
 			warn("Error retrieving enclosure page");
 			return (error);
 		}
 		type = get_enc_type(enc->Flags, &issep);
 		if (issep == 0)
 			snprintf(sepstr, 5, "    ");
 		else
 			snprintf(sepstr, 5, "%04x", enc->SEPDevHandle);
 		printf("  %.2d    %08x%08x    %s       %04x     %s\n",
 		    enc->NumSlots, enc->EnclosureLogicalID.High,
 		    enc->EnclosureLogicalID.Low, sepstr, enc->EnclosureHandle,
 		    type);
 		handle = enc->EnclosureHandle;
 		free(enc);
 	}
 	printf("\n");
 	close(fd);
 	return (0);
 }
 MPS_COMMAND(show, enclosures, show_enclosures, "", "Show attached enclosures");
 
 static int
 show_expanders(int ac, char **av)
 {
 	MPI2_CONFIG_PAGE_EXPANDER_0	*exp0;
 	MPI2_CONFIG_PAGE_EXPANDER_1	*exp1;
 	uint16_t IOCStatus, handle;
 	char enchandle[5], parent[5], rphy[3], rhandle[5];
 	char *speed, *min, *max, *type;
 	int fd, error, nphys, i;
 
 	fd = mps_open(mps_unit);
 	if (fd < 0) {
 		error = errno;
 		warn("mps_open");
 		return (error);
 	}
 
 	printf("NumPhys   SAS Address     DevHandle   Parent  EncHandle  SAS Level\n");
 	handle = 0xffff;
 	while (1) {
 		exp0 = mps_read_extended_config_page(fd,
 		    MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER,
 		    MPI2_SASEXPANDER0_PAGEVERSION, 0,
 		    MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL | handle,
 		    &IOCStatus);
 		if (exp0 == NULL) {
 			if (IOCStatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
 				break;
 			error = errno;
 			warn("Error retrieving expander page 0");
 			return (error);
 		}
 
 		nphys = exp0->NumPhys;
 		handle = exp0->DevHandle;
 
 		if (exp0->EnclosureHandle == 0x00)
 			snprintf(enchandle, 5, "    ");
 		else
 			snprintf(enchandle, 5, "%04d", exp0->EnclosureHandle);
 		if (exp0->ParentDevHandle == 0x0)
 			snprintf(parent, 5, "    ");
 		else
 			snprintf(parent, 5, "%04x", exp0->ParentDevHandle);
 		printf("  %02d    %08x%08x    %04x       %s     %s       %d\n",
 		    exp0->NumPhys, exp0->SASAddress.High, exp0->SASAddress.Low,
 		    exp0->DevHandle, parent, enchandle, exp0->SASLevel);
 
 		printf("\n");
 		printf("     Phy  RemotePhy  DevHandle  Speed   Min    Max    Device\n");
 		for (i = 0; i < nphys; i++) {
 			exp1 = mps_read_extended_config_page(fd,
 			    MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER,
 			    MPI2_SASEXPANDER1_PAGEVERSION, 1,
 			    MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM |
 			    (i << MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT) |
 			    exp0->DevHandle, &IOCStatus);
 			if (exp1 == NULL) {
 				if (IOCStatus !=
 				    MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
 					warn("Error retrieving expander pg 1");
 				continue;
 			}
 			type = get_device_type(exp1->AttachedDeviceInfo);
 			if ((exp1->AttachedDeviceInfo &0x7) == 0) {
 				speed = "     ";
 				snprintf(rphy, 3, "  ");
 				snprintf(rhandle, 5, "     ");
 			} else {
 				speed = get_device_speed(
 				    exp1->NegotiatedLinkRate);
 				snprintf(rphy, 3, "%02d",
 				    exp1->AttachedPhyIdentifier);
 				snprintf(rhandle, 5, "%04x",
 				    exp1->AttachedDevHandle);
 			}
 			min = get_device_speed(exp1->HwLinkRate);
 			max = get_device_speed(exp1->HwLinkRate >> 4);
 			printf("     %02d     %s         %s     %s  %s  %s  %s\n", exp1->Phy, rphy, rhandle, speed, min, max, type);
 
 			free(exp1);
 		}
 		free(exp0);
 	}
 
 	printf("\n");
 	close(fd);
 	return (0);
 }
 
 MPS_COMMAND(show, expanders, show_expanders, "", "Show attached expanders");
 
 static int
 show_cfgpage(int ac, char **av)
 {
 	MPI2_CONFIG_PAGE_HEADER *hdr;
 	MPI2_CONFIG_EXTENDED_PAGE_HEADER *ehdr;
 	void *data;
 	uint32_t addr;
 	uint16_t IOCStatus;
 	uint8_t page, num;
 	int fd, error, len, attrs;
 	char *pgname, *pgattr;
 
 	fd = mps_open(mps_unit);
 	if (fd < 0) {
 		error = errno;
 		warn("mps_open");
 		return (error);
 	}
 
 	addr = 0;
 	num = 0;
 	page = 0;
 
 	switch (ac) {
 	case 4:
 		addr = (uint32_t)strtoul(av[3], NULL, 0);
 	case 3:
 		num = (uint8_t)strtoul(av[2], NULL, 0);
 	case 2:
 		page = (uint8_t)strtoul(av[1], NULL, 0);
 		break;
 	default:
 		errno = EINVAL;
 		warn("cfgpage: not enough arguments");
 		return (EINVAL);
 	}
 
 	if (page >= 0x10)
 		data = mps_read_extended_config_page(fd, page, 0, num, addr,
 		    &IOCStatus);
 	 else 
 		data = mps_read_config_page(fd, page, num, addr, &IOCStatus);
 
 	if (data == NULL) {
 		error = errno;
 		warn("Error retrieving cfg page: %s\n",
 		    mps_ioc_status(IOCStatus));
 		return (error);
 	}
 
 	if (page >= 0x10) {
 		ehdr = data;
 		len = ehdr->ExtPageLength * 4;
 		page = ehdr->ExtPageType;
 		attrs = ehdr->PageType >> 4;
 	} else {
 		hdr = data;
 		len = hdr->PageLength * 4;
 		page = hdr->PageType & 0xf;
 		attrs = hdr->PageType >> 4;
 	}
 
 	pgname = get_page_name(page);
 	if (attrs == 0)
 		pgattr = "Read-only";
 	else if (attrs == 1)
 		pgattr = "Read-Write";
 	else if (attrs == 2)
 		pgattr = "Read-Write Persistent";
 	else
 		pgattr = "Unknown Page Attribute";
 
 	printf("Page 0x%x: %s %d, %s\n", page, pgname, num, pgattr);
 	hexdump(data, len, NULL, HD_REVERSED | 4);
 	free(data);
 	return (0);
 }
 
 MPS_COMMAND(show, cfgpage, show_cfgpage, "page [num] [addr]", "Display config page");
Index: projects/mpsutil/usr.sbin/mpsutil/mpsutil.c
===================================================================
--- projects/mpsutil/usr.sbin/mpsutil/mpsutil.c	(revision 289363)
+++ projects/mpsutil/usr.sbin/mpsutil/mpsutil.c	(revision 289364)
@@ -1,200 +1,203 @@
 /*-
  * Copyright (c) 2008 Yahoo!, Inc.
  * All rights reserved.
  * Written by: John Baldwin <jhb@FreeBSD.org>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  * 3. Neither the name of the author nor the names of any co-contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
 
 #include <sys/cdefs.h>
 __RCSID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/errno.h>
 #include <err.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include "mpsutil.h"
 
 SET_DECLARE(MPS_DATASET(top), struct mpsutil_command);
 SET_DECLARE(MPS_DATASET(usage), struct mpsutil_usage);
 
 int mps_unit;
+int is_mps;
 
 static void
 usage(void)
 {
 	struct mpsutil_usage **cmd;
 	const char *args, *desc;
 
-	fprintf(stderr, "usage: mpsutil [-u unit] <command> ...\n\n");
+	fprintf(stderr, "usage: %s [-u unit] <command> ...\n\n", getprogname());
 	fprintf(stderr, "Commands include:\n");
 	SET_FOREACH(cmd, MPS_DATASET(usage)) {
 		if (*cmd == NULL)
 			fprintf(stderr, "\n");
 		else
 			(*cmd)->handler(&args, &desc);
 			if (strncmp((*cmd)->set, "top", 3) == 0)
 				fprintf(stderr, "%s %-30s\t%s\n",
 				    (*cmd)->name, args, desc);
 			else
 				fprintf(stderr, "%s %s %-30s\t%s\n",
 				    (*cmd)->set, (*cmd)->name, args, desc);
 	}
 	exit(1);
 }
 
 static int
 version(int ac, char **av)
 {
 
-	printf("mpsutil: version %s", MPSUTIL_VERSION);
+	printf("%s: version %s", MPSUTIL_VERSION, getprogname());
 #ifdef DEBUG
 	printf(" (DEBUG)");
 #endif
 	printf("\n");
 	return (0);
 }
 
 MPS_COMMAND(top, version, version, "", "version")
 
 int
 main(int ac, char **av)
 {
 	struct mpsutil_command **cmd;
 	int ch;
+
+	is_mps = !strcmp(getprogname(), "mpsutil");
 
 	while ((ch = getopt(ac, av, "u:h?")) != -1) {
 		switch (ch) {
 		case 'u':
 			mps_unit = atoi(optarg);
 			break;
 		case 'h':
 		case '?':
 			usage();
 			return (1);
 		}
 	}
 
 	av += optind;
 	ac -= optind;
 
 	/* getopt() eats av[0], so we can't use mpt_table_handler() directly. */
 	if (ac == 0) {
 		usage();
 		return (1);
 	}
 
 	SET_FOREACH(cmd, MPS_DATASET(top)) {
 		if (strcmp((*cmd)->name, av[0]) == 0) {
 			if ((*cmd)->handler(ac, av))
 				return (1);
 			else
 				return (0);
 		}
 	}
 	warnx("Unknown command %s.", av[0]);
 	return (1);
 }
 
 int
 mps_table_handler(struct mpsutil_command **start, struct mpsutil_command **end,
     int ac, char **av)
 {
 	struct mpsutil_command **cmd;
 
 	if (ac < 2) {
 		warnx("The %s command requires a sub-command.", av[0]);
 		return (EINVAL);
 	}
 	for (cmd = start; cmd < end; cmd++) {
 		if (strcmp((*cmd)->name, av[1]) == 0)
 			return ((*cmd)->handler(ac - 1, av + 1));
 	}
 
 	warnx("%s is not a valid sub-command of %s.", av[1], av[0]);
 	return (ENOENT);
 }
 
 void
 hexdump(const void *ptr, int length, const char *hdr, int flags)
 {
 	int i, j, k;
 	int cols;
 	const unsigned char *cp;
 	char delim;
 
 	if ((flags & HD_DELIM_MASK) != 0)
 		delim = (flags & HD_DELIM_MASK) >> 8;
 	else
 		delim = ' ';
 
 	if ((flags & HD_COLUMN_MASK) != 0)
 		cols = flags & HD_COLUMN_MASK;
 	else
 		cols = 16;
 
 	cp = ptr;
 	for (i = 0; i < length; i+= cols) {
 		if (hdr != NULL)
 			printf("%s", hdr);
 
 		if ((flags & HD_OMIT_COUNT) == 0)
 			printf("%04x  ", i);
 
 		if ((flags & HD_OMIT_HEX) == 0) {
 			for (j = 0; j < cols; j++) {
 				if (flags & HD_REVERSED)
 					k = i + (cols - 1 - j);
 				else
 					k = i + j;
 				if (k < length)
 					printf("%c%02x", delim, cp[k]);
 				else
 					printf("   ");
 			}
 		}
 
 		if ((flags & HD_OMIT_CHARS) == 0) {
 			printf("  |");
 			for (j = 0; j < cols; j++) {
 				if (flags & HD_REVERSED)
 					k = i + (cols - 1 - j);
 				else
 					k = i + j;
 				if (k >= length)
 					printf(" ");
 				else if (cp[k] >= ' ' && cp[k] <= '~')
 					printf("%c", cp[k]);
 				else
 					printf(".");
 			}
 			printf("|");
 		}
 		printf("\n");
 	}
 }
Index: projects/mpsutil/usr.sbin/mpsutil/mpsutil.h
===================================================================
--- projects/mpsutil/usr.sbin/mpsutil/mpsutil.h	(revision 289363)
+++ projects/mpsutil/usr.sbin/mpsutil/mpsutil.h	(revision 289364)
@@ -1,200 +1,201 @@
 /*-
  * Copyright (c) 2008 Yahoo!, Inc.
  * All rights reserved.
  * Written by: John Baldwin <jhb@FreeBSD.org>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  * 3. Neither the name of the author nor the names of any co-contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  * $FreeBSD$
  */
 
 #ifndef __MPSUTIL_H__
 #define	__MPSUTIL_H__
 
 #include <sys/cdefs.h>
 #include <sys/linker_set.h>
 
 #include <dev/mps/mpi/mpi2_type.h>
 #include <dev/mps/mpi/mpi2.h>
 #include <dev/mps/mpi/mpi2_cnfg.h>
 #include <dev/mps/mpi/mpi2_raid.h>
 #include <dev/mps/mpi/mpi2_ioc.h>
 
 #define MPSUTIL_VERSION	"1.0.0"
 
 #define	IOC_STATUS_SUCCESS(status)					\
 	(((status) & MPI2_IOCSTATUS_MASK) == MPI2_IOCSTATUS_SUCCESS)
 
 struct mpsutil_command {
 	const char *name;
 	int (*handler)(int ac, char **av);
 };
 struct mpsutil_usage {
 	const char *set;
 	const char *name;
 	void (*handler)(const char **, const char**);
 };
 
 #define	MPS_DATASET(name)	mpsutil_ ## name ## _table
 
 #define	MPS_COMMAND(set, name, function, args, desc)			\
 	static struct mpsutil_command function ## _mpsutil_command =	\
 	{ #name, function };						\
 	DATA_SET(MPS_DATASET(set), function ## _mpsutil_command);	\
 	static void							\
 	function ## _usage(const char **a3, const char **a4)		\
 	{								\
 		*a3 = args;						\
 		*a4 = desc;						\
 		return;							\
 	};								\
 	static struct mpsutil_usage function ## _mpsutil_usage =	\
 	{ #set, #name, function ## _usage };				\
 	DATA_SET(MPS_DATASET(usage), function ## _mpsutil_usage);
 
 #define	_MPS_COMMAND(set, name, function)				\
 	static struct mpsutil_command function ## _mpsutil_command =	\
 	{ #name, function };						\
 	DATA_SET(MPS_DATASET(set), function ## _mpsutil_command);
 
 #define	MPS_TABLE(set, name)						\
 	SET_DECLARE(MPS_DATASET(name), struct mpsutil_command);		\
 									\
 	static int							\
 	mpsutil_ ## name ## _table_handler(int ac, char **av)		\
 	{								\
 		return (mps_table_handler(SET_BEGIN(MPS_DATASET(name)), \
 		    SET_LIMIT(MPS_DATASET(name)), ac, av));		\
 	}								\
 	_MPS_COMMAND(set, name, mpsutil_ ## name ## _table_handler)
 
 extern int mps_unit;
+extern int is_mps;
 #define MPS_MAX_UNIT 10
 
 void	hexdump(const void *ptr, int length, const char *hdr, int flags);
 #define	HD_COLUMN_MASK	0xff
 #define	HD_DELIM_MASK	0xff00
 #define	HD_OMIT_COUNT	(1 << 16)
 #define	HD_OMIT_HEX	(1 << 17)
 #define	HD_OMIT_CHARS	(1 << 18)
 #define HD_REVERSED	(1 << 19)
 
 int	mps_open(int unit);
 int	mps_table_handler(struct mpsutil_command **start,
     struct mpsutil_command **end, int ac, char **av);
 int	mps_user_command(int fd, void *req, uint32_t req_len, void *reply,
 	uint32_t reply_len, void *buffer, int len, uint32_t flags);
 int	mps_pass_command(int fd, void *req, uint32_t req_len, void *reply,
 	uint32_t reply_len, void *data_in, uint32_t datain_len, void *data_out,
 	uint32_t dataout_len, uint32_t timeout);
 int	mps_read_config_page_header(int fd, U8 PageType, U8 PageNumber,
     U32 PageAddress, MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus);
 int	mps_read_ext_config_page_header(int fd, U8 ExtPageType, U8 PageNumber,
     U32 PageAddress, MPI2_CONFIG_PAGE_HEADER *header,
     U16 *ExtPageLen, U16 *IOCStatus);
 void	*mps_read_config_page(int fd, U8 PageType, U8 PageNumber,
     U32 PageAddress, U16 *IOCStatus);
 void	*mps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
     U8 PageNumber, U32 PageAddress, U16 *IOCStatus);
 int	mps_map_btdh(int fd, uint16_t *devhandle, uint16_t *bus,
     uint16_t *target);
 const char *mps_ioc_status(U16 IOCStatus);
 #if 0
 int	mpt_write_config_page(int fd, void *buf, U16 *IOCStatus);
 int	mpt_raid_action(int fd, U8 Action, U8 VolumeBus, U8 VolumeID,
     U8 PhysDiskNum, U32 ActionDataWord, void *buf, int len,
     RAID_VOL0_STATUS *VolumeStatus, U32 *ActionData, int datalen,
     U16 *IOCStatus, U16 *ActionStatus, int write);
 const char *mpt_raid_status(U16 ActionStatus);
 const char *mpt_raid_level(U8 VolumeType);
 const char *mpt_volstate(U8 State);
 const char *mpt_pdstate(CONFIG_PAGE_RAID_PHYS_DISK_0 *info);
 const char *mpt_pd_inq_string(CONFIG_PAGE_RAID_PHYS_DISK_0 *pd_info);
 struct mpt_drive_list *mpt_pd_list(int fd);
 void	mpt_free_pd_list(struct mpt_drive_list *list);
 int	mpt_query_disk(U8 VolumeBus, U8 VolumeID, struct mpt_query_disk *qd);
 const char *mpt_volume_name(U8 VolumeBus, U8 VolumeID);
 int	mpt_fetch_disks(int fd, int *ndisks,
     struct mpt_standalone_disk **disksp);
 int	mpt_lock_volume(U8 VolumeBus, U8 VolumeID);
 int	mpt_lookup_drive(struct mpt_drive_list *list, const char *drive,
     U8 *PhysDiskNum);
 int	mpt_lookup_volume(int fd, const char *name, U8 *VolumeBus,
     U8 *VolumeID);
 int	mpt_rescan_bus(int bus, int id);
 #endif
 
 static __inline void *
 mps_read_man_page(int fd, U8 PageNumber, U16 *IOCStatus)
 {
 
 	return (mps_read_config_page(fd, MPI2_CONFIG_PAGETYPE_MANUFACTURING,
 	    PageNumber, 0, IOCStatus));
 }
 
 static __inline void *
 mps_read_ioc_page(int fd, U8 PageNumber, U16 *IOCStatus)
 {
 
 	return (mps_read_config_page(fd, MPI2_CONFIG_PAGETYPE_IOC, PageNumber,
 	    0, IOCStatus));
 }
 
 MPI2_IOC_FACTS_REPLY * mps_get_iocfacts(int fd);
 
 #if 0
 static __inline U32
 mpt_vol_pageaddr(U8 VolumeBus, U8 VolumeID)
 {
 
 	return (VolumeBus << 8 | VolumeID);
 }
 
 static __inline CONFIG_PAGE_RAID_VOL_0 *
 mpt_vol_info(int fd, U8 VolumeBus, U8 VolumeID, U16 *IOCStatus)
 {
 
 	return (mpt_read_config_page(fd, MPI_CONFIG_PAGETYPE_RAID_VOLUME, 0,
 	    mpt_vol_pageaddr(VolumeBus, VolumeID), IOCStatus));
 }
 
 static __inline CONFIG_PAGE_RAID_VOL_1 *
 mpt_vol_names(int fd, U8 VolumeBus, U8 VolumeID, U16 *IOCStatus)
 {
 
 	return (mpt_read_config_page(fd, MPI_CONFIG_PAGETYPE_RAID_VOLUME, 1,
 	    mpt_vol_pageaddr(VolumeBus, VolumeID), IOCStatus));
 }
 
 static __inline CONFIG_PAGE_RAID_PHYS_DISK_0 *
 mpt_pd_info(int fd, U8 PhysDiskNum, U16 *IOCStatus)
 {
 
 	return (mpt_read_config_page(fd, MPI_CONFIG_PAGETYPE_RAID_PHYSDISK, 0,
 	    PhysDiskNum, IOCStatus));
 }
 #endif
 
 #endif /* !__MPTUTIL_H__ */