1212420Sken/*- 2212420Sken * Copyright (c) 2008 Yahoo!, Inc. 3212420Sken * All rights reserved. 4212420Sken * Written by: John Baldwin <jhb@FreeBSD.org> 5212420Sken * 6212420Sken * Redistribution and use in source and binary forms, with or without 7212420Sken * modification, are permitted provided that the following conditions 8212420Sken * are met: 9212420Sken * 1. Redistributions of source code must retain the above copyright 10212420Sken * notice, this list of conditions and the following disclaimer. 11212420Sken * 2. Redistributions in binary form must reproduce the above copyright 12212420Sken * notice, this list of conditions and the following disclaimer in the 13212420Sken * documentation and/or other materials provided with the distribution. 14212420Sken * 3. Neither the name of the author nor the names of any co-contributors 15212420Sken * may be used to endorse or promote products derived from this software 16212420Sken * without specific prior written permission. 17212420Sken * 18212420Sken * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19212420Sken * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20212420Sken * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21212420Sken * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22212420Sken * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23212420Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24212420Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25212420Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26212420Sken * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27212420Sken * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28212420Sken * SUCH DAMAGE. 29212420Sken * 30230592Sken * LSI MPT-Fusion Host Adapter FreeBSD userland interface 31212420Sken */ 32230592Sken/*- 33237683Sken * Copyright (c) 2011, 2012 LSI Corp. 34230592Sken * All rights reserved. 35230592Sken * 36230592Sken * Redistribution and use in source and binary forms, with or without 37230592Sken * modification, are permitted provided that the following conditions 38230592Sken * are met: 39230592Sken * 1. Redistributions of source code must retain the above copyright 40230592Sken * notice, this list of conditions and the following disclaimer. 41230592Sken * 2. Redistributions in binary form must reproduce the above copyright 42230592Sken * notice, this list of conditions and the following disclaimer in the 43230592Sken * documentation and/or other materials provided with the distribution. 44230592Sken * 45230592Sken * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 46230592Sken * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 47230592Sken * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 48230592Sken * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 49230592Sken * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 50230592Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 51230592Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52230592Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 53230592Sken * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 54230592Sken * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 55230592Sken * SUCH DAMAGE. 56230592Sken * 57230592Sken * LSI MPT-Fusion Host Adapter FreeBSD 58230592Sken * 59230592Sken * $FreeBSD$ 60230592Sken */ 61212420Sken 62212420Sken#include <sys/cdefs.h> 63212420Sken__FBSDID("$FreeBSD$"); 64212420Sken 65213702Smdf#include "opt_compat.h" 66213702Smdf 67230592Sken/* TODO Move headers to mpsvar */ 68212420Sken#include <sys/types.h> 69212420Sken#include <sys/param.h> 70212420Sken#include <sys/systm.h> 71212420Sken#include <sys/kernel.h> 72212420Sken#include <sys/selinfo.h> 73212420Sken#include <sys/module.h> 74212420Sken#include <sys/bus.h> 75212420Sken#include <sys/conf.h> 76212420Sken#include <sys/bio.h> 77212420Sken#include <sys/malloc.h> 78212420Sken#include <sys/uio.h> 79212420Sken#include <sys/sysctl.h> 80212420Sken#include <sys/ioccom.h> 81212420Sken#include <sys/endian.h> 82230592Sken#include <sys/queue.h> 83230592Sken#include <sys/kthread.h> 84230592Sken#include <sys/taskqueue.h> 85213702Smdf#include <sys/proc.h> 86213702Smdf#include <sys/sysent.h> 87212420Sken 88212420Sken#include <machine/bus.h> 89212420Sken#include <machine/resource.h> 90212420Sken#include <sys/rman.h> 91212420Sken 92230592Sken#include <cam/cam.h> 93212420Sken#include <cam/scsi/scsi_all.h> 94212420Sken 95212420Sken#include <dev/mps/mpi/mpi2_type.h> 96212420Sken#include <dev/mps/mpi/mpi2.h> 97212420Sken#include <dev/mps/mpi/mpi2_ioc.h> 98212420Sken#include <dev/mps/mpi/mpi2_cnfg.h> 99230592Sken#include <dev/mps/mpi/mpi2_init.h> 100230592Sken#include <dev/mps/mpi/mpi2_tool.h> 101230592Sken#include <dev/mps/mps_ioctl.h> 102212420Sken#include <dev/mps/mpsvar.h> 103212420Sken#include <dev/mps/mps_table.h> 104230592Sken#include <dev/pci/pcivar.h> 105230592Sken#include <dev/pci/pcireg.h> 106212420Sken 107212420Skenstatic d_open_t mps_open; 108212420Skenstatic d_close_t mps_close; 109213702Smdfstatic d_ioctl_t mps_ioctl_devsw; 110212420Sken 111212420Skenstatic struct cdevsw mps_cdevsw = { 112212420Sken .d_version = D_VERSION, 113212420Sken .d_flags = 0, 114212420Sken .d_open = mps_open, 115212420Sken .d_close = mps_close, 116213702Smdf .d_ioctl = mps_ioctl_devsw, 117212420Sken .d_name = "mps", 118212420Sken}; 119212420Sken 120213708Smdftypedef int (mps_user_f)(struct mps_command *, struct mps_usr_command *); 121213708Smdfstatic mps_user_f mpi_pre_ioc_facts; 122213708Smdfstatic mps_user_f mpi_pre_port_facts; 123213708Smdfstatic mps_user_f mpi_pre_fw_download; 124213708Smdfstatic mps_user_f mpi_pre_fw_upload; 125213708Smdfstatic mps_user_f mpi_pre_sata_passthrough; 126213708Smdfstatic mps_user_f mpi_pre_smp_passthrough; 127213708Smdfstatic mps_user_f mpi_pre_config; 128213708Smdfstatic mps_user_f mpi_pre_sas_io_unit_control; 129213708Smdf 130213707Smdfstatic int mps_user_read_cfg_header(struct mps_softc *, 131213707Smdf struct mps_cfg_page_req *); 132213707Smdfstatic int mps_user_read_cfg_page(struct mps_softc *, 133213707Smdf struct mps_cfg_page_req *, void *); 134213707Smdfstatic int mps_user_read_extcfg_header(struct mps_softc *, 135213707Smdf struct mps_ext_cfg_page_req *); 136213707Smdfstatic int mps_user_read_extcfg_page(struct mps_softc *, 137213707Smdf struct mps_ext_cfg_page_req *, void *); 138213707Smdfstatic int mps_user_write_cfg_page(struct mps_softc *, 139213707Smdf struct mps_cfg_page_req *, void *); 140213708Smdfstatic int mps_user_setup_request(struct mps_command *, 141213708Smdf struct mps_usr_command *); 142213707Smdfstatic int mps_user_command(struct mps_softc *, struct mps_usr_command *); 143213707Smdf 144230592Skenstatic int mps_user_pass_thru(struct mps_softc *sc, mps_pass_thru_t *data); 145230592Skenstatic void mps_user_get_adapter_data(struct mps_softc *sc, 146230592Sken mps_adapter_data_t *data); 147230592Skenstatic void mps_user_read_pci_info(struct mps_softc *sc, 148230592Sken mps_pci_info_t *data); 149230592Skenstatic uint8_t mps_get_fw_diag_buffer_number(struct mps_softc *sc, 150230592Sken uint32_t unique_id); 151230592Skenstatic int mps_post_fw_diag_buffer(struct mps_softc *sc, 152230592Sken mps_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code); 153230592Skenstatic int mps_release_fw_diag_buffer(struct mps_softc *sc, 154230592Sken mps_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code, 155230592Sken uint32_t diag_type); 156230592Skenstatic int mps_diag_register(struct mps_softc *sc, 157230592Sken mps_fw_diag_register_t *diag_register, uint32_t *return_code); 158230592Skenstatic int mps_diag_unregister(struct mps_softc *sc, 159230592Sken mps_fw_diag_unregister_t *diag_unregister, uint32_t *return_code); 160230592Skenstatic int mps_diag_query(struct mps_softc *sc, mps_fw_diag_query_t *diag_query, 161230592Sken uint32_t *return_code); 162230592Skenstatic int mps_diag_read_buffer(struct mps_softc *sc, 163230592Sken mps_diag_read_buffer_t *diag_read_buffer, uint8_t *ioctl_buf, 164230592Sken uint32_t *return_code); 165230592Skenstatic int mps_diag_release(struct mps_softc *sc, 166230592Sken mps_fw_diag_release_t *diag_release, uint32_t *return_code); 167230592Skenstatic int mps_do_diag_action(struct mps_softc *sc, uint32_t action, 168230592Sken uint8_t *diag_action, uint32_t length, uint32_t *return_code); 169230592Skenstatic int mps_user_diag_action(struct mps_softc *sc, mps_diag_action_t *data); 170230592Skenstatic void mps_user_event_query(struct mps_softc *sc, mps_event_query_t *data); 171230592Skenstatic void mps_user_event_enable(struct mps_softc *sc, 172230592Sken mps_event_enable_t *data); 173230592Skenstatic int mps_user_event_report(struct mps_softc *sc, 174230592Sken mps_event_report_t *data); 175230592Skenstatic int mps_user_reg_access(struct mps_softc *sc, mps_reg_access_t *data); 176230592Skenstatic int mps_user_btdh(struct mps_softc *sc, mps_btdh_mapping_t *data); 177230592Sken 178212420Skenstatic MALLOC_DEFINE(M_MPSUSER, "mps_user", "Buffers for mps(4) ioctls"); 179212420Sken 180230592Sken/* Macros from compat/freebsd32/freebsd32.h */ 181230592Sken#define PTRIN(v) (void *)(uintptr_t)(v) 182230592Sken#define PTROUT(v) (uint32_t)(uintptr_t)(v) 183230592Sken 184230592Sken#define CP(src,dst,fld) do { (dst).fld = (src).fld; } while (0) 185230592Sken#define PTRIN_CP(src,dst,fld) \ 186230592Sken do { (dst).fld = PTRIN((src).fld); } while (0) 187230592Sken#define PTROUT_CP(src,dst,fld) \ 188230592Sken do { (dst).fld = PTROUT((src).fld); } while (0) 189230592Sken 190212420Skenint 191212420Skenmps_attach_user(struct mps_softc *sc) 192212420Sken{ 193212420Sken int unit; 194212420Sken 195212420Sken unit = device_get_unit(sc->mps_dev); 196212420Sken sc->mps_cdev = make_dev(&mps_cdevsw, unit, UID_ROOT, GID_OPERATOR, 0640, 197212420Sken "mps%d", unit); 198212420Sken if (sc->mps_cdev == NULL) { 199212420Sken return (ENOMEM); 200212420Sken } 201212420Sken sc->mps_cdev->si_drv1 = sc; 202212420Sken return (0); 203212420Sken} 204212420Sken 205212420Skenvoid 206212420Skenmps_detach_user(struct mps_softc *sc) 207212420Sken{ 208212420Sken 209212420Sken /* XXX: do a purge of pending requests? */ 210250900Smav if (sc->mps_cdev != NULL) 211250900Smav destroy_dev(sc->mps_cdev); 212212420Sken} 213212420Sken 214212420Skenstatic int 215212420Skenmps_open(struct cdev *dev, int flags, int fmt, struct thread *td) 216212420Sken{ 217212420Sken 218212420Sken return (0); 219212420Sken} 220212420Sken 221212420Skenstatic int 222212420Skenmps_close(struct cdev *dev, int flags, int fmt, struct thread *td) 223212420Sken{ 224212420Sken 225212420Sken return (0); 226212420Sken} 227212420Sken 228212420Skenstatic int 229212420Skenmps_user_read_cfg_header(struct mps_softc *sc, 230212420Sken struct mps_cfg_page_req *page_req) 231212420Sken{ 232212420Sken MPI2_CONFIG_PAGE_HEADER *hdr; 233212420Sken struct mps_config_params params; 234212420Sken int error; 235212420Sken 236212420Sken hdr = ¶ms.hdr.Struct; 237212420Sken params.action = MPI2_CONFIG_ACTION_PAGE_HEADER; 238212420Sken params.page_address = le32toh(page_req->page_address); 239212420Sken hdr->PageVersion = 0; 240212420Sken hdr->PageLength = 0; 241212420Sken hdr->PageNumber = page_req->header.PageNumber; 242212420Sken hdr->PageType = page_req->header.PageType; 243212420Sken params.buffer = NULL; 244212420Sken params.length = 0; 245212420Sken params.callback = NULL; 246212420Sken 247212420Sken if ((error = mps_read_config_page(sc, ¶ms)) != 0) { 248212420Sken /* 249212420Sken * Leave the request. Without resetting the chip, it's 250212420Sken * still owned by it and we'll just get into trouble 251212420Sken * freeing it now. Mark it as abandoned so that if it 252212420Sken * shows up later it can be freed. 253212420Sken */ 254212420Sken mps_printf(sc, "read_cfg_header timed out\n"); 255212420Sken return (ETIMEDOUT); 256212420Sken } 257212420Sken 258212420Sken page_req->ioc_status = htole16(params.status); 259212420Sken if ((page_req->ioc_status & MPI2_IOCSTATUS_MASK) == 260212420Sken MPI2_IOCSTATUS_SUCCESS) { 261212420Sken bcopy(hdr, &page_req->header, sizeof(page_req->header)); 262212420Sken } 263212420Sken 264212420Sken return (0); 265212420Sken} 266212420Sken 267212420Skenstatic int 268212420Skenmps_user_read_cfg_page(struct mps_softc *sc, struct mps_cfg_page_req *page_req, 269212420Sken void *buf) 270212420Sken{ 271212420Sken MPI2_CONFIG_PAGE_HEADER *reqhdr, *hdr; 272212420Sken struct mps_config_params params; 273212420Sken int error; 274212420Sken 275212420Sken reqhdr = buf; 276212420Sken hdr = ¶ms.hdr.Struct; 277212420Sken hdr->PageVersion = reqhdr->PageVersion; 278212420Sken hdr->PageLength = reqhdr->PageLength; 279212420Sken hdr->PageNumber = reqhdr->PageNumber; 280212420Sken hdr->PageType = reqhdr->PageType & MPI2_CONFIG_PAGETYPE_MASK; 281212420Sken params.action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; 282212420Sken params.page_address = le32toh(page_req->page_address); 283212420Sken params.buffer = buf; 284212420Sken params.length = le32toh(page_req->len); 285212420Sken params.callback = NULL; 286212420Sken 287212420Sken if ((error = mps_read_config_page(sc, ¶ms)) != 0) { 288212420Sken mps_printf(sc, "mps_user_read_cfg_page timed out\n"); 289212420Sken return (ETIMEDOUT); 290212420Sken } 291212420Sken 292212420Sken page_req->ioc_status = htole16(params.status); 293212420Sken return (0); 294212420Sken} 295212420Sken 296212420Skenstatic int 297212420Skenmps_user_read_extcfg_header(struct mps_softc *sc, 298212420Sken struct mps_ext_cfg_page_req *ext_page_req) 299212420Sken{ 300212420Sken MPI2_CONFIG_EXTENDED_PAGE_HEADER *hdr; 301212420Sken struct mps_config_params params; 302212420Sken int error; 303212420Sken 304212420Sken hdr = ¶ms.hdr.Ext; 305212420Sken params.action = MPI2_CONFIG_ACTION_PAGE_HEADER; 306212420Sken hdr->PageVersion = ext_page_req->header.PageVersion; 307251396Sasomers hdr->PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; 308212420Sken hdr->ExtPageLength = 0; 309212420Sken hdr->PageNumber = ext_page_req->header.PageNumber; 310212420Sken hdr->ExtPageType = ext_page_req->header.ExtPageType; 311212420Sken params.page_address = le32toh(ext_page_req->page_address); 312212420Sken if ((error = mps_read_config_page(sc, ¶ms)) != 0) { 313212420Sken /* 314212420Sken * Leave the request. Without resetting the chip, it's 315212420Sken * still owned by it and we'll just get into trouble 316212420Sken * freeing it now. Mark it as abandoned so that if it 317212420Sken * shows up later it can be freed. 318212420Sken */ 319212420Sken mps_printf(sc, "mps_user_read_extcfg_header timed out\n"); 320212420Sken return (ETIMEDOUT); 321212420Sken } 322212420Sken 323212420Sken ext_page_req->ioc_status = htole16(params.status); 324212420Sken if ((ext_page_req->ioc_status & MPI2_IOCSTATUS_MASK) == 325212420Sken MPI2_IOCSTATUS_SUCCESS) { 326212420Sken ext_page_req->header.PageVersion = hdr->PageVersion; 327212420Sken ext_page_req->header.PageNumber = hdr->PageNumber; 328212420Sken ext_page_req->header.PageType = hdr->PageType; 329212420Sken ext_page_req->header.ExtPageLength = hdr->ExtPageLength; 330212420Sken ext_page_req->header.ExtPageType = hdr->ExtPageType; 331212420Sken } 332212420Sken 333212420Sken return (0); 334212420Sken} 335212420Sken 336212420Skenstatic int 337212420Skenmps_user_read_extcfg_page(struct mps_softc *sc, 338212420Sken struct mps_ext_cfg_page_req *ext_page_req, void *buf) 339212420Sken{ 340212420Sken MPI2_CONFIG_EXTENDED_PAGE_HEADER *reqhdr, *hdr; 341212420Sken struct mps_config_params params; 342212420Sken int error; 343212420Sken 344212420Sken reqhdr = buf; 345212420Sken hdr = ¶ms.hdr.Ext; 346212420Sken params.action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; 347212420Sken params.page_address = le32toh(ext_page_req->page_address); 348212420Sken hdr->PageVersion = reqhdr->PageVersion; 349251396Sasomers hdr->PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; 350212420Sken hdr->PageNumber = reqhdr->PageNumber; 351212420Sken hdr->ExtPageType = reqhdr->ExtPageType; 352212420Sken hdr->ExtPageLength = reqhdr->ExtPageLength; 353212420Sken params.buffer = buf; 354212420Sken params.length = le32toh(ext_page_req->len); 355212420Sken params.callback = NULL; 356212420Sken 357212420Sken if ((error = mps_read_config_page(sc, ¶ms)) != 0) { 358212420Sken mps_printf(sc, "mps_user_read_extcfg_page timed out\n"); 359212420Sken return (ETIMEDOUT); 360212420Sken } 361212420Sken 362212420Sken ext_page_req->ioc_status = htole16(params.status); 363212420Sken return (0); 364212420Sken} 365212420Sken 366212420Skenstatic int 367212420Skenmps_user_write_cfg_page(struct mps_softc *sc, 368212420Sken struct mps_cfg_page_req *page_req, void *buf) 369212420Sken{ 370212420Sken MPI2_CONFIG_PAGE_HEADER *reqhdr, *hdr; 371212420Sken struct mps_config_params params; 372212420Sken u_int hdr_attr; 373212420Sken int error; 374212420Sken 375212420Sken reqhdr = buf; 376212420Sken hdr = ¶ms.hdr.Struct; 377212420Sken hdr_attr = reqhdr->PageType & MPI2_CONFIG_PAGEATTR_MASK; 378212420Sken if (hdr_attr != MPI2_CONFIG_PAGEATTR_CHANGEABLE && 379212420Sken hdr_attr != MPI2_CONFIG_PAGEATTR_PERSISTENT) { 380212420Sken mps_printf(sc, "page type 0x%x not changeable\n", 381212420Sken reqhdr->PageType & MPI2_CONFIG_PAGETYPE_MASK); 382212420Sken return (EINVAL); 383212420Sken } 384212420Sken 385212420Sken /* 386212420Sken * There isn't any point in restoring stripped out attributes 387212420Sken * if you then mask them going down to issue the request. 388212420Sken */ 389212420Sken 390212420Sken hdr->PageVersion = reqhdr->PageVersion; 391212420Sken hdr->PageLength = reqhdr->PageLength; 392212420Sken hdr->PageNumber = reqhdr->PageNumber; 393212420Sken hdr->PageType = reqhdr->PageType; 394212420Sken params.action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT; 395212420Sken params.page_address = le32toh(page_req->page_address); 396212420Sken params.buffer = buf; 397212420Sken params.length = le32toh(page_req->len); 398212420Sken params.callback = NULL; 399212420Sken 400212420Sken if ((error = mps_write_config_page(sc, ¶ms)) != 0) { 401212420Sken mps_printf(sc, "mps_write_cfg_page timed out\n"); 402212420Sken return (ETIMEDOUT); 403212420Sken } 404212420Sken 405212420Sken page_req->ioc_status = htole16(params.status); 406212420Sken return (0); 407212420Sken} 408212420Sken 409216088Skenvoid 410213839Smdfmpi_init_sge(struct mps_command *cm, void *req, void *sge) 411213839Smdf{ 412213839Smdf int off, space; 413213839Smdf 414213839Smdf space = (int)cm->cm_sc->facts->IOCRequestFrameSize * 4; 415213839Smdf off = (uintptr_t)sge - (uintptr_t)req; 416213839Smdf 417213839Smdf KASSERT(off < space, ("bad pointers %p %p, off %d, space %d", 418213839Smdf req, sge, off, space)); 419213839Smdf 420213839Smdf cm->cm_sge = sge; 421213839Smdf cm->cm_sglsize = space - off; 422213839Smdf} 423213839Smdf 424213708Smdf/* 425213708Smdf * Prepare the mps_command for an IOC_FACTS request. 426213708Smdf */ 427213708Smdfstatic int 428213708Smdfmpi_pre_ioc_facts(struct mps_command *cm, struct mps_usr_command *cmd) 429213708Smdf{ 430213708Smdf MPI2_IOC_FACTS_REQUEST *req = (void *)cm->cm_req; 431213708Smdf MPI2_IOC_FACTS_REPLY *rpl; 432213708Smdf 433213708Smdf if (cmd->req_len != sizeof *req) 434213708Smdf return (EINVAL); 435213708Smdf if (cmd->rpl_len != sizeof *rpl) 436213708Smdf return (EINVAL); 437213708Smdf 438213708Smdf cm->cm_sge = NULL; 439213708Smdf cm->cm_sglsize = 0; 440213708Smdf return (0); 441213708Smdf} 442213708Smdf 443213708Smdf/* 444213708Smdf * Prepare the mps_command for a PORT_FACTS request. 445213708Smdf */ 446213708Smdfstatic int 447213708Smdfmpi_pre_port_facts(struct mps_command *cm, struct mps_usr_command *cmd) 448213708Smdf{ 449213708Smdf MPI2_PORT_FACTS_REQUEST *req = (void *)cm->cm_req; 450213708Smdf MPI2_PORT_FACTS_REPLY *rpl; 451213708Smdf 452213708Smdf if (cmd->req_len != sizeof *req) 453213708Smdf return (EINVAL); 454213708Smdf if (cmd->rpl_len != sizeof *rpl) 455213708Smdf return (EINVAL); 456213708Smdf 457213708Smdf cm->cm_sge = NULL; 458213708Smdf cm->cm_sglsize = 0; 459213708Smdf return (0); 460213708Smdf} 461213708Smdf 462213708Smdf/* 463213708Smdf * Prepare the mps_command for a FW_DOWNLOAD request. 464213708Smdf */ 465213708Smdfstatic int 466213708Smdfmpi_pre_fw_download(struct mps_command *cm, struct mps_usr_command *cmd) 467213708Smdf{ 468213708Smdf MPI2_FW_DOWNLOAD_REQUEST *req = (void *)cm->cm_req; 469213708Smdf MPI2_FW_DOWNLOAD_REPLY *rpl; 470213840Smdf MPI2_FW_DOWNLOAD_TCSGE tc; 471213840Smdf int error; 472213708Smdf 473213840Smdf /* 474213840Smdf * This code assumes there is room in the request's SGL for 475213840Smdf * the TransactionContext plus at least a SGL chain element. 476213840Smdf */ 477213840Smdf CTASSERT(sizeof req->SGL >= sizeof tc + MPS_SGC_SIZE); 478213840Smdf 479213708Smdf if (cmd->req_len != sizeof *req) 480213708Smdf return (EINVAL); 481213708Smdf if (cmd->rpl_len != sizeof *rpl) 482213708Smdf return (EINVAL); 483213708Smdf 484213840Smdf if (cmd->len == 0) 485213840Smdf return (EINVAL); 486213840Smdf 487213840Smdf error = copyin(cmd->buf, cm->cm_data, cmd->len); 488213840Smdf if (error != 0) 489213840Smdf return (error); 490213840Smdf 491213839Smdf mpi_init_sge(cm, req, &req->SGL); 492213840Smdf bzero(&tc, sizeof tc); 493213840Smdf 494213840Smdf /* 495213840Smdf * For now, the F/W image must be provided in a single request. 496213840Smdf */ 497213840Smdf if ((req->MsgFlags & MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT) == 0) 498213840Smdf return (EINVAL); 499213840Smdf if (req->TotalImageSize != cmd->len) 500213840Smdf return (EINVAL); 501213840Smdf 502213840Smdf /* 503213840Smdf * The value of the first two elements is specified in the 504213840Smdf * Fusion-MPT Message Passing Interface document. 505213840Smdf */ 506213840Smdf tc.ContextSize = 0; 507213840Smdf tc.DetailsLength = 12; 508213840Smdf tc.ImageOffset = 0; 509213840Smdf tc.ImageSize = cmd->len; 510213840Smdf 511213840Smdf cm->cm_flags |= MPS_CM_FLAGS_DATAOUT; 512213840Smdf 513213840Smdf return (mps_push_sge(cm, &tc, sizeof tc, 0)); 514213708Smdf} 515213708Smdf 516213708Smdf/* 517213708Smdf * Prepare the mps_command for a FW_UPLOAD request. 518213708Smdf */ 519213708Smdfstatic int 520213708Smdfmpi_pre_fw_upload(struct mps_command *cm, struct mps_usr_command *cmd) 521213708Smdf{ 522213708Smdf MPI2_FW_UPLOAD_REQUEST *req = (void *)cm->cm_req; 523213708Smdf MPI2_FW_UPLOAD_REPLY *rpl; 524213839Smdf MPI2_FW_UPLOAD_TCSGE tc; 525213708Smdf 526213708Smdf /* 527213708Smdf * This code assumes there is room in the request's SGL for 528213708Smdf * the TransactionContext plus at least a SGL chain element. 529213708Smdf */ 530213839Smdf CTASSERT(sizeof req->SGL >= sizeof tc + MPS_SGC_SIZE); 531213708Smdf 532213708Smdf if (cmd->req_len != sizeof *req) 533213708Smdf return (EINVAL); 534213708Smdf if (cmd->rpl_len != sizeof *rpl) 535213708Smdf return (EINVAL); 536213708Smdf 537213839Smdf mpi_init_sge(cm, req, &req->SGL); 538213839Smdf bzero(&tc, sizeof tc); 539213708Smdf 540213708Smdf /* 541213708Smdf * The value of the first two elements is specified in the 542213708Smdf * Fusion-MPT Message Passing Interface document. 543213708Smdf */ 544213839Smdf tc.ContextSize = 0; 545213839Smdf tc.DetailsLength = 12; 546213708Smdf /* 547213708Smdf * XXX Is there any reason to fetch a partial image? I.e. to 548213708Smdf * set ImageOffset to something other than 0? 549213708Smdf */ 550213839Smdf tc.ImageOffset = 0; 551213839Smdf tc.ImageSize = cmd->len; 552213708Smdf 553238974Smav cm->cm_flags |= MPS_CM_FLAGS_DATAIN; 554238974Smav 555213839Smdf return (mps_push_sge(cm, &tc, sizeof tc, 0)); 556213708Smdf} 557213708Smdf 558213708Smdf/* 559213708Smdf * Prepare the mps_command for a SATA_PASSTHROUGH request. 560213708Smdf */ 561213708Smdfstatic int 562213708Smdfmpi_pre_sata_passthrough(struct mps_command *cm, struct mps_usr_command *cmd) 563213708Smdf{ 564213708Smdf MPI2_SATA_PASSTHROUGH_REQUEST *req = (void *)cm->cm_req; 565213708Smdf MPI2_SATA_PASSTHROUGH_REPLY *rpl; 566213708Smdf 567213708Smdf if (cmd->req_len != sizeof *req) 568213708Smdf return (EINVAL); 569213708Smdf if (cmd->rpl_len != sizeof *rpl) 570213708Smdf return (EINVAL); 571213708Smdf 572213839Smdf mpi_init_sge(cm, req, &req->SGL); 573213708Smdf return (0); 574213708Smdf} 575213708Smdf 576213708Smdf/* 577213708Smdf * Prepare the mps_command for a SMP_PASSTHROUGH request. 578213708Smdf */ 579213708Smdfstatic int 580213708Smdfmpi_pre_smp_passthrough(struct mps_command *cm, struct mps_usr_command *cmd) 581213708Smdf{ 582213708Smdf MPI2_SMP_PASSTHROUGH_REQUEST *req = (void *)cm->cm_req; 583213708Smdf MPI2_SMP_PASSTHROUGH_REPLY *rpl; 584213708Smdf 585213708Smdf if (cmd->req_len != sizeof *req) 586213708Smdf return (EINVAL); 587213708Smdf if (cmd->rpl_len != sizeof *rpl) 588213708Smdf return (EINVAL); 589213708Smdf 590213839Smdf mpi_init_sge(cm, req, &req->SGL); 591213708Smdf return (0); 592213708Smdf} 593213708Smdf 594213708Smdf/* 595213708Smdf * Prepare the mps_command for a CONFIG request. 596213708Smdf */ 597213708Smdfstatic int 598213708Smdfmpi_pre_config(struct mps_command *cm, struct mps_usr_command *cmd) 599213708Smdf{ 600213708Smdf MPI2_CONFIG_REQUEST *req = (void *)cm->cm_req; 601213708Smdf MPI2_CONFIG_REPLY *rpl; 602213708Smdf 603213708Smdf if (cmd->req_len != sizeof *req) 604213708Smdf return (EINVAL); 605213708Smdf if (cmd->rpl_len != sizeof *rpl) 606213708Smdf return (EINVAL); 607213708Smdf 608213839Smdf mpi_init_sge(cm, req, &req->PageBufferSGE); 609213708Smdf return (0); 610213708Smdf} 611213708Smdf 612213708Smdf/* 613213708Smdf * Prepare the mps_command for a SAS_IO_UNIT_CONTROL request. 614213708Smdf */ 615213708Smdfstatic int 616213708Smdfmpi_pre_sas_io_unit_control(struct mps_command *cm, 617213708Smdf struct mps_usr_command *cmd) 618213708Smdf{ 619213708Smdf 620213708Smdf cm->cm_sge = NULL; 621213708Smdf cm->cm_sglsize = 0; 622213708Smdf return (0); 623213708Smdf} 624213708Smdf 625213708Smdf/* 626213708Smdf * A set of functions to prepare an mps_command for the various 627213708Smdf * supported requests. 628213708Smdf */ 629212420Skenstruct mps_user_func { 630213708Smdf U8 Function; 631213708Smdf mps_user_f *f_pre; 632212420Sken} mps_user_func_list[] = { 633213708Smdf { MPI2_FUNCTION_IOC_FACTS, mpi_pre_ioc_facts }, 634213708Smdf { MPI2_FUNCTION_PORT_FACTS, mpi_pre_port_facts }, 635213708Smdf { MPI2_FUNCTION_FW_DOWNLOAD, mpi_pre_fw_download }, 636213708Smdf { MPI2_FUNCTION_FW_UPLOAD, mpi_pre_fw_upload }, 637213708Smdf { MPI2_FUNCTION_SATA_PASSTHROUGH, mpi_pre_sata_passthrough }, 638213708Smdf { MPI2_FUNCTION_SMP_PASSTHROUGH, mpi_pre_smp_passthrough}, 639213708Smdf { MPI2_FUNCTION_CONFIG, mpi_pre_config}, 640213708Smdf { MPI2_FUNCTION_SAS_IO_UNIT_CONTROL, mpi_pre_sas_io_unit_control }, 641213708Smdf { 0xFF, NULL } /* list end */ 642213708Smdf}; 643212420Sken 644212420Skenstatic int 645213708Smdfmps_user_setup_request(struct mps_command *cm, struct mps_usr_command *cmd) 646212420Sken{ 647213708Smdf MPI2_REQUEST_HEADER *hdr = (MPI2_REQUEST_HEADER *)cm->cm_req; 648213708Smdf struct mps_user_func *f; 649212420Sken 650213708Smdf for (f = mps_user_func_list; f->f_pre != NULL; f++) { 651213708Smdf if (hdr->Function == f->Function) 652213708Smdf return (f->f_pre(cm, cmd)); 653213708Smdf } 654213708Smdf return (EINVAL); 655212420Sken} 656212420Sken 657212420Skenstatic int 658212420Skenmps_user_command(struct mps_softc *sc, struct mps_usr_command *cmd) 659212420Sken{ 660212420Sken MPI2_REQUEST_HEADER *hdr; 661212420Sken MPI2_DEFAULT_REPLY *rpl; 662213704Smdf void *buf = NULL; 663213882Smdf struct mps_command *cm = NULL; 664212420Sken int err = 0; 665212420Sken int sz; 666212420Sken 667212420Sken mps_lock(sc); 668212420Sken cm = mps_alloc_command(sc); 669212420Sken 670212420Sken if (cm == NULL) { 671253550Sken mps_printf(sc, "%s: no mps requests\n", __func__); 672212420Sken err = ENOMEM; 673212420Sken goto Ret; 674212420Sken } 675212420Sken mps_unlock(sc); 676212420Sken 677212420Sken hdr = (MPI2_REQUEST_HEADER *)cm->cm_req; 678212420Sken 679253550Sken mps_dprint(sc, MPS_USER, "%s: req %p %d rpl %p %d\n", __func__, 680253550Sken cmd->req, cmd->req_len, cmd->rpl, cmd->rpl_len); 681212420Sken 682213704Smdf if (cmd->req_len > (int)sc->facts->IOCRequestFrameSize * 4) { 683213704Smdf err = EINVAL; 684213704Smdf goto RetFreeUnlocked; 685213704Smdf } 686213704Smdf err = copyin(cmd->req, hdr, cmd->req_len); 687213704Smdf if (err != 0) 688213704Smdf goto RetFreeUnlocked; 689212420Sken 690253550Sken mps_dprint(sc, MPS_USER, "%s: Function %02X MsgFlags %02X\n", __func__, 691253550Sken hdr->Function, hdr->MsgFlags); 692212420Sken 693212420Sken if (cmd->len > 0) { 694212420Sken buf = malloc(cmd->len, M_MPSUSER, M_WAITOK|M_ZERO); 695237683Sken if(!buf) { 696237683Sken mps_printf(sc, "Cannot allocate memory %s %d\n", 697237683Sken __func__, __LINE__); 698237683Sken return (ENOMEM); 699237683Sken } 700212420Sken cm->cm_data = buf; 701212420Sken cm->cm_length = cmd->len; 702212420Sken } else { 703212420Sken cm->cm_data = NULL; 704212420Sken cm->cm_length = 0; 705212420Sken } 706212420Sken 707230592Sken cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE; 708212420Sken cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 709212420Sken 710238974Smav err = mps_user_setup_request(cm, cmd); 711253550Sken if (err == EINVAL) { 712253550Sken mps_printf(sc, "%s: unsupported parameter or unsupported " 713253550Sken "function in request (function = 0x%X)\n", __func__, 714253550Sken hdr->Function); 715253550Sken } 716253550Sken if (err != 0) 717238974Smav goto RetFreeUnlocked; 718238974Smav 719212420Sken mps_lock(sc); 720253550Sken err = mps_wait_command(sc, cm, 60, CAN_SLEEP); 721212420Sken 722230592Sken if (err) { 723213882Smdf mps_printf(sc, "%s: invalid request: error %d\n", 724213882Smdf __func__, err); 725212420Sken goto Ret; 726212420Sken } 727212420Sken 728212420Sken rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply; 729238974Smav if (rpl != NULL) 730238974Smav sz = rpl->MsgLength * 4; 731238974Smav else 732238974Smav sz = 0; 733212420Sken 734212420Sken if (sz > cmd->rpl_len) { 735253550Sken mps_printf(sc, "%s: user reply buffer (%d) smaller than " 736253550Sken "returned buffer (%d)\n", __func__, cmd->rpl_len, sz); 737212420Sken sz = cmd->rpl_len; 738212420Sken } 739212420Sken 740212420Sken mps_unlock(sc); 741212420Sken copyout(rpl, cmd->rpl, sz); 742213704Smdf if (buf != NULL) 743212420Sken copyout(buf, cmd->buf, cmd->len); 744253550Sken mps_dprint(sc, MPS_USER, "%s: reply size %d\n", __func__, sz); 745212420Sken 746213704SmdfRetFreeUnlocked: 747213704Smdf mps_lock(sc); 748213882Smdf if (cm != NULL) 749213882Smdf mps_free_command(sc, cm); 750213882SmdfRet: 751213704Smdf mps_unlock(sc); 752213704Smdf if (buf != NULL) 753213704Smdf free(buf, M_MPSUSER); 754213704Smdf return (err); 755230592Sken} 756212420Sken 757212420Skenstatic int 758230592Skenmps_user_pass_thru(struct mps_softc *sc, mps_pass_thru_t *data) 759230592Sken{ 760230592Sken MPI2_REQUEST_HEADER *hdr, tmphdr; 761230592Sken MPI2_DEFAULT_REPLY *rpl; 762230592Sken struct mps_command *cm = NULL; 763230592Sken int err = 0, dir = 0, sz; 764230592Sken uint8_t function = 0; 765230592Sken u_int sense_len; 766230592Sken 767230592Sken /* 768230592Sken * Only allow one passthru command at a time. Use the MPS_FLAGS_BUSY 769230592Sken * bit to denote that a passthru is being processed. 770230592Sken */ 771230592Sken mps_lock(sc); 772230592Sken if (sc->mps_flags & MPS_FLAGS_BUSY) { 773253460Sscottl mps_dprint(sc, MPS_USER, "%s: Only one passthru command " 774230592Sken "allowed at a single time.", __func__); 775230592Sken mps_unlock(sc); 776230592Sken return (EBUSY); 777230592Sken } 778230592Sken sc->mps_flags |= MPS_FLAGS_BUSY; 779230592Sken mps_unlock(sc); 780230592Sken 781230592Sken /* 782230592Sken * Do some validation on data direction. Valid cases are: 783230592Sken * 1) DataSize is 0 and direction is NONE 784230592Sken * 2) DataSize is non-zero and one of: 785230592Sken * a) direction is READ or 786230592Sken * b) direction is WRITE or 787230592Sken * c) direction is BOTH and DataOutSize is non-zero 788230592Sken * If valid and the direction is BOTH, change the direction to READ. 789230592Sken * if valid and the direction is not BOTH, make sure DataOutSize is 0. 790230592Sken */ 791230592Sken if (((data->DataSize == 0) && 792230592Sken (data->DataDirection == MPS_PASS_THRU_DIRECTION_NONE)) || 793230592Sken ((data->DataSize != 0) && 794230592Sken ((data->DataDirection == MPS_PASS_THRU_DIRECTION_READ) || 795230592Sken (data->DataDirection == MPS_PASS_THRU_DIRECTION_WRITE) || 796230592Sken ((data->DataDirection == MPS_PASS_THRU_DIRECTION_BOTH) && 797230592Sken (data->DataOutSize != 0))))) { 798230592Sken if (data->DataDirection == MPS_PASS_THRU_DIRECTION_BOTH) 799230592Sken data->DataDirection = MPS_PASS_THRU_DIRECTION_READ; 800230592Sken else 801230592Sken data->DataOutSize = 0; 802230592Sken } else 803230592Sken return (EINVAL); 804230592Sken 805253460Sscottl mps_dprint(sc, MPS_USER, "%s: req 0x%jx %d rpl 0x%jx %d " 806230592Sken "data in 0x%jx %d data out 0x%jx %d data dir %d\n", __func__, 807230592Sken data->PtrRequest, data->RequestSize, data->PtrReply, 808230592Sken data->ReplySize, data->PtrData, data->DataSize, 809230592Sken data->PtrDataOut, data->DataOutSize, data->DataDirection); 810230592Sken 811230592Sken /* 812230592Sken * copy in the header so we know what we're dealing with before we 813230592Sken * commit to allocating a command for it. 814230592Sken */ 815230592Sken err = copyin(PTRIN(data->PtrRequest), &tmphdr, data->RequestSize); 816230592Sken if (err != 0) 817230592Sken goto RetFreeUnlocked; 818230592Sken 819230592Sken if (data->RequestSize > (int)sc->facts->IOCRequestFrameSize * 4) { 820230592Sken err = EINVAL; 821230592Sken goto RetFreeUnlocked; 822230592Sken } 823230592Sken 824230592Sken function = tmphdr.Function; 825253460Sscottl mps_dprint(sc, MPS_USER, "%s: Function %02X MsgFlags %02X\n", __func__, 826230592Sken function, tmphdr.MsgFlags); 827230592Sken 828230592Sken /* 829230592Sken * Handle a passthru TM request. 830230592Sken */ 831230592Sken if (function == MPI2_FUNCTION_SCSI_TASK_MGMT) { 832230592Sken MPI2_SCSI_TASK_MANAGE_REQUEST *task; 833230592Sken 834230592Sken mps_lock(sc); 835230592Sken cm = mpssas_alloc_tm(sc); 836230592Sken if (cm == NULL) { 837230592Sken err = EINVAL; 838230592Sken goto Ret; 839230592Sken } 840230592Sken 841230592Sken /* Copy the header in. Only a small fixup is needed. */ 842230592Sken task = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req; 843230592Sken bcopy(&tmphdr, task, data->RequestSize); 844230592Sken task->TaskMID = cm->cm_desc.Default.SMID; 845230592Sken 846230592Sken cm->cm_data = NULL; 847230592Sken cm->cm_desc.HighPriority.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; 848230592Sken cm->cm_complete = NULL; 849230592Sken cm->cm_complete_data = NULL; 850230592Sken 851253550Sken err = mps_wait_command(sc, cm, 30, CAN_SLEEP); 852230592Sken 853230592Sken if (err != 0) { 854230592Sken err = EIO; 855230592Sken mps_dprint(sc, MPS_FAULT, "%s: task management failed", 856230592Sken __func__); 857230592Sken } 858230592Sken /* 859230592Sken * Copy the reply data and sense data to user space. 860230592Sken */ 861230592Sken if (cm->cm_reply != NULL) { 862230592Sken rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply; 863230592Sken sz = rpl->MsgLength * 4; 864230592Sken 865230592Sken if (sz > data->ReplySize) { 866253550Sken mps_printf(sc, "%s: user reply buffer (%d) " 867253550Sken "smaller than returned buffer (%d)\n", 868253550Sken __func__, data->ReplySize, sz); 869230592Sken } 870253550Sken mps_unlock(sc); 871253550Sken copyout(cm->cm_reply, PTRIN(data->PtrReply), 872253550Sken data->ReplySize); 873253550Sken mps_lock(sc); 874230592Sken } 875230592Sken mpssas_free_tm(sc, cm); 876230592Sken goto Ret; 877230592Sken } 878230592Sken 879230592Sken mps_lock(sc); 880230592Sken cm = mps_alloc_command(sc); 881230592Sken 882230592Sken if (cm == NULL) { 883230592Sken mps_printf(sc, "%s: no mps requests\n", __func__); 884230592Sken err = ENOMEM; 885230592Sken goto Ret; 886230592Sken } 887230592Sken mps_unlock(sc); 888230592Sken 889230592Sken hdr = (MPI2_REQUEST_HEADER *)cm->cm_req; 890230592Sken bcopy(&tmphdr, hdr, data->RequestSize); 891230592Sken 892230592Sken /* 893230592Sken * Do some checking to make sure the IOCTL request contains a valid 894230592Sken * request. Then set the SGL info. 895230592Sken */ 896230592Sken mpi_init_sge(cm, hdr, (void *)((uint8_t *)hdr + data->RequestSize)); 897230592Sken 898230592Sken /* 899230592Sken * Set up for read, write or both. From check above, DataOutSize will 900230592Sken * be 0 if direction is READ or WRITE, but it will have some non-zero 901230592Sken * value if the direction is BOTH. So, just use the biggest size to get 902230592Sken * the cm_data buffer size. If direction is BOTH, 2 SGLs need to be set 903230592Sken * up; the first is for the request and the second will contain the 904230592Sken * response data. cm_out_len needs to be set here and this will be used 905230592Sken * when the SGLs are set up. 906230592Sken */ 907230592Sken cm->cm_data = NULL; 908230592Sken cm->cm_length = MAX(data->DataSize, data->DataOutSize); 909230592Sken cm->cm_out_len = data->DataOutSize; 910230592Sken cm->cm_flags = 0; 911230592Sken if (cm->cm_length != 0) { 912230592Sken cm->cm_data = malloc(cm->cm_length, M_MPSUSER, M_WAITOK | 913230592Sken M_ZERO); 914230592Sken if (cm->cm_data == NULL) { 915230592Sken mps_dprint(sc, MPS_FAULT, "%s: alloc failed for IOCTL " 916230592Sken "passthru length %d\n", __func__, cm->cm_length); 917230592Sken } else { 918230592Sken cm->cm_flags = MPS_CM_FLAGS_DATAIN; 919230592Sken if (data->DataOutSize) { 920230592Sken cm->cm_flags |= MPS_CM_FLAGS_DATAOUT; 921230592Sken err = copyin(PTRIN(data->PtrDataOut), 922230592Sken cm->cm_data, data->DataOutSize); 923230592Sken } else if (data->DataDirection == 924230592Sken MPS_PASS_THRU_DIRECTION_WRITE) { 925230592Sken cm->cm_flags = MPS_CM_FLAGS_DATAOUT; 926230592Sken err = copyin(PTRIN(data->PtrData), 927230592Sken cm->cm_data, data->DataSize); 928230592Sken } 929230592Sken if (err != 0) 930230592Sken mps_dprint(sc, MPS_FAULT, "%s: failed to copy " 931230592Sken "IOCTL data from user space\n", __func__); 932230592Sken } 933230592Sken } 934230592Sken cm->cm_flags |= MPS_CM_FLAGS_SGE_SIMPLE; 935230592Sken cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 936230592Sken 937230592Sken /* 938230592Sken * Set up Sense buffer and SGL offset for IO passthru. SCSI IO request 939230592Sken * uses SCSI IO descriptor. 940230592Sken */ 941230592Sken if ((function == MPI2_FUNCTION_SCSI_IO_REQUEST) || 942230592Sken (function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { 943230592Sken MPI2_SCSI_IO_REQUEST *scsi_io_req; 944230592Sken 945230592Sken scsi_io_req = (MPI2_SCSI_IO_REQUEST *)hdr; 946230592Sken /* 947230592Sken * Put SGE for data and data_out buffer at the end of 948230592Sken * scsi_io_request message header (64 bytes in total). 949230592Sken * Following above SGEs, the residual space will be used by 950230592Sken * sense data. 951230592Sken */ 952230592Sken scsi_io_req->SenseBufferLength = (uint8_t)(data->RequestSize - 953230592Sken 64); 954237683Sken scsi_io_req->SenseBufferLowAddress = htole32(cm->cm_sense_busaddr); 955230592Sken 956230592Sken /* 957230592Sken * Set SGLOffset0 value. This is the number of dwords that SGL 958230592Sken * is offset from the beginning of MPI2_SCSI_IO_REQUEST struct. 959230592Sken */ 960230592Sken scsi_io_req->SGLOffset0 = 24; 961230592Sken 962230592Sken /* 963230592Sken * Setup descriptor info. RAID passthrough must use the 964230592Sken * default request descriptor which is already set, so if this 965230592Sken * is a SCSI IO request, change the descriptor to SCSI IO. 966230592Sken * Also, if this is a SCSI IO request, handle the reply in the 967230592Sken * mpssas_scsio_complete function. 968230592Sken */ 969230592Sken if (function == MPI2_FUNCTION_SCSI_IO_REQUEST) { 970230592Sken cm->cm_desc.SCSIIO.RequestFlags = 971230592Sken MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; 972230592Sken cm->cm_desc.SCSIIO.DevHandle = scsi_io_req->DevHandle; 973230592Sken 974230592Sken /* 975230592Sken * Make sure the DevHandle is not 0 because this is a 976230592Sken * likely error. 977230592Sken */ 978230592Sken if (scsi_io_req->DevHandle == 0) { 979230592Sken err = EINVAL; 980230592Sken goto RetFreeUnlocked; 981230592Sken } 982230592Sken } 983230592Sken } 984230592Sken 985230592Sken mps_lock(sc); 986230592Sken 987253550Sken err = mps_wait_command(sc, cm, 30, CAN_SLEEP); 988230592Sken 989230592Sken if (err) { 990230592Sken mps_printf(sc, "%s: invalid request: error %d\n", __func__, 991230592Sken err); 992230592Sken mps_unlock(sc); 993230592Sken goto RetFreeUnlocked; 994230592Sken } 995230592Sken 996230592Sken /* 997230592Sken * Sync the DMA data, if any. Then copy the data to user space. 998230592Sken */ 999230592Sken if (cm->cm_data != NULL) { 1000230592Sken if (cm->cm_flags & MPS_CM_FLAGS_DATAIN) 1001230592Sken dir = BUS_DMASYNC_POSTREAD; 1002230592Sken else if (cm->cm_flags & MPS_CM_FLAGS_DATAOUT) 1003241844Seadler dir = BUS_DMASYNC_POSTWRITE; 1004230592Sken bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir); 1005230592Sken bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap); 1006230592Sken 1007230592Sken if (cm->cm_flags & MPS_CM_FLAGS_DATAIN) { 1008230592Sken mps_unlock(sc); 1009230592Sken err = copyout(cm->cm_data, 1010230592Sken PTRIN(data->PtrData), data->DataSize); 1011230592Sken mps_lock(sc); 1012230592Sken if (err != 0) 1013230592Sken mps_dprint(sc, MPS_FAULT, "%s: failed to copy " 1014230592Sken "IOCTL data to user space\n", __func__); 1015230592Sken } 1016230592Sken } 1017230592Sken 1018230592Sken /* 1019230592Sken * Copy the reply data and sense data to user space. 1020230592Sken */ 1021230592Sken if (cm->cm_reply != NULL) { 1022230592Sken rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply; 1023230592Sken sz = rpl->MsgLength * 4; 1024230592Sken 1025230592Sken if (sz > data->ReplySize) { 1026253550Sken mps_printf(sc, "%s: user reply buffer (%d) smaller " 1027253550Sken "than returned buffer (%d)\n", __func__, 1028253550Sken data->ReplySize, sz); 1029230592Sken } 1030253550Sken mps_unlock(sc); 1031253550Sken copyout(cm->cm_reply, PTRIN(data->PtrReply), data->ReplySize); 1032253550Sken mps_lock(sc); 1033230592Sken 1034230592Sken if ((function == MPI2_FUNCTION_SCSI_IO_REQUEST) || 1035230592Sken (function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { 1036230592Sken if (((MPI2_SCSI_IO_REPLY *)rpl)->SCSIState & 1037230592Sken MPI2_SCSI_STATE_AUTOSENSE_VALID) { 1038230592Sken sense_len = 1039237683Sken MIN((le32toh(((MPI2_SCSI_IO_REPLY *)rpl)->SenseCount)), 1040230592Sken sizeof(struct scsi_sense_data)); 1041230592Sken mps_unlock(sc); 1042230592Sken copyout(cm->cm_sense, cm->cm_req + 64, sense_len); 1043230592Sken mps_lock(sc); 1044230592Sken } 1045230592Sken } 1046230592Sken } 1047230592Sken mps_unlock(sc); 1048230592Sken 1049230592SkenRetFreeUnlocked: 1050230592Sken mps_lock(sc); 1051230592Sken 1052230592Sken if (cm != NULL) { 1053230592Sken if (cm->cm_data) 1054230592Sken free(cm->cm_data, M_MPSUSER); 1055230592Sken mps_free_command(sc, cm); 1056230592Sken } 1057230592SkenRet: 1058230592Sken sc->mps_flags &= ~MPS_FLAGS_BUSY; 1059230592Sken mps_unlock(sc); 1060230592Sken 1061230592Sken return (err); 1062230592Sken} 1063230592Sken 1064230592Skenstatic void 1065230592Skenmps_user_get_adapter_data(struct mps_softc *sc, mps_adapter_data_t *data) 1066230592Sken{ 1067230592Sken Mpi2ConfigReply_t mpi_reply; 1068230592Sken Mpi2BiosPage3_t config_page; 1069230592Sken 1070230592Sken /* 1071230592Sken * Use the PCI interface functions to get the Bus, Device, and Function 1072230592Sken * information. 1073230592Sken */ 1074230592Sken data->PciInformation.u.bits.BusNumber = pci_get_bus(sc->mps_dev); 1075230592Sken data->PciInformation.u.bits.DeviceNumber = pci_get_slot(sc->mps_dev); 1076230592Sken data->PciInformation.u.bits.FunctionNumber = 1077230592Sken pci_get_function(sc->mps_dev); 1078230592Sken 1079230592Sken /* 1080230592Sken * Get the FW version that should already be saved in IOC Facts. 1081230592Sken */ 1082230592Sken data->MpiFirmwareVersion = sc->facts->FWVersion.Word; 1083230592Sken 1084230592Sken /* 1085230592Sken * General device info. 1086230592Sken */ 1087230592Sken data->AdapterType = MPSIOCTL_ADAPTER_TYPE_SAS2; 1088230592Sken if (sc->mps_flags & MPS_FLAGS_WD_AVAILABLE) 1089230592Sken data->AdapterType = MPSIOCTL_ADAPTER_TYPE_SAS2_SSS6200; 1090230592Sken data->PCIDeviceHwId = pci_get_device(sc->mps_dev); 1091230592Sken data->PCIDeviceHwRev = pci_read_config(sc->mps_dev, PCIR_REVID, 1); 1092230592Sken data->SubSystemId = pci_get_subdevice(sc->mps_dev); 1093230592Sken data->SubsystemVendorId = pci_get_subvendor(sc->mps_dev); 1094230592Sken 1095230592Sken /* 1096230592Sken * Get the driver version. 1097230592Sken */ 1098230592Sken strcpy((char *)&data->DriverVersion[0], MPS_DRIVER_VERSION); 1099230592Sken 1100230592Sken /* 1101230592Sken * Need to get BIOS Config Page 3 for the BIOS Version. 1102230592Sken */ 1103230592Sken data->BiosVersion = 0; 1104231240Sken mps_lock(sc); 1105230592Sken if (mps_config_get_bios_pg3(sc, &mpi_reply, &config_page)) 1106230592Sken printf("%s: Error while retrieving BIOS Version\n", __func__); 1107230592Sken else 1108230592Sken data->BiosVersion = config_page.BiosVersion; 1109231240Sken mps_unlock(sc); 1110230592Sken} 1111230592Sken 1112230592Skenstatic void 1113230592Skenmps_user_read_pci_info(struct mps_softc *sc, mps_pci_info_t *data) 1114230592Sken{ 1115230592Sken int i; 1116230592Sken 1117230592Sken /* 1118230592Sken * Use the PCI interface functions to get the Bus, Device, and Function 1119230592Sken * information. 1120230592Sken */ 1121230592Sken data->BusNumber = pci_get_bus(sc->mps_dev); 1122230592Sken data->DeviceNumber = pci_get_slot(sc->mps_dev); 1123230592Sken data->FunctionNumber = pci_get_function(sc->mps_dev); 1124230592Sken 1125230592Sken /* 1126230592Sken * Now get the interrupt vector and the pci header. The vector can 1127230592Sken * only be 0 right now. The header is the first 256 bytes of config 1128230592Sken * space. 1129230592Sken */ 1130230592Sken data->InterruptVector = 0; 1131230592Sken for (i = 0; i < sizeof (data->PciHeader); i++) { 1132230592Sken data->PciHeader[i] = pci_read_config(sc->mps_dev, i, 1); 1133230592Sken } 1134230592Sken} 1135230592Sken 1136230592Skenstatic uint8_t 1137230592Skenmps_get_fw_diag_buffer_number(struct mps_softc *sc, uint32_t unique_id) 1138230592Sken{ 1139230592Sken uint8_t index; 1140230592Sken 1141230592Sken for (index = 0; index < MPI2_DIAG_BUF_TYPE_COUNT; index++) { 1142230592Sken if (sc->fw_diag_buffer_list[index].unique_id == unique_id) { 1143230592Sken return (index); 1144230592Sken } 1145230592Sken } 1146230592Sken 1147230592Sken return (MPS_FW_DIAGNOSTIC_UID_NOT_FOUND); 1148230592Sken} 1149230592Sken 1150230592Skenstatic int 1151230592Skenmps_post_fw_diag_buffer(struct mps_softc *sc, 1152230592Sken mps_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code) 1153230592Sken{ 1154230592Sken MPI2_DIAG_BUFFER_POST_REQUEST *req; 1155230592Sken MPI2_DIAG_BUFFER_POST_REPLY *reply; 1156230592Sken struct mps_command *cm = NULL; 1157230592Sken int i, status; 1158230592Sken 1159230592Sken /* 1160230592Sken * If buffer is not enabled, just leave. 1161230592Sken */ 1162230592Sken *return_code = MPS_FW_DIAG_ERROR_POST_FAILED; 1163230592Sken if (!pBuffer->enabled) { 1164230592Sken return (MPS_DIAG_FAILURE); 1165230592Sken } 1166230592Sken 1167230592Sken /* 1168230592Sken * Clear some flags initially. 1169230592Sken */ 1170230592Sken pBuffer->force_release = FALSE; 1171230592Sken pBuffer->valid_data = FALSE; 1172230592Sken pBuffer->owned_by_firmware = FALSE; 1173230592Sken 1174230592Sken /* 1175230592Sken * Get a command. 1176230592Sken */ 1177230592Sken cm = mps_alloc_command(sc); 1178230592Sken if (cm == NULL) { 1179230592Sken mps_printf(sc, "%s: no mps requests\n", __func__); 1180230592Sken return (MPS_DIAG_FAILURE); 1181230592Sken } 1182230592Sken 1183230592Sken /* 1184230592Sken * Build the request for releasing the FW Diag Buffer and send it. 1185230592Sken */ 1186230592Sken req = (MPI2_DIAG_BUFFER_POST_REQUEST *)cm->cm_req; 1187230592Sken req->Function = MPI2_FUNCTION_DIAG_BUFFER_POST; 1188230592Sken req->BufferType = pBuffer->buffer_type; 1189230592Sken req->ExtendedType = pBuffer->extended_type; 1190230592Sken req->BufferLength = pBuffer->size; 1191230592Sken for (i = 0; i < (sizeof(req->ProductSpecific) / 4); i++) 1192230592Sken req->ProductSpecific[i] = pBuffer->product_specific[i]; 1193230592Sken mps_from_u64(sc->fw_diag_busaddr, &req->BufferAddress); 1194230592Sken cm->cm_data = NULL; 1195230592Sken cm->cm_length = 0; 1196230592Sken cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 1197230592Sken cm->cm_complete_data = NULL; 1198230592Sken 1199230592Sken /* 1200230592Sken * Send command synchronously. 1201230592Sken */ 1202253550Sken status = mps_wait_command(sc, cm, 30, CAN_SLEEP); 1203230592Sken if (status) { 1204230592Sken mps_printf(sc, "%s: invalid request: error %d\n", __func__, 1205230592Sken status); 1206230592Sken status = MPS_DIAG_FAILURE; 1207230592Sken goto done; 1208230592Sken } 1209230592Sken 1210230592Sken /* 1211230592Sken * Process POST reply. 1212230592Sken */ 1213230592Sken reply = (MPI2_DIAG_BUFFER_POST_REPLY *)cm->cm_reply; 1214230592Sken if (reply->IOCStatus != MPI2_IOCSTATUS_SUCCESS) { 1215230592Sken status = MPS_DIAG_FAILURE; 1216230592Sken mps_dprint(sc, MPS_FAULT, "%s: post of FW Diag Buffer failed " 1217230592Sken "with IOCStatus = 0x%x, IOCLogInfo = 0x%x and " 1218230592Sken "TransferLength = 0x%x\n", __func__, reply->IOCStatus, 1219230592Sken reply->IOCLogInfo, reply->TransferLength); 1220230592Sken goto done; 1221230592Sken } 1222230592Sken 1223230592Sken /* 1224230592Sken * Post was successful. 1225230592Sken */ 1226230592Sken pBuffer->valid_data = TRUE; 1227230592Sken pBuffer->owned_by_firmware = TRUE; 1228230592Sken *return_code = MPS_FW_DIAG_ERROR_SUCCESS; 1229230592Sken status = MPS_DIAG_SUCCESS; 1230230592Sken 1231230592Skendone: 1232230592Sken mps_free_command(sc, cm); 1233230592Sken return (status); 1234230592Sken} 1235230592Sken 1236230592Skenstatic int 1237230592Skenmps_release_fw_diag_buffer(struct mps_softc *sc, 1238230592Sken mps_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code, 1239230592Sken uint32_t diag_type) 1240230592Sken{ 1241230592Sken MPI2_DIAG_RELEASE_REQUEST *req; 1242230592Sken MPI2_DIAG_RELEASE_REPLY *reply; 1243230592Sken struct mps_command *cm = NULL; 1244230592Sken int status; 1245230592Sken 1246230592Sken /* 1247230592Sken * If buffer is not enabled, just leave. 1248230592Sken */ 1249230592Sken *return_code = MPS_FW_DIAG_ERROR_RELEASE_FAILED; 1250230592Sken if (!pBuffer->enabled) { 1251253550Sken mps_dprint(sc, MPS_USER, "%s: This buffer type is not " 1252253550Sken "supported by the IOC", __func__); 1253230592Sken return (MPS_DIAG_FAILURE); 1254230592Sken } 1255230592Sken 1256230592Sken /* 1257230592Sken * Clear some flags initially. 1258230592Sken */ 1259230592Sken pBuffer->force_release = FALSE; 1260230592Sken pBuffer->valid_data = FALSE; 1261230592Sken pBuffer->owned_by_firmware = FALSE; 1262230592Sken 1263230592Sken /* 1264230592Sken * Get a command. 1265230592Sken */ 1266230592Sken cm = mps_alloc_command(sc); 1267230592Sken if (cm == NULL) { 1268230592Sken mps_printf(sc, "%s: no mps requests\n", __func__); 1269230592Sken return (MPS_DIAG_FAILURE); 1270230592Sken } 1271230592Sken 1272230592Sken /* 1273230592Sken * Build the request for releasing the FW Diag Buffer and send it. 1274230592Sken */ 1275230592Sken req = (MPI2_DIAG_RELEASE_REQUEST *)cm->cm_req; 1276230592Sken req->Function = MPI2_FUNCTION_DIAG_RELEASE; 1277230592Sken req->BufferType = pBuffer->buffer_type; 1278230592Sken cm->cm_data = NULL; 1279230592Sken cm->cm_length = 0; 1280230592Sken cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 1281230592Sken cm->cm_complete_data = NULL; 1282230592Sken 1283230592Sken /* 1284230592Sken * Send command synchronously. 1285230592Sken */ 1286253550Sken status = mps_wait_command(sc, cm, 30, CAN_SLEEP); 1287230592Sken if (status) { 1288230592Sken mps_printf(sc, "%s: invalid request: error %d\n", __func__, 1289230592Sken status); 1290230592Sken status = MPS_DIAG_FAILURE; 1291230592Sken goto done; 1292230592Sken } 1293230592Sken 1294230592Sken /* 1295230592Sken * Process RELEASE reply. 1296230592Sken */ 1297230592Sken reply = (MPI2_DIAG_RELEASE_REPLY *)cm->cm_reply; 1298230592Sken if ((reply->IOCStatus != MPI2_IOCSTATUS_SUCCESS) || 1299230592Sken pBuffer->owned_by_firmware) { 1300230592Sken status = MPS_DIAG_FAILURE; 1301230592Sken mps_dprint(sc, MPS_FAULT, "%s: release of FW Diag Buffer " 1302230592Sken "failed with IOCStatus = 0x%x and IOCLogInfo = 0x%x\n", 1303230592Sken __func__, reply->IOCStatus, reply->IOCLogInfo); 1304230592Sken goto done; 1305230592Sken } 1306230592Sken 1307230592Sken /* 1308230592Sken * Release was successful. 1309230592Sken */ 1310230592Sken *return_code = MPS_FW_DIAG_ERROR_SUCCESS; 1311230592Sken status = MPS_DIAG_SUCCESS; 1312230592Sken 1313230592Sken /* 1314230592Sken * If this was for an UNREGISTER diag type command, clear the unique ID. 1315230592Sken */ 1316230592Sken if (diag_type == MPS_FW_DIAG_TYPE_UNREGISTER) { 1317230592Sken pBuffer->unique_id = MPS_FW_DIAG_INVALID_UID; 1318230592Sken } 1319230592Sken 1320230592Skendone: 1321230592Sken return (status); 1322230592Sken} 1323230592Sken 1324230592Skenstatic int 1325230592Skenmps_diag_register(struct mps_softc *sc, mps_fw_diag_register_t *diag_register, 1326230592Sken uint32_t *return_code) 1327230592Sken{ 1328230592Sken mps_fw_diagnostic_buffer_t *pBuffer; 1329230592Sken uint8_t extended_type, buffer_type, i; 1330230592Sken uint32_t buffer_size; 1331230592Sken uint32_t unique_id; 1332230592Sken int status; 1333230592Sken 1334230592Sken extended_type = diag_register->ExtendedType; 1335230592Sken buffer_type = diag_register->BufferType; 1336230592Sken buffer_size = diag_register->RequestedBufferSize; 1337230592Sken unique_id = diag_register->UniqueId; 1338230592Sken 1339230592Sken /* 1340230592Sken * Check for valid buffer type 1341230592Sken */ 1342230592Sken if (buffer_type >= MPI2_DIAG_BUF_TYPE_COUNT) { 1343230592Sken *return_code = MPS_FW_DIAG_ERROR_INVALID_PARAMETER; 1344230592Sken return (MPS_DIAG_FAILURE); 1345230592Sken } 1346230592Sken 1347230592Sken /* 1348230592Sken * Get the current buffer and look up the unique ID. The unique ID 1349230592Sken * should not be found. If it is, the ID is already in use. 1350230592Sken */ 1351230592Sken i = mps_get_fw_diag_buffer_number(sc, unique_id); 1352230592Sken pBuffer = &sc->fw_diag_buffer_list[buffer_type]; 1353230592Sken if (i != MPS_FW_DIAGNOSTIC_UID_NOT_FOUND) { 1354230592Sken *return_code = MPS_FW_DIAG_ERROR_INVALID_UID; 1355230592Sken return (MPS_DIAG_FAILURE); 1356230592Sken } 1357230592Sken 1358230592Sken /* 1359230592Sken * The buffer's unique ID should not be registered yet, and the given 1360230592Sken * unique ID cannot be 0. 1361230592Sken */ 1362230592Sken if ((pBuffer->unique_id != MPS_FW_DIAG_INVALID_UID) || 1363230592Sken (unique_id == MPS_FW_DIAG_INVALID_UID)) { 1364230592Sken *return_code = MPS_FW_DIAG_ERROR_INVALID_UID; 1365230592Sken return (MPS_DIAG_FAILURE); 1366230592Sken } 1367230592Sken 1368230592Sken /* 1369230592Sken * If this buffer is already posted as immediate, just change owner. 1370230592Sken */ 1371230592Sken if (pBuffer->immediate && pBuffer->owned_by_firmware && 1372230592Sken (pBuffer->unique_id == MPS_FW_DIAG_INVALID_UID)) { 1373230592Sken pBuffer->immediate = FALSE; 1374230592Sken pBuffer->unique_id = unique_id; 1375230592Sken return (MPS_DIAG_SUCCESS); 1376230592Sken } 1377230592Sken 1378230592Sken /* 1379230592Sken * Post a new buffer after checking if it's enabled. The DMA buffer 1380230592Sken * that is allocated will be contiguous (nsegments = 1). 1381230592Sken */ 1382230592Sken if (!pBuffer->enabled) { 1383230592Sken *return_code = MPS_FW_DIAG_ERROR_NO_BUFFER; 1384230592Sken return (MPS_DIAG_FAILURE); 1385230592Sken } 1386230592Sken if (bus_dma_tag_create( sc->mps_parent_dmat, /* parent */ 1387230592Sken 1, 0, /* algnmnt, boundary */ 1388230592Sken BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 1389230592Sken BUS_SPACE_MAXADDR, /* highaddr */ 1390230592Sken NULL, NULL, /* filter, filterarg */ 1391230592Sken buffer_size, /* maxsize */ 1392230592Sken 1, /* nsegments */ 1393230592Sken buffer_size, /* maxsegsize */ 1394230592Sken 0, /* flags */ 1395230592Sken NULL, NULL, /* lockfunc, lockarg */ 1396230592Sken &sc->fw_diag_dmat)) { 1397230592Sken device_printf(sc->mps_dev, "Cannot allocate FW diag buffer DMA " 1398230592Sken "tag\n"); 1399230592Sken return (ENOMEM); 1400230592Sken } 1401230592Sken if (bus_dmamem_alloc(sc->fw_diag_dmat, (void **)&sc->fw_diag_buffer, 1402230592Sken BUS_DMA_NOWAIT, &sc->fw_diag_map)) { 1403230592Sken device_printf(sc->mps_dev, "Cannot allocate FW diag buffer " 1404230592Sken "memory\n"); 1405230592Sken return (ENOMEM); 1406230592Sken } 1407230592Sken bzero(sc->fw_diag_buffer, buffer_size); 1408230592Sken bus_dmamap_load(sc->fw_diag_dmat, sc->fw_diag_map, sc->fw_diag_buffer, 1409230592Sken buffer_size, mps_memaddr_cb, &sc->fw_diag_busaddr, 0); 1410230592Sken pBuffer->size = buffer_size; 1411230592Sken 1412230592Sken /* 1413230592Sken * Copy the given info to the diag buffer and post the buffer. 1414230592Sken */ 1415230592Sken pBuffer->buffer_type = buffer_type; 1416230592Sken pBuffer->immediate = FALSE; 1417230592Sken if (buffer_type == MPI2_DIAG_BUF_TYPE_TRACE) { 1418230592Sken for (i = 0; i < (sizeof (pBuffer->product_specific) / 4); 1419230592Sken i++) { 1420230592Sken pBuffer->product_specific[i] = 1421230592Sken diag_register->ProductSpecific[i]; 1422230592Sken } 1423230592Sken } 1424230592Sken pBuffer->extended_type = extended_type; 1425230592Sken pBuffer->unique_id = unique_id; 1426230592Sken status = mps_post_fw_diag_buffer(sc, pBuffer, return_code); 1427230592Sken 1428230592Sken /* 1429230592Sken * In case there was a failure, free the DMA buffer. 1430230592Sken */ 1431230592Sken if (status == MPS_DIAG_FAILURE) { 1432230592Sken if (sc->fw_diag_busaddr != 0) 1433230592Sken bus_dmamap_unload(sc->fw_diag_dmat, sc->fw_diag_map); 1434230592Sken if (sc->fw_diag_buffer != NULL) 1435230592Sken bus_dmamem_free(sc->fw_diag_dmat, sc->fw_diag_buffer, 1436230592Sken sc->fw_diag_map); 1437230592Sken if (sc->fw_diag_dmat != NULL) 1438230592Sken bus_dma_tag_destroy(sc->fw_diag_dmat); 1439230592Sken } 1440230592Sken 1441230592Sken return (status); 1442230592Sken} 1443230592Sken 1444230592Skenstatic int 1445230592Skenmps_diag_unregister(struct mps_softc *sc, 1446230592Sken mps_fw_diag_unregister_t *diag_unregister, uint32_t *return_code) 1447230592Sken{ 1448230592Sken mps_fw_diagnostic_buffer_t *pBuffer; 1449230592Sken uint8_t i; 1450230592Sken uint32_t unique_id; 1451230592Sken int status; 1452230592Sken 1453230592Sken unique_id = diag_unregister->UniqueId; 1454230592Sken 1455230592Sken /* 1456230592Sken * Get the current buffer and look up the unique ID. The unique ID 1457230592Sken * should be there. 1458230592Sken */ 1459230592Sken i = mps_get_fw_diag_buffer_number(sc, unique_id); 1460230592Sken if (i == MPS_FW_DIAGNOSTIC_UID_NOT_FOUND) { 1461230592Sken *return_code = MPS_FW_DIAG_ERROR_INVALID_UID; 1462230592Sken return (MPS_DIAG_FAILURE); 1463230592Sken } 1464230592Sken 1465230592Sken pBuffer = &sc->fw_diag_buffer_list[i]; 1466230592Sken 1467230592Sken /* 1468230592Sken * Try to release the buffer from FW before freeing it. If release 1469230592Sken * fails, don't free the DMA buffer in case FW tries to access it 1470230592Sken * later. If buffer is not owned by firmware, can't release it. 1471230592Sken */ 1472230592Sken if (!pBuffer->owned_by_firmware) { 1473230592Sken status = MPS_DIAG_SUCCESS; 1474230592Sken } else { 1475230592Sken status = mps_release_fw_diag_buffer(sc, pBuffer, return_code, 1476230592Sken MPS_FW_DIAG_TYPE_UNREGISTER); 1477230592Sken } 1478230592Sken 1479230592Sken /* 1480230592Sken * At this point, return the current status no matter what happens with 1481230592Sken * the DMA buffer. 1482230592Sken */ 1483230592Sken pBuffer->unique_id = MPS_FW_DIAG_INVALID_UID; 1484230592Sken if (status == MPS_DIAG_SUCCESS) { 1485230592Sken if (sc->fw_diag_busaddr != 0) 1486230592Sken bus_dmamap_unload(sc->fw_diag_dmat, sc->fw_diag_map); 1487230592Sken if (sc->fw_diag_buffer != NULL) 1488230592Sken bus_dmamem_free(sc->fw_diag_dmat, sc->fw_diag_buffer, 1489230592Sken sc->fw_diag_map); 1490230592Sken if (sc->fw_diag_dmat != NULL) 1491230592Sken bus_dma_tag_destroy(sc->fw_diag_dmat); 1492230592Sken } 1493230592Sken 1494230592Sken return (status); 1495230592Sken} 1496230592Sken 1497230592Skenstatic int 1498230592Skenmps_diag_query(struct mps_softc *sc, mps_fw_diag_query_t *diag_query, 1499230592Sken uint32_t *return_code) 1500230592Sken{ 1501230592Sken mps_fw_diagnostic_buffer_t *pBuffer; 1502230592Sken uint8_t i; 1503230592Sken uint32_t unique_id; 1504230592Sken 1505230592Sken unique_id = diag_query->UniqueId; 1506230592Sken 1507230592Sken /* 1508230592Sken * If ID is valid, query on ID. 1509230592Sken * If ID is invalid, query on buffer type. 1510230592Sken */ 1511230592Sken if (unique_id == MPS_FW_DIAG_INVALID_UID) { 1512230592Sken i = diag_query->BufferType; 1513230592Sken if (i >= MPI2_DIAG_BUF_TYPE_COUNT) { 1514230592Sken *return_code = MPS_FW_DIAG_ERROR_INVALID_UID; 1515230592Sken return (MPS_DIAG_FAILURE); 1516230592Sken } 1517230592Sken } else { 1518230592Sken i = mps_get_fw_diag_buffer_number(sc, unique_id); 1519230592Sken if (i == MPS_FW_DIAGNOSTIC_UID_NOT_FOUND) { 1520230592Sken *return_code = MPS_FW_DIAG_ERROR_INVALID_UID; 1521230592Sken return (MPS_DIAG_FAILURE); 1522230592Sken } 1523230592Sken } 1524230592Sken 1525230592Sken /* 1526230592Sken * Fill query structure with the diag buffer info. 1527230592Sken */ 1528230592Sken pBuffer = &sc->fw_diag_buffer_list[i]; 1529230592Sken diag_query->BufferType = pBuffer->buffer_type; 1530230592Sken diag_query->ExtendedType = pBuffer->extended_type; 1531230592Sken if (diag_query->BufferType == MPI2_DIAG_BUF_TYPE_TRACE) { 1532230592Sken for (i = 0; i < (sizeof(diag_query->ProductSpecific) / 4); 1533230592Sken i++) { 1534230592Sken diag_query->ProductSpecific[i] = 1535230592Sken pBuffer->product_specific[i]; 1536230592Sken } 1537230592Sken } 1538230592Sken diag_query->TotalBufferSize = pBuffer->size; 1539230592Sken diag_query->DriverAddedBufferSize = 0; 1540230592Sken diag_query->UniqueId = pBuffer->unique_id; 1541230592Sken diag_query->ApplicationFlags = 0; 1542230592Sken diag_query->DiagnosticFlags = 0; 1543230592Sken 1544230592Sken /* 1545230592Sken * Set/Clear application flags 1546230592Sken */ 1547230592Sken if (pBuffer->immediate) { 1548230592Sken diag_query->ApplicationFlags &= ~MPS_FW_DIAG_FLAG_APP_OWNED; 1549230592Sken } else { 1550230592Sken diag_query->ApplicationFlags |= MPS_FW_DIAG_FLAG_APP_OWNED; 1551230592Sken } 1552230592Sken if (pBuffer->valid_data || pBuffer->owned_by_firmware) { 1553230592Sken diag_query->ApplicationFlags |= MPS_FW_DIAG_FLAG_BUFFER_VALID; 1554230592Sken } else { 1555230592Sken diag_query->ApplicationFlags &= ~MPS_FW_DIAG_FLAG_BUFFER_VALID; 1556230592Sken } 1557230592Sken if (pBuffer->owned_by_firmware) { 1558230592Sken diag_query->ApplicationFlags |= 1559230592Sken MPS_FW_DIAG_FLAG_FW_BUFFER_ACCESS; 1560230592Sken } else { 1561230592Sken diag_query->ApplicationFlags &= 1562230592Sken ~MPS_FW_DIAG_FLAG_FW_BUFFER_ACCESS; 1563230592Sken } 1564230592Sken 1565230592Sken return (MPS_DIAG_SUCCESS); 1566230592Sken} 1567230592Sken 1568230592Skenstatic int 1569230592Skenmps_diag_read_buffer(struct mps_softc *sc, 1570230592Sken mps_diag_read_buffer_t *diag_read_buffer, uint8_t *ioctl_buf, 1571230592Sken uint32_t *return_code) 1572230592Sken{ 1573230592Sken mps_fw_diagnostic_buffer_t *pBuffer; 1574230592Sken uint8_t i, *pData; 1575230592Sken uint32_t unique_id; 1576230592Sken int status; 1577230592Sken 1578230592Sken unique_id = diag_read_buffer->UniqueId; 1579230592Sken 1580230592Sken /* 1581230592Sken * Get the current buffer and look up the unique ID. The unique ID 1582230592Sken * should be there. 1583230592Sken */ 1584230592Sken i = mps_get_fw_diag_buffer_number(sc, unique_id); 1585230592Sken if (i == MPS_FW_DIAGNOSTIC_UID_NOT_FOUND) { 1586230592Sken *return_code = MPS_FW_DIAG_ERROR_INVALID_UID; 1587230592Sken return (MPS_DIAG_FAILURE); 1588230592Sken } 1589230592Sken 1590230592Sken pBuffer = &sc->fw_diag_buffer_list[i]; 1591230592Sken 1592230592Sken /* 1593230592Sken * Make sure requested read is within limits 1594230592Sken */ 1595230592Sken if (diag_read_buffer->StartingOffset + diag_read_buffer->BytesToRead > 1596230592Sken pBuffer->size) { 1597230592Sken *return_code = MPS_FW_DIAG_ERROR_INVALID_PARAMETER; 1598230592Sken return (MPS_DIAG_FAILURE); 1599230592Sken } 1600230592Sken 1601230592Sken /* 1602230592Sken * Copy the requested data from DMA to the diag_read_buffer. The DMA 1603230592Sken * buffer that was allocated is one contiguous buffer. 1604230592Sken */ 1605230592Sken pData = (uint8_t *)(sc->fw_diag_buffer + 1606230592Sken diag_read_buffer->StartingOffset); 1607230592Sken if (copyout(pData, ioctl_buf, diag_read_buffer->BytesToRead) != 0) 1608230592Sken return (MPS_DIAG_FAILURE); 1609230592Sken diag_read_buffer->Status = 0; 1610230592Sken 1611230592Sken /* 1612230592Sken * Set or clear the Force Release flag. 1613230592Sken */ 1614230592Sken if (pBuffer->force_release) { 1615230592Sken diag_read_buffer->Flags |= MPS_FW_DIAG_FLAG_FORCE_RELEASE; 1616230592Sken } else { 1617230592Sken diag_read_buffer->Flags &= ~MPS_FW_DIAG_FLAG_FORCE_RELEASE; 1618230592Sken } 1619230592Sken 1620230592Sken /* 1621230592Sken * If buffer is to be reregistered, make sure it's not already owned by 1622230592Sken * firmware first. 1623230592Sken */ 1624230592Sken status = MPS_DIAG_SUCCESS; 1625230592Sken if (!pBuffer->owned_by_firmware) { 1626230592Sken if (diag_read_buffer->Flags & MPS_FW_DIAG_FLAG_REREGISTER) { 1627230592Sken status = mps_post_fw_diag_buffer(sc, pBuffer, 1628230592Sken return_code); 1629230592Sken } 1630230592Sken } 1631230592Sken 1632230592Sken return (status); 1633230592Sken} 1634230592Sken 1635230592Skenstatic int 1636230592Skenmps_diag_release(struct mps_softc *sc, mps_fw_diag_release_t *diag_release, 1637230592Sken uint32_t *return_code) 1638230592Sken{ 1639230592Sken mps_fw_diagnostic_buffer_t *pBuffer; 1640230592Sken uint8_t i; 1641230592Sken uint32_t unique_id; 1642230592Sken int status; 1643230592Sken 1644230592Sken unique_id = diag_release->UniqueId; 1645230592Sken 1646230592Sken /* 1647230592Sken * Get the current buffer and look up the unique ID. The unique ID 1648230592Sken * should be there. 1649230592Sken */ 1650230592Sken i = mps_get_fw_diag_buffer_number(sc, unique_id); 1651230592Sken if (i == MPS_FW_DIAGNOSTIC_UID_NOT_FOUND) { 1652230592Sken *return_code = MPS_FW_DIAG_ERROR_INVALID_UID; 1653230592Sken return (MPS_DIAG_FAILURE); 1654230592Sken } 1655230592Sken 1656230592Sken pBuffer = &sc->fw_diag_buffer_list[i]; 1657230592Sken 1658230592Sken /* 1659230592Sken * If buffer is not owned by firmware, it's already been released. 1660230592Sken */ 1661230592Sken if (!pBuffer->owned_by_firmware) { 1662230592Sken *return_code = MPS_FW_DIAG_ERROR_ALREADY_RELEASED; 1663230592Sken return (MPS_DIAG_FAILURE); 1664230592Sken } 1665230592Sken 1666230592Sken /* 1667230592Sken * Release the buffer. 1668230592Sken */ 1669230592Sken status = mps_release_fw_diag_buffer(sc, pBuffer, return_code, 1670230592Sken MPS_FW_DIAG_TYPE_RELEASE); 1671230592Sken return (status); 1672230592Sken} 1673230592Sken 1674230592Skenstatic int 1675230592Skenmps_do_diag_action(struct mps_softc *sc, uint32_t action, uint8_t *diag_action, 1676230592Sken uint32_t length, uint32_t *return_code) 1677230592Sken{ 1678230592Sken mps_fw_diag_register_t diag_register; 1679230592Sken mps_fw_diag_unregister_t diag_unregister; 1680230592Sken mps_fw_diag_query_t diag_query; 1681230592Sken mps_diag_read_buffer_t diag_read_buffer; 1682230592Sken mps_fw_diag_release_t diag_release; 1683230592Sken int status = MPS_DIAG_SUCCESS; 1684230592Sken uint32_t original_return_code; 1685230592Sken 1686230592Sken original_return_code = *return_code; 1687230592Sken *return_code = MPS_FW_DIAG_ERROR_SUCCESS; 1688230592Sken 1689230592Sken switch (action) { 1690230592Sken case MPS_FW_DIAG_TYPE_REGISTER: 1691230592Sken if (!length) { 1692230592Sken *return_code = 1693230592Sken MPS_FW_DIAG_ERROR_INVALID_PARAMETER; 1694230592Sken status = MPS_DIAG_FAILURE; 1695230592Sken break; 1696230592Sken } 1697230592Sken if (copyin(diag_action, &diag_register, 1698230592Sken sizeof(diag_register)) != 0) 1699230592Sken return (MPS_DIAG_FAILURE); 1700230592Sken status = mps_diag_register(sc, &diag_register, 1701230592Sken return_code); 1702230592Sken break; 1703230592Sken 1704230592Sken case MPS_FW_DIAG_TYPE_UNREGISTER: 1705230592Sken if (length < sizeof(diag_unregister)) { 1706230592Sken *return_code = 1707230592Sken MPS_FW_DIAG_ERROR_INVALID_PARAMETER; 1708230592Sken status = MPS_DIAG_FAILURE; 1709230592Sken break; 1710230592Sken } 1711230592Sken if (copyin(diag_action, &diag_unregister, 1712230592Sken sizeof(diag_unregister)) != 0) 1713230592Sken return (MPS_DIAG_FAILURE); 1714230592Sken status = mps_diag_unregister(sc, &diag_unregister, 1715230592Sken return_code); 1716230592Sken break; 1717230592Sken 1718230592Sken case MPS_FW_DIAG_TYPE_QUERY: 1719230592Sken if (length < sizeof (diag_query)) { 1720230592Sken *return_code = 1721230592Sken MPS_FW_DIAG_ERROR_INVALID_PARAMETER; 1722230592Sken status = MPS_DIAG_FAILURE; 1723230592Sken break; 1724230592Sken } 1725230592Sken if (copyin(diag_action, &diag_query, sizeof(diag_query)) 1726230592Sken != 0) 1727230592Sken return (MPS_DIAG_FAILURE); 1728230592Sken status = mps_diag_query(sc, &diag_query, return_code); 1729230592Sken if (status == MPS_DIAG_SUCCESS) 1730230592Sken if (copyout(&diag_query, diag_action, 1731230592Sken sizeof (diag_query)) != 0) 1732230592Sken return (MPS_DIAG_FAILURE); 1733230592Sken break; 1734230592Sken 1735230592Sken case MPS_FW_DIAG_TYPE_READ_BUFFER: 1736230592Sken if (copyin(diag_action, &diag_read_buffer, 1737230592Sken sizeof(diag_read_buffer)) != 0) 1738230592Sken return (MPS_DIAG_FAILURE); 1739230592Sken if (length < diag_read_buffer.BytesToRead) { 1740230592Sken *return_code = 1741230592Sken MPS_FW_DIAG_ERROR_INVALID_PARAMETER; 1742230592Sken status = MPS_DIAG_FAILURE; 1743230592Sken break; 1744230592Sken } 1745230592Sken status = mps_diag_read_buffer(sc, &diag_read_buffer, 1746230592Sken PTRIN(diag_read_buffer.PtrDataBuffer), 1747230592Sken return_code); 1748230592Sken if (status == MPS_DIAG_SUCCESS) { 1749230592Sken if (copyout(&diag_read_buffer, diag_action, 1750230592Sken sizeof(diag_read_buffer) - 1751230592Sken sizeof(diag_read_buffer.PtrDataBuffer)) != 1752230592Sken 0) 1753230592Sken return (MPS_DIAG_FAILURE); 1754230592Sken } 1755230592Sken break; 1756230592Sken 1757230592Sken case MPS_FW_DIAG_TYPE_RELEASE: 1758230592Sken if (length < sizeof(diag_release)) { 1759230592Sken *return_code = 1760230592Sken MPS_FW_DIAG_ERROR_INVALID_PARAMETER; 1761230592Sken status = MPS_DIAG_FAILURE; 1762230592Sken break; 1763230592Sken } 1764230592Sken if (copyin(diag_action, &diag_release, 1765230592Sken sizeof(diag_release)) != 0) 1766230592Sken return (MPS_DIAG_FAILURE); 1767230592Sken status = mps_diag_release(sc, &diag_release, 1768230592Sken return_code); 1769230592Sken break; 1770230592Sken 1771230592Sken default: 1772230592Sken *return_code = MPS_FW_DIAG_ERROR_INVALID_PARAMETER; 1773230592Sken status = MPS_DIAG_FAILURE; 1774230592Sken break; 1775230592Sken } 1776230592Sken 1777230592Sken if ((status == MPS_DIAG_FAILURE) && 1778230592Sken (original_return_code == MPS_FW_DIAG_NEW) && 1779230592Sken (*return_code != MPS_FW_DIAG_ERROR_SUCCESS)) 1780230592Sken status = MPS_DIAG_SUCCESS; 1781230592Sken 1782230592Sken return (status); 1783230592Sken} 1784230592Sken 1785230592Skenstatic int 1786230592Skenmps_user_diag_action(struct mps_softc *sc, mps_diag_action_t *data) 1787230592Sken{ 1788230592Sken int status; 1789230592Sken 1790230592Sken /* 1791230592Sken * Only allow one diag action at one time. 1792230592Sken */ 1793230592Sken if (sc->mps_flags & MPS_FLAGS_BUSY) { 1794253460Sscottl mps_dprint(sc, MPS_USER, "%s: Only one FW diag command " 1795230592Sken "allowed at a single time.", __func__); 1796230592Sken return (EBUSY); 1797230592Sken } 1798230592Sken sc->mps_flags |= MPS_FLAGS_BUSY; 1799230592Sken 1800230592Sken /* 1801230592Sken * Send diag action request 1802230592Sken */ 1803230592Sken if (data->Action == MPS_FW_DIAG_TYPE_REGISTER || 1804230592Sken data->Action == MPS_FW_DIAG_TYPE_UNREGISTER || 1805230592Sken data->Action == MPS_FW_DIAG_TYPE_QUERY || 1806230592Sken data->Action == MPS_FW_DIAG_TYPE_READ_BUFFER || 1807230592Sken data->Action == MPS_FW_DIAG_TYPE_RELEASE) { 1808230592Sken status = mps_do_diag_action(sc, data->Action, 1809230592Sken PTRIN(data->PtrDiagAction), data->Length, 1810230592Sken &data->ReturnCode); 1811230592Sken } else 1812230592Sken status = EINVAL; 1813230592Sken 1814230592Sken sc->mps_flags &= ~MPS_FLAGS_BUSY; 1815230592Sken return (status); 1816230592Sken} 1817230592Sken 1818230592Sken/* 1819230592Sken * Copy the event recording mask and the event queue size out. For 1820230592Sken * clarification, the event recording mask (events_to_record) is not the same 1821230592Sken * thing as the event mask (event_mask). events_to_record has a bit set for 1822230592Sken * every event type that is to be recorded by the driver, and event_mask has a 1823230592Sken * bit cleared for every event that is allowed into the driver from the IOC. 1824230592Sken * They really have nothing to do with each other. 1825230592Sken */ 1826230592Skenstatic void 1827230592Skenmps_user_event_query(struct mps_softc *sc, mps_event_query_t *data) 1828230592Sken{ 1829230592Sken uint8_t i; 1830230592Sken 1831230592Sken mps_lock(sc); 1832230592Sken data->Entries = MPS_EVENT_QUEUE_SIZE; 1833230592Sken 1834230592Sken for (i = 0; i < 4; i++) { 1835230592Sken data->Types[i] = sc->events_to_record[i]; 1836230592Sken } 1837230592Sken mps_unlock(sc); 1838230592Sken} 1839230592Sken 1840230592Sken/* 1841230592Sken * Set the driver's event mask according to what's been given. See 1842230592Sken * mps_user_event_query for explanation of the event recording mask and the IOC 1843230592Sken * event mask. It's the app's responsibility to enable event logging by setting 1844230592Sken * the bits in events_to_record. Initially, no events will be logged. 1845230592Sken */ 1846230592Skenstatic void 1847230592Skenmps_user_event_enable(struct mps_softc *sc, mps_event_enable_t *data) 1848230592Sken{ 1849230592Sken uint8_t i; 1850230592Sken 1851230592Sken mps_lock(sc); 1852230592Sken for (i = 0; i < 4; i++) { 1853230592Sken sc->events_to_record[i] = data->Types[i]; 1854230592Sken } 1855230592Sken mps_unlock(sc); 1856230592Sken} 1857230592Sken 1858230592Sken/* 1859230592Sken * Copy out the events that have been recorded, up to the max events allowed. 1860230592Sken */ 1861230592Skenstatic int 1862230592Skenmps_user_event_report(struct mps_softc *sc, mps_event_report_t *data) 1863230592Sken{ 1864230592Sken int status = 0; 1865230592Sken uint32_t size; 1866230592Sken 1867230592Sken mps_lock(sc); 1868230592Sken size = data->Size; 1869230592Sken if ((size >= sizeof(sc->recorded_events)) && (status == 0)) { 1870230592Sken mps_unlock(sc); 1871230592Sken if (copyout((void *)sc->recorded_events, 1872230592Sken PTRIN(data->PtrEvents), size) != 0) 1873230592Sken status = EFAULT; 1874230592Sken mps_lock(sc); 1875230592Sken } else { 1876230592Sken /* 1877230592Sken * data->Size value is not large enough to copy event data. 1878230592Sken */ 1879230592Sken status = EFAULT; 1880230592Sken } 1881230592Sken 1882230592Sken /* 1883230592Sken * Change size value to match the number of bytes that were copied. 1884230592Sken */ 1885230592Sken if (status == 0) 1886230592Sken data->Size = sizeof(sc->recorded_events); 1887230592Sken mps_unlock(sc); 1888230592Sken 1889230592Sken return (status); 1890230592Sken} 1891230592Sken 1892230592Sken/* 1893230592Sken * Record events into the driver from the IOC if they are not masked. 1894230592Sken */ 1895230592Skenvoid 1896230592Skenmpssas_record_event(struct mps_softc *sc, 1897230592Sken MPI2_EVENT_NOTIFICATION_REPLY *event_reply) 1898230592Sken{ 1899230592Sken uint32_t event; 1900230592Sken int i, j; 1901230592Sken uint16_t event_data_len; 1902230592Sken boolean_t sendAEN = FALSE; 1903230592Sken 1904230592Sken event = event_reply->Event; 1905230592Sken 1906230592Sken /* 1907230592Sken * Generate a system event to let anyone who cares know that a 1908230592Sken * LOG_ENTRY_ADDED event has occurred. This is sent no matter what the 1909230592Sken * event mask is set to. 1910230592Sken */ 1911230592Sken if (event == MPI2_EVENT_LOG_ENTRY_ADDED) { 1912230592Sken sendAEN = TRUE; 1913230592Sken } 1914230592Sken 1915230592Sken /* 1916230592Sken * Record the event only if its corresponding bit is set in 1917230592Sken * events_to_record. event_index is the index into recorded_events and 1918230592Sken * event_number is the overall number of an event being recorded since 1919230592Sken * start-of-day. event_index will roll over; event_number will never 1920230592Sken * roll over. 1921230592Sken */ 1922230592Sken i = (uint8_t)(event / 32); 1923230592Sken j = (uint8_t)(event % 32); 1924230592Sken if ((i < 4) && ((1 << j) & sc->events_to_record[i])) { 1925230592Sken i = sc->event_index; 1926230592Sken sc->recorded_events[i].Type = event; 1927230592Sken sc->recorded_events[i].Number = ++sc->event_number; 1928230592Sken bzero(sc->recorded_events[i].Data, MPS_MAX_EVENT_DATA_LENGTH * 1929230592Sken 4); 1930230592Sken event_data_len = event_reply->EventDataLength; 1931230592Sken 1932230592Sken if (event_data_len > 0) { 1933230592Sken /* 1934230592Sken * Limit data to size in m_event entry 1935230592Sken */ 1936230592Sken if (event_data_len > MPS_MAX_EVENT_DATA_LENGTH) { 1937230592Sken event_data_len = MPS_MAX_EVENT_DATA_LENGTH; 1938230592Sken } 1939230592Sken for (j = 0; j < event_data_len; j++) { 1940230592Sken sc->recorded_events[i].Data[j] = 1941230592Sken event_reply->EventData[j]; 1942230592Sken } 1943230592Sken 1944230592Sken /* 1945230592Sken * check for index wrap-around 1946230592Sken */ 1947230592Sken if (++i == MPS_EVENT_QUEUE_SIZE) { 1948230592Sken i = 0; 1949230592Sken } 1950230592Sken sc->event_index = (uint8_t)i; 1951230592Sken 1952230592Sken /* 1953230592Sken * Set flag to send the event. 1954230592Sken */ 1955230592Sken sendAEN = TRUE; 1956230592Sken } 1957230592Sken } 1958230592Sken 1959230592Sken /* 1960230592Sken * Generate a system event if flag is set to let anyone who cares know 1961230592Sken * that an event has occurred. 1962230592Sken */ 1963230592Sken if (sendAEN) { 1964230592Sken//SLM-how to send a system event (see kqueue, kevent) 1965230592Sken// (void) ddi_log_sysevent(mpt->m_dip, DDI_VENDOR_LSI, "MPT_SAS", 1966230592Sken// "SAS", NULL, NULL, DDI_NOSLEEP); 1967230592Sken } 1968230592Sken} 1969230592Sken 1970230592Skenstatic int 1971230592Skenmps_user_reg_access(struct mps_softc *sc, mps_reg_access_t *data) 1972230592Sken{ 1973230592Sken int status = 0; 1974230592Sken 1975230592Sken switch (data->Command) { 1976230592Sken /* 1977230592Sken * IO access is not supported. 1978230592Sken */ 1979230592Sken case REG_IO_READ: 1980230592Sken case REG_IO_WRITE: 1981253460Sscottl mps_dprint(sc, MPS_USER, "IO access is not supported. " 1982230592Sken "Use memory access."); 1983230592Sken status = EINVAL; 1984230592Sken break; 1985230592Sken 1986230592Sken case REG_MEM_READ: 1987230592Sken data->RegData = mps_regread(sc, data->RegOffset); 1988230592Sken break; 1989230592Sken 1990230592Sken case REG_MEM_WRITE: 1991230592Sken mps_regwrite(sc, data->RegOffset, data->RegData); 1992230592Sken break; 1993230592Sken 1994230592Sken default: 1995230592Sken status = EINVAL; 1996230592Sken break; 1997230592Sken } 1998230592Sken 1999230592Sken return (status); 2000230592Sken} 2001230592Sken 2002230592Skenstatic int 2003230592Skenmps_user_btdh(struct mps_softc *sc, mps_btdh_mapping_t *data) 2004230592Sken{ 2005230592Sken uint8_t bt2dh = FALSE; 2006230592Sken uint8_t dh2bt = FALSE; 2007230592Sken uint16_t dev_handle, bus, target; 2008230592Sken 2009230592Sken bus = data->Bus; 2010230592Sken target = data->TargetID; 2011230592Sken dev_handle = data->DevHandle; 2012230592Sken 2013230592Sken /* 2014230592Sken * When DevHandle is 0xFFFF and Bus/Target are not 0xFFFF, use Bus/ 2015230592Sken * Target to get DevHandle. When Bus/Target are 0xFFFF and DevHandle is 2016230592Sken * not 0xFFFF, use DevHandle to get Bus/Target. Anything else is 2017230592Sken * invalid. 2018230592Sken */ 2019230592Sken if ((bus == 0xFFFF) && (target == 0xFFFF) && (dev_handle != 0xFFFF)) 2020230592Sken dh2bt = TRUE; 2021230592Sken if ((dev_handle == 0xFFFF) && (bus != 0xFFFF) && (target != 0xFFFF)) 2022230592Sken bt2dh = TRUE; 2023230592Sken if (!dh2bt && !bt2dh) 2024230592Sken return (EINVAL); 2025230592Sken 2026230592Sken /* 2027230592Sken * Only handle bus of 0. Make sure target is within range. 2028230592Sken */ 2029230592Sken if (bt2dh) { 2030230592Sken if (bus != 0) 2031230592Sken return (EINVAL); 2032230592Sken 2033230592Sken if (target > sc->max_devices) { 2034230592Sken mps_dprint(sc, MPS_FAULT, "Target ID is out of range " 2035230592Sken "for Bus/Target to DevHandle mapping."); 2036230592Sken return (EINVAL); 2037230592Sken } 2038230592Sken dev_handle = sc->mapping_table[target].dev_handle; 2039230592Sken if (dev_handle) 2040230592Sken data->DevHandle = dev_handle; 2041230592Sken } else { 2042230592Sken bus = 0; 2043230592Sken target = mps_mapping_get_sas_id_from_handle(sc, dev_handle); 2044230592Sken data->Bus = bus; 2045230592Sken data->TargetID = target; 2046230592Sken } 2047230592Sken 2048230592Sken return (0); 2049230592Sken} 2050230592Sken 2051230592Skenstatic int 2052213702Smdfmps_ioctl(struct cdev *dev, u_long cmd, void *arg, int flag, 2053212420Sken struct thread *td) 2054212420Sken{ 2055212420Sken struct mps_softc *sc; 2056212420Sken struct mps_cfg_page_req *page_req; 2057212420Sken struct mps_ext_cfg_page_req *ext_page_req; 2058212420Sken void *mps_page; 2059237683Sken int error, msleep_ret; 2060212420Sken 2061212420Sken mps_page = NULL; 2062212420Sken sc = dev->si_drv1; 2063212420Sken page_req = (void *)arg; 2064212420Sken ext_page_req = (void *)arg; 2065212420Sken 2066212420Sken switch (cmd) { 2067212420Sken case MPSIO_READ_CFG_HEADER: 2068212420Sken mps_lock(sc); 2069212420Sken error = mps_user_read_cfg_header(sc, page_req); 2070212420Sken mps_unlock(sc); 2071212420Sken break; 2072212420Sken case MPSIO_READ_CFG_PAGE: 2073212420Sken mps_page = malloc(page_req->len, M_MPSUSER, M_WAITOK | M_ZERO); 2074237683Sken if(!mps_page) { 2075237683Sken mps_printf(sc, "Cannot allocate memory %s %d\n", 2076237683Sken __func__, __LINE__); 2077237683Sken return (ENOMEM); 2078237683Sken } 2079212420Sken error = copyin(page_req->buf, mps_page, 2080212420Sken sizeof(MPI2_CONFIG_PAGE_HEADER)); 2081212420Sken if (error) 2082212420Sken break; 2083212420Sken mps_lock(sc); 2084212420Sken error = mps_user_read_cfg_page(sc, page_req, mps_page); 2085212420Sken mps_unlock(sc); 2086212420Sken if (error) 2087212420Sken break; 2088212420Sken error = copyout(mps_page, page_req->buf, page_req->len); 2089212420Sken break; 2090212420Sken case MPSIO_READ_EXT_CFG_HEADER: 2091212420Sken mps_lock(sc); 2092212420Sken error = mps_user_read_extcfg_header(sc, ext_page_req); 2093212420Sken mps_unlock(sc); 2094212420Sken break; 2095212420Sken case MPSIO_READ_EXT_CFG_PAGE: 2096212420Sken mps_page = malloc(ext_page_req->len, M_MPSUSER, M_WAITOK|M_ZERO); 2097237683Sken if(!mps_page) { 2098237683Sken mps_printf(sc, "Cannot allocate memory %s %d\n", 2099237683Sken __func__, __LINE__); 2100237683Sken return (ENOMEM); 2101237683Sken } 2102212420Sken error = copyin(ext_page_req->buf, mps_page, 2103212420Sken sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); 2104212420Sken if (error) 2105212420Sken break; 2106212420Sken mps_lock(sc); 2107212420Sken error = mps_user_read_extcfg_page(sc, ext_page_req, mps_page); 2108212420Sken mps_unlock(sc); 2109212420Sken if (error) 2110212420Sken break; 2111212420Sken error = copyout(mps_page, ext_page_req->buf, ext_page_req->len); 2112212420Sken break; 2113212420Sken case MPSIO_WRITE_CFG_PAGE: 2114212420Sken mps_page = malloc(page_req->len, M_MPSUSER, M_WAITOK|M_ZERO); 2115237683Sken if(!mps_page) { 2116237683Sken mps_printf(sc, "Cannot allocate memory %s %d\n", 2117237683Sken __func__, __LINE__); 2118237683Sken return (ENOMEM); 2119237683Sken } 2120212420Sken error = copyin(page_req->buf, mps_page, page_req->len); 2121212420Sken if (error) 2122212420Sken break; 2123212420Sken mps_lock(sc); 2124212420Sken error = mps_user_write_cfg_page(sc, page_req, mps_page); 2125212420Sken mps_unlock(sc); 2126212420Sken break; 2127212420Sken case MPSIO_MPS_COMMAND: 2128212420Sken error = mps_user_command(sc, (struct mps_usr_command *)arg); 2129212420Sken break; 2130230592Sken case MPTIOCTL_PASS_THRU: 2131230592Sken /* 2132230592Sken * The user has requested to pass through a command to be 2133230592Sken * executed by the MPT firmware. Call our routine which does 2134230592Sken * this. Only allow one passthru IOCTL at one time. 2135230592Sken */ 2136230592Sken error = mps_user_pass_thru(sc, (mps_pass_thru_t *)arg); 2137230592Sken break; 2138230592Sken case MPTIOCTL_GET_ADAPTER_DATA: 2139230592Sken /* 2140230592Sken * The user has requested to read adapter data. Call our 2141230592Sken * routine which does this. 2142230592Sken */ 2143230592Sken error = 0; 2144230592Sken mps_user_get_adapter_data(sc, (mps_adapter_data_t *)arg); 2145230592Sken break; 2146230592Sken case MPTIOCTL_GET_PCI_INFO: 2147230592Sken /* 2148230592Sken * The user has requested to read pci info. Call 2149230592Sken * our routine which does this. 2150230592Sken */ 2151230592Sken mps_lock(sc); 2152230592Sken error = 0; 2153230592Sken mps_user_read_pci_info(sc, (mps_pci_info_t *)arg); 2154230592Sken mps_unlock(sc); 2155230592Sken break; 2156230592Sken case MPTIOCTL_RESET_ADAPTER: 2157230592Sken mps_lock(sc); 2158230592Sken sc->port_enable_complete = 0; 2159237683Sken uint32_t reinit_start = time_uptime; 2160230592Sken error = mps_reinit(sc); 2161237683Sken /* Sleep for 300 second. */ 2162237683Sken msleep_ret = msleep(&sc->port_enable_complete, &sc->mps_mtx, PRIBIO, 2163237683Sken "mps_porten", 300 * hz); 2164230592Sken mps_unlock(sc); 2165237683Sken if (msleep_ret) 2166230592Sken printf("Port Enable did not complete after Diag " 2167237683Sken "Reset msleep error %d.\n", msleep_ret); 2168237683Sken else 2169253460Sscottl mps_dprint(sc, MPS_USER, 2170237683Sken "Hard Reset with Port Enable completed in %d seconds.\n", 2171237683Sken (uint32_t) (time_uptime - reinit_start)); 2172230592Sken break; 2173230592Sken case MPTIOCTL_DIAG_ACTION: 2174230592Sken /* 2175230592Sken * The user has done a diag buffer action. Call our routine 2176230592Sken * which does this. Only allow one diag action at one time. 2177230592Sken */ 2178230592Sken mps_lock(sc); 2179230592Sken error = mps_user_diag_action(sc, (mps_diag_action_t *)arg); 2180230592Sken mps_unlock(sc); 2181230592Sken break; 2182230592Sken case MPTIOCTL_EVENT_QUERY: 2183230592Sken /* 2184230592Sken * The user has done an event query. Call our routine which does 2185230592Sken * this. 2186230592Sken */ 2187230592Sken error = 0; 2188230592Sken mps_user_event_query(sc, (mps_event_query_t *)arg); 2189230592Sken break; 2190230592Sken case MPTIOCTL_EVENT_ENABLE: 2191230592Sken /* 2192230592Sken * The user has done an event enable. Call our routine which 2193230592Sken * does this. 2194230592Sken */ 2195230592Sken error = 0; 2196230592Sken mps_user_event_enable(sc, (mps_event_enable_t *)arg); 2197230592Sken break; 2198230592Sken case MPTIOCTL_EVENT_REPORT: 2199230592Sken /* 2200230592Sken * The user has done an event report. Call our routine which 2201230592Sken * does this. 2202230592Sken */ 2203230592Sken error = mps_user_event_report(sc, (mps_event_report_t *)arg); 2204230592Sken break; 2205230592Sken case MPTIOCTL_REG_ACCESS: 2206230592Sken /* 2207230592Sken * The user has requested register access. Call our routine 2208230592Sken * which does this. 2209230592Sken */ 2210230592Sken mps_lock(sc); 2211230592Sken error = mps_user_reg_access(sc, (mps_reg_access_t *)arg); 2212230592Sken mps_unlock(sc); 2213230592Sken break; 2214230592Sken case MPTIOCTL_BTDH_MAPPING: 2215230592Sken /* 2216230592Sken * The user has requested to translate a bus/target to a 2217230592Sken * DevHandle or a DevHandle to a bus/target. Call our routine 2218230592Sken * which does this. 2219230592Sken */ 2220230592Sken error = mps_user_btdh(sc, (mps_btdh_mapping_t *)arg); 2221230592Sken break; 2222212420Sken default: 2223212420Sken error = ENOIOCTL; 2224212420Sken break; 2225212420Sken } 2226212420Sken 2227212420Sken if (mps_page != NULL) 2228212420Sken free(mps_page, M_MPSUSER); 2229212420Sken 2230213702Smdf return (error); 2231213702Smdf} 2232212420Sken 2233213702Smdf#ifdef COMPAT_FREEBSD32 2234213702Smdf 2235213702Smdfstruct mps_cfg_page_req32 { 2236213702Smdf MPI2_CONFIG_PAGE_HEADER header; 2237213702Smdf uint32_t page_address; 2238213702Smdf uint32_t buf; 2239213702Smdf int len; 2240213702Smdf uint16_t ioc_status; 2241213702Smdf}; 2242213702Smdf 2243213702Smdfstruct mps_ext_cfg_page_req32 { 2244213702Smdf MPI2_CONFIG_EXTENDED_PAGE_HEADER header; 2245213702Smdf uint32_t page_address; 2246213702Smdf uint32_t buf; 2247213702Smdf int len; 2248213702Smdf uint16_t ioc_status; 2249213702Smdf}; 2250213702Smdf 2251213702Smdfstruct mps_raid_action32 { 2252213702Smdf uint8_t action; 2253213702Smdf uint8_t volume_bus; 2254213702Smdf uint8_t volume_id; 2255213702Smdf uint8_t phys_disk_num; 2256213702Smdf uint32_t action_data_word; 2257213702Smdf uint32_t buf; 2258213702Smdf int len; 2259213702Smdf uint32_t volume_status; 2260213702Smdf uint32_t action_data[4]; 2261213702Smdf uint16_t action_status; 2262213702Smdf uint16_t ioc_status; 2263213702Smdf uint8_t write; 2264213702Smdf}; 2265213702Smdf 2266213702Smdfstruct mps_usr_command32 { 2267213702Smdf uint32_t req; 2268213702Smdf uint32_t req_len; 2269213702Smdf uint32_t rpl; 2270213702Smdf uint32_t rpl_len; 2271213702Smdf uint32_t buf; 2272213702Smdf int len; 2273213702Smdf uint32_t flags; 2274213702Smdf}; 2275213702Smdf 2276213702Smdf#define MPSIO_READ_CFG_HEADER32 _IOWR('M', 200, struct mps_cfg_page_req32) 2277213702Smdf#define MPSIO_READ_CFG_PAGE32 _IOWR('M', 201, struct mps_cfg_page_req32) 2278213702Smdf#define MPSIO_READ_EXT_CFG_HEADER32 _IOWR('M', 202, struct mps_ext_cfg_page_req32) 2279213702Smdf#define MPSIO_READ_EXT_CFG_PAGE32 _IOWR('M', 203, struct mps_ext_cfg_page_req32) 2280213702Smdf#define MPSIO_WRITE_CFG_PAGE32 _IOWR('M', 204, struct mps_cfg_page_req32) 2281213702Smdf#define MPSIO_RAID_ACTION32 _IOWR('M', 205, struct mps_raid_action32) 2282213702Smdf#define MPSIO_MPS_COMMAND32 _IOWR('M', 210, struct mps_usr_command32) 2283213702Smdf 2284213702Smdfstatic int 2285213702Smdfmps_ioctl32(struct cdev *dev, u_long cmd32, void *_arg, int flag, 2286213702Smdf struct thread *td) 2287213702Smdf{ 2288213702Smdf struct mps_cfg_page_req32 *page32 = _arg; 2289213702Smdf struct mps_ext_cfg_page_req32 *ext32 = _arg; 2290213702Smdf struct mps_raid_action32 *raid32 = _arg; 2291213702Smdf struct mps_usr_command32 *user32 = _arg; 2292213702Smdf union { 2293213702Smdf struct mps_cfg_page_req page; 2294213702Smdf struct mps_ext_cfg_page_req ext; 2295213702Smdf struct mps_raid_action raid; 2296213702Smdf struct mps_usr_command user; 2297213702Smdf } arg; 2298213702Smdf u_long cmd; 2299213702Smdf int error; 2300213702Smdf 2301213702Smdf switch (cmd32) { 2302212420Sken case MPSIO_READ_CFG_HEADER32: 2303212420Sken case MPSIO_READ_CFG_PAGE32: 2304212420Sken case MPSIO_WRITE_CFG_PAGE32: 2305213702Smdf if (cmd32 == MPSIO_READ_CFG_HEADER32) 2306213702Smdf cmd = MPSIO_READ_CFG_HEADER; 2307213702Smdf else if (cmd32 == MPSIO_READ_CFG_PAGE32) 2308213702Smdf cmd = MPSIO_READ_CFG_PAGE; 2309213702Smdf else 2310213702Smdf cmd = MPSIO_WRITE_CFG_PAGE; 2311213702Smdf CP(*page32, arg.page, header); 2312213702Smdf CP(*page32, arg.page, page_address); 2313213702Smdf PTRIN_CP(*page32, arg.page, buf); 2314213702Smdf CP(*page32, arg.page, len); 2315213702Smdf CP(*page32, arg.page, ioc_status); 2316212420Sken break; 2317213702Smdf 2318212420Sken case MPSIO_READ_EXT_CFG_HEADER32: 2319213702Smdf case MPSIO_READ_EXT_CFG_PAGE32: 2320213702Smdf if (cmd32 == MPSIO_READ_EXT_CFG_HEADER32) 2321213702Smdf cmd = MPSIO_READ_EXT_CFG_HEADER; 2322213702Smdf else 2323213702Smdf cmd = MPSIO_READ_EXT_CFG_PAGE; 2324213702Smdf CP(*ext32, arg.ext, header); 2325213702Smdf CP(*ext32, arg.ext, page_address); 2326213702Smdf PTRIN_CP(*ext32, arg.ext, buf); 2327213702Smdf CP(*ext32, arg.ext, len); 2328213702Smdf CP(*ext32, arg.ext, ioc_status); 2329212420Sken break; 2330213702Smdf 2331213702Smdf case MPSIO_RAID_ACTION32: 2332213702Smdf cmd = MPSIO_RAID_ACTION; 2333213702Smdf CP(*raid32, arg.raid, action); 2334213702Smdf CP(*raid32, arg.raid, volume_bus); 2335213702Smdf CP(*raid32, arg.raid, volume_id); 2336213702Smdf CP(*raid32, arg.raid, phys_disk_num); 2337213702Smdf CP(*raid32, arg.raid, action_data_word); 2338213702Smdf PTRIN_CP(*raid32, arg.raid, buf); 2339213702Smdf CP(*raid32, arg.raid, len); 2340213702Smdf CP(*raid32, arg.raid, volume_status); 2341213702Smdf bcopy(raid32->action_data, arg.raid.action_data, 2342213702Smdf sizeof arg.raid.action_data); 2343213702Smdf CP(*raid32, arg.raid, ioc_status); 2344213702Smdf CP(*raid32, arg.raid, write); 2345213702Smdf break; 2346213702Smdf 2347213702Smdf case MPSIO_MPS_COMMAND32: 2348213702Smdf cmd = MPSIO_MPS_COMMAND; 2349213702Smdf PTRIN_CP(*user32, arg.user, req); 2350213702Smdf CP(*user32, arg.user, req_len); 2351213702Smdf PTRIN_CP(*user32, arg.user, rpl); 2352213702Smdf CP(*user32, arg.user, rpl_len); 2353213702Smdf PTRIN_CP(*user32, arg.user, buf); 2354213702Smdf CP(*user32, arg.user, len); 2355213702Smdf CP(*user32, arg.user, flags); 2356213702Smdf break; 2357212420Sken default: 2358212420Sken return (ENOIOCTL); 2359212420Sken } 2360212420Sken 2361213702Smdf error = mps_ioctl(dev, cmd, &arg, flag, td); 2362213702Smdf if (error == 0 && (cmd32 & IOC_OUT) != 0) { 2363213702Smdf switch (cmd32) { 2364213702Smdf case MPSIO_READ_CFG_HEADER32: 2365213702Smdf case MPSIO_READ_CFG_PAGE32: 2366213702Smdf case MPSIO_WRITE_CFG_PAGE32: 2367213702Smdf CP(arg.page, *page32, header); 2368213702Smdf CP(arg.page, *page32, page_address); 2369213702Smdf PTROUT_CP(arg.page, *page32, buf); 2370213702Smdf CP(arg.page, *page32, len); 2371213702Smdf CP(arg.page, *page32, ioc_status); 2372213702Smdf break; 2373213702Smdf 2374213702Smdf case MPSIO_READ_EXT_CFG_HEADER32: 2375213702Smdf case MPSIO_READ_EXT_CFG_PAGE32: 2376213702Smdf CP(arg.ext, *ext32, header); 2377213702Smdf CP(arg.ext, *ext32, page_address); 2378213702Smdf PTROUT_CP(arg.ext, *ext32, buf); 2379213702Smdf CP(arg.ext, *ext32, len); 2380213702Smdf CP(arg.ext, *ext32, ioc_status); 2381213702Smdf break; 2382213702Smdf 2383213702Smdf case MPSIO_RAID_ACTION32: 2384213702Smdf CP(arg.raid, *raid32, action); 2385213702Smdf CP(arg.raid, *raid32, volume_bus); 2386213702Smdf CP(arg.raid, *raid32, volume_id); 2387213702Smdf CP(arg.raid, *raid32, phys_disk_num); 2388213702Smdf CP(arg.raid, *raid32, action_data_word); 2389213702Smdf PTROUT_CP(arg.raid, *raid32, buf); 2390213702Smdf CP(arg.raid, *raid32, len); 2391213702Smdf CP(arg.raid, *raid32, volume_status); 2392213702Smdf bcopy(arg.raid.action_data, raid32->action_data, 2393213702Smdf sizeof arg.raid.action_data); 2394213702Smdf CP(arg.raid, *raid32, ioc_status); 2395213702Smdf CP(arg.raid, *raid32, write); 2396213702Smdf break; 2397213702Smdf 2398213702Smdf case MPSIO_MPS_COMMAND32: 2399213702Smdf PTROUT_CP(arg.user, *user32, req); 2400213702Smdf CP(arg.user, *user32, req_len); 2401213702Smdf PTROUT_CP(arg.user, *user32, rpl); 2402213702Smdf CP(arg.user, *user32, rpl_len); 2403213702Smdf PTROUT_CP(arg.user, *user32, buf); 2404213702Smdf CP(arg.user, *user32, len); 2405213702Smdf CP(arg.user, *user32, flags); 2406213702Smdf break; 2407213702Smdf } 2408213702Smdf } 2409213702Smdf 2410213702Smdf return (error); 2411212420Sken} 2412213702Smdf#endif /* COMPAT_FREEBSD32 */ 2413213702Smdf 2414213702Smdfstatic int 2415213702Smdfmps_ioctl_devsw(struct cdev *dev, u_long com, caddr_t arg, int flag, 2416213702Smdf struct thread *td) 2417213702Smdf{ 2418213702Smdf#ifdef COMPAT_FREEBSD32 2419213702Smdf if (SV_CURPROC_FLAG(SV_ILP32)) 2420213702Smdf return (mps_ioctl32(dev, com, arg, flag, td)); 2421213702Smdf#endif 2422213702Smdf return (mps_ioctl(dev, com, arg, flag, td)); 2423213702Smdf} 2424