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

Cache object: 851aaaca651f4918a51edfb392f83d92


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