The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/mps/mps_user.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-3-Clause
    3  *
    4  * Copyright (c) 2008 Yahoo!, Inc.
    5  * All rights reserved.
    6  * Written by: John Baldwin <jhb@FreeBSD.org>
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. Neither the name of the author nor the names of any co-contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  *
   32  * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD userland interface
   33  */
   34 /*-
   35  * Copyright (c) 2011-2015 LSI Corp.
   36  * Copyright (c) 2013-2015 Avago Technologies
   37  * All rights reserved.
   38  *
   39  * Redistribution and use in source and binary forms, with or without
   40  * modification, are permitted provided that the following conditions
   41  * are met:
   42  * 1. Redistributions of source code must retain the above copyright
   43  *    notice, this list of conditions and the following disclaimer.
   44  * 2. Redistributions in binary form must reproduce the above copyright
   45  *    notice, this list of conditions and the following disclaimer in the
   46  *    documentation and/or other materials provided with the distribution.
   47  *
   48  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   49  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   50  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   51  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   52  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   53  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   54  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   55  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   56  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   57  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   58  * SUCH DAMAGE.
   59  *
   60  * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
   61  *
   62  * $FreeBSD: releng/12.0/sys/dev/mps/mps_user.c 332122 2018-04-06 17:35:35Z brooks $
   63  */
   64 
   65 #include <sys/cdefs.h>
   66 __FBSDID("$FreeBSD: releng/12.0/sys/dev/mps/mps_user.c 332122 2018-04-06 17:35:35Z brooks $");
   67 
   68 /* TODO Move headers to mpsvar */
   69 #include <sys/types.h>
   70 #include <sys/param.h>
   71 #include <sys/systm.h>
   72 #include <sys/kernel.h>
   73 #include <sys/selinfo.h>
   74 #include <sys/module.h>
   75 #include <sys/bus.h>
   76 #include <sys/conf.h>
   77 #include <sys/bio.h>
   78 #include <sys/malloc.h>
   79 #include <sys/uio.h>
   80 #include <sys/sysctl.h>
   81 #include <sys/ioccom.h>
   82 #include <sys/endian.h>
   83 #include <sys/queue.h>
   84 #include <sys/kthread.h>
   85 #include <sys/taskqueue.h>
   86 #include <sys/proc.h>
   87 #include <sys/sysent.h>
   88 
   89 #include <machine/bus.h>
   90 #include <machine/resource.h>
   91 #include <sys/rman.h>
   92 
   93 #include <cam/cam.h>
   94 #include <cam/cam_ccb.h>
   95 #include <cam/scsi/scsi_all.h>
   96 
   97 #include <dev/mps/mpi/mpi2_type.h>
   98 #include <dev/mps/mpi/mpi2.h>
   99 #include <dev/mps/mpi/mpi2_ioc.h>
  100 #include <dev/mps/mpi/mpi2_cnfg.h>
  101 #include <dev/mps/mpi/mpi2_init.h>
  102 #include <dev/mps/mpi/mpi2_tool.h>
  103 #include <dev/mps/mps_ioctl.h>
  104 #include <dev/mps/mpsvar.h>
  105 #include <dev/mps/mps_table.h>
  106 #include <dev/mps/mps_sas.h>
  107 #include <dev/pci/pcivar.h>
  108 #include <dev/pci/pcireg.h>
  109 
  110 static d_open_t         mps_open;
  111 static d_close_t        mps_close;
  112 static d_ioctl_t        mps_ioctl_devsw;
  113 
  114 static struct cdevsw mps_cdevsw = {
  115         .d_version =    D_VERSION,
  116         .d_flags =      0,
  117         .d_open =       mps_open,
  118         .d_close =      mps_close,
  119         .d_ioctl =      mps_ioctl_devsw,
  120         .d_name =       "mps",
  121 };
  122 
  123 typedef int (mps_user_f)(struct mps_command *, struct mps_usr_command *);
  124 static mps_user_f       mpi_pre_ioc_facts;
  125 static mps_user_f       mpi_pre_port_facts;
  126 static mps_user_f       mpi_pre_fw_download;
  127 static mps_user_f       mpi_pre_fw_upload;
  128 static mps_user_f       mpi_pre_sata_passthrough;
  129 static mps_user_f       mpi_pre_smp_passthrough;
  130 static mps_user_f       mpi_pre_config;
  131 static mps_user_f       mpi_pre_sas_io_unit_control;
  132 
  133 static int mps_user_read_cfg_header(struct mps_softc *,
  134                                     struct mps_cfg_page_req *);
  135 static int mps_user_read_cfg_page(struct mps_softc *,
  136                                   struct mps_cfg_page_req *, void *);
  137 static int mps_user_read_extcfg_header(struct mps_softc *,
  138                                      struct mps_ext_cfg_page_req *);
  139 static int mps_user_read_extcfg_page(struct mps_softc *,
  140                                      struct mps_ext_cfg_page_req *, void *);
  141 static int mps_user_write_cfg_page(struct mps_softc *,
  142                                    struct mps_cfg_page_req *, void *);
  143 static int mps_user_setup_request(struct mps_command *,
  144                                   struct mps_usr_command *);
  145 static int mps_user_command(struct mps_softc *, struct mps_usr_command *);
  146 
  147 static int mps_user_pass_thru(struct mps_softc *sc, mps_pass_thru_t *data);
  148 static void mps_user_get_adapter_data(struct mps_softc *sc,
  149     mps_adapter_data_t *data);
  150 static void mps_user_read_pci_info(struct mps_softc *sc,
  151     mps_pci_info_t *data);
  152 static uint8_t mps_get_fw_diag_buffer_number(struct mps_softc *sc,
  153     uint32_t unique_id);
  154 static int mps_post_fw_diag_buffer(struct mps_softc *sc,
  155     mps_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code);
  156 static int mps_release_fw_diag_buffer(struct mps_softc *sc,
  157     mps_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code,
  158     uint32_t diag_type);
  159 static int mps_diag_register(struct mps_softc *sc,
  160     mps_fw_diag_register_t *diag_register, uint32_t *return_code);
  161 static int mps_diag_unregister(struct mps_softc *sc,
  162     mps_fw_diag_unregister_t *diag_unregister, uint32_t *return_code);
  163 static int mps_diag_query(struct mps_softc *sc, mps_fw_diag_query_t *diag_query,
  164     uint32_t *return_code);
  165 static int mps_diag_read_buffer(struct mps_softc *sc,
  166     mps_diag_read_buffer_t *diag_read_buffer, uint8_t *ioctl_buf,
  167     uint32_t *return_code);
  168 static int mps_diag_release(struct mps_softc *sc,
  169     mps_fw_diag_release_t *diag_release, uint32_t *return_code);
  170 static int mps_do_diag_action(struct mps_softc *sc, uint32_t action,
  171     uint8_t *diag_action, uint32_t length, uint32_t *return_code);
  172 static int mps_user_diag_action(struct mps_softc *sc, mps_diag_action_t *data);
  173 static void mps_user_event_query(struct mps_softc *sc, mps_event_query_t *data);
  174 static void mps_user_event_enable(struct mps_softc *sc,
  175     mps_event_enable_t *data);
  176 static int mps_user_event_report(struct mps_softc *sc,
  177     mps_event_report_t *data);
  178 static int mps_user_reg_access(struct mps_softc *sc, mps_reg_access_t *data);
  179 static int mps_user_btdh(struct mps_softc *sc, mps_btdh_mapping_t *data);
  180 
  181 MALLOC_DEFINE(M_MPSUSER, "mps_user", "Buffers for mps(4) ioctls");
  182 
  183 /* Macros from compat/freebsd32/freebsd32.h */
  184 #define PTRIN(v)        (void *)(uintptr_t)(v)
  185 #define PTROUT(v)       (uint32_t)(uintptr_t)(v)
  186 
  187 #define CP(src,dst,fld) do { (dst).fld = (src).fld; } while (0)
  188 #define PTRIN_CP(src,dst,fld)                           \
  189         do { (dst).fld = PTRIN((src).fld); } while (0)
  190 #define PTROUT_CP(src,dst,fld) \
  191         do { (dst).fld = PTROUT((src).fld); } while (0)
  192 
  193 int
  194 mps_attach_user(struct mps_softc *sc)
  195 {
  196         int unit;
  197 
  198         unit = device_get_unit(sc->mps_dev);
  199         sc->mps_cdev = make_dev(&mps_cdevsw, unit, UID_ROOT, GID_OPERATOR, 0640,
  200             "mps%d", unit);
  201         if (sc->mps_cdev == NULL) {
  202                 return (ENOMEM);
  203         }
  204         sc->mps_cdev->si_drv1 = sc;
  205         return (0);
  206 }
  207 
  208 void
  209 mps_detach_user(struct mps_softc *sc)
  210 {
  211 
  212         /* XXX: do a purge of pending requests? */
  213         if (sc->mps_cdev != NULL)
  214                 destroy_dev(sc->mps_cdev);
  215 }
  216 
  217 static int
  218 mps_open(struct cdev *dev, int flags, int fmt, struct thread *td)
  219 {
  220 
  221         return (0);
  222 }
  223 
  224 static int
  225 mps_close(struct cdev *dev, int flags, int fmt, struct thread *td)
  226 {
  227 
  228         return (0);
  229 }
  230 
  231 static int
  232 mps_user_read_cfg_header(struct mps_softc *sc,
  233     struct mps_cfg_page_req *page_req)
  234 {
  235         MPI2_CONFIG_PAGE_HEADER *hdr;
  236         struct mps_config_params params;
  237         int         error;
  238 
  239         hdr = &params.hdr.Struct;
  240         params.action = MPI2_CONFIG_ACTION_PAGE_HEADER;
  241         params.page_address = le32toh(page_req->page_address);
  242         hdr->PageVersion = 0;
  243         hdr->PageLength = 0;
  244         hdr->PageNumber = page_req->header.PageNumber;
  245         hdr->PageType = page_req->header.PageType;
  246         params.buffer = NULL;
  247         params.length = 0;
  248         params.callback = NULL;
  249 
  250         if ((error = mps_read_config_page(sc, &params)) != 0) {
  251                 /*
  252                  * Leave the request. Without resetting the chip, it's
  253                  * still owned by it and we'll just get into trouble
  254                  * freeing it now. Mark it as abandoned so that if it
  255                  * shows up later it can be freed.
  256                  */
  257                 mps_printf(sc, "read_cfg_header timed out\n");
  258                 return (ETIMEDOUT);
  259         }
  260 
  261         page_req->ioc_status = htole16(params.status);
  262         if ((page_req->ioc_status & MPI2_IOCSTATUS_MASK) ==
  263             MPI2_IOCSTATUS_SUCCESS) {
  264                 bcopy(hdr, &page_req->header, sizeof(page_req->header));
  265         }
  266 
  267         return (0);
  268 }
  269 
  270 static int
  271 mps_user_read_cfg_page(struct mps_softc *sc, struct mps_cfg_page_req *page_req,
  272     void *buf)
  273 {
  274         MPI2_CONFIG_PAGE_HEADER *reqhdr, *hdr;
  275         struct mps_config_params params;
  276         int           error;
  277 
  278         reqhdr = buf;
  279         hdr = &params.hdr.Struct;
  280         hdr->PageVersion = reqhdr->PageVersion;
  281         hdr->PageLength = reqhdr->PageLength;
  282         hdr->PageNumber = reqhdr->PageNumber;
  283         hdr->PageType = reqhdr->PageType & MPI2_CONFIG_PAGETYPE_MASK;
  284         params.action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
  285         params.page_address = le32toh(page_req->page_address);
  286         params.buffer = buf;
  287         params.length = le32toh(page_req->len);
  288         params.callback = NULL;
  289 
  290         if ((error = mps_read_config_page(sc, &params)) != 0) {
  291                 mps_printf(sc, "mps_user_read_cfg_page timed out\n");
  292                 return (ETIMEDOUT);
  293         }
  294 
  295         page_req->ioc_status = htole16(params.status);
  296         return (0);
  297 }
  298 
  299 static int
  300 mps_user_read_extcfg_header(struct mps_softc *sc,
  301     struct mps_ext_cfg_page_req *ext_page_req)
  302 {
  303         MPI2_CONFIG_EXTENDED_PAGE_HEADER *hdr;
  304         struct mps_config_params params;
  305         int         error;
  306 
  307         hdr = &params.hdr.Ext;
  308         params.action = MPI2_CONFIG_ACTION_PAGE_HEADER;
  309         hdr->PageVersion = ext_page_req->header.PageVersion;
  310         hdr->PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
  311         hdr->ExtPageLength = 0;
  312         hdr->PageNumber = ext_page_req->header.PageNumber;
  313         hdr->ExtPageType = ext_page_req->header.ExtPageType;
  314         params.page_address = le32toh(ext_page_req->page_address);
  315         params.buffer = NULL;
  316         params.length = 0;
  317         params.callback = NULL;
  318 
  319         if ((error = mps_read_config_page(sc, &params)) != 0) {
  320                 /*
  321                  * Leave the request. Without resetting the chip, it's
  322                  * still owned by it and we'll just get into trouble
  323                  * freeing it now. Mark it as abandoned so that if it
  324                  * shows up later it can be freed.
  325                  */
  326                 mps_printf(sc, "mps_user_read_extcfg_header timed out\n");
  327                 return (ETIMEDOUT);
  328         }
  329 
  330         ext_page_req->ioc_status = htole16(params.status);
  331         if ((ext_page_req->ioc_status & MPI2_IOCSTATUS_MASK) ==
  332             MPI2_IOCSTATUS_SUCCESS) {
  333                 ext_page_req->header.PageVersion = hdr->PageVersion;
  334                 ext_page_req->header.PageNumber = hdr->PageNumber;
  335                 ext_page_req->header.PageType = hdr->PageType;
  336                 ext_page_req->header.ExtPageLength = hdr->ExtPageLength;
  337                 ext_page_req->header.ExtPageType = hdr->ExtPageType;
  338         }
  339 
  340         return (0);
  341 }
  342 
  343 static int
  344 mps_user_read_extcfg_page(struct mps_softc *sc,
  345     struct mps_ext_cfg_page_req *ext_page_req, void *buf)
  346 {
  347         MPI2_CONFIG_EXTENDED_PAGE_HEADER *reqhdr, *hdr;
  348         struct mps_config_params params;
  349         int error;
  350 
  351         reqhdr = buf;
  352         hdr = &params.hdr.Ext;
  353         params.action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
  354         params.page_address = le32toh(ext_page_req->page_address);
  355         hdr->PageVersion = reqhdr->PageVersion;
  356         hdr->PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
  357         hdr->PageNumber = reqhdr->PageNumber;
  358         hdr->ExtPageType = reqhdr->ExtPageType;
  359         hdr->ExtPageLength = reqhdr->ExtPageLength;
  360         params.buffer = buf;
  361         params.length = le32toh(ext_page_req->len);
  362         params.callback = NULL;
  363 
  364         if ((error = mps_read_config_page(sc, &params)) != 0) {
  365                 mps_printf(sc, "mps_user_read_extcfg_page timed out\n");
  366                 return (ETIMEDOUT);
  367         }
  368 
  369         ext_page_req->ioc_status = htole16(params.status);
  370         return (0);
  371 }
  372 
  373 static int
  374 mps_user_write_cfg_page(struct mps_softc *sc,
  375     struct mps_cfg_page_req *page_req, void *buf)
  376 {
  377         MPI2_CONFIG_PAGE_HEADER *reqhdr, *hdr;
  378         struct mps_config_params params;
  379         u_int         hdr_attr;
  380         int           error;
  381 
  382         reqhdr = buf;
  383         hdr = &params.hdr.Struct;
  384         hdr_attr = reqhdr->PageType & MPI2_CONFIG_PAGEATTR_MASK;
  385         if (hdr_attr != MPI2_CONFIG_PAGEATTR_CHANGEABLE &&
  386             hdr_attr != MPI2_CONFIG_PAGEATTR_PERSISTENT) {
  387                 mps_printf(sc, "page type 0x%x not changeable\n",
  388                         reqhdr->PageType & MPI2_CONFIG_PAGETYPE_MASK);
  389                 return (EINVAL);
  390         }
  391 
  392         /*
  393          * There isn't any point in restoring stripped out attributes
  394          * if you then mask them going down to issue the request.
  395          */
  396 
  397         hdr->PageVersion = reqhdr->PageVersion;
  398         hdr->PageLength = reqhdr->PageLength;
  399         hdr->PageNumber = reqhdr->PageNumber;
  400         hdr->PageType = reqhdr->PageType;
  401         params.action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT;
  402         params.page_address = le32toh(page_req->page_address);
  403         params.buffer = buf;
  404         params.length = le32toh(page_req->len);
  405         params.callback = NULL;
  406 
  407         if ((error = mps_write_config_page(sc, &params)) != 0) {
  408                 mps_printf(sc, "mps_write_cfg_page timed out\n");
  409                 return (ETIMEDOUT);
  410         }
  411 
  412         page_req->ioc_status = htole16(params.status);
  413         return (0);
  414 }
  415 
  416 void
  417 mpi_init_sge(struct mps_command *cm, void *req, void *sge)
  418 {
  419         int off, space;
  420 
  421         space = (int)cm->cm_sc->reqframesz;
  422         off = (uintptr_t)sge - (uintptr_t)req;
  423 
  424         KASSERT(off < space, ("bad pointers %p %p, off %d, space %d",
  425             req, sge, off, space));
  426 
  427         cm->cm_sge = sge;
  428         cm->cm_sglsize = space - off;
  429 }
  430 
  431 /*
  432  * Prepare the mps_command for an IOC_FACTS request.
  433  */
  434 static int
  435 mpi_pre_ioc_facts(struct mps_command *cm, struct mps_usr_command *cmd)
  436 {
  437         MPI2_IOC_FACTS_REQUEST *req = (void *)cm->cm_req;
  438         MPI2_IOC_FACTS_REPLY *rpl;
  439 
  440         if (cmd->req_len != sizeof *req)
  441                 return (EINVAL);
  442         if (cmd->rpl_len != sizeof *rpl)
  443                 return (EINVAL);
  444 
  445         cm->cm_sge = NULL;
  446         cm->cm_sglsize = 0;
  447         return (0);
  448 }
  449 
  450 /*
  451  * Prepare the mps_command for a PORT_FACTS request.
  452  */
  453 static int
  454 mpi_pre_port_facts(struct mps_command *cm, struct mps_usr_command *cmd)
  455 {
  456         MPI2_PORT_FACTS_REQUEST *req = (void *)cm->cm_req;
  457         MPI2_PORT_FACTS_REPLY *rpl;
  458 
  459         if (cmd->req_len != sizeof *req)
  460                 return (EINVAL);
  461         if (cmd->rpl_len != sizeof *rpl)
  462                 return (EINVAL);
  463 
  464         cm->cm_sge = NULL;
  465         cm->cm_sglsize = 0;
  466         return (0);
  467 }
  468 
  469 /*
  470  * Prepare the mps_command for a FW_DOWNLOAD request.
  471  */
  472 static int
  473 mpi_pre_fw_download(struct mps_command *cm, struct mps_usr_command *cmd)
  474 {
  475         MPI2_FW_DOWNLOAD_REQUEST *req = (void *)cm->cm_req;
  476         MPI2_FW_DOWNLOAD_REPLY *rpl;
  477         MPI2_FW_DOWNLOAD_TCSGE tc;
  478         int error;
  479 
  480         /*
  481          * This code assumes there is room in the request's SGL for
  482          * the TransactionContext plus at least a SGL chain element.
  483          */
  484         CTASSERT(sizeof req->SGL >= sizeof tc + MPS_SGC_SIZE);
  485 
  486         if (cmd->req_len != sizeof *req)
  487                 return (EINVAL);
  488         if (cmd->rpl_len != sizeof *rpl)
  489                 return (EINVAL);
  490 
  491         if (cmd->len == 0)
  492                 return (EINVAL);
  493 
  494         error = copyin(cmd->buf, cm->cm_data, cmd->len);
  495         if (error != 0)
  496                 return (error);
  497 
  498         mpi_init_sge(cm, req, &req->SGL);
  499         bzero(&tc, sizeof tc);
  500 
  501         /*
  502          * For now, the F/W image must be provided in a single request.
  503          */
  504         if ((req->MsgFlags & MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT) == 0)
  505                 return (EINVAL);
  506         if (req->TotalImageSize != cmd->len)
  507                 return (EINVAL);
  508 
  509         /*
  510          * The value of the first two elements is specified in the
  511          * Fusion-MPT Message Passing Interface document.
  512          */
  513         tc.ContextSize = 0;
  514         tc.DetailsLength = 12;
  515         tc.ImageOffset = 0;
  516         tc.ImageSize = cmd->len;
  517 
  518         cm->cm_flags |= MPS_CM_FLAGS_DATAOUT;
  519 
  520         return (mps_push_sge(cm, &tc, sizeof tc, 0));
  521 }
  522 
  523 /*
  524  * Prepare the mps_command for a FW_UPLOAD request.
  525  */
  526 static int
  527 mpi_pre_fw_upload(struct mps_command *cm, struct mps_usr_command *cmd)
  528 {
  529         MPI2_FW_UPLOAD_REQUEST *req = (void *)cm->cm_req;
  530         MPI2_FW_UPLOAD_REPLY *rpl;
  531         MPI2_FW_UPLOAD_TCSGE tc;
  532 
  533         /*
  534          * This code assumes there is room in the request's SGL for
  535          * the TransactionContext plus at least a SGL chain element.
  536          */
  537         CTASSERT(sizeof req->SGL >= sizeof tc + MPS_SGC_SIZE);
  538 
  539         if (cmd->req_len != sizeof *req)
  540                 return (EINVAL);
  541         if (cmd->rpl_len != sizeof *rpl)
  542                 return (EINVAL);
  543 
  544         mpi_init_sge(cm, req, &req->SGL);
  545         bzero(&tc, sizeof tc);
  546 
  547         /*
  548          * The value of the first two elements is specified in the
  549          * Fusion-MPT Message Passing Interface document.
  550          */
  551         tc.ContextSize = 0;
  552         tc.DetailsLength = 12;
  553         /*
  554          * XXX Is there any reason to fetch a partial image?  I.e. to
  555          * set ImageOffset to something other than 0?
  556          */
  557         tc.ImageOffset = 0;
  558         tc.ImageSize = cmd->len;
  559 
  560         cm->cm_flags |= MPS_CM_FLAGS_DATAIN;
  561 
  562         return (mps_push_sge(cm, &tc, sizeof tc, 0));
  563 }
  564 
  565 /*
  566  * Prepare the mps_command for a SATA_PASSTHROUGH request.
  567  */
  568 static int
  569 mpi_pre_sata_passthrough(struct mps_command *cm, struct mps_usr_command *cmd)
  570 {
  571         MPI2_SATA_PASSTHROUGH_REQUEST *req = (void *)cm->cm_req;
  572         MPI2_SATA_PASSTHROUGH_REPLY *rpl;
  573 
  574         if (cmd->req_len != sizeof *req)
  575                 return (EINVAL);
  576         if (cmd->rpl_len != sizeof *rpl)
  577                 return (EINVAL);
  578 
  579         mpi_init_sge(cm, req, &req->SGL);
  580         return (0);
  581 }
  582 
  583 /*
  584  * Prepare the mps_command for a SMP_PASSTHROUGH request.
  585  */
  586 static int
  587 mpi_pre_smp_passthrough(struct mps_command *cm, struct mps_usr_command *cmd)
  588 {
  589         MPI2_SMP_PASSTHROUGH_REQUEST *req = (void *)cm->cm_req;
  590         MPI2_SMP_PASSTHROUGH_REPLY *rpl;
  591 
  592         if (cmd->req_len != sizeof *req)
  593                 return (EINVAL);
  594         if (cmd->rpl_len != sizeof *rpl)
  595                 return (EINVAL);
  596 
  597         mpi_init_sge(cm, req, &req->SGL);
  598         return (0);
  599 }
  600 
  601 /*
  602  * Prepare the mps_command for a CONFIG request.
  603  */
  604 static int
  605 mpi_pre_config(struct mps_command *cm, struct mps_usr_command *cmd)
  606 {
  607         MPI2_CONFIG_REQUEST *req = (void *)cm->cm_req;
  608         MPI2_CONFIG_REPLY *rpl;
  609 
  610         if (cmd->req_len != sizeof *req)
  611                 return (EINVAL);
  612         if (cmd->rpl_len != sizeof *rpl)
  613                 return (EINVAL);
  614 
  615         mpi_init_sge(cm, req, &req->PageBufferSGE);
  616         return (0);
  617 }
  618 
  619 /*
  620  * Prepare the mps_command for a SAS_IO_UNIT_CONTROL request.
  621  */
  622 static int
  623 mpi_pre_sas_io_unit_control(struct mps_command *cm,
  624                              struct mps_usr_command *cmd)
  625 {
  626 
  627         cm->cm_sge = NULL;
  628         cm->cm_sglsize = 0;
  629         return (0);
  630 }
  631 
  632 /*
  633  * A set of functions to prepare an mps_command for the various
  634  * supported requests.
  635  */
  636 struct mps_user_func {
  637         U8              Function;
  638         mps_user_f      *f_pre;
  639 } mps_user_func_list[] = {
  640         { MPI2_FUNCTION_IOC_FACTS,              mpi_pre_ioc_facts },
  641         { MPI2_FUNCTION_PORT_FACTS,             mpi_pre_port_facts },
  642         { MPI2_FUNCTION_FW_DOWNLOAD,            mpi_pre_fw_download },
  643         { MPI2_FUNCTION_FW_UPLOAD,              mpi_pre_fw_upload },
  644         { MPI2_FUNCTION_SATA_PASSTHROUGH,       mpi_pre_sata_passthrough },
  645         { MPI2_FUNCTION_SMP_PASSTHROUGH,        mpi_pre_smp_passthrough},
  646         { MPI2_FUNCTION_CONFIG,                 mpi_pre_config},
  647         { MPI2_FUNCTION_SAS_IO_UNIT_CONTROL,    mpi_pre_sas_io_unit_control },
  648         { 0xFF,                                 NULL } /* list end */
  649 };
  650 
  651 static int
  652 mps_user_setup_request(struct mps_command *cm, struct mps_usr_command *cmd)
  653 {
  654         MPI2_REQUEST_HEADER *hdr = (MPI2_REQUEST_HEADER *)cm->cm_req;   
  655         struct mps_user_func *f;
  656 
  657         for (f = mps_user_func_list; f->f_pre != NULL; f++) {
  658                 if (hdr->Function == f->Function)
  659                         return (f->f_pre(cm, cmd));
  660         }
  661         return (EINVAL);
  662 }       
  663 
  664 static int
  665 mps_user_command(struct mps_softc *sc, struct mps_usr_command *cmd)
  666 {
  667         MPI2_REQUEST_HEADER *hdr;       
  668         MPI2_DEFAULT_REPLY *rpl;
  669         void *buf = NULL;
  670         struct mps_command *cm = NULL;
  671         int err = 0;
  672         int sz;
  673 
  674         mps_lock(sc);
  675         cm = mps_alloc_command(sc);
  676 
  677         if (cm == NULL) {
  678                 mps_printf(sc, "%s: no mps requests\n", __func__);
  679                 err = ENOMEM;
  680                 goto RetFree;
  681         }
  682         mps_unlock(sc);
  683 
  684         hdr = (MPI2_REQUEST_HEADER *)cm->cm_req;
  685 
  686         mps_dprint(sc, MPS_USER, "%s: req %p %d  rpl %p %d\n", __func__,
  687             cmd->req, cmd->req_len, cmd->rpl, cmd->rpl_len);
  688 
  689         if (cmd->req_len > (int)sc->reqframesz) {
  690                 err = EINVAL;
  691                 goto RetFreeUnlocked;
  692         }
  693         err = copyin(cmd->req, hdr, cmd->req_len);
  694         if (err != 0)
  695                 goto RetFreeUnlocked;
  696 
  697         mps_dprint(sc, MPS_USER, "%s: Function %02X MsgFlags %02X\n", __func__,
  698             hdr->Function, hdr->MsgFlags);
  699 
  700         if (cmd->len > 0) {
  701                 buf = malloc(cmd->len, M_MPSUSER, M_WAITOK|M_ZERO);
  702                 cm->cm_data = buf;
  703                 cm->cm_length = cmd->len;
  704         } else {
  705                 cm->cm_data = NULL;
  706                 cm->cm_length = 0;
  707         }
  708 
  709         cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE;
  710         cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
  711 
  712         err = mps_user_setup_request(cm, cmd);
  713         if (err == EINVAL) {
  714                 mps_printf(sc, "%s: unsupported parameter or unsupported "
  715                     "function in request (function = 0x%X)\n", __func__,
  716                     hdr->Function);
  717         }
  718         if (err != 0)
  719                 goto RetFreeUnlocked;
  720 
  721         mps_lock(sc);
  722         err = mps_wait_command(sc, &cm, 60, CAN_SLEEP);
  723 
  724         if (err || (cm == NULL)) {
  725                 mps_printf(sc, "%s: invalid request: error %d\n",
  726                     __func__, err);
  727                 goto RetFree;
  728         }
  729 
  730         rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply;
  731         if (rpl != NULL)
  732                 sz = rpl->MsgLength * 4;
  733         else
  734                 sz = 0;
  735         
  736         if (sz > cmd->rpl_len) {
  737                 mps_printf(sc, "%s: user reply buffer (%d) smaller than "
  738                     "returned buffer (%d)\n", __func__, cmd->rpl_len, sz);
  739                 sz = cmd->rpl_len;
  740         }       
  741 
  742         mps_unlock(sc);
  743         copyout(rpl, cmd->rpl, sz);
  744         if (buf != NULL)
  745                 copyout(buf, cmd->buf, cmd->len);
  746         mps_dprint(sc, MPS_USER, "%s: reply size %d\n", __func__, sz);
  747 
  748 RetFreeUnlocked:
  749         mps_lock(sc);
  750 RetFree:
  751         if (cm != NULL)
  752                 mps_free_command(sc, cm);
  753         mps_unlock(sc);
  754         if (buf != NULL)
  755                 free(buf, M_MPSUSER);
  756         return (err);
  757 }
  758 
  759 static int
  760 mps_user_pass_thru(struct mps_softc *sc, mps_pass_thru_t *data)
  761 {
  762         MPI2_REQUEST_HEADER     *hdr, tmphdr;   
  763         MPI2_DEFAULT_REPLY      *rpl = NULL;
  764         struct mps_command      *cm = NULL;
  765         int                     err = 0, dir = 0, sz;
  766         uint8_t                 function = 0;
  767         u_int                   sense_len;
  768         struct mpssas_target    *targ = NULL;
  769 
  770         /*
  771          * Only allow one passthru command at a time.  Use the MPS_FLAGS_BUSY
  772          * bit to denote that a passthru is being processed.
  773          */
  774         mps_lock(sc);
  775         if (sc->mps_flags & MPS_FLAGS_BUSY) {
  776                 mps_dprint(sc, MPS_USER, "%s: Only one passthru command "
  777                     "allowed at a single time.", __func__);
  778                 mps_unlock(sc);
  779                 return (EBUSY);
  780         }
  781         sc->mps_flags |= MPS_FLAGS_BUSY;
  782         mps_unlock(sc);
  783 
  784         /*
  785          * Do some validation on data direction.  Valid cases are:
  786          *    1) DataSize is 0 and direction is NONE
  787          *    2) DataSize is non-zero and one of:
  788          *        a) direction is READ or
  789          *        b) direction is WRITE or
  790          *        c) direction is BOTH and DataOutSize is non-zero
  791          * If valid and the direction is BOTH, change the direction to READ.
  792          * if valid and the direction is not BOTH, make sure DataOutSize is 0.
  793          */
  794         if (((data->DataSize == 0) &&
  795             (data->DataDirection == MPS_PASS_THRU_DIRECTION_NONE)) ||
  796             ((data->DataSize != 0) &&
  797             ((data->DataDirection == MPS_PASS_THRU_DIRECTION_READ) ||
  798             (data->DataDirection == MPS_PASS_THRU_DIRECTION_WRITE) ||
  799             ((data->DataDirection == MPS_PASS_THRU_DIRECTION_BOTH) &&
  800             (data->DataOutSize != 0))))) {
  801                 if (data->DataDirection == MPS_PASS_THRU_DIRECTION_BOTH)
  802                         data->DataDirection = MPS_PASS_THRU_DIRECTION_READ;
  803                 else
  804                         data->DataOutSize = 0;
  805         } else
  806                 return (EINVAL);
  807 
  808         mps_dprint(sc, MPS_USER, "%s: req 0x%jx %d  rpl 0x%jx %d "
  809             "data in 0x%jx %d data out 0x%jx %d data dir %d\n", __func__,
  810             data->PtrRequest, data->RequestSize, data->PtrReply,
  811             data->ReplySize, data->PtrData, data->DataSize,
  812             data->PtrDataOut, data->DataOutSize, data->DataDirection);
  813 
  814         /*
  815          * copy in the header so we know what we're dealing with before we
  816          * commit to allocating a command for it.
  817          */
  818         err = copyin(PTRIN(data->PtrRequest), &tmphdr, data->RequestSize);
  819         if (err != 0)
  820                 goto RetFreeUnlocked;
  821 
  822         if (data->RequestSize > (int)sc->reqframesz) {
  823                 err = EINVAL;
  824                 goto RetFreeUnlocked;
  825         }
  826 
  827         function = tmphdr.Function;
  828         mps_dprint(sc, MPS_USER, "%s: Function %02X MsgFlags %02X\n", __func__,
  829             function, tmphdr.MsgFlags);
  830 
  831         /*
  832          * Handle a passthru TM request.
  833          */
  834         if (function == MPI2_FUNCTION_SCSI_TASK_MGMT) {
  835                 MPI2_SCSI_TASK_MANAGE_REQUEST   *task;
  836 
  837                 mps_lock(sc);
  838                 cm = mpssas_alloc_tm(sc);
  839                 if (cm == NULL) {
  840                         err = EINVAL;
  841                         goto Ret;
  842                 }
  843 
  844                 /* Copy the header in.  Only a small fixup is needed. */
  845                 task = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req;
  846                 bcopy(&tmphdr, task, data->RequestSize);
  847                 task->TaskMID = cm->cm_desc.Default.SMID;
  848 
  849                 cm->cm_data = NULL;
  850                 cm->cm_desc.HighPriority.RequestFlags =
  851                     MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
  852                 cm->cm_complete = NULL;
  853                 cm->cm_complete_data = NULL;
  854 
  855                 targ = mpssas_find_target_by_handle(sc->sassc, 0,
  856                     task->DevHandle);
  857                 if (targ == NULL) {
  858                         mps_dprint(sc, MPS_INFO,
  859                            "%s %d : invalid handle for requested TM 0x%x \n",
  860                            __func__, __LINE__, task->DevHandle);
  861                         err = 1;
  862                 } else {
  863                         mpssas_prepare_for_tm(sc, cm, targ, CAM_LUN_WILDCARD);
  864                         err = mps_wait_command(sc, &cm, 30, CAN_SLEEP);
  865                 }
  866 
  867                 if (err != 0) {
  868                         err = EIO;
  869                         mps_dprint(sc, MPS_FAULT, "%s: task management failed",
  870                             __func__);
  871                 }
  872                 /*
  873                  * Copy the reply data and sense data to user space.
  874                  */
  875                 if ((cm != NULL) && (cm->cm_reply != NULL)) {
  876                         rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply;
  877                         sz = rpl->MsgLength * 4;
  878         
  879                         if (sz > data->ReplySize) {
  880                                 mps_printf(sc, "%s: user reply buffer (%d) "
  881                                     "smaller than returned buffer (%d)\n",
  882                                     __func__, data->ReplySize, sz);
  883                         }
  884                         mps_unlock(sc);
  885                         copyout(cm->cm_reply, PTRIN(data->PtrReply),
  886                             data->ReplySize);
  887                         mps_lock(sc);
  888                 }
  889                 mpssas_free_tm(sc, cm);
  890                 goto Ret;
  891         }
  892 
  893         mps_lock(sc);
  894         cm = mps_alloc_command(sc);
  895 
  896         if (cm == NULL) {
  897                 mps_printf(sc, "%s: no mps requests\n", __func__);
  898                 err = ENOMEM;
  899                 goto Ret;
  900         }
  901         mps_unlock(sc);
  902 
  903         hdr = (MPI2_REQUEST_HEADER *)cm->cm_req;
  904         bcopy(&tmphdr, hdr, data->RequestSize);
  905 
  906         /*
  907          * Do some checking to make sure the IOCTL request contains a valid
  908          * request.  Then set the SGL info.
  909          */
  910         mpi_init_sge(cm, hdr, (void *)((uint8_t *)hdr + data->RequestSize));
  911 
  912         /*
  913          * Set up for read, write or both.  From check above, DataOutSize will
  914          * be 0 if direction is READ or WRITE, but it will have some non-zero
  915          * value if the direction is BOTH.  So, just use the biggest size to get
  916          * the cm_data buffer size.  If direction is BOTH, 2 SGLs need to be set
  917          * up; the first is for the request and the second will contain the
  918          * response data. cm_out_len needs to be set here and this will be used
  919          * when the SGLs are set up.
  920          */
  921         cm->cm_data = NULL;
  922         cm->cm_length = MAX(data->DataSize, data->DataOutSize);
  923         cm->cm_out_len = data->DataOutSize;
  924         cm->cm_flags = 0;
  925         if (cm->cm_length != 0) {
  926                 cm->cm_data = malloc(cm->cm_length, M_MPSUSER, M_WAITOK |
  927                     M_ZERO);
  928                 cm->cm_flags = MPS_CM_FLAGS_DATAIN;
  929                 if (data->DataOutSize) {
  930                         cm->cm_flags |= MPS_CM_FLAGS_DATAOUT;
  931                         err = copyin(PTRIN(data->PtrDataOut),
  932                             cm->cm_data, data->DataOutSize);
  933                 } else if (data->DataDirection ==
  934                     MPS_PASS_THRU_DIRECTION_WRITE) {
  935                         cm->cm_flags = MPS_CM_FLAGS_DATAOUT;
  936                         err = copyin(PTRIN(data->PtrData),
  937                             cm->cm_data, data->DataSize);
  938                 }
  939                 if (err != 0)
  940                         mps_dprint(sc, MPS_FAULT, "%s: failed to copy "
  941                             "IOCTL data from user space\n", __func__);
  942         }
  943         cm->cm_flags |= MPS_CM_FLAGS_SGE_SIMPLE;
  944         cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
  945 
  946         /*
  947          * Set up Sense buffer and SGL offset for IO passthru.  SCSI IO request
  948          * uses SCSI IO descriptor.
  949          */
  950         if ((function == MPI2_FUNCTION_SCSI_IO_REQUEST) ||
  951             (function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
  952                 MPI2_SCSI_IO_REQUEST    *scsi_io_req;
  953 
  954                 scsi_io_req = (MPI2_SCSI_IO_REQUEST *)hdr;
  955                 /*
  956                  * Put SGE for data and data_out buffer at the end of
  957                  * scsi_io_request message header (64 bytes in total).
  958                  * Following above SGEs, the residual space will be used by
  959                  * sense data.
  960                  */
  961                 scsi_io_req->SenseBufferLength = (uint8_t)(data->RequestSize -
  962                     64);
  963                 scsi_io_req->SenseBufferLowAddress = htole32(cm->cm_sense_busaddr);
  964 
  965                 /*
  966                  * Set SGLOffset0 value.  This is the number of dwords that SGL
  967                  * is offset from the beginning of MPI2_SCSI_IO_REQUEST struct.
  968                  */
  969                 scsi_io_req->SGLOffset0 = 24;
  970 
  971                 /*
  972                  * Setup descriptor info.  RAID passthrough must use the
  973                  * default request descriptor which is already set, so if this
  974                  * is a SCSI IO request, change the descriptor to SCSI IO.
  975                  * Also, if this is a SCSI IO request, handle the reply in the
  976                  * mpssas_scsio_complete function.
  977                  */
  978                 if (function == MPI2_FUNCTION_SCSI_IO_REQUEST) {
  979                         cm->cm_desc.SCSIIO.RequestFlags =
  980                             MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
  981                         cm->cm_desc.SCSIIO.DevHandle = scsi_io_req->DevHandle;
  982 
  983                         /*
  984                          * Make sure the DevHandle is not 0 because this is a
  985                          * likely error.
  986                          */
  987                         if (scsi_io_req->DevHandle == 0) {
  988                                 err = EINVAL;
  989                                 goto RetFreeUnlocked;
  990                         }
  991                 }
  992         }
  993 
  994         mps_lock(sc);
  995 
  996         err = mps_wait_command(sc, &cm, 30, CAN_SLEEP);
  997 
  998         if (err || (cm == NULL)) {
  999                 mps_printf(sc, "%s: invalid request: error %d\n", __func__,
 1000                     err);
 1001                 mps_unlock(sc);
 1002                 goto RetFreeUnlocked;
 1003         }
 1004 
 1005         /*
 1006          * Sync the DMA data, if any.  Then copy the data to user space.
 1007          */
 1008         if (cm->cm_data != NULL) {
 1009                 if (cm->cm_flags & MPS_CM_FLAGS_DATAIN)
 1010                         dir = BUS_DMASYNC_POSTREAD;
 1011                 else if (cm->cm_flags & MPS_CM_FLAGS_DATAOUT)
 1012                         dir = BUS_DMASYNC_POSTWRITE;
 1013                 bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir);
 1014                 bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap);
 1015 
 1016                 if (cm->cm_flags & MPS_CM_FLAGS_DATAIN) {
 1017                         mps_unlock(sc);
 1018                         err = copyout(cm->cm_data,
 1019                             PTRIN(data->PtrData), data->DataSize);
 1020                         mps_lock(sc);
 1021                         if (err != 0)
 1022                                 mps_dprint(sc, MPS_FAULT, "%s: failed to copy "
 1023                                     "IOCTL data to user space\n", __func__);
 1024                 }
 1025         }
 1026 
 1027         /*
 1028          * Copy the reply data and sense data to user space.
 1029          */
 1030         if (cm->cm_reply != NULL) {
 1031                 rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply;
 1032                 sz = rpl->MsgLength * 4;
 1033 
 1034                 if (sz > data->ReplySize) {
 1035                         mps_printf(sc, "%s: user reply buffer (%d) smaller "
 1036                             "than returned buffer (%d)\n", __func__,
 1037                             data->ReplySize, sz);
 1038                 }
 1039                 mps_unlock(sc);
 1040                 copyout(cm->cm_reply, PTRIN(data->PtrReply), data->ReplySize);
 1041                 mps_lock(sc);
 1042 
 1043                 if ((function == MPI2_FUNCTION_SCSI_IO_REQUEST) ||
 1044                     (function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
 1045                         if (((MPI2_SCSI_IO_REPLY *)rpl)->SCSIState &
 1046                             MPI2_SCSI_STATE_AUTOSENSE_VALID) {
 1047                                 sense_len =
 1048                                     MIN((le32toh(((MPI2_SCSI_IO_REPLY *)rpl)->SenseCount)),
 1049                                     sizeof(struct scsi_sense_data));
 1050                                 mps_unlock(sc);
 1051                                 copyout(cm->cm_sense, cm->cm_req + 64, sense_len);
 1052                                 mps_lock(sc);
 1053                         }
 1054                 }
 1055         }
 1056         mps_unlock(sc);
 1057 
 1058 RetFreeUnlocked:
 1059         mps_lock(sc);
 1060 
 1061         if (cm != NULL) {
 1062                 if (cm->cm_data)
 1063                         free(cm->cm_data, M_MPSUSER);
 1064                 mps_free_command(sc, cm);
 1065         }
 1066 Ret:
 1067         sc->mps_flags &= ~MPS_FLAGS_BUSY;
 1068         mps_unlock(sc);
 1069 
 1070         return (err);
 1071 }
 1072 
 1073 static void
 1074 mps_user_get_adapter_data(struct mps_softc *sc, mps_adapter_data_t *data)
 1075 {
 1076         Mpi2ConfigReply_t       mpi_reply;
 1077         Mpi2BiosPage3_t         config_page;
 1078 
 1079         /*
 1080          * Use the PCI interface functions to get the Bus, Device, and Function
 1081          * information.
 1082          */
 1083         data->PciInformation.u.bits.BusNumber = pci_get_bus(sc->mps_dev);
 1084         data->PciInformation.u.bits.DeviceNumber = pci_get_slot(sc->mps_dev);
 1085         data->PciInformation.u.bits.FunctionNumber =
 1086             pci_get_function(sc->mps_dev);
 1087 
 1088         /*
 1089          * Get the FW version that should already be saved in IOC Facts.
 1090          */
 1091         data->MpiFirmwareVersion = sc->facts->FWVersion.Word;
 1092 
 1093         /*
 1094          * General device info.
 1095          */
 1096         data->AdapterType = MPSIOCTL_ADAPTER_TYPE_SAS2;
 1097         if (sc->mps_flags & MPS_FLAGS_WD_AVAILABLE)
 1098                 data->AdapterType = MPSIOCTL_ADAPTER_TYPE_SAS2_SSS6200;
 1099         data->PCIDeviceHwId = pci_get_device(sc->mps_dev);
 1100         data->PCIDeviceHwRev = pci_read_config(sc->mps_dev, PCIR_REVID, 1);
 1101         data->SubSystemId = pci_get_subdevice(sc->mps_dev);
 1102         data->SubsystemVendorId = pci_get_subvendor(sc->mps_dev);
 1103 
 1104         /*
 1105          * Get the driver version.
 1106          */
 1107         strcpy((char *)&data->DriverVersion[0], MPS_DRIVER_VERSION);
 1108 
 1109         /*
 1110          * Need to get BIOS Config Page 3 for the BIOS Version.
 1111          */
 1112         data->BiosVersion = 0;
 1113         mps_lock(sc);
 1114         if (mps_config_get_bios_pg3(sc, &mpi_reply, &config_page))
 1115                 printf("%s: Error while retrieving BIOS Version\n", __func__);
 1116         else
 1117                 data->BiosVersion = config_page.BiosVersion;
 1118         mps_unlock(sc);
 1119 }
 1120 
 1121 static void
 1122 mps_user_read_pci_info(struct mps_softc *sc, mps_pci_info_t *data)
 1123 {
 1124         int     i;
 1125 
 1126         /*
 1127          * Use the PCI interface functions to get the Bus, Device, and Function
 1128          * information.
 1129          */
 1130         data->BusNumber = pci_get_bus(sc->mps_dev);
 1131         data->DeviceNumber = pci_get_slot(sc->mps_dev);
 1132         data->FunctionNumber = pci_get_function(sc->mps_dev);
 1133 
 1134         /*
 1135          * Now get the interrupt vector and the pci header.  The vector can
 1136          * only be 0 right now.  The header is the first 256 bytes of config
 1137          * space.
 1138          */
 1139         data->InterruptVector = 0;
 1140         for (i = 0; i < sizeof (data->PciHeader); i++) {
 1141                 data->PciHeader[i] = pci_read_config(sc->mps_dev, i, 1);
 1142         }
 1143 }
 1144 
 1145 static uint8_t
 1146 mps_get_fw_diag_buffer_number(struct mps_softc *sc, uint32_t unique_id)
 1147 {
 1148         uint8_t index;
 1149 
 1150         for (index = 0; index < MPI2_DIAG_BUF_TYPE_COUNT; index++) {
 1151                 if (sc->fw_diag_buffer_list[index].unique_id == unique_id) {
 1152                         return (index);
 1153                 }
 1154         }
 1155 
 1156         return (MPS_FW_DIAGNOSTIC_UID_NOT_FOUND);
 1157 }
 1158 
 1159 static int
 1160 mps_post_fw_diag_buffer(struct mps_softc *sc,
 1161     mps_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code)
 1162 {
 1163         MPI2_DIAG_BUFFER_POST_REQUEST   *req;
 1164         MPI2_DIAG_BUFFER_POST_REPLY     *reply = NULL;
 1165         struct mps_command              *cm = NULL;
 1166         int                             i, status;
 1167 
 1168         /*
 1169          * If buffer is not enabled, just leave.
 1170          */
 1171         *return_code = MPS_FW_DIAG_ERROR_POST_FAILED;
 1172         if (!pBuffer->enabled) {
 1173                 return (MPS_DIAG_FAILURE);
 1174         }
 1175 
 1176         /*
 1177          * Clear some flags initially.
 1178          */
 1179         pBuffer->force_release = FALSE;
 1180         pBuffer->valid_data = FALSE;
 1181         pBuffer->owned_by_firmware = FALSE;
 1182 
 1183         /*
 1184          * Get a command.
 1185          */
 1186         cm = mps_alloc_command(sc);
 1187         if (cm == NULL) {
 1188                 mps_printf(sc, "%s: no mps requests\n", __func__);
 1189                 return (MPS_DIAG_FAILURE);
 1190         }
 1191 
 1192         /*
 1193          * Build the request for releasing the FW Diag Buffer and send it.
 1194          */
 1195         req = (MPI2_DIAG_BUFFER_POST_REQUEST *)cm->cm_req;
 1196         req->Function = MPI2_FUNCTION_DIAG_BUFFER_POST;
 1197         req->BufferType = pBuffer->buffer_type;
 1198         req->ExtendedType = pBuffer->extended_type;
 1199         req->BufferLength = pBuffer->size;
 1200         for (i = 0; i < (sizeof(req->ProductSpecific) / 4); i++)
 1201                 req->ProductSpecific[i] = pBuffer->product_specific[i];
 1202         mps_from_u64(sc->fw_diag_busaddr, &req->BufferAddress);
 1203         cm->cm_data = NULL;
 1204         cm->cm_length = 0;
 1205         cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
 1206         cm->cm_complete_data = NULL;
 1207 
 1208         /*
 1209          * Send command synchronously.
 1210          */
 1211         status = mps_wait_command(sc, &cm, 30, CAN_SLEEP);
 1212         if (status || (cm == NULL)) {
 1213                 mps_printf(sc, "%s: invalid request: error %d\n", __func__,
 1214                     status);
 1215                 status = MPS_DIAG_FAILURE;
 1216                 goto done;
 1217         }
 1218 
 1219         /*
 1220          * Process POST reply.
 1221          */
 1222         reply = (MPI2_DIAG_BUFFER_POST_REPLY *)cm->cm_reply;
 1223         if (reply == NULL) {
 1224                 mps_printf(sc, "%s: reply is NULL, probably due to "
 1225                     "reinitialization\n", __func__);
 1226                 status = MPS_DIAG_FAILURE;
 1227                 goto done;
 1228         }
 1229         if ((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) !=
 1230             MPI2_IOCSTATUS_SUCCESS) {
 1231                 status = MPS_DIAG_FAILURE;
 1232                 mps_dprint(sc, MPS_FAULT, "%s: post of FW  Diag Buffer failed "
 1233                     "with IOCStatus = 0x%x, IOCLogInfo = 0x%x and "
 1234                     "TransferLength = 0x%x\n", __func__,
 1235                     le16toh(reply->IOCStatus), le32toh(reply->IOCLogInfo),
 1236                     le32toh(reply->TransferLength));
 1237                 goto done;
 1238         }
 1239 
 1240         /*
 1241          * Post was successful.
 1242          */
 1243         pBuffer->valid_data = TRUE;
 1244         pBuffer->owned_by_firmware = TRUE;
 1245         *return_code = MPS_FW_DIAG_ERROR_SUCCESS;
 1246         status = MPS_DIAG_SUCCESS;
 1247 
 1248 done:
 1249         if (cm != NULL)
 1250                 mps_free_command(sc, cm);
 1251         return (status);
 1252 }
 1253 
 1254 static int
 1255 mps_release_fw_diag_buffer(struct mps_softc *sc,
 1256     mps_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code,
 1257     uint32_t diag_type)
 1258 {
 1259         MPI2_DIAG_RELEASE_REQUEST       *req;
 1260         MPI2_DIAG_RELEASE_REPLY         *reply = NULL;
 1261         struct mps_command              *cm = NULL;
 1262         int                             status;
 1263 
 1264         /*
 1265          * If buffer is not enabled, just leave.
 1266          */
 1267         *return_code = MPS_FW_DIAG_ERROR_RELEASE_FAILED;
 1268         if (!pBuffer->enabled) {
 1269                 mps_dprint(sc, MPS_USER, "%s: This buffer type is not "
 1270                     "supported by the IOC", __func__);
 1271                 return (MPS_DIAG_FAILURE);
 1272         }
 1273 
 1274         /*
 1275          * Clear some flags initially.
 1276          */
 1277         pBuffer->force_release = FALSE;
 1278         pBuffer->valid_data = FALSE;
 1279         pBuffer->owned_by_firmware = FALSE;
 1280 
 1281         /*
 1282          * Get a command.
 1283          */
 1284         cm = mps_alloc_command(sc);
 1285         if (cm == NULL) {
 1286                 mps_printf(sc, "%s: no mps requests\n", __func__);
 1287                 return (MPS_DIAG_FAILURE);
 1288         }
 1289 
 1290         /*
 1291          * Build the request for releasing the FW Diag Buffer and send it.
 1292          */
 1293         req = (MPI2_DIAG_RELEASE_REQUEST *)cm->cm_req;
 1294         req->Function = MPI2_FUNCTION_DIAG_RELEASE;
 1295         req->BufferType = pBuffer->buffer_type;
 1296         cm->cm_data = NULL;
 1297         cm->cm_length = 0;
 1298         cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
 1299         cm->cm_complete_data = NULL;
 1300 
 1301         /*
 1302          * Send command synchronously.
 1303          */
 1304         status = mps_wait_command(sc, &cm, 30, CAN_SLEEP);
 1305         if (status || (cm == NULL)) {
 1306                 mps_printf(sc, "%s: invalid request: error %d\n", __func__,
 1307                     status);
 1308                 status = MPS_DIAG_FAILURE;
 1309                 goto done;
 1310         }
 1311 
 1312         /*
 1313          * Process RELEASE reply.
 1314          */
 1315         reply = (MPI2_DIAG_RELEASE_REPLY *)cm->cm_reply;
 1316         if (reply == NULL) {
 1317                 mps_printf(sc, "%s: reply is NULL, probably due to "
 1318                     "reinitialization\n", __func__);
 1319                 status = MPS_DIAG_FAILURE;
 1320                 goto done;
 1321         }
 1322         if (((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) !=
 1323             MPI2_IOCSTATUS_SUCCESS) || pBuffer->owned_by_firmware) {
 1324                 status = MPS_DIAG_FAILURE;
 1325                 mps_dprint(sc, MPS_FAULT, "%s: release of FW Diag Buffer "
 1326                     "failed with IOCStatus = 0x%x and IOCLogInfo = 0x%x\n",
 1327                     __func__, le16toh(reply->IOCStatus),
 1328                     le32toh(reply->IOCLogInfo));
 1329                 goto done;
 1330         }
 1331 
 1332         /*
 1333          * Release was successful.
 1334          */
 1335         *return_code = MPS_FW_DIAG_ERROR_SUCCESS;
 1336         status = MPS_DIAG_SUCCESS;
 1337 
 1338         /*
 1339          * If this was for an UNREGISTER diag type command, clear the unique ID.
 1340          */
 1341         if (diag_type == MPS_FW_DIAG_TYPE_UNREGISTER) {
 1342                 pBuffer->unique_id = MPS_FW_DIAG_INVALID_UID;
 1343         }
 1344 
 1345 done:
 1346         if (cm != NULL)
 1347                 mps_free_command(sc, cm);
 1348 
 1349         return (status);
 1350 }
 1351 
 1352 static int
 1353 mps_diag_register(struct mps_softc *sc, mps_fw_diag_register_t *diag_register,
 1354     uint32_t *return_code)
 1355 {
 1356         mps_fw_diagnostic_buffer_t      *pBuffer;
 1357         struct mps_busdma_context       *ctx;
 1358         uint8_t                         extended_type, buffer_type, i;
 1359         uint32_t                        buffer_size;
 1360         uint32_t                        unique_id;
 1361         int                             status;
 1362         int                             error;
 1363 
 1364         extended_type = diag_register->ExtendedType;
 1365         buffer_type = diag_register->BufferType;
 1366         buffer_size = diag_register->RequestedBufferSize;
 1367         unique_id = diag_register->UniqueId;
 1368         ctx = NULL;
 1369         error = 0;
 1370 
 1371         /*
 1372          * Check for valid buffer type
 1373          */
 1374         if (buffer_type >= MPI2_DIAG_BUF_TYPE_COUNT) {
 1375                 *return_code = MPS_FW_DIAG_ERROR_INVALID_PARAMETER;
 1376                 return (MPS_DIAG_FAILURE);
 1377         }
 1378 
 1379         /*
 1380          * Get the current buffer and look up the unique ID.  The unique ID
 1381          * should not be found.  If it is, the ID is already in use.
 1382          */
 1383         i = mps_get_fw_diag_buffer_number(sc, unique_id);
 1384         pBuffer = &sc->fw_diag_buffer_list[buffer_type];
 1385         if (i != MPS_FW_DIAGNOSTIC_UID_NOT_FOUND) {
 1386                 *return_code = MPS_FW_DIAG_ERROR_INVALID_UID;
 1387                 return (MPS_DIAG_FAILURE);
 1388         }
 1389 
 1390         /*
 1391          * The buffer's unique ID should not be registered yet, and the given
 1392          * unique ID cannot be 0.
 1393          */
 1394         if ((pBuffer->unique_id != MPS_FW_DIAG_INVALID_UID) ||
 1395             (unique_id == MPS_FW_DIAG_INVALID_UID)) {
 1396                 *return_code = MPS_FW_DIAG_ERROR_INVALID_UID;
 1397                 return (MPS_DIAG_FAILURE);
 1398         }
 1399 
 1400         /*
 1401          * If this buffer is already posted as immediate, just change owner.
 1402          */
 1403         if (pBuffer->immediate && pBuffer->owned_by_firmware &&
 1404             (pBuffer->unique_id == MPS_FW_DIAG_INVALID_UID)) {
 1405                 pBuffer->immediate = FALSE;
 1406                 pBuffer->unique_id = unique_id;
 1407                 return (MPS_DIAG_SUCCESS);
 1408         }
 1409 
 1410         /*
 1411          * Post a new buffer after checking if it's enabled.  The DMA buffer
 1412          * that is allocated will be contiguous (nsegments = 1).
 1413          */
 1414         if (!pBuffer->enabled) {
 1415                 *return_code = MPS_FW_DIAG_ERROR_NO_BUFFER;
 1416                 return (MPS_DIAG_FAILURE);
 1417         }
 1418         if (bus_dma_tag_create( sc->mps_parent_dmat,    /* parent */
 1419                                 1, 0,                   /* algnmnt, boundary */
 1420                                 BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
 1421                                 BUS_SPACE_MAXADDR,      /* highaddr */
 1422                                 NULL, NULL,             /* filter, filterarg */
 1423                                 buffer_size,            /* maxsize */
 1424                                 1,                      /* nsegments */
 1425                                 buffer_size,            /* maxsegsize */
 1426                                 0,                      /* flags */
 1427                                 NULL, NULL,             /* lockfunc, lockarg */
 1428                                 &sc->fw_diag_dmat)) {
 1429                 mps_dprint(sc, MPS_ERROR,
 1430                     "Cannot allocate FW diag buffer DMA tag\n");
 1431                 *return_code = MPS_FW_DIAG_ERROR_NO_BUFFER;
 1432                 status = MPS_DIAG_FAILURE;
 1433                 goto bailout;
 1434         }
 1435         if (bus_dmamem_alloc(sc->fw_diag_dmat, (void **)&sc->fw_diag_buffer,
 1436             BUS_DMA_NOWAIT, &sc->fw_diag_map)) {
 1437                 mps_dprint(sc, MPS_ERROR,
 1438                     "Cannot allocate FW diag buffer memory\n");
 1439                 *return_code = MPS_FW_DIAG_ERROR_NO_BUFFER;
 1440                 status = MPS_DIAG_FAILURE;
 1441                 goto bailout;
 1442         }
 1443         bzero(sc->fw_diag_buffer, buffer_size);
 1444 
 1445         ctx = malloc(sizeof(*ctx), M_MPSUSER, M_WAITOK | M_ZERO);
 1446         if (ctx == NULL) {
 1447                 device_printf(sc->mps_dev, "%s: context malloc failed\n",
 1448                     __func__);
 1449                 *return_code = MPS_FW_DIAG_ERROR_NO_BUFFER;
 1450                 status = MPS_DIAG_FAILURE;
 1451                 goto bailout;
 1452         }
 1453         ctx->addr = &sc->fw_diag_busaddr;
 1454         ctx->buffer_dmat = sc->fw_diag_dmat;
 1455         ctx->buffer_dmamap = sc->fw_diag_map;
 1456         ctx->softc = sc;
 1457         error = bus_dmamap_load(sc->fw_diag_dmat, sc->fw_diag_map,
 1458             sc->fw_diag_buffer, buffer_size, mps_memaddr_wait_cb,
 1459             ctx, 0);
 1460 
 1461         if (error == EINPROGRESS) {
 1462 
 1463                 /* XXX KDM */
 1464                 device_printf(sc->mps_dev, "%s: Deferred bus_dmamap_load\n",
 1465                     __func__);
 1466                 /*
 1467                  * Wait for the load to complete.  If we're interrupted,
 1468                  * bail out.
 1469                  */
 1470                 mps_lock(sc);
 1471                 if (ctx->completed == 0) {
 1472                         error = msleep(ctx, &sc->mps_mtx, PCATCH, "mpswait", 0);
 1473                         if (error != 0) {
 1474                                 /*
 1475                                  * We got an error from msleep(9).  This is
 1476                                  * most likely due to a signal.  Tell
 1477                                  * mpr_memaddr_wait_cb() that we've abandoned
 1478                                  * the context, so it needs to clean up when
 1479                                  * it is called.
 1480                                  */
 1481                                 ctx->abandoned = 1;
 1482 
 1483                                 /* The callback will free this memory */
 1484                                 ctx = NULL;
 1485                                 mps_unlock(sc);
 1486 
 1487                                 device_printf(sc->mps_dev, "Cannot "
 1488                                     "bus_dmamap_load FW diag buffer, error = "
 1489                                     "%d returned from msleep\n", error);
 1490                                 *return_code = MPS_FW_DIAG_ERROR_NO_BUFFER;
 1491                                 status = MPS_DIAG_FAILURE;
 1492                                 goto bailout;
 1493                         }
 1494                 }
 1495                 mps_unlock(sc);
 1496         } 
 1497 
 1498         if ((error != 0) || (ctx->error != 0)) {
 1499                 device_printf(sc->mps_dev, "Cannot bus_dmamap_load FW diag "
 1500                     "buffer, %serror = %d\n", error ? "" : "callback ",
 1501                     error ? error : ctx->error);
 1502                 *return_code = MPS_FW_DIAG_ERROR_NO_BUFFER;
 1503                 status = MPS_DIAG_FAILURE;
 1504                 goto bailout;
 1505         }
 1506 
 1507         bus_dmamap_sync(sc->fw_diag_dmat, sc->fw_diag_map, BUS_DMASYNC_PREREAD);
 1508 
 1509         pBuffer->size = buffer_size;
 1510 
 1511         /*
 1512          * Copy the given info to the diag buffer and post the buffer.
 1513          */
 1514         pBuffer->buffer_type = buffer_type;
 1515         pBuffer->immediate = FALSE;
 1516         if (buffer_type == MPI2_DIAG_BUF_TYPE_TRACE) {
 1517                 for (i = 0; i < (sizeof (pBuffer->product_specific) / 4);
 1518                     i++) {
 1519                         pBuffer->product_specific[i] =
 1520                             diag_register->ProductSpecific[i];
 1521                 }
 1522         }
 1523         pBuffer->extended_type = extended_type;
 1524         pBuffer->unique_id = unique_id;
 1525         status = mps_post_fw_diag_buffer(sc, pBuffer, return_code);
 1526 
 1527 bailout:
 1528         /*
 1529          * In case there was a failure, free the DMA buffer.
 1530          */
 1531         if (status == MPS_DIAG_FAILURE) {
 1532                 if (sc->fw_diag_busaddr != 0) {
 1533                         bus_dmamap_unload(sc->fw_diag_dmat, sc->fw_diag_map);
 1534                         sc->fw_diag_busaddr = 0;
 1535                 }
 1536                 if (sc->fw_diag_buffer != NULL) {
 1537                         bus_dmamem_free(sc->fw_diag_dmat, sc->fw_diag_buffer,
 1538                             sc->fw_diag_map);
 1539                         sc->fw_diag_buffer = NULL;
 1540                 }
 1541                 if (sc->fw_diag_dmat != NULL) {
 1542                         bus_dma_tag_destroy(sc->fw_diag_dmat);
 1543                         sc->fw_diag_dmat = NULL;
 1544                 }
 1545         }
 1546 
 1547         if (ctx != NULL)
 1548                 free(ctx, M_MPSUSER);
 1549 
 1550         return (status);
 1551 }
 1552 
 1553 static int
 1554 mps_diag_unregister(struct mps_softc *sc,
 1555     mps_fw_diag_unregister_t *diag_unregister, uint32_t *return_code)
 1556 {
 1557         mps_fw_diagnostic_buffer_t      *pBuffer;
 1558         uint8_t                         i;
 1559         uint32_t                        unique_id;
 1560         int                             status;
 1561 
 1562         unique_id = diag_unregister->UniqueId;
 1563 
 1564         /*
 1565          * Get the current buffer and look up the unique ID.  The unique ID
 1566          * should be there.
 1567          */
 1568         i = mps_get_fw_diag_buffer_number(sc, unique_id);
 1569         if (i == MPS_FW_DIAGNOSTIC_UID_NOT_FOUND) {
 1570                 *return_code = MPS_FW_DIAG_ERROR_INVALID_UID;
 1571                 return (MPS_DIAG_FAILURE);
 1572         }
 1573 
 1574         pBuffer = &sc->fw_diag_buffer_list[i];
 1575 
 1576         /*
 1577          * Try to release the buffer from FW before freeing it.  If release
 1578          * fails, don't free the DMA buffer in case FW tries to access it
 1579          * later.  If buffer is not owned by firmware, can't release it.
 1580          */
 1581         if (!pBuffer->owned_by_firmware) {
 1582                 status = MPS_DIAG_SUCCESS;
 1583         } else {
 1584                 status = mps_release_fw_diag_buffer(sc, pBuffer, return_code,
 1585                     MPS_FW_DIAG_TYPE_UNREGISTER);
 1586         }
 1587 
 1588         /*
 1589          * At this point, return the current status no matter what happens with
 1590          * the DMA buffer.
 1591          */
 1592         pBuffer->unique_id = MPS_FW_DIAG_INVALID_UID;
 1593         if (status == MPS_DIAG_SUCCESS) {
 1594                 if (sc->fw_diag_busaddr != 0) {
 1595                         bus_dmamap_unload(sc->fw_diag_dmat, sc->fw_diag_map);
 1596                         sc->fw_diag_busaddr = 0;
 1597                 }
 1598                 if (sc->fw_diag_buffer != NULL) {
 1599                         bus_dmamem_free(sc->fw_diag_dmat, sc->fw_diag_buffer,
 1600                             sc->fw_diag_map);
 1601                         sc->fw_diag_buffer = NULL;
 1602                 }
 1603                 if (sc->fw_diag_dmat != NULL) {
 1604                         bus_dma_tag_destroy(sc->fw_diag_dmat);
 1605                         sc->fw_diag_dmat = NULL;
 1606                 }
 1607         }
 1608 
 1609         return (status);
 1610 }
 1611 
 1612 static int
 1613 mps_diag_query(struct mps_softc *sc, mps_fw_diag_query_t *diag_query,
 1614     uint32_t *return_code)
 1615 {
 1616         mps_fw_diagnostic_buffer_t      *pBuffer;
 1617         uint8_t                         i;
 1618         uint32_t                        unique_id;
 1619 
 1620         unique_id = diag_query->UniqueId;
 1621 
 1622         /*
 1623          * If ID is valid, query on ID.
 1624          * If ID is invalid, query on buffer type.
 1625          */
 1626         if (unique_id == MPS_FW_DIAG_INVALID_UID) {
 1627                 i = diag_query->BufferType;
 1628                 if (i >= MPI2_DIAG_BUF_TYPE_COUNT) {
 1629                         *return_code = MPS_FW_DIAG_ERROR_INVALID_UID;
 1630                         return (MPS_DIAG_FAILURE);
 1631                 }
 1632         } else {
 1633                 i = mps_get_fw_diag_buffer_number(sc, unique_id);
 1634                 if (i == MPS_FW_DIAGNOSTIC_UID_NOT_FOUND) {
 1635                         *return_code = MPS_FW_DIAG_ERROR_INVALID_UID;
 1636                         return (MPS_DIAG_FAILURE);
 1637                 }
 1638         }
 1639 
 1640         /*
 1641          * Fill query structure with the diag buffer info.
 1642          */
 1643         pBuffer = &sc->fw_diag_buffer_list[i];
 1644         diag_query->BufferType = pBuffer->buffer_type;
 1645         diag_query->ExtendedType = pBuffer->extended_type;
 1646         if (diag_query->BufferType == MPI2_DIAG_BUF_TYPE_TRACE) {
 1647                 for (i = 0; i < (sizeof(diag_query->ProductSpecific) / 4);
 1648                     i++) {
 1649                         diag_query->ProductSpecific[i] =
 1650                             pBuffer->product_specific[i];
 1651                 }
 1652         }
 1653         diag_query->TotalBufferSize = pBuffer->size;
 1654         diag_query->DriverAddedBufferSize = 0;
 1655         diag_query->UniqueId = pBuffer->unique_id;
 1656         diag_query->ApplicationFlags = 0;
 1657         diag_query->DiagnosticFlags = 0;
 1658 
 1659         /*
 1660          * Set/Clear application flags
 1661          */
 1662         if (pBuffer->immediate) {
 1663                 diag_query->ApplicationFlags &= ~MPS_FW_DIAG_FLAG_APP_OWNED;
 1664         } else {
 1665                 diag_query->ApplicationFlags |= MPS_FW_DIAG_FLAG_APP_OWNED;
 1666         }
 1667         if (pBuffer->valid_data || pBuffer->owned_by_firmware) {
 1668                 diag_query->ApplicationFlags |= MPS_FW_DIAG_FLAG_BUFFER_VALID;
 1669         } else {
 1670                 diag_query->ApplicationFlags &= ~MPS_FW_DIAG_FLAG_BUFFER_VALID;
 1671         }
 1672         if (pBuffer->owned_by_firmware) {
 1673                 diag_query->ApplicationFlags |=
 1674                     MPS_FW_DIAG_FLAG_FW_BUFFER_ACCESS;
 1675         } else {
 1676                 diag_query->ApplicationFlags &=
 1677                     ~MPS_FW_DIAG_FLAG_FW_BUFFER_ACCESS;
 1678         }
 1679 
 1680         return (MPS_DIAG_SUCCESS);
 1681 }
 1682 
 1683 static int
 1684 mps_diag_read_buffer(struct mps_softc *sc,
 1685     mps_diag_read_buffer_t *diag_read_buffer, uint8_t *ioctl_buf,
 1686     uint32_t *return_code)
 1687 {
 1688         mps_fw_diagnostic_buffer_t      *pBuffer;
 1689         uint8_t                         i, *pData;
 1690         uint32_t                        unique_id;
 1691         int                             status;
 1692 
 1693         unique_id = diag_read_buffer->UniqueId;
 1694 
 1695         /*
 1696          * Get the current buffer and look up the unique ID.  The unique ID
 1697          * should be there.
 1698          */
 1699         i = mps_get_fw_diag_buffer_number(sc, unique_id);
 1700         if (i == MPS_FW_DIAGNOSTIC_UID_NOT_FOUND) {
 1701                 *return_code = MPS_FW_DIAG_ERROR_INVALID_UID;
 1702                 return (MPS_DIAG_FAILURE);
 1703         }
 1704 
 1705         pBuffer = &sc->fw_diag_buffer_list[i];
 1706 
 1707         /*
 1708          * Make sure requested read is within limits
 1709          */
 1710         if (diag_read_buffer->StartingOffset + diag_read_buffer->BytesToRead >
 1711             pBuffer->size) {
 1712                 *return_code = MPS_FW_DIAG_ERROR_INVALID_PARAMETER;
 1713                 return (MPS_DIAG_FAILURE);
 1714         }
 1715 
 1716         /* Sync the DMA map before we copy to userland. */
 1717         bus_dmamap_sync(sc->fw_diag_dmat, sc->fw_diag_map,
 1718             BUS_DMASYNC_POSTREAD);
 1719 
 1720         /*
 1721          * Copy the requested data from DMA to the diag_read_buffer.  The DMA
 1722          * buffer that was allocated is one contiguous buffer.
 1723          */
 1724         pData = (uint8_t *)(sc->fw_diag_buffer +
 1725             diag_read_buffer->StartingOffset);
 1726         if (copyout(pData, ioctl_buf, diag_read_buffer->BytesToRead) != 0)
 1727                 return (MPS_DIAG_FAILURE);
 1728         diag_read_buffer->Status = 0;
 1729 
 1730         /*
 1731          * Set or clear the Force Release flag.
 1732          */
 1733         if (pBuffer->force_release) {
 1734                 diag_read_buffer->Flags |= MPS_FW_DIAG_FLAG_FORCE_RELEASE;
 1735         } else {
 1736                 diag_read_buffer->Flags &= ~MPS_FW_DIAG_FLAG_FORCE_RELEASE;
 1737         }
 1738 
 1739         /*
 1740          * If buffer is to be reregistered, make sure it's not already owned by
 1741          * firmware first.
 1742          */
 1743         status = MPS_DIAG_SUCCESS;
 1744         if (!pBuffer->owned_by_firmware) {
 1745                 if (diag_read_buffer->Flags & MPS_FW_DIAG_FLAG_REREGISTER) {
 1746                         status = mps_post_fw_diag_buffer(sc, pBuffer,
 1747                             return_code);
 1748                 }
 1749         }
 1750 
 1751         return (status);
 1752 }
 1753 
 1754 static int
 1755 mps_diag_release(struct mps_softc *sc, mps_fw_diag_release_t *diag_release,
 1756     uint32_t *return_code)
 1757 {
 1758         mps_fw_diagnostic_buffer_t      *pBuffer;
 1759         uint8_t                         i;
 1760         uint32_t                        unique_id;
 1761         int                             status;
 1762 
 1763         unique_id = diag_release->UniqueId;
 1764 
 1765         /*
 1766          * Get the current buffer and look up the unique ID.  The unique ID
 1767          * should be there.
 1768          */
 1769         i = mps_get_fw_diag_buffer_number(sc, unique_id);
 1770         if (i == MPS_FW_DIAGNOSTIC_UID_NOT_FOUND) {
 1771                 *return_code = MPS_FW_DIAG_ERROR_INVALID_UID;
 1772                 return (MPS_DIAG_FAILURE);
 1773         }
 1774 
 1775         pBuffer = &sc->fw_diag_buffer_list[i];
 1776 
 1777         /*
 1778          * If buffer is not owned by firmware, it's already been released.
 1779          */
 1780         if (!pBuffer->owned_by_firmware) {
 1781                 *return_code = MPS_FW_DIAG_ERROR_ALREADY_RELEASED;
 1782                 return (MPS_DIAG_FAILURE);
 1783         }
 1784 
 1785         /*
 1786          * Release the buffer.
 1787          */
 1788         status = mps_release_fw_diag_buffer(sc, pBuffer, return_code,
 1789             MPS_FW_DIAG_TYPE_RELEASE);
 1790         return (status);
 1791 }
 1792 
 1793 static int
 1794 mps_do_diag_action(struct mps_softc *sc, uint32_t action, uint8_t *diag_action,
 1795     uint32_t length, uint32_t *return_code)
 1796 {
 1797         mps_fw_diag_register_t          diag_register;
 1798         mps_fw_diag_unregister_t        diag_unregister;
 1799         mps_fw_diag_query_t             diag_query;
 1800         mps_diag_read_buffer_t          diag_read_buffer;
 1801         mps_fw_diag_release_t           diag_release;
 1802         int                             status = MPS_DIAG_SUCCESS;
 1803         uint32_t                        original_return_code;
 1804 
 1805         original_return_code = *return_code;
 1806         *return_code = MPS_FW_DIAG_ERROR_SUCCESS;
 1807 
 1808         switch (action) {
 1809                 case MPS_FW_DIAG_TYPE_REGISTER:
 1810                         if (!length) {
 1811                                 *return_code =
 1812                                     MPS_FW_DIAG_ERROR_INVALID_PARAMETER;
 1813                                 status = MPS_DIAG_FAILURE;
 1814                                 break;
 1815                         }
 1816                         if (copyin(diag_action, &diag_register,
 1817                             sizeof(diag_register)) != 0)
 1818                                 return (MPS_DIAG_FAILURE);
 1819                         status = mps_diag_register(sc, &diag_register,
 1820                             return_code);
 1821                         break;
 1822 
 1823                 case MPS_FW_DIAG_TYPE_UNREGISTER:
 1824                         if (length < sizeof(diag_unregister)) {
 1825                                 *return_code =
 1826                                     MPS_FW_DIAG_ERROR_INVALID_PARAMETER;
 1827                                 status = MPS_DIAG_FAILURE;
 1828                                 break;
 1829                         }
 1830                         if (copyin(diag_action, &diag_unregister,
 1831                             sizeof(diag_unregister)) != 0)
 1832                                 return (MPS_DIAG_FAILURE);
 1833                         status = mps_diag_unregister(sc, &diag_unregister,
 1834                             return_code);
 1835                         break;
 1836 
 1837                 case MPS_FW_DIAG_TYPE_QUERY:
 1838                         if (length < sizeof (diag_query)) {
 1839                                 *return_code =
 1840                                     MPS_FW_DIAG_ERROR_INVALID_PARAMETER;
 1841                                 status = MPS_DIAG_FAILURE;
 1842                                 break;
 1843                         }
 1844                         if (copyin(diag_action, &diag_query, sizeof(diag_query))
 1845                             != 0)
 1846                                 return (MPS_DIAG_FAILURE);
 1847                         status = mps_diag_query(sc, &diag_query, return_code);
 1848                         if (status == MPS_DIAG_SUCCESS)
 1849                                 if (copyout(&diag_query, diag_action,
 1850                                     sizeof (diag_query)) != 0)
 1851                                         return (MPS_DIAG_FAILURE);
 1852                         break;
 1853 
 1854                 case MPS_FW_DIAG_TYPE_READ_BUFFER:
 1855                         if (copyin(diag_action, &diag_read_buffer,
 1856                             sizeof(diag_read_buffer)) != 0)
 1857                                 return (MPS_DIAG_FAILURE);
 1858                         if (length < diag_read_buffer.BytesToRead) {
 1859                                 *return_code =
 1860                                     MPS_FW_DIAG_ERROR_INVALID_PARAMETER;
 1861                                 status = MPS_DIAG_FAILURE;
 1862                                 break;
 1863                         }
 1864                         status = mps_diag_read_buffer(sc, &diag_read_buffer,
 1865                             PTRIN(diag_read_buffer.PtrDataBuffer),
 1866                             return_code);
 1867                         if (status == MPS_DIAG_SUCCESS) {
 1868                                 if (copyout(&diag_read_buffer, diag_action,
 1869                                     sizeof(diag_read_buffer) -
 1870                                     sizeof(diag_read_buffer.PtrDataBuffer)) !=
 1871                                     0)
 1872                                         return (MPS_DIAG_FAILURE);
 1873                         }
 1874                         break;
 1875 
 1876                 case MPS_FW_DIAG_TYPE_RELEASE:
 1877                         if (length < sizeof(diag_release)) {
 1878                                 *return_code =
 1879                                     MPS_FW_DIAG_ERROR_INVALID_PARAMETER;
 1880                                 status = MPS_DIAG_FAILURE;
 1881                                 break;
 1882                         }
 1883                         if (copyin(diag_action, &diag_release,
 1884                             sizeof(diag_release)) != 0)
 1885                                 return (MPS_DIAG_FAILURE);
 1886                         status = mps_diag_release(sc, &diag_release,
 1887                             return_code);
 1888                         break;
 1889 
 1890                 default:
 1891                         *return_code = MPS_FW_DIAG_ERROR_INVALID_PARAMETER;
 1892                         status = MPS_DIAG_FAILURE;
 1893                         break;
 1894         }
 1895 
 1896         if ((status == MPS_DIAG_FAILURE) &&
 1897             (original_return_code == MPS_FW_DIAG_NEW) &&
 1898             (*return_code != MPS_FW_DIAG_ERROR_SUCCESS))
 1899                 status = MPS_DIAG_SUCCESS;
 1900 
 1901         return (status);
 1902 }
 1903 
 1904 static int
 1905 mps_user_diag_action(struct mps_softc *sc, mps_diag_action_t *data)
 1906 {
 1907         int                     status;
 1908 
 1909         /*
 1910          * Only allow one diag action at one time.
 1911          */
 1912         if (sc->mps_flags & MPS_FLAGS_BUSY) {
 1913                 mps_dprint(sc, MPS_USER, "%s: Only one FW diag command "
 1914                     "allowed at a single time.", __func__);
 1915                 return (EBUSY);
 1916         }
 1917         sc->mps_flags |= MPS_FLAGS_BUSY;
 1918 
 1919         /*
 1920          * Send diag action request
 1921          */
 1922         if (data->Action == MPS_FW_DIAG_TYPE_REGISTER ||
 1923             data->Action == MPS_FW_DIAG_TYPE_UNREGISTER ||
 1924             data->Action == MPS_FW_DIAG_TYPE_QUERY ||
 1925             data->Action == MPS_FW_DIAG_TYPE_READ_BUFFER ||
 1926             data->Action == MPS_FW_DIAG_TYPE_RELEASE) {
 1927                 status = mps_do_diag_action(sc, data->Action,
 1928                     PTRIN(data->PtrDiagAction), data->Length,
 1929                     &data->ReturnCode);
 1930         } else
 1931                 status = EINVAL;
 1932 
 1933         sc->mps_flags &= ~MPS_FLAGS_BUSY;
 1934         return (status);
 1935 }
 1936 
 1937 /*
 1938  * Copy the event recording mask and the event queue size out.  For
 1939  * clarification, the event recording mask (events_to_record) is not the same
 1940  * thing as the event mask (event_mask).  events_to_record has a bit set for
 1941  * every event type that is to be recorded by the driver, and event_mask has a
 1942  * bit cleared for every event that is allowed into the driver from the IOC.
 1943  * They really have nothing to do with each other.
 1944  */
 1945 static void
 1946 mps_user_event_query(struct mps_softc *sc, mps_event_query_t *data)
 1947 {
 1948         uint8_t i;
 1949 
 1950         mps_lock(sc);
 1951         data->Entries = MPS_EVENT_QUEUE_SIZE;
 1952 
 1953         for (i = 0; i < 4; i++) {
 1954                 data->Types[i] = sc->events_to_record[i];
 1955         }
 1956         mps_unlock(sc);
 1957 }
 1958 
 1959 /*
 1960  * Set the driver's event mask according to what's been given.  See
 1961  * mps_user_event_query for explanation of the event recording mask and the IOC
 1962  * event mask.  It's the app's responsibility to enable event logging by setting
 1963  * the bits in events_to_record.  Initially, no events will be logged.
 1964  */
 1965 static void
 1966 mps_user_event_enable(struct mps_softc *sc, mps_event_enable_t *data)
 1967 {
 1968         uint8_t i;
 1969 
 1970         mps_lock(sc);
 1971         for (i = 0; i < 4; i++) {
 1972                 sc->events_to_record[i] = data->Types[i];
 1973         }
 1974         mps_unlock(sc);
 1975 }
 1976 
 1977 /*
 1978  * Copy out the events that have been recorded, up to the max events allowed.
 1979  */
 1980 static int
 1981 mps_user_event_report(struct mps_softc *sc, mps_event_report_t *data)
 1982 {
 1983         int             status = 0;
 1984         uint32_t        size;
 1985 
 1986         mps_lock(sc);
 1987         size = data->Size;
 1988         if ((size >= sizeof(sc->recorded_events)) && (status == 0)) {
 1989                 mps_unlock(sc);
 1990                 if (copyout((void *)sc->recorded_events,
 1991                     PTRIN(data->PtrEvents), size) != 0)
 1992                         status = EFAULT;
 1993                 mps_lock(sc);
 1994         } else {
 1995                 /*
 1996                  * data->Size value is not large enough to copy event data.
 1997                  */
 1998                 status = EFAULT;
 1999         }
 2000 
 2001         /*
 2002          * Change size value to match the number of bytes that were copied.
 2003          */
 2004         if (status == 0)
 2005                 data->Size = sizeof(sc->recorded_events);
 2006         mps_unlock(sc);
 2007 
 2008         return (status);
 2009 }
 2010 
 2011 /*
 2012  * Record events into the driver from the IOC if they are not masked.
 2013  */
 2014 void
 2015 mpssas_record_event(struct mps_softc *sc,
 2016     MPI2_EVENT_NOTIFICATION_REPLY *event_reply)
 2017 {
 2018         uint32_t        event;
 2019         int             i, j;
 2020         uint16_t        event_data_len;
 2021         boolean_t       sendAEN = FALSE;
 2022 
 2023         event = event_reply->Event;
 2024 
 2025         /*
 2026          * Generate a system event to let anyone who cares know that a
 2027          * LOG_ENTRY_ADDED event has occurred.  This is sent no matter what the
 2028          * event mask is set to.
 2029          */
 2030         if (event == MPI2_EVENT_LOG_ENTRY_ADDED) {
 2031                 sendAEN = TRUE;
 2032         }
 2033 
 2034         /*
 2035          * Record the event only if its corresponding bit is set in
 2036          * events_to_record.  event_index is the index into recorded_events and
 2037          * event_number is the overall number of an event being recorded since
 2038          * start-of-day.  event_index will roll over; event_number will never
 2039          * roll over.
 2040          */
 2041         i = (uint8_t)(event / 32);
 2042         j = (uint8_t)(event % 32);
 2043         if ((i < 4) && ((1 << j) & sc->events_to_record[i])) {
 2044                 i = sc->event_index;
 2045                 sc->recorded_events[i].Type = event;
 2046                 sc->recorded_events[i].Number = ++sc->event_number;
 2047                 bzero(sc->recorded_events[i].Data, MPS_MAX_EVENT_DATA_LENGTH *
 2048                     4);
 2049                 event_data_len = event_reply->EventDataLength;
 2050 
 2051                 if (event_data_len > 0) {
 2052                         /*
 2053                          * Limit data to size in m_event entry
 2054                          */
 2055                         if (event_data_len > MPS_MAX_EVENT_DATA_LENGTH) {
 2056                                 event_data_len = MPS_MAX_EVENT_DATA_LENGTH;
 2057                         }
 2058                         for (j = 0; j < event_data_len; j++) {
 2059                                 sc->recorded_events[i].Data[j] =
 2060                                     event_reply->EventData[j];
 2061                         }
 2062 
 2063                         /*
 2064                          * check for index wrap-around
 2065                          */
 2066                         if (++i == MPS_EVENT_QUEUE_SIZE) {
 2067                                 i = 0;
 2068                         }
 2069                         sc->event_index = (uint8_t)i;
 2070 
 2071                         /*
 2072                          * Set flag to send the event.
 2073                          */
 2074                         sendAEN = TRUE;
 2075                 }
 2076         }
 2077 
 2078         /*
 2079          * Generate a system event if flag is set to let anyone who cares know
 2080          * that an event has occurred.
 2081          */
 2082         if (sendAEN) {
 2083 //SLM-how to send a system event (see kqueue, kevent)
 2084 //              (void) ddi_log_sysevent(mpt->m_dip, DDI_VENDOR_LSI, "MPT_SAS",
 2085 //                  "SAS", NULL, NULL, DDI_NOSLEEP);
 2086         }
 2087 }
 2088 
 2089 static int
 2090 mps_user_reg_access(struct mps_softc *sc, mps_reg_access_t *data)
 2091 {
 2092         int     status = 0;
 2093 
 2094         switch (data->Command) {
 2095                 /*
 2096                  * IO access is not supported.
 2097                  */
 2098                 case REG_IO_READ:
 2099                 case REG_IO_WRITE:
 2100                         mps_dprint(sc, MPS_USER, "IO access is not supported. "
 2101                             "Use memory access.");
 2102                         status = EINVAL;
 2103                         break;
 2104 
 2105                 case REG_MEM_READ:
 2106                         data->RegData = mps_regread(sc, data->RegOffset);
 2107                         break;
 2108 
 2109                 case REG_MEM_WRITE:
 2110                         mps_regwrite(sc, data->RegOffset, data->RegData);
 2111                         break;
 2112 
 2113                 default:
 2114                         status = EINVAL;
 2115                         break;
 2116         }
 2117 
 2118         return (status);
 2119 }
 2120 
 2121 static int
 2122 mps_user_btdh(struct mps_softc *sc, mps_btdh_mapping_t *data)
 2123 {
 2124         uint8_t         bt2dh = FALSE;
 2125         uint8_t         dh2bt = FALSE;
 2126         uint16_t        dev_handle, bus, target;
 2127 
 2128         bus = data->Bus;
 2129         target = data->TargetID;
 2130         dev_handle = data->DevHandle;
 2131 
 2132         /*
 2133          * When DevHandle is 0xFFFF and Bus/Target are not 0xFFFF, use Bus/
 2134          * Target to get DevHandle.  When Bus/Target are 0xFFFF and DevHandle is
 2135          * not 0xFFFF, use DevHandle to get Bus/Target.  Anything else is
 2136          * invalid.
 2137          */
 2138         if ((bus == 0xFFFF) && (target == 0xFFFF) && (dev_handle != 0xFFFF))
 2139                 dh2bt = TRUE;
 2140         if ((dev_handle == 0xFFFF) && (bus != 0xFFFF) && (target != 0xFFFF))
 2141                 bt2dh = TRUE;
 2142         if (!dh2bt && !bt2dh)
 2143                 return (EINVAL);
 2144 
 2145         /*
 2146          * Only handle bus of 0.  Make sure target is within range.
 2147          */
 2148         if (bt2dh) {
 2149                 if (bus != 0)
 2150                         return (EINVAL);
 2151 
 2152                 if (target > sc->max_devices) {
 2153                         mps_dprint(sc, MPS_FAULT, "Target ID is out of range "
 2154                            "for Bus/Target to DevHandle mapping.");
 2155                         return (EINVAL);
 2156                 }
 2157                 dev_handle = sc->mapping_table[target].dev_handle;
 2158                 if (dev_handle)
 2159                         data->DevHandle = dev_handle;
 2160         } else {
 2161                 bus = 0;
 2162                 target = mps_mapping_get_tid_from_handle(sc, dev_handle);
 2163                 data->Bus = bus;
 2164                 data->TargetID = target;
 2165         }
 2166 
 2167         return (0);
 2168 }
 2169 
 2170 static int
 2171 mps_ioctl(struct cdev *dev, u_long cmd, void *arg, int flag,
 2172     struct thread *td)
 2173 {
 2174         struct mps_softc *sc;
 2175         struct mps_cfg_page_req *page_req;
 2176         struct mps_ext_cfg_page_req *ext_page_req;
 2177         void *mps_page;
 2178         int error, msleep_ret;
 2179 
 2180         mps_page = NULL;
 2181         sc = dev->si_drv1;
 2182         page_req = (void *)arg;
 2183         ext_page_req = (void *)arg;
 2184 
 2185         switch (cmd) {
 2186         case MPSIO_READ_CFG_HEADER:
 2187                 mps_lock(sc);
 2188                 error = mps_user_read_cfg_header(sc, page_req);
 2189                 mps_unlock(sc);
 2190                 break;
 2191         case MPSIO_READ_CFG_PAGE:
 2192                 mps_page = malloc(page_req->len, M_MPSUSER, M_WAITOK | M_ZERO);
 2193                 error = copyin(page_req->buf, mps_page,
 2194                     sizeof(MPI2_CONFIG_PAGE_HEADER));
 2195                 if (error)
 2196                         break;
 2197                 mps_lock(sc);
 2198                 error = mps_user_read_cfg_page(sc, page_req, mps_page);
 2199                 mps_unlock(sc);
 2200                 if (error)
 2201                         break;
 2202                 error = copyout(mps_page, page_req->buf, page_req->len);
 2203                 break;
 2204         case MPSIO_READ_EXT_CFG_HEADER:
 2205                 mps_lock(sc);
 2206                 error = mps_user_read_extcfg_header(sc, ext_page_req);
 2207                 mps_unlock(sc);
 2208                 break;
 2209         case MPSIO_READ_EXT_CFG_PAGE:
 2210                 mps_page = malloc(ext_page_req->len, M_MPSUSER, M_WAITOK|M_ZERO);
 2211                 error = copyin(ext_page_req->buf, mps_page,
 2212                     sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
 2213                 if (error)
 2214                         break;
 2215                 mps_lock(sc);
 2216                 error = mps_user_read_extcfg_page(sc, ext_page_req, mps_page);
 2217                 mps_unlock(sc);
 2218                 if (error)
 2219                         break;
 2220                 error = copyout(mps_page, ext_page_req->buf, ext_page_req->len);
 2221                 break;
 2222         case MPSIO_WRITE_CFG_PAGE:
 2223                 mps_page = malloc(page_req->len, M_MPSUSER, M_WAITOK|M_ZERO);
 2224                 error = copyin(page_req->buf, mps_page, page_req->len);
 2225                 if (error)
 2226                         break;
 2227                 mps_lock(sc);
 2228                 error = mps_user_write_cfg_page(sc, page_req, mps_page);
 2229                 mps_unlock(sc);
 2230                 break;
 2231         case MPSIO_MPS_COMMAND:
 2232                 error = mps_user_command(sc, (struct mps_usr_command *)arg);
 2233                 break;
 2234         case MPTIOCTL_PASS_THRU:
 2235                 /*
 2236                  * The user has requested to pass through a command to be
 2237                  * executed by the MPT firmware.  Call our routine which does
 2238                  * this.  Only allow one passthru IOCTL at one time.
 2239                  */
 2240                 error = mps_user_pass_thru(sc, (mps_pass_thru_t *)arg);
 2241                 break;
 2242         case MPTIOCTL_GET_ADAPTER_DATA:
 2243                 /*
 2244                  * The user has requested to read adapter data.  Call our
 2245                  * routine which does this.
 2246                  */
 2247                 error = 0;
 2248                 mps_user_get_adapter_data(sc, (mps_adapter_data_t *)arg);
 2249                 break;
 2250         case MPTIOCTL_GET_PCI_INFO:
 2251                 /*
 2252                  * The user has requested to read pci info.  Call
 2253                  * our routine which does this.
 2254                  */
 2255                 mps_lock(sc);
 2256                 error = 0;
 2257                 mps_user_read_pci_info(sc, (mps_pci_info_t *)arg);
 2258                 mps_unlock(sc);
 2259                 break;
 2260         case MPTIOCTL_RESET_ADAPTER:
 2261                 mps_lock(sc);
 2262                 sc->port_enable_complete = 0;
 2263                 uint32_t reinit_start = time_uptime;
 2264                 error = mps_reinit(sc);
 2265                 /* Sleep for 300 second. */
 2266                 msleep_ret = msleep(&sc->port_enable_complete, &sc->mps_mtx, PRIBIO,
 2267                        "mps_porten", 300 * hz);
 2268                 mps_unlock(sc);
 2269                 if (msleep_ret)
 2270                         printf("Port Enable did not complete after Diag "
 2271                             "Reset msleep error %d.\n", msleep_ret);
 2272                 else
 2273                         mps_dprint(sc, MPS_USER,
 2274                                 "Hard Reset with Port Enable completed in %d seconds.\n",
 2275                                  (uint32_t) (time_uptime - reinit_start));
 2276                 break;
 2277         case MPTIOCTL_DIAG_ACTION:
 2278                 /*
 2279                  * The user has done a diag buffer action.  Call our routine
 2280                  * which does this.  Only allow one diag action at one time.
 2281                  */
 2282                 mps_lock(sc);
 2283                 error = mps_user_diag_action(sc, (mps_diag_action_t *)arg);
 2284                 mps_unlock(sc);
 2285                 break;
 2286         case MPTIOCTL_EVENT_QUERY:
 2287                 /*
 2288                  * The user has done an event query. Call our routine which does
 2289                  * this.
 2290                  */
 2291                 error = 0;
 2292                 mps_user_event_query(sc, (mps_event_query_t *)arg);
 2293                 break;
 2294         case MPTIOCTL_EVENT_ENABLE:
 2295                 /*
 2296                  * The user has done an event enable. Call our routine which
 2297                  * does this.
 2298                  */
 2299                 error = 0;
 2300                 mps_user_event_enable(sc, (mps_event_enable_t *)arg);
 2301                 break;
 2302         case MPTIOCTL_EVENT_REPORT:
 2303                 /*
 2304                  * The user has done an event report. Call our routine which
 2305                  * does this.
 2306                  */
 2307                 error = mps_user_event_report(sc, (mps_event_report_t *)arg);
 2308                 break;
 2309         case MPTIOCTL_REG_ACCESS:
 2310                 /*
 2311                  * The user has requested register access.  Call our routine
 2312                  * which does this.
 2313                  */
 2314                 mps_lock(sc);
 2315                 error = mps_user_reg_access(sc, (mps_reg_access_t *)arg);
 2316                 mps_unlock(sc);
 2317                 break;
 2318         case MPTIOCTL_BTDH_MAPPING:
 2319                 /*
 2320                  * The user has requested to translate a bus/target to a
 2321                  * DevHandle or a DevHandle to a bus/target.  Call our routine
 2322                  * which does this.
 2323                  */
 2324                 error = mps_user_btdh(sc, (mps_btdh_mapping_t *)arg);
 2325                 break;
 2326         default:
 2327                 error = ENOIOCTL;
 2328                 break;
 2329         }
 2330 
 2331         if (mps_page != NULL)
 2332                 free(mps_page, M_MPSUSER);
 2333 
 2334         return (error);
 2335 }
 2336 
 2337 #ifdef COMPAT_FREEBSD32
 2338 
 2339 struct mps_cfg_page_req32 {
 2340         MPI2_CONFIG_PAGE_HEADER header;
 2341         uint32_t page_address;
 2342         uint32_t buf;
 2343         int     len;    
 2344         uint16_t ioc_status;
 2345 };
 2346 
 2347 struct mps_ext_cfg_page_req32 {
 2348         MPI2_CONFIG_EXTENDED_PAGE_HEADER header;
 2349         uint32_t page_address;
 2350         uint32_t buf;
 2351         int     len;
 2352         uint16_t ioc_status;
 2353 };
 2354 
 2355 struct mps_raid_action32 {
 2356         uint8_t action;
 2357         uint8_t volume_bus;
 2358         uint8_t volume_id;
 2359         uint8_t phys_disk_num;
 2360         uint32_t action_data_word;
 2361         uint32_t buf;
 2362         int len;
 2363         uint32_t volume_status;
 2364         uint32_t action_data[4];
 2365         uint16_t action_status;
 2366         uint16_t ioc_status;
 2367         uint8_t write;
 2368 };
 2369 
 2370 struct mps_usr_command32 {
 2371         uint32_t req;
 2372         uint32_t req_len;
 2373         uint32_t rpl;
 2374         uint32_t rpl_len;
 2375         uint32_t buf;
 2376         int len;
 2377         uint32_t flags;
 2378 };
 2379 
 2380 #define MPSIO_READ_CFG_HEADER32 _IOWR('M', 200, struct mps_cfg_page_req32)
 2381 #define MPSIO_READ_CFG_PAGE32   _IOWR('M', 201, struct mps_cfg_page_req32)
 2382 #define MPSIO_READ_EXT_CFG_HEADER32 _IOWR('M', 202, struct mps_ext_cfg_page_req32)
 2383 #define MPSIO_READ_EXT_CFG_PAGE32 _IOWR('M', 203, struct mps_ext_cfg_page_req32)
 2384 #define MPSIO_WRITE_CFG_PAGE32  _IOWR('M', 204, struct mps_cfg_page_req32)
 2385 #define MPSIO_RAID_ACTION32     _IOWR('M', 205, struct mps_raid_action32)
 2386 #define MPSIO_MPS_COMMAND32     _IOWR('M', 210, struct mps_usr_command32)
 2387 
 2388 static int
 2389 mps_ioctl32(struct cdev *dev, u_long cmd32, void *_arg, int flag,
 2390     struct thread *td)
 2391 {
 2392         struct mps_cfg_page_req32 *page32 = _arg;
 2393         struct mps_ext_cfg_page_req32 *ext32 = _arg;
 2394         struct mps_raid_action32 *raid32 = _arg;
 2395         struct mps_usr_command32 *user32 = _arg;
 2396         union {
 2397                 struct mps_cfg_page_req page;
 2398                 struct mps_ext_cfg_page_req ext;
 2399                 struct mps_raid_action raid;
 2400                 struct mps_usr_command user;
 2401         } arg;
 2402         u_long cmd;
 2403         int error;
 2404 
 2405         switch (cmd32) {
 2406         case MPSIO_READ_CFG_HEADER32:
 2407         case MPSIO_READ_CFG_PAGE32:
 2408         case MPSIO_WRITE_CFG_PAGE32:
 2409                 if (cmd32 == MPSIO_READ_CFG_HEADER32)
 2410                         cmd = MPSIO_READ_CFG_HEADER;
 2411                 else if (cmd32 == MPSIO_READ_CFG_PAGE32)
 2412                         cmd = MPSIO_READ_CFG_PAGE;
 2413                 else
 2414                         cmd = MPSIO_WRITE_CFG_PAGE;
 2415                 CP(*page32, arg.page, header);
 2416                 CP(*page32, arg.page, page_address);
 2417                 PTRIN_CP(*page32, arg.page, buf);
 2418                 CP(*page32, arg.page, len);
 2419                 CP(*page32, arg.page, ioc_status);
 2420                 break;
 2421 
 2422         case MPSIO_READ_EXT_CFG_HEADER32:
 2423         case MPSIO_READ_EXT_CFG_PAGE32:
 2424                 if (cmd32 == MPSIO_READ_EXT_CFG_HEADER32)
 2425                         cmd = MPSIO_READ_EXT_CFG_HEADER;
 2426                 else
 2427                         cmd = MPSIO_READ_EXT_CFG_PAGE;
 2428                 CP(*ext32, arg.ext, header);
 2429                 CP(*ext32, arg.ext, page_address);
 2430                 PTRIN_CP(*ext32, arg.ext, buf);
 2431                 CP(*ext32, arg.ext, len);
 2432                 CP(*ext32, arg.ext, ioc_status);
 2433                 break;
 2434 
 2435         case MPSIO_RAID_ACTION32:
 2436                 cmd = MPSIO_RAID_ACTION;
 2437                 CP(*raid32, arg.raid, action);
 2438                 CP(*raid32, arg.raid, volume_bus);
 2439                 CP(*raid32, arg.raid, volume_id);
 2440                 CP(*raid32, arg.raid, phys_disk_num);
 2441                 CP(*raid32, arg.raid, action_data_word);
 2442                 PTRIN_CP(*raid32, arg.raid, buf);
 2443                 CP(*raid32, arg.raid, len);
 2444                 CP(*raid32, arg.raid, volume_status);
 2445                 bcopy(raid32->action_data, arg.raid.action_data,
 2446                     sizeof arg.raid.action_data);
 2447                 CP(*raid32, arg.raid, ioc_status);
 2448                 CP(*raid32, arg.raid, write);
 2449                 break;
 2450 
 2451         case MPSIO_MPS_COMMAND32:
 2452                 cmd = MPSIO_MPS_COMMAND;
 2453                 PTRIN_CP(*user32, arg.user, req);
 2454                 CP(*user32, arg.user, req_len);
 2455                 PTRIN_CP(*user32, arg.user, rpl);
 2456                 CP(*user32, arg.user, rpl_len);
 2457                 PTRIN_CP(*user32, arg.user, buf);
 2458                 CP(*user32, arg.user, len);
 2459                 CP(*user32, arg.user, flags);
 2460                 break;
 2461         default:
 2462                 return (ENOIOCTL);
 2463         }
 2464 
 2465         error = mps_ioctl(dev, cmd, &arg, flag, td);
 2466         if (error == 0 && (cmd32 & IOC_OUT) != 0) {
 2467                 switch (cmd32) {
 2468                 case MPSIO_READ_CFG_HEADER32:
 2469                 case MPSIO_READ_CFG_PAGE32:
 2470                 case MPSIO_WRITE_CFG_PAGE32:
 2471                         CP(arg.page, *page32, header);
 2472                         CP(arg.page, *page32, page_address);
 2473                         PTROUT_CP(arg.page, *page32, buf);
 2474                         CP(arg.page, *page32, len);
 2475                         CP(arg.page, *page32, ioc_status);
 2476                         break;
 2477 
 2478                 case MPSIO_READ_EXT_CFG_HEADER32:
 2479                 case MPSIO_READ_EXT_CFG_PAGE32:
 2480                         CP(arg.ext, *ext32, header);
 2481                         CP(arg.ext, *ext32, page_address);
 2482                         PTROUT_CP(arg.ext, *ext32, buf);
 2483                         CP(arg.ext, *ext32, len);
 2484                         CP(arg.ext, *ext32, ioc_status);
 2485                         break;
 2486 
 2487                 case MPSIO_RAID_ACTION32:
 2488                         CP(arg.raid, *raid32, action);
 2489                         CP(arg.raid, *raid32, volume_bus);
 2490                         CP(arg.raid, *raid32, volume_id);
 2491                         CP(arg.raid, *raid32, phys_disk_num);
 2492                         CP(arg.raid, *raid32, action_data_word);
 2493                         PTROUT_CP(arg.raid, *raid32, buf);
 2494                         CP(arg.raid, *raid32, len);
 2495                         CP(arg.raid, *raid32, volume_status);
 2496                         bcopy(arg.raid.action_data, raid32->action_data,
 2497                             sizeof arg.raid.action_data);
 2498                         CP(arg.raid, *raid32, ioc_status);
 2499                         CP(arg.raid, *raid32, write);
 2500                         break;
 2501 
 2502                 case MPSIO_MPS_COMMAND32:
 2503                         PTROUT_CP(arg.user, *user32, req);
 2504                         CP(arg.user, *user32, req_len);
 2505                         PTROUT_CP(arg.user, *user32, rpl);
 2506                         CP(arg.user, *user32, rpl_len);
 2507                         PTROUT_CP(arg.user, *user32, buf);
 2508                         CP(arg.user, *user32, len);
 2509                         CP(arg.user, *user32, flags);
 2510                         break;
 2511                 }
 2512         }
 2513 
 2514         return (error);
 2515 }
 2516 #endif /* COMPAT_FREEBSD32 */
 2517 
 2518 static int
 2519 mps_ioctl_devsw(struct cdev *dev, u_long com, caddr_t arg, int flag,
 2520     struct thread *td)
 2521 {
 2522 #ifdef COMPAT_FREEBSD32
 2523         if (SV_CURPROC_FLAG(SV_ILP32))
 2524                 return (mps_ioctl32(dev, com, arg, flag, td));
 2525 #endif
 2526         return (mps_ioctl(dev, com, arg, flag, td));
 2527 }

Cache object: aa69a0854599a6f7d8f5d0ffc9715ea5


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.