19b631363SMatt Jacob /* $FreeBSD$ */ 29b631363SMatt Jacob /* 39b631363SMatt Jacob * Generic routines for LSI '909 FC adapters. 49b631363SMatt Jacob * FreeBSD Version. 59b631363SMatt Jacob * 69b631363SMatt Jacob * Copyright (c) 2000, 2001 by Greg Ansley 79b631363SMatt Jacob * 89b631363SMatt Jacob * Redistribution and use in source and binary forms, with or without 99b631363SMatt Jacob * modification, are permitted provided that the following conditions 109b631363SMatt Jacob * are met: 119b631363SMatt Jacob * 1. Redistributions of source code must retain the above copyright 129b631363SMatt Jacob * notice immediately at the beginning of the file, without modification, 139b631363SMatt Jacob * this list of conditions, and the following disclaimer. 149b631363SMatt Jacob * 2. The name of the author may not be used to endorse or promote products 159b631363SMatt Jacob * derived from this software without specific prior written permission. 169b631363SMatt Jacob * 179b631363SMatt Jacob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 189b631363SMatt Jacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 199b631363SMatt Jacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 209b631363SMatt Jacob * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 219b631363SMatt Jacob * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 229b631363SMatt Jacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 239b631363SMatt Jacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 249b631363SMatt Jacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 259b631363SMatt Jacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 269b631363SMatt Jacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 279b631363SMatt Jacob * SUCH DAMAGE. 289b631363SMatt Jacob */ 299b631363SMatt Jacob /* 309b631363SMatt Jacob * Additional Copyright (c) 2002 by Matthew Jacob under same license. 319b631363SMatt Jacob */ 329b631363SMatt Jacob 339b631363SMatt Jacob #include <dev/mpt/mpt_freebsd.h> 347104aeefSMatt Jacob 359b631363SMatt Jacob #define MPT_MAX_TRYS 3 369b631363SMatt Jacob #define MPT_MAX_WAIT 300000 379b631363SMatt Jacob 389b631363SMatt Jacob static int maxwait_ack = 0; 399b631363SMatt Jacob static int maxwait_int = 0; 409b631363SMatt Jacob static int maxwait_state = 0; 419b631363SMatt Jacob 427104aeefSMatt Jacob static __inline u_int32_t mpt_rd_db(mpt_softc_t *mpt); 437104aeefSMatt Jacob static __inline u_int32_t mpt_rd_intr(mpt_softc_t *mpt); 449b631363SMatt Jacob 459b631363SMatt Jacob static __inline u_int32_t 467104aeefSMatt Jacob mpt_rd_db(mpt_softc_t *mpt) 479b631363SMatt Jacob { 489b631363SMatt Jacob return mpt_read(mpt, MPT_OFFSET_DOORBELL); 499b631363SMatt Jacob } 509b631363SMatt Jacob 519b631363SMatt Jacob static __inline u_int32_t 527104aeefSMatt Jacob mpt_rd_intr(mpt_softc_t *mpt) 539b631363SMatt Jacob { 549b631363SMatt Jacob return mpt_read(mpt, MPT_OFFSET_INTR_STATUS); 559b631363SMatt Jacob } 569b631363SMatt Jacob 579b631363SMatt Jacob /* Busy wait for a door bell to be read by IOC */ 589b631363SMatt Jacob static int 597104aeefSMatt Jacob mpt_wait_db_ack(mpt_softc_t *mpt) 609b631363SMatt Jacob { 619b631363SMatt Jacob int i; 629b631363SMatt Jacob for (i=0; i < MPT_MAX_WAIT; i++) { 639b631363SMatt Jacob if (!MPT_DB_IS_BUSY(mpt_rd_intr(mpt))) { 649b631363SMatt Jacob maxwait_ack = i > maxwait_ack ? i : maxwait_ack; 659b631363SMatt Jacob return MPT_OK; 669b631363SMatt Jacob } 679b631363SMatt Jacob 689b631363SMatt Jacob DELAY(100); 699b631363SMatt Jacob } 709b631363SMatt Jacob return MPT_FAIL; 719b631363SMatt Jacob } 729b631363SMatt Jacob 739b631363SMatt Jacob /* Busy wait for a door bell interrupt */ 749b631363SMatt Jacob static int 757104aeefSMatt Jacob mpt_wait_db_int(mpt_softc_t *mpt) 769b631363SMatt Jacob { 779b631363SMatt Jacob int i; 789b631363SMatt Jacob for (i=0; i < MPT_MAX_WAIT; i++) { 799b631363SMatt Jacob if (MPT_DB_INTR(mpt_rd_intr(mpt))) { 809b631363SMatt Jacob maxwait_int = i > maxwait_int ? i : maxwait_int; 819b631363SMatt Jacob return MPT_OK; 829b631363SMatt Jacob } 839b631363SMatt Jacob DELAY(100); 849b631363SMatt Jacob } 859b631363SMatt Jacob return MPT_FAIL; 869b631363SMatt Jacob } 879b631363SMatt Jacob 889b631363SMatt Jacob /* Wait for IOC to transition to a give state */ 899b631363SMatt Jacob void 907104aeefSMatt Jacob mpt_check_doorbell(mpt_softc_t *mpt) 919b631363SMatt Jacob { 929b631363SMatt Jacob u_int32_t db = mpt_rd_db(mpt); 939b631363SMatt Jacob if (MPT_STATE(db) != MPT_DB_STATE_RUNNING) { 949b631363SMatt Jacob device_printf(mpt->dev, "Device not running!\n"); 959b631363SMatt Jacob mpt_print_db(db); 969b631363SMatt Jacob } 979b631363SMatt Jacob } 989b631363SMatt Jacob 999b631363SMatt Jacob /* Wait for IOC to transition to a give state */ 1009b631363SMatt Jacob static int 1017104aeefSMatt Jacob mpt_wait_state(mpt_softc_t *mpt, enum DB_STATE_BITS state) 1029b631363SMatt Jacob { 1039b631363SMatt Jacob int i; 1049b631363SMatt Jacob 1059b631363SMatt Jacob for (i = 0; i < MPT_MAX_WAIT; i++) { 1069b631363SMatt Jacob u_int32_t db = mpt_rd_db(mpt); 1079b631363SMatt Jacob if (MPT_STATE(db) == state) { 1089b631363SMatt Jacob maxwait_state = i > maxwait_state ? i : maxwait_state; 1099b631363SMatt Jacob return (MPT_OK); 1109b631363SMatt Jacob } 1119b631363SMatt Jacob DELAY(100); 1129b631363SMatt Jacob } 1139b631363SMatt Jacob return (MPT_FAIL); 1149b631363SMatt Jacob } 1159b631363SMatt Jacob 1169b631363SMatt Jacob 1179b631363SMatt Jacob /* Issue the reset COMMAND to the IOC */ 1189b631363SMatt Jacob int 1197104aeefSMatt Jacob mpt_soft_reset(mpt_softc_t *mpt) 1209b631363SMatt Jacob { 1219b631363SMatt Jacob if (mpt->verbose) { 1229b631363SMatt Jacob device_printf(mpt->dev,"soft reset\n"); 1239b631363SMatt Jacob } 1249b631363SMatt Jacob 1259b631363SMatt Jacob /* Have to use hard reset if we are not in Running state */ 1269b631363SMatt Jacob if (MPT_STATE(mpt_rd_db(mpt)) != MPT_DB_STATE_RUNNING) { 1279b631363SMatt Jacob device_printf(mpt->dev, 1289b631363SMatt Jacob "soft reset failed: device not running\n"); 1299b631363SMatt Jacob return MPT_FAIL; 1309b631363SMatt Jacob } 1319b631363SMatt Jacob 1329b631363SMatt Jacob /* If door bell is in use we don't have a chance of getting 1339b631363SMatt Jacob * a word in since the IOC probably crashed in message 1349b631363SMatt Jacob * processing. So don't waste our time. 1359b631363SMatt Jacob */ 1369b631363SMatt Jacob if (MPT_DB_IS_IN_USE(mpt_rd_db(mpt))) { 1379b631363SMatt Jacob device_printf(mpt->dev, "soft reset failed: doorbell wedged\n"); 1389b631363SMatt Jacob return MPT_FAIL; 1399b631363SMatt Jacob } 1409b631363SMatt Jacob 1419b631363SMatt Jacob /* Send the reset request to the IOC */ 1429b631363SMatt Jacob mpt_write(mpt, MPT_OFFSET_DOORBELL, 1439b631363SMatt Jacob MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET << MPI_DOORBELL_FUNCTION_SHIFT); 1449b631363SMatt Jacob if (mpt_wait_db_ack(mpt) != MPT_OK) { 1459b631363SMatt Jacob device_printf(mpt->dev, "soft reset failed: ack timeout\n"); 1469b631363SMatt Jacob return MPT_FAIL; 1479b631363SMatt Jacob } 1489b631363SMatt Jacob 1499b631363SMatt Jacob /* Wait for the IOC to reload and come out of reset state */ 1509b631363SMatt Jacob if (mpt_wait_state(mpt, MPT_DB_STATE_READY) != MPT_OK) { 1519b631363SMatt Jacob device_printf(mpt->dev, 1529b631363SMatt Jacob "soft reset failed: device did not start running\n"); 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) { 1699b631363SMatt Jacob device_printf(mpt->dev, "hard reset\n"); 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) { 2199b631363SMatt Jacob device_printf(mpt->dev, "failed to reset device\n"); 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 { 2309b631363SMatt Jacob if (req == NULL || req != &mpt->requests[req->index]) { 2319b631363SMatt Jacob panic("mpt_free_request bad req ptr\n"); 2329b631363SMatt Jacob return; 2339b631363SMatt Jacob } 2349b631363SMatt Jacob req->ccb = NULL; 2359b631363SMatt Jacob req->debug = REQ_FREE; 2369b631363SMatt Jacob SLIST_INSERT_HEAD(&mpt->request_free_list, req, link); 2379b631363SMatt Jacob } 2389b631363SMatt Jacob 2399b631363SMatt Jacob /* Get a command buffer from the free queue */ 2409b631363SMatt Jacob request_t * 2417104aeefSMatt Jacob mpt_get_request(mpt_softc_t *mpt) 2429b631363SMatt Jacob { 2439b631363SMatt Jacob request_t *req; 2449b631363SMatt Jacob req = SLIST_FIRST(&mpt->request_free_list); 2459b631363SMatt Jacob if (req != NULL) { 2469b631363SMatt Jacob if (req != &mpt->requests[req->index]) { 2479b631363SMatt Jacob panic("mpt_get_request: corrupted request free list\n"); 2489b631363SMatt Jacob } 2499b631363SMatt Jacob if (req->ccb != NULL) { 2509b631363SMatt Jacob panic("mpt_get_request: corrupted request free list (ccb)\n"); 2519b631363SMatt Jacob } 2529b631363SMatt Jacob SLIST_REMOVE_HEAD(&mpt->request_free_list, link); 2539b631363SMatt Jacob req->debug = REQ_IN_PROGRESS; 2549b631363SMatt Jacob } 2559b631363SMatt Jacob return req; 2569b631363SMatt Jacob } 2579b631363SMatt Jacob 2589b631363SMatt Jacob /* Pass the command to the IOC */ 2599b631363SMatt Jacob void 2607104aeefSMatt Jacob mpt_send_cmd(mpt_softc_t *mpt, request_t *req) 2619b631363SMatt Jacob { 2629b631363SMatt Jacob req->sequence = mpt->sequence++; 2639b631363SMatt Jacob if (mpt->verbose > 1) { 2649b631363SMatt Jacob u_int32_t *pReq; 2659b631363SMatt Jacob pReq = req->req_vbuf; 26690f62fd2SMatt Jacob device_printf(mpt->dev, "Send Request %d (0x%lx):\n", 26790f62fd2SMatt Jacob req->index, (long) req->req_pbuf); 2689b631363SMatt Jacob device_printf(mpt->dev, "%08X %08X %08X %08X\n", 2699b631363SMatt Jacob pReq[0], pReq[1], pReq[2], pReq[3]); 2709b631363SMatt Jacob device_printf(mpt->dev, "%08X %08X %08X %08X\n", 2719b631363SMatt Jacob pReq[4], pReq[5], pReq[6], pReq[7]); 2729b631363SMatt Jacob device_printf(mpt->dev, "%08X %08X %08X %08X\n", 2739b631363SMatt Jacob pReq[8], pReq[9], pReq[10], pReq[11]); 2749b631363SMatt Jacob device_printf(mpt->dev, "%08X %08X %08X %08X\n", 2759b631363SMatt Jacob pReq[12], pReq[13], pReq[14], pReq[15]); 2769b631363SMatt Jacob } 2779b631363SMatt Jacob bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap, 2789b631363SMatt Jacob BUS_DMASYNC_PREWRITE); 2799b631363SMatt Jacob req->debug = REQ_ON_CHIP; 2809b631363SMatt Jacob mpt_write(mpt, MPT_OFFSET_REQUEST_Q, (u_int32_t) req->req_pbuf); 2819b631363SMatt Jacob } 2829b631363SMatt Jacob 2839b631363SMatt Jacob /* 2849b631363SMatt Jacob * Give the reply buffer back to the IOC after we have 2859b631363SMatt Jacob * finished processing it. 2869b631363SMatt Jacob */ 2879b631363SMatt Jacob void 2887104aeefSMatt Jacob mpt_free_reply(mpt_softc_t *mpt, u_int32_t ptr) 2899b631363SMatt Jacob { 2909b631363SMatt Jacob mpt_write(mpt, MPT_OFFSET_REPLY_Q, ptr); 2919b631363SMatt Jacob } 2929b631363SMatt Jacob 2939b631363SMatt Jacob /* Get a reply from the IOC */ 2949b631363SMatt Jacob u_int32_t 2957104aeefSMatt Jacob mpt_pop_reply_queue(mpt_softc_t *mpt) 2969b631363SMatt Jacob { 2979b631363SMatt Jacob return mpt_read(mpt, MPT_OFFSET_REPLY_Q); 2989b631363SMatt Jacob } 2999b631363SMatt Jacob 3009b631363SMatt Jacob /* 3019b631363SMatt Jacob * Send a command to the IOC via the handshake register. 3029b631363SMatt Jacob * 3039b631363SMatt Jacob * Only done at initialization time and for certain unusual 3049b631363SMatt Jacob * commands such as device/bus reset as specified by LSI. 3059b631363SMatt Jacob */ 3069b631363SMatt Jacob int 3077104aeefSMatt Jacob mpt_send_handshake_cmd(mpt_softc_t *mpt, size_t len, void *cmd) 3089b631363SMatt Jacob { 3099b631363SMatt Jacob int i; 3109b631363SMatt Jacob u_int32_t data, *data32; 3119b631363SMatt Jacob 3129b631363SMatt Jacob /* Check condition of the IOC */ 3139b631363SMatt Jacob data = mpt_rd_db(mpt); 3149b631363SMatt Jacob if (((MPT_STATE(data) != MPT_DB_STATE_READY) && 3159b631363SMatt Jacob (MPT_STATE(data) != MPT_DB_STATE_RUNNING) && 3169b631363SMatt Jacob (MPT_STATE(data) != MPT_DB_STATE_FAULT)) || 3179b631363SMatt Jacob ( MPT_DB_IS_IN_USE(data) )) { 3189b631363SMatt Jacob device_printf(mpt->dev, 3199b631363SMatt Jacob "handshake aborted due to invalid doorbell state\n"); 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) { 3429b631363SMatt Jacob device_printf(mpt->dev, "mpt_send_handshake_cmd timeout1!\n"); 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) { 3509b631363SMatt Jacob device_printf(mpt->dev, "mpt_send_handshake_cmd timeout2!\n"); 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) { 3589b631363SMatt Jacob device_printf(mpt->dev, 3599b631363SMatt Jacob "mpt_send_handshake_cmd timeout! index = %d\n", 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) { 3829b631363SMatt Jacob device_printf(mpt->dev, "mpt_recv_handshake_cmd timeout1!\n"); 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) { 3909b631363SMatt Jacob device_printf(mpt->dev, "mpt_recv_handshake_cmd timeout2!\n"); 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)) { 3989b631363SMatt Jacob device_printf(mpt->dev, 3999b631363SMatt Jacob "reply length does not match message length: " 40090f62fd2SMatt Jacob "got 0x%02x, expected 0x%02lx\n", 40190f62fd2SMatt Jacob hdr->MsgLength << 2, (long) (reply_len << 1)); 4029b631363SMatt Jacob } 4039b631363SMatt Jacob 4049b631363SMatt Jacob /* Get rest of the reply; but don't overflow the provided buffer */ 4059b631363SMatt Jacob left = (hdr->MsgLength << 1) - 2; 4069b631363SMatt Jacob reply_left = reply_len - 2; 4079b631363SMatt Jacob while (left--) { 4089b631363SMatt Jacob u_int16_t datum; 4099b631363SMatt Jacob 4109b631363SMatt Jacob if (mpt_wait_db_int(mpt) != MPT_OK) { 4119b631363SMatt Jacob device_printf(mpt->dev, 4129b631363SMatt Jacob "mpt_recv_handshake_cmd timeout3!\n"); 4139b631363SMatt Jacob return ETIMEDOUT; 4149b631363SMatt Jacob } 4159b631363SMatt Jacob datum = mpt_read(mpt, MPT_OFFSET_DOORBELL); 4169b631363SMatt Jacob 4179b631363SMatt Jacob if (reply_left-- > 0) 4189b631363SMatt Jacob *data16++ = datum & MPT_DB_DATA_MASK; 4199b631363SMatt Jacob 4209b631363SMatt Jacob mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 4219b631363SMatt Jacob } 4229b631363SMatt Jacob 4239b631363SMatt Jacob /* One more wait & clear at the end */ 4249b631363SMatt Jacob if (mpt_wait_db_int(mpt) != MPT_OK) { 4259b631363SMatt Jacob device_printf(mpt->dev, "mpt_recv_handshake_cmd timeout4!\n"); 4269b631363SMatt Jacob return ETIMEDOUT; 4279b631363SMatt Jacob } 4289b631363SMatt Jacob mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 4299b631363SMatt Jacob 4309b631363SMatt Jacob if ((hdr->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 4319b631363SMatt Jacob if (mpt->verbose > 1) 4329b631363SMatt Jacob mpt_print_reply(hdr); 4339b631363SMatt Jacob return (MPT_FAIL | hdr->IOCStatus); 4349b631363SMatt Jacob } 4359b631363SMatt Jacob 4369b631363SMatt Jacob return (0); 4379b631363SMatt Jacob } 4389b631363SMatt Jacob 4399b631363SMatt Jacob static int 4407104aeefSMatt Jacob mpt_get_iocfacts(mpt_softc_t *mpt, MSG_IOC_FACTS_REPLY *freplp) 4419b631363SMatt Jacob { 4429b631363SMatt Jacob MSG_IOC_FACTS f_req; 4439b631363SMatt Jacob int error; 4449b631363SMatt Jacob 4459b631363SMatt Jacob bzero(&f_req, sizeof f_req); 4469b631363SMatt Jacob f_req.Function = MPI_FUNCTION_IOC_FACTS; 4479b631363SMatt Jacob f_req.MsgContext = 0x12071942; 4489b631363SMatt Jacob error = mpt_send_handshake_cmd(mpt, sizeof f_req, &f_req); 4499b631363SMatt Jacob if (error) 4509b631363SMatt Jacob return(error); 4519b631363SMatt Jacob error = mpt_recv_handshake_reply(mpt, sizeof (*freplp), freplp); 4529b631363SMatt Jacob return (error); 4539b631363SMatt Jacob } 4549b631363SMatt Jacob 4557104aeefSMatt Jacob static int 4567104aeefSMatt Jacob mpt_get_portfacts(mpt_softc_t *mpt, MSG_PORT_FACTS_REPLY *freplp) 4577104aeefSMatt Jacob { 4587104aeefSMatt Jacob MSG_PORT_FACTS f_req; 4597104aeefSMatt Jacob int error; 4607104aeefSMatt Jacob 4617104aeefSMatt Jacob /* XXX: Only getting PORT FACTS for Port 0 */ 4627104aeefSMatt Jacob bzero(&f_req, sizeof f_req); 4637104aeefSMatt Jacob f_req.Function = MPI_FUNCTION_PORT_FACTS; 4647104aeefSMatt Jacob f_req.MsgContext = 0x12071943; 4657104aeefSMatt Jacob error = mpt_send_handshake_cmd(mpt, sizeof f_req, &f_req); 4667104aeefSMatt Jacob if (error) 4677104aeefSMatt Jacob return(error); 4687104aeefSMatt Jacob error = mpt_recv_handshake_reply(mpt, sizeof (*freplp), freplp); 4697104aeefSMatt Jacob return (error); 4707104aeefSMatt Jacob } 4717104aeefSMatt Jacob 4729b631363SMatt Jacob /* 4739b631363SMatt Jacob * Send the initialization request. This is where we specify how many 4749b631363SMatt Jacob * SCSI busses and how many devices per bus we wish to emulate. 4759b631363SMatt Jacob * This is also the command that specifies the max size of the reply 4769b631363SMatt Jacob * frames from the IOC that we will be allocating. 4779b631363SMatt Jacob */ 4789b631363SMatt Jacob static int 4797104aeefSMatt Jacob mpt_send_ioc_init(mpt_softc_t *mpt, u_int32_t who) 4809b631363SMatt Jacob { 4819b631363SMatt Jacob int error = 0; 4829b631363SMatt Jacob MSG_IOC_INIT init; 4839b631363SMatt Jacob MSG_IOC_INIT_REPLY reply; 4849b631363SMatt Jacob 4859b631363SMatt Jacob bzero(&init, sizeof init); 4869b631363SMatt Jacob init.WhoInit = who; 4879b631363SMatt Jacob init.Function = MPI_FUNCTION_IOC_INIT; 4889b631363SMatt Jacob if (mpt->is_fc) { 4899b631363SMatt Jacob init.MaxDevices = 255; 4909b631363SMatt Jacob } else { 4919b631363SMatt Jacob init.MaxDevices = 16; 4929b631363SMatt Jacob } 4939b631363SMatt Jacob init.MaxBuses = 1; 4949b631363SMatt Jacob init.ReplyFrameSize = MPT_REPLY_SIZE; 4959b631363SMatt Jacob init.MsgContext = 0x12071941; 4969b631363SMatt Jacob 4979b631363SMatt Jacob if ((error = mpt_send_handshake_cmd(mpt, sizeof init, &init)) != 0) { 4989b631363SMatt Jacob return(error); 4999b631363SMatt Jacob } 5009b631363SMatt Jacob 5019b631363SMatt Jacob error = mpt_recv_handshake_reply(mpt, sizeof reply, &reply); 5029b631363SMatt Jacob return (error); 5039b631363SMatt Jacob } 5049b631363SMatt Jacob 5057104aeefSMatt Jacob 5067104aeefSMatt Jacob /* 5077104aeefSMatt Jacob * Utiltity routine to read configuration headers and pages 5087104aeefSMatt Jacob */ 5097104aeefSMatt Jacob 5109b631363SMatt Jacob static int 5117104aeefSMatt Jacob mpt_read_cfg_header(mpt_softc_t *, int, int, int, fCONFIG_PAGE_HEADER *); 5127104aeefSMatt Jacob 5137104aeefSMatt Jacob static int 5147104aeefSMatt Jacob mpt_read_cfg_header(mpt_softc_t *mpt, int PageType, int PageNumber, 5157104aeefSMatt Jacob int PageAddress, fCONFIG_PAGE_HEADER *rslt) 5167104aeefSMatt Jacob { 5177104aeefSMatt Jacob int count; 5187104aeefSMatt Jacob request_t *req; 5197104aeefSMatt Jacob MSG_CONFIG *cfgp; 5207104aeefSMatt Jacob MSG_CONFIG_REPLY *reply; 5217104aeefSMatt Jacob 5227104aeefSMatt Jacob req = mpt_get_request(mpt); 5237104aeefSMatt Jacob 5247104aeefSMatt Jacob cfgp = req->req_vbuf; 5257104aeefSMatt Jacob bzero(cfgp, sizeof *cfgp); 5267104aeefSMatt Jacob 5277104aeefSMatt Jacob cfgp->Action = MPI_CONFIG_ACTION_PAGE_HEADER; 5287104aeefSMatt Jacob cfgp->Function = MPI_FUNCTION_CONFIG; 5297104aeefSMatt Jacob cfgp->Header.PageNumber = (U8) PageNumber; 5307104aeefSMatt Jacob cfgp->Header.PageType = (U8) PageType; 5317104aeefSMatt Jacob cfgp->PageAddress = PageAddress; 5327104aeefSMatt Jacob MPI_pSGE_SET_FLAGS(((SGE_SIMPLE32 *) &cfgp->PageBufferSGE), 5337104aeefSMatt Jacob (MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | 5347104aeefSMatt Jacob MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_LIST)); 5357104aeefSMatt Jacob cfgp->MsgContext = req->index | 0x80000000; 5367104aeefSMatt Jacob 5377104aeefSMatt Jacob mpt_check_doorbell(mpt); 5387104aeefSMatt Jacob mpt_send_cmd(mpt, req); 5397104aeefSMatt Jacob count = 0; 5407104aeefSMatt Jacob do { 5417104aeefSMatt Jacob DELAY(500); 5427104aeefSMatt Jacob mpt_intr(mpt); 5437104aeefSMatt Jacob if (++count == 1000) { 5447104aeefSMatt Jacob device_printf(mpt->dev, "read_cfg_header timed out\n"); 5457104aeefSMatt Jacob return (-1); 5467104aeefSMatt Jacob } 5477104aeefSMatt Jacob } while (req->debug == REQ_ON_CHIP); 5487104aeefSMatt Jacob 5497104aeefSMatt Jacob reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence); 5507104aeefSMatt Jacob if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 5517104aeefSMatt Jacob device_printf(mpt->dev, 5527104aeefSMatt Jacob "mpt_read_cfg_header: Config Info Status %x\n", 5537104aeefSMatt Jacob reply->IOCStatus); 5547104aeefSMatt Jacob return (-1); 5557104aeefSMatt Jacob } 5567104aeefSMatt Jacob bcopy(&reply->Header, rslt, sizeof (fCONFIG_PAGE_HEADER)); 5577104aeefSMatt Jacob mpt_free_reply(mpt, (req->sequence << 1)); 5587104aeefSMatt Jacob mpt_free_request(mpt, req); 5597104aeefSMatt Jacob return (0); 5607104aeefSMatt Jacob } 5617104aeefSMatt Jacob 5627104aeefSMatt Jacob #define CFG_DATA_OFF 40 5637104aeefSMatt Jacob 564ce68dae5SMatt Jacob int 5657104aeefSMatt Jacob mpt_read_cfg_page(mpt_softc_t *mpt, int PageAddress, fCONFIG_PAGE_HEADER *hdr) 5667104aeefSMatt Jacob { 5677104aeefSMatt Jacob int count; 5687104aeefSMatt Jacob request_t *req; 5697104aeefSMatt Jacob SGE_SIMPLE32 *se; 5707104aeefSMatt Jacob MSG_CONFIG *cfgp; 5717104aeefSMatt Jacob size_t amt; 5727104aeefSMatt Jacob MSG_CONFIG_REPLY *reply; 5737104aeefSMatt Jacob 5747104aeefSMatt Jacob req = mpt_get_request(mpt); 5757104aeefSMatt Jacob 5767104aeefSMatt Jacob cfgp = req->req_vbuf; 5777104aeefSMatt Jacob amt = (cfgp->Header.PageLength * sizeof (uint32_t)); 5787104aeefSMatt Jacob bzero(cfgp, sizeof *cfgp); 5797104aeefSMatt Jacob cfgp->Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 5807104aeefSMatt Jacob cfgp->Function = MPI_FUNCTION_CONFIG; 5817104aeefSMatt Jacob cfgp->Header = *hdr; 5827104aeefSMatt Jacob cfgp->Header.PageType &= MPI_CONFIG_PAGETYPE_MASK; 5837104aeefSMatt Jacob cfgp->PageAddress = PageAddress; 5847104aeefSMatt Jacob se = (SGE_SIMPLE32 *) &cfgp->PageBufferSGE; 5857104aeefSMatt Jacob se->Address = req->req_pbuf + CFG_DATA_OFF; 5867104aeefSMatt Jacob MPI_pSGE_SET_LENGTH(se, amt); 5877104aeefSMatt Jacob MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT | 5887104aeefSMatt Jacob MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | 5897104aeefSMatt Jacob MPI_SGE_FLAGS_END_OF_LIST)); 5907104aeefSMatt Jacob 5917104aeefSMatt Jacob cfgp->MsgContext = req->index | 0x80000000; 5927104aeefSMatt Jacob 5937104aeefSMatt Jacob mpt_check_doorbell(mpt); 5947104aeefSMatt Jacob mpt_send_cmd(mpt, req); 5957104aeefSMatt Jacob count = 0; 5967104aeefSMatt Jacob do { 5977104aeefSMatt Jacob DELAY(500); 5987104aeefSMatt Jacob mpt_intr(mpt); 5997104aeefSMatt Jacob if (++count == 1000) { 6007104aeefSMatt Jacob device_printf(mpt->dev, "read_cfg_page timed out\n"); 6017104aeefSMatt Jacob return (-1); 6027104aeefSMatt Jacob } 6037104aeefSMatt Jacob } while (req->debug == REQ_ON_CHIP); 6047104aeefSMatt Jacob 6057104aeefSMatt Jacob reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence); 6067104aeefSMatt Jacob if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 6077104aeefSMatt Jacob device_printf(mpt->dev, 6087104aeefSMatt Jacob "mpt_read_cfg_page: Config Info Status %x\n", 6097104aeefSMatt Jacob reply->IOCStatus); 6107104aeefSMatt Jacob return (-1); 6117104aeefSMatt Jacob } 6127104aeefSMatt Jacob mpt_free_reply(mpt, (req->sequence << 1)); 6137104aeefSMatt Jacob bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap, 6147104aeefSMatt Jacob BUS_DMASYNC_POSTREAD); 6157104aeefSMatt Jacob if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 6167104aeefSMatt Jacob cfgp->Header.PageNumber == 0) { 6177104aeefSMatt Jacob amt = sizeof (fCONFIG_PAGE_SCSI_PORT_0); 6187104aeefSMatt Jacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 6197104aeefSMatt Jacob cfgp->Header.PageNumber == 1) { 6207104aeefSMatt Jacob amt = sizeof (fCONFIG_PAGE_SCSI_PORT_1); 6217104aeefSMatt Jacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 6227104aeefSMatt Jacob cfgp->Header.PageNumber == 2) { 6237104aeefSMatt Jacob amt = sizeof (fCONFIG_PAGE_SCSI_PORT_2); 6247104aeefSMatt Jacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE && 6257104aeefSMatt Jacob cfgp->Header.PageNumber == 0) { 6267104aeefSMatt Jacob amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_0); 6277104aeefSMatt Jacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE && 6287104aeefSMatt Jacob cfgp->Header.PageNumber == 1) { 6297104aeefSMatt Jacob amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_1); 6307104aeefSMatt Jacob } 6317104aeefSMatt Jacob bcopy(((caddr_t)req->req_vbuf)+CFG_DATA_OFF, hdr, amt); 6327104aeefSMatt Jacob mpt_free_request(mpt, req); 6337104aeefSMatt Jacob return (0); 6347104aeefSMatt Jacob } 6357104aeefSMatt Jacob 636ce68dae5SMatt Jacob int 6377104aeefSMatt Jacob mpt_write_cfg_page(mpt_softc_t *mpt, int PageAddress, fCONFIG_PAGE_HEADER *hdr) 6387104aeefSMatt Jacob { 6397104aeefSMatt Jacob int count, hdr_attr; 6407104aeefSMatt Jacob request_t *req; 6417104aeefSMatt Jacob SGE_SIMPLE32 *se; 6427104aeefSMatt Jacob MSG_CONFIG *cfgp; 6437104aeefSMatt Jacob size_t amt; 6447104aeefSMatt Jacob MSG_CONFIG_REPLY *reply; 6457104aeefSMatt Jacob 6467104aeefSMatt Jacob req = mpt_get_request(mpt); 6477104aeefSMatt Jacob 6487104aeefSMatt Jacob cfgp = req->req_vbuf; 6497104aeefSMatt Jacob bzero(cfgp, sizeof *cfgp); 6507104aeefSMatt Jacob 6517104aeefSMatt Jacob hdr_attr = hdr->PageType & MPI_CONFIG_PAGEATTR_MASK; 6527104aeefSMatt Jacob if (hdr_attr != MPI_CONFIG_PAGEATTR_CHANGEABLE && 6537104aeefSMatt Jacob hdr_attr != MPI_CONFIG_PAGEATTR_PERSISTENT) { 6547104aeefSMatt Jacob device_printf(mpt->dev, "page type 0x%x not changeable\n", 6557104aeefSMatt Jacob hdr->PageType & MPI_CONFIG_PAGETYPE_MASK); 6567104aeefSMatt Jacob return (-1); 6577104aeefSMatt Jacob } 6587104aeefSMatt Jacob hdr->PageType &= MPI_CONFIG_PAGETYPE_MASK; 6597104aeefSMatt Jacob 6607104aeefSMatt Jacob amt = (cfgp->Header.PageLength * sizeof (uint32_t)); 6617104aeefSMatt Jacob cfgp->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; 6627104aeefSMatt Jacob cfgp->Function = MPI_FUNCTION_CONFIG; 6637104aeefSMatt Jacob cfgp->Header = *hdr; 6647104aeefSMatt Jacob cfgp->PageAddress = PageAddress; 6657104aeefSMatt Jacob 6667104aeefSMatt Jacob se = (SGE_SIMPLE32 *) &cfgp->PageBufferSGE; 6677104aeefSMatt Jacob se->Address = req->req_pbuf + CFG_DATA_OFF; 6687104aeefSMatt Jacob MPI_pSGE_SET_LENGTH(se, amt); 6697104aeefSMatt Jacob MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT | 6707104aeefSMatt Jacob MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | 6717104aeefSMatt Jacob MPI_SGE_FLAGS_END_OF_LIST | MPI_SGE_FLAGS_HOST_TO_IOC)); 6727104aeefSMatt Jacob 6737104aeefSMatt Jacob cfgp->MsgContext = req->index | 0x80000000; 6747104aeefSMatt Jacob 6757104aeefSMatt Jacob if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 6767104aeefSMatt Jacob cfgp->Header.PageNumber == 0) { 6777104aeefSMatt Jacob amt = sizeof (fCONFIG_PAGE_SCSI_PORT_0); 6787104aeefSMatt Jacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 6797104aeefSMatt Jacob cfgp->Header.PageNumber == 1) { 6807104aeefSMatt Jacob amt = sizeof (fCONFIG_PAGE_SCSI_PORT_1); 6817104aeefSMatt Jacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 6827104aeefSMatt Jacob cfgp->Header.PageNumber == 2) { 6837104aeefSMatt Jacob amt = sizeof (fCONFIG_PAGE_SCSI_PORT_2); 6847104aeefSMatt Jacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE && 6857104aeefSMatt Jacob cfgp->Header.PageNumber == 0) { 6867104aeefSMatt Jacob amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_0); 6877104aeefSMatt Jacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE && 6887104aeefSMatt Jacob cfgp->Header.PageNumber == 1) { 6897104aeefSMatt Jacob amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_1); 6907104aeefSMatt Jacob } 6917104aeefSMatt Jacob bcopy(hdr, ((caddr_t)req->req_vbuf)+CFG_DATA_OFF, amt); 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; 7017104aeefSMatt Jacob device_printf(mpt->dev, 7027104aeefSMatt Jacob "mpt_write_cfg_page timed out\n"); 7037104aeefSMatt Jacob return (-1); 7047104aeefSMatt Jacob } 7057104aeefSMatt Jacob } while (req->debug == REQ_ON_CHIP); 7067104aeefSMatt Jacob 7077104aeefSMatt Jacob reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence); 7087104aeefSMatt Jacob if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 7097104aeefSMatt Jacob device_printf(mpt->dev, 7107104aeefSMatt Jacob "mpt_write_cfg_page: Config Info Status %x\n", 7117104aeefSMatt Jacob reply->IOCStatus); 7127104aeefSMatt Jacob return (-1); 7137104aeefSMatt Jacob } 7147104aeefSMatt Jacob mpt_free_reply(mpt, (req->sequence << 1)); 7157104aeefSMatt Jacob 7167104aeefSMatt Jacob /* 7177104aeefSMatt Jacob * Restore stripped out attributes 7187104aeefSMatt Jacob */ 7197104aeefSMatt Jacob hdr->PageType |= hdr_attr; 7207104aeefSMatt Jacob mpt_free_request(mpt, req); 7217104aeefSMatt Jacob return (0); 7227104aeefSMatt Jacob } 7237104aeefSMatt Jacob 7247104aeefSMatt Jacob /* 7257104aeefSMatt Jacob * Read SCSI configuration information 7267104aeefSMatt Jacob */ 7277104aeefSMatt Jacob static int 7287104aeefSMatt Jacob mpt_read_config_info_spi(mpt_softc_t *mpt) 7297104aeefSMatt Jacob { 7307104aeefSMatt Jacob int rv, i; 7317104aeefSMatt Jacob 7327104aeefSMatt Jacob rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 0, 7337104aeefSMatt Jacob 0, &mpt->mpt_port_page0.Header); 7347104aeefSMatt Jacob if (rv) { 7357104aeefSMatt Jacob return (-1); 7367104aeefSMatt Jacob } 7377104aeefSMatt Jacob if (mpt->verbose > 1) { 7387104aeefSMatt Jacob device_printf(mpt->dev, "SPI Port Page 0 Header: %x %x %x %x\n", 7397104aeefSMatt Jacob mpt->mpt_port_page0.Header.PageVersion, 7407104aeefSMatt Jacob mpt->mpt_port_page0.Header.PageLength, 7417104aeefSMatt Jacob mpt->mpt_port_page0.Header.PageNumber, 7427104aeefSMatt Jacob mpt->mpt_port_page0.Header.PageType); 7437104aeefSMatt Jacob } 7447104aeefSMatt Jacob 7457104aeefSMatt Jacob rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 1, 7467104aeefSMatt Jacob 0, &mpt->mpt_port_page1.Header); 7477104aeefSMatt Jacob if (rv) { 7487104aeefSMatt Jacob return (-1); 7497104aeefSMatt Jacob } 7507104aeefSMatt Jacob if (mpt->verbose > 1) { 7517104aeefSMatt Jacob device_printf(mpt->dev, "SPI Port Page 1 Header: %x %x %x %x\n", 7527104aeefSMatt Jacob mpt->mpt_port_page1.Header.PageVersion, 7537104aeefSMatt Jacob mpt->mpt_port_page1.Header.PageLength, 7547104aeefSMatt Jacob mpt->mpt_port_page1.Header.PageNumber, 7557104aeefSMatt Jacob mpt->mpt_port_page1.Header.PageType); 7567104aeefSMatt Jacob } 7577104aeefSMatt Jacob 7587104aeefSMatt Jacob rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 2, 7597104aeefSMatt Jacob 0, &mpt->mpt_port_page2.Header); 7607104aeefSMatt Jacob if (rv) { 7617104aeefSMatt Jacob return (-1); 7627104aeefSMatt Jacob } 7637104aeefSMatt Jacob 7647104aeefSMatt Jacob if (mpt->verbose > 1) { 7657104aeefSMatt Jacob device_printf(mpt->dev, "SPI Port Page 2 Header: %x %x %x %x\n", 7667104aeefSMatt Jacob mpt->mpt_port_page1.Header.PageVersion, 7677104aeefSMatt Jacob mpt->mpt_port_page1.Header.PageLength, 7687104aeefSMatt Jacob mpt->mpt_port_page1.Header.PageNumber, 7697104aeefSMatt Jacob mpt->mpt_port_page1.Header.PageType); 7707104aeefSMatt Jacob } 7717104aeefSMatt Jacob 7727104aeefSMatt Jacob for (i = 0; i < 16; i++) { 7737104aeefSMatt Jacob rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE, 7747104aeefSMatt Jacob 0, i, &mpt->mpt_dev_page0[i].Header); 7757104aeefSMatt Jacob if (rv) { 7767104aeefSMatt Jacob return (-1); 7777104aeefSMatt Jacob } 7787104aeefSMatt Jacob if (mpt->verbose > 1) { 7797104aeefSMatt Jacob device_printf(mpt->dev, 7807104aeefSMatt Jacob "SPI Target %d Device Page 0 Header: %x %x %x %x\n", 7817104aeefSMatt Jacob i, mpt->mpt_dev_page0[i].Header.PageVersion, 7827104aeefSMatt Jacob mpt->mpt_dev_page0[i].Header.PageLength, 7837104aeefSMatt Jacob mpt->mpt_dev_page0[i].Header.PageNumber, 7847104aeefSMatt Jacob mpt->mpt_dev_page0[i].Header.PageType); 7857104aeefSMatt Jacob } 7867104aeefSMatt Jacob 7877104aeefSMatt Jacob rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE, 7887104aeefSMatt Jacob 1, i, &mpt->mpt_dev_page1[i].Header); 7897104aeefSMatt Jacob if (rv) { 7907104aeefSMatt Jacob return (-1); 7917104aeefSMatt Jacob } 7927104aeefSMatt Jacob if (mpt->verbose > 1) { 7937104aeefSMatt Jacob device_printf(mpt->dev, 7947104aeefSMatt Jacob "SPI Target %d Device Page 1 Header: %x %x %x %x\n", 7957104aeefSMatt Jacob i, mpt->mpt_dev_page1[i].Header.PageVersion, 7967104aeefSMatt Jacob mpt->mpt_dev_page1[i].Header.PageLength, 7977104aeefSMatt Jacob mpt->mpt_dev_page1[i].Header.PageNumber, 7987104aeefSMatt Jacob mpt->mpt_dev_page1[i].Header.PageType); 7997104aeefSMatt Jacob } 8007104aeefSMatt Jacob } 8017104aeefSMatt Jacob 8027104aeefSMatt Jacob /* 8037104aeefSMatt Jacob * At this point, we don't *have* to fail. As long as we have 8047104aeefSMatt Jacob * valid config header information, we can (barely) lurch 8057104aeefSMatt Jacob * along. 8067104aeefSMatt Jacob */ 8077104aeefSMatt Jacob 8087104aeefSMatt Jacob rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page0.Header); 8097104aeefSMatt Jacob if (rv) { 8107104aeefSMatt Jacob device_printf(mpt->dev, "failed to read SPI Port Page 0\n"); 8117104aeefSMatt Jacob } else if (mpt->verbose > 1) { 8127104aeefSMatt Jacob device_printf(mpt->dev, 8137104aeefSMatt Jacob "SPI Port Page 0: Capabilities %x PhysicalInterface %x\n", 8147104aeefSMatt Jacob mpt->mpt_port_page0.Capabilities, 8157104aeefSMatt Jacob mpt->mpt_port_page0.PhysicalInterface); 8167104aeefSMatt Jacob } 8177104aeefSMatt Jacob 8187104aeefSMatt Jacob rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page1.Header); 8197104aeefSMatt Jacob if (rv) { 8207104aeefSMatt Jacob device_printf(mpt->dev, "failed to read SPI Port Page 1\n"); 8217104aeefSMatt Jacob } else if (mpt->verbose > 1) { 8227104aeefSMatt Jacob device_printf(mpt->dev, 8237104aeefSMatt Jacob "SPI Port Page 1: Configuration %x OnBusTimerValue %x\n", 8247104aeefSMatt Jacob mpt->mpt_port_page1.Configuration, 8257104aeefSMatt Jacob mpt->mpt_port_page1.OnBusTimerValue); 8267104aeefSMatt Jacob } 8277104aeefSMatt Jacob 8287104aeefSMatt Jacob rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page2.Header); 8297104aeefSMatt Jacob if (rv) { 8307104aeefSMatt Jacob device_printf(mpt->dev, "failed to read SPI Port Page 2\n"); 8317104aeefSMatt Jacob } else if (mpt->verbose > 1) { 8327104aeefSMatt Jacob device_printf(mpt->dev, 8337104aeefSMatt Jacob "SPI Port Page 2: Flags %x Settings %x\n", 8347104aeefSMatt Jacob mpt->mpt_port_page2.PortFlags, 8357104aeefSMatt Jacob mpt->mpt_port_page2.PortSettings); 8367104aeefSMatt Jacob for (i = 0; i < 16; i++) { 8377104aeefSMatt Jacob device_printf(mpt->dev, 8387104aeefSMatt Jacob "SPI Port Page 2 Tgt %d: timo %x SF %x Flags %x\n", 8397104aeefSMatt Jacob i, mpt->mpt_port_page2.DeviceSettings[i].Timeout, 8407104aeefSMatt Jacob mpt->mpt_port_page2.DeviceSettings[i].SyncFactor, 8417104aeefSMatt Jacob mpt->mpt_port_page2.DeviceSettings[i].DeviceFlags); 8427104aeefSMatt Jacob } 8437104aeefSMatt Jacob } 8447104aeefSMatt Jacob 8457104aeefSMatt Jacob for (i = 0; i < 16; i++) { 8467104aeefSMatt Jacob rv = mpt_read_cfg_page(mpt, i, &mpt->mpt_dev_page0[i].Header); 8477104aeefSMatt Jacob if (rv) { 8487104aeefSMatt Jacob device_printf(mpt->dev, 8497104aeefSMatt Jacob "cannot read SPI Tgt %d Device Page 0\n", i); 8507104aeefSMatt Jacob continue; 8517104aeefSMatt Jacob } 8527104aeefSMatt Jacob if (mpt->verbose > 1) { 8537104aeefSMatt Jacob device_printf(mpt->dev, 8547104aeefSMatt Jacob "SPI Tgt %d Page 0: NParms %x Information %x\n", 8557104aeefSMatt Jacob i, mpt->mpt_dev_page0[i].NegotiatedParameters, 8567104aeefSMatt Jacob mpt->mpt_dev_page0[i].Information); 8577104aeefSMatt Jacob } 8587104aeefSMatt Jacob rv = mpt_read_cfg_page(mpt, i, &mpt->mpt_dev_page1[i].Header); 8597104aeefSMatt Jacob if (rv) { 8607104aeefSMatt Jacob device_printf(mpt->dev, 8617104aeefSMatt Jacob "cannot read SPI Tgt %d Device Page 1\n", i); 8627104aeefSMatt Jacob continue; 8637104aeefSMatt Jacob } 8647104aeefSMatt Jacob if (mpt->verbose > 1) { 8657104aeefSMatt Jacob device_printf(mpt->dev, 8667104aeefSMatt Jacob "SPI Tgt %d Page 1: RParms %x Configuration %x\n", 8677104aeefSMatt Jacob i, mpt->mpt_dev_page1[i].RequestedParameters, 8687104aeefSMatt Jacob mpt->mpt_dev_page1[i].Configuration); 8697104aeefSMatt Jacob } 8707104aeefSMatt Jacob } 8717104aeefSMatt Jacob return (0); 8727104aeefSMatt Jacob } 8737104aeefSMatt Jacob 8747104aeefSMatt Jacob /* 8757104aeefSMatt Jacob * Validate SPI configuration information. 8767104aeefSMatt Jacob * 8777104aeefSMatt Jacob * In particular, validate SPI Port Page 1. 8787104aeefSMatt Jacob */ 8797104aeefSMatt Jacob static int 8807104aeefSMatt Jacob mpt_set_initial_config_spi(mpt_softc_t *mpt) 8817104aeefSMatt Jacob { 8827104aeefSMatt Jacob int i, pp1val = ((1 << mpt->mpt_ini_id) << 16) | mpt->mpt_ini_id; 8837104aeefSMatt Jacob 884ce68dae5SMatt Jacob mpt->mpt_disc_enable = 0xff; 885ce68dae5SMatt Jacob mpt->mpt_tag_enable = 0; 886ce68dae5SMatt Jacob 8877104aeefSMatt Jacob if (mpt->mpt_port_page1.Configuration != pp1val) { 8887104aeefSMatt Jacob fCONFIG_PAGE_SCSI_PORT_1 tmp; 8897104aeefSMatt Jacob device_printf(mpt->dev, 8907104aeefSMatt Jacob "SPI Port Page 1 Config value bad (%x)- should be %x\n", 8917104aeefSMatt Jacob mpt->mpt_port_page1.Configuration, pp1val); 8927104aeefSMatt Jacob tmp = mpt->mpt_port_page1; 8937104aeefSMatt Jacob tmp.Configuration = pp1val; 8947104aeefSMatt Jacob if (mpt_write_cfg_page(mpt, 0, &tmp.Header)) { 8957104aeefSMatt Jacob return (-1); 8967104aeefSMatt Jacob } 8977104aeefSMatt Jacob if (mpt_read_cfg_page(mpt, 0, &tmp.Header)) { 8987104aeefSMatt Jacob return (-1); 8997104aeefSMatt Jacob } 9007104aeefSMatt Jacob if (tmp.Configuration != pp1val) { 9017104aeefSMatt Jacob device_printf(mpt->dev, 9027104aeefSMatt Jacob "failed to reset SPI Port Page 1 Config value\n"); 9037104aeefSMatt Jacob return (-1); 9047104aeefSMatt Jacob } 9057104aeefSMatt Jacob mpt->mpt_port_page1 = tmp; 9067104aeefSMatt Jacob } 9077104aeefSMatt Jacob 9087104aeefSMatt Jacob for (i = 0; i < 16; i++) { 9097104aeefSMatt Jacob fCONFIG_PAGE_SCSI_DEVICE_1 tmp; 9107104aeefSMatt Jacob tmp = mpt->mpt_dev_page1[i]; 9117104aeefSMatt Jacob tmp.RequestedParameters = 0; 9127104aeefSMatt Jacob tmp.Configuration = 0; 9137104aeefSMatt Jacob if (mpt->verbose > 1) { 9147104aeefSMatt Jacob device_printf(mpt->dev, 9157104aeefSMatt Jacob "Set Tgt %d SPI DevicePage 1 values to %x 0 %x\n", 9167104aeefSMatt Jacob i, tmp.RequestedParameters, tmp.Configuration); 9177104aeefSMatt Jacob } 9187104aeefSMatt Jacob if (mpt_write_cfg_page(mpt, i, &tmp.Header)) { 9197104aeefSMatt Jacob return (-1); 9207104aeefSMatt Jacob } 9217104aeefSMatt Jacob if (mpt_read_cfg_page(mpt, i, &tmp.Header)) { 9227104aeefSMatt Jacob return (-1); 9237104aeefSMatt Jacob } 9247104aeefSMatt Jacob mpt->mpt_dev_page1[i] = tmp; 9257104aeefSMatt Jacob if (mpt->verbose > 1) { 9267104aeefSMatt Jacob device_printf(mpt->dev, 9277104aeefSMatt Jacob "SPI Tgt %d Page 1: RParm %x Configuration %x\n", i, 9287104aeefSMatt Jacob mpt->mpt_dev_page1[i].RequestedParameters, 9297104aeefSMatt Jacob mpt->mpt_dev_page1[i].Configuration); 9307104aeefSMatt Jacob } 9317104aeefSMatt Jacob } 932ce68dae5SMatt Jacob 933ce68dae5SMatt Jacob /* 934ce68dae5SMatt Jacob * If the BIOS hasn't been enabled, the SCSI Port Page2 device 935ce68dae5SMatt Jacob * parameter are apparently complete nonsense. I've had partially 936ce68dae5SMatt Jacob * sensible Page2 settings on *one* bus, but nothing on another- 937ce68dae5SMatt Jacob * it's ridiculous. 938ce68dae5SMatt Jacob * 939ce68dae5SMatt Jacob * For that matter, the Port Page 0 parameters are *also* nonsense, 940ce68dae5SMatt Jacob * so the offset and period and currently connected physical interface 941ce68dae5SMatt Jacob * is also nonsense. 942ce68dae5SMatt Jacob * 943ce68dae5SMatt Jacob * This makes it very difficult to try and figure out what maximum 944ce68dae5SMatt Jacob * settings we could have. Therefore, we'll synthesize the maximums 945ce68dae5SMatt Jacob * here. 946ce68dae5SMatt Jacob */ 947ce68dae5SMatt Jacob for (i = 0; i < 16; i++) { 948ce68dae5SMatt Jacob mpt->mpt_port_page2.DeviceSettings[i].DeviceFlags = 949ce68dae5SMatt Jacob MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE | 950ce68dae5SMatt Jacob MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE; 951ce68dae5SMatt Jacob } 952ce68dae5SMatt Jacob mpt->mpt_port_page0.Capabilities = 953ce68dae5SMatt Jacob MPI_SCSIPORTPAGE0_CAP_IU | 954ce68dae5SMatt Jacob MPI_SCSIPORTPAGE0_CAP_DT | 955ce68dae5SMatt Jacob MPI_SCSIPORTPAGE0_CAP_QAS | 956ce68dae5SMatt Jacob MPI_SCSIPORTPAGE0_CAP_WIDE | 957ce68dae5SMatt Jacob (31 << 16) | /* offset */ 958ce68dae5SMatt Jacob (8 << 8); /* period */ 959ce68dae5SMatt Jacob mpt->mpt_port_page0.PhysicalInterface = 960ce68dae5SMatt Jacob MPI_SCSIPORTPAGE0_PHY_SIGNAL_LVD; 9617104aeefSMatt Jacob return (0); 9627104aeefSMatt Jacob } 9637104aeefSMatt Jacob 9647104aeefSMatt Jacob /* 9657104aeefSMatt Jacob * Enable IOC port 9667104aeefSMatt Jacob */ 9677104aeefSMatt Jacob static int 9687104aeefSMatt Jacob mpt_send_port_enable(mpt_softc_t *mpt, int port) 9699b631363SMatt Jacob { 9709b631363SMatt Jacob int count; 9719b631363SMatt Jacob request_t *req; 9729b631363SMatt Jacob MSG_PORT_ENABLE *enable_req; 9739b631363SMatt Jacob 9749b631363SMatt Jacob req = mpt_get_request(mpt); 9759b631363SMatt Jacob 9769b631363SMatt Jacob enable_req = req->req_vbuf; 9779b631363SMatt Jacob bzero(enable_req, sizeof *enable_req); 9789b631363SMatt Jacob 9799b631363SMatt Jacob enable_req->Function = MPI_FUNCTION_PORT_ENABLE; 9809b631363SMatt Jacob enable_req->MsgContext = req->index | 0x80000000; 9819b631363SMatt Jacob enable_req->PortNumber = port; 9829b631363SMatt Jacob 9839b631363SMatt Jacob mpt_check_doorbell(mpt); 9849b631363SMatt Jacob if (mpt->verbose > 1) { 9859b631363SMatt Jacob device_printf(mpt->dev, "enabling port %d\n", port); 9869b631363SMatt Jacob } 9879b631363SMatt Jacob mpt_send_cmd(mpt, req); 9889b631363SMatt Jacob 9899b631363SMatt Jacob count = 0; 9909b631363SMatt Jacob do { 9919b631363SMatt Jacob DELAY(500); 9929b631363SMatt Jacob mpt_intr(mpt); 9939b631363SMatt Jacob if (++count == 1000) { 9949b631363SMatt Jacob device_printf(mpt->dev, "port enable timed out\n"); 9959b631363SMatt Jacob return (-1); 9969b631363SMatt Jacob } 9979b631363SMatt Jacob } while (req->debug == REQ_ON_CHIP); 9989b631363SMatt Jacob mpt_free_request(mpt, req); 9999b631363SMatt Jacob return (0); 10009b631363SMatt Jacob } 10019b631363SMatt Jacob 10029b631363SMatt Jacob /* 10039b631363SMatt Jacob * Enable/Disable asynchronous event reporting. 10049b631363SMatt Jacob * 10059b631363SMatt Jacob * NB: this is the first command we send via shared memory 10069b631363SMatt Jacob * instead of the handshake register. 10079b631363SMatt Jacob */ 10089b631363SMatt Jacob static int 10097104aeefSMatt Jacob mpt_send_event_request(mpt_softc_t *mpt, int onoff) 10109b631363SMatt Jacob { 10119b631363SMatt Jacob request_t *req; 10129b631363SMatt Jacob MSG_EVENT_NOTIFY *enable_req; 10139b631363SMatt Jacob 10149b631363SMatt Jacob req = mpt_get_request(mpt); 10159b631363SMatt Jacob 10169b631363SMatt Jacob enable_req = req->req_vbuf; 10179b631363SMatt Jacob bzero(enable_req, sizeof *enable_req); 10189b631363SMatt Jacob 10199b631363SMatt Jacob enable_req->Function = MPI_FUNCTION_EVENT_NOTIFICATION; 10209b631363SMatt Jacob enable_req->MsgContext = req->index | 0x80000000; 10219b631363SMatt Jacob enable_req->Switch = onoff; 10229b631363SMatt Jacob 10239b631363SMatt Jacob mpt_check_doorbell(mpt); 10249b631363SMatt Jacob if (mpt->verbose > 1) { 10259b631363SMatt Jacob device_printf(mpt->dev, "%sabling async events\n", 10269b631363SMatt Jacob onoff? "en" : "dis"); 10279b631363SMatt Jacob } 10289b631363SMatt Jacob mpt_send_cmd(mpt, req); 10299b631363SMatt Jacob 10309b631363SMatt Jacob return (0); 10319b631363SMatt Jacob } 10329b631363SMatt Jacob 10339b631363SMatt Jacob /* 10349b631363SMatt Jacob * Un-mask the interupts on the chip. 10359b631363SMatt Jacob */ 10369b631363SMatt Jacob void 10377104aeefSMatt Jacob mpt_enable_ints(mpt_softc_t *mpt) 10389b631363SMatt Jacob { 10399b631363SMatt Jacob /* Unmask every thing except door bell int */ 10409b631363SMatt Jacob mpt_write(mpt, MPT_OFFSET_INTR_MASK, MPT_INTR_DB_MASK); 10419b631363SMatt Jacob } 10429b631363SMatt Jacob 10439b631363SMatt Jacob /* 10449b631363SMatt Jacob * Mask the interupts on the chip. 10459b631363SMatt Jacob */ 10469b631363SMatt Jacob void 10477104aeefSMatt Jacob mpt_disable_ints(mpt_softc_t *mpt) 10489b631363SMatt Jacob { 10499b631363SMatt Jacob /* Mask all interrupts */ 10509b631363SMatt Jacob mpt_write(mpt, MPT_OFFSET_INTR_MASK, 10519b631363SMatt Jacob MPT_INTR_REPLY_MASK | MPT_INTR_DB_MASK); 10529b631363SMatt Jacob } 10539b631363SMatt Jacob 10549b631363SMatt Jacob /* (Re)Initialize the chip for use */ 10559b631363SMatt Jacob int 10567104aeefSMatt Jacob mpt_init(mpt_softc_t *mpt, u_int32_t who) 10579b631363SMatt Jacob { 10589b631363SMatt Jacob int try; 10599b631363SMatt Jacob MSG_IOC_FACTS_REPLY facts; 10607104aeefSMatt Jacob MSG_PORT_FACTS_REPLY pfp; 10619b631363SMatt Jacob u_int32_t pptr; 10629b631363SMatt Jacob int val; 10639b631363SMatt Jacob 10649b631363SMatt Jacob /* Put all request buffers (back) on the free list */ 10659b631363SMatt Jacob SLIST_INIT(&mpt->request_free_list); 10669b631363SMatt Jacob for (val = 0; val < MPT_MAX_REQUESTS; val++) { 10679b631363SMatt Jacob mpt_free_request(mpt, &mpt->requests[val]); 10689b631363SMatt Jacob } 10699b631363SMatt Jacob 10709b631363SMatt Jacob if (mpt->verbose > 1) { 10719b631363SMatt Jacob device_printf(mpt->dev, "doorbell req = %s\n", 10729b631363SMatt Jacob mpt_ioc_diag(mpt_read(mpt, MPT_OFFSET_DOORBELL))); 10739b631363SMatt Jacob } 10749b631363SMatt Jacob 10759b631363SMatt Jacob /* 10769b631363SMatt Jacob * Start by making sure we're not at FAULT or RESET state 10779b631363SMatt Jacob */ 10789b631363SMatt Jacob switch (mpt_rd_db(mpt) & MPT_DB_STATE_MASK) { 10799b631363SMatt Jacob case MPT_DB_STATE_RESET: 10809b631363SMatt Jacob case MPT_DB_STATE_FAULT: 10819b631363SMatt Jacob if (mpt_reset(mpt) != MPT_OK) { 10829b631363SMatt Jacob return (EIO); 10839b631363SMatt Jacob } 10849b631363SMatt Jacob default: 10859b631363SMatt Jacob break; 10869b631363SMatt Jacob } 10879b631363SMatt Jacob 10889b631363SMatt Jacob for (try = 0; try < MPT_MAX_TRYS; try++) { 10899b631363SMatt Jacob /* 10909b631363SMatt Jacob * No need to reset if the IOC is already in the READY state. 10919b631363SMatt Jacob * 10929b631363SMatt Jacob * Force reset if initialization failed previously. 10939b631363SMatt Jacob * Note that a hard_reset of the second channel of a '929 10949b631363SMatt Jacob * will stop operation of the first channel. Hopefully, if the 10959b631363SMatt Jacob * first channel is ok, the second will not require a hard 10969b631363SMatt Jacob * reset. 10979b631363SMatt Jacob */ 10989b631363SMatt Jacob if ((mpt_rd_db(mpt) & MPT_DB_STATE_MASK) != 10999b631363SMatt Jacob MPT_DB_STATE_READY) { 11009b631363SMatt Jacob if (mpt_reset(mpt) != MPT_OK) { 11019b631363SMatt Jacob DELAY(10000); 11029b631363SMatt Jacob continue; 11039b631363SMatt Jacob } 11049b631363SMatt Jacob } 11059b631363SMatt Jacob 11069b631363SMatt Jacob if (mpt_get_iocfacts(mpt, &facts) != MPT_OK) { 11079b631363SMatt Jacob device_printf(mpt->dev, "mpt_get_iocfacts failed\n"); 11089b631363SMatt Jacob continue; 11097104aeefSMatt Jacob } 11107104aeefSMatt Jacob 11117104aeefSMatt Jacob if (mpt->verbose > 1) { 11129b631363SMatt Jacob device_printf(mpt->dev, 11139b631363SMatt Jacob "mpt_get_iocfacts: GlobalCredits=%d BlockSize=%u " 11149b631363SMatt Jacob "Request Frame Size %u\n", facts.GlobalCredits, 11159b631363SMatt Jacob facts.BlockSize, facts.RequestFrameSize); 11169b631363SMatt Jacob } 11179b631363SMatt Jacob mpt->mpt_global_credits = facts.GlobalCredits; 11189b631363SMatt Jacob mpt->request_frame_size = facts.RequestFrameSize; 11199b631363SMatt Jacob 11207104aeefSMatt Jacob if (mpt_get_portfacts(mpt, &pfp) != MPT_OK) { 11217104aeefSMatt Jacob device_printf(mpt->dev, "mpt_get_portfacts failed\n"); 11227104aeefSMatt Jacob continue; 11237104aeefSMatt Jacob } 11247104aeefSMatt Jacob 11257104aeefSMatt Jacob if (mpt->verbose > 1) { 11267104aeefSMatt Jacob device_printf(mpt->dev, 11277104aeefSMatt Jacob "mpt_get_portfacts: Type %x PFlags %x IID %d\n", 11287104aeefSMatt Jacob pfp.PortType, pfp.ProtocolFlags, pfp.PortSCSIID); 11297104aeefSMatt Jacob } 11307104aeefSMatt Jacob 11317104aeefSMatt Jacob if (pfp.PortType != MPI_PORTFACTS_PORTTYPE_SCSI && 11327104aeefSMatt Jacob pfp.PortType != MPI_PORTFACTS_PORTTYPE_FC) { 11337104aeefSMatt Jacob device_printf(mpt->dev, "Unsupported Port Type (%x)\n", 11347104aeefSMatt Jacob pfp.PortType); 11357104aeefSMatt Jacob return (ENXIO); 11367104aeefSMatt Jacob } 11377104aeefSMatt Jacob if (!(pfp.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)) { 11387104aeefSMatt Jacob device_printf(mpt->dev, "initiator role unsupported\n"); 11397104aeefSMatt Jacob return (ENXIO); 11407104aeefSMatt Jacob } 11417104aeefSMatt Jacob if (pfp.PortType == MPI_PORTFACTS_PORTTYPE_FC) { 11427104aeefSMatt Jacob mpt->is_fc = 1; 11437104aeefSMatt Jacob } else { 11447104aeefSMatt Jacob mpt->is_fc = 0; 11457104aeefSMatt Jacob } 11467104aeefSMatt Jacob mpt->mpt_ini_id = pfp.PortSCSIID; 11477104aeefSMatt Jacob 11489b631363SMatt Jacob if (mpt_send_ioc_init(mpt, who) != MPT_OK) { 11499b631363SMatt Jacob device_printf(mpt->dev, "mpt_send_ioc_init failed\n"); 11509b631363SMatt Jacob continue; 11517104aeefSMatt Jacob } 11527104aeefSMatt Jacob 11537104aeefSMatt Jacob if (mpt->verbose > 1) { 11549b631363SMatt Jacob device_printf(mpt->dev, "mpt_send_ioc_init ok\n"); 11559b631363SMatt Jacob } 11569b631363SMatt Jacob 11579b631363SMatt Jacob if (mpt_wait_state(mpt, MPT_DB_STATE_RUNNING) != MPT_OK) { 11589b631363SMatt Jacob device_printf(mpt->dev, 11599b631363SMatt Jacob "IOC failed to go to run state\n"); 11609b631363SMatt Jacob continue; 11617104aeefSMatt Jacob } 11627104aeefSMatt Jacob if (mpt->verbose > 1) { 11639b631363SMatt Jacob device_printf(mpt->dev, "IOC now at RUNSTATE\n"); 11649b631363SMatt Jacob } 11659b631363SMatt Jacob 11669b631363SMatt Jacob /* 11679b631363SMatt Jacob * Give it reply buffers 11689b631363SMatt Jacob * 11699b631363SMatt Jacob * Do *not* except global credits. 11709b631363SMatt Jacob */ 11719b631363SMatt Jacob for (val = 0, pptr = mpt->reply_phys; 11729b631363SMatt Jacob (pptr + MPT_REPLY_SIZE) < (mpt->reply_phys + PAGE_SIZE); 11739b631363SMatt Jacob pptr += MPT_REPLY_SIZE) { 11749b631363SMatt Jacob mpt_free_reply(mpt, pptr); 11759b631363SMatt Jacob if (++val == mpt->mpt_global_credits - 1) 11769b631363SMatt Jacob break; 11779b631363SMatt Jacob } 11789b631363SMatt Jacob 11797104aeefSMatt Jacob /* 11807104aeefSMatt Jacob * Enable asynchronous event reporting 11817104aeefSMatt Jacob */ 11829b631363SMatt Jacob mpt_send_event_request(mpt, 1); 11839b631363SMatt Jacob 11847104aeefSMatt Jacob 11857104aeefSMatt Jacob /* 11867104aeefSMatt Jacob * Read set up initial configuration information 11877104aeefSMatt Jacob * (SPI only for now) 11887104aeefSMatt Jacob */ 11897104aeefSMatt Jacob 11907104aeefSMatt Jacob if (mpt->is_fc == 0) { 11917104aeefSMatt Jacob if (mpt_read_config_info_spi(mpt)) { 11927104aeefSMatt Jacob return (EIO); 11937104aeefSMatt Jacob } 11947104aeefSMatt Jacob if (mpt_set_initial_config_spi(mpt)) { 11957104aeefSMatt Jacob return (EIO); 11967104aeefSMatt Jacob } 11977104aeefSMatt Jacob } 11987104aeefSMatt Jacob 11997104aeefSMatt Jacob /* 12007104aeefSMatt Jacob * Now enable the port 12017104aeefSMatt Jacob */ 12029b631363SMatt Jacob if (mpt_send_port_enable(mpt, 0) != MPT_OK) { 12039b631363SMatt Jacob device_printf(mpt->dev, "failed to enable port 0\n"); 12049b631363SMatt Jacob continue; 12057104aeefSMatt Jacob } 12067104aeefSMatt Jacob 12077104aeefSMatt Jacob if (mpt->verbose > 1) { 12089b631363SMatt Jacob device_printf(mpt->dev, "enabled port 0\n"); 12099b631363SMatt Jacob } 12109b631363SMatt Jacob 12119b631363SMatt Jacob /* Everything worked */ 12129b631363SMatt Jacob break; 12139b631363SMatt Jacob } 12149b631363SMatt Jacob 12159b631363SMatt Jacob if (try >= MPT_MAX_TRYS) { 12169b631363SMatt Jacob device_printf(mpt->dev, "failed to initialize IOC\n"); 12179b631363SMatt Jacob return (EIO); 12189b631363SMatt Jacob } 12199b631363SMatt Jacob 12209b631363SMatt Jacob if (mpt->verbose > 1) { 12219b631363SMatt Jacob device_printf(mpt->dev, "enabling interrupts\n"); 12229b631363SMatt Jacob } 12239b631363SMatt Jacob 12249b631363SMatt Jacob mpt_enable_ints(mpt); 12259b631363SMatt Jacob return (0); 12269b631363SMatt Jacob } 1227