xref: /freebsd/sys/dev/mpt/mpt.c (revision 7104aeef01959759804705e48ebc18bb92ebfdb3)
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;
2669b631363SMatt Jacob 		device_printf(mpt->dev, "Send Request %d (0x%x):\n",
2679b631363SMatt Jacob 		    req->index, 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: "
4009b631363SMatt Jacob 			"got 0x%02x, expected 0x%02x\n",
4019b631363SMatt Jacob 			hdr->MsgLength << 2, 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 static int
5137104aeefSMatt Jacob mpt_read_cfg_page(mpt_softc_t *, int, fCONFIG_PAGE_HEADER *);
5147104aeefSMatt Jacob static int
5157104aeefSMatt Jacob mpt_write_cfg_page(mpt_softc_t *, int, fCONFIG_PAGE_HEADER *);
5167104aeefSMatt Jacob 
5177104aeefSMatt Jacob static int
5187104aeefSMatt Jacob mpt_read_cfg_header(mpt_softc_t *mpt, int PageType, int PageNumber,
5197104aeefSMatt Jacob     int PageAddress, fCONFIG_PAGE_HEADER *rslt)
5207104aeefSMatt Jacob {
5217104aeefSMatt Jacob 	int count;
5227104aeefSMatt Jacob 	request_t *req;
5237104aeefSMatt Jacob 	MSG_CONFIG *cfgp;
5247104aeefSMatt Jacob 	MSG_CONFIG_REPLY *reply;
5257104aeefSMatt Jacob 
5267104aeefSMatt Jacob 	req = mpt_get_request(mpt);
5277104aeefSMatt Jacob 
5287104aeefSMatt Jacob 	cfgp = req->req_vbuf;
5297104aeefSMatt Jacob 	bzero(cfgp, sizeof *cfgp);
5307104aeefSMatt Jacob 
5317104aeefSMatt Jacob 	cfgp->Action = MPI_CONFIG_ACTION_PAGE_HEADER;
5327104aeefSMatt Jacob 	cfgp->Function = MPI_FUNCTION_CONFIG;
5337104aeefSMatt Jacob 	cfgp->Header.PageNumber = (U8) PageNumber;
5347104aeefSMatt Jacob 	cfgp->Header.PageType = (U8) PageType;
5357104aeefSMatt Jacob 	cfgp->PageAddress = PageAddress;
5367104aeefSMatt Jacob 	MPI_pSGE_SET_FLAGS(((SGE_SIMPLE32 *) &cfgp->PageBufferSGE),
5377104aeefSMatt Jacob 	    (MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
5387104aeefSMatt Jacob 	    MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_LIST));
5397104aeefSMatt Jacob 	cfgp->MsgContext = req->index | 0x80000000;
5407104aeefSMatt Jacob 
5417104aeefSMatt Jacob 	mpt_check_doorbell(mpt);
5427104aeefSMatt Jacob 	mpt_send_cmd(mpt, req);
5437104aeefSMatt Jacob 	count = 0;
5447104aeefSMatt Jacob 	do {
5457104aeefSMatt Jacob 		DELAY(500);
5467104aeefSMatt Jacob 		mpt_intr(mpt);
5477104aeefSMatt Jacob 		if (++count == 1000) {
5487104aeefSMatt Jacob 			device_printf(mpt->dev, "read_cfg_header timed out\n");
5497104aeefSMatt Jacob 			return (-1);
5507104aeefSMatt Jacob 		}
5517104aeefSMatt Jacob 	} while (req->debug == REQ_ON_CHIP);
5527104aeefSMatt Jacob 
5537104aeefSMatt Jacob 	reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence);
5547104aeefSMatt Jacob         if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
5557104aeefSMatt Jacob 		device_printf(mpt->dev,
5567104aeefSMatt Jacob 		    "mpt_read_cfg_header: Config Info Status %x\n",
5577104aeefSMatt Jacob 		    reply->IOCStatus);
5587104aeefSMatt Jacob 		return (-1);
5597104aeefSMatt Jacob 	}
5607104aeefSMatt Jacob 	bcopy(&reply->Header, rslt, sizeof (fCONFIG_PAGE_HEADER));
5617104aeefSMatt Jacob 	mpt_free_reply(mpt, (req->sequence << 1));
5627104aeefSMatt Jacob 	mpt_free_request(mpt, req);
5637104aeefSMatt Jacob 	return (0);
5647104aeefSMatt Jacob }
5657104aeefSMatt Jacob 
5667104aeefSMatt Jacob #define	CFG_DATA_OFF	40
5677104aeefSMatt Jacob 
5687104aeefSMatt Jacob static int
5697104aeefSMatt Jacob mpt_read_cfg_page(mpt_softc_t *mpt, int PageAddress, fCONFIG_PAGE_HEADER *hdr)
5707104aeefSMatt Jacob {
5717104aeefSMatt Jacob 	int count;
5727104aeefSMatt Jacob 	request_t *req;
5737104aeefSMatt Jacob 	SGE_SIMPLE32 *se;
5747104aeefSMatt Jacob 	MSG_CONFIG *cfgp;
5757104aeefSMatt Jacob 	size_t amt;
5767104aeefSMatt Jacob 	MSG_CONFIG_REPLY *reply;
5777104aeefSMatt Jacob 
5787104aeefSMatt Jacob 	req = mpt_get_request(mpt);
5797104aeefSMatt Jacob 
5807104aeefSMatt Jacob 	cfgp = req->req_vbuf;
5817104aeefSMatt Jacob  	amt = (cfgp->Header.PageLength * sizeof (uint32_t));
5827104aeefSMatt Jacob 	bzero(cfgp, sizeof *cfgp);
5837104aeefSMatt Jacob 	cfgp->Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5847104aeefSMatt Jacob 	cfgp->Function = MPI_FUNCTION_CONFIG;
5857104aeefSMatt Jacob 	cfgp->Header = *hdr;
5867104aeefSMatt Jacob 	cfgp->Header.PageType &= MPI_CONFIG_PAGETYPE_MASK;
5877104aeefSMatt Jacob 	cfgp->PageAddress = PageAddress;
5887104aeefSMatt Jacob 	se = (SGE_SIMPLE32 *) &cfgp->PageBufferSGE;
5897104aeefSMatt Jacob 	se->Address = req->req_pbuf + CFG_DATA_OFF;
5907104aeefSMatt Jacob 	MPI_pSGE_SET_LENGTH(se, amt);
5917104aeefSMatt Jacob 	MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
5927104aeefSMatt Jacob 	    MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
5937104aeefSMatt Jacob 	    MPI_SGE_FLAGS_END_OF_LIST));
5947104aeefSMatt Jacob 
5957104aeefSMatt Jacob 	cfgp->MsgContext = req->index | 0x80000000;
5967104aeefSMatt Jacob 
5977104aeefSMatt Jacob 	mpt_check_doorbell(mpt);
5987104aeefSMatt Jacob 	mpt_send_cmd(mpt, req);
5997104aeefSMatt Jacob 	count = 0;
6007104aeefSMatt Jacob 	do {
6017104aeefSMatt Jacob 		DELAY(500);
6027104aeefSMatt Jacob 		mpt_intr(mpt);
6037104aeefSMatt Jacob 		if (++count == 1000) {
6047104aeefSMatt Jacob 			device_printf(mpt->dev, "read_cfg_page timed out\n");
6057104aeefSMatt Jacob 			return (-1);
6067104aeefSMatt Jacob 		}
6077104aeefSMatt Jacob 	} while (req->debug == REQ_ON_CHIP);
6087104aeefSMatt Jacob 
6097104aeefSMatt Jacob 	reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence);
6107104aeefSMatt Jacob         if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
6117104aeefSMatt Jacob 		device_printf(mpt->dev,
6127104aeefSMatt Jacob 		    "mpt_read_cfg_page: Config Info Status %x\n",
6137104aeefSMatt Jacob 		    reply->IOCStatus);
6147104aeefSMatt Jacob 		return (-1);
6157104aeefSMatt Jacob 	}
6167104aeefSMatt Jacob 	mpt_free_reply(mpt, (req->sequence << 1));
6177104aeefSMatt Jacob 	bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap,
6187104aeefSMatt Jacob 	    BUS_DMASYNC_POSTREAD);
6197104aeefSMatt Jacob 	if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
6207104aeefSMatt Jacob 	    cfgp->Header.PageNumber == 0) {
6217104aeefSMatt Jacob 		amt = sizeof (fCONFIG_PAGE_SCSI_PORT_0);
6227104aeefSMatt Jacob 	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
6237104aeefSMatt Jacob 	    cfgp->Header.PageNumber == 1) {
6247104aeefSMatt Jacob 		amt = sizeof (fCONFIG_PAGE_SCSI_PORT_1);
6257104aeefSMatt Jacob 	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
6267104aeefSMatt Jacob 	    cfgp->Header.PageNumber == 2) {
6277104aeefSMatt Jacob 		amt = sizeof (fCONFIG_PAGE_SCSI_PORT_2);
6287104aeefSMatt Jacob 	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE  &&
6297104aeefSMatt Jacob 	    cfgp->Header.PageNumber == 0) {
6307104aeefSMatt Jacob 		amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_0);
6317104aeefSMatt Jacob 	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE  &&
6327104aeefSMatt Jacob 	    cfgp->Header.PageNumber == 1) {
6337104aeefSMatt Jacob 		amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_1);
6347104aeefSMatt Jacob 	}
6357104aeefSMatt Jacob 	bcopy(((caddr_t)req->req_vbuf)+CFG_DATA_OFF, hdr, amt);
6367104aeefSMatt Jacob 	mpt_free_request(mpt, req);
6377104aeefSMatt Jacob 	return (0);
6387104aeefSMatt Jacob }
6397104aeefSMatt Jacob 
6407104aeefSMatt Jacob static int
6417104aeefSMatt Jacob mpt_write_cfg_page(mpt_softc_t *mpt, int PageAddress, fCONFIG_PAGE_HEADER *hdr)
6427104aeefSMatt Jacob {
6437104aeefSMatt Jacob 	int count, hdr_attr;
6447104aeefSMatt Jacob 	request_t *req;
6457104aeefSMatt Jacob 	SGE_SIMPLE32 *se;
6467104aeefSMatt Jacob 	MSG_CONFIG *cfgp;
6477104aeefSMatt Jacob 	size_t amt;
6487104aeefSMatt Jacob 	MSG_CONFIG_REPLY *reply;
6497104aeefSMatt Jacob 
6507104aeefSMatt Jacob 	req = mpt_get_request(mpt);
6517104aeefSMatt Jacob 
6527104aeefSMatt Jacob 	cfgp = req->req_vbuf;
6537104aeefSMatt Jacob 	bzero(cfgp, sizeof *cfgp);
6547104aeefSMatt Jacob 
6557104aeefSMatt Jacob 	hdr_attr = hdr->PageType & MPI_CONFIG_PAGEATTR_MASK;
6567104aeefSMatt Jacob 	if (hdr_attr != MPI_CONFIG_PAGEATTR_CHANGEABLE &&
6577104aeefSMatt Jacob 	    hdr_attr != MPI_CONFIG_PAGEATTR_PERSISTENT) {
6587104aeefSMatt Jacob 		device_printf(mpt->dev, "page type 0x%x not changeable\n",
6597104aeefSMatt Jacob 		    hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
6607104aeefSMatt Jacob 		return (-1);
6617104aeefSMatt Jacob 	}
6627104aeefSMatt Jacob 	hdr->PageType &= MPI_CONFIG_PAGETYPE_MASK;
6637104aeefSMatt Jacob 
6647104aeefSMatt Jacob  	amt = (cfgp->Header.PageLength * sizeof (uint32_t));
6657104aeefSMatt Jacob 	cfgp->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
6667104aeefSMatt Jacob 	cfgp->Function = MPI_FUNCTION_CONFIG;
6677104aeefSMatt Jacob 	cfgp->Header = *hdr;
6687104aeefSMatt Jacob 	cfgp->PageAddress = PageAddress;
6697104aeefSMatt Jacob 
6707104aeefSMatt Jacob 	se = (SGE_SIMPLE32 *) &cfgp->PageBufferSGE;
6717104aeefSMatt Jacob 	se->Address = req->req_pbuf + CFG_DATA_OFF;
6727104aeefSMatt Jacob 	MPI_pSGE_SET_LENGTH(se, amt);
6737104aeefSMatt Jacob 	MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
6747104aeefSMatt Jacob 	    MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
6757104aeefSMatt Jacob 	    MPI_SGE_FLAGS_END_OF_LIST | MPI_SGE_FLAGS_HOST_TO_IOC));
6767104aeefSMatt Jacob 
6777104aeefSMatt Jacob 	cfgp->MsgContext = req->index | 0x80000000;
6787104aeefSMatt Jacob 
6797104aeefSMatt Jacob 	if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
6807104aeefSMatt Jacob 	    cfgp->Header.PageNumber == 0) {
6817104aeefSMatt Jacob 		amt = sizeof (fCONFIG_PAGE_SCSI_PORT_0);
6827104aeefSMatt Jacob 	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
6837104aeefSMatt Jacob 	    cfgp->Header.PageNumber == 1) {
6847104aeefSMatt Jacob 		amt = sizeof (fCONFIG_PAGE_SCSI_PORT_1);
6857104aeefSMatt Jacob 	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
6867104aeefSMatt Jacob 	    cfgp->Header.PageNumber == 2) {
6877104aeefSMatt Jacob 		amt = sizeof (fCONFIG_PAGE_SCSI_PORT_2);
6887104aeefSMatt Jacob 	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE  &&
6897104aeefSMatt Jacob 	    cfgp->Header.PageNumber == 0) {
6907104aeefSMatt Jacob 		amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_0);
6917104aeefSMatt Jacob 	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE  &&
6927104aeefSMatt Jacob 	    cfgp->Header.PageNumber == 1) {
6937104aeefSMatt Jacob 		amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_1);
6947104aeefSMatt Jacob 	}
6957104aeefSMatt Jacob 	bcopy(hdr, ((caddr_t)req->req_vbuf)+CFG_DATA_OFF, amt);
6967104aeefSMatt Jacob 
6977104aeefSMatt Jacob 	mpt_check_doorbell(mpt);
6987104aeefSMatt Jacob 	mpt_send_cmd(mpt, req);
6997104aeefSMatt Jacob 	count = 0;
7007104aeefSMatt Jacob 	do {
7017104aeefSMatt Jacob 		DELAY(500);
7027104aeefSMatt Jacob 		mpt_intr(mpt);
7037104aeefSMatt Jacob 		if (++count == 1000) {
7047104aeefSMatt Jacob 			hdr->PageType |= hdr_attr;
7057104aeefSMatt Jacob 			device_printf(mpt->dev,
7067104aeefSMatt Jacob 			    "mpt_write_cfg_page timed out\n");
7077104aeefSMatt Jacob 			return (-1);
7087104aeefSMatt Jacob 		}
7097104aeefSMatt Jacob 	} while (req->debug == REQ_ON_CHIP);
7107104aeefSMatt Jacob 
7117104aeefSMatt Jacob 	reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence);
7127104aeefSMatt Jacob         if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
7137104aeefSMatt Jacob 		device_printf(mpt->dev,
7147104aeefSMatt Jacob 		    "mpt_write_cfg_page: Config Info Status %x\n",
7157104aeefSMatt Jacob 		    reply->IOCStatus);
7167104aeefSMatt Jacob 		return (-1);
7177104aeefSMatt Jacob 	}
7187104aeefSMatt Jacob 	mpt_free_reply(mpt, (req->sequence << 1));
7197104aeefSMatt Jacob 
7207104aeefSMatt Jacob 	/*
7217104aeefSMatt Jacob 	 * Restore stripped out attributes
7227104aeefSMatt Jacob 	 */
7237104aeefSMatt Jacob 	hdr->PageType |= hdr_attr;
7247104aeefSMatt Jacob 	mpt_free_request(mpt, req);
7257104aeefSMatt Jacob 	return (0);
7267104aeefSMatt Jacob }
7277104aeefSMatt Jacob 
7287104aeefSMatt Jacob /*
7297104aeefSMatt Jacob  * Read SCSI configuration information
7307104aeefSMatt Jacob  */
7317104aeefSMatt Jacob static int
7327104aeefSMatt Jacob mpt_read_config_info_spi(mpt_softc_t *mpt)
7337104aeefSMatt Jacob {
7347104aeefSMatt Jacob 	int rv, i;
7357104aeefSMatt Jacob 
7367104aeefSMatt Jacob 	rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 0,
7377104aeefSMatt Jacob 	    0, &mpt->mpt_port_page0.Header);
7387104aeefSMatt Jacob 	if (rv) {
7397104aeefSMatt Jacob 		return (-1);
7407104aeefSMatt Jacob 	}
7417104aeefSMatt Jacob 	if (mpt->verbose > 1) {
7427104aeefSMatt Jacob 		device_printf(mpt->dev, "SPI Port Page 0 Header: %x %x %x %x\n",
7437104aeefSMatt Jacob 		    mpt->mpt_port_page0.Header.PageVersion,
7447104aeefSMatt Jacob 		    mpt->mpt_port_page0.Header.PageLength,
7457104aeefSMatt Jacob 		    mpt->mpt_port_page0.Header.PageNumber,
7467104aeefSMatt Jacob 		    mpt->mpt_port_page0.Header.PageType);
7477104aeefSMatt Jacob 	}
7487104aeefSMatt Jacob 
7497104aeefSMatt Jacob 	rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 1,
7507104aeefSMatt Jacob 	    0, &mpt->mpt_port_page1.Header);
7517104aeefSMatt Jacob 	if (rv) {
7527104aeefSMatt Jacob 		return (-1);
7537104aeefSMatt Jacob 	}
7547104aeefSMatt Jacob 	if (mpt->verbose > 1) {
7557104aeefSMatt Jacob 		device_printf(mpt->dev, "SPI Port Page 1 Header: %x %x %x %x\n",
7567104aeefSMatt Jacob 		    mpt->mpt_port_page1.Header.PageVersion,
7577104aeefSMatt Jacob 		    mpt->mpt_port_page1.Header.PageLength,
7587104aeefSMatt Jacob 		    mpt->mpt_port_page1.Header.PageNumber,
7597104aeefSMatt Jacob 		    mpt->mpt_port_page1.Header.PageType);
7607104aeefSMatt Jacob 	}
7617104aeefSMatt Jacob 
7627104aeefSMatt Jacob 	rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 2,
7637104aeefSMatt Jacob 	    0, &mpt->mpt_port_page2.Header);
7647104aeefSMatt Jacob 	if (rv) {
7657104aeefSMatt Jacob 		return (-1);
7667104aeefSMatt Jacob 	}
7677104aeefSMatt Jacob 
7687104aeefSMatt Jacob 	if (mpt->verbose > 1) {
7697104aeefSMatt Jacob 		device_printf(mpt->dev, "SPI Port Page 2 Header: %x %x %x %x\n",
7707104aeefSMatt Jacob 		    mpt->mpt_port_page1.Header.PageVersion,
7717104aeefSMatt Jacob 		    mpt->mpt_port_page1.Header.PageLength,
7727104aeefSMatt Jacob 		    mpt->mpt_port_page1.Header.PageNumber,
7737104aeefSMatt Jacob 		    mpt->mpt_port_page1.Header.PageType);
7747104aeefSMatt Jacob 	}
7757104aeefSMatt Jacob 
7767104aeefSMatt Jacob 	for (i = 0; i < 16; i++) {
7777104aeefSMatt Jacob 		rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE,
7787104aeefSMatt Jacob 		    0, i, &mpt->mpt_dev_page0[i].Header);
7797104aeefSMatt Jacob 		if (rv) {
7807104aeefSMatt Jacob 			return (-1);
7817104aeefSMatt Jacob 		}
7827104aeefSMatt Jacob 		if (mpt->verbose > 1) {
7837104aeefSMatt Jacob 			device_printf(mpt->dev,
7847104aeefSMatt Jacob 			    "SPI Target %d Device Page 0 Header: %x %x %x %x\n",
7857104aeefSMatt Jacob 			    i, mpt->mpt_dev_page0[i].Header.PageVersion,
7867104aeefSMatt Jacob 			    mpt->mpt_dev_page0[i].Header.PageLength,
7877104aeefSMatt Jacob 			    mpt->mpt_dev_page0[i].Header.PageNumber,
7887104aeefSMatt Jacob 			    mpt->mpt_dev_page0[i].Header.PageType);
7897104aeefSMatt Jacob 		}
7907104aeefSMatt Jacob 
7917104aeefSMatt Jacob 		rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE,
7927104aeefSMatt Jacob 		    1, i, &mpt->mpt_dev_page1[i].Header);
7937104aeefSMatt Jacob 		if (rv) {
7947104aeefSMatt Jacob 			return (-1);
7957104aeefSMatt Jacob 		}
7967104aeefSMatt Jacob 		if (mpt->verbose > 1) {
7977104aeefSMatt Jacob 			device_printf(mpt->dev,
7987104aeefSMatt Jacob 			    "SPI Target %d Device Page 1 Header: %x %x %x %x\n",
7997104aeefSMatt Jacob 			    i, mpt->mpt_dev_page1[i].Header.PageVersion,
8007104aeefSMatt Jacob 			    mpt->mpt_dev_page1[i].Header.PageLength,
8017104aeefSMatt Jacob 			    mpt->mpt_dev_page1[i].Header.PageNumber,
8027104aeefSMatt Jacob 			    mpt->mpt_dev_page1[i].Header.PageType);
8037104aeefSMatt Jacob 		}
8047104aeefSMatt Jacob 	}
8057104aeefSMatt Jacob 
8067104aeefSMatt Jacob 	/*
8077104aeefSMatt Jacob 	 * At this point, we don't *have* to fail. As long as we have
8087104aeefSMatt Jacob 	 * valid config header information, we can (barely) lurch
8097104aeefSMatt Jacob 	 * along.
8107104aeefSMatt Jacob 	 */
8117104aeefSMatt Jacob 
8127104aeefSMatt Jacob 	rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page0.Header);
8137104aeefSMatt Jacob 	if (rv) {
8147104aeefSMatt Jacob 		device_printf(mpt->dev, "failed to read SPI Port Page 0\n");
8157104aeefSMatt Jacob 	} else if (mpt->verbose > 1) {
8167104aeefSMatt Jacob 		device_printf(mpt->dev,
8177104aeefSMatt Jacob 		    "SPI Port Page 0: Capabilities %x PhysicalInterface %x\n",
8187104aeefSMatt Jacob 		    mpt->mpt_port_page0.Capabilities,
8197104aeefSMatt Jacob 		    mpt->mpt_port_page0.PhysicalInterface);
8207104aeefSMatt Jacob 	}
8217104aeefSMatt Jacob 
8227104aeefSMatt Jacob 	rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page1.Header);
8237104aeefSMatt Jacob 	if (rv) {
8247104aeefSMatt Jacob 		device_printf(mpt->dev, "failed to read SPI Port Page 1\n");
8257104aeefSMatt Jacob 	} else if (mpt->verbose > 1) {
8267104aeefSMatt Jacob 		device_printf(mpt->dev,
8277104aeefSMatt Jacob 		    "SPI Port Page 1: Configuration %x OnBusTimerValue %x\n",
8287104aeefSMatt Jacob 		    mpt->mpt_port_page1.Configuration,
8297104aeefSMatt Jacob 		    mpt->mpt_port_page1.OnBusTimerValue);
8307104aeefSMatt Jacob 	}
8317104aeefSMatt Jacob 
8327104aeefSMatt Jacob 	rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page2.Header);
8337104aeefSMatt Jacob 	if (rv) {
8347104aeefSMatt Jacob 		device_printf(mpt->dev, "failed to read SPI Port Page 2\n");
8357104aeefSMatt Jacob 	} else if (mpt->verbose > 1) {
8367104aeefSMatt Jacob 		device_printf(mpt->dev,
8377104aeefSMatt Jacob 		    "SPI Port Page 2: Flags %x Settings %x\n",
8387104aeefSMatt Jacob 		    mpt->mpt_port_page2.PortFlags,
8397104aeefSMatt Jacob 		    mpt->mpt_port_page2.PortSettings);
8407104aeefSMatt Jacob 		for (i = 0; i < 16; i++) {
8417104aeefSMatt Jacob 			device_printf(mpt->dev,
8427104aeefSMatt Jacob 		  	    "SPI Port Page 2 Tgt %d: timo %x SF %x Flags %x\n",
8437104aeefSMatt Jacob 			    i, mpt->mpt_port_page2.DeviceSettings[i].Timeout,
8447104aeefSMatt Jacob 			    mpt->mpt_port_page2.DeviceSettings[i].SyncFactor,
8457104aeefSMatt Jacob 			    mpt->mpt_port_page2.DeviceSettings[i].DeviceFlags);
8467104aeefSMatt Jacob 		}
8477104aeefSMatt Jacob 	}
8487104aeefSMatt Jacob 
8497104aeefSMatt Jacob 	for (i = 0; i < 16; i++) {
8507104aeefSMatt Jacob 		rv = mpt_read_cfg_page(mpt, i, &mpt->mpt_dev_page0[i].Header);
8517104aeefSMatt Jacob 		if (rv) {
8527104aeefSMatt Jacob 			device_printf(mpt->dev,
8537104aeefSMatt Jacob 			    "cannot read SPI Tgt %d Device Page 0\n", i);
8547104aeefSMatt Jacob 			continue;
8557104aeefSMatt Jacob 		}
8567104aeefSMatt Jacob 		if (mpt->verbose > 1) {
8577104aeefSMatt Jacob 			device_printf(mpt->dev,
8587104aeefSMatt Jacob 			    "SPI Tgt %d Page 0: NParms %x Information %x\n",
8597104aeefSMatt Jacob 			    i, mpt->mpt_dev_page0[i].NegotiatedParameters,
8607104aeefSMatt Jacob 			    mpt->mpt_dev_page0[i].Information);
8617104aeefSMatt Jacob 		}
8627104aeefSMatt Jacob 		rv = mpt_read_cfg_page(mpt, i, &mpt->mpt_dev_page1[i].Header);
8637104aeefSMatt Jacob 		if (rv) {
8647104aeefSMatt Jacob 			device_printf(mpt->dev,
8657104aeefSMatt Jacob 			    "cannot read SPI Tgt %d Device Page 1\n", i);
8667104aeefSMatt Jacob 			continue;
8677104aeefSMatt Jacob 		}
8687104aeefSMatt Jacob 		if (mpt->verbose > 1) {
8697104aeefSMatt Jacob 			device_printf(mpt->dev,
8707104aeefSMatt Jacob 			    "SPI Tgt %d Page 1: RParms %x Configuration %x\n",
8717104aeefSMatt Jacob 			    i, mpt->mpt_dev_page1[i].RequestedParameters,
8727104aeefSMatt Jacob 			    mpt->mpt_dev_page1[i].Configuration);
8737104aeefSMatt Jacob 		}
8747104aeefSMatt Jacob 	}
8757104aeefSMatt Jacob 	return (0);
8767104aeefSMatt Jacob }
8777104aeefSMatt Jacob 
8787104aeefSMatt Jacob /*
8797104aeefSMatt Jacob  * Validate SPI configuration information.
8807104aeefSMatt Jacob  *
8817104aeefSMatt Jacob  * In particular, validate SPI Port Page 1.
8827104aeefSMatt Jacob  */
8837104aeefSMatt Jacob static int
8847104aeefSMatt Jacob mpt_set_initial_config_spi(mpt_softc_t *mpt)
8857104aeefSMatt Jacob {
8867104aeefSMatt Jacob 	int i, pp1val = ((1 << mpt->mpt_ini_id) << 16) | mpt->mpt_ini_id;
8877104aeefSMatt Jacob 
8887104aeefSMatt Jacob 	if (mpt->mpt_port_page1.Configuration != pp1val) {
8897104aeefSMatt Jacob 		fCONFIG_PAGE_SCSI_PORT_1 tmp;
8907104aeefSMatt Jacob 		device_printf(mpt->dev,
8917104aeefSMatt Jacob 		    "SPI Port Page 1 Config value bad (%x)- should be %x\n",
8927104aeefSMatt Jacob 		    mpt->mpt_port_page1.Configuration, pp1val);
8937104aeefSMatt Jacob 		tmp = mpt->mpt_port_page1;
8947104aeefSMatt Jacob 		tmp.Configuration = pp1val;
8957104aeefSMatt Jacob 		if (mpt_write_cfg_page(mpt, 0, &tmp.Header)) {
8967104aeefSMatt Jacob 			return (-1);
8977104aeefSMatt Jacob 		}
8987104aeefSMatt Jacob 		if (mpt_read_cfg_page(mpt, 0, &tmp.Header)) {
8997104aeefSMatt Jacob 			return (-1);
9007104aeefSMatt Jacob 		}
9017104aeefSMatt Jacob 		if (tmp.Configuration != pp1val) {
9027104aeefSMatt Jacob 			device_printf(mpt->dev,
9037104aeefSMatt Jacob 			    "failed to reset SPI Port Page 1 Config value\n");
9047104aeefSMatt Jacob 			return (-1);
9057104aeefSMatt Jacob 		}
9067104aeefSMatt Jacob 		mpt->mpt_port_page1 = tmp;
9077104aeefSMatt Jacob 	}
9087104aeefSMatt Jacob 
9097104aeefSMatt Jacob #if	1
9107104aeefSMatt Jacob 	i = i;
9117104aeefSMatt Jacob #else
9127104aeefSMatt Jacob 	for (i = 0; i < 16; i++) {
9137104aeefSMatt Jacob 		fCONFIG_PAGE_SCSI_DEVICE_1 tmp;
9147104aeefSMatt Jacob 		tmp = mpt->mpt_dev_page1[i];
9157104aeefSMatt Jacob 		tmp.RequestedParameters = 0;
9167104aeefSMatt Jacob 		tmp.Configuration = 0;
9177104aeefSMatt Jacob 		if (mpt->verbose > 1) {
9187104aeefSMatt Jacob 			device_printf(mpt->dev,
9197104aeefSMatt Jacob 			    "Set Tgt %d SPI DevicePage 1 values to %x 0 %x\n",
9207104aeefSMatt Jacob 			    i, tmp.RequestedParameters, tmp.Configuration);
9217104aeefSMatt Jacob 		}
9227104aeefSMatt Jacob 		if (mpt_write_cfg_page(mpt, i, &tmp.Header)) {
9237104aeefSMatt Jacob 			return (-1);
9247104aeefSMatt Jacob 		}
9257104aeefSMatt Jacob 		if (mpt_read_cfg_page(mpt, i, &tmp.Header)) {
9267104aeefSMatt Jacob 			return (-1);
9277104aeefSMatt Jacob 		}
9287104aeefSMatt Jacob 		mpt->mpt_dev_page1[i] = tmp;
9297104aeefSMatt Jacob 		if (mpt->verbose > 1) {
9307104aeefSMatt Jacob 			device_printf(mpt->dev,
9317104aeefSMatt Jacob 		 	    "SPI Tgt %d Page 1: RParm %x Configuration %x\n", i,
9327104aeefSMatt Jacob 			    mpt->mpt_dev_page1[i].RequestedParameters,
9337104aeefSMatt Jacob 			    mpt->mpt_dev_page1[i].Configuration);
9347104aeefSMatt Jacob 		}
9357104aeefSMatt Jacob 	}
9367104aeefSMatt Jacob #endif
9377104aeefSMatt Jacob 	return (0);
9387104aeefSMatt Jacob }
9397104aeefSMatt Jacob 
9407104aeefSMatt Jacob /*
9417104aeefSMatt Jacob  * Enable IOC port
9427104aeefSMatt Jacob  */
9437104aeefSMatt Jacob static int
9447104aeefSMatt Jacob mpt_send_port_enable(mpt_softc_t *mpt, int port)
9459b631363SMatt Jacob {
9469b631363SMatt Jacob 	int count;
9479b631363SMatt Jacob 	request_t *req;
9489b631363SMatt Jacob 	MSG_PORT_ENABLE *enable_req;
9499b631363SMatt Jacob 
9509b631363SMatt Jacob 	req = mpt_get_request(mpt);
9519b631363SMatt Jacob 
9529b631363SMatt Jacob 	enable_req = req->req_vbuf;
9539b631363SMatt Jacob 	bzero(enable_req, sizeof *enable_req);
9549b631363SMatt Jacob 
9559b631363SMatt Jacob 	enable_req->Function   = MPI_FUNCTION_PORT_ENABLE;
9569b631363SMatt Jacob 	enable_req->MsgContext = req->index | 0x80000000;
9579b631363SMatt Jacob 	enable_req->PortNumber = port;
9589b631363SMatt Jacob 
9599b631363SMatt Jacob 	mpt_check_doorbell(mpt);
9609b631363SMatt Jacob 	if (mpt->verbose > 1) {
9619b631363SMatt Jacob 		device_printf(mpt->dev, "enabling port %d\n", port);
9629b631363SMatt Jacob 	}
9639b631363SMatt Jacob 	mpt_send_cmd(mpt, req);
9649b631363SMatt Jacob 
9659b631363SMatt Jacob 	count = 0;
9669b631363SMatt Jacob 	do {
9679b631363SMatt Jacob 		DELAY(500);
9689b631363SMatt Jacob 		mpt_intr(mpt);
9699b631363SMatt Jacob 		if (++count == 1000) {
9709b631363SMatt Jacob 			device_printf(mpt->dev, "port enable timed out\n");
9719b631363SMatt Jacob 			return (-1);
9729b631363SMatt Jacob 		}
9739b631363SMatt Jacob 	} while (req->debug == REQ_ON_CHIP);
9749b631363SMatt Jacob 	mpt_free_request(mpt, req);
9759b631363SMatt Jacob 	return (0);
9769b631363SMatt Jacob }
9779b631363SMatt Jacob 
9789b631363SMatt Jacob /*
9799b631363SMatt Jacob  * Enable/Disable asynchronous event reporting.
9809b631363SMatt Jacob  *
9819b631363SMatt Jacob  * NB: this is the first command we send via shared memory
9829b631363SMatt Jacob  * instead of the handshake register.
9839b631363SMatt Jacob  */
9849b631363SMatt Jacob static int
9857104aeefSMatt Jacob mpt_send_event_request(mpt_softc_t *mpt, int onoff)
9869b631363SMatt Jacob {
9879b631363SMatt Jacob 	request_t *req;
9889b631363SMatt Jacob 	MSG_EVENT_NOTIFY *enable_req;
9899b631363SMatt Jacob 
9909b631363SMatt Jacob 	req = mpt_get_request(mpt);
9919b631363SMatt Jacob 
9929b631363SMatt Jacob 	enable_req = req->req_vbuf;
9939b631363SMatt Jacob 	bzero(enable_req, sizeof *enable_req);
9949b631363SMatt Jacob 
9959b631363SMatt Jacob 	enable_req->Function   = MPI_FUNCTION_EVENT_NOTIFICATION;
9969b631363SMatt Jacob 	enable_req->MsgContext = req->index | 0x80000000;
9979b631363SMatt Jacob 	enable_req->Switch     = onoff;
9989b631363SMatt Jacob 
9999b631363SMatt Jacob 	mpt_check_doorbell(mpt);
10009b631363SMatt Jacob 	if (mpt->verbose > 1) {
10019b631363SMatt Jacob 		device_printf(mpt->dev, "%sabling async events\n",
10029b631363SMatt Jacob 		    onoff? "en" : "dis");
10039b631363SMatt Jacob 	}
10049b631363SMatt Jacob 	mpt_send_cmd(mpt, req);
10059b631363SMatt Jacob 
10069b631363SMatt Jacob 	return (0);
10079b631363SMatt Jacob }
10089b631363SMatt Jacob 
10099b631363SMatt Jacob /*
10109b631363SMatt Jacob  * Un-mask the interupts on the chip.
10119b631363SMatt Jacob  */
10129b631363SMatt Jacob void
10137104aeefSMatt Jacob mpt_enable_ints(mpt_softc_t *mpt)
10149b631363SMatt Jacob {
10159b631363SMatt Jacob 	/* Unmask every thing except door bell int */
10169b631363SMatt Jacob 	mpt_write(mpt, MPT_OFFSET_INTR_MASK, MPT_INTR_DB_MASK);
10179b631363SMatt Jacob }
10189b631363SMatt Jacob 
10199b631363SMatt Jacob /*
10209b631363SMatt Jacob  * Mask the interupts on the chip.
10219b631363SMatt Jacob  */
10229b631363SMatt Jacob void
10237104aeefSMatt Jacob mpt_disable_ints(mpt_softc_t *mpt)
10249b631363SMatt Jacob {
10259b631363SMatt Jacob 	/* Mask all interrupts */
10269b631363SMatt Jacob 	mpt_write(mpt, MPT_OFFSET_INTR_MASK,
10279b631363SMatt Jacob 	    MPT_INTR_REPLY_MASK | MPT_INTR_DB_MASK);
10289b631363SMatt Jacob }
10299b631363SMatt Jacob 
10309b631363SMatt Jacob /* (Re)Initialize the chip for use */
10319b631363SMatt Jacob int
10327104aeefSMatt Jacob mpt_init(mpt_softc_t *mpt, u_int32_t who)
10339b631363SMatt Jacob {
10349b631363SMatt Jacob         int try;
10359b631363SMatt Jacob         MSG_IOC_FACTS_REPLY facts;
10367104aeefSMatt Jacob         MSG_PORT_FACTS_REPLY pfp;
10379b631363SMatt Jacob 	u_int32_t pptr;
10389b631363SMatt Jacob         int val;
10399b631363SMatt Jacob 
10409b631363SMatt Jacob 	/* Put all request buffers (back) on the free list */
10419b631363SMatt Jacob         SLIST_INIT(&mpt->request_free_list);
10429b631363SMatt Jacob 	for (val = 0; val < MPT_MAX_REQUESTS; val++) {
10439b631363SMatt Jacob 		mpt_free_request(mpt, &mpt->requests[val]);
10449b631363SMatt Jacob 	}
10459b631363SMatt Jacob 
10469b631363SMatt Jacob 	if (mpt->verbose > 1) {
10479b631363SMatt Jacob 		device_printf(mpt->dev, "doorbell req = %s\n",
10489b631363SMatt Jacob 		    mpt_ioc_diag(mpt_read(mpt, MPT_OFFSET_DOORBELL)));
10499b631363SMatt Jacob 	}
10509b631363SMatt Jacob 
10519b631363SMatt Jacob 	/*
10529b631363SMatt Jacob 	 * Start by making sure we're not at FAULT or RESET state
10539b631363SMatt Jacob 	 */
10549b631363SMatt Jacob 	switch (mpt_rd_db(mpt) & MPT_DB_STATE_MASK) {
10559b631363SMatt Jacob 	case MPT_DB_STATE_RESET:
10569b631363SMatt Jacob 	case MPT_DB_STATE_FAULT:
10579b631363SMatt Jacob 		if (mpt_reset(mpt) != MPT_OK) {
10589b631363SMatt Jacob 			return (EIO);
10599b631363SMatt Jacob 		}
10609b631363SMatt Jacob 	default:
10619b631363SMatt Jacob 		break;
10629b631363SMatt Jacob 	}
10639b631363SMatt Jacob 
10649b631363SMatt Jacob 
10659b631363SMatt Jacob 	for (try = 0; try < MPT_MAX_TRYS; try++) {
10669b631363SMatt Jacob 		/*
10679b631363SMatt Jacob 		 * No need to reset if the IOC is already in the READY state.
10689b631363SMatt Jacob 		 *
10699b631363SMatt Jacob 		 * Force reset if initialization failed previously.
10709b631363SMatt Jacob 		 * Note that a hard_reset of the second channel of a '929
10719b631363SMatt Jacob 		 * will stop operation of the first channel.  Hopefully, if the
10729b631363SMatt Jacob 		 * first channel is ok, the second will not require a hard
10739b631363SMatt Jacob 		 * reset.
10749b631363SMatt Jacob 		 */
10759b631363SMatt Jacob 		if ((mpt_rd_db(mpt) & MPT_DB_STATE_MASK) !=
10769b631363SMatt Jacob 		    MPT_DB_STATE_READY) {
10779b631363SMatt Jacob 			if (mpt_reset(mpt) != MPT_OK) {
10789b631363SMatt Jacob 				DELAY(10000);
10799b631363SMatt Jacob 				continue;
10809b631363SMatt Jacob 			}
10819b631363SMatt Jacob 		}
10829b631363SMatt Jacob 
10839b631363SMatt Jacob 		if (mpt_get_iocfacts(mpt, &facts) != MPT_OK) {
10849b631363SMatt Jacob 			device_printf(mpt->dev, "mpt_get_iocfacts failed\n");
10859b631363SMatt Jacob 			continue;
10867104aeefSMatt Jacob 		}
10877104aeefSMatt Jacob 
10887104aeefSMatt Jacob 		if (mpt->verbose > 1) {
10899b631363SMatt Jacob 			device_printf(mpt->dev,
10909b631363SMatt Jacob 			    "mpt_get_iocfacts: GlobalCredits=%d BlockSize=%u "
10919b631363SMatt Jacob 			    "Request Frame Size %u\n", facts.GlobalCredits,
10929b631363SMatt Jacob 			    facts.BlockSize, facts.RequestFrameSize);
10939b631363SMatt Jacob 		}
10949b631363SMatt Jacob 		mpt->mpt_global_credits = facts.GlobalCredits;
10959b631363SMatt Jacob 		mpt->request_frame_size = facts.RequestFrameSize;
10969b631363SMatt Jacob 
10977104aeefSMatt Jacob 		if (mpt_get_portfacts(mpt, &pfp) != MPT_OK) {
10987104aeefSMatt Jacob 			device_printf(mpt->dev, "mpt_get_portfacts failed\n");
10997104aeefSMatt Jacob 			continue;
11007104aeefSMatt Jacob 		}
11017104aeefSMatt Jacob 
11027104aeefSMatt Jacob 		if (mpt->verbose > 1) {
11037104aeefSMatt Jacob 			device_printf(mpt->dev,
11047104aeefSMatt Jacob 			    "mpt_get_portfacts: Type %x PFlags %x IID %d\n",
11057104aeefSMatt Jacob 			    pfp.PortType, pfp.ProtocolFlags, pfp.PortSCSIID);
11067104aeefSMatt Jacob 		}
11077104aeefSMatt Jacob 
11087104aeefSMatt Jacob 		if (pfp.PortType != MPI_PORTFACTS_PORTTYPE_SCSI &&
11097104aeefSMatt Jacob 		    pfp.PortType != MPI_PORTFACTS_PORTTYPE_FC) {
11107104aeefSMatt Jacob 			device_printf(mpt->dev, "Unsupported Port Type (%x)\n",
11117104aeefSMatt Jacob 			    pfp.PortType);
11127104aeefSMatt Jacob 			return (ENXIO);
11137104aeefSMatt Jacob 		}
11147104aeefSMatt Jacob 		if (!(pfp.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)) {
11157104aeefSMatt Jacob 			device_printf(mpt->dev, "initiator role unsupported\n");
11167104aeefSMatt Jacob 			return (ENXIO);
11177104aeefSMatt Jacob 		}
11187104aeefSMatt Jacob 		if (pfp.PortType == MPI_PORTFACTS_PORTTYPE_FC) {
11197104aeefSMatt Jacob 			mpt->is_fc = 1;
11207104aeefSMatt Jacob 		} else {
11217104aeefSMatt Jacob 			mpt->is_fc = 0;
11227104aeefSMatt Jacob 		}
11237104aeefSMatt Jacob 		mpt->mpt_ini_id = pfp.PortSCSIID;
11247104aeefSMatt Jacob 
11259b631363SMatt Jacob 		if (mpt_send_ioc_init(mpt, who) != MPT_OK) {
11269b631363SMatt Jacob 			device_printf(mpt->dev, "mpt_send_ioc_init failed\n");
11279b631363SMatt Jacob 			continue;
11287104aeefSMatt Jacob 		}
11297104aeefSMatt Jacob 
11307104aeefSMatt Jacob 		if (mpt->verbose > 1) {
11319b631363SMatt Jacob 			device_printf(mpt->dev, "mpt_send_ioc_init ok\n");
11329b631363SMatt Jacob 		}
11339b631363SMatt Jacob 
11349b631363SMatt Jacob 		if (mpt_wait_state(mpt, MPT_DB_STATE_RUNNING) != MPT_OK) {
11359b631363SMatt Jacob 			device_printf(mpt->dev,
11369b631363SMatt Jacob 			    "IOC failed to go to run state\n");
11379b631363SMatt Jacob 			continue;
11387104aeefSMatt Jacob 		}
11397104aeefSMatt Jacob 		if (mpt->verbose > 1) {
11409b631363SMatt Jacob 			device_printf(mpt->dev, "IOC now at RUNSTATE\n");
11419b631363SMatt Jacob 		}
11429b631363SMatt Jacob 
11439b631363SMatt Jacob 		/*
11449b631363SMatt Jacob 		 * Give it reply buffers
11459b631363SMatt Jacob 		 *
11469b631363SMatt Jacob 		 * Do *not* except global credits.
11479b631363SMatt Jacob 		 */
11489b631363SMatt Jacob 		for (val = 0, pptr = mpt->reply_phys;
11499b631363SMatt Jacob 		    (pptr + MPT_REPLY_SIZE) < (mpt->reply_phys + PAGE_SIZE);
11509b631363SMatt Jacob 		     pptr += MPT_REPLY_SIZE) {
11519b631363SMatt Jacob 			mpt_free_reply(mpt, pptr);
11529b631363SMatt Jacob 			if (++val == mpt->mpt_global_credits - 1)
11539b631363SMatt Jacob 				break;
11549b631363SMatt Jacob 		}
11559b631363SMatt Jacob 
11567104aeefSMatt Jacob 		/*
11577104aeefSMatt Jacob 		 * Enable asynchronous event reporting
11587104aeefSMatt Jacob 		 */
11599b631363SMatt Jacob 		mpt_send_event_request(mpt, 1);
11609b631363SMatt Jacob 
11617104aeefSMatt Jacob 
11627104aeefSMatt Jacob 		/*
11637104aeefSMatt Jacob 		 * Read set up initial configuration information
11647104aeefSMatt Jacob 		 * (SPI only for now)
11657104aeefSMatt Jacob 		 */
11667104aeefSMatt Jacob 
11677104aeefSMatt Jacob 		if (mpt->is_fc == 0) {
11687104aeefSMatt Jacob 			if (mpt_read_config_info_spi(mpt)) {
11697104aeefSMatt Jacob 				return (EIO);
11707104aeefSMatt Jacob 			}
11717104aeefSMatt Jacob 			if (mpt_set_initial_config_spi(mpt)) {
11727104aeefSMatt Jacob 				return (EIO);
11737104aeefSMatt Jacob 			}
11747104aeefSMatt Jacob 		}
11757104aeefSMatt Jacob 
11767104aeefSMatt Jacob 		/*
11777104aeefSMatt Jacob 		 * Now enable the port
11787104aeefSMatt Jacob 		 */
11799b631363SMatt Jacob 		if (mpt_send_port_enable(mpt, 0) != MPT_OK) {
11809b631363SMatt Jacob 			device_printf(mpt->dev, "failed to enable port 0\n");
11819b631363SMatt Jacob 			continue;
11827104aeefSMatt Jacob 		}
11837104aeefSMatt Jacob 
11847104aeefSMatt Jacob 		if (mpt->verbose > 1) {
11859b631363SMatt Jacob 			device_printf(mpt->dev, "enabled port 0\n");
11869b631363SMatt Jacob 		}
11879b631363SMatt Jacob 
11889b631363SMatt Jacob 		/* Everything worked */
11899b631363SMatt Jacob 		break;
11909b631363SMatt Jacob 	}
11919b631363SMatt Jacob 
11929b631363SMatt Jacob 	if (try >= MPT_MAX_TRYS) {
11939b631363SMatt Jacob 		device_printf(mpt->dev, "failed to initialize IOC\n");
11949b631363SMatt Jacob 		return (EIO);
11959b631363SMatt Jacob 	}
11969b631363SMatt Jacob 
11979b631363SMatt Jacob 	if (mpt->verbose > 1) {
11989b631363SMatt Jacob 		device_printf(mpt->dev, "enabling interrupts\n");
11999b631363SMatt Jacob 	}
12009b631363SMatt Jacob 
12019b631363SMatt Jacob 	mpt_enable_ints(mpt);
12029b631363SMatt Jacob 	return (0);
12039b631363SMatt Jacob }
1204