1286180Sscottl/*- 2291002Sbapt * Copyright (c) 2015 Baptiste Daroussin <bapt@FreeBSD.org> 3291002Sbapt * 4290061Sscottl * Copyright (c) 2015 Netflix, Inc. 5290061Sscottl * All rights reserved. 6290061Sscottl * Written by: Scott Long <scottl@freebsd.org> 7290061Sscottl * 8286180Sscottl * Copyright (c) 2008 Yahoo!, Inc. 9286180Sscottl * All rights reserved. 10286180Sscottl * Written by: John Baldwin <jhb@FreeBSD.org> 11286180Sscottl * 12286180Sscottl * Redistribution and use in source and binary forms, with or without 13286180Sscottl * modification, are permitted provided that the following conditions 14286180Sscottl * are met: 15286180Sscottl * 1. Redistributions of source code must retain the above copyright 16286180Sscottl * notice, this list of conditions and the following disclaimer. 17286180Sscottl * 2. Redistributions in binary form must reproduce the above copyright 18286180Sscottl * notice, this list of conditions and the following disclaimer in the 19286180Sscottl * documentation and/or other materials provided with the distribution. 20286180Sscottl * 3. Neither the name of the author nor the names of any co-contributors 21286180Sscottl * may be used to endorse or promote products derived from this software 22286180Sscottl * without specific prior written permission. 23286180Sscottl * 24286180Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 25286180Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26286180Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27286180Sscottl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 28286180Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29286180Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30286180Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31286180Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32286180Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33286180Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34286180Sscottl * SUCH DAMAGE. 35286180Sscottl */ 36286180Sscottl 37286180Sscottl#include <sys/cdefs.h> 38286180Sscottl__RCSID("$FreeBSD: stable/11/usr.sbin/mpsutil/mps_cmd.c 315599 2017-03-20 00:54:45Z pfg $"); 39286180Sscottl 40286180Sscottl#include <sys/param.h> 41286180Sscottl#include <sys/errno.h> 42286180Sscottl#include <sys/ioctl.h> 43286180Sscottl#if 0 44286180Sscottl#include <sys/mps_ioctl.h> 45286180Sscottl#else 46286180Sscottl#include "mps_ioctl.h" 47289366Sbapt#include "mpr_ioctl.h" 48286180Sscottl#endif 49286180Sscottl#include <sys/sysctl.h> 50286180Sscottl#include <sys/uio.h> 51286180Sscottl 52286180Sscottl#include <err.h> 53286180Sscottl#include <fcntl.h> 54286180Sscottl#include <stdio.h> 55286180Sscottl#include <stdlib.h> 56286180Sscottl#include <string.h> 57286180Sscottl#include <unistd.h> 58286180Sscottl 59286180Sscottl#include "mpsutil.h" 60286180Sscottl 61286180Sscottl#ifndef USE_MPT_IOCTLS 62286180Sscottl#define USE_MPT_IOCTLS 63286180Sscottl#endif 64286180Sscottl 65286180Sscottlstatic const char *mps_ioc_status_codes[] = { 66286180Sscottl "Success", /* 0x0000 */ 67286180Sscottl "Invalid function", 68286180Sscottl "Busy", 69286180Sscottl "Invalid scatter-gather list", 70286180Sscottl "Internal error", 71286180Sscottl "Reserved", 72286180Sscottl "Insufficient resources", 73286180Sscottl "Invalid field", 74286180Sscottl "Invalid state", /* 0x0008 */ 75286180Sscottl "Operation state not supported", 76286180Sscottl NULL, 77286180Sscottl NULL, 78286180Sscottl NULL, 79286180Sscottl NULL, 80286180Sscottl NULL, 81286180Sscottl NULL, 82286180Sscottl NULL, /* 0x0010 */ 83286180Sscottl NULL, 84286180Sscottl NULL, 85286180Sscottl NULL, 86286180Sscottl NULL, 87286180Sscottl NULL, 88286180Sscottl NULL, 89286180Sscottl NULL, 90286180Sscottl NULL, /* 0x0018 */ 91286180Sscottl NULL, 92286180Sscottl NULL, 93286180Sscottl NULL, 94286180Sscottl NULL, 95286180Sscottl NULL, 96286180Sscottl NULL, 97286180Sscottl NULL, 98286180Sscottl "Invalid configuration action", /* 0x0020 */ 99286180Sscottl "Invalid configuration type", 100286180Sscottl "Invalid configuration page", 101286180Sscottl "Invalid configuration data", 102286180Sscottl "No configuration defaults", 103286180Sscottl "Unable to commit configuration change", 104286180Sscottl NULL, 105286180Sscottl NULL, 106286180Sscottl NULL, /* 0x0028 */ 107286180Sscottl NULL, 108286180Sscottl NULL, 109286180Sscottl NULL, 110286180Sscottl NULL, 111286180Sscottl NULL, 112286180Sscottl NULL, 113286180Sscottl NULL, 114286180Sscottl NULL, /* 0x0030 */ 115286180Sscottl NULL, 116286180Sscottl NULL, 117286180Sscottl NULL, 118286180Sscottl NULL, 119286180Sscottl NULL, 120286180Sscottl NULL, 121286180Sscottl NULL, 122286180Sscottl NULL, /* 0x0038 */ 123286180Sscottl NULL, 124286180Sscottl NULL, 125286180Sscottl NULL, 126286180Sscottl NULL, 127286180Sscottl NULL, 128286180Sscottl NULL, 129286180Sscottl NULL, 130286180Sscottl "Recovered SCSI error", /* 0x0040 */ 131286180Sscottl "Invalid SCSI bus", 132286180Sscottl "Invalid SCSI target ID", 133286180Sscottl "SCSI device not there", 134286180Sscottl "SCSI data overrun", 135286180Sscottl "SCSI data underrun", 136286180Sscottl "SCSI I/O error", 137286180Sscottl "SCSI protocol error", 138286180Sscottl "SCSI task terminated", /* 0x0048 */ 139286180Sscottl "SCSI residual mismatch", 140286180Sscottl "SCSI task management failed", 141286180Sscottl "SCSI I/O controller terminated", 142286180Sscottl "SCSI external controller terminated", 143286180Sscottl "EEDP guard error", 144286180Sscottl "EEDP reference tag error", 145286180Sscottl "EEDP application tag error", 146286180Sscottl NULL, /* 0x0050 */ 147286180Sscottl NULL, 148286180Sscottl NULL, 149286180Sscottl NULL, 150286180Sscottl NULL, 151286180Sscottl NULL, 152286180Sscottl NULL, 153286180Sscottl NULL, 154286180Sscottl NULL, /* 0x0058 */ 155286180Sscottl NULL, 156286180Sscottl NULL, 157286180Sscottl NULL, 158286180Sscottl NULL, 159286180Sscottl NULL, 160286180Sscottl NULL, 161286180Sscottl NULL, 162286180Sscottl "SCSI target priority I/O", /* 0x0060 */ 163286180Sscottl "Invalid SCSI target port", 164286180Sscottl "Invalid SCSI target I/O index", 165286180Sscottl "SCSI target aborted", 166286180Sscottl "No connection retryable", 167286180Sscottl "No connection", 168286180Sscottl "FC aborted", 169286180Sscottl "Invalid FC receive ID", 170286180Sscottl "FC did invalid", /* 0x0068 */ 171286180Sscottl "FC node logged out", 172286180Sscottl "Transfer count mismatch", 173286180Sscottl "STS data not set", 174286180Sscottl "FC exchange canceled", 175286180Sscottl "Data offset error", 176286180Sscottl "Too much write data", 177286180Sscottl "IU too short", 178286180Sscottl "ACK NAK timeout", /* 0x0070 */ 179286180Sscottl "NAK received", 180286180Sscottl NULL, 181286180Sscottl NULL, 182286180Sscottl NULL, 183286180Sscottl NULL, 184286180Sscottl NULL, 185286180Sscottl NULL, 186286180Sscottl NULL, /* 0x0078 */ 187286180Sscottl NULL, 188286180Sscottl NULL, 189286180Sscottl NULL, 190286180Sscottl NULL, 191286180Sscottl NULL, 192286180Sscottl NULL, 193286180Sscottl NULL, 194286180Sscottl "LAN device not found", /* 0x0080 */ 195286180Sscottl "LAN device failure", 196286180Sscottl "LAN transmit error", 197286180Sscottl "LAN transmit aborted", 198286180Sscottl "LAN receive error", 199286180Sscottl "LAN receive aborted", 200286180Sscottl "LAN partial packet", 201286180Sscottl "LAN canceled", 202286180Sscottl NULL, /* 0x0088 */ 203286180Sscottl NULL, 204286180Sscottl NULL, 205286180Sscottl NULL, 206286180Sscottl NULL, 207286180Sscottl NULL, 208286180Sscottl NULL, 209286180Sscottl NULL, 210286180Sscottl "SAS SMP request failed", /* 0x0090 */ 211286180Sscottl "SAS SMP data overrun", 212286180Sscottl NULL, 213286180Sscottl NULL, 214286180Sscottl NULL, 215286180Sscottl NULL, 216286180Sscottl NULL, 217286180Sscottl NULL, 218286180Sscottl "Inband aborted", /* 0x0098 */ 219286180Sscottl "No inband connection", 220286180Sscottl NULL, 221286180Sscottl NULL, 222286180Sscottl NULL, 223286180Sscottl NULL, 224286180Sscottl NULL, 225286180Sscottl NULL, 226286180Sscottl "Diagnostic released", /* 0x00A0 */ 227286180Sscottl}; 228286180Sscottl 229289366Sbaptstruct mprs_pass_thru { 230289366Sbapt uint64_t PtrRequest; 231289366Sbapt uint64_t PtrReply; 232289366Sbapt uint64_t PtrData; 233289366Sbapt uint32_t RequestSize; 234289366Sbapt uint32_t ReplySize; 235289366Sbapt uint32_t DataSize; 236289366Sbapt uint32_t DataDirection; 237289366Sbapt uint64_t PtrDataOut; 238289366Sbapt uint32_t DataOutSize; 239289366Sbapt uint32_t Timeout; 240289366Sbapt}; 241289366Sbapt 242289366Sbaptstruct mprs_btdh_mapping { 243289366Sbapt uint16_t TargetID; 244289366Sbapt uint16_t Bus; 245289366Sbapt uint16_t DevHandle; 246289366Sbapt uint16_t Reserved; 247289366Sbapt}; 248289366Sbapt 249286180Sscottlconst char * 250286180Sscottlmps_ioc_status(U16 IOCStatus) 251286180Sscottl{ 252286180Sscottl static char buffer[16]; 253286180Sscottl 254286180Sscottl IOCStatus &= MPI2_IOCSTATUS_MASK; 255286180Sscottl if (IOCStatus < sizeof(mps_ioc_status_codes) / sizeof(char *) && 256286180Sscottl mps_ioc_status_codes[IOCStatus] != NULL) 257286180Sscottl return (mps_ioc_status_codes[IOCStatus]); 258286180Sscottl snprintf(buffer, sizeof(buffer), "Status: 0x%04x", IOCStatus); 259286180Sscottl return (buffer); 260286180Sscottl} 261286180Sscottl 262286180Sscottl#ifdef USE_MPT_IOCTLS 263286180Sscottlint 264286180Sscottlmps_map_btdh(int fd, uint16_t *devhandle, uint16_t *bus, uint16_t *target) 265286180Sscottl{ 266286180Sscottl int error; 267289366Sbapt struct mprs_btdh_mapping map; 268286180Sscottl 269286180Sscottl map.Bus = *bus; 270286180Sscottl map.TargetID = *target; 271286180Sscottl map.DevHandle = *devhandle; 272286180Sscottl 273286180Sscottl if ((error = ioctl(fd, MPTIOCTL_BTDH_MAPPING, &map)) != 0) { 274286180Sscottl error = errno; 275286180Sscottl warn("Failed to map bus/target/device"); 276286180Sscottl return (error); 277286180Sscottl } 278286180Sscottl 279286180Sscottl *bus = map.Bus; 280286180Sscottl *target = map.TargetID; 281286180Sscottl *devhandle = map.DevHandle; 282286180Sscottl 283286180Sscottl return (0); 284286180Sscottl} 285286180Sscottl 286286180Sscottlint 287286180Sscottlmps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress, 288286180Sscottl MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus) 289286180Sscottl{ 290286180Sscottl MPI2_CONFIG_REQUEST req; 291286180Sscottl MPI2_CONFIG_REPLY reply; 292286180Sscottl 293286180Sscottl bzero(&req, sizeof(req)); 294286180Sscottl req.Function = MPI2_FUNCTION_CONFIG; 295286180Sscottl req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; 296286180Sscottl req.Header.PageType = PageType; 297286180Sscottl req.Header.PageNumber = PageNumber; 298286180Sscottl req.PageAddress = PageAddress; 299286180Sscottl 300286180Sscottl if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply), 301286180Sscottl NULL, 0, NULL, 0, 30)) 302286180Sscottl return (errno); 303286180Sscottl 304286180Sscottl if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) { 305286180Sscottl if (IOCStatus != NULL) 306286180Sscottl *IOCStatus = reply.IOCStatus; 307286180Sscottl return (EIO); 308286180Sscottl } 309286180Sscottl if (header == NULL) 310286180Sscottl return (EINVAL); 311286180Sscottl *header = reply.Header; 312286180Sscottl return (0); 313286180Sscottl} 314286180Sscottl 315286180Sscottlint 316286180Sscottlmps_read_ext_config_page_header(int fd, U8 ExtPageType, U8 PageNumber, U32 PageAddress, MPI2_CONFIG_PAGE_HEADER *header, U16 *ExtPageLength, U16 *IOCStatus) 317286180Sscottl{ 318286180Sscottl MPI2_CONFIG_REQUEST req; 319286180Sscottl MPI2_CONFIG_REPLY reply; 320286180Sscottl 321286180Sscottl bzero(&req, sizeof(req)); 322286180Sscottl req.Function = MPI2_FUNCTION_CONFIG; 323286180Sscottl req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; 324286180Sscottl req.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; 325286180Sscottl req.ExtPageType = ExtPageType; 326286180Sscottl req.Header.PageNumber = PageNumber; 327286180Sscottl req.PageAddress = PageAddress; 328286180Sscottl 329286180Sscottl if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply), 330286180Sscottl NULL, 0, NULL, 0, 30)) 331286180Sscottl return (errno); 332286180Sscottl 333286180Sscottl if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) { 334286180Sscottl if (IOCStatus != NULL) 335286180Sscottl *IOCStatus = reply.IOCStatus; 336286180Sscottl return (EIO); 337286180Sscottl } 338286180Sscottl if ((header == NULL) || (ExtPageLength == NULL)) 339286180Sscottl return (EINVAL); 340286180Sscottl *header = reply.Header; 341286180Sscottl *ExtPageLength = reply.ExtPageLength; 342286180Sscottl return (0); 343286180Sscottl} 344286180Sscottl 345286180Sscottlvoid * 346286180Sscottlmps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress, 347286180Sscottl U16 *IOCStatus) 348286180Sscottl{ 349286180Sscottl MPI2_CONFIG_REQUEST req; 350286180Sscottl MPI2_CONFIG_PAGE_HEADER header; 351286180Sscottl MPI2_CONFIG_REPLY reply; 352286180Sscottl void *buf; 353286180Sscottl int error, len; 354286180Sscottl 355286180Sscottl bzero(&header, sizeof(header)); 356286180Sscottl error = mps_read_config_page_header(fd, PageType, PageNumber, 357286180Sscottl PageAddress, &header, IOCStatus); 358286180Sscottl if (error) { 359286180Sscottl errno = error; 360286180Sscottl return (NULL); 361286180Sscottl } 362286180Sscottl 363286180Sscottl bzero(&req, sizeof(req)); 364286180Sscottl req.Function = MPI2_FUNCTION_CONFIG; 365286180Sscottl req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; 366286180Sscottl req.PageAddress = PageAddress; 367286180Sscottl req.Header = header; 368286180Sscottl req.Header.PageLength = reply.Header.PageLength; 369286180Sscottl if (reply.Header.PageLength == 0) 370286180Sscottl req.Header.PageLength = 4; 371286180Sscottl 372286180Sscottl len = req.Header.PageLength * 4; 373286180Sscottl buf = malloc(len); 374286180Sscottl if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply), 375286180Sscottl buf, len, NULL, 0, 30)) { 376286180Sscottl error = errno; 377286180Sscottl free(buf); 378286180Sscottl errno = error; 379286180Sscottl return (NULL); 380286180Sscottl } 381286180Sscottl if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) { 382286180Sscottl if (IOCStatus != NULL) 383286180Sscottl *IOCStatus = reply.IOCStatus; 384286180Sscottl else 385286180Sscottl warnx("Reading config page failed: 0x%x %s", 386286180Sscottl reply.IOCStatus, mps_ioc_status(reply.IOCStatus)); 387286180Sscottl free(buf); 388286180Sscottl errno = EIO; 389286180Sscottl return (NULL); 390286180Sscottl } 391286180Sscottl return (buf); 392286180Sscottl} 393286180Sscottl 394286180Sscottlvoid * 395286180Sscottlmps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion, 396286180Sscottl U8 PageNumber, U32 PageAddress, U16 *IOCStatus) 397286180Sscottl{ 398286180Sscottl MPI2_CONFIG_REQUEST req; 399286180Sscottl MPI2_CONFIG_PAGE_HEADER header; 400286180Sscottl MPI2_CONFIG_REPLY reply; 401286180Sscottl U16 pagelen; 402286180Sscottl void *buf; 403286180Sscottl int error, len; 404286180Sscottl 405286180Sscottl if (IOCStatus != NULL) 406286180Sscottl *IOCStatus = MPI2_IOCSTATUS_SUCCESS; 407286180Sscottl bzero(&header, sizeof(header)); 408286180Sscottl error = mps_read_ext_config_page_header(fd, ExtPageType, PageNumber, 409286180Sscottl PageAddress, &header, &pagelen, IOCStatus); 410286180Sscottl if (error) { 411286180Sscottl errno = error; 412286180Sscottl return (NULL); 413286180Sscottl } 414286180Sscottl 415286180Sscottl bzero(&req, sizeof(req)); 416286180Sscottl req.Function = MPI2_FUNCTION_CONFIG; 417286180Sscottl req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; 418286180Sscottl req.PageAddress = PageAddress; 419286180Sscottl req.Header = header; 420286180Sscottl if (pagelen == 0) 421286180Sscottl pagelen = 4; 422286180Sscottl req.ExtPageLength = pagelen; 423286180Sscottl req.ExtPageType = ExtPageType; 424286180Sscottl 425286180Sscottl len = pagelen * 4; 426286180Sscottl buf = malloc(len); 427286180Sscottl if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply), 428286180Sscottl buf, len, NULL, 0, 30)) { 429286180Sscottl error = errno; 430286180Sscottl free(buf); 431286180Sscottl errno = error; 432286180Sscottl return (NULL); 433286180Sscottl } 434286180Sscottl if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) { 435286180Sscottl if (IOCStatus != NULL) 436286180Sscottl *IOCStatus = reply.IOCStatus; 437286180Sscottl else 438286180Sscottl warnx("Reading extended config page failed: %s", 439286180Sscottl mps_ioc_status(reply.IOCStatus)); 440286180Sscottl free(buf); 441286180Sscottl errno = EIO; 442286180Sscottl return (NULL); 443286180Sscottl } 444286180Sscottl return (buf); 445286180Sscottl} 446286180Sscottl 447291002Sbaptint 448291002Sbaptmps_firmware_send(int fd, unsigned char *fw, uint32_t len, bool bios) 449291002Sbapt{ 450291002Sbapt MPI2_FW_DOWNLOAD_REQUEST req; 451291002Sbapt MPI2_FW_DOWNLOAD_REPLY reply; 452291002Sbapt 453291002Sbapt bzero(&req, sizeof(req)); 454291002Sbapt bzero(&reply, sizeof(reply)); 455291002Sbapt req.Function = MPI2_FUNCTION_FW_DOWNLOAD; 456291002Sbapt req.ImageType = bios ? MPI2_FW_DOWNLOAD_ITYPE_BIOS : MPI2_FW_DOWNLOAD_ITYPE_FW; 457291002Sbapt req.TotalImageSize = len; 458291002Sbapt req.MsgFlags = MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT; 459291002Sbapt 460291002Sbapt if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply), 461291002Sbapt fw, len, 0)) { 462291002Sbapt return (-1); 463291002Sbapt } 464291002Sbapt return (0); 465291002Sbapt} 466291002Sbapt 467291002Sbaptint 468291002Sbaptmps_firmware_get(int fd, unsigned char **firmware, bool bios) 469291002Sbapt{ 470291002Sbapt MPI2_FW_UPLOAD_REQUEST req; 471291002Sbapt MPI2_FW_UPLOAD_REPLY reply; 472291002Sbapt int size; 473291002Sbapt 474291002Sbapt *firmware = NULL; 475291002Sbapt bzero(&req, sizeof(req)); 476291002Sbapt bzero(&reply, sizeof(reply)); 477291002Sbapt req.Function = MPI2_FUNCTION_FW_UPLOAD; 478291002Sbapt req.ImageType = bios ? MPI2_FW_DOWNLOAD_ITYPE_BIOS : MPI2_FW_DOWNLOAD_ITYPE_FW; 479291002Sbapt 480291002Sbapt if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply), 481291002Sbapt NULL, 0, 0)) { 482291002Sbapt return (-1); 483291002Sbapt } 484291002Sbapt if (reply.ActualImageSize == 0) { 485291002Sbapt return (-1); 486291002Sbapt } 487291002Sbapt 488291002Sbapt size = reply.ActualImageSize; 489315599Spfg *firmware = calloc(size, sizeof(unsigned char)); 490291002Sbapt if (*firmware == NULL) { 491291002Sbapt warn("calloc"); 492291002Sbapt return (-1); 493291002Sbapt } 494291002Sbapt if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply), 495291002Sbapt *firmware, size, 0)) { 496291002Sbapt free(*firmware); 497291002Sbapt return (-1); 498291002Sbapt } 499291002Sbapt 500291002Sbapt return (size); 501291002Sbapt} 502291002Sbapt 503286180Sscottl#else 504286180Sscottl 505286180Sscottlint 506286180Sscottlmps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress, 507286180Sscottl MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus) 508286180Sscottl{ 509286180Sscottl struct mps_cfg_page_req req; 510286180Sscottl 511286180Sscottl if (IOCStatus != NULL) 512286180Sscottl *IOCStatus = MPI2_IOCSTATUS_SUCCESS; 513286180Sscottl if (header == NULL) 514286180Sscottl return (EINVAL); 515286180Sscottl bzero(&req, sizeof(req)); 516286180Sscottl req.header.PageType = PageType; 517286180Sscottl req.header.PageNumber = PageNumber; 518286180Sscottl req.page_address = PageAddress; 519286180Sscottl if (ioctl(fd, MPSIO_READ_CFG_HEADER, &req) < 0) 520286180Sscottl return (errno); 521286180Sscottl if (!IOC_STATUS_SUCCESS(req.ioc_status)) { 522286180Sscottl if (IOCStatus != NULL) 523286180Sscottl *IOCStatus = req.ioc_status; 524286180Sscottl return (EIO); 525286180Sscottl } 526286180Sscottl bcopy(&req.header, header, sizeof(*header)); 527286180Sscottl return (0); 528286180Sscottl} 529286180Sscottl 530286180Sscottlvoid * 531286180Sscottlmps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress, 532286180Sscottl U16 *IOCStatus) 533286180Sscottl{ 534286180Sscottl struct mps_cfg_page_req req; 535286180Sscottl void *buf; 536286180Sscottl int error; 537286180Sscottl 538286180Sscottl error = mps_read_config_page_header(fd, PageType, PageNumber, 539286180Sscottl PageAddress, &req.header, IOCStatus); 540286180Sscottl if (error) { 541286180Sscottl errno = error; 542286180Sscottl return (NULL); 543286180Sscottl } 544286180Sscottl 545286180Sscottl if (req.header.PageLength == 0) 546286180Sscottl req.header.PageLength = 4; 547286180Sscottl req.len = req.header.PageLength * 4; 548286180Sscottl buf = malloc(req.len); 549286180Sscottl req.buf = buf; 550286180Sscottl bcopy(&req.header, buf, sizeof(req.header)); 551286180Sscottl if (ioctl(fd, MPSIO_READ_CFG_PAGE, &req) < 0) { 552286180Sscottl error = errno; 553286180Sscottl free(buf); 554286180Sscottl errno = error; 555286180Sscottl return (NULL); 556286180Sscottl } 557286180Sscottl if (!IOC_STATUS_SUCCESS(req.ioc_status)) { 558286180Sscottl if (IOCStatus != NULL) 559286180Sscottl *IOCStatus = req.ioc_status; 560286180Sscottl else 561286180Sscottl warnx("Reading config page failed: 0x%x %s", 562286180Sscottl req.ioc_status, mps_ioc_status(req.ioc_status)); 563286180Sscottl free(buf); 564286180Sscottl errno = EIO; 565286180Sscottl return (NULL); 566286180Sscottl } 567286180Sscottl return (buf); 568286180Sscottl} 569286180Sscottl 570286180Sscottlvoid * 571286180Sscottlmps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion, 572286180Sscottl U8 PageNumber, U32 PageAddress, U16 *IOCStatus) 573286180Sscottl{ 574286180Sscottl struct mps_ext_cfg_page_req req; 575286180Sscottl void *buf; 576286180Sscottl int error; 577286180Sscottl 578286180Sscottl if (IOCStatus != NULL) 579286180Sscottl *IOCStatus = MPI2_IOCSTATUS_SUCCESS; 580286180Sscottl bzero(&req, sizeof(req)); 581286180Sscottl req.header.PageVersion = PageVersion; 582286180Sscottl req.header.PageNumber = PageNumber; 583286180Sscottl req.header.ExtPageType = ExtPageType; 584286180Sscottl req.page_address = PageAddress; 585286180Sscottl if (ioctl(fd, MPSIO_READ_EXT_CFG_HEADER, &req) < 0) 586286180Sscottl return (NULL); 587286180Sscottl if (!IOC_STATUS_SUCCESS(req.ioc_status)) { 588286180Sscottl if (IOCStatus != NULL) 589286180Sscottl *IOCStatus = req.ioc_status; 590286180Sscottl else 591286180Sscottl warnx("Reading extended config page header failed: %s", 592286180Sscottl mps_ioc_status(req.ioc_status)); 593286180Sscottl errno = EIO; 594286180Sscottl return (NULL); 595286180Sscottl } 596286180Sscottl req.len = req.header.ExtPageLength * 4; 597286180Sscottl buf = malloc(req.len); 598286180Sscottl req.buf = buf; 599286180Sscottl bcopy(&req.header, buf, sizeof(req.header)); 600286180Sscottl if (ioctl(fd, MPSIO_READ_EXT_CFG_PAGE, &req) < 0) { 601286180Sscottl error = errno; 602286180Sscottl free(buf); 603286180Sscottl errno = error; 604286180Sscottl return (NULL); 605286180Sscottl } 606286180Sscottl if (!IOC_STATUS_SUCCESS(req.ioc_status)) { 607286180Sscottl if (IOCStatus != NULL) 608286180Sscottl *IOCStatus = req.ioc_status; 609286180Sscottl else 610286180Sscottl warnx("Reading extended config page failed: %s", 611286180Sscottl mps_ioc_status(req.ioc_status)); 612286180Sscottl free(buf); 613286180Sscottl errno = EIO; 614286180Sscottl return (NULL); 615286180Sscottl } 616286180Sscottl return (buf); 617286180Sscottl} 618286180Sscottl#endif 619286180Sscottl 620286180Sscottlint 621286180Sscottlmps_open(int unit) 622286180Sscottl{ 623286180Sscottl char path[MAXPATHLEN]; 624286180Sscottl 625289364Sbapt snprintf(path, sizeof(path), "/dev/mp%s%d", is_mps ? "s": "r", unit); 626286180Sscottl return (open(path, O_RDWR)); 627286180Sscottl} 628286180Sscottl 629286180Sscottlint 630286180Sscottlmps_user_command(int fd, void *req, uint32_t req_len, void *reply, 631286180Sscottl uint32_t reply_len, void *buffer, int len, uint32_t flags) 632286180Sscottl{ 633286180Sscottl struct mps_usr_command cmd; 634286180Sscottl 635286180Sscottl bzero(&cmd, sizeof(struct mps_usr_command)); 636286180Sscottl cmd.req = req; 637286180Sscottl cmd.req_len = req_len; 638286180Sscottl cmd.rpl = reply; 639286180Sscottl cmd.rpl_len = reply_len; 640286180Sscottl cmd.buf = buffer; 641286180Sscottl cmd.len = len; 642286180Sscottl cmd.flags = flags; 643286180Sscottl 644289366Sbapt if (ioctl(fd, is_mps ? MPSIO_MPS_COMMAND : MPRIO_MPR_COMMAND, &cmd) < 0) 645286180Sscottl return (errno); 646286180Sscottl return (0); 647286180Sscottl} 648286180Sscottl 649286180Sscottlint 650286180Sscottlmps_pass_command(int fd, void *req, uint32_t req_len, void *reply, 651286180Sscottl uint32_t reply_len, void *data_in, uint32_t datain_len, void *data_out, 652286180Sscottl uint32_t dataout_len, uint32_t timeout) 653286180Sscottl{ 654289366Sbapt struct mprs_pass_thru pass; 655286180Sscottl 656286180Sscottl pass.PtrRequest = (uint64_t)(uintptr_t)req; 657286180Sscottl pass.PtrReply = (uint64_t)(uintptr_t)reply; 658286180Sscottl pass.PtrData = (uint64_t)(uintptr_t)data_in; 659286180Sscottl pass.PtrDataOut = (uint64_t)(uintptr_t)data_out; 660286180Sscottl pass.RequestSize = req_len; 661286180Sscottl pass.ReplySize = reply_len; 662286180Sscottl pass.DataSize = datain_len; 663286180Sscottl pass.DataOutSize = dataout_len; 664289366Sbapt if (datain_len && dataout_len) { 665289366Sbapt if (is_mps) { 666289366Sbapt pass.DataDirection = MPS_PASS_THRU_DIRECTION_BOTH; 667289366Sbapt } else { 668289366Sbapt pass.DataDirection = MPR_PASS_THRU_DIRECTION_BOTH; 669289366Sbapt } 670289366Sbapt } else if (datain_len) { 671289366Sbapt if (is_mps) { 672289366Sbapt pass.DataDirection = MPS_PASS_THRU_DIRECTION_READ; 673289366Sbapt } else { 674289366Sbapt pass.DataDirection = MPR_PASS_THRU_DIRECTION_READ; 675289366Sbapt } 676289366Sbapt } else if (dataout_len) { 677289366Sbapt if (is_mps) { 678289366Sbapt pass.DataDirection = MPS_PASS_THRU_DIRECTION_WRITE; 679289366Sbapt } else { 680289366Sbapt pass.DataDirection = MPR_PASS_THRU_DIRECTION_WRITE; 681289366Sbapt } 682289366Sbapt } else { 683289366Sbapt if (is_mps) { 684289366Sbapt pass.DataDirection = MPS_PASS_THRU_DIRECTION_NONE; 685289366Sbapt } else { 686289366Sbapt pass.DataDirection = MPR_PASS_THRU_DIRECTION_NONE; 687289366Sbapt } 688289366Sbapt } 689286180Sscottl pass.Timeout = timeout; 690286180Sscottl 691286180Sscottl if (ioctl(fd, MPTIOCTL_PASS_THRU, &pass) < 0) 692286180Sscottl return (errno); 693286180Sscottl return (0); 694286180Sscottl} 695286180Sscottl 696286180SscottlMPI2_IOC_FACTS_REPLY * 697286180Sscottlmps_get_iocfacts(int fd) 698286180Sscottl{ 699286180Sscottl MPI2_IOC_FACTS_REPLY *facts; 700286180Sscottl MPI2_IOC_FACTS_REQUEST req; 701286180Sscottl int error; 702286180Sscottl 703286180Sscottl facts = malloc(sizeof(MPI2_IOC_FACTS_REPLY)); 704286180Sscottl if (facts == NULL) { 705286180Sscottl errno = ENOMEM; 706286180Sscottl return (NULL); 707286180Sscottl } 708286180Sscottl 709286180Sscottl bzero(&req, sizeof(MPI2_IOC_FACTS_REQUEST)); 710286180Sscottl req.Function = MPI2_FUNCTION_IOC_FACTS; 711286180Sscottl 712286180Sscottl#if 1 713286180Sscottl error = mps_pass_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST), 714286180Sscottl facts, sizeof(MPI2_IOC_FACTS_REPLY), NULL, 0, NULL, 0, 10); 715286180Sscottl#else 716286180Sscottl error = mps_user_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST), 717286180Sscottl facts, sizeof(MPI2_IOC_FACTS_REPLY), NULL, 0, 0); 718286180Sscottl#endif 719286180Sscottl if (error) { 720286180Sscottl free(facts); 721286180Sscottl return (NULL); 722286180Sscottl } 723286180Sscottl 724286180Sscottl if (!IOC_STATUS_SUCCESS(facts->IOCStatus)) { 725286180Sscottl free(facts); 726286180Sscottl errno = EINVAL; 727286180Sscottl return (NULL); 728286180Sscottl } 729286180Sscottl return (facts); 730286180Sscottl} 731286180Sscottl 732