mpt.c revision 102199
1101704Smjacob/* $FreeBSD: head/sys/dev/mpt/mpt.c 102199 2002-08-20 23:04:08Z mjacob $ */
2101704Smjacob/*
3101704Smjacob * Generic routines for LSI '909 FC  adapters.
4101704Smjacob * FreeBSD Version.
5101704Smjacob *
6101704Smjacob * Copyright (c) 2000, 2001 by Greg Ansley
7101704Smjacob *
8101704Smjacob * Redistribution and use in source and binary forms, with or without
9101704Smjacob * modification, are permitted provided that the following conditions
10101704Smjacob * are met:
11101704Smjacob * 1. Redistributions of source code must retain the above copyright
12101704Smjacob *    notice immediately at the beginning of the file, without modification,
13101704Smjacob *    this list of conditions, and the following disclaimer.
14101704Smjacob * 2. The name of the author may not be used to endorse or promote products
15101704Smjacob *    derived from this software without specific prior written permission.
16101704Smjacob *
17101704Smjacob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18101704Smjacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19101704Smjacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20101704Smjacob * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
21101704Smjacob * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22101704Smjacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23101704Smjacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24101704Smjacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25101704Smjacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26101704Smjacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27101704Smjacob * SUCH DAMAGE.
28101704Smjacob */
29101704Smjacob/*
30101704Smjacob * Additional Copyright (c) 2002 by Matthew Jacob under same license.
31101704Smjacob */
32101704Smjacob
33101704Smjacob#include <dev/mpt/mpt_freebsd.h>
34102199Smjacob
35101704Smjacob#define MPT_MAX_TRYS 3
36101704Smjacob#define MPT_MAX_WAIT 300000
37101704Smjacob
38101704Smjacobstatic int maxwait_ack = 0;
39101704Smjacobstatic int maxwait_int = 0;
40101704Smjacobstatic int maxwait_state = 0;
41101704Smjacob
42102199Smjacobstatic __inline u_int32_t mpt_rd_db(mpt_softc_t *mpt);
43102199Smjacobstatic __inline  u_int32_t mpt_rd_intr(mpt_softc_t *mpt);
44101704Smjacob
45101704Smjacobstatic __inline u_int32_t
46102199Smjacobmpt_rd_db(mpt_softc_t *mpt)
47101704Smjacob{
48101704Smjacob	return mpt_read(mpt, MPT_OFFSET_DOORBELL);
49101704Smjacob}
50101704Smjacob
51101704Smjacobstatic __inline u_int32_t
52102199Smjacobmpt_rd_intr(mpt_softc_t *mpt)
53101704Smjacob{
54101704Smjacob	return mpt_read(mpt, MPT_OFFSET_INTR_STATUS);
55101704Smjacob}
56101704Smjacob
57101704Smjacob/* Busy wait for a door bell to be read by IOC */
58101704Smjacobstatic int
59102199Smjacobmpt_wait_db_ack(mpt_softc_t *mpt)
60101704Smjacob{
61101704Smjacob	int i;
62101704Smjacob	for (i=0; i < MPT_MAX_WAIT; i++) {
63101704Smjacob		if (!MPT_DB_IS_BUSY(mpt_rd_intr(mpt))) {
64101704Smjacob			maxwait_ack = i > maxwait_ack ? i : maxwait_ack;
65101704Smjacob			return MPT_OK;
66101704Smjacob		}
67101704Smjacob
68101704Smjacob		DELAY(100);
69101704Smjacob	}
70101704Smjacob	return MPT_FAIL;
71101704Smjacob}
72101704Smjacob
73101704Smjacob/* Busy wait for a door bell interrupt */
74101704Smjacobstatic int
75102199Smjacobmpt_wait_db_int(mpt_softc_t *mpt)
76101704Smjacob{
77101704Smjacob	int i;
78101704Smjacob	for (i=0; i < MPT_MAX_WAIT; i++) {
79101704Smjacob		if (MPT_DB_INTR(mpt_rd_intr(mpt))) {
80101704Smjacob			maxwait_int = i > maxwait_int ? i : maxwait_int;
81101704Smjacob			return MPT_OK;
82101704Smjacob		}
83101704Smjacob		DELAY(100);
84101704Smjacob	}
85101704Smjacob	return MPT_FAIL;
86101704Smjacob}
87101704Smjacob
88101704Smjacob/* Wait for IOC to transition to a give state */
89101704Smjacobvoid
90102199Smjacobmpt_check_doorbell(mpt_softc_t *mpt)
91101704Smjacob{
92101704Smjacob	u_int32_t db = mpt_rd_db(mpt);
93101704Smjacob	if (MPT_STATE(db) != MPT_DB_STATE_RUNNING) {
94101704Smjacob		device_printf(mpt->dev, "Device not running!\n");
95101704Smjacob		mpt_print_db(db);
96101704Smjacob	}
97101704Smjacob}
98101704Smjacob
99101704Smjacob/* Wait for IOC to transition to a give state */
100101704Smjacobstatic int
101102199Smjacobmpt_wait_state(mpt_softc_t *mpt, enum DB_STATE_BITS state)
102101704Smjacob{
103101704Smjacob	int i;
104101704Smjacob
105101704Smjacob	for (i = 0; i < MPT_MAX_WAIT; i++) {
106101704Smjacob		u_int32_t db = mpt_rd_db(mpt);
107101704Smjacob		if (MPT_STATE(db) == state) {
108101704Smjacob			maxwait_state = i > maxwait_state ? i : maxwait_state;
109101704Smjacob			return (MPT_OK);
110101704Smjacob		}
111101704Smjacob		DELAY(100);
112101704Smjacob	}
113101704Smjacob	return (MPT_FAIL);
114101704Smjacob}
115101704Smjacob
116101704Smjacob
117101704Smjacob/* Issue the reset COMMAND to the IOC */
118101704Smjacobint
119102199Smjacobmpt_soft_reset(mpt_softc_t *mpt)
120101704Smjacob{
121101704Smjacob	if (mpt->verbose) {
122101704Smjacob		device_printf(mpt->dev,"soft reset\n");
123101704Smjacob	}
124101704Smjacob
125101704Smjacob	/* Have to use hard reset if we are not in Running state */
126101704Smjacob	if (MPT_STATE(mpt_rd_db(mpt)) != MPT_DB_STATE_RUNNING) {
127101704Smjacob		device_printf(mpt->dev,
128101704Smjacob		    "soft reset failed: device not running\n");
129101704Smjacob		return MPT_FAIL;
130101704Smjacob	}
131101704Smjacob
132101704Smjacob	/* If door bell is in use we don't have a chance of getting
133101704Smjacob	 * a word in since the IOC probably crashed in message
134101704Smjacob	 * processing. So don't waste our time.
135101704Smjacob	 */
136101704Smjacob	if (MPT_DB_IS_IN_USE(mpt_rd_db(mpt))) {
137101704Smjacob		device_printf(mpt->dev, "soft reset failed: doorbell wedged\n");
138101704Smjacob		return MPT_FAIL;
139101704Smjacob	}
140101704Smjacob
141101704Smjacob	/* Send the reset request to the IOC */
142101704Smjacob	mpt_write(mpt, MPT_OFFSET_DOORBELL,
143101704Smjacob	    MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET << MPI_DOORBELL_FUNCTION_SHIFT);
144101704Smjacob	if (mpt_wait_db_ack(mpt) != MPT_OK) {
145101704Smjacob		device_printf(mpt->dev, "soft reset failed: ack timeout\n");
146101704Smjacob		return MPT_FAIL;
147101704Smjacob	}
148101704Smjacob
149101704Smjacob	/* Wait for the IOC to reload and come out of reset state */
150101704Smjacob	if (mpt_wait_state(mpt, MPT_DB_STATE_READY) != MPT_OK) {
151101704Smjacob		device_printf(mpt->dev,
152101704Smjacob		    "soft reset failed: device did not start running\n");
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) {
169101704Smjacob		device_printf(mpt->dev, "hard reset\n");
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) {
219101704Smjacob			device_printf(mpt->dev, "failed to reset device\n");
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{
230101704Smjacob	if (req == NULL || req != &mpt->requests[req->index]) {
231101704Smjacob		panic("mpt_free_request bad req ptr\n");
232101704Smjacob		return;
233101704Smjacob	}
234101704Smjacob	req->ccb = NULL;
235101704Smjacob	req->debug = REQ_FREE;
236101704Smjacob	SLIST_INSERT_HEAD(&mpt->request_free_list, req, link);
237101704Smjacob}
238101704Smjacob
239101704Smjacob/* Get a command buffer from the free queue */
240101704Smjacobrequest_t *
241102199Smjacobmpt_get_request(mpt_softc_t *mpt)
242101704Smjacob{
243101704Smjacob	request_t *req;
244101704Smjacob	req = SLIST_FIRST(&mpt->request_free_list);
245101704Smjacob	if (req != NULL) {
246101704Smjacob		if (req != &mpt->requests[req->index]) {
247101704Smjacob			panic("mpt_get_request: corrupted request free list\n");
248101704Smjacob		}
249101704Smjacob		if (req->ccb != NULL) {
250101704Smjacob			panic("mpt_get_request: corrupted request free list (ccb)\n");
251101704Smjacob		}
252101704Smjacob		SLIST_REMOVE_HEAD(&mpt->request_free_list, link);
253101704Smjacob		req->debug = REQ_IN_PROGRESS;
254101704Smjacob	}
255101704Smjacob	return req;
256101704Smjacob}
257101704Smjacob
258101704Smjacob/* Pass the command to the IOC */
259101704Smjacobvoid
260102199Smjacobmpt_send_cmd(mpt_softc_t *mpt, request_t *req)
261101704Smjacob{
262101704Smjacob	req->sequence = mpt->sequence++;
263101704Smjacob	if (mpt->verbose > 1) {
264101704Smjacob		u_int32_t *pReq;
265101704Smjacob		pReq = req->req_vbuf;
266101704Smjacob		device_printf(mpt->dev, "Send Request %d (0x%x):\n",
267101704Smjacob		    req->index, req->req_pbuf);
268101704Smjacob		device_printf(mpt->dev, "%08X %08X %08X %08X\n",
269101704Smjacob		    pReq[0], pReq[1], pReq[2], pReq[3]);
270101704Smjacob		device_printf(mpt->dev, "%08X %08X %08X %08X\n",
271101704Smjacob		    pReq[4], pReq[5], pReq[6], pReq[7]);
272101704Smjacob		device_printf(mpt->dev, "%08X %08X %08X %08X\n",
273101704Smjacob		    pReq[8], pReq[9], pReq[10], pReq[11]);
274101704Smjacob		device_printf(mpt->dev, "%08X %08X %08X %08X\n",
275101704Smjacob		    pReq[12], pReq[13], pReq[14], pReq[15]);
276101704Smjacob	}
277101704Smjacob	bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap,
278101704Smjacob	   BUS_DMASYNC_PREWRITE);
279101704Smjacob	req->debug = REQ_ON_CHIP;
280101704Smjacob	mpt_write(mpt, MPT_OFFSET_REQUEST_Q, (u_int32_t) req->req_pbuf);
281101704Smjacob}
282101704Smjacob
283101704Smjacob/*
284101704Smjacob * Give the reply buffer back to the IOC after we have
285101704Smjacob * finished processing it.
286101704Smjacob */
287101704Smjacobvoid
288102199Smjacobmpt_free_reply(mpt_softc_t *mpt, u_int32_t ptr)
289101704Smjacob{
290101704Smjacob     mpt_write(mpt, MPT_OFFSET_REPLY_Q, ptr);
291101704Smjacob}
292101704Smjacob
293101704Smjacob/* Get a reply from the IOC */
294101704Smjacobu_int32_t
295102199Smjacobmpt_pop_reply_queue(mpt_softc_t *mpt)
296101704Smjacob{
297101704Smjacob     return mpt_read(mpt, MPT_OFFSET_REPLY_Q);
298101704Smjacob}
299101704Smjacob
300101704Smjacob/*
301101704Smjacob * Send a command to the IOC via the handshake register.
302101704Smjacob *
303101704Smjacob * Only done at initialization time and for certain unusual
304101704Smjacob * commands such as device/bus reset as specified by LSI.
305101704Smjacob */
306101704Smjacobint
307102199Smjacobmpt_send_handshake_cmd(mpt_softc_t *mpt, size_t len, void *cmd)
308101704Smjacob{
309101704Smjacob	int i;
310101704Smjacob	u_int32_t data, *data32;
311101704Smjacob
312101704Smjacob	/* Check condition of the IOC */
313101704Smjacob	data = mpt_rd_db(mpt);
314101704Smjacob	if (((MPT_STATE(data) != MPT_DB_STATE_READY)	&&
315101704Smjacob	     (MPT_STATE(data) != MPT_DB_STATE_RUNNING)	&&
316101704Smjacob	     (MPT_STATE(data) != MPT_DB_STATE_FAULT))	||
317101704Smjacob	    (  MPT_DB_IS_IN_USE(data) )) {
318101704Smjacob		device_printf(mpt->dev,
319101704Smjacob		    "handshake aborted due to invalid doorbell state\n");
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) {
342101704Smjacob		device_printf(mpt->dev, "mpt_send_handshake_cmd timeout1!\n");
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) {
350101704Smjacob		device_printf(mpt->dev, "mpt_send_handshake_cmd timeout2!\n");
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) {
358101704Smjacob			device_printf(mpt->dev,
359101704Smjacob			    "mpt_send_handshake_cmd timeout! index = %d\n", 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) {
382101704Smjacob		device_printf(mpt->dev, "mpt_recv_handshake_cmd timeout1!\n");
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) {
390101704Smjacob		device_printf(mpt->dev, "mpt_recv_handshake_cmd timeout2!\n");
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)) {
398101704Smjacob		device_printf(mpt->dev,
399101704Smjacob			"reply length does not match message length: "
400101704Smjacob			"got 0x%02x, expected 0x%02x\n",
401101704Smjacob			hdr->MsgLength << 2, reply_len << 1);
402101704Smjacob	}
403101704Smjacob
404101704Smjacob	/* Get rest of the reply; but don't overflow the provided buffer */
405101704Smjacob	left = (hdr->MsgLength << 1) - 2;
406101704Smjacob	reply_left =  reply_len - 2;
407101704Smjacob	while (left--) {
408101704Smjacob		u_int16_t datum;
409101704Smjacob
410101704Smjacob		if (mpt_wait_db_int(mpt) != MPT_OK) {
411101704Smjacob			device_printf(mpt->dev,
412101704Smjacob			    "mpt_recv_handshake_cmd timeout3!\n");
413101704Smjacob			return ETIMEDOUT;
414101704Smjacob		}
415101704Smjacob		datum = mpt_read(mpt, MPT_OFFSET_DOORBELL);
416101704Smjacob
417101704Smjacob		if (reply_left-- > 0)
418101704Smjacob			*data16++ = datum & MPT_DB_DATA_MASK;
419101704Smjacob
420101704Smjacob		mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
421101704Smjacob	}
422101704Smjacob
423101704Smjacob	/* One more wait & clear at the end */
424101704Smjacob	if (mpt_wait_db_int(mpt) != MPT_OK) {
425101704Smjacob		device_printf(mpt->dev, "mpt_recv_handshake_cmd timeout4!\n");
426101704Smjacob		return ETIMEDOUT;
427101704Smjacob	}
428101704Smjacob	mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
429101704Smjacob
430101704Smjacob	if ((hdr->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
431101704Smjacob		if (mpt->verbose > 1)
432101704Smjacob			mpt_print_reply(hdr);
433101704Smjacob		return (MPT_FAIL | hdr->IOCStatus);
434101704Smjacob	}
435101704Smjacob
436101704Smjacob	return (0);
437101704Smjacob}
438101704Smjacob
439101704Smjacobstatic int
440102199Smjacobmpt_get_iocfacts(mpt_softc_t *mpt, MSG_IOC_FACTS_REPLY *freplp)
441101704Smjacob{
442101704Smjacob	MSG_IOC_FACTS f_req;
443101704Smjacob	int error;
444101704Smjacob
445101704Smjacob	bzero(&f_req, sizeof f_req);
446101704Smjacob	f_req.Function = MPI_FUNCTION_IOC_FACTS;
447101704Smjacob	f_req.MsgContext =  0x12071942;
448101704Smjacob	error = mpt_send_handshake_cmd(mpt, sizeof f_req, &f_req);
449101704Smjacob	if (error)
450101704Smjacob		return(error);
451101704Smjacob	error = mpt_recv_handshake_reply(mpt, sizeof (*freplp), freplp);
452101704Smjacob	return (error);
453101704Smjacob}
454101704Smjacob
455102199Smjacobstatic int
456102199Smjacobmpt_get_portfacts(mpt_softc_t *mpt, MSG_PORT_FACTS_REPLY *freplp)
457102199Smjacob{
458102199Smjacob	MSG_PORT_FACTS f_req;
459102199Smjacob	int error;
460102199Smjacob
461102199Smjacob	/* XXX: Only getting PORT FACTS for Port 0 */
462102199Smjacob	bzero(&f_req, sizeof f_req);
463102199Smjacob	f_req.Function = MPI_FUNCTION_PORT_FACTS;
464102199Smjacob	f_req.MsgContext =  0x12071943;
465102199Smjacob	error = mpt_send_handshake_cmd(mpt, sizeof f_req, &f_req);
466102199Smjacob	if (error)
467102199Smjacob		return(error);
468102199Smjacob	error = mpt_recv_handshake_reply(mpt, sizeof (*freplp), freplp);
469102199Smjacob	return (error);
470102199Smjacob}
471102199Smjacob
472101704Smjacob/*
473101704Smjacob * Send the initialization request. This is where we specify how many
474101704Smjacob * SCSI busses and how many devices per bus we wish to emulate.
475101704Smjacob * This is also the command that specifies the max size of the reply
476101704Smjacob * frames from the IOC that we will be allocating.
477101704Smjacob */
478101704Smjacobstatic int
479102199Smjacobmpt_send_ioc_init(mpt_softc_t *mpt, u_int32_t who)
480101704Smjacob{
481101704Smjacob	int error = 0;
482101704Smjacob	MSG_IOC_INIT init;
483101704Smjacob	MSG_IOC_INIT_REPLY reply;
484101704Smjacob
485101704Smjacob	bzero(&init, sizeof init);
486101704Smjacob	init.WhoInit = who;
487101704Smjacob	init.Function = MPI_FUNCTION_IOC_INIT;
488101704Smjacob	if (mpt->is_fc) {
489101704Smjacob		init.MaxDevices = 255;
490101704Smjacob	} else {
491101704Smjacob		init.MaxDevices = 16;
492101704Smjacob	}
493101704Smjacob	init.MaxBuses = 1;
494101704Smjacob	init.ReplyFrameSize = MPT_REPLY_SIZE;
495101704Smjacob	init.MsgContext = 0x12071941;
496101704Smjacob
497101704Smjacob	if ((error = mpt_send_handshake_cmd(mpt, sizeof init, &init)) != 0) {
498101704Smjacob		return(error);
499101704Smjacob	}
500101704Smjacob
501101704Smjacob	error = mpt_recv_handshake_reply(mpt, sizeof reply, &reply);
502101704Smjacob	return (error);
503101704Smjacob}
504101704Smjacob
505102199Smjacob
506102199Smjacob/*
507102199Smjacob * Utiltity routine to read configuration headers and pages
508102199Smjacob */
509102199Smjacob
510101704Smjacobstatic int
511102199Smjacobmpt_read_cfg_header(mpt_softc_t *, int, int, int, fCONFIG_PAGE_HEADER *);
512102199Smjacobstatic int
513102199Smjacobmpt_read_cfg_page(mpt_softc_t *, int, fCONFIG_PAGE_HEADER *);
514102199Smjacobstatic int
515102199Smjacobmpt_write_cfg_page(mpt_softc_t *, int, fCONFIG_PAGE_HEADER *);
516102199Smjacob
517102199Smjacobstatic int
518102199Smjacobmpt_read_cfg_header(mpt_softc_t *mpt, int PageType, int PageNumber,
519102199Smjacob    int PageAddress, fCONFIG_PAGE_HEADER *rslt)
520101704Smjacob{
521101704Smjacob	int count;
522101704Smjacob	request_t *req;
523102199Smjacob	MSG_CONFIG *cfgp;
524102199Smjacob	MSG_CONFIG_REPLY *reply;
525102199Smjacob
526102199Smjacob	req = mpt_get_request(mpt);
527102199Smjacob
528102199Smjacob	cfgp = req->req_vbuf;
529102199Smjacob	bzero(cfgp, sizeof *cfgp);
530102199Smjacob
531102199Smjacob	cfgp->Action = MPI_CONFIG_ACTION_PAGE_HEADER;
532102199Smjacob	cfgp->Function = MPI_FUNCTION_CONFIG;
533102199Smjacob	cfgp->Header.PageNumber = (U8) PageNumber;
534102199Smjacob	cfgp->Header.PageType = (U8) PageType;
535102199Smjacob	cfgp->PageAddress = PageAddress;
536102199Smjacob	MPI_pSGE_SET_FLAGS(((SGE_SIMPLE32 *) &cfgp->PageBufferSGE),
537102199Smjacob	    (MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
538102199Smjacob	    MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_LIST));
539102199Smjacob	cfgp->MsgContext = req->index | 0x80000000;
540102199Smjacob
541102199Smjacob	mpt_check_doorbell(mpt);
542102199Smjacob	mpt_send_cmd(mpt, req);
543102199Smjacob	count = 0;
544102199Smjacob	do {
545102199Smjacob		DELAY(500);
546102199Smjacob		mpt_intr(mpt);
547102199Smjacob		if (++count == 1000) {
548102199Smjacob			device_printf(mpt->dev, "read_cfg_header timed out\n");
549102199Smjacob			return (-1);
550102199Smjacob		}
551102199Smjacob	} while (req->debug == REQ_ON_CHIP);
552102199Smjacob
553102199Smjacob	reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence);
554102199Smjacob        if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
555102199Smjacob		device_printf(mpt->dev,
556102199Smjacob		    "mpt_read_cfg_header: Config Info Status %x\n",
557102199Smjacob		    reply->IOCStatus);
558102199Smjacob		return (-1);
559102199Smjacob	}
560102199Smjacob	bcopy(&reply->Header, rslt, sizeof (fCONFIG_PAGE_HEADER));
561102199Smjacob	mpt_free_reply(mpt, (req->sequence << 1));
562102199Smjacob	mpt_free_request(mpt, req);
563102199Smjacob	return (0);
564102199Smjacob}
565102199Smjacob
566102199Smjacob#define	CFG_DATA_OFF	40
567102199Smjacob
568102199Smjacobstatic int
569102199Smjacobmpt_read_cfg_page(mpt_softc_t *mpt, int PageAddress, fCONFIG_PAGE_HEADER *hdr)
570102199Smjacob{
571102199Smjacob	int count;
572102199Smjacob	request_t *req;
573102199Smjacob	SGE_SIMPLE32 *se;
574102199Smjacob	MSG_CONFIG *cfgp;
575102199Smjacob	size_t amt;
576102199Smjacob	MSG_CONFIG_REPLY *reply;
577102199Smjacob
578102199Smjacob	req = mpt_get_request(mpt);
579102199Smjacob
580102199Smjacob	cfgp = req->req_vbuf;
581102199Smjacob 	amt = (cfgp->Header.PageLength * sizeof (uint32_t));
582102199Smjacob	bzero(cfgp, sizeof *cfgp);
583102199Smjacob	cfgp->Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
584102199Smjacob	cfgp->Function = MPI_FUNCTION_CONFIG;
585102199Smjacob	cfgp->Header = *hdr;
586102199Smjacob	cfgp->Header.PageType &= MPI_CONFIG_PAGETYPE_MASK;
587102199Smjacob	cfgp->PageAddress = PageAddress;
588102199Smjacob	se = (SGE_SIMPLE32 *) &cfgp->PageBufferSGE;
589102199Smjacob	se->Address = req->req_pbuf + CFG_DATA_OFF;
590102199Smjacob	MPI_pSGE_SET_LENGTH(se, amt);
591102199Smjacob	MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
592102199Smjacob	    MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
593102199Smjacob	    MPI_SGE_FLAGS_END_OF_LIST));
594102199Smjacob
595102199Smjacob	cfgp->MsgContext = req->index | 0x80000000;
596102199Smjacob
597102199Smjacob	mpt_check_doorbell(mpt);
598102199Smjacob	mpt_send_cmd(mpt, req);
599102199Smjacob	count = 0;
600102199Smjacob	do {
601102199Smjacob		DELAY(500);
602102199Smjacob		mpt_intr(mpt);
603102199Smjacob		if (++count == 1000) {
604102199Smjacob			device_printf(mpt->dev, "read_cfg_page timed out\n");
605102199Smjacob			return (-1);
606102199Smjacob		}
607102199Smjacob	} while (req->debug == REQ_ON_CHIP);
608102199Smjacob
609102199Smjacob	reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence);
610102199Smjacob        if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
611102199Smjacob		device_printf(mpt->dev,
612102199Smjacob		    "mpt_read_cfg_page: Config Info Status %x\n",
613102199Smjacob		    reply->IOCStatus);
614102199Smjacob		return (-1);
615102199Smjacob	}
616102199Smjacob	mpt_free_reply(mpt, (req->sequence << 1));
617102199Smjacob	bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap,
618102199Smjacob	    BUS_DMASYNC_POSTREAD);
619102199Smjacob	if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
620102199Smjacob	    cfgp->Header.PageNumber == 0) {
621102199Smjacob		amt = sizeof (fCONFIG_PAGE_SCSI_PORT_0);
622102199Smjacob	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
623102199Smjacob	    cfgp->Header.PageNumber == 1) {
624102199Smjacob		amt = sizeof (fCONFIG_PAGE_SCSI_PORT_1);
625102199Smjacob	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
626102199Smjacob	    cfgp->Header.PageNumber == 2) {
627102199Smjacob		amt = sizeof (fCONFIG_PAGE_SCSI_PORT_2);
628102199Smjacob	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE  &&
629102199Smjacob	    cfgp->Header.PageNumber == 0) {
630102199Smjacob		amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_0);
631102199Smjacob	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE  &&
632102199Smjacob	    cfgp->Header.PageNumber == 1) {
633102199Smjacob		amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_1);
634102199Smjacob	}
635102199Smjacob	bcopy(((caddr_t)req->req_vbuf)+CFG_DATA_OFF, hdr, amt);
636102199Smjacob	mpt_free_request(mpt, req);
637102199Smjacob	return (0);
638102199Smjacob}
639102199Smjacob
640102199Smjacobstatic int
641102199Smjacobmpt_write_cfg_page(mpt_softc_t *mpt, int PageAddress, fCONFIG_PAGE_HEADER *hdr)
642102199Smjacob{
643102199Smjacob	int count, hdr_attr;
644102199Smjacob	request_t *req;
645102199Smjacob	SGE_SIMPLE32 *se;
646102199Smjacob	MSG_CONFIG *cfgp;
647102199Smjacob	size_t amt;
648102199Smjacob	MSG_CONFIG_REPLY *reply;
649102199Smjacob
650102199Smjacob	req = mpt_get_request(mpt);
651102199Smjacob
652102199Smjacob	cfgp = req->req_vbuf;
653102199Smjacob	bzero(cfgp, sizeof *cfgp);
654102199Smjacob
655102199Smjacob	hdr_attr = hdr->PageType & MPI_CONFIG_PAGEATTR_MASK;
656102199Smjacob	if (hdr_attr != MPI_CONFIG_PAGEATTR_CHANGEABLE &&
657102199Smjacob	    hdr_attr != MPI_CONFIG_PAGEATTR_PERSISTENT) {
658102199Smjacob		device_printf(mpt->dev, "page type 0x%x not changeable\n",
659102199Smjacob		    hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
660102199Smjacob		return (-1);
661102199Smjacob	}
662102199Smjacob	hdr->PageType &= MPI_CONFIG_PAGETYPE_MASK;
663102199Smjacob
664102199Smjacob 	amt = (cfgp->Header.PageLength * sizeof (uint32_t));
665102199Smjacob	cfgp->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
666102199Smjacob	cfgp->Function = MPI_FUNCTION_CONFIG;
667102199Smjacob	cfgp->Header = *hdr;
668102199Smjacob	cfgp->PageAddress = PageAddress;
669102199Smjacob
670102199Smjacob	se = (SGE_SIMPLE32 *) &cfgp->PageBufferSGE;
671102199Smjacob	se->Address = req->req_pbuf + CFG_DATA_OFF;
672102199Smjacob	MPI_pSGE_SET_LENGTH(se, amt);
673102199Smjacob	MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
674102199Smjacob	    MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
675102199Smjacob	    MPI_SGE_FLAGS_END_OF_LIST | MPI_SGE_FLAGS_HOST_TO_IOC));
676102199Smjacob
677102199Smjacob	cfgp->MsgContext = req->index | 0x80000000;
678102199Smjacob
679102199Smjacob	if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
680102199Smjacob	    cfgp->Header.PageNumber == 0) {
681102199Smjacob		amt = sizeof (fCONFIG_PAGE_SCSI_PORT_0);
682102199Smjacob	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
683102199Smjacob	    cfgp->Header.PageNumber == 1) {
684102199Smjacob		amt = sizeof (fCONFIG_PAGE_SCSI_PORT_1);
685102199Smjacob	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
686102199Smjacob	    cfgp->Header.PageNumber == 2) {
687102199Smjacob		amt = sizeof (fCONFIG_PAGE_SCSI_PORT_2);
688102199Smjacob	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE  &&
689102199Smjacob	    cfgp->Header.PageNumber == 0) {
690102199Smjacob		amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_0);
691102199Smjacob	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE  &&
692102199Smjacob	    cfgp->Header.PageNumber == 1) {
693102199Smjacob		amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_1);
694102199Smjacob	}
695102199Smjacob	bcopy(hdr, ((caddr_t)req->req_vbuf)+CFG_DATA_OFF, amt);
696102199Smjacob
697102199Smjacob	mpt_check_doorbell(mpt);
698102199Smjacob	mpt_send_cmd(mpt, req);
699102199Smjacob	count = 0;
700102199Smjacob	do {
701102199Smjacob		DELAY(500);
702102199Smjacob		mpt_intr(mpt);
703102199Smjacob		if (++count == 1000) {
704102199Smjacob			hdr->PageType |= hdr_attr;
705102199Smjacob			device_printf(mpt->dev,
706102199Smjacob			    "mpt_write_cfg_page timed out\n");
707102199Smjacob			return (-1);
708102199Smjacob		}
709102199Smjacob	} while (req->debug == REQ_ON_CHIP);
710102199Smjacob
711102199Smjacob	reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence);
712102199Smjacob        if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
713102199Smjacob		device_printf(mpt->dev,
714102199Smjacob		    "mpt_write_cfg_page: Config Info Status %x\n",
715102199Smjacob		    reply->IOCStatus);
716102199Smjacob		return (-1);
717102199Smjacob	}
718102199Smjacob	mpt_free_reply(mpt, (req->sequence << 1));
719102199Smjacob
720102199Smjacob	/*
721102199Smjacob	 * Restore stripped out attributes
722102199Smjacob	 */
723102199Smjacob	hdr->PageType |= hdr_attr;
724102199Smjacob	mpt_free_request(mpt, req);
725102199Smjacob	return (0);
726102199Smjacob}
727102199Smjacob
728102199Smjacob/*
729102199Smjacob * Read SCSI configuration information
730102199Smjacob */
731102199Smjacobstatic int
732102199Smjacobmpt_read_config_info_spi(mpt_softc_t *mpt)
733102199Smjacob{
734102199Smjacob	int rv, i;
735102199Smjacob
736102199Smjacob	rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 0,
737102199Smjacob	    0, &mpt->mpt_port_page0.Header);
738102199Smjacob	if (rv) {
739102199Smjacob		return (-1);
740102199Smjacob	}
741102199Smjacob	if (mpt->verbose > 1) {
742102199Smjacob		device_printf(mpt->dev, "SPI Port Page 0 Header: %x %x %x %x\n",
743102199Smjacob		    mpt->mpt_port_page0.Header.PageVersion,
744102199Smjacob		    mpt->mpt_port_page0.Header.PageLength,
745102199Smjacob		    mpt->mpt_port_page0.Header.PageNumber,
746102199Smjacob		    mpt->mpt_port_page0.Header.PageType);
747102199Smjacob	}
748102199Smjacob
749102199Smjacob	rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 1,
750102199Smjacob	    0, &mpt->mpt_port_page1.Header);
751102199Smjacob	if (rv) {
752102199Smjacob		return (-1);
753102199Smjacob	}
754102199Smjacob	if (mpt->verbose > 1) {
755102199Smjacob		device_printf(mpt->dev, "SPI Port Page 1 Header: %x %x %x %x\n",
756102199Smjacob		    mpt->mpt_port_page1.Header.PageVersion,
757102199Smjacob		    mpt->mpt_port_page1.Header.PageLength,
758102199Smjacob		    mpt->mpt_port_page1.Header.PageNumber,
759102199Smjacob		    mpt->mpt_port_page1.Header.PageType);
760102199Smjacob	}
761102199Smjacob
762102199Smjacob	rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 2,
763102199Smjacob	    0, &mpt->mpt_port_page2.Header);
764102199Smjacob	if (rv) {
765102199Smjacob		return (-1);
766102199Smjacob	}
767102199Smjacob
768102199Smjacob	if (mpt->verbose > 1) {
769102199Smjacob		device_printf(mpt->dev, "SPI Port Page 2 Header: %x %x %x %x\n",
770102199Smjacob		    mpt->mpt_port_page1.Header.PageVersion,
771102199Smjacob		    mpt->mpt_port_page1.Header.PageLength,
772102199Smjacob		    mpt->mpt_port_page1.Header.PageNumber,
773102199Smjacob		    mpt->mpt_port_page1.Header.PageType);
774102199Smjacob	}
775102199Smjacob
776102199Smjacob	for (i = 0; i < 16; i++) {
777102199Smjacob		rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE,
778102199Smjacob		    0, i, &mpt->mpt_dev_page0[i].Header);
779102199Smjacob		if (rv) {
780102199Smjacob			return (-1);
781102199Smjacob		}
782102199Smjacob		if (mpt->verbose > 1) {
783102199Smjacob			device_printf(mpt->dev,
784102199Smjacob			    "SPI Target %d Device Page 0 Header: %x %x %x %x\n",
785102199Smjacob			    i, mpt->mpt_dev_page0[i].Header.PageVersion,
786102199Smjacob			    mpt->mpt_dev_page0[i].Header.PageLength,
787102199Smjacob			    mpt->mpt_dev_page0[i].Header.PageNumber,
788102199Smjacob			    mpt->mpt_dev_page0[i].Header.PageType);
789102199Smjacob		}
790102199Smjacob
791102199Smjacob		rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE,
792102199Smjacob		    1, i, &mpt->mpt_dev_page1[i].Header);
793102199Smjacob		if (rv) {
794102199Smjacob			return (-1);
795102199Smjacob		}
796102199Smjacob		if (mpt->verbose > 1) {
797102199Smjacob			device_printf(mpt->dev,
798102199Smjacob			    "SPI Target %d Device Page 1 Header: %x %x %x %x\n",
799102199Smjacob			    i, mpt->mpt_dev_page1[i].Header.PageVersion,
800102199Smjacob			    mpt->mpt_dev_page1[i].Header.PageLength,
801102199Smjacob			    mpt->mpt_dev_page1[i].Header.PageNumber,
802102199Smjacob			    mpt->mpt_dev_page1[i].Header.PageType);
803102199Smjacob		}
804102199Smjacob	}
805102199Smjacob
806102199Smjacob	/*
807102199Smjacob	 * At this point, we don't *have* to fail. As long as we have
808102199Smjacob	 * valid config header information, we can (barely) lurch
809102199Smjacob	 * along.
810102199Smjacob	 */
811102199Smjacob
812102199Smjacob	rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page0.Header);
813102199Smjacob	if (rv) {
814102199Smjacob		device_printf(mpt->dev, "failed to read SPI Port Page 0\n");
815102199Smjacob	} else if (mpt->verbose > 1) {
816102199Smjacob		device_printf(mpt->dev,
817102199Smjacob		    "SPI Port Page 0: Capabilities %x PhysicalInterface %x\n",
818102199Smjacob		    mpt->mpt_port_page0.Capabilities,
819102199Smjacob		    mpt->mpt_port_page0.PhysicalInterface);
820102199Smjacob	}
821102199Smjacob
822102199Smjacob	rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page1.Header);
823102199Smjacob	if (rv) {
824102199Smjacob		device_printf(mpt->dev, "failed to read SPI Port Page 1\n");
825102199Smjacob	} else if (mpt->verbose > 1) {
826102199Smjacob		device_printf(mpt->dev,
827102199Smjacob		    "SPI Port Page 1: Configuration %x OnBusTimerValue %x\n",
828102199Smjacob		    mpt->mpt_port_page1.Configuration,
829102199Smjacob		    mpt->mpt_port_page1.OnBusTimerValue);
830102199Smjacob	}
831102199Smjacob
832102199Smjacob	rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page2.Header);
833102199Smjacob	if (rv) {
834102199Smjacob		device_printf(mpt->dev, "failed to read SPI Port Page 2\n");
835102199Smjacob	} else if (mpt->verbose > 1) {
836102199Smjacob		device_printf(mpt->dev,
837102199Smjacob		    "SPI Port Page 2: Flags %x Settings %x\n",
838102199Smjacob		    mpt->mpt_port_page2.PortFlags,
839102199Smjacob		    mpt->mpt_port_page2.PortSettings);
840102199Smjacob		for (i = 0; i < 16; i++) {
841102199Smjacob			device_printf(mpt->dev,
842102199Smjacob		  	    "SPI Port Page 2 Tgt %d: timo %x SF %x Flags %x\n",
843102199Smjacob			    i, mpt->mpt_port_page2.DeviceSettings[i].Timeout,
844102199Smjacob			    mpt->mpt_port_page2.DeviceSettings[i].SyncFactor,
845102199Smjacob			    mpt->mpt_port_page2.DeviceSettings[i].DeviceFlags);
846102199Smjacob		}
847102199Smjacob	}
848102199Smjacob
849102199Smjacob	for (i = 0; i < 16; i++) {
850102199Smjacob		rv = mpt_read_cfg_page(mpt, i, &mpt->mpt_dev_page0[i].Header);
851102199Smjacob		if (rv) {
852102199Smjacob			device_printf(mpt->dev,
853102199Smjacob			    "cannot read SPI Tgt %d Device Page 0\n", i);
854102199Smjacob			continue;
855102199Smjacob		}
856102199Smjacob		if (mpt->verbose > 1) {
857102199Smjacob			device_printf(mpt->dev,
858102199Smjacob			    "SPI Tgt %d Page 0: NParms %x Information %x\n",
859102199Smjacob			    i, mpt->mpt_dev_page0[i].NegotiatedParameters,
860102199Smjacob			    mpt->mpt_dev_page0[i].Information);
861102199Smjacob		}
862102199Smjacob		rv = mpt_read_cfg_page(mpt, i, &mpt->mpt_dev_page1[i].Header);
863102199Smjacob		if (rv) {
864102199Smjacob			device_printf(mpt->dev,
865102199Smjacob			    "cannot read SPI Tgt %d Device Page 1\n", i);
866102199Smjacob			continue;
867102199Smjacob		}
868102199Smjacob		if (mpt->verbose > 1) {
869102199Smjacob			device_printf(mpt->dev,
870102199Smjacob			    "SPI Tgt %d Page 1: RParms %x Configuration %x\n",
871102199Smjacob			    i, mpt->mpt_dev_page1[i].RequestedParameters,
872102199Smjacob			    mpt->mpt_dev_page1[i].Configuration);
873102199Smjacob		}
874102199Smjacob	}
875102199Smjacob	return (0);
876102199Smjacob}
877102199Smjacob
878102199Smjacob/*
879102199Smjacob * Validate SPI configuration information.
880102199Smjacob *
881102199Smjacob * In particular, validate SPI Port Page 1.
882102199Smjacob */
883102199Smjacobstatic int
884102199Smjacobmpt_set_initial_config_spi(mpt_softc_t *mpt)
885102199Smjacob{
886102199Smjacob	int i, pp1val = ((1 << mpt->mpt_ini_id) << 16) | mpt->mpt_ini_id;
887102199Smjacob
888102199Smjacob	if (mpt->mpt_port_page1.Configuration != pp1val) {
889102199Smjacob		fCONFIG_PAGE_SCSI_PORT_1 tmp;
890102199Smjacob		device_printf(mpt->dev,
891102199Smjacob		    "SPI Port Page 1 Config value bad (%x)- should be %x\n",
892102199Smjacob		    mpt->mpt_port_page1.Configuration, pp1val);
893102199Smjacob		tmp = mpt->mpt_port_page1;
894102199Smjacob		tmp.Configuration = pp1val;
895102199Smjacob		if (mpt_write_cfg_page(mpt, 0, &tmp.Header)) {
896102199Smjacob			return (-1);
897102199Smjacob		}
898102199Smjacob		if (mpt_read_cfg_page(mpt, 0, &tmp.Header)) {
899102199Smjacob			return (-1);
900102199Smjacob		}
901102199Smjacob		if (tmp.Configuration != pp1val) {
902102199Smjacob			device_printf(mpt->dev,
903102199Smjacob			    "failed to reset SPI Port Page 1 Config value\n");
904102199Smjacob			return (-1);
905102199Smjacob		}
906102199Smjacob		mpt->mpt_port_page1 = tmp;
907102199Smjacob	}
908102199Smjacob
909102199Smjacob#if	1
910102199Smjacob	i = i;
911102199Smjacob#else
912102199Smjacob	for (i = 0; i < 16; i++) {
913102199Smjacob		fCONFIG_PAGE_SCSI_DEVICE_1 tmp;
914102199Smjacob		tmp = mpt->mpt_dev_page1[i];
915102199Smjacob		tmp.RequestedParameters = 0;
916102199Smjacob		tmp.Configuration = 0;
917102199Smjacob		if (mpt->verbose > 1) {
918102199Smjacob			device_printf(mpt->dev,
919102199Smjacob			    "Set Tgt %d SPI DevicePage 1 values to %x 0 %x\n",
920102199Smjacob			    i, tmp.RequestedParameters, tmp.Configuration);
921102199Smjacob		}
922102199Smjacob		if (mpt_write_cfg_page(mpt, i, &tmp.Header)) {
923102199Smjacob			return (-1);
924102199Smjacob		}
925102199Smjacob		if (mpt_read_cfg_page(mpt, i, &tmp.Header)) {
926102199Smjacob			return (-1);
927102199Smjacob		}
928102199Smjacob		mpt->mpt_dev_page1[i] = tmp;
929102199Smjacob		if (mpt->verbose > 1) {
930102199Smjacob			device_printf(mpt->dev,
931102199Smjacob		 	    "SPI Tgt %d Page 1: RParm %x Configuration %x\n", i,
932102199Smjacob			    mpt->mpt_dev_page1[i].RequestedParameters,
933102199Smjacob			    mpt->mpt_dev_page1[i].Configuration);
934102199Smjacob		}
935102199Smjacob	}
936102199Smjacob#endif
937102199Smjacob	return (0);
938102199Smjacob}
939102199Smjacob
940102199Smjacob/*
941102199Smjacob * Enable IOC port
942102199Smjacob */
943102199Smjacobstatic int
944102199Smjacobmpt_send_port_enable(mpt_softc_t *mpt, int port)
945102199Smjacob{
946102199Smjacob	int count;
947102199Smjacob	request_t *req;
948101704Smjacob	MSG_PORT_ENABLE *enable_req;
949101704Smjacob
950101704Smjacob	req = mpt_get_request(mpt);
951101704Smjacob
952101704Smjacob	enable_req = req->req_vbuf;
953101704Smjacob	bzero(enable_req, sizeof *enable_req);
954101704Smjacob
955101704Smjacob	enable_req->Function   = MPI_FUNCTION_PORT_ENABLE;
956101704Smjacob	enable_req->MsgContext = req->index | 0x80000000;
957101704Smjacob	enable_req->PortNumber = port;
958101704Smjacob
959101704Smjacob	mpt_check_doorbell(mpt);
960101704Smjacob	if (mpt->verbose > 1) {
961101704Smjacob		device_printf(mpt->dev, "enabling port %d\n", port);
962101704Smjacob	}
963101704Smjacob	mpt_send_cmd(mpt, req);
964101704Smjacob
965101704Smjacob	count = 0;
966101704Smjacob	do {
967101704Smjacob		DELAY(500);
968101704Smjacob		mpt_intr(mpt);
969101704Smjacob		if (++count == 1000) {
970101704Smjacob			device_printf(mpt->dev, "port enable timed out\n");
971101704Smjacob			return (-1);
972101704Smjacob		}
973101704Smjacob	} while (req->debug == REQ_ON_CHIP);
974101704Smjacob	mpt_free_request(mpt, req);
975101704Smjacob	return (0);
976101704Smjacob}
977101704Smjacob
978101704Smjacob/*
979101704Smjacob * Enable/Disable asynchronous event reporting.
980101704Smjacob *
981101704Smjacob * NB: this is the first command we send via shared memory
982101704Smjacob * instead of the handshake register.
983101704Smjacob */
984101704Smjacobstatic int
985102199Smjacobmpt_send_event_request(mpt_softc_t *mpt, int onoff)
986101704Smjacob{
987101704Smjacob	request_t *req;
988101704Smjacob	MSG_EVENT_NOTIFY *enable_req;
989101704Smjacob
990101704Smjacob	req = mpt_get_request(mpt);
991101704Smjacob
992101704Smjacob	enable_req = req->req_vbuf;
993101704Smjacob	bzero(enable_req, sizeof *enable_req);
994101704Smjacob
995101704Smjacob	enable_req->Function   = MPI_FUNCTION_EVENT_NOTIFICATION;
996101704Smjacob	enable_req->MsgContext = req->index | 0x80000000;
997101704Smjacob	enable_req->Switch     = onoff;
998101704Smjacob
999101704Smjacob	mpt_check_doorbell(mpt);
1000101704Smjacob	if (mpt->verbose > 1) {
1001101704Smjacob		device_printf(mpt->dev, "%sabling async events\n",
1002101704Smjacob		    onoff? "en" : "dis");
1003101704Smjacob	}
1004101704Smjacob	mpt_send_cmd(mpt, req);
1005101704Smjacob
1006101704Smjacob	return (0);
1007101704Smjacob}
1008101704Smjacob
1009101704Smjacob/*
1010101704Smjacob * Un-mask the interupts on the chip.
1011101704Smjacob */
1012101704Smjacobvoid
1013102199Smjacobmpt_enable_ints(mpt_softc_t *mpt)
1014101704Smjacob{
1015101704Smjacob	/* Unmask every thing except door bell int */
1016101704Smjacob	mpt_write(mpt, MPT_OFFSET_INTR_MASK, MPT_INTR_DB_MASK);
1017101704Smjacob}
1018101704Smjacob
1019101704Smjacob/*
1020101704Smjacob * Mask the interupts on the chip.
1021101704Smjacob */
1022101704Smjacobvoid
1023102199Smjacobmpt_disable_ints(mpt_softc_t *mpt)
1024101704Smjacob{
1025101704Smjacob	/* Mask all interrupts */
1026101704Smjacob	mpt_write(mpt, MPT_OFFSET_INTR_MASK,
1027101704Smjacob	    MPT_INTR_REPLY_MASK | MPT_INTR_DB_MASK);
1028101704Smjacob}
1029101704Smjacob
1030101704Smjacob/* (Re)Initialize the chip for use */
1031101704Smjacobint
1032102199Smjacobmpt_init(mpt_softc_t *mpt, u_int32_t who)
1033101704Smjacob{
1034101704Smjacob        int try;
1035101704Smjacob        MSG_IOC_FACTS_REPLY facts;
1036102199Smjacob        MSG_PORT_FACTS_REPLY pfp;
1037101704Smjacob	u_int32_t pptr;
1038101704Smjacob        int val;
1039101704Smjacob
1040101704Smjacob	/* Put all request buffers (back) on the free list */
1041101704Smjacob        SLIST_INIT(&mpt->request_free_list);
1042101704Smjacob	for (val = 0; val < MPT_MAX_REQUESTS; val++) {
1043101704Smjacob		mpt_free_request(mpt, &mpt->requests[val]);
1044101704Smjacob	}
1045101704Smjacob
1046101704Smjacob	if (mpt->verbose > 1) {
1047101704Smjacob		device_printf(mpt->dev, "doorbell req = %s\n",
1048101704Smjacob		    mpt_ioc_diag(mpt_read(mpt, MPT_OFFSET_DOORBELL)));
1049101704Smjacob	}
1050101704Smjacob
1051101704Smjacob	/*
1052101704Smjacob	 * Start by making sure we're not at FAULT or RESET state
1053101704Smjacob	 */
1054101704Smjacob	switch (mpt_rd_db(mpt) & MPT_DB_STATE_MASK) {
1055101704Smjacob	case MPT_DB_STATE_RESET:
1056101704Smjacob	case MPT_DB_STATE_FAULT:
1057101704Smjacob		if (mpt_reset(mpt) != MPT_OK) {
1058101704Smjacob			return (EIO);
1059101704Smjacob		}
1060101704Smjacob	default:
1061101704Smjacob		break;
1062101704Smjacob	}
1063101704Smjacob
1064101704Smjacob
1065101704Smjacob	for (try = 0; try < MPT_MAX_TRYS; try++) {
1066101704Smjacob		/*
1067101704Smjacob		 * No need to reset if the IOC is already in the READY state.
1068101704Smjacob		 *
1069101704Smjacob		 * Force reset if initialization failed previously.
1070101704Smjacob		 * Note that a hard_reset of the second channel of a '929
1071101704Smjacob		 * will stop operation of the first channel.  Hopefully, if the
1072101704Smjacob		 * first channel is ok, the second will not require a hard
1073101704Smjacob		 * reset.
1074101704Smjacob		 */
1075101704Smjacob		if ((mpt_rd_db(mpt) & MPT_DB_STATE_MASK) !=
1076101704Smjacob		    MPT_DB_STATE_READY) {
1077101704Smjacob			if (mpt_reset(mpt) != MPT_OK) {
1078101704Smjacob				DELAY(10000);
1079101704Smjacob				continue;
1080101704Smjacob			}
1081101704Smjacob		}
1082101704Smjacob
1083101704Smjacob		if (mpt_get_iocfacts(mpt, &facts) != MPT_OK) {
1084101704Smjacob			device_printf(mpt->dev, "mpt_get_iocfacts failed\n");
1085101704Smjacob			continue;
1086102199Smjacob		}
1087102199Smjacob
1088102199Smjacob		if (mpt->verbose > 1) {
1089101704Smjacob			device_printf(mpt->dev,
1090101704Smjacob			    "mpt_get_iocfacts: GlobalCredits=%d BlockSize=%u "
1091101704Smjacob			    "Request Frame Size %u\n", facts.GlobalCredits,
1092101704Smjacob			    facts.BlockSize, facts.RequestFrameSize);
1093101704Smjacob		}
1094101704Smjacob		mpt->mpt_global_credits = facts.GlobalCredits;
1095101704Smjacob		mpt->request_frame_size = facts.RequestFrameSize;
1096101704Smjacob
1097102199Smjacob		if (mpt_get_portfacts(mpt, &pfp) != MPT_OK) {
1098102199Smjacob			device_printf(mpt->dev, "mpt_get_portfacts failed\n");
1099102199Smjacob			continue;
1100102199Smjacob		}
1101102199Smjacob
1102102199Smjacob		if (mpt->verbose > 1) {
1103102199Smjacob			device_printf(mpt->dev,
1104102199Smjacob			    "mpt_get_portfacts: Type %x PFlags %x IID %d\n",
1105102199Smjacob			    pfp.PortType, pfp.ProtocolFlags, pfp.PortSCSIID);
1106102199Smjacob		}
1107102199Smjacob
1108102199Smjacob		if (pfp.PortType != MPI_PORTFACTS_PORTTYPE_SCSI &&
1109102199Smjacob		    pfp.PortType != MPI_PORTFACTS_PORTTYPE_FC) {
1110102199Smjacob			device_printf(mpt->dev, "Unsupported Port Type (%x)\n",
1111102199Smjacob			    pfp.PortType);
1112102199Smjacob			return (ENXIO);
1113102199Smjacob		}
1114102199Smjacob		if (!(pfp.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)) {
1115102199Smjacob			device_printf(mpt->dev, "initiator role unsupported\n");
1116102199Smjacob			return (ENXIO);
1117102199Smjacob		}
1118102199Smjacob		if (pfp.PortType == MPI_PORTFACTS_PORTTYPE_FC) {
1119102199Smjacob			mpt->is_fc = 1;
1120102199Smjacob		} else {
1121102199Smjacob			mpt->is_fc = 0;
1122102199Smjacob		}
1123102199Smjacob		mpt->mpt_ini_id = pfp.PortSCSIID;
1124102199Smjacob
1125101704Smjacob		if (mpt_send_ioc_init(mpt, who) != MPT_OK) {
1126101704Smjacob			device_printf(mpt->dev, "mpt_send_ioc_init failed\n");
1127101704Smjacob			continue;
1128102199Smjacob		}
1129102199Smjacob
1130102199Smjacob		if (mpt->verbose > 1) {
1131101704Smjacob			device_printf(mpt->dev, "mpt_send_ioc_init ok\n");
1132101704Smjacob		}
1133101704Smjacob
1134101704Smjacob		if (mpt_wait_state(mpt, MPT_DB_STATE_RUNNING) != MPT_OK) {
1135101704Smjacob			device_printf(mpt->dev,
1136101704Smjacob			    "IOC failed to go to run state\n");
1137101704Smjacob			continue;
1138102199Smjacob		}
1139102199Smjacob		if (mpt->verbose > 1) {
1140101704Smjacob			device_printf(mpt->dev, "IOC now at RUNSTATE\n");
1141101704Smjacob		}
1142101704Smjacob
1143101704Smjacob		/*
1144101704Smjacob		 * Give it reply buffers
1145101704Smjacob		 *
1146101704Smjacob		 * Do *not* except global credits.
1147101704Smjacob		 */
1148101704Smjacob		for (val = 0, pptr = mpt->reply_phys;
1149101704Smjacob		    (pptr + MPT_REPLY_SIZE) < (mpt->reply_phys + PAGE_SIZE);
1150101704Smjacob		     pptr += MPT_REPLY_SIZE) {
1151101704Smjacob			mpt_free_reply(mpt, pptr);
1152101704Smjacob			if (++val == mpt->mpt_global_credits - 1)
1153101704Smjacob				break;
1154101704Smjacob		}
1155101704Smjacob
1156102199Smjacob		/*
1157102199Smjacob		 * Enable asynchronous event reporting
1158102199Smjacob		 */
1159101704Smjacob		mpt_send_event_request(mpt, 1);
1160101704Smjacob
1161102199Smjacob
1162102199Smjacob		/*
1163102199Smjacob		 * Read set up initial configuration information
1164102199Smjacob		 * (SPI only for now)
1165102199Smjacob		 */
1166102199Smjacob
1167102199Smjacob		if (mpt->is_fc == 0) {
1168102199Smjacob			if (mpt_read_config_info_spi(mpt)) {
1169102199Smjacob				return (EIO);
1170102199Smjacob			}
1171102199Smjacob			if (mpt_set_initial_config_spi(mpt)) {
1172102199Smjacob				return (EIO);
1173102199Smjacob			}
1174102199Smjacob		}
1175102199Smjacob
1176102199Smjacob		/*
1177102199Smjacob		 * Now enable the port
1178102199Smjacob		 */
1179101704Smjacob		if (mpt_send_port_enable(mpt, 0) != MPT_OK) {
1180101704Smjacob			device_printf(mpt->dev, "failed to enable port 0\n");
1181101704Smjacob			continue;
1182102199Smjacob		}
1183102199Smjacob
1184102199Smjacob		if (mpt->verbose > 1) {
1185101704Smjacob			device_printf(mpt->dev, "enabled port 0\n");
1186101704Smjacob		}
1187101704Smjacob
1188101704Smjacob		/* Everything worked */
1189101704Smjacob		break;
1190101704Smjacob	}
1191101704Smjacob
1192101704Smjacob	if (try >= MPT_MAX_TRYS) {
1193101704Smjacob		device_printf(mpt->dev, "failed to initialize IOC\n");
1194101704Smjacob		return (EIO);
1195101704Smjacob	}
1196101704Smjacob
1197101704Smjacob	if (mpt->verbose > 1) {
1198101704Smjacob		device_printf(mpt->dev, "enabling interrupts\n");
1199101704Smjacob	}
1200101704Smjacob
1201101704Smjacob	mpt_enable_ints(mpt);
1202101704Smjacob	return (0);
1203101704Smjacob}
1204