mpt.c revision 134123
12061Sjkh/*
218434Sache * Generic routines for LSI '909 FC  adapters.
32061Sjkh * FreeBSD Version.
42061Sjkh *
515603Smarkm * Copyright (c) 2000, 2001 by Greg Ansley
62061Sjkh *
72061Sjkh * Redistribution and use in source and binary forms, with or without
83197Scsgr * modification, are permitted provided that the following conditions
93197Scsgr * are met:
102061Sjkh * 1. Redistributions of source code must retain the above copyright
1112483Speter *    notice immediately at the beginning of the file, without modification,
122160Scsgr *    this list of conditions, and the following disclaimer.
132834Swollman * 2. The name of the author may not be used to endorse or promote products
142061Sjkh *    derived from this software without specific prior written permission.
152061Sjkh *
162160Scsgr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1717308Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
181594Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1917308Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2017308Speter * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2117308Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2217308Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2317308Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2417308Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2517308Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2617308Speter * SUCH DAMAGE.
2717308Speter */
2817308Speter/*
2917308Speter * Additional Copyright (c) 2002 by Matthew Jacob under same license.
302061Sjkh */
312061Sjkh
321594Srgrimes#include <sys/cdefs.h>
337407Srgrimes__FBSDID("$FreeBSD: head/sys/dev/mpt/mpt.c 134123 2004-08-21 17:44:57Z obrien $");
347407Srgrimes
357108Sphk#include <dev/mpt/mpt_freebsd.h>
367108Sphk
377108Sphk#define MPT_MAX_TRYS 3
387407Srgrimes#define MPT_MAX_WAIT 300000
397407Srgrimes
407407Srgrimesstatic int maxwait_ack = 0;
417108Sphkstatic int maxwait_int = 0;
422061Sjkhstatic int maxwait_state = 0;
432061Sjkh
442061Sjkhstatic INLINE u_int32_t mpt_rd_db(mpt_softc_t *mpt);
4517308Speterstatic INLINE  u_int32_t mpt_rd_intr(mpt_softc_t *mpt);
462061Sjkh
472061Sjkhstatic INLINE u_int32_t
482061Sjkhmpt_rd_db(mpt_softc_t *mpt)
492061Sjkh{
502061Sjkh	return mpt_read(mpt, MPT_OFFSET_DOORBELL);
513197Scsgr}
522626Scsgr
532626Scsgrstatic INLINE u_int32_t
542061Sjkhmpt_rd_intr(mpt_softc_t *mpt)
552061Sjkh{
562061Sjkh	return mpt_read(mpt, MPT_OFFSET_INTR_STATUS);
572061Sjkh}
582061Sjkh
592061Sjkh/* Busy wait for a door bell to be read by IOC */
602061Sjkhstatic int
612061Sjkhmpt_wait_db_ack(mpt_softc_t *mpt)
622061Sjkh{
632061Sjkh	int i;
642061Sjkh	for (i=0; i < MPT_MAX_WAIT; i++) {
652061Sjkh		if (!MPT_DB_IS_BUSY(mpt_rd_intr(mpt))) {
662061Sjkh			maxwait_ack = i > maxwait_ack ? i : maxwait_ack;
672061Sjkh			return MPT_OK;
682061Sjkh		}
692061Sjkh
702061Sjkh		DELAY(100);
712061Sjkh	}
722834Swollman	return MPT_FAIL;
732834Swollman}
742834Swollman
752834Swollman/* Busy wait for a door bell interrupt */
762834Swollmanstatic int
772834Swollmanmpt_wait_db_int(mpt_softc_t *mpt)
781594Srgrimes{
794486Sphk	int i;
804486Sphk	for (i=0; i < MPT_MAX_WAIT; i++) {
814486Sphk		if (MPT_DB_INTR(mpt_rd_intr(mpt))) {
824486Sphk			maxwait_int = i > maxwait_int ? i : maxwait_int;
834486Sphk			return MPT_OK;
842061Sjkh		}
852061Sjkh		DELAY(100);
862061Sjkh	}
872061Sjkh	return MPT_FAIL;
882061Sjkh}
892061Sjkh
902061Sjkh/* Wait for IOC to transition to a give state */
912061Sjkhvoid
922061Sjkhmpt_check_doorbell(mpt_softc_t *mpt)
9317308Speter{
942061Sjkh	u_int32_t db = mpt_rd_db(mpt);
952061Sjkh	if (MPT_STATE(db) != MPT_DB_STATE_RUNNING) {
962061Sjkh		mpt_prt(mpt, "Device not running");
972061Sjkh		mpt_print_db(db);
982061Sjkh	}
9912483Speter}
10012483Speter
10112483Speter/* Wait for IOC to transition to a give state */
10212483Speterstatic int
1032061Sjkhmpt_wait_state(mpt_softc_t *mpt, enum DB_STATE_BITS state)
1042061Sjkh{
1058854Srgrimes	int i;
1062061Sjkh
1072061Sjkh	for (i = 0; i < MPT_MAX_WAIT; i++) {
10812483Speter		u_int32_t db = mpt_rd_db(mpt);
1092061Sjkh		if (MPT_STATE(db) == state) {
11017308Speter			maxwait_state = i > maxwait_state ? i : maxwait_state;
11117308Speter			return (MPT_OK);
11217308Speter		}
11317308Speter		DELAY(100);
11415603Smarkm	}
11515603Smarkm	return (MPT_FAIL);
11617308Speter}
11717308Speter
11817308Speter
11917308Speter/* Issue the reset COMMAND to the IOC */
12017308Speterint
12117308Spetermpt_soft_reset(mpt_softc_t *mpt)
12217308Speter{
12317308Speter	if (mpt->verbose) {
12417308Speter		mpt_prt(mpt, "soft reset");
12518362Sjkh	}
12618434Sache
12718362Sjkh	/* Have to use hard reset if we are not in Running state */
12817308Speter	if (MPT_STATE(mpt_rd_db(mpt)) != MPT_DB_STATE_RUNNING) {
12917308Speter		mpt_prt(mpt, "soft reset failed: device not running");
13017308Speter		return MPT_FAIL;
13117308Speter	}
13217308Speter
13317308Speter	/* If door bell is in use we don't have a chance of getting
13416550Sjkh	 * a word in since the IOC probably crashed in message
1352061Sjkh	 * processing. So don't waste our time.
13617308Speter	 */
1372061Sjkh	if (MPT_DB_IS_IN_USE(mpt_rd_db(mpt))) {
13817308Speter		mpt_prt(mpt, "soft reset failed: doorbell wedged");
1392061Sjkh		return MPT_FAIL;
14017308Speter	}
14117308Speter
14217308Speter	/* Send the reset request to the IOC */
14317308Speter	mpt_write(mpt, MPT_OFFSET_DOORBELL,
14417308Speter	    MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET << MPI_DOORBELL_FUNCTION_SHIFT);
14517308Speter	if (mpt_wait_db_ack(mpt) != MPT_OK) {
14617308Speter		mpt_prt(mpt, "soft reset failed: ack timeout");
14717308Speter		return MPT_FAIL;
14817308Speter	}
14917308Speter
15017308Speter	/* Wait for the IOC to reload and come out of reset state */
15117466Speter	if (mpt_wait_state(mpt, MPT_DB_STATE_READY) != MPT_OK) {
15217308Speter		mpt_prt(mpt, "soft reset failed: device did not start running");
15317308Speter		return MPT_FAIL;
15417466Speter	}
15517308Speter
15617308Speter	return MPT_OK;
15717308Speter}
15817308Speter
15917466Speter/* This is a magic diagnostic reset that resets all the ARM
16017308Speter * processors in the chip.
16117308Speter */
16217308Spetervoid
16317308Spetermpt_hard_reset(mpt_softc_t *mpt)
16417308Speter{
16517308Speter	/* This extra read comes for the Linux source
16617308Speter	 * released by LSI. It's function is undocumented!
16717308Speter	 */
16817308Speter	if (mpt->verbose) {
16917308Speter		mpt_prt(mpt, "hard reset");
17017308Speter	}
17117308Speter	mpt_read(mpt, MPT_OFFSET_FUBAR);
17217308Speter
17317308Speter	/* Enable diagnostic registers */
17417308Speter	mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_1);
17517308Speter	mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_2);
17617308Speter	mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_3);
17717308Speter	mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_4);
17817308Speter	mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_5);
17917308Speter
18017308Speter	/* Diag. port is now active so we can now hit the reset bit */
18117308Speter	mpt_write(mpt, MPT_OFFSET_DIAGNOSTIC, MPT_DIAG_RESET_IOC);
18217308Speter
18317308Speter	DELAY(10000);
18417308Speter
18517308Speter	/* Disable Diagnostic Register */
18617308Speter	mpt_write(mpt, MPT_OFFSET_SEQUENCE, 0xFF);
18718392Speter
18817308Speter	/* Restore the config register values */
18917308Speter	/*   Hard resets are known to screw up the BAR for diagnostic
19017308Speter	     memory accesses (Mem1). */
19117308Speter	mpt_set_config_regs(mpt);
19217962Speter	if (mpt->mpt2 != NULL) {
19317308Speter		mpt_set_config_regs(mpt->mpt2);
19417962Speter	}
19517962Speter
19617962Speter	/* Note that if there is no valid firmware to run, the doorbell will
19717962Speter	   remain in the reset state (0x00000000) */
19817962Speter}
19917962Speter
20017962Speter/*
20117962Speter * Reset the IOC when needed. Try software command first then if needed
20217962Speter * poke at the magic diagnostic reset. Note that a hard reset resets
20317962Speter * *both* IOCs on dual function chips (FC929 && LSI1030) as well as
20417962Speter * fouls up the PCI configuration registers.
20517962Speter */
20617962Speterint
20717962Spetermpt_reset(mpt_softc_t *mpt)
20817962Speter{
20917308Speter	int ret;
21016550Sjkh
21117308Speter	/* Try a soft reset */
21217308Speter	if ((ret = mpt_soft_reset(mpt)) != MPT_OK) {
21317308Speter		/* Failed; do a hard reset */
21417308Speter		mpt_hard_reset(mpt);
21516550Sjkh
21616550Sjkh		/* Wait for the IOC to reload and come out of reset state */
21717308Speter		ret = mpt_wait_state(mpt, MPT_DB_STATE_READY);
21817308Speter		if (ret != MPT_OK) {
21918434Sache			mpt_prt(mpt, "failed to reset device");
22017962Speter		}
2212061Sjkh	}
22217308Speter
22317308Speter	return ret;
22417308Speter}
22517308Speter
22617308Speter/* Return a command buffer to the free queue */
22717308Spetervoid
22817308Spetermpt_free_request(mpt_softc_t *mpt, request_t *req)
22917308Speter{
23012483Speter	if (req == NULL || req != &mpt->request_pool[req->index]) {
23117308Speter		panic("mpt_free_request bad req ptr\n");
23212483Speter		return;
23317308Speter	}
23412483Speter	req->sequence = 0;
2352061Sjkh	req->ccb = NULL;
23617308Speter	req->debug = REQ_FREE;
2372061Sjkh	SLIST_INSERT_HEAD(&mpt->request_free_list, req, link);
23817308Speter}
23917308Speter
24017308Speter/* Get a command buffer from the free queue */
24117308Speterrequest_t *
24217308Spetermpt_get_request(mpt_softc_t *mpt)
24317308Speter{
24417308Speter	request_t *req;
24517308Speter	req = SLIST_FIRST(&mpt->request_free_list);
24617962Speter	if (req != NULL) {
24717308Speter		if (req != &mpt->request_pool[req->index]) {
24817962Speter			panic("mpt_get_request: corrupted request free list\n");
24917308Speter		}
25017962Speter		if (req->ccb != NULL) {
25117962Speter			panic("mpt_get_request: corrupted request free list (ccb)\n");
25217962Speter		}
25317962Speter		SLIST_REMOVE_HEAD(&mpt->request_free_list, link);
25417962Speter		req->debug = REQ_IN_PROGRESS;
25517962Speter	}
25617962Speter	return req;
25717962Speter}
25817308Speter
25917962Speter/* Pass the command to the IOC */
26017962Spetervoid
26117962Spetermpt_send_cmd(mpt_softc_t *mpt, request_t *req)
26217962Speter{
26317308Speter	req->sequence = mpt->sequence++;
2642061Sjkh	if (mpt->verbose > 1) {
26517308Speter		u_int32_t *pReq;
26617308Speter		pReq = req->req_vbuf;
26717308Speter		mpt_prt(mpt, "Send Request %d (0x%x):",
26817308Speter		    req->index, req->req_pbuf);
26917308Speter		mpt_prt(mpt, "%08x %08x %08x %08x",
27017308Speter		    pReq[0], pReq[1], pReq[2], pReq[3]);
27117308Speter		mpt_prt(mpt, "%08x %08x %08x %08x",
2722302Spaul		    pReq[4], pReq[5], pReq[6], pReq[7]);
2732302Spaul		mpt_prt(mpt, "%08x %08x %08x %08x",
2742302Spaul		    pReq[8], pReq[9], pReq[10], pReq[11]);
2752302Spaul		mpt_prt(mpt, "%08x %08x %08x %08x",
2762302Spaul		    pReq[12], pReq[13], pReq[14], pReq[15]);
2772302Spaul	}
27810760Sache	bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap,
27910760Sache	    BUS_DMASYNC_PREWRITE);
2802302Spaul	req->debug = REQ_ON_CHIP;
28110760Sache	mpt_write(mpt, MPT_OFFSET_REQUEST_Q, (u_int32_t) req->req_pbuf);
28210760Sache}
28310760Sache
28410760Sache/*
2852302Spaul * Give the reply buffer back to the IOC after we have
2862302Spaul * finished processing it.
2872302Spaul */
2882302Spaulvoid
28916591Spstmpt_free_reply(mpt_softc_t *mpt, u_int32_t ptr)
2902302Spaul{
2912302Spaul     mpt_write(mpt, MPT_OFFSET_REPLY_Q, ptr);
29217308Speter}
29317308Speter
29417308Speter/* Get a reply from the IOC */
29517308Speteru_int32_t
29617308Spetermpt_pop_reply_queue(mpt_softc_t *mpt)
29717308Speter{
29817308Speter     return mpt_read(mpt, MPT_OFFSET_REPLY_Q);
2992061Sjkh}
30017308Speter
3012061Sjkh/*
30217308Speter * Send a command to the IOC via the handshake register.
30317308Speter *
30417308Speter * Only done at initialization time and for certain unusual
30517308Speter * commands such as device/bus reset as specified by LSI.
30617308Speter */
30717308Speterint
30817308Spetermpt_send_handshake_cmd(mpt_softc_t *mpt, size_t len, void *cmd)
30917308Speter{
31017308Speter	int i;
31117308Speter	u_int32_t data, *data32;
31217308Speter
31317308Speter	/* Check condition of the IOC */
31417308Speter	data = mpt_rd_db(mpt);
31517308Speter	if (((MPT_STATE(data) != MPT_DB_STATE_READY)	&&
3162061Sjkh	     (MPT_STATE(data) != MPT_DB_STATE_RUNNING)	&&
31717308Speter	     (MPT_STATE(data) != MPT_DB_STATE_FAULT))	||
31817308Speter	    (  MPT_DB_IS_IN_USE(data) )) {
31917308Speter		mpt_prt(mpt, "handshake aborted due to invalid doorbell state");
32017308Speter		mpt_print_db(data);
32117308Speter		return(EBUSY);
32217308Speter	}
3233626Swollman
3243626Swollman	/* We move things in 32 bit chunks */
3253626Swollman	len = (len + 3) >> 2;
3263626Swollman	data32 = cmd;
3273626Swollman
3283626Swollman	/* Clear any left over pending doorbell interupts */
3293626Swollman	if (MPT_DB_INTR(mpt_rd_intr(mpt)))
3303626Swollman		mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
3313626Swollman
3323626Swollman	/*
3333626Swollman	 * Tell the handshake reg. we are going to send a command
3347059Sroberto         * and how long it is going to be.
3353626Swollman	 */
3363626Swollman	data = (MPI_FUNCTION_HANDSHAKE << MPI_DOORBELL_FUNCTION_SHIFT) |
3373626Swollman	    (len << MPI_DOORBELL_ADD_DWORDS_SHIFT);
3383626Swollman	mpt_write(mpt, MPT_OFFSET_DOORBELL, data);
3393626Swollman
3403626Swollman	/* Wait for the chip to notice */
3413626Swollman	if (mpt_wait_db_int(mpt) != MPT_OK) {
34217308Speter		mpt_prt(mpt, "mpt_send_handshake_cmd timeout1");
34317308Speter		return ETIMEDOUT;
34417308Speter	}
34517308Speter
34617308Speter	/* Clear the interrupt */
34717308Speter	mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
34817308Speter
34917308Speter	if (mpt_wait_db_ack(mpt) != MPT_OK) {
35017308Speter		mpt_prt(mpt, "mpt_send_handshake_cmd timeout2");
35117308Speter		return ETIMEDOUT;
3523626Swollman	}
35317308Speter
35417308Speter	/* Send the command */
35517308Speter	for (i = 0; i < len; i++) {
35617308Speter		mpt_write(mpt, MPT_OFFSET_DOORBELL, *data32++);
35717308Speter		if (mpt_wait_db_ack(mpt) != MPT_OK) {
35817308Speter			mpt_prt(mpt,
35917308Speter			    "mpt_send_handshake_cmd timeout! index = %d", i);
36017308Speter			return ETIMEDOUT;
36117308Speter		}
3622061Sjkh	}
36316663Sjkh	return MPT_OK;
3642061Sjkh}
36517308Speter
36617308Speter/* Get the response from the handshake register */
36717308Speterint
36817308Spetermpt_recv_handshake_reply(mpt_softc_t *mpt, size_t reply_len, void *reply)
36917308Speter{
37017308Speter	int left, reply_left;
37117820Sjkh	u_int16_t *data16;
37217308Speter	MSG_DEFAULT_REPLY *hdr;
37317820Sjkh
37417308Speter	/* We move things out in 16 bit chunks */
37517820Sjkh	reply_len >>= 1;
37617467Speter	data16 = (u_int16_t *)reply;
37717308Speter
37817308Speter	hdr = (MSG_DEFAULT_REPLY *)reply;
37917308Speter
38017308Speter	/* Get first word */
38117308Speter	if (mpt_wait_db_int(mpt) != MPT_OK) {
38217308Speter		mpt_prt(mpt, "mpt_recv_handshake_cmd timeout1");
38317308Speter		return ETIMEDOUT;
38417308Speter	}
38517820Sjkh	*data16++ = mpt_read(mpt, MPT_OFFSET_DOORBELL) & MPT_DB_DATA_MASK;
38617820Sjkh	mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
38717308Speter
38817308Speter	/* Get Second Word */
38917308Speter	if (mpt_wait_db_int(mpt) != MPT_OK) {
39017308Speter		mpt_prt(mpt, "mpt_recv_handshake_cmd timeout2");
39114119Speter		return ETIMEDOUT;
3922061Sjkh	}
3937130Srgrimes	*data16++ = mpt_read(mpt, MPT_OFFSET_DOORBELL) & MPT_DB_DATA_MASK;
3947130Srgrimes	mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
3957130Srgrimes
3962061Sjkh	/* With the second word, we can now look at the length */
39717962Speter	if (mpt->verbose > 1 && ((reply_len >> 1) != hdr->MsgLength)) {
3982061Sjkh		mpt_prt(mpt, "reply length does not match message length: "
39917308Speter			"got 0x%02x, expected 0x%02x",
4002685Srgrimes			hdr->MsgLength << 2, reply_len << 1);
4016927Snate	}
4022685Srgrimes
4033518Sache	/* Get rest of the reply; but don't overflow the provided buffer */
4043197Scsgr	left = (hdr->MsgLength << 1) - 2;
4053197Scsgr	reply_left =  reply_len - 2;
40612166Sjkh	while (left--) {
40712485Sjkh		u_int16_t datum;
4083197Scsgr
4092061Sjkh		if (mpt_wait_db_int(mpt) != MPT_OK) {
4102061Sjkh			mpt_prt(mpt, "mpt_recv_handshake_cmd timeout3");
4112061Sjkh			return ETIMEDOUT;
41216786Snate		}
4132883Sphk		datum = mpt_read(mpt, MPT_OFFSET_DOORBELL);
41417308Speter
41517308Speter		if (reply_left-- > 0)
4167281Srgrimes			*data16++ = datum & MPT_DB_DATA_MASK;
4173242Spaul
4183242Spaul		mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
4197171Sats	}
4202061Sjkh
4213213Spst	/* One more wait & clear at the end */
42217308Speter	if (mpt_wait_db_int(mpt) != MPT_OK) {
42317308Speter		mpt_prt(mpt, "mpt_recv_handshake_cmd timeout4");
4245749Swollman		return ETIMEDOUT;
4255772Swollman	}
42617308Speter	mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
42717308Speter
4282061Sjkh	if ((hdr->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
42917308Speter		if (mpt->verbose > 1)
43017308Speter			mpt_print_reply(hdr);
43117308Speter		return (MPT_FAIL | hdr->IOCStatus);
4325366Snate	}
43317820Sjkh
43417467Speter	return (0);
43517820Sjkh}
43617308Speter
43717820Sjkhstatic int
43817308Spetermpt_get_iocfacts(mpt_softc_t *mpt, MSG_IOC_FACTS_REPLY *freplp)
43917820Sjkh{
44017308Speter	MSG_IOC_FACTS f_req;
44117820Sjkh	int error;
44217308Speter
44317820Sjkh	bzero(&f_req, sizeof f_req);
44417308Speter	f_req.Function = MPI_FUNCTION_IOC_FACTS;
44517820Sjkh	f_req.MsgContext =  0x12071942;
44617308Speter	error = mpt_send_handshake_cmd(mpt, sizeof f_req, &f_req);
4475728Swollman	if (error)
44817820Sjkh		return(error);
44917308Speter	error = mpt_recv_handshake_reply(mpt, sizeof (*freplp), freplp);
45018392Speter	return (error);
45118392Speter}
45218392Speter
45318392Speterstatic int
45418392Spetermpt_get_portfacts(mpt_softc_t *mpt, MSG_PORT_FACTS_REPLY *freplp)
45518392Speter{
4565366Snate	MSG_PORT_FACTS f_req;
45717308Speter	int error;
45817308Speter
45917308Speter	/* XXX: Only getting PORT FACTS for Port 0 */
4602061Sjkh	bzero(&f_req, sizeof f_req);
4618295Srgrimes	f_req.Function = MPI_FUNCTION_PORT_FACTS;
46217820Sjkh	f_req.MsgContext =  0x12071943;
46317308Speter	error = mpt_send_handshake_cmd(mpt, sizeof f_req, &f_req);
4648295Srgrimes	if (error)
4658489Srgrimes		return(error);
46617820Sjkh	error = mpt_recv_handshake_reply(mpt, sizeof (*freplp), freplp);
46717308Speter	return (error);
4688489Srgrimes}
4698489Srgrimes
47017820Sjkh/*
47117308Speter * Send the initialization request. This is where we specify how many
4728489Srgrimes * SCSI busses and how many devices per bus we wish to emulate.
47317308Speter * This is also the command that specifies the max size of the reply
47417820Sjkh * frames from the IOC that we will be allocating.
47517308Speter */
47617308Speterstatic int
4778295Srgrimesmpt_send_ioc_init(mpt_softc_t *mpt, u_int32_t who)
47817820Sjkh{
47917308Speter	int error = 0;
4808295Srgrimes	MSG_IOC_INIT init;
4812160Scsgr	MSG_IOC_INIT_REPLY reply;
48217820Sjkh
48317308Speter	bzero(&init, sizeof init);
4842160Scsgr	init.WhoInit = who;
4852279Spaul	init.Function = MPI_FUNCTION_IOC_INIT;
48617820Sjkh	if (mpt->is_fc) {
48717308Speter		init.MaxDevices = 255;
4882279Spaul	} else {
48917234Sjraynard		init.MaxDevices = 16;
49017820Sjkh	}
49117308Speter	init.MaxBuses = 1;
49211772Snate	init.ReplyFrameSize = MPT_REPLY_SIZE;
4933197Scsgr	init.MsgContext = 0x12071941;
49417820Sjkh
49517308Speter	if ((error = mpt_send_handshake_cmd(mpt, sizeof init, &init)) != 0) {
4962626Scsgr		return(error);
4978304Srgrimes	}
49817820Sjkh
49917308Speter	error = mpt_recv_handshake_reply(mpt, sizeof reply, &reply);
5008304Srgrimes	return (error);
5012061Sjkh}
50217308Speter
50317308Speter
50417308Speter/*
50517308Speter * Utiltity routine to read configuration headers and pages
50611806Sphk */
50717820Sjkh
50817308Speterstatic int
50918204Sjfiebermpt_read_cfg_header(mpt_softc_t *, int, int, int, CONFIG_PAGE_HEADER *);
51018204Sjfieber
51117820Sjkhstatic int
51217308Spetermpt_read_cfg_header(mpt_softc_t *mpt, int PageType, int PageNumber,
51317820Sjkh    int PageAddress, CONFIG_PAGE_HEADER *rslt)
51417308Speter{
51517820Sjkh	int count;
51617308Speter	request_t *req;
51718362Sjkh	MSG_CONFIG *cfgp;
51818362Sjkh	MSG_CONFIG_REPLY *reply;
5192061Sjkh
5201594Srgrimes	req = mpt_get_request(mpt);
521
522	cfgp = req->req_vbuf;
523	bzero(cfgp, sizeof *cfgp);
524
525	cfgp->Action = MPI_CONFIG_ACTION_PAGE_HEADER;
526	cfgp->Function = MPI_FUNCTION_CONFIG;
527	cfgp->Header.PageNumber = (U8) PageNumber;
528	cfgp->Header.PageType = (U8) PageType;
529	cfgp->PageAddress = PageAddress;
530	MPI_pSGE_SET_FLAGS(((SGE_SIMPLE32 *) &cfgp->PageBufferSGE),
531	    (MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
532	    MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_LIST));
533	cfgp->MsgContext = req->index | 0x80000000;
534
535	mpt_check_doorbell(mpt);
536	mpt_send_cmd(mpt, req);
537	count = 0;
538	do {
539		DELAY(500);
540		mpt_intr(mpt);
541		if (++count == 1000) {
542			mpt_prt(mpt, "read_cfg_header timed out");
543			return (-1);
544		}
545	} while (req->debug == REQ_ON_CHIP);
546
547	reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence);
548        if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
549		mpt_prt(mpt, "mpt_read_cfg_header: Config Info Status %x",
550		    reply->IOCStatus);
551		mpt_free_reply(mpt, (req->sequence << 1));
552		return (-1);
553	}
554	bcopy(&reply->Header, rslt, sizeof (CONFIG_PAGE_HEADER));
555	mpt_free_reply(mpt, (req->sequence << 1));
556	mpt_free_request(mpt, req);
557	return (0);
558}
559
560#define	CFG_DATA_OFF	128
561
562int
563mpt_read_cfg_page(mpt_softc_t *mpt, int PageAddress, CONFIG_PAGE_HEADER *hdr)
564{
565	int count;
566	request_t *req;
567	SGE_SIMPLE32 *se;
568	MSG_CONFIG *cfgp;
569	size_t amt;
570	MSG_CONFIG_REPLY *reply;
571
572	req = mpt_get_request(mpt);
573
574	cfgp = req->req_vbuf;
575	bzero(cfgp, MPT_REQUEST_AREA);
576	cfgp->Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
577	cfgp->Function = MPI_FUNCTION_CONFIG;
578	cfgp->Header = *hdr;
579 	amt = (cfgp->Header.PageLength * sizeof (u_int32_t));
580	cfgp->Header.PageType &= MPI_CONFIG_PAGETYPE_MASK;
581	cfgp->PageAddress = PageAddress;
582	se = (SGE_SIMPLE32 *) &cfgp->PageBufferSGE;
583	se->Address = req->req_pbuf + CFG_DATA_OFF;
584	MPI_pSGE_SET_LENGTH(se, amt);
585	MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
586	    MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
587	    MPI_SGE_FLAGS_END_OF_LIST));
588
589	cfgp->MsgContext = req->index | 0x80000000;
590
591	mpt_check_doorbell(mpt);
592	mpt_send_cmd(mpt, req);
593	count = 0;
594	do {
595		DELAY(500);
596		mpt_intr(mpt);
597		if (++count == 1000) {
598			mpt_prt(mpt, "read_cfg_page timed out");
599			return (-1);
600		}
601	} while (req->debug == REQ_ON_CHIP);
602
603	reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence);
604        if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
605		mpt_prt(mpt, "mpt_read_cfg_page: Config Info Status %x",
606		    reply->IOCStatus);
607		mpt_free_reply(mpt, (req->sequence << 1));
608		return (-1);
609	}
610	mpt_free_reply(mpt, (req->sequence << 1));
611	bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap,
612	    BUS_DMASYNC_POSTREAD);
613	if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
614	    cfgp->Header.PageNumber == 0) {
615		amt = sizeof (CONFIG_PAGE_SCSI_PORT_0);
616	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
617	    cfgp->Header.PageNumber == 1) {
618		amt = sizeof (CONFIG_PAGE_SCSI_PORT_1);
619	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
620	    cfgp->Header.PageNumber == 2) {
621		amt = sizeof (CONFIG_PAGE_SCSI_PORT_2);
622	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE  &&
623	    cfgp->Header.PageNumber == 0) {
624		amt = sizeof (CONFIG_PAGE_SCSI_DEVICE_0);
625	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE  &&
626	    cfgp->Header.PageNumber == 1) {
627		amt = sizeof (CONFIG_PAGE_SCSI_DEVICE_1);
628	}
629	bcopy(((caddr_t)req->req_vbuf)+CFG_DATA_OFF, hdr, amt);
630	mpt_free_request(mpt, req);
631	return (0);
632}
633
634int
635mpt_write_cfg_page(mpt_softc_t *mpt, int PageAddress, CONFIG_PAGE_HEADER *hdr)
636{
637	int count, hdr_attr;
638	request_t *req;
639	SGE_SIMPLE32 *se;
640	MSG_CONFIG *cfgp;
641	size_t amt;
642	MSG_CONFIG_REPLY *reply;
643
644	req = mpt_get_request(mpt);
645
646	cfgp = req->req_vbuf;
647	bzero(cfgp, sizeof *cfgp);
648
649	hdr_attr = hdr->PageType & MPI_CONFIG_PAGEATTR_MASK;
650	if (hdr_attr != MPI_CONFIG_PAGEATTR_CHANGEABLE &&
651	    hdr_attr != MPI_CONFIG_PAGEATTR_PERSISTENT) {
652		mpt_prt(mpt, "page type 0x%x not changeable",
653		    hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
654		return (-1);
655	}
656	hdr->PageType &= MPI_CONFIG_PAGETYPE_MASK;
657
658	cfgp->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
659	cfgp->Function = MPI_FUNCTION_CONFIG;
660	cfgp->Header = *hdr;
661 	amt = (cfgp->Header.PageLength * sizeof (u_int32_t));
662	cfgp->PageAddress = PageAddress;
663
664	se = (SGE_SIMPLE32 *) &cfgp->PageBufferSGE;
665	se->Address = req->req_pbuf + CFG_DATA_OFF;
666	MPI_pSGE_SET_LENGTH(se, amt);
667	MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
668	    MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
669	    MPI_SGE_FLAGS_END_OF_LIST | MPI_SGE_FLAGS_HOST_TO_IOC));
670
671	cfgp->MsgContext = req->index | 0x80000000;
672
673	if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
674	    cfgp->Header.PageNumber == 0) {
675		amt = sizeof (CONFIG_PAGE_SCSI_PORT_0);
676	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
677	    cfgp->Header.PageNumber == 1) {
678		amt = sizeof (CONFIG_PAGE_SCSI_PORT_1);
679	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
680	    cfgp->Header.PageNumber == 2) {
681		amt = sizeof (CONFIG_PAGE_SCSI_PORT_2);
682	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE  &&
683	    cfgp->Header.PageNumber == 0) {
684		amt = sizeof (CONFIG_PAGE_SCSI_DEVICE_0);
685	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE  &&
686	    cfgp->Header.PageNumber == 1) {
687		amt = sizeof (CONFIG_PAGE_SCSI_DEVICE_1);
688	}
689	bcopy(hdr, ((caddr_t)req->req_vbuf)+CFG_DATA_OFF, amt);
690	/* Restore stripped out attributes */
691	hdr->PageType |= hdr_attr;
692
693	mpt_check_doorbell(mpt);
694	mpt_send_cmd(mpt, req);
695	count = 0;
696	do {
697		DELAY(500);
698		mpt_intr(mpt);
699		if (++count == 1000) {
700			hdr->PageType |= hdr_attr;
701			mpt_prt(mpt, "mpt_write_cfg_page timed out");
702			return (-1);
703		}
704	} while (req->debug == REQ_ON_CHIP);
705
706	reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence);
707        if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
708		mpt_prt(mpt, "mpt_write_cfg_page: Config Info Status %x",
709		    reply->IOCStatus);
710		mpt_free_reply(mpt, (req->sequence << 1));
711		return (-1);
712	}
713	mpt_free_reply(mpt, (req->sequence << 1));
714
715	mpt_free_request(mpt, req);
716	return (0);
717}
718
719/*
720 * Read SCSI configuration information
721 */
722static int
723mpt_read_config_info_spi(mpt_softc_t *mpt)
724{
725	int rv, i;
726
727	rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 0,
728	    0, &mpt->mpt_port_page0.Header);
729	if (rv) {
730		return (-1);
731	}
732	if (mpt->verbose > 1) {
733		mpt_prt(mpt, "SPI Port Page 0 Header: %x %x %x %x",
734		    mpt->mpt_port_page0.Header.PageVersion,
735		    mpt->mpt_port_page0.Header.PageLength,
736		    mpt->mpt_port_page0.Header.PageNumber,
737		    mpt->mpt_port_page0.Header.PageType);
738	}
739
740	rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 1,
741	    0, &mpt->mpt_port_page1.Header);
742	if (rv) {
743		return (-1);
744	}
745	if (mpt->verbose > 1) {
746		mpt_prt(mpt, "SPI Port Page 1 Header: %x %x %x %x",
747		    mpt->mpt_port_page1.Header.PageVersion,
748		    mpt->mpt_port_page1.Header.PageLength,
749		    mpt->mpt_port_page1.Header.PageNumber,
750		    mpt->mpt_port_page1.Header.PageType);
751	}
752
753	rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 2,
754	    0, &mpt->mpt_port_page2.Header);
755	if (rv) {
756		return (-1);
757	}
758
759	if (mpt->verbose > 1) {
760		mpt_prt(mpt, "SPI Port Page 2 Header: %x %x %x %x",
761		    mpt->mpt_port_page1.Header.PageVersion,
762		    mpt->mpt_port_page1.Header.PageLength,
763		    mpt->mpt_port_page1.Header.PageNumber,
764		    mpt->mpt_port_page1.Header.PageType);
765	}
766
767	for (i = 0; i < 16; i++) {
768		rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE,
769		    0, i, &mpt->mpt_dev_page0[i].Header);
770		if (rv) {
771			return (-1);
772		}
773		if (mpt->verbose > 1) {
774			mpt_prt(mpt,
775			    "SPI Target %d Device Page 0 Header: %x %x %x %x",
776			    i, mpt->mpt_dev_page0[i].Header.PageVersion,
777			    mpt->mpt_dev_page0[i].Header.PageLength,
778			    mpt->mpt_dev_page0[i].Header.PageNumber,
779			    mpt->mpt_dev_page0[i].Header.PageType);
780		}
781
782		rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE,
783		    1, i, &mpt->mpt_dev_page1[i].Header);
784		if (rv) {
785			return (-1);
786		}
787		if (mpt->verbose > 1) {
788			mpt_prt(mpt,
789			    "SPI Target %d Device Page 1 Header: %x %x %x %x",
790			    i, mpt->mpt_dev_page1[i].Header.PageVersion,
791			    mpt->mpt_dev_page1[i].Header.PageLength,
792			    mpt->mpt_dev_page1[i].Header.PageNumber,
793			    mpt->mpt_dev_page1[i].Header.PageType);
794		}
795	}
796
797	/*
798	 * At this point, we don't *have* to fail. As long as we have
799	 * valid config header information, we can (barely) lurch
800	 * along.
801	 */
802
803	rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page0.Header);
804	if (rv) {
805		mpt_prt(mpt, "failed to read SPI Port Page 0");
806	} else if (mpt->verbose > 1) {
807		mpt_prt(mpt,
808		    "SPI Port Page 0: Capabilities %x PhysicalInterface %x",
809		    mpt->mpt_port_page0.Capabilities,
810		    mpt->mpt_port_page0.PhysicalInterface);
811	}
812
813	rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page1.Header);
814	if (rv) {
815		mpt_prt(mpt, "failed to read SPI Port Page 1");
816	} else if (mpt->verbose > 1) {
817		mpt_prt(mpt,
818		    "SPI Port Page 1: Configuration %x OnBusTimerValue %x",
819		    mpt->mpt_port_page1.Configuration,
820		    mpt->mpt_port_page1.OnBusTimerValue);
821	}
822
823	rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page2.Header);
824	if (rv) {
825		mpt_prt(mpt, "failed to read SPI Port Page 2");
826	} else if (mpt->verbose > 1) {
827		mpt_prt(mpt,
828		    "SPI Port Page 2: Flags %x Settings %x",
829		    mpt->mpt_port_page2.PortFlags,
830		    mpt->mpt_port_page2.PortSettings);
831		for (i = 0; i < 16; i++) {
832			mpt_prt(mpt,
833		  	    "SPI Port Page 2 Tgt %d: timo %x SF %x Flags %x",
834			    i, mpt->mpt_port_page2.DeviceSettings[i].Timeout,
835			    mpt->mpt_port_page2.DeviceSettings[i].SyncFactor,
836			    mpt->mpt_port_page2.DeviceSettings[i].DeviceFlags);
837		}
838	}
839
840	for (i = 0; i < 16; i++) {
841		rv = mpt_read_cfg_page(mpt, i, &mpt->mpt_dev_page0[i].Header);
842		if (rv) {
843			mpt_prt(mpt, "cannot read SPI Tgt %d Device Page 0", i);
844			continue;
845		}
846		if (mpt->verbose > 1) {
847			mpt_prt(mpt,
848			    "SPI Tgt %d Page 0: NParms %x Information %x",
849			    i, mpt->mpt_dev_page0[i].NegotiatedParameters,
850			    mpt->mpt_dev_page0[i].Information);
851		}
852		rv = mpt_read_cfg_page(mpt, i, &mpt->mpt_dev_page1[i].Header);
853		if (rv) {
854			mpt_prt(mpt, "cannot read SPI Tgt %d Device Page 1", i);
855			continue;
856		}
857		if (mpt->verbose > 1) {
858			mpt_prt(mpt,
859			    "SPI Tgt %d Page 1: RParms %x Configuration %x",
860			    i, mpt->mpt_dev_page1[i].RequestedParameters,
861			    mpt->mpt_dev_page1[i].Configuration);
862		}
863	}
864	return (0);
865}
866
867/*
868 * Validate SPI configuration information.
869 *
870 * In particular, validate SPI Port Page 1.
871 */
872static int
873mpt_set_initial_config_spi(mpt_softc_t *mpt)
874{
875	int i, pp1val = ((1 << mpt->mpt_ini_id) << 16) | mpt->mpt_ini_id;
876
877	mpt->mpt_disc_enable = 0xff;
878	mpt->mpt_tag_enable = 0;
879
880	if (mpt->mpt_port_page1.Configuration != pp1val) {
881		CONFIG_PAGE_SCSI_PORT_1 tmp;
882		mpt_prt(mpt,
883		    "SPI Port Page 1 Config value bad (%x)- should be %x",
884		    mpt->mpt_port_page1.Configuration, pp1val);
885		tmp = mpt->mpt_port_page1;
886		tmp.Configuration = pp1val;
887		if (mpt_write_cfg_page(mpt, 0, &tmp.Header)) {
888			return (-1);
889		}
890		if (mpt_read_cfg_page(mpt, 0, &tmp.Header)) {
891			return (-1);
892		}
893		if (tmp.Configuration != pp1val) {
894			mpt_prt(mpt,
895			    "failed to reset SPI Port Page 1 Config value");
896			return (-1);
897		}
898		mpt->mpt_port_page1 = tmp;
899	}
900
901	for (i = 0; i < 16; i++) {
902		CONFIG_PAGE_SCSI_DEVICE_1 tmp;
903		tmp = mpt->mpt_dev_page1[i];
904		tmp.RequestedParameters = 0;
905		tmp.Configuration = 0;
906		if (mpt->verbose > 1) {
907			mpt_prt(mpt,
908			    "Set Tgt %d SPI DevicePage 1 values to %x 0 %x",
909			    i, tmp.RequestedParameters, tmp.Configuration);
910		}
911		if (mpt_write_cfg_page(mpt, i, &tmp.Header)) {
912			return (-1);
913		}
914		if (mpt_read_cfg_page(mpt, i, &tmp.Header)) {
915			return (-1);
916		}
917		mpt->mpt_dev_page1[i] = tmp;
918		if (mpt->verbose > 1) {
919			mpt_prt(mpt,
920		 	    "SPI Tgt %d Page 1: RParm %x Configuration %x", i,
921			    mpt->mpt_dev_page1[i].RequestedParameters,
922			    mpt->mpt_dev_page1[i].Configuration);
923		}
924	}
925	return (0);
926}
927
928/*
929 * Enable IOC port
930 */
931static int
932mpt_send_port_enable(mpt_softc_t *mpt, int port)
933{
934	int count;
935	request_t *req;
936	MSG_PORT_ENABLE *enable_req;
937
938	req = mpt_get_request(mpt);
939
940	enable_req = req->req_vbuf;
941	bzero(enable_req, sizeof *enable_req);
942
943	enable_req->Function   = MPI_FUNCTION_PORT_ENABLE;
944	enable_req->MsgContext = req->index | 0x80000000;
945	enable_req->PortNumber = port;
946
947	mpt_check_doorbell(mpt);
948	if (mpt->verbose > 1) {
949		mpt_prt(mpt, "enabling port %d", port);
950	}
951	mpt_send_cmd(mpt, req);
952
953	count = 0;
954	do {
955		DELAY(500);
956		mpt_intr(mpt);
957		if (++count == 100000) {
958			mpt_prt(mpt, "port enable timed out");
959			return (-1);
960		}
961	} while (req->debug == REQ_ON_CHIP);
962	mpt_free_request(mpt, req);
963	return (0);
964}
965
966/*
967 * Enable/Disable asynchronous event reporting.
968 *
969 * NB: this is the first command we send via shared memory
970 * instead of the handshake register.
971 */
972static int
973mpt_send_event_request(mpt_softc_t *mpt, int onoff)
974{
975	request_t *req;
976	MSG_EVENT_NOTIFY *enable_req;
977
978	req = mpt_get_request(mpt);
979
980	enable_req = req->req_vbuf;
981	bzero(enable_req, sizeof *enable_req);
982
983	enable_req->Function   = MPI_FUNCTION_EVENT_NOTIFICATION;
984	enable_req->MsgContext = req->index | 0x80000000;
985	enable_req->Switch     = onoff;
986
987	mpt_check_doorbell(mpt);
988	if (mpt->verbose > 1) {
989		mpt_prt(mpt, "%sabling async events", onoff? "en" : "dis");
990	}
991	mpt_send_cmd(mpt, req);
992
993	return (0);
994}
995
996/*
997 * Un-mask the interupts on the chip.
998 */
999void
1000mpt_enable_ints(mpt_softc_t *mpt)
1001{
1002	/* Unmask every thing except door bell int */
1003	mpt_write(mpt, MPT_OFFSET_INTR_MASK, MPT_INTR_DB_MASK);
1004}
1005
1006/*
1007 * Mask the interupts on the chip.
1008 */
1009void
1010mpt_disable_ints(mpt_softc_t *mpt)
1011{
1012	/* Mask all interrupts */
1013	mpt_write(mpt, MPT_OFFSET_INTR_MASK,
1014	    MPT_INTR_REPLY_MASK | MPT_INTR_DB_MASK);
1015}
1016
1017/* (Re)Initialize the chip for use */
1018int
1019mpt_init(mpt_softc_t *mpt, u_int32_t who)
1020{
1021        int try;
1022        MSG_IOC_FACTS_REPLY facts;
1023        MSG_PORT_FACTS_REPLY pfp;
1024	u_int32_t pptr;
1025        int val;
1026
1027	/* Put all request buffers (back) on the free list */
1028        SLIST_INIT(&mpt->request_free_list);
1029	for (val = 0; val < MPT_MAX_REQUESTS(mpt); val++) {
1030		mpt_free_request(mpt, &mpt->request_pool[val]);
1031	}
1032
1033	if (mpt->verbose > 1) {
1034		mpt_prt(mpt, "doorbell req = %s",
1035		    mpt_ioc_diag(mpt_read(mpt, MPT_OFFSET_DOORBELL)));
1036	}
1037
1038	/*
1039	 * Start by making sure we're not at FAULT or RESET state
1040	 */
1041	switch (mpt_rd_db(mpt) & MPT_DB_STATE_MASK) {
1042	case MPT_DB_STATE_RESET:
1043	case MPT_DB_STATE_FAULT:
1044		if (mpt_reset(mpt) != MPT_OK) {
1045			return (EIO);
1046		}
1047	default:
1048		break;
1049	}
1050
1051	for (try = 0; try < MPT_MAX_TRYS; try++) {
1052		/*
1053		 * No need to reset if the IOC is already in the READY state.
1054		 *
1055		 * Force reset if initialization failed previously.
1056		 * Note that a hard_reset of the second channel of a '929
1057		 * will stop operation of the first channel.  Hopefully, if the
1058		 * first channel is ok, the second will not require a hard
1059		 * reset.
1060		 */
1061		if ((mpt_rd_db(mpt) & MPT_DB_STATE_MASK) !=
1062		    MPT_DB_STATE_READY) {
1063			if (mpt_reset(mpt) != MPT_OK) {
1064				DELAY(10000);
1065				continue;
1066			}
1067		}
1068
1069		if (mpt_get_iocfacts(mpt, &facts) != MPT_OK) {
1070			mpt_prt(mpt, "mpt_get_iocfacts failed");
1071			continue;
1072		}
1073
1074		if (mpt->verbose > 1) {
1075			mpt_prt(mpt,
1076			    "IOCFACTS: GlobalCredits=%d BlockSize=%u "
1077			    "Request Frame Size %u\n", facts.GlobalCredits,
1078			    facts.BlockSize, facts.RequestFrameSize);
1079		}
1080		mpt->mpt_global_credits = facts.GlobalCredits;
1081		mpt->request_frame_size = facts.RequestFrameSize;
1082
1083		if (mpt_get_portfacts(mpt, &pfp) != MPT_OK) {
1084			mpt_prt(mpt, "mpt_get_portfacts failed");
1085			continue;
1086		}
1087
1088		if (mpt->verbose > 1) {
1089			mpt_prt(mpt,
1090			    "PORTFACTS: Type %x PFlags %x IID %d MaxDev %d\n",
1091			    pfp.PortType, pfp.ProtocolFlags, pfp.PortSCSIID,
1092			    pfp.MaxDevices);
1093		}
1094
1095		if (pfp.PortType != MPI_PORTFACTS_PORTTYPE_SCSI &&
1096		    pfp.PortType != MPI_PORTFACTS_PORTTYPE_FC) {
1097			mpt_prt(mpt, "Unsupported Port Type (%x)",
1098			    pfp.PortType);
1099			return (ENXIO);
1100		}
1101		if (!(pfp.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)) {
1102			mpt_prt(mpt, "initiator role unsupported");
1103			return (ENXIO);
1104		}
1105		if (pfp.PortType == MPI_PORTFACTS_PORTTYPE_FC) {
1106			mpt->is_fc = 1;
1107		} else {
1108			mpt->is_fc = 0;
1109		}
1110		mpt->mpt_ini_id = pfp.PortSCSIID;
1111
1112		if (mpt_send_ioc_init(mpt, who) != MPT_OK) {
1113			mpt_prt(mpt, "mpt_send_ioc_init failed");
1114			continue;
1115		}
1116
1117		if (mpt->verbose > 1) {
1118			mpt_prt(mpt, "mpt_send_ioc_init ok");
1119		}
1120
1121		if (mpt_wait_state(mpt, MPT_DB_STATE_RUNNING) != MPT_OK) {
1122			mpt_prt(mpt, "IOC failed to go to run state");
1123			continue;
1124		}
1125		if (mpt->verbose > 1) {
1126			mpt_prt(mpt, "IOC now at RUNSTATE");
1127		}
1128
1129		/*
1130		 * Give it reply buffers
1131		 *
1132		 * Do *not* except global credits.
1133		 */
1134		for (val = 0, pptr = mpt->reply_phys;
1135		    (pptr + MPT_REPLY_SIZE) < (mpt->reply_phys + PAGE_SIZE);
1136		     pptr += MPT_REPLY_SIZE) {
1137			mpt_free_reply(mpt, pptr);
1138			if (++val == mpt->mpt_global_credits - 1)
1139				break;
1140		}
1141
1142		/*
1143		 * Enable asynchronous event reporting
1144		 */
1145		mpt_send_event_request(mpt, 1);
1146
1147
1148		/*
1149		 * Read set up initial configuration information
1150		 * (SPI only for now)
1151		 */
1152
1153		if (mpt->is_fc == 0) {
1154			if (mpt_read_config_info_spi(mpt)) {
1155				return (EIO);
1156			}
1157			if (mpt_set_initial_config_spi(mpt)) {
1158				return (EIO);
1159			}
1160		}
1161
1162		/*
1163		 * Now enable the port
1164		 */
1165		if (mpt_send_port_enable(mpt, 0) != MPT_OK) {
1166			mpt_prt(mpt, "failed to enable port 0");
1167			continue;
1168		}
1169
1170		if (mpt->verbose > 1) {
1171			mpt_prt(mpt, "enabled port 0");
1172		}
1173
1174		/* Everything worked */
1175		break;
1176	}
1177
1178	if (try >= MPT_MAX_TRYS) {
1179		mpt_prt(mpt, "failed to initialize IOC");
1180		return (EIO);
1181	}
1182
1183	if (mpt->verbose > 1) {
1184		mpt_prt(mpt, "enabling interrupts");
1185	}
1186
1187	mpt_enable_ints(mpt);
1188	return (0);
1189}
1190