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