Print this page
7813 mpt_sas does not like concurrent HBA resets
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_impl.c
+++ new/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_impl.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
25 25 * Copyright 2014 OmniTI Computer Consulting, Inc. All rights reserved.
26 26 * Copyright (c) 2014, Tegile Systems Inc. All rights reserved.
27 27 */
28 28
29 29 /*
30 30 * Copyright (c) 2000 to 2010, LSI Corporation.
31 31 * All rights reserved.
32 32 *
33 33 * Redistribution and use in source and binary forms of all code within
34 34 * this file that is exclusively owned by LSI, with or without
35 35 * modification, is permitted provided that, in addition to the CDDL 1.0
36 36 * License requirements, the following conditions are met:
37 37 *
38 38 * Neither the name of the author nor the names of its contributors may be
39 39 * used to endorse or promote products derived from this software without
40 40 * specific prior written permission.
41 41 *
42 42 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
43 43 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
44 44 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
45 45 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
46 46 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
47 47 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
48 48 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
49 49 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
50 50 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
51 51 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
52 52 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
53 53 * DAMAGE.
54 54 */
55 55
56 56 /*
57 57 * mptsas_impl - This file contains all the basic functions for communicating
58 58 * to MPT based hardware.
59 59 */
60 60
61 61 #if defined(lint) || defined(DEBUG)
62 62 #define MPTSAS_DEBUG
63 63 #endif
64 64
65 65 /*
66 66 * standard header files
67 67 */
68 68 #include <sys/note.h>
69 69 #include <sys/scsi/scsi.h>
70 70 #include <sys/pci.h>
71 71
72 72 #pragma pack(1)
73 73 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h>
74 74 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2.h>
75 75 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h>
76 76 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h>
77 77 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_ioc.h>
78 78 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_sas.h>
79 79 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_tool.h>
80 80 #pragma pack()
81 81
82 82 /*
83 83 * private header files.
84 84 */
85 85 #include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
86 86 #include <sys/scsi/adapters/mpt_sas/mptsas_smhba.h>
87 87
88 88 /*
89 89 * FMA header files.
90 90 */
91 91 #include <sys/fm/io/ddi.h>
92 92
93 93 /*
94 94 * prototypes
95 95 */
96 96 static void mptsas_ioc_event_cmdq_add(mptsas_t *mpt, m_event_struct_t *cmd);
97 97 static void mptsas_ioc_event_cmdq_delete(mptsas_t *mpt, m_event_struct_t *cmd);
98 98 static m_event_struct_t *mptsas_ioc_event_find_by_cmd(mptsas_t *mpt,
99 99 struct mptsas_cmd *cmd);
100 100
101 101 /*
102 102 * add ioc evnet cmd into the queue
103 103 */
104 104 static void
105 105 mptsas_ioc_event_cmdq_add(mptsas_t *mpt, m_event_struct_t *cmd)
106 106 {
107 107 if ((cmd->m_event_linkp = mpt->m_ioc_event_cmdq) == NULL) {
108 108 mpt->m_ioc_event_cmdtail = &cmd->m_event_linkp;
109 109 mpt->m_ioc_event_cmdq = cmd;
110 110 } else {
111 111 cmd->m_event_linkp = NULL;
112 112 *(mpt->m_ioc_event_cmdtail) = cmd;
113 113 mpt->m_ioc_event_cmdtail = &cmd->m_event_linkp;
114 114 }
115 115 }
116 116
117 117 /*
118 118 * remove specified cmd from the ioc event queue
119 119 */
120 120 static void
121 121 mptsas_ioc_event_cmdq_delete(mptsas_t *mpt, m_event_struct_t *cmd)
122 122 {
123 123 m_event_struct_t *prev = mpt->m_ioc_event_cmdq;
124 124 if (prev == cmd) {
125 125 if ((mpt->m_ioc_event_cmdq = cmd->m_event_linkp) == NULL) {
126 126 mpt->m_ioc_event_cmdtail = &mpt->m_ioc_event_cmdq;
127 127 }
128 128 cmd->m_event_linkp = NULL;
129 129 return;
130 130 }
131 131 while (prev != NULL) {
132 132 if (prev->m_event_linkp == cmd) {
133 133 prev->m_event_linkp = cmd->m_event_linkp;
134 134 if (cmd->m_event_linkp == NULL) {
135 135 mpt->m_ioc_event_cmdtail = &prev->m_event_linkp;
136 136 }
137 137
138 138 cmd->m_event_linkp = NULL;
139 139 return;
140 140 }
141 141 prev = prev->m_event_linkp;
142 142 }
143 143 }
144 144
145 145 static m_event_struct_t *
146 146 mptsas_ioc_event_find_by_cmd(mptsas_t *mpt, struct mptsas_cmd *cmd)
147 147 {
148 148 m_event_struct_t *ioc_cmd = NULL;
149 149
150 150 ioc_cmd = mpt->m_ioc_event_cmdq;
151 151 while (ioc_cmd != NULL) {
152 152 if (&(ioc_cmd->m_event_cmd) == cmd) {
153 153 return (ioc_cmd);
154 154 }
155 155 ioc_cmd = ioc_cmd->m_event_linkp;
156 156 }
157 157 ioc_cmd = NULL;
158 158 return (ioc_cmd);
159 159 }
160 160
161 161 void
162 162 mptsas_destroy_ioc_event_cmd(mptsas_t *mpt)
163 163 {
164 164 m_event_struct_t *ioc_cmd = NULL;
165 165 m_event_struct_t *ioc_cmd_tmp = NULL;
166 166 ioc_cmd = mpt->m_ioc_event_cmdq;
167 167
168 168 /*
169 169 * because the IOC event queue is resource of per instance for driver,
170 170 * it's not only ACK event commands used it, but also some others used
171 171 * it. We need destroy all ACK event commands when IOC reset, but can't
172 172 * disturb others.So we use filter to clear the ACK event cmd in ioc
173 173 * event queue, and other requests should be reserved, and they would
174 174 * be free by its owner.
175 175 */
176 176 while (ioc_cmd != NULL) {
177 177 if (ioc_cmd->m_event_cmd.cmd_flags & CFLAG_CMDACK) {
178 178 NDBG20(("destroy!! remove Ack Flag ioc_cmd\n"));
179 179 if ((mpt->m_ioc_event_cmdq =
180 180 ioc_cmd->m_event_linkp) == NULL)
181 181 mpt->m_ioc_event_cmdtail =
182 182 &mpt->m_ioc_event_cmdq;
183 183 ioc_cmd_tmp = ioc_cmd;
184 184 ioc_cmd = ioc_cmd->m_event_linkp;
185 185 kmem_free(ioc_cmd_tmp, M_EVENT_STRUCT_SIZE);
186 186 } else {
187 187 /*
188 188 * it's not ack cmd, so continue to check next one
189 189 */
190 190
191 191 NDBG20(("destroy!! it's not Ack Flag, continue\n"));
192 192 ioc_cmd = ioc_cmd->m_event_linkp;
193 193 }
194 194
195 195 }
196 196 }
197 197
198 198 void
199 199 mptsas_start_config_page_access(mptsas_t *mpt, mptsas_cmd_t *cmd)
200 200 {
201 201 pMpi2ConfigRequest_t request;
202 202 pMpi2SGESimple64_t sge;
203 203 struct scsi_pkt *pkt = cmd->cmd_pkt;
204 204 mptsas_config_request_t *config = pkt->pkt_ha_private;
205 205 uint8_t direction;
206 206 uint32_t length, flagslength;
207 207 uint64_t request_desc;
208 208
209 209 ASSERT(mutex_owned(&mpt->m_mutex));
210 210
211 211 /*
212 212 * Point to the correct message and clear it as well as the global
213 213 * config page memory.
214 214 */
215 215 request = (pMpi2ConfigRequest_t)(mpt->m_req_frame +
216 216 (mpt->m_req_frame_size * cmd->cmd_slot));
217 217 bzero(request, mpt->m_req_frame_size);
218 218
219 219 /*
220 220 * Form the request message.
221 221 */
222 222 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Function,
223 223 MPI2_FUNCTION_CONFIG);
224 224 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Action, config->action);
225 225 direction = MPI2_SGE_FLAGS_IOC_TO_HOST;
226 226 length = 0;
227 227 sge = (pMpi2SGESimple64_t)&request->PageBufferSGE;
228 228 if (config->action == MPI2_CONFIG_ACTION_PAGE_HEADER) {
229 229 if (config->page_type > MPI2_CONFIG_PAGETYPE_MASK) {
230 230 ddi_put8(mpt->m_acc_req_frame_hdl,
231 231 &request->Header.PageType,
232 232 MPI2_CONFIG_PAGETYPE_EXTENDED);
233 233 ddi_put8(mpt->m_acc_req_frame_hdl,
234 234 &request->ExtPageType, config->page_type);
235 235 } else {
236 236 ddi_put8(mpt->m_acc_req_frame_hdl,
237 237 &request->Header.PageType, config->page_type);
238 238 }
239 239 } else {
240 240 ddi_put8(mpt->m_acc_req_frame_hdl, &request->ExtPageType,
241 241 config->ext_page_type);
242 242 ddi_put16(mpt->m_acc_req_frame_hdl, &request->ExtPageLength,
243 243 config->ext_page_length);
244 244 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageType,
245 245 config->page_type);
246 246 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageLength,
247 247 config->page_length);
248 248 ddi_put8(mpt->m_acc_req_frame_hdl,
249 249 &request->Header.PageVersion, config->page_version);
250 250 if ((config->page_type & MPI2_CONFIG_PAGETYPE_MASK) ==
251 251 MPI2_CONFIG_PAGETYPE_EXTENDED) {
252 252 length = config->ext_page_length * 4;
253 253 } else {
254 254 length = config->page_length * 4;
255 255 }
256 256
257 257 if (config->action == MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
258 258 direction = MPI2_SGE_FLAGS_HOST_TO_IOC;
259 259 }
260 260 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->Address.Low,
261 261 (uint32_t)cmd->cmd_dma_addr);
262 262 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->Address.High,
263 263 (uint32_t)(cmd->cmd_dma_addr >> 32));
264 264 }
265 265 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageNumber,
266 266 config->page_number);
267 267 ddi_put32(mpt->m_acc_req_frame_hdl, &request->PageAddress,
268 268 config->page_address);
269 269 flagslength = ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
270 270 MPI2_SGE_FLAGS_END_OF_BUFFER |
271 271 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
272 272 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
273 273 MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
274 274 direction |
275 275 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
276 276 flagslength |= length;
277 277 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->FlagsLength, flagslength);
278 278
279 279 (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
280 280 DDI_DMA_SYNC_FORDEV);
281 281 request_desc = (cmd->cmd_slot << 16) +
282 282 MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
283 283 cmd->cmd_rfm = NULL;
284 284 MPTSAS_START_CMD(mpt, request_desc);
285 285 if ((mptsas_check_dma_handle(mpt->m_dma_req_frame_hdl) !=
286 286 DDI_SUCCESS) ||
287 287 (mptsas_check_acc_handle(mpt->m_acc_req_frame_hdl) !=
288 288 DDI_SUCCESS)) {
289 289 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
290 290 }
291 291 }
292 292
293 293 int
294 294 mptsas_access_config_page(mptsas_t *mpt, uint8_t action, uint8_t page_type,
295 295 uint8_t page_number, uint32_t page_address, int (*callback) (mptsas_t *,
296 296 caddr_t, ddi_acc_handle_t, uint16_t, uint32_t, va_list), ...)
297 297 {
298 298 va_list ap;
299 299 ddi_dma_attr_t attrs;
300 300 ddi_dma_cookie_t cookie;
301 301 ddi_acc_handle_t accessp;
302 302 size_t len = 0;
303 303 mptsas_config_request_t config;
304 304 int rval = DDI_SUCCESS, config_flags = 0;
305 305 mptsas_cmd_t *cmd;
306 306 struct scsi_pkt *pkt;
307 307 pMpi2ConfigReply_t reply;
308 308 uint16_t iocstatus = 0;
309 309 uint32_t iocloginfo;
310 310 caddr_t page_memp;
311 311 boolean_t free_dma = B_FALSE;
312 312
313 313 va_start(ap, callback);
314 314 ASSERT(mutex_owned(&mpt->m_mutex));
315 315
316 316 /*
317 317 * Get a command from the pool.
318 318 */
319 319 if ((rval = (mptsas_request_from_pool(mpt, &cmd, &pkt))) == -1) {
320 320 mptsas_log(mpt, CE_NOTE, "command pool is full for config "
321 321 "page request");
322 322 rval = DDI_FAILURE;
323 323 goto page_done;
324 324 }
325 325 config_flags |= MPTSAS_REQUEST_POOL_CMD;
326 326
327 327 bzero((caddr_t)cmd, sizeof (*cmd));
328 328 bzero((caddr_t)pkt, scsi_pkt_size());
329 329 bzero((caddr_t)&config, sizeof (config));
330 330
331 331 /*
332 332 * Save the data for this request to be used in the call to start the
333 333 * config header request.
334 334 */
335 335 config.action = MPI2_CONFIG_ACTION_PAGE_HEADER;
336 336 config.page_type = page_type;
337 337 config.page_number = page_number;
338 338 config.page_address = page_address;
339 339
340 340 /*
341 341 * Form a blank cmd/pkt to store the acknowledgement message
342 342 */
343 343 pkt->pkt_ha_private = (opaque_t)&config;
344 344 pkt->pkt_flags = FLAG_HEAD;
345 345 pkt->pkt_time = 60;
346 346 cmd->cmd_pkt = pkt;
347 347 cmd->cmd_flags = CFLAG_CMDIOC | CFLAG_CONFIG;
348 348
349 349 /*
350 350 * Save the config header request message in a slot.
351 351 */
352 352 if (mptsas_save_cmd(mpt, cmd) == TRUE) {
353 353 cmd->cmd_flags |= CFLAG_PREPARED;
354 354 mptsas_start_config_page_access(mpt, cmd);
355 355 } else {
356 356 mptsas_waitq_add(mpt, cmd);
357 357 }
358 358
359 359 /*
360 360 * If this is a request for a RAID info page, or any page called during
361 361 * the RAID info page request, poll because these config page requests
362 362 * are nested. Poll to avoid data corruption due to one page's data
363 363 * overwriting the outer page request's data. This can happen when
364 364 * the mutex is released in cv_wait.
365 365 */
366 366 if ((page_type == MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG) ||
367 367 (page_type == MPI2_CONFIG_PAGETYPE_RAID_VOLUME) ||
368 368 (page_type == MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK)) {
369 369 (void) mptsas_poll(mpt, cmd, pkt->pkt_time * 1000);
370 370 } else {
371 371 while ((cmd->cmd_flags & CFLAG_FINISHED) == 0) {
372 372 cv_wait(&mpt->m_config_cv, &mpt->m_mutex);
373 373 }
374 374 }
375 375
376 376 /*
377 377 * Check if the header request completed without timing out
378 378 */
379 379 if (cmd->cmd_flags & CFLAG_TIMEOUT) {
380 380 mptsas_log(mpt, CE_WARN, "config header request timeout");
381 381 rval = DDI_FAILURE;
382 382 goto page_done;
383 383 }
384 384
385 385 /*
386 386 * cmd_rfm points to the reply message if a reply was given. Check the
387 387 * IOCStatus to make sure everything went OK with the header request.
388 388 */
389 389 if (cmd->cmd_rfm) {
390 390 config_flags |= MPTSAS_ADDRESS_REPLY;
391 391 (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
392 392 DDI_DMA_SYNC_FORCPU);
393 393 reply = (pMpi2ConfigReply_t)(mpt->m_reply_frame + (cmd->cmd_rfm
394 394 - (mpt->m_reply_frame_dma_addr & 0xffffffffu)));
395 395 config.page_type = ddi_get8(mpt->m_acc_reply_frame_hdl,
396 396 &reply->Header.PageType);
397 397 config.page_number = ddi_get8(mpt->m_acc_reply_frame_hdl,
398 398 &reply->Header.PageNumber);
399 399 config.page_length = ddi_get8(mpt->m_acc_reply_frame_hdl,
400 400 &reply->Header.PageLength);
401 401 config.page_version = ddi_get8(mpt->m_acc_reply_frame_hdl,
402 402 &reply->Header.PageVersion);
403 403 config.ext_page_type = ddi_get8(mpt->m_acc_reply_frame_hdl,
404 404 &reply->ExtPageType);
405 405 config.ext_page_length = ddi_get16(mpt->m_acc_reply_frame_hdl,
406 406 &reply->ExtPageLength);
407 407
408 408 iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl,
409 409 &reply->IOCStatus);
410 410 iocloginfo = ddi_get32(mpt->m_acc_reply_frame_hdl,
411 411 &reply->IOCLogInfo);
412 412
413 413 if (iocstatus) {
414 414 NDBG13(("mptsas_access_config_page header: "
415 415 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
416 416 iocloginfo));
417 417 rval = DDI_FAILURE;
418 418 goto page_done;
419 419 }
420 420
421 421 if ((config.page_type & MPI2_CONFIG_PAGETYPE_MASK) ==
422 422 MPI2_CONFIG_PAGETYPE_EXTENDED)
423 423 len = (config.ext_page_length * 4);
424 424 else
425 425 len = (config.page_length * 4);
426 426
427 427 }
428 428
429 429 if (pkt->pkt_reason == CMD_RESET) {
430 430 mptsas_log(mpt, CE_WARN, "ioc reset abort config header "
431 431 "request");
432 432 rval = DDI_FAILURE;
433 433 goto page_done;
434 434 }
435 435
436 436 /*
437 437 * Put the reply frame back on the free queue, increment the free
438 438 * index, and write the new index to the free index register. But only
439 439 * if this reply is an ADDRESS reply.
440 440 */
441 441 if (config_flags & MPTSAS_ADDRESS_REPLY) {
442 442 ddi_put32(mpt->m_acc_free_queue_hdl,
443 443 &((uint32_t *)(void *)mpt->m_free_queue)[mpt->m_free_index],
444 444 cmd->cmd_rfm);
445 445 (void) ddi_dma_sync(mpt->m_dma_free_queue_hdl, 0, 0,
446 446 DDI_DMA_SYNC_FORDEV);
447 447 if (++mpt->m_free_index == mpt->m_free_queue_depth) {
448 448 mpt->m_free_index = 0;
449 449 }
450 450 ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyFreeHostIndex,
451 451 mpt->m_free_index);
452 452 config_flags &= (~MPTSAS_ADDRESS_REPLY);
453 453 }
454 454
455 455 /*
456 456 * Allocate DMA buffer here. Store the info regarding this buffer in
457 457 * the cmd struct so that it can be used for this specific command and
458 458 * de-allocated after the command completes. The size of the reply
459 459 * will not be larger than the reply frame size.
460 460 */
461 461 attrs = mpt->m_msg_dma_attr;
462 462 attrs.dma_attr_sgllen = 1;
463 463 attrs.dma_attr_granular = (uint32_t)len;
464 464
465 465 if (mptsas_dma_addr_create(mpt, attrs,
466 466 &cmd->cmd_dmahandle, &accessp, &page_memp,
467 467 len, &cookie) == FALSE) {
468 468 rval = DDI_FAILURE;
469 469 mptsas_log(mpt, CE_WARN,
470 470 "mptsas_dma_addr_create(len=0x%x) failed", (int)len);
471 471 goto page_done;
472 472 }
473 473 /* NOW we can safely call mptsas_dma_addr_destroy(). */
474 474 free_dma = B_TRUE;
475 475
476 476 cmd->cmd_dma_addr = cookie.dmac_laddress;
477 477 bzero(page_memp, len);
478 478
479 479 /*
480 480 * Save the data for this request to be used in the call to start the
481 481 * config page read
482 482 */
483 483 config.action = action;
484 484 config.page_address = page_address;
485 485
486 486 /*
487 487 * Re-use the cmd that was used to get the header. Reset some of the
488 488 * values.
489 489 */
490 490 bzero((caddr_t)pkt, scsi_pkt_size());
491 491 pkt->pkt_ha_private = (opaque_t)&config;
492 492 pkt->pkt_flags = FLAG_HEAD;
493 493 pkt->pkt_time = 60;
494 494 cmd->cmd_flags = CFLAG_PREPARED | CFLAG_CMDIOC | CFLAG_CONFIG;
495 495
496 496 /*
497 497 * Send the config page request. cmd is re-used from header request.
498 498 */
499 499 mptsas_start_config_page_access(mpt, cmd);
500 500
501 501 /*
502 502 * If this is a request for a RAID info page, or any page called during
503 503 * the RAID info page request, poll because these config page requests
504 504 * are nested. Poll to avoid data corruption due to one page's data
505 505 * overwriting the outer page request's data. This can happen when
506 506 * the mutex is released in cv_wait.
507 507 */
508 508 if ((page_type == MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG) ||
509 509 (page_type == MPI2_CONFIG_PAGETYPE_RAID_VOLUME) ||
510 510 (page_type == MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK)) {
511 511 (void) mptsas_poll(mpt, cmd, pkt->pkt_time * 1000);
512 512 } else {
513 513 while ((cmd->cmd_flags & CFLAG_FINISHED) == 0) {
514 514 cv_wait(&mpt->m_config_cv, &mpt->m_mutex);
515 515 }
516 516 }
517 517
518 518 /*
519 519 * Check if the request completed without timing out
520 520 */
521 521 if (cmd->cmd_flags & CFLAG_TIMEOUT) {
522 522 mptsas_log(mpt, CE_WARN, "config page request timeout");
523 523 rval = DDI_FAILURE;
524 524 goto page_done;
525 525 }
526 526
527 527 /*
528 528 * cmd_rfm points to the reply message if a reply was given. The reply
529 529 * frame and the config page are returned from this function in the
530 530 * param list.
531 531 */
532 532 if (cmd->cmd_rfm) {
533 533 config_flags |= MPTSAS_ADDRESS_REPLY;
534 534 (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
535 535 DDI_DMA_SYNC_FORCPU);
536 536 (void) ddi_dma_sync(cmd->cmd_dmahandle, 0, 0,
537 537 DDI_DMA_SYNC_FORCPU);
538 538 reply = (pMpi2ConfigReply_t)(mpt->m_reply_frame + (cmd->cmd_rfm
539 539 - (mpt->m_reply_frame_dma_addr & 0xffffffffu)));
540 540 iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl,
541 541 &reply->IOCStatus);
542 542 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
543 543 iocloginfo = ddi_get32(mpt->m_acc_reply_frame_hdl,
544 544 &reply->IOCLogInfo);
545 545 }
546 546
547 547 if (callback(mpt, page_memp, accessp, iocstatus, iocloginfo, ap)) {
548 548 rval = DDI_FAILURE;
549 549 goto page_done;
550 550 }
551 551
552 552 mptsas_fma_check(mpt, cmd);
553 553 /*
554 554 * Check the DMA/ACC handles and then free the DMA buffer.
555 555 */
556 556 if ((mptsas_check_dma_handle(cmd->cmd_dmahandle) != DDI_SUCCESS) ||
557 557 (mptsas_check_acc_handle(accessp) != DDI_SUCCESS)) {
558 558 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
559 559 rval = DDI_FAILURE;
560 560 }
561 561
562 562 if (pkt->pkt_reason == CMD_TRAN_ERR) {
563 563 mptsas_log(mpt, CE_WARN, "config fma error");
564 564 rval = DDI_FAILURE;
565 565 goto page_done;
566 566 }
567 567 if (pkt->pkt_reason == CMD_RESET) {
568 568 mptsas_log(mpt, CE_WARN, "ioc reset abort config request");
569 569 rval = DDI_FAILURE;
570 570 goto page_done;
571 571 }
572 572
573 573 page_done:
574 574 va_end(ap);
575 575 /*
576 576 * Put the reply frame back on the free queue, increment the free
577 577 * index, and write the new index to the free index register. But only
578 578 * if this reply is an ADDRESS reply.
579 579 */
580 580 if (config_flags & MPTSAS_ADDRESS_REPLY) {
581 581 ddi_put32(mpt->m_acc_free_queue_hdl,
582 582 &((uint32_t *)(void *)mpt->m_free_queue)[mpt->m_free_index],
583 583 cmd->cmd_rfm);
584 584 (void) ddi_dma_sync(mpt->m_dma_free_queue_hdl, 0, 0,
585 585 DDI_DMA_SYNC_FORDEV);
586 586 if (++mpt->m_free_index == mpt->m_free_queue_depth) {
587 587 mpt->m_free_index = 0;
588 588 }
589 589 ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyFreeHostIndex,
590 590 mpt->m_free_index);
591 591 }
592 592
593 593 if (free_dma)
594 594 mptsas_dma_addr_destroy(&cmd->cmd_dmahandle, &accessp);
↓ open down ↓ |
594 lines elided |
↑ open up ↑ |
595 595
596 596 if (cmd && (cmd->cmd_flags & CFLAG_PREPARED)) {
597 597 mptsas_remove_cmd(mpt, cmd);
598 598 config_flags &= (~MPTSAS_REQUEST_POOL_CMD);
599 599 }
600 600 if (config_flags & MPTSAS_REQUEST_POOL_CMD)
601 601 mptsas_return_to_pool(mpt, cmd);
602 602
603 603 if (config_flags & MPTSAS_CMD_TIMEOUT) {
604 604 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
605 - if ((mptsas_restart_ioc(mpt)) == DDI_FAILURE) {
606 - mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
605 + if ((mptsas_reset_handler(mpt)) == DDI_FAILURE) {
606 + mptsas_log(mpt, CE_WARN, "mptsas_reset_handler failed");
607 607 }
608 608 }
609 609
610 610 return (rval);
611 611 }
612 612
613 613 int
614 614 mptsas_send_config_request_msg(mptsas_t *mpt, uint8_t action, uint8_t pagetype,
615 615 uint32_t pageaddress, uint8_t pagenumber, uint8_t pageversion,
616 616 uint8_t pagelength, uint32_t SGEflagslength, uint64_t SGEaddress)
617 617 {
618 618 pMpi2ConfigRequest_t config;
619 619 int send_numbytes;
620 620
621 621 bzero(mpt->m_hshk_memp, sizeof (MPI2_CONFIG_REQUEST));
622 622 config = (pMpi2ConfigRequest_t)mpt->m_hshk_memp;
623 623 ddi_put8(mpt->m_hshk_acc_hdl, &config->Function, MPI2_FUNCTION_CONFIG);
624 624 ddi_put8(mpt->m_hshk_acc_hdl, &config->Action, action);
625 625 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageNumber, pagenumber);
626 626 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageType, pagetype);
627 627 ddi_put32(mpt->m_hshk_acc_hdl, &config->PageAddress, pageaddress);
628 628 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageVersion, pageversion);
629 629 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageLength, pagelength);
630 630 ddi_put32(mpt->m_hshk_acc_hdl,
631 631 &config->PageBufferSGE.MpiSimple.FlagsLength, SGEflagslength);
632 632 ddi_put32(mpt->m_hshk_acc_hdl,
633 633 &config->PageBufferSGE.MpiSimple.u.Address64.Low, SGEaddress);
634 634 ddi_put32(mpt->m_hshk_acc_hdl,
635 635 &config->PageBufferSGE.MpiSimple.u.Address64.High,
636 636 SGEaddress >> 32);
637 637 send_numbytes = sizeof (MPI2_CONFIG_REQUEST);
638 638
639 639 /*
640 640 * Post message via handshake
641 641 */
642 642 if (mptsas_send_handshake_msg(mpt, (caddr_t)config, send_numbytes,
643 643 mpt->m_hshk_acc_hdl)) {
644 644 return (-1);
645 645 }
646 646 return (0);
647 647 }
648 648
649 649 int
650 650 mptsas_send_extended_config_request_msg(mptsas_t *mpt, uint8_t action,
651 651 uint8_t extpagetype, uint32_t pageaddress, uint8_t pagenumber,
652 652 uint8_t pageversion, uint16_t extpagelength,
653 653 uint32_t SGEflagslength, uint64_t SGEaddress)
654 654 {
655 655 pMpi2ConfigRequest_t config;
656 656 int send_numbytes;
657 657
658 658 bzero(mpt->m_hshk_memp, sizeof (MPI2_CONFIG_REQUEST));
659 659 config = (pMpi2ConfigRequest_t)mpt->m_hshk_memp;
660 660 ddi_put8(mpt->m_hshk_acc_hdl, &config->Function, MPI2_FUNCTION_CONFIG);
661 661 ddi_put8(mpt->m_hshk_acc_hdl, &config->Action, action);
662 662 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageNumber, pagenumber);
663 663 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageType,
664 664 MPI2_CONFIG_PAGETYPE_EXTENDED);
665 665 ddi_put8(mpt->m_hshk_acc_hdl, &config->ExtPageType, extpagetype);
666 666 ddi_put32(mpt->m_hshk_acc_hdl, &config->PageAddress, pageaddress);
667 667 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageVersion, pageversion);
668 668 ddi_put16(mpt->m_hshk_acc_hdl, &config->ExtPageLength, extpagelength);
669 669 ddi_put32(mpt->m_hshk_acc_hdl,
670 670 &config->PageBufferSGE.MpiSimple.FlagsLength, SGEflagslength);
671 671 ddi_put32(mpt->m_hshk_acc_hdl,
672 672 &config->PageBufferSGE.MpiSimple.u.Address64.Low, SGEaddress);
673 673 ddi_put32(mpt->m_hshk_acc_hdl,
674 674 &config->PageBufferSGE.MpiSimple.u.Address64.High,
675 675 SGEaddress >> 32);
676 676 send_numbytes = sizeof (MPI2_CONFIG_REQUEST);
677 677
678 678 /*
679 679 * Post message via handshake
680 680 */
681 681 if (mptsas_send_handshake_msg(mpt, (caddr_t)config, send_numbytes,
682 682 mpt->m_hshk_acc_hdl)) {
683 683 return (-1);
684 684 }
685 685 return (0);
686 686 }
687 687
688 688 int
689 689 mptsas_ioc_wait_for_response(mptsas_t *mpt)
690 690 {
691 691 int polls = 0;
692 692
693 693 while ((ddi_get32(mpt->m_datap,
694 694 &mpt->m_reg->HostInterruptStatus) & MPI2_HIS_IOP_DOORBELL_STATUS)) {
695 695 drv_usecwait(1000);
696 696 if (polls++ > 60000) {
697 697 return (-1);
698 698 }
699 699 }
700 700 return (0);
701 701 }
702 702
703 703 int
704 704 mptsas_ioc_wait_for_doorbell(mptsas_t *mpt)
705 705 {
706 706 int polls = 0;
707 707
708 708 while ((ddi_get32(mpt->m_datap,
709 709 &mpt->m_reg->HostInterruptStatus) & MPI2_HIM_DIM) == 0) {
710 710 drv_usecwait(1000);
711 711 if (polls++ > 300000) {
712 712 return (-1);
713 713 }
714 714 }
715 715 return (0);
716 716 }
717 717
718 718 int
719 719 mptsas_send_handshake_msg(mptsas_t *mpt, caddr_t memp, int numbytes,
720 720 ddi_acc_handle_t accessp)
721 721 {
722 722 int i;
723 723
724 724 /*
725 725 * clean pending doorbells
726 726 */
727 727 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
728 728 ddi_put32(mpt->m_datap, &mpt->m_reg->Doorbell,
729 729 ((MPI2_FUNCTION_HANDSHAKE << MPI2_DOORBELL_FUNCTION_SHIFT) |
730 730 ((numbytes / 4) << MPI2_DOORBELL_ADD_DWORDS_SHIFT)));
731 731
732 732 if (mptsas_ioc_wait_for_doorbell(mpt)) {
733 733 NDBG19(("mptsas_send_handshake failed. Doorbell not ready\n"));
734 734 return (-1);
735 735 }
736 736
737 737 /*
738 738 * clean pending doorbells again
739 739 */
740 740 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
741 741
742 742 if (mptsas_ioc_wait_for_response(mpt)) {
743 743 NDBG19(("mptsas_send_handshake failed. Doorbell not "
744 744 "cleared\n"));
745 745 return (-1);
746 746 }
747 747
748 748 /*
749 749 * post handshake message
750 750 */
751 751 for (i = 0; (i < numbytes / 4); i++, memp += 4) {
752 752 ddi_put32(mpt->m_datap, &mpt->m_reg->Doorbell,
753 753 ddi_get32(accessp, (uint32_t *)((void *)(memp))));
754 754 if (mptsas_ioc_wait_for_response(mpt)) {
755 755 NDBG19(("mptsas_send_handshake failed posting "
756 756 "message\n"));
757 757 return (-1);
758 758 }
759 759 }
760 760
761 761 if (mptsas_check_acc_handle(mpt->m_datap) != DDI_SUCCESS) {
762 762 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
763 763 ddi_fm_acc_err_clear(mpt->m_datap, DDI_FME_VER0);
764 764 return (-1);
765 765 }
766 766
767 767 return (0);
768 768 }
769 769
770 770 int
771 771 mptsas_get_handshake_msg(mptsas_t *mpt, caddr_t memp, int numbytes,
772 772 ddi_acc_handle_t accessp)
773 773 {
774 774 int i, totalbytes, bytesleft;
775 775 uint16_t val;
776 776
777 777 /*
778 778 * wait for doorbell
779 779 */
780 780 if (mptsas_ioc_wait_for_doorbell(mpt)) {
781 781 NDBG19(("mptsas_get_handshake failed. Doorbell not ready\n"));
782 782 return (-1);
783 783 }
784 784
785 785 /*
786 786 * get first 2 bytes of handshake message to determine how much
787 787 * data we will be getting
788 788 */
789 789 for (i = 0; i < 2; i++, memp += 2) {
790 790 val = (ddi_get32(mpt->m_datap,
791 791 &mpt->m_reg->Doorbell) & MPI2_DOORBELL_DATA_MASK);
792 792 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
793 793 if (mptsas_ioc_wait_for_doorbell(mpt)) {
794 794 NDBG19(("mptsas_get_handshake failure getting initial"
795 795 " data\n"));
796 796 return (-1);
797 797 }
798 798 ddi_put16(accessp, (uint16_t *)((void *)(memp)), val);
799 799 if (i == 1) {
800 800 totalbytes = (val & 0xFF) * 2;
801 801 }
802 802 }
803 803
804 804 /*
805 805 * If we are expecting less bytes than the message wants to send
806 806 * we simply save as much as we expected and then throw out the rest
807 807 * later
808 808 */
809 809 if (totalbytes > (numbytes / 2)) {
810 810 bytesleft = ((numbytes / 2) - 2);
811 811 } else {
812 812 bytesleft = (totalbytes - 2);
813 813 }
814 814
815 815 /*
816 816 * Get the rest of the data
817 817 */
818 818 for (i = 0; i < bytesleft; i++, memp += 2) {
819 819 val = (ddi_get32(mpt->m_datap,
820 820 &mpt->m_reg->Doorbell) & MPI2_DOORBELL_DATA_MASK);
821 821 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
822 822 if (mptsas_ioc_wait_for_doorbell(mpt)) {
823 823 NDBG19(("mptsas_get_handshake failure getting"
824 824 " main data\n"));
825 825 return (-1);
826 826 }
827 827 ddi_put16(accessp, (uint16_t *)((void *)(memp)), val);
828 828 }
829 829
830 830 /*
831 831 * Sometimes the device will send more data than is expected
832 832 * This data is not used by us but needs to be cleared from
833 833 * ioc doorbell. So we just read the values and throw
834 834 * them out.
835 835 */
836 836 if (totalbytes > (numbytes / 2)) {
837 837 for (i = (numbytes / 2); i < totalbytes; i++) {
838 838 val = (ddi_get32(mpt->m_datap,
839 839 &mpt->m_reg->Doorbell) &
840 840 MPI2_DOORBELL_DATA_MASK);
841 841 ddi_put32(mpt->m_datap,
842 842 &mpt->m_reg->HostInterruptStatus, 0);
843 843 if (mptsas_ioc_wait_for_doorbell(mpt)) {
844 844 NDBG19(("mptsas_get_handshake failure getting "
845 845 "extra garbage data\n"));
846 846 return (-1);
847 847 }
848 848 }
849 849 }
850 850
851 851 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
852 852
853 853 if (mptsas_check_acc_handle(mpt->m_datap) != DDI_SUCCESS) {
854 854 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
855 855 ddi_fm_acc_err_clear(mpt->m_datap, DDI_FME_VER0);
856 856 return (-1);
857 857 }
858 858
859 859 return (0);
860 860 }
861 861
862 862 int
863 863 mptsas_kick_start(mptsas_t *mpt)
864 864 {
865 865 int polls = 0;
866 866 uint32_t diag_reg, ioc_state, saved_HCB_size;
867 867
868 868 /*
869 869 * Start a hard reset. Write magic number and wait 500 mSeconds.
870 870 */
871 871 MPTSAS_ENABLE_DRWE(mpt);
872 872 drv_usecwait(500000);
873 873
874 874 /*
875 875 * Read the current Diag Reg and save the Host Controlled Boot size.
876 876 */
877 877 diag_reg = ddi_get32(mpt->m_datap, &mpt->m_reg->HostDiagnostic);
878 878 saved_HCB_size = ddi_get32(mpt->m_datap, &mpt->m_reg->HCBSize);
879 879
880 880 /*
881 881 * Set Reset Adapter bit and wait 50 mSeconds.
882 882 */
883 883 diag_reg |= MPI2_DIAG_RESET_ADAPTER;
884 884 ddi_put32(mpt->m_datap, &mpt->m_reg->HostDiagnostic, diag_reg);
885 885 drv_usecwait(50000);
886 886
887 887 /*
888 888 * Poll, waiting for Reset Adapter bit to clear. 300 Seconds max
889 889 * (600000 * 500 = 300,000,000 uSeconds, 300 seconds).
890 890 * If no more adapter (all FF's), just return failure.
891 891 */
892 892 for (polls = 0; polls < 600000; polls++) {
893 893 diag_reg = ddi_get32(mpt->m_datap,
894 894 &mpt->m_reg->HostDiagnostic);
895 895 if (diag_reg == 0xFFFFFFFF) {
896 896 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
897 897 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
898 898 return (DDI_FAILURE);
899 899 }
900 900 if (!(diag_reg & MPI2_DIAG_RESET_ADAPTER)) {
901 901 break;
902 902 }
903 903 drv_usecwait(500);
904 904 }
905 905 if (polls == 600000) {
906 906 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
907 907 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
908 908 return (DDI_FAILURE);
909 909 }
910 910
911 911 /*
912 912 * Check if adapter is in Host Boot Mode. If so, restart adapter
913 913 * assuming the HCB points to good FW.
914 914 * Set BootDeviceSel to HCDW (Host Code and Data Window).
915 915 */
916 916 if (diag_reg & MPI2_DIAG_HCB_MODE) {
917 917 diag_reg &= ~MPI2_DIAG_BOOT_DEVICE_SELECT_MASK;
918 918 diag_reg |= MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW;
919 919 ddi_put32(mpt->m_datap, &mpt->m_reg->HostDiagnostic, diag_reg);
920 920
921 921 /*
922 922 * Re-enable the HCDW.
923 923 */
924 924 ddi_put32(mpt->m_datap, &mpt->m_reg->HCBSize,
925 925 (saved_HCB_size | MPI2_HCB_SIZE_HCB_ENABLE));
926 926 }
927 927
928 928 /*
929 929 * Restart the adapter.
930 930 */
931 931 diag_reg &= ~MPI2_DIAG_HOLD_IOC_RESET;
932 932 ddi_put32(mpt->m_datap, &mpt->m_reg->HostDiagnostic, diag_reg);
933 933
934 934 /*
935 935 * Disable writes to the Host Diag register.
936 936 */
937 937 ddi_put32(mpt->m_datap, &mpt->m_reg->WriteSequence,
938 938 MPI2_WRSEQ_FLUSH_KEY_VALUE);
939 939
940 940 /*
941 941 * Wait 60 seconds max for FW to come to ready state.
942 942 */
943 943 for (polls = 0; polls < 60000; polls++) {
944 944 ioc_state = ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell);
945 945 if (ioc_state == 0xFFFFFFFF) {
946 946 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
947 947 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
948 948 return (DDI_FAILURE);
949 949 }
950 950 if ((ioc_state & MPI2_IOC_STATE_MASK) ==
951 951 MPI2_IOC_STATE_READY) {
952 952 break;
953 953 }
954 954 drv_usecwait(1000);
955 955 }
956 956 if (polls == 60000) {
957 957 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
958 958 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
959 959 return (DDI_FAILURE);
960 960 }
961 961
962 962 /*
963 963 * Clear the ioc ack events queue.
964 964 */
965 965 mptsas_destroy_ioc_event_cmd(mpt);
966 966
967 967 return (DDI_SUCCESS);
968 968 }
969 969
970 970 int
971 971 mptsas_ioc_reset(mptsas_t *mpt, int first_time)
972 972 {
973 973 int polls = 0;
974 974 uint32_t reset_msg;
975 975 uint32_t ioc_state;
976 976
977 977 ioc_state = ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell);
978 978 /*
979 979 * If chip is already in ready state then there is nothing to do.
980 980 */
981 981 if (ioc_state == MPI2_IOC_STATE_READY) {
982 982 return (MPTSAS_NO_RESET);
983 983 }
984 984 /*
985 985 * If the chip is already operational, we just need to send
986 986 * it a message unit reset to put it back in the ready state
987 987 */
988 988 if (ioc_state & MPI2_IOC_STATE_OPERATIONAL) {
989 989 /*
990 990 * If the first time, try MUR anyway, because we haven't even
991 991 * queried the card for m_event_replay and other capabilities.
992 992 * Other platforms do it this way, we can still do a hard
993 993 * reset if we need to, MUR takes less time than a full
994 994 * adapter reset, and there are reports that some HW
995 995 * combinations will lock up when receiving a hard reset.
996 996 */
997 997 if ((first_time || mpt->m_event_replay) &&
998 998 (mpt->m_softstate & MPTSAS_SS_MSG_UNIT_RESET)) {
999 999 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
1000 1000 reset_msg = MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET;
1001 1001 ddi_put32(mpt->m_datap, &mpt->m_reg->Doorbell,
1002 1002 (reset_msg << MPI2_DOORBELL_FUNCTION_SHIFT));
1003 1003 if (mptsas_ioc_wait_for_response(mpt)) {
1004 1004 NDBG19(("mptsas_ioc_reset failure sending "
1005 1005 "message_unit_reset\n"));
1006 1006 goto hard_reset;
1007 1007 }
1008 1008
1009 1009 /*
1010 1010 * Wait no more than 60 seconds for chip to become
1011 1011 * ready.
1012 1012 */
1013 1013 while ((ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell) &
1014 1014 MPI2_IOC_STATE_READY) == 0x0) {
1015 1015 drv_usecwait(1000);
1016 1016 if (polls++ > 60000) {
1017 1017 goto hard_reset;
1018 1018 }
1019 1019 }
1020 1020
1021 1021 /*
1022 1022 * Save the last reset mode done on IOC which will be
1023 1023 * helpful while resuming from suspension.
1024 1024 */
1025 1025 mpt->m_softstate |= MPTSAS_DID_MSG_UNIT_RESET;
1026 1026
1027 1027 /*
1028 1028 * the message unit reset would do reset operations
1029 1029 * clear reply and request queue, so we should clear
1030 1030 * ACK event cmd.
1031 1031 */
1032 1032 mptsas_destroy_ioc_event_cmd(mpt);
1033 1033 return (MPTSAS_SUCCESS_MUR);
1034 1034 }
1035 1035 }
1036 1036 hard_reset:
1037 1037 mpt->m_softstate &= ~MPTSAS_DID_MSG_UNIT_RESET;
1038 1038 if (mptsas_kick_start(mpt) == DDI_FAILURE) {
1039 1039 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
1040 1040 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
1041 1041 return (MPTSAS_RESET_FAIL);
1042 1042 }
1043 1043 return (MPTSAS_SUCCESS_HARDRESET);
1044 1044 }
1045 1045
1046 1046
1047 1047 int
1048 1048 mptsas_request_from_pool(mptsas_t *mpt, mptsas_cmd_t **cmd,
1049 1049 struct scsi_pkt **pkt)
1050 1050 {
1051 1051 m_event_struct_t *ioc_cmd = NULL;
1052 1052
1053 1053 ioc_cmd = kmem_zalloc(M_EVENT_STRUCT_SIZE, KM_SLEEP);
1054 1054 if (ioc_cmd == NULL) {
1055 1055 return (DDI_FAILURE);
1056 1056 }
1057 1057 ioc_cmd->m_event_linkp = NULL;
1058 1058 mptsas_ioc_event_cmdq_add(mpt, ioc_cmd);
1059 1059 *cmd = &(ioc_cmd->m_event_cmd);
1060 1060 *pkt = &(ioc_cmd->m_event_pkt);
1061 1061
1062 1062 return (DDI_SUCCESS);
1063 1063 }
1064 1064
1065 1065 void
1066 1066 mptsas_return_to_pool(mptsas_t *mpt, mptsas_cmd_t *cmd)
1067 1067 {
1068 1068 m_event_struct_t *ioc_cmd = NULL;
1069 1069
1070 1070 ioc_cmd = mptsas_ioc_event_find_by_cmd(mpt, cmd);
1071 1071 if (ioc_cmd == NULL) {
1072 1072 return;
1073 1073 }
1074 1074
1075 1075 mptsas_ioc_event_cmdq_delete(mpt, ioc_cmd);
1076 1076 kmem_free(ioc_cmd, M_EVENT_STRUCT_SIZE);
1077 1077 ioc_cmd = NULL;
1078 1078 }
1079 1079
1080 1080 /*
1081 1081 * NOTE: We should be able to queue TM requests in the controller to make this
1082 1082 * a lot faster. If resetting all targets, for example, we can load the hi
1083 1083 * priority queue with its limit and the controller will reply as they are
1084 1084 * completed. This way, we don't have to poll for one reply at a time.
1085 1085 * Think about enhancing this later.
1086 1086 */
1087 1087 int
1088 1088 mptsas_ioc_task_management(mptsas_t *mpt, int task_type, uint16_t dev_handle,
1089 1089 int lun, uint8_t *reply, uint32_t reply_size, int mode)
1090 1090 {
1091 1091 /*
1092 1092 * In order to avoid allocating variables on the stack,
1093 1093 * we make use of the pre-existing mptsas_cmd_t and
1094 1094 * scsi_pkt which are included in the mptsas_t which
1095 1095 * is passed to this routine.
1096 1096 */
1097 1097
1098 1098 pMpi2SCSITaskManagementRequest_t task;
1099 1099 int rval = FALSE;
1100 1100 mptsas_cmd_t *cmd;
1101 1101 struct scsi_pkt *pkt;
1102 1102 mptsas_slots_t *slots = mpt->m_active;
1103 1103 uint64_t request_desc, i;
1104 1104 pMPI2DefaultReply_t reply_msg;
1105 1105
1106 1106 /*
1107 1107 * Can't start another task management routine.
1108 1108 */
1109 1109 if (slots->m_slot[MPTSAS_TM_SLOT(mpt)] != NULL) {
1110 1110 mptsas_log(mpt, CE_WARN, "Can only start 1 task management"
1111 1111 " command at a time\n");
1112 1112 return (FALSE);
1113 1113 }
1114 1114
1115 1115 cmd = &(mpt->m_event_task_mgmt.m_event_cmd);
1116 1116 pkt = &(mpt->m_event_task_mgmt.m_event_pkt);
1117 1117
1118 1118 bzero((caddr_t)cmd, sizeof (*cmd));
1119 1119 bzero((caddr_t)pkt, scsi_pkt_size());
1120 1120
1121 1121 pkt->pkt_cdbp = (opaque_t)&cmd->cmd_cdb[0];
1122 1122 pkt->pkt_scbp = (opaque_t)&cmd->cmd_scb;
1123 1123 pkt->pkt_ha_private = (opaque_t)cmd;
1124 1124 pkt->pkt_flags = (FLAG_NOINTR | FLAG_HEAD);
1125 1125 pkt->pkt_time = 60;
1126 1126 pkt->pkt_address.a_target = dev_handle;
1127 1127 pkt->pkt_address.a_lun = (uchar_t)lun;
1128 1128 cmd->cmd_pkt = pkt;
1129 1129 cmd->cmd_scblen = 1;
1130 1130 cmd->cmd_flags = CFLAG_TM_CMD;
1131 1131 cmd->cmd_slot = MPTSAS_TM_SLOT(mpt);
1132 1132
1133 1133 slots->m_slot[MPTSAS_TM_SLOT(mpt)] = cmd;
1134 1134
1135 1135 /*
1136 1136 * Store the TM message in memory location corresponding to the TM slot
1137 1137 * number.
1138 1138 */
1139 1139 task = (pMpi2SCSITaskManagementRequest_t)(mpt->m_req_frame +
1140 1140 (mpt->m_req_frame_size * cmd->cmd_slot));
1141 1141 bzero(task, mpt->m_req_frame_size);
1142 1142
1143 1143 /*
1144 1144 * form message for requested task
1145 1145 */
1146 1146 mptsas_init_std_hdr(mpt->m_acc_req_frame_hdl, task, dev_handle, lun, 0,
1147 1147 MPI2_FUNCTION_SCSI_TASK_MGMT);
1148 1148
1149 1149 /*
1150 1150 * Set the task type
1151 1151 */
1152 1152 ddi_put8(mpt->m_acc_req_frame_hdl, &task->TaskType, task_type);
1153 1153
1154 1154 /*
1155 1155 * Send TM request using High Priority Queue.
1156 1156 */
1157 1157 (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
1158 1158 DDI_DMA_SYNC_FORDEV);
1159 1159 request_desc = (cmd->cmd_slot << 16) +
1160 1160 MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
1161 1161 MPTSAS_START_CMD(mpt, request_desc);
1162 1162 rval = mptsas_poll(mpt, cmd, MPTSAS_POLL_TIME);
1163 1163
1164 1164 if (pkt->pkt_reason == CMD_INCOMPLETE)
1165 1165 rval = FALSE;
1166 1166
1167 1167 /*
1168 1168 * If a reply frame was used and there is a reply buffer to copy the
1169 1169 * reply data into, copy it. If this fails, log a message, but don't
1170 1170 * fail the TM request.
1171 1171 */
1172 1172 if (cmd->cmd_rfm && reply) {
1173 1173 (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
1174 1174 DDI_DMA_SYNC_FORCPU);
1175 1175 reply_msg = (pMPI2DefaultReply_t)
1176 1176 (mpt->m_reply_frame + (cmd->cmd_rfm -
1177 1177 (mpt->m_reply_frame_dma_addr & 0xffffffffu)));
1178 1178 if (reply_size > sizeof (MPI2_SCSI_TASK_MANAGE_REPLY)) {
1179 1179 reply_size = sizeof (MPI2_SCSI_TASK_MANAGE_REPLY);
1180 1180 }
1181 1181 mutex_exit(&mpt->m_mutex);
1182 1182 for (i = 0; i < reply_size; i++) {
1183 1183 if (ddi_copyout((uint8_t *)reply_msg + i, reply + i, 1,
1184 1184 mode)) {
1185 1185 mptsas_log(mpt, CE_WARN, "failed to copy out "
1186 1186 "reply data for TM request");
1187 1187 break;
1188 1188 }
1189 1189 }
1190 1190 mutex_enter(&mpt->m_mutex);
1191 1191 }
1192 1192
1193 1193 /*
1194 1194 * clear the TM slot before returning
1195 1195 */
↓ open down ↓ |
579 lines elided |
↑ open up ↑ |
1196 1196 slots->m_slot[MPTSAS_TM_SLOT(mpt)] = NULL;
1197 1197
1198 1198 /*
1199 1199 * If we lost our task management command
1200 1200 * we need to reset the ioc
1201 1201 */
1202 1202 if (rval == FALSE) {
1203 1203 mptsas_log(mpt, CE_WARN, "mptsas_ioc_task_management failed "
1204 1204 "try to reset ioc to recovery!");
1205 1205 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
1206 - if (mptsas_restart_ioc(mpt)) {
1207 - mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
1206 + if (mptsas_reset_handler(mpt)) {
1207 + mptsas_log(mpt, CE_WARN, "mptsas_reset_handler failed");
1208 1208 rval = FAILED;
1209 1209 }
1210 1210 }
1211 1211
1212 1212 return (rval);
1213 1213 }
1214 1214
1215 1215 /*
1216 1216 * Complete firmware download frame for v2.0 cards.
1217 1217 */
1218 1218 static void
1219 1219 mptsas_uflash2(pMpi2FWDownloadRequest fwdownload,
1220 1220 ddi_acc_handle_t acc_hdl, uint32_t size, uint8_t type,
1221 1221 ddi_dma_cookie_t flsh_cookie)
1222 1222 {
1223 1223 pMpi2FWDownloadTCSGE_t tcsge;
1224 1224 pMpi2SGESimple64_t sge;
1225 1225 uint32_t flagslength;
1226 1226
1227 1227 ddi_put8(acc_hdl, &fwdownload->Function,
1228 1228 MPI2_FUNCTION_FW_DOWNLOAD);
1229 1229 ddi_put8(acc_hdl, &fwdownload->ImageType, type);
1230 1230 ddi_put8(acc_hdl, &fwdownload->MsgFlags,
1231 1231 MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT);
1232 1232 ddi_put32(acc_hdl, &fwdownload->TotalImageSize, size);
1233 1233
1234 1234 tcsge = (pMpi2FWDownloadTCSGE_t)&fwdownload->SGL;
1235 1235 ddi_put8(acc_hdl, &tcsge->ContextSize, 0);
1236 1236 ddi_put8(acc_hdl, &tcsge->DetailsLength, 12);
1237 1237 ddi_put8(acc_hdl, &tcsge->Flags, 0);
1238 1238 ddi_put32(acc_hdl, &tcsge->ImageOffset, 0);
1239 1239 ddi_put32(acc_hdl, &tcsge->ImageSize, size);
1240 1240
1241 1241 sge = (pMpi2SGESimple64_t)(tcsge + 1);
1242 1242 flagslength = size;
1243 1243 flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
1244 1244 MPI2_SGE_FLAGS_END_OF_BUFFER |
1245 1245 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
1246 1246 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
1247 1247 MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
1248 1248 MPI2_SGE_FLAGS_HOST_TO_IOC |
1249 1249 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
1250 1250 ddi_put32(acc_hdl, &sge->FlagsLength, flagslength);
1251 1251 ddi_put32(acc_hdl, &sge->Address.Low,
1252 1252 flsh_cookie.dmac_address);
1253 1253 ddi_put32(acc_hdl, &sge->Address.High,
1254 1254 (uint32_t)(flsh_cookie.dmac_laddress >> 32));
1255 1255 }
1256 1256
1257 1257 /*
1258 1258 * Complete firmware download frame for v2.5 cards.
1259 1259 */
1260 1260 static void
1261 1261 mptsas_uflash25(pMpi25FWDownloadRequest fwdownload,
1262 1262 ddi_acc_handle_t acc_hdl, uint32_t size, uint8_t type,
1263 1263 ddi_dma_cookie_t flsh_cookie)
1264 1264 {
1265 1265 pMpi2IeeeSgeSimple64_t sge;
1266 1266 uint8_t flags;
1267 1267
1268 1268 ddi_put8(acc_hdl, &fwdownload->Function,
1269 1269 MPI2_FUNCTION_FW_DOWNLOAD);
1270 1270 ddi_put8(acc_hdl, &fwdownload->ImageType, type);
1271 1271 ddi_put8(acc_hdl, &fwdownload->MsgFlags,
1272 1272 MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT);
1273 1273 ddi_put32(acc_hdl, &fwdownload->TotalImageSize, size);
1274 1274
1275 1275 ddi_put32(acc_hdl, &fwdownload->ImageOffset, 0);
1276 1276 ddi_put32(acc_hdl, &fwdownload->ImageSize, size);
1277 1277
1278 1278 sge = (pMpi2IeeeSgeSimple64_t)&fwdownload->SGL;
1279 1279 flags = MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT |
1280 1280 MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR |
1281 1281 MPI25_IEEE_SGE_FLAGS_END_OF_LIST;
1282 1282 ddi_put8(acc_hdl, &sge->Flags, flags);
1283 1283 ddi_put32(acc_hdl, &sge->Length, size);
1284 1284 ddi_put32(acc_hdl, &sge->Address.Low,
1285 1285 flsh_cookie.dmac_address);
1286 1286 ddi_put32(acc_hdl, &sge->Address.High,
1287 1287 (uint32_t)(flsh_cookie.dmac_laddress >> 32));
1288 1288 }
1289 1289
1290 1290 static int mptsas_enable_mpi25_flashupdate = 0;
1291 1291
1292 1292 int
1293 1293 mptsas_update_flash(mptsas_t *mpt, caddr_t ptrbuffer, uint32_t size,
1294 1294 uint8_t type, int mode)
1295 1295 {
1296 1296
1297 1297 /*
1298 1298 * In order to avoid allocating variables on the stack,
1299 1299 * we make use of the pre-existing mptsas_cmd_t and
1300 1300 * scsi_pkt which are included in the mptsas_t which
1301 1301 * is passed to this routine.
1302 1302 */
1303 1303
1304 1304 ddi_dma_attr_t flsh_dma_attrs;
1305 1305 ddi_dma_cookie_t flsh_cookie;
1306 1306 ddi_dma_handle_t flsh_dma_handle;
1307 1307 ddi_acc_handle_t flsh_accessp;
1308 1308 caddr_t memp, flsh_memp;
1309 1309 mptsas_cmd_t *cmd;
1310 1310 struct scsi_pkt *pkt;
1311 1311 int i;
1312 1312 int rvalue = 0;
1313 1313 uint64_t request_desc;
1314 1314
1315 1315 if (mpt->m_MPI25 && !mptsas_enable_mpi25_flashupdate) {
1316 1316 /*
1317 1317 * The code is there but not tested yet.
1318 1318 * User has to know there are risks here.
1319 1319 */
1320 1320 mptsas_log(mpt, CE_WARN, "mptsas_update_flash(): "
1321 1321 "Updating firmware through MPI 2.5 has not been "
1322 1322 "tested yet!\n"
1323 1323 "To enable set mptsas_enable_mpi25_flashupdate to 1\n");
1324 1324 return (-1);
1325 1325 } /* Otherwise, you pay your money and you take your chances. */
1326 1326
1327 1327 if ((rvalue = (mptsas_request_from_pool(mpt, &cmd, &pkt))) == -1) {
1328 1328 mptsas_log(mpt, CE_WARN, "mptsas_update_flash(): allocation "
1329 1329 "failed. event ack command pool is full\n");
1330 1330 return (rvalue);
1331 1331 }
1332 1332
1333 1333 bzero((caddr_t)cmd, sizeof (*cmd));
1334 1334 bzero((caddr_t)pkt, scsi_pkt_size());
1335 1335 cmd->ioc_cmd_slot = (uint32_t)rvalue;
1336 1336
1337 1337 /*
1338 1338 * dynamically create a customized dma attribute structure
1339 1339 * that describes the flash file.
1340 1340 */
1341 1341 flsh_dma_attrs = mpt->m_msg_dma_attr;
1342 1342 flsh_dma_attrs.dma_attr_sgllen = 1;
1343 1343
1344 1344 if (mptsas_dma_addr_create(mpt, flsh_dma_attrs, &flsh_dma_handle,
1345 1345 &flsh_accessp, &flsh_memp, size, &flsh_cookie) == FALSE) {
1346 1346 mptsas_log(mpt, CE_WARN,
1347 1347 "(unable to allocate dma resource.");
1348 1348 mptsas_return_to_pool(mpt, cmd);
1349 1349 return (-1);
1350 1350 }
1351 1351
1352 1352 bzero(flsh_memp, size);
1353 1353
1354 1354 for (i = 0; i < size; i++) {
1355 1355 (void) ddi_copyin(ptrbuffer + i, flsh_memp + i, 1, mode);
1356 1356 }
1357 1357 (void) ddi_dma_sync(flsh_dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
1358 1358
1359 1359 /*
1360 1360 * form a cmd/pkt to store the fw download message
1361 1361 */
1362 1362 pkt->pkt_cdbp = (opaque_t)&cmd->cmd_cdb[0];
1363 1363 pkt->pkt_scbp = (opaque_t)&cmd->cmd_scb;
1364 1364 pkt->pkt_ha_private = (opaque_t)cmd;
1365 1365 pkt->pkt_flags = FLAG_HEAD;
1366 1366 pkt->pkt_time = 60;
1367 1367 cmd->cmd_pkt = pkt;
1368 1368 cmd->cmd_scblen = 1;
1369 1369 cmd->cmd_flags = CFLAG_CMDIOC | CFLAG_FW_CMD;
1370 1370
1371 1371 /*
1372 1372 * Save the command in a slot
1373 1373 */
1374 1374 if (mptsas_save_cmd(mpt, cmd) == FALSE) {
1375 1375 mptsas_dma_addr_destroy(&flsh_dma_handle, &flsh_accessp);
1376 1376 mptsas_return_to_pool(mpt, cmd);
1377 1377 return (-1);
1378 1378 }
1379 1379
1380 1380 /*
1381 1381 * Fill in fw download message
1382 1382 */
1383 1383 ASSERT(cmd->cmd_slot != 0);
1384 1384 memp = mpt->m_req_frame + (mpt->m_req_frame_size * cmd->cmd_slot);
1385 1385 bzero(memp, mpt->m_req_frame_size);
1386 1386
1387 1387 if (mpt->m_MPI25)
1388 1388 mptsas_uflash25((pMpi25FWDownloadRequest)memp,
1389 1389 mpt->m_acc_req_frame_hdl, size, type, flsh_cookie);
1390 1390 else
1391 1391 mptsas_uflash2((pMpi2FWDownloadRequest)memp,
1392 1392 mpt->m_acc_req_frame_hdl, size, type, flsh_cookie);
1393 1393
1394 1394 /*
1395 1395 * Start command
1396 1396 */
1397 1397 (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
1398 1398 DDI_DMA_SYNC_FORDEV);
↓ open down ↓ |
181 lines elided |
↑ open up ↑ |
1399 1399 request_desc = (cmd->cmd_slot << 16) +
1400 1400 MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1401 1401 cmd->cmd_rfm = NULL;
1402 1402 MPTSAS_START_CMD(mpt, request_desc);
1403 1403
1404 1404 rvalue = 0;
1405 1405 (void) cv_reltimedwait(&mpt->m_fw_cv, &mpt->m_mutex,
1406 1406 drv_usectohz(60 * MICROSEC), TR_CLOCK_TICK);
1407 1407 if (!(cmd->cmd_flags & CFLAG_FINISHED)) {
1408 1408 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
1409 - if ((mptsas_restart_ioc(mpt)) == DDI_FAILURE) {
1410 - mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
1409 + if ((mptsas_reset_handler(mpt)) == DDI_FAILURE) {
1410 + mptsas_log(mpt, CE_WARN, "mptsas_reset_handler failed");
1411 1411 }
1412 1412 rvalue = -1;
1413 1413 }
1414 1414 mptsas_remove_cmd(mpt, cmd);
1415 1415 mptsas_dma_addr_destroy(&flsh_dma_handle, &flsh_accessp);
1416 1416
1417 1417 return (rvalue);
1418 1418 }
1419 1419
1420 1420 static int
1421 1421 mptsas_sasdevpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1422 1422 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1423 1423 va_list ap)
1424 1424 {
1425 1425 #ifndef __lock_lint
1426 1426 _NOTE(ARGUNUSED(ap))
1427 1427 #endif
1428 1428 pMpi2SasDevicePage0_t sasdevpage;
1429 1429 int rval = DDI_SUCCESS, i;
1430 1430 uint8_t *sas_addr = NULL;
1431 1431 uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1432 1432 uint16_t *devhdl, *bay_num, *enclosure;
1433 1433 uint64_t *sas_wwn;
1434 1434 uint32_t *dev_info;
1435 1435 uint8_t *physport, *phynum;
1436 1436 uint16_t *pdevhdl, *io_flags;
1437 1437 uint32_t page_address;
1438 1438
1439 1439 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1440 1440 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1441 1441 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_device_page0 "
1442 1442 "header: IOCStatus=0x%x, IOCLogInfo=0x%x",
1443 1443 iocstatus, iocloginfo);
1444 1444 rval = DDI_FAILURE;
1445 1445 return (rval);
1446 1446 }
1447 1447 page_address = va_arg(ap, uint32_t);
1448 1448 /*
1449 1449 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
1450 1450 * are no more pages. If everything is OK up to this point but the
1451 1451 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
1452 1452 * signal that device traversal is complete.
1453 1453 */
1454 1454 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
1455 1455 if ((page_address & MPI2_SAS_DEVICE_PGAD_FORM_MASK) ==
1456 1456 MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE) {
1457 1457 mpt->m_done_traverse_dev = 1;
1458 1458 }
1459 1459 rval = DDI_FAILURE;
1460 1460 return (rval);
1461 1461 }
1462 1462 devhdl = va_arg(ap, uint16_t *);
1463 1463 sas_wwn = va_arg(ap, uint64_t *);
1464 1464 dev_info = va_arg(ap, uint32_t *);
1465 1465 physport = va_arg(ap, uint8_t *);
1466 1466 phynum = va_arg(ap, uint8_t *);
1467 1467 pdevhdl = va_arg(ap, uint16_t *);
1468 1468 bay_num = va_arg(ap, uint16_t *);
1469 1469 enclosure = va_arg(ap, uint16_t *);
1470 1470 io_flags = va_arg(ap, uint16_t *);
1471 1471
1472 1472 sasdevpage = (pMpi2SasDevicePage0_t)page_memp;
1473 1473
1474 1474 *dev_info = ddi_get32(accessp, &sasdevpage->DeviceInfo);
1475 1475 *devhdl = ddi_get16(accessp, &sasdevpage->DevHandle);
1476 1476 sas_addr = (uint8_t *)(&sasdevpage->SASAddress);
1477 1477 for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1478 1478 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1479 1479 }
1480 1480 bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1481 1481 *sas_wwn = LE_64(*sas_wwn);
1482 1482 *physport = ddi_get8(accessp, &sasdevpage->PhysicalPort);
1483 1483 *phynum = ddi_get8(accessp, &sasdevpage->PhyNum);
1484 1484 *pdevhdl = ddi_get16(accessp, &sasdevpage->ParentDevHandle);
1485 1485 *bay_num = ddi_get16(accessp, &sasdevpage->Slot);
1486 1486 *enclosure = ddi_get16(accessp, &sasdevpage->EnclosureHandle);
1487 1487 *io_flags = ddi_get16(accessp, &sasdevpage->Flags);
1488 1488
1489 1489 if (*io_flags & MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE) {
1490 1490 /*
1491 1491 * Leave a messages about FP cabability in the log.
1492 1492 */
1493 1493 mptsas_log(mpt, CE_CONT,
1494 1494 "!w%016"PRIx64" FastPath Capable%s", *sas_wwn,
1495 1495 (*io_flags &
1496 1496 MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH)?
1497 1497 " and Enabled":" but Disabled");
1498 1498 }
1499 1499
1500 1500 return (rval);
1501 1501 }
1502 1502
1503 1503 /*
1504 1504 * Request MPI configuration page SAS device page 0 to get DevHandle, device
1505 1505 * info and SAS address.
1506 1506 */
1507 1507 int
1508 1508 mptsas_get_sas_device_page0(mptsas_t *mpt, uint32_t page_address,
1509 1509 uint16_t *dev_handle, uint64_t *sas_wwn, uint32_t *dev_info,
1510 1510 uint8_t *physport, uint8_t *phynum, uint16_t *pdev_handle,
1511 1511 uint16_t *bay_num, uint16_t *enclosure, uint16_t *io_flags)
1512 1512 {
1513 1513 int rval = DDI_SUCCESS;
1514 1514
1515 1515 ASSERT(mutex_owned(&mpt->m_mutex));
1516 1516
1517 1517 /*
1518 1518 * Get the header and config page. reply contains the reply frame,
1519 1519 * which holds status info for the request.
1520 1520 */
1521 1521 rval = mptsas_access_config_page(mpt,
1522 1522 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1523 1523 MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0, page_address,
1524 1524 mptsas_sasdevpage_0_cb, page_address, dev_handle, sas_wwn,
1525 1525 dev_info, physport, phynum, pdev_handle,
1526 1526 bay_num, enclosure, io_flags);
1527 1527
1528 1528 return (rval);
1529 1529 }
1530 1530
1531 1531 static int
1532 1532 mptsas_sasexpdpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1533 1533 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1534 1534 va_list ap)
1535 1535 {
1536 1536 #ifndef __lock_lint
1537 1537 _NOTE(ARGUNUSED(ap))
1538 1538 #endif
1539 1539 pMpi2ExpanderPage0_t expddevpage;
1540 1540 int rval = DDI_SUCCESS, i;
1541 1541 uint8_t *sas_addr = NULL;
1542 1542 uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1543 1543 uint16_t *devhdl;
1544 1544 uint64_t *sas_wwn;
1545 1545 uint8_t physport;
1546 1546 mptsas_phymask_t *phymask;
1547 1547 uint16_t *pdevhdl;
1548 1548 uint32_t page_address;
1549 1549
1550 1550 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1551 1551 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1552 1552 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page0 "
1553 1553 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1554 1554 iocstatus, iocloginfo);
1555 1555 rval = DDI_FAILURE;
1556 1556 return (rval);
1557 1557 }
1558 1558 page_address = va_arg(ap, uint32_t);
1559 1559 /*
1560 1560 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
1561 1561 * are no more pages. If everything is OK up to this point but the
1562 1562 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
1563 1563 * signal that device traversal is complete.
1564 1564 */
1565 1565 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
1566 1566 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
1567 1567 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
1568 1568 mpt->m_done_traverse_smp = 1;
1569 1569 }
1570 1570 rval = DDI_FAILURE;
1571 1571 return (rval);
1572 1572 }
1573 1573 devhdl = va_arg(ap, uint16_t *);
1574 1574 sas_wwn = va_arg(ap, uint64_t *);
1575 1575 phymask = va_arg(ap, mptsas_phymask_t *);
1576 1576 pdevhdl = va_arg(ap, uint16_t *);
1577 1577
1578 1578 expddevpage = (pMpi2ExpanderPage0_t)page_memp;
1579 1579
1580 1580 *devhdl = ddi_get16(accessp, &expddevpage->DevHandle);
1581 1581 physport = ddi_get8(accessp, &expddevpage->PhysicalPort);
1582 1582 *phymask = mptsas_physport_to_phymask(mpt, physport);
1583 1583 *pdevhdl = ddi_get16(accessp, &expddevpage->ParentDevHandle);
1584 1584 sas_addr = (uint8_t *)(&expddevpage->SASAddress);
1585 1585 for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1586 1586 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1587 1587 }
1588 1588 bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1589 1589 *sas_wwn = LE_64(*sas_wwn);
1590 1590
1591 1591 return (rval);
1592 1592 }
1593 1593
1594 1594 /*
1595 1595 * Request MPI configuration page SAS device page 0 to get DevHandle, phymask
1596 1596 * and SAS address.
1597 1597 */
1598 1598 int
1599 1599 mptsas_get_sas_expander_page0(mptsas_t *mpt, uint32_t page_address,
1600 1600 mptsas_smp_t *info)
1601 1601 {
1602 1602 int rval = DDI_SUCCESS;
1603 1603
1604 1604 ASSERT(mutex_owned(&mpt->m_mutex));
1605 1605
1606 1606 /*
1607 1607 * Get the header and config page. reply contains the reply frame,
1608 1608 * which holds status info for the request.
1609 1609 */
1610 1610 rval = mptsas_access_config_page(mpt,
1611 1611 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1612 1612 MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 0, page_address,
1613 1613 mptsas_sasexpdpage_0_cb, page_address, &info->m_devhdl,
1614 1614 &info->m_addr.mta_wwn, &info->m_addr.mta_phymask, &info->m_pdevhdl);
1615 1615
1616 1616 return (rval);
1617 1617 }
1618 1618
1619 1619 static int
1620 1620 mptsas_sasportpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1621 1621 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1622 1622 va_list ap)
1623 1623 {
1624 1624 #ifndef __lock_lint
1625 1625 _NOTE(ARGUNUSED(ap))
1626 1626 #endif
1627 1627 int rval = DDI_SUCCESS, i;
1628 1628 uint8_t *sas_addr = NULL;
1629 1629 uint64_t *sas_wwn;
1630 1630 uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1631 1631 uint8_t *portwidth;
1632 1632 pMpi2SasPortPage0_t sasportpage;
1633 1633
1634 1634 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1635 1635 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_port_page0 "
1636 1636 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1637 1637 iocstatus, iocloginfo);
1638 1638 rval = DDI_FAILURE;
1639 1639 return (rval);
1640 1640 }
1641 1641 sas_wwn = va_arg(ap, uint64_t *);
1642 1642 portwidth = va_arg(ap, uint8_t *);
1643 1643
1644 1644 sasportpage = (pMpi2SasPortPage0_t)page_memp;
1645 1645 sas_addr = (uint8_t *)(&sasportpage->SASAddress);
1646 1646 for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1647 1647 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1648 1648 }
1649 1649 bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1650 1650 *sas_wwn = LE_64(*sas_wwn);
1651 1651 *portwidth = ddi_get8(accessp, &sasportpage->PortWidth);
1652 1652 return (rval);
1653 1653 }
1654 1654
1655 1655 /*
1656 1656 * Request MPI configuration page SAS port page 0 to get initiator SAS address
1657 1657 * and port width.
1658 1658 */
1659 1659 int
1660 1660 mptsas_get_sas_port_page0(mptsas_t *mpt, uint32_t page_address,
1661 1661 uint64_t *sas_wwn, uint8_t *portwidth)
1662 1662 {
1663 1663 int rval = DDI_SUCCESS;
1664 1664
1665 1665 ASSERT(mutex_owned(&mpt->m_mutex));
1666 1666
1667 1667 /*
1668 1668 * Get the header and config page. reply contains the reply frame,
1669 1669 * which holds status info for the request.
1670 1670 */
1671 1671 rval = mptsas_access_config_page(mpt,
1672 1672 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1673 1673 MPI2_CONFIG_EXTPAGETYPE_SAS_PORT, 0, page_address,
1674 1674 mptsas_sasportpage_0_cb, sas_wwn, portwidth);
1675 1675
1676 1676 return (rval);
1677 1677 }
1678 1678
1679 1679 static int
1680 1680 mptsas_sasiou_page_0_cb(mptsas_t *mpt, caddr_t page_memp,
1681 1681 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1682 1682 va_list ap)
1683 1683 {
1684 1684 #ifndef __lock_lint
1685 1685 _NOTE(ARGUNUSED(ap))
1686 1686 #endif
1687 1687 int rval = DDI_SUCCESS;
1688 1688 pMpi2SasIOUnitPage0_t sasioupage0;
1689 1689 int i, num_phys;
1690 1690 uint32_t cpdi[MPTSAS_MAX_PHYS], *retrypage0, *readpage1;
1691 1691 uint8_t port_flags;
1692 1692
1693 1693 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1694 1694 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_io_unit_page0 "
1695 1695 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1696 1696 iocstatus, iocloginfo);
1697 1697 rval = DDI_FAILURE;
1698 1698 return (rval);
1699 1699 }
1700 1700 readpage1 = va_arg(ap, uint32_t *);
1701 1701 retrypage0 = va_arg(ap, uint32_t *);
1702 1702
1703 1703 sasioupage0 = (pMpi2SasIOUnitPage0_t)page_memp;
1704 1704
1705 1705 num_phys = ddi_get8(accessp, &sasioupage0->NumPhys);
1706 1706 /*
1707 1707 * ASSERT that the num_phys value in SAS IO Unit Page 0 is the same as
1708 1708 * was initially set. This should never change throughout the life of
1709 1709 * the driver.
1710 1710 */
1711 1711 ASSERT(num_phys == mpt->m_num_phys);
1712 1712 for (i = 0; i < num_phys; i++) {
1713 1713 cpdi[i] = ddi_get32(accessp,
1714 1714 &sasioupage0->PhyData[i].
1715 1715 ControllerPhyDeviceInfo);
1716 1716 port_flags = ddi_get8(accessp,
1717 1717 &sasioupage0->PhyData[i].PortFlags);
1718 1718 mpt->m_phy_info[i].port_num =
1719 1719 ddi_get8(accessp,
1720 1720 &sasioupage0->PhyData[i].Port);
1721 1721 mpt->m_phy_info[i].ctrl_devhdl =
1722 1722 ddi_get16(accessp, &sasioupage0->
1723 1723 PhyData[i].ControllerDevHandle);
1724 1724 mpt->m_phy_info[i].attached_devhdl =
1725 1725 ddi_get16(accessp, &sasioupage0->
1726 1726 PhyData[i].AttachedDevHandle);
1727 1727 mpt->m_phy_info[i].phy_device_type = cpdi[i];
1728 1728 mpt->m_phy_info[i].port_flags = port_flags;
1729 1729
1730 1730 if (port_flags & DISCOVERY_IN_PROGRESS) {
1731 1731 *retrypage0 = *retrypage0 + 1;
1732 1732 break;
1733 1733 } else {
1734 1734 *retrypage0 = 0;
1735 1735 }
1736 1736 if (!(port_flags & AUTO_PORT_CONFIGURATION)) {
1737 1737 /*
1738 1738 * some PHY configuration described in
1739 1739 * SAS IO Unit Page1
1740 1740 */
1741 1741 *readpage1 = 1;
1742 1742 }
1743 1743 }
1744 1744
1745 1745 return (rval);
1746 1746 }
1747 1747
1748 1748 static int
1749 1749 mptsas_sasiou_page_1_cb(mptsas_t *mpt, caddr_t page_memp,
1750 1750 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1751 1751 va_list ap)
1752 1752 {
1753 1753 #ifndef __lock_lint
1754 1754 _NOTE(ARGUNUSED(ap))
1755 1755 #endif
1756 1756 int rval = DDI_SUCCESS;
1757 1757 pMpi2SasIOUnitPage1_t sasioupage1;
1758 1758 int i, num_phys;
1759 1759 uint32_t cpdi[MPTSAS_MAX_PHYS];
1760 1760 uint8_t port_flags;
1761 1761
1762 1762 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1763 1763 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_io_unit_page1 "
1764 1764 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1765 1765 iocstatus, iocloginfo);
1766 1766 rval = DDI_FAILURE;
1767 1767 return (rval);
1768 1768 }
1769 1769
1770 1770 sasioupage1 = (pMpi2SasIOUnitPage1_t)page_memp;
1771 1771 num_phys = ddi_get8(accessp, &sasioupage1->NumPhys);
1772 1772 /*
1773 1773 * ASSERT that the num_phys value in SAS IO Unit Page 1 is the same as
1774 1774 * was initially set. This should never change throughout the life of
1775 1775 * the driver.
1776 1776 */
1777 1777 ASSERT(num_phys == mpt->m_num_phys);
1778 1778 for (i = 0; i < num_phys; i++) {
1779 1779 cpdi[i] = ddi_get32(accessp, &sasioupage1->PhyData[i].
1780 1780 ControllerPhyDeviceInfo);
1781 1781 port_flags = ddi_get8(accessp,
1782 1782 &sasioupage1->PhyData[i].PortFlags);
1783 1783 mpt->m_phy_info[i].port_num =
1784 1784 ddi_get8(accessp,
1785 1785 &sasioupage1->PhyData[i].Port);
1786 1786 mpt->m_phy_info[i].port_flags = port_flags;
1787 1787 mpt->m_phy_info[i].phy_device_type = cpdi[i];
1788 1788 }
1789 1789 return (rval);
1790 1790 }
1791 1791
1792 1792 /*
1793 1793 * Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
1794 1794 * page1 to update the PHY information. This is the message passing method of
1795 1795 * this function which should be called except during initialization.
1796 1796 */
1797 1797 int
1798 1798 mptsas_get_sas_io_unit_page(mptsas_t *mpt)
1799 1799 {
1800 1800 int rval = DDI_SUCCESS, state;
1801 1801 uint32_t readpage1 = 0, retrypage0 = 0;
1802 1802
1803 1803 ASSERT(mutex_owned(&mpt->m_mutex));
1804 1804
1805 1805 /*
1806 1806 * Now we cycle through the state machine. Here's what happens:
1807 1807 * 1. Read IO unit page 0 and set phy information
1808 1808 * 2. See if Read IO unit page1 is needed because of port configuration
1809 1809 * 3. Read IO unit page 1 and update phy information.
1810 1810 */
1811 1811 state = IOUC_READ_PAGE0;
1812 1812 while (state != IOUC_DONE) {
1813 1813 if (state == IOUC_READ_PAGE0) {
1814 1814 rval = mptsas_access_config_page(mpt,
1815 1815 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1816 1816 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, 0,
1817 1817 mptsas_sasiou_page_0_cb, &readpage1,
1818 1818 &retrypage0);
1819 1819 } else if (state == IOUC_READ_PAGE1) {
1820 1820 rval = mptsas_access_config_page(mpt,
1821 1821 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1822 1822 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 1, 0,
1823 1823 mptsas_sasiou_page_1_cb);
1824 1824 }
1825 1825
1826 1826 if (rval == DDI_SUCCESS) {
1827 1827 switch (state) {
1828 1828 case IOUC_READ_PAGE0:
1829 1829 /*
1830 1830 * retry 30 times if discovery is in process
1831 1831 */
1832 1832 if (retrypage0 && (retrypage0 < 30)) {
1833 1833 drv_usecwait(1000 * 100);
1834 1834 state = IOUC_READ_PAGE0;
1835 1835 break;
1836 1836 } else if (retrypage0 == 30) {
1837 1837 mptsas_log(mpt, CE_WARN,
1838 1838 "!Discovery in progress, can't "
1839 1839 "verify IO unit config, then "
1840 1840 "after 30 times retry, give "
1841 1841 "up!");
1842 1842 state = IOUC_DONE;
1843 1843 rval = DDI_FAILURE;
1844 1844 break;
1845 1845 }
1846 1846
1847 1847 if (readpage1 == 0) {
1848 1848 state = IOUC_DONE;
1849 1849 rval = DDI_SUCCESS;
1850 1850 break;
1851 1851 }
1852 1852
1853 1853 state = IOUC_READ_PAGE1;
1854 1854 break;
1855 1855
1856 1856 case IOUC_READ_PAGE1:
1857 1857 state = IOUC_DONE;
1858 1858 rval = DDI_SUCCESS;
1859 1859 break;
1860 1860 }
1861 1861 } else {
1862 1862 return (rval);
1863 1863 }
1864 1864 }
1865 1865
1866 1866 return (rval);
1867 1867 }
1868 1868
1869 1869 static int
1870 1870 mptsas_biospage_3_cb(mptsas_t *mpt, caddr_t page_memp,
1871 1871 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1872 1872 va_list ap)
1873 1873 {
1874 1874 #ifndef __lock_lint
1875 1875 _NOTE(ARGUNUSED(ap))
1876 1876 #endif
1877 1877 pMpi2BiosPage3_t sasbiospage;
1878 1878 int rval = DDI_SUCCESS;
1879 1879 uint32_t *bios_version;
1880 1880
1881 1881 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1882 1882 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1883 1883 mptsas_log(mpt, CE_WARN, "mptsas_get_bios_page3 header: "
1884 1884 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus, iocloginfo);
1885 1885 rval = DDI_FAILURE;
1886 1886 return (rval);
1887 1887 }
1888 1888 bios_version = va_arg(ap, uint32_t *);
1889 1889 sasbiospage = (pMpi2BiosPage3_t)page_memp;
1890 1890 *bios_version = ddi_get32(accessp, &sasbiospage->BiosVersion);
1891 1891
1892 1892 return (rval);
1893 1893 }
1894 1894
1895 1895 /*
1896 1896 * Request MPI configuration page BIOS page 3 to get BIOS version. Since all
1897 1897 * other information in this page is not needed, just ignore it.
1898 1898 */
1899 1899 int
1900 1900 mptsas_get_bios_page3(mptsas_t *mpt, uint32_t *bios_version)
1901 1901 {
1902 1902 int rval = DDI_SUCCESS;
1903 1903
1904 1904 ASSERT(mutex_owned(&mpt->m_mutex));
1905 1905
1906 1906 /*
1907 1907 * Get the header and config page. reply contains the reply frame,
1908 1908 * which holds status info for the request.
1909 1909 */
1910 1910 rval = mptsas_access_config_page(mpt,
1911 1911 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT, MPI2_CONFIG_PAGETYPE_BIOS, 3,
1912 1912 0, mptsas_biospage_3_cb, bios_version);
1913 1913
1914 1914 return (rval);
1915 1915 }
1916 1916
1917 1917 /*
1918 1918 * Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
1919 1919 * page1 to update the PHY information. This is the handshaking version of
1920 1920 * this function, which should be called during initialization only.
1921 1921 */
1922 1922 int
1923 1923 mptsas_get_sas_io_unit_page_hndshk(mptsas_t *mpt)
1924 1924 {
1925 1925 ddi_dma_attr_t recv_dma_attrs, page_dma_attrs;
1926 1926 ddi_dma_cookie_t page_cookie;
1927 1927 ddi_dma_handle_t recv_dma_handle, page_dma_handle;
1928 1928 ddi_acc_handle_t recv_accessp, page_accessp;
1929 1929 pMpi2ConfigReply_t configreply;
1930 1930 pMpi2SasIOUnitPage0_t sasioupage0;
1931 1931 pMpi2SasIOUnitPage1_t sasioupage1;
1932 1932 int recv_numbytes;
1933 1933 caddr_t recv_memp, page_memp;
1934 1934 int i, num_phys, start_phy = 0;
1935 1935 int page0_size =
1936 1936 sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_0) +
1937 1937 (sizeof (MPI2_SAS_IO_UNIT0_PHY_DATA) * (MPTSAS_MAX_PHYS - 1));
1938 1938 int page1_size =
1939 1939 sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_1) +
1940 1940 (sizeof (MPI2_SAS_IO_UNIT1_PHY_DATA) * (MPTSAS_MAX_PHYS - 1));
1941 1941 uint32_t flags_length;
1942 1942 uint32_t cpdi[MPTSAS_MAX_PHYS];
1943 1943 uint32_t readpage1 = 0, retrypage0 = 0;
1944 1944 uint16_t iocstatus;
1945 1945 uint8_t port_flags, page_number, action;
1946 1946 uint32_t reply_size = 256; /* Big enough for any page */
1947 1947 uint_t state;
1948 1948 int rval = DDI_FAILURE;
1949 1949 boolean_t free_recv = B_FALSE, free_page = B_FALSE;
1950 1950
1951 1951 /*
1952 1952 * Initialize our "state machine". This is a bit convoluted,
1953 1953 * but it keeps us from having to do the ddi allocations numerous
1954 1954 * times.
1955 1955 */
1956 1956
1957 1957 NDBG20(("mptsas_get_sas_io_unit_page_hndshk enter"));
1958 1958 ASSERT(mutex_owned(&mpt->m_mutex));
1959 1959 state = IOUC_READ_PAGE0;
1960 1960
1961 1961 /*
1962 1962 * dynamically create a customized dma attribute structure
1963 1963 * that describes mpt's config reply page request structure.
1964 1964 */
1965 1965 recv_dma_attrs = mpt->m_msg_dma_attr;
1966 1966 recv_dma_attrs.dma_attr_sgllen = 1;
1967 1967 recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
1968 1968
1969 1969 if (mptsas_dma_addr_create(mpt, recv_dma_attrs,
1970 1970 &recv_dma_handle, &recv_accessp, &recv_memp,
1971 1971 (sizeof (MPI2_CONFIG_REPLY)), NULL) == FALSE) {
1972 1972 mptsas_log(mpt, CE_WARN,
1973 1973 "mptsas_get_sas_io_unit_page_hndshk: recv dma failed");
1974 1974 goto cleanup;
1975 1975 }
1976 1976 /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
1977 1977 free_recv = B_TRUE;
1978 1978
1979 1979 page_dma_attrs = mpt->m_msg_dma_attr;
1980 1980 page_dma_attrs.dma_attr_sgllen = 1;
1981 1981 page_dma_attrs.dma_attr_granular = reply_size;
1982 1982
1983 1983 if (mptsas_dma_addr_create(mpt, page_dma_attrs,
1984 1984 &page_dma_handle, &page_accessp, &page_memp,
1985 1985 reply_size, &page_cookie) == FALSE) {
1986 1986 mptsas_log(mpt, CE_WARN,
1987 1987 "mptsas_get_sas_io_unit_page_hndshk: page dma failed");
1988 1988 goto cleanup;
1989 1989 }
1990 1990 /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
1991 1991 free_page = B_TRUE;
1992 1992
1993 1993 /*
1994 1994 * Now we cycle through the state machine. Here's what happens:
1995 1995 * 1. Read IO unit page 0 and set phy information
1996 1996 * 2. See if Read IO unit page1 is needed because of port configuration
1997 1997 * 3. Read IO unit page 1 and update phy information.
1998 1998 */
1999 1999
2000 2000 sasioupage0 = (pMpi2SasIOUnitPage0_t)page_memp;
2001 2001 sasioupage1 = (pMpi2SasIOUnitPage1_t)page_memp;
2002 2002
2003 2003 while (state != IOUC_DONE) {
2004 2004 switch (state) {
2005 2005 case IOUC_READ_PAGE0:
2006 2006 page_number = 0;
2007 2007 action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
2008 2008 flags_length = (uint32_t)page0_size;
2009 2009 flags_length |= ((uint32_t)(
2010 2010 MPI2_SGE_FLAGS_LAST_ELEMENT |
2011 2011 MPI2_SGE_FLAGS_END_OF_BUFFER |
2012 2012 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2013 2013 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
2014 2014 MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
2015 2015 MPI2_SGE_FLAGS_IOC_TO_HOST |
2016 2016 MPI2_SGE_FLAGS_END_OF_LIST) <<
2017 2017 MPI2_SGE_FLAGS_SHIFT);
2018 2018
2019 2019 break;
2020 2020
2021 2021 case IOUC_READ_PAGE1:
2022 2022 page_number = 1;
2023 2023 action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
2024 2024 flags_length = (uint32_t)page1_size;
2025 2025 flags_length |= ((uint32_t)(
2026 2026 MPI2_SGE_FLAGS_LAST_ELEMENT |
2027 2027 MPI2_SGE_FLAGS_END_OF_BUFFER |
2028 2028 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2029 2029 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
2030 2030 MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
2031 2031 MPI2_SGE_FLAGS_IOC_TO_HOST |
2032 2032 MPI2_SGE_FLAGS_END_OF_LIST) <<
2033 2033 MPI2_SGE_FLAGS_SHIFT);
2034 2034
2035 2035 break;
2036 2036 default:
2037 2037 break;
2038 2038 }
2039 2039
2040 2040 bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2041 2041 configreply = (pMpi2ConfigReply_t)recv_memp;
2042 2042 recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2043 2043
2044 2044 if (mptsas_send_extended_config_request_msg(mpt,
2045 2045 MPI2_CONFIG_ACTION_PAGE_HEADER,
2046 2046 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
2047 2047 0, page_number, 0, 0, 0, 0)) {
2048 2048 goto cleanup;
2049 2049 }
2050 2050
2051 2051 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2052 2052 recv_accessp)) {
2053 2053 goto cleanup;
2054 2054 }
2055 2055
2056 2056 iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus);
2057 2057 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
2058 2058
2059 2059 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
2060 2060 mptsas_log(mpt, CE_WARN,
2061 2061 "mptsas_get_sas_io_unit_page_hndshk: read page "
2062 2062 "header iocstatus = 0x%x", iocstatus);
2063 2063 goto cleanup;
2064 2064 }
2065 2065
2066 2066 if (action != MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
2067 2067 bzero(page_memp, reply_size);
2068 2068 }
2069 2069
2070 2070 if (mptsas_send_extended_config_request_msg(mpt, action,
2071 2071 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, page_number,
2072 2072 ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2073 2073 ddi_get16(recv_accessp, &configreply->ExtPageLength),
2074 2074 flags_length, page_cookie.dmac_laddress)) {
2075 2075 goto cleanup;
2076 2076 }
2077 2077
2078 2078 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2079 2079 recv_accessp)) {
2080 2080 goto cleanup;
2081 2081 }
2082 2082
2083 2083 iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus);
2084 2084 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
2085 2085
2086 2086 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
2087 2087 mptsas_log(mpt, CE_WARN,
2088 2088 "mptsas_get_sas_io_unit_page_hndshk: IO unit "
2089 2089 "config failed for action %d, iocstatus = 0x%x",
2090 2090 action, iocstatus);
2091 2091 goto cleanup;
2092 2092 }
2093 2093
2094 2094 switch (state) {
2095 2095 case IOUC_READ_PAGE0:
2096 2096 if ((ddi_dma_sync(page_dma_handle, 0, 0,
2097 2097 DDI_DMA_SYNC_FORCPU)) != DDI_SUCCESS) {
2098 2098 goto cleanup;
2099 2099 }
2100 2100
2101 2101 num_phys = ddi_get8(page_accessp,
2102 2102 &sasioupage0->NumPhys);
2103 2103 ASSERT(num_phys == mpt->m_num_phys);
2104 2104 if (num_phys > MPTSAS_MAX_PHYS) {
2105 2105 mptsas_log(mpt, CE_WARN, "Number of phys "
2106 2106 "supported by HBA (%d) is more than max "
2107 2107 "supported by driver (%d). Driver will "
2108 2108 "not attach.", num_phys,
2109 2109 MPTSAS_MAX_PHYS);
2110 2110 rval = DDI_FAILURE;
2111 2111 goto cleanup;
2112 2112 }
2113 2113 for (i = start_phy; i < num_phys; i++, start_phy = i) {
2114 2114 cpdi[i] = ddi_get32(page_accessp,
2115 2115 &sasioupage0->PhyData[i].
2116 2116 ControllerPhyDeviceInfo);
2117 2117 port_flags = ddi_get8(page_accessp,
2118 2118 &sasioupage0->PhyData[i].PortFlags);
2119 2119
2120 2120 mpt->m_phy_info[i].port_num =
2121 2121 ddi_get8(page_accessp,
2122 2122 &sasioupage0->PhyData[i].Port);
2123 2123 mpt->m_phy_info[i].ctrl_devhdl =
2124 2124 ddi_get16(page_accessp, &sasioupage0->
2125 2125 PhyData[i].ControllerDevHandle);
2126 2126 mpt->m_phy_info[i].attached_devhdl =
2127 2127 ddi_get16(page_accessp, &sasioupage0->
2128 2128 PhyData[i].AttachedDevHandle);
2129 2129 mpt->m_phy_info[i].phy_device_type = cpdi[i];
2130 2130 mpt->m_phy_info[i].port_flags = port_flags;
2131 2131
2132 2132 if (port_flags & DISCOVERY_IN_PROGRESS) {
2133 2133 retrypage0++;
2134 2134 NDBG20(("Discovery in progress, can't "
2135 2135 "verify IO unit config, then NO.%d"
2136 2136 " times retry", retrypage0));
2137 2137 break;
2138 2138 } else {
2139 2139 retrypage0 = 0;
2140 2140 }
2141 2141 if (!(port_flags & AUTO_PORT_CONFIGURATION)) {
2142 2142 /*
2143 2143 * some PHY configuration described in
2144 2144 * SAS IO Unit Page1
2145 2145 */
2146 2146 readpage1 = 1;
2147 2147 }
2148 2148 }
2149 2149
2150 2150 /*
2151 2151 * retry 30 times if discovery is in process
2152 2152 */
2153 2153 if (retrypage0 && (retrypage0 < 30)) {
2154 2154 drv_usecwait(1000 * 100);
2155 2155 state = IOUC_READ_PAGE0;
2156 2156 break;
2157 2157 } else if (retrypage0 == 30) {
2158 2158 mptsas_log(mpt, CE_WARN,
2159 2159 "!Discovery in progress, can't "
2160 2160 "verify IO unit config, then after"
2161 2161 " 30 times retry, give up!");
2162 2162 state = IOUC_DONE;
2163 2163 rval = DDI_FAILURE;
2164 2164 break;
2165 2165 }
2166 2166
2167 2167 if (readpage1 == 0) {
2168 2168 state = IOUC_DONE;
2169 2169 rval = DDI_SUCCESS;
2170 2170 break;
2171 2171 }
2172 2172
2173 2173 state = IOUC_READ_PAGE1;
2174 2174 break;
2175 2175
2176 2176 case IOUC_READ_PAGE1:
2177 2177 if ((ddi_dma_sync(page_dma_handle, 0, 0,
2178 2178 DDI_DMA_SYNC_FORCPU)) != DDI_SUCCESS) {
2179 2179 goto cleanup;
2180 2180 }
2181 2181
2182 2182 num_phys = ddi_get8(page_accessp,
2183 2183 &sasioupage1->NumPhys);
2184 2184 ASSERT(num_phys == mpt->m_num_phys);
2185 2185 if (num_phys > MPTSAS_MAX_PHYS) {
2186 2186 mptsas_log(mpt, CE_WARN, "Number of phys "
2187 2187 "supported by HBA (%d) is more than max "
2188 2188 "supported by driver (%d). Driver will "
2189 2189 "not attach.", num_phys,
2190 2190 MPTSAS_MAX_PHYS);
2191 2191 rval = DDI_FAILURE;
2192 2192 goto cleanup;
2193 2193 }
2194 2194 for (i = 0; i < num_phys; i++) {
2195 2195 cpdi[i] = ddi_get32(page_accessp,
2196 2196 &sasioupage1->PhyData[i].
2197 2197 ControllerPhyDeviceInfo);
2198 2198 port_flags = ddi_get8(page_accessp,
2199 2199 &sasioupage1->PhyData[i].PortFlags);
2200 2200 mpt->m_phy_info[i].port_num =
2201 2201 ddi_get8(page_accessp,
2202 2202 &sasioupage1->PhyData[i].Port);
2203 2203 mpt->m_phy_info[i].port_flags = port_flags;
2204 2204 mpt->m_phy_info[i].phy_device_type = cpdi[i];
2205 2205
2206 2206 }
2207 2207
2208 2208 state = IOUC_DONE;
2209 2209 rval = DDI_SUCCESS;
2210 2210 break;
2211 2211 }
2212 2212 }
2213 2213 if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2214 2214 (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2215 2215 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2216 2216 rval = DDI_FAILURE;
2217 2217 goto cleanup;
2218 2218 }
2219 2219 if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2220 2220 (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2221 2221 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2222 2222 rval = DDI_FAILURE;
2223 2223 goto cleanup;
2224 2224 }
2225 2225
2226 2226 cleanup:
2227 2227 if (free_recv)
2228 2228 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2229 2229 if (free_page)
2230 2230 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2231 2231 if (rval != DDI_SUCCESS) {
2232 2232 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
2233 2233 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
2234 2234 }
2235 2235 return (rval);
2236 2236 }
2237 2237
2238 2238 /*
2239 2239 * mptsas_get_manufacture_page5
2240 2240 *
2241 2241 * This function will retrieve the base WWID from the adapter. Since this
2242 2242 * function is only called during the initialization process, use handshaking.
2243 2243 */
2244 2244 int
2245 2245 mptsas_get_manufacture_page5(mptsas_t *mpt)
2246 2246 {
2247 2247 ddi_dma_attr_t recv_dma_attrs, page_dma_attrs;
2248 2248 ddi_dma_cookie_t page_cookie;
2249 2249 ddi_dma_handle_t recv_dma_handle, page_dma_handle;
2250 2250 ddi_acc_handle_t recv_accessp, page_accessp;
2251 2251 pMpi2ConfigReply_t configreply;
2252 2252 caddr_t recv_memp, page_memp;
2253 2253 int recv_numbytes;
2254 2254 pMpi2ManufacturingPage5_t m5;
2255 2255 uint32_t flagslength;
2256 2256 int rval = DDI_SUCCESS;
2257 2257 uint_t iocstatus;
2258 2258 boolean_t free_recv = B_FALSE, free_page = B_FALSE;
2259 2259
2260 2260 MPTSAS_DISABLE_INTR(mpt);
2261 2261
2262 2262 if (mptsas_send_config_request_msg(mpt, MPI2_CONFIG_ACTION_PAGE_HEADER,
2263 2263 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 5, 0, 0, 0, 0)) {
2264 2264 rval = DDI_FAILURE;
2265 2265 goto done;
2266 2266 }
2267 2267
2268 2268 /*
2269 2269 * dynamically create a customized dma attribute structure
2270 2270 * that describes the MPT's config reply page request structure.
2271 2271 */
2272 2272 recv_dma_attrs = mpt->m_msg_dma_attr;
2273 2273 recv_dma_attrs.dma_attr_sgllen = 1;
2274 2274 recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
2275 2275
2276 2276 if (mptsas_dma_addr_create(mpt, recv_dma_attrs,
2277 2277 &recv_dma_handle, &recv_accessp, &recv_memp,
2278 2278 (sizeof (MPI2_CONFIG_REPLY)), NULL) == FALSE) {
2279 2279 rval = DDI_FAILURE;
2280 2280 goto done;
2281 2281 }
2282 2282 /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
2283 2283 free_recv = B_TRUE;
2284 2284
2285 2285 bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2286 2286 configreply = (pMpi2ConfigReply_t)recv_memp;
2287 2287 recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2288 2288
2289 2289 /*
2290 2290 * get config reply message
2291 2291 */
2292 2292 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2293 2293 recv_accessp)) {
2294 2294 rval = DDI_FAILURE;
2295 2295 goto done;
2296 2296 }
2297 2297
2298 2298 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2299 2299 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 update: "
2300 2300 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2301 2301 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2302 2302 goto done;
2303 2303 }
2304 2304
2305 2305 /*
2306 2306 * dynamically create a customized dma attribute structure
2307 2307 * that describes the MPT's config page structure.
2308 2308 */
2309 2309 page_dma_attrs = mpt->m_msg_dma_attr;
2310 2310 page_dma_attrs.dma_attr_sgllen = 1;
2311 2311 page_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_PAGE_MAN_5));
2312 2312
2313 2313 if (mptsas_dma_addr_create(mpt, page_dma_attrs, &page_dma_handle,
2314 2314 &page_accessp, &page_memp, (sizeof (MPI2_CONFIG_PAGE_MAN_5)),
2315 2315 &page_cookie) == FALSE) {
2316 2316 rval = DDI_FAILURE;
2317 2317 goto done;
2318 2318 }
2319 2319 /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
2320 2320 free_page = B_TRUE;
2321 2321
2322 2322 bzero(page_memp, sizeof (MPI2_CONFIG_PAGE_MAN_5));
2323 2323 m5 = (pMpi2ManufacturingPage5_t)page_memp;
2324 2324 NDBG20(("mptsas_get_manufacture_page5: paddr 0x%p",
2325 2325 (void *)(uintptr_t)page_cookie.dmac_laddress));
2326 2326
2327 2327 /*
2328 2328 * Give reply address to IOC to store config page in and send
2329 2329 * config request out.
2330 2330 */
2331 2331
2332 2332 flagslength = sizeof (MPI2_CONFIG_PAGE_MAN_5);
2333 2333 flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
2334 2334 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2335 2335 MPI2_SGE_FLAGS_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
2336 2336 MPI2_SGE_FLAGS_IOC_TO_HOST |
2337 2337 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
2338 2338
2339 2339 if (mptsas_send_config_request_msg(mpt,
2340 2340 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2341 2341 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 5,
2342 2342 ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2343 2343 ddi_get8(recv_accessp, &configreply->Header.PageLength),
2344 2344 flagslength, page_cookie.dmac_laddress)) {
2345 2345 rval = DDI_FAILURE;
2346 2346 goto done;
2347 2347 }
2348 2348
2349 2349 /*
2350 2350 * get reply view handshake
2351 2351 */
2352 2352 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2353 2353 recv_accessp)) {
2354 2354 rval = DDI_FAILURE;
2355 2355 goto done;
2356 2356 }
2357 2357
2358 2358 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2359 2359 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 config: "
2360 2360 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2361 2361 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2362 2362 goto done;
2363 2363 }
2364 2364
2365 2365 (void) ddi_dma_sync(page_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
2366 2366
2367 2367 /*
2368 2368 * Fusion-MPT stores fields in little-endian format. This is
2369 2369 * why the low-order 32 bits are stored first.
2370 2370 */
2371 2371 mpt->un.sasaddr.m_base_wwid_lo =
2372 2372 ddi_get32(page_accessp, (uint32_t *)(void *)&m5->Phy[0].WWID);
2373 2373 mpt->un.sasaddr.m_base_wwid_hi =
2374 2374 ddi_get32(page_accessp, (uint32_t *)(void *)&m5->Phy[0].WWID + 1);
2375 2375
2376 2376 if (ddi_prop_update_int64(DDI_DEV_T_NONE, mpt->m_dip,
2377 2377 "base-wwid", mpt->un.m_base_wwid) != DDI_PROP_SUCCESS) {
2378 2378 NDBG2(("%s%d: failed to create base-wwid property",
2379 2379 ddi_driver_name(mpt->m_dip), ddi_get_instance(mpt->m_dip)));
2380 2380 }
2381 2381
2382 2382 /*
2383 2383 * Set the number of PHYs present.
2384 2384 */
2385 2385 mpt->m_num_phys = ddi_get8(page_accessp, (uint8_t *)&m5->NumPhys);
2386 2386
2387 2387 if (ddi_prop_update_int(DDI_DEV_T_NONE, mpt->m_dip,
2388 2388 "num-phys", mpt->m_num_phys) != DDI_PROP_SUCCESS) {
2389 2389 NDBG2(("%s%d: failed to create num-phys property",
2390 2390 ddi_driver_name(mpt->m_dip), ddi_get_instance(mpt->m_dip)));
2391 2391 }
2392 2392
2393 2393 mptsas_log(mpt, CE_NOTE, "!mpt%d: Initiator WWNs: 0x%016llx-0x%016llx",
2394 2394 mpt->m_instance, (unsigned long long)mpt->un.m_base_wwid,
2395 2395 (unsigned long long)mpt->un.m_base_wwid + mpt->m_num_phys - 1);
2396 2396
2397 2397 if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2398 2398 (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2399 2399 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2400 2400 rval = DDI_FAILURE;
2401 2401 goto done;
2402 2402 }
2403 2403 if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2404 2404 (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2405 2405 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2406 2406 rval = DDI_FAILURE;
2407 2407 }
2408 2408 done:
2409 2409 /*
2410 2410 * free up memory
2411 2411 */
2412 2412 if (free_recv)
2413 2413 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2414 2414 if (free_page)
2415 2415 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2416 2416 MPTSAS_ENABLE_INTR(mpt);
2417 2417
2418 2418 return (rval);
2419 2419 }
2420 2420
2421 2421 static int
2422 2422 mptsas_sasphypage_0_cb(mptsas_t *mpt, caddr_t page_memp,
2423 2423 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
2424 2424 va_list ap)
2425 2425 {
2426 2426 #ifndef __lock_lint
2427 2427 _NOTE(ARGUNUSED(ap))
2428 2428 #endif
2429 2429 pMpi2SasPhyPage0_t sasphypage;
2430 2430 int rval = DDI_SUCCESS;
2431 2431 uint16_t *owner_devhdl, *attached_devhdl;
2432 2432 uint8_t *attached_phy_identify;
2433 2433 uint32_t *attached_phy_info;
2434 2434 uint8_t *programmed_link_rate;
2435 2435 uint8_t *hw_link_rate;
2436 2436 uint8_t *change_count;
2437 2437 uint32_t *phy_info;
2438 2438 uint8_t *negotiated_link_rate;
2439 2439 uint32_t page_address;
2440 2440
2441 2441 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
2442 2442 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
2443 2443 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page0 "
2444 2444 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
2445 2445 iocstatus, iocloginfo);
2446 2446 rval = DDI_FAILURE;
2447 2447 return (rval);
2448 2448 }
2449 2449 page_address = va_arg(ap, uint32_t);
2450 2450 /*
2451 2451 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
2452 2452 * are no more pages. If everything is OK up to this point but the
2453 2453 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
2454 2454 * signal that device traversal is complete.
2455 2455 */
2456 2456 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
2457 2457 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
2458 2458 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
2459 2459 mpt->m_done_traverse_smp = 1;
2460 2460 }
2461 2461 rval = DDI_FAILURE;
2462 2462 return (rval);
2463 2463 }
2464 2464 owner_devhdl = va_arg(ap, uint16_t *);
2465 2465 attached_devhdl = va_arg(ap, uint16_t *);
2466 2466 attached_phy_identify = va_arg(ap, uint8_t *);
2467 2467 attached_phy_info = va_arg(ap, uint32_t *);
2468 2468 programmed_link_rate = va_arg(ap, uint8_t *);
2469 2469 hw_link_rate = va_arg(ap, uint8_t *);
2470 2470 change_count = va_arg(ap, uint8_t *);
2471 2471 phy_info = va_arg(ap, uint32_t *);
2472 2472 negotiated_link_rate = va_arg(ap, uint8_t *);
2473 2473
2474 2474 sasphypage = (pMpi2SasPhyPage0_t)page_memp;
2475 2475
2476 2476 *owner_devhdl =
2477 2477 ddi_get16(accessp, &sasphypage->OwnerDevHandle);
2478 2478 *attached_devhdl =
2479 2479 ddi_get16(accessp, &sasphypage->AttachedDevHandle);
2480 2480 *attached_phy_identify =
2481 2481 ddi_get8(accessp, &sasphypage->AttachedPhyIdentifier);
2482 2482 *attached_phy_info =
2483 2483 ddi_get32(accessp, &sasphypage->AttachedPhyInfo);
2484 2484 *programmed_link_rate =
2485 2485 ddi_get8(accessp, &sasphypage->ProgrammedLinkRate);
2486 2486 *hw_link_rate =
2487 2487 ddi_get8(accessp, &sasphypage->HwLinkRate);
2488 2488 *change_count =
2489 2489 ddi_get8(accessp, &sasphypage->ChangeCount);
2490 2490 *phy_info =
2491 2491 ddi_get32(accessp, &sasphypage->PhyInfo);
2492 2492 *negotiated_link_rate =
2493 2493 ddi_get8(accessp, &sasphypage->NegotiatedLinkRate);
2494 2494
2495 2495 return (rval);
2496 2496 }
2497 2497
2498 2498 /*
2499 2499 * Request MPI configuration page SAS phy page 0 to get DevHandle, phymask
2500 2500 * and SAS address.
2501 2501 */
2502 2502 int
2503 2503 mptsas_get_sas_phy_page0(mptsas_t *mpt, uint32_t page_address,
2504 2504 smhba_info_t *info)
2505 2505 {
2506 2506 int rval = DDI_SUCCESS;
2507 2507
2508 2508 ASSERT(mutex_owned(&mpt->m_mutex));
2509 2509
2510 2510 /*
2511 2511 * Get the header and config page. reply contains the reply frame,
2512 2512 * which holds status info for the request.
2513 2513 */
2514 2514 rval = mptsas_access_config_page(mpt,
2515 2515 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2516 2516 MPI2_CONFIG_EXTPAGETYPE_SAS_PHY, 0, page_address,
2517 2517 mptsas_sasphypage_0_cb, page_address, &info->owner_devhdl,
2518 2518 &info->attached_devhdl, &info->attached_phy_identify,
2519 2519 &info->attached_phy_info, &info->programmed_link_rate,
2520 2520 &info->hw_link_rate, &info->change_count,
2521 2521 &info->phy_info, &info->negotiated_link_rate);
2522 2522
2523 2523 return (rval);
2524 2524 }
2525 2525
2526 2526 static int
2527 2527 mptsas_sasphypage_1_cb(mptsas_t *mpt, caddr_t page_memp,
2528 2528 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
2529 2529 va_list ap)
2530 2530 {
2531 2531 #ifndef __lock_lint
2532 2532 _NOTE(ARGUNUSED(ap))
2533 2533 #endif
2534 2534 pMpi2SasPhyPage1_t sasphypage;
2535 2535 int rval = DDI_SUCCESS;
2536 2536
2537 2537 uint32_t *invalid_dword_count;
2538 2538 uint32_t *running_disparity_error_count;
2539 2539 uint32_t *loss_of_dword_sync_count;
2540 2540 uint32_t *phy_reset_problem_count;
2541 2541 uint32_t page_address;
2542 2542
2543 2543 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
2544 2544 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
2545 2545 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page1 "
2546 2546 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
2547 2547 iocstatus, iocloginfo);
2548 2548 rval = DDI_FAILURE;
2549 2549 return (rval);
2550 2550 }
2551 2551 page_address = va_arg(ap, uint32_t);
2552 2552 /*
2553 2553 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
2554 2554 * are no more pages. If everything is OK up to this point but the
2555 2555 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
2556 2556 * signal that device traversal is complete.
2557 2557 */
2558 2558 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
2559 2559 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
2560 2560 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
2561 2561 mpt->m_done_traverse_smp = 1;
2562 2562 }
2563 2563 rval = DDI_FAILURE;
2564 2564 return (rval);
2565 2565 }
2566 2566
2567 2567 invalid_dword_count = va_arg(ap, uint32_t *);
2568 2568 running_disparity_error_count = va_arg(ap, uint32_t *);
2569 2569 loss_of_dword_sync_count = va_arg(ap, uint32_t *);
2570 2570 phy_reset_problem_count = va_arg(ap, uint32_t *);
2571 2571
2572 2572 sasphypage = (pMpi2SasPhyPage1_t)page_memp;
2573 2573
2574 2574 *invalid_dword_count =
2575 2575 ddi_get32(accessp, &sasphypage->InvalidDwordCount);
2576 2576 *running_disparity_error_count =
2577 2577 ddi_get32(accessp, &sasphypage->RunningDisparityErrorCount);
2578 2578 *loss_of_dword_sync_count =
2579 2579 ddi_get32(accessp, &sasphypage->LossDwordSynchCount);
2580 2580 *phy_reset_problem_count =
2581 2581 ddi_get32(accessp, &sasphypage->PhyResetProblemCount);
2582 2582
2583 2583 return (rval);
2584 2584 }
2585 2585
2586 2586 /*
2587 2587 * Request MPI configuration page SAS phy page 0 to get DevHandle, phymask
2588 2588 * and SAS address.
2589 2589 */
2590 2590 int
2591 2591 mptsas_get_sas_phy_page1(mptsas_t *mpt, uint32_t page_address,
2592 2592 smhba_info_t *info)
2593 2593 {
2594 2594 int rval = DDI_SUCCESS;
2595 2595
2596 2596 ASSERT(mutex_owned(&mpt->m_mutex));
2597 2597
2598 2598 /*
2599 2599 * Get the header and config page. reply contains the reply frame,
2600 2600 * which holds status info for the request.
2601 2601 */
2602 2602 rval = mptsas_access_config_page(mpt,
2603 2603 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2604 2604 MPI2_CONFIG_EXTPAGETYPE_SAS_PHY, 1, page_address,
2605 2605 mptsas_sasphypage_1_cb, page_address,
2606 2606 &info->invalid_dword_count,
2607 2607 &info->running_disparity_error_count,
2608 2608 &info->loss_of_dword_sync_count,
2609 2609 &info->phy_reset_problem_count);
2610 2610
2611 2611 return (rval);
2612 2612 }
2613 2613 /*
2614 2614 * mptsas_get_manufacture_page0
2615 2615 *
2616 2616 * This function will retrieve the base
2617 2617 * Chip name, Board Name,Board Trace number from the adapter.
2618 2618 * Since this function is only called during the
2619 2619 * initialization process, use handshaking.
2620 2620 */
2621 2621 int
2622 2622 mptsas_get_manufacture_page0(mptsas_t *mpt)
2623 2623 {
2624 2624 ddi_dma_attr_t recv_dma_attrs, page_dma_attrs;
2625 2625 ddi_dma_cookie_t page_cookie;
2626 2626 ddi_dma_handle_t recv_dma_handle, page_dma_handle;
2627 2627 ddi_acc_handle_t recv_accessp, page_accessp;
2628 2628 pMpi2ConfigReply_t configreply;
2629 2629 caddr_t recv_memp, page_memp;
2630 2630 int recv_numbytes;
2631 2631 pMpi2ManufacturingPage0_t m0;
2632 2632 uint32_t flagslength;
2633 2633 int rval = DDI_SUCCESS;
2634 2634 uint_t iocstatus;
2635 2635 uint8_t i = 0;
2636 2636 boolean_t free_recv = B_FALSE, free_page = B_FALSE;
2637 2637
2638 2638 MPTSAS_DISABLE_INTR(mpt);
2639 2639
2640 2640 if (mptsas_send_config_request_msg(mpt, MPI2_CONFIG_ACTION_PAGE_HEADER,
2641 2641 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 0, 0, 0, 0, 0)) {
2642 2642 rval = DDI_FAILURE;
2643 2643 goto done;
2644 2644 }
2645 2645
2646 2646 /*
2647 2647 * dynamically create a customized dma attribute structure
2648 2648 * that describes the MPT's config reply page request structure.
2649 2649 */
2650 2650 recv_dma_attrs = mpt->m_msg_dma_attr;
2651 2651 recv_dma_attrs.dma_attr_sgllen = 1;
2652 2652 recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
2653 2653
2654 2654 if (mptsas_dma_addr_create(mpt, recv_dma_attrs, &recv_dma_handle,
2655 2655 &recv_accessp, &recv_memp, (sizeof (MPI2_CONFIG_REPLY)),
2656 2656 NULL) == FALSE) {
2657 2657 rval = DDI_FAILURE;
2658 2658 goto done;
2659 2659 }
2660 2660 /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
2661 2661 free_recv = B_TRUE;
2662 2662
2663 2663 bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2664 2664 configreply = (pMpi2ConfigReply_t)recv_memp;
2665 2665 recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2666 2666
2667 2667 /*
2668 2668 * get config reply message
2669 2669 */
2670 2670 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2671 2671 recv_accessp)) {
2672 2672 rval = DDI_FAILURE;
2673 2673 goto done;
2674 2674 }
2675 2675
2676 2676 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2677 2677 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 update: "
2678 2678 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2679 2679 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2680 2680 goto done;
2681 2681 }
2682 2682
2683 2683 /*
2684 2684 * dynamically create a customized dma attribute structure
2685 2685 * that describes the MPT's config page structure.
2686 2686 */
2687 2687 page_dma_attrs = mpt->m_msg_dma_attr;
2688 2688 page_dma_attrs.dma_attr_sgllen = 1;
2689 2689 page_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_PAGE_MAN_0));
2690 2690
2691 2691 if (mptsas_dma_addr_create(mpt, page_dma_attrs, &page_dma_handle,
2692 2692 &page_accessp, &page_memp, (sizeof (MPI2_CONFIG_PAGE_MAN_0)),
2693 2693 &page_cookie) == FALSE) {
2694 2694 rval = DDI_FAILURE;
2695 2695 goto done;
2696 2696 }
2697 2697 /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
2698 2698 free_page = B_TRUE;
2699 2699
2700 2700 bzero(page_memp, sizeof (MPI2_CONFIG_PAGE_MAN_0));
2701 2701 m0 = (pMpi2ManufacturingPage0_t)page_memp;
2702 2702
2703 2703 /*
2704 2704 * Give reply address to IOC to store config page in and send
2705 2705 * config request out.
2706 2706 */
2707 2707
2708 2708 flagslength = sizeof (MPI2_CONFIG_PAGE_MAN_0);
2709 2709 flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
2710 2710 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2711 2711 MPI2_SGE_FLAGS_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
2712 2712 MPI2_SGE_FLAGS_IOC_TO_HOST |
2713 2713 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
2714 2714
2715 2715 if (mptsas_send_config_request_msg(mpt,
2716 2716 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2717 2717 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 0,
2718 2718 ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2719 2719 ddi_get8(recv_accessp, &configreply->Header.PageLength),
2720 2720 flagslength, page_cookie.dmac_laddress)) {
2721 2721 rval = DDI_FAILURE;
2722 2722 goto done;
2723 2723 }
2724 2724
2725 2725 /*
2726 2726 * get reply view handshake
2727 2727 */
2728 2728 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2729 2729 recv_accessp)) {
2730 2730 rval = DDI_FAILURE;
2731 2731 goto done;
2732 2732 }
2733 2733
2734 2734 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2735 2735 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page0 config: "
2736 2736 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2737 2737 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2738 2738 goto done;
2739 2739 }
2740 2740
2741 2741 (void) ddi_dma_sync(page_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
2742 2742
2743 2743 /*
2744 2744 * Fusion-MPT stores fields in little-endian format. This is
2745 2745 * why the low-order 32 bits are stored first.
2746 2746 */
2747 2747
2748 2748 for (i = 0; i < 16; i++) {
2749 2749 mpt->m_MANU_page0.ChipName[i] =
2750 2750 ddi_get8(page_accessp,
2751 2751 (uint8_t *)(void *)&m0->ChipName[i]);
2752 2752 }
2753 2753
2754 2754 for (i = 0; i < 8; i++) {
2755 2755 mpt->m_MANU_page0.ChipRevision[i] =
2756 2756 ddi_get8(page_accessp,
2757 2757 (uint8_t *)(void *)&m0->ChipRevision[i]);
2758 2758 }
2759 2759
2760 2760 for (i = 0; i < 16; i++) {
2761 2761 mpt->m_MANU_page0.BoardName[i] =
2762 2762 ddi_get8(page_accessp,
2763 2763 (uint8_t *)(void *)&m0->BoardName[i]);
2764 2764 }
2765 2765
2766 2766 for (i = 0; i < 16; i++) {
2767 2767 mpt->m_MANU_page0.BoardAssembly[i] =
2768 2768 ddi_get8(page_accessp,
2769 2769 (uint8_t *)(void *)&m0->BoardAssembly[i]);
2770 2770 }
2771 2771
2772 2772 for (i = 0; i < 16; i++) {
2773 2773 mpt->m_MANU_page0.BoardTracerNumber[i] =
2774 2774 ddi_get8(page_accessp,
2775 2775 (uint8_t *)(void *)&m0->BoardTracerNumber[i]);
2776 2776 }
2777 2777
2778 2778 if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2779 2779 (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2780 2780 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2781 2781 rval = DDI_FAILURE;
2782 2782 goto done;
2783 2783 }
2784 2784 if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2785 2785 (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2786 2786 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2787 2787 rval = DDI_FAILURE;
2788 2788 }
2789 2789 done:
2790 2790 /*
2791 2791 * free up memory
2792 2792 */
2793 2793 if (free_recv)
2794 2794 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2795 2795 if (free_page)
2796 2796 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2797 2797 MPTSAS_ENABLE_INTR(mpt);
2798 2798
2799 2799 return (rval);
2800 2800 }
↓ open down ↓ |
1380 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX