1098ca2bdSWarner Losh /*- 29b631363SMatt Jacob * Generic routines for LSI '909 FC adapters. 39b631363SMatt Jacob * FreeBSD Version. 49b631363SMatt Jacob * 59b631363SMatt Jacob * Copyright (c) 2000, 2001 by Greg Ansley 69b631363SMatt Jacob * 79b631363SMatt Jacob * Redistribution and use in source and binary forms, with or without 89b631363SMatt Jacob * modification, are permitted provided that the following conditions 99b631363SMatt Jacob * are met: 109b631363SMatt Jacob * 1. Redistributions of source code must retain the above copyright 119b631363SMatt Jacob * notice immediately at the beginning of the file, without modification, 129b631363SMatt Jacob * this list of conditions, and the following disclaimer. 139b631363SMatt Jacob * 2. The name of the author may not be used to endorse or promote products 149b631363SMatt Jacob * derived from this software without specific prior written permission. 159b631363SMatt Jacob * 169b631363SMatt Jacob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 179b631363SMatt Jacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 189b631363SMatt Jacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 199b631363SMatt Jacob * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 209b631363SMatt Jacob * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 219b631363SMatt Jacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 229b631363SMatt Jacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 239b631363SMatt Jacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 249b631363SMatt Jacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 259b631363SMatt Jacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 269b631363SMatt Jacob * SUCH DAMAGE. 279b631363SMatt Jacob */ 289b631363SMatt Jacob /* 299b631363SMatt Jacob * Additional Copyright (c) 2002 by Matthew Jacob under same license. 309b631363SMatt Jacob */ 319b631363SMatt Jacob 329295c6c5SDavid E. O'Brien #include <sys/cdefs.h> 339295c6c5SDavid E. O'Brien __FBSDID("$FreeBSD$"); 349295c6c5SDavid E. O'Brien 359b631363SMatt Jacob #include <dev/mpt/mpt_freebsd.h> 367104aeefSMatt Jacob 379b631363SMatt Jacob #define MPT_MAX_TRYS 3 389b631363SMatt Jacob #define MPT_MAX_WAIT 300000 399b631363SMatt Jacob 409b631363SMatt Jacob static int maxwait_ack = 0; 419b631363SMatt Jacob static int maxwait_int = 0; 429b631363SMatt Jacob static int maxwait_state = 0; 439b631363SMatt Jacob 44301472c2SMatt Jacob static INLINE u_int32_t mpt_rd_db(mpt_softc_t *mpt); 45301472c2SMatt Jacob static INLINE u_int32_t mpt_rd_intr(mpt_softc_t *mpt); 469b631363SMatt Jacob 47301472c2SMatt Jacob static INLINE u_int32_t 487104aeefSMatt Jacob mpt_rd_db(mpt_softc_t *mpt) 499b631363SMatt Jacob { 509b631363SMatt Jacob return mpt_read(mpt, MPT_OFFSET_DOORBELL); 519b631363SMatt Jacob } 529b631363SMatt Jacob 53301472c2SMatt Jacob static INLINE u_int32_t 547104aeefSMatt Jacob mpt_rd_intr(mpt_softc_t *mpt) 559b631363SMatt Jacob { 569b631363SMatt Jacob return mpt_read(mpt, MPT_OFFSET_INTR_STATUS); 579b631363SMatt Jacob } 589b631363SMatt Jacob 599b631363SMatt Jacob /* Busy wait for a door bell to be read by IOC */ 609b631363SMatt Jacob static int 617104aeefSMatt Jacob mpt_wait_db_ack(mpt_softc_t *mpt) 629b631363SMatt Jacob { 639b631363SMatt Jacob int i; 649b631363SMatt Jacob for (i=0; i < MPT_MAX_WAIT; i++) { 659b631363SMatt Jacob if (!MPT_DB_IS_BUSY(mpt_rd_intr(mpt))) { 669b631363SMatt Jacob maxwait_ack = i > maxwait_ack ? i : maxwait_ack; 679b631363SMatt Jacob return MPT_OK; 689b631363SMatt Jacob } 699b631363SMatt Jacob 709b631363SMatt Jacob DELAY(100); 719b631363SMatt Jacob } 729b631363SMatt Jacob return MPT_FAIL; 739b631363SMatt Jacob } 749b631363SMatt Jacob 759b631363SMatt Jacob /* Busy wait for a door bell interrupt */ 769b631363SMatt Jacob static int 777104aeefSMatt Jacob mpt_wait_db_int(mpt_softc_t *mpt) 789b631363SMatt Jacob { 799b631363SMatt Jacob int i; 809b631363SMatt Jacob for (i=0; i < MPT_MAX_WAIT; i++) { 819b631363SMatt Jacob if (MPT_DB_INTR(mpt_rd_intr(mpt))) { 829b631363SMatt Jacob maxwait_int = i > maxwait_int ? i : maxwait_int; 839b631363SMatt Jacob return MPT_OK; 849b631363SMatt Jacob } 859b631363SMatt Jacob DELAY(100); 869b631363SMatt Jacob } 879b631363SMatt Jacob return MPT_FAIL; 889b631363SMatt Jacob } 899b631363SMatt Jacob 909b631363SMatt Jacob /* Wait for IOC to transition to a give state */ 919b631363SMatt Jacob void 927104aeefSMatt Jacob mpt_check_doorbell(mpt_softc_t *mpt) 939b631363SMatt Jacob { 949b631363SMatt Jacob u_int32_t db = mpt_rd_db(mpt); 959b631363SMatt Jacob if (MPT_STATE(db) != MPT_DB_STATE_RUNNING) { 96301472c2SMatt Jacob mpt_prt(mpt, "Device not running"); 979b631363SMatt Jacob mpt_print_db(db); 989b631363SMatt Jacob } 999b631363SMatt Jacob } 1009b631363SMatt Jacob 1019b631363SMatt Jacob /* Wait for IOC to transition to a give state */ 1029b631363SMatt Jacob static int 1037104aeefSMatt Jacob mpt_wait_state(mpt_softc_t *mpt, enum DB_STATE_BITS state) 1049b631363SMatt Jacob { 1059b631363SMatt Jacob int i; 1069b631363SMatt Jacob 1079b631363SMatt Jacob for (i = 0; i < MPT_MAX_WAIT; i++) { 1089b631363SMatt Jacob u_int32_t db = mpt_rd_db(mpt); 1099b631363SMatt Jacob if (MPT_STATE(db) == state) { 1109b631363SMatt Jacob maxwait_state = i > maxwait_state ? i : maxwait_state; 1119b631363SMatt Jacob return (MPT_OK); 1129b631363SMatt Jacob } 1139b631363SMatt Jacob DELAY(100); 1149b631363SMatt Jacob } 1159b631363SMatt Jacob return (MPT_FAIL); 1169b631363SMatt Jacob } 1179b631363SMatt Jacob 1189b631363SMatt Jacob 1199b631363SMatt Jacob /* Issue the reset COMMAND to the IOC */ 1209b631363SMatt Jacob int 1217104aeefSMatt Jacob mpt_soft_reset(mpt_softc_t *mpt) 1229b631363SMatt Jacob { 1239b631363SMatt Jacob if (mpt->verbose) { 124301472c2SMatt Jacob mpt_prt(mpt, "soft reset"); 1259b631363SMatt Jacob } 1269b631363SMatt Jacob 1279b631363SMatt Jacob /* Have to use hard reset if we are not in Running state */ 1289b631363SMatt Jacob if (MPT_STATE(mpt_rd_db(mpt)) != MPT_DB_STATE_RUNNING) { 129301472c2SMatt Jacob mpt_prt(mpt, "soft reset failed: device not running"); 1309b631363SMatt Jacob return MPT_FAIL; 1319b631363SMatt Jacob } 1329b631363SMatt Jacob 1339b631363SMatt Jacob /* If door bell is in use we don't have a chance of getting 1349b631363SMatt Jacob * a word in since the IOC probably crashed in message 1359b631363SMatt Jacob * processing. So don't waste our time. 1369b631363SMatt Jacob */ 1379b631363SMatt Jacob if (MPT_DB_IS_IN_USE(mpt_rd_db(mpt))) { 138301472c2SMatt Jacob mpt_prt(mpt, "soft reset failed: doorbell wedged"); 1399b631363SMatt Jacob return MPT_FAIL; 1409b631363SMatt Jacob } 1419b631363SMatt Jacob 1429b631363SMatt Jacob /* Send the reset request to the IOC */ 1439b631363SMatt Jacob mpt_write(mpt, MPT_OFFSET_DOORBELL, 1449b631363SMatt Jacob MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET << MPI_DOORBELL_FUNCTION_SHIFT); 1459b631363SMatt Jacob if (mpt_wait_db_ack(mpt) != MPT_OK) { 146301472c2SMatt Jacob mpt_prt(mpt, "soft reset failed: ack timeout"); 1479b631363SMatt Jacob return MPT_FAIL; 1489b631363SMatt Jacob } 1499b631363SMatt Jacob 1509b631363SMatt Jacob /* Wait for the IOC to reload and come out of reset state */ 1519b631363SMatt Jacob if (mpt_wait_state(mpt, MPT_DB_STATE_READY) != MPT_OK) { 152301472c2SMatt Jacob mpt_prt(mpt, "soft reset failed: device did not start running"); 1539b631363SMatt Jacob return MPT_FAIL; 1549b631363SMatt Jacob } 1559b631363SMatt Jacob 1569b631363SMatt Jacob return MPT_OK; 1579b631363SMatt Jacob } 1589b631363SMatt Jacob 1599b631363SMatt Jacob /* This is a magic diagnostic reset that resets all the ARM 1609b631363SMatt Jacob * processors in the chip. 1619b631363SMatt Jacob */ 1629b631363SMatt Jacob void 1637104aeefSMatt Jacob mpt_hard_reset(mpt_softc_t *mpt) 1649b631363SMatt Jacob { 1659b631363SMatt Jacob /* This extra read comes for the Linux source 1669b631363SMatt Jacob * released by LSI. It's function is undocumented! 1679b631363SMatt Jacob */ 1689b631363SMatt Jacob if (mpt->verbose) { 169301472c2SMatt Jacob mpt_prt(mpt, "hard reset"); 1709b631363SMatt Jacob } 1719b631363SMatt Jacob mpt_read(mpt, MPT_OFFSET_FUBAR); 1729b631363SMatt Jacob 1739b631363SMatt Jacob /* Enable diagnostic registers */ 1749b631363SMatt Jacob mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_1); 1759b631363SMatt Jacob mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_2); 1769b631363SMatt Jacob mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_3); 1779b631363SMatt Jacob mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_4); 1789b631363SMatt Jacob mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_5); 1799b631363SMatt Jacob 1809b631363SMatt Jacob /* Diag. port is now active so we can now hit the reset bit */ 1819b631363SMatt Jacob mpt_write(mpt, MPT_OFFSET_DIAGNOSTIC, MPT_DIAG_RESET_IOC); 1829b631363SMatt Jacob 1839b631363SMatt Jacob DELAY(10000); 1849b631363SMatt Jacob 1859b631363SMatt Jacob /* Disable Diagnostic Register */ 1869b631363SMatt Jacob mpt_write(mpt, MPT_OFFSET_SEQUENCE, 0xFF); 1879b631363SMatt Jacob 1889b631363SMatt Jacob /* Restore the config register values */ 1899b631363SMatt Jacob /* Hard resets are known to screw up the BAR for diagnostic 1909b631363SMatt Jacob memory accesses (Mem1). */ 1919b631363SMatt Jacob mpt_set_config_regs(mpt); 1929b631363SMatt Jacob if (mpt->mpt2 != NULL) { 1939b631363SMatt Jacob mpt_set_config_regs(mpt->mpt2); 1949b631363SMatt Jacob } 1959b631363SMatt Jacob 1969b631363SMatt Jacob /* Note that if there is no valid firmware to run, the doorbell will 1979b631363SMatt Jacob remain in the reset state (0x00000000) */ 1989b631363SMatt Jacob } 1999b631363SMatt Jacob 2009b631363SMatt Jacob /* 2019b631363SMatt Jacob * Reset the IOC when needed. Try software command first then if needed 2029b631363SMatt Jacob * poke at the magic diagnostic reset. Note that a hard reset resets 2039b631363SMatt Jacob * *both* IOCs on dual function chips (FC929 && LSI1030) as well as 2049b631363SMatt Jacob * fouls up the PCI configuration registers. 2059b631363SMatt Jacob */ 2069b631363SMatt Jacob int 2077104aeefSMatt Jacob mpt_reset(mpt_softc_t *mpt) 2089b631363SMatt Jacob { 2099b631363SMatt Jacob int ret; 2109b631363SMatt Jacob 2119b631363SMatt Jacob /* Try a soft reset */ 2129b631363SMatt Jacob if ((ret = mpt_soft_reset(mpt)) != MPT_OK) { 2139b631363SMatt Jacob /* Failed; do a hard reset */ 2149b631363SMatt Jacob mpt_hard_reset(mpt); 2159b631363SMatt Jacob 2169b631363SMatt Jacob /* Wait for the IOC to reload and come out of reset state */ 2179b631363SMatt Jacob ret = mpt_wait_state(mpt, MPT_DB_STATE_READY); 2189b631363SMatt Jacob if (ret != MPT_OK) { 219301472c2SMatt Jacob mpt_prt(mpt, "failed to reset device"); 2209b631363SMatt Jacob } 2219b631363SMatt Jacob } 2229b631363SMatt Jacob 2239b631363SMatt Jacob return ret; 2249b631363SMatt Jacob } 2259b631363SMatt Jacob 2269b631363SMatt Jacob /* Return a command buffer to the free queue */ 2279b631363SMatt Jacob void 2287104aeefSMatt Jacob mpt_free_request(mpt_softc_t *mpt, request_t *req) 2299b631363SMatt Jacob { 2307dec90bcSMatt Jacob if (req == NULL || req != &mpt->request_pool[req->index]) { 2319b631363SMatt Jacob panic("mpt_free_request bad req ptr\n"); 2329b631363SMatt Jacob return; 2339b631363SMatt Jacob } 2340424fb53SMatt Jacob req->sequence = 0; 2359b631363SMatt Jacob req->ccb = NULL; 2369b631363SMatt Jacob req->debug = REQ_FREE; 2379b631363SMatt Jacob SLIST_INSERT_HEAD(&mpt->request_free_list, req, link); 2389b631363SMatt Jacob } 2399b631363SMatt Jacob 2409b631363SMatt Jacob /* Get a command buffer from the free queue */ 2419b631363SMatt Jacob request_t * 2427104aeefSMatt Jacob mpt_get_request(mpt_softc_t *mpt) 2439b631363SMatt Jacob { 2449b631363SMatt Jacob request_t *req; 2459b631363SMatt Jacob req = SLIST_FIRST(&mpt->request_free_list); 2469b631363SMatt Jacob if (req != NULL) { 2477dec90bcSMatt Jacob if (req != &mpt->request_pool[req->index]) { 2489b631363SMatt Jacob panic("mpt_get_request: corrupted request free list\n"); 2499b631363SMatt Jacob } 2509b631363SMatt Jacob if (req->ccb != NULL) { 2519b631363SMatt Jacob panic("mpt_get_request: corrupted request free list (ccb)\n"); 2529b631363SMatt Jacob } 2539b631363SMatt Jacob SLIST_REMOVE_HEAD(&mpt->request_free_list, link); 2549b631363SMatt Jacob req->debug = REQ_IN_PROGRESS; 2559b631363SMatt Jacob } 2569b631363SMatt Jacob return req; 2579b631363SMatt Jacob } 2589b631363SMatt Jacob 2599b631363SMatt Jacob /* Pass the command to the IOC */ 2609b631363SMatt Jacob void 2617104aeefSMatt Jacob mpt_send_cmd(mpt_softc_t *mpt, request_t *req) 2629b631363SMatt Jacob { 2639b631363SMatt Jacob req->sequence = mpt->sequence++; 2649b631363SMatt Jacob if (mpt->verbose > 1) { 2659b631363SMatt Jacob u_int32_t *pReq; 2669b631363SMatt Jacob pReq = req->req_vbuf; 267301472c2SMatt Jacob mpt_prt(mpt, "Send Request %d (0x%x):", 268301472c2SMatt Jacob req->index, req->req_pbuf); 269301472c2SMatt Jacob mpt_prt(mpt, "%08x %08x %08x %08x", 2709b631363SMatt Jacob pReq[0], pReq[1], pReq[2], pReq[3]); 271301472c2SMatt Jacob mpt_prt(mpt, "%08x %08x %08x %08x", 2729b631363SMatt Jacob pReq[4], pReq[5], pReq[6], pReq[7]); 273301472c2SMatt Jacob mpt_prt(mpt, "%08x %08x %08x %08x", 2749b631363SMatt Jacob pReq[8], pReq[9], pReq[10], pReq[11]); 275301472c2SMatt Jacob mpt_prt(mpt, "%08x %08x %08x %08x", 2769b631363SMatt Jacob pReq[12], pReq[13], pReq[14], pReq[15]); 2779b631363SMatt Jacob } 2789b631363SMatt Jacob bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap, 2799b631363SMatt Jacob BUS_DMASYNC_PREWRITE); 2809b631363SMatt Jacob req->debug = REQ_ON_CHIP; 2819b631363SMatt Jacob mpt_write(mpt, MPT_OFFSET_REQUEST_Q, (u_int32_t) req->req_pbuf); 2829b631363SMatt Jacob } 2839b631363SMatt Jacob 2849b631363SMatt Jacob /* 2859b631363SMatt Jacob * Give the reply buffer back to the IOC after we have 2869b631363SMatt Jacob * finished processing it. 2879b631363SMatt Jacob */ 2889b631363SMatt Jacob void 2897104aeefSMatt Jacob mpt_free_reply(mpt_softc_t *mpt, u_int32_t ptr) 2909b631363SMatt Jacob { 2919b631363SMatt Jacob mpt_write(mpt, MPT_OFFSET_REPLY_Q, ptr); 2929b631363SMatt Jacob } 2939b631363SMatt Jacob 2949b631363SMatt Jacob /* Get a reply from the IOC */ 2959b631363SMatt Jacob u_int32_t 2967104aeefSMatt Jacob mpt_pop_reply_queue(mpt_softc_t *mpt) 2979b631363SMatt Jacob { 2989b631363SMatt Jacob return mpt_read(mpt, MPT_OFFSET_REPLY_Q); 2999b631363SMatt Jacob } 3009b631363SMatt Jacob 3019b631363SMatt Jacob /* 3029b631363SMatt Jacob * Send a command to the IOC via the handshake register. 3039b631363SMatt Jacob * 3049b631363SMatt Jacob * Only done at initialization time and for certain unusual 3059b631363SMatt Jacob * commands such as device/bus reset as specified by LSI. 3069b631363SMatt Jacob */ 3079b631363SMatt Jacob int 3087104aeefSMatt Jacob mpt_send_handshake_cmd(mpt_softc_t *mpt, size_t len, void *cmd) 3099b631363SMatt Jacob { 3109b631363SMatt Jacob int i; 3119b631363SMatt Jacob u_int32_t data, *data32; 3129b631363SMatt Jacob 3139b631363SMatt Jacob /* Check condition of the IOC */ 3149b631363SMatt Jacob data = mpt_rd_db(mpt); 3159b631363SMatt Jacob if (((MPT_STATE(data) != MPT_DB_STATE_READY) && 3169b631363SMatt Jacob (MPT_STATE(data) != MPT_DB_STATE_RUNNING) && 3179b631363SMatt Jacob (MPT_STATE(data) != MPT_DB_STATE_FAULT)) || 3189b631363SMatt Jacob ( MPT_DB_IS_IN_USE(data) )) { 319301472c2SMatt Jacob mpt_prt(mpt, "handshake aborted due to invalid doorbell state"); 3209b631363SMatt Jacob mpt_print_db(data); 3219b631363SMatt Jacob return(EBUSY); 3229b631363SMatt Jacob } 3239b631363SMatt Jacob 3249b631363SMatt Jacob /* We move things in 32 bit chunks */ 3259b631363SMatt Jacob len = (len + 3) >> 2; 3269b631363SMatt Jacob data32 = cmd; 3279b631363SMatt Jacob 3289b631363SMatt Jacob /* Clear any left over pending doorbell interupts */ 3299b631363SMatt Jacob if (MPT_DB_INTR(mpt_rd_intr(mpt))) 3309b631363SMatt Jacob mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 3319b631363SMatt Jacob 3329b631363SMatt Jacob /* 3339b631363SMatt Jacob * Tell the handshake reg. we are going to send a command 3349b631363SMatt Jacob * and how long it is going to be. 3359b631363SMatt Jacob */ 3369b631363SMatt Jacob data = (MPI_FUNCTION_HANDSHAKE << MPI_DOORBELL_FUNCTION_SHIFT) | 3379b631363SMatt Jacob (len << MPI_DOORBELL_ADD_DWORDS_SHIFT); 3389b631363SMatt Jacob mpt_write(mpt, MPT_OFFSET_DOORBELL, data); 3399b631363SMatt Jacob 3409b631363SMatt Jacob /* Wait for the chip to notice */ 3419b631363SMatt Jacob if (mpt_wait_db_int(mpt) != MPT_OK) { 342301472c2SMatt Jacob mpt_prt(mpt, "mpt_send_handshake_cmd timeout1"); 3439b631363SMatt Jacob return ETIMEDOUT; 3449b631363SMatt Jacob } 3459b631363SMatt Jacob 3469b631363SMatt Jacob /* Clear the interrupt */ 3479b631363SMatt Jacob mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 3489b631363SMatt Jacob 3499b631363SMatt Jacob if (mpt_wait_db_ack(mpt) != MPT_OK) { 350301472c2SMatt Jacob mpt_prt(mpt, "mpt_send_handshake_cmd timeout2"); 3519b631363SMatt Jacob return ETIMEDOUT; 3529b631363SMatt Jacob } 3539b631363SMatt Jacob 3549b631363SMatt Jacob /* Send the command */ 3559b631363SMatt Jacob for (i = 0; i < len; i++) { 3569b631363SMatt Jacob mpt_write(mpt, MPT_OFFSET_DOORBELL, *data32++); 3579b631363SMatt Jacob if (mpt_wait_db_ack(mpt) != MPT_OK) { 358301472c2SMatt Jacob mpt_prt(mpt, 359301472c2SMatt Jacob "mpt_send_handshake_cmd timeout! index = %d", i); 3609b631363SMatt Jacob return ETIMEDOUT; 3619b631363SMatt Jacob } 3629b631363SMatt Jacob } 3639b631363SMatt Jacob return MPT_OK; 3649b631363SMatt Jacob } 3659b631363SMatt Jacob 3669b631363SMatt Jacob /* Get the response from the handshake register */ 3679b631363SMatt Jacob int 3687104aeefSMatt Jacob mpt_recv_handshake_reply(mpt_softc_t *mpt, size_t reply_len, void *reply) 3699b631363SMatt Jacob { 3709b631363SMatt Jacob int left, reply_left; 3719b631363SMatt Jacob u_int16_t *data16; 3729b631363SMatt Jacob MSG_DEFAULT_REPLY *hdr; 3739b631363SMatt Jacob 3749b631363SMatt Jacob /* We move things out in 16 bit chunks */ 3759b631363SMatt Jacob reply_len >>= 1; 3769b631363SMatt Jacob data16 = (u_int16_t *)reply; 3779b631363SMatt Jacob 3789b631363SMatt Jacob hdr = (MSG_DEFAULT_REPLY *)reply; 3799b631363SMatt Jacob 3809b631363SMatt Jacob /* Get first word */ 3819b631363SMatt Jacob if (mpt_wait_db_int(mpt) != MPT_OK) { 382301472c2SMatt Jacob mpt_prt(mpt, "mpt_recv_handshake_cmd timeout1"); 3839b631363SMatt Jacob return ETIMEDOUT; 3849b631363SMatt Jacob } 3859b631363SMatt Jacob *data16++ = mpt_read(mpt, MPT_OFFSET_DOORBELL) & MPT_DB_DATA_MASK; 3869b631363SMatt Jacob mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 3879b631363SMatt Jacob 3889b631363SMatt Jacob /* Get Second Word */ 3899b631363SMatt Jacob if (mpt_wait_db_int(mpt) != MPT_OK) { 390301472c2SMatt Jacob mpt_prt(mpt, "mpt_recv_handshake_cmd timeout2"); 3919b631363SMatt Jacob return ETIMEDOUT; 3929b631363SMatt Jacob } 3939b631363SMatt Jacob *data16++ = mpt_read(mpt, MPT_OFFSET_DOORBELL) & MPT_DB_DATA_MASK; 3949b631363SMatt Jacob mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 3959b631363SMatt Jacob 3969b631363SMatt Jacob /* With the second word, we can now look at the length */ 3979b631363SMatt Jacob if (mpt->verbose > 1 && ((reply_len >> 1) != hdr->MsgLength)) { 398301472c2SMatt Jacob mpt_prt(mpt, "reply length does not match message length: " 399301472c2SMatt Jacob "got 0x%02x, expected 0x%02x", 400301472c2SMatt Jacob hdr->MsgLength << 2, reply_len << 1); 4019b631363SMatt Jacob } 4029b631363SMatt Jacob 4039b631363SMatt Jacob /* Get rest of the reply; but don't overflow the provided buffer */ 4049b631363SMatt Jacob left = (hdr->MsgLength << 1) - 2; 4059b631363SMatt Jacob reply_left = reply_len - 2; 4069b631363SMatt Jacob while (left--) { 4079b631363SMatt Jacob u_int16_t datum; 4089b631363SMatt Jacob 4099b631363SMatt Jacob if (mpt_wait_db_int(mpt) != MPT_OK) { 410301472c2SMatt Jacob mpt_prt(mpt, "mpt_recv_handshake_cmd timeout3"); 4119b631363SMatt Jacob return ETIMEDOUT; 4129b631363SMatt Jacob } 4139b631363SMatt Jacob datum = mpt_read(mpt, MPT_OFFSET_DOORBELL); 4149b631363SMatt Jacob 4159b631363SMatt Jacob if (reply_left-- > 0) 4169b631363SMatt Jacob *data16++ = datum & MPT_DB_DATA_MASK; 4179b631363SMatt Jacob 4189b631363SMatt Jacob mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 4199b631363SMatt Jacob } 4209b631363SMatt Jacob 4219b631363SMatt Jacob /* One more wait & clear at the end */ 4229b631363SMatt Jacob if (mpt_wait_db_int(mpt) != MPT_OK) { 423301472c2SMatt Jacob mpt_prt(mpt, "mpt_recv_handshake_cmd timeout4"); 4249b631363SMatt Jacob return ETIMEDOUT; 4259b631363SMatt Jacob } 4269b631363SMatt Jacob mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 4279b631363SMatt Jacob 4289b631363SMatt Jacob if ((hdr->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 4299b631363SMatt Jacob if (mpt->verbose > 1) 4309b631363SMatt Jacob mpt_print_reply(hdr); 4319b631363SMatt Jacob return (MPT_FAIL | hdr->IOCStatus); 4329b631363SMatt Jacob } 4339b631363SMatt Jacob 4349b631363SMatt Jacob return (0); 4359b631363SMatt Jacob } 4369b631363SMatt Jacob 4379b631363SMatt Jacob static int 4387104aeefSMatt Jacob mpt_get_iocfacts(mpt_softc_t *mpt, MSG_IOC_FACTS_REPLY *freplp) 4399b631363SMatt Jacob { 4409b631363SMatt Jacob MSG_IOC_FACTS f_req; 4419b631363SMatt Jacob int error; 4429b631363SMatt Jacob 4439b631363SMatt Jacob bzero(&f_req, sizeof f_req); 4449b631363SMatt Jacob f_req.Function = MPI_FUNCTION_IOC_FACTS; 4459b631363SMatt Jacob f_req.MsgContext = 0x12071942; 4469b631363SMatt Jacob error = mpt_send_handshake_cmd(mpt, sizeof f_req, &f_req); 4479b631363SMatt Jacob if (error) 4489b631363SMatt Jacob return(error); 4499b631363SMatt Jacob error = mpt_recv_handshake_reply(mpt, sizeof (*freplp), freplp); 4509b631363SMatt Jacob return (error); 4519b631363SMatt Jacob } 4529b631363SMatt Jacob 4537104aeefSMatt Jacob static int 4547104aeefSMatt Jacob mpt_get_portfacts(mpt_softc_t *mpt, MSG_PORT_FACTS_REPLY *freplp) 4557104aeefSMatt Jacob { 4567104aeefSMatt Jacob MSG_PORT_FACTS f_req; 4577104aeefSMatt Jacob int error; 4587104aeefSMatt Jacob 4597104aeefSMatt Jacob /* XXX: Only getting PORT FACTS for Port 0 */ 4607104aeefSMatt Jacob bzero(&f_req, sizeof f_req); 4617104aeefSMatt Jacob f_req.Function = MPI_FUNCTION_PORT_FACTS; 4627104aeefSMatt Jacob f_req.MsgContext = 0x12071943; 4637104aeefSMatt Jacob error = mpt_send_handshake_cmd(mpt, sizeof f_req, &f_req); 4647104aeefSMatt Jacob if (error) 4657104aeefSMatt Jacob return(error); 4667104aeefSMatt Jacob error = mpt_recv_handshake_reply(mpt, sizeof (*freplp), freplp); 4677104aeefSMatt Jacob return (error); 4687104aeefSMatt Jacob } 4697104aeefSMatt Jacob 4709b631363SMatt Jacob /* 4719b631363SMatt Jacob * Send the initialization request. This is where we specify how many 4729b631363SMatt Jacob * SCSI busses and how many devices per bus we wish to emulate. 4739b631363SMatt Jacob * This is also the command that specifies the max size of the reply 4749b631363SMatt Jacob * frames from the IOC that we will be allocating. 4759b631363SMatt Jacob */ 4769b631363SMatt Jacob static int 4777104aeefSMatt Jacob mpt_send_ioc_init(mpt_softc_t *mpt, u_int32_t who) 4789b631363SMatt Jacob { 4799b631363SMatt Jacob int error = 0; 4809b631363SMatt Jacob MSG_IOC_INIT init; 4819b631363SMatt Jacob MSG_IOC_INIT_REPLY reply; 4829b631363SMatt Jacob 4839b631363SMatt Jacob bzero(&init, sizeof init); 4849b631363SMatt Jacob init.WhoInit = who; 4859b631363SMatt Jacob init.Function = MPI_FUNCTION_IOC_INIT; 4869b631363SMatt Jacob if (mpt->is_fc) { 4879b631363SMatt Jacob init.MaxDevices = 255; 4889b631363SMatt Jacob } else { 4899b631363SMatt Jacob init.MaxDevices = 16; 4909b631363SMatt Jacob } 4919b631363SMatt Jacob init.MaxBuses = 1; 4929b631363SMatt Jacob init.ReplyFrameSize = MPT_REPLY_SIZE; 4939b631363SMatt Jacob init.MsgContext = 0x12071941; 4949b631363SMatt Jacob 4959b631363SMatt Jacob if ((error = mpt_send_handshake_cmd(mpt, sizeof init, &init)) != 0) { 4969b631363SMatt Jacob return(error); 4979b631363SMatt Jacob } 4989b631363SMatt Jacob 4999b631363SMatt Jacob error = mpt_recv_handshake_reply(mpt, sizeof reply, &reply); 5009b631363SMatt Jacob return (error); 5019b631363SMatt Jacob } 5029b631363SMatt Jacob 5037104aeefSMatt Jacob 5047104aeefSMatt Jacob /* 5057104aeefSMatt Jacob * Utiltity routine to read configuration headers and pages 5067104aeefSMatt Jacob */ 5077104aeefSMatt Jacob 5089b631363SMatt Jacob static int 5097fed69eeSMatt Jacob mpt_read_cfg_header(mpt_softc_t *, int, int, int, CONFIG_PAGE_HEADER *); 5107104aeefSMatt Jacob 5117104aeefSMatt Jacob static int 5127104aeefSMatt Jacob mpt_read_cfg_header(mpt_softc_t *mpt, int PageType, int PageNumber, 5137fed69eeSMatt Jacob int PageAddress, CONFIG_PAGE_HEADER *rslt) 5147104aeefSMatt Jacob { 5157104aeefSMatt Jacob int count; 5167104aeefSMatt Jacob request_t *req; 5177104aeefSMatt Jacob MSG_CONFIG *cfgp; 5187104aeefSMatt Jacob MSG_CONFIG_REPLY *reply; 5197104aeefSMatt Jacob 5207104aeefSMatt Jacob req = mpt_get_request(mpt); 5217104aeefSMatt Jacob 5227104aeefSMatt Jacob cfgp = req->req_vbuf; 5237104aeefSMatt Jacob bzero(cfgp, sizeof *cfgp); 5247104aeefSMatt Jacob 5257104aeefSMatt Jacob cfgp->Action = MPI_CONFIG_ACTION_PAGE_HEADER; 5267104aeefSMatt Jacob cfgp->Function = MPI_FUNCTION_CONFIG; 5277104aeefSMatt Jacob cfgp->Header.PageNumber = (U8) PageNumber; 5287104aeefSMatt Jacob cfgp->Header.PageType = (U8) PageType; 5297104aeefSMatt Jacob cfgp->PageAddress = PageAddress; 5307104aeefSMatt Jacob MPI_pSGE_SET_FLAGS(((SGE_SIMPLE32 *) &cfgp->PageBufferSGE), 5317104aeefSMatt Jacob (MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | 5327104aeefSMatt Jacob MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_LIST)); 5337104aeefSMatt Jacob cfgp->MsgContext = req->index | 0x80000000; 5347104aeefSMatt Jacob 5357104aeefSMatt Jacob mpt_check_doorbell(mpt); 5367104aeefSMatt Jacob mpt_send_cmd(mpt, req); 5377104aeefSMatt Jacob count = 0; 5387104aeefSMatt Jacob do { 5397104aeefSMatt Jacob DELAY(500); 5407104aeefSMatt Jacob mpt_intr(mpt); 5417104aeefSMatt Jacob if (++count == 1000) { 542301472c2SMatt Jacob mpt_prt(mpt, "read_cfg_header timed out"); 5437104aeefSMatt Jacob return (-1); 5447104aeefSMatt Jacob } 5457104aeefSMatt Jacob } while (req->debug == REQ_ON_CHIP); 5467104aeefSMatt Jacob 5477104aeefSMatt Jacob reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence); 5487104aeefSMatt Jacob if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 549301472c2SMatt Jacob mpt_prt(mpt, "mpt_read_cfg_header: Config Info Status %x", 5507104aeefSMatt Jacob reply->IOCStatus); 551301472c2SMatt Jacob mpt_free_reply(mpt, (req->sequence << 1)); 5527104aeefSMatt Jacob return (-1); 5537104aeefSMatt Jacob } 5547fed69eeSMatt Jacob bcopy(&reply->Header, rslt, sizeof (CONFIG_PAGE_HEADER)); 5557104aeefSMatt Jacob mpt_free_reply(mpt, (req->sequence << 1)); 5567104aeefSMatt Jacob mpt_free_request(mpt, req); 5577104aeefSMatt Jacob return (0); 5587104aeefSMatt Jacob } 5597104aeefSMatt Jacob 5600424fb53SMatt Jacob #define CFG_DATA_OFF 128 5617104aeefSMatt Jacob 562ce68dae5SMatt Jacob int 5637fed69eeSMatt Jacob mpt_read_cfg_page(mpt_softc_t *mpt, int PageAddress, CONFIG_PAGE_HEADER *hdr) 5647104aeefSMatt Jacob { 5657104aeefSMatt Jacob int count; 5667104aeefSMatt Jacob request_t *req; 5677104aeefSMatt Jacob SGE_SIMPLE32 *se; 5687104aeefSMatt Jacob MSG_CONFIG *cfgp; 5697104aeefSMatt Jacob size_t amt; 5707104aeefSMatt Jacob MSG_CONFIG_REPLY *reply; 5717104aeefSMatt Jacob 5727104aeefSMatt Jacob req = mpt_get_request(mpt); 5737104aeefSMatt Jacob 5747104aeefSMatt Jacob cfgp = req->req_vbuf; 5750424fb53SMatt Jacob bzero(cfgp, MPT_REQUEST_AREA); 5767104aeefSMatt Jacob cfgp->Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 5777104aeefSMatt Jacob cfgp->Function = MPI_FUNCTION_CONFIG; 5787104aeefSMatt Jacob cfgp->Header = *hdr; 579301472c2SMatt Jacob amt = (cfgp->Header.PageLength * sizeof (u_int32_t)); 5807104aeefSMatt Jacob cfgp->Header.PageType &= MPI_CONFIG_PAGETYPE_MASK; 5817104aeefSMatt Jacob cfgp->PageAddress = PageAddress; 5827104aeefSMatt Jacob se = (SGE_SIMPLE32 *) &cfgp->PageBufferSGE; 5837104aeefSMatt Jacob se->Address = req->req_pbuf + CFG_DATA_OFF; 5847104aeefSMatt Jacob MPI_pSGE_SET_LENGTH(se, amt); 5857104aeefSMatt Jacob MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT | 5867104aeefSMatt Jacob MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | 5877104aeefSMatt Jacob MPI_SGE_FLAGS_END_OF_LIST)); 5887104aeefSMatt Jacob 5897104aeefSMatt Jacob cfgp->MsgContext = req->index | 0x80000000; 5907104aeefSMatt Jacob 5917104aeefSMatt Jacob mpt_check_doorbell(mpt); 5927104aeefSMatt Jacob mpt_send_cmd(mpt, req); 5937104aeefSMatt Jacob count = 0; 5947104aeefSMatt Jacob do { 5957104aeefSMatt Jacob DELAY(500); 5967104aeefSMatt Jacob mpt_intr(mpt); 5977104aeefSMatt Jacob if (++count == 1000) { 598301472c2SMatt Jacob mpt_prt(mpt, "read_cfg_page timed out"); 5997104aeefSMatt Jacob return (-1); 6007104aeefSMatt Jacob } 6017104aeefSMatt Jacob } while (req->debug == REQ_ON_CHIP); 6027104aeefSMatt Jacob 6037104aeefSMatt Jacob reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence); 6047104aeefSMatt Jacob if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 605301472c2SMatt Jacob mpt_prt(mpt, "mpt_read_cfg_page: Config Info Status %x", 6067104aeefSMatt Jacob reply->IOCStatus); 607301472c2SMatt Jacob mpt_free_reply(mpt, (req->sequence << 1)); 6087104aeefSMatt Jacob return (-1); 6097104aeefSMatt Jacob } 6107104aeefSMatt Jacob mpt_free_reply(mpt, (req->sequence << 1)); 6117104aeefSMatt Jacob bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap, 6127104aeefSMatt Jacob BUS_DMASYNC_POSTREAD); 6137104aeefSMatt Jacob if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 6147104aeefSMatt Jacob cfgp->Header.PageNumber == 0) { 6157fed69eeSMatt Jacob amt = sizeof (CONFIG_PAGE_SCSI_PORT_0); 6167104aeefSMatt Jacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 6177104aeefSMatt Jacob cfgp->Header.PageNumber == 1) { 6187fed69eeSMatt Jacob amt = sizeof (CONFIG_PAGE_SCSI_PORT_1); 6197104aeefSMatt Jacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 6207104aeefSMatt Jacob cfgp->Header.PageNumber == 2) { 6217fed69eeSMatt Jacob amt = sizeof (CONFIG_PAGE_SCSI_PORT_2); 6227104aeefSMatt Jacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE && 6237104aeefSMatt Jacob cfgp->Header.PageNumber == 0) { 6247fed69eeSMatt Jacob amt = sizeof (CONFIG_PAGE_SCSI_DEVICE_0); 6257104aeefSMatt Jacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE && 6267104aeefSMatt Jacob cfgp->Header.PageNumber == 1) { 6277fed69eeSMatt Jacob amt = sizeof (CONFIG_PAGE_SCSI_DEVICE_1); 6287104aeefSMatt Jacob } 6297104aeefSMatt Jacob bcopy(((caddr_t)req->req_vbuf)+CFG_DATA_OFF, hdr, amt); 6307104aeefSMatt Jacob mpt_free_request(mpt, req); 6317104aeefSMatt Jacob return (0); 6327104aeefSMatt Jacob } 6337104aeefSMatt Jacob 634ce68dae5SMatt Jacob int 6357fed69eeSMatt Jacob mpt_write_cfg_page(mpt_softc_t *mpt, int PageAddress, CONFIG_PAGE_HEADER *hdr) 6367104aeefSMatt Jacob { 6377104aeefSMatt Jacob int count, hdr_attr; 6387104aeefSMatt Jacob request_t *req; 6397104aeefSMatt Jacob SGE_SIMPLE32 *se; 6407104aeefSMatt Jacob MSG_CONFIG *cfgp; 6417104aeefSMatt Jacob size_t amt; 6427104aeefSMatt Jacob MSG_CONFIG_REPLY *reply; 6437104aeefSMatt Jacob 6447104aeefSMatt Jacob req = mpt_get_request(mpt); 6457104aeefSMatt Jacob 6467104aeefSMatt Jacob cfgp = req->req_vbuf; 6477104aeefSMatt Jacob bzero(cfgp, sizeof *cfgp); 6487104aeefSMatt Jacob 6497104aeefSMatt Jacob hdr_attr = hdr->PageType & MPI_CONFIG_PAGEATTR_MASK; 6507104aeefSMatt Jacob if (hdr_attr != MPI_CONFIG_PAGEATTR_CHANGEABLE && 6517104aeefSMatt Jacob hdr_attr != MPI_CONFIG_PAGEATTR_PERSISTENT) { 652301472c2SMatt Jacob mpt_prt(mpt, "page type 0x%x not changeable", 6537104aeefSMatt Jacob hdr->PageType & MPI_CONFIG_PAGETYPE_MASK); 6547104aeefSMatt Jacob return (-1); 6557104aeefSMatt Jacob } 6567104aeefSMatt Jacob hdr->PageType &= MPI_CONFIG_PAGETYPE_MASK; 6577104aeefSMatt Jacob 6587104aeefSMatt Jacob cfgp->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; 6597104aeefSMatt Jacob cfgp->Function = MPI_FUNCTION_CONFIG; 6607104aeefSMatt Jacob cfgp->Header = *hdr; 661301472c2SMatt Jacob amt = (cfgp->Header.PageLength * sizeof (u_int32_t)); 6627104aeefSMatt Jacob cfgp->PageAddress = PageAddress; 6637104aeefSMatt Jacob 6647104aeefSMatt Jacob se = (SGE_SIMPLE32 *) &cfgp->PageBufferSGE; 6657104aeefSMatt Jacob se->Address = req->req_pbuf + CFG_DATA_OFF; 6667104aeefSMatt Jacob MPI_pSGE_SET_LENGTH(se, amt); 6677104aeefSMatt Jacob MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT | 6687104aeefSMatt Jacob MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | 6697104aeefSMatt Jacob MPI_SGE_FLAGS_END_OF_LIST | MPI_SGE_FLAGS_HOST_TO_IOC)); 6707104aeefSMatt Jacob 6717104aeefSMatt Jacob cfgp->MsgContext = req->index | 0x80000000; 6727104aeefSMatt Jacob 6737104aeefSMatt Jacob if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 6747104aeefSMatt Jacob cfgp->Header.PageNumber == 0) { 6757fed69eeSMatt Jacob amt = sizeof (CONFIG_PAGE_SCSI_PORT_0); 6767104aeefSMatt Jacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 6777104aeefSMatt Jacob cfgp->Header.PageNumber == 1) { 6787fed69eeSMatt Jacob amt = sizeof (CONFIG_PAGE_SCSI_PORT_1); 6797104aeefSMatt Jacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 6807104aeefSMatt Jacob cfgp->Header.PageNumber == 2) { 6817fed69eeSMatt Jacob amt = sizeof (CONFIG_PAGE_SCSI_PORT_2); 6827104aeefSMatt Jacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE && 6837104aeefSMatt Jacob cfgp->Header.PageNumber == 0) { 6847fed69eeSMatt Jacob amt = sizeof (CONFIG_PAGE_SCSI_DEVICE_0); 6857104aeefSMatt Jacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE && 6867104aeefSMatt Jacob cfgp->Header.PageNumber == 1) { 6877fed69eeSMatt Jacob amt = sizeof (CONFIG_PAGE_SCSI_DEVICE_1); 6887104aeefSMatt Jacob } 6897104aeefSMatt Jacob bcopy(hdr, ((caddr_t)req->req_vbuf)+CFG_DATA_OFF, amt); 690301472c2SMatt Jacob /* Restore stripped out attributes */ 691301472c2SMatt Jacob hdr->PageType |= hdr_attr; 6927104aeefSMatt Jacob 6937104aeefSMatt Jacob mpt_check_doorbell(mpt); 6947104aeefSMatt Jacob mpt_send_cmd(mpt, req); 6957104aeefSMatt Jacob count = 0; 6967104aeefSMatt Jacob do { 6977104aeefSMatt Jacob DELAY(500); 6987104aeefSMatt Jacob mpt_intr(mpt); 6997104aeefSMatt Jacob if (++count == 1000) { 7007104aeefSMatt Jacob hdr->PageType |= hdr_attr; 701301472c2SMatt Jacob mpt_prt(mpt, "mpt_write_cfg_page timed out"); 7027104aeefSMatt Jacob return (-1); 7037104aeefSMatt Jacob } 7047104aeefSMatt Jacob } while (req->debug == REQ_ON_CHIP); 7057104aeefSMatt Jacob 7067104aeefSMatt Jacob reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence); 7077104aeefSMatt Jacob if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 708301472c2SMatt Jacob mpt_prt(mpt, "mpt_write_cfg_page: Config Info Status %x", 7097104aeefSMatt Jacob reply->IOCStatus); 710301472c2SMatt Jacob mpt_free_reply(mpt, (req->sequence << 1)); 7117104aeefSMatt Jacob return (-1); 7127104aeefSMatt Jacob } 7137104aeefSMatt Jacob mpt_free_reply(mpt, (req->sequence << 1)); 7147104aeefSMatt Jacob 7157104aeefSMatt Jacob mpt_free_request(mpt, req); 7167104aeefSMatt Jacob return (0); 7177104aeefSMatt Jacob } 7187104aeefSMatt Jacob 7197104aeefSMatt Jacob /* 7207104aeefSMatt Jacob * Read SCSI configuration information 7217104aeefSMatt Jacob */ 7227104aeefSMatt Jacob static int 7237104aeefSMatt Jacob mpt_read_config_info_spi(mpt_softc_t *mpt) 7247104aeefSMatt Jacob { 7257104aeefSMatt Jacob int rv, i; 7267104aeefSMatt Jacob 7277104aeefSMatt Jacob rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 0, 7287104aeefSMatt Jacob 0, &mpt->mpt_port_page0.Header); 7297104aeefSMatt Jacob if (rv) { 7307104aeefSMatt Jacob return (-1); 7317104aeefSMatt Jacob } 7327104aeefSMatt Jacob if (mpt->verbose > 1) { 733301472c2SMatt Jacob mpt_prt(mpt, "SPI Port Page 0 Header: %x %x %x %x", 7347104aeefSMatt Jacob mpt->mpt_port_page0.Header.PageVersion, 7357104aeefSMatt Jacob mpt->mpt_port_page0.Header.PageLength, 7367104aeefSMatt Jacob mpt->mpt_port_page0.Header.PageNumber, 7377104aeefSMatt Jacob mpt->mpt_port_page0.Header.PageType); 7387104aeefSMatt Jacob } 7397104aeefSMatt Jacob 7407104aeefSMatt Jacob rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 1, 7417104aeefSMatt Jacob 0, &mpt->mpt_port_page1.Header); 7427104aeefSMatt Jacob if (rv) { 7437104aeefSMatt Jacob return (-1); 7447104aeefSMatt Jacob } 7457104aeefSMatt Jacob if (mpt->verbose > 1) { 746301472c2SMatt Jacob mpt_prt(mpt, "SPI Port Page 1 Header: %x %x %x %x", 7477104aeefSMatt Jacob mpt->mpt_port_page1.Header.PageVersion, 7487104aeefSMatt Jacob mpt->mpt_port_page1.Header.PageLength, 7497104aeefSMatt Jacob mpt->mpt_port_page1.Header.PageNumber, 7507104aeefSMatt Jacob mpt->mpt_port_page1.Header.PageType); 7517104aeefSMatt Jacob } 7527104aeefSMatt Jacob 7537104aeefSMatt Jacob rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 2, 7547104aeefSMatt Jacob 0, &mpt->mpt_port_page2.Header); 7557104aeefSMatt Jacob if (rv) { 7567104aeefSMatt Jacob return (-1); 7577104aeefSMatt Jacob } 7587104aeefSMatt Jacob 7597104aeefSMatt Jacob if (mpt->verbose > 1) { 760301472c2SMatt Jacob mpt_prt(mpt, "SPI Port Page 2 Header: %x %x %x %x", 7617104aeefSMatt Jacob mpt->mpt_port_page1.Header.PageVersion, 7627104aeefSMatt Jacob mpt->mpt_port_page1.Header.PageLength, 7637104aeefSMatt Jacob mpt->mpt_port_page1.Header.PageNumber, 7647104aeefSMatt Jacob mpt->mpt_port_page1.Header.PageType); 7657104aeefSMatt Jacob } 7667104aeefSMatt Jacob 7677104aeefSMatt Jacob for (i = 0; i < 16; i++) { 7687104aeefSMatt Jacob rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE, 7697104aeefSMatt Jacob 0, i, &mpt->mpt_dev_page0[i].Header); 7707104aeefSMatt Jacob if (rv) { 7717104aeefSMatt Jacob return (-1); 7727104aeefSMatt Jacob } 7737104aeefSMatt Jacob if (mpt->verbose > 1) { 774301472c2SMatt Jacob mpt_prt(mpt, 775301472c2SMatt Jacob "SPI Target %d Device Page 0 Header: %x %x %x %x", 7767104aeefSMatt Jacob i, mpt->mpt_dev_page0[i].Header.PageVersion, 7777104aeefSMatt Jacob mpt->mpt_dev_page0[i].Header.PageLength, 7787104aeefSMatt Jacob mpt->mpt_dev_page0[i].Header.PageNumber, 7797104aeefSMatt Jacob mpt->mpt_dev_page0[i].Header.PageType); 7807104aeefSMatt Jacob } 7817104aeefSMatt Jacob 7827104aeefSMatt Jacob rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE, 7837104aeefSMatt Jacob 1, i, &mpt->mpt_dev_page1[i].Header); 7847104aeefSMatt Jacob if (rv) { 7857104aeefSMatt Jacob return (-1); 7867104aeefSMatt Jacob } 7877104aeefSMatt Jacob if (mpt->verbose > 1) { 788301472c2SMatt Jacob mpt_prt(mpt, 789301472c2SMatt Jacob "SPI Target %d Device Page 1 Header: %x %x %x %x", 7907104aeefSMatt Jacob i, mpt->mpt_dev_page1[i].Header.PageVersion, 7917104aeefSMatt Jacob mpt->mpt_dev_page1[i].Header.PageLength, 7927104aeefSMatt Jacob mpt->mpt_dev_page1[i].Header.PageNumber, 7937104aeefSMatt Jacob mpt->mpt_dev_page1[i].Header.PageType); 7947104aeefSMatt Jacob } 7957104aeefSMatt Jacob } 7967104aeefSMatt Jacob 7977104aeefSMatt Jacob /* 7987104aeefSMatt Jacob * At this point, we don't *have* to fail. As long as we have 7997104aeefSMatt Jacob * valid config header information, we can (barely) lurch 8007104aeefSMatt Jacob * along. 8017104aeefSMatt Jacob */ 8027104aeefSMatt Jacob 8037104aeefSMatt Jacob rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page0.Header); 8047104aeefSMatt Jacob if (rv) { 805301472c2SMatt Jacob mpt_prt(mpt, "failed to read SPI Port Page 0"); 8067104aeefSMatt Jacob } else if (mpt->verbose > 1) { 807301472c2SMatt Jacob mpt_prt(mpt, 808301472c2SMatt Jacob "SPI Port Page 0: Capabilities %x PhysicalInterface %x", 8097104aeefSMatt Jacob mpt->mpt_port_page0.Capabilities, 8107104aeefSMatt Jacob mpt->mpt_port_page0.PhysicalInterface); 8117104aeefSMatt Jacob } 8127104aeefSMatt Jacob 8137104aeefSMatt Jacob rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page1.Header); 8147104aeefSMatt Jacob if (rv) { 815301472c2SMatt Jacob mpt_prt(mpt, "failed to read SPI Port Page 1"); 8167104aeefSMatt Jacob } else if (mpt->verbose > 1) { 817301472c2SMatt Jacob mpt_prt(mpt, 818301472c2SMatt Jacob "SPI Port Page 1: Configuration %x OnBusTimerValue %x", 8197104aeefSMatt Jacob mpt->mpt_port_page1.Configuration, 8207104aeefSMatt Jacob mpt->mpt_port_page1.OnBusTimerValue); 8217104aeefSMatt Jacob } 8227104aeefSMatt Jacob 8237104aeefSMatt Jacob rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page2.Header); 8247104aeefSMatt Jacob if (rv) { 825301472c2SMatt Jacob mpt_prt(mpt, "failed to read SPI Port Page 2"); 8267104aeefSMatt Jacob } else if (mpt->verbose > 1) { 827301472c2SMatt Jacob mpt_prt(mpt, 828301472c2SMatt Jacob "SPI Port Page 2: Flags %x Settings %x", 8297104aeefSMatt Jacob mpt->mpt_port_page2.PortFlags, 8307104aeefSMatt Jacob mpt->mpt_port_page2.PortSettings); 8317104aeefSMatt Jacob for (i = 0; i < 16; i++) { 832301472c2SMatt Jacob mpt_prt(mpt, 833301472c2SMatt Jacob "SPI Port Page 2 Tgt %d: timo %x SF %x Flags %x", 8347104aeefSMatt Jacob i, mpt->mpt_port_page2.DeviceSettings[i].Timeout, 8357104aeefSMatt Jacob mpt->mpt_port_page2.DeviceSettings[i].SyncFactor, 8367104aeefSMatt Jacob mpt->mpt_port_page2.DeviceSettings[i].DeviceFlags); 8377104aeefSMatt Jacob } 8387104aeefSMatt Jacob } 8397104aeefSMatt Jacob 8407104aeefSMatt Jacob for (i = 0; i < 16; i++) { 8417104aeefSMatt Jacob rv = mpt_read_cfg_page(mpt, i, &mpt->mpt_dev_page0[i].Header); 8427104aeefSMatt Jacob if (rv) { 843301472c2SMatt Jacob mpt_prt(mpt, "cannot read SPI Tgt %d Device Page 0", i); 8447104aeefSMatt Jacob continue; 8457104aeefSMatt Jacob } 8467104aeefSMatt Jacob if (mpt->verbose > 1) { 847301472c2SMatt Jacob mpt_prt(mpt, 848301472c2SMatt Jacob "SPI Tgt %d Page 0: NParms %x Information %x", 8497104aeefSMatt Jacob i, mpt->mpt_dev_page0[i].NegotiatedParameters, 8507104aeefSMatt Jacob mpt->mpt_dev_page0[i].Information); 8517104aeefSMatt Jacob } 8527104aeefSMatt Jacob rv = mpt_read_cfg_page(mpt, i, &mpt->mpt_dev_page1[i].Header); 8537104aeefSMatt Jacob if (rv) { 854301472c2SMatt Jacob mpt_prt(mpt, "cannot read SPI Tgt %d Device Page 1", i); 8557104aeefSMatt Jacob continue; 8567104aeefSMatt Jacob } 8577104aeefSMatt Jacob if (mpt->verbose > 1) { 858301472c2SMatt Jacob mpt_prt(mpt, 859301472c2SMatt Jacob "SPI Tgt %d Page 1: RParms %x Configuration %x", 8607104aeefSMatt Jacob i, mpt->mpt_dev_page1[i].RequestedParameters, 8617104aeefSMatt Jacob mpt->mpt_dev_page1[i].Configuration); 8627104aeefSMatt Jacob } 8637104aeefSMatt Jacob } 8647104aeefSMatt Jacob return (0); 8657104aeefSMatt Jacob } 8667104aeefSMatt Jacob 8677104aeefSMatt Jacob /* 8687104aeefSMatt Jacob * Validate SPI configuration information. 8697104aeefSMatt Jacob * 8707104aeefSMatt Jacob * In particular, validate SPI Port Page 1. 8717104aeefSMatt Jacob */ 8727104aeefSMatt Jacob static int 8737104aeefSMatt Jacob mpt_set_initial_config_spi(mpt_softc_t *mpt) 8747104aeefSMatt Jacob { 8757104aeefSMatt Jacob int i, pp1val = ((1 << mpt->mpt_ini_id) << 16) | mpt->mpt_ini_id; 8767104aeefSMatt Jacob 877ce68dae5SMatt Jacob mpt->mpt_disc_enable = 0xff; 878ce68dae5SMatt Jacob mpt->mpt_tag_enable = 0; 879ce68dae5SMatt Jacob 8807104aeefSMatt Jacob if (mpt->mpt_port_page1.Configuration != pp1val) { 8817fed69eeSMatt Jacob CONFIG_PAGE_SCSI_PORT_1 tmp; 882301472c2SMatt Jacob mpt_prt(mpt, 883301472c2SMatt Jacob "SPI Port Page 1 Config value bad (%x)- should be %x", 8847104aeefSMatt Jacob mpt->mpt_port_page1.Configuration, pp1val); 8857104aeefSMatt Jacob tmp = mpt->mpt_port_page1; 8867104aeefSMatt Jacob tmp.Configuration = pp1val; 8877104aeefSMatt Jacob if (mpt_write_cfg_page(mpt, 0, &tmp.Header)) { 8887104aeefSMatt Jacob return (-1); 8897104aeefSMatt Jacob } 8907104aeefSMatt Jacob if (mpt_read_cfg_page(mpt, 0, &tmp.Header)) { 8917104aeefSMatt Jacob return (-1); 8927104aeefSMatt Jacob } 8937104aeefSMatt Jacob if (tmp.Configuration != pp1val) { 894301472c2SMatt Jacob mpt_prt(mpt, 895301472c2SMatt Jacob "failed to reset SPI Port Page 1 Config value"); 8967104aeefSMatt Jacob return (-1); 8977104aeefSMatt Jacob } 8987104aeefSMatt Jacob mpt->mpt_port_page1 = tmp; 8997104aeefSMatt Jacob } 9007104aeefSMatt Jacob 9017104aeefSMatt Jacob for (i = 0; i < 16; i++) { 9027fed69eeSMatt Jacob CONFIG_PAGE_SCSI_DEVICE_1 tmp; 9037104aeefSMatt Jacob tmp = mpt->mpt_dev_page1[i]; 9047104aeefSMatt Jacob tmp.RequestedParameters = 0; 9057104aeefSMatt Jacob tmp.Configuration = 0; 9067104aeefSMatt Jacob if (mpt->verbose > 1) { 907301472c2SMatt Jacob mpt_prt(mpt, 908301472c2SMatt Jacob "Set Tgt %d SPI DevicePage 1 values to %x 0 %x", 9097104aeefSMatt Jacob i, tmp.RequestedParameters, tmp.Configuration); 9107104aeefSMatt Jacob } 9117104aeefSMatt Jacob if (mpt_write_cfg_page(mpt, i, &tmp.Header)) { 9127104aeefSMatt Jacob return (-1); 9137104aeefSMatt Jacob } 9147104aeefSMatt Jacob if (mpt_read_cfg_page(mpt, i, &tmp.Header)) { 9157104aeefSMatt Jacob return (-1); 9167104aeefSMatt Jacob } 9177104aeefSMatt Jacob mpt->mpt_dev_page1[i] = tmp; 9187104aeefSMatt Jacob if (mpt->verbose > 1) { 919301472c2SMatt Jacob mpt_prt(mpt, 920301472c2SMatt Jacob "SPI Tgt %d Page 1: RParm %x Configuration %x", i, 9217104aeefSMatt Jacob mpt->mpt_dev_page1[i].RequestedParameters, 9227104aeefSMatt Jacob mpt->mpt_dev_page1[i].Configuration); 9237104aeefSMatt Jacob } 9247104aeefSMatt Jacob } 9257104aeefSMatt Jacob return (0); 9267104aeefSMatt Jacob } 9277104aeefSMatt Jacob 9287104aeefSMatt Jacob /* 9297104aeefSMatt Jacob * Enable IOC port 9307104aeefSMatt Jacob */ 9317104aeefSMatt Jacob static int 9327104aeefSMatt Jacob mpt_send_port_enable(mpt_softc_t *mpt, int port) 9339b631363SMatt Jacob { 9349b631363SMatt Jacob int count; 9359b631363SMatt Jacob request_t *req; 9369b631363SMatt Jacob MSG_PORT_ENABLE *enable_req; 9379b631363SMatt Jacob 9389b631363SMatt Jacob req = mpt_get_request(mpt); 9399b631363SMatt Jacob 9409b631363SMatt Jacob enable_req = req->req_vbuf; 9419b631363SMatt Jacob bzero(enable_req, sizeof *enable_req); 9429b631363SMatt Jacob 9439b631363SMatt Jacob enable_req->Function = MPI_FUNCTION_PORT_ENABLE; 9449b631363SMatt Jacob enable_req->MsgContext = req->index | 0x80000000; 9459b631363SMatt Jacob enable_req->PortNumber = port; 9469b631363SMatt Jacob 9479b631363SMatt Jacob mpt_check_doorbell(mpt); 9489b631363SMatt Jacob if (mpt->verbose > 1) { 949301472c2SMatt Jacob mpt_prt(mpt, "enabling port %d", port); 9509b631363SMatt Jacob } 9519b631363SMatt Jacob mpt_send_cmd(mpt, req); 9529b631363SMatt Jacob 9539b631363SMatt Jacob count = 0; 9549b631363SMatt Jacob do { 9559b631363SMatt Jacob DELAY(500); 9569b631363SMatt Jacob mpt_intr(mpt); 9577dec90bcSMatt Jacob if (++count == 100000) { 958301472c2SMatt Jacob mpt_prt(mpt, "port enable timed out"); 9599b631363SMatt Jacob return (-1); 9609b631363SMatt Jacob } 9619b631363SMatt Jacob } while (req->debug == REQ_ON_CHIP); 9629b631363SMatt Jacob mpt_free_request(mpt, req); 9639b631363SMatt Jacob return (0); 9649b631363SMatt Jacob } 9659b631363SMatt Jacob 9669b631363SMatt Jacob /* 9679b631363SMatt Jacob * Enable/Disable asynchronous event reporting. 9689b631363SMatt Jacob * 9699b631363SMatt Jacob * NB: this is the first command we send via shared memory 9709b631363SMatt Jacob * instead of the handshake register. 9719b631363SMatt Jacob */ 9729b631363SMatt Jacob static int 9737104aeefSMatt Jacob mpt_send_event_request(mpt_softc_t *mpt, int onoff) 9749b631363SMatt Jacob { 9759b631363SMatt Jacob request_t *req; 9769b631363SMatt Jacob MSG_EVENT_NOTIFY *enable_req; 9779b631363SMatt Jacob 9789b631363SMatt Jacob req = mpt_get_request(mpt); 9799b631363SMatt Jacob 9809b631363SMatt Jacob enable_req = req->req_vbuf; 9819b631363SMatt Jacob bzero(enable_req, sizeof *enable_req); 9829b631363SMatt Jacob 9839b631363SMatt Jacob enable_req->Function = MPI_FUNCTION_EVENT_NOTIFICATION; 9849b631363SMatt Jacob enable_req->MsgContext = req->index | 0x80000000; 9859b631363SMatt Jacob enable_req->Switch = onoff; 9869b631363SMatt Jacob 9879b631363SMatt Jacob mpt_check_doorbell(mpt); 9889b631363SMatt Jacob if (mpt->verbose > 1) { 989301472c2SMatt Jacob mpt_prt(mpt, "%sabling async events", onoff? "en" : "dis"); 9909b631363SMatt Jacob } 9919b631363SMatt Jacob mpt_send_cmd(mpt, req); 9929b631363SMatt Jacob 9939b631363SMatt Jacob return (0); 9949b631363SMatt Jacob } 9959b631363SMatt Jacob 9969b631363SMatt Jacob /* 9979b631363SMatt Jacob * Un-mask the interupts on the chip. 9989b631363SMatt Jacob */ 9999b631363SMatt Jacob void 10007104aeefSMatt Jacob mpt_enable_ints(mpt_softc_t *mpt) 10019b631363SMatt Jacob { 10029b631363SMatt Jacob /* Unmask every thing except door bell int */ 10039b631363SMatt Jacob mpt_write(mpt, MPT_OFFSET_INTR_MASK, MPT_INTR_DB_MASK); 10049b631363SMatt Jacob } 10059b631363SMatt Jacob 10069b631363SMatt Jacob /* 10079b631363SMatt Jacob * Mask the interupts on the chip. 10089b631363SMatt Jacob */ 10099b631363SMatt Jacob void 10107104aeefSMatt Jacob mpt_disable_ints(mpt_softc_t *mpt) 10119b631363SMatt Jacob { 10129b631363SMatt Jacob /* Mask all interrupts */ 10139b631363SMatt Jacob mpt_write(mpt, MPT_OFFSET_INTR_MASK, 10149b631363SMatt Jacob MPT_INTR_REPLY_MASK | MPT_INTR_DB_MASK); 10159b631363SMatt Jacob } 10169b631363SMatt Jacob 10179b631363SMatt Jacob /* (Re)Initialize the chip for use */ 10189b631363SMatt Jacob int 10197104aeefSMatt Jacob mpt_init(mpt_softc_t *mpt, u_int32_t who) 10209b631363SMatt Jacob { 10219b631363SMatt Jacob int try; 10229b631363SMatt Jacob MSG_IOC_FACTS_REPLY facts; 10237104aeefSMatt Jacob MSG_PORT_FACTS_REPLY pfp; 10249b631363SMatt Jacob u_int32_t pptr; 10259b631363SMatt Jacob int val; 10269b631363SMatt Jacob 10279b631363SMatt Jacob /* Put all request buffers (back) on the free list */ 10289b631363SMatt Jacob SLIST_INIT(&mpt->request_free_list); 10297dec90bcSMatt Jacob for (val = 0; val < MPT_MAX_REQUESTS(mpt); val++) { 10307dec90bcSMatt Jacob mpt_free_request(mpt, &mpt->request_pool[val]); 10319b631363SMatt Jacob } 10329b631363SMatt Jacob 10339b631363SMatt Jacob if (mpt->verbose > 1) { 1034301472c2SMatt Jacob mpt_prt(mpt, "doorbell req = %s", 10359b631363SMatt Jacob mpt_ioc_diag(mpt_read(mpt, MPT_OFFSET_DOORBELL))); 10369b631363SMatt Jacob } 10379b631363SMatt Jacob 10389b631363SMatt Jacob /* 10399b631363SMatt Jacob * Start by making sure we're not at FAULT or RESET state 10409b631363SMatt Jacob */ 10419b631363SMatt Jacob switch (mpt_rd_db(mpt) & MPT_DB_STATE_MASK) { 10429b631363SMatt Jacob case MPT_DB_STATE_RESET: 10439b631363SMatt Jacob case MPT_DB_STATE_FAULT: 10449b631363SMatt Jacob if (mpt_reset(mpt) != MPT_OK) { 10459b631363SMatt Jacob return (EIO); 10469b631363SMatt Jacob } 10479b631363SMatt Jacob default: 10489b631363SMatt Jacob break; 10499b631363SMatt Jacob } 10509b631363SMatt Jacob 10519b631363SMatt Jacob for (try = 0; try < MPT_MAX_TRYS; try++) { 10529b631363SMatt Jacob /* 10539b631363SMatt Jacob * No need to reset if the IOC is already in the READY state. 10549b631363SMatt Jacob * 10559b631363SMatt Jacob * Force reset if initialization failed previously. 10569b631363SMatt Jacob * Note that a hard_reset of the second channel of a '929 10579b631363SMatt Jacob * will stop operation of the first channel. Hopefully, if the 10589b631363SMatt Jacob * first channel is ok, the second will not require a hard 10599b631363SMatt Jacob * reset. 10609b631363SMatt Jacob */ 10619b631363SMatt Jacob if ((mpt_rd_db(mpt) & MPT_DB_STATE_MASK) != 10629b631363SMatt Jacob MPT_DB_STATE_READY) { 10639b631363SMatt Jacob if (mpt_reset(mpt) != MPT_OK) { 10649b631363SMatt Jacob DELAY(10000); 10659b631363SMatt Jacob continue; 10669b631363SMatt Jacob } 10679b631363SMatt Jacob } 10689b631363SMatt Jacob 10699b631363SMatt Jacob if (mpt_get_iocfacts(mpt, &facts) != MPT_OK) { 1070301472c2SMatt Jacob mpt_prt(mpt, "mpt_get_iocfacts failed"); 10719b631363SMatt Jacob continue; 10727104aeefSMatt Jacob } 10737104aeefSMatt Jacob 10747104aeefSMatt Jacob if (mpt->verbose > 1) { 1075301472c2SMatt Jacob mpt_prt(mpt, 10767dec90bcSMatt Jacob "IOCFACTS: GlobalCredits=%d BlockSize=%u " 10779b631363SMatt Jacob "Request Frame Size %u\n", facts.GlobalCredits, 10789b631363SMatt Jacob facts.BlockSize, facts.RequestFrameSize); 10799b631363SMatt Jacob } 10809b631363SMatt Jacob mpt->mpt_global_credits = facts.GlobalCredits; 10819b631363SMatt Jacob mpt->request_frame_size = facts.RequestFrameSize; 10829b631363SMatt Jacob 10837104aeefSMatt Jacob if (mpt_get_portfacts(mpt, &pfp) != MPT_OK) { 1084301472c2SMatt Jacob mpt_prt(mpt, "mpt_get_portfacts failed"); 10857104aeefSMatt Jacob continue; 10867104aeefSMatt Jacob } 10877104aeefSMatt Jacob 10887104aeefSMatt Jacob if (mpt->verbose > 1) { 1089301472c2SMatt Jacob mpt_prt(mpt, 10907dec90bcSMatt Jacob "PORTFACTS: Type %x PFlags %x IID %d MaxDev %d\n", 10917dec90bcSMatt Jacob pfp.PortType, pfp.ProtocolFlags, pfp.PortSCSIID, 10927dec90bcSMatt Jacob pfp.MaxDevices); 10937104aeefSMatt Jacob } 10947104aeefSMatt Jacob 10957104aeefSMatt Jacob if (pfp.PortType != MPI_PORTFACTS_PORTTYPE_SCSI && 10967104aeefSMatt Jacob pfp.PortType != MPI_PORTFACTS_PORTTYPE_FC) { 1097301472c2SMatt Jacob mpt_prt(mpt, "Unsupported Port Type (%x)", 10987104aeefSMatt Jacob pfp.PortType); 10997104aeefSMatt Jacob return (ENXIO); 11007104aeefSMatt Jacob } 11017104aeefSMatt Jacob if (!(pfp.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)) { 1102301472c2SMatt Jacob mpt_prt(mpt, "initiator role unsupported"); 11037104aeefSMatt Jacob return (ENXIO); 11047104aeefSMatt Jacob } 11057104aeefSMatt Jacob if (pfp.PortType == MPI_PORTFACTS_PORTTYPE_FC) { 11067104aeefSMatt Jacob mpt->is_fc = 1; 11077104aeefSMatt Jacob } else { 11087104aeefSMatt Jacob mpt->is_fc = 0; 11097104aeefSMatt Jacob } 11107104aeefSMatt Jacob mpt->mpt_ini_id = pfp.PortSCSIID; 11117104aeefSMatt Jacob 11129b631363SMatt Jacob if (mpt_send_ioc_init(mpt, who) != MPT_OK) { 1113301472c2SMatt Jacob mpt_prt(mpt, "mpt_send_ioc_init failed"); 11149b631363SMatt Jacob continue; 11157104aeefSMatt Jacob } 11167104aeefSMatt Jacob 11177104aeefSMatt Jacob if (mpt->verbose > 1) { 1118301472c2SMatt Jacob mpt_prt(mpt, "mpt_send_ioc_init ok"); 11199b631363SMatt Jacob } 11209b631363SMatt Jacob 11219b631363SMatt Jacob if (mpt_wait_state(mpt, MPT_DB_STATE_RUNNING) != MPT_OK) { 1122301472c2SMatt Jacob mpt_prt(mpt, "IOC failed to go to run state"); 11239b631363SMatt Jacob continue; 11247104aeefSMatt Jacob } 11257104aeefSMatt Jacob if (mpt->verbose > 1) { 1126301472c2SMatt Jacob mpt_prt(mpt, "IOC now at RUNSTATE"); 11279b631363SMatt Jacob } 11289b631363SMatt Jacob 11299b631363SMatt Jacob /* 11309b631363SMatt Jacob * Give it reply buffers 11319b631363SMatt Jacob * 11329b631363SMatt Jacob * Do *not* except global credits. 11339b631363SMatt Jacob */ 11349b631363SMatt Jacob for (val = 0, pptr = mpt->reply_phys; 11359b631363SMatt Jacob (pptr + MPT_REPLY_SIZE) < (mpt->reply_phys + PAGE_SIZE); 11369b631363SMatt Jacob pptr += MPT_REPLY_SIZE) { 11379b631363SMatt Jacob mpt_free_reply(mpt, pptr); 11389b631363SMatt Jacob if (++val == mpt->mpt_global_credits - 1) 11399b631363SMatt Jacob break; 11409b631363SMatt Jacob } 11419b631363SMatt Jacob 11427104aeefSMatt Jacob /* 11437104aeefSMatt Jacob * Enable asynchronous event reporting 11447104aeefSMatt Jacob */ 11459b631363SMatt Jacob mpt_send_event_request(mpt, 1); 11469b631363SMatt Jacob 11477104aeefSMatt Jacob 11487104aeefSMatt Jacob /* 11497104aeefSMatt Jacob * Read set up initial configuration information 11507104aeefSMatt Jacob * (SPI only for now) 11517104aeefSMatt Jacob */ 11527104aeefSMatt Jacob 11537104aeefSMatt Jacob if (mpt->is_fc == 0) { 11547104aeefSMatt Jacob if (mpt_read_config_info_spi(mpt)) { 11557104aeefSMatt Jacob return (EIO); 11567104aeefSMatt Jacob } 11577104aeefSMatt Jacob if (mpt_set_initial_config_spi(mpt)) { 11587104aeefSMatt Jacob return (EIO); 11597104aeefSMatt Jacob } 11607104aeefSMatt Jacob } 11617104aeefSMatt Jacob 11627104aeefSMatt Jacob /* 11637104aeefSMatt Jacob * Now enable the port 11647104aeefSMatt Jacob */ 11659b631363SMatt Jacob if (mpt_send_port_enable(mpt, 0) != MPT_OK) { 1166301472c2SMatt Jacob mpt_prt(mpt, "failed to enable port 0"); 11679b631363SMatt Jacob continue; 11687104aeefSMatt Jacob } 11697104aeefSMatt Jacob 11707104aeefSMatt Jacob if (mpt->verbose > 1) { 1171301472c2SMatt Jacob mpt_prt(mpt, "enabled port 0"); 11729b631363SMatt Jacob } 11739b631363SMatt Jacob 11749b631363SMatt Jacob /* Everything worked */ 11759b631363SMatt Jacob break; 11769b631363SMatt Jacob } 11779b631363SMatt Jacob 11789b631363SMatt Jacob if (try >= MPT_MAX_TRYS) { 1179301472c2SMatt Jacob mpt_prt(mpt, "failed to initialize IOC"); 11809b631363SMatt Jacob return (EIO); 11819b631363SMatt Jacob } 11829b631363SMatt Jacob 11839b631363SMatt Jacob if (mpt->verbose > 1) { 1184301472c2SMatt Jacob mpt_prt(mpt, "enabling interrupts"); 11859b631363SMatt Jacob } 11869b631363SMatt Jacob 11879b631363SMatt Jacob mpt_enable_ints(mpt); 11889b631363SMatt Jacob return (0); 11899b631363SMatt Jacob } 1190