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