xref: /freebsd/sys/dev/mpt/mpt.c (revision 098ca2bda93c701c5331d4e6aace072495b4caaa)
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