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