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 * 30230920Sken * LSI MPT-Fusion Host Adapter FreeBSD userland interface 31212420Sken */ 32230920Sken/*- 33237876Sken * Copyright (c) 2011, 2012 LSI Corp. 34230920Sken * All rights reserved. 35230920Sken * 36230920Sken * Redistribution and use in source and binary forms, with or without 37230920Sken * modification, are permitted provided that the following conditions 38230920Sken * are met: 39230920Sken * 1. Redistributions of source code must retain the above copyright 40230920Sken * notice, this list of conditions and the following disclaimer. 41230920Sken * 2. Redistributions in binary form must reproduce the above copyright 42230920Sken * notice, this list of conditions and the following disclaimer in the 43230920Sken * documentation and/or other materials provided with the distribution. 44230920Sken * 45230920Sken * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 46230920Sken * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 47230920Sken * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 48230920Sken * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 49230920Sken * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 50230920Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 51230920Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52230920Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 53230920Sken * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 54230920Sken * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 55230920Sken * SUCH DAMAGE. 56230920Sken * 57230920Sken * LSI MPT-Fusion Host Adapter FreeBSD 58230920Sken * 59230920Sken * $FreeBSD$ 60230920Sken */ 61212420Sken 62212420Sken#include <sys/cdefs.h> 63212420Sken__FBSDID("$FreeBSD$"); 64212420Sken 65213702Smdf#include "opt_compat.h" 66213702Smdf 67230920Sken/* 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> 82230920Sken#include <sys/queue.h> 83230920Sken#include <sys/kthread.h> 84230920Sken#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 92230920Sken#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> 99230920Sken#include <dev/mps/mpi/mpi2_init.h> 100230920Sken#include <dev/mps/mpi/mpi2_tool.h> 101230920Sken#include <dev/mps/mps_ioctl.h> 102212420Sken#include <dev/mps/mpsvar.h> 103212420Sken#include <dev/mps/mps_table.h> 104230920Sken#include <dev/mps/mps_sas.h> 105230920Sken#include <dev/pci/pcivar.h> 106230920Sken#include <dev/pci/pcireg.h> 107212420Sken 108212420Skenstatic d_open_t mps_open; 109212420Skenstatic d_close_t mps_close; 110213702Smdfstatic d_ioctl_t mps_ioctl_devsw; 111212420Sken 112212420Skenstatic struct cdevsw mps_cdevsw = { 113212420Sken .d_version = D_VERSION, 114212420Sken .d_flags = 0, 115212420Sken .d_open = mps_open, 116212420Sken .d_close = mps_close, 117213702Smdf .d_ioctl = mps_ioctl_devsw, 118212420Sken .d_name = "mps", 119212420Sken}; 120212420Sken 121213708Smdftypedef int (mps_user_f)(struct mps_command *, struct mps_usr_command *); 122213708Smdfstatic mps_user_f mpi_pre_ioc_facts; 123213708Smdfstatic mps_user_f mpi_pre_port_facts; 124213708Smdfstatic mps_user_f mpi_pre_fw_download; 125213708Smdfstatic mps_user_f mpi_pre_fw_upload; 126213708Smdfstatic mps_user_f mpi_pre_sata_passthrough; 127213708Smdfstatic mps_user_f mpi_pre_smp_passthrough; 128213708Smdfstatic mps_user_f mpi_pre_config; 129213708Smdfstatic mps_user_f mpi_pre_sas_io_unit_control; 130213708Smdf 131213707Smdfstatic int mps_user_read_cfg_header(struct mps_softc *, 132213707Smdf struct mps_cfg_page_req *); 133213707Smdfstatic int mps_user_read_cfg_page(struct mps_softc *, 134213707Smdf struct mps_cfg_page_req *, void *); 135213707Smdfstatic int mps_user_read_extcfg_header(struct mps_softc *, 136213707Smdf struct mps_ext_cfg_page_req *); 137213707Smdfstatic int mps_user_read_extcfg_page(struct mps_softc *, 138213707Smdf struct mps_ext_cfg_page_req *, void *); 139213707Smdfstatic int mps_user_write_cfg_page(struct mps_softc *, 140213707Smdf struct mps_cfg_page_req *, void *); 141213708Smdfstatic int mps_user_setup_request(struct mps_command *, 142213708Smdf struct mps_usr_command *); 143213707Smdfstatic int mps_user_command(struct mps_softc *, struct mps_usr_command *); 144213707Smdf 145230920Skenstatic int mps_user_pass_thru(struct mps_softc *sc, mps_pass_thru_t *data); 146230920Skenstatic void mps_user_get_adapter_data(struct mps_softc *sc, 147230920Sken mps_adapter_data_t *data); 148230920Skenstatic void mps_user_read_pci_info(struct mps_softc *sc, 149230920Sken mps_pci_info_t *data); 150230920Skenstatic uint8_t mps_get_fw_diag_buffer_number(struct mps_softc *sc, 151230920Sken uint32_t unique_id); 152230920Skenstatic int mps_post_fw_diag_buffer(struct mps_softc *sc, 153230920Sken mps_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code); 154230920Skenstatic int mps_release_fw_diag_buffer(struct mps_softc *sc, 155230920Sken mps_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code, 156230920Sken uint32_t diag_type); 157230920Skenstatic int mps_diag_register(struct mps_softc *sc, 158230920Sken mps_fw_diag_register_t *diag_register, uint32_t *return_code); 159230920Skenstatic int mps_diag_unregister(struct mps_softc *sc, 160230920Sken mps_fw_diag_unregister_t *diag_unregister, uint32_t *return_code); 161230920Skenstatic int mps_diag_query(struct mps_softc *sc, mps_fw_diag_query_t *diag_query, 162230920Sken uint32_t *return_code); 163230920Skenstatic int mps_diag_read_buffer(struct mps_softc *sc, 164230920Sken mps_diag_read_buffer_t *diag_read_buffer, uint8_t *ioctl_buf, 165230920Sken uint32_t *return_code); 166230920Skenstatic int mps_diag_release(struct mps_softc *sc, 167230920Sken mps_fw_diag_release_t *diag_release, uint32_t *return_code); 168230920Skenstatic int mps_do_diag_action(struct mps_softc *sc, uint32_t action, 169230920Sken uint8_t *diag_action, uint32_t length, uint32_t *return_code); 170230920Skenstatic int mps_user_diag_action(struct mps_softc *sc, mps_diag_action_t *data); 171230920Skenstatic void mps_user_event_query(struct mps_softc *sc, mps_event_query_t *data); 172230920Skenstatic void mps_user_event_enable(struct mps_softc *sc, 173230920Sken mps_event_enable_t *data); 174230920Skenstatic int mps_user_event_report(struct mps_softc *sc, 175230920Sken mps_event_report_t *data); 176230920Skenstatic int mps_user_reg_access(struct mps_softc *sc, mps_reg_access_t *data); 177230920Skenstatic int mps_user_btdh(struct mps_softc *sc, mps_btdh_mapping_t *data); 178230920Sken 179212420Skenstatic MALLOC_DEFINE(M_MPSUSER, "mps_user", "Buffers for mps(4) ioctls"); 180212420Sken 181230920Sken/* Macros from compat/freebsd32/freebsd32.h */ 182230920Sken#define PTRIN(v) (void *)(uintptr_t)(v) 183230920Sken#define PTROUT(v) (uint32_t)(uintptr_t)(v) 184230920Sken 185230920Sken#define CP(src,dst,fld) do { (dst).fld = (src).fld; } while (0) 186230920Sken#define PTRIN_CP(src,dst,fld) \ 187230920Sken do { (dst).fld = PTRIN((src).fld); } while (0) 188230920Sken#define PTROUT_CP(src,dst,fld) \ 189230920Sken do { (dst).fld = PTROUT((src).fld); } while (0) 190230920Sken 191212420Skenint 192212420Skenmps_attach_user(struct mps_softc *sc) 193212420Sken{ 194212420Sken int unit; 195212420Sken 196212420Sken unit = device_get_unit(sc->mps_dev); 197212420Sken sc->mps_cdev = make_dev(&mps_cdevsw, unit, UID_ROOT, GID_OPERATOR, 0640, 198212420Sken "mps%d", unit); 199212420Sken if (sc->mps_cdev == NULL) { 200212420Sken return (ENOMEM); 201212420Sken } 202212420Sken sc->mps_cdev->si_drv1 = sc; 203212420Sken return (0); 204212420Sken} 205212420Sken 206212420Skenvoid 207212420Skenmps_detach_user(struct mps_softc *sc) 208212420Sken{ 209212420Sken 210212420Sken /* XXX: do a purge of pending requests? */ 211251092Smav if (sc->mps_cdev != NULL) 212251092Smav destroy_dev(sc->mps_cdev); 213212420Sken} 214212420Sken 215212420Skenstatic int 216212420Skenmps_open(struct cdev *dev, int flags, int fmt, struct thread *td) 217212420Sken{ 218212420Sken 219212420Sken return (0); 220212420Sken} 221212420Sken 222212420Skenstatic int 223212420Skenmps_close(struct cdev *dev, int flags, int fmt, struct thread *td) 224212420Sken{ 225212420Sken 226212420Sken return (0); 227212420Sken} 228212420Sken 229212420Skenstatic int 230212420Skenmps_user_read_cfg_header(struct mps_softc *sc, 231212420Sken struct mps_cfg_page_req *page_req) 232212420Sken{ 233212420Sken MPI2_CONFIG_PAGE_HEADER *hdr; 234212420Sken struct mps_config_params params; 235212420Sken int error; 236212420Sken 237212420Sken hdr = ¶ms.hdr.Struct; 238212420Sken params.action = MPI2_CONFIG_ACTION_PAGE_HEADER; 239212420Sken params.page_address = le32toh(page_req->page_address); 240212420Sken hdr->PageVersion = 0; 241212420Sken hdr->PageLength = 0; 242212420Sken hdr->PageNumber = page_req->header.PageNumber; 243212420Sken hdr->PageType = page_req->header.PageType; 244212420Sken params.buffer = NULL; 245212420Sken params.length = 0; 246212420Sken params.callback = NULL; 247212420Sken 248212420Sken if ((error = mps_read_config_page(sc, ¶ms)) != 0) { 249212420Sken /* 250212420Sken * Leave the request. Without resetting the chip, it's 251212420Sken * still owned by it and we'll just get into trouble 252212420Sken * freeing it now. Mark it as abandoned so that if it 253212420Sken * shows up later it can be freed. 254212420Sken */ 255212420Sken mps_printf(sc, "read_cfg_header timed out\n"); 256212420Sken return (ETIMEDOUT); 257212420Sken } 258212420Sken 259212420Sken page_req->ioc_status = htole16(params.status); 260212420Sken if ((page_req->ioc_status & MPI2_IOCSTATUS_MASK) == 261212420Sken MPI2_IOCSTATUS_SUCCESS) { 262212420Sken bcopy(hdr, &page_req->header, sizeof(page_req->header)); 263212420Sken } 264212420Sken 265212420Sken return (0); 266212420Sken} 267212420Sken 268212420Skenstatic int 269212420Skenmps_user_read_cfg_page(struct mps_softc *sc, struct mps_cfg_page_req *page_req, 270212420Sken void *buf) 271212420Sken{ 272212420Sken MPI2_CONFIG_PAGE_HEADER *reqhdr, *hdr; 273212420Sken struct mps_config_params params; 274212420Sken int error; 275212420Sken 276212420Sken reqhdr = buf; 277212420Sken hdr = ¶ms.hdr.Struct; 278212420Sken hdr->PageVersion = reqhdr->PageVersion; 279212420Sken hdr->PageLength = reqhdr->PageLength; 280212420Sken hdr->PageNumber = reqhdr->PageNumber; 281212420Sken hdr->PageType = reqhdr->PageType & MPI2_CONFIG_PAGETYPE_MASK; 282212420Sken params.action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; 283212420Sken params.page_address = le32toh(page_req->page_address); 284212420Sken params.buffer = buf; 285212420Sken params.length = le32toh(page_req->len); 286212420Sken params.callback = NULL; 287212420Sken 288212420Sken if ((error = mps_read_config_page(sc, ¶ms)) != 0) { 289212420Sken mps_printf(sc, "mps_user_read_cfg_page timed out\n"); 290212420Sken return (ETIMEDOUT); 291212420Sken } 292212420Sken 293212420Sken page_req->ioc_status = htole16(params.status); 294212420Sken return (0); 295212420Sken} 296212420Sken 297212420Skenstatic int 298212420Skenmps_user_read_extcfg_header(struct mps_softc *sc, 299212420Sken struct mps_ext_cfg_page_req *ext_page_req) 300212420Sken{ 301212420Sken MPI2_CONFIG_EXTENDED_PAGE_HEADER *hdr; 302212420Sken struct mps_config_params params; 303212420Sken int error; 304212420Sken 305212420Sken hdr = ¶ms.hdr.Ext; 306212420Sken params.action = MPI2_CONFIG_ACTION_PAGE_HEADER; 307212420Sken hdr->PageVersion = ext_page_req->header.PageVersion; 308251670Sasomers hdr->PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; 309212420Sken hdr->ExtPageLength = 0; 310212420Sken hdr->PageNumber = ext_page_req->header.PageNumber; 311212420Sken hdr->ExtPageType = ext_page_req->header.ExtPageType; 312212420Sken params.page_address = le32toh(ext_page_req->page_address); 313212420Sken if ((error = mps_read_config_page(sc, ¶ms)) != 0) { 314212420Sken /* 315212420Sken * Leave the request. Without resetting the chip, it's 316212420Sken * still owned by it and we'll just get into trouble 317212420Sken * freeing it now. Mark it as abandoned so that if it 318212420Sken * shows up later it can be freed. 319212420Sken */ 320212420Sken mps_printf(sc, "mps_user_read_extcfg_header timed out\n"); 321212420Sken return (ETIMEDOUT); 322212420Sken } 323212420Sken 324212420Sken ext_page_req->ioc_status = htole16(params.status); 325212420Sken if ((ext_page_req->ioc_status & MPI2_IOCSTATUS_MASK) == 326212420Sken MPI2_IOCSTATUS_SUCCESS) { 327212420Sken ext_page_req->header.PageVersion = hdr->PageVersion; 328212420Sken ext_page_req->header.PageNumber = hdr->PageNumber; 329212420Sken ext_page_req->header.PageType = hdr->PageType; 330212420Sken ext_page_req->header.ExtPageLength = hdr->ExtPageLength; 331212420Sken ext_page_req->header.ExtPageType = hdr->ExtPageType; 332212420Sken } 333212420Sken 334212420Sken return (0); 335212420Sken} 336212420Sken 337212420Skenstatic int 338212420Skenmps_user_read_extcfg_page(struct mps_softc *sc, 339212420Sken struct mps_ext_cfg_page_req *ext_page_req, void *buf) 340212420Sken{ 341212420Sken MPI2_CONFIG_EXTENDED_PAGE_HEADER *reqhdr, *hdr; 342212420Sken struct mps_config_params params; 343212420Sken int error; 344212420Sken 345212420Sken reqhdr = buf; 346212420Sken hdr = ¶ms.hdr.Ext; 347212420Sken params.action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; 348212420Sken params.page_address = le32toh(ext_page_req->page_address); 349212420Sken hdr->PageVersion = reqhdr->PageVersion; 350251670Sasomers hdr->PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; 351212420Sken hdr->PageNumber = reqhdr->PageNumber; 352212420Sken hdr->ExtPageType = reqhdr->ExtPageType; 353212420Sken hdr->ExtPageLength = reqhdr->ExtPageLength; 354212420Sken params.buffer = buf; 355212420Sken params.length = le32toh(ext_page_req->len); 356212420Sken params.callback = NULL; 357212420Sken 358212420Sken if ((error = mps_read_config_page(sc, ¶ms)) != 0) { 359212420Sken mps_printf(sc, "mps_user_read_extcfg_page timed out\n"); 360212420Sken return (ETIMEDOUT); 361212420Sken } 362212420Sken 363212420Sken ext_page_req->ioc_status = htole16(params.status); 364212420Sken return (0); 365212420Sken} 366212420Sken 367212420Skenstatic int 368212420Skenmps_user_write_cfg_page(struct mps_softc *sc, 369212420Sken struct mps_cfg_page_req *page_req, void *buf) 370212420Sken{ 371212420Sken MPI2_CONFIG_PAGE_HEADER *reqhdr, *hdr; 372212420Sken struct mps_config_params params; 373212420Sken u_int hdr_attr; 374212420Sken int error; 375212420Sken 376212420Sken reqhdr = buf; 377212420Sken hdr = ¶ms.hdr.Struct; 378212420Sken hdr_attr = reqhdr->PageType & MPI2_CONFIG_PAGEATTR_MASK; 379212420Sken if (hdr_attr != MPI2_CONFIG_PAGEATTR_CHANGEABLE && 380212420Sken hdr_attr != MPI2_CONFIG_PAGEATTR_PERSISTENT) { 381212420Sken mps_printf(sc, "page type 0x%x not changeable\n", 382212420Sken reqhdr->PageType & MPI2_CONFIG_PAGETYPE_MASK); 383212420Sken return (EINVAL); 384212420Sken } 385212420Sken 386212420Sken /* 387212420Sken * There isn't any point in restoring stripped out attributes 388212420Sken * if you then mask them going down to issue the request. 389212420Sken */ 390212420Sken 391212420Sken hdr->PageVersion = reqhdr->PageVersion; 392212420Sken hdr->PageLength = reqhdr->PageLength; 393212420Sken hdr->PageNumber = reqhdr->PageNumber; 394212420Sken hdr->PageType = reqhdr->PageType; 395212420Sken params.action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT; 396212420Sken params.page_address = le32toh(page_req->page_address); 397212420Sken params.buffer = buf; 398212420Sken params.length = le32toh(page_req->len); 399212420Sken params.callback = NULL; 400212420Sken 401212420Sken if ((error = mps_write_config_page(sc, ¶ms)) != 0) { 402212420Sken mps_printf(sc, "mps_write_cfg_page timed out\n"); 403212420Sken return (ETIMEDOUT); 404212420Sken } 405212420Sken 406212420Sken page_req->ioc_status = htole16(params.status); 407212420Sken return (0); 408212420Sken} 409212420Sken 410216088Skenvoid 411213839Smdfmpi_init_sge(struct mps_command *cm, void *req, void *sge) 412213839Smdf{ 413213839Smdf int off, space; 414213839Smdf 415213839Smdf space = (int)cm->cm_sc->facts->IOCRequestFrameSize * 4; 416213839Smdf off = (uintptr_t)sge - (uintptr_t)req; 417213839Smdf 418213839Smdf KASSERT(off < space, ("bad pointers %p %p, off %d, space %d", 419213839Smdf req, sge, off, space)); 420213839Smdf 421213839Smdf cm->cm_sge = sge; 422213839Smdf cm->cm_sglsize = space - off; 423213839Smdf} 424213839Smdf 425213708Smdf/* 426213708Smdf * Prepare the mps_command for an IOC_FACTS request. 427213708Smdf */ 428213708Smdfstatic int 429213708Smdfmpi_pre_ioc_facts(struct mps_command *cm, struct mps_usr_command *cmd) 430213708Smdf{ 431213708Smdf MPI2_IOC_FACTS_REQUEST *req = (void *)cm->cm_req; 432213708Smdf MPI2_IOC_FACTS_REPLY *rpl; 433213708Smdf 434213708Smdf if (cmd->req_len != sizeof *req) 435213708Smdf return (EINVAL); 436213708Smdf if (cmd->rpl_len != sizeof *rpl) 437213708Smdf return (EINVAL); 438213708Smdf 439213708Smdf cm->cm_sge = NULL; 440213708Smdf cm->cm_sglsize = 0; 441213708Smdf return (0); 442213708Smdf} 443213708Smdf 444213708Smdf/* 445213708Smdf * Prepare the mps_command for a PORT_FACTS request. 446213708Smdf */ 447213708Smdfstatic int 448213708Smdfmpi_pre_port_facts(struct mps_command *cm, struct mps_usr_command *cmd) 449213708Smdf{ 450213708Smdf MPI2_PORT_FACTS_REQUEST *req = (void *)cm->cm_req; 451213708Smdf MPI2_PORT_FACTS_REPLY *rpl; 452213708Smdf 453213708Smdf if (cmd->req_len != sizeof *req) 454213708Smdf return (EINVAL); 455213708Smdf if (cmd->rpl_len != sizeof *rpl) 456213708Smdf return (EINVAL); 457213708Smdf 458213708Smdf cm->cm_sge = NULL; 459213708Smdf cm->cm_sglsize = 0; 460213708Smdf return (0); 461213708Smdf} 462213708Smdf 463213708Smdf/* 464213708Smdf * Prepare the mps_command for a FW_DOWNLOAD request. 465213708Smdf */ 466213708Smdfstatic int 467213708Smdfmpi_pre_fw_download(struct mps_command *cm, struct mps_usr_command *cmd) 468213708Smdf{ 469213708Smdf MPI2_FW_DOWNLOAD_REQUEST *req = (void *)cm->cm_req; 470213708Smdf MPI2_FW_DOWNLOAD_REPLY *rpl; 471213840Smdf MPI2_FW_DOWNLOAD_TCSGE tc; 472213840Smdf int error; 473213708Smdf 474213840Smdf /* 475213840Smdf * This code assumes there is room in the request's SGL for 476213840Smdf * the TransactionContext plus at least a SGL chain element. 477213840Smdf */ 478213840Smdf CTASSERT(sizeof req->SGL >= sizeof tc + MPS_SGC_SIZE); 479213840Smdf 480213708Smdf if (cmd->req_len != sizeof *req) 481213708Smdf return (EINVAL); 482213708Smdf if (cmd->rpl_len != sizeof *rpl) 483213708Smdf return (EINVAL); 484213708Smdf 485213840Smdf if (cmd->len == 0) 486213840Smdf return (EINVAL); 487213840Smdf 488213840Smdf error = copyin(cmd->buf, cm->cm_data, cmd->len); 489213840Smdf if (error != 0) 490213840Smdf return (error); 491213840Smdf 492213839Smdf mpi_init_sge(cm, req, &req->SGL); 493213840Smdf bzero(&tc, sizeof tc); 494213840Smdf 495213840Smdf /* 496213840Smdf * For now, the F/W image must be provided in a single request. 497213840Smdf */ 498213840Smdf if ((req->MsgFlags & MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT) == 0) 499213840Smdf return (EINVAL); 500213840Smdf if (req->TotalImageSize != cmd->len) 501213840Smdf return (EINVAL); 502213840Smdf 503213840Smdf /* 504213840Smdf * The value of the first two elements is specified in the 505213840Smdf * Fusion-MPT Message Passing Interface document. 506213840Smdf */ 507213840Smdf tc.ContextSize = 0; 508213840Smdf tc.DetailsLength = 12; 509213840Smdf tc.ImageOffset = 0; 510213840Smdf tc.ImageSize = cmd->len; 511213840Smdf 512213840Smdf cm->cm_flags |= MPS_CM_FLAGS_DATAOUT; 513213840Smdf 514213840Smdf return (mps_push_sge(cm, &tc, sizeof tc, 0)); 515213708Smdf} 516213708Smdf 517213708Smdf/* 518213708Smdf * Prepare the mps_command for a FW_UPLOAD request. 519213708Smdf */ 520213708Smdfstatic int 521213708Smdfmpi_pre_fw_upload(struct mps_command *cm, struct mps_usr_command *cmd) 522213708Smdf{ 523213708Smdf MPI2_FW_UPLOAD_REQUEST *req = (void *)cm->cm_req; 524213708Smdf MPI2_FW_UPLOAD_REPLY *rpl; 525213839Smdf MPI2_FW_UPLOAD_TCSGE tc; 526213708Smdf 527213708Smdf /* 528213708Smdf * This code assumes there is room in the request's SGL for 529213708Smdf * the TransactionContext plus at least a SGL chain element. 530213708Smdf */ 531213839Smdf CTASSERT(sizeof req->SGL >= sizeof tc + MPS_SGC_SIZE); 532213708Smdf 533213708Smdf if (cmd->req_len != sizeof *req) 534213708Smdf return (EINVAL); 535213708Smdf if (cmd->rpl_len != sizeof *rpl) 536213708Smdf return (EINVAL); 537213708Smdf 538213839Smdf mpi_init_sge(cm, req, &req->SGL); 539213708Smdf if (cmd->len == 0) { 540213708Smdf /* Perhaps just asking what the size of the fw is? */ 541213708Smdf return (0); 542213708Smdf } 543213708Smdf 544213839Smdf bzero(&tc, sizeof tc); 545213708Smdf 546213708Smdf /* 547213708Smdf * The value of the first two elements is specified in the 548213708Smdf * Fusion-MPT Message Passing Interface document. 549213708Smdf */ 550213839Smdf tc.ContextSize = 0; 551213839Smdf tc.DetailsLength = 12; 552213708Smdf /* 553213708Smdf * XXX Is there any reason to fetch a partial image? I.e. to 554213708Smdf * set ImageOffset to something other than 0? 555213708Smdf */ 556213839Smdf tc.ImageOffset = 0; 557213839Smdf tc.ImageSize = cmd->len; 558213708Smdf 559213839Smdf return (mps_push_sge(cm, &tc, sizeof tc, 0)); 560213708Smdf} 561213708Smdf 562213708Smdf/* 563213708Smdf * Prepare the mps_command for a SATA_PASSTHROUGH request. 564213708Smdf */ 565213708Smdfstatic int 566213708Smdfmpi_pre_sata_passthrough(struct mps_command *cm, struct mps_usr_command *cmd) 567213708Smdf{ 568213708Smdf MPI2_SATA_PASSTHROUGH_REQUEST *req = (void *)cm->cm_req; 569213708Smdf MPI2_SATA_PASSTHROUGH_REPLY *rpl; 570213708Smdf 571213708Smdf if (cmd->req_len != sizeof *req) 572213708Smdf return (EINVAL); 573213708Smdf if (cmd->rpl_len != sizeof *rpl) 574213708Smdf return (EINVAL); 575213708Smdf 576213839Smdf mpi_init_sge(cm, req, &req->SGL); 577213708Smdf return (0); 578213708Smdf} 579213708Smdf 580213708Smdf/* 581213708Smdf * Prepare the mps_command for a SMP_PASSTHROUGH request. 582213708Smdf */ 583213708Smdfstatic int 584213708Smdfmpi_pre_smp_passthrough(struct mps_command *cm, struct mps_usr_command *cmd) 585213708Smdf{ 586213708Smdf MPI2_SMP_PASSTHROUGH_REQUEST *req = (void *)cm->cm_req; 587213708Smdf MPI2_SMP_PASSTHROUGH_REPLY *rpl; 588213708Smdf 589213708Smdf if (cmd->req_len != sizeof *req) 590213708Smdf return (EINVAL); 591213708Smdf if (cmd->rpl_len != sizeof *rpl) 592213708Smdf return (EINVAL); 593213708Smdf 594213839Smdf mpi_init_sge(cm, req, &req->SGL); 595213708Smdf return (0); 596213708Smdf} 597213708Smdf 598213708Smdf/* 599213708Smdf * Prepare the mps_command for a CONFIG request. 600213708Smdf */ 601213708Smdfstatic int 602213708Smdfmpi_pre_config(struct mps_command *cm, struct mps_usr_command *cmd) 603213708Smdf{ 604213708Smdf MPI2_CONFIG_REQUEST *req = (void *)cm->cm_req; 605213708Smdf MPI2_CONFIG_REPLY *rpl; 606213708Smdf 607213708Smdf if (cmd->req_len != sizeof *req) 608213708Smdf return (EINVAL); 609213708Smdf if (cmd->rpl_len != sizeof *rpl) 610213708Smdf return (EINVAL); 611213708Smdf 612213839Smdf mpi_init_sge(cm, req, &req->PageBufferSGE); 613213708Smdf return (0); 614213708Smdf} 615213708Smdf 616213708Smdf/* 617213708Smdf * Prepare the mps_command for a SAS_IO_UNIT_CONTROL request. 618213708Smdf */ 619213708Smdfstatic int 620213708Smdfmpi_pre_sas_io_unit_control(struct mps_command *cm, 621213708Smdf struct mps_usr_command *cmd) 622213708Smdf{ 623213708Smdf 624213708Smdf cm->cm_sge = NULL; 625213708Smdf cm->cm_sglsize = 0; 626213708Smdf return (0); 627213708Smdf} 628213708Smdf 629213708Smdf/* 630213708Smdf * A set of functions to prepare an mps_command for the various 631213708Smdf * supported requests. 632213708Smdf */ 633212420Skenstruct mps_user_func { 634213708Smdf U8 Function; 635213708Smdf mps_user_f *f_pre; 636212420Sken} mps_user_func_list[] = { 637213708Smdf { MPI2_FUNCTION_IOC_FACTS, mpi_pre_ioc_facts }, 638213708Smdf { MPI2_FUNCTION_PORT_FACTS, mpi_pre_port_facts }, 639213708Smdf { MPI2_FUNCTION_FW_DOWNLOAD, mpi_pre_fw_download }, 640213708Smdf { MPI2_FUNCTION_FW_UPLOAD, mpi_pre_fw_upload }, 641213708Smdf { MPI2_FUNCTION_SATA_PASSTHROUGH, mpi_pre_sata_passthrough }, 642213708Smdf { MPI2_FUNCTION_SMP_PASSTHROUGH, mpi_pre_smp_passthrough}, 643213708Smdf { MPI2_FUNCTION_CONFIG, mpi_pre_config}, 644213708Smdf { MPI2_FUNCTION_SAS_IO_UNIT_CONTROL, mpi_pre_sas_io_unit_control }, 645213708Smdf { 0xFF, NULL } /* list end */ 646213708Smdf}; 647212420Sken 648212420Skenstatic int 649213708Smdfmps_user_setup_request(struct mps_command *cm, struct mps_usr_command *cmd) 650212420Sken{ 651213708Smdf MPI2_REQUEST_HEADER *hdr = (MPI2_REQUEST_HEADER *)cm->cm_req; 652213708Smdf struct mps_user_func *f; 653212420Sken 654213708Smdf for (f = mps_user_func_list; f->f_pre != NULL; f++) { 655213708Smdf if (hdr->Function == f->Function) 656213708Smdf return (f->f_pre(cm, cmd)); 657213708Smdf } 658213708Smdf return (EINVAL); 659212420Sken} 660212420Sken 661212420Skenstatic int 662212420Skenmps_user_command(struct mps_softc *sc, struct mps_usr_command *cmd) 663212420Sken{ 664212420Sken MPI2_REQUEST_HEADER *hdr; 665212420Sken MPI2_DEFAULT_REPLY *rpl; 666213704Smdf void *buf = NULL; 667213882Smdf struct mps_command *cm = NULL; 668212420Sken int err = 0; 669212420Sken int sz; 670212420Sken 671212420Sken mps_lock(sc); 672212420Sken cm = mps_alloc_command(sc); 673212420Sken 674212420Sken if (cm == NULL) { 675254938Sken mps_printf(sc, "%s: no mps requests\n", __func__); 676212420Sken err = ENOMEM; 677212420Sken goto Ret; 678212420Sken } 679212420Sken mps_unlock(sc); 680212420Sken 681212420Sken hdr = (MPI2_REQUEST_HEADER *)cm->cm_req; 682212420Sken 683254938Sken mps_dprint(sc, MPS_USER, "%s: req %p %d rpl %p %d\n", __func__, 684254938Sken cmd->req, cmd->req_len, cmd->rpl, cmd->rpl_len); 685212420Sken 686213704Smdf if (cmd->req_len > (int)sc->facts->IOCRequestFrameSize * 4) { 687213704Smdf err = EINVAL; 688213704Smdf goto RetFreeUnlocked; 689213704Smdf } 690213704Smdf err = copyin(cmd->req, hdr, cmd->req_len); 691213704Smdf if (err != 0) 692213704Smdf goto RetFreeUnlocked; 693212420Sken 694254938Sken mps_dprint(sc, MPS_USER, "%s: Function %02X MsgFlags %02X\n", __func__, 695254938Sken hdr->Function, hdr->MsgFlags); 696212420Sken 697213708Smdf err = mps_user_setup_request(cm, cmd); 698212420Sken if (err != 0) { 699212420Sken mps_printf(sc, "mps_user_command: unsupported function 0x%X\n", 700212420Sken hdr->Function ); 701213704Smdf goto RetFreeUnlocked; 702212420Sken } 703212420Sken 704212420Sken if (cmd->len > 0) { 705212420Sken buf = malloc(cmd->len, M_MPSUSER, M_WAITOK|M_ZERO); 706237876Sken if(!buf) { 707237876Sken mps_printf(sc, "Cannot allocate memory %s %d\n", 708237876Sken __func__, __LINE__); 709237876Sken return (ENOMEM); 710237876Sken } 711212420Sken cm->cm_data = buf; 712212420Sken cm->cm_length = cmd->len; 713212420Sken } else { 714212420Sken cm->cm_data = NULL; 715212420Sken cm->cm_length = 0; 716212420Sken } 717212420Sken 718230920Sken cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE; 719212420Sken cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 720212420Sken 721254938Sken err = mps_user_setup_request(cm, cmd); 722254938Sken if (err == EINVAL) { 723254938Sken mps_printf(sc, "%s: unsupported parameter or unsupported " 724254938Sken "function in request (function = 0x%X)\n", __func__, 725254938Sken hdr->Function); 726254938Sken } 727254938Sken if (err != 0) 728254938Sken goto RetFreeUnlocked; 729254938Sken 730212420Sken mps_lock(sc); 731254938Sken err = mps_wait_command(sc, cm, 60, CAN_SLEEP); 732212420Sken 733230920Sken if (err) { 734213882Smdf mps_printf(sc, "%s: invalid request: error %d\n", 735213882Smdf __func__, err); 736212420Sken goto Ret; 737212420Sken } 738212420Sken 739212420Sken rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply; 740212420Sken sz = rpl->MsgLength * 4; 741212420Sken 742212420Sken if (sz > cmd->rpl_len) { 743254938Sken mps_printf(sc, "%s: user reply buffer (%d) smaller than " 744254938Sken "returned buffer (%d)\n", __func__, cmd->rpl_len, sz); 745212420Sken sz = cmd->rpl_len; 746212420Sken } 747212420Sken 748212420Sken mps_unlock(sc); 749212420Sken copyout(rpl, cmd->rpl, sz); 750213704Smdf if (buf != NULL) 751212420Sken copyout(buf, cmd->buf, cmd->len); 752254938Sken mps_dprint(sc, MPS_USER, "%s: reply size %d\n", __func__, sz); 753212420Sken 754213704SmdfRetFreeUnlocked: 755213704Smdf mps_lock(sc); 756213882Smdf if (cm != NULL) 757213882Smdf mps_free_command(sc, cm); 758213882SmdfRet: 759213704Smdf mps_unlock(sc); 760213704Smdf if (buf != NULL) 761213704Smdf free(buf, M_MPSUSER); 762213704Smdf return (err); 763230920Sken} 764212420Sken 765212420Skenstatic int 766230920Skenmps_user_pass_thru(struct mps_softc *sc, mps_pass_thru_t *data) 767230920Sken{ 768230920Sken MPI2_REQUEST_HEADER *hdr, tmphdr; 769230920Sken MPI2_DEFAULT_REPLY *rpl; 770230920Sken struct mps_command *cm = NULL; 771230920Sken int err = 0, dir = 0, sz; 772230920Sken uint8_t function = 0; 773230920Sken u_int sense_len; 774230920Sken 775230920Sken /* 776230920Sken * Only allow one passthru command at a time. Use the MPS_FLAGS_BUSY 777230920Sken * bit to denote that a passthru is being processed. 778230920Sken */ 779230920Sken mps_lock(sc); 780230920Sken if (sc->mps_flags & MPS_FLAGS_BUSY) { 781254938Sken mps_dprint(sc, MPS_USER, "%s: Only one passthru command " 782230920Sken "allowed at a single time.", __func__); 783230920Sken mps_unlock(sc); 784230920Sken return (EBUSY); 785230920Sken } 786230920Sken sc->mps_flags |= MPS_FLAGS_BUSY; 787230920Sken mps_unlock(sc); 788230920Sken 789230920Sken /* 790230920Sken * Do some validation on data direction. Valid cases are: 791230920Sken * 1) DataSize is 0 and direction is NONE 792230920Sken * 2) DataSize is non-zero and one of: 793230920Sken * a) direction is READ or 794230920Sken * b) direction is WRITE or 795230920Sken * c) direction is BOTH and DataOutSize is non-zero 796230920Sken * If valid and the direction is BOTH, change the direction to READ. 797230920Sken * if valid and the direction is not BOTH, make sure DataOutSize is 0. 798230920Sken */ 799230920Sken if (((data->DataSize == 0) && 800230920Sken (data->DataDirection == MPS_PASS_THRU_DIRECTION_NONE)) || 801230920Sken ((data->DataSize != 0) && 802230920Sken ((data->DataDirection == MPS_PASS_THRU_DIRECTION_READ) || 803230920Sken (data->DataDirection == MPS_PASS_THRU_DIRECTION_WRITE) || 804230920Sken ((data->DataDirection == MPS_PASS_THRU_DIRECTION_BOTH) && 805230920Sken (data->DataOutSize != 0))))) { 806230920Sken if (data->DataDirection == MPS_PASS_THRU_DIRECTION_BOTH) 807230920Sken data->DataDirection = MPS_PASS_THRU_DIRECTION_READ; 808230920Sken else 809230920Sken data->DataOutSize = 0; 810230920Sken } else 811230920Sken return (EINVAL); 812230920Sken 813254938Sken mps_dprint(sc, MPS_USER, "%s: req 0x%jx %d rpl 0x%jx %d " 814230920Sken "data in 0x%jx %d data out 0x%jx %d data dir %d\n", __func__, 815230920Sken data->PtrRequest, data->RequestSize, data->PtrReply, 816230920Sken data->ReplySize, data->PtrData, data->DataSize, 817230920Sken data->PtrDataOut, data->DataOutSize, data->DataDirection); 818230920Sken 819230920Sken /* 820230920Sken * copy in the header so we know what we're dealing with before we 821230920Sken * commit to allocating a command for it. 822230920Sken */ 823230920Sken err = copyin(PTRIN(data->PtrRequest), &tmphdr, data->RequestSize); 824230920Sken if (err != 0) 825230920Sken goto RetFreeUnlocked; 826230920Sken 827230920Sken if (data->RequestSize > (int)sc->facts->IOCRequestFrameSize * 4) { 828230920Sken err = EINVAL; 829230920Sken goto RetFreeUnlocked; 830230920Sken } 831230920Sken 832230920Sken function = tmphdr.Function; 833254938Sken mps_dprint(sc, MPS_USER, "%s: Function %02X MsgFlags %02X\n", __func__, 834230920Sken function, tmphdr.MsgFlags); 835230920Sken 836230920Sken /* 837230920Sken * Handle a passthru TM request. 838230920Sken */ 839230920Sken if (function == MPI2_FUNCTION_SCSI_TASK_MGMT) { 840230920Sken MPI2_SCSI_TASK_MANAGE_REQUEST *task; 841230920Sken 842230920Sken mps_lock(sc); 843230920Sken cm = mpssas_alloc_tm(sc); 844230920Sken if (cm == NULL) { 845230920Sken err = EINVAL; 846230920Sken goto Ret; 847230920Sken } 848230920Sken 849230920Sken /* Copy the header in. Only a small fixup is needed. */ 850230920Sken task = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req; 851230920Sken bcopy(&tmphdr, task, data->RequestSize); 852230920Sken task->TaskMID = cm->cm_desc.Default.SMID; 853230920Sken 854230920Sken cm->cm_data = NULL; 855230920Sken cm->cm_desc.HighPriority.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; 856230920Sken cm->cm_complete = NULL; 857230920Sken cm->cm_complete_data = NULL; 858230920Sken 859254938Sken err = mps_wait_command(sc, cm, 30, CAN_SLEEP); 860230920Sken 861230920Sken if (err != 0) { 862230920Sken err = EIO; 863230920Sken mps_dprint(sc, MPS_FAULT, "%s: task management failed", 864230920Sken __func__); 865230920Sken } 866230920Sken /* 867230920Sken * Copy the reply data and sense data to user space. 868230920Sken */ 869230920Sken if (cm->cm_reply != NULL) { 870230920Sken rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply; 871230920Sken sz = rpl->MsgLength * 4; 872230920Sken 873230920Sken if (sz > data->ReplySize) { 874254938Sken mps_printf(sc, "%s: user reply buffer (%d) " 875254938Sken "smaller than returned buffer (%d)\n", 876254938Sken __func__, data->ReplySize, sz); 877230920Sken } 878254938Sken mps_unlock(sc); 879254938Sken copyout(cm->cm_reply, PTRIN(data->PtrReply), 880254938Sken data->ReplySize); 881254938Sken mps_lock(sc); 882230920Sken } 883230920Sken mpssas_free_tm(sc, cm); 884230920Sken goto Ret; 885230920Sken } 886230920Sken 887230920Sken mps_lock(sc); 888230920Sken cm = mps_alloc_command(sc); 889230920Sken 890230920Sken if (cm == NULL) { 891230920Sken mps_printf(sc, "%s: no mps requests\n", __func__); 892230920Sken err = ENOMEM; 893230920Sken goto Ret; 894230920Sken } 895230920Sken mps_unlock(sc); 896230920Sken 897230920Sken hdr = (MPI2_REQUEST_HEADER *)cm->cm_req; 898230920Sken bcopy(&tmphdr, hdr, data->RequestSize); 899230920Sken 900230920Sken /* 901230920Sken * Do some checking to make sure the IOCTL request contains a valid 902230920Sken * request. Then set the SGL info. 903230920Sken */ 904230920Sken mpi_init_sge(cm, hdr, (void *)((uint8_t *)hdr + data->RequestSize)); 905230920Sken 906230920Sken /* 907230920Sken * Set up for read, write or both. From check above, DataOutSize will 908230920Sken * be 0 if direction is READ or WRITE, but it will have some non-zero 909230920Sken * value if the direction is BOTH. So, just use the biggest size to get 910230920Sken * the cm_data buffer size. If direction is BOTH, 2 SGLs need to be set 911230920Sken * up; the first is for the request and the second will contain the 912230920Sken * response data. cm_out_len needs to be set here and this will be used 913230920Sken * when the SGLs are set up. 914230920Sken */ 915230920Sken cm->cm_data = NULL; 916230920Sken cm->cm_length = MAX(data->DataSize, data->DataOutSize); 917230920Sken cm->cm_out_len = data->DataOutSize; 918230920Sken cm->cm_flags = 0; 919230920Sken if (cm->cm_length != 0) { 920230920Sken cm->cm_data = malloc(cm->cm_length, M_MPSUSER, M_WAITOK | 921230920Sken M_ZERO); 922230920Sken if (cm->cm_data == NULL) { 923230920Sken mps_dprint(sc, MPS_FAULT, "%s: alloc failed for IOCTL " 924230920Sken "passthru length %d\n", __func__, cm->cm_length); 925230920Sken } else { 926230920Sken cm->cm_flags = MPS_CM_FLAGS_DATAIN; 927230920Sken if (data->DataOutSize) { 928230920Sken cm->cm_flags |= MPS_CM_FLAGS_DATAOUT; 929230920Sken err = copyin(PTRIN(data->PtrDataOut), 930230920Sken cm->cm_data, data->DataOutSize); 931230920Sken } else if (data->DataDirection == 932230920Sken MPS_PASS_THRU_DIRECTION_WRITE) { 933230920Sken cm->cm_flags = MPS_CM_FLAGS_DATAOUT; 934230920Sken err = copyin(PTRIN(data->PtrData), 935230920Sken cm->cm_data, data->DataSize); 936230920Sken } 937230920Sken if (err != 0) 938230920Sken mps_dprint(sc, MPS_FAULT, "%s: failed to copy " 939230920Sken "IOCTL data from user space\n", __func__); 940230920Sken } 941230920Sken } 942230920Sken cm->cm_flags |= MPS_CM_FLAGS_SGE_SIMPLE; 943230920Sken cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 944230920Sken 945230920Sken /* 946230920Sken * Set up Sense buffer and SGL offset for IO passthru. SCSI IO request 947230920Sken * uses SCSI IO descriptor. 948230920Sken */ 949230920Sken if ((function == MPI2_FUNCTION_SCSI_IO_REQUEST) || 950230920Sken (function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { 951230920Sken MPI2_SCSI_IO_REQUEST *scsi_io_req; 952230920Sken 953230920Sken scsi_io_req = (MPI2_SCSI_IO_REQUEST *)hdr; 954230920Sken /* 955230920Sken * Put SGE for data and data_out buffer at the end of 956230920Sken * scsi_io_request message header (64 bytes in total). 957230920Sken * Following above SGEs, the residual space will be used by 958230920Sken * sense data. 959230920Sken */ 960230920Sken scsi_io_req->SenseBufferLength = (uint8_t)(data->RequestSize - 961230920Sken 64); 962237876Sken scsi_io_req->SenseBufferLowAddress = htole32(cm->cm_sense_busaddr); 963230920Sken 964230920Sken /* 965230920Sken * Set SGLOffset0 value. This is the number of dwords that SGL 966230920Sken * is offset from the beginning of MPI2_SCSI_IO_REQUEST struct. 967230920Sken */ 968230920Sken scsi_io_req->SGLOffset0 = 24; 969230920Sken 970230920Sken /* 971230920Sken * Setup descriptor info. RAID passthrough must use the 972230920Sken * default request descriptor which is already set, so if this 973230920Sken * is a SCSI IO request, change the descriptor to SCSI IO. 974230920Sken * Also, if this is a SCSI IO request, handle the reply in the 975230920Sken * mpssas_scsio_complete function. 976230920Sken */ 977230920Sken if (function == MPI2_FUNCTION_SCSI_IO_REQUEST) { 978230920Sken cm->cm_desc.SCSIIO.RequestFlags = 979230920Sken MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; 980230920Sken cm->cm_desc.SCSIIO.DevHandle = scsi_io_req->DevHandle; 981230920Sken 982230920Sken /* 983230920Sken * Make sure the DevHandle is not 0 because this is a 984230920Sken * likely error. 985230920Sken */ 986230920Sken if (scsi_io_req->DevHandle == 0) { 987230920Sken err = EINVAL; 988230920Sken goto RetFreeUnlocked; 989230920Sken } 990230920Sken } 991230920Sken } 992230920Sken 993230920Sken mps_lock(sc); 994230920Sken 995254938Sken err = mps_wait_command(sc, cm, 30, CAN_SLEEP); 996230920Sken 997230920Sken if (err) { 998230920Sken mps_printf(sc, "%s: invalid request: error %d\n", __func__, 999230920Sken err); 1000230920Sken mps_unlock(sc); 1001230920Sken goto RetFreeUnlocked; 1002230920Sken } 1003230920Sken 1004230920Sken /* 1005230920Sken * Sync the DMA data, if any. Then copy the data to user space. 1006230920Sken */ 1007230920Sken if (cm->cm_data != NULL) { 1008230920Sken if (cm->cm_flags & MPS_CM_FLAGS_DATAIN) 1009230920Sken dir = BUS_DMASYNC_POSTREAD; 1010230920Sken else if (cm->cm_flags & MPS_CM_FLAGS_DATAOUT) 1011242544Seadler dir = BUS_DMASYNC_POSTWRITE; 1012230920Sken bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir); 1013230920Sken bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap); 1014230920Sken 1015230920Sken if (cm->cm_flags & MPS_CM_FLAGS_DATAIN) { 1016230920Sken mps_unlock(sc); 1017230920Sken err = copyout(cm->cm_data, 1018230920Sken PTRIN(data->PtrData), data->DataSize); 1019230920Sken mps_lock(sc); 1020230920Sken if (err != 0) 1021230920Sken mps_dprint(sc, MPS_FAULT, "%s: failed to copy " 1022230920Sken "IOCTL data to user space\n", __func__); 1023230920Sken } 1024230920Sken } 1025230920Sken 1026230920Sken /* 1027230920Sken * Copy the reply data and sense data to user space. 1028230920Sken */ 1029230920Sken if (cm->cm_reply != NULL) { 1030230920Sken rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply; 1031230920Sken sz = rpl->MsgLength * 4; 1032230920Sken 1033230920Sken if (sz > data->ReplySize) { 1034254938Sken mps_printf(sc, "%s: user reply buffer (%d) smaller " 1035254938Sken "than returned buffer (%d)\n", __func__, 1036254938Sken data->ReplySize, sz); 1037230920Sken } 1038254938Sken mps_unlock(sc); 1039254938Sken copyout(cm->cm_reply, PTRIN(data->PtrReply), data->ReplySize); 1040254938Sken mps_lock(sc); 1041230920Sken 1042230920Sken if ((function == MPI2_FUNCTION_SCSI_IO_REQUEST) || 1043230920Sken (function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { 1044230920Sken if (((MPI2_SCSI_IO_REPLY *)rpl)->SCSIState & 1045230920Sken MPI2_SCSI_STATE_AUTOSENSE_VALID) { 1046230920Sken sense_len = 1047237876Sken MIN((le32toh(((MPI2_SCSI_IO_REPLY *)rpl)->SenseCount)), 1048230920Sken sizeof(struct scsi_sense_data)); 1049230920Sken mps_unlock(sc); 1050230920Sken copyout(cm->cm_sense, cm->cm_req + 64, sense_len); 1051230920Sken mps_lock(sc); 1052230920Sken } 1053230920Sken } 1054230920Sken } 1055230920Sken mps_unlock(sc); 1056230920Sken 1057230920SkenRetFreeUnlocked: 1058230920Sken mps_lock(sc); 1059230920Sken 1060230920Sken if (cm != NULL) { 1061230920Sken if (cm->cm_data) 1062230920Sken free(cm->cm_data, M_MPSUSER); 1063230920Sken mps_free_command(sc, cm); 1064230920Sken } 1065230920SkenRet: 1066230920Sken sc->mps_flags &= ~MPS_FLAGS_BUSY; 1067230920Sken mps_unlock(sc); 1068230920Sken 1069230920Sken return (err); 1070230920Sken} 1071230920Sken 1072230920Skenstatic void 1073230920Skenmps_user_get_adapter_data(struct mps_softc *sc, mps_adapter_data_t *data) 1074230920Sken{ 1075230920Sken Mpi2ConfigReply_t mpi_reply; 1076230920Sken Mpi2BiosPage3_t config_page; 1077230920Sken 1078230920Sken /* 1079230920Sken * Use the PCI interface functions to get the Bus, Device, and Function 1080230920Sken * information. 1081230920Sken */ 1082230920Sken data->PciInformation.u.bits.BusNumber = pci_get_bus(sc->mps_dev); 1083230920Sken data->PciInformation.u.bits.DeviceNumber = pci_get_slot(sc->mps_dev); 1084230920Sken data->PciInformation.u.bits.FunctionNumber = 1085230920Sken pci_get_function(sc->mps_dev); 1086230920Sken 1087230920Sken /* 1088230920Sken * Get the FW version that should already be saved in IOC Facts. 1089230920Sken */ 1090230920Sken data->MpiFirmwareVersion = sc->facts->FWVersion.Word; 1091230920Sken 1092230920Sken /* 1093230920Sken * General device info. 1094230920Sken */ 1095230920Sken data->AdapterType = MPSIOCTL_ADAPTER_TYPE_SAS2; 1096230920Sken if (sc->mps_flags & MPS_FLAGS_WD_AVAILABLE) 1097230920Sken data->AdapterType = MPSIOCTL_ADAPTER_TYPE_SAS2_SSS6200; 1098230920Sken data->PCIDeviceHwId = pci_get_device(sc->mps_dev); 1099230920Sken data->PCIDeviceHwRev = pci_read_config(sc->mps_dev, PCIR_REVID, 1); 1100230920Sken data->SubSystemId = pci_get_subdevice(sc->mps_dev); 1101230920Sken data->SubsystemVendorId = pci_get_subvendor(sc->mps_dev); 1102230920Sken 1103230920Sken /* 1104230920Sken * Get the driver version. 1105230920Sken */ 1106230920Sken strcpy((char *)&data->DriverVersion[0], MPS_DRIVER_VERSION); 1107230920Sken 1108230920Sken /* 1109230920Sken * Need to get BIOS Config Page 3 for the BIOS Version. 1110230920Sken */ 1111230920Sken data->BiosVersion = 0; 1112231679Sken mps_lock(sc); 1113230920Sken if (mps_config_get_bios_pg3(sc, &mpi_reply, &config_page)) 1114230920Sken printf("%s: Error while retrieving BIOS Version\n", __func__); 1115230920Sken else 1116230920Sken data->BiosVersion = config_page.BiosVersion; 1117231679Sken mps_unlock(sc); 1118230920Sken} 1119230920Sken 1120230920Skenstatic void 1121230920Skenmps_user_read_pci_info(struct mps_softc *sc, mps_pci_info_t *data) 1122230920Sken{ 1123230920Sken int i; 1124230920Sken 1125230920Sken /* 1126230920Sken * Use the PCI interface functions to get the Bus, Device, and Function 1127230920Sken * information. 1128230920Sken */ 1129230920Sken data->BusNumber = pci_get_bus(sc->mps_dev); 1130230920Sken data->DeviceNumber = pci_get_slot(sc->mps_dev); 1131230920Sken data->FunctionNumber = pci_get_function(sc->mps_dev); 1132230920Sken 1133230920Sken /* 1134230920Sken * Now get the interrupt vector and the pci header. The vector can 1135230920Sken * only be 0 right now. The header is the first 256 bytes of config 1136230920Sken * space. 1137230920Sken */ 1138230920Sken data->InterruptVector = 0; 1139230920Sken for (i = 0; i < sizeof (data->PciHeader); i++) { 1140230920Sken data->PciHeader[i] = pci_read_config(sc->mps_dev, i, 1); 1141230920Sken } 1142230920Sken} 1143230920Sken 1144230920Skenstatic uint8_t 1145230920Skenmps_get_fw_diag_buffer_number(struct mps_softc *sc, uint32_t unique_id) 1146230920Sken{ 1147230920Sken uint8_t index; 1148230920Sken 1149230920Sken for (index = 0; index < MPI2_DIAG_BUF_TYPE_COUNT; index++) { 1150230920Sken if (sc->fw_diag_buffer_list[index].unique_id == unique_id) { 1151230920Sken return (index); 1152230920Sken } 1153230920Sken } 1154230920Sken 1155230920Sken return (MPS_FW_DIAGNOSTIC_UID_NOT_FOUND); 1156230920Sken} 1157230920Sken 1158230920Skenstatic int 1159230920Skenmps_post_fw_diag_buffer(struct mps_softc *sc, 1160230920Sken mps_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code) 1161230920Sken{ 1162230920Sken MPI2_DIAG_BUFFER_POST_REQUEST *req; 1163230920Sken MPI2_DIAG_BUFFER_POST_REPLY *reply; 1164230920Sken struct mps_command *cm = NULL; 1165230920Sken int i, status; 1166230920Sken 1167230920Sken /* 1168230920Sken * If buffer is not enabled, just leave. 1169230920Sken */ 1170230920Sken *return_code = MPS_FW_DIAG_ERROR_POST_FAILED; 1171230920Sken if (!pBuffer->enabled) { 1172230920Sken return (MPS_DIAG_FAILURE); 1173230920Sken } 1174230920Sken 1175230920Sken /* 1176230920Sken * Clear some flags initially. 1177230920Sken */ 1178230920Sken pBuffer->force_release = FALSE; 1179230920Sken pBuffer->valid_data = FALSE; 1180230920Sken pBuffer->owned_by_firmware = FALSE; 1181230920Sken 1182230920Sken /* 1183230920Sken * Get a command. 1184230920Sken */ 1185230920Sken cm = mps_alloc_command(sc); 1186230920Sken if (cm == NULL) { 1187230920Sken mps_printf(sc, "%s: no mps requests\n", __func__); 1188230920Sken return (MPS_DIAG_FAILURE); 1189230920Sken } 1190230920Sken 1191230920Sken /* 1192230920Sken * Build the request for releasing the FW Diag Buffer and send it. 1193230920Sken */ 1194230920Sken req = (MPI2_DIAG_BUFFER_POST_REQUEST *)cm->cm_req; 1195230920Sken req->Function = MPI2_FUNCTION_DIAG_BUFFER_POST; 1196230920Sken req->BufferType = pBuffer->buffer_type; 1197230920Sken req->ExtendedType = pBuffer->extended_type; 1198230920Sken req->BufferLength = pBuffer->size; 1199230920Sken for (i = 0; i < (sizeof(req->ProductSpecific) / 4); i++) 1200230920Sken req->ProductSpecific[i] = pBuffer->product_specific[i]; 1201230920Sken mps_from_u64(sc->fw_diag_busaddr, &req->BufferAddress); 1202230920Sken cm->cm_data = NULL; 1203230920Sken cm->cm_length = 0; 1204230920Sken cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 1205230920Sken cm->cm_complete_data = NULL; 1206230920Sken 1207230920Sken /* 1208230920Sken * Send command synchronously. 1209230920Sken */ 1210254938Sken status = mps_wait_command(sc, cm, 30, CAN_SLEEP); 1211230920Sken if (status) { 1212230920Sken mps_printf(sc, "%s: invalid request: error %d\n", __func__, 1213230920Sken status); 1214230920Sken status = MPS_DIAG_FAILURE; 1215230920Sken goto done; 1216230920Sken } 1217230920Sken 1218230920Sken /* 1219230920Sken * Process POST reply. 1220230920Sken */ 1221230920Sken reply = (MPI2_DIAG_BUFFER_POST_REPLY *)cm->cm_reply; 1222230920Sken if (reply->IOCStatus != MPI2_IOCSTATUS_SUCCESS) { 1223230920Sken status = MPS_DIAG_FAILURE; 1224230920Sken mps_dprint(sc, MPS_FAULT, "%s: post of FW Diag Buffer failed " 1225230920Sken "with IOCStatus = 0x%x, IOCLogInfo = 0x%x and " 1226230920Sken "TransferLength = 0x%x\n", __func__, reply->IOCStatus, 1227230920Sken reply->IOCLogInfo, reply->TransferLength); 1228230920Sken goto done; 1229230920Sken } 1230230920Sken 1231230920Sken /* 1232230920Sken * Post was successful. 1233230920Sken */ 1234230920Sken pBuffer->valid_data = TRUE; 1235230920Sken pBuffer->owned_by_firmware = TRUE; 1236230920Sken *return_code = MPS_FW_DIAG_ERROR_SUCCESS; 1237230920Sken status = MPS_DIAG_SUCCESS; 1238230920Sken 1239230920Skendone: 1240230920Sken mps_free_command(sc, cm); 1241230920Sken return (status); 1242230920Sken} 1243230920Sken 1244230920Skenstatic int 1245230920Skenmps_release_fw_diag_buffer(struct mps_softc *sc, 1246230920Sken mps_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code, 1247230920Sken uint32_t diag_type) 1248230920Sken{ 1249230920Sken MPI2_DIAG_RELEASE_REQUEST *req; 1250230920Sken MPI2_DIAG_RELEASE_REPLY *reply; 1251230920Sken struct mps_command *cm = NULL; 1252230920Sken int status; 1253230920Sken 1254230920Sken /* 1255230920Sken * If buffer is not enabled, just leave. 1256230920Sken */ 1257230920Sken *return_code = MPS_FW_DIAG_ERROR_RELEASE_FAILED; 1258230920Sken if (!pBuffer->enabled) { 1259254938Sken mps_dprint(sc, MPS_USER, "%s: This buffer type is not " 1260254938Sken "supported by the IOC", __func__); 1261230920Sken return (MPS_DIAG_FAILURE); 1262230920Sken } 1263230920Sken 1264230920Sken /* 1265230920Sken * Clear some flags initially. 1266230920Sken */ 1267230920Sken pBuffer->force_release = FALSE; 1268230920Sken pBuffer->valid_data = FALSE; 1269230920Sken pBuffer->owned_by_firmware = FALSE; 1270230920Sken 1271230920Sken /* 1272230920Sken * Get a command. 1273230920Sken */ 1274230920Sken cm = mps_alloc_command(sc); 1275230920Sken if (cm == NULL) { 1276230920Sken mps_printf(sc, "%s: no mps requests\n", __func__); 1277230920Sken return (MPS_DIAG_FAILURE); 1278230920Sken } 1279230920Sken 1280230920Sken /* 1281230920Sken * Build the request for releasing the FW Diag Buffer and send it. 1282230920Sken */ 1283230920Sken req = (MPI2_DIAG_RELEASE_REQUEST *)cm->cm_req; 1284230920Sken req->Function = MPI2_FUNCTION_DIAG_RELEASE; 1285230920Sken req->BufferType = pBuffer->buffer_type; 1286230920Sken cm->cm_data = NULL; 1287230920Sken cm->cm_length = 0; 1288230920Sken cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 1289230920Sken cm->cm_complete_data = NULL; 1290230920Sken 1291230920Sken /* 1292230920Sken * Send command synchronously. 1293230920Sken */ 1294254938Sken status = mps_wait_command(sc, cm, 30, CAN_SLEEP); 1295230920Sken if (status) { 1296230920Sken mps_printf(sc, "%s: invalid request: error %d\n", __func__, 1297230920Sken status); 1298230920Sken status = MPS_DIAG_FAILURE; 1299230920Sken goto done; 1300230920Sken } 1301230920Sken 1302230920Sken /* 1303230920Sken * Process RELEASE reply. 1304230920Sken */ 1305230920Sken reply = (MPI2_DIAG_RELEASE_REPLY *)cm->cm_reply; 1306230920Sken if ((reply->IOCStatus != MPI2_IOCSTATUS_SUCCESS) || 1307230920Sken pBuffer->owned_by_firmware) { 1308230920Sken status = MPS_DIAG_FAILURE; 1309230920Sken mps_dprint(sc, MPS_FAULT, "%s: release of FW Diag Buffer " 1310230920Sken "failed with IOCStatus = 0x%x and IOCLogInfo = 0x%x\n", 1311230920Sken __func__, reply->IOCStatus, reply->IOCLogInfo); 1312230920Sken goto done; 1313230920Sken } 1314230920Sken 1315230920Sken /* 1316230920Sken * Release was successful. 1317230920Sken */ 1318230920Sken *return_code = MPS_FW_DIAG_ERROR_SUCCESS; 1319230920Sken status = MPS_DIAG_SUCCESS; 1320230920Sken 1321230920Sken /* 1322230920Sken * If this was for an UNREGISTER diag type command, clear the unique ID. 1323230920Sken */ 1324230920Sken if (diag_type == MPS_FW_DIAG_TYPE_UNREGISTER) { 1325230920Sken pBuffer->unique_id = MPS_FW_DIAG_INVALID_UID; 1326230920Sken } 1327230920Sken 1328230920Skendone: 1329230920Sken return (status); 1330230920Sken} 1331230920Sken 1332230920Skenstatic int 1333230920Skenmps_diag_register(struct mps_softc *sc, mps_fw_diag_register_t *diag_register, 1334230920Sken uint32_t *return_code) 1335230920Sken{ 1336230920Sken mps_fw_diagnostic_buffer_t *pBuffer; 1337230920Sken uint8_t extended_type, buffer_type, i; 1338230920Sken uint32_t buffer_size; 1339230920Sken uint32_t unique_id; 1340230920Sken int status; 1341230920Sken 1342230920Sken extended_type = diag_register->ExtendedType; 1343230920Sken buffer_type = diag_register->BufferType; 1344230920Sken buffer_size = diag_register->RequestedBufferSize; 1345230920Sken unique_id = diag_register->UniqueId; 1346230920Sken 1347230920Sken /* 1348230920Sken * Check for valid buffer type 1349230920Sken */ 1350230920Sken if (buffer_type >= MPI2_DIAG_BUF_TYPE_COUNT) { 1351230920Sken *return_code = MPS_FW_DIAG_ERROR_INVALID_PARAMETER; 1352230920Sken return (MPS_DIAG_FAILURE); 1353230920Sken } 1354230920Sken 1355230920Sken /* 1356230920Sken * Get the current buffer and look up the unique ID. The unique ID 1357230920Sken * should not be found. If it is, the ID is already in use. 1358230920Sken */ 1359230920Sken i = mps_get_fw_diag_buffer_number(sc, unique_id); 1360230920Sken pBuffer = &sc->fw_diag_buffer_list[buffer_type]; 1361230920Sken if (i != MPS_FW_DIAGNOSTIC_UID_NOT_FOUND) { 1362230920Sken *return_code = MPS_FW_DIAG_ERROR_INVALID_UID; 1363230920Sken return (MPS_DIAG_FAILURE); 1364230920Sken } 1365230920Sken 1366230920Sken /* 1367230920Sken * The buffer's unique ID should not be registered yet, and the given 1368230920Sken * unique ID cannot be 0. 1369230920Sken */ 1370230920Sken if ((pBuffer->unique_id != MPS_FW_DIAG_INVALID_UID) || 1371230920Sken (unique_id == MPS_FW_DIAG_INVALID_UID)) { 1372230920Sken *return_code = MPS_FW_DIAG_ERROR_INVALID_UID; 1373230920Sken return (MPS_DIAG_FAILURE); 1374230920Sken } 1375230920Sken 1376230920Sken /* 1377230920Sken * If this buffer is already posted as immediate, just change owner. 1378230920Sken */ 1379230920Sken if (pBuffer->immediate && pBuffer->owned_by_firmware && 1380230920Sken (pBuffer->unique_id == MPS_FW_DIAG_INVALID_UID)) { 1381230920Sken pBuffer->immediate = FALSE; 1382230920Sken pBuffer->unique_id = unique_id; 1383230920Sken return (MPS_DIAG_SUCCESS); 1384230920Sken } 1385230920Sken 1386230920Sken /* 1387230920Sken * Post a new buffer after checking if it's enabled. The DMA buffer 1388230920Sken * that is allocated will be contiguous (nsegments = 1). 1389230920Sken */ 1390230920Sken if (!pBuffer->enabled) { 1391230920Sken *return_code = MPS_FW_DIAG_ERROR_NO_BUFFER; 1392230920Sken return (MPS_DIAG_FAILURE); 1393230920Sken } 1394230920Sken if (bus_dma_tag_create( sc->mps_parent_dmat, /* parent */ 1395230920Sken 1, 0, /* algnmnt, boundary */ 1396230920Sken BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 1397230920Sken BUS_SPACE_MAXADDR, /* highaddr */ 1398230920Sken NULL, NULL, /* filter, filterarg */ 1399230920Sken buffer_size, /* maxsize */ 1400230920Sken 1, /* nsegments */ 1401230920Sken buffer_size, /* maxsegsize */ 1402230920Sken 0, /* flags */ 1403230920Sken NULL, NULL, /* lockfunc, lockarg */ 1404230920Sken &sc->fw_diag_dmat)) { 1405230920Sken device_printf(sc->mps_dev, "Cannot allocate FW diag buffer DMA " 1406230920Sken "tag\n"); 1407230920Sken return (ENOMEM); 1408230920Sken } 1409230920Sken if (bus_dmamem_alloc(sc->fw_diag_dmat, (void **)&sc->fw_diag_buffer, 1410230920Sken BUS_DMA_NOWAIT, &sc->fw_diag_map)) { 1411230920Sken device_printf(sc->mps_dev, "Cannot allocate FW diag buffer " 1412230920Sken "memory\n"); 1413230920Sken return (ENOMEM); 1414230920Sken } 1415230920Sken bzero(sc->fw_diag_buffer, buffer_size); 1416230920Sken bus_dmamap_load(sc->fw_diag_dmat, sc->fw_diag_map, sc->fw_diag_buffer, 1417230920Sken buffer_size, mps_memaddr_cb, &sc->fw_diag_busaddr, 0); 1418230920Sken pBuffer->size = buffer_size; 1419230920Sken 1420230920Sken /* 1421230920Sken * Copy the given info to the diag buffer and post the buffer. 1422230920Sken */ 1423230920Sken pBuffer->buffer_type = buffer_type; 1424230920Sken pBuffer->immediate = FALSE; 1425230920Sken if (buffer_type == MPI2_DIAG_BUF_TYPE_TRACE) { 1426230920Sken for (i = 0; i < (sizeof (pBuffer->product_specific) / 4); 1427230920Sken i++) { 1428230920Sken pBuffer->product_specific[i] = 1429230920Sken diag_register->ProductSpecific[i]; 1430230920Sken } 1431230920Sken } 1432230920Sken pBuffer->extended_type = extended_type; 1433230920Sken pBuffer->unique_id = unique_id; 1434230920Sken status = mps_post_fw_diag_buffer(sc, pBuffer, return_code); 1435230920Sken 1436230920Sken /* 1437230920Sken * In case there was a failure, free the DMA buffer. 1438230920Sken */ 1439230920Sken if (status == MPS_DIAG_FAILURE) { 1440230920Sken if (sc->fw_diag_busaddr != 0) 1441230920Sken bus_dmamap_unload(sc->fw_diag_dmat, sc->fw_diag_map); 1442230920Sken if (sc->fw_diag_buffer != NULL) 1443230920Sken bus_dmamem_free(sc->fw_diag_dmat, sc->fw_diag_buffer, 1444230920Sken sc->fw_diag_map); 1445230920Sken if (sc->fw_diag_dmat != NULL) 1446230920Sken bus_dma_tag_destroy(sc->fw_diag_dmat); 1447230920Sken } 1448230920Sken 1449230920Sken return (status); 1450230920Sken} 1451230920Sken 1452230920Skenstatic int 1453230920Skenmps_diag_unregister(struct mps_softc *sc, 1454230920Sken mps_fw_diag_unregister_t *diag_unregister, uint32_t *return_code) 1455230920Sken{ 1456230920Sken mps_fw_diagnostic_buffer_t *pBuffer; 1457230920Sken uint8_t i; 1458230920Sken uint32_t unique_id; 1459230920Sken int status; 1460230920Sken 1461230920Sken unique_id = diag_unregister->UniqueId; 1462230920Sken 1463230920Sken /* 1464230920Sken * Get the current buffer and look up the unique ID. The unique ID 1465230920Sken * should be there. 1466230920Sken */ 1467230920Sken i = mps_get_fw_diag_buffer_number(sc, unique_id); 1468230920Sken if (i == MPS_FW_DIAGNOSTIC_UID_NOT_FOUND) { 1469230920Sken *return_code = MPS_FW_DIAG_ERROR_INVALID_UID; 1470230920Sken return (MPS_DIAG_FAILURE); 1471230920Sken } 1472230920Sken 1473230920Sken pBuffer = &sc->fw_diag_buffer_list[i]; 1474230920Sken 1475230920Sken /* 1476230920Sken * Try to release the buffer from FW before freeing it. If release 1477230920Sken * fails, don't free the DMA buffer in case FW tries to access it 1478230920Sken * later. If buffer is not owned by firmware, can't release it. 1479230920Sken */ 1480230920Sken if (!pBuffer->owned_by_firmware) { 1481230920Sken status = MPS_DIAG_SUCCESS; 1482230920Sken } else { 1483230920Sken status = mps_release_fw_diag_buffer(sc, pBuffer, return_code, 1484230920Sken MPS_FW_DIAG_TYPE_UNREGISTER); 1485230920Sken } 1486230920Sken 1487230920Sken /* 1488230920Sken * At this point, return the current status no matter what happens with 1489230920Sken * the DMA buffer. 1490230920Sken */ 1491230920Sken pBuffer->unique_id = MPS_FW_DIAG_INVALID_UID; 1492230920Sken if (status == MPS_DIAG_SUCCESS) { 1493230920Sken if (sc->fw_diag_busaddr != 0) 1494230920Sken bus_dmamap_unload(sc->fw_diag_dmat, sc->fw_diag_map); 1495230920Sken if (sc->fw_diag_buffer != NULL) 1496230920Sken bus_dmamem_free(sc->fw_diag_dmat, sc->fw_diag_buffer, 1497230920Sken sc->fw_diag_map); 1498230920Sken if (sc->fw_diag_dmat != NULL) 1499230920Sken bus_dma_tag_destroy(sc->fw_diag_dmat); 1500230920Sken } 1501230920Sken 1502230920Sken return (status); 1503230920Sken} 1504230920Sken 1505230920Skenstatic int 1506230920Skenmps_diag_query(struct mps_softc *sc, mps_fw_diag_query_t *diag_query, 1507230920Sken uint32_t *return_code) 1508230920Sken{ 1509230920Sken mps_fw_diagnostic_buffer_t *pBuffer; 1510230920Sken uint8_t i; 1511230920Sken uint32_t unique_id; 1512230920Sken 1513230920Sken unique_id = diag_query->UniqueId; 1514230920Sken 1515230920Sken /* 1516230920Sken * If ID is valid, query on ID. 1517230920Sken * If ID is invalid, query on buffer type. 1518230920Sken */ 1519230920Sken if (unique_id == MPS_FW_DIAG_INVALID_UID) { 1520230920Sken i = diag_query->BufferType; 1521230920Sken if (i >= MPI2_DIAG_BUF_TYPE_COUNT) { 1522230920Sken *return_code = MPS_FW_DIAG_ERROR_INVALID_UID; 1523230920Sken return (MPS_DIAG_FAILURE); 1524230920Sken } 1525230920Sken } else { 1526230920Sken i = mps_get_fw_diag_buffer_number(sc, unique_id); 1527230920Sken if (i == MPS_FW_DIAGNOSTIC_UID_NOT_FOUND) { 1528230920Sken *return_code = MPS_FW_DIAG_ERROR_INVALID_UID; 1529230920Sken return (MPS_DIAG_FAILURE); 1530230920Sken } 1531230920Sken } 1532230920Sken 1533230920Sken /* 1534230920Sken * Fill query structure with the diag buffer info. 1535230920Sken */ 1536230920Sken pBuffer = &sc->fw_diag_buffer_list[i]; 1537230920Sken diag_query->BufferType = pBuffer->buffer_type; 1538230920Sken diag_query->ExtendedType = pBuffer->extended_type; 1539230920Sken if (diag_query->BufferType == MPI2_DIAG_BUF_TYPE_TRACE) { 1540230920Sken for (i = 0; i < (sizeof(diag_query->ProductSpecific) / 4); 1541230920Sken i++) { 1542230920Sken diag_query->ProductSpecific[i] = 1543230920Sken pBuffer->product_specific[i]; 1544230920Sken } 1545230920Sken } 1546230920Sken diag_query->TotalBufferSize = pBuffer->size; 1547230920Sken diag_query->DriverAddedBufferSize = 0; 1548230920Sken diag_query->UniqueId = pBuffer->unique_id; 1549230920Sken diag_query->ApplicationFlags = 0; 1550230920Sken diag_query->DiagnosticFlags = 0; 1551230920Sken 1552230920Sken /* 1553230920Sken * Set/Clear application flags 1554230920Sken */ 1555230920Sken if (pBuffer->immediate) { 1556230920Sken diag_query->ApplicationFlags &= ~MPS_FW_DIAG_FLAG_APP_OWNED; 1557230920Sken } else { 1558230920Sken diag_query->ApplicationFlags |= MPS_FW_DIAG_FLAG_APP_OWNED; 1559230920Sken } 1560230920Sken if (pBuffer->valid_data || pBuffer->owned_by_firmware) { 1561230920Sken diag_query->ApplicationFlags |= MPS_FW_DIAG_FLAG_BUFFER_VALID; 1562230920Sken } else { 1563230920Sken diag_query->ApplicationFlags &= ~MPS_FW_DIAG_FLAG_BUFFER_VALID; 1564230920Sken } 1565230920Sken if (pBuffer->owned_by_firmware) { 1566230920Sken diag_query->ApplicationFlags |= 1567230920Sken MPS_FW_DIAG_FLAG_FW_BUFFER_ACCESS; 1568230920Sken } else { 1569230920Sken diag_query->ApplicationFlags &= 1570230920Sken ~MPS_FW_DIAG_FLAG_FW_BUFFER_ACCESS; 1571230920Sken } 1572230920Sken 1573230920Sken return (MPS_DIAG_SUCCESS); 1574230920Sken} 1575230920Sken 1576230920Skenstatic int 1577230920Skenmps_diag_read_buffer(struct mps_softc *sc, 1578230920Sken mps_diag_read_buffer_t *diag_read_buffer, uint8_t *ioctl_buf, 1579230920Sken uint32_t *return_code) 1580230920Sken{ 1581230920Sken mps_fw_diagnostic_buffer_t *pBuffer; 1582230920Sken uint8_t i, *pData; 1583230920Sken uint32_t unique_id; 1584230920Sken int status; 1585230920Sken 1586230920Sken unique_id = diag_read_buffer->UniqueId; 1587230920Sken 1588230920Sken /* 1589230920Sken * Get the current buffer and look up the unique ID. The unique ID 1590230920Sken * should be there. 1591230920Sken */ 1592230920Sken i = mps_get_fw_diag_buffer_number(sc, unique_id); 1593230920Sken if (i == MPS_FW_DIAGNOSTIC_UID_NOT_FOUND) { 1594230920Sken *return_code = MPS_FW_DIAG_ERROR_INVALID_UID; 1595230920Sken return (MPS_DIAG_FAILURE); 1596230920Sken } 1597230920Sken 1598230920Sken pBuffer = &sc->fw_diag_buffer_list[i]; 1599230920Sken 1600230920Sken /* 1601230920Sken * Make sure requested read is within limits 1602230920Sken */ 1603230920Sken if (diag_read_buffer->StartingOffset + diag_read_buffer->BytesToRead > 1604230920Sken pBuffer->size) { 1605230920Sken *return_code = MPS_FW_DIAG_ERROR_INVALID_PARAMETER; 1606230920Sken return (MPS_DIAG_FAILURE); 1607230920Sken } 1608230920Sken 1609230920Sken /* 1610230920Sken * Copy the requested data from DMA to the diag_read_buffer. The DMA 1611230920Sken * buffer that was allocated is one contiguous buffer. 1612230920Sken */ 1613230920Sken pData = (uint8_t *)(sc->fw_diag_buffer + 1614230920Sken diag_read_buffer->StartingOffset); 1615230920Sken if (copyout(pData, ioctl_buf, diag_read_buffer->BytesToRead) != 0) 1616230920Sken return (MPS_DIAG_FAILURE); 1617230920Sken diag_read_buffer->Status = 0; 1618230920Sken 1619230920Sken /* 1620230920Sken * Set or clear the Force Release flag. 1621230920Sken */ 1622230920Sken if (pBuffer->force_release) { 1623230920Sken diag_read_buffer->Flags |= MPS_FW_DIAG_FLAG_FORCE_RELEASE; 1624230920Sken } else { 1625230920Sken diag_read_buffer->Flags &= ~MPS_FW_DIAG_FLAG_FORCE_RELEASE; 1626230920Sken } 1627230920Sken 1628230920Sken /* 1629230920Sken * If buffer is to be reregistered, make sure it's not already owned by 1630230920Sken * firmware first. 1631230920Sken */ 1632230920Sken status = MPS_DIAG_SUCCESS; 1633230920Sken if (!pBuffer->owned_by_firmware) { 1634230920Sken if (diag_read_buffer->Flags & MPS_FW_DIAG_FLAG_REREGISTER) { 1635230920Sken status = mps_post_fw_diag_buffer(sc, pBuffer, 1636230920Sken return_code); 1637230920Sken } 1638230920Sken } 1639230920Sken 1640230920Sken return (status); 1641230920Sken} 1642230920Sken 1643230920Skenstatic int 1644230920Skenmps_diag_release(struct mps_softc *sc, mps_fw_diag_release_t *diag_release, 1645230920Sken uint32_t *return_code) 1646230920Sken{ 1647230920Sken mps_fw_diagnostic_buffer_t *pBuffer; 1648230920Sken uint8_t i; 1649230920Sken uint32_t unique_id; 1650230920Sken int status; 1651230920Sken 1652230920Sken unique_id = diag_release->UniqueId; 1653230920Sken 1654230920Sken /* 1655230920Sken * Get the current buffer and look up the unique ID. The unique ID 1656230920Sken * should be there. 1657230920Sken */ 1658230920Sken i = mps_get_fw_diag_buffer_number(sc, unique_id); 1659230920Sken if (i == MPS_FW_DIAGNOSTIC_UID_NOT_FOUND) { 1660230920Sken *return_code = MPS_FW_DIAG_ERROR_INVALID_UID; 1661230920Sken return (MPS_DIAG_FAILURE); 1662230920Sken } 1663230920Sken 1664230920Sken pBuffer = &sc->fw_diag_buffer_list[i]; 1665230920Sken 1666230920Sken /* 1667230920Sken * If buffer is not owned by firmware, it's already been released. 1668230920Sken */ 1669230920Sken if (!pBuffer->owned_by_firmware) { 1670230920Sken *return_code = MPS_FW_DIAG_ERROR_ALREADY_RELEASED; 1671230920Sken return (MPS_DIAG_FAILURE); 1672230920Sken } 1673230920Sken 1674230920Sken /* 1675230920Sken * Release the buffer. 1676230920Sken */ 1677230920Sken status = mps_release_fw_diag_buffer(sc, pBuffer, return_code, 1678230920Sken MPS_FW_DIAG_TYPE_RELEASE); 1679230920Sken return (status); 1680230920Sken} 1681230920Sken 1682230920Skenstatic int 1683230920Skenmps_do_diag_action(struct mps_softc *sc, uint32_t action, uint8_t *diag_action, 1684230920Sken uint32_t length, uint32_t *return_code) 1685230920Sken{ 1686230920Sken mps_fw_diag_register_t diag_register; 1687230920Sken mps_fw_diag_unregister_t diag_unregister; 1688230920Sken mps_fw_diag_query_t diag_query; 1689230920Sken mps_diag_read_buffer_t diag_read_buffer; 1690230920Sken mps_fw_diag_release_t diag_release; 1691230920Sken int status = MPS_DIAG_SUCCESS; 1692230920Sken uint32_t original_return_code; 1693230920Sken 1694230920Sken original_return_code = *return_code; 1695230920Sken *return_code = MPS_FW_DIAG_ERROR_SUCCESS; 1696230920Sken 1697230920Sken switch (action) { 1698230920Sken case MPS_FW_DIAG_TYPE_REGISTER: 1699230920Sken if (!length) { 1700230920Sken *return_code = 1701230920Sken MPS_FW_DIAG_ERROR_INVALID_PARAMETER; 1702230920Sken status = MPS_DIAG_FAILURE; 1703230920Sken break; 1704230920Sken } 1705230920Sken if (copyin(diag_action, &diag_register, 1706230920Sken sizeof(diag_register)) != 0) 1707230920Sken return (MPS_DIAG_FAILURE); 1708230920Sken status = mps_diag_register(sc, &diag_register, 1709230920Sken return_code); 1710230920Sken break; 1711230920Sken 1712230920Sken case MPS_FW_DIAG_TYPE_UNREGISTER: 1713230920Sken if (length < sizeof(diag_unregister)) { 1714230920Sken *return_code = 1715230920Sken MPS_FW_DIAG_ERROR_INVALID_PARAMETER; 1716230920Sken status = MPS_DIAG_FAILURE; 1717230920Sken break; 1718230920Sken } 1719230920Sken if (copyin(diag_action, &diag_unregister, 1720230920Sken sizeof(diag_unregister)) != 0) 1721230920Sken return (MPS_DIAG_FAILURE); 1722230920Sken status = mps_diag_unregister(sc, &diag_unregister, 1723230920Sken return_code); 1724230920Sken break; 1725230920Sken 1726230920Sken case MPS_FW_DIAG_TYPE_QUERY: 1727230920Sken if (length < sizeof (diag_query)) { 1728230920Sken *return_code = 1729230920Sken MPS_FW_DIAG_ERROR_INVALID_PARAMETER; 1730230920Sken status = MPS_DIAG_FAILURE; 1731230920Sken break; 1732230920Sken } 1733230920Sken if (copyin(diag_action, &diag_query, sizeof(diag_query)) 1734230920Sken != 0) 1735230920Sken return (MPS_DIAG_FAILURE); 1736230920Sken status = mps_diag_query(sc, &diag_query, return_code); 1737230920Sken if (status == MPS_DIAG_SUCCESS) 1738230920Sken if (copyout(&diag_query, diag_action, 1739230920Sken sizeof (diag_query)) != 0) 1740230920Sken return (MPS_DIAG_FAILURE); 1741230920Sken break; 1742230920Sken 1743230920Sken case MPS_FW_DIAG_TYPE_READ_BUFFER: 1744230920Sken if (copyin(diag_action, &diag_read_buffer, 1745230920Sken sizeof(diag_read_buffer)) != 0) 1746230920Sken return (MPS_DIAG_FAILURE); 1747230920Sken if (length < diag_read_buffer.BytesToRead) { 1748230920Sken *return_code = 1749230920Sken MPS_FW_DIAG_ERROR_INVALID_PARAMETER; 1750230920Sken status = MPS_DIAG_FAILURE; 1751230920Sken break; 1752230920Sken } 1753230920Sken status = mps_diag_read_buffer(sc, &diag_read_buffer, 1754230920Sken PTRIN(diag_read_buffer.PtrDataBuffer), 1755230920Sken return_code); 1756230920Sken if (status == MPS_DIAG_SUCCESS) { 1757230920Sken if (copyout(&diag_read_buffer, diag_action, 1758230920Sken sizeof(diag_read_buffer) - 1759230920Sken sizeof(diag_read_buffer.PtrDataBuffer)) != 1760230920Sken 0) 1761230920Sken return (MPS_DIAG_FAILURE); 1762230920Sken } 1763230920Sken break; 1764230920Sken 1765230920Sken case MPS_FW_DIAG_TYPE_RELEASE: 1766230920Sken if (length < sizeof(diag_release)) { 1767230920Sken *return_code = 1768230920Sken MPS_FW_DIAG_ERROR_INVALID_PARAMETER; 1769230920Sken status = MPS_DIAG_FAILURE; 1770230920Sken break; 1771230920Sken } 1772230920Sken if (copyin(diag_action, &diag_release, 1773230920Sken sizeof(diag_release)) != 0) 1774230920Sken return (MPS_DIAG_FAILURE); 1775230920Sken status = mps_diag_release(sc, &diag_release, 1776230920Sken return_code); 1777230920Sken break; 1778230920Sken 1779230920Sken default: 1780230920Sken *return_code = MPS_FW_DIAG_ERROR_INVALID_PARAMETER; 1781230920Sken status = MPS_DIAG_FAILURE; 1782230920Sken break; 1783230920Sken } 1784230920Sken 1785230920Sken if ((status == MPS_DIAG_FAILURE) && 1786230920Sken (original_return_code == MPS_FW_DIAG_NEW) && 1787230920Sken (*return_code != MPS_FW_DIAG_ERROR_SUCCESS)) 1788230920Sken status = MPS_DIAG_SUCCESS; 1789230920Sken 1790230920Sken return (status); 1791230920Sken} 1792230920Sken 1793230920Skenstatic int 1794230920Skenmps_user_diag_action(struct mps_softc *sc, mps_diag_action_t *data) 1795230920Sken{ 1796230920Sken int status; 1797230920Sken 1798230920Sken /* 1799230920Sken * Only allow one diag action at one time. 1800230920Sken */ 1801230920Sken if (sc->mps_flags & MPS_FLAGS_BUSY) { 1802254938Sken mps_dprint(sc, MPS_USER, "%s: Only one FW diag command " 1803230920Sken "allowed at a single time.", __func__); 1804230920Sken return (EBUSY); 1805230920Sken } 1806230920Sken sc->mps_flags |= MPS_FLAGS_BUSY; 1807230920Sken 1808230920Sken /* 1809230920Sken * Send diag action request 1810230920Sken */ 1811230920Sken if (data->Action == MPS_FW_DIAG_TYPE_REGISTER || 1812230920Sken data->Action == MPS_FW_DIAG_TYPE_UNREGISTER || 1813230920Sken data->Action == MPS_FW_DIAG_TYPE_QUERY || 1814230920Sken data->Action == MPS_FW_DIAG_TYPE_READ_BUFFER || 1815230920Sken data->Action == MPS_FW_DIAG_TYPE_RELEASE) { 1816230920Sken status = mps_do_diag_action(sc, data->Action, 1817230920Sken PTRIN(data->PtrDiagAction), data->Length, 1818230920Sken &data->ReturnCode); 1819230920Sken } else 1820230920Sken status = EINVAL; 1821230920Sken 1822230920Sken sc->mps_flags &= ~MPS_FLAGS_BUSY; 1823230920Sken return (status); 1824230920Sken} 1825230920Sken 1826230920Sken/* 1827230920Sken * Copy the event recording mask and the event queue size out. For 1828230920Sken * clarification, the event recording mask (events_to_record) is not the same 1829230920Sken * thing as the event mask (event_mask). events_to_record has a bit set for 1830230920Sken * every event type that is to be recorded by the driver, and event_mask has a 1831230920Sken * bit cleared for every event that is allowed into the driver from the IOC. 1832230920Sken * They really have nothing to do with each other. 1833230920Sken */ 1834230920Skenstatic void 1835230920Skenmps_user_event_query(struct mps_softc *sc, mps_event_query_t *data) 1836230920Sken{ 1837230920Sken uint8_t i; 1838230920Sken 1839230920Sken mps_lock(sc); 1840230920Sken data->Entries = MPS_EVENT_QUEUE_SIZE; 1841230920Sken 1842230920Sken for (i = 0; i < 4; i++) { 1843230920Sken data->Types[i] = sc->events_to_record[i]; 1844230920Sken } 1845230920Sken mps_unlock(sc); 1846230920Sken} 1847230920Sken 1848230920Sken/* 1849230920Sken * Set the driver's event mask according to what's been given. See 1850230920Sken * mps_user_event_query for explanation of the event recording mask and the IOC 1851230920Sken * event mask. It's the app's responsibility to enable event logging by setting 1852230920Sken * the bits in events_to_record. Initially, no events will be logged. 1853230920Sken */ 1854230920Skenstatic void 1855230920Skenmps_user_event_enable(struct mps_softc *sc, mps_event_enable_t *data) 1856230920Sken{ 1857230920Sken uint8_t i; 1858230920Sken 1859230920Sken mps_lock(sc); 1860230920Sken for (i = 0; i < 4; i++) { 1861230920Sken sc->events_to_record[i] = data->Types[i]; 1862230920Sken } 1863230920Sken mps_unlock(sc); 1864230920Sken} 1865230920Sken 1866230920Sken/* 1867230920Sken * Copy out the events that have been recorded, up to the max events allowed. 1868230920Sken */ 1869230920Skenstatic int 1870230920Skenmps_user_event_report(struct mps_softc *sc, mps_event_report_t *data) 1871230920Sken{ 1872230920Sken int status = 0; 1873230920Sken uint32_t size; 1874230920Sken 1875230920Sken mps_lock(sc); 1876230920Sken size = data->Size; 1877230920Sken if ((size >= sizeof(sc->recorded_events)) && (status == 0)) { 1878230920Sken mps_unlock(sc); 1879230920Sken if (copyout((void *)sc->recorded_events, 1880230920Sken PTRIN(data->PtrEvents), size) != 0) 1881230920Sken status = EFAULT; 1882230920Sken mps_lock(sc); 1883230920Sken } else { 1884230920Sken /* 1885230920Sken * data->Size value is not large enough to copy event data. 1886230920Sken */ 1887230920Sken status = EFAULT; 1888230920Sken } 1889230920Sken 1890230920Sken /* 1891230920Sken * Change size value to match the number of bytes that were copied. 1892230920Sken */ 1893230920Sken if (status == 0) 1894230920Sken data->Size = sizeof(sc->recorded_events); 1895230920Sken mps_unlock(sc); 1896230920Sken 1897230920Sken return (status); 1898230920Sken} 1899230920Sken 1900230920Sken/* 1901230920Sken * Record events into the driver from the IOC if they are not masked. 1902230920Sken */ 1903230920Skenvoid 1904230920Skenmpssas_record_event(struct mps_softc *sc, 1905230920Sken MPI2_EVENT_NOTIFICATION_REPLY *event_reply) 1906230920Sken{ 1907230920Sken uint32_t event; 1908230920Sken int i, j; 1909230920Sken uint16_t event_data_len; 1910230920Sken boolean_t sendAEN = FALSE; 1911230920Sken 1912230920Sken event = event_reply->Event; 1913230920Sken 1914230920Sken /* 1915230920Sken * Generate a system event to let anyone who cares know that a 1916230920Sken * LOG_ENTRY_ADDED event has occurred. This is sent no matter what the 1917230920Sken * event mask is set to. 1918230920Sken */ 1919230920Sken if (event == MPI2_EVENT_LOG_ENTRY_ADDED) { 1920230920Sken sendAEN = TRUE; 1921230920Sken } 1922230920Sken 1923230920Sken /* 1924230920Sken * Record the event only if its corresponding bit is set in 1925230920Sken * events_to_record. event_index is the index into recorded_events and 1926230920Sken * event_number is the overall number of an event being recorded since 1927230920Sken * start-of-day. event_index will roll over; event_number will never 1928230920Sken * roll over. 1929230920Sken */ 1930230920Sken i = (uint8_t)(event / 32); 1931230920Sken j = (uint8_t)(event % 32); 1932230920Sken if ((i < 4) && ((1 << j) & sc->events_to_record[i])) { 1933230920Sken i = sc->event_index; 1934230920Sken sc->recorded_events[i].Type = event; 1935230920Sken sc->recorded_events[i].Number = ++sc->event_number; 1936230920Sken bzero(sc->recorded_events[i].Data, MPS_MAX_EVENT_DATA_LENGTH * 1937230920Sken 4); 1938230920Sken event_data_len = event_reply->EventDataLength; 1939230920Sken 1940230920Sken if (event_data_len > 0) { 1941230920Sken /* 1942230920Sken * Limit data to size in m_event entry 1943230920Sken */ 1944230920Sken if (event_data_len > MPS_MAX_EVENT_DATA_LENGTH) { 1945230920Sken event_data_len = MPS_MAX_EVENT_DATA_LENGTH; 1946230920Sken } 1947230920Sken for (j = 0; j < event_data_len; j++) { 1948230920Sken sc->recorded_events[i].Data[j] = 1949230920Sken event_reply->EventData[j]; 1950230920Sken } 1951230920Sken 1952230920Sken /* 1953230920Sken * check for index wrap-around 1954230920Sken */ 1955230920Sken if (++i == MPS_EVENT_QUEUE_SIZE) { 1956230920Sken i = 0; 1957230920Sken } 1958230920Sken sc->event_index = (uint8_t)i; 1959230920Sken 1960230920Sken /* 1961230920Sken * Set flag to send the event. 1962230920Sken */ 1963230920Sken sendAEN = TRUE; 1964230920Sken } 1965230920Sken } 1966230920Sken 1967230920Sken /* 1968230920Sken * Generate a system event if flag is set to let anyone who cares know 1969230920Sken * that an event has occurred. 1970230920Sken */ 1971230920Sken if (sendAEN) { 1972230920Sken//SLM-how to send a system event (see kqueue, kevent) 1973230920Sken// (void) ddi_log_sysevent(mpt->m_dip, DDI_VENDOR_LSI, "MPT_SAS", 1974230920Sken// "SAS", NULL, NULL, DDI_NOSLEEP); 1975230920Sken } 1976230920Sken} 1977230920Sken 1978230920Skenstatic int 1979230920Skenmps_user_reg_access(struct mps_softc *sc, mps_reg_access_t *data) 1980230920Sken{ 1981230920Sken int status = 0; 1982230920Sken 1983230920Sken switch (data->Command) { 1984230920Sken /* 1985230920Sken * IO access is not supported. 1986230920Sken */ 1987230920Sken case REG_IO_READ: 1988230920Sken case REG_IO_WRITE: 1989254938Sken mps_dprint(sc, MPS_USER, "IO access is not supported. " 1990230920Sken "Use memory access."); 1991230920Sken status = EINVAL; 1992230920Sken break; 1993230920Sken 1994230920Sken case REG_MEM_READ: 1995230920Sken data->RegData = mps_regread(sc, data->RegOffset); 1996230920Sken break; 1997230920Sken 1998230920Sken case REG_MEM_WRITE: 1999230920Sken mps_regwrite(sc, data->RegOffset, data->RegData); 2000230920Sken break; 2001230920Sken 2002230920Sken default: 2003230920Sken status = EINVAL; 2004230920Sken break; 2005230920Sken } 2006230920Sken 2007230920Sken return (status); 2008230920Sken} 2009230920Sken 2010230920Skenstatic int 2011230920Skenmps_user_btdh(struct mps_softc *sc, mps_btdh_mapping_t *data) 2012230920Sken{ 2013230920Sken uint8_t bt2dh = FALSE; 2014230920Sken uint8_t dh2bt = FALSE; 2015230920Sken uint16_t dev_handle, bus, target; 2016230920Sken 2017230920Sken bus = data->Bus; 2018230920Sken target = data->TargetID; 2019230920Sken dev_handle = data->DevHandle; 2020230920Sken 2021230920Sken /* 2022230920Sken * When DevHandle is 0xFFFF and Bus/Target are not 0xFFFF, use Bus/ 2023230920Sken * Target to get DevHandle. When Bus/Target are 0xFFFF and DevHandle is 2024230920Sken * not 0xFFFF, use DevHandle to get Bus/Target. Anything else is 2025230920Sken * invalid. 2026230920Sken */ 2027230920Sken if ((bus == 0xFFFF) && (target == 0xFFFF) && (dev_handle != 0xFFFF)) 2028230920Sken dh2bt = TRUE; 2029230920Sken if ((dev_handle == 0xFFFF) && (bus != 0xFFFF) && (target != 0xFFFF)) 2030230920Sken bt2dh = TRUE; 2031230920Sken if (!dh2bt && !bt2dh) 2032230920Sken return (EINVAL); 2033230920Sken 2034230920Sken /* 2035230920Sken * Only handle bus of 0. Make sure target is within range. 2036230920Sken */ 2037230920Sken if (bt2dh) { 2038230920Sken if (bus != 0) 2039230920Sken return (EINVAL); 2040230920Sken 2041230920Sken if (target > sc->max_devices) { 2042230920Sken mps_dprint(sc, MPS_FAULT, "Target ID is out of range " 2043230920Sken "for Bus/Target to DevHandle mapping."); 2044230920Sken return (EINVAL); 2045230920Sken } 2046230920Sken dev_handle = sc->mapping_table[target].dev_handle; 2047230920Sken if (dev_handle) 2048230920Sken data->DevHandle = dev_handle; 2049230920Sken } else { 2050230920Sken bus = 0; 2051230920Sken target = mps_mapping_get_sas_id_from_handle(sc, dev_handle); 2052230920Sken data->Bus = bus; 2053230920Sken data->TargetID = target; 2054230920Sken } 2055230920Sken 2056230920Sken return (0); 2057230920Sken} 2058230920Sken 2059230920Skenstatic int 2060213702Smdfmps_ioctl(struct cdev *dev, u_long cmd, void *arg, int flag, 2061212420Sken struct thread *td) 2062212420Sken{ 2063212420Sken struct mps_softc *sc; 2064212420Sken struct mps_cfg_page_req *page_req; 2065212420Sken struct mps_ext_cfg_page_req *ext_page_req; 2066212420Sken void *mps_page; 2067237876Sken int error, msleep_ret; 2068212420Sken 2069212420Sken mps_page = NULL; 2070212420Sken sc = dev->si_drv1; 2071212420Sken page_req = (void *)arg; 2072212420Sken ext_page_req = (void *)arg; 2073212420Sken 2074212420Sken switch (cmd) { 2075212420Sken case MPSIO_READ_CFG_HEADER: 2076212420Sken mps_lock(sc); 2077212420Sken error = mps_user_read_cfg_header(sc, page_req); 2078212420Sken mps_unlock(sc); 2079212420Sken break; 2080212420Sken case MPSIO_READ_CFG_PAGE: 2081212420Sken mps_page = malloc(page_req->len, M_MPSUSER, M_WAITOK | M_ZERO); 2082237876Sken if(!mps_page) { 2083237876Sken mps_printf(sc, "Cannot allocate memory %s %d\n", 2084237876Sken __func__, __LINE__); 2085237876Sken return (ENOMEM); 2086237876Sken } 2087212420Sken error = copyin(page_req->buf, mps_page, 2088212420Sken sizeof(MPI2_CONFIG_PAGE_HEADER)); 2089212420Sken if (error) 2090212420Sken break; 2091212420Sken mps_lock(sc); 2092212420Sken error = mps_user_read_cfg_page(sc, page_req, mps_page); 2093212420Sken mps_unlock(sc); 2094212420Sken if (error) 2095212420Sken break; 2096212420Sken error = copyout(mps_page, page_req->buf, page_req->len); 2097212420Sken break; 2098212420Sken case MPSIO_READ_EXT_CFG_HEADER: 2099212420Sken mps_lock(sc); 2100212420Sken error = mps_user_read_extcfg_header(sc, ext_page_req); 2101212420Sken mps_unlock(sc); 2102212420Sken break; 2103212420Sken case MPSIO_READ_EXT_CFG_PAGE: 2104212420Sken mps_page = malloc(ext_page_req->len, M_MPSUSER, M_WAITOK|M_ZERO); 2105237876Sken if(!mps_page) { 2106237876Sken mps_printf(sc, "Cannot allocate memory %s %d\n", 2107237876Sken __func__, __LINE__); 2108237876Sken return (ENOMEM); 2109237876Sken } 2110212420Sken error = copyin(ext_page_req->buf, mps_page, 2111212420Sken sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); 2112212420Sken if (error) 2113212420Sken break; 2114212420Sken mps_lock(sc); 2115212420Sken error = mps_user_read_extcfg_page(sc, ext_page_req, mps_page); 2116212420Sken mps_unlock(sc); 2117212420Sken if (error) 2118212420Sken break; 2119212420Sken error = copyout(mps_page, ext_page_req->buf, ext_page_req->len); 2120212420Sken break; 2121212420Sken case MPSIO_WRITE_CFG_PAGE: 2122212420Sken mps_page = malloc(page_req->len, M_MPSUSER, M_WAITOK|M_ZERO); 2123237876Sken if(!mps_page) { 2124237876Sken mps_printf(sc, "Cannot allocate memory %s %d\n", 2125237876Sken __func__, __LINE__); 2126237876Sken return (ENOMEM); 2127237876Sken } 2128212420Sken error = copyin(page_req->buf, mps_page, page_req->len); 2129212420Sken if (error) 2130212420Sken break; 2131212420Sken mps_lock(sc); 2132212420Sken error = mps_user_write_cfg_page(sc, page_req, mps_page); 2133212420Sken mps_unlock(sc); 2134212420Sken break; 2135212420Sken case MPSIO_MPS_COMMAND: 2136212420Sken error = mps_user_command(sc, (struct mps_usr_command *)arg); 2137212420Sken break; 2138230920Sken case MPTIOCTL_PASS_THRU: 2139230920Sken /* 2140230920Sken * The user has requested to pass through a command to be 2141230920Sken * executed by the MPT firmware. Call our routine which does 2142230920Sken * this. Only allow one passthru IOCTL at one time. 2143230920Sken */ 2144230920Sken error = mps_user_pass_thru(sc, (mps_pass_thru_t *)arg); 2145230920Sken break; 2146230920Sken case MPTIOCTL_GET_ADAPTER_DATA: 2147230920Sken /* 2148230920Sken * The user has requested to read adapter data. Call our 2149230920Sken * routine which does this. 2150230920Sken */ 2151230920Sken error = 0; 2152230920Sken mps_user_get_adapter_data(sc, (mps_adapter_data_t *)arg); 2153230920Sken break; 2154230920Sken case MPTIOCTL_GET_PCI_INFO: 2155230920Sken /* 2156230920Sken * The user has requested to read pci info. Call 2157230920Sken * our routine which does this. 2158230920Sken */ 2159230920Sken mps_lock(sc); 2160230920Sken error = 0; 2161230920Sken mps_user_read_pci_info(sc, (mps_pci_info_t *)arg); 2162230920Sken mps_unlock(sc); 2163230920Sken break; 2164230920Sken case MPTIOCTL_RESET_ADAPTER: 2165230920Sken mps_lock(sc); 2166230920Sken sc->port_enable_complete = 0; 2167237876Sken uint32_t reinit_start = time_uptime; 2168230920Sken error = mps_reinit(sc); 2169237876Sken /* Sleep for 300 second. */ 2170237876Sken msleep_ret = msleep(&sc->port_enable_complete, &sc->mps_mtx, PRIBIO, 2171237876Sken "mps_porten", 300 * hz); 2172230920Sken mps_unlock(sc); 2173237876Sken if (msleep_ret) 2174230920Sken printf("Port Enable did not complete after Diag " 2175237876Sken "Reset msleep error %d.\n", msleep_ret); 2176237876Sken else 2177254938Sken mps_dprint(sc, MPS_USER, 2178237876Sken "Hard Reset with Port Enable completed in %d seconds.\n", 2179237876Sken (uint32_t) (time_uptime - reinit_start)); 2180230920Sken break; 2181230920Sken case MPTIOCTL_DIAG_ACTION: 2182230920Sken /* 2183230920Sken * The user has done a diag buffer action. Call our routine 2184230920Sken * which does this. Only allow one diag action at one time. 2185230920Sken */ 2186230920Sken mps_lock(sc); 2187230920Sken error = mps_user_diag_action(sc, (mps_diag_action_t *)arg); 2188230920Sken mps_unlock(sc); 2189230920Sken break; 2190230920Sken case MPTIOCTL_EVENT_QUERY: 2191230920Sken /* 2192230920Sken * The user has done an event query. Call our routine which does 2193230920Sken * this. 2194230920Sken */ 2195230920Sken error = 0; 2196230920Sken mps_user_event_query(sc, (mps_event_query_t *)arg); 2197230920Sken break; 2198230920Sken case MPTIOCTL_EVENT_ENABLE: 2199230920Sken /* 2200230920Sken * The user has done an event enable. Call our routine which 2201230920Sken * does this. 2202230920Sken */ 2203230920Sken error = 0; 2204230920Sken mps_user_event_enable(sc, (mps_event_enable_t *)arg); 2205230920Sken break; 2206230920Sken case MPTIOCTL_EVENT_REPORT: 2207230920Sken /* 2208230920Sken * The user has done an event report. Call our routine which 2209230920Sken * does this. 2210230920Sken */ 2211230920Sken error = mps_user_event_report(sc, (mps_event_report_t *)arg); 2212230920Sken break; 2213230920Sken case MPTIOCTL_REG_ACCESS: 2214230920Sken /* 2215230920Sken * The user has requested register access. Call our routine 2216230920Sken * which does this. 2217230920Sken */ 2218230920Sken mps_lock(sc); 2219230920Sken error = mps_user_reg_access(sc, (mps_reg_access_t *)arg); 2220230920Sken mps_unlock(sc); 2221230920Sken break; 2222230920Sken case MPTIOCTL_BTDH_MAPPING: 2223230920Sken /* 2224230920Sken * The user has requested to translate a bus/target to a 2225230920Sken * DevHandle or a DevHandle to a bus/target. Call our routine 2226230920Sken * which does this. 2227230920Sken */ 2228230920Sken error = mps_user_btdh(sc, (mps_btdh_mapping_t *)arg); 2229230920Sken break; 2230212420Sken default: 2231212420Sken error = ENOIOCTL; 2232212420Sken break; 2233212420Sken } 2234212420Sken 2235212420Sken if (mps_page != NULL) 2236212420Sken free(mps_page, M_MPSUSER); 2237212420Sken 2238213702Smdf return (error); 2239213702Smdf} 2240212420Sken 2241213702Smdf#ifdef COMPAT_FREEBSD32 2242213702Smdf 2243213702Smdfstruct mps_cfg_page_req32 { 2244213702Smdf MPI2_CONFIG_PAGE_HEADER header; 2245213702Smdf uint32_t page_address; 2246213702Smdf uint32_t buf; 2247213702Smdf int len; 2248213702Smdf uint16_t ioc_status; 2249213702Smdf}; 2250213702Smdf 2251213702Smdfstruct mps_ext_cfg_page_req32 { 2252213702Smdf MPI2_CONFIG_EXTENDED_PAGE_HEADER header; 2253213702Smdf uint32_t page_address; 2254213702Smdf uint32_t buf; 2255213702Smdf int len; 2256213702Smdf uint16_t ioc_status; 2257213702Smdf}; 2258213702Smdf 2259213702Smdfstruct mps_raid_action32 { 2260213702Smdf uint8_t action; 2261213702Smdf uint8_t volume_bus; 2262213702Smdf uint8_t volume_id; 2263213702Smdf uint8_t phys_disk_num; 2264213702Smdf uint32_t action_data_word; 2265213702Smdf uint32_t buf; 2266213702Smdf int len; 2267213702Smdf uint32_t volume_status; 2268213702Smdf uint32_t action_data[4]; 2269213702Smdf uint16_t action_status; 2270213702Smdf uint16_t ioc_status; 2271213702Smdf uint8_t write; 2272213702Smdf}; 2273213702Smdf 2274213702Smdfstruct mps_usr_command32 { 2275213702Smdf uint32_t req; 2276213702Smdf uint32_t req_len; 2277213702Smdf uint32_t rpl; 2278213702Smdf uint32_t rpl_len; 2279213702Smdf uint32_t buf; 2280213702Smdf int len; 2281213702Smdf uint32_t flags; 2282213702Smdf}; 2283213702Smdf 2284213702Smdf#define MPSIO_READ_CFG_HEADER32 _IOWR('M', 200, struct mps_cfg_page_req32) 2285213702Smdf#define MPSIO_READ_CFG_PAGE32 _IOWR('M', 201, struct mps_cfg_page_req32) 2286213702Smdf#define MPSIO_READ_EXT_CFG_HEADER32 _IOWR('M', 202, struct mps_ext_cfg_page_req32) 2287213702Smdf#define MPSIO_READ_EXT_CFG_PAGE32 _IOWR('M', 203, struct mps_ext_cfg_page_req32) 2288213702Smdf#define MPSIO_WRITE_CFG_PAGE32 _IOWR('M', 204, struct mps_cfg_page_req32) 2289213702Smdf#define MPSIO_RAID_ACTION32 _IOWR('M', 205, struct mps_raid_action32) 2290213702Smdf#define MPSIO_MPS_COMMAND32 _IOWR('M', 210, struct mps_usr_command32) 2291213702Smdf 2292213702Smdfstatic int 2293213702Smdfmps_ioctl32(struct cdev *dev, u_long cmd32, void *_arg, int flag, 2294213702Smdf struct thread *td) 2295213702Smdf{ 2296213702Smdf struct mps_cfg_page_req32 *page32 = _arg; 2297213702Smdf struct mps_ext_cfg_page_req32 *ext32 = _arg; 2298213702Smdf struct mps_raid_action32 *raid32 = _arg; 2299213702Smdf struct mps_usr_command32 *user32 = _arg; 2300213702Smdf union { 2301213702Smdf struct mps_cfg_page_req page; 2302213702Smdf struct mps_ext_cfg_page_req ext; 2303213702Smdf struct mps_raid_action raid; 2304213702Smdf struct mps_usr_command user; 2305213702Smdf } arg; 2306213702Smdf u_long cmd; 2307213702Smdf int error; 2308213702Smdf 2309213702Smdf switch (cmd32) { 2310212420Sken case MPSIO_READ_CFG_HEADER32: 2311212420Sken case MPSIO_READ_CFG_PAGE32: 2312212420Sken case MPSIO_WRITE_CFG_PAGE32: 2313213702Smdf if (cmd32 == MPSIO_READ_CFG_HEADER32) 2314213702Smdf cmd = MPSIO_READ_CFG_HEADER; 2315213702Smdf else if (cmd32 == MPSIO_READ_CFG_PAGE32) 2316213702Smdf cmd = MPSIO_READ_CFG_PAGE; 2317213702Smdf else 2318213702Smdf cmd = MPSIO_WRITE_CFG_PAGE; 2319213702Smdf CP(*page32, arg.page, header); 2320213702Smdf CP(*page32, arg.page, page_address); 2321213702Smdf PTRIN_CP(*page32, arg.page, buf); 2322213702Smdf CP(*page32, arg.page, len); 2323213702Smdf CP(*page32, arg.page, ioc_status); 2324212420Sken break; 2325213702Smdf 2326212420Sken case MPSIO_READ_EXT_CFG_HEADER32: 2327213702Smdf case MPSIO_READ_EXT_CFG_PAGE32: 2328213702Smdf if (cmd32 == MPSIO_READ_EXT_CFG_HEADER32) 2329213702Smdf cmd = MPSIO_READ_EXT_CFG_HEADER; 2330213702Smdf else 2331213702Smdf cmd = MPSIO_READ_EXT_CFG_PAGE; 2332213702Smdf CP(*ext32, arg.ext, header); 2333213702Smdf CP(*ext32, arg.ext, page_address); 2334213702Smdf PTRIN_CP(*ext32, arg.ext, buf); 2335213702Smdf CP(*ext32, arg.ext, len); 2336213702Smdf CP(*ext32, arg.ext, ioc_status); 2337212420Sken break; 2338213702Smdf 2339213702Smdf case MPSIO_RAID_ACTION32: 2340213702Smdf cmd = MPSIO_RAID_ACTION; 2341213702Smdf CP(*raid32, arg.raid, action); 2342213702Smdf CP(*raid32, arg.raid, volume_bus); 2343213702Smdf CP(*raid32, arg.raid, volume_id); 2344213702Smdf CP(*raid32, arg.raid, phys_disk_num); 2345213702Smdf CP(*raid32, arg.raid, action_data_word); 2346213702Smdf PTRIN_CP(*raid32, arg.raid, buf); 2347213702Smdf CP(*raid32, arg.raid, len); 2348213702Smdf CP(*raid32, arg.raid, volume_status); 2349213702Smdf bcopy(raid32->action_data, arg.raid.action_data, 2350213702Smdf sizeof arg.raid.action_data); 2351213702Smdf CP(*raid32, arg.raid, ioc_status); 2352213702Smdf CP(*raid32, arg.raid, write); 2353213702Smdf break; 2354213702Smdf 2355213702Smdf case MPSIO_MPS_COMMAND32: 2356213702Smdf cmd = MPSIO_MPS_COMMAND; 2357213702Smdf PTRIN_CP(*user32, arg.user, req); 2358213702Smdf CP(*user32, arg.user, req_len); 2359213702Smdf PTRIN_CP(*user32, arg.user, rpl); 2360213702Smdf CP(*user32, arg.user, rpl_len); 2361213702Smdf PTRIN_CP(*user32, arg.user, buf); 2362213702Smdf CP(*user32, arg.user, len); 2363213702Smdf CP(*user32, arg.user, flags); 2364213702Smdf break; 2365212420Sken default: 2366212420Sken return (ENOIOCTL); 2367212420Sken } 2368212420Sken 2369213702Smdf error = mps_ioctl(dev, cmd, &arg, flag, td); 2370213702Smdf if (error == 0 && (cmd32 & IOC_OUT) != 0) { 2371213702Smdf switch (cmd32) { 2372213702Smdf case MPSIO_READ_CFG_HEADER32: 2373213702Smdf case MPSIO_READ_CFG_PAGE32: 2374213702Smdf case MPSIO_WRITE_CFG_PAGE32: 2375213702Smdf CP(arg.page, *page32, header); 2376213702Smdf CP(arg.page, *page32, page_address); 2377213702Smdf PTROUT_CP(arg.page, *page32, buf); 2378213702Smdf CP(arg.page, *page32, len); 2379213702Smdf CP(arg.page, *page32, ioc_status); 2380213702Smdf break; 2381213702Smdf 2382213702Smdf case MPSIO_READ_EXT_CFG_HEADER32: 2383213702Smdf case MPSIO_READ_EXT_CFG_PAGE32: 2384213702Smdf CP(arg.ext, *ext32, header); 2385213702Smdf CP(arg.ext, *ext32, page_address); 2386213702Smdf PTROUT_CP(arg.ext, *ext32, buf); 2387213702Smdf CP(arg.ext, *ext32, len); 2388213702Smdf CP(arg.ext, *ext32, ioc_status); 2389213702Smdf break; 2390213702Smdf 2391213702Smdf case MPSIO_RAID_ACTION32: 2392213702Smdf CP(arg.raid, *raid32, action); 2393213702Smdf CP(arg.raid, *raid32, volume_bus); 2394213702Smdf CP(arg.raid, *raid32, volume_id); 2395213702Smdf CP(arg.raid, *raid32, phys_disk_num); 2396213702Smdf CP(arg.raid, *raid32, action_data_word); 2397213702Smdf PTROUT_CP(arg.raid, *raid32, buf); 2398213702Smdf CP(arg.raid, *raid32, len); 2399213702Smdf CP(arg.raid, *raid32, volume_status); 2400213702Smdf bcopy(arg.raid.action_data, raid32->action_data, 2401213702Smdf sizeof arg.raid.action_data); 2402213702Smdf CP(arg.raid, *raid32, ioc_status); 2403213702Smdf CP(arg.raid, *raid32, write); 2404213702Smdf break; 2405213702Smdf 2406213702Smdf case MPSIO_MPS_COMMAND32: 2407213702Smdf PTROUT_CP(arg.user, *user32, req); 2408213702Smdf CP(arg.user, *user32, req_len); 2409213702Smdf PTROUT_CP(arg.user, *user32, rpl); 2410213702Smdf CP(arg.user, *user32, rpl_len); 2411213702Smdf PTROUT_CP(arg.user, *user32, buf); 2412213702Smdf CP(arg.user, *user32, len); 2413213702Smdf CP(arg.user, *user32, flags); 2414213702Smdf break; 2415213702Smdf } 2416213702Smdf } 2417213702Smdf 2418213702Smdf return (error); 2419212420Sken} 2420213702Smdf#endif /* COMPAT_FREEBSD32 */ 2421213702Smdf 2422213702Smdfstatic int 2423213702Smdfmps_ioctl_devsw(struct cdev *dev, u_long com, caddr_t arg, int flag, 2424213702Smdf struct thread *td) 2425213702Smdf{ 2426213702Smdf#ifdef COMPAT_FREEBSD32 2427213702Smdf if (SV_CURPROC_FLAG(SV_ILP32)) 2428213702Smdf return (mps_ioctl32(dev, com, arg, flag, td)); 2429213702Smdf#endif 2430213702Smdf return (mps_ioctl(dev, com, arg, flag, td)); 2431213702Smdf} 2432