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