xref: /illumos-gate/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_init.c (revision 44bc9120699af80bb18366ca474cb2c618608ca9)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  * Copyright (c) 2014, Tegile Systems Inc. All rights reserved.
26  */
27 
28 /*
29  * Copyright (c) 2000 to 2009, LSI Corporation.
30  * All rights reserved.
31  *
32  * Redistribution and use in source and binary forms of all code within
33  * this file that is exclusively owned by LSI, with or without
34  * modification, is permitted provided that, in addition to the CDDL 1.0
35  * License requirements, the following conditions are met:
36  *
37  *    Neither the name of the author nor the names of its contributors may be
38  *    used to endorse or promote products derived from this software without
39  *    specific prior written permission.
40  *
41  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
42  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
43  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
44  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
45  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
46  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
47  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
48  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
49  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
50  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
51  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
52  * DAMAGE.
53  */
54 
55 /*
56  * mptsas_init - This file contains all the functions used to initialize
57  * MPT2.0 based hardware.
58  */
59 
60 #if defined(lint) || defined(DEBUG)
61 #define	MPTSAS_DEBUG
62 #endif
63 
64 /*
65  * standard header files
66  */
67 #include <sys/note.h>
68 #include <sys/scsi/scsi.h>
69 
70 #pragma pack(1)
71 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h>
72 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2.h>
73 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h>
74 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h>
75 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_ioc.h>
76 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_tool.h>
77 #pragma pack()
78 /*
79  * private header files.
80  */
81 #include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
82 
83 static int mptsas_ioc_do_get_facts(mptsas_t *mpt, caddr_t memp, int var,
84 	ddi_acc_handle_t accessp);
85 static int mptsas_ioc_do_get_facts_reply(mptsas_t *mpt, caddr_t memp, int var,
86 	ddi_acc_handle_t accessp);
87 static int mptsas_ioc_do_get_port_facts(mptsas_t *mpt, caddr_t memp, int var,
88 	ddi_acc_handle_t accessp);
89 static int mptsas_ioc_do_get_port_facts_reply(mptsas_t *mpt, caddr_t memp,
90     int var, ddi_acc_handle_t accessp);
91 static int mptsas_ioc_do_enable_port(mptsas_t *mpt, caddr_t memp, int var,
92 	ddi_acc_handle_t accessp);
93 static int mptsas_ioc_do_enable_port_reply(mptsas_t *mpt, caddr_t memp, int var,
94 	ddi_acc_handle_t accessp);
95 static int mptsas_ioc_do_enable_event_notification(mptsas_t *mpt, caddr_t memp,
96 	int var, ddi_acc_handle_t accessp);
97 static int mptsas_ioc_do_enable_event_notification_reply(mptsas_t *mpt,
98     caddr_t memp, int var, ddi_acc_handle_t accessp);
99 static int mptsas_do_ioc_init(mptsas_t *mpt, caddr_t memp, int var,
100 	ddi_acc_handle_t accessp);
101 static int mptsas_do_ioc_init_reply(mptsas_t *mpt, caddr_t memp, int var,
102 	ddi_acc_handle_t accessp);
103 
104 static const char *
105 mptsas_devid_type_string(mptsas_t *mpt)
106 {
107 	switch (mpt->m_devid) {
108 	case MPI2_MFGPAGE_DEVID_SAS2008:
109 		return ("SAS2008");
110 	case MPI2_MFGPAGE_DEVID_SAS2004:
111 		return ("SAS2004");
112 	case MPI2_MFGPAGE_DEVID_SAS2108_1:
113 	case MPI2_MFGPAGE_DEVID_SAS2108_2:
114 	case MPI2_MFGPAGE_DEVID_SAS2108_3:
115 		return ("SAS2108");
116 	case MPI2_MFGPAGE_DEVID_SAS2116_1:
117 	case MPI2_MFGPAGE_DEVID_SAS2116_2:
118 		return ("SAS2116");
119 	case MPI2_MFGPAGE_DEVID_SAS2208_1:
120 	case MPI2_MFGPAGE_DEVID_SAS2208_2:
121 	case MPI2_MFGPAGE_DEVID_SAS2208_3:
122 	case MPI2_MFGPAGE_DEVID_SAS2208_4:
123 	case MPI2_MFGPAGE_DEVID_SAS2208_5:
124 	case MPI2_MFGPAGE_DEVID_SAS2208_6:
125 		return ("SAS2208");
126 	case MPI2_MFGPAGE_DEVID_SAS2308_1:
127 	case MPI2_MFGPAGE_DEVID_SAS2308_2:
128 	case MPI2_MFGPAGE_DEVID_SAS2308_3:
129 		return ("SAS2308");
130 	case MPI25_MFGPAGE_DEVID_SAS3004:
131 		return ("SAS3004");
132 	case MPI25_MFGPAGE_DEVID_SAS3008:
133 		return ("SAS3008");
134 	case MPI25_MFGPAGE_DEVID_SAS3108_1:
135 	case MPI25_MFGPAGE_DEVID_SAS3108_2:
136 	case MPI25_MFGPAGE_DEVID_SAS3108_5:
137 	case MPI25_MFGPAGE_DEVID_SAS3108_6:
138 		return ("SAS3108");
139 	default:
140 		return ("?");
141 	}
142 }
143 
144 int
145 mptsas_ioc_get_facts(mptsas_t *mpt)
146 {
147 	/*
148 	 * Send get facts messages
149 	 */
150 	if (mptsas_do_dma(mpt, sizeof (MPI2_IOC_FACTS_REQUEST), NULL,
151 	    mptsas_ioc_do_get_facts)) {
152 		return (DDI_FAILURE);
153 	}
154 
155 	/*
156 	 * Get facts reply messages
157 	 */
158 	if (mptsas_do_dma(mpt, sizeof (MPI2_IOC_FACTS_REPLY), NULL,
159 	    mptsas_ioc_do_get_facts_reply)) {
160 		return (DDI_FAILURE);
161 	}
162 
163 	return (DDI_SUCCESS);
164 }
165 
166 static int
167 mptsas_ioc_do_get_facts(mptsas_t *mpt, caddr_t memp, int var,
168 		ddi_acc_handle_t accessp)
169 {
170 #ifndef __lock_lint
171 	_NOTE(ARGUNUSED(var))
172 #endif
173 	pMpi2IOCFactsRequest_t	facts;
174 	int			numbytes;
175 
176 	bzero(memp, sizeof (*facts));
177 	facts = (void *)memp;
178 	ddi_put8(accessp, &facts->Function, MPI2_FUNCTION_IOC_FACTS);
179 	numbytes = sizeof (*facts);
180 
181 	/*
182 	 * Post message via handshake
183 	 */
184 	if (mptsas_send_handshake_msg(mpt, memp, numbytes, accessp)) {
185 		return (DDI_FAILURE);
186 	}
187 
188 	return (DDI_SUCCESS);
189 }
190 
191 static int
192 mptsas_ioc_do_get_facts_reply(mptsas_t *mpt, caddr_t memp, int var,
193 		ddi_acc_handle_t accessp)
194 {
195 #ifndef __lock_lint
196 	_NOTE(ARGUNUSED(var))
197 #endif
198 
199 	pMpi2IOCFactsReply_t	factsreply;
200 	int			numbytes;
201 	uint_t			iocstatus;
202 	char			buf[32];
203 	uint16_t		numReplyFrames;
204 	uint16_t		queueSize, queueDiff;
205 	int			simple_sge_main;
206 	int			simple_sge_next;
207 	uint32_t		capabilities;
208 	uint16_t		msgversion;
209 
210 	bzero(memp, sizeof (*factsreply));
211 	factsreply = (void *)memp;
212 	numbytes = sizeof (*factsreply);
213 
214 	/*
215 	 * get ioc facts reply message
216 	 */
217 	if (mptsas_get_handshake_msg(mpt, memp, numbytes, accessp)) {
218 		return (DDI_FAILURE);
219 	}
220 
221 	if (iocstatus = ddi_get16(accessp, &factsreply->IOCStatus)) {
222 		mptsas_log(mpt, CE_WARN, "mptsas_ioc_do_get_facts_reply: "
223 		    "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
224 		    ddi_get32(accessp, &factsreply->IOCLogInfo));
225 		return (DDI_FAILURE);
226 	}
227 
228 	/*
229 	 * store key values from reply to mpt structure
230 	 */
231 	mpt->m_fwversion = ddi_get32(accessp, &factsreply->FWVersion.Word);
232 	mpt->m_productid = ddi_get16(accessp, &factsreply->ProductID);
233 
234 
235 	(void) sprintf(buf, "%u.%u.%u.%u",
236 	    ddi_get8(accessp, &factsreply->FWVersion.Struct.Major),
237 	    ddi_get8(accessp, &factsreply->FWVersion.Struct.Minor),
238 	    ddi_get8(accessp, &factsreply->FWVersion.Struct.Unit),
239 	    ddi_get8(accessp, &factsreply->FWVersion.Struct.Dev));
240 	mptsas_log(mpt, CE_NOTE, "?MPT Firmware version v%s (%s)\n",
241 	    buf, mptsas_devid_type_string(mpt));
242 	(void) ddi_prop_update_string(DDI_DEV_T_NONE, mpt->m_dip,
243 	    "firmware-version", buf);
244 
245 	/*
246 	 * Set up request info.
247 	 */
248 	mpt->m_max_requests = ddi_get16(accessp,
249 	    &factsreply->RequestCredit) - 1;
250 	mpt->m_req_frame_size = ddi_get16(accessp,
251 	    &factsreply->IOCRequestFrameSize) * 4;
252 
253 	/*
254 	 * Size of reply free queue should be the number of requests
255 	 * plus some additional for events (32).  Make sure number of
256 	 * reply frames is not a multiple of 16 so that the queue sizes
257 	 * are calculated correctly later to be a multiple of 16.
258 	 */
259 	mpt->m_reply_frame_size = ddi_get8(accessp,
260 	    &factsreply->ReplyFrameSize) * 4;
261 	numReplyFrames = mpt->m_max_requests + 32;
262 	if (!(numReplyFrames % 16)) {
263 		numReplyFrames--;
264 	}
265 	mpt->m_max_replies = numReplyFrames;
266 	queueSize = numReplyFrames;
267 	queueSize += 16 - (queueSize % 16);
268 	mpt->m_free_queue_depth = queueSize;
269 
270 	/*
271 	 * Size of reply descriptor post queue should be the number of
272 	 * request frames + the number of reply frames + 1 and needs to
273 	 * be a multiple of 16.  This size can be no larger than
274 	 * MaxReplyDescriptorPostQueueDepth from IOCFacts.  If the
275 	 * calculated queue size is larger than allowed, subtract a
276 	 * multiple of 16 from m_max_requests, m_max_replies, and
277 	 * m_reply_free_depth.
278 	 */
279 	queueSize = mpt->m_max_requests + numReplyFrames + 1;
280 	if (queueSize % 16) {
281 		queueSize += 16 - (queueSize % 16);
282 	}
283 	mpt->m_post_queue_depth = ddi_get16(accessp,
284 	    &factsreply->MaxReplyDescriptorPostQueueDepth);
285 	if (queueSize > mpt->m_post_queue_depth) {
286 		queueDiff = queueSize - mpt->m_post_queue_depth;
287 		if (queueDiff % 16) {
288 			queueDiff += 16 - (queueDiff % 16);
289 		}
290 		mpt->m_max_requests -= queueDiff;
291 		mpt->m_max_replies -= queueDiff;
292 		mpt->m_free_queue_depth -= queueDiff;
293 		queueSize -= queueDiff;
294 	}
295 	mpt->m_post_queue_depth = queueSize;
296 
297 	/*
298 	 * Set up max chain depth.
299 	 */
300 	mpt->m_max_chain_depth = ddi_get8(accessp,
301 	    &factsreply->MaxChainDepth);
302 	mpt->m_ioc_capabilities = ddi_get32(accessp,
303 	    &factsreply->IOCCapabilities);
304 
305 	/*
306 	 * Set flag to check for SAS3 support.
307 	 */
308 	msgversion = ddi_get16(accessp, &factsreply->MsgVersion);
309 	if (msgversion == MPI2_VERSION_02_05) {
310 		mptsas_log(mpt, CE_NOTE, "?mpt_sas%d SAS 3 Supported\n",
311 		    mpt->m_instance);
312 		mpt->m_MPI25 = TRUE;
313 	} else {
314 		mptsas_log(mpt, CE_NOTE, "?mpt_sas%d MPI Version 0x%x\n",
315 		    mpt->m_instance, msgversion);
316 	}
317 
318 	/*
319 	 * Calculate max frames per request based on DMA S/G length.
320 	 */
321 	simple_sge_main = MPTSAS_MAX_FRAME_SGES64(mpt) - 1;
322 	simple_sge_next = mpt->m_req_frame_size / MPTSAS_SGE_SIZE(mpt) - 1;
323 
324 	mpt->m_max_request_frames = (MPTSAS_MAX_DMA_SEGS -
325 	    simple_sge_main) / simple_sge_next + 1;
326 	if (((MPTSAS_MAX_DMA_SEGS - simple_sge_main) %
327 	    simple_sge_next) > 1) {
328 		mpt->m_max_request_frames++;
329 	}
330 
331 	/*
332 	 * Check if controller supports FW diag buffers and set flag to enable
333 	 * each type.
334 	 */
335 	capabilities = ddi_get32(accessp, &factsreply->IOCCapabilities);
336 	if (capabilities & MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER) {
337 		mpt->m_fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_TRACE].enabled =
338 		    TRUE;
339 	}
340 	if (capabilities & MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER) {
341 		mpt->m_fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_SNAPSHOT].
342 		    enabled = TRUE;
343 	}
344 	if (capabilities & MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER) {
345 		mpt->m_fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_EXTENDED].
346 		    enabled = TRUE;
347 	}
348 
349 	/*
350 	 * Check if controller supports replaying events when issuing Message
351 	 * Unit Reset and set flag to enable MUR.
352 	 */
353 	if (capabilities & MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY) {
354 		mpt->m_event_replay = TRUE;
355 	}
356 
357 	/*
358 	 * Check if controller supports IR.
359 	 */
360 	if (capabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) {
361 		mpt->m_ir_capable = TRUE;
362 	}
363 
364 	return (DDI_SUCCESS);
365 }
366 
367 int
368 mptsas_ioc_get_port_facts(mptsas_t *mpt, int port)
369 {
370 	/*
371 	 * Send get port facts message
372 	 */
373 	if (mptsas_do_dma(mpt, sizeof (MPI2_PORT_FACTS_REQUEST), port,
374 	    mptsas_ioc_do_get_port_facts)) {
375 		return (DDI_FAILURE);
376 	}
377 
378 	/*
379 	 * Get port facts reply message
380 	 */
381 	if (mptsas_do_dma(mpt, sizeof (MPI2_PORT_FACTS_REPLY), port,
382 	    mptsas_ioc_do_get_port_facts_reply)) {
383 		return (DDI_FAILURE);
384 	}
385 
386 	return (DDI_SUCCESS);
387 }
388 
389 static int
390 mptsas_ioc_do_get_port_facts(mptsas_t *mpt, caddr_t memp, int var,
391 			ddi_acc_handle_t accessp)
392 {
393 	pMpi2PortFactsRequest_t	facts;
394 	int			numbytes;
395 
396 	bzero(memp, sizeof (*facts));
397 	facts = (void *)memp;
398 	ddi_put8(accessp, &facts->Function, MPI2_FUNCTION_PORT_FACTS);
399 	ddi_put8(accessp, &facts->PortNumber, var);
400 	numbytes = sizeof (*facts);
401 
402 	/*
403 	 * Send port facts message via handshake
404 	 */
405 	if (mptsas_send_handshake_msg(mpt, memp, numbytes, accessp)) {
406 		return (DDI_FAILURE);
407 	}
408 
409 	return (DDI_SUCCESS);
410 }
411 
412 static int
413 mptsas_ioc_do_get_port_facts_reply(mptsas_t *mpt, caddr_t memp, int var,
414 				ddi_acc_handle_t accessp)
415 {
416 #ifndef __lock_lint
417 	_NOTE(ARGUNUSED(var))
418 #endif
419 	pMpi2PortFactsReply_t	factsreply;
420 	int			numbytes;
421 	uint_t			iocstatus;
422 
423 	bzero(memp, sizeof (*factsreply));
424 	factsreply = (void *)memp;
425 	numbytes = sizeof (*factsreply);
426 
427 	/*
428 	 * Get port facts reply message via handshake
429 	 */
430 	if (mptsas_get_handshake_msg(mpt, memp, numbytes, accessp)) {
431 		return (DDI_FAILURE);
432 	}
433 
434 	if (iocstatus = ddi_get16(accessp, &factsreply->IOCStatus)) {
435 		mptsas_log(mpt, CE_WARN, "mptsas_ioc_do_get_port_facts_reply: "
436 		    "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
437 		    ddi_get32(accessp, &factsreply->IOCLogInfo));
438 		return (DDI_FAILURE);
439 	}
440 
441 	return (DDI_SUCCESS);
442 }
443 
444 int
445 mptsas_ioc_enable_port(mptsas_t *mpt)
446 {
447 	/*
448 	 * Send enable port message
449 	 */
450 	if (mptsas_do_dma(mpt, sizeof (MPI2_PORT_ENABLE_REQUEST), 0,
451 	    mptsas_ioc_do_enable_port)) {
452 		return (DDI_FAILURE);
453 	}
454 
455 	/*
456 	 * Get enable port reply message
457 	 */
458 	if (mptsas_do_dma(mpt, sizeof (MPI2_PORT_ENABLE_REPLY), 0,
459 	    mptsas_ioc_do_enable_port_reply)) {
460 		return (DDI_FAILURE);
461 	}
462 
463 	return (DDI_SUCCESS);
464 }
465 
466 static int
467 mptsas_ioc_do_enable_port(mptsas_t *mpt, caddr_t memp, int var,
468 	ddi_acc_handle_t accessp)
469 {
470 #ifndef __lock_lint
471 	_NOTE(ARGUNUSED(var))
472 #endif
473 	pMpi2PortEnableRequest_t	enable;
474 	int				numbytes;
475 
476 	bzero(memp, sizeof (*enable));
477 	enable = (void *)memp;
478 	ddi_put8(accessp, &enable->Function, MPI2_FUNCTION_PORT_ENABLE);
479 	numbytes = sizeof (*enable);
480 
481 	/*
482 	 * Send message via handshake
483 	 */
484 	if (mptsas_send_handshake_msg(mpt, memp, numbytes, accessp)) {
485 		return (DDI_FAILURE);
486 	}
487 
488 	return (DDI_SUCCESS);
489 }
490 
491 static int
492 mptsas_ioc_do_enable_port_reply(mptsas_t *mpt, caddr_t memp, int var,
493 	ddi_acc_handle_t accessp)
494 {
495 #ifndef __lock_lint
496 	_NOTE(ARGUNUSED(var))
497 #endif
498 
499 	int			numbytes;
500 	uint_t			iocstatus;
501 	pMpi2PortEnableReply_t	portreply;
502 
503 	numbytes = sizeof (MPI2_PORT_ENABLE_REPLY);
504 	bzero(memp, numbytes);
505 	portreply = (void *)memp;
506 
507 	/*
508 	 * Get message via handshake
509 	 */
510 	if (mptsas_get_handshake_msg(mpt, memp, numbytes, accessp)) {
511 		return (DDI_FAILURE);
512 	}
513 
514 	if (iocstatus = ddi_get16(accessp, &portreply->IOCStatus)) {
515 		mptsas_log(mpt, CE_WARN, "mptsas_ioc_do_enable_port_reply: "
516 		    "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
517 		    ddi_get32(accessp, &portreply->IOCLogInfo));
518 		return (DDI_FAILURE);
519 	}
520 
521 	return (DDI_SUCCESS);
522 }
523 
524 int
525 mptsas_ioc_enable_event_notification(mptsas_t *mpt)
526 {
527 	ASSERT(mutex_owned(&mpt->m_mutex));
528 
529 	/*
530 	 * Send enable event notification message
531 	 */
532 	if (mptsas_do_dma(mpt, sizeof (MPI2_EVENT_NOTIFICATION_REQUEST), NULL,
533 	    mptsas_ioc_do_enable_event_notification)) {
534 		return (DDI_FAILURE);
535 	}
536 
537 	/*
538 	 * Get enable event reply message
539 	 */
540 	if (mptsas_do_dma(mpt, sizeof (MPI2_EVENT_NOTIFICATION_REPLY), NULL,
541 	    mptsas_ioc_do_enable_event_notification_reply)) {
542 		return (DDI_FAILURE);
543 	}
544 
545 	return (DDI_SUCCESS);
546 }
547 
548 static int
549 mptsas_ioc_do_enable_event_notification(mptsas_t *mpt, caddr_t memp, int var,
550 	ddi_acc_handle_t accessp)
551 {
552 #ifndef __lock_lint
553 	_NOTE(ARGUNUSED(var))
554 #endif
555 
556 	pMpi2EventNotificationRequest_t	event;
557 	int				numbytes;
558 
559 	bzero(memp, sizeof (*event));
560 	event = (void *)memp;
561 	ddi_put8(accessp, &event->Function, MPI2_FUNCTION_EVENT_NOTIFICATION);
562 	numbytes = sizeof (*event);
563 
564 	/*
565 	 * Send message via handshake
566 	 */
567 	if (mptsas_send_handshake_msg(mpt, memp, numbytes, accessp)) {
568 		return (DDI_FAILURE);
569 	}
570 
571 	return (DDI_SUCCESS);
572 }
573 
574 static int
575 mptsas_ioc_do_enable_event_notification_reply(mptsas_t *mpt, caddr_t memp,
576     int var, ddi_acc_handle_t accessp)
577 {
578 #ifndef __lock_lint
579 	_NOTE(ARGUNUSED(var))
580 #endif
581 	int				numbytes;
582 	uint_t				iocstatus;
583 	pMpi2EventNotificationReply_t	eventsreply;
584 
585 	numbytes = sizeof (MPI2_EVENT_NOTIFICATION_REPLY);
586 	bzero(memp, numbytes);
587 	eventsreply = (void *)memp;
588 
589 	/*
590 	 * Get message via handshake
591 	 */
592 	if (mptsas_get_handshake_msg(mpt, memp, numbytes, accessp)) {
593 		return (DDI_FAILURE);
594 	}
595 
596 	if (iocstatus = ddi_get16(accessp, &eventsreply->IOCStatus)) {
597 		mptsas_log(mpt, CE_WARN,
598 		    "mptsas_ioc_do_enable_event_notification_reply: "
599 		    "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
600 		    ddi_get32(accessp, &eventsreply->IOCLogInfo));
601 		return (DDI_FAILURE);
602 	}
603 
604 	return (DDI_SUCCESS);
605 }
606 
607 int
608 mptsas_ioc_init(mptsas_t *mpt)
609 {
610 	/*
611 	 * Send ioc init message
612 	 */
613 	if (mptsas_do_dma(mpt, sizeof (MPI2_IOC_INIT_REQUEST), NULL,
614 	    mptsas_do_ioc_init)) {
615 		return (DDI_FAILURE);
616 	}
617 
618 	/*
619 	 * Get ioc init reply message
620 	 */
621 	if (mptsas_do_dma(mpt, sizeof (MPI2_IOC_INIT_REPLY), NULL,
622 	    mptsas_do_ioc_init_reply)) {
623 		return (DDI_FAILURE);
624 	}
625 
626 	return (DDI_SUCCESS);
627 }
628 
629 static int
630 mptsas_do_ioc_init(mptsas_t *mpt, caddr_t memp, int var,
631     ddi_acc_handle_t accessp)
632 {
633 #ifndef __lock_lint
634 	_NOTE(ARGUNUSED(var))
635 #endif
636 
637 	pMpi2IOCInitRequest_t	init;
638 	int			numbytes;
639 	timespec_t		time;
640 	uint64_t		mSec;
641 
642 	bzero(memp, sizeof (*init));
643 	init = (void *)memp;
644 	ddi_put8(accessp, &init->Function, MPI2_FUNCTION_IOC_INIT);
645 	ddi_put8(accessp, &init->WhoInit, MPI2_WHOINIT_HOST_DRIVER);
646 	ddi_put16(accessp, &init->MsgVersion, MPI2_VERSION);
647 	ddi_put16(accessp, &init->HeaderVersion, MPI2_HEADER_VERSION);
648 	ddi_put16(accessp, &init->SystemRequestFrameSize,
649 	    mpt->m_req_frame_size / 4);
650 	ddi_put16(accessp, &init->ReplyDescriptorPostQueueDepth,
651 	    mpt->m_post_queue_depth);
652 	ddi_put16(accessp, &init->ReplyFreeQueueDepth,
653 	    mpt->m_free_queue_depth);
654 
655 	/*
656 	 * These addresses are set using the DMA cookie addresses from when the
657 	 * memory was allocated.  Sense buffer hi address should be 0.
658 	 */
659 	ddi_put32(accessp, &init->SenseBufferAddressHigh,
660 	    (uint32_t)(mpt->m_req_sense_dma_addr >> 32));
661 	ddi_put32(accessp, &init->SystemReplyAddressHigh,
662 	    (uint32_t)(mpt->m_reply_frame_dma_addr >> 32));
663 	ddi_put32(accessp, &init->SystemRequestFrameBaseAddress.High,
664 	    (uint32_t)(mpt->m_req_frame_dma_addr >> 32));
665 	ddi_put32(accessp, &init->SystemRequestFrameBaseAddress.Low,
666 	    (uint32_t)mpt->m_req_frame_dma_addr);
667 	ddi_put32(accessp, &init->ReplyDescriptorPostQueueAddress.High,
668 	    (uint32_t)(mpt->m_post_queue_dma_addr >> 32));
669 	ddi_put32(accessp, &init->ReplyDescriptorPostQueueAddress.Low,
670 	    (uint32_t)mpt->m_post_queue_dma_addr);
671 	ddi_put32(accessp, &init->ReplyFreeQueueAddress.High,
672 	    (uint32_t)(mpt->m_free_queue_dma_addr >> 32));
673 	ddi_put32(accessp, &init->ReplyFreeQueueAddress.Low,
674 	    (uint32_t)mpt->m_free_queue_dma_addr);
675 
676 	/*
677 	 * Fill in the timestamp with the number of milliseconds since midnight
678 	 * of January 1, 1970 UT (Greenwich Mean Time).  Time is returned in
679 	 * seconds and nanoseconds.  Translate both to milliseconds and add
680 	 * them together to get total milliseconds.
681 	 */
682 	gethrestime(&time);
683 	mSec = time.tv_sec * MILLISEC;
684 	mSec += (time.tv_nsec / MICROSEC);
685 	ddi_put32(accessp, &init->TimeStamp.High, (uint32_t)(mSec >> 32));
686 	ddi_put32(accessp, &init->TimeStamp.Low, (uint32_t)mSec);
687 
688 	numbytes = sizeof (*init);
689 
690 	/*
691 	 * Post message via handshake
692 	 */
693 	if (mptsas_send_handshake_msg(mpt, memp, numbytes, accessp)) {
694 		return (DDI_FAILURE);
695 	}
696 
697 	return (DDI_SUCCESS);
698 }
699 
700 static int
701 mptsas_do_ioc_init_reply(mptsas_t *mpt, caddr_t memp, int var,
702 		ddi_acc_handle_t accessp)
703 {
704 #ifndef __lock_lint
705 	_NOTE(ARGUNUSED(var))
706 #endif
707 
708 	pMpi2IOCInitReply_t	initreply;
709 	int			numbytes;
710 	uint_t			iocstatus;
711 
712 	numbytes = sizeof (MPI2_IOC_INIT_REPLY);
713 	bzero(memp, numbytes);
714 	initreply = (void *)memp;
715 
716 	/*
717 	 * Get reply message via handshake
718 	 */
719 	if (mptsas_get_handshake_msg(mpt, memp, numbytes, accessp)) {
720 		return (DDI_FAILURE);
721 	}
722 
723 	if (iocstatus = ddi_get16(accessp, &initreply->IOCStatus)) {
724 		mptsas_log(mpt, CE_WARN, "mptsas_do_ioc_init_reply: "
725 		    "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
726 		    ddi_get32(accessp, &initreply->IOCLogInfo));
727 		return (DDI_FAILURE);
728 	}
729 
730 	if ((ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell)) &
731 	    MPI2_IOC_STATE_OPERATIONAL) {
732 		mptsas_log(mpt, CE_NOTE,
733 		    "?mpt%d: IOC Operational.\n", mpt->m_instance);
734 	} else {
735 		return (DDI_FAILURE);
736 	}
737 
738 	return (DDI_SUCCESS);
739 }
740