mpt.c revision 1.4 1 1.4 wiz /* $NetBSD: mpt.c,v 1.4 2003/11/02 11:07:45 wiz Exp $ */
2 1.1 thorpej
3 1.1 thorpej /*
4 1.1 thorpej * Copyright (c) 2000, 2001 by Greg Ansley
5 1.1 thorpej *
6 1.1 thorpej * Redistribution and use in source and binary forms, with or without
7 1.1 thorpej * modification, are permitted provided that the following conditions
8 1.1 thorpej * are met:
9 1.1 thorpej * 1. Redistributions of source code must retain the above copyright
10 1.1 thorpej * notice immediately at the beginning of the file, without modification,
11 1.1 thorpej * this list of conditions, and the following disclaimer.
12 1.1 thorpej * 2. The name of the author may not be used to endorse or promote products
13 1.1 thorpej * derived from this software without specific prior written permission.
14 1.1 thorpej *
15 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 1.1 thorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 1.1 thorpej * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 1.1 thorpej * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
19 1.1 thorpej * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 1.1 thorpej * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 1.1 thorpej * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 1.1 thorpej * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 1.1 thorpej * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 1.1 thorpej * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 1.1 thorpej * SUCH DAMAGE.
26 1.1 thorpej */
27 1.1 thorpej /*
28 1.1 thorpej * Additional Copyright (c) 2002 by Matthew Jacob under same license.
29 1.1 thorpej */
30 1.1 thorpej
31 1.1 thorpej /*
32 1.1 thorpej * mpt.c:
33 1.1 thorpej *
34 1.1 thorpej * Generic routines for LSI Fusion adapters.
35 1.1 thorpej *
36 1.1 thorpej * Adapted from the FreeBSD "mpt" driver by Jason R. Thorpe for
37 1.1 thorpej * Wasabi Systems, Inc.
38 1.1 thorpej */
39 1.3 lukem
40 1.3 lukem #include <sys/cdefs.h>
41 1.4 wiz __KERNEL_RCSID(0, "$NetBSD: mpt.c,v 1.4 2003/11/02 11:07:45 wiz Exp $");
42 1.1 thorpej
43 1.1 thorpej #include <dev/ic/mpt.h>
44 1.1 thorpej
45 1.1 thorpej #define MPT_MAX_TRYS 3
46 1.1 thorpej #define MPT_MAX_WAIT 300000
47 1.1 thorpej
48 1.1 thorpej static int maxwait_ack = 0;
49 1.1 thorpej static int maxwait_int = 0;
50 1.1 thorpej static int maxwait_state = 0;
51 1.1 thorpej
52 1.1 thorpej static __inline u_int32_t
53 1.1 thorpej mpt_rd_db(mpt_softc_t *mpt)
54 1.1 thorpej {
55 1.1 thorpej return mpt_read(mpt, MPT_OFFSET_DOORBELL);
56 1.1 thorpej }
57 1.1 thorpej
58 1.1 thorpej static __inline u_int32_t
59 1.1 thorpej mpt_rd_intr(mpt_softc_t *mpt)
60 1.1 thorpej {
61 1.1 thorpej return mpt_read(mpt, MPT_OFFSET_INTR_STATUS);
62 1.1 thorpej }
63 1.1 thorpej
64 1.1 thorpej /* Busy wait for a door bell to be read by IOC */
65 1.1 thorpej static int
66 1.1 thorpej mpt_wait_db_ack(mpt_softc_t *mpt)
67 1.1 thorpej {
68 1.1 thorpej int i;
69 1.1 thorpej for (i=0; i < MPT_MAX_WAIT; i++) {
70 1.1 thorpej if (!MPT_DB_IS_BUSY(mpt_rd_intr(mpt))) {
71 1.1 thorpej maxwait_ack = i > maxwait_ack ? i : maxwait_ack;
72 1.1 thorpej return MPT_OK;
73 1.1 thorpej }
74 1.1 thorpej
75 1.1 thorpej DELAY(100);
76 1.1 thorpej }
77 1.1 thorpej return MPT_FAIL;
78 1.1 thorpej }
79 1.1 thorpej
80 1.1 thorpej /* Busy wait for a door bell interrupt */
81 1.1 thorpej static int
82 1.1 thorpej mpt_wait_db_int(mpt_softc_t *mpt)
83 1.1 thorpej {
84 1.1 thorpej int i;
85 1.1 thorpej for (i=0; i < MPT_MAX_WAIT; i++) {
86 1.1 thorpej if (MPT_DB_INTR(mpt_rd_intr(mpt))) {
87 1.1 thorpej maxwait_int = i > maxwait_int ? i : maxwait_int;
88 1.1 thorpej return MPT_OK;
89 1.1 thorpej }
90 1.1 thorpej DELAY(100);
91 1.1 thorpej }
92 1.1 thorpej return MPT_FAIL;
93 1.1 thorpej }
94 1.1 thorpej
95 1.1 thorpej /* Wait for IOC to transition to a give state */
96 1.1 thorpej void
97 1.1 thorpej mpt_check_doorbell(mpt_softc_t *mpt)
98 1.1 thorpej {
99 1.1 thorpej u_int32_t db = mpt_rd_db(mpt);
100 1.1 thorpej if (MPT_STATE(db) != MPT_DB_STATE_RUNNING) {
101 1.1 thorpej mpt_prt(mpt, "Device not running");
102 1.1 thorpej mpt_print_db(db);
103 1.1 thorpej }
104 1.1 thorpej }
105 1.1 thorpej
106 1.1 thorpej /* Wait for IOC to transition to a give state */
107 1.1 thorpej static int
108 1.1 thorpej mpt_wait_state(mpt_softc_t *mpt, enum DB_STATE_BITS state)
109 1.1 thorpej {
110 1.1 thorpej int i;
111 1.1 thorpej
112 1.1 thorpej for (i = 0; i < MPT_MAX_WAIT; i++) {
113 1.1 thorpej u_int32_t db = mpt_rd_db(mpt);
114 1.1 thorpej if (MPT_STATE(db) == state) {
115 1.1 thorpej maxwait_state = i > maxwait_state ? i : maxwait_state;
116 1.1 thorpej return (MPT_OK);
117 1.1 thorpej }
118 1.1 thorpej DELAY(100);
119 1.1 thorpej }
120 1.1 thorpej return (MPT_FAIL);
121 1.1 thorpej }
122 1.1 thorpej
123 1.1 thorpej
124 1.1 thorpej /* Issue the reset COMMAND to the IOC */
125 1.1 thorpej int
126 1.1 thorpej mpt_soft_reset(mpt_softc_t *mpt)
127 1.1 thorpej {
128 1.1 thorpej if (mpt->verbose) {
129 1.1 thorpej mpt_prt(mpt, "soft reset");
130 1.1 thorpej }
131 1.1 thorpej
132 1.1 thorpej /* Have to use hard reset if we are not in Running state */
133 1.1 thorpej if (MPT_STATE(mpt_rd_db(mpt)) != MPT_DB_STATE_RUNNING) {
134 1.1 thorpej mpt_prt(mpt, "soft reset failed: device not running");
135 1.1 thorpej return MPT_FAIL;
136 1.1 thorpej }
137 1.1 thorpej
138 1.1 thorpej /* If door bell is in use we don't have a chance of getting
139 1.1 thorpej * a word in since the IOC probably crashed in message
140 1.1 thorpej * processing. So don't waste our time.
141 1.1 thorpej */
142 1.1 thorpej if (MPT_DB_IS_IN_USE(mpt_rd_db(mpt))) {
143 1.1 thorpej mpt_prt(mpt, "soft reset failed: doorbell wedged");
144 1.1 thorpej return MPT_FAIL;
145 1.1 thorpej }
146 1.1 thorpej
147 1.1 thorpej /* Send the reset request to the IOC */
148 1.1 thorpej mpt_write(mpt, MPT_OFFSET_DOORBELL,
149 1.1 thorpej MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET << MPI_DOORBELL_FUNCTION_SHIFT);
150 1.1 thorpej if (mpt_wait_db_ack(mpt) != MPT_OK) {
151 1.1 thorpej mpt_prt(mpt, "soft reset failed: ack timeout");
152 1.1 thorpej return MPT_FAIL;
153 1.1 thorpej }
154 1.1 thorpej
155 1.1 thorpej /* Wait for the IOC to reload and come out of reset state */
156 1.1 thorpej if (mpt_wait_state(mpt, MPT_DB_STATE_READY) != MPT_OK) {
157 1.1 thorpej mpt_prt(mpt, "soft reset failed: device did not start running");
158 1.1 thorpej return MPT_FAIL;
159 1.1 thorpej }
160 1.1 thorpej
161 1.1 thorpej return MPT_OK;
162 1.1 thorpej }
163 1.1 thorpej
164 1.1 thorpej /* This is a magic diagnostic reset that resets all the ARM
165 1.1 thorpej * processors in the chip.
166 1.1 thorpej */
167 1.1 thorpej void
168 1.1 thorpej mpt_hard_reset(mpt_softc_t *mpt)
169 1.1 thorpej {
170 1.1 thorpej /* This extra read comes for the Linux source
171 1.1 thorpej * released by LSI. It's function is undocumented!
172 1.1 thorpej */
173 1.1 thorpej if (mpt->verbose) {
174 1.1 thorpej mpt_prt(mpt, "hard reset");
175 1.1 thorpej }
176 1.1 thorpej mpt_read(mpt, MPT_OFFSET_FUBAR);
177 1.1 thorpej
178 1.1 thorpej /* Enable diagnostic registers */
179 1.1 thorpej mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_1);
180 1.1 thorpej mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_2);
181 1.1 thorpej mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_3);
182 1.1 thorpej mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_4);
183 1.1 thorpej mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_5);
184 1.1 thorpej
185 1.1 thorpej /* Diag. port is now active so we can now hit the reset bit */
186 1.1 thorpej mpt_write(mpt, MPT_OFFSET_DIAGNOSTIC, MPT_DIAG_RESET_IOC);
187 1.1 thorpej
188 1.1 thorpej DELAY(10000);
189 1.1 thorpej
190 1.1 thorpej /* Disable Diagnostic Register */
191 1.1 thorpej mpt_write(mpt, MPT_OFFSET_SEQUENCE, 0xFF);
192 1.1 thorpej
193 1.1 thorpej /* Restore the config register values */
194 1.1 thorpej /* Hard resets are known to screw up the BAR for diagnostic
195 1.1 thorpej memory accesses (Mem1). */
196 1.1 thorpej mpt_set_config_regs(mpt);
197 1.1 thorpej if (mpt->mpt2 != NULL) {
198 1.1 thorpej mpt_set_config_regs(mpt->mpt2);
199 1.1 thorpej }
200 1.1 thorpej
201 1.1 thorpej /* Note that if there is no valid firmware to run, the doorbell will
202 1.1 thorpej remain in the reset state (0x00000000) */
203 1.1 thorpej }
204 1.1 thorpej
205 1.1 thorpej /*
206 1.1 thorpej * Reset the IOC when needed. Try software command first then if needed
207 1.1 thorpej * poke at the magic diagnostic reset. Note that a hard reset resets
208 1.1 thorpej * *both* IOCs on dual function chips (FC929 && LSI1030) as well as
209 1.1 thorpej * fouls up the PCI configuration registers.
210 1.1 thorpej */
211 1.1 thorpej int
212 1.1 thorpej mpt_reset(mpt_softc_t *mpt)
213 1.1 thorpej {
214 1.1 thorpej int ret;
215 1.1 thorpej
216 1.1 thorpej /* Try a soft reset */
217 1.1 thorpej if ((ret = mpt_soft_reset(mpt)) != MPT_OK) {
218 1.1 thorpej /* Failed; do a hard reset */
219 1.1 thorpej mpt_hard_reset(mpt);
220 1.1 thorpej
221 1.1 thorpej /* Wait for the IOC to reload and come out of reset state */
222 1.1 thorpej ret = mpt_wait_state(mpt, MPT_DB_STATE_READY);
223 1.1 thorpej if (ret != MPT_OK) {
224 1.1 thorpej mpt_prt(mpt, "failed to reset device");
225 1.1 thorpej }
226 1.1 thorpej }
227 1.1 thorpej
228 1.1 thorpej return ret;
229 1.1 thorpej }
230 1.1 thorpej
231 1.1 thorpej /* Return a command buffer to the free queue */
232 1.1 thorpej void
233 1.1 thorpej mpt_free_request(mpt_softc_t *mpt, request_t *req)
234 1.1 thorpej {
235 1.1 thorpej if (req == NULL || req != &mpt->request_pool[req->index]) {
236 1.1 thorpej panic("mpt_free_request bad req ptr\n");
237 1.1 thorpej return;
238 1.1 thorpej }
239 1.1 thorpej req->sequence = 0;
240 1.1 thorpej req->xfer = NULL;
241 1.1 thorpej req->debug = REQ_FREE;
242 1.1 thorpej SLIST_INSERT_HEAD(&mpt->request_free_list, req, link);
243 1.1 thorpej }
244 1.1 thorpej
245 1.1 thorpej /* Get a command buffer from the free queue */
246 1.1 thorpej request_t *
247 1.1 thorpej mpt_get_request(mpt_softc_t *mpt)
248 1.1 thorpej {
249 1.1 thorpej request_t *req;
250 1.1 thorpej req = SLIST_FIRST(&mpt->request_free_list);
251 1.1 thorpej if (req != NULL) {
252 1.1 thorpej if (req != &mpt->request_pool[req->index]) {
253 1.1 thorpej panic("mpt_get_request: corrupted request free list\n");
254 1.1 thorpej }
255 1.1 thorpej if (req->xfer != NULL) {
256 1.1 thorpej panic("mpt_get_request: corrupted request free list (xfer)\n");
257 1.1 thorpej }
258 1.1 thorpej SLIST_REMOVE_HEAD(&mpt->request_free_list, link);
259 1.1 thorpej req->debug = REQ_IN_PROGRESS;
260 1.1 thorpej }
261 1.1 thorpej return req;
262 1.1 thorpej }
263 1.1 thorpej
264 1.1 thorpej /* Pass the command to the IOC */
265 1.1 thorpej void
266 1.1 thorpej mpt_send_cmd(mpt_softc_t *mpt, request_t *req)
267 1.1 thorpej {
268 1.1 thorpej req->sequence = mpt->sequence++;
269 1.1 thorpej if (mpt->verbose > 1) {
270 1.1 thorpej u_int32_t *pReq;
271 1.1 thorpej pReq = req->req_vbuf;
272 1.1 thorpej mpt_prt(mpt, "Send Request %d (0x%x):",
273 1.1 thorpej req->index, req->req_pbuf);
274 1.1 thorpej mpt_prt(mpt, "%08x %08x %08x %08x",
275 1.1 thorpej pReq[0], pReq[1], pReq[2], pReq[3]);
276 1.1 thorpej mpt_prt(mpt, "%08x %08x %08x %08x",
277 1.1 thorpej pReq[4], pReq[5], pReq[6], pReq[7]);
278 1.1 thorpej mpt_prt(mpt, "%08x %08x %08x %08x",
279 1.1 thorpej pReq[8], pReq[9], pReq[10], pReq[11]);
280 1.1 thorpej mpt_prt(mpt, "%08x %08x %08x %08x",
281 1.1 thorpej pReq[12], pReq[13], pReq[14], pReq[15]);
282 1.1 thorpej }
283 1.2 thorpej MPT_SYNC_REQ(mpt, req, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
284 1.1 thorpej req->debug = REQ_ON_CHIP;
285 1.1 thorpej mpt_write(mpt, MPT_OFFSET_REQUEST_Q, (u_int32_t) req->req_pbuf);
286 1.1 thorpej }
287 1.1 thorpej
288 1.1 thorpej /*
289 1.1 thorpej * Give the reply buffer back to the IOC after we have
290 1.1 thorpej * finished processing it.
291 1.1 thorpej */
292 1.1 thorpej void
293 1.1 thorpej mpt_free_reply(mpt_softc_t *mpt, u_int32_t ptr)
294 1.1 thorpej {
295 1.1 thorpej mpt_write(mpt, MPT_OFFSET_REPLY_Q, ptr);
296 1.1 thorpej }
297 1.1 thorpej
298 1.1 thorpej /* Get a reply from the IOC */
299 1.1 thorpej u_int32_t
300 1.1 thorpej mpt_pop_reply_queue(mpt_softc_t *mpt)
301 1.1 thorpej {
302 1.1 thorpej return mpt_read(mpt, MPT_OFFSET_REPLY_Q);
303 1.1 thorpej }
304 1.1 thorpej
305 1.1 thorpej /*
306 1.1 thorpej * Send a command to the IOC via the handshake register.
307 1.1 thorpej *
308 1.1 thorpej * Only done at initialization time and for certain unusual
309 1.1 thorpej * commands such as device/bus reset as specified by LSI.
310 1.1 thorpej */
311 1.1 thorpej int
312 1.1 thorpej mpt_send_handshake_cmd(mpt_softc_t *mpt, size_t len, void *cmd)
313 1.1 thorpej {
314 1.1 thorpej int i;
315 1.1 thorpej u_int32_t data, *data32;
316 1.1 thorpej
317 1.1 thorpej /* Check condition of the IOC */
318 1.1 thorpej data = mpt_rd_db(mpt);
319 1.1 thorpej if (((MPT_STATE(data) != MPT_DB_STATE_READY) &&
320 1.1 thorpej (MPT_STATE(data) != MPT_DB_STATE_RUNNING) &&
321 1.1 thorpej (MPT_STATE(data) != MPT_DB_STATE_FAULT)) ||
322 1.1 thorpej ( MPT_DB_IS_IN_USE(data) )) {
323 1.1 thorpej mpt_prt(mpt, "handshake aborted due to invalid doorbell state");
324 1.1 thorpej mpt_print_db(data);
325 1.1 thorpej return(EBUSY);
326 1.1 thorpej }
327 1.1 thorpej
328 1.1 thorpej /* We move things in 32 bit chunks */
329 1.1 thorpej len = (len + 3) >> 2;
330 1.1 thorpej data32 = cmd;
331 1.1 thorpej
332 1.4 wiz /* Clear any left over pending doorbell interrupts */
333 1.1 thorpej if (MPT_DB_INTR(mpt_rd_intr(mpt)))
334 1.1 thorpej mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
335 1.1 thorpej
336 1.1 thorpej /*
337 1.1 thorpej * Tell the handshake reg. we are going to send a command
338 1.1 thorpej * and how long it is going to be.
339 1.1 thorpej */
340 1.1 thorpej data = (MPI_FUNCTION_HANDSHAKE << MPI_DOORBELL_FUNCTION_SHIFT) |
341 1.1 thorpej (len << MPI_DOORBELL_ADD_DWORDS_SHIFT);
342 1.1 thorpej mpt_write(mpt, MPT_OFFSET_DOORBELL, data);
343 1.1 thorpej
344 1.1 thorpej /* Wait for the chip to notice */
345 1.1 thorpej if (mpt_wait_db_int(mpt) != MPT_OK) {
346 1.1 thorpej mpt_prt(mpt, "mpt_send_handshake_cmd timeout1");
347 1.1 thorpej return ETIMEDOUT;
348 1.1 thorpej }
349 1.1 thorpej
350 1.1 thorpej /* Clear the interrupt */
351 1.1 thorpej mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
352 1.1 thorpej
353 1.1 thorpej if (mpt_wait_db_ack(mpt) != MPT_OK) {
354 1.1 thorpej mpt_prt(mpt, "mpt_send_handshake_cmd timeout2");
355 1.1 thorpej return ETIMEDOUT;
356 1.1 thorpej }
357 1.1 thorpej
358 1.1 thorpej /* Send the command */
359 1.1 thorpej for (i = 0; i < len; i++) {
360 1.1 thorpej mpt_write(mpt, MPT_OFFSET_DOORBELL, *data32++);
361 1.1 thorpej if (mpt_wait_db_ack(mpt) != MPT_OK) {
362 1.1 thorpej mpt_prt(mpt,
363 1.1 thorpej "mpt_send_handshake_cmd timeout! index = %d", i);
364 1.1 thorpej return ETIMEDOUT;
365 1.1 thorpej }
366 1.1 thorpej }
367 1.1 thorpej return MPT_OK;
368 1.1 thorpej }
369 1.1 thorpej
370 1.1 thorpej /* Get the response from the handshake register */
371 1.1 thorpej int
372 1.1 thorpej mpt_recv_handshake_reply(mpt_softc_t *mpt, size_t reply_len, void *reply)
373 1.1 thorpej {
374 1.1 thorpej int left, reply_left;
375 1.1 thorpej u_int16_t *data16;
376 1.1 thorpej MSG_DEFAULT_REPLY *hdr;
377 1.1 thorpej
378 1.1 thorpej /* We move things out in 16 bit chunks */
379 1.1 thorpej reply_len >>= 1;
380 1.1 thorpej data16 = (u_int16_t *)reply;
381 1.1 thorpej
382 1.1 thorpej hdr = (MSG_DEFAULT_REPLY *)reply;
383 1.1 thorpej
384 1.1 thorpej /* Get first word */
385 1.1 thorpej if (mpt_wait_db_int(mpt) != MPT_OK) {
386 1.1 thorpej mpt_prt(mpt, "mpt_recv_handshake_cmd timeout1");
387 1.1 thorpej return ETIMEDOUT;
388 1.1 thorpej }
389 1.1 thorpej *data16++ = mpt_read(mpt, MPT_OFFSET_DOORBELL) & MPT_DB_DATA_MASK;
390 1.1 thorpej mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
391 1.1 thorpej
392 1.1 thorpej /* Get Second Word */
393 1.1 thorpej if (mpt_wait_db_int(mpt) != MPT_OK) {
394 1.1 thorpej mpt_prt(mpt, "mpt_recv_handshake_cmd timeout2");
395 1.1 thorpej return ETIMEDOUT;
396 1.1 thorpej }
397 1.1 thorpej *data16++ = mpt_read(mpt, MPT_OFFSET_DOORBELL) & MPT_DB_DATA_MASK;
398 1.1 thorpej mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
399 1.1 thorpej
400 1.1 thorpej /* With the second word, we can now look at the length */
401 1.1 thorpej if (mpt->verbose > 1 && ((reply_len >> 1) != hdr->MsgLength)) {
402 1.1 thorpej mpt_prt(mpt, "reply length does not match message length: "
403 1.1 thorpej "got 0x%02x, expected 0x%02x",
404 1.1 thorpej hdr->MsgLength << 2, reply_len << 1);
405 1.1 thorpej }
406 1.1 thorpej
407 1.1 thorpej /* Get rest of the reply; but don't overflow the provided buffer */
408 1.1 thorpej left = (hdr->MsgLength << 1) - 2;
409 1.1 thorpej reply_left = reply_len - 2;
410 1.1 thorpej while (left--) {
411 1.1 thorpej u_int16_t datum;
412 1.1 thorpej
413 1.1 thorpej if (mpt_wait_db_int(mpt) != MPT_OK) {
414 1.1 thorpej mpt_prt(mpt, "mpt_recv_handshake_cmd timeout3");
415 1.1 thorpej return ETIMEDOUT;
416 1.1 thorpej }
417 1.1 thorpej datum = mpt_read(mpt, MPT_OFFSET_DOORBELL);
418 1.1 thorpej
419 1.1 thorpej if (reply_left-- > 0)
420 1.1 thorpej *data16++ = datum & MPT_DB_DATA_MASK;
421 1.1 thorpej
422 1.1 thorpej mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
423 1.1 thorpej }
424 1.1 thorpej
425 1.1 thorpej /* One more wait & clear at the end */
426 1.1 thorpej if (mpt_wait_db_int(mpt) != MPT_OK) {
427 1.1 thorpej mpt_prt(mpt, "mpt_recv_handshake_cmd timeout4");
428 1.1 thorpej return ETIMEDOUT;
429 1.1 thorpej }
430 1.1 thorpej mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
431 1.1 thorpej
432 1.1 thorpej if ((hdr->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
433 1.1 thorpej if (mpt->verbose > 1)
434 1.1 thorpej mpt_print_reply(hdr);
435 1.1 thorpej return (MPT_FAIL | hdr->IOCStatus);
436 1.1 thorpej }
437 1.1 thorpej
438 1.1 thorpej return (0);
439 1.1 thorpej }
440 1.1 thorpej
441 1.1 thorpej static int
442 1.1 thorpej mpt_get_iocfacts(mpt_softc_t *mpt, MSG_IOC_FACTS_REPLY *freplp)
443 1.1 thorpej {
444 1.1 thorpej MSG_IOC_FACTS f_req;
445 1.1 thorpej int error;
446 1.1 thorpej
447 1.1 thorpej bzero(&f_req, sizeof f_req);
448 1.1 thorpej f_req.Function = MPI_FUNCTION_IOC_FACTS;
449 1.1 thorpej f_req.MsgContext = 0x12071942;
450 1.1 thorpej error = mpt_send_handshake_cmd(mpt, sizeof f_req, &f_req);
451 1.1 thorpej if (error)
452 1.1 thorpej return(error);
453 1.1 thorpej error = mpt_recv_handshake_reply(mpt, sizeof (*freplp), freplp);
454 1.1 thorpej return (error);
455 1.1 thorpej }
456 1.1 thorpej
457 1.1 thorpej static int
458 1.1 thorpej mpt_get_portfacts(mpt_softc_t *mpt, MSG_PORT_FACTS_REPLY *freplp)
459 1.1 thorpej {
460 1.1 thorpej MSG_PORT_FACTS f_req;
461 1.1 thorpej int error;
462 1.1 thorpej
463 1.1 thorpej /* XXX: Only getting PORT FACTS for Port 0 */
464 1.1 thorpej bzero(&f_req, sizeof f_req);
465 1.1 thorpej f_req.Function = MPI_FUNCTION_PORT_FACTS;
466 1.1 thorpej f_req.MsgContext = 0x12071943;
467 1.1 thorpej error = mpt_send_handshake_cmd(mpt, sizeof f_req, &f_req);
468 1.1 thorpej if (error)
469 1.1 thorpej return(error);
470 1.1 thorpej error = mpt_recv_handshake_reply(mpt, sizeof (*freplp), freplp);
471 1.1 thorpej return (error);
472 1.1 thorpej }
473 1.1 thorpej
474 1.1 thorpej /*
475 1.1 thorpej * Send the initialization request. This is where we specify how many
476 1.1 thorpej * SCSI busses and how many devices per bus we wish to emulate.
477 1.1 thorpej * This is also the command that specifies the max size of the reply
478 1.1 thorpej * frames from the IOC that we will be allocating.
479 1.1 thorpej */
480 1.1 thorpej static int
481 1.1 thorpej mpt_send_ioc_init(mpt_softc_t *mpt, u_int32_t who)
482 1.1 thorpej {
483 1.1 thorpej int error = 0;
484 1.1 thorpej MSG_IOC_INIT init;
485 1.1 thorpej MSG_IOC_INIT_REPLY reply;
486 1.1 thorpej
487 1.1 thorpej bzero(&init, sizeof init);
488 1.1 thorpej init.WhoInit = who;
489 1.1 thorpej init.Function = MPI_FUNCTION_IOC_INIT;
490 1.1 thorpej if (mpt->is_fc) {
491 1.1 thorpej init.MaxDevices = 255;
492 1.1 thorpej } else {
493 1.1 thorpej init.MaxDevices = 16;
494 1.1 thorpej }
495 1.1 thorpej init.MaxBuses = 1;
496 1.1 thorpej init.ReplyFrameSize = MPT_REPLY_SIZE;
497 1.1 thorpej init.MsgContext = 0x12071941;
498 1.1 thorpej
499 1.1 thorpej if ((error = mpt_send_handshake_cmd(mpt, sizeof init, &init)) != 0) {
500 1.1 thorpej return(error);
501 1.1 thorpej }
502 1.1 thorpej
503 1.1 thorpej error = mpt_recv_handshake_reply(mpt, sizeof reply, &reply);
504 1.1 thorpej return (error);
505 1.1 thorpej }
506 1.1 thorpej
507 1.1 thorpej
508 1.1 thorpej /*
509 1.1 thorpej * Utiltity routine to read configuration headers and pages
510 1.1 thorpej */
511 1.1 thorpej
512 1.1 thorpej static int
513 1.1 thorpej mpt_read_cfg_header(mpt_softc_t *, int, int, int, fCONFIG_PAGE_HEADER *);
514 1.1 thorpej
515 1.1 thorpej static int
516 1.1 thorpej mpt_read_cfg_header(mpt_softc_t *mpt, int PageType, int PageNumber,
517 1.1 thorpej int PageAddress, fCONFIG_PAGE_HEADER *rslt)
518 1.1 thorpej {
519 1.1 thorpej int count;
520 1.1 thorpej request_t *req;
521 1.1 thorpej MSG_CONFIG *cfgp;
522 1.1 thorpej MSG_CONFIG_REPLY *reply;
523 1.1 thorpej
524 1.1 thorpej req = mpt_get_request(mpt);
525 1.1 thorpej
526 1.1 thorpej cfgp = req->req_vbuf;
527 1.1 thorpej bzero(cfgp, sizeof *cfgp);
528 1.1 thorpej
529 1.1 thorpej cfgp->Action = MPI_CONFIG_ACTION_PAGE_HEADER;
530 1.1 thorpej cfgp->Function = MPI_FUNCTION_CONFIG;
531 1.1 thorpej cfgp->Header.PageNumber = (U8) PageNumber;
532 1.1 thorpej cfgp->Header.PageType = (U8) PageType;
533 1.1 thorpej cfgp->PageAddress = PageAddress;
534 1.1 thorpej MPI_pSGE_SET_FLAGS(((SGE_SIMPLE32 *) &cfgp->PageBufferSGE),
535 1.1 thorpej (MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
536 1.1 thorpej MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_LIST));
537 1.1 thorpej cfgp->MsgContext = req->index | 0x80000000;
538 1.1 thorpej
539 1.1 thorpej mpt_check_doorbell(mpt);
540 1.1 thorpej mpt_send_cmd(mpt, req);
541 1.1 thorpej count = 0;
542 1.1 thorpej do {
543 1.1 thorpej DELAY(500);
544 1.1 thorpej mpt_intr(mpt);
545 1.1 thorpej if (++count == 1000) {
546 1.1 thorpej mpt_prt(mpt, "read_cfg_header timed out");
547 1.1 thorpej return (-1);
548 1.1 thorpej }
549 1.1 thorpej } while (req->debug == REQ_ON_CHIP);
550 1.1 thorpej
551 1.1 thorpej reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence);
552 1.1 thorpej if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
553 1.1 thorpej mpt_prt(mpt, "mpt_read_cfg_header: Config Info Status %x",
554 1.1 thorpej reply->IOCStatus);
555 1.1 thorpej mpt_free_reply(mpt, (req->sequence << 1));
556 1.1 thorpej return (-1);
557 1.1 thorpej }
558 1.1 thorpej bcopy(&reply->Header, rslt, sizeof (fCONFIG_PAGE_HEADER));
559 1.1 thorpej mpt_free_reply(mpt, (req->sequence << 1));
560 1.1 thorpej mpt_free_request(mpt, req);
561 1.1 thorpej return (0);
562 1.1 thorpej }
563 1.1 thorpej
564 1.1 thorpej #define CFG_DATA_OFF 128
565 1.1 thorpej
566 1.1 thorpej int
567 1.1 thorpej mpt_read_cfg_page(mpt_softc_t *mpt, int PageAddress, fCONFIG_PAGE_HEADER *hdr)
568 1.1 thorpej {
569 1.1 thorpej int count;
570 1.1 thorpej request_t *req;
571 1.1 thorpej SGE_SIMPLE32 *se;
572 1.1 thorpej MSG_CONFIG *cfgp;
573 1.1 thorpej size_t amt;
574 1.1 thorpej MSG_CONFIG_REPLY *reply;
575 1.1 thorpej
576 1.1 thorpej req = mpt_get_request(mpt);
577 1.1 thorpej
578 1.1 thorpej cfgp = req->req_vbuf;
579 1.1 thorpej bzero(cfgp, MPT_REQUEST_AREA);
580 1.1 thorpej cfgp->Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
581 1.1 thorpej cfgp->Function = MPI_FUNCTION_CONFIG;
582 1.1 thorpej cfgp->Header = *hdr;
583 1.1 thorpej amt = (cfgp->Header.PageLength * sizeof (u_int32_t));
584 1.1 thorpej cfgp->Header.PageType &= MPI_CONFIG_PAGETYPE_MASK;
585 1.1 thorpej cfgp->PageAddress = PageAddress;
586 1.1 thorpej se = (SGE_SIMPLE32 *) &cfgp->PageBufferSGE;
587 1.1 thorpej se->Address = req->req_pbuf + CFG_DATA_OFF;
588 1.1 thorpej MPI_pSGE_SET_LENGTH(se, amt);
589 1.1 thorpej MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
590 1.1 thorpej MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
591 1.1 thorpej MPI_SGE_FLAGS_END_OF_LIST));
592 1.1 thorpej
593 1.1 thorpej cfgp->MsgContext = req->index | 0x80000000;
594 1.1 thorpej
595 1.1 thorpej mpt_check_doorbell(mpt);
596 1.1 thorpej mpt_send_cmd(mpt, req);
597 1.1 thorpej count = 0;
598 1.1 thorpej do {
599 1.1 thorpej DELAY(500);
600 1.1 thorpej mpt_intr(mpt);
601 1.1 thorpej if (++count == 1000) {
602 1.1 thorpej mpt_prt(mpt, "read_cfg_page timed out");
603 1.1 thorpej return (-1);
604 1.1 thorpej }
605 1.1 thorpej } while (req->debug == REQ_ON_CHIP);
606 1.1 thorpej
607 1.1 thorpej reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence);
608 1.1 thorpej if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
609 1.1 thorpej mpt_prt(mpt, "mpt_read_cfg_page: Config Info Status %x",
610 1.1 thorpej reply->IOCStatus);
611 1.1 thorpej mpt_free_reply(mpt, (req->sequence << 1));
612 1.1 thorpej return (-1);
613 1.1 thorpej }
614 1.1 thorpej mpt_free_reply(mpt, (req->sequence << 1));
615 1.1 thorpej #if 0 /* XXXJRT */
616 1.1 thorpej bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap,
617 1.1 thorpej BUS_DMASYNC_POSTREAD);
618 1.1 thorpej #endif
619 1.1 thorpej if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
620 1.1 thorpej cfgp->Header.PageNumber == 0) {
621 1.1 thorpej amt = sizeof (fCONFIG_PAGE_SCSI_PORT_0);
622 1.1 thorpej } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
623 1.1 thorpej cfgp->Header.PageNumber == 1) {
624 1.1 thorpej amt = sizeof (fCONFIG_PAGE_SCSI_PORT_1);
625 1.1 thorpej } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
626 1.1 thorpej cfgp->Header.PageNumber == 2) {
627 1.1 thorpej amt = sizeof (fCONFIG_PAGE_SCSI_PORT_2);
628 1.1 thorpej } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE &&
629 1.1 thorpej cfgp->Header.PageNumber == 0) {
630 1.1 thorpej amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_0);
631 1.1 thorpej } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE &&
632 1.1 thorpej cfgp->Header.PageNumber == 1) {
633 1.1 thorpej amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_1);
634 1.1 thorpej }
635 1.1 thorpej bcopy(((caddr_t)req->req_vbuf)+CFG_DATA_OFF, hdr, amt);
636 1.1 thorpej mpt_free_request(mpt, req);
637 1.1 thorpej return (0);
638 1.1 thorpej }
639 1.1 thorpej
640 1.1 thorpej int
641 1.1 thorpej mpt_write_cfg_page(mpt_softc_t *mpt, int PageAddress, fCONFIG_PAGE_HEADER *hdr)
642 1.1 thorpej {
643 1.1 thorpej int count, hdr_attr;
644 1.1 thorpej request_t *req;
645 1.1 thorpej SGE_SIMPLE32 *se;
646 1.1 thorpej MSG_CONFIG *cfgp;
647 1.1 thorpej size_t amt;
648 1.1 thorpej MSG_CONFIG_REPLY *reply;
649 1.1 thorpej
650 1.1 thorpej req = mpt_get_request(mpt);
651 1.1 thorpej
652 1.1 thorpej cfgp = req->req_vbuf;
653 1.1 thorpej bzero(cfgp, sizeof *cfgp);
654 1.1 thorpej
655 1.1 thorpej hdr_attr = hdr->PageType & MPI_CONFIG_PAGEATTR_MASK;
656 1.1 thorpej if (hdr_attr != MPI_CONFIG_PAGEATTR_CHANGEABLE &&
657 1.1 thorpej hdr_attr != MPI_CONFIG_PAGEATTR_PERSISTENT) {
658 1.1 thorpej mpt_prt(mpt, "page type 0x%x not changeable",
659 1.1 thorpej hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
660 1.1 thorpej return (-1);
661 1.1 thorpej }
662 1.1 thorpej hdr->PageType &= MPI_CONFIG_PAGETYPE_MASK;
663 1.1 thorpej
664 1.1 thorpej cfgp->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
665 1.1 thorpej cfgp->Function = MPI_FUNCTION_CONFIG;
666 1.1 thorpej cfgp->Header = *hdr;
667 1.1 thorpej amt = (cfgp->Header.PageLength * sizeof (u_int32_t));
668 1.1 thorpej cfgp->PageAddress = PageAddress;
669 1.1 thorpej
670 1.1 thorpej se = (SGE_SIMPLE32 *) &cfgp->PageBufferSGE;
671 1.1 thorpej se->Address = req->req_pbuf + CFG_DATA_OFF;
672 1.1 thorpej MPI_pSGE_SET_LENGTH(se, amt);
673 1.1 thorpej MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
674 1.1 thorpej MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
675 1.1 thorpej MPI_SGE_FLAGS_END_OF_LIST | MPI_SGE_FLAGS_HOST_TO_IOC));
676 1.1 thorpej
677 1.1 thorpej cfgp->MsgContext = req->index | 0x80000000;
678 1.1 thorpej
679 1.1 thorpej if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
680 1.1 thorpej cfgp->Header.PageNumber == 0) {
681 1.1 thorpej amt = sizeof (fCONFIG_PAGE_SCSI_PORT_0);
682 1.1 thorpej } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
683 1.1 thorpej cfgp->Header.PageNumber == 1) {
684 1.1 thorpej amt = sizeof (fCONFIG_PAGE_SCSI_PORT_1);
685 1.1 thorpej } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
686 1.1 thorpej cfgp->Header.PageNumber == 2) {
687 1.1 thorpej amt = sizeof (fCONFIG_PAGE_SCSI_PORT_2);
688 1.1 thorpej } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE &&
689 1.1 thorpej cfgp->Header.PageNumber == 0) {
690 1.1 thorpej amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_0);
691 1.1 thorpej } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE &&
692 1.1 thorpej cfgp->Header.PageNumber == 1) {
693 1.1 thorpej amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_1);
694 1.1 thorpej }
695 1.1 thorpej bcopy(hdr, ((caddr_t)req->req_vbuf)+CFG_DATA_OFF, amt);
696 1.1 thorpej /* Restore stripped out attributes */
697 1.1 thorpej hdr->PageType |= hdr_attr;
698 1.1 thorpej
699 1.1 thorpej mpt_check_doorbell(mpt);
700 1.1 thorpej mpt_send_cmd(mpt, req);
701 1.1 thorpej count = 0;
702 1.1 thorpej do {
703 1.1 thorpej DELAY(500);
704 1.1 thorpej mpt_intr(mpt);
705 1.1 thorpej if (++count == 1000) {
706 1.1 thorpej hdr->PageType |= hdr_attr;
707 1.1 thorpej mpt_prt(mpt, "mpt_write_cfg_page timed out");
708 1.1 thorpej return (-1);
709 1.1 thorpej }
710 1.1 thorpej } while (req->debug == REQ_ON_CHIP);
711 1.1 thorpej
712 1.1 thorpej reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence);
713 1.1 thorpej if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
714 1.1 thorpej mpt_prt(mpt, "mpt_write_cfg_page: Config Info Status %x",
715 1.1 thorpej reply->IOCStatus);
716 1.1 thorpej mpt_free_reply(mpt, (req->sequence << 1));
717 1.1 thorpej return (-1);
718 1.1 thorpej }
719 1.1 thorpej mpt_free_reply(mpt, (req->sequence << 1));
720 1.1 thorpej
721 1.1 thorpej mpt_free_request(mpt, req);
722 1.1 thorpej return (0);
723 1.1 thorpej }
724 1.1 thorpej
725 1.1 thorpej /*
726 1.1 thorpej * Read SCSI configuration information
727 1.1 thorpej */
728 1.1 thorpej static int
729 1.1 thorpej mpt_read_config_info_spi(mpt_softc_t *mpt)
730 1.1 thorpej {
731 1.1 thorpej int rv, i;
732 1.1 thorpej
733 1.1 thorpej rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 0,
734 1.1 thorpej 0, &mpt->mpt_port_page0.Header);
735 1.1 thorpej if (rv) {
736 1.1 thorpej return (-1);
737 1.1 thorpej }
738 1.1 thorpej if (mpt->verbose > 1) {
739 1.1 thorpej mpt_prt(mpt, "SPI Port Page 0 Header: %x %x %x %x",
740 1.1 thorpej mpt->mpt_port_page0.Header.PageVersion,
741 1.1 thorpej mpt->mpt_port_page0.Header.PageLength,
742 1.1 thorpej mpt->mpt_port_page0.Header.PageNumber,
743 1.1 thorpej mpt->mpt_port_page0.Header.PageType);
744 1.1 thorpej }
745 1.1 thorpej
746 1.1 thorpej rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 1,
747 1.1 thorpej 0, &mpt->mpt_port_page1.Header);
748 1.1 thorpej if (rv) {
749 1.1 thorpej return (-1);
750 1.1 thorpej }
751 1.1 thorpej if (mpt->verbose > 1) {
752 1.1 thorpej mpt_prt(mpt, "SPI Port Page 1 Header: %x %x %x %x",
753 1.1 thorpej mpt->mpt_port_page1.Header.PageVersion,
754 1.1 thorpej mpt->mpt_port_page1.Header.PageLength,
755 1.1 thorpej mpt->mpt_port_page1.Header.PageNumber,
756 1.1 thorpej mpt->mpt_port_page1.Header.PageType);
757 1.1 thorpej }
758 1.1 thorpej
759 1.1 thorpej rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 2,
760 1.1 thorpej 0, &mpt->mpt_port_page2.Header);
761 1.1 thorpej if (rv) {
762 1.1 thorpej return (-1);
763 1.1 thorpej }
764 1.1 thorpej
765 1.1 thorpej if (mpt->verbose > 1) {
766 1.1 thorpej mpt_prt(mpt, "SPI Port Page 2 Header: %x %x %x %x",
767 1.1 thorpej mpt->mpt_port_page1.Header.PageVersion,
768 1.1 thorpej mpt->mpt_port_page1.Header.PageLength,
769 1.1 thorpej mpt->mpt_port_page1.Header.PageNumber,
770 1.1 thorpej mpt->mpt_port_page1.Header.PageType);
771 1.1 thorpej }
772 1.1 thorpej
773 1.1 thorpej for (i = 0; i < 16; i++) {
774 1.1 thorpej rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE,
775 1.1 thorpej 0, i, &mpt->mpt_dev_page0[i].Header);
776 1.1 thorpej if (rv) {
777 1.1 thorpej return (-1);
778 1.1 thorpej }
779 1.1 thorpej if (mpt->verbose > 1) {
780 1.1 thorpej mpt_prt(mpt,
781 1.1 thorpej "SPI Target %d Device Page 0 Header: %x %x %x %x",
782 1.1 thorpej i, mpt->mpt_dev_page0[i].Header.PageVersion,
783 1.1 thorpej mpt->mpt_dev_page0[i].Header.PageLength,
784 1.1 thorpej mpt->mpt_dev_page0[i].Header.PageNumber,
785 1.1 thorpej mpt->mpt_dev_page0[i].Header.PageType);
786 1.1 thorpej }
787 1.1 thorpej
788 1.1 thorpej rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE,
789 1.1 thorpej 1, i, &mpt->mpt_dev_page1[i].Header);
790 1.1 thorpej if (rv) {
791 1.1 thorpej return (-1);
792 1.1 thorpej }
793 1.1 thorpej if (mpt->verbose > 1) {
794 1.1 thorpej mpt_prt(mpt,
795 1.1 thorpej "SPI Target %d Device Page 1 Header: %x %x %x %x",
796 1.1 thorpej i, mpt->mpt_dev_page1[i].Header.PageVersion,
797 1.1 thorpej mpt->mpt_dev_page1[i].Header.PageLength,
798 1.1 thorpej mpt->mpt_dev_page1[i].Header.PageNumber,
799 1.1 thorpej mpt->mpt_dev_page1[i].Header.PageType);
800 1.1 thorpej }
801 1.1 thorpej }
802 1.1 thorpej
803 1.1 thorpej /*
804 1.1 thorpej * At this point, we don't *have* to fail. As long as we have
805 1.1 thorpej * valid config header information, we can (barely) lurch
806 1.1 thorpej * along.
807 1.1 thorpej */
808 1.1 thorpej
809 1.1 thorpej rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page0.Header);
810 1.1 thorpej if (rv) {
811 1.1 thorpej mpt_prt(mpt, "failed to read SPI Port Page 0");
812 1.1 thorpej } else if (mpt->verbose > 1) {
813 1.1 thorpej mpt_prt(mpt,
814 1.1 thorpej "SPI Port Page 0: Capabilities %x PhysicalInterface %x",
815 1.1 thorpej mpt->mpt_port_page0.Capabilities,
816 1.1 thorpej mpt->mpt_port_page0.PhysicalInterface);
817 1.1 thorpej }
818 1.1 thorpej
819 1.1 thorpej rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page1.Header);
820 1.1 thorpej if (rv) {
821 1.1 thorpej mpt_prt(mpt, "failed to read SPI Port Page 1");
822 1.1 thorpej } else if (mpt->verbose > 1) {
823 1.1 thorpej mpt_prt(mpt,
824 1.1 thorpej "SPI Port Page 1: Configuration %x OnBusTimerValue %x",
825 1.1 thorpej mpt->mpt_port_page1.Configuration,
826 1.1 thorpej mpt->mpt_port_page1.OnBusTimerValue);
827 1.1 thorpej }
828 1.1 thorpej
829 1.1 thorpej rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page2.Header);
830 1.1 thorpej if (rv) {
831 1.1 thorpej mpt_prt(mpt, "failed to read SPI Port Page 2");
832 1.1 thorpej } else if (mpt->verbose > 1) {
833 1.1 thorpej mpt_prt(mpt,
834 1.1 thorpej "SPI Port Page 2: Flags %x Settings %x",
835 1.1 thorpej mpt->mpt_port_page2.PortFlags,
836 1.1 thorpej mpt->mpt_port_page2.PortSettings);
837 1.1 thorpej for (i = 0; i < 16; i++) {
838 1.1 thorpej mpt_prt(mpt,
839 1.1 thorpej "SPI Port Page 2 Tgt %d: timo %x SF %x Flags %x",
840 1.1 thorpej i, mpt->mpt_port_page2.DeviceSettings[i].Timeout,
841 1.1 thorpej mpt->mpt_port_page2.DeviceSettings[i].SyncFactor,
842 1.1 thorpej mpt->mpt_port_page2.DeviceSettings[i].DeviceFlags);
843 1.1 thorpej }
844 1.1 thorpej }
845 1.1 thorpej
846 1.1 thorpej for (i = 0; i < 16; i++) {
847 1.1 thorpej rv = mpt_read_cfg_page(mpt, i, &mpt->mpt_dev_page0[i].Header);
848 1.1 thorpej if (rv) {
849 1.1 thorpej mpt_prt(mpt, "cannot read SPI Tgt %d Device Page 0", i);
850 1.1 thorpej continue;
851 1.1 thorpej }
852 1.1 thorpej if (mpt->verbose > 1) {
853 1.1 thorpej mpt_prt(mpt,
854 1.1 thorpej "SPI Tgt %d Page 0: NParms %x Information %x",
855 1.1 thorpej i, mpt->mpt_dev_page0[i].NegotiatedParameters,
856 1.1 thorpej mpt->mpt_dev_page0[i].Information);
857 1.1 thorpej }
858 1.1 thorpej rv = mpt_read_cfg_page(mpt, i, &mpt->mpt_dev_page1[i].Header);
859 1.1 thorpej if (rv) {
860 1.1 thorpej mpt_prt(mpt, "cannot read SPI Tgt %d Device Page 1", i);
861 1.1 thorpej continue;
862 1.1 thorpej }
863 1.1 thorpej if (mpt->verbose > 1) {
864 1.1 thorpej mpt_prt(mpt,
865 1.1 thorpej "SPI Tgt %d Page 1: RParms %x Configuration %x",
866 1.1 thorpej i, mpt->mpt_dev_page1[i].RequestedParameters,
867 1.1 thorpej mpt->mpt_dev_page1[i].Configuration);
868 1.1 thorpej }
869 1.1 thorpej }
870 1.1 thorpej return (0);
871 1.1 thorpej }
872 1.1 thorpej
873 1.1 thorpej /*
874 1.1 thorpej * Validate SPI configuration information.
875 1.1 thorpej *
876 1.1 thorpej * In particular, validate SPI Port Page 1.
877 1.1 thorpej */
878 1.1 thorpej static int
879 1.1 thorpej mpt_set_initial_config_spi(mpt_softc_t *mpt)
880 1.1 thorpej {
881 1.1 thorpej int i, pp1val = ((1 << mpt->mpt_ini_id) << 16) | mpt->mpt_ini_id;
882 1.1 thorpej
883 1.1 thorpej mpt->mpt_disc_enable = 0xff;
884 1.1 thorpej mpt->mpt_tag_enable = 0;
885 1.1 thorpej
886 1.1 thorpej if (mpt->mpt_port_page1.Configuration != pp1val) {
887 1.1 thorpej fCONFIG_PAGE_SCSI_PORT_1 tmp;
888 1.1 thorpej mpt_prt(mpt,
889 1.1 thorpej "SPI Port Page 1 Config value bad (%x)- should be %x",
890 1.1 thorpej mpt->mpt_port_page1.Configuration, pp1val);
891 1.1 thorpej tmp = mpt->mpt_port_page1;
892 1.1 thorpej tmp.Configuration = pp1val;
893 1.1 thorpej if (mpt_write_cfg_page(mpt, 0, &tmp.Header)) {
894 1.1 thorpej return (-1);
895 1.1 thorpej }
896 1.1 thorpej if (mpt_read_cfg_page(mpt, 0, &tmp.Header)) {
897 1.1 thorpej return (-1);
898 1.1 thorpej }
899 1.1 thorpej if (tmp.Configuration != pp1val) {
900 1.1 thorpej mpt_prt(mpt,
901 1.1 thorpej "failed to reset SPI Port Page 1 Config value");
902 1.1 thorpej return (-1);
903 1.1 thorpej }
904 1.1 thorpej mpt->mpt_port_page1 = tmp;
905 1.1 thorpej }
906 1.1 thorpej
907 1.1 thorpej for (i = 0; i < 16; i++) {
908 1.1 thorpej fCONFIG_PAGE_SCSI_DEVICE_1 tmp;
909 1.1 thorpej tmp = mpt->mpt_dev_page1[i];
910 1.1 thorpej tmp.RequestedParameters = 0;
911 1.1 thorpej tmp.Configuration = 0;
912 1.1 thorpej if (mpt->verbose > 1) {
913 1.1 thorpej mpt_prt(mpt,
914 1.1 thorpej "Set Tgt %d SPI DevicePage 1 values to %x 0 %x",
915 1.1 thorpej i, tmp.RequestedParameters, tmp.Configuration);
916 1.1 thorpej }
917 1.1 thorpej if (mpt_write_cfg_page(mpt, i, &tmp.Header)) {
918 1.1 thorpej return (-1);
919 1.1 thorpej }
920 1.1 thorpej if (mpt_read_cfg_page(mpt, i, &tmp.Header)) {
921 1.1 thorpej return (-1);
922 1.1 thorpej }
923 1.1 thorpej mpt->mpt_dev_page1[i] = tmp;
924 1.1 thorpej if (mpt->verbose > 1) {
925 1.1 thorpej mpt_prt(mpt,
926 1.1 thorpej "SPI Tgt %d Page 1: RParm %x Configuration %x", i,
927 1.1 thorpej mpt->mpt_dev_page1[i].RequestedParameters,
928 1.1 thorpej mpt->mpt_dev_page1[i].Configuration);
929 1.1 thorpej }
930 1.1 thorpej }
931 1.1 thorpej return (0);
932 1.1 thorpej }
933 1.1 thorpej
934 1.1 thorpej /*
935 1.1 thorpej * Enable IOC port
936 1.1 thorpej */
937 1.1 thorpej static int
938 1.1 thorpej mpt_send_port_enable(mpt_softc_t *mpt, int port)
939 1.1 thorpej {
940 1.1 thorpej int count;
941 1.1 thorpej request_t *req;
942 1.1 thorpej MSG_PORT_ENABLE *enable_req;
943 1.1 thorpej
944 1.1 thorpej req = mpt_get_request(mpt);
945 1.1 thorpej
946 1.1 thorpej enable_req = req->req_vbuf;
947 1.1 thorpej bzero(enable_req, sizeof *enable_req);
948 1.1 thorpej
949 1.1 thorpej enable_req->Function = MPI_FUNCTION_PORT_ENABLE;
950 1.1 thorpej enable_req->MsgContext = req->index | 0x80000000;
951 1.1 thorpej enable_req->PortNumber = port;
952 1.1 thorpej
953 1.1 thorpej mpt_check_doorbell(mpt);
954 1.1 thorpej if (mpt->verbose > 1) {
955 1.1 thorpej mpt_prt(mpt, "enabling port %d", port);
956 1.1 thorpej }
957 1.1 thorpej mpt_send_cmd(mpt, req);
958 1.1 thorpej
959 1.1 thorpej count = 0;
960 1.1 thorpej do {
961 1.1 thorpej DELAY(500);
962 1.1 thorpej mpt_intr(mpt);
963 1.1 thorpej if (++count == 100000) {
964 1.1 thorpej mpt_prt(mpt, "port enable timed out");
965 1.1 thorpej return (-1);
966 1.1 thorpej }
967 1.1 thorpej } while (req->debug == REQ_ON_CHIP);
968 1.1 thorpej mpt_free_request(mpt, req);
969 1.1 thorpej return (0);
970 1.1 thorpej }
971 1.1 thorpej
972 1.1 thorpej /*
973 1.1 thorpej * Enable/Disable asynchronous event reporting.
974 1.1 thorpej *
975 1.1 thorpej * NB: this is the first command we send via shared memory
976 1.1 thorpej * instead of the handshake register.
977 1.1 thorpej */
978 1.1 thorpej static int
979 1.1 thorpej mpt_send_event_request(mpt_softc_t *mpt, int onoff)
980 1.1 thorpej {
981 1.1 thorpej request_t *req;
982 1.1 thorpej MSG_EVENT_NOTIFY *enable_req;
983 1.1 thorpej
984 1.1 thorpej req = mpt_get_request(mpt);
985 1.1 thorpej
986 1.1 thorpej enable_req = req->req_vbuf;
987 1.1 thorpej bzero(enable_req, sizeof *enable_req);
988 1.1 thorpej
989 1.1 thorpej enable_req->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
990 1.1 thorpej enable_req->MsgContext = req->index | 0x80000000;
991 1.1 thorpej enable_req->Switch = onoff;
992 1.1 thorpej
993 1.1 thorpej mpt_check_doorbell(mpt);
994 1.1 thorpej if (mpt->verbose > 1) {
995 1.1 thorpej mpt_prt(mpt, "%sabling async events", onoff? "en" : "dis");
996 1.1 thorpej }
997 1.1 thorpej mpt_send_cmd(mpt, req);
998 1.1 thorpej
999 1.1 thorpej return (0);
1000 1.1 thorpej }
1001 1.1 thorpej
1002 1.1 thorpej /*
1003 1.4 wiz * Un-mask the interrupts on the chip.
1004 1.1 thorpej */
1005 1.1 thorpej void
1006 1.1 thorpej mpt_enable_ints(mpt_softc_t *mpt)
1007 1.1 thorpej {
1008 1.1 thorpej /* Unmask every thing except door bell int */
1009 1.1 thorpej mpt_write(mpt, MPT_OFFSET_INTR_MASK, MPT_INTR_DB_MASK);
1010 1.1 thorpej }
1011 1.1 thorpej
1012 1.1 thorpej /*
1013 1.4 wiz * Mask the interrupts on the chip.
1014 1.1 thorpej */
1015 1.1 thorpej void
1016 1.1 thorpej mpt_disable_ints(mpt_softc_t *mpt)
1017 1.1 thorpej {
1018 1.1 thorpej /* Mask all interrupts */
1019 1.1 thorpej mpt_write(mpt, MPT_OFFSET_INTR_MASK,
1020 1.1 thorpej MPT_INTR_REPLY_MASK | MPT_INTR_DB_MASK);
1021 1.1 thorpej }
1022 1.1 thorpej
1023 1.1 thorpej /* (Re)Initialize the chip for use */
1024 1.1 thorpej int
1025 1.1 thorpej mpt_init(mpt_softc_t *mpt, u_int32_t who)
1026 1.1 thorpej {
1027 1.1 thorpej int try;
1028 1.1 thorpej MSG_IOC_FACTS_REPLY facts;
1029 1.1 thorpej MSG_PORT_FACTS_REPLY pfp;
1030 1.1 thorpej u_int32_t pptr;
1031 1.1 thorpej int val;
1032 1.1 thorpej
1033 1.1 thorpej /* Put all request buffers (back) on the free list */
1034 1.1 thorpej SLIST_INIT(&mpt->request_free_list);
1035 1.1 thorpej for (val = 0; val < MPT_MAX_REQUESTS(mpt); val++) {
1036 1.1 thorpej mpt_free_request(mpt, &mpt->request_pool[val]);
1037 1.1 thorpej }
1038 1.1 thorpej
1039 1.1 thorpej if (mpt->verbose > 1) {
1040 1.1 thorpej mpt_prt(mpt, "doorbell req = %s",
1041 1.1 thorpej mpt_ioc_diag(mpt_read(mpt, MPT_OFFSET_DOORBELL)));
1042 1.1 thorpej }
1043 1.1 thorpej
1044 1.1 thorpej /*
1045 1.1 thorpej * Start by making sure we're not at FAULT or RESET state
1046 1.1 thorpej */
1047 1.1 thorpej switch (mpt_rd_db(mpt) & MPT_DB_STATE_MASK) {
1048 1.1 thorpej case MPT_DB_STATE_RESET:
1049 1.1 thorpej case MPT_DB_STATE_FAULT:
1050 1.1 thorpej if (mpt_reset(mpt) != MPT_OK) {
1051 1.1 thorpej return (EIO);
1052 1.1 thorpej }
1053 1.1 thorpej default:
1054 1.1 thorpej break;
1055 1.1 thorpej }
1056 1.1 thorpej
1057 1.1 thorpej for (try = 0; try < MPT_MAX_TRYS; try++) {
1058 1.1 thorpej /*
1059 1.1 thorpej * No need to reset if the IOC is already in the READY state.
1060 1.1 thorpej *
1061 1.1 thorpej * Force reset if initialization failed previously.
1062 1.1 thorpej * Note that a hard_reset of the second channel of a '929
1063 1.1 thorpej * will stop operation of the first channel. Hopefully, if the
1064 1.1 thorpej * first channel is ok, the second will not require a hard
1065 1.1 thorpej * reset.
1066 1.1 thorpej */
1067 1.1 thorpej if ((mpt_rd_db(mpt) & MPT_DB_STATE_MASK) !=
1068 1.1 thorpej MPT_DB_STATE_READY) {
1069 1.1 thorpej if (mpt_reset(mpt) != MPT_OK) {
1070 1.1 thorpej DELAY(10000);
1071 1.1 thorpej continue;
1072 1.1 thorpej }
1073 1.1 thorpej }
1074 1.1 thorpej
1075 1.1 thorpej if (mpt_get_iocfacts(mpt, &facts) != MPT_OK) {
1076 1.1 thorpej mpt_prt(mpt, "mpt_get_iocfacts failed");
1077 1.1 thorpej continue;
1078 1.1 thorpej }
1079 1.1 thorpej
1080 1.1 thorpej if (mpt->verbose > 1) {
1081 1.1 thorpej mpt_prt(mpt,
1082 1.1 thorpej "IOCFACTS: GlobalCredits=%d BlockSize=%u "
1083 1.1 thorpej "Request Frame Size %u\n", facts.GlobalCredits,
1084 1.1 thorpej facts.BlockSize, facts.RequestFrameSize);
1085 1.1 thorpej }
1086 1.1 thorpej mpt->mpt_global_credits = facts.GlobalCredits;
1087 1.1 thorpej mpt->request_frame_size = facts.RequestFrameSize;
1088 1.1 thorpej
1089 1.1 thorpej if (mpt_get_portfacts(mpt, &pfp) != MPT_OK) {
1090 1.1 thorpej mpt_prt(mpt, "mpt_get_portfacts failed");
1091 1.1 thorpej continue;
1092 1.1 thorpej }
1093 1.1 thorpej
1094 1.1 thorpej if (mpt->verbose > 1) {
1095 1.1 thorpej mpt_prt(mpt,
1096 1.1 thorpej "PORTFACTS: Type %x PFlags %x IID %d MaxDev %d\n",
1097 1.1 thorpej pfp.PortType, pfp.ProtocolFlags, pfp.PortSCSIID,
1098 1.1 thorpej pfp.MaxDevices);
1099 1.1 thorpej }
1100 1.1 thorpej
1101 1.1 thorpej if (pfp.PortType != MPI_PORTFACTS_PORTTYPE_SCSI &&
1102 1.1 thorpej pfp.PortType != MPI_PORTFACTS_PORTTYPE_FC) {
1103 1.1 thorpej mpt_prt(mpt, "Unsupported Port Type (%x)",
1104 1.1 thorpej pfp.PortType);
1105 1.1 thorpej return (ENXIO);
1106 1.1 thorpej }
1107 1.1 thorpej if (!(pfp.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)) {
1108 1.1 thorpej mpt_prt(mpt, "initiator role unsupported");
1109 1.1 thorpej return (ENXIO);
1110 1.1 thorpej }
1111 1.1 thorpej if (pfp.PortType == MPI_PORTFACTS_PORTTYPE_FC) {
1112 1.1 thorpej mpt->is_fc = 1;
1113 1.1 thorpej } else {
1114 1.1 thorpej mpt->is_fc = 0;
1115 1.1 thorpej }
1116 1.1 thorpej mpt->mpt_ini_id = pfp.PortSCSIID;
1117 1.1 thorpej
1118 1.1 thorpej if (mpt_send_ioc_init(mpt, who) != MPT_OK) {
1119 1.1 thorpej mpt_prt(mpt, "mpt_send_ioc_init failed");
1120 1.1 thorpej continue;
1121 1.1 thorpej }
1122 1.1 thorpej
1123 1.1 thorpej if (mpt->verbose > 1) {
1124 1.1 thorpej mpt_prt(mpt, "mpt_send_ioc_init ok");
1125 1.1 thorpej }
1126 1.1 thorpej
1127 1.1 thorpej if (mpt_wait_state(mpt, MPT_DB_STATE_RUNNING) != MPT_OK) {
1128 1.1 thorpej mpt_prt(mpt, "IOC failed to go to run state");
1129 1.1 thorpej continue;
1130 1.1 thorpej }
1131 1.1 thorpej if (mpt->verbose > 1) {
1132 1.1 thorpej mpt_prt(mpt, "IOC now at RUNSTATE");
1133 1.1 thorpej }
1134 1.1 thorpej
1135 1.1 thorpej /*
1136 1.1 thorpej * Give it reply buffers
1137 1.1 thorpej *
1138 1.1 thorpej * Do *not* except global credits.
1139 1.1 thorpej */
1140 1.1 thorpej for (val = 0, pptr = mpt->reply_phys;
1141 1.1 thorpej (pptr + MPT_REPLY_SIZE) < (mpt->reply_phys + PAGE_SIZE);
1142 1.1 thorpej pptr += MPT_REPLY_SIZE) {
1143 1.1 thorpej mpt_free_reply(mpt, pptr);
1144 1.1 thorpej if (++val == mpt->mpt_global_credits - 1)
1145 1.1 thorpej break;
1146 1.1 thorpej }
1147 1.1 thorpej
1148 1.1 thorpej /*
1149 1.1 thorpej * Enable asynchronous event reporting
1150 1.1 thorpej */
1151 1.1 thorpej mpt_send_event_request(mpt, 1);
1152 1.1 thorpej
1153 1.1 thorpej
1154 1.1 thorpej /*
1155 1.1 thorpej * Read set up initial configuration information
1156 1.1 thorpej * (SPI only for now)
1157 1.1 thorpej */
1158 1.1 thorpej
1159 1.1 thorpej if (mpt->is_fc == 0) {
1160 1.1 thorpej if (mpt_read_config_info_spi(mpt)) {
1161 1.1 thorpej return (EIO);
1162 1.1 thorpej }
1163 1.1 thorpej if (mpt_set_initial_config_spi(mpt)) {
1164 1.1 thorpej return (EIO);
1165 1.1 thorpej }
1166 1.1 thorpej }
1167 1.1 thorpej
1168 1.1 thorpej /*
1169 1.1 thorpej * Now enable the port
1170 1.1 thorpej */
1171 1.1 thorpej if (mpt_send_port_enable(mpt, 0) != MPT_OK) {
1172 1.1 thorpej mpt_prt(mpt, "failed to enable port 0");
1173 1.1 thorpej continue;
1174 1.1 thorpej }
1175 1.1 thorpej
1176 1.1 thorpej if (mpt->verbose > 1) {
1177 1.1 thorpej mpt_prt(mpt, "enabled port 0");
1178 1.1 thorpej }
1179 1.1 thorpej
1180 1.1 thorpej /* Everything worked */
1181 1.1 thorpej break;
1182 1.1 thorpej }
1183 1.1 thorpej
1184 1.1 thorpej if (try >= MPT_MAX_TRYS) {
1185 1.1 thorpej mpt_prt(mpt, "failed to initialize IOC");
1186 1.1 thorpej return (EIO);
1187 1.1 thorpej }
1188 1.1 thorpej
1189 1.1 thorpej if (mpt->verbose > 1) {
1190 1.1 thorpej mpt_prt(mpt, "enabling interrupts");
1191 1.1 thorpej }
1192 1.1 thorpej
1193 1.1 thorpej mpt_enable_ints(mpt);
1194 1.1 thorpej return (0);
1195 1.1 thorpej }
1196