mpt.c revision 139749
1139749Simp/*-
2101704Smjacob * Generic routines for LSI '909 FC  adapters.
3101704Smjacob * FreeBSD Version.
4101704Smjacob *
5101704Smjacob * Copyright (c) 2000, 2001 by Greg Ansley
6101704Smjacob *
7101704Smjacob * Redistribution and use in source and binary forms, with or without
8101704Smjacob * modification, are permitted provided that the following conditions
9101704Smjacob * are met:
10101704Smjacob * 1. Redistributions of source code must retain the above copyright
11101704Smjacob *    notice immediately at the beginning of the file, without modification,
12101704Smjacob *    this list of conditions, and the following disclaimer.
13101704Smjacob * 2. The name of the author may not be used to endorse or promote products
14101704Smjacob *    derived from this software without specific prior written permission.
15101704Smjacob *
16101704Smjacob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17101704Smjacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18101704Smjacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19101704Smjacob * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20101704Smjacob * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21101704Smjacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22101704Smjacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23101704Smjacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24101704Smjacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25101704Smjacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26101704Smjacob * SUCH DAMAGE.
27101704Smjacob */
28101704Smjacob/*
29101704Smjacob * Additional Copyright (c) 2002 by Matthew Jacob under same license.
30101704Smjacob */
31101704Smjacob
32134123Sobrien#include <sys/cdefs.h>
33134123Sobrien__FBSDID("$FreeBSD: head/sys/dev/mpt/mpt.c 139749 2005-01-06 01:43:34Z imp $");
34134123Sobrien
35101704Smjacob#include <dev/mpt/mpt_freebsd.h>
36102199Smjacob
37101704Smjacob#define MPT_MAX_TRYS 3
38101704Smjacob#define MPT_MAX_WAIT 300000
39101704Smjacob
40101704Smjacobstatic int maxwait_ack = 0;
41101704Smjacobstatic int maxwait_int = 0;
42101704Smjacobstatic int maxwait_state = 0;
43101704Smjacob
44103914Smjacobstatic INLINE u_int32_t mpt_rd_db(mpt_softc_t *mpt);
45103914Smjacobstatic INLINE  u_int32_t mpt_rd_intr(mpt_softc_t *mpt);
46101704Smjacob
47103914Smjacobstatic INLINE u_int32_t
48102199Smjacobmpt_rd_db(mpt_softc_t *mpt)
49101704Smjacob{
50101704Smjacob	return mpt_read(mpt, MPT_OFFSET_DOORBELL);
51101704Smjacob}
52101704Smjacob
53103914Smjacobstatic INLINE u_int32_t
54102199Smjacobmpt_rd_intr(mpt_softc_t *mpt)
55101704Smjacob{
56101704Smjacob	return mpt_read(mpt, MPT_OFFSET_INTR_STATUS);
57101704Smjacob}
58101704Smjacob
59101704Smjacob/* Busy wait for a door bell to be read by IOC */
60101704Smjacobstatic int
61102199Smjacobmpt_wait_db_ack(mpt_softc_t *mpt)
62101704Smjacob{
63101704Smjacob	int i;
64101704Smjacob	for (i=0; i < MPT_MAX_WAIT; i++) {
65101704Smjacob		if (!MPT_DB_IS_BUSY(mpt_rd_intr(mpt))) {
66101704Smjacob			maxwait_ack = i > maxwait_ack ? i : maxwait_ack;
67101704Smjacob			return MPT_OK;
68101704Smjacob		}
69101704Smjacob
70101704Smjacob		DELAY(100);
71101704Smjacob	}
72101704Smjacob	return MPT_FAIL;
73101704Smjacob}
74101704Smjacob
75101704Smjacob/* Busy wait for a door bell interrupt */
76101704Smjacobstatic int
77102199Smjacobmpt_wait_db_int(mpt_softc_t *mpt)
78101704Smjacob{
79101704Smjacob	int i;
80101704Smjacob	for (i=0; i < MPT_MAX_WAIT; i++) {
81101704Smjacob		if (MPT_DB_INTR(mpt_rd_intr(mpt))) {
82101704Smjacob			maxwait_int = i > maxwait_int ? i : maxwait_int;
83101704Smjacob			return MPT_OK;
84101704Smjacob		}
85101704Smjacob		DELAY(100);
86101704Smjacob	}
87101704Smjacob	return MPT_FAIL;
88101704Smjacob}
89101704Smjacob
90101704Smjacob/* Wait for IOC to transition to a give state */
91101704Smjacobvoid
92102199Smjacobmpt_check_doorbell(mpt_softc_t *mpt)
93101704Smjacob{
94101704Smjacob	u_int32_t db = mpt_rd_db(mpt);
95101704Smjacob	if (MPT_STATE(db) != MPT_DB_STATE_RUNNING) {
96103914Smjacob		mpt_prt(mpt, "Device not running");
97101704Smjacob		mpt_print_db(db);
98101704Smjacob	}
99101704Smjacob}
100101704Smjacob
101101704Smjacob/* Wait for IOC to transition to a give state */
102101704Smjacobstatic int
103102199Smjacobmpt_wait_state(mpt_softc_t *mpt, enum DB_STATE_BITS state)
104101704Smjacob{
105101704Smjacob	int i;
106101704Smjacob
107101704Smjacob	for (i = 0; i < MPT_MAX_WAIT; i++) {
108101704Smjacob		u_int32_t db = mpt_rd_db(mpt);
109101704Smjacob		if (MPT_STATE(db) == state) {
110101704Smjacob			maxwait_state = i > maxwait_state ? i : maxwait_state;
111101704Smjacob			return (MPT_OK);
112101704Smjacob		}
113101704Smjacob		DELAY(100);
114101704Smjacob	}
115101704Smjacob	return (MPT_FAIL);
116101704Smjacob}
117101704Smjacob
118101704Smjacob
119101704Smjacob/* Issue the reset COMMAND to the IOC */
120101704Smjacobint
121102199Smjacobmpt_soft_reset(mpt_softc_t *mpt)
122101704Smjacob{
123101704Smjacob	if (mpt->verbose) {
124103914Smjacob		mpt_prt(mpt, "soft reset");
125101704Smjacob	}
126101704Smjacob
127101704Smjacob	/* Have to use hard reset if we are not in Running state */
128101704Smjacob	if (MPT_STATE(mpt_rd_db(mpt)) != MPT_DB_STATE_RUNNING) {
129103914Smjacob		mpt_prt(mpt, "soft reset failed: device not running");
130101704Smjacob		return MPT_FAIL;
131101704Smjacob	}
132101704Smjacob
133101704Smjacob	/* If door bell is in use we don't have a chance of getting
134101704Smjacob	 * a word in since the IOC probably crashed in message
135101704Smjacob	 * processing. So don't waste our time.
136101704Smjacob	 */
137101704Smjacob	if (MPT_DB_IS_IN_USE(mpt_rd_db(mpt))) {
138103914Smjacob		mpt_prt(mpt, "soft reset failed: doorbell wedged");
139101704Smjacob		return MPT_FAIL;
140101704Smjacob	}
141101704Smjacob
142101704Smjacob	/* Send the reset request to the IOC */
143101704Smjacob	mpt_write(mpt, MPT_OFFSET_DOORBELL,
144101704Smjacob	    MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET << MPI_DOORBELL_FUNCTION_SHIFT);
145101704Smjacob	if (mpt_wait_db_ack(mpt) != MPT_OK) {
146103914Smjacob		mpt_prt(mpt, "soft reset failed: ack timeout");
147101704Smjacob		return MPT_FAIL;
148101704Smjacob	}
149101704Smjacob
150101704Smjacob	/* Wait for the IOC to reload and come out of reset state */
151101704Smjacob	if (mpt_wait_state(mpt, MPT_DB_STATE_READY) != MPT_OK) {
152103914Smjacob		mpt_prt(mpt, "soft reset failed: device did not start running");
153101704Smjacob		return MPT_FAIL;
154101704Smjacob	}
155101704Smjacob
156101704Smjacob	return MPT_OK;
157101704Smjacob}
158101704Smjacob
159101704Smjacob/* This is a magic diagnostic reset that resets all the ARM
160101704Smjacob * processors in the chip.
161101704Smjacob */
162101704Smjacobvoid
163102199Smjacobmpt_hard_reset(mpt_softc_t *mpt)
164101704Smjacob{
165101704Smjacob	/* This extra read comes for the Linux source
166101704Smjacob	 * released by LSI. It's function is undocumented!
167101704Smjacob	 */
168101704Smjacob	if (mpt->verbose) {
169103914Smjacob		mpt_prt(mpt, "hard reset");
170101704Smjacob	}
171101704Smjacob	mpt_read(mpt, MPT_OFFSET_FUBAR);
172101704Smjacob
173101704Smjacob	/* Enable diagnostic registers */
174101704Smjacob	mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_1);
175101704Smjacob	mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_2);
176101704Smjacob	mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_3);
177101704Smjacob	mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_4);
178101704Smjacob	mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_5);
179101704Smjacob
180101704Smjacob	/* Diag. port is now active so we can now hit the reset bit */
181101704Smjacob	mpt_write(mpt, MPT_OFFSET_DIAGNOSTIC, MPT_DIAG_RESET_IOC);
182101704Smjacob
183101704Smjacob	DELAY(10000);
184101704Smjacob
185101704Smjacob	/* Disable Diagnostic Register */
186101704Smjacob	mpt_write(mpt, MPT_OFFSET_SEQUENCE, 0xFF);
187101704Smjacob
188101704Smjacob	/* Restore the config register values */
189101704Smjacob	/*   Hard resets are known to screw up the BAR for diagnostic
190101704Smjacob	     memory accesses (Mem1). */
191101704Smjacob	mpt_set_config_regs(mpt);
192101704Smjacob	if (mpt->mpt2 != NULL) {
193101704Smjacob		mpt_set_config_regs(mpt->mpt2);
194101704Smjacob	}
195101704Smjacob
196101704Smjacob	/* Note that if there is no valid firmware to run, the doorbell will
197101704Smjacob	   remain in the reset state (0x00000000) */
198101704Smjacob}
199101704Smjacob
200101704Smjacob/*
201101704Smjacob * Reset the IOC when needed. Try software command first then if needed
202101704Smjacob * poke at the magic diagnostic reset. Note that a hard reset resets
203101704Smjacob * *both* IOCs on dual function chips (FC929 && LSI1030) as well as
204101704Smjacob * fouls up the PCI configuration registers.
205101704Smjacob */
206101704Smjacobint
207102199Smjacobmpt_reset(mpt_softc_t *mpt)
208101704Smjacob{
209101704Smjacob	int ret;
210101704Smjacob
211101704Smjacob	/* Try a soft reset */
212101704Smjacob	if ((ret = mpt_soft_reset(mpt)) != MPT_OK) {
213101704Smjacob		/* Failed; do a hard reset */
214101704Smjacob		mpt_hard_reset(mpt);
215101704Smjacob
216101704Smjacob		/* Wait for the IOC to reload and come out of reset state */
217101704Smjacob		ret = mpt_wait_state(mpt, MPT_DB_STATE_READY);
218101704Smjacob		if (ret != MPT_OK) {
219103914Smjacob			mpt_prt(mpt, "failed to reset device");
220101704Smjacob		}
221101704Smjacob	}
222101704Smjacob
223101704Smjacob	return ret;
224101704Smjacob}
225101704Smjacob
226101704Smjacob/* Return a command buffer to the free queue */
227101704Smjacobvoid
228102199Smjacobmpt_free_request(mpt_softc_t *mpt, request_t *req)
229101704Smjacob{
230103871Smjacob	if (req == NULL || req != &mpt->request_pool[req->index]) {
231101704Smjacob		panic("mpt_free_request bad req ptr\n");
232101704Smjacob		return;
233101704Smjacob	}
234103827Smjacob	req->sequence = 0;
235101704Smjacob	req->ccb = NULL;
236101704Smjacob	req->debug = REQ_FREE;
237101704Smjacob	SLIST_INSERT_HEAD(&mpt->request_free_list, req, link);
238101704Smjacob}
239101704Smjacob
240101704Smjacob/* Get a command buffer from the free queue */
241101704Smjacobrequest_t *
242102199Smjacobmpt_get_request(mpt_softc_t *mpt)
243101704Smjacob{
244101704Smjacob	request_t *req;
245101704Smjacob	req = SLIST_FIRST(&mpt->request_free_list);
246101704Smjacob	if (req != NULL) {
247103871Smjacob		if (req != &mpt->request_pool[req->index]) {
248101704Smjacob			panic("mpt_get_request: corrupted request free list\n");
249101704Smjacob		}
250101704Smjacob		if (req->ccb != NULL) {
251101704Smjacob			panic("mpt_get_request: corrupted request free list (ccb)\n");
252101704Smjacob		}
253101704Smjacob		SLIST_REMOVE_HEAD(&mpt->request_free_list, link);
254101704Smjacob		req->debug = REQ_IN_PROGRESS;
255101704Smjacob	}
256101704Smjacob	return req;
257101704Smjacob}
258101704Smjacob
259101704Smjacob/* Pass the command to the IOC */
260101704Smjacobvoid
261102199Smjacobmpt_send_cmd(mpt_softc_t *mpt, request_t *req)
262101704Smjacob{
263101704Smjacob	req->sequence = mpt->sequence++;
264101704Smjacob	if (mpt->verbose > 1) {
265101704Smjacob		u_int32_t *pReq;
266101704Smjacob		pReq = req->req_vbuf;
267103914Smjacob		mpt_prt(mpt, "Send Request %d (0x%x):",
268103914Smjacob		    req->index, req->req_pbuf);
269103914Smjacob		mpt_prt(mpt, "%08x %08x %08x %08x",
270101704Smjacob		    pReq[0], pReq[1], pReq[2], pReq[3]);
271103914Smjacob		mpt_prt(mpt, "%08x %08x %08x %08x",
272101704Smjacob		    pReq[4], pReq[5], pReq[6], pReq[7]);
273103914Smjacob		mpt_prt(mpt, "%08x %08x %08x %08x",
274101704Smjacob		    pReq[8], pReq[9], pReq[10], pReq[11]);
275103914Smjacob		mpt_prt(mpt, "%08x %08x %08x %08x",
276101704Smjacob		    pReq[12], pReq[13], pReq[14], pReq[15]);
277101704Smjacob	}
278101704Smjacob	bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap,
279103914Smjacob	    BUS_DMASYNC_PREWRITE);
280101704Smjacob	req->debug = REQ_ON_CHIP;
281101704Smjacob	mpt_write(mpt, MPT_OFFSET_REQUEST_Q, (u_int32_t) req->req_pbuf);
282101704Smjacob}
283101704Smjacob
284101704Smjacob/*
285101704Smjacob * Give the reply buffer back to the IOC after we have
286101704Smjacob * finished processing it.
287101704Smjacob */
288101704Smjacobvoid
289102199Smjacobmpt_free_reply(mpt_softc_t *mpt, u_int32_t ptr)
290101704Smjacob{
291101704Smjacob     mpt_write(mpt, MPT_OFFSET_REPLY_Q, ptr);
292101704Smjacob}
293101704Smjacob
294101704Smjacob/* Get a reply from the IOC */
295101704Smjacobu_int32_t
296102199Smjacobmpt_pop_reply_queue(mpt_softc_t *mpt)
297101704Smjacob{
298101704Smjacob     return mpt_read(mpt, MPT_OFFSET_REPLY_Q);
299101704Smjacob}
300101704Smjacob
301101704Smjacob/*
302101704Smjacob * Send a command to the IOC via the handshake register.
303101704Smjacob *
304101704Smjacob * Only done at initialization time and for certain unusual
305101704Smjacob * commands such as device/bus reset as specified by LSI.
306101704Smjacob */
307101704Smjacobint
308102199Smjacobmpt_send_handshake_cmd(mpt_softc_t *mpt, size_t len, void *cmd)
309101704Smjacob{
310101704Smjacob	int i;
311101704Smjacob	u_int32_t data, *data32;
312101704Smjacob
313101704Smjacob	/* Check condition of the IOC */
314101704Smjacob	data = mpt_rd_db(mpt);
315101704Smjacob	if (((MPT_STATE(data) != MPT_DB_STATE_READY)	&&
316101704Smjacob	     (MPT_STATE(data) != MPT_DB_STATE_RUNNING)	&&
317101704Smjacob	     (MPT_STATE(data) != MPT_DB_STATE_FAULT))	||
318101704Smjacob	    (  MPT_DB_IS_IN_USE(data) )) {
319103914Smjacob		mpt_prt(mpt, "handshake aborted due to invalid doorbell state");
320101704Smjacob		mpt_print_db(data);
321101704Smjacob		return(EBUSY);
322101704Smjacob	}
323101704Smjacob
324101704Smjacob	/* We move things in 32 bit chunks */
325101704Smjacob	len = (len + 3) >> 2;
326101704Smjacob	data32 = cmd;
327101704Smjacob
328101704Smjacob	/* Clear any left over pending doorbell interupts */
329101704Smjacob	if (MPT_DB_INTR(mpt_rd_intr(mpt)))
330101704Smjacob		mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
331101704Smjacob
332101704Smjacob	/*
333101704Smjacob	 * Tell the handshake reg. we are going to send a command
334101704Smjacob         * and how long it is going to be.
335101704Smjacob	 */
336101704Smjacob	data = (MPI_FUNCTION_HANDSHAKE << MPI_DOORBELL_FUNCTION_SHIFT) |
337101704Smjacob	    (len << MPI_DOORBELL_ADD_DWORDS_SHIFT);
338101704Smjacob	mpt_write(mpt, MPT_OFFSET_DOORBELL, data);
339101704Smjacob
340101704Smjacob	/* Wait for the chip to notice */
341101704Smjacob	if (mpt_wait_db_int(mpt) != MPT_OK) {
342103914Smjacob		mpt_prt(mpt, "mpt_send_handshake_cmd timeout1");
343101704Smjacob		return ETIMEDOUT;
344101704Smjacob	}
345101704Smjacob
346101704Smjacob	/* Clear the interrupt */
347101704Smjacob	mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
348101704Smjacob
349101704Smjacob	if (mpt_wait_db_ack(mpt) != MPT_OK) {
350103914Smjacob		mpt_prt(mpt, "mpt_send_handshake_cmd timeout2");
351101704Smjacob		return ETIMEDOUT;
352101704Smjacob	}
353101704Smjacob
354101704Smjacob	/* Send the command */
355101704Smjacob	for (i = 0; i < len; i++) {
356101704Smjacob		mpt_write(mpt, MPT_OFFSET_DOORBELL, *data32++);
357101704Smjacob		if (mpt_wait_db_ack(mpt) != MPT_OK) {
358103914Smjacob			mpt_prt(mpt,
359103914Smjacob			    "mpt_send_handshake_cmd timeout! index = %d", i);
360101704Smjacob			return ETIMEDOUT;
361101704Smjacob		}
362101704Smjacob	}
363101704Smjacob	return MPT_OK;
364101704Smjacob}
365101704Smjacob
366101704Smjacob/* Get the response from the handshake register */
367101704Smjacobint
368102199Smjacobmpt_recv_handshake_reply(mpt_softc_t *mpt, size_t reply_len, void *reply)
369101704Smjacob{
370101704Smjacob	int left, reply_left;
371101704Smjacob	u_int16_t *data16;
372101704Smjacob	MSG_DEFAULT_REPLY *hdr;
373101704Smjacob
374101704Smjacob	/* We move things out in 16 bit chunks */
375101704Smjacob	reply_len >>= 1;
376101704Smjacob	data16 = (u_int16_t *)reply;
377101704Smjacob
378101704Smjacob	hdr = (MSG_DEFAULT_REPLY *)reply;
379101704Smjacob
380101704Smjacob	/* Get first word */
381101704Smjacob	if (mpt_wait_db_int(mpt) != MPT_OK) {
382103914Smjacob		mpt_prt(mpt, "mpt_recv_handshake_cmd timeout1");
383101704Smjacob		return ETIMEDOUT;
384101704Smjacob	}
385101704Smjacob	*data16++ = mpt_read(mpt, MPT_OFFSET_DOORBELL) & MPT_DB_DATA_MASK;
386101704Smjacob	mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
387101704Smjacob
388101704Smjacob	/* Get Second Word */
389101704Smjacob	if (mpt_wait_db_int(mpt) != MPT_OK) {
390103914Smjacob		mpt_prt(mpt, "mpt_recv_handshake_cmd timeout2");
391101704Smjacob		return ETIMEDOUT;
392101704Smjacob	}
393101704Smjacob	*data16++ = mpt_read(mpt, MPT_OFFSET_DOORBELL) & MPT_DB_DATA_MASK;
394101704Smjacob	mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
395101704Smjacob
396101704Smjacob	/* With the second word, we can now look at the length */
397101704Smjacob	if (mpt->verbose > 1 && ((reply_len >> 1) != hdr->MsgLength)) {
398103914Smjacob		mpt_prt(mpt, "reply length does not match message length: "
399103914Smjacob			"got 0x%02x, expected 0x%02x",
400103914Smjacob			hdr->MsgLength << 2, reply_len << 1);
401101704Smjacob	}
402101704Smjacob
403101704Smjacob	/* Get rest of the reply; but don't overflow the provided buffer */
404101704Smjacob	left = (hdr->MsgLength << 1) - 2;
405101704Smjacob	reply_left =  reply_len - 2;
406101704Smjacob	while (left--) {
407101704Smjacob		u_int16_t datum;
408101704Smjacob
409101704Smjacob		if (mpt_wait_db_int(mpt) != MPT_OK) {
410103914Smjacob			mpt_prt(mpt, "mpt_recv_handshake_cmd timeout3");
411101704Smjacob			return ETIMEDOUT;
412101704Smjacob		}
413101704Smjacob		datum = mpt_read(mpt, MPT_OFFSET_DOORBELL);
414101704Smjacob
415101704Smjacob		if (reply_left-- > 0)
416101704Smjacob			*data16++ = datum & MPT_DB_DATA_MASK;
417101704Smjacob
418101704Smjacob		mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
419101704Smjacob	}
420101704Smjacob
421101704Smjacob	/* One more wait & clear at the end */
422101704Smjacob	if (mpt_wait_db_int(mpt) != MPT_OK) {
423103914Smjacob		mpt_prt(mpt, "mpt_recv_handshake_cmd timeout4");
424101704Smjacob		return ETIMEDOUT;
425101704Smjacob	}
426101704Smjacob	mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
427101704Smjacob
428101704Smjacob	if ((hdr->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
429101704Smjacob		if (mpt->verbose > 1)
430101704Smjacob			mpt_print_reply(hdr);
431101704Smjacob		return (MPT_FAIL | hdr->IOCStatus);
432101704Smjacob	}
433101704Smjacob
434101704Smjacob	return (0);
435101704Smjacob}
436101704Smjacob
437101704Smjacobstatic int
438102199Smjacobmpt_get_iocfacts(mpt_softc_t *mpt, MSG_IOC_FACTS_REPLY *freplp)
439101704Smjacob{
440101704Smjacob	MSG_IOC_FACTS f_req;
441101704Smjacob	int error;
442101704Smjacob
443101704Smjacob	bzero(&f_req, sizeof f_req);
444101704Smjacob	f_req.Function = MPI_FUNCTION_IOC_FACTS;
445101704Smjacob	f_req.MsgContext =  0x12071942;
446101704Smjacob	error = mpt_send_handshake_cmd(mpt, sizeof f_req, &f_req);
447101704Smjacob	if (error)
448101704Smjacob		return(error);
449101704Smjacob	error = mpt_recv_handshake_reply(mpt, sizeof (*freplp), freplp);
450101704Smjacob	return (error);
451101704Smjacob}
452101704Smjacob
453102199Smjacobstatic int
454102199Smjacobmpt_get_portfacts(mpt_softc_t *mpt, MSG_PORT_FACTS_REPLY *freplp)
455102199Smjacob{
456102199Smjacob	MSG_PORT_FACTS f_req;
457102199Smjacob	int error;
458102199Smjacob
459102199Smjacob	/* XXX: Only getting PORT FACTS for Port 0 */
460102199Smjacob	bzero(&f_req, sizeof f_req);
461102199Smjacob	f_req.Function = MPI_FUNCTION_PORT_FACTS;
462102199Smjacob	f_req.MsgContext =  0x12071943;
463102199Smjacob	error = mpt_send_handshake_cmd(mpt, sizeof f_req, &f_req);
464102199Smjacob	if (error)
465102199Smjacob		return(error);
466102199Smjacob	error = mpt_recv_handshake_reply(mpt, sizeof (*freplp), freplp);
467102199Smjacob	return (error);
468102199Smjacob}
469102199Smjacob
470101704Smjacob/*
471101704Smjacob * Send the initialization request. This is where we specify how many
472101704Smjacob * SCSI busses and how many devices per bus we wish to emulate.
473101704Smjacob * This is also the command that specifies the max size of the reply
474101704Smjacob * frames from the IOC that we will be allocating.
475101704Smjacob */
476101704Smjacobstatic int
477102199Smjacobmpt_send_ioc_init(mpt_softc_t *mpt, u_int32_t who)
478101704Smjacob{
479101704Smjacob	int error = 0;
480101704Smjacob	MSG_IOC_INIT init;
481101704Smjacob	MSG_IOC_INIT_REPLY reply;
482101704Smjacob
483101704Smjacob	bzero(&init, sizeof init);
484101704Smjacob	init.WhoInit = who;
485101704Smjacob	init.Function = MPI_FUNCTION_IOC_INIT;
486101704Smjacob	if (mpt->is_fc) {
487101704Smjacob		init.MaxDevices = 255;
488101704Smjacob	} else {
489101704Smjacob		init.MaxDevices = 16;
490101704Smjacob	}
491101704Smjacob	init.MaxBuses = 1;
492101704Smjacob	init.ReplyFrameSize = MPT_REPLY_SIZE;
493101704Smjacob	init.MsgContext = 0x12071941;
494101704Smjacob
495101704Smjacob	if ((error = mpt_send_handshake_cmd(mpt, sizeof init, &init)) != 0) {
496101704Smjacob		return(error);
497101704Smjacob	}
498101704Smjacob
499101704Smjacob	error = mpt_recv_handshake_reply(mpt, sizeof reply, &reply);
500101704Smjacob	return (error);
501101704Smjacob}
502101704Smjacob
503102199Smjacob
504102199Smjacob/*
505102199Smjacob * Utiltity routine to read configuration headers and pages
506102199Smjacob */
507102199Smjacob
508101704Smjacobstatic int
509115778Smjacobmpt_read_cfg_header(mpt_softc_t *, int, int, int, CONFIG_PAGE_HEADER *);
510102199Smjacob
511102199Smjacobstatic int
512102199Smjacobmpt_read_cfg_header(mpt_softc_t *mpt, int PageType, int PageNumber,
513115778Smjacob    int PageAddress, CONFIG_PAGE_HEADER *rslt)
514101704Smjacob{
515101704Smjacob	int count;
516101704Smjacob	request_t *req;
517102199Smjacob	MSG_CONFIG *cfgp;
518102199Smjacob	MSG_CONFIG_REPLY *reply;
519102199Smjacob
520102199Smjacob	req = mpt_get_request(mpt);
521102199Smjacob
522102199Smjacob	cfgp = req->req_vbuf;
523102199Smjacob	bzero(cfgp, sizeof *cfgp);
524102199Smjacob
525102199Smjacob	cfgp->Action = MPI_CONFIG_ACTION_PAGE_HEADER;
526102199Smjacob	cfgp->Function = MPI_FUNCTION_CONFIG;
527102199Smjacob	cfgp->Header.PageNumber = (U8) PageNumber;
528102199Smjacob	cfgp->Header.PageType = (U8) PageType;
529102199Smjacob	cfgp->PageAddress = PageAddress;
530102199Smjacob	MPI_pSGE_SET_FLAGS(((SGE_SIMPLE32 *) &cfgp->PageBufferSGE),
531102199Smjacob	    (MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
532102199Smjacob	    MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_LIST));
533102199Smjacob	cfgp->MsgContext = req->index | 0x80000000;
534102199Smjacob
535102199Smjacob	mpt_check_doorbell(mpt);
536102199Smjacob	mpt_send_cmd(mpt, req);
537102199Smjacob	count = 0;
538102199Smjacob	do {
539102199Smjacob		DELAY(500);
540102199Smjacob		mpt_intr(mpt);
541102199Smjacob		if (++count == 1000) {
542103914Smjacob			mpt_prt(mpt, "read_cfg_header timed out");
543102199Smjacob			return (-1);
544102199Smjacob		}
545102199Smjacob	} while (req->debug == REQ_ON_CHIP);
546102199Smjacob
547102199Smjacob	reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence);
548102199Smjacob        if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
549103914Smjacob		mpt_prt(mpt, "mpt_read_cfg_header: Config Info Status %x",
550102199Smjacob		    reply->IOCStatus);
551103914Smjacob		mpt_free_reply(mpt, (req->sequence << 1));
552102199Smjacob		return (-1);
553102199Smjacob	}
554115778Smjacob	bcopy(&reply->Header, rslt, sizeof (CONFIG_PAGE_HEADER));
555102199Smjacob	mpt_free_reply(mpt, (req->sequence << 1));
556102199Smjacob	mpt_free_request(mpt, req);
557102199Smjacob	return (0);
558102199Smjacob}
559102199Smjacob
560103827Smjacob#define	CFG_DATA_OFF	128
561102199Smjacob
562102822Smjacobint
563115778Smjacobmpt_read_cfg_page(mpt_softc_t *mpt, int PageAddress, CONFIG_PAGE_HEADER *hdr)
564102199Smjacob{
565102199Smjacob	int count;
566102199Smjacob	request_t *req;
567102199Smjacob	SGE_SIMPLE32 *se;
568102199Smjacob	MSG_CONFIG *cfgp;
569102199Smjacob	size_t amt;
570102199Smjacob	MSG_CONFIG_REPLY *reply;
571102199Smjacob
572102199Smjacob	req = mpt_get_request(mpt);
573102199Smjacob
574102199Smjacob	cfgp = req->req_vbuf;
575103827Smjacob	bzero(cfgp, MPT_REQUEST_AREA);
576102199Smjacob	cfgp->Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
577102199Smjacob	cfgp->Function = MPI_FUNCTION_CONFIG;
578102199Smjacob	cfgp->Header = *hdr;
579103914Smjacob 	amt = (cfgp->Header.PageLength * sizeof (u_int32_t));
580102199Smjacob	cfgp->Header.PageType &= MPI_CONFIG_PAGETYPE_MASK;
581102199Smjacob	cfgp->PageAddress = PageAddress;
582102199Smjacob	se = (SGE_SIMPLE32 *) &cfgp->PageBufferSGE;
583102199Smjacob	se->Address = req->req_pbuf + CFG_DATA_OFF;
584102199Smjacob	MPI_pSGE_SET_LENGTH(se, amt);
585102199Smjacob	MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
586102199Smjacob	    MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
587102199Smjacob	    MPI_SGE_FLAGS_END_OF_LIST));
588102199Smjacob
589102199Smjacob	cfgp->MsgContext = req->index | 0x80000000;
590102199Smjacob
591102199Smjacob	mpt_check_doorbell(mpt);
592102199Smjacob	mpt_send_cmd(mpt, req);
593102199Smjacob	count = 0;
594102199Smjacob	do {
595102199Smjacob		DELAY(500);
596102199Smjacob		mpt_intr(mpt);
597102199Smjacob		if (++count == 1000) {
598103914Smjacob			mpt_prt(mpt, "read_cfg_page timed out");
599102199Smjacob			return (-1);
600102199Smjacob		}
601102199Smjacob	} while (req->debug == REQ_ON_CHIP);
602102199Smjacob
603102199Smjacob	reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence);
604102199Smjacob        if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
605103914Smjacob		mpt_prt(mpt, "mpt_read_cfg_page: Config Info Status %x",
606102199Smjacob		    reply->IOCStatus);
607103914Smjacob		mpt_free_reply(mpt, (req->sequence << 1));
608102199Smjacob		return (-1);
609102199Smjacob	}
610102199Smjacob	mpt_free_reply(mpt, (req->sequence << 1));
611102199Smjacob	bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap,
612102199Smjacob	    BUS_DMASYNC_POSTREAD);
613102199Smjacob	if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
614102199Smjacob	    cfgp->Header.PageNumber == 0) {
615115778Smjacob		amt = sizeof (CONFIG_PAGE_SCSI_PORT_0);
616102199Smjacob	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
617102199Smjacob	    cfgp->Header.PageNumber == 1) {
618115778Smjacob		amt = sizeof (CONFIG_PAGE_SCSI_PORT_1);
619102199Smjacob	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
620102199Smjacob	    cfgp->Header.PageNumber == 2) {
621115778Smjacob		amt = sizeof (CONFIG_PAGE_SCSI_PORT_2);
622102199Smjacob	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE  &&
623102199Smjacob	    cfgp->Header.PageNumber == 0) {
624115778Smjacob		amt = sizeof (CONFIG_PAGE_SCSI_DEVICE_0);
625102199Smjacob	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE  &&
626102199Smjacob	    cfgp->Header.PageNumber == 1) {
627115778Smjacob		amt = sizeof (CONFIG_PAGE_SCSI_DEVICE_1);
628102199Smjacob	}
629102199Smjacob	bcopy(((caddr_t)req->req_vbuf)+CFG_DATA_OFF, hdr, amt);
630102199Smjacob	mpt_free_request(mpt, req);
631102199Smjacob	return (0);
632102199Smjacob}
633102199Smjacob
634102822Smjacobint
635115778Smjacobmpt_write_cfg_page(mpt_softc_t *mpt, int PageAddress, CONFIG_PAGE_HEADER *hdr)
636102199Smjacob{
637102199Smjacob	int count, hdr_attr;
638102199Smjacob	request_t *req;
639102199Smjacob	SGE_SIMPLE32 *se;
640102199Smjacob	MSG_CONFIG *cfgp;
641102199Smjacob	size_t amt;
642102199Smjacob	MSG_CONFIG_REPLY *reply;
643102199Smjacob
644102199Smjacob	req = mpt_get_request(mpt);
645102199Smjacob
646102199Smjacob	cfgp = req->req_vbuf;
647102199Smjacob	bzero(cfgp, sizeof *cfgp);
648102199Smjacob
649102199Smjacob	hdr_attr = hdr->PageType & MPI_CONFIG_PAGEATTR_MASK;
650102199Smjacob	if (hdr_attr != MPI_CONFIG_PAGEATTR_CHANGEABLE &&
651102199Smjacob	    hdr_attr != MPI_CONFIG_PAGEATTR_PERSISTENT) {
652103914Smjacob		mpt_prt(mpt, "page type 0x%x not changeable",
653102199Smjacob		    hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
654102199Smjacob		return (-1);
655102199Smjacob	}
656102199Smjacob	hdr->PageType &= MPI_CONFIG_PAGETYPE_MASK;
657102199Smjacob
658102199Smjacob	cfgp->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
659102199Smjacob	cfgp->Function = MPI_FUNCTION_CONFIG;
660102199Smjacob	cfgp->Header = *hdr;
661103914Smjacob 	amt = (cfgp->Header.PageLength * sizeof (u_int32_t));
662102199Smjacob	cfgp->PageAddress = PageAddress;
663102199Smjacob
664102199Smjacob	se = (SGE_SIMPLE32 *) &cfgp->PageBufferSGE;
665102199Smjacob	se->Address = req->req_pbuf + CFG_DATA_OFF;
666102199Smjacob	MPI_pSGE_SET_LENGTH(se, amt);
667102199Smjacob	MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
668102199Smjacob	    MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
669102199Smjacob	    MPI_SGE_FLAGS_END_OF_LIST | MPI_SGE_FLAGS_HOST_TO_IOC));
670102199Smjacob
671102199Smjacob	cfgp->MsgContext = req->index | 0x80000000;
672102199Smjacob
673102199Smjacob	if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
674102199Smjacob	    cfgp->Header.PageNumber == 0) {
675115778Smjacob		amt = sizeof (CONFIG_PAGE_SCSI_PORT_0);
676102199Smjacob	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
677102199Smjacob	    cfgp->Header.PageNumber == 1) {
678115778Smjacob		amt = sizeof (CONFIG_PAGE_SCSI_PORT_1);
679102199Smjacob	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
680102199Smjacob	    cfgp->Header.PageNumber == 2) {
681115778Smjacob		amt = sizeof (CONFIG_PAGE_SCSI_PORT_2);
682102199Smjacob	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE  &&
683102199Smjacob	    cfgp->Header.PageNumber == 0) {
684115778Smjacob		amt = sizeof (CONFIG_PAGE_SCSI_DEVICE_0);
685102199Smjacob	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE  &&
686102199Smjacob	    cfgp->Header.PageNumber == 1) {
687115778Smjacob		amt = sizeof (CONFIG_PAGE_SCSI_DEVICE_1);
688102199Smjacob	}
689102199Smjacob	bcopy(hdr, ((caddr_t)req->req_vbuf)+CFG_DATA_OFF, amt);
690103914Smjacob	/* Restore stripped out attributes */
691103914Smjacob	hdr->PageType |= hdr_attr;
692102199Smjacob
693102199Smjacob	mpt_check_doorbell(mpt);
694102199Smjacob	mpt_send_cmd(mpt, req);
695102199Smjacob	count = 0;
696102199Smjacob	do {
697102199Smjacob		DELAY(500);
698102199Smjacob		mpt_intr(mpt);
699102199Smjacob		if (++count == 1000) {
700102199Smjacob			hdr->PageType |= hdr_attr;
701103914Smjacob			mpt_prt(mpt, "mpt_write_cfg_page timed out");
702102199Smjacob			return (-1);
703102199Smjacob		}
704102199Smjacob	} while (req->debug == REQ_ON_CHIP);
705102199Smjacob
706102199Smjacob	reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence);
707102199Smjacob        if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
708103914Smjacob		mpt_prt(mpt, "mpt_write_cfg_page: Config Info Status %x",
709102199Smjacob		    reply->IOCStatus);
710103914Smjacob		mpt_free_reply(mpt, (req->sequence << 1));
711102199Smjacob		return (-1);
712102199Smjacob	}
713102199Smjacob	mpt_free_reply(mpt, (req->sequence << 1));
714102199Smjacob
715102199Smjacob	mpt_free_request(mpt, req);
716102199Smjacob	return (0);
717102199Smjacob}
718102199Smjacob
719102199Smjacob/*
720102199Smjacob * Read SCSI configuration information
721102199Smjacob */
722102199Smjacobstatic int
723102199Smjacobmpt_read_config_info_spi(mpt_softc_t *mpt)
724102199Smjacob{
725102199Smjacob	int rv, i;
726102199Smjacob
727102199Smjacob	rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 0,
728102199Smjacob	    0, &mpt->mpt_port_page0.Header);
729102199Smjacob	if (rv) {
730102199Smjacob		return (-1);
731102199Smjacob	}
732102199Smjacob	if (mpt->verbose > 1) {
733103914Smjacob		mpt_prt(mpt, "SPI Port Page 0 Header: %x %x %x %x",
734102199Smjacob		    mpt->mpt_port_page0.Header.PageVersion,
735102199Smjacob		    mpt->mpt_port_page0.Header.PageLength,
736102199Smjacob		    mpt->mpt_port_page0.Header.PageNumber,
737102199Smjacob		    mpt->mpt_port_page0.Header.PageType);
738102199Smjacob	}
739102199Smjacob
740102199Smjacob	rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 1,
741102199Smjacob	    0, &mpt->mpt_port_page1.Header);
742102199Smjacob	if (rv) {
743102199Smjacob		return (-1);
744102199Smjacob	}
745102199Smjacob	if (mpt->verbose > 1) {
746103914Smjacob		mpt_prt(mpt, "SPI Port Page 1 Header: %x %x %x %x",
747102199Smjacob		    mpt->mpt_port_page1.Header.PageVersion,
748102199Smjacob		    mpt->mpt_port_page1.Header.PageLength,
749102199Smjacob		    mpt->mpt_port_page1.Header.PageNumber,
750102199Smjacob		    mpt->mpt_port_page1.Header.PageType);
751102199Smjacob	}
752102199Smjacob
753102199Smjacob	rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 2,
754102199Smjacob	    0, &mpt->mpt_port_page2.Header);
755102199Smjacob	if (rv) {
756102199Smjacob		return (-1);
757102199Smjacob	}
758102199Smjacob
759102199Smjacob	if (mpt->verbose > 1) {
760103914Smjacob		mpt_prt(mpt, "SPI Port Page 2 Header: %x %x %x %x",
761102199Smjacob		    mpt->mpt_port_page1.Header.PageVersion,
762102199Smjacob		    mpt->mpt_port_page1.Header.PageLength,
763102199Smjacob		    mpt->mpt_port_page1.Header.PageNumber,
764102199Smjacob		    mpt->mpt_port_page1.Header.PageType);
765102199Smjacob	}
766102199Smjacob
767102199Smjacob	for (i = 0; i < 16; i++) {
768102199Smjacob		rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE,
769102199Smjacob		    0, i, &mpt->mpt_dev_page0[i].Header);
770102199Smjacob		if (rv) {
771102199Smjacob			return (-1);
772102199Smjacob		}
773102199Smjacob		if (mpt->verbose > 1) {
774103914Smjacob			mpt_prt(mpt,
775103914Smjacob			    "SPI Target %d Device Page 0 Header: %x %x %x %x",
776102199Smjacob			    i, mpt->mpt_dev_page0[i].Header.PageVersion,
777102199Smjacob			    mpt->mpt_dev_page0[i].Header.PageLength,
778102199Smjacob			    mpt->mpt_dev_page0[i].Header.PageNumber,
779102199Smjacob			    mpt->mpt_dev_page0[i].Header.PageType);
780102199Smjacob		}
781102199Smjacob
782102199Smjacob		rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE,
783102199Smjacob		    1, i, &mpt->mpt_dev_page1[i].Header);
784102199Smjacob		if (rv) {
785102199Smjacob			return (-1);
786102199Smjacob		}
787102199Smjacob		if (mpt->verbose > 1) {
788103914Smjacob			mpt_prt(mpt,
789103914Smjacob			    "SPI Target %d Device Page 1 Header: %x %x %x %x",
790102199Smjacob			    i, mpt->mpt_dev_page1[i].Header.PageVersion,
791102199Smjacob			    mpt->mpt_dev_page1[i].Header.PageLength,
792102199Smjacob			    mpt->mpt_dev_page1[i].Header.PageNumber,
793102199Smjacob			    mpt->mpt_dev_page1[i].Header.PageType);
794102199Smjacob		}
795102199Smjacob	}
796102199Smjacob
797102199Smjacob	/*
798102199Smjacob	 * At this point, we don't *have* to fail. As long as we have
799102199Smjacob	 * valid config header information, we can (barely) lurch
800102199Smjacob	 * along.
801102199Smjacob	 */
802102199Smjacob
803102199Smjacob	rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page0.Header);
804102199Smjacob	if (rv) {
805103914Smjacob		mpt_prt(mpt, "failed to read SPI Port Page 0");
806102199Smjacob	} else if (mpt->verbose > 1) {
807103914Smjacob		mpt_prt(mpt,
808103914Smjacob		    "SPI Port Page 0: Capabilities %x PhysicalInterface %x",
809102199Smjacob		    mpt->mpt_port_page0.Capabilities,
810102199Smjacob		    mpt->mpt_port_page0.PhysicalInterface);
811102199Smjacob	}
812102199Smjacob
813102199Smjacob	rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page1.Header);
814102199Smjacob	if (rv) {
815103914Smjacob		mpt_prt(mpt, "failed to read SPI Port Page 1");
816102199Smjacob	} else if (mpt->verbose > 1) {
817103914Smjacob		mpt_prt(mpt,
818103914Smjacob		    "SPI Port Page 1: Configuration %x OnBusTimerValue %x",
819102199Smjacob		    mpt->mpt_port_page1.Configuration,
820102199Smjacob		    mpt->mpt_port_page1.OnBusTimerValue);
821102199Smjacob	}
822102199Smjacob
823102199Smjacob	rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page2.Header);
824102199Smjacob	if (rv) {
825103914Smjacob		mpt_prt(mpt, "failed to read SPI Port Page 2");
826102199Smjacob	} else if (mpt->verbose > 1) {
827103914Smjacob		mpt_prt(mpt,
828103914Smjacob		    "SPI Port Page 2: Flags %x Settings %x",
829102199Smjacob		    mpt->mpt_port_page2.PortFlags,
830102199Smjacob		    mpt->mpt_port_page2.PortSettings);
831102199Smjacob		for (i = 0; i < 16; i++) {
832103914Smjacob			mpt_prt(mpt,
833103914Smjacob		  	    "SPI Port Page 2 Tgt %d: timo %x SF %x Flags %x",
834102199Smjacob			    i, mpt->mpt_port_page2.DeviceSettings[i].Timeout,
835102199Smjacob			    mpt->mpt_port_page2.DeviceSettings[i].SyncFactor,
836102199Smjacob			    mpt->mpt_port_page2.DeviceSettings[i].DeviceFlags);
837102199Smjacob		}
838102199Smjacob	}
839102199Smjacob
840102199Smjacob	for (i = 0; i < 16; i++) {
841102199Smjacob		rv = mpt_read_cfg_page(mpt, i, &mpt->mpt_dev_page0[i].Header);
842102199Smjacob		if (rv) {
843103914Smjacob			mpt_prt(mpt, "cannot read SPI Tgt %d Device Page 0", i);
844102199Smjacob			continue;
845102199Smjacob		}
846102199Smjacob		if (mpt->verbose > 1) {
847103914Smjacob			mpt_prt(mpt,
848103914Smjacob			    "SPI Tgt %d Page 0: NParms %x Information %x",
849102199Smjacob			    i, mpt->mpt_dev_page0[i].NegotiatedParameters,
850102199Smjacob			    mpt->mpt_dev_page0[i].Information);
851102199Smjacob		}
852102199Smjacob		rv = mpt_read_cfg_page(mpt, i, &mpt->mpt_dev_page1[i].Header);
853102199Smjacob		if (rv) {
854103914Smjacob			mpt_prt(mpt, "cannot read SPI Tgt %d Device Page 1", i);
855102199Smjacob			continue;
856102199Smjacob		}
857102199Smjacob		if (mpt->verbose > 1) {
858103914Smjacob			mpt_prt(mpt,
859103914Smjacob			    "SPI Tgt %d Page 1: RParms %x Configuration %x",
860102199Smjacob			    i, mpt->mpt_dev_page1[i].RequestedParameters,
861102199Smjacob			    mpt->mpt_dev_page1[i].Configuration);
862102199Smjacob		}
863102199Smjacob	}
864102199Smjacob	return (0);
865102199Smjacob}
866102199Smjacob
867102199Smjacob/*
868102199Smjacob * Validate SPI configuration information.
869102199Smjacob *
870102199Smjacob * In particular, validate SPI Port Page 1.
871102199Smjacob */
872102199Smjacobstatic int
873102199Smjacobmpt_set_initial_config_spi(mpt_softc_t *mpt)
874102199Smjacob{
875102199Smjacob	int i, pp1val = ((1 << mpt->mpt_ini_id) << 16) | mpt->mpt_ini_id;
876102199Smjacob
877102822Smjacob	mpt->mpt_disc_enable = 0xff;
878102822Smjacob	mpt->mpt_tag_enable = 0;
879102822Smjacob
880102199Smjacob	if (mpt->mpt_port_page1.Configuration != pp1val) {
881115778Smjacob		CONFIG_PAGE_SCSI_PORT_1 tmp;
882103914Smjacob		mpt_prt(mpt,
883103914Smjacob		    "SPI Port Page 1 Config value bad (%x)- should be %x",
884102199Smjacob		    mpt->mpt_port_page1.Configuration, pp1val);
885102199Smjacob		tmp = mpt->mpt_port_page1;
886102199Smjacob		tmp.Configuration = pp1val;
887102199Smjacob		if (mpt_write_cfg_page(mpt, 0, &tmp.Header)) {
888102199Smjacob			return (-1);
889102199Smjacob		}
890102199Smjacob		if (mpt_read_cfg_page(mpt, 0, &tmp.Header)) {
891102199Smjacob			return (-1);
892102199Smjacob		}
893102199Smjacob		if (tmp.Configuration != pp1val) {
894103914Smjacob			mpt_prt(mpt,
895103914Smjacob			    "failed to reset SPI Port Page 1 Config value");
896102199Smjacob			return (-1);
897102199Smjacob		}
898102199Smjacob		mpt->mpt_port_page1 = tmp;
899102199Smjacob	}
900102199Smjacob
901102199Smjacob	for (i = 0; i < 16; i++) {
902115778Smjacob		CONFIG_PAGE_SCSI_DEVICE_1 tmp;
903102199Smjacob		tmp = mpt->mpt_dev_page1[i];
904102199Smjacob		tmp.RequestedParameters = 0;
905102199Smjacob		tmp.Configuration = 0;
906102199Smjacob		if (mpt->verbose > 1) {
907103914Smjacob			mpt_prt(mpt,
908103914Smjacob			    "Set Tgt %d SPI DevicePage 1 values to %x 0 %x",
909102199Smjacob			    i, tmp.RequestedParameters, tmp.Configuration);
910102199Smjacob		}
911102199Smjacob		if (mpt_write_cfg_page(mpt, i, &tmp.Header)) {
912102199Smjacob			return (-1);
913102199Smjacob		}
914102199Smjacob		if (mpt_read_cfg_page(mpt, i, &tmp.Header)) {
915102199Smjacob			return (-1);
916102199Smjacob		}
917102199Smjacob		mpt->mpt_dev_page1[i] = tmp;
918102199Smjacob		if (mpt->verbose > 1) {
919103914Smjacob			mpt_prt(mpt,
920103914Smjacob		 	    "SPI Tgt %d Page 1: RParm %x Configuration %x", i,
921102199Smjacob			    mpt->mpt_dev_page1[i].RequestedParameters,
922102199Smjacob			    mpt->mpt_dev_page1[i].Configuration);
923102199Smjacob		}
924102199Smjacob	}
925102199Smjacob	return (0);
926102199Smjacob}
927102199Smjacob
928102199Smjacob/*
929102199Smjacob * Enable IOC port
930102199Smjacob */
931102199Smjacobstatic int
932102199Smjacobmpt_send_port_enable(mpt_softc_t *mpt, int port)
933102199Smjacob{
934102199Smjacob	int count;
935102199Smjacob	request_t *req;
936101704Smjacob	MSG_PORT_ENABLE *enable_req;
937101704Smjacob
938101704Smjacob	req = mpt_get_request(mpt);
939101704Smjacob
940101704Smjacob	enable_req = req->req_vbuf;
941101704Smjacob	bzero(enable_req, sizeof *enable_req);
942101704Smjacob
943101704Smjacob	enable_req->Function   = MPI_FUNCTION_PORT_ENABLE;
944101704Smjacob	enable_req->MsgContext = req->index | 0x80000000;
945101704Smjacob	enable_req->PortNumber = port;
946101704Smjacob
947101704Smjacob	mpt_check_doorbell(mpt);
948101704Smjacob	if (mpt->verbose > 1) {
949103914Smjacob		mpt_prt(mpt, "enabling port %d", port);
950101704Smjacob	}
951101704Smjacob	mpt_send_cmd(mpt, req);
952101704Smjacob
953101704Smjacob	count = 0;
954101704Smjacob	do {
955101704Smjacob		DELAY(500);
956101704Smjacob		mpt_intr(mpt);
957103871Smjacob		if (++count == 100000) {
958103914Smjacob			mpt_prt(mpt, "port enable timed out");
959101704Smjacob			return (-1);
960101704Smjacob		}
961101704Smjacob	} while (req->debug == REQ_ON_CHIP);
962101704Smjacob	mpt_free_request(mpt, req);
963101704Smjacob	return (0);
964101704Smjacob}
965101704Smjacob
966101704Smjacob/*
967101704Smjacob * Enable/Disable asynchronous event reporting.
968101704Smjacob *
969101704Smjacob * NB: this is the first command we send via shared memory
970101704Smjacob * instead of the handshake register.
971101704Smjacob */
972101704Smjacobstatic int
973102199Smjacobmpt_send_event_request(mpt_softc_t *mpt, int onoff)
974101704Smjacob{
975101704Smjacob	request_t *req;
976101704Smjacob	MSG_EVENT_NOTIFY *enable_req;
977101704Smjacob
978101704Smjacob	req = mpt_get_request(mpt);
979101704Smjacob
980101704Smjacob	enable_req = req->req_vbuf;
981101704Smjacob	bzero(enable_req, sizeof *enable_req);
982101704Smjacob
983101704Smjacob	enable_req->Function   = MPI_FUNCTION_EVENT_NOTIFICATION;
984101704Smjacob	enable_req->MsgContext = req->index | 0x80000000;
985101704Smjacob	enable_req->Switch     = onoff;
986101704Smjacob
987101704Smjacob	mpt_check_doorbell(mpt);
988101704Smjacob	if (mpt->verbose > 1) {
989103914Smjacob		mpt_prt(mpt, "%sabling async events", onoff? "en" : "dis");
990101704Smjacob	}
991101704Smjacob	mpt_send_cmd(mpt, req);
992101704Smjacob
993101704Smjacob	return (0);
994101704Smjacob}
995101704Smjacob
996101704Smjacob/*
997101704Smjacob * Un-mask the interupts on the chip.
998101704Smjacob */
999101704Smjacobvoid
1000102199Smjacobmpt_enable_ints(mpt_softc_t *mpt)
1001101704Smjacob{
1002101704Smjacob	/* Unmask every thing except door bell int */
1003101704Smjacob	mpt_write(mpt, MPT_OFFSET_INTR_MASK, MPT_INTR_DB_MASK);
1004101704Smjacob}
1005101704Smjacob
1006101704Smjacob/*
1007101704Smjacob * Mask the interupts on the chip.
1008101704Smjacob */
1009101704Smjacobvoid
1010102199Smjacobmpt_disable_ints(mpt_softc_t *mpt)
1011101704Smjacob{
1012101704Smjacob	/* Mask all interrupts */
1013101704Smjacob	mpt_write(mpt, MPT_OFFSET_INTR_MASK,
1014101704Smjacob	    MPT_INTR_REPLY_MASK | MPT_INTR_DB_MASK);
1015101704Smjacob}
1016101704Smjacob
1017101704Smjacob/* (Re)Initialize the chip for use */
1018101704Smjacobint
1019102199Smjacobmpt_init(mpt_softc_t *mpt, u_int32_t who)
1020101704Smjacob{
1021101704Smjacob        int try;
1022101704Smjacob        MSG_IOC_FACTS_REPLY facts;
1023102199Smjacob        MSG_PORT_FACTS_REPLY pfp;
1024101704Smjacob	u_int32_t pptr;
1025101704Smjacob        int val;
1026101704Smjacob
1027101704Smjacob	/* Put all request buffers (back) on the free list */
1028101704Smjacob        SLIST_INIT(&mpt->request_free_list);
1029103871Smjacob	for (val = 0; val < MPT_MAX_REQUESTS(mpt); val++) {
1030103871Smjacob		mpt_free_request(mpt, &mpt->request_pool[val]);
1031101704Smjacob	}
1032101704Smjacob
1033101704Smjacob	if (mpt->verbose > 1) {
1034103914Smjacob		mpt_prt(mpt, "doorbell req = %s",
1035101704Smjacob		    mpt_ioc_diag(mpt_read(mpt, MPT_OFFSET_DOORBELL)));
1036101704Smjacob	}
1037101704Smjacob
1038101704Smjacob	/*
1039101704Smjacob	 * Start by making sure we're not at FAULT or RESET state
1040101704Smjacob	 */
1041101704Smjacob	switch (mpt_rd_db(mpt) & MPT_DB_STATE_MASK) {
1042101704Smjacob	case MPT_DB_STATE_RESET:
1043101704Smjacob	case MPT_DB_STATE_FAULT:
1044101704Smjacob		if (mpt_reset(mpt) != MPT_OK) {
1045101704Smjacob			return (EIO);
1046101704Smjacob		}
1047101704Smjacob	default:
1048101704Smjacob		break;
1049101704Smjacob	}
1050101704Smjacob
1051101704Smjacob	for (try = 0; try < MPT_MAX_TRYS; try++) {
1052101704Smjacob		/*
1053101704Smjacob		 * No need to reset if the IOC is already in the READY state.
1054101704Smjacob		 *
1055101704Smjacob		 * Force reset if initialization failed previously.
1056101704Smjacob		 * Note that a hard_reset of the second channel of a '929
1057101704Smjacob		 * will stop operation of the first channel.  Hopefully, if the
1058101704Smjacob		 * first channel is ok, the second will not require a hard
1059101704Smjacob		 * reset.
1060101704Smjacob		 */
1061101704Smjacob		if ((mpt_rd_db(mpt) & MPT_DB_STATE_MASK) !=
1062101704Smjacob		    MPT_DB_STATE_READY) {
1063101704Smjacob			if (mpt_reset(mpt) != MPT_OK) {
1064101704Smjacob				DELAY(10000);
1065101704Smjacob				continue;
1066101704Smjacob			}
1067101704Smjacob		}
1068101704Smjacob
1069101704Smjacob		if (mpt_get_iocfacts(mpt, &facts) != MPT_OK) {
1070103914Smjacob			mpt_prt(mpt, "mpt_get_iocfacts failed");
1071101704Smjacob			continue;
1072102199Smjacob		}
1073102199Smjacob
1074102199Smjacob		if (mpt->verbose > 1) {
1075103914Smjacob			mpt_prt(mpt,
1076103871Smjacob			    "IOCFACTS: GlobalCredits=%d BlockSize=%u "
1077101704Smjacob			    "Request Frame Size %u\n", facts.GlobalCredits,
1078101704Smjacob			    facts.BlockSize, facts.RequestFrameSize);
1079101704Smjacob		}
1080101704Smjacob		mpt->mpt_global_credits = facts.GlobalCredits;
1081101704Smjacob		mpt->request_frame_size = facts.RequestFrameSize;
1082101704Smjacob
1083102199Smjacob		if (mpt_get_portfacts(mpt, &pfp) != MPT_OK) {
1084103914Smjacob			mpt_prt(mpt, "mpt_get_portfacts failed");
1085102199Smjacob			continue;
1086102199Smjacob		}
1087102199Smjacob
1088102199Smjacob		if (mpt->verbose > 1) {
1089103914Smjacob			mpt_prt(mpt,
1090103871Smjacob			    "PORTFACTS: Type %x PFlags %x IID %d MaxDev %d\n",
1091103871Smjacob			    pfp.PortType, pfp.ProtocolFlags, pfp.PortSCSIID,
1092103871Smjacob			    pfp.MaxDevices);
1093102199Smjacob		}
1094102199Smjacob
1095102199Smjacob		if (pfp.PortType != MPI_PORTFACTS_PORTTYPE_SCSI &&
1096102199Smjacob		    pfp.PortType != MPI_PORTFACTS_PORTTYPE_FC) {
1097103914Smjacob			mpt_prt(mpt, "Unsupported Port Type (%x)",
1098102199Smjacob			    pfp.PortType);
1099102199Smjacob			return (ENXIO);
1100102199Smjacob		}
1101102199Smjacob		if (!(pfp.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)) {
1102103914Smjacob			mpt_prt(mpt, "initiator role unsupported");
1103102199Smjacob			return (ENXIO);
1104102199Smjacob		}
1105102199Smjacob		if (pfp.PortType == MPI_PORTFACTS_PORTTYPE_FC) {
1106102199Smjacob			mpt->is_fc = 1;
1107102199Smjacob		} else {
1108102199Smjacob			mpt->is_fc = 0;
1109102199Smjacob		}
1110102199Smjacob		mpt->mpt_ini_id = pfp.PortSCSIID;
1111102199Smjacob
1112101704Smjacob		if (mpt_send_ioc_init(mpt, who) != MPT_OK) {
1113103914Smjacob			mpt_prt(mpt, "mpt_send_ioc_init failed");
1114101704Smjacob			continue;
1115102199Smjacob		}
1116102199Smjacob
1117102199Smjacob		if (mpt->verbose > 1) {
1118103914Smjacob			mpt_prt(mpt, "mpt_send_ioc_init ok");
1119101704Smjacob		}
1120101704Smjacob
1121101704Smjacob		if (mpt_wait_state(mpt, MPT_DB_STATE_RUNNING) != MPT_OK) {
1122103914Smjacob			mpt_prt(mpt, "IOC failed to go to run state");
1123101704Smjacob			continue;
1124102199Smjacob		}
1125102199Smjacob		if (mpt->verbose > 1) {
1126103914Smjacob			mpt_prt(mpt, "IOC now at RUNSTATE");
1127101704Smjacob		}
1128101704Smjacob
1129101704Smjacob		/*
1130101704Smjacob		 * Give it reply buffers
1131101704Smjacob		 *
1132101704Smjacob		 * Do *not* except global credits.
1133101704Smjacob		 */
1134101704Smjacob		for (val = 0, pptr = mpt->reply_phys;
1135101704Smjacob		    (pptr + MPT_REPLY_SIZE) < (mpt->reply_phys + PAGE_SIZE);
1136101704Smjacob		     pptr += MPT_REPLY_SIZE) {
1137101704Smjacob			mpt_free_reply(mpt, pptr);
1138101704Smjacob			if (++val == mpt->mpt_global_credits - 1)
1139101704Smjacob				break;
1140101704Smjacob		}
1141101704Smjacob
1142102199Smjacob		/*
1143102199Smjacob		 * Enable asynchronous event reporting
1144102199Smjacob		 */
1145101704Smjacob		mpt_send_event_request(mpt, 1);
1146101704Smjacob
1147102199Smjacob
1148102199Smjacob		/*
1149102199Smjacob		 * Read set up initial configuration information
1150102199Smjacob		 * (SPI only for now)
1151102199Smjacob		 */
1152102199Smjacob
1153102199Smjacob		if (mpt->is_fc == 0) {
1154102199Smjacob			if (mpt_read_config_info_spi(mpt)) {
1155102199Smjacob				return (EIO);
1156102199Smjacob			}
1157102199Smjacob			if (mpt_set_initial_config_spi(mpt)) {
1158102199Smjacob				return (EIO);
1159102199Smjacob			}
1160102199Smjacob		}
1161102199Smjacob
1162102199Smjacob		/*
1163102199Smjacob		 * Now enable the port
1164102199Smjacob		 */
1165101704Smjacob		if (mpt_send_port_enable(mpt, 0) != MPT_OK) {
1166103914Smjacob			mpt_prt(mpt, "failed to enable port 0");
1167101704Smjacob			continue;
1168102199Smjacob		}
1169102199Smjacob
1170102199Smjacob		if (mpt->verbose > 1) {
1171103914Smjacob			mpt_prt(mpt, "enabled port 0");
1172101704Smjacob		}
1173101704Smjacob
1174101704Smjacob		/* Everything worked */
1175101704Smjacob		break;
1176101704Smjacob	}
1177101704Smjacob
1178101704Smjacob	if (try >= MPT_MAX_TRYS) {
1179103914Smjacob		mpt_prt(mpt, "failed to initialize IOC");
1180101704Smjacob		return (EIO);
1181101704Smjacob	}
1182101704Smjacob
1183101704Smjacob	if (mpt->verbose > 1) {
1184103914Smjacob		mpt_prt(mpt, "enabling interrupts");
1185101704Smjacob	}
1186101704Smjacob
1187101704Smjacob	mpt_enable_ints(mpt);
1188101704Smjacob	return (0);
1189101704Smjacob}
1190