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