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