mps_cmd.c revision 289364
1286180Sscottl/*-
2286180Sscottl * Copyright (c) 2008 Yahoo!, Inc.
3286180Sscottl * All rights reserved.
4286180Sscottl * Written by: John Baldwin <jhb@FreeBSD.org>
5286180Sscottl *
6286180Sscottl * Redistribution and use in source and binary forms, with or without
7286180Sscottl * modification, are permitted provided that the following conditions
8286180Sscottl * are met:
9286180Sscottl * 1. Redistributions of source code must retain the above copyright
10286180Sscottl *    notice, this list of conditions and the following disclaimer.
11286180Sscottl * 2. Redistributions in binary form must reproduce the above copyright
12286180Sscottl *    notice, this list of conditions and the following disclaimer in the
13286180Sscottl *    documentation and/or other materials provided with the distribution.
14286180Sscottl * 3. Neither the name of the author nor the names of any co-contributors
15286180Sscottl *    may be used to endorse or promote products derived from this software
16286180Sscottl *    without specific prior written permission.
17286180Sscottl *
18286180Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19286180Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20286180Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21286180Sscottl * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22286180Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23286180Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24286180Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25286180Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26286180Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27286180Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28286180Sscottl * SUCH DAMAGE.
29286180Sscottl */
30286180Sscottl
31286180Sscottl#include <sys/cdefs.h>
32286180Sscottl__RCSID("$FreeBSD: projects/mpsutil/usr.sbin/mpsutil/mps_cmd.c 289364 2015-10-15 15:19:38Z bapt $");
33286180Sscottl
34286180Sscottl#include <sys/param.h>
35286180Sscottl#include <sys/errno.h>
36286180Sscottl#include <sys/ioctl.h>
37286180Sscottl#if 0
38286180Sscottl#include <sys/mps_ioctl.h>
39286180Sscottl#else
40286180Sscottl#include "mps_ioctl.h"
41286180Sscottl#endif
42286180Sscottl#include <sys/sysctl.h>
43286180Sscottl#include <sys/uio.h>
44286180Sscottl
45286180Sscottl#include <err.h>
46286180Sscottl#include <fcntl.h>
47286180Sscottl#include <stdio.h>
48286180Sscottl#include <stdlib.h>
49286180Sscottl#include <string.h>
50286180Sscottl#include <unistd.h>
51286180Sscottl
52286180Sscottl#include "mpsutil.h"
53286180Sscottl
54286180Sscottl#ifndef USE_MPT_IOCTLS
55286180Sscottl#define USE_MPT_IOCTLS
56286180Sscottl#endif
57286180Sscottl
58286180Sscottlstatic const char *mps_ioc_status_codes[] = {
59286180Sscottl	"Success",				/* 0x0000 */
60286180Sscottl	"Invalid function",
61286180Sscottl	"Busy",
62286180Sscottl	"Invalid scatter-gather list",
63286180Sscottl	"Internal error",
64286180Sscottl	"Reserved",
65286180Sscottl	"Insufficient resources",
66286180Sscottl	"Invalid field",
67286180Sscottl	"Invalid state",			/* 0x0008 */
68286180Sscottl	"Operation state not supported",
69286180Sscottl	NULL,
70286180Sscottl	NULL,
71286180Sscottl	NULL,
72286180Sscottl	NULL,
73286180Sscottl	NULL,
74286180Sscottl	NULL,
75286180Sscottl	NULL,					/* 0x0010 */
76286180Sscottl	NULL,
77286180Sscottl	NULL,
78286180Sscottl	NULL,
79286180Sscottl	NULL,
80286180Sscottl	NULL,
81286180Sscottl	NULL,
82286180Sscottl	NULL,
83286180Sscottl	NULL,					/* 0x0018 */
84286180Sscottl	NULL,
85286180Sscottl	NULL,
86286180Sscottl	NULL,
87286180Sscottl	NULL,
88286180Sscottl	NULL,
89286180Sscottl	NULL,
90286180Sscottl	NULL,
91286180Sscottl	"Invalid configuration action",		/* 0x0020 */
92286180Sscottl	"Invalid configuration type",
93286180Sscottl	"Invalid configuration page",
94286180Sscottl	"Invalid configuration data",
95286180Sscottl	"No configuration defaults",
96286180Sscottl	"Unable to commit configuration change",
97286180Sscottl	NULL,
98286180Sscottl	NULL,
99286180Sscottl	NULL,					/* 0x0028 */
100286180Sscottl	NULL,
101286180Sscottl	NULL,
102286180Sscottl	NULL,
103286180Sscottl	NULL,
104286180Sscottl	NULL,
105286180Sscottl	NULL,
106286180Sscottl	NULL,
107286180Sscottl	NULL,					/* 0x0030 */
108286180Sscottl	NULL,
109286180Sscottl	NULL,
110286180Sscottl	NULL,
111286180Sscottl	NULL,
112286180Sscottl	NULL,
113286180Sscottl	NULL,
114286180Sscottl	NULL,
115286180Sscottl	NULL,					/* 0x0038 */
116286180Sscottl	NULL,
117286180Sscottl	NULL,
118286180Sscottl	NULL,
119286180Sscottl	NULL,
120286180Sscottl	NULL,
121286180Sscottl	NULL,
122286180Sscottl	NULL,
123286180Sscottl	"Recovered SCSI error",			/* 0x0040 */
124286180Sscottl	"Invalid SCSI bus",
125286180Sscottl	"Invalid SCSI target ID",
126286180Sscottl	"SCSI device not there",
127286180Sscottl	"SCSI data overrun",
128286180Sscottl	"SCSI data underrun",
129286180Sscottl	"SCSI I/O error",
130286180Sscottl	"SCSI protocol error",
131286180Sscottl	"SCSI task terminated",			/* 0x0048 */
132286180Sscottl	"SCSI residual mismatch",
133286180Sscottl	"SCSI task management failed",
134286180Sscottl	"SCSI I/O controller terminated",
135286180Sscottl	"SCSI external controller terminated",
136286180Sscottl	"EEDP guard error",
137286180Sscottl	"EEDP reference tag error",
138286180Sscottl	"EEDP application tag error",
139286180Sscottl	NULL,					/* 0x0050 */
140286180Sscottl	NULL,
141286180Sscottl	NULL,
142286180Sscottl	NULL,
143286180Sscottl	NULL,
144286180Sscottl	NULL,
145286180Sscottl	NULL,
146286180Sscottl	NULL,
147286180Sscottl	NULL,					/* 0x0058 */
148286180Sscottl	NULL,
149286180Sscottl	NULL,
150286180Sscottl	NULL,
151286180Sscottl	NULL,
152286180Sscottl	NULL,
153286180Sscottl	NULL,
154286180Sscottl	NULL,
155286180Sscottl	"SCSI target priority I/O",		/* 0x0060 */
156286180Sscottl	"Invalid SCSI target port",
157286180Sscottl	"Invalid SCSI target I/O index",
158286180Sscottl	"SCSI target aborted",
159286180Sscottl	"No connection retryable",
160286180Sscottl	"No connection",
161286180Sscottl	"FC aborted",
162286180Sscottl	"Invalid FC receive ID",
163286180Sscottl	"FC did invalid",			/* 0x0068 */
164286180Sscottl	"FC node logged out",
165286180Sscottl	"Transfer count mismatch",
166286180Sscottl	"STS data not set",
167286180Sscottl	"FC exchange canceled",
168286180Sscottl	"Data offset error",
169286180Sscottl	"Too much write data",
170286180Sscottl	"IU too short",
171286180Sscottl	"ACK NAK timeout",			/* 0x0070 */
172286180Sscottl	"NAK received",
173286180Sscottl	NULL,
174286180Sscottl	NULL,
175286180Sscottl	NULL,
176286180Sscottl	NULL,
177286180Sscottl	NULL,
178286180Sscottl	NULL,
179286180Sscottl	NULL,					/* 0x0078 */
180286180Sscottl	NULL,
181286180Sscottl	NULL,
182286180Sscottl	NULL,
183286180Sscottl	NULL,
184286180Sscottl	NULL,
185286180Sscottl	NULL,
186286180Sscottl	NULL,
187286180Sscottl	"LAN device not found",			/* 0x0080 */
188286180Sscottl	"LAN device failure",
189286180Sscottl	"LAN transmit error",
190286180Sscottl	"LAN transmit aborted",
191286180Sscottl	"LAN receive error",
192286180Sscottl	"LAN receive aborted",
193286180Sscottl	"LAN partial packet",
194286180Sscottl	"LAN canceled",
195286180Sscottl	NULL,					/* 0x0088 */
196286180Sscottl	NULL,
197286180Sscottl	NULL,
198286180Sscottl	NULL,
199286180Sscottl	NULL,
200286180Sscottl	NULL,
201286180Sscottl	NULL,
202286180Sscottl	NULL,
203286180Sscottl	"SAS SMP request failed",		/* 0x0090 */
204286180Sscottl	"SAS SMP data overrun",
205286180Sscottl	NULL,
206286180Sscottl	NULL,
207286180Sscottl	NULL,
208286180Sscottl	NULL,
209286180Sscottl	NULL,
210286180Sscottl	NULL,
211286180Sscottl	"Inband aborted",			/* 0x0098 */
212286180Sscottl	"No inband connection",
213286180Sscottl	NULL,
214286180Sscottl	NULL,
215286180Sscottl	NULL,
216286180Sscottl	NULL,
217286180Sscottl	NULL,
218286180Sscottl	NULL,
219286180Sscottl	"Diagnostic released",			/* 0x00A0 */
220286180Sscottl};
221286180Sscottl
222286180Sscottlconst char *
223286180Sscottlmps_ioc_status(U16 IOCStatus)
224286180Sscottl{
225286180Sscottl	static char buffer[16];
226286180Sscottl
227286180Sscottl	IOCStatus &= MPI2_IOCSTATUS_MASK;
228286180Sscottl	if (IOCStatus < sizeof(mps_ioc_status_codes) / sizeof(char *) &&
229286180Sscottl	    mps_ioc_status_codes[IOCStatus] != NULL)
230286180Sscottl		return (mps_ioc_status_codes[IOCStatus]);
231286180Sscottl	snprintf(buffer, sizeof(buffer), "Status: 0x%04x", IOCStatus);
232286180Sscottl	return (buffer);
233286180Sscottl}
234286180Sscottl
235286180Sscottl#ifdef USE_MPT_IOCTLS
236286180Sscottlint
237286180Sscottlmps_map_btdh(int fd, uint16_t *devhandle, uint16_t *bus, uint16_t *target)
238286180Sscottl{
239286180Sscottl	int error;
240286180Sscottl	struct mps_btdh_mapping map;
241286180Sscottl
242286180Sscottl	bzero(&map, sizeof(map));
243286180Sscottl	map.Bus = *bus;
244286180Sscottl	map.TargetID = *target;
245286180Sscottl	map.DevHandle = *devhandle;
246286180Sscottl
247286180Sscottl	if ((error = ioctl(fd, MPTIOCTL_BTDH_MAPPING, &map)) != 0) {
248286180Sscottl		error = errno;
249286180Sscottl		warn("Failed to map bus/target/device");
250286180Sscottl		return (error);
251286180Sscottl	}
252286180Sscottl
253286180Sscottl	*bus = map.Bus;
254286180Sscottl	*target = map.TargetID;
255286180Sscottl	*devhandle = map.DevHandle;
256286180Sscottl
257286180Sscottl	return (0);
258286180Sscottl}
259286180Sscottl
260286180Sscottlint
261286180Sscottlmps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
262286180Sscottl    MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
263286180Sscottl{
264286180Sscottl	MPI2_CONFIG_REQUEST req;
265286180Sscottl	MPI2_CONFIG_REPLY reply;
266286180Sscottl
267286180Sscottl	bzero(&req, sizeof(req));
268286180Sscottl	req.Function = MPI2_FUNCTION_CONFIG;
269286180Sscottl	req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
270286180Sscottl	req.Header.PageType = PageType;
271286180Sscottl	req.Header.PageNumber = PageNumber;
272286180Sscottl	req.PageAddress = PageAddress;
273286180Sscottl
274286180Sscottl	if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
275286180Sscottl	    NULL, 0, NULL, 0, 30))
276286180Sscottl		return (errno);
277286180Sscottl
278286180Sscottl	if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
279286180Sscottl		if (IOCStatus != NULL)
280286180Sscottl			*IOCStatus = reply.IOCStatus;
281286180Sscottl		return (EIO);
282286180Sscottl	}
283286180Sscottl	if (header == NULL)
284286180Sscottl		return (EINVAL);
285286180Sscottl	*header = reply.Header;
286286180Sscottl	return (0);
287286180Sscottl}
288286180Sscottl
289286180Sscottlint
290286180Sscottlmps_read_ext_config_page_header(int fd, U8 ExtPageType, U8 PageNumber, U32 PageAddress, MPI2_CONFIG_PAGE_HEADER *header, U16 *ExtPageLength, U16 *IOCStatus)
291286180Sscottl{
292286180Sscottl	MPI2_CONFIG_REQUEST req;
293286180Sscottl	MPI2_CONFIG_REPLY reply;
294286180Sscottl
295286180Sscottl	bzero(&req, sizeof(req));
296286180Sscottl	req.Function = MPI2_FUNCTION_CONFIG;
297286180Sscottl	req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
298286180Sscottl	req.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
299286180Sscottl	req.ExtPageType = ExtPageType;
300286180Sscottl	req.Header.PageNumber = PageNumber;
301286180Sscottl	req.PageAddress = PageAddress;
302286180Sscottl
303286180Sscottl	if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
304286180Sscottl	    NULL, 0, NULL, 0, 30))
305286180Sscottl		return (errno);
306286180Sscottl
307286180Sscottl	if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
308286180Sscottl		if (IOCStatus != NULL)
309286180Sscottl			*IOCStatus = reply.IOCStatus;
310286180Sscottl		return (EIO);
311286180Sscottl	}
312286180Sscottl	if ((header == NULL) || (ExtPageLength == NULL))
313286180Sscottl		return (EINVAL);
314286180Sscottl	*header = reply.Header;
315286180Sscottl	*ExtPageLength = reply.ExtPageLength;
316286180Sscottl	return (0);
317286180Sscottl}
318286180Sscottl
319286180Sscottlvoid *
320286180Sscottlmps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
321286180Sscottl    U16 *IOCStatus)
322286180Sscottl{
323286180Sscottl	MPI2_CONFIG_REQUEST req;
324286180Sscottl	MPI2_CONFIG_PAGE_HEADER header;
325286180Sscottl	MPI2_CONFIG_REPLY reply;
326286180Sscottl	void *buf;
327286180Sscottl	int error, len;
328286180Sscottl
329286180Sscottl	bzero(&header, sizeof(header));
330286180Sscottl	error = mps_read_config_page_header(fd, PageType, PageNumber,
331286180Sscottl	    PageAddress, &header, IOCStatus);
332286180Sscottl	if (error) {
333286180Sscottl		errno = error;
334286180Sscottl		return (NULL);
335286180Sscottl	}
336286180Sscottl
337286180Sscottl	bzero(&req, sizeof(req));
338286180Sscottl	req.Function = MPI2_FUNCTION_CONFIG;
339286180Sscottl	req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
340286180Sscottl	req.PageAddress = PageAddress;
341286180Sscottl	req.Header = header;
342286180Sscottl	req.Header.PageLength = reply.Header.PageLength;
343286180Sscottl	if (reply.Header.PageLength == 0)
344286180Sscottl		req.Header.PageLength = 4;
345286180Sscottl
346286180Sscottl	len = req.Header.PageLength * 4;
347286180Sscottl	buf = malloc(len);
348286180Sscottl	if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
349286180Sscottl	    buf, len, NULL, 0, 30)) {
350286180Sscottl		error = errno;
351286180Sscottl		free(buf);
352286180Sscottl		errno = error;
353286180Sscottl		return (NULL);
354286180Sscottl	}
355286180Sscottl	if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
356286180Sscottl		if (IOCStatus != NULL)
357286180Sscottl			*IOCStatus = reply.IOCStatus;
358286180Sscottl		else
359286180Sscottl			warnx("Reading config page failed: 0x%x %s",
360286180Sscottl			    reply.IOCStatus, mps_ioc_status(reply.IOCStatus));
361286180Sscottl		free(buf);
362286180Sscottl		errno = EIO;
363286180Sscottl		return (NULL);
364286180Sscottl	}
365286180Sscottl	return (buf);
366286180Sscottl}
367286180Sscottl
368286180Sscottlvoid *
369286180Sscottlmps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
370286180Sscottl    U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
371286180Sscottl{
372286180Sscottl	MPI2_CONFIG_REQUEST req;
373286180Sscottl	MPI2_CONFIG_PAGE_HEADER header;
374286180Sscottl	MPI2_CONFIG_REPLY reply;
375286180Sscottl	U16 pagelen;
376286180Sscottl	void *buf;
377286180Sscottl	int error, len;
378286180Sscottl
379286180Sscottl	if (IOCStatus != NULL)
380286180Sscottl		*IOCStatus = MPI2_IOCSTATUS_SUCCESS;
381286180Sscottl	bzero(&header, sizeof(header));
382286180Sscottl	error = mps_read_ext_config_page_header(fd, ExtPageType, PageNumber,
383286180Sscottl	    PageAddress, &header, &pagelen, IOCStatus);
384286180Sscottl	if (error) {
385286180Sscottl		errno = error;
386286180Sscottl		return (NULL);
387286180Sscottl	}
388286180Sscottl
389286180Sscottl	bzero(&req, sizeof(req));
390286180Sscottl	req.Function = MPI2_FUNCTION_CONFIG;
391286180Sscottl	req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
392286180Sscottl	req.PageAddress = PageAddress;
393286180Sscottl	req.Header = header;
394286180Sscottl	if (pagelen == 0)
395286180Sscottl		pagelen = 4;
396286180Sscottl	req.ExtPageLength = pagelen;
397286180Sscottl	req.ExtPageType = ExtPageType;
398286180Sscottl
399286180Sscottl	len = pagelen * 4;
400286180Sscottl	buf = malloc(len);
401286180Sscottl	if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
402286180Sscottl	    buf, len, NULL, 0, 30)) {
403286180Sscottl		error = errno;
404286180Sscottl		free(buf);
405286180Sscottl		errno = error;
406286180Sscottl		return (NULL);
407286180Sscottl	}
408286180Sscottl	if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
409286180Sscottl		if (IOCStatus != NULL)
410286180Sscottl			*IOCStatus = reply.IOCStatus;
411286180Sscottl		else
412286180Sscottl			warnx("Reading extended config page failed: %s",
413286180Sscottl			    mps_ioc_status(reply.IOCStatus));
414286180Sscottl		free(buf);
415286180Sscottl		errno = EIO;
416286180Sscottl		return (NULL);
417286180Sscottl	}
418286180Sscottl	return (buf);
419286180Sscottl}
420286180Sscottl
421286180Sscottl#else
422286180Sscottl
423286180Sscottlint
424286180Sscottlmps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
425286180Sscottl    MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
426286180Sscottl{
427286180Sscottl	struct mps_cfg_page_req req;
428286180Sscottl
429286180Sscottl	if (IOCStatus != NULL)
430286180Sscottl		*IOCStatus = MPI2_IOCSTATUS_SUCCESS;
431286180Sscottl	if (header == NULL)
432286180Sscottl		return (EINVAL);
433286180Sscottl	bzero(&req, sizeof(req));
434286180Sscottl	req.header.PageType = PageType;
435286180Sscottl	req.header.PageNumber = PageNumber;
436286180Sscottl	req.page_address = PageAddress;
437286180Sscottl	if (ioctl(fd, MPSIO_READ_CFG_HEADER, &req) < 0)
438286180Sscottl		return (errno);
439286180Sscottl	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
440286180Sscottl		if (IOCStatus != NULL)
441286180Sscottl			*IOCStatus = req.ioc_status;
442286180Sscottl		return (EIO);
443286180Sscottl	}
444286180Sscottl	bcopy(&req.header, header, sizeof(*header));
445286180Sscottl	return (0);
446286180Sscottl}
447286180Sscottl
448286180Sscottlvoid *
449286180Sscottlmps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
450286180Sscottl    U16 *IOCStatus)
451286180Sscottl{
452286180Sscottl	struct mps_cfg_page_req req;
453286180Sscottl	void *buf;
454286180Sscottl	int error;
455286180Sscottl
456286180Sscottl	error = mps_read_config_page_header(fd, PageType, PageNumber,
457286180Sscottl	    PageAddress, &req.header, IOCStatus);
458286180Sscottl	if (error) {
459286180Sscottl		errno = error;
460286180Sscottl		return (NULL);
461286180Sscottl	}
462286180Sscottl
463286180Sscottl	if (req.header.PageLength == 0)
464286180Sscottl		req.header.PageLength = 4;
465286180Sscottl	req.len = req.header.PageLength * 4;
466286180Sscottl	buf = malloc(req.len);
467286180Sscottl	req.buf = buf;
468286180Sscottl	bcopy(&req.header, buf, sizeof(req.header));
469286180Sscottl	if (ioctl(fd, MPSIO_READ_CFG_PAGE, &req) < 0) {
470286180Sscottl		error = errno;
471286180Sscottl		free(buf);
472286180Sscottl		errno = error;
473286180Sscottl		return (NULL);
474286180Sscottl	}
475286180Sscottl	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
476286180Sscottl		if (IOCStatus != NULL)
477286180Sscottl			*IOCStatus = req.ioc_status;
478286180Sscottl		else
479286180Sscottl			warnx("Reading config page failed: 0x%x %s",
480286180Sscottl			    req.ioc_status, mps_ioc_status(req.ioc_status));
481286180Sscottl		free(buf);
482286180Sscottl		errno = EIO;
483286180Sscottl		return (NULL);
484286180Sscottl	}
485286180Sscottl	return (buf);
486286180Sscottl}
487286180Sscottl
488286180Sscottlvoid *
489286180Sscottlmps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
490286180Sscottl    U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
491286180Sscottl{
492286180Sscottl	struct mps_ext_cfg_page_req req;
493286180Sscottl	void *buf;
494286180Sscottl	int error;
495286180Sscottl
496286180Sscottl	if (IOCStatus != NULL)
497286180Sscottl		*IOCStatus = MPI2_IOCSTATUS_SUCCESS;
498286180Sscottl	bzero(&req, sizeof(req));
499286180Sscottl	req.header.PageVersion = PageVersion;
500286180Sscottl	req.header.PageNumber = PageNumber;
501286180Sscottl	req.header.ExtPageType = ExtPageType;
502286180Sscottl	req.page_address = PageAddress;
503286180Sscottl	if (ioctl(fd, MPSIO_READ_EXT_CFG_HEADER, &req) < 0)
504286180Sscottl		return (NULL);
505286180Sscottl	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
506286180Sscottl		if (IOCStatus != NULL)
507286180Sscottl			*IOCStatus = req.ioc_status;
508286180Sscottl		else
509286180Sscottl			warnx("Reading extended config page header failed: %s",
510286180Sscottl			    mps_ioc_status(req.ioc_status));
511286180Sscottl		errno = EIO;
512286180Sscottl		return (NULL);
513286180Sscottl	}
514286180Sscottl	req.len = req.header.ExtPageLength * 4;
515286180Sscottl	buf = malloc(req.len);
516286180Sscottl	req.buf = buf;
517286180Sscottl	bcopy(&req.header, buf, sizeof(req.header));
518286180Sscottl	if (ioctl(fd, MPSIO_READ_EXT_CFG_PAGE, &req) < 0) {
519286180Sscottl		error = errno;
520286180Sscottl		free(buf);
521286180Sscottl		errno = error;
522286180Sscottl		return (NULL);
523286180Sscottl	}
524286180Sscottl	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
525286180Sscottl		if (IOCStatus != NULL)
526286180Sscottl			*IOCStatus = req.ioc_status;
527286180Sscottl		else
528286180Sscottl			warnx("Reading extended config page failed: %s",
529286180Sscottl			    mps_ioc_status(req.ioc_status));
530286180Sscottl		free(buf);
531286180Sscottl		errno = EIO;
532286180Sscottl		return (NULL);
533286180Sscottl	}
534286180Sscottl	return (buf);
535286180Sscottl}
536286180Sscottl#endif
537286180Sscottl
538286180Sscottl#if 0
539286180Sscottlint
540286180Sscottlmpt_write_config_page(int fd, void *buf, U16 *IOCStatus)
541286180Sscottl{
542286180Sscottl	CONFIG_PAGE_HEADER *hdr;
543286180Sscottl	struct mpt_cfg_page_req req;
544286180Sscottl
545286180Sscottl	if (IOCStatus != NULL)
546286180Sscottl		*IOCStatus = MPI_IOCSTATUS_SUCCESS;
547286180Sscottl	bzero(&req, sizeof(req));
548286180Sscottl	req.buf = buf;
549286180Sscottl	hdr = buf;
550286180Sscottl	req.len = hdr->PageLength * 4;
551286180Sscottl	if (ioctl(fd, MPTIO_WRITE_CFG_PAGE, &req) < 0)
552286180Sscottl		return (errno);
553286180Sscottl	if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
554286180Sscottl		if (IOCStatus != NULL) {
555286180Sscottl			*IOCStatus = req.ioc_status;
556286180Sscottl			return (0);
557286180Sscottl		}
558286180Sscottl		warnx("Writing config page failed: %s",
559286180Sscottl		    mpt_ioc_status(req.ioc_status));
560286180Sscottl		return (EIO);
561286180Sscottl	}
562286180Sscottl	return (0);
563286180Sscottl}
564286180Sscottl
565286180Sscottlint
566286180Sscottlmpt_raid_action(int fd, U8 Action, U8 VolumeBus, U8 VolumeID, U8 PhysDiskNum,
567286180Sscottl    U32 ActionDataWord, void *buf, int len, RAID_VOL0_STATUS *VolumeStatus,
568286180Sscottl    U32 *ActionData, int datalen, U16 *IOCStatus, U16 *ActionStatus, int write)
569286180Sscottl{
570286180Sscottl	struct mpt_raid_action raid_act;
571286180Sscottl
572286180Sscottl	if (IOCStatus != NULL)
573286180Sscottl		*IOCStatus = MPI_IOCSTATUS_SUCCESS;
574286180Sscottl	if (datalen < 0 || (unsigned)datalen > sizeof(raid_act.action_data))
575286180Sscottl		return (EINVAL);
576286180Sscottl	bzero(&raid_act, sizeof(raid_act));
577286180Sscottl	raid_act.action = Action;
578286180Sscottl	raid_act.volume_bus = VolumeBus;
579286180Sscottl	raid_act.volume_id = VolumeID;
580286180Sscottl	raid_act.phys_disk_num = PhysDiskNum;
581286180Sscottl	raid_act.action_data_word = ActionDataWord;
582286180Sscottl	if (buf != NULL && len != 0) {
583286180Sscottl		raid_act.buf = buf;
584286180Sscottl		raid_act.len = len;
585286180Sscottl		raid_act.write = write;
586286180Sscottl	}
587286180Sscottl
588286180Sscottl	if (ioctl(fd, MPTIO_RAID_ACTION, &raid_act) < 0)
589286180Sscottl		return (errno);
590286180Sscottl
591286180Sscottl	if (!IOC_STATUS_SUCCESS(raid_act.ioc_status)) {
592286180Sscottl		if (IOCStatus != NULL) {
593286180Sscottl			*IOCStatus = raid_act.ioc_status;
594286180Sscottl			return (0);
595286180Sscottl		}
596286180Sscottl		warnx("RAID action failed: %s",
597286180Sscottl		    mpt_ioc_status(raid_act.ioc_status));
598286180Sscottl		return (EIO);
599286180Sscottl	}
600286180Sscottl
601286180Sscottl	if (ActionStatus != NULL)
602286180Sscottl		*ActionStatus = raid_act.action_status;
603286180Sscottl	if (raid_act.action_status != MPI_RAID_ACTION_ASTATUS_SUCCESS) {
604286180Sscottl		if (ActionStatus != NULL)
605286180Sscottl			return (0);
606286180Sscottl		warnx("RAID action failed: %s",
607286180Sscottl		    mpt_raid_status(raid_act.action_status));
608286180Sscottl		return (EIO);
609286180Sscottl	}
610286180Sscottl
611286180Sscottl	if (VolumeStatus != NULL)
612286180Sscottl		*((U32 *)VolumeStatus) = raid_act.volume_status;
613286180Sscottl	if (ActionData != NULL)
614286180Sscottl		bcopy(raid_act.action_data, ActionData, datalen);
615286180Sscottl	return (0);
616286180Sscottl}
617286180Sscottl#endif
618286180Sscottl
619286180Sscottlint
620286180Sscottlmps_open(int unit)
621286180Sscottl{
622286180Sscottl	char path[MAXPATHLEN];
623286180Sscottl
624289364Sbapt	snprintf(path, sizeof(path), "/dev/mp%s%d", is_mps ? "s": "r", unit);
625286180Sscottl	return (open(path, O_RDWR));
626286180Sscottl}
627286180Sscottl
628286180Sscottlint
629286180Sscottlmps_user_command(int fd, void *req, uint32_t req_len, void *reply,
630286180Sscottl        uint32_t reply_len, void *buffer, int len, uint32_t flags)
631286180Sscottl{
632286180Sscottl	struct mps_usr_command cmd;
633286180Sscottl
634286180Sscottl	bzero(&cmd, sizeof(struct mps_usr_command));
635286180Sscottl	cmd.req = req;
636286180Sscottl	cmd.req_len = req_len;
637286180Sscottl	cmd.rpl = reply;
638286180Sscottl	cmd.rpl_len = reply_len;
639286180Sscottl	cmd.buf = buffer;
640286180Sscottl	cmd.len = len;
641286180Sscottl	cmd.flags = flags;
642286180Sscottl
643286180Sscottl	if (ioctl(fd, MPSIO_MPS_COMMAND, &cmd) < 0)
644286180Sscottl		return (errno);
645286180Sscottl	return (0);
646286180Sscottl}
647286180Sscottl
648286180Sscottlint
649286180Sscottlmps_pass_command(int fd, void *req, uint32_t req_len, void *reply,
650286180Sscottl	uint32_t reply_len, void *data_in, uint32_t datain_len, void *data_out,
651286180Sscottl	uint32_t dataout_len, uint32_t timeout)
652286180Sscottl{
653286180Sscottl	struct mps_pass_thru pass;
654286180Sscottl
655286180Sscottl	pass.PtrRequest = (uint64_t)(uintptr_t)req;
656286180Sscottl	pass.PtrReply = (uint64_t)(uintptr_t)reply;
657286180Sscottl	pass.PtrData = (uint64_t)(uintptr_t)data_in;
658286180Sscottl	pass.PtrDataOut = (uint64_t)(uintptr_t)data_out;
659286180Sscottl	pass.RequestSize = req_len;
660286180Sscottl	pass.ReplySize = reply_len;
661286180Sscottl	pass.DataSize = datain_len;
662286180Sscottl	pass.DataOutSize = dataout_len;
663286180Sscottl	if (datain_len && dataout_len)
664286180Sscottl		pass.DataDirection = MPS_PASS_THRU_DIRECTION_BOTH;
665286180Sscottl	else if (datain_len)
666286180Sscottl		pass.DataDirection = MPS_PASS_THRU_DIRECTION_READ;
667286180Sscottl	else if (dataout_len)
668286180Sscottl		pass.DataDirection = MPS_PASS_THRU_DIRECTION_WRITE;
669286180Sscottl	else
670286180Sscottl		pass.DataDirection = MPS_PASS_THRU_DIRECTION_NONE;
671286180Sscottl	pass.Timeout = timeout;
672286180Sscottl
673286180Sscottl	if (ioctl(fd, MPTIOCTL_PASS_THRU, &pass) < 0)
674286180Sscottl		return (errno);
675286180Sscottl	return (0);
676286180Sscottl}
677286180Sscottl
678286180SscottlMPI2_IOC_FACTS_REPLY *
679286180Sscottlmps_get_iocfacts(int fd)
680286180Sscottl{
681286180Sscottl	MPI2_IOC_FACTS_REPLY *facts;
682286180Sscottl	MPI2_IOC_FACTS_REQUEST req;
683286180Sscottl	int error;
684286180Sscottl
685286180Sscottl	facts = malloc(sizeof(MPI2_IOC_FACTS_REPLY));
686286180Sscottl	if (facts == NULL) {
687286180Sscottl		errno = ENOMEM;
688286180Sscottl		return (NULL);
689286180Sscottl	}
690286180Sscottl
691286180Sscottl	bzero(&req, sizeof(MPI2_IOC_FACTS_REQUEST));
692286180Sscottl	req.Function = MPI2_FUNCTION_IOC_FACTS;
693286180Sscottl
694286180Sscottl#if 1
695286180Sscottl	error = mps_pass_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
696286180Sscottl	    facts, sizeof(MPI2_IOC_FACTS_REPLY), NULL, 0, NULL, 0, 10);
697286180Sscottl#else
698286180Sscottl	error = mps_user_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
699286180Sscottl	    facts, sizeof(MPI2_IOC_FACTS_REPLY), NULL, 0, 0);
700286180Sscottl#endif
701286180Sscottl	if (error) {
702286180Sscottl		free(facts);
703286180Sscottl		return (NULL);
704286180Sscottl	}
705286180Sscottl
706286180Sscottl	if (!IOC_STATUS_SUCCESS(facts->IOCStatus)) {
707286180Sscottl		free(facts);
708286180Sscottl		errno = EINVAL;
709286180Sscottl		return (NULL);
710286180Sscottl	}
711286180Sscottl	return (facts);
712286180Sscottl}
713286180Sscottl
714