xref: /illumos-gate/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_init.c (revision d3b5f56344d8bfcdd6cfb82446af0e5e55ad9ebe)
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 	case MPI26_MFGPAGE_DEVID_SAS3216:
141 	case MPI26_MFGPAGE_DEVID_SAS3316_1:
142 	case MPI26_MFGPAGE_DEVID_SAS3316_2:
143 	case MPI26_MFGPAGE_DEVID_SAS3316_3:
144 	case MPI26_MFGPAGE_DEVID_SAS3316_4:
145 		return ("SAS3216");
146 	case MPI26_MFGPAGE_DEVID_SAS3224:
147 	case MPI26_MFGPAGE_DEVID_SAS3324_1:
148 	case MPI26_MFGPAGE_DEVID_SAS3324_2:
149 	case MPI26_MFGPAGE_DEVID_SAS3324_3:
150 	case MPI26_MFGPAGE_DEVID_SAS3324_4:
151 		return ("SAS3224");
152 	case MPI26_MFGPAGE_DEVID_SAS3408:
153 		return ("SAS3408");
154 	case MPI26_MFGPAGE_DEVID_SAS3416:
155 		return ("SAS3416");
156 	case MPI26_MFGPAGE_DEVID_SAS3508:
157 	case MPI26_MFGPAGE_DEVID_SAS3508_1:
158 		return ("SAS3508");
159 	case MPI26_MFGPAGE_DEVID_SAS3516:
160 	case MPI26_MFGPAGE_DEVID_SAS3516_1:
161 		return ("SAS3516");
162 	case MPI26_MFGPAGE_DEVID_SAS3616:
163 		return ("SAS3616");
164 	case MPI26_MFGPAGE_DEVID_SAS3708:
165 		return ("SAS3708");
166 	case MPI26_MFGPAGE_DEVID_SAS3716:
167 		return ("SAS3716");
168 	case MPI26_MFGPAGE_DEVID_SAS4008:
169 		return ("SAS4008");
170 	default:
171 		return ("?");
172 	}
173 }
174 
175 int
176 mptsas_ioc_get_facts(mptsas_t *mpt)
177 {
178 	/*
179 	 * Send get facts messages
180 	 */
181 	if (mptsas_do_dma(mpt, sizeof (MPI2_IOC_FACTS_REQUEST), 0,
182 	    mptsas_ioc_do_get_facts)) {
183 		return (DDI_FAILURE);
184 	}
185 
186 	/*
187 	 * Get facts reply messages
188 	 */
189 	if (mptsas_do_dma(mpt, sizeof (MPI2_IOC_FACTS_REPLY), 0,
190 	    mptsas_ioc_do_get_facts_reply)) {
191 		return (DDI_FAILURE);
192 	}
193 
194 	return (DDI_SUCCESS);
195 }
196 
197 static int
198 mptsas_ioc_do_get_facts(mptsas_t *mpt, caddr_t memp, int var,
199     ddi_acc_handle_t accessp)
200 {
201 #ifndef __lock_lint
202 	_NOTE(ARGUNUSED(var))
203 #endif
204 	pMpi2IOCFactsRequest_t	facts;
205 	int			numbytes;
206 
207 	bzero(memp, sizeof (*facts));
208 	facts = (void *)memp;
209 	ddi_put8(accessp, &facts->Function, MPI2_FUNCTION_IOC_FACTS);
210 	numbytes = sizeof (*facts);
211 
212 	/*
213 	 * Post message via handshake
214 	 */
215 	if (mptsas_send_handshake_msg(mpt, memp, numbytes, accessp)) {
216 		return (DDI_FAILURE);
217 	}
218 
219 	return (DDI_SUCCESS);
220 }
221 
222 static int
223 mptsas_ioc_do_get_facts_reply(mptsas_t *mpt, caddr_t memp, int var,
224     ddi_acc_handle_t accessp)
225 {
226 #ifndef __lock_lint
227 	_NOTE(ARGUNUSED(var))
228 #endif
229 
230 	pMpi2IOCFactsReply_t	factsreply;
231 	int			numbytes;
232 	uint_t			iocstatus;
233 	char			buf[32];
234 	uint16_t		numReplyFrames;
235 	uint16_t		queueSize, queueDiff;
236 	int			simple_sge_main;
237 	int			simple_sge_next;
238 	uint32_t		capabilities;
239 	uint16_t		msgversion;
240 
241 	bzero(memp, sizeof (*factsreply));
242 	factsreply = (void *)memp;
243 	numbytes = sizeof (*factsreply);
244 
245 	/*
246 	 * get ioc facts reply message
247 	 */
248 	if (mptsas_get_handshake_msg(mpt, memp, numbytes, accessp)) {
249 		return (DDI_FAILURE);
250 	}
251 
252 	if ((iocstatus = ddi_get16(accessp, &factsreply->IOCStatus)) != 0) {
253 		mptsas_log(mpt, CE_WARN, "mptsas_ioc_do_get_facts_reply: "
254 		    "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
255 		    ddi_get32(accessp, &factsreply->IOCLogInfo));
256 		return (DDI_FAILURE);
257 	}
258 
259 	/*
260 	 * store key values from reply to mpt structure
261 	 */
262 	mpt->m_fwversion = ddi_get32(accessp, &factsreply->FWVersion.Word);
263 	mpt->m_productid = ddi_get16(accessp, &factsreply->ProductID);
264 
265 
266 	(void) sprintf(buf, "%u.%u.%u.%u",
267 	    ddi_get8(accessp, &factsreply->FWVersion.Struct.Major),
268 	    ddi_get8(accessp, &factsreply->FWVersion.Struct.Minor),
269 	    ddi_get8(accessp, &factsreply->FWVersion.Struct.Unit),
270 	    ddi_get8(accessp, &factsreply->FWVersion.Struct.Dev));
271 	mptsas_log(mpt, CE_NOTE, "?MPT Firmware version v%s (%s)\n",
272 	    buf, mptsas_devid_type_string(mpt));
273 	(void) ddi_prop_update_string(DDI_DEV_T_NONE, mpt->m_dip,
274 	    "firmware-version", buf);
275 
276 	/*
277 	 * Set up request info.
278 	 */
279 	mpt->m_max_requests = ddi_get16(accessp,
280 	    &factsreply->RequestCredit) - 1;
281 	mpt->m_req_frame_size = ddi_get16(accessp,
282 	    &factsreply->IOCRequestFrameSize) * 4;
283 
284 	/*
285 	 * Size of reply free queue should be the number of requests
286 	 * plus some additional for events (32).  Make sure number of
287 	 * reply frames is not a multiple of 16 so that the queue sizes
288 	 * are calculated correctly later to be a multiple of 16.
289 	 */
290 	mpt->m_reply_frame_size = ddi_get8(accessp,
291 	    &factsreply->ReplyFrameSize) * 4;
292 	numReplyFrames = mpt->m_max_requests + 32;
293 	if (!(numReplyFrames % 16)) {
294 		numReplyFrames--;
295 	}
296 	mpt->m_max_replies = numReplyFrames;
297 	queueSize = numReplyFrames;
298 	queueSize += 16 - (queueSize % 16);
299 	mpt->m_free_queue_depth = queueSize;
300 
301 	/*
302 	 * Size of reply descriptor post queue should be the number of
303 	 * request frames + the number of reply frames + 1 and needs to
304 	 * be a multiple of 16.  This size can be no larger than
305 	 * MaxReplyDescriptorPostQueueDepth from IOCFacts.  If the
306 	 * calculated queue size is larger than allowed, subtract a
307 	 * multiple of 16 from m_max_requests, m_max_replies, and
308 	 * m_reply_free_depth.
309 	 */
310 	queueSize = mpt->m_max_requests + numReplyFrames + 1;
311 	if (queueSize % 16) {
312 		queueSize += 16 - (queueSize % 16);
313 	}
314 	mpt->m_post_queue_depth = ddi_get16(accessp,
315 	    &factsreply->MaxReplyDescriptorPostQueueDepth);
316 	if (queueSize > mpt->m_post_queue_depth) {
317 		queueDiff = queueSize - mpt->m_post_queue_depth;
318 		if (queueDiff % 16) {
319 			queueDiff += 16 - (queueDiff % 16);
320 		}
321 		mpt->m_max_requests -= queueDiff;
322 		mpt->m_max_replies -= queueDiff;
323 		mpt->m_free_queue_depth -= queueDiff;
324 		queueSize -= queueDiff;
325 	}
326 	mpt->m_post_queue_depth = queueSize;
327 
328 	/*
329 	 * Set up max chain depth.
330 	 */
331 	mpt->m_max_chain_depth = ddi_get8(accessp,
332 	    &factsreply->MaxChainDepth);
333 	mpt->m_ioc_capabilities = ddi_get32(accessp,
334 	    &factsreply->IOCCapabilities);
335 
336 	/*
337 	 * Set flag to check for SAS3 support.
338 	 */
339 	msgversion = ddi_get16(accessp, &factsreply->MsgVersion);
340 	if (msgversion >= MPI2_VERSION_02_05) {
341 		mptsas_log(mpt, CE_NOTE, "?mpt_sas%d SAS 3 Supported\n",
342 		    mpt->m_instance);
343 		mpt->m_MPI25 = TRUE;
344 	} else {
345 		mptsas_log(mpt, CE_NOTE, "?mpt_sas%d MPI Version 0x%x\n",
346 		    mpt->m_instance, msgversion);
347 	}
348 
349 	/*
350 	 * Calculate max frames per request based on DMA S/G length.
351 	 */
352 	simple_sge_main = MPTSAS_MAX_FRAME_SGES64(mpt) - 1;
353 	simple_sge_next = mpt->m_req_frame_size / MPTSAS_SGE_SIZE(mpt) - 1;
354 
355 	mpt->m_max_request_frames = (MPTSAS_MAX_DMA_SEGS -
356 	    simple_sge_main) / simple_sge_next + 1;
357 	if (((MPTSAS_MAX_DMA_SEGS - simple_sge_main) %
358 	    simple_sge_next) > 1) {
359 		mpt->m_max_request_frames++;
360 	}
361 
362 	/*
363 	 * Check if controller supports FW diag buffers and set flag to enable
364 	 * each type.
365 	 */
366 	capabilities = ddi_get32(accessp, &factsreply->IOCCapabilities);
367 	if (capabilities & MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER) {
368 		mpt->m_fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_TRACE].enabled =
369 		    TRUE;
370 	}
371 	if (capabilities & MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER) {
372 		mpt->m_fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_SNAPSHOT].
373 		    enabled = TRUE;
374 	}
375 	if (capabilities & MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER) {
376 		mpt->m_fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_EXTENDED].
377 		    enabled = TRUE;
378 	}
379 
380 	/*
381 	 * Check if controller supports replaying events when issuing Message
382 	 * Unit Reset and set flag to enable MUR.
383 	 */
384 	if (capabilities & MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY) {
385 		mpt->m_event_replay = TRUE;
386 	}
387 
388 	/*
389 	 * Check if controller supports IR.
390 	 */
391 	if (capabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) {
392 		mpt->m_ir_capable = TRUE;
393 	}
394 
395 	return (DDI_SUCCESS);
396 }
397 
398 int
399 mptsas_ioc_get_port_facts(mptsas_t *mpt, int port)
400 {
401 	/*
402 	 * Send get port facts message
403 	 */
404 	if (mptsas_do_dma(mpt, sizeof (MPI2_PORT_FACTS_REQUEST), port,
405 	    mptsas_ioc_do_get_port_facts)) {
406 		return (DDI_FAILURE);
407 	}
408 
409 	/*
410 	 * Get port facts reply message
411 	 */
412 	if (mptsas_do_dma(mpt, sizeof (MPI2_PORT_FACTS_REPLY), port,
413 	    mptsas_ioc_do_get_port_facts_reply)) {
414 		return (DDI_FAILURE);
415 	}
416 
417 	return (DDI_SUCCESS);
418 }
419 
420 static int
421 mptsas_ioc_do_get_port_facts(mptsas_t *mpt, caddr_t memp, int var,
422     ddi_acc_handle_t accessp)
423 {
424 	pMpi2PortFactsRequest_t	facts;
425 	int			numbytes;
426 
427 	bzero(memp, sizeof (*facts));
428 	facts = (void *)memp;
429 	ddi_put8(accessp, &facts->Function, MPI2_FUNCTION_PORT_FACTS);
430 	ddi_put8(accessp, &facts->PortNumber, var);
431 	numbytes = sizeof (*facts);
432 
433 	/*
434 	 * Send port facts message via handshake
435 	 */
436 	if (mptsas_send_handshake_msg(mpt, memp, numbytes, accessp)) {
437 		return (DDI_FAILURE);
438 	}
439 
440 	return (DDI_SUCCESS);
441 }
442 
443 static int
444 mptsas_ioc_do_get_port_facts_reply(mptsas_t *mpt, caddr_t memp, int var,
445     ddi_acc_handle_t accessp)
446 {
447 #ifndef __lock_lint
448 	_NOTE(ARGUNUSED(var))
449 #endif
450 	pMpi2PortFactsReply_t	factsreply;
451 	int			numbytes;
452 	uint_t			iocstatus;
453 
454 	bzero(memp, sizeof (*factsreply));
455 	factsreply = (void *)memp;
456 	numbytes = sizeof (*factsreply);
457 
458 	/*
459 	 * Get port facts reply message via handshake
460 	 */
461 	if (mptsas_get_handshake_msg(mpt, memp, numbytes, accessp)) {
462 		return (DDI_FAILURE);
463 	}
464 
465 	if ((iocstatus = ddi_get16(accessp, &factsreply->IOCStatus)) != 0) {
466 		mptsas_log(mpt, CE_WARN, "mptsas_ioc_do_get_port_facts_reply: "
467 		    "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
468 		    ddi_get32(accessp, &factsreply->IOCLogInfo));
469 		return (DDI_FAILURE);
470 	}
471 
472 	return (DDI_SUCCESS);
473 }
474 
475 int
476 mptsas_ioc_enable_port(mptsas_t *mpt)
477 {
478 	/*
479 	 * Send enable port message
480 	 */
481 	if (mptsas_do_dma(mpt, sizeof (MPI2_PORT_ENABLE_REQUEST), 0,
482 	    mptsas_ioc_do_enable_port)) {
483 		return (DDI_FAILURE);
484 	}
485 
486 	/*
487 	 * Get enable port reply message
488 	 */
489 	if (mptsas_do_dma(mpt, sizeof (MPI2_PORT_ENABLE_REPLY), 0,
490 	    mptsas_ioc_do_enable_port_reply)) {
491 		return (DDI_FAILURE);
492 	}
493 
494 	return (DDI_SUCCESS);
495 }
496 
497 static int
498 mptsas_ioc_do_enable_port(mptsas_t *mpt, caddr_t memp, int var,
499     ddi_acc_handle_t accessp)
500 {
501 #ifndef __lock_lint
502 	_NOTE(ARGUNUSED(var))
503 #endif
504 	pMpi2PortEnableRequest_t	enable;
505 	int				numbytes;
506 
507 	bzero(memp, sizeof (*enable));
508 	enable = (void *)memp;
509 	ddi_put8(accessp, &enable->Function, MPI2_FUNCTION_PORT_ENABLE);
510 	numbytes = sizeof (*enable);
511 
512 	/*
513 	 * Send message via handshake
514 	 */
515 	if (mptsas_send_handshake_msg(mpt, memp, numbytes, accessp)) {
516 		return (DDI_FAILURE);
517 	}
518 
519 	return (DDI_SUCCESS);
520 }
521 
522 static int
523 mptsas_ioc_do_enable_port_reply(mptsas_t *mpt, caddr_t memp, int var,
524     ddi_acc_handle_t accessp)
525 {
526 #ifndef __lock_lint
527 	_NOTE(ARGUNUSED(var))
528 #endif
529 
530 	int			numbytes;
531 	uint_t			iocstatus;
532 	pMpi2PortEnableReply_t	portreply;
533 
534 	numbytes = sizeof (MPI2_PORT_ENABLE_REPLY);
535 	bzero(memp, numbytes);
536 	portreply = (void *)memp;
537 
538 	/*
539 	 * Get message via handshake
540 	 */
541 	if (mptsas_get_handshake_msg(mpt, memp, numbytes, accessp)) {
542 		return (DDI_FAILURE);
543 	}
544 
545 	if ((iocstatus = ddi_get16(accessp, &portreply->IOCStatus)) != 0) {
546 		mptsas_log(mpt, CE_WARN, "mptsas_ioc_do_enable_port_reply: "
547 		    "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
548 		    ddi_get32(accessp, &portreply->IOCLogInfo));
549 		return (DDI_FAILURE);
550 	}
551 
552 	return (DDI_SUCCESS);
553 }
554 
555 int
556 mptsas_ioc_enable_event_notification(mptsas_t *mpt)
557 {
558 	ASSERT(mutex_owned(&mpt->m_mutex));
559 
560 	/*
561 	 * Send enable event notification message
562 	 */
563 	if (mptsas_do_dma(mpt, sizeof (MPI2_EVENT_NOTIFICATION_REQUEST), 0,
564 	    mptsas_ioc_do_enable_event_notification)) {
565 		return (DDI_FAILURE);
566 	}
567 
568 	/*
569 	 * Get enable event reply message
570 	 */
571 	if (mptsas_do_dma(mpt, sizeof (MPI2_EVENT_NOTIFICATION_REPLY), 0,
572 	    mptsas_ioc_do_enable_event_notification_reply)) {
573 		return (DDI_FAILURE);
574 	}
575 
576 	return (DDI_SUCCESS);
577 }
578 
579 static int
580 mptsas_ioc_do_enable_event_notification(mptsas_t *mpt, caddr_t memp, int var,
581     ddi_acc_handle_t accessp)
582 {
583 #ifndef __lock_lint
584 	_NOTE(ARGUNUSED(var))
585 #endif
586 
587 	pMpi2EventNotificationRequest_t	event;
588 	int				numbytes;
589 
590 	bzero(memp, sizeof (*event));
591 	event = (void *)memp;
592 	ddi_put8(accessp, &event->Function, MPI2_FUNCTION_EVENT_NOTIFICATION);
593 	numbytes = sizeof (*event);
594 
595 	/*
596 	 * Send message via handshake
597 	 */
598 	if (mptsas_send_handshake_msg(mpt, memp, numbytes, accessp)) {
599 		return (DDI_FAILURE);
600 	}
601 
602 	return (DDI_SUCCESS);
603 }
604 
605 static int
606 mptsas_ioc_do_enable_event_notification_reply(mptsas_t *mpt, caddr_t memp,
607     int var, ddi_acc_handle_t accessp)
608 {
609 #ifndef __lock_lint
610 	_NOTE(ARGUNUSED(var))
611 #endif
612 	int				numbytes;
613 	uint_t				iocstatus;
614 	pMpi2EventNotificationReply_t	eventsreply;
615 
616 	numbytes = sizeof (MPI2_EVENT_NOTIFICATION_REPLY);
617 	bzero(memp, numbytes);
618 	eventsreply = (void *)memp;
619 
620 	/*
621 	 * Get message via handshake
622 	 */
623 	if (mptsas_get_handshake_msg(mpt, memp, numbytes, accessp)) {
624 		return (DDI_FAILURE);
625 	}
626 
627 	if ((iocstatus = ddi_get16(accessp, &eventsreply->IOCStatus)) != 0) {
628 		mptsas_log(mpt, CE_WARN,
629 		    "mptsas_ioc_do_enable_event_notification_reply: "
630 		    "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
631 		    ddi_get32(accessp, &eventsreply->IOCLogInfo));
632 		return (DDI_FAILURE);
633 	}
634 
635 	return (DDI_SUCCESS);
636 }
637 
638 int
639 mptsas_ioc_init(mptsas_t *mpt)
640 {
641 	/*
642 	 * Send ioc init message
643 	 */
644 	if (mptsas_do_dma(mpt, sizeof (MPI2_IOC_INIT_REQUEST), 0,
645 	    mptsas_do_ioc_init)) {
646 		return (DDI_FAILURE);
647 	}
648 
649 	/*
650 	 * Get ioc init reply message
651 	 */
652 	if (mptsas_do_dma(mpt, sizeof (MPI2_IOC_INIT_REPLY), 0,
653 	    mptsas_do_ioc_init_reply)) {
654 		return (DDI_FAILURE);
655 	}
656 
657 	return (DDI_SUCCESS);
658 }
659 
660 static int
661 mptsas_do_ioc_init(mptsas_t *mpt, caddr_t memp, int var,
662     ddi_acc_handle_t accessp)
663 {
664 #ifndef __lock_lint
665 	_NOTE(ARGUNUSED(var))
666 #endif
667 
668 	pMpi2IOCInitRequest_t	init;
669 	int			numbytes;
670 	timespec_t		time;
671 	uint64_t		mSec;
672 
673 	bzero(memp, sizeof (*init));
674 	init = (void *)memp;
675 	ddi_put8(accessp, &init->Function, MPI2_FUNCTION_IOC_INIT);
676 	ddi_put8(accessp, &init->WhoInit, MPI2_WHOINIT_HOST_DRIVER);
677 	ddi_put16(accessp, &init->MsgVersion, MPI2_VERSION);
678 	ddi_put16(accessp, &init->HeaderVersion, MPI2_HEADER_VERSION);
679 	ddi_put16(accessp, &init->SystemRequestFrameSize,
680 	    mpt->m_req_frame_size / 4);
681 	ddi_put16(accessp, &init->ReplyDescriptorPostQueueDepth,
682 	    mpt->m_post_queue_depth);
683 	ddi_put16(accessp, &init->ReplyFreeQueueDepth,
684 	    mpt->m_free_queue_depth);
685 
686 	/*
687 	 * These addresses are set using the DMA cookie addresses from when the
688 	 * memory was allocated.  Sense buffer hi address should be 0.
689 	 */
690 	ddi_put32(accessp, &init->SenseBufferAddressHigh,
691 	    (uint32_t)(mpt->m_req_sense_dma_addr >> 32));
692 	ddi_put32(accessp, &init->SystemReplyAddressHigh,
693 	    (uint32_t)(mpt->m_reply_frame_dma_addr >> 32));
694 	ddi_put32(accessp, &init->SystemRequestFrameBaseAddress.High,
695 	    (uint32_t)(mpt->m_req_frame_dma_addr >> 32));
696 	ddi_put32(accessp, &init->SystemRequestFrameBaseAddress.Low,
697 	    (uint32_t)mpt->m_req_frame_dma_addr);
698 	ddi_put32(accessp, &init->ReplyDescriptorPostQueueAddress.High,
699 	    (uint32_t)(mpt->m_post_queue_dma_addr >> 32));
700 	ddi_put32(accessp, &init->ReplyDescriptorPostQueueAddress.Low,
701 	    (uint32_t)mpt->m_post_queue_dma_addr);
702 	ddi_put32(accessp, &init->ReplyFreeQueueAddress.High,
703 	    (uint32_t)(mpt->m_free_queue_dma_addr >> 32));
704 	ddi_put32(accessp, &init->ReplyFreeQueueAddress.Low,
705 	    (uint32_t)mpt->m_free_queue_dma_addr);
706 
707 	/*
708 	 * Fill in the timestamp with the number of milliseconds since midnight
709 	 * of January 1, 1970 UT (Greenwich Mean Time).  Time is returned in
710 	 * seconds and nanoseconds.  Translate both to milliseconds and add
711 	 * them together to get total milliseconds.
712 	 */
713 	gethrestime(&time);
714 	mSec = time.tv_sec * MILLISEC;
715 	mSec += (time.tv_nsec / MICROSEC);
716 	ddi_put32(accessp, &init->TimeStamp.High, (uint32_t)(mSec >> 32));
717 	ddi_put32(accessp, &init->TimeStamp.Low, (uint32_t)mSec);
718 
719 	numbytes = sizeof (*init);
720 
721 	/*
722 	 * Post message via handshake
723 	 */
724 	if (mptsas_send_handshake_msg(mpt, memp, numbytes, accessp)) {
725 		return (DDI_FAILURE);
726 	}
727 
728 	return (DDI_SUCCESS);
729 }
730 
731 static int
732 mptsas_do_ioc_init_reply(mptsas_t *mpt, caddr_t memp, int var,
733     ddi_acc_handle_t accessp)
734 {
735 #ifndef __lock_lint
736 	_NOTE(ARGUNUSED(var))
737 #endif
738 
739 	pMpi2IOCInitReply_t	initreply;
740 	int			numbytes;
741 	uint_t			iocstatus;
742 
743 	numbytes = sizeof (MPI2_IOC_INIT_REPLY);
744 	bzero(memp, numbytes);
745 	initreply = (void *)memp;
746 
747 	/*
748 	 * Get reply message via handshake
749 	 */
750 	if (mptsas_get_handshake_msg(mpt, memp, numbytes, accessp)) {
751 		return (DDI_FAILURE);
752 	}
753 
754 	if ((iocstatus = ddi_get16(accessp, &initreply->IOCStatus)) != 0) {
755 		mptsas_log(mpt, CE_WARN, "mptsas_do_ioc_init_reply: "
756 		    "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
757 		    ddi_get32(accessp, &initreply->IOCLogInfo));
758 		return (DDI_FAILURE);
759 	}
760 
761 	if ((ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell)) &
762 	    MPI2_IOC_STATE_OPERATIONAL) {
763 		mptsas_log(mpt, CE_NOTE,
764 		    "?mpt%d: IOC Operational.\n", mpt->m_instance);
765 	} else {
766 		return (DDI_FAILURE);
767 	}
768 
769 	return (DDI_SUCCESS);
770 }
771