xref: /netbsd/sys/dev/ic/mpt.c (revision 6550d01e)
1 /*	$NetBSD: mpt.c,v 1.14 2010/04/28 22:45:27 chs Exp $	*/
2 
3 /*
4  * Copyright (c) 2000, 2001 by Greg Ansley
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice immediately at the beginning of the file, without modification,
11  *    this list of conditions, and the following disclaimer.
12  * 2. The name of the author may not be used to endorse or promote products
13  *    derived from this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
19  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 /*
28  * Additional Copyright (c) 2002 by Matthew Jacob under same license.
29  */
30 /*-
31  * Copyright (c) 2002, 2006 by Matthew Jacob
32  * All rights reserved.
33  *
34  * Redistribution and use in source and binary forms, with or without
35  * modification, are permitted provided that the following conditions are
36  * met:
37  * 1. Redistributions of source code must retain the above copyright
38  *    notice, this list of conditions and the following disclaimer.
39  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
40  *    substantially similar to the "NO WARRANTY" disclaimer below
41  *    ("Disclaimer") and any redistribution must be conditioned upon including
42  *    a substantially similar Disclaimer requirement for further binary
43  *    redistribution.
44  * 3. Neither the names of the above listed copyright holders nor the names
45  *    of any contributors may be used to endorse or promote products derived
46  *    from this software without specific prior written permission.
47  *
48  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
49  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
52  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
53  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
54  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
55  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
56  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
57  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF THE COPYRIGHT
58  * OWNER OR CONTRIBUTOR IS ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
59  *
60  * Support from Chris Ellsworth in order to make SAS adapters work
61  * is gratefully acknowledged.
62  *
63  *
64  * Support from LSI-Logic has also gone a great deal toward making this a
65  * workable subsystem and is gratefully acknowledged.
66  */
67 /*-
68  * Copyright (c) 2004, Avid Technology, Inc. and its contributors.
69  * Copyright (c) 2005, WHEEL Sp. z o.o.
70  * Copyright (c) 2004, 2005 Justin T. Gibbs
71  * All rights reserved.
72  *
73  * Redistribution and use in source and binary forms, with or without
74  * modification, are permitted provided that the following conditions are
75  * met:
76  * 1. Redistributions of source code must retain the above copyright
77  *    notice, this list of conditions and the following disclaimer.
78  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
79  *    substantially similar to the "NO WARRANTY" disclaimer below
80  *    ("Disclaimer") and any redistribution must be conditioned upon including
81  *    a substantially similar Disclaimer requirement for further binary
82  *    redistribution.
83  * 3. Neither the names of the above listed copyright holders nor the names
84  *    of any contributors may be used to endorse or promote products derived
85  *    from this software without specific prior written permission.
86  *
87  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
88  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
89  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
90  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
91  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
92  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
93  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
94  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
95  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
96  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF THE COPYRIGHT
97  * OWNER OR CONTRIBUTOR IS ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
98  */
99 
100 
101 /*
102  * mpt.c:
103  *
104  * Generic routines for LSI Fusion adapters.
105  *
106  * Adapted from the FreeBSD "mpt" driver by Jason R. Thorpe for
107  * Wasabi Systems, Inc.
108  *
109  * Additional contributions by Garrett D'Amore on behalf of TELES AG.
110  */
111 
112 #include <sys/cdefs.h>
113 __KERNEL_RCSID(0, "$NetBSD: mpt.c,v 1.14 2010/04/28 22:45:27 chs Exp $");
114 
115 #include <dev/ic/mpt.h>
116 
117 #define MPT_MAX_TRYS 3
118 #define MPT_MAX_WAIT 300000
119 
120 static int maxwait_ack = 0;
121 static int maxwait_int = 0;
122 static int maxwait_state = 0;
123 
124 static inline u_int32_t
125 mpt_rd_db(mpt_softc_t *mpt)
126 {
127 	return mpt_read(mpt, MPT_OFFSET_DOORBELL);
128 }
129 
130 static inline u_int32_t
131 mpt_rd_intr(mpt_softc_t *mpt)
132 {
133 	return mpt_read(mpt, MPT_OFFSET_INTR_STATUS);
134 }
135 
136 /* Busy wait for a door bell to be read by IOC */
137 static int
138 mpt_wait_db_ack(mpt_softc_t *mpt)
139 {
140 	int i;
141 	for (i=0; i < MPT_MAX_WAIT; i++) {
142 		if (!MPT_DB_IS_BUSY(mpt_rd_intr(mpt))) {
143 			maxwait_ack = i > maxwait_ack ? i : maxwait_ack;
144 			return MPT_OK;
145 		}
146 
147 		DELAY(100);
148 	}
149 	return MPT_FAIL;
150 }
151 
152 /* Busy wait for a door bell interrupt */
153 static int
154 mpt_wait_db_int(mpt_softc_t *mpt)
155 {
156 	int i;
157 	for (i=0; i < MPT_MAX_WAIT; i++) {
158 		if (MPT_DB_INTR(mpt_rd_intr(mpt))) {
159 			maxwait_int = i > maxwait_int ? i : maxwait_int;
160 			return MPT_OK;
161 		}
162 		DELAY(100);
163 	}
164 	return MPT_FAIL;
165 }
166 
167 /* Wait for IOC to transition to a give state */
168 void
169 mpt_check_doorbell(mpt_softc_t *mpt)
170 {
171 	u_int32_t db = mpt_rd_db(mpt);
172 	if (MPT_STATE(db) != MPT_DB_STATE_RUNNING) {
173 		mpt_prt(mpt, "Device not running");
174 		mpt_print_db(db);
175 	}
176 }
177 
178 /* Wait for IOC to transition to a give state */
179 static int
180 mpt_wait_state(mpt_softc_t *mpt, enum DB_STATE_BITS state)
181 {
182 	int i;
183 
184 	for (i = 0; i < MPT_MAX_WAIT; i++) {
185 		u_int32_t db = mpt_rd_db(mpt);
186 		if (MPT_STATE(db) == state) {
187 			maxwait_state = i > maxwait_state ? i : maxwait_state;
188 			return (MPT_OK);
189 		}
190 		DELAY(100);
191 	}
192 	return (MPT_FAIL);
193 }
194 
195 
196 /* Issue the reset COMMAND to the IOC */
197 int
198 mpt_soft_reset(mpt_softc_t *mpt)
199 {
200 	if (mpt->verbose) {
201 		mpt_prt(mpt, "soft reset");
202 	}
203 
204 	/* Have to use hard reset if we are not in Running state */
205 	if (MPT_STATE(mpt_rd_db(mpt)) != MPT_DB_STATE_RUNNING) {
206 		mpt_prt(mpt, "soft reset failed: device not running");
207 		return MPT_FAIL;
208 	}
209 
210 	/* If door bell is in use we don't have a chance of getting
211 	 * a word in since the IOC probably crashed in message
212 	 * processing. So don't waste our time.
213 	 */
214 	if (MPT_DB_IS_IN_USE(mpt_rd_db(mpt))) {
215 		mpt_prt(mpt, "soft reset failed: doorbell wedged");
216 		return MPT_FAIL;
217 	}
218 
219 	/* Send the reset request to the IOC */
220 	mpt_write(mpt, MPT_OFFSET_DOORBELL,
221 	    MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET << MPI_DOORBELL_FUNCTION_SHIFT);
222 	if (mpt_wait_db_ack(mpt) != MPT_OK) {
223 		mpt_prt(mpt, "soft reset failed: ack timeout");
224 		return MPT_FAIL;
225 	}
226 
227 	/* Wait for the IOC to reload and come out of reset state */
228 	if (mpt_wait_state(mpt, MPT_DB_STATE_READY) != MPT_OK) {
229 		mpt_prt(mpt, "soft reset failed: device did not start running");
230 		return MPT_FAIL;
231 	}
232 
233 	return MPT_OK;
234 }
235 
236 /* This is a magic diagnostic reset that resets all the ARM
237  * processors in the chip.
238  */
239 void
240 mpt_hard_reset(mpt_softc_t *mpt)
241 {
242 	if (mpt->verbose) {
243 		mpt_prt(mpt, "hard reset");
244 	}
245 	mpt_write(mpt, MPT_OFFSET_SEQUENCE, 0xff);
246 
247 	/* Enable diagnostic registers */
248 	mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_1);
249 	mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_2);
250 	mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_3);
251 	mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_4);
252 	mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_5);
253 
254 	/* Diag. port is now active so we can now hit the reset bit */
255 	mpt_write(mpt, MPT_OFFSET_DIAGNOSTIC, MPT_DIAG_RESET_IOC);
256 
257 	DELAY(10000);
258 
259 	/* Disable Diagnostic Register */
260 	mpt_write(mpt, MPT_OFFSET_SEQUENCE, 0xFF);
261 }
262 
263 /*
264  * Reset the IOC when needed. Try software command first then if needed
265  * poke at the magic diagnostic reset. Note that a hard reset resets
266  * *both* IOCs on dual function chips (FC929 && LSI1030) as well as
267  * fouls up the PCI configuration registers.
268  */
269 int
270 mpt_reset(mpt_softc_t *mpt)
271 {
272 	int ret;
273 
274 	/* Try a soft reset */
275 	if ((ret = mpt_soft_reset(mpt)) != MPT_OK) {
276 		/* Failed; do a hard reset */
277 		mpt_hard_reset(mpt);
278 
279 		/* Wait for the IOC to reload and come out of reset state */
280 		ret = mpt_wait_state(mpt, MPT_DB_STATE_READY);
281 		if (ret != MPT_OK) {
282 			mpt_prt(mpt, "failed to reset device");
283 		}
284 	}
285 
286 	return ret;
287 }
288 
289 /* Return a command buffer to the free queue */
290 void
291 mpt_free_request(mpt_softc_t *mpt, request_t *req)
292 {
293 	if (req == NULL || req != &mpt->request_pool[req->index]) {
294 		panic("mpt_free_request bad req ptr\n");
295 		return;
296 	}
297 	req->sequence = 0;
298 	req->xfer = NULL;
299 	req->debug = REQ_FREE;
300 	SLIST_INSERT_HEAD(&mpt->request_free_list, req, link);
301 }
302 
303 /* Get a command buffer from the free queue */
304 request_t *
305 mpt_get_request(mpt_softc_t *mpt)
306 {
307 	request_t *req;
308 	req = SLIST_FIRST(&mpt->request_free_list);
309 	if (req != NULL) {
310 		if (req != &mpt->request_pool[req->index]) {
311 			panic("mpt_get_request: corrupted request free list\n");
312 		}
313 		if (req->xfer != NULL) {
314 			panic("mpt_get_request: corrupted request free list (xfer)\n");
315 		}
316 		SLIST_REMOVE_HEAD(&mpt->request_free_list, link);
317 		req->debug = REQ_IN_PROGRESS;
318 	}
319 	return req;
320 }
321 
322 /* Pass the command to the IOC */
323 void
324 mpt_send_cmd(mpt_softc_t *mpt, request_t *req)
325 {
326 	req->sequence = mpt->sequence++;
327 	if (mpt->verbose > 1) {
328 		u_int32_t *pReq;
329 		pReq = req->req_vbuf;
330 		mpt_prt(mpt, "Send Request %d (0x%x):",
331 		    req->index, req->req_pbuf);
332 		mpt_prt(mpt, "%08x %08x %08x %08x",
333 		    pReq[0], pReq[1], pReq[2], pReq[3]);
334 		mpt_prt(mpt, "%08x %08x %08x %08x",
335 		    pReq[4], pReq[5], pReq[6], pReq[7]);
336 		mpt_prt(mpt, "%08x %08x %08x %08x",
337 		    pReq[8], pReq[9], pReq[10], pReq[11]);
338 		mpt_prt(mpt, "%08x %08x %08x %08x",
339 		    pReq[12], pReq[13], pReq[14], pReq[15]);
340 	}
341 	MPT_SYNC_REQ(mpt, req, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
342 	req->debug = REQ_ON_CHIP;
343 	mpt_write(mpt, MPT_OFFSET_REQUEST_Q, (u_int32_t) req->req_pbuf);
344 }
345 
346 /*
347  * Give the reply buffer back to the IOC after we have
348  * finished processing it.
349  */
350 void
351 mpt_free_reply(mpt_softc_t *mpt, u_int32_t ptr)
352 {
353      mpt_write(mpt, MPT_OFFSET_REPLY_Q, ptr);
354 }
355 
356 /* Get a reply from the IOC */
357 u_int32_t
358 mpt_pop_reply_queue(mpt_softc_t *mpt)
359 {
360      return mpt_read(mpt, MPT_OFFSET_REPLY_Q);
361 }
362 
363 /*
364  * Send a command to the IOC via the handshake register.
365  *
366  * Only done at initialization time and for certain unusual
367  * commands such as device/bus reset as specified by LSI.
368  */
369 int
370 mpt_send_handshake_cmd(mpt_softc_t *mpt, size_t len, void *cmd)
371 {
372 	int i;
373 	u_int32_t data, *data32;
374 
375 	/* Check condition of the IOC */
376 	data = mpt_rd_db(mpt);
377 	if (((MPT_STATE(data) != MPT_DB_STATE_READY)	&&
378 	     (MPT_STATE(data) != MPT_DB_STATE_RUNNING)	&&
379 	     (MPT_STATE(data) != MPT_DB_STATE_FAULT))	||
380 	    (  MPT_DB_IS_IN_USE(data) )) {
381 		mpt_prt(mpt, "handshake aborted due to invalid doorbell state");
382 		mpt_print_db(data);
383 		return(EBUSY);
384 	}
385 
386 	/* We move things in 32 bit chunks */
387 	len = (len + 3) >> 2;
388 	data32 = cmd;
389 
390 	/* Clear any left over pending doorbell interrupts */
391 	if (MPT_DB_INTR(mpt_rd_intr(mpt)))
392 		mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
393 
394 	/*
395 	 * Tell the handshake reg. we are going to send a command
396          * and how long it is going to be.
397 	 */
398 	data = (MPI_FUNCTION_HANDSHAKE << MPI_DOORBELL_FUNCTION_SHIFT) |
399 	    (len << MPI_DOORBELL_ADD_DWORDS_SHIFT);
400 	mpt_write(mpt, MPT_OFFSET_DOORBELL, data);
401 
402 	/* Wait for the chip to notice */
403 	if (mpt_wait_db_int(mpt) != MPT_OK) {
404 		mpt_prt(mpt, "mpt_send_handshake_cmd timeout1");
405 		return ETIMEDOUT;
406 	}
407 
408 	/* Clear the interrupt */
409 	mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
410 
411 	if (mpt_wait_db_ack(mpt) != MPT_OK) {
412 		mpt_prt(mpt, "mpt_send_handshake_cmd timeout2");
413 		return ETIMEDOUT;
414 	}
415 
416 	/* Send the command */
417 	for (i = 0; i < len; i++) {
418 		mpt_write(mpt, MPT_OFFSET_DOORBELL, htole32(*data32++));
419 		if (mpt_wait_db_ack(mpt) != MPT_OK) {
420 			mpt_prt(mpt,
421 			    "mpt_send_handshake_cmd timeout! index = %d", i);
422 			return ETIMEDOUT;
423 		}
424 	}
425 	return MPT_OK;
426 }
427 
428 /* Get the response from the handshake register */
429 int
430 mpt_recv_handshake_reply(mpt_softc_t *mpt, size_t reply_len, void *reply)
431 {
432 	int left, reply_left;
433 	u_int16_t *data16;
434 	MSG_DEFAULT_REPLY *hdr;
435 
436 	/* We move things out in 16 bit chunks */
437 	reply_len >>= 1;
438 	data16 = (u_int16_t *)reply;
439 
440 	hdr = (MSG_DEFAULT_REPLY *)reply;
441 
442 	/* Get first word */
443 	if (mpt_wait_db_int(mpt) != MPT_OK) {
444 		mpt_prt(mpt, "mpt_recv_handshake_cmd timeout1");
445 		return ETIMEDOUT;
446 	}
447 	*data16++ = le16toh(mpt_read(mpt, MPT_OFFSET_DOORBELL) &
448 			    MPT_DB_DATA_MASK);
449 	mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
450 
451 	/* Get Second Word */
452 	if (mpt_wait_db_int(mpt) != MPT_OK) {
453 		mpt_prt(mpt, "mpt_recv_handshake_cmd timeout2");
454 		return ETIMEDOUT;
455 	}
456 	*data16++ = le16toh(mpt_read(mpt, MPT_OFFSET_DOORBELL) &
457 			    MPT_DB_DATA_MASK);
458 	mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
459 
460 	/* With the second word, we can now look at the length */
461 	if (mpt->verbose > 1 && ((reply_len >> 1) != hdr->MsgLength)) {
462 		mpt_prt(mpt, "reply length does not match message length: "
463 			"got 0x%02x, expected 0x%02x",
464 			hdr->MsgLength << 2, reply_len << 1);
465 	}
466 
467 	/* Get rest of the reply; but don't overflow the provided buffer */
468 	left = (hdr->MsgLength << 1) - 2;
469 	reply_left =  reply_len - 2;
470 	while (left--) {
471 		u_int16_t datum;
472 
473 		if (mpt_wait_db_int(mpt) != MPT_OK) {
474 			mpt_prt(mpt, "mpt_recv_handshake_cmd timeout3");
475 			return ETIMEDOUT;
476 		}
477 		datum = mpt_read(mpt, MPT_OFFSET_DOORBELL);
478 
479 		if (reply_left-- > 0)
480 			*data16++ = le16toh(datum & MPT_DB_DATA_MASK);
481 
482 		mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
483 	}
484 
485 	/* One more wait & clear at the end */
486 	if (mpt_wait_db_int(mpt) != MPT_OK) {
487 		mpt_prt(mpt, "mpt_recv_handshake_cmd timeout4");
488 		return ETIMEDOUT;
489 	}
490 	mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0);
491 
492 	if ((hdr->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
493 		if (mpt->verbose > 1)
494 			mpt_print_reply(hdr);
495 		return (MPT_FAIL | hdr->IOCStatus);
496 	}
497 
498 	return (0);
499 }
500 
501 static int
502 mpt_get_iocfacts(mpt_softc_t *mpt, MSG_IOC_FACTS_REPLY *freplp)
503 {
504 	MSG_IOC_FACTS f_req;
505 	int error;
506 
507 	memset(&f_req, 0, sizeof f_req);
508 	f_req.Function = MPI_FUNCTION_IOC_FACTS;
509 	f_req.MsgContext = htole32(0x12071942);
510 	error = mpt_send_handshake_cmd(mpt, sizeof f_req, &f_req);
511 	if (error)
512 		return(error);
513 	error = mpt_recv_handshake_reply(mpt, sizeof (*freplp), freplp);
514 	return (error);
515 }
516 
517 static int
518 mpt_get_portfacts(mpt_softc_t *mpt, MSG_PORT_FACTS_REPLY *freplp)
519 {
520 	MSG_PORT_FACTS f_req;
521 	int error;
522 
523 	/* XXX: Only getting PORT FACTS for Port 0 */
524 	memset(&f_req, 0, sizeof f_req);
525 	f_req.Function = MPI_FUNCTION_PORT_FACTS;
526 	f_req.MsgContext =  htole32(0x12071943);
527 	error = mpt_send_handshake_cmd(mpt, sizeof f_req, &f_req);
528 	if (error)
529 		return(error);
530 	error = mpt_recv_handshake_reply(mpt, sizeof (*freplp), freplp);
531 	return (error);
532 }
533 
534 /*
535  * Send the initialization request. This is where we specify how many
536  * SCSI busses and how many devices per bus we wish to emulate.
537  * This is also the command that specifies the max size of the reply
538  * frames from the IOC that we will be allocating.
539  */
540 static int
541 mpt_send_ioc_init(mpt_softc_t *mpt, u_int32_t who)
542 {
543 	int error = 0;
544 	MSG_IOC_INIT init;
545 	MSG_IOC_INIT_REPLY reply;
546 
547 	memset(&init, 0, sizeof init);
548 	init.WhoInit = who;
549 	init.Function = MPI_FUNCTION_IOC_INIT;
550 	init.MaxDevices = mpt->mpt_max_devices;
551 	init.MaxBuses = 1;
552 	init.ReplyFrameSize = htole16(MPT_REPLY_SIZE);
553 	init.MsgContext = htole32(0x12071941);
554 
555 	if ((error = mpt_send_handshake_cmd(mpt, sizeof init, &init)) != 0) {
556 		return(error);
557 	}
558 
559 	error = mpt_recv_handshake_reply(mpt, sizeof reply, &reply);
560 	return (error);
561 }
562 
563 
564 /*
565  * Utiltity routine to read configuration headers and pages
566  */
567 
568 static int
569 mpt_read_cfg_header(mpt_softc_t *, int, int, int, fCONFIG_PAGE_HEADER *);
570 
571 static int
572 mpt_read_cfg_header(mpt_softc_t *mpt, int PageType, int PageNumber,
573     int PageAddress, fCONFIG_PAGE_HEADER *rslt)
574 {
575 	int count;
576 	request_t *req;
577 	MSG_CONFIG *cfgp;
578 	MSG_CONFIG_REPLY *reply;
579 
580 	req = mpt_get_request(mpt);
581 
582 	cfgp = req->req_vbuf;
583 	memset(cfgp, 0, sizeof *cfgp);
584 
585 	cfgp->Action = MPI_CONFIG_ACTION_PAGE_HEADER;
586 	cfgp->Function = MPI_FUNCTION_CONFIG;
587 	cfgp->Header.PageNumber = (U8) PageNumber;
588 	cfgp->Header.PageType = (U8) PageType;
589 	cfgp->PageAddress = htole32(PageAddress);
590 	MPI_pSGE_SET_FLAGS(((SGE_SIMPLE32 *) &cfgp->PageBufferSGE),
591 	    (MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
592 	    MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_LIST));
593 	cfgp->MsgContext = htole32(req->index | 0x80000000);
594 
595 	mpt_check_doorbell(mpt);
596 	mpt_send_cmd(mpt, req);
597 	count = 0;
598 	do {
599 		DELAY(500);
600 		mpt_intr(mpt);
601 		if (++count == 1000) {
602 			mpt_prt(mpt, "read_cfg_header timed out");
603 			return (-1);
604 		}
605 	} while (req->debug == REQ_ON_CHIP);
606 
607 	reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence);
608         if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
609 		mpt_prt(mpt, "mpt_read_cfg_header: Config Info Status %x",
610 		    reply->IOCStatus);
611 		mpt_free_reply(mpt, (req->sequence << 1));
612 		return (-1);
613 	}
614 	memcpy(rslt, &reply->Header, sizeof (fCONFIG_PAGE_HEADER));
615 	mpt_free_reply(mpt, (req->sequence << 1));
616 	mpt_free_request(mpt, req);
617 	return (0);
618 }
619 
620 #define	CFG_DATA_OFF	128
621 
622 int
623 mpt_read_cfg_page(mpt_softc_t *mpt, int PageAddress, fCONFIG_PAGE_HEADER *hdr)
624 {
625 	int count;
626 	request_t *req;
627 	SGE_SIMPLE32 *se;
628 	MSG_CONFIG *cfgp;
629 	size_t amt;
630 	MSG_CONFIG_REPLY *reply;
631 
632 	req = mpt_get_request(mpt);
633 
634 	cfgp = req->req_vbuf;
635 	memset(cfgp, 0, MPT_REQUEST_AREA);
636 	cfgp->Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
637 	cfgp->Function = MPI_FUNCTION_CONFIG;
638 	cfgp->Header = *hdr;
639  	amt = (cfgp->Header.PageLength * sizeof (u_int32_t));
640 	cfgp->Header.PageType &= MPI_CONFIG_PAGETYPE_MASK;
641 	cfgp->PageAddress = htole32(PageAddress);
642 	se = (SGE_SIMPLE32 *) &cfgp->PageBufferSGE;
643 	se->Address = htole32(req->req_pbuf + CFG_DATA_OFF);
644 	MPI_pSGE_SET_LENGTH(se, amt);
645 	MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
646 	    MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
647 	    MPI_SGE_FLAGS_END_OF_LIST));
648 	se->FlagsLength = htole32(se->FlagsLength);
649 
650 	cfgp->MsgContext = htole32(req->index | 0x80000000);
651 
652 	mpt_check_doorbell(mpt);
653 	mpt_send_cmd(mpt, req);
654 	count = 0;
655 	do {
656 		DELAY(500);
657 		mpt_intr(mpt);
658 		if (++count == 1000) {
659 			mpt_prt(mpt, "read_cfg_page timed out");
660 			return (-1);
661 		}
662 	} while (req->debug == REQ_ON_CHIP);
663 
664 	reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence);
665         if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
666 		mpt_prt(mpt, "mpt_read_cfg_page: Config Info Status %x",
667 		    reply->IOCStatus);
668 		mpt_free_reply(mpt, (req->sequence << 1));
669 		return (-1);
670 	}
671 	mpt_free_reply(mpt, (req->sequence << 1));
672 #if 0 /* XXXJRT */
673 	bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap,
674 	    BUS_DMASYNC_POSTREAD);
675 #endif
676 	if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
677 	    cfgp->Header.PageNumber == 0) {
678 		amt = sizeof (fCONFIG_PAGE_SCSI_PORT_0);
679 	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
680 	    cfgp->Header.PageNumber == 1) {
681 		amt = sizeof (fCONFIG_PAGE_SCSI_PORT_1);
682 	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
683 	    cfgp->Header.PageNumber == 2) {
684 		amt = sizeof (fCONFIG_PAGE_SCSI_PORT_2);
685 	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE  &&
686 	    cfgp->Header.PageNumber == 0) {
687 		amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_0);
688 	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE  &&
689 	    cfgp->Header.PageNumber == 1) {
690 		amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_1);
691 	}
692 	memcpy(hdr, (char *)req->req_vbuf + CFG_DATA_OFF, amt);
693 	mpt_free_request(mpt, req);
694 	return (0);
695 }
696 
697 int
698 mpt_write_cfg_page(mpt_softc_t *mpt, int PageAddress, fCONFIG_PAGE_HEADER *hdr)
699 {
700 	int count, hdr_attr;
701 	request_t *req;
702 	SGE_SIMPLE32 *se;
703 	MSG_CONFIG *cfgp;
704 	size_t amt;
705 	MSG_CONFIG_REPLY *reply;
706 
707 	req = mpt_get_request(mpt);
708 
709 	cfgp = req->req_vbuf;
710 	memset(cfgp, 0, sizeof *cfgp);
711 
712 	hdr_attr = hdr->PageType & MPI_CONFIG_PAGEATTR_MASK;
713 	if (hdr_attr != MPI_CONFIG_PAGEATTR_CHANGEABLE &&
714 	    hdr_attr != MPI_CONFIG_PAGEATTR_PERSISTENT) {
715 		mpt_prt(mpt, "page type 0x%x not changeable",
716 		    hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
717 		return (-1);
718 	}
719 	hdr->PageType &= MPI_CONFIG_PAGETYPE_MASK;
720 
721 	cfgp->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
722 	cfgp->Function = MPI_FUNCTION_CONFIG;
723 	cfgp->Header = *hdr;
724  	amt = (cfgp->Header.PageLength * sizeof (u_int32_t));
725 	cfgp->PageAddress = htole32(PageAddress);
726 
727 	se = (SGE_SIMPLE32 *) &cfgp->PageBufferSGE;
728 	se->Address = htole32(req->req_pbuf + CFG_DATA_OFF);
729 	MPI_pSGE_SET_LENGTH(se, amt);
730 	MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
731 	    MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
732 	    MPI_SGE_FLAGS_END_OF_LIST | MPI_SGE_FLAGS_HOST_TO_IOC));
733 	se->FlagsLength = htole32(se->FlagsLength);
734 
735 	cfgp->MsgContext = htole32(req->index | 0x80000000);
736 
737 	if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
738 	    cfgp->Header.PageNumber == 0) {
739 		amt = sizeof (fCONFIG_PAGE_SCSI_PORT_0);
740 	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
741 	    cfgp->Header.PageNumber == 1) {
742 		amt = sizeof (fCONFIG_PAGE_SCSI_PORT_1);
743 	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT &&
744 	    cfgp->Header.PageNumber == 2) {
745 		amt = sizeof (fCONFIG_PAGE_SCSI_PORT_2);
746 	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE  &&
747 	    cfgp->Header.PageNumber == 0) {
748 		amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_0);
749 	} else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE  &&
750 	    cfgp->Header.PageNumber == 1) {
751 		amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_1);
752 	}
753 	memcpy((char *)req->req_vbuf + CFG_DATA_OFF, hdr, amt);
754 	/* Restore stripped out attributes */
755 	hdr->PageType |= hdr_attr;
756 
757 	mpt_check_doorbell(mpt);
758 	mpt_send_cmd(mpt, req);
759 	count = 0;
760 	do {
761 		DELAY(500);
762 		mpt_intr(mpt);
763 		if (++count == 1000) {
764 			hdr->PageType |= hdr_attr;
765 			mpt_prt(mpt, "mpt_write_cfg_page timed out");
766 			return (-1);
767 		}
768 	} while (req->debug == REQ_ON_CHIP);
769 
770 	reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence);
771         if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
772 		mpt_prt(mpt, "mpt_write_cfg_page: Config Info Status %x",
773 		    le16toh(reply->IOCStatus));
774 		mpt_free_reply(mpt, (req->sequence << 1));
775 		return (-1);
776 	}
777 	mpt_free_reply(mpt, (req->sequence << 1));
778 
779 	mpt_free_request(mpt, req);
780 	return (0);
781 }
782 
783 /*
784  * Read SCSI configuration information
785  */
786 static int
787 mpt_read_config_info_spi(mpt_softc_t *mpt)
788 {
789 	int rv, i;
790 
791 	rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 0,
792 	    0, &mpt->mpt_port_page0.Header);
793 	if (rv) {
794 		return (-1);
795 	}
796 	if (mpt->verbose > 1) {
797 		mpt_prt(mpt, "SPI Port Page 0 Header: %x %x %x %x",
798 		    mpt->mpt_port_page0.Header.PageVersion,
799 		    mpt->mpt_port_page0.Header.PageLength,
800 		    mpt->mpt_port_page0.Header.PageNumber,
801 		    mpt->mpt_port_page0.Header.PageType);
802 	}
803 
804 	rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 1,
805 	    0, &mpt->mpt_port_page1.Header);
806 	if (rv) {
807 		return (-1);
808 	}
809 	if (mpt->verbose > 1) {
810 		mpt_prt(mpt, "SPI Port Page 1 Header: %x %x %x %x",
811 		    mpt->mpt_port_page1.Header.PageVersion,
812 		    mpt->mpt_port_page1.Header.PageLength,
813 		    mpt->mpt_port_page1.Header.PageNumber,
814 		    mpt->mpt_port_page1.Header.PageType);
815 	}
816 
817 	rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 2,
818 	    0, &mpt->mpt_port_page2.Header);
819 	if (rv) {
820 		return (-1);
821 	}
822 
823 	if (mpt->verbose > 1) {
824 		mpt_prt(mpt, "SPI Port Page 2 Header: %x %x %x %x",
825 		    mpt->mpt_port_page1.Header.PageVersion,
826 		    mpt->mpt_port_page1.Header.PageLength,
827 		    mpt->mpt_port_page1.Header.PageNumber,
828 		    mpt->mpt_port_page1.Header.PageType);
829 	}
830 
831 	for (i = 0; i < 16; i++) {
832 		rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE,
833 		    0, i, &mpt->mpt_dev_page0[i].Header);
834 		if (rv) {
835 			return (-1);
836 		}
837 		if (mpt->verbose > 1) {
838 			mpt_prt(mpt,
839 			    "SPI Target %d Device Page 0 Header: %x %x %x %x",
840 			    i, mpt->mpt_dev_page0[i].Header.PageVersion,
841 			    mpt->mpt_dev_page0[i].Header.PageLength,
842 			    mpt->mpt_dev_page0[i].Header.PageNumber,
843 			    mpt->mpt_dev_page0[i].Header.PageType);
844 		}
845 
846 		rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE,
847 		    1, i, &mpt->mpt_dev_page1[i].Header);
848 		if (rv) {
849 			return (-1);
850 		}
851 		if (mpt->verbose > 1) {
852 			mpt_prt(mpt,
853 			    "SPI Target %d Device Page 1 Header: %x %x %x %x",
854 			    i, mpt->mpt_dev_page1[i].Header.PageVersion,
855 			    mpt->mpt_dev_page1[i].Header.PageLength,
856 			    mpt->mpt_dev_page1[i].Header.PageNumber,
857 			    mpt->mpt_dev_page1[i].Header.PageType);
858 		}
859 	}
860 
861 	/*
862 	 * At this point, we don't *have* to fail. As long as we have
863 	 * valid config header information, we can (barely) lurch
864 	 * along.
865 	 */
866 
867 	rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page0.Header);
868 	mpt2host_config_page_scsi_port_0(&mpt->mpt_port_page0);
869 	if (rv) {
870 		mpt_prt(mpt, "failed to read SPI Port Page 0");
871 	} else if (mpt->verbose > 1) {
872 		mpt_prt(mpt,
873 		    "SPI Port Page 0: Capabilities %x PhysicalInterface %x",
874 		    mpt->mpt_port_page0.Capabilities,
875 		    mpt->mpt_port_page0.PhysicalInterface);
876 	}
877 
878 	rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page1.Header);
879 	mpt2host_config_page_scsi_port_1(&mpt->mpt_port_page1);
880 	if (rv) {
881 		mpt_prt(mpt, "failed to read SPI Port Page 1");
882 	} else if (mpt->verbose > 1) {
883 		mpt_prt(mpt,
884 		    "SPI Port Page 1: Configuration %x OnBusTimerValue %x",
885 		    mpt->mpt_port_page1.Configuration,
886 		    mpt->mpt_port_page1.OnBusTimerValue);
887 	}
888 
889 	rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page2.Header);
890 	mpt2host_config_page_scsi_port_2(&mpt->mpt_port_page2);
891 	if (rv) {
892 		mpt_prt(mpt, "failed to read SPI Port Page 2");
893 	} else if (mpt->verbose > 1) {
894 		mpt_prt(mpt,
895 		    "SPI Port Page 2: Flags %x Settings %x",
896 		    mpt->mpt_port_page2.PortFlags,
897 		    mpt->mpt_port_page2.PortSettings);
898 		for (i = 0; i < 1; i++) {
899 			mpt_prt(mpt,
900 		  	    "SPI Port Page 2 Tgt %d: timo %x SF %x Flags %x",
901 			    i, mpt->mpt_port_page2.DeviceSettings[i].Timeout,
902 			    mpt->mpt_port_page2.DeviceSettings[i].SyncFactor,
903 			    mpt->mpt_port_page2.DeviceSettings[i].DeviceFlags);
904 		}
905 	}
906 
907 	for (i = 0; i < 16; i++) {
908 		rv = mpt_read_cfg_page(mpt, i, &mpt->mpt_dev_page0[i].Header);
909 		mpt2host_config_page_scsi_device_0(&mpt->mpt_dev_page0[i]);
910 		if (rv) {
911 			mpt_prt(mpt, "cannot read SPI Tgt %d Device Page 0", i);
912 			continue;
913 		}
914 		if (mpt->verbose > 1) {
915 			mpt_prt(mpt,
916 			    "SPI Tgt %d Page 0: NParms %x Information %x",
917 			    i, mpt->mpt_dev_page0[i].NegotiatedParameters,
918 			    mpt->mpt_dev_page0[i].Information);
919 		}
920 		rv = mpt_read_cfg_page(mpt, i, &mpt->mpt_dev_page1[i].Header);
921 		mpt2host_config_page_scsi_device_1(&mpt->mpt_dev_page1[i]);
922 		if (rv) {
923 			mpt_prt(mpt, "cannot read SPI Tgt %d Device Page 1", i);
924 			continue;
925 		}
926 		if (mpt->verbose > 1) {
927 			mpt_prt(mpt,
928 			    "SPI Tgt %d Page 1: RParms %x Configuration %x",
929 			    i, mpt->mpt_dev_page1[i].RequestedParameters,
930 			    mpt->mpt_dev_page1[i].Configuration);
931 		}
932 	}
933 	return (0);
934 }
935 
936 /*
937  * Validate SPI configuration information.
938  *
939  * In particular, validate SPI Port Page 1.
940  */
941 static int
942 mpt_set_initial_config_spi(mpt_softc_t *mpt)
943 {
944 	int i, pp1val = ((1 << mpt->mpt_ini_id) << 16) | mpt->mpt_ini_id;
945 
946 	mpt->mpt_disc_enable = 0xff;
947 	mpt->mpt_tag_enable = 0;
948 
949 	if (mpt->mpt_port_page1.Configuration != pp1val) {
950 		fCONFIG_PAGE_SCSI_PORT_1 tmp;
951 
952 		mpt_prt(mpt,
953 		    "SPI Port Page 1 Config value bad (%x)- should be %x",
954 		    mpt->mpt_port_page1.Configuration, pp1val);
955 		tmp = mpt->mpt_port_page1;
956 		tmp.Configuration = pp1val;
957 		host2mpt_config_page_scsi_port_1(&tmp);
958 		if (mpt_write_cfg_page(mpt, 0, &tmp.Header)) {
959 			return (-1);
960 		}
961 		if (mpt_read_cfg_page(mpt, 0, &tmp.Header)) {
962 			return (-1);
963 		}
964 		mpt2host_config_page_scsi_port_1(&tmp);
965 		if (tmp.Configuration != pp1val) {
966 			mpt_prt(mpt,
967 			    "failed to reset SPI Port Page 1 Config value");
968 			return (-1);
969 		}
970 		mpt->mpt_port_page1 = tmp;
971 	}
972 
973 	i = 0;
974 	for (i = 0; i < 16; i++) {
975 		fCONFIG_PAGE_SCSI_DEVICE_1 tmp;
976 
977 		tmp = mpt->mpt_dev_page1[i];
978 		tmp.RequestedParameters = 0;
979 		tmp.Configuration = 0;
980 		if (mpt->verbose > 1) {
981 			mpt_prt(mpt,
982 			    "Set Tgt %d SPI DevicePage 1 values to %x 0 %x",
983 			    i, tmp.RequestedParameters, tmp.Configuration);
984 		}
985 		host2mpt_config_page_scsi_device_1(&tmp);
986 		if (mpt_write_cfg_page(mpt, i, &tmp.Header)) {
987 			return (-1);
988 		}
989 		if (mpt_read_cfg_page(mpt, i, &tmp.Header)) {
990 			return (-1);
991 		}
992 		mpt2host_config_page_scsi_device_1(&tmp);
993 		mpt->mpt_dev_page1[i] = tmp;
994 		if (mpt->verbose > 1) {
995 			mpt_prt(mpt,
996 		 	    "SPI Tgt %d Page 1: RParm %x Configuration %x", i,
997 			    mpt->mpt_dev_page1[i].RequestedParameters,
998 			    mpt->mpt_dev_page1[i].Configuration);
999 		}
1000 	}
1001 	return (0);
1002 }
1003 
1004 /*
1005  * Enable IOC port
1006  */
1007 static int
1008 mpt_send_port_enable(mpt_softc_t *mpt, int port)
1009 {
1010 	int count;
1011 	request_t *req;
1012 	MSG_PORT_ENABLE *enable_req;
1013 
1014 	req = mpt_get_request(mpt);
1015 
1016 	enable_req = req->req_vbuf;
1017 	memset(enable_req, 0, sizeof *enable_req);
1018 
1019 	enable_req->Function   = MPI_FUNCTION_PORT_ENABLE;
1020 	enable_req->MsgContext = htole32(req->index | 0x80000000);
1021 	enable_req->PortNumber = port;
1022 
1023 	mpt_check_doorbell(mpt);
1024 	if (mpt->verbose > 1) {
1025 		mpt_prt(mpt, "enabling port %d", port);
1026 	}
1027 	mpt_send_cmd(mpt, req);
1028 
1029 	count = 0;
1030 	do {
1031 		DELAY(500);
1032 		mpt_intr(mpt);
1033 		if (++count == 100000) {
1034 			mpt_prt(mpt, "port enable timed out");
1035 			return (-1);
1036 		}
1037 	} while (req->debug == REQ_ON_CHIP);
1038 	mpt_free_request(mpt, req);
1039 	return (0);
1040 }
1041 
1042 /*
1043  * Enable/Disable asynchronous event reporting.
1044  *
1045  * NB: this is the first command we send via shared memory
1046  * instead of the handshake register.
1047  */
1048 static int
1049 mpt_send_event_request(mpt_softc_t *mpt, int onoff)
1050 {
1051 	request_t *req;
1052 	MSG_EVENT_NOTIFY *enable_req;
1053 
1054 	req = mpt_get_request(mpt);
1055 
1056 	enable_req = req->req_vbuf;
1057 	memset(enable_req, 0, sizeof *enable_req);
1058 
1059 	enable_req->Function   = MPI_FUNCTION_EVENT_NOTIFICATION;
1060 	enable_req->MsgContext = htole32(req->index | 0x80000000);
1061 	enable_req->Switch     = onoff;
1062 
1063 	mpt_check_doorbell(mpt);
1064 	if (mpt->verbose > 1) {
1065 		mpt_prt(mpt, "%sabling async events", onoff? "en" : "dis");
1066 	}
1067 	mpt_send_cmd(mpt, req);
1068 
1069 	return (0);
1070 }
1071 
1072 /*
1073  * Un-mask the interrupts on the chip.
1074  */
1075 void
1076 mpt_enable_ints(mpt_softc_t *mpt)
1077 {
1078 	/* Unmask every thing except door bell int */
1079 	mpt_write(mpt, MPT_OFFSET_INTR_MASK, MPT_INTR_DB_MASK);
1080 }
1081 
1082 /*
1083  * Mask the interrupts on the chip.
1084  */
1085 void
1086 mpt_disable_ints(mpt_softc_t *mpt)
1087 {
1088 	/* Mask all interrupts */
1089 	mpt_write(mpt, MPT_OFFSET_INTR_MASK,
1090 	    MPT_INTR_REPLY_MASK | MPT_INTR_DB_MASK);
1091 }
1092 
1093 /* (Re)Initialize the chip for use */
1094 int
1095 mpt_hw_init(mpt_softc_t *mpt)
1096 {
1097 	u_int32_t	db;
1098 	int		try;
1099 
1100 	/*
1101 	 * Start by making sure we're not at FAULT or RESET state
1102 	 */
1103 	for (try = 0; try < MPT_MAX_TRYS; try++) {
1104 
1105 		db = mpt_rd_db(mpt);
1106 
1107 		switch (MPT_STATE(db)) {
1108 		case MPT_DB_STATE_READY:
1109 			return (0);
1110 
1111 		default:
1112 			/* if peer has already reset us, don't do it again! */
1113 			if (MPT_WHO(db) == MPT_DB_INIT_PCIPEER)
1114 				return (0);
1115 			/*FALLTHRU*/
1116 		case MPT_DB_STATE_RESET:
1117 		case MPT_DB_STATE_FAULT:
1118 			if (mpt_reset(mpt) != MPT_OK) {
1119 				DELAY(10000);
1120 				continue;
1121 			}
1122 			break;
1123 		}
1124 	}
1125 	return (EIO);
1126 }
1127 
1128 int
1129 mpt_init(mpt_softc_t *mpt, u_int32_t who)
1130 {
1131         int try;
1132         MSG_IOC_FACTS_REPLY facts;
1133         MSG_PORT_FACTS_REPLY pfp;
1134 	u_int32_t pptr;
1135         int val;
1136 
1137 	/* Put all request buffers (back) on the free list */
1138         SLIST_INIT(&mpt->request_free_list);
1139 	for (val = 0; val < MPT_MAX_REQUESTS(mpt); val++) {
1140 		mpt_free_request(mpt, &mpt->request_pool[val]);
1141 	}
1142 
1143 	if (mpt->verbose > 1) {
1144 		mpt_prt(mpt, "doorbell req = %s",
1145 		    mpt_ioc_diag(mpt_read(mpt, MPT_OFFSET_DOORBELL)));
1146 	}
1147 
1148 	/*
1149 	 * Start by making sure we're not at FAULT or RESET state
1150 	 */
1151 	if (mpt_hw_init(mpt) != 0)
1152 		return (EIO);
1153 
1154 	for (try = 0; try < MPT_MAX_TRYS; try++) {
1155 		/*
1156 		 * No need to reset if the IOC is already in the READY state.
1157 		 */
1158 
1159 		if (mpt_get_iocfacts(mpt, &facts) != MPT_OK) {
1160 			mpt_prt(mpt, "mpt_get_iocfacts failed");
1161 			continue;
1162 		}
1163 		mpt2host_iocfacts_reply(&facts);
1164 
1165 		if (mpt->verbose > 1) {
1166 			mpt_prt(mpt,
1167 			    "IOCFACTS: GlobalCredits=%d BlockSize=%u "
1168 			    "Request Frame Size %u", facts.GlobalCredits,
1169 			    facts.BlockSize, facts.RequestFrameSize);
1170 		}
1171 		mpt->mpt_max_devices = facts.MaxDevices;
1172 		mpt->mpt_global_credits = facts.GlobalCredits;
1173 		mpt->request_frame_size = facts.RequestFrameSize;
1174 
1175 		if (mpt_get_portfacts(mpt, &pfp) != MPT_OK) {
1176 			mpt_prt(mpt, "mpt_get_portfacts failed");
1177 			continue;
1178 		}
1179 		mpt2host_portfacts_reply(&pfp);
1180 
1181 		if (mpt->verbose > 1) {
1182 			mpt_prt(mpt,
1183 			    "PORTFACTS: Type %x PFlags %x IID %d MaxDev %d",
1184 			    pfp.PortType, pfp.ProtocolFlags, pfp.PortSCSIID,
1185 			    pfp.MaxDevices);
1186 		}
1187 
1188 		if (!(pfp.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)) {
1189 			mpt_prt(mpt, "initiator role unsupported");
1190 			return (ENXIO);
1191 		}
1192 
1193 		switch (pfp.PortType) {
1194 		case MPI_PORTFACTS_PORTTYPE_FC:
1195 			mpt->is_fc = 1;
1196 			mpt->mpt_max_devices = 255;
1197 			break;
1198 		case MPI_PORTFACTS_PORTTYPE_SCSI:
1199 			mpt->is_scsi = 1;
1200 			/* some SPI controllers (VMWare, Sun) lie */
1201 			mpt->mpt_max_devices = 16;
1202 			break;
1203 		case MPI_PORTFACTS_PORTTYPE_SAS:
1204 			mpt->is_sas = 1;
1205 			break;
1206 		default:
1207 			mpt_prt(mpt, "Unsupported Port Type (%x)",
1208 			    pfp.PortType);
1209 			return (ENXIO);
1210 		}
1211 
1212 		mpt->mpt_ini_id = pfp.PortSCSIID;
1213 
1214 		if (mpt_send_ioc_init(mpt, who) != MPT_OK) {
1215 			mpt_prt(mpt, "mpt_send_ioc_init failed");
1216 			continue;
1217 		}
1218 
1219 		if (mpt->verbose > 1) {
1220 			mpt_prt(mpt, "mpt_send_ioc_init ok");
1221 		}
1222 
1223 		if (mpt_wait_state(mpt, MPT_DB_STATE_RUNNING) != MPT_OK) {
1224 			mpt_prt(mpt, "IOC failed to go to run state");
1225 			continue;
1226 		}
1227 		if (mpt->verbose > 1) {
1228 			mpt_prt(mpt, "IOC now at RUNSTATE");
1229 		}
1230 
1231 		/*
1232 		 * Give it reply buffers
1233 		 *
1234 		 * Do *not* except global credits.
1235 		 */
1236 		for (val = 0, pptr = mpt->reply_phys;
1237 		    (pptr + MPT_REPLY_SIZE) < (mpt->reply_phys + PAGE_SIZE);
1238 		     pptr += MPT_REPLY_SIZE) {
1239 			mpt_free_reply(mpt, pptr);
1240 			if (++val == mpt->mpt_global_credits - 1)
1241 				break;
1242 		}
1243 
1244 		/*
1245 		 * Enable asynchronous event reporting
1246 		 */
1247 		mpt_send_event_request(mpt, 1);
1248 
1249 
1250 		/*
1251 		 * Read set up initial configuration information
1252 		 * (SPI only for now)
1253 		 */
1254 
1255 		if (mpt->is_scsi) {
1256 			if (mpt_read_config_info_spi(mpt)) {
1257 				return (EIO);
1258 			}
1259 			if (mpt_set_initial_config_spi(mpt)) {
1260 				return (EIO);
1261 			}
1262 		}
1263 
1264 		/*
1265 		 * Now enable the port
1266 		 */
1267 		if (mpt_send_port_enable(mpt, 0) != MPT_OK) {
1268 			mpt_prt(mpt, "failed to enable port 0");
1269 			continue;
1270 		}
1271 
1272 		if (mpt->verbose > 1) {
1273 			mpt_prt(mpt, "enabled port 0");
1274 		}
1275 
1276 		/* Everything worked */
1277 		break;
1278 	}
1279 
1280 	if (try >= MPT_MAX_TRYS) {
1281 		mpt_prt(mpt, "failed to initialize IOC");
1282 		return (EIO);
1283 	}
1284 
1285 	if (mpt->verbose > 1) {
1286 		mpt_prt(mpt, "enabling interrupts");
1287 	}
1288 
1289 	mpt_enable_ints(mpt);
1290 	return (0);
1291 }
1292 
1293 /*
1294  * Endian Conversion Functions- only used on Big Endian machines
1295  */
1296 #if	_BYTE_ORDER == _BIG_ENDIAN
1297 void
1298 mpt2host_sge_simple_union(SGE_SIMPLE_UNION *sge)
1299 {
1300 
1301 	MPT_2_HOST32(sge, FlagsLength);
1302 	MPT_2_HOST32(sge, _u.Address64.Low);
1303 	MPT_2_HOST32(sge, _u.Address64.High);
1304 }
1305 
1306 void
1307 mpt2host_iocfacts_reply(MSG_IOC_FACTS_REPLY *rp)
1308 {
1309 
1310 	MPT_2_HOST16(rp, MsgVersion);
1311 #if 0
1312 	MPT_2_HOST16(rp, HeaderVersion);
1313 #endif
1314 	MPT_2_HOST32(rp, MsgContext);
1315 	MPT_2_HOST16(rp, IOCExceptions);
1316 	MPT_2_HOST16(rp, IOCStatus);
1317 	MPT_2_HOST32(rp, IOCLogInfo);
1318 	MPT_2_HOST16(rp, ReplyQueueDepth);
1319 	MPT_2_HOST16(rp, RequestFrameSize);
1320 	MPT_2_HOST16(rp, Reserved_0101_FWVersion);
1321 	MPT_2_HOST16(rp, ProductID);
1322 	MPT_2_HOST32(rp, CurrentHostMfaHighAddr);
1323 	MPT_2_HOST16(rp, GlobalCredits);
1324 	MPT_2_HOST32(rp, CurrentSenseBufferHighAddr);
1325 	MPT_2_HOST16(rp, CurReplyFrameSize);
1326 	MPT_2_HOST32(rp, FWImageSize);
1327 #if 0
1328 	MPT_2_HOST32(rp, IOCCapabilities);
1329 #endif
1330 	MPT_2_HOST32(rp, FWVersion.Word);
1331 #if 0
1332 	MPT_2_HOST16(rp, HighPriorityQueueDepth);
1333 	MPT_2_HOST16(rp, Reserved2);
1334 	mpt2host_sge_simple_union(&rp->HostPageBufferSGE);
1335 	MPT_2_HOST32(rp, ReplyFifoHostSignalingAddr);
1336 #endif
1337 }
1338 
1339 void
1340 mpt2host_portfacts_reply(MSG_PORT_FACTS_REPLY *pfp)
1341 {
1342 
1343 	MPT_2_HOST16(pfp, Reserved);
1344 	MPT_2_HOST16(pfp, Reserved1);
1345 	MPT_2_HOST32(pfp, MsgContext);
1346 	MPT_2_HOST16(pfp, Reserved2);
1347 	MPT_2_HOST16(pfp, IOCStatus);
1348 	MPT_2_HOST32(pfp, IOCLogInfo);
1349 	MPT_2_HOST16(pfp, MaxDevices);
1350 	MPT_2_HOST16(pfp, PortSCSIID);
1351 	MPT_2_HOST16(pfp, ProtocolFlags);
1352 	MPT_2_HOST16(pfp, MaxPostedCmdBuffers);
1353 	MPT_2_HOST16(pfp, MaxPersistentIDs);
1354 	MPT_2_HOST16(pfp, MaxLanBuckets);
1355 	MPT_2_HOST16(pfp, Reserved4);
1356 	MPT_2_HOST32(pfp, Reserved5);
1357 }
1358 
1359 void
1360 mpt2host_config_page_scsi_port_0(fCONFIG_PAGE_SCSI_PORT_0 *sp0)
1361 {
1362 
1363 	MPT_2_HOST32(sp0, Capabilities);
1364 	MPT_2_HOST32(sp0, PhysicalInterface);
1365 }
1366 
1367 void
1368 mpt2host_config_page_scsi_port_1(fCONFIG_PAGE_SCSI_PORT_1 *sp1)
1369 {
1370 
1371 	MPT_2_HOST32(sp1, Configuration);
1372 	MPT_2_HOST32(sp1, OnBusTimerValue);
1373 #if 0
1374 	MPT_2_HOST16(sp1, IDConfig);
1375 #endif
1376 }
1377 
1378 void
1379 host2mpt_config_page_scsi_port_1(fCONFIG_PAGE_SCSI_PORT_1 *sp1)
1380 {
1381 
1382 	HOST_2_MPT32(sp1, Configuration);
1383 	HOST_2_MPT32(sp1, OnBusTimerValue);
1384 #if 0
1385 	HOST_2_MPT16(sp1, IDConfig);
1386 #endif
1387 }
1388 
1389 void
1390 mpt2host_config_page_scsi_port_2(fCONFIG_PAGE_SCSI_PORT_2 *sp2)
1391 {
1392 	int i;
1393 
1394 	MPT_2_HOST32(sp2, PortFlags);
1395 	MPT_2_HOST32(sp2, PortSettings);
1396 	for (i = 0; i < sizeof(sp2->DeviceSettings) /
1397 	    sizeof(*sp2->DeviceSettings); i++) {
1398 		MPT_2_HOST16(sp2, DeviceSettings[i].DeviceFlags);
1399 	}
1400 }
1401 
1402 void
1403 mpt2host_config_page_scsi_device_0(fCONFIG_PAGE_SCSI_DEVICE_0 *sd0)
1404 {
1405 
1406 	MPT_2_HOST32(sd0, NegotiatedParameters);
1407 	MPT_2_HOST32(sd0, Information);
1408 }
1409 
1410 void
1411 host2mpt_config_page_scsi_device_0(fCONFIG_PAGE_SCSI_DEVICE_0 *sd0)
1412 {
1413 
1414 	HOST_2_MPT32(sd0, NegotiatedParameters);
1415 	HOST_2_MPT32(sd0, Information);
1416 }
1417 
1418 void
1419 mpt2host_config_page_scsi_device_1(fCONFIG_PAGE_SCSI_DEVICE_1 *sd1)
1420 {
1421 
1422 	MPT_2_HOST32(sd1, RequestedParameters);
1423 	MPT_2_HOST32(sd1, Reserved);
1424 	MPT_2_HOST32(sd1, Configuration);
1425 }
1426 
1427 void
1428 host2mpt_config_page_scsi_device_1(fCONFIG_PAGE_SCSI_DEVICE_1 *sd1)
1429 {
1430 
1431 	HOST_2_MPT32(sd1, RequestedParameters);
1432 	HOST_2_MPT32(sd1, Reserved);
1433 	HOST_2_MPT32(sd1, Configuration);
1434 }
1435 
1436 void
1437 mpt2host_config_page_fc_port_0(fCONFIG_PAGE_FC_PORT_0 *fp0)
1438 {
1439 
1440 	MPT_2_HOST32(fp0, Flags);
1441 	MPT_2_HOST32(fp0, PortIdentifier);
1442 	MPT_2_HOST32(fp0, WWNN.Low);
1443 	MPT_2_HOST32(fp0, WWNN.High);
1444 	MPT_2_HOST32(fp0, WWPN.Low);
1445 	MPT_2_HOST32(fp0, WWPN.High);
1446 	MPT_2_HOST32(fp0, SupportedServiceClass);
1447 	MPT_2_HOST32(fp0, SupportedSpeeds);
1448 	MPT_2_HOST32(fp0, CurrentSpeed);
1449 	MPT_2_HOST32(fp0, MaxFrameSize);
1450 	MPT_2_HOST32(fp0, FabricWWNN.Low);
1451 	MPT_2_HOST32(fp0, FabricWWNN.High);
1452 	MPT_2_HOST32(fp0, FabricWWPN.Low);
1453 	MPT_2_HOST32(fp0, FabricWWPN.High);
1454 	MPT_2_HOST32(fp0, DiscoveredPortsCount);
1455 	MPT_2_HOST32(fp0, MaxInitiators);
1456 }
1457 
1458 void
1459 mpt2host_config_page_fc_port_1(fCONFIG_PAGE_FC_PORT_1 *fp1)
1460 {
1461 
1462 	MPT_2_HOST32(fp1, Flags);
1463 	MPT_2_HOST32(fp1, NoSEEPROMWWNN.Low);
1464 	MPT_2_HOST32(fp1, NoSEEPROMWWNN.High);
1465 	MPT_2_HOST32(fp1, NoSEEPROMWWPN.Low);
1466 	MPT_2_HOST32(fp1, NoSEEPROMWWPN.High);
1467 }
1468 
1469 void
1470 host2mpt_config_page_fc_port_1(fCONFIG_PAGE_FC_PORT_1 *fp1)
1471 {
1472 
1473 	HOST_2_MPT32(fp1, Flags);
1474 	HOST_2_MPT32(fp1, NoSEEPROMWWNN.Low);
1475 	HOST_2_MPT32(fp1, NoSEEPROMWWNN.High);
1476 	HOST_2_MPT32(fp1, NoSEEPROMWWPN.Low);
1477 	HOST_2_MPT32(fp1, NoSEEPROMWWPN.High);
1478 }
1479 
1480 void
1481 mpt2host_config_page_raid_vol_0(fCONFIG_PAGE_RAID_VOL_0 *volp)
1482 {
1483 	int i;
1484 
1485 	MPT_2_HOST16(volp, VolumeStatus.Reserved);
1486 	MPT_2_HOST16(volp, VolumeSettings.Settings);
1487 	MPT_2_HOST32(volp, MaxLBA);
1488 #if 0
1489 	MPT_2_HOST32(volp, MaxLBAHigh);
1490 #endif
1491 	MPT_2_HOST32(volp, StripeSize);
1492 	MPT_2_HOST32(volp, Reserved2);
1493 	MPT_2_HOST32(volp, Reserved3);
1494 	for (i = 0; i < MPI_RAID_VOL_PAGE_0_PHYSDISK_MAX; i++) {
1495 		MPT_2_HOST16(volp, PhysDisk[i].Reserved);
1496 	}
1497 }
1498 
1499 void
1500 mpt2host_config_page_raid_phys_disk_0(fCONFIG_PAGE_RAID_PHYS_DISK_0 *rpd0)
1501 {
1502 
1503 	MPT_2_HOST32(rpd0, Reserved1);
1504 	MPT_2_HOST16(rpd0, PhysDiskStatus.Reserved);
1505 	MPT_2_HOST32(rpd0, MaxLBA);
1506 	MPT_2_HOST16(rpd0, ErrorData.Reserved);
1507 	MPT_2_HOST16(rpd0, ErrorData.ErrorCount);
1508 	MPT_2_HOST16(rpd0, ErrorData.SmartCount);
1509 }
1510 
1511 #endif
1512