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