1265236Sken/*- 2265236Sken * Copyright (c) 2008 Yahoo!, Inc. 3265236Sken * All rights reserved. 4265236Sken * Written by: John Baldwin <jhb@FreeBSD.org> 5265236Sken * 6265236Sken * Redistribution and use in source and binary forms, with or without 7265236Sken * modification, are permitted provided that the following conditions 8265236Sken * are met: 9265236Sken * 1. Redistributions of source code must retain the above copyright 10265236Sken * notice, this list of conditions and the following disclaimer. 11265236Sken * 2. Redistributions in binary form must reproduce the above copyright 12265236Sken * notice, this list of conditions and the following disclaimer in the 13265236Sken * documentation and/or other materials provided with the distribution. 14265236Sken * 3. Neither the name of the author nor the names of any co-contributors 15265236Sken * may be used to endorse or promote products derived from this software 16265236Sken * without specific prior written permission. 17265236Sken * 18265236Sken * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19265236Sken * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20265236Sken * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21265236Sken * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22265236Sken * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23265236Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24265236Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25265236Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26265236Sken * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27265236Sken * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28265236Sken * SUCH DAMAGE. 29265236Sken * 30283990Sslm * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD userland interface 31265236Sken */ 32265236Sken/*- 33283990Sslm * Copyright (c) 2011-2015 LSI Corp. 34299962Sslm * Copyright (c) 2013-2016 Avago Technologies 35265236Sken * All rights reserved. 36265236Sken * 37265236Sken * Redistribution and use in source and binary forms, with or without 38265236Sken * modification, are permitted provided that the following conditions 39265236Sken * are met: 40265236Sken * 1. Redistributions of source code must retain the above copyright 41265236Sken * notice, this list of conditions and the following disclaimer. 42265236Sken * 2. Redistributions in binary form must reproduce the above copyright 43265236Sken * notice, this list of conditions and the following disclaimer in the 44265236Sken * documentation and/or other materials provided with the distribution. 45265236Sken * 46265236Sken * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 47265236Sken * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 48265236Sken * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 49265236Sken * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 50265236Sken * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 51265236Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 52265236Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 53265236Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 54265236Sken * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 55265236Sken * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 56265236Sken * SUCH DAMAGE. 57265236Sken * 58283990Sslm * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD 59265236Sken * 60265236Sken * $FreeBSD: stable/10/sys/dev/mpr/mpr_user.c 322661 2017-08-18 15:38:08Z ken $ 61265236Sken */ 62265236Sken 63265236Sken#include <sys/cdefs.h> 64265236Sken__FBSDID("$FreeBSD: stable/10/sys/dev/mpr/mpr_user.c 322661 2017-08-18 15:38:08Z ken $"); 65265236Sken 66265236Sken#include "opt_compat.h" 67265236Sken 68265236Sken/* TODO Move headers to mprvar */ 69265236Sken#include <sys/types.h> 70265236Sken#include <sys/param.h> 71265236Sken#include <sys/systm.h> 72265236Sken#include <sys/kernel.h> 73265236Sken#include <sys/selinfo.h> 74265236Sken#include <sys/module.h> 75265236Sken#include <sys/bus.h> 76265236Sken#include <sys/conf.h> 77265236Sken#include <sys/bio.h> 78265236Sken#include <sys/malloc.h> 79265236Sken#include <sys/uio.h> 80265236Sken#include <sys/sysctl.h> 81265236Sken#include <sys/ioccom.h> 82265236Sken#include <sys/endian.h> 83265236Sken#include <sys/queue.h> 84265236Sken#include <sys/kthread.h> 85265236Sken#include <sys/taskqueue.h> 86265236Sken#include <sys/proc.h> 87265236Sken#include <sys/sysent.h> 88265236Sken 89265236Sken#include <machine/bus.h> 90265236Sken#include <machine/resource.h> 91265236Sken#include <sys/rman.h> 92265236Sken 93265236Sken#include <cam/cam.h> 94283990Sslm#include <cam/cam_ccb.h> 95265236Sken 96265236Sken#include <dev/mpr/mpi/mpi2_type.h> 97265236Sken#include <dev/mpr/mpi/mpi2.h> 98265236Sken#include <dev/mpr/mpi/mpi2_ioc.h> 99265236Sken#include <dev/mpr/mpi/mpi2_cnfg.h> 100265236Sken#include <dev/mpr/mpi/mpi2_init.h> 101265236Sken#include <dev/mpr/mpi/mpi2_tool.h> 102319436Sslm#include <dev/mpr/mpi/mpi2_pci.h> 103265236Sken#include <dev/mpr/mpr_ioctl.h> 104265236Sken#include <dev/mpr/mprvar.h> 105265236Sken#include <dev/mpr/mpr_table.h> 106265236Sken#include <dev/mpr/mpr_sas.h> 107265236Sken#include <dev/pci/pcivar.h> 108265236Sken#include <dev/pci/pcireg.h> 109265236Sken 110265236Skenstatic d_open_t mpr_open; 111265236Skenstatic d_close_t mpr_close; 112265236Skenstatic d_ioctl_t mpr_ioctl_devsw; 113265236Sken 114265236Skenstatic struct cdevsw mpr_cdevsw = { 115265236Sken .d_version = D_VERSION, 116265236Sken .d_flags = 0, 117265236Sken .d_open = mpr_open, 118265236Sken .d_close = mpr_close, 119265236Sken .d_ioctl = mpr_ioctl_devsw, 120265236Sken .d_name = "mpr", 121265236Sken}; 122265236Sken 123265236Skentypedef int (mpr_user_f)(struct mpr_command *, struct mpr_usr_command *); 124265236Skenstatic mpr_user_f mpi_pre_ioc_facts; 125265236Skenstatic mpr_user_f mpi_pre_port_facts; 126265236Skenstatic mpr_user_f mpi_pre_fw_download; 127265236Skenstatic mpr_user_f mpi_pre_fw_upload; 128265236Skenstatic mpr_user_f mpi_pre_sata_passthrough; 129265236Skenstatic mpr_user_f mpi_pre_smp_passthrough; 130265236Skenstatic mpr_user_f mpi_pre_config; 131265236Skenstatic mpr_user_f mpi_pre_sas_io_unit_control; 132265236Sken 133265236Skenstatic int mpr_user_read_cfg_header(struct mpr_softc *, 134299962Sslm struct mpr_cfg_page_req *); 135265236Skenstatic int mpr_user_read_cfg_page(struct mpr_softc *, 136299962Sslm struct mpr_cfg_page_req *, void *); 137265236Skenstatic int mpr_user_read_extcfg_header(struct mpr_softc *, 138299962Sslm struct mpr_ext_cfg_page_req *); 139265236Skenstatic int mpr_user_read_extcfg_page(struct mpr_softc *, 140299962Sslm struct mpr_ext_cfg_page_req *, void *); 141265236Skenstatic int mpr_user_write_cfg_page(struct mpr_softc *, 142299962Sslm struct mpr_cfg_page_req *, void *); 143265236Skenstatic int mpr_user_setup_request(struct mpr_command *, 144299962Sslm struct mpr_usr_command *); 145265236Skenstatic int mpr_user_command(struct mpr_softc *, struct mpr_usr_command *); 146265236Sken 147265236Skenstatic int mpr_user_pass_thru(struct mpr_softc *sc, mpr_pass_thru_t *data); 148265236Skenstatic void mpr_user_get_adapter_data(struct mpr_softc *sc, 149265236Sken mpr_adapter_data_t *data); 150299962Sslmstatic void mpr_user_read_pci_info(struct mpr_softc *sc, mpr_pci_info_t *data); 151265236Skenstatic uint8_t mpr_get_fw_diag_buffer_number(struct mpr_softc *sc, 152265236Sken uint32_t unique_id); 153265236Skenstatic int mpr_post_fw_diag_buffer(struct mpr_softc *sc, 154265236Sken mpr_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code); 155265236Skenstatic int mpr_release_fw_diag_buffer(struct mpr_softc *sc, 156265236Sken mpr_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code, 157265236Sken uint32_t diag_type); 158265236Skenstatic int mpr_diag_register(struct mpr_softc *sc, 159265236Sken mpr_fw_diag_register_t *diag_register, uint32_t *return_code); 160265236Skenstatic int mpr_diag_unregister(struct mpr_softc *sc, 161265236Sken mpr_fw_diag_unregister_t *diag_unregister, uint32_t *return_code); 162299962Sslmstatic int mpr_diag_query(struct mpr_softc *sc, mpr_fw_diag_query_t *diag_query, 163299962Sslm uint32_t *return_code); 164265236Skenstatic int mpr_diag_read_buffer(struct mpr_softc *sc, 165265236Sken mpr_diag_read_buffer_t *diag_read_buffer, uint8_t *ioctl_buf, 166265236Sken uint32_t *return_code); 167265236Skenstatic int mpr_diag_release(struct mpr_softc *sc, 168265236Sken mpr_fw_diag_release_t *diag_release, uint32_t *return_code); 169265236Skenstatic int mpr_do_diag_action(struct mpr_softc *sc, uint32_t action, 170265236Sken uint8_t *diag_action, uint32_t length, uint32_t *return_code); 171299962Sslmstatic int mpr_user_diag_action(struct mpr_softc *sc, mpr_diag_action_t *data); 172299962Sslmstatic void mpr_user_event_query(struct mpr_softc *sc, mpr_event_query_t *data); 173265236Skenstatic void mpr_user_event_enable(struct mpr_softc *sc, 174265236Sken mpr_event_enable_t *data); 175265236Skenstatic int mpr_user_event_report(struct mpr_softc *sc, 176265236Sken mpr_event_report_t *data); 177265236Skenstatic int mpr_user_reg_access(struct mpr_softc *sc, mpr_reg_access_t *data); 178265236Skenstatic int mpr_user_btdh(struct mpr_softc *sc, mpr_btdh_mapping_t *data); 179265236Sken 180265236Skenstatic MALLOC_DEFINE(M_MPRUSER, "mpr_user", "Buffers for mpr(4) ioctls"); 181265236Sken 182265236Sken/* Macros from compat/freebsd32/freebsd32.h */ 183265236Sken#define PTRIN(v) (void *)(uintptr_t)(v) 184265236Sken#define PTROUT(v) (uint32_t)(uintptr_t)(v) 185265236Sken 186265236Sken#define CP(src,dst,fld) do { (dst).fld = (src).fld; } while (0) 187265236Sken#define PTRIN_CP(src,dst,fld) \ 188265236Sken do { (dst).fld = PTRIN((src).fld); } while (0) 189265236Sken#define PTROUT_CP(src,dst,fld) \ 190265236Sken do { (dst).fld = PTROUT((src).fld); } while (0) 191265236Sken 192265236Sken/* 193265236Sken * MPI functions that support IEEE SGLs for SAS3. 194265236Sken */ 195265236Skenstatic uint8_t ieee_sgl_func_list[] = { 196265236Sken MPI2_FUNCTION_SCSI_IO_REQUEST, 197265236Sken MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH, 198265236Sken MPI2_FUNCTION_SMP_PASSTHROUGH, 199265236Sken MPI2_FUNCTION_SATA_PASSTHROUGH, 200265236Sken MPI2_FUNCTION_FW_UPLOAD, 201265236Sken MPI2_FUNCTION_FW_DOWNLOAD, 202265236Sken MPI2_FUNCTION_TARGET_ASSIST, 203265236Sken MPI2_FUNCTION_TARGET_STATUS_SEND, 204265236Sken MPI2_FUNCTION_TOOLBOX 205265236Sken}; 206265236Sken 207265236Skenint 208265236Skenmpr_attach_user(struct mpr_softc *sc) 209265236Sken{ 210265236Sken int unit; 211265236Sken 212265236Sken unit = device_get_unit(sc->mpr_dev); 213299962Sslm sc->mpr_cdev = make_dev(&mpr_cdevsw, unit, UID_ROOT, GID_OPERATOR, 0640, 214299962Sslm "mpr%d", unit); 215299962Sslm 216299962Sslm if (sc->mpr_cdev == NULL) 217265236Sken return (ENOMEM); 218299962Sslm 219265236Sken sc->mpr_cdev->si_drv1 = sc; 220265236Sken return (0); 221265236Sken} 222265236Sken 223265236Skenvoid 224265236Skenmpr_detach_user(struct mpr_softc *sc) 225265236Sken{ 226265236Sken 227265236Sken /* XXX: do a purge of pending requests? */ 228265236Sken if (sc->mpr_cdev != NULL) 229265236Sken destroy_dev(sc->mpr_cdev); 230265236Sken} 231265236Sken 232265236Skenstatic int 233265236Skenmpr_open(struct cdev *dev, int flags, int fmt, struct thread *td) 234265236Sken{ 235265236Sken 236265236Sken return (0); 237265236Sken} 238265236Sken 239265236Skenstatic int 240265236Skenmpr_close(struct cdev *dev, int flags, int fmt, struct thread *td) 241265236Sken{ 242265236Sken 243265236Sken return (0); 244265236Sken} 245265236Sken 246265236Skenstatic int 247265236Skenmpr_user_read_cfg_header(struct mpr_softc *sc, 248265236Sken struct mpr_cfg_page_req *page_req) 249265236Sken{ 250265236Sken MPI2_CONFIG_PAGE_HEADER *hdr; 251265236Sken struct mpr_config_params params; 252265236Sken int error; 253265236Sken 254265236Sken hdr = ¶ms.hdr.Struct; 255265236Sken params.action = MPI2_CONFIG_ACTION_PAGE_HEADER; 256265236Sken params.page_address = le32toh(page_req->page_address); 257265236Sken hdr->PageVersion = 0; 258265236Sken hdr->PageLength = 0; 259265236Sken hdr->PageNumber = page_req->header.PageNumber; 260265236Sken hdr->PageType = page_req->header.PageType; 261265236Sken params.buffer = NULL; 262265236Sken params.length = 0; 263265236Sken params.callback = NULL; 264265236Sken 265265236Sken if ((error = mpr_read_config_page(sc, ¶ms)) != 0) { 266265236Sken /* 267265236Sken * Leave the request. Without resetting the chip, it's 268265236Sken * still owned by it and we'll just get into trouble 269265236Sken * freeing it now. Mark it as abandoned so that if it 270265236Sken * shows up later it can be freed. 271265236Sken */ 272265236Sken mpr_printf(sc, "read_cfg_header timed out\n"); 273265236Sken return (ETIMEDOUT); 274265236Sken } 275265236Sken 276265236Sken page_req->ioc_status = htole16(params.status); 277265236Sken if ((page_req->ioc_status & MPI2_IOCSTATUS_MASK) == 278265236Sken MPI2_IOCSTATUS_SUCCESS) { 279265236Sken bcopy(hdr, &page_req->header, sizeof(page_req->header)); 280265236Sken } 281265236Sken 282265236Sken return (0); 283265236Sken} 284265236Sken 285265236Skenstatic int 286299962Sslmmpr_user_read_cfg_page(struct mpr_softc *sc, struct mpr_cfg_page_req *page_req, 287299962Sslm void *buf) 288265236Sken{ 289265236Sken MPI2_CONFIG_PAGE_HEADER *reqhdr, *hdr; 290265236Sken struct mpr_config_params params; 291265236Sken int error; 292265236Sken 293265236Sken reqhdr = buf; 294265236Sken hdr = ¶ms.hdr.Struct; 295265236Sken hdr->PageVersion = reqhdr->PageVersion; 296265236Sken hdr->PageLength = reqhdr->PageLength; 297265236Sken hdr->PageNumber = reqhdr->PageNumber; 298265236Sken hdr->PageType = reqhdr->PageType & MPI2_CONFIG_PAGETYPE_MASK; 299265236Sken params.action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; 300265236Sken params.page_address = le32toh(page_req->page_address); 301265236Sken params.buffer = buf; 302265236Sken params.length = le32toh(page_req->len); 303265236Sken params.callback = NULL; 304265236Sken 305265236Sken if ((error = mpr_read_config_page(sc, ¶ms)) != 0) { 306265236Sken mpr_printf(sc, "mpr_user_read_cfg_page timed out\n"); 307265236Sken return (ETIMEDOUT); 308265236Sken } 309265236Sken 310265236Sken page_req->ioc_status = htole16(params.status); 311265236Sken return (0); 312265236Sken} 313265236Sken 314265236Skenstatic int 315265236Skenmpr_user_read_extcfg_header(struct mpr_softc *sc, 316265236Sken struct mpr_ext_cfg_page_req *ext_page_req) 317265236Sken{ 318265236Sken MPI2_CONFIG_EXTENDED_PAGE_HEADER *hdr; 319265236Sken struct mpr_config_params params; 320265236Sken int error; 321265236Sken 322265236Sken hdr = ¶ms.hdr.Ext; 323265236Sken params.action = MPI2_CONFIG_ACTION_PAGE_HEADER; 324265236Sken hdr->PageVersion = ext_page_req->header.PageVersion; 325265236Sken hdr->PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; 326265236Sken hdr->ExtPageLength = 0; 327265236Sken hdr->PageNumber = ext_page_req->header.PageNumber; 328265236Sken hdr->ExtPageType = ext_page_req->header.ExtPageType; 329265236Sken params.page_address = le32toh(ext_page_req->page_address); 330283990Sslm params.buffer = NULL; 331283990Sslm params.length = 0; 332283990Sslm params.callback = NULL; 333283990Sslm 334265236Sken if ((error = mpr_read_config_page(sc, ¶ms)) != 0) { 335265236Sken /* 336265236Sken * Leave the request. Without resetting the chip, it's 337265236Sken * still owned by it and we'll just get into trouble 338265236Sken * freeing it now. Mark it as abandoned so that if it 339265236Sken * shows up later it can be freed. 340265236Sken */ 341265236Sken mpr_printf(sc, "mpr_user_read_extcfg_header timed out\n"); 342265236Sken return (ETIMEDOUT); 343265236Sken } 344265236Sken 345265236Sken ext_page_req->ioc_status = htole16(params.status); 346265236Sken if ((ext_page_req->ioc_status & MPI2_IOCSTATUS_MASK) == 347265236Sken MPI2_IOCSTATUS_SUCCESS) { 348265236Sken ext_page_req->header.PageVersion = hdr->PageVersion; 349265236Sken ext_page_req->header.PageNumber = hdr->PageNumber; 350265236Sken ext_page_req->header.PageType = hdr->PageType; 351265236Sken ext_page_req->header.ExtPageLength = hdr->ExtPageLength; 352265236Sken ext_page_req->header.ExtPageType = hdr->ExtPageType; 353265236Sken } 354265236Sken 355265236Sken return (0); 356265236Sken} 357265236Sken 358265236Skenstatic int 359265236Skenmpr_user_read_extcfg_page(struct mpr_softc *sc, 360265236Sken struct mpr_ext_cfg_page_req *ext_page_req, void *buf) 361265236Sken{ 362265236Sken MPI2_CONFIG_EXTENDED_PAGE_HEADER *reqhdr, *hdr; 363265236Sken struct mpr_config_params params; 364265236Sken int error; 365265236Sken 366265236Sken reqhdr = buf; 367265236Sken hdr = ¶ms.hdr.Ext; 368265236Sken params.action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; 369265236Sken params.page_address = le32toh(ext_page_req->page_address); 370265236Sken hdr->PageVersion = reqhdr->PageVersion; 371283990Sslm hdr->PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; 372265236Sken hdr->PageNumber = reqhdr->PageNumber; 373265236Sken hdr->ExtPageType = reqhdr->ExtPageType; 374265236Sken hdr->ExtPageLength = reqhdr->ExtPageLength; 375265236Sken params.buffer = buf; 376265236Sken params.length = le32toh(ext_page_req->len); 377265236Sken params.callback = NULL; 378265236Sken 379265236Sken if ((error = mpr_read_config_page(sc, ¶ms)) != 0) { 380265236Sken mpr_printf(sc, "mpr_user_read_extcfg_page timed out\n"); 381265236Sken return (ETIMEDOUT); 382265236Sken } 383265236Sken 384265236Sken ext_page_req->ioc_status = htole16(params.status); 385265236Sken return (0); 386265236Sken} 387265236Sken 388265236Skenstatic int 389265236Skenmpr_user_write_cfg_page(struct mpr_softc *sc, 390265236Sken struct mpr_cfg_page_req *page_req, void *buf) 391265236Sken{ 392265236Sken MPI2_CONFIG_PAGE_HEADER *reqhdr, *hdr; 393265236Sken struct mpr_config_params params; 394265236Sken u_int hdr_attr; 395265236Sken int error; 396265236Sken 397265236Sken reqhdr = buf; 398265236Sken hdr = ¶ms.hdr.Struct; 399265236Sken hdr_attr = reqhdr->PageType & MPI2_CONFIG_PAGEATTR_MASK; 400265236Sken if (hdr_attr != MPI2_CONFIG_PAGEATTR_CHANGEABLE && 401265236Sken hdr_attr != MPI2_CONFIG_PAGEATTR_PERSISTENT) { 402265236Sken mpr_printf(sc, "page type 0x%x not changeable\n", 403265236Sken reqhdr->PageType & MPI2_CONFIG_PAGETYPE_MASK); 404265236Sken return (EINVAL); 405265236Sken } 406265236Sken 407265236Sken /* 408265236Sken * There isn't any point in restoring stripped out attributes 409265236Sken * if you then mask them going down to issue the request. 410265236Sken */ 411265236Sken 412265236Sken hdr->PageVersion = reqhdr->PageVersion; 413265236Sken hdr->PageLength = reqhdr->PageLength; 414265236Sken hdr->PageNumber = reqhdr->PageNumber; 415265236Sken hdr->PageType = reqhdr->PageType; 416265236Sken params.action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT; 417265236Sken params.page_address = le32toh(page_req->page_address); 418265236Sken params.buffer = buf; 419265236Sken params.length = le32toh(page_req->len); 420265236Sken params.callback = NULL; 421265236Sken 422265236Sken if ((error = mpr_write_config_page(sc, ¶ms)) != 0) { 423265236Sken mpr_printf(sc, "mpr_write_cfg_page timed out\n"); 424265236Sken return (ETIMEDOUT); 425265236Sken } 426265236Sken 427265236Sken page_req->ioc_status = htole16(params.status); 428265236Sken return (0); 429265236Sken} 430265236Sken 431265236Skenvoid 432265236Skenmpr_init_sge(struct mpr_command *cm, void *req, void *sge) 433265236Sken{ 434265236Sken int off, space; 435265236Sken 436265236Sken space = (int)cm->cm_sc->facts->IOCRequestFrameSize * 4; 437265236Sken off = (uintptr_t)sge - (uintptr_t)req; 438265236Sken 439265236Sken KASSERT(off < space, ("bad pointers %p %p, off %d, space %d", 440265236Sken req, sge, off, space)); 441265236Sken 442265236Sken cm->cm_sge = sge; 443265236Sken cm->cm_sglsize = space - off; 444265236Sken} 445265236Sken 446265236Sken/* 447265236Sken * Prepare the mpr_command for an IOC_FACTS request. 448265236Sken */ 449265236Skenstatic int 450265236Skenmpi_pre_ioc_facts(struct mpr_command *cm, struct mpr_usr_command *cmd) 451265236Sken{ 452265236Sken MPI2_IOC_FACTS_REQUEST *req = (void *)cm->cm_req; 453265236Sken MPI2_IOC_FACTS_REPLY *rpl; 454265236Sken 455265236Sken if (cmd->req_len != sizeof *req) 456265236Sken return (EINVAL); 457265236Sken if (cmd->rpl_len != sizeof *rpl) 458265236Sken return (EINVAL); 459265236Sken 460265236Sken cm->cm_sge = NULL; 461265236Sken cm->cm_sglsize = 0; 462265236Sken return (0); 463265236Sken} 464265236Sken 465265236Sken/* 466265236Sken * Prepare the mpr_command for a PORT_FACTS request. 467265236Sken */ 468265236Skenstatic int 469265236Skenmpi_pre_port_facts(struct mpr_command *cm, struct mpr_usr_command *cmd) 470265236Sken{ 471265236Sken MPI2_PORT_FACTS_REQUEST *req = (void *)cm->cm_req; 472265236Sken MPI2_PORT_FACTS_REPLY *rpl; 473265236Sken 474265236Sken if (cmd->req_len != sizeof *req) 475265236Sken return (EINVAL); 476265236Sken if (cmd->rpl_len != sizeof *rpl) 477265236Sken return (EINVAL); 478265236Sken 479265236Sken cm->cm_sge = NULL; 480265236Sken cm->cm_sglsize = 0; 481265236Sken return (0); 482265236Sken} 483265236Sken 484265236Sken/* 485265236Sken * Prepare the mpr_command for a FW_DOWNLOAD request. 486265236Sken */ 487265236Skenstatic int 488265236Skenmpi_pre_fw_download(struct mpr_command *cm, struct mpr_usr_command *cmd) 489265236Sken{ 490265236Sken MPI25_FW_DOWNLOAD_REQUEST *req = (void *)cm->cm_req; 491265236Sken MPI2_FW_DOWNLOAD_REPLY *rpl; 492265236Sken int error; 493265236Sken 494265236Sken if (cmd->req_len != sizeof *req) 495265236Sken return (EINVAL); 496265236Sken if (cmd->rpl_len != sizeof *rpl) 497265236Sken return (EINVAL); 498265236Sken 499265236Sken if (cmd->len == 0) 500265236Sken return (EINVAL); 501265236Sken 502265236Sken error = copyin(cmd->buf, cm->cm_data, cmd->len); 503265236Sken if (error != 0) 504265236Sken return (error); 505265236Sken 506265236Sken mpr_init_sge(cm, req, &req->SGL); 507265236Sken 508265236Sken /* 509265236Sken * For now, the F/W image must be provided in a single request. 510265236Sken */ 511265236Sken if ((req->MsgFlags & MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT) == 0) 512265236Sken return (EINVAL); 513265236Sken if (req->TotalImageSize != cmd->len) 514265236Sken return (EINVAL); 515265236Sken 516265236Sken req->ImageOffset = 0; 517265236Sken req->ImageSize = cmd->len; 518265236Sken 519265236Sken cm->cm_flags |= MPR_CM_FLAGS_DATAOUT; 520265236Sken 521265236Sken return (mpr_push_ieee_sge(cm, &req->SGL, 0)); 522265236Sken} 523265236Sken 524265236Sken/* 525265236Sken * Prepare the mpr_command for a FW_UPLOAD request. 526265236Sken */ 527265236Skenstatic int 528265236Skenmpi_pre_fw_upload(struct mpr_command *cm, struct mpr_usr_command *cmd) 529265236Sken{ 530265236Sken MPI25_FW_UPLOAD_REQUEST *req = (void *)cm->cm_req; 531265236Sken MPI2_FW_UPLOAD_REPLY *rpl; 532265236Sken 533265236Sken if (cmd->req_len != sizeof *req) 534265236Sken return (EINVAL); 535265236Sken if (cmd->rpl_len != sizeof *rpl) 536265236Sken return (EINVAL); 537265236Sken 538265236Sken mpr_init_sge(cm, req, &req->SGL); 539265236Sken if (cmd->len == 0) { 540265236Sken /* Perhaps just asking what the size of the fw is? */ 541265236Sken return (0); 542265236Sken } 543265236Sken 544265236Sken req->ImageOffset = 0; 545265236Sken req->ImageSize = cmd->len; 546265236Sken 547283990Sslm cm->cm_flags |= MPR_CM_FLAGS_DATAIN; 548283990Sslm 549265236Sken return (mpr_push_ieee_sge(cm, &req->SGL, 0)); 550265236Sken} 551265236Sken 552265236Sken/* 553265236Sken * Prepare the mpr_command for a SATA_PASSTHROUGH request. 554265236Sken */ 555265236Skenstatic int 556265236Skenmpi_pre_sata_passthrough(struct mpr_command *cm, struct mpr_usr_command *cmd) 557265236Sken{ 558265236Sken MPI2_SATA_PASSTHROUGH_REQUEST *req = (void *)cm->cm_req; 559265236Sken MPI2_SATA_PASSTHROUGH_REPLY *rpl; 560265236Sken 561265236Sken if (cmd->req_len != sizeof *req) 562265236Sken return (EINVAL); 563265236Sken if (cmd->rpl_len != sizeof *rpl) 564265236Sken return (EINVAL); 565265236Sken 566265236Sken mpr_init_sge(cm, req, &req->SGL); 567265236Sken return (0); 568265236Sken} 569265236Sken 570265236Sken/* 571265236Sken * Prepare the mpr_command for a SMP_PASSTHROUGH request. 572265236Sken */ 573265236Skenstatic int 574265236Skenmpi_pre_smp_passthrough(struct mpr_command *cm, struct mpr_usr_command *cmd) 575265236Sken{ 576265236Sken MPI2_SMP_PASSTHROUGH_REQUEST *req = (void *)cm->cm_req; 577265236Sken MPI2_SMP_PASSTHROUGH_REPLY *rpl; 578265236Sken 579265236Sken if (cmd->req_len != sizeof *req) 580265236Sken return (EINVAL); 581265236Sken if (cmd->rpl_len != sizeof *rpl) 582265236Sken return (EINVAL); 583265236Sken 584265236Sken mpr_init_sge(cm, req, &req->SGL); 585265236Sken return (0); 586265236Sken} 587265236Sken 588265236Sken/* 589265236Sken * Prepare the mpr_command for a CONFIG request. 590265236Sken */ 591265236Skenstatic int 592265236Skenmpi_pre_config(struct mpr_command *cm, struct mpr_usr_command *cmd) 593265236Sken{ 594265236Sken MPI2_CONFIG_REQUEST *req = (void *)cm->cm_req; 595265236Sken MPI2_CONFIG_REPLY *rpl; 596265236Sken 597265236Sken if (cmd->req_len != sizeof *req) 598265236Sken return (EINVAL); 599265236Sken if (cmd->rpl_len != sizeof *rpl) 600265236Sken return (EINVAL); 601265236Sken 602265236Sken mpr_init_sge(cm, req, &req->PageBufferSGE); 603265236Sken return (0); 604265236Sken} 605265236Sken 606265236Sken/* 607265236Sken * Prepare the mpr_command for a SAS_IO_UNIT_CONTROL request. 608265236Sken */ 609265236Skenstatic int 610265236Skenmpi_pre_sas_io_unit_control(struct mpr_command *cm, 611265236Sken struct mpr_usr_command *cmd) 612265236Sken{ 613265236Sken 614265236Sken cm->cm_sge = NULL; 615265236Sken cm->cm_sglsize = 0; 616265236Sken return (0); 617265236Sken} 618265236Sken 619265236Sken/* 620265236Sken * A set of functions to prepare an mpr_command for the various 621265236Sken * supported requests. 622265236Sken */ 623265236Skenstruct mpr_user_func { 624265236Sken U8 Function; 625265236Sken mpr_user_f *f_pre; 626265236Sken} mpr_user_func_list[] = { 627265236Sken { MPI2_FUNCTION_IOC_FACTS, mpi_pre_ioc_facts }, 628265236Sken { MPI2_FUNCTION_PORT_FACTS, mpi_pre_port_facts }, 629265236Sken { MPI2_FUNCTION_FW_DOWNLOAD, mpi_pre_fw_download }, 630265236Sken { MPI2_FUNCTION_FW_UPLOAD, mpi_pre_fw_upload }, 631265236Sken { MPI2_FUNCTION_SATA_PASSTHROUGH, mpi_pre_sata_passthrough }, 632265236Sken { MPI2_FUNCTION_SMP_PASSTHROUGH, mpi_pre_smp_passthrough}, 633265236Sken { MPI2_FUNCTION_CONFIG, mpi_pre_config}, 634265236Sken { MPI2_FUNCTION_SAS_IO_UNIT_CONTROL, mpi_pre_sas_io_unit_control }, 635265236Sken { 0xFF, NULL } /* list end */ 636265236Sken}; 637265236Sken 638265236Skenstatic int 639265236Skenmpr_user_setup_request(struct mpr_command *cm, struct mpr_usr_command *cmd) 640265236Sken{ 641265236Sken MPI2_REQUEST_HEADER *hdr = (MPI2_REQUEST_HEADER *)cm->cm_req; 642265236Sken struct mpr_user_func *f; 643265236Sken 644265236Sken for (f = mpr_user_func_list; f->f_pre != NULL; f++) { 645265236Sken if (hdr->Function == f->Function) 646265236Sken return (f->f_pre(cm, cmd)); 647265236Sken } 648265236Sken return (EINVAL); 649265236Sken} 650265236Sken 651265236Skenstatic int 652265236Skenmpr_user_command(struct mpr_softc *sc, struct mpr_usr_command *cmd) 653265236Sken{ 654265236Sken MPI2_REQUEST_HEADER *hdr; 655322661Sken MPI2_DEFAULT_REPLY *rpl = NULL; 656265236Sken void *buf = NULL; 657265236Sken struct mpr_command *cm = NULL; 658265236Sken int err = 0; 659265236Sken int sz; 660265236Sken 661265236Sken mpr_lock(sc); 662265236Sken cm = mpr_alloc_command(sc); 663265236Sken 664265236Sken if (cm == NULL) { 665265236Sken mpr_printf(sc, "%s: no mpr requests\n", __func__); 666265236Sken err = ENOMEM; 667322661Sken goto RetFree; 668265236Sken } 669265236Sken mpr_unlock(sc); 670265236Sken 671265236Sken hdr = (MPI2_REQUEST_HEADER *)cm->cm_req; 672265236Sken 673265236Sken mpr_dprint(sc, MPR_USER, "%s: req %p %d rpl %p %d\n", __func__, 674265236Sken cmd->req, cmd->req_len, cmd->rpl, cmd->rpl_len); 675265236Sken 676265236Sken if (cmd->req_len > (int)sc->facts->IOCRequestFrameSize * 4) { 677265236Sken err = EINVAL; 678265236Sken goto RetFreeUnlocked; 679265236Sken } 680265236Sken err = copyin(cmd->req, hdr, cmd->req_len); 681265236Sken if (err != 0) 682265236Sken goto RetFreeUnlocked; 683265236Sken 684265236Sken mpr_dprint(sc, MPR_USER, "%s: Function %02X MsgFlags %02X\n", __func__, 685265236Sken hdr->Function, hdr->MsgFlags); 686265236Sken 687265236Sken if (cmd->len > 0) { 688265236Sken buf = malloc(cmd->len, M_MPRUSER, M_WAITOK|M_ZERO); 689265236Sken cm->cm_data = buf; 690265236Sken cm->cm_length = cmd->len; 691265236Sken } else { 692265236Sken cm->cm_data = NULL; 693265236Sken cm->cm_length = 0; 694265236Sken } 695265236Sken 696265236Sken cm->cm_flags = MPR_CM_FLAGS_SGE_SIMPLE; 697265236Sken cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 698265236Sken 699265236Sken err = mpr_user_setup_request(cm, cmd); 700265236Sken if (err == EINVAL) { 701265236Sken mpr_printf(sc, "%s: unsupported parameter or unsupported " 702265236Sken "function in request (function = 0x%X)\n", __func__, 703265236Sken hdr->Function); 704265236Sken } 705265236Sken if (err != 0) 706265236Sken goto RetFreeUnlocked; 707265236Sken 708265236Sken mpr_lock(sc); 709322661Sken err = mpr_wait_command(sc, &cm, 30, CAN_SLEEP); 710265236Sken 711322661Sken if (err || (cm == NULL)) { 712265236Sken mpr_printf(sc, "%s: invalid request: error %d\n", 713265236Sken __func__, err); 714322661Sken goto RetFree; 715265236Sken } 716265236Sken 717322661Sken if (cm != NULL) 718322661Sken rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply; 719265236Sken if (rpl != NULL) 720265236Sken sz = rpl->MsgLength * 4; 721265236Sken else 722265236Sken sz = 0; 723265236Sken 724265236Sken if (sz > cmd->rpl_len) { 725265236Sken mpr_printf(sc, "%s: user reply buffer (%d) smaller than " 726265236Sken "returned buffer (%d)\n", __func__, cmd->rpl_len, sz); 727265236Sken sz = cmd->rpl_len; 728265236Sken } 729265236Sken 730265236Sken mpr_unlock(sc); 731265236Sken copyout(rpl, cmd->rpl, sz); 732265236Sken if (buf != NULL) 733265236Sken copyout(buf, cmd->buf, cmd->len); 734265236Sken mpr_dprint(sc, MPR_USER, "%s: reply size %d\n", __func__, sz); 735265236Sken 736265236SkenRetFreeUnlocked: 737265236Sken mpr_lock(sc); 738322661SkenRetFree: 739265236Sken if (cm != NULL) 740265236Sken mpr_free_command(sc, cm); 741265236Sken mpr_unlock(sc); 742265236Sken if (buf != NULL) 743265236Sken free(buf, M_MPRUSER); 744265236Sken return (err); 745265236Sken} 746265236Sken 747265236Skenstatic int 748265236Skenmpr_user_pass_thru(struct mpr_softc *sc, mpr_pass_thru_t *data) 749265236Sken{ 750265236Sken MPI2_REQUEST_HEADER *hdr, tmphdr; 751265236Sken MPI2_DEFAULT_REPLY *rpl; 752319436Sslm Mpi26NVMeEncapsulatedErrorReply_t *nvme_error_reply = NULL; 753319436Sslm Mpi26NVMeEncapsulatedRequest_t *nvme_encap_request = NULL; 754265236Sken struct mpr_command *cm = NULL; 755265236Sken int i, err = 0, dir = 0, sz; 756265236Sken uint8_t tool, function = 0; 757265236Sken u_int sense_len; 758265236Sken struct mprsas_target *targ = NULL; 759265236Sken 760265236Sken /* 761265236Sken * Only allow one passthru command at a time. Use the MPR_FLAGS_BUSY 762265236Sken * bit to denote that a passthru is being processed. 763265236Sken */ 764265236Sken mpr_lock(sc); 765265236Sken if (sc->mpr_flags & MPR_FLAGS_BUSY) { 766265236Sken mpr_dprint(sc, MPR_USER, "%s: Only one passthru command " 767265236Sken "allowed at a single time.", __func__); 768265236Sken mpr_unlock(sc); 769265236Sken return (EBUSY); 770265236Sken } 771265236Sken sc->mpr_flags |= MPR_FLAGS_BUSY; 772265236Sken mpr_unlock(sc); 773265236Sken 774265236Sken /* 775265236Sken * Do some validation on data direction. Valid cases are: 776265236Sken * 1) DataSize is 0 and direction is NONE 777265236Sken * 2) DataSize is non-zero and one of: 778265236Sken * a) direction is READ or 779265236Sken * b) direction is WRITE or 780265236Sken * c) direction is BOTH and DataOutSize is non-zero 781265236Sken * If valid and the direction is BOTH, change the direction to READ. 782265236Sken * if valid and the direction is not BOTH, make sure DataOutSize is 0. 783265236Sken */ 784265236Sken if (((data->DataSize == 0) && 785265236Sken (data->DataDirection == MPR_PASS_THRU_DIRECTION_NONE)) || 786265236Sken ((data->DataSize != 0) && 787265236Sken ((data->DataDirection == MPR_PASS_THRU_DIRECTION_READ) || 788265236Sken (data->DataDirection == MPR_PASS_THRU_DIRECTION_WRITE) || 789265236Sken ((data->DataDirection == MPR_PASS_THRU_DIRECTION_BOTH) && 790265236Sken (data->DataOutSize != 0))))) { 791265236Sken if (data->DataDirection == MPR_PASS_THRU_DIRECTION_BOTH) 792265236Sken data->DataDirection = MPR_PASS_THRU_DIRECTION_READ; 793265236Sken else 794265236Sken data->DataOutSize = 0; 795265236Sken } else 796265236Sken return (EINVAL); 797265236Sken 798265236Sken mpr_dprint(sc, MPR_USER, "%s: req 0x%jx %d rpl 0x%jx %d " 799265236Sken "data in 0x%jx %d data out 0x%jx %d data dir %d\n", __func__, 800265236Sken data->PtrRequest, data->RequestSize, data->PtrReply, 801265236Sken data->ReplySize, data->PtrData, data->DataSize, 802265236Sken data->PtrDataOut, data->DataOutSize, data->DataDirection); 803265236Sken 804265236Sken /* 805265236Sken * copy in the header so we know what we're dealing with before we 806265236Sken * commit to allocating a command for it. 807265236Sken */ 808265236Sken err = copyin(PTRIN(data->PtrRequest), &tmphdr, data->RequestSize); 809265236Sken if (err != 0) 810265236Sken goto RetFreeUnlocked; 811265236Sken 812265236Sken if (data->RequestSize > (int)sc->facts->IOCRequestFrameSize * 4) { 813265236Sken err = EINVAL; 814265236Sken goto RetFreeUnlocked; 815265236Sken } 816265236Sken 817265236Sken function = tmphdr.Function; 818265236Sken mpr_dprint(sc, MPR_USER, "%s: Function %02X MsgFlags %02X\n", __func__, 819265236Sken function, tmphdr.MsgFlags); 820265236Sken 821265236Sken /* 822265236Sken * Handle a passthru TM request. 823265236Sken */ 824265236Sken if (function == MPI2_FUNCTION_SCSI_TASK_MGMT) { 825265236Sken MPI2_SCSI_TASK_MANAGE_REQUEST *task; 826265236Sken 827265236Sken mpr_lock(sc); 828265236Sken cm = mprsas_alloc_tm(sc); 829265236Sken if (cm == NULL) { 830265236Sken err = EINVAL; 831265236Sken goto Ret; 832265236Sken } 833265236Sken 834265236Sken /* Copy the header in. Only a small fixup is needed. */ 835265236Sken task = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req; 836265236Sken bcopy(&tmphdr, task, data->RequestSize); 837265236Sken task->TaskMID = cm->cm_desc.Default.SMID; 838265236Sken 839265236Sken cm->cm_data = NULL; 840283990Sslm cm->cm_desc.HighPriority.RequestFlags = 841283990Sslm MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; 842265236Sken cm->cm_complete = NULL; 843265236Sken cm->cm_complete_data = NULL; 844265236Sken 845283990Sslm targ = mprsas_find_target_by_handle(sc->sassc, 0, 846283990Sslm task->DevHandle); 847283990Sslm if (targ == NULL) { 848283990Sslm mpr_dprint(sc, MPR_INFO, 849283990Sslm "%s %d : invalid handle for requested TM 0x%x \n", 850283990Sslm __func__, __LINE__, task->DevHandle); 851283990Sslm err = 1; 852283990Sslm } else { 853283990Sslm mprsas_prepare_for_tm(sc, cm, targ, CAM_LUN_WILDCARD); 854322661Sken err = mpr_wait_command(sc, &cm, 30, CAN_SLEEP); 855283990Sslm } 856265236Sken 857265236Sken if (err != 0) { 858265236Sken err = EIO; 859265236Sken mpr_dprint(sc, MPR_FAULT, "%s: task management failed", 860265236Sken __func__); 861265236Sken } 862265236Sken /* 863265236Sken * Copy the reply data and sense data to user space. 864265236Sken */ 865322661Sken if ((cm != NULL) && (cm->cm_reply != NULL)) { 866265236Sken rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply; 867265236Sken sz = rpl->MsgLength * 4; 868265236Sken 869265236Sken if (sz > data->ReplySize) { 870265236Sken mpr_printf(sc, "%s: user reply buffer (%d) " 871265236Sken "smaller than returned buffer (%d)\n", 872265236Sken __func__, data->ReplySize, sz); 873265236Sken } 874265236Sken mpr_unlock(sc); 875265236Sken copyout(cm->cm_reply, PTRIN(data->PtrReply), 876265236Sken data->ReplySize); 877265236Sken mpr_lock(sc); 878265236Sken } 879265236Sken mprsas_free_tm(sc, cm); 880265236Sken goto Ret; 881265236Sken } 882265236Sken 883265236Sken mpr_lock(sc); 884265236Sken cm = mpr_alloc_command(sc); 885265236Sken 886265236Sken if (cm == NULL) { 887265236Sken mpr_printf(sc, "%s: no mpr requests\n", __func__); 888265236Sken err = ENOMEM; 889265236Sken goto Ret; 890265236Sken } 891265236Sken mpr_unlock(sc); 892265236Sken 893265236Sken hdr = (MPI2_REQUEST_HEADER *)cm->cm_req; 894265236Sken bcopy(&tmphdr, hdr, data->RequestSize); 895265236Sken 896265236Sken /* 897265236Sken * Do some checking to make sure the IOCTL request contains a valid 898265236Sken * request. Then set the SGL info. 899265236Sken */ 900265236Sken mpr_init_sge(cm, hdr, (void *)((uint8_t *)hdr + data->RequestSize)); 901265236Sken 902265236Sken /* 903265236Sken * Set up for read, write or both. From check above, DataOutSize will 904265236Sken * be 0 if direction is READ or WRITE, but it will have some non-zero 905265236Sken * value if the direction is BOTH. So, just use the biggest size to get 906265236Sken * the cm_data buffer size. If direction is BOTH, 2 SGLs need to be set 907265236Sken * up; the first is for the request and the second will contain the 908265236Sken * response data. cm_out_len needs to be set here and this will be used 909265236Sken * when the SGLs are set up. 910265236Sken */ 911265236Sken cm->cm_data = NULL; 912265236Sken cm->cm_length = MAX(data->DataSize, data->DataOutSize); 913265236Sken cm->cm_out_len = data->DataOutSize; 914265236Sken cm->cm_flags = 0; 915265236Sken if (cm->cm_length != 0) { 916265236Sken cm->cm_data = malloc(cm->cm_length, M_MPRUSER, M_WAITOK | 917265236Sken M_ZERO); 918319436Sslm cm->cm_flags = MPR_CM_FLAGS_DATAIN; 919319436Sslm if (data->DataOutSize) { 920319436Sslm cm->cm_flags |= MPR_CM_FLAGS_DATAOUT; 921319436Sslm err = copyin(PTRIN(data->PtrDataOut), 922319436Sslm cm->cm_data, data->DataOutSize); 923319436Sslm } else if (data->DataDirection == 924319436Sslm MPR_PASS_THRU_DIRECTION_WRITE) { 925319436Sslm cm->cm_flags = MPR_CM_FLAGS_DATAOUT; 926319436Sslm err = copyin(PTRIN(data->PtrData), 927319436Sslm cm->cm_data, data->DataSize); 928265236Sken } 929319436Sslm if (err != 0) 930319436Sslm mpr_dprint(sc, MPR_FAULT, "%s: failed to copy IOCTL " 931319436Sslm "data from user space\n", __func__); 932265236Sken } 933265236Sken /* 934265236Sken * Set this flag only if processing a command that does not need an 935265236Sken * IEEE SGL. The CLI Tool within the Toolbox uses IEEE SGLs, so clear 936265236Sken * the flag only for that tool if processing a Toolbox function. 937265236Sken */ 938265236Sken cm->cm_flags |= MPR_CM_FLAGS_SGE_SIMPLE; 939265236Sken for (i = 0; i < sizeof (ieee_sgl_func_list); i++) { 940265236Sken if (function == ieee_sgl_func_list[i]) { 941265236Sken if (function == MPI2_FUNCTION_TOOLBOX) 942265236Sken { 943265236Sken tool = (uint8_t)hdr->FunctionDependent1; 944265236Sken if (tool != MPI2_TOOLBOX_DIAGNOSTIC_CLI_TOOL) 945265236Sken break; 946265236Sken } 947265236Sken cm->cm_flags &= ~MPR_CM_FLAGS_SGE_SIMPLE; 948265236Sken break; 949265236Sken } 950265236Sken } 951265236Sken cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 952265236Sken 953319436Sslm if (function == MPI2_FUNCTION_NVME_ENCAPSULATED) { 954319436Sslm nvme_encap_request = 955319436Sslm (Mpi26NVMeEncapsulatedRequest_t *)cm->cm_req; 956319436Sslm cm->cm_desc.Default.RequestFlags = 957319436Sslm MPI26_REQ_DESCRIPT_FLAGS_PCIE_ENCAPSULATED; 958319436Sslm 959319436Sslm /* 960319436Sslm * Get the Physical Address of the sense buffer. 961319436Sslm * Save the user's Error Response buffer address and use that 962319436Sslm * field to hold the sense buffer address. 963319436Sslm * Clear the internal sense buffer, which will potentially hold 964319436Sslm * the Completion Queue Entry on return, or 0 if no Entry. 965319436Sslm * Build the PRPs and set direction bits. 966319436Sslm * Send the request. 967319436Sslm */ 968319436Sslm cm->nvme_error_response = 969319436Sslm (uint64_t *)(uintptr_t)(((uint64_t)nvme_encap_request-> 970319436Sslm ErrorResponseBaseAddress.High << 32) | 971319436Sslm (uint64_t)nvme_encap_request-> 972319436Sslm ErrorResponseBaseAddress.Low); 973319436Sslm nvme_encap_request->ErrorResponseBaseAddress.High = 974319436Sslm htole32((uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32)); 975319436Sslm nvme_encap_request->ErrorResponseBaseAddress.Low = 976319436Sslm htole32(cm->cm_sense_busaddr); 977319436Sslm memset(cm->cm_sense, 0, NVME_ERROR_RESPONSE_SIZE); 978319436Sslm mpr_build_nvme_prp(sc, cm, nvme_encap_request, cm->cm_data, 979319436Sslm data->DataSize, data->DataOutSize); 980319436Sslm } 981319436Sslm 982265236Sken /* 983265236Sken * Set up Sense buffer and SGL offset for IO passthru. SCSI IO request 984265236Sken * uses SCSI IO or Fast Path SCSI IO descriptor. 985265236Sken */ 986265236Sken if ((function == MPI2_FUNCTION_SCSI_IO_REQUEST) || 987265236Sken (function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { 988265236Sken MPI2_SCSI_IO_REQUEST *scsi_io_req; 989265236Sken 990265236Sken scsi_io_req = (MPI2_SCSI_IO_REQUEST *)hdr; 991265236Sken /* 992265236Sken * Put SGE for data and data_out buffer at the end of 993265236Sken * scsi_io_request message header (64 bytes in total). 994265236Sken * Following above SGEs, the residual space will be used by 995265236Sken * sense data. 996265236Sken */ 997265236Sken scsi_io_req->SenseBufferLength = (uint8_t)(data->RequestSize - 998265236Sken 64); 999265236Sken scsi_io_req->SenseBufferLowAddress = 1000265236Sken htole32(cm->cm_sense_busaddr); 1001265236Sken 1002265236Sken /* 1003265236Sken * Set SGLOffset0 value. This is the number of dwords that SGL 1004265236Sken * is offset from the beginning of MPI2_SCSI_IO_REQUEST struct. 1005265236Sken */ 1006265236Sken scsi_io_req->SGLOffset0 = 24; 1007265236Sken 1008265236Sken /* 1009265236Sken * Setup descriptor info. RAID passthrough must use the 1010265236Sken * default request descriptor which is already set, so if this 1011265236Sken * is a SCSI IO request, change the descriptor to SCSI IO or 1012265236Sken * Fast Path SCSI IO. Also, if this is a SCSI IO request, 1013265236Sken * handle the reply in the mprsas_scsio_complete function. 1014265236Sken */ 1015265236Sken if (function == MPI2_FUNCTION_SCSI_IO_REQUEST) { 1016265236Sken targ = mprsas_find_target_by_handle(sc->sassc, 0, 1017265236Sken scsi_io_req->DevHandle); 1018265236Sken 1019265236Sken if (!targ) { 1020265236Sken printf("No Target found for handle %d\n", 1021265236Sken scsi_io_req->DevHandle); 1022265236Sken err = EINVAL; 1023265236Sken goto RetFreeUnlocked; 1024265236Sken } 1025265236Sken 1026265236Sken if (targ->scsi_req_desc_type == 1027265236Sken MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO) { 1028265236Sken cm->cm_desc.FastPathSCSIIO.RequestFlags = 1029265236Sken MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO; 1030319436Sslm if (!sc->atomic_desc_capable) { 1031319436Sslm cm->cm_desc.FastPathSCSIIO.DevHandle = 1032319436Sslm scsi_io_req->DevHandle; 1033319436Sslm } 1034265236Sken scsi_io_req->IoFlags |= 1035265236Sken MPI25_SCSIIO_IOFLAGS_FAST_PATH; 1036265236Sken } else { 1037265236Sken cm->cm_desc.SCSIIO.RequestFlags = 1038265236Sken MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; 1039319436Sslm if (!sc->atomic_desc_capable) { 1040319436Sslm cm->cm_desc.SCSIIO.DevHandle = 1041319436Sslm scsi_io_req->DevHandle; 1042319436Sslm } 1043265236Sken } 1044265236Sken 1045265236Sken /* 1046265236Sken * Make sure the DevHandle is not 0 because this is a 1047265236Sken * likely error. 1048265236Sken */ 1049265236Sken if (scsi_io_req->DevHandle == 0) { 1050265236Sken err = EINVAL; 1051265236Sken goto RetFreeUnlocked; 1052265236Sken } 1053265236Sken } 1054265236Sken } 1055265236Sken 1056265236Sken mpr_lock(sc); 1057265236Sken 1058322661Sken err = mpr_wait_command(sc, &cm, 30, CAN_SLEEP); 1059265236Sken 1060322661Sken if (err || (cm == NULL)) { 1061265236Sken mpr_printf(sc, "%s: invalid request: error %d\n", __func__, 1062265236Sken err); 1063322661Sken goto RetFree; 1064265236Sken } 1065265236Sken 1066265236Sken /* 1067265236Sken * Sync the DMA data, if any. Then copy the data to user space. 1068265236Sken */ 1069265236Sken if (cm->cm_data != NULL) { 1070265236Sken if (cm->cm_flags & MPR_CM_FLAGS_DATAIN) 1071265236Sken dir = BUS_DMASYNC_POSTREAD; 1072265236Sken else if (cm->cm_flags & MPR_CM_FLAGS_DATAOUT) 1073283990Sslm dir = BUS_DMASYNC_POSTWRITE; 1074265236Sken bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir); 1075265236Sken bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap); 1076265236Sken 1077265236Sken if (cm->cm_flags & MPR_CM_FLAGS_DATAIN) { 1078265236Sken mpr_unlock(sc); 1079265236Sken err = copyout(cm->cm_data, 1080265236Sken PTRIN(data->PtrData), data->DataSize); 1081265236Sken mpr_lock(sc); 1082265236Sken if (err != 0) 1083265236Sken mpr_dprint(sc, MPR_FAULT, "%s: failed to copy " 1084265236Sken "IOCTL data to user space\n", __func__); 1085265236Sken } 1086265236Sken } 1087265236Sken 1088265236Sken /* 1089265236Sken * Copy the reply data and sense data to user space. 1090265236Sken */ 1091265236Sken if (cm->cm_reply != NULL) { 1092265236Sken rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply; 1093265236Sken sz = rpl->MsgLength * 4; 1094265236Sken 1095265236Sken if (sz > data->ReplySize) { 1096265236Sken mpr_printf(sc, "%s: user reply buffer (%d) smaller " 1097265236Sken "than returned buffer (%d)\n", __func__, 1098265236Sken data->ReplySize, sz); 1099265236Sken } 1100265236Sken mpr_unlock(sc); 1101265236Sken copyout(cm->cm_reply, PTRIN(data->PtrReply), data->ReplySize); 1102265236Sken mpr_lock(sc); 1103265236Sken 1104265236Sken if ((function == MPI2_FUNCTION_SCSI_IO_REQUEST) || 1105265236Sken (function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { 1106265236Sken if (((MPI2_SCSI_IO_REPLY *)rpl)->SCSIState & 1107265236Sken MPI2_SCSI_STATE_AUTOSENSE_VALID) { 1108265236Sken sense_len = 1109265236Sken MIN((le32toh(((MPI2_SCSI_IO_REPLY *)rpl)-> 1110265236Sken SenseCount)), sizeof(struct 1111265236Sken scsi_sense_data)); 1112265236Sken mpr_unlock(sc); 1113265236Sken copyout(cm->cm_sense, cm->cm_req + 64, 1114265236Sken sense_len); 1115265236Sken mpr_lock(sc); 1116265236Sken } 1117265236Sken } 1118319436Sslm 1119319436Sslm /* 1120319436Sslm * Copy out the NVMe Error Reponse to user. The Error Response 1121319436Sslm * buffer is given by the user, but a sense buffer is used to 1122319436Sslm * get that data from the IOC. The user's 1123319436Sslm * ErrorResponseBaseAddress is saved in the 1124319436Sslm * 'nvme_error_response' field before the command because that 1125319436Sslm * field is set to a sense buffer. When the command is 1126319436Sslm * complete, the Error Response data from the IOC is copied to 1127319436Sslm * that user address after it is checked for validity. 1128319436Sslm * Also note that 'sense' buffers are not defined for 1129319436Sslm * NVMe commands. Sense terminalogy is only used here so that 1130319436Sslm * the same IOCTL structure and sense buffers can be used for 1131319436Sslm * NVMe. 1132319436Sslm */ 1133319436Sslm if (function == MPI2_FUNCTION_NVME_ENCAPSULATED) { 1134319436Sslm if (cm->nvme_error_response == NULL) { 1135319436Sslm mpr_dprint(sc, MPR_INFO, "NVMe Error Response " 1136319436Sslm "buffer is NULL. Response data will not be " 1137319436Sslm "returned.\n"); 1138319436Sslm mpr_unlock(sc); 1139319436Sslm goto RetFreeUnlocked; 1140319436Sslm } 1141319436Sslm 1142319436Sslm nvme_error_reply = 1143319436Sslm (Mpi26NVMeEncapsulatedErrorReply_t *)cm->cm_reply; 1144319436Sslm sz = MIN(le32toh(nvme_error_reply->ErrorResponseCount), 1145319436Sslm NVME_ERROR_RESPONSE_SIZE); 1146319436Sslm mpr_unlock(sc); 1147319436Sslm copyout(cm->cm_sense, cm->nvme_error_response, sz); 1148319436Sslm mpr_lock(sc); 1149319436Sslm } 1150265236Sken } 1151265236Sken mpr_unlock(sc); 1152265236Sken 1153265236SkenRetFreeUnlocked: 1154265236Sken mpr_lock(sc); 1155265236Sken 1156322661SkenRetFree: 1157265236Sken if (cm != NULL) { 1158265236Sken if (cm->cm_data) 1159265236Sken free(cm->cm_data, M_MPRUSER); 1160265236Sken mpr_free_command(sc, cm); 1161265236Sken } 1162265236SkenRet: 1163265236Sken sc->mpr_flags &= ~MPR_FLAGS_BUSY; 1164265236Sken mpr_unlock(sc); 1165265236Sken 1166265236Sken return (err); 1167265236Sken} 1168265236Sken 1169265236Skenstatic void 1170265236Skenmpr_user_get_adapter_data(struct mpr_softc *sc, mpr_adapter_data_t *data) 1171265236Sken{ 1172265236Sken Mpi2ConfigReply_t mpi_reply; 1173265236Sken Mpi2BiosPage3_t config_page; 1174265236Sken 1175265236Sken /* 1176265236Sken * Use the PCI interface functions to get the Bus, Device, and Function 1177265236Sken * information. 1178265236Sken */ 1179265236Sken data->PciInformation.u.bits.BusNumber = pci_get_bus(sc->mpr_dev); 1180265236Sken data->PciInformation.u.bits.DeviceNumber = pci_get_slot(sc->mpr_dev); 1181265236Sken data->PciInformation.u.bits.FunctionNumber = 1182265236Sken pci_get_function(sc->mpr_dev); 1183265236Sken 1184265236Sken /* 1185265236Sken * Get the FW version that should already be saved in IOC Facts. 1186265236Sken */ 1187265236Sken data->MpiFirmwareVersion = sc->facts->FWVersion.Word; 1188265236Sken 1189265236Sken /* 1190265236Sken * General device info. 1191265236Sken */ 1192265236Sken data->AdapterType = MPRIOCTL_ADAPTER_TYPE_SAS3; 1193265236Sken data->PCIDeviceHwId = pci_get_device(sc->mpr_dev); 1194265236Sken data->PCIDeviceHwRev = pci_read_config(sc->mpr_dev, PCIR_REVID, 1); 1195265236Sken data->SubSystemId = pci_get_subdevice(sc->mpr_dev); 1196265236Sken data->SubsystemVendorId = pci_get_subvendor(sc->mpr_dev); 1197265236Sken 1198265236Sken /* 1199265236Sken * Get the driver version. 1200265236Sken */ 1201265236Sken strcpy((char *)&data->DriverVersion[0], MPR_DRIVER_VERSION); 1202265236Sken 1203265236Sken /* 1204265236Sken * Need to get BIOS Config Page 3 for the BIOS Version. 1205265236Sken */ 1206265236Sken data->BiosVersion = 0; 1207265236Sken mpr_lock(sc); 1208265236Sken if (mpr_config_get_bios_pg3(sc, &mpi_reply, &config_page)) 1209265236Sken printf("%s: Error while retrieving BIOS Version\n", __func__); 1210265236Sken else 1211265236Sken data->BiosVersion = config_page.BiosVersion; 1212265236Sken mpr_unlock(sc); 1213265236Sken} 1214265236Sken 1215265236Skenstatic void 1216265236Skenmpr_user_read_pci_info(struct mpr_softc *sc, mpr_pci_info_t *data) 1217265236Sken{ 1218265236Sken int i; 1219265236Sken 1220265236Sken /* 1221265236Sken * Use the PCI interface functions to get the Bus, Device, and Function 1222265236Sken * information. 1223265236Sken */ 1224265236Sken data->BusNumber = pci_get_bus(sc->mpr_dev); 1225265236Sken data->DeviceNumber = pci_get_slot(sc->mpr_dev); 1226265236Sken data->FunctionNumber = pci_get_function(sc->mpr_dev); 1227265236Sken 1228265236Sken /* 1229265236Sken * Now get the interrupt vector and the pci header. The vector can 1230265236Sken * only be 0 right now. The header is the first 256 bytes of config 1231265236Sken * space. 1232265236Sken */ 1233265236Sken data->InterruptVector = 0; 1234265236Sken for (i = 0; i < sizeof (data->PciHeader); i++) { 1235265236Sken data->PciHeader[i] = pci_read_config(sc->mpr_dev, i, 1); 1236265236Sken } 1237265236Sken} 1238265236Sken 1239265236Skenstatic uint8_t 1240265236Skenmpr_get_fw_diag_buffer_number(struct mpr_softc *sc, uint32_t unique_id) 1241265236Sken{ 1242265236Sken uint8_t index; 1243265236Sken 1244265236Sken for (index = 0; index < MPI2_DIAG_BUF_TYPE_COUNT; index++) { 1245265236Sken if (sc->fw_diag_buffer_list[index].unique_id == unique_id) { 1246265236Sken return (index); 1247265236Sken } 1248265236Sken } 1249265236Sken 1250265236Sken return (MPR_FW_DIAGNOSTIC_UID_NOT_FOUND); 1251265236Sken} 1252265236Sken 1253265236Skenstatic int 1254265236Skenmpr_post_fw_diag_buffer(struct mpr_softc *sc, 1255265236Sken mpr_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code) 1256265236Sken{ 1257265236Sken MPI2_DIAG_BUFFER_POST_REQUEST *req; 1258265236Sken MPI2_DIAG_BUFFER_POST_REPLY *reply; 1259265236Sken struct mpr_command *cm = NULL; 1260265236Sken int i, status; 1261265236Sken 1262265236Sken /* 1263265236Sken * If buffer is not enabled, just leave. 1264265236Sken */ 1265265236Sken *return_code = MPR_FW_DIAG_ERROR_POST_FAILED; 1266265236Sken if (!pBuffer->enabled) { 1267265236Sken return (MPR_DIAG_FAILURE); 1268265236Sken } 1269265236Sken 1270265236Sken /* 1271265236Sken * Clear some flags initially. 1272265236Sken */ 1273265236Sken pBuffer->force_release = FALSE; 1274265236Sken pBuffer->valid_data = FALSE; 1275265236Sken pBuffer->owned_by_firmware = FALSE; 1276265236Sken 1277265236Sken /* 1278265236Sken * Get a command. 1279265236Sken */ 1280265236Sken cm = mpr_alloc_command(sc); 1281265236Sken if (cm == NULL) { 1282265236Sken mpr_printf(sc, "%s: no mpr requests\n", __func__); 1283265236Sken return (MPR_DIAG_FAILURE); 1284265236Sken } 1285265236Sken 1286265236Sken /* 1287265236Sken * Build the request for releasing the FW Diag Buffer and send it. 1288265236Sken */ 1289265236Sken req = (MPI2_DIAG_BUFFER_POST_REQUEST *)cm->cm_req; 1290265236Sken req->Function = MPI2_FUNCTION_DIAG_BUFFER_POST; 1291265236Sken req->BufferType = pBuffer->buffer_type; 1292265236Sken req->ExtendedType = pBuffer->extended_type; 1293265236Sken req->BufferLength = pBuffer->size; 1294265236Sken for (i = 0; i < (sizeof(req->ProductSpecific) / 4); i++) 1295265236Sken req->ProductSpecific[i] = pBuffer->product_specific[i]; 1296265236Sken mpr_from_u64(sc->fw_diag_busaddr, &req->BufferAddress); 1297265236Sken cm->cm_data = NULL; 1298265236Sken cm->cm_length = 0; 1299265236Sken cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 1300265236Sken cm->cm_complete_data = NULL; 1301265236Sken 1302265236Sken /* 1303265236Sken * Send command synchronously. 1304265236Sken */ 1305322661Sken status = mpr_wait_command(sc, &cm, 30, CAN_SLEEP); 1306322661Sken if (status || (cm == NULL)) { 1307265236Sken mpr_printf(sc, "%s: invalid request: error %d\n", __func__, 1308265236Sken status); 1309265236Sken status = MPR_DIAG_FAILURE; 1310265236Sken goto done; 1311265236Sken } 1312265236Sken 1313265236Sken /* 1314265236Sken * Process POST reply. 1315265236Sken */ 1316265236Sken reply = (MPI2_DIAG_BUFFER_POST_REPLY *)cm->cm_reply; 1317299962Sslm if ((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) != 1318299962Sslm MPI2_IOCSTATUS_SUCCESS) { 1319265236Sken status = MPR_DIAG_FAILURE; 1320265236Sken mpr_dprint(sc, MPR_FAULT, "%s: post of FW Diag Buffer failed " 1321265236Sken "with IOCStatus = 0x%x, IOCLogInfo = 0x%x and " 1322299962Sslm "TransferLength = 0x%x\n", __func__, 1323299962Sslm le16toh(reply->IOCStatus), le32toh(reply->IOCLogInfo), 1324299962Sslm le32toh(reply->TransferLength)); 1325265236Sken goto done; 1326265236Sken } 1327265236Sken 1328265236Sken /* 1329265236Sken * Post was successful. 1330265236Sken */ 1331265236Sken pBuffer->valid_data = TRUE; 1332265236Sken pBuffer->owned_by_firmware = TRUE; 1333265236Sken *return_code = MPR_FW_DIAG_ERROR_SUCCESS; 1334265236Sken status = MPR_DIAG_SUCCESS; 1335265236Sken 1336265236Skendone: 1337322661Sken if (cm != NULL) 1338322661Sken mpr_free_command(sc, cm); 1339265236Sken return (status); 1340265236Sken} 1341265236Sken 1342265236Skenstatic int 1343265236Skenmpr_release_fw_diag_buffer(struct mpr_softc *sc, 1344265236Sken mpr_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code, 1345265236Sken uint32_t diag_type) 1346265236Sken{ 1347265236Sken MPI2_DIAG_RELEASE_REQUEST *req; 1348265236Sken MPI2_DIAG_RELEASE_REPLY *reply; 1349265236Sken struct mpr_command *cm = NULL; 1350265236Sken int status; 1351265236Sken 1352265236Sken /* 1353265236Sken * If buffer is not enabled, just leave. 1354265236Sken */ 1355265236Sken *return_code = MPR_FW_DIAG_ERROR_RELEASE_FAILED; 1356265236Sken if (!pBuffer->enabled) { 1357265236Sken mpr_dprint(sc, MPR_USER, "%s: This buffer type is not " 1358265236Sken "supported by the IOC", __func__); 1359265236Sken return (MPR_DIAG_FAILURE); 1360265236Sken } 1361265236Sken 1362265236Sken /* 1363265236Sken * Clear some flags initially. 1364265236Sken */ 1365265236Sken pBuffer->force_release = FALSE; 1366265236Sken pBuffer->valid_data = FALSE; 1367265236Sken pBuffer->owned_by_firmware = FALSE; 1368265236Sken 1369265236Sken /* 1370265236Sken * Get a command. 1371265236Sken */ 1372265236Sken cm = mpr_alloc_command(sc); 1373265236Sken if (cm == NULL) { 1374265236Sken mpr_printf(sc, "%s: no mpr requests\n", __func__); 1375265236Sken return (MPR_DIAG_FAILURE); 1376265236Sken } 1377265236Sken 1378265236Sken /* 1379265236Sken * Build the request for releasing the FW Diag Buffer and send it. 1380265236Sken */ 1381265236Sken req = (MPI2_DIAG_RELEASE_REQUEST *)cm->cm_req; 1382265236Sken req->Function = MPI2_FUNCTION_DIAG_RELEASE; 1383265236Sken req->BufferType = pBuffer->buffer_type; 1384265236Sken cm->cm_data = NULL; 1385265236Sken cm->cm_length = 0; 1386265236Sken cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 1387265236Sken cm->cm_complete_data = NULL; 1388265236Sken 1389265236Sken /* 1390265236Sken * Send command synchronously. 1391265236Sken */ 1392322661Sken status = mpr_wait_command(sc, &cm, 30, CAN_SLEEP); 1393322661Sken if (status || (cm == NULL)) { 1394265236Sken mpr_printf(sc, "%s: invalid request: error %d\n", __func__, 1395265236Sken status); 1396265236Sken status = MPR_DIAG_FAILURE; 1397265236Sken goto done; 1398265236Sken } 1399265236Sken 1400265236Sken /* 1401265236Sken * Process RELEASE reply. 1402265236Sken */ 1403265236Sken reply = (MPI2_DIAG_RELEASE_REPLY *)cm->cm_reply; 1404299962Sslm if (((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) != 1405299962Sslm MPI2_IOCSTATUS_SUCCESS) || pBuffer->owned_by_firmware) { 1406265236Sken status = MPR_DIAG_FAILURE; 1407265236Sken mpr_dprint(sc, MPR_FAULT, "%s: release of FW Diag Buffer " 1408265236Sken "failed with IOCStatus = 0x%x and IOCLogInfo = 0x%x\n", 1409299962Sslm __func__, le16toh(reply->IOCStatus), 1410299962Sslm le32toh(reply->IOCLogInfo)); 1411265236Sken goto done; 1412265236Sken } 1413265236Sken 1414265236Sken /* 1415265236Sken * Release was successful. 1416265236Sken */ 1417265236Sken *return_code = MPR_FW_DIAG_ERROR_SUCCESS; 1418265236Sken status = MPR_DIAG_SUCCESS; 1419265236Sken 1420265236Sken /* 1421265236Sken * If this was for an UNREGISTER diag type command, clear the unique ID. 1422265236Sken */ 1423265236Sken if (diag_type == MPR_FW_DIAG_TYPE_UNREGISTER) { 1424265236Sken pBuffer->unique_id = MPR_FW_DIAG_INVALID_UID; 1425265236Sken } 1426265236Sken 1427265236Skendone: 1428322661Sken if (cm != NULL) 1429322661Sken mpr_free_command(sc, cm); 1430322661Sken 1431265236Sken return (status); 1432265236Sken} 1433265236Sken 1434265236Skenstatic int 1435283990Sslmmpr_diag_register(struct mpr_softc *sc, mpr_fw_diag_register_t *diag_register, 1436283990Sslm uint32_t *return_code) 1437265236Sken{ 1438265236Sken mpr_fw_diagnostic_buffer_t *pBuffer; 1439265236Sken uint8_t extended_type, buffer_type, i; 1440265236Sken uint32_t buffer_size; 1441265236Sken uint32_t unique_id; 1442265236Sken int status; 1443265236Sken 1444265236Sken extended_type = diag_register->ExtendedType; 1445265236Sken buffer_type = diag_register->BufferType; 1446265236Sken buffer_size = diag_register->RequestedBufferSize; 1447265236Sken unique_id = diag_register->UniqueId; 1448265236Sken 1449265236Sken /* 1450265236Sken * Check for valid buffer type 1451265236Sken */ 1452265236Sken if (buffer_type >= MPI2_DIAG_BUF_TYPE_COUNT) { 1453265236Sken *return_code = MPR_FW_DIAG_ERROR_INVALID_PARAMETER; 1454265236Sken return (MPR_DIAG_FAILURE); 1455265236Sken } 1456265236Sken 1457265236Sken /* 1458265236Sken * Get the current buffer and look up the unique ID. The unique ID 1459265236Sken * should not be found. If it is, the ID is already in use. 1460265236Sken */ 1461265236Sken i = mpr_get_fw_diag_buffer_number(sc, unique_id); 1462265236Sken pBuffer = &sc->fw_diag_buffer_list[buffer_type]; 1463265236Sken if (i != MPR_FW_DIAGNOSTIC_UID_NOT_FOUND) { 1464265236Sken *return_code = MPR_FW_DIAG_ERROR_INVALID_UID; 1465265236Sken return (MPR_DIAG_FAILURE); 1466265236Sken } 1467265236Sken 1468265236Sken /* 1469265236Sken * The buffer's unique ID should not be registered yet, and the given 1470265236Sken * unique ID cannot be 0. 1471265236Sken */ 1472265236Sken if ((pBuffer->unique_id != MPR_FW_DIAG_INVALID_UID) || 1473265236Sken (unique_id == MPR_FW_DIAG_INVALID_UID)) { 1474265236Sken *return_code = MPR_FW_DIAG_ERROR_INVALID_UID; 1475265236Sken return (MPR_DIAG_FAILURE); 1476265236Sken } 1477265236Sken 1478265236Sken /* 1479265236Sken * If this buffer is already posted as immediate, just change owner. 1480265236Sken */ 1481265236Sken if (pBuffer->immediate && pBuffer->owned_by_firmware && 1482265236Sken (pBuffer->unique_id == MPR_FW_DIAG_INVALID_UID)) { 1483265236Sken pBuffer->immediate = FALSE; 1484265236Sken pBuffer->unique_id = unique_id; 1485265236Sken return (MPR_DIAG_SUCCESS); 1486265236Sken } 1487265236Sken 1488265236Sken /* 1489265236Sken * Post a new buffer after checking if it's enabled. The DMA buffer 1490265236Sken * that is allocated will be contiguous (nsegments = 1). 1491265236Sken */ 1492265236Sken if (!pBuffer->enabled) { 1493265236Sken *return_code = MPR_FW_DIAG_ERROR_NO_BUFFER; 1494265236Sken return (MPR_DIAG_FAILURE); 1495265236Sken } 1496265236Sken if (bus_dma_tag_create( sc->mpr_parent_dmat, /* parent */ 1497265236Sken 1, 0, /* algnmnt, boundary */ 1498265236Sken BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 1499265236Sken BUS_SPACE_MAXADDR, /* highaddr */ 1500265236Sken NULL, NULL, /* filter, filterarg */ 1501265236Sken buffer_size, /* maxsize */ 1502265236Sken 1, /* nsegments */ 1503265236Sken buffer_size, /* maxsegsize */ 1504265236Sken 0, /* flags */ 1505265236Sken NULL, NULL, /* lockfunc, lockarg */ 1506265236Sken &sc->fw_diag_dmat)) { 1507265236Sken device_printf(sc->mpr_dev, "Cannot allocate FW diag buffer DMA " 1508265236Sken "tag\n"); 1509265236Sken return (ENOMEM); 1510265236Sken } 1511265236Sken if (bus_dmamem_alloc(sc->fw_diag_dmat, (void **)&sc->fw_diag_buffer, 1512265236Sken BUS_DMA_NOWAIT, &sc->fw_diag_map)) { 1513265236Sken device_printf(sc->mpr_dev, "Cannot allocate FW diag buffer " 1514265236Sken "memory\n"); 1515265236Sken return (ENOMEM); 1516265236Sken } 1517265236Sken bzero(sc->fw_diag_buffer, buffer_size); 1518265236Sken bus_dmamap_load(sc->fw_diag_dmat, sc->fw_diag_map, sc->fw_diag_buffer, 1519265236Sken buffer_size, mpr_memaddr_cb, &sc->fw_diag_busaddr, 0); 1520265236Sken pBuffer->size = buffer_size; 1521265236Sken 1522265236Sken /* 1523265236Sken * Copy the given info to the diag buffer and post the buffer. 1524265236Sken */ 1525265236Sken pBuffer->buffer_type = buffer_type; 1526265236Sken pBuffer->immediate = FALSE; 1527265236Sken if (buffer_type == MPI2_DIAG_BUF_TYPE_TRACE) { 1528265236Sken for (i = 0; i < (sizeof (pBuffer->product_specific) / 4); 1529265236Sken i++) { 1530265236Sken pBuffer->product_specific[i] = 1531265236Sken diag_register->ProductSpecific[i]; 1532265236Sken } 1533265236Sken } 1534265236Sken pBuffer->extended_type = extended_type; 1535265236Sken pBuffer->unique_id = unique_id; 1536265236Sken status = mpr_post_fw_diag_buffer(sc, pBuffer, return_code); 1537265236Sken 1538265236Sken /* 1539265236Sken * In case there was a failure, free the DMA buffer. 1540265236Sken */ 1541265236Sken if (status == MPR_DIAG_FAILURE) { 1542265236Sken if (sc->fw_diag_busaddr != 0) 1543265236Sken bus_dmamap_unload(sc->fw_diag_dmat, sc->fw_diag_map); 1544265236Sken if (sc->fw_diag_buffer != NULL) 1545265236Sken bus_dmamem_free(sc->fw_diag_dmat, sc->fw_diag_buffer, 1546265236Sken sc->fw_diag_map); 1547265236Sken if (sc->fw_diag_dmat != NULL) 1548265236Sken bus_dma_tag_destroy(sc->fw_diag_dmat); 1549265236Sken } 1550265236Sken 1551265236Sken return (status); 1552265236Sken} 1553265236Sken 1554265236Skenstatic int 1555265236Skenmpr_diag_unregister(struct mpr_softc *sc, 1556265236Sken mpr_fw_diag_unregister_t *diag_unregister, uint32_t *return_code) 1557265236Sken{ 1558265236Sken mpr_fw_diagnostic_buffer_t *pBuffer; 1559265236Sken uint8_t i; 1560265236Sken uint32_t unique_id; 1561265236Sken int status; 1562265236Sken 1563265236Sken unique_id = diag_unregister->UniqueId; 1564265236Sken 1565265236Sken /* 1566265236Sken * Get the current buffer and look up the unique ID. The unique ID 1567265236Sken * should be there. 1568265236Sken */ 1569265236Sken i = mpr_get_fw_diag_buffer_number(sc, unique_id); 1570265236Sken if (i == MPR_FW_DIAGNOSTIC_UID_NOT_FOUND) { 1571265236Sken *return_code = MPR_FW_DIAG_ERROR_INVALID_UID; 1572265236Sken return (MPR_DIAG_FAILURE); 1573265236Sken } 1574265236Sken 1575265236Sken pBuffer = &sc->fw_diag_buffer_list[i]; 1576265236Sken 1577265236Sken /* 1578265236Sken * Try to release the buffer from FW before freeing it. If release 1579265236Sken * fails, don't free the DMA buffer in case FW tries to access it 1580265236Sken * later. If buffer is not owned by firmware, can't release it. 1581265236Sken */ 1582265236Sken if (!pBuffer->owned_by_firmware) { 1583265236Sken status = MPR_DIAG_SUCCESS; 1584265236Sken } else { 1585265236Sken status = mpr_release_fw_diag_buffer(sc, pBuffer, return_code, 1586265236Sken MPR_FW_DIAG_TYPE_UNREGISTER); 1587265236Sken } 1588265236Sken 1589265236Sken /* 1590265236Sken * At this point, return the current status no matter what happens with 1591265236Sken * the DMA buffer. 1592265236Sken */ 1593265236Sken pBuffer->unique_id = MPR_FW_DIAG_INVALID_UID; 1594265236Sken if (status == MPR_DIAG_SUCCESS) { 1595265236Sken if (sc->fw_diag_busaddr != 0) 1596265236Sken bus_dmamap_unload(sc->fw_diag_dmat, sc->fw_diag_map); 1597265236Sken if (sc->fw_diag_buffer != NULL) 1598265236Sken bus_dmamem_free(sc->fw_diag_dmat, sc->fw_diag_buffer, 1599265236Sken sc->fw_diag_map); 1600265236Sken if (sc->fw_diag_dmat != NULL) 1601265236Sken bus_dma_tag_destroy(sc->fw_diag_dmat); 1602265236Sken } 1603265236Sken 1604265236Sken return (status); 1605265236Sken} 1606265236Sken 1607265236Skenstatic int 1608265236Skenmpr_diag_query(struct mpr_softc *sc, mpr_fw_diag_query_t *diag_query, 1609265236Sken uint32_t *return_code) 1610265236Sken{ 1611265236Sken mpr_fw_diagnostic_buffer_t *pBuffer; 1612265236Sken uint8_t i; 1613265236Sken uint32_t unique_id; 1614265236Sken 1615265236Sken unique_id = diag_query->UniqueId; 1616265236Sken 1617265236Sken /* 1618265236Sken * If ID is valid, query on ID. 1619265236Sken * If ID is invalid, query on buffer type. 1620265236Sken */ 1621265236Sken if (unique_id == MPR_FW_DIAG_INVALID_UID) { 1622265236Sken i = diag_query->BufferType; 1623265236Sken if (i >= MPI2_DIAG_BUF_TYPE_COUNT) { 1624265236Sken *return_code = MPR_FW_DIAG_ERROR_INVALID_UID; 1625265236Sken return (MPR_DIAG_FAILURE); 1626265236Sken } 1627265236Sken } else { 1628265236Sken i = mpr_get_fw_diag_buffer_number(sc, unique_id); 1629265236Sken if (i == MPR_FW_DIAGNOSTIC_UID_NOT_FOUND) { 1630265236Sken *return_code = MPR_FW_DIAG_ERROR_INVALID_UID; 1631265236Sken return (MPR_DIAG_FAILURE); 1632265236Sken } 1633265236Sken } 1634265236Sken 1635265236Sken /* 1636265236Sken * Fill query structure with the diag buffer info. 1637265236Sken */ 1638265236Sken pBuffer = &sc->fw_diag_buffer_list[i]; 1639265236Sken diag_query->BufferType = pBuffer->buffer_type; 1640265236Sken diag_query->ExtendedType = pBuffer->extended_type; 1641265236Sken if (diag_query->BufferType == MPI2_DIAG_BUF_TYPE_TRACE) { 1642265236Sken for (i = 0; i < (sizeof(diag_query->ProductSpecific) / 4); 1643265236Sken i++) { 1644265236Sken diag_query->ProductSpecific[i] = 1645265236Sken pBuffer->product_specific[i]; 1646265236Sken } 1647265236Sken } 1648265236Sken diag_query->TotalBufferSize = pBuffer->size; 1649265236Sken diag_query->DriverAddedBufferSize = 0; 1650265236Sken diag_query->UniqueId = pBuffer->unique_id; 1651265236Sken diag_query->ApplicationFlags = 0; 1652265236Sken diag_query->DiagnosticFlags = 0; 1653265236Sken 1654265236Sken /* 1655265236Sken * Set/Clear application flags 1656265236Sken */ 1657265236Sken if (pBuffer->immediate) { 1658265236Sken diag_query->ApplicationFlags &= ~MPR_FW_DIAG_FLAG_APP_OWNED; 1659265236Sken } else { 1660265236Sken diag_query->ApplicationFlags |= MPR_FW_DIAG_FLAG_APP_OWNED; 1661265236Sken } 1662265236Sken if (pBuffer->valid_data || pBuffer->owned_by_firmware) { 1663265236Sken diag_query->ApplicationFlags |= MPR_FW_DIAG_FLAG_BUFFER_VALID; 1664265236Sken } else { 1665265236Sken diag_query->ApplicationFlags &= ~MPR_FW_DIAG_FLAG_BUFFER_VALID; 1666265236Sken } 1667265236Sken if (pBuffer->owned_by_firmware) { 1668265236Sken diag_query->ApplicationFlags |= 1669265236Sken MPR_FW_DIAG_FLAG_FW_BUFFER_ACCESS; 1670265236Sken } else { 1671265236Sken diag_query->ApplicationFlags &= 1672265236Sken ~MPR_FW_DIAG_FLAG_FW_BUFFER_ACCESS; 1673265236Sken } 1674265236Sken 1675265236Sken return (MPR_DIAG_SUCCESS); 1676265236Sken} 1677265236Sken 1678265236Skenstatic int 1679265236Skenmpr_diag_read_buffer(struct mpr_softc *sc, 1680265236Sken mpr_diag_read_buffer_t *diag_read_buffer, uint8_t *ioctl_buf, 1681265236Sken uint32_t *return_code) 1682265236Sken{ 1683265236Sken mpr_fw_diagnostic_buffer_t *pBuffer; 1684265236Sken uint8_t i, *pData; 1685265236Sken uint32_t unique_id; 1686265236Sken int status; 1687265236Sken 1688265236Sken unique_id = diag_read_buffer->UniqueId; 1689265236Sken 1690265236Sken /* 1691265236Sken * Get the current buffer and look up the unique ID. The unique ID 1692265236Sken * should be there. 1693265236Sken */ 1694265236Sken i = mpr_get_fw_diag_buffer_number(sc, unique_id); 1695265236Sken if (i == MPR_FW_DIAGNOSTIC_UID_NOT_FOUND) { 1696265236Sken *return_code = MPR_FW_DIAG_ERROR_INVALID_UID; 1697265236Sken return (MPR_DIAG_FAILURE); 1698265236Sken } 1699265236Sken 1700265236Sken pBuffer = &sc->fw_diag_buffer_list[i]; 1701265236Sken 1702265236Sken /* 1703265236Sken * Make sure requested read is within limits 1704265236Sken */ 1705265236Sken if (diag_read_buffer->StartingOffset + diag_read_buffer->BytesToRead > 1706265236Sken pBuffer->size) { 1707265236Sken *return_code = MPR_FW_DIAG_ERROR_INVALID_PARAMETER; 1708265236Sken return (MPR_DIAG_FAILURE); 1709265236Sken } 1710265236Sken 1711265236Sken /* 1712265236Sken * Copy the requested data from DMA to the diag_read_buffer. The DMA 1713265236Sken * buffer that was allocated is one contiguous buffer. 1714265236Sken */ 1715265236Sken pData = (uint8_t *)(sc->fw_diag_buffer + 1716265236Sken diag_read_buffer->StartingOffset); 1717265236Sken if (copyout(pData, ioctl_buf, diag_read_buffer->BytesToRead) != 0) 1718265236Sken return (MPR_DIAG_FAILURE); 1719265236Sken diag_read_buffer->Status = 0; 1720265236Sken 1721265236Sken /* 1722265236Sken * Set or clear the Force Release flag. 1723265236Sken */ 1724265236Sken if (pBuffer->force_release) { 1725265236Sken diag_read_buffer->Flags |= MPR_FW_DIAG_FLAG_FORCE_RELEASE; 1726265236Sken } else { 1727265236Sken diag_read_buffer->Flags &= ~MPR_FW_DIAG_FLAG_FORCE_RELEASE; 1728265236Sken } 1729265236Sken 1730265236Sken /* 1731265236Sken * If buffer is to be reregistered, make sure it's not already owned by 1732265236Sken * firmware first. 1733265236Sken */ 1734265236Sken status = MPR_DIAG_SUCCESS; 1735265236Sken if (!pBuffer->owned_by_firmware) { 1736265236Sken if (diag_read_buffer->Flags & MPR_FW_DIAG_FLAG_REREGISTER) { 1737265236Sken status = mpr_post_fw_diag_buffer(sc, pBuffer, 1738265236Sken return_code); 1739265236Sken } 1740265236Sken } 1741265236Sken 1742265236Sken return (status); 1743265236Sken} 1744265236Sken 1745265236Skenstatic int 1746265236Skenmpr_diag_release(struct mpr_softc *sc, mpr_fw_diag_release_t *diag_release, 1747265236Sken uint32_t *return_code) 1748265236Sken{ 1749265236Sken mpr_fw_diagnostic_buffer_t *pBuffer; 1750265236Sken uint8_t i; 1751265236Sken uint32_t unique_id; 1752265236Sken int status; 1753265236Sken 1754265236Sken unique_id = diag_release->UniqueId; 1755265236Sken 1756265236Sken /* 1757265236Sken * Get the current buffer and look up the unique ID. The unique ID 1758265236Sken * should be there. 1759265236Sken */ 1760265236Sken i = mpr_get_fw_diag_buffer_number(sc, unique_id); 1761265236Sken if (i == MPR_FW_DIAGNOSTIC_UID_NOT_FOUND) { 1762265236Sken *return_code = MPR_FW_DIAG_ERROR_INVALID_UID; 1763265236Sken return (MPR_DIAG_FAILURE); 1764265236Sken } 1765265236Sken 1766265236Sken pBuffer = &sc->fw_diag_buffer_list[i]; 1767265236Sken 1768265236Sken /* 1769265236Sken * If buffer is not owned by firmware, it's already been released. 1770265236Sken */ 1771265236Sken if (!pBuffer->owned_by_firmware) { 1772265236Sken *return_code = MPR_FW_DIAG_ERROR_ALREADY_RELEASED; 1773265236Sken return (MPR_DIAG_FAILURE); 1774265236Sken } 1775265236Sken 1776265236Sken /* 1777265236Sken * Release the buffer. 1778265236Sken */ 1779265236Sken status = mpr_release_fw_diag_buffer(sc, pBuffer, return_code, 1780265236Sken MPR_FW_DIAG_TYPE_RELEASE); 1781265236Sken return (status); 1782265236Sken} 1783265236Sken 1784265236Skenstatic int 1785299962Sslmmpr_do_diag_action(struct mpr_softc *sc, uint32_t action, uint8_t *diag_action, 1786299962Sslm uint32_t length, uint32_t *return_code) 1787265236Sken{ 1788265236Sken mpr_fw_diag_register_t diag_register; 1789265236Sken mpr_fw_diag_unregister_t diag_unregister; 1790265236Sken mpr_fw_diag_query_t diag_query; 1791265236Sken mpr_diag_read_buffer_t diag_read_buffer; 1792265236Sken mpr_fw_diag_release_t diag_release; 1793265236Sken int status = MPR_DIAG_SUCCESS; 1794265236Sken uint32_t original_return_code; 1795265236Sken 1796265236Sken original_return_code = *return_code; 1797265236Sken *return_code = MPR_FW_DIAG_ERROR_SUCCESS; 1798265236Sken 1799265236Sken switch (action) { 1800265236Sken case MPR_FW_DIAG_TYPE_REGISTER: 1801265236Sken if (!length) { 1802265236Sken *return_code = 1803265236Sken MPR_FW_DIAG_ERROR_INVALID_PARAMETER; 1804265236Sken status = MPR_DIAG_FAILURE; 1805265236Sken break; 1806265236Sken } 1807265236Sken if (copyin(diag_action, &diag_register, 1808265236Sken sizeof(diag_register)) != 0) 1809265236Sken return (MPR_DIAG_FAILURE); 1810265236Sken status = mpr_diag_register(sc, &diag_register, 1811265236Sken return_code); 1812265236Sken break; 1813265236Sken 1814265236Sken case MPR_FW_DIAG_TYPE_UNREGISTER: 1815265236Sken if (length < sizeof(diag_unregister)) { 1816265236Sken *return_code = 1817265236Sken MPR_FW_DIAG_ERROR_INVALID_PARAMETER; 1818265236Sken status = MPR_DIAG_FAILURE; 1819265236Sken break; 1820265236Sken } 1821265236Sken if (copyin(diag_action, &diag_unregister, 1822265236Sken sizeof(diag_unregister)) != 0) 1823265236Sken return (MPR_DIAG_FAILURE); 1824265236Sken status = mpr_diag_unregister(sc, &diag_unregister, 1825265236Sken return_code); 1826265236Sken break; 1827265236Sken 1828265236Sken case MPR_FW_DIAG_TYPE_QUERY: 1829265236Sken if (length < sizeof (diag_query)) { 1830265236Sken *return_code = 1831265236Sken MPR_FW_DIAG_ERROR_INVALID_PARAMETER; 1832265236Sken status = MPR_DIAG_FAILURE; 1833265236Sken break; 1834265236Sken } 1835265236Sken if (copyin(diag_action, &diag_query, sizeof(diag_query)) 1836265236Sken != 0) 1837265236Sken return (MPR_DIAG_FAILURE); 1838265236Sken status = mpr_diag_query(sc, &diag_query, return_code); 1839265236Sken if (status == MPR_DIAG_SUCCESS) 1840265236Sken if (copyout(&diag_query, diag_action, 1841265236Sken sizeof (diag_query)) != 0) 1842265236Sken return (MPR_DIAG_FAILURE); 1843265236Sken break; 1844265236Sken 1845265236Sken case MPR_FW_DIAG_TYPE_READ_BUFFER: 1846265236Sken if (copyin(diag_action, &diag_read_buffer, 1847265236Sken sizeof(diag_read_buffer)) != 0) 1848265236Sken return (MPR_DIAG_FAILURE); 1849265236Sken if (length < diag_read_buffer.BytesToRead) { 1850265236Sken *return_code = 1851265236Sken MPR_FW_DIAG_ERROR_INVALID_PARAMETER; 1852265236Sken status = MPR_DIAG_FAILURE; 1853265236Sken break; 1854265236Sken } 1855265236Sken status = mpr_diag_read_buffer(sc, &diag_read_buffer, 1856265236Sken PTRIN(diag_read_buffer.PtrDataBuffer), 1857265236Sken return_code); 1858265236Sken if (status == MPR_DIAG_SUCCESS) { 1859265236Sken if (copyout(&diag_read_buffer, diag_action, 1860265236Sken sizeof(diag_read_buffer) - 1861265236Sken sizeof(diag_read_buffer.PtrDataBuffer)) != 1862265236Sken 0) 1863265236Sken return (MPR_DIAG_FAILURE); 1864265236Sken } 1865265236Sken break; 1866265236Sken 1867265236Sken case MPR_FW_DIAG_TYPE_RELEASE: 1868265236Sken if (length < sizeof(diag_release)) { 1869265236Sken *return_code = 1870265236Sken MPR_FW_DIAG_ERROR_INVALID_PARAMETER; 1871265236Sken status = MPR_DIAG_FAILURE; 1872265236Sken break; 1873265236Sken } 1874265236Sken if (copyin(diag_action, &diag_release, 1875265236Sken sizeof(diag_release)) != 0) 1876265236Sken return (MPR_DIAG_FAILURE); 1877265236Sken status = mpr_diag_release(sc, &diag_release, 1878265236Sken return_code); 1879265236Sken break; 1880265236Sken 1881265236Sken default: 1882265236Sken *return_code = MPR_FW_DIAG_ERROR_INVALID_PARAMETER; 1883265236Sken status = MPR_DIAG_FAILURE; 1884265236Sken break; 1885265236Sken } 1886265236Sken 1887265236Sken if ((status == MPR_DIAG_FAILURE) && 1888265236Sken (original_return_code == MPR_FW_DIAG_NEW) && 1889265236Sken (*return_code != MPR_FW_DIAG_ERROR_SUCCESS)) 1890265236Sken status = MPR_DIAG_SUCCESS; 1891265236Sken 1892265236Sken return (status); 1893265236Sken} 1894265236Sken 1895265236Skenstatic int 1896265236Skenmpr_user_diag_action(struct mpr_softc *sc, mpr_diag_action_t *data) 1897265236Sken{ 1898265236Sken int status; 1899265236Sken 1900265236Sken /* 1901265236Sken * Only allow one diag action at one time. 1902265236Sken */ 1903265236Sken if (sc->mpr_flags & MPR_FLAGS_BUSY) { 1904265236Sken mpr_dprint(sc, MPR_USER, "%s: Only one FW diag command " 1905265236Sken "allowed at a single time.", __func__); 1906265236Sken return (EBUSY); 1907265236Sken } 1908265236Sken sc->mpr_flags |= MPR_FLAGS_BUSY; 1909265236Sken 1910265236Sken /* 1911265236Sken * Send diag action request 1912265236Sken */ 1913265236Sken if (data->Action == MPR_FW_DIAG_TYPE_REGISTER || 1914265236Sken data->Action == MPR_FW_DIAG_TYPE_UNREGISTER || 1915265236Sken data->Action == MPR_FW_DIAG_TYPE_QUERY || 1916265236Sken data->Action == MPR_FW_DIAG_TYPE_READ_BUFFER || 1917265236Sken data->Action == MPR_FW_DIAG_TYPE_RELEASE) { 1918265236Sken status = mpr_do_diag_action(sc, data->Action, 1919265236Sken PTRIN(data->PtrDiagAction), data->Length, 1920265236Sken &data->ReturnCode); 1921265236Sken } else 1922265236Sken status = EINVAL; 1923265236Sken 1924265236Sken sc->mpr_flags &= ~MPR_FLAGS_BUSY; 1925265236Sken return (status); 1926265236Sken} 1927265236Sken 1928265236Sken/* 1929265236Sken * Copy the event recording mask and the event queue size out. For 1930265236Sken * clarification, the event recording mask (events_to_record) is not the same 1931265236Sken * thing as the event mask (event_mask). events_to_record has a bit set for 1932265236Sken * every event type that is to be recorded by the driver, and event_mask has a 1933265236Sken * bit cleared for every event that is allowed into the driver from the IOC. 1934265236Sken * They really have nothing to do with each other. 1935265236Sken */ 1936265236Skenstatic void 1937265236Skenmpr_user_event_query(struct mpr_softc *sc, mpr_event_query_t *data) 1938265236Sken{ 1939265236Sken uint8_t i; 1940265236Sken 1941265236Sken mpr_lock(sc); 1942265236Sken data->Entries = MPR_EVENT_QUEUE_SIZE; 1943265236Sken 1944265236Sken for (i = 0; i < 4; i++) { 1945265236Sken data->Types[i] = sc->events_to_record[i]; 1946265236Sken } 1947265236Sken mpr_unlock(sc); 1948265236Sken} 1949265236Sken 1950265236Sken/* 1951265236Sken * Set the driver's event mask according to what's been given. See 1952265236Sken * mpr_user_event_query for explanation of the event recording mask and the IOC 1953265236Sken * event mask. It's the app's responsibility to enable event logging by setting 1954265236Sken * the bits in events_to_record. Initially, no events will be logged. 1955265236Sken */ 1956265236Skenstatic void 1957265236Skenmpr_user_event_enable(struct mpr_softc *sc, mpr_event_enable_t *data) 1958265236Sken{ 1959265236Sken uint8_t i; 1960265236Sken 1961265236Sken mpr_lock(sc); 1962265236Sken for (i = 0; i < 4; i++) { 1963265236Sken sc->events_to_record[i] = data->Types[i]; 1964265236Sken } 1965265236Sken mpr_unlock(sc); 1966265236Sken} 1967265236Sken 1968265236Sken/* 1969265236Sken * Copy out the events that have been recorded, up to the max events allowed. 1970265236Sken */ 1971265236Skenstatic int 1972265236Skenmpr_user_event_report(struct mpr_softc *sc, mpr_event_report_t *data) 1973265236Sken{ 1974265236Sken int status = 0; 1975265236Sken uint32_t size; 1976265236Sken 1977265236Sken mpr_lock(sc); 1978265236Sken size = data->Size; 1979265236Sken if ((size >= sizeof(sc->recorded_events)) && (status == 0)) { 1980265236Sken mpr_unlock(sc); 1981265236Sken if (copyout((void *)sc->recorded_events, 1982265236Sken PTRIN(data->PtrEvents), size) != 0) 1983265236Sken status = EFAULT; 1984265236Sken mpr_lock(sc); 1985265236Sken } else { 1986265236Sken /* 1987265236Sken * data->Size value is not large enough to copy event data. 1988265236Sken */ 1989265236Sken status = EFAULT; 1990265236Sken } 1991265236Sken 1992265236Sken /* 1993265236Sken * Change size value to match the number of bytes that were copied. 1994265236Sken */ 1995265236Sken if (status == 0) 1996265236Sken data->Size = sizeof(sc->recorded_events); 1997265236Sken mpr_unlock(sc); 1998265236Sken 1999265236Sken return (status); 2000265236Sken} 2001265236Sken 2002265236Sken/* 2003265236Sken * Record events into the driver from the IOC if they are not masked. 2004265236Sken */ 2005265236Skenvoid 2006265236Skenmprsas_record_event(struct mpr_softc *sc, 2007265236Sken MPI2_EVENT_NOTIFICATION_REPLY *event_reply) 2008265236Sken{ 2009265236Sken uint32_t event; 2010265236Sken int i, j; 2011265236Sken uint16_t event_data_len; 2012265236Sken boolean_t sendAEN = FALSE; 2013265236Sken 2014265236Sken event = event_reply->Event; 2015265236Sken 2016265236Sken /* 2017265236Sken * Generate a system event to let anyone who cares know that a 2018265236Sken * LOG_ENTRY_ADDED event has occurred. This is sent no matter what the 2019265236Sken * event mask is set to. 2020265236Sken */ 2021265236Sken if (event == MPI2_EVENT_LOG_ENTRY_ADDED) { 2022265236Sken sendAEN = TRUE; 2023265236Sken } 2024265236Sken 2025265236Sken /* 2026265236Sken * Record the event only if its corresponding bit is set in 2027265236Sken * events_to_record. event_index is the index into recorded_events and 2028265236Sken * event_number is the overall number of an event being recorded since 2029265236Sken * start-of-day. event_index will roll over; event_number will never 2030265236Sken * roll over. 2031265236Sken */ 2032265236Sken i = (uint8_t)(event / 32); 2033265236Sken j = (uint8_t)(event % 32); 2034265236Sken if ((i < 4) && ((1 << j) & sc->events_to_record[i])) { 2035265236Sken i = sc->event_index; 2036265236Sken sc->recorded_events[i].Type = event; 2037265236Sken sc->recorded_events[i].Number = ++sc->event_number; 2038265236Sken bzero(sc->recorded_events[i].Data, MPR_MAX_EVENT_DATA_LENGTH * 2039265236Sken 4); 2040265236Sken event_data_len = event_reply->EventDataLength; 2041265236Sken 2042265236Sken if (event_data_len > 0) { 2043265236Sken /* 2044265236Sken * Limit data to size in m_event entry 2045265236Sken */ 2046265236Sken if (event_data_len > MPR_MAX_EVENT_DATA_LENGTH) { 2047265236Sken event_data_len = MPR_MAX_EVENT_DATA_LENGTH; 2048265236Sken } 2049265236Sken for (j = 0; j < event_data_len; j++) { 2050265236Sken sc->recorded_events[i].Data[j] = 2051265236Sken event_reply->EventData[j]; 2052265236Sken } 2053265236Sken 2054265236Sken /* 2055265236Sken * check for index wrap-around 2056265236Sken */ 2057265236Sken if (++i == MPR_EVENT_QUEUE_SIZE) { 2058265236Sken i = 0; 2059265236Sken } 2060265236Sken sc->event_index = (uint8_t)i; 2061265236Sken 2062265236Sken /* 2063265236Sken * Set flag to send the event. 2064265236Sken */ 2065265236Sken sendAEN = TRUE; 2066265236Sken } 2067265236Sken } 2068265236Sken 2069265236Sken /* 2070265236Sken * Generate a system event if flag is set to let anyone who cares know 2071265236Sken * that an event has occurred. 2072265236Sken */ 2073265236Sken if (sendAEN) { 2074265236Sken//SLM-how to send a system event (see kqueue, kevent) 2075265236Sken// (void) ddi_log_sysevent(mpt->m_dip, DDI_VENDOR_LSI, "MPT_SAS", 2076265236Sken// "SAS", NULL, NULL, DDI_NOSLEEP); 2077265236Sken } 2078265236Sken} 2079265236Sken 2080265236Skenstatic int 2081265236Skenmpr_user_reg_access(struct mpr_softc *sc, mpr_reg_access_t *data) 2082265236Sken{ 2083265236Sken int status = 0; 2084265236Sken 2085265236Sken switch (data->Command) { 2086265236Sken /* 2087265236Sken * IO access is not supported. 2088265236Sken */ 2089265236Sken case REG_IO_READ: 2090265236Sken case REG_IO_WRITE: 2091265236Sken mpr_dprint(sc, MPR_USER, "IO access is not supported. " 2092265236Sken "Use memory access."); 2093265236Sken status = EINVAL; 2094265236Sken break; 2095265236Sken 2096265236Sken case REG_MEM_READ: 2097265236Sken data->RegData = mpr_regread(sc, data->RegOffset); 2098265236Sken break; 2099265236Sken 2100265236Sken case REG_MEM_WRITE: 2101265236Sken mpr_regwrite(sc, data->RegOffset, data->RegData); 2102265236Sken break; 2103265236Sken 2104265236Sken default: 2105265236Sken status = EINVAL; 2106265236Sken break; 2107265236Sken } 2108265236Sken 2109265236Sken return (status); 2110265236Sken} 2111265236Sken 2112265236Skenstatic int 2113265236Skenmpr_user_btdh(struct mpr_softc *sc, mpr_btdh_mapping_t *data) 2114265236Sken{ 2115265236Sken uint8_t bt2dh = FALSE; 2116265236Sken uint8_t dh2bt = FALSE; 2117265236Sken uint16_t dev_handle, bus, target; 2118265236Sken 2119265236Sken bus = data->Bus; 2120265236Sken target = data->TargetID; 2121265236Sken dev_handle = data->DevHandle; 2122265236Sken 2123265236Sken /* 2124265236Sken * When DevHandle is 0xFFFF and Bus/Target are not 0xFFFF, use Bus/ 2125265236Sken * Target to get DevHandle. When Bus/Target are 0xFFFF and DevHandle is 2126265236Sken * not 0xFFFF, use DevHandle to get Bus/Target. Anything else is 2127265236Sken * invalid. 2128265236Sken */ 2129265236Sken if ((bus == 0xFFFF) && (target == 0xFFFF) && (dev_handle != 0xFFFF)) 2130265236Sken dh2bt = TRUE; 2131265236Sken if ((dev_handle == 0xFFFF) && (bus != 0xFFFF) && (target != 0xFFFF)) 2132265236Sken bt2dh = TRUE; 2133265236Sken if (!dh2bt && !bt2dh) 2134265236Sken return (EINVAL); 2135265236Sken 2136265236Sken /* 2137265236Sken * Only handle bus of 0. Make sure target is within range. 2138265236Sken */ 2139265236Sken if (bt2dh) { 2140265236Sken if (bus != 0) 2141265236Sken return (EINVAL); 2142265236Sken 2143265236Sken if (target > sc->max_devices) { 2144319436Sslm mpr_dprint(sc, MPR_XINFO, "Target ID is out of range " 2145265236Sken "for Bus/Target to DevHandle mapping."); 2146265236Sken return (EINVAL); 2147265236Sken } 2148265236Sken dev_handle = sc->mapping_table[target].dev_handle; 2149265236Sken if (dev_handle) 2150265236Sken data->DevHandle = dev_handle; 2151265236Sken } else { 2152265236Sken bus = 0; 2153319445Sslm target = mpr_mapping_get_tid_from_handle(sc, dev_handle); 2154265236Sken data->Bus = bus; 2155265236Sken data->TargetID = target; 2156265236Sken } 2157265236Sken 2158265236Sken return (0); 2159265236Sken} 2160265236Sken 2161265236Skenstatic int 2162265236Skenmpr_ioctl(struct cdev *dev, u_long cmd, void *arg, int flag, 2163265236Sken struct thread *td) 2164265236Sken{ 2165265236Sken struct mpr_softc *sc; 2166265236Sken struct mpr_cfg_page_req *page_req; 2167265236Sken struct mpr_ext_cfg_page_req *ext_page_req; 2168265236Sken void *mpr_page; 2169265236Sken int error, msleep_ret; 2170265236Sken 2171265236Sken mpr_page = NULL; 2172265236Sken sc = dev->si_drv1; 2173265236Sken page_req = (void *)arg; 2174265236Sken ext_page_req = (void *)arg; 2175265236Sken 2176265236Sken switch (cmd) { 2177265236Sken case MPRIO_READ_CFG_HEADER: 2178265236Sken mpr_lock(sc); 2179265236Sken error = mpr_user_read_cfg_header(sc, page_req); 2180265236Sken mpr_unlock(sc); 2181265236Sken break; 2182265236Sken case MPRIO_READ_CFG_PAGE: 2183265236Sken mpr_page = malloc(page_req->len, M_MPRUSER, M_WAITOK | M_ZERO); 2184265236Sken error = copyin(page_req->buf, mpr_page, 2185265236Sken sizeof(MPI2_CONFIG_PAGE_HEADER)); 2186265236Sken if (error) 2187265236Sken break; 2188265236Sken mpr_lock(sc); 2189265236Sken error = mpr_user_read_cfg_page(sc, page_req, mpr_page); 2190265236Sken mpr_unlock(sc); 2191265236Sken if (error) 2192265236Sken break; 2193265236Sken error = copyout(mpr_page, page_req->buf, page_req->len); 2194265236Sken break; 2195265236Sken case MPRIO_READ_EXT_CFG_HEADER: 2196265236Sken mpr_lock(sc); 2197265236Sken error = mpr_user_read_extcfg_header(sc, ext_page_req); 2198265236Sken mpr_unlock(sc); 2199265236Sken break; 2200265236Sken case MPRIO_READ_EXT_CFG_PAGE: 2201265236Sken mpr_page = malloc(ext_page_req->len, M_MPRUSER, 2202265236Sken M_WAITOK | M_ZERO); 2203265236Sken error = copyin(ext_page_req->buf, mpr_page, 2204265236Sken sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); 2205265236Sken if (error) 2206265236Sken break; 2207265236Sken mpr_lock(sc); 2208265236Sken error = mpr_user_read_extcfg_page(sc, ext_page_req, mpr_page); 2209265236Sken mpr_unlock(sc); 2210265236Sken if (error) 2211265236Sken break; 2212265236Sken error = copyout(mpr_page, ext_page_req->buf, ext_page_req->len); 2213265236Sken break; 2214265236Sken case MPRIO_WRITE_CFG_PAGE: 2215265236Sken mpr_page = malloc(page_req->len, M_MPRUSER, M_WAITOK|M_ZERO); 2216265236Sken error = copyin(page_req->buf, mpr_page, page_req->len); 2217265236Sken if (error) 2218265236Sken break; 2219265236Sken mpr_lock(sc); 2220265236Sken error = mpr_user_write_cfg_page(sc, page_req, mpr_page); 2221265236Sken mpr_unlock(sc); 2222265236Sken break; 2223265236Sken case MPRIO_MPR_COMMAND: 2224265236Sken error = mpr_user_command(sc, (struct mpr_usr_command *)arg); 2225265236Sken break; 2226265236Sken case MPTIOCTL_PASS_THRU: 2227265236Sken /* 2228265236Sken * The user has requested to pass through a command to be 2229265236Sken * executed by the MPT firmware. Call our routine which does 2230265236Sken * this. Only allow one passthru IOCTL at one time. 2231265236Sken */ 2232265236Sken error = mpr_user_pass_thru(sc, (mpr_pass_thru_t *)arg); 2233265236Sken break; 2234265236Sken case MPTIOCTL_GET_ADAPTER_DATA: 2235265236Sken /* 2236265236Sken * The user has requested to read adapter data. Call our 2237265236Sken * routine which does this. 2238265236Sken */ 2239265236Sken error = 0; 2240265236Sken mpr_user_get_adapter_data(sc, (mpr_adapter_data_t *)arg); 2241265236Sken break; 2242265236Sken case MPTIOCTL_GET_PCI_INFO: 2243265236Sken /* 2244265236Sken * The user has requested to read pci info. Call 2245265236Sken * our routine which does this. 2246265236Sken */ 2247265236Sken mpr_lock(sc); 2248265236Sken error = 0; 2249265236Sken mpr_user_read_pci_info(sc, (mpr_pci_info_t *)arg); 2250265236Sken mpr_unlock(sc); 2251265236Sken break; 2252265236Sken case MPTIOCTL_RESET_ADAPTER: 2253265236Sken mpr_lock(sc); 2254265236Sken sc->port_enable_complete = 0; 2255265236Sken uint32_t reinit_start = time_uptime; 2256265236Sken error = mpr_reinit(sc); 2257265236Sken /* Sleep for 300 second. */ 2258265236Sken msleep_ret = msleep(&sc->port_enable_complete, &sc->mpr_mtx, 2259265236Sken PRIBIO, "mpr_porten", 300 * hz); 2260265236Sken mpr_unlock(sc); 2261265236Sken if (msleep_ret) 2262265236Sken printf("Port Enable did not complete after Diag " 2263265236Sken "Reset msleep error %d.\n", msleep_ret); 2264265236Sken else 2265265236Sken mpr_dprint(sc, MPR_USER, "Hard Reset with Port Enable " 2266265236Sken "completed in %d seconds.\n", 2267265236Sken (uint32_t)(time_uptime - reinit_start)); 2268265236Sken break; 2269265236Sken case MPTIOCTL_DIAG_ACTION: 2270265236Sken /* 2271265236Sken * The user has done a diag buffer action. Call our routine 2272265236Sken * which does this. Only allow one diag action at one time. 2273265236Sken */ 2274265236Sken mpr_lock(sc); 2275265236Sken error = mpr_user_diag_action(sc, (mpr_diag_action_t *)arg); 2276265236Sken mpr_unlock(sc); 2277265236Sken break; 2278265236Sken case MPTIOCTL_EVENT_QUERY: 2279265236Sken /* 2280265236Sken * The user has done an event query. Call our routine which does 2281265236Sken * this. 2282265236Sken */ 2283265236Sken error = 0; 2284265236Sken mpr_user_event_query(sc, (mpr_event_query_t *)arg); 2285265236Sken break; 2286265236Sken case MPTIOCTL_EVENT_ENABLE: 2287265236Sken /* 2288265236Sken * The user has done an event enable. Call our routine which 2289265236Sken * does this. 2290265236Sken */ 2291265236Sken error = 0; 2292265236Sken mpr_user_event_enable(sc, (mpr_event_enable_t *)arg); 2293265236Sken break; 2294265236Sken case MPTIOCTL_EVENT_REPORT: 2295265236Sken /* 2296265236Sken * The user has done an event report. Call our routine which 2297265236Sken * does this. 2298265236Sken */ 2299265236Sken error = mpr_user_event_report(sc, (mpr_event_report_t *)arg); 2300265236Sken break; 2301265236Sken case MPTIOCTL_REG_ACCESS: 2302265236Sken /* 2303265236Sken * The user has requested register access. Call our routine 2304265236Sken * which does this. 2305265236Sken */ 2306265236Sken mpr_lock(sc); 2307265236Sken error = mpr_user_reg_access(sc, (mpr_reg_access_t *)arg); 2308265236Sken mpr_unlock(sc); 2309265236Sken break; 2310265236Sken case MPTIOCTL_BTDH_MAPPING: 2311265236Sken /* 2312265236Sken * The user has requested to translate a bus/target to a 2313265236Sken * DevHandle or a DevHandle to a bus/target. Call our routine 2314265236Sken * which does this. 2315265236Sken */ 2316265236Sken error = mpr_user_btdh(sc, (mpr_btdh_mapping_t *)arg); 2317265236Sken break; 2318265236Sken default: 2319265236Sken error = ENOIOCTL; 2320265236Sken break; 2321265236Sken } 2322265236Sken 2323265236Sken if (mpr_page != NULL) 2324265236Sken free(mpr_page, M_MPRUSER); 2325265236Sken 2326265236Sken return (error); 2327265236Sken} 2328265236Sken 2329265236Sken#ifdef COMPAT_FREEBSD32 2330265236Sken 2331265236Skenstruct mpr_cfg_page_req32 { 2332265236Sken MPI2_CONFIG_PAGE_HEADER header; 2333265236Sken uint32_t page_address; 2334265236Sken uint32_t buf; 2335265236Sken int len; 2336265236Sken uint16_t ioc_status; 2337265236Sken}; 2338265236Sken 2339265236Skenstruct mpr_ext_cfg_page_req32 { 2340265236Sken MPI2_CONFIG_EXTENDED_PAGE_HEADER header; 2341265236Sken uint32_t page_address; 2342265236Sken uint32_t buf; 2343265236Sken int len; 2344265236Sken uint16_t ioc_status; 2345265236Sken}; 2346265236Sken 2347265236Skenstruct mpr_raid_action32 { 2348265236Sken uint8_t action; 2349265236Sken uint8_t volume_bus; 2350265236Sken uint8_t volume_id; 2351265236Sken uint8_t phys_disk_num; 2352265236Sken uint32_t action_data_word; 2353265236Sken uint32_t buf; 2354265236Sken int len; 2355265236Sken uint32_t volume_status; 2356265236Sken uint32_t action_data[4]; 2357265236Sken uint16_t action_status; 2358265236Sken uint16_t ioc_status; 2359265236Sken uint8_t write; 2360265236Sken}; 2361265236Sken 2362265236Skenstruct mpr_usr_command32 { 2363265236Sken uint32_t req; 2364265236Sken uint32_t req_len; 2365265236Sken uint32_t rpl; 2366265236Sken uint32_t rpl_len; 2367265236Sken uint32_t buf; 2368265236Sken int len; 2369265236Sken uint32_t flags; 2370265236Sken}; 2371265236Sken 2372265236Sken#define MPRIO_READ_CFG_HEADER32 _IOWR('M', 200, struct mpr_cfg_page_req32) 2373265236Sken#define MPRIO_READ_CFG_PAGE32 _IOWR('M', 201, struct mpr_cfg_page_req32) 2374265236Sken#define MPRIO_READ_EXT_CFG_HEADER32 _IOWR('M', 202, struct mpr_ext_cfg_page_req32) 2375265236Sken#define MPRIO_READ_EXT_CFG_PAGE32 _IOWR('M', 203, struct mpr_ext_cfg_page_req32) 2376265236Sken#define MPRIO_WRITE_CFG_PAGE32 _IOWR('M', 204, struct mpr_cfg_page_req32) 2377265236Sken#define MPRIO_RAID_ACTION32 _IOWR('M', 205, struct mpr_raid_action32) 2378265236Sken#define MPRIO_MPR_COMMAND32 _IOWR('M', 210, struct mpr_usr_command32) 2379265236Sken 2380265236Skenstatic int 2381265236Skenmpr_ioctl32(struct cdev *dev, u_long cmd32, void *_arg, int flag, 2382265236Sken struct thread *td) 2383265236Sken{ 2384265236Sken struct mpr_cfg_page_req32 *page32 = _arg; 2385265236Sken struct mpr_ext_cfg_page_req32 *ext32 = _arg; 2386265236Sken struct mpr_raid_action32 *raid32 = _arg; 2387265236Sken struct mpr_usr_command32 *user32 = _arg; 2388265236Sken union { 2389265236Sken struct mpr_cfg_page_req page; 2390265236Sken struct mpr_ext_cfg_page_req ext; 2391265236Sken struct mpr_raid_action raid; 2392265236Sken struct mpr_usr_command user; 2393265236Sken } arg; 2394265236Sken u_long cmd; 2395265236Sken int error; 2396265236Sken 2397265236Sken switch (cmd32) { 2398265236Sken case MPRIO_READ_CFG_HEADER32: 2399265236Sken case MPRIO_READ_CFG_PAGE32: 2400265236Sken case MPRIO_WRITE_CFG_PAGE32: 2401265236Sken if (cmd32 == MPRIO_READ_CFG_HEADER32) 2402265236Sken cmd = MPRIO_READ_CFG_HEADER; 2403265236Sken else if (cmd32 == MPRIO_READ_CFG_PAGE32) 2404265236Sken cmd = MPRIO_READ_CFG_PAGE; 2405265236Sken else 2406265236Sken cmd = MPRIO_WRITE_CFG_PAGE; 2407265236Sken CP(*page32, arg.page, header); 2408265236Sken CP(*page32, arg.page, page_address); 2409265236Sken PTRIN_CP(*page32, arg.page, buf); 2410265236Sken CP(*page32, arg.page, len); 2411265236Sken CP(*page32, arg.page, ioc_status); 2412265236Sken break; 2413265236Sken 2414265236Sken case MPRIO_READ_EXT_CFG_HEADER32: 2415265236Sken case MPRIO_READ_EXT_CFG_PAGE32: 2416265236Sken if (cmd32 == MPRIO_READ_EXT_CFG_HEADER32) 2417265236Sken cmd = MPRIO_READ_EXT_CFG_HEADER; 2418265236Sken else 2419265236Sken cmd = MPRIO_READ_EXT_CFG_PAGE; 2420265236Sken CP(*ext32, arg.ext, header); 2421265236Sken CP(*ext32, arg.ext, page_address); 2422265236Sken PTRIN_CP(*ext32, arg.ext, buf); 2423265236Sken CP(*ext32, arg.ext, len); 2424265236Sken CP(*ext32, arg.ext, ioc_status); 2425265236Sken break; 2426265236Sken 2427265236Sken case MPRIO_RAID_ACTION32: 2428265236Sken cmd = MPRIO_RAID_ACTION; 2429265236Sken CP(*raid32, arg.raid, action); 2430265236Sken CP(*raid32, arg.raid, volume_bus); 2431265236Sken CP(*raid32, arg.raid, volume_id); 2432265236Sken CP(*raid32, arg.raid, phys_disk_num); 2433265236Sken CP(*raid32, arg.raid, action_data_word); 2434265236Sken PTRIN_CP(*raid32, arg.raid, buf); 2435265236Sken CP(*raid32, arg.raid, len); 2436265236Sken CP(*raid32, arg.raid, volume_status); 2437265236Sken bcopy(raid32->action_data, arg.raid.action_data, 2438265236Sken sizeof arg.raid.action_data); 2439265236Sken CP(*raid32, arg.raid, ioc_status); 2440265236Sken CP(*raid32, arg.raid, write); 2441265236Sken break; 2442265236Sken 2443265236Sken case MPRIO_MPR_COMMAND32: 2444265236Sken cmd = MPRIO_MPR_COMMAND; 2445265236Sken PTRIN_CP(*user32, arg.user, req); 2446265236Sken CP(*user32, arg.user, req_len); 2447265236Sken PTRIN_CP(*user32, arg.user, rpl); 2448265236Sken CP(*user32, arg.user, rpl_len); 2449265236Sken PTRIN_CP(*user32, arg.user, buf); 2450265236Sken CP(*user32, arg.user, len); 2451265236Sken CP(*user32, arg.user, flags); 2452265236Sken break; 2453265236Sken default: 2454265236Sken return (ENOIOCTL); 2455265236Sken } 2456265236Sken 2457265236Sken error = mpr_ioctl(dev, cmd, &arg, flag, td); 2458265236Sken if (error == 0 && (cmd32 & IOC_OUT) != 0) { 2459265236Sken switch (cmd32) { 2460265236Sken case MPRIO_READ_CFG_HEADER32: 2461265236Sken case MPRIO_READ_CFG_PAGE32: 2462265236Sken case MPRIO_WRITE_CFG_PAGE32: 2463265236Sken CP(arg.page, *page32, header); 2464265236Sken CP(arg.page, *page32, page_address); 2465265236Sken PTROUT_CP(arg.page, *page32, buf); 2466265236Sken CP(arg.page, *page32, len); 2467265236Sken CP(arg.page, *page32, ioc_status); 2468265236Sken break; 2469265236Sken 2470265236Sken case MPRIO_READ_EXT_CFG_HEADER32: 2471265236Sken case MPRIO_READ_EXT_CFG_PAGE32: 2472265236Sken CP(arg.ext, *ext32, header); 2473265236Sken CP(arg.ext, *ext32, page_address); 2474265236Sken PTROUT_CP(arg.ext, *ext32, buf); 2475265236Sken CP(arg.ext, *ext32, len); 2476265236Sken CP(arg.ext, *ext32, ioc_status); 2477265236Sken break; 2478265236Sken 2479265236Sken case MPRIO_RAID_ACTION32: 2480265236Sken CP(arg.raid, *raid32, action); 2481265236Sken CP(arg.raid, *raid32, volume_bus); 2482265236Sken CP(arg.raid, *raid32, volume_id); 2483265236Sken CP(arg.raid, *raid32, phys_disk_num); 2484265236Sken CP(arg.raid, *raid32, action_data_word); 2485265236Sken PTROUT_CP(arg.raid, *raid32, buf); 2486265236Sken CP(arg.raid, *raid32, len); 2487265236Sken CP(arg.raid, *raid32, volume_status); 2488265236Sken bcopy(arg.raid.action_data, raid32->action_data, 2489265236Sken sizeof arg.raid.action_data); 2490265236Sken CP(arg.raid, *raid32, ioc_status); 2491265236Sken CP(arg.raid, *raid32, write); 2492265236Sken break; 2493265236Sken 2494265236Sken case MPRIO_MPR_COMMAND32: 2495265236Sken PTROUT_CP(arg.user, *user32, req); 2496265236Sken CP(arg.user, *user32, req_len); 2497265236Sken PTROUT_CP(arg.user, *user32, rpl); 2498265236Sken CP(arg.user, *user32, rpl_len); 2499265236Sken PTROUT_CP(arg.user, *user32, buf); 2500265236Sken CP(arg.user, *user32, len); 2501265236Sken CP(arg.user, *user32, flags); 2502265236Sken break; 2503265236Sken } 2504265236Sken } 2505265236Sken 2506265236Sken return (error); 2507265236Sken} 2508265236Sken#endif /* COMPAT_FREEBSD32 */ 2509265236Sken 2510265236Skenstatic int 2511265236Skenmpr_ioctl_devsw(struct cdev *dev, u_long com, caddr_t arg, int flag, 2512265236Sken struct thread *td) 2513265236Sken{ 2514265236Sken#ifdef COMPAT_FREEBSD32 2515265236Sken if (SV_CURPROC_FLAG(SV_ILP32)) 2516265236Sken return (mpr_ioctl32(dev, com, arg, flag, td)); 2517265236Sken#endif 2518265236Sken return (mpr_ioctl(dev, com, arg, flag, td)); 2519265236Sken} 2520