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/ic/mpt.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 /*      $NetBSD: mpt.c,v 1.10.42.1 2010/12/02 23:45:59 snj Exp $        */
    2 
    3 /*
    4  * Copyright (c) 2000, 2001 by Greg Ansley
    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 immediately at the beginning of the file, without modification,
   11  *    this list of conditions, and the following disclaimer.
   12  * 2. The name of the author may not be used to endorse or promote products
   13  *    derived from this software without specific prior written permission.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   19  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 /*
   28  * Additional Copyright (c) 2002 by Matthew Jacob under same license.
   29  */
   30 /*-
   31  * Copyright (c) 2002, 2006 by Matthew Jacob
   32  * All rights reserved.
   33  *
   34  * Redistribution and use in source and binary forms, with or without
   35  * modification, are permitted provided that the following conditions are
   36  * met:
   37  * 1. Redistributions of source code must retain the above copyright
   38  *    notice, this list of conditions and the following disclaimer.
   39  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
   40  *    substantially similar to the "NO WARRANTY" disclaimer below
   41  *    ("Disclaimer") and any redistribution must be conditioned upon including
   42  *    a substantially similar Disclaimer requirement for further binary
   43  *    redistribution.
   44  * 3. Neither the names of the above listed copyright holders nor the names
   45  *    of any contributors may be used to endorse or promote products derived
   46  *    from this software without specific prior written permission.
   47  *
   48  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   49  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   50  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   51  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
   52  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   53  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   54  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   55  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   56  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   57  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF THE COPYRIGHT
   58  * OWNER OR CONTRIBUTOR IS ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   59  *
   60  * Support from Chris Ellsworth in order to make SAS adapters work
   61  * is gratefully acknowledged.
   62  *
   63  *
   64  * Support from LSI-Logic has also gone a great deal toward making this a
   65  * workable subsystem and is gratefully acknowledged.
   66  */
   67 /*-
   68  * Copyright (c) 2004, Avid Technology, Inc. and its contributors.
   69  * Copyright (c) 2005, WHEEL Sp. z o.o.
   70  * Copyright (c) 2004, 2005 Justin T. Gibbs
   71  * All rights reserved.
   72  *
   73  * Redistribution and use in source and binary forms, with or without
   74  * modification, are permitted provided that the following conditions are
   75  * met:
   76  * 1. Redistributions of source code must retain the above copyright
   77  *    notice, this list of conditions and the following disclaimer.
   78  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
   79  *    substantially similar to the "NO WARRANTY" disclaimer below
   80  *    ("Disclaimer") and any redistribution must be conditioned upon including
   81  *    a substantially similar Disclaimer requirement for further binary
   82  *    redistribution.
   83  * 3. Neither the names of the above listed copyright holders nor the names
   84  *    of any contributors may be used to endorse or promote products derived
   85  *    from this software without specific prior written permission.
   86  *
   87  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   88  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   89  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   90  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
   91  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   92  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   93  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   94  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   95  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   96  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF THE COPYRIGHT
   97  * OWNER OR CONTRIBUTOR IS ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   98  */
   99 
  100 
  101 /*
  102  * mpt.c:
  103  *
  104  * Generic routines for LSI Fusion adapters.
  105  *
  106  * Adapted from the FreeBSD "mpt" driver by Jason R. Thorpe for
  107  * Wasabi Systems, Inc.
  108  *
  109  * Additional contributions by Garrett D'Amore on behalf of TELES AG.
  110  */
  111 
  112 #include <sys/cdefs.h>
  113 __KERNEL_RCSID(0, "$NetBSD: mpt.c,v 1.10.42.1 2010/12/02 23:45:59 snj Exp $");
  114 
  115 #include <dev/ic/mpt.h>
  116 
  117 #define MPT_MAX_TRYS 3
  118 #define MPT_MAX_WAIT 300000
  119 
  120 static int maxwait_ack = 0;
  121 static int maxwait_int = 0;
  122 static int maxwait_state = 0;
  123 
  124 static inline u_int32_t
  125 mpt_rd_db(mpt_softc_t *mpt)
  126 {
  127         return mpt_read(mpt, MPT_OFFSET_DOORBELL);
  128 }
  129 
  130 static inline u_int32_t
  131 mpt_rd_intr(mpt_softc_t *mpt)
  132 {
  133         return mpt_read(mpt, MPT_OFFSET_INTR_STATUS);
  134 }
  135 
  136 /* Busy wait for a door bell to be read by IOC */
  137 static int
  138 mpt_wait_db_ack(mpt_softc_t *mpt)
  139 {
  140         int i;
  141         for (i=0; i < MPT_MAX_WAIT; i++) {
  142                 if (!MPT_DB_IS_BUSY(mpt_rd_intr(mpt))) {
  143                         maxwait_ack = i > maxwait_ack ? i : maxwait_ack;
  144                         return MPT_OK;
  145                 }
  146 
  147                 DELAY(100);
  148         }
  149         return MPT_FAIL;
  150 }
  151 
  152 /* Busy wait for a door bell interrupt */
  153 static int
  154 mpt_wait_db_int(mpt_softc_t *mpt)
  155 {
  156         int i;
  157         for (i=0; i < MPT_MAX_WAIT; i++) {
  158                 if (MPT_DB_INTR(mpt_rd_intr(mpt))) {
  159                         maxwait_int = i > maxwait_int ? i : maxwait_int;
  160                         return MPT_OK;
  161                 }
  162                 DELAY(100);
  163         }
  164         return MPT_FAIL;
  165 }
  166 
  167 /* Wait for IOC to transition to a give state */
  168 void
  169 mpt_check_doorbell(mpt_softc_t *mpt)
  170 {
  171         u_int32_t db = mpt_rd_db(mpt);
  172         if (MPT_STATE(db) != MPT_DB_STATE_RUNNING) {
  173                 mpt_prt(mpt, "Device not running");
  174                 mpt_print_db(db);
  175         }
  176 }
  177 
  178 /* Wait for IOC to transition to a give state */
  179 static int
  180 mpt_wait_state(mpt_softc_t *mpt, enum DB_STATE_BITS state)
  181 {
  182         int i;
  183 
  184         for (i = 0; i < MPT_MAX_WAIT; i++) {
  185                 u_int32_t db = mpt_rd_db(mpt);
  186                 if (MPT_STATE(db) == state) {
  187                         maxwait_state = i > maxwait_state ? i : maxwait_state;
  188                         return (MPT_OK);
  189                 }
  190                 DELAY(100);
  191         }
  192         return (MPT_FAIL);
  193 }
  194 
  195 
  196 /* Issue the reset COMMAND to the IOC */
  197 int
  198 mpt_soft_reset(mpt_softc_t *mpt)
  199 {
  200         if (mpt->verbose) {
  201                 mpt_prt(mpt, "soft reset");
  202         }
  203 
  204         /* Have to use hard reset if we are not in Running state */
  205         if (MPT_STATE(mpt_rd_db(mpt)) != MPT_DB_STATE_RUNNING) {
  206                 mpt_prt(mpt, "soft reset failed: device not running");
  207                 return MPT_FAIL;
  208         }
  209 
  210         /* If door bell is in use we don't have a chance of getting
  211          * a word in since the IOC probably crashed in message
  212          * processing. So don't waste our time.
  213          */
  214         if (MPT_DB_IS_IN_USE(mpt_rd_db(mpt))) {
  215                 mpt_prt(mpt, "soft reset failed: doorbell wedged");
  216                 return MPT_FAIL;
  217         }
  218 
  219         /* Send the reset request to the IOC */
  220         mpt_write(mpt, MPT_OFFSET_DOORBELL,
  221             MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET << MPI_DOORBELL_FUNCTION_SHIFT);
  222         if (mpt_wait_db_ack(mpt) != MPT_OK) {
  223                 mpt_prt(mpt, "soft reset failed: ack timeout");
  224                 return MPT_FAIL;
  225         }
  226 
  227         /* Wait for the IOC to reload and come out of reset state */
  228         if (mpt_wait_state(mpt, MPT_DB_STATE_READY) != MPT_OK) {
  229                 mpt_prt(mpt, "soft reset failed: device did not start running");
  230                 return MPT_FAIL;
  231         }
  232 
  233         return MPT_OK;
  234 }
  235 
  236 /* This is a magic diagnostic reset that resets all the ARM
  237  * processors in the chip.
  238  */
  239 void
  240 mpt_hard_reset(mpt_softc_t *mpt)
  241 {
  242         if (mpt->verbose) {
  243                 mpt_prt(mpt, "hard reset");
  244         }
  245         mpt_write(mpt, MPT_OFFSET_SEQUENCE, 0xff);
  246 
  247         /* Enable diagnostic registers */
  248         mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_1);
  249         mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_2);
  250         mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_3);
  251         mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_4);
  252         mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_5);
  253 
  254         /* Diag. port is now active so we can now hit the reset bit */
  255         mpt_write(mpt, MPT_OFFSET_DIAGNOSTIC, MPT_DIAG_RESET_IOC);
  256 
  257         DELAY(10000);
  258 
  259         /* Disable Diagnostic Register */
  260         mpt_write(mpt, MPT_OFFSET_SEQUENCE, 0xFF);
  261 }
  262 
  263 /*
  264  * Reset the IOC when needed. Try software command first then if needed
  265  * poke at the magic diagnostic reset. Note that a hard reset resets
  266  * *both* IOCs on dual function chips (FC929 && LSI1030) as well as
  267  * fouls up the PCI configuration registers.
  268  */
  269 int
  270 mpt_reset(mpt_softc_t *mpt)
  271 {
  272         int ret;
  273 
  274         /* Try a soft reset */
  275         if ((ret = mpt_soft_reset(mpt)) != MPT_OK) {
  276                 /* Failed; do a hard reset */
  277                 mpt_hard_reset(mpt);
  278 
  279                 /* Wait for the IOC to reload and come out of reset state */
  280                 ret = mpt_wait_state(mpt, MPT_DB_STATE_READY);
  281                 if (ret != MPT_OK) {
  282                         mpt_prt(mpt, "failed to reset device");
  283                 }
  284         }
  285 
  286         return ret;
  287 }
  288 
  289 /* Return a command buffer to the free queue */
  290 void
  291 mpt_free_request(mpt_softc_t *mpt, request_t *req)
  292 {
  293         if (req == NULL || req != &mpt->request_pool[req->index]) {
  294                 panic("mpt_free_request bad req ptr\n");
  295                 return;
  296         }
  297         req->sequence = 0;
  298         req->xfer = NULL;
  299         req->debug = REQ_FREE;
  300         SLIST_INSERT_HEAD(&mpt->request_free_list, req, link);
  301 }
  302 
  303 /* Get a command buffer from the free queue */
  304 request_t *
  305 mpt_get_request(mpt_softc_t *mpt)
  306 {
  307         request_t *req;
  308         req = SLIST_FIRST(&mpt->request_free_list);
  309         if (req != NULL) {
  310                 if (req != &mpt->request_pool[req->index]) {
  311                         panic("mpt_get_request: corrupted request free list\n");
  312                 }
  313                 if (req->xfer != NULL) {
  314                         panic("mpt_get_request: corrupted request free list (xfer)\n");
  315                 }
  316                 SLIST_REMOVE_HEAD(&mpt->request_free_list, link);
  317                 req->debug = REQ_IN_PROGRESS;
  318         }
  319         return req;
  320 }
  321 
  322 /* Pass the command to the IOC */
  323 void
  324 mpt_send_cmd(mpt_softc_t *mpt, request_t *req)
  325 {
  326         req->sequence = mpt->sequence++;
  327         if (mpt->verbose > 1) {
  328                 u_int32_t *pReq;
  329                 pReq = req->req_vbuf;
  330                 mpt_prt(mpt, "Send Request %d (0x%x):",
  331                     req->index, req->req_pbuf);
  332                 mpt_prt(mpt, "%08x %08x %08x %08x",
  333                     pReq[0], pReq[1], pReq[2], pReq[3]);
  334                 mpt_prt(mpt, "%08x %08x %08x %08x",
  335                     pReq[4], pReq[5], pReq[6], pReq[7]);
  336                 mpt_prt(mpt, "%08x %08x %08x %08x",
  337                     pReq[8], pReq[9], pReq[10], pReq[11]);
  338                 mpt_prt(mpt, "%08x %08x %08x %08x",
  339                     pReq[12], pReq[13], pReq[14], pReq[15]);
  340         }
  341         MPT_SYNC_REQ(mpt, req, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
  342         req->debug = REQ_ON_CHIP;
  343         mpt_write(mpt, MPT_OFFSET_REQUEST_Q, (u_int32_t) req->req_pbuf);
  344 }
  345 
  346 /*
  347  * Give the reply buffer back to the IOC after we have
  348  * finished processing it.
  349  */
  350 void
  351 mpt_free_reply(mpt_softc_t *mpt, u_int32_t ptr)
  352 {
  353      mpt_write(mpt, MPT_OFFSET_REPLY_Q, ptr);
  354 }
  355 
  356 /* Get a reply from the IOC */
  357 u_int32_t
  358 mpt_pop_reply_queue(mpt_softc_t *mpt)
  359 {
  360      return mpt_read(mpt, MPT_OFFSET_REPLY_Q);
  361 }
  362 
  363 /*
  364  * Send a command to the IOC via the handshake register.
  365  *
  366  * Only done at initialization time and for certain unusual
  367  * commands such as device/bus reset as specified by LSI.
  368  */
  369 int
  370 mpt_send_handshake_cmd(mpt_softc_t *mpt, size_t len, void *cmd)
  371 {
  372         int i;
  373         u_int32_t data, *data32;
  374 
  375         /* Check condition of the IOC */
  376         data = mpt_rd_db(mpt);
  377         if (((MPT_STATE(data) != MPT_DB_STATE_READY)    &&
  378              (MPT_STATE(data) != MPT_DB_STATE_RUNNING)  &&
  379              (MPT_STATE(data) != MPT_DB_STATE_FAULT))   ||
  380             (  MPT_DB_IS_IN_USE(data) )) {
  381                 mpt_prt(mpt, "handshake aborted due to invalid doorbell state");
  382                 mpt_print_db(data);
  383                 return(EBUSY);
  384         }
  385 
  386         /* We move things in 32 bit chunks */
  387         len = (len + 3) >> 2;
  388         data32 = cmd;
  389 
  390         /* Clear any left over pending doorbell interrupts */
  391         if (MPT_DB_INTR(mpt_rd_intr(mpt)))
  392                 mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
  393 
  394         /*
  395          * Tell the handshake reg. we are going to send a command
  396          * and how long it is going to be.
  397          */
  398         data = (MPI_FUNCTION_HANDSHAKE << MPI_DOORBELL_FUNCTION_SHIFT) |
  399             (len << MPI_DOORBELL_ADD_DWORDS_SHIFT);
  400         mpt_write(mpt, MPT_OFFSET_DOORBELL, data);
  401 
  402         /* Wait for the chip to notice */
  403         if (mpt_wait_db_int(mpt) != MPT_OK) {
  404                 mpt_prt(mpt, "mpt_send_handshake_cmd timeout1");
  405                 return ETIMEDOUT;
  406         }
  407 
  408         /* Clear the interrupt */
  409         mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
  410 
  411         if (mpt_wait_db_ack(mpt) != MPT_OK) {
  412                 mpt_prt(mpt, "mpt_send_handshake_cmd timeout2");
  413                 return ETIMEDOUT;
  414         }
  415 
  416         /* Send the command */
  417         for (i = 0; i < len; i++) {
  418                 mpt_write(mpt, MPT_OFFSET_DOORBELL, htole32(*data32++));
  419                 if (mpt_wait_db_ack(mpt) != MPT_OK) {
  420                         mpt_prt(mpt,
  421                             "mpt_send_handshake_cmd timeout! index = %d", i);
  422                         return ETIMEDOUT;
  423                 }
  424         }
  425         return MPT_OK;
  426 }
  427 
  428 /* Get the response from the handshake register */
  429 int
  430 mpt_recv_handshake_reply(mpt_softc_t *mpt, size_t reply_len, void *reply)
  431 {
  432         int left, reply_left;
  433         u_int16_t *data16;
  434         MSG_DEFAULT_REPLY *hdr;
  435 
  436         /* We move things out in 16 bit chunks */
  437         reply_len >>= 1;
  438         data16 = (u_int16_t *)reply;
  439 
  440         hdr = (MSG_DEFAULT_REPLY *)reply;
  441 
  442         /* Get first word */
  443         if (mpt_wait_db_int(mpt) != MPT_OK) {
  444                 mpt_prt(mpt, "mpt_recv_handshake_cmd timeout1");
  445                 return ETIMEDOUT;
  446         }
  447         *data16++ = le16toh(mpt_read(mpt, MPT_OFFSET_DOORBELL) &
  448                             MPT_DB_DATA_MASK);
  449         mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
  450 
  451         /* Get Second Word */
  452         if (mpt_wait_db_int(mpt) != MPT_OK) {
  453                 mpt_prt(mpt, "mpt_recv_handshake_cmd timeout2");
  454                 return ETIMEDOUT;
  455         }
  456         *data16++ = le16toh(mpt_read(mpt, MPT_OFFSET_DOORBELL) &
  457                             MPT_DB_DATA_MASK);
  458         mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
  459 
  460         /* With the second word, we can now look at the length */
  461         if (mpt->verbose > 1 && ((reply_len >> 1) != hdr->MsgLength)) {
  462                 mpt_prt(mpt, "reply length does not match message length: "
  463                         "got 0x%02x, expected 0x%02x",
  464                         hdr->MsgLength << 2, reply_len << 1);
  465         }
  466 
  467         /* Get rest of the reply; but don't overflow the provided buffer */
  468         left = (hdr->MsgLength << 1) - 2;
  469         reply_left =  reply_len - 2;
  470         while (left--) {
  471                 u_int16_t datum;
  472 
  473                 if (mpt_wait_db_int(mpt) != MPT_OK) {
  474                         mpt_prt(mpt, "mpt_recv_handshake_cmd timeout3");
  475                         return ETIMEDOUT;
  476                 }
  477                 datum = mpt_read(mpt, MPT_OFFSET_DOORBELL);
  478 
  479                 if (reply_left-- > 0)
  480                         *data16++ = le16toh(datum & MPT_DB_DATA_MASK);
  481 
  482                 mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
  483         }
  484 
  485         /* One more wait & clear at the end */
  486         if (mpt_wait_db_int(mpt) != MPT_OK) {
  487                 mpt_prt(mpt, "mpt_recv_handshake_cmd timeout4");
  488                 return ETIMEDOUT;
  489         }
  490         mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
  491 
  492         if ((hdr->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
  493                 if (mpt->verbose > 1)
  494                         mpt_print_reply(hdr);
  495                 return (MPT_FAIL | hdr->IOCStatus);
  496         }
  497 
  498         return (0);
  499 }
  500 
  501 static int
  502 mpt_get_iocfacts(mpt_softc_t *mpt, MSG_IOC_FACTS_REPLY *freplp)
  503 {
  504         MSG_IOC_FACTS f_req;
  505         int error;
  506 
  507         bzero(&f_req, sizeof f_req);
  508         f_req.Function = MPI_FUNCTION_IOC_FACTS;
  509         f_req.MsgContext = htole32(0x12071942);
  510         error = mpt_send_handshake_cmd(mpt, sizeof f_req, &f_req);
  511         if (error)
  512                 return(error);
  513         error = mpt_recv_handshake_reply(mpt, sizeof (*freplp), freplp);
  514         return (error);
  515 }
  516 
  517 static int
  518 mpt_get_portfacts(mpt_softc_t *mpt, MSG_PORT_FACTS_REPLY *freplp)
  519 {
  520         MSG_PORT_FACTS f_req;
  521         int error;
  522 
  523         /* XXX: Only getting PORT FACTS for Port 0 */
  524         bzero(&f_req, sizeof f_req);
  525         f_req.Function = MPI_FUNCTION_PORT_FACTS;
  526         f_req.MsgContext =  htole32(0x12071943);
  527         error = mpt_send_handshake_cmd(mpt, sizeof f_req, &f_req);
  528         if (error)
  529                 return(error);
  530         error = mpt_recv_handshake_reply(mpt, sizeof (*freplp), freplp);
  531         return (error);
  532 }
  533 
  534 /*
  535  * Send the initialization request. This is where we specify how many
  536  * SCSI busses and how many devices per bus we wish to emulate.
  537  * This is also the command that specifies the max size of the reply
  538  * frames from the IOC that we will be allocating.
  539  */
  540 static int
  541 mpt_send_ioc_init(mpt_softc_t *mpt, u_int32_t who)
  542 {
  543         int error = 0;
  544         MSG_IOC_INIT init;
  545         MSG_IOC_INIT_REPLY reply;
  546 
  547         bzero(&init, sizeof init);
  548         init.WhoInit = who;
  549         init.Function = MPI_FUNCTION_IOC_INIT;
  550         init.MaxDevices = mpt->mpt_max_devices;
  551         init.MaxBuses = 1;
  552         init.ReplyFrameSize = htole16(MPT_REPLY_SIZE);
  553         init.MsgContext = htole32(0x12071941);
  554 
  555         if ((error = mpt_send_handshake_cmd(mpt, sizeof init, &init)) != 0) {
  556                 return(error);
  557         }
  558 
  559         error = mpt_recv_handshake_reply(mpt, sizeof reply, &reply);
  560         return (error);
  561 }
  562 
  563 
  564 /*
  565  * Utiltity routine to read configuration headers and pages
  566  */
  567 
  568 static int
  569 mpt_read_cfg_header(mpt_softc_t *, int, int, int, fCONFIG_PAGE_HEADER *);
  570 
  571 static int
  572 mpt_read_cfg_header(mpt_softc_t *mpt, int PageType, int PageNumber,
  573     int PageAddress, fCONFIG_PAGE_HEADER *rslt)
  574 {
  575         int count;
  576         request_t *req;
  577         MSG_CONFIG *cfgp;
  578         MSG_CONFIG_REPLY *reply;
  579 
  580         req = mpt_get_request(mpt);
  581 
  582         cfgp = req->req_vbuf;
  583         bzero(cfgp, sizeof *cfgp);
  584 
  585         cfgp->Action = MPI_CONFIG_ACTION_PAGE_HEADER;
  586         cfgp->Function = MPI_FUNCTION_CONFIG;
  587         cfgp->Header.PageNumber = (U8) PageNumber;
  588         cfgp->Header.PageType = (U8) PageType;
  589         cfgp->PageAddress = htole32(PageAddress);
  590         MPI_pSGE_SET_FLAGS(((SGE_SIMPLE32 *) &cfgp->PageBufferSGE),
  591             (MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
  592             MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_LIST));
  593         cfgp->MsgContext = htole32(req->index | 0x80000000);
  594 
  595         mpt_check_doorbell(mpt);
  596         mpt_send_cmd(mpt, req);
  597         count = 0;
  598         do {
  599                 DELAY(500);
  600                 mpt_intr(mpt);
  601                 if (++count == 1000) {
  602                         mpt_prt(mpt, "read_cfg_header timed out");
  603                         return (-1);
  604                 }
  605         } while (req->debug == REQ_ON_CHIP);
  606 
  607         reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence);
  608         if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
  609                 mpt_prt(mpt, "mpt_read_cfg_header: Config Info Status %x",
  610                     reply->IOCStatus);
  611                 mpt_free_reply(mpt, (req->sequence << 1));
  612                 return (-1);
  613         }
  614         bcopy(&reply->Header, rslt, sizeof (fCONFIG_PAGE_HEADER));
  615         mpt_free_reply(mpt, (req->sequence << 1));
  616         mpt_free_request(mpt, req);
  617         return (0);
  618 }
  619 
  620 #define CFG_DATA_OFF    128
  621 
  622 int
  623 mpt_read_cfg_page(mpt_softc_t *mpt, int PageAddress, fCONFIG_PAGE_HEADER *hdr)
  624 {
  625         int count;
  626         request_t *req;
  627         SGE_SIMPLE32 *se;
  628         MSG_CONFIG *cfgp;
  629         size_t amt;
  630         MSG_CONFIG_REPLY *reply;
  631 
  632         req = mpt_get_request(mpt);
  633 
  634         cfgp = req->req_vbuf;
  635         bzero(cfgp, MPT_REQUEST_AREA);
  636         cfgp->Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
  637         cfgp->Function = MPI_FUNCTION_CONFIG;
  638         cfgp->Header = *hdr;
  639         amt = (cfgp->Header.PageLength * sizeof (u_int32_t));
  640         cfgp->Header.PageType &= MPI_CONFIG_PAGETYPE_MASK;
  641         cfgp->PageAddress = htole32(PageAddress);
  642         se = (SGE_SIMPLE32 *) &cfgp->PageBufferSGE;
  643         se->Address = htole32(req->req_pbuf + CFG_DATA_OFF);
  644         MPI_pSGE_SET_LENGTH(se, amt);
  645         MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
  646             MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
  647             MPI_SGE_FLAGS_END_OF_LIST));
  648         se->FlagsLength = htole32(se->FlagsLength);
  649 
  650         cfgp->MsgContext = htole32(req->index | 0x80000000);
  651 
  652         mpt_check_doorbell(mpt);
  653         mpt_send_cmd(mpt, req);
  654         count = 0;
  655         do {
  656                 DELAY(500);
  657                 mpt_intr(mpt);
  658                 if (++count == 1000) {
  659                         mpt_prt(mpt, "read_cfg_page timed out");
  660                         return (-1);
  661                 }
  662         } while (req->debug == REQ_ON_CHIP);
  663 
  664         reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence);
  665         if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
  666                 mpt_prt(mpt, "mpt_read_cfg_page: Config Info Status %x",
  667                     reply->IOCStatus);
  668                 mpt_free_reply(mpt, (req->sequence << 1));
  669                 return (-1);
  670         }
  671         mpt_free_reply(mpt, (req->sequence << 1));
  672 #if 0 /* XXXJRT */
  673         bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap,
  674             BUS_DMASYNC_POSTREAD);
  675 #endif
  676         if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
  677             cfgp->Header.PageNumber == 0) {
  678                 amt = sizeof (fCONFIG_PAGE_SCSI_PORT_0);
  679         } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
  680             cfgp->Header.PageNumber == 1) {
  681                 amt = sizeof (fCONFIG_PAGE_SCSI_PORT_1);
  682         } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
  683             cfgp->Header.PageNumber == 2) {
  684                 amt = sizeof (fCONFIG_PAGE_SCSI_PORT_2);
  685         } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE  &&
  686             cfgp->Header.PageNumber == 0) {
  687                 amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_0);
  688         } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE  &&
  689             cfgp->Header.PageNumber == 1) {
  690                 amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_1);
  691         }
  692         memcpy(hdr, (char *)req->req_vbuf + CFG_DATA_OFF, amt);
  693         mpt_free_request(mpt, req);
  694         return (0);
  695 }
  696 
  697 int
  698 mpt_write_cfg_page(mpt_softc_t *mpt, int PageAddress, fCONFIG_PAGE_HEADER *hdr)
  699 {
  700         int count, hdr_attr;
  701         request_t *req;
  702         SGE_SIMPLE32 *se;
  703         MSG_CONFIG *cfgp;
  704         size_t amt;
  705         MSG_CONFIG_REPLY *reply;
  706 
  707         req = mpt_get_request(mpt);
  708 
  709         cfgp = req->req_vbuf;
  710         bzero(cfgp, sizeof *cfgp);
  711 
  712         hdr_attr = hdr->PageType & MPI_CONFIG_PAGEATTR_MASK;
  713         if (hdr_attr != MPI_CONFIG_PAGEATTR_CHANGEABLE &&
  714             hdr_attr != MPI_CONFIG_PAGEATTR_PERSISTENT) {
  715                 mpt_prt(mpt, "page type 0x%x not changeable",
  716                     hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
  717                 return (-1);
  718         }
  719         hdr->PageType &= MPI_CONFIG_PAGETYPE_MASK;
  720 
  721         cfgp->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
  722         cfgp->Function = MPI_FUNCTION_CONFIG;
  723         cfgp->Header = *hdr;
  724         amt = (cfgp->Header.PageLength * sizeof (u_int32_t));
  725         cfgp->PageAddress = htole32(PageAddress);
  726 
  727         se = (SGE_SIMPLE32 *) &cfgp->PageBufferSGE;
  728         se->Address = htole32(req->req_pbuf + CFG_DATA_OFF);
  729         MPI_pSGE_SET_LENGTH(se, amt);
  730         MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
  731             MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
  732             MPI_SGE_FLAGS_END_OF_LIST | MPI_SGE_FLAGS_HOST_TO_IOC));
  733         se->FlagsLength = htole32(se->FlagsLength);
  734 
  735         cfgp->MsgContext = htole32(req->index | 0x80000000);
  736 
  737         if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
  738             cfgp->Header.PageNumber == 0) {
  739                 amt = sizeof (fCONFIG_PAGE_SCSI_PORT_0);
  740         } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
  741             cfgp->Header.PageNumber == 1) {
  742                 amt = sizeof (fCONFIG_PAGE_SCSI_PORT_1);
  743         } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
  744             cfgp->Header.PageNumber == 2) {
  745                 amt = sizeof (fCONFIG_PAGE_SCSI_PORT_2);
  746         } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE  &&
  747             cfgp->Header.PageNumber == 0) {
  748                 amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_0);
  749         } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE  &&
  750             cfgp->Header.PageNumber == 1) {
  751                 amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_1);
  752         }
  753         memcpy((char *)req->req_vbuf + CFG_DATA_OFF, hdr, amt);
  754         /* Restore stripped out attributes */
  755         hdr->PageType |= hdr_attr;
  756 
  757         mpt_check_doorbell(mpt);
  758         mpt_send_cmd(mpt, req);
  759         count = 0;
  760         do {
  761                 DELAY(500);
  762                 mpt_intr(mpt);
  763                 if (++count == 1000) {
  764                         hdr->PageType |= hdr_attr;
  765                         mpt_prt(mpt, "mpt_write_cfg_page timed out");
  766                         return (-1);
  767                 }
  768         } while (req->debug == REQ_ON_CHIP);
  769 
  770         reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence);
  771         if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
  772                 mpt_prt(mpt, "mpt_write_cfg_page: Config Info Status %x",
  773                     le16toh(reply->IOCStatus));
  774                 mpt_free_reply(mpt, (req->sequence << 1));
  775                 return (-1);
  776         }
  777         mpt_free_reply(mpt, (req->sequence << 1));
  778 
  779         mpt_free_request(mpt, req);
  780         return (0);
  781 }
  782 
  783 /*
  784  * Read SCSI configuration information
  785  */
  786 static int
  787 mpt_read_config_info_spi(mpt_softc_t *mpt)
  788 {
  789         int rv, i;
  790 
  791         rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 0,
  792             0, &mpt->mpt_port_page0.Header);
  793         if (rv) {
  794                 return (-1);
  795         }
  796         if (mpt->verbose > 1) {
  797                 mpt_prt(mpt, "SPI Port Page 0 Header: %x %x %x %x",
  798                     mpt->mpt_port_page0.Header.PageVersion,
  799                     mpt->mpt_port_page0.Header.PageLength,
  800                     mpt->mpt_port_page0.Header.PageNumber,
  801                     mpt->mpt_port_page0.Header.PageType);
  802         }
  803 
  804         rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 1,
  805             0, &mpt->mpt_port_page1.Header);
  806         if (rv) {
  807                 return (-1);
  808         }
  809         if (mpt->verbose > 1) {
  810                 mpt_prt(mpt, "SPI Port Page 1 Header: %x %x %x %x",
  811                     mpt->mpt_port_page1.Header.PageVersion,
  812                     mpt->mpt_port_page1.Header.PageLength,
  813                     mpt->mpt_port_page1.Header.PageNumber,
  814                     mpt->mpt_port_page1.Header.PageType);
  815         }
  816 
  817         rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 2,
  818             0, &mpt->mpt_port_page2.Header);
  819         if (rv) {
  820                 return (-1);
  821         }
  822 
  823         if (mpt->verbose > 1) {
  824                 mpt_prt(mpt, "SPI Port Page 2 Header: %x %x %x %x",
  825                     mpt->mpt_port_page1.Header.PageVersion,
  826                     mpt->mpt_port_page1.Header.PageLength,
  827                     mpt->mpt_port_page1.Header.PageNumber,
  828                     mpt->mpt_port_page1.Header.PageType);
  829         }
  830 
  831         for (i = 0; i < 16; i++) {
  832                 rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE,
  833                     0, i, &mpt->mpt_dev_page0[i].Header);
  834                 if (rv) {
  835                         return (-1);
  836                 }
  837                 if (mpt->verbose > 1) {
  838                         mpt_prt(mpt,
  839                             "SPI Target %d Device Page 0 Header: %x %x %x %x",
  840                             i, mpt->mpt_dev_page0[i].Header.PageVersion,
  841                             mpt->mpt_dev_page0[i].Header.PageLength,
  842                             mpt->mpt_dev_page0[i].Header.PageNumber,
  843                             mpt->mpt_dev_page0[i].Header.PageType);
  844                 }
  845 
  846                 rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE,
  847                     1, i, &mpt->mpt_dev_page1[i].Header);
  848                 if (rv) {
  849                         return (-1);
  850                 }
  851                 if (mpt->verbose > 1) {
  852                         mpt_prt(mpt,
  853                             "SPI Target %d Device Page 1 Header: %x %x %x %x",
  854                             i, mpt->mpt_dev_page1[i].Header.PageVersion,
  855                             mpt->mpt_dev_page1[i].Header.PageLength,
  856                             mpt->mpt_dev_page1[i].Header.PageNumber,
  857                             mpt->mpt_dev_page1[i].Header.PageType);
  858                 }
  859         }
  860 
  861         /*
  862          * At this point, we don't *have* to fail. As long as we have
  863          * valid config header information, we can (barely) lurch
  864          * along.
  865          */
  866 
  867         rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page0.Header);
  868         mpt2host_config_page_scsi_port_0(&mpt->mpt_port_page0);
  869         if (rv) {
  870                 mpt_prt(mpt, "failed to read SPI Port Page 0");
  871         } else if (mpt->verbose > 1) {
  872                 mpt_prt(mpt,
  873                     "SPI Port Page 0: Capabilities %x PhysicalInterface %x",
  874                     mpt->mpt_port_page0.Capabilities,
  875                     mpt->mpt_port_page0.PhysicalInterface);
  876         }
  877 
  878         rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page1.Header);
  879         mpt2host_config_page_scsi_port_1(&mpt->mpt_port_page1);
  880         if (rv) {
  881                 mpt_prt(mpt, "failed to read SPI Port Page 1");
  882         } else if (mpt->verbose > 1) {
  883                 mpt_prt(mpt,
  884                     "SPI Port Page 1: Configuration %x OnBusTimerValue %x",
  885                     mpt->mpt_port_page1.Configuration,
  886                     mpt->mpt_port_page1.OnBusTimerValue);
  887         }
  888 
  889         rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page2.Header);
  890         mpt2host_config_page_scsi_port_2(&mpt->mpt_port_page2);
  891         if (rv) {
  892                 mpt_prt(mpt, "failed to read SPI Port Page 2");
  893         } else if (mpt->verbose > 1) {
  894                 mpt_prt(mpt,
  895                     "SPI Port Page 2: Flags %x Settings %x",
  896                     mpt->mpt_port_page2.PortFlags,
  897                     mpt->mpt_port_page2.PortSettings);
  898                 for (i = 0; i < 1; i++) {
  899                         mpt_prt(mpt,
  900                             "SPI Port Page 2 Tgt %d: timo %x SF %x Flags %x",
  901                             i, mpt->mpt_port_page2.DeviceSettings[i].Timeout,
  902                             mpt->mpt_port_page2.DeviceSettings[i].SyncFactor,
  903                             mpt->mpt_port_page2.DeviceSettings[i].DeviceFlags);
  904                 }
  905         }
  906 
  907         for (i = 0; i < 16; i++) {
  908                 rv = mpt_read_cfg_page(mpt, i, &mpt->mpt_dev_page0[i].Header);
  909                 mpt2host_config_page_scsi_device_0(&mpt->mpt_dev_page0[i]);
  910                 if (rv) {
  911                         mpt_prt(mpt, "cannot read SPI Tgt %d Device Page 0", i);
  912                         continue;
  913                 }
  914                 if (mpt->verbose > 1) {
  915                         mpt_prt(mpt,
  916                             "SPI Tgt %d Page 0: NParms %x Information %x",
  917                             i, mpt->mpt_dev_page0[i].NegotiatedParameters,
  918                             mpt->mpt_dev_page0[i].Information);
  919                 }
  920                 rv = mpt_read_cfg_page(mpt, i, &mpt->mpt_dev_page1[i].Header);
  921                 mpt2host_config_page_scsi_device_1(&mpt->mpt_dev_page1[i]);
  922                 if (rv) {
  923                         mpt_prt(mpt, "cannot read SPI Tgt %d Device Page 1", i);
  924                         continue;
  925                 }
  926                 if (mpt->verbose > 1) {
  927                         mpt_prt(mpt,
  928                             "SPI Tgt %d Page 1: RParms %x Configuration %x",
  929                             i, mpt->mpt_dev_page1[i].RequestedParameters,
  930                             mpt->mpt_dev_page1[i].Configuration);
  931                 }
  932         }
  933         return (0);
  934 }
  935 
  936 /*
  937  * Validate SPI configuration information.
  938  *
  939  * In particular, validate SPI Port Page 1.
  940  */
  941 static int
  942 mpt_set_initial_config_spi(mpt_softc_t *mpt)
  943 {
  944         int i, pp1val = ((1 << mpt->mpt_ini_id) << 16) | mpt->mpt_ini_id;
  945 
  946         mpt->mpt_disc_enable = 0xff;
  947         mpt->mpt_tag_enable = 0;
  948 
  949         if (mpt->mpt_port_page1.Configuration != pp1val) {
  950                 fCONFIG_PAGE_SCSI_PORT_1 tmp;
  951 
  952                 mpt_prt(mpt,
  953                     "SPI Port Page 1 Config value bad (%x)- should be %x",
  954                     mpt->mpt_port_page1.Configuration, pp1val);
  955                 tmp = mpt->mpt_port_page1;
  956                 tmp.Configuration = pp1val;
  957                 host2mpt_config_page_scsi_port_1(&tmp);
  958                 if (mpt_write_cfg_page(mpt, 0, &tmp.Header)) {
  959                         return (-1);
  960                 }
  961                 if (mpt_read_cfg_page(mpt, 0, &tmp.Header)) {
  962                         return (-1);
  963                 }
  964                 mpt2host_config_page_scsi_port_1(&tmp);
  965                 if (tmp.Configuration != pp1val) {
  966                         mpt_prt(mpt,
  967                             "failed to reset SPI Port Page 1 Config value");
  968                         return (-1);
  969                 }
  970                 mpt->mpt_port_page1 = tmp;
  971         }
  972 
  973         i = 0;
  974         for (i = 0; i < 16; i++) {
  975                 fCONFIG_PAGE_SCSI_DEVICE_1 tmp;
  976 
  977                 tmp = mpt->mpt_dev_page1[i];
  978                 tmp.RequestedParameters = 0;
  979                 tmp.Configuration = 0;
  980                 if (mpt->verbose > 1) {
  981                         mpt_prt(mpt,
  982                             "Set Tgt %d SPI DevicePage 1 values to %x 0 %x",
  983                             i, tmp.RequestedParameters, tmp.Configuration);
  984                 }
  985                 host2mpt_config_page_scsi_device_1(&tmp);
  986                 if (mpt_write_cfg_page(mpt, i, &tmp.Header)) {
  987                         return (-1);
  988                 }
  989                 if (mpt_read_cfg_page(mpt, i, &tmp.Header)) {
  990                         return (-1);
  991                 }
  992                 mpt2host_config_page_scsi_device_1(&tmp);
  993                 mpt->mpt_dev_page1[i] = tmp;
  994                 if (mpt->verbose > 1) {
  995                         mpt_prt(mpt,
  996                             "SPI Tgt %d Page 1: RParm %x Configuration %x", i,
  997                             mpt->mpt_dev_page1[i].RequestedParameters,
  998                             mpt->mpt_dev_page1[i].Configuration);
  999                 }
 1000         }
 1001         return (0);
 1002 }
 1003 
 1004 /*
 1005  * Enable IOC port
 1006  */
 1007 static int
 1008 mpt_send_port_enable(mpt_softc_t *mpt, int port)
 1009 {
 1010         int count;
 1011         request_t *req;
 1012         MSG_PORT_ENABLE *enable_req;
 1013 
 1014         req = mpt_get_request(mpt);
 1015 
 1016         enable_req = req->req_vbuf;
 1017         bzero(enable_req, sizeof *enable_req);
 1018 
 1019         enable_req->Function   = MPI_FUNCTION_PORT_ENABLE;
 1020         enable_req->MsgContext = htole32(req->index | 0x80000000);
 1021         enable_req->PortNumber = port;
 1022 
 1023         mpt_check_doorbell(mpt);
 1024         if (mpt->verbose > 1) {
 1025                 mpt_prt(mpt, "enabling port %d", port);
 1026         }
 1027         mpt_send_cmd(mpt, req);
 1028 
 1029         count = 0;
 1030         do {
 1031                 DELAY(500);
 1032                 mpt_intr(mpt);
 1033                 if (++count == 100000) {
 1034                         mpt_prt(mpt, "port enable timed out");
 1035                         return (-1);
 1036                 }
 1037         } while (req->debug == REQ_ON_CHIP);
 1038         mpt_free_request(mpt, req);
 1039         return (0);
 1040 }
 1041 
 1042 /*
 1043  * Enable/Disable asynchronous event reporting.
 1044  *
 1045  * NB: this is the first command we send via shared memory
 1046  * instead of the handshake register.
 1047  */
 1048 static int
 1049 mpt_send_event_request(mpt_softc_t *mpt, int onoff)
 1050 {
 1051         request_t *req;
 1052         MSG_EVENT_NOTIFY *enable_req;
 1053 
 1054         req = mpt_get_request(mpt);
 1055 
 1056         enable_req = req->req_vbuf;
 1057         bzero(enable_req, sizeof *enable_req);
 1058 
 1059         enable_req->Function   = MPI_FUNCTION_EVENT_NOTIFICATION;
 1060         enable_req->MsgContext = htole32(req->index | 0x80000000);
 1061         enable_req->Switch     = onoff;
 1062 
 1063         mpt_check_doorbell(mpt);
 1064         if (mpt->verbose > 1) {
 1065                 mpt_prt(mpt, "%sabling async events", onoff? "en" : "dis");
 1066         }
 1067         mpt_send_cmd(mpt, req);
 1068 
 1069         return (0);
 1070 }
 1071 
 1072 /*
 1073  * Un-mask the interrupts on the chip.
 1074  */
 1075 void
 1076 mpt_enable_ints(mpt_softc_t *mpt)
 1077 {
 1078         /* Unmask every thing except door bell int */
 1079         mpt_write(mpt, MPT_OFFSET_INTR_MASK, MPT_INTR_DB_MASK);
 1080 }
 1081 
 1082 /*
 1083  * Mask the interrupts on the chip.
 1084  */
 1085 void
 1086 mpt_disable_ints(mpt_softc_t *mpt)
 1087 {
 1088         /* Mask all interrupts */
 1089         mpt_write(mpt, MPT_OFFSET_INTR_MASK,
 1090             MPT_INTR_REPLY_MASK | MPT_INTR_DB_MASK);
 1091 }
 1092 
 1093 /* (Re)Initialize the chip for use */
 1094 int
 1095 mpt_hw_init(mpt_softc_t *mpt)
 1096 {
 1097         u_int32_t       db;
 1098         int             try;
 1099 
 1100         /*
 1101          * Start by making sure we're not at FAULT or RESET state
 1102          */
 1103         for (try = 0; try < MPT_MAX_TRYS; try++) {
 1104 
 1105                 db = mpt_rd_db(mpt);
 1106 
 1107                 switch (MPT_STATE(db)) {
 1108                 case MPT_DB_STATE_READY:
 1109                         return (0);
 1110 
 1111                 default:
 1112                         /* if peer has already reset us, don't do it again! */
 1113                         if (MPT_WHO(db) == MPT_DB_INIT_PCIPEER)
 1114                                 return (0);
 1115                         /*FALLTHRU*/
 1116                 case MPT_DB_STATE_RESET:
 1117                 case MPT_DB_STATE_FAULT:
 1118                         if (mpt_reset(mpt) != MPT_OK) {
 1119                                 DELAY(10000);
 1120                                 continue;
 1121                         }
 1122                         break;
 1123                 }
 1124         }
 1125         return (EIO);
 1126 }
 1127 
 1128 int
 1129 mpt_init(mpt_softc_t *mpt, u_int32_t who)
 1130 {
 1131         int try;
 1132         MSG_IOC_FACTS_REPLY facts;
 1133         MSG_PORT_FACTS_REPLY pfp;
 1134         u_int32_t pptr;
 1135         int val;
 1136 
 1137         /* Put all request buffers (back) on the free list */
 1138         SLIST_INIT(&mpt->request_free_list);
 1139         for (val = 0; val < MPT_MAX_REQUESTS(mpt); val++) {
 1140                 mpt_free_request(mpt, &mpt->request_pool[val]);
 1141         }
 1142 
 1143         if (mpt->verbose > 1) {
 1144                 mpt_prt(mpt, "doorbell req = %s",
 1145                     mpt_ioc_diag(mpt_read(mpt, MPT_OFFSET_DOORBELL)));
 1146         }
 1147 
 1148         /*
 1149          * Start by making sure we're not at FAULT or RESET state
 1150          */
 1151         if (mpt_hw_init(mpt) != 0)
 1152                 return (EIO);
 1153 
 1154         for (try = 0; try < MPT_MAX_TRYS; try++) {
 1155                 /*
 1156                  * No need to reset if the IOC is already in the READY state.
 1157                  */
 1158 
 1159                 if (mpt_get_iocfacts(mpt, &facts) != MPT_OK) {
 1160                         mpt_prt(mpt, "mpt_get_iocfacts failed");
 1161                         continue;
 1162                 }
 1163                 mpt2host_iocfacts_reply(&facts);
 1164 
 1165                 if (mpt->verbose > 1) {
 1166                         mpt_prt(mpt,
 1167                             "IOCFACTS: GlobalCredits=%d BlockSize=%u "
 1168                             "Request Frame Size %u", facts.GlobalCredits,
 1169                             facts.BlockSize, facts.RequestFrameSize);
 1170                 }
 1171                 mpt->mpt_max_devices = facts.MaxDevices;
 1172                 mpt->mpt_global_credits = facts.GlobalCredits;
 1173                 mpt->request_frame_size = facts.RequestFrameSize;
 1174 
 1175                 if (mpt_get_portfacts(mpt, &pfp) != MPT_OK) {
 1176                         mpt_prt(mpt, "mpt_get_portfacts failed");
 1177                         continue;
 1178                 }
 1179                 mpt2host_portfacts_reply(&pfp);
 1180 
 1181                 if (mpt->verbose > 1) {
 1182                         mpt_prt(mpt,
 1183                             "PORTFACTS: Type %x PFlags %x IID %d MaxDev %d",
 1184                             pfp.PortType, pfp.ProtocolFlags, pfp.PortSCSIID,
 1185                             pfp.MaxDevices);
 1186                 }
 1187 
 1188                 if (!(pfp.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)) {
 1189                         mpt_prt(mpt, "initiator role unsupported");
 1190                         return (ENXIO);
 1191                 }
 1192 
 1193                 switch (pfp.PortType) {
 1194                 case MPI_PORTFACTS_PORTTYPE_FC:
 1195                         mpt->is_fc = 1;
 1196                         mpt->mpt_max_devices = 255;
 1197                         break;
 1198                 case MPI_PORTFACTS_PORTTYPE_SCSI:
 1199                         mpt->is_scsi = 1;
 1200                         /* some SPI controllers (VMWare, Sun) lie */
 1201                         mpt->mpt_max_devices = 16;
 1202                         break;
 1203                 case MPI_PORTFACTS_PORTTYPE_SAS:
 1204                         mpt->is_sas = 1;
 1205                         break;
 1206                 default:
 1207                         mpt_prt(mpt, "Unsupported Port Type (%x)",
 1208                             pfp.PortType);
 1209                         return (ENXIO);
 1210                 }
 1211 
 1212                 mpt->mpt_ini_id = pfp.PortSCSIID;
 1213 
 1214                 if (mpt_send_ioc_init(mpt, who) != MPT_OK) {
 1215                         mpt_prt(mpt, "mpt_send_ioc_init failed");
 1216                         continue;
 1217                 }
 1218 
 1219                 if (mpt->verbose > 1) {
 1220                         mpt_prt(mpt, "mpt_send_ioc_init ok");
 1221                 }
 1222 
 1223                 if (mpt_wait_state(mpt, MPT_DB_STATE_RUNNING) != MPT_OK) {
 1224                         mpt_prt(mpt, "IOC failed to go to run state");
 1225                         continue;
 1226                 }
 1227                 if (mpt->verbose > 1) {
 1228                         mpt_prt(mpt, "IOC now at RUNSTATE");
 1229                 }
 1230 
 1231                 /*
 1232                  * Give it reply buffers
 1233                  *
 1234                  * Do *not* except global credits.
 1235                  */
 1236                 for (val = 0, pptr = mpt->reply_phys;
 1237                     (pptr + MPT_REPLY_SIZE) < (mpt->reply_phys + PAGE_SIZE);
 1238                      pptr += MPT_REPLY_SIZE) {
 1239                         mpt_free_reply(mpt, pptr);
 1240                         if (++val == mpt->mpt_global_credits - 1)
 1241                                 break;
 1242                 }
 1243 
 1244                 /*
 1245                  * Enable asynchronous event reporting
 1246                  */
 1247                 mpt_send_event_request(mpt, 1);
 1248 
 1249 
 1250                 /*
 1251                  * Read set up initial configuration information
 1252                  * (SPI only for now)
 1253                  */
 1254 
 1255                 if (mpt->is_scsi) {
 1256                         if (mpt_read_config_info_spi(mpt)) {
 1257                                 return (EIO);
 1258                         }
 1259                         if (mpt_set_initial_config_spi(mpt)) {
 1260                                 return (EIO);
 1261                         }
 1262                 }
 1263 
 1264                 /*
 1265                  * Now enable the port
 1266                  */
 1267                 if (mpt_send_port_enable(mpt, 0) != MPT_OK) {
 1268                         mpt_prt(mpt, "failed to enable port 0");
 1269                         continue;
 1270                 }
 1271 
 1272                 if (mpt->verbose > 1) {
 1273                         mpt_prt(mpt, "enabled port 0");
 1274                 }
 1275 
 1276                 /* Everything worked */
 1277                 break;
 1278         }
 1279 
 1280         if (try >= MPT_MAX_TRYS) {
 1281                 mpt_prt(mpt, "failed to initialize IOC");
 1282                 return (EIO);
 1283         }
 1284 
 1285         if (mpt->verbose > 1) {
 1286                 mpt_prt(mpt, "enabling interrupts");
 1287         }
 1288 
 1289         mpt_enable_ints(mpt);
 1290         return (0);
 1291 }
 1292 
 1293 /*
 1294  * Endian Conversion Functions- only used on Big Endian machines
 1295  */
 1296 #if     _BYTE_ORDER == _BIG_ENDIAN
 1297 void
 1298 mpt2host_sge_simple_union(SGE_SIMPLE_UNION *sge)
 1299 {
 1300 
 1301         MPT_2_HOST32(sge, FlagsLength);
 1302         MPT_2_HOST32(sge, _u.Address64.Low);
 1303         MPT_2_HOST32(sge, _u.Address64.High);
 1304 }
 1305 
 1306 void
 1307 mpt2host_iocfacts_reply(MSG_IOC_FACTS_REPLY *rp)
 1308 {
 1309 
 1310         MPT_2_HOST16(rp, MsgVersion);
 1311 #if 0
 1312         MPT_2_HOST16(rp, HeaderVersion);
 1313 #endif
 1314         MPT_2_HOST32(rp, MsgContext);
 1315         MPT_2_HOST16(rp, IOCExceptions);
 1316         MPT_2_HOST16(rp, IOCStatus);
 1317         MPT_2_HOST32(rp, IOCLogInfo);
 1318         MPT_2_HOST16(rp, ReplyQueueDepth);
 1319         MPT_2_HOST16(rp, RequestFrameSize);
 1320         MPT_2_HOST16(rp, Reserved_0101_FWVersion);
 1321         MPT_2_HOST16(rp, ProductID);
 1322         MPT_2_HOST32(rp, CurrentHostMfaHighAddr);
 1323         MPT_2_HOST16(rp, GlobalCredits);
 1324         MPT_2_HOST32(rp, CurrentSenseBufferHighAddr);
 1325         MPT_2_HOST16(rp, CurReplyFrameSize);
 1326         MPT_2_HOST32(rp, FWImageSize);
 1327 #if 0
 1328         MPT_2_HOST32(rp, IOCCapabilities);
 1329 #endif
 1330         MPT_2_HOST32(rp, FWVersion.Word);
 1331 #if 0
 1332         MPT_2_HOST16(rp, HighPriorityQueueDepth);
 1333         MPT_2_HOST16(rp, Reserved2);
 1334         mpt2host_sge_simple_union(&rp->HostPageBufferSGE);
 1335         MPT_2_HOST32(rp, ReplyFifoHostSignalingAddr);
 1336 #endif
 1337 }
 1338 
 1339 void
 1340 mpt2host_portfacts_reply(MSG_PORT_FACTS_REPLY *pfp)
 1341 {
 1342 
 1343         MPT_2_HOST16(pfp, Reserved);
 1344         MPT_2_HOST16(pfp, Reserved1);
 1345         MPT_2_HOST32(pfp, MsgContext);
 1346         MPT_2_HOST16(pfp, Reserved2);
 1347         MPT_2_HOST16(pfp, IOCStatus);
 1348         MPT_2_HOST32(pfp, IOCLogInfo);
 1349         MPT_2_HOST16(pfp, MaxDevices);
 1350         MPT_2_HOST16(pfp, PortSCSIID);
 1351         MPT_2_HOST16(pfp, ProtocolFlags);
 1352         MPT_2_HOST16(pfp, MaxPostedCmdBuffers);
 1353         MPT_2_HOST16(pfp, MaxPersistentIDs);
 1354         MPT_2_HOST16(pfp, MaxLanBuckets);
 1355         MPT_2_HOST16(pfp, Reserved4);
 1356         MPT_2_HOST32(pfp, Reserved5);
 1357 }
 1358 
 1359 void
 1360 mpt2host_config_page_scsi_port_0(fCONFIG_PAGE_SCSI_PORT_0 *sp0)
 1361 {
 1362 
 1363         MPT_2_HOST32(sp0, Capabilities);
 1364         MPT_2_HOST32(sp0, PhysicalInterface);
 1365 }
 1366 
 1367 void
 1368 mpt2host_config_page_scsi_port_1(fCONFIG_PAGE_SCSI_PORT_1 *sp1)
 1369 {
 1370 
 1371         MPT_2_HOST32(sp1, Configuration);
 1372         MPT_2_HOST32(sp1, OnBusTimerValue);
 1373 #if 0
 1374         MPT_2_HOST16(sp1, IDConfig);
 1375 #endif
 1376 }
 1377 
 1378 void
 1379 host2mpt_config_page_scsi_port_1(fCONFIG_PAGE_SCSI_PORT_1 *sp1)
 1380 {
 1381 
 1382         HOST_2_MPT32(sp1, Configuration);
 1383         HOST_2_MPT32(sp1, OnBusTimerValue);
 1384 #if 0
 1385         HOST_2_MPT16(sp1, IDConfig);
 1386 #endif
 1387 }
 1388 
 1389 void
 1390 mpt2host_config_page_scsi_port_2(fCONFIG_PAGE_SCSI_PORT_2 *sp2)
 1391 {
 1392         int i;
 1393 
 1394         MPT_2_HOST32(sp2, PortFlags);
 1395         MPT_2_HOST32(sp2, PortSettings);
 1396         for (i = 0; i < sizeof(sp2->DeviceSettings) /
 1397             sizeof(*sp2->DeviceSettings); i++) {
 1398                 MPT_2_HOST16(sp2, DeviceSettings[i].DeviceFlags);
 1399         }
 1400 }
 1401 
 1402 void
 1403 mpt2host_config_page_scsi_device_0(fCONFIG_PAGE_SCSI_DEVICE_0 *sd0)
 1404 {
 1405 
 1406         MPT_2_HOST32(sd0, NegotiatedParameters);
 1407         MPT_2_HOST32(sd0, Information);
 1408 }
 1409 
 1410 void
 1411 host2mpt_config_page_scsi_device_0(fCONFIG_PAGE_SCSI_DEVICE_0 *sd0)
 1412 {
 1413 
 1414         HOST_2_MPT32(sd0, NegotiatedParameters);
 1415         HOST_2_MPT32(sd0, Information);
 1416 }
 1417 
 1418 void
 1419 mpt2host_config_page_scsi_device_1(fCONFIG_PAGE_SCSI_DEVICE_1 *sd1)
 1420 {
 1421 
 1422         MPT_2_HOST32(sd1, RequestedParameters);
 1423         MPT_2_HOST32(sd1, Reserved);
 1424         MPT_2_HOST32(sd1, Configuration);
 1425 }
 1426 
 1427 void
 1428 host2mpt_config_page_scsi_device_1(fCONFIG_PAGE_SCSI_DEVICE_1 *sd1)
 1429 {
 1430 
 1431         HOST_2_MPT32(sd1, RequestedParameters);
 1432         HOST_2_MPT32(sd1, Reserved);
 1433         HOST_2_MPT32(sd1, Configuration);
 1434 }
 1435 
 1436 void
 1437 mpt2host_config_page_fc_port_0(fCONFIG_PAGE_FC_PORT_0 *fp0)
 1438 {
 1439 
 1440         MPT_2_HOST32(fp0, Flags);
 1441         MPT_2_HOST32(fp0, PortIdentifier);
 1442         MPT_2_HOST32(fp0, WWNN.Low);
 1443         MPT_2_HOST32(fp0, WWNN.High);
 1444         MPT_2_HOST32(fp0, WWPN.Low);
 1445         MPT_2_HOST32(fp0, WWPN.High);
 1446         MPT_2_HOST32(fp0, SupportedServiceClass);
 1447         MPT_2_HOST32(fp0, SupportedSpeeds);
 1448         MPT_2_HOST32(fp0, CurrentSpeed);
 1449         MPT_2_HOST32(fp0, MaxFrameSize);
 1450         MPT_2_HOST32(fp0, FabricWWNN.Low);
 1451         MPT_2_HOST32(fp0, FabricWWNN.High);
 1452         MPT_2_HOST32(fp0, FabricWWPN.Low);
 1453         MPT_2_HOST32(fp0, FabricWWPN.High);
 1454         MPT_2_HOST32(fp0, DiscoveredPortsCount);
 1455         MPT_2_HOST32(fp0, MaxInitiators);
 1456 }
 1457 
 1458 void
 1459 mpt2host_config_page_fc_port_1(fCONFIG_PAGE_FC_PORT_1 *fp1)
 1460 {
 1461 
 1462         MPT_2_HOST32(fp1, Flags);
 1463         MPT_2_HOST32(fp1, NoSEEPROMWWNN.Low);
 1464         MPT_2_HOST32(fp1, NoSEEPROMWWNN.High);
 1465         MPT_2_HOST32(fp1, NoSEEPROMWWPN.Low);
 1466         MPT_2_HOST32(fp1, NoSEEPROMWWPN.High);
 1467 }
 1468 
 1469 void
 1470 host2mpt_config_page_fc_port_1(fCONFIG_PAGE_FC_PORT_1 *fp1)
 1471 {
 1472 
 1473         HOST_2_MPT32(fp1, Flags);
 1474         HOST_2_MPT32(fp1, NoSEEPROMWWNN.Low);
 1475         HOST_2_MPT32(fp1, NoSEEPROMWWNN.High);
 1476         HOST_2_MPT32(fp1, NoSEEPROMWWPN.Low);
 1477         HOST_2_MPT32(fp1, NoSEEPROMWWPN.High);
 1478 }
 1479 
 1480 void
 1481 mpt2host_config_page_raid_vol_0(fCONFIG_PAGE_RAID_VOL_0 *volp)
 1482 {
 1483         int i;
 1484 
 1485         MPT_2_HOST16(volp, VolumeStatus.Reserved);
 1486         MPT_2_HOST16(volp, VolumeSettings.Settings);
 1487         MPT_2_HOST32(volp, MaxLBA);
 1488 #if 0
 1489         MPT_2_HOST32(volp, MaxLBAHigh);
 1490 #endif
 1491         MPT_2_HOST32(volp, StripeSize);
 1492         MPT_2_HOST32(volp, Reserved2);
 1493         MPT_2_HOST32(volp, Reserved3);
 1494         for (i = 0; i < MPI_RAID_VOL_PAGE_0_PHYSDISK_MAX; i++) {
 1495                 MPT_2_HOST16(volp, PhysDisk[i].Reserved);
 1496         }
 1497 }
 1498 
 1499 void
 1500 mpt2host_config_page_raid_phys_disk_0(fCONFIG_PAGE_RAID_PHYS_DISK_0 *rpd0)
 1501 {
 1502 
 1503         MPT_2_HOST32(rpd0, Reserved1);
 1504         MPT_2_HOST16(rpd0, PhysDiskStatus.Reserved);
 1505         MPT_2_HOST32(rpd0, MaxLBA);
 1506         MPT_2_HOST16(rpd0, ErrorData.Reserved);
 1507         MPT_2_HOST16(rpd0, ErrorData.ErrorCount);
 1508         MPT_2_HOST16(rpd0, ErrorData.SmartCount);
 1509 }
 1510 
 1511 #endif

Cache object: bda2951b98f2f1d82d3d8166f236a4ae


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