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