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