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

Cache object: c49d1e7b705ef9102f269538e1cf4540


[ 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.