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 */
26
27 /*
28 * Copyright (c) 2000 to 2009, LSI Corporation.
29 * All rights reserved.
30 *
31 * Redistribution and use in source and binary forms of all code within
32 * this file that is exclusively owned by LSI, with or without
33 * modification, is permitted provided that, in addition to the CDDL 1.0
34 * License requirements, the following conditions are met:
35 *
36 * Neither the name of the author nor the names of its contributors may be
37 * used to endorse or promote products derived from this software without
38 * specific prior written permission.
39 *
40 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
41 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
42 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
43 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
44 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
50 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
51 * DAMAGE.
52 */
53
54 /*
55 * mptsas_init - This file contains all the functions used to initialize
56 * MPT2.0 based hardware.
57 */
58
59 #if defined(lint) || defined(DEBUG)
60 #define MPTSAS_DEBUG
61 #endif
62
63 /*
64 * standard header files
65 */
66 #include <sys/note.h>
67 #include <sys/scsi/scsi.h>
68
69 #pragma pack(1)
70 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h>
71 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2.h>
72 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h>
73 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h>
74 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_ioc.h>
75 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_tool.h>
76 #pragma pack()
77 /*
78 * private header files.
79 */
80 #include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
81
82 static int mptsas_ioc_do_get_facts(mptsas_t *mpt, caddr_t memp, int var,
83 ddi_acc_handle_t accessp);
84 static int mptsas_ioc_do_get_facts_reply(mptsas_t *mpt, caddr_t memp, int var,
85 ddi_acc_handle_t accessp);
86 static int mptsas_ioc_do_get_port_facts(mptsas_t *mpt, caddr_t memp, int var,
87 ddi_acc_handle_t accessp);
88 static int mptsas_ioc_do_get_port_facts_reply(mptsas_t *mpt, caddr_t memp,
89 int var, ddi_acc_handle_t accessp);
90 static int mptsas_ioc_do_enable_port(mptsas_t *mpt, caddr_t memp, int var,
91 ddi_acc_handle_t accessp);
92 static int mptsas_ioc_do_enable_port_reply(mptsas_t *mpt, caddr_t memp, int var,
93 ddi_acc_handle_t accessp);
94 static int mptsas_ioc_do_enable_event_notification(mptsas_t *mpt, caddr_t memp,
95 int var, ddi_acc_handle_t accessp);
96 static int mptsas_ioc_do_enable_event_notification_reply(mptsas_t *mpt,
97 caddr_t memp, int var, ddi_acc_handle_t accessp);
98 static int mptsas_do_ioc_init(mptsas_t *mpt, caddr_t memp, int var,
99 ddi_acc_handle_t accessp);
100 static int mptsas_do_ioc_init_reply(mptsas_t *mpt, caddr_t memp, int var,
101 ddi_acc_handle_t accessp);
102
103 static const char *
104 mptsas_product_type_string(mptsas_t *mpt)
105 {
106 switch (mpt->m_productid & MPI2_FW_HEADER_PID_PROD_MASK) {
107
108 case MPI2_FW_HEADER_PID_PROD_A:
109 return ("A");
110 default:
111 return ("?");
112 }
113 }
114
115 int
116 mptsas_ioc_get_facts(mptsas_t *mpt)
117 {
118 /*
119 * Send get facts messages
120 */
121 if (mptsas_do_dma(mpt, sizeof (MPI2_IOC_FACTS_REQUEST), NULL,
122 mptsas_ioc_do_get_facts)) {
123 return (DDI_FAILURE);
124 }
125
126 /*
127 * Get facts reply messages
128 */
129 if (mptsas_do_dma(mpt, sizeof (MPI2_IOC_FACTS_REPLY), NULL,
159 return (DDI_SUCCESS);
160 }
161
162 static int
163 mptsas_ioc_do_get_facts_reply(mptsas_t *mpt, caddr_t memp, int var,
164 ddi_acc_handle_t accessp)
165 {
166 #ifndef __lock_lint
167 _NOTE(ARGUNUSED(var))
168 #endif
169
170 pMpi2IOCFactsReply_t factsreply;
171 int numbytes;
172 uint_t iocstatus;
173 char buf[32];
174 uint16_t numReplyFrames;
175 uint16_t queueSize, queueDiff;
176 int simple_sge_main;
177 int simple_sge_next;
178 uint32_t capabilities;
179
180 bzero(memp, sizeof (*factsreply));
181 factsreply = (void *)memp;
182 numbytes = sizeof (*factsreply);
183
184 /*
185 * get ioc facts reply message
186 */
187 if (mptsas_get_handshake_msg(mpt, memp, numbytes, accessp)) {
188 return (DDI_FAILURE);
189 }
190
191 if (iocstatus = ddi_get16(accessp, &factsreply->IOCStatus)) {
192 mptsas_log(mpt, CE_WARN, "mptsas_ioc_do_get_facts_reply: "
193 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
194 ddi_get32(accessp, &factsreply->IOCLogInfo));
195 return (DDI_FAILURE);
196 }
197
198 /*
199 * store key values from reply to mpt structure
200 */
201 mpt->m_fwversion = ddi_get32(accessp, &factsreply->FWVersion.Word);
202 mpt->m_productid = ddi_get16(accessp, &factsreply->ProductID);
203
204
205 (void) sprintf(buf, "%u.%u.%u.%u",
206 ddi_get8(accessp, &factsreply->FWVersion.Struct.Major),
207 ddi_get8(accessp, &factsreply->FWVersion.Struct.Minor),
208 ddi_get8(accessp, &factsreply->FWVersion.Struct.Unit),
209 ddi_get8(accessp, &factsreply->FWVersion.Struct.Dev));
210 mptsas_log(mpt, CE_NOTE, "?mpt%d Firmware version v%s (%s)\n",
211 mpt->m_instance, buf, mptsas_product_type_string(mpt));
212 (void) ddi_prop_update_string(DDI_DEV_T_NONE, mpt->m_dip,
213 "firmware-version", buf);
214
215 /*
216 * Set up request info.
217 */
218 mpt->m_max_requests = ddi_get16(accessp,
219 &factsreply->RequestCredit) - 1;
220 mpt->m_req_frame_size = ddi_get16(accessp,
221 &factsreply->IOCRequestFrameSize) * 4;
222
223 /*
224 * Size of reply free queue should be the number of requests
225 * plus some additional for events (32). Make sure number of
226 * reply frames is not a multiple of 16 so that the queue sizes
227 * are calculated correctly later to be a multiple of 16.
228 */
229 mpt->m_reply_frame_size = ddi_get8(accessp,
230 &factsreply->ReplyFrameSize) * 4;
231 numReplyFrames = mpt->m_max_requests + 32;
232 if (!(numReplyFrames % 16)) {
233 numReplyFrames--;
234 }
235 mpt->m_max_replies = numReplyFrames;
236 queueSize = numReplyFrames;
237 queueSize += 16 - (queueSize % 16);
238 mpt->m_free_queue_depth = queueSize;
239
240 /*
241 * Size of reply descriptor post queue should be the number of
242 * request frames + the number of reply frames + 1 and needs to
243 * be a multiple of 16. This size can be no larger than
244 * MaxReplyDescriptorPostQueueDepth from IOCFacts. If the
245 * calculated queue size is larger than allowed, subtract a
246 * multiple of 16 from m_max_requests, m_max_replies, and
247 * m_reply_free_depth.
248 */
249 queueSize = mpt->m_max_requests + numReplyFrames + 1;
250 if (queueSize % 16) {
251 queueSize += 16 - (queueSize % 16);
252 }
253 mpt->m_post_queue_depth = ddi_get16(accessp,
254 &factsreply->MaxReplyDescriptorPostQueueDepth);
255 if (queueSize > mpt->m_post_queue_depth) {
256 queueDiff = queueSize - mpt->m_post_queue_depth;
257 if (queueDiff % 16) {
258 queueDiff += 16 - (queueDiff % 16);
259 }
260 mpt->m_max_requests -= queueDiff;
261 mpt->m_max_replies -= queueDiff;
262 mpt->m_free_queue_depth -= queueDiff;
263 queueSize -= queueDiff;
264 }
265 mpt->m_post_queue_depth = queueSize;
266
267 /*
268 * Set up max chain depth.
269 */
270 mpt->m_max_chain_depth = ddi_get8(accessp,
271 &factsreply->MaxChainDepth);
272 mpt->m_ioc_capabilities = ddi_get32(accessp,
273 &factsreply->IOCCapabilities);
274
275 /*
276 * Calculate max frames per request based on DMA S/G length.
277 */
278 simple_sge_main = MPTSAS_MAX_FRAME_SGES64(mpt) - 1;
279 simple_sge_next = mpt->m_req_frame_size /
280 sizeof (MPI2_SGE_SIMPLE64) - 1;
281
282 mpt->m_max_request_frames = (MPTSAS_MAX_DMA_SEGS -
283 simple_sge_main) / simple_sge_next + 1;
284 if (((MPTSAS_MAX_DMA_SEGS - simple_sge_main) %
285 simple_sge_next) > 1) {
286 mpt->m_max_request_frames++;
287 }
288
289 /*
290 * Check if controller supports FW diag buffers and set flag to enable
291 * each type.
292 */
293 capabilities = ddi_get32(accessp, &factsreply->IOCCapabilities);
294 if (capabilities & MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER) {
295 mpt->m_fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_TRACE].enabled =
296 TRUE;
297 }
298 if (capabilities & MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER) {
299 mpt->m_fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_SNAPSHOT].
300 enabled = TRUE;
301 }
302 if (capabilities & MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER) {
303 mpt->m_fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_EXTENDED].
304 enabled = TRUE;
305 }
306
307 /*
308 * Check if controller supports replaying events when issuing Message
309 * Unit Reset and set flag to enable MUR.
310 */
311 if (capabilities & MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY) {
312 mpt->m_event_replay = TRUE;
313 }
586
587 static int
588 mptsas_do_ioc_init(mptsas_t *mpt, caddr_t memp, int var,
589 ddi_acc_handle_t accessp)
590 {
591 #ifndef __lock_lint
592 _NOTE(ARGUNUSED(var))
593 #endif
594
595 pMpi2IOCInitRequest_t init;
596 int numbytes;
597 timespec_t time;
598 uint64_t mSec;
599
600 bzero(memp, sizeof (*init));
601 init = (void *)memp;
602 ddi_put8(accessp, &init->Function, MPI2_FUNCTION_IOC_INIT);
603 ddi_put8(accessp, &init->WhoInit, MPI2_WHOINIT_HOST_DRIVER);
604 ddi_put16(accessp, &init->MsgVersion, MPI2_VERSION);
605 ddi_put16(accessp, &init->HeaderVersion, MPI2_HEADER_VERSION);
606 ddi_put16(accessp, &init->SystemRequestFrameSize,
607 mpt->m_req_frame_size / 4);
608 ddi_put16(accessp, &init->ReplyDescriptorPostQueueDepth,
609 mpt->m_post_queue_depth);
610 ddi_put16(accessp, &init->ReplyFreeQueueDepth,
611 mpt->m_free_queue_depth);
612
613 /*
614 * These addresses are set using the DMA cookie addresses from when the
615 * memory was allocated. Sense buffer hi address should be 0.
616 */
617 ddi_put32(accessp, &init->SenseBufferAddressHigh, 0);
618 ddi_put32(accessp, &init->SystemReplyAddressHigh,
619 (uint32_t)(mpt->m_reply_frame_dma_addr >> 32));
620 ddi_put32(accessp, &init->SystemRequestFrameBaseAddress.High,
621 (uint32_t)(mpt->m_req_frame_dma_addr >> 32));
622 ddi_put32(accessp, &init->SystemRequestFrameBaseAddress.Low,
623 (uint32_t)mpt->m_req_frame_dma_addr);
624 ddi_put32(accessp, &init->ReplyDescriptorPostQueueAddress.High,
625 (uint32_t)(mpt->m_post_queue_dma_addr >> 32));
626 ddi_put32(accessp, &init->ReplyDescriptorPostQueueAddress.Low,
627 (uint32_t)mpt->m_post_queue_dma_addr);
628 ddi_put32(accessp, &init->ReplyFreeQueueAddress.High,
629 (uint32_t)(mpt->m_free_queue_dma_addr >> 32));
630 ddi_put32(accessp, &init->ReplyFreeQueueAddress.Low,
631 (uint32_t)mpt->m_free_queue_dma_addr);
632
633 /*
634 * Fill in the timestamp with the number of milliseconds since midnight
635 * of January 1, 1970 UT (Greenwich Mean Time). Time is returned in
636 * seconds and nanoseconds. Translate both to milliseconds and add
637 * them together to get total milliseconds.
|
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,
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,
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 }
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.
|