1d3c7b9a0SKenneth D. Merry /*- 2d3c7b9a0SKenneth D. Merry * Copyright (c) 2008 Yahoo!, Inc. 3d3c7b9a0SKenneth D. Merry * All rights reserved. 4d3c7b9a0SKenneth D. Merry * Written by: John Baldwin <jhb@FreeBSD.org> 5d3c7b9a0SKenneth D. Merry * 6d3c7b9a0SKenneth D. Merry * Redistribution and use in source and binary forms, with or without 7d3c7b9a0SKenneth D. Merry * modification, are permitted provided that the following conditions 8d3c7b9a0SKenneth D. Merry * are met: 9d3c7b9a0SKenneth D. Merry * 1. Redistributions of source code must retain the above copyright 10d3c7b9a0SKenneth D. Merry * notice, this list of conditions and the following disclaimer. 11d3c7b9a0SKenneth D. Merry * 2. Redistributions in binary form must reproduce the above copyright 12d3c7b9a0SKenneth D. Merry * notice, this list of conditions and the following disclaimer in the 13d3c7b9a0SKenneth D. Merry * documentation and/or other materials provided with the distribution. 14d3c7b9a0SKenneth D. Merry * 3. Neither the name of the author nor the names of any co-contributors 15d3c7b9a0SKenneth D. Merry * may be used to endorse or promote products derived from this software 16d3c7b9a0SKenneth D. Merry * without specific prior written permission. 17d3c7b9a0SKenneth D. Merry * 18d3c7b9a0SKenneth D. Merry * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19d3c7b9a0SKenneth D. Merry * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20d3c7b9a0SKenneth D. Merry * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21d3c7b9a0SKenneth D. Merry * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22d3c7b9a0SKenneth D. Merry * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23d3c7b9a0SKenneth D. Merry * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24d3c7b9a0SKenneth D. Merry * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25d3c7b9a0SKenneth D. Merry * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26d3c7b9a0SKenneth D. Merry * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27d3c7b9a0SKenneth D. Merry * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28d3c7b9a0SKenneth D. Merry * SUCH DAMAGE. 29d3c7b9a0SKenneth D. Merry * 30d3c7b9a0SKenneth D. Merry * LSI MPS-Fusion Host Adapter FreeBSD userland interface 31d3c7b9a0SKenneth D. Merry */ 32d3c7b9a0SKenneth D. Merry 33d3c7b9a0SKenneth D. Merry #include <sys/cdefs.h> 34d3c7b9a0SKenneth D. Merry __FBSDID("$FreeBSD$"); 35d3c7b9a0SKenneth D. Merry 365ef98042SMatthew D Fleming #include "opt_compat.h" 375ef98042SMatthew D Fleming 38d3c7b9a0SKenneth D. Merry #include <sys/types.h> 39d3c7b9a0SKenneth D. Merry #include <sys/param.h> 40d3c7b9a0SKenneth D. Merry #include <sys/systm.h> 41d3c7b9a0SKenneth D. Merry #include <sys/kernel.h> 42d3c7b9a0SKenneth D. Merry #include <sys/selinfo.h> 43d3c7b9a0SKenneth D. Merry #include <sys/module.h> 44d3c7b9a0SKenneth D. Merry #include <sys/bus.h> 45d3c7b9a0SKenneth D. Merry #include <sys/conf.h> 46d3c7b9a0SKenneth D. Merry #include <sys/bio.h> 47d3c7b9a0SKenneth D. Merry #include <sys/malloc.h> 48d3c7b9a0SKenneth D. Merry #include <sys/uio.h> 49d3c7b9a0SKenneth D. Merry #include <sys/sysctl.h> 50d3c7b9a0SKenneth D. Merry #include <sys/ioccom.h> 51d3c7b9a0SKenneth D. Merry #include <sys/endian.h> 525ef98042SMatthew D Fleming #include <sys/proc.h> 535ef98042SMatthew D Fleming #include <sys/sysent.h> 54d3c7b9a0SKenneth D. Merry 55d3c7b9a0SKenneth D. Merry #include <machine/bus.h> 56d3c7b9a0SKenneth D. Merry #include <machine/resource.h> 57d3c7b9a0SKenneth D. Merry #include <sys/rman.h> 58d3c7b9a0SKenneth D. Merry 59d3c7b9a0SKenneth D. Merry #include <cam/scsi/scsi_all.h> 60d3c7b9a0SKenneth D. Merry 61d3c7b9a0SKenneth D. Merry #include <dev/mps/mpi/mpi2_type.h> 62d3c7b9a0SKenneth D. Merry #include <dev/mps/mpi/mpi2.h> 63d3c7b9a0SKenneth D. Merry #include <dev/mps/mpi/mpi2_ioc.h> 64d3c7b9a0SKenneth D. Merry #include <dev/mps/mpi/mpi2_cnfg.h> 65d3c7b9a0SKenneth D. Merry #include <dev/mps/mpsvar.h> 66d3c7b9a0SKenneth D. Merry #include <dev/mps/mps_table.h> 67d3c7b9a0SKenneth D. Merry #include <dev/mps/mps_ioctl.h> 68d3c7b9a0SKenneth D. Merry 69d3c7b9a0SKenneth D. Merry static d_open_t mps_open; 70d3c7b9a0SKenneth D. Merry static d_close_t mps_close; 715ef98042SMatthew D Fleming static d_ioctl_t mps_ioctl_devsw; 72d3c7b9a0SKenneth D. Merry 73d3c7b9a0SKenneth D. Merry static struct cdevsw mps_cdevsw = { 74d3c7b9a0SKenneth D. Merry .d_version = D_VERSION, 75d3c7b9a0SKenneth D. Merry .d_flags = 0, 76d3c7b9a0SKenneth D. Merry .d_open = mps_open, 77d3c7b9a0SKenneth D. Merry .d_close = mps_close, 785ef98042SMatthew D Fleming .d_ioctl = mps_ioctl_devsw, 79d3c7b9a0SKenneth D. Merry .d_name = "mps", 80d3c7b9a0SKenneth D. Merry }; 81d3c7b9a0SKenneth D. Merry 82d95f15e7SMatthew D Fleming typedef int (mps_user_f)(struct mps_command *, struct mps_usr_command *); 83d95f15e7SMatthew D Fleming static mps_user_f mpi_pre_ioc_facts; 84d95f15e7SMatthew D Fleming static mps_user_f mpi_pre_port_facts; 85d95f15e7SMatthew D Fleming static mps_user_f mpi_pre_fw_download; 86d95f15e7SMatthew D Fleming static mps_user_f mpi_pre_fw_upload; 87d95f15e7SMatthew D Fleming static mps_user_f mpi_pre_sata_passthrough; 88d95f15e7SMatthew D Fleming static mps_user_f mpi_pre_smp_passthrough; 89d95f15e7SMatthew D Fleming static mps_user_f mpi_pre_config; 90d95f15e7SMatthew D Fleming static mps_user_f mpi_pre_sas_io_unit_control; 91d95f15e7SMatthew D Fleming 92452909d7SMatthew D Fleming static int mps_user_read_cfg_header(struct mps_softc *, 93452909d7SMatthew D Fleming struct mps_cfg_page_req *); 94452909d7SMatthew D Fleming static int mps_user_read_cfg_page(struct mps_softc *, 95452909d7SMatthew D Fleming struct mps_cfg_page_req *, void *); 96452909d7SMatthew D Fleming static int mps_user_read_extcfg_header(struct mps_softc *, 97452909d7SMatthew D Fleming struct mps_ext_cfg_page_req *); 98452909d7SMatthew D Fleming static int mps_user_read_extcfg_page(struct mps_softc *, 99452909d7SMatthew D Fleming struct mps_ext_cfg_page_req *, void *); 100452909d7SMatthew D Fleming static int mps_user_write_cfg_page(struct mps_softc *, 101452909d7SMatthew D Fleming struct mps_cfg_page_req *, void *); 102d95f15e7SMatthew D Fleming static int mps_user_setup_request(struct mps_command *, 103d95f15e7SMatthew D Fleming struct mps_usr_command *); 104452909d7SMatthew D Fleming static int mps_user_command(struct mps_softc *, struct mps_usr_command *); 105452909d7SMatthew D Fleming 106d3c7b9a0SKenneth D. Merry static MALLOC_DEFINE(M_MPSUSER, "mps_user", "Buffers for mps(4) ioctls"); 107d3c7b9a0SKenneth D. Merry 108d3c7b9a0SKenneth D. Merry int 109d3c7b9a0SKenneth D. Merry mps_attach_user(struct mps_softc *sc) 110d3c7b9a0SKenneth D. Merry { 111d3c7b9a0SKenneth D. Merry int unit; 112d3c7b9a0SKenneth D. Merry 113d3c7b9a0SKenneth D. Merry unit = device_get_unit(sc->mps_dev); 114d3c7b9a0SKenneth D. Merry sc->mps_cdev = make_dev(&mps_cdevsw, unit, UID_ROOT, GID_OPERATOR, 0640, 115d3c7b9a0SKenneth D. Merry "mps%d", unit); 116d3c7b9a0SKenneth D. Merry if (sc->mps_cdev == NULL) { 117d3c7b9a0SKenneth D. Merry return (ENOMEM); 118d3c7b9a0SKenneth D. Merry } 119d3c7b9a0SKenneth D. Merry sc->mps_cdev->si_drv1 = sc; 120d3c7b9a0SKenneth D. Merry return (0); 121d3c7b9a0SKenneth D. Merry } 122d3c7b9a0SKenneth D. Merry 123d3c7b9a0SKenneth D. Merry void 124d3c7b9a0SKenneth D. Merry mps_detach_user(struct mps_softc *sc) 125d3c7b9a0SKenneth D. Merry { 126d3c7b9a0SKenneth D. Merry 127d3c7b9a0SKenneth D. Merry /* XXX: do a purge of pending requests? */ 128d3c7b9a0SKenneth D. Merry destroy_dev(sc->mps_cdev); 129d3c7b9a0SKenneth D. Merry 130d3c7b9a0SKenneth D. Merry } 131d3c7b9a0SKenneth D. Merry 132d3c7b9a0SKenneth D. Merry static int 133d3c7b9a0SKenneth D. Merry mps_open(struct cdev *dev, int flags, int fmt, struct thread *td) 134d3c7b9a0SKenneth D. Merry { 135d3c7b9a0SKenneth D. Merry 136d3c7b9a0SKenneth D. Merry return (0); 137d3c7b9a0SKenneth D. Merry } 138d3c7b9a0SKenneth D. Merry 139d3c7b9a0SKenneth D. Merry static int 140d3c7b9a0SKenneth D. Merry mps_close(struct cdev *dev, int flags, int fmt, struct thread *td) 141d3c7b9a0SKenneth D. Merry { 142d3c7b9a0SKenneth D. Merry 143d3c7b9a0SKenneth D. Merry return (0); 144d3c7b9a0SKenneth D. Merry } 145d3c7b9a0SKenneth D. Merry 146d3c7b9a0SKenneth D. Merry static int 147d3c7b9a0SKenneth D. Merry mps_user_read_cfg_header(struct mps_softc *sc, 148d3c7b9a0SKenneth D. Merry struct mps_cfg_page_req *page_req) 149d3c7b9a0SKenneth D. Merry { 150d3c7b9a0SKenneth D. Merry MPI2_CONFIG_PAGE_HEADER *hdr; 151d3c7b9a0SKenneth D. Merry struct mps_config_params params; 152d3c7b9a0SKenneth D. Merry int error; 153d3c7b9a0SKenneth D. Merry 154d3c7b9a0SKenneth D. Merry hdr = ¶ms.hdr.Struct; 155d3c7b9a0SKenneth D. Merry params.action = MPI2_CONFIG_ACTION_PAGE_HEADER; 156d3c7b9a0SKenneth D. Merry params.page_address = le32toh(page_req->page_address); 157d3c7b9a0SKenneth D. Merry hdr->PageVersion = 0; 158d3c7b9a0SKenneth D. Merry hdr->PageLength = 0; 159d3c7b9a0SKenneth D. Merry hdr->PageNumber = page_req->header.PageNumber; 160d3c7b9a0SKenneth D. Merry hdr->PageType = page_req->header.PageType; 161d3c7b9a0SKenneth D. Merry params.buffer = NULL; 162d3c7b9a0SKenneth D. Merry params.length = 0; 163d3c7b9a0SKenneth D. Merry params.callback = NULL; 164d3c7b9a0SKenneth D. Merry 165d3c7b9a0SKenneth D. Merry if ((error = mps_read_config_page(sc, ¶ms)) != 0) { 166d3c7b9a0SKenneth D. Merry /* 167d3c7b9a0SKenneth D. Merry * Leave the request. Without resetting the chip, it's 168d3c7b9a0SKenneth D. Merry * still owned by it and we'll just get into trouble 169d3c7b9a0SKenneth D. Merry * freeing it now. Mark it as abandoned so that if it 170d3c7b9a0SKenneth D. Merry * shows up later it can be freed. 171d3c7b9a0SKenneth D. Merry */ 172d3c7b9a0SKenneth D. Merry mps_printf(sc, "read_cfg_header timed out\n"); 173d3c7b9a0SKenneth D. Merry return (ETIMEDOUT); 174d3c7b9a0SKenneth D. Merry } 175d3c7b9a0SKenneth D. Merry 176d3c7b9a0SKenneth D. Merry page_req->ioc_status = htole16(params.status); 177d3c7b9a0SKenneth D. Merry if ((page_req->ioc_status & MPI2_IOCSTATUS_MASK) == 178d3c7b9a0SKenneth D. Merry MPI2_IOCSTATUS_SUCCESS) { 179d3c7b9a0SKenneth D. Merry bcopy(hdr, &page_req->header, sizeof(page_req->header)); 180d3c7b9a0SKenneth D. Merry } 181d3c7b9a0SKenneth D. Merry 182d3c7b9a0SKenneth D. Merry return (0); 183d3c7b9a0SKenneth D. Merry } 184d3c7b9a0SKenneth D. Merry 185d3c7b9a0SKenneth D. Merry static int 186d3c7b9a0SKenneth D. Merry mps_user_read_cfg_page(struct mps_softc *sc, struct mps_cfg_page_req *page_req, 187d3c7b9a0SKenneth D. Merry void *buf) 188d3c7b9a0SKenneth D. Merry { 189d3c7b9a0SKenneth D. Merry MPI2_CONFIG_PAGE_HEADER *reqhdr, *hdr; 190d3c7b9a0SKenneth D. Merry struct mps_config_params params; 191d3c7b9a0SKenneth D. Merry int error; 192d3c7b9a0SKenneth D. Merry 193d3c7b9a0SKenneth D. Merry reqhdr = buf; 194d3c7b9a0SKenneth D. Merry hdr = ¶ms.hdr.Struct; 195d3c7b9a0SKenneth D. Merry hdr->PageVersion = reqhdr->PageVersion; 196d3c7b9a0SKenneth D. Merry hdr->PageLength = reqhdr->PageLength; 197d3c7b9a0SKenneth D. Merry hdr->PageNumber = reqhdr->PageNumber; 198d3c7b9a0SKenneth D. Merry hdr->PageType = reqhdr->PageType & MPI2_CONFIG_PAGETYPE_MASK; 199d3c7b9a0SKenneth D. Merry params.action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; 200d3c7b9a0SKenneth D. Merry params.page_address = le32toh(page_req->page_address); 201d3c7b9a0SKenneth D. Merry params.buffer = buf; 202d3c7b9a0SKenneth D. Merry params.length = le32toh(page_req->len); 203d3c7b9a0SKenneth D. Merry params.callback = NULL; 204d3c7b9a0SKenneth D. Merry 205d3c7b9a0SKenneth D. Merry if ((error = mps_read_config_page(sc, ¶ms)) != 0) { 206d3c7b9a0SKenneth D. Merry mps_printf(sc, "mps_user_read_cfg_page timed out\n"); 207d3c7b9a0SKenneth D. Merry return (ETIMEDOUT); 208d3c7b9a0SKenneth D. Merry } 209d3c7b9a0SKenneth D. Merry 210d3c7b9a0SKenneth D. Merry page_req->ioc_status = htole16(params.status); 211d3c7b9a0SKenneth D. Merry return (0); 212d3c7b9a0SKenneth D. Merry } 213d3c7b9a0SKenneth D. Merry 214d3c7b9a0SKenneth D. Merry static int 215d3c7b9a0SKenneth D. Merry mps_user_read_extcfg_header(struct mps_softc *sc, 216d3c7b9a0SKenneth D. Merry struct mps_ext_cfg_page_req *ext_page_req) 217d3c7b9a0SKenneth D. Merry { 218d3c7b9a0SKenneth D. Merry MPI2_CONFIG_EXTENDED_PAGE_HEADER *hdr; 219d3c7b9a0SKenneth D. Merry struct mps_config_params params; 220d3c7b9a0SKenneth D. Merry int error; 221d3c7b9a0SKenneth D. Merry 222d3c7b9a0SKenneth D. Merry hdr = ¶ms.hdr.Ext; 223d3c7b9a0SKenneth D. Merry params.action = MPI2_CONFIG_ACTION_PAGE_HEADER; 224d3c7b9a0SKenneth D. Merry hdr->PageVersion = ext_page_req->header.PageVersion; 225d3c7b9a0SKenneth D. Merry hdr->ExtPageLength = 0; 226d3c7b9a0SKenneth D. Merry hdr->PageNumber = ext_page_req->header.PageNumber; 227d3c7b9a0SKenneth D. Merry hdr->ExtPageType = ext_page_req->header.ExtPageType; 228d3c7b9a0SKenneth D. Merry params.page_address = le32toh(ext_page_req->page_address); 229d3c7b9a0SKenneth D. Merry if ((error = mps_read_config_page(sc, ¶ms)) != 0) { 230d3c7b9a0SKenneth D. Merry /* 231d3c7b9a0SKenneth D. Merry * Leave the request. Without resetting the chip, it's 232d3c7b9a0SKenneth D. Merry * still owned by it and we'll just get into trouble 233d3c7b9a0SKenneth D. Merry * freeing it now. Mark it as abandoned so that if it 234d3c7b9a0SKenneth D. Merry * shows up later it can be freed. 235d3c7b9a0SKenneth D. Merry */ 236d3c7b9a0SKenneth D. Merry mps_printf(sc, "mps_user_read_extcfg_header timed out\n"); 237d3c7b9a0SKenneth D. Merry return (ETIMEDOUT); 238d3c7b9a0SKenneth D. Merry } 239d3c7b9a0SKenneth D. Merry 240d3c7b9a0SKenneth D. Merry ext_page_req->ioc_status = htole16(params.status); 241d3c7b9a0SKenneth D. Merry if ((ext_page_req->ioc_status & MPI2_IOCSTATUS_MASK) == 242d3c7b9a0SKenneth D. Merry MPI2_IOCSTATUS_SUCCESS) { 243d3c7b9a0SKenneth D. Merry ext_page_req->header.PageVersion = hdr->PageVersion; 244d3c7b9a0SKenneth D. Merry ext_page_req->header.PageNumber = hdr->PageNumber; 245d3c7b9a0SKenneth D. Merry ext_page_req->header.PageType = hdr->PageType; 246d3c7b9a0SKenneth D. Merry ext_page_req->header.ExtPageLength = hdr->ExtPageLength; 247d3c7b9a0SKenneth D. Merry ext_page_req->header.ExtPageType = hdr->ExtPageType; 248d3c7b9a0SKenneth D. Merry } 249d3c7b9a0SKenneth D. Merry 250d3c7b9a0SKenneth D. Merry return (0); 251d3c7b9a0SKenneth D. Merry } 252d3c7b9a0SKenneth D. Merry 253d3c7b9a0SKenneth D. Merry static int 254d3c7b9a0SKenneth D. Merry mps_user_read_extcfg_page(struct mps_softc *sc, 255d3c7b9a0SKenneth D. Merry struct mps_ext_cfg_page_req *ext_page_req, void *buf) 256d3c7b9a0SKenneth D. Merry { 257d3c7b9a0SKenneth D. Merry MPI2_CONFIG_EXTENDED_PAGE_HEADER *reqhdr, *hdr; 258d3c7b9a0SKenneth D. Merry struct mps_config_params params; 259d3c7b9a0SKenneth D. Merry int error; 260d3c7b9a0SKenneth D. Merry 261d3c7b9a0SKenneth D. Merry reqhdr = buf; 262d3c7b9a0SKenneth D. Merry hdr = ¶ms.hdr.Ext; 263d3c7b9a0SKenneth D. Merry params.action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; 264d3c7b9a0SKenneth D. Merry params.page_address = le32toh(ext_page_req->page_address); 265d3c7b9a0SKenneth D. Merry hdr->PageVersion = reqhdr->PageVersion; 266d3c7b9a0SKenneth D. Merry hdr->PageNumber = reqhdr->PageNumber; 267d3c7b9a0SKenneth D. Merry hdr->ExtPageType = reqhdr->ExtPageType; 268d3c7b9a0SKenneth D. Merry hdr->ExtPageLength = reqhdr->ExtPageLength; 269d3c7b9a0SKenneth D. Merry params.buffer = buf; 270d3c7b9a0SKenneth D. Merry params.length = le32toh(ext_page_req->len); 271d3c7b9a0SKenneth D. Merry params.callback = NULL; 272d3c7b9a0SKenneth D. Merry 273d3c7b9a0SKenneth D. Merry if ((error = mps_read_config_page(sc, ¶ms)) != 0) { 274d3c7b9a0SKenneth D. Merry mps_printf(sc, "mps_user_read_extcfg_page timed out\n"); 275d3c7b9a0SKenneth D. Merry return (ETIMEDOUT); 276d3c7b9a0SKenneth D. Merry } 277d3c7b9a0SKenneth D. Merry 278d3c7b9a0SKenneth D. Merry ext_page_req->ioc_status = htole16(params.status); 279d3c7b9a0SKenneth D. Merry return (0); 280d3c7b9a0SKenneth D. Merry } 281d3c7b9a0SKenneth D. Merry 282d3c7b9a0SKenneth D. Merry static int 283d3c7b9a0SKenneth D. Merry mps_user_write_cfg_page(struct mps_softc *sc, 284d3c7b9a0SKenneth D. Merry struct mps_cfg_page_req *page_req, void *buf) 285d3c7b9a0SKenneth D. Merry { 286d3c7b9a0SKenneth D. Merry MPI2_CONFIG_PAGE_HEADER *reqhdr, *hdr; 287d3c7b9a0SKenneth D. Merry struct mps_config_params params; 288d3c7b9a0SKenneth D. Merry u_int hdr_attr; 289d3c7b9a0SKenneth D. Merry int error; 290d3c7b9a0SKenneth D. Merry 291d3c7b9a0SKenneth D. Merry reqhdr = buf; 292d3c7b9a0SKenneth D. Merry hdr = ¶ms.hdr.Struct; 293d3c7b9a0SKenneth D. Merry hdr_attr = reqhdr->PageType & MPI2_CONFIG_PAGEATTR_MASK; 294d3c7b9a0SKenneth D. Merry if (hdr_attr != MPI2_CONFIG_PAGEATTR_CHANGEABLE && 295d3c7b9a0SKenneth D. Merry hdr_attr != MPI2_CONFIG_PAGEATTR_PERSISTENT) { 296d3c7b9a0SKenneth D. Merry mps_printf(sc, "page type 0x%x not changeable\n", 297d3c7b9a0SKenneth D. Merry reqhdr->PageType & MPI2_CONFIG_PAGETYPE_MASK); 298d3c7b9a0SKenneth D. Merry return (EINVAL); 299d3c7b9a0SKenneth D. Merry } 300d3c7b9a0SKenneth D. Merry 301d3c7b9a0SKenneth D. Merry /* 302d3c7b9a0SKenneth D. Merry * There isn't any point in restoring stripped out attributes 303d3c7b9a0SKenneth D. Merry * if you then mask them going down to issue the request. 304d3c7b9a0SKenneth D. Merry */ 305d3c7b9a0SKenneth D. Merry 306d3c7b9a0SKenneth D. Merry hdr->PageVersion = reqhdr->PageVersion; 307d3c7b9a0SKenneth D. Merry hdr->PageLength = reqhdr->PageLength; 308d3c7b9a0SKenneth D. Merry hdr->PageNumber = reqhdr->PageNumber; 309d3c7b9a0SKenneth D. Merry hdr->PageType = reqhdr->PageType; 310d3c7b9a0SKenneth D. Merry params.action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT; 311d3c7b9a0SKenneth D. Merry params.page_address = le32toh(page_req->page_address); 312d3c7b9a0SKenneth D. Merry params.buffer = buf; 313d3c7b9a0SKenneth D. Merry params.length = le32toh(page_req->len); 314d3c7b9a0SKenneth D. Merry params.callback = NULL; 315d3c7b9a0SKenneth D. Merry 316d3c7b9a0SKenneth D. Merry if ((error = mps_write_config_page(sc, ¶ms)) != 0) { 317d3c7b9a0SKenneth D. Merry mps_printf(sc, "mps_write_cfg_page timed out\n"); 318d3c7b9a0SKenneth D. Merry return (ETIMEDOUT); 319d3c7b9a0SKenneth D. Merry } 320d3c7b9a0SKenneth D. Merry 321d3c7b9a0SKenneth D. Merry page_req->ioc_status = htole16(params.status); 322d3c7b9a0SKenneth D. Merry return (0); 323d3c7b9a0SKenneth D. Merry } 324d3c7b9a0SKenneth D. Merry 32513ac67a7SMatthew D Fleming static void 32613ac67a7SMatthew D Fleming mpi_init_sge(struct mps_command *cm, void *req, void *sge) 32713ac67a7SMatthew D Fleming { 32813ac67a7SMatthew D Fleming int off, space; 32913ac67a7SMatthew D Fleming 33013ac67a7SMatthew D Fleming space = (int)cm->cm_sc->facts->IOCRequestFrameSize * 4; 33113ac67a7SMatthew D Fleming off = (uintptr_t)sge - (uintptr_t)req; 33213ac67a7SMatthew D Fleming 33313ac67a7SMatthew D Fleming KASSERT(off < space, ("bad pointers %p %p, off %d, space %d", 33413ac67a7SMatthew D Fleming req, sge, off, space)); 33513ac67a7SMatthew D Fleming 33613ac67a7SMatthew D Fleming cm->cm_sge = sge; 33713ac67a7SMatthew D Fleming cm->cm_sglsize = space - off; 33813ac67a7SMatthew D Fleming } 33913ac67a7SMatthew D Fleming 340d95f15e7SMatthew D Fleming /* 341d95f15e7SMatthew D Fleming * Prepare the mps_command for an IOC_FACTS request. 342d95f15e7SMatthew D Fleming */ 343d95f15e7SMatthew D Fleming static int 344d95f15e7SMatthew D Fleming mpi_pre_ioc_facts(struct mps_command *cm, struct mps_usr_command *cmd) 345d95f15e7SMatthew D Fleming { 346d95f15e7SMatthew D Fleming MPI2_IOC_FACTS_REQUEST *req = (void *)cm->cm_req; 347d95f15e7SMatthew D Fleming MPI2_IOC_FACTS_REPLY *rpl; 348d95f15e7SMatthew D Fleming 349d95f15e7SMatthew D Fleming if (cmd->req_len != sizeof *req) 350d95f15e7SMatthew D Fleming return (EINVAL); 351d95f15e7SMatthew D Fleming if (cmd->rpl_len != sizeof *rpl) 352d95f15e7SMatthew D Fleming return (EINVAL); 353d95f15e7SMatthew D Fleming 354d95f15e7SMatthew D Fleming cm->cm_sge = NULL; 355d95f15e7SMatthew D Fleming cm->cm_sglsize = 0; 356d95f15e7SMatthew D Fleming return (0); 357d95f15e7SMatthew D Fleming } 358d95f15e7SMatthew D Fleming 359d95f15e7SMatthew D Fleming /* 360d95f15e7SMatthew D Fleming * Prepare the mps_command for a PORT_FACTS request. 361d95f15e7SMatthew D Fleming */ 362d95f15e7SMatthew D Fleming static int 363d95f15e7SMatthew D Fleming mpi_pre_port_facts(struct mps_command *cm, struct mps_usr_command *cmd) 364d95f15e7SMatthew D Fleming { 365d95f15e7SMatthew D Fleming MPI2_PORT_FACTS_REQUEST *req = (void *)cm->cm_req; 366d95f15e7SMatthew D Fleming MPI2_PORT_FACTS_REPLY *rpl; 367d95f15e7SMatthew D Fleming 368d95f15e7SMatthew D Fleming if (cmd->req_len != sizeof *req) 369d95f15e7SMatthew D Fleming return (EINVAL); 370d95f15e7SMatthew D Fleming if (cmd->rpl_len != sizeof *rpl) 371d95f15e7SMatthew D Fleming return (EINVAL); 372d95f15e7SMatthew D Fleming 373d95f15e7SMatthew D Fleming cm->cm_sge = NULL; 374d95f15e7SMatthew D Fleming cm->cm_sglsize = 0; 375d95f15e7SMatthew D Fleming return (0); 376d95f15e7SMatthew D Fleming } 377d95f15e7SMatthew D Fleming 378d95f15e7SMatthew D Fleming /* 379d95f15e7SMatthew D Fleming * Prepare the mps_command for a FW_DOWNLOAD request. 380d95f15e7SMatthew D Fleming */ 381d95f15e7SMatthew D Fleming static int 382d95f15e7SMatthew D Fleming mpi_pre_fw_download(struct mps_command *cm, struct mps_usr_command *cmd) 383d95f15e7SMatthew D Fleming { 384d95f15e7SMatthew D Fleming MPI2_FW_DOWNLOAD_REQUEST *req = (void *)cm->cm_req; 385d95f15e7SMatthew D Fleming MPI2_FW_DOWNLOAD_REPLY *rpl; 3863f237b0bSMatthew D Fleming MPI2_FW_DOWNLOAD_TCSGE tc; 3873f237b0bSMatthew D Fleming int error; 3883f237b0bSMatthew D Fleming 3893f237b0bSMatthew D Fleming /* 3903f237b0bSMatthew D Fleming * This code assumes there is room in the request's SGL for 3913f237b0bSMatthew D Fleming * the TransactionContext plus at least a SGL chain element. 3923f237b0bSMatthew D Fleming */ 3933f237b0bSMatthew D Fleming CTASSERT(sizeof req->SGL >= sizeof tc + MPS_SGC_SIZE); 394d95f15e7SMatthew D Fleming 395d95f15e7SMatthew D Fleming if (cmd->req_len != sizeof *req) 396d95f15e7SMatthew D Fleming return (EINVAL); 397d95f15e7SMatthew D Fleming if (cmd->rpl_len != sizeof *rpl) 398d95f15e7SMatthew D Fleming return (EINVAL); 399d95f15e7SMatthew D Fleming 4003f237b0bSMatthew D Fleming if (cmd->len == 0) 4013f237b0bSMatthew D Fleming return (EINVAL); 4023f237b0bSMatthew D Fleming 4033f237b0bSMatthew D Fleming error = copyin(cmd->buf, cm->cm_data, cmd->len); 4043f237b0bSMatthew D Fleming if (error != 0) 4053f237b0bSMatthew D Fleming return (error); 4063f237b0bSMatthew D Fleming 40713ac67a7SMatthew D Fleming mpi_init_sge(cm, req, &req->SGL); 4083f237b0bSMatthew D Fleming bzero(&tc, sizeof tc); 4093f237b0bSMatthew D Fleming 4103f237b0bSMatthew D Fleming /* 4113f237b0bSMatthew D Fleming * For now, the F/W image must be provided in a single request. 4123f237b0bSMatthew D Fleming */ 4133f237b0bSMatthew D Fleming if ((req->MsgFlags & MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT) == 0) 4143f237b0bSMatthew D Fleming return (EINVAL); 4153f237b0bSMatthew D Fleming if (req->TotalImageSize != cmd->len) 4163f237b0bSMatthew D Fleming return (EINVAL); 4173f237b0bSMatthew D Fleming 4183f237b0bSMatthew D Fleming /* 4193f237b0bSMatthew D Fleming * The value of the first two elements is specified in the 4203f237b0bSMatthew D Fleming * Fusion-MPT Message Passing Interface document. 4213f237b0bSMatthew D Fleming */ 4223f237b0bSMatthew D Fleming tc.ContextSize = 0; 4233f237b0bSMatthew D Fleming tc.DetailsLength = 12; 4243f237b0bSMatthew D Fleming tc.ImageOffset = 0; 4253f237b0bSMatthew D Fleming tc.ImageSize = cmd->len; 4263f237b0bSMatthew D Fleming 4273f237b0bSMatthew D Fleming cm->cm_flags |= MPS_CM_FLAGS_DATAOUT; 4283f237b0bSMatthew D Fleming 4293f237b0bSMatthew D Fleming return (mps_push_sge(cm, &tc, sizeof tc, 0)); 430d95f15e7SMatthew D Fleming } 431d95f15e7SMatthew D Fleming 432d95f15e7SMatthew D Fleming /* 433d95f15e7SMatthew D Fleming * Prepare the mps_command for a FW_UPLOAD request. 434d95f15e7SMatthew D Fleming */ 435d95f15e7SMatthew D Fleming static int 436d95f15e7SMatthew D Fleming mpi_pre_fw_upload(struct mps_command *cm, struct mps_usr_command *cmd) 437d95f15e7SMatthew D Fleming { 438d95f15e7SMatthew D Fleming MPI2_FW_UPLOAD_REQUEST *req = (void *)cm->cm_req; 439d95f15e7SMatthew D Fleming MPI2_FW_UPLOAD_REPLY *rpl; 44013ac67a7SMatthew D Fleming MPI2_FW_UPLOAD_TCSGE tc; 441d95f15e7SMatthew D Fleming 442d95f15e7SMatthew D Fleming /* 443d95f15e7SMatthew D Fleming * This code assumes there is room in the request's SGL for 444d95f15e7SMatthew D Fleming * the TransactionContext plus at least a SGL chain element. 445d95f15e7SMatthew D Fleming */ 44613ac67a7SMatthew D Fleming CTASSERT(sizeof req->SGL >= sizeof tc + MPS_SGC_SIZE); 447d95f15e7SMatthew D Fleming 448d95f15e7SMatthew D Fleming if (cmd->req_len != sizeof *req) 449d95f15e7SMatthew D Fleming return (EINVAL); 450d95f15e7SMatthew D Fleming if (cmd->rpl_len != sizeof *rpl) 451d95f15e7SMatthew D Fleming return (EINVAL); 452d95f15e7SMatthew D Fleming 45313ac67a7SMatthew D Fleming mpi_init_sge(cm, req, &req->SGL); 454d95f15e7SMatthew D Fleming if (cmd->len == 0) { 455d95f15e7SMatthew D Fleming /* Perhaps just asking what the size of the fw is? */ 456d95f15e7SMatthew D Fleming return (0); 457d95f15e7SMatthew D Fleming } 458d95f15e7SMatthew D Fleming 45913ac67a7SMatthew D Fleming bzero(&tc, sizeof tc); 460d95f15e7SMatthew D Fleming 461d95f15e7SMatthew D Fleming /* 462d95f15e7SMatthew D Fleming * The value of the first two elements is specified in the 463d95f15e7SMatthew D Fleming * Fusion-MPT Message Passing Interface document. 464d95f15e7SMatthew D Fleming */ 46513ac67a7SMatthew D Fleming tc.ContextSize = 0; 46613ac67a7SMatthew D Fleming tc.DetailsLength = 12; 467d95f15e7SMatthew D Fleming /* 468d95f15e7SMatthew D Fleming * XXX Is there any reason to fetch a partial image? I.e. to 469d95f15e7SMatthew D Fleming * set ImageOffset to something other than 0? 470d95f15e7SMatthew D Fleming */ 47113ac67a7SMatthew D Fleming tc.ImageOffset = 0; 47213ac67a7SMatthew D Fleming tc.ImageSize = cmd->len; 473d95f15e7SMatthew D Fleming 47413ac67a7SMatthew D Fleming return (mps_push_sge(cm, &tc, sizeof tc, 0)); 475d95f15e7SMatthew D Fleming } 476d95f15e7SMatthew D Fleming 477d95f15e7SMatthew D Fleming /* 478d95f15e7SMatthew D Fleming * Prepare the mps_command for a SATA_PASSTHROUGH request. 479d95f15e7SMatthew D Fleming */ 480d95f15e7SMatthew D Fleming static int 481d95f15e7SMatthew D Fleming mpi_pre_sata_passthrough(struct mps_command *cm, struct mps_usr_command *cmd) 482d95f15e7SMatthew D Fleming { 483d95f15e7SMatthew D Fleming MPI2_SATA_PASSTHROUGH_REQUEST *req = (void *)cm->cm_req; 484d95f15e7SMatthew D Fleming MPI2_SATA_PASSTHROUGH_REPLY *rpl; 485d95f15e7SMatthew D Fleming 486d95f15e7SMatthew D Fleming if (cmd->req_len != sizeof *req) 487d95f15e7SMatthew D Fleming return (EINVAL); 488d95f15e7SMatthew D Fleming if (cmd->rpl_len != sizeof *rpl) 489d95f15e7SMatthew D Fleming return (EINVAL); 490d95f15e7SMatthew D Fleming 49113ac67a7SMatthew D Fleming mpi_init_sge(cm, req, &req->SGL); 492d95f15e7SMatthew D Fleming return (0); 493d95f15e7SMatthew D Fleming } 494d95f15e7SMatthew D Fleming 495d95f15e7SMatthew D Fleming /* 496d95f15e7SMatthew D Fleming * Prepare the mps_command for a SMP_PASSTHROUGH request. 497d95f15e7SMatthew D Fleming */ 498d95f15e7SMatthew D Fleming static int 499d95f15e7SMatthew D Fleming mpi_pre_smp_passthrough(struct mps_command *cm, struct mps_usr_command *cmd) 500d95f15e7SMatthew D Fleming { 501d95f15e7SMatthew D Fleming MPI2_SMP_PASSTHROUGH_REQUEST *req = (void *)cm->cm_req; 502d95f15e7SMatthew D Fleming MPI2_SMP_PASSTHROUGH_REPLY *rpl; 503d95f15e7SMatthew D Fleming 504d95f15e7SMatthew D Fleming if (cmd->req_len != sizeof *req) 505d95f15e7SMatthew D Fleming return (EINVAL); 506d95f15e7SMatthew D Fleming if (cmd->rpl_len != sizeof *rpl) 507d95f15e7SMatthew D Fleming return (EINVAL); 508d95f15e7SMatthew D Fleming 50913ac67a7SMatthew D Fleming mpi_init_sge(cm, req, &req->SGL); 510d95f15e7SMatthew D Fleming return (0); 511d95f15e7SMatthew D Fleming } 512d95f15e7SMatthew D Fleming 513d95f15e7SMatthew D Fleming /* 514d95f15e7SMatthew D Fleming * Prepare the mps_command for a CONFIG request. 515d95f15e7SMatthew D Fleming */ 516d95f15e7SMatthew D Fleming static int 517d95f15e7SMatthew D Fleming mpi_pre_config(struct mps_command *cm, struct mps_usr_command *cmd) 518d95f15e7SMatthew D Fleming { 519d95f15e7SMatthew D Fleming MPI2_CONFIG_REQUEST *req = (void *)cm->cm_req; 520d95f15e7SMatthew D Fleming MPI2_CONFIG_REPLY *rpl; 521d95f15e7SMatthew D Fleming 522d95f15e7SMatthew D Fleming if (cmd->req_len != sizeof *req) 523d95f15e7SMatthew D Fleming return (EINVAL); 524d95f15e7SMatthew D Fleming if (cmd->rpl_len != sizeof *rpl) 525d95f15e7SMatthew D Fleming return (EINVAL); 526d95f15e7SMatthew D Fleming 52713ac67a7SMatthew D Fleming mpi_init_sge(cm, req, &req->PageBufferSGE); 528d95f15e7SMatthew D Fleming return (0); 529d95f15e7SMatthew D Fleming } 530d95f15e7SMatthew D Fleming 531d95f15e7SMatthew D Fleming /* 532d95f15e7SMatthew D Fleming * Prepare the mps_command for a SAS_IO_UNIT_CONTROL request. 533d95f15e7SMatthew D Fleming */ 534d95f15e7SMatthew D Fleming static int 535d95f15e7SMatthew D Fleming mpi_pre_sas_io_unit_control(struct mps_command *cm, 536d95f15e7SMatthew D Fleming struct mps_usr_command *cmd) 537d95f15e7SMatthew D Fleming { 538d95f15e7SMatthew D Fleming 539d95f15e7SMatthew D Fleming cm->cm_sge = NULL; 540d95f15e7SMatthew D Fleming cm->cm_sglsize = 0; 541d95f15e7SMatthew D Fleming return (0); 542d95f15e7SMatthew D Fleming } 543d95f15e7SMatthew D Fleming 544d95f15e7SMatthew D Fleming /* 545d95f15e7SMatthew D Fleming * A set of functions to prepare an mps_command for the various 546d95f15e7SMatthew D Fleming * supported requests. 547d95f15e7SMatthew D Fleming */ 548d3c7b9a0SKenneth D. Merry struct mps_user_func { 549d95f15e7SMatthew D Fleming U8 Function; 550d95f15e7SMatthew D Fleming mps_user_f *f_pre; 551d3c7b9a0SKenneth D. Merry } mps_user_func_list[] = { 552d95f15e7SMatthew D Fleming { MPI2_FUNCTION_IOC_FACTS, mpi_pre_ioc_facts }, 553d95f15e7SMatthew D Fleming { MPI2_FUNCTION_PORT_FACTS, mpi_pre_port_facts }, 554d95f15e7SMatthew D Fleming { MPI2_FUNCTION_FW_DOWNLOAD, mpi_pre_fw_download }, 555d95f15e7SMatthew D Fleming { MPI2_FUNCTION_FW_UPLOAD, mpi_pre_fw_upload }, 556d95f15e7SMatthew D Fleming { MPI2_FUNCTION_SATA_PASSTHROUGH, mpi_pre_sata_passthrough }, 557d95f15e7SMatthew D Fleming { MPI2_FUNCTION_SMP_PASSTHROUGH, mpi_pre_smp_passthrough}, 558d95f15e7SMatthew D Fleming { MPI2_FUNCTION_CONFIG, mpi_pre_config}, 559d95f15e7SMatthew D Fleming { MPI2_FUNCTION_SAS_IO_UNIT_CONTROL, mpi_pre_sas_io_unit_control }, 560d95f15e7SMatthew D Fleming { 0xFF, NULL } /* list end */ 561d3c7b9a0SKenneth D. Merry }; 562d3c7b9a0SKenneth D. Merry 563d3c7b9a0SKenneth D. Merry static int 564d95f15e7SMatthew D Fleming mps_user_setup_request(struct mps_command *cm, struct mps_usr_command *cmd) 565d3c7b9a0SKenneth D. Merry { 566d95f15e7SMatthew D Fleming MPI2_REQUEST_HEADER *hdr = (MPI2_REQUEST_HEADER *)cm->cm_req; 567d95f15e7SMatthew D Fleming struct mps_user_func *f; 568d3c7b9a0SKenneth D. Merry 569d95f15e7SMatthew D Fleming for (f = mps_user_func_list; f->f_pre != NULL; f++) { 570d95f15e7SMatthew D Fleming if (hdr->Function == f->Function) 571d95f15e7SMatthew D Fleming return (f->f_pre(cm, cmd)); 572d3c7b9a0SKenneth D. Merry } 573d95f15e7SMatthew D Fleming return (EINVAL); 574d3c7b9a0SKenneth D. Merry } 575d3c7b9a0SKenneth D. Merry 576d3c7b9a0SKenneth D. Merry static int 577d3c7b9a0SKenneth D. Merry mps_user_command(struct mps_softc *sc, struct mps_usr_command *cmd) 578d3c7b9a0SKenneth D. Merry { 579d3c7b9a0SKenneth D. Merry MPI2_REQUEST_HEADER *hdr; 580d3c7b9a0SKenneth D. Merry MPI2_DEFAULT_REPLY *rpl; 58101095e3bSMatthew D Fleming void *buf = NULL; 582*e658cceaSMatthew D Fleming struct mps_command *cm = NULL; 583d3c7b9a0SKenneth D. Merry int err = 0; 584d3c7b9a0SKenneth D. Merry int sz; 585d3c7b9a0SKenneth D. Merry 586d3c7b9a0SKenneth D. Merry mps_lock(sc); 587d3c7b9a0SKenneth D. Merry cm = mps_alloc_command(sc); 588d3c7b9a0SKenneth D. Merry 589d3c7b9a0SKenneth D. Merry if (cm == NULL) { 590d3c7b9a0SKenneth D. Merry mps_printf(sc, "mps_user_command: no mps requests\n"); 591d3c7b9a0SKenneth D. Merry err = ENOMEM; 592d3c7b9a0SKenneth D. Merry goto Ret; 593d3c7b9a0SKenneth D. Merry } 594d3c7b9a0SKenneth D. Merry mps_unlock(sc); 595d3c7b9a0SKenneth D. Merry 596d3c7b9a0SKenneth D. Merry hdr = (MPI2_REQUEST_HEADER *)cm->cm_req; 597d3c7b9a0SKenneth D. Merry 598d3c7b9a0SKenneth D. Merry mps_dprint(sc, MPS_INFO, "mps_user_command: req %p %d rpl %p %d\n", 599d3c7b9a0SKenneth D. Merry cmd->req, cmd->req_len, cmd->rpl, cmd->rpl_len ); 600d3c7b9a0SKenneth D. Merry 60101095e3bSMatthew D Fleming if (cmd->req_len > (int)sc->facts->IOCRequestFrameSize * 4) { 60201095e3bSMatthew D Fleming err = EINVAL; 60301095e3bSMatthew D Fleming goto RetFreeUnlocked; 60401095e3bSMatthew D Fleming } 60501095e3bSMatthew D Fleming err = copyin(cmd->req, hdr, cmd->req_len); 60601095e3bSMatthew D Fleming if (err != 0) 60701095e3bSMatthew D Fleming goto RetFreeUnlocked; 608d3c7b9a0SKenneth D. Merry 609d3c7b9a0SKenneth D. Merry mps_dprint(sc, MPS_INFO, "mps_user_command: Function %02X " 610d3c7b9a0SKenneth D. Merry "MsgFlags %02X\n", hdr->Function, hdr->MsgFlags ); 611d3c7b9a0SKenneth D. Merry 612d95f15e7SMatthew D Fleming err = mps_user_setup_request(cm, cmd); 613d3c7b9a0SKenneth D. Merry if (err != 0) { 614d3c7b9a0SKenneth D. Merry mps_printf(sc, "mps_user_command: unsupported function 0x%X\n", 615d3c7b9a0SKenneth D. Merry hdr->Function ); 61601095e3bSMatthew D Fleming goto RetFreeUnlocked; 617d3c7b9a0SKenneth D. Merry } 618d3c7b9a0SKenneth D. Merry 619d3c7b9a0SKenneth D. Merry if (cmd->len > 0) { 620d3c7b9a0SKenneth D. Merry buf = malloc(cmd->len, M_MPSUSER, M_WAITOK|M_ZERO); 621d3c7b9a0SKenneth D. Merry cm->cm_data = buf; 622d3c7b9a0SKenneth D. Merry cm->cm_length = cmd->len; 623d3c7b9a0SKenneth D. Merry } else { 624d3c7b9a0SKenneth D. Merry cm->cm_data = NULL; 625d3c7b9a0SKenneth D. Merry cm->cm_length = 0; 626d3c7b9a0SKenneth D. Merry } 627d3c7b9a0SKenneth D. Merry 628d3c7b9a0SKenneth D. Merry cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_WAKEUP; 629d3c7b9a0SKenneth D. Merry cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 630d3c7b9a0SKenneth D. Merry 631d3c7b9a0SKenneth D. Merry mps_lock(sc); 632d3c7b9a0SKenneth D. Merry err = mps_map_command(sc, cm); 633d3c7b9a0SKenneth D. Merry 634*e658cceaSMatthew D Fleming if (err != 0 && err != EINPROGRESS) { 635*e658cceaSMatthew D Fleming mps_printf(sc, "%s: invalid request: error %d\n", 636*e658cceaSMatthew D Fleming __func__, err); 637d3c7b9a0SKenneth D. Merry goto Ret; 638d3c7b9a0SKenneth D. Merry } 639*e658cceaSMatthew D Fleming msleep(cm, &sc->mps_mtx, 0, "mpsuser", 0); 640d3c7b9a0SKenneth D. Merry 641d3c7b9a0SKenneth D. Merry rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply; 642d3c7b9a0SKenneth D. Merry sz = rpl->MsgLength * 4; 643d3c7b9a0SKenneth D. Merry 644d3c7b9a0SKenneth D. Merry if (sz > cmd->rpl_len) { 645d3c7b9a0SKenneth D. Merry mps_printf(sc, 646d3c7b9a0SKenneth D. Merry "mps_user_command: reply buffer too small %d required %d\n", 647d3c7b9a0SKenneth D. Merry cmd->rpl_len, sz ); 648d3c7b9a0SKenneth D. Merry err = EINVAL; 649d3c7b9a0SKenneth D. Merry sz = cmd->rpl_len; 650d3c7b9a0SKenneth D. Merry } 651d3c7b9a0SKenneth D. Merry 652d3c7b9a0SKenneth D. Merry mps_unlock(sc); 653d3c7b9a0SKenneth D. Merry copyout(rpl, cmd->rpl, sz); 65401095e3bSMatthew D Fleming if (buf != NULL) 655d3c7b9a0SKenneth D. Merry copyout(buf, cmd->buf, cmd->len); 656d3c7b9a0SKenneth D. Merry mps_dprint(sc, MPS_INFO, "mps_user_command: reply size %d\n", sz ); 657d3c7b9a0SKenneth D. Merry 65801095e3bSMatthew D Fleming RetFreeUnlocked: 65901095e3bSMatthew D Fleming mps_lock(sc); 660*e658cceaSMatthew D Fleming if (cm != NULL) 66101095e3bSMatthew D Fleming mps_free_command(sc, cm); 662*e658cceaSMatthew D Fleming Ret: 66301095e3bSMatthew D Fleming mps_unlock(sc); 66401095e3bSMatthew D Fleming if (buf != NULL) 66501095e3bSMatthew D Fleming free(buf, M_MPSUSER); 66601095e3bSMatthew D Fleming return (err); 667d3c7b9a0SKenneth D. Merry } 668d3c7b9a0SKenneth D. Merry 669d3c7b9a0SKenneth D. Merry static int 6705ef98042SMatthew D Fleming mps_ioctl(struct cdev *dev, u_long cmd, void *arg, int flag, 671d3c7b9a0SKenneth D. Merry struct thread *td) 672d3c7b9a0SKenneth D. Merry { 673d3c7b9a0SKenneth D. Merry struct mps_softc *sc; 674d3c7b9a0SKenneth D. Merry struct mps_cfg_page_req *page_req; 675d3c7b9a0SKenneth D. Merry struct mps_ext_cfg_page_req *ext_page_req; 676d3c7b9a0SKenneth D. Merry void *mps_page; 677d3c7b9a0SKenneth D. Merry int error; 678d3c7b9a0SKenneth D. Merry 679d3c7b9a0SKenneth D. Merry mps_page = NULL; 680d3c7b9a0SKenneth D. Merry sc = dev->si_drv1; 681d3c7b9a0SKenneth D. Merry page_req = (void *)arg; 682d3c7b9a0SKenneth D. Merry ext_page_req = (void *)arg; 683d3c7b9a0SKenneth D. Merry 684d3c7b9a0SKenneth D. Merry switch (cmd) { 685d3c7b9a0SKenneth D. Merry case MPSIO_READ_CFG_HEADER: 686d3c7b9a0SKenneth D. Merry mps_lock(sc); 687d3c7b9a0SKenneth D. Merry error = mps_user_read_cfg_header(sc, page_req); 688d3c7b9a0SKenneth D. Merry mps_unlock(sc); 689d3c7b9a0SKenneth D. Merry break; 690d3c7b9a0SKenneth D. Merry case MPSIO_READ_CFG_PAGE: 691d3c7b9a0SKenneth D. Merry mps_page = malloc(page_req->len, M_MPSUSER, M_WAITOK | M_ZERO); 692d3c7b9a0SKenneth D. Merry error = copyin(page_req->buf, mps_page, 693d3c7b9a0SKenneth D. Merry sizeof(MPI2_CONFIG_PAGE_HEADER)); 694d3c7b9a0SKenneth D. Merry if (error) 695d3c7b9a0SKenneth D. Merry break; 696d3c7b9a0SKenneth D. Merry mps_lock(sc); 697d3c7b9a0SKenneth D. Merry error = mps_user_read_cfg_page(sc, page_req, mps_page); 698d3c7b9a0SKenneth D. Merry mps_unlock(sc); 699d3c7b9a0SKenneth D. Merry if (error) 700d3c7b9a0SKenneth D. Merry break; 701d3c7b9a0SKenneth D. Merry error = copyout(mps_page, page_req->buf, page_req->len); 702d3c7b9a0SKenneth D. Merry break; 703d3c7b9a0SKenneth D. Merry case MPSIO_READ_EXT_CFG_HEADER: 704d3c7b9a0SKenneth D. Merry mps_lock(sc); 705d3c7b9a0SKenneth D. Merry error = mps_user_read_extcfg_header(sc, ext_page_req); 706d3c7b9a0SKenneth D. Merry mps_unlock(sc); 707d3c7b9a0SKenneth D. Merry break; 708d3c7b9a0SKenneth D. Merry case MPSIO_READ_EXT_CFG_PAGE: 709d3c7b9a0SKenneth D. Merry mps_page = malloc(ext_page_req->len, M_MPSUSER, M_WAITOK|M_ZERO); 710d3c7b9a0SKenneth D. Merry error = copyin(ext_page_req->buf, mps_page, 711d3c7b9a0SKenneth D. Merry sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); 712d3c7b9a0SKenneth D. Merry if (error) 713d3c7b9a0SKenneth D. Merry break; 714d3c7b9a0SKenneth D. Merry mps_lock(sc); 715d3c7b9a0SKenneth D. Merry error = mps_user_read_extcfg_page(sc, ext_page_req, mps_page); 716d3c7b9a0SKenneth D. Merry mps_unlock(sc); 717d3c7b9a0SKenneth D. Merry if (error) 718d3c7b9a0SKenneth D. Merry break; 719d3c7b9a0SKenneth D. Merry error = copyout(mps_page, ext_page_req->buf, ext_page_req->len); 720d3c7b9a0SKenneth D. Merry break; 721d3c7b9a0SKenneth D. Merry case MPSIO_WRITE_CFG_PAGE: 722d3c7b9a0SKenneth D. Merry mps_page = malloc(page_req->len, M_MPSUSER, M_WAITOK|M_ZERO); 723d3c7b9a0SKenneth D. Merry error = copyin(page_req->buf, mps_page, page_req->len); 724d3c7b9a0SKenneth D. Merry if (error) 725d3c7b9a0SKenneth D. Merry break; 726d3c7b9a0SKenneth D. Merry mps_lock(sc); 727d3c7b9a0SKenneth D. Merry error = mps_user_write_cfg_page(sc, page_req, mps_page); 728d3c7b9a0SKenneth D. Merry mps_unlock(sc); 729d3c7b9a0SKenneth D. Merry break; 730d3c7b9a0SKenneth D. Merry case MPSIO_MPS_COMMAND: 731d3c7b9a0SKenneth D. Merry error = mps_user_command(sc, (struct mps_usr_command *)arg); 732d3c7b9a0SKenneth D. Merry break; 733d3c7b9a0SKenneth D. Merry default: 734d3c7b9a0SKenneth D. Merry error = ENOIOCTL; 735d3c7b9a0SKenneth D. Merry break; 736d3c7b9a0SKenneth D. Merry } 737d3c7b9a0SKenneth D. Merry 738d3c7b9a0SKenneth D. Merry if (mps_page != NULL) 739d3c7b9a0SKenneth D. Merry free(mps_page, M_MPSUSER); 740d3c7b9a0SKenneth D. Merry 741d3c7b9a0SKenneth D. Merry return (error); 7425ef98042SMatthew D Fleming } 743d3c7b9a0SKenneth D. Merry 7445ef98042SMatthew D Fleming #ifdef COMPAT_FREEBSD32 7455ef98042SMatthew D Fleming 7465ef98042SMatthew D Fleming /* Macros from compat/freebsd32/freebsd32.h */ 7475ef98042SMatthew D Fleming #define PTRIN(v) (void *)(uintptr_t)(v) 7485ef98042SMatthew D Fleming #define PTROUT(v) (uint32_t)(uintptr_t)(v) 7495ef98042SMatthew D Fleming 7505ef98042SMatthew D Fleming #define CP(src,dst,fld) do { (dst).fld = (src).fld; } while (0) 7515ef98042SMatthew D Fleming #define PTRIN_CP(src,dst,fld) \ 7525ef98042SMatthew D Fleming do { (dst).fld = PTRIN((src).fld); } while (0) 7535ef98042SMatthew D Fleming #define PTROUT_CP(src,dst,fld) \ 7545ef98042SMatthew D Fleming do { (dst).fld = PTROUT((src).fld); } while (0) 7555ef98042SMatthew D Fleming 7565ef98042SMatthew D Fleming struct mps_cfg_page_req32 { 7575ef98042SMatthew D Fleming MPI2_CONFIG_PAGE_HEADER header; 7585ef98042SMatthew D Fleming uint32_t page_address; 7595ef98042SMatthew D Fleming uint32_t buf; 7605ef98042SMatthew D Fleming int len; 7615ef98042SMatthew D Fleming uint16_t ioc_status; 7625ef98042SMatthew D Fleming }; 7635ef98042SMatthew D Fleming 7645ef98042SMatthew D Fleming struct mps_ext_cfg_page_req32 { 7655ef98042SMatthew D Fleming MPI2_CONFIG_EXTENDED_PAGE_HEADER header; 7665ef98042SMatthew D Fleming uint32_t page_address; 7675ef98042SMatthew D Fleming uint32_t buf; 7685ef98042SMatthew D Fleming int len; 7695ef98042SMatthew D Fleming uint16_t ioc_status; 7705ef98042SMatthew D Fleming }; 7715ef98042SMatthew D Fleming 7725ef98042SMatthew D Fleming struct mps_raid_action32 { 7735ef98042SMatthew D Fleming uint8_t action; 7745ef98042SMatthew D Fleming uint8_t volume_bus; 7755ef98042SMatthew D Fleming uint8_t volume_id; 7765ef98042SMatthew D Fleming uint8_t phys_disk_num; 7775ef98042SMatthew D Fleming uint32_t action_data_word; 7785ef98042SMatthew D Fleming uint32_t buf; 7795ef98042SMatthew D Fleming int len; 7805ef98042SMatthew D Fleming uint32_t volume_status; 7815ef98042SMatthew D Fleming uint32_t action_data[4]; 7825ef98042SMatthew D Fleming uint16_t action_status; 7835ef98042SMatthew D Fleming uint16_t ioc_status; 7845ef98042SMatthew D Fleming uint8_t write; 7855ef98042SMatthew D Fleming }; 7865ef98042SMatthew D Fleming 7875ef98042SMatthew D Fleming struct mps_usr_command32 { 7885ef98042SMatthew D Fleming uint32_t req; 7895ef98042SMatthew D Fleming uint32_t req_len; 7905ef98042SMatthew D Fleming uint32_t rpl; 7915ef98042SMatthew D Fleming uint32_t rpl_len; 7925ef98042SMatthew D Fleming uint32_t buf; 7935ef98042SMatthew D Fleming int len; 7945ef98042SMatthew D Fleming uint32_t flags; 7955ef98042SMatthew D Fleming }; 7965ef98042SMatthew D Fleming 7975ef98042SMatthew D Fleming #define MPSIO_READ_CFG_HEADER32 _IOWR('M', 200, struct mps_cfg_page_req32) 7985ef98042SMatthew D Fleming #define MPSIO_READ_CFG_PAGE32 _IOWR('M', 201, struct mps_cfg_page_req32) 7995ef98042SMatthew D Fleming #define MPSIO_READ_EXT_CFG_HEADER32 _IOWR('M', 202, struct mps_ext_cfg_page_req32) 8005ef98042SMatthew D Fleming #define MPSIO_READ_EXT_CFG_PAGE32 _IOWR('M', 203, struct mps_ext_cfg_page_req32) 8015ef98042SMatthew D Fleming #define MPSIO_WRITE_CFG_PAGE32 _IOWR('M', 204, struct mps_cfg_page_req32) 8025ef98042SMatthew D Fleming #define MPSIO_RAID_ACTION32 _IOWR('M', 205, struct mps_raid_action32) 8035ef98042SMatthew D Fleming #define MPSIO_MPS_COMMAND32 _IOWR('M', 210, struct mps_usr_command32) 8045ef98042SMatthew D Fleming 8055ef98042SMatthew D Fleming static int 8065ef98042SMatthew D Fleming mps_ioctl32(struct cdev *dev, u_long cmd32, void *_arg, int flag, 8075ef98042SMatthew D Fleming struct thread *td) 8085ef98042SMatthew D Fleming { 8095ef98042SMatthew D Fleming struct mps_cfg_page_req32 *page32 = _arg; 8105ef98042SMatthew D Fleming struct mps_ext_cfg_page_req32 *ext32 = _arg; 8115ef98042SMatthew D Fleming struct mps_raid_action32 *raid32 = _arg; 8125ef98042SMatthew D Fleming struct mps_usr_command32 *user32 = _arg; 8135ef98042SMatthew D Fleming union { 8145ef98042SMatthew D Fleming struct mps_cfg_page_req page; 8155ef98042SMatthew D Fleming struct mps_ext_cfg_page_req ext; 8165ef98042SMatthew D Fleming struct mps_raid_action raid; 8175ef98042SMatthew D Fleming struct mps_usr_command user; 8185ef98042SMatthew D Fleming } arg; 8195ef98042SMatthew D Fleming u_long cmd; 8205ef98042SMatthew D Fleming int error; 8215ef98042SMatthew D Fleming 8225ef98042SMatthew D Fleming switch (cmd32) { 823d3c7b9a0SKenneth D. Merry case MPSIO_READ_CFG_HEADER32: 824d3c7b9a0SKenneth D. Merry case MPSIO_READ_CFG_PAGE32: 825d3c7b9a0SKenneth D. Merry case MPSIO_WRITE_CFG_PAGE32: 8265ef98042SMatthew D Fleming if (cmd32 == MPSIO_READ_CFG_HEADER32) 8275ef98042SMatthew D Fleming cmd = MPSIO_READ_CFG_HEADER; 8285ef98042SMatthew D Fleming else if (cmd32 == MPSIO_READ_CFG_PAGE32) 8295ef98042SMatthew D Fleming cmd = MPSIO_READ_CFG_PAGE; 8305ef98042SMatthew D Fleming else 8315ef98042SMatthew D Fleming cmd = MPSIO_WRITE_CFG_PAGE; 8325ef98042SMatthew D Fleming CP(*page32, arg.page, header); 8335ef98042SMatthew D Fleming CP(*page32, arg.page, page_address); 8345ef98042SMatthew D Fleming PTRIN_CP(*page32, arg.page, buf); 8355ef98042SMatthew D Fleming CP(*page32, arg.page, len); 8365ef98042SMatthew D Fleming CP(*page32, arg.page, ioc_status); 837d3c7b9a0SKenneth D. Merry break; 8385ef98042SMatthew D Fleming 839d3c7b9a0SKenneth D. Merry case MPSIO_READ_EXT_CFG_HEADER32: 840d3c7b9a0SKenneth D. Merry case MPSIO_READ_EXT_CFG_PAGE32: 8415ef98042SMatthew D Fleming if (cmd32 == MPSIO_READ_EXT_CFG_HEADER32) 8425ef98042SMatthew D Fleming cmd = MPSIO_READ_EXT_CFG_HEADER; 8435ef98042SMatthew D Fleming else 8445ef98042SMatthew D Fleming cmd = MPSIO_READ_EXT_CFG_PAGE; 8455ef98042SMatthew D Fleming CP(*ext32, arg.ext, header); 8465ef98042SMatthew D Fleming CP(*ext32, arg.ext, page_address); 8475ef98042SMatthew D Fleming PTRIN_CP(*ext32, arg.ext, buf); 8485ef98042SMatthew D Fleming CP(*ext32, arg.ext, len); 8495ef98042SMatthew D Fleming CP(*ext32, arg.ext, ioc_status); 8505ef98042SMatthew D Fleming break; 8515ef98042SMatthew D Fleming 8525ef98042SMatthew D Fleming case MPSIO_RAID_ACTION32: 8535ef98042SMatthew D Fleming cmd = MPSIO_RAID_ACTION; 8545ef98042SMatthew D Fleming CP(*raid32, arg.raid, action); 8555ef98042SMatthew D Fleming CP(*raid32, arg.raid, volume_bus); 8565ef98042SMatthew D Fleming CP(*raid32, arg.raid, volume_id); 8575ef98042SMatthew D Fleming CP(*raid32, arg.raid, phys_disk_num); 8585ef98042SMatthew D Fleming CP(*raid32, arg.raid, action_data_word); 8595ef98042SMatthew D Fleming PTRIN_CP(*raid32, arg.raid, buf); 8605ef98042SMatthew D Fleming CP(*raid32, arg.raid, len); 8615ef98042SMatthew D Fleming CP(*raid32, arg.raid, volume_status); 8625ef98042SMatthew D Fleming bcopy(raid32->action_data, arg.raid.action_data, 8635ef98042SMatthew D Fleming sizeof arg.raid.action_data); 8645ef98042SMatthew D Fleming CP(*raid32, arg.raid, ioc_status); 8655ef98042SMatthew D Fleming CP(*raid32, arg.raid, write); 8665ef98042SMatthew D Fleming break; 8675ef98042SMatthew D Fleming 8685ef98042SMatthew D Fleming case MPSIO_MPS_COMMAND32: 8695ef98042SMatthew D Fleming cmd = MPSIO_MPS_COMMAND; 8705ef98042SMatthew D Fleming PTRIN_CP(*user32, arg.user, req); 8715ef98042SMatthew D Fleming CP(*user32, arg.user, req_len); 8725ef98042SMatthew D Fleming PTRIN_CP(*user32, arg.user, rpl); 8735ef98042SMatthew D Fleming CP(*user32, arg.user, rpl_len); 8745ef98042SMatthew D Fleming PTRIN_CP(*user32, arg.user, buf); 8755ef98042SMatthew D Fleming CP(*user32, arg.user, len); 8765ef98042SMatthew D Fleming CP(*user32, arg.user, flags); 877d3c7b9a0SKenneth D. Merry break; 878d3c7b9a0SKenneth D. Merry default: 879d3c7b9a0SKenneth D. Merry return (ENOIOCTL); 880d3c7b9a0SKenneth D. Merry } 881d3c7b9a0SKenneth D. Merry 8825ef98042SMatthew D Fleming error = mps_ioctl(dev, cmd, &arg, flag, td); 8835ef98042SMatthew D Fleming if (error == 0 && (cmd32 & IOC_OUT) != 0) { 8845ef98042SMatthew D Fleming switch (cmd32) { 8855ef98042SMatthew D Fleming case MPSIO_READ_CFG_HEADER32: 8865ef98042SMatthew D Fleming case MPSIO_READ_CFG_PAGE32: 8875ef98042SMatthew D Fleming case MPSIO_WRITE_CFG_PAGE32: 8885ef98042SMatthew D Fleming CP(arg.page, *page32, header); 8895ef98042SMatthew D Fleming CP(arg.page, *page32, page_address); 8905ef98042SMatthew D Fleming PTROUT_CP(arg.page, *page32, buf); 8915ef98042SMatthew D Fleming CP(arg.page, *page32, len); 8925ef98042SMatthew D Fleming CP(arg.page, *page32, ioc_status); 8935ef98042SMatthew D Fleming break; 8945ef98042SMatthew D Fleming 8955ef98042SMatthew D Fleming case MPSIO_READ_EXT_CFG_HEADER32: 8965ef98042SMatthew D Fleming case MPSIO_READ_EXT_CFG_PAGE32: 8975ef98042SMatthew D Fleming CP(arg.ext, *ext32, header); 8985ef98042SMatthew D Fleming CP(arg.ext, *ext32, page_address); 8995ef98042SMatthew D Fleming PTROUT_CP(arg.ext, *ext32, buf); 9005ef98042SMatthew D Fleming CP(arg.ext, *ext32, len); 9015ef98042SMatthew D Fleming CP(arg.ext, *ext32, ioc_status); 9025ef98042SMatthew D Fleming break; 9035ef98042SMatthew D Fleming 9045ef98042SMatthew D Fleming case MPSIO_RAID_ACTION32: 9055ef98042SMatthew D Fleming CP(arg.raid, *raid32, action); 9065ef98042SMatthew D Fleming CP(arg.raid, *raid32, volume_bus); 9075ef98042SMatthew D Fleming CP(arg.raid, *raid32, volume_id); 9085ef98042SMatthew D Fleming CP(arg.raid, *raid32, phys_disk_num); 9095ef98042SMatthew D Fleming CP(arg.raid, *raid32, action_data_word); 9105ef98042SMatthew D Fleming PTROUT_CP(arg.raid, *raid32, buf); 9115ef98042SMatthew D Fleming CP(arg.raid, *raid32, len); 9125ef98042SMatthew D Fleming CP(arg.raid, *raid32, volume_status); 9135ef98042SMatthew D Fleming bcopy(arg.raid.action_data, raid32->action_data, 9145ef98042SMatthew D Fleming sizeof arg.raid.action_data); 9155ef98042SMatthew D Fleming CP(arg.raid, *raid32, ioc_status); 9165ef98042SMatthew D Fleming CP(arg.raid, *raid32, write); 9175ef98042SMatthew D Fleming break; 9185ef98042SMatthew D Fleming 9195ef98042SMatthew D Fleming case MPSIO_MPS_COMMAND32: 9205ef98042SMatthew D Fleming PTROUT_CP(arg.user, *user32, req); 9215ef98042SMatthew D Fleming CP(arg.user, *user32, req_len); 9225ef98042SMatthew D Fleming PTROUT_CP(arg.user, *user32, rpl); 9235ef98042SMatthew D Fleming CP(arg.user, *user32, rpl_len); 9245ef98042SMatthew D Fleming PTROUT_CP(arg.user, *user32, buf); 9255ef98042SMatthew D Fleming CP(arg.user, *user32, len); 9265ef98042SMatthew D Fleming CP(arg.user, *user32, flags); 9275ef98042SMatthew D Fleming break; 9285ef98042SMatthew D Fleming } 9295ef98042SMatthew D Fleming } 9305ef98042SMatthew D Fleming 9315ef98042SMatthew D Fleming return (error); 9325ef98042SMatthew D Fleming } 9335ef98042SMatthew D Fleming #endif /* COMPAT_FREEBSD32 */ 9345ef98042SMatthew D Fleming 9355ef98042SMatthew D Fleming static int 9365ef98042SMatthew D Fleming mps_ioctl_devsw(struct cdev *dev, u_long com, caddr_t arg, int flag, 9375ef98042SMatthew D Fleming struct thread *td) 9385ef98042SMatthew D Fleming { 9395ef98042SMatthew D Fleming #ifdef COMPAT_FREEBSD32 9405ef98042SMatthew D Fleming if (SV_CURPROC_FLAG(SV_ILP32)) 9415ef98042SMatthew D Fleming return (mps_ioctl32(dev, com, arg, flag, td)); 9425ef98042SMatthew D Fleming #endif 9435ef98042SMatthew D Fleming return (mps_ioctl(dev, com, arg, flag, td)); 944d3c7b9a0SKenneth D. Merry } 945